ETH Price: $3,916.32 (-0.03%)

Contract

0x8aF94528FBE3c4C148523E7aAD48BcEbcC0A71d7

Overview

ETH Balance

0 ETH

ETH Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

Please try again later

Latest 25 internal transactions (View All)

Parent Transaction Hash Block From To
169756982024-10-21 2:12:3354 days ago1729476753
0x8aF94528...bcC0A71d7
 Contract Creation0 ETH
125853192024-05-18 8:22:54209 days ago1716020574
0x8aF94528...bcC0A71d7
 Contract Creation0 ETH
125126442024-05-15 19:30:27212 days ago1715801427
0x8aF94528...bcC0A71d7
 Contract Creation0 ETH
63136202023-10-16 9:39:23424 days ago1697449163
0x8aF94528...bcC0A71d7
 Contract Creation0 ETH
61660822023-10-11 8:46:38429 days ago1697013998
0x8aF94528...bcC0A71d7
 Contract Creation0 ETH
59449722023-10-03 11:32:37437 days ago1696332757
0x8aF94528...bcC0A71d7
 Contract Creation0 ETH
56180222023-09-21 22:42:21449 days ago1695336141
0x8aF94528...bcC0A71d7
 Contract Creation0 ETH
19189982023-07-02 17:48:17530 days ago1688320097
0x8aF94528...bcC0A71d7
 Contract Creation0 ETH
16415562023-06-27 9:06:04535 days ago1687856764
0x8aF94528...bcC0A71d7
 Contract Creation0 ETH
14937712023-06-24 13:26:04538 days ago1687613164
0x8aF94528...bcC0A71d7
 Contract Creation0 ETH
13658012023-06-21 14:22:25541 days ago1687357345
0x8aF94528...bcC0A71d7
 Contract Creation0 ETH
10627152023-06-16 6:08:15546 days ago1686895695
0x8aF94528...bcC0A71d7
 Contract Creation0 ETH
8799032023-06-12 20:51:39550 days ago1686603099
0x8aF94528...bcC0A71d7
 Contract Creation0 ETH
8770352023-06-12 19:37:47550 days ago1686598667
0x8aF94528...bcC0A71d7
 Contract Creation0 ETH
7547622023-06-08 23:04:44554 days ago1686265484
0x8aF94528...bcC0A71d7
 Contract Creation0 ETH
4911082023-05-28 11:47:19565 days ago1685274439
0x8aF94528...bcC0A71d7
 Contract Creation0 ETH
4336482023-05-26 10:41:54567 days ago1685097714
0x8aF94528...bcC0A71d7
 Contract Creation0 ETH
4287722023-05-26 6:54:46567 days ago1685084086
0x8aF94528...bcC0A71d7
 Contract Creation0 ETH
3886162023-05-24 13:14:33569 days ago1684934073
0x8aF94528...bcC0A71d7
 Contract Creation0 ETH
3358842023-05-21 11:36:50572 days ago1684669010
0x8aF94528...bcC0A71d7
 Contract Creation0 ETH
2702062023-05-16 20:36:28577 days ago1684269388
0x8aF94528...bcC0A71d7
 Contract Creation0 ETH
2701792023-05-16 20:36:28577 days ago1684269388
0x8aF94528...bcC0A71d7
 Contract Creation0 ETH
2438912023-05-14 18:44:58579 days ago1684089898
0x8aF94528...bcC0A71d7
 Contract Creation0 ETH
2434332023-05-14 18:09:54579 days ago1684087794
0x8aF94528...bcC0A71d7
 Contract Creation0 ETH
2402162023-05-14 12:47:00579 days ago1684068420
0x8aF94528...bcC0A71d7
 Contract Creation0 ETH
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
AntfarmFactory

Compiler Version
v0.8.10+commit.fc410830

Optimization Enabled:
Yes with 1000 runs

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

import "./AntfarmPair.sol";
import "./AntfarmAtfPair.sol";
import "../utils/AntfarmFactoryErrors.sol";

/// @title Antfarm Factory
/// @notice The Factory is used to create new Pair contracts for each unique ERC20 token pair
contract AntfarmFactory is IAntfarmFactory {
    uint16[8] public possibleFees = [10, 50, 100, 150, 250, 500, 750, 1000];
    address[] public allPairs;
    address public antfarmToken;

    mapping(address => mapping(address => mapping(uint16 => address)))
        public getPair;

    mapping(address => mapping(address => uint16[8])) public feesForPair;

    constructor(address _antfarmToken) {
        require(_antfarmToken != address(0), "NULL_ATF_ADDRESS");
        antfarmToken = _antfarmToken;
    }

    /// @notice Get list of fees for existing Antfarm Pair of a specific pair
    /// @param _token0 token0 from the pair
    /// @param _token1 token1 from the pair
    /// @return uint16 Fixed fees array
    function getFeesForPair(address _token0, address _token1)
        external
        view
        override
        returns (uint16[8] memory)
    {
        return feesForPair[_token0][_token1];
    }

    /// @notice Get total number of Antfarm Pairs
    /// @return uint Number of created pairs
    function allPairsLength() public view returns (uint256) {
        return allPairs.length;
    }

    /// @notice Get Antfarm Pairs addresses
    /// @param startIndex Index of the first pair to query
    /// @param numOfPairs Number of pairs to be queried
    /// @return pairs Addresses of created pairs
    /// @return newIndex New index for chained calls
    function getPairs(uint256 startIndex, uint256 numOfPairs)
        external
        view
        returns (address[] memory pairs, uint256 newIndex)
    {
        if (numOfPairs > allPairsLength() - startIndex) {
            numOfPairs = allPairsLength() - startIndex;
        }

        pairs = new address[](numOfPairs);
        for (uint256 i; i < numOfPairs; ++i) {
            pairs[i] = allPairs[startIndex + i];
        }

        newIndex = startIndex + numOfPairs;
    }

    /// @notice Get all possible fees
    /// @return uint16[8] List of possible fees
    function getPossibleFees() external view returns (uint16[8] memory) {
        return possibleFees;
    }

    /// @notice Create new Antfarm Pair
    /// @param tokenA token0 to be used for the new Antfarm Pair
    /// @param tokenB token1 to be used for the new Antfarm Pair
    /// @param fee Fee to be used in the new Antfarm Pair
    /// @return address The address of the deployed Antfarm Pair
    function createPair(
        address tokenA,
        address tokenB,
        uint16 fee
    ) external returns (address) {
        uint16 feeIndex = validateFee(fee);
        if (tokenA == tokenB) revert IdenticalAddresses();
        address token0;
        address token1;
        if (tokenA == antfarmToken || tokenB == antfarmToken) {
            (token0, token1) = tokenA == antfarmToken
                ? (antfarmToken, tokenB)
                : (antfarmToken, tokenA);
            if (token1 == address(0)) revert ZeroAddress(); // antfarmToken can't be 0 but other could
            if (fee == 1000) revert ForbiddenFee();
        } else {
            (token0, token1) = tokenA < tokenB
                ? (tokenA, tokenB)
                : (tokenB, tokenA);
            if (token0 == address(0)) revert ZeroAddress();
        }
        if (getPair[token0][token1][fee] != address(0)) revert PairExists();

        address pair;
        bytes memory bytecode = token0 == antfarmToken
            ? type(AntfarmAtfPair).creationCode
            : type(AntfarmPair).creationCode;
        bytes32 salt = keccak256(
            abi.encodePacked(token0, token1, fee, antfarmToken)
        );
        assembly {
            pair := create2(0, add(bytecode, 32), mload(bytecode), salt)
        }
        getPair[token0][token1][fee] = pair;
        getPair[token1][token0][fee] = pair;
        writeFee(token0, token1, feeIndex);
        allPairs.push(pair);

        token0 == antfarmToken
            ? IAntfarmAtfPair(pair).initialize(token0, token1, fee)
            : IAntfarmPair(pair).initialize(token0, token1, fee, antfarmToken);
        emit PairCreated(token0, token1, pair, fee, allPairs.length);
        return pair;
    }

    // updates the fee array for a pair with the fee amount in its index
    function writeFee(
        address token0,
        address token1,
        uint16 index
    ) internal {
        uint16[8] memory fees = feesForPair[token0][token1];
        fees[index] = possibleFees[index];
        feesForPair[token0][token1] = fees;
        feesForPair[token1][token0] = fees;
    }

    // check the fee provided is one of the available ones
    function validateFee(uint16 fee) internal view returns (uint16) {
        for (uint16 i; i < 8; ++i) {
            if (fee == possibleFees[i]) {
                return i;
            }
        }
        revert IncorrectFee();
    }
}

File 2 of 25 : ReentrancyGuard.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Gas optimized reentrancy protection for smart contracts.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/utils/ReentrancyGuard.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/security/ReentrancyGuard.sol)
abstract contract ReentrancyGuard {
    uint256 private locked = 1;

    modifier nonReentrant() virtual {
        require(locked == 1, "REENTRANCY");

        locked = 2;

        _;

        locked = 1;
    }
}

File 3 of 25 : AntfarmAtfPair.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.10;

import "../interfaces/IERC20.sol";
import "../interfaces/IAntfarmFactory.sol";
import "../interfaces/IAntfarmAtfPair.sol";
import "../interfaces/IAntfarmOracle.sol";
import "../libraries/math.sol";
import "../libraries/UQ112x112.sol";
import "../libraries/TransferHelper.sol";
import "../utils/AntfarmPairErrors.sol";
import "@rari-capital/solmate/src/utils/ReentrancyGuard.sol";

/// @title Core contract for Antfarm Pairs with ATF token
/// @notice Low-level contract to mint/burn/swap and claim
contract AntfarmAtfPair is IAntfarmAtfPair, ReentrancyGuard, Math {
    using UQ112x112 for uint224;

    /// @inheritdoc IAntfarmPairState
    address public immutable factory;

    /// @inheritdoc IAntfarmPairState
    address public token0;

    /// @inheritdoc IAntfarmPairState
    address public token1;

    /// @inheritdoc IAntfarmPairState
    uint16 public fee;

    /// @inheritdoc IAntfarmPairState
    uint256 public totalSupply;

    /// @inheritdoc IAntfarmAtfPair
    uint256 public price1CumulativeLast;

    /// @inheritdoc IAntfarmPairState
    uint256 public antfarmTokenReserve;

    /// @inheritdoc IAntfarmAtfPair
    address public antfarmOracle;

    uint112 private reserve0;
    uint112 private reserve1;
    uint32 private blockTimestampLast;

    // DIVIDEND VARIABLES
    uint256 private totalDividendPoints;
    uint256 private constant POINT_MULTIPLIER = 1 ether;

    uint256 private constant MINIMUM_LIQUIDITY = 1000;

    struct Position {
        uint128 lp;
        uint256 dividend;
        uint256 lastDividendPoints;
    }

    mapping(address => mapping(uint256 => Position)) public positions;

    modifier updateDividend(address operator, uint256 positionId) {
        if (positions[operator][positionId].lp > 0) {
            uint256 owing = newDividends(
                operator,
                positionId,
                totalDividendPoints
            );
            if (owing > 0) {
                positions[operator][positionId].dividend += owing;
                positions[operator][positionId]
                    .lastDividendPoints = totalDividendPoints;
            }
        } else {
            positions[operator][positionId]
                .lastDividendPoints = totalDividendPoints;
        }
        _;
    }

    constructor() {
        factory = msg.sender;
    }

    function initialize(
        address _token0,
        address _token1,
        uint16 _fee
    ) external {
        if (msg.sender != factory) revert SenderNotFactory();
        token0 = _token0;
        token1 = _token1;
        fee = _fee;
    }

    /// @inheritdoc IAntfarmPairActions
    function mint(address to, uint256 positionId)
        external
        override
        nonReentrant
        updateDividend(to, positionId)
        returns (uint256)
    {
        (uint112 _reserve0, uint112 _reserve1, ) = getReserves();
        uint256 balance0 = IERC20(token0).balanceOf(address(this)) -
            antfarmTokenReserve;
        uint256 balance1 = IERC20(token1).balanceOf(address(this));
        uint256 amount0 = balance0 - _reserve0;
        uint256 amount1 = balance1 - _reserve1;

        uint256 liquidity;

        uint256 _totalSupply = totalSupply;
        if (_totalSupply == 0) {
            liquidity = Math.sqrt(amount0 * amount1) - MINIMUM_LIQUIDITY;
            totalSupply = MINIMUM_LIQUIDITY;
        } else {
            liquidity = Math.min(
                (amount0 * totalSupply) / _reserve0,
                (amount1 * totalSupply) / _reserve1
            );
        }
        if (liquidity == 0) revert InsufficientLiquidityMinted();
        positions[to][positionId].lp += uint128(liquidity);
        totalSupply = totalSupply + liquidity;

        _update(balance0, balance1, _reserve0, _reserve1);
        if (_totalSupply == 0) {
            if (fee == 10) {
                setOracleInstance();
            }
        }
        emit Mint(to, amount0, amount1);
        return liquidity;
    }

    /// @inheritdoc IAntfarmPairActions
    function burn(
        address to,
        uint256 positionId,
        uint256 liquidity
    )
        external
        override
        nonReentrant
        updateDividend(msg.sender, positionId)
        returns (uint256, uint256)
    {
        (uint112 _reserve0, uint112 _reserve1, ) = getReserves(); // gas savings

        uint256 balance0 = IERC20(token0).balanceOf(address(this)) -
            antfarmTokenReserve;
        uint256 balance1 = IERC20(token1).balanceOf(address(this));

        if (positions[msg.sender][positionId].lp < liquidity) {
            revert InsufficientLiquidity();
        }

        positions[msg.sender][positionId].lp -= uint128(liquidity);

        if (liquidity == 0) revert InsufficientLiquidity();

        uint256 _totalSupply = totalSupply; // gas savings
        uint256 amount0 = (liquidity * balance0) / _totalSupply;
        uint256 amount1 = (liquidity * balance1) / _totalSupply;
        totalSupply = totalSupply - liquidity;

        if (amount0 == 0 || amount1 == 0) revert InsufficientLiquidityBurned();

        TransferHelper.safeTransfer(token0, to, amount0);
        TransferHelper.safeTransfer(token1, to, amount1);

        balance0 =
            IERC20(token0).balanceOf(address(this)) -
            antfarmTokenReserve;
        balance1 = IERC20(token1).balanceOf(address(this));

        _update(balance0, balance1, _reserve0, _reserve1);
        emit Burn(msg.sender, amount0, amount1, to);
        return (amount0, amount1);
    }

    /// @inheritdoc IAntfarmPairActions
    function swap(
        uint256 amount0Out,
        uint256 amount1Out,
        address to
    ) external nonReentrant {
        if (amount0Out == 0 && amount1Out == 0) {
            revert InsufficientOutputAmount();
        }

        (uint112 _reserve0, uint112 _reserve1, ) = getReserves(); // gas savings
        if (amount0Out >= _reserve0 || amount1Out >= _reserve1) {
            revert InsufficientLiquidity();
        }

        uint256 balance0;
        uint256 balance1;
        address _token0 = token0;
        {
            address _token1 = token1;
            if (to == _token0 || to == _token1) revert InvalidReceiver();
            if (amount0Out > 0)
                TransferHelper.safeTransfer(_token0, to, amount0Out); // optimistically transfer tokens
            if (amount1Out > 0)
                TransferHelper.safeTransfer(_token1, to, amount1Out); // optimistically transfer tokens
            balance0 =
                IERC20(_token0).balanceOf(address(this)) -
                antfarmTokenReserve;
            balance1 = IERC20(_token1).balanceOf(address(this));
        }

        uint256 amount0In = balance0 > _reserve0 - amount0Out
            ? balance0 - (_reserve0 - amount0Out)
            : 0;
        uint256 amount1In = balance1 > _reserve1 - amount1Out
            ? balance1 - (_reserve1 - amount1Out)
            : 0;
        if (amount0In == 0 && amount1In == 0) revert InsufficientInputAmount();

        emit Swap(msg.sender, amount0In, amount1In, amount0Out, amount1Out, to);

        // MINIMUM_LIQUIDITY is used instead of 1000
        uint256 feeToPay = ((amount0In * fee) / (MINIMUM_LIQUIDITY + fee)) +
            ((amount0Out * fee) / (MINIMUM_LIQUIDITY - fee));
        if (feeToPay < MINIMUM_LIQUIDITY) revert SwapAmountTooLow();
        balance0 -= feeToPay;

        if (balance0 * balance1 < uint256(_reserve0) * _reserve1) revert K();
        _update(balance0, balance1, _reserve0, _reserve1);

        // only 1% pool have oracles
        if (fee == 10) {
            IAntfarmOracle(antfarmOracle).update(
                price1CumulativeLast,
                blockTimestampLast
            );
        }

        uint256 feeToDisburse = (feeToPay * 8500) / 10000;
        uint256 feeToBurn = feeToPay - feeToDisburse;

        _disburse(feeToDisburse);
        TransferHelper.safeTransfer(
            _token0,
            address(0x000000000000000000000000000000000000dEaD),
            feeToBurn
        );
    }

    /// @inheritdoc IAntfarmPairActions
    function claimDividend(address to, uint256 positionId)
        external
        override
        nonReentrant
        updateDividend(msg.sender, positionId)
        returns (uint256 claimAmount)
    {
        claimAmount = positions[msg.sender][positionId].dividend;
        if (claimAmount != 0) {
            positions[msg.sender][positionId].dividend = 0;
            antfarmTokenReserve -= claimAmount;
            TransferHelper.safeTransfer(token0, to, claimAmount);
        }
    }

    /// @inheritdoc IAntfarmPairActions
    function skim(address to) external nonReentrant {
        address _token0 = token0; // gas savings
        address _token1 = token1; // gas savings
        TransferHelper.safeTransfer(
            _token0,
            to,
            IERC20(_token0).balanceOf(address(this)) -
                reserve0 -
                antfarmTokenReserve
        );
        TransferHelper.safeTransfer(
            _token1,
            to,
            IERC20(_token1).balanceOf(address(this)) - reserve1
        );
    }

    /// @inheritdoc IAntfarmPairActions
    function sync() external nonReentrant {
        _update(
            IERC20(token0).balanceOf(address(this)) - antfarmTokenReserve,
            IERC20(token1).balanceOf(address(this)),
            reserve0,
            reserve1
        );
    }

    /// @inheritdoc IAntfarmPairDerivedState
    function getPositionLP(address operator, uint256 positionId)
        external
        view
        override
        returns (uint128)
    {
        return positions[operator][positionId].lp;
    }

    /// @inheritdoc IAntfarmPairDerivedState
    function getReserves()
        public
        view
        override
        returns (
            uint112 _reserve0,
            uint112 _reserve1,
            uint32 _blockTimestampLast
        )
    {
        _reserve0 = reserve0;
        _reserve1 = reserve1;
        _blockTimestampLast = blockTimestampLast;
    }

    /// @inheritdoc IAntfarmPairDerivedState
    function claimableDividends(address operator, uint256 positionId)
        external
        view
        override
        returns (uint256 amount)
    {
        uint256 tempTotalDividendPoints = totalDividendPoints;

        uint256 newDividend = newDividends(
            operator,
            positionId,
            tempTotalDividendPoints
        );
        amount = positions[operator][positionId].dividend + newDividend;
    }

    function newDividends(
        address operator,
        uint256 positionId,
        uint256 tempTotalDividendPoints
    ) internal view returns (uint256 amount) {
        uint256 newDividendPoints = tempTotalDividendPoints -
            positions[operator][positionId].lastDividendPoints;
        amount =
            (positions[operator][positionId].lp * newDividendPoints) /
            POINT_MULTIPLIER;
    }

    function setOracleInstance() internal {
        antfarmOracle = address(
            new AntfarmOracle(token1, price1CumulativeLast, blockTimestampLast)
        );
    }

    function _update(
        uint256 balance0,
        uint256 balance1,
        uint112 _reserve0,
        uint112 _reserve1
    ) private {
        if (balance0 > type(uint112).max || balance1 > type(uint112).max) {
            revert BalanceOverflow();
        }
        uint32 blockTimestamp = uint32(block.timestamp % 2**32);
        uint32 timeElapsed;

        unchecked {
            timeElapsed = blockTimestamp - blockTimestampLast; // overflow is desired
        }

        if (timeElapsed > 0 && _reserve0 != 0 && _reserve1 != 0) {
            // * never overflows, and + overflow is desired
            price1CumulativeLast =
                price1CumulativeLast +
                (uint256(UQ112x112.encode(_reserve0).uqdiv(_reserve1)) *
                    timeElapsed);
        }
        reserve0 = uint112(balance0);
        reserve1 = uint112(balance1);
        blockTimestampLast = blockTimestamp;
        emit Sync(reserve0, reserve1);
    }

    function _disburse(uint256 amount) private {
        totalDividendPoints =
            totalDividendPoints +
            ((amount * POINT_MULTIPLIER) / (totalSupply - MINIMUM_LIQUIDITY));
        antfarmTokenReserve = antfarmTokenReserve + amount;
    }
}

