Core Contracts

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

Incorrect veToken Balance Update in `increase()` Leading to Easy Reverts

Summary

An issue exists in the increase() function of veRAACToken.sol where the line:

veRAACToken.sol#L270

_mint(msg.sender, newPower - balanceOf(msg.sender));

🚨 Can cause the transaction to revert when newPower is smaller than balanceOf(msg.sender).

This happens because veTokens are recalculated based on the remaining lock time, which naturally reduces voting power over time unless a much larger amount of RAAC tokens has been added/increased.

The correct approach is to implement the mint/burn logic as seen in extend(), ensuring proper veToken balance updates.

Vulnerability Details

When _votingState.calculateAndUpdatePower() is invoked by increase(), the following logic will first update duration with the remaining duration, a reduced value compared to when it was first locked. So, the numerator, (amount * duration) may or may not be larger than the numerator when lock() was last called by the user. If the proportionate increase of amount is smaller than the proportionate decrease of duration, initialPower, i.e. bias is going to be smaller than the bias from the first lock.

VotingPowerLib.sol#L88-L93

// Calculate initial voting power that will decay linearly to 0 at unlock time
uint256 duration = unlockTime - block.timestamp;
uint256 initialPower = (amount * duration) / MAX_LOCK_DURATION; // Normalize by max duration
bias = int128(int256(initialPower));
slope = int128(int256(initialPower / duration)); // Power per second decay

🚨 Issue: If newPower < balanceOf(msg.sender), the subtraction results in a negative value, causing _mint() to revert.

Example Scenario

1️⃣ User locks 1000 RAAC for 4 years → Initial power = 1000 veTokens
2️⃣ After 2 years, user increases their lock by 500 RAAC

  • Remaining lock time = 2 years

  • New voting power = (1500 * 2 years) / 4 years = 750 veTokens

Since newPower = 750 but balanceOf(msg.sender) = 1000, the _mint() call fails:

_mint(msg.sender, 750 - 1000); // 🚨 Negative value! Causes revert.

Impact

Affects many users who try to increase their lock duration when their remaining lock time is already reduced unless a much larger amount is going to be increased. This flaw prevents users from dynamically managing their locked tokens.

Tools Used

Manual

Recommendations

Consider making the following change:

veRAACToken.sol#L264-L270

// Update checkpoints
+ uint256 oldPower = balanceOf(msg.sender);
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));
+ // Update veToken balance
+ if (newPower > oldPower) {
+ _mint(msg.sender, newPower - oldPower);
+ } else if (newPower < oldPower) {
+ _burn(msg.sender, oldPower - newPower);
+ }
Updates

Lead Judging Commences

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

veRAACToken::increase underflows on newPower - balanceOf(msg.sender)

Support

FAQs

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