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

Incorrect Use of counter Instead of flowData in _cancelFlow Function

Summary

In the _cancelFlow function, the contract erroneously uses the counter variable referencing deposit information when processing both deposit and withdrawal cancellation flows. For withdrawals, the correct state variable—flowData (which stores the specific deposit ID for the user attempting to withdraw)—should be used instead of counter (which tracks the last deposit). This mistake can lead to incorrect refund processing and state inconsistencies for withdrawal operations.

Vulnerability Details

  • Location:
    The vulnerability is found in the _cancelFlow function where the refund logic for both deposit and withdrawal flows references depositInfo[counter].

  • Code Context:
    The contract defines two distinct state variables:

  • counter:
    Used to track the latest deposit, recording details of users who deposited last.

  • flowData:
    Intended to store the deposit ID of the user initiating a withdrawal.

In the withdrawal branch of _cancelFlow, the code incorrectly references counter:

else if (flow == FLOW.WITHDRAW) {
try IGmxProxy(gmxProxy).refundExecutionFee(
depositInfo[counter].owner,
depositInfo[counter].executionFee
) {} catch {}
}

Impact

Incorrect Refund Processing:
The refund for execution fees in withdrawal flows will be attributed to the wrong deposit information. Users withdrawing their funds might not receive the proper refund, or refunds might be misdirected entirely.

POC

  • Deposit Action:

  • user A Execute a deposit transaction. The contract will update counter and record the deposit details accordingly.

  • user B Execute a deposit transaction. The contract will update counter and record the deposit details accordingly
    userA deposit id = 1;

    userB deposit id = 2;

  • Withdrawal Action:

  • user A Initiate a withdrawal transaction, ensuring that flowData is set to the deposit ID of the user requesting the withdrawal.
    which flowdata = 1;

  • Cancellation of Flow:
    Trigger the cancelFlow function during a withdrawal flow.
    Observe that the refund call references depositInfo[counter] rather than depositInfo[flowData] which will return 2, the current counter instaed of 1 the current flowdata

Observation:
The refund execution fee is fetched using the details of the last deposit (tracked by counter), not the intended withdrawal deposit (flowData), leading to improper refund behavior.

Tools Used

manual review

Recommendations

  • Correct Variable Reference:
    Modify the _cancelFlow function to reference flowData instead of counter when processing withdrawal flows. For example:

else if (flow == FLOW.WITHDRAW) {
+ uint256 depositId = flowData;
try IGmxPro;xy(gmxProxy).refundExecutionFee(
- depositInfo[counter].owner,
- depositInfo[counter].executionFee
+ depositInfo[depositId].owner,
+ depositInfo[depositId].executionFee
) {} catch {}
}
Updates

Lead Judging Commences

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

finding_counter_invalid_during_cancelFlow_after_withdrawing

Likelihood: Low, contract has to call cancelFlow after a withdraw, and the settle action is already executed by GMX. Impact: High, the fees will be distributed to the last depositor and not the withdrawer.

Support

FAQs

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

Give us feedback!