Skip to content

XCM Config

Introduction

The XCM executor is a crucial component responsible for interpreting and executing XCM messages (XCMs) with Polkadot SDK-based chains. It processes and manages XCM instructions, ensuring they are executed correctly and in sequentially. Adhering to the Cross-Consensus Virtual Machine (XCVM) specification, the XCM executor can be customized or replaced with an alternative that also complies with the XCVM standards.

The XcmExecutor is not a pallet but a struct parameterized by a Config trait. The Config trait is the inner configuration, parameterizing the outer XcmExecutor<Config> struct. Both configurations are set up within the runtime.

The executor is highly configurable, with the XCM builder offering building blocks to tailor the configuration to specific needs. While they serve as a foundation, users can easily create custom blocks to suit unique configurations. Users can also create their building blocks to address unique needs. This article examines the XCM configuration process, explains each configurable item, and provides examples of the tools and types available to help customize these settings.

XCM Executor Configuration

The Config trait defines the XCM executor’s configuration, which requires several associated types. Each type has specific trait bounds that the concrete implementation must fulfill. Some types, such as RuntimeCall, come with a default implementation in most cases, while others use the unit type () as the default. For many of these types, selecting the appropriate implementation carefully is crucial. Predefined solutions and building blocks can be adapted to your specific needs. These solutions can be found in the xcm-builder folder.

Each type is explained below, along with an overview of some of its implementations:

pub trait Config {
    type RuntimeCall: Parameter + Dispatchable<PostInfo = PostDispatchInfo> + GetDispatchInfo;
    type XcmSender: SendXcm;
    type AssetTransactor: TransactAsset;
    type OriginConverter: ConvertOrigin<<Self::RuntimeCall as Dispatchable>::RuntimeOrigin>;
    type IsReserve: ContainsPair<MultiAsset, MultiLocation>;
    type IsTeleporter: ContainsPair<MultiAsset, MultiLocation>;
    type Aliasers: ContainsPair<Location, Location>;
    type UniversalLocation: Get<InteriorMultiLocation>;
    type Barrier: ShouldExecute;
    type Weigher: WeightBounds<Self::RuntimeCall>;
    type Trader: WeightTrader;
    type ResponseHandler: OnResponse;
    type AssetTrap: DropAssets;
    type AssetClaims: ClaimAssets;
    type AssetLocker: AssetLock;
    type AssetExchanger: AssetExchange;
    type SubscriptionService: VersionChangeNotifier;
    type PalletInstancesInfo: PalletsInfoAccess;
    type MaxAssetsIntoHolding: Get<u32>;
    type FeeManager: FeeManager;
    type MessageExporter: ExportXcm;
    type UniversalAliases: Contains<(MultiLocation, Junction)>;
    type CallDispatcher: CallDispatcher<Self::RuntimeCall>;
    type SafeCallFilter: Contains<Self::RuntimeCall>;
    type TransactionalProcessor: ProcessTransaction;
    type HrmpNewChannelOpenRequestHandler: HandleHrmpNewChannelOpenRequest;
    type HrmpChannelAcceptedHandler: HandleHrmpChannelAccepted;
    type HrmpChannelClosingHandler: HandleHrmpChannelClosing;
    type XcmRecorder: RecordXcm;
}

Config Items

