ETH Price: $3,110.46 (+1.19%)

Contract

0x3a63171DD9BebF4D07BC782FECC7eb0b890C2A45

Overview

ETH Balance

0 ETH

ETH Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Add Liquidity163521532025-12-10 21:10:092 days ago1765401009IN
0x3a63171D...b890C2A45
0 ETH0.000000020.00010535
Remove Liquidity163015802025-12-09 17:04:234 days ago1765299863IN
0x3a63171D...b890C2A45
0 ETH0.000000180.001
Remove Liquidity161401432025-12-05 23:23:097 days ago1764976989IN
0x3a63171D...b890C2A45
0 ETH00.00000032
Remove Liquidity161300802025-12-05 17:47:438 days ago1764956863IN
0x3a63171D...b890C2A45
0 ETH00.00000032
Remove Liquidity161092702025-12-05 6:14:038 days ago1764915243IN
0x3a63171D...b890C2A45
0 ETH00.00000032
Add Liquidity158242172025-11-28 15:52:1715 days ago1764345137IN
0x3a63171D...b890C2A45
0 ETH00.00000032
Add Liquidity158241482025-11-28 15:49:5915 days ago1764344999IN
0x3a63171D...b890C2A45
0 ETH00.00000032
Remove Liquidity158069182025-11-28 6:15:3915 days ago1764310539IN
0x3a63171D...b890C2A45
0 ETH00.00000032
Add Liquidity157856322025-11-27 18:26:0716 days ago1764267967IN
0x3a63171D...b890C2A45
0 ETH00.00000032
Add Liquidity157856262025-11-27 18:25:5516 days ago1764267955IN
0x3a63171D...b890C2A45
0 ETH00.00000032
Add Liquidity157855602025-11-27 18:23:4316 days ago1764267823IN
0x3a63171D...b890C2A45
0 ETH00.00000032
Add Liquidity157855522025-11-27 18:23:2716 days ago1764267807IN
0x3a63171D...b890C2A45
0 ETH00.00000032
Remove Liquidity157595462025-11-27 3:56:3516 days ago1764215795IN
0x3a63171D...b890C2A45
0 ETH00.00000032
Remove Liquidity157566162025-11-27 2:18:5516 days ago1764209935IN
0x3a63171D...b890C2A45
0 ETH00.0000012
Remove Liquidity157553352025-11-27 1:36:1316 days ago1764207373IN
0x3a63171D...b890C2A45
0 ETH00.00000032
Remove Liquidity157535292025-11-27 0:36:0116 days ago1764203761IN
0x3a63171D...b890C2A45
0 ETH00.00000032
Remove Liquidity157533022025-11-27 0:28:2716 days ago1764203307IN
0x3a63171D...b890C2A45
0 ETH00.00000032
Remove Liquidity157492002025-11-26 22:11:4316 days ago1764195103IN
0x3a63171D...b890C2A45
0 ETH00.00000032
Remove Liquidity157430652025-11-26 18:47:1317 days ago1764182833IN
0x3a63171D...b890C2A45
0 ETH00.00000032
Remove Liquidity157364992025-11-26 15:08:2117 days ago1764169701IN
0x3a63171D...b890C2A45
0 ETH00.00000032
Add Liquidity157364022025-11-26 15:05:0717 days ago1764169507IN
0x3a63171D...b890C2A45
0 ETH00.00000032
Add Liquidity ET...157362522025-11-26 15:00:0717 days ago1764169207IN
0x3a63171D...b890C2A45
0.0004647 ETH00.00000032
Add Liquidity ET...157362482025-11-26 14:59:5917 days ago1764169199IN
0x3a63171D...b890C2A45
0.0004647 ETH00.00000032
Remove Liquidity156882232025-11-25 12:19:0918 days ago1764073149IN
0x3a63171D...b890C2A45
0 ETH00.00000032
Remove Liquidity156873822025-11-25 11:51:0718 days ago1764071467IN
0x3a63171D...b890C2A45
0 ETH00.00000032
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block From To
163521532025-12-10 21:10:092 days ago1765401009
0x3a63171D...b890C2A45
0 ETH
163521532025-12-10 21:10:092 days ago1765401009
0x3a63171D...b890C2A45
0 ETH
163521532025-12-10 21:10:092 days ago1765401009
0x3a63171D...b890C2A45
0 ETH
163521532025-12-10 21:10:092 days ago1765401009
0x3a63171D...b890C2A45
0 ETH
163521532025-12-10 21:10:092 days ago1765401009
0x3a63171D...b890C2A45
0 ETH
163015802025-12-09 17:04:234 days ago1765299863
0x3a63171D...b890C2A45
0 ETH
163015802025-12-09 17:04:234 days ago1765299863
0x3a63171D...b890C2A45
0 ETH
161401432025-12-05 23:23:097 days ago1764976989
0x3a63171D...b890C2A45
0 ETH
161401432025-12-05 23:23:097 days ago1764976989
0x3a63171D...b890C2A45
0 ETH
161300802025-12-05 17:47:438 days ago1764956863
0x3a63171D...b890C2A45
0 ETH
161300802025-12-05 17:47:438 days ago1764956863
0x3a63171D...b890C2A45
0 ETH
161092702025-12-05 6:14:038 days ago1764915243
0x3a63171D...b890C2A45
0 ETH
161092702025-12-05 6:14:038 days ago1764915243
0x3a63171D...b890C2A45
0 ETH
158242172025-11-28 15:52:1715 days ago1764345137
0x3a63171D...b890C2A45
0 ETH
158242172025-11-28 15:52:1715 days ago1764345137
0x3a63171D...b890C2A45
0 ETH
158242172025-11-28 15:52:1715 days ago1764345137
0x3a63171D...b890C2A45
0 ETH
158241482025-11-28 15:49:5915 days ago1764344999
0x3a63171D...b890C2A45
0 ETH
158241482025-11-28 15:49:5915 days ago1764344999
0x3a63171D...b890C2A45
0 ETH
158241482025-11-28 15:49:5915 days ago1764344999
0x3a63171D...b890C2A45
0 ETH
158241482025-11-28 15:49:5915 days ago1764344999
0x3a63171D...b890C2A45
0 ETH
158241482025-11-28 15:49:5915 days ago1764344999
0x3a63171D...b890C2A45
0 ETH
158069182025-11-28 6:15:3915 days ago1764310539
0x3a63171D...b890C2A45
0 ETH
158069182025-11-28 6:15:3915 days ago1764310539
0x3a63171D...b890C2A45
0 ETH
157856322025-11-27 18:26:0716 days ago1764267967
0x3a63171D...b890C2A45
0 ETH
157856322025-11-27 18:26:0716 days ago1764267967
0x3a63171D...b890C2A45
0 ETH
View All Internal Transactions

Cross-Chain Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Router

Compiler Version
v0.8.27+commit.40a35a09

Optimization Enabled:
Yes with 200 runs

Other Settings:
cancun EvmVersion
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity >=0.8.19 <0.9.0;

import {Math} from "@openzeppelin5/contracts/utils/math/Math.sol";
import {IERC20} from "@openzeppelin5/contracts/token/ERC20/IERC20.sol";
import {Clones} from "@openzeppelin5/contracts/proxy/Clones.sol";

import {IPool} from "./interfaces/pools/IPool.sol";
import {IPoolFactory} from "./interfaces/pools/IPoolFactory.sol";
import {IRouter} from "./interfaces/IRouter.sol";
import {IWETH} from "./interfaces/external/IWETH.sol";

/*

██╗   ██╗███████╗██╗      ██████╗ ██████╗ ██████╗  ██████╗ ███╗   ███╗███████╗
██║   ██║██╔════╝██║     ██╔═══██╗██╔══██╗██╔══██╗██╔═══██╗████╗ ████║██╔════╝
██║   ██║█████╗  ██║     ██║   ██║██║  ██║██████╔╝██║   ██║██╔████╔██║█████╗  
╚██╗ ██╔╝██╔══╝  ██║     ██║   ██║██║  ██║██╔══██╗██║   ██║██║╚██╔╝██║██╔══╝  
 ╚████╔╝ ███████╗███████╗╚██████╔╝██████╔╝██║  ██║╚██████╔╝██║ ╚═╝ ██║███████╗
  ╚═══╝  ╚══════╝╚══════╝ ╚═════╝ ╚═════╝ ╚═╝  ╚═╝ ╚═════╝ ╚═╝     ╚═╝╚══════╝
                                                                              
███████╗██╗   ██╗██████╗ ███████╗██████╗  ██████╗██╗  ██╗ █████╗ ██╗███╗   ██╗
██╔════╝██║   ██║██╔══██╗██╔════╝██╔══██╗██╔════╝██║  ██║██╔══██╗██║████╗  ██║
███████╗██║   ██║██████╔╝█████╗  ██████╔╝██║     ███████║███████║██║██╔██╗ ██║
╚════██║██║   ██║██╔═══╝ ██╔══╝  ██╔══██╗██║     ██╔══██║██╔══██║██║██║╚██╗██║
███████║╚██████╔╝██║     ███████╗██║  ██║╚██████╗██║  ██║██║  ██║██║██║ ╚████║
╚══════╝ ╚═════╝ ╚═╝     ╚══════╝╚═╝  ╚═╝ ╚═════╝╚═╝  ╚═╝╚═╝  ╚═╝╚═╝╚═╝  ╚═══╝
                                                                              
██████╗  ██████╗ ██╗   ██╗████████╗███████╗██████╗                            
██╔══██╗██╔═══██╗██║   ██║╚══██╔══╝██╔════╝██╔══██╗                           
██████╔╝██║   ██║██║   ██║   ██║   █████╗  ██████╔╝                           
██╔══██╗██║   ██║██║   ██║   ██║   ██╔══╝  ██╔══██╗                           
██║  ██║╚██████╔╝╚██████╔╝   ██║   ███████╗██║  ██║                           
╚═╝  ╚═╝ ╚═════╝  ╚═════╝    ╚═╝   ╚══════╝╚═╝  ╚═╝                                                                                                         

*/

