Core Contracts

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

Use of Voting Power Instead of Balance in Boost Calculation

Summary

The BoostController contract contains an inconsistency in how it calculates boost values. The external calculateBoost function incorrectly uses a user's time-weighted voting power instead of their veToken balance, while the internal implementation correctly uses the balance. This mismatch can lead to incorrect boost calculations, potentially resulting in manipulated reward distributions.

Vulnerability Details

In the calculateBoost function, the contract retrieves a user's voting power using veToken.getVotingPower():

function calculateBoost(
address user,
address pool,
uint256 amount
) external view override returns (uint256 boostBasisPoints, uint256 boostedAmount) {
// ...
uint256 userVotingPower = veToken.getVotingPower(user, block.timestamp);
// ...
return BoostCalculator.calculateTimeWeightedBoost(
params,
userVotingPower, // <-- Using voting power here
totalVotingPower,
amount
);
}

However, the calculateTimeWeightedBoost function expects a user's veToken balance as its second parameter, not their voting power:

function calculateTimeWeightedBoost(
BoostState storage state,
uint256 userBalance, // <-- Expects veToken balance
uint256 totalSupply,
uint256 amount
) internal

Meanwhile, the internal _calculateBoost function correctly uses the user's veToken balance:

function _calculateBoost(
address user,
address pool,
uint256 amount
) internal view returns (uint256) {
// ...
uint256 userBalance = IERC20(address(veToken)).balanceOf(user);
uint256 totalSupply = IERC20(address(veToken)).totalSupply();
// ...
}

In veToken systems, voting power and token balance are different metrics:

The balance represents the raw veToken amount
Voting power is time-weighted and decays linearly as the lock approaches expiry

Impact

Users may receive higher or lower boosts than intended, leading to unfair reward distributions. This opens up an an attack vector where sers could time their interactions to exploit differences between these calculations.

Tools Used

Manual Review

Recommendations

Modify calculateBoost to use veToken balance (recommended):

function calculateBoost(
address user,
address pool,
uint256 amount
) external view override returns (uint256 boostBasisPoints, uint256 boostedAmount) {
// ...
uint256 userBalance = IERC20(address(veToken)).balanceOf(user);
// ...
return BoostCalculator.calculateTimeWeightedBoost(
params,
userBalance, // Changed to balance
totalVotingPower,
amount
);
}
Updates

Lead Judging Commences

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

BoostController uses inconsistent input values in calculateBoost (voting power) vs _calculateBoost (token balance), creating misleading boost estimates

Support

FAQs

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