DeFiFoundry
20,000 USDC
View results
Submission Details
Severity: medium
Invalid

When `totalStaked = 0`, lastDistribution will not be updated.

Summary

When totalStaked = 0, lastDistribution will not be updated. This means that when new stakers join, they may receive more points than expected.

Vulnerability Details

https://github.com/Cyfrin/2024-08-fjord/blob/0312fa9dca29fa7ed9fc432fdcd05545b736575d/src/FjordPoints.sol#L232

function distributePoints() public {
if (block.timestamp < lastDistribution + EPOCH_DURATION) {
return;
}
if (totalStaked == 0) {
return;
}
uint256 weeksPending = (block.timestamp - lastDistribution) / EPOCH_DURATION;
pointsPerToken =
pointsPerToken.add(weeksPending * (pointsPerEpoch.mul(PRECISION_18).div(totalStaked)));
totalPoints = totalPoints.add(pointsPerEpoch * weeksPending);
lastDistribution = lastDistribution + (weeksPending * 1 weeks);
emit PointsDistributed(pointsPerEpoch, pointsPerToken);
}

When totalStaked equals 0, lastDistribution will not be updated and will directly exit instead. This means that new stakers can claim rewards for the period during which no staking occurred.
For example:

  1. Assume that staking FjordPoints has been deployed in advance, but no stakers have participated yet. After two weeks, staking opens.

  2. After the first staker joins stake and calls distributePoints(), Points are calculated. At this point, totalStaked is already greater than 0, and lastDistribution is the timestamp from two weeks ago. This means that they alone will receive all the Points rewards for the previous two weeks.

Impact

After the system has been in a non-staking state for a long time, the first staker can immediately receive all the Points rewards from the previous period.

Tools Used

Manual Review

Recommendations

Update lastDistribution regardless of whether totalStaked is 0 or not.

function distributePoints() public {
if (block.timestamp < lastDistribution + EPOCH_DURATION) {
return;
}
+ totalPoints = totalPoints.add(pointsPerEpoch * weeksPending);
+ lastDistribution = lastDistribution + (weeksPending * 1 weeks);
if (totalStaked == 0) {
return;
}
uint256 weeksPending = (block.timestamp - lastDistribution) / EPOCH_DURATION;
pointsPerToken =
pointsPerToken.add(weeksPending * (pointsPerEpoch.mul(PRECISION_18).div(totalStaked)));
- totalPoints = totalPoints.add(pointsPerEpoch * weeksPending);
- lastDistribution = lastDistribution + (weeksPending * 1 weeks);
emit PointsDistributed(pointsPerEpoch, pointsPerToken);
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 12 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.