Core Contracts

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

Inconsistent Voting Power Calculation in mint Function

Author Revealed upon completion

Summary

The mint function in the veRAACToken contract incorrectly mints veRAAC tokens based on raw amount instead of the calculated voting power (newPower) derived from _votingState.calculateAndUpdatePower, leading to an inconsistent representation of voting power versus locked RAAC tokens. This fully valid medium-impact, medium-likelihood vulnerability could result in users receiving more or fewer veRAAC tokens than their lock duration and amount entitle them to, skewing governance voting power and reward boosts in the RAAC protocol.

Vulnerability Details

The mint function is intended to mint veRAAC tokens proportional to the voting power calculated from locked RAAC amount and duration:

Issue:

amountToMint is the underlying RAAC amount, not the scaled voting power.

In lock, _mint uses newPower (time-weighted voting power), while mint uses amountToMint directly, bypassing _votingState.calculateAndUpdatePower.
No duration parameter in mint means voting power isn’t adjusted for lock time, unlike lock, leading to inconsistency (e.g., 1,000 RAAC locked for 1 year = 250 veRAAC, but mint gives 1,000 veRAAC).
Scenario:
Reserve pool mints 1,000 RAAC via mint for user A, index = 1e27.
User A receives 1,000 veRAAC, but protocol expects time-weighted power (e.g., 250 for 1-year lock).
User A votes with 1,000 power, skewing $10M governance decisions (e.g., 4x intended influence).
Inconsistent with lock, where 1,000 RAAC over 1 year yields ~250 veRAAC.
Analysis: mint lacks voting power adjustment, breaking the veToken model’s linear decay (amount * duration / max_duration), fully validating the inconsistency.

Impact

The over- or under-allocation of voting power (e.g., 1,000 vs. 250 veRAAC for $1,000 RAAC locked) is a medium-impact issue, as it skews governance influence and boost calculations (e.g., $10M pool rewards) without direct fund loss, but disrupts fairness and protocol integrity. The medium likelihood reflects frequent mint calls by the reserve pool in lending operations, making this a persistent risk in active use.

Tools Used

Manual Code Review: Confirmed mint bypasses _votingState.calculateAndUpdatePower, unlike lock, revealing the inconsistency with veToken design principles (e.g., Aave’s veBAL).

Recommendations

Correct mint to use time-weighted voting power:

function mint(
address caller,
address onBehalfOf,
uint256 amountToMint,
uint256 index,
uint256 duration // Add duration parameter
) external override onlyReservePool returns (bool, uint256, uint256, uint256) {
if (amountToMint == 0) {
return (false, 0, totalSupply(), 0);
}
uint256 amountScaled = amountToMint.rayDiv(index);
if (amountScaled == 0) revert InvalidAmount();
if (duration < MIN_LOCK_DURATION || duration > MAX_LOCK_DURATION) revert InvalidLockDuration();
uint256 scaledBalance = balanceOf(onBehalfOf);
bool isFirstMint = scaledBalance == 0;
uint256 balanceIncrease = 0;
if (_userState[onBehalfOf].index != 0 && _userState[onBehalfOf].index < index) {
balanceIncrease = scaledBalance.rayMul(index) - scaledBalance.rayMul(_userState[onBehalfOf].index);
}
_userState[onBehalfOf].index = index.toUint128();
uint256 unlockTime = block.timestamp + duration;
(int128 bias, int128 slope) = _votingState.calculateAndUpdatePower(onBehalfOf, amountToMint, unlockTime);
uint256 newPower = uint256(uint128(bias));
_mint(onBehalfOf, newPower.toUint128());
emit Mint(caller, onBehalfOf, amountToMint, index);
return (isFirstMint, newPower, totalSupply(), amountScaled);
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 11 days ago
Submission Judgement Published
Invalidated
Reason: Lack of quality

Support

FAQs

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