Core Contracts

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

`veRAACToken::increase` Overestimates Voting Power Due to Double Counting

Summary

The increase function in the veRAACToken contract incorrectly calculates the new voting power by adding the amount parameter to userLock.amount. Since userLock is assigned after _lockState.increaseLock(msg.sender, amount); is called, userLock.amount already reflects the updated value. This results in an inflated voting power calculation.

Vulnerability Details

The issue occurs because increase calls _lockState.increaseLock(msg.sender, amount); first, which updates the lock amount in storage. Then, it retrieves userLock from _lockState.locks[msg.sender], which already includes the updated amount. However, the function incorrectly adds amount again, leading to an overestimation of voting power.

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, // Incorrect: amount is already included in userLock.amount
userLock.end
);
// Update checkpoints
uint256 newPower = uint256(uint128(newBias));
_checkpointState.writeCheckpoint(msg.sender, newPower);
// Transfer additional tokens and mint veTokens
raacToken.safeTransferFrom(msg.sender, address(this), amount);
_mint(msg.sender, newPower - balanceOf(msg.sender));
emit LockIncreased(msg.sender, amount);
}
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();
@> lock.amount += additionalAmount; // Lock amount is already updated here
state.totalLocked += additionalAmount;
emit LockIncreased(user, additionalAmount);
}

The following is the output from running the should allow users to increase lock amount test. Console logs were added to the increase function, placed right before the _lockState.increaseLock(msg.sender, amount); line, immediately after it, and also to display the result of userLock.amount + amount:

veRAACToken
Lock Mechanism
Before increaseLock 1000000000000000000000
After increaseLock 1500000000000000000000
userLock + amount 2000000000000000000000

Impact

  • Governance manipulation: Users receive more voting power than they should, unfairly influencing governance decisions.

  • Boost miscalculations: _updateBoostState relies on _votingState.calculateAndUpdatePower, causing further inaccuracies in voting weight distribution.

Tools Used

Manual review of the contract’s logic.

Recommendations

Modify the increase function to use userLock.amount directly:

(int128 newBias, int128 newSlope) = _votingState.calculateAndUpdatePower(
msg.sender,
@> userLock.amount, // Corrected: use the already updated value
userLock.end
);

This ensures that voting power calculations accurately reflect the correct locked balance.

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.