ZeusRouter

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": {
    "src/ZeusRouter.sol": {
      "content": "// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.7.0 <0.9.0;

import {IWETH} from "./interfaces/IWETH.sol";
import {IUniswapV3Factory, IV4PoolManager, V4SwapParams, V4PoolKey} from "./interfaces/Uniswap.sol";
import {Swap} from "./lib/Swap.sol";
import {IPermit2} from "./interfaces/IPermit2.sol";
import {Commands} from "./lib/Commands.sol";
import {Inputs} from "./lib/Inputs.sol";
import {SafeTransferLib} from "./lib/SafeTransferLib.sol";

/*
ZZZZZZZZZZZZZZZZZZZ
Z:::::::::::::::::Z
Z:::::::::::::::::Z
Z:::ZZZZZZZZ:::::Z
ZZZZZ     Z:::::Z      eeeeeeeeeeee    uuuuuu    uuuuuu      ssssssssss
        Z:::::Z      ee::::::::::::ee  u::::u    u::::u    ss::::::::::s
       Z:::::Z      e::::::eeeee:::::eeu::::u    u::::u  ss:::::::::::::s
      Z:::::Z      e::::::e     e:::::eu::::u    u::::u  s::::::ssss:::::s
     Z:::::Z       e:::::::eeeee::::::eu::::u    u::::u   s:::::s  ssssss
    Z:::::Z        e:::::::::::::::::e u::::u    u::::u     s::::::s
   Z:::::Z         e::::::eeeeeeeeeee  u::::u    u::::u        s::::::s
ZZZ:::::Z     ZZZZZe:::::::e           u:::::uuuu:::::u  ssssss   s:::::s
Z::::::ZZZZZZZZ:::Ze::::::::e          u:::::::::::::::uus:::::ssss::::::s
Z:::::::::::::::::Z e::::::::eeeeeeee   u:::::::::::::::us::::::::::::::s
Z:::::::::::::::::Z  ee:::::::::::::e    uu::::::::uu:::u s:::::::::::ss
ZZZZZZZZZZZZZZZZZZZ    eeeeeeeeeeeeee      uuuuuuuu  uuuu  sssssssssss

Swap router contract made for Zeus
Github: https://github.com/greekfetacheese/zeus-router-v1
Main repo: https://github.com/greekfetacheese/zeus
*/

library BalanceDeltaLibrary {
    function amount0(int256 balanceDelta) internal pure returns (int128 _amount0) {
        assembly ("memory-safe") {
            _amount0 := sar(128, balanceDelta)
        }
    }

    function amount1(int256 balanceDelta) internal pure returns (int128 _amount1) {
        assembly ("memory-safe") {
            _amount1 := signextend(15, balanceDelta)
        }
    }
}

contract ZeusRouter {
    using BalanceDeltaLibrary for int256;

    address internal constant ETH = address(0);

    address public immutable WETH;
    address public immutable PERMIT2;
    address public immutable V4_POOL_MANAGER;
    address public immutable UNISWAP_V3_FACTORY;
    address public immutable PANCAKE_SWAP_V3_FACTORY;

    struct DeployParams {
        address weth;
        address permit2;
        address v4PoolManager;
        address uniswapV3Factory;
        address pancakeSwapV3Factory;
    }

    constructor(DeployParams memory params) {
        WETH = params.weth;
        PERMIT2 = params.permit2;
        V4_POOL_MANAGER = params.v4PoolManager;
        UNISWAP_V3_FACTORY = params.uniswapV3Factory;
        PANCAKE_SWAP_V3_FACTORY = params.pancakeSwapV3Factory;
    }

    function zSwap(Inputs.ZParams calldata params) public payable {
        require(params.deadline >= block.timestamp, "Deadline: Expired");

        uint256 currencyOutBalanceBefore;

        if (params.currencyOut == ETH) {
            currencyOutBalanceBefore = msg.sender.balance;
        } else {
            currencyOutBalanceBefore = SafeTransferLib.balanceOf(params.currencyOut, msg.sender);
        }

        execute(params);

        uint256 balanceAfter;
        if (params.currencyOut == ETH) {
            balanceAfter = msg.sender.balance;
        } else {
            balanceAfter = SafeTransferLib.balanceOf(params.currencyOut, msg.sender);
        }

        require(balanceAfter > currencyOutBalanceBefore, "Bad Swap: No amount received");

        uint256 realAmountOut = balanceAfter - currencyOutBalanceBefore;
        require(realAmountOut >= params.amountMin, "SlippageCheck: Insufficient output");
    }

    /// @notice Executes a series of commands with their corresponding inputs.
    function execute(Inputs.ZParams calldata swapParams) internal {
        for (uint256 i = 0; i < swapParams.commands.length; i++) {
            bytes1 command = swapParams.commands[i];
            bytes memory input = swapParams.inputs[i];

            bool isValid = command >= Commands.PERMIT2_PERMIT && command <= Commands.SWEEP;
            require(isValid, "Invalid command");

            if (command == Commands.PERMIT2_PERMIT) {
                Inputs.Permit2Permit memory params = abi.decode(input, (Inputs.Permit2Permit));
                IPermit2(PERMIT2).permit(msg.sender, params.permitSingle, params.signature);
            }

            if (command == Commands.V2_SWAP || command == Commands.V3_SWAP) {
                _swapV2V3(input);
            }

            if (command == Commands.V4_SWAP) {
                _swapV4(input);
            }

            if (command == Commands.WRAP_ETH) {
                wrapETH(input);
            }

            if (command == Commands.WRAP_ALL_ETH) {
                wrapAllETH(input);
            }

            if (command == Commands.UNWRAP_WETH) {
                unwrapWETH(input);
            }

            if (command == Commands.SWEEP) {
                sweep(input);
            }
        }
    }

    /// @notice Wraps a specified amount of contract's ETH into WETH and sends it to the recipient
    function wrapETH(bytes memory input) internal {
        Inputs.WrapETH memory params = abi.decode(input, (Inputs.WrapETH));
        IWETH(WETH).deposit{value: params.amount}();

        if (params.recipient != address(this)) {
            SafeTransferLib.safeTransfer(WETH, params.recipient, params.amount);
        }
    }

    /// @notice Wraps all contract's ETH into WETH and sends it to the recipient
    function wrapAllETH(bytes memory input) internal {
        Inputs.WrapAllETH memory params = abi.decode(input, (Inputs.WrapAllETH));
        IWETH(WETH).deposit{value: address(this).balance}();

        uint256 wethBalance = SafeTransferLib.balanceOf(WETH, address(this));

        if (params.recipient != address(this)) {
            SafeTransferLib.safeTransfer(WETH, params.recipient, wethBalance);
        }
    }

    /// @notice Unwraps all WETH from the contract and sends all the remaining ETH to the recipient
    function unwrapWETH(bytes memory input) internal {
        Inputs.UnwrapWETH memory params = abi.decode(input, (Inputs.UnwrapWETH));
        uint256 wethBalance = SafeTransferLib.balanceOf(WETH, address(this));

        IWETH(WETH).withdraw(wethBalance);

        uint256 ethBalance = address(this).balance;

        if (params.recipient != address(this)) {
            SafeTransferLib.forceSafeTransferETH(params.recipient, ethBalance);
        }
    }

    /// @notice Sweeps all of the contract's ERC20 or ETH and sends it to the recipient
    function sweep(bytes memory input) internal {
        Inputs.Sweep memory params = abi.decode(input, (Inputs.Sweep));
        uint256 balance;
        if (params.currency == ETH) {
            balance = address(this).balance;
            SafeTransferLib.forceSafeTransferETH(params.recipient, balance);
        } else {
            balance = SafeTransferLib.balanceOf(params.currency, address(this));
            SafeTransferLib.safeTransfer(params.currency, params.recipient, balance);
        }
    }

    function _swapV2V3(bytes memory input) internal {
        Inputs.V2V3SwapParams memory params = abi.decode(input, (Inputs.V2V3SwapParams));

        if (params.poolVariant == 0) {
            if (params.permit2) {
                IPermit2(PERMIT2).transferFrom(msg.sender, params.pool, uint160(params.amountIn), params.tokenIn);
            } else {
                SafeTransferLib.safeTransfer(params.tokenIn, params.pool, params.amountIn);
            }

            Swap.OnUniswapV2(params);
        } else if (params.poolVariant == 1) {
            Swap.OnUniswapV3(params, msg.sender);
        } else {
            revert("Invalid pool variant");
        }
    }

    function _swapV4(bytes memory input) internal {
        Inputs.V4SwapParams memory params = abi.decode(input, (Inputs.V4SwapParams));
        Swap.OnUniswapV4(params, msg.sender, V4_POOL_MANAGER);
    }

    /// @notice Callback for Uniswap V3 swaps.
    function uniswapV3SwapCallback(int256 amount0Delta, int256 amount1Delta, bytes calldata data) external {
        (address tokenIn, address tokenOut, uint256 amountIn, address payer, uint24 fee, bool permit2) = abi.decode(
            data,
            (address, address, uint256, address, uint24, bool)
        );
        bool zeroForOne = tokenIn < tokenOut;

        address pool = IUniswapV3Factory(UNISWAP_V3_FACTORY).getPool(tokenIn, tokenOut, fee);
        require(msg.sender == pool && pool != address(0), "UniswapV3SwapCallback: Msg.sender is not a pool");

        uint256 amountToPay = zeroForOne ? uint256(amount0Delta) : uint256(amount1Delta);
        require(amountToPay == amountIn, "UniswapV3SwapCallback: amountToPay != amountIn");

        if (permit2) {
            IPermit2(PERMIT2).transferFrom(payer, pool, uint160(amountToPay), tokenIn);
        } else {
            SafeTransferLib.safeTransfer(tokenIn, pool, amountToPay);
        }
    }

    /// @notice Callback for Pancake V3 swaps.
    function pancakeV3SwapCallback(int256 amount0Delta, int256 amount1Delta, bytes calldata data) external {
        (address tokenIn, address tokenOut, uint256 amountIn, address payer, uint24 fee, bool permit2) = abi.decode(
            data,
            (address, address, uint256, address, uint24, bool)
        );
        bool zeroForOne = tokenIn < tokenOut;

        // Verify caller is the correct pool
        address pool = IUniswapV3Factory(PANCAKE_SWAP_V3_FACTORY).getPool(tokenIn, tokenOut, fee);
        require(msg.sender == pool && pool != address(0), "PancakeV3SwapCallback: Msg.sender is not a pool");

        uint256 amountToPay = zeroForOne ? uint256(amount0Delta) : uint256(amount1Delta);
        require(amountToPay == amountIn, "PancakeV3SwapCallback: amountToPay != amountIn");

        if (permit2) {
            IPermit2(PERMIT2).transferFrom(payer, pool, uint160(amountToPay), tokenIn);
        } else {
            SafeTransferLib.safeTransfer(tokenIn, pool, amountToPay);
        }
    }

    /// @notice Callback for Uniswap V4 swaps.
    function unlockCallback(bytes calldata callbackData) public payable returns (bytes memory result) {
        require(msg.sender == V4_POOL_MANAGER, "UniswapV4SwapCallback: Msg.sender is not PoolManager");

        Swap.V4CallBackData memory data = abi.decode(callbackData, (Swap.V4CallBackData));

        (uint256 amountOut, uint256 amountToPay) = _swap(data);
        IV4PoolManager poolManager = IV4PoolManager(V4_POOL_MANAGER);

        // Settle input
        if (data.params.currencyIn == ETH) {
            poolManager.settle{value: amountToPay}();
        } else {
            if (data.params.permit2) {
                IPermit2(PERMIT2).transferFrom(
                    data.payer,
                    V4_POOL_MANAGER,
                    uint160(amountToPay),
                    data.params.currencyIn
                );
            } else {
                SafeTransferLib.safeTransfer(data.params.currencyIn, V4_POOL_MANAGER, amountToPay);
            }
            poolManager.settle();
        }

        poolManager.take(data.params.currencyOut, data.params.recipient, amountOut);

        return "";
    }

    function _swap(Swap.V4CallBackData memory data) internal returns (uint256 amountOut, uint256 amountToPay) {
        (address currency0, address currency1) = sortCurrencies(data.params.currencyIn, data.params.currencyOut);

        V4PoolKey memory poolKey = V4PoolKey(
            currency0,
            currency1,
            data.params.fee,
            data.params.tickSpacing,
            data.params.hooks
        );

        uint160 sqrtPriceLimitX96 = data.params.zeroForOne ? Swap.MIN_SQRT_RATIO : Swap.MAX_SQRT_RATIO;
        V4SwapParams memory swapParams = V4SwapParams(
            data.params.zeroForOne,
            -int256(data.params.amountIn),
            sqrtPriceLimitX96
        );

        IV4PoolManager poolManager = IV4PoolManager(V4_POOL_MANAGER);

        int256 delta = poolManager.swap(poolKey, swapParams, data.params.hookData);
        poolManager.sync(data.params.currencyIn);

        int128 inputDelta = data.params.zeroForOne ? delta.amount0() : delta.amount1();
        require(inputDelta < 0, "V4: Positive input delta");

        amountToPay = uint256(uint128(-inputDelta));
        require(amountToPay == data.params.amountIn, "V4: amountToPay != amountIn");

        int128 outputDelta = data.params.zeroForOne ? delta.amount1() : delta.amount0();
        require(outputDelta > 0, "V4: Negative output delta");

        amountOut = uint256(uint128(outputDelta));

        return (amountOut, amountToPay);
    }

    function sortCurrencies(address currencyA, address currencyB) internal pure returns (address, address) {
        if (currencyA < currencyB) {
            return (currencyA, currencyB);
        } else {
            return (currencyB, currencyA);
        }
    }

    receive() external payable {}
}
"
    },
    "src/interfaces/IWETH.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity >=0.7.0 <0.9.0;


