Incorrect maturityFeeGrowthX128
may lead to miscalculated rewards
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↗.