Each configuration item is explained below, detailing the associated type’s purpose and role in the XCM executor. Many of these types have predefined solutions available in the xcm-builder. Therefore, the available configuration items are:

  • RuntimeCall - defines the runtime's callable functions, created via the frame::runtime macro. It represents an enum listing the callable functions of all implemented pallets

    type RuntimeCall: Parameter + Dispatchable<PostInfo = PostDispatchInfo> + GetDispatchInfo
    
    The associated traits signify:

    • Parameter - ensures the type is encodable, decodable, and usable as a parameter
    • Dispatchable - indicates it can be executed in the runtime
    • GetDispatchInfo - provides weight details, determining how long execution takes
  • XcmSender - implements the SendXcm trait, specifying how the executor sends XCMs using transport layers (e.g., UMP for relay chains or XCMP for sibling chains). If a runtime lacks certain transport layers, such as HRMP (or XCMP)

    type XcmSender: SendXcm;
    

  • AssetTransactor - implements the TransactAsset trait, handling the conversion and transfer of MultiAssets between accounts or registers. It can be configured to support native tokens, fungibles, and non-fungibles or multiple tokens using pre-defined adapters like FungibleAdapter or custom solutions

    type AssetTransactor: TransactAsset;
    

  • OriginConverter - implements the ConvertOrigin trait to map MultiLocation origins to RuntimeOrigin. Multiple implementations can be combined, and OriginKind is used to resolve conflicts. Pre-defined converters like SovereignSignedViaLocation and SignedAccountId32AsNative handle sovereign and local accounts respectively

    type OriginConverter: ConvertOrigin<<Self::RuntimeCall as Dispatchable>::RuntimeOrigin>;
    

  • IsReserve - specifies trusted <MultiAsset, MultiLocation> pairs for depositing reserve assets. Using the unit type () blocks reserve deposits. The NativeAsset struct is an example of a reserve implementation

    type IsReserve: ContainsPair<MultiAsset, MultiLocation>;
    

  • IsTeleporter - defines trusted <MultiAsset, MultiLocation> pairs for teleporting assets to the chain. Using () blocks the ReceiveTeleportedAssets instruction. The NativeAsset struct can act as an implementation

    type IsTeleporter: ContainsPair<MultiAsset, MultiLocation>;
    

  • Aliasers - a list of (Origin, Target) pairs enabling each Origin to be replaced with its corresponding Target

    type Aliasers: ContainsPair<Location, Location>;
    

  • UniversalLocation - specifies the runtime's location in the consensus universe

    type UniversalLocation: Get<InteriorMultiLocation>;
    

    • Some examples are:
      • X1(GlobalConsensus(NetworkId::Polkadot)) for Polkadot
      • X1(GlobalConsensus(NetworkId::Kusama)) for Kusama
      • X2(GlobalConsensus(NetworkId::Polkadot), Parachain(1000)) for Statemint
  • Barrier - implements the ShouldExecute trait, functioning as a firewall for XCM execution. Multiple barriers can be combined in a tuple, where execution halts if one succeeds

    type Barrier: ShouldExecute;
    

  • Weigher - calculates the weight of XCMs and instructions, enforcing limits and refunding unused weight. Common solutions include FixedWeightBounds, which uses a base weight and limits on instructions

    type Weigher: WeightBounds<Self::RuntimeCall>;
    

  • Trader - manages asset-based weight purchases and refunds for BuyExecution instructions. The UsingComponents trader is a common implementation

    type Trader: WeightTrader;
    

  • ResponseHandler - handles QueryResponse instructions, implementing the OnResponse trait. FRAME systems typically use the pallet-xcm implementation

    type ResponseHandler: OnResponse;
    

  • AssetTrap - handles leftover assets in the holding register after XCM execution, allowing them to be claimed via ClaimAsset. If unsupported, assets are burned

    type AssetTrap: DropAssets;
    

  • AssetClaims - facilitates the claiming of trapped assets during the execution of the ClaimAsset instruction. Commonly implemented via pallet-xcm

    type AssetClaims: ClaimAssets;
    

  • AssetLocker - handles the locking and unlocking of assets. Can be omitted using () if asset locking is unnecessary

    type AssetLocker: AssetLock;
    

  • AssetExchanger - implements the AssetExchange trait to manage asset exchanges during the ExchangeAsset instruction. The unit type () disables this functionality

    type AssetExchanger: AssetExchange;
    

  • SubscriptionService - manages (Un)SubscribeVersion instructions and returns the XCM version via QueryResponse. Typically implemented by pallet-xcm

    type SubscriptionService: VersionChangeNotifier;
    

  • PalletInstancesInfo - provides runtime pallet information for QueryPallet and ExpectPallet instructions. FRAME-specific systems often use this, or it can be disabled with ()

    type PalletInstancesInfo: PalletsInfoAccess;
    

  • MaxAssetsIntoHolding - limits the number of assets in the Holding register. At most, twice this limit can be held under worst-case conditions

    type MaxAssetsIntoHolding: Get<u32>;
    

  • FeeManager - manages fees for XCM instructions, determining whether fees should be paid, waived, or handled in specific ways. Fees can be waived entirely using ()

    type FeeManager: FeeManager;
    

  • MessageExporter - implements the ExportXcm trait, enabling XCMs export to other consensus systems. It can spoof origins for use in bridges. Use () to disable exporting

    type MessageExporter: ExportXcm;
    

  • UniversalAliases - lists origin locations and universal junctions allowed to elevate themselves in the UniversalOrigin instruction. Using Nothing prevents origin aliasing

    type UniversalAliases: Contains<(MultiLocation, Junction)>;
    

  • CallDispatcher - dispatches calls from the Transact instruction, adapting the origin or modifying the call as needed. Can default to RuntimeCall

    type CallDispatcher: CallDispatcher<Self::RuntimeCall>;
    

  • SafeCallFilter - whitelists calls permitted in the Transact instruction. Using Everything allows all calls, though this is temporary until proof size weights are accounted for

    type SafeCallFilter: Contains<Self::RuntimeCall>;
    

  • TransactionalProcessor - implements the ProccessTransaction trait. It ensures that XCM instructions are executed atomically, meaning they either fully succeed or fully fail without any partial effects. This type allows for non-transactional XCM instruction processing by setting the () type

    type TransactionalProcessor: ProcessTransaction;
    

  • HrmpNewChannelOpenRequestHandler - enables optional logic execution in response to the HrmpNewChannelOpenRequest XCM notification

    type HrmpNewChannelOpenRequestHandler: HandleHrmpNewChannelOpenRequest;
    

  • HrmpChannelAcceptedHandler - enables optional logic execution in response to the HrmpChannelAccepted XCM notification

    type HrmpChannelAcceptedHandler: HandleHrmpChannelAccepted;
    

  • HrmpChannelClosingHandler - enables optional logic execution in response to the HrmpChannelClosing XCM notification
    type HrmpChannelClosingHandler: HandleHrmpChannelClosing;
    
  • XcmRecorder - allows tracking of the most recently executed XCM, primarily for use with dry-run runtime APIs
    type XcmRecorder: RecordXcm;
    

