Skip to content

Commit

Permalink
fix(emission0): compute weight control fee first (#27)
Browse files Browse the repository at this point in the history
Modifies the emission code to compute the weight control fee before
distributing emissions to stakers, ensuring that the dividends are
distributed to the weight-controller stakers as well.
  • Loading branch information
saiintbrisson authored Dec 28, 2024
1 parent 455e19b commit b085581
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 14 deletions.
35 changes: 27 additions & 8 deletions pallets/emission0/src/distribute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ fn linear_rewards<T: Config>(
};

let Emissions {
dividends,
mut dividends,
incentives,
normalized_emissions,
} = compute_emissions::<T>(
Expand All @@ -324,6 +324,32 @@ fn linear_rewards<T: Config>(

let pruning_scores = math::vec_max_upscale_to_u16(&normalized_emissions);

for (idx, input) in inputs.values().enumerate() {
let Some(delegating_to) = &input.delegating_to else {
continue;
};

let Some(dividend) = dividends
.get_mut(idx)
.filter(|dividend| dividend.peek() > 0)
else {
continue;
};

let control_fee = <T::Torus>::weight_control_fee(delegating_to);
let control_fee = control_fee.mul_floor(dividend.peek());
let stake = dividend.extract(control_fee);

if let Some(delegated_dividend) = id_to_idx
.get(delegating_to)
.and_then(|idx| dividends.get_mut(*idx))
{
delegated_dividend.subsume(stake);
} else {
T::Currency::resolve_creating(delegating_to, stake);
}
}

for (((input, incentive), mut dividend), pruning_score) in inputs
.values()
.zip(incentives)
Expand All @@ -338,13 +364,6 @@ fn linear_rewards<T: Config>(
};

if dividend.peek() != 0 {
if let Some(delegating_to) = &input.delegating_to {
let control_fee = <T::Torus>::weight_control_fee(delegating_to);
let control_fee = control_fee.mul_floor(dividend.peek());
let stake = dividend.extract(control_fee);
T::Currency::resolve_creating(delegating_to, stake);
}

let fixed_dividend = dividend.peek();

let stakers = input.normalized_stakers();
Expand Down
73 changes: 69 additions & 4 deletions pallets/emission0/tests/distribution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@ use polkadot_sdk::{
};
use substrate_fixed::{traits::ToFixed, types::I96F32};
use test_utils::{
add_balance, add_stake, get_balance,
add_balance, add_stake, get_balance, get_origin,
pallet_governance::TreasuryEmissionFee,
pallet_torus0::{fee::ValidatorFee, Fee, MaxAllowedValidators, MinAllowedStake, StakedBy},
pallet_torus0::{
fee::ValidatorFee, Fee, FeeConstraints, MaxAllowedValidators, MinAllowedStake, StakedBy,
},
register_empty_agent, step_block, Test,
};

Expand Down Expand Up @@ -348,8 +350,8 @@ fn pays_dividends_and_incentives() {

step_block(100);

let mut sum = 0;
let total_emission = get_total_emission_per_block::<Test>() * 100;
let mut sum = 0;

let stake = StakedBy::<Test>::get(0, 0).unwrap_or_default();
assert_eq!(stake - min_allowed_stake, total_emission / 2);
Expand Down Expand Up @@ -410,8 +412,8 @@ fn pays_dividends_to_stakers() {

step_block(100);

let mut sum = 0;
let total_emission = get_total_emission_per_block::<Test>() * 100;
let mut sum = 0;

let dividends = total_emission / 2;
let incentives = total_emission / 2;
Expand Down Expand Up @@ -457,3 +459,66 @@ fn pays_dividends_to_stakers() {
assert_eq!(sum, get_total_emission_per_block::<Test>() * 100);
});
}

#[test]
fn pays_weight_control_fee_and_dividends_to_stakers() {
test_utils::new_test_ext().execute_with(|| {
EmissionRecyclingPercentage::<Test>::set(Percent::zero());
TreasuryEmissionFee::<Test>::set(Percent::zero());

let weight_control_fee = Percent::from_parts(25);
FeeConstraints::<Test>::mutate(|constraints| {
constraints.min_staking_fee = Percent::zero();
constraints.min_weight_control_fee = weight_control_fee;
});

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

let val_1 = 0;
let val_2 = 1;

let miner = 2;

let mut member = ConsensusMember::<Test>::default();
member.update_weights(BoundedVec::truncate_from(vec![(miner, 1)]));

ConsensusMembers::<Test>::set(val_1, Some(member));
ConsensusMembers::<Test>::set(val_2, Some(Default::default()));
ConsensusMembers::<Test>::set(miner, Some(Default::default()));

for id in [val_1, val_2, miner] {
register_empty_agent(id);
}

pallet_emission0::weights::delegate_weight_control::<Test>(get_origin(val_2), val_1)
.expect("failed to delegate weight control");

let val_1_staker = 3;
add_stake(val_1_staker, val_1, min_allowed_stake);

let val_2_staker = 4;
add_stake(val_2_staker, val_2, min_allowed_stake);

step_block(100);

let total_dividends = (get_total_emission_per_block::<Test>() * 100) / 2;

let mut val_1_stake = total_dividends / 2;
let mut val_2_stake = total_dividends / 2;

let val_2_weight_control_fee = weight_control_fee.mul_floor(val_2_stake);

val_1_stake += val_2_weight_control_fee;
val_2_stake -= val_2_weight_control_fee;

assert_eq!(
StakedBy::<Test>::get(val_1, val_1_staker).unwrap_or_default() - min_allowed_stake,
val_1_stake
);
assert_eq!(
StakedBy::<Test>::get(val_2, val_2_staker).unwrap_or_default() - min_allowed_stake,
val_2_stake
);
});
}
6 changes: 4 additions & 2 deletions pallets/torus0/src/fee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,11 @@ pub struct ValidatorFee<T: crate::Config> {

impl<T: crate::Config> Default for ValidatorFee<T> {
fn default() -> Self {
let fee_constraints = crate::FeeConstraints::<T>::get();

Self {
staking_fee: Percent::from_percent(T::DefaultMinStakingFee::get()),
weight_control_fee: Percent::from_percent(T::DefaultMinWeightControlFee::get()),
staking_fee: fee_constraints.min_staking_fee,
weight_control_fee: fee_constraints.min_weight_control_fee,
_pd: PhantomData,
}
}
Expand Down

0 comments on commit b085581

Please sign in to comment.