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

Execution Fee Refund Sent to Wrong User

Summary

In the _handleReturn function, the refundFee logic incorrectly uses depositInfo[counter] instead of depositInfo[depositId] to determine the recipient (owner) and amount (executionFee) for refunding excess execution fees. The counter variable, incremented globally in the deposit function, represents the latest deposit ID, not the current withdrawal’s depositId from flowData. This results in refunds being sent to the wrong user (the owner of the most recent deposit) while the correct user receives nothing, leading to a significant misallocation of funds.

Vulnerability Details

Inside PerpetualVault.sol-

Affected Function: The bug occurs in the refundFee block of the _handleReturn function

if (refundFee) {
uint256 usedFee = callbackGasLimit * tx.gasprice;
if (depositInfo[depositId].executionFee > usedFee) {
// bug: Using counter instead of depositId
try IGmxProxy(gmxProxy).refundExecutionFee(depositInfo[counter].owner, depositInfo[counter].executionFee - usedFee) {} catch {}
}
}

depositId is unpacked from flowData and correctly identifies the withdrawing user’s deposit. However, the refund logic uses counter, a global variable incremented in the deposit function for each new deposit.

Refund logic mistakenly accesses depositInfo[counter] instead of depositInfo[depositId] .


Due to this, refund goes to the wrong user {depositInfo[counter].owner}, while the actual withdrawing user{depositInfo[depositId].owner} never receives their due refund.

Impact

The rightful depositor loses their leftover execution fee and a different user received funds they never claimed.

Tools Used

Manual Review

Recommendations

Replace counter with depositId in the refundFee logic to ensure the correct user receives their refund.

if (refundFee) {
uint256 usedFee = callbackGasLimit * tx.gasprice;
if (depositInfo[depositId].executionFee > usedFee) {
// @audit: Using correct owner and execution fee
try IGmxProxy(gmxProxy).refundExecutionFee(depositInfo[depositId].owner, depositInfo[depositId].executionFee - usedFee) {} catch {}
}
}
Updates

Lead Judging Commences

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

finding_counter_invalid_during_handleReturn

Likelihood: Medium/High, when withdraw on a 1x vault. 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!