mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 22:11:02 +00:00
XCMv4 (#1230)
# Note for reviewer
Most changes are just syntax changes necessary for the new version.
Most important files should be the ones under the `xcm` folder.
# Description
Added XCMv4.
## Removed `Multi` prefix
The following types have been renamed:
- MultiLocation -> Location
- MultiAsset -> Asset
- MultiAssets -> Assets
- InteriorMultiLocation -> InteriorLocation
- MultiAssetFilter -> AssetFilter
- VersionedMultiAsset -> VersionedAsset
- WildMultiAsset -> WildAsset
- VersionedMultiLocation -> VersionedLocation
In order to fix a name conflict, the `Assets` in `xcm-executor` were
renamed to `HoldingAssets`, as they represent assets in holding.
## Removed `Abstract` asset id
It was not being used anywhere and this simplifies the code.
Now assets are just constructed as follows:
```rust
let asset: Asset = (AssetId(Location::new(1, Here)), 100u128).into();
```
No need for specifying `Concrete` anymore.
## Outcome is now a named fields struct
Instead of
```rust
pub enum Outcome {
Complete(Weight),
Incomplete(Weight, Error),
Error(Error),
}
```
we now have
```rust
pub enum Outcome {
Complete { used: Weight },
Incomplete { used: Weight, error: Error },
Error { error: Error },
}
```
## Added Reanchorable trait
Now both locations and assets implement this trait, making it easier to
reanchor both.
## New syntax for building locations and junctions
Now junctions are built using the following methods:
```rust
let location = Location {
parents: 1,
interior: [Parachain(1000), PalletInstance(50), GeneralIndex(1984)].into()
};
```
or
```rust
let location = Location::new(1, [Parachain(1000), PalletInstance(50), GeneralIndex(1984)]);
```
And they are matched like so:
```rust
match location.unpack() {
(1, [Parachain(id)]) => ...
(0, Here) => ...,
(1, [_]) => ...,
}
```
This syntax is mandatory in v4, and has been also implemented for v2 and
v3 for easier migration.
This was needed to make all sizes smaller.
# TODO
- [x] Scaffold v4
- [x] Port github.com/paritytech/polkadot/pull/7236
- [x] Remove `Multi` prefix
- [x] Remove `Abstract` asset id
---------
Co-authored-by: command-bot <>
Co-authored-by: Keith Yeung <kungfukeith11@gmail.com>
This commit is contained in:
committed by
GitHub
parent
ec7bfae00a
commit
8428f678fe
@@ -19,26 +19,25 @@ use sp_std::marker::PhantomData;
|
||||
use xcm::latest::prelude::*;
|
||||
|
||||
/// Creates asset pairs for liquidity pools with `Target` always being the first asset.
|
||||
pub struct AssetPairFactory<Target, SelfParaId, PalletId>(
|
||||
PhantomData<(Target, SelfParaId, PalletId)>,
|
||||
pub struct AssetPairFactory<Target, SelfParaId, PalletId, L = Location>(
|
||||
PhantomData<(Target, SelfParaId, PalletId, L)>,
|
||||
);
|
||||
impl<Target: Get<MultiLocation>, SelfParaId: Get<ParaId>, PalletId: Get<u32>>
|
||||
pallet_asset_conversion::BenchmarkHelper<MultiLocation>
|
||||
for AssetPairFactory<Target, SelfParaId, PalletId>
|
||||
impl<Target: Get<L>, SelfParaId: Get<ParaId>, PalletId: Get<u32>, L: TryFrom<Location>>
|
||||
pallet_asset_conversion::BenchmarkHelper<L> for AssetPairFactory<Target, SelfParaId, PalletId, L>
|
||||
{
|
||||
fn create_pair(seed1: u32, seed2: u32) -> (MultiLocation, MultiLocation) {
|
||||
let with_id = MultiLocation::new(
|
||||
fn create_pair(seed1: u32, seed2: u32) -> (L, L) {
|
||||
let with_id = Location::new(
|
||||
1,
|
||||
X3(
|
||||
[
|
||||
Parachain(SelfParaId::get().into()),
|
||||
PalletInstance(PalletId::get() as u8),
|
||||
GeneralIndex(seed2.into()),
|
||||
),
|
||||
],
|
||||
);
|
||||
if seed1 % 2 == 0 {
|
||||
(with_id, Target::get())
|
||||
(with_id.try_into().map_err(|_| "Something went wrong").unwrap(), Target::get())
|
||||
} else {
|
||||
(Target::get(), with_id)
|
||||
(Target::get(), with_id.try_into().map_err(|_| "Something went wrong").unwrap())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,21 +17,21 @@ use frame_support::traits::{
|
||||
ContainsPair, EnsureOrigin, EnsureOriginWithArg, Everything, OriginTrait,
|
||||
};
|
||||
use pallet_xcm::{EnsureXcm, Origin as XcmOrigin};
|
||||
use xcm::latest::MultiLocation;
|
||||
use xcm::latest::Location;
|
||||
use xcm_executor::traits::ConvertLocation;
|
||||
|
||||
/// `EnsureOriginWithArg` impl for `CreateOrigin` that allows only XCM origins that are locations
|
||||
/// containing the class location.
|
||||
pub struct ForeignCreators<IsForeign, AccountOf, AccountId>(
|
||||
sp_std::marker::PhantomData<(IsForeign, AccountOf, AccountId)>,
|
||||
pub struct ForeignCreators<IsForeign, AccountOf, AccountId, L = Location>(
|
||||
sp_std::marker::PhantomData<(IsForeign, AccountOf, AccountId, L)>,
|
||||
);
|
||||
impl<
|
||||
IsForeign: ContainsPair<MultiLocation, MultiLocation>,
|
||||
IsForeign: ContainsPair<L, L>,
|
||||
AccountOf: ConvertLocation<AccountId>,
|
||||
AccountId: Clone,
|
||||
RuntimeOrigin: From<XcmOrigin> + OriginTrait + Clone,
|
||||
> EnsureOriginWithArg<RuntimeOrigin, MultiLocation>
|
||||
for ForeignCreators<IsForeign, AccountOf, AccountId>
|
||||
L: TryFrom<Location> + TryInto<Location> + Clone,
|
||||
> EnsureOriginWithArg<RuntimeOrigin, L> for ForeignCreators<IsForeign, AccountOf, AccountId, L>
|
||||
where
|
||||
RuntimeOrigin::PalletsOrigin:
|
||||
From<XcmOrigin> + TryInto<XcmOrigin, Error = RuntimeOrigin::PalletsOrigin>,
|
||||
@@ -40,17 +40,20 @@ where
|
||||
|
||||
fn try_origin(
|
||||
origin: RuntimeOrigin,
|
||||
asset_location: &MultiLocation,
|
||||
asset_location: &L,
|
||||
) -> sp_std::result::Result<Self::Success, RuntimeOrigin> {
|
||||
let origin_location = EnsureXcm::<Everything>::try_origin(origin.clone())?;
|
||||
let origin_location = EnsureXcm::<Everything, L>::try_origin(origin.clone())?;
|
||||
if !IsForeign::contains(asset_location, &origin_location) {
|
||||
return Err(origin)
|
||||
}
|
||||
AccountOf::convert_location(&origin_location).ok_or(origin)
|
||||
let latest_location: Location =
|
||||
origin_location.clone().try_into().map_err(|_| origin.clone())?;
|
||||
AccountOf::convert_location(&latest_location).ok_or(origin)
|
||||
}
|
||||
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
fn try_successful_origin(a: &MultiLocation) -> Result<RuntimeOrigin, ()> {
|
||||
Ok(pallet_xcm::Origin::Xcm(*a).into())
|
||||
fn try_successful_origin(a: &L) -> Result<RuntimeOrigin, ()> {
|
||||
let latest_location: Location = (*a).clone().try_into().map_err(|_| ())?;
|
||||
Ok(pallet_xcm::Origin::Xcm(latest_location).into())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,52 +19,48 @@ use crate::runtime_api::FungiblesAccessError;
|
||||
use frame_support::traits::Contains;
|
||||
use sp_runtime::traits::MaybeEquivalence;
|
||||
use sp_std::{borrow::Borrow, vec::Vec};
|
||||
use xcm::latest::{MultiAsset, MultiLocation};
|
||||
use xcm::latest::{Asset, Location};
|
||||
use xcm_builder::{ConvertedConcreteId, MatchedConvertedConcreteId};
|
||||
use xcm_executor::traits::MatchesFungibles;
|
||||
|
||||
/// Converting any [`(AssetId, Balance)`] to [`MultiAsset`]
|
||||
pub trait MultiAssetConverter<AssetId, Balance, ConvertAssetId, ConvertBalance>:
|
||||
/// Converting any [`(AssetId, Balance)`] to [`Asset`]
|
||||
pub trait AssetConverter<AssetId, Balance, ConvertAssetId, ConvertBalance>:
|
||||
MatchesFungibles<AssetId, Balance>
|
||||
where
|
||||
AssetId: Clone,
|
||||
Balance: Clone,
|
||||
ConvertAssetId: MaybeEquivalence<MultiLocation, AssetId>,
|
||||
ConvertAssetId: MaybeEquivalence<Location, AssetId>,
|
||||
ConvertBalance: MaybeEquivalence<u128, Balance>,
|
||||
{
|
||||
fn convert_ref(
|
||||
value: impl Borrow<(AssetId, Balance)>,
|
||||
) -> Result<MultiAsset, FungiblesAccessError>;
|
||||
fn convert_ref(value: impl Borrow<(AssetId, Balance)>) -> Result<Asset, FungiblesAccessError>;
|
||||
}
|
||||
|
||||
/// Checks for `MultiLocation`.
|
||||
pub trait MatchesMultiLocation<AssetId, Balance, MatchAssetId, ConvertAssetId, ConvertBalance>:
|
||||
/// Checks for `Location`.
|
||||
pub trait MatchesLocation<AssetId, Balance, MatchAssetId, ConvertAssetId, ConvertBalance>:
|
||||
MatchesFungibles<AssetId, Balance>
|
||||
where
|
||||
AssetId: Clone,
|
||||
Balance: Clone,
|
||||
MatchAssetId: Contains<MultiLocation>,
|
||||
ConvertAssetId: MaybeEquivalence<MultiLocation, AssetId>,
|
||||
MatchAssetId: Contains<Location>,
|
||||
ConvertAssetId: MaybeEquivalence<Location, AssetId>,
|
||||
ConvertBalance: MaybeEquivalence<u128, Balance>,
|
||||
{
|
||||
fn contains(location: &MultiLocation) -> bool;
|
||||
fn contains(location: &Location) -> bool;
|
||||
}
|
||||
|
||||
impl<
|
||||
AssetId: Clone,
|
||||
Balance: Clone,
|
||||
ConvertAssetId: MaybeEquivalence<MultiLocation, AssetId>,
|
||||
ConvertAssetId: MaybeEquivalence<Location, AssetId>,
|
||||
ConvertBalance: MaybeEquivalence<u128, Balance>,
|
||||
> MultiAssetConverter<AssetId, Balance, ConvertAssetId, ConvertBalance>
|
||||
> AssetConverter<AssetId, Balance, ConvertAssetId, ConvertBalance>
|
||||
for ConvertedConcreteId<AssetId, Balance, ConvertAssetId, ConvertBalance>
|
||||
{
|
||||
fn convert_ref(
|
||||
value: impl Borrow<(AssetId, Balance)>,
|
||||
) -> Result<MultiAsset, FungiblesAccessError> {
|
||||
fn convert_ref(value: impl Borrow<(AssetId, Balance)>) -> Result<Asset, FungiblesAccessError> {
|
||||
let (asset_id, balance) = value.borrow();
|
||||
match ConvertAssetId::convert_back(asset_id) {
|
||||
Some(asset_id_as_multilocation) => match ConvertBalance::convert_back(balance) {
|
||||
Some(amount) => Ok((asset_id_as_multilocation, amount).into()),
|
||||
Some(asset_id_as_location) => match ConvertBalance::convert_back(balance) {
|
||||
Some(amount) => Ok((asset_id_as_location, amount).into()),
|
||||
None => Err(FungiblesAccessError::AmountToBalanceConversionFailed),
|
||||
},
|
||||
None => Err(FungiblesAccessError::AssetIdConversionFailed),
|
||||
@@ -75,19 +71,17 @@ impl<
|
||||
impl<
|
||||
AssetId: Clone,
|
||||
Balance: Clone,
|
||||
MatchAssetId: Contains<MultiLocation>,
|
||||
ConvertAssetId: MaybeEquivalence<MultiLocation, AssetId>,
|
||||
MatchAssetId: Contains<Location>,
|
||||
ConvertAssetId: MaybeEquivalence<Location, AssetId>,
|
||||
ConvertBalance: MaybeEquivalence<u128, Balance>,
|
||||
> MultiAssetConverter<AssetId, Balance, ConvertAssetId, ConvertBalance>
|
||||
> AssetConverter<AssetId, Balance, ConvertAssetId, ConvertBalance>
|
||||
for MatchedConvertedConcreteId<AssetId, Balance, MatchAssetId, ConvertAssetId, ConvertBalance>
|
||||
{
|
||||
fn convert_ref(
|
||||
value: impl Borrow<(AssetId, Balance)>,
|
||||
) -> Result<MultiAsset, FungiblesAccessError> {
|
||||
fn convert_ref(value: impl Borrow<(AssetId, Balance)>) -> Result<Asset, FungiblesAccessError> {
|
||||
let (asset_id, balance) = value.borrow();
|
||||
match ConvertAssetId::convert_back(asset_id) {
|
||||
Some(asset_id_as_multilocation) => match ConvertBalance::convert_back(balance) {
|
||||
Some(amount) => Ok((asset_id_as_multilocation, amount).into()),
|
||||
Some(asset_id_as_location) => match ConvertBalance::convert_back(balance) {
|
||||
Some(amount) => Ok((asset_id_as_location, amount).into()),
|
||||
None => Err(FungiblesAccessError::AmountToBalanceConversionFailed),
|
||||
},
|
||||
None => Err(FungiblesAccessError::AssetIdConversionFailed),
|
||||
@@ -98,13 +92,13 @@ impl<
|
||||
impl<
|
||||
AssetId: Clone,
|
||||
Balance: Clone,
|
||||
MatchAssetId: Contains<MultiLocation>,
|
||||
ConvertAssetId: MaybeEquivalence<MultiLocation, AssetId>,
|
||||
MatchAssetId: Contains<Location>,
|
||||
ConvertAssetId: MaybeEquivalence<Location, AssetId>,
|
||||
ConvertBalance: MaybeEquivalence<u128, Balance>,
|
||||
> MatchesMultiLocation<AssetId, Balance, MatchAssetId, ConvertAssetId, ConvertBalance>
|
||||
> MatchesLocation<AssetId, Balance, MatchAssetId, ConvertAssetId, ConvertBalance>
|
||||
for MatchedConvertedConcreteId<AssetId, Balance, MatchAssetId, ConvertAssetId, ConvertBalance>
|
||||
{
|
||||
fn contains(location: &MultiLocation) -> bool {
|
||||
fn contains(location: &Location) -> bool {
|
||||
MatchAssetId::contains(location)
|
||||
}
|
||||
}
|
||||
@@ -113,12 +107,12 @@ impl<
|
||||
impl<
|
||||
AssetId: Clone,
|
||||
Balance: Clone,
|
||||
MatchAssetId: Contains<MultiLocation>,
|
||||
ConvertAssetId: MaybeEquivalence<MultiLocation, AssetId>,
|
||||
MatchAssetId: Contains<Location>,
|
||||
ConvertAssetId: MaybeEquivalence<Location, AssetId>,
|
||||
ConvertBalance: MaybeEquivalence<u128, Balance>,
|
||||
> MatchesMultiLocation<AssetId, Balance, MatchAssetId, ConvertAssetId, ConvertBalance> for Tuple
|
||||
> MatchesLocation<AssetId, Balance, MatchAssetId, ConvertAssetId, ConvertBalance> for Tuple
|
||||
{
|
||||
fn contains(location: &MultiLocation) -> bool {
|
||||
fn contains(location: &Location) -> bool {
|
||||
for_tuples!( #(
|
||||
match Tuple::contains(location) { o @ true => return o, _ => () }
|
||||
)* );
|
||||
@@ -127,27 +121,24 @@ impl<
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper function to convert collections with [`(AssetId, Balance)`] to [`MultiAsset`]
|
||||
/// Helper function to convert collections with [`(AssetId, Balance)`] to [`Asset`]
|
||||
pub fn convert<'a, AssetId, Balance, ConvertAssetId, ConvertBalance, Converter>(
|
||||
items: impl Iterator<Item = &'a (AssetId, Balance)>,
|
||||
) -> Result<Vec<MultiAsset>, FungiblesAccessError>
|
||||
) -> Result<Vec<Asset>, FungiblesAccessError>
|
||||
where
|
||||
AssetId: Clone + 'a,
|
||||
Balance: Clone + 'a,
|
||||
ConvertAssetId: MaybeEquivalence<MultiLocation, AssetId>,
|
||||
ConvertAssetId: MaybeEquivalence<Location, AssetId>,
|
||||
ConvertBalance: MaybeEquivalence<u128, Balance>,
|
||||
Converter: MultiAssetConverter<AssetId, Balance, ConvertAssetId, ConvertBalance>,
|
||||
Converter: AssetConverter<AssetId, Balance, ConvertAssetId, ConvertBalance>,
|
||||
{
|
||||
items.map(Converter::convert_ref).collect()
|
||||
}
|
||||
|
||||
/// Helper function to convert `Balance` with MultiLocation` to `MultiAsset`
|
||||
pub fn convert_balance<
|
||||
T: frame_support::pallet_prelude::Get<MultiLocation>,
|
||||
Balance: TryInto<u128>,
|
||||
>(
|
||||
/// Helper function to convert `Balance` with Location` to `Asset`
|
||||
pub fn convert_balance<T: frame_support::pallet_prelude::Get<Location>, Balance: TryInto<u128>>(
|
||||
balance: Balance,
|
||||
) -> Result<MultiAsset, FungiblesAccessError> {
|
||||
) -> Result<Asset, FungiblesAccessError> {
|
||||
match balance.try_into() {
|
||||
Ok(balance) => Ok((T::get(), balance).into()),
|
||||
Err(_) => Err(FungiblesAccessError::AmountToBalanceConversionFailed),
|
||||
@@ -162,20 +153,20 @@ mod tests {
|
||||
use xcm::latest::prelude::*;
|
||||
use xcm_executor::traits::{Identity, JustTry};
|
||||
|
||||
type Converter = MatchedConvertedConcreteId<MultiLocation, u64, Everything, Identity, JustTry>;
|
||||
type Converter = MatchedConvertedConcreteId<Location, u64, Everything, Identity, JustTry>;
|
||||
|
||||
#[test]
|
||||
fn converted_concrete_id_fungible_multi_asset_conversion_roundtrip_works() {
|
||||
let location = MultiLocation::new(0, X1(GlobalConsensus(ByGenesis([0; 32]))));
|
||||
let location = Location::new(0, [GlobalConsensus(ByGenesis([0; 32]))]);
|
||||
let amount = 123456_u64;
|
||||
let expected_multi_asset = MultiAsset {
|
||||
id: Concrete(MultiLocation::new(0, X1(GlobalConsensus(ByGenesis([0; 32]))))),
|
||||
let expected_multi_asset = Asset {
|
||||
id: AssetId(Location::new(0, [GlobalConsensus(ByGenesis([0; 32]))])),
|
||||
fun: Fungible(123456_u128),
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
Converter::matches_fungibles(&expected_multi_asset).map_err(|_| ()),
|
||||
Ok((location, amount))
|
||||
Ok((location.clone(), amount))
|
||||
);
|
||||
|
||||
assert_eq!(Converter::convert_ref((location, amount)), Ok(expected_multi_asset));
|
||||
@@ -184,17 +175,17 @@ mod tests {
|
||||
#[test]
|
||||
fn converted_concrete_id_fungible_multi_asset_conversion_collection_works() {
|
||||
let data = vec![
|
||||
(MultiLocation::new(0, X1(GlobalConsensus(ByGenesis([0; 32])))), 123456_u64),
|
||||
(MultiLocation::new(1, X1(GlobalConsensus(ByGenesis([1; 32])))), 654321_u64),
|
||||
(Location::new(0, [GlobalConsensus(ByGenesis([0; 32]))]), 123456_u64),
|
||||
(Location::new(1, [GlobalConsensus(ByGenesis([1; 32]))]), 654321_u64),
|
||||
];
|
||||
|
||||
let expected_data = vec![
|
||||
MultiAsset {
|
||||
id: Concrete(MultiLocation::new(0, X1(GlobalConsensus(ByGenesis([0; 32]))))),
|
||||
Asset {
|
||||
id: AssetId(Location::new(0, [GlobalConsensus(ByGenesis([0; 32]))])),
|
||||
fun: Fungible(123456_u128),
|
||||
},
|
||||
MultiAsset {
|
||||
id: Concrete(MultiLocation::new(1, X1(GlobalConsensus(ByGenesis([1; 32]))))),
|
||||
Asset {
|
||||
id: AssetId(Location::new(1, [GlobalConsensus(ByGenesis([1; 32]))])),
|
||||
fun: Fungible(654321_u128),
|
||||
},
|
||||
];
|
||||
|
||||
@@ -23,15 +23,24 @@ pub mod local_and_foreign_assets;
|
||||
pub mod matching;
|
||||
pub mod runtime_api;
|
||||
|
||||
use crate::matching::{LocalMultiLocationPattern, ParentLocation};
|
||||
use crate::matching::{LocalLocationPattern, ParentLocation};
|
||||
use frame_support::traits::{Equals, EverythingBut};
|
||||
use parachains_common::AssetIdForTrustBackedAssets;
|
||||
use xcm::prelude::MultiLocation;
|
||||
use xcm_builder::{AsPrefixedGeneralIndex, MatchedConvertedConcreteId, StartsWith};
|
||||
use xcm_executor::traits::{Identity, JustTry};
|
||||
use xcm_builder::{
|
||||
AsPrefixedGeneralIndex, MatchedConvertedConcreteId, StartsWith, V4V3LocationConverter,
|
||||
};
|
||||
use xcm_executor::traits::JustTry;
|
||||
|
||||
/// `MultiLocation` vs `AssetIdForTrustBackedAssets` converter for `TrustBackedAssets`
|
||||
/// `Location` vs `AssetIdForTrustBackedAssets` converter for `TrustBackedAssets`
|
||||
pub type AssetIdForTrustBackedAssetsConvert<TrustBackedAssetsPalletLocation> =
|
||||
AsPrefixedGeneralIndex<
|
||||
TrustBackedAssetsPalletLocation,
|
||||
AssetIdForTrustBackedAssets,
|
||||
JustTry,
|
||||
xcm::v3::Location,
|
||||
>;
|
||||
|
||||
pub type AssetIdForTrustBackedAssetsConvertLatest<TrustBackedAssetsPalletLocation> =
|
||||
AsPrefixedGeneralIndex<TrustBackedAssetsPalletLocation, AssetIdForTrustBackedAssets, JustTry>;
|
||||
|
||||
/// [`MatchedConvertedConcreteId`] converter dedicated for `TrustBackedAssets`
|
||||
@@ -40,59 +49,55 @@ pub type TrustBackedAssetsConvertedConcreteId<TrustBackedAssetsPalletLocation, B
|
||||
AssetIdForTrustBackedAssets,
|
||||
Balance,
|
||||
StartsWith<TrustBackedAssetsPalletLocation>,
|
||||
AssetIdForTrustBackedAssetsConvert<TrustBackedAssetsPalletLocation>,
|
||||
AssetIdForTrustBackedAssetsConvertLatest<TrustBackedAssetsPalletLocation>,
|
||||
JustTry,
|
||||
>;
|
||||
|
||||
/// AssetId used for identifying assets by MultiLocation.
|
||||
pub type MultiLocationForAssetId = MultiLocation;
|
||||
/// [`MatchedConvertedConcreteId`] converter dedicated for storing `AssetId` as `Location`.
|
||||
pub type LocationConvertedConcreteId<LocationFilter, Balance> = MatchedConvertedConcreteId<
|
||||
xcm::v3::Location,
|
||||
Balance,
|
||||
LocationFilter,
|
||||
V4V3LocationConverter,
|
||||
JustTry,
|
||||
>;
|
||||
|
||||
/// [`MatchedConvertedConcreteId`] converter dedicated for `TrustBackedAssets`
|
||||
pub type TrustBackedAssetsAsMultiLocation<TrustBackedAssetsPalletLocation, Balance> =
|
||||
pub type TrustBackedAssetsAsLocation<TrustBackedAssetsPalletLocation, Balance> =
|
||||
MatchedConvertedConcreteId<
|
||||
MultiLocationForAssetId,
|
||||
xcm::v3::Location,
|
||||
Balance,
|
||||
StartsWith<TrustBackedAssetsPalletLocation>,
|
||||
Identity,
|
||||
JustTry,
|
||||
>;
|
||||
|
||||
/// [`MatchedConvertedConcreteId`] converter dedicated for storing `AssetId` as `MultiLocation`.
|
||||
pub type MultiLocationConvertedConcreteId<MultiLocationFilter, Balance> =
|
||||
MatchedConvertedConcreteId<
|
||||
MultiLocationForAssetId,
|
||||
Balance,
|
||||
MultiLocationFilter,
|
||||
Identity,
|
||||
V4V3LocationConverter,
|
||||
JustTry,
|
||||
>;
|
||||
|
||||
/// [`MatchedConvertedConcreteId`] converter dedicated for storing `ForeignAssets` with `AssetId` as
|
||||
/// `MultiLocation`.
|
||||
/// `Location`.
|
||||
///
|
||||
/// Excludes by default:
|
||||
/// - parent as relay chain
|
||||
/// - all local MultiLocations
|
||||
/// - all local Locations
|
||||
///
|
||||
/// `AdditionalMultiLocationExclusionFilter` can customize additional excluded MultiLocations
|
||||
pub type ForeignAssetsConvertedConcreteId<AdditionalMultiLocationExclusionFilter, Balance> =
|
||||
MultiLocationConvertedConcreteId<
|
||||
/// `AdditionalLocationExclusionFilter` can customize additional excluded Locations
|
||||
pub type ForeignAssetsConvertedConcreteId<AdditionalLocationExclusionFilter, Balance> =
|
||||
LocationConvertedConcreteId<
|
||||
EverythingBut<(
|
||||
// Excludes relay/parent chain currency
|
||||
Equals<ParentLocation>,
|
||||
// Here we rely on fact that something like this works:
|
||||
// assert!(MultiLocation::new(1,
|
||||
// X1(Parachain(100))).starts_with(&MultiLocation::parent()));
|
||||
// assert!(X1(Parachain(100)).starts_with(&Here));
|
||||
StartsWith<LocalMultiLocationPattern>,
|
||||
// assert!(Location::new(1,
|
||||
// [Parachain(100)]).starts_with(&Location::parent()));
|
||||
// assert!([Parachain(100)].into().starts_with(&Here));
|
||||
StartsWith<LocalLocationPattern>,
|
||||
// Here we can exclude more stuff or leave it as `()`
|
||||
AdditionalMultiLocationExclusionFilter,
|
||||
AdditionalLocationExclusionFilter,
|
||||
)>,
|
||||
Balance,
|
||||
>;
|
||||
|
||||
type AssetIdForPoolAssets = u32;
|
||||
/// `MultiLocation` vs `AssetIdForPoolAssets` converter for `PoolAssets`.
|
||||
/// `Location` vs `AssetIdForPoolAssets` converter for `PoolAssets`.
|
||||
pub type AssetIdForPoolAssetsConvert<PoolAssetsPalletLocation> =
|
||||
AsPrefixedGeneralIndex<PoolAssetsPalletLocation, AssetIdForPoolAssets, JustTry>;
|
||||
/// [`MatchedConvertedConcreteId`] converter dedicated for `PoolAssets`
|
||||
@@ -109,28 +114,28 @@ pub type PoolAssetsConvertedConcreteId<PoolAssetsPalletLocation, Balance> =
|
||||
mod tests {
|
||||
use super::*;
|
||||
use sp_runtime::traits::MaybeEquivalence;
|
||||
use xcm::latest::prelude::*;
|
||||
use xcm::prelude::*;
|
||||
use xcm_builder::StartsWithExplicitGlobalConsensus;
|
||||
use xcm_executor::traits::{Error as MatchError, MatchesFungibles};
|
||||
|
||||
#[test]
|
||||
fn asset_id_for_trust_backed_assets_convert_works() {
|
||||
frame_support::parameter_types! {
|
||||
pub TrustBackedAssetsPalletLocation: MultiLocation = MultiLocation::new(5, X1(PalletInstance(13)));
|
||||
pub TrustBackedAssetsPalletLocation: Location = Location::new(5, [PalletInstance(13)]);
|
||||
}
|
||||
let local_asset_id = 123456789 as AssetIdForTrustBackedAssets;
|
||||
let expected_reverse_ref =
|
||||
MultiLocation::new(5, X2(PalletInstance(13), GeneralIndex(local_asset_id.into())));
|
||||
Location::new(5, [PalletInstance(13), GeneralIndex(local_asset_id.into())]);
|
||||
|
||||
assert_eq!(
|
||||
AssetIdForTrustBackedAssetsConvert::<TrustBackedAssetsPalletLocation>::convert_back(
|
||||
AssetIdForTrustBackedAssetsConvertLatest::<TrustBackedAssetsPalletLocation>::convert_back(
|
||||
&local_asset_id
|
||||
)
|
||||
.unwrap(),
|
||||
expected_reverse_ref
|
||||
);
|
||||
assert_eq!(
|
||||
AssetIdForTrustBackedAssetsConvert::<TrustBackedAssetsPalletLocation>::convert(
|
||||
AssetIdForTrustBackedAssetsConvertLatest::<TrustBackedAssetsPalletLocation>::convert(
|
||||
&expected_reverse_ref
|
||||
)
|
||||
.unwrap(),
|
||||
@@ -141,7 +146,7 @@ mod tests {
|
||||
#[test]
|
||||
fn trust_backed_assets_match_fungibles_works() {
|
||||
frame_support::parameter_types! {
|
||||
pub TrustBackedAssetsPalletLocation: MultiLocation = MultiLocation::new(0, X1(PalletInstance(13)));
|
||||
pub TrustBackedAssetsPalletLocation: Location = Location::new(0, [PalletInstance(13)]);
|
||||
}
|
||||
// setup convert
|
||||
type TrustBackedAssetsConvert =
|
||||
@@ -149,85 +154,86 @@ mod tests {
|
||||
|
||||
let test_data = vec![
|
||||
// missing GeneralIndex
|
||||
(ma_1000(0, X1(PalletInstance(13))), Err(MatchError::AssetIdConversionFailed)),
|
||||
(ma_1000(0, [PalletInstance(13)].into()), Err(MatchError::AssetIdConversionFailed)),
|
||||
(
|
||||
ma_1000(0, X2(PalletInstance(13), GeneralKey { data: [0; 32], length: 32 })),
|
||||
ma_1000(0, [PalletInstance(13), GeneralKey { data: [0; 32], length: 32 }].into()),
|
||||
Err(MatchError::AssetIdConversionFailed),
|
||||
),
|
||||
(
|
||||
ma_1000(0, X2(PalletInstance(13), Parachain(1000))),
|
||||
ma_1000(0, [PalletInstance(13), Parachain(1000)].into()),
|
||||
Err(MatchError::AssetIdConversionFailed),
|
||||
),
|
||||
// OK
|
||||
(ma_1000(0, X2(PalletInstance(13), GeneralIndex(1234))), Ok((1234, 1000))),
|
||||
(ma_1000(0, [PalletInstance(13), GeneralIndex(1234)].into()), Ok((1234, 1000))),
|
||||
(
|
||||
ma_1000(0, X3(PalletInstance(13), GeneralIndex(1234), GeneralIndex(2222))),
|
||||
ma_1000(0, [PalletInstance(13), GeneralIndex(1234), GeneralIndex(2222)].into()),
|
||||
Ok((1234, 1000)),
|
||||
),
|
||||
(
|
||||
ma_1000(
|
||||
0,
|
||||
X4(
|
||||
[
|
||||
PalletInstance(13),
|
||||
GeneralIndex(1234),
|
||||
GeneralIndex(2222),
|
||||
GeneralKey { data: [0; 32], length: 32 },
|
||||
),
|
||||
]
|
||||
.into(),
|
||||
),
|
||||
Ok((1234, 1000)),
|
||||
),
|
||||
// wrong pallet instance
|
||||
(
|
||||
ma_1000(0, X2(PalletInstance(77), GeneralIndex(1234))),
|
||||
ma_1000(0, [PalletInstance(77), GeneralIndex(1234)].into()),
|
||||
Err(MatchError::AssetNotHandled),
|
||||
),
|
||||
(
|
||||
ma_1000(0, X3(PalletInstance(77), GeneralIndex(1234), GeneralIndex(2222))),
|
||||
ma_1000(0, [PalletInstance(77), GeneralIndex(1234), GeneralIndex(2222)].into()),
|
||||
Err(MatchError::AssetNotHandled),
|
||||
),
|
||||
// wrong parent
|
||||
(
|
||||
ma_1000(1, X2(PalletInstance(13), GeneralIndex(1234))),
|
||||
ma_1000(1, [PalletInstance(13), GeneralIndex(1234)].into()),
|
||||
Err(MatchError::AssetNotHandled),
|
||||
),
|
||||
(
|
||||
ma_1000(1, X3(PalletInstance(13), GeneralIndex(1234), GeneralIndex(2222))),
|
||||
ma_1000(1, [PalletInstance(13), GeneralIndex(1234), GeneralIndex(2222)].into()),
|
||||
Err(MatchError::AssetNotHandled),
|
||||
),
|
||||
(
|
||||
ma_1000(1, X2(PalletInstance(77), GeneralIndex(1234))),
|
||||
ma_1000(1, [PalletInstance(77), GeneralIndex(1234)].into()),
|
||||
Err(MatchError::AssetNotHandled),
|
||||
),
|
||||
(
|
||||
ma_1000(1, X3(PalletInstance(77), GeneralIndex(1234), GeneralIndex(2222))),
|
||||
ma_1000(1, [PalletInstance(77), GeneralIndex(1234), GeneralIndex(2222)].into()),
|
||||
Err(MatchError::AssetNotHandled),
|
||||
),
|
||||
// wrong parent
|
||||
(
|
||||
ma_1000(2, X2(PalletInstance(13), GeneralIndex(1234))),
|
||||
ma_1000(2, [PalletInstance(13), GeneralIndex(1234)].into()),
|
||||
Err(MatchError::AssetNotHandled),
|
||||
),
|
||||
(
|
||||
ma_1000(2, X3(PalletInstance(13), GeneralIndex(1234), GeneralIndex(2222))),
|
||||
ma_1000(2, [PalletInstance(13), GeneralIndex(1234), GeneralIndex(2222)].into()),
|
||||
Err(MatchError::AssetNotHandled),
|
||||
),
|
||||
// missing GeneralIndex
|
||||
(ma_1000(0, X1(PalletInstance(77))), Err(MatchError::AssetNotHandled)),
|
||||
(ma_1000(1, X1(PalletInstance(13))), Err(MatchError::AssetNotHandled)),
|
||||
(ma_1000(2, X1(PalletInstance(13))), Err(MatchError::AssetNotHandled)),
|
||||
(ma_1000(0, [PalletInstance(77)].into()), Err(MatchError::AssetNotHandled)),
|
||||
(ma_1000(1, [PalletInstance(13)].into()), Err(MatchError::AssetNotHandled)),
|
||||
(ma_1000(2, [PalletInstance(13)].into()), Err(MatchError::AssetNotHandled)),
|
||||
];
|
||||
|
||||
for (multi_asset, expected_result) in test_data {
|
||||
for (asset, expected_result) in test_data {
|
||||
assert_eq!(
|
||||
<TrustBackedAssetsConvert as MatchesFungibles<AssetIdForTrustBackedAssets, u128>>::matches_fungibles(&multi_asset),
|
||||
expected_result, "multi_asset: {:?}", multi_asset);
|
||||
<TrustBackedAssetsConvert as MatchesFungibles<AssetIdForTrustBackedAssets, u128>>::matches_fungibles(&asset.clone().try_into().unwrap()),
|
||||
expected_result, "asset: {:?}", asset);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multi_location_converted_concrete_id_converter_works() {
|
||||
fn location_converted_concrete_id_converter_works() {
|
||||
frame_support::parameter_types! {
|
||||
pub Parachain100Pattern: MultiLocation = MultiLocation::new(1, X1(Parachain(100)));
|
||||
pub Parachain100Pattern: Location = Location::new(1, [Parachain(100)]);
|
||||
pub UniversalLocationNetworkId: NetworkId = NetworkId::ByGenesis([9; 32]);
|
||||
}
|
||||
|
||||
@@ -243,95 +249,125 @@ mod tests {
|
||||
let test_data = vec![
|
||||
// excluded as local
|
||||
(ma_1000(0, Here), Err(MatchError::AssetNotHandled)),
|
||||
(ma_1000(0, X1(Parachain(100))), Err(MatchError::AssetNotHandled)),
|
||||
(ma_1000(0, [Parachain(100)].into()), Err(MatchError::AssetNotHandled)),
|
||||
(
|
||||
ma_1000(0, X2(PalletInstance(13), GeneralIndex(1234))),
|
||||
ma_1000(0, [PalletInstance(13), GeneralIndex(1234)].into()),
|
||||
Err(MatchError::AssetNotHandled),
|
||||
),
|
||||
// excluded as parent
|
||||
(ma_1000(1, Here), Err(MatchError::AssetNotHandled)),
|
||||
// excluded as additional filter - Parachain100Pattern
|
||||
(ma_1000(1, X1(Parachain(100))), Err(MatchError::AssetNotHandled)),
|
||||
(ma_1000(1, X2(Parachain(100), GeneralIndex(1234))), Err(MatchError::AssetNotHandled)),
|
||||
(ma_1000(1, [Parachain(100)].into()), Err(MatchError::AssetNotHandled)),
|
||||
(
|
||||
ma_1000(1, X3(Parachain(100), PalletInstance(13), GeneralIndex(1234))),
|
||||
ma_1000(1, [Parachain(100), GeneralIndex(1234)].into()),
|
||||
Err(MatchError::AssetNotHandled),
|
||||
),
|
||||
(
|
||||
ma_1000(1, [Parachain(100), PalletInstance(13), GeneralIndex(1234)].into()),
|
||||
Err(MatchError::AssetNotHandled),
|
||||
),
|
||||
// excluded as additional filter - StartsWithExplicitGlobalConsensus
|
||||
(
|
||||
ma_1000(1, X1(GlobalConsensus(NetworkId::ByGenesis([9; 32])))),
|
||||
ma_1000(1, [GlobalConsensus(NetworkId::ByGenesis([9; 32]))].into()),
|
||||
Err(MatchError::AssetNotHandled),
|
||||
),
|
||||
(
|
||||
ma_1000(2, X1(GlobalConsensus(NetworkId::ByGenesis([9; 32])))),
|
||||
ma_1000(2, [GlobalConsensus(NetworkId::ByGenesis([9; 32]))].into()),
|
||||
Err(MatchError::AssetNotHandled),
|
||||
),
|
||||
(
|
||||
ma_1000(
|
||||
2,
|
||||
X3(
|
||||
[
|
||||
GlobalConsensus(NetworkId::ByGenesis([9; 32])),
|
||||
Parachain(200),
|
||||
GeneralIndex(1234),
|
||||
),
|
||||
]
|
||||
.into(),
|
||||
),
|
||||
Err(MatchError::AssetNotHandled),
|
||||
),
|
||||
// ok
|
||||
(ma_1000(1, X1(Parachain(200))), Ok((MultiLocation::new(1, X1(Parachain(200))), 1000))),
|
||||
(ma_1000(2, X1(Parachain(200))), Ok((MultiLocation::new(2, X1(Parachain(200))), 1000))),
|
||||
(
|
||||
ma_1000(1, X2(Parachain(200), GeneralIndex(1234))),
|
||||
Ok((MultiLocation::new(1, X2(Parachain(200), GeneralIndex(1234))), 1000)),
|
||||
ma_1000(1, [Parachain(200)].into()),
|
||||
Ok((xcm::v3::Location::new(1, [xcm::v3::Junction::Parachain(200)]), 1000)),
|
||||
),
|
||||
(
|
||||
ma_1000(2, X2(Parachain(200), GeneralIndex(1234))),
|
||||
Ok((MultiLocation::new(2, X2(Parachain(200), GeneralIndex(1234))), 1000)),
|
||||
ma_1000(2, [Parachain(200)].into()),
|
||||
Ok((xcm::v3::Location::new(2, [xcm::v3::Junction::Parachain(200)]), 1000)),
|
||||
),
|
||||
(
|
||||
ma_1000(2, X1(GlobalConsensus(NetworkId::ByGenesis([7; 32])))),
|
||||
ma_1000(1, [Parachain(200), GeneralIndex(1234)].into()),
|
||||
Ok((
|
||||
MultiLocation::new(2, X1(GlobalConsensus(NetworkId::ByGenesis([7; 32])))),
|
||||
xcm::v3::Location::new(
|
||||
1,
|
||||
[xcm::v3::Junction::Parachain(200), xcm::v3::Junction::GeneralIndex(1234)],
|
||||
),
|
||||
1000,
|
||||
)),
|
||||
),
|
||||
(
|
||||
ma_1000(2, [Parachain(200), GeneralIndex(1234)].into()),
|
||||
Ok((
|
||||
xcm::v3::Location::new(
|
||||
2,
|
||||
[xcm::v3::Junction::Parachain(200), xcm::v3::Junction::GeneralIndex(1234)],
|
||||
),
|
||||
1000,
|
||||
)),
|
||||
),
|
||||
(
|
||||
ma_1000(2, [GlobalConsensus(NetworkId::ByGenesis([7; 32]))].into()),
|
||||
Ok((
|
||||
xcm::v3::Location::new(
|
||||
2,
|
||||
[xcm::v3::Junction::GlobalConsensus(xcm::v3::NetworkId::ByGenesis(
|
||||
[7; 32],
|
||||
))],
|
||||
),
|
||||
1000,
|
||||
)),
|
||||
),
|
||||
(
|
||||
ma_1000(
|
||||
2,
|
||||
X3(
|
||||
[
|
||||
GlobalConsensus(NetworkId::ByGenesis([7; 32])),
|
||||
Parachain(200),
|
||||
GeneralIndex(1234),
|
||||
),
|
||||
]
|
||||
.into(),
|
||||
),
|
||||
Ok((
|
||||
MultiLocation::new(
|
||||
xcm::v3::Location::new(
|
||||
2,
|
||||
X3(
|
||||
GlobalConsensus(NetworkId::ByGenesis([7; 32])),
|
||||
Parachain(200),
|
||||
GeneralIndex(1234),
|
||||
),
|
||||
[
|
||||
xcm::v3::Junction::GlobalConsensus(xcm::v3::NetworkId::ByGenesis(
|
||||
[7; 32],
|
||||
)),
|
||||
xcm::v3::Junction::Parachain(200),
|
||||
xcm::v3::Junction::GeneralIndex(1234),
|
||||
],
|
||||
),
|
||||
1000,
|
||||
)),
|
||||
),
|
||||
];
|
||||
|
||||
for (multi_asset, expected_result) in test_data {
|
||||
for (asset, expected_result) in test_data {
|
||||
assert_eq!(
|
||||
<Convert as MatchesFungibles<MultiLocationForAssetId, u128>>::matches_fungibles(
|
||||
&multi_asset
|
||||
<Convert as MatchesFungibles<xcm::v3::MultiLocation, u128>>::matches_fungibles(
|
||||
&asset.clone().try_into().unwrap()
|
||||
),
|
||||
expected_result,
|
||||
"multi_asset: {:?}",
|
||||
multi_asset
|
||||
"asset: {:?}",
|
||||
asset
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Create MultiAsset
|
||||
fn ma_1000(parents: u8, interior: Junctions) -> MultiAsset {
|
||||
(MultiLocation::new(parents, interior), 1000).into()
|
||||
// Create Asset
|
||||
fn ma_1000(parents: u8, interior: Junctions) -> Asset {
|
||||
(Location::new(parents, interior), 1000).into()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,32 +20,32 @@ use sp_runtime::{
|
||||
Either::{Left, Right},
|
||||
};
|
||||
use sp_std::marker::PhantomData;
|
||||
use xcm::latest::MultiLocation;
|
||||
use xcm::latest::Location;
|
||||
|
||||
/// Converts a given [`MultiLocation`] to [`Either::Left`] when equal to `Target`, or
|
||||
/// Converts a given [`Location`] to [`Either::Left`] when equal to `Target`, or
|
||||
/// [`Either::Right`] otherwise.
|
||||
///
|
||||
/// Suitable for use as a `Criterion` with [`frame_support::traits::tokens::fungible::UnionOf`].
|
||||
pub struct TargetFromLeft<Target>(PhantomData<Target>);
|
||||
impl<Target: Get<MultiLocation>> Convert<MultiLocation, Either<(), MultiLocation>>
|
||||
for TargetFromLeft<Target>
|
||||
{
|
||||
fn convert(l: MultiLocation) -> Either<(), MultiLocation> {
|
||||
pub struct TargetFromLeft<Target, L = Location>(PhantomData<(Target, L)>);
|
||||
impl<Target: Get<L>, L: PartialEq + Eq> Convert<L, Either<(), L>> for TargetFromLeft<Target, L> {
|
||||
fn convert(l: L) -> Either<(), L> {
|
||||
Target::get().eq(&l).then(|| Left(())).map_or(Right(l), |n| n)
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts a given [`MultiLocation`] to [`Either::Left`] based on the `Equivalence` criteria.
|
||||
/// Converts a given [`Location`] to [`Either::Left`] based on the `Equivalence` criteria.
|
||||
/// Returns [`Either::Right`] if not equivalent.
|
||||
///
|
||||
/// Suitable for use as a `Criterion` with [`frame_support::traits::tokens::fungibles::UnionOf`].
|
||||
pub struct LocalFromLeft<Equivalence, AssetId>(PhantomData<(Equivalence, AssetId)>);
|
||||
impl<Equivalence, AssetId> Convert<MultiLocation, Either<AssetId, MultiLocation>>
|
||||
for LocalFromLeft<Equivalence, AssetId>
|
||||
pub struct LocalFromLeft<Equivalence, AssetId, L = Location>(
|
||||
PhantomData<(Equivalence, AssetId, L)>,
|
||||
);
|
||||
impl<Equivalence, AssetId, L> Convert<L, Either<AssetId, L>>
|
||||
for LocalFromLeft<Equivalence, AssetId, L>
|
||||
where
|
||||
Equivalence: MaybeEquivalence<MultiLocation, AssetId>,
|
||||
Equivalence: MaybeEquivalence<L, AssetId>,
|
||||
{
|
||||
fn convert(l: MultiLocation) -> Either<AssetId, MultiLocation> {
|
||||
fn convert(l: L) -> Either<AssetId, L> {
|
||||
match Equivalence::convert(&l) {
|
||||
Some(id) => Left(id),
|
||||
None => Right(l),
|
||||
@@ -53,7 +53,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub trait MatchesLocalAndForeignAssetsMultiLocation {
|
||||
fn is_local(location: &MultiLocation) -> bool;
|
||||
fn is_foreign(location: &MultiLocation) -> bool;
|
||||
pub trait MatchesLocalAndForeignAssetsLocation<L = Location> {
|
||||
fn is_local(location: &L) -> bool;
|
||||
fn is_foreign(location: &L) -> bool;
|
||||
}
|
||||
|
||||
@@ -15,67 +15,72 @@
|
||||
|
||||
use cumulus_primitives_core::ParaId;
|
||||
use frame_support::{pallet_prelude::Get, traits::ContainsPair};
|
||||
use xcm::{
|
||||
latest::prelude::{MultiAsset, MultiLocation},
|
||||
prelude::*,
|
||||
};
|
||||
use xcm::prelude::*;
|
||||
|
||||
use xcm_builder::ensure_is_remote;
|
||||
|
||||
frame_support::parameter_types! {
|
||||
pub LocalMultiLocationPattern: MultiLocation = MultiLocation::new(0, Here);
|
||||
pub ParentLocation: MultiLocation = MultiLocation::parent();
|
||||
pub LocalLocationPattern: Location = Location::new(0, Here);
|
||||
pub ParentLocation: Location = Location::parent();
|
||||
}
|
||||
|
||||
/// Accepts an asset if it is from the origin.
|
||||
pub struct IsForeignConcreteAsset<IsForeign>(sp_std::marker::PhantomData<IsForeign>);
|
||||
impl<IsForeign: ContainsPair<MultiLocation, MultiLocation>> ContainsPair<MultiAsset, MultiLocation>
|
||||
impl<IsForeign: ContainsPair<Location, Location>> ContainsPair<Asset, Location>
|
||||
for IsForeignConcreteAsset<IsForeign>
|
||||
{
|
||||
fn contains(asset: &MultiAsset, origin: &MultiLocation) -> bool {
|
||||
fn contains(asset: &Asset, origin: &Location) -> bool {
|
||||
log::trace!(target: "xcm::contains", "IsForeignConcreteAsset asset: {:?}, origin: {:?}", asset, origin);
|
||||
matches!(asset.id, Concrete(ref id) if IsForeign::contains(id, origin))
|
||||
matches!(asset.id, AssetId(ref id) if IsForeign::contains(id, origin))
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks if `a` is from sibling location `b`. Checks that `MultiLocation-a` starts with
|
||||
/// `MultiLocation-b`, and that the `ParaId` of `b` is not equal to `a`.
|
||||
pub struct FromSiblingParachain<SelfParaId>(sp_std::marker::PhantomData<SelfParaId>);
|
||||
impl<SelfParaId: Get<ParaId>> ContainsPair<MultiLocation, MultiLocation>
|
||||
for FromSiblingParachain<SelfParaId>
|
||||
/// Checks if `a` is from sibling location `b`. Checks that `Location-a` starts with
|
||||
/// `Location-b`, and that the `ParaId` of `b` is not equal to `a`.
|
||||
pub struct FromSiblingParachain<SelfParaId, L = Location>(
|
||||
sp_std::marker::PhantomData<(SelfParaId, L)>,
|
||||
);
|
||||
impl<SelfParaId: Get<ParaId>, L: TryFrom<Location> + TryInto<Location> + Clone> ContainsPair<L, L>
|
||||
for FromSiblingParachain<SelfParaId, L>
|
||||
{
|
||||
fn contains(&a: &MultiLocation, b: &MultiLocation) -> bool {
|
||||
// `a` needs to be from `b` at least
|
||||
if !a.starts_with(b) {
|
||||
return false
|
||||
}
|
||||
fn contains(a: &L, b: &L) -> bool {
|
||||
// We convert locations to latest
|
||||
let a = match ((*a).clone().try_into(), (*b).clone().try_into()) {
|
||||
(Ok(a), Ok(b)) if a.starts_with(&b) => a, // `a` needs to be from `b` at least
|
||||
_ => return false,
|
||||
};
|
||||
|
||||
// here we check if sibling
|
||||
match a {
|
||||
MultiLocation { parents: 1, interior } =>
|
||||
match a.unpack() {
|
||||
(1, interior) =>
|
||||
matches!(interior.first(), Some(Parachain(sibling_para_id)) if sibling_para_id.ne(&u32::from(SelfParaId::get()))),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks if `a` is from the expected global consensus network. Checks that `MultiLocation-a`
|
||||
/// starts with `MultiLocation-b`, and that network is a foreign consensus system.
|
||||
pub struct FromNetwork<UniversalLocation, ExpectedNetworkId>(
|
||||
sp_std::marker::PhantomData<(UniversalLocation, ExpectedNetworkId)>,
|
||||
/// Checks if `a` is from the expected global consensus network. Checks that `Location-a`
|
||||
/// starts with `Location-b`, and that network is a foreign consensus system.
|
||||
pub struct FromNetwork<UniversalLocation, ExpectedNetworkId, L = Location>(
|
||||
sp_std::marker::PhantomData<(UniversalLocation, ExpectedNetworkId, L)>,
|
||||
);
|
||||
impl<UniversalLocation: Get<InteriorMultiLocation>, ExpectedNetworkId: Get<NetworkId>>
|
||||
ContainsPair<MultiLocation, MultiLocation> for FromNetwork<UniversalLocation, ExpectedNetworkId>
|
||||
impl<
|
||||
UniversalLocation: Get<InteriorLocation>,
|
||||
ExpectedNetworkId: Get<NetworkId>,
|
||||
L: TryFrom<Location> + TryInto<Location> + Clone,
|
||||
> ContainsPair<L, L> for FromNetwork<UniversalLocation, ExpectedNetworkId, L>
|
||||
{
|
||||
fn contains(&a: &MultiLocation, b: &MultiLocation) -> bool {
|
||||
// `a` needs to be from `b` at least
|
||||
if !a.starts_with(b) {
|
||||
return false
|
||||
}
|
||||
fn contains(a: &L, b: &L) -> bool {
|
||||
// We convert locations to latest
|
||||
let a = match ((*a).clone().try_into(), (*b).clone().try_into()) {
|
||||
(Ok(a), Ok(b)) if a.starts_with(&b) => a, // `a` needs to be from `b` at least
|
||||
_ => return false,
|
||||
};
|
||||
|
||||
let universal_source = UniversalLocation::get();
|
||||
|
||||
// ensure that `a`` is remote and from the expected network
|
||||
match ensure_is_remote(universal_source, a) {
|
||||
// ensure that `a` is remote and from the expected network
|
||||
match ensure_is_remote(universal_source.clone(), a.clone()) {
|
||||
Ok((network_id, _)) => network_id == ExpectedNetworkId::get(),
|
||||
Err(e) => {
|
||||
log::trace!(
|
||||
@@ -89,19 +94,17 @@ impl<UniversalLocation: Get<InteriorMultiLocation>, ExpectedNetworkId: Get<Netwo
|
||||
}
|
||||
}
|
||||
|
||||
/// Adapter verifies if it is allowed to receive `MultiAsset` from `MultiLocation`.
|
||||
/// Adapter verifies if it is allowed to receive `Asset` from `Location`.
|
||||
///
|
||||
/// Note: `MultiLocation` has to be from a different global consensus.
|
||||
/// Note: `Location` has to be from a different global consensus.
|
||||
pub struct IsTrustedBridgedReserveLocationForConcreteAsset<UniversalLocation, Reserves>(
|
||||
sp_std::marker::PhantomData<(UniversalLocation, Reserves)>,
|
||||
);
|
||||
impl<
|
||||
UniversalLocation: Get<InteriorMultiLocation>,
|
||||
Reserves: ContainsPair<MultiAsset, MultiLocation>,
|
||||
> ContainsPair<MultiAsset, MultiLocation>
|
||||
impl<UniversalLocation: Get<InteriorLocation>, Reserves: ContainsPair<Asset, Location>>
|
||||
ContainsPair<Asset, Location>
|
||||
for IsTrustedBridgedReserveLocationForConcreteAsset<UniversalLocation, Reserves>
|
||||
{
|
||||
fn contains(asset: &MultiAsset, origin: &MultiLocation) -> bool {
|
||||
fn contains(asset: &Asset, origin: &Location) -> bool {
|
||||
let universal_source = UniversalLocation::get();
|
||||
log::trace!(
|
||||
target: "xcm::contains",
|
||||
@@ -110,7 +113,7 @@ impl<
|
||||
);
|
||||
|
||||
// check remote origin
|
||||
let _ = match ensure_is_remote(universal_source, *origin) {
|
||||
let _ = match ensure_is_remote(universal_source.clone(), origin.clone()) {
|
||||
Ok(devolved) => devolved,
|
||||
Err(_) => {
|
||||
log::trace!(
|
||||
@@ -133,14 +136,14 @@ mod tests {
|
||||
use frame_support::parameter_types;
|
||||
|
||||
parameter_types! {
|
||||
pub UniversalLocation: InteriorMultiLocation = X2(GlobalConsensus(Rococo), Parachain(1000));
|
||||
pub UniversalLocation: InteriorLocation = [GlobalConsensus(Rococo), Parachain(1000)].into();
|
||||
pub ExpectedNetworkId: NetworkId = Wococo;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_network_contains_works() {
|
||||
// asset and origin from foreign consensus works
|
||||
let asset: MultiLocation = (
|
||||
let asset: Location = (
|
||||
Parent,
|
||||
Parent,
|
||||
GlobalConsensus(Wococo),
|
||||
@@ -149,12 +152,11 @@ mod tests {
|
||||
GeneralIndex(1),
|
||||
)
|
||||
.into();
|
||||
let origin: MultiLocation =
|
||||
(Parent, Parent, GlobalConsensus(Wococo), Parachain(1000)).into();
|
||||
let origin: Location = (Parent, Parent, GlobalConsensus(Wococo), Parachain(1000)).into();
|
||||
assert!(FromNetwork::<UniversalLocation, ExpectedNetworkId>::contains(&asset, &origin));
|
||||
|
||||
// asset and origin from local consensus fails
|
||||
let asset: MultiLocation = (
|
||||
let asset: Location = (
|
||||
Parent,
|
||||
Parent,
|
||||
GlobalConsensus(Rococo),
|
||||
@@ -163,17 +165,16 @@ mod tests {
|
||||
GeneralIndex(1),
|
||||
)
|
||||
.into();
|
||||
let origin: MultiLocation =
|
||||
(Parent, Parent, GlobalConsensus(Rococo), Parachain(1000)).into();
|
||||
let origin: Location = (Parent, Parent, GlobalConsensus(Rococo), Parachain(1000)).into();
|
||||
assert!(!FromNetwork::<UniversalLocation, ExpectedNetworkId>::contains(&asset, &origin));
|
||||
|
||||
// asset and origin from here fails
|
||||
let asset: MultiLocation = (PalletInstance(1), GeneralIndex(1)).into();
|
||||
let origin: MultiLocation = Here.into();
|
||||
let asset: Location = (PalletInstance(1), GeneralIndex(1)).into();
|
||||
let origin: Location = Here.into();
|
||||
assert!(!FromNetwork::<UniversalLocation, ExpectedNetworkId>::contains(&asset, &origin));
|
||||
|
||||
// asset from different consensus fails
|
||||
let asset: MultiLocation = (
|
||||
let asset: Location = (
|
||||
Parent,
|
||||
Parent,
|
||||
GlobalConsensus(Polkadot),
|
||||
@@ -182,12 +183,11 @@ mod tests {
|
||||
GeneralIndex(1),
|
||||
)
|
||||
.into();
|
||||
let origin: MultiLocation =
|
||||
(Parent, Parent, GlobalConsensus(Wococo), Parachain(1000)).into();
|
||||
let origin: Location = (Parent, Parent, GlobalConsensus(Wococo), Parachain(1000)).into();
|
||||
assert!(!FromNetwork::<UniversalLocation, ExpectedNetworkId>::contains(&asset, &origin));
|
||||
|
||||
// origin from different consensus fails
|
||||
let asset: MultiLocation = (
|
||||
let asset: Location = (
|
||||
Parent,
|
||||
Parent,
|
||||
GlobalConsensus(Wococo),
|
||||
@@ -196,12 +196,11 @@ mod tests {
|
||||
GeneralIndex(1),
|
||||
)
|
||||
.into();
|
||||
let origin: MultiLocation =
|
||||
(Parent, Parent, GlobalConsensus(Polkadot), Parachain(1000)).into();
|
||||
let origin: Location = (Parent, Parent, GlobalConsensus(Polkadot), Parachain(1000)).into();
|
||||
assert!(!FromNetwork::<UniversalLocation, ExpectedNetworkId>::contains(&asset, &origin));
|
||||
|
||||
// asset and origin from unexpected consensus fails
|
||||
let asset: MultiLocation = (
|
||||
let asset: Location = (
|
||||
Parent,
|
||||
Parent,
|
||||
GlobalConsensus(Polkadot),
|
||||
@@ -210,8 +209,7 @@ mod tests {
|
||||
GeneralIndex(1),
|
||||
)
|
||||
.into();
|
||||
let origin: MultiLocation =
|
||||
(Parent, Parent, GlobalConsensus(Polkadot), Parachain(1000)).into();
|
||||
let origin: Location = (Parent, Parent, GlobalConsensus(Polkadot), Parachain(1000)).into();
|
||||
assert!(!FromNetwork::<UniversalLocation, ExpectedNetworkId>::contains(&asset, &origin));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,12 +18,12 @@
|
||||
use codec::{Codec, Decode, Encode};
|
||||
use sp_runtime::RuntimeDebug;
|
||||
#[cfg(feature = "std")]
|
||||
use {sp_std::vec::Vec, xcm::latest::MultiAsset};
|
||||
use {sp_std::vec::Vec, xcm::latest::Asset};
|
||||
|
||||
/// The possible errors that can happen querying the storage of assets.
|
||||
#[derive(Eq, PartialEq, Encode, Decode, RuntimeDebug, scale_info::TypeInfo)]
|
||||
pub enum FungiblesAccessError {
|
||||
/// `MultiLocation` to `AssetId`/`ClassId` conversion failed.
|
||||
/// `Location` to `AssetId`/`ClassId` conversion failed.
|
||||
AssetIdConversionFailed,
|
||||
/// `u128` amount to currency `Balance` conversion failed.
|
||||
AmountToBalanceConversionFailed,
|
||||
@@ -36,11 +36,11 @@ sp_api::decl_runtime_apis! {
|
||||
where
|
||||
AccountId: Codec,
|
||||
{
|
||||
/// Returns the list of all [`MultiAsset`] that an `AccountId` has.
|
||||
/// Returns the list of all [`Asset`] that an `AccountId` has.
|
||||
#[changed_in(2)]
|
||||
fn query_account_balances(account: AccountId) -> Result<Vec<MultiAsset>, FungiblesAccessError>;
|
||||
fn query_account_balances(account: AccountId) -> Result<Vec<Asset>, FungiblesAccessError>;
|
||||
|
||||
/// Returns the list of all [`MultiAsset`] that an `AccountId` has.
|
||||
fn query_account_balances(account: AccountId) -> Result<xcm::VersionedMultiAssets, FungiblesAccessError>;
|
||||
/// Returns the list of all [`Asset`] that an `AccountId` has.
|
||||
fn query_account_balances(account: AccountId) -> Result<xcm::VersionedAssets, FungiblesAccessError>;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user