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::TxCreditHold<T> for OnChargeDomainTransaction<C>
27where
28 T: pallet_transaction_payment::Config,
29{
30 type Credit = ();
31}
32
33impl<T, C> pallet_transaction_payment::OnChargeTransaction<T> for OnChargeDomainTransaction<C>
34where
35 T: pallet_transaction_payment::Config + crate::Config<Balance = BalanceOf<C, T>>,
36 C: Currency<AccountIdOf<T>>
37 + Inspect<AccountIdOf<T>, Balance = BalanceOf<C, T>>
38 + Mutate<AccountIdOf<T>>,
39 C::PositiveImbalance: Imbalance<BalanceOf<C, T>, Opposite = C::NegativeImbalance>,
40{
41 type Balance = BalanceOf<C, T>;
42 type LiquidityInfo = Option<LiquidityInfo<BalanceOf<C, T>, NegativeImbalanceOf<C, T>>>;
43
44 fn withdraw_fee(
45 who: &AccountIdOf<T>,
46 call: &T::RuntimeCall,
47 _info: &DispatchInfoOf<T::RuntimeCall>,
48 fee: Self::Balance,
49 tip: Self::Balance,
50 ) -> Result<Self::LiquidityInfo, TransactionValidityError> {
51 if fee.is_zero() {
52 return Ok(None);
53 }
54
55 let withdraw_reason = if tip.is_zero() {
56 WithdrawReasons::TRANSACTION_PAYMENT
57 } else {
58 WithdrawReasons::TRANSACTION_PAYMENT | WithdrawReasons::TIP
59 };
60
61 let withdraw_result =
62 C::withdraw(who, fee, withdraw_reason, ExistenceRequirement::KeepAlive);
63 let imbalance = withdraw_result.map_err(|_error| InvalidTransaction::Payment)?;
64
65 let consensus_storage_fee = BlockFees::<T>::consensus_chain_byte_fee()
67 * Self::Balance::from(call.encoded_size() as u32);
68
69 Ok(Some(LiquidityInfo {
70 consensus_storage_fee,
71 imbalance,
72 }))
73 }
74
75 fn can_withdraw_fee(
76 who: &T::AccountId,
77 _call: &T::RuntimeCall,
78 _dispatch_info: &DispatchInfoOf<T::RuntimeCall>,
79 fee: Self::Balance,
80 _tip: Self::Balance,
81 ) -> Result<(), TransactionValidityError> {
82 if fee.is_zero() {
83 return Ok(());
84 }
85
86 match C::can_withdraw(who, fee) {
87 WithdrawConsequence::Success => Ok(()),
88 _ => Err(InvalidTransaction::Payment.into()),
89 }
90 }
91
92 fn correct_and_deposit_fee(
93 who: &AccountIdOf<T>,
94 _dispatch_info: &DispatchInfoOf<T::RuntimeCall>,
95 _post_info: &PostDispatchInfoOf<T::RuntimeCall>,
96 corrected_fee: Self::Balance,
97 _tip: Self::Balance,
98 liquidity_info: Self::LiquidityInfo,
99 ) -> Result<(), TransactionValidityError> {
100 if let Some(LiquidityInfo {
101 consensus_storage_fee,
102 imbalance,
103 }) = liquidity_info
104 {
105 let refund_amount = imbalance.peek().saturating_sub(corrected_fee);
107 let refund_imbalance = C::deposit_into_existing(who, refund_amount)
110 .unwrap_or_else(|_| C::PositiveImbalance::zero());
111 let adjusted_paid = imbalance
113 .offset(refund_imbalance)
114 .same()
115 .map_err(|_| TransactionValidityError::Invalid(InvalidTransaction::Payment))?;
116
117 let (paid_consensus_storage_fee, paid_domain_fee) =
120 adjusted_paid.split(consensus_storage_fee);
121
122 BlockFees::<T>::note_consensus_storage_fee(paid_consensus_storage_fee.peek());
123 BlockFees::<T>::note_domain_execution_fee(paid_domain_fee.peek());
124 }
125 Ok(())
126 }
127
128 #[cfg(feature = "runtime-benchmarks")]
129 fn endow_account(who: &AccountIdOf<T>, amount: Self::Balance) {
130 C::set_balance(who, amount);
131 }
132
133 #[cfg(feature = "runtime-benchmarks")]
134 fn minimum_balance() -> Self::Balance {
135 <C as Currency<AccountIdOf<T>>>::minimum_balance()
136 }
137}