// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // 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 // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. use super::{ AccountId, AllPalletsWithSystem, Assets, Authorship, Balance, Balances, BaseDeliveryFee, FeeAssetId, ForeignAssets, ForeignAssetsInstance, ParachainInfo, ParachainSystem, PolkadotXcm, PoolAssets, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, ToRococoXcmRouter, TransactionByteFee, TrustBackedAssetsInstance, WeightToFee, XcmpQueue, }; use assets_common::{ local_and_foreign_assets::MatchesLocalAndForeignAssetsMultiLocation, matching::{FromSiblingParachain, IsForeignConcreteAsset}, }; use frame_support::{ match_types, parameter_types, traits::{ConstU32, Contains, Equals, Everything, Nothing, PalletInfoAccess}, }; use frame_system::EnsureRoot; use pallet_xcm::XcmPassthrough; use parachains_common::{ impls::ToStakingPot, xcm_config::{ AssetFeeAsExistentialDepositMultiplier, ConcreteAssetFromSystem, RelayOrOtherSystemParachains, }, TREASURY_PALLET_ID, }; use polkadot_parachain_primitives::primitives::Sibling; use polkadot_runtime_common::xcm_sender::ExponentialPrice; use sp_runtime::traits::{AccountIdConversion, ConvertInto}; use westend_runtime_constants::system_parachain; use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, CurrencyAdapter, DenyReserveTransferToRelayChain, DenyThenTry, DescribeFamily, DescribePalletTerminal, EnsureXcmOrigin, FungiblesAdapter, GlobalConsensusParachainConvertsFor, HashedDescription, IsConcrete, LocalMint, NetworkExportTableItem, NoChecking, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, StartsWith, StartsWithExplicitGlobalConsensus, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, XcmFeeManagerFromComponents, XcmFeeToAccount, }; use xcm_executor::{traits::WithOriginFilter, XcmExecutor}; #[cfg(feature = "runtime-benchmarks")] use {cumulus_primitives_core::ParaId, sp_core::Get}; parameter_types! { pub const WestendLocation: MultiLocation = MultiLocation::parent(); pub const RelayNetwork: Option = Some(NetworkId::Westend); pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); pub UniversalLocation: InteriorMultiLocation = X2(GlobalConsensus(RelayNetwork::get().unwrap()), Parachain(ParachainInfo::parachain_id().into())); pub UniversalLocationNetworkId: NetworkId = UniversalLocation::get().global_consensus().unwrap(); pub TrustBackedAssetsPalletLocation: MultiLocation = PalletInstance(::index() as u8).into(); pub ForeignAssetsPalletLocation: MultiLocation = PalletInstance(::index() as u8).into(); pub PoolAssetsPalletLocation: MultiLocation = PalletInstance(::index() as u8).into(); pub CheckingAccount: AccountId = PolkadotXcm::check_account(); pub TreasuryAccount: AccountId = TREASURY_PALLET_ID.into_account_truncating(); pub RelayTreasuryLocation: MultiLocation = (Parent, PalletInstance(westend_runtime_constants::TREASURY_PALLET_ID)).into(); } /// Type for specifying how a `MultiLocation` can be converted into an `AccountId`. This is used /// when determining ownership of accounts for asset transacting and when attempting to use XCM /// `Transact` in order to determine the dispatch Origin. pub type LocationToAccountId = ( // The parent (Relay-chain) origin converts to the parent `AccountId`. ParentIsPreset, // Sibling parachain origins convert to AccountId via the `ParaId::into`. SiblingParachainConvertsVia, // Straight up local `AccountId32` origins just alias directly to `AccountId`. AccountId32Aliases, // Foreign chain account alias into local accounts according to a hash of their standard // description. HashedDescription>, // Different global consensus parachain sovereign account. // (Used for over-bridge transfers and reserve processing) GlobalConsensusParachainConvertsFor, ); /// Means for transacting the native currency on this chain. pub type CurrencyTransactor = CurrencyAdapter< // Use this currency: Balances, // Use this currency when it is a fungible asset matching the given location or name: IsConcrete, // Convert an XCM MultiLocation into a local account id: LocationToAccountId, // Our chain's account ID type (we can't get away without mentioning it explicitly): AccountId, // We don't track any teleports of `Balances`. (), >; /// `AssetId/Balance` converter for `TrustBackedAssets` pub type TrustBackedAssetsConvertedConcreteId = assets_common::TrustBackedAssetsConvertedConcreteId; /// Means for transacting assets besides the native currency on this chain. pub type FungiblesTransactor = FungiblesAdapter< // Use this fungibles implementation: Assets, // Use this currency when it is a fungible asset matching the given location or name: TrustBackedAssetsConvertedConcreteId, // Convert an XCM MultiLocation into a local account id: LocationToAccountId, // Our chain's account ID type (we can't get away without mentioning it explicitly): AccountId, // We only want to allow teleports of known assets. We use non-zero issuance as an indication // that this asset is known. LocalMint>, // The account to use for tracking teleports. CheckingAccount, >; /// `AssetId/Balance` converter for `TrustBackedAssets` pub type ForeignAssetsConvertedConcreteId = assets_common::ForeignAssetsConvertedConcreteId< ( // Ignore `TrustBackedAssets` explicitly StartsWith, // Ignore asset which starts explicitly with our `GlobalConsensus(NetworkId)`, means: // - foreign assets from our consensus should be: `MultiLocation {parents: 1, // X*(Parachain(xyz), ..)} // - foreign assets outside our consensus with the same `GlobalConsensus(NetworkId)` wont // be accepted here StartsWithExplicitGlobalConsensus, ), Balance, >; /// Means for transacting foreign assets from different global consensus. pub type ForeignFungiblesTransactor = FungiblesAdapter< // Use this fungibles implementation: ForeignAssets, // Use this currency when it is a fungible asset matching the given location or name: ForeignAssetsConvertedConcreteId, // Convert an XCM MultiLocation into a local account id: LocationToAccountId, // Our chain's account ID type (we can't get away without mentioning it explicitly): AccountId, // We dont need to check teleports here. NoChecking, // The account to use for tracking teleports. CheckingAccount, >; /// `AssetId`/`Balance` converter for `PoolAssets`. pub type PoolAssetsConvertedConcreteId = assets_common::PoolAssetsConvertedConcreteId; /// Means for transacting asset conversion pool assets on this chain. pub type PoolFungiblesTransactor = FungiblesAdapter< // Use this fungibles implementation: PoolAssets, // Use this currency when it is a fungible asset matching the given location or name: PoolAssetsConvertedConcreteId, // Convert an XCM MultiLocation into a local account id: LocationToAccountId, // Our chain's account ID type (we can't get away without mentioning it explicitly): AccountId, // We only want to allow teleports of known assets. We use non-zero issuance as an indication // that this asset is known. LocalMint>, // The account to use for tracking teleports. CheckingAccount, >; /// Means for transacting assets on this chain. pub type AssetTransactors = (CurrencyTransactor, FungiblesTransactor, ForeignFungiblesTransactor, PoolFungiblesTransactor); /// Simple `MultiLocation` matcher for Local and Foreign asset `MultiLocation`. pub struct LocalAndForeignAssetsMultiLocationMatcher; impl MatchesLocalAndForeignAssetsMultiLocation for LocalAndForeignAssetsMultiLocationMatcher { fn is_local(location: &MultiLocation) -> bool { use assets_common::fungible_conversion::MatchesMultiLocation; TrustBackedAssetsConvertedConcreteId::contains(location) } fn is_foreign(location: &MultiLocation) -> bool { use assets_common::fungible_conversion::MatchesMultiLocation; ForeignAssetsConvertedConcreteId::contains(location) } } impl Contains for LocalAndForeignAssetsMultiLocationMatcher { fn contains(location: &MultiLocation) -> bool { Self::is_local(location) || Self::is_foreign(location) } } /// This is the type we use to convert an (incoming) XCM origin into a local `Origin` instance, /// ready for dispatching a transaction with Xcm's `Transact`. There is an `OriginKind` which can /// biases the kind of local `Origin` it will become. pub type XcmOriginToTransactDispatchOrigin = ( // Sovereign account converter; this attempts to derive an `AccountId` from the origin location // using `LocationToAccountId` and then turn that into the usual `Signed` origin. Useful for // foreign chains who want to have a local sovereign account on this chain which they control. SovereignSignedViaLocation, // Native converter for Relay-chain (Parent) location; will convert to a `Relay` origin when // recognised. RelayChainAsNative, // Native converter for sibling Parachains; will convert to a `SiblingPara` origin when // recognised. SiblingParachainAsNative, // Superuser converter for the Relay-chain (Parent) location. This will allow it to issue a // transaction from the Root origin. ParentAsSuperuser, // Native signed account converter; this just converts an `AccountId32` origin into a normal // `RuntimeOrigin::Signed` origin of the same 32-byte value. SignedAccountId32AsNative, // Xcm origins can be represented natively under the Xcm pallet's Xcm origin. XcmPassthrough, ); parameter_types! { pub const MaxInstructions: u32 = 100; pub const MaxAssetsIntoHolding: u32 = 64; pub XcmAssetFeesReceiver: Option = Authorship::author(); } match_types! { pub type ParentOrParentsPlurality: impl Contains = { MultiLocation { parents: 1, interior: Here } | MultiLocation { parents: 1, interior: X1(Plurality { .. }) } }; } /// A call filter for the XCM Transact instruction. This is a temporary measure until we properly /// account for proof size weights. /// /// Calls that are allowed through this filter must: /// 1. Have a fixed weight; /// 2. Cannot lead to another call being made; /// 3. Have a defined proof size weight, e.g. no unbounded vecs in call parameters. pub struct SafeCallFilter; impl Contains for SafeCallFilter { fn contains(call: &RuntimeCall) -> bool { #[cfg(feature = "runtime-benchmarks")] { if matches!(call, RuntimeCall::System(frame_system::Call::remark_with_event { .. })) { return true } } // Allow to change dedicated storage items (called by governance-like) match call { RuntimeCall::System(frame_system::Call::set_storage { items }) if items.iter().all(|(k, _)| k.eq(&bridging::XcmBridgeHubRouterByteFee::key())) => return true, _ => (), }; matches!( call, RuntimeCall::PolkadotXcm(pallet_xcm::Call::force_xcm_version { .. }) | RuntimeCall::System( frame_system::Call::set_heap_pages { .. } | frame_system::Call::set_code { .. } | frame_system::Call::set_code_without_checks { .. } | frame_system::Call::kill_prefix { .. }, ) | RuntimeCall::ParachainSystem(..) | RuntimeCall::Timestamp(..) | RuntimeCall::Balances(..) | RuntimeCall::CollatorSelection( pallet_collator_selection::Call::set_desired_candidates { .. } | pallet_collator_selection::Call::set_candidacy_bond { .. } | pallet_collator_selection::Call::register_as_candidate { .. } | pallet_collator_selection::Call::leave_intent { .. } | pallet_collator_selection::Call::set_invulnerables { .. } | pallet_collator_selection::Call::add_invulnerable { .. } | pallet_collator_selection::Call::remove_invulnerable { .. }, ) | RuntimeCall::Session(pallet_session::Call::purge_keys { .. }) | RuntimeCall::XcmpQueue(..) | RuntimeCall::MessageQueue(..) | RuntimeCall::Assets( pallet_assets::Call::create { .. } | pallet_assets::Call::force_create { .. } | pallet_assets::Call::start_destroy { .. } | pallet_assets::Call::destroy_accounts { .. } | pallet_assets::Call::destroy_approvals { .. } | pallet_assets::Call::finish_destroy { .. } | pallet_assets::Call::block { .. } | pallet_assets::Call::mint { .. } | pallet_assets::Call::burn { .. } | pallet_assets::Call::transfer { .. } | pallet_assets::Call::transfer_keep_alive { .. } | pallet_assets::Call::force_transfer { .. } | pallet_assets::Call::freeze { .. } | pallet_assets::Call::thaw { .. } | pallet_assets::Call::freeze_asset { .. } | pallet_assets::Call::thaw_asset { .. } | pallet_assets::Call::transfer_ownership { .. } | pallet_assets::Call::set_team { .. } | pallet_assets::Call::set_metadata { .. } | pallet_assets::Call::clear_metadata { .. } | pallet_assets::Call::force_set_metadata { .. } | pallet_assets::Call::force_clear_metadata { .. } | pallet_assets::Call::force_asset_status { .. } | pallet_assets::Call::approve_transfer { .. } | pallet_assets::Call::cancel_approval { .. } | pallet_assets::Call::force_cancel_approval { .. } | pallet_assets::Call::transfer_approved { .. } | pallet_assets::Call::touch { .. } | pallet_assets::Call::touch_other { .. } | pallet_assets::Call::refund { .. } | pallet_assets::Call::refund_other { .. }, ) | RuntimeCall::ForeignAssets( pallet_assets::Call::create { .. } | pallet_assets::Call::force_create { .. } | pallet_assets::Call::start_destroy { .. } | pallet_assets::Call::destroy_accounts { .. } | pallet_assets::Call::destroy_approvals { .. } | pallet_assets::Call::finish_destroy { .. } | pallet_assets::Call::block { .. } | pallet_assets::Call::mint { .. } | pallet_assets::Call::burn { .. } | pallet_assets::Call::transfer { .. } | pallet_assets::Call::transfer_keep_alive { .. } | pallet_assets::Call::force_transfer { .. } | pallet_assets::Call::freeze { .. } | pallet_assets::Call::thaw { .. } | pallet_assets::Call::freeze_asset { .. } | pallet_assets::Call::thaw_asset { .. } | pallet_assets::Call::transfer_ownership { .. } | pallet_assets::Call::set_team { .. } | pallet_assets::Call::set_metadata { .. } | pallet_assets::Call::clear_metadata { .. } | pallet_assets::Call::force_set_metadata { .. } | pallet_assets::Call::force_clear_metadata { .. } | pallet_assets::Call::force_asset_status { .. } | pallet_assets::Call::approve_transfer { .. } | pallet_assets::Call::cancel_approval { .. } | pallet_assets::Call::force_cancel_approval { .. } | pallet_assets::Call::transfer_approved { .. } | pallet_assets::Call::touch { .. } | pallet_assets::Call::touch_other { .. } | pallet_assets::Call::refund { .. } | pallet_assets::Call::refund_other { .. }, ) | RuntimeCall::PoolAssets( pallet_assets::Call::create { .. } | pallet_assets::Call::force_create { .. } | pallet_assets::Call::start_destroy { .. } | pallet_assets::Call::destroy_accounts { .. } | pallet_assets::Call::destroy_approvals { .. } | pallet_assets::Call::finish_destroy { .. } | pallet_assets::Call::block { .. } | pallet_assets::Call::mint { .. } | pallet_assets::Call::burn { .. } | pallet_assets::Call::transfer { .. } | pallet_assets::Call::transfer_keep_alive { .. } | pallet_assets::Call::force_transfer { .. } | pallet_assets::Call::freeze { .. } | pallet_assets::Call::thaw { .. } | pallet_assets::Call::freeze_asset { .. } | pallet_assets::Call::thaw_asset { .. } | pallet_assets::Call::transfer_ownership { .. } | pallet_assets::Call::set_team { .. } | pallet_assets::Call::set_metadata { .. } | pallet_assets::Call::clear_metadata { .. } | pallet_assets::Call::force_set_metadata { .. } | pallet_assets::Call::force_clear_metadata { .. } | pallet_assets::Call::force_asset_status { .. } | pallet_assets::Call::approve_transfer { .. } | pallet_assets::Call::cancel_approval { .. } | pallet_assets::Call::force_cancel_approval { .. } | pallet_assets::Call::transfer_approved { .. } | pallet_assets::Call::touch { .. } | pallet_assets::Call::touch_other { .. } | pallet_assets::Call::refund { .. } | pallet_assets::Call::refund_other { .. }, ) | RuntimeCall::AssetConversion( pallet_asset_conversion::Call::create_pool { .. } | pallet_asset_conversion::Call::add_liquidity { .. } | pallet_asset_conversion::Call::remove_liquidity { .. } | pallet_asset_conversion::Call::swap_tokens_for_exact_tokens { .. } | pallet_asset_conversion::Call::swap_exact_tokens_for_tokens { .. }, ) | RuntimeCall::NftFractionalization( pallet_nft_fractionalization::Call::fractionalize { .. } | pallet_nft_fractionalization::Call::unify { .. }, ) | RuntimeCall::Nfts( pallet_nfts::Call::create { .. } | pallet_nfts::Call::force_create { .. } | pallet_nfts::Call::destroy { .. } | pallet_nfts::Call::mint { .. } | pallet_nfts::Call::force_mint { .. } | pallet_nfts::Call::burn { .. } | pallet_nfts::Call::transfer { .. } | pallet_nfts::Call::lock_item_transfer { .. } | pallet_nfts::Call::unlock_item_transfer { .. } | pallet_nfts::Call::lock_collection { .. } | pallet_nfts::Call::transfer_ownership { .. } | pallet_nfts::Call::set_team { .. } | pallet_nfts::Call::force_collection_owner { .. } | pallet_nfts::Call::force_collection_config { .. } | pallet_nfts::Call::approve_transfer { .. } | pallet_nfts::Call::cancel_approval { .. } | pallet_nfts::Call::clear_all_transfer_approvals { .. } | pallet_nfts::Call::lock_item_properties { .. } | pallet_nfts::Call::set_attribute { .. } | pallet_nfts::Call::force_set_attribute { .. } | pallet_nfts::Call::clear_attribute { .. } | pallet_nfts::Call::approve_item_attributes { .. } | pallet_nfts::Call::cancel_item_attributes_approval { .. } | pallet_nfts::Call::set_metadata { .. } | pallet_nfts::Call::clear_metadata { .. } | pallet_nfts::Call::set_collection_metadata { .. } | pallet_nfts::Call::clear_collection_metadata { .. } | pallet_nfts::Call::set_accept_ownership { .. } | pallet_nfts::Call::set_collection_max_supply { .. } | pallet_nfts::Call::update_mint_settings { .. } | pallet_nfts::Call::set_price { .. } | pallet_nfts::Call::buy_item { .. } | pallet_nfts::Call::pay_tips { .. } | pallet_nfts::Call::create_swap { .. } | pallet_nfts::Call::cancel_swap { .. } | pallet_nfts::Call::claim_swap { .. }, ) | RuntimeCall::Uniques( pallet_uniques::Call::create { .. } | pallet_uniques::Call::force_create { .. } | pallet_uniques::Call::destroy { .. } | pallet_uniques::Call::mint { .. } | pallet_uniques::Call::burn { .. } | pallet_uniques::Call::transfer { .. } | pallet_uniques::Call::freeze { .. } | pallet_uniques::Call::thaw { .. } | pallet_uniques::Call::freeze_collection { .. } | pallet_uniques::Call::thaw_collection { .. } | pallet_uniques::Call::transfer_ownership { .. } | pallet_uniques::Call::set_team { .. } | pallet_uniques::Call::approve_transfer { .. } | pallet_uniques::Call::cancel_approval { .. } | pallet_uniques::Call::force_item_status { .. } | pallet_uniques::Call::set_attribute { .. } | pallet_uniques::Call::clear_attribute { .. } | pallet_uniques::Call::set_metadata { .. } | pallet_uniques::Call::clear_metadata { .. } | pallet_uniques::Call::set_collection_metadata { .. } | pallet_uniques::Call::clear_collection_metadata { .. } | pallet_uniques::Call::set_accept_ownership { .. } | pallet_uniques::Call::set_collection_max_supply { .. } | pallet_uniques::Call::set_price { .. } | pallet_uniques::Call::buy_item { .. } ) | RuntimeCall::ToRococoXcmRouter( pallet_xcm_bridge_hub_router::Call::report_bridge_status { .. } ) ) } } pub type Barrier = TrailingSetTopicAsId< DenyThenTry< DenyReserveTransferToRelayChain, ( TakeWeightCredit, // Expected responses are OK. AllowKnownQueryResponses, // Allow XCMs with some computed origins to pass through. WithComputedOrigin< ( // If the message is one that immediately attempts to pay for execution, then // allow it. AllowTopLevelPaidExecutionFrom, // Parent, its pluralities (i.e. governance bodies), relay treasury pallet and // BridgeHub get free execution. AllowExplicitUnpaidExecutionFrom<( ParentOrParentsPlurality, Equals, Equals, )>, // Subscriptions for version tracking are OK. AllowSubscriptionsFrom, ), UniversalLocation, ConstU32<8>, >, ), >, >; // TODO: This calls into the Assets pallet's default `BalanceToAssetBalance` implementation, which // uses the ratio of minimum balances and requires asset sufficiency. This means that purchasing // weight within XCM programs will still use the old way, and paying fees via asset conversion will // only be possible when transacting locally. We should add an impl of this trait that does asset // conversion. pub type AssetFeeAsExistentialDepositMultiplierFeeCharger = AssetFeeAsExistentialDepositMultiplier< Runtime, WeightToFee, pallet_assets::BalanceToAssetBalance, TrustBackedAssetsInstance, >; /// Multiplier used for dedicated `TakeFirstAssetTrader` with `ForeignAssets` instance. pub type ForeignAssetFeeAsExistentialDepositMultiplierFeeCharger = AssetFeeAsExistentialDepositMultiplier< Runtime, WeightToFee, pallet_assets::BalanceToAssetBalance, ForeignAssetsInstance, >; match_types! { pub type SystemParachains: impl Contains = { MultiLocation { parents: 1, interior: X1(Parachain( system_parachain::ASSET_HUB_ID | system_parachain::COLLECTIVES_ID | system_parachain::BRIDGE_HUB_ID )), } }; } /// Locations that will not be charged fees in the executor, /// either execution or delivery. /// We only waive fees for system functions, which these locations represent. pub type WaivedLocations = (RelayOrOtherSystemParachains, Equals); /// Cases where a remote origin is accepted as trusted Teleporter for a given asset: /// /// - WND with the parent Relay Chain and sibling system parachains; and /// - Sibling parachains' assets from where they originate (as `ForeignCreators`). pub type TrustedTeleporters = ( ConcreteAssetFromSystem, IsForeignConcreteAsset>>, ); pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = XcmRouter; type AssetTransactor = AssetTransactors; type OriginConverter = XcmOriginToTransactDispatchOrigin; // Asset Hub trusts only particular, pre-configured bridged locations from a different consensus // as reserve locations (we trust the Bridge Hub to relay the message that a reserve is being // held). Asset Hub may _act_ as a reserve location for WND and assets created // under `pallet-assets`. Users must use teleport where allowed (e.g. WND with the Relay Chain). type IsReserve = (bridging::to_rococo::IsTrustedBridgedReserveLocationForConcreteAsset,); type IsTeleporter = TrustedTeleporters; type UniversalLocation = UniversalLocation; type Barrier = Barrier; type Weigher = WeightInfoBounds< crate::weights::xcm::AssetHubWestendXcmWeight, RuntimeCall, MaxInstructions, >; type Trader = ( UsingComponents>, // This trader allows to pay with `is_sufficient=true` "Trust Backed" assets from dedicated // `pallet_assets` instance - `Assets`. cumulus_primitives_utility::TakeFirstAssetTrader< AccountId, AssetFeeAsExistentialDepositMultiplierFeeCharger, TrustBackedAssetsConvertedConcreteId, Assets, cumulus_primitives_utility::XcmFeesTo32ByteAccount< FungiblesTransactor, AccountId, XcmAssetFeesReceiver, >, >, // This trader allows to pay with `is_sufficient=true` "Foreign" assets from dedicated // `pallet_assets` instance - `ForeignAssets`. cumulus_primitives_utility::TakeFirstAssetTrader< AccountId, ForeignAssetFeeAsExistentialDepositMultiplierFeeCharger, ForeignAssetsConvertedConcreteId, ForeignAssets, cumulus_primitives_utility::XcmFeesTo32ByteAccount< ForeignFungiblesTransactor, AccountId, XcmAssetFeesReceiver, >, >, ); type ResponseHandler = PolkadotXcm; type AssetTrap = PolkadotXcm; type AssetClaims = PolkadotXcm; type SubscriptionService = PolkadotXcm; type PalletInstancesInfo = AllPalletsWithSystem; type MaxAssetsIntoHolding = MaxAssetsIntoHolding; type AssetLocker = (); type AssetExchanger = (); type FeeManager = XcmFeeManagerFromComponents< WaivedLocations, XcmFeeToAccount, >; type MessageExporter = (); type UniversalAliases = (bridging::to_rococo::UniversalAliases,); type CallDispatcher = WithOriginFilter; type SafeCallFilter = SafeCallFilter; type Aliasers = Nothing; } /// Local origins on this chain are allowed to dispatch XCM sends/executions. pub type LocalOriginToLocation = SignedToAccountId32; pub type PriceForParentDelivery = ExponentialPrice; /// For routing XCM messages which do not cross local consensus boundary. type LocalXcmRouter = ( // Two routers - use UMP to communicate with the relay chain: cumulus_primitives_utility::ParentAsUmp, // ..and XCMP to communicate with the sibling chains. XcmpQueue, ); /// The means for routing XCM messages which are not for local execution into the right message /// queues. pub type XcmRouter = WithUniqueTopic<( LocalXcmRouter, // Router which wraps and sends xcm to BridgeHub to be delivered to the Rococo // GlobalConsensus ToRococoXcmRouter, )>; #[cfg(feature = "runtime-benchmarks")] parameter_types! { pub ReachableDest: Option = Some(Parent.into()); } impl pallet_xcm::Config for Runtime { type RuntimeEvent = RuntimeEvent; type SendXcmOrigin = EnsureXcmOrigin; type XcmRouter = XcmRouter; type ExecuteXcmOrigin = EnsureXcmOrigin; type XcmExecuteFilter = Everything; type XcmExecutor = XcmExecutor; type XcmTeleportFilter = Everything; type XcmReserveTransferFilter = Everything; type Weigher = WeightInfoBounds< crate::weights::xcm::AssetHubWestendXcmWeight, RuntimeCall, MaxInstructions, >; type UniversalLocation = UniversalLocation; type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; type Currency = Balances; type CurrencyMatcher = (); type TrustedLockers = (); type SovereignAccountOf = LocationToAccountId; type MaxLockers = ConstU32<8>; type WeightInfo = crate::weights::pallet_xcm::WeightInfo; #[cfg(feature = "runtime-benchmarks")] type ReachableDest = ReachableDest; type AdminOrigin = EnsureRoot; type MaxRemoteLockConsumers = ConstU32<0>; type RemoteLockConsumerIdentifier = (); } impl cumulus_pallet_xcm::Config for Runtime { type RuntimeEvent = RuntimeEvent; type XcmExecutor = XcmExecutor; } pub type ForeignCreatorsSovereignAccountOf = ( SiblingParachainConvertsVia, AccountId32Aliases, ParentIsPreset, ); /// Simple conversion of `u32` into an `AssetId` for use in benchmarking. pub struct XcmBenchmarkHelper; #[cfg(feature = "runtime-benchmarks")] impl pallet_assets::BenchmarkHelper for XcmBenchmarkHelper { fn create_asset_id_parameter(id: u32) -> MultiLocation { MultiLocation { parents: 1, interior: X1(Parachain(id)) } } } #[cfg(feature = "runtime-benchmarks")] pub struct BenchmarkMultiLocationConverter { _phantom: sp_std::marker::PhantomData, } #[cfg(feature = "runtime-benchmarks")] impl pallet_asset_conversion::BenchmarkHelper> for BenchmarkMultiLocationConverter where SelfParaId: Get, { fn asset_id(asset_id: u32) -> MultiLocation { MultiLocation { parents: 1, interior: X3( Parachain(SelfParaId::get().into()), PalletInstance(::index() as u8), GeneralIndex(asset_id.into()), ), } } fn multiasset_id(asset_id: u32) -> sp_std::boxed::Box { sp_std::boxed::Box::new(Self::asset_id(asset_id)) } } /// All configuration related to bridging pub mod bridging { use super::*; use assets_common::matching; use sp_std::collections::btree_set::BTreeSet; parameter_types! { pub SiblingBridgeHubParaId: u32 = bp_bridge_hub_westend::BRIDGE_HUB_WESTEND_PARACHAIN_ID; pub SiblingBridgeHub: MultiLocation = MultiLocation::new(1, X1(Parachain(SiblingBridgeHubParaId::get()))); /// Router expects payment with this `AssetId`. /// (`AssetId` has to be aligned with `BridgeTable`) pub XcmBridgeHubRouterFeeAssetId: AssetId = WestendLocation::get().into(); /// Price per byte - can be adjusted via governance `set_storage` call. pub storage XcmBridgeHubRouterByteFee: Balance = TransactionByteFee::get(); pub BridgeTable: sp_std::vec::Vec = sp_std::vec::Vec::new().into_iter() .chain(to_rococo::BridgeTable::get()) .collect(); } pub type NetworkExportTable = xcm_builder::NetworkExportTable; pub mod to_rococo { use super::*; parameter_types! { pub SiblingBridgeHubWithBridgeHubRococoInstance: MultiLocation = MultiLocation::new( 1, X2( Parachain(SiblingBridgeHubParaId::get()), PalletInstance(bp_bridge_hub_westend::WITH_BRIDGE_WESTEND_TO_ROCOCO_MESSAGES_PALLET_INDEX) ) ); pub const RococoNetwork: NetworkId = NetworkId::Rococo; pub AssetHubRococo: MultiLocation = MultiLocation::new(2, X2(GlobalConsensus(RococoNetwork::get()), Parachain(bp_asset_hub_rococo::ASSET_HUB_ROCOCO_PARACHAIN_ID))); pub RocLocation: MultiLocation = MultiLocation::new(2, X1(GlobalConsensus(RococoNetwork::get()))); pub RocFromAssetHubRococo: (MultiAssetFilter, MultiLocation) = ( Wild(AllOf { fun: WildFungible, id: Concrete(RocLocation::get()) }), AssetHubRococo::get() ); /// Set up exporters configuration. /// `Option` represents static "base fee" which is used for total delivery fee calculation. pub BridgeTable: sp_std::vec::Vec = sp_std::vec![ NetworkExportTableItem::new( RococoNetwork::get(), Some(sp_std::vec![ AssetHubRococo::get().interior.split_global().expect("invalid configuration for AssetHubRococo").1, ]), SiblingBridgeHub::get(), // base delivery fee to local `BridgeHub` Some(( XcmBridgeHubRouterFeeAssetId::get(), bp_asset_hub_westend::BridgeHubWestendBaseFeeInWnds::get(), ).into()) ) ]; /// Universal aliases pub UniversalAliases: BTreeSet<(MultiLocation, Junction)> = BTreeSet::from_iter( sp_std::vec![ (SiblingBridgeHubWithBridgeHubRococoInstance::get(), GlobalConsensus(RococoNetwork::get())) ] ); } impl Contains<(MultiLocation, Junction)> for UniversalAliases { fn contains(alias: &(MultiLocation, Junction)) -> bool { UniversalAliases::get().contains(alias) } } /// Reserve locations filter for `xcm_executor::Config::IsReserve`. /// Locations from which the runtime accepts reserved assets. pub type IsTrustedBridgedReserveLocationForConcreteAsset = matching::IsTrustedBridgedReserveLocationForConcreteAsset< UniversalLocation, ( // allow receive ROC from AssetHubRococo xcm_builder::Case, // and nothing else ), >; impl Contains for ToRococoXcmRouter { fn contains(call: &RuntimeCall) -> bool { matches!( call, RuntimeCall::ToRococoXcmRouter( pallet_xcm_bridge_hub_router::Call::report_bridge_status { .. } ) ) } } } /// Benchmarks helper for bridging configuration. #[cfg(feature = "runtime-benchmarks")] pub struct BridgingBenchmarksHelper; #[cfg(feature = "runtime-benchmarks")] impl BridgingBenchmarksHelper { pub fn prepare_universal_alias() -> Option<(MultiLocation, Junction)> { let alias = to_rococo::UniversalAliases::get().into_iter().find_map(|(location, junction)| { match to_rococo::SiblingBridgeHubWithBridgeHubRococoInstance::get() .eq(&location) { true => Some((location, junction)), false => None, } }); assert!(alias.is_some(), "we expect here BridgeHubWestend to Rococo mapping at least"); Some(alias.unwrap()) } } }