ETH Price: $3,374.70 (+3.05%)
Gas: 4 Gwei

Contract

0x4f7903Ae97f1aD3665093417007d06e83b43C00C
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
0x60806040155883902022-09-22 10:49:23676 days ago1663843763IN
 Create: Vault
0 ETH0.021313594.70839419

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Vault

Compiler Version
v0.6.12+commit.27d51765

Optimization Enabled:
Yes with 1000 runs

Other Settings:
default evmVersion
File 1 of 6 : vault.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.6.12;
pragma experimental ABIEncoderV2;

import "./IERC20.sol";
// import "hardhat/console.sol";
import { Address } from "@openzeppelin/contracts/utils/Address.sol";
import "./trade_utils.sol";

/**
 * Math operations with safety checks
 */
library SafeMath {
    string private constant ERROR_MESSAGE = "SafeMath exception";
    function safeMul(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a * b;
        require(a == 0 || c / a == b, ERROR_MESSAGE);
        return c;
    }

    function safeDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b > 0, ERROR_MESSAGE);
        uint256 c = a / b;
        require(a == b * c + a % b, ERROR_MESSAGE);
        return c;
    }

    function safeSub(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b <= a, ERROR_MESSAGE);
        return a - b;
    }

    function safeAdd(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c>=a && c>=b, ERROR_MESSAGE);
        return c;
    }
}

/**
 * @title Counters
 * @author Matt Condon (@shrugs)
 * @dev Provides counters that can only be incremented or decremented by one. This can be used e.g. to track the number
 * of elements in a mapping, issuing ERC721 ids, or counting request ids.
 *
 * Include with `using Counters for Counters.Counter;`
 * Since it is not possible to overflow a 256 bit integer with increments of one, `increment` can skip the {SafeMath}
 * overflow check, thereby saving gas. This does assume however correct usage, in that the underlying `_value` is never
 * directly accessed.
 */
library Counters {
    using SafeMath for uint256;

    struct Counter {
        // This variable should never be directly accessed by users of the library: interactions must be restricted to
        // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add
        // this feature: see https://github.com/ethereum/solidity/issues/4637
        uint256 _value; // default: 0
    }

    function current(Counter storage counter) internal view returns (uint256) {
        return counter._value;
    }

    function increment(Counter storage counter) internal {
        // The {SafeMath} overflow check can be skipped here, see the comment at the top
        counter._value += 1;
    }

    function decrement(Counter storage counter) internal {
        counter._value = counter._value.safeSub(1);
    }
}


/**
 * @dev Interface of the contract capable of checking if an instruction is
 * confirmed over at Incognito Chain
 */
interface Incognito {
    function instructionApproved(
        bool,
        bytes32,
        uint,
        bytes32[] calldata,
        bool[] calldata,
        bytes32,
        bytes32,
        uint[] calldata,
        uint8[] calldata,
        bytes32[] calldata,
        bytes32[] calldata
    ) external view returns (bool);
}

/**
 * @dev Interface of the previous Vault contract to query burn proof status
 */
interface Withdrawable {
    function isWithdrawed(bytes32)  external view returns (bool);
    function isSigDataUsed(bytes32)  external view returns (bool);
    function getDepositedBalance(address, address)  external view returns (uint);
    function updateAssets(address[] calldata, uint[] calldata) external returns (bool);
    function paused() external view returns (bool);
}

/**
 * @dev Responsible for holding the assets and issue minting instruction to
 * Incognito Chain. Also, when presented with a burn proof created over at
 * Incognito Chain, releases the tokens back to user
 */
