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

Desynced reserves calculation in the current `ConstantProduct2.calcReserve()` inflates the value of the reserves

Summary

The function is intended to calculate reserves, but is flawed in it's calculations, leading to incorrect(inflated) reserve values.

Vulnerability Detail

See ConstantProduct.calcReserve() previous implementation

/// @dev `b_j = (s / n)^n / π_{i!=j}(b_i)`
function calcReserve(
uint256[] calldata reserves,
uint256 j,
uint256 lpTokenSupply,
bytes calldata
) external pure override returns (uint256 reserve) {
uint256 n = reserves.length;
reserve = (lpTokenSupply / n) ** n;
for (uint256 i; i < n; ++i) {
if (i != j) reserve = reserve / reserves[i];
}
}

Now see ConstantProduct2.calcReserve() current implementation

function calcReserve(
uint256[] calldata reserves,
uint256 j,
uint256 lpTokenSupply,
bytes calldata
) external pure override returns (uint256 reserve) {
if (j >= 2) {
revert InvalidJArgument();
}
// Note: potential optimization is to use unchecked math here
reserve = lpTokenSupply ** 2;
reserve = LibMath.roundUpDiv(reserve, reserves[j == 1 ? 0 : 1] * EXP_PRECISION);
}

From here onward assume the calcReserve() from ConstantProduct as calcReserveA() and the calcReserve() from ConstantProduct2 as `calcReserveB()

Assume we are passing in n as 2 cause we are trying to calculate the reserves in a two token well, which in normal instances should lead to the same for values in both implementations, keeping the exponentials asides

Given:

  • reserves = [1000]

  • j = 1

  • n = 2

  • lpTokenSupply = 100

calcReserveA() calculates:

reserve = (100 / 2) ** 2
(...snip)

calcReserveB calculates

reserve = (100 ** 2)
(...snip)

Evidently we can see that the crucial step of dividing the lpTokenSupply by the amount of tokens (2) in the well is missing.

Impact

The formula in the current calculation would lead to returning the values of inflated reserve calculations, leading to mismanagement/misassumption of funds & incorrect protocol behaviour in all instances where the reserves is expected to be rightly returned

Tool used

Manual Review

Recommendation

Reimplement the functionalities to be synced, considering in the previous implementation the lpTokenSupply is first divided by the amount of tokens before being powered by it, i.e (lpTokenSupply / n) ** n here however we only have the lpTokenSupply ** n.

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.