The afterOrderCancellation()
function in the contract PerpetualVault.sol
is responsible for handling failed order executions on GMX. However, the function does not properly recover from persistent failures, meaning that if an order fails once, it may continue to fail indefinitely, preventing the vault from progressing past the failed state. This issue arises due to the function blindly retrying the same failed action without considering why it failed in the first place.
The function attempts to retry failed operations by setting nextAction.selector
to retry swaps, deposits, or withdrawals. However, if the underlying reason for failure is not resolved, the same action will continue to be retried, causing an infinite loop of failures.
Relevant code snippet:
Blind Retries:
The function always sets nextAction.selector
to retry the failed action, regardless of the underlying cause of failure.
If the issue is due to insufficient liquidity, price impact, or incorrect calldata, retrying does not solve the problem.
No Failure Handling Mechanism:
If an order fails multiple times, there is no mechanism to halt retries or escalate the failure.
This can lock the vault in an infinite failure loop, preventing any further interactions.
No Fallback or Escalation Logic:
If the issue persists, the contract should escalate the failure, possibly requiring off-chain intervention or logging a critical failure event.
The current implementation assumes that retrying is always the correct solution, which is not the case.
Funds may become stuck indefinitely as the contract gets stuck in an infinite loop of failed transactions.
Vault operations may halt, as the system keeps retrying the same failed action without resolving the root cause.
Possible gas drain if keepers continue submitting transactions that fail due to the same underlying issue.
Users may not be able to deposit, withdraw, or modify positions, leading to serious usability issues.
Manual Code Review
Introduce a retry limit:
Implement a counter for retries, and if an action fails more than N times, log an error and stop retrying.
Example fix:
Log a critical failure event if an action fails too many times so off-chain monitoring systems can intervene.
Add a validation step before retrying orders:
Before retrying, check why the order failed (e.g., insufficient balance, invalid calldata, price impact too high).
Example:
Introduce a fallback mechanism:
If an order keeps failing, reset the contract state and require manual intervention instead of retrying indefinitely.
Example:
Modify afterOrderCancellation()
to prevent infinite failures:
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.