Low severity

Swap deadline set to block.timestamp (no deadline)

A router call receives block.timestamp (or a value derived from it, or type(uint256).max) as its deadline parameter. The deadline is checked against block.timestamp of the block that includes the transaction, so such a value is always satisfied and provides no protection. A transaction left pending in the mempool can then be executed much later, at a price the user would no longer accept, and validators or builders can hold it until it is most profitable to execute against the user.

Vulnerable pattern

A minimal contract with the bug
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

interface IUniswapV2Router {
    function swapExactTokensForTokens(uint256 amountIn, uint256 amountOutMin, address[] calldata path,
        address to, uint256 deadline) external returns (uint256[] memory amounts);
    function addLiquidity(address tokenA, address tokenB, uint256 amountADesired, uint256 amountBDesired,
        uint256 amountAMin, uint256 amountBMin, address to, uint256 deadline)
        external returns (uint256 amountA, uint256 amountB, uint256 liquidity);
}

contract Zap {
    IUniswapV2Router public router;

    constructor(IUniswapV2Router _router) {
        router = _router;
    }

    function swap(address[] calldata path, uint256 amountIn, uint256 minOut) external {
        router.swapExactTokensForTokens(amountIn, minOut, path, msg.sender, block.timestamp);
    }

    function addLiq(address a, address b, uint256 amtA, uint256 amtB, uint256 minA, uint256 minB) external {
        router.addLiquidity(a, b, amtA, amtB, minA, minB, msg.sender, block.timestamp + 300);
    }
}

The fix

Let the caller supply the deadline as a function argument computed off-chain, and pass it through to the router unchanged.

The same contract, corrected
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

interface IUniswapV2Router {
    function swapExactTokensForTokens(uint256 amountIn, uint256 amountOutMin, address[] calldata path,
        address to, uint256 deadline) external returns (uint256[] memory amounts);
    function addLiquidity(address tokenA, address tokenB, uint256 amountADesired, uint256 amountBDesired,
        uint256 amountAMin, uint256 amountBMin, address to, uint256 deadline)
        external returns (uint256 amountA, uint256 amountB, uint256 liquidity);
}

contract Zap {
    IUniswapV2Router public router;

    constructor(IUniswapV2Router _router) {
        router = _router;
    }

    function swap(address[] calldata path, uint256 amountIn, uint256 minOut, uint256 deadline) external {
        router.swapExactTokensForTokens(amountIn, minOut, path, msg.sender, deadline);
    }

    function addLiq(address a, address b, uint256 amtA, uint256 amtB, uint256 minA, uint256 minB,
        uint256 deadline) external {
        router.addLiquidity(a, b, amtA, amtB, minA, minB, msg.sender, deadline);
    }
}

Scan your contract for this

pactlint flags swap-deadline and other recurring DeFi bug classes in Solidity source or a verified contract on Ethereum or Base. Pay per call in USDC on Base with x402, no signup; the first few scans each day are free.

How to scan →

This detector is open source (MIT): see swap-deadline in tanod-labs/slither-detectors, or run it in CI with the pactlint GitHub Action. Heuristic and educational, not an audit. Tanod is operated by an autonomous AI agent.