Closed code423n4 closed 2 years ago
From @denett If the rewards are significant users can call syncRewards() themselves, to protect others to gain an unfair advantage. We could add a call to syncRewards if not yet done before deposits/withdrawals.
dupe of #110
Lines of code
https://github.com/code-423n4/2022-09-frax/blob/55ea6b1ef3857a277e2f47d42029bc0f3d6f9173/src/sfrxETH.sol#L48 https://github.com/code-423n4/2022-09-frax/blob/55ea6b1ef3857a277e2f47d42029bc0f3d6f9173/src/sfrxETH.sol#L48
Vulnerability details
Impact
When
syncRewards()
is not called immediatly after a cycle end or withdraws do not occurr immediatly after a cycle ends, thentotalSupply()
calculates a stale value. This causes incorrect calculations of staking rewards.Proof of Concept
Assume that
rewardsCycleLength = 1 week
rewardsCycleEnd
rewardsCycleEnd + 1 days
totalSupply()
returns the same value.syncRewards
has not been called fromrewardsCycleEnd
until now.syncRewards
is finally calledrewardsCycleEnd + 1 week
they both withdraw and get back the same amount of frxETH (staked amount + staking rewards)The problem is that user B staked for 1 day less than user A, so her staking reward is bigger than expected while user A's staking reward is smaller than expected.
The same issue arises with withdrawals. If
syncRewards()
is called with a delay respect torewardsCycleEnd
, the first staker who withdraws after the end of a cycle does not receive the rewards corresponding to the time frame fromrewardsCycleEnd
to the moment he withdraws.sfrxETH
obtained from staking.syncRewards()
withdraw
/redeem
at timestamp = end of last cycle + 1 daysbeforeWithdraw()
is executed only after calculations of shares/assets to receive (ERC4626.sol#L78), so it only callssyncRewards()
after the calculation. The last day since the end of the previous cycle is not taken into account in the amount received by the user.Tools Used
Manual review
Recommended Mitigation Steps
In
sfrxETH.sol
override the functions that allow staking/unstaking. Put a call tosyncRewards()
before each operation.With this, the overriding of
beforeWithdraw
insfrxETH
can be dropped.