When a staker un-stakes during an active pending stake, there is a vulnerability in the LiquidationPool contract that leads to a loss of liquidation rewards and reward fees. The issue arises when the LiquidationPool::decreasePosition() function is called, and there is an active PendingStake for the staker. The staker's address is removed from the holders array, causing problems during reward consolidation.
The problem lies in the LiquidationPool::decreasePosition() function, specifically in the check at the end of the function that removes the staker's address from the holders array if their position is empty. This becomes problematic when there is an active PendingStake for the staker. As a result, during reward consolidation, the staker's address is not added back to the holders array and also removed from the pendingStakes, impacting the calculation and distribution of rewards.
LIquidationPool::decreasePosition(...)
GitHub: 149-162
The LiqudiationPool::consolidatePendingStakes() function is responsible for consolidating pending stakes, but it fails to add the staker back to the holders array, leading to the loss of rewards. The only way for the staker to be added to the array is by depositing tokens again using the LiquidationPool::increasePosition() function.
Additionally, the LiquidationPool::distributeFees() and LiquidationPool::distributeAssets() functions depend on both the holders array and pendingStakes array to distribute rewards. Since the staker's address is not present in both arrays after stake consolidation, they do not receive any rewards.
LiquidationPool::distributeFees(...)
GitHub: 182-194
LiquidationPool::distributeAssets(...)
GitHub: 205
Let's take an example to understand it better:
There are three users alice, bob and mike.
alice and bob both has 1000 EUROs and 1000 TSTs. Both deposits that into the LiquidationPool. So now, there are 2000 EUROs and 2000 TSTs is in pending stakes.
Now mike comes and decides to create a SmartVault. So he calls the SmartVaultManager and creates one for himself. Now whenever he mints or burns or swaps any token, there will be fee he will have to pay that will be deposited to the LiquidationPoolManager that will ultimately be given to Pool Staker (i.e is alice and bob).
Now let's say 1 week has passed and both bob's and alice's stakes has been consolidated and they have earn some fee rewards and their new balance is 1010 EURO and 1000 TSTs each.
bob stakes 1000 EUROs more. But on the same day he decides to unstake his consolidated stakes due to some reasons. So he does that and removes 1010 EUROs and 1000 TSTs from the pool. But doing this has removed his address from the holders mapping as the LiquidationPool::empty() will return true and his address will be removed from the array. Now he has 1000 EUROs and 1000 TSTs in pending stakes.
Now he will keep earning his fee rewards on pending stakes. But when his pending stakes in consolidated after the deadline. his amount will be added to the positions mapping only and will not be added to the holders array. And that means any reward after that will not be sent to him as a staker needs to be present in the holders array to earn rewards as we have seen above. And hence loss of rewards for him as long as he does not stakes again.
Staker will lose rewards.
NOTE
The below given test is written in thefoundryframework instead ofhardhat. Please go to the repo given below and follow the steps mentioned in the readme to setup the project. Every tests for the current codebase is given in the repo itself.
Github: Repo
Here is a test for PoC that demonstarates the loss of fee rewards:
Original Test: [Link]
Output:
Manual Review
It is recomended to add one of the following ways to solve the issue:
If there is a pending stake for the staker, do not remove him from the holders durning the decreasePosition. Only decrease his position amount.
Call LiquidationPool::addUniqueHolder(...) in the LiquidationPool::consolidatePendingStakes.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.