A logic flaw in the LiquidationPool
contract may cause users with pending stakes to become ineligible for rewards if they withdraw their entire staked amount before consolidation, due to premature removal from the holders
array.
When a user has both staked and pending stakes. The vulnerability is triggered under the following conditions:
A user already has a stake recorded in the holders
array (e.g., tst
= 1000, euro
= 200).
The user decides to increase their stake, which results in additional amounts being added to pendingStakes
(e.g., tst
= 2000, euro
= 100). The consolidatePendingStakes()
function is designed to add unique holders to the holders
array, so it does not add this user in this case because the user is already listed.
If the user then decreases their entire staked position before the pending stakes are consolidated (within one day), the empty()
check within the decreasePosition()
function will lead to the user being removed from the holders
array.
After the one-day period passes and consolidatePendingStakes()
is called, the user's pending stakes are added to their position, but since they have been removed from the holders
array, they are no longer eligible to get any rewards when distributeFees()
or distributeAssets
function called, cause in this case they won't be a holder (not in the holders array) nor they have a pending stake (it's already executed) even they are a real holder.
here a poc that shows ,how bob can be deleted from array holders ,and not take any rewards , i used foundry with a custom setup for the protocol , i didn't use the proxy pattern so i have to set some intial values in the initialize function of smartVaultManager contract :
console after running test :
This flaw can result in a user being unfairly excluded from reward distributions, despite having a pending stake that should qualify them for rewards.
vs code
It is recommended to remove the addUniqueHolder()
function call from the increasePosition()
function, as its current placement is unnecessary. When a holder is unique, it implies their position is empty, and thus they are not entitled to rewards at that moment. To ensure accurate tracking and reward eligibility, the addUniqueHolder()
function should be called within the consolidatePendingStakes()
function after pending stakes have been added to the holder's position.
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.