Skip to main content
Sigvex

Slippage Validation Remediation

How to add slippage protection to DEX swap operations by exposing minimum output parameters and bounded deadlines to callers.

Slippage Validation Remediation

Overview

Missing slippage protection allows MEV bots to execute sandwich attacks against any DEX swap. The remediation requires exposing a minAmountOut parameter to callers and validating a bounded deadline. Never use 0 as the minimum output or block.timestamp as the deadline.

Related Detector: Slippage Validation

Before (Vulnerable)

function swap(address tokenIn, address tokenOut, uint256 amount) external {
    address[] memory path = new address[](2);
    path[0] = tokenIn;
    path[1] = tokenOut;
    // amountOutMin = 0, deadline = now — trivially sandwich-able
    router.swapExactTokensForTokens(amount, 0, path, msg.sender, block.timestamp);
}

After (Fixed)

function swap(
    address tokenIn,
    address tokenOut,
    uint256 amountIn,
    uint256 amountOutMin,  // Caller specifies minimum acceptable output
    uint256 deadline       // Caller specifies transaction window
) external {
    require(deadline > block.timestamp, "Deadline in past");
    require(amountOutMin > 0, "No slippage protection");

    address[] memory path = new address[](2);
    path[0] = tokenIn;
    path[1] = tokenOut;

    IERC20(tokenIn).transferFrom(msg.sender, address(this), amountIn);
    IERC20(tokenIn).approve(address(router), amountIn);

    router.swapExactTokensForTokens(amountIn, amountOutMin, path, msg.sender, deadline);
}

Alternative Mitigations

Protocol-enforced maximum slippage — compute minimum output from the current on-chain price and cap maximum slippage:

uint256 constant MAX_SLIPPAGE_BPS = 100; // 1%

function swap(address tokenIn, address tokenOut, uint256 amountIn, uint256 deadline) external {
    address[] memory path = new address[](2);
    path[0] = tokenIn;
    path[1] = tokenOut;

    uint256[] memory amounts = router.getAmountsOut(amountIn, path);
    uint256 expectedOut = amounts[amounts.length - 1];
    uint256 minOut = expectedOut * (10000 - MAX_SLIPPAGE_BPS) / 10000;

    IERC20(tokenIn).transferFrom(msg.sender, address(this), amountIn);
    IERC20(tokenIn).approve(address(router), amountIn);

    router.swapExactTokensForTokens(amountIn, minOut, path, msg.sender, deadline);
}

Private mempool for vault compounds — for automated vault strategies, submit compound transactions through MEV-protected RPC endpoints (Flashbots, MEV Blocker) in addition to protocol-level slippage.

Common Mistakes

Deriving minOut from the same pool’s spot price — if getAmountsOut() is called in the same transaction before the swap, an attacker can manipulate the pool to inflate expectedOut, then let the swap execute at the inflated price anyway (because minOut was derived from the manipulated price).

deadline = block.timestamp + 0 — equivalent to no deadline. Use at least block.timestamp + 15 minutes for user-initiated swaps.

amountOutMin = 1 — functionally equivalent to 0 for large swaps. Minimum must be a meaningful fraction of expected output.

References