Skip to content
This repository has been archived by the owner on Oct 22, 2024. It is now read-only.

Commit

Permalink
Reward relayer on AH
Browse files Browse the repository at this point in the history
  • Loading branch information
yrong committed Jul 28, 2024
1 parent 2cef4bd commit df8181b
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 50 deletions.
35 changes: 13 additions & 22 deletions bridges/snowbridge/pallets/inbound-queue/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,14 @@ use envelope::Envelope;
use frame_support::{
traits::{
fungible::{Inspect, Mutate},
tokens::{Fortitude, Preservation},
tokens::{Fortitude, Precision, Preservation},
},
weights::WeightToFee,
PalletError,
};
use frame_system::ensure_signed;
use scale_info::TypeInfo;
use sp_core::H160;
use sp_runtime::traits::Zero;
use sp_std::vec;
use xcm::prelude::{
send_xcm, Junction::*, Location, SendError as XcmpSendError, SendXcm, Xcm, XcmContext, XcmHash,
Expand All @@ -58,8 +57,7 @@ use xcm_executor::traits::TransactAsset;

use snowbridge_core::{
inbound::{Message, VerificationError, Verifier},
sibling_sovereign_account, BasicOperatingMode, Channel, ChannelId, ParaId, PricingParameters,
StaticLookup,
BasicOperatingMode, Channel, ChannelId, ParaId, PricingParameters, StaticLookup,
};
use snowbridge_router_primitives::{
inbound,
Expand Down Expand Up @@ -263,25 +261,12 @@ pub mod pallet {
}
})?;

// Reward relayer from the sovereign account of the destination parachain, only if funds
// are available
let sovereign_account = sibling_sovereign_account::<T>(channel.para_id);
let delivery_cost = Self::calculate_delivery_cost(message.encode().len() as u32);
let amount = T::Token::reducible_balance(
&sovereign_account,
Preservation::Preserve,
Fortitude::Polite,
)
.min(delivery_cost);
if !amount.is_zero() {
T::Token::transfer(&sovereign_account, &who, amount, Preservation::Preserve)?;
}

// Decode message into XCM
let (xcm, fee) =
match inbound::VersionedMessage::decode_all(&mut envelope.payload.as_ref()) {
Ok(message) => T::MessageConverter::convert(envelope.message_id, message)
.map_err(|e| Error::<T>::ConvertMessage(e))?,
Ok(message) =>
T::MessageConverter::convert(envelope.message_id, message, who.clone())
.map_err(|e| Error::<T>::ConvertMessage(e))?,
Err(_) => return Err(Error::<T>::InvalidPayload.into()),
};

Expand All @@ -292,8 +277,14 @@ pub mod pallet {
fee
);

// Burning fees for teleport
Self::burn_fees(channel.para_id, fee)?;
// Burning fees from the relay for teleport
T::Token::burn_from(
&who,
fee,
Preservation::Preserve,
Precision::BestEffort,
Fortitude::Polite,
)?;

// Attempt to send XCM to a dest parachain
let message_id = Self::send_xcm(xcm, channel.para_id)?;
Expand Down
32 changes: 27 additions & 5 deletions bridges/snowbridge/primitives/router/src/inbound/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ pub trait ConvertMessage {
fn convert(
message_id: H256,
message: VersionedMessage,
relayer: Self::AccountId,
) -> Result<(Xcm<()>, Self::Balance), ConvertMessageError>;
}

Expand Down Expand Up @@ -145,14 +146,23 @@ where
fn convert(
message_id: H256,
message: VersionedMessage,
relayer: AccountId,
) -> Result<(Xcm<()>, Self::Balance), ConvertMessageError> {
use Command::*;
use VersionedMessage::*;
match message {
V1(MessageV1 { chain_id, command: RegisterToken { token, fee } }) =>
Ok(Self::convert_register_token(message_id, chain_id, token, fee)),
V1(MessageV1 { chain_id, command: SendToken { token, destination, amount, fee } }) =>
Ok(Self::convert_send_token(message_id, chain_id, token, destination, amount, fee)),
Ok(Self::convert_send_token(
message_id,
relayer,
chain_id,
token,
destination,
amount,
fee,
)),
}
}
}
Expand Down Expand Up @@ -224,6 +234,7 @@ where

