In the BaseGauge contract, the boost parameters used to calculate reward multipliers are misconfigured. During initialization, the contract sets boostState.minBoost to 1e18 instead of the intended value of 10_000 (i.e., 10,000 basis points representing a 1× boost). This erroneous initialization causes the boost calculation in the reward distribution flow to underflow when computing the boost range (i.e., maxBoost - minBoost), leading to arithmetic errors and transaction reversion. As a result, when a user—such as Alice—attempts to claim rewards via the getReward function, the reward update mechanism (triggered by the updateReward modifier) eventually calls _applyBoost. This function then invokes BoostCalculator.calculateBoost, where the subtraction of minBoost from maxBoost underflows, causing the transaction to revert and effectively denying reward claims. The fallout is a critical denial of service affecting both RAACGauge and RWAGauge, ultimately undermining the protocol's governance and incentive mechanisms.
User Locking and Voting Power Acquisition:
Users lock their RAAC tokens using veRAACToken::lock to receive time-weighted veRAAC tokens. This process provides users with voting power for governance and rewards.
Gauge Setup and Reward Claiming:
The GaugeController admin adds a gauge (e.g., a RWA gauge) with a nonzero initial weight. When a user (Alice) later calls getReward, the reward flow begins:
The getReward function is called.
The updateReward modifier triggers an internal call to _updateReward, which computes the user's earned rewards.
Within _updateReward, the earned function is invoked, which in turn calls getUserWeight.
The getUserWeight function calls _applyBoost, whose role is to adjust the base weight by a boost factor calculated using the user's veRAAC balance and the total supply.
Boost Calculation Breakdown:
In _applyBoost, the contract constructs a BoostParameters struct using the boost state:
Then, it calls:
Inside BoostCalculator.calculateBoost, the boost range is computed as:
Since params.minBoost is set to 1e18 (a value far exceeding any reasonable maxBoost that might be set around 10_000), the subtraction underflows. Solidity (version 0.8+) automatically reverts on underflow, so the entire reward calculation fails.
BaseGauge Constructor (Initialization Bug):
_applyBoost Function in BaseGauge:
BoostCalculator.calculateBoost Function:
User Setup:
Alice locks RAAC tokens via veRAACToken::lock and acquires voting power.
A gauge is set up (e.g., via GaugeController) and configured with reward distribution parameters.
Reward Claim Attempt:
Alice calls getReward to claim her rewards.
The reward flow invokes _updateReward → earned → getUserWeight → _applyBoost.
In _applyBoost, the boost calculation fails due to the arithmetic underflow caused by boostState.minBoost being set to 1e18.
Consequently, the transaction reverts with an arithmetic error, and Alice cannot claim her rewards.
Below is a simplified Foundry test illustrating the DoS condition caused by the misconfigured minBoost:
Step 1: Create a Foundry project:
Step 2: Remove unnecessary files.
Step 3: Place your contracts in the src directory.
Step 4: Create a test directory adjacent to src and add the above test file (e.g., BaseGaugeBoostTest.t.sol).
Step 5: Run the test:
Expected Output:
The test should revert as expected, confirming that the reward claim fails due to the misconfigured boost parameter.
Denial of Service in Reward Claims:
Users like Alice will be unable to claim rewards because the arithmetic underflow in boost calculations causes transactions to revert.
Governance and Incentive Distortion:
Since reward multipliers and boosted voting power are integral to governance, an inability to compute the correct boost results in misaligned incentives and can skew governance outcomes.
Protocol Trust and Stability:
Repeated failures in reward distribution will erode user trust and can cause reduced participation in both staking and governance, destabilizing the protocol’s economic model.
Manual Review
Foundry
To remediate this vulnerability, the initialization of the boost state in the BaseGauge contract must be corrected. Specifically, boostState.minBoost should be set to the intended value of 10_000 (representing 1× boost or 10000 basis points) rather than 1e18.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.