interface IWETH {
    function deposit() external payable;
    function withdraw(uint256 amount) external;
}"
    },
    "src/interfaces/Uniswap.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity >=0.7.0 <0.9.0;

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

    function token0() external view returns (address);
    function token1() external view returns (address);
    function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
}

interface IUniswapV3Factory {
    function getPool(address tokenA, address tokenB, uint24 fee) external view returns (address pool);
}

interface IUniswapV3Pool {
    function swap(
        address recipient,
        bool zeroForOne,
        int amountSpecified,
        uint160 sqrtPriceLimitX96,
        bytes calldata data
    ) external returns (int amount0, int amount1);

    function fee() external view returns (uint24);
    function factory() external view returns (address);
}


struct V4PoolKey {
    address currency0;
    address currency1;
    uint24 fee;
    int24 tickSpacing;
    address hooks;
}

struct V4SwapParams {
    bool zeroForOne;
    int256 amountSpecified;
    uint160 sqrtPriceLimitX96;
}

interface IV4PoolManager {
    function unlock(bytes calldata data) external returns (bytes memory);
    function swap(
        V4PoolKey memory key,
        V4SwapParams memory params,
        bytes calldata hookData
    ) external returns (int256 swapDelta);
    function sync(address currency) external;
    function settle() external payable returns (uint256 paid);
    function take(address currency, address to, uint256 amount) external;
}
"
    },
    "src/lib/Swap.sol": {
      "content": "// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.7.0 <0.9.0;

import {Inputs} from "./Inputs.sol";
import {IUniswapV3Pool, IUniswapV2Pair, IV4PoolManager} from "../interfaces/Uniswap.sol";

library Swap {

    uint160 internal constant MIN_SQRT_RATIO = 4295128749;
    uint160 internal constant MAX_SQRT_RATIO = 1461446703485210103287273052203988822378723970341;

    struct V4CallBackData {
        address payer;
        Inputs.V4SwapParams params;
    }

    function OnUniswapV2(Inputs.V2V3SwapParams memory params) internal {

        uint reserveIn;
        uint reserveOut;

        {
            (uint reserve0, uint reserve1, ) = IUniswapV2Pair(params.pool).getReserves();

            // sort reserves
            if (params.tokenIn < params.tokenOut) {
                reserveIn = reserve0;
                reserveOut = reserve1;
            } else {
                reserveIn = reserve1;
                reserveOut = reserve0;
            }
        }

        uint256 amountOut = getAmountOut(params.amountIn, reserveIn, reserveOut, params.fee);

        (uint amount0Out, uint amount1Out) = params.tokenIn < params.tokenOut
            ? (uint(0), amountOut)
            : (amountOut, uint(0));

        IUniswapV2Pair(params.pool).swap(amount0Out, amount1Out, params.recipient, new bytes(0));
    }

    function OnUniswapV3(Inputs.V2V3SwapParams memory params, address payer) internal {
        bool zeroForOne = params.tokenIn < params.tokenOut;
        uint160 sqrtPriceLimitX96 = zeroForOne ? MIN_SQRT_RATIO : MAX_SQRT_RATIO;

        IUniswapV3Pool(params.pool).swap(
            params.recipient,
            zeroForOne,
            int256(params.amountIn),
            sqrtPriceLimitX96,
            abi.encode(params.tokenIn, params.tokenOut, params.amountIn, payer, params.fee, params.permit2)
        );
    }

    function OnUniswapV4(Inputs.V4SwapParams memory params, address payer, address poolManager) internal {
        V4CallBackData memory data = V4CallBackData(payer, params);
        IV4PoolManager(poolManager).unlock(abi.encode(data));
    }

    function getAmountOut(
        uint amountIn,
        uint reserveIn,
        uint reserveOut,
        uint poolfee
    ) internal pure returns (uint amountOut) {
        require(amountIn > 0, "UniswapV2Library: INSUFFICIENT_INPUT_AMOUNT");
        require(reserveIn > 0 && reserveOut > 0, "UniswapV2Library: INSUFFICIENT_LIQUIDITY");
        uint fee = (10000 - poolfee / 100) / 10;
        uint amountInWithFee = amountIn * fee;
        uint numerator = amountInWithFee * reserveOut;
        uint denominator = reserveIn * 1000 + amountInWithFee;
        amountOut = numerator / denominator;
    }
}
"
    },
    "src/interfaces/IPermit2.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IEIP712 {
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

