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

`_doDexSwap` Vulnerability Report

_doDexSwap Vulnerability Report

Summary

The _doDexSwap function in PerpetualVault lacks critical input validation and slippage protection, making it vulnerable to sandwich attacks and manipulation.

Vulnerability Details

function _doDexSwap(bytes memory data, bool isCollateralToIndex) internal returns (uint256 outputAmount) {
(address to, uint256 amount, bytes memory callData) = abi.decode(data, (address, uint256, bytes));
IERC20 inputToken;
IERC20 outputToken;
if (isCollateralToIndex) {
inputToken = collateralToken;
outputToken = IERC20(indexToken);
} else {
inputToken = IERC20(indexToken);
outputToken = collateralToken;
}
uint256 balBefore = outputToken.balanceOf(address(this));
ParaSwapUtils.swap(to, callData); // No slippage protection
outputAmount = IERC20(outputToken).balanceOf(address(this)) - balBefore;
emit DexSwap(address(inputToken), amount, address(outputToken), outputAmount, isCollateralToIndex);
}

Key issues:

  1. No minimum output amount validation

  2. No slippage protection

  3. No deadline for swap execution

  4. No validation of to address

  5. Assumes successful swap without checking return value

Impact

High severity - The vulnerability could lead to:

  1. MEV sandwich attacks

  2. Significant value loss through price manipulation

  3. Potential loss of user funds

  4. Failed trades with unacceptable slippage

Tools Used

  • Manual code review

  • Static analysis

  • Control flow analysis

Recommendations

Short-term Fix

function _doDexSwap(bytes memory data, bool isCollateralToIndex) internal returns (uint256 outputAmount) {
(
address to,
uint256 amount,
bytes memory callData,
uint256 minOutputAmount,
uint256 deadline
) = abi.decode(data, (address, uint256, bytes, uint256, uint256));
// Input validation
require(to != address(0), "Invalid DEX address");
require(amount > 0, "Invalid swap amount");
require(deadline >= block.timestamp, "Swap expired");
IERC20 inputToken = isCollateralToIndex ? collateralToken : IERC20(indexToken);
IERC20 outputToken = isCollateralToIndex ? IERC20(indexToken) : collateralToken;
uint256 balBefore = outputToken.balanceOf(address(this));
// Execute swap
bool success = ParaSwapUtils.trySwap(to, callData);
require(success, "Swap failed");
// Verify output
outputAmount = outputToken.balanceOf(address(this)) - balBefore;
require(outputAmount >= minOutputAmount, "Insufficient output amount");
emit DexSwap(
address(inputToken),
amount,
address(outputToken),
outputAmount,
isCollateralToIndex
);
}

Long-term Fixes:

  1. Implement circuit breakers for extreme price movements

  2. Add price oracle checks for validation

  3. Consider using aggregated DEX prices

  4. Implement maximum slippage parameters

  5. Add emergency pause functionality

  6. Monitor for suspicious trading patterns

Updates

Lead Judging Commences

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

invalid_swap_slippage_and_deadline

Slippage and deadline are handled externally. Paraswap implementation used by the current code (behind the proxy): https://etherscan.io/address/0xdffd706ee98953d3d25a3b8440e34e3a2c9beb2c GMX code: https://github.com/gmx-io/gmx-synthetics/blob/caf3dd8b51ad9ad27b0a399f668e3016fd2c14df/contracts/order/OrderUtils.sol#L150C15-L150C33

Support

FAQs

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