ETH Price: $2,638.29 (-0.09%)

Contract

0x6230F5C4193E632b084A083Dba713E73651Bb93A
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
0x60806040142182522022-02-16 16:38:07956 days ago1645029487IN
 Create: ATokenRootChainManager
0 ETH0.3870448100

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
ATokenRootChainManager

Compiler Version
v0.6.6+commit.6c089d02

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 15 : ATokenRootChainManager.sol
pragma solidity 0.6.6;

/**
 * aToken bridge to Matic Network
 * Author: Nick Mudge <[email protected]>
 * Modified from Matics ERC20 bridge: https://github.com/maticnetwork/pos-portal
 */

import {SafeMath} from "@openzeppelin/contracts/math/SafeMath.sol";
import {ICheckpointManager} from "../ICheckpointManager.sol";
import {RLPReader} from "../../lib/RLPReader.sol";
import {ExitPayloadReader} from "../../lib/ExitPayloadReader.sol";
import {MerklePatriciaProof} from "../../lib/MerklePatriciaProof.sol";
import {Merkle} from "../../lib/Merkle.sol";
import {NativeMetaTransaction} from "../../common/NativeMetaTransaction.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {ContextMixin} from "../../common/ContextMixin.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import {IStateSender} from "../StateSender/IStateSender.sol";
import {ICheckpointManager} from "../ICheckpointManager.sol";

interface ILendingPool {
    function getReserveNormalizedIncome(address _asset) external view returns (uint256);
}

interface IAToken {
    function POOL() external view returns (ILendingPool);

    function UNDERLYING_ASSET_ADDRESS() external view returns (address);
}

interface IERC20Meta {
    function name() external view returns (string memory);

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

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

struct AppStorage {
    mapping(address => address) rootToChildToken;
    mapping(address => address) childToRootToken;
    mapping(bytes32 => bool) processedExits;
    bool inited;
    IStateSender stateSender;
    ICheckpointManager checkpointManager;
    address childChainManagerAddress;
    bytes32 childTokenBytecodeHash;
    address owner;
    address mapper;
}

contract ATokenRootChainManager is ICheckpointManager, NativeMetaTransaction, ContextMixin {
    using RLPReader for bytes;
    using RLPReader for RLPReader.RLPItem;
    using ExitPayloadReader for bytes;
    using ExitPayloadReader for ExitPayloadReader.ExitPayload;
    using ExitPayloadReader for ExitPayloadReader.Log;
    using ExitPayloadReader for ExitPayloadReader.Receipt;
    using Merkle for bytes32;
    using SafeMath for uint256;
    using SafeERC20 for IERC20;

    AppStorage s;

    // maybe DEPOSIT and MAP_TOKEN can be reduced to bytes4
    bytes32 public constant DEPOSIT = keccak256("DEPOSIT");
    bytes32 public constant MAP_TOKEN = keccak256("MAP_TOKEN");
    bytes32 public constant MAPPER_ROLE = keccak256("MAPPER_ROLE");
    uint256 internal constant P27 = 1e27;
    uint256 internal constant HALF_P27 = P27 / 2;
    bytes32 public constant TRANSFER_EVENT_SIG = 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef;

    event TokenMapped(address indexed rootToken, address indexed childToken, bytes32 indexed tokenType);

    event LockedERC20(address indexed depositor, address indexed depositReceiver, address indexed rootToken, uint256 amount);

    /**
     * @notice Deposit ether by directly sending to the contract
     * The account sending ether receives WETH on child chain
     */
    receive() external payable {
        revert("Cannot send ETH over aToken bridge");
    }

    function initialize(
        address _owner,
        address _stateSender,
        address _checkpointManager,
        address _childChainManagerAddress,
        bytes32 _childTokenBytecodeHash
    ) external {
        require(!s.inited, "already inited");
        s.inited = true;
        _initializeEIP712("ATokenRootChainManager");
        s.owner = _owner;
        s.mapper = _owner;
        s.stateSender = IStateSender(_stateSender);
        s.checkpointManager = ICheckpointManager(_checkpointManager);
        s.childChainManagerAddress = _childChainManagerAddress;
        s.childTokenBytecodeHash = _childTokenBytecodeHash;
    }

    function rootToChildToken(address _rootToken) external view returns (address) {
        return s.rootToChildToken[_rootToken];
    }

    function childToRootToken(address _childToken) external view returns (address) {
        return s.childToRootToken[_childToken];
    }

    function mapper() external view returns (address) {
        return s.mapper;
    }

    function stateSender() external view returns (address) {
        return address(s.stateSender);
    }

    // Old function here so as to not break existing functionality
    function stateSenderAddress() external view returns (address) {
        return address(s.stateSender);
    }

    function owner() external view returns (address) {
        return s.owner;
    }

    modifier onlyOwner() {
        require(msgSender() == s.owner, "Is not owner");
        _;
    }

    modifier onlyMapper() {
        address sender = msgSender();
        require(sender == s.mapper || sender == s.owner, "Is not mapper");
        _;
    }

    modifier onlyStateSender() {
        require(msgSender() == address(s.stateSender), "Is not state sender");
        _;
    }

    function processedExits(bytes32 _exitHash) external view returns (bool) {
        return s.processedExits[_exitHash];
    }

    /**
     * @notice Set the state sender, callable only by admins
     * @dev This should be the state sender from plasma contracts
     * It is used to send bytes from root to child chain
     * @param newStateSender address of state sender contract
     */
    function setStateSender(address newStateSender) external onlyOwner {
        require(newStateSender != address(0), "RootChainManager: BAD_NEW_STATE_SENDER");
        s.stateSender = IStateSender(newStateSender);
    }

    /**
     * @notice Set the checkpoint manager, callable only by admins
     * @dev This should be the plasma contract responsible for keeping track of checkpoints
     * @param newCheckpointManager address of checkpoint manager contract
     */
    function setCheckpointManager(address newCheckpointManager) external onlyOwner {
        require(newCheckpointManager != address(0), "RootChainManager: BAD_NEW_CHECKPOINT_MANAGER");
        s.checkpointManager = ICheckpointManager(newCheckpointManager);
    }

    /**
     * @notice Get the address of contract set as checkpoint manager
     * @return The address of checkpoint manager contract
     */
    function checkpointManagerAddress() external view returns (address) {
        return address(s.checkpointManager);
    }

    event SetOwner(address indexed _previousOwner, address indexed _newOwner);

    function setOwner(address _newOwner) external onlyOwner {
        emit SetOwner(s.owner, _newOwner);
        s.owner = _newOwner;
    }

    event SetMapper(address indexed _previousMapper, address indexed _newMapper);

    function setMapper(address _newMapper) external onlyOwner {
        emit SetMapper(s.mapper, _newMapper);
        s.mapper = _newMapper;
    }

    /**
     * @notice Set the child chain manager, callable only by admins
     * @dev This should be the contract responsible to receive deposit bytes on child chain
     * @param newChildChainManager address of child chain manager contract
     * @param newChildTokenBytecodeHash hash of bytecode used to create child token
     */
    function setChildChainManagerAddressAndChildTokenBytecodeHash(address newChildChainManager, bytes32 newChildTokenBytecodeHash)
        external
        onlyOwner
    {
        require(newChildChainManager != address(0x0), "ATokenRootChainManager: INVALID_CHILD_CHAIN_ADDRESS");
        s.childChainManagerAddress = newChildChainManager;
        s.childTokenBytecodeHash = newChildTokenBytecodeHash;
    }

    /**
     * @notice Set the child chain manager, callable only by admins
     * @dev This should be the contract responsible to receive deposit bytes on child chain
     * @param newChildChainManager address of child chain manager contract
     */
    function setChildChainManagerAddress(address newChildChainManager) external onlyOwner {
        require(newChildChainManager != address(0x0), "ATokenRootChainManager: INVALID_CHILD_CHAIN_ADDRESS");
        s.childChainManagerAddress = newChildChainManager;
    }

    /**
     * @notice Set the child bytecode hash
     * @dev This is used by a create2 call to precalculate the child token address
     * @param newChildTokenBytecodeHash address of child chain manager contract
     */
    function setChildTokenBytecodeHash(bytes32 newChildTokenBytecodeHash) external onlyOwner {
        s.childTokenBytecodeHash = newChildTokenBytecodeHash;
    }

    function childTokenAddress(address rootToken) public view returns (address childToken_) {
        // precompute childToken address for mapping
        childToken_ = address(
            uint160(
                uint256(
                    keccak256(
                        abi.encodePacked(
                            bytes1(0xff),
                            s.childChainManagerAddress, // contract creating address
                            bytes32(bytes20(rootToken)), // salt
                            s.childTokenBytecodeHash // bytecode hash
                        )
                    )
                )
            )
        );
    }

    /**
     * @notice Map a token to enable its movement via the PoS Portal, callable only by mappers
     * @param rootToken address of token on root chain
     */
    function mapToken(address rootToken) external onlyMapper {
        // explicit check if token is already mapped to avoid accidental remaps
        require(s.rootToChildToken[rootToken] == address(0), "ATokenRootChainManager: ALREADY_MAPPED");
        address childToken = childTokenAddress(rootToken);
        _mapToken(rootToken, childToken);
    }

    /**
     * @notice Remap a token that has already been mapped, properly cleans up old mapping
     * Callable only by ADMIN
     * @param rootToken address of token on root chain
     */
    function remapToken(address rootToken) external onlyOwner {
        address childToken = childTokenAddress(rootToken);
        // cleanup old mapping
        address oldChildToken = s.rootToChildToken[rootToken];
        require(childToken != oldChildToken, "ATokenRootChainManager: Child token is the same");
        address oldRootToken = s.childToRootToken[childToken];
        if (s.rootToChildToken[oldRootToken] != address(0)) {
            s.rootToChildToken[oldRootToken] = address(0);
        }

        if (s.childToRootToken[oldChildToken] != address(0)) {
            s.childToRootToken[oldChildToken] = address(0);
        }
        _mapToken(rootToken, childToken);
    }

    function _mapToken(address rootToken, address childToken) private {
        s.rootToChildToken[rootToken] = childToken;
        s.childToRootToken[childToken] = rootToken;

        emit TokenMapped(rootToken, childToken, 0x0);

        bytes memory syncData =
            abi.encode(
                rootToken,
                abi.encodePacked("Matic ", IERC20Meta(rootToken).name()),
                abi.encodePacked("m", IERC20Meta(rootToken).symbol()),
                IERC20Meta(rootToken).decimals()
            );
        s.stateSender.syncState(s.childChainManagerAddress, abi.encode(MAP_TOKEN, syncData));
    }

    /**
     * @notice Move tokens from root to child chain
     * @dev This mechanism supports arbitrary tokens as long as its predicate has been registered and the token is mapped
     * @param user address of account that should receive this deposit on child chain
     * @param rootToken address of token that is being deposited
     * @param depositData bytes data that is sent to predicate and child token contracts to handle deposit
     */
    function depositFor(
        address user,
        address rootToken,
        bytes memory depositData
    ) public {
        require(s.rootToChildToken[rootToken] != address(0x0), "ATokenRootChainManager: TOKEN_NOT_MAPPED");
        require(user != address(0), "ATokenRootChainManager: INVALID_USER");

        uint256 aTokenValue = abi.decode(depositData, (uint256));
        address depositor = msgSender();
        emit LockedERC20(depositor, user, rootToken, aTokenValue);
        IERC20(rootToken).safeTransferFrom(depositor, address(this), aTokenValue);

        uint256 maTokenValue = getMATokenValue(rootToken, aTokenValue);
        // replace aTokenValue with maTokenValue in depositData
        // assembly increases start of bytes array and reduces the size by one uint256
        uint256 depositDataLength = depositData.length;
        assembly {
            depositData := add(depositData, 32)
            mstore(depositData, sub(depositDataLength, 32))
        }
        depositData = abi.encodePacked(maTokenValue, depositData);
        bytes memory syncData = abi.encode(user, rootToken, depositData);
        s.stateSender.syncState(s.childChainManagerAddress, abi.encode(DEPOSIT, syncData));
    }

    /**
     * @dev Divides two 27 decimal percision values, rounding half up to the nearest decimal
     * @param a 27 decimal percision value
     * @param b 27 decimal percision value
     * @return The result of a/b, in 27 decimal percision value
     **/
    function p27Div(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b != 0, "p27 division by 0");
        uint256 c = a * P27;
        require(a == c / P27, "p27 multiplication overflow");
        uint256 bDividedByTwo = b / 2;
        c += bDividedByTwo;
        require(c >= bDividedByTwo, "p27 multiplication addition overflow");
        return c / b;
    }

    /**
     * @dev Multiplies two 27 decimal percision values, rounding half up to the nearest decimal
     * @param a 27 decimal percision value
     * @param b 27 decimal percision value
     * @return The result of a*b, in 27 decimal percision value
     **/
    function p27Mul(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a * b;
        if (c == 0) {
            return 0;
        }
        require(b == c / a, "p27 multiplication overflow");
        c += HALF_P27;
        require(c >= HALF_P27, "p27 multiplication addition overflow");
        return c / P27;
    }

    /**
     * @dev Converts aToken value to maToken value
     * @param _aTokenAddress aToken contract address
     * @param _aTokenValue aToken value to convert
     * @return maTokenValue_ The converted maToken value
     **/
    function getMATokenValue(address _aTokenAddress, uint256 _aTokenValue) public view returns (uint256 maTokenValue_) {
        ILendingPool pool = IAToken(_aTokenAddress).POOL();
        uint256 liquidityIndex = pool.getReserveNormalizedIncome(IAToken(_aTokenAddress).UNDERLYING_ASSET_ADDRESS());
        maTokenValue_ = p27Div(_aTokenValue, liquidityIndex);
    }

    /**
     * @dev Converts maToken value to aToken value
     * @param _aTokenAddress aToken contract address
     * @param _maTokenValue maToken value to convert
     * @return aTokenValue_ The converted aToken value
     **/
    function getATokenValue(address _aTokenAddress, uint256 _maTokenValue) public view returns (uint256 aTokenValue_) {
        ILendingPool pool = IAToken(_aTokenAddress).POOL();
        uint256 liquidityIndex = pool.getReserveNormalizedIncome(IAToken(_aTokenAddress).UNDERLYING_ASSET_ADDRESS());
        aTokenValue_ = p27Mul(_maTokenValue, liquidityIndex);
    }

