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

Faulty Division Operation Vulnerability 

Summary

The FjordPoints contract contains a potential Faulty Division Operation vulnerability in its distributePoints function, which could lead to precision loss and incorrect calculation of distribution periods.

Vulnerability Details

The vulnerable line is in the distributePoints function:

uint256 weeksPending = (block.timestamp - lastDistribution) / EPOCH_DURATION;

This operation performs integer division to calculate the number of weeks pending for point distribution. However, integer division in Solidity truncates any remainder, potentially leading to lost precision and underestimation of the actual time elapsed.

Impact

The imprecise calculation of weeksPending can result in:

  1. Underestimation of distribution periods, leading to fewer points being distributed than intended.

  2. Inconsistent distribution timing, as fractional weeks are ignored.

  3. Potential for manipulation by timing transactions to maximize or minimize the weeksPending calculation.

Proof of Concept

Consider the following scenario:

  • EPOCH_DURATION is set to 1 week (604,800 seconds)

  • lastDistribution was 10 days ago (864,000 seconds)

The calculation would be:

weeksPending = 864,000 / 604,800 = 1

This results in only 1 week of points being distributed, despite nearly 1.5 weeks having passed, leading to an underdistribution of points.

Tools Used

Manual code review

Recommendations

  1. Use a Precision Factor:
    Multiply by a large factor before division to retain more precision:

    uint256 constant PRECISION_FACTOR = 1e18;
    uint256 weeksPending = ((block.timestamp - lastDistribution) * PRECISION_FACTOR) / EPOCH_DURATION;

    Then adjust subsequent calculations to account for this precision factor.

  2. Track Time in Smaller Units:
    Consider tracking time in days or hours instead of weeks for finer granularity:

    uint256 public constant EPOCH_DURATION = 1 days;
    uint256 daysPending = (block.timestamp - lastDistribution) / EPOCH_DURATION;
  3. Use OpenZeppelin's Math Library:
    Utilize OpenZeppelin's Math library for more precise calculations:

    import "@openzeppelin/contracts/utils/math/Math.sol";
    uint256 weeksPending = Math.ceilDiv(block.timestamp - lastDistribution, EPOCH_DURATION);
  4. Accumulate Leftover Time:
    Keep track of the remainder and include it in the next calculation:

    uint256 public timeLeftover;
    function distributePoints() public {
    uint256 timePassed = block.timestamp - lastDistribution + timeLeftover;
    uint256 weeksPending = timePassed / EPOCH_DURATION;
    timeLeftover = timePassed % EPOCH_DURATION;
    // ... rest of the distribution logic ...
    lastDistribution = block.timestamp;
    }
Updates

Lead Judging Commences

inallhonesty Lead Judge 9 months ago
Submission Judgement Published
Invalidated
Reason: Design choice

Support

FAQs

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