The BaseGauge::earned
function calculates rewards using the user’s boosted weight without verifying if the user has any tokens staked. In particular, since the getUserWeight
function returns a nonzero value based solely on the base weight and minimum boost (even if no tokens are locked), an attacker can claim rewards without participation by exploiting this miscalculation.
The earned function is implemented as:
Here, getUserWeight computes the boosted weight as:
However, the base weight (from the controller) multiplied by the minimum boost is returned regardless of whether the user has actually staked any tokens. As a result, an account that has not participated in the gauge (has no locked tokens) still obtains a positive weight, and thus accumulates rewards over time.
Please also take into consideration that the initial amount for minBoost set in the constructor parameters is 1e18 which is higher than the max boost, leading to wrong calculation.
The provided PoC demonstrates that a user (e.g., Bob) who hasn’t staked any tokens can still accrue and claim rewards:
Proof Of Concept
Add this under the Reward Distribution
describe in BaseGause.test.js
and execute with npx hardhat test --grep "user can manipulate gauge rewards"
Unjust Reward Claim: Users with no staked tokens can claim rewards, undermining the incentive model.
Manual Code Review
Unit Testing
Incorporate Stake Verification:
Modify the weight calculation logic in getUserWeight to account for the actual amount staked (or locked) by the user. The function should return zero if the user has not staked any tokens.
Reward Calculation Adjustment:
Alternatively, adjust the earned function to multiply the difference in reward per token by the user's staked balance, ensuring rewards are proportional to participation.
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.