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

Not matching calculations of price impact between Gamma and GMX lead to incorrect share calculation

Description:

In Gamma protocol, price impact is calculated and used only at the time when GMX calls GmxProxy::afterOrderExecution callback, which happens during the execution of MarketIncrease order, after a user deposited funds and those funds were added to the current open Gamma's position on GMX. At the time of the callback, GMX has already calculated price impact on their side and updated their state. The problem arises due to Gamma's way of calculating price impact not matching GMX's, and overall being too simple and not accounting for different possible market conditions.

This is where and how the price impact is calculated on GMX side:

https://github.com/gmx-io/gmx-synthetics/blob/b8fb11349eb59ae48a1834c239669d4ad63a38b5/contracts/pricing/PositionPricingUtils.sol#L159
https://github.com/gmx-io/gmx-synthetics/blob/b8fb11349eb59ae48a1834c239669d4ad63a38b5/contracts/pricing/PositionPricingUtils.sol#L188
https://github.com/gmx-io/gmx-synthetics/blob/b8fb11349eb59ae48a1834c239669d4ad63a38b5/contracts/pricing/PricingUtils.sol#L61
https://github.com/gmx-io/gmx-synthetics/blob/b8fb11349eb59ae48a1834c239669d4ad63a38b5/contracts/pricing/PricingUtils.sol#L88

As you can see, the calculation of price impact on GMX side is fairly complex, as it:

  • factors in market imbalance (long vs. short open interest differences)

  • includes virtual inventory checks

  • dynamically scales the price impact based on liquidity conditions

Here you can see the actual formula behind GMX price impact calculations:

https://github.com/gmx-io/gmx-synthetics/blob/main/README.md#price-impact

Meanwhile Gamma's way of calculating price impact looks like this:

function getPriceImpactInCollateral(
bytes32 positionKey,
uint256 sizeDeltaInUsd,
uint256 prevSizeInTokens,
MarketPrices memory prices
) external view returns (int256) {
uint256 expectedSizeInTokensDelta = sizeDeltaInUsd / prices.indexTokenPrice.min;
uint256 curSizeInTokens = getPositionSizeInTokens(positionKey);
uint256 realSizeInTokensDelta = curSizeInTokens - prevSizeInTokens;
int256 priceImpactInTokens = expectedSizeInTokensDelta.toInt256() - realSizeInTokensDelta.toInt256();
int256 priceImpactInCollateralTokens = priceImpactInTokens * prices.indexTokenPrice.min.toInt256() / prices.shortTokenPrice.min.toInt256();
return priceImpactInCollateralTokens;
}

This is a simplified version of how Gamma calculates price impact:

priceImpactInCollateralTokens = ((sizeDeltaInUsd / prices.indexTokenPrice.min) - (curSizeInTokens - prevSizeInTokens)) * prices.indexTokenPrice.min / prices.shortTokenPrice.min

  1. Basically it takes sizeDeltaInUsd variable (which was sent in from GMX, so it's the actual value) and divides it by index token (e.g. WETH) price, so the result is in terms of WETH.

  2. Then it takes curSizeInTokens, which is the current position size in tokens (e.g. in WETH) and subtracts it by prevSizeInTokens, which is the previous position size in tokens (before user's deposited funds were added)

  3. Then it subracts the second result from the first result, which makes the result essentially equal to: how the position changed based on sizeDeltaInUsd minus how the position changed in terms of tokens

  4. Finally, it applies prices to the result.

Gamma's way of calculating price impact is too simplistic and does not properly account for different possible market conditions the way GMX does.

Impact:

This issue leads to inaccuracies in share calculation for users who deposit into already open GMX positions, making them receive less or more (depending on market conditions) minted shares than users who deposited while the position was not open.

Likelihood:

This issue will occur pretty much always when a user deposits funds into Gamma's vault when there is an already open GMX position

Recommended Mitigation:

Use GMX’s non-linear price impact formula, instead of calculating price impact your own way. Make sure to factor in virtual inventory and open interest, because without these, price impact calculations will always be inaccurate.

Updates

Lead Judging Commences

n0kto Lead Judge 9 months ago
Submission Judgement Published
Invalidated
Reason: Design choice
Assigned finding tags:

Informational or Gas

Please read the CodeHawks documentation to know which submissions are valid. If you disagree, provide a coded PoC and explain the real likelihood and the detailed impact on the mainnet without any supposition (if, it could, etc) to prove your point.

Appeal created

n0kto Lead Judge
8 months ago
n0kto Lead Judge 8 months ago
Submission Judgement Published
Validated
Assigned finding tags:

finding_getPriceImpactInCollateral_no_difference_between_long_and_short

Likelihood: High, every price impact is not accurate for short position. Impact: High, not using different formula when position is short and long lead to incorrect shares calculation. Verified with the sponsor and one of the reason why PoCs on 454 works.

n0kto Lead Judge
8 months ago
n0kto Lead Judge
8 months ago
n0kto Lead Judge 8 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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

Give us feedback!