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

Single Queue Race Condition in GMX Order Management

Summary

The GmxProxy contract uses a single queue structure to track GMX orders, which causes a contention condition where concurrent orders can overwrite each other's data. This design flaw can result in stuck positions or incorrect order executions.

Vulnerability Details

struct OrderQueue {
bytes32 requestKey;
bool isSettle;
}
OrderQueue public queue;

This structure can only store one order at a time.

function createOrder(...) {
// ...
bytes32 requestKey = gExchangeRouter.createOrder(params);
queue.requestKey = requestKey; // Overwrites any existing order
return requestKey;
}
function settle(...) {
// ...
bytes32 requestKey = gExchangeRouter.createOrder(params);
queue.requestKey = requestKey; // Overwrites any existing order
queue.isSettle = true;
return requestKey;
}

The createOrder and settle functions immediately overwrite the existing queue without checking the previous order status.

function afterOrderExecution(...) {
// ... other code ...
// Only one order can be tracked
IGmxProxy.OrderResultData memory orderResultData = IGmxProxy.OrderResultData(
order.numbers.orderType,
order.flags.isLong,
order.numbers.sizeDeltaUsd,
outputToken,
outputAmount,
queue.isSettle // Using data from a queue that may have been overwritten
);
// Notifications to vault may use incorrect data
IPerpetualVault(perpVault).afterOrderExecution(
requestKey,
positionKey,
orderResultData,
prices
);
delete queue; // Deleting queue without validation
}

Only one order can be tracked in the afterOrderExecution function which may use data from an overwritten queue and the function deletes the queue without validation.

This will result in a stuck position if there are simultaneous orders because they overwrite each other's data.

Impact

The system can crash due to chaotic order tracking

Scenario

createOrder(Order.OrderType.MarketIncrease, orderDataA);
// queue = {requestKey: "0xA...", isSettle: false}
// t=1: User B creates a Market Swap order before order A is completed.
createOrder(Order.OrderType.MarketSwap, orderDataB);
// queue = {requestKey: "0xB...", isSettle: false}
// Order A is missing from tracking!
// t=2: GMX executes callback for Order A
afterOrderExecution("0xA...", orderA, eventDataA);
// Failed because queue.requestKey != "0xA..."

Tools Used

  • Manual review

Recommendations

Implement multiple order tracking.

Updates

Lead Judging Commences

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

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.

invalid_queue_requestKey_overwrite

Order is proceed one by one and requestKey is only used to cancelOrder. I didn’t see any real scenario where it will cause a problem. Flow and gmxLock will prevent that to happen.

Support

FAQs

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