contract Vault {
    using SafeMath for uint;
    using Counters for Counters.Counter;
    /**
     * @dev Storage slot with the incognito proxy.
     * This is the keccak-256 hash of "eip1967.proxy.incognito." subtracted by 1
     */
    bytes32 private constant _INCOGNITO_SLOT = 0x62135fc083646fdb4e1a9d700e351b886a4a5a39da980650269edd1ade91ffd2;
    address constant public ETH_TOKEN = 0x0000000000000000000000000000000000000000;
    /**
     * @dev Storage variables for Vault
     * This section is APPEND-ONLY, in order to preserve upgradeability
     * since we use Proxy Pattern
     */
    mapping(bytes32 => bool) public withdrawed;
    mapping(bytes32 => bool) public sigDataUsed;
    // address => token => amount
    mapping(address => mapping(address => uint)) public withdrawRequests;
    mapping(address => mapping(address => bool)) public migration;
    mapping(address => uint) public totalDepositedToSCAmount;
    Withdrawable public prevVault;
    bool public notEntered;
    bool public isInitialized;
    /**
    * @dev Added in Storage Layout version : 2.0
    */
    uint8 constant public CURRENT_NETWORK_ID = 1; // Ethereum
    uint8 constant public BURN_REQUEST_METADATA_TYPE = 241;
    uint8 constant public BURN_TO_CONTRACT_REQUEST_METADATA_TYPE = 243;
    uint8 constant public BURN_CALL_REQUEST_METADATA_TYPE = 158;
    Counters.Counter private idCounter;

    address public regulator;
    uint256 public storageLayoutVersion;
    address public executor;
    /**
    * @dev END Storage variables version : 2.0
    */

    /**
    * @dev END Storage variables
    */

    struct BurnInstData {
        uint8 meta; // type of the instruction
        uint8 shard; // ID of the Incognito shard containing the instruction, must be 1
        address token; // ETH address of the token contract (0x0 for ETH)
        address payable to; // ETH address of the receiver of the token
        uint amount; // burned amount (on Incognito)
        bytes32 itx; // Incognito's burning tx
    }

    struct RedepositOptions {
        address redepositToken;
        bytes redepositIncAddress;
        address payable withdrawAddress;
    }

    struct ShieldInfo {
        address sender; // the guy shield request
        bytes32 tx; // txid which sent fund to core team's addresses
    }

    enum Prefix {
        ETHEREUM_EXECUTE_SIGNATURE,
        ETHEREUM_REQUEST_WITHDRAW_SIGNATURE,
        BSC_EXECUTE_SIGNATURE,
        BSC_REQUEST_WITHDRAW_SIGNATURE,
        PLG_EXECUTE_SIGNATURE,
        PLG_REQUEST_WITHDRAW_SIGNATURE,
        FTM_EXECUTE_SIGNATURE,
        FTM_REQUEST_WITHDRAW_SIGNATURE
    }

    // error code
    enum Errors {
        EMPTY,
        NO_REENTRANCE,
        MAX_UINT_REACHED,
        VALUE_OVER_FLOW,
        INTERNAL_TX_ERROR,
        ALREADY_USED, // 5
        INVALID_DATA,
        TOKEN_NOT_ENOUGH,
        WITHDRAW_REQUEST_TOKEN_NOT_ENOUGH,
        INVALID_RETURN_DATA,
        NOT_EQUAL, // 10
        NULL_VALUE,
        ONLY_PREVAULT,
        PREVAULT_NOT_PAUSED,
        SAFEMATH_EXCEPTION,
        ALREADY_INITIALIZED, // 15
        INVALID_SIGNATURE,
        NOT_AUTHORISED,
        ALREADY_UPGRADED,
        INVALID_DATA_BURN_CALL_INST,
        ONLY_SELF_CALL
    }

    event Deposit(address token, string incognitoAddress, uint amount);
    event Withdraw(address token, address to, uint amount);
    event UpdateTokenTotal(address[] assets, uint[] amounts);
    event UpdateIncognitoProxy(address newIncognitoProxy);
    event Redeposit(address token, bytes redepositIncAddress, uint256 amount, bytes32 itx);
    event DepositV2(address token, string incognitoAddress, uint amount, uint256 depositID);
    event ExecuteFnLog(bytes32 id, uint256 phaseID, bytes errorData);

    /**
     * modifier for contract version
     */
    modifier onlyPreVault(){
        require(address(prevVault) != address(0x0) && msg.sender == address(prevVault), errorToString(Errors.ONLY_PREVAULT));
        _;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and make it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        // On the first call to nonReentrant, notEntered will be true
        require(notEntered, errorToString(Errors.NO_REENTRANCE));

        // Any calls to nonReentrant after this point will fail
        notEntered = false;

        _;

        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        notEntered = true;
    }

    /**
     * @dev Creates new Vault to hold assets for Incognito Chain
     * @param _prevVault: previous version of the Vault to refer back if necessary
     * @param _regulator: ...
     * @param _executor: helper contract to perform external call from
     * After migrating all assets to a new Vault, we still need to refer
     * back to previous Vault to make sure old withdrawals aren't being reused
     */
    function initialize(address _prevVault, address _regulator, address _executor) external {
        require(!isInitialized, errorToString(Errors.ALREADY_INITIALIZED));
        prevVault = Withdrawable(_prevVault);
        isInitialized = true;
        notEntered = true;
        require(regulator == address(0x0), errorToString(Errors.NOT_AUTHORISED));
        regulator = _regulator;
        executor = _executor;
        storageLayoutVersion = 2;
    }

    /**
     * @dev upgrade helper for storage layout version 2
     * @param _regulator: ...
     * @param _executor: helper contract to perform external call from
     */
    function upgradeVaultStorage(address _regulator, address _executor) external {
        // storageLayoutVersion is a new variable introduced in this storage layout version, then set to 2 to match the storage layout version itself
        require(storageLayoutVersion == 0, errorToString(Errors.ALREADY_UPGRADED));
        // make sure the version increase can only happen once
        storageLayoutVersion = 2;
        require(regulator == address(0x0), errorToString(Errors.NOT_AUTHORISED));
        regulator = _regulator;
        executor = _executor;
    }

    /**
     * @dev Returns the current incognito proxy.
     */
    function _incognito() internal view returns (address icg) {
        bytes32 slot = _INCOGNITO_SLOT;
        // solhint-disable-next-line no-inline-assembly
        assembly {
            icg := sload(slot)
        }
    }

    /**
     * @dev Makes a ETH deposit to the vault to mint pETH over at Incognito Chain
     * @notice This only works when the contract is not Paused
     * @notice The maximum amount to deposit is capped since Incognito balance is stored as uint64
     * @param incognitoAddress: Incognito Address to receive pETH
     * @param txId: move fund transaction hash
     * @param signData: regulator signature
     */
    function deposit(string calldata incognitoAddress, bytes32 txId, bytes calldata signData) external payable nonReentrant {
        require(address(this).balance <= 10 ** 27, errorToString(Errors.MAX_UINT_REACHED));
        verifyRegulator(txId, signData);

        emit Deposit(ETH_TOKEN, incognitoAddress, msg.value);
    }

    /**
     * @dev Makes a ERC20 deposit to the vault to mint pERC20 over at Incognito Chain
     * @notice This only works when the contract is not Paused
     * @notice The maximum amount to deposit is capped since Incognito balance is stored as uint64
     * @notice Before calling this function, enough ERC20 must be allowed to
     * tranfer from msg.sender to this contract
     * @param token: address of the ERC20 token
     * @param amount: to deposit to the vault and mint on Incognito Chain
     * @param incognitoAddress: Incognito Address to receive pERC20
     * @param txId: move fund transaction hash
     * @param signData: regulator signature
     */
    function depositERC20(address token, uint amount, string calldata incognitoAddress, bytes32 txId, bytes calldata signData) external nonReentrant {
        verifyRegulator(txId, signData);

        IERC20 erc20Interface = IERC20(token);
        uint8 decimals = getDecimals(address(token));
        uint tokenBalance = erc20Interface.balanceOf(address(this));
        uint beforeTransfer = tokenBalance;
        uint emitAmount = amount;
        if (decimals > 9) {
            emitAmount = emitAmount / (10 ** (uint(decimals) - 9));
            tokenBalance = tokenBalance / (10 ** (uint(decimals) - 9));
        }
        require(emitAmount <= 10 ** 18 && tokenBalance <= 10 ** 18 && emitAmount.safeAdd(tokenBalance) <= 10 ** 18, errorToString(Errors.VALUE_OVER_FLOW));
        erc20Interface.transferFrom(msg.sender, address(this), amount);
        require(checkSuccess(), errorToString(Errors.INTERNAL_TX_ERROR));
        require(balanceOf(token).safeSub(beforeTransfer) == amount, errorToString(Errors.NOT_EQUAL));

        emit Deposit(token, incognitoAddress, emitAmount);
    }

    /**
     * @dev Makes a ETH deposit to the vault to mint pETH over at Incognito Chain
     * @notice This only works when the contract is not Paused
     * @notice The maximum amount to deposit is capped since Incognito balance is stored as uint64
     * @param incognitoAddress: Incognito Address to receive pETH
     */
    function deposit_V2(string calldata incognitoAddress, bytes32 txId, bytes calldata signData) external payable nonReentrant {
        require(address(this).balance <= 10 ** 27, errorToString(Errors.MAX_UINT_REACHED));
        verifyRegulator(txId, signData);
        emit DepositV2(ETH_TOKEN, incognitoAddress, msg.value, idCounter.current());
        idCounter.increment();
    }

    /**
     * @dev Makes a ERC20 deposit to the vault to mint pERC20 over at Incognito Chain
     * @notice This only works when the contract is not Paused
     * @notice The maximum amount to deposit is capped since Incognito balance is stored as uint64
     * @notice Before calling this function, enough ERC20 must be allowed to
     * tranfer from msg.sender to this contract
     * @param token: address of the ERC20 token
     * @param amount: to deposit to the vault and mint on Incognito Chain
     * @param incognitoAddress: Incognito Address to receive pERC20
     */
    function depositERC20_V2(address token, uint amount, string calldata incognitoAddress, bytes32 txId, bytes calldata signData) external nonReentrant {
        verifyRegulator(txId, signData);
        IERC20 erc20Interface = IERC20(token);
        uint8 decimals = getDecimals(address(token));
        uint tokenBalance = erc20Interface.balanceOf(address(this));
        uint beforeTransfer = tokenBalance;
        uint emitAmount = amount;
        if (decimals > 9) {
            emitAmount = emitAmount / (10 ** (uint(decimals) - 9));
            tokenBalance = tokenBalance / (10 ** (uint(decimals) - 9));
        }
        require(emitAmount <= 10 ** 18 && tokenBalance <= 10 ** 18 && emitAmount.safeAdd(tokenBalance) <= 10 ** 18, errorToString(Errors.VALUE_OVER_FLOW));
        erc20Interface.transferFrom(msg.sender, address(this), amount);
        require(checkSuccess(), errorToString(Errors.INTERNAL_TX_ERROR));
        require(balanceOf(token).safeSub(beforeTransfer) == amount, errorToString(Errors.NOT_EQUAL));

        emit DepositV2(token, incognitoAddress, emitAmount, idCounter.current());
        idCounter.increment();
    }

    /**
     * @dev Checks if a burn proof has been used before
     * @notice First, we check inside the storage of this contract itself. If the
     * hash has been used before, we return the result. Otherwise, we query
     * previous vault recursively until the first Vault (prevVault address is 0x0)
     * @param hash: of the burn proof
     * @return bool: whether the proof has been used or not
     */
    function isWithdrawed(bytes32 hash) public view returns(bool) {
        if (withdrawed[hash]) {
            return true;
        } else if (address(prevVault) == address(0)) {
            return false;
        }
        return prevVault.isWithdrawed(hash);
    }

    /**
     * @dev Parses a burn instruction and returns the components
     * @param inst: the full instruction, containing both metadata and body
     */
    function parseBurnInst(bytes memory inst) public pure returns (BurnInstData memory) {
        BurnInstData memory data;
        data.meta = uint8(inst[0]);
        data.shard = uint8(inst[1]);
        address token;
        address payable to;
        uint amount;
        bytes32 itx;
        assembly {
        // skip first 0x20 bytes (stored length of inst)
            token := mload(add(inst, 0x22)) // [3:34]
            to := mload(add(inst, 0x42)) // [34:66]
            amount := mload(add(inst, 0x62)) // [66:98]
            itx := mload(add(inst, 0x82)) // [98:130]
        }
        data.token = token;
        data.to = to;
        data.amount = amount;
        data.itx = itx;
        return data;
    }

    /**
     * @dev Parses an extended burn instruction and returns the components
     * @param inst: the full instruction, containing both metadata and body
     */
    function parseCalldataFromBurnInst(bytes calldata inst) public pure returns (BurnInstData memory, RedepositOptions memory, bytes memory) {
        require(inst.length >= 296, errorToString(Errors.INVALID_DATA_BURN_CALL_INST));
        BurnInstData memory bdata;
        // layout: meta(1), shard(1), network(1), extToken(32), extCallAddr(32), amount(32), txID(32), recvToken(32), withdrawAddr(32), redepositAddr(101), extCalldata(*)
        {
            bdata.meta = uint8(inst[0]);
            bdata.shard = uint8(inst[1]);
            uint8 networkID = uint8(inst[2]);
            require(bdata.meta == BURN_CALL_REQUEST_METADATA_TYPE && bdata.shard == 1 && networkID == CURRENT_NETWORK_ID, errorToString(Errors.INVALID_DATA_BURN_CALL_INST));
        }
        RedepositOptions memory opt;
        {
            (bdata.token, bdata.to, bdata.amount, bdata.itx, opt.redepositToken, opt.withdrawAddress) = abi.decode(inst[3:195], (address, address, uint256, bytes32, address, address));
        }
    
        opt.redepositIncAddress = bytes(inst[195:296]);
        return (bdata, opt, bytes(inst[296:]));
    }

    /**
     * @dev Verifies that a burn instruction is valid
     * @notice All params except inst are the list of 2 elements corresponding to
     * the proof on beacon and bridge
     * @notice All params are the same as in `withdraw`
     */
    function verifyInst(
        bytes memory inst,
        uint heights,
        bytes32[] memory instPaths,
        bool[] memory instPathIsLefts,
        bytes32 instRoots,
        bytes32 blkData,
        uint[] memory sigIdxs,
        uint8[] memory sigVs,
        bytes32[] memory sigRs,
        bytes32[] memory sigSs
    ) view internal {
        // Each instruction can only by redeemed once
        bytes32 beaconInstHash = keccak256(abi.encodePacked(inst, heights));

        // Verify instruction on beacon
        require(Incognito(_incognito()).instructionApproved(
                true, // Only check instruction on beacon
                beaconInstHash,
                heights,
                instPaths,
                instPathIsLefts,
                instRoots,
                blkData,
                sigIdxs,
                sigVs,
                sigRs,
                sigSs
            ), errorToString(Errors.INVALID_DATA));
    }

    /**
     * @dev Withdraws pETH/pIERC20 by providing a burn proof over at Incognito Chain
     * @notice This function takes a burn instruction on Incognito Chain, checks
     * for its validity and returns the token back to ETH chain
     * @notice This only works when the contract is not Paused
     * @param inst: the decoded instruction as a list of bytes
     * @param heights: the blocks containing the instruction
     * @param instPaths: merkle path of the instruction
     * @param instPathIsLefts: whether each node on the path is the left or right child
     * @param instRoots: root of the merkle tree contains all instructions
     * @param blkData: merkle has of the block body
     * @param sigIdxs: indices of the validators who signed this block
     * @param sigVs: part of the signatures of the validators
     * @param sigRs: part of the signatures of the validators
     * @param sigSs: part of the signatures of the validators
     */
    function withdraw(
        bytes memory inst,
        uint heights,
        bytes32[] memory instPaths,
        bool[] memory instPathIsLefts,
        bytes32 instRoots,
        bytes32 blkData,
        uint[] memory sigIdxs,
        uint8[] memory sigVs,
        bytes32[] memory sigRs,
        bytes32[] memory sigSs
    ) public nonReentrant {
        require(inst.length >= 130, errorToString(Errors.INVALID_DATA));
        BurnInstData memory data = parseBurnInst(inst);
        require(data.meta == BURN_REQUEST_METADATA_TYPE && data.shard == 1, errorToString(Errors.INVALID_DATA)); // Check instruction type

        // Not withdrawed
        require(!isWithdrawed(data.itx), errorToString(Errors.ALREADY_USED));
        withdrawed[data.itx] = true;

        // Check if balance is enough
        if (data.token == ETH_TOKEN) {
            require(address(this).balance >= data.amount.safeAdd(totalDepositedToSCAmount[data.token]), errorToString(Errors.TOKEN_NOT_ENOUGH));
        } else {
            uint8 decimals = getDecimals(data.token);
            if (decimals > 9) {
                data.amount = data.amount.safeMul(10 ** (uint(decimals) - 9));
            }
            require(IERC20(data.token).balanceOf(address(this)) >= data.amount.safeAdd(totalDepositedToSCAmount[data.token]), errorToString(Errors.TOKEN_NOT_ENOUGH));
        }

        verifyInst(
            inst,
            heights,
            instPaths,
            instPathIsLefts,
            instRoots,
            blkData,
            sigIdxs,
            sigVs,
            sigRs,
            sigSs
        );

        // Send and notify
        if (data.token == ETH_TOKEN) {
            (bool success, ) =  data.to.call{value: data.amount}("");
            require(success, errorToString(Errors.INTERNAL_TX_ERROR));
        } else {
            IERC20(data.token).transfer(data.to, data.amount);
            require(checkSuccess(), errorToString(Errors.INTERNAL_TX_ERROR));
        }
        emit Withdraw(data.token, data.to, data.amount);
    }

    function executeWithBurnProof(
        bytes calldata inst,
        uint heights,
        bytes32[] memory instPaths,
        bool[] memory instPathIsLefts,
        bytes32 instRoots,
        bytes32 blkData,
        uint[] memory sigIdxs,
        uint8[] memory sigVs,
        bytes32[] memory sigRs,
        bytes32[] memory sigSs
    ) external nonReentrant {
        (BurnInstData memory data, RedepositOptions memory rOptions, bytes memory externalCalldata) = parseCalldataFromBurnInst(inst); // parse function also does sanity checks
        require(!isWithdrawed(data.itx), errorToString(Errors.ALREADY_USED)); // check if txID has been used previously
        withdrawed[data.itx] = true;
        // check if vault balance is sufficient
        if (data.token == ETH_TOKEN) {
            require(address(this).balance >= data.amount.safeAdd(totalDepositedToSCAmount[data.token]), errorToString(Errors.TOKEN_NOT_ENOUGH));
        } else {
            uint8 decimals = getDecimals(data.token);
            if (decimals > 9) {
                data.amount = data.amount.safeMul(10 ** (uint(decimals) - 9));
            }
            require(IERC20(data.token).balanceOf(address(this)) >= data.amount.safeAdd(totalDepositedToSCAmount[data.token]), errorToString(Errors.TOKEN_NOT_ENOUGH));
        }

        verifyInst(
            inst,
            heights,
            instPaths,
            instPathIsLefts,
            instRoots,
            blkData,
            sigIdxs,
            sigVs,
            sigRs,
            sigSs
        );


        // perform external msgcall
        try this._callExternal(data.token, data.to, data.amount, externalCalldata, rOptions.redepositToken) returns (uint256 returnedAmount) {
            if (rOptions.withdrawAddress == address(0)) {
                // after executing, one can redeposit to Incognito Chain
                _redeposit(rOptions.redepositToken, rOptions.redepositIncAddress, returnedAmount, data.itx);
            } else {
                // alternatively, the received funds can be withdrawn
                try this._transferExternal(rOptions.redepositToken, rOptions.withdrawAddress, returnedAmount) {
                    emit Withdraw(rOptions.redepositToken, rOptions.withdrawAddress, returnedAmount);
                } catch (bytes memory lowLevelData) {
                    // upon revert, emit Redeposit event
                    _redeposit(rOptions.redepositToken, rOptions.redepositIncAddress, returnedAmount, data.itx);
                    emit ExecuteFnLog(data.itx, 1, lowLevelData);
                    return;
                }
            }
        } catch (bytes memory lowLevelData) {
            _redeposit(data.token, rOptions.redepositIncAddress, data.amount, data.itx);
            emit ExecuteFnLog(data.itx, 0, lowLevelData);
            return;
        }
    }

    function _redeposit(address token, bytes memory redepositIncAddress, uint256 amount, bytes32 itx) internal {
        uint emitAmount = amount;
        if (token == ETH_TOKEN) {
            require(address(this).balance <= 10 ** 27, errorToString(Errors.MAX_UINT_REACHED));
        } else {
            uint8 decimals = getDecimals(address(token));
            if (decimals > 9) {
                emitAmount = emitAmount / (10 ** (uint(decimals) - 9));
            }
            require(emitAmount <= 10 ** 18, errorToString(Errors.VALUE_OVER_FLOW));
        }
        emit Redeposit(token, redepositIncAddress, emitAmount, itx);
    }

    function _transferExternal(address token, address payable to, uint256 amount) external onlySelf() {
        if (token == ETH_TOKEN) {
            Address.sendValue(to, amount);
        } else {
            IERC20(token).transfer(to, amount);
            require(checkSuccess(), errorToString(Errors.INTERNAL_TX_ERROR));
        }
    }

    function _callExternal(address token, address to, uint256 amount, bytes memory externalCalldata, address redepositToken) external onlySelf() returns (uint256) {
        uint balanceBeforeTrade = balanceOf(redepositToken);
        bytes memory result;
        uint256 msgval = 0;
        if (token == ETH_TOKEN) {
            msgval = amount;
        } else {
            IERC20(token).transfer(executor, amount);
            require(checkSuccess(), errorToString(Errors.INTERNAL_TX_ERROR));
        }
        result = Executor(executor).execute{value: msgval}(to, externalCalldata);
        require(result.length == 64, errorToString(Errors.INVALID_RETURN_DATA));
        (address returnedTokenAddress, uint returnedAmount) = abi.decode(result, (address, uint));
        require(returnedTokenAddress == redepositToken && balanceOf(redepositToken).safeSub(balanceBeforeTrade) == returnedAmount, errorToString(Errors.INVALID_RETURN_DATA));
        return returnedAmount;
    }

    modifier onlySelf() {
        require(address(this) == msg.sender, errorToString(Errors.ONLY_SELF_CALL));
        _;
    }

    /**
     * @dev Burnt Proof is submited to store burnt amount of p-token/p-ETH and receiver's address
     * Receiver then can call withdrawRequest to withdraw these token to he/she incognito address.
     * @notice This function takes a burn instruction on Incognito Chain, checks
     * for its validity and returns the token back to ETH chain
     * @notice This only works when the contract is not Paused
     * @param inst: the decoded instruction as a list of bytes
     * @param heights: the blocks containing the instruction
     * @param instPaths: merkle path of the instruction
     * @param instPathIsLefts: whether each node on the path is the left or right child
     * @param instRoots: root of the merkle tree contains all instructions
     * @param blkData: merkle has of the block body
     * @param sigIdxs: indices of the validators who signed this block
     * @param sigVs: part of the signatures of the validators
     * @param sigRs: part of the signatures of the validators
     * @param sigSs: part of the signatures of the validators
     */
    function submitBurnProof(
        bytes memory inst,
        uint heights,
        bytes32[] memory instPaths,
        bool[] memory instPathIsLefts,
        bytes32 instRoots,
        bytes32 blkData,
        uint[] memory sigIdxs,
        uint8[] memory sigVs,
        bytes32[] memory sigRs,
        bytes32[] memory sigSs
    ) public nonReentrant {
        require(inst.length >= 130, errorToString(Errors.INVALID_DATA));
        BurnInstData memory data = parseBurnInst(inst);
        require(data.meta == BURN_TO_CONTRACT_REQUEST_METADATA_TYPE && data.shard == 1, errorToString(Errors.INVALID_DATA)); // Check instruction type

        // Not withdrawed
        require(!isWithdrawed(data.itx), errorToString(Errors.ALREADY_USED));
        withdrawed[data.itx] = true;

        // Check if balance is enough
        if (data.token == ETH_TOKEN) {
            require(address(this).balance >= data.amount.safeAdd(totalDepositedToSCAmount[data.token]), errorToString(Errors.TOKEN_NOT_ENOUGH));
        } else {
            uint8 decimals = getDecimals(data.token);
            if (decimals > 9) {
                data.amount = data.amount.safeMul(10 ** (uint(decimals) - 9));
            }
            require(IERC20(data.token).balanceOf(address(this)) >= data.amount.safeAdd(totalDepositedToSCAmount[data.token]), errorToString(Errors.TOKEN_NOT_ENOUGH));
        }

        verifyInst(
            inst,
            heights,
            instPaths,
            instPathIsLefts,
            instRoots,
            blkData,
            sigIdxs,
            sigVs,
            sigRs,
            sigSs
        );

        withdrawRequests[data.to][data.token] = withdrawRequests[data.to][data.token].safeAdd(data.amount);
        totalDepositedToSCAmount[data.token] = totalDepositedToSCAmount[data.token].safeAdd(data.amount);
    }

    /**
     * @dev generate address from signature data and hash.
     */
    function sigToAddress(bytes memory signData, bytes32 hash) public pure returns (address) {
        bytes32 s;
        bytes32 r;
        uint8 v;
        assembly {
            r := mload(add(signData, 0x20))
            s := mload(add(signData, 0x40))
        }
        v = uint8(signData[64]) + 27;
        return ecrecover(hash, v, r, s);
    }

    /**
     * @dev Checks if a sig data has been used before
     * @notice First, we check inside the storage of this contract itself. If the
     * hash has been used before, we return the result. Otherwise, we query
     * previous vault recursively until the first Vault (prevVault address is 0x0)
     * @param hash: of the sig data
     * @return bool: whether the sig data has been used or not
     */
    function isSigDataUsed(bytes32 hash) public view returns(bool) {
        if (sigDataUsed[hash]) {
            return true;
        } else if (address(prevVault) == address(0)) {
            return false;
        }
        return prevVault.isSigDataUsed(hash);
    }

    struct PreSignData {
        Prefix prefix;
        address token;
        bytes timestamp;
        uint amount;
    }

    function newPreSignData(Prefix prefix, address token, bytes calldata timestamp, uint amount) pure internal returns (PreSignData memory) {
        PreSignData memory psd = PreSignData(prefix, token, timestamp, amount);
        return psd;
    }

    /**
     * @dev User requests withdraw token contains in withdrawRequests.
     * Deposit event will be emitted to let incognito recognize and mint new p-tokens for the user.
     * @param incognitoAddress: incognito's address that will receive minted p-tokens.
     * @param token: ethereum's token address (eg., ETH, DAI, ...)
     * @param amount: amount of the token in ethereum's denomination
     * @param signData: signature of an unique data that is signed by an account which is generated from user's incognito privkey
     * @param timestamp: unique data generated from client (timestamp for example)
     * @param txId: move fund transaction hash
     * @param signData: regulator signature
     */
    function requestWithdraw(
        string calldata incognitoAddress,
        address token,
        uint amount,
        bytes calldata signData,
        bytes calldata timestamp,
        bytes32 txId,
        bytes calldata regulatorSig
    ) external nonReentrant {
        verifyRegulator(txId, regulatorSig);

        // verify owner signs data
        address verifier = verifySignData(abi.encode(newPreSignData(Prefix.ETHEREUM_REQUEST_WITHDRAW_SIGNATURE, token, timestamp, amount), incognitoAddress), signData);

        // migrate from preVault
        migrateBalance(verifier, token);

        require(withdrawRequests[verifier][token] >= amount, errorToString(Errors.WITHDRAW_REQUEST_TOKEN_NOT_ENOUGH));
        withdrawRequests[verifier][token] = withdrawRequests[verifier][token].safeSub(amount);
        totalDepositedToSCAmount[token] = totalDepositedToSCAmount[token].safeSub(amount);

        // convert denomination from ethereum's to incognito's (pcoin)
        uint emitAmount = amount;
        if (token != ETH_TOKEN) {
            uint8 decimals = getDecimals(token);
            if (decimals > 9) {
                emitAmount = amount / (10 ** (uint(decimals) - 9));
            }
        }

        emit Deposit(token, incognitoAddress, emitAmount);
    }

    /**
     * @dev execute is a general function that plays a role as proxy to interact to other smart contracts.
     * @param token: ethereum's token address (eg., ETH, DAI, ...)
     * @param amount: amount of the token in ethereum's denomination
     * @param recipientToken: received token address.
     * @param exchangeAddress: address of targeting smart contract that actually executes the desired logics like trade, invest, borrow and so on.
     * @param callData: encoded with signature and params of function from targeting smart contract.
     * @param timestamp: unique data generated from client (timestamp for example)
     * @param signData: signature of an unique data that is signed by an account which is generated from user's incognito privkey
     */
    function execute(
        address token,
        uint amount,
        address recipientToken,
        address exchangeAddress,
        bytes calldata callData,
        bytes calldata timestamp,
        bytes calldata signData
    ) external payable nonReentrant {
        //verify ower signs data from input
        address verifier = verifySignData(abi.encode(newPreSignData(Prefix.ETHEREUM_EXECUTE_SIGNATURE, token, timestamp, amount), recipientToken, exchangeAddress, callData), signData);

        // migrate from preVault
        migrateBalance(verifier, token);
        require(withdrawRequests[verifier][token] >= amount, errorToString(Errors.WITHDRAW_REQUEST_TOKEN_NOT_ENOUGH));

        // update balance of verifier
        totalDepositedToSCAmount[token] = totalDepositedToSCAmount[token].safeSub(amount);
        withdrawRequests[verifier][token] = withdrawRequests[verifier][token].safeSub(amount);

        // define number of eth spent for forwarder.
        uint ethAmount = msg.value;
        if (token == ETH_TOKEN) {
            ethAmount = ethAmount.safeAdd(amount);
        } else {
            // transfer token to exchangeAddress.
            require(IERC20(token).balanceOf(address(this)) >= amount, errorToString(Errors.TOKEN_NOT_ENOUGH));
            IERC20(token).transfer(executor, amount);
            require(checkSuccess(), errorToString(Errors.INTERNAL_TX_ERROR));
        }
        uint returnedAmount = callExtFunc(recipientToken, ethAmount, callData, exchangeAddress);

        // update withdrawRequests
        withdrawRequests[verifier][recipientToken] = withdrawRequests[verifier][recipientToken].safeAdd(returnedAmount);
        totalDepositedToSCAmount[recipientToken] = totalDepositedToSCAmount[recipientToken].safeAdd(returnedAmount);
    }

    /**
     * @dev single trade
     */
    function callExtFunc(address recipientToken, uint ethAmount, bytes memory callData, address exchangeAddress) internal returns (uint) {
        // get balance of recipient token before trade to compare after trade.
        uint balanceBeforeTrade = balanceOf(recipientToken);
        if (recipientToken == ETH_TOKEN) {
            balanceBeforeTrade = balanceBeforeTrade.safeSub(msg.value);
        }
        require(address(this).balance >= ethAmount, errorToString(Errors.TOKEN_NOT_ENOUGH));
        bytes memory result = Executor(executor).execute{value: ethAmount}(exchangeAddress, callData);
        (address returnedTokenAddress, uint returnedAmount) = abi.decode(result, (address, uint));
        require(returnedTokenAddress == recipientToken && balanceOf(recipientToken).safeSub(balanceBeforeTrade) == returnedAmount, errorToString(Errors.INVALID_RETURN_DATA));
        return returnedAmount;
    }

    /**
     * @dev set regulator
     */
    function setRegulator(address _regulator) external {
        require((regulator == address(0x0) || msg.sender == regulator) && _regulator != address(0x0), errorToString(Errors.NOT_AUTHORISED));
        regulator = _regulator;
    }

    /**
     * @dev verify regulator
     */
    function verifyRegulator(bytes32 txId, bytes memory signData) internal view {
        // verify regulator signs data
        address signer = sigToAddress(signData, keccak256(abi.encode(ShieldInfo(msg.sender, txId))));
        require(signer == regulator, errorToString(Errors.INVALID_SIGNATURE));
    }

    /**
     * @dev verify sign data
     */
    function verifySignData(bytes memory data, bytes memory signData) internal returns(address){
        bytes32 hash = keccak256(data);
        require(!isSigDataUsed(hash), errorToString(Errors.ALREADY_USED));
        address verifier = sigToAddress(signData, hash);
        // reject when verifier equals zero
        require(verifier != address(0x0), errorToString(Errors.INVALID_SIGNATURE));
        // mark data hash of sig as used
        sigDataUsed[hash] = true;

        return verifier;
    }

    /**
      * @dev migrate balance from previous vault
      * Note: uncomment for next version
      */
    function migrateBalance(address owner, address token) internal {
        if (address(prevVault) != address(0x0) && !migration[owner][token]) {
            withdrawRequests[owner][token] = withdrawRequests[owner][token].safeAdd(prevVault.getDepositedBalance(token, owner));
            migration[owner][token] = true;
        }
    }

    /**
     * @dev Get the amount of specific coin for specific wallet
     */
    function getDepositedBalance(
        address token,
        address owner
    ) public view returns (uint) {
        if (address(prevVault) != address(0x0) && !migration[owner][token]) {
            return withdrawRequests[owner][token].safeAdd(prevVault.getDepositedBalance(token, owner));
        }
        return withdrawRequests[owner][token];
    }

    /**
     * @dev Move total number of assets to newVault
     * @notice This only works when the preVault is Paused
     * @notice This can only be called by preVault
     * @param assets: address of the ERC20 tokens to move, 0x0 for ETH
     * @param amounts: total number of the ERC20 tokens to move, 0x0 for ETH
     */
    function updateAssets(address[] calldata assets, uint[] calldata amounts) external onlyPreVault returns(bool) {
        require(assets.length == amounts.length,  errorToString(Errors.NOT_EQUAL));
        require(Withdrawable(prevVault).paused(), errorToString(Errors.PREVAULT_NOT_PAUSED));
        for (uint i = 0; i < assets.length; i++) {
            totalDepositedToSCAmount[assets[i]] = totalDepositedToSCAmount[assets[i]].safeAdd(amounts[i]);
        }
        emit UpdateTokenTotal(assets, amounts);

        return true;
    }

    /**
     * @dev Payable receive function to receive Ether from oldVault when migrating
     */
    receive() external payable {}

    /**
     * @dev Check if transfer() and transferFrom() of ERC20 succeeded or not
     * This check is needed to fix https://github.com/ethereum/solidity/issues/4116
     * This function is copied from https://github.com/AdExNetwork/adex-protocol-eth/blob/master/contracts/libs/SafeERC20.sol
     */
    function checkSuccess() private pure returns (bool) {
        uint256 returnValue = 0;
        assembly {
        // check number of bytes returned from last function call
            switch returndatasize()

            // no bytes returned: assume success
            case 0x0 {
                returnValue := 1
            }

            // 32 bytes returned: check if non-zero
            case 0x20 {
            // copy 32 bytes into scratch space
                returndatacopy(0x0, 0x0, 0x20)

            // load those bytes into returnValue
                returnValue := mload(0x0)
            }

            // not sure what was returned: don't mark as success
            default { }
        }
        return returnValue != 0;
    }

    /**
     * @dev convert enum to string value
     */
    function errorToString(Errors error) internal pure returns(string memory) {
        uint8 erroNum = uint8(error);
        uint maxlength = 10;
        bytes memory reversed = new bytes(maxlength);
        uint i = 0;
        while (erroNum != 0) {
            uint8 remainder = erroNum % 10;
            erroNum = erroNum / 10;
            reversed[i++] = byte(48 + remainder);
        }
        bytes memory s = new bytes(i + 1);
        for (uint j = 0; j <= i; j++) {
            s[j] = reversed[i - j];
        }
        return string(s);
    }

    /**
     * @dev Get the decimals of an ERC20 token, return 0 if it isn't defined
     * We check the returndatasize to covert both cases that the token has
     * and doesn't have the function decimals()
     */
    function getDecimals(address token) public view returns (uint8) {
        require(Address.isContract(token), "getDecimals non-contract");
        IERC20 erc20 = IERC20(token);
        try erc20.decimals() returns (uint256 d) {
            return uint8(d);    
        } catch {
            revert("get ERC20 decimal failed");
        }
    }

    /**
     * @dev Get the amount of coin deposited to this smartcontract
     */
    function balanceOf(address token) public view returns (uint) {
        if (token == ETH_TOKEN) {
            return address(this).balance;
        }
        require(Address.isContract(token), "balanceOf non-contract");
        try IERC20(token).balanceOf(address(this)) returns (uint256 b) {
            return b;
        } catch {
            revert("get ERC20 balance failed");
        }
    }
}

