# Nomination Pool Rebond ## Problem The staking pallet always rebonds and withdraws from the earliest unlock chunk. This has historically been fine for nominators, whereby there is only ever 1 actor manipulating their unlock chunks. Even when multiple actors (members of a nomination pool) are manipulating a pool's unlock chunks, withdrawing is still fine, as members are required to wait 28 eras before they can remove chunk(s) from the earliest submitted one. The issue arises when rebonding is introduced. A pool member unlock (SubPool - nomination_pools) is hetrogeneous from the pool unlock chunk (UnlockChunk - staking). If we allow rebonding in the curent system, **rebonding will always take the rebond amount from the last unlock chunk**. This causes inconsistenies in other member's unlocks: - A staker who has previously submitted an unlock chunk could be forced to wait *longer* than 28 eras. - The assumption that the unlock era is submitted_era + 28 is broken. #### Scenario | Action | Unlock Chunks | | -------- | -------- | | Staker 1 unbonds | [era 100 / unlocks era 129] | | Staker 2 unbonds | [era 100 / unlocks era 129] [era 101 / unlocks era 130] | | Staker 2 changes their mind and rebonds | [era 101 / unlocks 130] | Staker 1 originally submitted their unbond in era 100, with a guaranteed unlock at 129. But when staker 2 unbonds and decides to rebond again, they take the unlock chunk amount from the earliest available chunk. As a result, the earliest chunk will now be 101, causing staker 1 to wait another era to unlock their funds. This process can be repeated, causing staker 1 to wait an unpredictable amount of time before their chunk is unlocked. This problem currently exists in the following draft PR, that always rebonds from the earliest unlock chunk: https://github.com/paritytech/polkadot-sdk/pull/2667. ## Solution In scenarios where multiple actors are manipulating a pool's unlock chunks, there needs to be a 1 to 1 mapping maintaind between SubPool records and UnlockChunks. This will ensure that SubPools map on the pools pallet will match the UnlockChunks on the staking pallet. Submitting multiple rebonds will still restrict manipulation to one era - there will never be rebonding by fetching balance from multiple unlock chunks. Withdrawing is fine the way it is, as it enforces stakers to wait at least 28 eras before withdrawing (& manipulating the chunks), which guarantees there will be withdrawable funds for all those waiting to withdraw. We can see from `SubPools` we have access to the era and unlock amounts (not counting `no_era`): ![Screenshot 2023-12-11 at 12.43.02](https://hackmd.io/_uploads/rk_F-7V8a.png) And this should be consistent with the staking pallet's ledger for the pool: ![Screenshot 2023-12-11 at 12.45.38](https://hackmd.io/_uploads/HJHGfXVUp.png) To get a pool members unbonding record, we look at `poolMembers` storage (the following screenshot has no unbonding eras, but the era and total points would be here): ![Screenshot 2023-12-11 at 13.01.14](https://hackmd.io/_uploads/H1wCBQVIa.png) **We can assume that as long as unlocks are not in `no_era`, as to maintain the era mapping, they are elligible for rebonding.** ## Actions 1. Introduce a `rebond(era)` call to nomination pools. - Initially, get all points associated with the unbond. - Later, expand to `rebond(era, points)` to allow an arbitrary balance rebond. - Only allow rebond if era is present in `SubPools`. `no_era` = too late to rebond. 2. Introduce a `rebond_from_era(who, era)` to `StakingInterface` and `rebond_from_era(who, era)` to staking pallet `Config`, in order to manipulate the unlock chunk at a particular era. Make it obvious this is for pools, or for multiple actors acting on behalf of a nominator. - Later expand to `rebond_from_era(who, era, balance)`. 3. Test suite to prove system works on pools pallet. 4. Isolated staking pallet tests, benchmarks, etc. ## Notes - There should never be a scenario where the unlock chunk amount does not fulfil the requested rebond amount from `SubPools`. I propose a defensive proof in the event this does happen, to ensure tests flag the error & that runtimes log the error, so pallet developers can find out what went wrong. - This solution is UI friendly; it is easy to query `SubPools` to determine if rebonding is available, and even calculate the estimated time left before the `SubPool` could be merged into `no_era`.