pallet-xcm: enhance reserve_transfer_assets to support remote reserves (#1672)

## Motivation

`pallet-xcm` is the main user-facing interface for XCM functionality,
including assets manipulation functions like `teleportAssets()` and
`reserve_transfer_assets()` calls.

While `teleportAsset()` works both ways, `reserve_transfer_assets()`
works only for sending reserve-based assets to a remote destination and
beneficiary when the reserve is the _local chain_.

## Solution

This PR enhances `pallet_xcm::(limited_)reserve_withdraw_assets` to
support transfers when reserves are other chains.
This will allow complete, **bi-directional** reserve-based asset
transfers user stories using `pallet-xcm`.

Enables following scenarios:
- transferring assets with local reserve (was previously supported iff
asset used as fee also had local reserve - now it works in all cases),
- transferring assets with reserve on destination,
- transferring assets with reserve on remote/third-party chain (iff
assets and fees have same remote reserve),
- transferring assets with reserve different than the reserve of the
asset to be used as fees - meaning can be used to transfer random asset
with local/dest reserve while using DOT for fees on all involved chains,
even if DOT local/dest reserve doesn't match asset reserve,
- transferring assets with any type of local/dest reserve while using
fees which can be teleported between involved chains.

All of the above is done by pallet inner logic without the user having
to specify which scenario/reserves/teleports/etc. The correct scenario
and corresponding XCM programs are identified, and respectively, built
automatically based on runtime configuration of trusted teleporters and
trusted reserves.

#### Current limitations:
- while `fees` and "non-fee" `assets` CAN have different reserves (or
fees CAN be teleported), the remaining "non-fee" `assets` CANNOT, among
themselves, have different reserve locations (this is also implicitly
enforced by `MAX_ASSETS_FOR_TRANSFER=2`, but this can be safely
increased in the future).
- `fees` and "non-fee" `assets` CANNOT have **different remote**
reserves (this could also be supported in the future, but adds even more
complexity while possibly not being worth it - we'll see what the future
holds).

Fixes https://github.com/paritytech/polkadot-sdk/issues/1584
Fixes https://github.com/paritytech/polkadot-sdk/issues/2055

---------

Co-authored-by: Francisco Aguirre <franciscoaguirreperez@gmail.com>
Co-authored-by: Branislav Kontur <bkontur@gmail.com>
This commit is contained in:
Adrian Catangiu
2023-11-13 17:16:55 +02:00
committed by GitHub
parent 29654a4d71
commit 18257373b3
80 changed files with 3679 additions and 1466 deletions
+31 -1
View File
@@ -1588,7 +1588,7 @@ mod benches {
[pallet_asset_rate, AssetRate]
[pallet_whitelist, Whitelist]
// XCM
[pallet_xcm, XcmPallet]
[pallet_xcm, PalletXcmExtrinsiscsBenchmark::<Runtime>]
[pallet_xcm_benchmarks::fungible, pallet_xcm_benchmarks::fungible::Pallet::<Runtime>]
[pallet_xcm_benchmarks::generic, pallet_xcm_benchmarks::generic::Pallet::<Runtime>]
);
@@ -2064,6 +2064,8 @@ sp_api::impl_runtime_apis! {
use frame_system_benchmarking::Pallet as SystemBench;
use frame_benchmarking::baseline::Pallet as Baseline;
use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark;
let mut list = Vec::<BenchmarkList>::new();
list_benchmarks!(list, extra);
@@ -2081,6 +2083,7 @@ sp_api::impl_runtime_apis! {
use frame_benchmarking::{Benchmarking, BenchmarkBatch, BenchmarkError};
use frame_system_benchmarking::Pallet as SystemBench;
use frame_benchmarking::baseline::Pallet as Baseline;
use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark;
use sp_storage::TrackedStorageKey;
use xcm::latest::prelude::*;
use xcm_config::{
@@ -2097,6 +2100,33 @@ sp_api::impl_runtime_apis! {
impl frame_system_benchmarking::Config for Runtime {}
impl frame_benchmarking::baseline::Config for Runtime {}
impl pallet_xcm::benchmarking::Config for Runtime {
fn reachable_dest() -> Option<MultiLocation> {
Some(crate::xcm_config::AssetHub::get())
}
fn teleportable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> {
// Relay/native token can be teleported to/from AH.
Some((
MultiAsset {
fun: Fungible(EXISTENTIAL_DEPOSIT),
id: Concrete(Here.into())
},
crate::xcm_config::AssetHub::get(),
))
}
fn reserve_transferable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> {
// Relay can reserve transfer native token to some random parachain.
Some((
MultiAsset {
fun: Fungible(EXISTENTIAL_DEPOSIT),
id: Concrete(Here.into())
},
Parachain(43211234).into(),
))
}
}
impl pallet_xcm_benchmarks::Config for Runtime {
type XcmConfig = XcmConfig;
type AccountIdConverter = LocationConverter;
@@ -211,11 +211,6 @@ parameter_types! {
pub const FellowsBodyId: BodyId = BodyId::Technical;
}
#[cfg(feature = "runtime-benchmarks")]
parameter_types! {
pub ReachableDest: Option<MultiLocation> = Some(Parachain(ASSET_HUB_ID).into());
}
/// Type to convert an `Origin` type value into a `MultiLocation` value which represents an interior
/// location of this chain.
pub type LocalOriginToLocation = (
@@ -269,7 +264,5 @@ impl pallet_xcm::Config for Runtime {
type MaxRemoteLockConsumers = ConstU32<0>;
type RemoteLockConsumerIdentifier = ();
type WeightInfo = crate::weights::pallet_xcm::WeightInfo<Runtime>;
#[cfg(feature = "runtime-benchmarks")]
type ReachableDest = ReachableDest;
type AdminOrigin = EnsureRoot<AccountId>;
}