ETH Price: $2,346.53 (+1.26%)

Contract

0x52A8845DF664D76C69d2EEa607CD793565aF42B8

Overview

ETH Balance

0 ETH

ETH Value

$0.00

Token Holdings

More Info

Private Name Tags

Transaction Hash
Block
From
To
Set Fee To Sette...70771892022-02-28 3:16:411435 days ago1646018201IN
0x52A8845D...565aF42B8
0 ETH0.000214091826 ETH0.46301937

Latest 7 internal transactions

Parent Transaction Hash Block From To
70364322022-02-27 14:45:491436 days ago1645973149
0x52A8845D...565aF42B8
0 ETH
70364322022-02-27 14:45:491436 days ago1645973149
0x52A8845D...565aF42B8
0 ETH
70364322022-02-27 14:45:491436 days ago1645973149
0x52A8845D...565aF42B8
0 ETH
70364322022-02-27 14:45:491436 days ago1645973149
0x52A8845D...565aF42B8
0 ETH
70364322022-02-27 14:45:491436 days ago1645973149
0x52A8845D...565aF42B8
 Contract Creation0 ETH
70364322022-02-27 14:45:491436 days ago1645973149
0x52A8845D...565aF42B8
0 ETH
70364322022-02-27 14:45:491436 days ago1645973149
0x52A8845D...565aF42B8
0 ETH

Cross-Chain Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
AmmFactory

Compiler Version
v0.8.2+commit.661d1103

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;

import "./Amm.sol";
import "./interfaces/IAmmFactory.sol";
import "./interfaces/IPriceOracle.sol";

contract AmmFactory is IAmmFactory {
    address public immutable override upperFactory; // PairFactory
    address public immutable override config;
    address public override feeTo;
    address public override feeToSetter;

    // baseToken => quoteToken => amm
    mapping(address => mapping(address => address)) public override getAmm;

    modifier onlyUpper() {
        require(msg.sender == upperFactory, "AmmFactory: FORBIDDEN");
        _;
    }

    constructor(
        address upperFactory_,
        address config_,
        address feeToSetter_
    ) {
        require(config_ != address(0) && feeToSetter_ != address(0), "AmmFactory: ZERO_ADDRESS");
        upperFactory = upperFactory_;
        config = config_;
        feeToSetter = feeToSetter_;
    }

    function createAmm(address baseToken, address quoteToken) external override onlyUpper returns (address amm) {
        require(baseToken != quoteToken, "AmmFactory.createAmm: IDENTICAL_ADDRESSES");
        require(baseToken != address(0) && quoteToken != address(0), "AmmFactory.createAmm: ZERO_ADDRESS");
        require(getAmm[baseToken][quoteToken] == address(0), "AmmFactory.createAmm: AMM_EXIST");
        bytes32 salt = keccak256(abi.encodePacked(baseToken, quoteToken));
        bytes memory ammBytecode = type(Amm).creationCode;
        assembly {
            amm := create2(0, add(ammBytecode, 32), mload(ammBytecode), salt)
        }
        getAmm[baseToken][quoteToken] = amm;
        emit AmmCreated(baseToken, quoteToken, amm);
    }

    function initAmm(
        address baseToken,
        address quoteToken,
        address margin
    ) external override onlyUpper {
        address amm = getAmm[baseToken][quoteToken];
        Amm(amm).initialize(baseToken, quoteToken, margin);
        IPriceOracle(IConfig(config).priceOracle()).setupTwap(amm);
    }

    function setFeeTo(address feeTo_) external override {
        require(msg.sender == feeToSetter, "AmmFactory.setFeeTo: FORBIDDEN");
        feeTo = feeTo_;
    }

    function setFeeToSetter(address feeToSetter_) external override {
        require(msg.sender == feeToSetter, "AmmFactory.setFeeToSetter: FORBIDDEN");
        feeToSetter = feeToSetter_;
    }
}

// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;

import "./LiquidityERC20.sol";
import "./interfaces/IAmmFactory.sol";
import "./interfaces/IConfig.sol";
import "./interfaces/IPriceOracle.sol";
import "./interfaces/IMarginFactory.sol";
import "./interfaces/IAmm.sol";
import "./interfaces/IVault.sol";
import "./interfaces/IMargin.sol";
import "./interfaces/IPairFactory.sol";
import "../utils/Reentrant.sol";
import "../libraries/UQ112x112.sol";
import "../libraries/Math.sol";
import "../libraries/FullMath.sol";
import "../libraries/ChainAdapter.sol";

contract Amm is IAmm, LiquidityERC20, Reentrant {
    using UQ112x112 for uint224;

    uint256 public constant override MINIMUM_LIQUIDITY = 10**3;

    address public immutable override factory;
    address public override config;
    address public override baseToken;
    address public override quoteToken;
    address public override margin;

    uint256 public override price0CumulativeLast;
    uint256 public override price1CumulativeLast;

    uint256 public kLast;
    uint256 public override lastPrice;

    bytes4 private constant SELECTOR = bytes4(keccak256(bytes("transfer(address,uint256)")));
    uint112 private baseReserve; // uses single storage slot, accessible via getReserves
    uint112 private quoteReserve; // uses single storage slot, accessible via getReserves
    uint32 private blockTimestampLast;
    uint256 private lastBlockNumber;
    uint256 private rebaseTimestampLast;

    modifier onlyMargin() {
        require(margin == msg.sender, "Amm: ONLY_MARGIN");
        _;
    }

    constructor() {
        factory = msg.sender;
    }

    function initialize(
        address baseToken_,
        address quoteToken_,
        address margin_
    ) external override {
        require(msg.sender == factory, "Amm.initialize: FORBIDDEN"); // sufficient check
        baseToken = baseToken_;
        quoteToken = quoteToken_;
        margin = margin_;
        config = IAmmFactory(factory).config();
    }

    /// @notice add liquidity
    /// @dev  calculate the liquidity according to the real baseReserve.
    function mint(address to)
        external
        override
        nonReentrant
        returns (
            uint256 baseAmount,
            uint256 quoteAmount,
            uint256 liquidity
        )
    {
        (uint112 _baseReserve, uint112 _quoteReserve, ) = getReserves(); // gas savings
        // get real baseReserve
        int256 baseTokenOfNetPosition = IMargin(margin).netPosition();
        require(int256(uint256(_baseReserve)) + baseTokenOfNetPosition <= 2**112, "Amm.mint:NetPosition_VALUE_WRONT");

        int256 realBaseReserveSigned = int256(uint256(_baseReserve)) + baseTokenOfNetPosition;
        uint256 realBaseReserve = uint256(realBaseReserveSigned);

        baseAmount = IERC20(baseToken).balanceOf(address(this));
        require(baseAmount > 0, "Amm.mint: ZERO_BASE_AMOUNT");

        bool feeOn = _mintFee(_baseReserve, _quoteReserve);
        uint256 _totalSupply = totalSupply; // gas savings, must be defined here since totalSupply can update in _mintFee

        if (_totalSupply == 0) {
            (quoteAmount, ) = IPriceOracle(IConfig(config).priceOracle()).quote(baseToken, quoteToken, baseAmount);

            require(quoteAmount > 0, "Amm.mint: INSUFFICIENT_QUOTE_AMOUNT");
            liquidity = Math.sqrt(baseAmount * quoteAmount) - MINIMUM_LIQUIDITY;
            _mint(address(0), MINIMUM_LIQUIDITY); // permanently lock the first MINIMUM_LIQUIDITY tokens
        } else {
            quoteAmount = (baseAmount * _quoteReserve) / _baseReserve;

            // realBaseReserve
            liquidity = (baseAmount * _totalSupply) / realBaseReserve;
        }
        require(liquidity > 0, "Amm.mint: INSUFFICIENT_LIQUIDITY_MINTED");
        _mint(to, liquidity);

        _update(_baseReserve + baseAmount, _quoteReserve + quoteAmount, _baseReserve, _quoteReserve, false);
        if (feeOn) kLast = uint256(baseReserve) * quoteReserve;

        _safeTransfer(baseToken, margin, baseAmount);
        IVault(margin).deposit(msg.sender, baseAmount);

        emit Mint(msg.sender, to, baseAmount, quoteAmount, liquidity);
    }

    /// @notice add liquidity
    /// @dev  calculate the liquidity according to the real baseReserve.
    function burn(address to)
        external
        override
        nonReentrant
        returns (
            uint256 baseAmount,
            uint256 quoteAmount,
            uint256 liquidity
        )
    {
        (uint112 _baseReserve, uint112 _quoteReserve, ) = getReserves(); // gas savings
        liquidity = balanceOf[address(this)];

        // get real baseReserve
        int256 baseTokenOfNetPosition = IMargin(margin).netPosition();
        int256 realBaseReserveSigned = int256(uint256(_baseReserve)) + baseTokenOfNetPosition;
        uint256 realBaseReserve = uint256(realBaseReserveSigned);

        bool feeOn = _mintFee(_baseReserve, _quoteReserve);
        uint256 _totalSupply = totalSupply; // gas savings, must be defined here since totalSupply can update in _mintFee

        baseAmount = (liquidity * realBaseReserve) / _totalSupply; // using balances ensures pro-rata distribution
        // quoteAmount = (liquidity * _quoteReserve) / _totalSupply; // using balances ensures pro-rata distribution
        quoteAmount = (baseAmount * _quoteReserve) / _baseReserve;

        require(baseAmount > 0 && quoteAmount > 0, "Amm.burn: INSUFFICIENT_LIQUIDITY_BURNED");
        _burn(address(this), liquidity);
        _update(_baseReserve - baseAmount, _quoteReserve - quoteAmount, _baseReserve, _quoteReserve, false);
        if (feeOn) kLast = uint256(baseReserve) * quoteReserve;

        IVault(margin).withdraw(msg.sender, to, baseAmount);
        emit Burn(msg.sender, to, baseAmount, quoteAmount, liquidity);
    }

    /// @notice
    function swap(
        address trader,
        address inputToken,
        address outputToken,
        uint256 inputAmount,
        uint256 outputAmount
    ) external override nonReentrant onlyMargin returns (uint256[2] memory amounts) {
        uint256[2] memory reserves;
        (reserves, amounts) = _estimateSwap(inputToken, outputToken, inputAmount, outputAmount);
        //check trade slippage
        _checkTradeSlippage(reserves[0], reserves[1], baseReserve, quoteReserve);
        _update(reserves[0], reserves[1], baseReserve, quoteReserve, false);

        emit Swap(trader, inputToken, outputToken, amounts[0], amounts[1]);
    }

    /// @notice  use in the situation  of forcing closing position
    function forceSwap(
        address trader,
        address inputToken,
        address outputToken,
        uint256 inputAmount,
        uint256 outputAmount
    ) external override nonReentrant onlyMargin {
        require(inputToken == baseToken || inputToken == quoteToken, "Amm.forceSwap: WRONG_INPUT_TOKEN");
        require(outputToken == baseToken || outputToken == quoteToken, "Amm.forceSwap: WRONG_OUTPUT_TOKEN");
        require(inputToken != outputToken, "Amm.forceSwap: SAME_TOKENS");
        (uint112 _baseReserve, uint112 _quoteReserve, ) = getReserves();
        bool feeOn = _mintFee(_baseReserve, _quoteReserve);

        uint256 reserve0;
        uint256 reserve1;
        if (inputToken == baseToken) {
            reserve0 = _baseReserve + inputAmount;
            reserve1 = _quoteReserve - outputAmount;
        } else {
            reserve0 = _baseReserve - outputAmount;
            reserve1 = _quoteReserve + inputAmount;
        }

        _update(reserve0, reserve1, _baseReserve, _quoteReserve, true);
        if (feeOn) kLast = uint256(baseReserve) * quoteReserve;

        emit ForceSwap(trader, inputToken, outputToken, inputAmount, outputAmount);
    }

    /// @notice invoke when price gap is larger than "gap" percent;
    /// @notice gap is in config contract
    function rebase() external override nonReentrant returns (uint256 quoteReserveAfter) {
        require(msg.sender == tx.origin, "Amm.rebase: ONLY_EOA");
        uint256 interval = IConfig(config).rebaseInterval();
        require(block.timestamp - rebaseTimestampLast >= interval, "Amm.rebase: NOT_REACH_NEXT_REBASE_TIME");

        (uint112 _baseReserve, uint112 _quoteReserve, ) = getReserves();
        bool feeOn = _mintFee(_baseReserve, _quoteReserve);

        uint256 quoteReserveFromInternal;
        (uint256 quoteReserveFromExternal, uint8 priceSource) = IPriceOracle(IConfig(config).priceOracle()).quote(
            baseToken,
            quoteToken,
            _baseReserve
        );
        if (priceSource == 0) { // external price use UniswapV3Twap, internal price use ammTwap
            quoteReserveFromInternal = IPriceOracle(IConfig(config).priceOracle()).quoteFromAmmTwap(address(this), _baseReserve);
        } else { // otherwise, use lastPrice as internal price
            quoteReserveFromInternal = lastPrice * _baseReserve / 2**112;
        }

        uint256 gap = IConfig(config).rebasePriceGap();
        require(
            quoteReserveFromExternal * 100 >= quoteReserveFromInternal * (100 + gap) ||
                quoteReserveFromExternal * 100 <= quoteReserveFromInternal * (100 - gap),
            "Amm.rebase: NOT_BEYOND_PRICE_GAP"
        );

        if (quoteReserveFromExternal * 100 >= quoteReserveFromInternal * (100 + gap)) {
            quoteReserveAfter = uint256(_quoteReserve) * (100 + gap) / 100;
        } else {
            quoteReserveAfter = uint256(_quoteReserve) * (100 - gap) / 100;
        }
        rebaseTimestampLast = uint32(block.timestamp % 2**32);
        _update(_baseReserve, quoteReserveAfter, _baseReserve, _quoteReserve, true);
        if (feeOn) kLast = uint256(baseReserve) * quoteReserve;

        emit Rebase(_quoteReserve, quoteReserveAfter, _baseReserve, quoteReserveFromInternal, quoteReserveFromExternal);
    }

    /// notice view method for estimating swap
    function estimateSwap(
        address inputToken,
        address outputToken,
        uint256 inputAmount,
        uint256 outputAmount
    ) external view override returns (uint256[2] memory amounts) {
        (, amounts) = _estimateSwap(inputToken, outputToken, inputAmount, outputAmount);
    }

    function getReserves()
        public
        view
        override
        returns (
            uint112 reserveBase,
            uint112 reserveQuote,
            uint32 blockTimestamp
        )
    {
        reserveBase = baseReserve;
        reserveQuote = quoteReserve;
        blockTimestamp = blockTimestampLast;
    }

    function _checkTradeSlippage(
        uint256 baseReserveNew,
        uint256 quoteReserveNew,
        uint112 baseReserveOld,
        uint112 quoteReserveOld
    ) internal view {
        // check trade slippage for every transaction
        uint256 numerator = quoteReserveNew * baseReserveOld * 100;
        uint256 demominator = baseReserveNew * quoteReserveOld;
        uint256 tradingSlippage = IConfig(config).tradingSlippage();
        require(
            (numerator < (100 + tradingSlippage) * demominator) && (numerator > (100 - tradingSlippage) * demominator),
            "AMM._update: TRADINGSLIPPAGE_TOO_LARGE_THAN_LAST_TRANSACTION"
        );
        require(
            (quoteReserveNew * 100 < ((100 + tradingSlippage) * baseReserveNew * lastPrice) / 2**112) &&
                (quoteReserveNew * 100 > ((100 - tradingSlippage) * baseReserveNew * lastPrice) / 2**112),
            "AMM._update: TRADINGSLIPPAGE_TOO_LARGE_THAN_LAST_BLOCK"
        );
    }

    function _estimateSwap(
        address inputToken,
        address outputToken,
        uint256 inputAmount,
        uint256 outputAmount
    ) internal view returns (uint256[2] memory reserves, uint256[2] memory amounts) {
        require(inputToken == baseToken || inputToken == quoteToken, "Amm._estimateSwap: WRONG_INPUT_TOKEN");
        require(outputToken == baseToken || outputToken == quoteToken, "Amm._estimateSwap: WRONG_OUTPUT_TOKEN");
        require(inputToken != outputToken, "Amm._estimateSwap: SAME_TOKENS");
        require(inputAmount > 0 || outputAmount > 0, "Amm._estimateSwap: INSUFFICIENT_AMOUNT");

        (uint112 _baseReserve, uint112 _quoteReserve, ) = getReserves();
        uint256 reserve0;
        uint256 reserve1;
        if (inputAmount > 0 && inputToken != address(0)) {
            // swapInput
            if (inputToken == baseToken) {
                outputAmount = _getAmountOut(inputAmount, _baseReserve, _quoteReserve);
                reserve0 = _baseReserve + inputAmount;
                reserve1 = _quoteReserve - outputAmount;
            } else {
                outputAmount = _getAmountOut(inputAmount, _quoteReserve, _baseReserve);
                reserve0 = _baseReserve - outputAmount;
                reserve1 = _quoteReserve + inputAmount;
            }
        } else {
            //swapOutput
            if (outputToken == baseToken) {
                require(outputAmount < _baseReserve, "AMM._estimateSwap: INSUFFICIENT_LIQUIDITY");
                inputAmount = _getAmountIn(outputAmount, _quoteReserve, _baseReserve);
                reserve0 = _baseReserve - outputAmount;
                reserve1 = _quoteReserve + inputAmount;
            } else {
                require(outputAmount < _quoteReserve, "AMM._estimateSwap: INSUFFICIENT_LIQUIDITY");
                inputAmount = _getAmountIn(outputAmount, _baseReserve, _quoteReserve);
                reserve0 = _baseReserve + inputAmount;
                reserve1 = _quoteReserve - outputAmount;
            }
        }
        reserves = [reserve0, reserve1];
        amounts = [inputAmount, outputAmount];
    }

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

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

    // if fee is on, mint liquidity equivalent to 1/6th of the growth in sqrt(k)
    function _mintFee(uint112 reserve0, uint112 reserve1) private returns (bool feeOn) {
        address feeTo = IAmmFactory(factory).feeTo();
        feeOn = feeTo != address(0);
        uint256 _kLast = kLast; // gas savings
        if (feeOn) {
            if (_kLast != 0) {
                uint256 rootK = Math.sqrt(uint256(reserve0) * reserve1);
                uint256 rootKLast = Math.sqrt(_kLast);
                if (rootK > rootKLast) {
                    uint256 numerator = totalSupply * (rootK - rootKLast);

                    uint256 feeParameter = IConfig(config).feeParameter();
                    uint256 denominator = (rootK * feeParameter) / 100 + rootKLast;
                    uint256 liquidity = numerator / denominator;
                    if (liquidity > 0) _mint(feeTo, liquidity);
                }
            }
        } else if (_kLast != 0) {
            kLast = 0;
        }
    }

    function _update(
        uint256 baseReserveNew,
        uint256 quoteReserveNew,
        uint112 baseReserveOld,
        uint112 quoteReserveOld,
        bool isRebaseOrForceSwap
    ) private {
        require(baseReserveNew <= type(uint112).max && quoteReserveNew <= type(uint112).max, "AMM._update: OVERFLOW");

        uint32 blockTimestamp = uint32(block.timestamp % 2**32);

        uint32 timeElapsed = blockTimestamp - blockTimestampLast; // overflow is desired

        // last price means last block price.
        if (timeElapsed > 0 && baseReserveOld != 0 && quoteReserveOld != 0) {
            // * never overflows, and + overflow is desired
            price0CumulativeLast += uint256(UQ112x112.encode(quoteReserveOld).uqdiv(baseReserveOld)) * timeElapsed;
            price1CumulativeLast += uint256(UQ112x112.encode(baseReserveOld).uqdiv(quoteReserveOld)) * timeElapsed;

            // update twap
            IPriceOracle(IConfig(config).priceOracle()).updateAmmTwap(address(this));
        }

        uint256 blockNumberDelta = ChainAdapter.blockNumber() - lastBlockNumber;

        //every arbi block number calculate
        if (blockNumberDelta > 0 && baseReserveOld != 0) {
            lastPrice = uint256(UQ112x112.encode(quoteReserveOld).uqdiv(baseReserveOld));
        }

        //set the last price to current price for rebase may cause price gap oversize the tradeslippage.
        if ((lastPrice == 0 && baseReserveNew != 0) || isRebaseOrForceSwap) {
            lastPrice = uint256(UQ112x112.encode(uint112(quoteReserveNew)).uqdiv(uint112(baseReserveNew)));
        }

        baseReserve = uint112(baseReserveNew);
        quoteReserve = uint112(quoteReserveNew);

        lastBlockNumber = ChainAdapter.blockNumber();
        blockTimestampLast = blockTimestamp;

        emit Sync(baseReserve, quoteReserve);
    }

    function _safeTransfer(
        address token,
        address to,
        uint256 value
    ) private {
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(SELECTOR, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), "AMM._safeTransfer: TRANSFER_FAILED");
    }
}

// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;

interface IAmmFactory {
    event AmmCreated(address indexed baseToken, address indexed quoteToken, address amm);

    function createAmm(address baseToken, address quoteToken) external returns (address amm);

    function initAmm(
        address baseToken,
        address quoteToken,
        address margin
    ) external;

    function setFeeTo(address) external;

    function setFeeToSetter(address) external;

    function upperFactory() external view returns (address);

    function config() external view returns (address);

    function feeTo() external view returns (address);

    function feeToSetter() external view returns (address);

    function getAmm(address baseToken, address quoteToken) external view returns (address amm);
}

// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;

interface IPriceOracle {
    function setupTwap(address amm) external;

    function quoteFromAmmTwap(address amm, uint256 baseAmount) external view returns (uint256 quoteAmount);

    function updateAmmTwap(address pair) external ;

    // index price maybe get from different oracle, like UniswapV3 TWAP,Chainklink, or others
    // source represents which oracle used. 0 = UniswapV3 TWAP
    function quote(
        address baseToken,
        address quoteToken,
        uint256 baseAmount
    ) external view returns (uint256 quoteAmount, uint8 source);

    function getIndexPrice(address amm) external view returns (uint256);

    function getMarkPrice(address amm) external view returns (uint256 price);

    function getMarkPriceAcc(
        address amm,
        uint8 beta,
        uint256 quoteAmount,
        bool negative
    ) external view returns (uint256 baseAmount);

    function getPremiumFraction(address amm) external view returns (int256);
}

// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;

import "./interfaces/ILiquidityERC20.sol";

contract LiquidityERC20 is ILiquidityERC20 {
    string public constant override name = "APEX LP";
    string public constant override symbol = "APEX-LP";
    uint8 public constant override decimals = 18;
    // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
    bytes32 public constant override PERMIT_TYPEHASH =
        0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;

    bytes32 public immutable override DOMAIN_SEPARATOR;

    uint256 public override totalSupply;
    mapping(address => uint256) public override balanceOf;
    mapping(address => mapping(address => uint256)) public override allowance;
    mapping(address => uint256) public override nonces;

    constructor() {
        uint256 chainId;
        assembly {
            chainId := chainid()
        }
        DOMAIN_SEPARATOR = keccak256(
            abi.encode(
                keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
                keccak256(bytes(name)),
                keccak256(bytes("1")),
                chainId,
                address(this)
            )
        );
    }

    function approve(address spender, uint256 value) external override returns (bool) {
        _approve(msg.sender, spender, value);
        return true;
    }

    function transfer(address to, uint256 value) external override returns (bool) {
        _transfer(msg.sender, to, value);
        return true;
    }

    function transferFrom(
        address from,
        address to,
        uint256 value
    ) external override returns (bool) {
        if (allowance[from][msg.sender] != type(uint256).max) {
            allowance[from][msg.sender] = allowance[from][msg.sender] - value;
        }
        _transfer(from, to, value);
        return true;
    }

    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external override {
        require(deadline >= block.timestamp, "LiquidityERC20: EXPIRED");
        bytes32 digest = keccak256(
            abi.encodePacked(
                "\x19\x01",
                DOMAIN_SEPARATOR,
                keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline))
            )
        );
        address recoveredAddress = ecrecover(digest, v, r, s);
        require(recoveredAddress != address(0) && recoveredAddress == owner, "LiquidityERC20: INVALID_SIGNATURE");
        _approve(owner, spender, value);
    }

    function _mint(address to, uint256 value) internal {
        totalSupply = totalSupply + value;
        balanceOf[to] = balanceOf[to] + value;
        emit Transfer(address(0), to, value);
    }

    function _burn(address from, uint256 value) internal {
        balanceOf[from] = balanceOf[from] - value;
        totalSupply = totalSupply - value;
        emit Transfer(from, address(0), value);
    }

    function _approve(
        address owner,
        address spender,
        uint256 value
    ) private {
        allowance[owner][spender] = value;
        emit Approval(owner, spender, value);
    }

    function _transfer(
        address from,
        address to,
        uint256 value
    ) private {
        balanceOf[from] = balanceOf[from] - value;
        balanceOf[to] = balanceOf[to] + value;
        emit Transfer(from, to, value);
    }
}

// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;

interface IConfig {
    event PriceOracleChanged(address indexed oldOracle, address indexed newOracle);
    event RebasePriceGapChanged(uint256 oldGap, uint256 newGap);
    event RebaseIntervalChanged(uint256 oldInterval, uint256 newInterval);
    event TradingSlippageChanged(uint256 oldTradingSlippage, uint256 newTradingSlippage);
    event RouterRegistered(address indexed router);
    event RouterUnregistered(address indexed router);
    event SetLiquidateFeeRatio(uint256 oldLiquidateFeeRatio, uint256 liquidateFeeRatio);
    event SetLiquidateThreshold(uint256 oldLiquidateThreshold, uint256 liquidateThreshold);
    event SetInitMarginRatio(uint256 oldInitMarginRatio, uint256 initMarginRatio);
    event SetBeta(uint256 oldBeta, uint256 beta);
    event SetFeeParameter(uint256 oldFeeParameter, uint256 feeParameter);
    event SetMaxCPFBoost(uint256 oldMaxCPFBoost, uint256 maxCPFBoost);

    /// @notice get price oracle address.
    function priceOracle() external view returns (address);

    /// @notice get beta of amm.
    function beta() external view returns (uint8);

    /// @notice get feeParameter of amm.
    function feeParameter() external view returns (uint256);

    /// @notice get init margin ratio of margin.
    function initMarginRatio() external view returns (uint256);

    /// @notice get liquidate threshold of margin.
    function liquidateThreshold() external view returns (uint256);

    /// @notice get liquidate fee ratio of margin.
    function liquidateFeeRatio() external view returns (uint256);

    /// @notice get trading slippage  of amm.
    function tradingSlippage() external view returns (uint256);

    /// @notice get rebase gap of amm.
    function rebasePriceGap() external view returns (uint256);

