use core::marker::PhantomData;
use frame_support::traits::{Contains, Get};
use xcm::prelude::*;
use xcm_executor::traits::{FeeManager, FeeReason, TransactAsset};
pub trait HandleFee {
fn handle_fee(fee: Assets, context: Option<&XcmContext>, reason: FeeReason) -> Assets;
}
impl HandleFee for () {
fn handle_fee(_: Assets, _: Option<&XcmContext>, _: FeeReason) -> Assets {
Assets::new()
}
}
#[impl_trait_for_tuples::impl_for_tuples(1, 30)]
impl HandleFee for Tuple {
fn handle_fee(fee: Assets, context: Option<&XcmContext>, reason: FeeReason) -> Assets {
let mut unconsumed_fee = fee;
for_tuples!( #(
unconsumed_fee = Tuple::handle_fee(unconsumed_fee, context, reason.clone());
if unconsumed_fee.is_none() {
return unconsumed_fee;
}
)* );
unconsumed_fee
}
}
pub struct XcmFeeManagerFromComponents<WaivedLocations, HandleFee>(
PhantomData<(WaivedLocations, HandleFee)>,
);
impl<WaivedLocations: Contains<Location>, FeeHandler: HandleFee> FeeManager
for XcmFeeManagerFromComponents<WaivedLocations, FeeHandler>
{
fn is_waived(origin: Option<&Location>, _: FeeReason) -> bool {
let Some(loc) = origin else { return false };
WaivedLocations::contains(loc)
}
fn handle_fee(fee: Assets, context: Option<&XcmContext>, reason: FeeReason) {
FeeHandler::handle_fee(fee, context, reason);
}
}
#[deprecated(
note = "`XcmFeeToAccount` will be removed in January 2025. Use `SendXcmFeeToAccount` instead."
)]
pub struct XcmFeeToAccount<AssetTransactor, AccountId, ReceiverAccount>(
PhantomData<(AssetTransactor, AccountId, ReceiverAccount)>,
);
#[allow(deprecated)]
impl<
AssetTransactor: TransactAsset,
AccountId: Clone + Into<[u8; 32]>,
ReceiverAccount: Get<AccountId>,
> HandleFee for XcmFeeToAccount<AssetTransactor, AccountId, ReceiverAccount>
{
fn handle_fee(fee: Assets, context: Option<&XcmContext>, _reason: FeeReason) -> Assets {
let dest = AccountId32 { network: None, id: ReceiverAccount::get().into() }.into();
deposit_or_burn_fee::<AssetTransactor>(fee, context, dest);
Assets::new()
}
}
pub struct SendXcmFeeToAccount<AssetTransactor, ReceiverAccount>(
PhantomData<(AssetTransactor, ReceiverAccount)>,
);
impl<AssetTransactor: TransactAsset, ReceiverAccount: Get<Location>> HandleFee
for SendXcmFeeToAccount<AssetTransactor, ReceiverAccount>
{
fn handle_fee(fee: Assets, context: Option<&XcmContext>, _reason: FeeReason) -> Assets {
deposit_or_burn_fee::<AssetTransactor>(fee, context, ReceiverAccount::get());
Assets::new()
}
}
pub fn deposit_or_burn_fee<AssetTransactor: TransactAsset>(
fee: Assets,
context: Option<&XcmContext>,
dest: Location,
) {
for asset in fee.into_inner() {
if let Err(e) = AssetTransactor::deposit_asset(&asset, &dest, context) {
log::trace!(
target: "xcm::fees",
"`AssetTransactor::deposit_asset` returned error: {e:?}. Burning fee: {asset:?}. \
They might be burned.",
);
}
}
}