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:
Dastan
2024-03-07 11:36:30 +01:00
committed by GitHub
parent c16fcc47bc
commit 11831df8e7
5 changed files with 367 additions and 128 deletions
+37 -2
View File
@@ -2401,6 +2401,11 @@ pub mod pallet {
///
/// This directly forward the call to the staking pallet, on behalf of the pool bonded
/// account.
///
/// # Note
///
/// In addition to a `root` or `nominator` role of `origin`, pool's depositor needs to have
/// at least `depositor_min_bond` in the pool to start nominating.
#[pallet::call_index(8)]
#[pallet::weight(T::WeightInfo::nominate(validators.len() as u32))]
pub fn nominate(
@@ -2411,6 +2416,16 @@ pub mod pallet {
let who = ensure_signed(origin)?;
let bonded_pool = BondedPool::<T>::get(pool_id).ok_or(Error::<T>::PoolNotFound)?;
ensure!(bonded_pool.can_nominate(&who), Error::<T>::NotNominator);
let depositor_points = PoolMembers::<T>::get(&bonded_pool.roles.depositor)
.ok_or(Error::<T>::PoolMemberNotFound)?
.active_points();
ensure!(
bonded_pool.points_to_balance(depositor_points) >= Self::depositor_min_bond(),
Error::<T>::MinimumBondNotMet
);
T::Staking::nominate(&bonded_pool.bonded_account(), validators)
}
@@ -2573,17 +2588,37 @@ pub mod pallet {
/// Chill on behalf of the pool.
///
/// The dispatch origin of this call must be signed by the pool nominator or the pool
/// The dispatch origin of this call can be signed by the pool nominator or the pool
/// root role, same as [`Pallet::nominate`].
///
/// Under certain conditions, this call can be dispatched permissionlessly (i.e. by any
/// account).
///
/// # Conditions for a permissionless dispatch:
/// * When pool depositor has less than `MinNominatorBond` staked, otherwise pool members
/// are unable to unbond.
///
/// # Conditions for permissioned dispatch:
/// * The caller has a nominator or root role of the pool.
/// This directly forward the call to the staking pallet, on behalf of the pool bonded
/// account.
#[pallet::call_index(13)]
#[pallet::weight(T::WeightInfo::chill())]
pub fn chill(origin: OriginFor<T>, pool_id: PoolId) -> DispatchResult {
let who = ensure_signed(origin)?;
let bonded_pool = BondedPool::<T>::get(pool_id).ok_or(Error::<T>::PoolNotFound)?;
ensure!(bonded_pool.can_nominate(&who), Error::<T>::NotNominator);
let depositor_points = PoolMembers::<T>::get(&bonded_pool.roles.depositor)
.ok_or(Error::<T>::PoolMemberNotFound)?
.active_points();
if bonded_pool.points_to_balance(depositor_points) >=
T::Staking::minimum_nominator_bond()
{
ensure!(bonded_pool.can_nominate(&who), Error::<T>::NotNominator);
}
T::Staking::chill(&bonded_pool.bonded_account())
}