DeFiFoundry
50,000 USDC
View results
Submission Details
Severity: low
Invalid

Incorrect Price Impact Calculation in VaultReader.sol

Summary

The getPriceImpactInCollateral function calculates expectedSizeInTokensDelta using division before multiplication, leading to truncation errors. This results in understated price impact values, causing inaccurate loss calculations during swaps or leverage adjustments.


Vulnerability Details

Code Snippet

uint256 expectedSizeInTokensDelta = sizeDeltaInUsd / prices.indexTokenPrice.min;
int256 priceImpactInTokens = expectedSizeInTokensDelta.toInt256() - realSizeInTokensDelta.toInt256();
int256 priceImpactInCollateralTokens = priceImpactInTokens * prices.indexTokenPrice.min.toInt256() / prices.shortTokenPrice.min.toInt256();

Root Cause

  • Division Before Multiplication:

    • sizeDeltaInUsd / prices.indexTokenPrice.min truncates fractional values due to integer division.

    • Example: If sizeDeltaInUsd = 1500e30 (1,500 USD) and prices.indexTokenPrice.min = 2000e30 ($2,000 per token), the division yields 0.75 tokens, which truncates to 0 in integer math.

    • Subsequent multiplication (0 * price) results in zero price impact, even though the actual impact should be non-zero.


Impact

  • Understated Losses: Traders may incur larger-than-expected losses during swaps or leverage changes.

  • Protocol Insolvency Risk: Miscalculations could lead to insufficient collateral reserves to cover actual losses.


Proof of Concept (PoC)

Scenario

  1. Input Values:

    • sizeDeltaInUsd = 1500e30 ($1,500)

    • prices.indexTokenPrice.min = 2000e30 ($2,000 per token)

    • prices.shortTokenPrice.min = 1e30 ($1.00)

  2. Faulty Calculation:

    • expectedSizeInTokensDelta = 1500e30 / 2000e30 = 0 (truncated from 0.75).

    • priceImpactInTokens = 0 - realSizeInTokensDelta (assume realSizeInTokensDelta = 0.5).

    • priceImpactInCollateralTokens = (-0.5) * 2000e30 / 1e30 = -1000e30 (-$1,000).

  3. Correct Calculation (Multiplication First):

    • expectedSizeInTokensDelta = (1500e30 * 1e30) / 2000e30 = 750e27 (0.75 tokens).

    • priceImpactInTokens = 0.75 - 0.5 = 0.25.

    • priceImpactInCollateralTokens = 0.25 * 2000e30 / 1e30 = 500e30 ($500).

Result: The protocol understates the price impact by **1,000vs.+$500`), leading to incorrect loss reporting.


Recommended Mitigation

Re-Order Operations

Perform multiplication before division to preserve precision:

uint256 expectedSizeInTokensDelta = (sizeDeltaInUsd * PRECISION) / prices.indexTokenPrice.min;

Use Higher Precision

Add a scaling factor (e.g., 1e18) to minimize truncation:

uint256 expectedSizeInTokensDelta = (sizeDeltaInUsd * 1e18) / prices.indexTokenPrice.min;
Updates

Lead Judging Commences

n0kto Lead Judge 6 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement
Assigned finding tags:

invalid_prices_decimals

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.

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.