Core Contracts

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

Incorrect Boost Multiplier Calculation

Summary

The current implementation incorrectly calculates the boost multiplier by using the already boosted amount as both numerator and denominator. This results in the maximum boost value always being returned regardless of the actual user position.

Vulnerability Details

Due to flawed formula implementation, the getBoostMultiplier function incorrectly returned the maximum boost (2.5x) regardless of the user's actual position.

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

function getBoostMultiplier(
address user,
address pool
) external view override returns (uint256) {
if (!supportedPools[pool]) revert PoolNotSupported();
UserBoost storage userBoost = userBoosts[user][pool];
if (userBoost.amount == 0) return MIN_BOOST;
// Flawed calculation always returns MAX_BOOST
uint256 baseAmount = userBoost.amount * 10000 / MAX_BOOST;
return userBoost.amount * 10000 / baseAmount; // Always returns MAX_BOOST
}

Impact

Always returns MAX_BOOST resulting in wrong boost calculation

Recommendations

Handle how Curve handles it as stated in the documentation.

function getBoostMultiplier(
address user,
address pool
) external view override returns (uint256) {
if (!supportedPools[pool]) revert PoolNotSupported();
// Get voting power data
(uint256 totalWeight, uint256 totalVotingPower, uint256 votingPower) = updateTotalWeight();
uint256 userVotingPower = veToken.getVotingPower(user, block.timestamp);
// Get pool and user deposit information
PoolBoost storage poolBoost = poolBoosts[pool];
UserBoost storage userBoost = userBoosts[user][pool];
if (userBoost.amount == 0) return MIN_BOOST;
// Curve-style boost calculation
uint256 D = poolBoost.workingSupply; // Total working supply in pool
uint256 d = userBoost.amount; // User's base deposit amount
uint256 v = userVotingPower; // User's veToken voting power
uint256 V = totalVotingPower; // Total veToken voting power
if (D == 0 || V == 0 || d == 0) return MIN_BOOST;
// Calculate boost using Curve formula
uint256 boost = (150 * D * v) / (V * d) + 10000;
// Apply min/max bounds
return boost > MAX_BOOST ? MAX_BOOST : (boost < MIN_BOOST ? MIN_BOOST : boost);
}
Updates

Lead Judging Commences

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

BoostController::getBoostMultiplier always returns MAX_BOOST for any non-zero boost due to mathematical calculation error, defeating the incentive mechanism

Support

FAQs

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

Give us feedback!