The _runSwap function in the PerpetualVault contract updates critical state variables (swapProgressData) after making external calls to DEX/GMX swaps. This violates the Checks-Effects-Interactions pattern, creating a reentrancy risk if malicious tokens or callback functions reenter the contract before state consistency is restored.
Function: _runSwap(bytes[], bool, MarketPrices) (PerpetualVault.sol#976-1019)
External Calls:
Unsafe State Management:
After external swaps (DEX/GMX), the contract updates swapProgressData.swapped (for DEX) and swapProgressData.remaining/isCollateralToIndex (for GMX).
Example from _doGmxSwap:
This allows reentrancy during the external call (e.g., GMX callback) while swapProgressData is stale.
Cross-Function Reentrancy:
The afterOrderCancellation function (L592-623) uses swapProgressData to retry failed swaps.
An attacker could trigger this function mid-swap, exploiting outdated swapProgressData values.
Swap State Corruption: Reentrant calls could reset/modify swapProgressData, causing incorrect tracking of swap amounts.
Fund Loss/Theft: Malicious actors could exploit stale data to double-swap tokens or bypass swap limits.
Severity: High (exploitable via ERC777-like tokens or GMX callbacks).
Attacker Deposits ERC777 Token: Uses a token with a tokensReceived hook during transfers.
Trigger _runSwap: Initiates a DEX swap for the malicious token.
Reenter During Transfer:
The tokensReceived callback calls _runSwap again before swapProgressData is updated.
The reentrant _runSwap uses stale swapProgressData.remaining, allowing double swaps.
Drain Funds: Attacker withdraws excess tokens from corrupted swap tracking.
Update swapProgressData before external calls:
Apply the nonReentrant modifier to _runSwap and related functions:
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.