Skip to content

XCM Fees on Moonbeam

XCM Fees Banner

Introduction

XCM aims to be a language that communicates ideas between consensus systems. Sending an XCM message consists of a series of instructions that are executed in both the origin and the destination chain. The combination of XCM instructions result in actions such as token transfers. In order to process and execute each XCM instruction, there are typically associated fees that must be paid.

However, XCM is designed to be general, extensible, and efficient so that it remains useful and future-proof throughout a growing ecosystem. As such, the generality applies to concepts including payments of fees for XCM execution. In Ethereum, fees are baked into the transaction protocol, whereas in the Polkadot ecosystem, each chain has the flexibility to define how XCM fees are handled.

This guide will cover aspects of fee payment such as who is responsible to pay XCM execution fees, how it is paid for, and how the fees are calculated on Moonbeam.

Payment of Fees

Generally speaking, the fee payment process can be described as follows:

  1. Some assets need to be provided
  2. The exchange of assets for compute time (or weight) must be negotiated
  3. The XCM operations will be performed as instructed, with the provided weight limit or funds available for execution

Each chain can configure what happens with the XCM fees, and in which tokens they can be paid (either the native reserve token, or an external one). For example, on Polkadot and Kusama the fees are paid in DOT or KSM (respectively) and given to the validator of the block. On Moonbeam and Moonriver, the XCM execution fees can be paid in the reserve asset (GLMR or MOVR respectively), but also, in assets originated in other chains, and fees are sent to the treasury.

Consider the following scenario: Alice has some DOT on Polkadot and she wants to transfer it to Alith on Moonbeam. She sends an XCM message with a set of XCM instructions that will retrieve a given amount of DOT from her account on Polkadot and mint them as xcDOT into Alith's account. Part of the instructions are executed on Polkadot and the other part are executed on Moonbeam.

How does Alice pay Moonbeam to execute these instructions and fulfill her request? Her request is fulfilled through a series of XCM instructions that are included in the XCM message, which enables her to buy execution time minus any related XCM execution fees. The execution time is used to issue and transfer xcDOT, a representation of DOT on Moonbeam. This means that when Alice sends some DOT to Alith's account on Moonbeam, she'll receive a 1:1 representation of her DOT as xcDOT minus any XCM execution fees. Note that in this scenario, XCM execution fees are paid in xcDOT.

The exact process for Alice's transfer is as follows:

  1. Assets are sent to an account on Polkadot that is owned by Moonbeam, known as the sovereign account. After the assets are received, an XCM message is sent to Moonbeam
  2. The XCM message in Moonbeam will:
    1. Mint the corresponding asset representation
    2. Buy the corresponding execution time
    3. Use that execution time to deposit the representation (minus fees) to the destination account

XCM Instructions

An XCM message is comprised of a series of XCM instructions. As a result, different combinations of XCM instructions result in different actions. For example, to move DOT to Moonbeam, the following XCM instructions are used:

  1. TransferReserveAsset - gets executed in Polkadot. Moves assets from the origin account and deposits them into a destination account. In this case, the destination account is Moonbeam's sovereign account on Polkadot. It then sends an XCM message to the destination, which is Moonbeam, with the XCM instructions that are to be executed
  2. ReserveAssetDeposited - gets executed in Moonbeam. Takes a representation of the assets received in the sovereign account and places them into the holding register, a temporary position in the Cross-Consensus Virtual Machine (XCVM)
  3. ClearOrigin - gets executed in Moonbeam. Ensures that later XCM instructions cannot command the authority of the XCM author
  4. BuyExecution - gets executed in Moonbeam. Takes the assets from holding to pay for execution fees. The amount of fees to pay are determined by the target chain, which in this case is Moonbeam
  5. DepositAsset - gets executed in Moonbeam. Removes the assets from holding and sends them to a destination account on Moonbeam

To check how the instructions for an XCM message are built to transfer self reserve assets to a target chain, such as DOT to Moonbeam, you can refer to the X-Tokens Open Runtime Module Library repository (as an example). You'll want to take a look at the transfer_self_reserve_asset function. You'll notice that it calls TransferReserveAsset and passes in assets, dest, and xcm as parameters. In particular, the xcm parameter includes the BuyExecution and DepositAsset instructions. If you then head over to the Polkadot GitHub repository, you can find the TransferReserveAsset instruction. The XCM message is constructed by combining the ReserveAssetDeposited and ClearOrigin instructions with the xcm parameter, which as mentioned includes the BuyExecution and DepositAsset instructions.

To move xcDOT from Moonbeam back to Polkadot, the instructions that are used are:

  1. WithdrawAsset - gets executed in Moonbeam. Removes assets and places them into the holding register
  2. InitiateReserveWithdraw - gets executed in Moonbeam. Removes the assets from holding and sends an XCM message to the destination chain starting with the WithdrawAsset instruction
  3. WithdrawAsset - gets executed in Polkadot. Removes assets and places them into the holding register
  4. ClearOrigin - gets executed in Polkadot. Ensures that later XCM instructions cannot command the authority of the XCM author
  5. BuyExecution - gets executed in Polkadot. Takes the assets from holding to pay for execution fees. The amount of fees to pay are determined by the target chain, which in this case is Polkadot
  6. DepositAsset - gets executed in Polkadot. Removes the assets from holding and sends them to a destination account on Polkadot

