From 0cae8887c8be610c80efe8b858a188c42ee00214 Mon Sep 17 00:00:00 2001 From: ron Date: Wed, 31 Jul 2024 21:01:00 +0800 Subject: [PATCH] Revamp xcm executor to add destination to FeeReason --- .../assets/asset-hub-rococo/src/xcm_config.rs | 77 +++++++++++++++++-- .../src/fungible/benchmarking.rs | 6 +- polkadot/xcm/xcm-executor/src/lib.rs | 12 ++- .../xcm-executor/src/traits/fee_manager.rs | 4 +- 4 files changed, 86 insertions(+), 13 deletions(-) diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs index 65c470870303..d3590208e9ee 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs @@ -45,7 +45,10 @@ use parachains_common::{ use polkadot_parachain_primitives::primitives::Sibling; use polkadot_runtime_common::xcm_sender::ExponentialPrice; use snowbridge_router_primitives::inbound::GlobalConsensusEthereumConvertsFor; -use sp_runtime::traits::{AccountIdConversion, ConvertInto}; +use sp_runtime::{ + traits::{AccountIdConversion, ConvertInto}, + SaturatedConversion, +}; use sp_std::marker::PhantomData; use testnet_parachains_constants::rococo::snowbridge::{ EthereumNetwork, INBOUND_QUEUE_PALLET_INDEX, @@ -60,15 +63,15 @@ use xcm_builder::{ AllowHrmpNotificationsFromRelayChain, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, DenyReserveTransferToRelayChain, DenyThenTry, DescribeAllTerminal, DescribeFamily, EnsureXcmOrigin, ExporterFor, FrameTransactionalProcessor, - FungibleAdapter, FungiblesAdapter, GlobalConsensusParachainConvertsFor, HashedDescription, - InspectMessageQueues, IsConcrete, LocalMint, NetworkExportTableItem, NoChecking, - NonFungiblesAdapter, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, + FungibleAdapter, FungiblesAdapter, GlobalConsensusParachainConvertsFor, HandleFee, + HashedDescription, InspectMessageQueues, IsConcrete, LocalMint, NetworkExportTableItem, + NoChecking, NonFungiblesAdapter, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SendXcmFeeToAccount, SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, StartsWith, StartsWithExplicitGlobalConsensus, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, XcmFeeManagerFromComponents, }; -use xcm_executor::XcmExecutor; +use xcm_executor::{traits::FeeReason, XcmExecutor}; parameter_types! { pub const TokenLocation: Location = Location::parent(); @@ -420,7 +423,15 @@ impl xcm_executor::Config for XcmConfig { type AssetExchanger = (); type FeeManager = XcmFeeManagerFromComponents< WaivedLocations, - SendXcmFeeToAccount, + ( + SnowbridgeExportFee< + Balance, + bridging::to_ethereum::BridgeHubEthereumBaseFee, + TokenLocation, + bridging::to_ethereum::EthereumLocation, + >, + SendXcmFeeToAccount, + ), >; type MessageExporter = (); type UniversalAliases = @@ -536,6 +547,58 @@ impl InspectMessageQue } } +pub struct SnowbridgeExportFee( + PhantomData<(Balance, ExportFeeBalance, FeeAssetLocation, EthereumLocation)>, +); + +impl HandleFee + for SnowbridgeExportFee +where + Balance: From + Into, + ExportFeeBalance: Get, + FeeAssetLocation: Get, + EthereumLocation: Get, +{ + fn handle_fee( + fees: xcm::prelude::Assets, + _context: Option<&XcmContext>, + reason: FeeReason, + ) -> xcm::prelude::Assets { + // Check the reason to see if this export is for snowbridge. + if !matches!(reason, FeeReason::InitiateReserveWithdraw { destination } + if destination == EthereumLocation::get() + ) || fees.len() != 1 + { + return fees + } + + let fee = fees.get(0); + + if let Some(Asset { id: location, .. }) = fee { + if location.0 != FeeAssetLocation::get() { + return fees + } + } + + let fee_amount: Option = if let Some(Asset { fun: Fungible(amount), .. }) = fee { + Some(amount.clone()) + } else { + None + }; + + if fee_amount.is_none() { + return fees + } + + let export_fee_balance = ExportFeeBalance::get(); + + let delivery_fee = + fee_amount.unwrap().saturating_sub(export_fee_balance.saturated_into::()); + + return Asset::from((FeeAssetLocation::get(), delivery_fee)).into() + } +} + /// The means for routing XCM messages which are not for local execution into the right message /// queues. pub type XcmRouter = WithUniqueTopic<( @@ -735,6 +798,8 @@ pub mod bridging { PalletInstance(INBOUND_QUEUE_PALLET_INDEX) ] ); + pub EthereumLocation: Location = Location::new(2, [GlobalConsensus(EthereumNetwork::get())]); + /// Set up exporters configuration. /// `Option` represents static "base fee" which is used for total delivery fee calculation. diff --git a/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/benchmarking.rs b/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/benchmarking.rs index 6ce49074a6e2..ce6f97dd1716 100644 --- a/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/benchmarking.rs +++ b/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/benchmarking.rs @@ -150,8 +150,8 @@ benchmarks_instance_pallet! { let (expected_fees_mode, expected_assets_in_holding) = T::DeliveryHelper::ensure_successful_delivery( &sender_location, - &reserve, - FeeReason::InitiateReserveWithdraw, + &reserve.clone(), + FeeReason::InitiateReserveWithdraw{ destination:reserve.clone() }, ); let sender_account_balance_before = T::TransactAsset::balance(&sender_account); @@ -175,7 +175,7 @@ benchmarks_instance_pallet! { let instruction = Instruction::InitiateReserveWithdraw { // Worst case is looking through all holdings for every asset explicitly - respecting the limit `MAX_ITEMS_IN_ASSETS`. assets: Definite(holding.into_inner().into_iter().take(MAX_ITEMS_IN_ASSETS).collect::>().into()), - reserve, + reserve: reserve.clone(), xcm: Xcm(vec![]) }; let xcm = Xcm(vec![instruction]); diff --git a/polkadot/xcm/xcm-executor/src/lib.rs b/polkadot/xcm/xcm-executor/src/lib.rs index 1daf5ae750cf..01982e4e9a91 100644 --- a/polkadot/xcm/xcm-executor/src/lib.rs +++ b/polkadot/xcm/xcm-executor/src/lib.rs @@ -901,7 +901,11 @@ impl XcmExecutor { message.extend(xcm.0.into_iter()); // put back transport_fee in holding register to be charged by XcmSender self.holding.subsume_assets(transport_fee); - self.send(dest, Xcm(message), FeeReason::DepositReserveAsset)?; + self.send( + dest.clone(), + Xcm(message), + FeeReason::DepositReserveAsset { destination: dest }, + )?; Ok(()) }); if Config::TransactionalProcessor::IS_TRANSACTIONAL && result.is_err() { @@ -921,7 +925,11 @@ impl XcmExecutor { ); let mut message = vec![WithdrawAsset(assets), ClearOrigin]; message.extend(xcm.0.into_iter()); - self.send(reserve, Xcm(message), FeeReason::InitiateReserveWithdraw)?; + self.send( + reserve.clone(), + Xcm(message), + FeeReason::InitiateReserveWithdraw { destination: reserve }, + )?; Ok(()) }); if Config::TransactionalProcessor::IS_TRANSACTIONAL && result.is_err() { diff --git a/polkadot/xcm/xcm-executor/src/traits/fee_manager.rs b/polkadot/xcm/xcm-executor/src/traits/fee_manager.rs index b6e303daaad8..e2173b6120d0 100644 --- a/polkadot/xcm/xcm-executor/src/traits/fee_manager.rs +++ b/polkadot/xcm/xcm-executor/src/traits/fee_manager.rs @@ -34,9 +34,9 @@ pub enum FeeReason { /// When the `TransferReserveAsset` instruction is called. TransferReserveAsset, /// When the `DepositReserveAsset` instruction is called. - DepositReserveAsset, + DepositReserveAsset { destination: Location }, /// When the `InitiateReserveWithdraw` instruction is called. - InitiateReserveWithdraw, + InitiateReserveWithdraw { destination: Location }, /// When the `InitiateTeleport` instruction is called. InitiateTeleport, /// When the `QueryPallet` instruction is called.