File 2 of 6 : IERC20.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.5.0 <0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP. Does not include
 * the optional functions; to access them see `ERC20Detailed`.
 */
interface IERC20 {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint);

    /**
     * @dev Moves `amount` tokens from the caller's account to `recipient`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a `Transfer` event.
     */
    function transfer(address recipient, uint amount) external;

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through `transferFrom`. This is
     * zero by default.
     *
     * This value changes when `approve` or `transferFrom` are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * > Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an `Approval` event.
     */
    function approve(address spender, uint amount) external;

    /**
     * @dev Moves `amount` tokens from `sender` to `recipient` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a `Transfer` event.
     */
    function transferFrom(address sender, address recipient, uint amount) external;

    /**
     * @dev Returns the number of decimals used to get its user representation.
     * For example, if `decimals` equals `2`, a balance of `505` tokens should
     * be displayed to a user as `5,05` (`505 / 10 ** 2`).
     *
     * Tokens usually opt for a value of 18, imitating the relationship between
     * Ether and Wei.
     *
     * NOTE: This information is only used for _display_ purposes: it in
     * no way affects any of the arithmetic of the contract, including
     * {IERC20-balanceOf} and {IERC20-transfer}.
     */
    function decimals() external view returns (uint);

    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to `approve`. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint value);
}

File 3 of 6 : Address.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.2 <0.8.0;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize, which returns 0 for contracts in
        // construction, since the code is only stored at the end of the
        // constructor execution.

        uint256 size;
        // solhint-disable-next-line no-inline-assembly
        assembly { size := extcodesize(account) }
        return size > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
        (bool success, ) = recipient.call{ value: amount }("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain`call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
      return functionCall(target, data, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        require(isContract(target), "Address: call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.call{ value: value }(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {
        require(isContract(target), "Address: static call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.staticcall(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
        require(isContract(target), "Address: delegate call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

    function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly

                // solhint-disable-next-line no-inline-assembly
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

File 4 of 6 : trade_utils.sol
pragma solidity >=0.6.12 <=0.8.9;

import './IERC20.sol';
import '@openzeppelin/contracts/access/Ownable.sol';

contract TradeUtils {
	IERC20 constant public ETH_CONTRACT_ADDRESS = IERC20(0x0000000000000000000000000000000000000000);

	function balanceOf(IERC20 token) internal view returns (uint256) {
		if (token == ETH_CONTRACT_ADDRESS) {
			return address(this).balance;
		}
        return token.balanceOf(address(this));
    }

	function transfer(IERC20 token, uint amount) internal {
		if (token == ETH_CONTRACT_ADDRESS) {
			require(address(this).balance >= amount);
			(bool success, ) = msg.sender.call{value: amount}("");
          	require(success);
		} else {
			token.transfer(msg.sender, amount);
			require(checkSuccess());
		}
	}

	function approve(IERC20 token, address proxy, uint amount) internal {
		if (token != ETH_CONTRACT_ADDRESS) {
			token.approve(proxy, 0);
			require(checkSuccess());
			token.approve(proxy, amount);
			require(checkSuccess());
		}
	}

	/**
     * @dev Check if transfer() and transferFrom() of ERC20 succeeded or not
     * This check is needed to fix https://github.com/ethereum/solidity/issues/4116
     * This function is copied from https://github.com/AdExNetwork/adex-protocol-eth/blob/master/contracts/libs/SafeERC20.sol
     */
    function checkSuccess() internal pure returns (bool) {
		uint256 returnValue = 0;

		assembly {
			// check number of bytes returned from last function call
			switch returndatasize()

			// no bytes returned: assume success
			case 0x0 {
				returnValue := 1
			}

			// 32 bytes returned: check if non-zero
			case 0x20 {
				// copy 32 bytes into scratch space
				returndatacopy(0x0, 0x0, 0x20)

				// load those bytes into returnValue
				returnValue := mload(0x0)
			}

			// not sure what was returned: don't mark as success
			default { }
		}
		return returnValue != 0;
	}
}

abstract contract Executor is Ownable {
	mapping (address => bool) public dappAddresses;

	constructor() internal {
		dappAddresses[address(this)] = true;
	}

	function addDappAddress(address addr) external onlyOwner {
		require(addr != address(0x0), "Executor:A0"); // address is zero
		dappAddresses[addr] = true;
	}

	function removeDappAddress(address addr) external onlyOwner {
		require(addr != address(0x0), "Executor:A0"); // address is zero
		dappAddresses[addr] = false;
	}

	function dappExists(address addr) public view returns (bool) {
		return dappAddresses[addr];
	}

    function execute(address fns, bytes calldata data) external payable returns (bytes memory) {
    	require(dappExists(fns), "Executor:DNE"); // dapp does not exist
        (bool success, bytes memory result) = fns.delegatecall(data);
        if (!success) {
        	// Next 5 lines from https://ethereum.stackexchange.com/a/83577
            if (result.length < 68) revert();
            assembly {
                result := add(result, 0x04)
            }
            revert(abi.decode(result, (string)));
        }
        return result;
    }
}

File 5 of 6 : Ownable.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

import "../utils/Context.sol";
/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor () internal {
        address msgSender = _msgSender();
        _owner = msgSender;
        emit OwnershipTransferred(address(0), msgSender);
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
        _;
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        emit OwnershipTransferred(_owner, address(0));
        _owner = address(0);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        emit OwnershipTransferred(_owner, newOwner);
        _owner = newOwner;
    }
}

File 6 of 6 : Context.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/*
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with GSN meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address payable) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes memory) {
        this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
        return msg.data;
    }
}

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

Contract Security Audit

Contract ABI

[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"string","name":"incognitoAddress","type":"string"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"string","name":"incognitoAddress","type":"string"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"depositID","type":"uint256"}],"name":"DepositV2","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"id","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"phaseID","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"errorData","type":"bytes"}],"name":"ExecuteFnLog","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"bytes","name":"redepositIncAddress","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"itx","type":"bytes32"}],"name":"Redeposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newIncognitoProxy","type":"address"}],"name":"UpdateIncognitoProxy","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"assets","type":"address[]"},{"indexed":false,"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"UpdateTokenTotal","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"BURN_CALL_REQUEST_METADATA_TYPE","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BURN_REQUEST_METADATA_TYPE","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BURN_TO_CONTRACT_REQUEST_METADATA_TYPE","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CURRENT_NETWORK_ID","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ETH_TOKEN","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"externalCalldata","type":"bytes"},{"internalType":"address","name":"redepositToken","type":"address"}],"name":"_callExternal","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address payable","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"_transferExternal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"incognitoAddress","type":"string"},{"internalType":"bytes32","name":"txId","type":"bytes32"},{"internalType":"bytes","name":"signData","type":"bytes"}],"name":"deposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"string","name":"incognitoAddress","type":"string"},{"internalType":"bytes32","name":"txId","type":"bytes32"},{"internalType":"bytes","name":"signData","type":"bytes"}],"name":"depositERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"string","name":"incognitoAddress","type":"string"},{"internalType":"bytes32","name":"txId","type":"bytes32"},{"internalType":"bytes","name":"signData","type":"bytes"}],"name":"depositERC20_V2","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"incognitoAddress","type":"string"},{"internalType":"bytes32","name":"txId","type":"bytes32"},{"internalType":"bytes","name":"signData","type":"bytes"}],"name":"deposit_V2","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"recipientToken","type":"address"},{"internalType":"address","name":"exchangeAddress","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"bytes","name":"timestamp","type":"bytes"},{"internalType":"bytes","name":"signData","type":"bytes"}],"name":"execute","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"inst","type":"bytes"},{"internalType":"uint256","name":"heights","type":"uint256"},{"internalType":"bytes32[]","name":"instPaths","type":"bytes32[]"},{"internalType":"bool[]","name":"instPathIsLefts","type":"bool[]"},{"internalType":"bytes32","name":"instRoots","type":"bytes32"},{"internalType":"bytes32","name":"blkData","type":"bytes32"},{"internalType":"uint256[]","name":"sigIdxs","type":"uint256[]"},{"internalType":"uint8[]","name":"sigVs","type":"uint8[]"},{"internalType":"bytes32[]","name":"sigRs","type":"bytes32[]"},{"internalType":"bytes32[]","name":"sigSs","type":"bytes32[]"}],"name":"executeWithBurnProof","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"executor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"getDecimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"getDepositedBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_prevVault","type":"address"},{"internalType":"address","name":"_regulator","type":"address"},{"internalType":"address","name":"_executor","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isInitialized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"hash","type":"bytes32"}],"name":"isSigDataUsed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"hash","type":"bytes32"}],"name":"isWithdrawed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"migration","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"notEntered","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"inst","type":"bytes"}],"name":"parseBurnInst","outputs":[{"components":[{"internalType":"uint8","name":"meta","type":"uint8"},{"internalType":"uint8","name":"shard","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"address payable","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes32","name":"itx","type":"bytes32"}],"internalType":"struct Vault.BurnInstData","name":"","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"inst","type":"bytes"}],"name":"parseCalldataFromBurnInst","outputs":[{"components":[{"internalType":"uint8","name":"meta","type":"uint8"},{"internalType":"uint8","name":"shard","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"address payable","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes32","name":"itx","type":"bytes32"}],"internalType":"struct Vault.BurnInstData","name":"","type":"tuple"},{"components":[{"internalType":"address","name":"redepositToken","type":"address"},{"internalType":"bytes","name":"redepositIncAddress","type":"bytes"},{"internalType":"address payable","name":"withdrawAddress","type":"address"}],"internalType":"struct Vault.RedepositOptions","name":"","type":"tuple"},{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"prevVault","outputs":[{"internalType":"contract Withdrawable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"regulator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"incognitoAddress","type":"string"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"signData","type":"bytes"},{"internalType":"bytes","name":"timestamp","type":"bytes"},{"internalType":"bytes32","name":"txId","type":"bytes32"},{"internalType":"bytes","name":"regulatorSig","type":"bytes"}],"name":"requestWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_regulator","type":"address"}],"name":"setRegulator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"sigDataUsed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"signData","type":"bytes"},{"internalType":"bytes32","name":"hash","type":"bytes32"}],"name":"sigToAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"storageLayoutVersion","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"inst","type":"bytes"},{"internalType":"uint256","name":"heights","type":"uint256"},{"internalType":"bytes32[]","name":"instPaths","type":"bytes32[]"},{"internalType":"bool[]","name":"instPathIsLefts","type":"bool[]"},{"internalType":"bytes32","name":"instRoots","type":"bytes32"},{"internalType":"bytes32","name":"blkData","type":"bytes32"},{"internalType":"uint256[]","name":"sigIdxs","type":"uint256[]"},{"internalType":"uint8[]","name":"sigVs","type":"uint8[]"},{"internalType":"bytes32[]","name":"sigRs","type":"bytes32[]"},{"internalType":"bytes32[]","name":"sigSs","type":"bytes32[]"}],"name":"submitBurnProof","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"totalDepositedToSCAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"assets","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"updateAssets","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_regulator","type":"address"},{"internalType":"address","name":"_executor","type":"address"}],"name":"upgradeVaultStorage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"inst","type":"bytes"},{"internalType":"uint256","name":"heights","type":"uint256"},{"internalType":"bytes32[]","name":"instPaths","type":"bytes32[]"},{"internalType":"bool[]","name":"instPathIsLefts","type":"bool[]"},{"internalType":"bytes32","name":"instRoots","type":"bytes32"},{"internalType":"bytes32","name":"blkData","type":"bytes32"},{"internalType":"uint256[]","name":"sigIdxs","type":"uint256[]"},{"internalType":"uint8[]","name":"sigVs","type":"uint8[]"},{"internalType":"bytes32[]","name":"sigRs","type":"bytes32[]"},{"internalType":"bytes32[]","name":"sigSs","type":"bytes32[]"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"withdrawRequests","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"withdrawed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]

608060405234801561001057600080fd5b506150ee806100206000396000f3fe6080604052600436106102a45760003560e01c8063995fac111161016e578063cde0a4f8116100cb578063dd8fee141161007f578063f75b98ce11610064578063f75b98ce146106f6578063fa84702e14610716578063fee8efda1461072b576102ab565b8063dd8fee14146106c1578063e4bd7074146106d6576102ab565b8063d6a1fe3b116100b0578063d6a1fe3b14610677578063d7200eb11461068c578063dca40d9e146106a1576102ab565b8063cde0a4f814610637578063cf54aaa014610657576102ab565b8063bd835c4211610122578063c0c53b8b11610107578063c0c53b8b146105ef578063c34c08e51461060f578063c791d70514610624576102ab565b8063bd835c42146105ba578063bda9b509146105cf576102ab565b8063a73b153211610153578063a73b15321461055a578063a807b5bb1461057a578063b8237dbb1461059a576102ab565b8063995fac1114610525578063a3f5d8cc14610545576102ab565b80636304541c1161021c57806373bf9651116101d05780637e16e6e1116101b55780637e16e6e1146104d257806384b3ac03146104ff5780638588ccd614610512576102ab565b806373bf965114610492578063749c5f86146104b2576102ab565b806366945b311161020157806366945b311461042e5780636f2cbc481461045d57806370a0823114610472576102ab565b80636304541c146103e157806365b5a00f1461040e576102ab565b8063392e53cd116102735780633fec6b40116102585780633fec6b401461037d578063568c04fd146103aa57806358bc8337146103cc576102ab565b8063392e53cd146103485780633ed1b3761461035d576102ab565b8063145e2a6b146102b05780631beb7de2146102d25780631ea1940e146102f25780631ed4276d14610328576102ab565b366102ab57005b600080fd5b3480156102bc57600080fd5b506102d06102cb36600461404a565b61074b565b005b3480156102de57600080fd5b506102d06102ed3660046145cc565b610834565b3480156102fe57600080fd5b5061031261030d366004614344565b610c91565b60405161031f9190614c39565b60405180910390f35b34801561033457600080fd5b506103126103433660046142bf565b610ca6565b34801561035457600080fd5b50610312610ec7565b34801561036957600080fd5b506102d061037836600461439c565b610ed7565b34801561038957600080fd5b5061039d610398366004614589565b611437565b60405161031f9190614a2e565b3480156103b657600080fd5b506103bf6114c6565b60405161031f9190614fc5565b3480156103d857600080fd5b5061039d6114cb565b3480156103ed57600080fd5b506104016103fc366004613f53565b6114d0565b60405161031f9190614cf1565b34801561041a57600080fd5b50610401610429366004614012565b6114e2565b34801561043a57600080fd5b5061044e61044936600461435c565b6114ff565b60405161031f93929190614ec8565b34801561046957600080fd5b506103bf6116e2565b34801561047e57600080fd5b5061040161048d366004613f53565b6116e7565b34801561049e57600080fd5b506102d06104ad3660046145cc565b6117bb565b3480156104be57600080fd5b506103126104cd366004614344565b611b33565b3480156104de57600080fd5b506104f26104ed3660046144db565b611c03565b60405161031f9190614eba565b6102d061050d3660046147e6565b611c85565b6102d0610520366004614153565b611dae565b34801561053157600080fd5b50610312610540366004614012565b61224c565b34801561055157600080fd5b5061031261226c565b34801561056657600080fd5b506102d0610575366004614012565b61227c565b34801561058657600080fd5b506102d061059536600461422c565b61231f565b3480156105a657600080fd5b506102d06105b536600461422c565b6125fe565b3480156105c657600080fd5b506103bf6128ec565b3480156105db57600080fd5b506104016105ea3660046140d4565b6128f1565b3480156105fb57600080fd5b506102d061060a36600461408a565b612b15565b34801561061b57600080fd5b5061039d612c1f565b6102d06106323660046147e6565b612c2e565b34801561064357600080fd5b506102d0610652366004613f53565b612d42565b34801561066357600080fd5b506103bf610672366004613f53565b612dd0565b34801561068357600080fd5b50610401612e8a565b34801561069857600080fd5b506103bf612e90565b3480156106ad57600080fd5b506103126106bc366004614344565b612e95565b3480156106cd57600080fd5b5061039d612eaa565b3480156106e257600080fd5b506103126106f1366004614344565b612eb9565b34801561070257600080fd5b50610401610711366004614012565b612f39565b34801561072257600080fd5b5061039d613065565b34801561073757600080fd5b506102d06107463660046146fe565b613074565b30331461075860146132e0565b9061077f5760405162461bcd60e51b81526004016107769190614d37565b60405180910390fd5b506001600160a01b03831661079d57610798828261343a565b61082f565b60405163a9059cbb60e01b81526001600160a01b0384169063a9059cbb906107cb9085908590600401614a66565b600060405180830381600087803b1580156107e557600080fd5b505af11580156107f9573d6000803e3d6000fd5b505050506108056134d6565b61080f60046132e0565b9061082d5760405162461bcd60e51b81526004016107769190614d37565b505b505050565b600554600160a01b900460ff1661084b60016132e0565b906108695760405162461bcd60e51b81526004016107769190614d37565b506005805460ff60a01b1916905589516082111561088760066132e0565b906108a55760405162461bcd60e51b81526004016107769190614d37565b506108ae613c89565b6108b78b611c03565b805190915060ff1660f11480156108d55750806020015160ff166001145b6108df60066132e0565b906108fd5760405162461bcd60e51b81526004016107769190614d37565b5061090b8160a00151611b33565b1561091660056132e0565b906109345760405162461bcd60e51b81526004016107769190614d37565b5060a081015160009081526020819052604090819020805460ff191660011790558101516001600160a01b03166109bf576040808201516001600160a01b0316600090815260046020522054608082015161098e9161350a565b47101561099b60076132e0565b906109b95760405162461bcd60e51b81526004016107769190614d37565b50610ad1565b60006109ce8260400151612dd0565b905060098160ff1611156109fb5760808201516109f59060081960ff841601600a0a613570565b60808301525b6040808301516001600160a01b03166000908152600460205220546080830151610a249161350a565b82604001516001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401610a549190614a2e565b60206040518083038186803b158015610a6c57600080fd5b505afa158015610a80573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aa4919061485d565b1015610ab060076132e0565b90610ace5760405162461bcd60e51b81526004016107769190614d37565b50505b610ae38b8b8b8b8b8b8b8b8b8b6135d2565b60408101516001600160a01b0316610b8c57600081606001516001600160a01b03168260800151604051610b1690614a2b565b60006040518083038185875af1925050503d8060008114610b53576040519150601f19603f3d011682016040523d82523d6000602084013e610b58565b606091505b5050905080610b6760046132e0565b90610b855760405162461bcd60e51b81526004016107769190614d37565b5050610c2a565b80604001516001600160a01b031663a9059cbb826060015183608001516040518363ffffffff1660e01b8152600401610bc6929190614a66565b600060405180830381600087803b158015610be057600080fd5b505af1158015610bf4573d6000803e3d6000fd5b50505050610c006134d6565b610c0a60046132e0565b90610c285760405162461bcd60e51b81526004016107769190614d37565b505b7f9b1bfa7fa9ee420a16e124f794c35ac9f90472acc99140eb2f6447c714cad8eb816040015182606001518360800151604051610c6993929190614a42565b60405180910390a150506005805460ff60a01b1916600160a01b179055505050505050505050565b60016020526000908152604090205460ff1681565b6005546000906001600160a01b031615801590610ccd57506005546001600160a01b031633145b610cd7600c6132e0565b90610cf55760405162461bcd60e51b81526004016107769190614d37565b50838214610d03600a6132e0565b90610d215760405162461bcd60e51b81526004016107769190614d37565b50600560009054906101000a90046001600160a01b03166001600160a01b0316635c975abb6040518163ffffffff1660e01b815260040160206040518083038186803b158015610d7057600080fd5b505afa158015610d84573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610da89190614328565b610db2600d6132e0565b90610dd05760405162461bcd60e51b81526004016107769190614d37565b5060005b84811015610e7e57610e37848483818110610deb57fe5b9050602002013560046000898986818110610e0257fe5b9050602002016020810190610e179190613f53565b6001600160a01b031681526020810191909152604001600020549061350a565b60046000888885818110610e4757fe5b9050602002016020810190610e5c9190613f53565b6001600160a01b03168152602081019190915260400160002055600101610dd4565b507f6a7fbbcddfd518bb8c56b28ac6c7acb0f7ca093ed232eb3306e53d14e469895f85858585604051610eb49493929190614ba1565b60405180910390a1506001949350505050565b600554600160a81b900460ff1681565b600554600160a01b900460ff16610eee60016132e0565b90610f0c5760405162461bcd60e51b81526004016107769190614d37565b506005805460ff60a01b19169055610f22613c89565b610f2a613cbe565b6060610f368e8e6114ff565b925092509250610f498360a00151611b33565b15610f5460056132e0565b90610f725760405162461bcd60e51b81526004016107769190614d37565b5060a083015160009081526020819052604090819020805460ff191660011790558301516001600160a01b0316610ffd576040808401516001600160a01b03166000908152600460205220546080840151610fcc9161350a565b471015610fd960076132e0565b90610ff75760405162461bcd60e51b81526004016107769190614d37565b5061110f565b600061100c8460400151612dd0565b905060098160ff1611156110395760808401516110339060081960ff841601600a0a613570565b60808501525b6040808501516001600160a01b031660009081526004602052205460808501516110629161350a565b84604001516001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016110929190614a2e565b60206040518083038186803b1580156110aa57600080fd5b505afa1580156110be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110e2919061485d565b10156110ee60076132e0565b9061110c5760405162461bcd60e51b81526004016107769190614d37565b50505b6111658e8e8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050508d8d8d8d8d8d8d8d8d6135d2565b60408084015160608501516080860151855193517fbda9b509000000000000000000000000000000000000000000000000000000008152309463bda9b509946111b8949093909290918891600401614a99565b602060405180830381600087803b1580156111d257600080fd5b505af1925050508015611202575060408051601f3d908101601f191682019092526111ff9181019061485d565b60015b61129b573d808015611230576040519150601f19603f3d011682016040523d82523d6000602084013e611235565b606091505b506112528460400151846020015186608001518760a001516136cd565b7fdbbb883f24557adf486292429863dcfd4ac5d4db168ae94921da8e3d9a95d4168460a0015160008360405161128a93929190614cfa565b60405180910390a150505050611417565b60408301516001600160a01b03166112ca576112c583600001518460200151838760a001516136cd565b611412565b825160408085015190517f145e2a6b000000000000000000000000000000000000000000000000000000008152309263145e2a6b9261130d928690600401614a42565b600060405180830381600087803b15801561132757600080fd5b505af1925050508015611338575060015b6113ce573d808015611366576040519150601f19603f3d011682016040523d82523d6000602084013e61136b565b606091505b5061138484600001518560200151848860a001516136cd565b7fdbbb883f24557adf486292429863dcfd4ac5d4db168ae94921da8e3d9a95d4168560a001516001836040516113bc93929190614cfa565b60405180910390a15050505050611417565b7f9b1bfa7fa9ee420a16e124f794c35ac9f90472acc99140eb2f6447c714cad8eb836000015184604001518360405161140993929190614a42565b60405180910390a15b505050505b50506005805460ff60a01b1916600160a01b179055505050505050505050565b60008060008060208601519150604086015192508560408151811061145857fe5b602001015160f81c60f81b60f81c601b0190506001858284866040516000815260200160405260405161148e9493929190614d19565b6020604051602081039080840390855afa1580156114b0573d6000803e3d6000fd5b5050506020604051035193505050505b92915050565b60f181565b600081565b60046020526000908152604090205481565b600260209081526000928352604080842090915290825290205481565b611507613c89565b61150f613cbe565b606061012884101561152160136132e0565b9061153f5760405162461bcd60e51b81526004016107769190614d37565b50611548613c89565b8585600081811061155557fe5b919091013560f81c8252508585600181811061156d57fe5b919091013560f81c60208301525060008686600281811061158a57fe5b845192013560f81c92505060ff16609e1480156115ae5750816020015160ff166001145b80156115bd575060ff81166001145b6115c760136132e0565b906115e55760405162461bcd60e51b81526004016107769190614d37565b50506115ef613cbe565b6115fd60c36003888a61503e565b81019061160a9190613f76565b6001600160a01b03908116604088810191909152918116875260a08801929092526080870192909252918216606086015291169083015261165061012860c3888a61503e565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050506020820152818161169988610128818c61503e565b81818080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250969e959d50919b50939950505050505050505050565b60f381565b60006001600160a01b0382166116fe5750476117b6565b611707826137c3565b6117235760405162461bcd60e51b815260040161077690614e15565b6040516370a0823160e01b81526001600160a01b038316906370a082319061174f903090600401614a2e565b60206040518083038186803b15801561176757600080fd5b505afa925050508015611797575060408051601f3d908101601f191682019092526117949181019061485d565b60015b6117b35760405162461bcd60e51b815260040161077690614e83565b90505b919050565b600554600160a01b900460ff166117d260016132e0565b906117f05760405162461bcd60e51b81526004016107769190614d37565b506005805460ff60a01b1916905589516082111561180e60066132e0565b9061182c5760405162461bcd60e51b81526004016107769190614d37565b50611835613c89565b61183e8b611c03565b805190915060ff1660f314801561185c5750806020015160ff166001145b61186660066132e0565b906118845760405162461bcd60e51b81526004016107769190614d37565b506118928160a00151611b33565b1561189d60056132e0565b906118bb5760405162461bcd60e51b81526004016107769190614d37565b5060a081015160009081526020819052604090819020805460ff191660011790558101516001600160a01b0316611946576040808201516001600160a01b031660009081526004602052205460808201516119159161350a565b47101561192260076132e0565b906119405760405162461bcd60e51b81526004016107769190614d37565b50611a58565b60006119558260400151612dd0565b905060098160ff16111561198257608082015161197c9060081960ff841601600a0a613570565b60808301525b6040808301516001600160a01b031660009081526004602052205460808301516119ab9161350a565b82604001516001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016119db9190614a2e565b60206040518083038186803b1580156119f357600080fd5b505afa158015611a07573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a2b919061485d565b1015611a3760076132e0565b90611a555760405162461bcd60e51b81526004016107769190614d37565b50505b611a6a8b8b8b8b8b8b8b8b8b8b6135d2565b608081015160608201516001600160a01b0390811660009081526002602090815260408083208187015190941683529290522054611aa79161350a565b60608201516001600160a01b03908116600090815260026020908152604080832081870180518616855290835281842095909555608086015194519093168252600490522054611af69161350a565b6040918201516001600160a01b031660009081526004602052919091205550506005805460ff60a01b1916600160a01b1790555050505050505050565b60008181526020819052604081205460ff1615611b52575060016117b6565b6005546001600160a01b0316611b6a575060006117b6565b6005546040517f749c5f860000000000000000000000000000000000000000000000000000000081526001600160a01b039091169063749c5f8690611bb3908590600401614cf1565b60206040518083038186803b158015611bcb57600080fd5b505afa158015611bdf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117b39190614328565b611c0b613c89565b611c13613c89565b82600081518110611c2057fe5b016020015160f81c8152825183906001908110611c3957fe5b0160209081015160f81c9082015260228301516042840151606285015160828601516001600160a01b039384166040860152929091166060840152608083015260a08201529050919050565b600554600160a01b900460ff16611c9c60016132e0565b90611cba5760405162461bcd60e51b81526004016107769190614d37565b506005805460ff60a01b191690556b033b2e3c9fd0803ce8000000471115611ce260026132e0565b90611d005760405162461bcd60e51b81526004016107769190614d37565b50611d418383838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506137c992505050565b7fd30df8040a1092415b49422a02dbd8cdd5915a596abcba02cd0f65dd86ab38516000868634611d716006613836565b604051611d82959493929190614b6a565b60405180910390a1611d94600661383a565b50506005805460ff60a01b1916600160a01b179055505050565b600554600160a01b900460ff16611dc560016132e0565b90611de35760405162461bcd60e51b81526004016107769190614d37565b506005805460ff60a01b191690556000611e5f611e03828d88888f613843565b8a8a8a8a604051602001611e1b959493929190614f36565b60408051601f198184030181526020601f8701819004810284018101909252858352919086908690819084018382808284376000920191909152506138c992505050565b9050611e6b818c61396d565b6001600160a01b038082166000908152600260209081526040808320938f16835292905220548a1115611e9e60086132e0565b90611ebc5760405162461bcd60e51b81526004016107769190614d37565b506001600160a01b038b16600090815260046020526040902054611ee0908b613aaf565b6001600160a01b03808d1660008181526004602090815260408083209590955592851681526002835283812091815291522054611f1d908b613aaf565b60026000836001600160a01b03166001600160a01b0316815260200190815260200160002060008d6001600160a01b03166001600160a01b0316815260200190815260200160002081905550600034905060006001600160a01b03168c6001600160a01b03161415611f9a57611f93818c61350a565b90506120db565b6040516370a0823160e01b81528b906001600160a01b038e16906370a0823190611fc8903090600401614a2e565b60206040518083038186803b158015611fe057600080fd5b505afa158015611ff4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612018919061485d565b101561202460076132e0565b906120425760405162461bcd60e51b81526004016107769190614d37565b5060095460405163a9059cbb60e01b81526001600160a01b038e81169263a9059cbb9261207792909116908f90600401614a66565b600060405180830381600087803b15801561209157600080fd5b505af11580156120a5573d6000803e3d6000fd5b505050506120b16134d6565b6120bb60046132e0565b906120d95760405162461bcd60e51b81526004016107769190614d37565b505b600061212d8b838b8b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050508d613b05565b905061218a8160026000866001600160a01b03166001600160a01b0316815260200190815260200160002060008e6001600160a01b03166001600160a01b031681526020019081526020016000205461350a90919063ffffffff16565b60026000856001600160a01b03166001600160a01b0316815260200190815260200160002060008d6001600160a01b03166001600160a01b031681526020019081526020016000208190555061220e81600460008e6001600160a01b03166001600160a01b031681526020019081526020016000205461350a90919063ffffffff16565b6001600160a01b03909b1660009081526004602052604090209a909a5550506005805460ff60a01b1916600160a01b17905550505050505050505050565b600360209081526000928352604080842090915290825290205460ff1681565b600554600160a01b900460ff1681565b6008541561228a60126132e0565b906122a85760405162461bcd60e51b81526004016107769190614d37565b5060026008556007546001600160a01b0316156122c560116132e0565b906122e35760405162461bcd60e51b81526004016107769190614d37565b50600780546001600160a01b0393841673ffffffffffffffffffffffffffffffffffffffff199182161790915560098054929093169116179055565b600554600160a01b900460ff1661233660016132e0565b906123545760405162461bcd60e51b81526004016107769190614d37565b506005805460ff60a01b19169055604080516020601f84018190048102820181019092528281526123a29185919085908590819084018382808284376000920191909152506137c992505050565b8660006123ae82612dd0565b90506000826001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016123de9190614a2e565b60206040518083038186803b1580156123f657600080fd5b505afa15801561240a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061242e919061485d565b90508089600960ff851611156124695760098460ff1603600a0a818161245057fe5b04905060098460ff1603600a0a838161246557fe5b0492505b670de0b6b3a764000081111580156124895750670de0b6b3a76400008311155b80156124a65750670de0b6b3a76400006124a3828561350a565b11155b6124b060036132e0565b906124ce5760405162461bcd60e51b81526004016107769190614d37565b50846001600160a01b03166323b872dd33308e6040518463ffffffff1660e01b81526004016124ff93929190614a42565b600060405180830381600087803b15801561251957600080fd5b505af115801561252d573d6000803e3d6000fd5b505050506125396134d6565b61254360046132e0565b906125615760405162461bcd60e51b81526004016107769190614d37565b508a612576836125708f6116e7565b90613aaf565b14612581600a6132e0565b9061259f5760405162461bcd60e51b81526004016107769190614d37565b507f2d4b597935f3cd67fb2eebf1db4debc934cee5c7baa7153f980fdbeb2e74084e8c8b8b846040516125d59493929190614b36565b60405180910390a150506005805460ff60a01b1916600160a01b17905550505050505050505050565b600554600160a01b900460ff1661261560016132e0565b906126335760405162461bcd60e51b81526004016107769190614d37565b506005805460ff60a01b19169055604080516020601f84018190048102820181019092528281526126819185919085908590819084018382808284376000920191909152506137c992505050565b86600061268d82612dd0565b90506000826001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016126bd9190614a2e565b60206040518083038186803b1580156126d557600080fd5b505afa1580156126e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061270d919061485d565b90508089600960ff851611156127485760098460ff1603600a0a818161272f57fe5b04905060098460ff1603600a0a838161274457fe5b0492505b670de0b6b3a764000081111580156127685750670de0b6b3a76400008311155b80156127855750670de0b6b3a7640000612782828561350a565b11155b61278f60036132e0565b906127ad5760405162461bcd60e51b81526004016107769190614d37565b50846001600160a01b03166323b872dd33308e6040518463ffffffff1660e01b81526004016127de93929190614a42565b600060405180830381600087803b1580156127f857600080fd5b505af115801561280c573d6000803e3d6000fd5b505050506128186134d6565b61282260046132e0565b906128405760405162461bcd60e51b81526004016107769190614d37565b508a61284f836125708f6116e7565b1461285a600a6132e0565b906128785760405162461bcd60e51b81526004016107769190614d37565b507fd30df8040a1092415b49422a02dbd8cdd5915a596abcba02cd0f65dd86ab38518c8b8b846128a86006613836565b6040516128b9959493929190614b6a565b60405180910390a16128cb600661383a565b50506005805460ff60a01b1916600160a01b17905550505050505050505050565b609e81565b600030331461290060146132e0565b9061291e5760405162461bcd60e51b81526004016107769190614d37565b50600061292a836116e7565b9050606060006001600160a01b0389166129455750856129dd565b60095460405163a9059cbb60e01b81526001600160a01b038b81169263a9059cbb9261297992909116908b90600401614a66565b600060405180830381600087803b15801561299357600080fd5b505af11580156129a7573d6000803e3d6000fd5b505050506129b36134d6565b6129bd60046132e0565b906129db5760405162461bcd60e51b81526004016107769190614d37565b505b600954604051631cff79cd60e01b81526001600160a01b0390911690631cff79cd908390612a11908c908b90600401614adf565b6000604051808303818588803b158015612a2a57600080fd5b505af1158015612a3e573d6000803e3d6000fd5b50505050506040513d6000823e601f3d908101601f19168201604052612a679190810190614516565b91508151604014612a7860096132e0565b90612a965760405162461bcd60e51b81526004016107769190614d37565b5060008083806020019051810190612aae9190613fe5565b91509150866001600160a01b0316826001600160a01b0316148015612ade575080612adc866125708a6116e7565b145b612ae860096132e0565b90612b065760405162461bcd60e51b81526004016107769190614d37565b509a9950505050505050505050565b600554600160a81b900460ff1615612b2d600f6132e0565b90612b4b5760405162461bcd60e51b81526004016107769190614d37565b506005805460ff60a01b197fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff6001600160a01b0380881673ffffffffffffffffffffffffffffffffffffffff199094169390931716600160a81b1716600160a01b179091556007541615612bbf60116132e0565b90612bdd5760405162461bcd60e51b81526004016107769190614d37565b50600780546001600160a01b0393841673ffffffffffffffffffffffffffffffffffffffff199182161790915560098054929093169116179055506002600855565b6009546001600160a01b031681565b600554600160a01b900460ff16612c4560016132e0565b90612c635760405162461bcd60e51b81526004016107769190614d37565b506005805460ff60a01b191690556b033b2e3c9fd0803ce8000000471115612c8b60026132e0565b90612ca95760405162461bcd60e51b81526004016107769190614d37565b50612cea8383838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506137c992505050565b7f2d4b597935f3cd67fb2eebf1db4debc934cee5c7baa7153f980fdbeb2e74084e6000868634604051612d209493929190614b36565b60405180910390a150506005805460ff60a01b1916600160a01b179055505050565b6007546001600160a01b03161580612d6457506007546001600160a01b031633145b8015612d7857506001600160a01b03811615155b612d8260116132e0565b90612da05760405162461bcd60e51b81526004016107769190614d37565b506007805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055565b6000612ddb826137c3565b612df75760405162461bcd60e51b815260040161077690614e4c565b6000829050806001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b158015612e3557600080fd5b505afa925050508015612e65575060408051601f3d908101601f19168201909252612e629181019061485d565b60015b612e815760405162461bcd60e51b815260040161077690614d4a565b91506117b69050565b60085481565b600181565b60006020819052908152604090205460ff1681565b6007546001600160a01b031681565b60008181526001602052604081205460ff1615612ed8575060016117b6565b6005546001600160a01b0316612ef0575060006117b6565b6005546040517fe4bd70740000000000000000000000000000000000000000000000000000000081526001600160a01b039091169063e4bd707490611bb3908590600401614cf1565b6005546000906001600160a01b031615801590612f7c57506001600160a01b0380831660009081526003602090815260408083209387168352929052205460ff16155b1561303857600554604051637badcc6760e11b8152613031916001600160a01b03169063f75b98ce90612fb59087908790600401614a7f565b60206040518083038186803b158015612fcd57600080fd5b505afa158015612fe1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613005919061485d565b6001600160a01b038085166000908152600260209081526040808320938916835292905220549061350a565b90506114c0565b506001600160a01b0380821660009081526002602090815260408083209386168352929052205492915050565b6005546001600160a01b031681565b600554600160a01b900460ff1661308b60016132e0565b906130a95760405162461bcd60e51b81526004016107769190614d37565b506005805460ff60a01b19169055604080516020601f84018190048102820181019092528281526130f79185919085908590819084018382808284376000920191909152506137c992505050565b600061316261310a60018c89898e613843565b8d8d60405160200161311e93929190614f7f565b60408051601f198184030181526020601f8c018190048102840181019092528a835291908b908b90819084018382808284376000920191909152506138c992505050565b905061316e818b61396d565b6001600160a01b038082166000908152600260209081526040808320938e16835292905220548911156131a160086132e0565b906131bf5760405162461bcd60e51b81526004016107769190614d37565b506001600160a01b038082166000908152600260209081526040808320938e16835292905220546131f0908a613aaf565b6001600160a01b038083166000908152600260209081526040808320938f16835292815282822093909355600490925290205461322d908a613aaf565b6001600160a01b038b1660008181526004602052604090209190915589901561328157600061325b8c612dd0565b905060098160ff16111561327f5760098160ff1603600a0a8b8161327b57fe5b0491505b505b7f2d4b597935f3cd67fb2eebf1db4debc934cee5c7baa7153f980fdbeb2e74084e8b8e8e846040516132b69493929190614b36565b60405180910390a150506005805460ff60a01b1916600160a01b1790555050505050505050505050565b606060008260148111156132f057fe5b60408051600a808252818301909252919250906060908260208201818036833701905050905060005b60ff84161561337f578151600a60ff959095168581049560018401939106916030830160f81b918591811061334a57fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535050613319565b60608160010167ffffffffffffffff8111801561339b57600080fd5b506040519080825280601f01601f1916602001820160405280156133c6576020820181803683370190505b50905060005b82811161342f5783818403815181106133e157fe5b602001015160f81c60f81b8282815181106133f857fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053506001016133cc565b509695505050505050565b8047101561345a5760405162461bcd60e51b815260040161077690614dde565b6000826001600160a01b03168260405161347390614a2b565b60006040518083038185875af1925050503d80600081146134b0576040519150601f19603f3d011682016040523d82523d6000602084013e6134b5565b606091505b505090508061082f5760405162461bcd60e51b815260040161077690614d81565b6000803d80156134ed57602081146134f657613502565b60019150613502565b60206000803e60005191505b501515905090565b600082820183811080159061351f5750828110155b6040518060400160405280601281526020017129b0b332a6b0ba341032bc31b2b83a34b7b760711b815250906135685760405162461bcd60e51b81526004016107769190614d37565b509392505050565b600082820283158061351f57508284828161358757fe5b04146040518060400160405280601281526020017129b0b332a6b0ba341032bc31b2b83a34b7b760711b815250906135685760405162461bcd60e51b81526004016107769190614d37565b60008a8a6040516020016135e7929190614a09565b604051602081830303815290604052805190602001209050613607613c64565b6001600160a01b031663f65d21166001838d8d8d8d8d8d8d8d8d6040518c63ffffffff1660e01b81526004016136479b9a99989796959493929190614c44565b60206040518083038186803b15801561365f57600080fd5b505afa158015613673573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136979190614328565b6136a160066132e0565b906136bf5760405162461bcd60e51b81526004016107769190614d37565b505050505050505050505050565b816001600160a01b03851661371a576b033b2e3c9fd0803ce80000004711156136f660026132e0565b906137145760405162461bcd60e51b81526004016107769190614d37565b50613780565b600061372586612dd0565b905060098160ff1611156137495760098160ff1603600a0a828161374557fe5b0491505b670de0b6b3a764000082111561375f60036132e0565b9061377d5760405162461bcd60e51b81526004016107769190614d37565b50505b7eb45d95b5117447e2fafe7f34def913ff3ba220e4b8688acf37ae2328af7a3d858583856040516137b49493929190614b01565b60405180910390a15050505050565b3b151590565b6000613818826040518060400160405280336001600160a01b03168152602001868152506040516020016137fd9190614fa5565b60405160208183030381529060405280519060200120611437565b6007549091506001600160a01b0380831691161461080f60106132e0565b5490565b80546001019055565b61384b613cf1565b613853613cf1565b604051806080016040528088600781111561386a57fe5b8152602001876001600160a01b0316815260200186868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509082525060200184905291505095945050505050565b815160208301206000906138dc81612eb9565b156138e760056132e0565b906139055760405162461bcd60e51b81526004016107769190614d37565b5060006139128483611437565b90506001600160a01b038116151561392a60106132e0565b906139485760405162461bcd60e51b81526004016107769190614d37565b506000918252600160208190526040909220805460ff19169092179091559392505050565b6005546001600160a01b0316158015906139ad57506001600160a01b0380831660009081526003602090815260408083209385168352929052205460ff16155b15613aab57600554604051637badcc6760e11b8152613a62916001600160a01b03169063f75b98ce906139e69085908790600401614a7f565b60206040518083038186803b1580156139fe57600080fd5b505afa158015613a12573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a36919061485d565b6001600160a01b038085166000908152600260209081526040808320938716835292905220549061350a565b6001600160a01b038084166000818152600260209081526040808320948716808452948252808320959095559181526003825283812092815291905220805460ff191660011790555b5050565b6000828211156040518060400160405280601281526020017129b0b332a6b0ba341032bc31b2b83a34b7b760711b81525090613afe5760405162461bcd60e51b81526004016107769190614d37565b5050900390565b600080613b11866116e7565b90506001600160a01b038616613b2e57613b2b8134613aaf565b90505b84471015613b3c60076132e0565b90613b5a5760405162461bcd60e51b81526004016107769190614d37565b50600954604051631cff79cd60e01b81526060916001600160a01b031690631cff79cd908890613b909088908a90600401614adf565b6000604051808303818588803b158015613ba957600080fd5b505af1158015613bbd573d6000803e3d6000fd5b50505050506040513d6000823e601f3d908101601f19168201604052613be69190810190614516565b905060008082806020019051810190613bff9190613fe5565b91509150886001600160a01b0316826001600160a01b0316148015613c2f575080613c2d856125708c6116e7565b145b613c3960096132e0565b90613c575760405162461bcd60e51b81526004016107769190614d37565b5098975050505050505050565b7f62135fc083646fdb4e1a9d700e351b886a4a5a39da980650269edd1ade91ffd25490565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a081019190915290565b604051806060016040528060006001600160a01b031681526020016060815260200160006001600160a01b031681525090565b6040805160808101909152806000815260200160006001600160a01b0316815260200160608152602001600081525090565b80356114c081615092565b60008083601f840112613d3f578182fd5b50813567ffffffffffffffff811115613d56578182fd5b6020830191508360208083028501011115613d7057600080fd5b9250929050565b600082601f830112613d87578081fd5b8135613d9a613d9582614ffa565b614fd3565b818152915060208083019084810181840286018201871015613dbb57600080fd5b60005b84811015613de3578135613dd1816150aa565b84529282019290820190600101613dbe565b505050505092915050565b600082601f830112613dfe578081fd5b8135613e0c613d9582614ffa565b818152915060208083019084810181840286018201871015613e2d57600080fd5b60005b84811015613de357813584529282019290820190600101613e30565b600082601f830112613e5c578081fd5b8135613e6a613d9582614ffa565b818152915060208083019084810181840286018201871015613e8b57600080fd5b6000805b85811015613eb957823560ff81168114613ea7578283fd5b85529383019391830191600101613e8f565b50505050505092915050565b60008083601f840112613ed6578182fd5b50813567ffffffffffffffff811115613eed578182fd5b602083019150836020828501011115613d7057600080fd5b600082601f830112613f15578081fd5b8135613f23613d958261501a565b9150808252836020828501011115613f3a57600080fd5b8060208401602084013760009082016020015292915050565b600060208284031215613f64578081fd5b8135613f6f81615092565b9392505050565b60008060008060008060c08789031215613f8e578182fd5b8635613f9981615092565b95506020870135613fa981615092565b945060408701359350606087013592506080870135613fc781615092565b915060a0870135613fd781615092565b809150509295509295509295565b60008060408385031215613ff7578182fd5b825161400281615092565b6020939093015192949293505050565b60008060408385031215614024578182fd5b823561402f81615092565b9150602083013561403f81615092565b809150509250929050565b60008060006060848603121561405e578081fd5b833561406981615092565b9250602084013561407981615092565b929592945050506040919091013590565b60008060006060848603121561409e578081fd5b83356140a981615092565b925060208401356140b981615092565b915060408401356140c981615092565b809150509250925092565b600080600080600060a086880312156140eb578283fd5b85356140f681615092565b9450602086013561410681615092565b935060408601359250606086013567ffffffffffffffff811115614128578182fd5b61413488828901613f05565b925050608086013561414581615092565b809150509295509295909350565b60008060008060008060008060008060e08b8d031215614171578788fd5b8a3561417c81615092565b995060208b0135985060408b013561419381615092565b97506141a28c60608d01613d23565b965060808b013567ffffffffffffffff808211156141be578586fd5b6141ca8e838f01613ec5565b909850965060a08d01359150808211156141e2578586fd5b6141ee8e838f01613ec5565b909650945060c08d0135915080821115614206578384fd5b506142138d828e01613ec5565b915080935050809150509295989b9194979a5092959850565b600080600080600080600060a0888a031215614246578081fd5b873561425181615092565b965060208801359550604088013567ffffffffffffffff80821115614274578283fd5b6142808b838c01613ec5565b909750955060608a0135945060808a013591508082111561429f578283fd5b506142ac8a828b01613ec5565b989b979a50959850939692959293505050565b600080600080604085870312156142d4578182fd5b843567ffffffffffffffff808211156142eb578384fd5b6142f788838901613d2e565b9096509450602087013591508082111561430f578384fd5b5061431c87828801613d2e565b95989497509550505050565b600060208284031215614339578081fd5b8151613f6f816150aa565b600060208284031215614355578081fd5b5035919050565b6000806020838503121561436e578182fd5b823567ffffffffffffffff811115614384578283fd5b61439085828601613ec5565b90969095509350505050565b60008060008060008060008060008060006101408c8e0312156143bd578485fd5b67ffffffffffffffff808d3511156143d3578586fd5b6143e08e8e358f01613ec5565b909c509a5060208d0135995060408d01358110156143fc578586fd5b61440c8e60408f01358f01613dee565b98508060608e0135111561441e578586fd5b61442e8e60608f01358f01613d77565b975060808d0135965060a08d013595508060c08e0135111561444e578182fd5b61445e8e60c08f01358f01613dee565b94508060e08e01351115614470578182fd5b6144808e60e08f01358f01613e4c565b9350806101008e01351115614493578182fd5b6144a48e6101008f01358f01613dee565b9250806101208e013511156144b7578182fd5b506144c98d6101208e01358e01613dee565b90509295989b509295989b9093969950565b6000602082840312156144ec578081fd5b813567ffffffffffffffff811115614502578182fd5b61450e84828501613f05565b949350505050565b600060208284031215614527578081fd5b815167ffffffffffffffff81111561453d578182fd5b8201601f8101841361454d578182fd5b805161455b613d958261501a565b81815285602083850101111561456f578384fd5b614580826020830160208601615066565b95945050505050565b6000806040838503121561459b578182fd5b823567ffffffffffffffff8111156145b1578283fd5b6145bd85828601613f05565b95602094909401359450505050565b6000806000806000806000806000806101408b8d0312156145eb578384fd5b8a3567ffffffffffffffff80821115614602578586fd5b61460e8e838f01613f05565b9b5060208d01359a5060408d013591508082111561462a578586fd5b6146368e838f01613dee565b995060608d013591508082111561464b578586fd5b6146578e838f01613d77565b985060808d0135975060a08d0135965060c08d013591508082111561467a578586fd5b6146868e838f01613dee565b955060e08d013591508082111561469b578485fd5b6146a78e838f01613e4c565b94506101008d01359150808211156146bd578384fd5b6146c98e838f01613dee565b93506101208d01359150808211156146df578283fd5b506146ec8d828e01613dee565b9150509295989b9194979a5092959850565b600080600080600080600080600080600060e08c8e03121561471e578485fd5b67ffffffffffffffff808d351115614734578586fd5b6147418e8e358f01613ec5565b909c509a506147538e60208f01613d23565b995060408d013598508060608e0135111561476c578586fd5b61477c8e60608f01358f01613ec5565b909850965060808d0135811015614791578586fd5b6147a18e60808f01358f01613ec5565b909650945060a08d0135935060c08d01358110156147bd578182fd5b506147ce8d60c08e01358e01613ec5565b81935080925050509295989b509295989b9093969950565b6000806000806000606086880312156147fd578283fd5b853567ffffffffffffffff80821115614814578485fd5b61482089838a01613ec5565b909750955060208801359450604088013591508082111561483f578283fd5b5061484c88828901613ec5565b969995985093965092949392505050565b60006020828403121561486e578081fd5b5051919050565b6000815180845260208085019450808401835b838110156148a6578151151587529582019590820190600101614888565b509495945050505050565b6000815180845260208085019450808401835b838110156148a6578151875295820195908201906001016148c4565b6000815180845260208085019450808401835b838110156148a657815160ff16875295820195908201906001016148f3565b60008284528282602086013780602084860101526020601f19601f85011685010190509392505050565b60008151808452614954816020860160208601615066565b601f01601f19169290920160200192915050565b60ff815116825260ff602082015116602083015260408101516001600160a01b03808216604085015280606084015116606085015250506080810151608083015260a081015160a08301525050565b60008151600881106149c557fe5b808452506001600160a01b0360208301511660208401526040820151608060408501526149f5608085018261493c565b606093840151949093019390935250919050565b60008351614a1b818460208801615066565b9190910191825250602001919050565b90565b6001600160a01b0391909116815260200190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b0392831681529116602082015260400190565b60006001600160a01b038088168352808716602084015285604084015260a06060840152614aca60a084018661493c565b91508084166080840152509695505050505050565b60006001600160a01b03841682526040602083015261450e604083018461493c565b60006001600160a01b038616825260806020830152614b23608083018661493c565b6040830194909452506060015292915050565b60006001600160a01b038616825260606020830152614b59606083018587614912565b905082604083015295945050505050565b60006001600160a01b038716825260806020830152614b8d608083018688614912565b604083019490945250606001529392505050565b6040808252810184905260008560608301825b87811015614be45760208335614bc981615092565b6001600160a01b031683529283019290910190600101614bb4565b5083810360208501528481527f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff851115614c1c578283fd5b602085029150818660208301370160200190815295945050505050565b901515815260200190565b60006101608d151583528c60208401528b6040840152806060840152614c6c8184018c6148b1565b90508281036080840152614c80818b614875565b90508860a08401528760c084015282810360e0840152614ca081886148b1565b9050828103610100840152614cb581876148e0565b9050828103610120840152614cca81866148b1565b9050828103610140840152614cdf81856148b1565b9e9d5050505050505050505050505050565b90815260200190565b600084825283602083015260606040830152614580606083018461493c565b93845260ff9290921660208401526040830152606082015260800190565b600060208252613f6f602083018461493c565b60208082526018908201527f67657420455243323020646563696d616c206661696c65640000000000000000604082015260600190565b6020808252603a908201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260408201527f6563697069656e74206d61792068617665207265766572746564000000000000606082015260800190565b6020808252601d908201527f416464726573733a20696e73756666696369656e742062616c616e6365000000604082015260600190565b60208082526016908201527f62616c616e63654f66206e6f6e2d636f6e747261637400000000000000000000604082015260600190565b60208082526018908201527f676574446563696d616c73206e6f6e2d636f6e74726163740000000000000000604082015260600190565b60208082526018908201527f6765742045524332302062616c616e6365206661696c65640000000000000000604082015260600190565b60c081016114c08284614968565b6000610100614ed78387614968565b8060c08401526001600160a01b038086511682850152602086015191506060610120850152614f0a61016085018361493c565b9150806040870151166101408501525082810360e0840152614f2c818561493c565b9695505050505050565b600060808252614f4960808301886149b7565b6001600160a01b038781166020850152861660408401528281036060840152614f73818587614912565b98975050505050505050565b600060408252614f9260408301866149b7565b8281036020840152614f2c818587614912565b81516001600160a01b031681526020918201519181019190915260400190565b60ff91909116815260200190565b60405181810167ffffffffffffffff81118282101715614ff257600080fd5b604052919050565b600067ffffffffffffffff821115615010578081fd5b5060209081020190565b600067ffffffffffffffff821115615030578081fd5b50601f01601f191660200190565b6000808585111561504d578182fd5b83861115615059578182fd5b5050820193919092039150565b60005b83811015615081578181015183820152602001615069565b8381111561082d5750506000910152565b6001600160a01b03811681146150a757600080fd5b50565b80151581146150a757600080fdfea264697066735822122099ad7207700f19c214687c5501da9eb61c9c1fba2a2d9dd954462f4e3c6de73364736f6c634300060c0033

Deployed Bytecode

0x6080604052600436106102a45760003560e01c8063995fac111161016e578063cde0a4f8116100cb578063dd8fee141161007f578063f75b98ce11610064578063f75b98ce146106f6578063fa84702e14610716578063fee8efda1461072b576102ab565b8063dd8fee14146106c1578063e4bd7074146106d6576102ab565b8063d6a1fe3b116100b0578063d6a1fe3b14610677578063d7200eb11461068c578063dca40d9e146106a1576102ab565b8063cde0a4f814610637578063cf54aaa014610657576102ab565b8063bd835c4211610122578063c0c53b8b11610107578063c0c53b8b146105ef578063c34c08e51461060f578063c791d70514610624576102ab565b8063bd835c42146105ba578063bda9b509146105cf576102ab565b8063a73b153211610153578063a73b15321461055a578063a807b5bb1461057a578063b8237dbb1461059a576102ab565b8063995fac1114610525578063a3f5d8cc14610545576102ab565b80636304541c1161021c57806373bf9651116101d05780637e16e6e1116101b55780637e16e6e1146104d257806384b3ac03146104ff5780638588ccd614610512576102ab565b806373bf965114610492578063749c5f86146104b2576102ab565b806366945b311161020157806366945b311461042e5780636f2cbc481461045d57806370a0823114610472576102ab565b80636304541c146103e157806365b5a00f1461040e576102ab565b8063392e53cd116102735780633fec6b40116102585780633fec6b401461037d578063568c04fd146103aa57806358bc8337146103cc576102ab565b8063392e53cd146103485780633ed1b3761461035d576102ab565b8063145e2a6b146102b05780631beb7de2146102d25780631ea1940e146102f25780631ed4276d14610328576102ab565b366102ab57005b600080fd5b3480156102bc57600080fd5b506102d06102cb36600461404a565b61074b565b005b3480156102de57600080fd5b506102d06102ed3660046145cc565b610834565b3480156102fe57600080fd5b5061031261030d366004614344565b610c91565b60405161031f9190614c39565b60405180910390f35b34801561033457600080fd5b506103126103433660046142bf565b610ca6565b34801561035457600080fd5b50610312610ec7565b34801561036957600080fd5b506102d061037836600461439c565b610ed7565b34801561038957600080fd5b5061039d610398366004614589565b611437565b60405161031f9190614a2e565b3480156103b657600080fd5b506103bf6114c6565b60405161031f9190614fc5565b3480156103d857600080fd5b5061039d6114cb565b3480156103ed57600080fd5b506104016103fc366004613f53565b6114d0565b60405161031f9190614cf1565b34801561041a57600080fd5b50610401610429366004614012565b6114e2565b34801561043a57600080fd5b5061044e61044936600461435c565b6114ff565b60405161031f93929190614ec8565b34801561046957600080fd5b506103bf6116e2565b34801561047e57600080fd5b5061040161048d366004613f53565b6116e7565b34801561049e57600080fd5b506102d06104ad3660046145cc565b6117bb565b3480156104be57600080fd5b506103126104cd366004614344565b611b33565b3480156104de57600080fd5b506104f26104ed3660046144db565b611c03565b60405161031f9190614eba565b6102d061050d3660046147e6565b611c85565b6102d0610520366004614153565b611dae565b34801561053157600080fd5b50610312610540366004614012565b61224c565b34801561055157600080fd5b5061031261226c565b34801561056657600080fd5b506102d0610575366004614012565b61227c565b34801561058657600080fd5b506102d061059536600461422c565b61231f565b3480156105a657600080fd5b506102d06105b536600461422c565b6125fe565b3480156105c657600080fd5b506103bf6128ec565b3480156105db57600080fd5b506104016105ea3660046140d4565b6128f1565b3480156105fb57600080fd5b506102d061060a36600461408a565b612b15565b34801561061b57600080fd5b5061039d612c1f565b6102d06106323660046147e6565b612c2e565b34801561064357600080fd5b506102d0610652366004613f53565b612d42565b34801561066357600080fd5b506103bf610672366004613f53565b612dd0565b34801561068357600080fd5b50610401612e8a565b34801561069857600080fd5b506103bf612e90565b3480156106ad57600080fd5b506103126106bc366004614344565b612e95565b3480156106cd57600080fd5b5061039d612eaa565b3480156106e257600080fd5b506103126106f1366004614344565b612eb9565b34801561070257600080fd5b50610401610711366004614012565b612f39565b34801561072257600080fd5b5061039d613065565b34801561073757600080fd5b506102d06107463660046146fe565b613074565b30331461075860146132e0565b9061077f5760405162461bcd60e51b81526004016107769190614d37565b60405180910390fd5b506001600160a01b03831661079d57610798828261343a565b61082f565b60405163a9059cbb60e01b81526001600160a01b0384169063a9059cbb906107cb9085908590600401614a66565b600060405180830381600087803b1580156107e557600080fd5b505af11580156107f9573d6000803e3d6000fd5b505050506108056134d6565b61080f60046132e0565b9061082d5760405162461bcd60e51b81526004016107769190614d37565b505b505050565b600554600160a01b900460ff1661084b60016132e0565b906108695760405162461bcd60e51b81526004016107769190614d37565b506005805460ff60a01b1916905589516082111561088760066132e0565b906108a55760405162461bcd60e51b81526004016107769190614d37565b506108ae613c89565b6108b78b611c03565b805190915060ff1660f11480156108d55750806020015160ff166001145b6108df60066132e0565b906108fd5760405162461bcd60e51b81526004016107769190614d37565b5061090b8160a00151611b33565b1561091660056132e0565b906109345760405162461bcd60e51b81526004016107769190614d37565b5060a081015160009081526020819052604090819020805460ff191660011790558101516001600160a01b03166109bf576040808201516001600160a01b0316600090815260046020522054608082015161098e9161350a565b47101561099b60076132e0565b906109b95760405162461bcd60e51b81526004016107769190614d37565b50610ad1565b60006109ce8260400151612dd0565b905060098160ff1611156109fb5760808201516109f59060081960ff841601600a0a613570565b60808301525b6040808301516001600160a01b03166000908152600460205220546080830151610a249161350a565b82604001516001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401610a549190614a2e565b60206040518083038186803b158015610a6c57600080fd5b505afa158015610a80573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aa4919061485d565b1015610ab060076132e0565b90610ace5760405162461bcd60e51b81526004016107769190614d37565b50505b610ae38b8b8b8b8b8b8b8b8b8b6135d2565b60408101516001600160a01b0316610b8c57600081606001516001600160a01b03168260800151604051610b1690614a2b565b60006040518083038185875af1925050503d8060008114610b53576040519150601f19603f3d011682016040523d82523d6000602084013e610b58565b606091505b5050905080610b6760046132e0565b90610b855760405162461bcd60e51b81526004016107769190614d37565b5050610c2a565b80604001516001600160a01b031663a9059cbb826060015183608001516040518363ffffffff1660e01b8152600401610bc6929190614a66565b600060405180830381600087803b158015610be057600080fd5b505af1158015610bf4573d6000803e3d6000fd5b50505050610c006134d6565b610c0a60046132e0565b90610c285760405162461bcd60e51b81526004016107769190614d37565b505b7f9b1bfa7fa9ee420a16e124f794c35ac9f90472acc99140eb2f6447c714cad8eb816040015182606001518360800151604051610c6993929190614a42565b60405180910390a150506005805460ff60a01b1916600160a01b179055505050505050505050565b60016020526000908152604090205460ff1681565b6005546000906001600160a01b031615801590610ccd57506005546001600160a01b031633145b610cd7600c6132e0565b90610cf55760405162461bcd60e51b81526004016107769190614d37565b50838214610d03600a6132e0565b90610d215760405162461bcd60e51b81526004016107769190614d37565b50600560009054906101000a90046001600160a01b03166001600160a01b0316635c975abb6040518163ffffffff1660e01b815260040160206040518083038186803b158015610d7057600080fd5b505afa158015610d84573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610da89190614328565b610db2600d6132e0565b90610dd05760405162461bcd60e51b81526004016107769190614d37565b5060005b84811015610e7e57610e37848483818110610deb57fe5b9050602002013560046000898986818110610e0257fe5b9050602002016020810190610e179190613f53565b6001600160a01b031681526020810191909152604001600020549061350a565b60046000888885818110610e4757fe5b9050602002016020810190610e5c9190613f53565b6001600160a01b03168152602081019190915260400160002055600101610dd4565b507f6a7fbbcddfd518bb8c56b28ac6c7acb0f7ca093ed232eb3306e53d14e469895f85858585604051610eb49493929190614ba1565b60405180910390a1506001949350505050565b600554600160a81b900460ff1681565b600554600160a01b900460ff16610eee60016132e0565b90610f0c5760405162461bcd60e51b81526004016107769190614d37565b506005805460ff60a01b19169055610f22613c89565b610f2a613cbe565b6060610f368e8e6114ff565b925092509250610f498360a00151611b33565b15610f5460056132e0565b90610f725760405162461bcd60e51b81526004016107769190614d37565b5060a083015160009081526020819052604090819020805460ff191660011790558301516001600160a01b0316610ffd576040808401516001600160a01b03166000908152600460205220546080840151610fcc9161350a565b471015610fd960076132e0565b90610ff75760405162461bcd60e51b81526004016107769190614d37565b5061110f565b600061100c8460400151612dd0565b905060098160ff1611156110395760808401516110339060081960ff841601600a0a613570565b60808501525b6040808501516001600160a01b031660009081526004602052205460808501516110629161350a565b84604001516001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016110929190614a2e565b60206040518083038186803b1580156110aa57600080fd5b505afa1580156110be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110e2919061485d565b10156110ee60076132e0565b9061110c5760405162461bcd60e51b81526004016107769190614d37565b50505b6111658e8e8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050508d8d8d8d8d8d8d8d8d6135d2565b60408084015160608501516080860151855193517fbda9b509000000000000000000000000000000000000000000000000000000008152309463bda9b509946111b8949093909290918891600401614a99565b602060405180830381600087803b1580156111d257600080fd5b505af1925050508015611202575060408051601f3d908101601f191682019092526111ff9181019061485d565b60015b61129b573d808015611230576040519150601f19603f3d011682016040523d82523d6000602084013e611235565b606091505b506112528460400151846020015186608001518760a001516136cd565b7fdbbb883f24557adf486292429863dcfd4ac5d4db168ae94921da8e3d9a95d4168460a0015160008360405161128a93929190614cfa565b60405180910390a150505050611417565b60408301516001600160a01b03166112ca576112c583600001518460200151838760a001516136cd565b611412565b825160408085015190517f145e2a6b000000000000000000000000000000000000000000000000000000008152309263145e2a6b9261130d928690600401614a42565b600060405180830381600087803b15801561132757600080fd5b505af1925050508015611338575060015b6113ce573d808015611366576040519150601f19603f3d011682016040523d82523d6000602084013e61136b565b606091505b5061138484600001518560200151848860a001516136cd565b7fdbbb883f24557adf486292429863dcfd4ac5d4db168ae94921da8e3d9a95d4168560a001516001836040516113bc93929190614cfa565b60405180910390a15050505050611417565b7f9b1bfa7fa9ee420a16e124f794c35ac9f90472acc99140eb2f6447c714cad8eb836000015184604001518360405161140993929190614a42565b60405180910390a15b505050505b50506005805460ff60a01b1916600160a01b179055505050505050505050565b60008060008060208601519150604086015192508560408151811061145857fe5b602001015160f81c60f81b60f81c601b0190506001858284866040516000815260200160405260405161148e9493929190614d19565b6020604051602081039080840390855afa1580156114b0573d6000803e3d6000fd5b5050506020604051035193505050505b92915050565b60f181565b600081565b60046020526000908152604090205481565b600260209081526000928352604080842090915290825290205481565b611507613c89565b61150f613cbe565b606061012884101561152160136132e0565b9061153f5760405162461bcd60e51b81526004016107769190614d37565b50611548613c89565b8585600081811061155557fe5b919091013560f81c8252508585600181811061156d57fe5b919091013560f81c60208301525060008686600281811061158a57fe5b845192013560f81c92505060ff16609e1480156115ae5750816020015160ff166001145b80156115bd575060ff81166001145b6115c760136132e0565b906115e55760405162461bcd60e51b81526004016107769190614d37565b50506115ef613cbe565b6115fd60c36003888a61503e565b81019061160a9190613f76565b6001600160a01b03908116604088810191909152918116875260a08801929092526080870192909252918216606086015291169083015261165061012860c3888a61503e565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050506020820152818161169988610128818c61503e565b81818080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250969e959d50919b50939950505050505050505050565b60f381565b60006001600160a01b0382166116fe5750476117b6565b611707826137c3565b6117235760405162461bcd60e51b815260040161077690614e15565b6040516370a0823160e01b81526001600160a01b038316906370a082319061174f903090600401614a2e565b60206040518083038186803b15801561176757600080fd5b505afa925050508015611797575060408051601f3d908101601f191682019092526117949181019061485d565b60015b6117b35760405162461bcd60e51b815260040161077690614e83565b90505b919050565b600554600160a01b900460ff166117d260016132e0565b906117f05760405162461bcd60e51b81526004016107769190614d37565b506005805460ff60a01b1916905589516082111561180e60066132e0565b9061182c5760405162461bcd60e51b81526004016107769190614d37565b50611835613c89565b61183e8b611c03565b805190915060ff1660f314801561185c5750806020015160ff166001145b61186660066132e0565b906118845760405162461bcd60e51b81526004016107769190614d37565b506118928160a00151611b33565b1561189d60056132e0565b906118bb5760405162461bcd60e51b81526004016107769190614d37565b5060a081015160009081526020819052604090819020805460ff191660011790558101516001600160a01b0316611946576040808201516001600160a01b031660009081526004602052205460808201516119159161350a565b47101561192260076132e0565b906119405760405162461bcd60e51b81526004016107769190614d37565b50611a58565b60006119558260400151612dd0565b905060098160ff16111561198257608082015161197c9060081960ff841601600a0a613570565b60808301525b6040808301516001600160a01b031660009081526004602052205460808301516119ab9161350a565b82604001516001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016119db9190614a2e565b60206040518083038186803b1580156119f357600080fd5b505afa158015611a07573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a2b919061485d565b1015611a3760076132e0565b90611a555760405162461bcd60e51b81526004016107769190614d37565b50505b611a6a8b8b8b8b8b8b8b8b8b8b6135d2565b608081015160608201516001600160a01b0390811660009081526002602090815260408083208187015190941683529290522054611aa79161350a565b60608201516001600160a01b03908116600090815260026020908152604080832081870180518616855290835281842095909555608086015194519093168252600490522054611af69161350a565b6040918201516001600160a01b031660009081526004602052919091205550506005805460ff60a01b1916600160a01b1790555050505050505050565b60008181526020819052604081205460ff1615611b52575060016117b6565b6005546001600160a01b0316611b6a575060006117b6565b6005546040517f749c5f860000000000000000000000000000000000000000000000000000000081526001600160a01b039091169063749c5f8690611bb3908590600401614cf1565b60206040518083038186803b158015611bcb57600080fd5b505afa158015611bdf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117b39190614328565b611c0b613c89565b611c13613c89565b82600081518110611c2057fe5b016020015160f81c8152825183906001908110611c3957fe5b0160209081015160f81c9082015260228301516042840151606285015160828601516001600160a01b039384166040860152929091166060840152608083015260a08201529050919050565b600554600160a01b900460ff16611c9c60016132e0565b90611cba5760405162461bcd60e51b81526004016107769190614d37565b506005805460ff60a01b191690556b033b2e3c9fd0803ce8000000471115611ce260026132e0565b90611d005760405162461bcd60e51b81526004016107769190614d37565b50611d418383838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506137c992505050565b7fd30df8040a1092415b49422a02dbd8cdd5915a596abcba02cd0f65dd86ab38516000868634611d716006613836565b604051611d82959493929190614b6a565b60405180910390a1611d94600661383a565b50506005805460ff60a01b1916600160a01b179055505050565b600554600160a01b900460ff16611dc560016132e0565b90611de35760405162461bcd60e51b81526004016107769190614d37565b506005805460ff60a01b191690556000611e5f611e03828d88888f613843565b8a8a8a8a604051602001611e1b959493929190614f36565b60408051601f198184030181526020601f8701819004810284018101909252858352919086908690819084018382808284376000920191909152506138c992505050565b9050611e6b818c61396d565b6001600160a01b038082166000908152600260209081526040808320938f16835292905220548a1115611e9e60086132e0565b90611ebc5760405162461bcd60e51b81526004016107769190614d37565b506001600160a01b038b16600090815260046020526040902054611ee0908b613aaf565b6001600160a01b03808d1660008181526004602090815260408083209590955592851681526002835283812091815291522054611f1d908b613aaf565b60026000836001600160a01b03166001600160a01b0316815260200190815260200160002060008d6001600160a01b03166001600160a01b0316815260200190815260200160002081905550600034905060006001600160a01b03168c6001600160a01b03161415611f9a57611f93818c61350a565b90506120db565b6040516370a0823160e01b81528b906001600160a01b038e16906370a0823190611fc8903090600401614a2e565b60206040518083038186803b158015611fe057600080fd5b505afa158015611ff4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612018919061485d565b101561202460076132e0565b906120425760405162461bcd60e51b81526004016107769190614d37565b5060095460405163a9059cbb60e01b81526001600160a01b038e81169263a9059cbb9261207792909116908f90600401614a66565b600060405180830381600087803b15801561209157600080fd5b505af11580156120a5573d6000803e3d6000fd5b505050506120b16134d6565b6120bb60046132e0565b906120d95760405162461bcd60e51b81526004016107769190614d37565b505b600061212d8b838b8b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050508d613b05565b905061218a8160026000866001600160a01b03166001600160a01b0316815260200190815260200160002060008e6001600160a01b03166001600160a01b031681526020019081526020016000205461350a90919063ffffffff16565b60026000856001600160a01b03166001600160a01b0316815260200190815260200160002060008d6001600160a01b03166001600160a01b031681526020019081526020016000208190555061220e81600460008e6001600160a01b03166001600160a01b031681526020019081526020016000205461350a90919063ffffffff16565b6001600160a01b03909b1660009081526004602052604090209a909a5550506005805460ff60a01b1916600160a01b17905550505050505050505050565b600360209081526000928352604080842090915290825290205460ff1681565b600554600160a01b900460ff1681565b6008541561228a60126132e0565b906122a85760405162461bcd60e51b81526004016107769190614d37565b5060026008556007546001600160a01b0316156122c560116132e0565b906122e35760405162461bcd60e51b81526004016107769190614d37565b50600780546001600160a01b0393841673ffffffffffffffffffffffffffffffffffffffff199182161790915560098054929093169116179055565b600554600160a01b900460ff1661233660016132e0565b906123545760405162461bcd60e51b81526004016107769190614d37565b506005805460ff60a01b19169055604080516020601f84018190048102820181019092528281526123a29185919085908590819084018382808284376000920191909152506137c992505050565b8660006123ae82612dd0565b90506000826001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016123de9190614a2e565b60206040518083038186803b1580156123f657600080fd5b505afa15801561240a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061242e919061485d565b90508089600960ff851611156124695760098460ff1603600a0a818161245057fe5b04905060098460ff1603600a0a838161246557fe5b0492505b670de0b6b3a764000081111580156124895750670de0b6b3a76400008311155b80156124a65750670de0b6b3a76400006124a3828561350a565b11155b6124b060036132e0565b906124ce5760405162461bcd60e51b81526004016107769190614d37565b50846001600160a01b03166323b872dd33308e6040518463ffffffff1660e01b81526004016124ff93929190614a42565b600060405180830381600087803b15801561251957600080fd5b505af115801561252d573d6000803e3d6000fd5b505050506125396134d6565b61254360046132e0565b906125615760405162461bcd60e51b81526004016107769190614d37565b508a612576836125708f6116e7565b90613aaf565b14612581600a6132e0565b9061259f5760405162461bcd60e51b81526004016107769190614d37565b507f2d4b597935f3cd67fb2eebf1db4debc934cee5c7baa7153f980fdbeb2e74084e8c8b8b846040516125d59493929190614b36565b60405180910390a150506005805460ff60a01b1916600160a01b17905550505050505050505050565b600554600160a01b900460ff1661261560016132e0565b906126335760405162461bcd60e51b81526004016107769190614d37565b506005805460ff60a01b19169055604080516020601f84018190048102820181019092528281526126819185919085908590819084018382808284376000920191909152506137c992505050565b86600061268d82612dd0565b90506000826001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016126bd9190614a2e565b60206040518083038186803b1580156126d557600080fd5b505afa1580156126e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061270d919061485d565b90508089600960ff851611156127485760098460ff1603600a0a818161272f57fe5b04905060098460ff1603600a0a838161274457fe5b0492505b670de0b6b3a764000081111580156127685750670de0b6b3a76400008311155b80156127855750670de0b6b3a7640000612782828561350a565b11155b61278f60036132e0565b906127ad5760405162461bcd60e51b81526004016107769190614d37565b50846001600160a01b03166323b872dd33308e6040518463ffffffff1660e01b81526004016127de93929190614a42565b600060405180830381600087803b1580156127f857600080fd5b505af115801561280c573d6000803e3d6000fd5b505050506128186134d6565b61282260046132e0565b906128405760405162461bcd60e51b81526004016107769190614d37565b508a61284f836125708f6116e7565b1461285a600a6132e0565b906128785760405162461bcd60e51b81526004016107769190614d37565b507fd30df8040a1092415b49422a02dbd8cdd5915a596abcba02cd0f65dd86ab38518c8b8b846128a86006613836565b6040516128b9959493929190614b6a565b60405180910390a16128cb600661383a565b50506005805460ff60a01b1916600160a01b17905550505050505050505050565b609e81565b600030331461290060146132e0565b9061291e5760405162461bcd60e51b81526004016107769190614d37565b50600061292a836116e7565b9050606060006001600160a01b0389166129455750856129dd565b60095460405163a9059cbb60e01b81526001600160a01b038b81169263a9059cbb9261297992909116908b90600401614a66565b600060405180830381600087803b15801561299357600080fd5b505af11580156129a7573d6000803e3d6000fd5b505050506129b36134d6565b6129bd60046132e0565b906129db5760405162461bcd60e51b81526004016107769190614d37565b505b600954604051631cff79cd60e01b81526001600160a01b0390911690631cff79cd908390612a11908c908b90600401614adf565b6000604051808303818588803b158015612a2a57600080fd5b505af1158015612a3e573d6000803e3d6000fd5b50505050506040513d6000823e601f3d908101601f19168201604052612a679190810190614516565b91508151604014612a7860096132e0565b90612a965760405162461bcd60e51b81526004016107769190614d37565b5060008083806020019051810190612aae9190613fe5565b91509150866001600160a01b0316826001600160a01b0316148015612ade575080612adc866125708a6116e7565b145b612ae860096132e0565b90612b065760405162461bcd60e51b81526004016107769190614d37565b509a9950505050505050505050565b600554600160a81b900460ff1615612b2d600f6132e0565b90612b4b5760405162461bcd60e51b81526004016107769190614d37565b506005805460ff60a01b197fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff6001600160a01b0380881673ffffffffffffffffffffffffffffffffffffffff199094169390931716600160a81b1716600160a01b179091556007541615612bbf60116132e0565b90612bdd5760405162461bcd60e51b81526004016107769190614d37565b50600780546001600160a01b0393841673ffffffffffffffffffffffffffffffffffffffff199182161790915560098054929093169116179055506002600855565b6009546001600160a01b031681565b600554600160a01b900460ff16612c4560016132e0565b90612c635760405162461bcd60e51b81526004016107769190614d37565b506005805460ff60a01b191690556b033b2e3c9fd0803ce8000000471115612c8b60026132e0565b90612ca95760405162461bcd60e51b81526004016107769190614d37565b50612cea8383838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506137c992505050565b7f2d4b597935f3cd67fb2eebf1db4debc934cee5c7baa7153f980fdbeb2e74084e6000868634604051612d209493929190614b36565b60405180910390a150506005805460ff60a01b1916600160a01b179055505050565b6007546001600160a01b03161580612d6457506007546001600160a01b031633145b8015612d7857506001600160a01b03811615155b612d8260116132e0565b90612da05760405162461bcd60e51b81526004016107769190614d37565b506007805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055565b6000612ddb826137c3565b612df75760405162461bcd60e51b815260040161077690614e4c565b6000829050806001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b158015612e3557600080fd5b505afa925050508015612e65575060408051601f3d908101601f19168201909252612e629181019061485d565b60015b612e815760405162461bcd60e51b815260040161077690614d4a565b91506117b69050565b60085481565b600181565b60006020819052908152604090205460ff1681565b6007546001600160a01b031681565b60008181526001602052604081205460ff1615612ed8575060016117b6565b6005546001600160a01b0316612ef0575060006117b6565b6005546040517fe4bd70740000000000000000000000000000000000000000000000000000000081526001600160a01b039091169063e4bd707490611bb3908590600401614cf1565b6005546000906001600160a01b031615801590612f7c57506001600160a01b0380831660009081526003602090815260408083209387168352929052205460ff16155b1561303857600554604051637badcc6760e11b8152613031916001600160a01b03169063f75b98ce90612fb59087908790600401614a7f565b60206040518083038186803b158015612fcd57600080fd5b505afa158015612fe1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613005919061485d565b6001600160a01b038085166000908152600260209081526040808320938916835292905220549061350a565b90506114c0565b506001600160a01b0380821660009081526002602090815260408083209386168352929052205492915050565b6005546001600160a01b031681565b600554600160a01b900460ff1661308b60016132e0565b906130a95760405162461bcd60e51b81526004016107769190614d37565b506005805460ff60a01b19169055604080516020601f84018190048102820181019092528281526130f79185919085908590819084018382808284376000920191909152506137c992505050565b600061316261310a60018c89898e613843565b8d8d60405160200161311e93929190614f7f565b60408051601f198184030181526020601f8c018190048102840181019092528a835291908b908b90819084018382808284376000920191909152506138c992505050565b905061316e818b61396d565b6001600160a01b038082166000908152600260209081526040808320938e16835292905220548911156131a160086132e0565b906131bf5760405162461bcd60e51b81526004016107769190614d37565b506001600160a01b038082166000908152600260209081526040808320938e16835292905220546131f0908a613aaf565b6001600160a01b038083166000908152600260209081526040808320938f16835292815282822093909355600490925290205461322d908a613aaf565b6001600160a01b038b1660008181526004602052604090209190915589901561328157600061325b8c612dd0565b905060098160ff16111561327f5760098160ff1603600a0a8b8161327b57fe5b0491505b505b7f2d4b597935f3cd67fb2eebf1db4debc934cee5c7baa7153f980fdbeb2e74084e8b8e8e846040516132b69493929190614b36565b60405180910390a150506005805460ff60a01b1916600160a01b1790555050505050505050505050565b606060008260148111156132f057fe5b60408051600a808252818301909252919250906060908260208201818036833701905050905060005b60ff84161561337f578151600a60ff959095168581049560018401939106916030830160f81b918591811061334a57fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535050613319565b60608160010167ffffffffffffffff8111801561339b57600080fd5b506040519080825280601f01601f1916602001820160405280156133c6576020820181803683370190505b50905060005b82811161342f5783818403815181106133e157fe5b602001015160f81c60f81b8282815181106133f857fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053506001016133cc565b509695505050505050565b8047101561345a5760405162461bcd60e51b815260040161077690614dde565b6000826001600160a01b03168260405161347390614a2b565b60006040518083038185875af1925050503d80600081146134b0576040519150601f19603f3d011682016040523d82523d6000602084013e6134b5565b606091505b505090508061082f5760405162461bcd60e51b815260040161077690614d81565b6000803d80156134ed57602081146134f657613502565b60019150613502565b60206000803e60005191505b501515905090565b600082820183811080159061351f5750828110155b6040518060400160405280601281526020017129b0b332a6b0ba341032bc31b2b83a34b7b760711b815250906135685760405162461bcd60e51b81526004016107769190614d37565b509392505050565b600082820283158061351f57508284828161358757fe5b04146040518060400160405280601281526020017129b0b332a6b0ba341032bc31b2b83a34b7b760711b815250906135685760405162461bcd60e51b81526004016107769190614d37565b60008a8a6040516020016135e7929190614a09565b604051602081830303815290604052805190602001209050613607613c64565b6001600160a01b031663f65d21166001838d8d8d8d8d8d8d8d8d6040518c63ffffffff1660e01b81526004016136479b9a99989796959493929190614c44565b60206040518083038186803b15801561365f57600080fd5b505afa158015613673573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136979190614328565b6136a160066132e0565b906136bf5760405162461bcd60e51b81526004016107769190614d37565b505050505050505050505050565b816001600160a01b03851661371a576b033b2e3c9fd0803ce80000004711156136f660026132e0565b906137145760405162461bcd60e51b81526004016107769190614d37565b50613780565b600061372586612dd0565b905060098160ff1611156137495760098160ff1603600a0a828161374557fe5b0491505b670de0b6b3a764000082111561375f60036132e0565b9061377d5760405162461bcd60e51b81526004016107769190614d37565b50505b7eb45d95b5117447e2fafe7f34def913ff3ba220e4b8688acf37ae2328af7a3d858583856040516137b49493929190614b01565b60405180910390a15050505050565b3b151590565b6000613818826040518060400160405280336001600160a01b03168152602001868152506040516020016137fd9190614fa5565b60405160208183030381529060405280519060200120611437565b6007549091506001600160a01b0380831691161461080f60106132e0565b5490565b80546001019055565b61384b613cf1565b613853613cf1565b604051806080016040528088600781111561386a57fe5b8152602001876001600160a01b0316815260200186868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509082525060200184905291505095945050505050565b815160208301206000906138dc81612eb9565b156138e760056132e0565b906139055760405162461bcd60e51b81526004016107769190614d37565b5060006139128483611437565b90506001600160a01b038116151561392a60106132e0565b906139485760405162461bcd60e51b81526004016107769190614d37565b506000918252600160208190526040909220805460ff19169092179091559392505050565b6005546001600160a01b0316158015906139ad57506001600160a01b0380831660009081526003602090815260408083209385168352929052205460ff16155b15613aab57600554604051637badcc6760e11b8152613a62916001600160a01b03169063f75b98ce906139e69085908790600401614a7f565b60206040518083038186803b1580156139fe57600080fd5b505afa158015613a12573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a36919061485d565b6001600160a01b038085166000908152600260209081526040808320938716835292905220549061350a565b6001600160a01b038084166000818152600260209081526040808320948716808452948252808320959095559181526003825283812092815291905220805460ff191660011790555b5050565b6000828211156040518060400160405280601281526020017129b0b332a6b0ba341032bc31b2b83a34b7b760711b81525090613afe5760405162461bcd60e51b81526004016107769190614d37565b5050900390565b600080613b11866116e7565b90506001600160a01b038616613b2e57613b2b8134613aaf565b90505b84471015613b3c60076132e0565b90613b5a5760405162461bcd60e51b81526004016107769190614d37565b50600954604051631cff79cd60e01b81526060916001600160a01b031690631cff79cd908890613b909088908a90600401614adf565b6000604051808303818588803b158015613ba957600080fd5b505af1158015613bbd573d6000803e3d6000fd5b50505050506040513d6000823e601f3d908101601f19168201604052613be69190810190614516565b905060008082806020019051810190613bff9190613fe5565b91509150886001600160a01b0316826001600160a01b0316148015613c2f575080613c2d856125708c6116e7565b145b613c3960096132e0565b90613c575760405162461bcd60e51b81526004016107769190614d37565b5098975050505050505050565b7f62135fc083646fdb4e1a9d700e351b886a4a5a39da980650269edd1ade91ffd25490565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a081019190915290565b604051806060016040528060006001600160a01b031681526020016060815260200160006001600160a01b031681525090565b6040805160808101909152806000815260200160006001600160a01b0316815260200160608152602001600081525090565b80356114c081615092565b60008083601f840112613d3f578182fd5b50813567ffffffffffffffff811115613d56578182fd5b6020830191508360208083028501011115613d7057600080fd5b9250929050565b600082601f830112613d87578081fd5b8135613d9a613d9582614ffa565b614fd3565b818152915060208083019084810181840286018201871015613dbb57600080fd5b60005b84811015613de3578135613dd1816150aa565b84529282019290820190600101613dbe565b505050505092915050565b600082601f830112613dfe578081fd5b8135613e0c613d9582614ffa565b818152915060208083019084810181840286018201871015613e2d57600080fd5b60005b84811015613de357813584529282019290820190600101613e30565b600082601f830112613e5c578081fd5b8135613e6a613d9582614ffa565b818152915060208083019084810181840286018201871015613e8b57600080fd5b6000805b85811015613eb957823560ff81168114613ea7578283fd5b85529383019391830191600101613e8f565b50505050505092915050565b60008083601f840112613ed6578182fd5b50813567ffffffffffffffff811115613eed578182fd5b602083019150836020828501011115613d7057600080fd5b600082601f830112613f15578081fd5b8135613f23613d958261501a565b9150808252836020828501011115613f3a57600080fd5b8060208401602084013760009082016020015292915050565b600060208284031215613f64578081fd5b8135613f6f81615092565b9392505050565b60008060008060008060c08789031215613f8e578182fd5b8635613f9981615092565b95506020870135613fa981615092565b945060408701359350606087013592506080870135613fc781615092565b915060a0870135613fd781615092565b809150509295509295509295565b60008060408385031215613ff7578182fd5b825161400281615092565b6020939093015192949293505050565b60008060408385031215614024578182fd5b823561402f81615092565b9150602083013561403f81615092565b809150509250929050565b60008060006060848603121561405e578081fd5b833561406981615092565b9250602084013561407981615092565b929592945050506040919091013590565b60008060006060848603121561409e578081fd5b83356140a981615092565b925060208401356140b981615092565b915060408401356140c981615092565b809150509250925092565b600080600080600060a086880312156140eb578283fd5b85356140f681615092565b9450602086013561410681615092565b935060408601359250606086013567ffffffffffffffff811115614128578182fd5b61413488828901613f05565b925050608086013561414581615092565b809150509295509295909350565b60008060008060008060008060008060e08b8d031215614171578788fd5b8a3561417c81615092565b995060208b0135985060408b013561419381615092565b97506141a28c60608d01613d23565b965060808b013567ffffffffffffffff808211156141be578586fd5b6141ca8e838f01613ec5565b909850965060a08d01359150808211156141e2578586fd5b6141ee8e838f01613ec5565b909650945060c08d0135915080821115614206578384fd5b506142138d828e01613ec5565b915080935050809150509295989b9194979a5092959850565b600080600080600080600060a0888a031215614246578081fd5b873561425181615092565b965060208801359550604088013567ffffffffffffffff80821115614274578283fd5b6142808b838c01613ec5565b909750955060608a0135945060808a013591508082111561429f578283fd5b506142ac8a828b01613ec5565b989b979a50959850939692959293505050565b600080600080604085870312156142d4578182fd5b843567ffffffffffffffff808211156142eb578384fd5b6142f788838901613d2e565b9096509450602087013591508082111561430f578384fd5b5061431c87828801613d2e565b95989497509550505050565b600060208284031215614339578081fd5b8151613f6f816150aa565b600060208284031215614355578081fd5b5035919050565b6000806020838503121561436e578182fd5b823567ffffffffffffffff811115614384578283fd5b61439085828601613ec5565b90969095509350505050565b60008060008060008060008060008060006101408c8e0312156143bd578485fd5b67ffffffffffffffff808d3511156143d3578586fd5b6143e08e8e358f01613ec5565b909c509a5060208d0135995060408d01358110156143fc578586fd5b61440c8e60408f01358f01613dee565b98508060608e0135111561441e578586fd5b61442e8e60608f01358f01613d77565b975060808d0135965060a08d013595508060c08e0135111561444e578182fd5b61445e8e60c08f01358f01613dee565b94508060e08e01351115614470578182fd5b6144808e60e08f01358f01613e4c565b9350806101008e01351115614493578182fd5b6144a48e6101008f01358f01613dee565b9250806101208e013511156144b7578182fd5b506144c98d6101208e01358e01613dee565b90509295989b509295989b9093969950565b6000602082840312156144ec578081fd5b813567ffffffffffffffff811115614502578182fd5b61450e84828501613f05565b949350505050565b600060208284031215614527578081fd5b815167ffffffffffffffff81111561453d578182fd5b8201601f8101841361454d578182fd5b805161455b613d958261501a565b81815285602083850101111561456f578384fd5b614580826020830160208601615066565b95945050505050565b6000806040838503121561459b578182fd5b823567ffffffffffffffff8111156145b1578283fd5b6145bd85828601613f05565b95602094909401359450505050565b6000806000806000806000806000806101408b8d0312156145eb578384fd5b8a3567ffffffffffffffff80821115614602578586fd5b61460e8e838f01613f05565b9b5060208d01359a5060408d013591508082111561462a578586fd5b6146368e838f01613dee565b995060608d013591508082111561464b578586fd5b6146578e838f01613d77565b985060808d0135975060a08d0135965060c08d013591508082111561467a578586fd5b6146868e838f01613dee565b955060e08d013591508082111561469b578485fd5b6146a78e838f01613e4c565b94506101008d01359150808211156146bd578384fd5b6146c98e838f01613dee565b93506101208d01359150808211156146df578283fd5b506146ec8d828e01613dee565b9150509295989b9194979a5092959850565b600080600080600080600080600080600060e08c8e03121561471e578485fd5b67ffffffffffffffff808d351115614734578586fd5b6147418e8e358f01613ec5565b909c509a506147538e60208f01613d23565b995060408d013598508060608e0135111561476c578586fd5b61477c8e60608f01358f01613ec5565b909850965060808d0135811015614791578586fd5b6147a18e60808f01358f01613ec5565b909650945060a08d0135935060c08d01358110156147bd578182fd5b506147ce8d60c08e01358e01613ec5565b81935080925050509295989b509295989b9093969950565b6000806000806000606086880312156147fd578283fd5b853567ffffffffffffffff80821115614814578485fd5b61482089838a01613ec5565b909750955060208801359450604088013591508082111561483f578283fd5b5061484c88828901613ec5565b969995985093965092949392505050565b60006020828403121561486e578081fd5b5051919050565b6000815180845260208085019450808401835b838110156148a6578151151587529582019590820190600101614888565b509495945050505050565b6000815180845260208085019450808401835b838110156148a6578151875295820195908201906001016148c4565b6000815180845260208085019450808401835b838110156148a657815160ff16875295820195908201906001016148f3565b60008284528282602086013780602084860101526020601f19601f85011685010190509392505050565b60008151808452614954816020860160208601615066565b601f01601f19169290920160200192915050565b60ff815116825260ff602082015116602083015260408101516001600160a01b03808216604085015280606084015116606085015250506080810151608083015260a081015160a08301525050565b60008151600881106149c557fe5b808452506001600160a01b0360208301511660208401526040820151608060408501526149f5608085018261493c565b606093840151949093019390935250919050565b60008351614a1b818460208801615066565b9190910191825250602001919050565b90565b6001600160a01b0391909116815260200190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b0392831681529116602082015260400190565b60006001600160a01b038088168352808716602084015285604084015260a06060840152614aca60a084018661493c565b91508084166080840152509695505050505050565b60006001600160a01b03841682526040602083015261450e604083018461493c565b60006001600160a01b038616825260806020830152614b23608083018661493c565b6040830194909452506060015292915050565b60006001600160a01b038616825260606020830152614b59606083018587614912565b905082604083015295945050505050565b60006001600160a01b038716825260806020830152614b8d608083018688614912565b604083019490945250606001529392505050565b6040808252810184905260008560608301825b87811015614be45760208335614bc981615092565b6001600160a01b031683529283019290910190600101614bb4565b5083810360208501528481527f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff851115614c1c578283fd5b602085029150818660208301370160200190815295945050505050565b901515815260200190565b60006101608d151583528c60208401528b6040840152806060840152614c6c8184018c6148b1565b90508281036080840152614c80818b614875565b90508860a08401528760c084015282810360e0840152614ca081886148b1565b9050828103610100840152614cb581876148e0565b9050828103610120840152614cca81866148b1565b9050828103610140840152614cdf81856148b1565b9e9d5050505050505050505050505050565b90815260200190565b600084825283602083015260606040830152614580606083018461493c565b93845260ff9290921660208401526040830152606082015260800190565b600060208252613f6f602083018461493c565b60208082526018908201527f67657420455243323020646563696d616c206661696c65640000000000000000604082015260600190565b6020808252603a908201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260408201527f6563697069656e74206d61792068617665207265766572746564000000000000606082015260800190565b6020808252601d908201527f416464726573733a20696e73756666696369656e742062616c616e6365000000604082015260600190565b60208082526016908201527f62616c616e63654f66206e6f6e2d636f6e747261637400000000000000000000604082015260600190565b60208082526018908201527f676574446563696d616c73206e6f6e2d636f6e74726163740000000000000000604082015260600190565b60208082526018908201527f6765742045524332302062616c616e6365206661696c65640000000000000000604082015260600190565b60c081016114c08284614968565b6000610100614ed78387614968565b8060c08401526001600160a01b038086511682850152602086015191506060610120850152614f0a61016085018361493c565b9150806040870151166101408501525082810360e0840152614f2c818561493c565b9695505050505050565b600060808252614f4960808301886149b7565b6001600160a01b038781166020850152861660408401528281036060840152614f73818587614912565b98975050505050505050565b600060408252614f9260408301866149b7565b8281036020840152614f2c818587614912565b81516001600160a01b031681526020918201519181019190915260400190565b60ff91909116815260200190565b60405181810167ffffffffffffffff81118282101715614ff257600080fd5b604052919050565b600067ffffffffffffffff821115615010578081fd5b5060209081020190565b600067ffffffffffffffff821115615030578081fd5b50601f01601f191660200190565b6000808585111561504d578182fd5b83861115615059578182fd5b5050820193919092039150565b60005b83811015615081578181015183820152602001615069565b8381111561082d5750506000910152565b6001600160a01b03811681146150a757600080fd5b50565b80151581146150a757600080fdfea264697066735822122099ad7207700f19c214687c5501da9eb61c9c1fba2a2d9dd954462f4e3c6de73364736f6c634300060c0033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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