ETH Price: $3,229.19 (+2.96%)

Contract

0x61f4ECD130291e5D5D7809A112f9F9081b8Ed3A5

Overview

ETH Balance

0 ETH

ETH Value

$0.00

Token Holdings

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Swap Exact Token...191574902025-01-14 17:49:415 hrs ago1736876981IN
0x61f4ECD1...81b8Ed3A5
0 ETH0.000025380.15
Swap Exact Token...191537462025-01-14 14:21:348 hrs ago1736864494IN
0x61f4ECD1...81b8Ed3A5
0 ETH0.000021920.1296
Swap Exact Token...191357452025-01-13 20:42:1426 hrs ago1736800934IN
0x61f4ECD1...81b8Ed3A5
0 ETH0.000018720.12
Swap Exact Token...191356522025-01-13 20:36:2426 hrs ago1736800584IN
0x61f4ECD1...81b8Ed3A5
0 ETH0.000018610.11
Swap Exact Token...191307032025-01-13 15:58:5431 hrs ago1736783934IN
0x61f4ECD1...81b8Ed3A5
0 ETH0.000031460.186
Swap Exact Token...191234132025-01-13 9:10:5038 hrs ago1736759450IN
0x61f4ECD1...81b8Ed3A5
0 ETH0.000011770.07275
Swap Exact Token...191199552025-01-13 5:59:3241 hrs ago1736747972IN
0x61f4ECD1...81b8Ed3A5
0 ETH0.000005880.0348
Swap Exact Token...191031332025-01-12 14:26:392 days ago1736691999IN
0x61f4ECD1...81b8Ed3A5
0 ETH0.000008810.0565
Swap Exact Token...191023872025-01-12 13:45:262 days ago1736689526IN
0x61f4ECD1...81b8Ed3A5
0 ETH0.000004880.0289
Swap Exact Token...190979092025-01-12 9:37:362 days ago1736674656IN
0x61f4ECD1...81b8Ed3A5
0 ETH0.00000770.05
Swap Exact Token...190958402025-01-12 7:41:462 days ago1736667706IN
0x61f4ECD1...81b8Ed3A5
0 ETH0.000004580.0271
Swap Exact Token...190932632025-01-12 5:19:272 days ago1736659167IN
0x61f4ECD1...81b8Ed3A5
0 ETH0.000004970.0294
Swap Exact Token...190919452025-01-12 4:07:402 days ago1736654860IN
0x61f4ECD1...81b8Ed3A5
0 ETH0.000005650.0334
Swap Exact Token...190798702025-01-11 16:59:213 days ago1736614761IN
0x61f4ECD1...81b8Ed3A5
0 ETH0.000008640.06
Swap Exact Token...190429672025-01-10 7:06:554 days ago1736492815IN
0x61f4ECD1...81b8Ed3A5
0 ETH0.00000970.0622
Swap Exact Token...190428322025-01-10 6:59:244 days ago1736492364IN
0x61f4ECD1...81b8Ed3A5
0 ETH0.00000890.0571
Swap Exact Token...190428112025-01-10 6:58:114 days ago1736492291IN
0x61f4ECD1...81b8Ed3A5
0 ETH0.000010270.0659
Swap Exact Token...190427572025-01-10 6:55:034 days ago1736492103IN
0x61f4ECD1...81b8Ed3A5
0 ETH0.000010920.07
Swap Exact Token...190427512025-01-10 6:54:434 days ago1736492083IN
0x61f4ECD1...81b8Ed3A5
0 ETH0.000008780.0519
Swap Exact Token...190415982025-01-10 5:51:134 days ago1736488273IN
0x61f4ECD1...81b8Ed3A5
0 ETH0.000008680.0557
Swap Exact Token...190411832025-01-10 5:27:474 days ago1736486867IN
0x61f4ECD1...81b8Ed3A5
0 ETH0.000007560.0447
Swap Exact Token...190223642025-01-09 12:08:595 days ago1736424539IN
0x61f4ECD1...81b8Ed3A5
0 ETH0.000010230.0656
Swap Exact Token...190221112025-01-09 11:54:505 days ago1736423690IN
0x61f4ECD1...81b8Ed3A5
0 ETH0.000011150.0659
Swap Exact Token...190218412025-01-09 11:39:485 days ago1736422788IN
0x61f4ECD1...81b8Ed3A5
0 ETH0.00001020.0654
Swap Exact Token...190216992025-01-09 11:31:515 days ago1736422311IN
0x61f4ECD1...81b8Ed3A5
0 ETH0.000010290.066
View all transactions

Latest 25 internal transactions (View All)

Parent Transaction Hash Block From To
191574902025-01-14 17:49:415 hrs ago1736876981
0x61f4ECD1...81b8Ed3A5
0.00024695 ETH
191574902025-01-14 17:49:415 hrs ago1736876981
0x61f4ECD1...81b8Ed3A5
0.00024695 ETH
191537462025-01-14 14:21:348 hrs ago1736864494
0x61f4ECD1...81b8Ed3A5
0.00005982 ETH
191537462025-01-14 14:21:348 hrs ago1736864494
0x61f4ECD1...81b8Ed3A5
0.00005982 ETH
191357452025-01-13 20:42:1426 hrs ago1736800934
0x61f4ECD1...81b8Ed3A5
0.00007411 ETH
191357452025-01-13 20:42:1426 hrs ago1736800934
0x61f4ECD1...81b8Ed3A5
0.00007411 ETH
191356522025-01-13 20:36:2426 hrs ago1736800584
0x61f4ECD1...81b8Ed3A5
0.00010274 ETH
191356522025-01-13 20:36:2426 hrs ago1736800584
0x61f4ECD1...81b8Ed3A5
0.00010274 ETH
191307032025-01-13 15:58:5431 hrs ago1736783934
0x61f4ECD1...81b8Ed3A5
0.00010336 ETH
191307032025-01-13 15:58:5431 hrs ago1736783934
0x61f4ECD1...81b8Ed3A5
0.00010336 ETH
191199552025-01-13 5:59:3241 hrs ago1736747972
0x61f4ECD1...81b8Ed3A5
0.00327472 ETH
191199552025-01-13 5:59:3241 hrs ago1736747972
0x61f4ECD1...81b8Ed3A5
0.00327472 ETH
191031332025-01-12 14:26:392 days ago1736691999
0x61f4ECD1...81b8Ed3A5
0.00008866 ETH
191031332025-01-12 14:26:392 days ago1736691999
0x61f4ECD1...81b8Ed3A5
0.00008866 ETH
191023872025-01-12 13:45:262 days ago1736689526
0x61f4ECD1...81b8Ed3A5
0.00010679 ETH
191023872025-01-12 13:45:262 days ago1736689526
0x61f4ECD1...81b8Ed3A5
0.00010679 ETH
190958402025-01-12 7:41:462 days ago1736667706
0x61f4ECD1...81b8Ed3A5
0.0000896 ETH
190958402025-01-12 7:41:462 days ago1736667706
0x61f4ECD1...81b8Ed3A5
0.0000896 ETH
190932632025-01-12 5:19:272 days ago1736659167
0x61f4ECD1...81b8Ed3A5
0.00008865 ETH
190932632025-01-12 5:19:272 days ago1736659167
0x61f4ECD1...81b8Ed3A5
0.00008865 ETH
190919452025-01-12 4:07:402 days ago1736654860
0x61f4ECD1...81b8Ed3A5
0.00009037 ETH
190919452025-01-12 4:07:402 days ago1736654860
0x61f4ECD1...81b8Ed3A5
0.00009037 ETH
190798702025-01-11 16:59:213 days ago1736614761
0x61f4ECD1...81b8Ed3A5
0.00017896 ETH
190798702025-01-11 16:59:213 days ago1736614761
0x61f4ECD1...81b8Ed3A5
0.00017896 ETH
190429672025-01-10 7:06:554 days ago1736492815
0x61f4ECD1...81b8Ed3A5
0.00003208 ETH
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
AntfarmRouter

Compiler Version
v0.8.10+commit.fc410830

Optimization Enabled:
Yes with 1000 runs

Other Settings:
default evmVersion
File 1 of 19 : AntfarmRouter.sol
// SPDX-License-Identifier: MIT
pragma solidity =0.8.10;

import "../interfaces/IAntfarmRouter.sol";
import "../interfaces/IAntfarmPair.sol";
import "../interfaces/IAntfarmFactory.sol";
import "../interfaces/IERC20.sol";
import "../interfaces/IWETH.sol";
import "../libraries/TransferHelper.sol";
import "./AntfarmOracle.sol";
import "../utils/AntfarmRouterErrors.sol";