File 4 of 25 : 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 5 of 25 : AntfarmPair.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.10;

import "../interfaces/IERC20.sol";
import "../interfaces/IAntfarmFactory.sol";
import "../interfaces/IAntfarmPair.sol";
import "../interfaces/IAntfarmAtfPair.sol";
import "../interfaces/IAntfarmOracle.sol";
import "../libraries/math.sol";
import "../libraries/UQ112x112.sol";
import "../libraries/TransferHelper.sol";
import "../utils/AntfarmPairErrors.sol";
import "@rari-capital/solmate/src/utils/ReentrancyGuard.sol";

/// @title Core contract for Antfarm
/// @notice Low-level contract to mint/burn/swap and claim
contract AntfarmPair is IAntfarmPair, ReentrancyGuard, Math {
    using UQ112x112 for uint224;

    /// @inheritdoc IAntfarmPairState
    address public immutable factory;

    /// @inheritdoc IAntfarmPairState
    address public token0;

    /// @inheritdoc IAntfarmPairState
    address public token1;

    /// @inheritdoc IAntfarmPairState
    uint16 public fee;

    /// @inheritdoc IAntfarmPairState
    uint256 public totalSupply;

    /// @inheritdoc IAntfarmPairState
    uint256 public antfarmTokenReserve;

    /// @inheritdoc IAntfarmPair
    address public antfarmToken;

    /// @inheritdoc IAntfarmPair
    address public antfarmOracle;

    uint112 private reserve0;
    uint112 private reserve1;

    // DIVIDEND VARIABLES
    uint256 private totalDividendPoints;
    uint256 private constant POINT_MULTIPLIER = 1 ether;

    uint256 private constant MINIMUM_LIQUIDITY = 1000;

    struct Position {
        uint128 lp;
        uint256 dividend;
        uint256 lastDividendPoints;
    }

    mapping(address => mapping(uint256 => Position)) public positions;

    modifier updateDividend(address operator, uint256 positionId) {
        if (positions[operator][positionId].lp > 0) {
            uint256 owing = newDividends(
                operator,
                positionId,
                totalDividendPoints
            );
            if (owing > 0) {
                positions[operator][positionId].dividend += owing;
                positions[operator][positionId]
                    .lastDividendPoints = totalDividendPoints;
            }
        } else {
            positions[operator][positionId]
                .lastDividendPoints = totalDividendPoints;
        }
        _;
    }

    constructor() {
        factory = msg.sender;
    }

    function initialize(
        address _token0,
        address _token1,
        uint16 _fee,
        address _antfarmToken
    ) external {
        if (msg.sender != factory) revert SenderNotFactory();
        token0 = _token0;
        token1 = _token1;
        fee = _fee;
        antfarmToken = _antfarmToken;
    }

    /// @inheritdoc IAntfarmPairActions
    function mint(address to, uint256 positionId)
        external
        override
        nonReentrant
        updateDividend(to, positionId)
        returns (uint256)
    {
        (uint112 _reserve0, uint112 _reserve1, ) = getReserves();
        uint256 balance0 = IERC20(token0).balanceOf(address(this));
        uint256 balance1 = IERC20(token1).balanceOf(address(this));
        uint256 amount0 = balance0 - _reserve0;
        uint256 amount1 = balance1 - _reserve1;

        uint256 liquidity;

        uint256 _totalSupply = totalSupply;
        if (_totalSupply == 0) {
            liquidity = Math.sqrt(amount0 * amount1) - MINIMUM_LIQUIDITY;
            totalSupply = MINIMUM_LIQUIDITY;
        } else {
            liquidity = Math.min(
                (amount0 * totalSupply) / _reserve0,
                (amount1 * totalSupply) / _reserve1
            );
        }
        if (liquidity == 0) revert InsufficientLiquidityMinted();
        positions[to][positionId].lp += uint128(liquidity);
        totalSupply = totalSupply + liquidity;

        _update(balance0, balance1);
        if (_totalSupply == 0) {
            setOracleInstance();
        }

        emit Mint(to, amount0, amount1);
        return liquidity;
    }

    /// @inheritdoc IAntfarmPairActions
    function burn(
        address to,
        uint256 positionId,
        uint256 liquidity
    )
        external
        override
        nonReentrant
        updateDividend(msg.sender, positionId)
        returns (uint256, uint256)
    {
        address _token0 = token0; // gas savings
        address _token1 = token1; // gas savings
        uint256 balance0 = IERC20(_token0).balanceOf(address(this));
        uint256 balance1 = IERC20(_token1).balanceOf(address(this));

        if (positions[msg.sender][positionId].lp < liquidity) {
            revert InsufficientLiquidity();
        }

        positions[msg.sender][positionId].lp -= uint128(liquidity);

        if (liquidity == 0) revert InsufficientLiquidity();

        uint256 _totalSupply = totalSupply; // gas savings
        uint256 amount0 = (liquidity * balance0) / _totalSupply;
        uint256 amount1 = (liquidity * balance1) / _totalSupply;
        totalSupply = totalSupply - liquidity;

        if (amount0 == 0 || amount1 == 0) revert InsufficientLiquidityBurned();
        TransferHelper.safeTransfer(_token0, to, amount0);
        TransferHelper.safeTransfer(_token1, to, amount1);

        balance0 = IERC20(_token0).balanceOf(address(this));
        balance1 = IERC20(_token1).balanceOf(address(this));

        _update(balance0, balance1);
        emit Burn(msg.sender, amount0, amount1, to);
        return (amount0, amount1);
    }

    /// @inheritdoc IAntfarmPairActions
    function swap(
        uint256 amount0Out,
        uint256 amount1Out,
        address to
    ) external nonReentrant {
        if (amount0Out == 0 && amount1Out == 0) {
            revert InsufficientOutputAmount();
        }

        (uint112 _reserve0, uint112 _reserve1, ) = getReserves(); // gas savings
        if (amount0Out >= _reserve0 || amount1Out >= _reserve1) {
            revert InsufficientLiquidity();
        }

        uint256 balance0;
        uint256 balance1;
        {
            address _token0 = token0;
            address _token1 = token1;
            if (to == _token0 || to == _token1) revert InvalidReceiver();
            if (amount0Out > 0)
                TransferHelper.safeTransfer(_token0, to, amount0Out); // optimistically transfer tokens
            if (amount1Out > 0)
                TransferHelper.safeTransfer(_token1, to, amount1Out); // optimistically transfer tokens

            balance0 = IERC20(_token0).balanceOf(address(this));
            balance1 = IERC20(_token1).balanceOf(address(this));
        }

        uint256 amount0In = balance0 > _reserve0 - amount0Out
            ? balance0 - (_reserve0 - amount0Out)
            : 0;
        uint256 amount1In = balance1 > _reserve1 - amount1Out
            ? balance1 - (_reserve1 - amount1Out)
            : 0;
        if (amount0In == 0 && amount1In == 0) revert InsufficientInputAmount();

        emit Swap(msg.sender, amount0In, amount1In, amount0Out, amount1Out, to);

        uint256 feeToPay;

        feeToPay = getFees(amount0Out, amount0In, amount1Out, amount1In);
        if (feeToPay < MINIMUM_LIQUIDITY) revert SwapAmountTooLow();
        if (
            IERC20(antfarmToken).balanceOf(address(this)) -
                antfarmTokenReserve <
            feeToPay
        ) {
            revert InsufficientFee();
        }

        if (balance0 * balance1 < uint256(_reserve0) * _reserve1) revert K();
        _update(balance0, balance1);

        uint256 feeToDisburse = (feeToPay * 8500) / 10000;
        uint256 feeToBurn = feeToPay - feeToDisburse;

        _disburse(feeToDisburse);
        TransferHelper.safeTransfer(
            antfarmToken,
            address(0x000000000000000000000000000000000000dEaD),
            feeToBurn
        );
    }

    /// @inheritdoc IAntfarmPairActions
    function claimDividend(address to, uint256 positionId)
        external
        override
        nonReentrant
        updateDividend(msg.sender, positionId)
        returns (uint256 claimAmount)
    {
        claimAmount = positions[msg.sender][positionId].dividend;
        if (claimAmount != 0) {
            positions[msg.sender][positionId].dividend = 0;
            antfarmTokenReserve -= claimAmount;
            TransferHelper.safeTransfer(antfarmToken, to, claimAmount);
        }
    }

    /// @inheritdoc IAntfarmPairActions
    function skim(address to) external nonReentrant {
        address _token0 = token0; // gas savings
        address _token1 = token1; // gas savings
        TransferHelper.safeTransfer(
            _token0,
            to,
            IERC20(_token0).balanceOf(address(this)) - reserve0
        );
        TransferHelper.safeTransfer(
            _token1,
            to,
            IERC20(_token1).balanceOf(address(this)) - reserve1
        );
    }

    /// @inheritdoc IAntfarmPairActions
    function sync() external nonReentrant {
        _update(
            IERC20(token0).balanceOf(address(this)),
            IERC20(token1).balanceOf(address(this))
        );
    }

    /// @inheritdoc IAntfarmPairDerivedState
    function getPositionLP(address operator, uint256 positionId)
        external
        view
        override
        returns (uint128)
    {
        return positions[operator][positionId].lp;
    }

    /// @inheritdoc IAntfarmPair
    function updateOracle() public {
        address actualOracle;
        uint112 maxReserve;
        if (antfarmOracle != address(0)) {
            actualOracle = IAntfarmOracle(antfarmOracle).pair();
            (maxReserve, , ) = IAntfarmAtfPair(actualOracle).getReserves();
        }

        address bestOracle = scanOracles(maxReserve);
        if (bestOracle == address(0)) revert NoOracleFound();
        if (bestOracle == antfarmOracle) revert NoBetterOracle();
        antfarmOracle = bestOracle;
    }

    /// @inheritdoc IAntfarmPairDerivedState
    function getReserves()
        public
        view
        override
        returns (
            uint112 _reserve0,
            uint112 _reserve1,
            uint32 _blockTimestampLast
        )
    {
        _reserve0 = reserve0;
        _reserve1 = reserve1;
        _blockTimestampLast = 0;
    }

    /// @inheritdoc IAntfarmPair
    function getFees(
        uint256 amount0Out,
        uint256 amount0In,
        uint256 amount1Out,
        uint256 amount1In
    ) public view returns (uint256 feeToPay) {
        if (IAntfarmOracle(antfarmOracle).token1() == token0) {
            feeToPay = IAntfarmOracle(antfarmOracle).consult(
                token0,
                ((amount0In + amount0Out) * fee) / MINIMUM_LIQUIDITY
            );
        } else {
            feeToPay = IAntfarmOracle(antfarmOracle).consult(
                token1,
                ((amount1In + amount1Out) * fee) / MINIMUM_LIQUIDITY
            );
        }
    }

    /// @inheritdoc IAntfarmPairDerivedState
    function claimableDividends(address operator, uint256 positionId)
        external
        view
        override
        returns (uint256 amount)
    {
        uint256 tempTotalDividendPoints = totalDividendPoints;

        uint256 newDividend = newDividends(
            operator,
            positionId,
            tempTotalDividendPoints
        );
        amount = positions[operator][positionId].dividend + newDividend;
    }

    /// @inheritdoc IAntfarmPair
    function scanOracles(uint112 maxReserve)
        public
        view
        override
        returns (address bestOracle)
    {
        address[2] memory tokens = [token0, token1];

        for (uint256 token; token < 2; ++token) {
            address pairAddress = IAntfarmFactory(factory).getPair(
                antfarmToken,
                tokens[token],
                uint16(10)
            );

            if (pairAddress == address(0)) {
                continue;
            }

            IAntfarmAtfPair pair = IAntfarmAtfPair(pairAddress);

            if (AntfarmOracle(pair.antfarmOracle()).firstUpdateCall()) {
                continue;
            }

            (uint112 _reserve0, , ) = pair.getReserves();

            if (_reserve0 >= maxReserve) {
                bestOracle = address(pair.antfarmOracle());
                maxReserve = _reserve0;
            }
        }
    }

    function newDividends(
        address operator,
        uint256 positionId,
        uint256 tempTotalDividendPoints
    ) internal view returns (uint256 amount) {
        uint256 newDividendPoints = tempTotalDividendPoints -
            positions[operator][positionId].lastDividendPoints;
        amount =
            (positions[operator][positionId].lp * newDividendPoints) /
            POINT_MULTIPLIER;
    }

    function setOracleInstance() internal {
        updateOracle();
        if (antfarmOracle == address(0)) {
            revert NoOracleFound();
        }
    }

    function _update(uint256 balance0, uint256 balance1) private {
        if (balance0 > type(uint112).max || balance1 > type(uint112).max) {
            revert BalanceOverflow();
        }

        reserve0 = uint112(balance0);
        reserve1 = uint112(balance1);
        emit Sync(reserve0, reserve1);
    }

    function _disburse(uint256 amount) private {
        totalDividendPoints =
            totalDividendPoints +
            ((amount * POINT_MULTIPLIER) / (totalSupply - MINIMUM_LIQUIDITY));
        antfarmTokenReserve = antfarmTokenReserve + amount;
    }
}

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

