use crate::impls::AccountIdOf; use core::marker::PhantomData; use frame_support::{ log, traits::{fungibles::Inspect, tokens::BalanceConversion}, weights::{Weight, WeightToFee, WeightToFeePolynomial}, }; use sp_runtime::traits::Get; use xcm::latest::{prelude::*, Weight as XCMWeight}; use xcm_executor::traits::{FilterAssetLocation, ShouldExecute}; //TODO: move DenyThenTry to polkadot's xcm module. /// Deny executing the XCM if it matches any of the Deny filter regardless of anything else. /// If it passes the Deny, and matches one of the Allow cases then it is let through. pub struct DenyThenTry(PhantomData, PhantomData) where Deny: ShouldExecute, Allow: ShouldExecute; impl ShouldExecute for DenyThenTry where Deny: ShouldExecute, Allow: ShouldExecute, { fn should_execute( origin: &MultiLocation, message: &mut Xcm, max_weight: XCMWeight, weight_credit: &mut XCMWeight, ) -> Result<(), ()> { Deny::should_execute(origin, message, max_weight, weight_credit)?; Allow::should_execute(origin, message, max_weight, weight_credit) } } // See issue #5233 pub struct DenyReserveTransferToRelayChain; impl ShouldExecute for DenyReserveTransferToRelayChain { fn should_execute( origin: &MultiLocation, message: &mut Xcm, _max_weight: XCMWeight, _weight_credit: &mut XCMWeight, ) -> Result<(), ()> { if message.0.iter().any(|inst| { matches!( inst, InitiateReserveWithdraw { reserve: MultiLocation { parents: 1, interior: Here }, .. } | DepositReserveAsset { dest: MultiLocation { parents: 1, interior: Here }, .. } | TransferReserveAsset { dest: MultiLocation { parents: 1, interior: Here }, .. } ) }) { return Err(()) // Deny } // An unexpected reserve transfer has arrived from the Relay Chain. Generally, `IsReserve` // should not allow this, but we just log it here. if matches!(origin, MultiLocation { parents: 1, interior: Here }) && message.0.iter().any(|inst| matches!(inst, ReserveAssetDeposited { .. })) { log::warn!( target: "xcm::barrier", "Unexpected ReserveAssetDeposited from the Relay Chain", ); } // Permit everything else Ok(()) } } /// A `ChargeFeeInFungibles` implementation that converts the output of /// a given WeightToFee implementation an amount charged in /// a particular assetId from pallet-assets pub struct AssetFeeAsExistentialDepositMultiplier( PhantomData<(Runtime, WeightToFee, BalanceConverter)>, ); impl cumulus_primitives_utility::ChargeWeightInFungibles< AccountIdOf, pallet_assets::Pallet, > for AssetFeeAsExistentialDepositMultiplier where Runtime: pallet_assets::Config, WeightToFee: WeightToFeePolynomial, BalanceConverter: BalanceConversion< CurrencyBalance, ::AssetId, ::Balance, >, AccountIdOf: From + Into, { fn charge_weight_in_fungibles( asset_id: as Inspect>>::AssetId, weight: Weight, ) -> Result< as Inspect>>::Balance, XcmError> { let amount = WeightToFee::weight_to_fee(&weight); // If the amount gotten is not at least the ED, then make it be the ED of the asset // This is to avoid burning assets and decreasing the supply let asset_amount = BalanceConverter::to_asset_balance(amount, asset_id) .map_err(|_| XcmError::TooExpensive)?; Ok(asset_amount) } } /// Accepts an asset if it is a native asset from a particular `MultiLocation`. pub struct ConcreteNativeAssetFrom(PhantomData); impl> FilterAssetLocation for ConcreteNativeAssetFrom { fn filter_asset_location(asset: &MultiAsset, origin: &MultiLocation) -> bool { log::trace!(target: "xcm::filter_asset_location", "ConcreteNativeAsset asset: {:?}, origin: {:?}, location: {:?}", asset, origin, Location::get()); matches!(asset.id, Concrete(ref id) if id == origin && origin == &Location::get()) } }