Submitted by 0xDjango, also found by unforgiven
StakerVault.sol#L112-L119
I believe this to be a high severity vulnerability that is potentially included in the currently deployed StakerVault.sol contract also. The team will be contacted immediately following the submission of this report.
In StakerVault.sol, the user checkpoints occur AFTER the balances are updated in the transfer() function. The user checkpoints update the amount of rewards claimable by the user. Since their rewards will be updated after transfer, a user can send funds between their own accounts and repeatedly claim maximum rewards since the pools inception.
In every actionable function except transfer() of StakerVault.sol, a call to ILpGauge(lpGauge).userCheckpoint() is correctly made BEFORE the action effects.
Assume a certain period of time has passed since the pools inception. For easy accounting, assume poolStakedIntegral of LpGauge.sol equals 1. The poolStakedIntegral is used to keep track of the current reward rate.
Steps:
Assuming Account B is new to the protocol, their perUserStakedIntegral[user] will default to 0.
perUserShare[B] += 1000 * (1 - 0) = 1000
In StakerVault.transfer(), move the call to ILpGauge(lpGauge).userCheckpoint() to before the balances are updated.
chase-manning (Backd) confirmed and resolved
