use crate::impls::AccountIdOf; use core::marker::PhantomData; use frame_support::{ log, traits::{fungibles::Inspect, tokens::BalanceConversion, ContainsPair}, weights::{Weight, WeightToFee, WeightToFeePolynomial}, }; use sp_runtime::traits::Get; use xcm::latest::prelude::*; use xcm_executor::traits::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 [Instruction], max_weight: Weight, weight_credit: &mut Weight, ) -> Result<(), ()> { Deny::should_execute(origin, message, max_weight, weight_credit)?; Allow::should_execute(origin, message, max_weight, weight_credit) } } // See issue pub struct DenyReserveTransferToRelayChain; impl ShouldExecute for DenyReserveTransferToRelayChain { fn should_execute( origin: &MultiLocation, message: &mut [Instruction], _max_weight: Weight, _weight_credit: &mut Weight, ) -> Result<(), ()> { if message.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.iter().any(|inst| matches!(inst, ReserveAssetDeposited { .. })) { log::warn!( target: "xcm::barriers", "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< Runtime, WeightToFee, BalanceConverter, AssetInstance: 'static, >(PhantomData<(Runtime, WeightToFee, BalanceConverter, AssetInstance)>); 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< AccountIdOf, >>::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> ContainsPair for ConcreteNativeAssetFrom { fn contains(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()) } }