    /**
     * @notice exit tokens by providing proof
     * @dev This function verifies if the transaction actually happened on child chain
     * the transaction log is then sent to token predicate to handle it accordingly
     *
     * @param inputData RLP encoded data of the reference tx containing following list of fields
     *  0 - headerNumber - Checkpoint header block number containing the reference tx
     *  1 - blockProof - Proof that the block header (in the child chain) is a leaf in the submitted merkle root
     *  2 - blockNumber - Block number containing the reference tx on child chain
     *  3 - blockTime - Reference tx block time
     *  4 - txRoot - Transactions root of block
     *  5 - receiptRoot - Receipts root of block
     *  6 - receipt - Receipt of the reference transaction
     *  7 - receiptProof - Merkle proof of the reference receipt
     *  8 - branchMask - 32 bits denoting the path of receipt in merkle tree
     *  9 - receiptLogIndex - Log Index to read from the receipt
     */
    function exit(bytes calldata inputData) external {
        ExitPayloadReader.ExitPayload memory payload = inputData.toExitPayload();

        bytes memory branchMaskBytes = payload.getBranchMaskAsBytes();
        // checking if exit has already been processed
        // unique exit is identified using hash of (blockNumber, branchMask, receiptLogIndex)
        bytes32 exitHash =
            keccak256(
                abi.encodePacked(
                    payload.getBlockNumber(),
                    // first 2 nibbles are dropped while generating nibble array
                    // this allows branch masks that are valid but bypass exitHash check (changing first 2 nibbles only)
                    // so converting to nibble array and then hashing it
                    MerklePatriciaProof._getNibbleArray(branchMaskBytes),
                    payload.getReceiptLogIndex()
                )
            );
        require(s.processedExits[exitHash] == false, "ATokenRootChainManager: EXIT_ALREADY_PROCESSED");
        s.processedExits[exitHash] = true;

        ExitPayloadReader.Receipt memory receipt = payload.getReceipt();
        ExitPayloadReader.Log memory log = receipt.getLog();

        // log should be emmited only by the child token
        address rootToken = s.childToRootToken[log.getEmitter()];
        require(rootToken != address(0), "ATokenRootChainManager: TOKEN_NOT_MAPPED");

        // branch mask can be maximum 32 bits
        require(
            payload.getBranchMaskAsUint() & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000 == 0,
            "ATokenRootChainManager: INVALID_BRANCH_MASK"
        );

        // verify receipt inclusion
        require(
            MerklePatriciaProof.verify(
                receipt.toBytes(),
                branchMaskBytes,
                payload.getReceiptProof(),
                payload.getReceiptRoot()
            ),
            "ATokenRootChainManager: INVALID_PROOF"
        );

        // verify checkpoint inclusion
        _checkBlockMembershipInCheckpoint(
            payload.getBlockNumber(),
            payload.getBlockTime(),
            payload.getTxRoot(),
            payload.getReceiptRoot(),
            payload.getHeaderNumber(),
            payload.getBlockProof()
        );

        exitTokens(msgSender(), rootToken, log.toRlpBytes());
    }

    function exitTokens(
        address,
        address rootToken,
        bytes memory log
    ) private {
        RLPReader.RLPItem[] memory logRLPList = log.toRlpItem().toList();
        RLPReader.RLPItem[] memory logTopicRLPList = logRLPList[1].toList(); // topics

        require(
            bytes32(logTopicRLPList[0].toUint()) == TRANSFER_EVENT_SIG, // topic0 is event sig
            "ATokenRootChainManager: INVALID_SIGNATURE"
        );

        address withdrawer = address(logTopicRLPList[1].toUint()); // topic1 is from address

        require(
            address(logTopicRLPList[2].toUint()) == address(0), // topic2 is to address
            "ATokenRootChainManager: INVALID_RECEIVER"
        );

        uint256 maTokenValue = logRLPList[2].toUint(); // log data field
        uint256 aTokenValue = getATokenValue(rootToken, maTokenValue);

        IERC20(rootToken).safeTransfer(withdrawer, aTokenValue);
    }

    function _checkBlockMembershipInCheckpoint(
        uint256 blockNumber,
        uint256 blockTime,
        bytes32 txRoot,
        bytes32 receiptRoot,
        uint256 headerNumber,
        bytes memory blockProof
    ) private view returns (uint256) {
        (bytes32 headerRoot, uint256 startBlock, , uint256 createdAt, ) = s.checkpointManager.headerBlocks(headerNumber);

        require(
            keccak256(abi.encodePacked(blockNumber, blockTime, txRoot, receiptRoot)).checkMembership(
                blockNumber.sub(startBlock),
                headerRoot,
                blockProof
            ),
            "ATokenRootChainManager: INVALID_HEADER"
        );
        return createdAt;
    }
}

File 2 of 15 : SafeMath.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        uint256 c = a + b;
        if (c < a) return (false, 0);
        return (true, c);
    }

    /**
     * @dev Returns the substraction of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (b > a) return (false, 0);
        return (true, a - b);
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) return (true, 0);
        uint256 c = a * b;
        if (c / a != b) return (false, 0);
        return (true, c);
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (b == 0) return (false, 0);
        return (true, a / b);
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (b == 0) return (false, 0);
        return (true, a % b);
    }

    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");
        return c;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b <= a, "SafeMath: subtraction overflow");
        return a - b;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        if (a == 0) return 0;
        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");
        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b > 0, "SafeMath: division by zero");
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b > 0, "SafeMath: modulo by zero");
        return a % b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {trySub}.
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        return a - b;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryDiv}.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting with custom message when dividing by zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryMod}.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        return a % b;
    }
}

File 3 of 15 : ICheckpointManager.sol
pragma solidity 0.6.6;

contract ICheckpointManager {
    struct HeaderBlock {
        bytes32 root;
        uint256 start;
        uint256 end;
        uint256 createdAt;
        address proposer;
    }

    /**
     * @notice mapping of checkpoint header numbers to block details
     * @dev These checkpoints are submited by plasma contracts
     */
    mapping(uint256 => HeaderBlock) public headerBlocks;
}

File 4 of 15 : RLPReader.sol
/*
 * @author Hamdi Allam [email protected]
 * Please reach out with any questions or concerns
 * https://github.com/hamdiallam/Solidity-RLP/blob/e681e25a376dbd5426b509380bc03446f05d0f97/contracts/RLPReader.sol
 */
pragma solidity 0.6.6;

library RLPReader {
    uint8 constant STRING_SHORT_START = 0x80;
    uint8 constant STRING_LONG_START  = 0xb8;
    uint8 constant LIST_SHORT_START   = 0xc0;
    uint8 constant LIST_LONG_START    = 0xf8;
    uint8 constant WORD_SIZE = 32;

    struct RLPItem {
        uint len;
        uint memPtr;
    }

    struct Iterator {
        RLPItem item;   // Item that's being iterated over.
        uint nextPtr;   // Position of the next item in the list.
    }

    /*
    * @dev Returns the next element in the iteration. Reverts if it has not next element.
    * @param self The iterator.
    * @return The next element in the iteration.
    */
    function next(Iterator memory self) internal pure returns (RLPItem memory) {
        require(hasNext(self));

        uint ptr = self.nextPtr;
        uint itemLength = _itemLength(ptr);
        self.nextPtr = ptr + itemLength;

        return RLPItem(itemLength, ptr);
    }

    /*
    * @dev Returns true if the iteration has more elements.
    * @param self The iterator.
    * @return true if the iteration has more elements.
    */
    function hasNext(Iterator memory self) internal pure returns (bool) {
        RLPItem memory item = self.item;
        return self.nextPtr < item.memPtr + item.len;
    }

    /*
    * @param item RLP encoded bytes
    */
    function toRlpItem(bytes memory item) internal pure returns (RLPItem memory) {
        uint memPtr;
        assembly {
            memPtr := add(item, 0x20)
        }

        return RLPItem(item.length, memPtr);
    }

    /*
    * @dev Create an iterator. Reverts if item is not a list.
    * @param self The RLP item.
    * @return An 'Iterator' over the item.
    */
    function iterator(RLPItem memory self) internal pure returns (Iterator memory) {
        require(isList(self));

        uint ptr = self.memPtr + _payloadOffset(self.memPtr);
        return Iterator(self, ptr);
    }

    /*
    * @param the RLP item.
    */
    function rlpLen(RLPItem memory item) internal pure returns (uint) {
        return item.len;
    }

    /*
     * @param the RLP item.
     * @return (memPtr, len) pair: location of the item's payload in memory.
     */
    function payloadLocation(RLPItem memory item) internal pure returns (uint, uint) {
        uint offset = _payloadOffset(item.memPtr);
        uint memPtr = item.memPtr + offset;
        uint len = item.len - offset; // data length
        return (memPtr, len);
    }

    /*
    * @param the RLP item.
    */
    function payloadLen(RLPItem memory item) internal pure returns (uint) {
        (, uint len) = payloadLocation(item);
        return len;
    }

    /*
    * @param the RLP item containing the encoded list.
    */
    function toList(RLPItem memory item) internal pure returns (RLPItem[] memory) {
        require(isList(item));

        uint items = numItems(item);
        RLPItem[] memory result = new RLPItem[](items);

        uint memPtr = item.memPtr + _payloadOffset(item.memPtr);
        uint dataLen;
        for (uint i = 0; i < items; i++) {
            dataLen = _itemLength(memPtr);
            result[i] = RLPItem(dataLen, memPtr); 
            memPtr = memPtr + dataLen;
        }

        return result;
    }

    // @return indicator whether encoded payload is a list. negate this function call for isData.
    function isList(RLPItem memory item) internal pure returns (bool) {
        if (item.len == 0) return false;

        uint8 byte0;
        uint memPtr = item.memPtr;
        assembly {
            byte0 := byte(0, mload(memPtr))
        }

        if (byte0 < LIST_SHORT_START)
            return false;
        return true;
    }

    /*
     * @dev A cheaper version of keccak256(toRlpBytes(item)) that avoids copying memory.
     * @return keccak256 hash of RLP encoded bytes.
     */
    function rlpBytesKeccak256(RLPItem memory item) internal pure returns (bytes32) {
        uint256 ptr = item.memPtr;
        uint256 len = item.len;
        bytes32 result;
        assembly {
            result := keccak256(ptr, len)
        }
        return result;
    }

    /*
     * @dev A cheaper version of keccak256(toBytes(item)) that avoids copying memory.
     * @return keccak256 hash of the item payload.
     */
    function payloadKeccak256(RLPItem memory item) internal pure returns (bytes32) {
        (uint memPtr, uint len) = payloadLocation(item);
        bytes32 result;
        assembly {
            result := keccak256(memPtr, len)
        }
        return result;
    }

    /** RLPItem conversions into data types **/

    // @returns raw rlp encoding in bytes
    function toRlpBytes(RLPItem memory item) internal pure returns (bytes memory) {
        bytes memory result = new bytes(item.len);
        if (result.length == 0) return result;
        
        uint ptr;
        assembly {
            ptr := add(0x20, result)
        }

        copy(item.memPtr, ptr, item.len);
        return result;
    }

    // any non-zero byte except "0x80" is considered true
    function toBoolean(RLPItem memory item) internal pure returns (bool) {
        require(item.len == 1);
        uint result;
        uint memPtr = item.memPtr;
        assembly {
            result := byte(0, mload(memPtr))
        }

        // SEE Github Issue #5.
        // Summary: Most commonly used RLP libraries (i.e Geth) will encode
        // "0" as "0x80" instead of as "0". We handle this edge case explicitly
        // here.
        if (result == 0 || result == STRING_SHORT_START) {
            return false;
        } else {
            return true;
        }
    }

    function toAddress(RLPItem memory item) internal pure returns (address) {
        // 1 byte for the length prefix
        require(item.len == 21);

        return address(toUint(item));
    }

    function toUint(RLPItem memory item) internal pure returns (uint) {
        require(item.len > 0 && item.len <= 33);

        (uint memPtr, uint len) = payloadLocation(item);

        uint result;
        assembly {
            result := mload(memPtr)

            // shfit to the correct location if neccesary
            if lt(len, 32) {
                result := div(result, exp(256, sub(32, len)))
            }
        }

        return result;
    }

    // enforces 32 byte length
    function toUintStrict(RLPItem memory item) internal pure returns (uint) {
        // one byte prefix
        require(item.len == 33);

        uint result;
        uint memPtr = item.memPtr + 1;
        assembly {
            result := mload(memPtr)
        }

        return result;
    }

    function toBytes(RLPItem memory item) internal pure returns (bytes memory) {
        require(item.len > 0);

        (uint memPtr, uint len) = payloadLocation(item);
        bytes memory result = new bytes(len);

        uint destPtr;
        assembly {
            destPtr := add(0x20, result)
        }

        copy(memPtr, destPtr, len);
        return result;
    }

    /*
    * Private Helpers
    */

    // @return number of payload items inside an encoded list.
    function numItems(RLPItem memory item) private pure returns (uint) {
        if (item.len == 0) return 0;

        uint count = 0;
        uint currPtr = item.memPtr + _payloadOffset(item.memPtr);
        uint endPtr = item.memPtr + item.len;
        while (currPtr < endPtr) {
           currPtr = currPtr + _itemLength(currPtr); // skip over an item
           count++;
        }

        return count;
    }

    // @return entire rlp item byte length
    function _itemLength(uint memPtr) private pure returns (uint) {
        uint itemLen;
        uint byte0;
        assembly {
            byte0 := byte(0, mload(memPtr))
        }

        if (byte0 < STRING_SHORT_START)
            itemLen = 1;
        
        else if (byte0 < STRING_LONG_START)
            itemLen = byte0 - STRING_SHORT_START + 1;

        else if (byte0 < LIST_SHORT_START) {
            assembly {
                let byteLen := sub(byte0, 0xb7) // # of bytes the actual length is
                memPtr := add(memPtr, 1) // skip over the first byte
                
                /* 32 byte word size */
                let dataLen := div(mload(memPtr), exp(256, sub(32, byteLen))) // right shifting to get the len
                itemLen := add(dataLen, add(byteLen, 1))
            }
        }

        else if (byte0 < LIST_LONG_START) {
            itemLen = byte0 - LIST_SHORT_START + 1;
        } 

        else {
            assembly {
                let byteLen := sub(byte0, 0xf7)
                memPtr := add(memPtr, 1)

                let dataLen := div(mload(memPtr), exp(256, sub(32, byteLen))) // right shifting to the correct length
                itemLen := add(dataLen, add(byteLen, 1))
            }
        }

        return itemLen;
    }

    // @return number of bytes until the data
    function _payloadOffset(uint memPtr) private pure returns (uint) {
        uint byte0;
        assembly {
            byte0 := byte(0, mload(memPtr))
        }

        if (byte0 < STRING_SHORT_START) 
            return 0;
        else if (byte0 < STRING_LONG_START || (byte0 >= LIST_SHORT_START && byte0 < LIST_LONG_START))
            return 1;
        else if (byte0 < LIST_SHORT_START)  // being explicit
            return byte0 - (STRING_LONG_START - 1) + 1;
        else
            return byte0 - (LIST_LONG_START - 1) + 1;
    }

    /*
    * @param src Pointer to source
    * @param dest Pointer to destination
    * @param len Amount of memory to copy from the source
    */
    function copy(uint src, uint dest, uint len) private pure {
        if (len == 0) return;

        // copy as many word sizes as possible
        for (; len >= WORD_SIZE; len -= WORD_SIZE) {
            assembly {
                mstore(dest, mload(src))
            }

            src += WORD_SIZE;
            dest += WORD_SIZE;
        }

        if (len > 0) {
            // left over bytes. Mask is used to remove unwanted bytes from the word
            uint mask = 256 ** (WORD_SIZE - len) - 1;
            assembly {
                let srcpart := and(mload(src), not(mask)) // zero out src
                let destpart := and(mload(dest), mask) // retrieve the bytes
                mstore(dest, or(destpart, srcpart))
            }
        }
    }
}

