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

Loss Proration Failure in Negative Equity Scenarios

Summary

The protocol fails to prorate losses (insolvency) or negative fees (liquidations), allowing early exits to drain collateral unfairly.

When the vault’s net equity turns negative—whether during routine withdrawals or mass liquidations—the current calculations do not account for the proportional allocation of losses. As a result, early withdrawers may receive a disproportionate amount of collateral while later users are forced to absorb the entire loss.

Vulnerability Details

The withdrawal function via _handleReturn

/**
* @notice this function is an end of withdrawal flow.
* @dev should update all necessary global state variables
*
* @param withdrawn amount of token withdrawn from the position
* @param positionClosed true when position is closed completely by withdrawing all funds, or false
*/
function _handleReturn(uint256 withdrawn, bool positionClosed, bool refundFee) internal {
(uint256 depositId) = flowData;
uint256 shares = depositInfo[depositId].shares;
uint256 amount;
if (positionClosed) {
amount = collateralToken.balanceOf(address(this)) * shares / totalShares;
} else {
uint256 balanceBeforeWithdrawal = collateralToken.balanceOf(address(this)) - withdrawn;
amount = withdrawn + balanceBeforeWithdrawal * shares / totalShares;
}
if (amount > 0) {
_transferToken(depositId, amount);
}
emit Burned(depositId, depositInfo[depositId].recipient, depositInfo[depositId].shares, amount);
_burn(depositId);
if (refundFee) {
uint256 usedFee = callbackGasLimit * tx.gasprice;
if (depositInfo[depositId].executionFee > usedFee) {
try IGmxProxy(gmxProxy).refundExecutionFee(depositInfo[counter].owner, depositInfo[counter].executionFee - usedFee) {} catch {}
}
}
// update global state
delete swapProgressData;
delete flowData;
delete flow;
}

computes the user’s redeemable amount as:

uint256 amount = collateralToken.balanceOf(address(this)) * shares / totalShares;

This calculation assumes that the vault’s collateral value is positive. In an insolvency event (for example, where total liabilities exceed assets), the simple proportional division ignores the negative net value.

Scenario:

  • Total shares: 1,000

  • Collateral balance: 500 USDC

  • Implied liabilities: 1,000 USDC (net equity = –500 USDC)

  • A user with 500 shares would, by the current formula, withdraw: 500 × (500⁄1000) = 250 USDC
    --> This leaves the vault with a negative burden that then must be borne entirely by remaining depositors, effectively freezing or greatly reducing withdrawals for later users.

Example:-

  • A vault is operating under stress where market losses have driven net equity negative, example collateral worth USD 1,000 with liabilities of USD 1,500

  • Two depositors hold equal shares.

  • The first depositor withdraws using the current formula and receives an amount based solely on the nominal collateral balance.

  • The second depositor’s share is then calculated on an even lower remaining collateral balance, effectively absorbing the full loss.

  • The differences between the early and late withdrawals demonstrates that the protocol’s withdrawal mechanism does not share losses proportionally.

Similarly, during mass liquidations the fee–claiming mechanism (such as in GmxProxy.afterOrderExecution globally applies negative funding fees without tracking individual exposure. Thus, if some users exit early, the entire fee burden falls on those left in the system.

Impact

Early withdrawers might extract a full‐value payout while later withdrawers see their shares dramatically devalued. Depositors who remain in the vault absorb 100% of losses, potentially locking funds or forcing further liquidations. This violates the fair share invariant and may lead to systemic user distrust.

Tools Used

Manual Review

Recommendations

Track each depositor’s share‐age (or use a time‑weighted share mechanism) so that both deposits and withdrawals account for accrued losses. For example, calculate a user’s effective claim as the difference between their proportional entitlement of assets and of liabilities, such as:

uint256 maxWithdraw = (collateralBalance * shares) / totalShares;
uint256 userDebt = (totalLiabilities * shares) / totalShares;
amount = maxWithdraw > userDebt ? maxWithdraw - userDebt : 0;
Updates

Lead Judging Commences

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

Suppositions

There is no real proof, concrete root cause, specific impact, or enough details in those submissions. Examples include: "It could happen" without specifying when, "If this impossible case happens," "Unexpected behavior," etc. Make a Proof of Concept (PoC) using external functions and realistic parameters. Do not test only the internal function where you think you found something.

Support

FAQs

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

Give us feedback!