    function rebaseInterval() external view returns (uint256);

    function routerMap(address) external view returns (bool);

    function maxCPFBoost() external view returns (uint256);

    function registerRouter(address router) external;

    function unregisterRouter(address router) external;

    /// @notice Set a new oracle
    /// @param newOracle new oracle address.
    function setPriceOracle(address newOracle) external;

    /// @notice Set a new beta of amm
    /// @param newBeta new beta.
    function setBeta(uint8 newBeta) external;

    /// @notice Set a new rebase gap of amm
    /// @param newGap new gap.
    function setRebasePriceGap(uint256 newGap) external;

    function setRebaseInterval(uint256 interval) external;

    /// @notice Set a new trading slippage of amm
    /// @param newTradingSlippage .
    function setTradingSlippage(uint256 newTradingSlippage) external;

    /// @notice Set a new init margin ratio of margin
    /// @param marginRatio new init margin ratio.
    function setInitMarginRatio(uint256 marginRatio) external;

    /// @notice Set a new liquidate threshold of margin
    /// @param threshold new liquidate threshold of margin.
    function setLiquidateThreshold(uint256 threshold) external;

    /// @notice Set a new liquidate fee of margin
    /// @param feeRatio new liquidate fee of margin.
    function setLiquidateFeeRatio(uint256 feeRatio) external;

    /// @notice Set a new feeParameter.
    /// @param newFeeParameter New feeParameter get from AMM swap fee.
    /// @dev feeParameter = (1/fee -1 ) *100 where fee set by owner.
    function setFeeParameter(uint256 newFeeParameter) external;

    function setMaxCPFBoost(uint256 newMaxCPFBoost) external;
}

// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;

interface IMarginFactory {
    event MarginCreated(address indexed baseToken, address indexed quoteToken, address margin);

    function createMargin(address baseToken, address quoteToken) external returns (address margin);

    function initMargin(
        address baseToken,
        address quoteToken,
        address amm
    ) external;

    function upperFactory() external view returns (address);

    function config() external view returns (address);

    function getMargin(address baseToken, address quoteToken) external view returns (address margin);
}

// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;

interface IAmm {
    event Mint(address indexed sender, address indexed to, uint256 baseAmount, uint256 quoteAmount, uint256 liquidity);
    event Burn(address indexed sender, address indexed to, uint256 baseAmount, uint256 quoteAmount, uint256 liquidity);
    event Swap(address indexed trader, address indexed inputToken, address indexed outputToken, uint256 inputAmount, uint256 outputAmount);
    event ForceSwap(address indexed trader, address indexed inputToken, address indexed outputToken, uint256 inputAmount, uint256 outputAmount);
    event Rebase(uint256 quoteReserveBefore, uint256 quoteReserveAfter, uint256 _baseReserve , uint256 quoteReserveFromInternal,  uint256 quoteReserveFromExternal );
    event Sync(uint112 reserveBase, uint112 reserveQuote);

    // only factory can call this function
    function initialize(
        address baseToken_,
        address quoteToken_,
        address margin_
    ) external;

    function mint(address to)
        external
        returns (
            uint256 baseAmount,
            uint256 quoteAmount,
            uint256 liquidity
        );

    function burn(address to)
        external
        returns (
            uint256 baseAmount,
            uint256 quoteAmount,
            uint256 liquidity
        );

    // only binding margin can call this function
    function swap(
        address trader,
        address inputToken,
        address outputToken,
        uint256 inputAmount,
        uint256 outputAmount
    ) external returns (uint256[2] memory amounts);

    // only binding margin can call this function
    function forceSwap(
        address trader,
        address inputToken,
        address outputToken,
        uint256 inputAmount,
        uint256 outputAmount
    ) external;

    function rebase() external returns (uint256 quoteReserveAfter);

    function factory() external view returns (address);

    function config() external view returns (address);

    function baseToken() external view returns (address);

    function quoteToken() external view returns (address);

    function price0CumulativeLast() external view returns (uint256);

    function price1CumulativeLast() external view returns (uint256);

    function margin() external view returns (address);

    function lastPrice() external view returns (uint256);

    function getReserves()
        external
        view
        returns (
            uint112 reserveBase,
            uint112 reserveQuote,
            uint32 blockTimestamp
        );

    function estimateSwap(
        address inputToken,
        address outputToken,
        uint256 inputAmount,
        uint256 outputAmount
    ) external view returns (uint256[2] memory amounts);

    function MINIMUM_LIQUIDITY() external pure returns (uint256);
}

// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;

interface IVault {
    event Deposit(address indexed user, uint256 amount);
    event Withdraw(address indexed user, address indexed receiver, uint256 amount);

    /// @notice deposit baseToken to user
    function deposit(address user, uint256 amount) external;

    /// @notice withdraw user's baseToken from margin contract to receiver
    function withdraw(
        address user,
        address receiver,
        uint256 amount
    ) external;

    /// @notice get baseToken amount in margin
    function reserve() external view returns (uint256);
}

// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;

interface IMargin {
    struct Position {
        int256 quoteSize; //quote amount of position
        int256 baseSize; //margin + fundingFee + unrealizedPnl + deltaBaseWhenClosePosition
        uint256 tradeSize; //if quoteSize>0 unrealizedPnl = baseValueOfQuoteSize - tradeSize; if quoteSize<0 unrealizedPnl = tradeSize - baseValueOfQuoteSize;
    }

    event AddMargin(address indexed trader, uint256 depositAmount, Position position);
    event RemoveMargin(
        address indexed trader,
        address indexed to,
        uint256 withdrawAmount,
        int256 fundingFee,
        uint256 withdrawAmountFromMargin,
        Position position
    );
    event OpenPosition(
        address indexed trader,
        uint8 side,
        uint256 baseAmount,
        uint256 quoteAmount,
        int256 fundingFee,
        Position position
    );
    event ClosePosition(
        address indexed trader,
        uint256 quoteAmount,
        uint256 baseAmount,
        int256 fundingFee,
        Position position
    );
    event Liquidate(
        address indexed liquidator,
        address indexed trader,
        uint256 quoteAmount,
        uint256 baseAmount,
        uint256 bonus,
        int256 fundingFee,
        Position position
    );
    event UpdateCPF(uint256 timeStamp, int256 cpf);

    /// @notice only factory can call this function
    /// @param baseToken_ margin's baseToken.
    /// @param quoteToken_ margin's quoteToken.
    /// @param amm_ amm address.
    function initialize(
        address baseToken_,
        address quoteToken_,
        address amm_
    ) external;

    /// @notice add margin to trader
    /// @param trader .
    /// @param depositAmount base amount to add.
    function addMargin(address trader, uint256 depositAmount) external;

    /// @notice remove margin to msg.sender
    /// @param withdrawAmount base amount to withdraw.
    function removeMargin(
        address trader,
        address to,
        uint256 withdrawAmount
    ) external;

    /// @notice open position with side and quoteAmount by msg.sender
    /// @param side long or short.
    /// @param quoteAmount quote amount.
    function openPosition(
        address trader,
        uint8 side,
        uint256 quoteAmount
    ) external returns (uint256 baseAmount);

    /// @notice close msg.sender's position with quoteAmount
    /// @param quoteAmount quote amount to close.
    function closePosition(address trader, uint256 quoteAmount) external returns (uint256 baseAmount);

    /// @notice liquidate trader
    function liquidate(address trader)
        external
        returns (
            uint256 quoteAmount,
            uint256 baseAmount,
            uint256 bonus
        );

    function updateCPF() external returns (int256);

    /// @notice get factory address
    function factory() external view returns (address);

    /// @notice get config address
    function config() external view returns (address);

    /// @notice get base token address
    function baseToken() external view returns (address);

    /// @notice get quote token address
    function quoteToken() external view returns (address);

    /// @notice get amm address of this margin
    function amm() external view returns (address);

    /// @notice get all users' net position of base
    function netPosition() external view returns (int256 netBasePosition);

    /// @notice get trader's position
    function getPosition(address trader)
        external
        view
        returns (
            int256 baseSize,
            int256 quoteSize,
            uint256 tradeSize
        );

    /// @notice get withdrawable margin of trader
    function getWithdrawable(address trader) external view returns (uint256 amount);

    /// @notice check if can liquidate this trader's position
    function canLiquidate(address trader) external view returns (bool);

    /// @notice calculate the latest funding fee with current position
    function calFundingFee(address trader) external view returns (int256 fundingFee);

    /// @notice calculate the latest debt ratio with Pnl and funding fee
    function calDebtRatio(address trader) external view returns (uint256 debtRatio);

    function calUnrealizedPnl(address trader) external view returns (int256);

    function getNewLatestCPF() external view returns (int256);

    function querySwapBaseWithAmm(bool isLong, uint256 quoteAmount) external view returns (uint256);
}

// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;

interface IPairFactory {
    event NewPair(address indexed baseToken, address indexed quoteToken, address amm, address margin);

    function createPair(address baseToken, address quotoToken) external returns (address amm, address margin);

    function ammFactory() external view returns (address);

    function marginFactory() external view returns (address);

    function getAmm(address baseToken, address quoteToken) external view returns (address);

    function getMargin(address baseToken, address quoteToken) external view returns (address);
}

File 12 of 18 : Reentrant.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;

abstract contract Reentrant {
    bool private entered;

    modifier nonReentrant() {
        require(entered == false, "Reentrant: reentrant call");
        entered = true;
        _;
        entered = false;
    }
}

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

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

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