/// @title Antfarm Router for AntFarmPair
/// @notice High-level contract that serves as the entrypoint for swapping
contract AntfarmRouter is IAntfarmRouter {
    address public immutable factory;
    address public immutable WETH;
    address public immutable antfarmToken;

    modifier ensure(uint256 deadline) {
        if (deadline < block.timestamp) revert Expired();
        _;
    }

    constructor(
        address _factory,
        address _WETH,
        address _antfarmToken
    ) {
        require(_factory != address(0), "NULL_FACTORY_ADDRESS");
        require(_WETH != address(0), "NULL_WETH_ADDRESS");
        require(_antfarmToken != address(0), "NULL_ATF_ADDRESS");
        factory = _factory;
        WETH = _WETH;
        antfarmToken = _antfarmToken;
    }

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

    /// @notice Swaps an exact amount of input tokens for as many output tokens as possible
    /// @param params The parameters necessary for the swap, encoded as `swapExactTokensForTokensParams` in calldata
    // @param amountIn The amount of input tokens to send
    // @param amountOutMin The minimum amount of output tokens that must be received for the transaction not to revert
    // @param maxFee Maximum fees to be paid
    // @param path An array of token addresses
    // @param fees Associated fee for each two token addresses within the path
    // @param to Recipient of the output tokens
    // @param deadline Unix timestamp after which the transaction will revert
    /// @return amounts The input token amount and all subsequent output token amounts
    function swapExactTokensForTokens(
        swapExactTokensForTokensParams calldata params
    )
        external
        virtual
        ensure(params.deadline)
        returns (uint256[] memory amounts)
    {
        uint256 amountIn = params.path[0] == antfarmToken
            ? (params.amountIn * (1000 + params.fees[0])) / 1000
            : params.amountIn;
        amounts = getAmountsOut(amountIn, params.path, params.fees);
        if (amounts[amounts.length - 1] < params.amountOutMin) {
            revert InsufficientOutputAmount();
        }
        TransferHelper.safeTransferFrom(
            params.path[0],
            msg.sender,
            pairFor(params.path[0], params.path[1], params.fees[0]),
            amounts[0]
        );
        if (
            _swap(amounts, params.path, params.fees, params.to) > params.maxFee
        ) {
            revert InsufficientMaxFee();
        }
    }

    /// @notice Receive an exact amount of output tokens for as few input tokens as possible
    /// @param params The parameters necessary for the swap, encoded as `swapTokensForExactTokensParams` in calldata
    // @param amountOut The amount of output tokens to receive
    // @param amountInMax The maximum amount of input tokens that can be required before the transaction reverts
    // @param maxFee Maximum fees to be paid
    // @param path An array of token addresses
    // @param fees Associated fee for each two token addresses within the path
    // @param to Recipient of the output tokens
    // @param deadline Unix timestamp after which the transaction will revert
    /// @return amounts The input token amount and all subsequent output token amounts
    function swapTokensForExactTokens(
        swapTokensForExactTokensParams calldata params
    )
        external
        virtual
        ensure(params.deadline)
        returns (uint256[] memory amounts)
    {
        uint256 amountInMax = params.path[0] == antfarmToken
            ? (params.amountInMax * (1000 + params.fees[0])) / 1000
            : params.amountInMax;
        amounts = getAmountsIn(params.amountOut, params.path, params.fees);
        if (amounts[0] > amountInMax) revert ExcessiveInputAmount();
        TransferHelper.safeTransferFrom(
            params.path[0],
            msg.sender,
            pairFor(params.path[0], params.path[1], params.fees[0]),
            amounts[0]
        );
        if (
            _swap(amounts, params.path, params.fees, params.to) > params.maxFee
        ) {
            revert InsufficientMaxFee();
        }
    }

    /// @notice Swaps an exact amount of ETH for as many output tokens as possible
    /// @param params The parameters necessary for the swap, encoded as `swapExactETHForTokensParams` in calldata
    // @param amountOutMin The minimum amount of output tokens that must be received for the transaction not to revert
    // @param maxFee Maximum fees to be paid
    // @param path An array of token addresses
    // @param fees Associated fee for each two token addresses within the path
    // @param to Recipient of the output tokens
    // @param deadline Unix timestamp after which the transaction will revert
    /// @return amounts The input token amount and all subsequent output token amounts
    function swapExactETHForTokens(swapExactETHForTokensParams calldata params)
        external
        payable
        virtual
        ensure(params.deadline)
        returns (uint256[] memory amounts)
    {
        if (params.path[0] != WETH) revert InvalidPath();
        amounts = getAmountsOut(msg.value, params.path, params.fees);
        if (amounts[amounts.length - 1] < params.amountOutMin) {
            revert InsufficientOutputAmount();
        }
        IWETH(WETH).deposit{value: amounts[0]}();
        assert(
            IWETH(WETH).transfer(
                pairFor(params.path[0], params.path[1], params.fees[0]),
                amounts[0]
            )
        );
        if (
            _swap(amounts, params.path, params.fees, params.to) > params.maxFee
        ) {
            revert InsufficientMaxFee();
        }
    }

    /// @notice Receive an exact amount of ETH for as few input tokens as possible
    /// @param params The parameters necessary for the swap, encoded as `swapTokensForExactETHParams` in calldata
    // @param amountOut The amount of ETH to receive
    // @param amountInMax The maximum amount of input tokens that can be required before the transaction reverts
    // @param maxFee Maximum fees to be paid
    // @param path An array of token addresses
    // @param fees Associated fee for each two token addresses within the path
    // @param to Recipient of the output tokens
    // @param deadline Unix timestamp after which the transaction will revert
    /// @return amounts The input token amount and all subsequent output token amounts
    function swapTokensForExactETH(swapTokensForExactETHParams calldata params)
        external
        virtual
        ensure(params.deadline)
        returns (uint256[] memory amounts)
    {
        if (params.path[params.path.length - 1] != WETH) revert InvalidPath();
        uint256 amountInMax = params.path[0] == antfarmToken
            ? (params.amountInMax * (1000 + params.fees[0])) / 1000
            : params.amountInMax;
        amounts = getAmountsIn(params.amountOut, params.path, params.fees);
        if (amounts[0] > amountInMax) revert ExcessiveInputAmount();
        TransferHelper.safeTransferFrom(
            params.path[0],
            msg.sender,
            pairFor(params.path[0], params.path[1], params.fees[0]),
            amounts[0]
        );
        if (
            _swap(amounts, params.path, params.fees, address(this)) >
            params.maxFee
        ) {
            revert InsufficientMaxFee();
        }
        IWETH(WETH).withdraw(amounts[amounts.length - 1]);
        TransferHelper.safeTransferETH(params.to, amounts[amounts.length - 1]);
    }

    /// @notice Swaps an exact amount of tokens for as much ETH as possible
    /// @param params The parameters necessary for the swap, encoded as `swapExactTokensForETHParams` in calldata
    // @param amountIn The amount of input tokens to send
    // @param amountOutMin The minimum amount of output tokens that must be received for the transaction not to revert
    // @param maxFee Maximum fees to be paid
    // @param path An array of token addresses
    // @param fees Associated fee for each two token addresses within the path
    // @param to Recipient of the output tokens
    // @param deadline Unix timestamp after which the transaction will revert
    /// @return amounts The input token amount and all subsequent output token amounts
    function swapExactTokensForETH(swapExactTokensForETHParams calldata params)
        external
        virtual
        ensure(params.deadline)
        returns (uint256[] memory amounts)
    {
        uint256 amountIn = params.path[0] == antfarmToken
            ? (params.amountIn * (1000 + params.fees[0])) / 1000
            : params.amountIn;
        if (params.path[params.path.length - 1] != WETH) revert InvalidPath();
        amounts = getAmountsOut(amountIn, params.path, params.fees);
        if (amounts[amounts.length - 1] < params.amountOutMin) {
            revert InsufficientOutputAmount();
        }
        TransferHelper.safeTransferFrom(
            params.path[0],
            msg.sender,
            pairFor(params.path[0], params.path[1], params.fees[0]),
            amounts[0]
        );
        if (
            _swap(amounts, params.path, params.fees, address(this)) >
            params.maxFee
        ) {
            revert InsufficientMaxFee();
        }
        IWETH(WETH).withdraw(amounts[amounts.length - 1]);
        TransferHelper.safeTransferETH(params.to, amounts[amounts.length - 1]);
    }

    /// @notice Receive an exact amount of tokens for as little ETH as possible
    /// @param params The parameters necessary for the swap, encoded as `swapETHForExactTokensParams` in calldata
    // @param amountOut The amount of tokens to receive
    // @param maxFee Maximum fees to be paid
    // @param path An array of token addresses
    // @param fees Associated fee for each two token addresses within the path
    // @param to Recipient of the output tokens
    // @param deadline Unix timestamp after which the transaction will revert
    /// @return amounts The input token amount and all subsequent output token amounts
    function swapETHForExactTokens(swapETHForExactTokensParams calldata params)
        external
        payable
        virtual
        ensure(params.deadline)
        returns (uint256[] memory amounts)
    {
        if (params.path[0] != WETH) revert InvalidPath();
        amounts = getAmountsIn(params.amountOut, params.path, params.fees);
        if (amounts[0] > msg.value) revert ExcessiveInputAmount();
        IWETH(WETH).deposit{value: amounts[0]}();
        assert(
            IWETH(WETH).transfer(
                pairFor(params.path[0], params.path[1], params.fees[0]),
                amounts[0]
            )
        );
        if (
            _swap(amounts, params.path, params.fees, params.to) > params.maxFee
        ) {
            revert InsufficientMaxFee();
        }
        // refund dust ETH if any
        if (msg.value > amounts[0])
            TransferHelper.safeTransferETH(msg.sender, msg.value - amounts[0]);
    }

    /// @notice Identical to swapExactTokensForTokens, but succeeds for tokens that take a fee on transfer
    /// @param params The parameters necessary for the swap, encoded as `swapExactTokensForTokensParams` in calldata
    // @param amountIn The amount of input tokens to send
    // @param amountOutMin The minimum amount of output tokens that must be received for the transaction not to revert
    // @param path An array of token addresses
    // @param fees Associated fee for each two token addresses within the path
    // @param to Recipient of the output tokens
    // @param deadline Unix timestamp after which the transaction will revert
    function swapExactTokensForTokensSupportingFeeOnTransferTokens(
        swapExactTokensForTokensParams calldata params
    ) external virtual ensure(params.deadline) {
        TransferHelper.safeTransferFrom(
            params.path[0],
            msg.sender,
            pairFor(params.path[0], params.path[1], params.fees[0]),
            params.amountIn
        );
        uint256 balanceBefore = IERC20(params.path[params.path.length - 1])
            .balanceOf(params.to);
        swapParams memory sParams = swapParams(
            params.path,
            params.fees,
            params.to
        );
        if (_swapSupportingFeeOnTransferTokens(sParams) > params.maxFee) {
            revert InsufficientMaxFee();
        }
        if (
            IERC20(params.path[params.path.length - 1]).balanceOf(params.to) -
                balanceBefore <
            params.amountOutMin
        ) {
            revert InsufficientOutputAmount();
        }
    }

    /// @notice Identical to swapExactETHForTokens, but succeeds for tokens that take a fee on transfer
    /// @param params The parameters necessary for the swap, encoded as `swapExactETHForTokensParams` in calldata
    // @param amountOutMin The minimum amount of output tokens that must be received for the transaction not to revert
    // @param path An array of token addresses
    // @param fees Associated fee for each two token addresses within the path
    // @param to Recipient of the output tokens
    // @param deadline Unix timestamp after which the transaction will revert
    function swapExactETHForTokensSupportingFeeOnTransferTokens(
        swapExactETHForTokensParams calldata params
    ) external payable virtual ensure(params.deadline) {
        if (params.path[0] != WETH) revert InvalidPath();
        uint256 amountIn = msg.value;
        IWETH(WETH).deposit{value: amountIn}();
        assert(
            IWETH(WETH).transfer(
                pairFor(params.path[0], params.path[1], params.fees[0]),
                amountIn
            )
        );
        uint256 balanceBefore = IERC20(params.path[params.path.length - 1])
            .balanceOf(params.to);
        swapParams memory sParams = swapParams(
            params.path,
            params.fees,
            params.to
        );
        if (_swapSupportingFeeOnTransferTokens(sParams) > params.maxFee) {
            revert InsufficientMaxFee();
        }
        if (
            IERC20(params.path[params.path.length - 1]).balanceOf(params.to) -
                balanceBefore <
            params.amountOutMin
        ) {
            revert InsufficientOutputAmount();
        }
    }

    /// @notice Identical to swapExactTokensForETH, but succeeds for tokens that take a fee on transfer
    /// @param params The parameters necessary for the swap, encoded as `swapExactTokensForETHParams` in calldata
    // @param amountIn The amount of input tokens to send
    // @param amountOutMin The minimum amount of output tokens that must be received for the transaction not to revert
    // @param path An array of token addresses
    // @param fees Associated fee for each two token addresses within the path
    // @param to Recipient of the output tokens
    // @param deadline Unix timestamp after which the transaction will revert
    function swapExactTokensForETHSupportingFeeOnTransferTokens(
        swapExactTokensForETHParams calldata params
    ) external virtual ensure(params.deadline) {
        if (params.path[params.path.length - 1] != WETH) revert InvalidPath();
        TransferHelper.safeTransferFrom(
            params.path[0],
            msg.sender,
            pairFor(params.path[0], params.path[1], params.fees[0]),
            params.amountIn
        );
        swapParams memory sParams = swapParams(
            params.path,
            params.fees,
            address(this)
        );
        if (_swapSupportingFeeOnTransferTokens(sParams) > params.maxFee) {
            revert InsufficientMaxFee();
        }
        uint256 amountOut = IERC20(WETH).balanceOf(address(this));
        if (amountOut < params.amountOutMin) revert InsufficientOutputAmount();
        IWETH(WETH).withdraw(amountOut);
        TransferHelper.safeTransferETH(params.to, amountOut);
    }

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

    // SWAP
    // requires the initial amount to have already been sent to the first pair
    function _swap(
        uint256[] memory amounts,
        address[] memory path,
        uint16[] memory fees,
        address _to
    ) internal virtual returns (uint256 totalFee) {
        for (uint256 i; i < path.length - 1; i++) {
            (address input, address output) = (path[i], path[i + 1]);
            uint16 fee = fees[i];
            IAntfarmPair antfarmPair = IAntfarmPair(
                pairFor(input, output, fee)
            );

            (address token0, ) = sortTokens(input, output);
            (uint256 amount0Out, uint256 amount1Out) = input == token0
                ? (uint256(0), amounts[i + 1])
                : (amounts[i + 1], uint256(0));

            {
                uint256 amountIn = amounts[i];

                if (input == antfarmToken) {
                    totalFee = totalFee + ((amountIn * fee) / (1000 + fee));
                } else if (output == antfarmToken) {
                    totalFee =
                        totalFee +
                        ((amounts[i + 1] * fee) / (1000 - fee));
                } else {
                    uint256 feeToPay = antfarmPair.getFees(
                        amount0Out,
                        input == token0 ? amountIn : uint256(0),
                        amount1Out,
                        input == token0 ? uint256(0) : amountIn
                    );

                    TransferHelper.safeTransferFrom(
                        antfarmToken,
                        msg.sender,
                        address(antfarmPair),
                        feeToPay
                    );

                    totalFee = totalFee + feeToPay;
                }
            }

            address to = i < path.length - 2
                ? pairFor(output, path[i + 2], fees[i + 1])
                : _to;
            antfarmPair.swap(amount0Out, amount1Out, to);
        }
    }

    // **** SWAP (supporting fee-on-transfer tokens) ****
    function _swapSupportingFeeOnTransferTokens(swapParams memory sParams)
        internal
        virtual
        returns (uint256 totalFee)
    {
        for (uint256 i; i < sParams.path.length - 1; i++) {
            (address input, address output) = (
                sParams.path[i],
                sParams.path[i + 1]
            );
            uint16 fee = sParams.fees[i];
            IAntfarmPair antfarmPair = IAntfarmPair(
                pairFor(input, output, fee)
            );

            (address token0, ) = sortTokens(input, output);

            uint256 amountIn;
            uint256 amountOut;
            {
                (uint256 reserve0, uint256 reserve1, ) = antfarmPair
                    .getReserves();
                (uint256 reserveIn, uint256 reserveOut) = input == token0
                    ? (reserve0, reserve1)
                    : (reserve1, reserve0);

                amountIn =
                    IERC20(input).balanceOf(address(antfarmPair)) -
                    reserveIn;

                if (input == antfarmToken) {
                    amountOut = getAmountOut(
                        (amountIn * 1000) / (1000 + fee),
                        reserveIn,
                        reserveOut
                    );
                } else if (output == antfarmToken) {
                    amountOut =
                        (getAmountOut(amountIn, reserveIn, reserveOut) *
                            (1000 - fee)) /
                        1000;
                } else {
                    amountOut = getAmountOut(amountIn, reserveIn, reserveOut);
                }
            }

            (uint256 amount0Out, uint256 amount1Out) = input == token0
                ? (uint256(0), amountOut)
                : (amountOut, uint256(0));

            if (input == antfarmToken) {
                totalFee = totalFee + ((amountIn * fee) / (1000 + fee));
            } else if (output == antfarmToken) {
                totalFee = totalFee + ((amountIn * fee) / 1000);
            } else {
                uint256 feeToPay = antfarmPair.getFees(
                    amount0Out,
                    input == token0 ? amountIn : uint256(0),
                    amount1Out,
                    input == token0 ? uint256(0) : amountIn
                );

                TransferHelper.safeTransferFrom(
                    antfarmToken,
                    msg.sender,
                    address(antfarmPair),
                    feeToPay
                );

                totalFee = totalFee + feeToPay;
            }

            address to = i < sParams.path.length - 2
                ? pairFor(output, sParams.path[i + 2], sParams.fees[i + 1])
                : sParams.to;
            antfarmPair.swap(amount0Out, amount1Out, to);
        }
    }

    // **** LIBRARY FUNCTIONS ADDED INTO THE CONTRACT ****
    // returns sorted token addresses, used to handle return values from pairs sorted in this order
    function sortTokens(address tokenA, address tokenB)
        internal
        view
        returns (address token0, address token1)
    {
        if (tokenA == tokenB) revert IdenticalAddresses();
        if (tokenA == antfarmToken || tokenB == antfarmToken) {
            (token0, token1) = tokenA == antfarmToken
                ? (antfarmToken, tokenB)
                : (antfarmToken, tokenA);
            if (token1 == address(0)) revert ZeroAddress();
        } else {
            (token0, token1) = tokenA < tokenB
                ? (tokenA, tokenB)
                : (tokenB, tokenA);
            if (token0 == address(0)) revert ZeroAddress();
        }
    }

    /// @notice Calculates the CREATE2 address for a pair without making any external calls
    /// @param tokenA Token0 from the AntfarmPair
    /// @param tokenB Token1 from the AntfarmPair
    /// @param fee Associated fee to the AntfarmPair
    /// @return pair The CREATE2 address for the desired AntFarmPair
    function pairFor(
        address tokenA,
        address tokenB,
        uint16 fee
    ) public view returns (address pair) {
        (address token0, address token1) = sortTokens(tokenA, tokenB);
        pair = address(
            uint160(
                uint256(
                    keccak256(
                        abi.encodePacked(
                            hex"ff",
                            factory,
                            keccak256(
                                abi.encodePacked(
                                    token0,
                                    token1,
                                    fee,
                                    antfarmToken
                                )
                            ),
                            token0 == antfarmToken
                                ? hex"99c189a5ef3d337612cf0ce2bd055546e23b91fea9e9e54201b23f14d763f333" // AtfPair init code hash
                                : hex"3b29ecd4cb06592a81cac4799fb24ef6a176fe95ecb50f304972882b150f3f3a" // Pair init code hash
                        )
                    )
                )
            )
        );
    }

    // performs chained getAmountOut calculations on any number of pairs
    function getAmountsOut(
        uint256 amountIn,
        address[] memory path,
        uint16[] memory fees
    ) public view returns (uint256[] memory) {
        if (path.length < 2) revert InvalidPath();
        uint256[] memory amounts = new uint256[](path.length);
        amounts[0] = amountIn;
        for (uint256 i; i < path.length - 1; i++) {
            (uint256 reserveIn, uint256 reserveOut) = getReserves(
                path[i],
                path[i + 1],
                fees[i]
            );
            if (path[i] == antfarmToken) {
                amounts[i + 1] = getAmountOut(
                    (amounts[i] * 1000) / (1000 + fees[i]),
                    reserveIn,
                    reserveOut
                );
            } else if (path[i + 1] == antfarmToken) {
                amounts[i + 1] =
                    (getAmountOut(amounts[i], reserveIn, reserveOut) *
                        (1000 - fees[i])) /
                    1000;
            } else {
                amounts[i + 1] = getAmountOut(
                    amounts[i],
                    reserveIn,
                    reserveOut
                );
            }
        }
        return amounts;
    }

    // performs chained getAmountIn calculations on any number of pairs
    function getAmountsIn(
        uint256 amountOut,
        address[] memory path,
        uint16[] memory fees
    ) public view returns (uint256[] memory) {
        if (path.length < 2) revert InvalidPath();
        uint256[] memory amounts = new uint256[](path.length);
        amounts[path.length - 1] = amountOut;
        for (uint256 i = path.length - 1; i > 0; i--) {
            (uint256 reserveIn, uint256 reserveOut) = getReserves(
                path[i - 1],
                path[i],
                fees[i - 1]
            );
            if (path[i - 1] == antfarmToken) {
                amounts[i - 1] =
                    (getAmountIn(amounts[i], reserveIn, reserveOut) *
                        (1000 + fees[i - 1])) /
                    1000;
            } else if (path[i] == antfarmToken) {
                amounts[i - 1] = getAmountIn(
                    (amounts[i] * 1000) / (1000 - fees[i - 1]),
                    reserveIn,
                    reserveOut
                );
            } else {
                amounts[i - 1] = getAmountIn(amounts[i], reserveIn, reserveOut);
            }
        }
        return amounts;
    }

    // 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) {
        if (amountIn == 0) revert InsufficientInputAmount();
        if (reserveIn == 0 || reserveOut == 0) revert InsufficientLiquidity();
        uint256 numerator = amountIn * reserveOut;
        uint256 denominator = reserveIn + amountIn;
        return 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) {
        if (amountOut == 0) revert InsufficientOutputAmount();
        if (reserveIn == 0 || reserveOut == 0) revert InsufficientLiquidity();
        uint256 numerator = reserveIn * amountOut;
        uint256 denominator = reserveOut - amountOut;
        return (numerator / denominator) + 1;
    }
}

