If liquidation returns indexToken (e.g., ETH) instead of collateralToken (e.g., USDC), calling runNextAction with INCREASE_ACTION fails due to a mismatch between GMX swap data and the ParaSwap-specific _doDexSwap function, resulting in a memory allocation error (0x41). This locks all funds in the vault (collateralToken and indexToken), rendering them unrecoverable without owner intervention.
Location: PerpetualVault.sol, runNextAction function, INCREASE_ACTION branch.
Condition: indexToken balance * price ≥ ONE_USD (e.g., 0.005 ETH * 3386 > 1 USD), triggering _doDexSwap with GMX-formatted data (PROTOCOL.GMX, (address[], uint256, uint256)).
Behavior: _doDexSwap expects (address, uint256, bytes), fails to decode, and reverts, stalling flows like DEPOSIT and locking funds in vault2x.
Likelihood: Low to Medium – GMX typically returns USDC for shorts, but indexToken return is possible in edge cases (e.g., pool imbalances).
Severity: High – All vault funds during the flow (e.g., 10 USDC + 0.005 ETH) are locked, requiring owner action via setVaultState, introducing centralization and delay risks.
User Risk: Complete loss of access to funds until manual recovery, potentially indefinite if owner is unresponsive.
Deploy PerpetualVault with 2x leverage (vault2x), ETH/USDC market.
User deposits 10 USDC (depositFixtureInto2x).
Keeper opens a 2x short position (runShort2x).
User deposits another 10 USDC (deposit).
Simulate full liquidation returning 0.005 ETH (deal to vault2x, sizeInTokens = 0).
Keeper calls runNextAction with GMX swap data, which fails, locking funds.
Add these 2 functions to PerpetualVaul.t.sol to use the same setup.
Manual review.
Foundry (Forge) for testing and simulation.
Solidity compiler for contract analysis.
Protocol Check: Modify runNextAction to check PROTOCOL and call _doGmxSwap for PROTOCOL.GMX, preventing the decoding error.
Auto-Swap: In afterLiquidationExecution, detect indexToken balance and initiate a GMX swap to collateralToken, avoiding flow stalls.
Owner Recovery: Document the setVaultState workaround as a temporary mitigation, but prioritize automated handling.
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. Keepers are added by the admin, there is no "malicious keeper" and if there is a problem in those keepers, that's out of scope. ReadMe and known issues states: " * System relies heavily on keeper for executing trades * Single keeper point of failure if not properly distributed * Malicious keeper could potentially front-run or delay transactions * Assume that Keeper will always have enough gas to execute transactions. There is a pay execution fee function, but the assumption should be that there's more than enough gas to cover transaction failures, retries, etc * There are two spot swap functionalies: (1) using GMX swap and (2) using Paraswap. We can assume that any swap failure will be retried until success. " " * Heavy dependency on GMX protocol functioning correctly * Owner can update GMX-related addresses * Changes in GMX protocol could impact system operations * We can assume that the GMX keeper won't misbehave, delay, or go offline. " "Issues related to GMX Keepers being DOS'd or losing functionality would be considered invalid."
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.