To check how the instructions for an XCM message are built to transfer reserve assets to a target chain, such as xcDOT to Polkadot, you can refer to the X-Tokens Open Runtime Module Library repository. You'll want to take a look at the transfer_to_reserve function. You'll notice that it calls WithdrawAsset, then InitiateReserveWithdraw and passes in assets, dest, and xcm as parameters. In particular, the xcm parameter includes the BuyExecution and DepositAsset instructions. If you then head over to the Polkadot GitHub repository, you can find the InitiateReserveWithdraw instruction. The XCM message is constructed by combining the WithdrawAsset and ClearOrigin instructions with the xcm parameter, which as mentioned includes the BuyExecution and DepositAsset instructions.

Fee Calculation for Reserve Assets

Substrate has introduced a weight system that determines how heavy or, in other words, how expensive from a computational cost perspective an extrinsic is. When it comes to paying fees, users will pay a transaction fee based on the weight of the call that is being made, in addition to factors such as network congestion. One unit of weight is defined as one picosecond of execution time.

The following sections will break down how to calculate XCM fees for Polkadot, Kusama, and Moonbeam-based networks. It's important to note that Kusama in particular uses benchmarked data to determine the total weight costs for XCM instructions, and that some XCM instructions might include database reads/writes, which add weight to the call.

There are two databases available in Polkadot and Kusama, RocksDB (which is the default) and ParityDB, both of which have their own associated weight costs for each network.

Polkadot

As previously mentioned, Polkadot currently uses a fixed amount of weight for all XCM instructions, which is 1,000,000,000 weight units.

Although Polkadot doesn't currently use database weight units to calculate costs, the weight units for database operations, which have been benchmarked, are shared here for reference.

Database Read Write
RocksDB (default) 20,499,000 83,471,000
ParityDB 11,826,000 30,052,000

With the instruction weight cost established, you can calculate the cost of the instruction in DOT.

In Polkadot, the ExtrinsicBaseWeight is set to 85,212,000 which is mapped to 1/10th of a cent. Where 1 cent is 10^10 / 10,000. Therefore, a constant exists in the formula for calculating the final fee in DOT:

Planck-DOT-Weight =  PlanckDOT-Mapped * (1 / ExtrinsicBaseWeight)

Where the constant is calculated as follows:

Planck-DOT-Weight = (10^10 / 10000) * (1 / 85212000)

As a result, Planck-DOT-Weight is equal to 0.117354363 Planck-DOT. Now, you can begin to calculate the final fee in DOT, using Planck-DOT-Weight as a constant, and TotalWeight as the variable:

Total-Planck-DOT = TotalWeight * Planck-DOT-Weight
DOT = Total-Planck-DOT / DOTDecimalConversion

Therefore, the actual calculation for one XCM instruction is:

Total-Planck-DOT = 1000000000 * 0.117354363 
DOT = 117354360 / 10^10

The total cost is 0.0117354363 DOT.

As an example, you can calculate the total cost of DOT for sending an XCM message that transfers xcDOT to DOT on Polkadot using the following weights and instruction costs:

Instruction Weight Cost
WithdrawAsset 1,000,000,000 0.0117354363 DOT
ClearOrigin 1,000,000,000 0.0117354363 DOT
BuyExecution 1,000,000,000 0.0117354363 DOT
DepositAsset 1,000,000,000 0.0117354363 DOT
TOTAL 4,000,000,000 0.0469417452 DOT

Kusama

The total weight costs on Kusama take into consideration database reads and writes in addition to the weight required for a given instruction. Database read and write operations have not been benchmarked, while instruction weights have been. The breakdown of weight costs for the database operations are as follows:

Database Read Write
RocksDB (default) 25,000,000 100,000,000
ParityDB 8,000,000 50,000,000

Now that you are aware of the weight costs for database reads and writes on Kusama, you can calculate the weight cost for a given instruction using the base weight for an instruction.

The WithdrawAsset instruction has a base weight of 20,385,000, and includes one database read, and one database write. Therefore, the total weight cost of the WithdrawAsset instruction is calculated like so:

20,385,000 + 25,000,000 + 100,000,000 = 145,385,000

The BuyExecution instruction has a base weight of 3,109,000 and doesn't include any database reads or writes. Therefore, the total weight cost of the BuyExecution instruction is 3,109,000.

On Kusama, the benchmarked base weights are broken up into two categories: fungible and generic. Fungible weights are for XCM instructions that involve moving assets, and generic weights are for everything else. You can view the current weights for fungible assets and generic assets directly in the Kusama Runtime code.

With the instruction weight cost established, you can calculate the cost of the instruction in KSM.

In Kusama, the ExtrinsicBaseWeight is set to 86,309,000 which is mapped to 1/10th of a cent. Where 1 cent is 10^12 / 30,000. Therefore, a constant exists in the formula for calculating the final fee in DOT:

Planck-KSM-Weight =  PlanckKSM-Mapped * (1 / ExtrinsicBaseWeight)

