diff --git a/Cargo.lock b/Cargo.lock index 800973b38c08..17d92e732d60 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5791,6 +5791,21 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-uniques" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#f6679ddd31f68e9f1578064d58a246130c27026b" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-utility" version = "4.0.0-dev" @@ -12634,7 +12649,9 @@ version = "0.9.17" dependencies = [ "frame-support", "frame-system", + "log", "pallet-balances", + "pallet-uniques", "pallet-xcm", "parity-scale-codec", "polkadot-core-primitives", @@ -12645,6 +12662,7 @@ dependencies = [ "sp-io", "sp-runtime", "sp-std", + "sp-tracing", "xcm", "xcm-builder", "xcm-executor", diff --git a/runtime/kusama/src/xcm_config.rs b/runtime/kusama/src/xcm_config.rs index aab416f7f33d..8adb87b804a6 100644 --- a/runtime/kusama/src/xcm_config.rs +++ b/runtime/kusama/src/xcm_config.rs @@ -21,7 +21,7 @@ use super::{ Origin, ParaId, Runtime, WeightToFee, XcmPallet, }; use frame_support::{ - match_type, parameter_types, + match_types, parameter_types, traits::{Everything, Nothing}, weights::Weight, }; @@ -114,7 +114,7 @@ parameter_types! { pub type TrustedTeleporters = (xcm_builder::Case, xcm_builder::Case); -match_type! { +match_types! { pub type OnlyParachains: impl Contains = { MultiLocation { parents: 0, interior: X1(Parachain(_)) } }; diff --git a/runtime/parachains/src/ump/benchmarking.rs b/runtime/parachains/src/ump/benchmarking.rs index 2c132324d44a..0d38e77b7b71 100644 --- a/runtime/parachains/src/ump/benchmarking.rs +++ b/runtime/parachains/src/ump/benchmarking.rs @@ -42,7 +42,7 @@ fn queue_upward_msg( fn create_message_min_size(size: u32) -> Vec { // Create a message with an empty remark call to determine the encoding overhead let msg_size_empty_transact = VersionedXcm::::from(Xcm::(vec![Transact { - origin_type: OriginKind::SovereignAccount, + origin_kind: OriginKind::SovereignAccount, require_weight_at_most: Weight::MAX, call: frame_system::Call::::remark_with_event { remark: vec![] }.encode().into(), }])) @@ -54,7 +54,7 @@ fn create_message_min_size(size: u32) -> Vec { let mut remark = Vec::new(); remark.resize(size, 0u8); let msg = VersionedXcm::::from(Xcm::(vec![Transact { - origin_type: OriginKind::SovereignAccount, + origin_kind: OriginKind::SovereignAccount, require_weight_at_most: Weight::MAX, call: frame_system::Call::::remark_with_event { remark }.encode().into(), }])) @@ -69,7 +69,7 @@ fn create_message_overweight() -> Vec { // We use a `set_code` Call because it let call = frame_system::Call::::set_code { code: vec![] }; VersionedXcm::::from(Xcm::(vec![Transact { - origin_type: OriginKind::Superuser, + origin_kind: OriginKind::Superuser, require_weight_at_most: max_block_weight, call: call.encode().into(), }])) diff --git a/runtime/polkadot/src/xcm_config.rs b/runtime/polkadot/src/xcm_config.rs index 7f67563bf319..d88596847983 100644 --- a/runtime/polkadot/src/xcm_config.rs +++ b/runtime/polkadot/src/xcm_config.rs @@ -21,7 +21,7 @@ use super::{ Origin, ParaId, Runtime, WeightToFee, XcmPallet, }; use frame_support::{ - match_type, parameter_types, + match_types, parameter_types, traits::{Everything, Nothing}, weights::Weight, }; @@ -108,7 +108,7 @@ parameter_types! { pub type TrustedTeleporters = (xcm_builder::Case,); -match_type! { +match_types! { pub type OnlyParachains: impl Contains = { MultiLocation { parents: 0, interior: X1(Parachain(_)) } }; diff --git a/runtime/westend/src/weights/xcm/mod.rs b/runtime/westend/src/weights/xcm/mod.rs index 77fba4396aaa..226328992e0f 100644 --- a/runtime/westend/src/weights/xcm/mod.rs +++ b/runtime/westend/src/weights/xcm/mod.rs @@ -98,7 +98,7 @@ impl XcmWeightInfo for WestendXcmWeight { assets.weigh_multi_assets(XcmBalancesWeight::::transfer_reserve_asset()) } fn transact( - _origin_type: &OriginKind, + _origin_kind: &OriginKind, _require_weight_at_most: &u64, _call: &DoubleEncoded, ) -> Weight { diff --git a/xcm/pallet-xcm-benchmarks/src/generic/benchmarking.rs b/xcm/pallet-xcm-benchmarks/src/generic/benchmarking.rs index adc2d98a1bb0..2d3b4fe6ff91 100644 --- a/xcm/pallet-xcm-benchmarks/src/generic/benchmarking.rs +++ b/xcm/pallet-xcm-benchmarks/src/generic/benchmarking.rs @@ -63,7 +63,7 @@ benchmarks! { let fee_asset = Concrete(Here.into()); let instruction = Instruction::>::BuyExecution { - fees: (fee_asset, 100_000_000).into(), // should be something inside of holding + fees: (fee_asset, 100_000_000u128).into(), // should be something inside of holding weight_limit: WeightLimit::Unlimited, }; diff --git a/xcm/pallet-xcm-benchmarks/src/mock.rs b/xcm/pallet-xcm-benchmarks/src/mock.rs index 85bbea99d775..e2940ff83c4e 100644 --- a/xcm/pallet-xcm-benchmarks/src/mock.rs +++ b/xcm/pallet-xcm-benchmarks/src/mock.rs @@ -15,8 +15,7 @@ // along with Polkadot. If not, see . use crate::*; -use frame_support::{parameter_types, weights::Weight}; -use xcm_executor::traits::FilterAssetLocation; +use frame_support::{parameter_types, traits::ContainsPair, weights::Weight}; // An xcm sender/receiver akin to > /dev/null pub struct DevNull; @@ -67,8 +66,8 @@ parameter_types! { } pub struct AllAssetLocationsPass; -impl FilterAssetLocation for AllAssetLocationsPass { - fn filter_asset_location(_: &MultiAsset, _: &MultiLocation) -> bool { +impl ContainsPair for AllAssetLocationsPass { + fn contains(_: &MultiAsset, _: &MultiLocation) -> bool { true } } diff --git a/xcm/pallet-xcm/src/lib.rs b/xcm/pallet-xcm/src/lib.rs index e7f8c82630a7..c31bcc7c7c07 100644 --- a/xcm/pallet-xcm/src/lib.rs +++ b/xcm/pallet-xcm/src/lib.rs @@ -25,7 +25,7 @@ mod tests; use codec::{Decode, Encode, EncodeLike}; use frame_support::traits::{ - Contains, Currency, Defensive, EnsureOrigin, Get, LockableCurrency, OriginTrait, + Contains, ContainsPair, Currency, Defensive, EnsureOrigin, Get, LockableCurrency, OriginTrait, }; use scale_info::TypeInfo; use sp_runtime::{ @@ -82,48 +82,6 @@ pub mod pallet { #[pallet::without_storage_info] pub struct Pallet(_); - /// A trait for querying whether a type can be said to "contain" a single pair-value. - pub trait ContainsPair { - /// Return `true` if this "contains" the pair-value `a, b`. - fn contains(a: &A, b: &B) -> bool; - } - - impl ContainsPair for frame_support::traits::Everything { - fn contains(_: &A, _: &B) -> bool { - true - } - } - - impl ContainsPair for frame_support::traits::Nothing { - fn contains(_: &A, _: &B) -> bool { - false - } - } - - #[impl_trait_for_tuples::impl_for_tuples(0, 30)] - impl ContainsPair for Tuple { - fn contains(a: &A, b: &B) -> bool { - for_tuples!( #( - if Tuple::contains(a, b) { return true } - )* ); - false - } - } - - /// Create a type which implements the `Contains` trait for a particular type with syntax similar - /// to `matches!`. - #[macro_export] - macro_rules! match_type { - ( pub type $n:ident: impl ContainsPair<$a:ty, $b:ty> = { $phead:pat_param $( | $ptail:pat )* } ; ) => { - pub struct $n; - impl $crate::traits::ContainsPair<$a, $b> for $n { - fn contains(a: &$a, b: &$b) -> bool { - matches!((a, b), $phead $( | $ptail )* ) - } - } - } - } - pub type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; @@ -1315,7 +1273,7 @@ impl Pallet { } else { None }; - log::trace!(target: "xcm::send_xcm", "dest: {:?}, message: {:?}", &dest, &message); + log::debug!(target: "xcm::send_xcm", "dest: {:?}, message: {:?}", &dest, &message); let (ticket, price) = validate_send::(dest, message)?; if let Some(fee_payer) = maybe_fee_payer { Self::charge_fees(fee_payer, price).map_err(|_| SendError::Fees)?; diff --git a/xcm/src/lib.rs b/xcm/src/lib.rs index e883f959b5b9..bef1fa7e29fe 100644 --- a/xcm/src/lib.rs +++ b/xcm/src/lib.rs @@ -561,5 +561,5 @@ pub trait GetWeight { #[test] fn conversion_works() { use latest::prelude::*; - let _: VersionedMultiAssets = (Here, 1).into(); + let _: VersionedMultiAssets = (Here, 1u128).into(); } diff --git a/xcm/src/v2/mod.rs b/xcm/src/v2/mod.rs index 4a787877fa95..813d0e95d15a 100644 --- a/xcm/src/v2/mod.rs +++ b/xcm/src/v2/mod.rs @@ -1026,10 +1026,12 @@ mod tests { #[test] fn basic_roundtrip_works() { - let xcm = - Xcm::<()>(vec![TransferAsset { assets: (Here, 1).into(), beneficiary: Here.into() }]); + let xcm = Xcm::<()>(vec![TransferAsset { + assets: (Here, 1u128).into(), + beneficiary: Here.into(), + }]); let old_xcm = - OldXcm::<()>::TransferAsset { assets: (Here, 1).into(), beneficiary: Here.into() }; + OldXcm::<()>::TransferAsset { assets: (Here, 1u128).into(), beneficiary: Here.into() }; assert_eq!(old_xcm, OldXcm::<()>::try_from(xcm.clone()).unwrap()); let new_xcm: Xcm<()> = old_xcm.try_into().unwrap(); assert_eq!(new_xcm, xcm); @@ -1038,12 +1040,12 @@ mod tests { #[test] fn teleport_roundtrip_works() { let xcm = Xcm::<()>(vec![ - ReceiveTeleportedAsset((Here, 1).into()), + ReceiveTeleportedAsset((Here, 1u128).into()), ClearOrigin, DepositAsset { assets: Wild(All), max_assets: 1, beneficiary: Here.into() }, ]); let old_xcm: OldXcm<()> = OldXcm::<()>::ReceiveTeleportedAsset { - assets: (Here, 1).into(), + assets: (Here, 1u128).into(), effects: vec![OldOrder::DepositAsset { assets: Wild(All), max_assets: 1, @@ -1058,16 +1060,16 @@ mod tests { #[test] fn reserve_deposit_roundtrip_works() { let xcm = Xcm::<()>(vec![ - ReserveAssetDeposited((Here, 1).into()), + ReserveAssetDeposited((Here, 1u128).into()), ClearOrigin, - BuyExecution { fees: (Here, 1).into(), weight_limit: Some(1).into() }, + BuyExecution { fees: (Here, 1u128).into(), weight_limit: Some(1).into() }, DepositAsset { assets: Wild(All), max_assets: 1, beneficiary: Here.into() }, ]); let old_xcm: OldXcm<()> = OldXcm::<()>::ReserveAssetDeposited { - assets: (Here, 1).into(), + assets: (Here, 1u128).into(), effects: vec![ OldOrder::BuyExecution { - fees: (Here, 1).into(), + fees: (Here, 1u128).into(), debt: 1, weight: 0, instructions: vec![], diff --git a/xcm/src/v3/junction.rs b/xcm/src/v3/junction.rs index 60fbff43f229..e778df963591 100644 --- a/xcm/src/v3/junction.rs +++ b/xcm/src/v3/junction.rs @@ -71,7 +71,9 @@ impl From for Option { } /// An identifier of a pluralistic body. -#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)] +#[derive( + Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, TypeInfo, MaxEncodedLen, +)] pub enum BodyId { /// The only body in its context. Unit, @@ -115,7 +117,9 @@ impl TryFrom for BodyId { } /// A part of a pluralistic body. -#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)] +#[derive( + Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, TypeInfo, MaxEncodedLen, +)] pub enum BodyPart { /// The body's declaration, under whatever means it decides. Voice, @@ -176,7 +180,9 @@ impl TryFrom for BodyPart { /// A single item in a path to describe the relative location of a consensus system. /// /// Each item assumes a pre-existing location as its context and is defined in terms of it. -#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)] +#[derive( + Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, TypeInfo, MaxEncodedLen, +)] pub enum Junction { /// An indexed parachain belonging to and operated by the context. /// diff --git a/xcm/src/v3/junctions.rs b/xcm/src/v3/junctions.rs index 88df3a0d3061..d958478ac50d 100644 --- a/xcm/src/v3/junctions.rs +++ b/xcm/src/v3/junctions.rs @@ -29,7 +29,9 @@ pub(crate) const MAX_JUNCTIONS: usize = 8; /// /// Parent junctions cannot be constructed with this type. Refer to `MultiLocation` for /// instructions on constructing parent junctions. -#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)] +#[derive( + Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, TypeInfo, MaxEncodedLen, +)] pub enum Junctions { /// The interpreting consensus system. Here, @@ -527,6 +529,10 @@ impl Junctions { } return self.at(prefix.len()) } + + pub fn starts_with(&self, prefix: &Junctions) -> bool { + prefix.len() <= self.len() && prefix.iter().zip(self.iter()).all(|(x, y)| x == y) + } } impl TryFrom for Junctions { diff --git a/xcm/src/v3/mod.rs b/xcm/src/v3/mod.rs index 5e522e32baba..1e92ea4d79a1 100644 --- a/xcm/src/v3/mod.rs +++ b/xcm/src/v3/mod.rs @@ -1220,8 +1220,10 @@ mod tests { #[test] fn basic_roundtrip_works() { - let xcm = - Xcm::<()>(vec![TransferAsset { assets: (Here, 1).into(), beneficiary: Here.into() }]); + let xcm = Xcm::<()>(vec![TransferAsset { + assets: (Here, 1u128).into(), + beneficiary: Here.into(), + }]); let old_xcm = OldXcm::<()>(vec![OldInstruction::TransferAsset { assets: (OldHere, 1).into(), beneficiary: OldHere.into(), @@ -1234,7 +1236,7 @@ mod tests { #[test] fn teleport_roundtrip_works() { let xcm = Xcm::<()>(vec![ - ReceiveTeleportedAsset((Here, 1).into()), + ReceiveTeleportedAsset((Here, 1u128).into()), ClearOrigin, DepositAsset { assets: Wild(AllCounted(1)), beneficiary: Here.into() }, ]); @@ -1255,9 +1257,9 @@ mod tests { #[test] fn reserve_deposit_roundtrip_works() { let xcm = Xcm::<()>(vec![ - ReserveAssetDeposited((Here, 1).into()), + ReserveAssetDeposited((Here, 1u128).into()), ClearOrigin, - BuyExecution { fees: (Here, 1).into(), weight_limit: Some(1).into() }, + BuyExecution { fees: (Here, 1u128).into(), weight_limit: Some(1).into() }, DepositAsset { assets: Wild(AllCounted(1)), beneficiary: Here.into() }, ]); let old_xcm = OldXcm::<()>(vec![ @@ -1281,7 +1283,7 @@ mod tests { #[test] fn deposit_asset_roundtrip_works() { let xcm = Xcm::<()>(vec![ - WithdrawAsset((Here, 1).into()), + WithdrawAsset((Here, 1u128).into()), DepositAsset { assets: Wild(AllCounted(1)), beneficiary: Here.into() }, ]); let old_xcm = OldXcm::<()>(vec![ @@ -1300,7 +1302,7 @@ mod tests { #[test] fn deposit_reserve_asset_roundtrip_works() { let xcm = Xcm::<()>(vec![ - WithdrawAsset((Here, 1).into()), + WithdrawAsset((Here, 1u128).into()), DepositReserveAsset { assets: Wild(AllCounted(1)), dest: Here.into(), diff --git a/xcm/src/v3/multiasset.rs b/xcm/src/v3/multiasset.rs index 9762fd97c02a..c93ac0902789 100644 --- a/xcm/src/v3/multiasset.rs +++ b/xcm/src/v3/multiasset.rs @@ -39,7 +39,9 @@ use parity_scale_codec::{self as codec, Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; /// A general identifier for an instance of a non-fungible asset class. -#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)] +#[derive( + Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, TypeInfo, MaxEncodedLen, +)] pub enum AssetInstance { /// Undefined - used if the non-fungible asset class has only one instance. Undefined, @@ -107,6 +109,130 @@ impl From<[u8; 32]> for AssetInstance { } } +impl From for AssetInstance { + fn from(x: u8) -> Self { + Self::Index(x as u128) + } +} + +impl From for AssetInstance { + fn from(x: u16) -> Self { + Self::Index(x as u128) + } +} + +impl From for AssetInstance { + fn from(x: u32) -> Self { + Self::Index(x as u128) + } +} + +impl From for AssetInstance { + fn from(x: u64) -> Self { + Self::Index(x as u128) + } +} + +impl TryFrom for () { + type Error = (); + fn try_from(x: AssetInstance) -> Result { + match x { + AssetInstance::Undefined => Ok(()), + _ => Err(()), + } + } +} + +impl TryFrom for [u8; 4] { + type Error = (); + fn try_from(x: AssetInstance) -> Result { + match x { + AssetInstance::Array4(x) => Ok(x), + _ => Err(()), + } + } +} + +impl TryFrom for [u8; 8] { + type Error = (); + fn try_from(x: AssetInstance) -> Result { + match x { + AssetInstance::Array8(x) => Ok(x), + _ => Err(()), + } + } +} + +impl TryFrom for [u8; 16] { + type Error = (); + fn try_from(x: AssetInstance) -> Result { + match x { + AssetInstance::Array16(x) => Ok(x), + _ => Err(()), + } + } +} + +impl TryFrom for [u8; 32] { + type Error = (); + fn try_from(x: AssetInstance) -> Result { + match x { + AssetInstance::Array32(x) => Ok(x), + _ => Err(()), + } + } +} + +impl TryFrom for u8 { + type Error = (); + fn try_from(x: AssetInstance) -> Result { + match x { + AssetInstance::Index(x) => x.try_into().map_err(|_| ()), + _ => Err(()), + } + } +} + +impl TryFrom for u16 { + type Error = (); + fn try_from(x: AssetInstance) -> Result { + match x { + AssetInstance::Index(x) => x.try_into().map_err(|_| ()), + _ => Err(()), + } + } +} + +impl TryFrom for u32 { + type Error = (); + fn try_from(x: AssetInstance) -> Result { + match x { + AssetInstance::Index(x) => x.try_into().map_err(|_| ()), + _ => Err(()), + } + } +} + +impl TryFrom for u64 { + type Error = (); + fn try_from(x: AssetInstance) -> Result { + match x { + AssetInstance::Index(x) => x.try_into().map_err(|_| ()), + _ => Err(()), + } + } +} + +impl TryFrom for u128 { + type Error = (); + fn try_from(x: AssetInstance) -> Result { + match x { + AssetInstance::Index(x) => Ok(x), + _ => Err(()), + } + } +} + /// Classification of whether an asset is fungible or not, along with a mandatory amount or instance. #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, Decode, TypeInfo, MaxEncodedLen)] pub enum Fungibility { @@ -122,6 +248,13 @@ impl Fungibility { } } +impl From for Fungibility { + fn from(amount: i32) -> Fungibility { + debug_assert_ne!(amount, 0); + Fungibility::Fungible(amount as u128) + } +} + impl From for Fungibility { fn from(amount: u128) -> Fungibility { debug_assert_ne!(amount, 0); @@ -167,7 +300,9 @@ impl TryFrom for WildFungibility { } /// Classification of an asset being concrete or abstract. -#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, Decode, TypeInfo, MaxEncodedLen)] +#[derive( + Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, Decode, TypeInfo, MaxEncodedLen, +)] pub enum AssetId { Concrete(MultiLocation), Abstract([u8; 32]), @@ -703,5 +838,5 @@ impl TryFrom<(OldMultiAssetFilter, u32)> for MultiAssetFilter { fn conversion_works() { use super::prelude::*; - let _: MultiAssets = (Here, 1).into(); + let _: MultiAssets = (Here, 1u128).into(); } diff --git a/xcm/src/v3/multilocation.rs b/xcm/src/v3/multilocation.rs index 6cd684afa147..f5d9256aacc3 100644 --- a/xcm/src/v3/multilocation.rs +++ b/xcm/src/v3/multilocation.rs @@ -51,7 +51,9 @@ use scale_info::TypeInfo; /// that a value is strictly an interior location, in those cases, `Junctions` may be used. /// /// The `MultiLocation` value of `Null` simply refers to the interpreting consensus system. -#[derive(Clone, Decode, Encode, Eq, PartialEq, Ord, PartialOrd, Debug, TypeInfo, MaxEncodedLen)] +#[derive( + Copy, Clone, Decode, Encode, Eq, PartialEq, Ord, PartialOrd, Debug, TypeInfo, MaxEncodedLen, +)] pub struct MultiLocation { /// The number of parent junctions at the beginning of this `MultiLocation`. pub parents: u8, @@ -268,6 +270,10 @@ impl MultiLocation { self.interior.match_and_split(&prefix.interior) } + pub fn starts_with(&self, prefix: &MultiLocation) -> bool { + self.parents == prefix.parents && self.interior.starts_with(&prefix.interior) + } + /// Mutate `self` so that it is suffixed with `suffix`. /// /// Does not modify `self` and returns `Err` with `suffix` in case of overflow. diff --git a/xcm/xcm-builder/src/asset_conversion.rs b/xcm/xcm-builder/src/asset_conversion.rs new file mode 100644 index 000000000000..1a13f1ffb444 --- /dev/null +++ b/xcm/xcm-builder/src/asset_conversion.rs @@ -0,0 +1,149 @@ +// Copyright 2022 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot 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. + +// Polkadot 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 Polkadot. If not, see . + +//! Adapters to work with `frame_support::traits::tokens::fungibles` through XCM. + +use frame_support::traits::Get; +use sp_std::{borrow::Borrow, marker::PhantomData, prelude::*, result}; +use xcm::latest::prelude::*; +use xcm_executor::traits::{Convert, Error as MatchError, MatchesFungibles, MatchesNonFungibles}; + +/// Converter struct implementing `AssetIdConversion` converting a numeric asset ID (must be `TryFrom/TryInto`) into +/// a `GeneralIndex` junction, prefixed by some `MultiLocation` value. The `MultiLocation` value will typically be a +/// `PalletInstance` junction. +pub struct AsPrefixedGeneralIndex( + PhantomData<(Prefix, AssetId, ConvertAssetId)>, +); +impl, AssetId: Clone, ConvertAssetId: Convert> + Convert for AsPrefixedGeneralIndex +{ + fn convert_ref(id: impl Borrow) -> result::Result { + let prefix = Prefix::get(); + let id = id.borrow(); + if prefix.parent_count() != id.parent_count() || + prefix + .interior() + .iter() + .enumerate() + .any(|(index, junction)| id.interior().at(index) != Some(junction)) + { + return Err(()) + } + match id.interior().at(prefix.interior().len()) { + Some(Junction::GeneralIndex(id)) => ConvertAssetId::convert_ref(id), + _ => Err(()), + } + } + fn reverse_ref(what: impl Borrow) -> result::Result { + let mut location = Prefix::get(); + let id = ConvertAssetId::reverse_ref(what)?; + location.push_interior(Junction::GeneralIndex(id)).map_err(|_| ())?; + Ok(location) + } +} + +pub struct ConvertedConcreteId( + PhantomData<(AssetId, Balance, ConvertAssetId, ConvertOther)>, +); +impl< + AssetId: Clone, + Balance: Clone, + ConvertAssetId: Convert, + ConvertBalance: Convert, + > MatchesFungibles + for ConvertedConcreteId +{ + fn matches_fungibles(a: &MultiAsset) -> result::Result<(AssetId, Balance), MatchError> { + let (amount, id) = match (&a.fun, &a.id) { + (Fungible(ref amount), Concrete(ref id)) => (amount, id), + _ => return Err(MatchError::AssetNotFound), + }; + let what = + ConvertAssetId::convert_ref(id).map_err(|_| MatchError::AssetIdConversionFailed)?; + let amount = ConvertBalance::convert_ref(amount) + .map_err(|_| MatchError::AmountToBalanceConversionFailed)?; + Ok((what, amount)) + } +} +impl< + ClassId: Clone, + InstanceId: Clone, + ConvertClassId: Convert, + ConvertInstanceId: Convert, + > MatchesNonFungibles + for ConvertedConcreteId +{ + fn matches_nonfungibles(a: &MultiAsset) -> result::Result<(ClassId, InstanceId), MatchError> { + let (instance, class) = match (&a.fun, &a.id) { + (NonFungible(ref instance), Concrete(ref class)) => (instance, class), + _ => return Err(MatchError::AssetNotFound), + }; + let what = + ConvertClassId::convert_ref(class).map_err(|_| MatchError::AssetIdConversionFailed)?; + let instance = ConvertInstanceId::convert_ref(instance) + .map_err(|_| MatchError::InstanceConversionFailed)?; + Ok((what, instance)) + } +} + +pub struct ConvertedAbstractId( + PhantomData<(AssetId, Balance, ConvertAssetId, ConvertOther)>, +); +impl< + AssetId: Clone, + Balance: Clone, + ConvertAssetId: Convert<[u8; 32], AssetId>, + ConvertBalance: Convert, + > MatchesFungibles + for ConvertedAbstractId +{ + fn matches_fungibles(a: &MultiAsset) -> result::Result<(AssetId, Balance), MatchError> { + let (amount, id) = match (&a.fun, &a.id) { + (Fungible(ref amount), Abstract(ref id)) => (amount, id), + _ => return Err(MatchError::AssetNotFound), + }; + let what = + ConvertAssetId::convert_ref(id).map_err(|_| MatchError::AssetIdConversionFailed)?; + let amount = ConvertBalance::convert_ref(amount) + .map_err(|_| MatchError::AmountToBalanceConversionFailed)?; + Ok((what, amount)) + } +} +impl< + ClassId: Clone, + InstanceId: Clone, + ConvertClassId: Convert<[u8; 32], ClassId>, + ConvertInstanceId: Convert, + > MatchesNonFungibles + for ConvertedAbstractId +{ + fn matches_nonfungibles(a: &MultiAsset) -> result::Result<(ClassId, InstanceId), MatchError> { + let (instance, class) = match (&a.fun, &a.id) { + (NonFungible(ref instance), Abstract(ref class)) => (instance, class), + _ => return Err(MatchError::AssetNotFound), + }; + let what = + ConvertClassId::convert_ref(class).map_err(|_| MatchError::AssetIdConversionFailed)?; + let instance = ConvertInstanceId::convert_ref(instance) + .map_err(|_| MatchError::InstanceConversionFailed)?; + Ok((what, instance)) + } +} + +#[deprecated = "Use `ConvertedConcreteId` instead"] +pub type ConvertedConcreteAssetId = ConvertedConcreteId; +#[deprecated = "Use `ConvertedAbstractId` instead"] +pub type ConvertedAbstractAssetId = ConvertedAbstractId; diff --git a/xcm/xcm-builder/src/filter_asset_location.rs b/xcm/xcm-builder/src/filter_asset_location.rs index cb404a4dbce9..1701988d624b 100644 --- a/xcm/xcm-builder/src/filter_asset_location.rs +++ b/xcm/xcm-builder/src/filter_asset_location.rs @@ -14,27 +14,28 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -//! Various implementations of `FilterAssetLocation`. +//! Various implementations of `ContainsPair`. -use frame_support::traits::Get; +use frame_support::traits::{ContainsPair, Get}; use sp_std::marker::PhantomData; use xcm::latest::{AssetId::Concrete, MultiAsset, MultiAssetFilter, MultiLocation}; -use xcm_executor::traits::FilterAssetLocation; /// Accepts an asset iff it is a native asset. pub struct NativeAsset; -impl FilterAssetLocation for NativeAsset { - fn filter_asset_location(asset: &MultiAsset, origin: &MultiLocation) -> bool { - log::trace!(target: "xcm::filter_asset_location", "NativeAsset asset: {:?}, origin: {:?}", asset, origin); +impl ContainsPair for NativeAsset { + fn contains(asset: &MultiAsset, origin: &MultiLocation) -> bool { + log::trace!(target: "xcm::contains", "NativeAsset asset: {:?}, origin: {:?}", asset, origin); matches!(asset.id, Concrete(ref id) if id == origin) } } /// Accepts an asset if it is contained in the given `T`'s `Get` implementation. pub struct Case(PhantomData); -impl> FilterAssetLocation for Case { - fn filter_asset_location(asset: &MultiAsset, origin: &MultiLocation) -> bool { - log::trace!(target: "xcm::filter_asset_location", "Case asset: {:?}, origin: {:?}", asset, origin); +impl> ContainsPair + for Case +{ + fn contains(asset: &MultiAsset, origin: &MultiLocation) -> bool { + log::trace!(target: "xcm::contains", "Case asset: {:?}, origin: {:?}", asset, origin); let (a, o) = T::get(); a.matches(asset) && &o == origin } diff --git a/xcm/xcm-builder/src/fungibles_adapter.rs b/xcm/xcm-builder/src/fungibles_adapter.rs index cb7abd048d0d..c5e17bbdc2c2 100644 --- a/xcm/xcm-builder/src/fungibles_adapter.rs +++ b/xcm/xcm-builder/src/fungibles_adapter.rs @@ -17,97 +17,10 @@ //! Adapters to work with `frame_support::traits::tokens::fungibles` through XCM. use frame_support::traits::{tokens::fungibles, Contains, Get}; -use sp_std::{borrow::Borrow, marker::PhantomData, prelude::*, result}; -use xcm::latest::{ - AssetId::{Abstract, Concrete}, - Error as XcmError, - Fungibility::Fungible, - Junction, MultiAsset, MultiLocation, Result, -}; +use sp_std::{marker::PhantomData, prelude::*, result}; +use xcm::latest::prelude::*; use xcm_executor::traits::{Convert, Error as MatchError, MatchesFungibles, TransactAsset}; -/// Converter struct implementing `AssetIdConversion` converting a numeric asset ID (must be `TryFrom/TryInto`) into -/// a `GeneralIndex` junction, prefixed by some `MultiLocation` value. The `MultiLocation` value will typically be a -/// `PalletInstance` junction. -pub struct AsPrefixedGeneralIndex( - PhantomData<(Prefix, AssetId, ConvertAssetId)>, -); -impl, AssetId: Clone, ConvertAssetId: Convert> - Convert for AsPrefixedGeneralIndex -{ - fn convert_ref(id: impl Borrow) -> result::Result { - let prefix = Prefix::get(); - let id = id.borrow(); - if prefix.parent_count() != id.parent_count() || - prefix - .interior() - .iter() - .enumerate() - .any(|(index, junction)| id.interior().at(index) != Some(junction)) - { - return Err(()) - } - match id.interior().at(prefix.interior().len()) { - Some(Junction::GeneralIndex(id)) => ConvertAssetId::convert_ref(id), - _ => Err(()), - } - } - fn reverse_ref(what: impl Borrow) -> result::Result { - let mut location = Prefix::get(); - let id = ConvertAssetId::reverse_ref(what)?; - location.push_interior(Junction::GeneralIndex(id)).map_err(|_| ())?; - Ok(location) - } -} - -pub struct ConvertedConcreteAssetId( - PhantomData<(AssetId, Balance, ConvertAssetId, ConvertBalance)>, -); -impl< - AssetId: Clone, - Balance: Clone, - ConvertAssetId: Convert, - ConvertBalance: Convert, - > MatchesFungibles - for ConvertedConcreteAssetId -{ - fn matches_fungibles(a: &MultiAsset) -> result::Result<(AssetId, Balance), MatchError> { - let (amount, id) = match (&a.fun, &a.id) { - (Fungible(ref amount), Concrete(ref id)) => (amount, id), - _ => return Err(MatchError::AssetNotFound), - }; - let what = - ConvertAssetId::convert_ref(id).map_err(|_| MatchError::AssetIdConversionFailed)?; - let amount = ConvertBalance::convert_ref(amount) - .map_err(|_| MatchError::AmountToBalanceConversionFailed)?; - Ok((what, amount)) - } -} - -pub struct ConvertedAbstractAssetId( - PhantomData<(AssetId, Balance, ConvertAssetId, ConvertBalance)>, -); -impl< - AssetId: Clone, - Balance: Clone, - ConvertAssetId: Convert<[u8; 32], AssetId>, - ConvertBalance: Convert, - > MatchesFungibles - for ConvertedAbstractAssetId -{ - fn matches_fungibles(a: &MultiAsset) -> result::Result<(AssetId, Balance), MatchError> { - let (amount, id) = match (&a.fun, &a.id) { - (Fungible(ref amount), Abstract(ref id)) => (amount, id), - _ => return Err(MatchError::AssetNotFound), - }; - let what = - ConvertAssetId::convert_ref(id).map_err(|_| MatchError::AssetIdConversionFailed)?; - let amount = ConvertBalance::convert_ref(amount) - .map_err(|_| MatchError::AmountToBalanceConversionFailed)?; - Ok((what, amount)) - } -} - pub struct FungiblesTransferAdapter( PhantomData<(Assets, Matcher, AccountIdConverter, AccountId)>, ); @@ -165,7 +78,7 @@ impl< CheckingAccount, > { - fn can_check_in(_origin: &MultiLocation, what: &MultiAsset) -> Result { + fn can_check_in(_origin: &MultiLocation, what: &MultiAsset) -> XcmResult { log::trace!( target: "xcm::fungibles_adapter", "can_check_in origin: {:?}, what: {:?}", @@ -216,7 +129,7 @@ impl< } } - fn deposit_asset(what: &MultiAsset, who: &MultiLocation) -> Result { + fn deposit_asset(what: &MultiAsset, who: &MultiLocation) -> XcmResult { log::trace!( target: "xcm::fungibles_adapter", "deposit_asset what: {:?}, who: {:?}", @@ -267,7 +180,7 @@ impl< > TransactAsset for FungiblesAdapter { - fn can_check_in(origin: &MultiLocation, what: &MultiAsset) -> Result { + fn can_check_in(origin: &MultiLocation, what: &MultiAsset) -> XcmResult { FungiblesMutateAdapter::< Assets, Matcher, @@ -300,7 +213,7 @@ impl< >::check_out(dest, what) } - fn deposit_asset(what: &MultiAsset, who: &MultiLocation) -> Result { + fn deposit_asset(what: &MultiAsset, who: &MultiLocation) -> XcmResult { FungiblesMutateAdapter::< Assets, Matcher, diff --git a/xcm/xcm-builder/src/lib.rs b/xcm/xcm-builder/src/lib.rs index 1cde398c7713..e69dfbfbc6af 100644 --- a/xcm/xcm-builder/src/lib.rs +++ b/xcm/xcm-builder/src/lib.rs @@ -40,6 +40,11 @@ pub use origin_conversion::{ SignedToAccountId32, SovereignSignedViaLocation, }; +mod asset_conversion; +pub use asset_conversion::{AsPrefixedGeneralIndex, ConvertedAbstractId, ConvertedConcreteId}; +#[allow(deprecated)] +pub use asset_conversion::{ConvertedAbstractAssetId, ConvertedConcreteAssetId}; + mod barriers; pub use barriers::{ AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, @@ -50,9 +55,11 @@ mod currency_adapter; pub use currency_adapter::CurrencyAdapter; mod fungibles_adapter; -pub use fungibles_adapter::{ - AsPrefixedGeneralIndex, ConvertedAbstractAssetId, ConvertedConcreteAssetId, FungiblesAdapter, - FungiblesMutateAdapter, FungiblesTransferAdapter, +pub use fungibles_adapter::{FungiblesAdapter, FungiblesMutateAdapter, FungiblesTransferAdapter}; + +mod nonfungibles_adapter; +pub use nonfungibles_adapter::{ + NonFungiblesAdapter, NonFungiblesMutateAdapter, NonFungiblesTransferAdapter, }; mod weight; @@ -60,8 +67,8 @@ pub use weight::{ FixedRateOfFungible, FixedWeightBounds, TakeRevenue, UsingComponents, WeightInfoBounds, }; -mod matches_fungible; -pub use matches_fungible::{IsAbstract, IsConcrete}; +mod matches_token; +pub use matches_token::{IsAbstract, IsConcrete}; mod filter_asset_location; pub use filter_asset_location::{Case, NativeAsset}; diff --git a/xcm/xcm-builder/src/matches_fungible.rs b/xcm/xcm-builder/src/matches_token.rs similarity index 67% rename from xcm/xcm-builder/src/matches_fungible.rs rename to xcm/xcm-builder/src/matches_token.rs index d1ba33f6146e..aa0454fea8f0 100644 --- a/xcm/xcm-builder/src/matches_fungible.rs +++ b/xcm/xcm-builder/src/matches_token.rs @@ -17,14 +17,17 @@ //! Various implementations for the `MatchesFungible` trait. use frame_support::traits::Get; -use sp_runtime::traits::CheckedConversion; -use sp_std::{convert::TryFrom, marker::PhantomData}; +use sp_std::{ + convert::{TryFrom, TryInto}, + marker::PhantomData, +}; use xcm::latest::{ AssetId::{Abstract, Concrete}, - Fungibility::Fungible, + AssetInstance, + Fungibility::{Fungible, NonFungible}, MultiAsset, MultiLocation, }; -use xcm_executor::traits::MatchesFungible; +use xcm_executor::traits::{MatchesFungible, MatchesNonFungible}; /// Converts a `MultiAsset` into balance `B` if it is a concrete fungible with an id equal to that /// given by `T`'s `Get`. @@ -51,7 +54,16 @@ impl, B: TryFrom> MatchesFungible for IsConcrete< fn matches_fungible(a: &MultiAsset) -> Option { match (&a.id, &a.fun) { (Concrete(ref id), Fungible(ref amount)) if id == &T::get() => - CheckedConversion::checked_from(*amount), + (*amount).try_into().ok(), + _ => None, + } + } +} +impl, I: TryFrom> MatchesNonFungible for IsConcrete { + fn matches_nonfungible(a: &MultiAsset) -> Option { + match (&a.id, &a.fun) { + (Concrete(ref id), NonFungible(ref instance)) if id == &T::get() => + instance.clone().try_into().ok(), _ => None, } } @@ -64,16 +76,21 @@ impl, B: TryFrom> MatchesFungible for IsConcrete< /// ``` /// use xcm::latest::prelude::*; /// use xcm_builder::IsAbstract; -/// use xcm_executor::traits::MatchesFungible; +/// use xcm_executor::traits::{MatchesFungible, MatchesNonFungible}; /// /// frame_support::parameter_types! { /// pub TargetLocation: [u8; 32] = [7u8; 32]; /// } /// /// # fn main() { -/// let asset = ([7u8; 32], 999).into(); -/// // match `asset` if it is a concrete asset in `TargetLocation`. +/// let asset = ([7u8; 32], 999u128).into(); +/// // match `asset` if it is an abstract asset in `TargetLocation`. /// assert_eq!( as MatchesFungible>::matches_fungible(&asset), Some(999)); +/// let nft = ([7u8; 32], [42u8; 4]).into(); +/// assert_eq!( +/// as MatchesNonFungible<[u8; 4]>>::matches_nonfungible(&nft), +/// Some([42u8; 4]) +/// ); /// # } /// ``` pub struct IsAbstract(PhantomData); @@ -81,7 +98,16 @@ impl, B: TryFrom> MatchesFungible for IsAbstract { fn matches_fungible(a: &MultiAsset) -> Option { match (&a.id, &a.fun) { (Abstract(ref id), Fungible(ref amount)) if id == &T::get() => - CheckedConversion::checked_from(*amount), + (*amount).try_into().ok(), + _ => None, + } + } +} +impl, B: TryFrom> MatchesNonFungible for IsAbstract { + fn matches_nonfungible(a: &MultiAsset) -> Option { + match (&a.id, &a.fun) { + (Abstract(ref id), NonFungible(ref instance)) if id == &T::get() => + instance.clone().try_into().ok(), _ => None, } } diff --git a/xcm/xcm-builder/src/nonfungibles_adapter.rs b/xcm/xcm-builder/src/nonfungibles_adapter.rs new file mode 100644 index 000000000000..14a749022be0 --- /dev/null +++ b/xcm/xcm-builder/src/nonfungibles_adapter.rs @@ -0,0 +1,252 @@ +// Copyright 2022 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot 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. + +// Polkadot 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 Polkadot. If not, see . + +//! Adapters to work with `frame_support::traits::tokens::fungibles` through XCM. + +use frame_support::{ + ensure, + traits::{tokens::nonfungibles, Contains, Get}, +}; +use sp_std::{marker::PhantomData, prelude::*, result}; +use xcm::latest::prelude::*; +use xcm_executor::traits::{Convert, Error as MatchError, MatchesNonFungibles, TransactAsset}; + +pub struct NonFungiblesTransferAdapter( + PhantomData<(Assets, Matcher, AccountIdConverter, AccountId)>, +); +impl< + Assets: nonfungibles::Transfer, + Matcher: MatchesNonFungibles, + AccountIdConverter: Convert, + AccountId: Clone, // can't get away without it since Currency is generic over it. + > TransactAsset for NonFungiblesTransferAdapter +{ + fn transfer_asset( + what: &MultiAsset, + from: &MultiLocation, + to: &MultiLocation, + ) -> result::Result { + log::trace!( + target: "xcm::non_fungibles_adapter", + "transfer_asset what: {:?}, from: {:?}, to: {:?}", + what, from, to + ); + // Check we handle this asset. + let (class, instance) = Matcher::matches_nonfungibles(what)?; + let destination = AccountIdConverter::convert_ref(to) + .map_err(|()| MatchError::AccountIdConversionFailed)?; + Assets::transfer(&class, &instance, &destination) + .map_err(|e| XcmError::FailedToTransactAsset(e.into()))?; + Ok(what.clone().into()) + } +} + +pub struct NonFungiblesMutateAdapter< + Assets, + Matcher, + AccountIdConverter, + AccountId, + CheckAsset, + CheckingAccount, +>(PhantomData<(Assets, Matcher, AccountIdConverter, AccountId, CheckAsset, CheckingAccount)>); +impl< + Assets: nonfungibles::Mutate, + Matcher: MatchesNonFungibles, + AccountIdConverter: Convert, + AccountId: Clone + Eq, // can't get away without it since Currency is generic over it. + CheckAsset: Contains, + CheckingAccount: Get>, + > TransactAsset + for NonFungiblesMutateAdapter< + Assets, + Matcher, + AccountIdConverter, + AccountId, + CheckAsset, + CheckingAccount, + > +{ + fn can_check_in(_origin: &MultiLocation, what: &MultiAsset) -> XcmResult { + log::trace!( + target: "xcm::fungibles_adapter", + "can_check_in origin: {:?}, what: {:?}", + _origin, what + ); + // Check we handle this asset. + let (class, instance) = Matcher::matches_nonfungibles(what)?; + if CheckAsset::contains(&class) { + if let Some(checking_account) = CheckingAccount::get() { + // This is an asset whose teleports we track. + let owner = Assets::owner(&class, &instance); + ensure!(owner == Some(checking_account), XcmError::NotWithdrawable); + ensure!(Assets::can_transfer(&class, &instance), XcmError::NotWithdrawable); + } + } + Ok(()) + } + + fn check_in(_origin: &MultiLocation, what: &MultiAsset) { + log::trace!( + target: "xcm::fungibles_adapter", + "check_in origin: {:?}, what: {:?}", + _origin, what + ); + if let Ok((class, instance)) = Matcher::matches_nonfungibles(what) { + if CheckAsset::contains(&class) { + let ok = Assets::burn(&class, &instance, None).is_ok(); + debug_assert!( + ok, + "`can_check_in` must have returned `true` immediately prior; qed" + ); + } + } + } + + fn check_out(_dest: &MultiLocation, what: &MultiAsset) { + log::trace!( + target: "xcm::fungibles_adapter", + "check_out dest: {:?}, what: {:?}", + _dest, what + ); + if let Ok((class, instance)) = Matcher::matches_nonfungibles(what) { + if CheckAsset::contains(&class) { + if let Some(checking_account) = CheckingAccount::get() { + let ok = Assets::mint_into(&class, &instance, &checking_account).is_ok(); + debug_assert!(ok, "`mint_into` cannot generally fail; qed"); + } + } + } + } + + fn deposit_asset(what: &MultiAsset, who: &MultiLocation) -> XcmResult { + log::trace!( + target: "xcm::fungibles_adapter", + "deposit_asset what: {:?}, who: {:?}", + what, who, + ); + // Check we handle this asset. + let (class, instance) = Matcher::matches_nonfungibles(what)?; + let who = AccountIdConverter::convert_ref(who) + .map_err(|()| MatchError::AccountIdConversionFailed)?; + Assets::mint_into(&class, &instance, &who) + .map_err(|e| XcmError::FailedToTransactAsset(e.into())) + } + + fn withdraw_asset( + what: &MultiAsset, + who: &MultiLocation, + ) -> result::Result { + log::trace!( + target: "xcm::fungibles_adapter", + "withdraw_asset what: {:?}, who: {:?}", + what, who, + ); + // Check we handle this asset. + let who = AccountIdConverter::convert_ref(who) + .map_err(|()| MatchError::AccountIdConversionFailed)?; + let (class, instance) = Matcher::matches_nonfungibles(what)?; + Assets::burn(&class, &instance, Some(&who)) + .map_err(|e| XcmError::FailedToTransactAsset(e.into()))?; + Ok(what.clone().into()) + } +} + +pub struct NonFungiblesAdapter< + Assets, + Matcher, + AccountIdConverter, + AccountId, + CheckAsset, + CheckingAccount, +>(PhantomData<(Assets, Matcher, AccountIdConverter, AccountId, CheckAsset, CheckingAccount)>); +impl< + Assets: nonfungibles::Mutate + nonfungibles::Transfer, + Matcher: MatchesNonFungibles, + AccountIdConverter: Convert, + AccountId: Clone + Eq, // can't get away without it since Currency is generic over it. + CheckAsset: Contains, + CheckingAccount: Get>, + > TransactAsset + for NonFungiblesAdapter +{ + fn can_check_in(origin: &MultiLocation, what: &MultiAsset) -> XcmResult { + NonFungiblesMutateAdapter::< + Assets, + Matcher, + AccountIdConverter, + AccountId, + CheckAsset, + CheckingAccount, + >::can_check_in(origin, what) + } + + fn check_in(origin: &MultiLocation, what: &MultiAsset) { + NonFungiblesMutateAdapter::< + Assets, + Matcher, + AccountIdConverter, + AccountId, + CheckAsset, + CheckingAccount, + >::check_in(origin, what) + } + + fn check_out(dest: &MultiLocation, what: &MultiAsset) { + NonFungiblesMutateAdapter::< + Assets, + Matcher, + AccountIdConverter, + AccountId, + CheckAsset, + CheckingAccount, + >::check_out(dest, what) + } + + fn deposit_asset(what: &MultiAsset, who: &MultiLocation) -> XcmResult { + NonFungiblesMutateAdapter::< + Assets, + Matcher, + AccountIdConverter, + AccountId, + CheckAsset, + CheckingAccount, + >::deposit_asset(what, who) + } + + fn withdraw_asset( + what: &MultiAsset, + who: &MultiLocation, + ) -> result::Result { + NonFungiblesMutateAdapter::< + Assets, + Matcher, + AccountIdConverter, + AccountId, + CheckAsset, + CheckingAccount, + >::withdraw_asset(what, who) + } + + fn transfer_asset( + what: &MultiAsset, + from: &MultiLocation, + to: &MultiLocation, + ) -> result::Result { + NonFungiblesTransferAdapter::::transfer_asset( + what, from, to, + ) + } +} diff --git a/xcm/xcm-builder/src/test_utils.rs b/xcm/xcm-builder/src/test_utils.rs index bdca8f02ff99..ceb41aa409ac 100644 --- a/xcm/xcm-builder/src/test_utils.rs +++ b/xcm/xcm-builder/src/test_utils.rs @@ -25,7 +25,7 @@ use sp_std::vec::Vec; pub use xcm::latest::prelude::*; use xcm_executor::traits::{ClaimAssets, DropAssets, VersionChangeNotifier}; pub use xcm_executor::{ - traits::{ConvertOrigin, FilterAssetLocation, OnResponse, TransactAsset, UniversalLocation}, + traits::{ConvertOrigin, OnResponse, TransactAsset, UniversalLocation}, Assets, Config, }; diff --git a/xcm/xcm-builder/src/tests/assets.rs b/xcm/xcm-builder/src/tests/assets.rs index e3d4c9ab75fe..afec771cb0a8 100644 --- a/xcm/xcm-builder/src/tests/assets.rs +++ b/xcm/xcm-builder/src/tests/assets.rs @@ -19,79 +19,79 @@ use super::*; #[test] fn exchange_asset_should_work() { AllowUnpaidFrom::set(vec![Parent.into()]); - add_asset(Parent, (Parent, 1000)); - set_exchange_assets(vec![(Here, 100).into()]); + add_asset(Parent, (Parent, 1000u128)); + set_exchange_assets(vec![(Here, 100u128).into()]); let r = XcmExecutor::::execute_xcm( Parent, Xcm(vec![ - WithdrawAsset((Parent, 100).into()), + WithdrawAsset((Parent, 100u128).into()), SetAppendix( vec![DepositAsset { assets: AllCounted(2).into(), beneficiary: Parent.into() }] .into(), ), ExchangeAsset { - give: Definite((Parent, 50).into()), - want: (Here, 50).into(), + give: Definite((Parent, 50u128).into()), + want: (Here, 50u128).into(), maximal: true, }, ]), 50, ); assert_eq!(r, Outcome::Complete(40)); - assert_eq!(asset_list(Parent), vec![(Here, 100).into(), (Parent, 950).into()]); - assert_eq!(exchange_assets(), vec![(Parent, 50).into()].into()); + assert_eq!(asset_list(Parent), vec![(Here, 100u128).into(), (Parent, 950u128).into()]); + assert_eq!(exchange_assets(), vec![(Parent, 50u128).into()].into()); } #[test] fn exchange_asset_without_maximal_should_work() { AllowUnpaidFrom::set(vec![Parent.into()]); add_asset(Parent, (Parent, 1000)); - set_exchange_assets(vec![(Here, 100).into()]); + set_exchange_assets(vec![(Here, 100u128).into()]); let r = XcmExecutor::::execute_xcm( Parent, Xcm(vec![ - WithdrawAsset((Parent, 100).into()), + WithdrawAsset((Parent, 100u128).into()), SetAppendix( vec![DepositAsset { assets: AllCounted(2).into(), beneficiary: Parent.into() }] .into(), ), ExchangeAsset { - give: Definite((Parent, 50).into()), - want: (Here, 50).into(), + give: Definite((Parent, 50u128).into()), + want: (Here, 50u128).into(), maximal: false, }, ]), 50, ); assert_eq!(r, Outcome::Complete(40)); - assert_eq!(asset_list(Parent), vec![(Here, 50).into(), (Parent, 950).into()]); - assert_eq!(exchange_assets(), vec![(Here, 50).into(), (Parent, 50).into()].into()); + assert_eq!(asset_list(Parent), vec![(Here, 50u128).into(), (Parent, 950u128).into()]); + assert_eq!(exchange_assets(), vec![(Here, 50u128).into(), (Parent, 50u128).into()].into()); } #[test] fn exchange_asset_should_fail_when_no_deal_possible() { AllowUnpaidFrom::set(vec![Parent.into()]); add_asset(Parent, (Parent, 1000)); - set_exchange_assets(vec![(Here, 100).into()]); + set_exchange_assets(vec![(Here, 100u128).into()]); let r = XcmExecutor::::execute_xcm( Parent, Xcm(vec![ - WithdrawAsset((Parent, 150).into()), + WithdrawAsset((Parent, 150u128).into()), SetAppendix( vec![DepositAsset { assets: AllCounted(2).into(), beneficiary: Parent.into() }] .into(), ), ExchangeAsset { - give: Definite((Parent, 150).into()), - want: (Here, 150).into(), + give: Definite((Parent, 150u128).into()), + want: (Here, 150u128).into(), maximal: false, }, ]), 50, ); assert_eq!(r, Outcome::Incomplete(40, XcmError::NoDeal)); - assert_eq!(asset_list(Parent), vec![(Parent, 1000).into()]); - assert_eq!(exchange_assets(), vec![(Here, 100).into()].into()); + assert_eq!(asset_list(Parent), vec![(Parent, 1000u128).into()]); + assert_eq!(exchange_assets(), vec![(Here, 100u128).into()].into()); } #[test] @@ -100,16 +100,16 @@ fn paying_reserve_deposit_should_work() { add_reserve(Parent.into(), (Parent, WildFungible).into()); WeightPrice::set((Parent.into(), 1_000_000_000_000)); - let fees = (Parent, 30).into(); + let fees = (Parent, 30u128).into(); let message = Xcm(vec![ - ReserveAssetDeposited((Parent, 100).into()), + ReserveAssetDeposited((Parent, 100u128).into()), BuyExecution { fees, weight_limit: Limited(30) }, DepositAsset { assets: AllCounted(1).into(), beneficiary: Here.into() }, ]); let weight_limit = 50; let r = XcmExecutor::::execute_xcm(Parent, message, weight_limit); assert_eq!(r, Outcome::Complete(30)); - assert_eq!(asset_list(Here), vec![(Parent, 70).into()]); + assert_eq!(asset_list(Here), vec![(Parent, 70u128).into()]); } #[test] @@ -122,14 +122,17 @@ fn transfer_should_work() { let r = XcmExecutor::::execute_xcm( Parachain(1), Xcm(vec![TransferAsset { - assets: (Here, 100).into(), + assets: (Here, 100u128).into(), beneficiary: X1(AccountIndex64 { index: 3, network: None }).into(), }]), 50, ); assert_eq!(r, Outcome::Complete(10)); - assert_eq!(asset_list(AccountIndex64 { index: 3, network: None }), vec![(Here, 100).into()]); - assert_eq!(asset_list(Parachain(1)), vec![(Here, 900).into()]); + assert_eq!( + asset_list(AccountIndex64 { index: 3, network: None }), + vec![(Here, 100u128).into()] + ); + assert_eq!(asset_list(Parachain(1)), vec![(Here, 900u128).into()]); assert_eq!(sent_xcm(), vec![]); } @@ -146,7 +149,7 @@ fn reserve_transfer_should_work() { let r = XcmExecutor::::execute_xcm( Parachain(1), Xcm(vec![TransferReserveAsset { - assets: (Here, 100).into(), + assets: (Here, 100u128).into(), dest: Parachain(2).into(), xcm: Xcm::<()>(vec![DepositAsset { assets: AllCounted(1).into(), @@ -157,13 +160,13 @@ fn reserve_transfer_should_work() { ); assert_eq!(r, Outcome::Complete(10)); - assert_eq!(asset_list(Parachain(2)), vec![(Here, 100).into()]); + assert_eq!(asset_list(Parachain(2)), vec![(Here, 100u128).into()]); assert_eq!( sent_xcm(), vec![( Parachain(2).into(), Xcm::<()>(vec![ - ReserveAssetDeposited((Parent, 100).into()), + ReserveAssetDeposited((Parent, 100u128).into()), ClearOrigin, DepositAsset { assets: AllCounted(1).into(), beneficiary: three }, ]), @@ -181,22 +184,22 @@ fn burn_should_work() { let r = XcmExecutor::::execute_xcm( Parachain(1), Xcm(vec![ - WithdrawAsset((Here, 1000).into()), - BurnAsset((Here, 100).into()), + WithdrawAsset((Here, 1000u128).into()), + BurnAsset((Here, 100u128).into()), DepositAsset { assets: Wild(AllCounted(1)), beneficiary: Parachain(1).into() }, ]), 50, ); assert_eq!(r, Outcome::Complete(30)); - assert_eq!(asset_list(Parachain(1)), vec![(Here, 900).into()]); + assert_eq!(asset_list(Parachain(1)), vec![(Here, 900u128).into()]); assert_eq!(sent_xcm(), vec![]); // Now they want to burn 1000 of them, which will actually only burn 900. let r = XcmExecutor::::execute_xcm( Parachain(1), Xcm(vec![ - WithdrawAsset((Here, 900).into()), - BurnAsset((Here, 1000).into()), + WithdrawAsset((Here, 900u128).into()), + BurnAsset((Here, 1000u128).into()), DepositAsset { assets: Wild(AllCounted(1)), beneficiary: Parachain(1).into() }, ]), 50, @@ -217,7 +220,7 @@ fn basic_asset_trap_should_work() { let r = XcmExecutor::::execute_xcm( Parachain(1), Xcm(vec![ - WithdrawAsset((Here, 100).into()), + WithdrawAsset((Here, 100u128).into()), DepositAsset { assets: Wild(AllCounted(0)), // <<< 0 is an error. beneficiary: AccountIndex64 { index: 3, network: None }.into(), @@ -226,7 +229,7 @@ fn basic_asset_trap_should_work() { 20, ); assert_eq!(r, Outcome::Complete(25)); - assert_eq!(asset_list(Parachain(1)), vec![(Here, 900).into()]); + assert_eq!(asset_list(Parachain(1)), vec![(Here, 900u128).into()]); assert_eq!(asset_list(AccountIndex64 { index: 3, network: None }), vec![]); // Incorrect ticket doesn't work. @@ -234,7 +237,7 @@ fn basic_asset_trap_should_work() { let r = XcmExecutor::::execute_xcm( Parachain(1), Xcm(vec![ - ClaimAsset { assets: (Here, 100).into(), ticket: GeneralIndex(1).into() }, + ClaimAsset { assets: (Here, 100u128).into(), ticket: GeneralIndex(1).into() }, DepositAsset { assets: Wild(AllCounted(1)), beneficiary: AccountIndex64 { index: 3, network: None }.into(), @@ -243,7 +246,7 @@ fn basic_asset_trap_should_work() { 20, ); assert_eq!(r, Outcome::Incomplete(10, XcmError::UnknownClaim)); - assert_eq!(asset_list(Parachain(1)), vec![(Here, 900).into()]); + assert_eq!(asset_list(Parachain(1)), vec![(Here, 900u128).into()]); assert_eq!(asset_list(AccountIndex64 { index: 3, network: None }), vec![]); assert_eq!(old_trapped_assets, TrappedAssets::get()); @@ -252,7 +255,7 @@ fn basic_asset_trap_should_work() { let r = XcmExecutor::::execute_xcm( Parachain(2), Xcm(vec![ - ClaimAsset { assets: (Here, 100).into(), ticket: GeneralIndex(0).into() }, + ClaimAsset { assets: (Here, 100u128).into(), ticket: GeneralIndex(0u128).into() }, DepositAsset { assets: Wild(AllCounted(1)), beneficiary: AccountIndex64 { index: 3, network: None }.into(), @@ -261,7 +264,7 @@ fn basic_asset_trap_should_work() { 20, ); assert_eq!(r, Outcome::Incomplete(10, XcmError::UnknownClaim)); - assert_eq!(asset_list(Parachain(1)), vec![(Here, 900).into()]); + assert_eq!(asset_list(Parachain(1)), vec![(Here, 900u128).into()]); assert_eq!(asset_list(AccountIndex64 { index: 3, network: None }), vec![]); assert_eq!(old_trapped_assets, TrappedAssets::get()); @@ -270,7 +273,7 @@ fn basic_asset_trap_should_work() { let r = XcmExecutor::::execute_xcm( Parachain(1), Xcm(vec![ - ClaimAsset { assets: (Here, 101).into(), ticket: GeneralIndex(0).into() }, + ClaimAsset { assets: (Here, 101u128).into(), ticket: GeneralIndex(0u128).into() }, DepositAsset { assets: Wild(AllCounted(1)), beneficiary: AccountIndex64 { index: 3, network: None }.into(), @@ -279,14 +282,14 @@ fn basic_asset_trap_should_work() { 20, ); assert_eq!(r, Outcome::Incomplete(10, XcmError::UnknownClaim)); - assert_eq!(asset_list(Parachain(1)), vec![(Here, 900).into()]); + assert_eq!(asset_list(Parachain(1)), vec![(Here, 900u128).into()]); assert_eq!(asset_list(AccountIndex64 { index: 3, network: None }), vec![]); assert_eq!(old_trapped_assets, TrappedAssets::get()); let r = XcmExecutor::::execute_xcm( Parachain(1), Xcm(vec![ - ClaimAsset { assets: (Here, 100).into(), ticket: GeneralIndex(0).into() }, + ClaimAsset { assets: (Here, 100u128).into(), ticket: GeneralIndex(0u128).into() }, DepositAsset { assets: Wild(AllCounted(1)), beneficiary: AccountIndex64 { index: 3, network: None }.into(), @@ -295,14 +298,17 @@ fn basic_asset_trap_should_work() { 20, ); assert_eq!(r, Outcome::Complete(20)); - assert_eq!(asset_list(Parachain(1)), vec![(Here, 900).into()]); - assert_eq!(asset_list(AccountIndex64 { index: 3, network: None }), vec![(Here, 100).into()]); + assert_eq!(asset_list(Parachain(1)), vec![(Here, 900u128).into()]); + assert_eq!( + asset_list(AccountIndex64 { index: 3, network: None }), + vec![(Here, 100u128).into()] + ); // Same again doesn't work :-) let r = XcmExecutor::::execute_xcm( Parachain(1), Xcm(vec![ - ClaimAsset { assets: (Here, 100).into(), ticket: GeneralIndex(0).into() }, + ClaimAsset { assets: (Here, 100u128).into(), ticket: GeneralIndex(0u128).into() }, DepositAsset { assets: Wild(AllCounted(1)), beneficiary: AccountIndex64 { index: 3, network: None }.into(), @@ -318,28 +324,28 @@ fn max_assets_limit_should_work() { // we'll let them have message execution for free. AllowUnpaidFrom::set(vec![X1(Parachain(1)).into()]); // Child parachain #1 owns 1000 tokens held by us in reserve. - add_asset(Parachain(1), ([1u8; 32], 1000)); - add_asset(Parachain(1), ([2u8; 32], 1000)); - add_asset(Parachain(1), ([3u8; 32], 1000)); - add_asset(Parachain(1), ([4u8; 32], 1000)); - add_asset(Parachain(1), ([5u8; 32], 1000)); - add_asset(Parachain(1), ([6u8; 32], 1000)); - add_asset(Parachain(1), ([7u8; 32], 1000)); - add_asset(Parachain(1), ([8u8; 32], 1000)); - add_asset(Parachain(1), ([9u8; 32], 1000)); + add_asset(Parachain(1), ([1u8; 32], 1000u128)); + add_asset(Parachain(1), ([2u8; 32], 1000u128)); + add_asset(Parachain(1), ([3u8; 32], 1000u128)); + add_asset(Parachain(1), ([4u8; 32], 1000u128)); + add_asset(Parachain(1), ([5u8; 32], 1000u128)); + add_asset(Parachain(1), ([6u8; 32], 1000u128)); + add_asset(Parachain(1), ([7u8; 32], 1000u128)); + add_asset(Parachain(1), ([8u8; 32], 1000u128)); + add_asset(Parachain(1), ([9u8; 32], 1000u128)); // Attempt to withdraw 8 (=2x4)different assets. This will succeed. let r = XcmExecutor::::execute_xcm( Parachain(1), Xcm(vec![ - WithdrawAsset(([1u8; 32], 100).into()), - WithdrawAsset(([2u8; 32], 100).into()), - WithdrawAsset(([3u8; 32], 100).into()), - WithdrawAsset(([4u8; 32], 100).into()), - WithdrawAsset(([5u8; 32], 100).into()), - WithdrawAsset(([6u8; 32], 100).into()), - WithdrawAsset(([7u8; 32], 100).into()), - WithdrawAsset(([8u8; 32], 100).into()), + WithdrawAsset(([1u8; 32], 100u128).into()), + WithdrawAsset(([2u8; 32], 100u128).into()), + WithdrawAsset(([3u8; 32], 100u128).into()), + WithdrawAsset(([4u8; 32], 100u128).into()), + WithdrawAsset(([5u8; 32], 100u128).into()), + WithdrawAsset(([6u8; 32], 100u128).into()), + WithdrawAsset(([7u8; 32], 100u128).into()), + WithdrawAsset(([8u8; 32], 100u128).into()), ]), 100, ); @@ -349,15 +355,15 @@ fn max_assets_limit_should_work() { let r = XcmExecutor::::execute_xcm( Parachain(1), Xcm(vec![ - WithdrawAsset(([1u8; 32], 100).into()), - WithdrawAsset(([2u8; 32], 100).into()), - WithdrawAsset(([3u8; 32], 100).into()), - WithdrawAsset(([4u8; 32], 100).into()), - WithdrawAsset(([5u8; 32], 100).into()), - WithdrawAsset(([6u8; 32], 100).into()), - WithdrawAsset(([7u8; 32], 100).into()), - WithdrawAsset(([8u8; 32], 100).into()), - WithdrawAsset(([9u8; 32], 100).into()), + WithdrawAsset(([1u8; 32], 100u128).into()), + WithdrawAsset(([2u8; 32], 100u128).into()), + WithdrawAsset(([3u8; 32], 100u128).into()), + WithdrawAsset(([4u8; 32], 100u128).into()), + WithdrawAsset(([5u8; 32], 100u128).into()), + WithdrawAsset(([6u8; 32], 100u128).into()), + WithdrawAsset(([7u8; 32], 100u128).into()), + WithdrawAsset(([8u8; 32], 100u128).into()), + WithdrawAsset(([9u8; 32], 100u128).into()), ]), 100, ); @@ -367,18 +373,18 @@ fn max_assets_limit_should_work() { let r = XcmExecutor::::execute_xcm( Parachain(1), Xcm(vec![ - WithdrawAsset(([1u8; 32], 100).into()), - WithdrawAsset(([2u8; 32], 100).into()), - WithdrawAsset(([3u8; 32], 100).into()), - WithdrawAsset(([4u8; 32], 100).into()), - WithdrawAsset(([1u8; 32], 100).into()), - WithdrawAsset(([2u8; 32], 100).into()), - WithdrawAsset(([3u8; 32], 100).into()), - WithdrawAsset(([4u8; 32], 100).into()), - WithdrawAsset(([5u8; 32], 100).into()), - WithdrawAsset(([6u8; 32], 100).into()), - WithdrawAsset(([7u8; 32], 100).into()), - WithdrawAsset(([8u8; 32], 100).into()), + WithdrawAsset(([1u8; 32], 100u128).into()), + WithdrawAsset(([2u8; 32], 100u128).into()), + WithdrawAsset(([3u8; 32], 100u128).into()), + WithdrawAsset(([4u8; 32], 100u128).into()), + WithdrawAsset(([1u8; 32], 100u128).into()), + WithdrawAsset(([2u8; 32], 100u128).into()), + WithdrawAsset(([3u8; 32], 100u128).into()), + WithdrawAsset(([4u8; 32], 100u128).into()), + WithdrawAsset(([5u8; 32], 100u128).into()), + WithdrawAsset(([6u8; 32], 100u128).into()), + WithdrawAsset(([7u8; 32], 100u128).into()), + WithdrawAsset(([8u8; 32], 100u128).into()), ]), 200, ); @@ -388,18 +394,18 @@ fn max_assets_limit_should_work() { let r = XcmExecutor::::execute_xcm( Parachain(1), Xcm(vec![ - WithdrawAsset(([1u8; 32], 100).into()), - WithdrawAsset(([2u8; 32], 100).into()), - WithdrawAsset(([3u8; 32], 100).into()), - WithdrawAsset(([4u8; 32], 100).into()), - WithdrawAsset(([5u8; 32], 100).into()), - WithdrawAsset(([6u8; 32], 100).into()), - WithdrawAsset(([7u8; 32], 100).into()), - WithdrawAsset(([8u8; 32], 100).into()), - WithdrawAsset(([1u8; 32], 100).into()), - WithdrawAsset(([2u8; 32], 100).into()), - WithdrawAsset(([3u8; 32], 100).into()), - WithdrawAsset(([4u8; 32], 100).into()), + WithdrawAsset(([1u8; 32], 100u128).into()), + WithdrawAsset(([2u8; 32], 100u128).into()), + WithdrawAsset(([3u8; 32], 100u128).into()), + WithdrawAsset(([4u8; 32], 100u128).into()), + WithdrawAsset(([5u8; 32], 100u128).into()), + WithdrawAsset(([6u8; 32], 100u128).into()), + WithdrawAsset(([7u8; 32], 100u128).into()), + WithdrawAsset(([8u8; 32], 100u128).into()), + WithdrawAsset(([1u8; 32], 100u128).into()), + WithdrawAsset(([2u8; 32], 100u128).into()), + WithdrawAsset(([3u8; 32], 100u128).into()), + WithdrawAsset(([4u8; 32], 100u128).into()), ]), 200, ); @@ -410,16 +416,16 @@ fn max_assets_limit_should_work() { Parachain(1), Xcm(vec![ WithdrawAsset(MultiAssets::from(vec![ - ([1u8; 32], 100).into(), - ([2u8; 32], 100).into(), - ([3u8; 32], 100).into(), - ([4u8; 32], 100).into(), - ([5u8; 32], 100).into(), - ([6u8; 32], 100).into(), - ([7u8; 32], 100).into(), - ([8u8; 32], 100).into(), + ([1u8; 32], 100u128).into(), + ([2u8; 32], 100u128).into(), + ([3u8; 32], 100u128).into(), + ([4u8; 32], 100u128).into(), + ([5u8; 32], 100u128).into(), + ([6u8; 32], 100u128).into(), + ([7u8; 32], 100u128).into(), + ([8u8; 32], 100u128).into(), ])), - WithdrawAsset(([1u8; 32], 100).into()), + WithdrawAsset(([1u8; 32], 100u128).into()), ]), 200, ); diff --git a/xcm/xcm-builder/src/tests/basic.rs b/xcm/xcm-builder/src/tests/basic.rs index 1b611d5b6168..383385a9baad 100644 --- a/xcm/xcm-builder/src/tests/basic.rs +++ b/xcm/xcm-builder/src/tests/basic.rs @@ -19,10 +19,9 @@ use super::*; #[test] fn basic_setup_works() { add_reserve(Parent.into(), Wild((Parent, WildFungible).into())); - assert!(::IsReserve::filter_asset_location( - &(Parent, 100).into(), - &Parent.into(), - )); + assert!( + ::IsReserve::contains(&(Parent, 100u128).into(), &Parent.into(),) + ); assert_eq!(to_account(Parachain(1)), Ok(1001)); assert_eq!(to_account(Parachain(50)), Ok(1050)); @@ -42,8 +41,8 @@ fn basic_setup_works() { #[test] fn weigher_should_work() { let mut message = Xcm(vec![ - ReserveAssetDeposited((Parent, 100).into()), - BuyExecution { fees: (Parent, 1).into(), weight_limit: Limited(30) }, + ReserveAssetDeposited((Parent, 100u128).into()), + BuyExecution { fees: (Parent, 1u128).into(), weight_limit: Limited(30) }, DepositAsset { assets: AllCounted(1).into(), beneficiary: Here.into() }, ]); assert_eq!(::Weigher::weight(&mut message), Ok(30)); @@ -54,12 +53,12 @@ fn code_registers_should_work() { // we'll let them have message execution for free. AllowUnpaidFrom::set(vec![Here.into()]); // We own 1000 of our tokens. - add_asset(Here, (Here, 21)); + add_asset(Here, (Here, 21u128)); let mut message = Xcm(vec![ // Set our error handler - this will fire only on the second message, when there's an error SetErrorHandler(Xcm(vec![ TransferAsset { - assets: (Here, 2).into(), + assets: (Here, 2u128).into(), beneficiary: X1(AccountIndex64 { index: 3, network: None }).into(), }, // It was handled fine. @@ -67,17 +66,17 @@ fn code_registers_should_work() { ])), // Set the appendix - this will always fire. SetAppendix(Xcm(vec![TransferAsset { - assets: (Here, 4).into(), + assets: (Here, 4u128).into(), beneficiary: X1(AccountIndex64 { index: 3, network: None }).into(), }])), // First xfer always works ok TransferAsset { - assets: (Here, 1).into(), + assets: (Here, 1u128).into(), beneficiary: X1(AccountIndex64 { index: 3, network: None }).into(), }, // Second xfer results in error on the second message - our error handler will fire. TransferAsset { - assets: (Here, 8).into(), + assets: (Here, 8u128).into(), beneficiary: X1(AccountIndex64 { index: 3, network: None }).into(), }, ]); @@ -87,13 +86,13 @@ fn code_registers_should_work() { let r = XcmExecutor::::execute_xcm(Here, message.clone(), limit); assert_eq!(r, Outcome::Complete(50)); // We don't pay the 20 weight for the error handler. - assert_eq!(asset_list(AccountIndex64 { index: 3, network: None }), vec![(Here, 13).into()]); - assert_eq!(asset_list(Here), vec![(Here, 8).into()]); + assert_eq!(asset_list(AccountIndex64 { index: 3, network: None }), vec![(Here, 13u128).into()]); + assert_eq!(asset_list(Here), vec![(Here, 8u128).into()]); assert_eq!(sent_xcm(), vec![]); let r = XcmExecutor::::execute_xcm(Here, message, limit); assert_eq!(r, Outcome::Complete(70)); // We pay the full weight here. - assert_eq!(asset_list(AccountIndex64 { index: 3, network: None }), vec![(Here, 20).into()]); - assert_eq!(asset_list(Here), vec![(Here, 1).into()]); + assert_eq!(asset_list(AccountIndex64 { index: 3, network: None }), vec![(Here, 20u128).into()]); + assert_eq!(asset_list(Here), vec![(Here, 1u128).into()]); assert_eq!(sent_xcm(), vec![]); } diff --git a/xcm/xcm-builder/src/tests/bridging/mod.rs b/xcm/xcm-builder/src/tests/bridging/mod.rs index 9bb5e13196c2..575cd7af7368 100644 --- a/xcm/xcm-builder/src/tests/bridging/mod.rs +++ b/xcm/xcm-builder/src/tests/bridging/mod.rs @@ -36,7 +36,7 @@ mod remote_relay_relay; parameter_types! { pub Local: NetworkId = ByGenesis([0; 32]); pub Remote: NetworkId = ByGenesis([1; 32]); - pub Price: MultiAssets = MultiAssets::from((Here, 100)); + pub Price: MultiAssets = MultiAssets::from((Here, 100u128)); } std::thread_local! { diff --git a/xcm/xcm-builder/src/tests/bridging/paid_remote_relay_relay.rs b/xcm/xcm-builder/src/tests/bridging/paid_remote_relay_relay.rs index 8336e03d1faa..f3b31582116c 100644 --- a/xcm/xcm-builder/src/tests/bridging/paid_remote_relay_relay.rs +++ b/xcm/xcm-builder/src/tests/bridging/paid_remote_relay_relay.rs @@ -28,7 +28,7 @@ parameter_types! { pub RelayUniversalLocation: Junctions = X1(GlobalConsensus(Local::get())); pub RemoteUniversalLocation: Junctions = X1(GlobalConsensus(Remote::get())); pub static BridgeTable: Vec<(NetworkId, MultiLocation, Option)> - = vec![(Remote::get(), MultiLocation::parent(), Some((Parent, 150).into()))]; + = vec![(Remote::get(), MultiLocation::parent(), Some((Parent, 150u128).into()))]; // ^^^ 100 to use the bridge (export) and 50 for the remote execution weight (5 instuctions // x 10 weight each). } @@ -63,10 +63,10 @@ fn sending_to_bridged_chain_works() { ); // Initialize the local relay so that our parachain has funds to pay for export. - add_asset(Parachain(100), (Here, 1000)); + add_asset(Parachain(100), (Here, 1000u128)); let msg = Xcm(vec![Trap(1)]); - assert_eq!(send_xcm::(dest, msg), Ok((Parent, 150).into())); + assert_eq!(send_xcm::(dest, msg), Ok((Parent, 150u128).into())); assert_eq!(TheBridge::service(), 1); assert_eq!( take_received_remote_messages(), @@ -81,7 +81,7 @@ fn sending_to_bridged_chain_works() { ); // The export cost 50 weight units (and thus 50 units of balance). - assert_eq!(asset_list(Parachain(100)), vec![(Here, 850).into()]); + assert_eq!(asset_list(Parachain(100)), vec![(Here, 850u128).into()]); } /// ```nocompile @@ -104,9 +104,9 @@ fn sending_to_parachain_of_bridged_chain_works() { ); // Initialize the local relay so that our parachain has funds to pay for export. - add_asset(Parachain(100), (Here, 1000)); + add_asset(Parachain(100), (Here, 1000u128)); - assert_eq!(send_xcm::(dest, Xcm(vec![Trap(1)])), Ok((Parent, 150).into())); + assert_eq!(send_xcm::(dest, Xcm(vec![Trap(1)])), Ok((Parent, 150u128).into())); assert_eq!(TheBridge::service(), 1); let expected = vec![( Parachain(100).into(), @@ -119,5 +119,5 @@ fn sending_to_parachain_of_bridged_chain_works() { assert_eq!(take_received_remote_messages(), expected); // The export cost 50 weight units (and thus 50 units of balance). - assert_eq!(asset_list(Parachain(100)), vec![(Here, 850).into()]); + assert_eq!(asset_list(Parachain(100)), vec![(Here, 850u128).into()]); } diff --git a/xcm/xcm-builder/src/tests/locking.rs b/xcm/xcm-builder/src/tests/locking.rs index 01cdb80f8ad5..d6afe08e4970 100644 --- a/xcm/xcm-builder/src/tests/locking.rs +++ b/xcm/xcm-builder/src/tests/locking.rs @@ -22,37 +22,40 @@ fn lock_roundtrip_should_work() { // Account #3 and Parachain #1 can execute for free AllowUnpaidFrom::set(vec![(3u64,).into(), (Parent, Parachain(1)).into()]); // Account #3 owns 1000 native parent tokens. - add_asset((3u64,), (Parent, 1000)); + add_asset((3u64,), (Parent, 1000u128)); // Sending a message costs 10 parent-tokens. - set_send_price((Parent, 10)); + set_send_price((Parent, 10u128)); // They want to lock 100 of the native parent tokens to be unlocked only by Parachain #1. let r = XcmExecutor::::execute_xcm( (3u64,), Xcm(vec![ - WithdrawAsset((Parent, 100).into()), + WithdrawAsset((Parent, 100u128).into()), SetAppendix( vec![DepositAsset { assets: AllCounted(2).into(), beneficiary: (3u64,).into() }] .into(), ), - LockAsset { asset: (Parent, 100).into(), unlocker: (Parent, Parachain(1)).into() }, + LockAsset { asset: (Parent, 100u128).into(), unlocker: (Parent, Parachain(1)).into() }, ]), 50, ); assert_eq!(r, Outcome::Complete(40)); - assert_eq!(asset_list((3u64,)), vec![(Parent, 990).into()]); + assert_eq!(asset_list((3u64,)), vec![(Parent, 990u128).into()]); assert_eq!( sent_xcm(), vec![( (Parent, Parachain(1)).into(), - Xcm::<()>(vec![NoteUnlockable { owner: (3u64,).into(), asset: (Parent, 100).into() },]), + Xcm::<()>(vec![NoteUnlockable { + owner: (Parent, Parachain(42), 3u64).into(), + asset: (Parent, 100u128).into() + },]), )] ); assert_eq!( take_lock_trace(), vec![Lock { - asset: (Parent, 100).into(), + asset: (Parent, 100u128).into(), owner: (3u64,).into(), unlocker: (Parent, Parachain(1)).into(), }] @@ -61,7 +64,7 @@ fn lock_roundtrip_should_work() { // Now we'll unlock it. let r = XcmExecutor::::execute_xcm( (Parent, Parachain(1)), - Xcm(vec![UnlockAsset { asset: (Parent, 100).into(), target: (3u64,).into() }]), + Xcm(vec![UnlockAsset { asset: (Parent, 100u128).into(), target: (3u64,).into() }]), 50, ); assert_eq!(r, Outcome::Complete(10)); @@ -72,21 +75,21 @@ fn auto_fee_paying_should_work() { // Account #3 and Parachain #1 can execute for free AllowUnpaidFrom::set(vec![(3u64,).into()]); // Account #3 owns 1000 native parent tokens. - add_asset((3u64,), (Parent, 1000)); + add_asset((3u64,), (Parent, 1000u128)); // Sending a message costs 10 parent-tokens. - set_send_price((Parent, 10)); + set_send_price((Parent, 10u128)); // They want to lock 100 of the native parent tokens to be unlocked only by Parachain #1. let r = XcmExecutor::::execute_xcm( (3u64,), Xcm(vec![ SetFeesMode { jit_withdraw: true }, - LockAsset { asset: (Parent, 100).into(), unlocker: (Parent, Parachain(1)).into() }, + LockAsset { asset: (Parent, 100u128).into(), unlocker: (Parent, Parachain(1)).into() }, ]), 50, ); assert_eq!(r, Outcome::Complete(20)); - assert_eq!(asset_list((3u64,)), vec![(Parent, 990).into()]); + assert_eq!(asset_list((3u64,)), vec![(Parent, 990u128).into()]); } #[test] @@ -99,7 +102,7 @@ fn lock_should_fail_correctly() { let r = XcmExecutor::::execute_xcm( (3u64,), Xcm(vec![LockAsset { - asset: (Parent, 100).into(), + asset: (Parent, 100u128).into(), unlocker: (Parent, Parachain(1)).into(), }]), 50, @@ -109,16 +112,16 @@ fn lock_should_fail_correctly() { assert_eq!(take_lock_trace(), vec![]); // Account #3 owns 1000 native parent tokens. - add_asset((3u64,), (Parent, 1000)); + add_asset((3u64,), (Parent, 1000u128)); // But we require a price to be paid for the sending - set_send_price((Parent, 10)); + set_send_price((Parent, 10u128)); // #3 wants to lock 100 of the native parent tokens to be unlocked only by parachain ../#1, // but there's nothing to pay the fees for sending the notification message. let r = XcmExecutor::::execute_xcm( (3u64,), Xcm(vec![LockAsset { - asset: (Parent, 100).into(), + asset: (Parent, 100u128).into(), unlocker: (Parent, Parachain(1)).into(), }]), 50, @@ -133,21 +136,21 @@ fn remote_unlock_roundtrip_should_work() { // Account #3 can execute for free AllowUnpaidFrom::set(vec![(3u64,).into(), (Parent, Parachain(1)).into()]); // Account #3 owns 1000 native parent tokens. - add_asset((3u64,), (Parent, 1000)); + add_asset((3u64,), (Parent, 1000u128)); // Sending a message costs 10 parent-tokens. - set_send_price((Parent, 10)); + set_send_price((Parent, 10u128)); // We have been told by Parachain #1 that Account #3 has locked funds which we can unlock. let r = XcmExecutor::::execute_xcm( (Parent, Parachain(1)), - Xcm(vec![NoteUnlockable { asset: (Parent, 100).into(), owner: (3u64,).into() }]), + Xcm(vec![NoteUnlockable { asset: (Parent, 100u128).into(), owner: (3u64,).into() }]), 50, ); assert_eq!(r, Outcome::Complete(10)); assert_eq!( take_lock_trace(), vec![Note { - asset: (Parent, 100).into(), + asset: (Parent, 100u128).into(), owner: (3u64,).into(), locker: (Parent, Parachain(1)).into(), }] @@ -157,29 +160,35 @@ fn remote_unlock_roundtrip_should_work() { let r = XcmExecutor::::execute_xcm( (3u64,), Xcm(vec![ - WithdrawAsset((Parent, 100).into()), + WithdrawAsset((Parent, 100u128).into()), SetAppendix( vec![DepositAsset { assets: AllCounted(2).into(), beneficiary: (3u64,).into() }] .into(), ), - RequestUnlock { asset: (Parent, 100).into(), locker: (Parent, Parachain(1)).into() }, + RequestUnlock { + asset: (Parent, 100u128).into(), + locker: (Parent, Parachain(1)).into(), + }, ]), 50, ); assert_eq!(r, Outcome::Complete(40)); - assert_eq!(asset_list((3u64,)), vec![(Parent, 990).into()]); + assert_eq!(asset_list((3u64,)), vec![(Parent, 990u128).into()]); assert_eq!( sent_xcm(), vec![( (Parent, Parachain(1)).into(), - Xcm::<()>(vec![UnlockAsset { target: (3u64,).into(), asset: (Parent, 100).into() },]), + Xcm::<()>(vec![UnlockAsset { + target: (3u64,).into(), + asset: (Parent, 100u128).into() + },]), )] ); assert_eq!( take_lock_trace(), vec![Reduce { - asset: (Parent, 100).into(), + asset: (Parent, 100u128).into(), owner: (3u64,).into(), locker: (Parent, Parachain(1)).into(), }] @@ -191,7 +200,7 @@ fn remote_unlock_should_fail_correctly() { // Account #3 can execute for free AllowUnpaidFrom::set(vec![(3u64,).into(), (Parent, Parachain(1)).into()]); // But we require a price to be paid for the sending - set_send_price((Parent, 10)); + set_send_price((Parent, 10u128)); // We want to unlock 100 of the native parent tokens which were locked for us on parachain. // This won't work as we don't have any record of them being locked for us. @@ -199,7 +208,7 @@ fn remote_unlock_should_fail_correctly() { let r = XcmExecutor::::execute_xcm( (3u64,), Xcm(vec![RequestUnlock { - asset: (Parent, 100).into(), + asset: (Parent, 100u128).into(), locker: (Parent, Parachain(1)).into(), }]), 50, @@ -211,7 +220,7 @@ fn remote_unlock_should_fail_correctly() { // We have been told by Parachain #1 that Account #3 has locked funds which we can unlock. let r = XcmExecutor::::execute_xcm( (Parent, Parachain(1)), - Xcm(vec![NoteUnlockable { asset: (Parent, 100).into(), owner: (3u64,).into() }]), + Xcm(vec![NoteUnlockable { asset: (Parent, 100u128).into(), owner: (3u64,).into() }]), 50, ); assert_eq!(r, Outcome::Complete(10)); @@ -223,7 +232,7 @@ fn remote_unlock_should_fail_correctly() { let r = XcmExecutor::::execute_xcm( (3u64,), Xcm(vec![RequestUnlock { - asset: (Parent, 100).into(), + asset: (Parent, 100u128).into(), locker: (Parent, Parachain(1)).into(), }]), 50, diff --git a/xcm/xcm-builder/src/tests/mock.rs b/xcm/xcm-builder/src/tests/mock.rs index bcaad110dd33..3972170ab15c 100644 --- a/xcm/xcm-builder/src/tests/mock.rs +++ b/xcm/xcm-builder/src/tests/mock.rs @@ -19,6 +19,7 @@ pub use crate::{ AllowKnownQueryResponses, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, FixedRateOfFungible, FixedWeightBounds, LocationInverter, TakeWeightCredit, }; +use frame_support::traits::ContainsPair; pub use frame_support::{ dispatch::{ DispatchError, DispatchInfo, DispatchResultWithPostInfo, Dispatchable, Parameter, Weight, @@ -39,7 +40,7 @@ pub use xcm::latest::prelude::*; pub use xcm_executor::{ traits::{ AssetExchange, AssetLock, ConvertOrigin, Enact, ExportXcm, FeeManager, FeeReason, - FilterAssetLocation, LockError, OnResponse, TransactAsset, UniversalLocation, + LockError, OnResponse, TransactAsset, UniversalLocation, }, Assets, Config, }; @@ -283,15 +284,15 @@ pub fn clear_universal_aliases() { } pub struct TestIsReserve; -impl FilterAssetLocation for TestIsReserve { - fn filter_asset_location(asset: &MultiAsset, origin: &MultiLocation) -> bool { +impl ContainsPair for TestIsReserve { + fn contains(asset: &MultiAsset, origin: &MultiLocation) -> bool { IS_RESERVE .with(|r| r.borrow().get(origin).map_or(false, |v| v.iter().any(|a| a.matches(asset)))) } } pub struct TestIsTeleporter; -impl FilterAssetLocation for TestIsTeleporter { - fn filter_asset_location(asset: &MultiAsset, origin: &MultiLocation) -> bool { +impl ContainsPair for TestIsTeleporter { + fn contains(asset: &MultiAsset, origin: &MultiLocation) -> bool { IS_TELEPORTER .with(|r| r.borrow().get(origin).map_or(false, |v| v.iter().any(|a| a.matches(asset)))) } diff --git a/xcm/xcm-builder/src/tests/mod.rs b/xcm/xcm-builder/src/tests/mod.rs index da17f2d36e83..d49b207f73b1 100644 --- a/xcm/xcm-builder/src/tests/mod.rs +++ b/xcm/xcm-builder/src/tests/mod.rs @@ -16,8 +16,12 @@ use super::{test_utils::*, *}; use core::convert::TryInto; -use frame_support::{assert_err, traits::ConstU32, weights::constants::WEIGHT_PER_SECOND}; -use xcm_executor::{traits::*, Config, XcmExecutor}; +use frame_support::{ + assert_err, + traits::{ConstU32, ContainsPair}, + weights::constants::WEIGHT_PER_SECOND, +}; +use xcm_executor::{traits::prelude::*, Config, XcmExecutor}; mod mock; use mock::*; diff --git a/xcm/xcm-builder/src/tests/origins.rs b/xcm/xcm-builder/src/tests/origins.rs index 5dee287a559b..93569d9d0fb1 100644 --- a/xcm/xcm-builder/src/tests/origins.rs +++ b/xcm/xcm-builder/src/tests/origins.rs @@ -29,7 +29,7 @@ fn universal_origin_should_work() { Parachain(2), Xcm(vec![ UniversalOrigin(GlobalConsensus(Kusama)), - TransferAsset { assets: (Parent, 100).into(), beneficiary: Here.into() }, + TransferAsset { assets: (Parent, 100u128).into(), beneficiary: Here.into() }, ]), 50, ); @@ -39,18 +39,18 @@ fn universal_origin_should_work() { Parachain(1), Xcm(vec![ UniversalOrigin(GlobalConsensus(Kusama)), - TransferAsset { assets: (Parent, 100).into(), beneficiary: Here.into() }, + TransferAsset { assets: (Parent, 100u128).into(), beneficiary: Here.into() }, ]), 50, ); assert_eq!(r, Outcome::Incomplete(20, XcmError::NotWithdrawable)); - add_asset((Ancestor(2), GlobalConsensus(Kusama)), (Parent, 100)); + add_asset((Ancestor(2), GlobalConsensus(Kusama)), (Parent, 100u128)); let r = XcmExecutor::::execute_xcm( Parachain(1), Xcm(vec![ UniversalOrigin(GlobalConsensus(Kusama)), - TransferAsset { assets: (Parent, 100).into(), beneficiary: Here.into() }, + TransferAsset { assets: (Parent, 100u128).into(), beneficiary: Here.into() }, ]), 50, ); @@ -64,8 +64,10 @@ fn export_message_should_work() { AllowUnpaidFrom::set(vec![X1(Parachain(1)).into()]); // Local parachain #1 issues a transfer asset on Polkadot Relay-chain, transfering 100 Planck to // Polkadot parachain #2. - let message = - Xcm(vec![TransferAsset { assets: (Here, 100).into(), beneficiary: Parachain(2).into() }]); + let message = Xcm(vec![TransferAsset { + assets: (Here, 100u128).into(), + beneficiary: Parachain(2).into(), + }]); let r = XcmExecutor::::execute_xcm( Parachain(1), Xcm(vec![ExportMessage { network: Polkadot, destination: Here, xcm: message.clone() }]), diff --git a/xcm/xcm-builder/src/tests/querying.rs b/xcm/xcm-builder/src/tests/querying.rs index 1b6e90e230d4..feb3259208ed 100644 --- a/xcm/xcm-builder/src/tests/querying.rs +++ b/xcm/xcm-builder/src/tests/querying.rs @@ -100,7 +100,7 @@ fn prepaid_result_of_query_should_get_free_execution() { // We put this in manually here, but normally this would be done at the point of crafting the message. expect_response(query_id, Parent.into()); - let the_response = Response::Assets((Parent, 100).into()); + let the_response = Response::Assets((Parent, 100u128).into()); let message = Xcm::(vec![QueryResponse { query_id, response: the_response.clone(), diff --git a/xcm/xcm-builder/src/tests/transacting.rs b/xcm/xcm-builder/src/tests/transacting.rs index 643a1054d8cb..009ba5ad96d1 100644 --- a/xcm/xcm-builder/src/tests/transacting.rs +++ b/xcm/xcm-builder/src/tests/transacting.rs @@ -62,13 +62,13 @@ fn transacting_should_refund_weight() { fn paid_transacting_should_refund_payment_for_unused_weight() { let one: MultiLocation = AccountIndex64 { index: 1, network: None }.into(); AllowPaidFrom::set(vec![one.clone()]); - add_asset(AccountIndex64 { index: 1, network: None }, (Parent, 100)); + add_asset(AccountIndex64 { index: 1, network: None }, (Parent, 100u128)); WeightPrice::set((Parent.into(), 1_000_000_000_000)); let origin = one.clone(); - let fees = (Parent, 100).into(); + let fees = (Parent, 100u128).into(); let message = Xcm::(vec![ - WithdrawAsset((Parent, 100).into()), // enough for 100 units of weight. + WithdrawAsset((Parent, 100u128).into()), // enough for 100 units of weight. BuyExecution { fees, weight_limit: Limited(100) }, Transact { origin_kind: OriginKind::Native, @@ -82,7 +82,10 @@ fn paid_transacting_should_refund_payment_for_unused_weight() { let weight_limit = 100; let r = XcmExecutor::::execute_xcm(origin, message, weight_limit); assert_eq!(r, Outcome::Complete(60)); - assert_eq!(asset_list(AccountIndex64 { index: 1, network: None }), vec![(Parent, 40).into()]); + assert_eq!( + asset_list(AccountIndex64 { index: 1, network: None }), + vec![(Parent, 40u128).into()] + ); } #[test] diff --git a/xcm/xcm-builder/src/tests/weight.rs b/xcm/xcm-builder/src/tests/weight.rs index 6c2a5cf112f8..f0a3aaf57a1b 100644 --- a/xcm/xcm-builder/src/tests/weight.rs +++ b/xcm/xcm-builder/src/tests/weight.rs @@ -21,21 +21,21 @@ fn errors_should_return_unused_weight() { // we'll let them have message execution for free. AllowUnpaidFrom::set(vec![Here.into()]); // We own 1000 of our tokens. - add_asset(Here, (Here, 11)); + add_asset(Here, (Here, 11u128)); let mut message = Xcm(vec![ // First xfer results in an error on the last message only TransferAsset { - assets: (Here, 1).into(), + assets: (Here, 1u128).into(), beneficiary: X1(AccountIndex64 { index: 3, network: None }).into(), }, // Second xfer results in error third message and after TransferAsset { - assets: (Here, 2).into(), + assets: (Here, 2u128).into(), beneficiary: X1(AccountIndex64 { index: 3, network: None }).into(), }, // Third xfer results in error second message and after TransferAsset { - assets: (Here, 4).into(), + assets: (Here, 4u128).into(), beneficiary: X1(AccountIndex64 { index: 3, network: None }).into(), }, ]); @@ -45,25 +45,25 @@ fn errors_should_return_unused_weight() { let r = XcmExecutor::::execute_xcm(Here, message.clone(), limit); assert_eq!(r, Outcome::Complete(30)); - assert_eq!(asset_list(AccountIndex64 { index: 3, network: None }), vec![(Here, 7).into()]); - assert_eq!(asset_list(Here), vec![(Here, 4).into()]); + assert_eq!(asset_list(AccountIndex64 { index: 3, network: None }), vec![(Here, 7u128).into()]); + assert_eq!(asset_list(Here), vec![(Here, 4u128).into()]); assert_eq!(sent_xcm(), vec![]); let r = XcmExecutor::::execute_xcm(Here, message.clone(), limit); assert_eq!(r, Outcome::Incomplete(30, XcmError::NotWithdrawable)); - assert_eq!(asset_list(AccountIndex64 { index: 3, network: None }), vec![(Here, 10).into()]); - assert_eq!(asset_list(Here), vec![(Here, 1).into()]); + assert_eq!(asset_list(AccountIndex64 { index: 3, network: None }), vec![(Here, 10u128).into()]); + assert_eq!(asset_list(Here), vec![(Here, 1u128).into()]); assert_eq!(sent_xcm(), vec![]); let r = XcmExecutor::::execute_xcm(Here, message.clone(), limit); assert_eq!(r, Outcome::Incomplete(20, XcmError::NotWithdrawable)); - assert_eq!(asset_list(AccountIndex64 { index: 3, network: None }), vec![(Here, 11).into()]); + assert_eq!(asset_list(AccountIndex64 { index: 3, network: None }), vec![(Here, 11u128).into()]); assert_eq!(asset_list(Here), vec![]); assert_eq!(sent_xcm(), vec![]); let r = XcmExecutor::::execute_xcm(Here, message, limit); assert_eq!(r, Outcome::Incomplete(10, XcmError::NotWithdrawable)); - assert_eq!(asset_list(AccountIndex64 { index: 3, network: None }), vec![(Here, 11).into()]); + assert_eq!(asset_list(AccountIndex64 { index: 3, network: None }), vec![(Here, 11u128).into()]); assert_eq!(asset_list(Here), vec![]); assert_eq!(sent_xcm(), vec![]); } diff --git a/xcm/xcm-executor/src/config.rs b/xcm/xcm-executor/src/config.rs index 67b8ca3d72ab..23cc7e885764 100644 --- a/xcm/xcm-executor/src/config.rs +++ b/xcm/xcm-executor/src/config.rs @@ -16,15 +16,15 @@ use crate::traits::{ AssetExchange, AssetLock, ClaimAssets, ConvertOrigin, DropAssets, ExportXcm, FeeManager, - FilterAssetLocation, OnResponse, ShouldExecute, TransactAsset, UniversalLocation, - VersionChangeNotifier, WeightBounds, WeightTrader, + OnResponse, ShouldExecute, TransactAsset, UniversalLocation, VersionChangeNotifier, + WeightBounds, WeightTrader, }; use frame_support::{ dispatch::{Dispatchable, Parameter}, - traits::{Contains, Get, PalletsInfoAccess}, + traits::{Contains, ContainsPair, Get, PalletsInfoAccess}, weights::{GetDispatchInfo, PostDispatchInfo}, }; -use xcm::latest::{Junction, MultiLocation, SendXcm}; +use xcm::prelude::*; /// The trait to parameterize the `XcmExecutor`. pub trait Config { @@ -40,11 +40,11 @@ pub trait Config { /// How to get a call origin from a `OriginKind` value. type OriginConverter: ConvertOrigin<::Origin>; - /// Combinations of (Location, Asset) pairs which we trust as reserves. - type IsReserve: FilterAssetLocation; + /// Combinations of (Asset, Location) pairs which we trust as reserves. + type IsReserve: ContainsPair; - /// Combinations of (Location, Asset) pairs which we trust as teleporters. - type IsTeleporter: FilterAssetLocation; + /// Combinations of (Asset, Location) pairs which we trust as teleporters. + type IsTeleporter: ContainsPair; /// Means of inverting a location. type LocationInverter: UniversalLocation; diff --git a/xcm/xcm-executor/src/lib.rs b/xcm/xcm-executor/src/lib.rs index fcd7f85b18ea..ec7f583128e9 100644 --- a/xcm/xcm-executor/src/lib.rs +++ b/xcm/xcm-executor/src/lib.rs @@ -19,7 +19,7 @@ use frame_support::{ dispatch::{Dispatchable, Weight}, ensure, - traits::{Contains, Get, PalletsInfoAccess}, + traits::{Contains, ContainsPair, Get, PalletsInfoAccess}, weights::GetDispatchInfo, }; use parity_scale_codec::{Decode, Encode}; @@ -31,8 +31,8 @@ use xcm::latest::prelude::*; pub mod traits; use traits::{ validate_export, AssetExchange, AssetLock, ClaimAssets, ConvertOrigin, DropAssets, Enact, - ExportXcm, FeeManager, FeeReason, FilterAssetLocation, OnResponse, ShouldExecute, - TransactAsset, UniversalLocation, VersionChangeNotifier, WeightBounds, WeightTrader, + ExportXcm, FeeManager, FeeReason, OnResponse, ShouldExecute, TransactAsset, UniversalLocation, + VersionChangeNotifier, WeightBounds, WeightTrader, }; mod assets; @@ -192,7 +192,7 @@ impl ExecuteXcm for XcmExecutor { xcm_weight, &mut weight_credit, ) { - log::debug!( + log::trace!( target: "xcm::execute_xcm_in_credit", "Barrier blocked execution! Error: {:?}. (origin: {:?}, message: {:?}, weight_credit: {:?})", e, @@ -291,6 +291,7 @@ impl XcmExecutor { match &mut result { r @ Ok(()) => if let Err(e) = self.process_instruction(instr) { + log::trace!(target: "xcm::execute", "!!! ERROR: {:?}", e); *r = Err(ExecutorError { index: i as u32, xcm_error: e, weight: 0 }); }, Err(ref mut error) => @@ -323,7 +324,7 @@ impl XcmExecutor { // TODO: #2841 #REALWEIGHT We should deduct the cost of any instructions following // the error which didn't end up being executed. Some((_i, e)) => { - log::debug!(target: "xcm::execute_xcm_in_credit", "Execution errored at {:?}: {:?} (original_origin: {:?})", _i, e, self.original_origin); + log::trace!(target: "xcm::execute_xcm_in_credit", "Execution errored at {:?}: {:?} (original_origin: {:?})", _i, e, self.original_origin); Outcome::Incomplete(weight_used, e) }, } @@ -400,6 +401,11 @@ impl XcmExecutor { /// Process a single XCM instruction, mutating the state of the XCM virtual machine. fn process_instruction(&mut self, instr: Instruction) -> Result<(), XcmError> { + log::trace!( + target: "xcm::process_instruction", + "=== {:?}", + instr + ); match instr { WithdrawAsset(assets) => { // Take `assets` from the origin account (on-chain) and place in holding. @@ -416,7 +422,7 @@ impl XcmExecutor { for asset in assets.into_inner().into_iter() { // Must ensure that we recognise the asset as being managed by the origin. ensure!( - Config::IsReserve::filter_asset_location(&asset, &origin), + Config::IsReserve::contains(&asset, &origin), XcmError::UntrustedReserveLocation ); self.subsume_asset(asset)?; @@ -451,7 +457,7 @@ impl XcmExecutor { // We only trust the origin to send us assets that they identify as their // sovereign assets. ensure!( - Config::IsTeleporter::filter_asset_location(asset, &origin), + Config::IsTeleporter::contains(asset, &origin), XcmError::UntrustedTeleportLocation ); // We should check that the asset can actually be teleported in (for this to be in error, there @@ -731,11 +737,12 @@ impl XcmExecutor { }, LockAsset { asset, unlocker } => { let origin = self.origin.as_ref().ok_or(XcmError::BadOrigin)?.clone(); - let remote_asset = Self::try_reanchor(asset.clone(), &unlocker)?; + let (remote_asset, context) = Self::try_reanchor(asset.clone(), &unlocker)?; let lock_ticket = Config::AssetLocker::prepare_lock(unlocker.clone(), asset, origin.clone())?; - let msg = - Xcm::<()>(vec![NoteUnlockable { asset: remote_asset, owner: origin.clone() }]); + let owner = + origin.reanchored(&unlocker, &context).map_err(|_| XcmError::ReanchorFailed)?; + let msg = Xcm::<()>(vec![NoteUnlockable { asset: remote_asset, owner }]); let (ticket, price) = validate_send::(unlocker, msg)?; self.take_fee(price, FeeReason::LockAsset)?; lock_ticket.enact()?; @@ -754,7 +761,7 @@ impl XcmExecutor { }, RequestUnlock { asset, locker } => { let origin = self.origin.as_ref().ok_or(XcmError::BadOrigin)?.clone(); - let remote_asset = Self::try_reanchor(asset.clone(), &locker)?; + let remote_asset = Self::try_reanchor(asset.clone(), &locker)?.0; let reduce_ticket = Config::AssetLocker::prepare_reduce_unlockable( locker.clone(), asset, @@ -850,9 +857,12 @@ impl XcmExecutor { fn try_reanchor( asset: MultiAsset, destination: &MultiLocation, - ) -> Result { + ) -> Result<(MultiAsset, MultiLocation), XcmError> { let context = Config::LocationInverter::universal_location().into(); - asset.reanchored(&destination, &context).map_err(|()| XcmError::ReanchorFailed) + let asset = asset + .reanchored(&destination, &context) + .map_err(|()| XcmError::ReanchorFailed)?; + Ok((asset, context)) } /// NOTE: Any assets which were unable to be reanchored are introduced into `failed_bin`. diff --git a/xcm/xcm-executor/src/traits/filter_asset_location.rs b/xcm/xcm-executor/src/traits/filter_asset_location.rs index 31b9c47a828c..ec9fecbab640 100644 --- a/xcm/xcm-executor/src/traits/filter_asset_location.rs +++ b/xcm/xcm-executor/src/traits/filter_asset_location.rs @@ -14,28 +14,21 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . +use frame_support::traits::ContainsPair; use xcm::latest::{MultiAsset, MultiLocation}; /// Filters assets/location pairs. /// /// Can be amalgamated into tuples. If any item returns `true`, it short-circuits, else `false` is returned. +#[deprecated = "Use `frame_support::traits::ContainsPair` instead"] pub trait FilterAssetLocation { /// A filter to distinguish between asset/location pairs. - fn filter_asset_location(asset: &MultiAsset, origin: &MultiLocation) -> bool; + fn contains(asset: &MultiAsset, origin: &MultiLocation) -> bool; } -#[impl_trait_for_tuples::impl_for_tuples(30)] -impl FilterAssetLocation for Tuple { - fn filter_asset_location(what: &MultiAsset, origin: &MultiLocation) -> bool { - for_tuples!( #( - if Tuple::filter_asset_location(what, origin) { return true } - )* ); - log::trace!( - target: "xcm::filter_asset_location", - "got filtered: what: {:?}, origin: {:?}", - what, - origin, - ); - false +#[allow(deprecated)] +impl> FilterAssetLocation for T { + fn contains(asset: &MultiAsset, origin: &MultiLocation) -> bool { + T::contains(asset, origin) } } diff --git a/xcm/xcm-executor/src/traits/matches_fungible.rs b/xcm/xcm-executor/src/traits/matches_fungible.rs deleted file mode 100644 index 4989f263a63d..000000000000 --- a/xcm/xcm-executor/src/traits/matches_fungible.rs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2020 Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot 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. - -// Polkadot 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 Polkadot. If not, see . - -use xcm::latest::MultiAsset; - -pub trait MatchesFungible { - fn matches_fungible(a: &MultiAsset) -> Option; -} - -#[impl_trait_for_tuples::impl_for_tuples(30)] -impl MatchesFungible for Tuple { - fn matches_fungible(a: &MultiAsset) -> Option { - for_tuples!( #( - match Tuple::matches_fungible(a) { o @ Some(_) => return o, _ => () } - )* ); - log::trace!(target: "xcm::matches_fungible", "did not match fungible asset: {:?}", &a); - None - } -} diff --git a/xcm/xcm-executor/src/traits/mod.rs b/xcm/xcm-executor/src/traits/mod.rs index 293077d52201..4ad216effde6 100644 --- a/xcm/xcm-executor/src/traits/mod.rs +++ b/xcm/xcm-executor/src/traits/mod.rs @@ -31,11 +31,12 @@ pub use export::{export_xcm, validate_export, ExportXcm}; mod fee_manager; pub use fee_manager::{FeeManager, FeeReason}; mod filter_asset_location; +#[allow(deprecated)] pub use filter_asset_location::FilterAssetLocation; -mod matches_fungible; -pub use matches_fungible::MatchesFungible; -mod matches_fungibles; -pub use matches_fungibles::{Error, MatchesFungibles}; +mod token_matching; +pub use token_matching::{ + Error, MatchesFungible, MatchesFungibles, MatchesNonFungible, MatchesNonFungibles, +}; mod on_response; pub use on_response::{OnResponse, VersionChangeNotifier}; mod should_execute; @@ -44,3 +45,13 @@ mod transact_asset; pub use transact_asset::TransactAsset; mod weight; pub use weight::{WeightBounds, WeightTrader}; + +pub mod prelude { + pub use super::{ + export_xcm, validate_export, AssetExchange, AssetLock, ClaimAssets, Convert, ConvertOrigin, + Decoded, DropAssets, Enact, Encoded, Error, ExportXcm, FeeManager, FeeReason, Identity, + JustTry, LockError, MatchesFungible, MatchesFungibles, MatchesNonFungible, + MatchesNonFungibles, OnResponse, ShouldExecute, TransactAsset, UniversalLocation, + VersionChangeNotifier, WeightBounds, WeightTrader, + }; +} diff --git a/xcm/xcm-executor/src/traits/matches_fungibles.rs b/xcm/xcm-executor/src/traits/token_matching.rs similarity index 51% rename from xcm/xcm-executor/src/traits/matches_fungibles.rs rename to xcm/xcm-executor/src/traits/token_matching.rs index f5baafdcd97a..befff6b1b726 100644 --- a/xcm/xcm-executor/src/traits/matches_fungibles.rs +++ b/xcm/xcm-executor/src/traits/token_matching.rs @@ -15,7 +15,37 @@ // along with Polkadot. If not, see . use sp_std::result; -use xcm::latest::{Error as XcmError, MultiAsset}; +use xcm::latest::prelude::*; + +pub trait MatchesFungible { + fn matches_fungible(a: &MultiAsset) -> Option; +} + +#[impl_trait_for_tuples::impl_for_tuples(30)] +impl MatchesFungible for Tuple { + fn matches_fungible(a: &MultiAsset) -> Option { + for_tuples!( #( + match Tuple::matches_fungible(a) { o @ Some(_) => return o, _ => () } + )* ); + log::trace!(target: "xcm::matches_fungible", "did not match fungible asset: {:?}", &a); + None + } +} + +pub trait MatchesNonFungible { + fn matches_nonfungible(a: &MultiAsset) -> Option; +} + +#[impl_trait_for_tuples::impl_for_tuples(30)] +impl MatchesNonFungible for Tuple { + fn matches_nonfungible(a: &MultiAsset) -> Option { + for_tuples!( #( + match Tuple::matches_nonfungible(a) { o @ Some(_) => return o, _ => () } + )* ); + log::trace!(target: "xcm::matches_non_fungible", "did not match non-fungible asset: {:?}", &a); + None + } +} /// Errors associated with [`MatchesFungibles`] operation. pub enum Error { @@ -25,8 +55,10 @@ pub enum Error { AccountIdConversionFailed, /// `u128` amount to currency `Balance` conversion failed. AmountToBalanceConversionFailed, - /// `MultiLocation` to `AssetId` conversion failed. + /// `MultiLocation` to `AssetId`/`ClassId` conversion failed. AssetIdConversionFailed, + /// `AssetInstance` to non-fungibles instance ID conversion failed. + InstanceConversionFailed, } impl From for XcmError { @@ -38,6 +70,7 @@ impl From for XcmError { Error::AmountToBalanceConversionFailed => FailedToTransactAsset("AmountToBalanceConversionFailed"), Error::AssetIdConversionFailed => FailedToTransactAsset("AssetIdConversionFailed"), + Error::InstanceConversionFailed => FailedToTransactAsset("InstanceConversionFailed"), } } } @@ -47,7 +80,7 @@ pub trait MatchesFungibles { } #[impl_trait_for_tuples::impl_for_tuples(30)] -impl MatchesFungibles for Tuple { +impl MatchesFungibles for Tuple { fn matches_fungibles(a: &MultiAsset) -> result::Result<(AssetId, Balance), Error> { for_tuples!( #( match Tuple::matches_fungibles(a) { o @ Ok(_) => return o, _ => () } @@ -56,3 +89,18 @@ impl MatchesFungibles for Tupl Err(Error::AssetNotFound) } } + +pub trait MatchesNonFungibles { + fn matches_nonfungibles(a: &MultiAsset) -> result::Result<(AssetId, Instance), Error>; +} + +#[impl_trait_for_tuples::impl_for_tuples(30)] +impl MatchesNonFungibles for Tuple { + fn matches_nonfungibles(a: &MultiAsset) -> result::Result<(AssetId, Instance), Error> { + for_tuples!( #( + match Tuple::matches_nonfungibles(a) { o @ Ok(_) => return o, _ => () } + )* ); + log::trace!(target: "xcm::matches_non_fungibles", "did not match fungibles asset: {:?}", &a); + Err(Error::AssetNotFound) + } +} diff --git a/xcm/xcm-executor/src/traits/transact_asset.rs b/xcm/xcm-executor/src/traits/transact_asset.rs index 78e2180ed7a4..7a933275a45a 100644 --- a/xcm/xcm-executor/src/traits/transact_asset.rs +++ b/xcm/xcm-executor/src/traits/transact_asset.rs @@ -95,7 +95,7 @@ pub trait TransactAsset { to: &MultiLocation, ) -> Result { match Self::transfer_asset(asset, from, to) { - Err(XcmError::Unimplemented) => { + Err(XcmError::AssetNotFound | XcmError::Unimplemented) => { let assets = Self::withdraw_asset(asset, from)?; // Not a very forgiving attitude; once we implement roll-backs then it'll be nicer. Self::deposit_asset(asset, to)?; @@ -273,7 +273,7 @@ mod tests { (UnimplementedTransactor, NotFoundTransactor, UnimplementedTransactor); assert_eq!( - MultiTransactor::deposit_asset(&(Here, 1).into(), &Here.into()), + MultiTransactor::deposit_asset(&(Here, 1u128).into(), &Here.into()), Err(XcmError::AssetNotFound) ); } @@ -282,7 +282,7 @@ mod tests { fn unimplemented_and_not_found_continue_iteration() { type MultiTransactor = (UnimplementedTransactor, NotFoundTransactor, SuccessfulTransactor); - assert_eq!(MultiTransactor::deposit_asset(&(Here, 1).into(), &Here.into()), Ok(()),); + assert_eq!(MultiTransactor::deposit_asset(&(Here, 1u128).into(), &Here.into()), Ok(()),); } #[test] @@ -290,7 +290,7 @@ mod tests { type MultiTransactor = (OverflowTransactor, SuccessfulTransactor); assert_eq!( - MultiTransactor::deposit_asset(&(Here, 1).into(), &Here.into()), + MultiTransactor::deposit_asset(&(Here, 1u128).into(), &Here.into()), Err(XcmError::Overflow) ); } @@ -299,6 +299,6 @@ mod tests { fn success_stops_iteration() { type MultiTransactor = (SuccessfulTransactor, OverflowTransactor); - assert_eq!(MultiTransactor::deposit_asset(&(Here, 1).into(), &Here.into()), Ok(()),); + assert_eq!(MultiTransactor::deposit_asset(&(Here, 1u128).into(), &Here.into()), Ok(()),); } } diff --git a/xcm/xcm-simulator/example/Cargo.toml b/xcm/xcm-simulator/example/Cargo.toml index 1ec8601ea2c7..6c0263996467 100644 --- a/xcm/xcm-simulator/example/Cargo.toml +++ b/xcm/xcm-simulator/example/Cargo.toml @@ -8,14 +8,17 @@ edition = "2021" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0" } scale-info = { version = "2.0.0", features = ["derive"] } +log = { version = "0.4.14", default-features = false } frame-system = { git = "https://github.com/paritytech/substrate", branch = "master" } frame-support = { git = "https://github.com/paritytech/substrate", branch = "master" } pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master" } +pallet-uniques = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-std = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-io = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-tracing = { git = "https://github.com/paritytech/substrate", branch = "master" } xcm = { path = "../../" } xcm-simulator = { path = "../" } @@ -25,3 +28,18 @@ pallet-xcm = { path = "../../pallet-xcm" } polkadot-core-primitives = { path = "../../../core-primitives" } polkadot-runtime-parachains = { path = "../../../runtime/parachains" } polkadot-parachain = { path = "../../../parachain" } + +[features] +default = [] +runtime-benchmarks = [ + "frame-system/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "pallet-balances/runtime-benchmarks", + "pallet-uniques/runtime-benchmarks", + "pallet-xcm/runtime-benchmarks", + "xcm-builder/runtime-benchmarks", + "xcm-executor/runtime-benchmarks", + "xcm/runtime-benchmarks", + "polkadot-runtime-parachains/runtime-benchmarks", + "polkadot-parachain/runtime-benchmarks", +] diff --git a/xcm/xcm-simulator/example/src/lib.rs b/xcm/xcm-simulator/example/src/lib.rs index 9e705145dd17..d9c08a5f369f 100644 --- a/xcm/xcm-simulator/example/src/lib.rs +++ b/xcm/xcm-simulator/example/src/lib.rs @@ -17,8 +17,9 @@ mod parachain; mod relay_chain; -use polkadot_parachain::primitives::Id as ParaId; -use sp_runtime::traits::AccountIdConversion; +use frame_support::sp_tracing; +use xcm::prelude::*; +use xcm_executor::traits::Convert; use xcm_simulator::{decl_test_network, decl_test_parachain, decl_test_relay_chain}; pub const ALICE: sp_runtime::AccountId32 = sp_runtime::AccountId32::new([0u8; 32]); @@ -60,8 +61,29 @@ decl_test_network! { } } -pub fn para_account_id(id: u32) -> relay_chain::AccountId { - ParaId::from(id).into_account() +pub fn parent_account_id() -> parachain::AccountId { + let location = (Parent,); + parachain::LocationToAccountId::convert(location.into()).unwrap() +} + +pub fn child_account_id(para: u32) -> relay_chain::AccountId { + let location = (Parachain(para),); + relay_chain::LocationToAccountId::convert(location.into()).unwrap() +} + +pub fn child_account_account_id(para: u32, who: sp_runtime::AccountId32) -> relay_chain::AccountId { + let location = (Parachain(para), AccountId32 { network: None, id: who.into() }); + relay_chain::LocationToAccountId::convert(location.into()).unwrap() +} + +pub fn sibling_account_account_id(para: u32, who: sp_runtime::AccountId32) -> parachain::AccountId { + let location = (Parent, Parachain(para), AccountId32 { network: None, id: who.into() }); + parachain::LocationToAccountId::convert(location.into()).unwrap() +} + +pub fn parent_account_account_id(who: sp_runtime::AccountId32) -> parachain::AccountId { + let location = (Parent, AccountId32 { network: None, id: who.into() }); + parachain::LocationToAccountId::convert(location.into()).unwrap() } pub fn para_ext(para_id: u32) -> sp_io::TestExternalities { @@ -69,12 +91,15 @@ pub fn para_ext(para_id: u32) -> sp_io::TestExternalities { let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); - pallet_balances::GenesisConfig:: { balances: vec![(ALICE, INITIAL_BALANCE)] } - .assimilate_storage(&mut t) - .unwrap(); + pallet_balances::GenesisConfig:: { + balances: vec![(ALICE, INITIAL_BALANCE), (parent_account_id(), INITIAL_BALANCE)], + } + .assimilate_storage(&mut t) + .unwrap(); let mut ext = sp_io::TestExternalities::new(t); ext.execute_with(|| { + sp_tracing::try_init_simple(); System::set_block_number(1); MsgQueue::set_para_id(para_id.into()); }); @@ -82,22 +107,26 @@ pub fn para_ext(para_id: u32) -> sp_io::TestExternalities { } pub fn relay_ext() -> sp_io::TestExternalities { - use relay_chain::{Runtime, System}; + use relay_chain::{Origin, Runtime, System, Uniques}; let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); pallet_balances::GenesisConfig:: { balances: vec![ (ALICE, INITIAL_BALANCE), - (para_account_id(1), INITIAL_BALANCE), - (para_account_id(2), INITIAL_BALANCE), + (child_account_id(1), INITIAL_BALANCE), + (child_account_id(2), INITIAL_BALANCE), ], } .assimilate_storage(&mut t) .unwrap(); let mut ext = sp_io::TestExternalities::new(t); - ext.execute_with(|| System::set_block_number(1)); + ext.execute_with(|| { + System::set_block_number(1); + assert_eq!(Uniques::force_create(Origin::root(), 1, ALICE, true), Ok(())); + assert_eq!(Uniques::mint(Origin::signed(ALICE), 1, 42, child_account_id(1)), Ok(())); + }); ext } @@ -110,7 +139,7 @@ mod tests { use codec::Encode; use frame_support::assert_ok; - use xcm::latest::{prelude::*, QueryResponseInfo}; + use xcm::latest::QueryResponseInfo; use xcm_simulator::TestExt; // Helper function for forming buy execution message @@ -118,6 +147,13 @@ mod tests { BuyExecution { fees: fees.into(), weight_limit: Unlimited } } + #[test] + fn remote_account_ids_work() { + child_account_account_id(1, ALICE); + sibling_account_account_id(1, ALICE); + parent_account_account_id(ALICE); + } + #[test] fn dmp() { MockNet::reset(); @@ -216,7 +252,7 @@ mod tests { 0, )); assert_eq!( - parachain::Balances::free_balance(¶_account_id(1)), + parachain::Balances::free_balance(&child_account_id(1)), INITIAL_BALANCE + withdraw_amount ); }); @@ -237,18 +273,17 @@ mod tests { let locked_amount = 100; ParaB::execute_with(|| { - let message = Xcm(vec![ - WithdrawAsset((Here, locked_amount).into()), - buy_execution((Here, locked_amount)), - LockAsset { asset: (Here, locked_amount).into(), unlocker: Parachain(1).into() }, - ]); + let message = Xcm(vec![LockAsset { + asset: (Here, locked_amount).into(), + unlocker: (Parachain(1),).into(), + }]); assert_ok!(ParachainPalletXcm::send_xcm(Here, Parent, message.clone())); }); Relay::execute_with(|| { use pallet_balances::{BalanceLock, Reasons}; assert_eq!( - relay_chain::Balances::locks(¶_account_id(2)), + relay_chain::Balances::locks(&child_account_id(2)), vec![BalanceLock { id: *b"py/xcmlk", amount: locked_amount, @@ -268,6 +303,232 @@ mod tests { }); } + /// Scenario: + /// A parachain transfers an NFT resident on the relay chain to another parachain account. + /// + /// Asserts that the parachain accounts are updated as expected. + #[test] + fn withdraw_and_deposit_nft() { + MockNet::reset(); + + Relay::execute_with(|| { + assert_eq!(relay_chain::Uniques::owner(1, 42), Some(child_account_id(1))); + }); + + ParaA::execute_with(|| { + let message = Xcm(vec![TransferAsset { + assets: (GeneralIndex(1), 42u32).into(), + beneficiary: Parachain(2).into(), + }]); + // Send withdraw and deposit + assert_ok!(ParachainPalletXcm::send_xcm(Here, Parent, message)); + }); + + Relay::execute_with(|| { + assert_eq!(relay_chain::Uniques::owner(1, 42), Some(child_account_id(2))); + }); + } + + /// Scenario: + /// The relay-chain teleports an NFT to a parachain. + /// + /// Asserts that the parachain accounts are updated as expected. + #[test] + fn teleport_nft() { + MockNet::reset(); + + Relay::execute_with(|| { + // Mint the NFT (1, 69) and give it to our "parachain#1 alias". + assert_ok!(relay_chain::Uniques::mint( + relay_chain::Origin::signed(ALICE), + 1, + 69, + child_account_account_id(1, ALICE), + )); + // The parachain#1 alias of Alice is what must hold it on the Relay-chain for it to be + // withdrawable by Alice on the parachain. + assert_eq!( + relay_chain::Uniques::owner(1, 69), + Some(child_account_account_id(1, ALICE)) + ); + }); + ParaA::execute_with(|| { + assert_ok!(parachain::ForeignUniques::force_create( + parachain::Origin::root(), + (Parent, GeneralIndex(1)).into(), + ALICE, + false, + )); + assert_eq!( + parachain::ForeignUniques::owner((Parent, GeneralIndex(1)).into(), 69u32.into()), + None, + ); + assert_eq!(parachain::Balances::reserved_balance(&ALICE), 0); + + // IRL Alice would probably just execute this locally on the Relay-chain, but we can't + // easily do that here since we only send between chains. + let message = Xcm(vec![ + WithdrawAsset((GeneralIndex(1), 69u32).into()), + InitiateTeleport { + assets: AllCounted(1).into(), + dest: Parachain(1).into(), + xcm: Xcm(vec![DepositAsset { + assets: AllCounted(1).into(), + beneficiary: (AccountId32 { id: ALICE.into(), network: None },).into(), + }]), + }, + ]); + // Send teleport + let alice = AccountId32 { id: ALICE.into(), network: None }; + assert_ok!(ParachainPalletXcm::send_xcm(alice, Parent, message)); + }); + ParaA::execute_with(|| { + assert_eq!( + parachain::ForeignUniques::owner((Parent, GeneralIndex(1)).into(), 69u32.into()), + Some(ALICE), + ); + assert_eq!(parachain::Balances::reserved_balance(&ALICE), 1000); + }); + Relay::execute_with(|| { + assert_eq!(relay_chain::Uniques::owner(1, 69), None); + }); + } + + /// Scenario: + /// The relay-chain transfers an NFT into a parachain's sovereign account, who then mints a + /// trustless-backed-derivated locally. + /// + /// Asserts that the parachain accounts are updated as expected. + #[test] + fn reserve_asset_transfer_nft() { + sp_tracing::init_for_tests(); + MockNet::reset(); + + Relay::execute_with(|| { + assert_ok!(relay_chain::Uniques::force_create( + relay_chain::Origin::root(), + 2, + ALICE, + false + )); + assert_ok!(relay_chain::Uniques::mint( + relay_chain::Origin::signed(ALICE), + 2, + 69, + child_account_account_id(1, ALICE) + )); + assert_eq!( + relay_chain::Uniques::owner(2, 69), + Some(child_account_account_id(1, ALICE)) + ); + }); + ParaA::execute_with(|| { + assert_ok!(parachain::ForeignUniques::force_create( + parachain::Origin::root(), + (Parent, GeneralIndex(2)).into(), + ALICE, + false, + )); + assert_eq!( + parachain::ForeignUniques::owner((Parent, GeneralIndex(2)).into(), 69u32.into()), + None, + ); + assert_eq!(parachain::Balances::reserved_balance(&ALICE), 0); + + let message = Xcm(vec![ + WithdrawAsset((GeneralIndex(2), 69u32).into()), + DepositReserveAsset { + assets: AllCounted(1).into(), + dest: Parachain(1).into(), + xcm: Xcm(vec![DepositAsset { + assets: AllCounted(1).into(), + beneficiary: (AccountId32 { id: ALICE.into(), network: None },).into(), + }]), + }, + ]); + // Send transfer + let alice = AccountId32 { id: ALICE.into(), network: None }; + assert_ok!(ParachainPalletXcm::send_xcm(alice, Parent, message)); + }); + ParaA::execute_with(|| { + log::debug!(target: "xcm-exceutor", "Hello"); + assert_eq!( + parachain::ForeignUniques::owner((Parent, GeneralIndex(2)).into(), 69u32.into()), + Some(ALICE), + ); + assert_eq!(parachain::Balances::reserved_balance(&ALICE), 1000); + }); + + Relay::execute_with(|| { + assert_eq!(relay_chain::Uniques::owner(2, 69), Some(child_account_id(1))); + }); + } + + /// Scenario: + /// The relay-chain creates an asset class on a parachain and then Alice transfers her NFT into + /// that parachain's sovereign account, who then mints a trustless-backed-derivative locally. + /// + /// Asserts that the parachain accounts are updated as expected. + #[test] + fn reserve_asset_class_create_and_reserve_transfer() { + MockNet::reset(); + + Relay::execute_with(|| { + assert_ok!(relay_chain::Uniques::force_create( + relay_chain::Origin::root(), + 2, + ALICE, + false + )); + assert_ok!(relay_chain::Uniques::mint( + relay_chain::Origin::signed(ALICE), + 2, + 69, + child_account_account_id(1, ALICE) + )); + assert_eq!( + relay_chain::Uniques::owner(2, 69), + Some(child_account_account_id(1, ALICE)) + ); + + let message = Xcm(vec![Transact { + origin_kind: OriginKind::Xcm, + require_weight_at_most: 1_000_000_000, + call: parachain::Call::from(pallet_uniques::Call::::create { + class: (Parent, 2u64).into(), + admin: parent_account_id(), + }) + .encode() + .into(), + }]); + // Send creation. + assert_ok!(RelayChainPalletXcm::send_xcm(Here, Parachain(1), message)); + }); + ParaA::execute_with(|| { + // Then transfer + let message = Xcm(vec![ + WithdrawAsset((GeneralIndex(2), 69u32).into()), + DepositReserveAsset { + assets: AllCounted(1).into(), + dest: Parachain(1).into(), + xcm: Xcm(vec![DepositAsset { + assets: AllCounted(1).into(), + beneficiary: (AccountId32 { id: ALICE.into(), network: None },).into(), + }]), + }, + ]); + let alice = AccountId32 { id: ALICE.into(), network: None }; + assert_ok!(ParachainPalletXcm::send_xcm(alice, Parent, message)); + }); + ParaA::execute_with(|| { + assert_eq!(parachain::Balances::reserved_balance(&parent_account_id()), 1000); + assert_eq!( + parachain::ForeignUniques::class_owner((Parent, 2u64).into()), + Some(parent_account_id()) + ); + }); + } + /// Scenario: /// A parachain transfers funds on the relay chain to another parachain account. /// @@ -290,11 +551,11 @@ mod tests { Relay::execute_with(|| { assert_eq!( - relay_chain::Balances::free_balance(para_account_id(1)), + relay_chain::Balances::free_balance(child_account_id(1)), INITIAL_BALANCE - send_amount ); assert_eq!( - relay_chain::Balances::free_balance(para_account_id(2)), + relay_chain::Balances::free_balance(child_account_id(2)), INITIAL_BALANCE + send_amount ); }); @@ -335,12 +596,12 @@ mod tests { Relay::execute_with(|| { // Withdraw executed assert_eq!( - relay_chain::Balances::free_balance(para_account_id(1)), + relay_chain::Balances::free_balance(child_account_id(1)), INITIAL_BALANCE - send_amount ); // Deposit executed assert_eq!( - relay_chain::Balances::free_balance(para_account_id(2)), + relay_chain::Balances::free_balance(child_account_id(2)), INITIAL_BALANCE + send_amount ); }); diff --git a/xcm/xcm-simulator/example/src/parachain.rs b/xcm/xcm-simulator/example/src/parachain.rs index f7f8588fe382..ac322dddb499 100644 --- a/xcm/xcm-simulator/example/src/parachain.rs +++ b/xcm/xcm-simulator/example/src/parachain.rs @@ -19,7 +19,7 @@ use codec::{Decode, Encode}; use frame_support::{ construct_runtime, parameter_types, - traits::{Everything, Nothing}, + traits::{EnsureOrigin, EnsureOriginWithArg, Everything, EverythingBut, Nothing}, weights::{constants::WEIGHT_PER_SECOND, Weight}, }; use sp_core::H256; @@ -37,12 +37,22 @@ use polkadot_parachain::primitives::{ }; use xcm::{latest::prelude::*, VersionedXcm}; use xcm_builder::{ - AccountId32Aliases, AllowUnpaidExecutionFrom, CurrencyAdapter as XcmCurrencyAdapter, - EnsureXcmOrigin, FixedRateOfFungible, FixedWeightBounds, IsConcrete, LocationInverter, - NativeAsset, ParentIsPreset, SiblingParachainConvertsVia, SignedAccountId32AsNative, - SignedToAccountId32, SovereignSignedViaLocation, + Account32Hash, AccountId32Aliases, AllowUnpaidExecutionFrom, ConvertedConcreteId, + CurrencyAdapter as XcmCurrencyAdapter, EnsureXcmOrigin, FixedRateOfFungible, FixedWeightBounds, + IsConcrete, LocationInverter, NativeAsset, NonFungiblesAdapter, ParentIsPreset, + SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, + SovereignSignedViaLocation, +}; +use xcm_executor::{ + traits::{Convert, JustTry}, + Config, XcmExecutor, }; -use xcm_executor::{Config, XcmExecutor}; + +pub type SovereignAccountOf = ( + SiblingParachainConvertsVia, + AccountId32Aliases, + ParentIsPreset, +); pub type AccountId = AccountId32; pub type Balance = u128; @@ -96,6 +106,58 @@ impl pallet_balances::Config for Runtime { type ReserveIdentifier = [u8; 8]; } +#[cfg(feature = "runtime-benchmarks")] +pub struct UniquesHelper; +#[cfg(feature = "runtime-benchmarks")] +impl pallet_uniques::BenchmarkHelper for UniquesHelper { + fn class(i: u16) -> MultiLocation { + GeneralIndex(i as u128).into() + } + fn instance(i: u16) -> AssetInstance { + AssetInstance::Index(i as u128) + } +} + +impl pallet_uniques::Config for Runtime { + type Event = Event; + type ClassId = MultiLocation; + type InstanceId = AssetInstance; + type Currency = Balances; + type CreateOrigin = ForeignCreators; + type ForceOrigin = frame_system::EnsureRoot; + type ClassDeposit = frame_support::traits::ConstU128<1_000>; + type InstanceDeposit = frame_support::traits::ConstU128<1_000>; + type MetadataDepositBase = frame_support::traits::ConstU128<1_000>; + type AttributeDepositBase = frame_support::traits::ConstU128<1_000>; + type DepositPerByte = frame_support::traits::ConstU128<1>; + type StringLimit = frame_support::traits::ConstU32<64>; + type KeyLimit = frame_support::traits::ConstU32<64>; + type ValueLimit = frame_support::traits::ConstU32<128>; + type WeightInfo = (); + #[cfg(feature = "runtime-benchmarks")] + type Helper = UniquesHelper; +} + +// `EnsureOriginWithArg` impl for `CreateOrigin` which allows only XCM origins +// which are locations containing the class location. +pub struct ForeignCreators; +impl EnsureOriginWithArg for ForeignCreators { + type Success = AccountId; + + fn try_origin(o: Origin, a: &MultiLocation) -> sp_std::result::Result { + let origin_location = pallet_xcm::EnsureXcm::::try_origin(o.clone())?; + if !a.starts_with(&origin_location) { + return Err(o) + } + SovereignAccountOf::convert(origin_location).map_err(|_| o) + } + + #[cfg(feature = "runtime-benchmarks")] + fn successful_origin(a: &MultiLocation) -> Origin { + pallet_xcm::Origin::Xcm(a.clone()).into() + } +} + parameter_types! { pub const ReservedXcmpWeight: Weight = WEIGHT_PER_SECOND / 4; pub const ReservedDmpWeight: Weight = WEIGHT_PER_SECOND / 4; @@ -111,6 +173,7 @@ pub type LocationToAccountId = ( ParentIsPreset, SiblingParachainConvertsVia, AccountId32Aliases, + Account32Hash<(), AccountId>, ); pub type XcmOriginToCallOrigin = ( @@ -124,22 +187,41 @@ parameter_types! { pub KsmPerSecond: (AssetId, u128) = (Concrete(Parent.into()), 1); pub const MaxInstructions: u32 = 100; pub const MaxAssetsIntoHolding: u32 = 64; + pub ForeignPrefix: MultiLocation = (Parent,).into(); } -pub type LocalAssetTransactor = - XcmCurrencyAdapter, LocationToAccountId, AccountId, ()>; +pub type LocalAssetTransactor = ( + XcmCurrencyAdapter, LocationToAccountId, AccountId, ()>, + NonFungiblesAdapter< + ForeignUniques, + ConvertedConcreteId, + SovereignAccountOf, + AccountId, + Nothing, + (), + >, +); pub type XcmRouter = super::ParachainXcmRouter; pub type Barrier = AllowUnpaidExecutionFrom; +parameter_types! { + pub NftCollectionOne: MultiAssetFilter + = Wild(AllOf { fun: WildNonFungible, id: Concrete((Parent, GeneralIndex(1)).into()) }); + pub NftCollectionOneForRelay: (MultiAssetFilter, MultiLocation) + = (NftCollectionOne::get(), (Parent,).into()); +} +pub type TrustedTeleporters = xcm_builder::Case; +pub type TrustedReserves = EverythingBut>; + pub struct XcmConfig; impl Config for XcmConfig { type Call = Call; type XcmSender = XcmRouter; type AssetTransactor = LocalAssetTransactor; type OriginConverter = XcmOriginToCallOrigin; - type IsReserve = NativeAsset; - type IsTeleporter = (); + type IsReserve = (NativeAsset, TrustedReserves); + type IsTeleporter = TrustedTeleporters; type LocationInverter = LocationInverter; type Barrier = Barrier; type Weigher = FixedWeightBounds; @@ -338,5 +420,6 @@ construct_runtime!( Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, MsgQueue: mock_msg_queue::{Pallet, Storage, Event}, PolkadotXcm: pallet_xcm::{Pallet, Call, Event, Origin}, + ForeignUniques: pallet_uniques::{Pallet, Call, Storage, Event}, } ); diff --git a/xcm/xcm-simulator/example/src/relay_chain.rs b/xcm/xcm-simulator/example/src/relay_chain.rs index 5bf0613b5e28..256780e0c692 100644 --- a/xcm/xcm-simulator/example/src/relay_chain.rs +++ b/xcm/xcm-simulator/example/src/relay_chain.rs @@ -18,7 +18,7 @@ use frame_support::{ construct_runtime, parameter_types, - traits::{Everything, Nothing}, + traits::{AsEnsureOriginWithArg, Everything, Nothing}, weights::Weight, }; use sp_core::H256; @@ -28,12 +28,13 @@ use polkadot_parachain::primitives::Id as ParaId; use polkadot_runtime_parachains::{configuration, origin, shared, ump}; use xcm::latest::prelude::*; use xcm_builder::{ - AccountId32Aliases, AllowUnpaidExecutionFrom, ChildParachainAsNative, - ChildParachainConvertsVia, ChildSystemParachainAsSuperuser, - CurrencyAdapter as XcmCurrencyAdapter, FixedRateOfFungible, FixedWeightBounds, IsConcrete, - LocationInverter, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, + Account32Hash, AccountId32Aliases, AllowUnpaidExecutionFrom, AsPrefixedGeneralIndex, + ChildParachainAsNative, ChildParachainConvertsVia, ChildSystemParachainAsSuperuser, + ConvertedConcreteId, CurrencyAdapter as XcmCurrencyAdapter, FixedRateOfFungible, + FixedWeightBounds, IsConcrete, LocationInverter, NonFungiblesAdapter, + SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, }; -use xcm_executor::{Config, XcmExecutor}; +use xcm_executor::{traits::JustTry, Config, XcmExecutor}; pub type AccountId = AccountId32; pub type Balance = u128; @@ -87,6 +88,26 @@ impl pallet_balances::Config for Runtime { type ReserveIdentifier = [u8; 8]; } +impl pallet_uniques::Config for Runtime { + type Event = Event; + type ClassId = u32; + type InstanceId = u32; + type Currency = Balances; + type CreateOrigin = AsEnsureOriginWithArg>; + type ForceOrigin = frame_system::EnsureRoot; + type ClassDeposit = frame_support::traits::ConstU128<1_000>; + type InstanceDeposit = frame_support::traits::ConstU128<1_000>; + type MetadataDepositBase = frame_support::traits::ConstU128<1_000>; + type AttributeDepositBase = frame_support::traits::ConstU128<1_000>; + type DepositPerByte = frame_support::traits::ConstU128<1>; + type StringLimit = frame_support::traits::ConstU32<64>; + type KeyLimit = frame_support::traits::ConstU32<64>; + type ValueLimit = frame_support::traits::ConstU32<128>; + type WeightInfo = (); + #[cfg(feature = "runtime-benchmarks")] + type Helper = (); +} + impl shared::Config for Runtime {} impl configuration::Config for Runtime { @@ -101,14 +122,26 @@ parameter_types! { pub UnitWeightCost: Weight = 1_000; } -pub type SovereignAccountOf = - (ChildParachainConvertsVia, AccountId32Aliases); +pub type LocationToAccountId = ( + ChildParachainConvertsVia, + AccountId32Aliases, + Account32Hash<(), AccountId>, +); -pub type LocalAssetTransactor = - XcmCurrencyAdapter, SovereignAccountOf, AccountId, ()>; +pub type LocalAssetTransactor = ( + XcmCurrencyAdapter, LocationToAccountId, AccountId, ()>, + NonFungiblesAdapter< + Uniques, + ConvertedConcreteId, JustTry>, + LocationToAccountId, + AccountId, + Nothing, + (), + >, +); type LocalOriginConverter = ( - SovereignSignedViaLocation, + SovereignSignedViaLocation, ChildParachainAsNative, SignedAccountId32AsNative, ChildSystemParachainAsSuperuser, @@ -116,7 +149,7 @@ type LocalOriginConverter = ( parameter_types! { pub const BaseXcmWeight: Weight = 1_000; - pub KsmPerSecond: (AssetId, u128) = (Concrete(TokenLocation::get()), 1); + pub TokensPerSecond: (AssetId, u128) = (Concrete(TokenLocation::get()), 1_000_000_000_000); pub const MaxInstructions: u32 = 100; pub const MaxAssetsIntoHolding: u32 = 64; } @@ -135,7 +168,7 @@ impl Config for XcmConfig { type LocationInverter = LocationInverter; type Barrier = Barrier; type Weigher = FixedWeightBounds; - type Trader = FixedRateOfFungible; + type Trader = FixedRateOfFungible; type ResponseHandler = (); type AssetTrap = (); type AssetLocker = XcmPallet; @@ -170,7 +203,7 @@ impl pallet_xcm::Config for Runtime { type Currency = Balances; type CurrencyMatcher = IsConcrete; type TrustedLockers = (); - type SovereignAccountOf = SovereignAccountOf; + type SovereignAccountOf = LocationToAccountId; type MaxLockers = frame_support::traits::ConstU32<8>; } @@ -202,5 +235,6 @@ construct_runtime!( ParasOrigin: origin::{Pallet, Origin}, ParasUmp: ump::{Pallet, Call, Storage, Event}, XcmPallet: pallet_xcm::{Pallet, Call, Storage, Event, Origin}, + Uniques: pallet_uniques::{Pallet, Call, Storage, Event}, } );