shiden_runtime/
xcm_config.rs

1// This file is part of Astar.
2
3// Copyright (C) Stake Technologies Pte.Ltd.
4// SPDX-License-Identifier: GPL-3.0-or-later
5
6// Astar is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10
11// Astar is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14// GNU General Public License for more details.
15
16// You should have received a copy of the GNU General Public License
17// along with Astar. If not, see <http://www.gnu.org/licenses/>.
18
19use super::{
20    AccountId, AllPalletsWithSystem, AssetId, Assets, Balance, Balances, DealWithFees,
21    MessageQueue, ParachainInfo, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent,
22    RuntimeOrigin, ShidenAssetLocationIdConverter, TreasuryAccountId, XcAssetConfig,
23    XcmWeightToFee, XcmpQueue,
24};
25use crate::weights;
26use frame_support::{
27    parameter_types,
28    traits::{ConstU32, Contains, Everything, Nothing},
29    weights::Weight,
30};
31use frame_system::EnsureRoot;
32use sp_runtime::traits::{Convert, MaybeEquivalence};
33
34// Polkadot imports
35use cumulus_primitives_core::{AggregateMessageOrigin, ParaId};
36use frame_support::traits::{Disabled, TransformOrigin};
37use parachains_common::{
38    message_queue::ParaIdToSibling, xcm_config::ParentRelayOrSiblingParachains,
39};
40use polkadot_runtime_common::xcm_sender::NoPriceForMessageDelivery;
41use xcm::latest::prelude::*;
42use xcm_builder::{
43    AccountId32Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowUnpaidExecutionFrom,
44    ConvertedConcreteId, DescribeAllTerminal, DescribeFamily, EnsureXcmOrigin,
45    FrameTransactionalProcessor, FungibleAdapter, FungiblesAdapter, HashedDescription, IsConcrete,
46    NoChecking, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative,
47    SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32,
48    SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents,
49    WeightInfoBounds, WithComputedOrigin,
50};
51use xcm_executor::{
52    traits::{JustTry, WithOriginFilter},
53    XcmExecutor,
54};
55
56// ORML imports
57use orml_xcm_support::DisabledParachainFee;
58
59// Astar imports
60use astar_primitives::xcm::{
61    AbsoluteAndRelativeReserveProvider, AccountIdToMultiLocation, AllowTopLevelPaidExecutionFrom,
62    FixedRateOfForeignAsset, ReserveAssetFilter, XcmFungibleFeeHandler,
63};
64
65parameter_types! {
66    pub RelayNetwork: Option<NetworkId> = Some(NetworkId::Kusama);
67    pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into();
68    pub UniversalLocation: InteriorLocation =
69    [GlobalConsensus(RelayNetwork::get().unwrap()), Parachain(ParachainInfo::parachain_id().into())].into();
70    pub const ShidenLocation: Location = Here.into_location();
71    pub DummyCheckingAccount: AccountId = PolkadotXcm::check_account();
72}
73
74/// Type for specifying how a `Location` can be converted into an `AccountId`. This is used
75/// when determining ownership of accounts for asset transacting and when attempting to use XCM
76/// `Transact` in order to determine the dispatch Origin.
77pub type LocationToAccountId = (
78    // The parent (Relay-chain) origin converts to the default `AccountId`.
79    ParentIsPreset<AccountId>,
80    // Sibling parachain origins convert to AccountId via the `ParaId::into`.
81    SiblingParachainConvertsVia<polkadot_parachain::primitives::Sibling, AccountId>,
82    // Straight up local `AccountId32` origins just alias directly to `AccountId`.
83    AccountId32Aliases<RelayNetwork, AccountId>,
84    // Generates private `AccountId`s from `Location`s, in a stable & safe way.
85    // Replaces the old `Account32Hash` approach.
86    HashedDescription<AccountId, DescribeFamily<DescribeAllTerminal>>,
87);
88
89/// Means for transacting the native currency on this chain.
90pub type CurrencyTransactor = FungibleAdapter<
91    // Use this currency:
92    Balances,
93    // Use this currency when it is a fungible asset matching the given location or name:
94    IsConcrete<ShidenLocation>,
95    // Convert an XCM Location into a local account id:
96    LocationToAccountId,
97    // Our chain's account ID type (we can't get away without mentioning it explicitly):
98    AccountId,
99    // We don't track any teleports of `Balances`.
100    (),
101>;
102
103/// Means for transacting assets besides the native currency on this chain.
104pub type FungiblesTransactor = FungiblesAdapter<
105    // Use this fungibles implementation:
106    Assets,
107    // Use this currency when it is a fungible asset matching the given location or name:
108    ConvertedConcreteId<AssetId, Balance, ShidenAssetLocationIdConverter, JustTry>,
109    // Convert an XCM Location into a local account id:
110    LocationToAccountId,
111    // Our chain's account ID type (we can't get away without mentioning it explicitly):
112    AccountId,
113    // We don't support teleport so no need to check any assets.
114    NoChecking,
115    // We don't track any teleports of `Assets`.
116    DummyCheckingAccount,
117>;
118
119/// Means for transacting assets on this chain.
120pub type AssetTransactors = (CurrencyTransactor, FungiblesTransactor);
121
122/// This is the type we use to convert an (incoming) XCM origin into a local `Origin` instance,
123/// ready for dispatching a transaction with Xcm's `Transact`. There is an `OriginKind` which can
124/// biases the kind of local `Origin` it will become.
125pub type XcmOriginToTransactDispatchOrigin = (
126    // Sovereign account converter; this attempts to derive an `AccountId` from the origin location
127    // using `LocationToAccountId` and then turn that into the usual `Signed` origin. Useful for
128    // foreign chains who want to have a local sovereign account on this chain which they control.
129    SovereignSignedViaLocation<LocationToAccountId, RuntimeOrigin>,
130    // Native converter for Relay-chain (Parent) location; will convert to a `Relay` origin when
131    // recognised.
132    RelayChainAsNative<RelayChainOrigin, RuntimeOrigin>,
133    // Native converter for sibling Parachains; will convert to a `SiblingPara` origin when
134    // recognised.
135    SiblingParachainAsNative<cumulus_pallet_xcm::Origin, RuntimeOrigin>,
136    // Superuser converter for the Relay-chain (Parent) location. This will allow it to issue a
137    // transaction from the Root origin.
138    ParentAsSuperuser<RuntimeOrigin>,
139    // Xcm origins can be represented natively under the Xcm pallet's Xcm origin.
140    pallet_xcm::XcmPassthrough<RuntimeOrigin>,
141    // Native signed account converter; this just converts an `AccountId32` origin into a normal
142    // `Origin::Signed` origin of the same 32-byte value.
143    SignedAccountId32AsNative<RelayNetwork, RuntimeOrigin>,
144);
145
146parameter_types! {
147    // One XCM operation is 1_000_000_000 weight - almost certainly a conservative estimate.
148    // For the PoV size, we estimate 4 kB per instruction. This will be changed when we benchmark the instructions.
149    pub UnitWeightCost: Weight = Weight::from_parts(1_000_000_000, 4 * 1024);
150    pub const MaxInstructions: u32 = 100;
151}
152
153pub struct ParentOrParentsPlurality;
154impl Contains<Location> for ParentOrParentsPlurality {
155    fn contains(location: &Location) -> bool {
156        matches!(location.unpack(), (1, []) | (1, [Plurality { .. }]))
157    }
158}
159
160/// A call filter for the XCM Transact instruction. This is a temporary measure until we properly
161/// account for proof size weights.
162pub struct SafeCallFilter;
163impl SafeCallFilter {
164    // 1. RuntimeCall::EVM(..) & RuntimeCall::Ethereum(..) have to be prohibited since we cannot measure PoV size properly
165
166    /// Checks whether the base (non-composite) call is allowed to be executed via `Transact` XCM instruction.
167    pub fn allow_base_call(call: &RuntimeCall) -> bool {
168        match call {
169            RuntimeCall::System(..)
170            | RuntimeCall::Contracts(..)
171            | RuntimeCall::Identity(..)
172            | RuntimeCall::Balances(..)
173            | RuntimeCall::Vesting(..)
174            | RuntimeCall::DappStaking(..)
175            | RuntimeCall::Assets(..)
176            | RuntimeCall::PolkadotXcm(..)
177            | RuntimeCall::Session(..)
178            | RuntimeCall::Proxy(
179                pallet_proxy::Call::add_proxy { .. }
180                | pallet_proxy::Call::remove_proxy { .. }
181                | pallet_proxy::Call::remove_proxies { .. }
182                | pallet_proxy::Call::create_pure { .. }
183                | pallet_proxy::Call::kill_pure { .. }
184                | pallet_proxy::Call::announce { .. }
185                | pallet_proxy::Call::remove_announcement { .. }
186                | pallet_proxy::Call::reject_announcement { .. },
187            )
188            | RuntimeCall::Multisig(
189                pallet_multisig::Call::approve_as_multi { .. }
190                | pallet_multisig::Call::cancel_as_multi { .. },
191            ) => true,
192            _ => false,
193        }
194    }
195    /// Checks whether composite call is allowed to be executed via `Transact` XCM instruction.
196    ///
197    /// Each composite call's subcalls are checked against base call filter. No nesting of composite calls is allowed.
198    pub fn allow_composite_call(call: &RuntimeCall) -> bool {
199        match call {
200            RuntimeCall::Proxy(pallet_proxy::Call::proxy { call, .. }) => {
201                Self::allow_base_call(call)
202            }
203            RuntimeCall::Proxy(pallet_proxy::Call::proxy_announced { call, .. }) => {
204                Self::allow_base_call(call)
205            }
206            RuntimeCall::Utility(pallet_utility::Call::batch { calls, .. }) => {
207                calls.iter().all(|call| Self::allow_base_call(call))
208            }
209            RuntimeCall::Utility(pallet_utility::Call::batch_all { calls, .. }) => {
210                calls.iter().all(|call| Self::allow_base_call(call))
211            }
212            RuntimeCall::Utility(pallet_utility::Call::as_derivative { call, .. }) => {
213                Self::allow_base_call(call)
214            }
215            RuntimeCall::Multisig(pallet_multisig::Call::as_multi_threshold_1 { call, .. }) => {
216                Self::allow_base_call(call)
217            }
218            RuntimeCall::Multisig(pallet_multisig::Call::as_multi { call, .. }) => {
219                Self::allow_base_call(call)
220            }
221            _ => false,
222        }
223    }
224}
225
226impl Contains<RuntimeCall> for SafeCallFilter {
227    fn contains(call: &RuntimeCall) -> bool {
228        Self::allow_base_call(call) || Self::allow_composite_call(call)
229    }
230}
231
232pub type XcmBarrier = TrailingSetTopicAsId<(
233    TakeWeightCredit,
234    // Expected responses are OK.
235    AllowKnownQueryResponses<PolkadotXcm>,
236    // Allow XCMs with some computed origins to pass through.
237    WithComputedOrigin<
238        (
239            // If the message is one that immediately attempts to pay for execution, then allow it.
240            AllowTopLevelPaidExecutionFrom<Everything>,
241            // Subscriptions for version tracking are OK.
242            AllowSubscriptionsFrom<ParentRelayOrSiblingParachains>,
243        ),
244        UniversalLocation,
245        ConstU32<8>,
246    >,
247    // Parent and its plurality get free execution
248    AllowUnpaidExecutionFrom<ParentOrParentsPlurality>,
249)>;
250
251// Used to handle XCM fee deposit into treasury account
252pub type ShidenXcmFungibleFeeHandler = XcmFungibleFeeHandler<
253    AccountId,
254    ConvertedConcreteId<AssetId, Balance, ShidenAssetLocationIdConverter, JustTry>,
255    Assets,
256    TreasuryAccountId,
257>;
258
259pub struct XcmConfig;
260impl xcm_executor::Config for XcmConfig {
261    type RuntimeCall = RuntimeCall;
262    type XcmSender = XcmRouter;
263    type AssetTransactor = AssetTransactors;
264    type OriginConverter = XcmOriginToTransactDispatchOrigin;
265    type IsReserve = ReserveAssetFilter;
266    type IsTeleporter = ();
267    type UniversalLocation = UniversalLocation;
268    type Barrier = XcmBarrier;
269    type Weigher = Weigher;
270    type Trader = (
271        UsingComponents<XcmWeightToFee, ShidenLocation, AccountId, Balances, DealWithFees>,
272        FixedRateOfForeignAsset<XcAssetConfig, ShidenXcmFungibleFeeHandler>,
273    );
274    type ResponseHandler = PolkadotXcm;
275    type AssetTrap = PolkadotXcm;
276    type AssetClaims = PolkadotXcm;
277    type SubscriptionService = PolkadotXcm;
278
279    type PalletInstancesInfo = AllPalletsWithSystem;
280    type MaxAssetsIntoHolding = ConstU32<64>;
281    type AssetLocker = ();
282    type AssetExchanger = ();
283    type FeeManager = ();
284    type MessageExporter = ();
285    type UniversalAliases = Nothing;
286    type CallDispatcher = WithOriginFilter<SafeCallFilter>;
287    type SafeCallFilter = SafeCallFilter;
288    type Aliasers = Nothing;
289    type TransactionalProcessor = FrameTransactionalProcessor;
290
291    type HrmpNewChannelOpenRequestHandler = ();
292    type HrmpChannelAcceptedHandler = ();
293    type HrmpChannelClosingHandler = ();
294    type XcmRecorder = PolkadotXcm;
295    type XcmEventEmitter = PolkadotXcm;
296}
297
298/// Local origins on this chain are allowed to dispatch XCM sends/executions.
299pub type LocalOriginToLocation = SignedToAccountId32<RuntimeOrigin, AccountId, RelayNetwork>;
300
301/// The means for routing XCM messages which are not for local execution into the right message
302/// queues.
303pub type XcmRouter = (
304    // Two routers - use UMP to communicate with the relay chain:
305    cumulus_primitives_utility::ParentAsUmp<ParachainSystem, PolkadotXcm, ()>,
306    // ..and XCMP to communicate with the sibling chains.
307    XcmpQueue,
308);
309
310pub type Weigher =
311    WeightInfoBounds<weights::xcm::XcmWeight<Runtime, RuntimeCall>, RuntimeCall, MaxInstructions>;
312
313impl pallet_xcm::Config for Runtime {
314    const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100;
315
316    type RuntimeEvent = RuntimeEvent;
317    type SendXcmOrigin = EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>;
318    type XcmRouter = XcmRouter;
319    type ExecuteXcmOrigin = EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>;
320    type XcmExecuteFilter = Nothing;
321    type XcmExecutor = XcmExecutor<XcmConfig>;
322    type XcmTeleportFilter = Nothing;
323    type XcmReserveTransferFilter = Everything;
324    type Weigher = Weigher;
325    type UniversalLocation = UniversalLocation;
326    type RuntimeOrigin = RuntimeOrigin;
327    type RuntimeCall = RuntimeCall;
328    type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion;
329
330    type Currency = Balances;
331    type CurrencyMatcher = ();
332    type TrustedLockers = ();
333    type SovereignAccountOf = LocationToAccountId;
334    type MaxLockers = ConstU32<0>;
335    type WeightInfo = weights::pallet_xcm::SubstrateWeight<Runtime>;
336    type MaxRemoteLockConsumers = ConstU32<0>;
337    type RemoteLockConsumerIdentifier = ();
338    type AdminOrigin = EnsureRoot<AccountId>;
339    type AuthorizedAliasConsideration = Disabled;
340}
341
342impl cumulus_pallet_xcm::Config for Runtime {
343    type RuntimeEvent = RuntimeEvent;
344    type XcmExecutor = XcmExecutor<XcmConfig>;
345}
346
347impl cumulus_pallet_xcmp_queue::Config for Runtime {
348    type RuntimeEvent = RuntimeEvent;
349    type ChannelInfo = ParachainSystem;
350    type VersionWrapper = PolkadotXcm;
351    type XcmpQueue = TransformOrigin<MessageQueue, AggregateMessageOrigin, ParaId, ParaIdToSibling>;
352    type MaxInboundSuspended = ConstU32<1_000>;
353    type MaxActiveOutboundChannels = ConstU32<128>;
354    type MaxPageSize = ConstU32<{ 128 * 1024 }>;
355    type ControllerOrigin = EnsureRoot<AccountId>;
356    type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin;
357    type PriceForSiblingDelivery = NoPriceForMessageDelivery<ParaId>;
358    type WeightInfo = cumulus_pallet_xcmp_queue::weights::SubstrateWeight<Runtime>;
359}
360
361parameter_types! {
362    /// The absolute location in perspective of the whole network.
363    pub ShidenLocationAbsolute: Location = Location {
364        parents: 1,
365        interior: Parachain(ParachainInfo::parachain_id().into()).into()
366
367    };
368    /// Max asset types for one cross-chain transfer. `2` covers all current use cases.
369    /// Can be updated with extra test cases in the future if needed.
370    pub const MaxAssetsForTransfer: usize = 2;
371}
372
373/// Convert `AssetId` to optional `Location`. The impl is a wrapper
374/// on `ShidenAssetLocationIdConverter`.
375pub struct AssetIdConvert;
376impl Convert<AssetId, Option<Location>> for AssetIdConvert {
377    fn convert(asset_id: AssetId) -> Option<Location> {
378        ShidenAssetLocationIdConverter::convert_back(&asset_id)
379    }
380}
381
382impl orml_xtokens::Config for Runtime {
383    type Balance = Balance;
384    type CurrencyId = AssetId;
385    type CurrencyIdConvert = AssetIdConvert;
386    type AccountIdToLocation = AccountIdToMultiLocation;
387    type SelfLocation = ShidenLocation;
388    type XcmExecutor = XcmExecutor<XcmConfig>;
389    type Weigher = Weigher;
390    type BaseXcmWeight = UnitWeightCost;
391    type UniversalLocation = UniversalLocation;
392    type MaxAssetsForTransfer = MaxAssetsForTransfer;
393    // Default impl. Refer to `orml-xtokens` docs for more details.
394    type MinXcmFee = DisabledParachainFee;
395    type LocationsFilter = Everything;
396    type ReserveProvider = AbsoluteAndRelativeReserveProvider<ShidenLocationAbsolute>;
397    type RateLimiter = ();
398    type RateLimiterId = ();
399}