Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pallet-xcm: use XcmTeleportFilter for teleported fees in reserve transfers #2322

Merged
merged 1 commit into from
Nov 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion polkadot/xcm/pallet-xcm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()),
});
Expand Down Expand Up @@ -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()
Expand Down
29 changes: 27 additions & 2 deletions polkadot/xcm/pallet-xcm/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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());
Expand Down Expand Up @@ -466,6 +482,7 @@ impl xcm_executor::Config for XcmConfig {
Case<TrustedSystemPara>,
Case<TrustedUsdt>,
Case<TeleportUsdtToForeign>,
Case<TrustedFilteredTeleport>,
);
type UniversalLocation = UniversalLocation;
type Barrier = Barrier;
Expand Down Expand Up @@ -496,14 +513,22 @@ 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>;
type XcmRouter = XcmRouter;
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;
Expand Down
54 changes: 54 additions & 0 deletions polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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")
}))
);
});
}