When a user interacts with a gauge and a new balance checkpoint is created (in storage of this gauge), then checkpoint.voted for this new checkpoint is always false.
Unless users are aware of this bug and call voter.poke after each interaction with the gauge or before claiming rewards, they will be unfairly missing rewards.
Proof of Concept
User Alice votes. That creates her first checkpoint with voted == true. Then she waits some time and deposits tokens to the same gauge. This creates another checkpoint. Boolean variable voted is calculated in this line:
Lines of code
https://github.com/code-423n4/2022-05-velodrome/blob/7fda97c570b758bbfa7dd6724a336c43d4041740/contracts/contracts/Gauge.sol#L309
Vulnerability details
Impact
When a user interacts with a gauge and a new balance checkpoint is created (in storage of this gauge), then
checkpoint.voted
for this new checkpoint is alwaysfalse
.Unless users are aware of this bug and call
voter.poke
after each interaction with the gauge or before claiming rewards, they will be unfairly missing rewards.Proof of Concept
User Alice votes. That creates her first checkpoint with
voted == true
. Then she waits some time and deposits tokens to the same gauge. This creates another checkpoint. Boolean variablevoted
is calculated in this line:_nCheckPoints
is index of a checkpoint that doesn’t yet exist, socheckpoints[account][_nCheckPoints].voted
evaluates tofalse
Missing of rewards is caused by the following lines in earned function:
https://github.com/code-423n4/2022-05-velodrome/blob/7fda97c570b758bbfa7dd6724a336c43d4041740/contracts/contracts/Gauge.sol#L489-L490
https://github.com/code-423n4/2022-05-velodrome/blob/7fda97c570b758bbfa7dd6724a336c43d4041740/contracts/contracts/Gauge.sol#L499-L500
Tools Used
Tested in Foundry
Recommended Mitigation Steps
Change
to
Last checkpoint has index
_nCheckPoints - 1
, not_nCheckPoints
.