File 5 of 15 : ExitPayloadReader.sol
pragma solidity 0.6.6;

import { RLPReader } from "./RLPReader.sol";

library ExitPayloadReader {
  using RLPReader for bytes;
  using RLPReader for RLPReader.RLPItem;

  uint8 constant WORD_SIZE = 32;

  struct ExitPayload {
    RLPReader.RLPItem[] data;
  }

  struct Receipt {
    RLPReader.RLPItem[] data;
    bytes raw;
    uint256 logIndex;
  }

  struct Log {
    RLPReader.RLPItem data;
    RLPReader.RLPItem[] list;
  }

  struct LogTopics {
    RLPReader.RLPItem[] data;
  }

  // copy paste of private copy() from RLPReader to avoid changing of existing contracts
  function copy(uint src, uint dest, uint len) private pure {
        if (len == 0) return;

        // copy as many word sizes as possible
        for (; len >= WORD_SIZE; len -= WORD_SIZE) {
            assembly {
                mstore(dest, mload(src))
            }

            src += WORD_SIZE;
            dest += WORD_SIZE;
        }

        // left over bytes. Mask is used to remove unwanted bytes from the word
        uint mask = 256 ** (WORD_SIZE - len) - 1;
        assembly {
            let srcpart := and(mload(src), not(mask)) // zero out src
            let destpart := and(mload(dest), mask) // retrieve the bytes
            mstore(dest, or(destpart, srcpart))
        }
    }

  function toExitPayload(bytes memory data)
        internal
        pure
        returns (ExitPayload memory)
    {
        RLPReader.RLPItem[] memory payloadData = data
            .toRlpItem()
            .toList();

        return ExitPayload(payloadData);
    }

    function getHeaderNumber(ExitPayload memory payload) internal pure returns(uint256) {
      return payload.data[0].toUint();
    }

    function getBlockProof(ExitPayload memory payload) internal pure returns(bytes memory) {
      return payload.data[1].toBytes();
    }

    function getBlockNumber(ExitPayload memory payload) internal pure returns(uint256) {
      return payload.data[2].toUint();
    }

    function getBlockTime(ExitPayload memory payload) internal pure returns(uint256) {
      return payload.data[3].toUint();
    }

    function getTxRoot(ExitPayload memory payload) internal pure returns(bytes32) {
      return bytes32(payload.data[4].toUint());
    }

    function getReceiptRoot(ExitPayload memory payload) internal pure returns(bytes32) {
      return bytes32(payload.data[5].toUint());
    }

    function getReceipt(ExitPayload memory payload) internal pure returns(Receipt memory receipt) {
      receipt.raw = payload.data[6].toBytes();
      RLPReader.RLPItem memory receiptItem = receipt.raw.toRlpItem();

      if (receiptItem.isList()) {
          // legacy tx
          receipt.data = receiptItem.toList();
      } else {
          // pop first byte before parsting receipt
          bytes memory typedBytes = receipt.raw;
          bytes memory result = new bytes(typedBytes.length - 1);
          uint256 srcPtr;
          uint256 destPtr;
          assembly {
              srcPtr := add(33, typedBytes)
              destPtr := add(0x20, result)
          }

          copy(srcPtr, destPtr, result.length);
          receipt.data = result.toRlpItem().toList();
      }

      receipt.logIndex = getReceiptLogIndex(payload);
      return receipt;
    }

    function getReceiptProof(ExitPayload memory payload) internal pure returns(bytes memory) {
      return payload.data[7].toBytes();
    }

    function getBranchMaskAsBytes(ExitPayload memory payload) internal pure returns(bytes memory) {
      return payload.data[8].toBytes();
    }

    function getBranchMaskAsUint(ExitPayload memory payload) internal pure returns(uint256) {
      return payload.data[8].toUint();
    }

    function getReceiptLogIndex(ExitPayload memory payload) internal pure returns(uint256) {
      return payload.data[9].toUint();
    }
    
    // Receipt methods
    function toBytes(Receipt memory receipt) internal pure returns(bytes memory) {
        return receipt.raw;
    }

    function getLog(Receipt memory receipt) internal pure returns(Log memory) {
        RLPReader.RLPItem memory logData = receipt.data[3].toList()[receipt.logIndex];
        return Log(logData, logData.toList());
    }

    // Log methods
    function getEmitter(Log memory log) internal pure returns(address) {
      return RLPReader.toAddress(log.list[0]);
    }

    function getTopics(Log memory log) internal pure returns(LogTopics memory) {
        return LogTopics(log.list[1].toList());
    }

    function getData(Log memory log) internal pure returns(bytes memory) {
        return log.list[2].toBytes();
    }

    function toRlpBytes(Log memory log) internal pure returns(bytes memory) {
      return log.data.toRlpBytes();
    }

    // LogTopics methods
    function getField(LogTopics memory topics, uint256 index) internal pure returns(RLPReader.RLPItem memory) {
      return topics.data[index];
    }
}

File 6 of 15 : MerklePatriciaProof.sol
/*
 * @title MerklePatriciaVerifier
 * @author Sam Mayo ([email protected])
 *
 * @dev Library for verifing merkle patricia proofs.
 */
pragma solidity 0.6.6;

import {RLPReader} from "./RLPReader.sol";

library MerklePatriciaProof {
    /*
     * @dev Verifies a merkle patricia proof.
     * @param value The terminating value in the trie.
     * @param encodedPath The path in the trie leading to value.
     * @param rlpParentNodes The rlp encoded stack of nodes.
     * @param root The root hash of the trie.
     * @return The boolean validity of the proof.
     */
    function verify(
        bytes memory value,
        bytes memory encodedPath,
        bytes memory rlpParentNodes,
        bytes32 root
    ) internal pure returns (bool) {
        RLPReader.RLPItem memory item = RLPReader.toRlpItem(rlpParentNodes);
        RLPReader.RLPItem[] memory parentNodes = RLPReader.toList(item);

        bytes memory currentNode;
        RLPReader.RLPItem[] memory currentNodeList;

        bytes32 nodeKey = root;
        uint256 pathPtr = 0;

        bytes memory path = _getNibbleArray(encodedPath);
        if (path.length == 0) {
            return false;
        }

        for (uint256 i = 0; i < parentNodes.length; i++) {
            if (pathPtr > path.length) {
                return false;
            }

            currentNode = RLPReader.toRlpBytes(parentNodes[i]);
            if (nodeKey != keccak256(currentNode)) {
                return false;
            }
            currentNodeList = RLPReader.toList(parentNodes[i]);

            if (currentNodeList.length == 17) {
                if (pathPtr == path.length) {
                    if (
                        keccak256(RLPReader.toBytes(currentNodeList[16])) ==
                        keccak256(value)
                    ) {
                        return true;
                    } else {
                        return false;
                    }
                }

                uint8 nextPathNibble = uint8(path[pathPtr]);
                if (nextPathNibble > 16) {
                    return false;
                }
                nodeKey = bytes32(
                    RLPReader.toUintStrict(currentNodeList[nextPathNibble])
                );
                pathPtr += 1;
            } else if (currentNodeList.length == 2) {
                uint256 traversed = _nibblesToTraverse(
                    RLPReader.toBytes(currentNodeList[0]),
                    path,
                    pathPtr
                );
                if (pathPtr + traversed == path.length) {
                    //leaf node
                    if (
                        keccak256(RLPReader.toBytes(currentNodeList[1])) ==
                        keccak256(value)
                    ) {
                        return true;
                    } else {
                        return false;
                    }
                }

                //extension node
                if (traversed == 0) {
                    return false;
                }

                pathPtr += traversed;
                nodeKey = bytes32(RLPReader.toUintStrict(currentNodeList[1]));
            } else {
                return false;
            }
        }
    }

    function _nibblesToTraverse(
        bytes memory encodedPartialPath,
        bytes memory path,
        uint256 pathPtr
    ) private pure returns (uint256) {
        uint256 len = 0;
        // encodedPartialPath has elements that are each two hex characters (1 byte), but partialPath
        // and slicedPath have elements that are each one hex character (1 nibble)
        bytes memory partialPath = _getNibbleArray(encodedPartialPath);
        bytes memory slicedPath = new bytes(partialPath.length);

        // pathPtr counts nibbles in path
        // partialPath.length is a number of nibbles
        for (uint256 i = pathPtr; i < pathPtr + partialPath.length; i++) {
            bytes1 pathNibble = path[i];
            slicedPath[i - pathPtr] = pathNibble;
        }

        if (keccak256(partialPath) == keccak256(slicedPath)) {
            len = partialPath.length;
        } else {
            len = 0;
        }
        return len;
    }

    // bytes b must be hp encoded
    function _getNibbleArray(bytes memory b)
        internal
        pure
        returns (bytes memory)
    {
        bytes memory nibbles = "";
        if (b.length > 0) {
            uint8 offset;
            uint8 hpNibble = uint8(_getNthNibbleOfBytes(0, b));
            if (hpNibble == 1 || hpNibble == 3) {
                nibbles = new bytes(b.length * 2 - 1);
                bytes1 oddNibble = _getNthNibbleOfBytes(1, b);
                nibbles[0] = oddNibble;
                offset = 1;
            } else {
                nibbles = new bytes(b.length * 2 - 2);
                offset = 0;
            }

            for (uint256 i = offset; i < nibbles.length; i++) {
                nibbles[i] = _getNthNibbleOfBytes(i - offset + 2, b);
            }
        }
        return nibbles;
    }

    function _getNthNibbleOfBytes(uint256 n, bytes memory str)
        private
        pure
        returns (bytes1)
    {
        return
            bytes1(
                n % 2 == 0 ? uint8(str[n / 2]) / 0x10 : uint8(str[n / 2]) % 0x10
            );
    }
}

File 7 of 15 : Merkle.sol
pragma solidity 0.6.6;


library Merkle {
    function checkMembership(
        bytes32 leaf,
        uint256 index,
        bytes32 rootHash,
        bytes memory proof
    ) internal pure returns (bool) {
        require(proof.length % 32 == 0, "Invalid proof length");
        uint256 proofHeight = proof.length / 32;
        // Proof of size n means, height of the tree is n+1.
        // In a tree of height n+1, max #leafs possible is 2 ^ n
        require(index < 2 ** proofHeight, "Leaf index is too big");

        bytes32 proofElement;
        bytes32 computedHash = leaf;
        for (uint256 i = 32; i <= proof.length; i += 32) {
            assembly {
                proofElement := mload(add(proof, i))
            }

            if (index % 2 == 0) {
                computedHash = keccak256(
                    abi.encodePacked(computedHash, proofElement)
                );
            } else {
                computedHash = keccak256(
                    abi.encodePacked(proofElement, computedHash)
                );
            }

            index = index / 2;
        }
        return computedHash == rootHash;
    }
}

File 8 of 15 : NativeMetaTransaction.sol
pragma solidity 0.6.6;


import {SafeMath} from "@openzeppelin/contracts/math/SafeMath.sol";
import {EIP712Base} from "./EIP712Base.sol";

contract NativeMetaTransaction is EIP712Base {
    using SafeMath for uint256;
    bytes32 private constant META_TRANSACTION_TYPEHASH = keccak256(
        bytes(
            "MetaTransaction(uint256 nonce,address from,bytes functionSignature)"
        )
    );
    event MetaTransactionExecuted(
        address userAddress,
        address payable relayerAddress,
        bytes functionSignature
    );
    mapping(address => uint256) nonces;

    /*
     * Meta transaction structure.
     * No point of including value field here as if user is doing value transfer then he has the funds to pay for gas
     * He should call the desired function directly in that case.
     */
    struct MetaTransaction {
        uint256 nonce;
        address from;
        bytes functionSignature;
    }

    function executeMetaTransaction(
        address userAddress,
        bytes memory functionSignature,
        bytes32 sigR,
        bytes32 sigS,
        uint8 sigV
    ) public payable returns (bytes memory) {
        MetaTransaction memory metaTx = MetaTransaction({
            nonce: nonces[userAddress],
            from: userAddress,
            functionSignature: functionSignature
        });

        require(
            verify(userAddress, metaTx, sigR, sigS, sigV),
            "Signer and signature do not match"
        );

        // increase nonce for user (to avoid re-use)
        nonces[userAddress] = nonces[userAddress].add(1);

        emit MetaTransactionExecuted(
            userAddress,
            msg.sender,
            functionSignature
        );

        // Append userAddress and relayer address at the end to extract it from calling context
        (bool success, bytes memory returnData) = address(this).call(
            abi.encodePacked(functionSignature, userAddress)
        );
        require(success, "Function call not successful");

        return returnData;
    }

    function hashMetaTransaction(MetaTransaction memory metaTx)
        internal
        pure
        returns (bytes32)
    {
        return
            keccak256(
                abi.encode(
                    META_TRANSACTION_TYPEHASH,
                    metaTx.nonce,
                    metaTx.from,
                    keccak256(metaTx.functionSignature)
                )
            );
    }

    function getNonce(address user) public view returns (uint256 nonce) {
        nonce = nonces[user];
    }

    function verify(
        address signer,
        MetaTransaction memory metaTx,
        bytes32 sigR,
        bytes32 sigS,
        uint8 sigV
    ) internal view returns (bool) {
        require(signer != address(0), "NativeMetaTransaction: INVALID_SIGNER");
        return
            signer ==
            ecrecover(
                toTypedMessageHash(hashMetaTransaction(metaTx)),
                sigV,
                sigR,
                sigS
            );
    }
}

