The _totalAmount
function in PerpetualVault.sol adds values with different decimal precisions (1e18 and 1e6) without proper normalization, resulting in incorrect total amount calculations. This affects share minting and withdrawal calculations, potentially causing users to receive incorrect amounts of shares or tokens.
The _totalAmount
function calculates the total value of the vault by adding three components:
IndexToken value: IERC20(indexToken).balanceOf(address(this)) * prices.indexTokenPrice.min / prices.shortTokenPrice.min
(1e18 decimals)
Collateral token balance: collateralToken.balanceOf(address(this))
(collateralToken decimals)
Position net value: positionData.netValue / prices.shortTokenPrice.min
(collateralToken decimals)
Visual representation of the decimal precision issue:
This inconsistency means values with different precisions are added directly, leading to incorrect proportions in the final sum.
Example scenario:
The incorrect total amount calculation severely impacts the vault's core functionality by causing users to receive incorrect share amounts during minting, ultimately compromising the vault's accounting accuracy and user fairness.
Normalize all values to match the collateral token's decimals before addition:
This solution dynamically adjusts for any collateral token's decimal precision, ensuring correct calculations regardless of the tokens involved.
GMX github documentation: “Prices stored within the Oracle contract represent the price of one unit of the token using a value with 30 decimals of precision. Representing the prices in this way allows for conversions between token amounts and fiat values to be simplified, e.g. to calculate the fiat value of a given number of tokens the calculation would just be: token amount * oracle price, to calculate the token amount for a fiat value it would be: fiat value / oracle price.” Sponsor confirmed the keeper does the same, so price decimals change in function of the token, to be sure the above rule is true. Example for USDC (6 decimals): Prices will have 24 decimals → 1e6 * 1e24 = 1e30. Just a reminder for some submissions: shortToken == collateralTokens, so the decimals is 1e24 for shortToken prices.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.