pallet_block_fees/
fees.rs1use crate::Pallet as BlockFees;
2use frame_support::traits::fungible::{Inspect, Mutate};
3use frame_support::traits::tokens::WithdrawConsequence;
4use frame_support::traits::{Currency, ExistenceRequirement, Imbalance, WithdrawReasons};
5use parity_scale_codec::Encode;
6use sp_runtime::Saturating;
7use sp_runtime::traits::{DispatchInfoOf, PostDispatchInfoOf, Zero};
8use sp_runtime::transaction_validity::{InvalidTransaction, TransactionValidityError};
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>>
28 + Inspect<AccountIdOf<T>, Balance = BalanceOf<C, T>>
29 + Mutate<AccountIdOf<T>>,
30 C::PositiveImbalance: Imbalance<BalanceOf<C, T>, Opposite = C::NegativeImbalance>,
31{
32 type Balance = BalanceOf<C, T>;
33 type LiquidityInfo = Option<LiquidityInfo<BalanceOf<C, T>, NegativeImbalanceOf<C, T>>>;
34
35 fn withdraw_fee(
36 who: &AccountIdOf<T>,
37 call: &T::RuntimeCall,
38 _info: &DispatchInfoOf<T::RuntimeCall>,
39 fee: Self::Balance,
40 tip: Self::Balance,
41 ) -> Result<Self::LiquidityInfo, TransactionValidityError> {
42 if fee.is_zero() {
43 return Ok(None);
44 }
45
46 let withdraw_reason = if tip.is_zero() {
47 WithdrawReasons::TRANSACTION_PAYMENT
48 } else {
49 WithdrawReasons::TRANSACTION_PAYMENT | WithdrawReasons::TIP
50 };
51
52 let withdraw_result =
53 C::withdraw(who, fee, withdraw_reason, ExistenceRequirement::KeepAlive);
54 let imbalance = withdraw_result.map_err(|_error| InvalidTransaction::Payment)?;
55
56 let consensus_storage_fee = BlockFees::<T>::consensus_chain_byte_fee()
58 * Self::Balance::from(call.encoded_size() as u32);
59
60 Ok(Some(LiquidityInfo {
61 consensus_storage_fee,
62 imbalance,
63 }))
64 }
65
66 fn can_withdraw_fee(
67 who: &T::AccountId,
68 _call: &T::RuntimeCall,
69 _dispatch_info: &DispatchInfoOf<T::RuntimeCall>,
70 fee: Self::Balance,
71 _tip: Self::Balance,
72 ) -> Result<(), TransactionValidityError> {
73 if fee.is_zero() {
74 return Ok(());
75 }
76
77 match C::can_withdraw(who, fee) {
78 WithdrawConsequence::Success => Ok(()),
79 _ => Err(InvalidTransaction::Payment.into()),
80 }
81 }
82
83 fn correct_and_deposit_fee(
84 who: &AccountIdOf<T>,
85 _dispatch_info: &DispatchInfoOf<T::RuntimeCall>,
86 _post_info: &PostDispatchInfoOf<T::RuntimeCall>,
87 corrected_fee: Self::Balance,
88 _tip: Self::Balance,
89 liquidity_info: Self::LiquidityInfo,
90 ) -> Result<(), TransactionValidityError> {
91 if let Some(LiquidityInfo {
92 consensus_storage_fee,
93 imbalance,
94 }) = liquidity_info
95 {
96 let refund_amount = imbalance.peek().saturating_sub(corrected_fee);
98 let refund_imbalance = C::deposit_into_existing(who, refund_amount)
101 .unwrap_or_else(|_| C::PositiveImbalance::zero());
102 let adjusted_paid = imbalance
104 .offset(refund_imbalance)
105 .same()
106 .map_err(|_| TransactionValidityError::Invalid(InvalidTransaction::Payment))?;
107
108 let (paid_consensus_storage_fee, paid_domain_fee) =
111 adjusted_paid.split(consensus_storage_fee);
112
113 BlockFees::<T>::note_consensus_storage_fee(paid_consensus_storage_fee.peek());
114 BlockFees::<T>::note_domain_execution_fee(paid_domain_fee.peek());
115 }
116 Ok(())
117 }
118
119 #[cfg(feature = "runtime-benchmarks")]
120 fn endow_account(who: &AccountIdOf<T>, amount: Self::Balance) {
121 C::set_balance(who, amount);
122 }
123
124 #[cfg(feature = "runtime-benchmarks")]
125 fn minimum_balance() -> Self::Balance {
126 <C as Currency<AccountIdOf<T>>>::minimum_balance()
127 }
128}