Submitted by TheSchnilch, also found by Aymen0909
With unbond_instant, a user can unbond a bonded amount directly without having to wait. However, they must pay a fee for this:
Here, the mistake is that T::OnUnbonded::happened is called with final_amount, meaning without a fee. As a result, a portion of the shares that were added as shares during bonding can no longer be removed. This, in turn, leads to these shares still receiving rewards that other users cannot receive.
If you insert a println! statement into the functions bond and unbond_instant to display the amounts with which OnBonded::happened and OnUnbonded::happened are called, you will see when you execute the following code that not all shares are removed when the bonded amount of a user is removed with unbond_instant:
For bond:
For unbond_instant:
Code that can be inserted into the file modules/earning/src/tests.rs to test both functions:
The code can be started with the command cargo test poc -- --nocapture.
So every time a user calls unbond_instant, some shares will remain in the reward system and continue to accumulate rewards that other users who actually bond can no longer get. These shares can then no longer be removed and are stuck. With a maximum fee of 20%, some shares could accumulate over a period of time and these shares would accumulate rewards. The owners of the shares can still claim these rewards. In addition, one share is no longer the same as one underlying token.
For unbond_instant, the final_amount should not be used to remove the shares, but change.change should be used instead.
xlc (Acala) confirmed and commented:
