Core Contracts

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

Incorrect Working Balance Due to Missing State Updates in BoostController

Relevant GitHub Links

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

https://github.com/Cyfrin/2025-02-raac/blob/89ccb062e2b175374d40d824263a4c0b601bcb7f/contracts/core/governance/gauges/BaseGauge.sol#L583-L586

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

Summary

getWorkingBalance() in BoostController.sol reads user boost values without requiring prior state updates via updateUserBoost(). This can lead to incorrect working balance calculations that affect reward distributions and voting power.

Vulnerability Details

In BoostController.sol, getWorkingBalance() retrieves values from userBoosts mapping:

function getWorkingBalance(
address user,
address pool
) external view returns (uint256) {
if (!supportedPools[pool]) revert PoolNotSupported();
UserBoost storage userBoost = userBoosts[user][pool];
return userBoost.amount;
}

The userBoosts mapping only gets populated when updateUserBoost() is called. Without a prior call to updateUserBoost(), userBoost.amount remains at its default value of 0, leading to incorrect working balance calculations.

This working balance is used in critical functions like reward calculations in BaseGauge.sol:

function earned(address account) public view returns (uint256) {
return (getUserWeight(account) *
(getRewardPerToken() - userStates[account].rewardPerTokenPaid) / 1e18
) + userStates[account].rewards;
}

Impact

  1. Users may receive incorrect rewards if their working balance is not properly initialized

  2. Voting power calculations may be inaccurate, affecting governance

  3. Boost multipliers may not be properly applied to staking positions

Tools Used

Manual Review

Recommendations

Add state synchronization:

Make getWorkingBalance() call updateUserBoost() internally:

function getWorkingBalance(address user, address pool) external returns (uint256) {
if (!supportedPools[pool]) revert PoolNotSupported();
updateUserBoost(user, pool);
return userBoosts[user][pool].amount;
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 7 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
inallhonesty Lead Judge 7 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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

Give us feedback!