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

Reward relayer on AH for E->S transfer #165

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)?;
}

Comment on lines -266 to -279
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove the reward logic here, instead to reward relayer on AH with the fee token transfered from Ethereum.

// 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,
)?;
Comment on lines +280 to +287
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Burn fees from relayer instead of the Parachain sovereign.


// 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(),
}])),
Comment on lines +277 to +282
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add an extra SetErrorHandle try to Deposit the asset to beneficiary in any case.

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
Loading