polkadot_runtime/
xcm_config.rs

1// Copyright (C) Parity Technologies (UK) Ltd.
2// This file is part of Polkadot.
3
4// Polkadot is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// Polkadot is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.
16
17//! XCM configuration for Polkadot.
18
19use super::{
20	parachains_origin, AccountId, AllPalletsWithSystem, Balances, Dmp, FellowshipAdmin,
21	GeneralAdmin, ParaId, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, StakingAdmin,
22	TransactionByteFee, WeightToFee, XcmPallet,
23};
24use frame_support::{
25	match_types, parameter_types,
26	traits::{Everything, Nothing},
27	weights::Weight,
28};
29use frame_system::EnsureRoot;
30use pallet_xcm::XcmPassthrough;
31use polkadot_runtime_constants::{
32	currency::CENTS, system_parachain::*, xcm::body::FELLOWSHIP_ADMIN_INDEX,
33};
34use runtime_common::{
35	xcm_sender::{ChildParachainRouter, ExponentialPrice},
36	ToAuthor,
37};
38use sp_core::ConstU32;
39use xcm::latest::prelude::*;
40use xcm_builder::{
41	AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses,
42	AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, ChildParachainAsNative,
43	ChildParachainConvertsVia, CurrencyAdapter as XcmCurrencyAdapter, DescribeBodyTerminal,
44	DescribeFamily, HashedDescription, IsConcrete, MintLocation, OriginToPluralityVoice,
45	SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit,
46	TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic,
47};
48
49parameter_types! {
50	/// The location of the DOT token, from the context of this chain. Since this token is native to this
51	/// chain, we make it synonymous with it and thus it is the `Here` location, which means "equivalent to
52	/// the context".
53	pub const TokenLocation: MultiLocation = Here.into_location();
54	/// The Polkadot network ID. This is named.
55	pub const ThisNetwork: NetworkId = NetworkId::Polkadot;
56	/// Our location in the universe of consensus systems.
57	pub const UniversalLocation: InteriorMultiLocation = X1(GlobalConsensus(ThisNetwork::get()));
58	/// The Checking Account, which holds any native assets that have been teleported out and not back in (yet).
59	pub CheckAccount: AccountId = XcmPallet::check_account();
60	/// The Checking Account along with the indication that the local chain is able to mint tokens.
61	pub LocalCheckAccount: (AccountId, MintLocation) = (CheckAccount::get(), MintLocation::Local);
62}
63
64/// The canonical means of converting a `MultiLocation` into an `AccountId`, used when we want to
65/// determine the sovereign account controlled by a location.
66pub type SovereignAccountOf = (
67	// We can convert a child parachain using the standard `AccountId` conversion.
68	ChildParachainConvertsVia<ParaId, AccountId>,
69	// We can directly alias an `AccountId32` into a local account.
70	AccountId32Aliases<ThisNetwork, AccountId>,
71	// Allow governance body to be used as a sovereign account.
72	HashedDescription<AccountId, DescribeFamily<DescribeBodyTerminal>>,
73);
74
75/// Our asset transactor. This is what allows us to interact with the runtime assets from the point
76/// of view of XCM-only concepts like `MultiLocation` and `MultiAsset`.
77///
78/// Ours is only aware of the Balances pallet, which is mapped to `TokenLocation`.
79pub type LocalAssetTransactor = XcmCurrencyAdapter<
80	// Use this currency:
81	Balances,
82	// Use this currency when it is a fungible asset matching the given location or name:
83	IsConcrete<TokenLocation>,
84	// We can convert the MultiLocations with our converter above:
85	SovereignAccountOf,
86	// Our chain's account ID type (we can't get away without mentioning it explicitly):
87	AccountId,
88	// We track our teleports in/out to keep total issuance correct.
89	LocalCheckAccount,
90>;
91
92/// The means that we convert an XCM origin `MultiLocation` into the runtime's `Origin` type for
93/// local dispatch. This is a conversion function from an `OriginKind` type along with the
94/// `MultiLocation` value and returns an `Origin` value or an error.
95type LocalOriginConverter = (
96	// If the origin kind is `Sovereign`, then return a `Signed` origin with the account determined
97	// by the `SovereignAccountOf` converter.
98	SovereignSignedViaLocation<SovereignAccountOf, RuntimeOrigin>,
99	// If the origin kind is `Native` and the XCM origin is a child parachain, then we can express
100	// it with the special `parachains_origin::Origin` origin variant.
101	ChildParachainAsNative<parachains_origin::Origin, RuntimeOrigin>,
102	// If the origin kind is `Native` and the XCM origin is the `AccountId32` location, then it can
103	// be expressed using the `Signed` origin variant.
104	SignedAccountId32AsNative<ThisNetwork, RuntimeOrigin>,
105	// Xcm origins can be represented natively under the Xcm pallet's Xcm origin.
106	XcmPassthrough<RuntimeOrigin>,
107);
108
109parameter_types! {
110	/// The amount of weight an XCM operation takes. This is a safe overestimate.
111	pub const BaseXcmWeight: Weight = Weight::from_parts(1_000_000_000, 1024);
112	/// Maximum number of instructions in a single XCM fragment. A sanity check against weight
113	/// calculations getting too crazy.
114	pub const MaxInstructions: u32 = 100;
115	/// The asset ID for the asset that we use to pay for message delivery fees.
116	pub FeeAssetId: AssetId = Concrete(TokenLocation::get());
117	/// The base fee for the message delivery fees.
118	pub const BaseDeliveryFee: u128 = CENTS.saturating_mul(3);
119}
120
121/// The XCM router. When we want to send an XCM message, we use this type. It amalgamates all of our
122/// individual routers.
123pub type XcmRouter = WithUniqueTopic<(
124	// Only one router so far - use DMP to communicate with child parachains.
125	ChildParachainRouter<
126		Runtime,
127		XcmPallet,
128		ExponentialPrice<FeeAssetId, BaseDeliveryFee, TransactionByteFee, Dmp>,
129	>,
130)>;
131
132parameter_types! {
133	pub const Dot: MultiAssetFilter = Wild(AllOf { fun: WildFungible, id: Concrete(TokenLocation::get()) });
134	pub const StatemintLocation: MultiLocation = Parachain(STATEMINT_ID).into_location();
135	pub const DotForStatemint: (MultiAssetFilter, MultiLocation) = (Dot::get(), StatemintLocation::get());
136	pub const CollectivesLocation: MultiLocation = Parachain(COLLECTIVES_ID).into_location();
137	pub const DotForCollectives: (MultiAssetFilter, MultiLocation) = (Dot::get(), CollectivesLocation::get());
138	pub const MaxAssetsIntoHolding: u32 = 64;
139}
140
141/// Polkadot Relay recognizes/respects the Statemint chain as a teleporter.
142pub type TrustedTeleporters =
143	(xcm_builder::Case<DotForStatemint>, xcm_builder::Case<DotForCollectives>);
144
145match_types! {
146	pub type OnlyParachains: impl Contains<MultiLocation> = {
147		MultiLocation { parents: 0, interior: X1(Parachain(_)) }
148	};
149	pub type CollectivesOrFellows: impl Contains<MultiLocation> = {
150		MultiLocation { parents: 0, interior: X1(Parachain(COLLECTIVES_ID)) } |
151		MultiLocation { parents: 0, interior: X2(Parachain(COLLECTIVES_ID), Plurality { id: BodyId::Technical, .. }) }
152	};
153}
154
155/// The barriers one of which must be passed for an XCM message to be executed.
156pub type Barrier = TrailingSetTopicAsId<(
157	// Weight that is paid for may be consumed.
158	TakeWeightCredit,
159	// Expected responses are OK.
160	AllowKnownQueryResponses<XcmPallet>,
161	WithComputedOrigin<
162		(
163			// If the message is one that immediately attemps to pay for execution, then allow it.
164			AllowTopLevelPaidExecutionFrom<Everything>,
165			// Subscriptions for version tracking are OK.
166			AllowSubscriptionsFrom<OnlyParachains>,
167			// Collectives and Fellows plurality get free execution.
168			AllowExplicitUnpaidExecutionFrom<CollectivesOrFellows>,
169		),
170		UniversalLocation,
171		ConstU32<8>,
172	>,
173)>;
174
175pub struct XcmConfig;
176impl xcm_executor::Config for XcmConfig {
177	type RuntimeCall = RuntimeCall;
178	type XcmSender = XcmRouter;
179	type AssetTransactor = LocalAssetTransactor;
180	type OriginConverter = LocalOriginConverter;
181	// Polkadot Relay recognises no chains which act as reserves.
182	type IsReserve = ();
183	type IsTeleporter = TrustedTeleporters;
184	type UniversalLocation = UniversalLocation;
185	type Barrier = Barrier;
186	type Weigher = WeightInfoBounds<
187		crate::weights::xcm::PolkadotXcmWeight<RuntimeCall>,
188		RuntimeCall,
189		MaxInstructions,
190	>;
191	// The weight trader piggybacks on the existing transaction-fee conversion logic.
192	type Trader =
193		UsingComponents<WeightToFee, TokenLocation, AccountId, Balances, ToAuthor<Runtime>>;
194	type ResponseHandler = XcmPallet;
195	type AssetTrap = XcmPallet;
196	type AssetLocker = ();
197	type AssetExchanger = ();
198	type AssetClaims = XcmPallet;
199	type SubscriptionService = XcmPallet;
200	type PalletInstancesInfo = AllPalletsWithSystem;
201	type MaxAssetsIntoHolding = MaxAssetsIntoHolding;
202	type FeeManager = ();
203	// No bridges yet...
204	type MessageExporter = ();
205	type UniversalAliases = Nothing;
206	type CallDispatcher = RuntimeCall;
207	type SafeCallFilter = Everything;
208	type Aliasers = Nothing;
209}
210
211parameter_types! {
212	// `GeneralAdmin` pluralistic body.
213	pub const GeneralAdminBodyId: BodyId = BodyId::Administration;
214	// StakingAdmin pluralistic body.
215	pub const StakingAdminBodyId: BodyId = BodyId::Defense;
216	// FellowshipAdmin pluralistic body.
217	pub const FellowshipAdminBodyId: BodyId = BodyId::Index(FELLOWSHIP_ADMIN_INDEX);
218}
219
220#[cfg(feature = "runtime-benchmarks")]
221parameter_types! {
222	pub ReachableDest: Option<MultiLocation> = Some(Parachain(1000).into());
223}
224
225/// Type to convert the `GeneralAdmin` origin to a Plurality `MultiLocation` value.
226pub type GeneralAdminToPlurality =
227	OriginToPluralityVoice<RuntimeOrigin, GeneralAdmin, GeneralAdminBodyId>;
228
229/// Type to convert an `Origin` type value into a `MultiLocation` value which represents an interior
230/// location of this chain.
231pub type LocalOriginToLocation = (
232	GeneralAdminToPlurality,
233	// And a usual Signed origin to be used in XCM as a corresponding AccountId32
234	SignedToAccountId32<RuntimeOrigin, AccountId, ThisNetwork>,
235);
236
237/// Type to convert the `StakingAdmin` origin to a Plurality `MultiLocation` value.
238pub type StakingAdminToPlurality =
239	OriginToPluralityVoice<RuntimeOrigin, StakingAdmin, StakingAdminBodyId>;
240
241/// Type to convert the `FellowshipAdmin` origin to a Plurality `MultiLocation` value.
242pub type FellowshipAdminToPlurality =
243	OriginToPluralityVoice<RuntimeOrigin, FellowshipAdmin, FellowshipAdminBodyId>;
244
245/// Type to convert a pallet `Origin` type value into a `MultiLocation` value which represents an
246/// interior location of this chain for a destination chain.
247pub type LocalPalletOriginToLocation = (
248	// GeneralAdmin origin to be used in XCM as a corresponding Plurality `MultiLocation` value.
249	GeneralAdminToPlurality,
250	// StakingAdmin origin to be used in XCM as a corresponding Plurality `MultiLocation` value.
251	StakingAdminToPlurality,
252	// FellowshipAdmin origin to be used in XCM as a corresponding Plurality `MultiLocation` value.
253	FellowshipAdminToPlurality,
254);
255
256impl pallet_xcm::Config for Runtime {
257	type RuntimeEvent = RuntimeEvent;
258	// We only allow the root, the general admin, the fellowship admin and the staking admin to send
259	// messages.
260	type SendXcmOrigin = xcm_builder::EnsureXcmOrigin<RuntimeOrigin, LocalPalletOriginToLocation>;
261	type XcmRouter = XcmRouter;
262	// Anyone can execute XCM messages locally...
263	type ExecuteXcmOrigin = xcm_builder::EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>;
264	// ...but they must match our filter, which rejects all.
265	type XcmExecuteFilter = Nothing; // == Deny All
266	type XcmExecutor = xcm_executor::XcmExecutor<XcmConfig>;
267	type XcmTeleportFilter = Everything; // == Allow All
268	type XcmReserveTransferFilter = Everything; // == Allow All
269	type Weigher = WeightInfoBounds<
270		crate::weights::xcm::PolkadotXcmWeight<RuntimeCall>,
271		RuntimeCall,
272		MaxInstructions,
273	>;
274	type UniversalLocation = UniversalLocation;
275	type RuntimeOrigin = RuntimeOrigin;
276	type RuntimeCall = RuntimeCall;
277	const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100;
278	type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion;
279	type Currency = Balances;
280	type CurrencyMatcher = ();
281	type TrustedLockers = ();
282	type SovereignAccountOf = SovereignAccountOf;
283	type MaxLockers = ConstU32<8>;
284	type MaxRemoteLockConsumers = ConstU32<0>;
285	type RemoteLockConsumerIdentifier = ();
286	type WeightInfo = crate::weights::pallet_xcm::WeightInfo<Runtime>;
287	#[cfg(feature = "runtime-benchmarks")]
288	type ReachableDest = ReachableDest;
289	type AdminOrigin = EnsureRoot<AccountId>;
290}