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.