mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-13 09:21:05 +00:00
nomination-pools: add permissionless condition to chill (#3453)
Currently, pool member funds cannot be unbonded if the depositor's stake is less than `MinNominatorBond`. This usually happens after `T::MinNominatorBond` is increased. To fix this, the above mentioned condition is added as a case for permissionless dispatch of `chill`. After pool is chilled, pool members can unbond their funds since pool won't be nominating anymore. Consequently, same check is added to `nominate` call, i.e pool can not start nominating if it's depositor does not have `MinNominatorBond` cc @Ank4n @kianenigma closes #2350 Polkadot address: 16FqwPZ8GRC5U5D4Fu7W33nA55ZXzXGWHwmbnE1eT6pxuqcT --------- Co-authored-by: Ankan <10196091+Ank4n@users.noreply.github.com> Co-authored-by: Gonçalo Pestana <g6pestana@gmail.com> Co-authored-by: command-bot <>
This commit is contained in:
@@ -22,10 +22,12 @@ mod mock;
|
||||
use frame_support::{assert_noop, assert_ok, traits::Currency};
|
||||
use mock::*;
|
||||
use pallet_nomination_pools::{
|
||||
BondedPools, Error as PoolsError, Event as PoolsEvent, LastPoolId, PoolMember, PoolMembers,
|
||||
PoolState,
|
||||
BondExtra, BondedPools, Error as PoolsError, Event as PoolsEvent, LastPoolId, PoolMember,
|
||||
PoolMembers, PoolState,
|
||||
};
|
||||
use pallet_staking::{
|
||||
CurrentEra, Error as StakingError, Event as StakingEvent, Payee, RewardDestination,
|
||||
};
|
||||
use pallet_staking::{CurrentEra, Event as StakingEvent, Payee, RewardDestination};
|
||||
use sp_runtime::{bounded_btree_map, traits::Zero};
|
||||
|
||||
#[test]
|
||||
@@ -191,6 +193,131 @@ fn pool_lifecycle_e2e() {
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pool_chill_e2e() {
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_eq!(Balances::minimum_balance(), 5);
|
||||
assert_eq!(Staking::current_era(), None);
|
||||
|
||||
// create the pool, we know this has id 1.
|
||||
assert_ok!(Pools::create(RuntimeOrigin::signed(10), 50, 10, 10, 10));
|
||||
assert_eq!(LastPoolId::<Runtime>::get(), 1);
|
||||
|
||||
// have the pool nominate.
|
||||
assert_ok!(Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3]));
|
||||
|
||||
assert_eq!(
|
||||
staking_events_since_last_call(),
|
||||
vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 50 }]
|
||||
);
|
||||
assert_eq!(
|
||||
pool_events_since_last_call(),
|
||||
vec![
|
||||
PoolsEvent::Created { depositor: 10, pool_id: 1 },
|
||||
PoolsEvent::Bonded { member: 10, pool_id: 1, bonded: 50, joined: true },
|
||||
]
|
||||
);
|
||||
|
||||
// have two members join
|
||||
assert_ok!(Pools::join(RuntimeOrigin::signed(20), 10, 1));
|
||||
assert_ok!(Pools::join(RuntimeOrigin::signed(21), 10, 1));
|
||||
|
||||
assert_eq!(
|
||||
staking_events_since_last_call(),
|
||||
vec![
|
||||
StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 },
|
||||
StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 },
|
||||
]
|
||||
);
|
||||
assert_eq!(
|
||||
pool_events_since_last_call(),
|
||||
vec![
|
||||
PoolsEvent::Bonded { member: 20, pool_id: 1, bonded: 10, joined: true },
|
||||
PoolsEvent::Bonded { member: 21, pool_id: 1, bonded: 10, joined: true },
|
||||
]
|
||||
);
|
||||
|
||||
// in case depositor does not have more than `MinNominatorBond` staked, we can end up in
|
||||
// situation where a member unbonding would cause pool balance to drop below
|
||||
// `MinNominatorBond` and hence not allowed. This can happen if the `MinNominatorBond` is
|
||||
// increased after the pool is created.
|
||||
assert_ok!(Staking::set_staking_configs(
|
||||
RuntimeOrigin::root(),
|
||||
pallet_staking::ConfigOp::Set(55), // minimum nominator bond
|
||||
pallet_staking::ConfigOp::Noop,
|
||||
pallet_staking::ConfigOp::Noop,
|
||||
pallet_staking::ConfigOp::Noop,
|
||||
pallet_staking::ConfigOp::Noop,
|
||||
pallet_staking::ConfigOp::Noop,
|
||||
pallet_staking::ConfigOp::Noop,
|
||||
));
|
||||
|
||||
// members can unbond as long as total stake of the pool is above min nominator bond
|
||||
assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 10),);
|
||||
assert_eq!(PoolMembers::<Runtime>::get(20).unwrap().unbonding_eras.len(), 1);
|
||||
assert_eq!(PoolMembers::<Runtime>::get(20).unwrap().points, 0);
|
||||
|
||||
// this member cannot unbond since it will cause `pool stake < MinNominatorBond`
|
||||
assert_noop!(
|
||||
Pools::unbond(RuntimeOrigin::signed(21), 21, 10),
|
||||
StakingError::<Runtime>::InsufficientBond,
|
||||
);
|
||||
|
||||
// members can call `chill` permissionlessly now
|
||||
assert_ok!(Pools::chill(RuntimeOrigin::signed(20), 1));
|
||||
|
||||
// now another member can unbond.
|
||||
assert_ok!(Pools::unbond(RuntimeOrigin::signed(21), 21, 10));
|
||||
assert_eq!(PoolMembers::<Runtime>::get(21).unwrap().unbonding_eras.len(), 1);
|
||||
assert_eq!(PoolMembers::<Runtime>::get(21).unwrap().points, 0);
|
||||
|
||||
// nominator can not resume nomination until depositor have enough stake
|
||||
assert_noop!(
|
||||
Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3]),
|
||||
PoolsError::<Runtime>::MinimumBondNotMet,
|
||||
);
|
||||
|
||||
// other members joining pool does not affect the depositor's ability to resume nomination
|
||||
assert_ok!(Pools::join(RuntimeOrigin::signed(22), 10, 1));
|
||||
|
||||
assert_noop!(
|
||||
Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3]),
|
||||
PoolsError::<Runtime>::MinimumBondNotMet,
|
||||
);
|
||||
|
||||
// depositor can bond extra stake
|
||||
assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(10), BondExtra::FreeBalance(10)));
|
||||
|
||||
// `chill` can not be called permissionlessly anymore
|
||||
assert_noop!(
|
||||
Pools::chill(RuntimeOrigin::signed(20), 1),
|
||||
PoolsError::<Runtime>::NotNominator,
|
||||
);
|
||||
|
||||
// now nominator can resume nomination
|
||||
assert_ok!(Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3]));
|
||||
|
||||
// skip to make the unbonding period end.
|
||||
CurrentEra::<Runtime>::set(Some(BondingDuration::get()));
|
||||
|
||||
// members can now withdraw.
|
||||
assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(20), 20, 0));
|
||||
assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(21), 21, 0));
|
||||
|
||||
assert_eq!(
|
||||
staking_events_since_last_call(),
|
||||
vec![
|
||||
StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 },
|
||||
StakingEvent::Chilled { stash: POOL1_BONDED },
|
||||
StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 },
|
||||
StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 }, // other member bonding
|
||||
StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 }, // depositor bond extra
|
||||
StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 20 },
|
||||
]
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pool_slash_e2e() {
|
||||
new_test_ext().execute_with(|| {
|
||||
|
||||
Reference in New Issue
Block a user