interface IPermit2 is IEIP712 {
    /// @notice The permit data for a token
    struct PermitDetails {
        // ERC20 token address
        address token;
        // the maximum amount allowed to spend
        uint160 amount;
        // timestamp at which a spender's token allowances become invalid
        uint48 expiration;
        // an incrementing value indexed per owner,token,and spender for each signature
        uint48 nonce;
    }

    /// @notice The permit message signed for a single token allowance
    struct PermitSingle {
        // the permit data for a single token alownce
        PermitDetails details;
        // address permissioned on the allowed tokens
        address spender;
        // deadline on the permit signature
        uint256 sigDeadline;
    }

    /// @notice Permit a spender to a given amount of the owners token via the owner's EIP-712 signature
    /// @dev May fail if the owner's nonce was invalidated in-flight by invalidateNonce
    /// @param owner The owner of the tokens being approved
    /// @param permitSingle Data signed over by the owner specifying the terms of approval
    /// @param signature The owner's signature over the permit data
    function permit(address owner, PermitSingle memory permitSingle, bytes calldata signature) external;

    /// @notice Transfer approved tokens from one address to another
    /// @param from The address to transfer from
    /// @param to The address of the recipient
    /// @param amount The amount of the token to transfer
    /// @param token The token address to transfer
    /// @dev Requires the from address to have approved at least the desired amount
    /// of tokens to msg.sender.
    function transferFrom(address from, address to, uint160 amount, address token) external;
}
"
    },
    "src/lib/Commands.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity >=0.7.0 <0.9.0;

