Core Contracts

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

Double-Counting Lock Amounts in `veRAACToken.increase()` Leads to Inflated Voting Power

Summary

A critical double-counting vulnerability exists in the veRAAC token lock increase mechanism, causing inflated voting power calculations. The error occurs when the system incorrectly adds a lock amount increase twice - first during the lock state update LockManager.increaseLock(), then again during voting power recalculation veRAACToken.increase(). This fundamental accounting flaw propagates through governance voting weights, gauge boost multipliers, and protocol reward distributions, enabling attackers to gain disproportionate influence over protocol operations through manipulated position increases.

Vulnerability Details

The vulnerability occurs in the lock amount handling sequence when increasing a user's veRAAC position by calling function veRAACToken.increase (veRAACToken.sol#L260). The flawed logic appears in two key locations:

  • After successfully increasing the lock amount via _lockState.increaseLock(), the code retrieves the already updated lock amount

  • The voting power calculation _votingState.calculateAndUpdatePower() then incorrectly adds the amount parameter a second time, creating a double-counting error

contract veRAACToken is ERC20, Ownable, ReentrancyGuard, IveRAACToken {
function increase(uint256 amount) external nonReentrant whenNotPaused {
// Increase lock using LockManager
@> _lockState.increaseLock(msg.sender, amount);
_updateBoostState(msg.sender, locks[msg.sender].amount);
// Update voting power
LockManager.Lock memory userLock = _lockState.locks[msg.sender];
(int128 newBias, int128 newSlope) = _votingState.calculateAndUpdatePower(
msg.sender,
@> userLock.amount + amount,
userLock.end
);
// ...
}
}
library LockManager {
function increaseLock(
LockState storage state,
address user,
uint256 additionalAmount
) internal {
Lock storage lock = state.locks[user];
if (!lock.exists) revert LockNotFound();
if (lock.end <= block.timestamp) revert LockExpired();
// Maximum lock amount
if (lock.amount + additionalAmount > state.maxLockAmount) revert AmountExceedsLimit();
// Maximum total locked amount
// if (state.totalLocked + additionalAmount > state.maxTotalLocked) revert AmountExceedsLimit();
@> lock.amount += additionalAmount;
state.totalLocked += additionalAmount;
emit LockIncreased(user, additionalAmount);
}
}

This creates a critical discrepancy between the actual locked amount and the amount used for voting power calculations. The double-counting error propagates through multiple systems:

  • Distorts historical voting power checkpoints

  • Corrupts slope calculations used for time-decayed voting power

  • Invalidates boost multiplier calculations in gauge systems

  • Compromises governance proposal weight calculations

The miscalculation persists until the next lock modification operation, creating a window for exploitation through strategic timing of lock increases and governance actions.

Impact

This miscalculation creates systemic distortions across multiple protocol mechanisms:

  1. Governance Manipulation Risk
    Attackers could gain disproportionate voting power in proposals, enabling:

    • Approval of malicious parameter changes

    • Takeover of protocol direction through skewed voting outcomes

  2. Boost System Exploitation
    Inflated voting power leads to:

    • Unfair reward distributions in RAAC/RWA gauges

    • Protocol-owned liquidity mining incentives being drained faster than designed

  3. Token Inflation Vector
    Incorrect minting calculations could:

    • Create veRAAC supply inflation through corrupted checkpoints

    • Distort the veToken → CRVUSD economic equilibrium

The vulnerability creates a persistent error state until the next lock operation, enabling attackers to strategically time increases for maximum protocol impact.

Tools Used

Manual Review

Recommendations

Modify the voting power calculation in _lockState.increaseLock() to use the correct lock amount:

// Update voting power
LockManager.Lock memory userLock = _lockState.locks[msg.sender];
(int128 newBias, int128 newSlope) = _votingState.calculateAndUpdatePower(
msg.sender,
- userLock.amount + amount,
+ userLock.amount,
userLock.end
);
Updates

Lead Judging Commences

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

veRAACToken::increase doubles the voting power of users

Support

FAQs

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