Skip to main content

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