FRAX Price: $0.84 (-17.53%)

Contract

0x3a63171DD9BebF4D07BC782FECC7eb0b890C2A45

Overview

FRAX Balance | FXTL Balance

0 FRAX | 5,232 FXTL

FRAX Value

$0.00

Token Holdings

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Block
From
To
Remove Liquidity301374902025-12-30 9:08:1126 days ago1767085691IN
0x3a63171D...b890C2A45
0 FRAX0.0000070.001
Remove Liquidity226781402025-07-10 17:03:11199 days ago1752166991IN
0x3a63171D...b890C2A45
0 FRAX0.001152040.00110025
Remove Liquidity212415102025-06-07 10:55:31232 days ago1749293731IN
0x3a63171D...b890C2A45
0 FRAX0.000134280.00110025
Add Liquidity208945442025-05-30 10:09:59240 days ago1748599799IN
0x3a63171D...b890C2A45
0 FRAX0.000014580.04472153
Add Liquidity207617902025-05-27 8:24:51243 days ago1748334291IN
0x3a63171D...b890C2A45
0 FRAX0.000003210.00110111
Add Liquidity206361572025-05-24 10:37:05246 days ago1748083025IN
0x3a63171D...b890C2A45
0 FRAX0.000001180.0011011
Add Liquidity205460422025-05-22 8:33:15248 days ago1747902795IN
0x3a63171D...b890C2A45
0 FRAX0.000000250.00111135
Add Liquidity204178802025-05-19 9:21:11251 days ago1747646471IN
0x3a63171D...b890C2A45
0 FRAX0.000000210.00110112
Add Liquidity203309072025-05-17 9:02:05253 days ago1747472525IN
0x3a63171D...b890C2A45
0 FRAX0.000000210.00110111
Add Liquidity202337312025-05-15 3:02:53255 days ago1747278173IN
0x3a63171D...b890C2A45
0 FRAX0.000000210.00110111
Add Liquidity200948782025-05-11 21:54:27258 days ago1747000467IN
0x3a63171D...b890C2A45
0 FRAX0.000000210.00110113
Add Liquidity200345672025-05-10 12:24:05260 days ago1746879845IN
0x3a63171D...b890C2A45
0 FRAX0.000000210.00110113
Add Liquidity197505382025-05-03 22:36:27266 days ago1746311787IN
0x3a63171D...b890C2A45
0 FRAX0.000000210.00110025
Add Liquidity195203302025-04-28 14:42:51272 days ago1745851371IN
0x3a63171D...b890C2A45
0 FRAX0.000000380.00110025
Add Liquidity194968792025-04-28 1:41:09272 days ago1745804469IN
0x3a63171D...b890C2A45
0 FRAX0.000000290.00110025
Add Liquidity194778342025-04-27 15:06:19273 days ago1745766379IN
0x3a63171D...b890C2A45
0 FRAX0.000000340.00110025
Remove Liquidity194652472025-04-27 8:06:45273 days ago1745741205IN
0x3a63171D...b890C2A45
0 FRAX0.000000690.003
Remove Liquidity194500972025-04-26 23:41:45273 days ago1745710905IN
0x3a63171D...b890C2A45
0 FRAX0.000000080.00010025
Add Liquidity194373692025-04-26 16:37:29274 days ago1745685449IN
0x3a63171D...b890C2A45
0 FRAX0.000000380.00110025
Remove Liquidity194017562025-04-25 20:50:23274 days ago1745614223IN
0x3a63171D...b890C2A45
0 FRAX0.000000350.00100025
Remove Liquidity193554002025-04-24 19:05:11275 days ago1745521511IN
0x3a63171D...b890C2A45
0 FRAX0.000000160.00010025
Remove Liquidity193304592025-04-24 5:13:49276 days ago1745471629IN
0x3a63171D...b890C2A45
0 FRAX0.000000330.00110025
Remove Liquidity192275832025-04-21 20:04:37278 days ago1745265877IN
0x3a63171D...b890C2A45
0 FRAX0.000000370.00110025
Add Liquidity192133972025-04-21 12:11:45279 days ago1745237505IN
0x3a63171D...b890C2A45
0 FRAX0.000000250.00110025
Remove Liquidity190868242025-04-18 13:52:39282 days ago1744984359IN
0x3a63171D...b890C2A45
0 FRAX0.000000080.00010025
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block From To
311168742026-01-22 1:14:193 days ago1769044459
0x3a63171D...b890C2A45
0 FRAX
311168742026-01-22 1:14:193 days ago1769044459
0x3a63171D...b890C2A45
0 FRAX
311168742026-01-22 1:14:193 days ago1769044459
0x3a63171D...b890C2A45
0 FRAX
311168742026-01-22 1:14:193 days ago1769044459
0x3a63171D...b890C2A45
0 FRAX
311168742026-01-22 1:14:193 days ago1769044459
0x3a63171D...b890C2A45
0 FRAX
311168742026-01-22 1:14:193 days ago1769044459
0x3a63171D...b890C2A45
0 FRAX
311166962026-01-22 1:08:233 days ago1769044103
0x3a63171D...b890C2A45
0 FRAX
311166962026-01-22 1:08:233 days ago1769044103
0x3a63171D...b890C2A45
0 FRAX
311166962026-01-22 1:08:233 days ago1769044103
0x3a63171D...b890C2A45
0 FRAX
311166962026-01-22 1:08:233 days ago1769044103
0x3a63171D...b890C2A45
0 FRAX
311166962026-01-22 1:08:233 days ago1769044103
0x3a63171D...b890C2A45
0 FRAX
311166962026-01-22 1:08:233 days ago1769044103
0x3a63171D...b890C2A45
0 FRAX
307707382026-01-14 0:56:2711 days ago1768352187
0x3a63171D...b890C2A45
0 FRAX
307707382026-01-14 0:56:2711 days ago1768352187
0x3a63171D...b890C2A45
0 FRAX
307707382026-01-14 0:56:2711 days ago1768352187
0x3a63171D...b890C2A45
0 FRAX
307707382026-01-14 0:56:2711 days ago1768352187
0x3a63171D...b890C2A45
0 FRAX
307707382026-01-14 0:56:2711 days ago1768352187
0x3a63171D...b890C2A45
0 FRAX
307707382026-01-14 0:56:2711 days ago1768352187
0x3a63171D...b890C2A45
0 FRAX
307707222026-01-14 0:55:5511 days ago1768352155
0x3a63171D...b890C2A45
0 FRAX
307707222026-01-14 0:55:5511 days ago1768352155
0x3a63171D...b890C2A45
0 FRAX
307707222026-01-14 0:55:5511 days ago1768352155
0x3a63171D...b890C2A45
0 FRAX
307707222026-01-14 0:55:5511 days ago1768352155
0x3a63171D...b890C2A45
0 FRAX
307707222026-01-14 0:55:5511 days ago1768352155
0x3a63171D...b890C2A45
0 FRAX
307707222026-01-14 0:55:5511 days ago1768352155
0x3a63171D...b890C2A45
0 FRAX
307706582026-01-14 0:53:4711 days ago1768352027
0x3a63171D...b890C2A45
0 FRAX
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:
paris 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/",
    "forge-gas-snapshot/=lib/forge-gas-snapshot/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": "paris",
  "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"}]

