Skip to main content

asset_hub_rococo_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	AccountId, AllPalletsWithSystem, Assets, Balance, Balances, BaseDeliveryFee, CollatorSelection,
18	FeeAssetId, ForeignAssets, ParachainInfo, ParachainSystem, PolkadotXcm, PoolAssets, Runtime,
19	RuntimeCall, RuntimeEvent, RuntimeHoldReason, RuntimeOrigin, ToWestendXcmRouter,
20	TransactionByteFee, Uniques, WeightToFee, XcmpQueue,
21};
22use assets_common::{
23	matching::{
24		FromNetwork, IsForeignConcreteAsset, NonTeleportableAssetFromTrustedReserve,
25		ParentLocation, TeleportableAssetWithTrustedReserve,
26	},
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::{AuthorizedAliasers, XcmPassthrough};
39use parachains_common::{
40	xcm_config::{
41		AllSiblingSystemParachains, ConcreteAssetFromSystem, ParentRelayOrSiblingParachains,
42		RelayOrOtherSystemParachains,
43	},
44	TREASURY_PALLET_ID,
45};
46use polkadot_parachain_primitives::primitives::Sibling;
47use polkadot_runtime_common::xcm_sender::ExponentialPrice;
48use rococo_runtime_constants::system_parachain::ASSET_HUB_ID;
49use sp_runtime::traits::{AccountIdConversion, TryConvertInto};
50use testnet_parachains_constants::rococo::snowbridge::{
51	EthereumNetwork, INBOUND_QUEUE_PALLET_INDEX,
52};
53use xcm::latest::{prelude::*, ROCOCO_GENESIS_HASH, WESTEND_GENESIS_HASH};
54use xcm_builder::{
55	unique_instances::UniqueInstancesAdapter, AccountId32Aliases, AliasChildLocation,
56	AllowExplicitUnpaidExecutionFrom, AllowHrmpNotificationsFromRelayChain,
57	AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom,
58	DenyRecursively, DenyReserveTransferToRelayChain, DenyThenTry, DescribeAllTerminal,
59	DescribeFamily, EnsureXcmOrigin, ExternalConsensusLocationsConverterFor,
60	FrameTransactionalProcessor, FungibleAdapter, FungiblesAdapter, HashedDescription, IsConcrete,
61	LocalMint, MatchInClassInstances, MatchedConvertedConcreteId, NetworkExportTableItem,
62	NoChecking, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SendXcmFeeToAccount,
63	SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative,
64	SignedToAccountId32, SingleAssetExchangeAdapter, SovereignPaidRemoteExporter,
65	SovereignSignedViaLocation, StartsWith, StartsWithExplicitGlobalConsensus, TakeWeightCredit,
66	TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin,
67	WithLatestLocationConverter, WithUniqueTopic, XcmFeeManagerFromComponents,
68};
69use xcm_executor::XcmExecutor;
70
71parameter_types! {
72	pub const RootLocation: Location = Location::here();
73	pub const TokenLocation: Location = Location::parent();
74	pub const RelayNetwork: NetworkId = NetworkId::ByGenesis(ROCOCO_GENESIS_HASH);
75	pub const AssetHubParaId: crate::ParaId = crate::ParaId::new(ASSET_HUB_ID);
76	pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into();
77	pub UniversalLocation: InteriorLocation =
78		[GlobalConsensus(RelayNetwork::get()), Parachain(ParachainInfo::parachain_id().into())].into();
79	pub UniversalLocationNetworkId: NetworkId = UniversalLocation::get().global_consensus().unwrap();
80	pub TrustBackedAssetsPalletLocation: Location =
81		PalletInstance(TrustBackedAssetsPalletIndex::get()).into();
82	pub TrustBackedAssetsPalletIndex: u8 = <Assets as PalletInfoAccess>::index() as u8;
83	pub TrustBackedAssetsPalletLocationV3: xcm::v3::Location =
84		xcm::v3::Junction::PalletInstance(<Assets as PalletInfoAccess>::index() as u8).into();
85	pub PoolAssetsPalletLocationV3: xcm::v3::Location =
86		xcm::v3::Junction::PalletInstance(<PoolAssets as PalletInfoAccess>::index() as u8).into();
87	pub ForeignAssetsPalletLocation: Location =
88		PalletInstance(<ForeignAssets as PalletInfoAccess>::index() as u8).into();
89	pub PoolAssetsPalletLocation: Location =
90		PalletInstance(<PoolAssets as PalletInfoAccess>::index() as u8).into();
91	pub UniquesPalletLocation: Location =
92		PalletInstance(<Uniques as PalletInfoAccess>::index() as u8).into();
93	pub CheckingAccount: AccountId = PolkadotXcm::check_account();
94	pub const GovernanceLocation: Location = Location::parent();
95	pub StakingPot: AccountId = CollatorSelection::account_id();
96	pub TreasuryAccount: AccountId = TREASURY_PALLET_ID.into_account_truncating();
97	pub RelayTreasuryLocation: Location = (Parent, PalletInstance(rococo_runtime_constants::TREASURY_PALLET_ID)).into();
98}
99
100/// Type for specifying how a `Location` can be converted into an `AccountId`. This is used
101/// when determining ownership of accounts for asset transacting and when attempting to use XCM
102/// `Transact` in order to determine the dispatch Origin.
103pub type LocationToAccountId = (
104	// The parent (Relay-chain) origin converts to the parent `AccountId`.
105	ParentIsPreset<AccountId>,
106	// Sibling parachain origins convert to AccountId via the `ParaId::into`.
107	SiblingParachainConvertsVia<Sibling, AccountId>,
108	// Straight up local `AccountId32` origins just alias directly to `AccountId`.
109	AccountId32Aliases<RelayNetwork, AccountId>,
110	// Foreign locations alias into accounts according to a hash of their standard description.
111	HashedDescription<AccountId, DescribeFamily<DescribeAllTerminal>>,
112	// Different global consensus locations sovereign accounts.
113	ExternalConsensusLocationsConverterFor<UniversalLocation, AccountId>,
114);
115
116/// Means for transacting the native currency on this chain.
117pub type FungibleTransactor = FungibleAdapter<
118	// Use this currency:
119	Balances,
120	// Use this currency when it is a fungible asset matching the given location or name:
121	IsConcrete<TokenLocation>,
122	// Convert an XCM Location into a local account id:
123	LocationToAccountId,
124	// Our chain's account ID type (we can't get away without mentioning it explicitly):
125	AccountId,
126	// We don't track any teleports of `Balances`.
127	(),
128>;
129
130/// `AssetId`/`Balance` converter for `TrustBackedAssets`.
131pub type TrustBackedAssetsConvertedConcreteId =
132	assets_common::TrustBackedAssetsConvertedConcreteId<TrustBackedAssetsPalletLocation, Balance>;
133
134/// Means for transacting assets besides the native currency on this chain.
135pub type FungiblesTransactor = FungiblesAdapter<
136	// Use this fungibles implementation:
137	Assets,
138	// Use this currency when it is a fungible asset matching the given location or name:
139	TrustBackedAssetsConvertedConcreteId,
140	// Convert an XCM Location into a local account id:
141	LocationToAccountId,
142	// Our chain's account ID type (we can't get away without mentioning it explicitly):
143	AccountId,
144	// We only want to allow teleports of known assets. We use non-zero issuance as an indication
145	// that this asset is known.
146	LocalMint<parachains_common::impls::NonZeroIssuance<AccountId, Assets>>,
147	// The account to use for tracking teleports.
148	CheckingAccount,
149>;
150
151/// Matcher for converting `ClassId`/`InstanceId` into a uniques asset.
152pub type UniquesConvertedConcreteId =
153	assets_common::UniquesConvertedConcreteId<UniquesPalletLocation>;
154
155/// Means for transacting unique assets.
156pub type UniquesTransactor = UniqueInstancesAdapter<
157	AccountId,
158	LocationToAccountId,
159	MatchInClassInstances<UniquesConvertedConcreteId>,
160	pallet_uniques::asset_ops::Item<Uniques>,
161>;
162
163/// `AssetId`/`Balance` converter for `ForeignAssets`.
164pub type ForeignAssetsConvertedConcreteId = assets_common::ForeignAssetsConvertedConcreteId<
165	(
166		// Ignore `TrustBackedAssets` explicitly
167		StartsWith<TrustBackedAssetsPalletLocation>,
168		// Ignore assets that start explicitly with our `GlobalConsensus(NetworkId)`, means:
169		// - foreign assets from our consensus should be: `Location {parents: 1, X*(Parachain(xyz),
170		//   ..)}`
171		// - foreign assets outside our consensus with the same `GlobalConsensus(NetworkId)` won't
172		//   be accepted here
173		StartsWithExplicitGlobalConsensus<UniversalLocationNetworkId>,
174	),
175	Balance,
176	xcm::v5::Location,
177>;
178
179/// Means for transacting foreign assets from different global consensus.
180pub type ForeignFungiblesTransactor = FungiblesAdapter<
181	// Use this fungibles implementation:
182	ForeignAssets,
183	// Use this currency when it is a fungible asset matching the given location or name:
184	ForeignAssetsConvertedConcreteId,
185	// Convert an XCM Location into a local account id:
186	LocationToAccountId,
187	// Our chain's account ID type (we can't get away without mentioning it explicitly):
188	AccountId,
189	// We don't need to check teleports here.
190	NoChecking,
191	// The account to use for tracking teleports.
192	CheckingAccount,
193>;
194
195/// `AssetId`/`Balance` converter for `PoolAssets`.
196pub type PoolAssetsConvertedConcreteId =
197	assets_common::PoolAssetsConvertedConcreteId<PoolAssetsPalletLocation, Balance>;
198
199/// Means for transacting asset conversion pool assets on this chain.
200pub type PoolFungiblesTransactor = FungiblesAdapter<
201	// Use this fungibles implementation:
202	PoolAssets,
203	// Use this currency when it is a fungible asset matching the given location or name:
204	PoolAssetsConvertedConcreteId,
205	// Convert an XCM Location into a local account id:
206	LocationToAccountId,
207	// Our chain's account ID type (we can't get away without mentioning it explicitly):
208	AccountId,
209	// We only want to allow teleports of known assets. We use non-zero issuance as an indication
210	// that this asset is known.
211	LocalMint<parachains_common::impls::NonZeroIssuance<AccountId, PoolAssets>>,
212	// The account to use for tracking teleports.
213	CheckingAccount,
214>;
215
216/// Means for transacting assets on this chain.
217pub type AssetTransactors = (
218	FungibleTransactor,
219	FungiblesTransactor,
220	ForeignFungiblesTransactor,
221	PoolFungiblesTransactor,
222	UniquesTransactor,
223);
224
225/// This is the type we use to convert an (incoming) XCM origin into a local `Origin` instance,
226/// ready for dispatching a transaction with Xcm's `Transact`. There is an `OriginKind` which can
227/// biases the kind of local `Origin` it will become.
228pub type XcmOriginToTransactDispatchOrigin = (
229	// Sovereign account converter; this attempts to derive an `AccountId` from the origin location
230	// using `LocationToAccountId` and then turn that into the usual `Signed` origin. Useful for
231	// foreign chains who want to have a local sovereign account on this chain which they control.
232	SovereignSignedViaLocation<LocationToAccountId, RuntimeOrigin>,
233	// Native converter for Relay-chain (Parent) location; will convert to a `Relay` origin when
234	// recognised.
235	RelayChainAsNative<RelayChainOrigin, RuntimeOrigin>,
236	// Native converter for sibling Parachains; will convert to a `SiblingPara` origin when
237	// recognised.
238	SiblingParachainAsNative<cumulus_pallet_xcm::Origin, RuntimeOrigin>,
239	// Superuser converter for the Relay-chain (Parent) location. This will allow it to issue a
240	// transaction from the Root origin.
241	ParentAsSuperuser<RuntimeOrigin>,
242	// Native signed account converter; this just converts an `AccountId32` origin into a normal
243	// `RuntimeOrigin::Signed` origin of the same 32-byte value.
244	SignedAccountId32AsNative<RelayNetwork, RuntimeOrigin>,
245	// Xcm origins can be represented natively under the Xcm pallet's Xcm origin.
246	XcmPassthrough<RuntimeOrigin>,
247);
248
249parameter_types! {
250	pub const MaxInstructions: u32 = 100;
251	pub const MaxAssetsIntoHolding: u32 = 64;
252}
253
254pub struct ParentOrParentsPlurality;
255impl Contains<Location> for ParentOrParentsPlurality {
256	fn contains(location: &Location) -> bool {
257		matches!(location.unpack(), (1, []) | (1, [Plurality { .. }]))
258	}
259}
260
261pub type Barrier = TrailingSetTopicAsId<
262	DenyThenTry<
263		DenyRecursively<DenyReserveTransferToRelayChain>,
264		(
265			TakeWeightCredit,
266			// Expected responses are OK.
267			AllowKnownQueryResponses<PolkadotXcm>,
268			// Allow XCMs with some computed origins to pass through.
269			WithComputedOrigin<
270				(
271					// If the message is one that immediately attempts to pay for execution, then
272					// allow it.
273					AllowTopLevelPaidExecutionFrom<Everything>,
274					// Parent, its pluralities (i.e. governance bodies), relay treasury pallet and
275					// BridgeHub get free execution.
276					AllowExplicitUnpaidExecutionFrom<(
277						ParentOrParentsPlurality,
278						Equals<RelayTreasuryLocation>,
279						Equals<bridging::SiblingBridgeHub>,
280					)>,
281					// Subscriptions for version tracking are OK.
282					AllowSubscriptionsFrom<ParentRelayOrSiblingParachains>,
283					// HRMP notifications from the relay chain are OK.
284					AllowHrmpNotificationsFromRelayChain,
285				),
286				UniversalLocation,
287				ConstU32<8>,
288			>,
289		),
290	>,
291>;
292
293/// Locations that will not be charged fees in the executor,
294/// either execution or delivery.
295/// We only waive fees for system functions, which these locations represent.
296pub type WaivedLocations = (
297	Equals<RootLocation>,
298	RelayOrOtherSystemParachains<AllSiblingSystemParachains, Runtime>,
299	Equals<RelayTreasuryLocation>,
300);
301
302// Asset Hub trusts only particular, pre-configured bridged locations from a different consensus
303// as reserve locations (we trust the Bridge Hub to relay the message that a reserve is being
304// held). On Rococo Asset Hub, we allow Westend Asset Hub to act as reserve for any asset native
305// to the Westend ecosystem. We also allow Ethereum contracts to act as reserves for the foreign
306// assets identified by the same respective contracts locations.
307pub type TrustedReserves = (
308	bridging::to_westend::WestendOrEthereumAssetFromAssetHubWestend,
309	bridging::to_ethereum::EthereumAssetFromEthereum,
310	IsForeignConcreteAsset<
311		NonTeleportableAssetFromTrustedReserve<AssetHubParaId, crate::ForeignAssets>,
312	>,
313);
314
315/// Cases where a remote origin is accepted as trusted Teleporter for a given asset:
316///
317/// - ROC with the parent Relay Chain and sibling system parachains; and
318/// - Sibling parachains' assets from where they originate (as `ForeignCreators`).
319pub type TrustedTeleporters = (
320	ConcreteAssetFromSystem<TokenLocation>,
321	IsForeignConcreteAsset<
322		TeleportableAssetWithTrustedReserve<AssetHubParaId, crate::ForeignAssets>,
323	>,
324);
325
326/// Defines origin aliasing rules for this chain.
327///
328/// - Allow any origin to alias into a child sub-location (equivalent to DescendOrigin),
329/// - Allow origins explicitly authorized by the alias target location.
330pub type TrustedAliasers = (AliasChildLocation, AuthorizedAliasers<Runtime>);
331
332/// Asset converter for pool assets.
333/// Used to convert one asset to another, when there is a pool available between the two.
334/// This type thus allows paying fees with any asset as long as there is a pool between said
335/// asset and the asset required for fee payment.
336pub type PoolAssetsExchanger = SingleAssetExchangeAdapter<
337	crate::AssetConversion,
338	crate::NativeAndNonPoolAssets,
339	(
340		TrustBackedAssetsAsLocation<TrustBackedAssetsPalletLocation, Balance, xcm::v5::Location>,
341		ForeignAssetsConvertedConcreteId,
342		// `ForeignAssetsConvertedConcreteId` excludes the relay token, so we add it back here.
343		MatchedConvertedConcreteId<
344			xcm::v5::Location,
345			Balance,
346			Equals<ParentLocation>,
347			WithLatestLocationConverter<xcm::v5::Location>,
348			TryConvertInto,
349		>,
350	),
351	AccountId,
352>;
353
354pub struct XcmConfig;
355impl xcm_executor::Config for XcmConfig {
356	type RuntimeCall = RuntimeCall;
357	type XcmSender = XcmRouter;
358	type XcmEventEmitter = PolkadotXcm;
359	type AssetTransactor = AssetTransactors;
360	type OriginConverter = XcmOriginToTransactDispatchOrigin;
361	type IsReserve = TrustedReserves;
362	type IsTeleporter = TrustedTeleporters;
363	type UniversalLocation = UniversalLocation;
364	type Barrier = Barrier;
365	type Weigher = WeightInfoBounds<
366		crate::weights::xcm::AssetHubRococoXcmWeight<RuntimeCall>,
367		RuntimeCall,
368		MaxInstructions,
369	>;
370	type Trader = (
371		UsingComponents<
372			WeightToFee,
373			TokenLocation,
374			AccountId,
375			Balances,
376			ResolveTo<StakingPot, Balances>,
377		>,
378		cumulus_primitives_utility::SwapFirstAssetTrader<
379			TokenLocation,
380			crate::AssetConversion,
381			WeightToFee,
382			crate::NativeAndNonPoolAssets,
383			(
384				TrustBackedAssetsAsLocation<
385					TrustBackedAssetsPalletLocation,
386					Balance,
387					xcm::v5::Location,
388				>,
389				ForeignAssetsConvertedConcreteId,
390			),
391			ResolveAssetTo<StakingPot, crate::NativeAndNonPoolAssets>,
392			AccountId,
393		>,
394	);
395	type ResponseHandler = PolkadotXcm;
396	type AssetTrap = PolkadotXcm;
397	type SubscriptionService = PolkadotXcm;
398	type PalletInstancesInfo = AllPalletsWithSystem;
399	type MaxAssetsIntoHolding = MaxAssetsIntoHolding;
400	type AssetLocker = ();
401	type AssetExchanger = PoolAssetsExchanger;
402	type FeeManager = XcmFeeManagerFromComponents<
403		WaivedLocations,
404		SendXcmFeeToAccount<Self::AssetTransactor, TreasuryAccount>,
405	>;
406	type MessageExporter = ();
407	type UniversalAliases =
408		(bridging::to_westend::UniversalAliases, bridging::to_ethereum::UniversalAliases);
409	type CallDispatcher = RuntimeCall;
410	type SafeCallFilter = Everything;
411	// We allow any origin to alias into a child sub-location (equivalent to DescendOrigin).
412	type Aliasers = TrustedAliasers;
413	type TransactionalProcessor = FrameTransactionalProcessor;
414	type HrmpNewChannelOpenRequestHandler = ();
415	type HrmpChannelAcceptedHandler = ();
416	type HrmpChannelClosingHandler = ();
417	type XcmRecorder = PolkadotXcm;
418}
419
420/// Converts a local signed origin into an XCM location. Forms the basis for local origins
421/// sending/executing XCMs.
422pub type LocalOriginToLocation = SignedToAccountId32<RuntimeOrigin, AccountId, RelayNetwork>;
423
424pub type PriceForParentDelivery =
425	ExponentialPrice<FeeAssetId, BaseDeliveryFee, TransactionByteFee, ParachainSystem>;
426
427/// For routing XCM messages which do not cross local consensus boundary.
428type LocalXcmRouter = (
429	// Two routers - use UMP to communicate with the relay chain:
430	cumulus_primitives_utility::ParentAsUmp<ParachainSystem, PolkadotXcm, PriceForParentDelivery>,
431	// ..and XCMP to communicate with the sibling chains.
432	XcmpQueue,
433);
434
435/// The means for routing XCM messages which are not for local execution into the right message
436/// queues.
437pub type XcmRouter = WithUniqueTopic<(
438	LocalXcmRouter,
439	// Router which wraps and sends xcm to BridgeHub to be delivered to the Westend
440	// GlobalConsensus
441	ToWestendXcmRouter,
442	// Router which wraps and sends xcm to BridgeHub to be delivered to the Ethereum
443	// GlobalConsensus
444	SovereignPaidRemoteExporter<bridging::EthereumNetworkExportTable, XcmpQueue, UniversalLocation>,
445)>;
446
447parameter_types! {
448	pub const DepositPerItem: Balance = crate::deposit(1, 0);
449	pub const DepositPerByte: Balance = crate::deposit(0, 1);
450	pub const AuthorizeAliasHoldReason: RuntimeHoldReason = RuntimeHoldReason::PolkadotXcm(pallet_xcm::HoldReason::AuthorizeAlias);
451}
452
453impl pallet_xcm::Config for Runtime {
454	type RuntimeEvent = RuntimeEvent;
455	// We want to disallow users sending (arbitrary) XCMs from this chain.
456	type SendXcmOrigin = EnsureXcmOrigin<RuntimeOrigin, ()>;
457	type XcmRouter = XcmRouter;
458	// We support local origins dispatching XCM executions.
459	type ExecuteXcmOrigin = EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>;
460	type XcmExecuteFilter = Everything;
461	type XcmExecutor = XcmExecutor<XcmConfig>;
462	type XcmTeleportFilter = Everything;
463	type XcmReserveTransferFilter = Everything;
464	type Weigher = WeightInfoBounds<
465		crate::weights::xcm::AssetHubRococoXcmWeight<RuntimeCall>,
466		RuntimeCall,
467		MaxInstructions,
468	>;
469	type UniversalLocation = UniversalLocation;
470	type RuntimeOrigin = RuntimeOrigin;
471	type RuntimeCall = RuntimeCall;
472	const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100;
473	type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion;
474	type Currency = Balances;
475	type CurrencyMatcher = ();
476	type TrustedLockers = ();
477	type SovereignAccountOf = LocationToAccountId;
478	type MaxLockers = ConstU32<8>;
479	type WeightInfo = crate::weights::pallet_xcm::WeightInfo<Runtime>;
480	type AdminOrigin = EnsureRoot<AccountId>;
481	type MaxRemoteLockConsumers = ConstU32<0>;
482	type RemoteLockConsumerIdentifier = ();
483	// xcm_executor::Config::Aliasers also uses pallet_xcm::AuthorizedAliasers.
484	type AuthorizedAliasConsideration = HoldConsideration<
485		AccountId,
486		Balances,
487		AuthorizeAliasHoldReason,
488		LinearStoragePrice<DepositPerItem, DepositPerByte, Balance>,
489	>;
490}
491
492impl cumulus_pallet_xcm::Config for Runtime {
493	type RuntimeEvent = RuntimeEvent;
494	type XcmExecutor = XcmExecutor<XcmConfig>;
495}
496
497/// All configuration related to bridging
498pub mod bridging {
499	use super::*;
500	use alloc::collections::btree_set::BTreeSet;
501	use assets_common::matching;
502
503	// common/shared parameters
504	parameter_types! {
505		/// Base price of every byte of the Rococo -> Westend message. Can be adjusted via
506		/// governance `set_storage` call.
507		///
508		/// Default value is our estimation of the:
509		///
510		/// 1) an approximate cost of XCM execution (`ExportMessage` and surroundings) at Rococo bridge hub;
511		///
512		/// 2) the approximate cost of Rococo -> Westend message delivery transaction on Westend Bridge Hub,
513		///    converted into ROCs using 1:1 conversion rate;
514		///
515		/// 3) the approximate cost of Rococo -> Westend message confirmation transaction on Rococo Bridge Hub.
516		pub storage XcmBridgeHubRouterBaseFee: Balance =
517			bp_bridge_hub_rococo::BridgeHubRococoBaseXcmFeeInRocs::get()
518				.saturating_add(bp_bridge_hub_westend::BridgeHubWestendBaseDeliveryFeeInWnds::get())
519				.saturating_add(bp_bridge_hub_rococo::BridgeHubRococoBaseConfirmationFeeInRocs::get());
520		/// Price of every byte of the Rococo -> Westend message. Can be adjusted via
521		/// governance `set_storage` call.
522		pub storage XcmBridgeHubRouterByteFee: Balance = TransactionByteFee::get();
523
524		pub SiblingBridgeHubParaId: u32 = bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID;
525		pub SiblingBridgeHub: Location = Location::new(1, [Parachain(SiblingBridgeHubParaId::get())]);
526		/// Router expects payment with this `AssetId`.
527		/// (`AssetId` has to be aligned with `BridgeTable`)
528		pub XcmBridgeHubRouterFeeAssetId: AssetId = TokenLocation::get().into();
529
530		pub BridgeTable: alloc::vec::Vec<NetworkExportTableItem> =
531			alloc::vec::Vec::new().into_iter()
532			.chain(to_westend::BridgeTable::get())
533			.collect();
534
535		pub EthereumBridgeTable: alloc::vec::Vec<NetworkExportTableItem> =
536			alloc::vec::Vec::new().into_iter()
537			.chain(to_ethereum::BridgeTable::get())
538			.collect();
539	}
540
541	pub type NetworkExportTable = xcm_builder::NetworkExportTable<BridgeTable>;
542
543	pub type EthereumNetworkExportTable = xcm_builder::NetworkExportTable<EthereumBridgeTable>;
544
545	pub mod to_westend {
546		use super::*;
547
548		parameter_types! {
549			pub SiblingBridgeHubWithBridgeHubWestendInstance: Location = Location::new(
550				1,
551				[
552					Parachain(SiblingBridgeHubParaId::get()),
553					PalletInstance(bp_bridge_hub_rococo::WITH_BRIDGE_ROCOCO_TO_WESTEND_MESSAGES_PALLET_INDEX)
554				]
555			);
556
557			pub const WestendNetwork: NetworkId = NetworkId::ByGenesis(WESTEND_GENESIS_HASH);
558			pub const EthereumNetwork: NetworkId = NetworkId::Ethereum { chain_id: 11155111 };
559			pub WestendEcosystem: Location = Location::new(2, [GlobalConsensus(WestendNetwork::get())]);
560			pub EthereumEcosystem: Location = Location::new(2, [GlobalConsensus(EthereumNetwork::get())]);
561			pub WndLocation: Location = Location::new(2, [GlobalConsensus(WestendNetwork::get())]);
562			pub AssetHubWestend: Location = Location::new(2, [
563				GlobalConsensus(WestendNetwork::get()),
564				Parachain(bp_asset_hub_westend::ASSET_HUB_WESTEND_PARACHAIN_ID)
565			]);
566
567			/// Set up exporters configuration.
568			/// `Option<Asset>` represents static "base fee" which is used for total delivery fee calculation.
569			pub BridgeTable: alloc::vec::Vec<NetworkExportTableItem> = alloc::vec![
570				NetworkExportTableItem::new(
571					WestendNetwork::get(),
572					Some(alloc::vec![
573						AssetHubWestend::get().interior.split_global().expect("invalid configuration for AssetHubWestend").1,
574					]),
575					SiblingBridgeHub::get(),
576					// base delivery fee to local `BridgeHub`
577					Some((
578						XcmBridgeHubRouterFeeAssetId::get(),
579						XcmBridgeHubRouterBaseFee::get(),
580					).into())
581				)
582			];
583
584			/// Universal aliases
585			pub UniversalAliases: BTreeSet<(Location, Junction)> = BTreeSet::from_iter(
586				alloc::vec![
587					(SiblingBridgeHubWithBridgeHubWestendInstance::get(), GlobalConsensus(WestendNetwork::get()))
588				]
589			);
590		}
591
592		impl Contains<(Location, Junction)> for UniversalAliases {
593			fn contains(alias: &(Location, Junction)) -> bool {
594				UniversalAliases::get().contains(alias)
595			}
596		}
597
598		/// Allow any asset native to the Westend or Ethereum ecosystems if it comes from Westend
599		/// Asset Hub.
600		pub type WestendOrEthereumAssetFromAssetHubWestend = matching::RemoteAssetFromLocation<
601			(StartsWith<WestendEcosystem>, StartsWith<EthereumEcosystem>),
602			AssetHubWestend,
603		>;
604	}
605
606	pub mod to_ethereum {
607		use super::*;
608
609		parameter_types! {
610			/// User fee for ERC20 token transfer back to Ethereum.
611			/// (initially was calculated by test `OutboundQueue::calculate_fees` - ETH/ROC 1/400 and fee_per_gas 20 GWEI = 2200698000000 + *25%)
612			/// Needs to be more than fee calculated from DefaultFeeConfig FeeConfigRecord in snowbridge:parachain/pallets/outbound-queue/src/lib.rs
613			/// Polkadot uses 10 decimals, Kusama and Rococo 12 decimals.
614			pub const DefaultBridgeHubEthereumBaseFee: Balance = 3_833_568_200_000;
615			pub storage BridgeHubEthereumBaseFee: Balance = DefaultBridgeHubEthereumBaseFee::get();
616			pub SiblingBridgeHubWithEthereumInboundQueueInstance: Location = Location::new(
617				1,
618				[
619					Parachain(SiblingBridgeHubParaId::get()),
620					PalletInstance(INBOUND_QUEUE_PALLET_INDEX)
621				]
622			);
623
624			/// Set up exporters configuration.
625			/// `Option<Asset>` represents static "base fee" which is used for total delivery fee calculation.
626			pub BridgeTable: alloc::vec::Vec<NetworkExportTableItem> = alloc::vec![
627				NetworkExportTableItem::new(
628					EthereumNetwork::get().into(),
629					Some(alloc::vec![Junctions::Here]),
630					SiblingBridgeHub::get(),
631					Some((
632						XcmBridgeHubRouterFeeAssetId::get(),
633						BridgeHubEthereumBaseFee::get(),
634					).into())
635				),
636			];
637
638			/// Universal aliases
639			pub UniversalAliases: BTreeSet<(Location, Junction)> = BTreeSet::from_iter(
640				alloc::vec![
641					(SiblingBridgeHubWithEthereumInboundQueueInstance::get(), GlobalConsensus(EthereumNetwork::get().into())),
642				]
643			);
644		}
645
646		pub type EthereumAssetFromEthereum =
647			IsForeignConcreteAsset<FromNetwork<UniversalLocation, EthereumNetwork>>;
648
649		impl Contains<(Location, Junction)> for UniversalAliases {
650			fn contains(alias: &(Location, Junction)) -> bool {
651				UniversalAliases::get().contains(alias)
652			}
653		}
654	}
655
656	/// Benchmarks helper for bridging configuration.
657	#[cfg(feature = "runtime-benchmarks")]
658	pub struct BridgingBenchmarksHelper;
659
660	#[cfg(feature = "runtime-benchmarks")]
661	impl BridgingBenchmarksHelper {
662		pub fn prepare_universal_alias() -> Option<(Location, Junction)> {
663			let alias =
664				to_westend::UniversalAliases::get()
665					.into_iter()
666					.find_map(|(location, junction)| {
667						match to_westend::SiblingBridgeHubWithBridgeHubWestendInstance::get()
668							.eq(&location)
669						{
670							true => Some((location, junction)),
671							false => None,
672						}
673					});
674			Some(alias.expect("we expect here BridgeHubRococo to Westend mapping at least"))
675		}
676	}
677}