Skip to main content

Holding Register Modifiers

Most of the XCM instructions alter the Holding Register. We already have seen instructions that alter the Holding Register, like the WithdrawAsset or DepositAsset instructions. In this chapter we go over more instructions that alter the holding register, namely:

  • BurnAsset
  • ExchangeAsset

BurnAsset

BurnAsset(MultiAssets)

The BurnAsset instruction allows for the reduction of assets in the Holding Register by up to the specified assets. The execution of the instruction does not throw an error if the Holding Register does not contain the assets (to make this an error, use ExpectAsset prior).

Example

For the full example, check the repo. The Scenario of the example is as follows: Parachain A withdraws 10 units from its sovereign account on the relay chain and burns 4 of them. The relay chain then reports back the status of the Holding Register to Parachain A. We expect the Holding Register to hold 6 units. Note: If we would have added more then 10 units worth of assets in the BurnAsset instruction, we would have burned all assets in the Holding Register and the execution would succeed.

let message = Xcm(vec![
WithdrawAsset((Here, 10 * CENTS).into()),
BuyExecution { fees: (Here, CENTS).into(), weight_limit: WeightLimit::Unlimited },
BurnAsset((Here, 4 * CENTS).into()),
ReportHolding {
response_info: QueryResponseInfo {
destination: Parachain(1).into(),
query_id: QUERY_ID,
max_weight: Weight::from_parts(1_000_000_000, 64*64) },
assets: All.into()
}
]);

We expect the following response:

Response::Assets((Parent, 6 * CENTS).into())

ExchangeAsset

ExchangeAsset { give: MultiAssetFilter, want: MultiAssets, maximal: bool }

The ExchangeAsset instruction allows us to remove asset(s) (give) from the Holding Register and replace them with alternative assets (want). The ExchangeAsset instruction has three fields.

The give field indicates the maximum number of assets that can be removed from the Holding register.

The want field indicates the minimum amount of assets which give should be exchanged for. We should at a minimum get the assets in want for the execution of the instruction not to fail.

If the maximal field is true, then we prefer to give as much as possible up to the limit of give and receive accordingly more assets then stated in want. If the maximal field is false, then we prefer to give as little as possible in order to receive as little as possible while receiving at least want.

Example

The full example can be found in the repo.

The scenario for the example is this: Scenario: The relay chain sends an XCM to Parachain A that: .1 Withdraws some native assets .2 Exchanges these assets for relay chain derivative tokens, with maximal set to true. .3 Deposit all the assets that are in the Holding in the account of Alice.

NOTE: The implementation of the AssetExchanger is simple and in this case swaps all the assets in the exchange for the assets in give. Depending on the implementation of AssetExchanger, the test results could differ.

The Assets in the exchange in Parachain(1). This is a custom exchange implementation just for testing purposes.

let assets_in_exchange = vec![(Parent, 10 * CENTS).into()];
parachain::set_exchange_assets(assets_in_exchange);

The message that is send:

let message = Xcm(vec![
WithdrawAsset((Here, 10 * CENTS).into()),
BuyExecution { fees: (Here, CENTS).into(), weight_limit: WeightLimit::Unlimited },
// Maximal field set to true.
ExchangeAsset {
give: Definite((Here, 5 * CENTS).into()),
want: (Parent, 5 * CENTS).into(),
maximal: true,
},
DepositAsset {
assets: AllCounted(2).into(),
beneficiary: AccountId32 {
network: Some(parachain::RelayNetwork::get()),
id: ALICE.into(),
}
.into(),
},
]);

Alice receives 5 CENTS worth of native assets (Here) and 5 CENTS worth of relay chain derivative assets (Parent).