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

Migrate Fee payment to use Fungible Adapter #2624

Merged
merged 9 commits into from Feb 6, 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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
580 changes: 290 additions & 290 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion primitives/xcm/src/fee_handlers.rs
Expand Up @@ -164,7 +164,7 @@ pub struct XcmFeesToAccount<Assets, Matcher, AccountId, ReceiverAccount>(
impl<
Assets: Mutate<AccountId>,
Matcher: MatchesFungibles<Assets::AssetId, Assets::Balance>,
AccountId: Clone,
AccountId: Clone + Eq,
ReceiverAccount: Get<AccountId>,
> TakeRevenue for XcmFeesToAccount<Assets, Matcher, AccountId, ReceiverAccount>
{
Expand Down
26 changes: 10 additions & 16 deletions runtime/common/src/impl_on_charge_evm_transaction.rs
Expand Up @@ -17,43 +17,37 @@
#[macro_export]
macro_rules! impl_on_charge_evm_transaction {
{} => {
type CurrencyAccountId<T> = <T as frame_system::Config>::AccountId;
type FungibleAccountId<T> = <T as frame_system::Config>::AccountId;

type BalanceFor<T> =
<<T as pallet_evm::Config>::Currency as CurrencyT<CurrencyAccountId<T>>>::Balance;

type PositiveImbalanceFor<T> =
<<T as pallet_evm::Config>::Currency as CurrencyT<CurrencyAccountId<T>>>::PositiveImbalance;

type NegativeImbalanceFor<T> =
<<T as pallet_evm::Config>::Currency as CurrencyT<CurrencyAccountId<T>>>::NegativeImbalance;
<<T as pallet_evm::Config>::Currency as Inspect<FungibleAccountId<T>>>::Balance;

pub struct OnChargeEVMTransaction<OU>(sp_std::marker::PhantomData<OU>);

impl<T, OU> OnChargeEVMTransactionT<T> for OnChargeEVMTransaction<OU>
where
T: pallet_evm::Config,
PositiveImbalanceFor<T>: Imbalance<BalanceFor<T>, Opposite = NegativeImbalanceFor<T>>,
NegativeImbalanceFor<T>: Imbalance<BalanceFor<T>, Opposite = PositiveImbalanceFor<T>>,
OU: OnUnbalanced<NegativeImbalanceFor<T>>,
T::Currency: Balanced<T::AccountId>,
OU: OnUnbalanced<Credit<T::AccountId, T::Currency>>,
U256: UniqueSaturatedInto<BalanceFor<T>>
{
type LiquidityInfo = Option<NegativeImbalanceFor<T>>;
type LiquidityInfo = Option<Credit<T::AccountId, T::Currency>>;

fn withdraw_fee(who: &H160, fee: U256) -> Result<Self::LiquidityInfo, pallet_evm::Error<T>> {
EVMCurrencyAdapter::<<T as pallet_evm::Config>::Currency, ()>::withdraw_fee(who, fee)
EVMFungibleAdapter::<<T as pallet_evm::Config>::Currency, ()>::withdraw_fee(who, fee)
}

fn can_withdraw(who: &H160, amount: U256) -> Result<(), pallet_evm::Error<T>> {
EVMCurrencyAdapter::<<T as pallet_evm::Config>::Currency, ()>::can_withdraw(who, amount)
EVMFungibleAdapter::<<T as pallet_evm::Config>::Currency, ()>::can_withdraw(who, amount)
}

fn correct_and_deposit_fee(
who: &H160,
corrected_fee: U256,
base_fee: U256,
already_withdrawn: Self::LiquidityInfo,
) -> Self::LiquidityInfo {
<EVMCurrencyAdapter<<T as pallet_evm::Config>::Currency, OU> as OnChargeEVMTransactionT<
) -> Result<Self::LiquidityInfo, pallet_evm::Error<T>> {
<EVMFungibleAdapter<<T as pallet_evm::Config>::Currency, OU> as OnChargeEVMTransactionT<
T,
>>::correct_and_deposit_fee(who, corrected_fee, base_fee, already_withdrawn)
}
Expand Down
41 changes: 23 additions & 18 deletions runtime/moonbase/src/lib.rs
Expand Up @@ -63,12 +63,12 @@ use frame_support::{
pallet_prelude::DispatchResult,
parameter_types,
traits::{
fungible::HoldConsideration,
fungible::{Balanced, Credit, HoldConsideration, Inspect},
tokens::imbalance::ResolveTo,
tokens::{PayFromAccount, UnityAssetBalanceConversion},
ConstBool, ConstU128, ConstU16, ConstU32, ConstU64, ConstU8, Contains,
Currency as CurrencyT, EitherOfDiverse, EqualPrivilegeOnly, FindAuthor, Imbalance,
InstanceFilter, LinearStoragePrice, OffchainWorker, OnFinalize, OnIdle, OnInitialize,
OnRuntimeUpgrade, OnUnbalanced,
ConstBool, ConstU128, ConstU16, ConstU32, ConstU64, ConstU8, Contains, EitherOfDiverse,
EqualPrivilegeOnly, FindAuthor, Imbalance, InstanceFilter, LinearStoragePrice,
OffchainWorker, OnFinalize, OnIdle, OnInitialize, OnRuntimeUpgrade, OnUnbalanced,
},
weights::{
constants::{RocksDbWeight, WEIGHT_REF_TIME_PER_SECOND},
Expand All @@ -83,15 +83,15 @@ use governance::councils::*;
use moonbeam_rpc_primitives_txpool::TxPoolResponse;
use moonbeam_runtime_common::weights as moonbeam_weights;
use nimbus_primitives::CanAuthor;
use pallet_balances::NegativeImbalance;
use pallet_ethereum::Call::transact;
use pallet_ethereum::{PostLogContent, Transaction as EthereumTransaction};
use pallet_evm::{
Account as EVMAccount, EVMCurrencyAdapter, EnsureAddressNever, EnsureAddressRoot,
Account as EVMAccount, EVMFungibleAdapter, EnsureAddressNever, EnsureAddressRoot,
FeeCalculator, GasWeightMapping, IdentityAddressMapping,
OnChargeEVMTransaction as OnChargeEVMTransactionT, Runner,
};
use pallet_transaction_payment::{CurrencyAdapter, Multiplier, TargetedFeeAdjustment};
use pallet_transaction_payment::{FungibleAdapter, Multiplier, TargetedFeeAdjustment};
use pallet_treasury::TreasuryAccountId;
use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
use scale_info::TypeInfo;
use sp_api::impl_runtime_apis;
Expand Down Expand Up @@ -318,36 +318,41 @@ impl pallet_balances::Config for Runtime {
}

pub struct DealWithFees<R>(sp_std::marker::PhantomData<R>);
impl<R> OnUnbalanced<NegativeImbalance<R>> for DealWithFees<R>
impl<R> OnUnbalanced<Credit<R::AccountId, pallet_balances::Pallet<R>>> for DealWithFees<R>
where
R: pallet_balances::Config + pallet_treasury::Config,
pallet_treasury::Pallet<R>: OnUnbalanced<NegativeImbalance<R>>,
{
// this seems to be called for substrate-based transactions
fn on_unbalanceds<B>(mut fees_then_tips: impl Iterator<Item = NegativeImbalance<R>>) {
fn on_unbalanceds<B>(
mut fees_then_tips: impl Iterator<Item = Credit<R::AccountId, pallet_balances::Pallet<R>>>,
) {
if let Some(fees) = fees_then_tips.next() {
// for fees, 80% are burned, 20% to the treasury
let (_, to_treasury) = fees.ration(80, 20);
// Balances pallet automatically burns dropped Negative Imbalances by decreasing
// Balances pallet automatically burns dropped Credits by decreasing
// total_supply accordingly
<pallet_treasury::Pallet<R> as OnUnbalanced<_>>::on_unbalanced(to_treasury);
ResolveTo::<TreasuryAccountId<R>, pallet_balances::Pallet<R>>::on_unbalanced(
to_treasury,
);

// handle tip if there is one
if let Some(tip) = fees_then_tips.next() {
// for now we use the same burn/treasury strategy used for regular fees
let (_, to_treasury) = tip.ration(80, 20);
<pallet_treasury::Pallet<R> as OnUnbalanced<_>>::on_unbalanced(to_treasury);
ResolveTo::<TreasuryAccountId<R>, pallet_balances::Pallet<R>>::on_unbalanced(
to_treasury,
);
}
}
}

// this is called from pallet_evm for Ethereum-based transactions
// (technically, it calls on_unbalanced, which calls this when non-zero)
fn on_nonzero_unbalanced(amount: NegativeImbalance<R>) {
// Balances pallet automatically burns dropped Negative Imbalances by decreasing
fn on_nonzero_unbalanced(amount: Credit<R::AccountId, pallet_balances::Pallet<R>>) {
// Balances pallet automatically burns dropped Credits by decreasing
// total_supply accordingly
let (_, to_treasury) = amount.ration(80, 20);
<pallet_treasury::Pallet<R> as OnUnbalanced<_>>::on_unbalanced(to_treasury);
ResolveTo::<TreasuryAccountId<R>, pallet_balances::Pallet<R>>::on_unbalanced(to_treasury);
}
}

Expand Down Expand Up @@ -375,7 +380,7 @@ impl WeightToFeePolynomial for LengthToFee {

impl pallet_transaction_payment::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type OnChargeTransaction = CurrencyAdapter<Balances, DealWithFees<Runtime>>;
type OnChargeTransaction = FungibleAdapter<Balances, DealWithFees<Runtime>>;
type OperationalFeeMultiplier = ConstU8<5>;
type WeightToFee = ConstantMultiplier<Balance, ConstU128<{ currency::WEIGHT_FEE }>>;
type LengthToFee = LengthToFee;
Expand Down
58 changes: 33 additions & 25 deletions runtime/moonbase/tests/integration_test.rs
Expand Up @@ -19,7 +19,6 @@
mod common;
use common::*;

use pallet_balances::NegativeImbalance;
use precompile_utils::{
precompile_set::{is_precompile_or_fail, IsActivePrecompile},
prelude::*,
Expand Down Expand Up @@ -2707,30 +2706,39 @@ fn deal_with_fees_handles_tip() {
use frame_support::traits::OnUnbalanced;
use moonbase_runtime::{DealWithFees, Treasury};

ExtBuilder::default()
.with_balances(vec![(AccountId::from(ALICE), 10_000)])
.build()
.execute_with(|| {
// Alice has 10_000, which makes inital supply 10_000.
// drop()ing the NegativeImbalance below will cause the total_supply to be decreased
// incorrectly (since there was never a withdraw to begin with), which in this case has
// the desired effect of showing that currency was burned.
let total_supply_before = Balances::total_issuance();
assert_eq!(total_supply_before, 10_000);

let fees_then_tips = vec![
NegativeImbalance::<moonbase_runtime::Runtime>::new(100),
NegativeImbalance::<moonbase_runtime::Runtime>::new(1_000),
];
DealWithFees::on_unbalanceds(fees_then_tips.into_iter());

// treasury should have received 20%
assert_eq!(Balances::free_balance(&Treasury::account_id()), 220);

// verify 80% burned
let total_supply_after = Balances::total_issuance();
assert_eq!(total_supply_before - total_supply_after, 880);
});
ExtBuilder::default().build().execute_with(|| {
// This test checks the functionality of the `DealWithFees` trait implementation in the runtime.
// It simulates a scenario where a fee and a tip are issued to an account and ensures that the
// treasury receives the correct amount (20% of the total), and the rest is burned (80%).
//
// The test follows these steps:
// 1. It issues a fee of 100 and a tip of 1000.
// 2. It checks the total supply before the fee and tip are dealt with, which should be 1_100.
// 3. It checks that the treasury's balance is initially 0.
// 4. It calls `DealWithFees::on_unbalanceds` with the fee and tip.
// 5. It checks that the treasury's balance is now 220 (20% of the fee and tip).
// 6. It checks that the total supply has decreased by 880 (80% of the fee and tip), indicating
// that this amount was burned.
let fee = <pallet_balances::Pallet<Runtime> as frame_support::traits::fungible::Balanced<
AccountId,
>>::issue(100);
let tip = <pallet_balances::Pallet<Runtime> as frame_support::traits::fungible::Balanced<
AccountId,
>>::issue(1000);

let total_supply_before = Balances::total_issuance();
assert_eq!(total_supply_before, 1_100);
assert_eq!(Balances::free_balance(&Treasury::account_id()), 0);

DealWithFees::on_unbalanceds(vec![fee, tip].into_iter());

// treasury should have received 20%
assert_eq!(Balances::free_balance(&Treasury::account_id()), 220);

// verify 80% burned
let total_supply_after = Balances::total_issuance();
assert_eq!(total_supply_before - total_supply_after, 880);
});
}

#[test]
Expand Down
41 changes: 23 additions & 18 deletions runtime/moonbeam/src/lib.rs
Expand Up @@ -45,12 +45,12 @@ use frame_support::{
pallet_prelude::DispatchResult,
parameter_types,
traits::{
fungible::HoldConsideration,
fungible::{Balanced, Credit, HoldConsideration, Inspect},
tokens::imbalance::ResolveTo,
tokens::{PayFromAccount, UnityAssetBalanceConversion},
ConstBool, ConstU128, ConstU16, ConstU32, ConstU64, ConstU8, Contains,
Currency as CurrencyT, EitherOfDiverse, EqualPrivilegeOnly, Imbalance, InstanceFilter,
LinearStoragePrice, OffchainWorker, OnFinalize, OnIdle, OnInitialize, OnRuntimeUpgrade,
OnUnbalanced,
ConstBool, ConstU128, ConstU16, ConstU32, ConstU64, ConstU8, Contains, EitherOfDiverse,
EqualPrivilegeOnly, Imbalance, InstanceFilter, LinearStoragePrice, OffchainWorker,
OnFinalize, OnIdle, OnInitialize, OnRuntimeUpgrade, OnUnbalanced,
},
weights::{
constants::{RocksDbWeight, WEIGHT_REF_TIME_PER_SECOND},
Expand All @@ -66,16 +66,16 @@ pub use moonbeam_core_primitives::{
};
use moonbeam_rpc_primitives_txpool::TxPoolResponse;
use moonbeam_runtime_common::weights as moonbeam_weights;
use pallet_balances::NegativeImbalance;
use pallet_ethereum::Call::transact;
use pallet_ethereum::{PostLogContent, Transaction as EthereumTransaction};
use pallet_evm::{
Account as EVMAccount, EVMCurrencyAdapter, EnsureAddressNever, EnsureAddressRoot,
Account as EVMAccount, EVMFungibleAdapter, EnsureAddressNever, EnsureAddressRoot,
FeeCalculator, GasWeightMapping, IdentityAddressMapping,
OnChargeEVMTransaction as OnChargeEVMTransactionT, Runner,
};
pub use pallet_parachain_staking::{weights::WeightInfo, InflationInfo, Range};
use pallet_transaction_payment::{CurrencyAdapter, Multiplier, TargetedFeeAdjustment};
use pallet_transaction_payment::{FungibleAdapter, Multiplier, TargetedFeeAdjustment};
use pallet_treasury::TreasuryAccountId;
use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
use scale_info::TypeInfo;
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -307,36 +307,41 @@ impl pallet_balances::Config for Runtime {
}

pub struct DealWithFees<R>(sp_std::marker::PhantomData<R>);
impl<R> OnUnbalanced<NegativeImbalance<R>> for DealWithFees<R>
impl<R> OnUnbalanced<Credit<R::AccountId, pallet_balances::Pallet<R>>> for DealWithFees<R>
where
R: pallet_balances::Config + pallet_treasury::Config,
pallet_treasury::Pallet<R>: OnUnbalanced<NegativeImbalance<R>>,
{
// this seems to be called for substrate-based transactions
fn on_unbalanceds<B>(mut fees_then_tips: impl Iterator<Item = NegativeImbalance<R>>) {
fn on_unbalanceds<B>(
mut fees_then_tips: impl Iterator<Item = Credit<R::AccountId, pallet_balances::Pallet<R>>>,
) {
if let Some(fees) = fees_then_tips.next() {
// for fees, 80% are burned, 20% to the treasury
let (_, to_treasury) = fees.ration(80, 20);
// Balances pallet automatically burns dropped Negative Imbalances by decreasing
// Balances pallet automatically burns dropped Credits by decreasing
// total_supply accordingly
<pallet_treasury::Pallet<R> as OnUnbalanced<_>>::on_unbalanced(to_treasury);
ResolveTo::<TreasuryAccountId<R>, pallet_balances::Pallet<R>>::on_unbalanced(
to_treasury,
);

// handle tip if there is one
if let Some(tip) = fees_then_tips.next() {
// for now we use the same burn/treasury strategy used for regular fees
let (_, to_treasury) = tip.ration(80, 20);
<pallet_treasury::Pallet<R> as OnUnbalanced<_>>::on_unbalanced(to_treasury);
ResolveTo::<TreasuryAccountId<R>, pallet_balances::Pallet<R>>::on_unbalanced(
to_treasury,
);
}
}
}

// this is called from pallet_evm for Ethereum-based transactions
// (technically, it calls on_unbalanced, which calls this when non-zero)
fn on_nonzero_unbalanced(amount: NegativeImbalance<R>) {
// Balances pallet automatically burns dropped Negative Imbalances by decreasing
fn on_nonzero_unbalanced(amount: Credit<R::AccountId, pallet_balances::Pallet<R>>) {
// Balances pallet automatically burns dropped Credits by decreasing
// total_supply accordingly
let (_, to_treasury) = amount.ration(80, 20);
<pallet_treasury::Pallet<R> as OnUnbalanced<_>>::on_unbalanced(to_treasury);
ResolveTo::<TreasuryAccountId<R>, pallet_balances::Pallet<R>>::on_unbalanced(to_treasury);
}
}

Expand Down Expand Up @@ -364,7 +369,7 @@ impl WeightToFeePolynomial for LengthToFee {

impl pallet_transaction_payment::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type OnChargeTransaction = CurrencyAdapter<Balances, DealWithFees<Runtime>>;
type OnChargeTransaction = FungibleAdapter<Balances, DealWithFees<Runtime>>;
type OperationalFeeMultiplier = ConstU8<5>;
type WeightToFee = ConstantMultiplier<Balance, ConstU128<{ currency::WEIGHT_FEE }>>;
type LengthToFee = LengthToFee;
Expand Down
58 changes: 33 additions & 25 deletions runtime/moonbeam/tests/integration_test.rs
Expand Up @@ -2618,32 +2618,40 @@ fn removed_precompiles() {
fn deal_with_fees_handles_tip() {
use frame_support::traits::OnUnbalanced;
use moonbeam_runtime::{DealWithFees, Treasury};
use pallet_balances::NegativeImbalance;

ExtBuilder::default()
.with_balances(vec![(AccountId::from(ALICE), 10_000)])
.build()
.execute_with(|| {
// Alice has 10_000, which makes inital supply 10_000.
// drop()ing the NegativeImbalance below will cause the total_supply to be decreased
// incorrectly (since there was never a withdraw to begin with), which in this case has
// the desired effect of showing that currency was burned.
let total_supply_before = Balances::total_issuance();
assert_eq!(total_supply_before, 10_000);

let fees_then_tips = vec![
NegativeImbalance::<moonbeam_runtime::Runtime>::new(100),
NegativeImbalance::<moonbeam_runtime::Runtime>::new(1_000),
];
DealWithFees::on_unbalanceds(fees_then_tips.into_iter());

// treasury should have received 20%
assert_eq!(Balances::free_balance(&Treasury::account_id()), 220);

// verify 80% burned
let total_supply_after = Balances::total_issuance();
assert_eq!(total_supply_before - total_supply_after, 880);
});
ExtBuilder::default().build().execute_with(|| {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at this I do wonder if there's an alternative for duplicating tests like these

// This test checks the functionality of the `DealWithFees` trait implementation in the runtime.
// It simulates a scenario where a fee and a tip are issued to an account and ensures that the
// treasury receives the correct amount (20% of the total), and the rest is burned (80%).
//
// The test follows these steps:
// 1. It issues a fee of 100 and a tip of 1000.
// 2. It checks the total supply before the fee and tip are dealt with, which should be 1_100.
// 3. It checks that the treasury's balance is initially 0.
// 4. It calls `DealWithFees::on_unbalanceds` with the fee and tip.
// 5. It checks that the treasury's balance is now 220 (20% of the fee and tip).
// 6. It checks that the total supply has decreased by 880 (80% of the fee and tip), indicating
// that this amount was burned.
let fee = <pallet_balances::Pallet<Runtime> as frame_support::traits::fungible::Balanced<
AccountId,
>>::issue(100);
let tip = <pallet_balances::Pallet<Runtime> as frame_support::traits::fungible::Balanced<
AccountId,
>>::issue(1000);

let total_supply_before = Balances::total_issuance();
assert_eq!(total_supply_before, 1_100);
assert_eq!(Balances::free_balance(&Treasury::account_id()), 0);

DealWithFees::on_unbalanceds(vec![fee, tip].into_iter());

// treasury should have received 20%
assert_eq!(Balances::free_balance(&Treasury::account_id()), 220);

// verify 80% burned
let total_supply_after = Balances::total_issuance();
assert_eq!(total_supply_before - total_supply_after, 880);
});
}

#[test]
Expand Down