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