DeFiFoundry
50,000 USDC
View results
Submission Details
Severity: high
Valid

Incorrect Position Size Handling in pnl Calculation During Withdrawals

Summary

The VaultReader.getPnl() function incorrectly calculates PnL when processing partial withdrawals by using the entire position size instead of the proportional size specified in the withdrawal request. This leads to withdrawers being penalized/credited for the full position’s PnL instead of their proportionate share in case if PnL is negative.

Vulnerability Details

In PerpetualVault._withdraw(), when a user attempts to withdraw a subset of their shares (partial withdrawal), the protocol calls VaultReader.getPnl() with a sizeDeltaUsd calculated as:

uint256 sizeDeltaInUsd = positionData.sizeInUsd * shares / totalShares;

This sizeDeltaInUsd represents only the portion of the position being withdrawn (user proportion according shares weight like userShares/totalShares). However, VaultReader.getPnl() forces usePositionSizeAsSizeDeltaUsd = true in its call to GMX’s getPositionInfo(), overriding the intended sizeDeltaUsd with the full position size:

function getPnl(...) {
...
gmxReader.getPositionInfo(..., sizeDeltaUsd, ..., true); // Last param `true` = use full position size
}

Example Scenario:

Total position size: 100,000;
User withdraws 10% (shares / totalShares = 0.1) → valid sizeDeltaInUsd = 10,000
Total Position PnL: -5,000 (5% loss)
User portion PnL for withdrawal: -500 (10% of 5,000)
Actual user portion PnL due to bug: -5,000 full loss applied invalidly to the 10,000 withdrawal.

Impact

Unfair Losses: Withdrawing users are penalized with the entire position’s loss, even if they only exit a small portion.

Tools Used

Manual review

Recommendations

Modify VaultReader.getPnl() to respect the passed sizeDeltaUsd by setting usePositionSizeAsSizeDeltaUsd = false.

function getPnl(...) {
...
gmxReader.getPositionInfo(
...,
sizeDeltaUsd,
address(0),
false // Use `False` instead of True`. `sizeDeltaUsd` instead of full position size
);
Updates

Lead Judging Commences

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

finding_getPnL_use_usePositionSizeAsSizeDeltaUsd_and_substract_it

Likelihood: Medium/High, every withdrawal from a short or leveraged vault that is not liquidated and has a negative PnL. Impact: High, subtract collateralDeltaAmount from the entire PnL of the position instead of the delta amount PnL. DoS or loss of funds

Support

FAQs

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

Give us feedback!