[XCM] Transfer Reserve & Non-Reserve Assets in a Single XCM

As far as I know, there is no way to construct an XCM message that can transfer both a Reserve and Non-Reserve asset in a single message.

The primary reason is that the XCM message pallets typically built for Reserve Assets are comprised of the following instructions:

  1. TransferReserveAsset - Executed in the Reserve Chain, this transfers XYZ tokens to the destination chain’s sovereign account. It appends ReserveAssetDeposited and ClearOrigin. As a result, only the ReserveAssetDeposited instruction can be executed before the origin information is cleared in the Non-Reserve chain (destination chain).
  2. ReserveAssetDeposited - This typically mints a representation of the asset deposited in the sovereign account.
  3. ClearOrigin - This wipes out all origin info, so the subsequent instructions that can be executed cannot require specific origins.
  4. BuyExecution (with whatever asset you specify here) and DepositAsset

This combination of instructions is limited to handling only Reserve assets out of the Reserve Chain. When transferring Non-Reserve assets, the process is somewhat similar but with InitiateReserveWithdraw, which prepends WithdrawAsset and ClearOrigin to the XCM message that will be executed by the (in this case) Reserve Chain. Therefore you are limiting that combination to handle only Non-Reserve asset transfers back to the Reserve Chain.

Is it possible to create a call that combines both processes? Let’s say we have Chain A with Reserve Asset A, and Chain B with Reserve Asset B. Alice wants to send an XCM Message from Chain A to Chain B, which includes instructions to transfer both tokens in one go. In this case, the XCM message executed in Chain B should include:

  1. ReserveAssetDeposited - To mint the representation of Reserve Asset A on Chain B.
  2. WithdrawAsset - To withdraw Reserve Asset B tokens from Chain A’s sovereign account.
  3. ClearOrigin - To clear all origin info.
  4. BuyExecution
  5. DepositAsset

Is this flow feasible?

Thanks in advance!

4 Likes

Thank you for the question! I’m happy to answer.

First of all, the extrinsics for asset teleportation and reserve asset transfers in pallet xcm aim to solve really useful scenarios. However, it’s encouraged to make your own pallets with extrinsics that use XCM in the way that’s most useful to your use case.
That said, this flow is definitely possible.

You can create your own extrinsic in a pallet to send a message with exactly those instructions.

Let’s say we have the following accounts:

let alice = sp_runtime::AccountId32::new([0u8; 32]); // Sender
let bob = sp_runtime::AccountId32::new([1u8; 32]); // Recipient

and the following amounts:

let amount_a = 1 * UNITS; // Amount of asset A to send (via derivative)
let amount_b = 2 * UNITS; // Amount of asset B to send (local transaction)

and let’s assume chains A and B are parachains of a relay chain with ids 1 and 2 respectively.

Then we could send this message:

let message = Xcm(vec![
  ReserveAssetDeposited((ParentThen(X1(Parachain(1))), amount_a).into()),
  WithdrawAsset((Here, amount_b).into()),
  ClearOrigin,
  BuyExecution {
    fees: (Here, amount_b).into(),
    weight_limit: WeightLimit::Unlimited,
  },
  DepositAsset {
    assets: All.into(),
    beneficiary: Junction::AccountId32 {
      id: bob.into(),
      network: None
    }.into(),
  },
]);

Sending this message would work. bob in chain B will have 1 unit of a derivative representing asset A and 2 units of the real asset B in his account.

This XCM is not enough though. When we just send a ReserveAssetDeposited instruction, we need to make sure we move an equal amount of the real asset A to chain B’s sovereign account on chain A. We need to do this ourselves. Instructions like TransferReserveAsset or DepositReserveAsset take care of this in case we want the most common behaviour (it’s expected to want to do custom things and get a little bit in the weeds). If we don’t fix this, derivatives don’t mean anything.

We need to make sure before we send our XCM that we transfer assets locally from alice’s account on chain A to chain B’s sovereign account. You could do this with the balances pallet.

Being allowed by the IsReserve config item of the other system is the only thing you need to make sure they trust that you actually do what’s needed before sending them the instruction to mint derivatives.

I hope that answers your question

4 Likes

Yes, thank you for the detailed explanation!

I kind of figured it was possible but I was curious as to why this has not yet been implemented in any pallet. So I thought maybe I missed something.

Also, it is understandable that TransferReserveAsset and DepositReserveAsset instructions can’t be used in the origin as they both force the first two instructions, and so they limit the XCM message on what type of assets it “can move”.

(cc @librelois)

1 Like

I guess it is possible to do this but it is just super hard to create a generalized implementation to perform XCM transfer with multiple assets with multiple reserves in a single message. And we don’t yet have many needs on such use case, so that’s why it is never implemented.

1 Like

It would be nice if XCMv4 could natively support the transfer of multiple assets with different reserves, with new instructions to ensure that this is done safely on the sending side.

In the meantime, I agree that it can already be done with a manual implementation on the sending chain, but it is not ideal.

2 Likes

How would you transfer multiple assets with multiple reserves in a single message?
Let’s say you wanted to send a message from A to B transferring assets X1, …, Xn with reserves R1, …, Rn.
If you send a message from A to B with ReserveAssetDeposited(X1, ..., Xn), you would run into a lot of problems. You would have to previously notify all reserves to move assets to B’s sovereign account, else it’s meaningless. That would already mean multiple messages. Also, B would have to trust A to act as a reserve for all those assets, since the message comes from it, which is very confusing and unsafe.

The way to do this now would just be to send n messages to the reserves, all of which send one message to B for it to mint the derivatives. In this case, B needs to trust all n reserves. It’s more messages, and you’d have to send an extra message from A to B to use the assets (after making sure all the transfers were completed), but it works. An extrinsic that does this could be built by someone in the ecosystem.

If you need it to happen in one message, have any idea of how to do it in a way that works for your use-cases, and think it would benefit the ecosystem, you should definitely build it. Then you can package your solution in a pallet/extrinsic and let the ecosystem use it.

It’s intended for ecosystem builders to use XCM building blocks to build complex scenarios like this. XCM implementers can’t add instructions for every use-case, it is detrimental to the format and bad for the ecosystem.
That said, if you think you have an idea for an improvement to the XCM spec itself that is not better suited to be an extrinsic you build yourself, then there’s the XCM format RFC process to propose it and get a discussion going.

1 Like

Sorry I wasn’t specific enough, I was thinking of the case where we need to send assets whose reserves are A and B (in the context of a message A->B). This is typically the case if the user on B needs to pay the xcm fees on A with an asset whose reserve is B.

pallet-xcm now offers a flexible transfer_assets() extrinsic that does what you want :+1:

It can combine multiple types of transfers in same XCM as long as the path of all the assets is the same ( A->B or A->OtherReserve->B). Works even if some assets have reserve on A while others have it on B or others are teleportable between A and B.

More details here: pallet-xcm: add new flexible `transfer_assets()` call/extrinsic by acatangiu · Pull Request #2388 · paritytech/polkadot-sdk · GitHub

The main reason one cannot (or should not) combine assets that take different paths in a single transfer is that with multiple paths there is no ordering guarantee (e.g. assets can arrive before the fees) and no transfer atomicity guarantee (only half the transfer works, so it’s undefined state: not successful, not failed).

1 Like