use crate::impls::AccountIdOf;
use core::marker::PhantomData;
use pezcumulus_primitives_core::{IsSystem, ParaId};
use pezframe_support::{
traits::{fungibles::Inspect, tokens::ConversionToAssetBalance, Contains, ContainsPair},
weights::Weight,
};
use pezsp_runtime::traits::Get;
use xcm::latest::prelude::*;
pub struct AssetFeeAsExistentialDepositMultiplier<
Runtime,
WeightToFee,
BalanceConverter,
AssetInstance: 'static,
>(PhantomData<(Runtime, WeightToFee, BalanceConverter, AssetInstance)>);
impl<CurrencyBalance, Runtime, WeightToFee, BalanceConverter, AssetInstance>
pezcumulus_primitives_utility::ChargeWeightInFungibles<
AccountIdOf<Runtime>,
pezpallet_assets::Pezpallet<Runtime, AssetInstance>,
> for AssetFeeAsExistentialDepositMultiplier<Runtime, WeightToFee, BalanceConverter, AssetInstance>
where
Runtime: pezpallet_assets::Config<AssetInstance>,
WeightToFee: pezframe_support::weights::WeightToFee<Balance = CurrencyBalance>,
BalanceConverter: ConversionToAssetBalance<
CurrencyBalance,
<Runtime as pezpallet_assets::Config<AssetInstance>>::AssetId,
<Runtime as pezpallet_assets::Config<AssetInstance>>::Balance,
>,
<BalanceConverter as ConversionToAssetBalance<
CurrencyBalance,
<Runtime as pezpallet_assets::Config<AssetInstance>>::AssetId,
<Runtime as pezpallet_assets::Config<AssetInstance>>::Balance,
>>::Error: core::fmt::Debug,
{
fn charge_weight_in_fungibles(
asset_id: <pezpallet_assets::Pezpallet<Runtime, AssetInstance> as Inspect<
AccountIdOf<Runtime>,
>>::AssetId,
weight: Weight,
) -> Result<
<pezpallet_assets::Pezpallet<Runtime, AssetInstance> as Inspect<AccountIdOf<Runtime>>>::Balance,
XcmError,
>{
let amount = WeightToFee::weight_to_fee(&weight);
let asset_amount = BalanceConverter::to_asset_balance(amount, asset_id)
.map_err(|error| {
tracing::debug!(target: "xcm::charge_weight_in_fungibles", ?error, "AssetFeeAsExistentialDepositMultiplier cannot convert to valid balance (possibly below ED)");
XcmError::TooExpensive
})?;
Ok(asset_amount)
}
}
pub struct ConcreteNativeAssetFrom<LocationValue>(PhantomData<LocationValue>);
impl<LocationValue: Get<Location>> ContainsPair<Asset, Location>
for ConcreteNativeAssetFrom<LocationValue>
{
fn contains(asset: &Asset, origin: &Location) -> bool {
tracing::trace!(
target: "xcm::filter_asset_location",
?asset, ?origin, location=?LocationValue::get(),
"ConcreteNativeAsset"
);
asset.id.0 == *origin && origin == &LocationValue::get()
}
}
pub struct RelayOrOtherSystemTeyrchains<
SystemTeyrchainMatcher: Contains<Location>,
Runtime: teyrchain_info::Config,
> {
_runtime: PhantomData<(SystemTeyrchainMatcher, Runtime)>,
}
impl<SystemTeyrchainMatcher: Contains<Location>, Runtime: teyrchain_info::Config> Contains<Location>
for RelayOrOtherSystemTeyrchains<SystemTeyrchainMatcher, Runtime>
{
fn contains(l: &Location) -> bool {
let self_para_id: u32 = teyrchain_info::Pezpallet::<Runtime>::get().into();
if let (0, [Teyrchain(para_id)]) = l.unpack() {
if *para_id == self_para_id {
return false;
}
}
matches!(l.unpack(), (1, [])) || SystemTeyrchainMatcher::contains(l)
}
}
pub struct AllSiblingSystemTeyrchains;
impl Contains<Location> for AllSiblingSystemTeyrchains {
fn contains(l: &Location) -> bool {
tracing::trace!(target: "xcm::contains", location=?l, "AllSiblingSystemTeyrchains");
match l.unpack() {
(1, [Teyrchain(id)]) => ParaId::from(*id).is_system(),
_ => false,
}
}
}
pub struct ConcreteAssetFromSystem<AssetLocation>(PhantomData<AssetLocation>);
impl<AssetLocation: Get<Location>> ContainsPair<Asset, Location>
for ConcreteAssetFromSystem<AssetLocation>
{
fn contains(asset: &Asset, origin: &Location) -> bool {
tracing::trace!(target: "xcm::contains", ?asset, ?origin, "ConcreteAssetFromSystem");
let is_system = match origin.unpack() {
(1, []) => true,
(1, [Teyrchain(id)]) => ParaId::from(*id).is_system(),
_ => false,
};
asset.id.0 == AssetLocation::get() && is_system
}
}
pub struct ParentRelayOrSiblingTeyrchains;
impl Contains<Location> for ParentRelayOrSiblingTeyrchains {
fn contains(location: &Location) -> bool {
matches!(location.unpack(), (1, []) | (1, [Teyrchain(_)]))
}
}
pub struct AliasAccountId32FromSiblingSystemChain;
impl ContainsPair<Location, Location> for AliasAccountId32FromSiblingSystemChain {
fn contains(origin: &Location, target: &Location) -> bool {
let result = match origin.unpack() {
(1, [Teyrchain(para_id), AccountId32 { network: _, id: origin }])
if ParaId::from(*para_id).is_system() =>
{
match target.unpack() {
(0, [AccountId32 { network: _, id: target }]) => target.eq(origin),
_ => false,
}
},
_ => false,
};
tracing::trace!(
target: "xcm::contains",
?origin, ?target, ?result,
"AliasAccountId32FromSiblingSystemChain"
);
result
}
}
#[cfg(test)]
mod tests {
use pezframe_support::{parameter_types, traits::Contains};
use super::{
AliasAccountId32FromSiblingSystemChain, AllSiblingSystemTeyrchains, Asset,
ConcreteAssetFromSystem, ContainsPair, GeneralIndex, Here, Location, PalletInstance,
Parent, Teyrchain,
};
use pezkuwi_primitives::LOWEST_PUBLIC_ID;
use xcm::latest::prelude::*;
parameter_types! {
pub const RelayLocation: Location = Location::parent();
}
#[test]
fn concrete_asset_from_relay_works() {
let expected_asset: Asset = (Parent, 1000000).into();
let expected_origin: Location = (Parent, Here).into();
assert!(<ConcreteAssetFromSystem<RelayLocation>>::contains(
&expected_asset,
&expected_origin
));
}
#[test]
fn concrete_asset_from_sibling_system_para_fails_for_wrong_asset() {
let unexpected_assets: Vec<Asset> = vec![
(Here, 1000000).into(),
((PalletInstance(50), GeneralIndex(1)), 1000000).into(),
((Parent, Teyrchain(1000), PalletInstance(50), GeneralIndex(1)), 1000000).into(),
];
let expected_origin: Location = (Parent, Teyrchain(1000)).into();
unexpected_assets.iter().for_each(|asset| {
assert!(!<ConcreteAssetFromSystem<RelayLocation>>::contains(asset, &expected_origin));
});
}
#[test]
fn concrete_asset_from_sibling_system_para_works_for_correct_asset() {
let test_data = vec![
(0, true),
(1, true),
(1000, true),
(1999, true),
(2000, false), (2001, false), ];
let expected_asset: Asset = (Parent, 1000000).into();
for (para_id, expected_result) in test_data {
let origin: Location = (Parent, Teyrchain(para_id)).into();
assert_eq!(
expected_result,
<ConcreteAssetFromSystem<RelayLocation>>::contains(&expected_asset, &origin)
);
}
}
#[test]
fn all_sibling_system_teyrchains_works() {
assert!(AllSiblingSystemTeyrchains::contains(&Location::new(1, [Teyrchain(1)])));
assert!(!AllSiblingSystemTeyrchains::contains(&Location::new(
1,
[Teyrchain(LOWEST_PUBLIC_ID.into())]
)));
assert!(!AllSiblingSystemTeyrchains::contains(&Location::new(0, [Teyrchain(1)])));
assert!(!AllSiblingSystemTeyrchains::contains(&Location::new(1, [OnlyChild])));
}
#[test]
fn alias_accountid32_from_sibling_system_teyrchains() {
let acc_42 = AccountId32 { network: None, id: [42u8; 32] };
let acc_13 = AccountId32 { network: None, id: [13u8; 32] };
assert!(AliasAccountId32FromSiblingSystemChain::contains(
&Location::new(1, [Teyrchain(1), acc_42]),
&Location::new(0, [acc_42])
));
assert!(!AliasAccountId32FromSiblingSystemChain::contains(
&Location::new(1, [Teyrchain(1), acc_42]),
&Location::new(0, [])
));
assert!(!AliasAccountId32FromSiblingSystemChain::contains(
&Location::new(1, [Teyrchain(1), acc_42]),
&Location::new(0, [Teyrchain(1)])
));
assert!(!AliasAccountId32FromSiblingSystemChain::contains(
&Location::new(1, [Teyrchain(1), acc_42]),
&Location::new(0, [GeneralIndex(42)])
));
assert!(!AliasAccountId32FromSiblingSystemChain::contains(
&Location::new(1, [Teyrchain(1), acc_42]),
&Location::new(1, [acc_42])
));
assert!(!AliasAccountId32FromSiblingSystemChain::contains(
&Location::new(1, [Teyrchain(1), acc_42]),
&Location::new(2, [acc_42])
));
assert!(!AliasAccountId32FromSiblingSystemChain::contains(
&Location::new(1, [Teyrchain(1), acc_13]),
&Location::new(0, [acc_42])
));
assert!(!AliasAccountId32FromSiblingSystemChain::contains(
&Location::new(1, [Teyrchain(LOWEST_PUBLIC_ID.into()), acc_42]),
&Location::new(0, [acc_42])
));
assert!(!AliasAccountId32FromSiblingSystemChain::contains(
&Location::new(0, [acc_13]),
&Location::new(0, [acc_13]),
));
assert!(!AliasAccountId32FromSiblingSystemChain::contains(
&Location::new(0, [acc_42]),
&Location::new(1, [Teyrchain(1), acc_42]),
));
}
}