60e060405234801561001057600080fd5b50604051612dcf380380612dcf83398101604081905261002f916100d1565b6001600160a01b038216608081905260408051635c60da1b60e01b81529051635c60da1b916004808201926020929091908290030181865afa158015610079573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061009d9190610104565b6001600160a01b0390811660a0521660c05250610126565b80516001600160a01b03811681146100cc57600080fd5b919050565b600080604083850312156100e457600080fd5b6100ed836100b5565b91506100fb602084016100b5565b90509250929050565b60006020828403121561011657600080fd5b61011f826100b5565b9392505050565b60805160a05160c051612be76101e860003960008181610112015281816102080152818161055e015281816107ac01528181610d1501528181610e2a01528181610eb80152818161150e01528181611544015281816115790152818161160e01528181611736015281816117860152818161192201526119db015260008181610391015261092d01526000818161035d015281816108f10152818161099b015281816111790152818161130101528181611eb30152611f540152612be76000f3fe6080604052600436106101025760003560e01c806367ffb66a11610095578063c45a015511610064578063c45a01551461034b578063cefa77991461037f578063d7b0e0a5146103b3578063f41766d8146103d3578063fe411f14146103f357600080fd5b806367ffb66a146102e55780639881fcb4146102f857806398a0fb3c14610318578063b7e0d4c01461033857600080fd5b80634386e63c116100d15780634386e63c1461022a578063544caa561461024a5780635a47ddc31461028a5780635e60dab5146102c557600080fd5b80630dede6c41461015757806318a130861461019157806328eb0b4a146101be5780633fc8cef3146101f657600080fd5b3661015257336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610150576040516301f180c960e01b815260040160405180910390fd5b005b600080fd5b34801561016357600080fd5b506101776101723660046123ad565b610421565b604080519283526020830191909152015b60405180910390f35b34801561019d57600080fd5b506101b16101ac366004612477565b610548565b60405161018891906124ea565b3480156101ca57600080fd5b506101de6101d936600461252d565b61088b565b6040516001600160a01b039091168152602001610188565b34801561020257600080fd5b506101de7f000000000000000000000000000000000000000000000000000000000000000081565b34801561023657600080fd5b50610177610245366004612578565b610994565b34801561025657600080fd5b5061026a6102653660046125c9565b610afb565b604080516001600160a01b03938416815292909116602083015201610188565b34801561029657600080fd5b506102aa6102a5366004612602565b610b86565b60408051938452602084019290925290820152606001610188565b3480156102d157600080fd5b506101776102e036600461252d565b610c4f565b6101b16102f3366004612692565b610d07565b34801561030457600080fd5b506101b16103133660046127b6565b611051565b34801561032457600080fd5b506102aa61033336600461287d565b6112f9565b6102aa6103463660046128d8565b6114f9565b34801561035757600080fd5b506101de7f000000000000000000000000000000000000000000000000000000000000000081565b34801561038b57600080fd5b506101de7f000000000000000000000000000000000000000000000000000000000000000081565b3480156103bf57600080fd5b506101776103ce3660046128d8565b611723565b3480156103df57600080fd5b506101b16103ee366004612477565b611801565b3480156103ff57600080fd5b5061041361040e3660046128d8565b611910565b604051908152602001610188565b6000808261042e81611a55565b600061043b8c8c8c61088b565b90506104498133838c611a79565b60405163226bf2d160e21b81526001600160a01b03878116600483015260009182918416906389afcb449060240160408051808303816000875af1158015610495573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104b9919061294b565b9150915060006104c98f8f610afb565b509050806001600160a01b03168f6001600160a01b0316146104ec5781836104ef565b82825b90975095508a871015610515576040516323d9bb0560e21b815260040160405180910390fd5b8986101561053657604051630d32418960e21b815260040160405180910390fd5b50505050509850989650505050505050565b60608161055481611a55565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016868661058b600182612985565b81811061059a5761059a612998565b90506060020160200160208101906105b291906129ae565b6001600160a01b0316146105d9576040516320db826760e01b815260040160405180910390fd5b610635888787808060200260200160405190810160405280939291908181526020016000905b8282101561062b5761061c606083028601368190038101906129cb565b815260200190600101906105ff565b5050505050611051565b91508682600184516106479190612985565b8151811061065757610657612998565b6020026020010151101561067e576040516342301c2360e01b815260040160405180910390fd5b61074d8686600081811061069457610694612998565b6106aa92602060609092020190810191506129ae565b3361072d898960008181106106c1576106c1612998565b6106d792602060609092020190810191506129ae565b8a8a60008181106106ea576106ea612998565b905060600201602001602081019061070291906129ae565b8b8b600081811061071557610715612998565b90506060020160400160208101906101d991906129e7565b8560008151811061074057610740612998565b6020026020010151611a79565b6107aa828787808060200260200160405190810160405280939291908181526020016000905b8282101561079f57610790606083028601368190038101906129cb565b81526020019060010190610773565b505050505030611b71565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316632e1a7d4d83600185516107e89190612985565b815181106107f8576107f8612998565b60200260200101516040518263ffffffff1660e01b815260040161081e91815260200190565b600060405180830381600087803b15801561083857600080fd5b505af115801561084c573d6000803e3d6000fd5b505050506108808483600185516108639190612985565b8151811061087357610873612998565b6020026020010151611dc1565b509695505050505050565b600080600061089a8686610afb565b6040516bffffffffffffffffffffffff19606084811b8216602084015283901b16603482015286151560f81b6048820152919350915060009060490160408051601f198184030181529082905280516020909101207f000000000000000000000000000000000000000000000000000000000000000060388301526f5af43d82803e903d91602b57fd5bf3ff60248301527f00000000000000000000000000000000000000000000000000000000000000006014830152733d602d80600a3d3981f3363d3d373d3d3d363d738252605882018190526037600c83012060788301526055604390920191909120909150979650505050505050565b60008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166379bc57d58888886040518463ffffffff1660e01b81526004016109e993929190612a04565b602060405180830381865afa158015610a06573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a2a9190612a28565b90506001600160a01b038116610a47576000809250925050610af2565b600080610a55898989610c4f565b915091506000836001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a99573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610abd9190612a45565b905080610aca8489612a5e565b610ad49190612a8b565b955080610ae18389612a5e565b610aeb9190612a8b565b9450505050505b94509492505050565b600080826001600160a01b0316846001600160a01b031603610b3057604051633295f3fd60e21b815260040160405180910390fd5b826001600160a01b0316846001600160a01b031610610b50578284610b53565b83835b90925090506001600160a01b038216610b7f5760405163d92e233d60e01b815260040160405180910390fd5b9250929050565b600080600083610b9581611a55565b610ba48d8d8d8d8d8d8d611e54565b90945092506000610bb68e8e8e61088b565b9050610bc48e338388611a79565b610bd08d338387611a79565b6040516335313c2160e11b81526001600160a01b038881166004830152821690636a627842906024016020604051808303816000875af1158015610c18573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c3c9190612a45565b9250505099509950999650505050505050565b6000806000610c5e8686610afb565b509050600080610c6f88888861088b565b6001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa158015610cac573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cd09190612aad565b5091509150826001600160a01b0316886001600160a01b031614610cf5578082610cf8565b81815b90999098509650505050505050565b606081610d1381611a55565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031686866000818110610d5057610d50612998565b610d6692602060609092020190810191506129ae565b6001600160a01b031614610d8d576040516320db826760e01b815260040160405180910390fd5b610ddf348787808060200260200160405190810160405280939291908181526020016000905b8282101561062b57610dd0606083028601368190038101906129cb565b81526020019060010190610db3565b9150868260018451610df19190612985565b81518110610e0157610e01612998565b60200260200101511015610e28576040516342301c2360e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db083600081518110610e6a57610e6a612998565b60200260200101516040518263ffffffff1660e01b81526004016000604051808303818588803b158015610e9d57600080fd5b505af1158015610eb1573d6000803e3d6000fd5b50505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a9059cbb610f4f88886000818110610efb57610efb612998565b610f1192602060609092020190810191506129ae565b89896000818110610f2457610f24612998565b9050606002016020016020810190610f3c91906129ae565b8a8a600081811061071557610715612998565b84600081518110610f6257610f62612998565b60200260200101516040518363ffffffff1660e01b8152600401610f9b9291906001600160a01b03929092168252602082015260400190565b6020604051808303816000875af1158015610fba573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fde9190612adb565b610fea57610fea612af8565b611047828787808060200260200160405190810160405280939291908181526020016000905b8282101561103c5761102d606083028601368190038101906129cb565b81526020019060010190611010565b505050505086611b71565b5095945050505050565b6060600182511015611076576040516320db826760e01b815260040160405180910390fd5b8151611083906001612b0e565b67ffffffffffffffff81111561109b5761109b6126f9565b6040519080825280602002602001820160405280156110c4578160200160208202803683370190505b50905082816000815181106110db576110db612998565b6020908102919091010152815160005b818110156112f157600061115785838151811061110a5761110a612998565b60200260200101516000015186848151811061112857611128612998565b60200260200101516020015187858151811061114657611146612998565b60200260200101516040015161088b565b604051635b16ebb760e01b81526001600160a01b0380831660048301529192507f000000000000000000000000000000000000000000000000000000000000000090911690635b16ebb790602401602060405180830381865afa1580156111c2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111e69190612adb565b156112cf57806001600160a01b031663f140a35a85848151811061120c5761120c612998565b602002602001015187858151811061122657611226612998565b6020026020010151600001516040518363ffffffff1660e01b81526004016112619291909182526001600160a01b0316602082015260400190565b602060405180830381865afa15801561127e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112a29190612a45565b846112ae846001612b0e565b815181106112be576112be612998565b6020026020010181815250506112e8565b6040516320db826760e01b815260040160405180910390fd5b506001016110eb565b505092915050565b6000806000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166379bc57d58a8a8a6040518463ffffffff1660e01b815260040161134f93929190612a04565b602060405180830381865afa15801561136c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113909190612a28565b9050600080806001600160a01b0384161561141a57836001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113e3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114079190612a45565b90506114148c8c8c610c4f565b90935091505b82158015611426575081155b15611457578896508795506103e8611446611441888a612a5e565b61209c565b6114509190612985565b94506114ea565b60006114648a858561218b565b90508881116114ac578997509550856114a584611481848b612a5e565b61148b9190612a8b565b84611496858b612a5e565b6114a09190612a8b565b6121f4565b95506114e8565b60006114b98a858761218b565b98508997508890506114e4856114cf8584612a5e565b6114d99190612a8b565b85611496868c612a5e565b9650505b505b50505050955095509592505050565b60008060008361150881611a55565b6115378b7f00000000000000000000000000000000000000000000000000000000000000008c8c348d8d611e54565b909450925060006115698c7f00000000000000000000000000000000000000000000000000000000000000008d61088b565b90506115778c338388611a79565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0856040518263ffffffff1660e01b81526004016000604051808303818588803b1580156115d257600080fd5b505af11580156115e6573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b038581166004830152602482018990527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb925060440190506020604051808303816000875af115801561165b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061167f9190612adb565b61168b5761168b612af8565b6040516335313c2160e11b81526001600160a01b038881166004830152821690636a627842906024016020604051808303816000875af11580156116d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116f79190612a45565b925083341115611714576117143361170f8634612985565b611dc1565b50509750975097945050505050565b6000808261173081611a55565b6117608a7f00000000000000000000000000000000000000000000000000000000000000008b8b8b8b308b610421565b90935091506117708a868561220e565b604051632e1a7d4d60e01b8152600481018390527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b1580156117d257600080fd5b505af11580156117e6573d6000803e3d6000fd5b505050506117f48583611dc1565b5097509795505050505050565b60608161180d81611a55565b61185f888787808060200260200160405190810160405280939291908181526020016000905b8282101561062b57611850606083028601368190038101906129cb565b81526020019060010190611833565b91508682600184516118719190612985565b8151811061188157611881612998565b602002602001015110156118a8576040516342301c2360e01b815260040160405180910390fd5b6118be8686600081811061069457610694612998565b610880828787808060200260200160405190810160405280939291908181526020016000905b8282101561103c57611901606083028601368190038101906129cb565b815260200190600101906118e4565b60008161191c81611a55565b61194c897f00000000000000000000000000000000000000000000000000000000000000008a8a8a8a308a610421565b6040516370a0823160e01b81523060048201529093506119c591508a9086906001600160a01b038316906370a0823190602401602060405180830381865afa15801561199c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119c09190612a45565b61220e565b604051632e1a7d4d60e01b8152600481018390527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b158015611a2757600080fd5b505af1158015611a3b573d6000803e3d6000fd5b50505050611a498483611dc1565b50979650505050505050565b42811015611a7657604051630407b05b60e31b815260040160405180910390fd5b50565b6000846001600160a01b03163b11611a9057600080fd5b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b1790529151600092839290881691611af49190612b45565b6000604051808303816000865af19150503d8060008114611b31576040519150601f19603f3d011682016040523d82523d6000602084013e611b36565b606091505b5091509150818015611b60575080511580611b60575080806020019051810190611b609190612adb565b611b6957600080fd5b505050505050565b815160005b81811015611dba576000611bc4858381518110611b9557611b95612998565b602002602001015160000151868481518110611bb357611bb3612998565b602002602001015160200151610afb565b509050600086611bd5846001612b0e565b81518110611be557611be5612998565b60200260200101519050600080836001600160a01b0316888681518110611c0e57611c0e612998565b6020026020010151600001516001600160a01b031614611c3057826000611c34565b6000835b91509150600060018951611c489190612985565b8610611c545787611cc7565b611cc789611c63886001612b0e565b81518110611c7357611c73612998565b6020026020010151600001518a886001611c8d9190612b0e565b81518110611c9d57611c9d612998565b6020026020010151602001518b896001611cb79190612b0e565b8151811061114657611146612998565b9050611d1a898781518110611cde57611cde612998565b6020026020010151600001518a8881518110611cfc57611cfc612998565b6020026020010151602001518b898151811061114657611146612998565b6001600160a01b031663022c0d9f84848460006040519080825280601f01601f191660200182016040528015611d57576020820181803683370190505b506040518563ffffffff1660e01b8152600401611d779493929190612b61565b600060405180830381600087803b158015611d9157600080fd5b505af1158015611da5573d6000803e3d6000fd5b505060019097019650611b7695505050505050565b5050505050565b604080516000808252602082019092526001600160a01b038416908390604051611deb9190612b45565b60006040518083038185875af1925050503d8060008114611e28576040519150601f19603f3d011682016040523d82523d6000602084013e611e2d565b606091505b5050905080611e4f5760405163b12d13eb60e01b815260040160405180910390fd5b505050565b60008083861015611e7857604051636e35977960e11b815260040160405180910390fd5b82851015611e995760405163acee051360e01b815260040160405180910390fd5b6040516379bc57d560e01b81526000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906379bc57d590611eec908d908d908d90600401612a04565b602060405180830381865afa158015611f09573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f2d9190612a28565b90506001600160a01b038116611fd3576040516301b5fcad60e51b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906336bf95a090611f8d908d908d908d90600401612a04565b6020604051808303816000875af1158015611fac573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fd09190612a28565b90505b600080611fe18c8c8c610c4f565b91509150816000148015611ff3575080155b156120035788945087935061208d565b60006120108a848461218b565b9050888111612045578681101561203a57604051630d32418960e21b815260040160405180910390fd5b89955093508361208b565b60006120528a848661218b565b90508a81111561206457612064612af8565b88811015612085576040516323d9bb0560e21b815260040160405180910390fd5b95508894505b505b50505097509795505050505050565b6000816000036120ae57506000919050565b600060016120bb846122f6565b901c6001901b905060018184816120d4576120d4612a75565b048201901c905060018184816120ec576120ec612a75565b048201901c9050600181848161210457612104612a75565b048201901c9050600181848161211c5761211c612a75565b048201901c9050600181848161213457612134612a75565b048201901c9050600181848161214c5761214c612a75565b048201901c9050600181848161216457612164612a75565b048201901c90506121848182858161217e5761217e612a75565b046121f4565b9392505050565b6000836000036121ae57604051632ca2f52b60e11b815260040160405180910390fd5b8215806121b9575081155b156121d75760405163bb55fd2760e01b815260040160405180910390fd5b826121e28386612a5e565b6121ec9190612a8b565b949350505050565b60008183106122035781612205565b825b90505b92915050565b6000836001600160a01b03163b1161222557600080fd5b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b17905291516000928392908716916122819190612b45565b6000604051808303816000865af19150503d80600081146122be576040519150601f19603f3d011682016040523d82523d6000602084013e6122c3565b606091505b50915091508180156122ed5750805115806122ed5750808060200190518101906122ed9190612adb565b611dba57600080fd5b600080608083901c1561230b57608092831c92015b604083901c1561231d57604092831c92015b602083901c1561232f57602092831c92015b601083901c1561234157601092831c92015b600883901c1561235357600892831c92015b600483901c1561236557600492831c92015b600283901c1561237757600292831c92015b600183901c156122085760010192915050565b6001600160a01b0381168114611a7657600080fd5b8015158114611a7657600080fd5b600080600080600080600080610100898b0312156123ca57600080fd5b88356123d58161238a565b975060208901356123e58161238a565b965060408901356123f58161239f565b9550606089013594506080890135935060a0890135925060c089013561241a8161238a565b979a969950949793969295919450919260e001359150565b60008083601f84011261244457600080fd5b50813567ffffffffffffffff81111561245c57600080fd5b602083019150836020606083028501011115610b7f57600080fd5b60008060008060008060a0878903121561249057600080fd5b8635955060208701359450604087013567ffffffffffffffff8111156124b557600080fd5b6124c189828a01612432565b90955093505060608701356124d58161238a565b95989497509295919493608090920135925050565b602080825282518282018190526000918401906040840190835b81811015612522578351835260209384019390920191600101612504565b509095945050505050565b60008060006060848603121561254257600080fd5b833561254d8161238a565b9250602084013561255d8161238a565b9150604084013561256d8161239f565b809150509250925092565b6000806000806080858703121561258e57600080fd5b84356125998161238a565b935060208501356125a98161238a565b925060408501356125b98161239f565b9396929550929360600135925050565b600080604083850312156125dc57600080fd5b82356125e78161238a565b915060208301356125f78161238a565b809150509250929050565b60008060008060008060008060006101208a8c03121561262157600080fd5b893561262c8161238a565b985060208a013561263c8161238a565b975060408a013561264c8161239f565b965060608a0135955060808a0135945060a08a0135935060c08a0135925060e08a01356126788161238a565b989b979a5095989497939692955090936101000135919050565b6000806000806000608086880312156126aa57600080fd5b85359450602086013567ffffffffffffffff8111156126c857600080fd5b6126d488828901612432565b90955093505060408601356126e88161238a565b949793965091946060013592915050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715612738576127386126f9565b604052919050565b60006060828403121561275257600080fd5b6040516060810167ffffffffffffffff81118282101715612775576127756126f9565b60405290508082356127868161238a565b815260208301356127968161238a565b602082015260408301356127a98161239f565b6040919091015292915050565b600080604083850312156127c957600080fd5b82359150602083013567ffffffffffffffff8111156127e757600080fd5b8301601f810185136127f857600080fd5b803567ffffffffffffffff811115612812576128126126f9565b61282160208260051b0161270f565b8082825260208201915060206060840285010192508783111561284357600080fd5b6020840193505b8284101561286f5761285c8885612740565b825260208201915060608401935061284a565b809450505050509250929050565b600080600080600060a0868803121561289557600080fd5b85356128a08161238a565b945060208601356128b08161238a565b935060408601356128c08161239f565b94979396509394606081013594506080013592915050565b600080600080600080600060e0888a0312156128f357600080fd5b87356128fe8161238a565b9650602088013561290e8161239f565b955060408801359450606088013593506080880135925060a08801356129338161238a565b96999598509396929591949193505060c09091013590565b6000806040838503121561295e57600080fd5b505080516020909101519092909150565b634e487b7160e01b600052601160045260246000fd5b818103818111156122085761220861296f565b634e487b7160e01b600052603260045260246000fd5b6000602082840312156129c057600080fd5b81356121848161238a565b6000606082840312156129dd57600080fd5b6122058383612740565b6000602082840312156129f957600080fd5b81356121848161239f565b6001600160a01b039384168152919092166020820152901515604082015260600190565b600060208284031215612a3a57600080fd5b81516121848161238a565b600060208284031215612a5757600080fd5b5051919050565b80820281158282048414176122085761220861296f565b634e487b7160e01b600052601260045260246000fd5b600082612aa857634e487b7160e01b600052601260045260246000fd5b500490565b600080600060608486031215612ac257600080fd5b5050815160208301516040909301519094929350919050565b600060208284031215612aed57600080fd5b81516121848161239f565b634e487b7160e01b600052600160045260246000fd5b808201808211156122085761220861296f565b60005b83811015612b3c578181015183820152602001612b24565b50506000910152565b60008251612b57818460208701612b21565b9190910192915050565b84815283602082015260018060a01b03831660408201526080606082015260008251806080840152612b9a8160a0850160208701612b21565b601f01601f19169190910160a0019594505050505056fea2646970667358221220703a20d765a7928b354554c5db5191fc748ff8d37d8f7661682c377595cec7f264736f6c634300081b003300000000000000000000000031832f2a97fd20664d76cc421207669b55ce4bc0000000000000000000000000fc00000000000000000000000000000000000006

