1#![cfg_attr(not(feature = "std"), no_std)]
49
50use codec::{Decode, Encode, MaxEncodedLen};
51use scale_info::TypeInfo;
52
53use frame_support::{
54 dispatch::{
55 DispatchClass, DispatchInfo, DispatchResult, GetDispatchInfo, Pays, PostDispatchInfo,
56 },
57 pallet_prelude::TransactionSource,
58 traits::{Defensive, EstimateCallFee, Get},
59 weights::{Weight, WeightToFee},
60 RuntimeDebugNoBound,
61};
62pub use pallet::*;
63pub use payment::*;
64use sp_runtime::{
65 traits::{
66 Convert, DispatchInfoOf, Dispatchable, One, PostDispatchInfoOf, SaturatedConversion,
67 Saturating, TransactionExtension, Zero,
68 },
69 transaction_validity::{TransactionPriority, TransactionValidityError, ValidTransaction},
70 FixedPointNumber, FixedU128, Perbill, Perquintill, RuntimeDebug,
71};
72pub use types::{FeeDetails, InclusionFee, RuntimeDispatchInfo};
73pub use weights::WeightInfo;
74
75#[cfg(test)]
76mod mock;
77#[cfg(test)]
78mod tests;
79
80#[cfg(feature = "runtime-benchmarks")]
81mod benchmarking;
82
83mod payment;
84mod types;
85pub mod weights;
86
87pub type Multiplier = FixedU128;
89
90type BalanceOf<T> = <<T as Config>::OnChargeTransaction as OnChargeTransaction<T>>::Balance;
91
92pub struct TargetedFeeAdjustment<T, S, V, M, X>(core::marker::PhantomData<(T, S, V, M, X)>);
145
146pub trait MultiplierUpdate: Convert<Multiplier, Multiplier> {
148 fn min() -> Multiplier;
150 fn max() -> Multiplier;
152 fn target() -> Perquintill;
154 fn variability() -> Multiplier;
156}
157
158impl MultiplierUpdate for () {
159 fn min() -> Multiplier {
160 Default::default()
161 }
162 fn max() -> Multiplier {
163 <Multiplier as sp_runtime::traits::Bounded>::max_value()
164 }
165 fn target() -> Perquintill {
166 Default::default()
167 }
168 fn variability() -> Multiplier {
169 Default::default()
170 }
171}
172
173impl<T, S, V, M, X> MultiplierUpdate for TargetedFeeAdjustment<T, S, V, M, X>
174where
175 T: frame_system::Config,
176 S: Get<Perquintill>,
177 V: Get<Multiplier>,
178 M: Get<Multiplier>,
179 X: Get<Multiplier>,
180{
181 fn min() -> Multiplier {
182 M::get()
183 }
184 fn max() -> Multiplier {
185 X::get()
186 }
187 fn target() -> Perquintill {
188 S::get()
189 }
190 fn variability() -> Multiplier {
191 V::get()
192 }
193}
194
195impl<T, S, V, M, X> Convert<Multiplier, Multiplier> for TargetedFeeAdjustment<T, S, V, M, X>
196where
197 T: frame_system::Config,
198 S: Get<Perquintill>,
199 V: Get<Multiplier>,
200 M: Get<Multiplier>,
201 X: Get<Multiplier>,
202{
203 fn convert(previous: Multiplier) -> Multiplier {
204 let min_multiplier = M::get();
208 let max_multiplier = X::get();
209 let previous = previous.max(min_multiplier);
210
211 let weights = T::BlockWeights::get();
212 let normal_max_weight =
214 weights.get(DispatchClass::Normal).max_total.unwrap_or(weights.max_block);
215 let current_block_weight = frame_system::Pallet::<T>::block_weight();
216 let normal_block_weight =
217 current_block_weight.get(DispatchClass::Normal).min(normal_max_weight);
218
219 let normalized_ref_time = Perbill::from_rational(
221 normal_block_weight.ref_time(),
222 normal_max_weight.ref_time().max(1),
223 );
224 let normalized_proof_size = Perbill::from_rational(
225 normal_block_weight.proof_size(),
226 normal_max_weight.proof_size().max(1),
227 );
228
229 let (normal_limiting_dimension, max_limiting_dimension) =
232 if normalized_ref_time < normalized_proof_size {
233 (normal_block_weight.proof_size(), normal_max_weight.proof_size())
234 } else {
235 (normal_block_weight.ref_time(), normal_max_weight.ref_time())
236 };
237
238 let target_block_fullness = S::get();
239 let adjustment_variable = V::get();
240
241 let target_weight = (target_block_fullness * max_limiting_dimension) as u128;
242 let block_weight = normal_limiting_dimension as u128;
243
244 let positive = block_weight >= target_weight;
246 let diff_abs = block_weight.max(target_weight) - block_weight.min(target_weight);
247
248 let diff = Multiplier::saturating_from_rational(diff_abs, max_limiting_dimension.max(1));
251 let diff_squared = diff.saturating_mul(diff);
252
253 let v_squared_2 = adjustment_variable.saturating_mul(adjustment_variable) /
254 Multiplier::saturating_from_integer(2);
255
256 let first_term = adjustment_variable.saturating_mul(diff);
257 let second_term = v_squared_2.saturating_mul(diff_squared);
258
259 if positive {
260 let excess = first_term.saturating_add(second_term).saturating_mul(previous);
261 previous.saturating_add(excess).clamp(min_multiplier, max_multiplier)
262 } else {
263 let negative = first_term.saturating_sub(second_term).saturating_mul(previous);
265 previous.saturating_sub(negative).clamp(min_multiplier, max_multiplier)
266 }
267 }
268}
269
270pub struct ConstFeeMultiplier<M: Get<Multiplier>>(core::marker::PhantomData<M>);
272
273impl<M: Get<Multiplier>> MultiplierUpdate for ConstFeeMultiplier<M> {
274 fn min() -> Multiplier {
275 M::get()
276 }
277 fn max() -> Multiplier {
278 M::get()
279 }
280 fn target() -> Perquintill {
281 Default::default()
282 }
283 fn variability() -> Multiplier {
284 Default::default()
285 }
286}
287
288impl<M> Convert<Multiplier, Multiplier> for ConstFeeMultiplier<M>
289where
290 M: Get<Multiplier>,
291{
292 fn convert(_previous: Multiplier) -> Multiplier {
293 Self::min()
294 }
295}
296
297#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)]
299pub enum Releases {
300 V1Ancient,
302 V2,
304}
305
306impl Default for Releases {
307 fn default() -> Self {
308 Releases::V1Ancient
309 }
310}
311
312const MULTIPLIER_DEFAULT_VALUE: Multiplier = Multiplier::from_u32(1);
315
316#[frame_support::pallet]
317pub mod pallet {
318 use frame_support::pallet_prelude::*;
319 use frame_system::pallet_prelude::*;
320
321 use super::*;
322
323 #[pallet::pallet]
324 pub struct Pallet<T>(_);
325
326 pub mod config_preludes {
327 use super::*;
328 use frame_support::derive_impl;
329
330 pub struct TestDefaultConfig;
332
333 #[derive_impl(frame_system::config_preludes::TestDefaultConfig, no_aggregated_types)]
334 impl frame_system::DefaultConfig for TestDefaultConfig {}
335
336 #[frame_support::register_default_impl(TestDefaultConfig)]
337 impl DefaultConfig for TestDefaultConfig {
338 #[inject_runtime_type]
339 type RuntimeEvent = ();
340 type FeeMultiplierUpdate = ();
341 type OperationalFeeMultiplier = ();
342 type WeightInfo = ();
343 }
344 }
345
346 #[pallet::config(with_default)]
347 pub trait Config: frame_system::Config {
348 #[pallet::no_default_bounds]
350 type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
351
352 #[pallet::no_default]
359 type OnChargeTransaction: OnChargeTransaction<Self>;
360
361 #[pallet::no_default]
363 type WeightToFee: WeightToFee<Balance = BalanceOf<Self>>;
364
365 #[pallet::no_default]
367 type LengthToFee: WeightToFee<Balance = BalanceOf<Self>>;
368
369 type FeeMultiplierUpdate: MultiplierUpdate;
371
372 #[pallet::constant]
394 type OperationalFeeMultiplier: Get<u8>;
395
396 type WeightInfo: WeightInfo;
398 }
399
400 #[pallet::type_value]
401 pub fn NextFeeMultiplierOnEmpty() -> Multiplier {
402 MULTIPLIER_DEFAULT_VALUE
403 }
404
405 #[pallet::storage]
406 #[pallet::whitelist_storage]
407 pub type NextFeeMultiplier<T: Config> =
408 StorageValue<_, Multiplier, ValueQuery, NextFeeMultiplierOnEmpty>;
409
410 #[pallet::storage]
411 pub type StorageVersion<T: Config> = StorageValue<_, Releases, ValueQuery>;
412
413 #[pallet::genesis_config]
414 pub struct GenesisConfig<T: Config> {
415 pub multiplier: Multiplier,
416 #[serde(skip)]
417 pub _config: core::marker::PhantomData<T>,
418 }
419
420 impl<T: Config> Default for GenesisConfig<T> {
421 fn default() -> Self {
422 Self { multiplier: MULTIPLIER_DEFAULT_VALUE, _config: Default::default() }
423 }
424 }
425
426 #[pallet::genesis_build]
427 impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
428 fn build(&self) {
429 StorageVersion::<T>::put(Releases::V2);
430 NextFeeMultiplier::<T>::put(self.multiplier);
431 }
432 }
433
434 #[pallet::event]
435 #[pallet::generate_deposit(pub(super) fn deposit_event)]
436 pub enum Event<T: Config> {
437 TransactionFeePaid { who: T::AccountId, actual_fee: BalanceOf<T>, tip: BalanceOf<T> },
440 }
441
442 #[pallet::hooks]
443 impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
444 fn on_finalize(_: frame_system::pallet_prelude::BlockNumberFor<T>) {
445 NextFeeMultiplier::<T>::mutate(|fm| {
446 *fm = T::FeeMultiplierUpdate::convert(*fm);
447 });
448 }
449
450 #[cfg(feature = "std")]
451 fn integrity_test() {
452 assert!(
456 <Multiplier as sp_runtime::traits::Bounded>::max_value() >=
457 Multiplier::checked_from_integer::<u128>(
458 T::BlockWeights::get().max_block.ref_time().try_into().unwrap()
459 )
460 .unwrap(),
461 );
462
463 let target = T::FeeMultiplierUpdate::target() *
464 T::BlockWeights::get().get(DispatchClass::Normal).max_total.expect(
465 "Setting `max_total` for `Normal` dispatch class is not compatible with \
466 `transaction-payment` pallet.",
467 );
468 let addition = target / 100;
470 if addition == Weight::zero() {
471 return
474 }
475
476 let min_value = T::FeeMultiplierUpdate::min();
481 let target = target + addition;
482
483 frame_system::Pallet::<T>::set_block_consumed_resources(target, 0);
484 let next = T::FeeMultiplierUpdate::convert(min_value);
485 assert!(
486 next > min_value,
487 "The minimum bound of the multiplier is too low. When \
488 block saturation is more than target by 1% and multiplier is minimal then \
489 the multiplier doesn't increase."
490 );
491 }
492 }
493}
494
495impl<T: Config> Pallet<T> {
496 pub fn next_fee_multiplier() -> Multiplier {
498 NextFeeMultiplier::<T>::get()
499 }
500
501 pub fn query_info<Extrinsic: sp_runtime::traits::ExtrinsicLike + GetDispatchInfo>(
510 unchecked_extrinsic: Extrinsic,
511 len: u32,
512 ) -> RuntimeDispatchInfo<BalanceOf<T>>
513 where
514 T::RuntimeCall: Dispatchable<Info = DispatchInfo>,
515 {
516 let dispatch_info = <Extrinsic as GetDispatchInfo>::get_dispatch_info(&unchecked_extrinsic);
522
523 let partial_fee = if unchecked_extrinsic.is_bare() {
524 0u32.into()
526 } else {
527 Self::compute_fee(len, &dispatch_info, 0u32.into())
528 };
529
530 let DispatchInfo { class, .. } = dispatch_info;
531
532 RuntimeDispatchInfo { weight: dispatch_info.total_weight(), class, partial_fee }
533 }
534
535 pub fn query_fee_details<Extrinsic: sp_runtime::traits::ExtrinsicLike + GetDispatchInfo>(
537 unchecked_extrinsic: Extrinsic,
538 len: u32,
539 ) -> FeeDetails<BalanceOf<T>>
540 where
541 T::RuntimeCall: Dispatchable<Info = DispatchInfo>,
542 {
543 let dispatch_info = <Extrinsic as GetDispatchInfo>::get_dispatch_info(&unchecked_extrinsic);
544
545 let tip = 0u32.into();
546
547 if unchecked_extrinsic.is_bare() {
548 FeeDetails { inclusion_fee: None, tip }
550 } else {
551 Self::compute_fee_details(len, &dispatch_info, tip)
552 }
553 }
554
555 pub fn query_call_info(call: T::RuntimeCall, len: u32) -> RuntimeDispatchInfo<BalanceOf<T>>
557 where
558 T::RuntimeCall: Dispatchable<Info = DispatchInfo> + GetDispatchInfo,
559 {
560 let dispatch_info = <T::RuntimeCall as GetDispatchInfo>::get_dispatch_info(&call);
561 let DispatchInfo { class, .. } = dispatch_info;
562
563 RuntimeDispatchInfo {
564 weight: dispatch_info.total_weight(),
565 class,
566 partial_fee: Self::compute_fee(len, &dispatch_info, 0u32.into()),
567 }
568 }
569
570 pub fn query_call_fee_details(call: T::RuntimeCall, len: u32) -> FeeDetails<BalanceOf<T>>
572 where
573 T::RuntimeCall: Dispatchable<Info = DispatchInfo> + GetDispatchInfo,
574 {
575 let dispatch_info = <T::RuntimeCall as GetDispatchInfo>::get_dispatch_info(&call);
576 let tip = 0u32.into();
577
578 Self::compute_fee_details(len, &dispatch_info, tip)
579 }
580
581 pub fn compute_fee(
583 len: u32,
584 info: &DispatchInfoOf<T::RuntimeCall>,
585 tip: BalanceOf<T>,
586 ) -> BalanceOf<T>
587 where
588 T::RuntimeCall: Dispatchable<Info = DispatchInfo>,
589 {
590 Self::compute_fee_details(len, info, tip).final_fee()
591 }
592
593 pub fn compute_fee_details(
595 len: u32,
596 info: &DispatchInfoOf<T::RuntimeCall>,
597 tip: BalanceOf<T>,
598 ) -> FeeDetails<BalanceOf<T>>
599 where
600 T::RuntimeCall: Dispatchable<Info = DispatchInfo>,
601 {
602 Self::compute_fee_raw(len, info.total_weight(), tip, info.pays_fee, info.class)
603 }
604
605 pub fn compute_actual_fee(
610 len: u32,
611 info: &DispatchInfoOf<T::RuntimeCall>,
612 post_info: &PostDispatchInfoOf<T::RuntimeCall>,
613 tip: BalanceOf<T>,
614 ) -> BalanceOf<T>
615 where
616 T::RuntimeCall: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo>,
617 {
618 Self::compute_actual_fee_details(len, info, post_info, tip).final_fee()
619 }
620
621 pub fn compute_actual_fee_details(
623 len: u32,
624 info: &DispatchInfoOf<T::RuntimeCall>,
625 post_info: &PostDispatchInfoOf<T::RuntimeCall>,
626 tip: BalanceOf<T>,
627 ) -> FeeDetails<BalanceOf<T>>
628 where
629 T::RuntimeCall: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo>,
630 {
631 Self::compute_fee_raw(
632 len,
633 post_info.calc_actual_weight(info),
634 tip,
635 post_info.pays_fee(info),
636 info.class,
637 )
638 }
639
640 fn compute_fee_raw(
641 len: u32,
642 weight: Weight,
643 tip: BalanceOf<T>,
644 pays_fee: Pays,
645 class: DispatchClass,
646 ) -> FeeDetails<BalanceOf<T>> {
647 if pays_fee == Pays::Yes {
648 let unadjusted_weight_fee = Self::weight_to_fee(weight);
650 let multiplier = NextFeeMultiplier::<T>::get();
651 let adjusted_weight_fee = multiplier.saturating_mul_int(unadjusted_weight_fee);
653
654 let len_fee = Self::length_to_fee(len);
656
657 let base_fee = Self::weight_to_fee(T::BlockWeights::get().get(class).base_extrinsic);
658 FeeDetails {
659 inclusion_fee: Some(InclusionFee { base_fee, len_fee, adjusted_weight_fee }),
660 tip,
661 }
662 } else {
663 FeeDetails { inclusion_fee: None, tip }
664 }
665 }
666
667 pub fn length_to_fee(length: u32) -> BalanceOf<T> {
669 T::LengthToFee::weight_to_fee(&Weight::from_parts(length as u64, 0))
670 }
671
672 pub fn weight_to_fee(weight: Weight) -> BalanceOf<T> {
675 let capped_weight = weight.min(T::BlockWeights::get().max_block);
678 T::WeightToFee::weight_to_fee(&capped_weight)
679 }
680
681 pub fn deposit_fee_paid_event(who: T::AccountId, actual_fee: BalanceOf<T>, tip: BalanceOf<T>) {
683 Self::deposit_event(Event::TransactionFeePaid { who, actual_fee, tip });
684 }
685}
686
687impl<T> Convert<Weight, BalanceOf<T>> for Pallet<T>
688where
689 T: Config,
690{
691 fn convert(weight: Weight) -> BalanceOf<T> {
697 NextFeeMultiplier::<T>::get().saturating_mul_int(Self::weight_to_fee(weight))
698 }
699}
700
701#[derive(Encode, Decode, Clone, Eq, PartialEq, TypeInfo)]
712#[scale_info(skip_type_params(T))]
713pub struct ChargeTransactionPayment<T: Config>(#[codec(compact)] BalanceOf<T>);
714
715impl<T: Config> ChargeTransactionPayment<T>
716where
717 T::RuntimeCall: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo>,
718 BalanceOf<T>: Send + Sync,
719{
720 pub fn from(fee: BalanceOf<T>) -> Self {
722 Self(fee)
723 }
724
725 pub fn tip(&self) -> BalanceOf<T> {
727 self.0
728 }
729
730 fn withdraw_fee(
731 &self,
732 who: &T::AccountId,
733 call: &T::RuntimeCall,
734 info: &DispatchInfoOf<T::RuntimeCall>,
735 fee: BalanceOf<T>,
736 ) -> Result<
737 (
738 BalanceOf<T>,
739 <<T as Config>::OnChargeTransaction as OnChargeTransaction<T>>::LiquidityInfo,
740 ),
741 TransactionValidityError,
742 > {
743 let tip = self.0;
744
745 <<T as Config>::OnChargeTransaction as OnChargeTransaction<T>>::withdraw_fee(
746 who, call, info, fee, tip,
747 )
748 .map(|i| (fee, i))
749 }
750
751 fn can_withdraw_fee(
752 &self,
753 who: &T::AccountId,
754 call: &T::RuntimeCall,
755 info: &DispatchInfoOf<T::RuntimeCall>,
756 len: usize,
757 ) -> Result<BalanceOf<T>, TransactionValidityError> {
758 let tip = self.0;
759 let fee = Pallet::<T>::compute_fee(len as u32, info, tip);
760
761 <<T as Config>::OnChargeTransaction as OnChargeTransaction<T>>::can_withdraw_fee(
762 who, call, info, fee, tip,
763 )?;
764 Ok(fee)
765 }
766
767 pub fn get_priority(
781 info: &DispatchInfoOf<T::RuntimeCall>,
782 len: usize,
783 tip: BalanceOf<T>,
784 final_fee: BalanceOf<T>,
785 ) -> TransactionPriority {
786 let max_block_weight = T::BlockWeights::get().max_block;
789 let max_block_length = *T::BlockLength::get().max.get(info.class) as u64;
790
791 let bounded_weight =
793 info.total_weight().max(Weight::from_parts(1, 1)).min(max_block_weight);
794 let bounded_length = (len as u64).clamp(1, max_block_length);
795
796 let max_tx_per_block_weight = max_block_weight
798 .checked_div_per_component(&bounded_weight)
799 .defensive_proof("bounded_weight is non-zero; qed")
800 .unwrap_or(1);
801 let max_tx_per_block_length = max_block_length / bounded_length;
802 let max_tx_per_block = max_tx_per_block_length
807 .min(max_tx_per_block_weight)
808 .saturated_into::<BalanceOf<T>>();
809 let max_reward = |val: BalanceOf<T>| val.saturating_mul(max_tx_per_block);
810
811 let tip = tip.saturating_add(One::one());
814 let scaled_tip = max_reward(tip);
815
816 match info.class {
817 DispatchClass::Normal => {
818 scaled_tip
820 },
821 DispatchClass::Mandatory => {
822 scaled_tip
825 },
826 DispatchClass::Operational => {
827 let fee_multiplier = T::OperationalFeeMultiplier::get().saturated_into();
833 let virtual_tip = final_fee.saturating_mul(fee_multiplier);
834 let scaled_virtual_tip = max_reward(virtual_tip);
835
836 scaled_tip.saturating_add(scaled_virtual_tip)
837 },
838 }
839 .saturated_into::<TransactionPriority>()
840 }
841}
842
843impl<T: Config> core::fmt::Debug for ChargeTransactionPayment<T> {
844 #[cfg(feature = "std")]
845 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
846 write!(f, "ChargeTransactionPayment<{:?}>", self.0)
847 }
848 #[cfg(not(feature = "std"))]
849 fn fmt(&self, _: &mut core::fmt::Formatter) -> core::fmt::Result {
850 Ok(())
851 }
852}
853
854#[derive(RuntimeDebugNoBound)]
856pub enum Val<T: Config> {
857 Charge {
858 tip: BalanceOf<T>,
859 who: T::AccountId,
861 fee: BalanceOf<T>,
863 },
864 NoCharge,
865}
866
867pub enum Pre<T: Config> {
870 Charge {
871 tip: BalanceOf<T>,
872 who: T::AccountId,
874 imbalance: <<T as Config>::OnChargeTransaction as OnChargeTransaction<T>>::LiquidityInfo,
876 },
877 NoCharge {
878 refund: Weight,
880 },
881}
882
883impl<T: Config> core::fmt::Debug for Pre<T> {
884 #[cfg(feature = "std")]
885 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
886 match self {
887 Pre::Charge { tip, who, imbalance: _ } => {
888 write!(f, "Charge {{ tip: {:?}, who: {:?}, imbalance: <stripped> }}", tip, who)
889 },
890 Pre::NoCharge { refund } => write!(f, "NoCharge {{ refund: {:?} }}", refund),
891 }
892 }
893
894 #[cfg(not(feature = "std"))]
895 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
896 f.write_str("<wasm:stripped>")
897 }
898}
899
900impl<T: Config> TransactionExtension<T::RuntimeCall> for ChargeTransactionPayment<T>
901where
902 T::RuntimeCall: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo>,
903{
904 const IDENTIFIER: &'static str = "ChargeTransactionPayment";
905 type Implicit = ();
906 type Val = Val<T>;
907 type Pre = Pre<T>;
908
909 fn weight(&self, _: &T::RuntimeCall) -> Weight {
910 T::WeightInfo::charge_transaction_payment()
911 }
912
913 fn validate(
914 &self,
915 origin: <T::RuntimeCall as Dispatchable>::RuntimeOrigin,
916 call: &T::RuntimeCall,
917 info: &DispatchInfoOf<T::RuntimeCall>,
918 len: usize,
919 _: (),
920 _implication: &impl Encode,
921 _source: TransactionSource,
922 ) -> Result<
923 (ValidTransaction, Self::Val, <T::RuntimeCall as Dispatchable>::RuntimeOrigin),
924 TransactionValidityError,
925 > {
926 let Ok(who) = frame_system::ensure_signed(origin.clone()) else {
927 return Ok((ValidTransaction::default(), Val::NoCharge, origin));
928 };
929 let final_fee = self.can_withdraw_fee(&who, call, info, len)?;
930 let tip = self.0;
931 Ok((
932 ValidTransaction {
933 priority: Self::get_priority(info, len, tip, final_fee),
934 ..Default::default()
935 },
936 Val::Charge { tip: self.0, who, fee: final_fee },
937 origin,
938 ))
939 }
940
941 fn prepare(
942 self,
943 val: Self::Val,
944 _origin: &<T::RuntimeCall as Dispatchable>::RuntimeOrigin,
945 call: &T::RuntimeCall,
946 info: &DispatchInfoOf<T::RuntimeCall>,
947 _len: usize,
948 ) -> Result<Self::Pre, TransactionValidityError> {
949 match val {
950 Val::Charge { tip, who, fee } => {
951 let (_final_fee, imbalance) = self.withdraw_fee(&who, call, info, fee)?;
953 Ok(Pre::Charge { tip, who, imbalance })
954 },
955 Val::NoCharge => Ok(Pre::NoCharge { refund: self.weight(call) }),
956 }
957 }
958
959 fn post_dispatch_details(
960 pre: Self::Pre,
961 info: &DispatchInfoOf<T::RuntimeCall>,
962 post_info: &PostDispatchInfoOf<T::RuntimeCall>,
963 len: usize,
964 _result: &DispatchResult,
965 ) -> Result<Weight, TransactionValidityError> {
966 let (tip, who, imbalance) = match pre {
967 Pre::Charge { tip, who, imbalance } => (tip, who, imbalance),
968 Pre::NoCharge { refund } => {
969 return Ok(refund)
971 },
972 };
973 let actual_fee = Pallet::<T>::compute_actual_fee(len as u32, info, &post_info, tip);
974 T::OnChargeTransaction::correct_and_deposit_fee(
975 &who, info, &post_info, actual_fee, tip, imbalance,
976 )?;
977 Pallet::<T>::deposit_event(Event::<T>::TransactionFeePaid { who, actual_fee, tip });
978 Ok(Weight::zero())
979 }
980}
981
982impl<T: Config, AnyCall: GetDispatchInfo + Encode> EstimateCallFee<AnyCall, BalanceOf<T>>
983 for Pallet<T>
984where
985 T::RuntimeCall: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo>,
986{
987 fn estimate_call_fee(call: &AnyCall, post_info: PostDispatchInfo) -> BalanceOf<T> {
988 let len = call.encoded_size() as u32;
989 let info = call.get_dispatch_info();
990 Self::compute_actual_fee(len, &info, &post_info, Zero::zero())
991 }
992}