1#![cfg_attr(not(feature = "std"), no_std)]
49
50use codec::{Decode, DecodeWithMemTracking, 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 #[allow(deprecated)]
351 type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
352
353 #[pallet::no_default]
360 type OnChargeTransaction: OnChargeTransaction<Self>;
361
362 #[pallet::no_default]
364 type WeightToFee: WeightToFee<Balance = BalanceOf<Self>>;
365
366 #[pallet::no_default]
368 type LengthToFee: WeightToFee<Balance = BalanceOf<Self>>;
369
370 type FeeMultiplierUpdate: MultiplierUpdate;
372
373 #[pallet::constant]
395 type OperationalFeeMultiplier: Get<u8>;
396
397 type WeightInfo: WeightInfo;
399 }
400
401 #[pallet::type_value]
402 pub fn NextFeeMultiplierOnEmpty() -> Multiplier {
403 MULTIPLIER_DEFAULT_VALUE
404 }
405
406 #[pallet::storage]
407 #[pallet::whitelist_storage]
408 pub type NextFeeMultiplier<T: Config> =
409 StorageValue<_, Multiplier, ValueQuery, NextFeeMultiplierOnEmpty>;
410
411 #[pallet::storage]
412 pub type StorageVersion<T: Config> = StorageValue<_, Releases, ValueQuery>;
413
414 #[pallet::genesis_config]
415 pub struct GenesisConfig<T: Config> {
416 pub multiplier: Multiplier,
417 #[serde(skip)]
418 pub _config: core::marker::PhantomData<T>,
419 }
420
421 impl<T: Config> Default for GenesisConfig<T> {
422 fn default() -> Self {
423 Self { multiplier: MULTIPLIER_DEFAULT_VALUE, _config: Default::default() }
424 }
425 }
426
427 #[pallet::genesis_build]
428 impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
429 fn build(&self) {
430 StorageVersion::<T>::put(Releases::V2);
431 NextFeeMultiplier::<T>::put(self.multiplier);
432 }
433 }
434
435 #[pallet::event]
436 #[pallet::generate_deposit(pub(super) fn deposit_event)]
437 pub enum Event<T: Config> {
438 TransactionFeePaid { who: T::AccountId, actual_fee: BalanceOf<T>, tip: BalanceOf<T> },
441 }
442
443 #[pallet::hooks]
444 impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
445 fn on_finalize(_: frame_system::pallet_prelude::BlockNumberFor<T>) {
446 NextFeeMultiplier::<T>::mutate(|fm| {
447 *fm = T::FeeMultiplierUpdate::convert(*fm);
448 });
449 }
450
451 #[cfg(feature = "std")]
452 fn integrity_test() {
453 assert!(
457 <Multiplier as sp_runtime::traits::Bounded>::max_value() >=
458 Multiplier::checked_from_integer::<u128>(
459 T::BlockWeights::get().max_block.ref_time().try_into().unwrap()
460 )
461 .unwrap(),
462 );
463
464 let target = T::FeeMultiplierUpdate::target() *
465 T::BlockWeights::get().get(DispatchClass::Normal).max_total.expect(
466 "Setting `max_total` for `Normal` dispatch class is not compatible with \
467 `transaction-payment` pallet.",
468 );
469 let addition = target / 100;
471 if addition == Weight::zero() {
472 return
475 }
476
477 let min_value = T::FeeMultiplierUpdate::min();
482 let target = target + addition;
483
484 frame_system::Pallet::<T>::set_block_consumed_resources(target, 0);
485 let next = T::FeeMultiplierUpdate::convert(min_value);
486 assert!(
487 next > min_value,
488 "The minimum bound of the multiplier is too low. When \
489 block saturation is more than target by 1% and multiplier is minimal then \
490 the multiplier doesn't increase."
491 );
492 }
493 }
494}
495
496impl<T: Config> Pallet<T> {
497 pub fn next_fee_multiplier() -> Multiplier {
499 NextFeeMultiplier::<T>::get()
500 }
501
502 pub fn query_info<Extrinsic: sp_runtime::traits::ExtrinsicLike + GetDispatchInfo>(
511 unchecked_extrinsic: Extrinsic,
512 len: u32,
513 ) -> RuntimeDispatchInfo<BalanceOf<T>>
514 where
515 T::RuntimeCall: Dispatchable<Info = DispatchInfo>,
516 {
517 let dispatch_info = <Extrinsic as GetDispatchInfo>::get_dispatch_info(&unchecked_extrinsic);
523
524 let partial_fee = if unchecked_extrinsic.is_bare() {
525 0u32.into()
527 } else {
528 Self::compute_fee(len, &dispatch_info, 0u32.into())
529 };
530
531 let DispatchInfo { class, .. } = dispatch_info;
532
533 RuntimeDispatchInfo { weight: dispatch_info.total_weight(), class, partial_fee }
534 }
535
536 pub fn query_fee_details<Extrinsic: sp_runtime::traits::ExtrinsicLike + GetDispatchInfo>(
538 unchecked_extrinsic: Extrinsic,
539 len: u32,
540 ) -> FeeDetails<BalanceOf<T>>
541 where
542 T::RuntimeCall: Dispatchable<Info = DispatchInfo>,
543 {
544 let dispatch_info = <Extrinsic as GetDispatchInfo>::get_dispatch_info(&unchecked_extrinsic);
545
546 let tip = 0u32.into();
547
548 if unchecked_extrinsic.is_bare() {
549 FeeDetails { inclusion_fee: None, tip }
551 } else {
552 Self::compute_fee_details(len, &dispatch_info, tip)
553 }
554 }
555
556 pub fn query_call_info(call: T::RuntimeCall, len: u32) -> RuntimeDispatchInfo<BalanceOf<T>>
558 where
559 T::RuntimeCall: Dispatchable<Info = DispatchInfo> + GetDispatchInfo,
560 {
561 let dispatch_info = <T::RuntimeCall as GetDispatchInfo>::get_dispatch_info(&call);
562 let DispatchInfo { class, .. } = dispatch_info;
563
564 RuntimeDispatchInfo {
565 weight: dispatch_info.total_weight(),
566 class,
567 partial_fee: Self::compute_fee(len, &dispatch_info, 0u32.into()),
568 }
569 }
570
571 pub fn query_call_fee_details(call: T::RuntimeCall, len: u32) -> FeeDetails<BalanceOf<T>>
573 where
574 T::RuntimeCall: Dispatchable<Info = DispatchInfo> + GetDispatchInfo,
575 {
576 let dispatch_info = <T::RuntimeCall as GetDispatchInfo>::get_dispatch_info(&call);
577 let tip = 0u32.into();
578
579 Self::compute_fee_details(len, &dispatch_info, tip)
580 }
581
582 pub fn compute_fee(
584 len: u32,
585 info: &DispatchInfoOf<T::RuntimeCall>,
586 tip: BalanceOf<T>,
587 ) -> BalanceOf<T>
588 where
589 T::RuntimeCall: Dispatchable<Info = DispatchInfo>,
590 {
591 Self::compute_fee_details(len, info, tip).final_fee()
592 }
593
594 pub fn compute_fee_details(
596 len: u32,
597 info: &DispatchInfoOf<T::RuntimeCall>,
598 tip: BalanceOf<T>,
599 ) -> FeeDetails<BalanceOf<T>>
600 where
601 T::RuntimeCall: Dispatchable<Info = DispatchInfo>,
602 {
603 Self::compute_fee_raw(len, info.total_weight(), tip, info.pays_fee, info.class)
604 }
605
606 pub fn compute_actual_fee(
611 len: u32,
612 info: &DispatchInfoOf<T::RuntimeCall>,
613 post_info: &PostDispatchInfoOf<T::RuntimeCall>,
614 tip: BalanceOf<T>,
615 ) -> BalanceOf<T>
616 where
617 T::RuntimeCall: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo>,
618 {
619 Self::compute_actual_fee_details(len, info, post_info, tip).final_fee()
620 }
621
622 pub fn compute_actual_fee_details(
624 len: u32,
625 info: &DispatchInfoOf<T::RuntimeCall>,
626 post_info: &PostDispatchInfoOf<T::RuntimeCall>,
627 tip: BalanceOf<T>,
628 ) -> FeeDetails<BalanceOf<T>>
629 where
630 T::RuntimeCall: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo>,
631 {
632 Self::compute_fee_raw(
633 len,
634 post_info.calc_actual_weight(info),
635 tip,
636 post_info.pays_fee(info),
637 info.class,
638 )
639 }
640
641 fn compute_fee_raw(
642 len: u32,
643 weight: Weight,
644 tip: BalanceOf<T>,
645 pays_fee: Pays,
646 class: DispatchClass,
647 ) -> FeeDetails<BalanceOf<T>> {
648 if pays_fee == Pays::Yes {
649 let unadjusted_weight_fee = Self::weight_to_fee(weight);
651 let multiplier = NextFeeMultiplier::<T>::get();
652 let adjusted_weight_fee = multiplier.saturating_mul_int(unadjusted_weight_fee);
654
655 let len_fee = Self::length_to_fee(len);
657
658 let base_fee = Self::weight_to_fee(T::BlockWeights::get().get(class).base_extrinsic);
659 FeeDetails {
660 inclusion_fee: Some(InclusionFee { base_fee, len_fee, adjusted_weight_fee }),
661 tip,
662 }
663 } else {
664 FeeDetails { inclusion_fee: None, tip }
665 }
666 }
667
668 pub fn length_to_fee(length: u32) -> BalanceOf<T> {
670 T::LengthToFee::weight_to_fee(&Weight::from_parts(length as u64, 0))
671 }
672
673 pub fn weight_to_fee(weight: Weight) -> BalanceOf<T> {
676 let capped_weight = weight.min(T::BlockWeights::get().max_block);
679 T::WeightToFee::weight_to_fee(&capped_weight)
680 }
681
682 pub fn deposit_fee_paid_event(who: T::AccountId, actual_fee: BalanceOf<T>, tip: BalanceOf<T>) {
684 Self::deposit_event(Event::TransactionFeePaid { who, actual_fee, tip });
685 }
686}
687
688impl<T> Convert<Weight, BalanceOf<T>> for Pallet<T>
689where
690 T: Config,
691{
692 fn convert(weight: Weight) -> BalanceOf<T> {
698 NextFeeMultiplier::<T>::get().saturating_mul_int(Self::weight_to_fee(weight))
699 }
700}
701
702#[derive(Encode, Decode, DecodeWithMemTracking, Clone, Eq, PartialEq, TypeInfo)]
713#[scale_info(skip_type_params(T))]
714pub struct ChargeTransactionPayment<T: Config>(#[codec(compact)] BalanceOf<T>);
715
716impl<T: Config> ChargeTransactionPayment<T>
717where
718 T::RuntimeCall: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo>,
719 BalanceOf<T>: Send + Sync,
720{
721 pub fn from(fee: BalanceOf<T>) -> Self {
723 Self(fee)
724 }
725
726 pub fn tip(&self) -> BalanceOf<T> {
728 self.0
729 }
730
731 fn withdraw_fee(
732 &self,
733 who: &T::AccountId,
734 call: &T::RuntimeCall,
735 info: &DispatchInfoOf<T::RuntimeCall>,
736 fee: BalanceOf<T>,
737 ) -> Result<
738 (
739 BalanceOf<T>,
740 <<T as Config>::OnChargeTransaction as OnChargeTransaction<T>>::LiquidityInfo,
741 ),
742 TransactionValidityError,
743 > {
744 let tip = self.0;
745
746 <<T as Config>::OnChargeTransaction as OnChargeTransaction<T>>::withdraw_fee(
747 who, call, info, fee, tip,
748 )
749 .map(|i| (fee, i))
750 }
751
752 fn can_withdraw_fee(
753 &self,
754 who: &T::AccountId,
755 call: &T::RuntimeCall,
756 info: &DispatchInfoOf<T::RuntimeCall>,
757 len: usize,
758 ) -> Result<BalanceOf<T>, TransactionValidityError> {
759 let tip = self.0;
760 let fee = Pallet::<T>::compute_fee(len as u32, info, tip);
761
762 <<T as Config>::OnChargeTransaction as OnChargeTransaction<T>>::can_withdraw_fee(
763 who, call, info, fee, tip,
764 )?;
765 Ok(fee)
766 }
767
768 pub fn get_priority(
782 info: &DispatchInfoOf<T::RuntimeCall>,
783 len: usize,
784 tip: BalanceOf<T>,
785 final_fee: BalanceOf<T>,
786 ) -> TransactionPriority {
787 let max_block_weight = T::BlockWeights::get().max_block;
790 let max_block_length = *T::BlockLength::get().max.get(info.class) as u64;
791
792 let bounded_weight =
794 info.total_weight().max(Weight::from_parts(1, 1)).min(max_block_weight);
795 let bounded_length = (len as u64).clamp(1, max_block_length);
796
797 let max_tx_per_block_weight = max_block_weight
799 .checked_div_per_component(&bounded_weight)
800 .defensive_proof("bounded_weight is non-zero; qed")
801 .unwrap_or(1);
802 let max_tx_per_block_length = max_block_length / bounded_length;
803 let max_tx_per_block = max_tx_per_block_length
808 .min(max_tx_per_block_weight)
809 .saturated_into::<BalanceOf<T>>();
810 let max_reward = |val: BalanceOf<T>| val.saturating_mul(max_tx_per_block);
811
812 let tip = tip.saturating_add(One::one());
815 let scaled_tip = max_reward(tip);
816
817 match info.class {
818 DispatchClass::Normal => {
819 scaled_tip
821 },
822 DispatchClass::Mandatory => {
823 scaled_tip
826 },
827 DispatchClass::Operational => {
828 let fee_multiplier = T::OperationalFeeMultiplier::get().saturated_into();
834 let virtual_tip = final_fee.saturating_mul(fee_multiplier);
835 let scaled_virtual_tip = max_reward(virtual_tip);
836
837 scaled_tip.saturating_add(scaled_virtual_tip)
838 },
839 }
840 .saturated_into::<TransactionPriority>()
841 }
842}
843
844impl<T: Config> core::fmt::Debug for ChargeTransactionPayment<T> {
845 #[cfg(feature = "std")]
846 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
847 write!(f, "ChargeTransactionPayment<{:?}>", self.0)
848 }
849 #[cfg(not(feature = "std"))]
850 fn fmt(&self, _: &mut core::fmt::Formatter) -> core::fmt::Result {
851 Ok(())
852 }
853}
854
855#[derive(RuntimeDebugNoBound)]
857pub enum Val<T: Config> {
858 Charge {
859 tip: BalanceOf<T>,
860 who: T::AccountId,
862 fee: BalanceOf<T>,
864 },
865 NoCharge,
866}
867
868pub enum Pre<T: Config> {
871 Charge {
872 tip: BalanceOf<T>,
873 who: T::AccountId,
875 imbalance: <<T as Config>::OnChargeTransaction as OnChargeTransaction<T>>::LiquidityInfo,
877 },
878 NoCharge {
879 refund: Weight,
881 },
882}
883
884impl<T: Config> core::fmt::Debug for Pre<T> {
885 #[cfg(feature = "std")]
886 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
887 match self {
888 Pre::Charge { tip, who, imbalance: _ } => {
889 write!(f, "Charge {{ tip: {:?}, who: {:?}, imbalance: <stripped> }}", tip, who)
890 },
891 Pre::NoCharge { refund } => write!(f, "NoCharge {{ refund: {:?} }}", refund),
892 }
893 }
894
895 #[cfg(not(feature = "std"))]
896 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
897 f.write_str("<wasm:stripped>")
898 }
899}
900
901impl<T: Config> TransactionExtension<T::RuntimeCall> for ChargeTransactionPayment<T>
902where
903 T::RuntimeCall: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo>,
904{
905 const IDENTIFIER: &'static str = "ChargeTransactionPayment";
906 type Implicit = ();
907 type Val = Val<T>;
908 type Pre = Pre<T>;
909
910 fn weight(&self, _: &T::RuntimeCall) -> Weight {
911 T::WeightInfo::charge_transaction_payment()
912 }
913
914 fn validate(
915 &self,
916 origin: <T::RuntimeCall as Dispatchable>::RuntimeOrigin,
917 call: &T::RuntimeCall,
918 info: &DispatchInfoOf<T::RuntimeCall>,
919 len: usize,
920 _: (),
921 _implication: &impl Encode,
922 _source: TransactionSource,
923 ) -> Result<
924 (ValidTransaction, Self::Val, <T::RuntimeCall as Dispatchable>::RuntimeOrigin),
925 TransactionValidityError,
926 > {
927 let Ok(who) = frame_system::ensure_signed(origin.clone()) else {
928 return Ok((ValidTransaction::default(), Val::NoCharge, origin));
929 };
930 let final_fee = self.can_withdraw_fee(&who, call, info, len)?;
931 let tip = self.0;
932 Ok((
933 ValidTransaction {
934 priority: Self::get_priority(info, len, tip, final_fee),
935 ..Default::default()
936 },
937 Val::Charge { tip: self.0, who, fee: final_fee },
938 origin,
939 ))
940 }
941
942 fn prepare(
943 self,
944 val: Self::Val,
945 _origin: &<T::RuntimeCall as Dispatchable>::RuntimeOrigin,
946 call: &T::RuntimeCall,
947 info: &DispatchInfoOf<T::RuntimeCall>,
948 _len: usize,
949 ) -> Result<Self::Pre, TransactionValidityError> {
950 match val {
951 Val::Charge { tip, who, fee } => {
952 let (_final_fee, imbalance) = self.withdraw_fee(&who, call, info, fee)?;
954 Ok(Pre::Charge { tip, who, imbalance })
955 },
956 Val::NoCharge => Ok(Pre::NoCharge { refund: self.weight(call) }),
957 }
958 }
959
960 fn post_dispatch_details(
961 pre: Self::Pre,
962 info: &DispatchInfoOf<T::RuntimeCall>,
963 post_info: &PostDispatchInfoOf<T::RuntimeCall>,
964 len: usize,
965 _result: &DispatchResult,
966 ) -> Result<Weight, TransactionValidityError> {
967 let (tip, who, imbalance) = match pre {
968 Pre::Charge { tip, who, imbalance } => (tip, who, imbalance),
969 Pre::NoCharge { refund } => {
970 return Ok(refund)
972 },
973 };
974 let actual_fee = Pallet::<T>::compute_actual_fee(len as u32, info, &post_info, tip);
975 T::OnChargeTransaction::correct_and_deposit_fee(
976 &who, info, &post_info, actual_fee, tip, imbalance,
977 )?;
978 Pallet::<T>::deposit_event(Event::<T>::TransactionFeePaid { who, actual_fee, tip });
979 Ok(Weight::zero())
980 }
981}
982
983impl<T: Config, AnyCall: GetDispatchInfo + Encode> EstimateCallFee<AnyCall, BalanceOf<T>>
984 for Pallet<T>
985where
986 T::RuntimeCall: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo>,
987{
988 fn estimate_call_fee(call: &AnyCall, post_info: PostDispatchInfo) -> BalanceOf<T> {
989 let len = call.encoded_size() as u32;
990 let info = call.get_dispatch_info();
991 Self::compute_actual_fee(len, &info, &post_info, Zero::zero())
992 }
993}