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, 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, Imbalance, SuppressedDrop},
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;
91type CreditOf<T> = <StoredCreditOf<T> as SuppressedDrop>::Inner;
92type StoredCreditOf<T> = <<T as Config>::OnChargeTransaction as TxCreditHold<T>>::Credit;
93
94const LOG_TARGET: &str = "runtime::txpayment";
95
96/// A struct to update the weight multiplier per block. It implements `Convert<Multiplier,
97/// Multiplier>`, meaning that it can convert the previous multiplier to the next one. This should
98/// be called on `on_finalize` of a block, prior to potentially cleaning the weight data from the
99/// system pallet.
100///
101/// given:
102/// 	s = previous block weight
103/// 	s'= ideal block weight
104/// 	m = maximum block weight
105/// 		diff = (s - s')/m
106/// 		v = 0.00001
107/// 		t1 = (v * diff)
108/// 		t2 = (v * diff)^2 / 2
109/// 	then:
110/// 	next_multiplier = prev_multiplier * (1 + t1 + t2)
111///
112/// Where `(s', v)` must be given as the `Get` implementation of the `T` generic type. Moreover, `M`
113/// must provide the minimum allowed value for the multiplier. Note that a runtime should ensure
114/// with tests that the combination of this `M` and `V` is not such that the multiplier can drop to
115/// zero and never recover.
116///
117/// Note that `s'` is interpreted as a portion in the _normal transaction_ capacity of the block.
118/// For example, given `s' == 0.25` and `AvailableBlockRatio = 0.75`, then the target fullness is
119/// _0.25 of the normal capacity_ and _0.1875 of the entire block_.
120///
121/// Since block weight is multi-dimension, we use the scarcer resource, referred as limiting
122/// dimension, for calculation of fees. We determine the limiting dimension by comparing the
123/// dimensions using the ratio of `dimension_value / max_dimension_value` and selecting the largest
124/// ratio. For instance, if a block is 30% full based on `ref_time` and 25% full based on
125/// `proof_size`, we identify `ref_time` as the limiting dimension, indicating that the block is 30%
126/// full.
127///
128/// This implementation implies the bound:
129/// - `v ≤ p / k * (s − s')`
130/// - or, solving for `p`: `p >= v * k * (s - s')`
131///
132/// where `p` is the amount of change over `k` blocks.
133///
134/// Hence:
135/// - in a fully congested chain: `p >= v * k * (1 - s')`.
136/// - in an empty chain: `p >= v * k * (-s')`.
137///
138/// For example, when all blocks are full and there are 28800 blocks per day (default in
139/// `substrate-node`) and v == 0.00001, s' == 0.1875, we'd have:
140///
141/// p >= 0.00001 * 28800 * 0.8125
142/// p >= 0.234
143///
144/// Meaning that fees can change by around ~23% per day, given extreme congestion.
145///
146/// More info can be found at:
147/// <https://research.web3.foundation/Polkadot/overview/token-economics>
148pub struct TargetedFeeAdjustment<T, S, V, M, X>(core::marker::PhantomData<(T, S, V, M, X)>);
149
150/// Something that can convert the current multiplier to the next one.
151pub trait MultiplierUpdate: Convert<Multiplier, Multiplier> {
152	/// Minimum multiplier. Any outcome of the `convert` function should be at least this.
153	fn min() -> Multiplier;
154	/// Maximum multiplier. Any outcome of the `convert` function should be less or equal this.
155	fn max() -> Multiplier;
156	/// Target block saturation level
157	fn target() -> Perquintill;
158	/// Variability factor
159	fn variability() -> Multiplier;
160}
161
162impl MultiplierUpdate for () {
163	fn min() -> Multiplier {
164		Default::default()
165	}
166	fn max() -> Multiplier {
167		<Multiplier as sp_runtime::traits::Bounded>::max_value()
168	}
169	fn target() -> Perquintill {
170		Default::default()
171	}
172	fn variability() -> Multiplier {
173		Default::default()
174	}
175}
176
177impl<T, S, V, M, X> MultiplierUpdate for TargetedFeeAdjustment<T, S, V, M, X>
178where
179	T: frame_system::Config,
180	S: Get<Perquintill>,
181	V: Get<Multiplier>,
182	M: Get<Multiplier>,
183	X: Get<Multiplier>,
184{
185	fn min() -> Multiplier {
186		M::get()
187	}
188	fn max() -> Multiplier {
189		X::get()
190	}
191	fn target() -> Perquintill {
192		S::get()
193	}
194	fn variability() -> Multiplier {
195		V::get()
196	}
197}
198
199impl<T, S, V, M, X> Convert<Multiplier, Multiplier> for TargetedFeeAdjustment<T, S, V, M, X>
200where
201	T: frame_system::Config,
202	S: Get<Perquintill>,
203	V: Get<Multiplier>,
204	M: Get<Multiplier>,
205	X: Get<Multiplier>,
206{
207	fn convert(previous: Multiplier) -> Multiplier {
208		// Defensive only. The multiplier in storage should always be at most positive. Nonetheless
209		// we recover here in case of errors, because any value below this would be stale and can
210		// never change.
211		let min_multiplier = M::get();
212		let max_multiplier = X::get();
213		let previous = previous.max(min_multiplier);
214
215		let weights = T::BlockWeights::get();
216		// the computed ratio is only among the normal class.
217		let normal_max_weight =
218			weights.get(DispatchClass::Normal).max_total.unwrap_or(weights.max_block);
219		let current_block_weight = frame_system::Pallet::<T>::block_weight();
220		let normal_block_weight =
221			current_block_weight.get(DispatchClass::Normal).min(normal_max_weight);
222
223		// Normalize dimensions so they can be compared. Ensure (defensive) max weight is non-zero.
224		let normalized_ref_time = Perbill::from_rational(
225			normal_block_weight.ref_time(),
226			normal_max_weight.ref_time().max(1),
227		);
228		let normalized_proof_size = Perbill::from_rational(
229			normal_block_weight.proof_size(),
230			normal_max_weight.proof_size().max(1),
231		);
232
233		// Pick the limiting dimension. If the proof size is the limiting dimension, then the
234		// multiplier is adjusted by the proof size. Otherwise, it is adjusted by the ref time.
235		let (normal_limiting_dimension, max_limiting_dimension) =
236			if normalized_ref_time < normalized_proof_size {
237				(normal_block_weight.proof_size(), normal_max_weight.proof_size())
238			} else {
239				(normal_block_weight.ref_time(), normal_max_weight.ref_time())
240			};
241
242		let target_block_fullness = S::get();
243		let adjustment_variable = V::get();
244
245		let target_weight = (target_block_fullness * max_limiting_dimension) as u128;
246		let block_weight = normal_limiting_dimension as u128;
247
248		// determines if the first_term is positive
249		let positive = block_weight >= target_weight;
250		let diff_abs = block_weight.max(target_weight) - block_weight.min(target_weight);
251
252		// defensive only, a test case assures that the maximum weight diff can fit in Multiplier
253		// without any saturation.
254		let diff = Multiplier::saturating_from_rational(diff_abs, max_limiting_dimension.max(1));
255		let diff_squared = diff.saturating_mul(diff);
256
257		let v_squared_2 = adjustment_variable.saturating_mul(adjustment_variable) /
258			Multiplier::saturating_from_integer(2);
259
260		let first_term = adjustment_variable.saturating_mul(diff);
261		let second_term = v_squared_2.saturating_mul(diff_squared);
262
263		if positive {
264			let excess = first_term.saturating_add(second_term).saturating_mul(previous);
265			previous.saturating_add(excess).clamp(min_multiplier, max_multiplier)
266		} else {
267			// Defensive-only: first_term > second_term. Safe subtraction.
268			let negative = first_term.saturating_sub(second_term).saturating_mul(previous);
269			previous.saturating_sub(negative).clamp(min_multiplier, max_multiplier)
270		}
271	}
272}
273
274/// A struct to make the fee multiplier a constant
275pub struct ConstFeeMultiplier<M: Get<Multiplier>>(core::marker::PhantomData<M>);
276
277impl<M: Get<Multiplier>> MultiplierUpdate for ConstFeeMultiplier<M> {
278	fn min() -> Multiplier {
279		M::get()
280	}
281	fn max() -> Multiplier {
282		M::get()
283	}
284	fn target() -> Perquintill {
285		Default::default()
286	}
287	fn variability() -> Multiplier {
288		Default::default()
289	}
290}
291
292impl<M> Convert<Multiplier, Multiplier> for ConstFeeMultiplier<M>
293where
294	M: Get<Multiplier>,
295{
296	fn convert(_previous: Multiplier) -> Multiplier {
297		Self::min()
298	}
299}
300
301/// Storage releases of the pallet.
302#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)]
303pub enum Releases {
304	/// Original version of the pallet.
305	V1Ancient,
306	/// One that bumps the usage to FixedU128 from FixedI128.
307	V2,
308}
309
310impl Default for Releases {
311	fn default() -> Self {
312		Releases::V1Ancient
313	}
314}
315
316/// Default value for NextFeeMultiplier. This is used in genesis and is also used in
317/// NextFeeMultiplierOnEmpty() to provide a value when none exists in storage.
318const MULTIPLIER_DEFAULT_VALUE: Multiplier = Multiplier::from_u32(1);
319
320#[frame_support::pallet]
321pub mod pallet {
322	use frame_support::pallet_prelude::*;
323	use frame_system::pallet_prelude::*;
324
325	use super::*;
326
327	#[pallet::pallet]
328	pub struct Pallet<T>(_);
329
330	pub mod config_preludes {
331		use super::*;
332		use frame_support::derive_impl;
333
334		/// Default prelude sensible to be used in a testing environment.
335		pub struct TestDefaultConfig;
336
337		#[derive_impl(frame_system::config_preludes::TestDefaultConfig, no_aggregated_types)]
338		impl frame_system::DefaultConfig for TestDefaultConfig {}
339
340		#[frame_support::register_default_impl(TestDefaultConfig)]
341		impl DefaultConfig for TestDefaultConfig {
342			#[inject_runtime_type]
343			type RuntimeEvent = ();
344			type FeeMultiplierUpdate = ();
345			type OperationalFeeMultiplier = ();
346			type WeightInfo = ();
347		}
348	}
349
350	#[pallet::config(with_default)]
351	pub trait Config: frame_system::Config {
352		/// The overarching event type.
353		#[pallet::no_default_bounds]
354		#[allow(deprecated)]
355		type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
356
357		/// Handler for withdrawing, refunding and depositing the transaction fee.
358		/// Transaction fees are withdrawn before the transaction is executed.
359		/// After the transaction was executed the transaction weight can be
360		/// adjusted, depending on the used resources by the transaction. If the
361		/// transaction weight is lower than expected, parts of the transaction fee
362		/// might be refunded. In the end the fees can be deposited.
363		#[pallet::no_default]
364		type OnChargeTransaction: OnChargeTransaction<Self>;
365
366		/// Convert a weight value into a deductible fee based on the currency type.
367		#[pallet::no_default]
368		type WeightToFee: WeightToFee<Balance = BalanceOf<Self>>;
369
370		/// Convert a length value into a deductible fee based on the currency type.
371		#[pallet::no_default]
372		type LengthToFee: WeightToFee<Balance = BalanceOf<Self>>;
373
374		/// Update the multiplier of the next block, based on the previous block's weight.
375		type FeeMultiplierUpdate: MultiplierUpdate;
376
377		/// A fee multiplier for `Operational` extrinsics to compute "virtual tip" to boost their
378		/// `priority`
379		///
380		/// This value is multiplied by the `final_fee` to obtain a "virtual tip" that is later
381		/// added to a tip component in regular `priority` calculations.
382		/// It means that a `Normal` transaction can front-run a similarly-sized `Operational`
383		/// extrinsic (with no tip), by including a tip value greater than the virtual tip.
384		///
385		/// ```rust,ignore
386		/// // For `Normal`
387		/// let priority = priority_calc(tip);
388		///
389		/// // For `Operational`
390		/// let virtual_tip = (inclusion_fee + tip) * OperationalFeeMultiplier;
391		/// let priority = priority_calc(tip + virtual_tip);
392		/// ```
393		///
394		/// Note that since we use `final_fee` the multiplier applies also to the regular `tip`
395		/// sent with the transaction. So, not only does the transaction get a priority bump based
396		/// on the `inclusion_fee`, but we also amplify the impact of tips applied to `Operational`
397		/// transactions.
398		#[pallet::constant]
399		type OperationalFeeMultiplier: Get<u8>;
400
401		/// The weight information of this pallet.
402		type WeightInfo: WeightInfo;
403	}
404
405	#[pallet::type_value]
406	pub fn NextFeeMultiplierOnEmpty() -> Multiplier {
407		MULTIPLIER_DEFAULT_VALUE
408	}
409
410	#[pallet::storage]
411	#[pallet::whitelist_storage]
412	pub type NextFeeMultiplier<T: Config> =
413		StorageValue<_, Multiplier, ValueQuery, NextFeeMultiplierOnEmpty>;
414
415	#[pallet::storage]
416	pub type StorageVersion<T: Config> = StorageValue<_, Releases, ValueQuery>;
417
418	/// The `OnChargeTransaction` stores the withdrawn tx fee here.
419	///
420	/// Use `withdraw_txfee` and `remaining_txfee` to access from outside the crate.
421	#[pallet::storage]
422	#[pallet::whitelist_storage]
423	pub(crate) type TxPaymentCredit<T: Config> = StorageValue<_, StoredCreditOf<T>>;
424
425	#[pallet::genesis_config]
426	pub struct GenesisConfig<T: Config> {
427		pub multiplier: Multiplier,
428		#[serde(skip)]
429		pub _config: core::marker::PhantomData<T>,
430	}
431
432	impl<T: Config> Default for GenesisConfig<T> {
433		fn default() -> Self {
434			Self { multiplier: MULTIPLIER_DEFAULT_VALUE, _config: Default::default() }
435		}
436	}
437
438	#[pallet::genesis_build]
439	impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
440		fn build(&self) {
441			StorageVersion::<T>::put(Releases::V2);
442			NextFeeMultiplier::<T>::put(self.multiplier);
443		}
444	}
445
446	#[pallet::event]
447	#[pallet::generate_deposit(pub(super) fn deposit_event)]
448	pub enum Event<T: Config> {
449		/// A transaction fee `actual_fee`, of which `tip` was added to the minimum inclusion fee,
450		/// has been paid by `who`.
451		TransactionFeePaid { who: T::AccountId, actual_fee: BalanceOf<T>, tip: BalanceOf<T> },
452	}
453
454	#[pallet::hooks]
455	impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
456		fn on_finalize(_: frame_system::pallet_prelude::BlockNumberFor<T>) {
457			NextFeeMultiplier::<T>::mutate(|fm| {
458				*fm = T::FeeMultiplierUpdate::convert(*fm);
459			});
460
461			// We generally expect the `OnChargeTransaction` implementation to delete this value
462			// after each transaction. To make sure it is never stored between blocks we
463			// delete the value here just in case.
464			TxPaymentCredit::<T>::take().map(|credit| {
465				log::error!(target: LOG_TARGET, "The `TxPaymentCredit` was stored between blocks. This is a bug.");
466				// Converting to inner makes sure that the drop implementation is called.
467				credit.into_inner()
468			});
469		}
470
471		#[cfg(feature = "std")]
472		fn integrity_test() {
473			// given weight == u64, we build multipliers from `diff` of two weight values, which can
474			// at most be maximum block weight. Make sure that this can fit in a multiplier without
475			// loss.
476			assert!(
477				<Multiplier as sp_runtime::traits::Bounded>::max_value() >=
478					Multiplier::checked_from_integer::<u128>(
479						T::BlockWeights::get().max_block.ref_time().try_into().unwrap()
480					)
481					.unwrap(),
482			);
483
484			let target = T::FeeMultiplierUpdate::target() *
485				T::BlockWeights::get().get(DispatchClass::Normal).max_total.expect(
486					"Setting `max_total` for `Normal` dispatch class is not compatible with \
487					`transaction-payment` pallet.",
488				);
489			// add 1 percent;
490			let addition = target / 100;
491			if addition == Weight::zero() {
492				// this is most likely because in a test setup we set everything to ()
493				// or to `ConstFeeMultiplier`.
494				return
495			}
496
497			// This is the minimum value of the multiplier. Make sure that if we collapse to this
498			// value, we can recover with a reasonable amount of traffic. For this test we assert
499			// that if we collapse to minimum, the trend will be positive with a weight value which
500			// is 1% more than the target.
501			let min_value = T::FeeMultiplierUpdate::min();
502			let target = target + addition;
503
504			frame_system::Pallet::<T>::set_block_consumed_resources(target, 0);
505			let next = T::FeeMultiplierUpdate::convert(min_value);
506			assert!(
507				next > min_value,
508				"The minimum bound of the multiplier is too low. When \
509				block saturation is more than target by 1% and multiplier is minimal then \
510				the multiplier doesn't increase."
511			);
512		}
513	}
514}
515
516impl<T: Config> Pallet<T> {
517	/// Public function to access the next fee multiplier.
518	pub fn next_fee_multiplier() -> Multiplier {
519		NextFeeMultiplier::<T>::get()
520	}
521
522	/// Query the data that we know about the fee of a given `call`.
523	///
524	/// This pallet is not and cannot be aware of the internals of a signed extension, for example
525	/// a tip. It only interprets the extrinsic as some encoded value and accounts for its weight
526	/// and length, the runtime's extrinsic base weight, and the current fee multiplier.
527	///
528	/// All dispatchables must be annotated with weight and will have some fee info. This function
529	/// always returns.
530	pub fn query_info<Extrinsic: sp_runtime::traits::ExtrinsicLike + GetDispatchInfo>(
531		unchecked_extrinsic: Extrinsic,
532		len: u32,
533	) -> RuntimeDispatchInfo<BalanceOf<T>>
534	where
535		T::RuntimeCall: Dispatchable<Info = DispatchInfo>,
536	{
537		// NOTE: we can actually make it understand `ChargeTransactionPayment`, but would be some
538		// hassle for sure. We have to make it aware of the index of `ChargeTransactionPayment` in
539		// `Extra`. Alternatively, we could actually execute the tx's per-dispatch and record the
540		// balance of the sender before and after the pipeline.. but this is way too much hassle for
541		// a very very little potential gain in the future.
542		let dispatch_info = <Extrinsic as GetDispatchInfo>::get_dispatch_info(&unchecked_extrinsic);
543
544		let partial_fee = if unchecked_extrinsic.is_bare() {
545			// Bare extrinsics have no partial fee.
546			0u32.into()
547		} else {
548			Self::compute_fee(len, &dispatch_info, 0u32.into())
549		};
550
551		let DispatchInfo { class, .. } = dispatch_info;
552
553		RuntimeDispatchInfo { weight: dispatch_info.total_weight(), class, partial_fee }
554	}
555
556	/// Query the detailed fee of a given `call`.
557	pub fn query_fee_details<Extrinsic: sp_runtime::traits::ExtrinsicLike + GetDispatchInfo>(
558		unchecked_extrinsic: Extrinsic,
559		len: u32,
560	) -> FeeDetails<BalanceOf<T>>
561	where
562		T::RuntimeCall: Dispatchable<Info = DispatchInfo>,
563	{
564		let dispatch_info = <Extrinsic as GetDispatchInfo>::get_dispatch_info(&unchecked_extrinsic);
565
566		let tip = 0u32.into();
567
568		if unchecked_extrinsic.is_bare() {
569			// Bare extrinsics have no inclusion fee.
570			FeeDetails { inclusion_fee: None, tip }
571		} else {
572			Self::compute_fee_details(len, &dispatch_info, tip)
573		}
574	}
575
576	/// Query information of a dispatch class, weight, and fee of a given encoded `Call`.
577	pub fn query_call_info(call: T::RuntimeCall, len: u32) -> RuntimeDispatchInfo<BalanceOf<T>>
578	where
579		T::RuntimeCall: Dispatchable<Info = DispatchInfo> + GetDispatchInfo,
580	{
581		let dispatch_info = <T::RuntimeCall as GetDispatchInfo>::get_dispatch_info(&call);
582		let DispatchInfo { class, .. } = dispatch_info;
583
584		RuntimeDispatchInfo {
585			weight: dispatch_info.total_weight(),
586			class,
587			partial_fee: Self::compute_fee(len, &dispatch_info, 0u32.into()),
588		}
589	}
590
591	/// Query fee details of a given encoded `Call`.
592	pub fn query_call_fee_details(call: T::RuntimeCall, len: u32) -> FeeDetails<BalanceOf<T>>
593	where
594		T::RuntimeCall: Dispatchable<Info = DispatchInfo> + GetDispatchInfo,
595	{
596		let dispatch_info = <T::RuntimeCall as GetDispatchInfo>::get_dispatch_info(&call);
597		let tip = 0u32.into();
598
599		Self::compute_fee_details(len, &dispatch_info, tip)
600	}
601
602	/// Compute the final fee value (including tip) for a particular transaction.
603	pub fn compute_fee(
604		len: u32,
605		info: &DispatchInfoOf<T::RuntimeCall>,
606		tip: BalanceOf<T>,
607	) -> BalanceOf<T>
608	where
609		T::RuntimeCall: Dispatchable<Info = DispatchInfo>,
610	{
611		Self::compute_fee_details(len, info, tip).final_fee()
612	}
613
614	/// Compute the fee details for a particular transaction.
615	pub fn compute_fee_details(
616		len: u32,
617		info: &DispatchInfoOf<T::RuntimeCall>,
618		tip: BalanceOf<T>,
619	) -> FeeDetails<BalanceOf<T>>
620	where
621		T::RuntimeCall: Dispatchable<Info = DispatchInfo>,
622	{
623		Self::compute_fee_raw(len, info.total_weight(), tip, info.pays_fee, info.class)
624	}
625
626	/// Compute the actual post dispatch fee for a particular transaction.
627	///
628	/// Identical to `compute_fee` with the only difference that the post dispatch corrected
629	/// weight is used for the weight fee calculation.
630	pub fn compute_actual_fee(
631		len: u32,
632		info: &DispatchInfoOf<T::RuntimeCall>,
633		post_info: &PostDispatchInfoOf<T::RuntimeCall>,
634		tip: BalanceOf<T>,
635	) -> BalanceOf<T>
636	where
637		T::RuntimeCall: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo>,
638	{
639		Self::compute_actual_fee_details(len, info, post_info, tip).final_fee()
640	}
641
642	/// Compute the actual post dispatch fee details for a particular transaction.
643	pub fn compute_actual_fee_details(
644		len: u32,
645		info: &DispatchInfoOf<T::RuntimeCall>,
646		post_info: &PostDispatchInfoOf<T::RuntimeCall>,
647		tip: BalanceOf<T>,
648	) -> FeeDetails<BalanceOf<T>>
649	where
650		T::RuntimeCall: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo>,
651	{
652		Self::compute_fee_raw(
653			len,
654			post_info.calc_actual_weight(info),
655			tip,
656			post_info.pays_fee(info),
657			info.class,
658		)
659	}
660
661	fn compute_fee_raw(
662		len: u32,
663		weight: Weight,
664		tip: BalanceOf<T>,
665		pays_fee: Pays,
666		class: DispatchClass,
667	) -> FeeDetails<BalanceOf<T>> {
668		if pays_fee == Pays::Yes {
669			// the adjustable part of the fee.
670			let unadjusted_weight_fee = Self::weight_to_fee(weight);
671			let multiplier = NextFeeMultiplier::<T>::get();
672			// final adjusted weight fee.
673			let adjusted_weight_fee = multiplier.saturating_mul_int(unadjusted_weight_fee);
674
675			// length fee. this is adjusted via `LengthToFee`.
676			let len_fee = Self::length_to_fee(len);
677
678			let base_fee = Self::weight_to_fee(T::BlockWeights::get().get(class).base_extrinsic);
679			FeeDetails {
680				inclusion_fee: Some(InclusionFee { base_fee, len_fee, adjusted_weight_fee }),
681				tip,
682			}
683		} else {
684			FeeDetails { inclusion_fee: None, tip }
685		}
686	}
687
688	/// Compute the length portion of a fee by invoking the configured `LengthToFee` impl.
689	pub fn length_to_fee(length: u32) -> BalanceOf<T> {
690		T::LengthToFee::weight_to_fee(&Weight::from_parts(length as u64, 0))
691	}
692
693	/// Compute the unadjusted portion of the weight fee by invoking the configured `WeightToFee`
694	/// impl. Note that the input `weight` is capped by the maximum block weight before computation.
695	pub fn weight_to_fee(weight: Weight) -> BalanceOf<T> {
696		// cap the weight to the maximum defined in runtime, otherwise it will be the
697		// `Bounded` maximum of its data type, which is not desired.
698		let capped_weight = weight.min(T::BlockWeights::get().max_block);
699		T::WeightToFee::weight_to_fee(&capped_weight)
700	}
701
702	/// Deposit the [`Event::TransactionFeePaid`] event.
703	pub fn deposit_fee_paid_event(who: T::AccountId, actual_fee: BalanceOf<T>, tip: BalanceOf<T>) {
704		Self::deposit_event(Event::TransactionFeePaid { who, actual_fee, tip });
705	}
706
707	/// Withdraw `amount` from the currents transaction's fees.
708	///
709	/// If enough balance is available a credit of size `amount` is returned.
710	///
711	/// # Warning
712	///
713	/// Do **not** use this to pay for Weight fees. Use only to pay for storage fees
714	/// that can be rolled back by a storage transaction.
715	///
716	/// # Note
717	///
718	/// This is only useful if a pallet knows that the pre-dispatch weight was vastly
719	/// overestimated. Pallets need to make sure to leave enough balance to pay for the
720	/// transaction fees. They can do that by first drawing as much as they need and then
721	/// at the end of the transaction (when they know the post dispatch fee) return an error
722	/// in case not enough is left. The error will automatically roll back all the storage
723	/// changes done by the pallet including the balance drawn by calling this function.
724	pub fn withdraw_txfee<Balance>(amount: Balance) -> Option<CreditOf<T>>
725	where
726		CreditOf<T>: Imbalance<Balance>,
727		Balance: PartialOrd,
728	{
729		<TxPaymentCredit<T>>::mutate(|credit| {
730			let credit = SuppressedDrop::as_mut(credit.as_mut()?);
731			if amount > credit.peek() {
732				return None
733			}
734			Some(credit.extract(amount))
735		})
736	}
737
738	/// Deposit some additional balance.
739	pub fn deposit_txfee<Balance>(deposit: CreditOf<T>)
740	where
741		CreditOf<T>: Imbalance<Balance>,
742	{
743		<TxPaymentCredit<T>>::mutate(|credit| {
744			if let Some(credit) = credit.as_mut().map(SuppressedDrop::as_mut) {
745				credit.subsume(deposit);
746			} else {
747				*credit = Some(SuppressedDrop::new(deposit))
748			}
749		});
750	}
751
752	/// Return how much balance is currently available to pay for the transaction.
753	///
754	/// Does **not** include the tip.
755	///
756	/// If noone calls `charge_from_txfee` it is the same as the pre dispatch fee.
757	pub fn remaining_txfee<Balance>() -> Balance
758	where
759		CreditOf<T>: Imbalance<Balance>,
760		Balance: Default,
761	{
762		<TxPaymentCredit<T>>::get()
763			.map(|c| SuppressedDrop::as_ref(&c).peek())
764			.unwrap_or_default()
765	}
766}
767
768impl<T> Convert<Weight, BalanceOf<T>> for Pallet<T>
769where
770	T: Config,
771{
772	/// Compute the fee for the specified weight.
773	///
774	/// This fee is already adjusted by the per block fee adjustment factor and is therefore the
775	/// share that the weight contributes to the overall fee of a transaction. It is mainly
776	/// for informational purposes and not used in the actual fee calculation.
777	fn convert(weight: Weight) -> BalanceOf<T> {
778		NextFeeMultiplier::<T>::get().saturating_mul_int(Self::weight_to_fee(weight))
779	}
780}
781
782/// Require the transactor pay for themselves and maybe include a tip to gain additional priority
783/// in the queue.
784///
785/// # Transaction Validity
786///
787/// This extension sets the `priority` field of `TransactionValidity` depending on the amount
788/// of tip being paid per weight unit.
789///
790/// Operational transactions will receive an additional priority bump, so that they are normally
791/// considered before regular transactions.
792#[derive(Encode, Decode, DecodeWithMemTracking, Clone, Eq, PartialEq, TypeInfo)]
793#[scale_info(skip_type_params(T))]
794pub struct ChargeTransactionPayment<T: Config>(#[codec(compact)] BalanceOf<T>);
795
796impl<T: Config> ChargeTransactionPayment<T>
797where
798	T::RuntimeCall: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo>,
799	BalanceOf<T>: Send + Sync,
800{
801	/// utility constructor. Used only in client/factory code.
802	pub fn from(fee: BalanceOf<T>) -> Self {
803		Self(fee)
804	}
805
806	/// Returns the tip as being chosen by the transaction sender.
807	pub fn tip(&self) -> BalanceOf<T> {
808		self.0
809	}
810
811	fn withdraw_fee(
812		&self,
813		who: &T::AccountId,
814		call: &T::RuntimeCall,
815		info: &DispatchInfoOf<T::RuntimeCall>,
816		fee_with_tip: BalanceOf<T>,
817	) -> Result<
818		(
819			BalanceOf<T>,
820			<<T as Config>::OnChargeTransaction as OnChargeTransaction<T>>::LiquidityInfo,
821		),
822		TransactionValidityError,
823	> {
824		let tip = self.0;
825
826		<<T as Config>::OnChargeTransaction as OnChargeTransaction<T>>::withdraw_fee(
827			who,
828			call,
829			info,
830			fee_with_tip,
831			tip,
832		)
833		.map(|liquidity_info| (fee_with_tip, liquidity_info))
834	}
835
836	fn can_withdraw_fee(
837		&self,
838		who: &T::AccountId,
839		call: &T::RuntimeCall,
840		info: &DispatchInfoOf<T::RuntimeCall>,
841		len: usize,
842	) -> Result<BalanceOf<T>, TransactionValidityError> {
843		let tip = self.0;
844		let fee_with_tip = Pallet::<T>::compute_fee(len as u32, info, tip);
845
846		<<T as Config>::OnChargeTransaction as OnChargeTransaction<T>>::can_withdraw_fee(
847			who,
848			call,
849			info,
850			fee_with_tip,
851			tip,
852		)?;
853		Ok(fee_with_tip)
854	}
855
856	/// Get an appropriate priority for a transaction with the given `DispatchInfo`, encoded length
857	/// and user-included tip.
858	///
859	/// The priority is based on the amount of `tip` the user is willing to pay per unit of either
860	/// `weight` or `length`, depending which one is more limiting. For `Operational` extrinsics
861	/// we add a "virtual tip" to the calculations.
862	///
863	/// The formula should simply be `tip / bounded_{weight|length}`, but since we are using
864	/// integer division, we have no guarantees it's going to give results in any reasonable
865	/// range (might simply end up being zero). Hence we use a scaling factor:
866	/// `tip * (max_block_{weight|length} / bounded_{weight|length})`, since given current
867	/// state of-the-art blockchains, number of per-block transactions is expected to be in a
868	/// range reasonable enough to not saturate the `Balance` type while multiplying by the tip.
869	pub fn get_priority(
870		info: &DispatchInfoOf<T::RuntimeCall>,
871		len: usize,
872		tip: BalanceOf<T>,
873		final_fee_with_tip: BalanceOf<T>,
874	) -> TransactionPriority {
875		// Calculate how many such extrinsics we could fit into an empty block and take the
876		// limiting factor.
877		let max_block_weight = T::BlockWeights::get().max_block;
878		let max_block_length = *T::BlockLength::get().max.get(info.class) as u64;
879
880		// bounded_weight is used as a divisor later so we keep it non-zero.
881		let bounded_weight =
882			info.total_weight().max(Weight::from_parts(1, 1)).min(max_block_weight);
883		let bounded_length = (len as u64).clamp(1, max_block_length);
884
885		// returns the scarce resource, i.e. the one that is limiting the number of transactions.
886		let max_tx_per_block_weight = max_block_weight
887			.checked_div_per_component(&bounded_weight)
888			.defensive_proof("bounded_weight is non-zero; qed")
889			.unwrap_or(1);
890		let max_tx_per_block_length = max_block_length / bounded_length;
891		// Given our current knowledge this value is going to be in a reasonable range - i.e.
892		// less than 10^9 (2^30), so multiplying by the `tip` value is unlikely to overflow the
893		// balance type. We still use saturating ops obviously, but the point is to end up with some
894		// `priority` distribution instead of having all transactions saturate the priority.
895		let max_tx_per_block = max_tx_per_block_length
896			.min(max_tx_per_block_weight)
897			.saturated_into::<BalanceOf<T>>();
898		let max_reward = |val: BalanceOf<T>| val.saturating_mul(max_tx_per_block);
899
900		// To distribute no-tip transactions a little bit, we increase the tip value by one.
901		// This means that given two transactions without a tip, smaller one will be preferred.
902		let tip = tip.saturating_add(One::one());
903		let scaled_tip = max_reward(tip);
904
905		match info.class {
906			DispatchClass::Normal => {
907				// For normal class we simply take the `tip_per_weight`.
908				scaled_tip
909			},
910			DispatchClass::Mandatory => {
911				// Mandatory extrinsics should be prohibited (e.g. by the [`CheckWeight`]
912				// extensions), but just to be safe let's return the same priority as `Normal` here.
913				scaled_tip
914			},
915			DispatchClass::Operational => {
916				// A "virtual tip" value added to an `Operational` extrinsic.
917				// This value should be kept high enough to allow `Operational` extrinsics
918				// to get in even during congestion period, but at the same time low
919				// enough to prevent a possible spam attack by sending invalid operational
920				// extrinsics which push away regular transactions from the pool.
921				let fee_multiplier = T::OperationalFeeMultiplier::get().saturated_into();
922				let virtual_tip = final_fee_with_tip.saturating_mul(fee_multiplier);
923				let scaled_virtual_tip = max_reward(virtual_tip);
924
925				scaled_tip.saturating_add(scaled_virtual_tip)
926			},
927		}
928		.saturated_into::<TransactionPriority>()
929	}
930}
931
932impl<T: Config> core::fmt::Debug for ChargeTransactionPayment<T> {
933	#[cfg(feature = "std")]
934	fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
935		write!(f, "ChargeTransactionPayment<{:?}>", self.0)
936	}
937	#[cfg(not(feature = "std"))]
938	fn fmt(&self, _: &mut core::fmt::Formatter) -> core::fmt::Result {
939		Ok(())
940	}
941}
942
943/// The info passed between the validate and prepare steps for the `ChargeAssetTxPayment` extension.
944#[derive(RuntimeDebugNoBound)]
945pub enum Val<T: Config> {
946	Charge {
947		tip: BalanceOf<T>,
948		// who paid the fee
949		who: T::AccountId,
950		// transaction fee
951		fee_with_tip: BalanceOf<T>,
952	},
953	NoCharge,
954}
955
956/// The info passed between the prepare and post-dispatch steps for the `ChargeAssetTxPayment`
957/// extension.
958pub enum Pre<T: Config> {
959	Charge {
960		tip: BalanceOf<T>,
961		// who paid the fee
962		who: T::AccountId,
963		// implementation defined type that is passed into the post charge function
964		liquidity_info:
965			<<T as Config>::OnChargeTransaction as OnChargeTransaction<T>>::LiquidityInfo,
966	},
967	NoCharge {
968		// weight initially estimated by the extension, to be refunded
969		refund: Weight,
970	},
971}
972
973impl<T: Config> core::fmt::Debug for Pre<T> {
974	#[cfg(feature = "std")]
975	fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
976		match self {
977			Pre::Charge { tip, who, liquidity_info: _ } => {
978				write!(f, "Charge {{ tip: {:?}, who: {:?}, imbalance: <stripped> }}", tip, who)
979			},
980			Pre::NoCharge { refund } => write!(f, "NoCharge {{ refund: {:?} }}", refund),
981		}
982	}
983
984	#[cfg(not(feature = "std"))]
985	fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
986		f.write_str("<wasm:stripped>")
987	}
988}
989
990impl<T: Config> TransactionExtension<T::RuntimeCall> for ChargeTransactionPayment<T>
991where
992	T::RuntimeCall: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo>,
993{
994	const IDENTIFIER: &'static str = "ChargeTransactionPayment";
995	type Implicit = ();
996	type Val = Val<T>;
997	type Pre = Pre<T>;
998
999	fn weight(&self, _: &T::RuntimeCall) -> Weight {
1000		T::WeightInfo::charge_transaction_payment()
1001	}
1002
1003	fn validate(
1004		&self,
1005		origin: <T::RuntimeCall as Dispatchable>::RuntimeOrigin,
1006		call: &T::RuntimeCall,
1007		info: &DispatchInfoOf<T::RuntimeCall>,
1008		len: usize,
1009		_: (),
1010		_implication: &impl Encode,
1011		_source: TransactionSource,
1012	) -> Result<
1013		(ValidTransaction, Self::Val, <T::RuntimeCall as Dispatchable>::RuntimeOrigin),
1014		TransactionValidityError,
1015	> {
1016		let Ok(who) = frame_system::ensure_signed(origin.clone()) else {
1017			return Ok((ValidTransaction::default(), Val::NoCharge, origin));
1018		};
1019		let fee_with_tip = self.can_withdraw_fee(&who, call, info, len)?;
1020		let tip = self.0;
1021		Ok((
1022			ValidTransaction {
1023				priority: Self::get_priority(info, len, tip, fee_with_tip),
1024				..Default::default()
1025			},
1026			Val::Charge { tip: self.0, who, fee_with_tip },
1027			origin,
1028		))
1029	}
1030
1031	fn prepare(
1032		self,
1033		val: Self::Val,
1034		_origin: &<T::RuntimeCall as Dispatchable>::RuntimeOrigin,
1035		call: &T::RuntimeCall,
1036		info: &DispatchInfoOf<T::RuntimeCall>,
1037		_len: usize,
1038	) -> Result<Self::Pre, TransactionValidityError> {
1039		match val {
1040			Val::Charge { tip, who, fee_with_tip } => {
1041				// Mutating call to `withdraw_fee` to actually charge for the transaction.
1042				let (_fee_with_tip, liquidity_info) =
1043					self.withdraw_fee(&who, call, info, fee_with_tip)?;
1044				Ok(Pre::Charge { tip, who, liquidity_info })
1045			},
1046			Val::NoCharge => Ok(Pre::NoCharge { refund: self.weight(call) }),
1047		}
1048	}
1049
1050	fn post_dispatch_details(
1051		pre: Self::Pre,
1052		info: &DispatchInfoOf<T::RuntimeCall>,
1053		post_info: &PostDispatchInfoOf<T::RuntimeCall>,
1054		len: usize,
1055		_result: &DispatchResult,
1056	) -> Result<Weight, TransactionValidityError> {
1057		let (tip, who, liquidity_info) = match pre {
1058			Pre::Charge { tip, who, liquidity_info } => (tip, who, liquidity_info),
1059			Pre::NoCharge { refund } => {
1060				// No-op: Refund everything
1061				return Ok(refund)
1062			},
1063		};
1064		let actual_fee_with_tip =
1065			Pallet::<T>::compute_actual_fee(len as u32, info, &post_info, tip);
1066		T::OnChargeTransaction::correct_and_deposit_fee(
1067			&who,
1068			info,
1069			&post_info,
1070			actual_fee_with_tip,
1071			tip,
1072			liquidity_info,
1073		)?;
1074		Pallet::<T>::deposit_event(Event::<T>::TransactionFeePaid {
1075			who,
1076			actual_fee: actual_fee_with_tip,
1077			tip,
1078		});
1079		Ok(Weight::zero())
1080	}
1081}
1082
1083impl<T: Config, AnyCall: GetDispatchInfo + Encode> EstimateCallFee<AnyCall, BalanceOf<T>>
1084	for Pallet<T>
1085where
1086	T::RuntimeCall: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo>,
1087{
1088	fn estimate_call_fee(call: &AnyCall, post_info: PostDispatchInfo) -> BalanceOf<T> {
1089		let len = call.encoded_size() as u32;
1090		let info = call.get_dispatch_info();
1091		Self::compute_actual_fee(len, &info, &post_info, Zero::zero())
1092	}
1093}