Core Contracts

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

Missing Checkpoints Update in emergencyWithdraw() :: veRAACToken.sol .

Summary

The emergencyWithdraw() function allows users to withdraw their locked RAAC tokens in case of emergencies. However, unlike the withdraw() function, it does not update the checkpoint state to zero power. This inconsistency can lead to inaccurate voting power calculations and governance manipulation.

Vulnerability Details

  • The withdraw() function correctly calls _checkpointState.writeCheckpoint(msg.sender, 0); to reset the user's voting power.

  • In contrast, the emergencyWithdraw() function does not update the checkpoint state, leaving stale voting power records.

    [ https://github.com/Cyfrin/2025-02-raac/blob/89ccb062e2b175374d40d824263a4c0b601bcb7f/contracts/core/tokens/veRAACToken.sol#L367-L384 ]

    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-issue : Missing _checkpointState update
    _burn(msg.sender, currentPower);
    raacToken.safeTransfer(msg.sender, amount);
    emit EmergencyWithdrawn(msg.sender, amount);
    }
  • This omission means that even after withdrawing all tokens, a user's previous voting power may still be counted in governance calculations, leading to incorrect vote weight allocations and potential governance manipulation.

Impact

  • Governance Manipulation: Users could retain voting power after withdrawing, allowing them to influence decisions without holding any tokens.

  • Inconsistent Voting Power Calculation: The voting system may count non-existent voting power, leading to inaccurate vote distributions.

Tools Used

Manual Review .

Recommendations

Update the Checkpoint State in emergencyWithdraw():

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

Give us feedback!