referrerpolicy=no-referrer-when-downgrade

pallet_staking_async_parachain_runtime/
xcm_config.rs

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