Skip to content

Commit

Permalink
feat(vara,gear-bank): Split gas and fees to author/treasury (#3652)
Browse files Browse the repository at this point in the history
Co-authored-by: Dmitry Novikov <novikov.dm.al@gmail.com>
  • Loading branch information
ukint-vs and breathx authored Aug 22, 2024
1 parent f7eb906 commit 854467b
Show file tree
Hide file tree
Showing 17 changed files with 166 additions and 23 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

37 changes: 31 additions & 6 deletions pallets/gear-bank/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ macro_rules! impl_config {
type Currency = Balances;
type BankAddress = BankAddress;
type GasMultiplier = GasMultiplier;
type SplitGasFeeRatio = SplitGasFeeRatio;
type SplitTxFeeRatio = SplitTxFeeRatio;
}
};
}
Expand Down Expand Up @@ -78,7 +80,7 @@ pub mod pallet {
use pallet_authorship::Pallet as Authorship;
use parity_scale_codec::{Decode, Encode, EncodeLike, MaxEncodedLen};
use scale_info::TypeInfo;
use sp_runtime::traits::Zero;
use sp_runtime::{traits::Zero, Perbill};

// Funds pallet struct itself.
#[pallet::pallet]
Expand All @@ -100,6 +102,11 @@ pub mod pallet {
#[pallet::constant]
/// Gas price converter.
type GasMultiplier: Get<GasMultiplier<Self>>;

type SplitGasFeeRatio: Get<Option<(Perbill, AccountIdOf<Self>)>>;

/// The ratio of how much of the tx fees goes to the treasury
type SplitTxFeeRatio: Get<Option<u32>>;
}

// Funds pallets error.
Expand Down Expand Up @@ -218,10 +225,28 @@ pub mod pallet {
while let Some((account_id, value)) = OnFinalizeTransfers::<T>::drain().next() {
total = total.saturating_add(value);

if let Err(e) = Self::withdraw(&account_id, value) {
log::error!(
"Block #{bn:?} ended with unreachable error while performing on-finalize transfer to {account_id:?}: {e:?}"
);
if let Some((gas_split, split_dest)) = T::SplitGasFeeRatio::get() {
// split value by `SplitGasFeeRatio`.
let to_split = gas_split.mul_floor(value);
let to_user = value - to_split;

// Withdraw value to user.
if let Err(e) = Self::withdraw(&account_id, to_user) {
log::error!(
"Block #{bn:?} ended with unreachable error while performing on-finalize transfer to {account_id:?}: {e:?}"
);
}

// Withdraw value to `SplitGasFeeRatio` destination.
if let Err(e) = Self::withdraw(&split_dest, to_split) {
log::error!(
"Block #{bn:?} ended with unreachable error while performing on-finalize transfer to {account_id:?}: {e:?}"
);
}
} else {
let _ = Self::withdraw(&account_id, value).map_err(|e| log::error!(
"Block #{bn:?} ended with unreachable error while performing on-finalize transfer to {account_id:?}: {e:?}"
));
}
}

Expand Down Expand Up @@ -541,7 +566,7 @@ pub mod pallet {
let err_msg = format!(
"pallet_gear_bank::withdraw_value: withdraw failed. \
Receiver - {account_id:?}, value - {value:?}, receiver reducible balance - {receiver_balance:?}, \
bank reducible balance - {bank_balance:?}, unused value - {unused_value:?},
bank reducible balance - {bank_balance:?}, unused value - {unused_value:?},
on finalize value - {on_finalize_value:?}. \
Got error - {e:?}"
);
Expand Down
8 changes: 6 additions & 2 deletions pallets/gear-bank/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,13 @@ use frame_support::{
construct_runtime, parameter_types,
traits::{ConstU32, FindAuthor},
weights::constants::RocksDbWeight,
PalletId,
};
use primitive_types::H256;
use sp_io::TestExternalities;
use sp_runtime::{
traits::{BlakeTwo256, IdentityLookup},
BuildStorage,
traits::{AccountIdConversion, BlakeTwo256, IdentityLookup},
BuildStorage, Perbill,
};

pub type AccountId = u8;
Expand Down Expand Up @@ -64,6 +65,9 @@ parameter_types! {
pub const GasMultiplier: common::GasMultiplier<Balance, u64> = common::GasMultiplier::ValuePerGas(VALUE_PER_GAS);
pub const BlockHashCount: BlockNumber = 250;
pub const ExistentialDeposit: Balance = EXISTENTIAL_DEPOSIT;
// TODO: Issue #4058
pub SplitGasFeeRatio: Option<(Perbill, AccountId)> = Some((Perbill::from_percent(50), PalletId(*b"py/trsry").into_account_truncating()));
pub SplitTxFeeRatio: Option<u32> = None;
}

construct_runtime!(
Expand Down
11 changes: 9 additions & 2 deletions pallets/gear-bank/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -499,7 +499,9 @@ fn spend_gas_all_balance_validator_account_deleted() {

assert_bank_balance(0, 0);

assert_balance(&BLOCK_AUTHOR, gas_price(GAS_AMOUNT));
// mul ceil GAS_AMOUNT because of gas fee split.
let (gas_split, _) = SplitGasFeeRatio::get().unwrap();
assert_balance(&BLOCK_AUTHOR, gas_split.mul_ceil(gas_price(GAS_AMOUNT)));

assert_alice_dec(gas_price(GAS_AMOUNT));
assert_gas_value(&ALICE, 0, 0);
Expand Down Expand Up @@ -1636,7 +1638,12 @@ mod utils {
// Asserts block author balance inc.
#[track_caller]
pub fn assert_block_author_inc(diff: Balance) {
assert_balance(&BLOCK_AUTHOR, EXISTENTIAL_DEPOSIT + diff)
// mul ceil diff because of gas fee split.
let (gas_split, _) = SplitGasFeeRatio::get().unwrap();
assert_balance(
&BLOCK_AUTHOR,
EXISTENTIAL_DEPOSIT + gas_split.mul_ceil(diff),
)
}

// Asserts Charlie balance inc.
Expand Down
2 changes: 2 additions & 0 deletions pallets/gear-builtin/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,8 @@ parameter_types! {
pub const PerformanceMultiplier: u32 = 100;
pub const BankAddress: AccountId = 15082001;
pub const GasMultiplier: common::GasMultiplier<Balance, u64> = common::GasMultiplier::ValuePerGas(25);
pub SplitGasFeeRatio: Option<(Perbill, AccountId)> = None;
pub SplitTxFeeRatio: Option<u32> = None;
}

pallet_gear_bank::impl_config!(Test);
Expand Down
2 changes: 2 additions & 0 deletions pallets/gear-builtin/src/tests/bad_builtin_ids.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ parameter_types! {
pub const PerformanceMultiplier: u32 = 100;
pub const BankAddress: AccountId = 15082001;
pub const GasMultiplier: common::GasMultiplier<Balance, u64> = common::GasMultiplier::ValuePerGas(25);
pub SplitGasFeeRatio: Option<(Perbill, AccountId)> = None;
pub SplitTxFeeRatio: Option<u32> = None;
}

pallet_gear_bank::impl_config!(Test);
Expand Down
2 changes: 2 additions & 0 deletions pallets/gear-builtin/src/tests/staking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -704,6 +704,8 @@ mod util {
pub const PerformanceMultiplier: u32 = 100;
pub const BankAddress: AccountId = 15082001;
pub const GasMultiplier: common::GasMultiplier<Balance, u64> = common::GasMultiplier::ValuePerGas(25);
pub SplitGasFeeRatio: Option<(Perbill, AccountId)> = None;
pub SplitTxFeeRatio: Option<u32> = None;
}

pub struct TestSessionHandler;
Expand Down
4 changes: 3 additions & 1 deletion pallets/gear-debug/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ use primitive_types::H256;
use sp_core::ConstBool;
use sp_runtime::{
traits::{BlakeTwo256, ConstU64, IdentityLookup},
BuildStorage,
BuildStorage, Perbill,
};
use sp_std::convert::{TryFrom, TryInto};

Expand Down Expand Up @@ -70,6 +70,8 @@ parameter_types! {
pub ResumeSessionDuration: BlockNumber = 1_000;
pub const BankAddress: AccountId = 15082001;
pub const GasMultiplier: common::GasMultiplier<Balance, u64> = common::GasMultiplier::ValuePerGas(25);
pub SplitGasFeeRatio: Option<(Perbill, AccountId)> = None;
pub SplitTxFeeRatio: Option<u32> = None;
pub ReserveThreshold: BlockNumber = 1;
}

Expand Down
4 changes: 3 additions & 1 deletion pallets/gear-eth-bridge/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ use sp_core::{ed25519::Public, H256};
use sp_runtime::{
impl_opaque_keys,
traits::{BlakeTwo256, IdentityLookup},
BuildStorage,
BuildStorage, Perbill,
};
use sp_std::convert::{TryFrom, TryInto};

Expand Down Expand Up @@ -160,6 +160,8 @@ parameter_types! {
pub const PerformanceMultiplier: u32 = 100;
pub const BankAddress: AccountId = 15082001;
pub const GasMultiplier: common::GasMultiplier<Balance, u64> = common::GasMultiplier::ValuePerGas(25);
pub SplitGasFeeRatio: Option<(Perbill, AccountId)> = None;
pub SplitTxFeeRatio: Option<u32> = None;
}

pallet_gear_bank::impl_config!(Test);
Expand Down
4 changes: 3 additions & 1 deletion pallets/gear-scheduler/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ use pallet_gear::GasAllowanceOf;
use sp_core::{ConstBool, H256};
use sp_runtime::{
traits::{BlakeTwo256, IdentityLookup},
BuildStorage,
BuildStorage, Perbill,
};

use sp_std::convert::{TryFrom, TryInto};
Expand Down Expand Up @@ -94,6 +94,8 @@ parameter_types! {
pub ResumeSessionDuration: BlockNumber = 1_000;
pub const BankAddress: AccountId = 15082001;
pub const GasMultiplier: common::GasMultiplier<Balance, u64> = common::GasMultiplier::ValuePerGas(25);
pub SplitGasFeeRatio: Option<(Perbill, AccountId)> = None;
pub SplitTxFeeRatio: Option<u32> = None;
}

// Build genesis storage according to the mock runtime.
Expand Down
4 changes: 3 additions & 1 deletion pallets/gear/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ use frame_system::{self as system, limits::BlockWeights, mocking, pallet_prelude
use sp_core::{ConstU8, H256};
use sp_runtime::{
traits::{BlakeTwo256, IdentityLookup},
BuildStorage,
BuildStorage, Perbill,
};
use sp_std::{
cell::RefCell,
Expand Down Expand Up @@ -173,6 +173,8 @@ impl Drop for DynamicScheduleReset {
parameter_types! {
pub const BankAddress: AccountId = 15082001;
pub const GasMultiplier: common::GasMultiplier<Balance, u64> = common::GasMultiplier::ValuePerGas(1);
pub SplitGasFeeRatio: Option<(Perbill, AccountId)> = None;
pub SplitTxFeeRatio: Option<u32> = None;
pub const MinVoucherDuration: BlockNumber = 5;
pub const MaxVoucherDuration: BlockNumber = 100_000_000;
}
Expand Down
4 changes: 3 additions & 1 deletion pallets/payment/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ use primitive_types::H256;
use sp_runtime::{
testing::TestXt,
traits::{BlakeTwo256, ConstBool, ConstU64, IdentityLookup},
BuildStorage,
BuildStorage, Perbill,
};
use sp_std::{
convert::{TryFrom, TryInto},
Expand Down Expand Up @@ -119,6 +119,8 @@ parameter_types! {
pub ResumeSessionDuration: BlockNumber = 1_000;
pub const BankAddress: AccountId = 15082001;
pub const GasMultiplier: common::GasMultiplier<Balance, u64> = common::GasMultiplier::ValuePerGas(25);
pub SplitGasFeeRatio: Option<(Perbill, AccountId)> = None;
pub SplitTxFeeRatio: Option<u32> = None;
}

type NegativeImbalance = <Balances as Currency<u64>>::NegativeImbalance;
Expand Down
1 change: 1 addition & 0 deletions runtime/common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ frame-system.workspace = true
pallet-authorship.workspace = true
pallet-balances.workspace = true
pallet-session.workspace = true
pallet-treasury.workspace = true
sp-runtime.workspace = true
sp-std.workspace = true

Expand Down
6 changes: 6 additions & 0 deletions runtime/common/src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,9 @@ pub const RENT_FREE_PERIOD_MONTH_FACTOR: BlockNumber = 6;
/// The amount of blocks on which tasks of pausing program shifted
/// in a case of disabled program rent logic, represented as a factor of weeks.
pub const RENT_DISABLED_DELTA_WEEK_FACTOR: BlockNumber = 1;

/// The percentage of the transaction fee that will go to the treasury
pub const SPLIT_TX_FEE_PERCENT: u32 = 0;

/// The percentage of the gas fee that will go to the specified destination
pub const SPLIT_GAS_PERCENT: u32 = 0;
50 changes: 42 additions & 8 deletions runtime/common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,12 @@ mod apis;
pub mod constants;
pub mod weights;

use sp_runtime::traits::Get;

use frame_support::{
pallet_prelude::DispatchClass,
parameter_types,
traits::{Currency, OnUnbalanced},
traits::{Currency, Imbalance, OnUnbalanced},
weights::{
constants::{BlockExecutionWeight, ExtrinsicBaseWeight},
Weight,
Expand Down Expand Up @@ -85,22 +87,54 @@ pub type NegativeImbalance<T> = <pallet_balances::Pallet<T> as Currency<
<T as frame_system::Config>::AccountId,
>>::NegativeImbalance;

/// Logic for the author to get a portion of fees.
pub struct ToAuthor<R>(sp_std::marker::PhantomData<R>);
impl<R> OnUnbalanced<NegativeImbalance<R>> for ToAuthor<R>
where
R: pallet_balances::Config + pallet_authorship::Config,
<R as frame_system::Config>::AccountId: From<AccountId>,
<R as frame_system::Config>::AccountId: Into<AccountId>,
{
fn on_nonzero_unbalanced(amount: NegativeImbalance<R>) {
if let Some(author) = <pallet_authorship::Pallet<R>>::author() {
<pallet_balances::Pallet<R>>::resolve_creating(&author, amount);
}
}
}

pub struct DealWithFees<R>(sp_std::marker::PhantomData<R>);
impl<R> OnUnbalanced<NegativeImbalance<R>> for DealWithFees<R>
where
R: pallet_balances::Config + pallet_authorship::Config,
R: pallet_balances::Config
+ pallet_treasury::Config
+ pallet_authorship::Config
+ pallet_gear_bank::Config,
pallet_treasury::Pallet<R>: OnUnbalanced<NegativeImbalance<R>>,
<R as frame_system::Config>::AccountId: From<AccountId>,
<R as frame_system::Config>::AccountId: Into<AccountId>,
{
fn on_unbalanceds<B>(mut fees_then_tips: impl Iterator<Item = NegativeImbalance<R>>) {
use pallet_treasury::Pallet as Treasury;

if let Some(fees) = fees_then_tips.next() {
if let Some(author) = <pallet_authorship::Pallet<R>>::author() {
<pallet_balances::Pallet<R>>::resolve_creating(&author, fees);
}
if let Some(tips) = fees_then_tips.next() {
if let Some(author) = <pallet_authorship::Pallet<R>>::author() {
<pallet_balances::Pallet<R>>::resolve_creating(&author, tips);
let split_tx_fee_ratio = R::SplitTxFeeRatio::get();
if let Some(split_tx_fee_ratio) = split_tx_fee_ratio {
// for fees, SplitTxFeeRatio to treasury else to author
let (mut to_author, to_treasury) =
fees.ration(100 - split_tx_fee_ratio, split_tx_fee_ratio);
if let Some(tips) = fees_then_tips.next() {
// for tips, if any, 100% to author
tips.merge_into(&mut to_author);
}
<Treasury<R> as OnUnbalanced<_>>::on_unbalanced(to_treasury);
<ToAuthor<R> as OnUnbalanced<_>>::on_unbalanced(to_author);
} else {
let mut to_author = fees;
if let Some(tips) = fees_then_tips.next() {
// for tips, if any, 100% to author
tips.merge_into(&mut to_author);
}
<ToAuthor<R> as OnUnbalanced<_>>::on_unbalanced(to_author);
}
}
}
Expand Down
45 changes: 45 additions & 0 deletions runtime/vara/src/integration_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -861,3 +861,48 @@ fn fungible_api_works() {
);
});
}

#[test]
fn test_fees_and_tip_split() {
init_logger();

let alice = AccountKeyring::Alice;
let charlie = AccountKeyring::Charlie;

ExtBuilder::default()
.initial_authorities(vec![(
alice.into(),
charlie.into(),
alice.public(),
ed25519::Pair::from_string("//Alice", None)
.unwrap()
.public(),
alice.public(),
alice.public(),
)])
.stash(STASH)
.endowment(ENDOWMENT)
.endowed_accounts(vec![])
.root(alice.into())
.build()
.execute_with(|| {
let fee = Balances::issue(10);
let tip = Balances::issue(20);

assert_eq!(
Balances::free_balance(Treasury::account_id()),
EXISTENTIAL_DEPOSIT
);
assert_eq!(Balances::free_balance(alice.to_account_id()), STASH);

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

// Author gets 100% of the tip and 100% of the fee = 30
assert_eq!(Balances::free_balance(alice.to_account_id()), STASH + 30);
// Treasury gets 0% of the fee
assert_eq!(
Balances::free_balance(Treasury::account_id()),
EXISTENTIAL_DEPOSIT
);
});
}
Loading

0 comments on commit 854467b

Please sign in to comment.