Skip to content

Commit

Permalink
Configurable tier slots calculation formula (#1179)
Browse files Browse the repository at this point in the history
* Configurable tier slots calculation formula

* Remove redundant struct

* Comment

* Shiden runtime upgrade hook

* Post-merge fixes
  • Loading branch information
Dinonard authored Mar 12, 2024
1 parent c463c64 commit c267517
Show file tree
Hide file tree
Showing 15 changed files with 111 additions and 167 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.

3 changes: 2 additions & 1 deletion pallets/dapp-staking-migration/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ use sp_runtime::{
};

use astar_primitives::{
dapp_staking::{CycleConfiguration, SmartContract, StakingRewardHandler},
dapp_staking::{CycleConfiguration, SmartContract, StakingRewardHandler, StandardTierSlots},
oracle::PriceProvider,
Balance, BlockNumber,
};
Expand Down Expand Up @@ -180,6 +180,7 @@ impl pallet_dapp_staking_v3::Config for Test {
type CycleConfiguration = DummyCycleConfiguration;
type Observers = ();
type AccountCheck = ();
type TierSlots = StandardTierSlots;
type EraRewardSpanLength = ConstU32<8>;
type RewardRetentionInPeriods = ConstU32<2>;
type MaxNumberOfContracts = ConstU32<10>;
Expand Down
3 changes: 2 additions & 1 deletion pallets/dapp-staking-v3/src/benchmarking/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,11 +191,12 @@ pub(super) fn initial_config<T: Config>() {
};

// Init tier config, based on the initial params
let init_tier_config = TiersConfiguration::<T::NumberOfTiers> {
let init_tier_config = TiersConfiguration::<T::NumberOfTiers, T::TierSlots> {
number_of_slots: NUMBER_OF_SLOTS.try_into().unwrap(),
slots_per_tier: BoundedVec::try_from(vec![10, 20, 30, 40]).unwrap(),
reward_portion: tier_params.reward_portion.clone(),
tier_thresholds: tier_params.tier_thresholds.clone(),
_phantom: Default::default(),
};

assert!(tier_params.is_valid());
Expand Down
14 changes: 8 additions & 6 deletions pallets/dapp-staking-v3/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ use frame_support::{
pallet_prelude::*,
traits::{
fungible::{Inspect as FunInspect, MutateFreeze as FunMutateFreeze},
OnRuntimeUpgrade, StorageVersion,
StorageVersion,
},
weights::Weight,
};
Expand All @@ -53,7 +53,7 @@ pub use sp_std::vec::Vec;
use astar_primitives::{
dapp_staking::{
AccountCheck, CycleConfiguration, DAppId, EraNumber, Observer as DAppStakingObserver,
PeriodNumber, SmartContractHandle, StakingRewardHandler, TierId,
PeriodNumber, SmartContractHandle, StakingRewardHandler, TierId, TierSlots as TierSlotFunc,
},
oracle::PriceProvider,
Balance, BlockNumber,
Expand All @@ -70,8 +70,6 @@ mod benchmarking;
mod types;
pub use types::*;

pub mod migrations;

pub mod weights;
pub use weights::WeightInfo;

Expand Down Expand Up @@ -147,6 +145,9 @@ pub mod pallet {
/// Used to check whether an account is allowed to participate in dApp staking.
type AccountCheck: AccountCheck<Self::AccountId>;

/// Used to calculate total number of tier slots for some price.
type TierSlots: TierSlotFunc;

/// Maximum length of a single era reward span length entry.
#[pallet::constant]
type EraRewardSpanLength: Get<u32>;
Expand Down Expand Up @@ -446,7 +447,7 @@ pub mod pallet {
/// Tier configuration user for current & preceding eras.
#[pallet::storage]
pub type TierConfig<T: Config> =
StorageValue<_, TiersConfiguration<T::NumberOfTiers>, ValueQuery>;
StorageValue<_, TiersConfiguration<T::NumberOfTiers, T::TierSlots>, ValueQuery>;

/// Information about which tier a dApp belonged to in a specific era.
#[pallet::storage]
Expand Down Expand Up @@ -506,14 +507,15 @@ pub mod pallet {
let number_of_slots = self.slots_per_tier.iter().fold(0_u16, |acc, &slots| {
acc.checked_add(slots).expect("Overflow")
});
let tier_config = TiersConfiguration::<T::NumberOfTiers> {
let tier_config = TiersConfiguration::<T::NumberOfTiers, T::TierSlots> {
number_of_slots,
slots_per_tier: BoundedVec::<u16, T::NumberOfTiers>::try_from(
self.slots_per_tier.clone(),
)
.expect("Invalid number of slots per tier entries provided."),
reward_portion: tier_params.reward_portion.clone(),
tier_thresholds: tier_params.tier_thresholds.clone(),
_phantom: Default::default(),
};
assert!(
tier_params.is_valid(),
Expand Down
129 changes: 0 additions & 129 deletions pallets/dapp-staking-v3/src/migrations.rs

This file was deleted.

10 changes: 8 additions & 2 deletions pallets/dapp-staking-v3/src/test/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ use sp_runtime::{
use sp_std::cell::RefCell;

use astar_primitives::{
dapp_staking::{Observer as DappStakingObserver, SmartContract},
dapp_staking::{Observer as DappStakingObserver, SmartContract, StandardTierSlots},
testing::Header,
Balance, BlockNumber,
};

Expand Down Expand Up @@ -204,6 +205,7 @@ impl pallet_dapp_staking::Config for Test {
type CycleConfiguration = DummyCycleConfiguration;
type Observers = DummyDappStakingObserver;
type AccountCheck = DummyAccountCheck;
type TierSlots = StandardTierSlots;
type EraRewardSpanLength = ConstU32<8>;
type RewardRetentionInPeriods = ConstU32<2>;
type MaxNumberOfContracts = ConstU32<10>;
Expand Down Expand Up @@ -309,11 +311,15 @@ impl ExtBuilder {
};

// Init tier config, based on the initial params
let init_tier_config = TiersConfiguration::<<Test as Config>::NumberOfTiers> {
let init_tier_config = TiersConfiguration::<
<Test as Config>::NumberOfTiers,
<Test as Config>::TierSlots,
> {
number_of_slots: 40,
slots_per_tier: BoundedVec::try_from(vec![2, 5, 13, 20]).unwrap(),
reward_portion: tier_params.reward_portion.clone(),
tier_thresholds: tier_params.tier_thresholds.clone(),
_phantom: Default::default(),
};

pallet_dapp_staking::StaticTierParams::<Test>::put(tier_params);
Expand Down
5 changes: 3 additions & 2 deletions pallets/dapp-staking-v3/src/test/tests_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
// You should have received a copy of the GNU General Public License
// along with Astar. If not, see <http://www.gnu.org/licenses/>.

use astar_primitives::Balance;
use astar_primitives::{dapp_staking::StandardTierSlots, Balance};
use frame_support::assert_ok;
use sp_arithmetic::fixed_point::FixedU64;
use sp_runtime::Permill;
Expand Down Expand Up @@ -2732,11 +2732,12 @@ fn tier_configuration_basic_tests() {
assert!(params.is_valid(), "Example params must be valid!");

// Create a configuration with some values
let init_config = TiersConfiguration::<TiersNum> {
let init_config = TiersConfiguration::<TiersNum, StandardTierSlots> {
number_of_slots: 100,
slots_per_tier: BoundedVec::try_from(vec![10, 20, 30, 40]).unwrap(),
reward_portion: params.reward_portion.clone(),
tier_thresholds: params.tier_thresholds.clone(),
_phantom: Default::default(),
};
assert!(init_config.is_valid(), "Init config must be valid!");

Expand Down
25 changes: 11 additions & 14 deletions pallets/dapp-staking-v3/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ use sp_runtime::{
pub use sp_std::{collections::btree_map::BTreeMap, fmt::Debug, vec::Vec};

use astar_primitives::{
dapp_staking::{DAppId, EraNumber, PeriodNumber, TierId},
dapp_staking::{DAppId, EraNumber, PeriodNumber, TierId, TierSlots as TierSlotsFunc},
Balance, BlockNumber,
};

Expand Down Expand Up @@ -1485,8 +1485,8 @@ impl<NT: Get<u32>> Default for TierParameters<NT> {
CloneNoBound,
TypeInfo,
)]
#[scale_info(skip_type_params(NT))]
pub struct TiersConfiguration<NT: Get<u32>> {
#[scale_info(skip_type_params(NT, T))]
pub struct TiersConfiguration<NT: Get<u32>, T: TierSlotsFunc> {
/// Total number of slots.
#[codec(compact)]
pub number_of_slots: u16,
Expand All @@ -1500,15 +1500,19 @@ pub struct TiersConfiguration<NT: Get<u32>> {
/// Requirements for entry into each tier.
/// First entry refers to the first tier, and so on.
pub tier_thresholds: BoundedVec<TierThreshold, NT>,
/// Phantom data to keep track of the tier slots function.
#[codec(skip)]
pub(crate) _phantom: PhantomData<T>,
}

impl<NT: Get<u32>> Default for TiersConfiguration<NT> {
impl<NT: Get<u32>, T: TierSlotsFunc> Default for TiersConfiguration<NT, T> {
fn default() -> Self {
Self {
number_of_slots: 0,
slots_per_tier: BoundedVec::default(),
reward_portion: BoundedVec::default(),
tier_thresholds: BoundedVec::default(),
_phantom: Default::default(),
}
}
}
Expand All @@ -1518,7 +1522,7 @@ impl<NT: Get<u32>> Default for TiersConfiguration<NT> {
// * There's no need to keep thresholds in two separate storage items since the calculation can always be done compared to the
// anchor value of 5 cents. This still needs to be checked & investigated, but it's worth a try.

impl<NT: Get<u32>> TiersConfiguration<NT> {
impl<NT: Get<u32>, T: TierSlotsFunc> TiersConfiguration<NT, T> {
/// Check if parameters are valid.
pub fn is_valid(&self) -> bool {
let number_of_tiers: usize = NT::get() as usize;
Expand All @@ -1533,7 +1537,7 @@ impl<NT: Get<u32>> TiersConfiguration<NT> {
/// Calculate new `TiersConfiguration`, based on the old settings, current native currency price and tier configuration.
pub fn calculate_new(&self, native_price: FixedU64, params: &TierParameters<NT>) -> Self {
// It must always be at least 1 slot.
let new_number_of_slots = Self::calculate_number_of_slots(native_price).max(1);
let new_number_of_slots = T::number_of_slots(native_price).max(1);

// Calculate how much each tier gets slots.
let new_slots_per_tier: Vec<u16> = params
Expand Down Expand Up @@ -1621,16 +1625,9 @@ impl<NT: Get<u32>> TiersConfiguration<NT> {
slots_per_tier: new_slots_per_tier,
reward_portion: params.reward_portion.clone(),
tier_thresholds: new_tier_thresholds,
_phantom: Default::default(),
}
}

/// Calculate number of slots, based on the provided native token price.
pub fn calculate_number_of_slots(native_price: FixedU64) -> u16 {
// floor(1000 x price + 50), formula proposed in Tokenomics 2.0 document.
let result: u64 = native_price.saturating_mul_int(1000).saturating_add(50);

result.unique_saturated_into()
}
}

/// Information about all of the dApps that got into tiers, and tier rewards
Expand Down
2 changes: 2 additions & 0 deletions precompiles/dapp-staking-v3/src/test/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ extern crate alloc;
use astar_primitives::{
dapp_staking::{
CycleConfiguration, EraNumber, PeriodNumber, SmartContract, StakingRewardHandler,
StandardTierSlots,
},
oracle::PriceProvider,
AccountId, Balance, BlockNumber,
Expand Down Expand Up @@ -253,6 +254,7 @@ impl pallet_dapp_staking_v3::Config for Test {
type CycleConfiguration = DummyCycleConfiguration;
type Observers = ();
type AccountCheck = ();
type TierSlots = StandardTierSlots;
type EraRewardSpanLength = ConstU32<8>;
type RewardRetentionInPeriods = ConstU32<2>;
type MaxNumberOfContracts = ConstU32<10>;
Expand Down
Loading

0 comments on commit c267517

Please sign in to comment.