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

Unhandled LimitIncrease Order Type in Gas Limit Calculation

Summary

The GmxProxy.sol::getExecutionGasLimit function's if-else statement misses handling the LimitIncrease order type, which could lead to incorrect gas limit calculations if this order type is used.

Vulnerability Details

The GmxProxy.sol::getExecutionGasLimit function does not handle the Order.OrderType.LimitIncrease order type, meaning that any LimitIncrease order submitted will use an incorrect gas limit estimation. If an order of type LimitIncrease is created, estimatedGasLimit remains uninitialised (causing a compilation error) or defaults to zero, leading to an underestimated gas limit. This can result in failed transactions due to insufficient gas.

The getExecutionGasLimit function explicitly handles:

  • MarketIncrease

  • MarketDecrease

  • LimitDecrease

  • StopLossDecrease

  • MarketSwap

This missing case leads to estimatedGasLimit being unset (remaining 0), which results in an incorrect executionGasLimit calculation, potentially causing transaction failures.

Affected Function: getExecutionGasLimit()

function getExecutionGasLimit(
Order.OrderType orderType,
uint256 _callbackGasLimit
) public view returns (uint256 executionGasLimit) {
uint256 baseGasLimit = dataStore.getUint(ESTIMATED_GAS_FEE_BASE_AMOUNT_V2_1);
uint256 oraclePriceCount = 5;
baseGasLimit += dataStore.getUint(ESTIMATED_GAS_FEE_PER_ORACLE_PRICE) * oraclePriceCount;
uint256 multiplierFactor = dataStore.getUint(ESTIMATED_GAS_FEE_MULTIPLIER_FACTOR);
uint256 gasPerSwap = dataStore.getUint(SINGLE_SWAP_GAS_LIMIT);
uint256 estimatedGasLimit;
if (orderType == Order.OrderType.MarketIncrease) {
estimatedGasLimit = dataStore.getUint(INCREASE_ORDER_GAS_LIMIT) + gasPerSwap;
} else if (orderType == Order.OrderType.MarketDecrease) {
estimatedGasLimit = dataStore.getUint(DECREASE_ORDER_GAS_LIMIT) + gasPerSwap;
} else if (orderType == Order.OrderType.LimitDecrease) {
estimatedGasLimit = dataStore.getUint(DECREASE_ORDER_GAS_LIMIT) + gasPerSwap;
} else if (orderType == Order.OrderType.StopLossDecrease) {
estimatedGasLimit = dataStore.getUint(DECREASE_ORDER_GAS_LIMIT) + gasPerSwap;
} else if (orderType == Order.OrderType.MarketSwap) {
estimatedGasLimit = dataStore.getUint(SWAP_ORDER_GAS_LIMIT) + gasPerSwap;
}
executionGasLimit = baseGasLimit +
((estimatedGasLimit + _callbackGasLimit) * multiplierFactor) / PRECISION;
}

Impact

  1. Transaction Failures: Orders will be submitted with insufficient gas, causing failed transactions.

  2. Fund Lockups: Execution fees may be locked in GMX contracts due to failed order processing.

  3. Protocol Disruption: The inability to execute critical limit orders could destabilise hedging strategies.

  4. Reputation Damage: Users may lose trust in the protocol’s order execution reliability.

Tools Used

I used DeepSeek and OpenAi to verify my hunch regarding the completeness of the IF ELSE statement. To quote Daniel Von Fange, "Every time you write an if statement you are giving Satan a little place to live in your code"

Recommendations

Add Explicit Handling for LimitIncrease Orders

Modify getExecutionGasLimit to properly set estimatedGasLimit for LimitIncrease:

if (orderType == Order.OrderType.MarketIncrease) {
estimatedGasLimit = dataStore.getUint(INCREASE_ORDER_GAS_LIMIT) + gasPerSwap;
+ } else if (orderType == Order.OrderType.LimitIncrease) {
+ estimatedGasLimit = dataStore.getUint(INCREASE_ORDER_GAS_LIMIT) + gasPerSwap;
} else if (orderType == Order.OrderType.MarketDecrease) {
estimatedGasLimit = dataStore.getUint(DECREASE_ORDER_GAS_LIMIT) + gasPerSwap;
}

Add a Default Case to Revert Unhandled Orders:

else {
revert("Unsupported order type in gas calculation");
}

Implement compile-time validation of all Order.OrderType variants:

// Ensure all order types are handled
function validateOrderTypes() internal pure {
assert(uint8(Order.OrderType.MarketIncrease) == 0);
assert(uint8(Order.OrderType.LimitIncrease) == 1);
// ... continue for all known order types ...
}
Updates

Lead Judging Commences

n0kto Lead Judge 5 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

Informational or Gas

Please read the CodeHawks documentation to know which submissions are valid. If you disagree, provide a coded PoC and explain the real likelihood and the detailed impact on the mainnet without any supposition (if, it could, etc) to prove your point.

Suppositions

There is no real proof, concrete root cause, specific impact, or enough details in those submissions. Examples include: "It could happen" without specifying when, "If this impossible case happens," "Unexpected behavior," etc. Make a Proof of Concept (PoC) using external functions and realistic parameters. Do not test only the internal function where you think you found something.

Support

FAQs

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