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

ADL issue causes incorrect collateral token withdrawal amounts

Title

ADL issue causes incorrect collateral token withdrawal amounts

Summary

When an ADL (Assume Debt and Liquidity) event occurs right before finalizing a withdrawal, the system incorrectly calculates the amount of collateral tokens a user should receive. This can result in users getting more funds than they should, causing financial losses for others.

Vulnerability Details

The withdrawal process involves a series of steps. First, a decrease order is executed, which triggers GmxProxy::afterOrderExecution(). This in turn calls PerpetualVault::afterOrderExecution(). The code snippet below shows how the collateral balance is recorded before finalization:

if (flow == FLOW.WITHDRAW) {
nextAction.selector = NextActionSelector.FINALIZE;
uint256 prevCollateralBalance = collateralToken.balanceOf(address(this)) - orderResultData.outputAmount;
nextAction.data = abi.encode(prevCollateralBalance, sizeInUsd == 0, false);
}

The runNextAction() function handles finalization. It swaps index tokens to collateral tokens and calls _finalize():

else if (_nextAction.selector == NextActionSelector.FINALIZE) {
if (
IERC20(indexToken).balanceOf(address(this)) * prices.indexTokenPrice.min >= ONE_USD
) {
(, bytes memory data) = abi.decode(metadata[1], (PROTOCOL, bytes));
_doDexSwap(data, false);
}
_finalize(_nextAction.data);
}

In _finalize(), the collateral token balance is checked again to determine how much to return:

function _finalize(bytes memory data) internal {
if (flow == FLOW.WITHDRAW) {
(uint256 prevCollateralBalance, bool positionClosed, bool refundFee) = abi.decode(data, (uint256, bool, bool));
uint256 withdrawn = collateralToken.balanceOf(address(this)) - prevCollateralBalance;
_handleReturn(withdrawn, positionClosed, refundFee);
} else {
delete swapProgressData;
delete flowData;
delete flow;
}
}

The issue arises when ADL occurs before finalization. In _handleReturn(), the calculation assumes all collateral tokens come from the withdrawal, ignoring any changes caused by ADL:

uint256 balanceBeforeWithdrawal = collateralToken.balanceOf(address(this)) - withdrawn;
amount = withdrawn + balanceBeforeWithdrawal * shares / totalShares;

This leads to overpayment because the system doesn't account for the additional funds introduced by ADL.

Impact

Users may receive more collateral tokens than they should, causing financial losses for others due to incorrect collateral accounting.

Tools Used

Manual Review

Recommendations

Track collateral changes caused by ADL events

Updates

Lead Judging Commences

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

finding_ADL_before_a_finalize_withdraw_profit_to_one_user

Likelihood: Low, when ADL with profit happen just before a nextAction.FINALIZE and FLOW.WITHDRAW Impact: High, the withdrawing user receives all the delivery with the tokens.

Support

FAQs

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