use crate::impls::AccountIdOf; use core::{marker::PhantomData, ops::ControlFlow}; use frame_support::{ log, traits::{ fungibles::Inspect, tokens::ConversionToAssetBalance, ContainsPair, ProcessMessageError, }, weights::Weight, }; use sp_runtime::traits::Get; use xcm::latest::prelude::*; use xcm_builder::{CreateMatcher, MatchXcm}; 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<(), ProcessMessageError> { 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<(), ProcessMessageError> { message.matcher().match_next_inst_while( |_| true, |inst| match inst { InitiateReserveWithdraw { reserve: MultiLocation { parents: 1, interior: Here }, .. } | DepositReserveAsset { dest: MultiLocation { parents: 1, interior: Here }, .. } | TransferReserveAsset { dest: MultiLocation { parents: 1, interior: Here }, .. } => { Err(ProcessMessageError::Unsupported) // Deny }, // An unexpected reserve transfer has arrived from the Relay Chain. Generally, // `IsReserve` should not allow this, but we just log it here. ReserveAssetDeposited { .. } if matches!(origin, MultiLocation { parents: 1, interior: Here }) => { log::warn!( target: "xcm::barrier", "Unexpected ReserveAssetDeposited from the Relay Chain", ); Ok(ControlFlow::Continue(())) }, _ => Ok(ControlFlow::Continue(())), }, )?; // 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: frame_support::weights::WeightToFee, BalanceConverter: ConversionToAssetBalance< 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()) } }