The Modulus Blockchain Explorer

Contract Address Details

0xa8d173aE30353D773a2a2F2A45C1f9bFbf112d16

Overview

CULT BALANCE

0 CULT

USD VALUE

More Info

CONTRACT CREATOR

TOKEN TRACKER

Multi Chain

MULTICHAIN ADDRESSES

Contract name:

StoneSwapRouter

Optimization enabled

true

Compiler version

v0.8.9+commit.e5eed63a

Optimization runs

200

EVM Version

default

Verified at

2023-07-31T19:42:06.449442Z

Constructor Arguments
0x0000000000000000000000000e47c8606a2ce2149e2ba6ab3bc73af3a0b79c69000000000000000000000000127876278b76e2c224e27c209d22daf0854bdcbb

Arg [0] (address) : 0x0e47c8606a2ce2149e2ba6ab3bc73af3a0b79c69
Arg [1] (address) : 0x127876278b76e2c224e27c209d22daf0854bdcbb

                
contracts/StoneSwapRouter.sol
// SPDX-License-Identifier: GPL-3.0-or-later

pragma solidity 0.8.9;

//solhint-disable not-rely-on-time
//solhint-disable var-name-mixedcase
//solhint-disable reason-string

import "./interfaces/IStoneSwapFactory.sol";
import "./libraries/TransferHelper.sol";

import "./interfaces/IStoneSwapRouter.sol";
import "./libraries/StoneSwapLibrary.sol";
import "./interfaces/IERC20.sol";
import "./interfaces/IWETH.sol";