/// @title Velodrome Superchain Router
/// @author velodrome.finance, Solidly, Uniswap Labs, @pegahcarter
/// @notice Supports adding and removing liquidity from v2 pools
contract Router is IRouter {
    /// @inheritdoc IRouter
    address public immutable factory;
    /// @inheritdoc IRouter
    address public immutable poolImplementation;
    /// @inheritdoc IRouter
    IWETH public immutable weth;
    uint256 internal constant MINIMUM_LIQUIDITY = 10 ** 3;

    modifier ensure(uint256 deadline) {
        _ensureDeadline(deadline);
        _;
    }

    function _ensureDeadline(uint256 deadline) internal view {
        if (deadline < block.timestamp) revert Expired();
    }

    constructor(address _factory, address _weth) {
        factory = _factory;
        poolImplementation = IPoolFactory(_factory).implementation();
        weth = IWETH(_weth);
    }

    receive() external payable {
        if (msg.sender != address(weth)) revert OnlyWETH();
    }

    /// @inheritdoc IRouter
    function sortTokens(address tokenA, address tokenB) public pure returns (address token0, address token1) {
        if (tokenA == tokenB) revert SameAddresses();
        (token0, token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
        if (token0 == address(0)) revert ZeroAddress();
    }

    /// @inheritdoc IRouter
    function poolFor(address tokenA, address tokenB, bool stable) public view returns (address pool) {
        (address token0, address token1) = sortTokens(tokenA, tokenB);
        bytes32 salt = keccak256(abi.encodePacked(token0, token1, stable));
        pool = Clones.predictDeterministicAddress(poolImplementation, salt, factory);
    }

    /// @dev given some amount of an asset and pool reserves, returns an equivalent amount of the other asset
    /// @dev this only accounts for volatile pools and may return insufficient liquidity for stable pools
    function quoteLiquidity(uint256 amountA, uint256 reserveA, uint256 reserveB)
        internal
        pure
        returns (uint256 amountB)
    {
        if (amountA == 0) revert InsufficientAmount();
        if (reserveA == 0 || reserveB == 0) revert InsufficientLiquidity();
        amountB = (amountA * reserveB) / reserveA;
    }

    /// @inheritdoc IRouter
    function getReserves(address tokenA, address tokenB, bool stable)
        public
        view
        returns (uint256 reserveA, uint256 reserveB)
    {
        (address token0,) = sortTokens(tokenA, tokenB);
        (uint256 reserve0, uint256 reserve1,) = IPool(poolFor(tokenA, tokenB, stable)).getReserves();
        (reserveA, reserveB) = tokenA == token0 ? (reserve0, reserve1) : (reserve1, reserve0);
    }

    /// @inheritdoc IRouter
    function getAmountsOut(uint256 amountIn, Route[] memory routes) public view returns (uint256[] memory amounts) {
        if (routes.length < 1) revert InvalidPath();
        amounts = new uint256[](routes.length + 1);
        amounts[0] = amountIn;
        uint256 _length = routes.length;
        for (uint256 i = 0; i < _length; i++) {
            address pool = poolFor(routes[i].from, routes[i].to, routes[i].stable);
            if (IPoolFactory(factory).isPool(pool)) {
                amounts[i + 1] = IPool(pool).getAmountOut(amounts[i], routes[i].from);
            } else {
                revert InvalidPath();
            }
        }
    }

    /// @inheritdoc IRouter
    function quoteAddLiquidity(
        address tokenA,
        address tokenB,
        bool stable,
        uint256 amountADesired,
        uint256 amountBDesired
    ) external view returns (uint256 amountA, uint256 amountB, uint256 liquidity) {
        address _pool = IPoolFactory(factory).getPool(tokenA, tokenB, stable);
        (uint256 reserveA, uint256 reserveB) = (0, 0);
        uint256 _totalSupply = 0;
        if (_pool != address(0)) {
            _totalSupply = IERC20(_pool).totalSupply();
            (reserveA, reserveB) = getReserves(tokenA, tokenB, stable);
        }
        if (reserveA == 0 && reserveB == 0) {
            (amountA, amountB) = (amountADesired, amountBDesired);
            liquidity = Math.sqrt(amountA * amountB) - MINIMUM_LIQUIDITY;
        } else {
            uint256 amountBOptimal = quoteLiquidity(amountADesired, reserveA, reserveB);
            if (amountBOptimal <= amountBDesired) {
                (amountA, amountB) = (amountADesired, amountBOptimal);
                liquidity = Math.min((amountA * _totalSupply) / reserveA, (amountB * _totalSupply) / reserveB);
            } else {
                uint256 amountAOptimal = quoteLiquidity(amountBDesired, reserveB, reserveA);
                (amountA, amountB) = (amountAOptimal, amountBDesired);
                liquidity = Math.min((amountA * _totalSupply) / reserveA, (amountB * _totalSupply) / reserveB);
            }
        }
    }

    /// @inheritdoc IRouter
    function quoteRemoveLiquidity(address tokenA, address tokenB, bool stable, uint256 liquidity)
        external
        view
        returns (uint256 amountA, uint256 amountB)
    {
        address _pool = IPoolFactory(factory).getPool(tokenA, tokenB, stable);

        if (_pool == address(0)) {
            return (0, 0);
        }

        (uint256 reserveA, uint256 reserveB) = getReserves(tokenA, tokenB, stable);
        uint256 _totalSupply = IERC20(_pool).totalSupply();

        amountA = (liquidity * reserveA) / _totalSupply; // using balances ensures pro-rata distribution
        amountB = (liquidity * reserveB) / _totalSupply; // using balances ensures pro-rata distribution
    }

    function _addLiquidity(
        address tokenA,
        address tokenB,
        bool stable,
        uint256 amountADesired,
        uint256 amountBDesired,
        uint256 amountAMin,
        uint256 amountBMin
    ) internal returns (uint256 amountA, uint256 amountB) {
        if (amountADesired < amountAMin) revert InsufficientAmountADesired();
        if (amountBDesired < amountBMin) revert InsufficientAmountBDesired();
        // create the pool if it doesn't exist yet
        address _pool = IPoolFactory(factory).getPool(tokenA, tokenB, stable);
        if (_pool == address(0)) {
            _pool = IPoolFactory(factory).createPool(tokenA, tokenB, stable);
        }
        (uint256 reserveA, uint256 reserveB) = getReserves(tokenA, tokenB, stable);
        if (reserveA == 0 && reserveB == 0) {
            (amountA, amountB) = (amountADesired, amountBDesired);
        } else {
            uint256 amountBOptimal = quoteLiquidity(amountADesired, reserveA, reserveB);
            if (amountBOptimal <= amountBDesired) {
                if (amountBOptimal < amountBMin) revert InsufficientAmountB();
                (amountA, amountB) = (amountADesired, amountBOptimal);
            } else {
                uint256 amountAOptimal = quoteLiquidity(amountBDesired, reserveB, reserveA);
                assert(amountAOptimal <= amountADesired);
                if (amountAOptimal < amountAMin) revert InsufficientAmountA();
                (amountA, amountB) = (amountAOptimal, amountBDesired);
            }
        }
    }

    /// @inheritdoc IRouter
    function addLiquidity(
        address tokenA,
        address tokenB,
        bool stable,
        uint256 amountADesired,
        uint256 amountBDesired,
        uint256 amountAMin,
        uint256 amountBMin,
        address to,
        uint256 deadline
    ) external ensure(deadline) returns (uint256 amountA, uint256 amountB, uint256 liquidity) {
        (amountA, amountB) =
            _addLiquidity(tokenA, tokenB, stable, amountADesired, amountBDesired, amountAMin, amountBMin);
        address pool = poolFor(tokenA, tokenB, stable);
        _safeTransferFrom(tokenA, msg.sender, pool, amountA);
        _safeTransferFrom(tokenB, msg.sender, pool, amountB);
        liquidity = IPool(pool).mint(to);
    }

    /// @inheritdoc IRouter
    function addLiquidityETH(
        address token,
        bool stable,
        uint256 amountTokenDesired,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline
    ) external payable ensure(deadline) returns (uint256 amountToken, uint256 amountETH, uint256 liquidity) {
        (amountToken, amountETH) =
            _addLiquidity(token, address(weth), stable, amountTokenDesired, msg.value, amountTokenMin, amountETHMin);
        address pool = poolFor(token, address(weth), stable);
        _safeTransferFrom(token, msg.sender, pool, amountToken);
        weth.deposit{value: amountETH}();
        assert(weth.transfer(pool, amountETH));
        liquidity = IPool(pool).mint(to);
        // refund dust eth, if any
        if (msg.value > amountETH) _safeTransferETH(msg.sender, msg.value - amountETH);
    }

    // **** REMOVE LIQUIDITY ****

    /// @inheritdoc IRouter
    function removeLiquidity(
        address tokenA,
        address tokenB,
        bool stable,
        uint256 liquidity,
        uint256 amountAMin,
        uint256 amountBMin,
        address to,
        uint256 deadline
    ) public ensure(deadline) returns (uint256 amountA, uint256 amountB) {
        address pool = poolFor(tokenA, tokenB, stable);
        _safeTransferFrom(pool, msg.sender, pool, liquidity);
        (uint256 amount0, uint256 amount1) = IPool(pool).burn(to);
        (address token0,) = sortTokens(tokenA, tokenB);
        (amountA, amountB) = tokenA == token0 ? (amount0, amount1) : (amount1, amount0);
        if (amountA < amountAMin) revert InsufficientAmountA();
        if (amountB < amountBMin) revert InsufficientAmountB();
    }

    /// @inheritdoc IRouter
    function removeLiquidityETH(
        address token,
        bool stable,
        uint256 liquidity,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline
    ) external ensure(deadline) returns (uint256 amountToken, uint256 amountETH) {
        (amountToken, amountETH) = removeLiquidity(
            token, address(weth), stable, liquidity, amountTokenMin, amountETHMin, address(this), deadline
        );
        _safeTransfer(token, to, amountToken);
        weth.withdraw(amountETH);
        _safeTransferETH(to, amountETH);
    }

    // **** SWAP ****
    /// @dev requires the initial amount to have already been sent to the first pool
    function _swap(uint256[] memory amounts, Route[] memory routes, address _to) internal virtual {
        uint256 _length = routes.length;
        for (uint256 i = 0; i < _length; i++) {
            (address token0,) = sortTokens(routes[i].from, routes[i].to);
            uint256 amountOut = amounts[i + 1];
            (uint256 amount0Out, uint256 amount1Out) =
                routes[i].from == token0 ? (uint256(0), amountOut) : (amountOut, uint256(0));
            address to =
                i < routes.length - 1 ? poolFor(routes[i + 1].from, routes[i + 1].to, routes[i + 1].stable) : _to;
            IPool(poolFor(routes[i].from, routes[i].to, routes[i].stable)).swap(
                amount0Out, amount1Out, to, new bytes(0)
            );
        }
    }

    /// @inheritdoc IRouter
    function swapExactTokensForTokens(
        uint256 amountIn,
        uint256 amountOutMin,
        Route[] calldata routes,
        address to,
        uint256 deadline
    ) external ensure(deadline) returns (uint256[] memory amounts) {
        amounts = getAmountsOut(amountIn, routes);
        if (amounts[amounts.length - 1] < amountOutMin) revert InsufficientOutputAmount();
        _safeTransferFrom(
            routes[0].from, msg.sender, poolFor(routes[0].from, routes[0].to, routes[0].stable), amounts[0]
        );
        _swap(amounts, routes, to);
    }

    /// @inheritdoc IRouter
    function swapExactETHForTokens(uint256 amountOutMin, Route[] calldata routes, address to, uint256 deadline)
        external
        payable
        ensure(deadline)
        returns (uint256[] memory amounts)
    {
        if (routes[0].from != address(weth)) revert InvalidPath();
        amounts = getAmountsOut(msg.value, routes);
        if (amounts[amounts.length - 1] < amountOutMin) revert InsufficientOutputAmount();
        weth.deposit{value: amounts[0]}();
        assert(weth.transfer(poolFor(routes[0].from, routes[0].to, routes[0].stable), amounts[0]));
        _swap(amounts, routes, to);
    }

    /// @inheritdoc IRouter
    function swapExactTokensForETH(
        uint256 amountIn,
        uint256 amountOutMin,
        Route[] calldata routes,
        address to,
        uint256 deadline
    ) external ensure(deadline) returns (uint256[] memory amounts) {
        if (routes[routes.length - 1].to != address(weth)) revert InvalidPath();
        amounts = getAmountsOut(amountIn, routes);
        if (amounts[amounts.length - 1] < amountOutMin) revert InsufficientOutputAmount();
        _safeTransferFrom(
            routes[0].from, msg.sender, poolFor(routes[0].from, routes[0].to, routes[0].stable), amounts[0]
        );
        _swap(amounts, routes, address(this));
        weth.withdraw(amounts[amounts.length - 1]);
        _safeTransferETH(to, amounts[amounts.length - 1]);
    }

    // **** REMOVE LIQUIDITY (supporting fee-on-transfer tokens) ****
    function removeLiquidityETHSupportingFeeOnTransferTokens(
        address token,
        bool stable,
        uint256 liquidity,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline
    ) public ensure(deadline) returns (uint256 amountETH) {
        (, amountETH) = removeLiquidity(
            token, address(weth), stable, liquidity, amountTokenMin, amountETHMin, address(this), deadline
        );
        _safeTransfer(token, to, IERC20(token).balanceOf(address(this)));
        weth.withdraw(amountETH);
        _safeTransferETH(to, amountETH);
    }

    function _safeTransferETH(address to, uint256 value) internal {
        (bool success,) = to.call{value: value}(new bytes(0));
        if (!success) revert ETHTransferFailed();
    }

    function _safeTransfer(address token, address to, uint256 value) internal {
        require(token.code.length > 0);
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.transfer.selector, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))));
    }

    function _safeTransferFrom(address token, address from, address to, uint256 value) internal {
        require(token.code.length > 0);
        (bool success, bytes memory data) =
            token.call(abi.encodeWithSelector(IERC20.transferFrom.selector, from, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))));
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)

