Core Contracts

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

Inconsistent Boost Calculation Data Sources

Location

governance -> boost ->BoostController.sol

Summary

In the BoostController contract, boost values are calculated using two different sources. One method simply reads the raw ERC20 balance (using IERC20(veToken).balanceOf(user)), while the other uses a time‑weighted approach (veToken.getVotingPower(user, block.timestamp)). Moreover, the updateTotalWeight() function pulls the contract’s own lock position instead of combining all relevant data. This mismatch can cause the same user to end up with different boost values, resulting in unpredictable reward allocations.

Vulnerability Details

Different functions in the BoostController derive boost values using inconsistent data:

  • The internal _calculateBoost function queries the user’s balance and total supply using the ERC20 interface.

  • The external calculateBoost function calls veToken.getVotingPower(user, block.timestamp).

  • The helper updateTotalWeight() returns the contract’s lock position rather than a global measure.
    This means that a user might receive one boost value when calling calculateBoost and a different one when the boost is updated via updateUserBoost, potentially enabling exploitation or unintentional misallocation of rewards.

Impact

Economic Impact: Users might end up with a boost—and thus rewards—that are either lower or higher than expected, potentially disrupting the intended incentive structure of the protocol.

User Trust: When boost values are inconsistent, it can erode confidence in the protocol’s fairness and accuracy, leading to disputes or reduced participation.

Exploitation Risk: An attacker might exploit the inconsistency by manipulating one of the data sources (for example, by temporarily changing their token balance) to gain an unfair advantage.

Proof of Code

// In _calculateBoost:
uint256 userBalance = IERC20(address(veToken)).balanceOf(user);
uint256 totalSupply = IERC20(address(veToken)).totalSupply();
// In calculateBoost:
uint256 userVotingPower = veToken.getVotingPower(user, block.timestamp);

Recommendations

Standardize the data source for all boost calculations. For example, always use the time‑weighted getVotingPower method and adjust updateTotalWeight() to return a globally consistent measure. This ensures that both on‑chain boost updates and external queries yield consistent values.

Updates

Lead Judging Commences

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

BaseGauge::_applyBoost, GaugeController::vote, BoostController::calculateBoost use balanceOf() instead of getVotingPower() for vote-escrow tokens, negating time-decay mechanism

Support

FAQs

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