Implements a % cap on staking rewards from era inflation (#1660)

This PR implements an (optional) cap of the era inflation that is
allocated to staking rewards. The remaining is minted directly into the
[`RewardRemainder`](https://github.com/paritytech/polkadot-sdk/blob/fb0fd3e62445eb2dee2b2456a0c8574d1ecdcc73/substrate/frame/staking/src/pallet/mod.rs#L160)
account, which is the treasury pot account in Polkadot and Kusama.

The staking pallet now has a percent storage item, `MaxStakersRewards`,
which defines the max percentage of the era inflation that should be
allocated to staking rewards. The remaining era inflation (i.e.
`remaining = max_era_payout - staking_payout.min(staking_payout *
MaxStakersRewards))` is minted directly into the treasury.

The `MaxStakersRewards` can be set by a privileged origin through the
`set_staking_configs` extrinsic.

**To finish**
- [x] run benchmarks for westend-runtime

Replaces https://github.com/paritytech/polkadot-sdk/pull/1483
Closes https://github.com/paritytech/polkadot-sdk/issues/403

---------

Co-authored-by: command-bot <>
This commit is contained in:
Gonçalo Pestana
2024-02-15 20:13:35 +01:00
committed by GitHub
parent 5fc7622cb3
commit fde44474e4
9 changed files with 427 additions and 300 deletions
+10 -1
View File
@@ -36,7 +36,7 @@ use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin};
use pallet_session::historical;
use sp_runtime::{
traits::{Bounded, Convert, One, SaturatedConversion, Saturating, StaticLookup, Zero},
Perbill,
Perbill, Percent,
};
use sp_staking::{
currency_to_vote::CurrencyToVote,
@@ -507,9 +507,18 @@ impl<T: Config> Pallet<T> {
.saturated_into::<u64>();
let staked = Self::eras_total_stake(&active_era.index);
let issuance = T::Currency::total_issuance();
let (validator_payout, remainder) =
T::EraPayout::era_payout(staked, issuance, era_duration);
let total_payout = validator_payout.saturating_add(remainder);
let max_staked_rewards =
MaxStakedRewards::<T>::get().unwrap_or(Percent::from_percent(100));
// apply cap to validators payout and add difference to remainder.
let validator_payout = validator_payout.min(max_staked_rewards * total_payout);
let remainder = total_payout.saturating_sub(validator_payout);
Self::deposit_event(Event::<T>::EraPaid {
era_index: active_era.index,
validator_payout,
@@ -564,6 +564,12 @@ pub mod pallet {
#[pallet::getter(fn force_era)]
pub type ForceEra<T> = StorageValue<_, Forcing, ValueQuery>;
/// Maximum staked rewards, i.e. the percentage of the era inflation that
/// is used for stake rewards.
/// See [Era payout](./index.html#era-payout).
#[pallet::storage]
pub type MaxStakedRewards<T> = StorageValue<_, Percent, OptionQuery>;
/// The percentage of the slash that is distributed to reporters.
///
/// The rest of the slashed value is handled by the `Slash`.
@@ -1717,6 +1723,7 @@ pub mod pallet {
max_validator_count: ConfigOp<u32>,
chill_threshold: ConfigOp<Percent>,
min_commission: ConfigOp<Perbill>,
max_staked_rewards: ConfigOp<Percent>,
) -> DispatchResult {
ensure_root(origin)?;
@@ -1736,6 +1743,7 @@ pub mod pallet {
config_op_exp!(MaxValidatorsCount<T>, max_validator_count);
config_op_exp!(ChillThreshold<T>, chill_threshold);
config_op_exp!(MinCommission<T>, min_commission);
config_op_exp!(MaxStakedRewards<T>, max_staked_rewards);
Ok(())
}
/// Declare a `controller` to stop participating as either a validator or nominator.