DeFiHardhat
12,000 USDC
View results
Submission Details
Severity: low
Invalid

Misplacement of `returnIfBelowMin` boolean check leads to loss of precision

Description

The function _capLpTokenSupply contains a condition to return an empty array if the reserves are set to decrease after an update. The intention is to cap the ratio first and then call _capLpTokenSupply again. However, this condition is currently located in the part of the function that calculates the increase in reserves.

Whenever the lpTokenSupply increases significantly (and consequently, the reserves), the function calculates the ratio first. However, it does not do the same when the reserves decrease.

function _capLpTokenSupply(
...
) internal view returns (uint256[] memory cappedReserves) {
...
// If LP Token Supply increased, check that it didn't increase above the max.
if (lpTokenSupply > lastLpTokenSupply) {
...
if (lpTokenSupply > maxLpTokenSupply) {
@> // If `_capLpTokenSupply` decreases the reserves, cap the ratio first, to maximize precision.
@> if (returnIfBelowMin) return new uint256[](0);
cappedReserves = tryCalcLPTokenUnderlying(
mfpWf,
maxLpTokenSupply,
cappedReserves,
lpTokenSupply,
data
);
}
// If LP Token Suppply decreased, check that it didn't increase below the min.
} else if (lpTokenSupply < lastLpTokenSupply) {
uint256 minLpTokenSupply = (lastLpTokenSupply *
(ABDKMathQuad.ONE.sub(crp.maxLpSupplyDecrease))
.powu(capExponent)
.to128x128()
.toUint256()) / CAP_PRECISION2;
if (lpTokenSupply < minLpTokenSupply) {
cappedReserves = tryCalcLPTokenUnderlying(
mfpWf,
minLpTokenSupply,
cappedReserves,
lpTokenSupply,
data
);
}
}
}

Risk

Likelyhood: High

  • Each time the new lpTokenSupply are higher than the maxLpTokenSupply or lower than minLpTokenSupply.

Impact: Medium

  • _capReserves calculate the rate first when the supply increases instead of decreasing, leading to a loss of precision.

Proof of Concept

Foundry PoC to add in `Pump.CapReserves.t.sol`
function test_capLpTokenSupplyBad0ArrayReturn() public {
lastReserves[0] = 100;
lastReserves[1] = 100;
// Reserves decreases
reserves[0] = 100;
reserves[1] = 80;
IMultiFlowPumpWellFunction mfpWf = IMultiFlowPumpWellFunction(
address(wf)
);
uint256[] memory cappedReserves = _capLpTokenSupply(
lastReserves,
reserves,
1,
CapReservesParameters(
maxRateChanges,
maxLpSupplyIncrease,
maxLpSupplyDecrease
),
mfpWf,
new bytes(0),
true
);
// will revert
assertEq(cappedReserves.length, 0);
}

Recommended Mitigation

Move the condition to be used when if (lpTokenSupply < minLpTokenSupply).

Updates

Lead Judging Commences

giovannidisiena Lead Judge
about 1 year ago
giovannidisiena Lead Judge about 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

Calc LP below min

giovannidisiena Lead Judge
about 1 year ago
giovannidisiena Lead Judge about 1 year ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement
Assigned finding tags:

Calc LP below min

Support

FAQs

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