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)]
80#[allow(dead_code)]
81pub struct XcmFeeToAccount<AssetTransactor, AccountId, ReceiverAccount>(
82 PhantomData<(AssetTransactor, AccountId, ReceiverAccount)>,
83);
84
85#[allow(deprecated)]
86impl<
87 AssetTransactor: TransactAsset,
88 AccountId: Clone + Into<[u8; 32]>,
89 ReceiverAccount: Get<AccountId>,
90 > HandleFee for XcmFeeToAccount<AssetTransactor, AccountId, ReceiverAccount>
91{
92 fn handle_fee(fee: Assets, context: Option<&XcmContext>, _reason: FeeReason) -> Assets {
93 let dest = AccountId32 { network: None, id: ReceiverAccount::get().into() }.into();
94 deposit_or_burn_fee::<AssetTransactor>(fee, context, dest);
95
96 Assets::new()
97 }
98}
99
100pub struct SendXcmFeeToAccount<AssetTransactor, ReceiverAccount>(
109 PhantomData<(AssetTransactor, ReceiverAccount)>,
110);
111
112impl<AssetTransactor: TransactAsset, ReceiverAccount: Get<Location>> HandleFee
113 for SendXcmFeeToAccount<AssetTransactor, ReceiverAccount>
114{
115 fn handle_fee(fee: Assets, context: Option<&XcmContext>, _reason: FeeReason) -> Assets {
116 deposit_or_burn_fee::<AssetTransactor>(fee, context, ReceiverAccount::get());
117
118 Assets::new()
119 }
120}
121
122pub fn deposit_or_burn_fee<AssetTransactor: TransactAsset>(
125 fee: Assets,
126 context: Option<&XcmContext>,
127 dest: Location,
128) {
129 for asset in fee.into_inner() {
130 if let Err(e) = AssetTransactor::deposit_asset(&asset, &dest, context) {
131 tracing::trace!(
132 target: "xcm::fees",
133 "`AssetTransactor::deposit_asset` returned error: {e:?}. Burning fee: {asset:?}. \
134 They might be burned.",
135 );
136 }
137 }
138}