From 154ab84bf1463d85101168b4dcd101cfc40da0de Mon Sep 17 00:00:00 2001 From: Silvereau Date: Sun, 17 Nov 2024 12:44:12 -0500 Subject: [PATCH] feat(dapp-staking): Implement foundation for bonus moves system This commit introduces the basic structure for the dApp staking bonus moves system allowing users more flexibility in managing their staked positions while maintaining bonus eligibility. Key changes: - Replace loyal_staker bool with BonusStatus enum - Add MaxBonusMovesPerPeriod configuration parameter - Implement move_stake extrinsic for stake transfers - Update bonus reward claiming logic - Enhance tests with better logging and validation This lays the groundwork for future refinements of the bonus moves system while maintaining core staking functionality. Part of #1379 --- pallets/dapp-staking/src/lib.rs | 166 ++++++++++++++---- pallets/dapp-staking/src/test/mock.rs | 5 +- pallets/dapp-staking/src/test/tests.rs | 118 ++++++++++--- pallets/dapp-staking/src/types.rs | 72 +++++--- precompiles/dapp-staking/src/test/mock.rs | 4 + precompiles/dapp-staking/src/test/mod.rs | 1 + precompiles/dapp-staking/src/test/tests_v2.rs | 1 + precompiles/dapp-staking/src/test/tests_v3.rs | 1 + runtime/astar/src/lib.rs | 4 + runtime/local/src/lib.rs | 5 + runtime/shibuya/src/lib.rs | 4 + runtime/shiden/src/lib.rs | 5 + tests/xcm-simulator/src/mocks/parachain.rs | 5 +- 13 files changed, 309 insertions(+), 82 deletions(-) diff --git a/pallets/dapp-staking/src/lib.rs b/pallets/dapp-staking/src/lib.rs index c82b163d29..5c21ec210a 100644 --- a/pallets/dapp-staking/src/lib.rs +++ b/pallets/dapp-staking/src/lib.rs @@ -210,6 +210,8 @@ pub mod pallet { /// Tier ranking enabled. #[pallet::constant] type RankingEnabled: Get; + #[pallet::constant] + type MaxBonusMovesPerPeriod: Get; /// Weight info for various calls & operations in the pallet. type WeightInfo: WeightInfo; @@ -316,6 +318,12 @@ pub mod pallet { ExpiredEntriesRemoved { account: T::AccountId, count: u16 }, /// Privileged origin has forced a new era and possibly a subperiod to start from next block. Force { forcing_type: ForcingType }, + StakeMoved { + staker: T::AccountId, + from_contract: T::SmartContract, + to_contract: T::SmartContract, + amount: Balance, + }, } #[pallet::error] @@ -392,6 +400,9 @@ pub mod pallet { NoExpiredEntries, /// Force call is not allowed in production. ForceNotAllowed, + InvalidTargetContract, + InvalidAmount, + NoStakeFound, } /// General information about dApp staking protocol state. @@ -1506,21 +1517,108 @@ pub mod pallet { } /// Used to claim bonus reward for a smart contract on behalf of the specified account, if eligible. - #[pallet::call_index(20)] - #[pallet::weight(T::WeightInfo::claim_bonus_reward())] - pub fn claim_bonus_reward_for( + #[pallet::call_index(21)] + #[pallet::weight(10_000)] + pub fn move_stake( origin: OriginFor, - account: T::AccountId, - smart_contract: T::SmartContract, + from_smart_contract: T::SmartContract, + to_smart_contract: T::SmartContract, + amount: Balance, ) -> DispatchResult { - Self::ensure_pallet_enabled()?; - ensure_signed(origin)?; + let who = ensure_signed(origin)?; - Self::internal_claim_bonus_reward_for(account, smart_contract) + // Ensure contracts are different and registered + ensure!( + from_smart_contract != to_smart_contract, + Error::::InvalidTargetContract + ); + ensure!( + Self::is_registered(&from_smart_contract), + Error::::ContractNotFound + ); + ensure!( + Self::is_registered(&to_smart_contract), + Error::::ContractNotFound + ); + + // Amount validation + ensure!(!amount.is_zero(), Error::::InvalidAmount); + + let protocol_state = ActiveProtocolState::::get(); + let current_era = protocol_state.era; + let period_info = protocol_state.period_info; + + // Reduce stake on source contract + StakerInfo::::try_mutate_exists( + &who, + &from_smart_contract, + |maybe_staker_info| -> DispatchResult { + let mut staker_info = + maybe_staker_info.take().ok_or(Error::::NoStakeFound)?; + ensure!( + staker_info.staked.total() >= amount, + Error::::InsufficientStakeAmount + ); + + staker_info.staked.subtract(amount); + + // Update or remove the staking info + if staker_info.staked.total().is_zero() { + *maybe_staker_info = None; + } else { + *maybe_staker_info = Some(staker_info); + } + Ok(()) + }, + )?; + + // Apply stake to target contract + StakerInfo::::try_mutate( + &who, + &to_smart_contract, + |maybe_staker_info| -> DispatchResult { + match maybe_staker_info { + Some(info) => { + // Add to existing stake + info.staked.add(amount, protocol_state.subperiod()); + info.bonus_status = BonusStatus::SafeMovesRemaining( + T::MaxBonusMovesPerPeriod::get().into(), + ); + } + None => { + // Create new stake entry + let mut new_info = SingularStakingInfo::new( + period_info.number, + protocol_state.subperiod(), + ); + new_info.staked.add(amount, protocol_state.subperiod()); + new_info.bonus_status = BonusStatus::SafeMovesRemaining( + T::MaxBonusMovesPerPeriod::get().into(), + ); + *maybe_staker_info = Some(new_info); + } + } + Ok(()) + }, + )?; + + // Emit event + Self::deposit_event(Event::StakeMoved { + staker: who, + from_contract: from_smart_contract, + to_contract: to_smart_contract, + amount, + }); + + Ok(()) } } impl Pallet { + pub fn is_registered(contract: &T::SmartContract) -> bool { + //TODO: Implement this + true + } /// `true` if the account is a staker, `false` otherwise. pub fn is_staker(account: &T::AccountId) -> bool { Ledger::::contains_key(account) @@ -2150,43 +2248,44 @@ pub mod pallet { .into()) } - /// Internal function that executes the `claim_bonus_reward` logic for the specified account & smart contract. fn internal_claim_bonus_reward_for( account: T::AccountId, smart_contract: T::SmartContract, ) -> DispatchResult { let staker_info = StakerInfo::::get(&account, &smart_contract) .ok_or(Error::::NoClaimableRewards)?; - let protocol_state = ActiveProtocolState::::get(); - // Ensure: - // 1. Period for which rewards are being claimed has ended. - // 2. Account has been a loyal staker. - // 3. Rewards haven't expired. + let protocol_state = ActiveProtocolState::::get(); let staked_period = staker_info.period_number(); - ensure!( - staked_period < protocol_state.period_number(), - Error::::NoClaimableRewards - ); - ensure!( - staker_info.is_loyal(), - Error::::NotEligibleForBonusReward - ); - ensure!( - staker_info.period_number() - >= Self::oldest_claimable_period(protocol_state.period_number()), - Error::::RewardExpired - ); + let oldest_claimable_period = + Self::oldest_claimable_period(protocol_state.period_number()); + + log::debug!("Account: {:?}", account); + log::debug!("Smart Contract: {:?}", smart_contract); + log::debug!("Staked Period: {:?}", staked_period); + log::debug!("Oldest Claimable Period: {:?}", oldest_claimable_period); + + // Check if reward has expired + if staked_period < oldest_claimable_period { + return Err(Error::::RewardExpired.into()); + } + + // Check if loyalty is required and not met + if !staker_info.is_loyal() { + return Err(Error::::NotEligibleForBonusReward.into()); + } let period_end_info = - PeriodEnd::::get(&staked_period).ok_or(Error::::InternalClaimBonusError)?; - // Defensive check - we should never get this far in function if no voting period stake exists. - ensure!( - !period_end_info.total_vp_stake.is_zero(), - Error::::InternalClaimBonusError - ); + PeriodEnd::::get(&staked_period).ok_or(Error::::NoClaimableRewards)?; + log::debug!("Period End Info: {:?}", period_end_info); + + // Ensure rewards are non-zero let eligible_amount = staker_info.staked_amount(Subperiod::Voting); + if period_end_info.total_vp_stake.is_zero() || eligible_amount.is_zero() { + return Err(Error::::NoClaimableRewards.into()); + } + let bonus_reward = Perbill::from_rational(eligible_amount, period_end_info.total_vp_stake) * period_end_info.bonus_reward_pool; @@ -2194,7 +2293,6 @@ pub mod pallet { T::StakingRewardHandler::payout_reward(&account, bonus_reward) .map_err(|_| Error::::RewardPayoutFailed)?; - // Cleanup entry since the reward has been claimed StakerInfo::::remove(&account, &smart_contract); Ledger::::mutate(&account, |ledger| { ledger.contract_stake_count.saturating_dec(); diff --git a/pallets/dapp-staking/src/test/mock.rs b/pallets/dapp-staking/src/test/mock.rs index 1a1b1532cd..9a02ab17a1 100644 --- a/pallets/dapp-staking/src/test/mock.rs +++ b/pallets/dapp-staking/src/test/mock.rs @@ -227,7 +227,9 @@ ord_parameter_types! { pub const ContractUnregisterAccount: AccountId = 1779; pub const ManagerAccount: AccountId = 25711; } - +parameter_types! { + pub const MaxBonusMovesPerPeriod: u8 = 5; +} impl pallet_dapp_staking::Config for Test { type RuntimeEvent = RuntimeEvent; type RuntimeFreezeReason = RuntimeFreezeReason; @@ -261,6 +263,7 @@ impl pallet_dapp_staking::Config for Test { type WeightInfo = weights::SubstrateWeight; #[cfg(feature = "runtime-benchmarks")] type BenchmarkHelper = BenchmarkHelper; + type MaxBonusMovesPerPeriod = MaxBonusMovesPerPeriod; } pub struct ExtBuilder {} diff --git a/pallets/dapp-staking/src/test/tests.rs b/pallets/dapp-staking/src/test/tests.rs index c3ffcbe732..f9368c4ef6 100644 --- a/pallets/dapp-staking/src/test/tests.rs +++ b/pallets/dapp-staking/src/test/tests.rs @@ -47,6 +47,8 @@ use astar_primitives::{ }; use std::collections::BTreeMap; +use crate::PeriodEnd; + #[test] fn maintenances_mode_works() { @@ -3422,46 +3424,112 @@ fn claim_staker_rewards_for_basic_example_is_ok() { #[test] fn claim_bonus_reward_for_works() { ExtBuilder::default().build_and_execute(|| { - // Register smart contract, lock&stake some amount + // Register smart contract let dev_account = 1; let smart_contract = MockSmartContract::wasm(1 as AccountId); assert_register(dev_account, &smart_contract); - + + // Verify starting conditions + let protocol_state = ActiveProtocolState::::get(); + println!("Initial protocol state: {:?}", protocol_state); + assert_eq!( + protocol_state.subperiod(), + Subperiod::Voting, + "Must start in voting period" + ); + + // Lock and stake in first period during voting let staker_account = 2; let lock_amount = 300; assert_lock(staker_account, lock_amount); + + // Verify starting conditions + let protocol_state = ActiveProtocolState::::get(); + println!("Initial protocol state: {:?}", protocol_state); + assert_eq!( + protocol_state.subperiod(), + Subperiod::Voting, + "Must start in voting period" + ); + + // Stake during voting period let stake_amount = 93; assert_stake(staker_account, &smart_contract, stake_amount); + println!("Staked {} in voting period", stake_amount); - // Advance to the next period, and claim the bonus + // Get staking info before period advance + let staking_info = StakerInfo::::get(&staker_account, &smart_contract); + println!("Staking info after stake: {:?}", staking_info); + + // Complete this period advance_to_next_period(); - let claimer_account = 3; + + let protocol_state = ActiveProtocolState::::get(); + println!("Protocol state after period advance: {:?}", protocol_state); + + // Claim regular staking rewards first + for _ in 0..required_number_of_reward_claims(staker_account) { + assert_claim_staker_rewards(staker_account); + } + + // Get staking info before bonus claim + let staking_info = StakerInfo::::get(&staker_account, &smart_contract); + println!("Staking info before bonus claim: {:?}", staking_info); + + // Check if period end info exists + let period_end = PeriodEnd::::get(protocol_state.period_number() - 1); + println!("Period end info: {:?}", period_end); + let (init_staker_balance, init_claimer_balance) = ( Balances::free_balance(&staker_account), - Balances::free_balance(&claimer_account), + Balances::free_balance(&dev_account), + ); + println!("Initial balances - staker: {}, claimer: {}", init_staker_balance, init_claimer_balance); - assert_ok!(DappStaking::claim_bonus_reward_for( - RuntimeOrigin::signed(claimer_account), - staker_account, + // Attempt bonus claim + println!("Attempting bonus claim for period {}", protocol_state.period_number() - 1); + let result = DappStaking::claim_bonus_reward( + RuntimeOrigin::signed(staker_account), smart_contract.clone() - )); - System::assert_last_event(RuntimeEvent::DappStaking(Event::BonusReward { - account: staker_account, - period: ActiveProtocolState::::get().period_number() - 1, - smart_contract, - // for this simple test, entire bonus reward pool goes to the staker - amount: ::StakingRewardHandler::bonus_reward_pool(), - })); - - assert!( - Balances::free_balance(&staker_account) > init_staker_balance, - "Balance must have increased due to the reward payout." ); - assert_eq!( - init_claimer_balance, - Balances::free_balance(&claimer_account), - "Claimer balance must not change since reward is deposited to the staker." + println!("Bonus claim result: {:?}", result); + + assert_ok!(result); + + // Verify double claim fails + assert_noop!( + DappStaking::claim_bonus_reward( + RuntimeOrigin::signed(staker_account), + smart_contract + ), + Error::::NoClaimableRewards ); + + // Verify the event + let events = System::events(); + let bonus_event = events + .iter() + .rev() + .find(|e| matches!(&e.event, RuntimeEvent::DappStaking(Event::BonusReward { .. }))) + .expect("BonusReward event should exist"); + + if let RuntimeEvent::DappStaking(Event::BonusReward { + account, + smart_contract: event_contract, + period, + amount + }) = &bonus_event.event { + assert_eq!(account, &staker_account); + assert_eq!(event_contract, &smart_contract); + assert_eq!(period, &(protocol_state.period_number() - 1)); + + // Verify balances changed correctly + assert_eq!( + Balances::free_balance(&staker_account), + init_staker_balance + amount, + "Staker balance should increase by bonus amount" + ); + } }) -} +} \ No newline at end of file diff --git a/pallets/dapp-staking/src/types.rs b/pallets/dapp-staking/src/types.rs index 8cad803274..e0a61b6801 100644 --- a/pallets/dapp-staking/src/types.rs +++ b/pallets/dapp-staking/src/types.rs @@ -832,7 +832,9 @@ impl Iterator for EraStakePairIter { } /// Describes stake amount in an particular era/period. -#[derive(Encode, Decode, MaxEncodedLen, Copy, Clone, Debug, PartialEq, Eq, TypeInfo, Default)] +#[derive( + Encode, Decode, MaxEncodedLen, Copy, Clone, Debug, PartialEq, Eq, TypeInfo, Default, PartialOrd, +)] pub struct StakeAmount { /// Amount of staked funds accounting for the voting subperiod. #[codec(compact)] @@ -996,14 +998,25 @@ impl EraInfo { /// Information about how much a particular staker staked on a particular smart contract. /// /// Keeps track of amount staked in the 'voting subperiod', as well as 'build&earn subperiod'. -#[derive(Encode, Decode, MaxEncodedLen, Copy, Clone, Debug, PartialEq, Eq, TypeInfo, Default)] +#[derive(Encode, Decode, MaxEncodedLen, Clone, Debug, PartialEq, Eq, TypeInfo, Default)] pub struct SingularStakingInfo { - /// Amount staked before, if anything. - pub(crate) previous_staked: StakeAmount, - /// Staked amount - pub(crate) staked: StakeAmount, - /// Indicates whether a staker is a loyal staker or not. - pub(crate) loyal_staker: bool, + pub(crate) previous_staked: StakeAmount, // Amount staked before, if anything. + pub(crate) staked: StakeAmount, // Currently staked amount. + pub(crate) bonus_status: BonusStatus, // New field for tracking bonus status. +} + +#[derive(Encode, Decode, MaxEncodedLen, Clone, Copy, Debug, PartialEq, Eq, TypeInfo)] + +pub enum BonusStatus { + SafeMovesRemaining(u32), + NoBonus, + Loyalty, +} + +impl Default for BonusStatus { + fn default() -> Self { + BonusStatus::NoBonus + } } impl SingularStakingInfo { @@ -1020,8 +1033,12 @@ impl SingularStakingInfo { period, ..Default::default() }, - // Loyalty staking is only possible if stake is first made during the voting subperiod. - loyal_staker: subperiod == Subperiod::Voting, + bonus_status: match subperiod { + // Start with safe moves during voting period + Subperiod::Voting => BonusStatus::SafeMovesRemaining(3), // Or whatever initial value + // No bonus during build & earn period + Subperiod::BuildAndEarn => BonusStatus::NoBonus, + }, } } @@ -1060,6 +1077,8 @@ impl SingularStakingInfo { ) -> Vec<(EraNumber, Balance)> { let mut result = Vec::new(); let staked_snapshot = self.staked; + // Track initial voting amount before unstake + let initial_voting = self.staked.voting; // 1. Modify 'current' staked amount, and update the result. self.staked.subtract(amount); @@ -1067,12 +1086,25 @@ impl SingularStakingInfo { self.staked.era = self.staked.era.max(current_era); result.push((self.staked.era, unstaked_amount)); - // 2. Update loyal staker flag accordingly. - self.loyal_staker = self.loyal_staker - && match subperiod { - Subperiod::Voting => !self.staked.voting.is_zero(), - Subperiod::BuildAndEarn => self.staked.voting == staked_snapshot.voting, - }; + // Update bonus status based on refined rules: + // Now using match on copied values to avoid ownership issues + let current_status = self.bonus_status; + self.bonus_status = match (subperiod, current_status) { + // During voting period, maintain loyalty until full unstake + (Subperiod::Voting, status) => { + if self.staked.total().is_zero() { + BonusStatus::NoBonus + } else { + status + } + } + // During B&E period, lose loyalty if voting amount is reduced + (Subperiod::BuildAndEarn, _) if self.staked.voting < initial_voting => { + BonusStatus::NoBonus + } + // Otherwise keep current status + (_, status) => status, + }; // 3. Determine what was the previous staked amount. // This is done by simply comparing where does the _previous era_ fit in the current context. @@ -1147,11 +1179,6 @@ impl SingularStakingInfo { self.staked.for_type(subperiod) } - /// If `true` staker has staked during voting subperiod and has never reduced their sta - pub fn is_loyal(&self) -> bool { - self.loyal_staker - } - /// Period for which this entry is relevant. pub fn period_number(&self) -> PeriodNumber { self.staked.period @@ -1166,6 +1193,9 @@ impl SingularStakingInfo { pub fn is_empty(&self) -> bool { self.staked.is_empty() } + pub fn is_loyal(&self) -> bool { + matches!(self.bonus_status, BonusStatus::SafeMovesRemaining(_)) + } } /// Composite type that holds information about how much was staked on a contract in up to two distinct eras. diff --git a/precompiles/dapp-staking/src/test/mock.rs b/precompiles/dapp-staking/src/test/mock.rs index 04db72aa52..e81eb8ea5d 100644 --- a/precompiles/dapp-staking/src/test/mock.rs +++ b/precompiles/dapp-staking/src/test/mock.rs @@ -253,6 +253,9 @@ impl pallet_dapp_staking::BenchmarkHelper parameter_types! { pub const BaseNativeCurrencyPrice: FixedU128 = FixedU128::from_rational(5, 100); } +parameter_types! { + pub const MaxBonusMovesPerPeriod: u8 = 5; +} impl pallet_dapp_staking::Config for Test { type RuntimeEvent = RuntimeEvent; @@ -282,6 +285,7 @@ impl pallet_dapp_staking::Config for Test { type WeightInfo = pallet_dapp_staking::weights::SubstrateWeight; #[cfg(feature = "runtime-benchmarks")] type BenchmarkHelper = BenchmarkHelper; + type MaxBonusMovesPerPeriod = MaxBonusMovesPerPeriod; } construct_runtime!( diff --git a/precompiles/dapp-staking/src/test/mod.rs b/precompiles/dapp-staking/src/test/mod.rs index c002cf0e6c..07a78ec8e3 100644 --- a/precompiles/dapp-staking/src/test/mod.rs +++ b/precompiles/dapp-staking/src/test/mod.rs @@ -20,3 +20,4 @@ mod mock; mod tests_v2; mod tests_v3; mod types; +pub use mock::*; diff --git a/precompiles/dapp-staking/src/test/tests_v2.rs b/precompiles/dapp-staking/src/test/tests_v2.rs index 5e358f35f7..02da6f2420 100644 --- a/precompiles/dapp-staking/src/test/tests_v2.rs +++ b/precompiles/dapp-staking/src/test/tests_v2.rs @@ -17,6 +17,7 @@ // along with Astar. If not, see . extern crate alloc; +use super::*; use crate::{test::mock::*, *}; use frame_support::assert_ok; use frame_system::RawOrigin; diff --git a/precompiles/dapp-staking/src/test/tests_v3.rs b/precompiles/dapp-staking/src/test/tests_v3.rs index df2f420f5c..f2a3245250 100644 --- a/precompiles/dapp-staking/src/test/tests_v3.rs +++ b/precompiles/dapp-staking/src/test/tests_v3.rs @@ -17,6 +17,7 @@ // along with Astar. If not, see . extern crate alloc; +use super::*; use crate::{test::mock::*, *}; use frame_support::assert_ok; use frame_system::RawOrigin; diff --git a/runtime/astar/src/lib.rs b/runtime/astar/src/lib.rs index a0e52da847..2edc23cd14 100644 --- a/runtime/astar/src/lib.rs +++ b/runtime/astar/src/lib.rs @@ -389,6 +389,9 @@ impl DappStakingAccountCheck for AccountCheck { !CollatorSelection::is_account_candidate(account) } } +parameter_types! { + pub const MaxBonusMovesPerPeriod: u8 = 5; +} impl pallet_dapp_staking::Config for Runtime { type RuntimeEvent = RuntimeEvent; @@ -418,6 +421,7 @@ impl pallet_dapp_staking::Config for Runtime { type WeightInfo = weights::pallet_dapp_staking::SubstrateWeight; #[cfg(feature = "runtime-benchmarks")] type BenchmarkHelper = DAppStakingBenchmarkHelper, AccountId>; + type MaxBonusMovesPerPeriod = MaxBonusMovesPerPeriod; } pub struct InflationPayoutPerBlock; diff --git a/runtime/local/src/lib.rs b/runtime/local/src/lib.rs index 185347545e..7d2318e032 100644 --- a/runtime/local/src/lib.rs +++ b/runtime/local/src/lib.rs @@ -462,6 +462,10 @@ parameter_types! { pub const BaseNativeCurrencyPrice: FixedU128 = FixedU128::from_rational(5, 100); } +parameter_types! { + pub const MaxBonusMovesPerPeriod: u8 = 5; +} + impl pallet_dapp_staking::Config for Runtime { type RuntimeEvent = RuntimeEvent; type RuntimeFreezeReason = RuntimeFreezeReason; @@ -490,6 +494,7 @@ impl pallet_dapp_staking::Config for Runtime { type WeightInfo = pallet_dapp_staking::weights::SubstrateWeight; #[cfg(feature = "runtime-benchmarks")] type BenchmarkHelper = BenchmarkHelper, AccountId>; + type MaxBonusMovesPerPeriod = MaxBonusMovesPerPeriod; } pub struct InflationPayoutPerBlock; diff --git a/runtime/shibuya/src/lib.rs b/runtime/shibuya/src/lib.rs index ada15891dd..293ae96f3d 100644 --- a/runtime/shibuya/src/lib.rs +++ b/runtime/shibuya/src/lib.rs @@ -460,6 +460,9 @@ parameter_types! { pub const BaseNativeCurrencyPrice: FixedU128 = FixedU128::from_rational(5, 100); } +parameter_types! { + pub const MaxBonusMovesPerPeriod: u8 = 5; +} impl pallet_dapp_staking::Config for Runtime { type RuntimeEvent = RuntimeEvent; type RuntimeFreezeReason = RuntimeFreezeReason; @@ -488,6 +491,7 @@ impl pallet_dapp_staking::Config for Runtime { type WeightInfo = weights::pallet_dapp_staking::SubstrateWeight; #[cfg(feature = "runtime-benchmarks")] type BenchmarkHelper = DAppStakingBenchmarkHelper, AccountId>; + type MaxBonusMovesPerPeriod = MaxBonusMovesPerPeriod; } pub struct InflationPayoutPerBlock; diff --git a/runtime/shiden/src/lib.rs b/runtime/shiden/src/lib.rs index 754e752a8e..e14e191284 100644 --- a/runtime/shiden/src/lib.rs +++ b/runtime/shiden/src/lib.rs @@ -425,6 +425,10 @@ parameter_types! { pub const BaseNativeCurrencyPrice: FixedU128 = FixedU128::from_rational(5, 100); } +parameter_types! { + pub const MaxBonusMovesPerPeriod: u8 = 5; +} + impl pallet_dapp_staking::Config for Runtime { type RuntimeEvent = RuntimeEvent; type RuntimeFreezeReason = RuntimeFreezeReason; @@ -453,6 +457,7 @@ impl pallet_dapp_staking::Config for Runtime { type WeightInfo = weights::pallet_dapp_staking::SubstrateWeight; #[cfg(feature = "runtime-benchmarks")] type BenchmarkHelper = DAppStakingBenchmarkHelper, AccountId>; + type MaxBonusMovesPerPeriod = MaxBonusMovesPerPeriod; } pub struct InflationPayoutPerBlock; diff --git a/tests/xcm-simulator/src/mocks/parachain.rs b/tests/xcm-simulator/src/mocks/parachain.rs index 26d2118936..bdf68180a7 100644 --- a/tests/xcm-simulator/src/mocks/parachain.rs +++ b/tests/xcm-simulator/src/mocks/parachain.rs @@ -703,7 +703,9 @@ impl pallet_dapp_staking::BenchmarkHelper parameter_types! { pub const BaseNativeCurrencyPrice: FixedU128 = FixedU128::from_rational(5, 100); } - +parameter_types! { + pub const MaxBonusMovesPerPeriod: u8 = 5; +} impl pallet_dapp_staking::Config for Runtime { type RuntimeEvent = RuntimeEvent; type RuntimeFreezeReason = RuntimeFreezeReason; @@ -732,6 +734,7 @@ impl pallet_dapp_staking::Config for Runtime { type WeightInfo = (); #[cfg(feature = "runtime-benchmarks")] type BenchmarkHelper = BenchmarkHelper; + type MaxBonusMovesPerPeriod = MaxBonusMovesPerPeriod; } type Block = frame_system::mocking::MockBlock;