import "../antfarm/AntfarmOracle.sol";
import "./IAntfarmBase.sol";

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

    /// @notice The Oracle instance associated to the AntfarmPair
    /// @return AntfarmOracle Oracle instance
    function antfarmOracle() external view returns (address);

    /// @notice Average token0 price depending on the AntfarmOracle's period
    /// @return uint token0 Average price
    function price1CumulativeLast() external view returns (uint256);
}

File 7 of 25 : 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 8 of 25 : 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 9 of 25 : IAntfarmOracle.sol
// SPDX-License-Identifier: MIT
pragma solidity =0.8.10;

interface IAntfarmOracle {
    function pair() external view returns (address);

    function token1() external view returns (address);

    function consult(address, uint256) external view returns (uint256);

    function update(uint256, uint32) external;
}

File 10 of 25 : 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 11 of 25 : 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 12 of 25 : 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 13 of 25 : 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 14 of 25 : 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 15 of 25 : 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 16 of 25 : 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 17 of 25 : 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 18 of 25 : 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 19 of 25 : 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 20 of 25 : 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 21 of 25 : math.sol
// SPDX-License-Identifier: MIT
pragma solidity =0.8.10;

// a library for performing various math operations

contract Math {
    function min(uint256 x, uint256 y) internal pure returns (uint256 z) {
        z = x < y ? x : y;
    }

    // babylonian method (https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method)
    function sqrt(uint256 y) internal pure returns (uint256 z) {
        if (y > 3) {
            z = y;
            uint256 x = y / 2 + 1;
            while (x < z) {
                z = x;
                x = (y / x + x) / 2;
            }
        } else if (y != 0) {
            z = 1;
        }
    }
}

File 22 of 25 : 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 23 of 25 : UQ112x112.sol
// SPDX-License-Identifier: MIT
pragma solidity =0.8.10;

// a library for handling binary fixed point numbers (https://en.wikipedia.org/wiki/Q_(number_format))

// range: [0, 2**112 - 1]
// resolution: 1 / 2**112

library UQ112x112 {
    uint224 constant Q112 = 2**112;

    // encode a uint112 as a UQ112x112
    function encode(uint112 y) internal pure returns (uint224 z) {
        z = uint224(y) * Q112; // never overflows
    }

    // divide a UQ112x112 by a uint112, returning a UQ112x112
    function uqdiv(uint224 x, uint112 y) internal pure returns (uint224 z) {
        z = x / uint224(y);
    }
}

File 24 of 25 : AntfarmFactoryErrors.sol
// SPDX-License-Identifier: MIT
pragma solidity =0.8.10;

error IdenticalAddresses();
error ZeroAddress();
error PairExists();
error IncorrectFee();
error ForbiddenFee();

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

