veRAACToken provides increase() function enabling users to add extra tokens to their lock positions. However, the increase() function incorrectly assumes that new voting power will always be greater than the current balance when increasing lock amount, failing to account for voting power decay over time. This can cause the function to revert due to underflow, making it impossible for users to increase their lock amounts in certain scenarios.
The root cause of this issue is that in increase() function, when _mint() veRAACToken, it does not consider newPower can be less than balanceOf(msg.sender).
contracts/core/tokens/veRAACToken.sol#L270
The newPower value is determined in calculateAndUpdatePower() function by calculation (amount * (unlockTime - block.timestamp)) / MAX_LOCK_DURATION;. Even though the amount is increased, when the remaining lock duration is short, eventually the newPower value will be less than balanceOf(msg.sender).
This can cause the function to revert due to underflow error in _mint().
The following PoC test case demonstrates that:
A user creates an initial lock with 1000 RAACToken for 1 year
Fast forwards time to 60% of the lock duration
Attempts to increase the lock amount by 100 RAAC but reverts
The PoC can be run by appending to the original veRAACToken.test.js test file.
The impact is high as user cannot increase their lock amounts in a common senario when newPower < balanceOf(msg.sender). This affects core protocol functionality around governance participation.
Manual code review
Update increase() function to handle both increasing and decreasing voting power scenarios:
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.