staging_xcm_builder/
fee_handling.rs1use core::marker::PhantomData;
18use frame_support::traits::{Contains, Get};
19use xcm::prelude::*;
20use xcm_executor::traits::{FeeManager, FeeReason, TransactAsset};
21
22pub trait HandleFee {
24 fn handle_fee(fee: Assets, context: Option<&XcmContext>, reason: FeeReason) -> Assets;
29}
30
31impl HandleFee for () {
33 fn handle_fee(_: Assets, _: Option<&XcmContext>, _: FeeReason) -> Assets {
34 Assets::new()
35 }
36}
37
38#[impl_trait_for_tuples::impl_for_tuples(1, 30)]
39impl HandleFee for Tuple {
40 fn handle_fee(fee: Assets, context: Option<&XcmContext>, reason: FeeReason) -> Assets {
41 let mut unconsumed_fee = fee;
42 for_tuples!( #(
43 unconsumed_fee = Tuple::handle_fee(unconsumed_fee, context, reason.clone());
44 if unconsumed_fee.is_none() {
45 return unconsumed_fee;
46 }
47 )* );
48
49 unconsumed_fee
50 }
51}
52
53pub struct XcmFeeManagerFromComponents<WaivedLocations, HandleFee>(
56 PhantomData<(WaivedLocations, HandleFee)>,
57);
58impl<WaivedLocations: Contains<Location>, FeeHandler: HandleFee> FeeManager
59 for XcmFeeManagerFromComponents<WaivedLocations, FeeHandler>
60{
61 fn is_waived(origin: Option<&Location>, _: FeeReason) -> bool {
62 let Some(loc) = origin else { return false };
63 WaivedLocations::contains(loc)
64 }
65
66 fn handle_fee(fee: Assets, context: Option<&XcmContext>, reason: FeeReason) {
67 FeeHandler::handle_fee(fee, context, reason);
68 }
69}
70
71#[deprecated(
78 note = "`XcmFeeToAccount` will be removed in January 2025. Use `SendXcmFeeToAccount` instead."
79)]
80pub struct XcmFeeToAccount<AssetTransactor, AccountId, ReceiverAccount>(
81 PhantomData<(AssetTransactor, AccountId, ReceiverAccount)>,
82);
83
84#[allow(deprecated)]
85impl<
86 AssetTransactor: TransactAsset,
87 AccountId: Clone + Into<[u8; 32]>,
88 ReceiverAccount: Get<AccountId>,
89 > HandleFee for XcmFeeToAccount<AssetTransactor, AccountId, ReceiverAccount>
90{
91 fn handle_fee(fee: Assets, context: Option<&XcmContext>, _reason: FeeReason) -> Assets {
92 let dest = AccountId32 { network: None, id: ReceiverAccount::get().into() }.into();
93 deposit_or_burn_fee::<AssetTransactor>(fee, context, dest);
94
95 Assets::new()
96 }
97}
98
99pub struct SendXcmFeeToAccount<AssetTransactor, ReceiverAccount>(
108 PhantomData<(AssetTransactor, ReceiverAccount)>,
109);
110
111impl<AssetTransactor: TransactAsset, ReceiverAccount: Get<Location>> HandleFee
112 for SendXcmFeeToAccount<AssetTransactor, ReceiverAccount>
113{
114 fn handle_fee(fee: Assets, context: Option<&XcmContext>, _reason: FeeReason) -> Assets {
115 deposit_or_burn_fee::<AssetTransactor>(fee, context, ReceiverAccount::get());
116
117 Assets::new()
118 }
119}
120
121pub fn deposit_or_burn_fee<AssetTransactor: TransactAsset>(
124 fee: Assets,
125 context: Option<&XcmContext>,
126 dest: Location,
127) {
128 for asset in fee.into_inner() {
129 if let Err(e) = AssetTransactor::deposit_asset(&asset, &dest, context) {
130 tracing::trace!(
131 target: "xcm::fees",
132 "`AssetTransactor::deposit_asset` returned error: {e:?}. Burning fee: {asset:?}. \
133 They might be burned.",
134 );
135 }
136 }
137}