123456#![cfg_attr(not(feature = "std"), no_std)]78#[cfg(feature = "std")]9pub use std::*;1011#[cfg(feature = "std")]12pub use serde::*;1314#[cfg(feature = "runtime-benchmarks")]15mod benchmarking;1617#[cfg(test)]18mod tests;1920use codec::{Decode, Encode};21use frame_support::traits::{ Get};22use frame_support::{23 decl_module, decl_storage,24 traits::{25 IsSubType, 26 },27 weights::{28 DispatchInfo, PostDispatchInfo, DispatchClass29 }30};31use sp_runtime::{32 traits::{ 33 DispatchInfoOf, Dispatchable, PostDispatchInfoOf, Saturating, SaturatedConversion, SignedExtension, Zero,34 },35 transaction_validity::{ 36 TransactionPriority, TransactionValidity, TransactionValidityError, ValidTransaction,37 },38 FixedPointOperand, DispatchResult39};40use pallet_contracts::chain_extension::UncheckedFrom;41use pallet_transaction_payment::OnChargeTransaction;42use sp_std::prelude::*;434445pub trait Config: frame_system::Config + 46 pallet_nft_transaction_payment::Config47{4849}5051decl_storage! {52 trait Store for Module<T: Config> as NftTransactionPayment53 {}54}5556decl_module! {5758 pub struct Module<T: Config> for enum Call 59 where 60 origin: T::Origin,61 {}62}6364type BalanceOf<T> = <<T as pallet_transaction_payment::Config>::OnChargeTransaction as pallet_transaction_payment::OnChargeTransaction<T>>::Balance;65666768#[derive(Encode, Decode, Clone, Eq, PartialEq)]69pub struct ChargeTransactionPayment<T: Config>(#[codec(compact)] BalanceOf<T>);7071impl<T: Config + Send + Sync> sp_std::fmt::Debug 72 for ChargeTransactionPayment<T>73{74 #[cfg(feature = "std")]75 fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {76 write!(f, "ChargeTransactionPayment<{:?}>", self.0)77 }78 #[cfg(not(feature = "std"))]79 fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {80 Ok(())81 }82}8384impl<T: Config> ChargeTransactionPayment<T>85where86 T::Call: Dispatchable<Info=DispatchInfo, PostInfo=PostDispatchInfo> + IsSubType<pallet_nft::Call<T>> + IsSubType<pallet_contracts::Call<T>>,87 BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand,88 T::AccountId: AsRef<[u8]>,89 T::AccountId: UncheckedFrom<T::Hash>,90{91 fn traditional_fee(92 len: usize,93 info: &DispatchInfoOf<T::Call>,94 tip: BalanceOf<T>,95 ) -> BalanceOf<T>96 where97 T::Call: Dispatchable<Info = DispatchInfo>,98 {99 <pallet_transaction_payment::Module<T>>::compute_fee(len as u32, info, tip)100 }101102 fn get_priority(len: usize, info: &DispatchInfoOf<T::Call>, final_fee: BalanceOf<T>) -> TransactionPriority {103 let weight_saturation = T::BlockWeights::get().max_block / info.weight.max(1);104 let max_block_length = *T::BlockLength::get().max.get(DispatchClass::Normal);105 let len_saturation = max_block_length as u64 / (len as u64).max(1);106 let coefficient: BalanceOf<T> = weight_saturation107 .min(len_saturation)108 .saturated_into::<BalanceOf<T>>();109 final_fee110 .saturating_mul(coefficient)111 .saturated_into::<TransactionPriority>()112 }113114 fn withdraw_fee(115 &self,116 who: &T::AccountId,117 call: &T::Call,118 info: &DispatchInfoOf<T::Call>,119 len: usize,120 ) -> Result<121 (122 BalanceOf<T>,123 <<T as pallet_transaction_payment::Config>::OnChargeTransaction as pallet_transaction_payment::OnChargeTransaction<T>>::LiquidityInfo,124 ),125 TransactionValidityError,126 > {127 let tip = self.0;128129 let fee = Self::traditional_fee(len, info, tip);130131 132 if fee.is_zero() {133 return <<T as pallet_transaction_payment::Config>::OnChargeTransaction as pallet_transaction_payment::OnChargeTransaction<T>>::withdraw_fee(who, call, info, fee, tip)134 .map(|i| (fee, i));135 }136137 138 let _error = <pallet_nft_transaction_payment::Module<T>>::check_error(who, call);139 match _error {140 Err(_error) => return Err(_error),141 Ok(_error) => {}142 };143144 145 146 let sponsor = <pallet_nft_transaction_payment::Module<T>>::withdraw_type(who, call);147148 let who_pays_fee = sponsor.unwrap_or_else(|| who.clone());149150 <<T as pallet_transaction_payment::Config>::OnChargeTransaction as pallet_transaction_payment::OnChargeTransaction<T>>::withdraw_fee(&who_pays_fee, call, info, fee, tip)151 .map(|i| (fee, i))152 }153}154155impl<T: Config + Send + Sync> SignedExtension156 for ChargeTransactionPayment<T>157where158 BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand,159 T::Call: Dispatchable<Info=DispatchInfo, PostInfo=PostDispatchInfo> + IsSubType<pallet_nft::Call<T>> + IsSubType<pallet_contracts::Call<T>>,160 T::AccountId: AsRef<[u8]>,161 T::AccountId: UncheckedFrom<T::Hash>,162{163 const IDENTIFIER: &'static str = "ChargeTransactionPayment";164 type AccountId = T::AccountId;165 type Call = T::Call;166 type AdditionalSigned = ();167 type Pre = (168 169 BalanceOf<T>,170 171 Self::AccountId,172 173 <<T as pallet_transaction_payment::Config>::OnChargeTransaction as pallet_transaction_payment::OnChargeTransaction<T>>::LiquidityInfo,174 );175 fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> {176 Ok(())177 }178179 fn validate(180 &self,181 who: &Self::AccountId,182 call: &Self::Call,183 info: &DispatchInfoOf<Self::Call>,184 len: usize,185 ) -> TransactionValidity {186 let (fee, _) = self.withdraw_fee(who, call, info, len)?;187 Ok(ValidTransaction {188 priority: Self::get_priority(len, info, fee),189 ..Default::default()190 })191 }192193 fn pre_dispatch(194 self,195 who: &Self::AccountId,196 call: &Self::Call,197 info: &DispatchInfoOf<Self::Call>,198 len: usize,199 ) -> Result<Self::Pre, TransactionValidityError> {200 let (_fee, imbalance) = self.withdraw_fee(who, call, info, len)?;201 Ok((self.0, who.clone(), imbalance))202 }203204 fn post_dispatch(205 pre: Self::Pre,206 info: &DispatchInfoOf<Self::Call>,207 post_info: &PostDispatchInfoOf<Self::Call>,208 len: usize,209 _result: &DispatchResult,210 ) -> Result<(), TransactionValidityError> {211 let (tip, who, imbalance) = pre;212 let actual_fee = pallet_transaction_payment::Module::<T>::compute_actual_fee(213 len as u32,214 info,215 post_info,216 tip,217 );218 <T as pallet_transaction_payment::Config>::OnChargeTransaction::correct_and_deposit_fee(&who, info, post_info, actual_fee, tip, imbalance)?;219 Ok(())220 }221}