The withdraw()
function in veRaacToken.sol
allows users to unlock their previously locked RAAC tokens after the lock period expires by deleting their lock data, burning their veTokens, and transferring the original RAAC tokens back. However, while the locking process increases the global locked amount, the withdrawal process merely deletes the user's lock details without decrementing the global total of locked tokens.
When a user calls withdraw()
, the function performs the following steps:
Validation:
It checks that a lock exists for the caller and that the current timestamp is past the lock expiry.
State Clearing:
The function deletes the user's lock data from _lockState.locks
and associated voting power checkpoints from _votingState.points
.
Checkpoint Update:
It updates the user's checkpoint to zero to reflect the loss of voting power.
Token Burn and Transfer:
The function burns the user's veTokens (representing voting power) and transfers the locked RAAC tokens back to the user.
While these operations correctly handle the user-specific state, the function does not adjust any global variable that tracks the total locked amount. This means that the global metric remains artificially high even after tokens are withdrawn.
Imagine a user locks 100 RAAC tokens, increasing the global locked amount by 100 tokens. Later, when the user withdraws, the function clears their lock and returns 100 tokens to the user, but the global locked total is not reduced. If several users follow this pattern, the overall locked amount reported by the protocol will be significantly higher than the actual tokens locked, leading to misaligned incentives and inaccurate governance calculations.
Inaccurate Global Metrics:
The total locked amount remains overstated, potentially affecting calculations for voting power, rewards, and governance decisions.
Economic Imbalance:
Over time, if many users withdraw their tokens without the global counter being updated, the protocol may misallocate rewards or fees based on inflated locked totals.
Reduced Transparency:
Stakeholders relying on global locked metrics may be misled about the actual level of token commitment within the protocol.
Manual review
Update Global Locked Counter:
Modify the withdrawal logic to decrement the global locked total by the withdrawn amount. For instance, if _lockState.totalLocked
tracks the cumulative locked tokens, ensure that it is reduced accordingly when a withdrawal occurs.
Ensure Consistency:
Review the LockManager library to confirm that all operations (locking, increasing, extending, and withdrawing) consistently update the global state variables.
Implement Unit Tests:
Develop comprehensive tests that simulate locking and withdrawing tokens to verify that the global locked amount accurately reflects the sum of all active locks.
By updating the global locked counter on withdrawal, the protocol will maintain accurate metrics, ensuring that reward and governance calculations remain fair and transparent.
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.