Malicious users can abuse the points distribution mechanism by staking and unstaking Fjord Tokens around the distributePoints transaction, allowing them to earn points for instant staking period. This also enables them to manipulate the pointsPerToken distribution by temporarily staking large amounts of tokens, thereby distorting the reward mechanism without any costs
Fjord Points (BJB) are earned by staking Fjord Tokens in the Fjord Staking contract. Users accrue points based on the duration their FJO tokens remain staked, with the accumulation rate determined by the pointsPerToken value:
Points are distributed after each epoch by calling distributePoints.
Malicious users can abuse this mechanism by strategically staking and unstaking tokens around the distributePoints function call. Specifically, they can:
Refrain from staking any Fjord Tokens initially.
At the end of a FjordStaking epoch, call FjordStaking::stake to stake tokens, the tokens will be staked in a new epoch.
Call distributePoints.
Back-run the distributePoints to:
3.1 Claim the earned points corresponding to a week’s stake by calling claimPoints
3.2 Immediately unstake their Fjord Tokens. The unstake is possible since the stake was done on the same epoch and the contract allows for immediate unstake in such case:
This behavior allows users to earn points for an instant staking period. Additionally, by staking a significant amount of Fjord Tokens temporarily, users can manipulate the pointsPerToken distribution, as the increase in pointsPerToken is inversely proportional to the total staked amount:
Users can stake a large amount of tokens to skew the pointsPerToken calculation, and then immediately unstake to regain access to their tokens. Effectively the cost of this exploit is zero.
Copy and paste the following test case into test/unit/points.t.sol:
First, make some necessary changes to produce a real PoC since the existing test suite on points.t.sol only mocks the stake action:
Add the following test case:
By front-running the distributePoints function to stake and back-running it to claim points and unstake, users can exploit the points distribution to:
Earn points for an instant staking period.
Manipulate the pointsPerToken distribution by staking a large number of tokens temporarily.
Manual Review
The easiest fix is to restrict the distributePoints to FjordStaking and call it after each epoch's increment in _checkEpochRollover:
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.