diff --git a/Cargo.lock b/Cargo.lock index eba6513a5..c27a34c6f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3811,7 +3811,7 @@ dependencies = [ "pallet-omnipool-liquidity-mining", "pallet-route-executor", "pallet-stableswap", - "pallet-staking 1.0.1", + "pallet-staking 2.0.0", "pallet-transaction-multi-payment", "pallet-uniques", "parity-scale-codec", @@ -3831,7 +3831,7 @@ dependencies = [ [[package]] name = "hydradx-runtime" -version = "182.0.0" +version = "183.0.0" dependencies = [ "cumulus-pallet-aura-ext", "cumulus-pallet-dmp-queue", @@ -3893,7 +3893,7 @@ dependencies = [ "pallet-scheduler", "pallet-session", "pallet-stableswap", - "pallet-staking 1.0.1", + "pallet-staking 2.0.0", "pallet-timestamp", "pallet-tips", "pallet-transaction-multi-payment", @@ -7411,7 +7411,7 @@ dependencies = [ [[package]] name = "pallet-staking" -version = "1.0.1" +version = "2.0.0" dependencies = [ "frame-benchmarking", "frame-support", @@ -10220,7 +10220,7 @@ dependencies = [ [[package]] name = "runtime-integration-tests" -version = "1.12.4" +version = "1.13.0" dependencies = [ "cumulus-pallet-aura-ext", "cumulus-pallet-dmp-queue", @@ -10275,7 +10275,7 @@ dependencies = [ "pallet-scheduler", "pallet-session", "pallet-stableswap", - "pallet-staking 1.0.1", + "pallet-staking 2.0.0", "pallet-sudo", "pallet-timestamp", "pallet-tips", diff --git a/integration-tests/Cargo.toml b/integration-tests/Cargo.toml index 552a0b9d8..427cb6e53 100644 --- a/integration-tests/Cargo.toml +++ b/integration-tests/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "runtime-integration-tests" -version = "1.12.4" +version = "1.13.0" description = "Integration tests" authors = ["GalacticCouncil"] edition = "2021" @@ -189,4 +189,4 @@ std = [ # we don't include integration tests when benchmarking feature is enabled runtime-benchmarks = [ "hydradx-runtime/runtime-benchmarks", -] \ No newline at end of file +] diff --git a/integration-tests/src/staking.rs b/integration-tests/src/staking.rs index a4c2d2ff1..d8c612cf7 100644 --- a/integration-tests/src/staking.rs +++ b/integration-tests/src/staking.rs @@ -858,3 +858,100 @@ fn stake_should_fail_when_tokens_are_already_staked() { ); }); } + +#[test] +fn staking_should_assign_less_action_points_when_portion_of_staking_lock_is_vested() { + TestNet::reset(); + Hydra::execute_with(|| { + System::set_block_number(0); + init_omnipool(); + assert_ok!(Staking::initialize_staking(RawOrigin::Root.into())); + + let staking_account = pallet_staking::Pallet::::pot_account_id(); + assert_ok!(Currencies::update_balance( + RawOrigin::Root.into(), + staking_account, + HDX, + (10_000 * UNITS) as i128, + )); + + assert_ok!(Currencies::update_balance( + RawOrigin::Root.into(), + vesting_account(), + HDX, + (1_000_000 * UNITS) as i128, + )); + + assert_ok!(Currencies::update_balance( + RawOrigin::Root.into(), + ALICE.into(), + HDX, + (1_000_000 * UNITS) as i128, + )); + + assert_ok!(Currencies::update_balance( + RawOrigin::Root.into(), + BOB.into(), + HDX, + (99_000 * UNITS) as i128, + )); + + assert_ok!(Vesting::vested_transfer( + RawOrigin::Root.into(), + BOB.into(), + vesting_schedule() + )); + + assert_eq!(Currencies::free_balance(HDX, &BOB.into()), 200_000 * UNITS); + assert_ok!(Staking::stake( + hydradx_runtime::RuntimeOrigin::signed(BOB.into()), + 100_000 * UNITS + )); + + //Transfer 50% so there is not enough tokens to satify both locks withou overlay. + assert_ok!(Currencies::transfer( + hydradx_runtime::RuntimeOrigin::signed(BOB.into()), + ALICE.into(), + HDX, + 50_000 * UNITS + )); + + let r = begin_referendum(); + + assert_ok!(Democracy::vote( + hydradx_runtime::RuntimeOrigin::signed(BOB.into()), + r, + AccountVote::Standard { + vote: Vote { + aye: true, + conviction: Conviction::Locked6x, + }, + balance: 150_000 * UNITS, + } + )); + end_referendum(); + + let stake_position_id = pallet_staking::Pallet::::get_user_position_id( + &sp_runtime::AccountId32::from(BOB), + ) + .unwrap() + .unwrap(); + let position_votes = + pallet_staking::Pallet::::get_position_votes(stake_position_id).votes; + + assert_eq!(position_votes.len(), 1); + assert_eq!( + position_votes[0].1, + pallet_staking::types::Vote::new(50_000 * UNITS, pallet_staking::types::Conviction::Locked6x) + ); + + assert_ok!(Staking::claim( + hydradx_runtime::RuntimeOrigin::signed(BOB.into()), + stake_position_id + )); + + let position = pallet_staking::Pallet::::positions(stake_position_id).unwrap(); + + assert_eq!(position.get_action_points(), 50_u128); + }); +} diff --git a/pallets/staking/Cargo.toml b/pallets/staking/Cargo.toml index 03437d251..0babe26ba 100644 --- a/pallets/staking/Cargo.toml +++ b/pallets/staking/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pallet-staking" -version = "1.0.1" +version = "2.0.0" authors = ['GalacticCouncil'] edition = "2021" license = "Apache-2.0" diff --git a/pallets/staking/src/integrations/democracy.rs b/pallets/staking/src/integrations/democracy.rs index 30299f56d..d44674666 100644 --- a/pallets/staking/src/integrations/democracy.rs +++ b/pallets/staking/src/integrations/democracy.rs @@ -1,12 +1,13 @@ use crate::pallet::{PositionVotes, Positions}; -use crate::traits::DemocracyReferendum; +use crate::traits::{DemocracyReferendum, VestingDetails}; use crate::types::{Balance, Conviction, Vote}; use crate::{Config, Error, Pallet}; use frame_support::defensive; use frame_support::dispatch::DispatchResult; -use orml_traits::MultiCurrencyExtended; +use orml_traits::{MultiCurrency, MultiCurrencyExtended}; use pallet_democracy::traits::DemocracyHooks; use pallet_democracy::{AccountVote, ReferendumIndex, ReferendumInfo}; +use sp_core::Get; pub struct StakingDemocracy(sp_std::marker::PhantomData); @@ -28,7 +29,7 @@ where let e = crate::Error::::InconsistentState(crate::InconsistentStateError::PositionNotFound); defensive!(e); - //NOTE: This is intetional, user can't recover from this state and we don't want + //NOTE: This is intentional, user can't recover from this state and we don't want //to block voting. return Ok(()); } @@ -51,8 +52,17 @@ where Conviction::default() }; + // We are capping vote by min(position stake, user's balance - vested amount - locked + // rewards). + // Sub of vested and lockek rewards is necessary because locks overlay so users may end + // up in the situation where portion of the staking lock is also vested or locked + // rewads and we don't want to assign points for it. + let max_vote = T::Currency::free_balance(T::NativeAssetId::get(), who) + .saturating_sub(T::Vesting::locked(who.clone())) + .saturating_sub(position.accumulated_locked_rewards) + .min(position.stake); let staking_vote = Vote { - amount: amount.min(position.stake), // use only max staked amount + amount: amount.min(position.stake).min(max_vote), conviction, }; @@ -87,7 +97,7 @@ where let e = crate::Error::::InconsistentState(crate::InconsistentStateError::PositionNotFound); defensive!(e); - //NOTE: This is intetional, user can't recover from this state and we don't want + //NOTE: This is intentional, user can't recover from this state and we don't want //to block voting. return Ok(()); } @@ -102,8 +112,11 @@ where #[cfg(feature = "runtime-benchmarks")] fn on_vote_worst_case(who: &T::AccountId) { + use crate::LockIdentifier; + #[cfg(not(feature = "std"))] + use codec::alloc::string::ToString; use frame_system::Origin; - use sp_core::Get; + use orml_traits::MultiLockableCurrency; T::Currency::update_balance( T::NativeAssetId::get(), @@ -128,6 +141,15 @@ where )); } + for i in 0..::MaxLocks::get() - 5 { + let id: LockIdentifier = scale_info::prelude::format!("{:a>8}", i.to_string()) + .as_bytes() + .try_into() + .unwrap(); + + T::Currency::set_lock(id, T::NativeAssetId::get(), who, 10_000_000_000_000_u128).unwrap(); + } + let voting = crate::types::Voting:: { votes: votes.try_into().unwrap(), }; @@ -138,7 +160,6 @@ where #[cfg(feature = "runtime-benchmarks")] fn on_remove_vote_worst_case(who: &T::AccountId) { use frame_system::Origin; - use sp_core::Get; T::Currency::update_balance( T::NativeAssetId::get(), diff --git a/pallets/staking/src/lib.rs b/pallets/staking/src/lib.rs index 3b0aa5feb..1015dd663 100644 --- a/pallets/staking/src/lib.rs +++ b/pallets/staking/src/lib.rs @@ -172,6 +172,10 @@ pub mod pallet { /// Provides information about amount of vested tokens. type Vesting: VestingDetails; + #[cfg(feature = "runtime-benchmarks")] + /// Max mumber of locks per account. It's used in on_vote_worst_case benchmarks. + type MaxLocks: Get; + /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; } @@ -215,6 +219,7 @@ pub mod pallet { total_stake: Balance, locked_rewards: Balance, slashed_points: Point, + payable_percentage: FixedU128, }, /// Rewards were claimed. @@ -225,6 +230,7 @@ pub mod pallet { unlocked_rewards: Balance, slashed_points: Point, slashed_unpaid_rewards: Balance, + payable_percentage: FixedU128, }, /// Staked amount was withdrawn and NFT was burned. @@ -232,8 +238,6 @@ pub mod pallet { who: T::AccountId, position_id: T::PositionItemId, unlocked_stake: Balance, - rewards: Balance, - unlocked_rewards: Balance, }, /// Staking was initialized. @@ -435,13 +439,14 @@ pub mod pallet { let created_at = Self::get_period_number(position.created_at) .defensive_ok_or::>(InconsistentStateError::Arithmetic.into())?; - let (claimable_rewards, claimable_unpaid_rewards, unpaid_rewards, _) = Self::calculate_rewards( - position, - staking.accumulated_reward_per_stake, - current_period, - created_at, - ) - .ok_or(Error::::Arithmetic)?; + let (claimable_rewards, claimable_unpaid_rewards, unpaid_rewards, payable_percentage) = + Self::calculate_rewards( + position, + staking.accumulated_reward_per_stake, + current_period, + created_at, + ) + .ok_or(Error::::Arithmetic)?; let rewards = claimable_rewards .checked_add(claimable_unpaid_rewards) @@ -500,6 +505,7 @@ pub mod pallet { total_stake: position.stake, locked_rewards: rewards, slashed_points: slash_points, + payable_percentage, }); Ok(()) @@ -510,7 +516,7 @@ pub mod pallet { /// Claim rewards accumulated for specific staking position. /// /// Function calculates amount of rewards to pay for specified staking position based on - /// the amount of points position accumulated. Function also unlocks portion of the rewards locked + /// the amount of points position accumulated. Function also unlocks all the rewards locked /// from `increase_stake` based on the amount of the points. /// /// This action is penalized by removing all the points and returning allocated unpaid rewards @@ -561,13 +567,8 @@ pub mod pallet { let pot = Self::pot_account_id(); T::Currency::transfer(T::NativeAssetId::get(), &pot, &who, rewards_to_pay)?; - let rewards_to_unlock = - math::calculate_percentage_amount(position.accumulated_locked_rewards, payable_percentage); - - position.accumulated_locked_rewards = position - .accumulated_locked_rewards - .checked_sub(rewards_to_unlock) - .ok_or(Error::::Arithmetic)?; + let rewards_to_unlock = position.accumulated_locked_rewards; + position.accumulated_locked_rewards = Zero::zero(); position.accumulated_unpaid_rewards = position .accumulated_unpaid_rewards @@ -617,6 +618,7 @@ pub mod pallet { unlocked_rewards: rewards_to_unlock, slashed_points: points_to_slash, slashed_unpaid_rewards, + payable_percentage, }); Ok(()) @@ -634,7 +636,7 @@ pub mod pallet { /// Parameters: /// - `position_id`: The identifier of the position to be destroyed. /// - /// Emits `Unstaked` event when successful. + /// Emits `RewardsClaimed` and `Unstaked` events when successful. /// #[pallet::call_index(4)] #[pallet::weight(::WeightInfo::unstake())] @@ -660,13 +662,14 @@ pub mod pallet { let created_at = Self::get_period_number(position.created_at) .defensive_ok_or::>(InconsistentStateError::Arithmetic.into())?; - let (claimable_rewards, claimable_unpaid_rewards, unpaid_rewards, _) = Self::calculate_rewards( - position, - staking.accumulated_reward_per_stake, - current_period, - created_at, - ) - .ok_or(Error::::Arithmetic)?; + let (claimable_rewards, claimable_unpaid_rewards, unpaid_rewards, payable_percentage) = + Self::calculate_rewards( + position, + staking.accumulated_reward_per_stake, + current_period, + created_at, + ) + .ok_or(Error::::Arithmetic)?; let rewards_to_pay = claimable_rewards .checked_add(claimable_unpaid_rewards) @@ -697,12 +700,21 @@ pub mod pallet { T::NFTHandler::burn(&T::NFTCollectionId::get(), &position_id, Some(&who))?; T::Currency::remove_lock(STAKING_LOCK_ID, T::NativeAssetId::get(), &who)?; + Self::deposit_event(Event::RewardsClaimed { + who: who.clone(), + position_id, + paid_rewards: rewards_to_pay, + unlocked_rewards: position.accumulated_locked_rewards, + slashed_points: Self::get_points(position, current_period, created_at) + .ok_or(Error::::Arithmetic)?, + slashed_unpaid_rewards: return_to_pot, + payable_percentage, + }); + Self::deposit_event(Event::Unstaked { who, position_id, unlocked_stake: position.stake, - rewards: rewards_to_pay, - unlocked_rewards: position.accumulated_locked_rewards, }); PositionVotes::::remove(position_id); @@ -730,14 +742,16 @@ impl Pallet { position: Option<&Position>, ) -> Result<(), DispatchError> { let free_balance = T::Currency::free_balance(T::NativeAssetId::get(), who); - let staked = position.map(|p| p.stake).unwrap_or_default(); + let staked = position + .map(|p| p.stake.saturating_add(p.accumulated_locked_rewards)) + .unwrap_or_default(); let vested = T::Vesting::locked(who.clone()); + //NOTE: locks overlay so vested + staked can be bigger than free_balance let stakeable = free_balance .checked_sub(vested) .ok_or(Error::::Arithmetic)? - .checked_sub(staked) - .ok_or(Error::::Arithmetic)?; + .saturating_sub(staked); ensure!(stakeable >= stake, Error::::InsufficientBalance); diff --git a/pallets/staking/src/tests/claim.rs b/pallets/staking/src/tests/claim.rs index a8051bc9e..5e962e844 100644 --- a/pallets/staking/src/tests/claim.rs +++ b/pallets/staking/src/tests/claim.rs @@ -75,6 +75,7 @@ fn claim_should_work_when_claiming_multiple_times() { unlocked_rewards: 0, slashed_points: 16, slashed_unpaid_rewards: 57_516_815_324_327_787_u128, + payable_percentage: FixedU128::from_inner(828_752_599_443_917_u128), } .into()); @@ -160,6 +161,7 @@ fn claim_should_work_when_staking_position_exists() { unlocked_rewards: 0, slashed_points: 40, slashed_unpaid_rewards: 10_336_797_680_797_565_u128, + payable_percentage: FixedU128::from_inner(31_383_184_812_088_337_u128), } .into()); @@ -327,6 +329,7 @@ fn claim_should_work_when_claiming_after_unclaimable_periods() { unlocked_rewards: 0, slashed_points: 29, slashed_unpaid_rewards: 65_631_977_451_377_841_u128, + payable_percentage: FixedU128::from_inner(8_872_106_273_751_589_u128), } .into()); @@ -407,14 +410,15 @@ fn claim_should_work_when_staked_was_increased() { who: BOB, position_id: bob_position_id, paid_rewards: 17_792_982_258_382_321_u128, - unlocked_rewards: 14_186_603_458_327_466_u128, + unlocked_rewards: 46_073_370_138_355_002_u128, slashed_points: 77, slashed_unpaid_rewards: 39_992_706_885_866_227_u128, + payable_percentage: FixedU128::from_inner(307_913_300_366_917_409_u128), } .into()); - assert_unlocked_balance!(&BOB, HDX, 281_979_585_716_709_787_u128); - assert_hdx_lock!(BOB, 281_886_766_680_027_536_u128, STAKING_LOCK); + assert_unlocked_balance!(&BOB, HDX, 313_866_352_396_737_323_u128); + assert_hdx_lock!(BOB, 250_000 * ONE, STAKING_LOCK); assert_eq!( Staking::positions(bob_position_id).unwrap(), Position { @@ -423,7 +427,7 @@ fn claim_should_work_when_staked_was_increased() { created_at: 1_452_987, reward_per_stake: FixedU128::from_inner(3_061_853_686_489_680_776_u128), accumulated_slash_points: 104, - accumulated_locked_rewards: 31_886_766_680_027_536_u128, + accumulated_locked_rewards: Zero::zero(), accumulated_unpaid_rewards: Zero::zero(), } ); @@ -495,11 +499,12 @@ fn claim_should_claim_zero_rewards_when_claiming_in_same_block_without_additiona unlocked_rewards: 0, slashed_points: 0, slashed_unpaid_rewards: 27_771_941_672_360_647_u128, + payable_percentage: FixedU128::from_inner(0_u128), } .into()); - assert_unlocked_balance!(&BOB, HDX, 281_979_585_716_709_787_u128); - assert_hdx_lock!(BOB, 281_886_766_680_027_536_u128, STAKING_LOCK); + assert_unlocked_balance!(&BOB, HDX, 313_866_352_396_737_323_u128); + assert_hdx_lock!(BOB, 250_000 * ONE, STAKING_LOCK); assert_eq!( Staking::positions(1).unwrap(), Position { @@ -508,7 +513,7 @@ fn claim_should_claim_zero_rewards_when_claiming_in_same_block_without_additiona created_at: 1_452_987, reward_per_stake: FixedU128::from_inner(3_172_941_453_179_123_366_u128), accumulated_slash_points: 104, - accumulated_locked_rewards: 31_886_766_680_027_536_u128, + accumulated_locked_rewards: Zero::zero(), accumulated_unpaid_rewards: Zero::zero(), } ); diff --git a/pallets/staking/src/tests/increase_stake.rs b/pallets/staking/src/tests/increase_stake.rs index de62cdf75..300e80d2e 100644 --- a/pallets/staking/src/tests/increase_stake.rs +++ b/pallets/staking/src/tests/increase_stake.rs @@ -132,7 +132,8 @@ fn increase_stake_should_work_when_user_already_staked() { stake: 100_000 * ONE, total_stake: 200_000 * ONE, locked_rewards: 432_086_451_705_829_u128, - slashed_points: 12 + slashed_points: 12, + payable_percentage: FixedU128::from_inner(4_181_481_790_701_572_u128) } .into()); assert_staking_data!( @@ -188,7 +189,8 @@ fn increase_stake_should_slash_no_points_when_increase_is_small() { stake: 10 * ONE, total_stake: 100_010 * ONE, locked_rewards: 432_086_451_705_829_u128, - slashed_points: 0 + slashed_points: 0, + payable_percentage: FixedU128::from_inner(4_181_481_790_701_572_u128) } .into()); assert_eq!( @@ -231,6 +233,7 @@ fn increase_stake_should_slash_all_points_when_increase_is_big() { total_stake: 15_100_000 * ONE, locked_rewards: 432_086_451_705_829_u128, slashed_points: 24, + payable_percentage: FixedU128::from_inner(4_181_481_790_701_572_u128) } .into()); assert_eq!( @@ -272,7 +275,8 @@ fn increase_stake_should_accumulate_slash_points_when_called_multiple_times() { stake: 100_000 * ONE, total_stake: 200_000 * ONE, locked_rewards: 432_086_451_705_829_u128, - slashed_points: 12 + slashed_points: 12, + payable_percentage: FixedU128::from_inner(4_181_481_790_701_572_u128) } .into()); assert_eq!( @@ -294,7 +298,8 @@ fn increase_stake_should_accumulate_slash_points_when_called_multiple_times() { stake: 100_000 * ONE, total_stake: 300_000 * ONE, locked_rewards: 26_998_317_793_092_u128, - slashed_points: 3 + slashed_points: 3, + payable_percentage: FixedU128::from_inner(262_371_143_317_147_u128) } .into()); assert_eq!( @@ -318,7 +323,8 @@ fn increase_stake_should_accumulate_slash_points_when_called_multiple_times() { stake: 100_000 * ONE, total_stake: 400_000 * ONE, locked_rewards: 506_092_568_094_174_u128, - slashed_points: 4 + slashed_points: 4, + payable_percentage: FixedU128::from_inner(4_919_526_267_840_874_u128) } .into()); assert_staking_data!( @@ -390,3 +396,114 @@ fn increase_stake_should_not_work_when_tokens_are_are_alredy_staked() { ); }); } + +#[test] +fn increase_stake_should_not_work_when_staking_locked_rewards() { + ExtBuilder::default() + .with_endowed_accounts(vec![(ALICE, HDX, 250_000 * ONE), (BOB, HDX, 150_000 * ONE)]) + .with_initialized_staking() + .with_stakes(vec![ + (ALICE, 100_000 * ONE, 1_452_987, 1_000_000 * ONE), + (BOB, 50_000 * ONE, 1_452_987, 1_000_000 * ONE), + ]) + .start_at_block(1_452_987) + .build() + .execute_with(|| { + //Arrange + set_pending_rewards(1_000_000 * ONE); + set_block_number(1_600_000); + + let alice_position_id = 0; + let alice_locked_rewards = 11_150_618_108_537_525_u128; + //1-th increase to receive locked rewards + assert_ok!(Staking::increase_stake( + RuntimeOrigin::signed(ALICE), + alice_position_id, + 100_000 * ONE + )); + + assert_last_event!(Event::::StakeAdded { + who: ALICE, + position_id: alice_position_id, + stake: 100_000 * ONE, + total_stake: 200_000 * ONE, + locked_rewards: alice_locked_rewards, + slashed_points: 12, + payable_percentage: FixedU128::from_inner(4_181_481_790_701_572_u128) + } + .into()); + + assert_eq!(Tokens::free_balance(HDX, &ALICE), 250_000 * ONE + alice_locked_rewards); + + //NOTE: balance structure: 200K locked in staking + ~11K locked in staking rewards + //total balance is ~260K, Alice is trying to stake 60K from which 11K is locked in + //rewards. + //Act + assert_noop!( + Staking::increase_stake( + RuntimeOrigin::signed(ALICE), + alice_position_id, + //NOTE: Alice has 50K unlocked + ~11k as locked rewards + 60_000 * ONE + ), + Error::::InsufficientBalance + ); + }); +} + +#[test] +fn increase_stake_should_not_return_arithmetic_error_when_vested_and_locked_rewards_are_bigger_than_free_balance() { + ExtBuilder::default() + .with_endowed_accounts(vec![(VESTED_100K, HDX, 250_000 * ONE), (BOB, HDX, 150_000 * ONE)]) + .with_initialized_staking() + .with_stakes(vec![ + (VESTED_100K, 100_000 * ONE, 1_452_987, 1_000_000 * ONE), + (BOB, 50_000 * ONE, 1_452_987, 1_000_000 * ONE), + ]) + .start_at_block(1_452_987) + .build() + .execute_with(|| { + //Arrange + set_pending_rewards(1_000_000 * ONE); + set_block_number(1_600_000); + + let vested_position_id = 0; + let vested_locked_rewards = 11_150_618_108_537_525_u128; + //1-th increase to receive locked rewards + assert_ok!(Staking::increase_stake( + RuntimeOrigin::signed(VESTED_100K), + vested_position_id, + 25_000 * ONE + )); + + assert_last_event!(Event::::StakeAdded { + who: VESTED_100K, + position_id: vested_position_id, + stake: 25_000 * ONE, + total_stake: 125_000 * ONE, + locked_rewards: vested_locked_rewards, + slashed_points: 3, + payable_percentage: FixedU128::from_inner(4_181_481_790_701_572_u128) + } + .into()); + + Tokens::transfer(RuntimeOrigin::signed(VESTED_100K), ALICE, HDX, 100_000 * ONE).unwrap(); + assert_eq!( + Tokens::free_balance(HDX, &VESTED_100K), + 150_000 * ONE + vested_locked_rewards + ); + + //NOTE: balance structure: 125K locked in staking + ~11K locked in staking rewards + //+100K in vesting => sum of locked tokens is bigger than user's balance. + //Act + assert_noop!( + Staking::increase_stake( + RuntimeOrigin::signed(VESTED_100K), + vested_position_id, + //NOTE: Alice has 25K unlocked + ~11k as locked rewards + 25_000 * ONE + ), + Error::::InsufficientBalance + ); + }); +} diff --git a/pallets/staking/src/tests/mock.rs b/pallets/staking/src/tests/mock.rs index 950f51a23..21bf003ad 100644 --- a/pallets/staking/src/tests/mock.rs +++ b/pallets/staking/src/tests/mock.rs @@ -225,6 +225,9 @@ impl pallet_staking::Config for Test { type Vesting = DummyVesting; type Collections = FreezableUniques; type AuthorityOrigin = EnsureRoot; + + #[cfg(feature = "runtime-benchmarks")] + type MaxLocks = MaxLocks; } pub struct DummyMaxPointsPerAction; diff --git a/pallets/staking/src/tests/tests.rs b/pallets/staking/src/tests/tests.rs index 7acde292c..e85267105 100644 --- a/pallets/staking/src/tests/tests.rs +++ b/pallets/staking/src/tests/tests.rs @@ -747,3 +747,140 @@ fn process_votes_should_calculate_action_points_corectly_when_referendum_is_fini assert_eq!(PositionVotes::::get(position_id).votes.len(), 0); }); } + +#[test] +fn democracy_hook_vote_cap_should_work() { + //Locks OVERLAY so 1000 tokens lock and 100 tokens lock results in 1000 tokens locked in total. + use pallet_democracy::{Conviction as Dconviction, Vote as Dvote}; + ExtBuilder::default() + .with_endowed_accounts(vec![ + (ALICE, HDX, 150_000 * ONE), + (BOB, HDX, 250_000 * ONE), + (CHARLIE, HDX, 10_000 * ONE), + (DAVE, HDX, 100_000 * ONE), + (VESTED_100K, HDX, 180_000 * ONE), + ]) + .start_at_block(1_452_987) + .with_initialized_staking() + .with_stakes(vec![ + (ALICE, 100_000 * ONE, 1_452_987, 200_000 * ONE), + (BOB, 120_000 * ONE, 1_452_987, 0), + (CHARLIE, 10_000 * ONE, 1_455_000, 10_000 * ONE), + (DAVE, 10 * ONE, 1_465_000, 1), + (VESTED_100K, 80_000 * ONE, 1_465_000, 10_000 * ONE), + ]) + .build() + .execute_with(|| { + //Arrange + let vested_position_id = 4; + let ref_idx: u32 = 1; + let v = AccountVote::Standard { + vote: Dvote { + aye: true, + conviction: Dconviction::Locked6x, + }, + balance: 100_000 * ONE, + }; + + assert_eq!(Staking::position_votes(vested_position_id).votes.len(), 0); + + //Act - happy path, user have enough token for staking and vesting. + assert_ok!(StakingDemocracy::::on_vote(&VESTED_100K, ref_idx, v)); + + //Assert + let staking_votes = Staking::position_votes(vested_position_id).votes; + + assert_eq!(staking_votes.len(), 1); + assert_eq!(staking_votes[0].1, Vote::new(80_000 * ONE, Conviction::Locked6x)); + + //Assert 2 - 1 token is missing to fully satisfy both locks + PositionVotes::::remove(vested_position_id); + Tokens::transfer(RuntimeOrigin::signed(VESTED_100K), ALICE, HDX, 1).unwrap(); + + //Act + assert_ok!(StakingDemocracy::::on_vote(&VESTED_100K, ref_idx, v)); + + //Assert + let staking_votes = Staking::position_votes(vested_position_id).votes; + + assert_eq!(staking_votes.len(), 1); + assert_eq!(staking_votes[0].1, Vote::new(80_000 * ONE - 1, Conviction::Locked6x)); + + //Assert 3 - only vesting lock is satisfied + PositionVotes::::remove(vested_position_id); + Tokens::transfer(RuntimeOrigin::signed(VESTED_100K), ALICE, HDX, 80_000 * ONE - 1).unwrap(); + + assert_eq!(Tokens::free_balance(HDX, &VESTED_100K), 100_000 * ONE); + + //Act 3 + assert_ok!(StakingDemocracy::::on_vote(&VESTED_100K, ref_idx, v)); + + //Assert + let staking_votes = Staking::position_votes(vested_position_id).votes; + + assert_eq!(staking_votes.len(), 1); + assert_eq!(staking_votes[0].1, Vote::new(0, Conviction::Locked6x)); + + //Assert 4 - portion of the lock are locked rewards + PositionVotes::::remove(vested_position_id); + Tokens::transfer(RuntimeOrigin::signed(ALICE), VESTED_100K, HDX, 20_000 * ONE).unwrap(); + + let p = Staking::positions(vested_position_id).unwrap(); + Positions::::insert( + vested_position_id, + Position { + accumulated_locked_rewards: 10_000 * ONE, + ..p + }, + ); + + assert_eq!(Tokens::free_balance(HDX, &VESTED_100K), 120_000 * ONE); + let v = AccountVote::Standard { + vote: Dvote { + aye: true, + conviction: Dconviction::Locked6x, + }, + balance: 120_000 * ONE, + }; + + //Act 4 + assert_ok!(StakingDemocracy::::on_vote(&VESTED_100K, ref_idx, v)); + + //Assert + let staking_votes = Staking::position_votes(vested_position_id).votes; + + assert_eq!(staking_votes.len(), 1); + assert_eq!(staking_votes[0].1, Vote::new(10_000 * ONE, Conviction::Locked6x)); + + //Assert 5 - sum of vested and locked rewards is bigger than account's balance + PositionVotes::::remove(vested_position_id); + Tokens::transfer(RuntimeOrigin::signed(VESTED_100K), ALICE, HDX, 20_000 * ONE).unwrap(); + + let p = Staking::positions(vested_position_id).unwrap(); + Positions::::insert( + vested_position_id, + Position { + accumulated_locked_rewards: 10_000 * ONE, + ..p + }, + ); + + assert_eq!(Tokens::free_balance(HDX, &VESTED_100K), 100_000 * ONE); + let v = AccountVote::Standard { + vote: Dvote { + aye: true, + conviction: Dconviction::Locked6x, + }, + balance: 100_000 * ONE, + }; + + //Act 5 + assert_ok!(StakingDemocracy::::on_vote(&VESTED_100K, ref_idx, v)); + + //Assert + let staking_votes = Staking::position_votes(vested_position_id).votes; + + assert_eq!(staking_votes.len(), 1); + assert_eq!(staking_votes[0].1, Vote::new(0, Conviction::Locked6x)); + }); +} diff --git a/pallets/staking/src/tests/unstake.rs b/pallets/staking/src/tests/unstake.rs index 47322f793..1dcec386e 100644 --- a/pallets/staking/src/tests/unstake.rs +++ b/pallets/staking/src/tests/unstake.rs @@ -61,7 +61,6 @@ fn unstake_should_not_work_when_staking_is_not_initialized() { ); }); } - #[test] fn unstake_should_work_when_staking_position_exists() { ExtBuilder::default() @@ -90,12 +89,23 @@ fn unstake_should_work_when_staking_position_exists() { assert_ok!(Staking::unstake(RuntimeOrigin::signed(BOB), bob_position_id)); //Assert + assert!(has_event( + Event::::RewardsClaimed { + who: BOB, + position_id: bob_position_id, + paid_rewards: 334_912_244_857_841_u128, + unlocked_rewards: 0, + slashed_points: 40, + slashed_unpaid_rewards: 10_336_797_680_797_565_u128, + payable_percentage: FixedU128::from_inner(31_383_184_812_088_337_u128) + } + .into() + )); + assert_last_event!(Event::::Unstaked { who: BOB, position_id: bob_position_id, unlocked_stake: 120_000 * ONE, - rewards: 334_912_244_857_841_u128, - unlocked_rewards: 0 } .into()); @@ -141,12 +151,23 @@ fn unstake_should_claim_zero_rewards_when_unstaking_during_unclaimable_periods() assert_ok!(Staking::unstake(RuntimeOrigin::signed(BOB), bob_position_id)); //Assert + assert!(has_event( + Event::::RewardsClaimed { + who: BOB, + position_id: bob_position_id, + paid_rewards: 0_u128, + unlocked_rewards: 0, + slashed_points: 3, + slashed_unpaid_rewards: 10_671_709_925_655_406_u128, + payable_percentage: FixedU128::from(0_u128) + } + .into() + )); + assert_last_event!(Event::::Unstaked { who: BOB, position_id: bob_position_id, unlocked_stake: 120_000 * ONE, - rewards: 0, - unlocked_rewards: 0 } .into()); assert_unlocked_balance!(&BOB, HDX, 250_000 * ONE); @@ -192,12 +213,22 @@ fn unstake_should_work_when_called_after_unclaimable_periods_and_stake_was_incre assert_ok!(Staking::unstake(RuntimeOrigin::signed(BOB), bob_position_id)); //Assert + assert!(has_event( + Event::::RewardsClaimed { + who: BOB, + position_id: bob_position_id, + paid_rewards: 586_654_644_470_047_u128, + unlocked_rewards: 95_992_170_755_783_u128, + slashed_points: 29, + slashed_unpaid_rewards: 65_536_836_933_362_451_u128, + payable_percentage: FixedU128::from_inner(8_872_106_273_751_589_u128) + } + .into() + )); assert_last_event!(Event::::Unstaked { who: BOB, position_id: bob_position_id, unlocked_stake: 420_000 * ONE, - rewards: 586_654_644_470_047_u128, - unlocked_rewards: 95_992_170_755_783_u128 } .into()); assert_unlocked_balance!(&BOB, HDX, 500_682_646_815_225_830_u128); @@ -246,12 +277,23 @@ fn unstake_should_claim_no_additional_rewards_when_called_immediately_after_clai assert_ok!(Staking::unstake(RuntimeOrigin::signed(BOB), bob_position_id)); //Assert + assert!(has_event( + Event::::RewardsClaimed { + who: BOB, + position_id: bob_position_id, + paid_rewards: 0_u128, + unlocked_rewards: 0_u128, + slashed_points: 0, + slashed_unpaid_rewards: 51_933_872_025_079_204_u128, + payable_percentage: FixedU128::from_inner(0_u128) + } + .into() + )); + assert_last_event!(Event::::Unstaked { who: BOB, position_id: bob_position_id, unlocked_stake: 420_000 * ONE, - rewards: 0, - unlocked_rewards: 95_140_518_015_390_u128, } .into()); assert_unlocked_balance!(&BOB, HDX, bob_balance); @@ -299,39 +341,87 @@ fn unstake_should_work_when_called_by_all_stakers() { //Act assert_ok!(Staking::unstake(RuntimeOrigin::signed(BOB), bob_position_id)); //Assert + assert!(has_event( + Event::::RewardsClaimed { + who: BOB, + position_id: bob_position_id, + paid_rewards: 586_654_644_470_047_u128, + unlocked_rewards: 95_992_170_755_783_u128, + slashed_points: 29, + slashed_unpaid_rewards: 65_536_836_933_362_451_u128, + payable_percentage: FixedU128::from_inner(8_872_106_273_751_589_u128) + } + .into() + )); + assert_last_event!(Event::::Unstaked { who: BOB, position_id: bob_position_id, unlocked_stake: 420_000 * ONE, - rewards: 586_654_644_470_047_u128, - unlocked_rewards: 95_992_170_755_783_u128, } .into()); + + //Act assert_ok!(Staking::unstake(RuntimeOrigin::signed(ALICE), alice_position_id)); + //Assert + assert!(has_event( + Event::::RewardsClaimed { + who: ALICE, + position_id: alice_position_id, + paid_rewards: 7_965_081_713_348_758_u128, + unlocked_rewards: 0_u128, + slashed_points: 38, + slashed_unpaid_rewards: 301_821_938_567_408_560_u128, + payable_percentage: FixedU128::from_inner(25_711_476_569_063_717_u128) + } + .into() + )); assert_last_event!(Event::::Unstaked { who: ALICE, position_id: alice_position_id, unlocked_stake: 100_000 * ONE, - rewards: 7_965_081_713_348_758_u128, - unlocked_rewards: 0 } .into()); + + //Act assert_ok!(Staking::unstake(RuntimeOrigin::signed(CHARLIE), charlie_position_id)); + //Assert + assert!(has_event( + Event::::RewardsClaimed { + who: CHARLIE, + position_id: charlie_position_id, + paid_rewards: 8_023_126_771_488_456_u128, + unlocked_rewards: 0_u128, + slashed_points: 38, + slashed_unpaid_rewards: 304_021_447_951_301_121_u128, + payable_percentage: FixedU128::from_inner(25_711_476_569_063_717_u128) + } + .into() + )); assert_last_event!(Event::::Unstaked { who: CHARLIE, position_id: charlie_position_id, unlocked_stake: 10_000 * ONE, - rewards: 8_023_126_771_488_456_u128, - unlocked_rewards: 0 } .into()); + assert_ok!(Staking::unstake(RuntimeOrigin::signed(DAVE), dave_position_id)); + assert!(has_event( + Event::::RewardsClaimed { + who: DAVE, + position_id: dave_position_id, + paid_rewards: 5_672_178_270_331_647_u128, + unlocked_rewards: 0_u128, + slashed_points: 35, + slashed_unpaid_rewards: 298_656_966_429_605_307_u128, + payable_percentage: FixedU128::from_inner(18_638_301_224_564_978_u128) + } + .into() + )); assert_last_event!(Event::::Unstaked { who: DAVE, position_id: dave_position_id, unlocked_stake: 10 * ONE, - rewards: 5_672_178_270_331_647_u128, - unlocked_rewards: 0 } .into()); diff --git a/runtime/hydradx/Cargo.toml b/runtime/hydradx/Cargo.toml index b8e1f245f..4d36357fe 100644 --- a/runtime/hydradx/Cargo.toml +++ b/runtime/hydradx/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "hydradx-runtime" -version = "182.0.0" +version = "183.0.0" authors = ["GalacticCouncil"] edition = "2021" license = "Apache 2.0" diff --git a/runtime/hydradx/src/assets.rs b/runtime/hydradx/src/assets.rs index ef408fae8..f8c922620 100644 --- a/runtime/hydradx/src/assets.rs +++ b/runtime/hydradx/src/assets.rs @@ -863,6 +863,9 @@ impl pallet_staking::Config for Runtime { type MaxPointsPerAction = PointsPerAction; type Vesting = VestingInfo; type WeightInfo = weights::staking::HydraWeight; + + #[cfg(feature = "runtime-benchmarks")] + type MaxLocks = MaxLocks; } // LBP diff --git a/runtime/hydradx/src/lib.rs b/runtime/hydradx/src/lib.rs index 42cc5ddf5..c7ffe6dd6 100644 --- a/runtime/hydradx/src/lib.rs +++ b/runtime/hydradx/src/lib.rs @@ -94,7 +94,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("hydradx"), impl_name: create_runtime_str!("hydradx"), authoring_version: 1, - spec_version: 182, + spec_version: 183, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1, diff --git a/runtime/hydradx/src/weights/democracy.rs b/runtime/hydradx/src/weights/democracy.rs index 3f9e25a4e..113a03179 100644 --- a/runtime/hydradx/src/weights/democracy.rs +++ b/runtime/hydradx/src/weights/democracy.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_democracy //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-08-08, STEPS: 5, REPEAT: 20, LOW RANGE: [], HIGH RANGE: [] +//! DATE: 2023-09-21, STEPS: 5, REPEAT: 20, LOW RANGE: [], HIGH RANGE: [] //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -61,16 +61,16 @@ impl WeightInfo for HydraWeight { // Storage: Democracy DepositOf (r:0 w:1) // Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) fn propose() -> Weight { - // Minimum execution time: 45_202 nanoseconds. - Weight::from_ref_time(45_797_000 as u64) + // Minimum execution time: 45_683 nanoseconds. + Weight::from_ref_time(46_213_000 as u64) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Democracy DepositOf (r:1 w:1) // Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) fn second() -> Weight { - // Minimum execution time: 41_735 nanoseconds. - Weight::from_ref_time(42_204_000 as u64) + // Minimum execution time: 41_709 nanoseconds. + Weight::from_ref_time(42_180_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -87,8 +87,8 @@ impl WeightInfo for HydraWeight { // Storage: Staking PositionVotes (r:1 w:1) // Proof: Staking PositionVotes (max_values: None, max_size: Some(2134), added: 4609, mode: MaxEncodedLen) fn vote_new() -> Weight { - // Minimum execution time: 415_335 nanoseconds. - Weight::from_ref_time(417_879_000 as u64) + // Minimum execution time: 416_420 nanoseconds. + Weight::from_ref_time(420_164_000 as u64) .saturating_add(T::DbWeight::get().reads(106 as u64)) .saturating_add(T::DbWeight::get().writes(5 as u64)) } @@ -105,8 +105,8 @@ impl WeightInfo for HydraWeight { // Storage: Staking PositionVotes (r:1 w:1) // Proof: Staking PositionVotes (max_values: None, max_size: Some(2134), added: 4609, mode: MaxEncodedLen) fn vote_existing() -> Weight { - // Minimum execution time: 419_343 nanoseconds. - Weight::from_ref_time(422_126_000 as u64) + // Minimum execution time: 415_618 nanoseconds. + Weight::from_ref_time(418_917_000 as u64) .saturating_add(T::DbWeight::get().reads(106 as u64)) .saturating_add(T::DbWeight::get().writes(5 as u64)) } @@ -115,8 +115,8 @@ impl WeightInfo for HydraWeight { // Storage: Democracy Cancellations (r:1 w:1) // Proof: Democracy Cancellations (max_values: None, max_size: Some(33), added: 2508, mode: MaxEncodedLen) fn emergency_cancel() -> Weight { - // Minimum execution time: 21_493 nanoseconds. - Weight::from_ref_time(21_911_000 as u64) + // Minimum execution time: 22_130 nanoseconds. + Weight::from_ref_time(22_516_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } @@ -133,8 +133,8 @@ impl WeightInfo for HydraWeight { // Storage: Democracy Blacklist (r:0 w:1) // Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) fn blacklist() -> Weight { - // Minimum execution time: 102_539 nanoseconds. - Weight::from_ref_time(103_630_000 as u64) + // Minimum execution time: 102_512 nanoseconds. + Weight::from_ref_time(103_621_000 as u64) .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(7 as u64)) } @@ -143,22 +143,22 @@ impl WeightInfo for HydraWeight { // Storage: Democracy Blacklist (r:1 w:0) // Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) fn external_propose() -> Weight { - // Minimum execution time: 15_681 nanoseconds. - Weight::from_ref_time(16_102_000 as u64) + // Minimum execution time: 15_705 nanoseconds. + Weight::from_ref_time(16_110_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Democracy NextExternal (r:0 w:1) // Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) fn external_propose_majority() -> Weight { - // Minimum execution time: 4_835 nanoseconds. - Weight::from_ref_time(5_055_000 as u64).saturating_add(T::DbWeight::get().writes(1 as u64)) + // Minimum execution time: 5_151 nanoseconds. + Weight::from_ref_time(5_478_000 as u64).saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Democracy NextExternal (r:0 w:1) // Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) fn external_propose_default() -> Weight { - // Minimum execution time: 5_159 nanoseconds. - Weight::from_ref_time(5_314_000 as u64).saturating_add(T::DbWeight::get().writes(1 as u64)) + // Minimum execution time: 5_449 nanoseconds. + Weight::from_ref_time(5_654_000 as u64).saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Democracy NextExternal (r:1 w:1) // Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) @@ -167,8 +167,8 @@ impl WeightInfo for HydraWeight { // Storage: Democracy ReferendumInfoOf (r:0 w:1) // Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) fn fast_track() -> Weight { - // Minimum execution time: 20_795 nanoseconds. - Weight::from_ref_time(21_236_000 as u64) + // Minimum execution time: 21_249 nanoseconds. + Weight::from_ref_time(21_560_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -177,8 +177,8 @@ impl WeightInfo for HydraWeight { // Storage: Democracy Blacklist (r:1 w:1) // Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) fn veto_external() -> Weight { - // Minimum execution time: 28_250 nanoseconds. - Weight::from_ref_time(28_816_000 as u64) + // Minimum execution time: 27_789 nanoseconds. + Weight::from_ref_time(28_426_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } @@ -189,16 +189,16 @@ impl WeightInfo for HydraWeight { // Storage: System Account (r:2 w:2) // Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn cancel_proposal() -> Weight { - // Minimum execution time: 81_716 nanoseconds. - Weight::from_ref_time(82_843_000 as u64) + // Minimum execution time: 81_206 nanoseconds. + Weight::from_ref_time(81_785_000 as u64) .saturating_add(T::DbWeight::get().reads(4 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: Democracy ReferendumInfoOf (r:0 w:1) // Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) fn cancel_referendum() -> Weight { - // Minimum execution time: 11_461 nanoseconds. - Weight::from_ref_time(11_578_000 as u64).saturating_add(T::DbWeight::get().writes(1 as u64)) + // Minimum execution time: 12_168 nanoseconds. + Weight::from_ref_time(12_379_000 as u64).saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Democracy LowestUnbaked (r:1 w:1) // Proof: Democracy LowestUnbaked (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -208,9 +208,9 @@ impl WeightInfo for HydraWeight { // Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) /// The range of component `r` is `[0, 99]`. fn on_initialize_base(r: u32) -> Weight { - // Minimum execution time: 6_229 nanoseconds. - Weight::from_ref_time(7_538_568 as u64) // Standard Error: 9_282 - .saturating_add(Weight::from_ref_time(3_335_430 as u64).saturating_mul(r as u64)) + // Minimum execution time: 6_027 nanoseconds. + Weight::from_ref_time(7_967_274 as u64) // Standard Error: 15_297 + .saturating_add(Weight::from_ref_time(3_181_785 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(1 as u64)) @@ -229,9 +229,9 @@ impl WeightInfo for HydraWeight { // Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) /// The range of component `r` is `[0, 99]`. fn on_initialize_base_with_launch_period(r: u32) -> Weight { - // Minimum execution time: 9_565 nanoseconds. - Weight::from_ref_time(12_117_854 as u64) // Standard Error: 13_146 - .saturating_add(Weight::from_ref_time(3_289_524 as u64).saturating_mul(r as u64)) + // Minimum execution time: 9_463 nanoseconds. + Weight::from_ref_time(11_351_448 as u64) // Standard Error: 20_855 + .saturating_add(Weight::from_ref_time(3_232_061 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(5 as u64)) .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(1 as u64)) @@ -244,9 +244,9 @@ impl WeightInfo for HydraWeight { // Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) /// The range of component `r` is `[0, 99]`. fn delegate(r: u32) -> Weight { - // Minimum execution time: 44_605 nanoseconds. - Weight::from_ref_time(48_411_691 as u64) // Standard Error: 14_286 - .saturating_add(Weight::from_ref_time(4_630_028 as u64).saturating_mul(r as u64)) + // Minimum execution time: 44_617 nanoseconds. + Weight::from_ref_time(48_848_842 as u64) // Standard Error: 13_644 + .saturating_add(Weight::from_ref_time(4_709_492 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(4 as u64)) .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(4 as u64)) @@ -258,9 +258,9 @@ impl WeightInfo for HydraWeight { // Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) /// The range of component `r` is `[0, 99]`. fn undelegate(r: u32) -> Weight { - // Minimum execution time: 25_621 nanoseconds. - Weight::from_ref_time(26_831_234 as u64) // Standard Error: 12_723 - .saturating_add(Weight::from_ref_time(4_617_965 as u64).saturating_mul(r as u64)) + // Minimum execution time: 25_601 nanoseconds. + Weight::from_ref_time(28_142_536 as u64) // Standard Error: 15_036 + .saturating_add(Weight::from_ref_time(4_603_513 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(2 as u64)) @@ -269,8 +269,8 @@ impl WeightInfo for HydraWeight { // Storage: Democracy PublicProps (r:0 w:1) // Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) fn clear_public_proposals() -> Weight { - // Minimum execution time: 4_830 nanoseconds. - Weight::from_ref_time(4_933_000 as u64).saturating_add(T::DbWeight::get().writes(1 as u64)) + // Minimum execution time: 5_167 nanoseconds. + Weight::from_ref_time(5_294_000 as u64).saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Democracy VotingOf (r:1 w:1) // Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) @@ -280,9 +280,9 @@ impl WeightInfo for HydraWeight { // Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `r` is `[0, 99]`. fn unlock_remove(r: u32) -> Weight { - // Minimum execution time: 24_431 nanoseconds. - Weight::from_ref_time(28_057_776 as u64) // Standard Error: 9_291 - .saturating_add(Weight::from_ref_time(73_814 as u64).saturating_mul(r as u64)) + // Minimum execution time: 23_905 nanoseconds. + Weight::from_ref_time(27_865_439 as u64) // Standard Error: 10_086 + .saturating_add(Weight::from_ref_time(82_552 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -294,9 +294,9 @@ impl WeightInfo for HydraWeight { // Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `r` is `[0, 99]`. fn unlock_set(r: u32) -> Weight { - // Minimum execution time: 31_169 nanoseconds. - Weight::from_ref_time(31_185_754 as u64) // Standard Error: 1_067 - .saturating_add(Weight::from_ref_time(74_882 as u64).saturating_mul(r as u64)) + // Minimum execution time: 31_411 nanoseconds. + Weight::from_ref_time(31_838_954 as u64) // Standard Error: 803 + .saturating_add(Weight::from_ref_time(61_046 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -310,9 +310,9 @@ impl WeightInfo for HydraWeight { // Proof: Staking PositionVotes (max_values: None, max_size: Some(2134), added: 4609, mode: MaxEncodedLen) /// The range of component `r` is `[1, 100]`. fn remove_vote(r: u32) -> Weight { - // Minimum execution time: 40_102 nanoseconds. - Weight::from_ref_time(42_088_350 as u64) // Standard Error: 5_357 - .saturating_add(Weight::from_ref_time(131_906 as u64).saturating_mul(r as u64)) + // Minimum execution time: 40_945 nanoseconds. + Weight::from_ref_time(43_077_999 as u64) // Standard Error: 5_059 + .saturating_add(Weight::from_ref_time(121_781 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(5 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -326,9 +326,9 @@ impl WeightInfo for HydraWeight { // Proof: Staking PositionVotes (max_values: None, max_size: Some(2134), added: 4609, mode: MaxEncodedLen) /// The range of component `r` is `[1, 100]`. fn remove_other_vote(r: u32) -> Weight { - // Minimum execution time: 40_246 nanoseconds. - Weight::from_ref_time(42_220_431 as u64) // Standard Error: 5_209 - .saturating_add(Weight::from_ref_time(133_473 as u64).saturating_mul(r as u64)) + // Minimum execution time: 41_589 nanoseconds. + Weight::from_ref_time(43_200_170 as u64) // Standard Error: 4_502 + .saturating_add(Weight::from_ref_time(122_627 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(5 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } diff --git a/runtime/hydradx/src/weights/staking.rs b/runtime/hydradx/src/weights/staking.rs index 54f300aa1..5d103f612 100644 --- a/runtime/hydradx/src/weights/staking.rs +++ b/runtime/hydradx/src/weights/staking.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_staking //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-07-18, STEPS: 10, REPEAT: 30, LOW RANGE: [], HIGH RANGE: [] +//! DATE: 2023-09-21, STEPS: 5, REPEAT: 20, LOW RANGE: [], HIGH RANGE: [] //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -26,8 +26,8 @@ // benchmark // pallet // --chain=dev -// --steps=10 -// --repeat=30 +// --steps=5 +// --repeat=20 // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 @@ -61,8 +61,8 @@ impl WeightInfo for HydraWeight { // Storage: Uniques ClassAccount (r:0 w:1) // Proof: Uniques ClassAccount (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) fn initialize_staking() -> Weight { - // Minimum execution time: 45_493 nanoseconds. - Weight::from_ref_time(46_285_000 as u64) + // Minimum execution time: 46_503 nanoseconds. + Weight::from_ref_time(47_119_000 as u64) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -85,8 +85,8 @@ impl WeightInfo for HydraWeight { // Storage: Staking Positions (r:0 w:1) // Proof: Staking Positions (max_values: None, max_size: Some(132), added: 2607, mode: MaxEncodedLen) fn stake() -> Weight { - // Minimum execution time: 93_365 nanoseconds. - Weight::from_ref_time(94_660_000 as u64) + // Minimum execution time: 93_410 nanoseconds. + Weight::from_ref_time(94_534_000 as u64) .saturating_add(T::DbWeight::get().reads(9 as u64)) .saturating_add(T::DbWeight::get().writes(8 as u64)) } @@ -94,21 +94,21 @@ impl WeightInfo for HydraWeight { // Proof: Staking Staking (max_values: Some(1), max_size: Some(48), added: 543, mode: MaxEncodedLen) // Storage: Uniques Asset (r:1 w:0) // Proof: Uniques Asset (max_values: None, max_size: Some(146), added: 2621, mode: MaxEncodedLen) - // Storage: System Account (r:2 w:1) + // Storage: System Account (r:2 w:2) // Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) // Storage: Staking Positions (r:1 w:1) // Proof: Staking Positions (max_values: None, max_size: Some(132), added: 2607, mode: MaxEncodedLen) // Storage: Balances Locks (r:1 w:1) // Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - // Storage: Staking PositionVotes (r:1 w:0) + // Storage: Staking PositionVotes (r:1 w:1) // Proof: Staking PositionVotes (max_values: None, max_size: Some(2134), added: 4609, mode: MaxEncodedLen) // Storage: Democracy ReferendumInfoOf (r:100 w:0) // Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) fn increase_stake() -> Weight { - // Minimum execution time: 206_722 nanoseconds. - Weight::from_ref_time(209_665_000 as u64) + // Minimum execution time: 237_592 nanoseconds. + Weight::from_ref_time(239_395_000 as u64) .saturating_add(T::DbWeight::get().reads(107 as u64)) - .saturating_add(T::DbWeight::get().writes(4 as u64)) + .saturating_add(T::DbWeight::get().writes(6 as u64)) } // Storage: Staking Staking (r:1 w:1) // Proof: Staking Staking (max_values: Some(1), max_size: Some(48), added: 543, mode: MaxEncodedLen) @@ -118,17 +118,17 @@ impl WeightInfo for HydraWeight { // Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) // Storage: Staking Positions (r:1 w:1) // Proof: Staking Positions (max_values: None, max_size: Some(132), added: 2607, mode: MaxEncodedLen) - // Storage: Staking PositionVotes (r:1 w:0) + // Storage: Staking PositionVotes (r:1 w:1) // Proof: Staking PositionVotes (max_values: None, max_size: Some(2134), added: 4609, mode: MaxEncodedLen) // Storage: Democracy ReferendumInfoOf (r:100 w:0) // Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) // Storage: Balances Locks (r:1 w:1) // Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) fn claim() -> Weight { - // Minimum execution time: 225_912 nanoseconds. - Weight::from_ref_time(227_912_000 as u64) + // Minimum execution time: 233_614 nanoseconds. + Weight::from_ref_time(236_034_000 as u64) .saturating_add(T::DbWeight::get().reads(107 as u64)) - .saturating_add(T::DbWeight::get().writes(5 as u64)) + .saturating_add(T::DbWeight::get().writes(6 as u64)) } // Storage: Staking Staking (r:1 w:1) // Proof: Staking Staking (max_values: Some(1), max_size: Some(48), added: 543, mode: MaxEncodedLen) @@ -138,7 +138,7 @@ impl WeightInfo for HydraWeight { // Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) // Storage: Staking Positions (r:1 w:1) // Proof: Staking Positions (max_values: None, max_size: Some(132), added: 2607, mode: MaxEncodedLen) - // Storage: Staking PositionVotes (r:1 w:0) + // Storage: Staking PositionVotes (r:1 w:1) // Proof: Staking PositionVotes (max_values: None, max_size: Some(2134), added: 4609, mode: MaxEncodedLen) // Storage: Democracy ReferendumInfoOf (r:100 w:0) // Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) @@ -151,9 +151,9 @@ impl WeightInfo for HydraWeight { // Storage: Uniques ItemPriceOf (r:0 w:1) // Proof: Uniques ItemPriceOf (max_values: None, max_size: Some(113), added: 2588, mode: MaxEncodedLen) fn unstake() -> Weight { - // Minimum execution time: 246_989 nanoseconds. - Weight::from_ref_time(249_570_000 as u64) + // Minimum execution time: 264_098 nanoseconds. + Weight::from_ref_time(266_429_000 as u64) .saturating_add(T::DbWeight::get().reads(108 as u64)) - .saturating_add(T::DbWeight::get().writes(9 as u64)) + .saturating_add(T::DbWeight::get().writes(10 as u64)) } }