RustitrageExecutorOptimized

Description:

Decentralized Finance (DeFi) protocol contract providing Swap, Factory functionality.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

{{
  "language": "Solidity",
  "sources": {
    "RustitrageExecutorOptimizedv4.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

/*
 * RustitrageExecutorOptimized
 * ------------------------------------------------------------
 * This contract executes multi‑hop swaps across multiple AMM versions.
 * It supports Uniswap V2, Uniswap V3 (including Pancake V3) and
 * Uniswap V4 pools via a custom implementation.  To minimise gas
 * consumption, all relevant swap parameters (zeroForOne flag, pool
 * key, etc.) are supplied off‑chain via the SwapParams.extraData
 * field.  No on‑chain token0/token1 lookups are performed.
 *
 * V4 integration notes:
 *
 *  - All v4 pools are managed by a single PoolManager contract.
 *  - The swap must be executed inside an unlock callback; therefore
 *    this contract implements the IUnlockCallback interface.
 *  - Off‑chain code must compute the PoolKey (currency0, currency1,
 *    fee, tickSpacing, hooks) and encode it in extraData.  The
 *    amountSpecified and zeroForOne are provided in the top‑level
 *    SwapParams.
 *  - The extraData for a v4 hop should abi‑encode the V4SwapData
 *    struct defined below.  See _swapV4() for details.
 *
 *  - To execute a v4 swap safely, the contract:
 *      1. Calls poolManager.sync(tokenIn) before sending tokens in.
 *      2. Transfers the input tokens into the PoolManager.
 *      3. Calls poolManager.unlock() with encoded data.  This
 *         triggers unlockCallback(), which calls swap(), settles the
 *         negative delta (input) and withdraws the positive delta
 *         (output).
 *      4. After unlock returns, the amount of output tokens is
 *         decoded from the return data and compared against
 *         minAmountOut.
 *
 *  - Only the whitelisted PoolManager may call unlockCallback().
 */

// ----------------- ERC20 + safe wrappers -----------------
interface IERC20 {
    function balanceOf(address) external view returns (uint256);
    function allowance(address owner, address spender) external view returns (uint256);
    function approve(address spender, uint256 value) external returns (bool);
    function transfer(address to, uint256 value) external returns (bool);
    function transferFrom(address from, address to, uint256 value) external returns (bool);
}

library SafeERC20 {
    function _call(address token, bytes memory data) private returns (bytes memory) {
        (bool ok, bytes memory ret) = token.call(data);
        require(ok, "TOK_CALL_FAIL");
        if (ret.length > 0) require(abi.decode(ret, (bool)), "TOK_FALSE");
        return ret;
    }
    function safeTransfer(IERC20 t, address to, uint256 v) internal {
        _call(address(t), abi.encodeWithSelector(t.transfer.selector, to, v));
    }
    function safeTransferFrom(IERC20 t, address f, address to, uint256 v) internal {
        _call(address(t), abi.encodeWithSelector(t.transferFrom.selector, f, to, v));
    }
    function safeApprove(IERC20 t, address s, uint256 v) internal {
        _call(address(t), abi.encodeWithSelector(t.approve.selector, s, v));
    }
}

// ----------------- V2 -----------------
interface IUniswapV2Pair {
    function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external;
}

// ----------------- V3 -----------------
interface IUniswapV3Pool {
    function swap(
        address recipient,
        bool zeroForOne,
        int256 amountSpecified,
        uint160 sqrtPriceLimitX96,
        bytes calldata data
    ) external returns (int256 amount0, int256 amount1);
    function token0() external view returns (address);
    function token1() external view returns (address);
}

interface IUniswapV3SwapCallback {
    function uniswapV3SwapCallback(int256 amount0Delta, int256 amount1Delta, bytes calldata data) external;
}
interface IPancakeV3SwapCallback {
    function pancakeV3SwapCallback(int256 amount0Delta, int256 amount1Delta, bytes calldata data) external;
}
// Factory interface (Uniswap/Pancake style)
interface IV3FactoryLike {
    function getPool(address tokenA, address tokenB, uint24 fee) external view returns (address);
}

// ----------------- V4 -----------------
/**
 * @dev Minimal interface for Uniswap v4 PoolManager, used here for swaps.
 * Only the functions needed by this contract are included.  Currency is
 * treated as an address; real implementation treats Currency as a type
 * alias of address.  swap() returns a BalanceDelta, which packs two
 * signed 128‑bit integers representing amount0 and amount1 deltas.
 */
interface IPoolManager {
    struct PoolKey {
        address currency0;
        address currency1;
        uint24 fee;
        int24 tickSpacing;
        address hooks;
    }
    struct SwapParams {
        bool zeroForOne;
        int256 amountSpecified;
        uint160 sqrtPriceLimitX96;
    }
    function swap(PoolKey calldata key, SwapParams calldata params, bytes calldata data) external returns (int256 swapDelta);
    function take(address currency, address to, uint256 amount) external;
    function settle() external payable returns (uint256 paid);
    function sync(address currency) external;
    function unlock(bytes calldata data) external returns (bytes memory);
}

/**
 * @dev Interface for the v4 unlock callback.  PoolManager will call
 * unlockCallback(data) during unlock().  This contract must inherit
 * from this interface and implement unlockCallback() to perform the
 * swap and settle/take operations.
 */
interface IUnlockCallback {
    function unlockCallback(bytes calldata data) external returns (bytes memory);
}

/**
 * @dev Library for unpacking BalanceDelta values returned from v4 swap().
 * A BalanceDelta is a single int256 in which the upper 128 bits encode
 * amount0 and the lower 128 bits encode amount1.  Positive deltas mean
 * the PoolManager owes the caller tokens; negative deltas mean the
 * caller owes the PoolManager tokens.
 */
library BalanceDeltaLibrary {
    function amount0(int256 balanceDelta) internal pure returns (int128 _amount0) {
        _amount0 = int128(balanceDelta >> 128);
    }
    function amount1(int256 balanceDelta) internal pure returns (int128 _amount1) {
        // mask lower 128 bits and sign extend
        int256 masked = int256(uint256(balanceDelta) & ((1 << 128) - 1));
        _amount1 = int128(masked);
    }
}

// ----------------- DODO (DVM/DPP-like) -----------------
interface IDODOLike {
    function sellBaseToken(uint256 amount, uint256 minReceive, bytes calldata data) external returns (uint256);
    function sellQuoteToken(uint256 amount, uint256 minReceive, bytes calldata data) external returns (uint256);
    function _BASE_TOKEN_() external view returns (address);
    function _QUOTE_TOKEN_() external view returns (address);
}

// ----------------- Ownable (minimal) -----------------
abstract contract Ownable {
    address public owner;
    event OwnershipTransferred(address indexed prev, address indexed next);
    constructor() { owner = msg.sender; emit OwnershipTransferred(address(0), msg.sender); }
    modifier onlyOwner() { require(msg.sender == owner, "ONLY_OWNER"); _; }
    function transferOwnership(address next) external onlyOwner { require(next != address(0), "ZERO"); emit OwnershipTransferred(owner, next); owner = next; }
}

// ----------------- Executor -----------------
contract RustitrageExecutorOptimized is IUniswapV3SwapCallback, IPancakeV3SwapCallback, IUnlockCallback, Ownable {
    using SafeERC20 for IERC20;

    // Pool type constants
    uint8 internal constant PT_V2   = 1;
    uint8 internal constant PT_V3   = 2;
    uint8 internal constant PT_DODO = 3;
    uint8 internal constant PT_V4   = 4;

    // Custom errors
    error UNAUTH_FACTORY();
    error BAD_V3_POOL();
    error NO_DELTA();
    error V4_MIN_OUT_NOT_MET();

    // Immutable factories for whitelisting v3 pools
    address immutable FACTORY_A;
    address immutable FACTORY_B;
    address immutable FACTORY_C;

    // Immutable PoolManager for v4
    IPoolManager public immutable POOL_MANAGER;

    constructor(address factoryA, address factoryB, address factoryC, IPoolManager poolManager) {
        FACTORY_A = factoryA;
        FACTORY_B = factoryB;
        FACTORY_C = factoryC;
        POOL_MANAGER = poolManager;
    }

    /// @dev pure/view check without storage reads
    function _isAllowedFactory(address f) internal view returns (bool) {
        if (f == address(0)) return false;
        return (f == FACTORY_A) || (f == FACTORY_B) || (f == FACTORY_C);
    }

    /// @notice parameters describing one hop of a multi‑hop swap
    struct SwapParams {
        address tokenIn;
        address tokenOut;
        uint256 amountIn;
        uint256 minAmountOut;
        address pool;
        uint8   poolType;
        bool    zeroForOne;
        bytes   extraData;
    }

    /// @notice extra data for v4 swap: encodes the PoolKey, recipient and price limit
    struct V4SwapData {
        IPoolManager.PoolKey key;
        address recipient;
        uint160 sqrtPriceLimitX96;
    }

    /**
     * @notice Execute a sequence of swaps. The caller is expected to ensure
     *         that the contract holds `hops[0].amountIn` of the first token.
     * @param hops An array of SwapParams describing each hop
     */
    function execute(SwapParams[] calldata hops) external onlyOwner {
        require(hops.length > 0, "NO_HOPS");
        uint256 amountIn;
        // initial amountIn is specified in hop[0]
        amountIn = hops[0].amountIn;
        for (uint256 i; i < hops.length; ) {
            SwapParams calldata p = hops[i];
            if (p.poolType == PT_V2) {
                _swapV2(p.pool, p.tokenIn, amountIn, p.minAmountOut, p.zeroForOne);
                amountIn = p.minAmountOut;
            } else if (p.poolType == PT_V3) {
                amountIn = _swapV3(p.pool, p.tokenIn, p.tokenOut, amountIn, p.minAmountOut, p.zeroForOne, p.extraData);
            } else if (p.poolType == PT_V4) {
                amountIn = _swapV4(p.pool, p.tokenIn, amountIn, p.minAmountOut, p.zeroForOne, p.extraData);
            } else {
                revert("BAD_POOL_TYPE");
            }
            unchecked { ++i; }
        }
    }

    // --- V2 swap ---
    /**
     * @dev Executes a Uniswap V2 style swap. The `zeroForOne` boolean controls
     *      whether tokenIn is token0 (true) or token1 (false). No external
     *      calls to token0()/token1() are made, so the caller must set
     *      `zeroForOne` correctly. If it is incorrect the swap may revert or
     *      produce the wrong token flow.
     */
    function _swapV2(
        address pair,
        address tokenIn,
        uint256 amountIn,
        uint256 minOut,
        bool zeroForOne
    ) internal {
        // trust zeroForOne: do not call token0/token1
        IERC20(tokenIn).safeTransfer(pair, amountIn);
        uint amount0Out = zeroForOne ? 0 : minOut;
        uint amount1Out = zeroForOne ? minOut : 0;
        IUniswapV2Pair(pair).swap(amount0Out, amount1Out, address(this), new bytes(0));
    }

    // --- V3 swap ---
    /**
     * @dev Executes a Uniswap V3 style swap. The caller must supply
     *      zeroForOne to indicate the direction of the swap. The extraData
     *      parameter may contain:
     *        - empty: uses default sqrtPrice limits
     *        - 32 bytes: sqrtPriceLimitX96
     *        - 64 bytes: fee + factory
     *        - 96 bytes: sqrtPriceLimitX96 + fee + factory
     */
    function _swapV3(
        address pool,
        address tokenIn,
        address tokenOut,
        uint256 amountIn,
        uint256 minOut,
        bool zeroForOne,
        bytes calldata extra
    ) internal returns (uint256 amountOut) {
        (uint160 sqrtLimit, uint24 fee, address factory) = _parseV3Extra(extra, zeroForOne);
        bytes memory cb = abi.encode(tokenIn, tokenOut, fee, factory);
        (int256 a0, int256 a1) = IUniswapV3Pool(pool).swap(
            address(this),
            zeroForOne,
            int256(amountIn),
            sqrtLimit,
            cb
        );
        int256 deltaOut = zeroForOne ? a1 : a0;
        require(deltaOut <= 0, "V3_POS_DELTA");
        amountOut = uint256(-deltaOut);
        require(amountOut >= minOut, "V3_SLIPPAGE");
    }

    // Extract sqrtPriceLimit, fee and factory from extra data. See header for details.
    function _parseV3Extra(bytes calldata extra, bool zeroForOne) internal pure returns (uint160 sqrtLimit, uint24 fee, address factory) {
        uint160 defaultLimit = zeroForOne ? (uint160(1)) : (type(uint160).max - 1);
        sqrtLimit = defaultLimit;
        fee = 0;
        factory = address(0);
        if (extra.length == 0) {
            return (sqrtLimit, fee, factory);
        } else if (extra.length == 32) {
            uint256 raw256 = abi.decode(extra, (uint256));
            uint160 raw = uint160(raw256);
            sqrtLimit = _clampSqrtPriceLimit(raw);
        } else if (extra.length == 64) {
            (fee, factory) = abi.decode(extra, (uint24, address));
        } else if (extra.length == 96) {
            (sqrtLimit, fee, factory) = abi.decode(extra, (uint160, uint24, address));
            sqrtLimit = _clampSqrtPriceLimit(sqrtLimit);
        }
    }

    function _clampSqrtPriceLimit(uint160 x) internal pure returns (uint160) {
        if (x <= 1) return 1;
        if (x >= type(uint160).max) return type(uint160).max - 1;
        return x;
    }

    /**
     * @dev Uniswap V3 callback. Verifies the pool via the provided factory if
     *      one is supplied in extraData. Does not rely on a storage mapping for
     *      factory authorisation to save gas.
     */
    function uniswapV3SwapCallback(
        int256 amount0Delta,
        int256 amount1Delta,
        bytes calldata data
    ) external override {
        if (!(amount0Delta > 0 || amount1Delta > 0)) revert NO_DELTA();
        (address tokenIn, address tokenOut, uint24 fee, address factory) = abi.decode(data, (address, address, uint24, address));
        if (factory != address(0)) {
            if (!_isAllowedFactory(factory)) revert UNAUTH_FACTORY();
            address expected = IV3FactoryLike(factory).getPool(tokenIn, tokenOut, fee);
            if (expected == address(0) || msg.sender != expected) revert BAD_V3_POOL();
        } else {
            revert UNAUTH_FACTORY();
        }
        uint256 amountToPay = uint256(amount0Delta > 0 ? amount0Delta : amount1Delta);
        address t0 = IUniswapV3Pool(msg.sender).token0();
        address payToken = amount0Delta > 0 ? t0 : IUniswapV3Pool(msg.sender).token1();
        IERC20(payToken).safeTransfer(msg.sender, amountToPay);
    }

    function pancakeV3SwapCallback(
        int256 amount0Delta,
        int256 amount1Delta,
        bytes calldata data
    ) external override {
        if (!(amount0Delta > 0 || amount1Delta > 0)) revert NO_DELTA();
        (address tokenIn, address tokenOut, uint24 fee, address factory) = abi.decode(data, (address, address, uint24, address));
        if (factory != address(0)) {
            if (!_isAllowedFactory(factory)) revert UNAUTH_FACTORY();
            address expected = IV3FactoryLike(factory).getPool(tokenIn, tokenOut, fee);
            if (expected == address(0) || msg.sender != expected) revert BAD_V3_POOL();
        } else {
            revert UNAUTH_FACTORY();
        }
        uint256 amountToPay = uint256(amount0Delta > 0 ? amount0Delta : amount1Delta);
        address t0 = IUniswapV3Pool(msg.sender).token0();
        address payToken = amount0Delta > 0 ? t0 : IUniswapV3Pool(msg.sender).token1();
        IERC20(payToken).safeTransfer(msg.sender, amountToPay);
    }

    // --- V4 swap ---
    /**
     * @dev Performs a Uniswap v4 swap.  The caller must supply a PoolManager
     *      address in the SwapParams.pool field, and extraData must
     *      abi‑encode a V4SwapData struct containing the pool key and
     *      recipient.  zeroForOne comes from the top‑level SwapParams.
     */
    function _swapV4(
        address manager,
        address tokenIn,
        uint256 amountIn,
        uint256 minOut,
        bool zeroForOne,
        bytes calldata extra
    ) internal returns (uint256 amountOut) {
        require(manager == address(POOL_MANAGER), "V4_BAD_PM");
        // decode extra into V4SwapData
        V4SwapData memory v4 = abi.decode(extra, (V4SwapData));
        // build swap params: negative for exact input
        IPoolManager.SwapParams memory params;
        params.zeroForOne = zeroForOne;
        params.amountSpecified = -int256(amountIn);
        if (v4.sqrtPriceLimitX96 == 0) {
            // apply extreme limits to avoid hitting virtual range
            params.sqrtPriceLimitX96 = zeroForOne ? 1 : (type(uint160).max - 1);
        } else {
            params.sqrtPriceLimitX96 = v4.sqrtPriceLimitX96;
        }
        // step 1: sync balance for tokenIn
        POOL_MANAGER.sync(tokenIn);
        // step 2: transfer input tokens to PoolManager
        IERC20(tokenIn).safeTransfer(manager, amountIn);
        // step 3: encode data for unlock callback (minOut included for safety)
        bytes memory cbData = abi.encode(v4.key, params, v4.recipient, minOut);
        // step 4: call unlock on pool manager; returns encoded amountOut
        bytes memory result = POOL_MANAGER.unlock(cbData);
        amountOut = abi.decode(result, (uint256));
        require(amountOut >= minOut, "V4_SLIPPAGE");
    }

    /**
     * @dev V4 unlock callback.  Only the whitelisted PoolManager may call this.
     *      Performs the actual swap, settles negative deltas, withdraws
     *      positive deltas, and returns the amount out encoded in bytes.
     */
    function unlockCallback(bytes calldata data) external override returns (bytes memory) {
        require(msg.sender == address(POOL_MANAGER), "V4_ONLY_PM");
        (IPoolManager.PoolKey memory key, IPoolManager.SwapParams memory params, address recipient, uint256 minOut) = abi.decode(data, (IPoolManager.PoolKey, IPoolManager.SwapParams, address, uint256));
        // perform swap
        int256 delta = POOL_MANAGER.swap(key, params, "");
        // decode deltas
        int128 d0 = BalanceDeltaLibrary.amount0(delta);
        int128 d1 = BalanceDeltaLibrary.amount1(delta);
        // settle negative input delta
        if (d0 < 0) {
            POOL_MANAGER.settle();
        }
        uint256 amountOut;
        // withdraw positive output delta
        if (d1 > 0) {
            amountOut = uint256(int256(d1));
            // currency out is key.currency1 if zeroForOne, else key.currency0
            address currencyOut = params.zeroForOne ? key.currency1 : key.currency0;
            POOL_MANAGER.take(currencyOut, recipient, amountOut);
        }
        require(amountOut >= minOut, "V4_MIN_OUT");
        return abi.encode(amountOut);
    }

    // --- Utilities ---
    function sweep(address token, address to) external onlyOwner {
        uint256 bal = IERC20(token).balanceOf(address(this));
        IERC20(token).safeTransfer(to, bal);
    }
}"
    }
  },
  "settings": {
    "optimizer": {
      "enabled": true,
      "runs": 2000
    },
    "outputSelection": {
      "*": {
        "*": [
          "evm.bytecode",
          "evm.deployedBytecode",
          "devdoc",
          "userdoc",
          "metadata",
          "abi"
        ]
      }
    },
    "remappings": []
  }
}}

Tags:
ERC20, DeFi, Swap, Factory|addr:0x62d3f3b8b50871be7dfa75de1dcf1135a10de51e|verified:true|block:23689077|tx:0xb304502e21e04e9c8c9bcd466c8ef4ed2e679757094dd963e0fe20c4f9ae274c|first_check:1761829643

Submitted on: 2025-10-30 14:07:26

Comments

Log in to comment.

No comments yet.