File 2 of 19 : AntfarmOracle.sol
// SPDX-License-Identifier: MIT
pragma solidity =0.8.10;

import "../libraries/fixedpoint/FixedPoint.sol";

error InvalidToken();

/// @title Antfarm Oracle for AntfarmPair
/// @notice Fixed window oracle that recomputes the average price for the entire period once every period
contract AntfarmOracle {
    using FixedPoint for *;

    uint256 public constant PERIOD = 1 hours;

    address public token1;
    address public pair;

    uint256 public price1CumulativeLast;
    uint32 public blockTimestampLast;
    FixedPoint.uq112x112 public price1Average;

    bool public firstUpdateCall;

    constructor(
        address _token1,
        uint256 _price1CumulativeLast,
        uint32 _blockTimestampLast
    ) {
        token1 = _token1;
        pair = msg.sender;
        price1CumulativeLast = _price1CumulativeLast; // fetch the current accumulated price value (1 / 0)
        blockTimestampLast = _blockTimestampLast;
        firstUpdateCall = true;
    }

    /// @notice Average price update
    /// @param price1Cumulative Price cumulative for the associated AntfarmPair's token1
    /// @param blockTimestamp Last block timestamp for the associated AntfarmPair
    /// @dev Only usable by the associated AntfarmPair
    function update(uint256 price1Cumulative, uint32 blockTimestamp) external {
        require(msg.sender == pair);
        unchecked {
            uint32 timeElapsed = blockTimestamp - blockTimestampLast; // overflow is desired
            // ensure that at least one full period has passed since the last update
            if (timeElapsed >= PERIOD || firstUpdateCall) {
                // overflow is desired, casting never truncates
                // cumulative price is in (uq112x112 price * seconds) units so we simply wrap it after division by time elapsed
                price1Average = FixedPoint.uq112x112(
                    uint224(
                        (price1Cumulative - price1CumulativeLast) / timeElapsed
                    )
                );
                price1CumulativeLast = price1Cumulative;
                blockTimestampLast = blockTimestamp;
                if (firstUpdateCall) {
                    firstUpdateCall = false;
                }
            }
        }
    }

    /// @notice Consult the average price for a given token
    /// @param token Price cumulative for the associated AntfarmPair's token
    /// @param amountIn The amount to get the value of
    /// @return amountOut Return the calculated amount (always return 0 before update has been called successfully for the first time)
    function consult(address token, uint256 amountIn)
        external
        view
        returns (uint256 amountOut)
    {
        if (token == token1) {
            amountOut = price1Average.mul(amountIn).decode144();
        } else {
            revert InvalidToken();
        }
    }
}

File 3 of 19 : IAntfarmBase.sol
// SPDX-License-Identifier: MIT
pragma solidity =0.8.10;

import "./pair/IAntfarmPairState.sol";
import "./pair/IAntfarmPairEvents.sol";
import "./pair/IAntfarmPairActions.sol";
import "./pair/IAntfarmPairDerivedState.sol";

interface IAntfarmBase is
    IAntfarmPairState,
    IAntfarmPairEvents,
    IAntfarmPairActions,
    IAntfarmPairDerivedState
{}

File 4 of 19 : IAntfarmFactory.sol
// SPDX-License-Identifier: MIT
pragma solidity =0.8.10;

interface IAntfarmFactory {
    event PairCreated(
        address indexed token0,
        address indexed token1,
        address pair,
        uint16 fee,
        uint256 allPairsLength
    );

    function possibleFees(uint256) external view returns (uint16);

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

    function antfarmToken() external view returns (address);

    function getPairs(uint256 startIndex, uint256 numOfPairs)
        external
        view
        returns (address[] memory, uint256);

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

    function feesForPair(
        address tokenA,
        address tokenB,
        uint256
    ) external view returns (uint16);

    function getFeesForPair(address tokenA, address tokenB)
        external
        view
        returns (uint16[8] memory fees);

    function allPairsLength() external view returns (uint256);

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

File 5 of 19 : IAntfarmPair.sol
// SPDX-License-Identifier: MIT
pragma solidity =0.8.10;

import "./IAntfarmBase.sol";

interface IAntfarmPair is IAntfarmBase {
    /// @notice Initialize the pair
    /// @dev Can only be called by the factory
    function initialize(
        address,
        address,
        uint16,
        address
    ) external;

    /// @notice The Antfarm token address
    /// @return address Address
    function antfarmToken() external view returns (address);

    /// @notice The Oracle instance used to compute swap's fees
    /// @return AntfarmOracle Oracle instance
    function antfarmOracle() external view returns (address);

    /// @notice Calcul fee to pay
    /// @param amount0Out The token0 amount going out of the pool
    /// @param amount0In The token0 amount going in the pool
    /// @param amount1Out The token1 amount going out of the pool
    /// @param amount1In The token1 amount going in the pool
    /// @return feeToPay Calculated fee to be paid
    function getFees(
        uint256 amount0Out,
        uint256 amount0In,
        uint256 amount1Out,
        uint256 amount1In
    ) external view returns (uint256 feeToPay);

    /// @notice Check for the best Oracle to use to perform fee calculation for a swap
    /// @dev Returns address(0) if no better oracle is found.
    /// @param maxReserve Actual oracle reserve0
    /// @return bestOracle Address from the best oracle found
    function scanOracles(uint112 maxReserve)
        external
        view
        returns (address bestOracle);

    /// @notice Update oracle for token
    /// @custom:usability Update the current Oracle with a more suitable one. Revert if the current Oracle is already the more suitable
    function updateOracle() external;
}

File 6 of 19 : IAntfarmRouter.sol
// SPDX-License-Identifier: MIT
pragma solidity =0.8.10;

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

    function WETH() external view returns (address);

    function antfarmToken() external view returns (address);

    struct swapParams {
        address[] path;
        uint16[] fees;
        address to;
    }

    struct swapExactTokensForTokensParams {
        uint256 amountIn;
        uint256 amountOutMin;
        uint256 maxFee;
        address[] path;
        uint16[] fees;
        address to;
        uint256 deadline;
    }

    function swapExactTokensForTokens(
        swapExactTokensForTokensParams calldata params
    ) external returns (uint256[] memory amounts);

    struct swapTokensForExactTokensParams {
        uint256 amountOut;
        uint256 amountInMax;
        uint256 maxFee;
        address[] path;
        uint16[] fees;
        address to;
        uint256 deadline;
    }

    function swapTokensForExactTokens(
        swapTokensForExactTokensParams calldata params
    ) external returns (uint256[] memory amounts);

    struct swapExactETHForTokensParams {
        uint256 amountOutMin;
        uint256 maxFee;
        address[] path;
        uint16[] fees;
        address to;
        uint256 deadline;
    }

    function swapExactETHForTokens(swapExactETHForTokensParams calldata params)
        external
        payable
        returns (uint256[] memory amounts);

    struct swapTokensForExactETHParams {
        uint256 amountOut;
        uint256 amountInMax;
        uint256 maxFee;
        address[] path;
        uint16[] fees;
        address to;
        uint256 deadline;
    }

    function swapTokensForExactETH(swapTokensForExactETHParams calldata params)
        external
        returns (uint256[] memory amounts);

    struct swapExactTokensForETHParams {
        uint256 amountIn;
        uint256 amountOutMin;
        uint256 maxFee;
        address[] path;
        uint16[] fees;
        address to;
        uint256 deadline;
    }

    function swapExactTokensForETH(swapExactTokensForETHParams calldata params)
        external
        returns (uint256[] memory amounts);

    struct swapETHForExactTokensParams {
        uint256 amountOut;
        uint256 maxFee;
        address[] path;
        uint16[] fees;
        address to;
        uint256 deadline;
    }

    function swapETHForExactTokens(swapETHForExactTokensParams calldata params)
        external
        payable
        returns (uint256[] memory amounts);

    function swapExactTokensForTokensSupportingFeeOnTransferTokens(
        swapExactTokensForTokensParams calldata params
    ) external;

    function swapExactETHForTokensSupportingFeeOnTransferTokens(
        swapExactETHForTokensParams calldata params
    ) external payable;

    function swapExactTokensForETHSupportingFeeOnTransferTokens(
        swapExactTokensForETHParams calldata params
    ) external;

    // fetches and sorts the reserves for a pair
    function getReserves(
        address tokenA,
        address tokenB,
        uint16 fee
    ) external view returns (uint256 reserveA, uint256 reserveB);
}

File 7 of 19 : IAntfarmToken.sol
// SPDX-License-Identifier: MIT
pragma solidity =0.8.10;

interface IAntfarmToken {
    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 account) external view returns (uint256);

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

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

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

    function transfer(address recipient, uint256 amount)
        external
        returns (bool);

    function transferFrom(
        address sender,
        address recipient,
        uint256 amount
    ) external returns (bool);

    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    function DOMAIN_SEPARATOR() external view returns (bytes32);

    function burn(uint256 _amount) external;
}

File 8 of 19 : IERC20.sol
// SPDX-License-Identifier: MIT
pragma solidity =0.8.10;

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

    event Approval(
        address indexed owner,
        address indexed spender,
        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);
}

File 9 of 19 : IWETH.sol
// SPDX-License-Identifier: MIT
pragma solidity =0.8.10;

interface IWETH {
    function deposit() external payable;

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

    function withdraw(uint256) external;
}

File 10 of 19 : IAntfarmPairActions.sol
// SPDX-License-Identifier: MIT
pragma solidity =0.8.10;

interface IAntfarmPairActions {
    /// @notice Mint liquidity for a specific position
    /// @dev Low-level function. Should be called from another contract which performs all necessary checks
    /// @param to The address to mint liquidity
    /// @param positionId The ID to store the position to allow multiple positions for a single address
    /// @return liquidity Minted liquidity
    function mint(address to, uint256 positionId)
        external
        returns (uint256 liquidity);

    /// @notice Burn liquidity from a specific position
    /// @dev Low-level function. Should be called from another contract which performs all necessary checks
    /// @param to The address to return the liquidity to
    /// @param positionId The ID of the position to burn liquidity from
    /// @param liquidity Liquidity amount to be burned
    /// @return amount0 The token0 amount received from the liquidity burn
    /// @return amount1 The token1 amount received from the liquidity burn
    function burn(
        address to,
        uint256 liquidity,
        uint256 positionId
    ) external returns (uint256 amount0, uint256 amount1);

    /// @notice Swap tokens
    /// @dev Low-level function. Should be called from another contract which performs all necessary checks
    /// @param amount0Out token0 amount to be swapped
    /// @param amount1Out token1 amount to be swapped
    /// @param to The address to send the swapped tokens
    function swap(
        uint256 amount0Out,
        uint256 amount1Out,
        address to
    ) external;

    /// @notice Force balances to match reserves
    /// @param to The address to send excessive tokens
    function skim(address to) external;

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

    /// @notice Claim dividends for a specific position
    /// @param to The address to receive claimed dividends
    /// @param positionId The ID of the position to claim
    /// @return claimedAmount The amount claimed
    function claimDividend(address to, uint256 positionId)
        external
        returns (uint256 claimedAmount);
}

File 11 of 19 : IAntfarmPairDerivedState.sol
// SPDX-License-Identifier: MIT
pragma solidity =0.8.10;

interface IAntfarmPairDerivedState {
    /// @notice Get position LP tokens
    /// @param operator Position owner
    /// @param positionId ID of the position
    /// @return uint128 LP tokens owned by the operator
    function getPositionLP(address operator, uint256 positionId)
        external
        view
        returns (uint128);

    /// @notice Get pair reserves
    /// @return reserve0 Reserve for token0
    /// @return reserve1 Reserve for token1
    /// @return blockTimestampLast Last block proceeded
    function getReserves()
        external
        view
        returns (
            uint112 reserve0,
            uint112 reserve1,
            uint32 blockTimestampLast
        );

    /// @notice Get Dividend from a specific position
    /// @param operator The address used to get dividends
    /// @param positionId Specific position
    /// @return amount Dividends owned by the address
    function claimableDividends(address operator, uint256 positionId)
        external
        view
        returns (uint256 amount);
}

File 12 of 19 : IAntfarmPairEvents.sol
// SPDX-License-Identifier: MIT
pragma solidity =0.8.10;

interface IAntfarmPairEvents {
    /// @notice Emitted when a position's liquidity is removed
    /// @param sender The address that initiated the burn call
    /// @param amount0 The amount of token0 withdrawn
    /// @param amount1 The amount of token1 withdrawn
    /// @param to The address to send token0 & token1
    event Burn(
        address indexed sender,
        uint256 amount0,
        uint256 amount1,
        address indexed to
    );

    /// @notice Emitted when liquidity is minted for a given position
    /// @param sender The address that initiated the mint call
    /// @param amount0 Required token0 for the minted liquidity
    /// @param amount1 Required token1 for the minted liquidity
    event Mint(address indexed sender, uint256 amount0, uint256 amount1);

    /// @notice Emitted by the pool for any swaps between token0 and token1
    /// @param sender The address that initiated the swap call
    /// @param amount0In Amount of token0 sent to the pair
    /// @param amount1In Amount of token1 sent to the pair
    /// @param amount0Out Amount of token0 going out of the pair
    /// @param amount1Out Amount of token1 going out of the pair
    /// @param to Address to transfer the swapped amount
    event Swap(
        address indexed sender,
        uint256 amount0In,
        uint256 amount1In,
        uint256 amount0Out,
        uint256 amount1Out,
        address indexed to
    );

    /// @notice Emitted by the pool for any call to Sync function
    /// @param reserve0 reserve0 updated from the pair
    /// @param reserve1 reserve1 updated from the pair
    event Sync(uint112 reserve0, uint112 reserve1);
}

File 13 of 19 : IAntfarmPairState.sol
// SPDX-License-Identifier: MIT
pragma solidity =0.8.10;
import "../IAntfarmToken.sol";

interface IAntfarmPairState {
    /// @notice The contract that deployed the AntfarmPair, which must adhere to the IAntfarmFactory interface
    /// @return address The contract address
    function factory() external view returns (address);

    /// @notice The first of the two tokens of the AntfarmPair, sorted by address
    /// @return address The token contract address
    function token0() external view returns (address);

    /// @notice The second of the two tokens of the AntfarmPair, sorted by address
    /// @return address The token contract address
    function token1() external view returns (address);

    /// @notice Fee associated to the AntfarmPair instance
    /// @return uint16 Fee
    function fee() external view returns (uint16);

    /// @notice The LP tokens total circulating supply
    /// @return uint Total LP tokens
    function totalSupply() external view returns (uint256);

    /// @notice The AntFarmPair AntFarm's tokens cumulated fees
    /// @return uint Total Antfarm tokens
    function antfarmTokenReserve() external view returns (uint256);
}

File 14 of 19 : Babylonian.sol
// SPDX-License-Identifier: GPL-3.0-or-later

pragma solidity >=0.8.0;

