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

_gmxLock Not Reset After _settle() Execution

Summary

The internal function in PerpetualVault.sol _settle() sets _gmxLock = true before calling gmxProxy.settle(orderData). However, there is no mechanism to reset _gmxLock back to false, which can cause the contract to remain locked and prevent further interactions such as deposits, withdrawals, or new trade executions.

Vulnerability Details

  • _gmxLock is used as a mutex lock to prevent re-entrant or overlapping operations.

  • In _settle(), it is set to true before calling gmxProxy.settle(orderData).

  • If _gmxLock is never reset, all functions that check _gmxLock before execution will always revert or fail, effectively locking the contract indefinitely.

  • This issue can break vault operations by preventing any further trading, withdrawals, or deposits.

Affected Code:

function _settle() internal {
IGmxProxy.OrderData memory orderData = IGmxProxy.OrderData({
market: market,
indexToken: indexToken,
initialCollateralToken: address(collateralToken),
swapPath: new address isLong: beenLong,
sizeDeltaUsd: 0,
initialCollateralDeltaAmount: 0,
amountIn: 0,
callbackGasLimit: callbackGasLimit,
acceptablePrice: 0,
minOutputAmount: 0
});
_gmxLock = true;
gmxProxy.settle(orderData);
}

Impact

  1. Contract Gets Stuck:

    • _gmxLock remains true, preventing any further trades, withdrawals, or deposits.

    • The vault becomes non-functional after _settle() is called.

  2. User Funds Become Inaccessible:

    • Users may not be able to withdraw their funds if _gmxLock prevents further operations.

  3. Operational Failure & Loss of Trading Opportunities:

    • Automated trading logic relying on _settle() will fail due to the locked state, potentially resulting in missed trading opportunities or financial losses.

Tools Used

Manuel Review

Recommendations

Fix: Ensure _gmxLock is reset after gmxProxy.settle(orderData) is executed.
Modify _settle() as follows:

function _settle() internal {
IGmxProxy.OrderData memory orderData = IGmxProxy.OrderData({
market: market,
indexToken: indexToken,
initialCollateralToken: address(collateralToken),
swapPath: new address ,
isLong: beenLong,
sizeDeltaUsd: 0,
initialCollateralDeltaAmount: 0,
amountIn: 0,
callbackGasLimit: callbackGasLimit,
acceptablePrice: 0,
minOutputAmount: 0
});
_gmxLock = true;
gmxProxy.settle(orderData);
// ✅ Reset `_gmxLock` after settlement is complete
_gmxLock = false;
}

Alternatively, if settle() is asynchronous, reset _gmxLock in a callback function once settlement is confirmed.

Updates

Lead Judging Commences

n0kto Lead Judge 9 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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

Give us feedback!