A formula inside the calcMinTokensSlippageAmt function calculates incorrect results if tokens are used that do not have 18 decimal places.
The calcMinTokensSlippageAmt function is used to calculate the minimum tokens to receive when removing liquidity and looks like this:
uint256 public constant SAFE_MULTIPLIER = 1e18;
...
function calcMinTokensSlippageAmt(
GMXTypes.Store storage self,
uint256 lpAmt,
address minLongToken,
address minShortToken,
uint256 slippage
) external view returns (uint256, uint256) {
uint256 _withdrawValue = lpAmt
* self.gmxOracle.getLpTokenValue(
address(self.lpToken),
address(self.tokenA),
address(self.tokenA),
address(self.tokenB),
false,
false
)
/ SAFE_MULTIPLIER;
(uint256 _tokenAWeight, uint256 _tokenBWeight) = GMXReader.tokenWeights(self);
uint256 _minLongTokenAmt = _withdrawValue
* _tokenAWeight / SAFE_MULTIPLIER
* SAFE_MULTIPLIER
/ GMXReader.convertToUsdValue(
self,
minLongToken,
10**(IERC20Metadata(minLongToken).decimals())
)
/ (10 ** (18 - IERC20Metadata(minLongToken).decimals()));
uint256 _minShortTokenAmt = _withdrawValue
* _tokenBWeight / SAFE_MULTIPLIER
* SAFE_MULTIPLIER
/ GMXReader.convertToUsdValue(
self,
minShortToken,
10**(IERC20Metadata(minShortToken).decimals())
)
/ (10 ** (18 - IERC20Metadata(minShortToken).decimals()));
return (
_minLongTokenAmt * (10000 - slippage) / 10000,
_minShortTokenAmt * (10000 - slippage) / 10000
);
}
minLongTokenAmt = withdrawValue * tokenWeight / 1e18 * 1e18 / usdValueOfOneToken / (10 ** (18 - tokenDecimals)
withdrawValue = 500e18
tokenWeight = 0.5e18
usdValueOfOneToken = 100e18
For tokenDecimals = 18:
minLongTokenAmt = 500e18 * 0.5e18 / 1e18 * 1e18 / 100e18 / (10 ** (18 - 18) = 2.5e18
For tokenDecimals = 8:
minLongTokenAmt = 500e18 * 0.5e18 / 1e18 * 1e18 / 100e18 / (10 ** (18 - 8) = 2.5e8
As we can see, 10 decimal places are missing and therefore this formula does not work with tokens that have a precision other than 18 decimal places.
Adjust the formula so that it can work with varying degrees of precision.