// computes square roots using the babylonian method
// https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method
library Babylonian {
    // credit for this implementation goes to
    // https://github.com/abdk-consulting/abdk-libraries-solidity/blob/master/ABDKMath64x64.sol#L687
    function sqrt(uint256 x) internal pure returns (uint256) {
        if (x == 0) return 0;
        // this block is equivalent to r = uint256(1) << (BitMath.mostSignificantBit(x) / 2);
        // however that code costs significantly more gas
        uint256 xx = x;
        uint256 r = 1;
        if (xx >= 0x100000000000000000000000000000000) {
            xx >>= 128;
            r <<= 64;
        }
        if (xx >= 0x10000000000000000) {
            xx >>= 64;
            r <<= 32;
        }
        if (xx >= 0x100000000) {
            xx >>= 32;
            r <<= 16;
        }
        if (xx >= 0x10000) {
            xx >>= 16;
            r <<= 8;
        }
        if (xx >= 0x100) {
            xx >>= 8;
            r <<= 4;
        }
        if (xx >= 0x10) {
            xx >>= 4;
            r <<= 2;
        }
        if (xx >= 0x8) {
            r <<= 1;
        }
        r = (r + x / r) >> 1;
        r = (r + x / r) >> 1;
        r = (r + x / r) >> 1;
        r = (r + x / r) >> 1;
        r = (r + x / r) >> 1;
        r = (r + x / r) >> 1;
        r = (r + x / r) >> 1; // Seven iterations should be enough
        uint256 r1 = x / r;
        return (r < r1 ? r : r1);
    }
}

File 15 of 19 : BitMath.sol
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity >=0.8.0;

library BitMath {
    // returns the 0 indexed position of the most significant bit of the input x
    // s.t. x >= 2**msb and x < 2**(msb+1)
    function mostSignificantBit(uint256 x) internal pure returns (uint8 r) {
        require(x > 0, "BitMath::mostSignificantBit: zero");

        if (x >= 0x100000000000000000000000000000000) {
            x >>= 128;
            r += 128;
        }
        if (x >= 0x10000000000000000) {
            x >>= 64;
            r += 64;
        }
        if (x >= 0x100000000) {
            x >>= 32;
            r += 32;
        }
        if (x >= 0x10000) {
            x >>= 16;
            r += 16;
        }
        if (x >= 0x100) {
            x >>= 8;
            r += 8;
        }
        if (x >= 0x10) {
            x >>= 4;
            r += 4;
        }
        if (x >= 0x4) {
            x >>= 2;
            r += 2;
        }
        if (x >= 0x2) r += 1;
    }

    // returns the 0 indexed position of the least significant bit of the input x
    // s.t. (x & 2**lsb) != 0 and (x & (2**(lsb) - 1)) == 0)
    // i.e. the bit at the index is set and the mask of all lower bits is 0
    function leastSignificantBit(uint256 x) internal pure returns (uint8 r) {
        require(x > 0, "BitMath::leastSignificantBit: zero");

        r = 255;
        if (x & type(uint128).max > 0) {
            r -= 128;
        } else {
            x >>= 128;
        }
        if (x & type(uint64).max > 0) {
            r -= 64;
        } else {
            x >>= 64;
        }
        if (x & type(uint32).max > 0) {
            r -= 32;
        } else {
            x >>= 32;
        }
        if (x & type(uint16).max > 0) {
            r -= 16;
        } else {
            x >>= 16;
        }
        if (x & type(uint16).max > 0) {
            r -= 8;
        } else {
            x >>= 8;
        }
        if (x & 0xf > 0) {
            r -= 4;
        } else {
            x >>= 4;
        }
        if (x & 0x3 > 0) {
            r -= 2;
        } else {
            x >>= 2;
        }
        if (x & 0x1 > 0) r -= 1;
    }
}

File 16 of 19 : FixedPoint.sol
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity >=0.8.0;

import "./FullMath.sol";
import "./Babylonian.sol";
import "./BitMath.sol";

// a library for handling binary fixed point numbers (https://en.wikipedia.org/wiki/Q_(number_format))
library FixedPoint {
    // range: [0, 2**112 - 1]
    // resolution: 1 / 2**112
    struct uq112x112 {
        uint224 _x;
    }

    // range: [0, 2**144 - 1]
    // resolution: 1 / 2**112
    struct uq144x112 {
        uint256 _x;
    }

    uint8 public constant RESOLUTION = 112;
    uint256 public constant Q112 = 0x10000000000000000000000000000; // 2**112
    uint256 private constant Q224 = 0x100000000000000000000000000000000000000000000000000000000; // 2**224
    uint256 private constant LOWER_MASK = 0xffffffffffffffffffffffffffff; // decimal of UQ*x112 (lower 112 bits)

    // encode a uint112 as a UQ112x112
    function encode(uint112 x) internal pure returns (uq112x112 memory) {
        return uq112x112(uint224(x) << RESOLUTION);
    }

    // encodes a uint144 as a UQ144x112
    function encode144(uint144 x) internal pure returns (uq144x112 memory) {
        return uq144x112(uint256(x) << RESOLUTION);
    }

    // decode a UQ112x112 into a uint112 by truncating after the radix point
    function decode(uq112x112 memory self) internal pure returns (uint112) {
        return uint112(self._x >> RESOLUTION);
    }

    // decode a UQ144x112 into a uint144 by truncating after the radix point
    function decode144(uq144x112 memory self) internal pure returns (uint144) {
        return uint144(self._x >> RESOLUTION);
    }

    // multiply a UQ112x112 by a uint, returning a UQ144x112
    // reverts on overflow
    function mul(uq112x112 memory self, uint256 y) internal pure returns (uq144x112 memory) {
        uint256 z = 0;
        require(y == 0 || (z = self._x * y) / y == self._x, "FixedPoint::mul: overflow");
        return uq144x112(z);
    }

    // multiply a UQ112x112 by an int and decode, returning an int
    // reverts on overflow
    function muli(uq112x112 memory self, int256 y) internal pure returns (int256) {
        uint256 z = FullMath.mulDiv(self._x, uint256(y < 0 ? -y : y), Q112);
        require(z < 2**255, "FixedPoint::muli: overflow");
        return y < 0 ? -int256(z) : int256(z);
    }

    // multiply a UQ112x112 by a UQ112x112, returning a UQ112x112
    // lossy
    function muluq(uq112x112 memory self, uq112x112 memory other) internal pure returns (uq112x112 memory) {
        if (self._x == 0 || other._x == 0) {
            return uq112x112(0);
        }
        uint112 upper_self = uint112(self._x >> RESOLUTION); // * 2^0
        uint112 lower_self = uint112(self._x & LOWER_MASK); // * 2^-112
        uint112 upper_other = uint112(other._x >> RESOLUTION); // * 2^0
        uint112 lower_other = uint112(other._x & LOWER_MASK); // * 2^-112

        // partial products
        uint224 upper = uint224(upper_self) * upper_other; // * 2^0
        uint224 lower = uint224(lower_self) * lower_other; // * 2^-224
        uint224 uppers_lowero = uint224(upper_self) * lower_other; // * 2^-112
        uint224 uppero_lowers = uint224(upper_other) * lower_self; // * 2^-112

        // so the bit shift does not overflow
        require(upper <= type(uint112).max, "FixedPoint::muluq: upper overflow");

        // this cannot exceed 256 bits, all values are 224 bits
        uint256 sum = uint256(upper << RESOLUTION) + uppers_lowero + uppero_lowers + (lower >> RESOLUTION);

        // so the cast does not overflow
        require(sum <= type(uint224).max, "FixedPoint::muluq: sum overflow");

        return uq112x112(uint224(sum));
    }

    // divide a UQ112x112 by a UQ112x112, returning a UQ112x112
    function divuq(uq112x112 memory self, uq112x112 memory other) internal pure returns (uq112x112 memory) {
        require(other._x > 0, "FixedPoint::divuq: division by zero");
        if (self._x == other._x) {
            return uq112x112(uint224(Q112));
        }
        if (self._x <= type(uint144).max) {
            uint256 value = (uint256(self._x) << RESOLUTION) / other._x;
            require(value <= type(uint224).max, "FixedPoint::divuq: overflow");
            return uq112x112(uint224(value));
        }

        uint256 result = FullMath.mulDiv(Q112, self._x, other._x);
        require(result <= type(uint224).max, "FixedPoint::divuq: overflow");
        return uq112x112(uint224(result));
    }

    // returns a UQ112x112 which represents the ratio of the numerator to the denominator
    // can be lossy
    function fraction(uint256 numerator, uint256 denominator) internal pure returns (uq112x112 memory) {
        require(denominator > 0, "FixedPoint::fraction: division by zero");
        if (numerator == 0) return FixedPoint.uq112x112(0);

        if (numerator <= type(uint144).max) {
            uint256 result = (numerator << RESOLUTION) / denominator;
            require(result <= type(uint224).max, "FixedPoint::fraction: overflow");
            return uq112x112(uint224(result));
        } else {
            uint256 result = FullMath.mulDiv(numerator, Q112, denominator);
            require(result <= type(uint224).max, "FixedPoint::fraction: overflow");
            return uq112x112(uint224(result));
        }
    }

    // take the reciprocal of a UQ112x112
    // reverts on overflow
    // lossy
    function reciprocal(uq112x112 memory self) internal pure returns (uq112x112 memory) {
        require(self._x != 0, "FixedPoint::reciprocal: reciprocal of zero");
        require(self._x != 1, "FixedPoint::reciprocal: overflow");
        return uq112x112(uint224(Q224 / self._x));
    }

    // square root of a UQ112x112
    // lossy between 0/1 and 40 bits
    function sqrt(uq112x112 memory self) internal pure returns (uq112x112 memory) {
        if (self._x <= type(uint144).max) {
            return uq112x112(uint224(Babylonian.sqrt(uint256(self._x) << 112)));
        }

        uint8 safeShiftBits = 255 - BitMath.mostSignificantBit(self._x);
        safeShiftBits -= safeShiftBits % 2;
        return uq112x112(uint224(Babylonian.sqrt(uint256(self._x) << safeShiftBits) << ((112 - safeShiftBits) / 2)));
    }
}

File 17 of 19 : FullMath.sol
// SPDX-License-Identifier: CC-BY-4.0
pragma solidity >=0.8.0;

// taken from https://medium.com/coinmonks/math-in-solidity-part-3-percents-and-proportions-4db014e080b1
// license is CC-BY-4.0
library FullMath {
    function fullMul(uint256 x, uint256 y) internal pure returns (uint256 l, uint256 h) {
        uint256 mm = mulmod(x, y, type(uint256).max);
        l = x * y;
        h = mm - l;
        if (mm < l) h -= 1;
    }

    function fullDiv(
        uint256 l,
        uint256 h,
        uint256 d
    ) private pure returns (uint256) {
        uint256 pow2 = d & (type(uint256).max - d + 1) & d;
        d /= pow2;
        l /= pow2;
        l += h * (((type(uint256).max - pow2 + 1) & pow2) / pow2 + 1);
        uint256 r = 1;
        r *= 2 - d * r;
        r *= 2 - d * r;
        r *= 2 - d * r;
        r *= 2 - d * r;
        r *= 2 - d * r;
        r *= 2 - d * r;
        r *= 2 - d * r;
        r *= 2 - d * r;
        return l * r;
    }

    function mulDiv(
        uint256 x,
        uint256 y,
        uint256 d
    ) internal pure returns (uint256) {
        (uint256 l, uint256 h) = fullMul(x, y);

        uint256 mm = mulmod(x, y, d);
        if (mm > l) h -= 1;
        l -= mm;

        if (h == 0) return l / d;

        require(h < d, "FullMath: FULLDIV_OVERFLOW");
        return fullDiv(l, h, d);
    }
}

File 18 of 19 : TransferHelper.sol
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity =0.8.10;

// 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"
        );
    }
}

File 19 of 19 : AntfarmRouterErrors.sol
// SPDX-License-Identifier: MIT
pragma solidity =0.8.10;

error Expired();
error InsufficientOutputAmount();
error InsufficientInputAmount();
error InsufficientLiquidity();
error InsufficientMaxFee();
error ExcessiveInputAmount();
error InvalidPath();
error IdenticalAddresses();
error ZeroAddress();

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 1000
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "metadata": {
    "useLiteralContent": true
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_factory","type":"address"},{"internalType":"address","name":"_WETH","type":"address"},{"internalType":"address","name":"_antfarmToken","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ExcessiveInputAmount","type":"error"},{"inputs":[],"name":"Expired","type":"error"},{"inputs":[],"name":"IdenticalAddresses","type":"error"},{"inputs":[],"name":"InsufficientInputAmount","type":"error"},{"inputs":[],"name":"InsufficientLiquidity","type":"error"},{"inputs":[],"name":"InsufficientMaxFee","type":"error"},{"inputs":[],"name":"InsufficientOutputAmount","type":"error"},{"inputs":[],"name":"InvalidPath","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"inputs":[],"name":"WETH","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"antfarmToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"uint16[]","name":"fees","type":"uint16[]"}],"name":"getAmountsIn","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"uint16[]","name":"fees","type":"uint16[]"}],"name":"getAmountsOut","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"uint16","name":"fee","type":"uint16"}],"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":"uint16","name":"fee","type":"uint16"}],"name":"pairFor","outputs":[{"internalType":"address","name":"pair","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"maxFee","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"uint16[]","name":"fees","type":"uint16[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IAntfarmRouter.swapETHForExactTokensParams","name":"params","type":"tuple"}],"name":"swapETHForExactTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"uint256","name":"maxFee","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"uint16[]","name":"fees","type":"uint16[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IAntfarmRouter.swapExactETHForTokensParams","name":"params","type":"tuple"}],"name":"swapExactETHForTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"uint256","name":"maxFee","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"uint16[]","name":"fees","type":"uint16[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IAntfarmRouter.swapExactETHForTokensParams","name":"params","type":"tuple"}],"name":"swapExactETHForTokensSupportingFeeOnTransferTokens","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"uint256","name":"maxFee","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"uint16[]","name":"fees","type":"uint16[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IAntfarmRouter.swapExactTokensForETHParams","name":"params","type":"tuple"}],"name":"swapExactTokensForETH","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"uint256","name":"maxFee","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"uint16[]","name":"fees","type":"uint16[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IAntfarmRouter.swapExactTokensForETHParams","name":"params","type":"tuple"}],"name":"swapExactTokensForETHSupportingFeeOnTransferTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"uint256","name":"maxFee","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"uint16[]","name":"fees","type":"uint16[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IAntfarmRouter.swapExactTokensForTokensParams","name":"params","type":"tuple"}],"name":"swapExactTokensForTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"uint256","name":"maxFee","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"uint16[]","name":"fees","type":"uint16[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IAntfarmRouter.swapExactTokensForTokensParams","name":"params","type":"tuple"}],"name":"swapExactTokensForTokensSupportingFeeOnTransferTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMax","type":"uint256"},{"internalType":"uint256","name":"maxFee","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"uint16[]","name":"fees","type":"uint16[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IAntfarmRouter.swapTokensForExactETHParams","name":"params","type":"tuple"}],"name":"swapTokensForExactETH","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMax","type":"uint256"},{"internalType":"uint256","name":"maxFee","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"uint16[]","name":"fees","type":"uint16[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IAntfarmRouter.swapTokensForExactTokensParams","name":"params","type":"tuple"}],"name":"swapTokensForExactTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

