The VaultReader contract calculates the price impact in collateral by unconditionally using shortTokenPrice.min, disregarding whether the position is Long or Short and which token is actually collateralized. As a result, positions that rely on a different collateral asset (for example, a stablecoin in a Long position) may experience inaccurate price impact calculations. This discrepancy can lead to misreported costs, imprecise estimates of unrealized profit and loss, and potential misjudgment of liquidation thresholds.
The logic in getPriceImpactInCollateral inherently assumes that collateral must be priced using shortTokenPrice.min, even when the position might be Long and collateralized by a different asset, such as a stablecoin or the indexToken itself. This oversight leads to misalignment between real collateral value and the value utilized during price-impact calculations, creating inaccurate cost estimates and potentially leading to erroneous decisions about fees, profit/loss, or liquidation thresholds. By relying solely on shortTokenPrice.min, the function disregards vital context—namely, whether the position is actually Long or Short—and what the true collateral token is.
This logic error can produce incorrect price impact calculations whenever the collateral differs from the short token, leading to possible under- or over-charging of fees, miscalculation of slippage, and inaccuracies in profit/loss or liquidation estimates. In extreme cases, users could be prematurely liquidated or retain positions for longer than intended based on misrepresented collateral values.
The getPriceImpactInCollateral function always converts “price impact” into collateral using prices.shortTokenPrice.min, completely ignoring whether the position is Long or Short and which token is actually used as collateral.
As a result, if the collateral is not the short token (for example, in Long positions collateralized by a stablecoin or the same indexToken), this calculation may return inaccurate values, potentially leading to decisions or price impact data being misrepresented.
Below is the relevant portion of the getPriceImpactInCollateral function, highlighting the exact location where the issue occurs:
Where the Issue Lies:
Within the calculation of priceImpactInCollateralTokens, the function assumes that the “collateral” always corresponds to shortTokenPrice.min, without checking isLong or verifying which token is truly being used as collateral.
The function computes priceImpactInTokens based on the indexTokenPrice.
It then converts that “price impact” into “collateral” by dividing by prices.shortTokenPrice.min.
The core problem:
It does not take into account whether the position is Long or Short.
It does not verify which token is used as collateral.
If a position is Long and the collateral is a stable token (or any asset other than the short token), this formula becomes inaccurate and may produce an erroneous output.
A user opens a Long position using collateral that is not the short token (e.g., a stablecoin like USDC). The protocol then calls getPriceImpactInCollateral to calculate the price impact in collateral terms. Because the calculation leverages prices.shortTokenPrice.min, it returns an incorrect value by ignoring that the user’s collateral might be a stablecoin.
As a result:
The protocol may apply incorrect discounts or charges for slippage.
Gains/losses on collateral could be under- or over-estimated, affecting the precision of liquidations and fees.
This test sets up a 2x Long position with collateral that is not the short token, then calls getPriceImpactInCollateral. It compares the function’s actual result—which always uses shortTokenPrice.min—against a hypothetical calculation using the correct collateral price. The logs show a massive discrepancy (-723383 vs 1.000029671490240875e33), confirming that the function is ignoring the actual collateral token. The test passes because it detects this mismatch, thereby validating the logical error.
Add the following test to test/PerpetualVault.t.sol
The absence of any validation related to isLong or checks on the actual collateral token—combined with the fixed use of shortTokenPrice.min—confirms this finding. It applies to any scenario where the position is not a Short with short-token collateral.
Manual Code Review
The code was thoroughly inspected on a line-by-line basis to pinpoint logical inconsistencies and confirm the error through targeted testing.
Replace the unconditional use of shortTokenPrice.min with logic that checks whether the position is Long or Short, and then applies the correct collateral price accordingly.
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.