Where Planck-KSM-Weight is calculated as follows:

Planck-KSM-Weight = (10^12 / 30000 * 10) * (1 / 86309000)

As a result, Planck-KSM-Weight is equal to 0.038620924044228684 Planck-KSM. Now, you can begin to calculate the final fee in KSM, using Planck-KSM-Weight as a constant, and TotalWeight as the variable:

Total-Planck-KSM = TotalWeight * Planck-KSM-Weight
KSM = Total-Planck-KSM / KSMDecimalConversion

Therefore, the actual calculation for the WithdrawAsset instruction is:

Total-Planck-KSM = 145,385,000 * 0.038620924044228684
KSM = 5614903.04216 / 10^12

The total cost is 0.00000561490304213694 KSM.

As an example, you can calculate the total cost of KSMs for sending an XCM message that transfers xcKSM to KSM on Kusama using the following weights and instruction costs:

Instruction Weight Cost
WithdrawAsset 145,385,000 0.00000561490304213694 KSM
ClearOrigin 3,111,000 0.000000120149695 KSM
BuyExecution 3,109,000 0.000000120072453 KSM
DepositAsset 146,763,000 0.000011523247866 KSM
TOTAL 298,368,000 0.000011523247866 KSM

Moonbeam-based Networks

Moonbeam uses a fixed amount of weight for each XCM instruction. Then the weight units are converted to balance units as part of the fee calculation. The amount of weight and Wei per weight for each of the Moonbeam-based networks is as follows:

Weight Wei per weight
200,000,000 5,000,000
Weight Wei per weight
200,000,000 50,000
Weight Wei per weight
100,000,000 50,000

This means that on Moonbeam, for example, the formula to calculate the cost of one XCM instruction is as follows:

Wei = Weight * Wei_Per_Weight
GLMR = Wei / (10^18)

Therefore, the actual calculation is:

Wei = 200000000 * 5,000,000
GLMR = 1000000000000000 / (10^18)

The total cost is 0.001 GLMR for an XCM instruction on Moonbeam.

Fee Calculation for External Assets

Considering the scenario with Alice sending DOT to Alith's account on Moonbeam, the fees are taken from the amount of xcDOT Alith receives. To determine how much to charge, Moonbeam uses a concept called UnitsPerSecond, which refers to the units of tokens that the network charges per second of XCM execution time (considering decimals). This concept is used by Moonbeam (and maybe other parachains) to determine how much to charge for XCM execution using a different asset than its reserve.

Moreover, XCM execution on Moonbeam can be paid by multiple assets that originate in the chain where the asset is coming from. For example, at the time of writing, an XCM message sent from Statemine can be paid in xcKSM, xcRMRK or xcUSDT. As long as that asset has an UnitsPerSecond set in Moonbeam/Moonriver, it can be used to pay XCM execution for an XCM message coming from that specific chain.

To find out the UnitsPerSecond for a given asset, you can query assetManager.assetTypeUnitsPerSecond and pass in the multilocation of the asset in question.

If you're unsure of the multilocation, you can retrieve it using the assetManager.assetIdType query.

For example, you can navigate to the Polkadot.js Apps page for Moonbeam and under the Developer dropdown, choose Chain State. From there you can take the following steps:

  1. For the selected state query dropdown, choose assetManager
  2. Select the assetIdType extrinsic
  3. Under Option enter in the asset ID or toggle the include option off to return information for all of the assets. This example will get information for xcUNITs which has an asset ID of 42259045809535163221576417993425387648
  4. Click the + button to submit the query

Get the xcUNIT asset multilocation

You can take the result of the query and then use it to query the assetTypeUnitsPerSecond extrinsic:

  1. Make sure assetManager is selected
  2. Select the assetTypeUnitsPerSecond extrinsic
  3. For MoonbeamRuntimeXcmConfigAssetType, choose Xcm
  4. Enter 1 for parents
  5. Select Here for interior
  6. Click the + button to submit the query

The UnitsPerSecond for xcDOT is 11,285,231,116.

Get the xcUNIT units per second value

Remember that one unit of weight is defined as one picosecond of execution time. Therefore, the formula to determine execution time is as follows:

ExecutionTime = (Weight / Picosecond) * NumberOfInstructions

To determine the execution time for Alice's transfer of DOT to Moonbeam, which contains four XCM instructions, you can use the following calculation:

ExecutionTime = (200000000 / 10^12) * 4

Which means that four XCM instructions cost 0.0008 seconds of block execution time.

To calculate the total cost in xcDOT, you'll also need the number of decimals the asset in question uses, which for xcDOT is 10 decimals. You can determine the number of decimals for any asset by querying the asset metadata.

The block execution formula can then be used to determine how much Alice's transfer of DOT to Alith's account on Moonbeam costs. The formula for finding the total cost is as follows:

Cost = (UnitsPerSecond / DecimalConversion) * ExecutionTime

Then the calculation for the transfer is:

Cost = (11285231116 / 10^10) * 0.0008

The total cost to transfer Alice's DOT to Alith's account for xcDOT is 0.00090281848 xcDOT.