fn convert_send_token(
message_id: H256,
relayer: AccountId,
chain_id: u64,
token: H160,
destination: Destination,
Expand Down Expand Up @@ -263,6 +274,12 @@ where
BuyExecution { fees: asset_hub_fee_asset, weight_limit: Unlimited },
DescendOrigin(PalletInstance(inbound_queue_pallet_index).into()),
UniversalOrigin(GlobalConsensus(network)),
// No matter what error it is just try to Deposit the asset to beneficiary without
// trapped.
SetErrorHandler(Xcm(vec![DepositAsset {
assets: Definite(asset.clone().into()),
beneficiary: beneficiary.clone(),
}])),
ReserveAssetDeposited(asset.clone().into()),
ClearOrigin,
];
Expand All @@ -289,11 +306,16 @@ where
]);
},
None => {
// Deposit asset to beneficiary and all fees left to relayer
instructions.extend(vec![
// Deposit both asset and fees to beneficiary so the fees will not get
// trapped. Another benefit is when fees left more than ED on AssetHub could be
// used to create the beneficiary account in case it does not exist.
DepositAsset { assets: Wild(AllCounted(2)), beneficiary },
DepositAsset {
assets: Definite(asset.clone().into()),
beneficiary: beneficiary.clone(),
},
DepositAsset {
assets: Wild(AllCounted(2)),
beneficiary: Location::from(relayer.into()),
},
]);
},
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ use codec::{Decode, Encode};
use emulated_integration_tests_common::xcm_emulator::ConvertLocation;
use frame_support::pallet_prelude::TypeInfo;
use hex_literal::hex;
use rococo_westend_system_emulated_network::BridgeHubRococoParaSender as BridgeHubRococoSender;
use rococo_westend_system_emulated_network::{
BridgeHubRococoParaReceiver as BridgeHubRococoReceiver,
BridgeHubRococoParaSender as BridgeHubRococoSender,
};
use snowbridge_core::{inbound::InboundQueueFixture, outbound::OperatingMode};
use snowbridge_pallet_inbound_queue_fixtures::{
register_token::make_register_token_message, send_token::make_send_token_message,
Expand All @@ -40,6 +43,7 @@ pub const WETH: [u8; 20] = hex!("87d1f7fdfEe7f651FaBc8bFCB6E086C278b77A7d");
const ETHEREUM_DESTINATION_ADDRESS: [u8; 20] = hex!("44a57ee2f2FCcb85FDa2B0B18EBD0D8D2333700e");
const INSUFFICIENT_XCM_FEE: u128 = 1000;
const XCM_FEE: u128 = 4_000_000_000;
const WETH_AMOUNT: u128 = 1_000_000_000;

#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)]
pub enum ControlCall {
Expand Down Expand Up @@ -239,20 +243,46 @@ fn register_weth_token_from_ethereum_to_asset_hub() {
/// Tests the registering of a token as an asset on AssetHub, and then subsequently sending
/// a token from Ethereum to AssetHub.
#[test]
fn send_token_from_ethereum_to_asset_hub() {
BridgeHubRococo::fund_para_sovereign(AssetHubRococo::para_id().into(), INITIAL_FUND);
fn send_token_from_ethereum_to_asset_hub_happy_path() {
let weth_asset_location: Location = Location::new(
2,
[EthereumNetwork::get().into(), AccountKey20 { network: None, key: WETH }],
);

// Fund ethereum sovereign on AssetHub
AssetHubRococo::fund_accounts(vec![(AssetHubRococoReceiver::get(), INITIAL_FUND)]);
// Register WETH
AssetHubRococo::execute_with(|| {
type RuntimeOrigin = <AssetHubRococo as Chain>::RuntimeOrigin;

assert_ok!(<AssetHubRococo as AssetHubRococoPallet>::ForeignAssets::force_create(
RuntimeOrigin::root(),
weth_asset_location.clone().try_into().unwrap(),
AssetHubRococoReceiver::get().into(),
false,
1,
));

assert!(<AssetHubRococo as AssetHubRococoPallet>::ForeignAssets::asset_exists(
weth_asset_location.clone().try_into().unwrap(),
));
});

BridgeHubRococo::execute_with(|| {
type RuntimeEvent = <BridgeHubRococo as Chain>::RuntimeEvent;
type Converter = <bridge_hub_rococo_runtime::Runtime as snowbridge_pallet_inbound_queue::Config>::MessageConverter;

// Construct RegisterToken message and sent to inbound queue
assert_ok!(send_inbound_message(make_register_token_message()));

// Construct SendToken message and sent to inbound queue
assert_ok!(send_inbound_message(make_send_token_message()));
let message_id: H256 = [0; 32].into();
let message = VersionedMessage::V1(MessageV1 {
chain_id: CHAIN_ID,
command: Command::SendToken {
token: WETH.into(),
destination: Destination::AccountId32 { id: AssetHubRococoReceiver::get().into() },
amount: WETH_AMOUNT,
fee: XCM_FEE,
},
});
let relayer = BridgeHubRococoReceiver::get();
let (xcm, _) = Converter::convert(message_id, message, relayer.into()).unwrap();
let _ = EthereumInboundQueue::send_xcm(xcm, AssetHubRococo::para_id().into()).unwrap();

// Check that the message was sent
assert_expected_events!(
Expand Down Expand Up @@ -506,16 +536,6 @@ fn send_weth_asset_from_asset_hub_to_ethereum() {
});
}

#[test]
fn send_token_from_ethereum_to_asset_hub_fail_for_insufficient_fund() {
// Insufficient fund
BridgeHubRococo::fund_para_sovereign(AssetHubRococo::para_id().into(), 1_000);

BridgeHubRococo::execute_with(|| {
assert_err!(send_inbound_message(make_register_token_message()), Token(FundsUnavailable));
});
}

#[test]
fn register_weth_token_in_asset_hub_fail_for_insufficient_fee() {
BridgeHubRococo::fund_para_sovereign(AssetHubRococo::para_id().into(), INITIAL_FUND);
Expand All @@ -535,7 +555,8 @@ fn register_weth_token_in_asset_hub_fail_for_insufficient_fee() {
fee: INSUFFICIENT_XCM_FEE,
},
});
let (xcm, _) = Converter::convert(message_id, message).unwrap();
let relayer = BridgeHubRococoReceiver::get();
let (xcm, _) = Converter::convert(message_id, message, relayer).unwrap();
let _ = EthereumInboundQueue::send_xcm(xcm, AssetHubRococo::para_id().into()).unwrap();

assert_expected_events!(
Expand Down Expand Up @@ -579,7 +600,7 @@ fn send_token_from_ethereum_to_asset_hub_with_fee(account_id: [u8; 32], fee: u12
RuntimeOrigin::root(),
weth_asset_location.clone().try_into().unwrap(),
asset_hub_sovereign.into(),
false,
true,
1,
));

Expand All @@ -605,7 +626,8 @@ fn send_token_from_ethereum_to_asset_hub_with_fee(account_id: [u8; 32], fee: u12
fee,
},
});
let (xcm, _) = Converter::convert(message_id, message).unwrap();
let relayer = BridgeHubRococoReceiver::get();
let (xcm, _) = Converter::convert(message_id, message, relayer).unwrap();
assert_ok!(EthereumInboundQueue::send_xcm(xcm, AssetHubRococo::para_id().into()));

// Check that the message was sent
Expand Down

0 comments on commit df8181b

Please sign in to comment.