library Commands {
    bytes1 constant PERMIT2_PERMIT = 0x00;
    bytes1 constant V2_SWAP = 0x01;
    bytes1 constant V3_SWAP = 0x02;
    bytes1 constant V4_SWAP = 0x03;
    bytes1 constant WRAP_ETH = 0x04;
    bytes1 constant WRAP_ALL_ETH = 0x05;
    bytes1 constant UNWRAP_WETH = 0x06;
    bytes1 constant SWEEP = 0x07;
}
"
    },
    "src/lib/Inputs.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity >=0.7.0 <0.9.0;

import {IPermit2} from "../interfaces/IPermit2.sol";

library Inputs {
        struct ZParams {
        bytes commands;
        bytes[] inputs;
        address currencyOut;
        uint256 amountMin;
        uint256 deadline;
    }
    
    struct Permit2Permit {
        IPermit2.PermitSingle permitSingle;
        bytes signature;
    }

    /// @notice Parameters for a V2/V3 swap
    /// @param amountIn The amount of tokenIn to swap
    /// @param tokenIn The input token
    /// @param tokenOut The output token
    /// @param pool The pool to swap on
    /// @param poolVariant 0 for V2, 1 for V3
    /// @param recipient The recipient of the tokenOut
    /// @param fee The pool fee in hundredths of bips (eg. 3000 for 0.3%)
    /// @param permit2 Whether the funds should come from permit or are already in the router
    struct V2V3SwapParams {
        uint256 amountIn;
        address tokenIn;
        address tokenOut;
        address pool;
        uint poolVariant;
        address recipient;
        uint24 fee;
        bool permit2;
    }


    /// @notice Parameters for a V4 swap
    /// @param currencyIn The input currency (address(0) for ETH)
    /// @param currencyOut The output currency (address(0) for ETH)
    /// @param amountIn The amount of currencyIn to swap
    /// @param fee The pool fee in hundredths of bips (eg. 3000 for 0.3%)
    /// @param tickSpacing The tick spacing of the pool
    /// @param zeroForOne Whether the swap is from currencyIn to currencyOut
    /// @param hooks The hooks to use for the swap
    /// @param hookData The data to pass to the hooks
    /// @param recipient The recipient of the currencyOut
    /// @param permit2 Whether the funds should come from permit or are already in the router
    struct V4SwapParams {
        address currencyIn;
        address currencyOut;
        uint256 amountIn;
        uint24 fee;
        int24 tickSpacing;
        bool zeroForOne;
        address hooks;
        bytes hookData;
        address recipient;
        bool permit2;
    }

    /// @notice WrapETH
    /// @param recipient The recipient of the wrapped ETH
    /// @param amount The amount of ETH to wrap
    struct WrapETH {
        address recipient;
        uint256 amount;
    }

    /// @notice WrapAllETH
    /// @param recipient The recipient of the wrapped ETH
    struct WrapAllETH {
        address recipient;
    }
    
    /// @notice UnwrapWETH
    /// @param recipient The recipient of the unwrapped ETH
    struct UnwrapWETH {
        address recipient;
    }

    /// @notice Sweep
    /// @param currency The currency to sweep, Use address(0) for ETH
    /// @param recipient The recipient of the tokens
    struct Sweep {
        address currency;
        address recipient;
    }
}
"
    },
    "src/lib/SafeTransferLib.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity >=0.7.0 <0.9.0;

