Skip to content

XCM Precompile

Introduction

The XCM (Cross-Consensus Message) precompile enables Polkadot Hub developers to access XCM functionality directly from their smart contracts, sending cross-chain messages, executing XCM instructions locally, and estimating execution costs—all through a standardized Solidity interface.

Located at the fixed address 0x00000000000000000000000000000000000a0000, the XCM precompile offers three primary functions:

  • execute: for local XCM execution
  • send: for cross-chain message transmission
  • weighMessage: for cost estimation

This guide demonstrates how to interact with the XCM precompile through Solidity smart contracts using Remix IDE.

Precompile Interface

The XCM precompile implements the IXcm interface, which defines the structure for interacting with XCM functionality. The source code for the interface is as follows:

IXcm.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

/// @dev The on-chain address of the XCM (Cross-Consensus Messaging) precompile.
address constant XCM_PRECOMPILE_ADDRESS = address(0xA0000);

/// @title XCM Precompile Interface
/// @notice A low-level interface for interacting with `pallet_xcm`.
/// It forwards calls directly to the corresponding dispatchable functions,
/// providing access to XCM execution and message passing.
/// @dev Documentation:
/// @dev - XCM: https://docs.polkadot.com/develop/interoperability
/// @dev - SCALE codec: https://docs.polkadot.com/polkadot-protocol/parachain-basics/data-encoding
/// @dev - Weights: https://docs.polkadot.com/polkadot-protocol/parachain-basics/blocks-transactions-fees/fees/#transactions-weights-and-fees
interface IXcm {
    /// @notice Weight v2 used for measurement for an XCM execution
    struct Weight {
        /// @custom:property The computational time used to execute some logic based on reference hardware.
        uint64 refTime;
        /// @custom:property The size of the proof needed to execute some logic.
        uint64 proofSize;
    }

    /// @notice Executes an XCM message locally on the current chain with the caller's origin.
    /// @dev Internally calls `pallet_xcm::execute`.
    /// @param message A SCALE-encoded Versioned XCM message.
    /// @param weight The maximum allowed `Weight` for execution.
    /// @dev Call @custom:function weighMessage(message) to ensure sufficient weight allocation.
    function execute(bytes calldata message, Weight calldata weight) external;

    /// @notice Sends an XCM message to another parachain or consensus system.
    /// @dev Internally calls `pallet_xcm::send`.
    /// @param destination SCALE-encoded destination MultiLocation.
    /// @param message SCALE-encoded Versioned XCM message.
    function send(bytes calldata destination, bytes calldata message) external;

    /// @notice Estimates the `Weight` required to execute a given XCM message.
    /// @param message SCALE-encoded Versioned XCM message to analyze.
    /// @return weight Struct containing estimated `refTime` and `proofSize`.
    function weighMessage(bytes calldata message) external view returns (Weight memory weight);
}

The interface defines a Weight struct that represents the computational cost of XCM operations. Weight has two components:

  • refTime: computational time on reference hardware
  • proofSize: the size of the proof required for execution

All XCM messages must be encoded using the SCALE codec, Polkadot's standard serialization format.

For further information, check the precompiles/IXCM.sol file present in the pallet-xcm.

Interact with the XCM Precompile

To interact with the XCM precompile, you can use the precompile interface directly in Remix IDE:

  1. Create a new file called IXcm.sol in Remix.
  2. Copy and paste the IXcm interface code into the file.
  3. Compile the interface by selecting the button or using Ctrl +S keys:

  4. In the Deploy & Run Transactions tab, select the IXcm interface from the contract dropdown.

  5. Enter the precompile address 0x00000000000000000000000000000000000a0000 in the At Address input field.
  6. Select the At Address button to connect to the precompile.

  7. Once connected, you can use the Remix interface to interact with the XCM precompile's execute, send, and weighMessage functions.

Weigh a Message

The weighMessage function estimates the computational cost required to execute an XCM message. This estimate is crucial for understanding the resources needed before actually executing or sending a message.

To test this functionality in Remix, you can call callWeighMessage with a SCALE-encoded XCM message. For example, for testing, you can use the following encoded XCM message:

encoded-xcm-message-example
0x050c000401000003008c86471301000003008c8647000d010101000000010100368e8759910dab756d344995f1d3c79374ca8f70066d3a709e48029f6bf0ee7e

This encoded message represents a sequence of XCM instructions:

  • Withdraw Asset: This instruction removes assets from the local chain's sovereign account or the caller's account, making them available for use in subsequent XCM instructions.
  • Buy Execution: This instruction purchases execution time on the destination chain using the withdrawn assets, ensuring the message can be processed.
  • Deposit Asset: This instruction deposits the remaining assets into a specified account on the destination chain after execution costs have been deducted.

This encoded message is provided as an example. You can craft your own XCM message tailored to your specific use case as needed.

The function returns a Weight struct containing refTime and proofSize values, which indicate the estimated computational cost of executing this message. If successful, after calling the callWeighMessage function, you should see the refTime and proofSize of the message:

Note

To interact with Polkadot Hub TestNet, visit this gist, which provides examples of how to craft XCM messages for different purposes.

Execute a Message

The execute function runs an XCM message locally using the caller's origin. This function helps execute XCM instructions that don't require cross-chain communication.

Follow these steps to execute a message:

  1. Call callWeighMessage with your XCM message to get the required weight.
  2. Use the returned weight values when calling callXcmExecute.
  3. Pass the same XCM message bytes and the weight obtained from the previous step. For example, using the same message from the weighing example, you would call callXcmExecute with:

    • message: The encoded XCM message bytes.
    • weight: The Weight struct returned from callWeighMessage.

    You can use the papi console to examine the complete extrinsic structure for this operation.

  4. Click on the Transact button to execute the xcm message:

    If successful, you will see the following output in the Remix terminal:

Additionally, you can verify that the execution of this specific message was successful by checking that the beneficiary account associated with the XCM message has received the funds accordingly.

Send a Message

The send function is responsible for transmitting an XCM message to a destination chain, enabling essential cross-chain communication.

To send a message:

  1. Prepare your destination location encoded in XCM format.
  2. Prepare your XCM message (similar to the execute example).
  3. Call callXcmSend with both parameters.

The destination parameter must be encoded according to XCM's location format, specifying the target parachain or consensus system. The message parameter contains the XCM instructions to be executed on the destination chain.

Unlike execute, the send function doesn't require a weight parameter since the destination chain will handle execution costs according to its fee structure.

Cross Contract Calls

Beyond direct interaction and wrapper contracts, you can integrate XCM functionality directly into your existing smart contracts by inheriting from or importing the IXcm interface. This approach enables you to embed cross-chain capabilities into your application logic seamlessly.

Whether you're building DeFi protocols, governance systems, or any application requiring cross-chain coordination, you can incorporate XCM calls directly within your contract's functions.

Conclusion

The XCM precompile provides a powerful interface for cross-chain interactions within the Polkadot ecosystem. By understanding how to properly encode messages, estimate weights, and execute or send XCM instructions, developers can build sophisticated cross-chain applications that leverage the full potential of Polkadot's interoperability features.

Last update: July 15, 2025
| Created: July 15, 2025