Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Backported fee payment fix #17

Merged
merged 4 commits into from
Oct 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion substrate/bin/minimal/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ impl pallet_timestamp::Config for Runtime {}

#[derive_impl(pallet_transaction_payment::config_preludes::TestDefaultConfig as pallet_transaction_payment::DefaultConfig)]
impl pallet_transaction_payment::Config for Runtime {
type OnChargeTransaction = pallet_transaction_payment::CurrencyAdapter<Balances, ()>;
type OnChargeTransaction = pallet_transaction_payment::FungibleAdapter<Balances, ()>;
type WeightToFee = NoFee<<Self as pallet_balances::Config>::Balance>;
type LengthToFee = FixedFee<1, <Self as pallet_balances::Config>::Balance>;
}
Expand Down
4 changes: 2 additions & 2 deletions substrate/bin/node-template/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ pub use frame_support::{
pub use frame_system::Call as SystemCall;
pub use pallet_balances::Call as BalancesCall;
pub use pallet_timestamp::Call as TimestampCall;
use pallet_transaction_payment::{ConstFeeMultiplier, CurrencyAdapter, Multiplier};
use pallet_transaction_payment::{ConstFeeMultiplier, FungibleAdapter, Multiplier};
#[cfg(any(feature = "std", test))]
pub use sp_runtime::BuildStorage;
pub use sp_runtime::{Perbill, Permill};
Expand Down Expand Up @@ -236,7 +236,7 @@ parameter_types! {

impl pallet_transaction_payment::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type OnChargeTransaction = CurrencyAdapter<Balances, ()>;
type OnChargeTransaction = FungibleAdapter<Balances, ()>;
type OperationalFeeMultiplier = ConstU8<5>;
type WeightToFee = IdentityFee<Balance>;
type LengthToFee = IdentityFee<Balance>;
Expand Down
2 changes: 2 additions & 0 deletions substrate/bin/node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ use pallet_im_online::sr25519::AuthorityId as ImOnlineId;
use pallet_nfts::PalletFeatures;
use pallet_nis::WithMaximumOf;
use pallet_session::historical as pallet_session_historical;
#[allow(deprecated)]
pub use pallet_transaction_payment::{CurrencyAdapter, Multiplier, TargetedFeeAdjustment};
use pallet_transaction_payment::{FeeDetails, RuntimeDispatchInfo};
use pallet_tx_pause::RuntimeCallNameOf;
Expand Down Expand Up @@ -544,6 +545,7 @@ parameter_types! {
pub MaximumMultiplier: Multiplier = Bounded::max_value();
}

#[allow(deprecated)]
impl pallet_transaction_payment::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type OnChargeTransaction = CurrencyAdapter<Balances, DealWithFees>;
Expand Down
4 changes: 2 additions & 2 deletions substrate/frame/balances/src/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ use frame_support::{
weights::{IdentityFee, Weight},
};
use frame_system::{self as system, RawOrigin};
use pallet_transaction_payment::{ChargeTransactionPayment, CurrencyAdapter, Multiplier};
use pallet_transaction_payment::{ChargeTransactionPayment, FungibleAdapter, Multiplier};
use scale_info::TypeInfo;
use sp_core::{hexdisplay::HexDisplay, H256};
use sp_io;
Expand Down Expand Up @@ -119,7 +119,7 @@ impl frame_system::Config for Test {

impl pallet_transaction_payment::Config for Test {
type RuntimeEvent = RuntimeEvent;
type OnChargeTransaction = CurrencyAdapter<Pallet<Test>, ()>;
type OnChargeTransaction = FungibleAdapter<Pallet<Test>, ()>;
type OperationalFeeMultiplier = ConstU8<5>;
type WeightToFee = IdentityFee<u64>;
type LengthToFee = IdentityFee<u64>;
Expand Down
4 changes: 2 additions & 2 deletions substrate/frame/executive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -768,7 +768,7 @@ mod tests {
};
use frame_system::{ChainContext, LastRuntimeUpgrade, LastRuntimeUpgradeInfo};
use pallet_balances::Call as BalancesCall;
use pallet_transaction_payment::CurrencyAdapter;
use pallet_transaction_payment::FungibleAdapter;

const TEST_KEY: &[u8] = b":test:key:";

Expand Down Expand Up @@ -966,7 +966,7 @@ mod tests {
}
impl pallet_transaction_payment::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type OnChargeTransaction = CurrencyAdapter<Balances, ()>;
type OnChargeTransaction = FungibleAdapter<Balances, ()>;
type OperationalFeeMultiplier = ConstU8<5>;
type WeightToFee = IdentityFee<Balance>;
type LengthToFee = ConstantMultiplier<Balance, TransactionByteFee>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ use frame_support::{
use frame_system as system;
use frame_system::{EnsureRoot, EnsureSignedBy};
use pallet_asset_conversion::{Ascending, Chain, WithFirstAsset};
use pallet_transaction_payment::CurrencyAdapter;
use pallet_transaction_payment::FungibleAdapter;
use sp_core::H256;
use sp_runtime::{
traits::{AccountIdConversion, BlakeTwo256, IdentityLookup, SaturatedConversion},
Expand Down Expand Up @@ -170,7 +170,7 @@ impl OnUnbalanced<pallet_balances::NegativeImbalance<Runtime>> for DealWithFees

impl pallet_transaction_payment::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type OnChargeTransaction = CurrencyAdapter<Balances, DealWithFees>;
type OnChargeTransaction = FungibleAdapter<Balances, DealWithFees>;
type WeightToFee = WeightToFee;
type LengthToFee = TransactionByteFee;
type FeeMultiplierUpdate = ();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ use frame_support::{
};
use frame_system as system;
use frame_system::EnsureRoot;
use pallet_transaction_payment::CurrencyAdapter;
use pallet_transaction_payment::FungibleAdapter;
use sp_core::H256;
use sp_runtime::traits::{BlakeTwo256, ConvertInto, IdentityLookup, SaturatedConversion};

Expand Down Expand Up @@ -138,7 +138,7 @@ impl WeightToFeeT for TransactionByteFee {

impl pallet_transaction_payment::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type OnChargeTransaction = CurrencyAdapter<Balances, ()>;
type OnChargeTransaction = FungibleAdapter<Balances, ()>;
type WeightToFee = WeightToFee;
type LengthToFee = TransactionByteFee;
type FeeMultiplierUpdate = ();
Expand Down
2 changes: 1 addition & 1 deletion substrate/frame/transaction-payment/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ impl OnUnbalanced<pallet_balances::NegativeImbalance<Runtime>> for DealWithFees

impl Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type OnChargeTransaction = CurrencyAdapter<Balances, DealWithFees>;
type OnChargeTransaction = FungibleAdapter<Balances, DealWithFees>;
type OperationalFeeMultiplier = OperationalFeeMultiplier;
type WeightToFee = WeightToFee;
type LengthToFee = TransactionByteFee;
Expand Down
90 changes: 83 additions & 7 deletions substrate/frame/transaction-payment/src/payment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,11 @@ use sp_runtime::{
use sp_std::marker::PhantomData;

use frame_support::{
traits::{Currency, ExistenceRequirement, Imbalance, OnUnbalanced, WithdrawReasons},
traits::{
fungible::{Balanced, Credit, Debt, Inspect},
tokens::Precision,
Currency, ExistenceRequirement, Imbalance, OnUnbalanced, TryDrop, WithdrawReasons,
},
unsigned::TransactionValidityError,
};

Expand Down Expand Up @@ -66,18 +70,90 @@ pub trait OnChargeTransaction<T: Config> {
) -> Result<(), TransactionValidityError>;
}

/// Implements the transaction payment for a pallet implementing the `Currency`
/// Implements transaction payment for a pallet implementing the [`fungible`]
/// trait (eg. pallet_balances) using an unbalance handler (implementing
/// [`OnUnbalanced`]).
///
/// The unbalance handler is given 2 unbalanceds in [`OnUnbalanced::on_unbalanceds`]: `fee` and
/// then `tip`.
pub struct FungibleAdapter<F, OU>(PhantomData<(F, OU)>);

impl<T, F, OU> OnChargeTransaction<T> for FungibleAdapter<F, OU>
where
T: Config,
F: Balanced<T::AccountId>,
OU: OnUnbalanced<Credit<T::AccountId, F>>,
{
type LiquidityInfo = Option<Credit<T::AccountId, F>>;
type Balance = <F as Inspect<<T as frame_system::Config>::AccountId>>::Balance;

fn withdraw_fee(
who: &<T>::AccountId,
_call: &<T>::RuntimeCall,
_dispatch_info: &DispatchInfoOf<<T>::RuntimeCall>,
fee: Self::Balance,
_tip: Self::Balance,
) -> Result<Self::LiquidityInfo, TransactionValidityError> {
if fee.is_zero() {
return Ok(None)
}

match F::withdraw(
who,
fee,
Precision::Exact,
frame_support::traits::tokens::Preservation::Preserve,
frame_support::traits::tokens::Fortitude::Polite,
) {
Ok(imbalance) => Ok(Some(imbalance)),
Err(_) => Err(InvalidTransaction::Payment.into()),
}
}

fn correct_and_deposit_fee(
who: &<T>::AccountId,
_dispatch_info: &DispatchInfoOf<<T>::RuntimeCall>,
_post_info: &PostDispatchInfoOf<<T>::RuntimeCall>,
corrected_fee: Self::Balance,
tip: Self::Balance,
already_withdrawn: Self::LiquidityInfo,
) -> Result<(), TransactionValidityError> {
if let Some(paid) = already_withdrawn {
// Calculate how much refund we should return
let refund_amount = paid.peek().saturating_sub(corrected_fee);
// refund to the the account that paid the fees. If this fails, the
// account might have dropped below the existential balance. In
// that case we don't refund anything.
let refund_imbalance = F::deposit(who, refund_amount, Precision::BestEffort)
.unwrap_or_else(|_| Debt::<T::AccountId, F>::zero());
// merge the imbalance caused by paying the fees and refunding parts of it again.
let adjusted_paid: Credit<T::AccountId, F> = paid
.offset(refund_imbalance)
.same()
.map_err(|_| TransactionValidityError::Invalid(InvalidTransaction::Payment))?;
// Call someone else to handle the imbalance (fee and tip separately)
let (tip, fee) = adjusted_paid.split(tip);
OU::on_unbalanceds(Some(fee).into_iter().chain(Some(tip)));
}

Ok(())
}
}

/// Implements the transaction payment for a pallet implementing the [`Currency`]
/// trait (eg. the pallet_balances) using an unbalance handler (implementing
/// `OnUnbalanced`).
/// [`OnUnbalanced`]).
///
/// The unbalance handler is given 2 unbalanceds in [`OnUnbalanced::on_unbalanceds`]: fee and
/// then tip.
/// The unbalance handler is given 2 unbalanceds in [`OnUnbalanced::on_unbalanceds`]: `fee` and
/// then `tip`.
#[deprecated(note = "Please use the fungible trait and FungibleAdapter instead where possible.")]
pub struct CurrencyAdapter<C, OU>(PhantomData<(C, OU)>);

/// Default implementation for a Currency and an OnUnbalanced handler.
///
/// The unbalance handler is given 2 unbalanceds in [`OnUnbalanced::on_unbalanceds`]: fee and
/// then tip.
/// The unbalance handler is given 2 unbalanceds in [`OnUnbalanced::on_unbalanceds`]: `fee` and
/// then `tip`.
#[allow(deprecated)]
impl<T, C, OU> OnChargeTransaction<T> for CurrencyAdapter<C, OU>
where
T: Config,
Expand Down
14 changes: 13 additions & 1 deletion substrate/frame/treasury/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ use sp_runtime::{
traits::{AccountIdConversion, CheckedAdd, Saturating, StaticLookup, Zero},
Permill, RuntimeDebug,
};
use sp_std::{collections::btree_map::BTreeMap, prelude::*};
use sp_std::{collections::btree_map::BTreeMap, marker::PhantomData, prelude::*};

use frame_support::{
dispatch::{DispatchResult, DispatchResultWithPostInfo},
Expand Down Expand Up @@ -1120,3 +1120,15 @@ impl<T: Config<I>, I: 'static> OnUnbalanced<NegativeImbalanceOf<T, I>> for Palle
Self::deposit_event(Event::Deposit { value: numeric_amount });
}
}

/// TypedGet implementation to get the AccountId of the Treasury.
pub struct TreasuryAccountId<R>(PhantomData<R>);
impl<R> sp_runtime::traits::TypedGet for TreasuryAccountId<R>
where
R: crate::Config,
{
type Type = <R as frame_system::Config>::AccountId;
fn get() -> Self::Type {
crate::Pallet::<R>::account_id()
}
}
Loading