mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 14:01:02 +00:00
XCM v1 (#2815)
* MultiAsset TWO * Draft next MultiAsset API. * XCM core builds * XCM Executor builds * XCM Builder builds * API changes making their way throughout * Some TODOs * Further build fixes * Basic compile builds * First test fixed * All executor tests fixed * Typo * Optimize subsume_assets and add test * Optimize checked_sub * XCM Builder first test fixed * Fix builder tests * Fix doc test * fix some doc tests * spelling * named fields for AllOf * Update xcm/src/v0/multiasset.rs Co-authored-by: Alexander Popiak <alexander.popiak@parity.io> * Update xcm/src/v0/multiasset.rs Co-authored-by: Alexander Popiak <alexander.popiak@parity.io> * Update xcm/src/v0/multiasset.rs Co-authored-by: Alexander Popiak <alexander.popiak@parity.io> * Update xcm/src/v0/multiasset.rs Co-authored-by: Alexander Popiak <alexander.popiak@parity.io> * Reformat * Move to XCM version 1 * Spelling * warnings * Replace some more v0->v1s * warnings * format * Add max_assets param * building * test fixes * tests * another test * final test * tests * Rename Null -> Here * Introduce * More ergonomics * More ergonomics * test fix * test fixes * docs * BuyExecution includes * Fix XCM extrinsics * fmt * Make Vec<MultiAsset>/MultiAssets conversions safe * More MultiAssets conversion safety * spelling * fix doc test * Apply suggestions from code review Co-authored-by: Amar Singh <asinghchrony@protonmail.com> * Apply suggestions from code review Co-authored-by: Amar Singh <asinghchrony@protonmail.com> * fmt * Add v0, remove VersionedMultiAsset * Remove VersionedMultiLocation * Update xcm/src/v1/order.rs Co-authored-by: Amar Singh <asinghchrony@protonmail.com> * Update xcm/src/v1/mod.rs Co-authored-by: Amar Singh <asinghchrony@protonmail.com> * XCM v0 backwards compatibility * Full compatibility * fmt * Update xcm/pallet-xcm/src/lib.rs * Update xcm/src/v0/order.rs Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com> * Tweaks to versioning system * Fixes * fmt * Update xcm/xcm-executor/src/assets.rs Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com> * Update xcm/xcm-executor/src/assets.rs Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com> * Grumbles * Update xcm/src/v1/multiasset.rs Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com> * fmt * Update xcm/src/v1/multiasset.rs Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com> * Update xcm/src/v1/multiasset.rs Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com> * Fixes * Formatting Co-authored-by: Alexander Popiak <alexander.popiak@parity.io> Co-authored-by: Amar Singh <asinghchrony@protonmail.com> Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com>
This commit is contained in:
@@ -23,10 +23,11 @@ mod mock;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
use codec::{Decode, Encode};
|
||||
use frame_support::traits::{Contains, EnsureOrigin, Filter, Get, OriginTrait};
|
||||
use sp_runtime::{traits::BadOrigin, RuntimeDebug};
|
||||
use sp_std::{boxed::Box, convert::TryInto, marker::PhantomData, prelude::*, vec};
|
||||
use xcm::v0::prelude::*;
|
||||
use xcm::latest::prelude::*;
|
||||
use xcm_executor::traits::ConvertOrigin;
|
||||
|
||||
use frame_support::PalletId;
|
||||
@@ -87,7 +88,7 @@ pub mod pallet {
|
||||
#[pallet::event]
|
||||
#[pallet::generate_deposit(pub(super) fn deposit_event)]
|
||||
pub enum Event<T: Config> {
|
||||
Attempted(xcm::v0::Outcome),
|
||||
Attempted(xcm::latest::Outcome),
|
||||
Sent(MultiLocation, MultiLocation, Xcm<()>),
|
||||
}
|
||||
|
||||
@@ -134,15 +135,15 @@ pub mod pallet {
|
||||
/// from parachain to parachain, or `X1(Parachain(..))` to send from relay to parachain.
|
||||
/// - `beneficiary`: A beneficiary location for the assets in the context of `dest`. Will generally be
|
||||
/// an `AccountId32` value.
|
||||
/// - `assets`: The assets to be withdrawn. This should include the assets used to pay the fee on the
|
||||
/// `dest` side.
|
||||
/// - `assets`: The assets to be withdrawn. The first item should be the currency used to to pay the fee on the
|
||||
/// `dest` side. May not be empty.
|
||||
/// - `dest_weight`: Equal to the total weight on `dest` of the XCM message
|
||||
/// `Teleport { assets, effects: [ BuyExecution{..}, DepositAsset{..} ] }`.
|
||||
#[pallet::weight({
|
||||
let mut message = Xcm::WithdrawAsset {
|
||||
assets: assets.clone(),
|
||||
effects: sp_std::vec![ InitiateTeleport {
|
||||
assets: sp_std::vec![ All ],
|
||||
assets: Wild(All),
|
||||
dest: dest.clone(),
|
||||
effects: sp_std::vec![],
|
||||
} ]
|
||||
@@ -153,21 +154,28 @@ pub mod pallet {
|
||||
origin: OriginFor<T>,
|
||||
dest: MultiLocation,
|
||||
beneficiary: MultiLocation,
|
||||
assets: Vec<MultiAsset>,
|
||||
assets: MultiAssets,
|
||||
fee_asset_item: u32,
|
||||
dest_weight: Weight,
|
||||
) -> DispatchResult {
|
||||
let origin_location = T::ExecuteXcmOrigin::ensure_origin(origin)?;
|
||||
ensure!(assets.len() <= MAX_ASSETS_FOR_TRANSFER, Error::<T>::TooManyAssets);
|
||||
let value = (origin_location, assets);
|
||||
let value = (origin_location, assets.drain());
|
||||
ensure!(T::XcmTeleportFilter::contains(&value), Error::<T>::Filtered);
|
||||
let (origin_location, assets) = value;
|
||||
let inv_dest = T::LocationInverter::invert_location(&dest);
|
||||
let mut fees = assets.first().ok_or(Error::<T>::Empty)?.clone();
|
||||
fees.reanchor(&inv_dest).map_err(|_| Error::<T>::CannotReanchor)?;
|
||||
let fees = assets
|
||||
.get(fee_asset_item as usize)
|
||||
.ok_or(Error::<T>::Empty)?
|
||||
.clone()
|
||||
.reanchored(&inv_dest)
|
||||
.map_err(|_| Error::<T>::CannotReanchor)?;
|
||||
let max_assets = assets.len() as u32;
|
||||
let assets = assets.into();
|
||||
let mut message = Xcm::WithdrawAsset {
|
||||
assets,
|
||||
effects: vec![InitiateTeleport {
|
||||
assets: vec![All],
|
||||
assets: Wild(All),
|
||||
dest,
|
||||
effects: vec![
|
||||
BuyExecution {
|
||||
@@ -176,9 +184,10 @@ pub mod pallet {
|
||||
weight: 0,
|
||||
debt: dest_weight,
|
||||
halt_on_error: false,
|
||||
xcm: vec![],
|
||||
orders: vec![],
|
||||
instructions: vec![],
|
||||
},
|
||||
DepositAsset { assets: vec![All], dest: beneficiary },
|
||||
DepositAsset { assets: Wild(All), max_assets, beneficiary },
|
||||
],
|
||||
}],
|
||||
};
|
||||
@@ -203,7 +212,7 @@ pub mod pallet {
|
||||
/// - `assets`: The assets to be withdrawn. This should include the assets used to pay the fee on the
|
||||
/// `dest` side.
|
||||
/// - `dest_weight`: Equal to the total weight on `dest` of the XCM message
|
||||
/// `ReserveAssetDeposit { assets, effects: [ BuyExecution{..}, DepositAsset{..} ] }`.
|
||||
/// `ReserveAssetDeposited { assets, effects: [ BuyExecution{..}, DepositAsset{..} ] }`.
|
||||
#[pallet::weight({
|
||||
let mut message = Xcm::TransferReserveAsset {
|
||||
assets: assets.clone(),
|
||||
@@ -216,30 +225,38 @@ pub mod pallet {
|
||||
origin: OriginFor<T>,
|
||||
dest: MultiLocation,
|
||||
beneficiary: MultiLocation,
|
||||
assets: Vec<MultiAsset>,
|
||||
assets: MultiAssets,
|
||||
fee_asset_item: u32,
|
||||
dest_weight: Weight,
|
||||
) -> DispatchResult {
|
||||
let origin_location = T::ExecuteXcmOrigin::ensure_origin(origin)?;
|
||||
ensure!(assets.len() <= MAX_ASSETS_FOR_TRANSFER, Error::<T>::TooManyAssets);
|
||||
let value = (origin_location, assets);
|
||||
let value = (origin_location, assets.drain());
|
||||
ensure!(T::XcmReserveTransferFilter::contains(&value), Error::<T>::Filtered);
|
||||
let (origin_location, assets) = value;
|
||||
let inv_dest = T::LocationInverter::invert_location(&dest);
|
||||
let mut fees = assets.first().ok_or(Error::<T>::Empty)?.clone();
|
||||
fees.reanchor(&inv_dest).map_err(|_| Error::<T>::CannotReanchor)?;
|
||||
let fees = assets
|
||||
.get(fee_asset_item as usize)
|
||||
.ok_or(Error::<T>::Empty)?
|
||||
.clone()
|
||||
.reanchored(&inv_dest)
|
||||
.map_err(|_| Error::<T>::CannotReanchor)?;
|
||||
let max_assets = assets.len() as u32;
|
||||
let assets = assets.into();
|
||||
let mut message = Xcm::TransferReserveAsset {
|
||||
assets,
|
||||
dest,
|
||||
effects: vec![
|
||||
BuyExecution {
|
||||
fees,
|
||||
// Zero weight for additional XCM (since there are none to execute)
|
||||
// Zero weight for additional instructions/orders (since there are none to execute)
|
||||
weight: 0,
|
||||
debt: dest_weight,
|
||||
debt: dest_weight, // covers this, `TransferReserveAsset` xcm, and `DepositAsset` order.
|
||||
halt_on_error: false,
|
||||
xcm: vec![],
|
||||
orders: vec![],
|
||||
instructions: vec![],
|
||||
},
|
||||
DepositAsset { assets: vec![All], dest: beneficiary },
|
||||
DepositAsset { assets: Wild(All), max_assets, beneficiary },
|
||||
],
|
||||
};
|
||||
let weight =
|
||||
@@ -286,7 +303,7 @@ pub mod pallet {
|
||||
message: Xcm<()>,
|
||||
) -> Result<(), XcmError> {
|
||||
let message = match interior {
|
||||
MultiLocation::Null => message,
|
||||
MultiLocation::Here => message,
|
||||
who => Xcm::<()>::RelayedFrom { who, message: Box::new(message) },
|
||||
};
|
||||
log::trace!(target: "xcm::send_xcm", "dest: {:?}, message: {:?}", &dest, &message);
|
||||
@@ -363,7 +380,7 @@ where
|
||||
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
fn successful_origin() -> O {
|
||||
O::from(Origin::Xcm(MultiLocation::Null))
|
||||
O::from(Origin::Xcm(MultiLocation::Here))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,15 +25,15 @@ use sp_core::H256;
|
||||
use sp_runtime::{testing::Header, traits::IdentityLookup, AccountId32};
|
||||
pub use sp_std::{cell::RefCell, fmt::Debug, marker::PhantomData};
|
||||
use xcm::{
|
||||
opaque::v0::{Error as XcmError, MultiAsset, Result as XcmResult, SendXcm, Xcm},
|
||||
v0::{MultiLocation, NetworkId, Order},
|
||||
latest::prelude::*,
|
||||
opaque::latest::{Error as XcmError, MultiAsset, Result as XcmResult, SendXcm, Xcm},
|
||||
};
|
||||
use xcm_builder::{
|
||||
AccountId32Aliases, AllowTopLevelPaidExecutionFrom, ChildParachainAsNative,
|
||||
ChildParachainConvertsVia, ChildSystemParachainAsSuperuser,
|
||||
CurrencyAdapter as XcmCurrencyAdapter, FixedRateOfConcreteFungible, FixedWeightBounds,
|
||||
IsConcrete, LocationInverter, SignedAccountId32AsNative, SignedToAccountId32,
|
||||
SovereignSignedViaLocation, TakeWeightCredit,
|
||||
CurrencyAdapter as XcmCurrencyAdapter, FixedRateOfFungible, FixedWeightBounds, IsConcrete,
|
||||
LocationInverter, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation,
|
||||
TakeWeightCredit,
|
||||
};
|
||||
use xcm_executor::XcmExecutor;
|
||||
|
||||
@@ -133,9 +133,9 @@ impl pallet_balances::Config for Test {
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
pub const RelayLocation: MultiLocation = MultiLocation::Null;
|
||||
pub const RelayLocation: MultiLocation = MultiLocation::Here;
|
||||
pub const AnyNetwork: NetworkId = NetworkId::Any;
|
||||
pub Ancestry: MultiLocation = MultiLocation::Null;
|
||||
pub Ancestry: MultiLocation = MultiLocation::Here;
|
||||
pub UnitWeightCost: Weight = 1_000;
|
||||
}
|
||||
|
||||
@@ -154,7 +154,7 @@ type LocalOriginConverter = (
|
||||
|
||||
parameter_types! {
|
||||
pub const BaseXcmWeight: Weight = 1_000;
|
||||
pub CurrencyPerSecond: (MultiLocation, u128) = (RelayLocation::get(), 1);
|
||||
pub CurrencyPerSecond: (AssetId, u128) = (Concrete(RelayLocation::get()), 1);
|
||||
}
|
||||
|
||||
pub type Barrier = (TakeWeightCredit, AllowTopLevelPaidExecutionFrom<All<MultiLocation>>);
|
||||
@@ -170,7 +170,7 @@ impl xcm_executor::Config for XcmConfig {
|
||||
type LocationInverter = LocationInverter<Ancestry>;
|
||||
type Barrier = Barrier;
|
||||
type Weigher = FixedWeightBounds<BaseXcmWeight, Call>;
|
||||
type Trader = FixedRateOfConcreteFungible<CurrencyPerSecond, ()>;
|
||||
type Trader = FixedRateOfFungible<CurrencyPerSecond, ()>;
|
||||
type ResponseHandler = ();
|
||||
}
|
||||
|
||||
@@ -181,7 +181,7 @@ impl pallet_xcm::Config for Test {
|
||||
type SendXcmOrigin = xcm_builder::EnsureXcmOrigin<Origin, LocalOriginToLocation>;
|
||||
type XcmRouter = (TestSendXcmErrX8, TestSendXcm);
|
||||
type ExecuteXcmOrigin = xcm_builder::EnsureXcmOrigin<Origin, LocalOriginToLocation>;
|
||||
type XcmExecuteFilter = All<(MultiLocation, xcm::v0::Xcm<Call>)>;
|
||||
type XcmExecuteFilter = All<(MultiLocation, xcm::latest::Xcm<Call>)>;
|
||||
type XcmExecutor = XcmExecutor<XcmConfig>;
|
||||
type XcmTeleportFilter = All<(MultiLocation, Vec<MultiAsset>)>;
|
||||
type XcmReserveTransferFilter = All<(MultiLocation, Vec<MultiAsset>)>;
|
||||
@@ -195,9 +195,16 @@ pub(crate) fn last_event() -> Event {
|
||||
System::events().pop().expect("Event expected").event
|
||||
}
|
||||
|
||||
pub(crate) fn buy_execution<C>(debt: Weight, fees: MultiAsset) -> Order<C> {
|
||||
use xcm::opaque::v0::prelude::*;
|
||||
Order::BuyExecution { fees, weight: 0, debt, halt_on_error: false, xcm: vec![] }
|
||||
pub(crate) fn buy_execution<C>(fees: impl Into<MultiAsset>, debt: Weight) -> Order<C> {
|
||||
use xcm::opaque::latest::prelude::*;
|
||||
Order::BuyExecution {
|
||||
fees: fees.into(),
|
||||
weight: 0,
|
||||
debt,
|
||||
halt_on_error: false,
|
||||
orders: vec![],
|
||||
instructions: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn new_test_ext_with_balances(
|
||||
|
||||
@@ -18,8 +18,8 @@ use crate::mock::*;
|
||||
use frame_support::{assert_noop, assert_ok, traits::Currency};
|
||||
use polkadot_parachain::primitives::{AccountIdConversion, Id as ParaId};
|
||||
use xcm::{
|
||||
opaque::v0::prelude::*,
|
||||
v0::{Junction, Xcm},
|
||||
opaque::v1::prelude::*,
|
||||
v1::{Junction, Xcm},
|
||||
};
|
||||
|
||||
const ALICE: AccountId = AccountId::new([0u8; 32]);
|
||||
@@ -38,22 +38,19 @@ fn send_works() {
|
||||
new_test_ext_with_balances(balances).execute_with(|| {
|
||||
let weight = 2 * BaseXcmWeight::get();
|
||||
let sender: MultiLocation =
|
||||
Junction::AccountId32 { network: AnyNetwork::get(), id: ALICE.into() }.into();
|
||||
let message = Xcm::ReserveAssetDeposit {
|
||||
assets: vec![ConcreteFungible { id: Parent.into(), amount: SEND_AMOUNT }],
|
||||
AccountId32 { network: AnyNetwork::get(), id: ALICE.into() }.into();
|
||||
let message = Xcm::ReserveAssetDeposited {
|
||||
assets: (X1(Parent), SEND_AMOUNT).into(),
|
||||
effects: vec![
|
||||
buy_execution(
|
||||
weight,
|
||||
ConcreteFungible { id: MultiLocation::Null, amount: SEND_AMOUNT },
|
||||
),
|
||||
DepositAsset { assets: vec![All], dest: sender.clone() },
|
||||
buy_execution((Parent, SEND_AMOUNT), weight),
|
||||
DepositAsset { assets: All.into(), max_assets: 1, beneficiary: sender.clone() },
|
||||
],
|
||||
};
|
||||
assert_ok!(XcmPallet::send(Origin::signed(ALICE), RelayLocation::get(), message.clone()));
|
||||
assert_eq!(
|
||||
sent_xcm(),
|
||||
vec![(
|
||||
MultiLocation::Null,
|
||||
MultiLocation::Here,
|
||||
RelayedFrom { who: sender.clone(), message: Box::new(message.clone()) }
|
||||
)]
|
||||
);
|
||||
@@ -76,14 +73,11 @@ fn send_fails_when_xcm_router_blocks() {
|
||||
let weight = 2 * BaseXcmWeight::get();
|
||||
let sender: MultiLocation =
|
||||
Junction::AccountId32 { network: AnyNetwork::get(), id: ALICE.into() }.into();
|
||||
let message = Xcm::ReserveAssetDeposit {
|
||||
assets: vec![ConcreteFungible { id: Parent.into(), amount: SEND_AMOUNT }],
|
||||
let message = Xcm::ReserveAssetDeposited {
|
||||
assets: (Parent, SEND_AMOUNT).into(),
|
||||
effects: vec![
|
||||
buy_execution(
|
||||
weight,
|
||||
ConcreteFungible { id: MultiLocation::Null, amount: SEND_AMOUNT },
|
||||
),
|
||||
DepositAsset { assets: vec![All], dest: sender.clone() },
|
||||
buy_execution((Parent, SEND_AMOUNT), weight),
|
||||
DepositAsset { assets: All.into(), max_assets: 1, beneficiary: sender.clone() },
|
||||
],
|
||||
};
|
||||
assert_noop!(
|
||||
@@ -120,8 +114,9 @@ fn teleport_assets_works() {
|
||||
assert_ok!(XcmPallet::teleport_assets(
|
||||
Origin::signed(ALICE),
|
||||
RelayLocation::get(),
|
||||
MultiLocation::X1(Junction::AccountId32 { network: NetworkId::Any, id: BOB.into() }),
|
||||
vec![ConcreteFungible { id: MultiLocation::Null, amount: SEND_AMOUNT }],
|
||||
X1(AccountId32 { network: Any, id: BOB.into() }),
|
||||
(Here, SEND_AMOUNT).into(),
|
||||
0,
|
||||
weight,
|
||||
));
|
||||
assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE - SEND_AMOUNT);
|
||||
@@ -149,7 +144,8 @@ fn reserve_transfer_assets_works() {
|
||||
Origin::signed(ALICE),
|
||||
Parachain(PARA_ID).into(),
|
||||
dest.clone(),
|
||||
vec![ConcreteFungible { id: MultiLocation::Null, amount: SEND_AMOUNT }],
|
||||
(Here, SEND_AMOUNT).into(),
|
||||
0,
|
||||
weight
|
||||
));
|
||||
// Alice spent amount
|
||||
@@ -161,14 +157,11 @@ fn reserve_transfer_assets_works() {
|
||||
sent_xcm(),
|
||||
vec![(
|
||||
Parachain(PARA_ID).into(),
|
||||
Xcm::ReserveAssetDeposit {
|
||||
assets: vec![ConcreteFungible { id: Parent.into(), amount: SEND_AMOUNT }],
|
||||
Xcm::ReserveAssetDeposited {
|
||||
assets: (X1(Parent), SEND_AMOUNT).into(),
|
||||
effects: vec![
|
||||
buy_execution(
|
||||
weight,
|
||||
ConcreteFungible { id: Parent.into(), amount: SEND_AMOUNT }
|
||||
),
|
||||
DepositAsset { assets: vec![All], dest },
|
||||
buy_execution((Parent, SEND_AMOUNT), weight),
|
||||
DepositAsset { assets: All.into(), max_assets: 1, beneficiary: dest },
|
||||
]
|
||||
}
|
||||
)]
|
||||
@@ -196,13 +189,10 @@ fn execute_withdraw_to_deposit_works() {
|
||||
assert_ok!(XcmPallet::execute(
|
||||
Origin::signed(ALICE),
|
||||
Box::new(Xcm::WithdrawAsset {
|
||||
assets: vec![ConcreteFungible { id: MultiLocation::Null, amount: SEND_AMOUNT }],
|
||||
assets: (Here, SEND_AMOUNT).into(),
|
||||
effects: vec![
|
||||
buy_execution(
|
||||
weight,
|
||||
ConcreteFungible { id: MultiLocation::Null, amount: SEND_AMOUNT }
|
||||
),
|
||||
DepositAsset { assets: vec![All], dest },
|
||||
buy_execution((Here, SEND_AMOUNT), weight),
|
||||
DepositAsset { assets: All.into(), max_assets: 1, beneficiary: dest }
|
||||
],
|
||||
}),
|
||||
weight
|
||||
|
||||
Reference in New Issue
Block a user