pallet_block_fees/
fees.rs1use crate::Pallet as BlockFees;
2use frame_support::traits::fungible::Inspect;
3use frame_support::traits::tokens::WithdrawConsequence;
4use frame_support::traits::{Currency, ExistenceRequirement, Imbalance, WithdrawReasons};
5use parity_scale_codec::Encode;
6use sp_runtime::traits::{DispatchInfoOf, PostDispatchInfoOf, Zero};
7use sp_runtime::transaction_validity::{InvalidTransaction, TransactionValidityError};
8use sp_runtime::Saturating;
9use sp_std::marker::PhantomData;
10
11pub struct LiquidityInfo<Balance, NegativeImbalance> {
12 consensus_storage_fee: Balance,
13 imbalance: NegativeImbalance,
14}
15
16type AccountIdOf<T> = <T as frame_system::Config>::AccountId;
17type BalanceOf<C, T> = <C as Currency<AccountIdOf<T>>>::Balance;
18type NegativeImbalanceOf<C, T> = <C as Currency<AccountIdOf<T>>>::NegativeImbalance;
19
20pub struct OnChargeDomainTransaction<C>(PhantomData<C>);
23
24impl<T, C> pallet_transaction_payment::OnChargeTransaction<T> for OnChargeDomainTransaction<C>
25where
26 T: pallet_transaction_payment::Config + crate::Config<Balance = BalanceOf<C, T>>,
27 C: Currency<AccountIdOf<T>> + Inspect<AccountIdOf<T>, Balance = BalanceOf<C, T>>,
28 C::PositiveImbalance: Imbalance<BalanceOf<C, T>, Opposite = C::NegativeImbalance>,
29{
30 type Balance = BalanceOf<C, T>;
31 type LiquidityInfo = Option<LiquidityInfo<BalanceOf<C, T>, NegativeImbalanceOf<C, T>>>;
32
33 fn withdraw_fee(
34 who: &AccountIdOf<T>,
35 call: &T::RuntimeCall,
36 _info: &DispatchInfoOf<T::RuntimeCall>,
37 fee: Self::Balance,
38 tip: Self::Balance,
39 ) -> Result<Self::LiquidityInfo, TransactionValidityError> {
40 if fee.is_zero() {
41 return Ok(None);
42 }
43
44 let withdraw_reason = if tip.is_zero() {
45 WithdrawReasons::TRANSACTION_PAYMENT
46 } else {
47 WithdrawReasons::TRANSACTION_PAYMENT | WithdrawReasons::TIP
48 };
49
50 let withdraw_result =
51 C::withdraw(who, fee, withdraw_reason, ExistenceRequirement::KeepAlive);
52 let imbalance = withdraw_result.map_err(|_error| InvalidTransaction::Payment)?;
53
54 let consensus_storage_fee = BlockFees::<T>::consensus_chain_byte_fee()
56 * Self::Balance::from(call.encoded_size() as u32);
57
58 Ok(Some(LiquidityInfo {
59 consensus_storage_fee,
60 imbalance,
61 }))
62 }
63
64 fn can_withdraw_fee(
65 who: &T::AccountId,
66 _call: &T::RuntimeCall,
67 _dispatch_info: &DispatchInfoOf<T::RuntimeCall>,
68 fee: Self::Balance,
69 _tip: Self::Balance,
70 ) -> Result<(), TransactionValidityError> {
71 if fee.is_zero() {
72 return Ok(());
73 }
74
75 match C::can_withdraw(who, fee) {
76 WithdrawConsequence::Success => Ok(()),
77 _ => Err(InvalidTransaction::Payment.into()),
78 }
79 }
80
81 fn correct_and_deposit_fee(
82 who: &AccountIdOf<T>,
83 _dispatch_info: &DispatchInfoOf<T::RuntimeCall>,
84 _post_info: &PostDispatchInfoOf<T::RuntimeCall>,
85 corrected_fee: Self::Balance,
86 _tip: Self::Balance,
87 liquidity_info: Self::LiquidityInfo,
88 ) -> Result<(), TransactionValidityError> {
89 if let Some(LiquidityInfo {
90 consensus_storage_fee,
91 imbalance,
92 }) = liquidity_info
93 {
94 let refund_amount = imbalance.peek().saturating_sub(corrected_fee);
96 let refund_imbalance = C::deposit_into_existing(who, refund_amount)
99 .unwrap_or_else(|_| C::PositiveImbalance::zero());
100 let adjusted_paid = imbalance
102 .offset(refund_imbalance)
103 .same()
104 .map_err(|_| TransactionValidityError::Invalid(InvalidTransaction::Payment))?;
105
106 let (paid_consensus_storage_fee, paid_domain_fee) =
109 adjusted_paid.split(consensus_storage_fee);
110
111 BlockFees::<T>::note_consensus_storage_fee(paid_consensus_storage_fee.peek());
112 BlockFees::<T>::note_domain_execution_fee(paid_domain_fee.peek());
113 }
114 Ok(())
115 }
116}