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

Missing code to delete `nextAction` in `afterOrderCancellation()` will result incorrect execution of `FLOW.COMPOUND` deviating from the intented flow .

Summary

Missing code to delete nextAction in afterOrderCancellation() will result incorrect execution of FLOW.COMPOUND deviating from the intented flow .

It also breaks the key invariant mentioned in the readMe. (nextAction should be empty when all acitons are completed.)

Vulnerability Details

  • afterOrderCancellation() is a callback fun which is executed by GMXproxy when the gmxKeeper cancels its current pending order.

  • If the pending order is because of the SIGNAL_CHANGE flow , the code is only deleting the flow and flowData . gmxLock is also disabled allowing the keeper and users to continue their operation , marking the completion of an action.

  • For a keeper to execute FLOW.COMPUND , he just needs to call runNextAction() with no precondition. As a result this code will get executed and COMPOUND FLOW is generated.

Now lets say the current position is long with 2x leverage.
Keeper calls run() to convert the position to short.
As a result , nextAction.selector is made to INCREASE_ACTION and a decrease order is generate to be executed by the GMX.code

But GMX couldnt execute it and hence calls the callback function afterOrderCancellation().

Since the flow is SIGNAL_CHANGE , the nextAction.selector remains unchanged.

function afterOrderCancellation() external {
....
if (orderResultData.isSettle) {
....
} else if (orderType == Order.OrderType.MarketSwap) {
....
} else {
if (flow == FLOW.DEPOSIT) {
....
} else if (flow == FLOW.WITHDRAW) {
....
=> } else {
// If signal change fails, the offchain script starts again from the current status.
delete flowData;
delete flow;
}
}
}

Note : It is mentioned in the dev cmnt that the offchain scripts starts again with the current status. That means next txn can be any action depending on the current state.

Now , the keeper , inorder to execute FLOW.COMPOUND , calls runNextAction().

But, since the nextAction.selector has the value INCREASE_ACTION , it will execute the wrong if{} condition code.

Impact

The key invariant in the readMe After all actions completed, nextAction, swapProgressData should be empty. PositionKey is 0 when no position is broken.

Incorrect flow is executed deviating from the actual flow.

The check isFundIdle()code is skipped before creating an increase Order. Hence the remaining collateral balance of the perps contract is used for increasing the position without checking the minDeposit threshold.

Tools Used

Manual

Recommendations

delete the nextAction when the flow is SIGNAL_CHANGE while the current action ends with afterOrderCancellation() callback.

Updates

Lead Judging Commences

n0kto Lead Judge 5 months ago
Submission Judgement Published
Invalidated
Reason: Design choice
Assigned finding tags:

invalid_afterOrderCancellation_do_not_reset_nextAction

Normal behavior, the keeper will retry to increase the position. That’s why there is this condition in `_createIncreasePosition`: ``` if (flow == FLOW.DEPOSIT) { amountIn = depositInfo[counter].amount; flowData = vaultReader.getPositionSizeInTokens(curPositionKey); } else { amountIn = collateralToken.balanceOf(address(this)); } ```

Support

FAQs

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