pragma solidity ^0.8.20;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    /**
     * @dev Muldiv operation overflow.
     */
    error MathOverflowedMulDiv();

    enum Rounding {
        Floor, // Toward negative infinity
        Ceil, // Toward positive infinity
        Trunc, // Toward zero
        Expand // Away from zero
    }

    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            uint256 c = a + b;
            if (c < a) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, with an overflow flag.
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b > a) return (false, 0);
            return (true, a - b);
        }
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
            // benefit is lost if 'b' is also tested.
            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
            if (a == 0) return (true, 0);
            uint256 c = a * b;
            if (c / a != b) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a / b);
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a % b);
        }
    }

    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow.
        return (a & b) + (a ^ b) / 2;
    }

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds towards infinity instead
     * of rounding towards zero.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        if (b == 0) {
            // Guarantee the same behavior as in a regular Solidity division.
            return a / b;
        }

        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a == 0 ? 0 : (a - 1) / b + 1;
    }

    /**
     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
     * denominator == 0.
     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
     * Uniswap Labs also under MIT license.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
        unchecked {
            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
            // variables such that product = prod1 * 2^256 + prod0.
            uint256 prod0 = x * y; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly {
                let mm := mulmod(x, y, not(0))
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Handle non-overflow cases, 256 by 256 division.
            if (prod1 == 0) {
                // Solidity will revert if denominator == 0, unlike the div opcode on its own.
                // The surrounding unchecked block does not change this fact.
                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
                return prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            if (denominator <= prod1) {
                revert MathOverflowedMulDiv();
            }

            ///////////////////////////////////////////////
            // 512 by 256 division.
            ///////////////////////////////////////////////

            // Make division exact by subtracting the remainder from [prod1 prod0].
            uint256 remainder;
            assembly {
                // Compute remainder using mulmod.
                remainder := mulmod(x, y, denominator)

                // Subtract 256 bit number from 512 bit number.
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator and compute largest power of two divisor of denominator.
            // Always >= 1. See https://cs.stackexchange.com/q/138556/92363.

            uint256 twos = denominator & (0 - denominator);
            assembly {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

                // Divide [prod1 prod0] by twos.
                prod0 := div(prod0, twos)

                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                twos := add(div(sub(0, twos), twos), 1)
            }

            // Shift in bits from prod1 into prod0.
            prod0 |= prod1 * twos;

            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
            // four bits. That is, denominator * inv = 1 mod 2^4.
            uint256 inverse = (3 * denominator) ^ 2;

            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
            // works in modular arithmetic, doubling the correct bits in each step.
            inverse *= 2 - denominator * inverse; // inverse mod 2^8
            inverse *= 2 - denominator * inverse; // inverse mod 2^16
            inverse *= 2 - denominator * inverse; // inverse mod 2^32
            inverse *= 2 - denominator * inverse; // inverse mod 2^64
            inverse *= 2 - denominator * inverse; // inverse mod 2^128
            inverse *= 2 - denominator * inverse; // inverse mod 2^256

            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
            // is no longer required.
            result = prod0 * inverse;
            return result;
        }
    }

    /**
     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
        uint256 result = mulDiv(x, y, denominator);
        if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) {
            result += 1;
        }
        return result;
    }

    /**
     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
     * towards zero.
     *
     * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
     */
    function sqrt(uint256 a) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
        //
        // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
        //
        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
        //
        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
        uint256 result = 1 << (log2(a) >> 1);

        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
        // into the expected uint128 result.
        unchecked {
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            return min(result, a / result);
        }
    }

    /**
     * @notice Calculates sqrt(a), following the selected rounding direction.
     */
    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = sqrt(a);
            return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 2 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     */
    function log2(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 128;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 64;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 32;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 16;
            }
            if (value >> 8 > 0) {
                value >>= 8;
                result += 8;
            }
            if (value >> 4 > 0) {
                value >>= 4;
                result += 4;
            }
            if (value >> 2 > 0) {
                value >>= 2;
                result += 2;
            }
            if (value >> 1 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log2(value);
            return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 10 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     */
    function log10(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >= 10 ** 64) {
                value /= 10 ** 64;
                result += 64;
            }
            if (value >= 10 ** 32) {
                value /= 10 ** 32;
                result += 32;
            }
            if (value >= 10 ** 16) {
                value /= 10 ** 16;
                result += 16;
            }
            if (value >= 10 ** 8) {
                value /= 10 ** 8;
                result += 8;
            }
            if (value >= 10 ** 4) {
                value /= 10 ** 4;
                result += 4;
            }
            if (value >= 10 ** 2) {
                value /= 10 ** 2;
                result += 2;
            }
            if (value >= 10 ** 1) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log10(value);
            return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 256 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     *
     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
     */
    function log256(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 16;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 8;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 4;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 2;
            }
            if (value >> 8 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 256, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log256(value);
            return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
        }
    }

    /**
     * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
     */
    function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
        return uint8(rounding) % 2 == 1;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the value of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the value of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 value) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the
     * allowance mechanism. `value` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 value) external returns (bool);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/Clones.sol)

pragma solidity ^0.8.20;

/**
 * @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for
 * deploying minimal proxy contracts, also known as "clones".
 *
 * > To simply and cheaply clone contract functionality in an immutable way, this standard specifies
 * > a minimal bytecode implementation that delegates all calls to a known, fixed address.
 *
 * The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`
 * (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the
 * deterministic method.
 */