File 9 of 15 : IERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

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

    /**
     * @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, uint256 amount) external returns (bool);

    /**
     * @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.
     *
     * IMPORTANT: 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, uint256 amount) external returns (bool);

    /**
     * @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, uint256 amount) external returns (bool);

    /**
     * @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, uint256 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, uint256 value);
}

File 10 of 15 : ContextMixin.sol
pragma solidity 0.6.6;


abstract contract ContextMixin {
    function msgSender()
        internal
        view
        returns (address payable sender)
    {
        if (msg.sender == address(this)) {
            bytes memory array = msg.data;
            uint256 index = msg.data.length;
            assembly {
                // Load the 32 bytes word from memory with the address on the lower 20 bytes, and mask those.
                sender := and(
                    mload(add(array, index)),
                    0xffffffffffffffffffffffffffffffffffffffff
                )
            }
        } else {
            sender = msg.sender;
        }
        return sender;
    }
}

File 11 of 15 : SafeERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

import "./IERC20.sol";
import "../../math/SafeMath.sol";
import "../../utils/Address.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using SafeMath for uint256;
    using Address for address;

    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    /**
     * @dev Deprecated. This function has issues similar to the ones found in
     * {IERC20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    function safeApprove(IERC20 token, address spender, uint256 value) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        // solhint-disable-next-line max-line-length
        require((value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 newAllowance = token.allowance(address(this), spender).add(value);
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
        if (returndata.length > 0) { // Return data is optional
            // solhint-disable-next-line max-line-length
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}

File 12 of 15 : IStateSender.sol
pragma solidity 0.6.6;

interface IStateSender {
    function syncState(address receiver, bytes calldata data) external;
}

File 13 of 15 : EIP712Base.sol
pragma solidity 0.6.6;


import {Initializable} from "./Initializable.sol";

contract EIP712Base is Initializable {
    struct EIP712Domain {
        string name;
        string version;
        address verifyingContract;
        bytes32 salt;
    }

    string constant public ERC712_VERSION = "1";

    bytes32 internal constant EIP712_DOMAIN_TYPEHASH = keccak256(
        bytes(
            "EIP712Domain(string name,string version,address verifyingContract,bytes32 salt)"
        )
    );
    bytes32 internal domainSeperator;

    // supposed to be called once while initializing.
    // one of the contractsa that inherits this contract follows proxy pattern
    // so it is not possible to do this in a constructor
    function _initializeEIP712(
        string memory name
    )
        internal
        initializer
    {
        _setDomainSeperator(name);
    }

    function _setDomainSeperator(string memory name) internal {
        domainSeperator = keccak256(
            abi.encode(
                EIP712_DOMAIN_TYPEHASH,
                keccak256(bytes(name)),
                keccak256(bytes(ERC712_VERSION)),
                address(this),
                bytes32(getChainId())
            )
        );
    }

    function getDomainSeperator() public view returns (bytes32) {
        return domainSeperator;
    }

    function getChainId() public pure returns (uint256) {
        uint256 id;
        assembly {
            id := chainid()
        }
        return id;
    }

    /**
     * Accept message hash and returns hash message in EIP712 compatible form
     * So that it can be used to recover signer from signature signed using EIP712 formatted data
     * https://eips.ethereum.org/EIPS/eip-712
     * "\\x19" makes the encoding deterministic
     * "\\x01" is the version byte to make it compatible to EIP-191
     */
    function toTypedMessageHash(bytes32 messageHash)
        internal
        view
        returns (bytes32)
    {
        return
            keccak256(
                abi.encodePacked("\x19\x01", getDomainSeperator(), messageHash)
            );
    }
}

File 14 of 15 : Initializable.sol
pragma solidity 0.6.6;

contract Initializable {
    bool inited = false;

    modifier initializer() {
        require(!inited, "already inited");
        _;
        inited = true;
    }
}

File 15 of 15 : 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);
            }
        }
    }
}

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

Contract Security Audit

Contract ABI

[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"depositor","type":"address"},{"indexed":true,"internalType":"address","name":"depositReceiver","type":"address"},{"indexed":true,"internalType":"address","name":"rootToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"LockedERC20","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"userAddress","type":"address"},{"indexed":false,"internalType":"address payable","name":"relayerAddress","type":"address"},{"indexed":false,"internalType":"bytes","name":"functionSignature","type":"bytes"}],"name":"MetaTransactionExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_previousMapper","type":"address"},{"indexed":true,"internalType":"address","name":"_newMapper","type":"address"}],"name":"SetMapper","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"_newOwner","type":"address"}],"name":"SetOwner","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"rootToken","type":"address"},{"indexed":true,"internalType":"address","name":"childToken","type":"address"},{"indexed":true,"internalType":"bytes32","name":"tokenType","type":"bytes32"}],"name":"TokenMapped","type":"event"},{"inputs":[],"name":"DEPOSIT","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ERC712_VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAPPER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAP_TOKEN","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TRANSFER_EVENT_SIG","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"checkpointManagerAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_childToken","type":"address"}],"name":"childToRootToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"rootToken","type":"address"}],"name":"childTokenAddress","outputs":[{"internalType":"address","name":"childToken_","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"rootToken","type":"address"},{"internalType":"bytes","name":"depositData","type":"bytes"}],"name":"depositFor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"userAddress","type":"address"},{"internalType":"bytes","name":"functionSignature","type":"bytes"},{"internalType":"bytes32","name":"sigR","type":"bytes32"},{"internalType":"bytes32","name":"sigS","type":"bytes32"},{"internalType":"uint8","name":"sigV","type":"uint8"}],"name":"executeMetaTransaction","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"inputData","type":"bytes"}],"name":"exit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_aTokenAddress","type":"address"},{"internalType":"uint256","name":"_maTokenValue","type":"uint256"}],"name":"getATokenValue","outputs":[{"internalType":"uint256","name":"aTokenValue_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getChainId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getDomainSeperator","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_aTokenAddress","type":"address"},{"internalType":"uint256","name":"_aTokenValue","type":"uint256"}],"name":"getMATokenValue","outputs":[{"internalType":"uint256","name":"maTokenValue_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getNonce","outputs":[{"internalType":"uint256","name":"nonce","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"headerBlocks","outputs":[{"internalType":"bytes32","name":"root","type":"bytes32"},{"internalType":"uint256","name":"start","type":"uint256"},{"internalType":"uint256","name":"end","type":"uint256"},{"internalType":"uint256","name":"createdAt","type":"uint256"},{"internalType":"address","name":"proposer","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_stateSender","type":"address"},{"internalType":"address","name":"_checkpointManager","type":"address"},{"internalType":"address","name":"_childChainManagerAddress","type":"address"},{"internalType":"bytes32","name":"_childTokenBytecodeHash","type":"bytes32"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"rootToken","type":"address"}],"name":"mapToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"mapper","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_exitHash","type":"bytes32"}],"name":"processedExits","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"rootToken","type":"address"}],"name":"remapToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_rootToken","type":"address"}],"name":"rootToChildToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newCheckpointManager","type":"address"}],"name":"setCheckpointManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newChildChainManager","type":"address"}],"name":"setChildChainManagerAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newChildChainManager","type":"address"},{"internalType":"bytes32","name":"newChildTokenBytecodeHash","type":"bytes32"}],"name":"setChildChainManagerAddressAndChildTokenBytecodeHash","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"newChildTokenBytecodeHash","type":"bytes32"}],"name":"setChildTokenBytecodeHash","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newMapper","type":"address"}],"name":"setMapper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newOwner","type":"address"}],"name":"setOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newStateSender","type":"address"}],"name":"setStateSender","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stateSender","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stateSenderAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]