60e06040523480156200001157600080fd5b506040516200417c3803806200417c833981016040819052620000349162000162565b6001600160a01b038316620000905760405162461bcd60e51b815260206004820152601460248201527f4e554c4c5f464143544f52595f4144445245535300000000000000000000000060448201526064015b60405180910390fd5b6001600160a01b038216620000dc5760405162461bcd60e51b81526020600482015260116024820152704e554c4c5f574554485f4144445245535360781b604482015260640162000087565b6001600160a01b038116620001275760405162461bcd60e51b815260206004820152601060248201526f4e554c4c5f4154465f4144445245535360801b604482015260640162000087565b6001600160a01b0392831660805290821660a0521660c052620001ac565b80516001600160a01b03811681146200015d57600080fd5b919050565b6000806000606084860312156200017857600080fd5b620001838462000145565b9250620001936020850162000145565b9150620001a36040850162000145565b90509250925092565b60805160a05160c051613e88620002f4600039600081816102ca015281816108f001528181610cdf01528181610fd10152818161129a0152818161138c0152818161196d01528181611a5b01528181611cb201528181611d1b015281816124ac01528181612b4401528181612ba401528181612c4c01528181612cc101528181612dda015281816131c00152818161323501528181613382015281816136d7015281816137120152818161374d0152818161378601526137ad01526000818161010701528181610296015281816103c301528181610444015281816104b801528181610c4101528181610eb8015281816114ea015281816115f40152818161168201528181611e2a01528181611f4301528181611fd10152818161257b0152818161269b0152818161282001526128e90152600081816102fe0152611ce00152613e886000f3fe6080604052600436106100f75760003560e01c8063a502d3a01161008a578063cd0ba5df11610059578063cd0ba5df14610320578063d2a4949a14610333578063e80d2b3414610353578063ef1c88fb1461037357600080fd5b8063a502d3a01461024c578063ad5c464814610284578063c12a00a8146102b8578063c45a0155146102ec57600080fd5b80635ec70f5d116100c65780635ec70f5d146101c4578063636f5e0e146101e45780636451737d146101f7578063951eb42d1461021757600080fd5b80630438c45e1461013b57806305f9b6271461014e578063164d01be1461018457806359c90959146101a457600080fd5b3661013657336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461013457610134613855565b005b600080fd5b61013461014936600461387d565b610393565b34801561015a57600080fd5b5061016e6101693660046138cc565b6108bc565b60405161017b9190613901565b60405180910390f35b34801561019057600080fd5b5061016e61019f3660046138cc565b610c0f565b3480156101b057600080fd5b5061016e6101bf3660046138cc565b610f9d565b3480156101d057600080fd5b5061016e6101df366004613a50565b61116a565b61016e6101f236600461387d565b6114b8565b34801561020357600080fd5b5061016e610212366004613a50565b61186a565b34801561022357600080fd5b50610237610232366004613b1b565b611b76565b6040805192835260208301919091520161017b565b34801561025857600080fd5b5061026c610267366004613b1b565b611c4e565b6040516001600160a01b03909116815260200161017b565b34801561029057600080fd5b5061026c7f000000000000000000000000000000000000000000000000000000000000000081565b3480156102c457600080fd5b5061026c7f000000000000000000000000000000000000000000000000000000000000000081565b3480156102f857600080fd5b5061026c7f000000000000000000000000000000000000000000000000000000000000000081565b61016e61032e36600461387d565b611df8565b34801561033f57600080fd5b5061013461034e3660046138cc565b6120e1565b34801561035f57600080fd5b5061016e61036e3660046138cc565b612478565b34801561037f57600080fd5b5061013461038e3660046138cc565b61266b565b8060a00135428110156103b957604051630407b05b60e31b815260040160405180910390fd5b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166103f06040840184613b5e565b600081811061040157610401613ba8565b90506020020160208101906104169190613bbe565b6001600160a01b03161461043d576040516320db826760e01b815260040160405180910390fd5b60003490507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561049d57600080fd5b505af11580156104b1573d6000803e3d6000fd5b50505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a9059cbb6105848580604001906104f89190613b5e565b600081811061050957610509613ba8565b905060200201602081019061051e9190613bbe565b61052b6040880188613b5e565b600181811061053c5761053c613ba8565b90506020020160208101906105519190613bbe565b61055e6060890189613b5e565b600081811061056f5761056f613ba8565b90506020020160208101906102679190613be0565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602481018490526044016020604051808303816000875af11580156105d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105f59190613bfb565b61060157610601613855565b60006106106040850185613b5e565b600161061f6040880188613b5e565b61062a929150613c33565b81811061063957610639613ba8565b905060200201602081019061064e9190613bbe565b6001600160a01b03166370a0823161066c60a0870160808801613bbe565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa1580156106b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106d49190613c4a565b9050600060405180606001604052808680604001906106f39190613b5e565b808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152505050908252506020016107376060880188613b5e565b8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050509082525060200161077e60a0880160808901613bbe565b6001600160a01b031690529050602085013561079982612968565b11156107b857604051634b41cb4560e01b815260040160405180910390fd5b8435826107c86040880188613b5e565b60016107d760408b018b613b5e565b6107e2929150613c33565b8181106107f1576107f1613ba8565b90506020020160208101906108069190613bbe565b6001600160a01b03166370a0823161082460a08a0160808b01613bbe565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015610868573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061088c9190613c4a565b6108969190613c33565b10156108b5576040516342301c2360e01b815260040160405180910390fd5b5050505050565b60608160c00135428110156108e457604051630407b05b60e31b815260040160405180910390fd5b60006001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001661091d6060860186613b5e565b600081811061092e5761092e613ba8565b90506020020160208101906109439190613bbe565b6001600160a01b03161461095b5783602001356109b9565b6103e861096b6080860186613b5e565b600081811061097c5761097c613ba8565b90506020020160208101906109919190613be0565b61099d906103e8613c63565b6109af9061ffff166020870135613c89565b6109b99190613ca8565b9050610a4384356109cd6060870187613b5e565b80806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250610a0c925050506080880188613b5e565b8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061116a92505050565b92508083600081518110610a5957610a59613ba8565b60200260200101511115610a805760405163e1b0da4f60e01b815260040160405180910390fd5b610b4d610a906060860186613b5e565b6000818110610aa157610aa1613ba8565b9050602002016020810190610ab69190613bbe565b33610b2d610ac76060890189613b5e565b6000818110610ad857610ad8613ba8565b9050602002016020810190610aed9190613bbe565b610afa60608a018a613b5e565b6001818110610b0b57610b0b613ba8565b9050602002016020810190610b209190613bbe565b61055e60808b018b613b5e565b86600081518110610b4057610b40613ba8565b6020026020010151612f15565b6040840135610be984610b636060880188613b5e565b80806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250610ba2925050506080890189613b5e565b80806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250610be49250505060c08a0160a08b01613bbe565b613092565b1115610c0857604051634b41cb4560e01b815260040160405180910390fd5b5050919050565b60608160c0013542811015610c3757604051630407b05b60e31b815260040160405180910390fd5b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016610c6e6060850185613b5e565b6001610c7d6060880188613b5e565b610c88929150613c33565b818110610c9757610c97613ba8565b9050602002016020810190610cac9190613bbe565b6001600160a01b031614610cd3576040516320db826760e01b815260040160405180910390fd5b60006001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016610d0c6060860186613b5e565b6000818110610d1d57610d1d613ba8565b9050602002016020810190610d329190613bbe565b6001600160a01b031614610d4a578360200135610da8565b6103e8610d5a6080860186613b5e565b6000818110610d6b57610d6b613ba8565b9050602002016020810190610d809190613be0565b610d8c906103e8613c63565b610d9e9061ffff166020870135613c89565b610da89190613ca8565b9050610dbc84356109cd6060870187613b5e565b92508083600081518110610dd257610dd2613ba8565b60200260200101511115610df95760405163e1b0da4f60e01b815260040160405180910390fd5b610e09610a906060860186613b5e565b6040840135610e9784610e1f6060880188613b5e565b80806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250610e5e925050506080890189613b5e565b80806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250309250613092915050565b1115610eb657604051634b41cb4560e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316632e1a7d4d8460018651610ef49190613c33565b81518110610f0457610f04613ba8565b60200260200101516040518263ffffffff1660e01b8152600401610f2a91815260200190565b600060405180830381600087803b158015610f4457600080fd5b505af1158015610f58573d6000803e3d6000fd5b50610c089250610f7191505060c0860160a08701613bbe565b8460018651610f809190613c33565b81518110610f9057610f90613ba8565b6020026020010151613492565b60608160c0013542811015610fc557604051630407b05b60e31b815260040160405180910390fd5b60006001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016610ffe6060860186613b5e565b600081811061100f5761100f613ba8565b90506020020160208101906110249190613bbe565b6001600160a01b031614611039578335611094565b6103e86110496080860186613b5e565b600081811061105a5761105a613ba8565b905060200201602081019061106f9190613be0565b61107b906103e8613c63565b61108a9061ffff168635613c89565b6110949190613ca8565b905061111d816110a76060870187613b5e565b808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506110e6925050506080880188613b5e565b8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061186a92505050565b9250836020013583600185516111339190613c33565b8151811061114357611143613ba8565b60200260200101511015610a80576040516342301c2360e01b815260040160405180910390fd5b606060028351101561118f576040516320db826760e01b815260040160405180910390fd5b6000835167ffffffffffffffff8111156111ab576111ab613945565b6040519080825280602002602001820160405280156111d4578160200160208202803683370190505b5090508481600186516111e79190613c33565b815181106111f7576111f7613ba8565b6020026020010181815250506000600185516112139190613c33565b90505b80156114af5760008061128b8761122e600186613c33565b8151811061123e5761123e613ba8565b602002602001015188858151811061125857611258613ba8565b60200260200101518860018761126e9190613c33565b8151811061127e5761127e613ba8565b6020026020010151611b76565b90925090506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016876112c6600186613c33565b815181106112d6576112d6613ba8565b60200260200101516001600160a01b0316141561138a576103e8866112fc600186613c33565b8151811061130c5761130c613ba8565b60200260200101516103e86113219190613c63565b61ffff1661134986868151811061133a5761133a613ba8565b6020026020010151858561357a565b6113539190613c89565b61135d9190613ca8565b84611369600186613c33565b8151811061137957611379613ba8565b60200260200101818152505061149a565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168784815181106113c6576113c6613ba8565b60200260200101516001600160a01b0316141561144d5761135d866113ec600186613c33565b815181106113fc576113fc613ba8565b60200260200101516103e86114119190613cca565b61ffff1685858151811061142757611427613ba8565b60200260200101516103e861143c9190613c89565b6114469190613ca8565b838361357a565b61147184848151811061146257611462613ba8565b6020026020010151838361357a565b8461147d600186613c33565b8151811061148d5761148d613ba8565b6020026020010181815250505b505080806114a790613ced565b915050611216565b50949350505050565b60608160a00135428110156114e057604051630407b05b60e31b815260040160405180910390fd5b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166115176040850185613b5e565b600081811061152857611528613ba8565b905060200201602081019061153d9190613bbe565b6001600160a01b031614611564576040516320db826760e01b815260040160405180910390fd5b6115b583356115766040860186613b5e565b80806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250610a0c925050506060870187613b5e565b915034826000815181106115cb576115cb613ba8565b602002602001015111156115f25760405163e1b0da4f60e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db08360008151811061163457611634613ba8565b60200260200101516040518263ffffffff1660e01b81526004016000604051808303818588803b15801561166757600080fd5b505af115801561167b573d6000803e3d6000fd5b50505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a9059cbb6116c28580604001906104f89190613b5e565b846000815181106116d5576116d5613ba8565b60200260200101516040518363ffffffff1660e01b815260040161170e9291906001600160a01b03929092168252602082015260400190565b6020604051808303816000875af115801561172d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117519190613bfb565b61175d5761175d613855565b60208301356117f4836117736040870187613b5e565b808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506117b2925050506060880188613b5e565b80806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250610be49250505060a0890160808a01613bbe565b111561181357604051634b41cb4560e01b815260040160405180910390fd5b8160008151811061182657611826613ba8565b602002602001015134111561186457611864338360008151811061184c5761184c613ba8565b60200260200101513461185f9190613c33565b613492565b50919050565b606060028351101561188f576040516320db826760e01b815260040160405180910390fd5b6000835167ffffffffffffffff8111156118ab576118ab613945565b6040519080825280602002602001820160405280156118d4578160200160208202803683370190505b50905084816000815181106118eb576118eb613ba8565b60200260200101818152505060005b600185516119089190613c33565b8110156114af5760008061196787848151811061192757611927613ba8565b60200260200101518885600161193d9190613d04565b8151811061194d5761194d613ba8565b602002602001015188868151811061127e5761127e613ba8565b915091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168784815181106119a7576119a7613ba8565b60200260200101516001600160a01b03161415611a5157611a248684815181106119d3576119d3613ba8565b60200260200101516103e86119e89190613c63565b61ffff168585815181106119fe576119fe613ba8565b60200260200101516103e8611a139190613c89565b611a1d9190613ca8565b83836135fe565b84611a30856001613d04565b81518110611a4057611a40613ba8565b602002602001018181525050611b61565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001687611a87856001613d04565b81518110611a9757611a97613ba8565b60200260200101516001600160a01b03161415611b14576103e8868481518110611ac357611ac3613ba8565b60200260200101516103e8611ad89190613cca565b61ffff16611b00868681518110611af157611af1613ba8565b602002602001015185856135fe565b611b0a9190613c89565b611a249190613ca8565b611b38848481518110611b2957611b29613ba8565b602002602001015183836135fe565b84611b44856001613d04565b81518110611b5457611b54613ba8565b6020026020010181815250505b50508080611b6e90613d1c565b9150506118fa565b6000806000611b858686613686565b509050600080611b96888888611c4e565b6001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa158015611bd3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bf79190613d55565b506dffffffffffffffffffffffffffff1691506dffffffffffffffffffffffffffff169150826001600160a01b0316886001600160a01b031614611c3c578082611c3f565b81815b90999098509650505050505050565b6000806000611c5d8686613686565b6040516bffffffffffffffffffffffff19606084811b8216602084015283811b821660348401527fffff00000000000000000000000000000000000000000000000000000000000060f08a901b1660488401527f0000000000000000000000000000000000000000000000000000000000000000901b16604a82015291935091507f000000000000000000000000000000000000000000000000000000000000000090605e01604051602081830303815290604052805190602001207f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b031614611d8d576040518060400160405280602081526020017f3b29ecd4cb06592a81cac4799fb24ef6a176fe95ecb50f304972882b150f3f3a815250611dc4565b6040518060400160405280602081526020017f99c189a5ef3d337612cf0ce2bd055546e23b91fea9e9e54201b23f14d763f3338152505b604051602001611dd693929190613dd1565b60408051601f1981840301815291905280516020909101209695505050505050565b60608160a0013542811015611e2057604051630407b05b60e31b815260040160405180910390fd5b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016611e576040850185613b5e565b6000818110611e6857611e68613ba8565b9050602002016020810190611e7d9190613bbe565b6001600160a01b031614611ea4576040516320db826760e01b815260040160405180910390fd5b611ef434611eb56040860186613b5e565b808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506110e6925050506060870187613b5e565b915082600001358260018451611f0a9190613c33565b81518110611f1a57611f1a613ba8565b60200260200101511015611f41576040516342301c2360e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db083600081518110611f8357611f83613ba8565b60200260200101516040518263ffffffff1660e01b81526004016000604051808303818588803b158015611fb657600080fd5b505af1158015611fca573d6000803e3d6000fd5b50505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a9059cbb6120118580604001906104f89190613b5e565b8460008151811061202457612024613ba8565b60200260200101516040518363ffffffff1660e01b815260040161205d9291906001600160a01b03929092168252602082015260400190565b6020604051808303816000875af115801561207c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120a09190613bfb565b6120ac576120ac613855565b60208301356120c2836117736040870187613b5e565b111561186457604051634b41cb4560e01b815260040160405180910390fd5b8060c001354281101561210757604051630407b05b60e31b815260040160405180910390fd5b6121bb6121176060840184613b5e565b600081811061212857612128613ba8565b905060200201602081019061213d9190613bbe565b336121b461214e6060870187613b5e565b600081811061215f5761215f613ba8565b90506020020160208101906121749190613bbe565b6121816060880188613b5e565b600181811061219257612192613ba8565b90506020020160208101906121a79190613bbe565b61055e6080890189613b5e565b8535612f15565b60006121ca6060840184613b5e565b60016121d96060870187613b5e565b6121e4929150613c33565b8181106121f3576121f3613ba8565b90506020020160208101906122089190613bbe565b6001600160a01b03166370a0823161222660c0860160a08701613bbe565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa15801561226a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061228e9190613c4a565b9050600060405180606001604052808580606001906122ad9190613b5e565b808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152505050908252506020016122f16080870187613b5e565b8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050509082525060200161233860c0870160a08801613bbe565b6001600160a01b031690529050604084013561235382612968565b111561237257604051634b41cb4560e01b815260040160405180910390fd5b6020840135826123856060870187613b5e565b600161239460608a018a613b5e565b61239f929150613c33565b8181106123ae576123ae613ba8565b90506020020160208101906123c39190613bbe565b6001600160a01b03166370a082316123e160c0890160a08a01613bbe565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015612425573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124499190613c4a565b6124539190613c33565b1015612472576040516342301c2360e01b815260040160405180910390fd5b50505050565b60608160c00135428110156124a057604051630407b05b60e31b815260040160405180910390fd5b60006001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166124d96060860186613b5e565b60008181106124ea576124ea613ba8565b90506020020160208101906124ff9190613bbe565b6001600160a01b03161461251457833561256f565b6103e86125246080860186613b5e565b600081811061253557612535613ba8565b905060200201602081019061254a9190613be0565b612556906103e8613c63565b6125659061ffff168635613c89565b61256f9190613ca8565b90506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166125a86060860186613b5e565b60016125b76060890189613b5e565b6125c2929150613c33565b8181106125d1576125d1613ba8565b90506020020160208101906125e69190613bbe565b6001600160a01b03161461260d576040516320db826760e01b815260040160405180910390fd5b61261e816110a76060870187613b5e565b9250836020013583600185516126349190613c33565b8151811061264457612644613ba8565b60200260200101511015610df9576040516342301c2360e01b815260040160405180910390fd5b8060c001354281101561269157604051630407b05b60e31b815260040160405180910390fd5b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166126c86060840184613b5e565b60016126d76060870187613b5e565b6126e2929150613c33565b8181106126f1576126f1613ba8565b90506020020160208101906127069190613bbe565b6001600160a01b03161461272d576040516320db826760e01b815260040160405180910390fd5b61273d6121176060840184613b5e565b6000604051806060016040528084806060019061275a9190613b5e565b8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050509082525060200161279e6080860186613b5e565b8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050509082525030602090910152905060408301356127e982612968565b111561280857604051634b41cb4560e01b815260040160405180910390fd5b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561286f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128939190613c4a565b905083602001358110156128ba576040516342301c2360e01b815260040160405180910390fd5b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561293557600080fd5b505af1158015612949573d6000803e3d6000fd5b50612472925061296291505060c0860160a08701613bbe565b82613492565b6000805b82515161297b90600190613c33565b811015611864576000808460000151838151811061299b5761299b613ba8565b602002602001015185600001518460016129b59190613d04565b815181106129c5576129c5613ba8565b6020026020010151915091506000856020015184815181106129e9576129e9613ba8565b602002602001015190506000612a00848484611c4e565b90506000612a0e8585613686565b509050600080600080856001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa158015612a55573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a799190613d55565b506dffffffffffffffffffffffffffff1691506dffffffffffffffffffffffffffff169150600080866001600160a01b03168b6001600160a01b031614612ac1578284612ac4565b83835b6040516370a0823160e01b81526001600160a01b038b8116600483015292945090925083918d16906370a0823190602401602060405180830381865afa158015612b12573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b369190613c4a565b612b409190613c33565b95507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168b6001600160a01b03161415612ba257612b9b612b8b8a6103e8613c63565b61ffff16611a13886103e8613c89565b9450612c1a565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168a6001600160a01b03161415612c0c576103e8612be98a82613cca565b61ffff16612bf88885856135fe565b612c029190613c89565b612b9b9190613ca8565b612c178683836135fe565b94505b50505050600080846001600160a01b0316896001600160a01b031614612c4257826000612c46565b6000835b915091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316896001600160a01b03161415612cbf57612c90876103e8613c63565b61ffff168761ffff1685612ca49190613c89565b612cae9190613ca8565b612cb8908c613d04565b9a50612e0f565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316886001600160a01b03161415612d0a576103e8612ca461ffff891686613c89565b6000866001600160a01b0316632f72563884886001600160a01b03168d6001600160a01b031614612d3c576000612d3e565b875b858a6001600160a01b03168f6001600160a01b031614612d5e5789612d61565b60005b6040516001600160e01b031960e087901b1681526004810194909452602484019290925260448301526064820152608401602060405180830381865afa158015612daf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dd39190613c4a565b9050612e017f0000000000000000000000000000000000000000000000000000000000000000338984612f15565b612e0b818d613d04565b9b50505b8b5151600090612e2190600290613c33565b8b10612e31578c60400151612e8b565b8c51612e8b908a90612e448e6002613d04565b81518110612e5457612e54613ba8565b60200260200101518f602001518e6001612e6e9190613d04565b81518110612e7e57612e7e613ba8565b6020026020010151611c4e565b6040516336cd320560e11b815260048101859052602481018490526001600160a01b03808316604483015291925090881690636d9a640a90606401600060405180830381600087803b158015612ee057600080fd5b505af1158015612ef4573d6000803e3d6000fd5b50505050505050505050505050508080612f0d90613d1c565b91505061296c565b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd000000000000000000000000000000000000000000000000000000001790529151600092839290881691612fa79190613e36565b6000604051808303816000865af19150503d8060008114612fe4576040519150601f19603f3d011682016040523d82523d6000602084013e612fe9565b606091505b50915091508180156130135750805115806130135750808060200190518101906130139190613bfb565b61308a5760405162461bcd60e51b815260206004820152603160248201527f5472616e7366657248656c7065723a3a7472616e7366657246726f6d3a20747260448201527f616e7366657246726f6d206661696c656400000000000000000000000000000060648201526084015b60405180910390fd5b505050505050565b6000805b600185516130a49190613c33565b8110156114af576000808683815181106130c0576130c0613ba8565b6020026020010151878460016130d69190613d04565b815181106130e6576130e6613ba8565b602002602001015191509150600086848151811061310657613106613ba8565b60200260200101519050600061311d848484611c4e565b9050600061312b8585613686565b509050600080826001600160a01b0316876001600160a01b031614613175578c613156896001613d04565b8151811061316657613166613ba8565b6020026020010151600061319c565b60008d6131838a6001613d04565b8151811061319357613193613ba8565b60200260200101515b9150915060008d89815181106131b4576131b4613ba8565b602002602001015190507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316886001600160a01b0316141561323357613204866103e8613c63565b61ffff168661ffff16826132189190613c89565b6132229190613ca8565b61322c908b613d04565b99506133b7565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316876001600160a01b031614156132b257613279866103e8613cca565b61ffff168661ffff168f8b60016132909190613d04565b815181106132a0576132a0613ba8565b60200260200101516132189190613c89565b6000856001600160a01b0316632f72563885876001600160a01b03168c6001600160a01b0316146132e45760006132e6565b845b86896001600160a01b03168e6001600160a01b0316146133065786613309565b60005b6040516001600160e01b031960e087901b1681526004810194909452602484019290925260448301526064820152608401602060405180830381865afa158015613357573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061337b9190613c4a565b90506133a97f0000000000000000000000000000000000000000000000000000000000000000338884612f15565b6133b3818c613d04565b9a50505b50600060028d516133c89190613c33565b89106133d4578a61340a565b61340a878e6133e48c6002613d04565b815181106133f4576133f4613ba8565b60200260200101518e8c6001612e6e9190613d04565b6040516336cd320560e11b815260048101859052602481018490526001600160a01b03808316604483015291925090861690636d9a640a90606401600060405180830381600087803b15801561345f57600080fd5b505af1158015613473573d6000803e3d6000fd5b505050505050505050505050808061348a90613d1c565b915050613096565b604080516000808252602082019092526001600160a01b0384169083906040516134bc9190613e36565b60006040518083038185875af1925050503d80600081146134f9576040519150601f19603f3d011682016040523d82523d6000602084013e6134fe565b606091505b50509050806135755760405162461bcd60e51b815260206004820152603460248201527f5472616e7366657248656c7065723a3a736166655472616e736665724554483a60448201527f20455448207472616e73666572206661696c65640000000000000000000000006064820152608401613081565b505050565b60008361359a576040516342301c2360e01b815260040160405180910390fd5b8215806135a5575081155b156135c35760405163bb55fd2760e01b815260040160405180910390fd5b60006135cf8585613c89565b905060006135dd8685613c33565b90506135e98183613ca8565b6135f4906001613d04565b9695505050505050565b600083613637576040517f098fb56100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b821580613642575081155b156136605760405163bb55fd2760e01b815260040160405180910390fd5b600061366c8386613c89565b9050600061367a8686613d04565b90506135f48183613ca8565b600080826001600160a01b0316846001600160a01b031614156136d5576040517fbd969eb000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b0316148061374657507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b0316145b156137ff577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b0316146137ab577f0000000000000000000000000000000000000000000000000000000000000000846137ce565b7f0000000000000000000000000000000000000000000000000000000000000000835b90925090506001600160a01b0381166137fa5760405163d92e233d60e01b815260040160405180910390fd5b61384e565b826001600160a01b0316846001600160a01b03161061381f578284613822565b83835b90925090506001600160a01b03821661384e5760405163d92e233d60e01b815260040160405180910390fd5b9250929050565b634e487b7160e01b600052600160045260246000fd5b600060c0828403121561186457600080fd5b60006020828403121561388f57600080fd5b813567ffffffffffffffff8111156138a657600080fd5b6138b28482850161386b565b949350505050565b600060e0828403121561186457600080fd5b6000602082840312156138de57600080fd5b813567ffffffffffffffff8111156138f557600080fd5b6138b2848285016138ba565b6020808252825182820181905260009190848201906040850190845b818110156139395783518352928401929184019160010161391d565b50909695505050505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561398457613984613945565b604052919050565b600067ffffffffffffffff8211156139a6576139a6613945565b5060051b60200190565b80356001600160a01b03811681146139c757600080fd5b919050565b803561ffff811681146139c757600080fd5b600082601f8301126139ef57600080fd5b81356020613a046139ff8361398c565b61395b565b82815260059290921b84018101918181019086841115613a2357600080fd5b8286015b84811015613a4557613a38816139cc565b8352918301918301613a27565b509695505050505050565b600080600060608486031215613a6557600080fd5b8335925060208085013567ffffffffffffffff80821115613a8557600080fd5b818701915087601f830112613a9957600080fd5b8135613aa76139ff8261398c565b81815260059190911b8301840190848101908a831115613ac657600080fd5b938501935b82851015613aeb57613adc856139b0565b82529385019390850190613acb565b965050506040870135925080831115613b0357600080fd5b5050613b11868287016139de565b9150509250925092565b600080600060608486031215613b3057600080fd5b613b39846139b0565b9250613b47602085016139b0565b9150613b55604085016139cc565b90509250925092565b6000808335601e19843603018112613b7557600080fd5b83018035915067ffffffffffffffff821115613b9057600080fd5b6020019150600581901b360382131561384e57600080fd5b634e487b7160e01b600052603260045260246000fd5b600060208284031215613bd057600080fd5b613bd9826139b0565b9392505050565b600060208284031215613bf257600080fd5b613bd9826139cc565b600060208284031215613c0d57600080fd5b81518015158114613bd957600080fd5b634e487b7160e01b600052601160045260246000fd5b600082821015613c4557613c45613c1d565b500390565b600060208284031215613c5c57600080fd5b5051919050565b600061ffff808316818516808303821115613c8057613c80613c1d565b01949350505050565b6000816000190483118215151615613ca357613ca3613c1d565b500290565b600082613cc557634e487b7160e01b600052601260045260246000fd5b500490565b600061ffff83811690831681811015613ce557613ce5613c1d565b039392505050565b600081613cfc57613cfc613c1d565b506000190190565b60008219821115613d1757613d17613c1d565b500190565b6000600019821415613d3057613d30613c1d565b5060010190565b80516dffffffffffffffffffffffffffff811681146139c757600080fd5b600080600060608486031215613d6a57600080fd5b613d7384613d37565b9250613d8160208501613d37565b9150604084015163ffffffff81168114613d9a57600080fd5b809150509250925092565b60005b83811015613dc0578181015183820152602001613da8565b838111156124725750506000910152565b7fff0000000000000000000000000000000000000000000000000000000000000081526bffffffffffffffffffffffff198460601b16600182015282601582015260008251613e27816035850160208701613da5565b91909101603501949350505050565b60008251613e48818460208701613da5565b919091019291505056fea2646970667358221220035e8a06ff2fb49525cf9f2c1541d7436c7f4a2a69289412e1072cf4ddea72c364736f6c634300080a00330000000000000000000000008af94528fbe3c4c148523e7aad48bcebcc0a71d70000000000000000000000004f9a0e7fd2bf6067db6994cf12e4495df938e6e900000000000000000000000040df0c3bbaae5ea3a509d8f2aa9e086776c98e6c

