pallet_transaction_payment/
lib.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! # Transaction Payment Pallet
19//!
20//! This pallet provides the basic logic needed to pay the absolute minimum amount needed for a
21//! transaction to be included. This includes:
22//!   - _base fee_: This is the minimum amount a user pays for a transaction. It is declared
23//! 	as a base _weight_ in the runtime and converted to a fee using `WeightToFee`.
24//!   - _weight fee_: A fee proportional to amount of weight a transaction consumes.
25//!   - _length fee_: A fee proportional to the encoded length of the transaction.
26//!   - _tip_: An optional tip. Tip increases the priority of the transaction, giving it a higher
27//!     chance to be included by the transaction queue.
28//!
29//! The base fee and adjusted weight and length fees constitute the _inclusion fee_, which is
30//! the minimum fee for a transaction to be included in a block.
31//!
32//! The formula of final fee:
33//!   ```ignore
34//!   inclusion_fee = base_fee + length_fee + [targeted_fee_adjustment * weight_fee];
35//!   final_fee = inclusion_fee + tip;
36//!   ```
37//!
38//!   - `targeted_fee_adjustment`: This is a multiplier that can tune the final fee based on
39//! 	the congestion of the network.
40//!
41//! Additionally, this pallet allows one to configure:
42//!   - The mapping between one unit of weight to one unit of fee via [`Config::WeightToFee`].
43//!   - A means of updating the fee for the next block, via defining a multiplier, based on the
44//!     final state of the chain at the end of the previous block. This can be configured via
45//!     [`Config::FeeMultiplierUpdate`]
46//!   - How the fees are paid via [`Config::OnChargeTransaction`].
47
48#![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
87/// Fee multiplier.
88pub type Multiplier = FixedU128;
89
90type BalanceOf<T> = <<T as Config>::OnChargeTransaction as OnChargeTransaction<T>>::Balance;
91
92/// A struct to update the weight multiplier per block. It implements `Convert<Multiplier,
93/// Multiplier>`, meaning that it can convert the previous multiplier to the next one. This should
94/// be called on `on_finalize` of a block, prior to potentially cleaning the weight data from the
95/// system pallet.
96///
97/// given:
98/// 	s = previous block weight
99/// 	s'= ideal block weight
100/// 	m = maximum block weight
101/// 		diff = (s - s')/m
102/// 		v = 0.00001
103/// 		t1 = (v * diff)
104/// 		t2 = (v * diff)^2 / 2
105/// 	then:
106/// 	next_multiplier = prev_multiplier * (1 + t1 + t2)
107///
108/// Where `(s', v)` must be given as the `Get` implementation of the `T` generic type. Moreover, `M`
109/// must provide the minimum allowed value for the multiplier. Note that a runtime should ensure
110/// with tests that the combination of this `M` and `V` is not such that the multiplier can drop to
111/// zero and never recover.
112///
113/// Note that `s'` is interpreted as a portion in the _normal transaction_ capacity of the block.
114/// For example, given `s' == 0.25` and `AvailableBlockRatio = 0.75`, then the target fullness is
115/// _0.25 of the normal capacity_ and _0.1875 of the entire block_.
116///
117/// Since block weight is multi-dimension, we use the scarcer resource, referred as limiting
118/// dimension, for calculation of fees. We determine the limiting dimension by comparing the
119/// dimensions using the ratio of `dimension_value / max_dimension_value` and selecting the largest
120/// ratio. For instance, if a block is 30% full based on `ref_time` and 25% full based on
121/// `proof_size`, we identify `ref_time` as the limiting dimension, indicating that the block is 30%
122/// full.
123///
124/// This implementation implies the bound:
125/// - `v ≤ p / k * (s − s')`
126/// - or, solving for `p`: `p >= v * k * (s - s')`
127///
128/// where `p` is the amount of change over `k` blocks.
129///
130/// Hence:
131/// - in a fully congested chain: `p >= v * k * (1 - s')`.
132/// - in an empty chain: `p >= v * k * (-s')`.
133///
134/// For example, when all blocks are full and there are 28800 blocks per day (default in
135/// `substrate-node`) and v == 0.00001, s' == 0.1875, we'd have:
136///
137/// p >= 0.00001 * 28800 * 0.8125
138/// p >= 0.234
139///
140/// Meaning that fees can change by around ~23% per day, given extreme congestion.
141///
142/// More info can be found at:
143/// <https://research.web3.foundation/en/latest/polkadot/overview/2-token-economics.html>
144pub struct TargetedFeeAdjustment<T, S, V, M, X>(core::marker::PhantomData<(T, S, V, M, X)>);
145
146/// Something that can convert the current multiplier to the next one.
147pub trait MultiplierUpdate: Convert<Multiplier, Multiplier> {
148	/// Minimum multiplier. Any outcome of the `convert` function should be at least this.
149	fn min() -> Multiplier;
150	/// Maximum multiplier. Any outcome of the `convert` function should be less or equal this.
151	fn max() -> Multiplier;
152	/// Target block saturation level
153	fn target() -> Perquintill;
154	/// Variability factor
155	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		// Defensive only. The multiplier in storage should always be at most positive. Nonetheless
205		// we recover here in case of errors, because any value below this would be stale and can
206		// never change.
207		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		// the computed ratio is only among the normal class.
213		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		// Normalize dimensions so they can be compared. Ensure (defensive) max weight is non-zero.
220		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		// Pick the limiting dimension. If the proof size is the limiting dimension, then the
230		// multiplier is adjusted by the proof size. Otherwise, it is adjusted by the ref time.
231		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		// determines if the first_term is positive
245		let positive = block_weight >= target_weight;
246		let diff_abs = block_weight.max(target_weight) - block_weight.min(target_weight);
247
248		// defensive only, a test case assures that the maximum weight diff can fit in Multiplier
249		// without any saturation.
250		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			// Defensive-only: first_term > second_term. Safe subtraction.
264			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
270/// A struct to make the fee multiplier a constant
271pub 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/// Storage releases of the pallet.
298#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)]
299pub enum Releases {
300	/// Original version of the pallet.
301	V1Ancient,
302	/// One that bumps the usage to FixedU128 from FixedI128.
303	V2,
304}
305
306impl Default for Releases {
307	fn default() -> Self {
308		Releases::V1Ancient
309	}
310}
311
312/// Default value for NextFeeMultiplier. This is used in genesis and is also used in
313/// NextFeeMultiplierOnEmpty() to provide a value when none exists in storage.
314const 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		/// Default prelude sensible to be used in a testing environment.
331		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		/// The overarching event type.
349		#[pallet::no_default_bounds]
350		type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
351
352		/// Handler for withdrawing, refunding and depositing the transaction fee.
353		/// Transaction fees are withdrawn before the transaction is executed.
354		/// After the transaction was executed the transaction weight can be
355		/// adjusted, depending on the used resources by the transaction. If the
356		/// transaction weight is lower than expected, parts of the transaction fee
357		/// might be refunded. In the end the fees can be deposited.
358		#[pallet::no_default]
359		type OnChargeTransaction: OnChargeTransaction<Self>;
360
361		/// Convert a weight value into a deductible fee based on the currency type.
362		#[pallet::no_default]
363		type WeightToFee: WeightToFee<Balance = BalanceOf<Self>>;
364
365		/// Convert a length value into a deductible fee based on the currency type.
366		#[pallet::no_default]
367		type LengthToFee: WeightToFee<Balance = BalanceOf<Self>>;
368
369		/// Update the multiplier of the next block, based on the previous block's weight.
370		type FeeMultiplierUpdate: MultiplierUpdate;
371
372		/// A fee multiplier for `Operational` extrinsics to compute "virtual tip" to boost their
373		/// `priority`
374		///
375		/// This value is multiplied by the `final_fee` to obtain a "virtual tip" that is later
376		/// added to a tip component in regular `priority` calculations.
377		/// It means that a `Normal` transaction can front-run a similarly-sized `Operational`
378		/// extrinsic (with no tip), by including a tip value greater than the virtual tip.
379		///
380		/// ```rust,ignore
381		/// // For `Normal`
382		/// let priority = priority_calc(tip);
383		///
384		/// // For `Operational`
385		/// let virtual_tip = (inclusion_fee + tip) * OperationalFeeMultiplier;
386		/// let priority = priority_calc(tip + virtual_tip);
387		/// ```
388		///
389		/// Note that since we use `final_fee` the multiplier applies also to the regular `tip`
390		/// sent with the transaction. So, not only does the transaction get a priority bump based
391		/// on the `inclusion_fee`, but we also amplify the impact of tips applied to `Operational`
392		/// transactions.
393		#[pallet::constant]
394		type OperationalFeeMultiplier: Get<u8>;
395
396		/// The weight information of this pallet.
397		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		/// A transaction fee `actual_fee`, of which `tip` was added to the minimum inclusion fee,
438		/// has been paid by `who`.
439		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			// given weight == u64, we build multipliers from `diff` of two weight values, which can
453			// at most be maximum block weight. Make sure that this can fit in a multiplier without
454			// loss.
455			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			// add 1 percent;
469			let addition = target / 100;
470			if addition == Weight::zero() {
471				// this is most likely because in a test setup we set everything to ()
472				// or to `ConstFeeMultiplier`.
473				return
474			}
475
476			// This is the minimum value of the multiplier. Make sure that if we collapse to this
477			// value, we can recover with a reasonable amount of traffic. For this test we assert
478			// that if we collapse to minimum, the trend will be positive with a weight value which
479			// is 1% more than the target.
480			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	/// Public function to access the next fee multiplier.
497	pub fn next_fee_multiplier() -> Multiplier {
498		NextFeeMultiplier::<T>::get()
499	}
500
501	/// Query the data that we know about the fee of a given `call`.
502	///
503	/// This pallet is not and cannot be aware of the internals of a signed extension, for example
504	/// a tip. It only interprets the extrinsic as some encoded value and accounts for its weight
505	/// and length, the runtime's extrinsic base weight, and the current fee multiplier.
506	///
507	/// All dispatchables must be annotated with weight and will have some fee info. This function
508	/// always returns.
509	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		// NOTE: we can actually make it understand `ChargeTransactionPayment`, but would be some
517		// hassle for sure. We have to make it aware of the index of `ChargeTransactionPayment` in
518		// `Extra`. Alternatively, we could actually execute the tx's per-dispatch and record the
519		// balance of the sender before and after the pipeline.. but this is way too much hassle for
520		// a very very little potential gain in the future.
521		let dispatch_info = <Extrinsic as GetDispatchInfo>::get_dispatch_info(&unchecked_extrinsic);
522
523		let partial_fee = if unchecked_extrinsic.is_bare() {
524			// Bare extrinsics have no partial fee.
525			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	/// Query the detailed fee of a given `call`.
536	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			// Bare extrinsics have no inclusion fee.
549			FeeDetails { inclusion_fee: None, tip }
550		} else {
551			Self::compute_fee_details(len, &dispatch_info, tip)
552		}
553	}
554
555	/// Query information of a dispatch class, weight, and fee of a given encoded `Call`.
556	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	/// Query fee details of a given encoded `Call`.
571	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	/// Compute the final fee value for a particular transaction.
582	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	/// Compute the fee details for a particular transaction.
594	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	/// Compute the actual post dispatch fee for a particular transaction.
606	///
607	/// Identical to `compute_fee` with the only difference that the post dispatch corrected
608	/// weight is used for the weight fee calculation.
609	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	/// Compute the actual post dispatch fee details for a particular transaction.
622	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			// the adjustable part of the fee.
649			let unadjusted_weight_fee = Self::weight_to_fee(weight);
650			let multiplier = NextFeeMultiplier::<T>::get();
651			// final adjusted weight fee.
652			let adjusted_weight_fee = multiplier.saturating_mul_int(unadjusted_weight_fee);
653
654			// length fee. this is adjusted via `LengthToFee`.
655			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	/// Compute the length portion of a fee by invoking the configured `LengthToFee` impl.
668	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	/// Compute the unadjusted portion of the weight fee by invoking the configured `WeightToFee`
673	/// impl. Note that the input `weight` is capped by the maximum block weight before computation.
674	pub fn weight_to_fee(weight: Weight) -> BalanceOf<T> {
675		// cap the weight to the maximum defined in runtime, otherwise it will be the
676		// `Bounded` maximum of its data type, which is not desired.
677		let capped_weight = weight.min(T::BlockWeights::get().max_block);
678		T::WeightToFee::weight_to_fee(&capped_weight)
679	}
680
681	/// Deposit the [`Event::TransactionFeePaid`] event.
682	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	/// Compute the fee for the specified weight.
692	///
693	/// This fee is already adjusted by the per block fee adjustment factor and is therefore the
694	/// share that the weight contributes to the overall fee of a transaction. It is mainly
695	/// for informational purposes and not used in the actual fee calculation.
696	fn convert(weight: Weight) -> BalanceOf<T> {
697		NextFeeMultiplier::<T>::get().saturating_mul_int(Self::weight_to_fee(weight))
698	}
699}
700
701/// Require the transactor pay for themselves and maybe include a tip to gain additional priority
702/// in the queue.
703///
704/// # Transaction Validity
705///
706/// This extension sets the `priority` field of `TransactionValidity` depending on the amount
707/// of tip being paid per weight unit.
708///
709/// Operational transactions will receive an additional priority bump, so that they are normally
710/// considered before regular transactions.
711#[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	/// utility constructor. Used only in client/factory code.
721	pub fn from(fee: BalanceOf<T>) -> Self {
722		Self(fee)
723	}
724
725	/// Returns the tip as being chosen by the transaction sender.
726	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	/// Get an appropriate priority for a transaction with the given `DispatchInfo`, encoded length
768	/// and user-included tip.
769	///
770	/// The priority is based on the amount of `tip` the user is willing to pay per unit of either
771	/// `weight` or `length`, depending which one is more limiting. For `Operational` extrinsics
772	/// we add a "virtual tip" to the calculations.
773	///
774	/// The formula should simply be `tip / bounded_{weight|length}`, but since we are using
775	/// integer division, we have no guarantees it's going to give results in any reasonable
776	/// range (might simply end up being zero). Hence we use a scaling factor:
777	/// `tip * (max_block_{weight|length} / bounded_{weight|length})`, since given current
778	/// state of-the-art blockchains, number of per-block transactions is expected to be in a
779	/// range reasonable enough to not saturate the `Balance` type while multiplying by the tip.
780	pub fn get_priority(
781		info: &DispatchInfoOf<T::RuntimeCall>,
782		len: usize,
783		tip: BalanceOf<T>,
784		final_fee: BalanceOf<T>,
785	) -> TransactionPriority {
786		// Calculate how many such extrinsics we could fit into an empty block and take the
787		// limiting factor.
788		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		// bounded_weight is used as a divisor later so we keep it non-zero.
792		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		// returns the scarce resource, i.e. the one that is limiting the number of transactions.
797		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		// Given our current knowledge this value is going to be in a reasonable range - i.e.
803		// less than 10^9 (2^30), so multiplying by the `tip` value is unlikely to overflow the
804		// balance type. We still use saturating ops obviously, but the point is to end up with some
805		// `priority` distribution instead of having all transactions saturate the priority.
806		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		// To distribute no-tip transactions a little bit, we increase the tip value by one.
812		// This means that given two transactions without a tip, smaller one will be preferred.
813		let tip = tip.saturating_add(One::one());
814		let scaled_tip = max_reward(tip);
815
816		match info.class {
817			DispatchClass::Normal => {
818				// For normal class we simply take the `tip_per_weight`.
819				scaled_tip
820			},
821			DispatchClass::Mandatory => {
822				// Mandatory extrinsics should be prohibited (e.g. by the [`CheckWeight`]
823				// extensions), but just to be safe let's return the same priority as `Normal` here.
824				scaled_tip
825			},
826			DispatchClass::Operational => {
827				// A "virtual tip" value added to an `Operational` extrinsic.
828				// This value should be kept high enough to allow `Operational` extrinsics
829				// to get in even during congestion period, but at the same time low
830				// enough to prevent a possible spam attack by sending invalid operational
831				// extrinsics which push away regular transactions from the pool.
832				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/// The info passed between the validate and prepare steps for the `ChargeAssetTxPayment` extension.
855#[derive(RuntimeDebugNoBound)]
856pub enum Val<T: Config> {
857	Charge {
858		tip: BalanceOf<T>,
859		// who paid the fee
860		who: T::AccountId,
861		// transaction fee
862		fee: BalanceOf<T>,
863	},
864	NoCharge,
865}
866
867/// The info passed between the prepare and post-dispatch steps for the `ChargeAssetTxPayment`
868/// extension.
869pub enum Pre<T: Config> {
870	Charge {
871		tip: BalanceOf<T>,
872		// who paid the fee
873		who: T::AccountId,
874		// imbalance resulting from withdrawing the fee
875		imbalance: <<T as Config>::OnChargeTransaction as OnChargeTransaction<T>>::LiquidityInfo,
876	},
877	NoCharge {
878		// weight initially estimated by the extension, to be refunded
879		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				// Mutating call to `withdraw_fee` to actually charge for the transaction.
952				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				// No-op: Refund everything
970				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}