From df8181b3587f200a27cb3f6ffccfc9ee46a97f45 Mon Sep 17 00:00:00 2001 From: ron Date: Sun, 28 Jul 2024 18:29:27 +0800 Subject: [PATCH] Reward relayer on AH --- .../pallets/inbound-queue/src/lib.rs | 35 ++++------ .../primitives/router/src/inbound/mod.rs | 32 +++++++-- .../bridge-hub-rococo/src/tests/snowbridge.rs | 68 ++++++++++++------- 3 files changed, 85 insertions(+), 50 deletions(-) diff --git a/bridges/snowbridge/pallets/inbound-queue/src/lib.rs b/bridges/snowbridge/pallets/inbound-queue/src/lib.rs index 171a26621c08..ddfb55bf0411 100644 --- a/bridges/snowbridge/pallets/inbound-queue/src/lib.rs +++ b/bridges/snowbridge/pallets/inbound-queue/src/lib.rs @@ -41,7 +41,7 @@ use envelope::Envelope; use frame_support::{ traits::{ fungible::{Inspect, Mutate}, - tokens::{Fortitude, Preservation}, + tokens::{Fortitude, Precision, Preservation}, }, weights::WeightToFee, PalletError, @@ -49,7 +49,6 @@ use frame_support::{ 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, @@ -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, @@ -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::(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::::ConvertMessage(e))?, + Ok(message) => + T::MessageConverter::convert(envelope.message_id, message, who.clone()) + .map_err(|e| Error::::ConvertMessage(e))?, Err(_) => return Err(Error::::InvalidPayload.into()), }; @@ -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)?; diff --git a/bridges/snowbridge/primitives/router/src/inbound/mod.rs b/bridges/snowbridge/primitives/router/src/inbound/mod.rs index c5c5bda11d67..27e38dbdbff7 100644 --- a/bridges/snowbridge/primitives/router/src/inbound/mod.rs +++ b/bridges/snowbridge/primitives/router/src/inbound/mod.rs @@ -118,6 +118,7 @@ pub trait ConvertMessage { fn convert( message_id: H256, message: VersionedMessage, + relayer: Self::AccountId, ) -> Result<(Xcm<()>, Self::Balance), ConvertMessageError>; } @@ -145,6 +146,7 @@ where fn convert( message_id: H256, message: VersionedMessage, + relayer: AccountId, ) -> Result<(Xcm<()>, Self::Balance), ConvertMessageError> { use Command::*; use VersionedMessage::*; @@ -152,7 +154,15 @@ where 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, + )), } } } @@ -224,6 +234,7 @@ where fn convert_send_token( message_id: H256, + relayer: AccountId, chain_id: u64, token: H160, destination: Destination, @@ -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, ]; @@ -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()), + }, ]); }, } diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs index 4cb8680686e8..6f8cd06d3f1e 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs @@ -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, @@ -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 { @@ -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 = ::RuntimeOrigin; + + assert_ok!(::ForeignAssets::force_create( + RuntimeOrigin::root(), + weth_asset_location.clone().try_into().unwrap(), + AssetHubRococoReceiver::get().into(), + false, + 1, + )); + + assert!(::ForeignAssets::asset_exists( + weth_asset_location.clone().try_into().unwrap(), + )); + }); BridgeHubRococo::execute_with(|| { type RuntimeEvent = ::RuntimeEvent; + type Converter = ::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!( @@ -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); @@ -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!( @@ -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, )); @@ -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