Summary
The emergency withdrawal function allows users to withdraw before the unlock time if admins allows an emergency withdrawal but this fails to reset the checkpoint of the user.
Vulnerability Details
Inconsistency in the withdraw and emergency withdrawal function
* @notice Withdraws locked RAAC tokens after lock expiry
* @dev Burns veRAAC tokens and returns the original RAAC tokens to the user
*/
function withdraw() external nonReentrant {
LockManager.Lock memory userLock = _lockState.locks[msg.sender];
if (userLock.amount == 0) revert LockNotFound();
if (block.timestamp < userLock.end) revert LockNotExpired();
uint256 amount = userLock.amount;
uint256 currentPower = balanceOf(msg.sender);
delete _lockState.locks[msg.sender];
delete _votingState.points[msg.sender];
@audit>> _checkpointState.writeCheckpoint(msg.sender, 0);
_burn(msg.sender, currentPower);
raacToken.safeTransfer(msg.sender, amount);
emit Withdrawn(msg.sender, amount);
}
* @notice Allows emergency withdrawal of locked tokens
* @dev Users can withdraw their tokens before lock expiry during emergency
*/
function emergencyWithdraw() external nonReentrant {
if (emergencyWithdrawDelay == 0 || block.timestamp < emergencyWithdrawDelay)
revert EmergencyWithdrawNotEnabled();
LockManager.Lock memory userLock = _lockState.locks[msg.sender];
if (userLock.amount == 0) revert NoTokensLocked();
uint256 amount = userLock.amount;
uint256 currentPower = balanceOf(msg.sender);
delete _lockState.locks[msg.sender];
delete _votingState.points[msg.sender];
@audit>>
_burn(msg.sender, currentPower);
raacToken.safeTransfer(msg.sender, amount);
emit EmergencyWithdrawn(msg.sender, amount);
}
Impact
Users power and blocknumber are still saved with in the contract.
Tools Used
Manual Review
Recommendations
Reset checkpoint to 0.