mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-28 07:27:55 +00:00
pallet-xcm: use XcmTeleportFilter for teleported fees in reserve transfers (#2322)
Disallow reserve transfers that use teleportable fees if `(origin, fees)` matches `XcmTeleportFilter`. Add regression tests for filtering based on `XcmTeleportFilter` for both `(limited_)reserve_transfer_assets()` and `(limited_)teleport_assets` extrinsics.
This commit is contained in:
@@ -1379,7 +1379,7 @@ impl<T: Config> Pallet<T> {
|
||||
TransferType::DestinationReserve =>
|
||||
Self::destination_reserve_fees_instructions(dest, fees, weight_limit)?,
|
||||
TransferType::Teleport =>
|
||||
Self::teleport_fees_instructions(dest, fees, weight_limit)?,
|
||||
Self::teleport_fees_instructions(origin_location, dest, fees, weight_limit)?,
|
||||
TransferType::RemoteReserve(_) =>
|
||||
return Err(Error::<T>::InvalidAssetUnsupportedReserve.into()),
|
||||
});
|
||||
@@ -1715,10 +1715,14 @@ impl<T: Config> Pallet<T> {
|
||||
}
|
||||
|
||||
fn teleport_fees_instructions(
|
||||
origin: MultiLocation,
|
||||
dest: MultiLocation,
|
||||
fees: MultiAsset,
|
||||
weight_limit: WeightLimit,
|
||||
) -> Result<(Xcm<<T as Config>::RuntimeCall>, Xcm<()>), Error<T>> {
|
||||
let value = (origin, vec![fees.clone()]);
|
||||
ensure!(T::XcmTeleportFilter::contains(&value), Error::<T>::Filtered);
|
||||
|
||||
let context = T::UniversalLocation::get();
|
||||
let reanchored_fees = fees
|
||||
.clone()
|
||||
|
||||
@@ -18,7 +18,8 @@ use codec::Encode;
|
||||
use frame_support::{
|
||||
construct_runtime, match_types, parameter_types,
|
||||
traits::{
|
||||
AsEnsureOriginWithArg, ConstU128, ConstU32, Equals, Everything, EverythingBut, Nothing,
|
||||
AsEnsureOriginWithArg, ConstU128, ConstU32, Contains, Equals, Everything, EverythingBut,
|
||||
Nothing,
|
||||
},
|
||||
weights::Weight,
|
||||
};
|
||||
@@ -341,6 +342,9 @@ pub const USDT_PARA_ID: u32 = 2003;
|
||||
// This child parachain is not configured as trusted reserve or teleport location for any assets.
|
||||
pub const OTHER_PARA_ID: u32 = 2009;
|
||||
|
||||
// This child parachain is used for filtered/disallowed assets.
|
||||
pub const FILTERED_PARA_ID: u32 = 2010;
|
||||
|
||||
parameter_types! {
|
||||
pub const RelayLocation: MultiLocation = Here.into_location();
|
||||
pub const NativeAsset: MultiAsset = MultiAsset {
|
||||
@@ -384,6 +388,17 @@ parameter_types! {
|
||||
interior: X1(Parachain(USDT_PARA_ID)),
|
||||
}),
|
||||
};
|
||||
pub const FilteredTeleportLocation: MultiLocation = MultiLocation {
|
||||
parents: 0,
|
||||
interior: X1(Parachain(FILTERED_PARA_ID))
|
||||
};
|
||||
pub const FilteredTeleportAsset: MultiAsset = MultiAsset {
|
||||
fun: Fungible(10),
|
||||
id: Concrete(MultiLocation {
|
||||
parents: 0,
|
||||
interior: X1(Parachain(FILTERED_PARA_ID)),
|
||||
}),
|
||||
};
|
||||
pub const AnyNetwork: Option<NetworkId> = None;
|
||||
pub UniversalLocation: InteriorMultiLocation = Here;
|
||||
pub UnitWeightCost: u64 = 1_000;
|
||||
@@ -430,6 +445,7 @@ parameter_types! {
|
||||
pub TrustedLocal: (MultiAssetFilter, MultiLocation) = (All.into(), Here.into());
|
||||
pub TrustedSystemPara: (MultiAssetFilter, MultiLocation) = (NativeAsset::get().into(), SystemParachainLocation::get());
|
||||
pub TrustedUsdt: (MultiAssetFilter, MultiLocation) = (Usdt::get().into(), UsdtTeleportLocation::get());
|
||||
pub TrustedFilteredTeleport: (MultiAssetFilter, MultiLocation) = (FilteredTeleportAsset::get().into(), FilteredTeleportLocation::get());
|
||||
pub TeleportUsdtToForeign: (MultiAssetFilter, MultiLocation) = (Usdt::get().into(), ForeignReserveLocation::get());
|
||||
pub TrustedForeign: (MultiAssetFilter, MultiLocation) = (ForeignAsset::get().into(), ForeignReserveLocation::get());
|
||||
pub TrustedUsdc: (MultiAssetFilter, MultiLocation) = (Usdc::get().into(), UsdcReserveLocation::get());
|
||||
@@ -466,6 +482,7 @@ impl xcm_executor::Config for XcmConfig {
|
||||
Case<TrustedSystemPara>,
|
||||
Case<TrustedUsdt>,
|
||||
Case<TeleportUsdtToForeign>,
|
||||
Case<TrustedFilteredTeleport>,
|
||||
);
|
||||
type UniversalLocation = UniversalLocation;
|
||||
type Barrier = Barrier;
|
||||
@@ -496,6 +513,14 @@ parameter_types! {
|
||||
pub static AdvertisedXcmVersion: pallet_xcm::XcmVersion = 3;
|
||||
}
|
||||
|
||||
pub struct XcmTeleportFiltered;
|
||||
impl Contains<(MultiLocation, Vec<MultiAsset>)> for XcmTeleportFiltered {
|
||||
fn contains(t: &(MultiLocation, Vec<MultiAsset>)) -> bool {
|
||||
let filtered = FilteredTeleportAsset::get();
|
||||
t.1.iter().any(|asset| asset == &filtered)
|
||||
}
|
||||
}
|
||||
|
||||
impl pallet_xcm::Config for Test {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type SendXcmOrigin = xcm_builder::EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>;
|
||||
@@ -503,7 +528,7 @@ impl pallet_xcm::Config for Test {
|
||||
type ExecuteXcmOrigin = xcm_builder::EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>;
|
||||
type XcmExecuteFilter = Everything;
|
||||
type XcmExecutor = XcmExecutor<XcmConfig>;
|
||||
type XcmTeleportFilter = Everything;
|
||||
type XcmTeleportFilter = EverythingBut<XcmTeleportFiltered>;
|
||||
type XcmReserveTransferFilter = Everything;
|
||||
type Weigher = FixedWeightBounds<BaseXcmWeight, RuntimeCall, MaxInstructions>;
|
||||
type UniversalLocation = UniversalLocation;
|
||||
|
||||
@@ -117,6 +117,30 @@ fn limited_teleport_assets_works() {
|
||||
);
|
||||
}
|
||||
|
||||
/// `limited_teleport_assets` should fail for filtered assets
|
||||
#[test]
|
||||
fn limited_teleport_filtered_assets_disallowed() {
|
||||
let beneficiary: MultiLocation = AccountId32 { network: None, id: BOB.into() }.into();
|
||||
new_test_ext_with_balances(vec![(ALICE, INITIAL_BALANCE)]).execute_with(|| {
|
||||
let result = XcmPallet::limited_teleport_assets(
|
||||
RuntimeOrigin::signed(ALICE),
|
||||
Box::new(FilteredTeleportLocation::get().into()),
|
||||
Box::new(beneficiary.into()),
|
||||
Box::new(FilteredTeleportAsset::get().into()),
|
||||
0,
|
||||
Unlimited,
|
||||
);
|
||||
assert_eq!(
|
||||
result,
|
||||
Err(DispatchError::Module(ModuleError {
|
||||
index: 4,
|
||||
error: [2, 0, 0, 0],
|
||||
message: Some("Filtered")
|
||||
}))
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/// Test `reserve_transfer_assets_with_paid_router_works`
|
||||
///
|
||||
/// Asserts that the sender's balance is decreased and the beneficiary's balance
|
||||
@@ -1403,3 +1427,33 @@ fn reserve_transfer_assets_with_teleportable_asset_fails() {
|
||||
assert_eq!(Assets::active_issuance(usdt_id_multilocation), usdt_initial_local_amount);
|
||||
});
|
||||
}
|
||||
|
||||
/// Test `reserve_transfer_assets` with teleportable fee that is filtered - should fail.
|
||||
#[test]
|
||||
fn reserve_transfer_assets_with_filtered_teleported_fee_disallowed() {
|
||||
let beneficiary: MultiLocation = AccountId32 { network: None, id: BOB.into() }.into();
|
||||
new_test_ext_with_balances(vec![(ALICE, INITIAL_BALANCE)]).execute_with(|| {
|
||||
let (assets, fee_index, _, _) = into_multiassets_checked(
|
||||
// FilteredTeleportAsset for fees - teleportable but filtered
|
||||
FilteredTeleportAsset::get().into(),
|
||||
// native asset to transfer (not used for fees) - local reserve
|
||||
(MultiLocation::here(), SEND_AMOUNT).into(),
|
||||
);
|
||||
let result = XcmPallet::limited_reserve_transfer_assets(
|
||||
RuntimeOrigin::signed(ALICE),
|
||||
Box::new(FilteredTeleportLocation::get().into()),
|
||||
Box::new(beneficiary.into()),
|
||||
Box::new(assets.into()),
|
||||
fee_index as u32,
|
||||
Unlimited,
|
||||
);
|
||||
assert_eq!(
|
||||
result,
|
||||
Err(DispatchError::Module(ModuleError {
|
||||
index: 4,
|
||||
error: [2, 0, 0, 0],
|
||||
message: Some("Filtered")
|
||||
}))
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user