60806040526001805460ff1916905534801561001a57600080fd5b506144ff8061002a6000396000f3fe6080604052600436106101f15760003560e01c80636cb136b01161010d578063c38a960e116100a0578063dc993a231161006f578063dc993a2314610857578063e2c49de114610803578063e3dec8fb1461088a578063ea60c7c414610954578063f4a120f7146109875761022d565b8063c38a960e146107d0578063cb10f94c14610803578063d45d760e14610818578063d81c8e52146108425761022d565b80638da5cb5b116100dc5780638da5cb5b1461073a5780639b2492c81461074f578063b017a30f14610788578063bc08452b1461079d5761022d565b80636cb136b0146106865780636e86b770146106b9578063886a69ba146106ec57806389d60963146107015761022d565b80632d0335ab1161018557806341539d4a1161015457806341539d4a146105c0578063568b80b51461061e578063607f2d421461063357806362f4f6a2146106715761022d565b80632d0335ab146104e85780633138b6f11461051b5780633408e470146105305780633805550f146105455761022d565b806313af4035116101c157806313af4035146104085780631d97c02b1461043b57806320379ee51461046e578063297a3e57146104955761022d565b8062561b7c146102325780630c53c51c1461026d5780630f7e5970146103a45780631116f918146103b95761022d565b3661022d5760405162461bcd60e51b81526004018080602001828103825260228152602001806142016022913960400191505060405180910390fd5b600080fd5b34801561023e57600080fd5b5061026b6004803603604081101561025557600080fd5b506001600160a01b0381351690602001356109ba565b005b61032f600480360360a081101561028357600080fd5b6001600160a01b038235169190810190604081016020820135600160201b8111156102ad57600080fd5b8201836020820111156102bf57600080fd5b803590602001918460018302840111600160201b831117156102e057600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550508235935050506020810135906040013560ff16610a83565b6040805160208082528351818301528351919283929083019185019080838360005b83811015610369578181015183820152602001610351565b50505050905090810190601f1680156103965780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3480156103b057600080fd5b5061032f610d86565b3480156103c557600080fd5b506103ec600480360360208110156103dc57600080fd5b50356001600160a01b0316610da3565b604080516001600160a01b039092168252519081900360200190f35b34801561041457600080fd5b5061026b6004803603602081101561042b57600080fd5b50356001600160a01b0316610e08565b34801561044757600080fd5b5061026b6004803603602081101561045e57600080fd5b50356001600160a01b0316610ec2565b34801561047a57600080fd5b5061048361103d565b60408051918252519081900360200190f35b3480156104a157600080fd5b5061026b600480360360a08110156104b857600080fd5b506001600160a01b0381358116916020810135821691604082013581169160608101359091169060800135611043565b3480156104f457600080fd5b506104836004803603602081101561050b57600080fd5b50356001600160a01b0316611140565b34801561052757600080fd5b506103ec61115b565b34801561053c57600080fd5b5061048361116a565b34801561055157600080fd5b5061026b6004803603602081101561056857600080fd5b810190602081018135600160201b81111561058257600080fd5b82018360208201111561059457600080fd5b803590602001918460018302840111600160201b831117156105b557600080fd5b50909250905061116e565b3480156105cc57600080fd5b506105ea600480360360208110156105e357600080fd5b503561145b565b6040805195865260208601949094528484019290925260608401526001600160a01b03166080830152519081900360a00190f35b34801561062a57600080fd5b50610483611493565b34801561063f57600080fd5b5061065d6004803603602081101561065657600080fd5b50356114b6565b604080519115158252519081900360200190f35b34801561067d57600080fd5b506103ec6114ce565b34801561069257600080fd5b5061026b600480360360208110156106a957600080fd5b50356001600160a01b03166114dd565b3480156106c557600080fd5b506103ec600480360360208110156106dc57600080fd5b50356001600160a01b03166115a8565b3480156106f857600080fd5b506104836115c6565b34801561070d57600080fd5b506104836004803603604081101561072457600080fd5b506001600160a01b0381351690602001356115e7565b34801561074657600080fd5b506103ec611753565b34801561075b57600080fd5b506104836004803603604081101561077257600080fd5b506001600160a01b038135169060200135611762565b34801561079457600080fd5b506104836118c5565b3480156107a957600080fd5b5061026b600480360360208110156107c057600080fd5b50356001600160a01b03166118e9565b3480156107dc57600080fd5b5061026b600480360360208110156107f357600080fd5b50356001600160a01b03166119ae565b34801561080f57600080fd5b506103ec611a68565b34801561082457600080fd5b5061026b6004803603602081101561083b57600080fd5b5035611a7c565b34801561084e57600080fd5b50610483611adf565b34801561086357600080fd5b5061026b6004803603602081101561087a57600080fd5b50356001600160a01b0316611afe565b34801561089657600080fd5b5061026b600480360360608110156108ad57600080fd5b6001600160a01b038235811692602081013590911691810190606081016040820135600160201b8111156108e057600080fd5b8201836020820111156108f257600080fd5b803590602001918460018302840111600160201b8311171561091357600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550611bc3945050505050565b34801561096057600080fd5b506103ec6004803603602081101561097757600080fd5b50356001600160a01b0316611fd2565b34801561099357600080fd5b5061026b600480360360208110156109aa57600080fd5b50356001600160a01b0316611ff0565b600b546001600160a01b03166109ce6120da565b6001600160a01b031614610a18576040805162461bcd60e51b815260206004820152600c60248201526b24b9903737ba1037bbb732b960a11b604482015290519081900360640190fd5b6001600160a01b038216610a5d5760405162461bcd60e51b815260040180806020018281038252603381526020018061441c6033913960400191505060405180910390fd5b600980546001600160a01b0319166001600160a01b039390931692909217909155600a55565b6060610a8d6140ce565b50604080516060810182526001600160a01b03881660008181526003602090815290849020548352820152908101869052610acb8782878787612138565b610b065760405162461bcd60e51b81526004018080602001828103825260218152602001806143d56021913960400191505060405180910390fd5b6001600160a01b038716600090815260036020526040902054610b3090600163ffffffff61221516565b6001600160a01b03881660008181526003602090815260408083209490945583519283523383820181905260609484018581528b51958501959095528a517f5845892132946850460bff5a0083f71031bc5bf9aadcd40f1de79423eac9b10b958d9592948d94919260808501928601918190849084905b83811015610bbf578181015183820152602001610ba7565b50505050905090810190601f168015610bec5780820380516001836020036101000a031916815260200191505b5094505050505060405180910390a160006060306001600160a01b0316888a6040516020018083805190602001908083835b60208310610c3d5780518252601f199092019160209182019101610c1e565b6001836020036101000a038019825116818451168082178552505050505050905001826001600160a01b03166001600160a01b031660601b8152601401925050506040516020818303038152906040526040518082805190602001908083835b60208310610cbc5780518252601f199092019160209182019101610c9d565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114610d1e576040519150601f19603f3d011682016040523d82523d6000602084013e610d23565b606091505b509150915081610d7a576040805162461bcd60e51b815260206004820152601c60248201527f46756e6374696f6e2063616c6c206e6f74207375636365737366756c00000000604482015290519081900360640190fd5b98975050505050505050565b604051806040016040528060018152602001603160f81b81525081565b600954600a54604080516001600160f81b03196020808301919091526bffffffffffffffffffffffff19606095861b811660218401529590941b9094166035850152605580850192909252805180850390920182526075909301909252815191012090565b600b546001600160a01b0316610e1c6120da565b6001600160a01b031614610e66576040805162461bcd60e51b815260206004820152600c60248201526b24b9903737ba1037bbb732b960a11b604482015290519081900360640190fd5b600b546040516001600160a01b038084169216907fcbf985117192c8f614a58aaf97226bb80a754772f5f6edf06f87c675f2e6c66390600090a3600b80546001600160a01b0319166001600160a01b0392909216919091179055565b600b546001600160a01b0316610ed66120da565b6001600160a01b031614610f20576040805162461bcd60e51b815260206004820152600c60248201526b24b9903737ba1037bbb732b960a11b604482015290519081900360640190fd5b6000610f2b82610da3565b6001600160a01b03808416600090815260046020526040902054919250908116908216811415610f8c5760405162461bcd60e51b815260040180806020018281038252602f815260200180614167602f913960400191505060405180910390fd5b6001600160a01b03808316600090815260056020908152604080832054841680845260049092529091205490911615610fe6576001600160a01b038116600090815260046020526040902080546001600160a01b03191690555b6001600160a01b03828116600090815260056020526040902054161561102d576001600160a01b038216600090815260056020526040902080546001600160a01b03191690555b6110378484612278565b50505050565b60025490565b60075460ff161561108c576040805162461bcd60e51b815260206004820152600e60248201526d185b1c9958591e481a5b9a5d195960921b604482015290519081900360640190fd5b6007805460ff1916600117905560408051808201909152601681527520aa37b5b2b72937b7ba21b430b4b726b0b730b3b2b960511b60208201526110cf9061291e565b600b80546001600160a01b03199081166001600160a01b03978816908117909255600c8054821690921790915560078054610100600160a81b031916610100968816969096029590951790945560088054851693861693909317909255600980549093169316929092179055600a55565b6001600160a01b031660009081526003602052604090205490565b6008546001600160a01b031690565b4690565b6111766140f8565b6111b583838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061297f92505050565b905060606111c2826129af565b905060006111cf836129d2565b6111d8836129f5565b6111e185612b68565b6040516020018084815260200183805190602001908083835b602083106112195780518252601f1990920191602091820191016111fa565b51815160209384036101000a6000190180199092169116179052920193845250604080518085038152938201815283519382019390932060008181526006909252929020549194505060ff161591506112a590505760405162461bcd60e51b815260040180806020018281038252602e815260200180614355602e913960400191505060405180910390fd5b6000818152600660205260409020805460ff191660011790556112c661410b565b6112cf84612b7e565b90506112d961412c565b6112e282612c68565b905060006005816112f284612cd5565b6001600160a01b0390811682526020820192909252604001600020541690508061134d5760405162461bcd60e51b81526004018080602001828103825260288152602001806141d96028913960400191505060405180910390fd5b61135686612cf8565b63ffffffff1916156113995760405162461bcd60e51b815260040180806020018281038252602b81526020018061432a602b913960400191505060405180910390fd5b6113bd6113a584612d0e565b866113af89612d15565b6113b88a612d2b565b612d41565b6113f85760405162461bcd60e51b81526004018080602001828103825260258152602001806142e06025913960400191505060405180910390fd5b611436611404876129d2565b61140d88612f88565b61141689612f9e565b61141f8a612d2b565b6114288b612fb4565b6114318c612fca565b612fe0565b506114516114426120da565b8261144c85613113565b613122565b5050505050505050565b60006020819052908152604090208054600182015460028301546003840154600490940154929391929091906001600160a01b031685565b604080516a4d41505045525f524f4c4560a81b8152905190819003600b01902081565b60008181526006602052604090205460ff165b919050565b600c546001600160a01b031690565b600b546001600160a01b03166114f16120da565b6001600160a01b03161461153b576040805162461bcd60e51b815260206004820152600c60248201526b24b9903737ba1037bbb732b960a11b604482015290519081900360640190fd5b6001600160a01b0381166115805760405162461bcd60e51b81526004018080602001828103825260268152602001806143f66026913960400191505060405180910390fd5b600780546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b6001600160a01b039081166000908152600560205260409020541690565b604080516826a0a82faa27a5a2a760b91b8152905190819003600901902081565b600080836001600160a01b0316637535d2466040518163ffffffff1660e01b815260040160206040518083038186803b15801561162357600080fd5b505afa158015611637573d6000803e3d6000fd5b505050506040513d602081101561164d57600080fd5b5051604080516358b50cef60e11b815290519192506000916001600160a01b038085169263d15e0053929189169163b16a19de91600480820192602092909190829003018186803b1580156116a157600080fd5b505afa1580156116b5573d6000803e3d6000fd5b505050506040513d60208110156116cb57600080fd5b5051604080516001600160e01b031960e085901b1681526001600160a01b039092166004830152516024808301926020929190829003018186803b15801561171257600080fd5b505afa158015611726573d6000803e3d6000fd5b505050506040513d602081101561173c57600080fd5b5051905061174a8482613266565b95945050505050565b600b546001600160a01b031690565b600080836001600160a01b0316637535d2466040518163ffffffff1660e01b815260040160206040518083038186803b15801561179e57600080fd5b505afa1580156117b2573d6000803e3d6000fd5b505050506040513d60208110156117c857600080fd5b5051604080516358b50cef60e11b815290519192506000916001600160a01b038085169263d15e0053929189169163b16a19de91600480820192602092909190829003018186803b15801561181c57600080fd5b505afa158015611830573d6000803e3d6000fd5b505050506040513d602081101561184657600080fd5b5051604080516001600160e01b031960e085901b1681526001600160a01b039092166004830152516024808301926020929190829003018186803b15801561188d57600080fd5b505afa1580156118a1573d6000803e3d6000fd5b505050506040513d60208110156118b757600080fd5b5051905061174a848261336e565b7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef81565b600b546001600160a01b03166118fd6120da565b6001600160a01b031614611947576040805162461bcd60e51b815260206004820152600c60248201526b24b9903737ba1037bbb732b960a11b604482015290519081900360640190fd5b6001600160a01b03811661198c5760405162461bcd60e51b815260040180806020018281038252602c815260200180614383602c913960400191505060405180910390fd5b600880546001600160a01b0319166001600160a01b0392909216919091179055565b600b546001600160a01b03166119c26120da565b6001600160a01b031614611a0c576040805162461bcd60e51b815260206004820152600c60248201526b24b9903737ba1037bbb732b960a11b604482015290519081900360640190fd5b600c546040516001600160a01b038084169216907fc3ccb9ca599457fe5a9bb338f84c2f853b1898c3a6e7eba842d95b0f017a7fa190600090a3600c80546001600160a01b0319166001600160a01b0392909216919091179055565b60075461010090046001600160a01b031690565b600b546001600160a01b0316611a906120da565b6001600160a01b031614611ada576040805162461bcd60e51b815260206004820152600c60248201526b24b9903737ba1037bbb732b960a11b604482015290519081900360640190fd5b600a55565b604080516611115413d4d25560ca1b8152905190819003600701902081565b600b546001600160a01b0316611b126120da565b6001600160a01b031614611b5c576040805162461bcd60e51b815260206004820152600c60248201526b24b9903737ba1037bbb732b960a11b604482015290519081900360640190fd5b6001600160a01b038116611ba15760405162461bcd60e51b815260040180806020018281038252603381526020018061441c6033913960400191505060405180910390fd5b600980546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b0382811660009081526004602052604090205416611c195760405162461bcd60e51b81526004018080602001828103825260288152602001806141d96028913960400191505060405180910390fd5b6001600160a01b038316611c5e5760405162461bcd60e51b81526004018080602001828103825260248152602001806142236024913960400191505060405180910390fd5b6000818060200190516020811015611c7557600080fd5b505190506000611c836120da565b9050836001600160a01b0316856001600160a01b0316826001600160a01b03167f9b217a401a5ddf7c4d474074aff9958a18d48690d77cc2151c4706aa7348b401856040518082815260200191505060405180910390a4611cf56001600160a01b03851682308563ffffffff61344416565b6000611d0185846115e7565b905060008451905060208501945060208103855281856040516020018083815260200182805190602001908083835b60208310611d4f5780518252601f199092019160209182019101611d30565b6001836020036101000a038019825116818451168082178552505050505050905001925050506040516020818303038152906040529450606087878760405160200180846001600160a01b03166001600160a01b03168152602001836001600160a01b03166001600160a01b0316815260200180602001828103825283818151815260200191508051906020019080838360005b83811015611dfb578181015183820152602001611de3565b50505050905090810190601f168015611e285780820380516001836020036101000a031916815260200191505b5060408051808303601f19018152828252600780546009546611115413d4d25560ca1b865284519586900390920185206020808701828152878701968752855160608901528551959d506101009093046001600160a01b039081169c506316f198319b50909316985096508a955093608001919085019080838360005b83811015611ebd578181015183820152602001611ea5565b50505050905090810190601f168015611eea5780820380516001836020036101000a031916815260200191505b5093505050506040516020818303038152906040526040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200180602001828103825283818151815260200191508051906020019080838360005b83811015611f63578181015183820152602001611f4b565b50505050905090810190601f168015611f905780820380516001836020036101000a031916815260200191505b509350505050600060405180830381600087803b158015611fb057600080fd5b505af1158015611fc4573d6000803e3d6000fd5b505050505050505050505050565b6001600160a01b039081166000908152600460205260409020541690565b6000611ffa6120da565b600c549091506001600160a01b03808316911614806120265750600b546001600160a01b038281169116145b612067576040805162461bcd60e51b815260206004820152600d60248201526c24b9903737ba1036b0b83832b960991b604482015290519081900360640190fd5b6001600160a01b0382811660009081526004602052604090205416156120be5760405162461bcd60e51b81526004018080602001828103825260268152602001806142966026913960400191505060405180910390fd5b60006120c983610da3565b90506120d58382612278565b505050565b6000333014156121325760606000368080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050503601516001600160a01b031691506121359050565b50335b90565b60006001600160a01b03861661217f5760405162461bcd60e51b81526004018080602001828103825260258152602001806143056025913960400191505060405180910390fd5b600161219261218d8761349e565b61352a565b83868660405160008152602001604052604051808581526020018460ff1660ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa1580156121ec573d6000803e3d6000fd5b505050602060405103516001600160a01b0316866001600160a01b031614905095945050505050565b60008282018381101561226f576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b90505b92915050565b6001600160a01b03808316600081815260046020908152604080832080549587166001600160a01b031996871681179091558084526005909252808320805490951684179094559251909291907f9e651a8866fbea043e911d816ec254b0e3c992c06fff32d605e72362d6023bd9908490a4606082836001600160a01b03166306fdde036040518163ffffffff1660e01b815260040160006040518083038186803b15801561232657600080fd5b505afa15801561233a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101561236357600080fd5b8101908080516040519392919084600160201b82111561238257600080fd5b90830190602082018581111561239757600080fd5b8251600160201b8111828201881017156123b057600080fd5b82525081516020918201929091019080838360005b838110156123dd5781810151838201526020016123c5565b50505050905090810190601f16801561240a5780820380516001836020036101000a031916815260200191505b50604052505050604051602001808065026b0ba34b1960d51b81525060060182805190602001908083835b602083106124545780518252601f199092019160209182019101612435565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051602081830303815290604052846001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b1580156124c157600080fd5b505afa1580156124d5573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405260208110156124fe57600080fd5b8101908080516040519392919084600160201b82111561251d57600080fd5b90830190602082018581111561253257600080fd5b8251600160201b81118282018810171561254b57600080fd5b82525081516020918201929091019080838360005b83811015612578578181015183820152602001612560565b50505050905090810190601f1680156125a55780820380516001836020036101000a031916815260200191505b506040525050506040516020018080606d60f81b81525060010182805190602001908083835b602083106125ea5780518252601f1990920191602091820191016125cb565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051602081830303815290604052856001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b15801561265757600080fd5b505afa15801561266b573d6000803e3d6000fd5b505050506040513d602081101561268157600080fd5b5051604080516001600160a01b038616602082810191825260ff8516608080850191909152938301938452865160a08401528651919392606081019260c09091019188019080838360005b838110156126e45781810151838201526020016126cc565b50505050905090810190601f1680156127115780820380516001836020036101000a031916815260200191505b50838103825285518152855160209182019187019080838360005b8381101561274457818101518382015260200161272c565b50505050905090810190601f1680156127715780820380516001836020036101000a031916815260200191505b5060408051601f19818403018152828252600754600980546826a0a82faa27a5a2a760b91b865284519586900390910185206020868101828152878701968752855160608901528551959f506001600160a01b0361010090950485169e506316f198319d50929093169a5098508c975095509193506080909201919085019080838360005b8381101561280e5781810151838201526020016127f6565b50505050905090810190601f16801561283b5780820380516001836020036101000a031916815260200191505b5093505050506040516020818303038152906040526040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200180602001828103825283818151815260200191508051906020019080838360005b838110156128b457818101518382015260200161289c565b50505050905090810190601f1680156128e15780820380516001836020036101000a031916815260200191505b509350505050600060405180830381600087803b15801561290157600080fd5b505af1158015612915573d6000803e3d6000fd5b50505050505050565b60015460ff1615612967576040805162461bcd60e51b815260206004820152600e60248201526d185b1c9958591e481a5b9a5d195960921b604482015290519081900360640190fd5b61297081613576565b506001805460ff191681179055565b6129876140f8565b606061299a61299584613632565b613657565b60408051602081019091529081529392505050565b606061227282600001516008815181106129c557fe5b602002602001015161373f565b600061227282600001516002815181106129e857fe5b60200260200101516137bc565b6040805160208101909152600081528151606091901561227257600080612a1d600086613809565b60f81c90506001811480612a3457508060ff166003145b15612ac357600185516002020367ffffffffffffffff81118015612a5757600080fd5b506040519080825280601f01601f191660200182016040528015612a82576020820181803683370190505b5092506000612a92600187613809565b90508084600081518110612aa257fe5b60200101906001600160f81b031916908160001a9053506001925050612b14565b600285516002020367ffffffffffffffff81118015612ae157600080fd5b506040519080825280601f01601f191660200182016040528015612b0c576020820181803683370190505b509250600091505b60ff82165b8351811015612b5f57612b348360ff16820360020187613809565b848281518110612b4057fe5b60200101906001600160f81b031916908160001a905350600101612b19565b50505092915050565b600061227282600001516009815181106129e857fe5b612b8661410b565b612b9a82600001516006815181106129c557fe5b6020820152612ba761414c565b612bb48260200151613632565b9050612bbf81613866565b15612bd457612bcd81613657565b8252612c54565b602082015180516060906000190167ffffffffffffffff81118015612bf857600080fd5b506040519080825280601f01601f191660200182016040528015612c23576020820181803683370190505b509050600080836021019150826020019050612c41828285516138a0565b612c4d61299584613632565b8652505050505b612c5d83612b68565b604083015250919050565b612c7061412c565b612c7861414c565b612c998360000151600381518110612c8c57fe5b6020026020010151613657565b836040015181518110612ca857fe5b602002602001015190506040518060400160405280828152602001612ccc83613657565b90529392505050565b60006122728260200151600081518110612ceb57fe5b60200260200101516138eb565b600061227282600001516008815181106129e857fe5b6020015190565b606061227282600001516007815181106129c557fe5b600061227282600001516005815181106129e857fe5b6000612d4b61414c565b612d5484613632565b90506060612d6182613657565b905060608085600082612d738b6129f5565b9050805160001415612d8f576000975050505050505050612f80565b60005b8651811015612f77578151831115612db557600098505050505050505050612f80565b612dd1878281518110612dc457fe5b6020026020010151613905565b955085805190602001208414612df257600098505050505050505050612f80565b612e01878281518110612c8c57fe5b9450845160111415612ebe578151831415612e5d578c80519060200120612e2e866010815181106129c557fe5b805190602001201415612e4c57600198505050505050505050612f80565b600098505050505050505050612f80565b6000828481518110612e6b57fe5b016020015160f81c90506010811115612e905760009950505050505050505050612f80565b612eaf868260ff1681518110612ea257fe5b6020026020010151613984565b94505060019290920191612f6f565b845160021415612e4c576000612ee4612edd876000815181106129c557fe5b84866139a1565b905082518185011415612f3a578d80519060200120612f09876001815181106129c557fe5b805190602001201415612f285760019950505050505050505050612f80565b60009950505050505050505050612f80565b80612f515760009950505050505050505050612f80565b8084019350612f6686600181518110612ea257fe5b9450612f6f9050565b600101612d92565b50505050505050505b949350505050565b600061227282600001516003815181106129e857fe5b600061227282600001516004815181106129e857fe5b600061227282600001516000815181106129e857fe5b606061227282600001516001815181106129c557fe5b600854604080516320a9cea560e11b81526004810185905290516000928392839283926001600160a01b0316916341539d4a9160248083019260a0929190829003018186803b15801561303257600080fd5b505afa158015613046573d6000803e3d6000fd5b505050506040513d60a081101561305c57600080fd5b508051602082015160609092015190945090925090506130cb6130858b8463ffffffff613a8216565b6040805160208082018f90528183018e9052606082018d905260808083018d90528351808403909101815260a0909201909252805191012090858863ffffffff613adf16565b6131065760405162461bcd60e51b81526004018080602001828103825260268152602001806143af6026913960400191505060405180910390fd5b9998505050505050505050565b60606122728260000151613905565b606061313061299583613632565b9050606061314482600181518110612c8c57fe5b90507fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60001b61317a826000815181106129e857fe5b146131b65760405162461bcd60e51b815260040180806020018281038252602981526020018061444f6029913960400191505060405180910390fd5b60006131c8826001815181106129e857fe5b905060006001600160a01b03166131e5836002815181106129e857fe5b6001600160a01b03161461322a5760405162461bcd60e51b81526004018080602001828103825260288152602001806144a26028913960400191505060405180910390fd5b600061323c846002815181106129e857fe5b9050600061324a8783611762565b90506114516001600160a01b038816848363ffffffff613c3516565b6000816132ae576040805162461bcd60e51b81526020600482015260116024820152700703237206469766973696f6e206279203607c1b604482015290519081900360640190fd5b6b033b2e3c9fd0803ce80000008381029081048414613314576040805162461bcd60e51b815260206004820152601b60248201527f703237206d756c7469706c69636174696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b60028304908101908082101561335b5760405162461bcd60e51b81526004018080602001828103825260248152602001806142bc6024913960400191505060405180910390fd5b83828161336457fe5b0495945050505050565b600082820280613382576000915050612272565b83818161338b57fe5b0483146133df576040805162461bcd60e51b815260206004820152601b60248201527f703237206d756c7469706c69636174696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b6b019d971e4fe8401e740000009081019081101561342e5760405162461bcd60e51b81526004018080602001828103825260248152602001806142bc6024913960400191505060405180910390fd5b6b033b2e3c9fd0803ce800000090049392505050565b604080516001600160a01b0380861660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052611037908590613c83565b600060405180608001604052806043815260200161419660439139805190602001208260000151836020015184604001518051906020012060405160200180858152602001848152602001836001600160a01b03166001600160a01b03168152602001828152602001945050505050604051602081830303815290604052805190602001209050919050565b600061353461103d565b82604051602001808061190160f01b81525060020183815260200182815260200192505050604051602081830303815290604052805190602001209050919050565b6040518060800160405280604f8152602001614247604f913980516020918201208251838301206040805180820190915260018152603160f81b930192909252907fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6306135e161116a565b604080516020808201979097528082019590955260608501939093526001600160a01b03909116608084015260a0808401919091528151808403909101815260c09092019052805191012060025550565b61363a61414c565b506040805180820190915281518152602082810190820152919050565b606061366282613866565b61366b57600080fd5b600061367683613d34565b905060608167ffffffffffffffff8111801561369157600080fd5b506040519080825280602002602001820160405280156136cb57816020015b6136b861414c565b8152602001906001900390816136b05790505b50905060006136dd8560200151613d90565b60208601510190506000805b84811015613734576136fa83613df3565b915060405180604001604052808381526020018481525084828151811061371d57fe5b6020908102919091010152918101916001016136e9565b509195945050505050565b805160609061374d57600080fd5b60008061375984613e87565b9150915060608167ffffffffffffffff8111801561377657600080fd5b506040519080825280601f01601f1916602001820160405280156137a1576020820181803683370190505b509050602081016137b3848285613ead565b50949350505050565b8051600090158015906137d157508151602110155b6137da57600080fd5b6000806137e684613e87565b815191935091506020821015612f805760208290036101000a9004949350505050565b6000600283061561383a57601082600285048151811061382557fe5b016020015160f81c8161383457fe5b0661385c565b601082600285048151811061384b57fe5b016020015160f81c8161385a57fe5b045b60f81b9392505050565b8051600090613877575060006114c9565b6020820151805160001a9060c0821015613896576000925050506114c9565b5060019392505050565b806138aa576120d5565b5b602081106138ca578251825260209283019290910190601f19016138ab565b915181516020939093036101000a6000190180199091169216919091179052565b80516000906015146138fc57600080fd5b612272826137bc565b606080826000015167ffffffffffffffff8111801561392357600080fd5b506040519080825280601f01601f19166020018201604052801561394e576020820181803683370190505b5090508051600014156139625790506114c9565b600081602001905061397d8460200151828660000151613ead565b5092915050565b805160009060211461399557600080fd5b50602001516001015190565b60008060606139af866129f5565b90506060815167ffffffffffffffff811180156139cb57600080fd5b506040519080825280601f01601f1916602001820160405280156139f6576020820181803683370190505b509050845b82518601811015613a50576000878281518110613a1457fe5b602001015160f81c60f81b9050808388840381518110613a3057fe5b60200101906001600160f81b031916908160001a905350506001016139fb565b50808051906020012082805190602001201415613a705781519250613a75565b600092505b50909150505b9392505050565b600082821115613ad9576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b60006020825181613aec57fe5b0615613b36576040805162461bcd60e51b8152602060048201526014602482015273092dcecc2d8d2c840e0e4dedecc40d8cadccee8d60631b604482015290519081900360640190fd5b60006020835181613b4357fe5b0490508060020a8510613b95576040805162461bcd60e51b81526020600482015260156024820152744c65616620696e64657820697320746f6f2062696760581b604482015290519081900360640190fd5b60008660205b85518111613c275785810151925060028806613be75781836040516020018083815260200182815260200192505050604051602081830303815290604052805190602001209150613c19565b828260405160200180838152602001828152602001925050506040516020818303038152906040528051906020012091505b600288049750602001613b9b565b509094149695505050505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b1790526120d59084905b6060613cd8826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613efe9092919063ffffffff16565b8051909150156120d557808060200190516020811015613cf757600080fd5b50516120d55760405162461bcd60e51b815260040180806020018281038252602a815260200180614478602a913960400191505060405180910390fd5b8051600090613d45575060006114c9565b60008090506000613d598460200151613d90565b602085015185519181019250015b80821015613d8757613d7882613df3565b60019093019290910190613d67565b50909392505050565b8051600090811a6080811015613daa5760009150506114c9565b60b8811080613dc5575060c08110801590613dc5575060f881105b15613dd45760019150506114c9565b60c0811015613de85760b5190190506114c9565b60f5190190506114c9565b80516000908190811a6080811015613e0e576001915061397d565b60b8811015613e2357607e198101915061397d565b60c0811015613e505760b78103600185019450806020036101000a8551046001820181019350505061397d565b60f8811015613e655760be198101915061397d565b60019390930151602084900360f7016101000a900490920160f5190192915050565b6000806000613e998460200151613d90565b602085015194519481019594039392505050565b80613eb7576120d5565b5b60208110613ed7578251825260209283019290910190601f1901613eb8565b80156120d557915181516020939093036101000a6000190180199091169216919091179052565b6060612f80848460008585613f1285614024565b613f63576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015290519081900360640190fd5b60006060866001600160a01b031685876040518082805190602001908083835b60208310613fa25780518252601f199092019160209182019101613f83565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d8060008114614004576040519150601f19603f3d011682016040523d82523d6000602084013e614009565b606091505b509150915061401982828661402a565b979650505050505050565b3b151590565b60608315614039575081613a7b565b8251156140495782518084602001fd5b8160405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561409357818101518382015260200161407b565b50505050905090810190601f1680156140c05780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b60405180606001604052806000815260200160006001600160a01b03168152602001606081525090565b6040518060200160405280606081525090565b60405180606001604052806060815260200160608152602001600081525090565b604051806040016040528061413f61414c565b8152602001606081525090565b60405180604001604052806000815260200160008152509056fe41546f6b656e526f6f74436861696e4d616e616765723a204368696c6420746f6b656e206973207468652073616d654d6574615472616e73616374696f6e2875696e74323536206e6f6e63652c616464726573732066726f6d2c62797465732066756e6374696f6e5369676e61747572652941546f6b656e526f6f74436861696e4d616e616765723a20544f4b454e5f4e4f545f4d415050454443616e6e6f742073656e6420455448206f7665722061546f6b656e2062726964676541546f6b656e526f6f74436861696e4d616e616765723a20494e56414c49445f55534552454950373132446f6d61696e28737472696e67206e616d652c737472696e672076657273696f6e2c6164647265737320766572696679696e67436f6e74726163742c627974657333322073616c742941546f6b656e526f6f74436861696e4d616e616765723a20414c52454144595f4d4150504544703237206d756c7469706c69636174696f6e206164646974696f6e206f766572666c6f7741546f6b656e526f6f74436861696e4d616e616765723a20494e56414c49445f50524f4f464e61746976654d6574615472616e73616374696f6e3a20494e56414c49445f5349474e455241546f6b656e526f6f74436861696e4d616e616765723a20494e56414c49445f4252414e43485f4d41534b41546f6b656e526f6f74436861696e4d616e616765723a20455849545f414c52454144595f50524f434553534544526f6f74436861696e4d616e616765723a204241445f4e45575f434845434b504f494e545f4d414e4147455241546f6b656e526f6f74436861696e4d616e616765723a20494e56414c49445f4845414445525369676e657220616e64207369676e617475726520646f206e6f74206d61746368526f6f74436861696e4d616e616765723a204241445f4e45575f53544154455f53454e44455241546f6b656e526f6f74436861696e4d616e616765723a20494e56414c49445f4348494c445f434841494e5f4144445245535341546f6b656e526f6f74436861696e4d616e616765723a20494e56414c49445f5349474e41545552455361666545524332303a204552433230206f7065726174696f6e20646964206e6f74207375636365656441546f6b656e526f6f74436861696e4d616e616765723a20494e56414c49445f5245434549564552a264697066735822122037454f12bec2f2dc5b85f7a30be5e9fa05dca30edf2849f968433600081f42ca64736f6c63430006060033

