Inside the GMX protocol contract ExecuteOrderUtils.sol, after making the callback to GmxProxy.sol::afterOrderExecution() of the Gamma protocol, it initiates the process of paying the execution fee to the GMX keeper for the transaction and refunds any excess amount to the callback contract (GmxProxy.sol).
ExecuteOrderUtils.sol::executeOrder():
GasUtils.sol::payExecutionFee()
As you can see, if the refund transaction fails due to insufficient gas or other errors, the refund is made to the receiver() address of the order object (refundReceiver == PerpetualVault).
Inside TokenUtils.sol::sendNativeToken(), it first attempts to send the native token; if that fails, it will send the Wrapped Native Token (WNT) to the refund receiver (PerpetualVault).
TokenUtils.sol::sendNativeToken()
And according the integration notes of GMX contracts:
ETH transfers are sent with NATIVE_TOKEN_TRANSFER_GAS_LIMIT for the gas limit, if the transfer fails due to insufficient gas or other errors, the ETH is sent as WETH instead
Accounts may receive ETH for ADLs / liquidations, if the account cannot receive ETH then WETH would be sent instead
As the Perpetual Vault contract lacks functionality for handling the Native Token or WNT, perpetual vaults whose market tokens are neither the Native Token nor WNT as collateralToken or indexToken will have the refund funds stuck in the contract.
For instance, the market LINK/USD don't handle any WETH or ETH as indexToken or collateralToken, when the vault receive some funds in Native or WNT tokens because of some refund, then those funds will be stuck in the contract. It also won't account as idle funds because is taking the balance of the collateralToken(USDC):
So we can say that in some perpetual vaults, the refund funds will be locked in the contract.
Funds stucked into the contract.
Not having functionality for handling the refund amounts of Native WNT tokens.
Add some function to transfer the native tokens to the Gmx Proxy and withdraw the WNT as the Gmx proxy don't have functionality for handle WNT as well.
`TokenUtils.sol::sendNativeToken()` has no reason to fail since there is a `receive` function without any instruction in the GmxProxy. It’s the simpliest and cheapest transfer possible. Good finding, but there is no likelihood.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.