library Math {
    function min(uint256 x, uint256 y) internal pure returns (uint256) {
        if (x > y) {
            return y;
        }
        return x;
    }

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

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

/// @title Contains 512-bit math functions
/// @notice Facilitates multiplication and division that can have overflow of an intermediate value without any loss of precision
/// @dev Handles "phantom overflow" i.e., allows multiplication and division where an intermediate value overflows 256 bits
library FullMath {
    /// @notice Calculates floor(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
    /// @param a The multiplicand
    /// @param b The multiplier
    /// @param denominator The divisor
    /// @return result The 256-bit result
    /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv
    function mulDiv(
        uint256 a,
        uint256 b,
        uint256 denominator
    ) internal pure returns (uint256 result) {
        // 512-bit multiply [prod1 prod0] = a * b
        // Compute the product mod 2**256 and mod 2**256 - 1
        // then use the Chinese Remainder Theorem to reconstruct
        // the 512 bit result. The result is stored in two 256
        // variables such that product = prod1 * 2**256 + prod0
        uint256 prod0; // Least significant 256 bits of the product
        uint256 prod1; // Most significant 256 bits of the product

        // todo unchecked
        unchecked {
            assembly {
                let mm := mulmod(a, b, not(0))
                prod0 := mul(a, b)
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Handle non-overflow cases, 256 by 256 division
            if (prod1 == 0) {
                require(denominator > 0);
                assembly {
                    result := div(prod0, denominator)
                }
                return result;
            }

            // Make sure the result is less than 2**256.
            // Also prevents denominator == 0
            require(denominator > prod1);

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

            // Make division exact by subtracting the remainder from [prod1 prod0]
            // Compute remainder using mulmod
            uint256 remainder;
            assembly {
                remainder := mulmod(a, b, denominator)
            }
            // Subtract 256 bit number from 512 bit number
            assembly {
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator
            // Compute largest power of two divisor of denominator.
            // Always >= 1.
            uint256 twos = (~denominator + 1) & denominator;
            // Divide denominator by power of two
            assembly {
                denominator := div(denominator, twos)
            }

            // Divide [prod1 prod0] by the factors of two
            assembly {
                prod0 := div(prod0, twos)
            }
            // Shift in bits from prod1 into prod0. For this we need
            // to flip `twos` such that it is 2**256 / twos.
            // If twos is zero, then it becomes one
            assembly {
                twos := add(div(sub(0, twos), twos), 1)
            }

            prod0 |= prod1 * twos;

            // Invert denominator mod 2**256
            // Now that denominator is an odd number, it has an inverse
            // modulo 2**256 such that denominator * inv = 1 mod 2**256.
            // Compute the inverse by starting with a seed that is correct
            // correct for four bits. That is, denominator * inv = 1 mod 2**4
            uint256 inv = (3 * denominator) ^ 2;
            // Now use Newton-Raphson iteration to improve the precision.
            // Thanks to Hensel's lifting lemma, this also works in modular
            // arithmetic, doubling the correct bits in each step.

            inv *= 2 - denominator * inv; // inverse mod 2**8
            inv *= 2 - denominator * inv; // inverse mod 2**16
            inv *= 2 - denominator * inv; // inverse mod 2**32
            inv *= 2 - denominator * inv; // inverse mod 2**64
            inv *= 2 - denominator * inv; // inverse mod 2**128
            inv *= 2 - denominator * inv; // inverse mod 2**256

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

    /// @notice Calculates ceil(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
    /// @param a The multiplicand
    /// @param b The multiplier
    /// @param denominator The divisor
    /// @return result The 256-bit result
    function mulDivRoundingUp(
        uint256 a,
        uint256 b,
        uint256 denominator
    ) internal pure returns (uint256 result) {
        result = mulDiv(a, b, denominator);
        if (mulmod(a, b, denominator) > 0) {
            require(result < type(uint256).max);
            result++;
        }
    }
}

// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;

interface IArbSys {
    function arbBlockNumber() external view returns (uint256);
}

library ChainAdapter {
    address constant arbSys = address(100);

    function blockNumber() internal view returns (uint256) {
        uint256 chainId;
        assembly {
            chainId := chainid()
        }
        if (chainId == 421611 || chainId == 42161) { // Arbitrum Testnet || Arbitrum Mainnet
            return IArbSys(arbSys).arbBlockNumber();
        } else {
            return block.number;
        }
    }
}

// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;

import "./IERC20.sol";

interface ILiquidityERC20 is IERC20 {
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

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

    function DOMAIN_SEPARATOR() external view returns (bytes32);

    function PERMIT_TYPEHASH() external pure returns (bytes32);
}

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

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

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

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

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

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

    function totalSupply() external view returns (uint256);

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

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

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

    function decimals() external pure returns (uint8);
}

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

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"upperFactory_","type":"address"},{"internalType":"address","name":"config_","type":"address"},{"internalType":"address","name":"feeToSetter_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"baseToken","type":"address"},{"indexed":true,"internalType":"address","name":"quoteToken","type":"address"},{"indexed":false,"internalType":"address","name":"amm","type":"address"}],"name":"AmmCreated","type":"event"},{"inputs":[],"name":"config","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"baseToken","type":"address"},{"internalType":"address","name":"quoteToken","type":"address"}],"name":"createAmm","outputs":[{"internalType":"address","name":"amm","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"feeTo","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeToSetter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"getAmm","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"baseToken","type":"address"},{"internalType":"address","name":"quoteToken","type":"address"},{"internalType":"address","name":"margin","type":"address"}],"name":"initAmm","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"feeTo_","type":"address"}],"name":"setFeeTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"feeToSetter_","type":"address"}],"name":"setFeeToSetter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"upperFactory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]

60c060405234801561001057600080fd5b506040516140d83803806140d883398101604081905261002f916100fb565b6001600160a01b0382161580159061004f57506001600160a01b03811615155b61009f5760405162461bcd60e51b815260206004820152601860248201527f416d6d466163746f72793a205a45524f5f414444524553530000000000000000604482015260640160405180910390fd5b606092831b6001600160601b03199081166080529190921b1660a052600180546001600160a01b0319166001600160a01b0390921691909117905561013d565b80516001600160a01b03811681146100f657600080fd5b919050565b60008060006060848603121561010f578283fd5b610118846100df565b9250610126602085016100df565b9150610134604085016100df565b90509250925092565b60805160601c60a05160601c613f5b61017d6000396000818161013b01526102ac015260008181610175015281816101b501526103ab0152613f5b6000f3fe608060405234801561001057600080fd5b50600436106100935760003560e01c806365cc7a1d1161006657806365cc7a1d1461010257806379502c5514610136578063a2e74af61461015d578063cedc12d814610170578063f46901ed1461019757610093565b8063017e7e5814610098578063094b7415146100c757806335e30d41146100da5780635131c85b146100ef575b600080fd5b6000546100ab906001600160a01b031681565b6040516001600160a01b03909116815260200160405180910390f35b6001546100ab906001600160a01b031681565b6100ed6100e83660046107e8565b6101aa565b005b6100ab6100fd3660046107b0565b61039e565b6100ab6101103660046107b0565b60026020908152600092835260408084209091529082529020546001600160a01b031681565b6100ab7f000000000000000000000000000000000000000000000000000000000000000081565b6100ed61016b366004610771565b610660565b6100ab7f000000000000000000000000000000000000000000000000000000000000000081565b6100ed6101a5366004610771565b6106e8565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461021f5760405162461bcd60e51b815260206004820152601560248201527420b6b6a330b1ba37b93c9d102327a92124a22222a760591b60448201526064015b60405180910390fd5b6001600160a01b03838116600081815260026020908152604080832087861680855292529182902054915163c0c53b8b60e01b815260048101939093526024830152838316604483015290911690819063c0c53b8b90606401600060405180830381600087803b15801561029257600080fd5b505af11580156102a6573d6000803e3d6000fd5b505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316632630c12f6040518163ffffffff1660e01b815260040160206040518083038186803b15801561030357600080fd5b505afa158015610317573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061033b9190610794565b604051637b2bb85d60e11b81526001600160a01b038381166004830152919091169063f65770ba90602401600060405180830381600087803b15801561038057600080fd5b505af1158015610394573d6000803e3d6000fd5b5050505050505050565b6000336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146104105760405162461bcd60e51b815260206004820152601560248201527420b6b6a330b1ba37b93c9d102327a92124a22222a760591b6044820152606401610216565b816001600160a01b0316836001600160a01b031614156104845760405162461bcd60e51b815260206004820152602960248201527f416d6d466163746f72792e637265617465416d6d3a204944454e544943414c5f60448201526841444452455353455360b81b6064820152608401610216565b6001600160a01b038316158015906104a457506001600160a01b03821615155b6104fb5760405162461bcd60e51b815260206004820152602260248201527f416d6d466163746f72792e637265617465416d6d3a205a45524f5f4144445245604482015261535360f01b6064820152608401610216565b6001600160a01b038381166000908152600260209081526040808320868516845290915290205416156105705760405162461bcd60e51b815260206004820152601f60248201527f416d6d466163746f72792e637265617465416d6d3a20414d4d5f4558495354006044820152606401610216565b6040516bffffffffffffffffffffffff19606085811b8216602084015284901b1660348201526000906048016040516020818303038152906040528051906020012090506000604051806020016105c690610764565b6020820181038252601f19601f820116604052509050818151602083016000f56001600160a01b0386811660008181526002602090815260408083208a86168085529083529281902080546001600160a01b0319169587169586179055519384529396509290917f8eef5cf520576c00176a77de7eeee6762c3f44c7231914ce6c5c01e03a703820910160405180910390a3505092915050565b6001546001600160a01b031633146106c65760405162461bcd60e51b8152602060048201526024808201527f416d6d466163746f72792e736574466565546f5365747465723a20464f524249604482015263222222a760e11b6064820152608401610216565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b6001546001600160a01b031633146107425760405162461bcd60e51b815260206004820152601e60248201527f416d6d466163746f72792e736574466565546f3a20464f5242494444454e00006044820152606401610216565b600080546001600160a01b0319166001600160a01b0392909216919091179055565b6136db8061084b83390190565b600060208284031215610782578081fd5b813561078d81610832565b9392505050565b6000602082840312156107a5578081fd5b815161078d81610832565b600080604083850312156107c2578081fd5b82356107cd81610832565b915060208301356107dd81610832565b809150509250929050565b6000806000606084860312156107fc578081fd5b833561080781610832565b9250602084013561081781610832565b9150604084013561082781610832565b809150509250925092565b6001600160a01b038116811461084757600080fd5b5056fe60c060405234801561001057600080fd5b506040805180820182526007815266041504558204c560cc1b6020918201528151808301835260018152603160f81b9082015281517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f918101919091527f61b9d5b67636ce161ec7cadd1dad2e234b7b19f7846bc9e1c0e66fc72bb44376918101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6606082015246608082018190523060a08301529060c00160408051601f198184030181529190528051602090910120608052503360601b60a05260805160a05160601c6135a76101346000396000818161049d0152818161183b015281816118f50152611e4d01526000818161031d0152611a0d01526135a76000f3fe608060405234801561001057600080fd5b50600436106101e55760003560e01c806379502c551161010f578063ba9a7a56116100a2578063c55dae6311610071578063c55dae63146104bf578063d505accf146104d2578063dd62ed3e146104e5578063e343fe1214610510576101e5565b8063ba9a7a561461045c578063bc93657614610465578063c0c53b8b14610485578063c45a015514610498576101e5565b806395d89b41116100de57806395d89b4114610406578063988370a31461042c578063a9059cbb14610441578063af14052c14610454576101e5565b806379502c55146103a85780637ecebe00146103c057806389afcb44146103e05780638f76691a146103f3576101e5565b806330adf81f116101875780635a3d5493116101565780635a3d5493146103485780636a6278421461035157806370a082311461037f5780637464fc3d1461039f576101e5565b806330adf81f146102d7578063313ce567146102fe5780633644e515146103185780635909c0d51461033f576101e5565b8063095ea7b3116101c3578063095ea7b31461026d57806318160ddd14610290578063217a4b701461029957806323b872dd146102c4576101e5565b8063053f14da146101ea57806306fdde03146102065780630902f1ac14610239575b600080fd5b6101f3600b5481565b6040519081526020015b60405180910390f35b61022c60405180604001604052806007815260200166041504558204c560cc1b81525081565b6040516101fd91906132ef565b610241610523565b604080516001600160701b03948516815293909216602084015263ffffffff16908201526060016101fd565b61028061027b36600461321b565b61054d565b60405190151581526020016101fd565b6101f360005481565b6006546102ac906001600160a01b031681565b6040516001600160a01b0390911681526020016101fd565b6102806102d2366004613126565b610563565b6101f37f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c981565b610306601281565b60405160ff90911681526020016101fd565b6101f37f000000000000000000000000000000000000000000000000000000000000000081565b6101f360085481565b6101f360095481565b61036461035f366004613012565b6105f8565b604080519384526020840192909252908201526060016101fd565b6101f361038d366004613012565b60016020526000908152604090205481565b6101f3600a5481565b6004546102ac9061010090046001600160a01b031681565b6101f36103ce366004613012565b60036020526000908152604090205481565b6103646103ee366004613012565b610bca565b6007546102ac906001600160a01b031681565b61022c604051806040016040528060078152602001660415045582d4c560cc1b81525081565b61043f61043a3660046130cc565b610e8d565b005b61028061044f36600461321b565b6111a1565b6101f36111ae565b6101f36103e881565b610478610473366004613166565b611812565b6040516101fd91906132be565b61043f610493366004613082565b611830565b6102ac7f000000000000000000000000000000000000000000000000000000000000000081565b6005546102ac906001600160a01b031681565b61043f6104e03660046131ab565b6119a1565b6101f36104f336600461304a565b600260209081526000928352604080842090915290825290205481565b61047861051e3660046130cc565b611be5565b600c546001600160701b0380821692600160701b830490911691600160e01b900463ffffffff1690565b600061055a338484611d3e565b50600192915050565b6001600160a01b0383166000908152600260209081526040808320338452909152812054600019146105e3576001600160a01b03841660009081526002602090815260408083203384529091529020546105be908390613483565b6001600160a01b03851660009081526002602090815260408083203384529091529020555b6105ee848484611da0565b5060019392505050565b6004546000908190819060ff161561062b5760405162461bcd60e51b815260040161062290613322565b60405180910390fd5b6004805460ff19166001179055600080610643610523565b50915091506000600760009054906101000a90046001600160a01b03166001600160a01b031663833b0acb6040518163ffffffff1660e01b815260040160206040518083038186803b15801561069857600080fd5b505afa1580156106ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106d09190613266565b9050600160701b6106ea826001600160701b0386166133a2565b13156107385760405162461bcd60e51b815260206004820181905260248201527f416d6d2e6d696e743a4e6574506f736974696f6e5f56414c55455f57524f4e546044820152606401610622565b600061074d826001600160701b0386166133a2565b6005546040516370a0823160e01b815230600482015291925082916001600160a01b03909116906370a082319060240160206040518083038186803b15801561079557600080fd5b505afa1580156107a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107cd9190613266565b97506000881161081f5760405162461bcd60e51b815260206004820152601a60248201527f416d6d2e6d696e743a205a45524f5f424153455f414d4f554e540000000000006044820152606401610622565b600061082b8686611e48565b600054909150806109d857600460019054906101000a90046001600160a01b03166001600160a01b0316632630c12f6040518163ffffffff1660e01b815260040160206040518083038186803b15801561088457600080fd5b505afa158015610898573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108bc919061302e565b600554600654604051632d9198e160e21b81526001600160a01b0392831660048201529082166024820152604481018d905291169063b646638490606401604080518083038186803b15801561091157600080fd5b505afa158015610925573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610949919061327e565b509850886109a55760405162461bcd60e51b815260206004820152602360248201527f416d6d2e6d696e743a20494e53554646494349454e545f51554f54455f414d4f60448201526215539560ea1b6064820152608401610622565b6103e86109ba6109b58b8d613464565b612037565b6109c49190613483565b97506109d360006103e86120a7565b610a1b565b866001600160701b0316866001600160701b03168b6109f79190613464565b610a019190613421565b985082610a0e828c613464565b610a189190613421565b97505b60008811610a7b5760405162461bcd60e51b815260206004820152602760248201527f416d6d2e6d696e743a20494e53554646494349454e545f4c495155494449545960448201526617d3525395115160ca1b6064820152608401610622565b610a858b896120a7565b610ab7610a9b8b6001600160701b038a166133e3565b610aae8b6001600160701b038a166133e3565b89896000612138565b8115610ae057600c54610adc906001600160701b03600160701b820481169116613464565b600a555b600554600754610afd916001600160a01b0390811691168c6124bd565b6007546040516311f9fbc960e21b8152336004820152602481018c90526001600160a01b03909116906347e7ef2490604401600060405180830381600087803b158015610b4957600080fd5b505af1158015610b5d573d6000803e3d6000fd5b5050604080518d8152602081018d90529081018b90526001600160a01b038e1692503391507f458f5fa412d0f69b08dd84872b0215675cc67bc1d5b6fd93300a1c3878b86196906060015b60405180910390a350506004805460ff19169055509597949650929450505050565b6004546000908190819060ff1615610bf45760405162461bcd60e51b815260040161062290613322565b6004805460ff19166001179055600080610c0c610523565b5030600090815260016020908152604080832054600754825163833b0acb60e01b8152925191995095975093955091936001600160a01b03169263833b0acb926004808201939291829003018186803b158015610c6857600080fd5b505afa158015610c7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ca09190613266565b90506000610cb7826001600160701b0386166133a2565b9050806000610cc68686611e48565b60005490915080610cd7848a613464565b610ce19190613421565b9950866001600160701b0316866001600160701b03168b610d029190613464565b610d0c9190613421565b985060008a118015610d1e5750600089115b610d7a5760405162461bcd60e51b815260206004820152602760248201527f416d6d2e6275726e3a20494e53554646494349454e545f4c495155494449545960448201526617d0955493915160ca1b6064820152608401610622565b610d843089612613565b610dad610d9a8b6001600160701b038a16613483565b610aae8b6001600160701b038a16613483565b8115610dd657600c54610dd2906001600160701b03600160701b820481169116613464565b600a555b600754604051636ce5768960e11b81523360048201526001600160a01b038d81166024830152604482018d90529091169063d9caed1290606401600060405180830381600087803b158015610e2a57600080fd5b505af1158015610e3e573d6000803e3d6000fd5b5050604080518d8152602081018d90529081018b90526001600160a01b038e1692503391507f4cf25bc1d991c17529c25213d3cc0cda295eeaad5f13f361969b12ea48015f9090606001610ba8565b60045460ff1615610eb05760405162461bcd60e51b815260040161062290613322565b6004805460ff191660011790556007546001600160a01b03163314610f0a5760405162461bcd60e51b815260206004820152601060248201526f20b6b69d1027a7262cafa6a0a923a4a760811b6044820152606401610622565b6005546001600160a01b0385811691161480610f3357506006546001600160a01b038581169116145b610f7f5760405162461bcd60e51b815260206004820181905260248201527f416d6d2e666f726365537761703a2057524f4e475f494e5055545f544f4b454e6044820152606401610622565b6005546001600160a01b0384811691161480610fa857506006546001600160a01b038481169116145b610ffe5760405162461bcd60e51b815260206004820152602160248201527f416d6d2e666f726365537761703a2057524f4e475f4f55545055545f544f4b456044820152602760f91b6064820152608401610622565b826001600160a01b0316846001600160a01b031614156110605760405162461bcd60e51b815260206004820152601a60248201527f416d6d2e666f726365537761703a2053414d455f544f4b454e530000000000006044820152606401610622565b60008061106b610523565b5091509150600061107c8383611e48565b60055490915060009081906001600160a01b038a8116911614156110c9576110ad876001600160701b0387166133e3565b91506110c2866001600160701b038616613483565b90506110f4565b6110dc866001600160701b038716613483565b91506110f1876001600160701b0386166133e3565b90505b611102828287876001612138565b821561112b57600c54611127906001600160701b03600160701b820481169116613464565b600a555b876001600160a01b0316896001600160a01b03168b6001600160a01b03167fa36e6e2023c9daa81ac16fbc0d2499822bc9617326793b1ec3ab50c90bcfe8728a8a604051611183929190918252602082015260400190565b60405180910390a450506004805460ff191690555050505050505050565b600061055a338484611da0565b60045460009060ff16156111d45760405162461bcd60e51b815260040161062290613322565b6004805460ff191660011790553332146112275760405162461bcd60e51b8152602060048201526014602482015273416d6d2e7265626173653a204f4e4c595f454f4160601b6044820152606401610622565b6000600460019054906101000a90046001600160a01b03166001600160a01b03166389edeb746040518163ffffffff1660e01b815260040160206040518083038186803b15801561127757600080fd5b505afa15801561128b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112af9190613266565b905080600e54426112c09190613483565b101561131d5760405162461bcd60e51b815260206004820152602660248201527f416d6d2e7265626173653a204e4f545f52454143485f4e4558545f5245424153604482015265455f54494d4560d01b6064820152608401610622565b600080611328610523565b509150915060006113398383611e48565b90506000806000600460019054906101000a90046001600160a01b03166001600160a01b0316632630c12f6040518163ffffffff1660e01b815260040160206040518083038186803b15801561138e57600080fd5b505afa1580156113a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113c6919061302e565b600554600654604051632d9198e160e21b81526001600160a01b03928316600482015290821660248201526001600160701b038916604482015291169063b646638490606401604080518083038186803b15801561142357600080fd5b505afa158015611437573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061145b919061327e565b915091508060ff166000141561158057600460019054906101000a90046001600160a01b03166001600160a01b0316632630c12f6040518163ffffffff1660e01b815260040160206040518083038186803b1580156114b957600080fd5b505afa1580156114cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114f1919061302e565b6040516335201cc760e21b81523060048201526001600160701b03881660248201526001600160a01b03919091169063d480731c9060440160206040518083038186803b15801561154157600080fd5b505afa158015611555573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115799190613266565b92506115a9565b600160701b866001600160701b0316600b5461159c9190613464565b6115a69190613421565b92505b6000600460019054906101000a90046001600160a01b03166001600160a01b0316638ecb45516040518163ffffffff1660e01b815260040160206040518083038186803b1580156115f957600080fd5b505afa15801561160d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116319190613266565b905061163e8160646133e3565b6116489085613464565b611653846064613464565b10158061167e5750611666816064613483565b6116709085613464565b61167b846064613464565b11155b6116ca5760405162461bcd60e51b815260206004820181905260248201527f416d6d2e7265626173653a204e4f545f4245594f4e445f50524943455f4741506044820152606401610622565b6116d58160646133e3565b6116df9085613464565b6116ea846064613464565b1061171f5760646116fb82826133e3565b61170e906001600160701b038916613464565b6117189190613421565b985061174b565b606461172b8282613483565b61173e906001600160701b038916613464565b6117489190613421565b98505b61175a6401000000004261350a565b63ffffffff16600e5561177a6001600160701b0388168a89896001612138565b84156117a357600c5461179f906001600160701b03600160701b820481169116613464565b600a555b604080516001600160701b038881168252602082018c9052891681830152606081018690526080810185905290517fa904dcf42a3461c90173c0b966672b2cb4350e529ea12d44e562fcec438363249181900360a00190a150506004805460ff19169055509495945050505050565b61181a612ff4565b6118268585858561269f565b9695505050505050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146118a85760405162461bcd60e51b815260206004820152601960248201527f416d6d2e696e697469616c697a653a20464f5242494444454e000000000000006044820152606401610622565b600580546001600160a01b038086166001600160a01b03199283161790925560068054858416908316179055600780548484169216919091179055604080516379502c5560e01b815290517f0000000000000000000000000000000000000000000000000000000000000000909216916379502c5591600480820192602092909190829003018186803b15801561193e57600080fd5b505afa158015611952573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611976919061302e565b600460016101000a8154816001600160a01b0302191690836001600160a01b03160217905550505050565b428410156119f15760405162461bcd60e51b815260206004820152601760248201527f4c697175696469747945524332303a20455850495245440000000000000000006044820152606401610622565b6001600160a01b038716600090815260036020526040812080547f0000000000000000000000000000000000000000000000000000000000000000917f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9918b918b918b9187611a5f836134ef565b909155506040805160208101969096526001600160a01b0394851690860152929091166060840152608083015260a082015260c0810187905260e00160405160208183030381529060405280519060200120604051602001611ad892919061190160f01b81526002810192909252602282015260420190565b60408051601f198184030181528282528051602091820120600080855291840180845281905260ff88169284019290925260608301869052608083018590529092509060019060a0016020604051602081039080840390855afa158015611b43573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b03811615801590611b795750886001600160a01b0316816001600160a01b0316145b611bcf5760405162461bcd60e51b815260206004820152602160248201527f4c697175696469747945524332303a20494e56414c49445f5349474e415455526044820152604560f81b6064820152608401610622565b611bda898989611d3e565b505050505050505050565b611bed612ff4565b60045460ff1615611c105760405162461bcd60e51b815260040161062290613322565b6004805460ff191660011790556007546001600160a01b03163314611c6a5760405162461bcd60e51b815260206004820152601060248201526f20b6b69d1027a7262cafa6a0a923a4a760811b6044820152606401610622565b611c72612ff4565b611c7e8686868661269f565b81516020830151600c54929550929350611cad9290916001600160701b0380821691600160701b900416612a78565b80516020820151600c54611cd89291906001600160701b0380821691600160701b9004166000612138565b815160208084015160408051938452918301526001600160a01b038781169289821692918b16917fcd3829a3813dc3cdd188fd3d01dcf3268c16be2fdd2dd21d0665418816e46062910160405180910390a4506004805460ff1916905595945050505050565b6001600160a01b0383811660008181526002602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b6001600160a01b038316600090815260016020526040902054611dc4908290613483565b6001600160a01b038085166000908152600160205260408082209390935590841681522054611df49082906133e3565b6001600160a01b0380841660008181526001602052604090819020939093559151908516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90611d939085815260200190565b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663017e7e586040518163ffffffff1660e01b815260040160206040518083038186803b158015611ea457600080fd5b505afa158015611eb8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611edc919061302e565b600a546001600160a01b03821615801594509192509061202357801561201e576000611f176109b56001600160701b03808816908916613464565b90506000611f2483612037565b90508082111561201b576000611f3a8284613483565b600054611f479190613464565b90506000600460019054906101000a90046001600160a01b03166001600160a01b031663b85f9f0b6040518163ffffffff1660e01b815260040160206040518083038186803b158015611f9957600080fd5b505afa158015611fad573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fd19190613266565b90506000836064611fe28488613464565b611fec9190613421565b611ff691906133e3565b905060006120048285613421565b905080156120165761201688826120a7565b505050505b50505b61202f565b801561202f576000600a555b505092915050565b600060038211156120985750806000612051600283613421565b61205c9060016133e3565b90505b81811015612092579050806002816120778186613421565b61208191906133e3565b61208b9190613421565b905061205f565b506120a2565b81156120a2575060015b919050565b806000546120b591906133e3565b60009081556001600160a01b0383168152600160205260409020546120db9082906133e3565b6001600160a01b0383166000818152600160205260408082209390935591519091907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9061212c9085815260200190565b60405180910390a35050565b6001600160701b03851180159061215657506001600160701b038411155b61219a5760405162461bcd60e51b8152602060048201526015602482015274414d4d2e5f7570646174653a204f564552464c4f5760581b6044820152606401610622565b60006121ab6401000000004261350a565b600c549091506000906121cb90600160e01b900463ffffffff168361349a565b905060008163ffffffff161180156121eb57506001600160701b03851615155b80156121ff57506001600160701b03841615155b15612371578063ffffffff166122278661221887612cdf565b6001600160e01b031690612cfe565b6001600160e01b031661223a9190613464565b6008600082825461224b91906133e3565b909155505063ffffffff81166122648561221888612cdf565b6001600160e01b03166122779190613464565b6009600082825461228891906133e3565b92505081905550600460019054906101000a90046001600160a01b03166001600160a01b0316632630c12f6040518163ffffffff1660e01b815260040160206040518083038186803b1580156122dd57600080fd5b505afa1580156122f1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612315919061302e565b604051630422bb0160e41b81523060048201526001600160a01b03919091169063422bb01090602401600060405180830381600087803b15801561235857600080fd5b505af115801561236c573d6000803e3d6000fd5b505050505b6000600d5461237e612d1a565b6123889190613483565b90506000811180156123a257506001600160701b03861615155b156123c1576123b48661221887612cdf565b6001600160e01b0316600b555b600b541580156123d057508715155b806123d85750835b156123f7576123ea8861221889612cdf565b6001600160e01b0316600b555b600c80546001600160701b03898116600160701b026dffffffffffffffffffffffffffff60701b19918c166dffffffffffffffffffffffffffff199093169290921716179055612445612d1a565b600d55600c80546001600160e01b0316600160e01b63ffffffff8616021790819055604080516001600160701b038084168252600160701b90930490921660208301527f1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1910160405180910390a15050505050505050565b604080518082018252601981527f7472616e7366657228616464726573732c75696e74323536290000000000000060209182015281516001600160a01b0385811660248301526044808301869052845180840390910181526064909201845291810180516001600160e01b031663a9059cbb60e01b1790529151600092839287169161254991906132a2565b6000604051808303816000865af19150503d8060008114612586576040519150601f19603f3d011682016040523d82523d6000602084013e61258b565b606091505b50915091508180156125b55750805115806125b55750808060200190518101906125b59190613246565b61260c5760405162461bcd60e51b815260206004820152602260248201527f414d4d2e5f736166655472616e736665723a205452414e534645525f4641494c604482015261115160f21b6064820152608401610622565b5050505050565b6001600160a01b038216600090815260016020526040902054612637908290613483565b6001600160a01b0383166000908152600160205260408120919091555461265f908290613483565b60009081556040518281526001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200161212c565b6126a7612ff4565b6126af612ff4565b6005546001600160a01b03878116911614806126d857506006546001600160a01b038781169116145b6127305760405162461bcd60e51b8152602060048201526024808201527f416d6d2e5f657374696d617465537761703a2057524f4e475f494e5055545f5460448201526327a5a2a760e11b6064820152608401610622565b6005546001600160a01b038681169116148061275957506006546001600160a01b038681169116145b6127b35760405162461bcd60e51b815260206004820152602560248201527f416d6d2e5f657374696d617465537761703a2057524f4e475f4f55545055545f6044820152642a27a5a2a760d91b6064820152608401610622565b846001600160a01b0316866001600160a01b031614156128155760405162461bcd60e51b815260206004820152601e60248201527f416d6d2e5f657374696d617465537761703a2053414d455f544f4b454e5300006044820152606401610622565b60008411806128245750600083115b61287f5760405162461bcd60e51b815260206004820152602660248201527f416d6d2e5f657374696d617465537761703a20494e53554646494349454e545f604482015265105353d5539560d21b6064820152608401610622565b60008061288a610523565b50915091506000806000881180156128aa57506001600160a01b038a1615155b15612962576005546001600160a01b038b811691161415612913576128e288856001600160701b0316856001600160701b0316612db6565b96506128f7886001600160701b0386166133e3565b915061290c876001600160701b038516613483565b905061295d565b61293088846001600160701b0316866001600160701b0316612db6565b9650612945876001600160701b038616613483565b915061295a886001600160701b0385166133e3565b90505b612a44565b6005546001600160a01b038a8116911614156129d257836001600160701b031687106129a05760405162461bcd60e51b815260040161062290613359565b6129bd87846001600160701b0316866001600160701b0316612ed8565b9750612945876001600160701b038616613483565b826001600160701b031687106129fa5760405162461bcd60e51b815260040161062290613359565b612a1787856001600160701b0316856001600160701b0316612ed8565b9750612a2c886001600160701b0386166133e3565b9150612a41876001600160701b038516613483565b90505b6040805180820182529283526020808401929092528051808201909152978852870195909552509296939550929350505050565b6000612a8d6001600160701b03841685613464565b612a98906064613464565b90506000612aaf6001600160701b03841687613464565b90506000600460019054906101000a90046001600160a01b03166001600160a01b0316638ff471f76040518163ffffffff1660e01b815260040160206040518083038186803b158015612b0157600080fd5b505afa158015612b15573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b399190613266565b905081612b478260646133e3565b612b519190613464565b83108015612b73575081612b66826064613483565b612b709190613464565b83115b612be55760405162461bcd60e51b815260206004820152603c60248201527f414d4d2e5f7570646174653a2054524144494e47534c4950504147455f544f4f60448201527f5f4c415247455f5448414e5f4c4153545f5452414e53414354494f4e000000006064820152608401610622565b600b54600160701b9088612bfa8460646133e3565b612c049190613464565b612c0e9190613464565b612c189190613421565b612c23876064613464565b108015612c6b5750600b54600160701b9088612c40846064613483565b612c4a9190613464565b612c549190613464565b612c5e9190613421565b612c69876064613464565b115b612cd65760405162461bcd60e51b815260206004820152603660248201527f414d4d2e5f7570646174653a2054524144494e47534c4950504147455f544f4f6044820152755f4c415247455f5448414e5f4c4153545f424c4f434b60501b6064820152608401610622565b50505050505050565b6000612cf8600160701b6001600160701b038416613435565b92915050565b6000612d136001600160701b038316846133fb565b9392505050565b60004662066eeb811480612d2f57508061a4b1145b15612dae5760646001600160a01b031663a3b1b31d6040518163ffffffff1660e01b815260040160206040518083038186803b158015612d6e57600080fd5b505afa158015612d82573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612da69190613266565b915050612db3565b439150505b90565b6000808411612e1c5760405162461bcd60e51b815260206004820152602c60248201527f416d6d2e5f676574416d6f756e744f75743a20494e53554646494349454e545f60448201526b125394155517d05353d5539560a21b6064820152608401610622565b600083118015612e2c5750600082115b612e8a5760405162461bcd60e51b815260206004820152602960248201527f416d6d2e5f676574416d6f756e744f75743a20494e53554646494349454e545f6044820152684c495155494449545960b81b6064820152608401610622565b6000612e98856103e7613464565b90506000612ea68483613464565b9050600082612eb7876103e8613464565b612ec191906133e3565b9050612ecd8183613421565b979650505050505050565b6000808411612f3e5760405162461bcd60e51b815260206004820152602c60248201527f416d6d2e5f676574416d6f756e74496e3a20494e53554646494349454e545f4f60448201526b155514155517d05353d5539560a21b6064820152608401610622565b600083118015612f4e5750600082115b612fab5760405162461bcd60e51b815260206004820152602860248201527f416d6d2e5f676574416d6f756e74496e3a20494e53554646494349454e545f4c604482015267495155494449545960c01b6064820152608401610622565b6000612fb78585613464565b612fc3906103e8613464565b90506000612fd18685613483565b612fdd906103e7613464565b9050612fe98183613421565b6118269060016133e3565b60405180604001604052806002906020820280368337509192915050565b600060208284031215613023578081fd5b8135612d138161354a565b60006020828403121561303f578081fd5b8151612d138161354a565b6000806040838503121561305c578081fd5b82356130678161354a565b915060208301356130778161354a565b809150509250929050565b600080600060608486031215613096578081fd5b83356130a18161354a565b925060208401356130b18161354a565b915060408401356130c18161354a565b809150509250925092565b600080600080600060a086880312156130e3578081fd5b85356130ee8161354a565b945060208601356130fe8161354a565b9350604086013561310e8161354a565b94979396509394606081013594506080013592915050565b60008060006060848603121561313a578283fd5b83356131458161354a565b925060208401356131558161354a565b929592945050506040919091013590565b6000806000806080858703121561317b578384fd5b84356131868161354a565b935060208501356131968161354a565b93969395505050506040820135916060013590565b600080600080600080600060e0888a0312156131c5578182fd5b87356131d08161354a565b965060208801356131e08161354a565b9550604088013594506060880135935060808801356131fe81613562565b9699959850939692959460a0840135945060c09093013592915050565b6000806040838503121561322d578182fd5b82356132388161354a565b946020939093013593505050565b600060208284031215613257578081fd5b81518015158114612d13578182fd5b600060208284031215613277578081fd5b5051919050565b60008060408385031215613290578182fd5b82519150602083015161307781613562565b600082516132b48184602087016134bf565b9190910192915050565b60408101818360005b60028110156132e65781518352602092830192909101906001016132c7565b50505092915050565b600060208252825180602084015261330e8160408501602087016134bf565b601f01601f19169190910160400192915050565b60208082526019908201527f5265656e7472616e743a207265656e7472616e742063616c6c00000000000000604082015260600190565b60208082526029908201527f414d4d2e5f657374696d617465537761703a20494e53554646494349454e545f6040820152684c495155494449545960b81b606082015260800190565b600080821280156001600160ff1b03849003851316156133c4576133c461351e565b600160ff1b83900384128116156133dd576133dd61351e565b50500190565b600082198211156133f6576133f661351e565b500190565b60006001600160e01b038381168061341557613415613534565b92169190910492915050565b60008261343057613430613534565b500490565b60006001600160e01b038281168482168115158284048211161561345b5761345b61351e565b02949350505050565b600081600019048311821515161561347e5761347e61351e565b500290565b6000828210156134955761349561351e565b500390565b600063ffffffff838116908316818110156134b7576134b761351e565b039392505050565b60005b838110156134da5781810151838201526020016134c2565b838111156134e9576000848401525b50505050565b60006000198214156135035761350361351e565b5060010190565b60008261351957613519613534565b500690565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b6001600160a01b038116811461355f57600080fd5b50565b60ff8116811461355f57600080fdfea26469706673582212207be797794c2d35f28ba63893e5e99be3584ad6278fde2c29ff3432442375923664736f6c63430008020033a2646970667358221220ccb7e7fe13f59c3ed8c022cfa36dc94737f7ce55a8ea1d20ba277995d60db4d664736f6c63430008020033000000000000000000000000623ff58c87e4128ec628da4670c311103d31af1a0000000000000000000000007faaf13e445771fd3eef01acd1f24e39ca889d11000000000000000000000000845f67df76391f91a2d378d3c13006456592c939

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106100935760003560e01c806365cc7a1d1161006657806365cc7a1d1461010257806379502c5514610136578063a2e74af61461015d578063cedc12d814610170578063f46901ed1461019757610093565b8063017e7e5814610098578063094b7415146100c757806335e30d41146100da5780635131c85b146100ef575b600080fd5b6000546100ab906001600160a01b031681565b6040516001600160a01b03909116815260200160405180910390f35b6001546100ab906001600160a01b031681565b6100ed6100e83660046107e8565b6101aa565b005b6100ab6100fd3660046107b0565b61039e565b6100ab6101103660046107b0565b60026020908152600092835260408084209091529082529020546001600160a01b031681565b6100ab7f0000000000000000000000007faaf13e445771fd3eef01acd1f24e39ca889d1181565b6100ed61016b366004610771565b610660565b6100ab7f000000000000000000000000623ff58c87e4128ec628da4670c311103d31af1a81565b6100ed6101a5366004610771565b6106e8565b336001600160a01b037f000000000000000000000000623ff58c87e4128ec628da4670c311103d31af1a161461021f5760405162461bcd60e51b815260206004820152601560248201527420b6b6a330b1ba37b93c9d102327a92124a22222a760591b60448201526064015b60405180910390fd5b6001600160a01b03838116600081815260026020908152604080832087861680855292529182902054915163c0c53b8b60e01b815260048101939093526024830152838316604483015290911690819063c0c53b8b90606401600060405180830381600087803b15801561029257600080fd5b505af11580156102a6573d6000803e3d6000fd5b505050507f0000000000000000000000007faaf13e445771fd3eef01acd1f24e39ca889d116001600160a01b0316632630c12f6040518163ffffffff1660e01b815260040160206040518083038186803b15801561030357600080fd5b505afa158015610317573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061033b9190610794565b604051637b2bb85d60e11b81526001600160a01b038381166004830152919091169063f65770ba90602401600060405180830381600087803b15801561038057600080fd5b505af1158015610394573d6000803e3d6000fd5b5050505050505050565b6000336001600160a01b037f000000000000000000000000623ff58c87e4128ec628da4670c311103d31af1a16146104105760405162461bcd60e51b815260206004820152601560248201527420b6b6a330b1ba37b93c9d102327a92124a22222a760591b6044820152606401610216565b816001600160a01b0316836001600160a01b031614156104845760405162461bcd60e51b815260206004820152602960248201527f416d6d466163746f72792e637265617465416d6d3a204944454e544943414c5f60448201526841444452455353455360b81b6064820152608401610216565b6001600160a01b038316158015906104a457506001600160a01b03821615155b6104fb5760405162461bcd60e51b815260206004820152602260248201527f416d6d466163746f72792e637265617465416d6d3a205a45524f5f4144445245604482015261535360f01b6064820152608401610216565b6001600160a01b038381166000908152600260209081526040808320868516845290915290205416156105705760405162461bcd60e51b815260206004820152601f60248201527f416d6d466163746f72792e637265617465416d6d3a20414d4d5f4558495354006044820152606401610216565b6040516bffffffffffffffffffffffff19606085811b8216602084015284901b1660348201526000906048016040516020818303038152906040528051906020012090506000604051806020016105c690610764565b6020820181038252601f19601f820116604052509050818151602083016000f56001600160a01b0386811660008181526002602090815260408083208a86168085529083529281902080546001600160a01b0319169587169586179055519384529396509290917f8eef5cf520576c00176a77de7eeee6762c3f44c7231914ce6c5c01e03a703820910160405180910390a3505092915050565b6001546001600160a01b031633146106c65760405162461bcd60e51b8152602060048201526024808201527f416d6d466163746f72792e736574466565546f5365747465723a20464f524249604482015263222222a760e11b6064820152608401610216565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b6001546001600160a01b031633146107425760405162461bcd60e51b815260206004820152601e60248201527f416d6d466163746f72792e736574466565546f3a20464f5242494444454e00006044820152606401610216565b600080546001600160a01b0319166001600160a01b0392909216919091179055565b6136db8061084b83390190565b600060208284031215610782578081fd5b813561078d81610832565b9392505050565b6000602082840312156107a5578081fd5b815161078d81610832565b600080604083850312156107c2578081fd5b82356107cd81610832565b915060208301356107dd81610832565b809150509250929050565b6000806000606084860312156107fc578081fd5b833561080781610832565b9250602084013561081781610832565b9150604084013561082781610832565b809150509250925092565b6001600160a01b038116811461084757600080fd5b5056fe60c060405234801561001057600080fd5b506040805180820182526007815266041504558204c560cc1b6020918201528151808301835260018152603160f81b9082015281517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f918101919091527f61b9d5b67636ce161ec7cadd1dad2e234b7b19f7846bc9e1c0e66fc72bb44376918101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6606082015246608082018190523060a08301529060c00160408051601f198184030181529190528051602090910120608052503360601b60a05260805160a05160601c6135a76101346000396000818161049d0152818161183b015281816118f50152611e4d01526000818161031d0152611a0d01526135a76000f3fe608060405234801561001057600080fd5b50600436106101e55760003560e01c806379502c551161010f578063ba9a7a56116100a2578063c55dae6311610071578063c55dae63146104bf578063d505accf146104d2578063dd62ed3e146104e5578063e343fe1214610510576101e5565b8063ba9a7a561461045c578063bc93657614610465578063c0c53b8b14610485578063c45a015514610498576101e5565b806395d89b41116100de57806395d89b4114610406578063988370a31461042c578063a9059cbb14610441578063af14052c14610454576101e5565b806379502c55146103a85780637ecebe00146103c057806389afcb44146103e05780638f76691a146103f3576101e5565b806330adf81f116101875780635a3d5493116101565780635a3d5493146103485780636a6278421461035157806370a082311461037f5780637464fc3d1461039f576101e5565b806330adf81f146102d7578063313ce567146102fe5780633644e515146103185780635909c0d51461033f576101e5565b8063095ea7b3116101c3578063095ea7b31461026d57806318160ddd14610290578063217a4b701461029957806323b872dd146102c4576101e5565b8063053f14da146101ea57806306fdde03146102065780630902f1ac14610239575b600080fd5b6101f3600b5481565b6040519081526020015b60405180910390f35b61022c60405180604001604052806007815260200166041504558204c560cc1b81525081565b6040516101fd91906132ef565b610241610523565b604080516001600160701b03948516815293909216602084015263ffffffff16908201526060016101fd565b61028061027b36600461321b565b61054d565b60405190151581526020016101fd565b6101f360005481565b6006546102ac906001600160a01b031681565b6040516001600160a01b0390911681526020016101fd565b6102806102d2366004613126565b610563565b6101f37f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c981565b610306601281565b60405160ff90911681526020016101fd565b6101f37f000000000000000000000000000000000000000000000000000000000000000081565b6101f360085481565b6101f360095481565b61036461035f366004613012565b6105f8565b604080519384526020840192909252908201526060016101fd565b6101f361038d366004613012565b60016020526000908152604090205481565b6101f3600a5481565b6004546102ac9061010090046001600160a01b031681565b6101f36103ce366004613012565b60036020526000908152604090205481565b6103646103ee366004613012565b610bca565b6007546102ac906001600160a01b031681565b61022c604051806040016040528060078152602001660415045582d4c560cc1b81525081565b61043f61043a3660046130cc565b610e8d565b005b61028061044f36600461321b565b6111a1565b6101f36111ae565b6101f36103e881565b610478610473366004613166565b611812565b6040516101fd91906132be565b61043f610493366004613082565b611830565b6102ac7f000000000000000000000000000000000000000000000000000000000000000081565b6005546102ac906001600160a01b031681565b61043f6104e03660046131ab565b6119a1565b6101f36104f336600461304a565b600260209081526000928352604080842090915290825290205481565b61047861051e3660046130cc565b611be5565b600c546001600160701b0380821692600160701b830490911691600160e01b900463ffffffff1690565b600061055a338484611d3e565b50600192915050565b6001600160a01b0383166000908152600260209081526040808320338452909152812054600019146105e3576001600160a01b03841660009081526002602090815260408083203384529091529020546105be908390613483565b6001600160a01b03851660009081526002602090815260408083203384529091529020555b6105ee848484611da0565b5060019392505050565b6004546000908190819060ff161561062b5760405162461bcd60e51b815260040161062290613322565b60405180910390fd5b6004805460ff19166001179055600080610643610523565b50915091506000600760009054906101000a90046001600160a01b03166001600160a01b031663833b0acb6040518163ffffffff1660e01b815260040160206040518083038186803b15801561069857600080fd5b505afa1580156106ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106d09190613266565b9050600160701b6106ea826001600160701b0386166133a2565b13156107385760405162461bcd60e51b815260206004820181905260248201527f416d6d2e6d696e743a4e6574506f736974696f6e5f56414c55455f57524f4e546044820152606401610622565b600061074d826001600160701b0386166133a2565b6005546040516370a0823160e01b815230600482015291925082916001600160a01b03909116906370a082319060240160206040518083038186803b15801561079557600080fd5b505afa1580156107a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107cd9190613266565b97506000881161081f5760405162461bcd60e51b815260206004820152601a60248201527f416d6d2e6d696e743a205a45524f5f424153455f414d4f554e540000000000006044820152606401610622565b600061082b8686611e48565b600054909150806109d857600460019054906101000a90046001600160a01b03166001600160a01b0316632630c12f6040518163ffffffff1660e01b815260040160206040518083038186803b15801561088457600080fd5b505afa158015610898573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108bc919061302e565b600554600654604051632d9198e160e21b81526001600160a01b0392831660048201529082166024820152604481018d905291169063b646638490606401604080518083038186803b15801561091157600080fd5b505afa158015610925573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610949919061327e565b509850886109a55760405162461bcd60e51b815260206004820152602360248201527f416d6d2e6d696e743a20494e53554646494349454e545f51554f54455f414d4f60448201526215539560ea1b6064820152608401610622565b6103e86109ba6109b58b8d613464565b612037565b6109c49190613483565b97506109d360006103e86120a7565b610a1b565b866001600160701b0316866001600160701b03168b6109f79190613464565b610a019190613421565b985082610a0e828c613464565b610a189190613421565b97505b60008811610a7b5760405162461bcd60e51b815260206004820152602760248201527f416d6d2e6d696e743a20494e53554646494349454e545f4c495155494449545960448201526617d3525395115160ca1b6064820152608401610622565b610a858b896120a7565b610ab7610a9b8b6001600160701b038a166133e3565b610aae8b6001600160701b038a166133e3565b89896000612138565b8115610ae057600c54610adc906001600160701b03600160701b820481169116613464565b600a555b600554600754610afd916001600160a01b0390811691168c6124bd565b6007546040516311f9fbc960e21b8152336004820152602481018c90526001600160a01b03909116906347e7ef2490604401600060405180830381600087803b158015610b4957600080fd5b505af1158015610b5d573d6000803e3d6000fd5b5050604080518d8152602081018d90529081018b90526001600160a01b038e1692503391507f458f5fa412d0f69b08dd84872b0215675cc67bc1d5b6fd93300a1c3878b86196906060015b60405180910390a350506004805460ff19169055509597949650929450505050565b6004546000908190819060ff1615610bf45760405162461bcd60e51b815260040161062290613322565b6004805460ff19166001179055600080610c0c610523565b5030600090815260016020908152604080832054600754825163833b0acb60e01b8152925191995095975093955091936001600160a01b03169263833b0acb926004808201939291829003018186803b158015610c6857600080fd5b505afa158015610c7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ca09190613266565b90506000610cb7826001600160701b0386166133a2565b9050806000610cc68686611e48565b60005490915080610cd7848a613464565b610ce19190613421565b9950866001600160701b0316866001600160701b03168b610d029190613464565b610d0c9190613421565b985060008a118015610d1e5750600089115b610d7a5760405162461bcd60e51b815260206004820152602760248201527f416d6d2e6275726e3a20494e53554646494349454e545f4c495155494449545960448201526617d0955493915160ca1b6064820152608401610622565b610d843089612613565b610dad610d9a8b6001600160701b038a16613483565b610aae8b6001600160701b038a16613483565b8115610dd657600c54610dd2906001600160701b03600160701b820481169116613464565b600a555b600754604051636ce5768960e11b81523360048201526001600160a01b038d81166024830152604482018d90529091169063d9caed1290606401600060405180830381600087803b158015610e2a57600080fd5b505af1158015610e3e573d6000803e3d6000fd5b5050604080518d8152602081018d90529081018b90526001600160a01b038e1692503391507f4cf25bc1d991c17529c25213d3cc0cda295eeaad5f13f361969b12ea48015f9090606001610ba8565b60045460ff1615610eb05760405162461bcd60e51b815260040161062290613322565b6004805460ff191660011790556007546001600160a01b03163314610f0a5760405162461bcd60e51b815260206004820152601060248201526f20b6b69d1027a7262cafa6a0a923a4a760811b6044820152606401610622565b6005546001600160a01b0385811691161480610f3357506006546001600160a01b038581169116145b610f7f5760405162461bcd60e51b815260206004820181905260248201527f416d6d2e666f726365537761703a2057524f4e475f494e5055545f544f4b454e6044820152606401610622565b6005546001600160a01b0384811691161480610fa857506006546001600160a01b038481169116145b610ffe5760405162461bcd60e51b815260206004820152602160248201527f416d6d2e666f726365537761703a2057524f4e475f4f55545055545f544f4b456044820152602760f91b6064820152608401610622565b826001600160a01b0316846001600160a01b031614156110605760405162461bcd60e51b815260206004820152601a60248201527f416d6d2e666f726365537761703a2053414d455f544f4b454e530000000000006044820152606401610622565b60008061106b610523565b5091509150600061107c8383611e48565b60055490915060009081906001600160a01b038a8116911614156110c9576110ad876001600160701b0387166133e3565b91506110c2866001600160701b038616613483565b90506110f4565b6110dc866001600160701b038716613483565b91506110f1876001600160701b0386166133e3565b90505b611102828287876001612138565b821561112b57600c54611127906001600160701b03600160701b820481169116613464565b600a555b876001600160a01b0316896001600160a01b03168b6001600160a01b03167fa36e6e2023c9daa81ac16fbc0d2499822bc9617326793b1ec3ab50c90bcfe8728a8a604051611183929190918252602082015260400190565b60405180910390a450506004805460ff191690555050505050505050565b600061055a338484611da0565b60045460009060ff16156111d45760405162461bcd60e51b815260040161062290613322565b6004805460ff191660011790553332146112275760405162461bcd60e51b8152602060048201526014602482015273416d6d2e7265626173653a204f4e4c595f454f4160601b6044820152606401610622565b6000600460019054906101000a90046001600160a01b03166001600160a01b03166389edeb746040518163ffffffff1660e01b815260040160206040518083038186803b15801561127757600080fd5b505afa15801561128b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112af9190613266565b905080600e54426112c09190613483565b101561131d5760405162461bcd60e51b815260206004820152602660248201527f416d6d2e7265626173653a204e4f545f52454143485f4e4558545f5245424153604482015265455f54494d4560d01b6064820152608401610622565b600080611328610523565b509150915060006113398383611e48565b90506000806000600460019054906101000a90046001600160a01b03166001600160a01b0316632630c12f6040518163ffffffff1660e01b815260040160206040518083038186803b15801561138e57600080fd5b505afa1580156113a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113c6919061302e565b600554600654604051632d9198e160e21b81526001600160a01b03928316600482015290821660248201526001600160701b038916604482015291169063b646638490606401604080518083038186803b15801561142357600080fd5b505afa158015611437573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061145b919061327e565b915091508060ff166000141561158057600460019054906101000a90046001600160a01b03166001600160a01b0316632630c12f6040518163ffffffff1660e01b815260040160206040518083038186803b1580156114b957600080fd5b505afa1580156114cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114f1919061302e565b6040516335201cc760e21b81523060048201526001600160701b03881660248201526001600160a01b03919091169063d480731c9060440160206040518083038186803b15801561154157600080fd5b505afa158015611555573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115799190613266565b92506115a9565b600160701b866001600160701b0316600b5461159c9190613464565b6115a69190613421565b92505b6000600460019054906101000a90046001600160a01b03166001600160a01b0316638ecb45516040518163ffffffff1660e01b815260040160206040518083038186803b1580156115f957600080fd5b505afa15801561160d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116319190613266565b905061163e8160646133e3565b6116489085613464565b611653846064613464565b10158061167e5750611666816064613483565b6116709085613464565b61167b846064613464565b11155b6116ca5760405162461bcd60e51b815260206004820181905260248201527f416d6d2e7265626173653a204e4f545f4245594f4e445f50524943455f4741506044820152606401610622565b6116d58160646133e3565b6116df9085613464565b6116ea846064613464565b1061171f5760646116fb82826133e3565b61170e906001600160701b038916613464565b6117189190613421565b985061174b565b606461172b8282613483565b61173e906001600160701b038916613464565b6117489190613421565b98505b61175a6401000000004261350a565b63ffffffff16600e5561177a6001600160701b0388168a89896001612138565b84156117a357600c5461179f906001600160701b03600160701b820481169116613464565b600a555b604080516001600160701b038881168252602082018c9052891681830152606081018690526080810185905290517fa904dcf42a3461c90173c0b966672b2cb4350e529ea12d44e562fcec438363249181900360a00190a150506004805460ff19169055509495945050505050565b61181a612ff4565b6118268585858561269f565b9695505050505050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146118a85760405162461bcd60e51b815260206004820152601960248201527f416d6d2e696e697469616c697a653a20464f5242494444454e000000000000006044820152606401610622565b600580546001600160a01b038086166001600160a01b03199283161790925560068054858416908316179055600780548484169216919091179055604080516379502c5560e01b815290517f0000000000000000000000000000000000000000000000000000000000000000909216916379502c5591600480820192602092909190829003018186803b15801561193e57600080fd5b505afa158015611952573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611976919061302e565b600460016101000a8154816001600160a01b0302191690836001600160a01b03160217905550505050565b428410156119f15760405162461bcd60e51b815260206004820152601760248201527f4c697175696469747945524332303a20455850495245440000000000000000006044820152606401610622565b6001600160a01b038716600090815260036020526040812080547f0000000000000000000000000000000000000000000000000000000000000000917f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9918b918b918b9187611a5f836134ef565b909155506040805160208101969096526001600160a01b0394851690860152929091166060840152608083015260a082015260c0810187905260e00160405160208183030381529060405280519060200120604051602001611ad892919061190160f01b81526002810192909252602282015260420190565b60408051601f198184030181528282528051602091820120600080855291840180845281905260ff88169284019290925260608301869052608083018590529092509060019060a0016020604051602081039080840390855afa158015611b43573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b03811615801590611b795750886001600160a01b0316816001600160a01b0316145b611bcf5760405162461bcd60e51b815260206004820152602160248201527f4c697175696469747945524332303a20494e56414c49445f5349474e415455526044820152604560f81b6064820152608401610622565b611bda898989611d3e565b505050505050505050565b611bed612ff4565b60045460ff1615611c105760405162461bcd60e51b815260040161062290613322565b6004805460ff191660011790556007546001600160a01b03163314611c6a5760405162461bcd60e51b815260206004820152601060248201526f20b6b69d1027a7262cafa6a0a923a4a760811b6044820152606401610622565b611c72612ff4565b611c7e8686868661269f565b81516020830151600c54929550929350611cad9290916001600160701b0380821691600160701b900416612a78565b80516020820151600c54611cd89291906001600160701b0380821691600160701b9004166000612138565b815160208084015160408051938452918301526001600160a01b038781169289821692918b16917fcd3829a3813dc3cdd188fd3d01dcf3268c16be2fdd2dd21d0665418816e46062910160405180910390a4506004805460ff1916905595945050505050565b6001600160a01b0383811660008181526002602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b6001600160a01b038316600090815260016020526040902054611dc4908290613483565b6001600160a01b038085166000908152600160205260408082209390935590841681522054611df49082906133e3565b6001600160a01b0380841660008181526001602052604090819020939093559151908516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90611d939085815260200190565b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663017e7e586040518163ffffffff1660e01b815260040160206040518083038186803b158015611ea457600080fd5b505afa158015611eb8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611edc919061302e565b600a546001600160a01b03821615801594509192509061202357801561201e576000611f176109b56001600160701b03808816908916613464565b90506000611f2483612037565b90508082111561201b576000611f3a8284613483565b600054611f479190613464565b90506000600460019054906101000a90046001600160a01b03166001600160a01b031663b85f9f0b6040518163ffffffff1660e01b815260040160206040518083038186803b158015611f9957600080fd5b505afa158015611fad573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fd19190613266565b90506000836064611fe28488613464565b611fec9190613421565b611ff691906133e3565b905060006120048285613421565b905080156120165761201688826120a7565b505050505b50505b61202f565b801561202f576000600a555b505092915050565b600060038211156120985750806000612051600283613421565b61205c9060016133e3565b90505b81811015612092579050806002816120778186613421565b61208191906133e3565b61208b9190613421565b905061205f565b506120a2565b81156120a2575060015b919050565b806000546120b591906133e3565b60009081556001600160a01b0383168152600160205260409020546120db9082906133e3565b6001600160a01b0383166000818152600160205260408082209390935591519091907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9061212c9085815260200190565b60405180910390a35050565b6001600160701b03851180159061215657506001600160701b038411155b61219a5760405162461bcd60e51b8152602060048201526015602482015274414d4d2e5f7570646174653a204f564552464c4f5760581b6044820152606401610622565b60006121ab6401000000004261350a565b600c549091506000906121cb90600160e01b900463ffffffff168361349a565b905060008163ffffffff161180156121eb57506001600160701b03851615155b80156121ff57506001600160701b03841615155b15612371578063ffffffff166122278661221887612cdf565b6001600160e01b031690612cfe565b6001600160e01b031661223a9190613464565b6008600082825461224b91906133e3565b909155505063ffffffff81166122648561221888612cdf565b6001600160e01b03166122779190613464565b6009600082825461228891906133e3565b92505081905550600460019054906101000a90046001600160a01b03166001600160a01b0316632630c12f6040518163ffffffff1660e01b815260040160206040518083038186803b1580156122dd57600080fd5b505afa1580156122f1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612315919061302e565b604051630422bb0160e41b81523060048201526001600160a01b03919091169063422bb01090602401600060405180830381600087803b15801561235857600080fd5b505af115801561236c573d6000803e3d6000fd5b505050505b6000600d5461237e612d1a565b6123889190613483565b90506000811180156123a257506001600160701b03861615155b156123c1576123b48661221887612cdf565b6001600160e01b0316600b555b600b541580156123d057508715155b806123d85750835b156123f7576123ea8861221889612cdf565b6001600160e01b0316600b555b600c80546001600160701b03898116600160701b026dffffffffffffffffffffffffffff60701b19918c166dffffffffffffffffffffffffffff199093169290921716179055612445612d1a565b600d55600c80546001600160e01b0316600160e01b63ffffffff8616021790819055604080516001600160701b038084168252600160701b90930490921660208301527f1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1910160405180910390a15050505050505050565b604080518082018252601981527f7472616e7366657228616464726573732c75696e74323536290000000000000060209182015281516001600160a01b0385811660248301526044808301869052845180840390910181526064909201845291810180516001600160e01b031663a9059cbb60e01b1790529151600092839287169161254991906132a2565b6000604051808303816000865af19150503d8060008114612586576040519150601f19603f3d011682016040523d82523d6000602084013e61258b565b606091505b50915091508180156125b55750805115806125b55750808060200190518101906125b59190613246565b61260c5760405162461bcd60e51b815260206004820152602260248201527f414d4d2e5f736166655472616e736665723a205452414e534645525f4641494c604482015261115160f21b6064820152608401610622565b5050505050565b6001600160a01b038216600090815260016020526040902054612637908290613483565b6001600160a01b0383166000908152600160205260408120919091555461265f908290613483565b60009081556040518281526001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200161212c565b6126a7612ff4565b6126af612ff4565b6005546001600160a01b03878116911614806126d857506006546001600160a01b038781169116145b6127305760405162461bcd60e51b8152602060048201526024808201527f416d6d2e5f657374696d617465537761703a2057524f4e475f494e5055545f5460448201526327a5a2a760e11b6064820152608401610622565b6005546001600160a01b038681169116148061275957506006546001600160a01b038681169116145b6127b35760405162461bcd60e51b815260206004820152602560248201527f416d6d2e5f657374696d617465537761703a2057524f4e475f4f55545055545f6044820152642a27a5a2a760d91b6064820152608401610622565b846001600160a01b0316866001600160a01b031614156128155760405162461bcd60e51b815260206004820152601e60248201527f416d6d2e5f657374696d617465537761703a2053414d455f544f4b454e5300006044820152606401610622565b60008411806128245750600083115b61287f5760405162461bcd60e51b815260206004820152602660248201527f416d6d2e5f657374696d617465537761703a20494e53554646494349454e545f604482015265105353d5539560d21b6064820152608401610622565b60008061288a610523565b50915091506000806000881180156128aa57506001600160a01b038a1615155b15612962576005546001600160a01b038b811691161415612913576128e288856001600160701b0316856001600160701b0316612db6565b96506128f7886001600160701b0386166133e3565b915061290c876001600160701b038516613483565b905061295d565b61293088846001600160701b0316866001600160701b0316612db6565b9650612945876001600160701b038616613483565b915061295a886001600160701b0385166133e3565b90505b612a44565b6005546001600160a01b038a8116911614156129d257836001600160701b031687106129a05760405162461bcd60e51b815260040161062290613359565b6129bd87846001600160701b0316866001600160701b0316612ed8565b9750612945876001600160701b038616613483565b826001600160701b031687106129fa5760405162461bcd60e51b815260040161062290613359565b612a1787856001600160701b0316856001600160701b0316612ed8565b9750612a2c886001600160701b0386166133e3565b9150612a41876001600160701b038516613483565b90505b6040805180820182529283526020808401929092528051808201909152978852870195909552509296939550929350505050565b6000612a8d6001600160701b03841685613464565b612a98906064613464565b90506000612aaf6001600160701b03841687613464565b90506000600460019054906101000a90046001600160a01b03166001600160a01b0316638ff471f76040518163ffffffff1660e01b815260040160206040518083038186803b158015612b0157600080fd5b505afa158015612b15573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b399190613266565b905081612b478260646133e3565b612b519190613464565b83108015612b73575081612b66826064613483565b612b709190613464565b83115b612be55760405162461bcd60e51b815260206004820152603c60248201527f414d4d2e5f7570646174653a2054524144494e47534c4950504147455f544f4f60448201527f5f4c415247455f5448414e5f4c4153545f5452414e53414354494f4e000000006064820152608401610622565b600b54600160701b9088612bfa8460646133e3565b612c049190613464565b612c0e9190613464565b612c189190613421565b612c23876064613464565b108015612c6b5750600b54600160701b9088612c40846064613483565b612c4a9190613464565b612c549190613464565b612c5e9190613421565b612c69876064613464565b115b612cd65760405162461bcd60e51b815260206004820152603660248201527f414d4d2e5f7570646174653a2054524144494e47534c4950504147455f544f4f6044820152755f4c415247455f5448414e5f4c4153545f424c4f434b60501b6064820152608401610622565b50505050505050565b6000612cf8600160701b6001600160701b038416613435565b92915050565b6000612d136001600160701b038316846133fb565b9392505050565b60004662066eeb811480612d2f57508061a4b1145b15612dae5760646001600160a01b031663a3b1b31d6040518163ffffffff1660e01b815260040160206040518083038186803b158015612d6e57600080fd5b505afa158015612d82573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612da69190613266565b915050612db3565b439150505b90565b6000808411612e1c5760405162461bcd60e51b815260206004820152602c60248201527f416d6d2e5f676574416d6f756e744f75743a20494e53554646494349454e545f60448201526b125394155517d05353d5539560a21b6064820152608401610622565b600083118015612e2c5750600082115b612e8a5760405162461bcd60e51b815260206004820152602960248201527f416d6d2e5f676574416d6f756e744f75743a20494e53554646494349454e545f6044820152684c495155494449545960b81b6064820152608401610622565b6000612e98856103e7613464565b90506000612ea68483613464565b9050600082612eb7876103e8613464565b612ec191906133e3565b9050612ecd8183613421565b979650505050505050565b6000808411612f3e5760405162461bcd60e51b815260206004820152602c60248201527f416d6d2e5f676574416d6f756e74496e3a20494e53554646494349454e545f4f60448201526b155514155517d05353d5539560a21b6064820152608401610622565b600083118015612f4e5750600082115b612fab5760405162461bcd60e51b815260206004820152602860248201527f416d6d2e5f676574416d6f756e74496e3a20494e53554646494349454e545f4c604482015267495155494449545960c01b6064820152608401610622565b6000612fb78585613464565b612fc3906103e8613464565b90506000612fd18685613483565b612fdd906103e7613464565b9050612fe98183613421565b6118269060016133e3565b60405180604001604052806002906020820280368337509192915050565b600060208284031215613023578081fd5b8135612d138161354a565b60006020828403121561303f578081fd5b8151612d138161354a565b6000806040838503121561305c578081fd5b82356130678161354a565b915060208301356130778161354a565b809150509250929050565b600080600060608486031215613096578081fd5b83356130a18161354a565b925060208401356130b18161354a565b915060408401356130c18161354a565b809150509250925092565b600080600080600060a086880312156130e3578081fd5b85356130ee8161354a565b945060208601356130fe8161354a565b9350604086013561310e8161354a565b94979396509394606081013594506080013592915050565b60008060006060848603121561313a578283fd5b83356131458161354a565b925060208401356131558161354a565b929592945050506040919091013590565b6000806000806080858703121561317b578384fd5b84356131868161354a565b935060208501356131968161354a565b93969395505050506040820135916060013590565b600080600080600080600060e0888a0312156131c5578182fd5b87356131d08161354a565b965060208801356131e08161354a565b9550604088013594506060880135935060808801356131fe81613562565b9699959850939692959460a0840135945060c09093013592915050565b6000806040838503121561322d578182fd5b82356132388161354a565b946020939093013593505050565b600060208284031215613257578081fd5b81518015158114612d13578182fd5b600060208284031215613277578081fd5b5051919050565b60008060408385031215613290578182fd5b82519150602083015161307781613562565b600082516132b48184602087016134bf565b9190910192915050565b60408101818360005b60028110156132e65781518352602092830192909101906001016132c7565b50505092915050565b600060208252825180602084015261330e8160408501602087016134bf565b601f01601f19169190910160400192915050565b60208082526019908201527f5265656e7472616e743a207265656e7472616e742063616c6c00000000000000604082015260600190565b60208082526029908201527f414d4d2e5f657374696d617465537761703a20494e53554646494349454e545f6040820152684c495155494449545960b81b606082015260800190565b600080821280156001600160ff1b03849003851316156133c4576133c461351e565b600160ff1b83900384128116156133dd576133dd61351e565b50500190565b600082198211156133f6576133f661351e565b500190565b60006001600160e01b038381168061341557613415613534565b92169190910492915050565b60008261343057613430613534565b500490565b60006001600160e01b038281168482168115158284048211161561345b5761345b61351e565b02949350505050565b600081600019048311821515161561347e5761347e61351e565b500290565b6000828210156134955761349561351e565b500390565b600063ffffffff838116908316818110156134b7576134b761351e565b039392505050565b60005b838110156134da5781810151838201526020016134c2565b838111156134e9576000848401525b50505050565b60006000198214156135035761350361351e565b5060010190565b60008261351957613519613534565b500690565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b6001600160a01b038116811461355f57600080fd5b50565b60ff8116811461355f57600080fdfea26469706673582212207be797794c2d35f28ba63893e5e99be3584ad6278fde2c29ff3432442375923664736f6c63430008020033a2646970667358221220ccb7e7fe13f59c3ed8c022cfa36dc94737f7ce55a8ea1d20ba277995d60db4d664736f6c63430008020033

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

000000000000000000000000623ff58c87e4128ec628da4670c311103d31af1a0000000000000000000000007faaf13e445771fd3eef01acd1f24e39ca889d11000000000000000000000000845f67df76391f91a2d378d3c13006456592c939

-----Decoded View---------------
Arg [0] : upperFactory_ (address): 0x623Ff58C87E4128EC628da4670C311103D31aF1A
Arg [1] : config_ (address): 0x7FAaF13e445771fd3eEf01AcD1f24E39ca889d11
Arg [2] : feeToSetter_ (address): 0x845f67Df76391f91A2D378d3C13006456592c939

-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 000000000000000000000000623ff58c87e4128ec628da4670c311103d31af1a
Arg [1] : 0000000000000000000000007faaf13e445771fd3eef01acd1f24e39ca889d11
Arg [2] : 000000000000000000000000845f67df76391f91a2d378d3c13006456592c939


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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