Core Contracts

Regnum Aurum Acquisition Corp
HardhatReal World AssetsNFT
77,280 USDC
View results
Submission Details
Severity: low
Valid

Missing Checkpoint Reset in `veRAACToken::emergencyWithdraw` Function

Summary

In the veRAACToken::emergencyWithdraw function, while user locks and voting power points are cleared during an emergency withdrawal, the user’s voting power checkpoint is not reset. This omission results in outdated checkpoint data remaining on-chain even after the user has withdrawn their tokens, leading to inaccurate historical voting power records.

Vulnerability Details

During an emergency withdrawal, the contract clears the user’s lock and voting power data by deleting the corresponding entries from _lockState.locks and _votingState.points. However, the function fails to reset the checkpoint by not calling _checkpointState.writeCheckpoint(msg.sender, 0). This checkpoint is crucial for tracking historical voting power, and its inaccurate state can lead to discrepancies between the user’s actual token holdings and the recorded voting power at specific snapshots.

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];
_burn(msg.sender, currentPower);
raacToken.safeTransfer(msg.sender, amount);
emit EmergencyWithdrawn(msg.sender, amount);
}

Impact

The stale checkpoint data may lead to inaccurate historical voting power reports, affecting governance decisions that depend on past voting snapshots.

Tools Used

Manual Review

Recommendations

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];
+ // Update checkpoints
+ _checkpointState.writeCheckpoint(msg.sender, 0);
_burn(msg.sender, currentPower);
raacToken.safeTransfer(msg.sender, amount);
emit EmergencyWithdrawn(msg.sender, amount);
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 6 months ago
Submission Judgement Published
Validated
Assigned finding tags:

veRAACToken::emergencyWithdraw doesn't update checkpoint - innacurate historical voting power, inconsistent state

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.