A malicious user can manipulate the rewardPerToken
value by sandwiching other users' reward claims with large stake/unstake actions, causing victims to lose rewards
The earned()
function calculates rewards based on the current rewardPerToken
value and the user's weight. The issue lies in how rewardPerToken
is calculated in getRewardPerToken()
:
An attacker can:
Stake a large amount just before a victim claims
Let the victim claim with a diluted rewardPerToken value
Immediately unstake and claim their own rewards
Users can permanently lose their rightful rewards due to manipulation of the rewardPerToken
calculation.
The impact is HIGH because:
Direct loss of funds (rewards) for users
Attack is profitable for malicious actors
Core reward distribution mechanism is compromised
Manual review
First a bug in the BaseGauge::constructor()
function need to be fixed, as this cause overflow in the calculations due to a incorrect assignment of boostState.minBoost
:
Add the following test case to the test/unit/core/governance/gauges/GaugeController.test.js
file:
Implement a reward calculation mechanism that is resistant to short-term stake/unstake manipulations like a minimum stake duration.
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.