Core Contracts

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

emergencyWithdraw is not updating checkpoints

Summary

In the veRAACToken contract, the emergencyWithdraw function does not update checkpoints, unlike the withdraw function. This inconsistency can lead to potential issues in the contract's state management, particularly affecting voting power calculations and historical data tracking.

Vulnerability Details

The emergencyWithdraw function allows users to withdraw their locked tokens in case of an emergency, bypassing the usual lock expiration period. However, unlike the withdraw function, it does not update the checkpoints after deleting the user's lock and voting points. This omission can result in outdated or incorrect voting power calculations, as the checkpoint system is designed to track changes in voting power over time.

Code Comparison

  • emergencyWithdraw Function:

    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);
    }
  • withdraw Function:

    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);
    // Clear lock data
    delete _lockState.locks[msg.sender];
    delete _votingState.points[msg.sender];
    // Update checkpoints
    _checkpointState.writeCheckpoint(msg.sender, 0);
    // Burn veTokens and transfer RAAC
    _burn(msg.sender, currentPower);
    raacToken.safeTransfer(msg.sender, amount);
    emit Withdrawn(msg.sender, amount);
    }

Impact

The lack of checkpoint updates in the emergencyWithdraw function can lead to:

Inaccurate Voting Power Calculations:** The checkpoint system is used to track voting power over time. Without updating the checkpoints, the contract may incorrectly calculate a user's voting power in this block: getPastVotes.

Tools Used

Manual Review

Recommendations

To address this issue, consider updating the checkpoints in the emergencyWithdraw function, similar to how it is done in the withdraw function. Here is the recommended change:

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 4 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.