In FjordPoints.sol, the contract accumulates point distribution across epochs via pointsPerToken. Based on the current mechanism, users can unfairly earn larger rewards than they should when they:
Stake tokens, unstake tokens and re-stake tokens after a couple of epochs have passed.
Stake a small number of token and accumulate the pointsPerToken across many epochs by not calling FjordPoints::claimPoints. When pointsPerToken has accumulated to a large amount, stake a large number of tokens in that epoch and claim larger rewards then they should.
The updatePendingPoints() function calculates pending rewards based on the difference between the current pointsPerToken and the user’s lastPointsPerToken.
Points are distributed per epoch using the distributePoints() function. This function calculates the pointsPerToken by dividing the points accrued since the last distribution by the total amount staked.
If the lastPointsPerToken is not properly updated when the user re-stakes, the user may receive points for all epochs between their unstake and re-stake, even though they were not participating in staking during that time. Please see below example:
Epoch 1:
User stakes 100 tokens.
Total Staked: 1000 tokens.
Points distributed = 100 points.
pointsPerToken = 100 points / 1000 tokens = 0.1 points per token.
User’s lastPointsPerToken is set to 0.1.
Epoch 2:
User unstakes all 100 tokens.
Total Staked: 1000 tokens.
Points distributed = 100 points.
pointsPerToken = 0.1 + 100 points / 1000 tokens = 0.2 points per token.
User’s lastPointsPerToken is set to 0.2.
Epochs 3-9:
Additional points are distributed, but the user is not staking any tokens.
Assume pointsPerToken increases to 1.0 by the end of epoch 9.
Epoch 10:
User re-stakes 100 tokens.
Total Staked: 1000 tokens.
pointsPerToken after distribution = 1.1 points per token.
The updatePendingPoints() function calculates pending points as:
pendingPoints = 100 * (1.1 - 0.2) = 90 points.
Here, the user receives 90 points, which includes rewards for epochs 3-9, even though they were not staked during those epochs.
Similarly, in the case where a user stakes a small number of token and accumulate the pointsPerToken across many epochs by not calling FjordPoints::claimPoints, and increases their stake significatntly when pointsPerToken has accumulated to a large amount before claiming their rewards, they could also unfairly gain extra rewards than intended.
Incorrect/ unfair accounting of rewards leading to larger than intended payouts of points to users who intentially or unintentially manipulate the system in ways described above. Further, it leads to more points being minted then what was intended per epoch based on pointsPerEpoch.
Manual review.
Consider allocating points on an epoch-by-epoch basis, where users only receive points for epochs they have participated in. This can be done by recording the user's staked amount at the start of each epoch and calculating rewards based on that specific epoch.
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.