error SenderNotFactory();
error InsufficientOutputAmount();
error InsufficientLiquidity();
error InsufficientLiquidityMinted();
error InsufficientLiquidityBurned();
error InvalidReceiver();
error InsufficientInputAmount();
error InsufficientFee();
error K();
error SwapAmountTooLow();
error NoOracleFound();
error NoBetterOracle();
error BalanceOverflow();

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":"_antfarmToken","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ForbiddenFee","type":"error"},{"inputs":[],"name":"IdenticalAddresses","type":"error"},{"inputs":[],"name":"IncorrectFee","type":"error"},{"inputs":[],"name":"PairExists","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token0","type":"address"},{"indexed":true,"internalType":"address","name":"token1","type":"address"},{"indexed":false,"internalType":"address","name":"pair","type":"address"},{"indexed":false,"internalType":"uint16","name":"fee","type":"uint16"},{"indexed":false,"internalType":"uint256","name":"allPairsLength","type":"uint256"}],"name":"PairCreated","type":"event"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"allPairs","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"allPairsLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"antfarmToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"uint16","name":"fee","type":"uint16"}],"name":"createPair","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"feesForPair","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token0","type":"address"},{"internalType":"address","name":"_token1","type":"address"}],"name":"getFeesForPair","outputs":[{"internalType":"uint16[8]","name":"","type":"uint16[8]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint16","name":"","type":"uint16"}],"name":"getPair","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"startIndex","type":"uint256"},{"internalType":"uint256","name":"numOfPairs","type":"uint256"}],"name":"getPairs","outputs":[{"internalType":"address[]","name":"pairs","type":"address[]"},{"internalType":"uint256","name":"newIndex","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPossibleFees","outputs":[{"internalType":"uint16[8]","name":"","type":"uint16[8]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"possibleFees","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"}]

610180604052600a6080908152603260a052606460c052609660e05260fa610100526101f4610120526102ee610140526103e86101605262000046906000906008620000eb565b503480156200005457600080fd5b5060405162005f2838038062005f2883398101604081905262000077916200019f565b6001600160a01b038116620000c55760405162461bcd60e51b815260206004820152601060248201526f4e554c4c5f4154465f4144445245535360801b604482015260640160405180910390fd5b600280546001600160a01b0319166001600160a01b0392909216919091179055620001d1565b600183019183908215620001765791602002820160005b838211156200014457835183826101000a81548161ffff021916908361ffff160217905550926020019260020160208160010104928301926001030262000102565b8015620001745782816101000a81549061ffff021916905560020160208160010104928301926001030262000144565b505b506200018492915062000188565b5090565b5b8082111562000184576000815560010162000189565b600060208284031215620001b257600080fd5b81516001600160a01b0381168114620001ca57600080fd5b9392505050565b615d4780620001e16000396000f3fe608060405234801561001057600080fd5b50600436106100be5760003560e01c8063af5a96f211610076578063e579c2c21161005b578063e579c2c2146101aa578063ea313891146101b2578063f2364e91146101c557600080fd5b8063af5a96f214610184578063c12a00a81461019757600080fd5b80634bc72874116100a75780634bc728741461012d578063574f2ba3146101535780638647fe2e1461016457600080fd5b806309175fa7146100c35780631e3dd18b1461011a575b600080fd5b6100fd6100d1366004610d46565b60036020908152600093845260408085208252928452828420905282529020546001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b6100fd610128366004610d94565b6101e6565b61014061013b366004610dad565b610210565b60405161ffff9091168152602001610111565b600154604051908152602001610111565b610177610172366004610de9565b61025a565b6040516101119190610e13565b610140610192366004610d94565b6102e3565b6002546100fd906001600160a01b031681565b610177610311565b6100fd6101c0366004610d46565b610373565b6101d86101d3366004610e49565b610964565b604051610111929190610e6b565b600181815481106101f657600080fd5b6000918252602090912001546001600160a01b0316905081565b6004602052826000526040600020602052816000526040600020816008811061023857600080fd5b6010918282040191900660020292509250509054906101000a900461ffff1681565b610262610c46565b6001600160a01b03838116600090815260046020908152604080832093861683529290528181208251610100810193849052929091600891908390855b82829054906101000a900461ffff1661ffff168152602001906002019060208260010104928301926001038202915080841161029f57509498975050505050505050565b600081600881106102f357600080fd5b60109182820401919006600202915054906101000a900461ffff1681565b610319610c46565b60408051610100810191829052906000906008908280855b82829054906101000a900461ffff1661ffff16815260200190600201906020826001010492830192600103820291508084116103315790505050505050905090565b60008061037f83610a72565b9050836001600160a01b0316856001600160a01b031614156103cd576040517fbd969eb000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60025460009081906001600160a01b03888116911614806103fb57506002546001600160a01b038781169116145b156104a6576002546001600160a01b03888116911614610427576002546001600160a01b031687610435565b6002546001600160a01b0316865b90925090506001600160a01b0381166104615760405163d92e233d60e01b815260040160405180910390fd5b8461ffff166103e814156104a1576040517f0c3f0a8800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6104f5565b856001600160a01b0316876001600160a01b0316106104c65785876104c9565b86865b90925090506001600160a01b0382166104f55760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b0382811660009081526003602090815260408083208585168452825280832061ffff8a1684529091529020541615610560576040517f3d77e89100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60025460009081906001600160a01b038581169116146105a15760405161058960208201610c65565b601f1982820381018352601f909101166040526105c4565b6040516105b060208201610c72565b601f1982820381018352601f909101166040525b6002546040516bffffffffffffffffffffffff19606088811b8216602084015287811b821660348401527fffff00000000000000000000000000000000000000000000000000000000000060f08d901b1660488401529290921b909116604a820152909150600090605e01604051602081830303815290604052805190602001209050808251602084016000f592508260036000876001600160a01b03166001600160a01b031681526020019081526020016000206000866001600160a01b03166001600160a01b0316815260200190815260200160002060008a61ffff1661ffff16815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b031602179055508260036000866001600160a01b03166001600160a01b031681526020019081526020016000206000876001600160a01b03166001600160a01b0316815260200190815260200160002060008a61ffff1661ffff16815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b0316021790555061076a858588610b0c565b6001805480820182556000919091527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf60180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0385811691909117909155600254811690861614610875576002546040517fb1ffa5820000000000000000000000000000000000000000000000000000000081526001600160a01b038781166004830152868116602483015261ffff8b16604483015291821660648201529084169063b1ffa58290608401600060405180830381600087803b15801561085857600080fd5b505af115801561086c573d6000803e3d6000fd5b505050506108fc565b6040517f7ebef5290000000000000000000000000000000000000000000000000000000081526001600160a01b038681166004830152858116602483015261ffff8a166044830152841690637ebef52990606401600060405180830381600087803b1580156108e357600080fd5b505af11580156108f7573d6000803e3d6000fd5b505050505b600154604080516001600160a01b03868116825261ffff8c1660208301529181019290925280861691908716907f510cf15a092d0302f720eeedd34384cb979a59f85143c19f100768c260bc3f5f9060600160405180910390a3509098975050505050505050565b606060008361097260015490565b61097c9190610ed2565b83111561099a578361098d60015490565b6109979190610ed2565b92505b8267ffffffffffffffff8111156109b3576109b3610ee9565b6040519080825280602002602001820160405280156109dc578160200160208202803683370190505b50915060005b83811015610a5e5760016109f68287610eff565b81548110610a0657610a06610f17565b9060005260206000200160009054906101000a90046001600160a01b0316838281518110610a3657610a36610f17565b6001600160a01b0390921660209283029190910190910152610a5781610f2d565b90506109e2565b50610a698385610eff565b90509250929050565b6000805b60088161ffff161015610ad95760008161ffff1660088110610a9a57610a9a610f17565b601091828204019190066002029054906101000a900461ffff1661ffff168361ffff161415610ac95792915050565b610ad281610f48565b9050610a76565b506040517fcd3cb2bb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0383811660009081526004602090815260408083209386168352929052818120825161010081019384905291926008908285855b82829054906101000a900461ffff1661ffff1681526020019060020190602082600101049283019260010382029150808411610b475790505050505050905060008261ffff1660088110610b9d57610b9d610f17565b601091828204019190066002029054906101000a900461ffff16818361ffff1660088110610bcd57610bcd610f17565b61ffff909216602092830291909101526001600160a01b0380861660009081526004835260408082209287168252919092529020610c0d90826008610c7f565b506001600160a01b038084166000908152600460209081526040808320938816835292905220610c3f90826008610c7f565b5050505050565b6040518061010001604052806008906020820280368337509192915050565b61256d80610f6b83390190565b61283a806134d883390190565b600183019183908215610d055791602002820160005b83821115610cd557835183826101000a81548161ffff021916908361ffff1602179055509260200192600201602081600101049283019260010302610c95565b8015610d035782816101000a81549061ffff0219169055600201602081600101049283019260010302610cd5565b505b50610d11929150610d15565b5090565b5b80821115610d115760008155600101610d16565b80356001600160a01b0381168114610d4157600080fd5b919050565b600080600060608486031215610d5b57600080fd5b610d6484610d2a565b9250610d7260208501610d2a565b9150604084013561ffff81168114610d8957600080fd5b809150509250925092565b600060208284031215610da657600080fd5b5035919050565b600080600060608486031215610dc257600080fd5b610dcb84610d2a565b9250610dd960208501610d2a565b9150604084013590509250925092565b60008060408385031215610dfc57600080fd5b610e0583610d2a565b9150610a6960208401610d2a565b6101008101818360005b6008811015610e4057815161ffff16835260209283019290910190600101610e1d565b50505092915050565b60008060408385031215610e5c57600080fd5b50508035926020909101359150565b604080825283519082018190526000906020906060840190828701845b82811015610ead5781516001600160a01b031684529284019290840190600101610e88565b50505092019290925292915050565b634e487b7160e01b600052601160045260246000fd5b600082821015610ee457610ee4610ebc565b500390565b634e487b7160e01b600052604160045260246000fd5b60008219821115610f1257610f12610ebc565b500190565b634e487b7160e01b600052603260045260246000fd5b6000600019821415610f4157610f41610ebc565b5060010190565b600061ffff80831681811415610f6057610f60610ebc565b600101939250505056fe60a0604052600160005534801561001557600080fd5b503360805260805161252a610043600039600081816103680152818161113301526113e2015261252a6000f3fe608060405234801561001057600080fd5b50600436106101825760003560e01c8063bc25cf77116100d8578063d6f124f01161008c578063f5298aca11610066578063f5298aca146103e0578063f6c67d8d14610408578063fff6cae91461041b57600080fd5b8063d6f124f01461039d578063ddca3f43146103a5578063e680ea2c146103cd57600080fd5b8063c1be6677116100bd578063c1be6677146102fa578063c45a015514610363578063d21220a71461038a57600080fd5b8063bc25cf77146102d4578063c12a00a8146102e757600080fd5b80632f7256381161013a5780636d9a640a116101145780636d9a640a1461029957806382e6a1c6146102ae578063b1ffa582146102c157600080fd5b80632f7256381461026057806340c10f19146102735780635247ab051461028657600080fd5b80630eb290661161016b5780630eb29066146101e957806318160ddd146102005780631f9d4db21461020957600080fd5b80630902f1ac146101875780630dfe1681146101be575b600080fd5b600754604080516001600160701b038084168252600160701b90930490921660208301526000908201526060015b60405180910390f35b6001546101d1906001600160a01b031681565b6040516001600160a01b0390911681526020016101b5565b6101f260045481565b6040519081526020016101b5565b6101f260035481565b61024861021736600461218e565b6001600160a01b0391909116600090815260096020908152604080832093835292905220546001600160801b031690565b6040516001600160801b0390911681526020016101b5565b6101f261026e3660046121ba565b610423565b6101f261028136600461218e565b61063f565b6101f261029436600461218e565b610a40565b6102ac6102a73660046121ec565b610bd3565b005b6101d16102bc36600461223a565b6110f2565b6102ac6102cf366004612257565b6113d7565b6102ac6102e23660046122ba565b6114b6565b6005546101d1906001600160a01b031681565b61033e61030836600461218e565b60096020908152600092835260408084209091529082529020805460018201546002909201546001600160801b03909116919083565b604080516001600160801b0390941684526020840192909252908201526060016101b5565b6101d17f000000000000000000000000000000000000000000000000000000000000000081565b6002546101d1906001600160a01b031681565b6102ac6115e7565b6002546103ba90600160a01b900461ffff1681565b60405161ffff90911681526020016101b5565b6101f26103db36600461218e565b61178b565b6103f36103ee3660046122d7565b6117db565b604080519283526020830191909152016101b5565b6006546101d1906001600160a01b031681565b6102ac611c8d565b600154600654604080517fd21220a700000000000000000000000000000000000000000000000000000000815290516000936001600160a01b0390811693169163d21220a79160048083019260209291908290030181865afa15801561048d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104b1919061230c565b6001600160a01b0316141561057e576006546001546002546001600160a01b0392831692633ddac9539216906103e890600160a01b900461ffff166104f68a8a61233f565b6105009190612357565b61050a9190612376565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa158015610553573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105779190612398565b9050610637565b6006546002546001600160a01b0391821691633ddac95391908116906103e890600160a01b900461ffff166105b3888861233f565b6105bd9190612357565b6105c79190612376565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa158015610610573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106349190612398565b90505b949350505050565b600080546001146106845760405162461bcd60e51b815260206004820152600a6024820152695245454e5452414e435960b01b60448201526064015b60405180910390fd5b600260009081556001600160a01b0384168152600960209081526040808320858452909152902054839083906001600160801b0316156107415760006106cd8383600854611db7565b9050801561073b576001600160a01b03831660009081526009602090815260408083208584529091528120600101805483929061070b90849061233f565b90915550506008546001600160a01b03841660009081526009602090815260408083208684529091529020600201555b5061076c565b6008546001600160a01b03831660009081526009602090815260408083208584529091529020600201555b60075460009081906001600160701b0380821691600160701b9004166001546040516370a0823160e01b81523060048201529294509092506000916001600160a01b03909116906370a0823190602401602060405180830381865afa1580156107d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107fd9190612398565b6002546040516370a0823160e01b81523060048201529192506000916001600160a01b03909116906370a0823190602401602060405180830381865afa15801561084b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061086f9190612398565b905060006108866001600160701b038616846123b1565b9050600061089d6001600160701b038616846123b1565b600354909150600090806108d7576103e86108c06108bb8587612357565b611e39565b6108ca91906123b1565b6103e86003559150610926565b610923886001600160701b0316600354866108f29190612357565b6108fc9190612376565b886001600160701b0316600354866109149190612357565b61091e9190612376565b611ea9565b91505b8161095d576040517fd226f9d400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038d1660009081526009602090815260408083208f8452909152812080548492906109999084906001600160801b03166123c8565b92506101000a8154816001600160801b0302191690836001600160801b03160217905550816003546109cb919061233f565b6003556109d88686611ec1565b806109e5576109e5611f84565b60408051858152602081018590526001600160a01b038f16917f4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f910160405180910390a25098505050505050505b5050600160005592915050565b60008054600114610a805760405162461bcd60e51b815260206004820152600a6024820152695245454e5452414e435960b01b604482015260640161067b565b60026000908155338082526009602090815260408084208685529091529091205483906001600160801b031615610b34576000610ac08383600854611db7565b90508015610b2e576001600160a01b038316600090815260096020908152604080832085845290915281206001018054839290610afe90849061233f565b90915550506008546001600160a01b03841660009081526009602090815260408083208684529091529020600201555b50610b5f565b6008546001600160a01b03831660009081526009602090815260408083208584529091529020600201555b33600090815260096020908152604080832087845290915290206001015492508215610a3357336000908152600960209081526040808320878452909152812060010181905560048054859290610bb79084906123b1565b9091555050600554610a33906001600160a01b03168685611fb7565b600054600114610c125760405162461bcd60e51b815260206004820152600a6024820152695245454e5452414e435960b01b604482015260640161067b565b600260005582158015610c23575081155b15610c5a576040517f42301c2300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6007546001600160701b0380821691600160701b9004168185101580610c895750806001600160701b03168410155b15610ca75760405163bb55fd2760e01b815260040160405180910390fd5b60015460025460009182916001600160a01b0391821691908116908716821480610ce25750806001600160a01b0316876001600160a01b0316145b15610d19576040517f1e4ec46b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8815610d2a57610d2a82888b611fb7565b8715610d3b57610d3b81888a611fb7565b6040516370a0823160e01b81523060048201526001600160a01b038316906370a0823190602401602060405180830381865afa158015610d7f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610da39190612398565b6040516370a0823160e01b81523060048201529094506001600160a01b038216906370a0823190602401602060405180830381865afa158015610dea573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e0e9190612398565b92505050600087856001600160701b0316610e2991906123b1565b8311610e36576000610e53565b610e49886001600160701b0387166123b1565b610e5390846123b1565b90506000610e6a886001600160701b0387166123b1565b8311610e77576000610e94565b610e8a886001600160701b0387166123b1565b610e9490846123b1565b905081158015610ea2575080155b15610ed9576040517f098fb56100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408051838152602081018390529081018a9052606081018990526001600160a01b0388169033907fd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d8229060800160405180910390a36000610f3c8a848b85610423565b90506103e8811015610f7a576040517ff570cd7700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600480546005546040516370a0823160e01b8152309381019390935283926001600160a01b03909116906370a0823190602401602060405180830381865afa158015610fca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fee9190612398565b610ff891906123b1565b1015611030576040517f025dbdd400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6110466001600160701b03808816908916612357565b6110508587612357565b1015611088576040517fa932492f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6110928585611ec1565b60006127106110a383612134612357565b6110ad9190612376565b905060006110bb82846123b1565b90506110c682612126565b6005546110df906001600160a01b031661dead83611fb7565b5050600160005550505050505050505050565b604080518082019091526001546001600160a01b039081168252600254166020820152600090815b60028110156113d0576005546000906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116916309175fa7911685856002811061116e5761116e6123f3565b60200201516040516001600160e01b031960e085901b1681526001600160a01b03928316600482015291166024820152600a6044820152606401602060405180830381865afa1580156111c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111e9919061230c565b90506001600160a01b0381166111ff57506113c0565b6000819050806001600160a01b031663f6c67d8d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611242573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611266919061230c565b6001600160a01b031663fcfedfb16040518163ffffffff1660e01b8152600401602060405180830381865afa1580156112a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112c79190612409565b156112d35750506113c0565b6000816001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa158015611313573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611337919061242b565b50509050866001600160701b0316816001600160701b0316106113bc57816001600160a01b031663f6c67d8d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611392573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113b6919061230c565b95508096505b5050505b6113c981612476565b905061111a565b5050919050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611439576040517f015551dc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180546001600160a01b0395861673ffffffffffffffffffffffffffffffffffffffff19918216179091556002805461ffff909416600160a01b027fffffffffffffffffffff00000000000000000000000000000000000000000000909416948616949094179290921790925560058054929093169116179055565b6000546001146114f55760405162461bcd60e51b815260206004820152600a6024820152695245454e5452414e435960b01b604482015260640161067b565b6002600081905560015490546007546040516370a0823160e01b81523060048201526001600160a01b03938416939092169161159591849186916001600160701b03169083906370a08231906024015b602060405180830381865afa158015611562573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115869190612398565b61159091906123b1565b611fb7565b6007546040516370a0823160e01b81523060048201526115dd9183918691600160701b90046001600160701b0316906001600160a01b038416906370a0823190602401611545565b5050600160005550565b60065460009081906001600160a01b0316156116de57600660009054906101000a90046001600160a01b03166001600160a01b031663a8aa1b316040518163ffffffff1660e01b8152600401602060405180830381865afa158015611650573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611674919061230c565b9150816001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa1580156116b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116d8919061242b565b50909150505b60006116e9826110f2565b90506001600160a01b03811661171257604051639989e18760e01b815260040160405180910390fd5b6006546001600160a01b038281169116141561175a576040517febd9054000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6006805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03929092169190911790555050565b6008546000908161179d858584611db7565b6001600160a01b03861660009081526009602090815260408083208884529091529020600101549091506117d290829061233f565b95945050505050565b60008060005460011461181d5760405162461bcd60e51b815260206004820152600a6024820152695245454e5452414e435960b01b604482015260640161067b565b60026000908155338082526009602090815260408084208885529091529091205485906001600160801b0316156118d157600061185d8383600854611db7565b905080156118cb576001600160a01b03831660009081526009602090815260408083208584529091528120600101805483929061189b90849061233f565b90915550506008546001600160a01b03841660009081526009602090815260408083208684529091529020600201555b506118fc565b6008546001600160a01b03831660009081526009602090815260408083208584529091529020600201555b6001546002546040516370a0823160e01b81523060048201526001600160a01b03928316929091169060009083906370a0823190602401602060405180830381865afa158015611950573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119749190612398565b6040516370a0823160e01b81523060048201529091506000906001600160a01b038416906370a0823190602401602060405180830381865afa1580156119be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119e29190612398565b3360009081526009602090815260408083208e84529091529020549091506001600160801b0316891115611a295760405163bb55fd2760e01b815260040160405180910390fd5b3360009081526009602090815260408083208d8452909152812080548b9290611a5c9084906001600160801b0316612491565b92506101000a8154816001600160801b0302191690836001600160801b031602179055508860001415611aa25760405163bb55fd2760e01b815260040160405180910390fd5b600354600081611ab2858d612357565b611abc9190612376565b9050600082611acb858e612357565b611ad59190612376565b90508b600354611ae591906123b1565b600355811580611af3575080155b15611b2a576040517f749383ad00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611b35878f84611fb7565b611b40868f83611fb7565b6040516370a0823160e01b81523060048201526001600160a01b038816906370a0823190602401602060405180830381865afa158015611b84573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ba89190612398565b6040516370a0823160e01b81523060048201529095506001600160a01b038716906370a0823190602401602060405180830381865afa158015611bef573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c139190612398565b9350611c1f8585611ec1565b8d6001600160a01b0316336001600160a01b03167fdccd412f0b1252819cb1fd330b93224ca42612892bb3f4f789976e6d819364968484604051611c6d929190918252602082015260400190565b60405180910390a36001600055909d909c509a5050505050505050505050565b600054600114611ccc5760405162461bcd60e51b815260206004820152600a6024820152695245454e5452414e435960b01b604482015260640161067b565b60026000556001546040516370a0823160e01b8152306004820152611db0916001600160a01b0316906370a0823190602401602060405180830381865afa158015611d1b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d3f9190612398565b6002546040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa158015611d87573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dab9190612398565b611ec1565b6001600055565b6001600160a01b03831660009081526009602090815260408083208584529091528120600201548190611dea90846123b1565b6001600160a01b0386166000908152600960209081526040808320888452909152902054909150670de0b6b3a764000090611e2f9083906001600160801b0316612357565b6117d29190612376565b60006003821115611e9a5750806000611e53600283612376565b611e5e90600161233f565b90505b81811015611e9457905080600281611e798186612376565b611e83919061233f565b611e8d9190612376565b9050611e61565b50919050565b8115611ea4575060015b919050565b6000818310611eb85781611eba565b825b9392505050565b6001600160701b03821180611edc57506001600160701b0381115b15611f13576040517f89560ca100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600780546001600160701b03838116600160701b9081026001600160e01b0319909316868316179290921792839055604080518483168152929093041660208201527f1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1910160405180910390a15050565b611f8c6115e7565b6006546001600160a01b0316611fb557604051639989e18760e01b815260040160405180910390fd5b565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052915160009283929087169161204191906124b9565b6000604051808303816000865af19150503d806000811461207e576040519150601f19603f3d011682016040523d82523d6000602084013e612083565b606091505b50915091508180156120ad5750805115806120ad5750808060200190518101906120ad9190612409565b61211f5760405162461bcd60e51b815260206004820152602d60248201527f5472616e7366657248656c7065723a3a736166655472616e736665723a20747260448201527f616e73666572206661696c656400000000000000000000000000000000000000606482015260840161067b565b5050505050565b6103e860035461213691906123b1565b612148670de0b6b3a764000083612357565b6121529190612376565b60085461215f919061233f565b60085560045461217090829061233f565b60045550565b6001600160a01b038116811461218b57600080fd5b50565b600080604083850312156121a157600080fd5b82356121ac81612176565b946020939093013593505050565b600080600080608085870312156121d057600080fd5b5050823594602084013594506040840135936060013592509050565b60008060006060848603121561220157600080fd5b8335925060208401359150604084013561221a81612176565b809150509250925092565b6001600160701b038116811461218b57600080fd5b60006020828403121561224c57600080fd5b8135611eba81612225565b6000806000806080858703121561226d57600080fd5b843561227881612176565b9350602085013561228881612176565b9250604085013561ffff8116811461229f57600080fd5b915060608501356122af81612176565b939692955090935050565b6000602082840312156122cc57600080fd5b8135611eba81612176565b6000806000606084860312156122ec57600080fd5b83356122f781612176565b95602085013595506040909401359392505050565b60006020828403121561231e57600080fd5b8151611eba81612176565b634e487b7160e01b600052601160045260246000fd5b6000821982111561235257612352612329565b500190565b600081600019048311821515161561237157612371612329565b500290565b60008261239357634e487b7160e01b600052601260045260246000fd5b500490565b6000602082840312156123aa57600080fd5b5051919050565b6000828210156123c3576123c3612329565b500390565b60006001600160801b038083168185168083038211156123ea576123ea612329565b01949350505050565b634e487b7160e01b600052603260045260246000fd5b60006020828403121561241b57600080fd5b81518015158114611eba57600080fd5b60008060006060848603121561244057600080fd5b835161244b81612225565b602085015190935061245c81612225565b604085015190925063ffffffff8116811461221a57600080fd5b600060001982141561248a5761248a612329565b5060010190565b60006001600160801b03838116908316818110156124b1576124b1612329565b039392505050565b6000825160005b818110156124da57602081860181015185830152016124c0565b818111156124e9576000828501525b50919091019291505056fea2646970667358221220ed2b296666058c99a67fe8c1e2c2ec013d6cb863394d87553af151363540861f64736f6c634300080a003360a0604052600160005534801561001557600080fd5b50336080526080516127fe61003c6000396000818161034e015261103501526127fe6000f3fe60806040523480156200001157600080fd5b50600436106200016c5760003560e01c80637ebef52911620000dd578063ddca3f43116200008b578063f5298aca116200006e578063f5298aca14620003c5578063f6c67d8d14620003f2578063fff6cae9146200040657600080fd5b8063ddca3f431462000384578063e680ea2c14620003ae57600080fd5b8063c1be667711620000c0578063c1be667714620002db578063c45a01551462000348578063d21220a7146200037057600080fd5b80637ebef52914620002ad578063bc25cf7714620002c457600080fd5b80631f9d4db2116200013b5780635247ab05116200011e5780635247ab0514620002735780635a3d5493146200028a5780636d9a640a146200029457600080fd5b80631f9d4db2146200020157806340c10f19146200025c57600080fd5b80630902f1ac14620001715780630dfe168114620001b15780630eb2906614620001de57806318160ddd14620001f7575b600080fd5b600754604080516001600160701b038084168252600160701b8404166020820152600160e01b90920463ffffffff16908201526060015b60405180910390f35b600154620001c5906001600160a01b031681565b6040516001600160a01b039091168152602001620001a8565b620001e860055481565b604051908152602001620001a8565b620001e860035481565b620002436200021236600462001f12565b6001600160a01b0391909116600090815260096020908152604080832093835292905220546001600160801b031690565b6040516001600160801b039091168152602001620001a8565b620001e86200026d36600462001f12565b62000410565b620001e86200028436600462001f12565b6200087e565b620001e860045481565b620002ab620002a536600462001f3f565b62000a1f565b005b620002ab620002be36600462001f77565b6200102a565b620002ab620002d536600462001fcb565b620010f9565b62000322620002ec36600462001f12565b60096020908152600092835260408084209091529082529020805460018201546002909201546001600160801b03909116919083565b604080516001600160801b039094168452602084019290925290820152606001620001a8565b620001c57f000000000000000000000000000000000000000000000000000000000000000081565b600254620001c5906001600160a01b031681565b6002546200039a90600160a01b900461ffff1681565b60405161ffff9091168152602001620001a8565b620001e8620003bf36600462001f12565b62001283565b620003dc620003d636600462001fe9565b620012d7565b60408051928352602083019190915201620001a8565b600654620001c5906001600160a01b031681565b620002ab62001827565b60008054600114620004565760405162461bcd60e51b815260206004820152600a6024820152695245454e5452414e435960b01b60448201526064015b60405180910390fd5b600260009081556001600160a01b0384168152600960209081526040808320858452909152902054839083906001600160801b0316156200051a576000620004a2838360085462001982565b9050801562000513576001600160a01b038316600090815260096020908152604080832085845290915281206001018054839290620004e390849062002035565b90915550506008546001600160a01b03841660009081526009602090815260408083208684529091529020600201555b5062000545565b6008546001600160a01b03831660009081526009602090815260408083208584529091529020600201555b600080620005776007546001600160701b0380821692600160701b83049091169163ffffffff600160e01b9091041690565b506005546001546040516370a0823160e01b815230600482015293955091935060009290916001600160a01b0316906370a0823190602401602060405180830381865afa158015620005cd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620005f3919062002050565b620005ff91906200206a565b6002546040516370a0823160e01b81523060048201529192506000916001600160a01b03909116906370a0823190602401602060405180830381865afa1580156200064e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000674919062002050565b905060006200068d6001600160701b038616846200206a565b90506000620006a66001600160701b038616846200206a565b60035490915060009080620006e8576103e8620006ce620006c8858762002084565b62001a0a565b620006da91906200206a565b6103e8600355915062000741565b6200073e886001600160701b03166003548662000706919062002084565b620007129190620020bc565b886001600160701b0316600354866200072c919062002084565b620007389190620020bc565b62001a88565b91505b8162000779576040517fd226f9d400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038d1660009081526009602090815260408083208f845290915281208054849290620007b79084906001600160801b0316620020d3565b92506101000a8154816001600160801b0302191690836001600160801b0316021790555081600354620007eb919062002035565b600355620007fc86868a8a62001aa2565b806200082357600254600160a01b900461ffff16600a141562000823576200082362001c54565b60408051858152602081018590526001600160a01b038f16917f4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f910160405180910390a25098505050505050505b5050600160005592915050565b60008054600114620008c05760405162461bcd60e51b815260206004820152600a6024820152695245454e5452414e435960b01b60448201526064016200044d565b60026000908155338082526009602090815260408084208685529091529091205483906001600160801b0316156200097b57600062000903838360085462001982565b9050801562000974576001600160a01b0383166000908152600960209081526040808320858452909152812060010180548392906200094490849062002035565b90915550506008546001600160a01b03841660009081526009602090815260408083208684529091529020600201555b50620009a6565b6008546001600160a01b03831660009081526009602090815260408083208584529091529020600201555b33600090815260096020908152604080832087845290915290206001015492508215620008715733600090815260096020908152604080832087845290915281206001018190556005805485929062000a019084906200206a565b909155505060015462000871906001600160a01b0316868562001cf6565b60005460011462000a605760405162461bcd60e51b815260206004820152600a6024820152695245454e5452414e435960b01b60448201526064016200044d565b60026000558215801562000a72575081155b1562000aaa576040517f42301c2300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008062000adc6007546001600160701b0380821692600160701b83049091169163ffffffff600160e01b9091041690565b5091509150816001600160701b03168510158062000b035750806001600160701b03168410155b1562000b225760405163bb55fd2760e01b815260040160405180910390fd5b60015460025460009182916001600160a01b039182169190811690871682148062000b5e5750806001600160a01b0316876001600160a01b0316145b1562000b96576040517f1e4ec46b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b881562000baa5762000baa82888b62001cf6565b871562000bbe5762000bbe81888a62001cf6565b6005546040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa15801562000c06573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000c2c919062002050565b62000c3891906200206a565b6040516370a0823160e01b81523060048201529094506001600160a01b038216906370a0823190602401602060405180830381865afa15801562000c80573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000ca6919062002050565b92506000905062000cc1896001600160701b0388166200206a565b841162000cd057600062000cf1565b62000ce5896001600160701b0388166200206a565b62000cf190856200206a565b9050600062000d0a896001600160701b0388166200206a565b841162000d1957600062000d3a565b62000d2e896001600160701b0388166200206a565b62000d3a90856200206a565b90508115801562000d49575080155b1562000d81576040517f098fb56100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408051838152602081018390529081018b9052606081018a90526001600160a01b0389169033907fd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d8229060800160405180910390a360025460009062000df590600160a01b900461ffff166103e86200206a565b60025462000e0f90600160a01b900461ffff168d62002084565b62000e1b9190620020bc565b60025462000e3790600160a01b900461ffff166103e862002035565b60025462000e5190600160a01b900461ffff168662002084565b62000e5d9190620020bc565b62000e69919062002035565b90506103e881101562000ea8576040517ff570cd7700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b62000eb481876200206a565b955062000ece6001600160701b03808916908a1662002084565b62000eda868862002084565b101562000f13576040517fa932492f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b62000f2186868a8a62001aa2565b600254600160a01b900461ffff16600a141562000fcb57600654600480546007546040517fcebab53d00000000000000000000000000000000000000000000000000000000815292830191909152600160e01b900463ffffffff1660248201526001600160a01b039091169063cebab53d90604401600060405180830381600087803b15801562000fb157600080fd5b505af115801562000fc6573d6000803e3d6000fd5b505050505b600061271062000fde8361213462002084565b62000fea9190620020bc565b9050600062000ffa82846200206a565b9050620010078262001e5a565b620010168661dead8362001cf6565b505060016000555050505050505050505050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146200108d576040517f015551dc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180546001600160a01b0394851673ffffffffffffffffffffffffffffffffffffffff199091161790556002805461ffff909216600160a01b027fffffffffffffffffffff000000000000000000000000000000000000000000009092169290931691909117179055565b6000546001146200113a5760405162461bcd60e51b815260206004820152600a6024820152695245454e5452414e435960b01b60448201526064016200044d565b6002600081905560015490546005546007546040516370a0823160e01b81523060048201526001600160a01b039485169490931692620011f192859287926001600160701b039091169084906370a0823190602401602060405180830381865afa158015620011ad573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620011d3919062002050565b620011df91906200206a565b620011eb91906200206a565b62001cf6565b6007546040516370a0823160e01b8152306004820152620012799183918691600160701b90046001600160701b0316906001600160a01b038416906370a0823190602401602060405180830381865afa15801562001253573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620011df919062002050565b5050600160005550565b600854600090816200129785858462001982565b6001600160a01b0386166000908152600960209081526040808320888452909152902060010154909150620012ce90829062002035565b95945050505050565b6000806000546001146200131b5760405162461bcd60e51b815260206004820152600a6024820152695245454e5452414e435960b01b60448201526064016200044d565b60026000908155338082526009602090815260408084208885529091529091205485906001600160801b031615620013d65760006200135e838360085462001982565b90508015620013cf576001600160a01b0383166000908152600960209081526040808320858452909152812060010180548392906200139f90849062002035565b90915550506008546001600160a01b03841660009081526009602090815260408083208684529091529020600201555b5062001401565b6008546001600160a01b03831660009081526009602090815260408083208584529091529020600201555b600080620014336007546001600160701b0380821692600160701b83049091169163ffffffff600160e01b9091041690565b506005546001546040516370a0823160e01b815230600482015293955091935060009290916001600160a01b0316906370a0823190602401602060405180830381865afa15801562001489573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620014af919062002050565b620014bb91906200206a565b6002546040516370a0823160e01b81523060048201529192506000916001600160a01b03909116906370a0823190602401602060405180830381865afa1580156200150a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001530919062002050565b3360009081526009602090815260408083208e84529091529020549091506001600160801b0316891115620015785760405163bb55fd2760e01b815260040160405180910390fd5b3360009081526009602090815260408083208d8452909152812080548b9290620015ad9084906001600160801b031662002101565b92506101000a8154816001600160801b0302191690836001600160801b031602179055508860001415620015f45760405163bb55fd2760e01b815260040160405180910390fd5b60035460008162001606858d62002084565b620016129190620020bc565b905060008262001623858e62002084565b6200162f9190620020bc565b90508b6003546200164191906200206a565b60035581158062001650575080155b1562001688576040517f749383ad00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600154620016a1906001600160a01b03168f8462001cf6565b600254620016ba906001600160a01b03168f8362001cf6565b6005546001546040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa15801562001706573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200172c919062002050565b6200173891906200206a565b6002546040516370a0823160e01b81523060048201529196506001600160a01b0316906370a0823190602401602060405180830381865afa15801562001782573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620017a8919062002050565b9350620017b88585898962001aa2565b8d6001600160a01b0316336001600160a01b03167fdccd412f0b1252819cb1fd330b93224ca42612892bb3f4f789976e6d81936496848460405162001807929190918252602082015260400190565b60405180910390a36001600055909d909c509a5050505050505050505050565b600054600114620018685760405162461bcd60e51b815260206004820152600a6024820152695245454e5452414e435960b01b60448201526064016200044d565b60026000556005546001546040516370a0823160e01b81523060048201526200197b92916001600160a01b0316906370a0823190602401602060405180830381865afa158015620018bd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620018e3919062002050565b620018ef91906200206a565b6002546040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa15801562001938573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200195e919062002050565b6007546001600160701b0380821691600160701b90041662001aa2565b6001600055565b6001600160a01b03831660009081526009602090815260408083208584529091528120600201548190620019b790846200206a565b6001600160a01b0386166000908152600960209081526040808320888452909152902054909150670de0b6b3a764000090620019fe9083906001600160801b031662002084565b620012ce9190620020bc565b6000600382111562001a78575080600062001a27600283620020bc565b62001a3490600162002035565b90505b8181101562001a725790508060028162001a528186620020bc565b62001a5e919062002035565b62001a6a9190620020bc565b905062001a37565b50919050565b811562001a83575060015b919050565b600081831062001a99578162001a9b565b825b9392505050565b6001600160701b0384118062001abe57506001600160701b0383115b1562001af6576040517f89560ca100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600062001b09640100000000426200212c565b60075490915063ffffffff600160e01b909104811682039081161580159062001b3a57506001600160701b03841615155b801562001b4f57506001600160701b03831615155b1562001ba4578063ffffffff1662001b7c8462001b6c8762001eb4565b6001600160e01b03169062001ed5565b6001600160e01b031662001b91919062002084565b60045462001ba0919062002035565b6004555b6007805463ffffffff8416600160e01b026001600160e01b036001600160701b03898116600160701b9081027fffffffff000000000000000000000000000000000000000000000000000000009095168c83161794909417918216831794859055604080519382169282169290921783529290930490911660208201527f1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1910160405180910390a1505050505050565b6002546004546007546040516001600160a01b0390931692600160e01b90910463ffffffff169062001c869062001eec565b6001600160a01b039093168352602083019190915263ffffffff166040820152606001604051809103906000f08015801562001cc6573d6000803e3d6000fd5b506006805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b03167fa9059cbb00000000000000000000000000000000000000000000000000000000179052915160009283929087169162001d6d919062002143565b6000604051808303816000865af19150503d806000811462001dac576040519150601f19603f3d011682016040523d82523d6000602084013e62001db1565b606091505b509150915081801562001ddf57508051158062001ddf57508080602001905181019062001ddf919062002181565b62001e535760405162461bcd60e51b815260206004820152602d60248201527f5472616e7366657248656c7065723a3a736166655472616e736665723a20747260448201527f616e73666572206661696c65640000000000000000000000000000000000000060648201526084016200044d565b5050505050565b6103e860035462001e6c91906200206a565b62001e80670de0b6b3a76400008362002084565b62001e8c9190620020bc565b60085462001e9b919062002035565b60085560055462001eae90829062002035565b60055550565b600062001ecf600160701b6001600160701b038416620021a5565b92915050565b600062001a9b6001600160701b03831684620021d7565b6105c8806200220183390190565b80356001600160a01b038116811462001a8357600080fd5b6000806040838503121562001f2657600080fd5b62001f318362001efa565b946020939093013593505050565b60008060006060848603121562001f5557600080fd5b833592506020840135915062001f6e6040850162001efa565b90509250925092565b60008060006060848603121562001f8d57600080fd5b62001f988462001efa565b925062001fa86020850162001efa565b9150604084013561ffff8116811462001fc057600080fd5b809150509250925092565b60006020828403121562001fde57600080fd5b62001a9b8262001efa565b60008060006060848603121562001fff57600080fd5b6200200a8462001efa565b95602085013595506040909401359392505050565b634e487b7160e01b600052601160045260246000fd5b600082198211156200204b576200204b6200201f565b500190565b6000602082840312156200206357600080fd5b5051919050565b6000828210156200207f576200207f6200201f565b500390565b6000816000190483118215151615620020a157620020a16200201f565b500290565b634e487b7160e01b600052601260045260246000fd5b600082620020ce57620020ce620020a6565b500490565b60006001600160801b03808316818516808303821115620020f857620020f86200201f565b01949350505050565b60006001600160801b03838116908316818110156200212457620021246200201f565b039392505050565b6000826200213e576200213e620020a6565b500690565b6000825160005b818110156200216657602081860181015185830152016200214a565b8181111562002176576000828501525b509190910192915050565b6000602082840312156200219457600080fd5b8151801515811462001a9b57600080fd5b60006001600160e01b0380831681851681830481118215151615620021ce57620021ce6200201f565b02949350505050565b60006001600160e01b0380841680620021f457620021f4620020a6565b9216919091049291505056fe608060405234801561001057600080fd5b506040516105c83803806105c883398101604081905261002f9161008b565b600080546001600160a01b039094166001600160a01b031994851617905560018054909316331783556002919091556003805463ffffffff90921663ffffffff199092169190911790556005805460ff191690911790556100e3565b6000806000606084860312156100a057600080fd5b83516001600160a01b03811681146100b757600080fd5b60208501516040860151919450925063ffffffff811681146100d857600080fd5b809150509250925092565b6104d6806100f26000396000f3fe608060405234801561001057600080fd5b50600436106100a35760003560e01c8063b4d1d79511610076578063cebab53d1161005b578063cebab53d1461015b578063d21220a714610170578063fcfedfb11461018357600080fd5b8063b4d1d7951461012d578063c5700a021461013657600080fd5b80633ddac953146100a85780635a3d5493146100ce5780635e6aaf2c146100d7578063a8aa1b3114610102575b600080fd5b6100bb6100b63660046103ca565b6101a0565b6040519081526020015b60405180910390f35b6100bb60025481565b6004546100ea906001600160e01b031681565b6040516001600160e01b0390911681526020016100c5565b600154610115906001600160a01b031681565b6040516001600160a01b0390911681526020016100c5565b6100bb610e1081565b6003546101469063ffffffff1681565b60405163ffffffff90911681526020016100c5565b61016e610169366004610402565b610238565b005b600054610115906001600160a01b031681565b6005546101909060ff1681565b60405190151581526020016100c5565b600080546001600160a01b03848116911614156102005760408051602081019091526004546001600160e01b031681526101e5906101de908461030e565b5160701c90565b71ffffffffffffffffffffffffffffffffffff169050610232565b6040517fc1ab6dc100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b92915050565b6001546001600160a01b0316331461024f57600080fd5b60035463ffffffff908116820390610e10908216101580610272575060055460ff165b156103095760405180602001604052808263ffffffff1660025486038161029b5761029b61043b565b046001600160e01b039081169091529051600480547fffffffff00000000000000000000000000000000000000000000000000000000169190921617905560028390556003805463ffffffff191663ffffffff841617905560055460ff1615610309576005805460ff191690555b505050565b604080516020810190915260008152600082158061034b575083516001600160e01b03168361033d8183610451565b9250610349908361047e565b145b6103b5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4669786564506f696e743a3a6d756c3a206f766572666c6f7700000000000000604482015260640160405180910390fd5b60408051602081019091529081529392505050565b600080604083850312156103dd57600080fd5b82356001600160a01b03811681146103f457600080fd5b946020939093013593505050565b6000806040838503121561041557600080fd5b82359150602083013563ffffffff8116811461043057600080fd5b809150509250929050565b634e487b7160e01b600052601260045260246000fd5b600081600019048311821515161561047957634e487b7160e01b600052601160045260246000fd5b500290565b60008261049b57634e487b7160e01b600052601260045260246000fd5b50049056fea26469706673582212205f6b4dad031f2b09ee010b27cf8d81fe590b4af24b73d5b60e7c163c7aeb478764736f6c634300080a0033a2646970667358221220701ca9581e1af984f165ca7011f34f579caa8cef9f23f2d2213936d8e467e3b464736f6c634300080a0033a26469706673582212201bacf5617855e13b83230eea19c90ecb28b0139049748a47fa97384dd9d4c3be64736f6c634300080a003300000000000000000000000040df0c3bbaae5ea3a509d8f2aa9e086776c98e6c

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106100be5760003560e01c8063af5a96f211610076578063e579c2c21161005b578063e579c2c2146101aa578063ea313891146101b2578063f2364e91146101c557600080fd5b8063af5a96f214610184578063c12a00a81461019757600080fd5b80634bc72874116100a75780634bc728741461012d578063574f2ba3146101535780638647fe2e1461016457600080fd5b806309175fa7146100c35780631e3dd18b1461011a575b600080fd5b6100fd6100d1366004610d46565b60036020908152600093845260408085208252928452828420905282529020546001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b6100fd610128366004610d94565b6101e6565b61014061013b366004610dad565b610210565b60405161ffff9091168152602001610111565b600154604051908152602001610111565b610177610172366004610de9565b61025a565b6040516101119190610e13565b610140610192366004610d94565b6102e3565b6002546100fd906001600160a01b031681565b610177610311565b6100fd6101c0366004610d46565b610373565b6101d86101d3366004610e49565b610964565b604051610111929190610e6b565b600181815481106101f657600080fd5b6000918252602090912001546001600160a01b0316905081565b6004602052826000526040600020602052816000526040600020816008811061023857600080fd5b6010918282040191900660020292509250509054906101000a900461ffff1681565b610262610c46565b6001600160a01b03838116600090815260046020908152604080832093861683529290528181208251610100810193849052929091600891908390855b82829054906101000a900461ffff1661ffff168152602001906002019060208260010104928301926001038202915080841161029f57509498975050505050505050565b600081600881106102f357600080fd5b60109182820401919006600202915054906101000a900461ffff1681565b610319610c46565b60408051610100810191829052906000906008908280855b82829054906101000a900461ffff1661ffff16815260200190600201906020826001010492830192600103820291508084116103315790505050505050905090565b60008061037f83610a72565b9050836001600160a01b0316856001600160a01b031614156103cd576040517fbd969eb000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60025460009081906001600160a01b03888116911614806103fb57506002546001600160a01b038781169116145b156104a6576002546001600160a01b03888116911614610427576002546001600160a01b031687610435565b6002546001600160a01b0316865b90925090506001600160a01b0381166104615760405163d92e233d60e01b815260040160405180910390fd5b8461ffff166103e814156104a1576040517f0c3f0a8800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6104f5565b856001600160a01b0316876001600160a01b0316106104c65785876104c9565b86865b90925090506001600160a01b0382166104f55760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b0382811660009081526003602090815260408083208585168452825280832061ffff8a1684529091529020541615610560576040517f3d77e89100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60025460009081906001600160a01b038581169116146105a15760405161058960208201610c65565b601f1982820381018352601f909101166040526105c4565b6040516105b060208201610c72565b601f1982820381018352601f909101166040525b6002546040516bffffffffffffffffffffffff19606088811b8216602084015287811b821660348401527fffff00000000000000000000000000000000000000000000000000000000000060f08d901b1660488401529290921b909116604a820152909150600090605e01604051602081830303815290604052805190602001209050808251602084016000f592508260036000876001600160a01b03166001600160a01b031681526020019081526020016000206000866001600160a01b03166001600160a01b0316815260200190815260200160002060008a61ffff1661ffff16815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b031602179055508260036000866001600160a01b03166001600160a01b031681526020019081526020016000206000876001600160a01b03166001600160a01b0316815260200190815260200160002060008a61ffff1661ffff16815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b0316021790555061076a858588610b0c565b6001805480820182556000919091527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf60180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0385811691909117909155600254811690861614610875576002546040517fb1ffa5820000000000000000000000000000000000000000000000000000000081526001600160a01b038781166004830152868116602483015261ffff8b16604483015291821660648201529084169063b1ffa58290608401600060405180830381600087803b15801561085857600080fd5b505af115801561086c573d6000803e3d6000fd5b505050506108fc565b6040517f7ebef5290000000000000000000000000000000000000000000000000000000081526001600160a01b038681166004830152858116602483015261ffff8a166044830152841690637ebef52990606401600060405180830381600087803b1580156108e357600080fd5b505af11580156108f7573d6000803e3d6000fd5b505050505b600154604080516001600160a01b03868116825261ffff8c1660208301529181019290925280861691908716907f510cf15a092d0302f720eeedd34384cb979a59f85143c19f100768c260bc3f5f9060600160405180910390a3509098975050505050505050565b606060008361097260015490565b61097c9190610ed2565b83111561099a578361098d60015490565b6109979190610ed2565b92505b8267ffffffffffffffff8111156109b3576109b3610ee9565b6040519080825280602002602001820160405280156109dc578160200160208202803683370190505b50915060005b83811015610a5e5760016109f68287610eff565b81548110610a0657610a06610f17565b9060005260206000200160009054906101000a90046001600160a01b0316838281518110610a3657610a36610f17565b6001600160a01b0390921660209283029190910190910152610a5781610f2d565b90506109e2565b50610a698385610eff565b90509250929050565b6000805b60088161ffff161015610ad95760008161ffff1660088110610a9a57610a9a610f17565b601091828204019190066002029054906101000a900461ffff1661ffff168361ffff161415610ac95792915050565b610ad281610f48565b9050610a76565b506040517fcd3cb2bb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0383811660009081526004602090815260408083209386168352929052818120825161010081019384905291926008908285855b82829054906101000a900461ffff1661ffff1681526020019060020190602082600101049283019260010382029150808411610b475790505050505050905060008261ffff1660088110610b9d57610b9d610f17565b601091828204019190066002029054906101000a900461ffff16818361ffff1660088110610bcd57610bcd610f17565b61ffff909216602092830291909101526001600160a01b0380861660009081526004835260408082209287168252919092529020610c0d90826008610c7f565b506001600160a01b038084166000908152600460209081526040808320938816835292905220610c3f90826008610c7f565b5050505050565b6040518061010001604052806008906020820280368337509192915050565b61256d80610f6b83390190565b61283a806134d883390190565b600183019183908215610d055791602002820160005b83821115610cd557835183826101000a81548161ffff021916908361ffff1602179055509260200192600201602081600101049283019260010302610c95565b8015610d035782816101000a81549061ffff0219169055600201602081600101049283019260010302610cd5565b505b50610d11929150610d15565b5090565b5b80821115610d115760008155600101610d16565b80356001600160a01b0381168114610d4157600080fd5b919050565b600080600060608486031215610d5b57600080fd5b610d6484610d2a565b9250610d7260208501610d2a565b9150604084013561ffff81168114610d8957600080fd5b809150509250925092565b600060208284031215610da657600080fd5b5035919050565b600080600060608486031215610dc257600080fd5b610dcb84610d2a565b9250610dd960208501610d2a565b9150604084013590509250925092565b60008060408385031215610dfc57600080fd5b610e0583610d2a565b9150610a6960208401610d2a565b6101008101818360005b6008811015610e4057815161ffff16835260209283019290910190600101610e1d565b50505092915050565b60008060408385031215610e5c57600080fd5b50508035926020909101359150565b604080825283519082018190526000906020906060840190828701845b82811015610ead5781516001600160a01b031684529284019290840190600101610e88565b50505092019290925292915050565b634e487b7160e01b600052601160045260246000fd5b600082821015610ee457610ee4610ebc565b500390565b634e487b7160e01b600052604160045260246000fd5b60008219821115610f1257610f12610ebc565b500190565b634e487b7160e01b600052603260045260246000fd5b6000600019821415610f4157610f41610ebc565b5060010190565b600061ffff80831681811415610f6057610f60610ebc565b600101939250505056fe60a0604052600160005534801561001557600080fd5b503360805260805161252a610043600039600081816103680152818161113301526113e2015261252a6000f3fe608060405234801561001057600080fd5b50600436106101825760003560e01c8063bc25cf77116100d8578063d6f124f01161008c578063f5298aca11610066578063f5298aca146103e0578063f6c67d8d14610408578063fff6cae91461041b57600080fd5b8063d6f124f01461039d578063ddca3f43146103a5578063e680ea2c146103cd57600080fd5b8063c1be6677116100bd578063c1be6677146102fa578063c45a015514610363578063d21220a71461038a57600080fd5b8063bc25cf77146102d4578063c12a00a8146102e757600080fd5b80632f7256381161013a5780636d9a640a116101145780636d9a640a1461029957806382e6a1c6146102ae578063b1ffa582146102c157600080fd5b80632f7256381461026057806340c10f19146102735780635247ab051461028657600080fd5b80630eb290661161016b5780630eb29066146101e957806318160ddd146102005780631f9d4db21461020957600080fd5b80630902f1ac146101875780630dfe1681146101be575b600080fd5b600754604080516001600160701b038084168252600160701b90930490921660208301526000908201526060015b60405180910390f35b6001546101d1906001600160a01b031681565b6040516001600160a01b0390911681526020016101b5565b6101f260045481565b6040519081526020016101b5565b6101f260035481565b61024861021736600461218e565b6001600160a01b0391909116600090815260096020908152604080832093835292905220546001600160801b031690565b6040516001600160801b0390911681526020016101b5565b6101f261026e3660046121ba565b610423565b6101f261028136600461218e565b61063f565b6101f261029436600461218e565b610a40565b6102ac6102a73660046121ec565b610bd3565b005b6101d16102bc36600461223a565b6110f2565b6102ac6102cf366004612257565b6113d7565b6102ac6102e23660046122ba565b6114b6565b6005546101d1906001600160a01b031681565b61033e61030836600461218e565b60096020908152600092835260408084209091529082529020805460018201546002909201546001600160801b03909116919083565b604080516001600160801b0390941684526020840192909252908201526060016101b5565b6101d17f000000000000000000000000000000000000000000000000000000000000000081565b6002546101d1906001600160a01b031681565b6102ac6115e7565b6002546103ba90600160a01b900461ffff1681565b60405161ffff90911681526020016101b5565b6101f26103db36600461218e565b61178b565b6103f36103ee3660046122d7565b6117db565b604080519283526020830191909152016101b5565b6006546101d1906001600160a01b031681565b6102ac611c8d565b600154600654604080517fd21220a700000000000000000000000000000000000000000000000000000000815290516000936001600160a01b0390811693169163d21220a79160048083019260209291908290030181865afa15801561048d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104b1919061230c565b6001600160a01b0316141561057e576006546001546002546001600160a01b0392831692633ddac9539216906103e890600160a01b900461ffff166104f68a8a61233f565b6105009190612357565b61050a9190612376565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa158015610553573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105779190612398565b9050610637565b6006546002546001600160a01b0391821691633ddac95391908116906103e890600160a01b900461ffff166105b3888861233f565b6105bd9190612357565b6105c79190612376565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa158015610610573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106349190612398565b90505b949350505050565b600080546001146106845760405162461bcd60e51b815260206004820152600a6024820152695245454e5452414e435960b01b60448201526064015b60405180910390fd5b600260009081556001600160a01b0384168152600960209081526040808320858452909152902054839083906001600160801b0316156107415760006106cd8383600854611db7565b9050801561073b576001600160a01b03831660009081526009602090815260408083208584529091528120600101805483929061070b90849061233f565b90915550506008546001600160a01b03841660009081526009602090815260408083208684529091529020600201555b5061076c565b6008546001600160a01b03831660009081526009602090815260408083208584529091529020600201555b60075460009081906001600160701b0380821691600160701b9004166001546040516370a0823160e01b81523060048201529294509092506000916001600160a01b03909116906370a0823190602401602060405180830381865afa1580156107d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107fd9190612398565b6002546040516370a0823160e01b81523060048201529192506000916001600160a01b03909116906370a0823190602401602060405180830381865afa15801561084b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061086f9190612398565b905060006108866001600160701b038616846123b1565b9050600061089d6001600160701b038616846123b1565b600354909150600090806108d7576103e86108c06108bb8587612357565b611e39565b6108ca91906123b1565b6103e86003559150610926565b610923886001600160701b0316600354866108f29190612357565b6108fc9190612376565b886001600160701b0316600354866109149190612357565b61091e9190612376565b611ea9565b91505b8161095d576040517fd226f9d400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038d1660009081526009602090815260408083208f8452909152812080548492906109999084906001600160801b03166123c8565b92506101000a8154816001600160801b0302191690836001600160801b03160217905550816003546109cb919061233f565b6003556109d88686611ec1565b806109e5576109e5611f84565b60408051858152602081018590526001600160a01b038f16917f4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f910160405180910390a25098505050505050505b5050600160005592915050565b60008054600114610a805760405162461bcd60e51b815260206004820152600a6024820152695245454e5452414e435960b01b604482015260640161067b565b60026000908155338082526009602090815260408084208685529091529091205483906001600160801b031615610b34576000610ac08383600854611db7565b90508015610b2e576001600160a01b038316600090815260096020908152604080832085845290915281206001018054839290610afe90849061233f565b90915550506008546001600160a01b03841660009081526009602090815260408083208684529091529020600201555b50610b5f565b6008546001600160a01b03831660009081526009602090815260408083208584529091529020600201555b33600090815260096020908152604080832087845290915290206001015492508215610a3357336000908152600960209081526040808320878452909152812060010181905560048054859290610bb79084906123b1565b9091555050600554610a33906001600160a01b03168685611fb7565b600054600114610c125760405162461bcd60e51b815260206004820152600a6024820152695245454e5452414e435960b01b604482015260640161067b565b600260005582158015610c23575081155b15610c5a576040517f42301c2300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6007546001600160701b0380821691600160701b9004168185101580610c895750806001600160701b03168410155b15610ca75760405163bb55fd2760e01b815260040160405180910390fd5b60015460025460009182916001600160a01b0391821691908116908716821480610ce25750806001600160a01b0316876001600160a01b0316145b15610d19576040517f1e4ec46b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8815610d2a57610d2a82888b611fb7565b8715610d3b57610d3b81888a611fb7565b6040516370a0823160e01b81523060048201526001600160a01b038316906370a0823190602401602060405180830381865afa158015610d7f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610da39190612398565b6040516370a0823160e01b81523060048201529094506001600160a01b038216906370a0823190602401602060405180830381865afa158015610dea573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e0e9190612398565b92505050600087856001600160701b0316610e2991906123b1565b8311610e36576000610e53565b610e49886001600160701b0387166123b1565b610e5390846123b1565b90506000610e6a886001600160701b0387166123b1565b8311610e77576000610e94565b610e8a886001600160701b0387166123b1565b610e9490846123b1565b905081158015610ea2575080155b15610ed9576040517f098fb56100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408051838152602081018390529081018a9052606081018990526001600160a01b0388169033907fd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d8229060800160405180910390a36000610f3c8a848b85610423565b90506103e8811015610f7a576040517ff570cd7700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600480546005546040516370a0823160e01b8152309381019390935283926001600160a01b03909116906370a0823190602401602060405180830381865afa158015610fca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fee9190612398565b610ff891906123b1565b1015611030576040517f025dbdd400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6110466001600160701b03808816908916612357565b6110508587612357565b1015611088576040517fa932492f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6110928585611ec1565b60006127106110a383612134612357565b6110ad9190612376565b905060006110bb82846123b1565b90506110c682612126565b6005546110df906001600160a01b031661dead83611fb7565b5050600160005550505050505050505050565b604080518082019091526001546001600160a01b039081168252600254166020820152600090815b60028110156113d0576005546000906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116916309175fa7911685856002811061116e5761116e6123f3565b60200201516040516001600160e01b031960e085901b1681526001600160a01b03928316600482015291166024820152600a6044820152606401602060405180830381865afa1580156111c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111e9919061230c565b90506001600160a01b0381166111ff57506113c0565b6000819050806001600160a01b031663f6c67d8d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611242573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611266919061230c565b6001600160a01b031663fcfedfb16040518163ffffffff1660e01b8152600401602060405180830381865afa1580156112a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112c79190612409565b156112d35750506113c0565b6000816001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa158015611313573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611337919061242b565b50509050866001600160701b0316816001600160701b0316106113bc57816001600160a01b031663f6c67d8d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611392573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113b6919061230c565b95508096505b5050505b6113c981612476565b905061111a565b5050919050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611439576040517f015551dc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180546001600160a01b0395861673ffffffffffffffffffffffffffffffffffffffff19918216179091556002805461ffff909416600160a01b027fffffffffffffffffffff00000000000000000000000000000000000000000000909416948616949094179290921790925560058054929093169116179055565b6000546001146114f55760405162461bcd60e51b815260206004820152600a6024820152695245454e5452414e435960b01b604482015260640161067b565b6002600081905560015490546007546040516370a0823160e01b81523060048201526001600160a01b03938416939092169161159591849186916001600160701b03169083906370a08231906024015b602060405180830381865afa158015611562573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115869190612398565b61159091906123b1565b611fb7565b6007546040516370a0823160e01b81523060048201526115dd9183918691600160701b90046001600160701b0316906001600160a01b038416906370a0823190602401611545565b5050600160005550565b60065460009081906001600160a01b0316156116de57600660009054906101000a90046001600160a01b03166001600160a01b031663a8aa1b316040518163ffffffff1660e01b8152600401602060405180830381865afa158015611650573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611674919061230c565b9150816001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa1580156116b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116d8919061242b565b50909150505b60006116e9826110f2565b90506001600160a01b03811661171257604051639989e18760e01b815260040160405180910390fd5b6006546001600160a01b038281169116141561175a576040517febd9054000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6006805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03929092169190911790555050565b6008546000908161179d858584611db7565b6001600160a01b03861660009081526009602090815260408083208884529091529020600101549091506117d290829061233f565b95945050505050565b60008060005460011461181d5760405162461bcd60e51b815260206004820152600a6024820152695245454e5452414e435960b01b604482015260640161067b565b60026000908155338082526009602090815260408084208885529091529091205485906001600160801b0316156118d157600061185d8383600854611db7565b905080156118cb576001600160a01b03831660009081526009602090815260408083208584529091528120600101805483929061189b90849061233f565b90915550506008546001600160a01b03841660009081526009602090815260408083208684529091529020600201555b506118fc565b6008546001600160a01b03831660009081526009602090815260408083208584529091529020600201555b6001546002546040516370a0823160e01b81523060048201526001600160a01b03928316929091169060009083906370a0823190602401602060405180830381865afa158015611950573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119749190612398565b6040516370a0823160e01b81523060048201529091506000906001600160a01b038416906370a0823190602401602060405180830381865afa1580156119be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119e29190612398565b3360009081526009602090815260408083208e84529091529020549091506001600160801b0316891115611a295760405163bb55fd2760e01b815260040160405180910390fd5b3360009081526009602090815260408083208d8452909152812080548b9290611a5c9084906001600160801b0316612491565b92506101000a8154816001600160801b0302191690836001600160801b031602179055508860001415611aa25760405163bb55fd2760e01b815260040160405180910390fd5b600354600081611ab2858d612357565b611abc9190612376565b9050600082611acb858e612357565b611ad59190612376565b90508b600354611ae591906123b1565b600355811580611af3575080155b15611b2a576040517f749383ad00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611b35878f84611fb7565b611b40868f83611fb7565b6040516370a0823160e01b81523060048201526001600160a01b038816906370a0823190602401602060405180830381865afa158015611b84573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ba89190612398565b6040516370a0823160e01b81523060048201529095506001600160a01b038716906370a0823190602401602060405180830381865afa158015611bef573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c139190612398565b9350611c1f8585611ec1565b8d6001600160a01b0316336001600160a01b03167fdccd412f0b1252819cb1fd330b93224ca42612892bb3f4f789976e6d819364968484604051611c6d929190918252602082015260400190565b60405180910390a36001600055909d909c509a5050505050505050505050565b600054600114611ccc5760405162461bcd60e51b815260206004820152600a6024820152695245454e5452414e435960b01b604482015260640161067b565b60026000556001546040516370a0823160e01b8152306004820152611db0916001600160a01b0316906370a0823190602401602060405180830381865afa158015611d1b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d3f9190612398565b6002546040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa158015611d87573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dab9190612398565b611ec1565b6001600055565b6001600160a01b03831660009081526009602090815260408083208584529091528120600201548190611dea90846123b1565b6001600160a01b0386166000908152600960209081526040808320888452909152902054909150670de0b6b3a764000090611e2f9083906001600160801b0316612357565b6117d29190612376565b60006003821115611e9a5750806000611e53600283612376565b611e5e90600161233f565b90505b81811015611e9457905080600281611e798186612376565b611e83919061233f565b611e8d9190612376565b9050611e61565b50919050565b8115611ea4575060015b919050565b6000818310611eb85781611eba565b825b9392505050565b6001600160701b03821180611edc57506001600160701b0381115b15611f13576040517f89560ca100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600780546001600160701b03838116600160701b9081026001600160e01b0319909316868316179290921792839055604080518483168152929093041660208201527f1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1910160405180910390a15050565b611f8c6115e7565b6006546001600160a01b0316611fb557604051639989e18760e01b815260040160405180910390fd5b565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052915160009283929087169161204191906124b9565b6000604051808303816000865af19150503d806000811461207e576040519150601f19603f3d011682016040523d82523d6000602084013e612083565b606091505b50915091508180156120ad5750805115806120ad5750808060200190518101906120ad9190612409565b61211f5760405162461bcd60e51b815260206004820152602d60248201527f5472616e7366657248656c7065723a3a736166655472616e736665723a20747260448201527f616e73666572206661696c656400000000000000000000000000000000000000606482015260840161067b565b5050505050565b6103e860035461213691906123b1565b612148670de0b6b3a764000083612357565b6121529190612376565b60085461215f919061233f565b60085560045461217090829061233f565b60045550565b6001600160a01b038116811461218b57600080fd5b50565b600080604083850312156121a157600080fd5b82356121ac81612176565b946020939093013593505050565b600080600080608085870312156121d057600080fd5b5050823594602084013594506040840135936060013592509050565b60008060006060848603121561220157600080fd5b8335925060208401359150604084013561221a81612176565b809150509250925092565b6001600160701b038116811461218b57600080fd5b60006020828403121561224c57600080fd5b8135611eba81612225565b6000806000806080858703121561226d57600080fd5b843561227881612176565b9350602085013561228881612176565b9250604085013561ffff8116811461229f57600080fd5b915060608501356122af81612176565b939692955090935050565b6000602082840312156122cc57600080fd5b8135611eba81612176565b6000806000606084860312156122ec57600080fd5b83356122f781612176565b95602085013595506040909401359392505050565b60006020828403121561231e57600080fd5b8151611eba81612176565b634e487b7160e01b600052601160045260246000fd5b6000821982111561235257612352612329565b500190565b600081600019048311821515161561237157612371612329565b500290565b60008261239357634e487b7160e01b600052601260045260246000fd5b500490565b6000602082840312156123aa57600080fd5b5051919050565b6000828210156123c3576123c3612329565b500390565b60006001600160801b038083168185168083038211156123ea576123ea612329565b01949350505050565b634e487b7160e01b600052603260045260246000fd5b60006020828403121561241b57600080fd5b81518015158114611eba57600080fd5b60008060006060848603121561244057600080fd5b835161244b81612225565b602085015190935061245c81612225565b604085015190925063ffffffff8116811461221a57600080fd5b600060001982141561248a5761248a612329565b5060010190565b60006001600160801b03838116908316818110156124b1576124b1612329565b039392505050565b6000825160005b818110156124da57602081860181015185830152016124c0565b818111156124e9576000828501525b50919091019291505056fea2646970667358221220ed2b296666058c99a67fe8c1e2c2ec013d6cb863394d87553af151363540861f64736f6c634300080a003360a0604052600160005534801561001557600080fd5b50336080526080516127fe61003c6000396000818161034e015261103501526127fe6000f3fe60806040523480156200001157600080fd5b50600436106200016c5760003560e01c80637ebef52911620000dd578063ddca3f43116200008b578063f5298aca116200006e578063f5298aca14620003c5578063f6c67d8d14620003f2578063fff6cae9146200040657600080fd5b8063ddca3f431462000384578063e680ea2c14620003ae57600080fd5b8063c1be667711620000c0578063c1be667714620002db578063c45a01551462000348578063d21220a7146200037057600080fd5b80637ebef52914620002ad578063bc25cf7714620002c457600080fd5b80631f9d4db2116200013b5780635247ab05116200011e5780635247ab0514620002735780635a3d5493146200028a5780636d9a640a146200029457600080fd5b80631f9d4db2146200020157806340c10f19146200025c57600080fd5b80630902f1ac14620001715780630dfe168114620001b15780630eb2906614620001de57806318160ddd14620001f7575b600080fd5b600754604080516001600160701b038084168252600160701b8404166020820152600160e01b90920463ffffffff16908201526060015b60405180910390f35b600154620001c5906001600160a01b031681565b6040516001600160a01b039091168152602001620001a8565b620001e860055481565b604051908152602001620001a8565b620001e860035481565b620002436200021236600462001f12565b6001600160a01b0391909116600090815260096020908152604080832093835292905220546001600160801b031690565b6040516001600160801b039091168152602001620001a8565b620001e86200026d36600462001f12565b62000410565b620001e86200028436600462001f12565b6200087e565b620001e860045481565b620002ab620002a536600462001f3f565b62000a1f565b005b620002ab620002be36600462001f77565b6200102a565b620002ab620002d536600462001fcb565b620010f9565b62000322620002ec36600462001f12565b60096020908152600092835260408084209091529082529020805460018201546002909201546001600160801b03909116919083565b604080516001600160801b039094168452602084019290925290820152606001620001a8565b620001c57f000000000000000000000000000000000000000000000000000000000000000081565b600254620001c5906001600160a01b031681565b6002546200039a90600160a01b900461ffff1681565b60405161ffff9091168152602001620001a8565b620001e8620003bf36600462001f12565b62001283565b620003dc620003d636600462001fe9565b620012d7565b60408051928352602083019190915201620001a8565b600654620001c5906001600160a01b031681565b620002ab62001827565b60008054600114620004565760405162461bcd60e51b815260206004820152600a6024820152695245454e5452414e435960b01b60448201526064015b60405180910390fd5b600260009081556001600160a01b0384168152600960209081526040808320858452909152902054839083906001600160801b0316156200051a576000620004a2838360085462001982565b9050801562000513576001600160a01b038316600090815260096020908152604080832085845290915281206001018054839290620004e390849062002035565b90915550506008546001600160a01b03841660009081526009602090815260408083208684529091529020600201555b5062000545565b6008546001600160a01b03831660009081526009602090815260408083208584529091529020600201555b600080620005776007546001600160701b0380821692600160701b83049091169163ffffffff600160e01b9091041690565b506005546001546040516370a0823160e01b815230600482015293955091935060009290916001600160a01b0316906370a0823190602401602060405180830381865afa158015620005cd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620005f3919062002050565b620005ff91906200206a565b6002546040516370a0823160e01b81523060048201529192506000916001600160a01b03909116906370a0823190602401602060405180830381865afa1580156200064e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000674919062002050565b905060006200068d6001600160701b038616846200206a565b90506000620006a66001600160701b038616846200206a565b60035490915060009080620006e8576103e8620006ce620006c8858762002084565b62001a0a565b620006da91906200206a565b6103e8600355915062000741565b6200073e886001600160701b03166003548662000706919062002084565b620007129190620020bc565b886001600160701b0316600354866200072c919062002084565b620007389190620020bc565b62001a88565b91505b8162000779576040517fd226f9d400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038d1660009081526009602090815260408083208f845290915281208054849290620007b79084906001600160801b0316620020d3565b92506101000a8154816001600160801b0302191690836001600160801b0316021790555081600354620007eb919062002035565b600355620007fc86868a8a62001aa2565b806200082357600254600160a01b900461ffff16600a141562000823576200082362001c54565b60408051858152602081018590526001600160a01b038f16917f4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f910160405180910390a25098505050505050505b5050600160005592915050565b60008054600114620008c05760405162461bcd60e51b815260206004820152600a6024820152695245454e5452414e435960b01b60448201526064016200044d565b60026000908155338082526009602090815260408084208685529091529091205483906001600160801b0316156200097b57600062000903838360085462001982565b9050801562000974576001600160a01b0383166000908152600960209081526040808320858452909152812060010180548392906200094490849062002035565b90915550506008546001600160a01b03841660009081526009602090815260408083208684529091529020600201555b50620009a6565b6008546001600160a01b03831660009081526009602090815260408083208584529091529020600201555b33600090815260096020908152604080832087845290915290206001015492508215620008715733600090815260096020908152604080832087845290915281206001018190556005805485929062000a019084906200206a565b909155505060015462000871906001600160a01b0316868562001cf6565b60005460011462000a605760405162461bcd60e51b815260206004820152600a6024820152695245454e5452414e435960b01b60448201526064016200044d565b60026000558215801562000a72575081155b1562000aaa576040517f42301c2300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008062000adc6007546001600160701b0380821692600160701b83049091169163ffffffff600160e01b9091041690565b5091509150816001600160701b03168510158062000b035750806001600160701b03168410155b1562000b225760405163bb55fd2760e01b815260040160405180910390fd5b60015460025460009182916001600160a01b039182169190811690871682148062000b5e5750806001600160a01b0316876001600160a01b0316145b1562000b96576040517f1e4ec46b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b881562000baa5762000baa82888b62001cf6565b871562000bbe5762000bbe81888a62001cf6565b6005546040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa15801562000c06573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000c2c919062002050565b62000c3891906200206a565b6040516370a0823160e01b81523060048201529094506001600160a01b038216906370a0823190602401602060405180830381865afa15801562000c80573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000ca6919062002050565b92506000905062000cc1896001600160701b0388166200206a565b841162000cd057600062000cf1565b62000ce5896001600160701b0388166200206a565b62000cf190856200206a565b9050600062000d0a896001600160701b0388166200206a565b841162000d1957600062000d3a565b62000d2e896001600160701b0388166200206a565b62000d3a90856200206a565b90508115801562000d49575080155b1562000d81576040517f098fb56100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408051838152602081018390529081018b9052606081018a90526001600160a01b0389169033907fd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d8229060800160405180910390a360025460009062000df590600160a01b900461ffff166103e86200206a565b60025462000e0f90600160a01b900461ffff168d62002084565b62000e1b9190620020bc565b60025462000e3790600160a01b900461ffff166103e862002035565b60025462000e5190600160a01b900461ffff168662002084565b62000e5d9190620020bc565b62000e69919062002035565b90506103e881101562000ea8576040517ff570cd7700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b62000eb481876200206a565b955062000ece6001600160701b03808916908a1662002084565b62000eda868862002084565b101562000f13576040517fa932492f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b62000f2186868a8a62001aa2565b600254600160a01b900461ffff16600a141562000fcb57600654600480546007546040517fcebab53d00000000000000000000000000000000000000000000000000000000815292830191909152600160e01b900463ffffffff1660248201526001600160a01b039091169063cebab53d90604401600060405180830381600087803b15801562000fb157600080fd5b505af115801562000fc6573d6000803e3d6000fd5b505050505b600061271062000fde8361213462002084565b62000fea9190620020bc565b9050600062000ffa82846200206a565b9050620010078262001e5a565b620010168661dead8362001cf6565b505060016000555050505050505050505050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146200108d576040517f015551dc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180546001600160a01b0394851673ffffffffffffffffffffffffffffffffffffffff199091161790556002805461ffff909216600160a01b027fffffffffffffffffffff000000000000000000000000000000000000000000009092169290931691909117179055565b6000546001146200113a5760405162461bcd60e51b815260206004820152600a6024820152695245454e5452414e435960b01b60448201526064016200044d565b6002600081905560015490546005546007546040516370a0823160e01b81523060048201526001600160a01b039485169490931692620011f192859287926001600160701b039091169084906370a0823190602401602060405180830381865afa158015620011ad573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620011d3919062002050565b620011df91906200206a565b620011eb91906200206a565b62001cf6565b6007546040516370a0823160e01b8152306004820152620012799183918691600160701b90046001600160701b0316906001600160a01b038416906370a0823190602401602060405180830381865afa15801562001253573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620011df919062002050565b5050600160005550565b600854600090816200129785858462001982565b6001600160a01b0386166000908152600960209081526040808320888452909152902060010154909150620012ce90829062002035565b95945050505050565b6000806000546001146200131b5760405162461bcd60e51b815260206004820152600a6024820152695245454e5452414e435960b01b60448201526064016200044d565b60026000908155338082526009602090815260408084208885529091529091205485906001600160801b031615620013d65760006200135e838360085462001982565b90508015620013cf576001600160a01b0383166000908152600960209081526040808320858452909152812060010180548392906200139f90849062002035565b90915550506008546001600160a01b03841660009081526009602090815260408083208684529091529020600201555b5062001401565b6008546001600160a01b03831660009081526009602090815260408083208584529091529020600201555b600080620014336007546001600160701b0380821692600160701b83049091169163ffffffff600160e01b9091041690565b506005546001546040516370a0823160e01b815230600482015293955091935060009290916001600160a01b0316906370a0823190602401602060405180830381865afa15801562001489573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620014af919062002050565b620014bb91906200206a565b6002546040516370a0823160e01b81523060048201529192506000916001600160a01b03909116906370a0823190602401602060405180830381865afa1580156200150a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001530919062002050565b3360009081526009602090815260408083208e84529091529020549091506001600160801b0316891115620015785760405163bb55fd2760e01b815260040160405180910390fd5b3360009081526009602090815260408083208d8452909152812080548b9290620015ad9084906001600160801b031662002101565b92506101000a8154816001600160801b0302191690836001600160801b031602179055508860001415620015f45760405163bb55fd2760e01b815260040160405180910390fd5b60035460008162001606858d62002084565b620016129190620020bc565b905060008262001623858e62002084565b6200162f9190620020bc565b90508b6003546200164191906200206a565b60035581158062001650575080155b1562001688576040517f749383ad00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600154620016a1906001600160a01b03168f8462001cf6565b600254620016ba906001600160a01b03168f8362001cf6565b6005546001546040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa15801562001706573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200172c919062002050565b6200173891906200206a565b6002546040516370a0823160e01b81523060048201529196506001600160a01b0316906370a0823190602401602060405180830381865afa15801562001782573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620017a8919062002050565b9350620017b88585898962001aa2565b8d6001600160a01b0316336001600160a01b03167fdccd412f0b1252819cb1fd330b93224ca42612892bb3f4f789976e6d81936496848460405162001807929190918252602082015260400190565b60405180910390a36001600055909d909c509a5050505050505050505050565b600054600114620018685760405162461bcd60e51b815260206004820152600a6024820152695245454e5452414e435960b01b60448201526064016200044d565b60026000556005546001546040516370a0823160e01b81523060048201526200197b92916001600160a01b0316906370a0823190602401602060405180830381865afa158015620018bd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620018e3919062002050565b620018ef91906200206a565b6002546040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa15801562001938573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200195e919062002050565b6007546001600160701b0380821691600160701b90041662001aa2565b6001600055565b6001600160a01b03831660009081526009602090815260408083208584529091528120600201548190620019b790846200206a565b6001600160a01b0386166000908152600960209081526040808320888452909152902054909150670de0b6b3a764000090620019fe9083906001600160801b031662002084565b620012ce9190620020bc565b6000600382111562001a78575080600062001a27600283620020bc565b62001a3490600162002035565b90505b8181101562001a725790508060028162001a528186620020bc565b62001a5e919062002035565b62001a6a9190620020bc565b905062001a37565b50919050565b811562001a83575060015b919050565b600081831062001a99578162001a9b565b825b9392505050565b6001600160701b0384118062001abe57506001600160701b0383115b1562001af6576040517f89560ca100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600062001b09640100000000426200212c565b60075490915063ffffffff600160e01b909104811682039081161580159062001b3a57506001600160701b03841615155b801562001b4f57506001600160701b03831615155b1562001ba4578063ffffffff1662001b7c8462001b6c8762001eb4565b6001600160e01b03169062001ed5565b6001600160e01b031662001b91919062002084565b60045462001ba0919062002035565b6004555b6007805463ffffffff8416600160e01b026001600160e01b036001600160701b03898116600160701b9081027fffffffff000000000000000000000000000000000000000000000000000000009095168c83161794909417918216831794859055604080519382169282169290921783529290930490911660208201527f1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1910160405180910390a1505050505050565b6002546004546007546040516001600160a01b0390931692600160e01b90910463ffffffff169062001c869062001eec565b6001600160a01b039093168352602083019190915263ffffffff166040820152606001604051809103906000f08015801562001cc6573d6000803e3d6000fd5b506006805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b03167fa9059cbb00000000000000000000000000000000000000000000000000000000179052915160009283929087169162001d6d919062002143565b6000604051808303816000865af19150503d806000811462001dac576040519150601f19603f3d011682016040523d82523d6000602084013e62001db1565b606091505b509150915081801562001ddf57508051158062001ddf57508080602001905181019062001ddf919062002181565b62001e535760405162461bcd60e51b815260206004820152602d60248201527f5472616e7366657248656c7065723a3a736166655472616e736665723a20747260448201527f616e73666572206661696c65640000000000000000000000000000000000000060648201526084016200044d565b5050505050565b6103e860035462001e6c91906200206a565b62001e80670de0b6b3a76400008362002084565b62001e8c9190620020bc565b60085462001e9b919062002035565b60085560055462001eae90829062002035565b60055550565b600062001ecf600160701b6001600160701b038416620021a5565b92915050565b600062001a9b6001600160701b03831684620021d7565b6105c8806200220183390190565b80356001600160a01b038116811462001a8357600080fd5b6000806040838503121562001f2657600080fd5b62001f318362001efa565b946020939093013593505050565b60008060006060848603121562001f5557600080fd5b833592506020840135915062001f6e6040850162001efa565b90509250925092565b60008060006060848603121562001f8d57600080fd5b62001f988462001efa565b925062001fa86020850162001efa565b9150604084013561ffff8116811462001fc057600080fd5b809150509250925092565b60006020828403121562001fde57600080fd5b62001a9b8262001efa565b60008060006060848603121562001fff57600080fd5b6200200a8462001efa565b95602085013595506040909401359392505050565b634e487b7160e01b600052601160045260246000fd5b600082198211156200204b576200204b6200201f565b500190565b6000602082840312156200206357600080fd5b5051919050565b6000828210156200207f576200207f6200201f565b500390565b6000816000190483118215151615620020a157620020a16200201f565b500290565b634e487b7160e01b600052601260045260246000fd5b600082620020ce57620020ce620020a6565b500490565b60006001600160801b03808316818516808303821115620020f857620020f86200201f565b01949350505050565b60006001600160801b03838116908316818110156200212457620021246200201f565b039392505050565b6000826200213e576200213e620020a6565b500690565b6000825160005b818110156200216657602081860181015185830152016200214a565b8181111562002176576000828501525b509190910192915050565b6000602082840312156200219457600080fd5b8151801515811462001a9b57600080fd5b60006001600160e01b0380831681851681830481118215151615620021ce57620021ce6200201f565b02949350505050565b60006001600160e01b0380841680620021f457620021f4620020a6565b9216919091049291505056fe608060405234801561001057600080fd5b506040516105c83803806105c883398101604081905261002f9161008b565b600080546001600160a01b039094166001600160a01b031994851617905560018054909316331783556002919091556003805463ffffffff90921663ffffffff199092169190911790556005805460ff191690911790556100e3565b6000806000606084860312156100a057600080fd5b83516001600160a01b03811681146100b757600080fd5b60208501516040860151919450925063ffffffff811681146100d857600080fd5b809150509250925092565b6104d6806100f26000396000f3fe608060405234801561001057600080fd5b50600436106100a35760003560e01c8063b4d1d79511610076578063cebab53d1161005b578063cebab53d1461015b578063d21220a714610170578063fcfedfb11461018357600080fd5b8063b4d1d7951461012d578063c5700a021461013657600080fd5b80633ddac953146100a85780635a3d5493146100ce5780635e6aaf2c146100d7578063a8aa1b3114610102575b600080fd5b6100bb6100b63660046103ca565b6101a0565b6040519081526020015b60405180910390f35b6100bb60025481565b6004546100ea906001600160e01b031681565b6040516001600160e01b0390911681526020016100c5565b600154610115906001600160a01b031681565b6040516001600160a01b0390911681526020016100c5565b6100bb610e1081565b6003546101469063ffffffff1681565b60405163ffffffff90911681526020016100c5565b61016e610169366004610402565b610238565b005b600054610115906001600160a01b031681565b6005546101909060ff1681565b60405190151581526020016100c5565b600080546001600160a01b03848116911614156102005760408051602081019091526004546001600160e01b031681526101e5906101de908461030e565b5160701c90565b71ffffffffffffffffffffffffffffffffffff169050610232565b6040517fc1ab6dc100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b92915050565b6001546001600160a01b0316331461024f57600080fd5b60035463ffffffff908116820390610e10908216101580610272575060055460ff165b156103095760405180602001604052808263ffffffff1660025486038161029b5761029b61043b565b046001600160e01b039081169091529051600480547fffffffff00000000000000000000000000000000000000000000000000000000169190921617905560028390556003805463ffffffff191663ffffffff841617905560055460ff1615610309576005805460ff191690555b505050565b604080516020810190915260008152600082158061034b575083516001600160e01b03168361033d8183610451565b9250610349908361047e565b145b6103b5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4669786564506f696e743a3a6d756c3a206f766572666c6f7700000000000000604482015260640160405180910390fd5b60408051602081019091529081529392505050565b600080604083850312156103dd57600080fd5b82356001600160a01b03811681146103f457600080fd5b946020939093013593505050565b6000806040838503121561041557600080fd5b82359150602083013563ffffffff8116811461043057600080fd5b809150509250929050565b634e487b7160e01b600052601260045260246000fd5b600081600019048311821515161561047957634e487b7160e01b600052601160045260246000fd5b500290565b60008261049b57634e487b7160e01b600052601260045260246000fd5b50049056fea26469706673582212205f6b4dad031f2b09ee010b27cf8d81fe590b4af24b73d5b60e7c163c7aeb478764736f6c634300080a0033a2646970667358221220701ca9581e1af984f165ca7011f34f579caa8cef9f23f2d2213936d8e467e3b464736f6c634300080a0033a26469706673582212201bacf5617855e13b83230eea19c90ecb28b0139049748a47fa97384dd9d4c3be64736f6c634300080a0033

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

00000000000000000000000040df0c3bbaae5ea3a509d8f2aa9e086776c98e6c

-----Decoded View---------------
Arg [0] : _antfarmToken (address): 0x40DF0C3BBAAE5Ea3A509d8F2aa9E086776C98E6c

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 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  ]

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.