use alloc::vec::Vec;
use core::marker::PhantomData;
use frame_support::traits::{Contains, ContainsPair, Get};
use xcm::latest::{Asset, AssetFilter, AssetId, Location, WildAsset};
pub struct NativeAsset;
impl ContainsPair<Asset, Location> for NativeAsset {
fn contains(asset: &Asset, origin: &Location) -> bool {
log::trace!(target: "xcm::contains", "NativeAsset asset: {:?}, origin: {:?}", asset, origin);
matches!(asset.id, AssetId(ref id) if id == origin)
}
}
pub struct Case<T>(PhantomData<T>);
impl<T: Get<(AssetFilter, Location)>> ContainsPair<Asset, Location> for Case<T> {
fn contains(asset: &Asset, origin: &Location) -> bool {
log::trace!(target: "xcm::contains", "Case asset: {:?}, origin: {:?}", asset, origin);
let (a, o) = T::get();
a.matches(asset) && &o == origin
}
}
pub struct LocationWithAssetFilters<LocationFilter, AssetFilters>(
core::marker::PhantomData<(LocationFilter, AssetFilters)>,
);
impl<LocationFilter: Contains<Location>, AssetFilters: Get<Vec<AssetFilter>>>
Contains<(Location, Vec<Asset>)> for LocationWithAssetFilters<LocationFilter, AssetFilters>
{
fn contains((location, assets): &(Location, Vec<Asset>)) -> bool {
log::trace!(target: "xcm::contains", "LocationWithAssetFilters location: {:?}, assets: {:?}", location, assets);
if !LocationFilter::contains(location) {
return false
}
let filters = AssetFilters::get();
assets.iter().all(|asset| {
for filter in &filters {
if filter.matches(asset) {
return true
}
}
false
})
}
}
pub struct AllAssets;
impl Get<Vec<AssetFilter>> for AllAssets {
fn get() -> Vec<AssetFilter> {
alloc::vec![AssetFilter::Wild(WildAsset::All)]
}
}
#[cfg(test)]
mod tests {
use super::*;
use frame_support::traits::Equals;
use xcm::latest::prelude::*;
#[test]
fn location_with_asset_filters_works() {
frame_support::parameter_types! {
pub ParaA: Location = Location::new(1, [Parachain(1001)]);
pub ParaB: Location = Location::new(1, [Parachain(1002)]);
pub ParaC: Location = Location::new(1, [Parachain(1003)]);
pub AssetXLocation: Location = Location::new(1, [GeneralIndex(1111)]);
pub AssetYLocation: Location = Location::new(1, [GeneralIndex(2222)]);
pub AssetZLocation: Location = Location::new(1, [GeneralIndex(3333)]);
pub OnlyAssetXOrAssetY: alloc::vec::Vec<AssetFilter> = alloc::vec![
Wild(AllOf { fun: WildFungible, id: AssetId(AssetXLocation::get()) }),
Wild(AllOf { fun: WildFungible, id: AssetId(AssetYLocation::get()) }),
];
pub OnlyAssetZ: alloc::vec::Vec<AssetFilter> = alloc::vec![
Wild(AllOf { fun: WildFungible, id: AssetId(AssetZLocation::get()) })
];
}
let test_data: Vec<(Location, Vec<Asset>, bool)> = vec![
(ParaA::get(), vec![(AssetXLocation::get(), 1).into()], true),
(ParaA::get(), vec![(AssetYLocation::get(), 1).into()], true),
(ParaA::get(), vec![(AssetZLocation::get(), 1).into()], false),
(
ParaA::get(),
vec![(AssetXLocation::get(), 1).into(), (AssetYLocation::get(), 1).into()],
true,
),
(
ParaA::get(),
vec![(AssetXLocation::get(), 1).into(), (AssetZLocation::get(), 1).into()],
false,
),
(
ParaA::get(),
vec![(AssetYLocation::get(), 1).into(), (AssetZLocation::get(), 1).into()],
false,
),
(
ParaA::get(),
vec![
(AssetXLocation::get(), 1).into(),
(AssetYLocation::get(), 1).into(),
(AssetZLocation::get(), 1).into(),
],
false,
),
(ParaB::get(), vec![(AssetXLocation::get(), 1).into()], false),
(ParaB::get(), vec![(AssetYLocation::get(), 1).into()], false),
(ParaB::get(), vec![(AssetZLocation::get(), 1).into()], true),
(
ParaB::get(),
vec![(AssetXLocation::get(), 1).into(), (AssetYLocation::get(), 1).into()],
false,
),
(
ParaB::get(),
vec![(AssetXLocation::get(), 1).into(), (AssetZLocation::get(), 1).into()],
false,
),
(
ParaB::get(),
vec![(AssetYLocation::get(), 1).into(), (AssetZLocation::get(), 1).into()],
false,
),
(
ParaB::get(),
vec![
(AssetXLocation::get(), 1).into(),
(AssetYLocation::get(), 1).into(),
(AssetZLocation::get(), 1).into(),
],
false,
),
(ParaC::get(), vec![(AssetXLocation::get(), 1).into()], true),
(ParaC::get(), vec![(AssetYLocation::get(), 1).into()], true),
(ParaC::get(), vec![(AssetZLocation::get(), 1).into()], true),
(
ParaC::get(),
vec![(AssetXLocation::get(), 1).into(), (AssetYLocation::get(), 1).into()],
true,
),
(
ParaC::get(),
vec![(AssetXLocation::get(), 1).into(), (AssetZLocation::get(), 1).into()],
true,
),
(
ParaC::get(),
vec![(AssetYLocation::get(), 1).into(), (AssetZLocation::get(), 1).into()],
true,
),
(
ParaC::get(),
vec![
(AssetXLocation::get(), 1).into(),
(AssetYLocation::get(), 1).into(),
(AssetZLocation::get(), 1).into(),
],
true,
),
];
type Filter = (
LocationWithAssetFilters<Equals<ParaA>, OnlyAssetXOrAssetY>,
LocationWithAssetFilters<Equals<ParaB>, OnlyAssetZ>,
LocationWithAssetFilters<Equals<ParaC>, AllAssets>,
);
for (location, assets, expected_result) in test_data {
assert_eq!(
Filter::contains(&(location.clone(), assets.clone())),
expected_result,
"expected_result: {expected_result} not matched for (location, assets): ({:?}, {:?})!", location, assets,
)
}
}
}