diff --git a/bridges/snowbridge/primitives/router/src/outbound/mod.rs b/bridges/snowbridge/primitives/router/src/outbound/mod.rs index e19e65e556bf..e2a4fee3f130 100644 --- a/bridges/snowbridge/primitives/router/src/outbound/mod.rs +++ b/bridges/snowbridge/primitives/router/src/outbound/mod.rs @@ -76,7 +76,7 @@ where } let para_id = match local_sub.as_slice() { - [Parachain(para_id)] => *para_id, + [Parachain(para_id), AccountId32 { .. }] => *para_id, _ => { log::error!(target: "xcm::ethereum_blob_exporter", "could not get parachain id from universal source '{local_sub:?}'."); return Err(SendError::MissingArgument) 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 ca5e761ea5af..319477465fe4 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 @@ -489,7 +489,7 @@ fn send_weth_asset_from_asset_hub_to_ethereum() { // Assert there is still some fee left in sov account after the transfer let free_balance_of_sovereign_on_bh_after = ::Balances::free_balance(assethub_sovereign); - assert_eq!(free_balance_of_sovereign_on_bh_after, 15590000); + assert_eq!(free_balance_of_sovereign_on_bh_after, 10686667); }); } 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 40ade5381cfa..3a6ceaa0bfb7 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 @@ -461,7 +461,7 @@ impl, msg: &mut Option>, - _source: Option<&Location>, + source: Option<&Location>, ) -> SendResult { let d = dest.as_ref().ok_or(MissingArgument)?; let devolved = @@ -478,6 +478,11 @@ impl(bridge, message, None)?; - if let Some(bridge_payment) = maybe_payment { - cost.push(bridge_payment); - } - Ok((v, cost, None)) + let (v, cost, _) = validate_send::(bridge, message, None)?; + Ok((v, cost, Some(payments))) } fn deliver(ticket: Router::Ticket) -> Result { @@ -727,7 +733,7 @@ pub mod bridging { parameter_types! { /// User fee for delivery cost on bridge hub. Leave some buffer here for avoid spamming /// should cover at least the BuyExecution on BH - pub const DefaultBridgeHubEthereumBaseFee: Balance = 48_000_000; + pub const DefaultBridgeHubEthereumBaseFee: Balance = 60_000_000; pub storage BridgeHubEthereumBaseFee: Balance = DefaultBridgeHubEthereumBaseFee::get(); pub SiblingBridgeHubWithEthereumInboundQueueInstance: Location = Location::new( 1, diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs index 511f6f750de2..dd19dd4706f6 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs @@ -22,21 +22,23 @@ use super::{ use bp_messages::LaneId; use bp_relayers::{PayRewardFromAccount, RewardsAccountOwner, RewardsAccountParams}; use bp_runtime::ChainId; +use cumulus_primitives_core::ParaId; use frame_support::{ parameter_types, - traits::{tokens::imbalance::ResolveTo, ConstU32, Contains, Equals, Everything, Nothing}, + traits::{ + tokens::imbalance::ResolveTo, ConstU32, Contains, ContainsPair, Equals, Everything, Nothing, + }, }; use frame_system::EnsureRoot; use pallet_collator_selection::StakingPotAccountId; use pallet_xcm::XcmPassthrough; use parachains_common::{ xcm_config::{ - AllSiblingSystemParachains, ConcreteAssetFromSystem, ParentRelayOrSiblingParachains, - RelayOrOtherSystemParachains, + AllSiblingSystemParachains, ParentRelayOrSiblingParachains, RelayOrOtherSystemParachains, }, TREASURY_PALLET_ID, }; -use polkadot_parachain_primitives::primitives::Sibling; +use polkadot_parachain_primitives::primitives::{IsSystem, Sibling}; use polkadot_runtime_common::xcm_sender::ExponentialPrice; use sp_core::Get; use sp_runtime::traits::AccountIdConversion; @@ -167,9 +169,29 @@ pub type WaivedLocations = ( Equals, ); +pub struct ConcreteAssetFromUserOriginOfSystemChain(PhantomData); +impl> ContainsPair + for ConcreteAssetFromUserOriginOfSystemChain +{ + fn contains(asset: &Asset, origin: &Location) -> bool { + log::trace!(target: "xcm::contains", "ConcreteAssetFromSystem asset: {:?}, origin: {:?}", asset, origin); + let is_system = match origin.unpack() { + // The Relay Chain + (1, []) => true, + // System parachain + (1, [Parachain(id)]) => ParaId::from(*id).is_system(), + // User from system chain + (1, [Parachain(id), AccountId32 { .. }]) => ParaId::from(*id).is_system(), + // Others + _ => false, + }; + asset.id.0 == AssetLocation::get() && is_system + } +} + /// Cases where a remote origin is accepted as trusted Teleporter for a given asset: /// - NativeToken with the parent Relay Chain and sibling parachains. -pub type TrustedTeleporters = ConcreteAssetFromSystem; +pub type TrustedTeleporters = ConcreteAssetFromUserOriginOfSystemChain; pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { diff --git a/polkadot/xcm/xcm-builder/src/routing.rs b/polkadot/xcm/xcm-builder/src/routing.rs index d9f6c9c871ad..4c66ddf96e50 100644 --- a/polkadot/xcm/xcm-builder/src/routing.rs +++ b/polkadot/xcm/xcm-builder/src/routing.rs @@ -42,7 +42,7 @@ impl SendXcm for WithUniqueTopic { fn validate( destination: &mut Option, message: &mut Option>, - _source: Option<&Location>, + source: Option<&Location>, ) -> SendResult { let mut message = message.take().ok_or(SendError::MissingArgument)?; let unique_id = if let Some(SetTopic(id)) = message.last() { @@ -52,8 +52,8 @@ impl SendXcm for WithUniqueTopic { message.0.push(SetTopic(unique_id)); unique_id }; - let (ticket, assets, _) = Inner::validate(destination, &mut Some(message), None)?; - Ok(((ticket, unique_id), assets, None)) + let (ticket, assets, burnt) = Inner::validate(destination, &mut Some(message), source)?; + Ok(((ticket, unique_id), assets, burnt)) } fn deliver(ticket: Self::Ticket) -> Result { diff --git a/polkadot/xcm/xcm-executor/src/lib.rs b/polkadot/xcm/xcm-executor/src/lib.rs index bc29f8a968a5..2bfd90512394 100644 --- a/polkadot/xcm/xcm-executor/src/lib.rs +++ b/polkadot/xcm/xcm-executor/src/lib.rs @@ -387,8 +387,12 @@ impl XcmExecutor { reason = ?reason, "Sending msg", ); - let (ticket, fee, _) = validate_send::(dest, msg, self.origin_ref())?; - self.take_fee(fee, reason)?; + let (ticket, fee, fee_to_burn) = + validate_send::(dest, msg, self.origin_ref())?; + self.take_fee(fee, reason.clone())?; + if let Some(fee_to_burn) = fee_to_burn { + self.burn_fee(fee_to_burn, reason)?; + } Config::XcmSender::deliver(ticket).map_err(Into::into) } @@ -494,6 +498,30 @@ impl XcmExecutor { Ok(()) } + fn burn_fee(&mut self, fee: Assets, reason: FeeReason) -> XcmResult { + if Config::FeeManager::is_waived(self.origin_ref(), reason.clone()) { + return Ok(()) + } + tracing::trace!( + target: "xcm::fees", + ?fee, + origin_ref = ?self.origin_ref(), + fees_mode = ?self.fees_mode, + ?reason, + "Burning fees", + ); + if self.fees_mode.jit_withdraw { + let origin = self.origin_ref().ok_or(XcmError::BadOrigin)?; + for asset in fee.inner() { + Config::AssetTransactor::withdraw_asset(&asset, origin, Some(&self.context))?; + } + fee + } else { + self.holding.try_take(fee.into()).map_err(|_| XcmError::NotHoldingFees)?.into() + }; + Ok(()) + } + /// Calculates what `local_querier` would be from the perspective of `destination`. fn to_querier( local_querier: Option,