diff --git a/Cargo.lock b/Cargo.lock index b4ab72431284b..7d4d51dd6a2a6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1146,6 +1146,7 @@ dependencies = [ "snowbridge-inbound-queue-primitives", "snowbridge-outbound-queue-primitives", "snowbridge-pallet-system-frontend", + "snowbridge-runtime-common", "sp-api 26.0.0", "sp-block-builder", "sp-consensus-aura", @@ -22134,7 +22135,9 @@ name = "snowbridge-runtime-common" version = "0.2.0" dependencies = [ "frame-support", + "frame-system", "log", + "pallet-xcm", "parity-scale-codec", "snowbridge-core", "snowbridge-outbound-queue-primitives", diff --git a/bridges/snowbridge/runtime/runtime-common/Cargo.toml b/bridges/snowbridge/runtime/runtime-common/Cargo.toml index cc1b3c5427cef..121fba6664555 100644 --- a/bridges/snowbridge/runtime/runtime-common/Cargo.toml +++ b/bridges/snowbridge/runtime/runtime-common/Cargo.toml @@ -17,16 +17,17 @@ exclude-from-umbrella = true [dependencies] codec = { workspace = true } frame-support = { workspace = true } +frame-system = { workspace = true } log = { workspace = true } +pallet-xcm = { workspace = true } +snowbridge-core = { workspace = true } +snowbridge-outbound-queue-primitives = { workspace = true } sp-arithmetic = { workspace = true } sp-std = { workspace = true } xcm = { workspace = true } xcm-builder = { workspace = true } xcm-executor = { workspace = true } -snowbridge-core = { workspace = true } -snowbridge-outbound-queue-primitives = { workspace = true } - [dev-dependencies] [features] @@ -34,7 +35,9 @@ default = ["std"] std = [ "codec/std", "frame-support/std", + "frame-system/std", "log/std", + "pallet-xcm/std", "snowbridge-core/std", "snowbridge-outbound-queue-primitives/std", "sp-arithmetic/std", @@ -45,8 +48,15 @@ std = [ ] runtime-benchmarks = [ "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "pallet-xcm/runtime-benchmarks", "snowbridge-core/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", "xcm/runtime-benchmarks", ] +try-runtime = [ + "frame-support/try-runtime", + "frame-system/try-runtime", + "pallet-xcm/try-runtime", +] diff --git a/bridges/snowbridge/runtime/runtime-common/src/lib.rs b/bridges/snowbridge/runtime/runtime-common/src/lib.rs index 9e96ceb4a9ec2..479a1b34008ee 100644 --- a/bridges/snowbridge/runtime/runtime-common/src/lib.rs +++ b/bridges/snowbridge/runtime/runtime-common/src/lib.rs @@ -4,149 +4,9 @@ //! //! Common traits and types shared by runtimes. #![cfg_attr(not(feature = "std"), no_std)] - #[cfg(test)] mod tests; - -use codec::FullCodec; -use core::marker::PhantomData; -use frame_support::traits::Get; -use snowbridge_outbound_queue_primitives::SendMessageFeeProvider; -use sp_arithmetic::traits::{BaseArithmetic, Unsigned}; -use sp_std::fmt::Debug; -use xcm::prelude::*; -use xcm_builder::HandleFee; -use xcm_executor::traits::{FeeReason, TransactAsset}; - -pub const LOG_TARGET: &str = "xcm::export-fee-to-sibling"; - -/// A `HandleFee` implementation that takes fees from `ExportMessage` XCM instructions -/// to Snowbridge and splits off the remote fee and deposits it to the origin -/// parachain sovereign account. The local fee is then returned back to be handled by -/// the next fee handler in the chain. Most likely the treasury account. -pub struct XcmExportFeeToSibling< - Balance, - AccountId, - FeeAssetLocation, - EthereumNetwork, - AssetTransactor, - FeeProvider, ->( - PhantomData<( - Balance, - AccountId, - FeeAssetLocation, - EthereumNetwork, - AssetTransactor, - FeeProvider, - )>, -); - -impl HandleFee - for XcmExportFeeToSibling< - Balance, - AccountId, - FeeAssetLocation, - EthereumNetwork, - AssetTransactor, - FeeProvider, - > -where - Balance: BaseArithmetic + Unsigned + Copy + From + Into + Debug, - AccountId: Clone + FullCodec, - FeeAssetLocation: Get, - EthereumNetwork: Get, - AssetTransactor: TransactAsset, - FeeProvider: SendMessageFeeProvider, -{ - fn handle_fee(fees: Assets, context: Option<&XcmContext>, reason: FeeReason) -> Assets { - let token_location = FeeAssetLocation::get(); - - // Check the reason to see if this export is for snowbridge. - if !matches!( - reason, - FeeReason::Export { network: bridged_network, ref destination } - if bridged_network == EthereumNetwork::get() && destination == &Here - ) { - return fees - } - - // Get the parachain sovereign from the `context`. - let maybe_para_id: Option = - if let Some(XcmContext { origin: Some(Location { parents: 1, interior }), .. }) = - context - { - if let Some(Parachain(sibling_para_id)) = interior.first() { - Some(*sibling_para_id) - } else { - None - } - } else { - None - }; - if maybe_para_id.is_none() { - log::error!( - target: LOG_TARGET, - "invalid location in context {:?}", - context, - ); - return fees - } - let para_id = maybe_para_id.unwrap(); - - // Get the total fee offered by export message. - let maybe_total_supplied_fee: Option<(usize, Balance)> = fees - .inner() - .iter() - .enumerate() - .filter_map(|(index, asset)| { - if let Asset { id: location, fun: Fungible(amount) } = asset { - if location.0 == token_location { - return Some((index, (*amount).into())) - } - } - None - }) - .next(); - if maybe_total_supplied_fee.is_none() { - log::error!( - target: LOG_TARGET, - "could not find fee asset item in fees: {:?}", - fees, - ); - return fees - } - let (fee_index, total_fee) = maybe_total_supplied_fee.unwrap(); - let local_fee = FeeProvider::local_fee(); - let remote_fee = total_fee.saturating_sub(local_fee); - if local_fee == Balance::zero() || remote_fee == Balance::zero() { - log::error!( - target: LOG_TARGET, - "calculated refund incorrect with local_fee: {:?} and remote_fee: {:?}", - local_fee, - remote_fee, - ); - return fees - } - // Refund remote component of fee to physical origin - let result = AssetTransactor::deposit_asset( - &Asset { id: AssetId(token_location.clone()), fun: Fungible(remote_fee.into()) }, - &Location::new(1, [Parachain(para_id)]), - context, - ); - if result.is_err() { - log::error!( - target: LOG_TARGET, - "transact fee asset failed: {:?}", - result.unwrap_err() - ); - return fees - } - - // 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(Asset { id: AssetId(token_location), fun: Fungible(local_fee.into()) }); - modified_fees.into() - } -} +pub mod v1; +pub mod v2; +pub use v1::fee_handler::XcmExportFeeToSibling; +pub use v2::register_token::{ForeignAssetOwner, LocalAssetOwner}; diff --git a/bridges/snowbridge/runtime/runtime-common/src/v1/fee_handler.rs b/bridges/snowbridge/runtime/runtime-common/src/v1/fee_handler.rs new file mode 100644 index 0000000000000..fa2b9486f2cd8 --- /dev/null +++ b/bridges/snowbridge/runtime/runtime-common/src/v1/fee_handler.rs @@ -0,0 +1,146 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2023 Snowfork +//! Handling of fees for `ExportMessage` on BridgeHub in V1. + +use codec::FullCodec; +use core::marker::PhantomData; +use frame_support::traits::Get; +use snowbridge_outbound_queue_primitives::SendMessageFeeProvider; +use sp_arithmetic::traits::{BaseArithmetic, Unsigned}; +use sp_std::fmt::Debug; +use xcm::prelude::*; +use xcm_builder::HandleFee; +use xcm_executor::traits::{FeeReason, TransactAsset}; + +pub const LOG_TARGET: &str = "xcm::export-fee-to-sibling"; + +/// A `HandleFee` implementation that takes fees from `ExportMessage` XCM instructions +/// to Snowbridge and splits off the remote fee and deposits it to the origin +/// parachain sovereign account. The local fee is then returned back to be handled by +/// the next fee handler in the chain. Most likely the treasury account. +pub struct XcmExportFeeToSibling< + Balance, + AccountId, + FeeAssetLocation, + EthereumNetwork, + AssetTransactor, + FeeProvider, +>( + PhantomData<( + Balance, + AccountId, + FeeAssetLocation, + EthereumNetwork, + AssetTransactor, + FeeProvider, + )>, +); + +impl HandleFee + for XcmExportFeeToSibling< + Balance, + AccountId, + FeeAssetLocation, + EthereumNetwork, + AssetTransactor, + FeeProvider, + > +where + Balance: BaseArithmetic + Unsigned + Copy + From + Into + Debug, + AccountId: Clone + FullCodec, + FeeAssetLocation: Get, + EthereumNetwork: Get, + AssetTransactor: TransactAsset, + FeeProvider: SendMessageFeeProvider, +{ + fn handle_fee(fees: Assets, context: Option<&XcmContext>, reason: FeeReason) -> Assets { + let token_location = FeeAssetLocation::get(); + + // Check the reason to see if this export is for snowbridge. + if !matches!( + reason, + FeeReason::Export { network: bridged_network, ref destination } + if bridged_network == EthereumNetwork::get() && destination == &Here + ) { + return fees + } + + // Get the parachain sovereign from the `context`. + let maybe_para_id: Option = + if let Some(XcmContext { origin: Some(Location { parents: 1, interior }), .. }) = + context + { + if let Some(Parachain(sibling_para_id)) = interior.first() { + Some(*sibling_para_id) + } else { + None + } + } else { + None + }; + if maybe_para_id.is_none() { + log::error!( + target: LOG_TARGET, + "invalid location in context {:?}", + context, + ); + return fees + } + let para_id = maybe_para_id.unwrap(); + + // Get the total fee offered by export message. + let maybe_total_supplied_fee: Option<(usize, Balance)> = fees + .inner() + .iter() + .enumerate() + .filter_map(|(index, asset)| { + if let Asset { id: location, fun: Fungible(amount) } = asset { + if location.0 == token_location { + return Some((index, (*amount).into())) + } + } + None + }) + .next(); + if maybe_total_supplied_fee.is_none() { + log::error!( + target: LOG_TARGET, + "could not find fee asset item in fees: {:?}", + fees, + ); + return fees + } + let (fee_index, total_fee) = maybe_total_supplied_fee.unwrap(); + let local_fee = FeeProvider::local_fee(); + let remote_fee = total_fee.saturating_sub(local_fee); + if local_fee == Balance::zero() || remote_fee == Balance::zero() { + log::error!( + target: LOG_TARGET, + "calculated refund incorrect with local_fee: {:?} and remote_fee: {:?}", + local_fee, + remote_fee, + ); + return fees + } + // Refund remote component of fee to physical origin + let result = AssetTransactor::deposit_asset( + &Asset { id: AssetId(token_location.clone()), fun: Fungible(remote_fee.into()) }, + &Location::new(1, [Parachain(para_id)]), + context, + ); + if result.is_err() { + log::error!( + target: LOG_TARGET, + "transact fee asset failed: {:?}", + result.unwrap_err() + ); + return fees + } + + // 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(Asset { id: AssetId(token_location), fun: Fungible(local_fee.into()) }); + modified_fees.into() + } +} diff --git a/bridges/snowbridge/runtime/runtime-common/src/v1/mod.rs b/bridges/snowbridge/runtime/runtime-common/src/v1/mod.rs new file mode 100644 index 0000000000000..eee91c7a38d90 --- /dev/null +++ b/bridges/snowbridge/runtime/runtime-common/src/v1/mod.rs @@ -0,0 +1,3 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2023 Snowfork +pub mod fee_handler; diff --git a/bridges/snowbridge/runtime/runtime-common/src/v2/mod.rs b/bridges/snowbridge/runtime/runtime-common/src/v2/mod.rs new file mode 100644 index 0000000000000..7b882430af59d --- /dev/null +++ b/bridges/snowbridge/runtime/runtime-common/src/v2/mod.rs @@ -0,0 +1,3 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2023 Snowfork +pub mod register_token; diff --git a/bridges/snowbridge/runtime/runtime-common/src/v2/register_token.rs b/bridges/snowbridge/runtime/runtime-common/src/v2/register_token.rs new file mode 100644 index 0000000000000..16860c5483b68 --- /dev/null +++ b/bridges/snowbridge/runtime/runtime-common/src/v2/register_token.rs @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2023 Snowfork + +use frame_support::{ + dispatch::RawOrigin, + sp_runtime::traits::MaybeEquivalence, + traits::{ContainsPair, EnsureOrigin, EnsureOriginWithArg, Everything, OriginTrait}, +}; +use frame_system::ensure_signed; +use pallet_xcm::{EnsureXcm, Origin as XcmOrigin}; +use xcm::prelude::Location; + +/// Origin check that verifies that an origin is the owner of a foreign asset. +/// 1. Allows XCM origins +/// 2. Checks that the asset exists +/// 3. The origin must be the owner of the asset +pub struct ForeignAssetOwner( + core::marker::PhantomData<(IsForeign, AssetInspect, AccountId, LocationToAccountId, L)>, +); +impl< + IsForeign: ContainsPair, + AssetInspect: frame_support::traits::fungibles::roles::Inspect, + AccountId: Eq + Clone, + LocationToAccountId: xcm_executor::traits::ConvertLocation, + RuntimeOrigin: From + OriginTrait + Clone, + L: From + Into + Clone, + > EnsureOriginWithArg + for ForeignAssetOwner +where + RuntimeOrigin::PalletsOrigin: + From + TryInto, + >::AssetId: From, +{ + type Success = L; + + fn try_origin( + origin: RuntimeOrigin, + asset_location: &L, + ) -> Result { + let origin_location = EnsureXcm::::try_origin(origin.clone())?; + if !IsForeign::contains(asset_location, &origin_location) { + return Err(origin) + } + let asset_location: Location = asset_location.clone().into(); + let owner = AssetInspect::owner(asset_location.into()); + let location: Location = origin_location.clone().into(); + let from = LocationToAccountId::convert_location(&location); + if from != owner { + return Err(origin) + } + Ok(location.into()) + } + + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin(a: &L) -> Result { + let latest_location: Location = (*a).clone().try_into().map_err(|_| ())?; + Ok(pallet_xcm::Origin::Xcm(latest_location).into()) + } +} + +/// Origin check that verifies that an origin is the owner of a local trusted asset. +/// 1. Allows signed origins +/// 2. Checks that the asset exists +/// 3. The origin must be the owner of the asset +pub struct LocalAssetOwner( + core::marker::PhantomData<(MatchAssetId, AssetInspect, AccountId, AssetId, L)>, +); +impl< + MatchAssetId: MaybeEquivalence, + AssetInspect: frame_support::traits::fungibles::roles::Inspect, + AccountId: Eq + Clone + Into, + AssetId: Eq + Clone, + RuntimeOrigin: OriginTrait + Clone, + L: From + Into + Clone, + > EnsureOriginWithArg + for LocalAssetOwner +where + RuntimeOrigin: Into, RuntimeOrigin>> + From>, + >::AssetId: From, +{ + type Success = L; + + fn try_origin( + origin: RuntimeOrigin, + asset_location: &L, + ) -> Result { + let who = ensure_signed(origin.clone()).map_err(|_| origin.clone())?; + let asset_id = MatchAssetId::convert(asset_location).ok_or(origin.clone())?; + let owner = AssetInspect::owner(asset_id.into()).ok_or(origin.clone())?; + if who != owner { + return Err(origin) + } + Ok(who.into()) + } + + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin(_: &L) -> Result { + Ok(RawOrigin::Root.into()) + } +} diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/snowbridge_v2_outbound.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/snowbridge_v2_outbound.rs index 295d761ff0364..82ba7f15a259d 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/snowbridge_v2_outbound.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/snowbridge_v2_outbound.rs @@ -13,7 +13,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::{imports::*, tests::snowbridge_common::*}; +use crate::{ + imports::*, + tests::{snowbridge_common::*, usdt_at_ah_westend}, +}; use bridge_hub_westend_runtime::{ bridge_to_ethereum_config::EthereumGatewayAddress, EthereumOutboundQueueV2, }; @@ -140,8 +143,8 @@ pub fn register_relay_token_from_asset_hub_with_sudo() { }); } -#[allow(dead_code)] -pub fn register_relay_token_from_asset_hub_user_origin() { +#[test] +pub fn register_usdt_from_owner_on_asset_hub() { fund_on_bh(); register_assets_on_ah(); fund_on_ah(); @@ -150,13 +153,13 @@ pub fn register_relay_token_from_asset_hub_user_origin() { assert_ok!( ::SnowbridgeSystemFrontend::register_token( - RuntimeOrigin::signed(AssetHubWestendSender::get()), - bx!(VersionedLocation::from(Location { parents: 1, interior: [].into() })), + RuntimeOrigin::signed(AssetHubWestendAssetOwner::get()), + bx!(VersionedLocation::from(usdt_at_ah_westend())), AssetMetadata { - name: "wnd".as_bytes().to_vec().try_into().unwrap(), - symbol: "wnd".as_bytes().to_vec().try_into().unwrap(), - decimals: 12, - }, + name: "usdt".as_bytes().to_vec().try_into().unwrap(), + symbol: "usdt".as_bytes().to_vec().try_into().unwrap(), + decimals: 6, + } ) ); }); diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/snowbridge_v2_outbound_edge_case.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/snowbridge_v2_outbound_edge_case.rs index 8b0098b5aecea..ece58f762e2a3 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/snowbridge_v2_outbound_edge_case.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/snowbridge_v2_outbound_edge_case.rs @@ -1,6 +1,9 @@ // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 +use frame_support::assert_noop; +use snowbridge_core::AssetMetadata; +use sp_runtime::DispatchError::BadOrigin; // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at @@ -18,6 +21,7 @@ use crate::{ tests::{ snowbridge_common::*, snowbridge_v2_outbound::{EthereumSystemFrontend, EthereumSystemFrontendCall}, + usdt_at_ah_westend, }, }; use xcm::v5::AssetTransferFilter; @@ -167,3 +171,50 @@ fn export_from_non_system_parachain_will_fail() { ); }); } + +#[test] +pub fn register_usdt_not_from_owner_on_asset_hub_will_fail() { + fund_on_bh(); + register_assets_on_ah(); + fund_on_ah(); + AssetHubWestend::execute_with(|| { + type RuntimeOrigin = ::RuntimeOrigin; + + assert_noop!( + ::SnowbridgeSystemFrontend::register_token( + // The owner is Alice, while AssetHubWestendReceiver is Bob, so it should fail + RuntimeOrigin::signed(AssetHubWestendReceiver::get()), + bx!(VersionedLocation::from(usdt_at_ah_westend())), + AssetMetadata { + name: "usdt".as_bytes().to_vec().try_into().unwrap(), + symbol: "usdt".as_bytes().to_vec().try_into().unwrap(), + decimals: 6, + } + ), + BadOrigin + ); + }); +} + +#[test] +pub fn register_relay_token_from_asset_hub_user_origin_will_fail() { + fund_on_bh(); + register_assets_on_ah(); + fund_on_ah(); + AssetHubWestend::execute_with(|| { + type RuntimeOrigin = ::RuntimeOrigin; + + assert_noop!( + ::SnowbridgeSystemFrontend::register_token( + RuntimeOrigin::signed(AssetHubWestendSender::get()), + bx!(VersionedLocation::from(Location { parents: 1, interior: [].into() })), + AssetMetadata { + name: "wnd".as_bytes().to_vec().try_into().unwrap(), + symbol: "wnd".as_bytes().to_vec().try_into().unwrap(), + decimals: 12, + }, + ), + BadOrigin + ); + }); +} diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/snowbridge_v2_outbound_from_rococo.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/snowbridge_v2_outbound_from_rococo.rs index 10d60b5bd39a3..dd4d042b8fd4e 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/snowbridge_v2_outbound_from_rococo.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/snowbridge_v2_outbound_from_rococo.rs @@ -345,6 +345,14 @@ fn register_rococo_asset_on_ethereum_from_rah() { ], ); + AssetHubWestend::force_create_foreign_asset( + bridged_asset_at_wah.clone(), + sa_of_rah_on_wah.clone(), + true, + ASSET_MIN_BALANCE, + vec![], + ); + let call = EthereumSystemFrontend::EthereumSystemFrontend(EthereumSystemFrontendCall::RegisterToken { asset_id: Box::new(VersionedLocation::from(bridged_asset_at_wah.clone())), diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml index 419a16c94c8bd..497c6ee096b9f 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml @@ -110,6 +110,7 @@ pallet-xcm-bridge-hub-router = { workspace = true } snowbridge-inbound-queue-primitives = { workspace = true } snowbridge-outbound-queue-primitives = { workspace = true } snowbridge-pallet-system-frontend = { workspace = true } +snowbridge-runtime-common = { workspace = true } [dev-dependencies] asset-test-utils = { workspace = true, default-features = true } @@ -160,6 +161,7 @@ runtime-benchmarks = [ "polkadot-runtime-common/runtime-benchmarks", "snowbridge-inbound-queue-primitives/runtime-benchmarks", "snowbridge-pallet-system-frontend/runtime-benchmarks", + "snowbridge-runtime-common/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", @@ -204,6 +206,7 @@ try-runtime = [ "parachain-info/try-runtime", "polkadot-runtime-common/try-runtime", "snowbridge-pallet-system-frontend/try-runtime", + "snowbridge-runtime-common/try-runtime", "sp-runtime/try-runtime", ] std = [ @@ -269,6 +272,7 @@ std = [ "snowbridge-inbound-queue-primitives/std", "snowbridge-outbound-queue-primitives/std", "snowbridge-pallet-system-frontend/std", + "snowbridge-runtime-common/std", "sp-api/std", "sp-block-builder/std", "sp-consensus-aura/std", diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/bridge_to_ethereum_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/bridge_to_ethereum_config.rs index 778deb136ff3f..aa5a96cc7036d 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/bridge_to_ethereum_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/bridge_to_ethereum_config.rs @@ -15,25 +15,25 @@ use crate::{ weights, xcm_config, - xcm_config::{AssetTransactors, XcmConfig}, - Runtime, RuntimeEvent, + xcm_config::{ + AssetTransactors, LocationToAccountId, TrustBackedAssetsPalletLocation, UniversalLocation, + XcmConfig, + }, + AccountId, Assets, ForeignAssets, Runtime, RuntimeEvent, }; -use assets_common::matching::FromSiblingParachain; -use frame_support::{parameter_types, traits::Everything}; -use pallet_xcm::{EnsureXcm, Origin as XcmOrigin}; +use assets_common::{matching::FromSiblingParachain, AssetIdForTrustBackedAssetsConvert}; +use frame_support::{parameter_types, traits::EitherOf}; +use frame_system::EnsureRootWithSuccess; +use parachains_common::AssetIdForTrustBackedAssets; +use snowbridge_runtime_common::{ForeignAssetOwner, LocalAssetOwner}; use testnet_parachains_constants::westend::snowbridge::EthereumNetwork; use xcm::prelude::{Asset, InteriorLocation, Location, PalletInstance, Parachain}; use xcm_executor::XcmExecutor; -use crate::xcm_config::UniversalLocation; #[cfg(not(feature = "runtime-benchmarks"))] use crate::xcm_config::XcmRouter; #[cfg(feature = "runtime-benchmarks")] use benchmark_helpers::DoNothingRouter; -use frame_support::traits::{ - ContainsPair, EitherOf, EnsureOrigin, EnsureOriginWithArg, OriginTrait, -}; -use frame_system::EnsureRootWithSuccess; #[cfg(feature = "runtime-benchmarks")] pub mod benchmark_helpers { @@ -83,14 +83,26 @@ impl snowbridge_pallet_system_frontend::Config for Runtime { #[cfg(feature = "runtime-benchmarks")] type Helper = (); type RegisterTokenOrigin = EitherOf< - ForeignTokenCreator< - ( - FromSiblingParachain, Location>, - xcm_config::bridging::to_rococo::RococoAssetFromAssetHubRococo, - ), - Location, + EitherOf< + LocalAssetOwner< + AssetIdForTrustBackedAssetsConvert, + Assets, + AccountId, + AssetIdForTrustBackedAssets, + Location, + >, + ForeignAssetOwner< + ( + FromSiblingParachain, Location>, + xcm_config::bridging::to_rococo::RococoAssetFromAssetHubRococo, + ), + ForeignAssets, + AccountId, + LocationToAccountId, + Location, + >, >, - EnsureRootWithSuccess, + EnsureRootWithSuccess, >; #[cfg(not(feature = "runtime-benchmarks"))] type XcmSender = XcmRouter; @@ -104,36 +116,3 @@ impl snowbridge_pallet_system_frontend::Config for Runtime { type PalletLocation = SystemFrontendPalletLocation; type BackendWeightInfo = weights::snowbridge_pallet_system_backend::WeightInfo; } - -/// `EnsureOriginWithArg` impl for `ForeignTokenCreator` that allows only XCM origins that are -/// locations containing the class location. -pub struct ForeignTokenCreator(core::marker::PhantomData<(IsForeign, L)>); -impl< - IsForeign: ContainsPair, - RuntimeOrigin: From + OriginTrait + Clone, - L: TryFrom + TryInto + Clone, - > EnsureOriginWithArg for ForeignTokenCreator -where - RuntimeOrigin::PalletsOrigin: - From + TryInto, -{ - type Success = Location; - - fn try_origin( - origin: RuntimeOrigin, - asset_location: &L, - ) -> Result { - let origin_location = EnsureXcm::::try_origin(origin.clone())?; - if !IsForeign::contains(asset_location, &origin_location) { - return Err(origin) - } - let latest_location: Location = origin_location.clone().try_into().map_err(|_| origin)?; - Ok(latest_location) - } - - #[cfg(feature = "runtime-benchmarks")] - fn try_successful_origin(a: &L) -> Result { - let latest_location: Location = (*a).clone().try_into().map_err(|_| ())?; - Ok(pallet_xcm::Origin::Xcm(latest_location).into()) - } -} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs index b781191e93198..699e403e179d9 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs @@ -42,7 +42,6 @@ use bridge_runtime_common::extensions::{ }; use cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases; use cumulus_primitives_core::{ClaimQueueOffset, CoreSelector, ParaId}; -use frame_support::traits::Contains; use sp_api::impl_runtime_apis; use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; use sp_runtime::{ diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs index 84362abe33f57..dc6261b4874a1 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs @@ -220,7 +220,7 @@ impl xcm_executor::Config for XcmConfig { WestendLocation, EthereumNetwork, Self::AssetTransactor, - crate::EthereumOutboundQueueV2, + crate::EthereumOutboundQueue, >, SendXcmFeeToAccount, ),