Deployed Bytecode

0x6080604052600436106100f75760003560e01c8063a502d3a01161008a578063cd0ba5df11610059578063cd0ba5df14610320578063d2a4949a14610333578063e80d2b3414610353578063ef1c88fb1461037357600080fd5b8063a502d3a01461024c578063ad5c464814610284578063c12a00a8146102b8578063c45a0155146102ec57600080fd5b80635ec70f5d116100c65780635ec70f5d146101c4578063636f5e0e146101e45780636451737d146101f7578063951eb42d1461021757600080fd5b80630438c45e1461013b57806305f9b6271461014e578063164d01be1461018457806359c90959146101a457600080fd5b3661013657336001600160a01b037f0000000000000000000000004f9a0e7fd2bf6067db6994cf12e4495df938e6e9161461013457610134613855565b005b600080fd5b61013461014936600461387d565b610393565b34801561015a57600080fd5b5061016e6101693660046138cc565b6108bc565b60405161017b9190613901565b60405180910390f35b34801561019057600080fd5b5061016e61019f3660046138cc565b610c0f565b3480156101b057600080fd5b5061016e6101bf3660046138cc565b610f9d565b3480156101d057600080fd5b5061016e6101df366004613a50565b61116a565b61016e6101f236600461387d565b6114b8565b34801561020357600080fd5b5061016e610212366004613a50565b61186a565b34801561022357600080fd5b50610237610232366004613b1b565b611b76565b6040805192835260208301919091520161017b565b34801561025857600080fd5b5061026c610267366004613b1b565b611c4e565b6040516001600160a01b03909116815260200161017b565b34801561029057600080fd5b5061026c7f0000000000000000000000004f9a0e7fd2bf6067db6994cf12e4495df938e6e981565b3480156102c457600080fd5b5061026c7f00000000000000000000000040df0c3bbaae5ea3a509d8f2aa9e086776c98e6c81565b3480156102f857600080fd5b5061026c7f0000000000000000000000008af94528fbe3c4c148523e7aad48bcebcc0a71d781565b61016e61032e36600461387d565b611df8565b34801561033f57600080fd5b5061013461034e3660046138cc565b6120e1565b34801561035f57600080fd5b5061016e61036e3660046138cc565b612478565b34801561037f57600080fd5b5061013461038e3660046138cc565b61266b565b8060a00135428110156103b957604051630407b05b60e31b815260040160405180910390fd5b6001600160a01b037f0000000000000000000000004f9a0e7fd2bf6067db6994cf12e4495df938e6e9166103f06040840184613b5e565b600081811061040157610401613ba8565b90506020020160208101906104169190613bbe565b6001600160a01b03161461043d576040516320db826760e01b815260040160405180910390fd5b60003490507f0000000000000000000000004f9a0e7fd2bf6067db6994cf12e4495df938e6e96001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561049d57600080fd5b505af11580156104b1573d6000803e3d6000fd5b50505050507f0000000000000000000000004f9a0e7fd2bf6067db6994cf12e4495df938e6e96001600160a01b031663a9059cbb6105848580604001906104f89190613b5e565b600081811061050957610509613ba8565b905060200201602081019061051e9190613bbe565b61052b6040880188613b5e565b600181811061053c5761053c613ba8565b90506020020160208101906105519190613bbe565b61055e6060890189613b5e565b600081811061056f5761056f613ba8565b90506020020160208101906102679190613be0565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602481018490526044016020604051808303816000875af11580156105d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105f59190613bfb565b61060157610601613855565b60006106106040850185613b5e565b600161061f6040880188613b5e565b61062a929150613c33565b81811061063957610639613ba8565b905060200201602081019061064e9190613bbe565b6001600160a01b03166370a0823161066c60a0870160808801613bbe565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa1580156106b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106d49190613c4a565b9050600060405180606001604052808680604001906106f39190613b5e565b808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152505050908252506020016107376060880188613b5e565b8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050509082525060200161077e60a0880160808901613bbe565b6001600160a01b031690529050602085013561079982612968565b11156107b857604051634b41cb4560e01b815260040160405180910390fd5b8435826107c86040880188613b5e565b60016107d760408b018b613b5e565b6107e2929150613c33565b8181106107f1576107f1613ba8565b90506020020160208101906108069190613bbe565b6001600160a01b03166370a0823161082460a08a0160808b01613bbe565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015610868573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061088c9190613c4a565b6108969190613c33565b10156108b5576040516342301c2360e01b815260040160405180910390fd5b5050505050565b60608160c00135428110156108e457604051630407b05b60e31b815260040160405180910390fd5b60006001600160a01b037f00000000000000000000000040df0c3bbaae5ea3a509d8f2aa9e086776c98e6c1661091d6060860186613b5e565b600081811061092e5761092e613ba8565b90506020020160208101906109439190613bbe565b6001600160a01b03161461095b5783602001356109b9565b6103e861096b6080860186613b5e565b600081811061097c5761097c613ba8565b90506020020160208101906109919190613be0565b61099d906103e8613c63565b6109af9061ffff166020870135613c89565b6109b99190613ca8565b9050610a4384356109cd6060870187613b5e565b80806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250610a0c925050506080880188613b5e565b8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061116a92505050565b92508083600081518110610a5957610a59613ba8565b60200260200101511115610a805760405163e1b0da4f60e01b815260040160405180910390fd5b610b4d610a906060860186613b5e565b6000818110610aa157610aa1613ba8565b9050602002016020810190610ab69190613bbe565b33610b2d610ac76060890189613b5e565b6000818110610ad857610ad8613ba8565b9050602002016020810190610aed9190613bbe565b610afa60608a018a613b5e565b6001818110610b0b57610b0b613ba8565b9050602002016020810190610b209190613bbe565b61055e60808b018b613b5e565b86600081518110610b4057610b40613ba8565b6020026020010151612f15565b6040840135610be984610b636060880188613b5e565b80806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250610ba2925050506080890189613b5e565b80806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250610be49250505060c08a0160a08b01613bbe565b613092565b1115610c0857604051634b41cb4560e01b815260040160405180910390fd5b5050919050565b60608160c0013542811015610c3757604051630407b05b60e31b815260040160405180910390fd5b6001600160a01b037f0000000000000000000000004f9a0e7fd2bf6067db6994cf12e4495df938e6e916610c6e6060850185613b5e565b6001610c7d6060880188613b5e565b610c88929150613c33565b818110610c9757610c97613ba8565b9050602002016020810190610cac9190613bbe565b6001600160a01b031614610cd3576040516320db826760e01b815260040160405180910390fd5b60006001600160a01b037f00000000000000000000000040df0c3bbaae5ea3a509d8f2aa9e086776c98e6c16610d0c6060860186613b5e565b6000818110610d1d57610d1d613ba8565b9050602002016020810190610d329190613bbe565b6001600160a01b031614610d4a578360200135610da8565b6103e8610d5a6080860186613b5e565b6000818110610d6b57610d6b613ba8565b9050602002016020810190610d809190613be0565b610d8c906103e8613c63565b610d9e9061ffff166020870135613c89565b610da89190613ca8565b9050610dbc84356109cd6060870187613b5e565b92508083600081518110610dd257610dd2613ba8565b60200260200101511115610df95760405163e1b0da4f60e01b815260040160405180910390fd5b610e09610a906060860186613b5e565b6040840135610e9784610e1f6060880188613b5e565b80806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250610e5e925050506080890189613b5e565b80806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250309250613092915050565b1115610eb657604051634b41cb4560e01b815260040160405180910390fd5b7f0000000000000000000000004f9a0e7fd2bf6067db6994cf12e4495df938e6e96001600160a01b0316632e1a7d4d8460018651610ef49190613c33565b81518110610f0457610f04613ba8565b60200260200101516040518263ffffffff1660e01b8152600401610f2a91815260200190565b600060405180830381600087803b158015610f4457600080fd5b505af1158015610f58573d6000803e3d6000fd5b50610c089250610f7191505060c0860160a08701613bbe565b8460018651610f809190613c33565b81518110610f9057610f90613ba8565b6020026020010151613492565b60608160c0013542811015610fc557604051630407b05b60e31b815260040160405180910390fd5b60006001600160a01b037f00000000000000000000000040df0c3bbaae5ea3a509d8f2aa9e086776c98e6c16610ffe6060860186613b5e565b600081811061100f5761100f613ba8565b90506020020160208101906110249190613bbe565b6001600160a01b031614611039578335611094565b6103e86110496080860186613b5e565b600081811061105a5761105a613ba8565b905060200201602081019061106f9190613be0565b61107b906103e8613c63565b61108a9061ffff168635613c89565b6110949190613ca8565b905061111d816110a76060870187613b5e565b808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506110e6925050506080880188613b5e565b8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061186a92505050565b9250836020013583600185516111339190613c33565b8151811061114357611143613ba8565b60200260200101511015610a80576040516342301c2360e01b815260040160405180910390fd5b606060028351101561118f576040516320db826760e01b815260040160405180910390fd5b6000835167ffffffffffffffff8111156111ab576111ab613945565b6040519080825280602002602001820160405280156111d4578160200160208202803683370190505b5090508481600186516111e79190613c33565b815181106111f7576111f7613ba8565b6020026020010181815250506000600185516112139190613c33565b90505b80156114af5760008061128b8761122e600186613c33565b8151811061123e5761123e613ba8565b602002602001015188858151811061125857611258613ba8565b60200260200101518860018761126e9190613c33565b8151811061127e5761127e613ba8565b6020026020010151611b76565b90925090506001600160a01b037f00000000000000000000000040df0c3bbaae5ea3a509d8f2aa9e086776c98e6c16876112c6600186613c33565b815181106112d6576112d6613ba8565b60200260200101516001600160a01b0316141561138a576103e8866112fc600186613c33565b8151811061130c5761130c613ba8565b60200260200101516103e86113219190613c63565b61ffff1661134986868151811061133a5761133a613ba8565b6020026020010151858561357a565b6113539190613c89565b61135d9190613ca8565b84611369600186613c33565b8151811061137957611379613ba8565b60200260200101818152505061149a565b7f00000000000000000000000040df0c3bbaae5ea3a509d8f2aa9e086776c98e6c6001600160a01b03168784815181106113c6576113c6613ba8565b60200260200101516001600160a01b0316141561144d5761135d866113ec600186613c33565b815181106113fc576113fc613ba8565b60200260200101516103e86114119190613cca565b61ffff1685858151811061142757611427613ba8565b60200260200101516103e861143c9190613c89565b6114469190613ca8565b838361357a565b61147184848151811061146257611462613ba8565b6020026020010151838361357a565b8461147d600186613c33565b8151811061148d5761148d613ba8565b6020026020010181815250505b505080806114a790613ced565b915050611216565b50949350505050565b60608160a00135428110156114e057604051630407b05b60e31b815260040160405180910390fd5b6001600160a01b037f0000000000000000000000004f9a0e7fd2bf6067db6994cf12e4495df938e6e9166115176040850185613b5e565b600081811061152857611528613ba8565b905060200201602081019061153d9190613bbe565b6001600160a01b031614611564576040516320db826760e01b815260040160405180910390fd5b6115b583356115766040860186613b5e565b80806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250610a0c925050506060870187613b5e565b915034826000815181106115cb576115cb613ba8565b602002602001015111156115f25760405163e1b0da4f60e01b815260040160405180910390fd5b7f0000000000000000000000004f9a0e7fd2bf6067db6994cf12e4495df938e6e96001600160a01b031663d0e30db08360008151811061163457611634613ba8565b60200260200101516040518263ffffffff1660e01b81526004016000604051808303818588803b15801561166757600080fd5b505af115801561167b573d6000803e3d6000fd5b50505050507f0000000000000000000000004f9a0e7fd2bf6067db6994cf12e4495df938e6e96001600160a01b031663a9059cbb6116c28580604001906104f89190613b5e565b846000815181106116d5576116d5613ba8565b60200260200101516040518363ffffffff1660e01b815260040161170e9291906001600160a01b03929092168252602082015260400190565b6020604051808303816000875af115801561172d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117519190613bfb565b61175d5761175d613855565b60208301356117f4836117736040870187613b5e565b808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506117b2925050506060880188613b5e565b80806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250610be49250505060a0890160808a01613bbe565b111561181357604051634b41cb4560e01b815260040160405180910390fd5b8160008151811061182657611826613ba8565b602002602001015134111561186457611864338360008151811061184c5761184c613ba8565b60200260200101513461185f9190613c33565b613492565b50919050565b606060028351101561188f576040516320db826760e01b815260040160405180910390fd5b6000835167ffffffffffffffff8111156118ab576118ab613945565b6040519080825280602002602001820160405280156118d4578160200160208202803683370190505b50905084816000815181106118eb576118eb613ba8565b60200260200101818152505060005b600185516119089190613c33565b8110156114af5760008061196787848151811061192757611927613ba8565b60200260200101518885600161193d9190613d04565b8151811061194d5761194d613ba8565b602002602001015188868151811061127e5761127e613ba8565b915091507f00000000000000000000000040df0c3bbaae5ea3a509d8f2aa9e086776c98e6c6001600160a01b03168784815181106119a7576119a7613ba8565b60200260200101516001600160a01b03161415611a5157611a248684815181106119d3576119d3613ba8565b60200260200101516103e86119e89190613c63565b61ffff168585815181106119fe576119fe613ba8565b60200260200101516103e8611a139190613c89565b611a1d9190613ca8565b83836135fe565b84611a30856001613d04565b81518110611a4057611a40613ba8565b602002602001018181525050611b61565b6001600160a01b037f00000000000000000000000040df0c3bbaae5ea3a509d8f2aa9e086776c98e6c1687611a87856001613d04565b81518110611a9757611a97613ba8565b60200260200101516001600160a01b03161415611b14576103e8868481518110611ac357611ac3613ba8565b60200260200101516103e8611ad89190613cca565b61ffff16611b00868681518110611af157611af1613ba8565b602002602001015185856135fe565b611b0a9190613c89565b611a249190613ca8565b611b38848481518110611b2957611b29613ba8565b602002602001015183836135fe565b84611b44856001613d04565b81518110611b5457611b54613ba8565b6020026020010181815250505b50508080611b6e90613d1c565b9150506118fa565b6000806000611b858686613686565b509050600080611b96888888611c4e565b6001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa158015611bd3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bf79190613d55565b506dffffffffffffffffffffffffffff1691506dffffffffffffffffffffffffffff169150826001600160a01b0316886001600160a01b031614611c3c578082611c3f565b81815b90999098509650505050505050565b6000806000611c5d8686613686565b6040516bffffffffffffffffffffffff19606084811b8216602084015283811b821660348401527fffff00000000000000000000000000000000000000000000000000000000000060f08a901b1660488401527f00000000000000000000000040df0c3bbaae5ea3a509d8f2aa9e086776c98e6c901b16604a82015291935091507f0000000000000000000000008af94528fbe3c4c148523e7aad48bcebcc0a71d790605e01604051602081830303815290604052805190602001207f00000000000000000000000040df0c3bbaae5ea3a509d8f2aa9e086776c98e6c6001600160a01b0316846001600160a01b031614611d8d576040518060400160405280602081526020017f3b29ecd4cb06592a81cac4799fb24ef6a176fe95ecb50f304972882b150f3f3a815250611dc4565b6040518060400160405280602081526020017f99c189a5ef3d337612cf0ce2bd055546e23b91fea9e9e54201b23f14d763f3338152505b604051602001611dd693929190613dd1565b60408051601f1981840301815291905280516020909101209695505050505050565b60608160a0013542811015611e2057604051630407b05b60e31b815260040160405180910390fd5b6001600160a01b037f0000000000000000000000004f9a0e7fd2bf6067db6994cf12e4495df938e6e916611e576040850185613b5e565b6000818110611e6857611e68613ba8565b9050602002016020810190611e7d9190613bbe565b6001600160a01b031614611ea4576040516320db826760e01b815260040160405180910390fd5b611ef434611eb56040860186613b5e565b808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506110e6925050506060870187613b5e565b915082600001358260018451611f0a9190613c33565b81518110611f1a57611f1a613ba8565b60200260200101511015611f41576040516342301c2360e01b815260040160405180910390fd5b7f0000000000000000000000004f9a0e7fd2bf6067db6994cf12e4495df938e6e96001600160a01b031663d0e30db083600081518110611f8357611f83613ba8565b60200260200101516040518263ffffffff1660e01b81526004016000604051808303818588803b158015611fb657600080fd5b505af1158015611fca573d6000803e3d6000fd5b50505050507f0000000000000000000000004f9a0e7fd2bf6067db6994cf12e4495df938e6e96001600160a01b031663a9059cbb6120118580604001906104f89190613b5e565b8460008151811061202457612024613ba8565b60200260200101516040518363ffffffff1660e01b815260040161205d9291906001600160a01b03929092168252602082015260400190565b6020604051808303816000875af115801561207c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120a09190613bfb565b6120ac576120ac613855565b60208301356120c2836117736040870187613b5e565b111561186457604051634b41cb4560e01b815260040160405180910390fd5b8060c001354281101561210757604051630407b05b60e31b815260040160405180910390fd5b6121bb6121176060840184613b5e565b600081811061212857612128613ba8565b905060200201602081019061213d9190613bbe565b336121b461214e6060870187613b5e565b600081811061215f5761215f613ba8565b90506020020160208101906121749190613bbe565b6121816060880188613b5e565b600181811061219257612192613ba8565b90506020020160208101906121a79190613bbe565b61055e6080890189613b5e565b8535612f15565b60006121ca6060840184613b5e565b60016121d96060870187613b5e565b6121e4929150613c33565b8181106121f3576121f3613ba8565b90506020020160208101906122089190613bbe565b6001600160a01b03166370a0823161222660c0860160a08701613bbe565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa15801561226a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061228e9190613c4a565b9050600060405180606001604052808580606001906122ad9190613b5e565b808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152505050908252506020016122f16080870187613b5e565b8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050509082525060200161233860c0870160a08801613bbe565b6001600160a01b031690529050604084013561235382612968565b111561237257604051634b41cb4560e01b815260040160405180910390fd5b6020840135826123856060870187613b5e565b600161239460608a018a613b5e565b61239f929150613c33565b8181106123ae576123ae613ba8565b90506020020160208101906123c39190613bbe565b6001600160a01b03166370a082316123e160c0890160a08a01613bbe565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015612425573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124499190613c4a565b6124539190613c33565b1015612472576040516342301c2360e01b815260040160405180910390fd5b50505050565b60608160c00135428110156124a057604051630407b05b60e31b815260040160405180910390fd5b60006001600160a01b037f00000000000000000000000040df0c3bbaae5ea3a509d8f2aa9e086776c98e6c166124d96060860186613b5e565b60008181106124ea576124ea613ba8565b90506020020160208101906124ff9190613bbe565b6001600160a01b03161461251457833561256f565b6103e86125246080860186613b5e565b600081811061253557612535613ba8565b905060200201602081019061254a9190613be0565b612556906103e8613c63565b6125659061ffff168635613c89565b61256f9190613ca8565b90506001600160a01b037f0000000000000000000000004f9a0e7fd2bf6067db6994cf12e4495df938e6e9166125a86060860186613b5e565b60016125b76060890189613b5e565b6125c2929150613c33565b8181106125d1576125d1613ba8565b90506020020160208101906125e69190613bbe565b6001600160a01b03161461260d576040516320db826760e01b815260040160405180910390fd5b61261e816110a76060870187613b5e565b9250836020013583600185516126349190613c33565b8151811061264457612644613ba8565b60200260200101511015610df9576040516342301c2360e01b815260040160405180910390fd5b8060c001354281101561269157604051630407b05b60e31b815260040160405180910390fd5b6001600160a01b037f0000000000000000000000004f9a0e7fd2bf6067db6994cf12e4495df938e6e9166126c86060840184613b5e565b60016126d76060870187613b5e565b6126e2929150613c33565b8181106126f1576126f1613ba8565b90506020020160208101906127069190613bbe565b6001600160a01b03161461272d576040516320db826760e01b815260040160405180910390fd5b61273d6121176060840184613b5e565b6000604051806060016040528084806060019061275a9190613b5e565b8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050509082525060200161279e6080860186613b5e565b8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050509082525030602090910152905060408301356127e982612968565b111561280857604051634b41cb4560e01b815260040160405180910390fd5b6040516370a0823160e01b81523060048201526000907f0000000000000000000000004f9a0e7fd2bf6067db6994cf12e4495df938e6e96001600160a01b0316906370a0823190602401602060405180830381865afa15801561286f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128939190613c4a565b905083602001358110156128ba576040516342301c2360e01b815260040160405180910390fd5b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290527f0000000000000000000000004f9a0e7fd2bf6067db6994cf12e4495df938e6e96001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561293557600080fd5b505af1158015612949573d6000803e3d6000fd5b50612472925061296291505060c0860160a08701613bbe565b82613492565b6000805b82515161297b90600190613c33565b811015611864576000808460000151838151811061299b5761299b613ba8565b602002602001015185600001518460016129b59190613d04565b815181106129c5576129c5613ba8565b6020026020010151915091506000856020015184815181106129e9576129e9613ba8565b602002602001015190506000612a00848484611c4e565b90506000612a0e8585613686565b509050600080600080856001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa158015612a55573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a799190613d55565b506dffffffffffffffffffffffffffff1691506dffffffffffffffffffffffffffff169150600080866001600160a01b03168b6001600160a01b031614612ac1578284612ac4565b83835b6040516370a0823160e01b81526001600160a01b038b8116600483015292945090925083918d16906370a0823190602401602060405180830381865afa158015612b12573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b369190613c4a565b612b409190613c33565b95507f00000000000000000000000040df0c3bbaae5ea3a509d8f2aa9e086776c98e6c6001600160a01b03168b6001600160a01b03161415612ba257612b9b612b8b8a6103e8613c63565b61ffff16611a13886103e8613c89565b9450612c1a565b7f00000000000000000000000040df0c3bbaae5ea3a509d8f2aa9e086776c98e6c6001600160a01b03168a6001600160a01b03161415612c0c576103e8612be98a82613cca565b61ffff16612bf88885856135fe565b612c029190613c89565b612b9b9190613ca8565b612c178683836135fe565b94505b50505050600080846001600160a01b0316896001600160a01b031614612c4257826000612c46565b6000835b915091507f00000000000000000000000040df0c3bbaae5ea3a509d8f2aa9e086776c98e6c6001600160a01b0316896001600160a01b03161415612cbf57612c90876103e8613c63565b61ffff168761ffff1685612ca49190613c89565b612cae9190613ca8565b612cb8908c613d04565b9a50612e0f565b7f00000000000000000000000040df0c3bbaae5ea3a509d8f2aa9e086776c98e6c6001600160a01b0316886001600160a01b03161415612d0a576103e8612ca461ffff891686613c89565b6000866001600160a01b0316632f72563884886001600160a01b03168d6001600160a01b031614612d3c576000612d3e565b875b858a6001600160a01b03168f6001600160a01b031614612d5e5789612d61565b60005b6040516001600160e01b031960e087901b1681526004810194909452602484019290925260448301526064820152608401602060405180830381865afa158015612daf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dd39190613c4a565b9050612e017f00000000000000000000000040df0c3bbaae5ea3a509d8f2aa9e086776c98e6c338984612f15565b612e0b818d613d04565b9b50505b8b5151600090612e2190600290613c33565b8b10612e31578c60400151612e8b565b8c51612e8b908a90612e448e6002613d04565b81518110612e5457612e54613ba8565b60200260200101518f602001518e6001612e6e9190613d04565b81518110612e7e57612e7e613ba8565b6020026020010151611c4e565b6040516336cd320560e11b815260048101859052602481018490526001600160a01b03808316604483015291925090881690636d9a640a90606401600060405180830381600087803b158015612ee057600080fd5b505af1158015612ef4573d6000803e3d6000fd5b50505050505050505050505050508080612f0d90613d1c565b91505061296c565b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd000000000000000000000000000000000000000000000000000000001790529151600092839290881691612fa79190613e36565b6000604051808303816000865af19150503d8060008114612fe4576040519150601f19603f3d011682016040523d82523d6000602084013e612fe9565b606091505b50915091508180156130135750805115806130135750808060200190518101906130139190613bfb565b61308a5760405162461bcd60e51b815260206004820152603160248201527f5472616e7366657248656c7065723a3a7472616e7366657246726f6d3a20747260448201527f616e7366657246726f6d206661696c656400000000000000000000000000000060648201526084015b60405180910390fd5b505050505050565b6000805b600185516130a49190613c33565b8110156114af576000808683815181106130c0576130c0613ba8565b6020026020010151878460016130d69190613d04565b815181106130e6576130e6613ba8565b602002602001015191509150600086848151811061310657613106613ba8565b60200260200101519050600061311d848484611c4e565b9050600061312b8585613686565b509050600080826001600160a01b0316876001600160a01b031614613175578c613156896001613d04565b8151811061316657613166613ba8565b6020026020010151600061319c565b60008d6131838a6001613d04565b8151811061319357613193613ba8565b60200260200101515b9150915060008d89815181106131b4576131b4613ba8565b602002602001015190507f00000000000000000000000040df0c3bbaae5ea3a509d8f2aa9e086776c98e6c6001600160a01b0316886001600160a01b0316141561323357613204866103e8613c63565b61ffff168661ffff16826132189190613c89565b6132229190613ca8565b61322c908b613d04565b99506133b7565b7f00000000000000000000000040df0c3bbaae5ea3a509d8f2aa9e086776c98e6c6001600160a01b0316876001600160a01b031614156132b257613279866103e8613cca565b61ffff168661ffff168f8b60016132909190613d04565b815181106132a0576132a0613ba8565b60200260200101516132189190613c89565b6000856001600160a01b0316632f72563885876001600160a01b03168c6001600160a01b0316146132e45760006132e6565b845b86896001600160a01b03168e6001600160a01b0316146133065786613309565b60005b6040516001600160e01b031960e087901b1681526004810194909452602484019290925260448301526064820152608401602060405180830381865afa158015613357573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061337b9190613c4a565b90506133a97f00000000000000000000000040df0c3bbaae5ea3a509d8f2aa9e086776c98e6c338884612f15565b6133b3818c613d04565b9a50505b50600060028d516133c89190613c33565b89106133d4578a61340a565b61340a878e6133e48c6002613d04565b815181106133f4576133f4613ba8565b60200260200101518e8c6001612e6e9190613d04565b6040516336cd320560e11b815260048101859052602481018490526001600160a01b03808316604483015291925090861690636d9a640a90606401600060405180830381600087803b15801561345f57600080fd5b505af1158015613473573d6000803e3d6000fd5b505050505050505050505050808061348a90613d1c565b915050613096565b604080516000808252602082019092526001600160a01b0384169083906040516134bc9190613e36565b60006040518083038185875af1925050503d80600081146134f9576040519150601f19603f3d011682016040523d82523d6000602084013e6134fe565b606091505b50509050806135755760405162461bcd60e51b815260206004820152603460248201527f5472616e7366657248656c7065723a3a736166655472616e736665724554483a60448201527f20455448207472616e73666572206661696c65640000000000000000000000006064820152608401613081565b505050565b60008361359a576040516342301c2360e01b815260040160405180910390fd5b8215806135a5575081155b156135c35760405163bb55fd2760e01b815260040160405180910390fd5b60006135cf8585613c89565b905060006135dd8685613c33565b90506135e98183613ca8565b6135f4906001613d04565b9695505050505050565b600083613637576040517f098fb56100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b821580613642575081155b156136605760405163bb55fd2760e01b815260040160405180910390fd5b600061366c8386613c89565b9050600061367a8686613d04565b90506135f48183613ca8565b600080826001600160a01b0316846001600160a01b031614156136d5576040517fbd969eb000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f00000000000000000000000040df0c3bbaae5ea3a509d8f2aa9e086776c98e6c6001600160a01b0316846001600160a01b0316148061374657507f00000000000000000000000040df0c3bbaae5ea3a509d8f2aa9e086776c98e6c6001600160a01b0316836001600160a01b0316145b156137ff577f00000000000000000000000040df0c3bbaae5ea3a509d8f2aa9e086776c98e6c6001600160a01b0316846001600160a01b0316146137ab577f00000000000000000000000040df0c3bbaae5ea3a509d8f2aa9e086776c98e6c846137ce565b7f00000000000000000000000040df0c3bbaae5ea3a509d8f2aa9e086776c98e6c835b90925090506001600160a01b0381166137fa5760405163d92e233d60e01b815260040160405180910390fd5b61384e565b826001600160a01b0316846001600160a01b03161061381f578284613822565b83835b90925090506001600160a01b03821661384e5760405163d92e233d60e01b815260040160405180910390fd5b9250929050565b634e487b7160e01b600052600160045260246000fd5b600060c0828403121561186457600080fd5b60006020828403121561388f57600080fd5b813567ffffffffffffffff8111156138a657600080fd5b6138b28482850161386b565b949350505050565b600060e0828403121561186457600080fd5b6000602082840312156138de57600080fd5b813567ffffffffffffffff8111156138f557600080fd5b6138b2848285016138ba565b6020808252825182820181905260009190848201906040850190845b818110156139395783518352928401929184019160010161391d565b50909695505050505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561398457613984613945565b604052919050565b600067ffffffffffffffff8211156139a6576139a6613945565b5060051b60200190565b80356001600160a01b03811681146139c757600080fd5b919050565b803561ffff811681146139c757600080fd5b600082601f8301126139ef57600080fd5b81356020613a046139ff8361398c565b61395b565b82815260059290921b84018101918181019086841115613a2357600080fd5b8286015b84811015613a4557613a38816139cc565b8352918301918301613a27565b509695505050505050565b600080600060608486031215613a6557600080fd5b8335925060208085013567ffffffffffffffff80821115613a8557600080fd5b818701915087601f830112613a9957600080fd5b8135613aa76139ff8261398c565b81815260059190911b8301840190848101908a831115613ac657600080fd5b938501935b82851015613aeb57613adc856139b0565b82529385019390850190613acb565b965050506040870135925080831115613b0357600080fd5b5050613b11868287016139de565b9150509250925092565b600080600060608486031215613b3057600080fd5b613b39846139b0565b9250613b47602085016139b0565b9150613b55604085016139cc565b90509250925092565b6000808335601e19843603018112613b7557600080fd5b83018035915067ffffffffffffffff821115613b9057600080fd5b6020019150600581901b360382131561384e57600080fd5b634e487b7160e01b600052603260045260246000fd5b600060208284031215613bd057600080fd5b613bd9826139b0565b9392505050565b600060208284031215613bf257600080fd5b613bd9826139cc565b600060208284031215613c0d57600080fd5b81518015158114613bd957600080fd5b634e487b7160e01b600052601160045260246000fd5b600082821015613c4557613c45613c1d565b500390565b600060208284031215613c5c57600080fd5b5051919050565b600061ffff808316818516808303821115613c8057613c80613c1d565b01949350505050565b6000816000190483118215151615613ca357613ca3613c1d565b500290565b600082613cc557634e487b7160e01b600052601260045260246000fd5b500490565b600061ffff83811690831681811015613ce557613ce5613c1d565b039392505050565b600081613cfc57613cfc613c1d565b506000190190565b60008219821115613d1757613d17613c1d565b500190565b6000600019821415613d3057613d30613c1d565b5060010190565b80516dffffffffffffffffffffffffffff811681146139c757600080fd5b600080600060608486031215613d6a57600080fd5b613d7384613d37565b9250613d8160208501613d37565b9150604084015163ffffffff81168114613d9a57600080fd5b809150509250925092565b60005b83811015613dc0578181015183820152602001613da8565b838111156124725750506000910152565b7fff0000000000000000000000000000000000000000000000000000000000000081526bffffffffffffffffffffffff198460601b16600182015282601582015260008251613e27816035850160208701613da5565b91909101603501949350505050565b60008251613e48818460208701613da5565b919091019291505056fea2646970667358221220035e8a06ff2fb49525cf9f2c1541d7436c7f4a2a69289412e1072cf4ddea72c364736f6c634300080a0033

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

0000000000000000000000008af94528fbe3c4c148523e7aad48bcebcc0a71d70000000000000000000000004f9a0e7fd2bf6067db6994cf12e4495df938e6e900000000000000000000000040df0c3bbaae5ea3a509d8f2aa9e086776c98e6c

-----Decoded View---------------
Arg [0] : _factory (address): 0x8aF94528FBE3c4C148523E7aAD48BcEbcC0A71d7
Arg [1] : _WETH (address): 0x4F9A0e7FD2Bf6067db6994CF12E4495Df938E6e9
Arg [2] : _antfarmToken (address): 0x40DF0C3BBAAE5Ea3A509d8F2aa9E086776C98E6c

-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 0000000000000000000000008af94528fbe3c4c148523e7aad48bcebcc0a71d7
Arg [1] : 0000000000000000000000004f9a0e7fd2bf6067db6994cf12e4495df938e6e9
Arg [2] : 00000000000000000000000040df0c3bbaae5ea3a509d8f2aa9e086776c98e6c


Block Transaction Gas Used Reward
view all blocks sequenced

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
[ Download: CSV Export  ]
[ 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.