Deployed Bytecode

0x6080604052600436106101025760003560e01c806367ffb66a11610095578063c45a015511610064578063c45a01551461034b578063cefa77991461037f578063d7b0e0a5146103b3578063f41766d8146103d3578063fe411f14146103f357600080fd5b806367ffb66a146102e55780639881fcb4146102f857806398a0fb3c14610318578063b7e0d4c01461033857600080fd5b80634386e63c116100d15780634386e63c1461022a578063544caa561461024a5780635a47ddc31461028a5780635e60dab5146102c557600080fd5b80630dede6c41461015757806318a130861461019157806328eb0b4a146101be5780633fc8cef3146101f657600080fd5b3661015257336001600160a01b037f000000000000000000000000fc000000000000000000000000000000000000061614610150576040516301f180c960e01b815260040160405180910390fd5b005b600080fd5b34801561016357600080fd5b506101776101723660046123ad565b610421565b604080519283526020830191909152015b60405180910390f35b34801561019d57600080fd5b506101b16101ac366004612477565b610548565b60405161018891906124ea565b3480156101ca57600080fd5b506101de6101d936600461252d565b61088b565b6040516001600160a01b039091168152602001610188565b34801561020257600080fd5b506101de7f000000000000000000000000fc0000000000000000000000000000000000000681565b34801561023657600080fd5b50610177610245366004612578565b610994565b34801561025657600080fd5b5061026a6102653660046125c9565b610afb565b604080516001600160a01b03938416815292909116602083015201610188565b34801561029657600080fd5b506102aa6102a5366004612602565b610b86565b60408051938452602084019290925290820152606001610188565b3480156102d157600080fd5b506101776102e036600461252d565b610c4f565b6101b16102f3366004612692565b610d07565b34801561030457600080fd5b506101b16103133660046127b6565b611051565b34801561032457600080fd5b506102aa61033336600461287d565b6112f9565b6102aa6103463660046128d8565b6114f9565b34801561035757600080fd5b506101de7f00000000000000000000000031832f2a97fd20664d76cc421207669b55ce4bc081565b34801561038b57600080fd5b506101de7f00000000000000000000000010499d88bd32af443fc936f67de32be1c8bb374c81565b3480156103bf57600080fd5b506101776103ce3660046128d8565b611723565b3480156103df57600080fd5b506101b16103ee366004612477565b611801565b3480156103ff57600080fd5b5061041361040e3660046128d8565b611910565b604051908152602001610188565b6000808261042e81611a55565b600061043b8c8c8c61088b565b90506104498133838c611a79565b60405163226bf2d160e21b81526001600160a01b03878116600483015260009182918416906389afcb449060240160408051808303816000875af1158015610495573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104b9919061294b565b9150915060006104c98f8f610afb565b509050806001600160a01b03168f6001600160a01b0316146104ec5781836104ef565b82825b90975095508a871015610515576040516323d9bb0560e21b815260040160405180910390fd5b8986101561053657604051630d32418960e21b815260040160405180910390fd5b50505050509850989650505050505050565b60608161055481611a55565b6001600160a01b037f000000000000000000000000fc0000000000000000000000000000000000000616868661058b600182612985565b81811061059a5761059a612998565b90506060020160200160208101906105b291906129ae565b6001600160a01b0316146105d9576040516320db826760e01b815260040160405180910390fd5b610635888787808060200260200160405190810160405280939291908181526020016000905b8282101561062b5761061c606083028601368190038101906129cb565b815260200190600101906105ff565b5050505050611051565b91508682600184516106479190612985565b8151811061065757610657612998565b6020026020010151101561067e576040516342301c2360e01b815260040160405180910390fd5b61074d8686600081811061069457610694612998565b6106aa92602060609092020190810191506129ae565b3361072d898960008181106106c1576106c1612998565b6106d792602060609092020190810191506129ae565b8a8a60008181106106ea576106ea612998565b905060600201602001602081019061070291906129ae565b8b8b600081811061071557610715612998565b90506060020160400160208101906101d991906129e7565b8560008151811061074057610740612998565b6020026020010151611a79565b6107aa828787808060200260200160405190810160405280939291908181526020016000905b8282101561079f57610790606083028601368190038101906129cb565b81526020019060010190610773565b505050505030611b71565b7f000000000000000000000000fc000000000000000000000000000000000000066001600160a01b0316632e1a7d4d83600185516107e89190612985565b815181106107f8576107f8612998565b60200260200101516040518263ffffffff1660e01b815260040161081e91815260200190565b600060405180830381600087803b15801561083857600080fd5b505af115801561084c573d6000803e3d6000fd5b505050506108808483600185516108639190612985565b8151811061087357610873612998565b6020026020010151611dc1565b509695505050505050565b600080600061089a8686610afb565b6040516bffffffffffffffffffffffff19606084811b8216602084015283901b16603482015286151560f81b6048820152919350915060009060490160408051601f198184030181529082905280516020909101207f00000000000000000000000031832f2a97fd20664d76cc421207669b55ce4bc060388301526f5af43d82803e903d91602b57fd5bf3ff60248301527f00000000000000000000000010499d88bd32af443fc936f67de32be1c8bb374c6014830152733d602d80600a3d3981f3363d3d373d3d3d363d738252605882018190526037600c83012060788301526055604390920191909120909150979650505050505050565b60008060007f00000000000000000000000031832f2a97fd20664d76cc421207669b55ce4bc06001600160a01b03166379bc57d58888886040518463ffffffff1660e01b81526004016109e993929190612a04565b602060405180830381865afa158015610a06573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a2a9190612a28565b90506001600160a01b038116610a47576000809250925050610af2565b600080610a55898989610c4f565b915091506000836001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a99573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610abd9190612a45565b905080610aca8489612a5e565b610ad49190612a8b565b955080610ae18389612a5e565b610aeb9190612a8b565b9450505050505b94509492505050565b600080826001600160a01b0316846001600160a01b031603610b3057604051633295f3fd60e21b815260040160405180910390fd5b826001600160a01b0316846001600160a01b031610610b50578284610b53565b83835b90925090506001600160a01b038216610b7f5760405163d92e233d60e01b815260040160405180910390fd5b9250929050565b600080600083610b9581611a55565b610ba48d8d8d8d8d8d8d611e54565b90945092506000610bb68e8e8e61088b565b9050610bc48e338388611a79565b610bd08d338387611a79565b6040516335313c2160e11b81526001600160a01b038881166004830152821690636a627842906024016020604051808303816000875af1158015610c18573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c3c9190612a45565b9250505099509950999650505050505050565b6000806000610c5e8686610afb565b509050600080610c6f88888861088b565b6001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa158015610cac573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cd09190612aad565b5091509150826001600160a01b0316886001600160a01b031614610cf5578082610cf8565b81815b90999098509650505050505050565b606081610d1381611a55565b7f000000000000000000000000fc000000000000000000000000000000000000066001600160a01b031686866000818110610d5057610d50612998565b610d6692602060609092020190810191506129ae565b6001600160a01b031614610d8d576040516320db826760e01b815260040160405180910390fd5b610ddf348787808060200260200160405190810160405280939291908181526020016000905b8282101561062b57610dd0606083028601368190038101906129cb565b81526020019060010190610db3565b9150868260018451610df19190612985565b81518110610e0157610e01612998565b60200260200101511015610e28576040516342301c2360e01b815260040160405180910390fd5b7f000000000000000000000000fc000000000000000000000000000000000000066001600160a01b031663d0e30db083600081518110610e6a57610e6a612998565b60200260200101516040518263ffffffff1660e01b81526004016000604051808303818588803b158015610e9d57600080fd5b505af1158015610eb1573d6000803e3d6000fd5b50505050507f000000000000000000000000fc000000000000000000000000000000000000066001600160a01b031663a9059cbb610f4f88886000818110610efb57610efb612998565b610f1192602060609092020190810191506129ae565b89896000818110610f2457610f24612998565b9050606002016020016020810190610f3c91906129ae565b8a8a600081811061071557610715612998565b84600081518110610f6257610f62612998565b60200260200101516040518363ffffffff1660e01b8152600401610f9b9291906001600160a01b03929092168252602082015260400190565b6020604051808303816000875af1158015610fba573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fde9190612adb565b610fea57610fea612af8565b611047828787808060200260200160405190810160405280939291908181526020016000905b8282101561103c5761102d606083028601368190038101906129cb565b81526020019060010190611010565b505050505086611b71565b5095945050505050565b6060600182511015611076576040516320db826760e01b815260040160405180910390fd5b8151611083906001612b0e565b67ffffffffffffffff81111561109b5761109b6126f9565b6040519080825280602002602001820160405280156110c4578160200160208202803683370190505b50905082816000815181106110db576110db612998565b6020908102919091010152815160005b818110156112f157600061115785838151811061110a5761110a612998565b60200260200101516000015186848151811061112857611128612998565b60200260200101516020015187858151811061114657611146612998565b60200260200101516040015161088b565b604051635b16ebb760e01b81526001600160a01b0380831660048301529192507f00000000000000000000000031832f2a97fd20664d76cc421207669b55ce4bc090911690635b16ebb790602401602060405180830381865afa1580156111c2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111e69190612adb565b156112cf57806001600160a01b031663f140a35a85848151811061120c5761120c612998565b602002602001015187858151811061122657611226612998565b6020026020010151600001516040518363ffffffff1660e01b81526004016112619291909182526001600160a01b0316602082015260400190565b602060405180830381865afa15801561127e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112a29190612a45565b846112ae846001612b0e565b815181106112be576112be612998565b6020026020010181815250506112e8565b6040516320db826760e01b815260040160405180910390fd5b506001016110eb565b505092915050565b6000806000807f00000000000000000000000031832f2a97fd20664d76cc421207669b55ce4bc06001600160a01b03166379bc57d58a8a8a6040518463ffffffff1660e01b815260040161134f93929190612a04565b602060405180830381865afa15801561136c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113909190612a28565b9050600080806001600160a01b0384161561141a57836001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113e3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114079190612a45565b90506114148c8c8c610c4f565b90935091505b82158015611426575081155b15611457578896508795506103e8611446611441888a612a5e565b61209c565b6114509190612985565b94506114ea565b60006114648a858561218b565b90508881116114ac578997509550856114a584611481848b612a5e565b61148b9190612a8b565b84611496858b612a5e565b6114a09190612a8b565b6121f4565b95506114e8565b60006114b98a858761218b565b98508997508890506114e4856114cf8584612a5e565b6114d99190612a8b565b85611496868c612a5e565b9650505b505b50505050955095509592505050565b60008060008361150881611a55565b6115378b7f000000000000000000000000fc000000000000000000000000000000000000068c8c348d8d611e54565b909450925060006115698c7f000000000000000000000000fc000000000000000000000000000000000000068d61088b565b90506115778c338388611a79565b7f000000000000000000000000fc000000000000000000000000000000000000066001600160a01b031663d0e30db0856040518263ffffffff1660e01b81526004016000604051808303818588803b1580156115d257600080fd5b505af11580156115e6573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b038581166004830152602482018990527f000000000000000000000000fc0000000000000000000000000000000000000616935063a9059cbb925060440190506020604051808303816000875af115801561165b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061167f9190612adb565b61168b5761168b612af8565b6040516335313c2160e11b81526001600160a01b038881166004830152821690636a627842906024016020604051808303816000875af11580156116d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116f79190612a45565b925083341115611714576117143361170f8634612985565b611dc1565b50509750975097945050505050565b6000808261173081611a55565b6117608a7f000000000000000000000000fc000000000000000000000000000000000000068b8b8b8b308b610421565b90935091506117708a868561220e565b604051632e1a7d4d60e01b8152600481018390527f000000000000000000000000fc000000000000000000000000000000000000066001600160a01b031690632e1a7d4d90602401600060405180830381600087803b1580156117d257600080fd5b505af11580156117e6573d6000803e3d6000fd5b505050506117f48583611dc1565b5097509795505050505050565b60608161180d81611a55565b61185f888787808060200260200160405190810160405280939291908181526020016000905b8282101561062b57611850606083028601368190038101906129cb565b81526020019060010190611833565b91508682600184516118719190612985565b8151811061188157611881612998565b602002602001015110156118a8576040516342301c2360e01b815260040160405180910390fd5b6118be8686600081811061069457610694612998565b610880828787808060200260200160405190810160405280939291908181526020016000905b8282101561103c57611901606083028601368190038101906129cb565b815260200190600101906118e4565b60008161191c81611a55565b61194c897f000000000000000000000000fc000000000000000000000000000000000000068a8a8a8a308a610421565b6040516370a0823160e01b81523060048201529093506119c591508a9086906001600160a01b038316906370a0823190602401602060405180830381865afa15801561199c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119c09190612a45565b61220e565b604051632e1a7d4d60e01b8152600481018390527f000000000000000000000000fc000000000000000000000000000000000000066001600160a01b031690632e1a7d4d90602401600060405180830381600087803b158015611a2757600080fd5b505af1158015611a3b573d6000803e3d6000fd5b50505050611a498483611dc1565b50979650505050505050565b42811015611a7657604051630407b05b60e31b815260040160405180910390fd5b50565b6000846001600160a01b03163b11611a9057600080fd5b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b1790529151600092839290881691611af49190612b45565b6000604051808303816000865af19150503d8060008114611b31576040519150601f19603f3d011682016040523d82523d6000602084013e611b36565b606091505b5091509150818015611b60575080511580611b60575080806020019051810190611b609190612adb565b611b6957600080fd5b505050505050565b815160005b81811015611dba576000611bc4858381518110611b9557611b95612998565b602002602001015160000151868481518110611bb357611bb3612998565b602002602001015160200151610afb565b509050600086611bd5846001612b0e565b81518110611be557611be5612998565b60200260200101519050600080836001600160a01b0316888681518110611c0e57611c0e612998565b6020026020010151600001516001600160a01b031614611c3057826000611c34565b6000835b91509150600060018951611c489190612985565b8610611c545787611cc7565b611cc789611c63886001612b0e565b81518110611c7357611c73612998565b6020026020010151600001518a886001611c8d9190612b0e565b81518110611c9d57611c9d612998565b6020026020010151602001518b896001611cb79190612b0e565b8151811061114657611146612998565b9050611d1a898781518110611cde57611cde612998565b6020026020010151600001518a8881518110611cfc57611cfc612998565b6020026020010151602001518b898151811061114657611146612998565b6001600160a01b031663022c0d9f84848460006040519080825280601f01601f191660200182016040528015611d57576020820181803683370190505b506040518563ffffffff1660e01b8152600401611d779493929190612b61565b600060405180830381600087803b158015611d9157600080fd5b505af1158015611da5573d6000803e3d6000fd5b505060019097019650611b7695505050505050565b5050505050565b604080516000808252602082019092526001600160a01b038416908390604051611deb9190612b45565b60006040518083038185875af1925050503d8060008114611e28576040519150601f19603f3d011682016040523d82523d6000602084013e611e2d565b606091505b5050905080611e4f5760405163b12d13eb60e01b815260040160405180910390fd5b505050565b60008083861015611e7857604051636e35977960e11b815260040160405180910390fd5b82851015611e995760405163acee051360e01b815260040160405180910390fd5b6040516379bc57d560e01b81526000906001600160a01b037f00000000000000000000000031832f2a97fd20664d76cc421207669b55ce4bc016906379bc57d590611eec908d908d908d90600401612a04565b602060405180830381865afa158015611f09573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f2d9190612a28565b90506001600160a01b038116611fd3576040516301b5fcad60e51b81526001600160a01b037f00000000000000000000000031832f2a97fd20664d76cc421207669b55ce4bc016906336bf95a090611f8d908d908d908d90600401612a04565b6020604051808303816000875af1158015611fac573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fd09190612a28565b90505b600080611fe18c8c8c610c4f565b91509150816000148015611ff3575080155b156120035788945087935061208d565b60006120108a848461218b565b9050888111612045578681101561203a57604051630d32418960e21b815260040160405180910390fd5b89955093508361208b565b60006120528a848661218b565b90508a81111561206457612064612af8565b88811015612085576040516323d9bb0560e21b815260040160405180910390fd5b95508894505b505b50505097509795505050505050565b6000816000036120ae57506000919050565b600060016120bb846122f6565b901c6001901b905060018184816120d4576120d4612a75565b048201901c905060018184816120ec576120ec612a75565b048201901c9050600181848161210457612104612a75565b048201901c9050600181848161211c5761211c612a75565b048201901c9050600181848161213457612134612a75565b048201901c9050600181848161214c5761214c612a75565b048201901c9050600181848161216457612164612a75565b048201901c90506121848182858161217e5761217e612a75565b046121f4565b9392505050565b6000836000036121ae57604051632ca2f52b60e11b815260040160405180910390fd5b8215806121b9575081155b156121d75760405163bb55fd2760e01b815260040160405180910390fd5b826121e28386612a5e565b6121ec9190612a8b565b949350505050565b60008183106122035781612205565b825b90505b92915050565b6000836001600160a01b03163b1161222557600080fd5b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b17905291516000928392908716916122819190612b45565b6000604051808303816000865af19150503d80600081146122be576040519150601f19603f3d011682016040523d82523d6000602084013e6122c3565b606091505b50915091508180156122ed5750805115806122ed5750808060200190518101906122ed9190612adb565b611dba57600080fd5b600080608083901c1561230b57608092831c92015b604083901c1561231d57604092831c92015b602083901c1561232f57602092831c92015b601083901c1561234157601092831c92015b600883901c1561235357600892831c92015b600483901c1561236557600492831c92015b600283901c1561237757600292831c92015b600183901c156122085760010192915050565b6001600160a01b0381168114611a7657600080fd5b8015158114611a7657600080fd5b600080600080600080600080610100898b0312156123ca57600080fd5b88356123d58161238a565b975060208901356123e58161238a565b965060408901356123f58161239f565b9550606089013594506080890135935060a0890135925060c089013561241a8161238a565b979a969950949793969295919450919260e001359150565b60008083601f84011261244457600080fd5b50813567ffffffffffffffff81111561245c57600080fd5b602083019150836020606083028501011115610b7f57600080fd5b60008060008060008060a0878903121561249057600080fd5b8635955060208701359450604087013567ffffffffffffffff8111156124b557600080fd5b6124c189828a01612432565b90955093505060608701356124d58161238a565b95989497509295919493608090920135925050565b602080825282518282018190526000918401906040840190835b81811015612522578351835260209384019390920191600101612504565b509095945050505050565b60008060006060848603121561254257600080fd5b833561254d8161238a565b9250602084013561255d8161238a565b9150604084013561256d8161239f565b809150509250925092565b6000806000806080858703121561258e57600080fd5b84356125998161238a565b935060208501356125a98161238a565b925060408501356125b98161239f565b9396929550929360600135925050565b600080604083850312156125dc57600080fd5b82356125e78161238a565b915060208301356125f78161238a565b809150509250929050565b60008060008060008060008060006101208a8c03121561262157600080fd5b893561262c8161238a565b985060208a013561263c8161238a565b975060408a013561264c8161239f565b965060608a0135955060808a0135945060a08a0135935060c08a0135925060e08a01356126788161238a565b989b979a5095989497939692955090936101000135919050565b6000806000806000608086880312156126aa57600080fd5b85359450602086013567ffffffffffffffff8111156126c857600080fd5b6126d488828901612432565b90955093505060408601356126e88161238a565b949793965091946060013592915050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715612738576127386126f9565b604052919050565b60006060828403121561275257600080fd5b6040516060810167ffffffffffffffff81118282101715612775576127756126f9565b60405290508082356127868161238a565b815260208301356127968161238a565b602082015260408301356127a98161239f565b6040919091015292915050565b600080604083850312156127c957600080fd5b82359150602083013567ffffffffffffffff8111156127e757600080fd5b8301601f810185136127f857600080fd5b803567ffffffffffffffff811115612812576128126126f9565b61282160208260051b0161270f565b8082825260208201915060206060840285010192508783111561284357600080fd5b6020840193505b8284101561286f5761285c8885612740565b825260208201915060608401935061284a565b809450505050509250929050565b600080600080600060a0868803121561289557600080fd5b85356128a08161238a565b945060208601356128b08161238a565b935060408601356128c08161239f565b94979396509394606081013594506080013592915050565b600080600080600080600060e0888a0312156128f357600080fd5b87356128fe8161238a565b9650602088013561290e8161239f565b955060408801359450606088013593506080880135925060a08801356129338161238a565b96999598509396929591949193505060c09091013590565b6000806040838503121561295e57600080fd5b505080516020909101519092909150565b634e487b7160e01b600052601160045260246000fd5b818103818111156122085761220861296f565b634e487b7160e01b600052603260045260246000fd5b6000602082840312156129c057600080fd5b81356121848161238a565b6000606082840312156129dd57600080fd5b6122058383612740565b6000602082840312156129f957600080fd5b81356121848161239f565b6001600160a01b039384168152919092166020820152901515604082015260600190565b600060208284031215612a3a57600080fd5b81516121848161238a565b600060208284031215612a5757600080fd5b5051919050565b80820281158282048414176122085761220861296f565b634e487b7160e01b600052601260045260246000fd5b600082612aa857634e487b7160e01b600052601260045260246000fd5b500490565b600080600060608486031215612ac257600080fd5b5050815160208301516040909301519094929350919050565b600060208284031215612aed57600080fd5b81516121848161239f565b634e487b7160e01b600052600160045260246000fd5b808201808211156122085761220861296f565b60005b83811015612b3c578181015183820152602001612b24565b50506000910152565b60008251612b57818460208701612b21565b9190910192915050565b84815283602082015260018060a01b03831660408201526080606082015260008251806080840152612b9a8160a0850160208701612b21565b601f01601f19169190910160a0019594505050505056fea2646970667358221220703a20d765a7928b354554c5db5191fc748ff8d37d8f7661682c377595cec7f264736f6c634300081b0033

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

00000000000000000000000031832f2a97fd20664d76cc421207669b55ce4bc0000000000000000000000000fc00000000000000000000000000000000000006

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

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


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
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.