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