Skip to content

Commit

Permalink
feat(emission0): general emission fees
Browse files Browse the repository at this point in the history
  • Loading branch information
saiintbrisson committed Dec 27, 2024
1 parent 8fc6bb7 commit 10dcaf0
Show file tree
Hide file tree
Showing 13 changed files with 111 additions and 45 deletions.
4 changes: 4 additions & 0 deletions Cargo.lock

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

13 changes: 12 additions & 1 deletion pallets/emission0/src/distribute.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use pallet_governance_api::GovernanceApi;
use pallet_torus0_api::Torus0Api;
use polkadot_sdk::{
frame_support::{
Expand Down Expand Up @@ -72,7 +73,10 @@ pub fn get_total_emission_per_block<T: Config>() -> BalanceOf<T> {

let interval = T::HalvingInterval::get();
let halving_count = total_issuance.saturating_div(interval.get());
T::BlockEmission::get() >> halving_count
let emission = T::BlockEmission::get() >> halving_count;

let not_recycled = Percent::one() - crate::EmissionRecyclingPercentage::<T>::get();
not_recycled.mul_floor(emission)
}

#[doc(hidden)]
Expand Down Expand Up @@ -251,6 +255,13 @@ impl<T: Config> ConsensusMemberInput<T> {
fn linear_rewards<T: Config>(
mut emission: <T::Currency as Currency<T::AccountId>>::NegativeImbalance,
) -> <T::Currency as Currency<T::AccountId>>::NegativeImbalance {
let treasury_fee = <T::Governance>::treasury_emission_fee();
if !treasury_fee.is_zero() {
let treasury_fee = treasury_fee.mul_floor(emission.peek());
let treasury_fee = emission.extract(treasury_fee);
T::Currency::resolve_creating(&<T::Governance>::dao_treasury_address(), treasury_fee);
}

let inputs = ConsensusMemberInput::<T>::all_members();

let id_to_idx: BTreeMap<_, _> = inputs
Expand Down
11 changes: 11 additions & 0 deletions pallets/emission0/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use polkadot_sdk::frame_system;
use polkadot_sdk::frame_system::pallet_prelude::OriginFor;
use polkadot_sdk::polkadot_sdk_frame::prelude::BlockNumberFor;
use polkadot_sdk::polkadot_sdk_frame::{self as frame, traits::Currency};
use polkadot_sdk::sp_runtime::Percent;

#[doc(hidden)]
pub mod distribute;
Expand All @@ -21,6 +22,7 @@ pub mod pallet {
use core::num::NonZeroU128;

use frame::prelude::BlockNumberFor;
use pallet_governance_api::GovernanceApi;
use pallet_torus0_api::Torus0Api;
use polkadot_sdk::sp_std;

Expand All @@ -45,6 +47,10 @@ pub mod pallet {
#[pallet::storage]
pub type MinStakePerWeight<T> = StorageValue<_, BalanceOf<T>, ValueQuery>;

#[pallet::storage]
pub type EmissionRecyclingPercentage<T: Config> =
StorageValue<_, Percent, ValueQuery, T::DefaultEmissionRecyclingPercentage>;

#[pallet::storage]
pub type PendingEmission<T: Config> = StorageValue<_, BalanceOf<T>, ValueQuery>;

Expand All @@ -71,13 +77,18 @@ pub mod pallet {
#[pallet::constant]
type DefaultMaxAllowedWeights: Get<u16>;

#[pallet::constant]
type DefaultEmissionRecyclingPercentage: Get<Percent>;

type Currency: Currency<Self::AccountId, Balance = u128> + Send + Sync;

type Torus: Torus0Api<
Self::AccountId,
<Self::Currency as Currency<Self::AccountId>>::Balance,
<Self::Currency as Currency<Self::AccountId>>::NegativeImbalance,
>;

type Governance: GovernanceApi<Self::AccountId>;
}

#[pallet::pallet]
Expand Down
41 changes: 27 additions & 14 deletions pallets/emission0/tests/distribution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ use std::array::from_fn;

use pallet_emission0::{
distribute::{get_total_emission_per_block, ConsensusMemberInput},
Config, ConsensusMember, ConsensusMembers, PendingEmission, WeightControlDelegation,
Config, ConsensusMember, ConsensusMembers, EmissionRecyclingPercentage, PendingEmission,
WeightControlDelegation,
};
use polkadot_sdk::{
pallet_balances,
Expand All @@ -12,6 +13,7 @@ use polkadot_sdk::{
use substrate_fixed::{traits::ToFixed, types::I96F32};
use test_utils::{
add_balance, add_stake, get_balance,
pallet_governance::TreasuryEmissionFee,
pallet_torus0::{fee::ValidatorFee, Fee, MaxAllowedValidators, MinAllowedStake, StakedBy},
register_empty_agent, step_block, Test,
};
Expand All @@ -23,20 +25,26 @@ fn total_emission_per_block_does_halving() {
let halving_interval = <<Test as Config>::HalvingInterval as Get<u128>>::get();
let max_supply = <<Test as Config>::MaxSupply as Get<u128>>::get();

let recycling_percentage = EmissionRecyclingPercentage::<Test>::get();
let halving_emission = |halving: u128| {
let block_emission = block_emission >> halving;
block_emission - recycling_percentage.mul_ceil(block_emission)
};

let emissions = get_total_emission_per_block::<Test>();
assert_eq!(emissions, block_emission);
assert_eq!(emissions, halving_emission(0));

pallet_balances::TotalIssuance::<Test>::set(halving_interval - 1);
let emissions = get_total_emission_per_block::<Test>();
assert_eq!(emissions, block_emission);
assert_eq!(emissions, halving_emission(0));

pallet_balances::TotalIssuance::<Test>::set(halving_interval);
let emissions = get_total_emission_per_block::<Test>();
assert_eq!(emissions, block_emission >> 1);
assert_eq!(emissions, halving_emission(1));

pallet_balances::TotalIssuance::<Test>::set(halving_interval * 2);
let emissions = get_total_emission_per_block::<Test>();
assert_eq!(emissions, block_emission >> 2);
assert_eq!(emissions, halving_emission(2));

pallet_balances::TotalIssuance::<Test>::set(max_supply);
let emissions = get_total_emission_per_block::<Test>();
Expand All @@ -47,22 +55,23 @@ fn total_emission_per_block_does_halving() {
#[test]
fn pending_emission_accumulates_and_returns_when_network_is_empty() {
test_utils::new_test_ext().execute_with(|| {
assert_eq!(PendingEmission::<Test>::get(), 0);
EmissionRecyclingPercentage::<Test>::set(Percent::zero());

step_block(1);
assert_eq!(PendingEmission::<Test>::get(), 0);

let emissions = get_total_emission_per_block::<Test>();
assert_eq!(PendingEmission::<Test>::get(), emissions);

step_block(1);
assert_eq!(PendingEmission::<Test>::get(), emissions);

let emissions = get_total_emission_per_block::<Test>();
step_block(1);
assert_eq!(PendingEmission::<Test>::get(), emissions * 2);

step_block(98);
let after_treasury_fee = Percent::one() - TreasuryEmissionFee::<Test>::get();
let emissions = after_treasury_fee.mul_floor(emissions * 100);

let emissions = get_total_emission_per_block::<Test>();
assert_eq!(PendingEmission::<Test>::get(), emissions * 100);
step_block(98);
assert_eq!(PendingEmission::<Test>::get(), emissions);
});
}

Expand Down Expand Up @@ -317,6 +326,9 @@ fn deregister_old_agents_and_registers_new() {
#[test]
fn pays_dividends_and_incentives() {
test_utils::new_test_ext().execute_with(|| {
EmissionRecyclingPercentage::<Test>::set(Percent::zero());
TreasuryEmissionFee::<Test>::set(Percent::zero());

let min_allowed_stake = MinAllowedStake::<Test>::get();

let mut member = ConsensusMember::<Test>::default();
Expand Down Expand Up @@ -361,6 +373,9 @@ fn pays_dividends_and_incentives() {
#[test]
fn pays_dividends_to_stakers() {
test_utils::new_test_ext().execute_with(|| {
EmissionRecyclingPercentage::<Test>::set(Percent::zero());
TreasuryEmissionFee::<Test>::set(Percent::zero());

let min_allowed_stake = 1;
MinAllowedStake::<Test>::set(min_allowed_stake);

Expand Down Expand Up @@ -442,5 +457,3 @@ fn pays_dividends_to_stakers() {
assert_eq!(sum, get_total_emission_per_block::<Test>() * 100);
});
}

// TODO: test staking and weight control delegation
7 changes: 5 additions & 2 deletions pallets/governance/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,15 @@ try-runtime = [

[dependencies]
codec = { workspace = true, features = ["derive"] }
pallet-torus0 = { workspace = true }
pallet-emission0 = { workspace = true }
polkadot-sdk = { workspace = true, features = [
"experimental",
"runtime",
"pallet-sudo",
] }
scale-info = { workspace = true, features = ["derive"] }
substrate-fixed = { workspace = true }

pallet-torus0 = { workspace = true }
pallet-emission0 = { workspace = true }

pallet-governance-api.workspace = true
7 changes: 7 additions & 0 deletions pallets/governance/api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,11 @@ license = "MIT-0"
authors.workspace = true
edition.workspace = true

[features]
default = ["std"]
std = ["polkadot-sdk/std"]
runtime-benchmarks = ["polkadot-sdk/runtime-benchmarks"]
try-runtime = ["polkadot-sdk/try-runtime"]

[dependencies]
polkadot-sdk = { workspace = true, features = ["sp-runtime"] }
6 changes: 5 additions & 1 deletion pallets/governance/api/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
#![no_std]

use polkadot_sdk::sp_runtime::Percent;

pub trait GovernanceApi<AccountId> {
fn get_dao_treasury_address() -> AccountId;
fn dao_treasury_address() -> AccountId;

fn treasury_emission_fee() -> Percent;

fn is_whitelisted(key: &AccountId) -> bool;
}
16 changes: 15 additions & 1 deletion pallets/governance/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ pub mod pallet {
pub type Curators<T: Config> = StorageMap<_, Identity, AccountIdOf<T>, ()>;

#[pallet::storage]
pub type TreasuryEmissionFee<T> =
pub type TreasuryEmissionFee<T: Config> =
StorageValue<_, Percent, ValueQuery, T::DefaultTreasuryEmissionFee>;

#[pallet::config(with_default)]
Expand Down Expand Up @@ -374,3 +374,17 @@ pub mod pallet {
InvalidMinWeightControlFee,
}
}

impl<T: Config> pallet_governance_api::GovernanceApi<T::AccountId> for Pallet<T> {
fn dao_treasury_address() -> T::AccountId {
DaoTreasuryAddress::<T>::get()
}

fn treasury_emission_fee() -> Percent {
TreasuryEmissionFee::<T>::get()
}

fn is_whitelisted(key: &T::AccountId) -> bool {
whitelist::is_whitelisted::<T>(key)
}
}
3 changes: 2 additions & 1 deletion pallets/torus0/src/agent.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::AccountIdOf;
use codec::{Decode, Encode, MaxEncodedLen};
use pallet_governance_api::GovernanceApi;
use polkadot_sdk::frame_election_provider_support::Get;
use polkadot_sdk::sp_runtime::DispatchError;
use polkadot_sdk::{
Expand Down Expand Up @@ -53,7 +54,7 @@ pub fn register<T: crate::Config>(
);

ensure!(
<T as pallet_governance_api::GovernanceApi<T::AccountId>>::is_whitelisted(&agent_key),
<T::Governance>::is_whitelisted(&agent_key),
crate::Error::<T>::AgentKeyNotWhitelisted
);

Expand Down
7 changes: 4 additions & 3 deletions pallets/torus0/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ use scale_info::prelude::vec::Vec;
pub mod pallet {

use frame::prelude::BlockNumberFor;
use pallet_governance_api::GovernanceApi;

use super::*;

Expand Down Expand Up @@ -124,9 +125,7 @@ pub mod pallet {
}

#[pallet::config(with_default)]
pub trait Config:
polkadot_sdk::frame_system::Config + pallet_governance_api::GovernanceApi<Self::AccountId>
{
pub trait Config: polkadot_sdk::frame_system::Config {
#[pallet::constant]
type DefaultMaxAllowedValidators: Get<u16>;

Expand Down Expand Up @@ -202,6 +201,8 @@ pub mod pallet {
+ IsType<<Self as polkadot_sdk::frame_system::Config>::RuntimeEvent>;

type Currency: Currency<Self::AccountId, Balance = u128> + Send + Sync;

type Governance: GovernanceApi<Self::AccountId>;
}

#[pallet::pallet]
Expand Down
10 changes: 0 additions & 10 deletions runtime/src/apis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -463,13 +463,3 @@ impl_runtime_apis! {
}
}
}

impl pallet_governance_api::GovernanceApi<AccountId> for Runtime {
fn get_dao_treasury_address() -> AccountId {
pallet_governance::DaoTreasuryAddress::<Runtime>::get()
}

fn is_whitelisted(key: &AccountId) -> bool {
pallet_governance::whitelist::is_whitelisted::<Runtime>(key)
}
}
9 changes: 8 additions & 1 deletion runtime/src/configs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -335,11 +335,13 @@ impl pallet_torus0::Config for Runtime {
type RuntimeEvent = RuntimeEvent;

type Currency = Balances;

type Governance = Governance;
}

parameter_types! {
pub const GovernancePalletId: PalletId = PalletId(*b"torusgov");
pub const DefaultTreasuryEmissionFee: Percent = Percent::from_percent(10);
pub const DefaultTreasuryEmissionFee: Percent = Percent::from_percent(20);
}

impl pallet_governance::Config for Runtime {
Expand All @@ -363,6 +365,7 @@ impl pallet_governance::Config for Runtime {
parameter_types! {
pub HalvingInterval: NonZeroU128 = NonZeroU128::new(250_000_000 * 10u128.pow(TOKEN_DECIMALS)).unwrap();
pub MaxSupply: NonZeroU128 = NonZeroU128::new(1_000_000_000 * 10u128.pow(TOKEN_DECIMALS)).unwrap();
pub const DefaultEmissionRecyclingPercentage: Percent = Percent::from_percent(70);
}

impl pallet_emission0::Config for Runtime {
Expand All @@ -378,9 +381,13 @@ impl pallet_emission0::Config for Runtime {

type DefaultMaxAllowedWeights = ConstU16<420>;

type DefaultEmissionRecyclingPercentage = DefaultEmissionRecyclingPercentage;

type Currency = Balances;

type Torus = Torus0;

type Governance = Governance;
}

// type DefaultMinAllowedWeights = ConstU16<1>;
Expand Down
Loading

0 comments on commit 10dcaf0

Please sign in to comment.