The StakePool is over complicated to further extend its functionalities. It's th…e time to reconsider its design.
## 1. Scheduler and the force shutdown mechanism
Force shutdown is a fallback protection mechanism to ensure the stakers (delegators) can always withdraw their stake from a pool, even if the pool owner doesn't release the funds proactively. When a withdrawal is requested, the pool owner have 7 days "grace period" to prepare enough free stake to release the funds for the request. Otherwise the entire pool will be shutdown to release sufficient funds.
The idea is simple, but the implementation was terribly complicated. It causes a problem even existing now: the slash cannot be properly handled when the miner is being stopped.
To enable the auto shutdown, the pallet needs to check if the queue has any withdrawal requests not being fulfilled for more than 7 days. The fulfillment is determined by tracking the "releasing stake" -- the sum of the stopping miners' stakes. And then automatically trigger the shutdown if the condition doesn't meet.
The automatic execution is very tricky. If we somehow exhausted the block weight, the chain will halt. So the first principle is to minimize the calculation on the blockchain.
Then first, we decided to maintain the "releasing stake" by adding up all the stopped miners' stake. It turns out to be the source of the problem. When adding, we only know the current stake under the miner. If the miner got slashed right after stopping (which is pretty common, since GK will settle all the slash as soon as it notice the miner will stop), we don't know how to correct the total releasing stake.
Secondly, the stop condition will only be checked once -- 7 days after the withdrawal request was queued. As the slash can happen after stopping, even if we correct the releasing stake dynamically, we still need to check the stop condition multiple times (since the slash can make the condition different). This violates the minimum computation principle and adds a lot of complexity to the pallet.
### Solution
Remove the automatic force shutdown. Instead, we allow anyone to trigger a shutdown check to a pool by sending transactions. It can run more complex computation, and can also be triggered more than once. So we can dynamically sum up the releasing stake instead of tracking it. The slash can also be handled because whenever the stop condition hits, the stacker can trigger the shutdown.
## 2. Very complex fund management
Now the pool design is complex. It tracks shares, pending rewards (accumulator), pending slashes (accumulator), balance locks, and potentially withdraw request for each user.
The first part of complexity comes from the accumulators, which is used to distribute some pending value to all the stakers propotionally. If we build a valut (a layer 2 pool to invest stake pools), the downstream pools also need to handle the rewards and slash.
Ideally, we should be able to abstract all the pools as the unit that can receive stakes, stake to the upstream, and settle the final rewards for the stakers. Whenver an entity stake to a pool, it gets the corresponding shares in the pool, and can redeem the funds back by their share. Since there could be rewards and slashes, the total funds in the pool can change over the time. However the stakers shouldn't need to track the reward or slash until they decide to redeem their share back.
### Solution
Remove the accumulators and only maintain a shared deposit in the pool. When there's new stake added to the pool, we add the funds to the pool, and allocate the corresponding share to the staker. The reward and the slashes will be handled by the shared deposit pool, causing increase or decrease of the deposit. Finally, stakes can redeem the deposit back from the pool by burning their shares, hopefully for profit.
This essentially makes the stake pool an coumpond investment target, since all the reward earned by a staker will become free stake in the pool, and available for new miners. On the other hand, since the share and the actual value of the assets is decoupled, the multi-layer pool impelmentation can be simplified.
## 3. Account based tracking
Now the staker's share in stake pools is tracked under their account and cannot be moved until it's unlocked. However this is not required by the tokenomic. The tokenomic just needs to lock some funds to enable slashing. It works no matter if it's locked under some accounts or some token.
A good example is LP-token in the DeFi world. For example, in Uniswap, anyone can redeem the underlying assets by providing their LP-token to the contract. We can also apply a similar idea to the stake pool. When someone stake some funds to a pool, the pool can issue a NFT representing the share in the pool. The NFT can be traded or sent to other accounts freely, and can be used to redeem the funds when the owner wants to withdraw the funds.
### Solution
We can replace the account-based share tracking by NFTs. As mentioned above, the NFTs are mented when some funds are staked to a pool. The NFT records a share amount in a pool. It can be burned to redeem the withdrawal from the pool.
This creates another problem. Now when a staker deposits some funds to a pool, the funds are actually locked inside the staker's account. We didn't ask the user to transfer to token to the pool because otherwise the user cannot use the funds to participate in democracy or council election voting. However when the locked funds are represented by a NFT rather than the staker's account, when the NFT is transferred, the locked funds should also be transferred accordingly. This is possible, but must be handled carefully. When making a transfer of the NFT, the locked funds will temporarily unlocked and transferred to the new owner as well. We must ensure the locked funds are transferrable after the stake pool lock is temporarily removed. A counter example is that, if someone have used all his fund to stake and vote, the NFT will not be transferrable until the vote lock is expired.
NFT can also represent the state of some shares. Combined with the manually triggered force shutdown, when a user triggers a withdraw request, we can mark the NFT as pending withdraw state with the start date. After the grace period, the NFT owner can trigger the force withdraw check. The withdrawal NFT ids can also be queued so that when there's free stake, the stake can be released.
To support partial withdrawal of the funds, it should allow to split a (non-withdrawing) NFT. On the other hand, multiple (non-withdrawing) NFTs in the same pool can be merged to save the storage. This makes the share NFTs similar to Bitcoin UTXOs.
## Conclusion
1. Remove the schedulers for force shutdown. Instead, allow the stakers to manually trigger the check.
2. Remove the reward and slash accumulators and use a simple compound pool structure.
3. Decouple the shares in the pool from the accounts. Mint the shares as NFTs and enable free transfer.
Once the above changes are finished, it will be possible to build vaults (layer 2 stake pool).