Skip to content

Commit

Permalink
pallet-xcm: enhance reserve_transfer_assets to support remote reser…
Browse files Browse the repository at this point in the history
…ves (#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 #1584
Fixes #2055

---------

Co-authored-by: Francisco Aguirre <franciscoaguirreperez@gmail.com>
Co-authored-by: Branislav Kontur <bkontur@gmail.com>
  • Loading branch information
3 people authored Nov 13, 2023
1 parent 29654a4 commit 1825737
Show file tree
Hide file tree
Showing 80 changed files with 3,650 additions and 1,437 deletions.
5 changes: 5 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 0 additions & 7 deletions cumulus/parachain-template/runtime/src/xcm_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,11 +150,6 @@ pub type XcmRouter = WithUniqueTopic<(
XcmpQueue,
)>;

#[cfg(feature = "runtime-benchmarks")]
parameter_types! {
pub ReachableDest: Option<MultiLocation> = Some(Parent.into());
}

impl pallet_xcm::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type SendXcmOrigin = EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>;
Expand All @@ -180,8 +175,6 @@ impl pallet_xcm::Config for Runtime {
type SovereignAccountOf = LocationToAccountId;
type MaxLockers = ConstU32<8>;
type WeightInfo = pallet_xcm::TestWeightInfo;
#[cfg(feature = "runtime-benchmarks")]
type ReachableDest = ReachableDest;
type AdminOrigin = EnsureRoot<AccountId>;
type MaxRemoteLockConsumers = ConstU32<0>;
type RemoteLockConsumerIdentifier = ();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use frame_support::traits::OnInitialize;
// Cumulus
use emulated_integration_tests_common::{
impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain,
impl_assets_helpers_for_system_parachain, xcm_emulator::decl_test_parachains,
impl_assets_helpers_for_parachain, xcm_emulator::decl_test_parachains,
};
use rococo_emulated_chain::Rococo;

Expand Down Expand Up @@ -51,5 +51,5 @@ decl_test_parachains! {

// AssetHubRococo implementation
impl_accounts_helpers_for_parachain!(AssetHubRococo);
impl_assert_events_helpers_for_parachain!(AssetHubRococo);
impl_assets_helpers_for_system_parachain!(AssetHubRococo, Rococo);
impl_assert_events_helpers_for_parachain!(AssetHubRococo, false);
impl_assets_helpers_for_parachain!(AssetHubRococo, Rococo);
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use frame_support::traits::OnInitialize;
// Cumulus
use emulated_integration_tests_common::{
impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain,
impl_assets_helpers_for_system_parachain, xcm_emulator::decl_test_parachains,
impl_assets_helpers_for_parachain, xcm_emulator::decl_test_parachains,
};
use westend_emulated_chain::Westend;

Expand Down Expand Up @@ -51,5 +51,5 @@ decl_test_parachains! {

// AssetHubWestend implementation
impl_accounts_helpers_for_parachain!(AssetHubWestend);
impl_assert_events_helpers_for_parachain!(AssetHubWestend);
impl_assets_helpers_for_system_parachain!(AssetHubWestend, Westend);
impl_assert_events_helpers_for_parachain!(AssetHubWestend, false);
impl_assets_helpers_for_parachain!(AssetHubWestend, Westend);
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use frame_support::traits::OnInitialize;
// Cumulus
use emulated_integration_tests_common::{
impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain,
impl_assets_helpers_for_system_parachain, xcm_emulator::decl_test_parachains,
impl_assets_helpers_for_parachain, xcm_emulator::decl_test_parachains,
};
use wococo_emulated_chain::Wococo;

Expand Down Expand Up @@ -49,5 +49,5 @@ decl_test_parachains! {

// AssetHubWococo implementation
impl_accounts_helpers_for_parachain!(AssetHubWococo);
impl_assert_events_helpers_for_parachain!(AssetHubWococo);
impl_assets_helpers_for_system_parachain!(AssetHubWococo, Wococo);
impl_assert_events_helpers_for_parachain!(AssetHubWococo, false);
impl_assets_helpers_for_parachain!(AssetHubWococo, Wococo);
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,4 @@ decl_test_parachains! {

// BridgeHubRococo implementation
impl_accounts_helpers_for_parachain!(BridgeHubRococo);
impl_assert_events_helpers_for_parachain!(BridgeHubRococo);
impl_assert_events_helpers_for_parachain!(BridgeHubRococo, false);
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,4 @@ decl_test_parachains! {

// BridgeHubWestend implementation
impl_accounts_helpers_for_parachain!(BridgeHubWestend);
impl_assert_events_helpers_for_parachain!(BridgeHubWestend);
impl_assert_events_helpers_for_parachain!(BridgeHubWestend, false);
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,4 @@ decl_test_parachains! {

// BridgeHubWococo implementation
impl_accounts_helpers_for_parachain!(BridgeHubWococo);
impl_assert_events_helpers_for_parachain!(BridgeHubWococo);
impl_assert_events_helpers_for_parachain!(BridgeHubWococo, false);
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@ parachains-common = { path = "../../../../../../../parachains/common" }
cumulus-primitives-core = { path = "../../../../../../../primitives/core", default-features = false }
emulated-integration-tests-common = { path = "../../../../common", default-features = false }
penpal-runtime = { path = "../../../../../../runtimes/testing/penpal" }
rococo-emulated-chain = { path = "../../../relays/rococo" }
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@ use frame_support::traits::OnInitialize;

// Cumulus
use emulated_integration_tests_common::{
impl_assert_events_helpers_for_parachain, xcm_emulator::decl_test_parachains,
impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain,
impl_assets_helpers_for_parachain, xcm_emulator::decl_test_parachains,
};
use rococo_emulated_chain::Rococo;

// Penpal Parachain declaration
decl_test_parachains! {
Expand All @@ -40,6 +42,7 @@ decl_test_parachains! {
pallets = {
PolkadotXcm: penpal_runtime::PolkadotXcm,
Assets: penpal_runtime::Assets,
Balances: penpal_runtime::Balances,
}
},
pub struct PenpalB {
Expand All @@ -56,10 +59,13 @@ decl_test_parachains! {
pallets = {
PolkadotXcm: penpal_runtime::PolkadotXcm,
Assets: penpal_runtime::Assets,
Balances: penpal_runtime::Balances,
}
},
}

// Penpal implementation
impl_assert_events_helpers_for_parachain!(PenpalA);
impl_assert_events_helpers_for_parachain!(PenpalB);
impl_accounts_helpers_for_parachain!(PenpalA);
impl_assets_helpers_for_parachain!(PenpalA, Rococo);
impl_assert_events_helpers_for_parachain!(PenpalA, true);
impl_assert_events_helpers_for_parachain!(PenpalB, true);
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ decl_test_relay_chains! {
on_init = (),
runtime = westend_runtime,
core = {
SovereignAccountOf: westend_runtime::xcm_config::LocationConverter, //TODO: rename to SovereignAccountOf,
SovereignAccountOf: westend_runtime::xcm_config::LocationConverter,
},
pallets = {
XcmPallet: westend_runtime::XcmPallet,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,7 @@ macro_rules! impl_accounts_helpers_for_parachain {

#[macro_export]
macro_rules! impl_assert_events_helpers_for_parachain {
( $chain:ident ) => {
( $chain:ident, $ignore_weight:expr ) => {
$crate::impls::paste::paste! {
type [<$chain RuntimeEvent>]<N> = <$chain<N> as $crate::impls::Chain>::RuntimeEvent;

Expand All @@ -412,7 +412,7 @@ macro_rules! impl_assert_events_helpers_for_parachain {
[<$chain RuntimeEvent>]::<N>::PolkadotXcm(
$crate::impls::pallet_xcm::Event::Attempted { outcome: $crate::impls::Outcome::Complete(weight) }
) => {
weight: $crate::impls::weight_within_threshold(
weight: $ignore_weight || $crate::impls::weight_within_threshold(
($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD),
expected_weight.unwrap_or(*weight),
*weight
Expand All @@ -434,7 +434,7 @@ macro_rules! impl_assert_events_helpers_for_parachain {
[<$chain RuntimeEvent>]::<N>::PolkadotXcm(
$crate::impls::pallet_xcm::Event::Attempted { outcome: $crate::impls::Outcome::Incomplete(weight, error) }
) => {
weight: $crate::impls::weight_within_threshold(
weight: $ignore_weight || $crate::impls::weight_within_threshold(
($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD),
expected_weight.unwrap_or(*weight),
*weight
Expand Down Expand Up @@ -490,7 +490,7 @@ macro_rules! impl_assert_events_helpers_for_parachain {
[<$chain RuntimeEvent>]::<N>::MessageQueue($crate::impls::pallet_message_queue::Event::Processed {
success: true, weight_used: weight, ..
}) => {
weight: $crate::impls::weight_within_threshold(
weight: $ignore_weight || $crate::impls::weight_within_threshold(
($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD),
expected_weight.unwrap_or(*weight),
*weight
Expand All @@ -510,7 +510,7 @@ macro_rules! impl_assert_events_helpers_for_parachain {
[<$chain RuntimeEvent>]::<N>::MessageQueue($crate::impls::pallet_message_queue::Event::Processed {
success: false, weight_used: weight, ..
}) => {
weight: $crate::impls::weight_within_threshold(
weight: $ignore_weight || $crate::impls::weight_within_threshold(
($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD),
expected_weight.unwrap_or(*weight),
*weight
Expand Down Expand Up @@ -541,7 +541,7 @@ macro_rules! impl_assert_events_helpers_for_parachain {
vec![
[<$chain RuntimeEvent>]::<N>::MessageQueue($crate::impls::pallet_message_queue::Event::Processed { success: true, weight_used: weight, .. }
) => {
weight: $crate::impls::weight_within_threshold(
weight: $ignore_weight || $crate::impls::weight_within_threshold(
($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD),
expected_weight.unwrap_or(*weight),
*weight
Expand All @@ -556,7 +556,7 @@ macro_rules! impl_assert_events_helpers_for_parachain {
}

#[macro_export]
macro_rules! impl_assets_helpers_for_system_parachain {
macro_rules! impl_assets_helpers_for_parachain {
( $chain:ident, $relay_chain:ident ) => {
$crate::impls::paste::paste! {
impl<N: $crate::impls::Network> $chain<N> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ frame-support = { path = "../../../../../../../substrate/frame/support", default
pallet-balances = { path = "../../../../../../../substrate/frame/balances", default-features = false}
pallet-assets = { path = "../../../../../../../substrate/frame/assets", default-features = false}
pallet-asset-conversion = { path = "../../../../../../../substrate/frame/asset-conversion", default-features = false}
pallet-message-queue = { path = "../../../../../../../substrate/frame/message-queue", default-features = false }

# Polkadot
xcm = { package = "staging-xcm", path = "../../../../../../../polkadot/xcm", default-features = false}
Expand All @@ -28,5 +29,6 @@ rococo-runtime = { path = "../../../../../../../polkadot/runtime/rococo" }
asset-test-utils = { path = "../../../../../runtimes/assets/test-utils" }
parachains-common = { path = "../../../../../../parachains/common" }
asset-hub-rococo-runtime = { path = "../../../../../runtimes/assets/asset-hub-rococo" }
emulated-integration-tests-common = { path = "../../../common", default-features = false}
emulated-integration-tests-common = { path = "../../../common", default-features = false }
penpal-runtime = { path = "../../../../../runtimes/testing/penpal" }
rococo-system-emulated-network ={ path = "../../../networks/rococo-system" }
Original file line number Diff line number Diff line change
Expand Up @@ -61,18 +61,20 @@ pub const ASSET_MIN_BALANCE: u128 = 1000;
pub const ASSETS_PALLET_ID: u8 = 50;

pub type RelayToSystemParaTest = Test<Rococo, AssetHubRococo>;
pub type RelayToParaTest = Test<Rococo, PenpalA>;
pub type SystemParaToRelayTest = Test<AssetHubRococo, Rococo>;
pub type SystemParaToParaTest = Test<AssetHubRococo, PenpalA>;
pub type ParaToSystemParaTest = Test<PenpalA, AssetHubRococo>;

/// Returns a `TestArgs` instance to de used for the Relay Chain accross integraton tests
pub fn relay_test_args(amount: Balance) -> TestArgs {
/// Returns a `TestArgs` instance to be used for the Relay Chain across integration tests
pub fn relay_test_args(
dest: MultiLocation,
beneficiary_id: AccountId32,
amount: Balance,
) -> TestArgs {
TestArgs {
dest: Rococo::child_location_of(AssetHubRococo::para_id()),
beneficiary: AccountId32Junction {
network: None,
id: AssetHubRococoReceiver::get().into(),
}
.into(),
dest,
beneficiary: AccountId32Junction { network: None, id: beneficiary_id.into() }.into(),
amount,
assets: (Here, amount).into(),
asset_id: None,
Expand All @@ -81,21 +83,22 @@ pub fn relay_test_args(amount: Balance) -> TestArgs {
}
}

/// Returns a `TestArgs` instance to de used for the System Parachain accross integraton tests
pub fn system_para_test_args(
/// Returns a `TestArgs` instance to be used by parachains across integration tests
pub fn para_test_args(
dest: MultiLocation,
beneficiary_id: AccountId32,
amount: Balance,
assets: MultiAssets,
asset_id: Option<u32>,
fee_asset_item: u32,
) -> TestArgs {
TestArgs {
dest,
beneficiary: AccountId32Junction { network: None, id: beneficiary_id.into() }.into(),
amount,
assets,
asset_id,
fee_asset_item: 0,
fee_asset_item,
weight_limit: WeightLimit::Unlimited,
}
}
Expand Down
Loading

0 comments on commit 1825737

Please sign in to comment.