contract StoneSwapRouter is IStoneSwapRouter {
    address public immutable override factory;
    address public immutable override WETH;

    modifier ensure(uint256 deadline) {
        require(deadline >= block.timestamp, "StoneSwapRouter: EXPIRED");
        _;
    }

    constructor(address _factory, address _WETH) {
        factory = _factory;
        WETH = _WETH;
    }

    receive() external payable {
        assert(msg.sender == WETH); // only accept ETH via fallback from the WETH contract
    }

    // **** ADD LIQUIDITY ****
    function _addLiquidity(
        address tokenA,
        address tokenB,
        uint256 amountADesired,
        uint256 amountBDesired,
        uint256 amountAMin,
        uint256 amountBMin
    ) internal virtual returns (uint256 amountA, uint256 amountB) {
        // create the pair if it doesn't exist yet
        if (IStoneSwapFactory(factory).getPair(tokenA, tokenB) == address(0)) {
            IStoneSwapFactory(factory).createPair(tokenA, tokenB);
        }
        (uint256 reserveA, uint256 reserveB) = StoneSwapLibrary.getReserves(
            factory,
            tokenA,
            tokenB
        );
        if (reserveA == 0 && reserveB == 0) {
            (amountA, amountB) = (amountADesired, amountBDesired);
        } else {
            uint256 amountBOptimal = StoneSwapLibrary.quote(
                amountADesired,
                reserveA,
                reserveB
            );
            if (amountBOptimal <= amountBDesired) {
                require(
                    amountBOptimal >= amountBMin,
                    "StoneSwapRouter: INSUFFICIENT_B_AMOUNT"
                );
                (amountA, amountB) = (amountADesired, amountBOptimal);
            } else {
                uint256 amountAOptimal = StoneSwapLibrary.quote(
                    amountBDesired,
                    reserveB,
                    reserveA
                );
                assert(amountAOptimal <= amountADesired);
                require(
                    amountAOptimal >= amountAMin,
                    "StoneSwapRouter: INSUFFICIENT_A_AMOUNT"
                );
                (amountA, amountB) = (amountAOptimal, amountBDesired);
            }
        }
    }

    function addLiquidity(
        address tokenA,
        address tokenB,
        uint256 amountADesired,
        uint256 amountBDesired,
        uint256 amountAMin,
        uint256 amountBMin,
        address to,
        uint256 deadline
    )
        external
        virtual
        override
        ensure(deadline)
        returns (uint256 amountA, uint256 amountB, uint256 liquidity)
    {
        (amountA, amountB) = _addLiquidity(
            tokenA,
            tokenB,
            amountADesired,
            amountBDesired,
            amountAMin,
            amountBMin
        );
        address pair = StoneSwapLibrary.pairFor(factory, tokenA, tokenB);
        TransferHelper.safeTransferFrom(tokenA, msg.sender, pair, amountA);
        TransferHelper.safeTransferFrom(tokenB, msg.sender, pair, amountB);
        liquidity = IStoneSwapPair(pair).mint(to);
    }

    function addLiquidityETH(
        address token,
        uint256 amountTokenDesired,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline
    )
        external
        payable
        virtual
        override
        ensure(deadline)
        returns (uint256 amountToken, uint256 amountETH, uint256 liquidity)
    {
        (amountToken, amountETH) = _addLiquidity(
            token,
            WETH,
            amountTokenDesired,
            msg.value,
            amountTokenMin,
            amountETHMin
        );
        address pair = StoneSwapLibrary.pairFor(factory, token, WETH);
        TransferHelper.safeTransferFrom(token, msg.sender, pair, amountToken);
        IWETH(WETH).deposit{value: amountETH}();
        assert(IWETH(WETH).transfer(pair, amountETH));
        liquidity = IStoneSwapPair(pair).mint(to);
        // refund dust eth, if any
        if (msg.value > amountETH)
            TransferHelper.safeTransferETH(msg.sender, msg.value - amountETH);
    }

    // **** REMOVE LIQUIDITY ****
    function removeLiquidity(
        address tokenA,
        address tokenB,
        uint256 liquidity,
        uint256 amountAMin,
        uint256 amountBMin,
        address to,
        uint256 deadline
    )
        public
        virtual
        override
        ensure(deadline)
        returns (uint256 amountA, uint256 amountB)
    {
        address pair = StoneSwapLibrary.pairFor(factory, tokenA, tokenB);
        IStoneSwapPair(pair).transferFrom(msg.sender, pair, liquidity); // send liquidity to pair
        (uint256 amount0, uint256 amount1) = IStoneSwapPair(pair).burn(to);
        (address token0, ) = StoneSwapLibrary.sortTokens(tokenA, tokenB);
        (amountA, amountB) = tokenA == token0
            ? (amount0, amount1)
            : (amount1, amount0);
        require(
            amountA >= amountAMin,
            "StoneSwapRouter: INSUFFICIENT_A_AMOUNT"
        );
        require(
            amountB >= amountBMin,
            "StoneSwapRouter: INSUFFICIENT_B_AMOUNT"
        );
    }

    function removeLiquidityETH(
        address token,
        uint256 liquidity,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline
    )
        public
        virtual
        override
        ensure(deadline)
        returns (uint256 amountToken, uint256 amountETH)
    {
        (amountToken, amountETH) = removeLiquidity(
            token,
            WETH,
            liquidity,
            amountTokenMin,
            amountETHMin,
            address(this),
            deadline
        );
        TransferHelper.safeTransfer(token, to, amountToken);
        IWETH(WETH).withdraw(amountETH);
        TransferHelper.safeTransferETH(to, amountETH);
    }

    function removeLiquidityWithPermit(
        address tokenA,
        address tokenB,
        uint256 liquidity,
        uint256 amountAMin,
        uint256 amountBMin,
        address to,
        uint256 deadline,
        bool approveMax,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external virtual override returns (uint256 amountA, uint256 amountB) {
        address pair = StoneSwapLibrary.pairFor(factory, tokenA, tokenB);
        uint256 value = approveMax ? type(uint256).max : liquidity;
        IStoneSwapPair(pair).permit(
            msg.sender,
            address(this),
            value,
            deadline,
            v,
            r,
            s
        );
        (amountA, amountB) = removeLiquidity(
            tokenA,
            tokenB,
            liquidity,
            amountAMin,
            amountBMin,
            to,
            deadline
        );
    }

    function removeLiquidityETHWithPermit(
        address token,
        uint256 liquidity,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline,
        bool approveMax,
        uint8 v,
        bytes32 r,
        bytes32 s
    )
        external
        virtual
        override
        returns (uint256 amountToken, uint256 amountETH)
    {
        address pair = StoneSwapLibrary.pairFor(factory, token, WETH);
        uint256 value = approveMax ? type(uint256).max : liquidity;
        IStoneSwapPair(pair).permit(
            msg.sender,
            address(this),
            value,
            deadline,
            v,
            r,
            s
        );
        (amountToken, amountETH) = removeLiquidityETH(
            token,
            liquidity,
            amountTokenMin,
            amountETHMin,
            to,
            deadline
        );
    }

    // **** REMOVE LIQUIDITY (supporting fee-on-transfer tokens) ****
    function removeLiquidityETHSupportingFeeOnTransferTokens(
        address token,
        uint256 liquidity,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline
    ) public virtual override ensure(deadline) returns (uint256 amountETH) {
        (, amountETH) = removeLiquidity(
            token,
            WETH,
            liquidity,
            amountTokenMin,
            amountETHMin,
            address(this),
            deadline
        );
        TransferHelper.safeTransfer(
            token,
            to,
            IERC20(token).balanceOf(address(this))
        );
        IWETH(WETH).withdraw(amountETH);
        TransferHelper.safeTransferETH(to, amountETH);
    }

    function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
        address token,
        uint256 liquidity,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline,
        bool approveMax,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external virtual override returns (uint256 amountETH) {
        address pair = StoneSwapLibrary.pairFor(factory, token, WETH);
        uint256 value = approveMax ? type(uint256).max : liquidity;
        IStoneSwapPair(pair).permit(
            msg.sender,
            address(this),
            value,
            deadline,
            v,
            r,
            s
        );
        amountETH = removeLiquidityETHSupportingFeeOnTransferTokens(
            token,
            liquidity,
            amountTokenMin,
            amountETHMin,
            to,
            deadline
        );
    }

    // **** SWAP ****
    // requires the initial amount to have already been sent to the first pair
    function _swap(
        uint256[] memory amounts,
        address[] memory path,
        address _to
    ) internal virtual {
        for (uint256 i; i < path.length - 1; i++) {
            (address input, address output) = (path[i], path[i + 1]);
            (address token0, ) = StoneSwapLibrary.sortTokens(input, output);
            uint256 amountOut = amounts[i + 1];
            (uint256 amount0Out, uint256 amount1Out) = input == token0
                ? (uint256(0), amountOut)
                : (amountOut, uint256(0));
            address to = i < path.length - 2
                ? StoneSwapLibrary.pairFor(factory, output, path[i + 2])
                : _to;
            IStoneSwapPair(StoneSwapLibrary.pairFor(factory, input, output))
                .swap(amount0Out, amount1Out, to, new bytes(0));
        }
    }

    function swapExactTokensForTokens(
        uint256 amountIn,
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    )
        external
        virtual
        override
        ensure(deadline)
        returns (uint256[] memory amounts)
    {
        amounts = StoneSwapLibrary.getAmountsOut(factory, amountIn, path);
        require(
            amounts[amounts.length - 1] >= amountOutMin,
            "StoneSwapRouter: INSUFFICIENT_OUTPUT_AMOUNT"
        );
        TransferHelper.safeTransferFrom(
            path[0],
            msg.sender,
            StoneSwapLibrary.pairFor(factory, path[0], path[1]),
            amounts[0]
        );
        _swap(amounts, path, to);
    }

    function swapTokensForExactTokens(
        uint256 amountOut,
        uint256 amountInMax,
        address[] calldata path,
        address to,
        uint256 deadline
    )
        external
        virtual
        override
        ensure(deadline)
        returns (uint256[] memory amounts)
    {
        amounts = StoneSwapLibrary.getAmountsIn(factory, amountOut, path);
        require(
            amounts[0] <= amountInMax,
            "StoneSwapRouter: EXCESSIVE_INPUT_AMOUNT"
        );
        TransferHelper.safeTransferFrom(
            path[0],
            msg.sender,
            StoneSwapLibrary.pairFor(factory, path[0], path[1]),
            amounts[0]
        );
        _swap(amounts, path, to);
    }

    function swapExactETHForTokens(
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    )
        external
        payable
        virtual
        override
        ensure(deadline)
        returns (uint256[] memory amounts)
    {
        require(path[0] == WETH, "StoneSwapRouter: INVALID_PATH");
        amounts = StoneSwapLibrary.getAmountsOut(factory, msg.value, path);
        require(
            amounts[amounts.length - 1] >= amountOutMin,
            "StoneSwapRouter: INSUFFICIENT_OUTPUT_AMOUNT"
        );
        IWETH(WETH).deposit{value: amounts[0]}();
        assert(
            IWETH(WETH).transfer(
                StoneSwapLibrary.pairFor(factory, path[0], path[1]),
                amounts[0]
            )
        );
        _swap(amounts, path, to);
    }

    function swapTokensForExactETH(
        uint256 amountOut,
        uint256 amountInMax,
        address[] calldata path,
        address to,
        uint256 deadline
    )
        external
        virtual
        override
        ensure(deadline)
        returns (uint256[] memory amounts)
    {
        require(path[path.length - 1] == WETH, "StoneSwapRouter: INVALID_PATH");
        amounts = StoneSwapLibrary.getAmountsIn(factory, amountOut, path);
        require(
            amounts[0] <= amountInMax,
            "StoneSwapRouter: EXCESSIVE_INPUT_AMOUNT"
        );
        TransferHelper.safeTransferFrom(
            path[0],
            msg.sender,
            StoneSwapLibrary.pairFor(factory, path[0], path[1]),
            amounts[0]
        );
        _swap(amounts, path, address(this));
        IWETH(WETH).withdraw(amounts[amounts.length - 1]);
        TransferHelper.safeTransferETH(to, amounts[amounts.length - 1]);
    }

    function swapExactTokensForETH(
        uint256 amountIn,
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    )
        external
        virtual
        override
        ensure(deadline)
        returns (uint256[] memory amounts)
    {
        require(path[path.length - 1] == WETH, "StoneSwapRouter: INVALID_PATH");
        amounts = StoneSwapLibrary.getAmountsOut(factory, amountIn, path);
        require(
            amounts[amounts.length - 1] >= amountOutMin,
            "StoneSwapRouter: INSUFFICIENT_OUTPUT_AMOUNT"
        );
        TransferHelper.safeTransferFrom(
            path[0],
            msg.sender,
            StoneSwapLibrary.pairFor(factory, path[0], path[1]),
            amounts[0]
        );
        _swap(amounts, path, address(this));
        IWETH(WETH).withdraw(amounts[amounts.length - 1]);
        TransferHelper.safeTransferETH(to, amounts[amounts.length - 1]);
    }

    function swapETHForExactTokens(
        uint256 amountOut,
        address[] calldata path,
        address to,
        uint256 deadline
    )
        external
        payable
        virtual
        override
        ensure(deadline)
        returns (uint256[] memory amounts)
    {
        require(path[0] == WETH, "StoneSwapRouter: INVALID_PATH");
        amounts = StoneSwapLibrary.getAmountsIn(factory, amountOut, path);
        require(
            amounts[0] <= msg.value,
            "StoneSwapRouter: EXCESSIVE_INPUT_AMOUNT"
        );
        IWETH(WETH).deposit{value: amounts[0]}();
        assert(
            IWETH(WETH).transfer(
                StoneSwapLibrary.pairFor(factory, path[0], path[1]),
                amounts[0]
            )
        );
        _swap(amounts, path, to);
        // refund dust eth, if any
        if (msg.value > amounts[0])
            TransferHelper.safeTransferETH(msg.sender, msg.value - amounts[0]);
    }

    // **** SWAP (supporting fee-on-transfer tokens) ****
    // requires the initial amount to have already been sent to the first pair
    function _swapSupportingFeeOnTransferTokens(
        address[] memory path,
        address _to
    ) internal virtual {
        for (uint256 i; i < path.length - 1; i++) {
            (address input, address output) = (path[i], path[i + 1]);
            (address token0, ) = StoneSwapLibrary.sortTokens(input, output);
            IStoneSwapPair pair = IStoneSwapPair(
                StoneSwapLibrary.pairFor(factory, input, output)
            );
            uint256 amountInput;
            uint256 amountOutput;
            {
                // scope to avoid stack too deep errors
                (uint256 reserve0, uint256 reserve1, ) = pair.getReserves();
                (uint256 reserveInput, uint256 reserveOutput) = input == token0
                    ? (reserve0, reserve1)
                    : (reserve1, reserve0);
                amountInput =
                    IERC20(input).balanceOf(address(pair)) -
                    reserveInput;
                amountOutput = StoneSwapLibrary.getAmountOut(
                    amountInput,
                    reserveInput,
                    reserveOutput
                );
            }
            (uint256 amount0Out, uint256 amount1Out) = input == token0
                ? (uint256(0), amountOutput)
                : (amountOutput, uint256(0));
            address to = i < path.length - 2
                ? StoneSwapLibrary.pairFor(factory, output, path[i + 2])
                : _to;
            pair.swap(amount0Out, amount1Out, to, new bytes(0));
        }
    }

    function swapExactTokensForTokensSupportingFeeOnTransferTokens(
        uint256 amountIn,
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external virtual override ensure(deadline) {
        TransferHelper.safeTransferFrom(
            path[0],
            msg.sender,
            StoneSwapLibrary.pairFor(factory, path[0], path[1]),
            amountIn
        );
        uint256 balanceBefore = IERC20(path[path.length - 1]).balanceOf(to);
        _swapSupportingFeeOnTransferTokens(path, to);
        require(
            IERC20(path[path.length - 1]).balanceOf(to) - balanceBefore >=
                amountOutMin,
            "StoneSwapRouter: INSUFFICIENT_OUTPUT_AMOUNT"
        );
    }

    function swapExactETHForTokensSupportingFeeOnTransferTokens(
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external payable virtual override ensure(deadline) {
        require(path[0] == WETH, "StoneSwapRouter: INVALID_PATH");
        uint256 amountIn = msg.value;
        IWETH(WETH).deposit{value: amountIn}();
        assert(
            IWETH(WETH).transfer(
                StoneSwapLibrary.pairFor(factory, path[0], path[1]),
                amountIn
            )
        );
        uint256 balanceBefore = IERC20(path[path.length - 1]).balanceOf(to);
        _swapSupportingFeeOnTransferTokens(path, to);
        require(
            IERC20(path[path.length - 1]).balanceOf(to) - balanceBefore >=
                amountOutMin,
            "StoneSwapRouter: INSUFFICIENT_OUTPUT_AMOUNT"
        );
    }

    function swapExactTokensForETHSupportingFeeOnTransferTokens(
        uint256 amountIn,
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external virtual override ensure(deadline) {
        require(path[path.length - 1] == WETH, "StoneSwapRouter: INVALID_PATH");
        TransferHelper.safeTransferFrom(
            path[0],
            msg.sender,
            StoneSwapLibrary.pairFor(factory, path[0], path[1]),
            amountIn
        );
        _swapSupportingFeeOnTransferTokens(path, address(this));
        uint256 amountOut = IERC20(WETH).balanceOf(address(this));
        require(
            amountOut >= amountOutMin,
            "StoneSwapRouter: INSUFFICIENT_OUTPUT_AMOUNT"
        );
        IWETH(WETH).withdraw(amountOut);
        TransferHelper.safeTransferETH(to, amountOut);
    }

    // **** LIBRARY FUNCTIONS ****
    function quote(
        uint256 amountA,
        uint256 reserveA,
        uint256 reserveB
    ) public pure virtual override returns (uint256 amountB) {
        return StoneSwapLibrary.quote(amountA, reserveA, reserveB);
    }

    function getAmountOut(
        uint256 amountIn,
        uint256 reserveIn,
        uint256 reserveOut
    ) public pure virtual override returns (uint256 amountOut) {
        return StoneSwapLibrary.getAmountOut(amountIn, reserveIn, reserveOut);
    }

    function getAmountIn(
        uint256 amountOut,
        uint256 reserveIn,
        uint256 reserveOut
    ) public pure virtual override returns (uint256 amountIn) {
        return StoneSwapLibrary.getAmountIn(amountOut, reserveIn, reserveOut);
    }

    function getAmountsOut(
        uint256 amountIn,
        address[] memory path
    ) public view virtual override returns (uint256[] memory amounts) {
        return StoneSwapLibrary.getAmountsOut(factory, amountIn, path);
    }

    function getAmountsIn(
        uint256 amountOut,
        address[] memory path
    ) public view virtual override returns (uint256[] memory amounts) {
        return StoneSwapLibrary.getAmountsIn(factory, amountOut, path);
    }
}
          
contracts/interfaces/IERC20.sol
// SPDX-License-Identifier: GPL-3.0-or-later

//solhint-disable-next-line compiler-version
pragma solidity >=0.5.0;

interface IERC20 {
    event Approval(
        address indexed owner,
        address indexed spender,
        uint256 value
    );
    event Transfer(address indexed from, address indexed to, uint256 value);

    function name() external view returns (string memory);

    function symbol() external view returns (string memory);

    function decimals() external view returns (uint8);

    function totalSupply() external view returns (uint256);

    function balanceOf(address owner) external view returns (uint256);

    function allowance(
        address owner,
        address spender
    ) external view returns (uint256);

    function approve(address spender, uint256 value) external returns (bool);

    function transfer(address to, uint256 value) external returns (bool);

    function transferFrom(
        address from,
        address to,
        uint256 value
    ) external returns (bool);
}
            
contracts/interfaces/IStoneSwapERC20.sol
// SPDX-License-Identifier: GPL-3.0-or-later

//solhint-disable-next-line compiler-version
pragma solidity >=0.5.0;

//solhint-disable func-name-mixedcase
interface IStoneSwapERC20 {
    event Approval(
        address indexed owner,
        address indexed spender,
        uint256 value
    );
    event Transfer(address indexed from, address indexed to, uint256 value);

    function name() external pure returns (string memory);

    function symbol() external pure returns (string memory);

    function decimals() external pure returns (uint8);

    function totalSupply() external view returns (uint256);

    function balanceOf(address owner) external view returns (uint256);

    function allowance(
        address owner,
        address spender
    ) external view returns (uint256);

    function approve(address spender, uint256 value) external returns (bool);

    function transfer(address to, uint256 value) external returns (bool);

    function transferFrom(
        address from,
        address to,
        uint256 value
    ) external returns (bool);

    function DOMAIN_SEPARATOR() external view returns (bytes32);

    function PERMIT_TYPEHASH() external pure returns (bytes32);

    function nonces(address owner) external view returns (uint256);

    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;
}
            
contracts/interfaces/IStoneSwapFactory.sol
// SPDX-License-Identifier: GPL-3.0-or-later

//solhint-disable-next-line compiler-version
pragma solidity >=0.5.0;

interface IStoneSwapFactory {
    event PairCreated(
        address indexed token0,
        address indexed token1,
        address pair,
        uint256
    );

    function feeTo() external view returns (address);

    function cultFeeTo() external view returns (address);

    function feeToSetter() external view returns (address);

    function getPair(
        address tokenA,
        address tokenB
    ) external view returns (address pair);

    function allPairs(uint256) external view returns (address pair);

    function allPairsLength() external view returns (uint256);

    function createPair(
        address tokenA,
        address tokenB
    ) external returns (address pair);

    function setFeeTo(address) external;

    function setCultFeeTo(address) external;

    function setFeeSetter(address) external;
}
            
contracts/interfaces/IStoneSwapPair.sol
// SPDX-License-Identifier: GPL-3.0-or-later

//solhint-disable-next-line compiler-version
pragma solidity >=0.5.0;

//solhint-disable func-name-mixedcase

import "./IStoneSwapERC20.sol";

interface IStoneSwapPair is IStoneSwapERC20 {
    event Mint(address indexed sender, uint256 amount0, uint256 amount1);
    event Burn(
        address indexed sender,
        uint256 amount0,
        uint256 amount1,
        address indexed to
    );
    event Swap(
        address indexed sender,
        uint256 amount0In,
        uint256 amount1In,
        uint256 amount0Out,
        uint256 amount1Out,
        address indexed to
    );
    event Sync(uint112 reserve0, uint112 reserve1);

    function MINIMUM_LIQUIDITY() external pure returns (uint256);

    function factory() external view returns (address);

    function token0() external view returns (address);

    function token1() external view returns (address);

    function getReserves()
        external
        view
        returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);

    function price0CumulativeLast() external view returns (uint256);

    function price1CumulativeLast() external view returns (uint256);

    function kLast() external view returns (uint256);

    function mint(address to) external returns (uint256 liquidity);

    function burn(
        address to
    ) external returns (uint256 amount0, uint256 amount1);

    function swap(
        uint256 amount0Out,
        uint256 amount1Out,
        address to,
        bytes calldata data
    ) external;

    function skim(address to) external;

    function sync() external;

    function initialize(address, address) external;
}
            
contracts/interfaces/IStoneSwapRouter.sol
// SPDX-License-Identifier: GPL-3.0-or-later

pragma solidity 0.8.9;

import "./IStoneSwapRouter01.sol";

interface IStoneSwapRouter is IStoneSwapRouter01 {
    function removeLiquidityETHSupportingFeeOnTransferTokens(
        address token,
        uint256 liquidity,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline
    ) external returns (uint256 amountETH);

    function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
        address token,
        uint256 liquidity,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline,
        bool approveMax,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external returns (uint256 amountETH);

    function swapExactTokensForTokensSupportingFeeOnTransferTokens(
        uint256 amountIn,
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external;

    function swapExactETHForTokensSupportingFeeOnTransferTokens(
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external payable;

    function swapExactTokensForETHSupportingFeeOnTransferTokens(
        uint256 amountIn,
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external;
}
            
contracts/interfaces/IStoneSwapRouter01.sol
// SPDX-License-Identifier: GPL-3.0-or-later

pragma solidity 0.8.9;

//solhint-disable func-name-mixedcase

interface IStoneSwapRouter01 {
    function factory() external view returns (address);

    function WETH() external view returns (address);

    function addLiquidity(
        address tokenA,
        address tokenB,
        uint256 amountADesired,
        uint256 amountBDesired,
        uint256 amountAMin,
        uint256 amountBMin,
        address to,
        uint256 deadline
    ) external returns (uint256 amountA, uint256 amountB, uint256 liquidity);

    function addLiquidityETH(
        address token,
        uint256 amountTokenDesired,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline
    )
        external
        payable
        returns (uint256 amountToken, uint256 amountETH, uint256 liquidity);

    function removeLiquidity(
        address tokenA,
        address tokenB,
        uint256 liquidity,
        uint256 amountAMin,
        uint256 amountBMin,
        address to,
        uint256 deadline
    ) external returns (uint256 amountA, uint256 amountB);

    function removeLiquidityETH(
        address token,
        uint256 liquidity,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline
    ) external returns (uint256 amountToken, uint256 amountETH);

    function removeLiquidityWithPermit(
        address tokenA,
        address tokenB,
        uint256 liquidity,
        uint256 amountAMin,
        uint256 amountBMin,
        address to,
        uint256 deadline,
        bool approveMax,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external returns (uint256 amountA, uint256 amountB);

    function removeLiquidityETHWithPermit(
        address token,
        uint256 liquidity,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline,
        bool approveMax,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external returns (uint256 amountToken, uint256 amountETH);

    function swapExactTokensForTokens(
        uint256 amountIn,
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external returns (uint256[] memory amounts);

    function swapTokensForExactTokens(
        uint256 amountOut,
        uint256 amountInMax,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external returns (uint256[] memory amounts);

    function swapExactETHForTokens(
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external payable returns (uint256[] memory amounts);

    function swapTokensForExactETH(
        uint256 amountOut,
        uint256 amountInMax,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external returns (uint256[] memory amounts);

    function swapExactTokensForETH(
        uint256 amountIn,
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external returns (uint256[] memory amounts);

    function swapETHForExactTokens(
        uint256 amountOut,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external payable returns (uint256[] memory amounts);

    function quote(
        uint256 amountA,
        uint256 reserveA,
        uint256 reserveB
    ) external pure returns (uint256 amountB);

    function getAmountOut(
        uint256 amountIn,
        uint256 reserveIn,
        uint256 reserveOut
    ) external pure returns (uint256 amountOut);

    function getAmountIn(
        uint256 amountOut,
        uint256 reserveIn,
        uint256 reserveOut
    ) external pure returns (uint256 amountIn);

    function getAmountsOut(
        uint256 amountIn,
        address[] calldata path
    ) external view returns (uint256[] memory amounts);

    function getAmountsIn(
        uint256 amountOut,
        address[] calldata path
    ) external view returns (uint256[] memory amounts);
}
            
contracts/interfaces/IWETH.sol
// SPDX-License-Identifier: GPL-3.0-or-later

pragma solidity 0.8.9;

interface IWETH {
    function deposit() external payable;

    function transfer(address to, uint256 value) external returns (bool);

    function withdraw(uint256) external;
}
            
contracts/libraries/StoneSwapLibrary.sol
// SPDX-License-Identifier: GPL-3.0-or-later

pragma solidity 0.8.9;

//solhint-disable reason-string

import "../interfaces/IStoneSwapPair.sol";

library StoneSwapLibrary {
    // returns sorted token addresses, used to handle return values from pairs sorted in this order
    function sortTokens(
        address tokenA,
        address tokenB
    ) internal pure returns (address token0, address token1) {
        require(tokenA != tokenB, "StoneSwapLibrary: IDENTICAL_ADDRESSES");
        (token0, token1) = tokenA < tokenB
            ? (tokenA, tokenB)
            : (tokenB, tokenA);
        require(token0 != address(0), "StoneSwapLibrary: ZERO_ADDRESS");
    }

    // calculates the CREATE2 address for a pair without making any external calls
    function pairFor(
        address factory,
        address tokenA,
        address tokenB
    ) internal pure returns (address pair) {
        (address token0, address token1) = sortTokens(tokenA, tokenB);
        pair = address(
            uint160(
                uint256(
                    keccak256(
                        abi.encodePacked(
                            bytes1(0xff),
                            factory,
                            keccak256(abi.encodePacked(token0, token1)),
                            hex"2bf0cd46972a88aec59c98ddaba3cfd678559e2ccdbc618335079ba2f94aad93" // init code hash
                        )
                    )
                )
            )
        );
    }

    // fetches and sorts the reserves for a pair
    function getReserves(
        address factory,
        address tokenA,
        address tokenB
    ) internal view returns (uint256 reserveA, uint256 reserveB) {
        (address token0, ) = sortTokens(tokenA, tokenB);
        (uint256 reserve0, uint256 reserve1, ) = IStoneSwapPair(
            pairFor(factory, tokenA, tokenB)
        ).getReserves();
        (reserveA, reserveB) = tokenA == token0
            ? (reserve0, reserve1)
            : (reserve1, reserve0);
    }

    // given some amount of an asset and pair reserves, returns an equivalent amount of the other asset
    function quote(
        uint256 amountA,
        uint256 reserveA,
        uint256 reserveB
    ) internal pure returns (uint256 amountB) {
        require(amountA > 0, "StoneSwapLibrary: INSUFFICIENT_AMOUNT");
        require(
            reserveA > 0 && reserveB > 0,
            "StoneSwapLibrary: INSUFFICIENT_LIQUIDITY"
        );
        amountB = (amountA * reserveB) / reserveA;
    }

    // given an input amount of an asset and pair reserves, returns the maximum output amount of the other asset
    function getAmountOut(
        uint256 amountIn,
        uint256 reserveIn,
        uint256 reserveOut
    ) internal pure returns (uint256 amountOut) {
        require(amountIn > 0, "StoneSwapLibrary: INSUFFICIENT_INPUT_AMOUNT");
        require(
            reserveIn > 0 && reserveOut > 0,
            "StoneSwapLibrary: INSUFFICIENT_LIQUIDITY"
        );
        uint256 amountInWithFee = amountIn * 996;
        uint256 numerator = amountInWithFee * reserveOut;
        uint256 denominator = reserveIn * 1000 + amountInWithFee;
        amountOut = numerator / denominator;
    }

    // given an output amount of an asset and pair reserves, returns a required input amount of the other asset
    function getAmountIn(
        uint256 amountOut,
        uint256 reserveIn,
        uint256 reserveOut
    ) internal pure returns (uint256 amountIn) {
        require(amountOut > 0, "StoneSwapLibrary: INSUFFICIENT_OUTPUT_AMOUNT");
        require(
            reserveIn > 0 && reserveOut > 0,
            "StoneSwapLibrary: INSUFFICIENT_LIQUIDITY"
        );
        uint256 numerator = reserveIn * amountOut * 1000;
        uint256 denominator = (reserveOut - amountOut) * 996;
        amountIn = numerator / denominator + 1;
    }

    // performs chained getAmountOut calculations on any number of pairs
    function getAmountsOut(
        address factory,
        uint256 amountIn,
        address[] memory path
    ) internal view returns (uint256[] memory amounts) {
        require(path.length >= 2, "StoneSwapLibrary: INVALID_PATH");
        amounts = new uint256[](path.length);
        amounts[0] = amountIn;
        for (uint256 i; i < path.length - 1; i++) {
            (uint256 reserveIn, uint256 reserveOut) = getReserves(
                factory,
                path[i],
                path[i + 1]
            );
            amounts[i + 1] = getAmountOut(amounts[i], reserveIn, reserveOut);
        }
    }

    // performs chained getAmountIn calculations on any number of pairs
    function getAmountsIn(
        address factory,
        uint256 amountOut,
        address[] memory path
    ) internal view returns (uint256[] memory amounts) {
        require(path.length >= 2, "StoneSwapLibrary: INVALID_PATH");
        amounts = new uint256[](path.length);
        amounts[amounts.length - 1] = amountOut;
        for (uint256 i = path.length - 1; i > 0; i--) {
            (uint256 reserveIn, uint256 reserveOut) = getReserves(
                factory,
                path[i - 1],
                path[i]
            );
            amounts[i - 1] = getAmountIn(amounts[i], reserveIn, reserveOut);
        }
    }
}
            
contracts/libraries/TransferHelper.sol
// SPDX-License-Identifier: GPL-3.0-or-later

pragma solidity 0.8.9;

//solhint-disable avoid-low-level-calls
//solhint-disable reason-string

// helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false
library TransferHelper {
    function safeApprove(address token, address to, uint256 value) internal {
        // bytes4(keccak256(bytes('approve(address,uint256)')));
        (bool success, bytes memory data) = token.call(
            abi.encodeWithSelector(0x095ea7b3, to, value)
        );
        require(
            success && (data.length == 0 || abi.decode(data, (bool))),
            "TransferHelper::safeApprove: approve failed"
        );
    }

    function safeTransfer(address token, address to, uint256 value) internal {
        // bytes4(keccak256(bytes('transfer(address,uint256)')));
        (bool success, bytes memory data) = token.call(
            abi.encodeWithSelector(0xa9059cbb, to, value)
        );
        require(
            success && (data.length == 0 || abi.decode(data, (bool))),
            "TransferHelper::safeTransfer: transfer failed"
        );
    }

    function safeTransferFrom(
        address token,
        address from,
        address to,
        uint256 value
    ) internal {
        // bytes4(keccak256(bytes('transferFrom(address,address,uint256)')));
        (bool success, bytes memory data) = token.call(
            abi.encodeWithSelector(0x23b872dd, from, to, value)
        );
        require(
            success && (data.length == 0 || abi.decode(data, (bool))),
            "TransferHelper::transferFrom: transferFrom failed"
        );
    }

    function safeTransferETH(address to, uint256 value) internal {
        (bool success, ) = to.call{value: value}(new bytes(0));
        require(
            success,
            "TransferHelper::safeTransferETH: ETH transfer failed"
        );
    }
}
            
Contract ABI
[{"type":"constructor","inputs":[{"type":"address","name":"_factory","internalType":"address"},{"type":"address","name":"_WETH","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"WETH","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"amountA","internalType":"uint256"},{"type":"uint256","name":"amountB","internalType":"uint256"},{"type":"uint256","name":"liquidity","internalType":"uint256"}],"name":"addLiquidity","inputs":[{"type":"address","name":"tokenA","internalType":"address"},{"type":"address","name":"tokenB","internalType":"address"},{"type":"uint256","name":"amountADesired","internalType":"uint256"},{"type":"uint256","name":"amountBDesired","internalType":"uint256"},{"type":"uint256","name":"amountAMin","internalType":"uint256"},{"type":"uint256","name":"amountBMin","internalType":"uint256"},{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"deadline","internalType":"uint256"}]},{"type":"function","stateMutability":"payable","outputs":[{"type":"uint256","name":"amountToken","internalType":"uint256"},{"type":"uint256","name":"amountETH","internalType":"uint256"},{"type":"uint256","name":"liquidity","internalType":"uint256"}],"name":"addLiquidityETH","inputs":[{"type":"address","name":"token","internalType":"address"},{"type":"uint256","name":"amountTokenDesired","internalType":"uint256"},{"type":"uint256","name":"amountTokenMin","internalType":"uint256"},{"type":"uint256","name":"amountETHMin","internalType":"uint256"},{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"deadline","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"factory","inputs":[]},{"type":"function","stateMutability":"pure","outputs":[{"type":"uint256","name":"amountIn","internalType":"uint256"}],"name":"getAmountIn","inputs":[{"type":"uint256","name":"amountOut","internalType":"uint256"},{"type":"uint256","name":"reserveIn","internalType":"uint256"},{"type":"uint256","name":"reserveOut","internalType":"uint256"}]},{"type":"function","stateMutability":"pure","outputs":[{"type":"uint256","name":"amountOut","internalType":"uint256"}],"name":"getAmountOut","inputs":[{"type":"uint256","name":"amountIn","internalType":"uint256"},{"type":"uint256","name":"reserveIn","internalType":"uint256"},{"type":"uint256","name":"reserveOut","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256[]","name":"amounts","internalType":"uint256[]"}],"name":"getAmountsIn","inputs":[{"type":"uint256","name":"amountOut","internalType":"uint256"},{"type":"address[]","name":"path","internalType":"address[]"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256[]","name":"amounts","internalType":"uint256[]"}],"name":"getAmountsOut","inputs":[{"type":"uint256","name":"amountIn","internalType":"uint256"},{"type":"address[]","name":"path","internalType":"address[]"}]},{"type":"function","stateMutability":"pure","outputs":[{"type":"uint256","name":"amountB","internalType":"uint256"}],"name":"quote","inputs":[{"type":"uint256","name":"amountA","internalType":"uint256"},{"type":"uint256","name":"reserveA","internalType":"uint256"},{"type":"uint256","name":"reserveB","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"amountA","internalType":"uint256"},{"type":"uint256","name":"amountB","internalType":"uint256"}],"name":"removeLiquidity","inputs":[{"type":"address","name":"tokenA","internalType":"address"},{"type":"address","name":"tokenB","internalType":"address"},{"type":"uint256","name":"liquidity","internalType":"uint256"},{"type":"uint256","name":"amountAMin","internalType":"uint256"},{"type":"uint256","name":"amountBMin","internalType":"uint256"},{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"deadline","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"amountToken","internalType":"uint256"},{"type":"uint256","name":"amountETH","internalType":"uint256"}],"name":"removeLiquidityETH","inputs":[{"type":"address","name":"token","internalType":"address"},{"type":"uint256","name":"liquidity","internalType":"uint256"},{"type":"uint256","name":"amountTokenMin","internalType":"uint256"},{"type":"uint256","name":"amountETHMin","internalType":"uint256"},{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"deadline","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"amountETH","internalType":"uint256"}],"name":"removeLiquidityETHSupportingFeeOnTransferTokens","inputs":[{"type":"address","name":"token","internalType":"address"},{"type":"uint256","name":"liquidity","internalType":"uint256"},{"type":"uint256","name":"amountTokenMin","internalType":"uint256"},{"type":"uint256","name":"amountETHMin","internalType":"uint256"},{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"deadline","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"amountToken","internalType":"uint256"},{"type":"uint256","name":"amountETH","internalType":"uint256"}],"name":"removeLiquidityETHWithPermit","inputs":[{"type":"address","name":"token","internalType":"address"},{"type":"uint256","name":"liquidity","internalType":"uint256"},{"type":"uint256","name":"amountTokenMin","internalType":"uint256"},{"type":"uint256","name":"amountETHMin","internalType":"uint256"},{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"deadline","internalType":"uint256"},{"type":"bool","name":"approveMax","internalType":"bool"},{"type":"uint8","name":"v","internalType":"uint8"},{"type":"bytes32","name":"r","internalType":"bytes32"},{"type":"bytes32","name":"s","internalType":"bytes32"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"amountETH","internalType":"uint256"}],"name":"removeLiquidityETHWithPermitSupportingFeeOnTransferTokens","inputs":[{"type":"address","name":"token","internalType":"address"},{"type":"uint256","name":"liquidity","internalType":"uint256"},{"type":"uint256","name":"amountTokenMin","internalType":"uint256"},{"type":"uint256","name":"amountETHMin","internalType":"uint256"},{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"deadline","internalType":"uint256"},{"type":"bool","name":"approveMax","internalType":"bool"},{"type":"uint8","name":"v","internalType":"uint8"},{"type":"bytes32","name":"r","internalType":"bytes32"},{"type":"bytes32","name":"s","internalType":"bytes32"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"amountA","internalType":"uint256"},{"type":"uint256","name":"amountB","internalType":"uint256"}],"name":"removeLiquidityWithPermit","inputs":[{"type":"address","name":"tokenA","internalType":"address"},{"type":"address","name":"tokenB","internalType":"address"},{"type":"uint256","name":"liquidity","internalType":"uint256"},{"type":"uint256","name":"amountAMin","internalType":"uint256"},{"type":"uint256","name":"amountBMin","internalType":"uint256"},{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"deadline","internalType":"uint256"},{"type":"bool","name":"approveMax","internalType":"bool"},{"type":"uint8","name":"v","internalType":"uint8"},{"type":"bytes32","name":"r","internalType":"bytes32"},{"type":"bytes32","name":"s","internalType":"bytes32"}]},{"type":"function","stateMutability":"payable","outputs":[{"type":"uint256[]","name":"amounts","internalType":"uint256[]"}],"name":"swapETHForExactTokens","inputs":[{"type":"uint256","name":"amountOut","internalType":"uint256"},{"type":"address[]","name":"path","internalType":"address[]"},{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"deadline","internalType":"uint256"}]},{"type":"function","stateMutability":"payable","outputs":[{"type":"uint256[]","name":"amounts","internalType":"uint256[]"}],"name":"swapExactETHForTokens","inputs":[{"type":"uint256","name":"amountOutMin","internalType":"uint256"},{"type":"address[]","name":"path","internalType":"address[]"},{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"deadline","internalType":"uint256"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"swapExactETHForTokensSupportingFeeOnTransferTokens","inputs":[{"type":"uint256","name":"amountOutMin","internalType":"uint256"},{"type":"address[]","name":"path","internalType":"address[]"},{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"deadline","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256[]","name":"amounts","internalType":"uint256[]"}],"name":"swapExactTokensForETH","inputs":[{"type":"uint256","name":"amountIn","internalType":"uint256"},{"type":"uint256","name":"amountOutMin","internalType":"uint256"},{"type":"address[]","name":"path","internalType":"address[]"},{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"deadline","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"swapExactTokensForETHSupportingFeeOnTransferTokens","inputs":[{"type":"uint256","name":"amountIn","internalType":"uint256"},{"type":"uint256","name":"amountOutMin","internalType":"uint256"},{"type":"address[]","name":"path","internalType":"address[]"},{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"deadline","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256[]","name":"amounts","internalType":"uint256[]"}],"name":"swapExactTokensForTokens","inputs":[{"type":"uint256","name":"amountIn","internalType":"uint256"},{"type":"uint256","name":"amountOutMin","internalType":"uint256"},{"type":"address[]","name":"path","internalType":"address[]"},{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"deadline","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"swapExactTokensForTokensSupportingFeeOnTransferTokens","inputs":[{"type":"uint256","name":"amountIn","internalType":"uint256"},{"type":"uint256","name":"amountOutMin","internalType":"uint256"},{"type":"address[]","name":"path","internalType":"address[]"},{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"deadline","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256[]","name":"amounts","internalType":"uint256[]"}],"name":"swapTokensForExactETH","inputs":[{"type":"uint256","name":"amountOut","internalType":"uint256"},{"type":"uint256","name":"amountInMax","internalType":"uint256"},{"type":"address[]","name":"path","internalType":"address[]"},{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"deadline","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256[]","name":"amounts","internalType":"uint256[]"}],"name":"swapTokensForExactTokens","inputs":[{"type":"uint256","name":"amountOut","internalType":"uint256"},{"type":"uint256","name":"amountInMax","internalType":"uint256"},{"type":"address[]","name":"path","internalType":"address[]"},{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"deadline","internalType":"uint256"}]},{"type":"receive"}]
              
Deployed ByteCode
0x60806040526004361061014f5760003560e01c80638803dbee116100b6578063c45a01551161006f578063c45a01551461041a578063d06ca61f1461044e578063ded9382a1461046e578063e8e337001461048e578063f305d719146104c9578063fb3bdb41146104dc57600080fd5b80638803dbee1461033b578063ad5c46481461035b578063ad615dec146103a7578063af2979eb146103c7578063b6f9de95146103e7578063baa2abde146103fa57600080fd5b80634a25d94a116101085780634a25d94a146102885780635b0d5984146102a85780635c11d795146102c8578063791ac947146102e85780637ff36ab51461030857806385f8c2591461031b57600080fd5b806302751cec14610193578063054d50d4146101cd57806318cbafe5146101fb5780631f00ca74146102285780632195995c1461024857806338ed17391461026857600080fd5b3661018e57336001600160a01b037f000000000000000000000000127876278b76e2c224e27c209d22daf0854bdcbb161461018c5761018c613772565b005b600080fd5b34801561019f57600080fd5b506101b36101ae3660046137b0565b6104ef565b604080519283526020830191909152015b60405180910390f35b3480156101d957600080fd5b506101ed6101e836600461380e565b6105eb565b6040519081526020016101c4565b34801561020757600080fd5b5061021b61021636600461387f565b610600565b6040516101c491906138f2565b34801561023457600080fd5b5061021b61024336600461394c565b61092f565b34801561025457600080fd5b506101b3610263366004613a3c565b610963565b34801561027457600080fd5b5061021b61028336600461387f565b610a3c565b34801561029457600080fd5b5061021b6102a336600461387f565b610b5a565b3480156102b457600080fd5b506101ed6102c3366004613ae6565b610c98565b3480156102d457600080fd5b5061018c6102e336600461387f565b610d85565b3480156102f457600080fd5b5061018c61030336600461387f565b611006565b61021b610316366004613b7c565b61123c565b34801561032757600080fd5b506101ed61033636600461380e565b611564565b34801561034757600080fd5b5061021b61035636600461387f565b611571565b34801561036757600080fd5b5061038f7f000000000000000000000000127876278b76e2c224e27c209d22daf0854bdcbb81565b6040516001600160a01b0390911681526020016101c4565b3480156103b357600080fd5b506101ed6103c236600461380e565b61162e565b3480156103d357600080fd5b506101ed6103e23660046137b0565b61163b565b61018c6103f5366004613b7c565b611799565b34801561040657600080fd5b506101b3610415366004613be3565b611aee565b34801561042657600080fd5b5061038f7f0000000000000000000000000e47c8606a2ce2149e2ba6ab3bc73af3a0b79c6981565b34801561045a57600080fd5b5061021b61046936600461394c565b611cd4565b34801561047a57600080fd5b506101b3610489366004613ae6565b611d01565b34801561049a57600080fd5b506104ae6104a9366004613c55565b611df4565b604080519384526020840192909252908201526060016101c4565b6104ae6104d73660046137b0565b611f01565b61021b6104ea366004613b7c565b61217e565b600080824281101561051c5760405162461bcd60e51b815260040161051390613cd1565b60405180910390fd5b61054b897f000000000000000000000000127876278b76e2c224e27c209d22daf0854bdcbb8a8a8a308a611aee565b909350915061055b8986856124dc565b604051632e1a7d4d60e01b8152600481018390527f000000000000000000000000127876278b76e2c224e27c209d22daf0854bdcbb6001600160a01b031690632e1a7d4d90602401600060405180830381600087803b1580156105bd57600080fd5b505af11580156105d1573d6000803e3d6000fd5b505050506105df858361260d565b50965096945050505050565b60006105f88484846126ec565b949350505050565b606081428110156106235760405162461bcd60e51b815260040161051390613cd1565b6001600160a01b037f000000000000000000000000127876278b76e2c224e27c209d22daf0854bdcbb16868661065a600182613d1e565b81811061066957610669613d35565b905060200201602081019061067e9190613d4b565b6001600160a01b0316146106a45760405162461bcd60e51b815260040161051390613d68565b6107027f0000000000000000000000000e47c8606a2ce2149e2ba6ab3bc73af3a0b79c69898888808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506127cb92505050565b91508682600184516107149190613d1e565b8151811061072457610724613d35565b6020026020010151101561074a5760405162461bcd60e51b815260040161051390613d9f565b61080f8686600081811061076057610760613d35565b90506020020160208101906107759190613d4b565b336107ef7f0000000000000000000000000e47c8606a2ce2149e2ba6ab3bc73af3a0b79c698a8a60008181106107ad576107ad613d35565b90506020020160208101906107c29190613d4b565b8b8b60018181106107d5576107d5613d35565b90506020020160208101906107ea9190613d4b565b612956565b8560008151811061080257610802613d35565b6020026020010151612a1a565b61084e82878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250309250612b58915050565b7f000000000000000000000000127876278b76e2c224e27c209d22daf0854bdcbb6001600160a01b0316632e1a7d4d836001855161088c9190613d1e565b8151811061089c5761089c613d35565b60200260200101516040518263ffffffff1660e01b81526004016108c291815260200190565b600060405180830381600087803b1580156108dc57600080fd5b505af11580156108f0573d6000803e3d6000fd5b505050506109248483600185516109079190613d1e565b8151811061091757610917613d35565b602002602001015161260d565b509695505050505050565b606061095c7f0000000000000000000000000e47c8606a2ce2149e2ba6ab3bc73af3a0b79c698484612d60565b9392505050565b60008060006109937f0000000000000000000000000e47c8606a2ce2149e2ba6ab3bc73af3a0b79c698f8f612956565b90506000876109a2578c6109a6565b6000195b60405163d505accf60e01b81529091506001600160a01b0383169063d505accf906109e1903390309086908f908e908e908e90600401613dea565b600060405180830381600087803b1580156109fb57600080fd5b505af1158015610a0f573d6000803e3d6000fd5b50505050610a228f8f8f8f8f8f8f611aee565b809450819550505050509b509b9950505050505050505050565b60608142811015610a5f5760405162461bcd60e51b815260040161051390613cd1565b610abd7f0000000000000000000000000e47c8606a2ce2149e2ba6ab3bc73af3a0b79c69898888808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506127cb92505050565b9150868260018451610acf9190613d1e565b81518110610adf57610adf613d35565b60200260200101511015610b055760405162461bcd60e51b815260040161051390613d9f565b610b1b8686600081811061076057610760613d35565b61092482878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250899250612b58915050565b60608142811015610b7d5760405162461bcd60e51b815260040161051390613cd1565b6001600160a01b037f000000000000000000000000127876278b76e2c224e27c209d22daf0854bdcbb168686610bb4600182613d1e565b818110610bc357610bc3613d35565b9050602002016020810190610bd89190613d4b565b6001600160a01b031614610bfe5760405162461bcd60e51b815260040161051390613d68565b610c5c7f0000000000000000000000000e47c8606a2ce2149e2ba6ab3bc73af3a0b79c6989888880806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250612d6092505050565b91508682600081518110610c7257610c72613d35565b6020026020010151111561074a5760405162461bcd60e51b815260040161051390613e2b565b600080610ce67f0000000000000000000000000e47c8606a2ce2149e2ba6ab3bc73af3a0b79c698d7f000000000000000000000000127876278b76e2c224e27c209d22daf0854bdcbb612956565b9050600086610cf5578b610cf9565b6000195b60405163d505accf60e01b81529091506001600160a01b0383169063d505accf90610d34903390309086908e908d908d908d90600401613dea565b600060405180830381600087803b158015610d4e57600080fd5b505af1158015610d62573d6000803e3d6000fd5b50505050610d748d8d8d8d8d8d61163b565b9d9c50505050505050505050505050565b8042811015610da65760405162461bcd60e51b815260040161051390613cd1565b610e3785856000818110610dbc57610dbc613d35565b9050602002016020810190610dd19190613d4b565b33610e317f0000000000000000000000000e47c8606a2ce2149e2ba6ab3bc73af3a0b79c6989896000818110610e0957610e09613d35565b9050602002016020810190610e1e9190613d4b565b8a8a60018181106107d5576107d5613d35565b8a612a1a565b60008585610e46600182613d1e565b818110610e5557610e55613d35565b9050602002016020810190610e6a9190613d4b565b6040516370a0823160e01b81526001600160a01b03868116600483015291909116906370a082319060240160206040518083038186803b158015610ead57600080fd5b505afa158015610ec1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ee59190613e72565b9050610f25868680806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250889250612ee1915050565b86818787610f34600182613d1e565b818110610f4357610f43613d35565b9050602002016020810190610f589190613d4b565b6040516370a0823160e01b81526001600160a01b03888116600483015291909116906370a08231906024015b60206040518083038186803b158015610f9c57600080fd5b505afa158015610fb0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fd49190613e72565b610fde9190613d1e565b1015610ffc5760405162461bcd60e51b815260040161051390613d9f565b5050505050505050565b80428110156110275760405162461bcd60e51b815260040161051390613cd1565b6001600160a01b037f000000000000000000000000127876278b76e2c224e27c209d22daf0854bdcbb16858561105e600182613d1e565b81811061106d5761106d613d35565b90506020020160208101906110829190613d4b565b6001600160a01b0316146110a85760405162461bcd60e51b815260040161051390613d68565b6110be85856000818110610dbc57610dbc613d35565b6110fc858580806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250309250612ee1915050565b6040516370a0823160e01b81523060048201526000907f000000000000000000000000127876278b76e2c224e27c209d22daf0854bdcbb6001600160a01b0316906370a082319060240160206040518083038186803b15801561115e57600080fd5b505afa158015611172573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111969190613e72565b9050868110156111b85760405162461bcd60e51b815260040161051390613d9f565b604051632e1a7d4d60e01b8152600481018290527f000000000000000000000000127876278b76e2c224e27c209d22daf0854bdcbb6001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561121a57600080fd5b505af115801561122e573d6000803e3d6000fd5b50505050610ffc848261260d565b6060814281101561125f5760405162461bcd60e51b815260040161051390613cd1565b7f000000000000000000000000127876278b76e2c224e27c209d22daf0854bdcbb6001600160a01b03168686600081811061129c5761129c613d35565b90506020020160208101906112b19190613d4b565b6001600160a01b0316146112d75760405162461bcd60e51b815260040161051390613d68565b6113357f0000000000000000000000000e47c8606a2ce2149e2ba6ab3bc73af3a0b79c69348888808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506127cb92505050565b91508682600184516113479190613d1e565b8151811061135757611357613d35565b6020026020010151101561137d5760405162461bcd60e51b815260040161051390613d9f565b7f000000000000000000000000127876278b76e2c224e27c209d22daf0854bdcbb6001600160a01b031663d0e30db0836000815181106113bf576113bf613d35565b60200260200101516040518263ffffffff1660e01b81526004016000604051808303818588803b1580156113f257600080fd5b505af1158015611406573d6000803e3d6000fd5b50505050507f000000000000000000000000127876278b76e2c224e27c209d22daf0854bdcbb6001600160a01b031663a9059cbb6114717f0000000000000000000000000e47c8606a2ce2149e2ba6ab3bc73af3a0b79c6989896000818110610e0957610e09613d35565b8460008151811061148457611484613d35565b60200260200101516040518363ffffffff1660e01b81526004016114bd9291906001600160a01b03929092168252602082015260400190565b602060405180830381600087803b1580156114d757600080fd5b505af11580156114eb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061150f9190613e8b565b61151b5761151b613772565b61155a82878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250899250612b58915050565b5095945050505050565b60006105f88484846131d9565b606081428110156115945760405162461bcd60e51b815260040161051390613cd1565b6115f27f0000000000000000000000000e47c8606a2ce2149e2ba6ab3bc73af3a0b79c6989888880806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250612d6092505050565b9150868260008151811061160857611608613d35565b60200260200101511115610b055760405162461bcd60e51b815260040161051390613e2b565b60006105f88484846132be565b6000814281101561165e5760405162461bcd60e51b815260040161051390613cd1565b61168d887f000000000000000000000000127876278b76e2c224e27c209d22daf0854bdcbb8989893089611aee565b6040516370a0823160e01b81523060048201529093506117159150899086906001600160a01b038316906370a082319060240160206040518083038186803b1580156116d857600080fd5b505afa1580156116ec573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117109190613e72565b6124dc565b604051632e1a7d4d60e01b8152600481018390527f000000000000000000000000127876278b76e2c224e27c209d22daf0854bdcbb6001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561177757600080fd5b505af115801561178b573d6000803e3d6000fd5b50505050610924848361260d565b80428110156117ba5760405162461bcd60e51b815260040161051390613cd1565b7f000000000000000000000000127876278b76e2c224e27c209d22daf0854bdcbb6001600160a01b0316858560008181106117f7576117f7613d35565b905060200201602081019061180c9190613d4b565b6001600160a01b0316146118325760405162461bcd60e51b815260040161051390613d68565b60003490507f000000000000000000000000127876278b76e2c224e27c209d22daf0854bdcbb6001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561189257600080fd5b505af11580156118a6573d6000803e3d6000fd5b50505050507f000000000000000000000000127876278b76e2c224e27c209d22daf0854bdcbb6001600160a01b031663a9059cbb6119117f0000000000000000000000000e47c8606a2ce2149e2ba6ab3bc73af3a0b79c6989896000818110610e0957610e09613d35565b6040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260248101849052604401602060405180830381600087803b15801561195957600080fd5b505af115801561196d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119919190613e8b565b61199d5761199d613772565b600086866119ac600182613d1e565b8181106119bb576119bb613d35565b90506020020160208101906119d09190613d4b565b6040516370a0823160e01b81526001600160a01b03878116600483015291909116906370a082319060240160206040518083038186803b158015611a1357600080fd5b505afa158015611a27573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a4b9190613e72565b9050611a8b878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250899250612ee1915050565b87818888611a9a600182613d1e565b818110611aa957611aa9613d35565b9050602002016020810190611abe9190613d4b565b6040516370a0823160e01b81526001600160a01b03898116600483015291909116906370a0823190602401610f84565b6000808242811015611b125760405162461bcd60e51b815260040161051390613cd1565b6000611b3f7f0000000000000000000000000e47c8606a2ce2149e2ba6ab3bc73af3a0b79c698c8c612956565b6040516323b872dd60e01b81523360048201526001600160a01b03821660248201819052604482018c90529192506323b872dd90606401602060405180830381600087803b158015611b9057600080fd5b505af1158015611ba4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bc89190613e8b565b5060405163226bf2d160e21b81526001600160a01b03878116600483015260009182918416906389afcb44906024016040805180830381600087803b158015611c1057600080fd5b505af1158015611c24573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c489190613ea8565b915091506000611c588e8e61335e565b509050806001600160a01b03168e6001600160a01b031614611c7b578183611c7e565b82825b90975095508a871015611ca35760405162461bcd60e51b815260040161051390613ecc565b89861015611cc35760405162461bcd60e51b815260040161051390613f12565b505050505097509795505050505050565b606061095c7f0000000000000000000000000e47c8606a2ce2149e2ba6ab3bc73af3a0b79c6984846127cb565b6000806000611d517f0000000000000000000000000e47c8606a2ce2149e2ba6ab3bc73af3a0b79c698e7f000000000000000000000000127876278b76e2c224e27c209d22daf0854bdcbb612956565b9050600087611d60578c611d64565b6000195b60405163d505accf60e01b81529091506001600160a01b0383169063d505accf90611d9f903390309086908f908e908e908e90600401613dea565b600060405180830381600087803b158015611db957600080fd5b505af1158015611dcd573d6000803e3d6000fd5b50505050611ddf8e8e8e8e8e8e6104ef565b909f909e509c50505050505050505050505050565b60008060008342811015611e1a5760405162461bcd60e51b815260040161051390613cd1565b611e288c8c8c8c8c8c613456565b90945092506000611e5a7f0000000000000000000000000e47c8606a2ce2149e2ba6ab3bc73af3a0b79c698e8e612956565b9050611e688d338388612a1a565b611e748c338387612a1a565b6040516335313c2160e11b81526001600160a01b038881166004830152821690636a62784290602401602060405180830381600087803b158015611eb757600080fd5b505af1158015611ecb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611eef9190613e72565b92505050985098509895505050505050565b60008060008342811015611f275760405162461bcd60e51b815260040161051390613cd1565b611f558a7f000000000000000000000000127876278b76e2c224e27c209d22daf0854bdcbb8b348c8c613456565b90945092506000611fa77f0000000000000000000000000e47c8606a2ce2149e2ba6ab3bc73af3a0b79c698c7f000000000000000000000000127876278b76e2c224e27c209d22daf0854bdcbb612956565b9050611fb58b338388612a1a565b7f000000000000000000000000127876278b76e2c224e27c209d22daf0854bdcbb6001600160a01b031663d0e30db0856040518263ffffffff1660e01b81526004016000604051808303818588803b15801561201057600080fd5b505af1158015612024573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b038581166004830152602482018990527f000000000000000000000000127876278b76e2c224e27c209d22daf0854bdcbb16935063a9059cbb92506044019050602060405180830381600087803b15801561209457600080fd5b505af11580156120a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120cc9190613e8b565b6120d8576120d8613772565b6040516335313c2160e11b81526001600160a01b038881166004830152821690636a62784290602401602060405180830381600087803b15801561211b57600080fd5b505af115801561212f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121539190613e72565b925083341115612170576121703361216b8634613d1e565b61260d565b505096509650969350505050565b606081428110156121a15760405162461bcd60e51b815260040161051390613cd1565b7f000000000000000000000000127876278b76e2c224e27c209d22daf0854bdcbb6001600160a01b0316868660008181106121de576121de613d35565b90506020020160208101906121f39190613d4b565b6001600160a01b0316146122195760405162461bcd60e51b815260040161051390613d68565b6122777f0000000000000000000000000e47c8606a2ce2149e2ba6ab3bc73af3a0b79c6988888880806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250612d6092505050565b9150348260008151811061228d5761228d613d35565b602002602001015111156122b35760405162461bcd60e51b815260040161051390613e2b565b7f000000000000000000000000127876278b76e2c224e27c209d22daf0854bdcbb6001600160a01b031663d0e30db0836000815181106122f5576122f5613d35565b60200260200101516040518263ffffffff1660e01b81526004016000604051808303818588803b15801561232857600080fd5b505af115801561233c573d6000803e3d6000fd5b50505050507f000000000000000000000000127876278b76e2c224e27c209d22daf0854bdcbb6001600160a01b031663a9059cbb6123a77f0000000000000000000000000e47c8606a2ce2149e2ba6ab3bc73af3a0b79c6989896000818110610e0957610e09613d35565b846000815181106123ba576123ba613d35565b60200260200101516040518363ffffffff1660e01b81526004016123f39291906001600160a01b03929092168252602082015260400190565b602060405180830381600087803b15801561240d57600080fd5b505af1158015612421573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124459190613e8b565b61245157612451613772565b61249082878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250899250612b58915050565b816000815181106124a3576124a3613d35565b602002602001015134111561155a5761155a33836000815181106124c9576124c9613d35565b60200260200101513461216b9190613d1e565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b17905291516000928392908716916125389190613f84565b6000604051808303816000865af19150503d8060008114612575576040519150601f19603f3d011682016040523d82523d6000602084013e61257a565b606091505b50915091508180156125a45750805115806125a45750808060200190518101906125a49190613e8b565b6126065760405162461bcd60e51b815260206004820152602d60248201527f5472616e7366657248656c7065723a3a736166655472616e736665723a20747260448201526c185b9cd9995c8819985a5b1959609a1b6064820152608401610513565b5050505050565b604080516000808252602082019092526001600160a01b0384169083906040516126379190613f84565b60006040518083038185875af1925050503d8060008114612674576040519150601f19603f3d011682016040523d82523d6000602084013e612679565b606091505b50509050806126e75760405162461bcd60e51b815260206004820152603460248201527f5472616e7366657248656c7065723a3a736166655472616e736665724554483a60448201527308115512081d1c985b9cd9995c8819985a5b195960621b6064820152608401610513565b505050565b60008084116127515760405162461bcd60e51b815260206004820152602b60248201527f53746f6e65537761704c6962726172793a20494e53554646494349454e545f4960448201526a1394155517d05353d5539560aa1b6064820152608401610513565b6000831180156127615750600082115b61277d5760405162461bcd60e51b815260040161051390613fa0565b600061278b856103e4613fe8565b905060006127998483613fe8565b90506000826127aa876103e8613fe8565b6127b49190614007565b90506127c0818361401f565b979650505050505050565b606060028251101561281f5760405162461bcd60e51b815260206004820152601e60248201527f53746f6e65537761704c6962726172793a20494e56414c49445f5041544800006044820152606401610513565b815167ffffffffffffffff81111561283957612839613936565b604051908082528060200260200182016040528015612862578160200160208202803683370190505b509050828160008151811061287957612879613d35565b60200260200101818152505060005b600183516128969190613d1e565b81101561294e576000806128e9878685815181106128b6576128b6613d35565b6020026020010151878660016128cc9190614007565b815181106128dc576128dc613d35565b6020026020010151613699565b9150915061291184848151811061290257612902613d35565b602002602001015183836126ec565b8461291d856001614007565b8151811061292d5761292d613d35565b6020026020010181815250505050808061294690614041565b915050612888565b509392505050565b6000806000612965858561335e565b604080516bffffffffffffffffffffffff19606085811b821660208085019190915285821b83166034850152845180850360280181526048850190955284519401939093206001600160f81b03196068840152928b901b166069820152607d8101919091527f2bf0cd46972a88aec59c98ddaba3cfd678559e2ccdbc618335079ba2f94aad93609d820152919350915060bd0160408051601f1981840301815291905280516020909101209695505050505050565b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b1790529151600092839290881691612a7e9190613f84565b6000604051808303816000865af19150503d8060008114612abb576040519150601f19603f3d011682016040523d82523d6000602084013e612ac0565b606091505b5091509150818015612aea575080511580612aea575080806020019051810190612aea9190613e8b565b612b505760405162461bcd60e51b815260206004820152603160248201527f5472616e7366657248656c7065723a3a7472616e7366657246726f6d3a207472604482015270185b9cd9995c919c9bdb4819985a5b1959607a1b6064820152608401610513565b505050505050565b60005b60018351612b699190613d1e565b811015612d5a57600080848381518110612b8557612b85613d35565b602002602001015185846001612b9b9190614007565b81518110612bab57612bab613d35565b6020026020010151915091506000612bc3838361335e565b509050600087612bd4866001614007565b81518110612be457612be4613d35565b60200260200101519050600080836001600160a01b0316866001600160a01b031614612c1257826000612c16565b6000835b91509150600060028a51612c2a9190613d1e565b8810612c365788612c84565b612c847f0000000000000000000000000e47c8606a2ce2149e2ba6ab3bc73af3a0b79c69878c612c678c6002614007565b81518110612c7757612c77613d35565b6020026020010151612956565b9050612cb17f0000000000000000000000000e47c8606a2ce2149e2ba6ab3bc73af3a0b79c698888612956565b6001600160a01b031663022c0d9f84848460006040519080825280601f01601f191660200182016040528015612cee576020820181803683370190505b506040518563ffffffff1660e01b8152600401612d0e949392919061405c565b600060405180830381600087803b158015612d2857600080fd5b505af1158015612d3c573d6000803e3d6000fd5b50505050505050505050508080612d5290614041565b915050612b5b565b50505050565b6060600282511015612db45760405162461bcd60e51b815260206004820152601e60248201527f53746f6e65537761704c6962726172793a20494e56414c49445f5041544800006044820152606401610513565b815167ffffffffffffffff811115612dce57612dce613936565b604051908082528060200260200182016040528015612df7578160200160208202803683370190505b509050828160018351612e0a9190613d1e565b81518110612e1a57612e1a613d35565b602002602001018181525050600060018351612e369190613d1e565b90505b801561294e57600080612e7c8786612e52600187613d1e565b81518110612e6257612e62613d35565b60200260200101518786815181106128dc576128dc613d35565b91509150612ea4848481518110612e9557612e95613d35565b602002602001015183836131d9565b84612eb0600186613d1e565b81518110612ec057612ec0613d35565b60200260200101818152505050508080612ed9906140ac565b915050612e39565b60005b60018351612ef29190613d1e565b8110156126e757600080848381518110612f0e57612f0e613d35565b602002602001015185846001612f249190614007565b81518110612f3457612f34613d35565b6020026020010151915091506000612f4c838361335e565b5090506000612f7c7f0000000000000000000000000e47c8606a2ce2149e2ba6ab3bc73af3a0b79c698585612956565b9050600080600080846001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b158015612fbd57600080fd5b505afa158015612fd1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ff591906140da565b506001600160701b031691506001600160701b03169150600080876001600160a01b03168a6001600160a01b03161461302f578284613032565b83835b6040516370a0823160e01b81526001600160a01b038a8116600483015292945090925083918c16906370a082319060240160206040518083038186803b15801561307b57600080fd5b505afa15801561308f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130b39190613e72565b6130bd9190613d1e565b95506130ca8683836126ec565b945050505050600080856001600160a01b0316886001600160a01b0316146130f4578260006130f8565b6000835b91509150600060028c5161310c9190613d1e565b8a10613118578a613149565b6131497f0000000000000000000000000e47c8606a2ce2149e2ba6ab3bc73af3a0b79c69898e612c678e6002614007565b6040805160008152602081019182905263022c0d9f60e01b9091529091506001600160a01b0387169063022c0d9f9061318b908690869086906024810161405c565b600060405180830381600087803b1580156131a557600080fd5b505af11580156131b9573d6000803e3d6000fd5b5050505050505050505050505080806131d190614041565b915050612ee4565b600080841161323f5760405162461bcd60e51b815260206004820152602c60248201527f53746f6e65537761704c6962726172793a20494e53554646494349454e545f4f60448201526b155514155517d05353d5539560a21b6064820152608401610513565b60008311801561324f5750600082115b61326b5760405162461bcd60e51b815260040161051390613fa0565b60006132778585613fe8565b613283906103e8613fe8565b905060006132918685613d1e565b61329d906103e4613fe8565b90506132a9818361401f565b6132b4906001614007565b9695505050505050565b600080841161331d5760405162461bcd60e51b815260206004820152602560248201527f53746f6e65537761704c6962726172793a20494e53554646494349454e545f416044820152641353d5539560da1b6064820152608401610513565b60008311801561332d5750600082115b6133495760405162461bcd60e51b815260040161051390613fa0565b826133548386613fe8565b6105f8919061401f565b600080826001600160a01b0316846001600160a01b031614156133d15760405162461bcd60e51b815260206004820152602560248201527f53746f6e65537761704c6962726172793a204944454e544943414c5f41444452604482015264455353455360d81b6064820152608401610513565b826001600160a01b0316846001600160a01b0316106133f15782846133f4565b83835b90925090506001600160a01b03821661344f5760405162461bcd60e51b815260206004820152601e60248201527f53746f6e65537761704c6962726172793a205a45524f5f4144445245535300006044820152606401610513565b9250929050565b60405163e6a4390560e01b81526001600160a01b0387811660048301528681166024830152600091829182917f0000000000000000000000000e47c8606a2ce2149e2ba6ab3bc73af3a0b79c699091169063e6a439059060440160206040518083038186803b1580156134c857600080fd5b505afa1580156134dc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613500919061412a565b6001600160a01b031614156135b4576040516364e329cb60e11b81526001600160a01b03898116600483015288811660248301527f0000000000000000000000000e47c8606a2ce2149e2ba6ab3bc73af3a0b79c69169063c9c6539690604401602060405180830381600087803b15801561357a57600080fd5b505af115801561358e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135b2919061412a565b505b6000806135e27f0000000000000000000000000e47c8606a2ce2149e2ba6ab3bc73af3a0b79c698b8b613699565b915091508160001480156135f4575080155b156136045787935086925061368c565b60006136118984846132be565b9050878111613645578581101561363a5760405162461bcd60e51b815260040161051390613f12565b88945092508261368a565b60006136528984866132be565b90508981111561366457613664613772565b878110156136845760405162461bcd60e51b815260040161051390613ecc565b94508793505b505b5050965096945050505050565b60008060006136a8858561335e565b5090506000806136b9888888612956565b6001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b1580156136f157600080fd5b505afa158015613705573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061372991906140da565b506001600160701b031691506001600160701b03169150826001600160a01b0316876001600160a01b031614613760578082613763565b81815b90999098509650505050505050565b634e487b7160e01b600052600160045260246000fd5b6001600160a01b038116811461379d57600080fd5b50565b80356137ab81613788565b919050565b60008060008060008060c087890312156137c957600080fd5b86356137d481613788565b955060208701359450604087013593506060870135925060808701356137f981613788565b8092505060a087013590509295509295509295565b60008060006060848603121561382357600080fd5b505081359360208301359350604090920135919050565b60008083601f84011261384c57600080fd5b50813567ffffffffffffffff81111561386457600080fd5b6020830191508360208260051b850101111561344f57600080fd5b60008060008060008060a0878903121561389857600080fd5b8635955060208701359450604087013567ffffffffffffffff8111156138bd57600080fd5b6138c989828a0161383a565b90955093505060608701356138dd81613788565b80925050608087013590509295509295509295565b6020808252825182820181905260009190848201906040850190845b8181101561392a5783518352928401929184019160010161390e565b50909695505050505050565b634e487b7160e01b600052604160045260246000fd5b6000806040838503121561395f57600080fd5b8235915060208084013567ffffffffffffffff8082111561397f57600080fd5b818601915086601f83011261399357600080fd5b8135818111156139a5576139a5613936565b8060051b604051601f19603f830116810181811085821117156139ca576139ca613936565b6040529182528482019250838101850191898311156139e857600080fd5b938501935b82851015613a0d576139fe856137a0565b845293850193928501926139ed565b8096505050505050509250929050565b801515811461379d57600080fd5b803560ff811681146137ab57600080fd5b60008060008060008060008060008060006101608c8e031215613a5e57600080fd5b8b35613a6981613788565b9a5060208c0135613a7981613788565b995060408c0135985060608c0135975060808c0135965060a08c0135613a9e81613788565b955060c08c0135945060e08c0135613ab581613a1d565b9350613ac46101008d01613a2b565b92506101208c013591506101408c013590509295989b509295989b9093969950565b6000806000806000806000806000806101408b8d031215613b0657600080fd5b8a35613b1181613788565b995060208b0135985060408b0135975060608b0135965060808b0135613b3681613788565b955060a08b0135945060c08b0135613b4d81613a1d565b9350613b5b60e08c01613a2b565b92506101008b013591506101208b013590509295989b9194979a5092959850565b600080600080600060808688031215613b9457600080fd5b85359450602086013567ffffffffffffffff811115613bb257600080fd5b613bbe8882890161383a565b9095509350506040860135613bd281613788565b949793965091946060013592915050565b600080600080600080600060e0888a031215613bfe57600080fd5b8735613c0981613788565b96506020880135613c1981613788565b955060408801359450606088013593506080880135925060a0880135613c3e81613788565b8092505060c0880135905092959891949750929550565b600080600080600080600080610100898b031215613c7257600080fd5b8835613c7d81613788565b97506020890135613c8d81613788565b965060408901359550606089013594506080890135935060a0890135925060c0890135613cb981613788565b8092505060e089013590509295985092959890939650565b60208082526018908201527f53746f6e6553776170526f757465723a20455850495245440000000000000000604082015260600190565b634e487b7160e01b600052601160045260246000fd5b600082821015613d3057613d30613d08565b500390565b634e487b7160e01b600052603260045260246000fd5b600060208284031215613d5d57600080fd5b813561095c81613788565b6020808252601d908201527f53746f6e6553776170526f757465723a20494e56414c49445f50415448000000604082015260600190565b6020808252602b908201527f53746f6e6553776170526f757465723a20494e53554646494349454e545f4f5560408201526a1514155517d05353d5539560aa1b606082015260800190565b6001600160a01b0397881681529590961660208601526040850193909352606084019190915260ff16608083015260a082015260c081019190915260e00190565b60208082526027908201527f53746f6e6553776170526f757465723a204558434553534956455f494e50555460408201526617d05353d5539560ca1b606082015260800190565b600060208284031215613e8457600080fd5b5051919050565b600060208284031215613e9d57600080fd5b815161095c81613a1d565b60008060408385031215613ebb57600080fd5b505080516020909101519092909150565b60208082526026908201527f53746f6e6553776170526f757465723a20494e53554646494349454e545f415f604082015265105353d5539560d21b606082015260800190565b60208082526026908201527f53746f6e6553776170526f757465723a20494e53554646494349454e545f425f604082015265105353d5539560d21b606082015260800190565b60005b83811015613f73578181015183820152602001613f5b565b83811115612d5a5750506000910152565b60008251613f96818460208701613f58565b9190910192915050565b60208082526028908201527f53746f6e65537761704c6962726172793a20494e53554646494349454e545f4c604082015267495155494449545960c01b606082015260800190565b600081600019048311821515161561400257614002613d08565b500290565b6000821982111561401a5761401a613d08565b500190565b60008261403c57634e487b7160e01b600052601260045260246000fd5b500490565b600060001982141561405557614055613d08565b5060010190565b84815283602082015260018060a01b038316604082015260806060820152600082518060808401526140958160a0850160208701613f58565b601f01601f19169190910160a00195945050505050565b6000816140bb576140bb613d08565b506000190190565b80516001600160701b03811681146137ab57600080fd5b6000806000606084860312156140ef57600080fd5b6140f8846140c3565b9250614106602085016140c3565b9150604084015163ffffffff8116811461411f57600080fd5b809150509250925092565b60006020828403121561413c57600080fd5b815161095c8161378856fea2646970667358221220aa72adbe4b84c21bfaf8ea7d234cd058cba104afe2b03ed27d0537c1362c192a64736f6c63430008090033