123456#![cfg_attr(not(feature = "std"), no_std)]78#[cfg(feature = "std")]9pub use std::*;1011#[cfg(feature = "std")]12pub use serde::*;1314use codec::{Decode, Encode};15use frame_support::traits::Get;16use frame_support::{17 decl_module, decl_storage,18 weights::{DispatchInfo, PostDispatchInfo, DispatchClass},19};20use sp_runtime::{21 traits::{22 DispatchInfoOf, Dispatchable, PostDispatchInfoOf, Saturating, SaturatedConversion,23 SignedExtension, Zero,24 },25 transaction_validity::{26 TransactionPriority, TransactionValidity, TransactionValidityError, ValidTransaction,27 },28 FixedPointOperand, DispatchResult,29};30use pallet_transaction_payment::OnChargeTransaction;31use sp_std::prelude::*;3233pub trait Config: frame_system::Config + pallet_nft_transaction_payment::Config {}3435decl_storage! {36 trait Store for Module<T: Config> as NftTransactionPayment37 {}38}3940decl_module! {4142 pub struct Module<T: Config> for enum Call43 where44 origin: T::Origin,45 {}46}4748type BalanceOf<T> = <<T as pallet_transaction_payment::Config>::OnChargeTransaction as pallet_transaction_payment::OnChargeTransaction<T>>::Balance;49505152#[derive(Encode, Decode, Clone, Eq, PartialEq)]53pub struct ChargeTransactionPayment<T: Config>(#[codec(compact)] BalanceOf<T>);5455impl<T: Config + Send + Sync> sp_std::fmt::Debug for ChargeTransactionPayment<T> {56 #[cfg(feature = "std")]57 fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {58 write!(f, "ChargeTransactionPayment<{:?}>", self.0)59 }60 #[cfg(not(feature = "std"))]61 fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {62 Ok(())63 }64}6566impl<T: Config> ChargeTransactionPayment<T>67where68 T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo>,69 BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand,70{71 fn traditional_fee(72 len: usize,73 info: &DispatchInfoOf<T::Call>,74 tip: BalanceOf<T>,75 ) -> BalanceOf<T>76 where77 T::Call: Dispatchable<Info = DispatchInfo>,78 {79 <pallet_transaction_payment::Module<T>>::compute_fee(len as u32, info, tip)80 }8182 fn get_priority(83 len: usize,84 info: &DispatchInfoOf<T::Call>,85 final_fee: BalanceOf<T>,86 ) -> TransactionPriority {87 let weight_saturation = T::BlockWeights::get().max_block / info.weight.max(1);88 let max_block_length = *T::BlockLength::get().max.get(DispatchClass::Normal);89 let len_saturation = max_block_length as u64 / (len as u64).max(1);90 let coefficient: BalanceOf<T> = weight_saturation91 .min(len_saturation)92 .saturated_into::<BalanceOf<T>>();93 final_fee94 .saturating_mul(coefficient)95 .saturated_into::<TransactionPriority>()96 }9798 #[allow(clippy::type_complexity)]99 fn withdraw_fee(100 &self,101 who: &T::AccountId,102 call: &T::Call,103 info: &DispatchInfoOf<T::Call>,104 len: usize,105 ) -> Result<106 (107 BalanceOf<T>,108 <<T as pallet_transaction_payment::Config>::OnChargeTransaction as pallet_transaction_payment::OnChargeTransaction<T>>::LiquidityInfo,109 ),110 TransactionValidityError,111 >{112 let tip = self.0;113114 let fee = Self::traditional_fee(len, info, tip);115116 117 if fee.is_zero() {118 return <<T as pallet_transaction_payment::Config>::OnChargeTransaction as pallet_transaction_payment::OnChargeTransaction<T>>::withdraw_fee(who, call, info, fee, tip)119 .map(|i| (fee, i));120 }121122 123 124 let sponsor = <pallet_nft_transaction_payment::Module<T>>::withdraw_type(who, call);125126 let who_pays_fee = sponsor.unwrap_or_else(|| who.clone());127128 <<T as pallet_transaction_payment::Config>::OnChargeTransaction as pallet_transaction_payment::OnChargeTransaction<T>>::withdraw_fee(&who_pays_fee, call, info, fee, tip)129 .map(|i| (fee, i))130 }131}132133impl<T: Config + Send + Sync> SignedExtension for ChargeTransactionPayment<T>134where135 BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand,136 T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo>,137{138 const IDENTIFIER: &'static str = "ChargeTransactionPayment";139 type AccountId = T::AccountId;140 type Call = T::Call;141 type AdditionalSigned = ();142 type Pre = (143 144 BalanceOf<T>,145 146 Self::AccountId,147 148 <<T as pallet_transaction_payment::Config>::OnChargeTransaction as pallet_transaction_payment::OnChargeTransaction<T>>::LiquidityInfo,149 );150 fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> {151 Ok(())152 }153154 fn validate(155 &self,156 who: &Self::AccountId,157 call: &Self::Call,158 info: &DispatchInfoOf<Self::Call>,159 len: usize,160 ) -> TransactionValidity {161 let (fee, _) = self.withdraw_fee(who, call, info, len)?;162 Ok(ValidTransaction {163 priority: Self::get_priority(len, info, fee),164 ..Default::default()165 })166 }167168 fn pre_dispatch(169 self,170 who: &Self::AccountId,171 call: &Self::Call,172 info: &DispatchInfoOf<Self::Call>,173 len: usize,174 ) -> Result<Self::Pre, TransactionValidityError> {175 let (_fee, imbalance) = self.withdraw_fee(who, call, info, len)?;176 Ok((self.0, who.clone(), imbalance))177 }178179 fn post_dispatch(180 pre: Self::Pre,181 info: &DispatchInfoOf<Self::Call>,182 post_info: &PostDispatchInfoOf<Self::Call>,183 len: usize,184 _result: &DispatchResult,185 ) -> Result<(), TransactionValidityError> {186 let (tip, who, imbalance) = pre;187 let actual_fee = pallet_transaction_payment::Pallet::<T>::compute_actual_fee(188 len as u32, info, post_info, tip,189 );190 <T as pallet_transaction_payment::Config>::OnChargeTransaction::correct_and_deposit_fee(191 &who, info, post_info, actual_fee, tip, imbalance,192 )?;193 Ok(())194 }195}