First Look
In this section, we take you through a simple example of an XCM. In this example, we withdraw the native token from the account of Alice and deposit this token in the account of Bob. This message simulates a transfer between two accounts in the same consensus system (ParaA
). You can find the complete code example in the repo.
Message
let message = Xcm(vec![
WithdrawAsset((Here, amount).into()),
BuyExecution{ fees: (Here, amount).into(), weight_limit: WeightLimit::Unlimited },
DepositAsset {
assets: All.into(),
beneficiary: MultiLocation {
parents: 0,
interior: Junction::AccountId32 {
network: None,
id: BOB.clone().into()
}.into(),
}.into()
}
]);
The message consists of three instructions: WithdrawAsset
, BuyExecution
, and DepositAsset
.
In the following sections we will go over each instruction.
WithdrawAsset
#![allow(unused)] fn main() { WithdrawAsset((Here, amount).into()) }
The first instruction takes as an input the MultiAsset that should be withdrawn. The MultiAsset describes the native parachain token with the Here
keyword. The amount
parameter is the number of tokens that are transferred. The withdrawal account depends on the origin of the message. In this example the origin of the message is Alice.
The WithdrawAsset instruction moves amount
number of native tokens from Alice's account into the holding register.
BuyExecution
#![allow(unused)] fn main() { BuyExecution{fees: (Here, amount).into(), weight_limit: WeightLimit::Unlimited} }
To execute XCM instructions, weight (some amount of resources) has to be bought.
The amount of weight needed to execute an XCM depends on the number and type of instructions in the XCM.
The BuyExecution
instruction pays for the weight using the fees
.
The fees
parameter describes the asset in the holding register that should be used for paying for the weight.
The weight_limit
parameter defines the maximum amount of fees that can be used for buying weight.
There are special occasions where it is not necessary to buy weight.
See the chapter on weight and fees for more information about the fees in XCM.
DepositAsset
#![allow(unused)] fn main() { DepositAsset { assets: All.into(), beneficiary: MultiLocation { parents: 0, interior: Junction::AccountId32 { network: None, id: BOB.clone().into() }.into(), }.into() } }
The DepositAsset instruction is used to deposit funds from the holding register into the account of the beneficiary.
We don’t actually know how much is remaining in the holding register after the BuyExecution
instruction, but that doesn’t matter since we specify a wildcard for the asset(s) which should be deposited.
In this case, the wildcard is All
, meaning that all assets in the holding register at that point in the execution should be deposited.
The beneficiary in this case is the account of Bob in the current consensus system.
When the three instructions are combined, we withdraw amount
native tokens from the account of Alice, pay for the execution of these instructions, and deposit the remaining tokens in the account of Bob.
What next?
Now that we have taken a first look at an XCM, we can dive deeper into all the XCM instructions, to be able to build more complex XCVM programs.
For an overview of the instructions check out the xcm-format repo.
We'll show examples for every instruction in the journey through XCM chapter.
First, it's important to learn the fundamentals, MultiLocation
, MultiAsset
, and other concepts in XCM.
We'll talk about those next.