Deployed Bytecode

0x6080604052600436106101f15760003560e01c80636cb136b01161010d578063c38a960e116100a0578063dc993a231161006f578063dc993a2314610857578063e2c49de114610803578063e3dec8fb1461088a578063ea60c7c414610954578063f4a120f7146109875761022d565b8063c38a960e146107d0578063cb10f94c14610803578063d45d760e14610818578063d81c8e52146108425761022d565b80638da5cb5b116100dc5780638da5cb5b1461073a5780639b2492c81461074f578063b017a30f14610788578063bc08452b1461079d5761022d565b80636cb136b0146106865780636e86b770146106b9578063886a69ba146106ec57806389d60963146107015761022d565b80632d0335ab1161018557806341539d4a1161015457806341539d4a146105c0578063568b80b51461061e578063607f2d421461063357806362f4f6a2146106715761022d565b80632d0335ab146104e85780633138b6f11461051b5780633408e470146105305780633805550f146105455761022d565b806313af4035116101c157806313af4035146104085780631d97c02b1461043b57806320379ee51461046e578063297a3e57146104955761022d565b8062561b7c146102325780630c53c51c1461026d5780630f7e5970146103a45780631116f918146103b95761022d565b3661022d5760405162461bcd60e51b81526004018080602001828103825260228152602001806142016022913960400191505060405180910390fd5b600080fd5b34801561023e57600080fd5b5061026b6004803603604081101561025557600080fd5b506001600160a01b0381351690602001356109ba565b005b61032f600480360360a081101561028357600080fd5b6001600160a01b038235169190810190604081016020820135600160201b8111156102ad57600080fd5b8201836020820111156102bf57600080fd5b803590602001918460018302840111600160201b831117156102e057600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550508235935050506020810135906040013560ff16610a83565b6040805160208082528351818301528351919283929083019185019080838360005b83811015610369578181015183820152602001610351565b50505050905090810190601f1680156103965780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3480156103b057600080fd5b5061032f610d86565b3480156103c557600080fd5b506103ec600480360360208110156103dc57600080fd5b50356001600160a01b0316610da3565b604080516001600160a01b039092168252519081900360200190f35b34801561041457600080fd5b5061026b6004803603602081101561042b57600080fd5b50356001600160a01b0316610e08565b34801561044757600080fd5b5061026b6004803603602081101561045e57600080fd5b50356001600160a01b0316610ec2565b34801561047a57600080fd5b5061048361103d565b60408051918252519081900360200190f35b3480156104a157600080fd5b5061026b600480360360a08110156104b857600080fd5b506001600160a01b0381358116916020810135821691604082013581169160608101359091169060800135611043565b3480156104f457600080fd5b506104836004803603602081101561050b57600080fd5b50356001600160a01b0316611140565b34801561052757600080fd5b506103ec61115b565b34801561053c57600080fd5b5061048361116a565b34801561055157600080fd5b5061026b6004803603602081101561056857600080fd5b810190602081018135600160201b81111561058257600080fd5b82018360208201111561059457600080fd5b803590602001918460018302840111600160201b831117156105b557600080fd5b50909250905061116e565b3480156105cc57600080fd5b506105ea600480360360208110156105e357600080fd5b503561145b565b6040805195865260208601949094528484019290925260608401526001600160a01b03166080830152519081900360a00190f35b34801561062a57600080fd5b50610483611493565b34801561063f57600080fd5b5061065d6004803603602081101561065657600080fd5b50356114b6565b604080519115158252519081900360200190f35b34801561067d57600080fd5b506103ec6114ce565b34801561069257600080fd5b5061026b600480360360208110156106a957600080fd5b50356001600160a01b03166114dd565b3480156106c557600080fd5b506103ec600480360360208110156106dc57600080fd5b50356001600160a01b03166115a8565b3480156106f857600080fd5b506104836115c6565b34801561070d57600080fd5b506104836004803603604081101561072457600080fd5b506001600160a01b0381351690602001356115e7565b34801561074657600080fd5b506103ec611753565b34801561075b57600080fd5b506104836004803603604081101561077257600080fd5b506001600160a01b038135169060200135611762565b34801561079457600080fd5b506104836118c5565b3480156107a957600080fd5b5061026b600480360360208110156107c057600080fd5b50356001600160a01b03166118e9565b3480156107dc57600080fd5b5061026b600480360360208110156107f357600080fd5b50356001600160a01b03166119ae565b34801561080f57600080fd5b506103ec611a68565b34801561082457600080fd5b5061026b6004803603602081101561083b57600080fd5b5035611a7c565b34801561084e57600080fd5b50610483611adf565b34801561086357600080fd5b5061026b6004803603602081101561087a57600080fd5b50356001600160a01b0316611afe565b34801561089657600080fd5b5061026b600480360360608110156108ad57600080fd5b6001600160a01b038235811692602081013590911691810190606081016040820135600160201b8111156108e057600080fd5b8201836020820111156108f257600080fd5b803590602001918460018302840111600160201b8311171561091357600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550611bc3945050505050565b34801561096057600080fd5b506103ec6004803603602081101561097757600080fd5b50356001600160a01b0316611fd2565b34801561099357600080fd5b5061026b600480360360208110156109aa57600080fd5b50356001600160a01b0316611ff0565b600b546001600160a01b03166109ce6120da565b6001600160a01b031614610a18576040805162461bcd60e51b815260206004820152600c60248201526b24b9903737ba1037bbb732b960a11b604482015290519081900360640190fd5b6001600160a01b038216610a5d5760405162461bcd60e51b815260040180806020018281038252603381526020018061441c6033913960400191505060405180910390fd5b600980546001600160a01b0319166001600160a01b039390931692909217909155600a55565b6060610a8d6140ce565b50604080516060810182526001600160a01b03881660008181526003602090815290849020548352820152908101869052610acb8782878787612138565b610b065760405162461bcd60e51b81526004018080602001828103825260218152602001806143d56021913960400191505060405180910390fd5b6001600160a01b038716600090815260036020526040902054610b3090600163ffffffff61221516565b6001600160a01b03881660008181526003602090815260408083209490945583519283523383820181905260609484018581528b51958501959095528a517f5845892132946850460bff5a0083f71031bc5bf9aadcd40f1de79423eac9b10b958d9592948d94919260808501928601918190849084905b83811015610bbf578181015183820152602001610ba7565b50505050905090810190601f168015610bec5780820380516001836020036101000a031916815260200191505b5094505050505060405180910390a160006060306001600160a01b0316888a6040516020018083805190602001908083835b60208310610c3d5780518252601f199092019160209182019101610c1e565b6001836020036101000a038019825116818451168082178552505050505050905001826001600160a01b03166001600160a01b031660601b8152601401925050506040516020818303038152906040526040518082805190602001908083835b60208310610cbc5780518252601f199092019160209182019101610c9d565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114610d1e576040519150601f19603f3d011682016040523d82523d6000602084013e610d23565b606091505b509150915081610d7a576040805162461bcd60e51b815260206004820152601c60248201527f46756e6374696f6e2063616c6c206e6f74207375636365737366756c00000000604482015290519081900360640190fd5b98975050505050505050565b604051806040016040528060018152602001603160f81b81525081565b600954600a54604080516001600160f81b03196020808301919091526bffffffffffffffffffffffff19606095861b811660218401529590941b9094166035850152605580850192909252805180850390920182526075909301909252815191012090565b600b546001600160a01b0316610e1c6120da565b6001600160a01b031614610e66576040805162461bcd60e51b815260206004820152600c60248201526b24b9903737ba1037bbb732b960a11b604482015290519081900360640190fd5b600b546040516001600160a01b038084169216907fcbf985117192c8f614a58aaf97226bb80a754772f5f6edf06f87c675f2e6c66390600090a3600b80546001600160a01b0319166001600160a01b0392909216919091179055565b600b546001600160a01b0316610ed66120da565b6001600160a01b031614610f20576040805162461bcd60e51b815260206004820152600c60248201526b24b9903737ba1037bbb732b960a11b604482015290519081900360640190fd5b6000610f2b82610da3565b6001600160a01b03808416600090815260046020526040902054919250908116908216811415610f8c5760405162461bcd60e51b815260040180806020018281038252602f815260200180614167602f913960400191505060405180910390fd5b6001600160a01b03808316600090815260056020908152604080832054841680845260049092529091205490911615610fe6576001600160a01b038116600090815260046020526040902080546001600160a01b03191690555b6001600160a01b03828116600090815260056020526040902054161561102d576001600160a01b038216600090815260056020526040902080546001600160a01b03191690555b6110378484612278565b50505050565b60025490565b60075460ff161561108c576040805162461bcd60e51b815260206004820152600e60248201526d185b1c9958591e481a5b9a5d195960921b604482015290519081900360640190fd5b6007805460ff1916600117905560408051808201909152601681527520aa37b5b2b72937b7ba21b430b4b726b0b730b3b2b960511b60208201526110cf9061291e565b600b80546001600160a01b03199081166001600160a01b03978816908117909255600c8054821690921790915560078054610100600160a81b031916610100968816969096029590951790945560088054851693861693909317909255600980549093169316929092179055600a55565b6001600160a01b031660009081526003602052604090205490565b6008546001600160a01b031690565b4690565b6111766140f8565b6111b583838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061297f92505050565b905060606111c2826129af565b905060006111cf836129d2565b6111d8836129f5565b6111e185612b68565b6040516020018084815260200183805190602001908083835b602083106112195780518252601f1990920191602091820191016111fa565b51815160209384036101000a6000190180199092169116179052920193845250604080518085038152938201815283519382019390932060008181526006909252929020549194505060ff161591506112a590505760405162461bcd60e51b815260040180806020018281038252602e815260200180614355602e913960400191505060405180910390fd5b6000818152600660205260409020805460ff191660011790556112c661410b565b6112cf84612b7e565b90506112d961412c565b6112e282612c68565b905060006005816112f284612cd5565b6001600160a01b0390811682526020820192909252604001600020541690508061134d5760405162461bcd60e51b81526004018080602001828103825260288152602001806141d96028913960400191505060405180910390fd5b61135686612cf8565b63ffffffff1916156113995760405162461bcd60e51b815260040180806020018281038252602b81526020018061432a602b913960400191505060405180910390fd5b6113bd6113a584612d0e565b866113af89612d15565b6113b88a612d2b565b612d41565b6113f85760405162461bcd60e51b81526004018080602001828103825260258152602001806142e06025913960400191505060405180910390fd5b611436611404876129d2565b61140d88612f88565b61141689612f9e565b61141f8a612d2b565b6114288b612fb4565b6114318c612fca565b612fe0565b506114516114426120da565b8261144c85613113565b613122565b5050505050505050565b60006020819052908152604090208054600182015460028301546003840154600490940154929391929091906001600160a01b031685565b604080516a4d41505045525f524f4c4560a81b8152905190819003600b01902081565b60008181526006602052604090205460ff165b919050565b600c546001600160a01b031690565b600b546001600160a01b03166114f16120da565b6001600160a01b03161461153b576040805162461bcd60e51b815260206004820152600c60248201526b24b9903737ba1037bbb732b960a11b604482015290519081900360640190fd5b6001600160a01b0381166115805760405162461bcd60e51b81526004018080602001828103825260268152602001806143f66026913960400191505060405180910390fd5b600780546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b6001600160a01b039081166000908152600560205260409020541690565b604080516826a0a82faa27a5a2a760b91b8152905190819003600901902081565b600080836001600160a01b0316637535d2466040518163ffffffff1660e01b815260040160206040518083038186803b15801561162357600080fd5b505afa158015611637573d6000803e3d6000fd5b505050506040513d602081101561164d57600080fd5b5051604080516358b50cef60e11b815290519192506000916001600160a01b038085169263d15e0053929189169163b16a19de91600480820192602092909190829003018186803b1580156116a157600080fd5b505afa1580156116b5573d6000803e3d6000fd5b505050506040513d60208110156116cb57600080fd5b5051604080516001600160e01b031960e085901b1681526001600160a01b039092166004830152516024808301926020929190829003018186803b15801561171257600080fd5b505afa158015611726573d6000803e3d6000fd5b505050506040513d602081101561173c57600080fd5b5051905061174a8482613266565b95945050505050565b600b546001600160a01b031690565b600080836001600160a01b0316637535d2466040518163ffffffff1660e01b815260040160206040518083038186803b15801561179e57600080fd5b505afa1580156117b2573d6000803e3d6000fd5b505050506040513d60208110156117c857600080fd5b5051604080516358b50cef60e11b815290519192506000916001600160a01b038085169263d15e0053929189169163b16a19de91600480820192602092909190829003018186803b15801561181c57600080fd5b505afa158015611830573d6000803e3d6000fd5b505050506040513d602081101561184657600080fd5b5051604080516001600160e01b031960e085901b1681526001600160a01b039092166004830152516024808301926020929190829003018186803b15801561188d57600080fd5b505afa1580156118a1573d6000803e3d6000fd5b505050506040513d60208110156118b757600080fd5b5051905061174a848261336e565b7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef81565b600b546001600160a01b03166118fd6120da565b6001600160a01b031614611947576040805162461bcd60e51b815260206004820152600c60248201526b24b9903737ba1037bbb732b960a11b604482015290519081900360640190fd5b6001600160a01b03811661198c5760405162461bcd60e51b815260040180806020018281038252602c815260200180614383602c913960400191505060405180910390fd5b600880546001600160a01b0319166001600160a01b0392909216919091179055565b600b546001600160a01b03166119c26120da565b6001600160a01b031614611a0c576040805162461bcd60e51b815260206004820152600c60248201526b24b9903737ba1037bbb732b960a11b604482015290519081900360640190fd5b600c546040516001600160a01b038084169216907fc3ccb9ca599457fe5a9bb338f84c2f853b1898c3a6e7eba842d95b0f017a7fa190600090a3600c80546001600160a01b0319166001600160a01b0392909216919091179055565b60075461010090046001600160a01b031690565b600b546001600160a01b0316611a906120da565b6001600160a01b031614611ada576040805162461bcd60e51b815260206004820152600c60248201526b24b9903737ba1037bbb732b960a11b604482015290519081900360640190fd5b600a55565b604080516611115413d4d25560ca1b8152905190819003600701902081565b600b546001600160a01b0316611b126120da565b6001600160a01b031614611b5c576040805162461bcd60e51b815260206004820152600c60248201526b24b9903737ba1037bbb732b960a11b604482015290519081900360640190fd5b6001600160a01b038116611ba15760405162461bcd60e51b815260040180806020018281038252603381526020018061441c6033913960400191505060405180910390fd5b600980546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b0382811660009081526004602052604090205416611c195760405162461bcd60e51b81526004018080602001828103825260288152602001806141d96028913960400191505060405180910390fd5b6001600160a01b038316611c5e5760405162461bcd60e51b81526004018080602001828103825260248152602001806142236024913960400191505060405180910390fd5b6000818060200190516020811015611c7557600080fd5b505190506000611c836120da565b9050836001600160a01b0316856001600160a01b0316826001600160a01b03167f9b217a401a5ddf7c4d474074aff9958a18d48690d77cc2151c4706aa7348b401856040518082815260200191505060405180910390a4611cf56001600160a01b03851682308563ffffffff61344416565b6000611d0185846115e7565b905060008451905060208501945060208103855281856040516020018083815260200182805190602001908083835b60208310611d4f5780518252601f199092019160209182019101611d30565b6001836020036101000a038019825116818451168082178552505050505050905001925050506040516020818303038152906040529450606087878760405160200180846001600160a01b03166001600160a01b03168152602001836001600160a01b03166001600160a01b0316815260200180602001828103825283818151815260200191508051906020019080838360005b83811015611dfb578181015183820152602001611de3565b50505050905090810190601f168015611e285780820380516001836020036101000a031916815260200191505b5060408051808303601f19018152828252600780546009546611115413d4d25560ca1b865284519586900390920185206020808701828152878701968752855160608901528551959d506101009093046001600160a01b039081169c506316f198319b50909316985096508a955093608001919085019080838360005b83811015611ebd578181015183820152602001611ea5565b50505050905090810190601f168015611eea5780820380516001836020036101000a031916815260200191505b5093505050506040516020818303038152906040526040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200180602001828103825283818151815260200191508051906020019080838360005b83811015611f63578181015183820152602001611f4b565b50505050905090810190601f168015611f905780820380516001836020036101000a031916815260200191505b509350505050600060405180830381600087803b158015611fb057600080fd5b505af1158015611fc4573d6000803e3d6000fd5b505050505050505050505050565b6001600160a01b039081166000908152600460205260409020541690565b6000611ffa6120da565b600c549091506001600160a01b03808316911614806120265750600b546001600160a01b038281169116145b612067576040805162461bcd60e51b815260206004820152600d60248201526c24b9903737ba1036b0b83832b960991b604482015290519081900360640190fd5b6001600160a01b0382811660009081526004602052604090205416156120be5760405162461bcd60e51b81526004018080602001828103825260268152602001806142966026913960400191505060405180910390fd5b60006120c983610da3565b90506120d58382612278565b505050565b6000333014156121325760606000368080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050503601516001600160a01b031691506121359050565b50335b90565b60006001600160a01b03861661217f5760405162461bcd60e51b81526004018080602001828103825260258152602001806143056025913960400191505060405180910390fd5b600161219261218d8761349e565b61352a565b83868660405160008152602001604052604051808581526020018460ff1660ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa1580156121ec573d6000803e3d6000fd5b505050602060405103516001600160a01b0316866001600160a01b031614905095945050505050565b60008282018381101561226f576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b90505b92915050565b6001600160a01b03808316600081815260046020908152604080832080549587166001600160a01b031996871681179091558084526005909252808320805490951684179094559251909291907f9e651a8866fbea043e911d816ec254b0e3c992c06fff32d605e72362d6023bd9908490a4606082836001600160a01b03166306fdde036040518163ffffffff1660e01b815260040160006040518083038186803b15801561232657600080fd5b505afa15801561233a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101561236357600080fd5b8101908080516040519392919084600160201b82111561238257600080fd5b90830190602082018581111561239757600080fd5b8251600160201b8111828201881017156123b057600080fd5b82525081516020918201929091019080838360005b838110156123dd5781810151838201526020016123c5565b50505050905090810190601f16801561240a5780820380516001836020036101000a031916815260200191505b50604052505050604051602001808065026b0ba34b1960d51b81525060060182805190602001908083835b602083106124545780518252601f199092019160209182019101612435565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051602081830303815290604052846001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b1580156124c157600080fd5b505afa1580156124d5573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405260208110156124fe57600080fd5b8101908080516040519392919084600160201b82111561251d57600080fd5b90830190602082018581111561253257600080fd5b8251600160201b81118282018810171561254b57600080fd5b82525081516020918201929091019080838360005b83811015612578578181015183820152602001612560565b50505050905090810190601f1680156125a55780820380516001836020036101000a031916815260200191505b506040525050506040516020018080606d60f81b81525060010182805190602001908083835b602083106125ea5780518252601f1990920191602091820191016125cb565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051602081830303815290604052856001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b15801561265757600080fd5b505afa15801561266b573d6000803e3d6000fd5b505050506040513d602081101561268157600080fd5b5051604080516001600160a01b038616602082810191825260ff8516608080850191909152938301938452865160a08401528651919392606081019260c09091019188019080838360005b838110156126e45781810151838201526020016126cc565b50505050905090810190601f1680156127115780820380516001836020036101000a031916815260200191505b50838103825285518152855160209182019187019080838360005b8381101561274457818101518382015260200161272c565b50505050905090810190601f1680156127715780820380516001836020036101000a031916815260200191505b5060408051601f19818403018152828252600754600980546826a0a82faa27a5a2a760b91b865284519586900390910185206020868101828152878701968752855160608901528551959f506001600160a01b0361010090950485169e506316f198319d50929093169a5098508c975095509193506080909201919085019080838360005b8381101561280e5781810151838201526020016127f6565b50505050905090810190601f16801561283b5780820380516001836020036101000a031916815260200191505b5093505050506040516020818303038152906040526040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200180602001828103825283818151815260200191508051906020019080838360005b838110156128b457818101518382015260200161289c565b50505050905090810190601f1680156128e15780820380516001836020036101000a031916815260200191505b509350505050600060405180830381600087803b15801561290157600080fd5b505af1158015612915573d6000803e3d6000fd5b50505050505050565b60015460ff1615612967576040805162461bcd60e51b815260206004820152600e60248201526d185b1c9958591e481a5b9a5d195960921b604482015290519081900360640190fd5b61297081613576565b506001805460ff191681179055565b6129876140f8565b606061299a61299584613632565b613657565b60408051602081019091529081529392505050565b606061227282600001516008815181106129c557fe5b602002602001015161373f565b600061227282600001516002815181106129e857fe5b60200260200101516137bc565b6040805160208101909152600081528151606091901561227257600080612a1d600086613809565b60f81c90506001811480612a3457508060ff166003145b15612ac357600185516002020367ffffffffffffffff81118015612a5757600080fd5b506040519080825280601f01601f191660200182016040528015612a82576020820181803683370190505b5092506000612a92600187613809565b90508084600081518110612aa257fe5b60200101906001600160f81b031916908160001a9053506001925050612b14565b600285516002020367ffffffffffffffff81118015612ae157600080fd5b506040519080825280601f01601f191660200182016040528015612b0c576020820181803683370190505b509250600091505b60ff82165b8351811015612b5f57612b348360ff16820360020187613809565b848281518110612b4057fe5b60200101906001600160f81b031916908160001a905350600101612b19565b50505092915050565b600061227282600001516009815181106129e857fe5b612b8661410b565b612b9a82600001516006815181106129c557fe5b6020820152612ba761414c565b612bb48260200151613632565b9050612bbf81613866565b15612bd457612bcd81613657565b8252612c54565b602082015180516060906000190167ffffffffffffffff81118015612bf857600080fd5b506040519080825280601f01601f191660200182016040528015612c23576020820181803683370190505b509050600080836021019150826020019050612c41828285516138a0565b612c4d61299584613632565b8652505050505b612c5d83612b68565b604083015250919050565b612c7061412c565b612c7861414c565b612c998360000151600381518110612c8c57fe5b6020026020010151613657565b836040015181518110612ca857fe5b602002602001015190506040518060400160405280828152602001612ccc83613657565b90529392505050565b60006122728260200151600081518110612ceb57fe5b60200260200101516138eb565b600061227282600001516008815181106129e857fe5b6020015190565b606061227282600001516007815181106129c557fe5b600061227282600001516005815181106129e857fe5b6000612d4b61414c565b612d5484613632565b90506060612d6182613657565b905060608085600082612d738b6129f5565b9050805160001415612d8f576000975050505050505050612f80565b60005b8651811015612f77578151831115612db557600098505050505050505050612f80565b612dd1878281518110612dc457fe5b6020026020010151613905565b955085805190602001208414612df257600098505050505050505050612f80565b612e01878281518110612c8c57fe5b9450845160111415612ebe578151831415612e5d578c80519060200120612e2e866010815181106129c557fe5b805190602001201415612e4c57600198505050505050505050612f80565b600098505050505050505050612f80565b6000828481518110612e6b57fe5b016020015160f81c90506010811115612e905760009950505050505050505050612f80565b612eaf868260ff1681518110612ea257fe5b6020026020010151613984565b94505060019290920191612f6f565b845160021415612e4c576000612ee4612edd876000815181106129c557fe5b84866139a1565b905082518185011415612f3a578d80519060200120612f09876001815181106129c557fe5b805190602001201415612f285760019950505050505050505050612f80565b60009950505050505050505050612f80565b80612f515760009950505050505050505050612f80565b8084019350612f6686600181518110612ea257fe5b9450612f6f9050565b600101612d92565b50505050505050505b949350505050565b600061227282600001516003815181106129e857fe5b600061227282600001516004815181106129e857fe5b600061227282600001516000815181106129e857fe5b606061227282600001516001815181106129c557fe5b600854604080516320a9cea560e11b81526004810185905290516000928392839283926001600160a01b0316916341539d4a9160248083019260a0929190829003018186803b15801561303257600080fd5b505afa158015613046573d6000803e3d6000fd5b505050506040513d60a081101561305c57600080fd5b508051602082015160609092015190945090925090506130cb6130858b8463ffffffff613a8216565b6040805160208082018f90528183018e9052606082018d905260808083018d90528351808403909101815260a0909201909252805191012090858863ffffffff613adf16565b6131065760405162461bcd60e51b81526004018080602001828103825260268152602001806143af6026913960400191505060405180910390fd5b9998505050505050505050565b60606122728260000151613905565b606061313061299583613632565b9050606061314482600181518110612c8c57fe5b90507fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60001b61317a826000815181106129e857fe5b146131b65760405162461bcd60e51b815260040180806020018281038252602981526020018061444f6029913960400191505060405180910390fd5b60006131c8826001815181106129e857fe5b905060006001600160a01b03166131e5836002815181106129e857fe5b6001600160a01b03161461322a5760405162461bcd60e51b81526004018080602001828103825260288152602001806144a26028913960400191505060405180910390fd5b600061323c846002815181106129e857fe5b9050600061324a8783611762565b90506114516001600160a01b038816848363ffffffff613c3516565b6000816132ae576040805162461bcd60e51b81526020600482015260116024820152700703237206469766973696f6e206279203607c1b604482015290519081900360640190fd5b6b033b2e3c9fd0803ce80000008381029081048414613314576040805162461bcd60e51b815260206004820152601b60248201527f703237206d756c7469706c69636174696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b60028304908101908082101561335b5760405162461bcd60e51b81526004018080602001828103825260248152602001806142bc6024913960400191505060405180910390fd5b83828161336457fe5b0495945050505050565b600082820280613382576000915050612272565b83818161338b57fe5b0483146133df576040805162461bcd60e51b815260206004820152601b60248201527f703237206d756c7469706c69636174696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b6b019d971e4fe8401e740000009081019081101561342e5760405162461bcd60e51b81526004018080602001828103825260248152602001806142bc6024913960400191505060405180910390fd5b6b033b2e3c9fd0803ce800000090049392505050565b604080516001600160a01b0380861660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052611037908590613c83565b600060405180608001604052806043815260200161419660439139805190602001208260000151836020015184604001518051906020012060405160200180858152602001848152602001836001600160a01b03166001600160a01b03168152602001828152602001945050505050604051602081830303815290604052805190602001209050919050565b600061353461103d565b82604051602001808061190160f01b81525060020183815260200182815260200192505050604051602081830303815290604052805190602001209050919050565b6040518060800160405280604f8152602001614247604f913980516020918201208251838301206040805180820190915260018152603160f81b930192909252907fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6306135e161116a565b604080516020808201979097528082019590955260608501939093526001600160a01b03909116608084015260a0808401919091528151808403909101815260c09092019052805191012060025550565b61363a61414c565b506040805180820190915281518152602082810190820152919050565b606061366282613866565b61366b57600080fd5b600061367683613d34565b905060608167ffffffffffffffff8111801561369157600080fd5b506040519080825280602002602001820160405280156136cb57816020015b6136b861414c565b8152602001906001900390816136b05790505b50905060006136dd8560200151613d90565b60208601510190506000805b84811015613734576136fa83613df3565b915060405180604001604052808381526020018481525084828151811061371d57fe5b6020908102919091010152918101916001016136e9565b509195945050505050565b805160609061374d57600080fd5b60008061375984613e87565b9150915060608167ffffffffffffffff8111801561377657600080fd5b506040519080825280601f01601f1916602001820160405280156137a1576020820181803683370190505b509050602081016137b3848285613ead565b50949350505050565b8051600090158015906137d157508151602110155b6137da57600080fd5b6000806137e684613e87565b815191935091506020821015612f805760208290036101000a9004949350505050565b6000600283061561383a57601082600285048151811061382557fe5b016020015160f81c8161383457fe5b0661385c565b601082600285048151811061384b57fe5b016020015160f81c8161385a57fe5b045b60f81b9392505050565b8051600090613877575060006114c9565b6020820151805160001a9060c0821015613896576000925050506114c9565b5060019392505050565b806138aa576120d5565b5b602081106138ca578251825260209283019290910190601f19016138ab565b915181516020939093036101000a6000190180199091169216919091179052565b80516000906015146138fc57600080fd5b612272826137bc565b606080826000015167ffffffffffffffff8111801561392357600080fd5b506040519080825280601f01601f19166020018201604052801561394e576020820181803683370190505b5090508051600014156139625790506114c9565b600081602001905061397d8460200151828660000151613ead565b5092915050565b805160009060211461399557600080fd5b50602001516001015190565b60008060606139af866129f5565b90506060815167ffffffffffffffff811180156139cb57600080fd5b506040519080825280601f01601f1916602001820160405280156139f6576020820181803683370190505b509050845b82518601811015613a50576000878281518110613a1457fe5b602001015160f81c60f81b9050808388840381518110613a3057fe5b60200101906001600160f81b031916908160001a905350506001016139fb565b50808051906020012082805190602001201415613a705781519250613a75565b600092505b50909150505b9392505050565b600082821115613ad9576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b60006020825181613aec57fe5b0615613b36576040805162461bcd60e51b8152602060048201526014602482015273092dcecc2d8d2c840e0e4dedecc40d8cadccee8d60631b604482015290519081900360640190fd5b60006020835181613b4357fe5b0490508060020a8510613b95576040805162461bcd60e51b81526020600482015260156024820152744c65616620696e64657820697320746f6f2062696760581b604482015290519081900360640190fd5b60008660205b85518111613c275785810151925060028806613be75781836040516020018083815260200182815260200192505050604051602081830303815290604052805190602001209150613c19565b828260405160200180838152602001828152602001925050506040516020818303038152906040528051906020012091505b600288049750602001613b9b565b509094149695505050505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b1790526120d59084905b6060613cd8826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613efe9092919063ffffffff16565b8051909150156120d557808060200190516020811015613cf757600080fd5b50516120d55760405162461bcd60e51b815260040180806020018281038252602a815260200180614478602a913960400191505060405180910390fd5b8051600090613d45575060006114c9565b60008090506000613d598460200151613d90565b602085015185519181019250015b80821015613d8757613d7882613df3565b60019093019290910190613d67565b50909392505050565b8051600090811a6080811015613daa5760009150506114c9565b60b8811080613dc5575060c08110801590613dc5575060f881105b15613dd45760019150506114c9565b60c0811015613de85760b5190190506114c9565b60f5190190506114c9565b80516000908190811a6080811015613e0e576001915061397d565b60b8811015613e2357607e198101915061397d565b60c0811015613e505760b78103600185019450806020036101000a8551046001820181019350505061397d565b60f8811015613e655760be198101915061397d565b60019390930151602084900360f7016101000a900490920160f5190192915050565b6000806000613e998460200151613d90565b602085015194519481019594039392505050565b80613eb7576120d5565b5b60208110613ed7578251825260209283019290910190601f1901613eb8565b80156120d557915181516020939093036101000a6000190180199091169216919091179052565b6060612f80848460008585613f1285614024565b613f63576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015290519081900360640190fd5b60006060866001600160a01b031685876040518082805190602001908083835b60208310613fa25780518252601f199092019160209182019101613f83565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d8060008114614004576040519150601f19603f3d011682016040523d82523d6000602084013e614009565b606091505b509150915061401982828661402a565b979650505050505050565b3b151590565b60608315614039575081613a7b565b8251156140495782518084602001fd5b8160405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561409357818101518382015260200161407b565b50505050905090810190601f1680156140c05780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b60405180606001604052806000815260200160006001600160a01b03168152602001606081525090565b6040518060200160405280606081525090565b60405180606001604052806060815260200160608152602001600081525090565b604051806040016040528061413f61414c565b8152602001606081525090565b60405180604001604052806000815260200160008152509056fe41546f6b656e526f6f74436861696e4d616e616765723a204368696c6420746f6b656e206973207468652073616d654d6574615472616e73616374696f6e2875696e74323536206e6f6e63652c616464726573732066726f6d2c62797465732066756e6374696f6e5369676e61747572652941546f6b656e526f6f74436861696e4d616e616765723a20544f4b454e5f4e4f545f4d415050454443616e6e6f742073656e6420455448206f7665722061546f6b656e2062726964676541546f6b656e526f6f74436861696e4d616e616765723a20494e56414c49445f55534552454950373132446f6d61696e28737472696e67206e616d652c737472696e672076657273696f6e2c6164647265737320766572696679696e67436f6e74726163742c627974657333322073616c742941546f6b656e526f6f74436861696e4d616e616765723a20414c52454144595f4d4150504544703237206d756c7469706c69636174696f6e206164646974696f6e206f766572666c6f7741546f6b656e526f6f74436861696e4d616e616765723a20494e56414c49445f50524f4f464e61746976654d6574615472616e73616374696f6e3a20494e56414c49445f5349474e455241546f6b656e526f6f74436861696e4d616e616765723a20494e56414c49445f4252414e43485f4d41534b41546f6b656e526f6f74436861696e4d616e616765723a20455849545f414c52454144595f50524f434553534544526f6f74436861696e4d616e616765723a204241445f4e45575f434845434b504f494e545f4d414e4147455241546f6b656e526f6f74436861696e4d616e616765723a20494e56414c49445f4845414445525369676e657220616e64207369676e617475726520646f206e6f74206d61746368526f6f74436861696e4d616e616765723a204241445f4e45575f53544154455f53454e44455241546f6b656e526f6f74436861696e4d616e616765723a20494e56414c49445f4348494c445f434841494e5f4144445245535341546f6b656e526f6f74436861696e4d616e616765723a20494e56414c49445f5349474e41545552455361666545524332303a204552433230206f7065726174696f6e20646964206e6f74207375636365656441546f6b656e526f6f74436861696e4d616e616765723a20494e56414c49445f5245434549564552a264697066735822122037454f12bec2f2dc5b85f7a30be5e9fa05dca30edf2849f968433600081f42ca64736f6c63430006060033

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.