Trapping and Claiming assets.

When we reach the end of the execution of the XCM there can still be assets in the Holding Register. We can do nothing with them (essentially burning the assets) or we can trap the assets. When we trap the assets, we keep track of the assets together with the origin of the XCM. The origin can claim the assets back in one of the next XCMs. We have two instructions related to trapping and claiming assets:

  • Trap
  • ClaimAsset

Trap

Trap(#[codec(compact)] u64)

The Trap instruction throws an error of type Trap. Both the Trap instruction and Trap error take an u64 that can be used to represent some value. The Trap instruction is useful for throwing custom errors. An important thing to note is that the Trap instruction does not directly trap assets. It can however forcefully halt the further execution of instructions and if there are still assets in the Holding Register, these assets can be trapped.

ClaimAsset

ClaimAsset { assets: MultiAssets, ticket: MultiLocation }

Once assets are trapped, the ClaimAsset instruction can be used to claim the assets. The ClaimAsset instruction has two fields.

The assets field tells which trapped assets should be claimed. This must match exactly with the assets claimable by the origin.

The ticket field is an identifier that helps locating the asset. It is, for example, useful for distinguishing between Asset Versions. Lets say we have an XCM V2 trapped asset and send an XCM V3 ClaimAsset instruction, then the ticket field can be used to tell between the versions. In the xcm-pallet, Here is used to describe the same version as the ClaimAsset instruction, while the GeneralIndex Junction is used to describe other XCM versions.

Example

The full example can be found here.

The scenario of the example is this: Parachain A withdraws funds from its sovereign account on the relay chain. The assets are trapped because an error is thrown and the execution is halted. Parachain A claims the trapped assets and receives a report of the holding register.

Parachain A sends the following message to the relay chain. The message errors because of the Trap instruction, so all assets in the Holding Register are trapped.

let message = Xcm(vec![
    WithdrawAsset((Here, 10 * CENTS).into()),
    BuyExecution { fees: (Here, CENTS).into(), weight_limit: WeightLimit::Unlimited },
    Trap(0), // <-- Errors
    DepositAsset { // <-- Not executed because of error.
        assets: All.into(), 
        beneficiary: AccountId32 { 
            network: Some(parachain::RelayNetwork::get()), 
            id: ALICE.into() 
        }.into() 
    }
]);

Parachain A claims the assets, reports them to itself and deposits them in the Account of Alice.

let claim_message = Xcm(vec![
    ClaimAsset { assets: (Here, 10 * CENTS).into(), ticket: Here.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()
    },
    DepositAsset {
        assets: All.into(), 
        beneficiary: AccountId32 { 
            network: Some(parachain::RelayNetwork::get()), 
            id: ALICE.into() 
        }.into() 
    },
]);