staging_xcm_builder/
fee_handling.rs1use core::marker::PhantomData;
18use frame_support::traits::{Contains, Get};
19use xcm::prelude::*;
20use xcm_executor::{
21 traits::{FeeManager, FeeReason, TransactAsset},
22 AssetsInHolding,
23};
24
25pub trait HandleFee {
27 fn handle_fee(
32 fee: AssetsInHolding,
33 context: Option<&XcmContext>,
34 reason: FeeReason,
35 ) -> AssetsInHolding;
36}
37
38impl HandleFee for () {
40 fn handle_fee(_: AssetsInHolding, _: Option<&XcmContext>, _: FeeReason) -> AssetsInHolding {
41 AssetsInHolding::new()
42 }
43}
44
45#[impl_trait_for_tuples::impl_for_tuples(1, 30)]
46impl HandleFee for Tuple {
47 fn handle_fee(
48 fee: AssetsInHolding,
49 context: Option<&XcmContext>,
50 reason: FeeReason,
51 ) -> AssetsInHolding {
52 let mut unconsumed_fee = fee;
53 for_tuples!( #(
54 unconsumed_fee = Tuple::handle_fee(unconsumed_fee, context, reason.clone());
55 if unconsumed_fee.is_empty() {
56 return unconsumed_fee;
57 }
58 )* );
59
60 unconsumed_fee
61 }
62}
63
64pub struct XcmFeeManagerFromComponents<WaivedLocations, HandleFee>(
67 PhantomData<(WaivedLocations, HandleFee)>,
68);
69impl<WaivedLocations: Contains<Location>, FeeHandler: HandleFee> FeeManager
70 for XcmFeeManagerFromComponents<WaivedLocations, FeeHandler>
71{
72 fn is_waived(origin: Option<&Location>, _: FeeReason) -> bool {
73 let Some(loc) = origin else { return false };
74 WaivedLocations::contains(loc)
75 }
76
77 fn handle_fee(fee: AssetsInHolding, context: Option<&XcmContext>, reason: FeeReason) {
78 FeeHandler::handle_fee(fee, context, reason);
79 }
80}
81
82pub struct SendXcmFeeToAccount<AssetTransactor, ReceiverAccount>(
91 PhantomData<(AssetTransactor, ReceiverAccount)>,
92);
93
94impl<AssetTransactor: TransactAsset, ReceiverAccount: Get<Location>> HandleFee
95 for SendXcmFeeToAccount<AssetTransactor, ReceiverAccount>
96{
97 fn handle_fee(
98 fee: AssetsInHolding,
99 context: Option<&XcmContext>,
100 _reason: FeeReason,
101 ) -> AssetsInHolding {
102 deposit_or_burn_fee::<AssetTransactor>(fee, context, ReceiverAccount::get());
103 AssetsInHolding::new()
104 }
105}
106
107pub fn deposit_or_burn_fee<AssetTransactor: TransactAsset>(
110 fee: AssetsInHolding,
111 context: Option<&XcmContext>,
112 dest: Location,
113) {
114 for (asset_id, credit) in fee.fungible.into_iter() {
117 let fee_asset = AssetsInHolding::new_from_fungible_credit(asset_id, credit);
118 if let Err((unspent, e)) = AssetTransactor::deposit_asset(fee_asset, &dest, context) {
119 tracing::trace!(
120 target: "xcm::fees",
121 "`AssetTransactor::deposit_asset` returned error: {e:?}. \
122 Dropping fee: {unspent:?} (might be burned).",
123 );
124 }
125 }
126}