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

Reentrancy Vulnerability in _runSwap Function Report

Reentrancy Vulnerability in _runSwap Function Report

Summary

A reentrancy vulnerability has been identified in the _runSwap function of the PerpetualVault contract, where state changes occur after external calls.

Vulnerability Details

function _runSwap(bytes[] memory metadata, bool isCollateralToIndex, MarketPrices memory prices) internal returns (bool completed) {
if (metadata.length == 2) {
// Vulnerable section
swapProgressData.swapped = swapProgressData.swapped + _doDexSwap(data, isCollateralToIndex); // External call
_doGmxSwap(data, isCollateralToIndex); // External call
return false;
} else {
// State changes after external calls
if (_protocol == PROTOCOL.DEX) {
uint256 outputAmount = _doDexSwap(data, isCollateralToIndex);
// State updates after external call
if (flow == FLOW.DEPOSIT) {
_mint(counter, outputAmount + swapProgressData.swapped, true, prices);
}
}
}
}

Key issues:

  1. External calls made before state updates

  2. State variable swapProgressData modified after external calls

  3. Multiple external calls in sequence without state locks

  4. Cross-function reentrancy possible through afterOrderCancellation

Impact

High severity:

  1. Potential double-swaps

  2. Incorrect state updates

  3. Fund loss through repeated operations

  4. Race conditions in swap execution

Tools Used

  • Slither static analyzer

  • Manual code review

  • Control flow analysis

Recommendations

Short-term Fix

function _runSwap(bytes[] memory metadata, bool isCollateralToIndex, MarketPrices memory prices) internal returns (bool completed) {
// Add reentrancy guard
require(!_reentrancyGuard, "ReentrancyGuard: reentrant call");
_reentrancyGuard = true;
// Update state first
SwapProgress memory tempSwapProgress = swapProgressData;
if (metadata.length == 2) {
(PROTOCOL _protocol, bytes memory data) = abi.decode(metadata[0], (PROTOCOL, bytes));
require(_protocol == PROTOCOL.DEX, "Invalid protocol");
// Execute swaps
uint256 dexOutput = _doDexSwap(data, isCollateralToIndex);
tempSwapProgress.swapped += dexOutput;
// Update state before second call
swapProgressData = tempSwapProgress;
(_protocol, data) = abi.decode(metadata[1], (PROTOCOL, bytes));
require(_protocol == PROTOCOL.GMX, "Invalid protocol");
_doGmxSwap(data, isCollateralToIndex);
_reentrancyGuard = false;
return false;
}
_reentrancyGuard = false;
return true;
}

Long-term Fixes:

  1. Implement Checks-Effects-Interactions pattern

  2. Add comprehensive reentrancy guards

  3. Consider using OpenZeppelin's ReentrancyGuard

  4. Add state validation checks

  5. Implement emergency pause functionality

  6. Add comprehensive event logging

  7. Consider splitting complex operations

  8. Add thorough testing for reentrancy scenarios

Updates

Lead Judging Commences

n0kto Lead Judge 5 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

Informational or Gas

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.

Suppositions

There is no real proof, concrete root cause, specific impact, or enough details in those submissions. Examples include: "It could happen" without specifying when, "If this impossible case happens," "Unexpected behavior," etc. Make a Proof of Concept (PoC) using external functions and realistic parameters. Do not test only the internal function where you think you found something.

n0kto Lead Judge 5 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

Informational or Gas

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.

Suppositions

There is no real proof, concrete root cause, specific impact, or enough details in those submissions. Examples include: "It could happen" without specifying when, "If this impossible case happens," "Unexpected behavior," etc. Make a Proof of Concept (PoC) using external functions and realistic parameters. Do not test only the internal function where you think you found something.

Support

FAQs

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