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

Mis-handling of PnL in Partial Withdrawals Pre-adjusting `collateralDeltaAmount` for PnL Mismatches GMX’s Realization, Causing Small Over/Under-Adjustments

[L-2] Mis-handling of PnL in Partial Withdrawals Pre-adjusting collateralDeltaAmount for PnL Mismatches GMX’s Realization, Causing Small Over/Under-Adjustments

Description:

In the PerpetualVault.sol contract’s _withdraw function, the collateralDeltaAmount for partial GMX position withdrawals is pre-adjusted based on the proportional PnL (vaultReader.getPnl(curPositionKey, prices, sizeDeltaInUsd)). For negative PnL, it subtracts the loss from collateralDeltaAmount before submitting the decrease order to GMX. However, GMX realizes PnL during the decrease operation itself, adjusting the collateral returned. This pre-adjustment can lead to a mismatch, as the contract anticipates the PnL impact, while GMX applies it independently, potentially double-counting losses or misaligning with volatile market conditions.

Impact:

  • Minor Over/Under-Adjustments: For negative PnL, pre-subtracting the loss may reduce the withdrawal amount more than necessary if GMX also deducts it, causing users to receive slightly less than entitled. For positive PnL, no pre-adjustment occurs, relying on GMX’s realization, which is correct but inconsistent with the negative case, leading to small discrepancies.

  • No Vault Drain: The vault doesn’t lose funds beyond the position’s value, as GMX ensures correct final adjustments, but users may experience minor underpayments (e.g., a few USDC).

  • User Trust: Small inaccuracies in withdrawal amounts could erode confidence, though the financial impact is limited and doesn’t compromise vault integrity.

Recommended Mitigation:

Remove the pre-adjustment of collateralDeltaAmount for PnL, allowing GMX to handle PnL realization fully during the decrease operation, ensuring alignment with actual outcomes:

  • Fix:

    collateralDeltaAmount = positionData.collateralAmount * shares / totalShares;
    uint256 feeAmount = vaultReader.getPositionFeeUsd(market, sizeDeltaInUsd, false) / prices.shortTokenPrice.max;
    collateralDeltaAmount = collateralDeltaAmount - feeAmount; // Remove PnL adjustment, rely on GMX
    _createDecreasePosition(collateralDeltaAmount, sizeDeltaInUsd, beenLong, acceptablePrice, prices);
Updates

Lead Judging Commences

n0kto Lead Judge 9 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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