From f360d7bf8a5d46102a0d91c133a24c2b9b44d0f9 Mon Sep 17 00:00:00 2001 From: Alistair Singh Date: Thu, 9 Nov 2023 22:20:56 +0200 Subject: [PATCH] fixes and cleaner implementation --- .../primitives/runtime-common/Cargo.toml | 2 - .../primitives/runtime-common/src/lib.rs | 148 +++++++++--------- polkadot-sdk | 2 +- 3 files changed, 72 insertions(+), 80 deletions(-) diff --git a/parachain/primitives/runtime-common/Cargo.toml b/parachain/primitives/runtime-common/Cargo.toml index f39e9e3949..fb1d8ce5a8 100644 --- a/parachain/primitives/runtime-common/Cargo.toml +++ b/parachain/primitives/runtime-common/Cargo.toml @@ -9,7 +9,6 @@ log = { version = "0.4.20", default-features = false } bp-rococo = { path = "../../../polkadot-sdk/bridges/primitives/chain-rococo", default-features = false } frame-support = { path = "../../../polkadot-sdk/substrate/frame/support", default-features = false } -sp-io = { path = "../../../polkadot-sdk/substrate/primitives/io", default-features = false } xcm = { package = "staging-xcm", path = "../../../polkadot-sdk/polkadot/xcm", default-features = false } xcm-builder = { package = "staging-xcm-builder", path = "../../../polkadot-sdk/polkadot/xcm/xcm-builder", default-features = false } xcm-executor = { package = "staging-xcm-executor", path = "../../../polkadot-sdk/polkadot/xcm/xcm-executor", default-features = false } @@ -24,7 +23,6 @@ std = [ "bp-rococo/std", "frame-support/std", "snowbridge-core/std", - "sp-io/std", "xcm-builder/std", "xcm-executor/std", "xcm/std", diff --git a/parachain/primitives/runtime-common/src/lib.rs b/parachain/primitives/runtime-common/src/lib.rs index c6cefa5019..dfd31e2af7 100644 --- a/parachain/primitives/runtime-common/src/lib.rs +++ b/parachain/primitives/runtime-common/src/lib.rs @@ -1,3 +1,10 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2023 Snowfork +//! # Runtime Common +//! +//! Common traits and types shared by runtimes. +#![cfg_attr(not(feature = "std"), no_std)] + use bp_rococo::AccountId; use core::marker::PhantomData; use frame_support::traits::Get; @@ -7,29 +14,19 @@ use xcm_builder::{deposit_or_burn_fee, HandleFee}; use xcm_executor::traits::{FeeReason, TransactAsset}; /// A `HandleFee` implementation that takes fees from `ExportMessage` XCM instructions -/// to Snowbridge and holds it in a receiver account. Burns the fees in case of a failure. -pub struct XcmExportFeeToSnowbridge< - TokenLocation, - EthereumNetwork, - ReceiverAccount, - AssetTransactor, - OutboundQueue, ->(PhantomData<(TokenLocation, EthereumNetwork, ReceiverAccount, AssetTransactor, OutboundQueue)>); +/// to Snowbridge and splits it between the origin parachains sovereign and the system +/// treasury account specified by `ReceiverAmount`. +pub struct XcmExportFeeToSnowbridge( + PhantomData<(TokenLocation, EthereumNetwork, AssetTransactor, OutboundQueue)>, +); impl< TokenLocation: Get, EthereumNetwork: Get, - ReceiverAccount: Get, AssetTransactor: TransactAsset, OutboundQueue: SendMessageFeeProvider, > HandleFee - for XcmExportFeeToSnowbridge< - TokenLocation, - EthereumNetwork, - ReceiverAccount, - AssetTransactor, - OutboundQueue, - > + for XcmExportFeeToSnowbridge { fn handle_fee( fees: MultiAssets, @@ -37,75 +34,72 @@ impl< reason: FeeReason, ) -> MultiAssets { let token_location = TokenLocation::get(); - let mut fees = fees.into_inner(); - if matches!(reason, FeeReason::Export { network: bridged_network, destination } - if bridged_network == EthereumNetwork::get() && destination == Here) - { - log::info!( - target: "xcm::fees", - "XcmExportFeeToSnowbridge fees: {fees:?}, context: {context:?}, reason: {reason:?}", - ); + // Check the reason to see if this export is for snowbridge. + let snowbridge_export = matches!( + reason, + FeeReason::Export { network: bridged_network, destination } + if bridged_network == EthereumNetwork::get() && destination == Here + ); - let fee_item_index = fees.iter().position(|asset| { - matches!( - asset, - MultiAsset { id: Concrete(location), fun: Fungible(..)} - if *location == token_location, - ) - }); - // Find the fee asset. - let fee_item = if let Some(element) = fee_item_index { - fees.remove(element) + // Get the parachain sovereign from the `context`. + let maybe_para_sovereign = if let Some(XcmContext { + origin: Some(MultiLocation { parents: 1, interior }), + .. + }) = context + { + if let Some(Parachain(sibling_para_id)) = interior.first() { + let account: AccountId = + sibling_sovereign_account_raw((*sibling_para_id).into()).into(); + Some(account) } else { - return fees.into() - }; - - let receiver = ReceiverAccount::get(); - // There is an origin so split fee into parts. - if let Some(XcmContext { - origin: Some(MultiLocation { parents: 1, interior }), .. - }) = context - { - if let Some(Parachain(sibling_para_id)) = interior.first() { - let account: AccountId = - sibling_sovereign_account_raw((*sibling_para_id).into()).into(); - let local_fee = OutboundQueue::local_fee(); - if let Fungible(amount) = fee_item.fun { - let remote_fee = amount.saturating_sub(local_fee); + None + } + } else { + None + }; - // Send local fee to receiver - deposit_or_burn_fee::( - MultiAsset { - id: Concrete(token_location), - fun: Fungible(amount - remote_fee), - } - .into(), - context, - receiver, - ); - // Send remote fee to origin - deposit_or_burn_fee::( - MultiAsset { id: Concrete(token_location), fun: Fungible(remote_fee) } - .into(), - context, - account, - ); - } else { - // Push the fee item back and bail out to let other handlers run. - fees.push(fee_item); - return fees.into() + // Get the total fee offered by export message. + let maybe_total_supplied_fee = fees + .inner() + .iter() + .enumerate() + .filter_map(|(index, asset)| { + if let MultiAsset { id: Concrete(location), fun: Fungible(amount) } = asset { + if *location == token_location { + return Some((index, amount)) } - } else { - // Origin conversion failed so send the full fee to the receiver. - deposit_or_burn_fee::(fee_item.into(), context, receiver); } - } else { - // There is no context so send the full fee to the receiver. - deposit_or_burn_fee::(fee_item.into(), context, receiver); + return None + }) + .next(); + + if let (true, Some(para_sovereign), Some((fee_index, total_fee))) = + (snowbridge_export, maybe_para_sovereign, maybe_total_supplied_fee) + { + let remote_fee = total_fee.saturating_sub(OutboundQueue::local_fee()); + if remote_fee > 0 { + // Send remote fee to origin + deposit_or_burn_fee::( + MultiAsset { id: Concrete(token_location), fun: Fungible(remote_fee) }.into(), + context, + para_sovereign, + ); + // Return remaining fee to the next fee handler in the chain. + let mut modified_fees = fees.inner().clone(); + modified_fees.remove(fee_index); + modified_fees.push(MultiAsset { + id: Concrete(token_location), + fun: Fungible(total_fee - remote_fee), + }); + return modified_fees.into() } } - fees.into() + log::trace!( + target: "xcm::fees", + "XcmExportFeeToSnowbridge skipped: {fees:?}, context: {context:?}, reason: {reason:?}", + ); + return fees } } diff --git a/polkadot-sdk b/polkadot-sdk index 114f5524c7..f56aaf93e3 160000 --- a/polkadot-sdk +++ b/polkadot-sdk @@ -1 +1 @@ -Subproject commit 114f5524c7cc990b916997d23ad2ac73c1bb5281 +Subproject commit f56aaf93e36117392e61e48a59e66ae764d697ff