123456#![cfg_attr(not(feature = "std"), no_std)]78#[cfg(feature = "std")]9pub use std::*;1011use scale_info::TypeInfo;12#[cfg(feature = "std")]13pub use serde::*;1415use codec::{Decode, Encode};16use frame_support::traits::Get;17use frame_support::{18 decl_module, decl_storage,19 weights::{DispatchInfo, PostDispatchInfo, DispatchClass},20};21use sp_runtime::{22 traits::{23 DispatchInfoOf, Dispatchable, PostDispatchInfoOf, Saturating, SaturatedConversion,24 SignedExtension, Zero,25 },26 transaction_validity::{27 TransactionPriority, TransactionValidity, TransactionValidityError, ValidTransaction,28 },29 FixedPointOperand, DispatchResult,30};31use pallet_transaction_payment::OnChargeTransaction;32use sp_std::prelude::*;3334pub trait Config: frame_system::Config + pallet_nft_transaction_payment::Config + TypeInfo {}3536decl_storage! {37 trait Store for Module<T: Config> as NftTransactionPayment38 {}39}4041decl_module! {4243 pub struct Module<T: Config> for enum Call44 where45 origin: T::Origin,46 {}47}4849type BalanceOf<T> = <<T as pallet_transaction_payment::Config>::OnChargeTransaction as pallet_transaction_payment::OnChargeTransaction<T>>::Balance;50515253#[derive(Encode, Decode, Clone, Eq, PartialEq, scale_info::TypeInfo)]54pub struct ChargeTransactionPayment<T: Config>(#[codec(compact)] BalanceOf<T>);5556impl<T: Config + Send + Sync> sp_std::fmt::Debug for ChargeTransactionPayment<T> {57 #[cfg(feature = "std")]58 fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {59 write!(f, "ChargeTransactionPayment<{:?}>", self.0)60 }61 #[cfg(not(feature = "std"))]62 fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {63 Ok(())64 }65}6667impl<T: Config> ChargeTransactionPayment<T>68where69 T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo>,70 BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand,71{72 fn traditional_fee(73 len: usize,74 info: &DispatchInfoOf<T::Call>,75 tip: BalanceOf<T>,76 ) -> BalanceOf<T>77 where78 T::Call: Dispatchable<Info = DispatchInfo>,79 {80 <pallet_transaction_payment::Pallet<T>>::compute_fee(len as u32, info, tip)81 }8283 fn get_priority(84 len: usize,85 info: &DispatchInfoOf<T::Call>,86 final_fee: BalanceOf<T>,87 ) -> TransactionPriority {88 let weight_saturation = T::BlockWeights::get().max_block / info.weight.max(1);89 let max_block_length = *T::BlockLength::get().max.get(DispatchClass::Normal);90 let len_saturation = max_block_length as u64 / (len as u64).max(1);91 let coefficient: BalanceOf<T> = weight_saturation92 .min(len_saturation)93 .saturated_into::<BalanceOf<T>>();94 final_fee95 .saturating_mul(coefficient)96 .saturated_into::<TransactionPriority>()97 }9899 #[allow(clippy::type_complexity)]100 fn withdraw_fee(101 &self,102 who: &T::AccountId,103 call: &T::Call,104 info: &DispatchInfoOf<T::Call>,105 len: usize,106 ) -> Result<107 (108 BalanceOf<T>,109 <<T as pallet_transaction_payment::Config>::OnChargeTransaction as pallet_transaction_payment::OnChargeTransaction<T>>::LiquidityInfo,110 ),111 TransactionValidityError,112 >{113 let tip = self.0;114115 let fee = Self::traditional_fee(len, info, tip);116117 118 if fee.is_zero() {119 return <<T as pallet_transaction_payment::Config>::OnChargeTransaction as pallet_transaction_payment::OnChargeTransaction<T>>::withdraw_fee(who, call, info, fee, tip)120 .map(|i| (fee, i));121 }122123 124 125 let sponsor = <pallet_nft_transaction_payment::Module<T>>::withdraw_type(who, call);126127 let who_pays_fee = sponsor.unwrap_or_else(|| who.clone());128129 <<T as pallet_transaction_payment::Config>::OnChargeTransaction as pallet_transaction_payment::OnChargeTransaction<T>>::withdraw_fee(&who_pays_fee, call, info, fee, tip)130 .map(|i| (fee, i))131 }132}133134impl<T: Config + Send + Sync> SignedExtension for ChargeTransactionPayment<T>135where136 BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand,137 T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo>,138{139 const IDENTIFIER: &'static str = "ChargeTransactionPayment";140 type AccountId = T::AccountId;141 type Call = T::Call;142 type AdditionalSigned = ();143 type Pre = (144 145 BalanceOf<T>,146 147 Self::AccountId,148 149 <<T as pallet_transaction_payment::Config>::OnChargeTransaction as pallet_transaction_payment::OnChargeTransaction<T>>::LiquidityInfo,150 );151 fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> {152 Ok(())153 }154155 fn validate(156 &self,157 who: &Self::AccountId,158 call: &Self::Call,159 info: &DispatchInfoOf<Self::Call>,160 len: usize,161 ) -> TransactionValidity {162 let (fee, _) = self.withdraw_fee(who, call, info, len)?;163 Ok(ValidTransaction {164 priority: Self::get_priority(len, info, fee),165 ..Default::default()166 })167 }168169 fn pre_dispatch(170 self,171 who: &Self::AccountId,172 call: &Self::Call,173 info: &DispatchInfoOf<Self::Call>,174 len: usize,175 ) -> Result<Self::Pre, TransactionValidityError> {176 let (_fee, imbalance) = self.withdraw_fee(who, call, info, len)?;177 Ok((self.0, who.clone(), imbalance))178 }179180 fn post_dispatch(181 pre: Self::Pre,182 info: &DispatchInfoOf<Self::Call>,183 post_info: &PostDispatchInfoOf<Self::Call>,184 len: usize,185 _result: &DispatchResult,186 ) -> Result<(), TransactionValidityError> {187 let (tip, who, imbalance) = pre;188 let actual_fee = pallet_transaction_payment::Pallet::<T>::compute_actual_fee(189 len as u32, info, post_info, tip,190 );191 <T as pallet_transaction_payment::Config>::OnChargeTransaction::correct_and_deposit_fee(192 &who, info, post_info, actual_fee, tip, imbalance,193 )?;194 Ok(())195 }196}