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

Ratio between the passed time and the `capInterval` is not taken into account properly

Summary

In case of relatively frequent reserves update the capped reserves changing can be faster than expected due to the difference between short time passed and specified capInterval.

Vulnerability Details

The MultiFlowPump.update lets specify capInterval which is used for periods number calculation and CapReservesParameters which determine maximum changing in a period (capInterval).

function update(uint256[] calldata reserves, bytes calldata data) external {
(bytes16 alpha, uint256 capInterval, CapReservesParameters memory crp) =
abi.decode(data, (bytes16, uint256, CapReservesParameters));
<...>
bytes16 alphaN;
bytes16 deltaTimestampBytes;
uint256 capExponent;
// Isolate in brackets to prevent stack too deep errors
{
uint256 deltaTimestamp = _getDeltaTimestamp(pumpState.lastTimestamp);
// If no time has passed, don't update the pump reserves.
if (deltaTimestamp == 0) return;
alphaN = alpha.powu(deltaTimestamp);
deltaTimestampBytes = deltaTimestamp.fromUInt();
// Round up in case capInterval > block time to guarantee capExponent > 0 if time has passed since the last update.
>> capExponent = calcCapExponent(deltaTimestamp, capInterval);
}
pumpState.lastReserves = _capReserves(msg.sender, pumpState.lastReserves, reserves, capExponent, crp);

As mentions in the comment before calcCapExponent function invoke at least one interval will be accounted. But there are no CapReservesParameters adjustment for the decreased interval in the contract logic, they are used as is instead.

function _capReserves(
address well,
uint256[] memory lastReserves,
uint256[] memory reserves,
uint256 capExponent,
>> CapReservesParameters memory crp
) internal view returns (uint256[] memory cappedReserves) {
// Assume two token well
if (reserves.length != 2) {
revert TooManyTokens();
}
Call memory wf = IWell(well).wellFunction();
IMultiFlowPumpWellFunction mfpWf = IMultiFlowPumpWellFunction(wf.target);
// The order that the LP token supply and the rates are capped are dependent upon the values of the reserves to maximize precision.
>> cappedReserves = _capLpTokenSupply(lastReserves, reserves, capExponent, crp, mfpWf, wf.data, true);
// If `_capLpTokenSupply` returns an empty array, then the rates should be capped first.
if (cappedReserves.length == 0) {
>> cappedReserves = _capRates(lastReserves, reserves, capExponent, crp, mfpWf, wf.data);
>> cappedReserves = _capLpTokenSupply(lastReserves, cappedReserves, capExponent, crp, mfpWf, wf.data, false);
} else {
>> cappedReserves = _capRates(lastReserves, cappedReserves, capExponent, crp, mfpWf, wf.data);
}
}

Impact

Unexpected fast capped reserves changing can break a Well logic, lost of precision

Tools used

Manual Review

Recommendations

Consider using a unified 1 second capInterval for all Wells or implementing a logic of CapReservesParameters params adjustment as ratio between actual time passed and capInterval.

Updates

Lead Judging Commences

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

Informational/Invalid

pontifex Submitter
about 1 year ago
giovannidisiena Lead Judge
about 1 year ago
pontifex Submitter
about 1 year ago
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.