mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-31 06:21:02 +00:00
18257373b3
## 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>
82 lines
2.9 KiB
Rust
82 lines
2.9 KiB
Rust
// Copyright (C) Parity Technologies (UK) Ltd.
|
|
// This file is part of Cumulus.
|
|
|
|
// Cumulus is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
|
|
// Cumulus is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with Cumulus. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
//! Module contains predefined test-case scenarios for `Runtime` with various assets.
|
|
|
|
pub mod test_cases;
|
|
pub mod test_cases_over_bridge;
|
|
pub mod xcm_helpers;
|
|
|
|
use frame_support::traits::ProcessMessageError;
|
|
pub use parachains_runtimes_test_utils::*;
|
|
use std::fmt::Debug;
|
|
|
|
use xcm::latest::prelude::*;
|
|
use xcm_builder::{CreateMatcher, MatchXcm};
|
|
|
|
/// Given a message, a sender, and a destination, it returns the delivery fees
|
|
fn get_fungible_delivery_fees<S: SendXcm>(destination: MultiLocation, message: Xcm<()>) -> u128 {
|
|
let Ok((_, delivery_fees)) = validate_send::<S>(destination, message) else {
|
|
unreachable!("message can be sent; qed")
|
|
};
|
|
if let Some(delivery_fee) = delivery_fees.inner().first() {
|
|
let Fungible(delivery_fee_amount) = delivery_fee.fun else {
|
|
unreachable!("asset is fungible; qed");
|
|
};
|
|
delivery_fee_amount
|
|
} else {
|
|
0
|
|
}
|
|
}
|
|
|
|
/// Helper function to verify `xcm` contains all relevant instructions expected on destination
|
|
/// chain as part of a reserve-asset-transfer.
|
|
pub(crate) fn assert_matches_reserve_asset_deposited_instructions<RuntimeCall: Debug>(
|
|
xcm: &mut Xcm<RuntimeCall>,
|
|
expected_reserve_assets_deposited: &MultiAssets,
|
|
expected_beneficiary: &MultiLocation,
|
|
) {
|
|
let _ = xcm
|
|
.0
|
|
.matcher()
|
|
.skip_inst_while(|inst| !matches!(inst, ReserveAssetDeposited(..)))
|
|
.expect("no instruction ReserveAssetDeposited?")
|
|
.match_next_inst(|instr| match instr {
|
|
ReserveAssetDeposited(reserve_assets) => {
|
|
assert_eq!(reserve_assets, expected_reserve_assets_deposited);
|
|
Ok(())
|
|
},
|
|
_ => Err(ProcessMessageError::BadFormat),
|
|
})
|
|
.expect("expected instruction ReserveAssetDeposited")
|
|
.match_next_inst(|instr| match instr {
|
|
ClearOrigin => Ok(()),
|
|
_ => Err(ProcessMessageError::BadFormat),
|
|
})
|
|
.expect("expected instruction ClearOrigin")
|
|
.match_next_inst(|instr| match instr {
|
|
BuyExecution { .. } => Ok(()),
|
|
_ => Err(ProcessMessageError::BadFormat),
|
|
})
|
|
.expect("expected instruction BuyExecution")
|
|
.match_next_inst(|instr| match instr {
|
|
DepositAsset { assets: _, beneficiary } if beneficiary == expected_beneficiary =>
|
|
Ok(()),
|
|
_ => Err(ProcessMessageError::BadFormat),
|
|
})
|
|
.expect("expected instruction DepositAsset");
|
|
}
|