Assessment reports>Falcon Finance>Medium findings>Incorrect ,maturityFeeGrowthX128, may lead to miscalculated rewards
Category: Coding Mistakes

Incorrect maturityFeeGrowthX128 may lead to miscalculated rewards

Medium Severity
Medium Impact
High Likelihood

Description

The maturityFeeGrowthX128 mapping is used to store the current fee growth at maturity time for a specific duration supported by the contract.

function mature(uint256 duration, uint256 timestamp) public {
    // Round timestamp to days to match mint behavior
    timestamp = (timestamp / 1 days) * 1 days;
    require(timestamp <= block.timestamp, ImmaturePosition());

    // Iterate through supported durations
    MaturityBucket storage bucket = maturityBuckets[duration][timestamp];

    if (bucket.totalLiquidity > 0) {
        // Snapshot current fee growth for this duration
        maturityFeeGrowthX128[timestamp] = _durationInfo[duration].feeGrowthX128;
    [...]
    }
}

Additionally, maturityFeeGrowthX128 is utilized for reward calculations for positions locked for a certain duration and associated with a specific maturityTime.

function _unrealizedRewards(Position memory position) internal view returns (uint256, uint256) {
    uint256 currentFeeGrowth;

    // If position is matured, use the snapshotted fee growth
    if (block.timestamp >= position.maturityTime) {
        currentFeeGrowth = maturityFeeGrowthX128[position.maturityTime];
    [...]
    uint256 feeGrowthDeltaX128 = currentFeeGrowth - position.feeGrowthInsideLastX128;
    return ((position.principal * feeGrowthDeltaX128) >> 128, currentFeeGrowth);
}

The issue arises when the contract supports multiple durations, as over time, positions with different durations can share the same maturity time.

Impact

The maturityFeeGrowthX128 value for a specific timestamp can be overwritten by the feeGrowthX128 value corresponding to a different duration.

As a result, in the _unrealizedRewards function, an incorrect maturityFeeGrowthX128 snapshot may be used, containing fee-growth data for a duration unrelated to the given position. Consequently, this function may return an incorrect reward amount, which could be either higher or lower than expected.

Recommendations

We recommend modifying the maturityFeeGrowthX128 mapping to store values not only by timestamp but also by duration. This change would ensure that fee-growth data is accurately maintained for each duration separately, preventing unintended overwrites and ensuring correct reward calculations.

Remediation

This issue has been acknowledged by Falcon, and a fix was implemented in commit 9c34a242.

Zellic © 2025Back to top ↑