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

`_capRates()` returns uncapped values.

Summary

In the MultiFlowPump._capRates() function, the return values from calcReservesAtRatioSwap() are ignored, leading to incorrect cappedReserves values being returned.

Vulnerability Details

Consider the function _capRates() from the MultiFlowPump contract.

function _capRates(
uint256[] memory lastReserves,
uint256[] memory reserves,
uint256 capExponent,
CapReservesParameters memory crp,
IMultiFlowPumpWellFunction mfpWf,
bytes memory data
) internal view returns (uint256[] memory cappedReserves) {
cappedReserves = reserves; // (1) cappedReserves initially set here
// Part 1: Cap Rates
// Use the larger reserve as the numerator for the ratio to maximize precision
(uint256 i, uint256 j) = lastReserves[0] > lastReserves[1] ? (0, 1) : (1, 0);
CapRatesVariables memory crv;
crv.rLast = mfpWf.calcRate(lastReserves, i, j, data);
crv.r = mfpWf.calcRate(cappedReserves, i, j, data);
// If the ratio increased, check that it didn't increase above the max.
if (crv.r > crv.rLast) {
bytes16 tempExp = ABDKMathQuad.ONE.add(crp.maxRateChanges[i][j]).powu(capExponent);
crv.rLimit = tempExp.cmp(MAX_CONVERT_TO_128x128) != -1
? crv.rLimit = type(uint256).max
: crv.rLast.mulDivOrMax(tempExp.to128x128().toUint256(), CAP_PRECISION2);
if (cappedReserves[i].mulDiv(CAP_PRECISION, cappedReserves[j]) > crv.rLimit) {
// (2) return value ignored
calcReservesAtRatioSwap(mfpWf, crv.rLimit, cappedReserves, i, j, data);
}
// If the ratio decreased, check that it didn't decrease below the max.
} else if (crv.r < crv.rLast) {
crv.rLimit = crv.rLast.mulDiv(
ABDKMathQuad.ONE.div(ABDKMathQuad.ONE.add(crp.maxRateChanges[j][i])).powu(capExponent).to128x128()
.toUint256(),
CAP_PRECISION2
);
if (cappedReserves[i].mulDiv(CAP_PRECISION, cappedReserves[j]) < crv.rLimit) {
// (3) return value ignored
calcReservesAtRatioSwap(mfpWf, crv.rLimit, cappedReserves, i, j, data);
}
}
}

At both occurrences where calcReservesAtRatioSwap() is called (refer to (2) and (3) in the provided code snippet), the returned values are ignored. Consequently, the cappedReserves variable remains unchanged from its initialization using reserves at the beginning of the function (refer to (1)). As a result, the function returns uncapped values instead of the intended capped ones. This discrepancy is highlighted when comparing _capRates() with the _capLpTokenSupply() function, where return values are appropriately assigned to the cappedReserves variable.

Since _capRates() is utilized by _capReserves(), which in turn is utilized by readCappedReserves() and update() within the MultiFlowPump contract, the incorrect cappedReserves values could significantly impact the output of this oracle.

Impact

MultiFlowPump._capRates() returns incorrect cappedReserves values when cappedReserves[i].mulDiv(CAP_PRECISION, cappedReserves[j]) > crv.rLimit or cappedReserves[i].mulDiv(CAP_PRECISION, cappedReserves[j]) < crv.rLimit, uncapped ratio values will be employed in further computations, (readCappedReserves() and update()), leading to wrong results.

Tools Used

Manual Review

Recommendations

Do not ignore the returned values and instead set cappedReserves to the return values of the function calcReservesAtRatioSwap(). See code below:

diff --git a/MultiFlowPump.sol b/MultiFlowPump.mod.sol
index dac892a..60f4581 100644
--- a/MultiFlowPump.sol
+++ b/MultiFlowPump.mod.sol
@@ -273,7 +273,7 @@ contract MultiFlowPump is IPump, IMultiFlowPumpErrors, IInstantaneousPump, ICumu
? crv.rLimit = type(uint256).max
: crv.rLast.mulDivOrMax(tempExp.to128x128().toUint256(), CAP_PRECISION2);
if (cappedReserves[i].mulDiv(CAP_PRECISION, cappedReserves[j]) > crv.rLimit) {
- calcReservesAtRatioSwap(mfpWf, crv.rLimit, cappedReserves, i, j, data);
+ cappedReserves = calcReservesAtRatioSwap(mfpWf, crv.rLimit, cappedReserves, i, j, data);
}
// If the ratio decreased, check that it didn't decrease below the max.
} else if (crv.r < crv.rLast) {
@@ -283,7 +283,7 @@ contract MultiFlowPump is IPump, IMultiFlowPumpErrors, IInstantaneousPump, ICumu
CAP_PRECISION2
);
if (cappedReserves[i].mulDiv(CAP_PRECISION, cappedReserves[j]) < crv.rLimit) {
- calcReservesAtRatioSwap(mfpWf, crv.rLimit, cappedReserves, i, j, data);
+ cappedReserves = calcReservesAtRatioSwap(mfpWf, crv.rLimit, cappedReserves, i, j, data);
}
}
}
Updates

Lead Judging Commences

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

Informational/Invalid

Support

FAQs

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