Inner Config

The Config trait underpins the XcmExecutor, defining its core behavior through associated types for asset handling, XCM processing, and permission management. These types are categorized as follows:

  • Handlers - manage XCMs sending, asset transactions, and special notifications
  • Filters - define trusted combinations, origin substitutions, and execution barriers
  • Converters - handle origin conversion for call execution
  • Accessors - provide weight determination and pallet information
  • Constants - specify universal locations and asset limits
  • Common Configs - include shared settings like RuntimeCall

The following diagram outlines this categorization:

flowchart LR
    A[Inner Config] --> B[Handlers]
    A --> C[Filters]
    A --> D[Converters]
    A --> E[Accessors]
    A --> F[Constants]
    A --> G[Common Configs]

    B --> H[XcmSender]
    B --> I[AssetTransactor]
    B --> J[Trader]
    B --> K[ResponseHandler]
    B --> L[AssetTrap]
    B --> M[AssetLocker]
    B --> N[AssetExchanger]
    B --> O[AssetClaims]
    B --> P[SubscriptionService]
    B --> Q[FeeManager]
    B --> R[MessageExporter]
    B --> S[CallDispatcher]
    B --> T[HrmpNewChannelOpenRequestHandler]
    B --> U[HrmpChannelAcceptedHandler]
    B --> V[HrmpChannelClosingHandler]

    C --> W[IsReserve]
    C --> X[IsTeleporter]
    C --> Y[Aliasers]
    C --> Z[Barrier]
    C --> AA[UniversalAliases]
    C --> AB[SafeCallFilter]

    D --> AC[OriginConverter]

    E --> AD[Weigher]
    E --> AE[PalletInstancesInfo]

    F --> AF[UniversalLocation]
    F --> AG[MaxAssetsIntoHolding]

    G --> AH[RuntimeCall]

Outer Config

The XcmExecutor<Config> struct extends the functionality of the inner config by introducing fields for execution context, asset handling, error tracking, and operational management. For further details, see the documentation for XcmExecutor<Config>.

Multiple Implementations

Some associated types in the Config trait are highly configurable and may have multiple implementations (e.g., Barrier). These implementations are organized into a tuple (impl_1, impl_2, ..., impl_n), and the execution follows a sequential order. Each item in the tuple is evaluated individually, each being checked to see if it fails. If an item passes (e.g., returns Ok or true), the execution stops, and the remaining items are not evaluated. The following example of the Barrier type demonstrates how this grouping operates (understanding each item in the tuple is unnecessary for this explanation).

In the following example, the system will first check the TakeWeightCredit type when evaluating the barrier. If it fails, it will check AllowTopLevelPaidExecutionFrom, and so on, until one of them returns a positive result. If all checks fail, a Barrier error will be triggered.

pub type Barrier = (
    TakeWeightCredit,
    AllowTopLevelPaidExecutionFrom<Everything>,
    AllowKnownQueryResponses<XcmPallet>,
    AllowSubscriptionsFrom<Everything>,
);

pub struct XcmConfig;
impl xcm_executor::Config for XcmConfig {
    ...
    type Barrier = Barrier;
    ...
}
Last update: November 23, 2024
| Created: October 18, 2024