referrerpolicy=no-referrer-when-downgrade

asset_hub_westend_runtime/
xcm_config.rs

1// Copyright (C) Parity Technologies (UK) Ltd.
2// SPDX-License-Identifier: Apache-2.0
3
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// 	http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16use super::{
17	governance::TreasuryAccount, AccountId, AllPalletsWithSystem, Assets, Balance, Balances,
18	BaseDeliveryFee, CollatorSelection, DepositPerByte, DepositPerItem, FeeAssetId,
19	FellowshipAdmin, ForeignAssets, GeneralAdmin, ParachainInfo, ParachainSystem, PolkadotXcm,
20	PoolAssets, Runtime, RuntimeCall, RuntimeEvent, RuntimeHoldReason, RuntimeOrigin, StakingAdmin,
21	ToRococoXcmRouter, TransactionByteFee, Treasurer, Uniques, WeightToFee, XcmpQueue,
22};
23use alloc::{collections::BTreeSet, vec, vec::Vec};
24use assets_common::{
25	matching::{FromSiblingParachain, IsForeignConcreteAsset, ParentLocation},
26	TrustBackedAssetsAsLocation,
27};
28use frame_support::{
29	parameter_types,
30	traits::{
31		fungible::HoldConsideration,
32		tokens::imbalance::{ResolveAssetTo, ResolveTo},
33		ConstU32, Contains, Equals, Everything, LinearStoragePrice, PalletInfoAccess,
34	},
35	PalletId,
36};
37use frame_system::EnsureRoot;
38use pallet_xcm::{AuthorizedAliasers, XcmPassthrough};
39use parachains_common::xcm_config::{
40	AllSiblingSystemParachains, ConcreteAssetFromSystem, RelayOrOtherSystemParachains,
41};
42use polkadot_parachain_primitives::primitives::Sibling;
43use polkadot_runtime_common::xcm_sender::ExponentialPrice;
44use snowbridge_outbound_queue_primitives::v2::exporter::PausableExporter;
45use sp_runtime::traits::{AccountIdConversion, TryConvertInto};
46use testnet_parachains_constants::westend::locations::AssetHubParaId;
47use westend_runtime_constants::{
48	system_parachain::COLLECTIVES_ID, xcm::body::FELLOWSHIP_ADMIN_INDEX,
49};
50use xcm::latest::{prelude::*, ROCOCO_GENESIS_HASH, WESTEND_GENESIS_HASH};
51use xcm_builder::{
52	unique_instances::UniqueInstancesAdapter, AccountId32Aliases, AliasChildLocation,
53	AllowExplicitUnpaidExecutionFrom, AllowHrmpNotificationsFromRelayChain,
54	AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom,
55	DenyRecursively, DenyReserveTransferToRelayChain, DenyThenTry, DescribeAllTerminal,
56	DescribeFamily, EnsureXcmOrigin, ExternalConsensusLocationsConverterFor,
57	FrameTransactionalProcessor, FungibleAdapter, FungiblesAdapter, HashedDescription, IsConcrete,
58	LocalMint, MatchInClassInstances, MatchedConvertedConcreteId, MintLocation,
59	NetworkExportTableItem, NoChecking, OriginToPluralityVoice, ParentAsSuperuser, ParentIsPreset,
60	RelayChainAsNative, SendXcmFeeToAccount, SiblingParachainAsNative, SiblingParachainConvertsVia,
61	SignedAccountId32AsNative, SignedToAccountId32, SingleAssetExchangeAdapter,
62	SovereignSignedViaLocation, StartsWith, StartsWithExplicitGlobalConsensus, TakeWeightCredit,
63	TrailingSetTopicAsId, UnpaidRemoteExporter, UsingComponents, WeightInfoBounds,
64	WithComputedOrigin, WithLatestLocationConverter, WithUniqueTopic, XcmFeeManagerFromComponents,
65};
66use xcm_executor::XcmExecutor;
67
68parameter_types! {
69	pub const RootLocation: Location = Location::here();
70	pub const WestendLocation: Location = Location::parent();
71	pub const RelayNetwork: Option<NetworkId> = Some(NetworkId::ByGenesis(WESTEND_GENESIS_HASH));
72	pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into();
73	pub UniversalLocation: InteriorLocation =
74		[GlobalConsensus(RelayNetwork::get().unwrap()), Parachain(ParachainInfo::parachain_id().into())].into();
75	pub UniversalLocationNetworkId: NetworkId = UniversalLocation::get().global_consensus().unwrap();
76	pub TrustBackedAssetsPalletLocation: Location =
77		PalletInstance(TrustBackedAssetsPalletIndex::get()).into();
78	pub TrustBackedAssetsPalletIndex: u8 = <Assets as PalletInfoAccess>::index() as u8;
79	pub ForeignAssetsPalletLocation: Location =
80		PalletInstance(<ForeignAssets as PalletInfoAccess>::index() as u8).into();
81	pub PoolAssetsPalletLocation: Location =
82		PalletInstance(<PoolAssets as PalletInfoAccess>::index() as u8).into();
83	pub UniquesPalletLocation: Location =
84		PalletInstance(<Uniques as PalletInfoAccess>::index() as u8).into();
85	pub CheckingAccount: AccountId = PolkadotXcm::check_account();
86	pub StakingPot: AccountId = CollatorSelection::account_id();
87	pub RelayTreasuryLocation: Location = (Parent, PalletInstance(westend_runtime_constants::TREASURY_PALLET_ID)).into();
88	/// Asset Hub has mint authority since the Asset Hub migration.
89	pub TeleportTracking: Option<(AccountId, MintLocation)> = Some((CheckingAccount::get(), MintLocation::Local));
90}
91
92/// Type for specifying how a `Location` can be converted into an `AccountId`. This is used
93/// when determining ownership of accounts for asset transacting and when attempting to use XCM
94/// `Transact` in order to determine the dispatch Origin.
95pub type LocationToAccountId = (
96	// The parent (Relay-chain) origin converts to the parent `AccountId`.
97	ParentIsPreset<AccountId>,
98	// Sibling parachain origins convert to AccountId via the `ParaId::into`.
99	SiblingParachainConvertsVia<Sibling, AccountId>,
100	// Straight up local `AccountId32` origins just alias directly to `AccountId`.
101	AccountId32Aliases<RelayNetwork, AccountId>,
102	// Foreign locations alias into accounts according to a hash of their standard description.
103	HashedDescription<AccountId, DescribeFamily<DescribeAllTerminal>>,
104	// Different global consensus locations sovereign accounts.
105	ExternalConsensusLocationsConverterFor<UniversalLocation, AccountId>,
106);
107
108/// Means for transacting the native currency on this chain.
109pub type FungibleTransactor = FungibleAdapter<
110	// Use this currency:
111	Balances,
112	// Use this currency when it is a fungible asset matching the given location or name:
113	IsConcrete<WestendLocation>,
114	// Convert an XCM Location into a local account id:
115	LocationToAccountId,
116	// Our chain's account ID type (we can't get away without mentioning it explicitly):
117	AccountId,
118	// Teleports tracking
119	TeleportTracking,
120>;
121
122/// `AssetId`/`Balance` converter for `TrustBackedAssets`.
123pub type TrustBackedAssetsConvertedConcreteId =
124	assets_common::TrustBackedAssetsConvertedConcreteId<TrustBackedAssetsPalletLocation, Balance>;
125
126/// Means for transacting assets besides the native currency on this chain.
127pub type FungiblesTransactor = FungiblesAdapter<
128	// Use this fungibles implementation:
129	Assets,
130	// Use this currency when it is a fungible asset matching the given location or name:
131	TrustBackedAssetsConvertedConcreteId,
132	// Convert an XCM Location into a local account id:
133	LocationToAccountId,
134	// Our chain's account ID type (we can't get away without mentioning it explicitly):
135	AccountId,
136	// We only want to allow teleports of known assets. We use non-zero issuance as an indication
137	// that this asset is known.
138	LocalMint<parachains_common::impls::NonZeroIssuance<AccountId, Assets>>,
139	// The account to use for tracking teleports.
140	CheckingAccount,
141>;
142
143/// Matcher for converting `ClassId`/`InstanceId` into a uniques asset.
144pub type UniquesConvertedConcreteId =
145	assets_common::UniquesConvertedConcreteId<UniquesPalletLocation>;
146
147/// Means for transacting unique assets.
148pub type UniquesTransactor = UniqueInstancesAdapter<
149	AccountId,
150	LocationToAccountId,
151	MatchInClassInstances<UniquesConvertedConcreteId>,
152	pallet_uniques::asset_ops::Item<Uniques>,
153>;
154
155/// `AssetId`/`Balance` converter for `ForeignAssets`.
156pub type ForeignAssetsConvertedConcreteId = assets_common::ForeignAssetsConvertedConcreteId<
157	(
158		// Ignore `TrustBackedAssets` explicitly
159		StartsWith<TrustBackedAssetsPalletLocation>,
160		// Ignore asset which starts explicitly with our `GlobalConsensus(NetworkId)`, means:
161		// - foreign assets from our consensus should be: `Location {parents: 1, X*(Parachain(xyz),
162		//   ..)}
163		// - foreign assets outside our consensus with the same `GlobalConsensus(NetworkId)` wont
164		//   be accepted here
165		StartsWithExplicitGlobalConsensus<UniversalLocationNetworkId>,
166	),
167	Balance,
168	xcm::v5::Location,
169>;
170
171/// Means for transacting foreign assets from different global consensus.
172pub type ForeignFungiblesTransactor = FungiblesAdapter<
173	// Use this fungibles implementation:
174	ForeignAssets,
175	// Use this currency when it is a fungible asset matching the given location or name:
176	ForeignAssetsConvertedConcreteId,
177	// Convert an XCM Location into a local account id:
178	LocationToAccountId,
179	// Our chain's account ID type (we can't get away without mentioning it explicitly):
180	AccountId,
181	// We don't need to check teleports here.
182	NoChecking,
183	// The account to use for tracking teleports.
184	CheckingAccount,
185>;
186
187/// `AssetId`/`Balance` converter for `PoolAssets`.
188pub type PoolAssetsConvertedConcreteId =
189	assets_common::PoolAssetsConvertedConcreteId<PoolAssetsPalletLocation, Balance>;
190
191/// Means for transacting asset conversion pool assets on this chain.
192pub type PoolFungiblesTransactor = FungiblesAdapter<
193	// Use this fungibles implementation:
194	PoolAssets,
195	// Use this currency when it is a fungible asset matching the given location or name:
196	PoolAssetsConvertedConcreteId,
197	// Convert an XCM Location into a local account id:
198	LocationToAccountId,
199	// Our chain's account ID type (we can't get away without mentioning it explicitly):
200	AccountId,
201	// We only want to allow teleports of known assets. We use non-zero issuance as an indication
202	// that this asset is known.
203	LocalMint<parachains_common::impls::NonZeroIssuance<AccountId, PoolAssets>>,
204	// The account to use for tracking teleports.
205	CheckingAccount,
206>;
207
208parameter_types! {
209	/// Taken from the real gas and deposits of a standard ERC20 transfer call.
210	pub const ERC20TransferGasLimit: Weight = Weight::from_parts(700_000_000, 200_000);
211	pub const ERC20TransferStorageDepositLimit: Balance = 10_200_000_000;
212	pub ERC20TransfersCheckingAccount: AccountId = PalletId(*b"py/revch").into_account_truncating();
213}
214
215/// Transactor for ERC20 tokens.
216pub type ERC20Transactor = assets_common::ERC20Transactor<
217	// We need this for accessing pallet-revive.
218	Runtime,
219	// The matcher for smart contracts.
220	assets_common::ERC20Matcher,
221	// How to convert from a location to an account id.
222	LocationToAccountId,
223	// The maximum gas that can be used by a standard ERC20 transfer.
224	ERC20TransferGasLimit,
225	// The maximum storage deposit that can be used by a standard ERC20 transfer.
226	ERC20TransferStorageDepositLimit,
227	// We're generic over this so we can't escape specifying it.
228	AccountId,
229	// Checking account for ERC20 transfers.
230	ERC20TransfersCheckingAccount,
231>;
232
233/// Means for transacting assets on this chain.
234pub type AssetTransactors = (
235	FungibleTransactor,
236	FungiblesTransactor,
237	ForeignFungiblesTransactor,
238	PoolFungiblesTransactor,
239	UniquesTransactor,
240	ERC20Transactor,
241);
242
243/// This is the type we use to convert an (incoming) XCM origin into a local `Origin` instance,
244/// ready for dispatching a transaction with Xcm's `Transact`. There is an `OriginKind` which can
245/// biases the kind of local `Origin` it will become.
246pub type XcmOriginToTransactDispatchOrigin = (
247	// Sovereign account converter; this attempts to derive an `AccountId` from the origin location
248	// using `LocationToAccountId` and then turn that into the usual `Signed` origin. Useful for
249	// foreign chains who want to have a local sovereign account on this chain which they control.
250	SovereignSignedViaLocation<LocationToAccountId, RuntimeOrigin>,
251	// Native converter for Relay-chain (Parent) location; will convert to a `Relay` origin when
252	// recognised.
253	RelayChainAsNative<RelayChainOrigin, RuntimeOrigin>,
254	// Native converter for sibling Parachains; will convert to a `SiblingPara` origin when
255	// recognised.
256	SiblingParachainAsNative<cumulus_pallet_xcm::Origin, RuntimeOrigin>,
257	// Superuser converter for the Relay-chain (Parent) location. This will allow it to issue a
258	// transaction from the Root origin.
259	ParentAsSuperuser<RuntimeOrigin>,
260	// Native signed account converter; this just converts an `AccountId32` origin into a normal
261	// `RuntimeOrigin::Signed` origin of the same 32-byte value.
262	SignedAccountId32AsNative<RelayNetwork, RuntimeOrigin>,
263	// Xcm origins can be represented natively under the Xcm pallet's Xcm origin.
264	XcmPassthrough<RuntimeOrigin>,
265);
266
267parameter_types! {
268	pub const MaxInstructions: u32 = 100;
269	pub const MaxAssetsIntoHolding: u32 = 64;
270}
271
272pub struct ParentOrParentsPlurality;
273impl Contains<Location> for ParentOrParentsPlurality {
274	fn contains(location: &Location) -> bool {
275		matches!(location.unpack(), (1, []) | (1, [Plurality { .. }]))
276	}
277}
278
279pub struct FellowshipEntities;
280impl Contains<Location> for FellowshipEntities {
281	fn contains(location: &Location) -> bool {
282		matches!(
283			location.unpack(),
284			(1, [Parachain(COLLECTIVES_ID), Plurality { id: BodyId::Technical, .. }]) |
285				(1, [Parachain(COLLECTIVES_ID), PalletInstance(64)]) |
286				(1, [Parachain(COLLECTIVES_ID), PalletInstance(65)])
287		)
288	}
289}
290
291pub struct LocalPlurality;
292impl Contains<Location> for LocalPlurality {
293	fn contains(loc: &Location) -> bool {
294		matches!(loc.unpack(), (0, [Plurality { .. }]))
295	}
296}
297
298pub struct AmbassadorEntities;
299impl Contains<Location> for AmbassadorEntities {
300	fn contains(location: &Location) -> bool {
301		matches!(location.unpack(), (1, [Parachain(COLLECTIVES_ID), PalletInstance(74)]))
302	}
303}
304
305pub struct SecretaryEntities;
306impl Contains<Location> for SecretaryEntities {
307	fn contains(location: &Location) -> bool {
308		matches!(location.unpack(), (1, [Parachain(COLLECTIVES_ID), PalletInstance(91)]))
309	}
310}
311
312pub type Barrier = TrailingSetTopicAsId<
313	DenyThenTry<
314		DenyRecursively<DenyReserveTransferToRelayChain>,
315		(
316			TakeWeightCredit,
317			// Expected responses are OK.
318			AllowKnownQueryResponses<PolkadotXcm>,
319			// Allow XCMs with some computed origins to pass through.
320			WithComputedOrigin<
321				(
322					// If the message is one that immediately attempts to pay for execution, then
323					// allow it.
324					AllowTopLevelPaidExecutionFrom<Everything>,
325					// Parent, its pluralities (i.e. governance bodies), relay treasury pallet and
326					// sibling parachains get free execution.
327					AllowExplicitUnpaidExecutionFrom<(
328						ParentOrParentsPlurality,
329						Equals<RelayTreasuryLocation>,
330						RelayOrOtherSystemParachains<AllSiblingSystemParachains, Runtime>,
331						FellowshipEntities,
332						AmbassadorEntities,
333						SecretaryEntities,
334					)>,
335					// Subscriptions for version tracking are OK.
336					AllowSubscriptionsFrom<Everything>,
337					// HRMP notifications from the relay chain are OK.
338					AllowHrmpNotificationsFromRelayChain,
339				),
340				UniversalLocation,
341				ConstU32<8>,
342			>,
343		),
344	>,
345>;
346
347/// Locations that will not be charged fees in the executor,
348/// either execution or delivery.
349/// We only waive fees for system functions, which these locations represent.
350pub type WaivedLocations = (
351	Equals<RootLocation>,
352	RelayOrOtherSystemParachains<AllSiblingSystemParachains, Runtime>,
353	Equals<RelayTreasuryLocation>,
354	FellowshipEntities,
355	AmbassadorEntities,
356	LocalPlurality,
357	SecretaryEntities,
358);
359
360/// Cases where a remote origin is accepted as trusted Teleporter for a given asset:
361///
362/// - WND with the parent Relay Chain and sibling system parachains; and
363/// - Sibling parachains' assets from where they originate (as `ForeignCreators`).
364pub type TrustedTeleporters = (
365	ConcreteAssetFromSystem<WestendLocation>,
366	IsForeignConcreteAsset<FromSiblingParachain<AssetHubParaId>>,
367);
368
369/// Defines origin aliasing rules for this chain.
370///
371/// - Allow any origin to alias into a child sub-location (equivalent to DescendOrigin),
372/// - Allow origins explicitly authorized by the alias target location.
373pub type TrustedAliasers = (AliasChildLocation, AuthorizedAliasers<Runtime>);
374
375/// Asset converter for pool assets.
376/// Used to convert one asset to another, when there is a pool available between the two.
377/// This type thus allows paying fees with any asset as long as there is a pool between said
378/// asset and the asset required for fee payment.
379pub type PoolAssetsExchanger = SingleAssetExchangeAdapter<
380	crate::AssetConversion,
381	crate::NativeAndNonPoolAssets,
382	(
383		TrustBackedAssetsAsLocation<TrustBackedAssetsPalletLocation, Balance, xcm::v5::Location>,
384		ForeignAssetsConvertedConcreteId,
385		// `ForeignAssetsConvertedConcreteId` excludes the relay token, so we add it back here.
386		MatchedConvertedConcreteId<
387			xcm::v5::Location,
388			Balance,
389			Equals<ParentLocation>,
390			WithLatestLocationConverter<xcm::v5::Location>,
391			TryConvertInto,
392		>,
393	),
394	AccountId,
395>;
396
397pub struct XcmConfig;
398impl xcm_executor::Config for XcmConfig {
399	type RuntimeCall = RuntimeCall;
400	type XcmSender = XcmRouter;
401	type XcmEventEmitter = PolkadotXcm;
402	type AssetTransactor = AssetTransactors;
403	type OriginConverter = XcmOriginToTransactDispatchOrigin;
404	// Asset Hub trusts only particular, pre-configured bridged locations from a different consensus
405	// as reserve locations (we trust the Bridge Hub to relay the message that a reserve is being
406	// held). On Westend Asset Hub, we allow Rococo Asset Hub to act as reserve for any asset native
407	// to the Rococo or Ethereum ecosystems.
408	type IsReserve = (
409		bridging::to_rococo::RococoAssetFromAssetHubRococo,
410		bridging::to_ethereum::EthereumAssetFromEthereum,
411	);
412	type IsTeleporter = TrustedTeleporters;
413	type UniversalLocation = UniversalLocation;
414	type Barrier = Barrier;
415	type Weigher = WeightInfoBounds<
416		crate::weights::xcm::AssetHubWestendXcmWeight<RuntimeCall>,
417		RuntimeCall,
418		MaxInstructions,
419	>;
420	type Trader = (
421		UsingComponents<
422			WeightToFee,
423			WestendLocation,
424			AccountId,
425			Balances,
426			ResolveTo<StakingPot, Balances>,
427		>,
428		cumulus_primitives_utility::SwapFirstAssetTrader<
429			WestendLocation,
430			crate::AssetConversion,
431			WeightToFee,
432			crate::NativeAndNonPoolAssets,
433			(
434				TrustBackedAssetsAsLocation<
435					TrustBackedAssetsPalletLocation,
436					Balance,
437					xcm::v5::Location,
438				>,
439				ForeignAssetsConvertedConcreteId,
440			),
441			ResolveAssetTo<StakingPot, crate::NativeAndNonPoolAssets>,
442			AccountId,
443		>,
444	);
445	type ResponseHandler = PolkadotXcm;
446	type AssetTrap = PolkadotXcm;
447	type AssetClaims = PolkadotXcm;
448	type SubscriptionService = PolkadotXcm;
449	type PalletInstancesInfo = AllPalletsWithSystem;
450	type MaxAssetsIntoHolding = MaxAssetsIntoHolding;
451	type AssetLocker = ();
452	type AssetExchanger = PoolAssetsExchanger;
453	type FeeManager = XcmFeeManagerFromComponents<
454		WaivedLocations,
455		SendXcmFeeToAccount<Self::AssetTransactor, TreasuryAccount>,
456	>;
457	type MessageExporter = ();
458	type UniversalAliases =
459		(bridging::to_rococo::UniversalAliases, bridging::to_ethereum::UniversalAliases);
460	type CallDispatcher = RuntimeCall;
461	type SafeCallFilter = Everything;
462	type Aliasers = TrustedAliasers;
463	type TransactionalProcessor = FrameTransactionalProcessor;
464	type HrmpNewChannelOpenRequestHandler = ();
465	type HrmpChannelAcceptedHandler = ();
466	type HrmpChannelClosingHandler = ();
467	type XcmRecorder = PolkadotXcm;
468}
469
470parameter_types! {
471	// `GeneralAdmin` pluralistic body.
472	pub const GeneralAdminBodyId: BodyId = BodyId::Administration;
473	// StakingAdmin pluralistic body.
474	pub const StakingAdminBodyId: BodyId = BodyId::Defense;
475	// FellowshipAdmin pluralistic body.
476	pub const FellowshipAdminBodyId: BodyId = BodyId::Index(FELLOWSHIP_ADMIN_INDEX);
477	// `Treasurer` pluralistic body.
478	pub const TreasurerBodyId: BodyId = BodyId::Treasury;
479}
480
481/// Type to convert the `GeneralAdmin` origin to a Plurality `Location` value.
482pub type GeneralAdminToPlurality =
483	OriginToPluralityVoice<RuntimeOrigin, GeneralAdmin, GeneralAdminBodyId>;
484
485/// Local origins on this chain are allowed to dispatch XCM sends/executions.
486pub type LocalOriginToLocation =
487	(GeneralAdminToPlurality, SignedToAccountId32<RuntimeOrigin, AccountId, RelayNetwork>);
488
489/// Type to convert the `StakingAdmin` origin to a Plurality `Location` value.
490pub type StakingAdminToPlurality =
491	OriginToPluralityVoice<RuntimeOrigin, StakingAdmin, StakingAdminBodyId>;
492
493/// Type to convert the `FellowshipAdmin` origin to a Plurality `Location` value.
494pub type FellowshipAdminToPlurality =
495	OriginToPluralityVoice<RuntimeOrigin, FellowshipAdmin, FellowshipAdminBodyId>;
496
497/// Type to convert the `Treasurer` origin to a Plurality `Location` value.
498pub type TreasurerToPlurality = OriginToPluralityVoice<RuntimeOrigin, Treasurer, TreasurerBodyId>;
499
500/// Type to convert a pallet `Origin` type value into a `Location` value which represents an
501/// interior location of this chain for a destination chain.
502pub type LocalPalletOriginToLocation = (
503	// GeneralAdmin origin to be used in XCM as a corresponding Plurality `Location` value.
504	GeneralAdminToPlurality,
505	// StakingAdmin origin to be used in XCM as a corresponding Plurality `Location` value.
506	StakingAdminToPlurality,
507	// FellowshipAdmin origin to be used in XCM as a corresponding Plurality `Location` value.
508	FellowshipAdminToPlurality,
509	// `Treasurer` origin to be used in XCM as a corresponding Plurality `Location` value.
510	TreasurerToPlurality,
511);
512
513pub type PriceForParentDelivery =
514	ExponentialPrice<FeeAssetId, BaseDeliveryFee, TransactionByteFee, ParachainSystem>;
515
516/// For routing XCM messages which do not cross local consensus boundary.
517type LocalXcmRouter = (
518	// Two routers - use UMP to communicate with the relay chain:
519	cumulus_primitives_utility::ParentAsUmp<ParachainSystem, PolkadotXcm, PriceForParentDelivery>,
520	// ..and XCMP to communicate with the sibling chains.
521	XcmpQueue,
522);
523
524/// The means for routing XCM messages which are not for local execution into the right message
525/// queues.
526pub type XcmRouter = WithUniqueTopic<(
527	LocalXcmRouter,
528	// Router which wraps and sends xcm to BridgeHub to be delivered to the Rococo
529	// GlobalConsensus
530	ToRococoXcmRouter,
531	// Router which wraps and sends xcm to BridgeHub to be delivered to the Ethereum
532	// GlobalConsensus with a pausable flag, if the flag is set true then the Router is paused
533	PausableExporter<
534		crate::SnowbridgeSystemFrontend,
535		(
536			UnpaidRemoteExporter<
537				(
538					bridging::to_ethereum::EthereumNetworkExportTableV2,
539					bridging::to_ethereum::EthereumNetworkExportTableV1,
540				),
541				XcmpQueue,
542				UniversalLocation,
543			>,
544		),
545	>,
546)>;
547
548parameter_types! {
549	pub Collectives: Location = Location::new(1, [Parachain(COLLECTIVES_ID)]);
550	pub const AuthorizeAliasHoldReason: RuntimeHoldReason = RuntimeHoldReason::PolkadotXcm(pallet_xcm::HoldReason::AuthorizeAlias);
551}
552
553impl pallet_xcm::Config for Runtime {
554	type RuntimeEvent = RuntimeEvent;
555	type SendXcmOrigin = EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>;
556	type XcmRouter = XcmRouter;
557	type ExecuteXcmOrigin = EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>;
558	type XcmExecuteFilter = Everything;
559	type XcmExecutor = XcmExecutor<XcmConfig>;
560	type XcmTeleportFilter = Everything;
561	type XcmReserveTransferFilter = Everything;
562	type Weigher = WeightInfoBounds<
563		crate::weights::xcm::AssetHubWestendXcmWeight<RuntimeCall>,
564		RuntimeCall,
565		MaxInstructions,
566	>;
567	type UniversalLocation = UniversalLocation;
568	type RuntimeOrigin = RuntimeOrigin;
569	type RuntimeCall = RuntimeCall;
570	const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100;
571	type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion;
572	type Currency = Balances;
573	type CurrencyMatcher = ();
574	type TrustedLockers = ();
575	type SovereignAccountOf = LocationToAccountId;
576	type MaxLockers = ConstU32<8>;
577	type WeightInfo = crate::weights::pallet_xcm::WeightInfo<Runtime>;
578	type AdminOrigin = EnsureRoot<AccountId>;
579	type MaxRemoteLockConsumers = ConstU32<0>;
580	type RemoteLockConsumerIdentifier = ();
581	// xcm_executor::Config::Aliasers also uses pallet_xcm::AuthorizedAliasers.
582	type AuthorizedAliasConsideration = HoldConsideration<
583		AccountId,
584		Balances,
585		AuthorizeAliasHoldReason,
586		LinearStoragePrice<DepositPerItem, DepositPerByte, Balance>,
587	>;
588}
589
590impl cumulus_pallet_xcm::Config for Runtime {
591	type RuntimeEvent = RuntimeEvent;
592	type XcmExecutor = XcmExecutor<XcmConfig>;
593}
594
595/// Simple conversion of `u32` into an `AssetId` for use in benchmarking.
596pub struct XcmBenchmarkHelper;
597#[cfg(feature = "runtime-benchmarks")]
598impl pallet_assets::BenchmarkHelper<xcm::v5::Location> for XcmBenchmarkHelper {
599	fn create_asset_id_parameter(id: u32) -> xcm::v5::Location {
600		xcm::v5::Location::new(1, [xcm::v5::Junction::Parachain(id)])
601	}
602}
603
604/// All configuration related to bridging
605pub mod bridging {
606	use super::*;
607	use assets_common::matching;
608
609	parameter_types! {
610		/// Base price of every byte of the Westend -> Rococo message. Can be adjusted via
611		/// governance `set_storage` call.
612		///
613		/// Default value is our estimation of the:
614		///
615		/// 1) an approximate cost of XCM execution (`ExportMessage` and surroundings) at Westend bridge hub;
616		///
617		/// 2) the approximate cost of Westend -> Rococo message delivery transaction on Rococo Bridge Hub,
618		///    converted into WNDs using 1:1 conversion rate;
619		///
620		/// 3) the approximate cost of Westend -> Rococo message confirmation transaction on Westend Bridge Hub.
621		pub storage XcmBridgeHubRouterBaseFee: Balance =
622			bp_bridge_hub_westend::BridgeHubWestendBaseXcmFeeInWnds::get()
623				.saturating_add(bp_bridge_hub_rococo::BridgeHubRococoBaseDeliveryFeeInRocs::get())
624				.saturating_add(bp_bridge_hub_westend::BridgeHubWestendBaseConfirmationFeeInWnds::get());
625		/// Price of every byte of the Westend -> Rococo message. Can be adjusted via
626		/// governance `set_storage` call.
627		pub storage XcmBridgeHubRouterByteFee: Balance = TransactionByteFee::get();
628
629		pub SiblingBridgeHubParaId: u32 = bp_bridge_hub_westend::BRIDGE_HUB_WESTEND_PARACHAIN_ID;
630		pub SiblingBridgeHub: Location = Location::new(1, [Parachain(SiblingBridgeHubParaId::get())]);
631		/// Router expects payment with this `AssetId`.
632		/// (`AssetId` has to be aligned with `BridgeTable`)
633		pub XcmBridgeHubRouterFeeAssetId: AssetId = WestendLocation::get().into();
634
635		pub BridgeTable: Vec<NetworkExportTableItem> =
636			Vec::new().into_iter()
637			.chain(to_rococo::BridgeTable::get())
638			.collect();
639	}
640
641	pub type NetworkExportTable = xcm_builder::NetworkExportTable<BridgeTable>;
642
643	pub mod to_rococo {
644		use super::*;
645
646		parameter_types! {
647			pub SiblingBridgeHubWithBridgeHubRococoInstance: Location = Location::new(
648				1,
649				[
650					Parachain(SiblingBridgeHubParaId::get()),
651					PalletInstance(bp_bridge_hub_westend::WITH_BRIDGE_WESTEND_TO_ROCOCO_MESSAGES_PALLET_INDEX)
652				]
653			);
654
655			pub const RococoNetwork: NetworkId = NetworkId::ByGenesis(ROCOCO_GENESIS_HASH);
656			pub RococoEcosystem: Location = Location::new(2, [GlobalConsensus(RococoNetwork::get())]);
657			pub RocLocation: Location = Location::new(2, [GlobalConsensus(RococoNetwork::get())]);
658			pub AssetHubRococo: Location = Location::new(2, [
659				GlobalConsensus(RococoNetwork::get()),
660				Parachain(bp_asset_hub_rococo::ASSET_HUB_ROCOCO_PARACHAIN_ID)
661			]);
662
663			/// Set up exporters configuration.
664			/// `Option<Asset>` represents static "base fee" which is used for total delivery fee calculation.
665			pub BridgeTable: Vec<NetworkExportTableItem> = vec![
666				NetworkExportTableItem::new(
667					RococoNetwork::get(),
668					Some(vec![
669						AssetHubRococo::get().interior.split_global().expect("invalid configuration for AssetHubRococo").1,
670					]),
671					SiblingBridgeHub::get(),
672					// base delivery fee to local `BridgeHub`
673					Some((
674						XcmBridgeHubRouterFeeAssetId::get(),
675						XcmBridgeHubRouterBaseFee::get(),
676					).into())
677				)
678			];
679
680			/// Universal aliases
681			pub UniversalAliases: BTreeSet<(Location, Junction)> = BTreeSet::from_iter(
682				vec![
683					(SiblingBridgeHubWithBridgeHubRococoInstance::get(), GlobalConsensus(RococoNetwork::get()))
684				]
685			);
686		}
687
688		impl Contains<(Location, Junction)> for UniversalAliases {
689			fn contains(alias: &(Location, Junction)) -> bool {
690				UniversalAliases::get().contains(alias)
691			}
692		}
693
694		/// Allow any asset native to the Rococo ecosystem if it comes from Rococo Asset Hub.
695		pub type RococoAssetFromAssetHubRococo =
696			matching::RemoteAssetFromLocation<StartsWith<RococoEcosystem>, AssetHubRococo>;
697	}
698
699	pub mod to_ethereum {
700		use super::*;
701		use assets_common::matching::FromNetwork;
702		use testnet_parachains_constants::westend::snowbridge::{
703			EthereumNetwork, INBOUND_QUEUE_PALLET_INDEX_V1, INBOUND_QUEUE_PALLET_INDEX_V2,
704		};
705
706		parameter_types! {
707			/// User fee for ERC20 token transfer back to Ethereum.
708			/// (initially was calculated by test `OutboundQueue::calculate_fees` - ETH/WND 1/400 and fee_per_gas 20 GWEI = 2200698000000 + *25%)
709			/// Needs to be more than fee calculated from DefaultFeeConfig FeeConfigRecord in snowbridge:parachain/pallets/outbound-queue/src/lib.rs
710			/// Polkadot uses 10 decimals, Kusama,Rococo,Westend 12 decimals.
711			pub const DefaultBridgeHubEthereumBaseFee: Balance = 3_833_568_200_000;
712			pub const DefaultBridgeHubEthereumBaseFeeV2: Balance = 100_000_000_000;
713			pub storage BridgeHubEthereumBaseFee: Balance = DefaultBridgeHubEthereumBaseFee::get();
714			pub storage BridgeHubEthereumBaseFeeV2: Balance = DefaultBridgeHubEthereumBaseFeeV2::get();
715			pub SiblingBridgeHubWithEthereumInboundQueueV1Instance: Location = Location::new(
716				1,
717				[
718					Parachain(SiblingBridgeHubParaId::get()),
719					PalletInstance(INBOUND_QUEUE_PALLET_INDEX_V1)
720				]
721			);
722			pub SiblingBridgeHubWithEthereumInboundQueueV2Instance: Location = Location::new(
723				1,
724				[
725					Parachain(SiblingBridgeHubParaId::get()),
726					PalletInstance(INBOUND_QUEUE_PALLET_INDEX_V2)
727				]
728			);
729
730			/// Set up exporters configuration.
731			/// `Option<Asset>` represents static "base fee" which is used for total delivery fee calculation.
732			pub EthereumBridgeTableV1: vec::Vec<NetworkExportTableItem> = vec![
733				NetworkExportTableItem::new(
734					EthereumNetwork::get(),
735					Some(vec![Junctions::Here]),
736					SiblingBridgeHub::get(),
737					Some((
738						XcmBridgeHubRouterFeeAssetId::get(),
739						BridgeHubEthereumBaseFee::get(),
740					).into())
741				),
742			];
743
744			pub EthereumBridgeTableV2: vec::Vec<NetworkExportTableItem> = vec![
745				NetworkExportTableItem::new(
746					EthereumNetwork::get(),
747					Some(vec![Junctions::Here]),
748					SiblingBridgeHub::get(),
749					Some((
750						XcmBridgeHubRouterFeeAssetId::get(),
751						BridgeHubEthereumBaseFeeV2::get(),
752					).into())
753				),
754			];
755
756			/// Universal aliases
757			pub UniversalAliases: BTreeSet<(Location, Junction)> = BTreeSet::from_iter(
758				vec![
759					(SiblingBridgeHubWithEthereumInboundQueueV2Instance::get(), GlobalConsensus(EthereumNetwork::get().into())),
760					(SiblingBridgeHubWithEthereumInboundQueueV1Instance::get(), GlobalConsensus(EthereumNetwork::get().into())),
761				]
762			);
763		}
764
765		pub type EthereumNetworkExportTableV1 =
766			xcm_builder::NetworkExportTable<EthereumBridgeTableV1>;
767
768		pub type EthereumNetworkExportTableV2 =
769			snowbridge_outbound_queue_primitives::v2::XcmFilterExporter<
770				xcm_builder::NetworkExportTable<EthereumBridgeTableV2>,
771				snowbridge_outbound_queue_primitives::v2::XcmForSnowbridgeV2,
772			>;
773
774		pub type EthereumAssetFromEthereum =
775			IsForeignConcreteAsset<FromNetwork<UniversalLocation, EthereumNetwork>>;
776
777		impl Contains<(Location, Junction)> for UniversalAliases {
778			fn contains(alias: &(Location, Junction)) -> bool {
779				UniversalAliases::get().contains(alias)
780			}
781		}
782	}
783
784	/// Benchmarks helper for bridging configuration.
785	#[cfg(feature = "runtime-benchmarks")]
786	pub struct BridgingBenchmarksHelper;
787
788	#[cfg(feature = "runtime-benchmarks")]
789	impl BridgingBenchmarksHelper {
790		pub fn prepare_universal_alias() -> Option<(Location, Junction)> {
791			let alias =
792				to_rococo::UniversalAliases::get().into_iter().find_map(|(location, junction)| {
793					match to_rococo::SiblingBridgeHubWithBridgeHubRococoInstance::get()
794						.eq(&location)
795					{
796						true => Some((location, junction)),
797						false => None,
798					}
799				});
800			Some(alias.expect("we expect here BridgeHubWestend to Rococo mapping at least"))
801		}
802	}
803}