Core Contracts

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

Incorrect Boost Amount Calculation Leading to Wrong Reward Distribution

Summary

The boost calculation logic returns incorrect values in certain scenarios, potentially leading to users receiving incorrect reward amounts and breaking the intended boost mechanics.

Description

https://github.com/Cyfrin/2025-02-raac/blob/89ccb062e2b175374d40d824263a4c0b601bcb7f/contracts/core/governance/boost/BoostController.sol#L122

In the BoostController contract's _calculateBoost() function, there is a logical error in how the boost amounts are calculated and returned. The current implementation:

  1. Incorrectly handles cases where boostedAmount < amount

  2. Has inconsistent minimum boost enforcement

  3. Could return unboosted amounts when it should return boosted ones

Impact

  • Users could receive incorrect (lower) rewards than they should

  • Others might get higher than the maximum allowed boost (2.5x)

Proof of concept

amount = 1000
MIN_BOOST = 10000 (1x)
MAX_BOOST = 25000 (2.5x)

Case 1: boostedAmount = 900

  • Current code returns 1000 (unboosted)

  • Should return 1000 * MIN_BOOST / 10000 = 1000

Case 2: boostedAmount = 2600

  • Current code returns min(2600, 2500)

  • Correct, but reached through the wrong logic path

Recommendations

function _calculateBoost(
address user,
address pool,
uint256 amount
) internal view returns (uint256) {
if (amount == 0) revert InvalidBoostAmount();
if (!supportedPools[pool]) revert PoolNotSupported();
// Get current weights without modifying state
(uint256 totalWeight, uint256 totalVotingPower, uint256 votingPower) = updateTotalWeight();
// @audit : uses the current voting power , instead of the user snapshot
uint256 userBalance = IERC20(address(veToken)).balanceOf(user);
uint256 totalSupply = IERC20(address(veToken)).totalSupply();
if (userBalance == 0 || totalSupply == 0) {
return amount;
}
// Create parameters struct for calculation
BoostCalculator.BoostParameters memory params = BoostCalculator.BoostParameters({
maxBoost: boostState.maxBoost,
minBoost: boostState.minBoost,
boostWindow: boostState.boostWindow,
totalWeight: totalWeight,
totalVotingPower: totalVotingPower,
votingPower: votingPower
});
(uint256 boostBasisPoints, uint256 boostedAmount) = BoostCalculator.calculateTimeWeightedBoost(
params,
userBalance,
totalSupply,
amount
);
uint256 minBoostAmount = amount * MIN_BOOST / 10000; // 1x
uint256 maxBoostAmount = amount * MAX_BOOST / 10000; // 2.5x
// Clamp boostedAmount between min and max boost
if (boostedAmount < minBoostAmount) {
return minBoostAmount;
}
if (boostedAmount > maxBoostAmount) {
return maxBoostAmount;
}
return boostedAmount;
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 7 months ago
Submission Judgement Published
Invalidated
Reason: Too generic

Support

FAQs

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

Give us feedback!