If FjordPoints
and FjordStaking
are deployed in different blocks, resulting in different block timestamps, the epoch switch will occur at different times. This discrepancy creates an opportunity for Points
farming without requiring token locking for the lockCycle
, allowing users to frontrun the Points
distribution.
Because FjordPoints
and FjordStaking
contracts are deployed independently, they might be deployed in different blocks with varying block timestamps.
Examining the deployment script:
Here, FjordPoints
is deployed before FjordStaking
. Although Foundry broadcasts these transactions sequentially, there is no guarantee that the FjordStaking
deployment will occur in the same block as the FjordPoints
deployment. In an edge case, FjordPoints
could be included in one block, and due to a gas spike, FjordStaking
might be deployed several blocks later.
If FjordPoints
and FjordStaking
are deployed in different blocks, their epoch start times will differ. This discrepancy can be exploited to farm Points
without locking tokens for the lockCycle
in FjordStaking
.
This is possible because in the FjordStaking
contract, users can stake and unstake FJO
tokens immediately within the same epoch, as shown in this code:
Consider this scenario:
Alice notices that FjordPoints
and FjordStaking
are deployed in different blocks, causing their epoch switches to differ.
Alice stakes a large amount of FJO
in FjordStaking
just before the epoch switch in the FjordPoints
contract.
Alice calls FjordPoints.distributePoints()
in the first block that allows for new Points
distribution (after the epoch switch in the FjordPoints
contract) and then calls the unstake function in the same block before the epoch switch in the FjordStaking
contract.
Alice is awarded Points
from FJO
that she didn't need to stake for the full lockCycle
duration.
There is no frontrunning protection mechanism for Points
distribution other than locking tokens for the lockCycle
in the FjordStaking
contract, which can be circumvented as shown.
In the FjordStaking
contract, frontrunning protection is present in two forms: new rewards are only distributed to stakers from the previous epoch and only for tokens locked for the full lockCycle
duration.
Frontrunning of the Points
distribution in the FjordPoints
contract.
https://github.com/Cyfrin/2024-08-fjord/blob/main/script/forge/DeployStaking.s.sol#L10-L25
https://github.com/Cyfrin/2024-08-fjord/blob/main/src/FjordStaking.sol#L462-L466
https://github.com/Cyfrin/2024-08-fjord/blob/main/src/FjordPoints.sol#L232-L248
Manual review.
The epoch switch times should be aligned for both FjordPoints
and FjordStaking
contracts.
This can be achieved by either deploying the FjordPoints
contract within the FjordStaking
contract's constructor:
Or by updating the lastDistribution
with FjordStaking.startTime()
when calling the FjordPoints.setStakingContract()
function:
Impact: High - Users are getting an unreasonable amount of points through exploiting a vulnerability Likelihood: Low - Most of the times, when using the script, all deployment tx will get processed in the same block. But, there is a small chance for them to be processed in different blocks.
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.