polkadot icon indicating copy to clipboard operation
polkadot copied to clipboard

pallet-xcm: XCM assets reserve withdraw feature

Open akru opened this issue 3 years ago • 8 comments

Motivation

Historically pallet-xcm is basic Polkadot pallet for sending XCM, including assets manipulation functions like reserve_transfer_assets call. Unfortunately pallet-xcm miss function for getting reserved / transferred assets back.

For example, reserve_transfer_assets send multi-asset using TransferReserveAssets instruction, which process lock asset and notify destination parachain about.

https://github.com/paritytech/polkadot/blob/d1002106ab43f7b01cc86ad9aa2fe41d4b4a8f5f/xcm/pallet-xcm/src/lib.rs#L816

But in pair to it, I believe, should exist a way for get these assets back using InitiateReserveWithdraw instruction, which burn synthetic asset on chain and send notification to destination for releasing locked asset.

Solution

This PR implements reserve_withdraw_asset in pair to reserve_transfer_assets, it uses InitiateReserveWithdraw XCVM instruction and can be used for sending reserved assets back. It release ecosystem projects of using multiple XCM pallets like xtokens / pallet-xcm: one for assets deposing and other for assets withdraw.

Applying this PR makes possible ecosystem projects to use pallet-xcm only for full XCM assets support.

akru avatar Sep 07 '22 03:09 akru

Adding an extrinsic to execute an XCM that includes InitiateReserveWithdraw doesn't simply allow the destination chain to send synthetic/derivative/bookkeeping assets back to the reserve, it also allows any two chains to send/receive said assets via an intermediary reserve chain.

We'll need to think thoroughly about the implications of such an extrinsic first to see whether it's a fit for the purposes of the XCM pallet.

KiChjang avatar Sep 08 '22 04:09 KiChjang

Thank you for feedback @KiChjang, I believe if pallet-xcm includes reserve transfer (deposit) function then it should have reserve withdraw function.

Looking forward to your final decision.

akru avatar Sep 09 '22 02:09 akru

I would just expose do_reserve_withdraw_assets as reserve_withdraw_assets, rather than having two separate extrinsics.

gavofyork avatar Sep 12 '22 10:09 gavofyork

@gavofyork thank you for fixes.

I just made do_* and call separately in manner of reserve_transfer_assets/limited_reserve_transfer_assets, it makes possible to provide 'limited' version of same call.

akru avatar Sep 12 '22 12:09 akru

This pull request has been mentioned on Polkadot Forum. There might be relevant details there:

https://forum.polkadot.network/t/asset-multilocation-punning/423/1

Polkadot-Forum avatar Sep 18 '22 17:09 Polkadot-Forum

@KiChjang just to make summary of this PR high-level workflow discussion.

How reserve transfer should works:

  1. The Alice wan't to transfer asset(T) to Bob from parachain A to parachain B (T has MultiLocation = X);
  2. The Alice send extrinsic reserve_transfer_assets which precisely send XCM in form
let xcm = Xcm(vec![
    BuyExecution { fees, weight_limit },
    DepositAsset { assets: Wild(All), max_assets, beneficiary },
]);
let mut message = Xcm(vec![TransferReserveAsset { assets, dest, xcm }]);

where parachain B receives message:

Xcm(vec![
    ReserveAssetDeposited(assets),
    ClearOrigin,
    BuyExecution { fees, weight_limit: Limited(0) },
    DepositAsset { assets: Wild(All), max_assets, beneficiary },
]);
  1. This step is important, because the parachain B dont receives precisely same multi-asset as parachain A sent. I believe that anchor/reanchor wrappers in XCM executor is used for making different multi-asset location before send:

https://github.com/paritytech/polkadot/blob/master/xcm/xcm-executor/src/lib.rs#L314

  1. Reverse way is the same but uses InitiateReserveWithdraw opcode. XCM executor reanchor multi-location of asset before sending it back to parachain A.
let xcm = Xcm(vec![
                BuyExecution { fees, weight_limit },
                DepositAsset {
                    assets: Wild(All),
                    max_assets,
                    beneficiary,
                },
            ]);
            let message = Xcm(vec![
                WithdrawAsset(assets),
                InitiateReserveWithdraw {
                    assets: Wild(All),
                    reserve: dest,
                    xcm,
                },
            ]);

XCM message don't directly use user sent multi-asset values, XCM executor converts it before sent:

https://github.com/paritytech/polkadot/blob/master/xcm/xcm-executor/src/lib.rs#L415

So, I guess your concern should be applied not for this PR because it uses XCM executor anchor/reanchor logic.

Why it looks like parachains uses same asset id for local and remote assets, I guess it is because of AssetId conversion used inside AssetTransactor that should definitely have 1-1 mapping between numeric asset_id and asset multi-location.

akru avatar Sep 23 '22 04:09 akru

@akru From your description, it would seem to me that it isn't clear how re-anchoring works to you. All re-anchoring does is rewrite the MultiLocation from the perspective of the destination, i.e. if your asset was originally written as ../Here, re-anchoring this to the relay chain would simply change it to Here, or if the destination is Statemint, it would still stay the same as ../Here.

If we have a derivative asset that has a MultiLocation of PalletIndex(17)/GeneralIndex(42) instead, then reanchoring this MultiLocation to the relay chain would yield Parachain(your_para_id)/PalletIndex(17)/GeneralIndex(42), and if the destination is Statemint, it would be re-anchored to ../Parachain(your_para_id)/PalletIndex(17)/GeneralIndex(42).

I hope you can see that the MultiLocation still points to the derivative asset, and not the reserve asset. In short, re-anchoring does not magically convert the MultiLocation of the derivative asset to that of the reserve asset.

KiChjang avatar Sep 23 '22 05:09 KiChjang

@KiChjang thank you for explanation. I see, here you meant derivative asset in your opinion should have totally different multi-location without any reference to original, right? So, in this case we should have some kind of mapping between derivative and reserved asset, that makes things more and more complex, didn’t?

akru avatar Sep 24 '22 06:09 akru