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

Overestimation of Vault Value Due to Slippage

Summary

The contract calcukates the vault's value by converting indexToken (e.g., ETH) to collateralToken (e.g., USDC) using a simple price ratio:

uint256 total = IERC20(indexToken).balanceOf(address(this)) * prices.indexTokenPrice.min / prices.shortTokenPrice.min

Vulnerability Details

This calculation assumes perfect market conditions, meaning:

  • No slippage (price stays constant no matter how much is sold).

  • Infinite liquidity (you can sell any amount withput affecting the price).

But in reality:

  • If the vault holds a large amount of indexToken, selling it will move the market price (causing slippage).

  • The actual amount received will be lower than expected, leading to overestimating the vaults tootal value.

  • Users could withdraw more than what's actually available, causing insolvency.
    EXAMPLE:

  • Suppose the vault holds 10,000 ETH

  • ETH market price (from oracle) = $2,000

  • The contract assumes selling 10,000 ETH will give $20M (10,000 x 2,000).

  • But DEX liquidity is low, and selling so much ETH causes slippage:

    • The actual price received is $1,800 per ETH instead of $2,000.
      The vault actually holds $18M not $20M.
      However, the contract doesn't account for this and allows users to withdraw based on $20M.

  • Result: The vault loses $2M and becomes insolvent.

Impact

  • Users can withdraw more than what's available leading to insolvency.

  • Attackers can manipulate oracle prices inflate prices to withdraw extra funds before correction.

Tools Used

Manual Review

Recommendations

Instead of the incorrect formula:

uint256 total = IERC20(indexToken).balanceOf(address(this)) * prices.indexTokenPrice.min / prices.shortTokenPrice.min

which assumes perfect liquidity, we should simulate actual market conditions when converting assets.

  • Use a DEX price impact function to calculate the actual amount.

  • Check available liquidity before allowing large withdrawals.
    Example Fix:

uint256 indexTokenBalance = IERC20(indexToken).balanceOf(address(this));
// Use an on-chain price oracle or DEX function to estimate actual output
uint256 estimatedCollateralAmount = getExpectedOutput(indexToken, collateralToken, indexTokenBalance);
uint256 total = estimatedCollateralAmount
+ collateralToken.balanceOf(address(this))
+ positionData.netValue / prices.shortTokenPrice.min;

Here, getExpectedOutput() is a function that fetches actual conversion rates from the DEX instead of assuming a fixed ratio.

Updates

Lead Judging Commences

n0kto Lead Judge 8 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
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.

Support

FAQs

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