library Clones {
    /**
     * @dev A clone instance deployment failed.
     */
    error ERC1167FailedCreateClone();

    /**
     * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
     *
     * This function uses the create opcode, which should never revert.
     */
    function clone(address implementation) internal returns (address instance) {
        /// @solidity memory-safe-assembly
        assembly {
            // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes
            // of the `implementation` address with the bytecode before the address.
            mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
            // Packs the remaining 17 bytes of `implementation` with the bytecode after the address.
            mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))
            instance := create(0, 0x09, 0x37)
        }
        if (instance == address(0)) {
            revert ERC1167FailedCreateClone();
        }
    }

    /**
     * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
     *
     * This function uses the create2 opcode and a `salt` to deterministically deploy
     * the clone. Using the same `implementation` and `salt` multiple time will revert, since
     * the clones cannot be deployed twice at the same address.
     */
    function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {
        /// @solidity memory-safe-assembly
        assembly {
            // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes
            // of the `implementation` address with the bytecode before the address.
            mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
            // Packs the remaining 17 bytes of `implementation` with the bytecode after the address.
            mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))
            instance := create2(0, 0x09, 0x37, salt)
        }
        if (instance == address(0)) {
            revert ERC1167FailedCreateClone();
        }
    }

    /**
     * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
     */
    function predictDeterministicAddress(
        address implementation,
        bytes32 salt,
        address deployer
    ) internal pure returns (address predicted) {
        /// @solidity memory-safe-assembly
        assembly {
            let ptr := mload(0x40)
            mstore(add(ptr, 0x38), deployer)
            mstore(add(ptr, 0x24), 0x5af43d82803e903d91602b57fd5bf3ff)
            mstore(add(ptr, 0x14), implementation)
            mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73)
            mstore(add(ptr, 0x58), salt)
            mstore(add(ptr, 0x78), keccak256(add(ptr, 0x0c), 0x37))
            predicted := keccak256(add(ptr, 0x43), 0x55)
        }
    }

    /**
     * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
     */
    function predictDeterministicAddress(
        address implementation,
        bytes32 salt
    ) internal view returns (address predicted) {
        return predictDeterministicAddress(implementation, salt, address(this));
    }
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IPool {
    error DepositsNotEqual();
    error BelowMinimumK();
    error FactoryAlreadySet();
    error InsufficientLiquidity();
    error InsufficientLiquidityMinted();
    error InsufficientLiquidityBurned();
    error InsufficientOutputAmount();
    error InsufficientInputAmount();
    error IsPaused();
    error InvalidTo();
    error K();

    event Fees(address indexed sender, uint256 amount0, uint256 amount1);
    event Mint(address indexed sender, address indexed to, uint256 amount0, uint256 amount1);
    event Burn(address indexed sender, address indexed to, uint256 amount0, uint256 amount1);
    event Swap(
        address indexed sender,
        address indexed to,
        uint256 amount0In,
        uint256 amount1In,
        uint256 amount0Out,
        uint256 amount1Out
    );
    event Sync(uint256 reserve0, uint256 reserve1);
    event Claim(address indexed sender, address indexed recipient, uint256 amount0, uint256 amount1);

    // Struct to capture time period obervations every 30 minutes, used for local oracles
    struct Observation {
        uint256 timestamp;
        uint256 reserve0Cumulative;
        uint256 reserve1Cumulative;
    }

    /// @notice Returns the decimal (dec), reserves (r), stable (st), and tokens (t) of token0 and token1
    function metadata()
        external
        view
        returns (uint256 dec0, uint256 dec1, uint256 r0, uint256 r1, bool st, address t0, address t1);

    /// @notice Claim accumulated but unclaimed fees (claimable0 and claimable1)
    function claimFees() external returns (uint256, uint256);

    /// @notice Returns [token0, token1]
    function tokens() external view returns (address, address);

    /// @notice Address of token in the pool with the lower address value
    function token0() external view returns (address);

    /// @notice Address of token in the pool with the higher address value
    function token1() external view returns (address);

    /// @notice Address of linked PoolFees.sol
    function poolFees() external view returns (address);

    /// @notice Address of PoolFactory that created this contract
    function factory() external view returns (address);

    /// @notice Capture oracle reading every 30 minutes (1800 seconds)
    function periodSize() external view returns (uint256);

    /// @notice Amount of token0 in pool
    function reserve0() external view returns (uint256);

    /// @notice Amount of token1 in pool
    function reserve1() external view returns (uint256);

    /// @notice Timestamp of last update to pool
    function blockTimestampLast() external view returns (uint256);

    /// @notice Cumulative of reserve0 factoring in time elapsed
    function reserve0CumulativeLast() external view returns (uint256);

    /// @notice Cumulative of reserve1 factoring in time elapsed
    function reserve1CumulativeLast() external view returns (uint256);

    /// @notice Accumulated fees of token0 (global)
    function index0() external view returns (uint256);

    /// @notice Accumulated fees of token1 (global)
    function index1() external view returns (uint256);

    /// @notice Get an LP's relative index0 to index0
    function supplyIndex0(address) external view returns (uint256);

    /// @notice Get an LP's relative index1 to index1
    function supplyIndex1(address) external view returns (uint256);

    /// @notice Amount of unclaimed, but claimable tokens from fees of token0 for an LP
    function claimable0(address) external view returns (uint256);

    /// @notice Amount of unclaimed, but claimable tokens from fees of token1 for an LP
    function claimable1(address) external view returns (uint256);

    /// @notice Returns the value of K in the Pool, based on its reserves.
    function getK() external returns (uint256);

    /// @notice Set pool name
    ///         Only callable by Voter.emergencyCouncil()
    /// @param __name String of new name
    function setName(string calldata __name) external;

    /// @notice Set pool symbol
    ///         Only callable by Voter.emergencyCouncil()
    /// @param __symbol String of new symbol
    function setSymbol(string calldata __symbol) external;

    /// @notice Get the number of observations recorded
    function observationLength() external view returns (uint256);

    /// @notice Get the value of the most recent observation
    function lastObservation() external view returns (Observation memory);

    /// @notice True if pool is stable, false if volatile
    function stable() external view returns (bool);

    /// @notice Produces the cumulative price using counterfactuals to save gas and avoid a call to sync.
    function currentCumulativePrices()
        external
        view
        returns (uint256 reserve0Cumulative, uint256 reserve1Cumulative, uint256 blockTimestamp);

    /// @notice Provides twap price with user configured granularity, up to the full window size
    /// @param tokenIn .
    /// @param amountIn .
    /// @param granularity .
    /// @return amountOut .
    function quote(address tokenIn, uint256 amountIn, uint256 granularity) external view returns (uint256 amountOut);

    /// @notice Returns a memory set of TWAP prices
    ///         Same as calling sample(tokenIn, amountIn, points, 1)
    /// @param tokenIn .
    /// @param amountIn .
    /// @param points Number of points to return
    /// @return Array of TWAP prices
    function prices(address tokenIn, uint256 amountIn, uint256 points) external view returns (uint256[] memory);

    /// @notice Same as prices with with an additional window argument.
    ///         Window = 2 means 2 * 30min (or 1 hr) between observations
    /// @param tokenIn .
    /// @param amountIn .
    /// @param points .
    /// @param window .
    /// @return Array of TWAP prices
    function sample(address tokenIn, uint256 amountIn, uint256 points, uint256 window)
        external
        view
        returns (uint256[] memory);

    /// @notice This low-level function should be called from a contract which performs important safety checks
    /// @param amount0Out   Amount of token0 to send to `to`
    /// @param amount1Out   Amount of token1 to send to `to`
    /// @param to           Address to recieve the swapped output
    /// @param data         Additional calldata for flashloans
    function swap(uint256 amount0Out, uint256 amount1Out, address to, bytes calldata data) external;

    /// @notice This low-level function should be called from a contract which performs important safety checks
    ///         standard uniswap v2 implementation
    /// @param to Address to receive token0 and token1 from burning the pool token
    /// @return amount0 Amount of token0 returned
    /// @return amount1 Amount of token1 returned
    function burn(address to) external returns (uint256 amount0, uint256 amount1);

    /// @notice This low-level function should be called by addLiquidity functions in Router.sol, which performs important safety checks
    ///         standard uniswap v2 implementation
    /// @param to           Address to receive the minted LP token
    /// @return liquidity   Amount of LP token minted
    function mint(address to) external returns (uint256 liquidity);

    /// @notice Update reserves and, on the first call per block, price accumulators
    /// @return _reserve0 .
    /// @return _reserve1 .
    /// @return _blockTimestampLast .
    function getReserves() external view returns (uint256 _reserve0, uint256 _reserve1, uint256 _blockTimestampLast);

    /// @notice Get the amount of tokenOut given the amount of tokenIn
    /// @param amountIn Amount of token in
    /// @param tokenIn  Address of token
    /// @return Amount out
    function getAmountOut(uint256 amountIn, address tokenIn) external view returns (uint256);

    /// @notice Force balances to match reserves
    /// @param to Address to receive any skimmed rewards
    function skim(address to) external;

    /// @notice Force reserves to match balances
    function sync() external;

    /// @notice Called on pool creation by PoolFactory
    /// @param _token0 Address of token0
    /// @param _token1 Address of token1
    /// @param _stable True if stable, false if volatile
    function initialize(address _token0, address _token1, bool _stable) external;
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IPoolFactory {
    event SetFeeManager(address indexed feeManager);
    event SetPauser(address indexed pauser);
    event SetPauseState(bool indexed state);
    event SetPoolAdmin(address indexed poolAdmin);
    event PoolCreated(address indexed token0, address indexed token1, bool indexed stable, address pool, uint256);
    event SetDefaultFee(bool indexed stable, uint256 fee);
    event FeeModuleChanged(address indexed oldFeeModule, address indexed newFeeModule);

    error FeeInvalid();
    error FeeTooHigh();
    error NotFeeManager();
    error NotPauser();
    error NotPoolAdmin();
    error PoolAlreadyExists();
    error SameAddress();
    error ZeroFee();
    error ZeroAddress();

    /// @notice Return a single pool created by this factory
    /// @return Address of pool
    function allPools(uint256 index) external view returns (address);

    /// @notice Returns all pools created by this factory
    /// @return Array of pool addresses
    function allPools() external view returns (address[] memory);

    /// @notice returns the number of pools created from this factory
    function allPoolsLength() external view returns (uint256);

    /// @notice Is a valid pool created by this factory.
    /// @param .
    function isPool(address pool) external view returns (bool);

    /// @notice Return address of pool created by this factory
    /// @param tokenA .
    /// @param tokenB .
    /// @param stable True if stable, false if volatile
    function getPool(address tokenA, address tokenB, bool stable) external view returns (address);

    /// @notice Support for v3-style pools which wraps around getPool(tokenA,tokenB,stable)
    /// @dev fee is converted to stable boolean.
    /// @param tokenA .
    /// @param tokenB .
    /// @param fee  1 if stable, 0 if volatile, else returns address(0)
    function getPool(address tokenA, address tokenB, uint24 fee) external view returns (address);

    /// @notice Set pool administrator
    /// @dev Allowed to change the name and symbol of any pool created by this factory
    /// @param _poolAdmin Address of the pool administrator
    function setPoolAdmin(address _poolAdmin) external;

    /// @notice Set the pauser for the factory contract
    /// @dev The pauser can pause swaps on pools associated with the factory. Liquidity will always be withdrawable.
    /// @dev Must be called by the pauser
    /// @param _pauser Address of the pauser
    function setPauser(address _pauser) external;

    /// @notice Pause or unpause swaps on pools associated with the factory
    /// @param _state True to pause, false to unpause
    function setPauseState(bool _state) external;

    /// @notice Set the fee manager for the factory contract
    /// @dev The fee manager can set fees on pools associated with the factory.
    /// @dev Must be called by the fee manager
    /// @param _feeManager Address of the fee manager
    function setFeeManager(address _feeManager) external;

    /// @notice Updates the feeModule of the factory
    /// @dev Must be called by the current fee manager
    /// @param _feeModule The new feeModule of the factory
    function setFeeModule(address _feeModule) external;

    /// @notice Set default fee for stable and volatile pools.
    /// @dev Throws if higher than maximum fee.
    ///      Throws if fee is zero.
    /// @param _stable Stable or volatile pool.
    /// @param _fee .
    function setFee(bool _stable, uint256 _fee) external;

    /// @notice Returns fee for a pool, as custom fees are possible.
    function getFee(address _pool, bool _stable) external view returns (uint256);

    /// @notice Create a pool given two tokens and if they're stable/volatile
    /// @dev token order does not matter
    /// @param tokenA .
    /// @param tokenB .
    /// @param stable .
    function createPool(address tokenA, address tokenB, bool stable) external returns (address pool);

    /// @notice Support for v3-style pools which wraps around createPool(tokenA,tokenB,stable)
    /// @dev fee is converted to stable boolean
    /// @dev token order does not matter
    /// @param tokenA .
    /// @param tokenB .
    /// @param fee 1 if stable, 0 if volatile, else revert
    function createPool(address tokenA, address tokenB, uint24 fee) external returns (address pool);

    /// @notice The pool implementation used to create pools
    /// @return Address of pool implementation
    function implementation() external view returns (address);

    /// @notice Whether the pools associated with the factory are paused or not.
    /// @dev Pause only pauses swaps, liquidity will always be withdrawable.
    function isPaused() external view returns (bool);

    /// @notice The address of the pauser, can pause swaps on pools associated with factory.
    /// @return Address of the pauser
    function pauser() external view returns (address);

    /// @notice The default fee for all stable pools
    /// @return Default stable fee
    function stableFee() external view returns (uint256);

    /// @notice The default fee for all volatile pools
    /// @return Default volatile fee
    function volatileFee() external view returns (uint256);

    /// @notice Maximum possible fee for default stable or volatile fee
    /// @return 3%
    function MAX_FEE() external view returns (uint256);

    /// @notice Address of the fee manager, can set fees on pools associated with factory.
    /// @notice This overrides the default fee for that pool.
    /// @return Address of the fee manager
    function feeManager() external view returns (address);

    /// @notice Address of the fee module of the factory
    /// @dev Can be changed by the current fee manager via setFeeModule
    /// @return Address of the fee module
    function feeModule() external view returns (address);

    /// @notice Address of the pool administrator, can change the name and symbol of pools created by factory.
    /// @return Address of the pool administrator
    function poolAdmin() external view returns (address);
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {IWETH} from "./external/IWETH.sol";

interface IRouter {
    struct Route {
        address from;
        address to;
        bool stable;
    }

    error ETHTransferFailed();
    error Expired();
    error InsufficientAmount();
    error InsufficientAmountA();
    error InsufficientAmountB();
    error InsufficientAmountADesired();
    error InsufficientAmountBDesired();
    error InsufficientLiquidity();
    error InsufficientOutputAmount();
    error InvalidPath();
    error OnlyWETH();
    error SameAddresses();
    error ZeroAddress();

    /// @notice Address of Velodrome v2 pool factory
    function factory() external view returns (address);

    /// @notice Address of Velodrome v2 pool implementation
    function poolImplementation() external view returns (address);

    /// @notice Interface of WETH contract used for WETH => ETH wrapping/unwrapping
    function weth() external view returns (IWETH);

    /// @notice Sort two tokens by which address value is less than the other
    /// @param tokenA   Address of token to sort
    /// @param tokenB   Address of token to sort
    /// @return token0  Lower address value between tokenA and tokenB
    /// @return token1  Higher address value between tokenA and tokenB
    function sortTokens(address tokenA, address tokenB) external pure returns (address token0, address token1);

    /// @notice Calculate the address of a pool by its' factory.
    /// @dev Returns a randomly generated address for a nonexistent pool
    /// @param tokenA   Address of token to query
    /// @param tokenB   Address of token to query
    /// @param stable   True if pool is stable, false if volatile
    function poolFor(address tokenA, address tokenB, bool stable) external view returns (address pool);

    /// @notice Fetch and sort the reserves for a pool
    /// @param tokenA       .
    /// @param tokenB       .
    /// @param stable       True if pool is stable, false if volatile
    /// @return reserveA    Amount of reserves of the sorted token A
    /// @return reserveB    Amount of reserves of the sorted token B
    function getReserves(address tokenA, address tokenB, bool stable)
        external
        view
        returns (uint256 reserveA, uint256 reserveB);

    /// @notice Perform chained getAmountOut calculations on any number of pools
    function getAmountsOut(uint256 amountIn, Route[] memory routes) external view returns (uint256[] memory amounts);

    // **** ADD LIQUIDITY ****

    /// @notice Quote the amount deposited into a Pool
    /// @param tokenA           .
    /// @param tokenB           .
    /// @param stable           True if pool is stable, false if volatile
    /// @param amountADesired   Amount of tokenA desired to deposit
    /// @param amountBDesired   Amount of tokenB desired to deposit
    /// @return amountA         Amount of tokenA to actually deposit
    /// @return amountB         Amount of tokenB to actually deposit
    /// @return liquidity       Amount of liquidity token returned from deposit
    function quoteAddLiquidity(
        address tokenA,
        address tokenB,
        bool stable,
        uint256 amountADesired,
        uint256 amountBDesired
    ) external view returns (uint256 amountA, uint256 amountB, uint256 liquidity);

    /// @notice Quote the amount of liquidity removed from a Pool
    /// @param tokenA       .
    /// @param tokenB       .
    /// @param stable       True if pool is stable, false if volatile
    /// @param liquidity    Amount of liquidity to remove
    /// @return amountA     Amount of tokenA received
    /// @return amountB     Amount of tokenB received
    function quoteRemoveLiquidity(address tokenA, address tokenB, bool stable, uint256 liquidity)
        external
        view
        returns (uint256 amountA, uint256 amountB);

    /// @notice Add liquidity of two tokens to a Pool
    /// @param tokenA           .
    /// @param tokenB           .
    /// @param stable           True if pool is stable, false if volatile
    /// @param amountADesired   Amount of tokenA desired to deposit
    /// @param amountBDesired   Amount of tokenB desired to deposit
    /// @param amountAMin       Minimum amount of tokenA to deposit
    /// @param amountBMin       Minimum amount of tokenB to deposit
    /// @param to               Recipient of liquidity token
    /// @param deadline         Deadline to receive liquidity
    /// @return amountA         Amount of tokenA to actually deposit
    /// @return amountB         Amount of tokenB to actually deposit
    /// @return liquidity       Amount of liquidity token returned from deposit
    function addLiquidity(
        address tokenA,
        address tokenB,
        bool stable,
        uint256 amountADesired,
        uint256 amountBDesired,
        uint256 amountAMin,
        uint256 amountBMin,
        address to,
        uint256 deadline
    ) external returns (uint256 amountA, uint256 amountB, uint256 liquidity);

    /// @notice Add liquidity of a token and WETH (transferred as ETH) to a Pool
    /// @param token                .
    /// @param stable               True if pool is stable, false if volatile
    /// @param amountTokenDesired   Amount of token desired to deposit
    /// @param amountTokenMin       Minimum amount of token to deposit
    /// @param amountETHMin         Minimum amount of ETH to deposit
    /// @param to                   Recipient of liquidity token
    /// @param deadline             Deadline to add liquidity
    /// @return amountToken         Amount of token to actually deposit
    /// @return amountETH           Amount of tokenETH to actually deposit
    /// @return liquidity           Amount of liquidity token returned from deposit
    function addLiquidityETH(
        address token,
        bool stable,
        uint256 amountTokenDesired,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline
    ) external payable returns (uint256 amountToken, uint256 amountETH, uint256 liquidity);

    // **** REMOVE LIQUIDITY ****

    /// @notice Remove liquidity of two tokens from a Pool
    /// @param tokenA       .
    /// @param tokenB       .
    /// @param stable       True if pool is stable, false if volatile
    /// @param liquidity    Amount of liquidity to remove
    /// @param amountAMin   Minimum amount of tokenA to receive
    /// @param amountBMin   Minimum amount of tokenB to receive
    /// @param to           Recipient of tokens received
    /// @param deadline     Deadline to remove liquidity
    /// @return amountA     Amount of tokenA received
    /// @return amountB     Amount of tokenB received
    function removeLiquidity(
        address tokenA,
        address tokenB,
        bool stable,
        uint256 liquidity,
        uint256 amountAMin,
        uint256 amountBMin,
        address to,
        uint256 deadline
    ) external returns (uint256 amountA, uint256 amountB);

    /// @notice Remove liquidity of a token and WETH (returned as ETH) from a Pool
    /// @param token            .
    /// @param stable           True if pool is stable, false if volatile
    /// @param liquidity        Amount of liquidity to remove
    /// @param amountTokenMin   Minimum amount of token to receive
    /// @param amountETHMin     Minimum amount of ETH to receive
    /// @param to               Recipient of liquidity token
    /// @param deadline         Deadline to receive liquidity
    /// @return amountToken     Amount of token received
    /// @return amountETH       Amount of ETH received
    function removeLiquidityETH(
        address token,
        bool stable,
        uint256 liquidity,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline
    ) external returns (uint256 amountToken, uint256 amountETH);

    /// @notice Remove liquidity of a fee-on-transfer token and WETH (returned as ETH) from a Pool
    /// @param token            .
    /// @param stable           True if pool is stable, false if volatile
    /// @param liquidity        Amount of liquidity to remove
    /// @param amountTokenMin   Minimum amount of token to receive
    /// @param amountETHMin     Minimum amount of ETH to receive
    /// @param to               Recipient of liquidity token
    /// @param deadline         Deadline to receive liquidity
    /// @return amountETH       Amount of ETH received
    function removeLiquidityETHSupportingFeeOnTransferTokens(
        address token,
        bool stable,
        uint256 liquidity,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline
    ) external returns (uint256 amountETH);

    /// @notice Swap one token for another
    /// @param amountIn     Amount of token in
    /// @param amountOutMin Minimum amount of desired token received
    /// @param routes       Array of trade routes used in the swap
    /// @param to           Recipient of the tokens received
    /// @param deadline     Deadline to receive tokens
    /// @return amounts     Array of amounts returned per route
    function swapExactTokensForTokens(
        uint256 amountIn,
        uint256 amountOutMin,
        Route[] calldata routes,
        address to,
        uint256 deadline
    ) external returns (uint256[] memory amounts);

    /// @notice Swap ETH for a token
    /// @param amountOutMin Minimum amount of desired token received
    /// @param routes       Array of trade routes used in the swap
    /// @param to           Recipient of the tokens received
    /// @param deadline     Deadline to receive tokens
    /// @return amounts     Array of amounts returned per route
    function swapExactETHForTokens(uint256 amountOutMin, Route[] calldata routes, address to, uint256 deadline)
        external
        payable
        returns (uint256[] memory amounts);

    /// @notice Swap a token for WETH (returned as ETH)
    /// @param amountIn     Amount of token in
    /// @param amountOutMin Minimum amount of desired ETH
    /// @param routes       Array of trade routes used in the swap
    /// @param to           Recipient of the tokens received
    /// @param deadline     Deadline to receive tokens
    /// @return amounts     Array of amounts returned per route
    function swapExactTokensForETH(
        uint256 amountIn,
        uint256 amountOutMin,
        Route[] calldata routes,
        address to,
        uint256 deadline
    ) external returns (uint256[] memory amounts);
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {IERC20} from "@openzeppelin5/contracts/token/ERC20/IERC20.sol";

interface IWETH is IERC20 {
    function deposit() external payable;

    function withdraw(uint256 wad) external;
}

Settings
{
  "remappings": [
    "@openzeppelin5/contracts/=lib/openzeppelin-contracts/contracts/",
    "ds-test/=lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/src/",
    "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
    "forge-std/src/=lib/forge-std/src/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/",
    "createX/=lib/createX/src/",
    "@nomad-xyz/=lib/ExcessivelySafeCall/",
    "@hyperlane/=node_modules/@hyperlane-xyz/",
    "@openzeppelin/contracts/=node_modules/@openzeppelin/contracts/",
    "@openzeppelin/contracts-upgradeable/=node_modules/@openzeppelin/contracts-upgradeable/",
    "ExcessivelySafeCall/=lib/ExcessivelySafeCall/src/",
    "openzeppelin/=lib/createX/lib/openzeppelin-contracts/contracts/",
    "solady/=lib/createX/lib/solady/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "cancun",
  "viaIR": false,
  "libraries": {}
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"_factory","type":"address"},{"internalType":"address","name":"_weth","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ETHTransferFailed","type":"error"},{"inputs":[],"name":"Expired","type":"error"},{"inputs":[],"name":"InsufficientAmount","type":"error"},{"inputs":[],"name":"InsufficientAmountA","type":"error"},{"inputs":[],"name":"InsufficientAmountADesired","type":"error"},{"inputs":[],"name":"InsufficientAmountB","type":"error"},{"inputs":[],"name":"InsufficientAmountBDesired","type":"error"},{"inputs":[],"name":"InsufficientLiquidity","type":"error"},{"inputs":[],"name":"InsufficientOutputAmount","type":"error"},{"inputs":[],"name":"InvalidPath","type":"error"},{"inputs":[],"name":"OnlyWETH","type":"error"},{"inputs":[],"name":"SameAddresses","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"uint256","name":"amountADesired","type":"uint256"},{"internalType":"uint256","name":"amountBDesired","type":"uint256"},{"internalType":"uint256","name":"amountAMin","type":"uint256"},{"internalType":"uint256","name":"amountBMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"addLiquidity","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"uint256","name":"amountTokenDesired","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"addLiquidityETH","outputs":[{"internalType":"uint256","name":"amountToken","type":"uint256"},{"internalType":"uint256","name":"amountETH","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"stable","type":"bool"}],"internalType":"struct IRouter.Route[]","name":"routes","type":"tuple[]"}],"name":"getAmountsOut","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"bool","name":"stable","type":"bool"}],"name":"getReserves","outputs":[{"internalType":"uint256","name":"reserveA","type":"uint256"},{"internalType":"uint256","name":"reserveB","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"bool","name":"stable","type":"bool"}],"name":"poolFor","outputs":[{"internalType":"address","name":"pool","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolImplementation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"uint256","name":"amountADesired","type":"uint256"},{"internalType":"uint256","name":"amountBDesired","type":"uint256"}],"name":"quoteAddLiquidity","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"name":"quoteRemoveLiquidity","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountAMin","type":"uint256"},{"internalType":"uint256","name":"amountBMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidity","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidityETH","outputs":[{"internalType":"uint256","name":"amountToken","type":"uint256"},{"internalType":"uint256","name":"amountETH","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidityETHSupportingFeeOnTransferTokens","outputs":[{"internalType":"uint256","name":"amountETH","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"}],"name":"sortTokens","outputs":[{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"stable","type":"bool"}],"internalType":"struct IRouter.Route[]","name":"routes","type":"tuple[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactETHForTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"stable","type":"bool"}],"internalType":"struct IRouter.Route[]","name":"routes","type":"tuple[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForETH","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"stable","type":"bool"}],"internalType":"struct IRouter.Route[]","name":"routes","type":"tuple[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"weth","outputs":[{"internalType":"contract IWETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]

60e060405234801561000f575f5ffd5b50604051612c91380380612c9183398101604081905261002e916100cd565b6001600160a01b038216608081905260408051635c60da1b60e01b81529051635c60da1b916004808201926020929091908290030181865afa158015610076573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061009a91906100fe565b6001600160a01b0390811660a0521660c0525061011e565b80516001600160a01b03811681146100c8575f5ffd5b919050565b5f5f604083850312156100de575f5ffd5b6100e7836100b2565b91506100f5602084016100b2565b90509250929050565b5f6020828403121561010e575f5ffd5b610117826100b2565b9392505050565b60805160a05160c051612ab66101db5f395f818161010d015281816101fe015281816105420152818161078901528181610cd501528181610de801528181610e71015281816114ab015281816114e001528181611515015281816115a6015281816116c701528181611717015281816118aa015261196101525f818161037f015261090201525f818161034c015281816108c60152818161096e01528181611126015281816112a701528181611e150152611eb40152612ab65ff3fe6080604052600436106100fd575f3560e01c806367ffb66a11610092578063c45a015511610062578063c45a01551461033b578063cefa77991461036e578063d7b0e0a5146103a1578063f41766d8146103c0578063fe411f14146103df575f5ffd5b806367ffb66a146102d75780639881fcb4146102ea57806398a0fb3c14610309578063b7e0d4c014610328575f5ffd5b80634386e63c116100cd5780634386e63c14610220578063544caa561461023f5780635a47ddc31461027e5780635e60dab5146102b8575f5ffd5b80630dede6c41461015157806318a130861461018a57806328eb0b4a146101b65780633fc8cef3146101ed575f5ffd5b3661014d57336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461014b576040516301f180c960e01b815260040160405180910390fd5b005b5f5ffd5b34801561015c575f5ffd5b5061017061016b3660046122f4565b61040c565b604080519283526020830191909152015b60405180910390f35b348015610195575f5ffd5b506101a96101a43660046123b5565b61052c565b6040516101819190612423565b3480156101c1575f5ffd5b506101d56101d0366004612465565b610863565b6040516001600160a01b039091168152602001610181565b3480156101f8575f5ffd5b506101d57f000000000000000000000000000000000000000000000000000000000000000081565b34801561022b575f5ffd5b5061017061023a3660046124ad565b610969565b34801561024a575f5ffd5b5061025e6102593660046124fb565b610ac7565b604080516001600160a01b03938416815292909116602083015201610181565b348015610289575f5ffd5b5061029d610298366004612532565b610b51565b60408051938452602084019290925290820152606001610181565b3480156102c3575f5ffd5b506101706102d2366004612465565b610c14565b6101a96102e53660046125bc565b610cc7565b3480156102f5575f5ffd5b506101a96103043660046126d7565b611002565b348015610314575f5ffd5b5061029d610323366004612799565b6112a1565b61029d6103363660046127f0565b611498565b348015610346575f5ffd5b506101d57f000000000000000000000000000000000000000000000000000000000000000081565b348015610379575f5ffd5b506101d57f000000000000000000000000000000000000000000000000000000000000000081565b3480156103ac575f5ffd5b506101706103bb3660046127f0565b6116b5565b3480156103cb575f5ffd5b506101a96103da3660046123b5565b61178d565b3480156103ea575f5ffd5b506103fe6103f93660046127f0565b611899565b604051908152602001610181565b5f5f82610418816119d6565b5f6104248c8c8c610863565b90506104328133838c6119fa565b60405163226bf2d160e21b81526001600160a01b0387811660048301525f9182918416906389afcb449060240160408051808303815f875af115801561047a573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061049e919061285e565b915091505f6104ad8f8f610ac7565b509050806001600160a01b03168f6001600160a01b0316146104d05781836104d3565b82825b90975095508a8710156104f9576040516323d9bb0560e21b815260040160405180910390fd5b8986101561051a57604051630d32418960e21b815260040160405180910390fd5b50505050509850989650505050505050565b606081610538816119d6565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016868661056f600182612894565b81811061057e5761057e6128a7565b905060600201602001602081019061059691906128bb565b6001600160a01b0316146105bd576040516320db826760e01b815260040160405180910390fd5b610618888787808060200260200160405190810160405280939291908181526020015f905b8282101561060e576105ff606083028601368190038101906128d6565b815260200190600101906105e2565b5050505050611002565b915086826001845161062a9190612894565b8151811061063a5761063a6128a7565b60200260200101511015610661576040516342301c2360e01b815260040160405180910390fd5b61072b86865f818110610676576106766128a7565b61068c92602060609092020190810191506128bb565b3361070c89895f8181106106a2576106a26128a7565b6106b892602060609092020190810191506128bb565b8a8a5f8181106106ca576106ca6128a7565b90506060020160200160208101906106e291906128bb565b8b8b5f8181106106f4576106f46128a7565b90506060020160400160208101906101d091906128f0565b855f8151811061071e5761071e6128a7565b60200260200101516119fa565b610787828787808060200260200160405190810160405280939291908181526020015f905b8282101561077c5761076d606083028601368190038101906128d6565b81526020019060010190610750565b505050505030611aea565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316632e1a7d4d83600185516107c59190612894565b815181106107d5576107d56128a7565b60200260200101516040518263ffffffff1660e01b81526004016107fb91815260200190565b5f604051808303815f87803b158015610812575f5ffd5b505af1158015610824573d5f5f3e3d5ffd5b5050505061085884836001855161083b9190612894565b8151811061084b5761084b6128a7565b6020026020010151611d29565b509695505050505050565b5f5f5f6108708686610ac7565b6040516bffffffffffffffffffffffff19606084811b8216602084015283901b16603482015286151560f81b604882015291935091505f9060490160408051601f198184030181529082905280516020909101207f000000000000000000000000000000000000000000000000000000000000000060388301526f5af43d82803e903d91602b57fd5bf3ff60248301527f00000000000000000000000000000000000000000000000000000000000000006014830152733d602d80600a3d3981f3363d3d373d3d3d363d738252605882018190526037600c83012060788301526055604390920191909120909150979650505050505050565b5f5f5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166379bc57d58888886040518463ffffffff1660e01b81526004016109bc9392919061290b565b602060405180830381865afa1580156109d7573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109fb919061292f565b90506001600160a01b038116610a17575f5f9250925050610abe565b5f5f610a24898989610c14565b915091505f836001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a65573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a89919061294a565b905080610a968489612961565b610aa0919061298c565b955080610aad8389612961565b610ab7919061298c565b9450505050505b94509492505050565b5f5f826001600160a01b0316846001600160a01b031603610afb57604051633295f3fd60e21b815260040160405180910390fd5b826001600160a01b0316846001600160a01b031610610b1b578284610b1e565b83835b90925090506001600160a01b038216610b4a5760405163d92e233d60e01b815260040160405180910390fd5b9250929050565b5f5f5f83610b5e816119d6565b610b6d8d8d8d8d8d8d8d611db8565b90945092505f610b7e8e8e8e610863565b9050610b8c8e3383886119fa565b610b988d3383876119fa565b6040516335313c2160e11b81526001600160a01b038881166004830152821690636a627842906024016020604051808303815f875af1158015610bdd573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c01919061294a565b9250505099509950999650505050505050565b5f5f5f610c218686610ac7565b5090505f5f610c31888888610863565b6001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa158015610c6c573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c9091906129ab565b5091509150826001600160a01b0316886001600160a01b031614610cb5578082610cb8565b81815b90999098509650505050505050565b606081610cd3816119d6565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031686865f818110610d0f57610d0f6128a7565b610d2592602060609092020190810191506128bb565b6001600160a01b031614610d4c576040516320db826760e01b815260040160405180910390fd5b610d9d348787808060200260200160405190810160405280939291908181526020015f905b8282101561060e57610d8e606083028601368190038101906128d6565b81526020019060010190610d71565b9150868260018451610daf9190612894565b81518110610dbf57610dbf6128a7565b60200260200101511015610de6576040516342301c2360e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0835f81518110610e2757610e276128a7565b60200260200101516040518263ffffffff1660e01b81526004015f604051808303818588803b158015610e58575f5ffd5b505af1158015610e6a573d5f5f3e3d5ffd5b50505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a9059cbb610f0588885f818110610eb357610eb36128a7565b610ec992602060609092020190810191506128bb565b89895f818110610edb57610edb6128a7565b9050606002016020016020810190610ef391906128bb565b8a8a5f8181106106f4576106f46128a7565b845f81518110610f1757610f176128a7565b60200260200101516040518363ffffffff1660e01b8152600401610f509291906001600160a01b03929092168252602082015260400190565b6020604051808303815f875af1158015610f6c573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f9091906129d6565b610f9c57610f9c6129f1565b610ff8828787808060200260200160405190810160405280939291908181526020015f905b82821015610fed57610fde606083028601368190038101906128d6565b81526020019060010190610fc1565b505050505086611aea565b5095945050505050565b6060600182511015611027576040516320db826760e01b815260040160405180910390fd5b8151611034906001612a05565b67ffffffffffffffff81111561104c5761104c61261e565b604051908082528060200260200182016040528015611075578160200160208202803683370190505b50905082815f8151811061108b5761108b6128a7565b602090810291909101015281515f5b81811015611299575f6111048583815181106110b8576110b86128a7565b60200260200101515f01518684815181106110d5576110d56128a7565b6020026020010151602001518785815181106110f3576110f36128a7565b602002602001015160400151610863565b604051635b16ebb760e01b81526001600160a01b0380831660048301529192507f000000000000000000000000000000000000000000000000000000000000000090911690635b16ebb790602401602060405180830381865afa15801561116d573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061119191906129d6565b1561127757806001600160a01b031663f140a35a8584815181106111b7576111b76128a7565b60200260200101518785815181106111d1576111d16128a7565b60200260200101515f01516040518363ffffffff1660e01b815260040161120b9291909182526001600160a01b0316602082015260400190565b602060405180830381865afa158015611226573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061124a919061294a565b84611256846001612a05565b81518110611266576112666128a7565b602002602001018181525050611290565b6040516320db826760e01b815260040160405180910390fd5b5060010161109a565b505092915050565b5f5f5f5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166379bc57d58a8a8a6040518463ffffffff1660e01b81526004016112f59392919061290b565b602060405180830381865afa158015611310573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611334919061292f565b90505f80806001600160a01b038416156113bb57836001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611384573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113a8919061294a565b90506113b58c8c8c610c14565b90935091505b821580156113c7575081155b156113f8578896508795506103e86113e76113e2888a612961565b611ff5565b6113f19190612894565b9450611489565b5f6114048a85856120e0565b905088811161144c5789975095508561144584611421848b612961565b61142b919061298c565b84611436858b612961565b611440919061298c565b612147565b9550611487565b5f6114588a85876120e0565b98508997508890506114838561146e8584612961565b611478919061298c565b85611436868c612961565b9650505b505b50505050955095509592505050565b5f5f5f836114a5816119d6565b6114d48b7f00000000000000000000000000000000000000000000000000000000000000008c8c348d8d611db8565b90945092505f6115058c7f00000000000000000000000000000000000000000000000000000000000000008d610863565b90506115138c3383886119fa565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0856040518263ffffffff1660e01b81526004015f604051808303818588803b15801561156c575f5ffd5b505af115801561157e573d5f5f3e3d5ffd5b505060405163a9059cbb60e01b81526001600160a01b038581166004830152602482018990527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb925060440190506020604051808303815f875af11580156115f0573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061161491906129d6565b611620576116206129f1565b6040516335313c2160e11b81526001600160a01b038881166004830152821690636a627842906024016020604051808303815f875af1158015611665573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611689919061294a565b9250833411156116a6576116a6336116a18634612894565b611d29565b50509750975097945050505050565b5f5f826116c1816119d6565b6116f18a7f00000000000000000000000000000000000000000000000000000000000000008b8b8b8b308b61040c565b90935091506117018a8685612160565b604051632e1a7d4d60e01b8152600481018390527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d906024015f604051808303815f87803b158015611760575f5ffd5b505af1158015611772573d5f5f3e3d5ffd5b505050506117808583611d29565b5097509795505050505050565b606081611799816119d6565b6117ea888787808060200260200160405190810160405280939291908181526020015f905b8282101561060e576117db606083028601368190038101906128d6565b815260200190600101906117be565b91508682600184516117fc9190612894565b8151811061180c5761180c6128a7565b60200260200101511015611833576040516342301c2360e01b815260040160405180910390fd5b61184886865f818110610676576106766128a7565b610858828787808060200260200160405190810160405280939291908181526020015f905b82821015610fed5761188a606083028601368190038101906128d6565b8152602001906001019061186d565b5f816118a4816119d6565b6118d4897f00000000000000000000000000000000000000000000000000000000000000008a8a8a8a308a61040c565b6040516370a0823160e01b815230600482015290935061194b91508a9086906001600160a01b038316906370a0823190602401602060405180830381865afa158015611922573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611946919061294a565b612160565b604051632e1a7d4d60e01b8152600481018390527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d906024015f604051808303815f87803b1580156119aa575f5ffd5b505af11580156119bc573d5f5f3e3d5ffd5b505050506119ca8483611d29565b50979650505050505050565b428110156119f757604051630407b05b60e31b815260040160405180910390fd5b50565b5f846001600160a01b03163b11611a0f575f5ffd5b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b17905291515f92839290881691611a729190612a18565b5f604051808303815f865af19150503d805f8114611aab576040519150601f19603f3d011682016040523d82523d5f602084013e611ab0565b606091505b5091509150818015611ada575080511580611ada575080806020019051810190611ada91906129d6565b611ae2575f5ffd5b505050505050565b81515f5b81811015611d22575f611b3a858381518110611b0c57611b0c6128a7565b60200260200101515f0151868481518110611b2957611b296128a7565b602002602001015160200151610ac7565b5090505f86611b4a846001612a05565b81518110611b5a57611b5a6128a7565b602002602001015190505f5f836001600160a01b0316888681518110611b8257611b826128a7565b60200260200101515f01516001600160a01b031614611ba257825f611ba5565b5f835b915091505f60018951611bb89190612894565b8610611bc45787611c36565b611c3689611bd3886001612a05565b81518110611be357611be36128a7565b60200260200101515f01518a886001611bfc9190612a05565b81518110611c0c57611c0c6128a7565b6020026020010151602001518b896001611c269190612a05565b815181106110f3576110f36128a7565b9050611c88898781518110611c4d57611c4d6128a7565b60200260200101515f01518a8881518110611c6a57611c6a6128a7565b6020026020010151602001518b89815181106110f3576110f36128a7565b6001600160a01b031663022c0d9f8484845f6040519080825280601f01601f191660200182016040528015611cc4576020820181803683370190505b506040518563ffffffff1660e01b8152600401611ce49493929190612a2e565b5f604051808303815f87803b158015611cfb575f5ffd5b505af1158015611d0d573d5f5f3e3d5ffd5b505060019097019650611aee95505050505050565b5050505050565b604080515f808252602082019092526001600160a01b038416908390604051611d529190612a18565b5f6040518083038185875af1925050503d805f8114611d8c576040519150601f19603f3d011682016040523d82523d5f602084013e611d91565b606091505b5050905080611db35760405163b12d13eb60e01b815260040160405180910390fd5b505050565b5f5f83861015611ddb57604051636e35977960e11b815260040160405180910390fd5b82851015611dfc5760405163acee051360e01b815260040160405180910390fd5b6040516379bc57d560e01b81525f906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906379bc57d590611e4e908d908d908d9060040161290b565b602060405180830381865afa158015611e69573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e8d919061292f565b90506001600160a01b038116611f30576040516301b5fcad60e51b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906336bf95a090611eed908d908d908d9060040161290b565b6020604051808303815f875af1158015611f09573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f2d919061292f565b90505b5f5f611f3d8c8c8c610c14565b91509150815f148015611f4e575080155b15611f5e57889450879350611fe6565b5f611f6a8a84846120e0565b9050888111611f9f5786811015611f9457604051630d32418960e21b815260040160405180910390fd5b899550935083611fe4565b5f611fab8a84866120e0565b90508a811115611fbd57611fbd6129f1565b88811015611fde576040516323d9bb0560e21b815260040160405180910390fd5b95508894505b505b50505097509795505050505050565b5f815f0361200457505f919050565b5f600161201084612240565b901c6001901b9050600181848161202957612029612978565b048201901c9050600181848161204157612041612978565b048201901c9050600181848161205957612059612978565b048201901c9050600181848161207157612071612978565b048201901c9050600181848161208957612089612978565b048201901c905060018184816120a1576120a1612978565b048201901c905060018184816120b9576120b9612978565b048201901c90506120d9818285816120d3576120d3612978565b04612147565b9392505050565b5f835f0361210157604051632ca2f52b60e11b815260040160405180910390fd5b82158061210c575081155b1561212a5760405163bb55fd2760e01b815260040160405180910390fd5b826121358386612961565b61213f919061298c565b949350505050565b5f8183106121555781612157565b825b90505b92915050565b5f836001600160a01b03163b11612175575f5ffd5b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b17905291515f928392908716916121d09190612a18565b5f604051808303815f865af19150503d805f8114612209576040519150601f19603f3d011682016040523d82523d5f602084013e61220e565b606091505b509150915081801561223857508051158061223857508080602001905181019061223891906129d6565b611d22575f5ffd5b5f80608083901c1561225457608092831c92015b604083901c1561226657604092831c92015b602083901c1561227857602092831c92015b601083901c1561228a57601092831c92015b600883901c1561229c57600892831c92015b600483901c156122ae57600492831c92015b600283901c156122c057600292831c92015b600183901c1561215a5760010192915050565b6001600160a01b03811681146119f7575f5ffd5b80151581146119f7575f5ffd5b5f5f5f5f5f5f5f5f610100898b03121561230c575f5ffd5b8835612317816122d3565b97506020890135612327816122d3565b96506040890135612337816122e7565b9550606089013594506080890135935060a0890135925060c089013561235c816122d3565b979a969950949793969295919450919260e001359150565b5f5f83601f840112612384575f5ffd5b50813567ffffffffffffffff81111561239b575f5ffd5b602083019150836020606083028501011115610b4a575f5ffd5b5f5f5f5f5f5f60a087890312156123ca575f5ffd5b8635955060208701359450604087013567ffffffffffffffff8111156123ee575f5ffd5b6123fa89828a01612374565b909550935050606087013561240e816122d3565b95989497509295919493608090920135925050565b602080825282518282018190525f918401906040840190835b8181101561245a57835183526020938401939092019160010161243c565b509095945050505050565b5f5f5f60608486031215612477575f5ffd5b8335612482816122d3565b92506020840135612492816122d3565b915060408401356124a2816122e7565b809150509250925092565b5f5f5f5f608085870312156124c0575f5ffd5b84356124cb816122d3565b935060208501356124db816122d3565b925060408501356124eb816122e7565b9396929550929360600135925050565b5f5f6040838503121561250c575f5ffd5b8235612517816122d3565b91506020830135612527816122d3565b809150509250929050565b5f5f5f5f5f5f5f5f5f6101208a8c03121561254b575f5ffd5b8935612556816122d3565b985060208a0135612566816122d3565b975060408a0135612576816122e7565b965060608a0135955060808a0135945060a08a0135935060c08a0135925060e08a01356125a2816122d3565b989b979a5095989497939692955090936101000135919050565b5f5f5f5f5f608086880312156125d0575f5ffd5b85359450602086013567ffffffffffffffff8111156125ed575f5ffd5b6125f988828901612374565b909550935050604086013561260d816122d3565b949793965091946060013592915050565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561265b5761265b61261e565b604052919050565b5f60608284031215612673575f5ffd5b6040516060810167ffffffffffffffff811182821017156126965761269661261e565b60405290508082356126a7816122d3565b815260208301356126b7816122d3565b602082015260408301356126ca816122e7565b6040919091015292915050565b5f5f604083850312156126e8575f5ffd5b82359150602083013567ffffffffffffffff811115612705575f5ffd5b8301601f81018513612715575f5ffd5b803567ffffffffffffffff81111561272f5761272f61261e565b61273e60208260051b01612632565b8082825260208201915060206060840285010192508783111561275f575f5ffd5b6020840193505b8284101561278b576127788885612663565b8252602082019150606084019350612766565b809450505050509250929050565b5f5f5f5f5f60a086880312156127ad575f5ffd5b85356127b8816122d3565b945060208601356127c8816122d3565b935060408601356127d8816122e7565b94979396509394606081013594506080013592915050565b5f5f5f5f5f5f5f60e0888a031215612806575f5ffd5b8735612811816122d3565b96506020880135612821816122e7565b955060408801359450606088013593506080880135925060a0880135612846816122d3565b96999598509396929591949193505060c09091013590565b5f5f6040838503121561286f575f5ffd5b505080516020909101519092909150565b634e487b7160e01b5f52601160045260245ffd5b8181038181111561215a5761215a612880565b634e487b7160e01b5f52603260045260245ffd5b5f602082840312156128cb575f5ffd5b81356120d9816122d3565b5f606082840312156128e6575f5ffd5b6121578383612663565b5f60208284031215612900575f5ffd5b81356120d9816122e7565b6001600160a01b039384168152919092166020820152901515604082015260600190565b5f6020828403121561293f575f5ffd5b81516120d9816122d3565b5f6020828403121561295a575f5ffd5b5051919050565b808202811582820484141761215a5761215a612880565b634e487b7160e01b5f52601260045260245ffd5b5f826129a657634e487b7160e01b5f52601260045260245ffd5b500490565b5f5f5f606084860312156129bd575f5ffd5b5050815160208301516040909301519094929350919050565b5f602082840312156129e6575f5ffd5b81516120d9816122e7565b634e487b7160e01b5f52600160045260245ffd5b8082018082111561215a5761215a612880565b5f82518060208501845e5f920191825250919050565b84815283602082015260018060a01b0383166040820152608060608201525f8251806080840152806020850160a085015e5f60a0828501015260a0601f19601f8301168401019150509594505050505056fea26469706673582212204be651d0a9aafdfc35e6ba3f749de7739ddfe05e5fa91f4726ad079313c3f5e164736f6c634300081b003300000000000000000000000031832f2a97fd20664d76cc421207669b55ce4bc00000000000000000000000004200000000000000000000000000000000000006

Deployed Bytecode

0x6080604052600436106100fd575f3560e01c806367ffb66a11610092578063c45a015511610062578063c45a01551461033b578063cefa77991461036e578063d7b0e0a5146103a1578063f41766d8146103c0578063fe411f14146103df575f5ffd5b806367ffb66a146102d75780639881fcb4146102ea57806398a0fb3c14610309578063b7e0d4c014610328575f5ffd5b80634386e63c116100cd5780634386e63c14610220578063544caa561461023f5780635a47ddc31461027e5780635e60dab5146102b8575f5ffd5b80630dede6c41461015157806318a130861461018a57806328eb0b4a146101b65780633fc8cef3146101ed575f5ffd5b3661014d57336001600160a01b037f0000000000000000000000004200000000000000000000000000000000000006161461014b576040516301f180c960e01b815260040160405180910390fd5b005b5f5ffd5b34801561015c575f5ffd5b5061017061016b3660046122f4565b61040c565b604080519283526020830191909152015b60405180910390f35b348015610195575f5ffd5b506101a96101a43660046123b5565b61052c565b6040516101819190612423565b3480156101c1575f5ffd5b506101d56101d0366004612465565b610863565b6040516001600160a01b039091168152602001610181565b3480156101f8575f5ffd5b506101d57f000000000000000000000000420000000000000000000000000000000000000681565b34801561022b575f5ffd5b5061017061023a3660046124ad565b610969565b34801561024a575f5ffd5b5061025e6102593660046124fb565b610ac7565b604080516001600160a01b03938416815292909116602083015201610181565b348015610289575f5ffd5b5061029d610298366004612532565b610b51565b60408051938452602084019290925290820152606001610181565b3480156102c3575f5ffd5b506101706102d2366004612465565b610c14565b6101a96102e53660046125bc565b610cc7565b3480156102f5575f5ffd5b506101a96103043660046126d7565b611002565b348015610314575f5ffd5b5061029d610323366004612799565b6112a1565b61029d6103363660046127f0565b611498565b348015610346575f5ffd5b506101d57f00000000000000000000000031832f2a97fd20664d76cc421207669b55ce4bc081565b348015610379575f5ffd5b506101d57f00000000000000000000000010499d88bd32af443fc936f67de32be1c8bb374c81565b3480156103ac575f5ffd5b506101706103bb3660046127f0565b6116b5565b3480156103cb575f5ffd5b506101a96103da3660046123b5565b61178d565b3480156103ea575f5ffd5b506103fe6103f93660046127f0565b611899565b604051908152602001610181565b5f5f82610418816119d6565b5f6104248c8c8c610863565b90506104328133838c6119fa565b60405163226bf2d160e21b81526001600160a01b0387811660048301525f9182918416906389afcb449060240160408051808303815f875af115801561047a573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061049e919061285e565b915091505f6104ad8f8f610ac7565b509050806001600160a01b03168f6001600160a01b0316146104d05781836104d3565b82825b90975095508a8710156104f9576040516323d9bb0560e21b815260040160405180910390fd5b8986101561051a57604051630d32418960e21b815260040160405180910390fd5b50505050509850989650505050505050565b606081610538816119d6565b6001600160a01b037f000000000000000000000000420000000000000000000000000000000000000616868661056f600182612894565b81811061057e5761057e6128a7565b905060600201602001602081019061059691906128bb565b6001600160a01b0316146105bd576040516320db826760e01b815260040160405180910390fd5b610618888787808060200260200160405190810160405280939291908181526020015f905b8282101561060e576105ff606083028601368190038101906128d6565b815260200190600101906105e2565b5050505050611002565b915086826001845161062a9190612894565b8151811061063a5761063a6128a7565b60200260200101511015610661576040516342301c2360e01b815260040160405180910390fd5b61072b86865f818110610676576106766128a7565b61068c92602060609092020190810191506128bb565b3361070c89895f8181106106a2576106a26128a7565b6106b892602060609092020190810191506128bb565b8a8a5f8181106106ca576106ca6128a7565b90506060020160200160208101906106e291906128bb565b8b8b5f8181106106f4576106f46128a7565b90506060020160400160208101906101d091906128f0565b855f8151811061071e5761071e6128a7565b60200260200101516119fa565b610787828787808060200260200160405190810160405280939291908181526020015f905b8282101561077c5761076d606083028601368190038101906128d6565b81526020019060010190610750565b505050505030611aea565b7f00000000000000000000000042000000000000000000000000000000000000066001600160a01b0316632e1a7d4d83600185516107c59190612894565b815181106107d5576107d56128a7565b60200260200101516040518263ffffffff1660e01b81526004016107fb91815260200190565b5f604051808303815f87803b158015610812575f5ffd5b505af1158015610824573d5f5f3e3d5ffd5b5050505061085884836001855161083b9190612894565b8151811061084b5761084b6128a7565b6020026020010151611d29565b509695505050505050565b5f5f5f6108708686610ac7565b6040516bffffffffffffffffffffffff19606084811b8216602084015283901b16603482015286151560f81b604882015291935091505f9060490160408051601f198184030181529082905280516020909101207f00000000000000000000000031832f2a97fd20664d76cc421207669b55ce4bc060388301526f5af43d82803e903d91602b57fd5bf3ff60248301527f00000000000000000000000010499d88bd32af443fc936f67de32be1c8bb374c6014830152733d602d80600a3d3981f3363d3d373d3d3d363d738252605882018190526037600c83012060788301526055604390920191909120909150979650505050505050565b5f5f5f7f00000000000000000000000031832f2a97fd20664d76cc421207669b55ce4bc06001600160a01b03166379bc57d58888886040518463ffffffff1660e01b81526004016109bc9392919061290b565b602060405180830381865afa1580156109d7573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109fb919061292f565b90506001600160a01b038116610a17575f5f9250925050610abe565b5f5f610a24898989610c14565b915091505f836001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a65573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a89919061294a565b905080610a968489612961565b610aa0919061298c565b955080610aad8389612961565b610ab7919061298c565b9450505050505b94509492505050565b5f5f826001600160a01b0316846001600160a01b031603610afb57604051633295f3fd60e21b815260040160405180910390fd5b826001600160a01b0316846001600160a01b031610610b1b578284610b1e565b83835b90925090506001600160a01b038216610b4a5760405163d92e233d60e01b815260040160405180910390fd5b9250929050565b5f5f5f83610b5e816119d6565b610b6d8d8d8d8d8d8d8d611db8565b90945092505f610b7e8e8e8e610863565b9050610b8c8e3383886119fa565b610b988d3383876119fa565b6040516335313c2160e11b81526001600160a01b038881166004830152821690636a627842906024016020604051808303815f875af1158015610bdd573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c01919061294a565b9250505099509950999650505050505050565b5f5f5f610c218686610ac7565b5090505f5f610c31888888610863565b6001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa158015610c6c573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c9091906129ab565b5091509150826001600160a01b0316886001600160a01b031614610cb5578082610cb8565b81815b90999098509650505050505050565b606081610cd3816119d6565b7f00000000000000000000000042000000000000000000000000000000000000066001600160a01b031686865f818110610d0f57610d0f6128a7565b610d2592602060609092020190810191506128bb565b6001600160a01b031614610d4c576040516320db826760e01b815260040160405180910390fd5b610d9d348787808060200260200160405190810160405280939291908181526020015f905b8282101561060e57610d8e606083028601368190038101906128d6565b81526020019060010190610d71565b9150868260018451610daf9190612894565b81518110610dbf57610dbf6128a7565b60200260200101511015610de6576040516342301c2360e01b815260040160405180910390fd5b7f00000000000000000000000042000000000000000000000000000000000000066001600160a01b031663d0e30db0835f81518110610e2757610e276128a7565b60200260200101516040518263ffffffff1660e01b81526004015f604051808303818588803b158015610e58575f5ffd5b505af1158015610e6a573d5f5f3e3d5ffd5b50505050507f00000000000000000000000042000000000000000000000000000000000000066001600160a01b031663a9059cbb610f0588885f818110610eb357610eb36128a7565b610ec992602060609092020190810191506128bb565b89895f818110610edb57610edb6128a7565b9050606002016020016020810190610ef391906128bb565b8a8a5f8181106106f4576106f46128a7565b845f81518110610f1757610f176128a7565b60200260200101516040518363ffffffff1660e01b8152600401610f509291906001600160a01b03929092168252602082015260400190565b6020604051808303815f875af1158015610f6c573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f9091906129d6565b610f9c57610f9c6129f1565b610ff8828787808060200260200160405190810160405280939291908181526020015f905b82821015610fed57610fde606083028601368190038101906128d6565b81526020019060010190610fc1565b505050505086611aea565b5095945050505050565b6060600182511015611027576040516320db826760e01b815260040160405180910390fd5b8151611034906001612a05565b67ffffffffffffffff81111561104c5761104c61261e565b604051908082528060200260200182016040528015611075578160200160208202803683370190505b50905082815f8151811061108b5761108b6128a7565b602090810291909101015281515f5b81811015611299575f6111048583815181106110b8576110b86128a7565b60200260200101515f01518684815181106110d5576110d56128a7565b6020026020010151602001518785815181106110f3576110f36128a7565b602002602001015160400151610863565b604051635b16ebb760e01b81526001600160a01b0380831660048301529192507f00000000000000000000000031832f2a97fd20664d76cc421207669b55ce4bc090911690635b16ebb790602401602060405180830381865afa15801561116d573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061119191906129d6565b1561127757806001600160a01b031663f140a35a8584815181106111b7576111b76128a7565b60200260200101518785815181106111d1576111d16128a7565b60200260200101515f01516040518363ffffffff1660e01b815260040161120b9291909182526001600160a01b0316602082015260400190565b602060405180830381865afa158015611226573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061124a919061294a565b84611256846001612a05565b81518110611266576112666128a7565b602002602001018181525050611290565b6040516320db826760e01b815260040160405180910390fd5b5060010161109a565b505092915050565b5f5f5f5f7f00000000000000000000000031832f2a97fd20664d76cc421207669b55ce4bc06001600160a01b03166379bc57d58a8a8a6040518463ffffffff1660e01b81526004016112f59392919061290b565b602060405180830381865afa158015611310573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611334919061292f565b90505f80806001600160a01b038416156113bb57836001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611384573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113a8919061294a565b90506113b58c8c8c610c14565b90935091505b821580156113c7575081155b156113f8578896508795506103e86113e76113e2888a612961565b611ff5565b6113f19190612894565b9450611489565b5f6114048a85856120e0565b905088811161144c5789975095508561144584611421848b612961565b61142b919061298c565b84611436858b612961565b611440919061298c565b612147565b9550611487565b5f6114588a85876120e0565b98508997508890506114838561146e8584612961565b611478919061298c565b85611436868c612961565b9650505b505b50505050955095509592505050565b5f5f5f836114a5816119d6565b6114d48b7f00000000000000000000000042000000000000000000000000000000000000068c8c348d8d611db8565b90945092505f6115058c7f00000000000000000000000042000000000000000000000000000000000000068d610863565b90506115138c3383886119fa565b7f00000000000000000000000042000000000000000000000000000000000000066001600160a01b031663d0e30db0856040518263ffffffff1660e01b81526004015f604051808303818588803b15801561156c575f5ffd5b505af115801561157e573d5f5f3e3d5ffd5b505060405163a9059cbb60e01b81526001600160a01b038581166004830152602482018990527f000000000000000000000000420000000000000000000000000000000000000616935063a9059cbb925060440190506020604051808303815f875af11580156115f0573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061161491906129d6565b611620576116206129f1565b6040516335313c2160e11b81526001600160a01b038881166004830152821690636a627842906024016020604051808303815f875af1158015611665573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611689919061294a565b9250833411156116a6576116a6336116a18634612894565b611d29565b50509750975097945050505050565b5f5f826116c1816119d6565b6116f18a7f00000000000000000000000042000000000000000000000000000000000000068b8b8b8b308b61040c565b90935091506117018a8685612160565b604051632e1a7d4d60e01b8152600481018390527f00000000000000000000000042000000000000000000000000000000000000066001600160a01b031690632e1a7d4d906024015f604051808303815f87803b158015611760575f5ffd5b505af1158015611772573d5f5f3e3d5ffd5b505050506117808583611d29565b5097509795505050505050565b606081611799816119d6565b6117ea888787808060200260200160405190810160405280939291908181526020015f905b8282101561060e576117db606083028601368190038101906128d6565b815260200190600101906117be565b91508682600184516117fc9190612894565b8151811061180c5761180c6128a7565b60200260200101511015611833576040516342301c2360e01b815260040160405180910390fd5b61184886865f818110610676576106766128a7565b610858828787808060200260200160405190810160405280939291908181526020015f905b82821015610fed5761188a606083028601368190038101906128d6565b8152602001906001019061186d565b5f816118a4816119d6565b6118d4897f00000000000000000000000042000000000000000000000000000000000000068a8a8a8a308a61040c565b6040516370a0823160e01b815230600482015290935061194b91508a9086906001600160a01b038316906370a0823190602401602060405180830381865afa158015611922573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611946919061294a565b612160565b604051632e1a7d4d60e01b8152600481018390527f00000000000000000000000042000000000000000000000000000000000000066001600160a01b031690632e1a7d4d906024015f604051808303815f87803b1580156119aa575f5ffd5b505af11580156119bc573d5f5f3e3d5ffd5b505050506119ca8483611d29565b50979650505050505050565b428110156119f757604051630407b05b60e31b815260040160405180910390fd5b50565b5f846001600160a01b03163b11611a0f575f5ffd5b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b17905291515f92839290881691611a729190612a18565b5f604051808303815f865af19150503d805f8114611aab576040519150601f19603f3d011682016040523d82523d5f602084013e611ab0565b606091505b5091509150818015611ada575080511580611ada575080806020019051810190611ada91906129d6565b611ae2575f5ffd5b505050505050565b81515f5b81811015611d22575f611b3a858381518110611b0c57611b0c6128a7565b60200260200101515f0151868481518110611b2957611b296128a7565b602002602001015160200151610ac7565b5090505f86611b4a846001612a05565b81518110611b5a57611b5a6128a7565b602002602001015190505f5f836001600160a01b0316888681518110611b8257611b826128a7565b60200260200101515f01516001600160a01b031614611ba257825f611ba5565b5f835b915091505f60018951611bb89190612894565b8610611bc45787611c36565b611c3689611bd3886001612a05565b81518110611be357611be36128a7565b60200260200101515f01518a886001611bfc9190612a05565b81518110611c0c57611c0c6128a7565b6020026020010151602001518b896001611c269190612a05565b815181106110f3576110f36128a7565b9050611c88898781518110611c4d57611c4d6128a7565b60200260200101515f01518a8881518110611c6a57611c6a6128a7565b6020026020010151602001518b89815181106110f3576110f36128a7565b6001600160a01b031663022c0d9f8484845f6040519080825280601f01601f191660200182016040528015611cc4576020820181803683370190505b506040518563ffffffff1660e01b8152600401611ce49493929190612a2e565b5f604051808303815f87803b158015611cfb575f5ffd5b505af1158015611d0d573d5f5f3e3d5ffd5b505060019097019650611aee95505050505050565b5050505050565b604080515f808252602082019092526001600160a01b038416908390604051611d529190612a18565b5f6040518083038185875af1925050503d805f8114611d8c576040519150601f19603f3d011682016040523d82523d5f602084013e611d91565b606091505b5050905080611db35760405163b12d13eb60e01b815260040160405180910390fd5b505050565b5f5f83861015611ddb57604051636e35977960e11b815260040160405180910390fd5b82851015611dfc5760405163acee051360e01b815260040160405180910390fd5b6040516379bc57d560e01b81525f906001600160a01b037f00000000000000000000000031832f2a97fd20664d76cc421207669b55ce4bc016906379bc57d590611e4e908d908d908d9060040161290b565b602060405180830381865afa158015611e69573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e8d919061292f565b90506001600160a01b038116611f30576040516301b5fcad60e51b81526001600160a01b037f00000000000000000000000031832f2a97fd20664d76cc421207669b55ce4bc016906336bf95a090611eed908d908d908d9060040161290b565b6020604051808303815f875af1158015611f09573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f2d919061292f565b90505b5f5f611f3d8c8c8c610c14565b91509150815f148015611f4e575080155b15611f5e57889450879350611fe6565b5f611f6a8a84846120e0565b9050888111611f9f5786811015611f9457604051630d32418960e21b815260040160405180910390fd5b899550935083611fe4565b5f611fab8a84866120e0565b90508a811115611fbd57611fbd6129f1565b88811015611fde576040516323d9bb0560e21b815260040160405180910390fd5b95508894505b505b50505097509795505050505050565b5f815f0361200457505f919050565b5f600161201084612240565b901c6001901b9050600181848161202957612029612978565b048201901c9050600181848161204157612041612978565b048201901c9050600181848161205957612059612978565b048201901c9050600181848161207157612071612978565b048201901c9050600181848161208957612089612978565b048201901c905060018184816120a1576120a1612978565b048201901c905060018184816120b9576120b9612978565b048201901c90506120d9818285816120d3576120d3612978565b04612147565b9392505050565b5f835f0361210157604051632ca2f52b60e11b815260040160405180910390fd5b82158061210c575081155b1561212a5760405163bb55fd2760e01b815260040160405180910390fd5b826121358386612961565b61213f919061298c565b949350505050565b5f8183106121555781612157565b825b90505b92915050565b5f836001600160a01b03163b11612175575f5ffd5b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b17905291515f928392908716916121d09190612a18565b5f604051808303815f865af19150503d805f8114612209576040519150601f19603f3d011682016040523d82523d5f602084013e61220e565b606091505b509150915081801561223857508051158061223857508080602001905181019061223891906129d6565b611d22575f5ffd5b5f80608083901c1561225457608092831c92015b604083901c1561226657604092831c92015b602083901c1561227857602092831c92015b601083901c1561228a57601092831c92015b600883901c1561229c57600892831c92015b600483901c156122ae57600492831c92015b600283901c156122c057600292831c92015b600183901c1561215a5760010192915050565b6001600160a01b03811681146119f7575f5ffd5b80151581146119f7575f5ffd5b5f5f5f5f5f5f5f5f610100898b03121561230c575f5ffd5b8835612317816122d3565b97506020890135612327816122d3565b96506040890135612337816122e7565b9550606089013594506080890135935060a0890135925060c089013561235c816122d3565b979a969950949793969295919450919260e001359150565b5f5f83601f840112612384575f5ffd5b50813567ffffffffffffffff81111561239b575f5ffd5b602083019150836020606083028501011115610b4a575f5ffd5b5f5f5f5f5f5f60a087890312156123ca575f5ffd5b8635955060208701359450604087013567ffffffffffffffff8111156123ee575f5ffd5b6123fa89828a01612374565b909550935050606087013561240e816122d3565b95989497509295919493608090920135925050565b602080825282518282018190525f918401906040840190835b8181101561245a57835183526020938401939092019160010161243c565b509095945050505050565b5f5f5f60608486031215612477575f5ffd5b8335612482816122d3565b92506020840135612492816122d3565b915060408401356124a2816122e7565b809150509250925092565b5f5f5f5f608085870312156124c0575f5ffd5b84356124cb816122d3565b935060208501356124db816122d3565b925060408501356124eb816122e7565b9396929550929360600135925050565b5f5f6040838503121561250c575f5ffd5b8235612517816122d3565b91506020830135612527816122d3565b809150509250929050565b5f5f5f5f5f5f5f5f5f6101208a8c03121561254b575f5ffd5b8935612556816122d3565b985060208a0135612566816122d3565b975060408a0135612576816122e7565b965060608a0135955060808a0135945060a08a0135935060c08a0135925060e08a01356125a2816122d3565b989b979a5095989497939692955090936101000135919050565b5f5f5f5f5f608086880312156125d0575f5ffd5b85359450602086013567ffffffffffffffff8111156125ed575f5ffd5b6125f988828901612374565b909550935050604086013561260d816122d3565b949793965091946060013592915050565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561265b5761265b61261e565b604052919050565b5f60608284031215612673575f5ffd5b6040516060810167ffffffffffffffff811182821017156126965761269661261e565b60405290508082356126a7816122d3565b815260208301356126b7816122d3565b602082015260408301356126ca816122e7565b6040919091015292915050565b5f5f604083850312156126e8575f5ffd5b82359150602083013567ffffffffffffffff811115612705575f5ffd5b8301601f81018513612715575f5ffd5b803567ffffffffffffffff81111561272f5761272f61261e565b61273e60208260051b01612632565b8082825260208201915060206060840285010192508783111561275f575f5ffd5b6020840193505b8284101561278b576127788885612663565b8252602082019150606084019350612766565b809450505050509250929050565b5f5f5f5f5f60a086880312156127ad575f5ffd5b85356127b8816122d3565b945060208601356127c8816122d3565b935060408601356127d8816122e7565b94979396509394606081013594506080013592915050565b5f5f5f5f5f5f5f60e0888a031215612806575f5ffd5b8735612811816122d3565b96506020880135612821816122e7565b955060408801359450606088013593506080880135925060a0880135612846816122d3565b96999598509396929591949193505060c09091013590565b5f5f6040838503121561286f575f5ffd5b505080516020909101519092909150565b634e487b7160e01b5f52601160045260245ffd5b8181038181111561215a5761215a612880565b634e487b7160e01b5f52603260045260245ffd5b5f602082840312156128cb575f5ffd5b81356120d9816122d3565b5f606082840312156128e6575f5ffd5b6121578383612663565b5f60208284031215612900575f5ffd5b81356120d9816122e7565b6001600160a01b039384168152919092166020820152901515604082015260600190565b5f6020828403121561293f575f5ffd5b81516120d9816122d3565b5f6020828403121561295a575f5ffd5b5051919050565b808202811582820484141761215a5761215a612880565b634e487b7160e01b5f52601260045260245ffd5b5f826129a657634e487b7160e01b5f52601260045260245ffd5b500490565b5f5f5f606084860312156129bd575f5ffd5b5050815160208301516040909301519094929350919050565b5f602082840312156129e6575f5ffd5b81516120d9816122e7565b634e487b7160e01b5f52600160045260245ffd5b8082018082111561215a5761215a612880565b5f82518060208501845e5f920191825250919050565b84815283602082015260018060a01b0383166040820152608060608201525f8251806080840152806020850160a085015e5f60a0828501015260a0601f19601f8301168401019150509594505050505056fea26469706673582212204be651d0a9aafdfc35e6ba3f749de7739ddfe05e5fa91f4726ad079313c3f5e164736f6c634300081b0033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

00000000000000000000000031832f2a97fd20664d76cc421207669b55ce4bc00000000000000000000000004200000000000000000000000000000000000006

-----Decoded View---------------
Arg [0] : _factory (address): 0x31832f2a97Fd20664D76Cc421207669b55CE4BC0
Arg [1] : _weth (address): 0x4200000000000000000000000000000000000006

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 00000000000000000000000031832f2a97fd20664d76cc421207669b55ce4bc0
Arg [1] : 0000000000000000000000004200000000000000000000000000000000000006


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.