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