diff --git a/frame/nomination-pools/src/lib.rs b/frame/nomination-pools/src/lib.rs index b5e605e26f555..e7f205f724a47 100644 --- a/frame/nomination-pools/src/lib.rs +++ b/frame/nomination-pools/src/lib.rs @@ -1953,14 +1953,15 @@ impl Pallet { current_points: BalanceOf, points: BalanceOf, ) -> BalanceOf { + let u256 = |x| T::BalanceToU256::convert(x); + let balance = |x| T::U256ToBalance::convert(x); if current_balance.is_zero() || current_points.is_zero() || points.is_zero() { // There is nothing to unbond return Zero::zero() } // Equivalent of (current_balance / current_points) * points - current_balance - .saturating_mul(points) + balance(u256(current_balance).saturating_mul(u256(points))) // We check for zero above .div(current_points) } diff --git a/frame/nomination-pools/src/tests.rs b/frame/nomination-pools/src/tests.rs index 350bc97295f23..15beb0572b9e1 100644 --- a/frame/nomination-pools/src/tests.rs +++ b/frame/nomination-pools/src/tests.rs @@ -1828,9 +1828,9 @@ mod unbond { }) } + // depositor can unbond inly up to `MinCreateBond`. #[test] fn depositor_permissioned_partial_unbond() { - // Scenarios where non-admin accounts can unbond others ExtBuilder::default() .ed(1) .add_delegators(vec![(100, 100)]) @@ -1852,6 +1852,29 @@ mod unbond { ); }); } + + // same as above, but the pool is slashed and therefore the depositor cannot partially unbond. + #[test] + fn depositor_permissioned_partial_unbond_slashed() { + ExtBuilder::default() + .ed(1) + .add_delegators(vec![(100, 100)]) + .build_and_execute(|| { + // given + assert_eq!(MinCreateBond::::get(), 2); + assert_eq!(Delegators::::get(10).unwrap().active_points(), 10); + assert_eq!(Delegators::::get(10).unwrap().unbonding_points(), 0); + + // slash the default pool + StakingMock::set_bonded_balance(Pools::create_bonded_account(1), 5); + + // cannot unbond even 7, because the value of shares is now less. + assert_noop!( + Pools::unbond(Origin::signed(10), 10, 7), + Error::::NotOnlyDelegator + ); + }); + } } mod pool_withdraw_unbonded {