/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SafeTransferLib.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)
/// @author Permit2 operations from (https://github.com/Uniswap/permit2/blob/main/src/libraries/Permit2Lib.sol)
///
/// @dev Note:
/// - For ETH transfers, please use `forceSafeTransferETH` for DoS protection.
library SafeTransferLib {
    /// @dev Suggested gas stipend for contract receiving ETH to perform a few
    /// storage reads and writes, but low enough to prevent griefing.
    uint256 internal constant GAS_STIPEND_NO_GRIEF = 100000;

    /// @dev Sends `amount` of ERC20 `token` from `from` to `to`.
    /// Reverts upon failure.
    ///
    /// The `from` account must have at least `amount` approved for
    /// the current contract to manage.
    function safeTransferFrom(address token, address from, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x60, amount) // Store the `amount` argument.
            mstore(0x40, to) // Store the `to` argument.
            mstore(0x2c, shl(96, from)) // Store the `from` argument.
            mstore(0x0c, 0x23b872dd000000000000000000000000) // `transferFrom(address,address,uint256)`.
            let success := call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
            if iszero(and(eq(mload(0x00), 1), success)) {
                if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
                    mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
                    revert(0x1c, 0x04)
                }
            }
            mstore(0x60, 0) // Restore the zero slot to zero.
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /// @dev Force sends `amount` (in wei) ETH to `to`, with `GAS_STIPEND_NO_GRIEF`.
    function forceSafeTransferETH(address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            if lt(selfbalance(), amount) {
                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
                revert(0x1c, 0x04)
            }
            if iszero(call(GAS_STIPEND_NO_GRIEF, to, amount, codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, to) // Store the address in scratch space.
                mstore8(0x0b, 0x73) // Opcode `PUSH20`.
                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
                if iszero(create(amount, 0x0b, 0x16)) {
                    revert(codesize(), codesize())
                } // For gas estimation.
            }
        }
    }

    /// @dev Sends `amount` of ERC20 `token` from the current contract to `to`.
    /// Reverts upon failure.
    function safeTransfer(address token, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, to) // Store the `to` argument.
            mstore(0x34, amount) // Store the `amount` argument.
            mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`.
            // Perform the transfer, reverting upon failure.
            let success := call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
            if iszero(and(eq(mload(0x00), 1), success)) {
                if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
                    mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
                    revert(0x1c, 0x04)
                }
            }
            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
        }
    }

    /// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract.
    /// Reverts upon failure.
    function safeApprove(address token, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, to) // Store the `to` argument.
            mstore(0x34, amount) // Store the `amount` argument.
            mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
            let success := call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
            if iszero(and(eq(mload(0x00), 1), success)) {
                if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
                    mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`.
                    revert(0x1c, 0x04)
                }
            }
            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
        }
    }

    /// @dev Returns the amount of ERC20 `token` owned by `account`.
    /// Returns zero if the `token` does not exist.
    function balanceOf(address token, address account) internal view returns (uint256 amount) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, account) // Store the `account` argument.
            mstore(0x00, 0x70a08231000000000000000000000000) // `balanceOf(address)`.
            amount := mul(
                // The arguments of `mul` are evaluated from right to left.
                mload(0x20),
                and(
                    // The arguments of `and` are evaluated from right to left.
                    gt(returndatasize(), 0x1f), // At least 32 bytes returned.
                    staticcall(gas(), token, 0x10, 0x24, 0x20, 0x20)
                )
            )
        }
    }
}
"
    }
  },
  "settings": {
    "remappings": [
      "forge-std/=lib/forge-std/src/"
    ],
    "optimizer": {
      "enabled": true,
      "runs": 500
    },
    "metadata": {
      "useLiteralContent": false,
      "bytecodeHash": "ipfs",
      "appendCBOR": true
    },
    "outputSelection": {
      "*": {
        "*": [
          "evm.bytecode",
          "evm.deployedBytecode",
          "devdoc",
          "userdoc",
          "metadata",
          "abi"
        ]
      }
    },
    "evmVersion": "prague",
    "viaIR": true
  }
}}

Tags:
DeFi, Swap, Factory|addr:0xd8537916f38da373d4b269b53ebb20d7222ceb78|verified:true|block:23718042|tx:0xce90dccf3e1cd57064f9487941af66899e5dc25780dfc2abd8ece0e69752b33f|first_check:1762169829

Submitted on: 2025-11-03 12:37:10

Comments

Log in to comment.

No comments yet.