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

Applying Price Impact When Withdrawing Will Lead to Impossible-to-Withdraw Positions

Summary

When withdrawing the Initial Margin (IM), the check uses a fill price as if the user had closed their positions. This causes the price to differ from what it actually is, which makes their margin ratio appear lower than it actually is, making it impossible to withdraw any amount while the deflated margin ratio is below the IM.

Vulnerability Details

Below is where the Initial Margin is calculated:

(UD60x18 requiredInitialMarginUsdX18,, SD59x18 accountTotalUnrealizedPnlUsdX18) =
tradingAccount.getAccountMarginRequirementUsdAndUnrealizedPnlUsd(0, SD59x18_ZERO);

And here is where the markPrice is calculated. This price is then used to determine PnL:

UD60x18 markPrice = perpMarket.getMarkPrice(sd59x18(-position.size), perpMarket.getIndexPrice());

And here is where the PnL is calculated:

SD59x18 positionUnrealizedPnl =
position.getUnrealizedPnl(markPrice).add(position.getAccruedFunding(fundingFeePerUnit));

This PnL is then part of the margin balance calculation:

SD59x18 marginBalanceUsdX18 = tradingAccount.getMarginBalanceUsd(accountTotalUnrealizedPnlUsdX18);

Which finally is compared to the initial margin to see if the account is healthy enough to withdraw:

tradingAccount.validateMarginRequirement(requiredInitialMarginUsdX18, marginBalanceUsdX18, UD60x18_ZERO);

The issue here is that markPrice is calculated as if the position was closing:

UD60x18 markPrice = perpMarket.getMarkPrice(sd59x18(-position.size), perpMarket.getIndexPrice());

This means that the PnL will be lower than it should be in cases where negative price impact would occur. With the lower PnL, the users will have a worse marginBalanceUsdX18, which will wrongly put the marginBalanceUsdX18 below requiredInitialMarginUsdX18. With this check wrongly failing, the user will not be able to withdraw any assets, even though they would in fact be above the IM.

Overall, this is an understandable safety measure. However, because users will not be able to withdraw assets that they should be able to, this safety measure becomes a vulnerability that impacts users by temporarily locking their funds.

The heart of this issue is that price impact is applied to a user's position even though their position is not changing, resulting in false passes of solvency checks in some cases and, in much worse cases, false failures that will lock away liquidity.

This is an edge case within the withdrawing functionality with high impact and low/medium likelihood, making this a medium overall.

Impact

Temporary locked funds.

Tools Used

Manual analysis

Recommendations

When determining solvency upon withdrawing, the markPrice should be calculated as if the position delta is 0, as there is no position change.

Updates

Lead Judging Commences

inallhonesty Lead Judge
over 1 year ago
inallhonesty Lead Judge over 1 year ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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