The calcReserveAtRatioLiquidity function tries to update scaledReserves[j] based on the pd.lutData (the data from the lookup table) and the scaledReserves[i] value. However, this approach is not ideal. If the target price (pd.targetPrice) is closer to the pd.lutData.highPrice, the function sets scaledReserves[j] based on the pd.lutData.highPriceJ value. Similarly, if the target price is closer to the pd.lutData.lowPrice, the function sets scaledReserves[j] based on the pd.lutData.lowPriceJ value.
Code
if (pd.lutData.highPrice - pd.targetPrice > pd.targetPrice - pd.lutData.lowPrice) {
// targetPrice is closer to lowPrice.
scaledReserves[j] = scaledReserves[i] * pd.lutData.lowPriceJ / pd.lutData.precision;
// set current price to lowPrice.
pd.currentPrice = pd.lutData.lowPrice;
} else {
// targetPrice is closer to highPrice.
scaledReserves[j] = scaledReserves[i] * pd.lutData.highPriceJ / pd.lutData.precision;
The problem with this logic is that these price ratios (pd.lutData.highPriceJ and pd.lutData.lowPriceJ) may not necessarily be accurate enough to correctly set the initial value of scaledReserves[j]. This can lead to the loop not converging to the desired result within the 255 iterations.
Impact
The calcReserveAtRatioLiquidity function is used to calculate the reserves for swap operations. If the reserve values are not calculated accurately, it can lead to suboptimal swap pricing and potentially less efficient swap executions.
In the worst-case scenario, the inaccurate reserve calculations could lead to capital loss for users providing liquidity or executing swaps, as the pool may not be able to maintain the expected parity between the token reserves.
In this test, I set up a scenario with different decimal places for the two tokens (18 and 6 decimals). We then call the calcReserveAtRatioLiquidity function and check that the returned reserve value is close to the expected value, which is calculated directly from the provided ratios and the other reserve.
Mitigation
Consider using a more robust method to initialize the scaledReserves[j] value, such as calculating it directly from the scaledReserves[i] and the target price ratio, rather than relying on the lookup table data.
Lines of code
https://github.com/code-423n4/2024-07-basin/blob/7d5aacbb144d0ba0bc358dfde6e0cc913d25310e/src/functions/Stable2.sol#L267
Vulnerability details
Vulnerability Details
The
calcReserveAtRatioLiquidity
function tries to updatescaledReserves[j]
based on thepd.lutData
(the data from the lookup table) and thescaledReserves[i]
value. However, this approach is not ideal. If the target price (pd.targetPrice
) is closer to thepd.lutData.highPrice
, the function setsscaledReserves[j]
based on thepd.lutData.highPriceJ
value. Similarly, if the target price is closer to thepd.lutData.lowPrice
, the function setsscaledReserves[j]
based on thepd.lutData.lowPriceJ
value.Code
The problem with this logic is that these price ratios (
pd.lutData.highPriceJ
andpd.lutData.lowPriceJ
) may not necessarily be accurate enough to correctly set the initial value ofscaledReserves[j]
. This can lead to the loop not converging to the desired result within the 255 iterations.Impact
The
calcReserveAtRatioLiquidity
function is used to calculate the reserves for swap operations. If the reserve values are not calculated accurately, it can lead to suboptimal swap pricing and potentially less efficient swap executions.In the worst-case scenario, the inaccurate reserve calculations could lead to capital loss for users providing liquidity or executing swaps, as the pool may not be able to maintain the expected parity between the token reserves.
Poc
In this test, I set up a scenario with different decimal places for the two tokens (18 and 6 decimals). We then call the calcReserveAtRatioLiquidity function and check that the returned reserve value is close to the expected value, which is calculated directly from the provided ratios and the other reserve.
Mitigation
Consider using a more robust method to initialize the
scaledReserves[j]
value, such as calculating it directly from thescaledReserves[i]
and the target price ratio, rather than relying on the lookup table data.Assessed type
Math