ETH Price: $3,688.28 (+3.33%)

Contract

0x6F8a42cf6f3CE657B66A9d5849f1251dE7a35168
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

Please try again later

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Similar Match Source Code
This contract matches the deployed Bytecode of the Source Code for Contract 0xFF233166...3Ea73bc9c
The constructor portion of the code might be different and could alter the actual behaviour of the contract

Contract Name:
WithdrawManager

Compiler Version
v0.5.17+commit.d19bba13

Optimization Enabled:
Yes with 200 runs

Other Settings:
istanbul EvmVersion
File 1 of 43 : WithdrawManager.sol
pragma solidity ^0.5.2;

import {ERC20} from "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol";
import {ERC721} from "openzeppelin-solidity/contracts/token/ERC721/ERC721.sol";
import {Math} from "openzeppelin-solidity/contracts/math/Math.sol";

import {Merkle} from "../../common/lib/Merkle.sol";
import {MerklePatriciaProof} from "../../common/lib/MerklePatriciaProof.sol";
import {PriorityQueue} from "../../common/lib/PriorityQueue.sol";
import {ExitPayloadReader} from "../../common/lib/ExitPayloadReader.sol";

import {ExitNFT} from "./ExitNFT.sol";
import {DepositManager} from "../depositManager/DepositManager.sol";
import {IPredicate} from "../predicates/IPredicate.sol";
import {IWithdrawManager} from "./IWithdrawManager.sol";
import {RootChainHeader} from "../RootChainStorage.sol";
import {Registry} from "../../common/Registry.sol";
import {WithdrawManagerStorage} from "./WithdrawManagerStorage.sol";


contract WithdrawManager is WithdrawManagerStorage, IWithdrawManager {
    using Merkle for bytes32;

    using ExitPayloadReader for bytes;
    using ExitPayloadReader for ExitPayloadReader.ExitPayload;
    using ExitPayloadReader for ExitPayloadReader.Receipt;
    using ExitPayloadReader for ExitPayloadReader.Log;
    using ExitPayloadReader for ExitPayloadReader.LogTopics;

    modifier isBondProvided() {
        require(msg.value == BOND_AMOUNT, "Invalid Bond amount");
        _;
    }

    modifier isPredicateAuthorized() {
        require(registry.predicates(msg.sender) != Registry.Type.Invalid, "PREDICATE_NOT_AUTHORIZED");
        _;
    }

    modifier checkPredicateAndTokenMapping(address rootToken) {
        Registry.Type _type = registry.predicates(msg.sender);
        require(registry.rootToChildToken(rootToken) != address(0x0), "rootToken not supported");
        if (_type == Registry.Type.ERC20) {
            require(registry.isERC721(rootToken) == false, "Predicate supports only ERC20 tokens");
        } else if (_type == Registry.Type.ERC721) {
            require(registry.isERC721(rootToken) == true, "Predicate supports only ERC721 tokens");
        } else if (_type == Registry.Type.Custom) {} else {
            revert("PREDICATE_NOT_AUTHORIZED");
        }
        _;
    }

    /**
     * @dev Receive bond for bonded exits
     */
    function() external payable {}

    function createExitQueue(address token) external {
        require(msg.sender == address(registry), "UNAUTHORIZED_REGISTRY_ONLY");
        exitsQueues[token] = address(new PriorityQueue());
    }

    /**
     During coverage tests verifyInclusion fails co compile with "stack too deep" error.
     */
    struct VerifyInclusionVars {
        uint256 headerNumber;
        uint256 blockNumber;
        uint256 createdAt;
        uint256 branchMask;
        bytes32 txRoot;
        bytes32 receiptRoot;
        bytes branchMaskBytes;
    }

    /**
     * @dev Verify the inclusion of the receipt in the checkpoint
     * @param data RLP encoded data of the reference tx(s) that encodes the following fields for each tx
     * headerNumber Header block number of which the reference tx was a part of
     * blockProof Proof that the block header (in the child chain) is a leaf in the submitted merkle root
     * blockNumber Block number of which the reference tx is a part of
     * blockTime Reference tx block time
     * blocktxRoot Transactions root of block
     * blockReceiptsRoot Receipts root of block
     * receipt Receipt of the reference transaction
     * receiptProof Merkle proof of the reference receipt
     * branchMask Merkle proof branchMask for the receipt
     * logIndex Log Index to read from the receipt
     * @param offset offset in the data array
     * @param verifyTxInclusion Whether to also verify the inclusion of the raw tx in the txRoot
     * @return ageOfInput Measure of the position of the receipt and the log in the child chain
     */
    function verifyInclusion(
        bytes calldata data,
        uint8 offset,
        bool verifyTxInclusion
    )
        external
        view
        returns (
            uint256 /* ageOfInput */
        )
    {
        ExitPayloadReader.ExitPayload memory payload = data.toExitPayload();
        VerifyInclusionVars memory vars;

        vars.headerNumber = payload.getHeaderNumber();
        vars.branchMaskBytes = payload.getBranchMaskAsBytes();
        require(vars.branchMaskBytes[0] == 0, "incorrect mask");
        vars.txRoot = payload.getTxRoot();
        vars.receiptRoot = payload.getReceiptRoot();
        require(
            MerklePatriciaProof.verify(
                payload.getReceipt().toBytes(),
                vars.branchMaskBytes,
                payload.getReceiptProof(),
                vars.receiptRoot
            ),
            "INVALID_RECEIPT_MERKLE_PROOF"
        );

        if (verifyTxInclusion) {
            require(
                MerklePatriciaProof.verify(
                    payload.getTx(),
                    vars.branchMaskBytes,
                    payload.getTxProof(), 
                    vars.txRoot
                ),
                "INVALID_TX_MERKLE_PROOF"
            );
        }

        vars.blockNumber = payload.getBlockNumber();
        vars.createdAt = checkBlockMembershipInCheckpoint(
            vars.blockNumber,
            payload.getBlockTime(),
            vars.txRoot,
            vars.receiptRoot,
            vars.headerNumber,
            payload.getBlockProof()
        );

        vars.branchMask = payload.getBranchMaskAsUint();
        require(
            vars.branchMask & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000 == 0,
            "Branch mask should be 32 bits"
        );
        // ageOfInput is denoted as
        // 1 reserve bit (see last 2 lines in comment)
        // 128 bits for exitableAt timestamp
        // 95 bits for child block number
        // 32 bits for receiptPos + logIndex * MAX_LOGS + oIndex
        // In predicates, the exitId will be evaluated by shifting the ageOfInput left by 1 bit
        // (Only in erc20Predicate) Last bit is to differentiate whether the sender or receiver of the in-flight tx is starting an exit
        return (getExitableAt(vars.createdAt) << 127) | (vars.blockNumber << 32) | vars.branchMask;
    }

    function startExitWithDepositedTokens(
        uint256 depositId,
        address token,
        uint256 amountOrToken
    ) external payable isBondProvided {
        // (bytes32 depositHash, uint256 createdAt) = getDepositManager().deposits(depositId);
        // require(keccak256(abi.encodePacked(msg.sender, token, amountOrToken)) == depositHash, "UNAUTHORIZED_EXIT");
        // uint256 ageOfInput = getExitableAt(createdAt) << 127 | (depositId % 10000 /* MAX_DEPOSITS */);
        // uint256 exitId = ageOfInput << 1;
        // address predicate = registry.isTokenMappedAndGetPredicate(token);
        // _addExitToQueue(
        //     msg.sender,
        //     token,
        //     amountOrToken,
        //     bytes32(0), /* txHash */
        //     false, /* isRegularExit */
        //     exitId,
        //     predicate
        // );
        // _addInput(
        //     exitId,
        //     ageOfInput,
        //     msg.sender, /* utxoOwner */
        //     predicate,
        //     token
        // );
    }

    function addExitToQueue(
        address exitor,
        address childToken,
        address rootToken,
        uint256 exitAmountOrTokenId,
        bytes32 txHash,
        bool isRegularExit,
        uint256 priority
    ) external checkPredicateAndTokenMapping(rootToken) {
        require(registry.rootToChildToken(rootToken) == childToken, "INVALID_ROOT_TO_CHILD_TOKEN_MAPPING");
        _addExitToQueue(exitor, rootToken, exitAmountOrTokenId, txHash, isRegularExit, priority, msg.sender);
    }

    function challengeExit(
        uint256 exitId,
        uint256 inputId,
        bytes calldata challengeData,
        address adjudicatorPredicate
    ) external {
        PlasmaExit storage exit = exits[exitId];
        Input storage input = exit.inputs[inputId];
        require(exit.owner != address(0x0) && input.utxoOwner != address(0x0), "Invalid exit or input id");
        require(registry.predicates(adjudicatorPredicate) != Registry.Type.Invalid, "INVALID_PREDICATE");
        require(
            IPredicate(adjudicatorPredicate).verifyDeprecation(
                encodeExit(exit),
                encodeInputUtxo(inputId, input),
                challengeData
            ),
            "Challenge failed"
        );
        // In the call to burn(exitId), there is an implicit check that prevents challenging the same exit twice
        ExitNFT(exitNft).burn(exitId);

        // Send bond amount to challenger
        msg.sender.send(BOND_AMOUNT);

        // delete exits[exitId];
        emit ExitCancelled(exitId);
    }

    function processExits(address _token) public {
        uint256 exitableAt;
        uint256 exitId;

        PriorityQueue exitQueue = PriorityQueue(exitsQueues[_token]);

        while (exitQueue.currentSize() > 0 && gasleft() > ON_FINALIZE_GAS_LIMIT) {
            (exitableAt, exitId) = exitQueue.getMin();
            exitId = (exitableAt << 128) | exitId;
            PlasmaExit memory currentExit = exits[exitId];

            // Stop processing exits if the exit that is next is queue is still in its challenge period
            if (exitableAt > block.timestamp) return;

            exitQueue.delMin();
            // If the exitNft was deleted as a result of a challenge, skip processing this exit
            if (!exitNft.exists(exitId)) continue;
            address exitor = exitNft.ownerOf(exitId);
            exits[exitId].owner = exitor;
            exitNft.burn(exitId);
            // If finalizing a particular exit is reverting, it will block any following exits from being processed.
            // Hence, call predicate.onFinalizeExit in a revertless manner.
            // (bool success, bytes memory result) =
            currentExit.predicate.call(
                abi.encodeWithSignature("onFinalizeExit(bytes)", encodeExitForProcessExit(exitId))
            );

            emit Withdraw(exitId, exitor, _token, currentExit.receiptAmountOrNFTId);

            if (!currentExit.isRegularExit) {
                // return the bond amount if this was a MoreVp style exit
                address(uint160(exitor)).send(BOND_AMOUNT);
            }
        }
    }

    function processExitsBatch(address[] calldata _tokens) external {
        for (uint256 i = 0; i < _tokens.length; i++) {
            processExits(_tokens[i]);
        }
    }

    /**
     * @dev Add a state update (UTXO style input) to an exit
     * @param exitId Exit ID
     * @param age age of the UTXO style input
     * @param utxoOwner User for whom the input acts as a proof-of-funds
     * (alternate expression) User who could have potentially spent this UTXO
     * @param token Token (Think of it like Utxo color)
     */
    function addInput(
        uint256 exitId,
        uint256 age,
        address utxoOwner,
        address token
    ) external isPredicateAuthorized {
        PlasmaExit storage exitObject = exits[exitId];
        require(exitObject.owner != address(0x0), "INVALID_EXIT_ID");
        _addInput(
            exitId,
            age,
            utxoOwner,
            /* predicate */
            msg.sender,
            token
        );
    }

    function _addInput(
        uint256 exitId,
        uint256 age,
        address utxoOwner,
        address predicate,
        address token
    ) internal {
        exits[exitId].inputs[age] = Input(utxoOwner, predicate, token);
        emit ExitUpdated(exitId, age, utxoOwner);
    }

    function encodeExit(PlasmaExit storage exit) internal view returns (bytes memory) {
        return
            abi.encode(
                exit.owner,
                registry.rootToChildToken(exit.token),
                exit.receiptAmountOrNFTId,
                exit.txHash,
                exit.isRegularExit
            );
    }

    function encodeExitForProcessExit(uint256 exitId) internal view returns (bytes memory) {
        PlasmaExit storage exit = exits[exitId];
        return abi.encode(exitId, exit.token, exit.owner, exit.receiptAmountOrNFTId);
    }

    function encodeInputUtxo(uint256 age, Input storage input) internal view returns (bytes memory) {
        return abi.encode(age, input.utxoOwner, input.predicate, registry.rootToChildToken(input.token));
    }

    function _addExitToQueue(
        address exitor,
        address rootToken,
        uint256 exitAmountOrTokenId,
        bytes32 txHash,
        bool isRegularExit,
        uint256 exitId,
        address predicate
    ) internal {
        require(exits[exitId].token == address(0x0), "EXIT_ALREADY_EXISTS");
        exits[exitId] = PlasmaExit(
            exitAmountOrTokenId,
            txHash,
            exitor,
            rootToken,
            isRegularExit,
            predicate
        );
        PlasmaExit storage _exitObject = exits[exitId];

        bytes32 key = getKey(_exitObject.token, _exitObject.owner, _exitObject.receiptAmountOrNFTId);

        if (isRegularExit) {
            require(!isKnownExit[uint128(exitId)], "KNOWN_EXIT");
            isKnownExit[uint128(exitId)] = true;
        } else {
            // a user cannot start 2 MoreVP exits for the same erc20 token or nft
            require(ownerExits[key] == 0, "EXIT_ALREADY_IN_PROGRESS");
            ownerExits[key] = exitId;
        }

        PriorityQueue queue = PriorityQueue(exitsQueues[_exitObject.token]);

        // Way priority queue is implemented is such that it expects 2 uint256 params with most significant 128 bits masked out
        // This is a workaround to split exitId, which otherwise is conclusive in itself
        // exitId >> 128 gives 128 most significant bits
        // uint256(uint128(exitId)) gives 128 least significant bits
        // @todo Fix this mess
        queue.insert(exitId >> 128, uint256(uint128(exitId)));

        // create exit nft
        exitNft.mint(_exitObject.owner, exitId);
        emit ExitStarted(exitor, exitId, rootToken, exitAmountOrTokenId, isRegularExit);
    }

    function checkBlockMembershipInCheckpoint(
        uint256 blockNumber,
        uint256 blockTime,
        bytes32 txRoot,
        bytes32 receiptRoot,
        uint256 headerNumber,
        bytes memory blockProof
    )
        internal
        view
        returns (
            uint256 /* createdAt */
        )
    {
        (bytes32 headerRoot, uint256 startBlock, , uint256 createdAt, ) = rootChain.headerBlocks(headerNumber);
        require(
            keccak256(abi.encodePacked(blockNumber, blockTime, txRoot, receiptRoot)).checkMembership(
                blockNumber - startBlock,
                headerRoot,
                blockProof
            ),
            "WITHDRAW_BLOCK_NOT_A_PART_OF_SUBMITTED_HEADER"
        );
        return createdAt;
    }

    function getKey(
        address token,
        address exitor,
        uint256 amountOrToken
    ) internal view returns (bytes32 key) {
        if (registry.isERC721(token)) {
            key = keccak256(abi.encodePacked(token, exitor, amountOrToken));
        } else {
            // validate amount
            require(amountOrToken > 0, "CANNOT_EXIT_ZERO_AMOUNTS");
            key = keccak256(abi.encodePacked(token, exitor));
        }
    }

    function getDepositManager() internal view returns (DepositManager) {
        return DepositManager(address(uint160(registry.getDepositManagerAddress())));
    }

    function getExitableAt(uint256 createdAt) internal view returns (uint256) {
        return Math.max(createdAt + 2 * HALF_EXIT_PERIOD, now + HALF_EXIT_PERIOD);
    }

    // Housekeeping function. @todo remove later
    function updateExitPeriod(uint256 halfExitPeriod) public onlyOwner {
        emit ExitPeriodUpdate(HALF_EXIT_PERIOD, halfExitPeriod);
        HALF_EXIT_PERIOD = halfExitPeriod;
    }
}

File 2 of 43 : ERC20.sol
pragma solidity ^0.5.2;

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

/**
 * @title Standard ERC20 token
 *
 * @dev Implementation of the basic standard token.
 * https://eips.ethereum.org/EIPS/eip-20
 * Originally based on code by FirstBlood:
 * https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
 *
 * This implementation emits additional Approval events, allowing applications to reconstruct the allowance status for
 * all accounts just by listening to said events. Note that this isn't required by the specification, and other
 * compliant implementations may not do it.
 */
contract ERC20 is IERC20 {
    using SafeMath for uint256;

    mapping (address => uint256) private _balances;

    mapping (address => mapping (address => uint256)) private _allowed;

    uint256 private _totalSupply;

    /**
     * @dev Total number of tokens in existence
     */
    function totalSupply() public view returns (uint256) {
        return _totalSupply;
    }

    /**
     * @dev Gets the balance of the specified address.
     * @param owner The address to query the balance of.
     * @return A uint256 representing the amount owned by the passed address.
     */
    function balanceOf(address owner) public view returns (uint256) {
        return _balances[owner];
    }

    /**
     * @dev Function to check the amount of tokens that an owner allowed to a spender.
     * @param owner address The address which owns the funds.
     * @param spender address The address which will spend the funds.
     * @return A uint256 specifying the amount of tokens still available for the spender.
     */
    function allowance(address owner, address spender) public view returns (uint256) {
        return _allowed[owner][spender];
    }

    /**
     * @dev Transfer token to a specified address
     * @param to The address to transfer to.
     * @param value The amount to be transferred.
     */
    function transfer(address to, uint256 value) public returns (bool) {
        _transfer(msg.sender, to, value);
        return true;
    }

    /**
     * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
     * 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
     * @param spender The address which will spend the funds.
     * @param value The amount of tokens to be spent.
     */
    function approve(address spender, uint256 value) public returns (bool) {
        _approve(msg.sender, spender, value);
        return true;
    }

    /**
     * @dev Transfer tokens from one address to another.
     * Note that while this function emits an Approval event, this is not required as per the specification,
     * and other compliant implementations may not emit the event.
     * @param from address The address which you want to send tokens from
     * @param to address The address which you want to transfer to
     * @param value uint256 the amount of tokens to be transferred
     */
    function transferFrom(address from, address to, uint256 value) public returns (bool) {
        _transfer(from, to, value);
        _approve(from, msg.sender, _allowed[from][msg.sender].sub(value));
        return true;
    }

    /**
     * @dev Increase the amount of tokens that an owner allowed to a spender.
     * approve should be called when _allowed[msg.sender][spender] == 0. To increment
     * allowed value is better to use this function to avoid 2 calls (and wait until
     * the first transaction is mined)
     * From MonolithDAO Token.sol
     * Emits an Approval event.
     * @param spender The address which will spend the funds.
     * @param addedValue The amount of tokens to increase the allowance by.
     */
    function increaseAllowance(address spender, uint256 addedValue) public returns (bool) {
        _approve(msg.sender, spender, _allowed[msg.sender][spender].add(addedValue));
        return true;
    }

    /**
     * @dev Decrease the amount of tokens that an owner allowed to a spender.
     * approve should be called when _allowed[msg.sender][spender] == 0. To decrement
     * allowed value is better to use this function to avoid 2 calls (and wait until
     * the first transaction is mined)
     * From MonolithDAO Token.sol
     * Emits an Approval event.
     * @param spender The address which will spend the funds.
     * @param subtractedValue The amount of tokens to decrease the allowance by.
     */
    function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) {
        _approve(msg.sender, spender, _allowed[msg.sender][spender].sub(subtractedValue));
        return true;
    }

    /**
     * @dev Transfer token for a specified addresses
     * @param from The address to transfer from.
     * @param to The address to transfer to.
     * @param value The amount to be transferred.
     */
    function _transfer(address from, address to, uint256 value) internal {
        require(to != address(0));

        _balances[from] = _balances[from].sub(value);
        _balances[to] = _balances[to].add(value);
        emit Transfer(from, to, value);
    }

    /**
     * @dev Internal function that mints an amount of the token and assigns it to
     * an account. This encapsulates the modification of balances such that the
     * proper events are emitted.
     * @param account The account that will receive the created tokens.
     * @param value The amount that will be created.
     */
    function _mint(address account, uint256 value) internal {
        require(account != address(0));

        _totalSupply = _totalSupply.add(value);
        _balances[account] = _balances[account].add(value);
        emit Transfer(address(0), account, value);
    }

    /**
     * @dev Internal function that burns an amount of the token of a given
     * account.
     * @param account The account whose tokens will be burnt.
     * @param value The amount that will be burnt.
     */
    function _burn(address account, uint256 value) internal {
        require(account != address(0));

        _totalSupply = _totalSupply.sub(value);
        _balances[account] = _balances[account].sub(value);
        emit Transfer(account, address(0), value);
    }

    /**
     * @dev Approve an address to spend another addresses' tokens.
     * @param owner The address that owns the tokens.
     * @param spender The address that will spend the tokens.
     * @param value The number of tokens that can be spent.
     */
    function _approve(address owner, address spender, uint256 value) internal {
        require(spender != address(0));
        require(owner != address(0));

        _allowed[owner][spender] = value;
        emit Approval(owner, spender, value);
    }

    /**
     * @dev Internal function that burns an amount of the token of a given
     * account, deducting from the sender's allowance for said account. Uses the
     * internal burn function.
     * Emits an Approval event (reflecting the reduced allowance).
     * @param account The account whose tokens will be burnt.
     * @param value The amount that will be burnt.
     */
    function _burnFrom(address account, uint256 value) internal {
        _burn(account, value);
        _approve(account, msg.sender, _allowed[account][msg.sender].sub(value));
    }
}

File 3 of 43 : ERC721.sol
pragma solidity ^0.5.2;

import "./IERC721.sol";
import "./IERC721Receiver.sol";
import "../../math/SafeMath.sol";
import "../../utils/Address.sol";
import "../../drafts/Counters.sol";
import "../../introspection/ERC165.sol";

/**
 * @title ERC721 Non-Fungible Token Standard basic implementation
 * @dev see https://eips.ethereum.org/EIPS/eip-721
 */
contract ERC721 is ERC165, IERC721 {
    using SafeMath for uint256;
    using Address for address;
    using Counters for Counters.Counter;

    // Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
    // which can be also obtained as `IERC721Receiver(0).onERC721Received.selector`
    bytes4 private constant _ERC721_RECEIVED = 0x150b7a02;

    // Mapping from token ID to owner
    mapping (uint256 => address) private _tokenOwner;

    // Mapping from token ID to approved address
    mapping (uint256 => address) private _tokenApprovals;

    // Mapping from owner to number of owned token
    mapping (address => Counters.Counter) private _ownedTokensCount;

    // Mapping from owner to operator approvals
    mapping (address => mapping (address => bool)) private _operatorApprovals;

    bytes4 private constant _INTERFACE_ID_ERC721 = 0x80ac58cd;
    /*
     * 0x80ac58cd ===
     *     bytes4(keccak256('balanceOf(address)')) ^
     *     bytes4(keccak256('ownerOf(uint256)')) ^
     *     bytes4(keccak256('approve(address,uint256)')) ^
     *     bytes4(keccak256('getApproved(uint256)')) ^
     *     bytes4(keccak256('setApprovalForAll(address,bool)')) ^
     *     bytes4(keccak256('isApprovedForAll(address,address)')) ^
     *     bytes4(keccak256('transferFrom(address,address,uint256)')) ^
     *     bytes4(keccak256('safeTransferFrom(address,address,uint256)')) ^
     *     bytes4(keccak256('safeTransferFrom(address,address,uint256,bytes)'))
     */

    constructor () public {
        // register the supported interfaces to conform to ERC721 via ERC165
        _registerInterface(_INTERFACE_ID_ERC721);
    }

    /**
     * @dev Gets the balance of the specified address
     * @param owner address to query the balance of
     * @return uint256 representing the amount owned by the passed address
     */
    function balanceOf(address owner) public view returns (uint256) {
        require(owner != address(0));
        return _ownedTokensCount[owner].current();
    }

    /**
     * @dev Gets the owner of the specified token ID
     * @param tokenId uint256 ID of the token to query the owner of
     * @return address currently marked as the owner of the given token ID
     */
    function ownerOf(uint256 tokenId) public view returns (address) {
        address owner = _tokenOwner[tokenId];
        require(owner != address(0));
        return owner;
    }

    /**
     * @dev Approves another address to transfer the given token ID
     * The zero address indicates there is no approved address.
     * There can only be one approved address per token at a given time.
     * Can only be called by the token owner or an approved operator.
     * @param to address to be approved for the given token ID
     * @param tokenId uint256 ID of the token to be approved
     */
    function approve(address to, uint256 tokenId) public {
        address owner = ownerOf(tokenId);
        require(to != owner);
        require(msg.sender == owner || isApprovedForAll(owner, msg.sender));

        _tokenApprovals[tokenId] = to;
        emit Approval(owner, to, tokenId);
    }

    /**
     * @dev Gets the approved address for a token ID, or zero if no address set
     * Reverts if the token ID does not exist.
     * @param tokenId uint256 ID of the token to query the approval of
     * @return address currently approved for the given token ID
     */
    function getApproved(uint256 tokenId) public view returns (address) {
        require(_exists(tokenId));
        return _tokenApprovals[tokenId];
    }

    /**
     * @dev Sets or unsets the approval of a given operator
     * An operator is allowed to transfer all tokens of the sender on their behalf
     * @param to operator address to set the approval
     * @param approved representing the status of the approval to be set
     */
    function setApprovalForAll(address to, bool approved) public {
        require(to != msg.sender);
        _operatorApprovals[msg.sender][to] = approved;
        emit ApprovalForAll(msg.sender, to, approved);
    }

    /**
     * @dev Tells whether an operator is approved by a given owner
     * @param owner owner address which you want to query the approval of
     * @param operator operator address which you want to query the approval of
     * @return bool whether the given operator is approved by the given owner
     */
    function isApprovedForAll(address owner, address operator) public view returns (bool) {
        return _operatorApprovals[owner][operator];
    }

    /**
     * @dev Transfers the ownership of a given token ID to another address
     * Usage of this method is discouraged, use `safeTransferFrom` whenever possible
     * Requires the msg.sender to be the owner, approved, or operator
     * @param from current owner of the token
     * @param to address to receive the ownership of the given token ID
     * @param tokenId uint256 ID of the token to be transferred
     */
    function transferFrom(address from, address to, uint256 tokenId) public {
        require(_isApprovedOrOwner(msg.sender, tokenId));

        _transferFrom(from, to, tokenId);
    }

    /**
     * @dev Safely transfers the ownership of a given token ID to another address
     * If the target address is a contract, it must implement `onERC721Received`,
     * which is called upon a safe transfer, and return the magic value
     * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise,
     * the transfer is reverted.
     * Requires the msg.sender to be the owner, approved, or operator
     * @param from current owner of the token
     * @param to address to receive the ownership of the given token ID
     * @param tokenId uint256 ID of the token to be transferred
     */
    function safeTransferFrom(address from, address to, uint256 tokenId) public {
        safeTransferFrom(from, to, tokenId, "");
    }

    /**
     * @dev Safely transfers the ownership of a given token ID to another address
     * If the target address is a contract, it must implement `onERC721Received`,
     * which is called upon a safe transfer, and return the magic value
     * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise,
     * the transfer is reverted.
     * Requires the msg.sender to be the owner, approved, or operator
     * @param from current owner of the token
     * @param to address to receive the ownership of the given token ID
     * @param tokenId uint256 ID of the token to be transferred
     * @param _data bytes data to send along with a safe transfer check
     */
    function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) public {
        transferFrom(from, to, tokenId);
        require(_checkOnERC721Received(from, to, tokenId, _data));
    }

    /**
     * @dev Returns whether the specified token exists
     * @param tokenId uint256 ID of the token to query the existence of
     * @return bool whether the token exists
     */
    function _exists(uint256 tokenId) internal view returns (bool) {
        address owner = _tokenOwner[tokenId];
        return owner != address(0);
    }

    /**
     * @dev Returns whether the given spender can transfer a given token ID
     * @param spender address of the spender to query
     * @param tokenId uint256 ID of the token to be transferred
     * @return bool whether the msg.sender is approved for the given token ID,
     * is an operator of the owner, or is the owner of the token
     */
    function _isApprovedOrOwner(address spender, uint256 tokenId) internal view returns (bool) {
        address owner = ownerOf(tokenId);
        return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender));
    }

    /**
     * @dev Internal function to mint a new token
     * Reverts if the given token ID already exists
     * @param to The address that will own the minted token
     * @param tokenId uint256 ID of the token to be minted
     */
    function _mint(address to, uint256 tokenId) internal {
        require(to != address(0));
        require(!_exists(tokenId));

        _tokenOwner[tokenId] = to;
        _ownedTokensCount[to].increment();

        emit Transfer(address(0), to, tokenId);
    }

    /**
     * @dev Internal function to burn a specific token
     * Reverts if the token does not exist
     * Deprecated, use _burn(uint256) instead.
     * @param owner owner of the token to burn
     * @param tokenId uint256 ID of the token being burned
     */
    function _burn(address owner, uint256 tokenId) internal {
        require(ownerOf(tokenId) == owner);

        _clearApproval(tokenId);

        _ownedTokensCount[owner].decrement();
        _tokenOwner[tokenId] = address(0);

        emit Transfer(owner, address(0), tokenId);
    }

    /**
     * @dev Internal function to burn a specific token
     * Reverts if the token does not exist
     * @param tokenId uint256 ID of the token being burned
     */
    function _burn(uint256 tokenId) internal {
        _burn(ownerOf(tokenId), tokenId);
    }

    /**
     * @dev Internal function to transfer ownership of a given token ID to another address.
     * As opposed to transferFrom, this imposes no restrictions on msg.sender.
     * @param from current owner of the token
     * @param to address to receive the ownership of the given token ID
     * @param tokenId uint256 ID of the token to be transferred
     */
    function _transferFrom(address from, address to, uint256 tokenId) internal {
        require(ownerOf(tokenId) == from);
        require(to != address(0));

        _clearApproval(tokenId);

        _ownedTokensCount[from].decrement();
        _ownedTokensCount[to].increment();

        _tokenOwner[tokenId] = to;

        emit Transfer(from, to, tokenId);
    }

    /**
     * @dev Internal function to invoke `onERC721Received` on a target address
     * The call is not executed if the target address is not a contract
     * @param from address representing the previous owner of the given token ID
     * @param to target address that will receive the tokens
     * @param tokenId uint256 ID of the token to be transferred
     * @param _data bytes optional data to send along with the call
     * @return bool whether the call correctly returned the expected magic value
     */
    function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory _data)
        internal returns (bool)
    {
        if (!to.isContract()) {
            return true;
        }

        bytes4 retval = IERC721Receiver(to).onERC721Received(msg.sender, from, tokenId, _data);
        return (retval == _ERC721_RECEIVED);
    }

    /**
     * @dev Private function to clear current approval of a given token ID
     * @param tokenId uint256 ID of the token to be transferred
     */
    function _clearApproval(uint256 tokenId) private {
        if (_tokenApprovals[tokenId] != address(0)) {
            _tokenApprovals[tokenId] = address(0);
        }
    }
}

File 4 of 43 : Math.sol
pragma solidity ^0.5.2;

/**
 * @title Math
 * @dev Assorted math operations
 */
library Math {
    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a >= b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Calculates the average of two numbers. Since these are integers,
     * averages of an even and odd number cannot be represented, and will be
     * rounded down.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow, so we distribute
        return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2);
    }
}

File 5 of 43 : Merkle.sol
pragma solidity ^0.5.2;

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 6 of 43 : MerklePatriciaProof.sol
/*
 * @title MerklePatriciaVerifier
 * @author Sam Mayo ([email protected])
 *
 * @dev Library for verifing merkle patricia proofs.
 */
pragma solidity ^0.5.2;

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) {
                bytes memory nodeValue = RLPReader.toBytes(currentNodeList[0]);
                uint256 traversed = _nibblesToTraverse(
                    nodeValue,
                    path,
                    pathPtr
                );
                //enforce correct nibble
                bytes1 prefix = _getNthNibbleOfBytes(0, nodeValue);
                if (pathPtr + traversed == path.length) {
                    //leaf node
                    if (
                        keccak256(RLPReader.toBytes(currentNodeList[1])) == keccak256(value) && 
                        (prefix == bytes1(uint8(2)) || prefix == bytes1(uint8(3)))
                    ) {
                        return true;
                    } else {
                        return false;
                    }
                }
                //extension node
                if (traversed == 0 || (prefix != bytes1(uint8(0)) && prefix != bytes1(uint8(1)))) {
                    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;
        // 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)
        private
        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 43 : PriorityQueue.sol
pragma solidity ^0.5.2;

import "openzeppelin-solidity/contracts/ownership/Ownable.sol";
import {SafeMath} from "openzeppelin-solidity/contracts/math/SafeMath.sol";

/**
 * @title PriorityQueue
 * @dev A priority queue implementation.
 */
contract PriorityQueue is Ownable {
    using SafeMath for uint256;

    uint256[] heapList;
    uint256 public currentSize;

    constructor() public {
        heapList = [0];
    }

    /**
  * @dev Inserts an element into the priority queue.
  * @param _priority Priority to insert.
  * @param _value Some additional value.
  */
    function insert(uint256 _priority, uint256 _value) public onlyOwner {
        uint256 element = (_priority << 128) | _value;
        heapList.push(element);
        currentSize = currentSize.add(1);
        _percUp(currentSize);
    }

    /**
  * @dev Returns the top element of the heap.
  * @return The smallest element in the priority queue.
  */
    function getMin() public view returns (uint256, uint256) {
        return _splitElement(heapList[1]);
    }

    /**
  * @dev Deletes the top element of the heap and shifts everything up.
  * @return The smallest element in the priorty queue.
  */
    function delMin() public onlyOwner returns (uint256, uint256) {
        uint256 retVal = heapList[1];
        heapList[1] = heapList[currentSize];
        delete heapList[currentSize];
        currentSize = currentSize.sub(1);
        _percDown(1);
        heapList.length = heapList.length.sub(1);
        return _splitElement(retVal);
    }

    /**
  * @dev Determines the minimum child of a given node in the tree.
  * @param _index Index of the node in the tree.
  * @return The smallest child node.
  */
    function _minChild(uint256 _index) private view returns (uint256) {
        if (_index.mul(2).add(1) > currentSize) {
            return _index.mul(2);
        } else {
            if (heapList[_index.mul(2)] < heapList[_index.mul(2).add(1)]) {
                return _index.mul(2);
            } else {
                return _index.mul(2).add(1);
            }
        }
    }

    /**
   * @dev Bubbles the element at some index up.
   */
    function _percUp(uint256 _index) private {
        uint256 index = _index;
        uint256 j = index;
        uint256 newVal = heapList[index];

        while (newVal < heapList[index.div(2)]) {
            heapList[index] = heapList[index.div(2)];
            index = index.div(2);
        }

        if (index != j) {
            heapList[index] = newVal;
        }
    }

    /**
   * @dev Bubbles the element at some index down.
   */
    function _percDown(uint256 _index) private {
        uint256 index = _index;
        uint256 j = index;
        uint256 newVal = heapList[index];
        uint256 mc = _minChild(index);
        while (mc <= currentSize && newVal > heapList[mc]) {
            heapList[index] = heapList[mc];
            index = mc;
            mc = _minChild(index);
        }

        if (index != j) {
            heapList[index] = newVal;
        }
    }

    /**
   * @dev Split an element into its priority and value.
   * @param _element Element to decode.
   * @return A tuple containing the priority and value.
   */
    function _splitElement(uint256 _element)
        private
        pure
        returns (uint256, uint256)
    {
        uint256 priority = _element >> 128;
        uint256 value = uint256(uint128(_element));
        return (priority, value);
    }
}

File 8 of 43 : ExitPayloadReader.sol
pragma solidity 0.5.17;

import {RLPReader} from "./RLPReader.sol";
import {BytesLib} from "./BytesLib.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;
  }

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

        return ExitPayload(payloadData);
    }

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

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

    function getTxProof(ExitPayload memory payload) internal pure returns(bytes memory) {
      return payload.data[11].toBytes();
    }
    
    // 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 9 of 43 : ExitNFT.sol
pragma solidity ^0.5.2;

import {ERC721} from "openzeppelin-solidity/contracts/token/ERC721/ERC721.sol";
import {Registry} from "../../common/Registry.sol";

contract ExitNFT is ERC721 {
    Registry internal registry;

    modifier onlyWithdrawManager() {
        require(
            msg.sender == registry.getWithdrawManagerAddress(),
            "UNAUTHORIZED_WITHDRAW_MANAGER_ONLY"
        );
        _;
    }

    constructor(address _registry) public {
        registry = Registry(_registry);
    }

    function mint(address _owner, uint256 _tokenId)
        external
        onlyWithdrawManager
    {
        _mint(_owner, _tokenId);
    }

    function burn(uint256 _tokenId) external onlyWithdrawManager {
        _burn(_tokenId);
    }

    function exists(uint256 tokenId) public view returns (bool) {
        return _exists(tokenId);
    }
}

File 10 of 43 : DepositManager.sol
pragma solidity ^0.5.2;

import {ERC721Holder} from "openzeppelin-solidity/contracts/token/ERC721/ERC721Holder.sol";
import {IERC20} from "openzeppelin-solidity/contracts/token/ERC20/IERC20.sol";
import {IERC721} from "openzeppelin-solidity/contracts/token/ERC721/IERC721.sol";
import {SafeMath} from "openzeppelin-solidity/contracts/math/SafeMath.sol";
import {SafeERC20} from "openzeppelin-solidity/contracts/token/ERC20/SafeERC20.sol";

import {Registry} from "../../common/Registry.sol";
import {WETH} from "../../common/tokens/WETH.sol";
import {IDepositManager} from "./IDepositManager.sol";
import {DepositManagerStorage} from "./DepositManagerStorage.sol";
import {StateSender} from "../stateSyncer/StateSender.sol";
import {GovernanceLockable} from "../../common/mixin/GovernanceLockable.sol";
import {RootChain} from "../RootChain.sol";

interface IPolygonMigration {
    function migrate(uint256 amount) external;
}


contract DepositManager is DepositManagerStorage, IDepositManager, ERC721Holder {
    using SafeMath for uint256;
    using SafeERC20 for IERC20;

    modifier isTokenMapped(address _token) {
        require(
            registry.isTokenMapped(_token),
            "TOKEN_NOT_SUPPORTED"
        );
        _;
    }

    modifier isPredicateAuthorized() {
        require(uint8(registry.predicates(msg.sender)) != 0, "Not a valid predicate");
        _;
    }

    constructor() public GovernanceLockable(address(0x0)) {}

    // deposit ETH by sending to this contract
    function() external payable {
        depositEther();
    }

    // new: governance function to migrate MATIC to POL
    function migrateMatic() external onlyGovernance {
        IERC20 matic = IERC20(registry.contractMap(keccak256("matic")));
        _migrateMatic(matic.balanceOf(address(this)));
    }

    function _migrateMatic(uint256 _amount) private {
        IERC20 matic = IERC20(registry.contractMap(keccak256("matic")));
        address polygonMigration = registry.contractMap(keccak256("polygonMigration"));

        // check that _amount is not too high
        require(matic.balanceOf(address(this)) >= _amount, "amount exceeds this contract's MATIC balance");

        // approve
        matic.approve(polygonMigration, _amount);

        // call migrate function
        IPolygonMigration(polygonMigration).migrate(_amount);
    }

    function updateMaxErc20Deposit(uint256 maxDepositAmount) public onlyGovernance {
        require(maxDepositAmount != 0);
        emit MaxErc20DepositUpdate(maxErc20Deposit, maxDepositAmount);
        maxErc20Deposit = maxDepositAmount;
    }

    function transferAssets(address _token, address _user, uint256 _amountOrNFTId) external isPredicateAuthorized {
        address wethToken = registry.getWethTokenAddress();

        if (registry.isERC721(_token)) {
            IERC721(_token).transferFrom(address(this), _user, _amountOrNFTId);
        } else if (_token == wethToken) {
            WETH t = WETH(_token);
            t.withdraw(_amountOrNFTId, _user);
        } else {
            // new: pay out POL when MATIC is withdrawn
            if (_token == registry.contractMap(keccak256("matic"))) {
                require(
                    IERC20(registry.contractMap(keccak256("pol"))).transfer(_user, _amountOrNFTId),
                    "TRANSFER_FAILED"
                );
            } else {
                require(IERC20(_token).transfer(_user, _amountOrNFTId), "TRANSFER_FAILED");
            }
        }
    }

    function depositERC20(address _token, uint256 _amount) external {
        depositERC20ForUser(_token, msg.sender, _amount);
    }

    function depositERC721(address _token, uint256 _tokenId) external {
        depositERC721ForUser(_token, msg.sender, _tokenId);
    }

    function depositBulk(
        address[] calldata _tokens,
        uint256[] calldata _amountOrTokens,
        address _user
    )
        external
        onlyWhenUnlocked // unlike other deposit functions, depositBulk doesn't invoke _safeCreateDepositBlock
    {
        require(_tokens.length == _amountOrTokens.length, "Invalid Input");
        uint256 depositId = rootChain.updateDepositId(_tokens.length);
        Registry _registry = registry;

        for (uint256 i = 0; i < _tokens.length; i++) {
            // will revert if token is not mapped
            if (_registry.isTokenMappedAndIsErc721(_tokens[i])) {
                _safeTransferERC721(msg.sender, _tokens[i], _amountOrTokens[i]);
            } else {
                IERC20(_tokens[i]).safeTransferFrom(msg.sender, address(this), _amountOrTokens[i]);
            }

            _createDepositBlock(_user, _tokens[i], _amountOrTokens[i], depositId);
            depositId = depositId.add(1);
        }
    }

    /**
     * @dev Caches childChain and stateSender (frequently used variables) from registry
     */
    function updateChildChainAndStateSender() public {
        (address _childChain, address _stateSender) = registry.getChildChainAndStateSender();
        require(
            _stateSender != address(stateSender) || _childChain != childChain,
            "Atleast one of stateSender or childChain address should change"
        );
        childChain = _childChain;
        stateSender = StateSender(_stateSender);
    }

    function depositERC20ForUser(address _token, address _user, uint256 _amount) public {
        require(_amount <= maxErc20Deposit, "exceed maximum deposit amount");
        IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount);

        _safeCreateDepositBlock(_user, _token, _amount);
    }

    function depositERC721ForUser(address _token, address _user, uint256 _tokenId) public {
        require(registry.isTokenMappedAndIsErc721(_token), "not erc721");

        _safeTransferERC721(msg.sender, _token, _tokenId);
        _safeCreateDepositBlock(_user, _token, _tokenId);
    }

    // @todo: write depositEtherForUser
    function depositEther() public payable {
        address wethToken = registry.getWethTokenAddress();
        WETH t = WETH(wethToken);
        t.deposit.value(msg.value)();
        _safeCreateDepositBlock(msg.sender, wethToken, msg.value);
    }

    function _safeCreateDepositBlock(
        address _user,
        address _token,
        uint256 _amountOrToken
    ) internal onlyWhenUnlocked isTokenMapped(_token) {
        _createDepositBlock(_user, _token, _amountOrToken, rootChain.updateDepositId(1)); // returns _depositId
    }

    function _createDepositBlock(address _user, address _token, uint256 _amountOrToken, uint256 _depositId) internal {
        address matic = registry.contractMap(keccak256("matic"));

        // new: auto-migrate MATIC to POL
        if (_token == matic) {
            _migrateMatic(_amountOrToken);
        }
        // new: bridge POL as MATIC, child chain behaviour does not change
        else if (_token == registry.contractMap(keccak256("pol"))) {
            _token = matic;
        }

        deposits[_depositId] = DepositBlock(keccak256(abi.encodePacked(_user, _token, _amountOrToken)), now);
        stateSender.syncState(childChain, abi.encode(_user, _token, _amountOrToken, _depositId));
        emit NewDepositBlock(_user, _token, _amountOrToken, _depositId);
    }

    // Housekeeping function. @todo remove later
    function updateRootChain(address _rootChain) public onlyOwner {
        rootChain = RootChain(_rootChain);
    }

    function _safeTransferERC721(address _user, address _token, uint256 _tokenId) private {
        IERC721(_token).safeTransferFrom(_user, address(this), _tokenId);
    }
}

File 11 of 43 : IPredicate.sol
pragma solidity ^0.5.2;

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

import {Common} from "../../common/lib/Common.sol";
import {RLPEncode} from "../../common/lib/RLPEncode.sol";

import {IWithdrawManager} from "../withdrawManager/IWithdrawManager.sol";
import {IDepositManager} from "../depositManager/IDepositManager.sol";
import {ExitsDataStructure} from "../withdrawManager/WithdrawManagerStorage.sol";
import {ChainIdMixin} from "../../common/mixin/ChainIdMixin.sol";

interface IPredicate {
    /**
   * @notice Verify the deprecation of a state update
   * @param exit ABI encoded PlasmaExit data
   * @param inputUtxo ABI encoded Input UTXO data
   * @param challengeData RLP encoded data of the challenge reference tx that encodes the following fields
   * headerNumber Header block number of which the reference tx was a part of
   * blockProof Proof that the block header (in the child chain) is a leaf in the submitted merkle root
   * blockNumber Block number of which the reference tx is a part of
   * blockTime Reference tx block time
   * blocktxRoot Transactions root of block
   * blockReceiptsRoot Receipts root of block
   * receipt Receipt of the reference transaction
   * receiptProof Merkle proof of the reference receipt
   * branchMask Merkle proof branchMask for the receipt
   * logIndex Log Index to read from the receipt
   * tx Challenge transaction
   * txProof Merkle proof of the challenge tx
   * @return Whether or not the state is deprecated
   */
    function verifyDeprecation(
        bytes calldata exit,
        bytes calldata inputUtxo,
        bytes calldata challengeData
    ) external returns (bool);

    function interpretStateUpdate(bytes calldata state)
        external
        view
        returns (bytes memory);
    function onFinalizeExit(bytes calldata data) external;
}

contract PredicateUtils is ExitsDataStructure, ChainIdMixin {
    using RLPReader for RLPReader.RLPItem;

    // Bonded exits collaterized at 0.1 ETH
    uint256 private constant BOND_AMOUNT = 10**17;

    IWithdrawManager internal withdrawManager;
    IDepositManager internal depositManager;

    modifier onlyWithdrawManager() {
        require(
            msg.sender == address(withdrawManager),
            "ONLY_WITHDRAW_MANAGER"
        );
        _;
    }

    modifier isBondProvided() {
        require(msg.value == BOND_AMOUNT, "Invalid Bond amount");
        _;
    }

    function onFinalizeExit(bytes calldata data) external onlyWithdrawManager {
        (, address token, address exitor, uint256 tokenId) = decodeExitForProcessExit(
            data
        );
        depositManager.transferAssets(token, exitor, tokenId);
    }

    function sendBond() internal {
        address(uint160(address(withdrawManager))).transfer(BOND_AMOUNT);
    }

    function getAddressFromTx(RLPReader.RLPItem[] memory txList)
        internal
        pure
        returns (address signer, bytes32 txHash)
    {
        bytes[] memory rawTx = new bytes[](9);
        for (uint8 i = 0; i <= 5; i++) {
            rawTx[i] = txList[i].toBytes();
        }
        rawTx[6] = networkId;
        rawTx[7] = hex""; // [7] and [8] have something to do with v, r, s values
        rawTx[8] = hex"";

        txHash = keccak256(RLPEncode.encodeList(rawTx));
        signer = ecrecover(
            txHash,
            Common.getV(txList[6].toBytes(), Common.toUint16(networkId)),
            bytes32(txList[7].toUint()),
            bytes32(txList[8].toUint())
        );
        require(signer != address(0), "Invalid signer");
    }

    function decodeExit(bytes memory data)
        internal
        pure
        returns (PlasmaExit memory)
    {
        (address owner, address token, uint256 amountOrTokenId, bytes32 txHash, bool isRegularExit) = abi
            .decode(data, (address, address, uint256, bytes32, bool));
        return
            PlasmaExit(
                amountOrTokenId,
                txHash,
                owner,
                token,
                isRegularExit,
                address(0) /* predicate value is not required */
            );
    }

    function decodeExitForProcessExit(bytes memory data)
        internal
        pure
        returns (uint256 exitId, address token, address exitor, uint256 tokenId)
    {
        (exitId, token, exitor, tokenId) = abi.decode(
            data,
            (uint256, address, address, uint256)
        );
    }

    function decodeInputUtxo(bytes memory data)
        internal
        pure
        returns (uint256 age, address signer, address predicate, address token)
    {
        (age, signer, predicate, token) = abi.decode(
            data,
            (uint256, address, address, address)
        );
    }

}

contract IErcPredicate is IPredicate, PredicateUtils {
    enum ExitType {Invalid, OutgoingTransfer, IncomingTransfer, Burnt}

    struct ExitTxData {
        uint256 amountOrToken;
        bytes32 txHash;
        address childToken;
        address signer;
        ExitType exitType;
    }

    struct ReferenceTxData {
        uint256 closingBalance;
        uint256 age;
        address childToken;
        address rootToken;
    }

    uint256 internal constant MAX_LOGS = 10;

    constructor(address _withdrawManager, address _depositManager) public {
        withdrawManager = IWithdrawManager(_withdrawManager);
        depositManager = IDepositManager(_depositManager);
    }
}

File 12 of 43 : IWithdrawManager.sol
pragma solidity ^0.5.2;

contract IWithdrawManager {
    function createExitQueue(address token) external;

    function verifyInclusion(
        bytes calldata data,
        uint8 offset,
        bool verifyTxInclusion
    ) external view returns (uint256 age);

    function addExitToQueue(
        address exitor,
        address childToken,
        address rootToken,
        uint256 exitAmountOrTokenId,
        bytes32 txHash,
        bool isRegularExit,
        uint256 priority
    ) external;

    function addInput(
        uint256 exitId,
        uint256 age,
        address utxoOwner,
        address token
    ) external;

    function challengeExit(
        uint256 exitId,
        uint256 inputId,
        bytes calldata challengeData,
        address adjudicatorPredicate
    ) external;
}

File 13 of 43 : RootChainStorage.sol
pragma solidity ^0.5.2;

import {Registry} from "../common/Registry.sol";
import {ProxyStorage} from "../common/misc/ProxyStorage.sol";
import {ChainIdMixin} from "../common/mixin/ChainIdMixin.sol";


contract RootChainHeader {
    event NewHeaderBlock(
        address indexed proposer,
        uint256 indexed headerBlockId,
        uint256 indexed reward,
        uint256 start,
        uint256 end,
        bytes32 root
    );
    // housekeeping event
    event ResetHeaderBlock(address indexed proposer, uint256 indexed headerBlockId);
    struct HeaderBlock {
        bytes32 root;
        uint256 start;
        uint256 end;
        uint256 createdAt;
        address proposer;
    }
}


contract RootChainStorage is ProxyStorage, RootChainHeader, ChainIdMixin {
    bytes32 public heimdallId;
    uint8 public constant VOTE_TYPE = 2;

    uint16 internal constant MAX_DEPOSITS = 10000;
    uint256 public _nextHeaderBlock = MAX_DEPOSITS;
    uint256 internal _blockDepositId = 1;
    mapping(uint256 => HeaderBlock) public headerBlocks;
    Registry internal registry;
}

File 14 of 43 : Registry.sol
pragma solidity ^0.5.2;

import {Governable} from "./governance/Governable.sol";
import {IWithdrawManager} from "../root/withdrawManager/IWithdrawManager.sol";


contract Registry is Governable {
    // @todo hardcode constants
    bytes32 private constant WETH_TOKEN = keccak256("wethToken");
    bytes32 private constant DEPOSIT_MANAGER = keccak256("depositManager");
    bytes32 private constant STAKE_MANAGER = keccak256("stakeManager");
    bytes32 private constant VALIDATOR_SHARE = keccak256("validatorShare");
    bytes32 private constant WITHDRAW_MANAGER = keccak256("withdrawManager");
    bytes32 private constant CHILD_CHAIN = keccak256("childChain");
    bytes32 private constant STATE_SENDER = keccak256("stateSender");
    bytes32 private constant SLASHING_MANAGER = keccak256("slashingManager");

    address public erc20Predicate;
    address public erc721Predicate;

    mapping(bytes32 => address) public contractMap;
    mapping(address => address) public rootToChildToken;
    mapping(address => address) public childToRootToken;
    mapping(address => bool) public proofValidatorContracts;
    mapping(address => bool) public isERC721;

    enum Type {Invalid, ERC20, ERC721, Custom}
    struct Predicate {
        Type _type;
    }
    mapping(address => Predicate) public predicates;

    event TokenMapped(address indexed rootToken, address indexed childToken);
    event ProofValidatorAdded(address indexed validator, address indexed from);
    event ProofValidatorRemoved(address indexed validator, address indexed from);
    event PredicateAdded(address indexed predicate, address indexed from);
    event PredicateRemoved(address indexed predicate, address indexed from);
    event ContractMapUpdated(bytes32 indexed key, address indexed previousContract, address indexed newContract);

    constructor(address _governance) public Governable(_governance) {}

    function updateContractMap(bytes32 _key, address _address) external onlyGovernance {
        emit ContractMapUpdated(_key, contractMap[_key], _address);
        contractMap[_key] = _address;
    }

    /**
     * @dev Map root token to child token
     * @param _rootToken Token address on the root chain
     * @param _childToken Token address on the child chain
     * @param _isERC721 Is the token being mapped ERC721
     */
    function mapToken(
        address _rootToken,
        address _childToken,
        bool _isERC721
    ) external onlyGovernance {
        require(_rootToken != address(0x0) && _childToken != address(0x0), "INVALID_TOKEN_ADDRESS");
        rootToChildToken[_rootToken] = _childToken;
        childToRootToken[_childToken] = _rootToken;
        isERC721[_rootToken] = _isERC721;
        IWithdrawManager(contractMap[WITHDRAW_MANAGER]).createExitQueue(_rootToken);
        emit TokenMapped(_rootToken, _childToken);
    }

    function addErc20Predicate(address predicate) public onlyGovernance {
        require(predicate != address(0x0), "Can not add null address as predicate");
        erc20Predicate = predicate;
        addPredicate(predicate, Type.ERC20);
    }

    function addErc721Predicate(address predicate) public onlyGovernance {
        erc721Predicate = predicate;
        addPredicate(predicate, Type.ERC721);
    }

    function addPredicate(address predicate, Type _type) public onlyGovernance {
        require(predicates[predicate]._type == Type.Invalid, "Predicate already added");
        predicates[predicate]._type = _type;
        emit PredicateAdded(predicate, msg.sender);
    }

    function removePredicate(address predicate) public onlyGovernance {
        require(predicates[predicate]._type != Type.Invalid, "Predicate does not exist");
        delete predicates[predicate];
        emit PredicateRemoved(predicate, msg.sender);
    }

    function getValidatorShareAddress() public view returns (address) {
        return contractMap[VALIDATOR_SHARE];
    }

    function getWethTokenAddress() public view returns (address) {
        return contractMap[WETH_TOKEN];
    }

    function getDepositManagerAddress() public view returns (address) {
        return contractMap[DEPOSIT_MANAGER];
    }

    function getStakeManagerAddress() public view returns (address) {
        return contractMap[STAKE_MANAGER];
    }

    function getSlashingManagerAddress() public view returns (address) {
        return contractMap[SLASHING_MANAGER];
    }

    function getWithdrawManagerAddress() public view returns (address) {
        return contractMap[WITHDRAW_MANAGER];
    }

    function getChildChainAndStateSender() public view returns (address, address) {
        return (contractMap[CHILD_CHAIN], contractMap[STATE_SENDER]);
    }

    function isTokenMapped(address _token) public view returns (bool) {
        return rootToChildToken[_token] != address(0x0);
    }

    function isTokenMappedAndIsErc721(address _token) public view returns (bool) {
        require(isTokenMapped(_token), "TOKEN_NOT_MAPPED");
        return isERC721[_token];
    }

    function isTokenMappedAndGetPredicate(address _token) public view returns (address) {
        if (isTokenMappedAndIsErc721(_token)) {
            return erc721Predicate;
        }
        return erc20Predicate;
    }

    function isChildTokenErc721(address childToken) public view returns (bool) {
        address rootToken = childToRootToken[childToken];
        require(rootToken != address(0x0), "Child token is not mapped");
        return isERC721[rootToken];
    }
}

File 15 of 43 : WithdrawManagerStorage.sol
pragma solidity ^0.5.2;

import {ProxyStorage} from "../../common/misc/ProxyStorage.sol";
import {Registry} from "../../common/Registry.sol";
import {RootChain} from "../RootChain.sol";
import {ExitNFT} from "./ExitNFT.sol";


contract ExitsDataStructure {
    struct Input {
        address utxoOwner;
        address predicate;
        address token;
    }

    struct PlasmaExit {
        uint256 receiptAmountOrNFTId;
        bytes32 txHash;
        address owner;
        address token;
        bool isRegularExit;
        address predicate;
        // Mapping from age of input to Input
        mapping(uint256 => Input) inputs;
    }
}


contract WithdrawManagerHeader is ExitsDataStructure {
    event Withdraw(uint256 indexed exitId, address indexed user, address indexed token, uint256 amount);

    event ExitStarted(
        address indexed exitor,
        uint256 indexed exitId,
        address indexed token,
        uint256 amount,
        bool isRegularExit
    );

    event ExitUpdated(uint256 indexed exitId, uint256 indexed age, address signer);
    event ExitPeriodUpdate(uint256 indexed oldExitPeriod, uint256 indexed newExitPeriod);

    event ExitCancelled(uint256 indexed exitId);
}


contract WithdrawManagerStorage is ProxyStorage, WithdrawManagerHeader {
    // 0.5 week = 7 * 86400 / 2 = 302400
    uint256 public HALF_EXIT_PERIOD = 302400;

    // Bonded exits collaterized at 0.1 ETH
    uint256 internal constant BOND_AMOUNT = 10**17;

    Registry internal registry;
    RootChain internal rootChain;

    mapping(uint128 => bool) isKnownExit;
    mapping(uint256 => PlasmaExit) public exits;
    // mapping with token => (owner => exitId) keccak(token+owner) keccak(token+owner+tokenId)
    mapping(bytes32 => uint256) public ownerExits;
    mapping(address => address) public exitsQueues;
    ExitNFT public exitNft;

    // ERC721, ERC20 and Weth transfers require 155000, 100000, 52000 gas respectively
    // Processing each exit in a while loop iteration requires ~52000 gas (@todo check if this changed)
    // uint32 constant internal ITERATION_GAS = 52000;

    // So putting an upper limit of 155000 + 52000 + leeway
    uint32 public ON_FINALIZE_GAS_LIMIT = 300000;

    uint256 public exitWindow;
}

File 16 of 43 : IERC20.sol
pragma solidity ^0.5.2;

/**
 * @title ERC20 interface
 * @dev see https://eips.ethereum.org/EIPS/eip-20
 */
interface IERC20 {
    function transfer(address to, uint256 value) external returns (bool);

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

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

    function totalSupply() external view returns (uint256);

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

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

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

    event Approval(address indexed owner, address indexed spender, uint256 value);
}

File 17 of 43 : SafeMath.sol
pragma solidity ^0.5.2;

/**
 * @title SafeMath
 * @dev Unsigned math operations with safety checks that revert on error
 */
library SafeMath {
    /**
     * @dev Multiplies two unsigned integers, reverts on overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (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-solidity/pull/522
        if (a == 0) {
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b);

        return c;
    }

    /**
     * @dev Integer division of two unsigned integers truncating the quotient, reverts on division by zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        // Solidity only automatically asserts when dividing by 0
        require(b > 0);
        uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold

        return c;
    }

    /**
     * @dev Subtracts two unsigned integers, reverts on overflow (i.e. if subtrahend is greater than minuend).
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b <= a);
        uint256 c = a - b;

        return c;
    }

    /**
     * @dev Adds two unsigned integers, reverts on overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a);

        return c;
    }

    /**
     * @dev Divides two unsigned integers and returns the remainder (unsigned integer modulo),
     * reverts when dividing by zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b != 0);
        return a % b;
    }
}

File 18 of 43 : IERC721.sol
pragma solidity ^0.5.2;

import "../../introspection/IERC165.sol";

/**
 * @title ERC721 Non-Fungible Token Standard basic interface
 * @dev see https://eips.ethereum.org/EIPS/eip-721
 */
contract IERC721 is IERC165 {
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    function balanceOf(address owner) public view returns (uint256 balance);
    function ownerOf(uint256 tokenId) public view returns (address owner);

    function approve(address to, uint256 tokenId) public;
    function getApproved(uint256 tokenId) public view returns (address operator);

    function setApprovalForAll(address operator, bool _approved) public;
    function isApprovedForAll(address owner, address operator) public view returns (bool);

    function transferFrom(address from, address to, uint256 tokenId) public;
    function safeTransferFrom(address from, address to, uint256 tokenId) public;

    function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public;
}

File 19 of 43 : IERC721Receiver.sol
pragma solidity ^0.5.2;

/**
 * @title ERC721 token receiver interface
 * @dev Interface for any contract that wants to support safeTransfers
 * from ERC721 asset contracts.
 */
contract IERC721Receiver {
    /**
     * @notice Handle the receipt of an NFT
     * @dev The ERC721 smart contract calls this function on the recipient
     * after a `safeTransfer`. This function MUST return the function selector,
     * otherwise the caller will revert the transaction. The selector to be
     * returned can be obtained as `this.onERC721Received.selector`. This
     * function MAY throw to revert and reject the transfer.
     * Note: the ERC721 contract address is always the message sender.
     * @param operator The address which called `safeTransferFrom` function
     * @param from The address which previously owned the token
     * @param tokenId The NFT identifier which is being transferred
     * @param data Additional data with no specified format
     * @return bytes4 `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
     */
    function onERC721Received(address operator, address from, uint256 tokenId, bytes memory data)
    public returns (bytes4);
}

File 20 of 43 : Address.sol
pragma solidity ^0.5.2;

/**
 * Utility library of inline functions on addresses
 */
library Address {
    /**
     * Returns whether the target address is a contract
     * @dev This function will return false if invoked during the constructor of a contract,
     * as the code is not actually created until after the constructor finishes.
     * @param account address of the account to check
     * @return whether the target address is a contract
     */
    function isContract(address account) internal view returns (bool) {
        uint256 size;
        // XXX Currently there is no better way to check if there is a contract in an address
        // than to check the size of the code at that address.
        // See https://ethereum.stackexchange.com/a/14016/36603
        // for more details about how this works.
        // TODO Check this again before the Serenity release, because all addresses will be
        // contracts then.
        // solhint-disable-next-line no-inline-assembly
        assembly { size := extcodesize(account) }
        return size > 0;
    }
}

File 21 of 43 : Counters.sol
pragma solidity ^0.5.2;

import "../math/SafeMath.sol";

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

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

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

    function increment(Counter storage counter) internal {
        counter._value += 1;
    }

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

File 22 of 43 : ERC165.sol
pragma solidity ^0.5.2;

import "./IERC165.sol";

/**
 * @title ERC165
 * @author Matt Condon (@shrugs)
 * @dev Implements ERC165 using a lookup table.
 */
contract ERC165 is IERC165 {
    bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7;
    /*
     * 0x01ffc9a7 ===
     *     bytes4(keccak256('supportsInterface(bytes4)'))
     */

    /**
     * @dev a mapping of interface id to whether or not it's supported
     */
    mapping(bytes4 => bool) private _supportedInterfaces;

    /**
     * @dev A contract implementing SupportsInterfaceWithLookup
     * implement ERC165 itself
     */
    constructor () internal {
        _registerInterface(_INTERFACE_ID_ERC165);
    }

    /**
     * @dev implement supportsInterface(bytes4) using a lookup table
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool) {
        return _supportedInterfaces[interfaceId];
    }

    /**
     * @dev internal method for registering an interface
     */
    function _registerInterface(bytes4 interfaceId) internal {
        require(interfaceId != 0xffffffff);
        _supportedInterfaces[interfaceId] = true;
    }
}

File 23 of 43 : RLPReader.sol
// SPDX-License-Identifier: Apache-2.0

/*
 * @author Hamdi Allam [email protected]
 * Please reach out with any questions or concerns
 */
pragma solidity >=0.5.10 <0.9.0;

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 {
        uint256 len;
        uint256 memPtr;
    }

    struct Iterator {
        RLPItem item; // Item that's being iterated over.
        uint256 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));

        uint256 ptr = self.nextPtr;
        uint256 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) {
        uint256 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));

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

    /*
     * @param the RLP item.
     */
    function rlpLen(RLPItem memory item) internal pure returns (uint256) {
        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 (uint256, uint256) {
        uint256 offset = _payloadOffset(item.memPtr);
        uint256 memPtr = item.memPtr + offset;
        uint256 len = item.len - offset; // data length
        return (memPtr, len);
    }

    /*
     * @param the RLP item.
     */
    function payloadLen(RLPItem memory item) internal pure returns (uint256) {
        (, uint256 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));

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

        uint256 memPtr = item.memPtr + _payloadOffset(item.memPtr);
        uint256 dataLen;
        for (uint256 i = 0; i < items; i++) {
            dataLen = _itemLength(memPtr);
            result[i] = RLPItem(dataLen, memPtr);
            memPtr = memPtr + dataLen;
        }
        // New check to see if the last mempointer of the last read item has moved farther than the parent item is long
        require(memPtr - item.memPtr == item.len, "Wrong total length.");

        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;
        uint256 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) {
        (uint256 memPtr, uint256 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;

        uint256 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);
        uint256 result;
        uint256 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(uint160(toUint(item)));
    }

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

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

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

            // shift 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 (uint256) {
        // one byte prefix
        require(item.len == 33);

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

        return result;
    }

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

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

        uint256 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 (uint256) {
        if (item.len == 0) return 0;

        uint256 count = 0;
        uint256 currPtr = item.memPtr + _payloadOffset(item.memPtr);
        uint256 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(uint256 memPtr) private pure returns (uint256) {
        uint256 itemLen;
        uint256 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(uint256 memPtr) private pure returns (uint256) {
        uint256 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(uint256 src, uint256 dest, uint256 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
            uint256 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 24 of 43 : Ownable.sol
pragma solidity ^0.5.2;

/**
 * @title Ownable
 * @dev The Ownable contract has an owner address, and provides basic authorization control
 * functions, this simplifies the implementation of "user permissions".
 */
contract Ownable {
    address private _owner;

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

    /**
     * @dev The Ownable constructor sets the original `owner` of the contract to the sender
     * account.
     */
    constructor () internal {
        _owner = msg.sender;
        emit OwnershipTransferred(address(0), _owner);
    }

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

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(isOwner());
        _;
    }

    /**
     * @return true if `msg.sender` is the owner of the contract.
     */
    function isOwner() public view returns (bool) {
        return msg.sender == _owner;
    }

    /**
     * @dev Allows the current owner to relinquish control of the contract.
     * It will not be possible to call the functions with the `onlyOwner`
     * modifier anymore.
     * @notice Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public onlyOwner {
        emit OwnershipTransferred(_owner, address(0));
        _owner = address(0);
    }

    /**
     * @dev Allows the current owner to transfer control of the contract to a newOwner.
     * @param newOwner The address to transfer ownership to.
     */
    function transferOwnership(address newOwner) public onlyOwner {
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers control of the contract to a newOwner.
     * @param newOwner The address to transfer ownership to.
     */
    function _transferOwnership(address newOwner) internal {
        require(newOwner != address(0));
        emit OwnershipTransferred(_owner, newOwner);
        _owner = newOwner;
    }
}

File 25 of 43 : BytesLib.sol
pragma solidity ^0.5.2;

import "openzeppelin-solidity/contracts/math/SafeMath.sol";

library BytesLib {
    function concat(bytes memory _preBytes, bytes memory _postBytes)
        internal
        pure
        returns (bytes memory)
    {
        bytes memory tempBytes;
        assembly {
            // Get a location of some free memory and store it in tempBytes as
            // Solidity does for memory variables.
            tempBytes := mload(0x40)

            // Store the length of the first bytes array at the beginning of
            // the memory for tempBytes.
            let length := mload(_preBytes)
            mstore(tempBytes, length)

            // Maintain a memory counter for the current write location in the
            // temp bytes array by adding the 32 bytes for the array length to
            // the starting location.
            let mc := add(tempBytes, 0x20)
            // Stop copying when the memory counter reaches the length of the
            // first bytes array.
            let end := add(mc, length)

            for {
                // Initialize a copy counter to the start of the _preBytes data,
                // 32 bytes into its memory.
                let cc := add(_preBytes, 0x20)
            } lt(mc, end) {
                // Increase both counters by 32 bytes each iteration.
                mc := add(mc, 0x20)
                cc := add(cc, 0x20)
            } {
                // Write the _preBytes data into the tempBytes memory 32 bytes
                // at a time.
                mstore(mc, mload(cc))
            }

            // Add the length of _postBytes to the current length of tempBytes
            // and store it as the new length in the first 32 bytes of the
            // tempBytes memory.
            length := mload(_postBytes)
            mstore(tempBytes, add(length, mload(tempBytes)))

            // Move the memory counter back from a multiple of 0x20 to the
            // actual end of the _preBytes data.
            mc := end
            // Stop copying when the memory counter reaches the new combined
            // length of the arrays.
            end := add(mc, length)

            for {
                let cc := add(_postBytes, 0x20)
            } lt(mc, end) {
                mc := add(mc, 0x20)
                cc := add(cc, 0x20)
            } {
                mstore(mc, mload(cc))
            }

            // Update the free-memory pointer by padding our last write location
            // to 32 bytes: add 31 bytes to the end of tempBytes to move to the
            // next 32 byte block, then round down to the nearest multiple of
            // 32. If the sum of the length of the two arrays is zero then add
            // one before rounding down to leave a blank 32 bytes (the length block with 0).
            mstore(
                0x40,
                and(
                    add(add(end, iszero(add(length, mload(_preBytes)))), 31),
                    not(31) // Round down to the nearest 32 bytes.
                )
            )
        }
        return tempBytes;
    }

    function slice(bytes memory _bytes, uint256 _start, uint256 _length)
        internal
        pure
        returns (bytes memory)
    {
        require(_bytes.length >= (_start + _length));
        bytes memory tempBytes;
        assembly {
            switch iszero(_length)
                case 0 {
                    // Get a location of some free memory and store it in tempBytes as
                    // Solidity does for memory variables.
                    tempBytes := mload(0x40)

                    // The first word of the slice result is potentially a partial
                    // word read from the original array. To read it, we calculate
                    // the length of that partial word and start copying that many
                    // bytes into the array. The first word we copy will start with
                    // data we don't care about, but the last `lengthmod` bytes will
                    // land at the beginning of the contents of the new array. When
                    // we're done copying, we overwrite the full first word with
                    // the actual length of the slice.
                    let lengthmod := and(_length, 31)

                    // The multiplication in the next line is necessary
                    // because when slicing multiples of 32 bytes (lengthmod == 0)
                    // the following copy loop was copying the origin's length
                    // and then ending prematurely not copying everything it should.
                    let mc := add(
                        add(tempBytes, lengthmod),
                        mul(0x20, iszero(lengthmod))
                    )
                    let end := add(mc, _length)

                    for {
                        // The multiplication in the next line has the same exact purpose
                        // as the one above.
                        let cc := add(
                            add(
                                add(_bytes, lengthmod),
                                mul(0x20, iszero(lengthmod))
                            ),
                            _start
                        )
                    } lt(mc, end) {
                        mc := add(mc, 0x20)
                        cc := add(cc, 0x20)
                    } {
                        mstore(mc, mload(cc))
                    }

                    mstore(tempBytes, _length)

                    //update free-memory pointer
                    //allocating the array padded to 32 bytes like the compiler does now
                    mstore(0x40, and(add(mc, 31), not(31)))
                }
                //if we want a zero-length slice let's just return a zero-length array
                default {
                    tempBytes := mload(0x40)
                    mstore(0x40, add(tempBytes, 0x20))
                }
        }

        return tempBytes;
    }

    // Pad a bytes array to 32 bytes
    function leftPad(bytes memory _bytes) internal pure returns (bytes memory) {
        // may underflow if bytes.length < 32. Hence using SafeMath.sub
        bytes memory newBytes = new bytes(SafeMath.sub(32, _bytes.length));
        return concat(newBytes, _bytes);
    }

    function toBytes32(bytes memory b) internal pure returns (bytes32) {
        require(b.length >= 32, "Bytes array should atleast be 32 bytes");
        bytes32 out;
        for (uint256 i = 0; i < 32; i++) {
            out |= bytes32(b[i] & 0xFF) >> (i * 8);
        }
        return out;
    }

    function toBytes4(bytes memory b) internal pure returns (bytes4 result) {
        assembly {
            result := mload(add(b, 32))
        }
    }

    function fromBytes32(bytes32 x) internal pure returns (bytes memory) {
        bytes memory b = new bytes(32);
        for (uint256 i = 0; i < 32; i++) {
            b[i] = bytes1(uint8(uint256(x) / (2**(8 * (31 - i)))));
        }
        return b;
    }

    function fromUint(uint256 _num) internal pure returns (bytes memory _ret) {
        _ret = new bytes(32);
        assembly {
            mstore(add(_ret, 32), _num)
        }
    }

    function toUint(bytes memory _bytes, uint256 _start)
        internal
        pure
        returns (uint256)
    {
        require(_bytes.length >= (_start + 32));
        uint256 tempUint;
        assembly {
            tempUint := mload(add(add(_bytes, 0x20), _start))
        }
        return tempUint;
    }

    function toAddress(bytes memory _bytes, uint256 _start)
        internal
        pure
        returns (address)
    {
        require(_bytes.length >= (_start + 20));
        address tempAddress;
        assembly {
            tempAddress := div(
                mload(add(add(_bytes, 0x20), _start)),
                0x1000000000000000000000000
            )
        }

        return tempAddress;
    }
}

File 26 of 43 : ERC721Holder.sol
pragma solidity ^0.5.2;

import "./IERC721Receiver.sol";

contract ERC721Holder is IERC721Receiver {
    function onERC721Received(address, address, uint256, bytes memory) public returns (bytes4) {
        return this.onERC721Received.selector;
    }
}

File 27 of 43 : SafeERC20.sol
pragma solidity ^0.5.2;

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 ERC20;` 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));
    }

    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'
        require((value == 0) || (token.allowance(address(this), spender) == 0));
        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);
        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 equal true).
     * @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.

        // A Solidity high level call has three parts:
        //  1. The target address is checked to verify it contains contract code
        //  2. The call itself is made, and success asserted
        //  3. The return value is decoded, which in turn checks the size of the returned data.

        require(address(token).isContract());

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = address(token).call(data);
        require(success);

        if (returndata.length > 0) { // Return data is optional
            require(abi.decode(returndata, (bool)));
        }
    }
}

File 28 of 43 : WETH.sol
pragma solidity ^0.5.2;

import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol";

contract WETH is ERC20 {
    event Deposit(address indexed dst, uint256 wad);
    event Withdrawal(address indexed src, uint256 wad);

    function deposit() public payable;

    function withdraw(uint256 wad) public;

    function withdraw(uint256 wad, address user) public;
}

File 29 of 43 : IDepositManager.sol
pragma solidity ^0.5.2;

interface IDepositManager {
    function depositEther() external payable;
    function transferAssets(
        address _token,
        address _user,
        uint256 _amountOrNFTId
    ) external;
    function depositERC20(address _token, uint256 _amount) external;
    function depositERC721(address _token, uint256 _tokenId) external;
}

File 30 of 43 : DepositManagerStorage.sol
pragma solidity ^0.5.2;

import {Registry} from "../../common/Registry.sol";
import {RootChain} from "../RootChain.sol";
import {ProxyStorage} from "../../common/misc/ProxyStorage.sol";
import {StateSender} from "../stateSyncer/StateSender.sol";
import {GovernanceLockable} from "../../common/mixin/GovernanceLockable.sol";


contract DepositManagerHeader {
    event NewDepositBlock(address indexed owner, address indexed token, uint256 amountOrNFTId, uint256 depositBlockId);
    event MaxErc20DepositUpdate(uint256 indexed oldLimit, uint256 indexed newLimit);

    struct DepositBlock {
        bytes32 depositHash;
        uint256 createdAt;
    }
}


contract DepositManagerStorage is ProxyStorage, GovernanceLockable, DepositManagerHeader {
    Registry public registry;
    RootChain public rootChain;
    StateSender public stateSender;

    mapping(uint256 => DepositBlock) public deposits;

    address public childChain;
    uint256 public maxErc20Deposit = 100 * (10**18);
}

File 31 of 43 : StateSender.sol
pragma solidity ^0.5.2;

import {Ownable} from "openzeppelin-solidity/contracts/ownership/Ownable.sol";
import {SafeMath} from "openzeppelin-solidity/contracts/math/SafeMath.sol";

contract StateSender is Ownable {
    using SafeMath for uint256;

    uint256 public counter;
    mapping(address => address) public registrations;

    event NewRegistration(
        address indexed user,
        address indexed sender,
        address indexed receiver
    );
    event RegistrationUpdated(
        address indexed user,
        address indexed sender,
        address indexed receiver
    );
    event StateSynced(
        uint256 indexed id,
        address indexed contractAddress,
        bytes data
    );

    modifier onlyRegistered(address receiver) {
        require(registrations[receiver] == msg.sender, "Invalid sender");
        _;
    }

    function syncState(address receiver, bytes calldata data)
        external
        onlyRegistered(receiver)
    {
        counter = counter.add(1);
        emit StateSynced(counter, receiver, data);
    }

    // register new contract for state sync
    function register(address sender, address receiver) public {
        require(
            isOwner() || registrations[receiver] == msg.sender,
            "StateSender.register: Not authorized to register"
        );
        registrations[receiver] = sender;
        if (registrations[receiver] == address(0)) {
            emit NewRegistration(msg.sender, sender, receiver);
        } else {
            emit RegistrationUpdated(msg.sender, sender, receiver);
        }
    }
}

File 32 of 43 : GovernanceLockable.sol
pragma solidity ^0.5.2;

import {Governable} from "../governance/Governable.sol";
import {Lockable} from "./Lockable.sol";

contract GovernanceLockable is Lockable, Governable {
    constructor(address governance) public Governable(governance) {}

    function lock() public onlyGovernance {
        super.lock();
    }

    function unlock() public onlyGovernance {
        super.unlock();
    }
}

File 33 of 43 : RootChain.sol
pragma solidity ^0.5.2;

import {SafeMath} from "openzeppelin-solidity/contracts/math/SafeMath.sol";

import {RootChainHeader, RootChainStorage} from "./RootChainStorage.sol";

import {IStakeManager} from "../staking/stakeManager/IStakeManager.sol";
import {IRootChain} from "./IRootChain.sol";
import {Registry} from "../common/Registry.sol";


contract RootChain is RootChainStorage, IRootChain {
    using SafeMath for uint256;
   

    modifier onlyDepositManager() {
        require(msg.sender == registry.getDepositManagerAddress(), "UNAUTHORIZED_DEPOSIT_MANAGER_ONLY");
        _;
    }

    function submitHeaderBlock(bytes calldata data, bytes calldata sigs) external {
        revert();
    }

    function submitCheckpoint(bytes calldata data, uint[3][] calldata sigs) external {
        (address proposer, uint256 start, uint256 end, bytes32 rootHash, bytes32 accountHash, uint256 _borChainID) = abi
            .decode(data, (address, uint256, uint256, bytes32, bytes32, uint256));
        require(CHAINID == _borChainID, "Invalid bor chain id");

        require(_buildHeaderBlock(proposer, start, end, rootHash), "INCORRECT_HEADER_DATA");

        // check if it is better to keep it in local storage instead
        IStakeManager stakeManager = IStakeManager(registry.getStakeManagerAddress());
        uint256 _reward = stakeManager.checkSignatures(
            end.sub(start).add(1),
            /**  
                prefix 01 to data 
                01 represents positive vote on data and 00 is negative vote
                malicious validator can try to send 2/3 on negative vote so 01 is appended
             */
            keccak256(abi.encodePacked(bytes(hex"01"), data)),
            accountHash,
            proposer,
            sigs
        );

        require(_reward != 0, "Invalid checkpoint");
        emit NewHeaderBlock(proposer, _nextHeaderBlock, _reward, start, end, rootHash);
        _nextHeaderBlock = _nextHeaderBlock.add(MAX_DEPOSITS);
        _blockDepositId = 1;
    }

    function updateDepositId(uint256 numDeposits) external onlyDepositManager returns (uint256 depositId) {
        depositId = currentHeaderBlock().add(_blockDepositId);
        // deposit ids will be (_blockDepositId, _blockDepositId + 1, .... _blockDepositId + numDeposits - 1)
        _blockDepositId = _blockDepositId.add(numDeposits);
        require(
            // Since _blockDepositId is initialized to 1; only (MAX_DEPOSITS - 1) deposits per header block are allowed
            _blockDepositId <= MAX_DEPOSITS,
            "TOO_MANY_DEPOSITS"
        );
    }

    function getLastChildBlock() external view returns (uint256) {
        return headerBlocks[currentHeaderBlock()].end;
    }

    function slash() external {
        //TODO: future implementation
    }

    function currentHeaderBlock() public view returns (uint256) {
        return _nextHeaderBlock.sub(MAX_DEPOSITS);
    }

    function _buildHeaderBlock(
        address proposer,
        uint256 start,
        uint256 end,
        bytes32 rootHash
    ) private returns (bool) {
        uint256 nextChildBlock;
        /*
    The ID of the 1st header block is MAX_DEPOSITS.
    if _nextHeaderBlock == MAX_DEPOSITS, then the first header block is yet to be submitted, hence nextChildBlock = 0
    */
        if (_nextHeaderBlock > MAX_DEPOSITS) {
            nextChildBlock = headerBlocks[currentHeaderBlock()].end + 1;
        }
        if (nextChildBlock != start) {
            return false;
        }

        HeaderBlock memory headerBlock = HeaderBlock({
            root: rootHash,
            start: nextChildBlock,
            end: end,
            createdAt: now,
            proposer: proposer
        });

        headerBlocks[_nextHeaderBlock] = headerBlock;
        return true;
    }

    // Housekeeping function. @todo remove later
    function setNextHeaderBlock(uint256 _value) public onlyOwner {
        require(_value % MAX_DEPOSITS == 0, "Invalid value");
        for (uint256 i = _value; i < _nextHeaderBlock; i += MAX_DEPOSITS) {
            delete headerBlocks[i];
        }
        _nextHeaderBlock = _value;
        _blockDepositId = 1;
        emit ResetHeaderBlock(msg.sender, _nextHeaderBlock);
    }

    // Housekeeping function. @todo remove later
    function setHeimdallId(string memory _heimdallId) public onlyOwner {
        heimdallId = keccak256(abi.encodePacked(_heimdallId));
    }
}

File 34 of 43 : Common.sol
pragma solidity ^0.5.2;

import "./BytesLib.sol";

library Common {
    function getV(bytes memory v, uint16 chainId) public pure returns (uint8) {
        if (chainId > 0) {
            return
                uint8(
                    BytesLib.toUint(BytesLib.leftPad(v), 0) - (chainId * 2) - 8
                );
        } else {
            return uint8(BytesLib.toUint(BytesLib.leftPad(v), 0));
        }
    }

    //assemble the given address bytecode. If bytecode exists then the _addr is a contract.
    function isContract(address _addr) public view returns (bool) {
        uint256 length;
        assembly {
            //retrieve the size of the code on target address, this needs assembly
            length := extcodesize(_addr)
        }
        return (length > 0);
    }

    // convert bytes to uint8
    function toUint8(bytes memory _arg) public pure returns (uint8) {
        return uint8(_arg[0]);
    }

    function toUint16(bytes memory _arg) public pure returns (uint16) {
        return (uint16(uint8(_arg[0])) << 8) | uint16(uint8(_arg[1]));
    }
}

File 35 of 43 : RLPEncode.sol
// Library for RLP encoding a list of bytes arrays.
// Modeled after ethereumjs/rlp (https://github.com/ethereumjs/rlp)
// [Very] modified version of Sam Mayo's library.
pragma solidity ^0.5.2;

import "./BytesLib.sol";

library RLPEncode {
    // Encode an item (bytes memory)
    function encodeItem(bytes memory self)
        internal
        pure
        returns (bytes memory)
    {
        bytes memory encoded;
        if (self.length == 1 && uint8(self[0] & 0xFF) < 0x80) {
            encoded = new bytes(1);
            encoded = self;
        } else {
            encoded = BytesLib.concat(encodeLength(self.length, 128), self);
        }
        return encoded;
    }

    // Encode a list of items
    function encodeList(bytes[] memory self)
        internal
        pure
        returns (bytes memory)
    {
        bytes memory encoded;
        for (uint256 i = 0; i < self.length; i++) {
            encoded = BytesLib.concat(encoded, encodeItem(self[i]));
        }
        return BytesLib.concat(encodeLength(encoded.length, 192), encoded);
    }

    // Hack to encode nested lists. If you have a list as an item passed here, included
    // pass = true in that index. E.g.
    // [item, list, item] --> pass = [false, true, false]
    // function encodeListWithPasses(bytes[] memory self, bool[] pass) internal pure returns (bytes memory) {
    //   bytes memory encoded;
    //   for (uint i=0; i < self.length; i++) {
    // 		if (pass[i] == true) {
    // 			encoded = BytesLib.concat(encoded, self[i]);
    // 		} else {
    // 			encoded = BytesLib.concat(encoded, encodeItem(self[i]));
    // 		}
    //   }
    //   return BytesLib.concat(encodeLength(encoded.length, 192), encoded);
    // }

    // Generate the prefix for an item or the entire list based on RLP spec
    function encodeLength(uint256 L, uint256 offset)
        internal
        pure
        returns (bytes memory)
    {
        if (L < 56) {
            bytes memory prefix = new bytes(1);
            prefix[0] = bytes1(uint8(L + offset));
            return prefix;
        } else {
            // lenLen is the length of the hex representation of the data length
            uint256 lenLen;
            uint256 i = 0x1;

            while (L / i != 0) {
                lenLen++;
                i *= 0x100;
            }

            bytes memory prefix0 = getLengthBytes(offset + 55 + lenLen);
            bytes memory prefix1 = getLengthBytes(L);
            return BytesLib.concat(prefix0, prefix1);
        }
    }

    function getLengthBytes(uint256 x) internal pure returns (bytes memory b) {
        // Figure out if we need 1 or two bytes to express the length.
        // 1 byte gets us to max 255
        // 2 bytes gets us to max 65535 (no payloads will be larger than this)
        uint256 nBytes = 1;
        if (x > 255) {
            nBytes = 2;
        }

        b = new bytes(nBytes);
        // Encode the length and return it
        for (uint256 i = 0; i < nBytes; i++) {
            b[i] = bytes1(uint8(x / (2**(8 * (nBytes - 1 - i)))));
        }
    }
}

File 36 of 43 : ChainIdMixin.sol
pragma solidity ^0.5.2;

contract ChainIdMixin {
  bytes constant public networkId = hex"3A99";
  uint256 constant public CHAINID = 15001;
}

File 37 of 43 : ProxyStorage.sol
pragma solidity ^0.5.2;
import {Ownable} from "openzeppelin-solidity/contracts/ownership/Ownable.sol";

contract ProxyStorage is Ownable {
    address internal proxyTo;
}

File 38 of 43 : Governable.sol
pragma solidity ^0.5.2;

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

contract Governable {
    IGovernance public governance;

    constructor(address _governance) public {
        governance = IGovernance(_governance);
    }

    modifier onlyGovernance() {
        _assertGovernance();
        _;
    }

    function _assertGovernance() private view {
        require(
            msg.sender == address(governance),
            "Only governance contract is authorized"
        );
    }
}

File 39 of 43 : IERC165.sol
pragma solidity ^0.5.2;

/**
 * @title IERC165
 * @dev https://eips.ethereum.org/EIPS/eip-165
 */
interface IERC165 {
    /**
     * @notice Query if a contract implements an interface
     * @param interfaceId The interface identifier, as specified in ERC-165
     * @dev Interface identification is specified in ERC-165. This function
     * uses less than 30,000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

File 40 of 43 : Lockable.sol
pragma solidity ^0.5.2;

contract Lockable {
    bool public locked;

    modifier onlyWhenUnlocked() {
        _assertUnlocked();
        _;
    }

    function _assertUnlocked() private view {
        require(!locked, "locked");
    }

    function lock() public {
        locked = true;
    }

    function unlock() public {
        locked = false;
    }
}

File 41 of 43 : IStakeManager.sol
pragma solidity 0.5.17;

contract IStakeManager {
    // validator replacement
    function startAuction(
        uint256 validatorId,
        uint256 amount,
        bool acceptDelegation,
        bytes calldata signerPubkey
    ) external;

    function confirmAuctionBid(uint256 validatorId, uint256 heimdallFee) external;

    function transferFunds(
        uint256 validatorId,
        uint256 amount,
        address delegator
    ) external returns (bool);

    function transferFundsPOL(
        uint256 validatorId, 
        uint256 amount, 
        address delegator
    ) external returns (bool);

    function delegationDeposit(
        uint256 validatorId,
        uint256 amount,
        address delegator
    ) external returns (bool);

    function delegationDepositPOL(
        uint256 validatorId, 
        uint256 amount, 
        address delegator
    ) external returns (bool);

    function unstake(uint256 validatorId) external;

    function unstakePOL(uint256 validatorId) external;

    function totalStakedFor(address addr) external view returns (uint256);

    function stakeFor(
        address user,
        uint256 amount,
        uint256 heimdallFee,
        bool acceptDelegation,
        bytes memory signerPubkey
    ) public;

    function stakeForPOL(
        address user,
        uint256 amount,
        uint256 heimdallFee,
        bool acceptDelegation,
        bytes memory signerPubkey
    ) public;

    function checkSignatures(
        uint256 blockInterval,
        bytes32 voteHash,
        bytes32 stateRoot,
        address proposer,
        uint[3][] calldata sigs
    ) external returns (uint256);

    function updateValidatorState(uint256 validatorId, int256 amount) public;

    function ownerOf(uint256 tokenId) public view returns (address);

    function slash(bytes calldata slashingInfoList) external returns (uint256);

    function validatorStake(uint256 validatorId) public view returns (uint256);

    function epoch() public view returns (uint256);

    function getRegistry() public view returns (address);

    function withdrawalDelay() public view returns (uint256);

    function delegatedAmount(uint256 validatorId) public view returns(uint256);

    function decreaseValidatorDelegatedAmount(uint256 validatorId, uint256 amount) public;

    function withdrawDelegatorsReward(uint256 validatorId) public returns(uint256);

    function delegatorsReward(uint256 validatorId) public view returns(uint256);

    function dethroneAndStake(
        address auctionUser,
        uint256 heimdallFee,
        uint256 validatorId,
        uint256 auctionAmount,
        bool acceptDelegation,
        bytes calldata signerPubkey
    ) external;
}

File 42 of 43 : IRootChain.sol
pragma solidity ^0.5.2;


interface IRootChain {
    function slash() external;

    function submitHeaderBlock(bytes calldata data, bytes calldata sigs)
        external;
    
    function submitCheckpoint(bytes calldata data, uint[3][] calldata sigs)
        external;

    function getLastChildBlock() external view returns (uint256);

    function currentHeaderBlock() external view returns (uint256);
}

File 43 of 43 : IGovernance.sol
pragma solidity ^0.5.2;

interface IGovernance {
    function update(address target, bytes calldata data) external;
}

Settings
{
  "remappings": [
    "openzeppelin-solidity/=node_modules/openzeppelin-solidity/",
    "@ensdomains/=node_modules/@ensdomains/",
    "eth-gas-reporter/=node_modules/eth-gas-reporter/",
    "forge-std/=lib/forge-std/src/",
    "hardhat/=node_modules/hardhat/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "useLiteralContent": false
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "istanbul",
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"exitId","type":"uint256"}],"name":"ExitCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"oldExitPeriod","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"newExitPeriod","type":"uint256"}],"name":"ExitPeriodUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"exitor","type":"address"},{"indexed":true,"internalType":"uint256","name":"exitId","type":"uint256"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"isRegularExit","type":"bool"}],"name":"ExitStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"exitId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"age","type":"uint256"},{"indexed":false,"internalType":"address","name":"signer","type":"address"}],"name":"ExitUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"exitId","type":"uint256"},{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdraw","type":"event"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"constant":true,"inputs":[],"name":"HALF_EXIT_PERIOD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"ON_FINALIZE_GAS_LIMIT","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"exitor","type":"address"},{"internalType":"address","name":"childToken","type":"address"},{"internalType":"address","name":"rootToken","type":"address"},{"internalType":"uint256","name":"exitAmountOrTokenId","type":"uint256"},{"internalType":"bytes32","name":"txHash","type":"bytes32"},{"internalType":"bool","name":"isRegularExit","type":"bool"},{"internalType":"uint256","name":"priority","type":"uint256"}],"name":"addExitToQueue","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"exitId","type":"uint256"},{"internalType":"uint256","name":"age","type":"uint256"},{"internalType":"address","name":"utxoOwner","type":"address"},{"internalType":"address","name":"token","type":"address"}],"name":"addInput","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"exitId","type":"uint256"},{"internalType":"uint256","name":"inputId","type":"uint256"},{"internalType":"bytes","name":"challengeData","type":"bytes"},{"internalType":"address","name":"adjudicatorPredicate","type":"address"}],"name":"challengeExit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"createExitQueue","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"exitNft","outputs":[{"internalType":"contract ExitNFT","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"exitWindow","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"exits","outputs":[{"internalType":"uint256","name":"receiptAmountOrNFTId","type":"uint256"},{"internalType":"bytes32","name":"txHash","type":"bytes32"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"bool","name":"isRegularExit","type":"bool"},{"internalType":"address","name":"predicate","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"exitsQueues","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isOwner","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"ownerExits","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"processExits","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address[]","name":"_tokens","type":"address[]"}],"name":"processExitsBatch","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"renounceOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"depositId","type":"uint256"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amountOrToken","type":"uint256"}],"name":"startExitWithDepositedTokens","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"halfExitPeriod","type":"uint256"}],"name":"updateExitPeriod","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint8","name":"offset","type":"uint8"},{"internalType":"bool","name":"verifyTxInclusion","type":"bool"}],"name":"verifyInclusion","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"}]

Deployed Bytecode

0x6080604052600436106200013a5760003560e01c80639145e6df11620000af578063d11f045c116200006d578063d11f045c1462000571578063d931a86914620005a8578063ed4a0be81462000609578063edeca09b1462000621578063f2fde38b1462000639576200013a565b80639145e6df146200035d5780639492b0b8146200039457806396cbd812146200042d578063ad1d8069146200045e578063c74ab88a14620004ed576200013a565b8063433c76bf11620000fd578063433c76bf1462000289578063661429c814620002b7578063715018a614620002e55780638da5cb5b14620002fd5780638f32d59b1462000331576200013a565b80630f6795f2146200013c578063144a03b314620001735780631e29848b14620001a857806322f192af14620001d2578063342de179146200021d575b005b3480156200014957600080fd5b506200013a600480360360208110156200016257600080fd5b50356001600160a01b031662000670565b6200013a600480360360608110156200018b57600080fd5b508035906001600160a01b03602082013516906040013562000bed565b348015620001b557600080fd5b50620001c062000c45565b60408051918252519081900360200190f35b348015620001df57600080fd5b506200013a60048036036080811015620001f857600080fd5b508035906020810135906001600160a01b036040820135811691606001351662000c4b565b3480156200022a57600080fd5b506200024b600480360360208110156200024357600080fd5b503562000d96565b6040805196875260208701959095526001600160a01b03938416868601529183166060860152151560808501521660a0830152519081900360c00190f35b3480156200029657600080fd5b506200013a60048036036020811015620002af57600080fd5b503562000ddf565b348015620002c457600080fd5b50620001c060048036036020811015620002dd57600080fd5b503562000e27565b348015620002f257600080fd5b506200013a62000e39565b3480156200030a57600080fd5b506200031562000e97565b604080516001600160a01b039092168252519081900360200190f35b3480156200033e57600080fd5b506200034962000ea6565b604080519115158252519081900360200190f35b3480156200036a57600080fd5b506200013a600480360360208110156200038357600080fd5b50356001600160a01b031662000eb7565b348015620003a157600080fd5b506200013a60048036036080811015620003ba57600080fd5b813591602081013591810190606081016040820135640100000000811115620003e257600080fd5b820183602082011115620003f557600080fd5b803590602001918460018302840111640100000000831117156200041857600080fd5b9193509150356001600160a01b031662000f71565b3480156200043a57600080fd5b506200044562001362565b6040805163ffffffff9092168252519081900360200190f35b3480156200046b57600080fd5b50620001c0600480360360608110156200048457600080fd5b810190602081018135640100000000811115620004a057600080fd5b820183602082011115620004b357600080fd5b80359060200191846001830284011164010000000083111715620004d657600080fd5b919350915060ff8135169060200135151562001375565b348015620004fa57600080fd5b506200013a600480360360208110156200051357600080fd5b8101906020810181356401000000008111156200052f57600080fd5b8201836020820111156200054257600080fd5b803590602001918460208302840111640100000000831117156200056557600080fd5b50909250905062001655565b3480156200057e57600080fd5b5062000315600480360360208110156200059757600080fd5b50356001600160a01b031662001691565b348015620005b557600080fd5b506200013a600480360360e0811015620005ce57600080fd5b506001600160a01b03813581169160208101358216916040820135169060608101359060808101359060a081013515159060c00135620016ac565b3480156200061657600080fd5b50620001c062001afb565b3480156200062e57600080fd5b506200031562001b01565b3480156200064657600080fd5b506200013a600480360360208110156200065f57600080fd5b50356001600160a01b031662001b10565b6001600160a01b0380821660009081526008602052604081205490918291165b6000816001600160a01b031663bda1504b6040518163ffffffff1660e01b815260040160206040518083038186803b158015620006cc57600080fd5b505afa158015620006e1573d6000803e3d6000fd5b505050506040513d6020811015620006f857600080fd5b5051118015620007165750600954600160a01b900463ffffffff165a115b1562000be657806001600160a01b031663d6362e976040518163ffffffff1660e01b8152600401604080518083038186803b1580156200075557600080fd5b505afa1580156200076a573d6000803e3d6000fd5b505050506040513d60408110156200078157600080fd5b508051602090910151909350608084901b1791506200079f62003381565b50600082815260066020908152604091829020825160c0810184528154815260018201549281019290925260028101546001600160a01b039081169383019390935260038101548084166060840152600160a01b900460ff16151560808301526004015490911660a0820152428411156200081e575050505062000bea565b816001600160a01b031663b07576ac6040518163ffffffff1660e01b81526004016040805180830381600087803b1580156200085957600080fd5b505af11580156200086e573d6000803e3d6000fd5b505050506040513d60408110156200088557600080fd5b505060095460408051634f558e7960e01b81526004810186905290516001600160a01b0390921691634f558e7991602480820192602092909190829003018186803b158015620008d457600080fd5b505afa158015620008e9573d6000803e3d6000fd5b505050506040513d60208110156200090057600080fd5b50516200090e575062000690565b600954604080516331a9108f60e11b81526004810186905290516000926001600160a01b031691636352211e916024808301926020929190829003018186803b1580156200095b57600080fd5b505afa15801562000970573d6000803e3d6000fd5b505050506040513d60208110156200098757600080fd5b505160008581526006602052604080822060020180546001600160a01b0319166001600160a01b03808616919091179091556009548251630852cd8d60e31b8152600481018a9052925194955016926342966c689260248084019391929182900301818387803b158015620009fb57600080fd5b505af115801562000a10573d6000803e3d6000fd5b505050508160a001516001600160a01b031662000a2d8562001b2f565b6040516024018080602001828103825283818151815260200191508051906020019080838360005b8381101562000a6f57818101518382015260200162000a55565b50505050905090810190601f16801562000a9d5780820380516001836020036101000a031916815260200191505b5060408051601f198184030181529181526020820180516001600160e01b0316637bd94e0360e01b178152905182519295509350839250908083835b6020831062000afa5780518252601f19909201916020918201910162000ad9565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d806000811462000b5e576040519150601f19603f3d011682016040523d82523d6000602084013e62000b63565b606091505b5050825160408051918252516001600160a01b03808a16935084169187917ffeb2000dca3e617cd6f3a8bbb63014bb54a124aac6ccbf73ee7229b4cd01f1209181900360200190a4816080015162000bde576040516001600160a01b0382169060009067016345785d8a00009082818181858883f150505050505b505062000690565b5050505b50565b67016345785d8a0000341462000c40576040805162461bcd60e51b8152602060048201526013602482015272125b9d985b1a5908109bdb9908185b5bdd5b9d606a1b604482015290519081900360640190fd5b505050565b600a5481565b600354604080516337b1d58560e01b815233600482015290516000926001600160a01b0316916337b1d585916024808301926020929190829003018186803b15801562000c9757600080fd5b505afa15801562000cac573d6000803e3d6000fd5b505050506040513d602081101562000cc357600080fd5b5051600381111562000cd157fe5b141562000d20576040805162461bcd60e51b8152602060048201526018602482015277141491511250d0551157d393d517d055551213d49256915160421b604482015290519081900360640190fd5b600084815260066020526040902060028101546001600160a01b031662000d80576040805162461bcd60e51b815260206004820152600f60248201526e1253959053125117d156125517d251608a1b604482015290519081900360640190fd5b62000d8f858585338662001b8c565b5050505050565b60066020526000908152604090208054600182015460028301546003840154600490940154929391926001600160a01b039182169282811692600160a01b90910460ff16911686565b62000de962000ea6565b62000df357600080fd5b6002546040518291907f06b98f3947a8966918fef150b41170e78ba1d91dd2b1d2fd48a59c91ffbd66a190600090a3600255565b60076020526000908152604090205481565b62000e4362000ea6565b62000e4d57600080fd5b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080546001600160a01b0319169055565b6000546001600160a01b031690565b6000546001600160a01b0316331490565b6003546001600160a01b0316331462000f17576040805162461bcd60e51b815260206004820152601a60248201527f554e415554484f52495a45445f52454749535452595f4f4e4c59000000000000604482015290519081900360640190fd5b60405162000f2590620033b6565b604051809103906000f08015801562000f42573d6000803e3d6000fd5b506001600160a01b03918216600090815260086020526040902080546001600160a01b03191691909216179055565b60008581526006602090815260408083208784526005810190925290912060028201546001600160a01b03161580159062000fb5575080546001600160a01b031615155b62001007576040805162461bcd60e51b815260206004820152601860248201527f496e76616c69642065786974206f7220696e7075742069640000000000000000604482015290519081900360640190fd5b6000600354604080516337b1d58560e01b81526001600160a01b038781166004830152915191909216916337b1d585916024808301926020929190829003018186803b1580156200105757600080fd5b505afa1580156200106c573d6000803e3d6000fd5b505050506040513d60208110156200108357600080fd5b505160038111156200109157fe5b1415620010d9576040805162461bcd60e51b8152602060048201526011602482015270494e56414c49445f50524544494341544560781b604482015290519081900360640190fd5b826001600160a01b031663ec58410c620010f38462001c4b565b620010ff898562001d3a565b88886040518563ffffffff1660e01b815260040180806020018060200180602001848103845288818151815260200191508051906020019080838360005b83811015620011575781810151838201526020016200113d565b50505050905090810190601f168015620011855780820380516001836020036101000a031916815260200191505b50848103835287518152875160209182019189019080838360005b83811015620011ba578181015183820152602001620011a0565b50505050905090810190601f168015620011e85780820380516001836020036101000a031916815260200191505b508481038252858152602001868680828437600081840152601f19601f820116905080830192505050975050505050505050602060405180830381600087803b1580156200123557600080fd5b505af11580156200124a573d6000803e3d6000fd5b505050506040513d60208110156200126157600080fd5b5051620012a8576040805162461bcd60e51b815260206004820152601060248201526f10da185b1b195b99d94819985a5b195960821b604482015290519081900360640190fd5b60095460408051630852cd8d60e31b8152600481018a905290516001600160a01b03909216916342966c689160248082019260009290919082900301818387803b158015620012f657600080fd5b505af11580156200130b573d6000803e3d6000fd5b50506040513392506000915067016345785d8a00009082818181858883f150506040518a93507f93a8052a01c184f88312af177ab8fae2e56a9973b6aa4bdc62dfcf744e09d041925060009150a250505050505050565b600954600160a01b900463ffffffff1681565b600062001381620033c4565b620013c286868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525062001e1492505050565b9050620013ce620033d7565b620013d98262001e4a565b8152620013e68262001e76565b60c082018190528051600090620013f957fe5b01602001516001600160f81b031916156200144c576040805162461bcd60e51b815260206004820152600e60248201526d696e636f7272656374206d61736b60901b604482015290519081900360640190fd5b620014578262001e9c565b6080820152620014678262001eb4565b60a0820152620014a0620014856200147f8462001ecc565b62001fb7565b8260c00151620014958562001fbe565b8460a0015162001fd6565b620014f2576040805162461bcd60e51b815260206004820152601c60248201527f494e56414c49445f524543454950545f4d45524b4c455f50524f4f4600000000604482015290519081900360640190fd5b83156200157557620015236200150883620022de565b8260c001516200151885620022f6565b846080015162001fd6565b62001575576040805162461bcd60e51b815260206004820152601760248201527f494e56414c49445f54585f4d45524b4c455f50524f4f46000000000000000000604482015290519081900360640190fd5b62001580826200230e565b60208201819052620015b490620015978462002326565b608084015160a08501518551620015ae886200233e565b62002356565b6040820152620015c482620024ba565b6060820181905263ffffffff19161562001625576040805162461bcd60e51b815260206004820152601d60248201527f4272616e6368206d61736b2073686f756c642062652033322062697473000000604482015290519081900360640190fd5b806060015160208260200151901b607f620016448460400151620024d2565b901b1717925050505b949350505050565b60005b8181101562000c4057620016888383838181106200167257fe5b905060200201356001600160a01b031662000670565b60010162001658565b6008602052600090815260409020546001600160a01b031681565b600354604080516337b1d58560e01b8152336004820152905187926000926001600160a01b03909116916337b1d58591602480820192602092909190829003018186803b158015620016fd57600080fd5b505afa15801562001712573d6000803e3d6000fd5b505050506040513d60208110156200172957600080fd5b505160035460408051633a9831f160e21b81526001600160a01b0386811660048301529151939450600093919092169163ea60c7c4916024808301926020929190829003018186803b1580156200177f57600080fd5b505afa15801562001794573d6000803e3d6000fd5b505050506040513d6020811015620017ab57600080fd5b50516001600160a01b031614156200180a576040805162461bcd60e51b815260206004820152601760248201527f726f6f74546f6b656e206e6f7420737570706f72746564000000000000000000604482015290519081900360640190fd5b60018160038111156200181957fe5b1415620018e057600354604080516336a8279560e21b81526001600160a01b0385811660048301529151919092169163daa09e54916024808301926020929190829003018186803b1580156200186e57600080fd5b505afa15801562001883573d6000803e3d6000fd5b505050506040513d60208110156200189a57600080fd5b505115620018da5760405162461bcd60e51b815260040180806020018281038252602481526020018062003cf76024913960400191505060405180910390fd5b62001a18565b6002816003811115620018ef57fe5b1415620019b457600354604080516336a8279560e21b81526001600160a01b0385811660048301529151919092169163daa09e54916024808301926020929190829003018186803b1580156200194457600080fd5b505afa15801562001959573d6000803e3d6000fd5b505050506040513d60208110156200197057600080fd5b50511515600114620018da5760405162461bcd60e51b815260040180806020018281038252602581526020018062003ca56025913960400191505060405180910390fd5b6003816003811115620019c357fe5b1415620019d05762001a18565b6040805162461bcd60e51b8152602060048201526018602482015277141491511250d0551157d393d517d055551213d49256915160421b604482015290519081900360640190fd5b60035460408051633a9831f160e21b81526001600160a01b038a811660048301529151828c16939092169163ea60c7c491602480820192602092909190829003018186803b15801562001a6a57600080fd5b505afa15801562001a7f573d6000803e3d6000fd5b505050506040513d602081101562001a9657600080fd5b50516001600160a01b03161462001adf5760405162461bcd60e51b815260040180806020018281038252602381526020018062003d1b6023913960400191505060405180910390fd5b62001af089888888888833620024eb565b505050505050505050565b60025481565b6009546001600160a01b031681565b62001b1a62000ea6565b62001b2457600080fd5b62000bea8162002873565b60008181526006602090815260409182902060038101546002820154915484519384018690526001600160a01b0391821684860152911660608301526080808301919091528251808303909101815260a09091019091525b919050565b604080516060810182526001600160a01b03808616808352858216602080850191825286841685870190815260008c8152600683528781208c82526005018352879020955186549086166001600160a01b03199182161787559251600187018054918716918516919091179055516002909501805495909416949091169390931790915582519081529151869288927f87d2daa6e85f166015ebbcf09f5ee4bc50f93677579339fe128e3561a6807cb692918290030190a35050505050565b6002810154600380549083015460408051633a9831f160e21b81526001600160a01b03928316600482015290516060948316939092169163ea60c7c491602480820192602092909190829003018186803b15801562001ca957600080fd5b505afa15801562001cbe573d6000803e3d6000fd5b505050506040513d602081101562001cd557600080fd5b5051835460018501546003860154604080516001600160a01b03968716602082015295909416858501526060850192909252608084015260ff600160a01b90910416151560a0808401919091528151808403909101815260c090920190529050919050565b80546001820154600354600284015460408051633a9831f160e21b81526001600160a01b039283166004820152905160609588959084169490841693169163ea60c7c4916024808301926020929190829003018186803b15801562001d9e57600080fd5b505afa15801562001db3573d6000803e3d6000fd5b505050506040513d602081101562001dca57600080fd5b50516040805160208101959095526001600160a01b03938416858201529183166060850152919091166080808401919091528151808403909101815260a090920190529392505050565b62001e1e620033c4565b606062001e3562001e2f84620028e2565b62002909565b60408051602081019091529081529392505050565b600062001e70826000015160008151811062001e6257fe5b602002602001015162002a3c565b92915050565b606062001e70826000015160088151811062001e8e57fe5b602002602001015162002a8e565b600062001e70826000015160048151811062001e6257fe5b600062001e70826000015160058151811062001e6257fe5b62001ed66200341a565b62001eec826000015160068151811062001e8e57fe5b602082015262001efb6200343b565b62001f0a8260200151620028e2565b905062001f178162002afa565b1562001f305762001f288162002909565b825262001fa1565b606082602001519050606060018251036040519080825280601f01601f19166020018201604052801562001f6b576020820181803883390190505b50905060008083602101915082602001905062001f8b8282855162002b38565b62001f9a62001e2f84620028e2565b8652505050505b62001fac8362002b87565b604083015250919050565b6020015190565b606062001e70826000015160078151811062001e8e57fe5b600062001fe26200343b565b62001fed84620028e2565b9050606062001ffc8262002909565b905060608085600082620020108b62002b9f565b90508051600014156200202e5760009750505050505050506200164d565b60005b8651811015620022ce57815183111562002057576000985050505050505050506200164d565b620020768782815181106200206857fe5b602002602001015162002ce7565b95508580519060200120841462002099576000985050505050505050506200164d565b620020b8878281518110620020aa57fe5b602002602001015162002909565b9450845160111415620021835781518314156200211b578c80519060200120620020e98660108151811062001e8e57fe5b80519060200120141562002109576001985050505050505050506200164d565b6000985050505050505050506200164d565b60008284815181106200212a57fe5b016020015160f81c905060108111156200215157600099505050505050505050506200164d565b62002173868260ff16815181106200216557fe5b602002602001015162002d54565b94505060019290920191620022c5565b84516002141562002109576060620021a28660008151811062001e8e57fe5b90506000620021b382858762002d72565b90506000620021c460008462002e45565b90508451828701141562002256578f80519060200120620021ec8960018151811062001e8e57fe5b805190602001201480156200222657506001600160f81b03198116600160f91b14806200222657506001600160f81b03198116600360f81b145b15620022415760019b5050505050505050505050506200164d565b60009b5050505050505050505050506200164d565b8115806200228757506001600160f81b03198116158015906200228757506001600160f81b03198116600160f81b14155b15620022a25760009b5050505050505050505050506200164d565b8186019550620022b9886001815181106200216557fe5b9650620022c592505050565b60010162002031565b5050505050505050949350505050565b606062001e708260000151600a8151811062001e8e57fe5b606062001e708260000151600b8151811062001e8e57fe5b600062001e70826000015160028151811062001e6257fe5b600062001e70826000015160038151811062001e6257fe5b606062001e70826000015160018151811062001e8e57fe5b60048054604080516320a9cea560e11b8152928301859052516000928392839283926001600160a01b03909216916341539d4a9160248083019260a0929190829003018186803b158015620023aa57600080fd5b505afa158015620023bf573d6000803e3d6000fd5b505050506040513d60a0811015620023d657600080fd5b810190808051906020019092919080519060200190929190805190602001909291908051906020019092919080519060200190929190505050509350509250925062002470828b0384878d8d8d8d604051602001808581526020018481526020018381526020018281526020019450505050506040516020818303038152906040528051906020012062002ea8909392919063ffffffff16565b620024ad5760405162461bcd60e51b815260040180806020018281038252602d81526020018062003cca602d913960400191505060405180910390fd5b9998505050505050505050565b600062001e70826000015160088151811062001e6257fe5b600062001e706002546002028301600254420162003006565b6000828152600660205260409020600301546001600160a01b0316156200254f576040805162461bcd60e51b8152602060048201526013602482015272455849545f414c52454144595f45584953545360681b604482015290519081900360640190fd5b6040805160c08101825286815260208082018781526001600160a01b03808c168486019081528b8216606086019081528915156080870190815288841660a0880190815260008b8152600690975297862096518088559451600188015591516002870180549185166001600160a01b03199283161790819055915160038801805494511515600160a01b0260ff60a01b199287169584169590951791909116939093179283905596516004870180549185169190981617909655939492936200261f93908216929116906200301f565b90508415620026ad576001600160801b03841660009081526005602052604090205460ff161562002684576040805162461bcd60e51b815260206004820152600a60248201526912d393d5d397d156125560b21b604482015290519081900360640190fd5b6001600160801b0384166000908152600560205260409020805460ff1916600117905562002721565b600081815260076020526040902054156200270f576040805162461bcd60e51b815260206004820152601860248201527f455849545f414c52454144595f494e5f50524f47524553530000000000000000604482015290519081900360640190fd5b60008181526007602052604090208490555b60038201546001600160a01b03908116600090815260086020526040808220548151631d834a1b60e01b8152608089901c60048201526001600160801b038916602482015291519316928392631d834a1b926044808201939182900301818387803b1580156200279057600080fd5b505af1158015620027a5573d6000803e3d6000fd5b50506009546002860154604080516340c10f1960e01b81526001600160a01b039283166004820152602481018b905290519190921693506340c10f199250604480830192600092919082900301818387803b1580156200280457600080fd5b505af115801562002819573d6000803e3d6000fd5b5050604080518b8152891515602082015281516001600160a01b03808f1695508a94508f16927faa5303fdad123ab5ecaefaf69137bf8632257839546d43a3b3dd148cc2879d6f928290030190a450505050505050505050565b6001600160a01b0381166200288757600080fd5b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b620028ec6200343b565b506040805180820190915281518152602082810190820152919050565b6060620029168262002afa565b6200292057600080fd5b60006200292d8362003197565b90506060816040519080825280602002602001820160405280156200296f57816020015b6200295b6200343b565b815260200190600190039081620029515790505b5090506000620029838560200151620031fb565b60208601510190506000805b84811015620029df57620029a38362003267565b9150604051806040016040528083815260200184815250848281518110620029c757fe5b6020908102919091010152918101916001016200298f565b508551602087015183031462002a32576040805162461bcd60e51b81526020600482015260136024820152722bb937b733903a37ba30b6103632b733ba341760691b604482015290519081900360640190fd5b5090949350505050565b80516000901580159062002a5257508151602110155b62002a5c57600080fd5b60008062002a6a8462003303565b8151919350915060208210156200164d5760208290036101000a9004949350505050565b805160609062002a9d57600080fd5b60008062002aab8462003303565b915091506060816040519080825280601f01601f19166020018201604052801562002add576020820181803883390190505b5090506020810162002af18482856200332b565b50949350505050565b805160009062002b0d5750600062001b87565b6020820151805160001a9060c082101562002b2e5760009250505062001b87565b5060019392505050565b8062002b445762000c40565b5b6020811062002b66578251825260209283019290910190601f190162002b45565b915181516020939093036101000a6000190180199091169216919091179052565b600062001e70826000015160098151811062001e6257fe5b60608060008351111562001e705760008062002bbd60008662002e45565b60f81c9050600181148062002bd557508060ff166003145b1562002c535760018551600202036040519080825280601f01601f19166020018201604052801562002c0e576020820181803883390190505b509250600062002c2060018762002e45565b9050808460008151811062002c3157fe5b60200101906001600160f81b031916908160001a905350600192505062002c8e565b60028551600202036040519080825280601f01601f19166020018201604052801562002c86576020820181803883390190505b509250600091505b60ff82165b835181101562002cde5762002cb18360ff1682036002018762002e45565b84828151811062002cbe57fe5b60200101906001600160f81b031916908160001a90535060010162002c93565b50505092915050565b60608082600001516040519080825280601f01601f19166020018201604052801562002d1a576020820181803883390190505b50905080516000141562002d3057905062001b87565b600081602001905062002d4d84602001518286600001516200332b565b5092915050565b805160009060211462002d6657600080fd5b50602001516001015190565b600080606062002d828662002b9f565b9050606081516040519080825280601f01601f19166020018201604052801562002db3576020820181803883390190505b509050845b8251860181101562002e1157600087828151811062002dd357fe5b602001015160f81c60f81b905080838884038151811062002df057fe5b60200101906001600160f81b031916908160001a9053505060010162002db8565b5080805190602001208280519060200120141562002e33578151925062002e38565b600092505b50909150505b9392505050565b6000600283061562002e7a57601082600285048151811062002e6357fe5b016020015160f81c8162002e7357fe5b0662002e9e565b601082600285048151811062002e8c57fe5b016020015160f81c8162002e9c57fe5b045b60f81b9392505050565b6000602082518162002eb657fe5b061562002f01576040805162461bcd60e51b8152602060048201526014602482015273092dcecc2d8d2c840e0e4dedecc40d8cadccee8d60631b604482015290519081900360640190fd5b6000602083518162002f0f57fe5b0490508060020a851062002f62576040805162461bcd60e51b81526020600482015260156024820152744c65616620696e64657820697320746f6f2062696760581b604482015290519081900360640190fd5b60008660205b8551811162002ff8578581015192506002880662002fb7578183604051602001808381526020018281526020019250505060405160208183030381529060405280519060200120915062002fe9565b828260405160200180838152602001828152602001925050506040516020818303038152906040528051906020012091505b60028804975060200162002f68565b509094149695505050505050565b60008183101562003018578162002e3e565b5090919050565b600354604080516336a8279560e21b81526001600160a01b0386811660048301529151600093929092169163daa09e5491602480820192602092909190829003018186803b1580156200307157600080fd5b505afa15801562003086573d6000803e3d6000fd5b505050506040513d60208110156200309d57600080fd5b505115620030f8575060408051606085811b6bffffffffffffffffffffffff199081166020808501919091529186901b1660348301526048808301859052835180840390910181526068909201909252805191012062002e3e565b600082116200314e576040805162461bcd60e51b815260206004820152601860248201527f43414e4e4f545f455849545f5a45524f5f414d4f554e54530000000000000000604482015290519081900360640190fd5b5050604080516bffffffffffffffffffffffff19606094851b81166020808401919091529390941b90931660348401528051602881850301815260489093019052815191012090565b8051600090620031aa5750600062001b87565b60008090506000620031c08460200151620031fb565b602085015185519181019250015b80821015620031f257620031e28262003267565b60019093019290910190620031ce565b50909392505050565b8051600090811a60808110156200321757600091505062001b87565b60b881108062003234575060c0811080159062003234575060f881105b156200324557600191505062001b87565b60c08110156200325b5760b51901905062001b87565b60f51901905062001b87565b80516000908190811a608081101562003284576001915062002d4d565b60b88110156200329b57607e198101915062002d4d565b60c0811015620032ca5760b78103600185019450806020036101000a8551046001820181019350505062002d4d565b60f8811015620032e15760be198101915062002d4d565b60019390930151602084900360f7016101000a900490920160f5190192915050565b6000806000620033178460200151620031fb565b602085015194519481019594039392505050565b80620033375762000c40565b5b6020811062003359578251825260209283019290910190601f190162003338565b801562000c4057915181516020939093036101000a6000190180199091169216919091179052565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a081019190915290565b61084f806200345683390190565b6040518060200160405280606081525090565b6040518060e00160405280600081526020016000815260200160008152602001600081526020016000801916815260200160008019168152602001606081525090565b60405180606001604052806060815260200160608152602001600081525090565b60405180604001604052806000815260200160008152509056fe608060405234801561001057600080fd5b50600080546001600160a01b03191633178082556040516001600160a01b039190911691907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a3604080516020810190915260008152610076906001908161007c565b506100e9565b8280548282559060005260206000209081019282156100bc579160200282015b828111156100bc578251829060ff1690559160200191906001019061009c565b506100c89291506100cc565b5090565b6100e691905b808211156100c857600081556001016100d2565b90565b610757806100f86000396000f3fe608060405234801561001057600080fd5b50600436106100885760003560e01c8063b07576ac1161005b578063b07576ac146100fa578063bda1504b1461011b578063d6362e9714610135578063f2fde38b1461013d57610088565b80631d834a1b1461008d578063715018a6146100b25780638da5cb5b146100ba5780638f32d59b146100de575b600080fd5b6100b0600480360360408110156100a357600080fd5b5080359060200135610163565b005b6100b06101d8565b6100c2610233565b604080516001600160a01b039092168252519081900360200190f35b6100e6610243565b604080519115158252519081900360200190f35b610102610254565b6040805192835260208301919091528051918290030190f35b610123610325565b60408051918252519081900360200190f35b61010261032b565b6100b06004803603602081101561015357600080fd5b50356001600160a01b0316610356565b61016b610243565b61017457600080fd5b6001805480820182556000829052608084901b83177fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf690910181905560025490916101c5919063ffffffff61037316565b60028190556101d39061038e565b505050565b6101e0610243565b6101e957600080fd5b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080546001600160a01b0319169055565b6000546001600160a01b03165b90565b6000546001600160a01b0316331490565b60008061025f610243565b61026857600080fd5b60006001808154811061027757fe5b9060005260206000200154905060016002548154811061029357fe5b9060005260206000200154600180815481106102ab57fe5b90600052602060002001819055506001600254815481106102c857fe5b60009182526020822001556002546102e790600163ffffffff61046216565b6002556102f46001610477565b600180546103079163ffffffff61046216565b6103126001826106e5565b5061031c81610542565b92509250509091565b60025481565b60008061034e6001808154811061033e57fe5b9060005260206000200154610542565b915091509091565b61035e610243565b61036757600080fd5b6103708161055f565b50565b60008282018381101561038557600080fd5b90505b92915050565b600180548291829160009190839081106103a457fe5b906000526020600020015490505b60016103c584600263ffffffff6105cd16565b815481106103cf57fe5b906000526020600020015481101561043a5760016103f484600263ffffffff6105cd16565b815481106103fe57fe5b90600052602060002001546001848154811061041657fe5b60009182526020909120015561043383600263ffffffff6105cd16565b92506103b2565b81831461045c57806001848154811061044f57fe5b6000918252602090912001555b50505050565b60008282111561047157600080fd5b50900390565b6001805482918291600091908390811061048d57fe5b9060005260206000200154905060006104a5846105ef565b90505b60025481111580156104d05750600181815481106104c257fe5b906000526020600020015482115b1561051957600181815481106104e257fe5b9060005260206000200154600185815481106104fa57fe5b600091825260209091200155925082610512816105ef565b90506104a8565b82841461053b57816001858154811061052e57fe5b6000918252602090912001555b5050505050565b608081901c6fffffffffffffffffffffffffffffffff8216915091565b6001600160a01b03811661057257600080fd5b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b60008082116105db57600080fd5b60008284816105e657fe5b04949350505050565b6000600254610619600161060d6002866106be90919063ffffffff16565b9063ffffffff61037316565b11156106375761063082600263ffffffff6106be16565b90506106b9565b600161064e8161060d85600263ffffffff6106be16565b8154811061065857fe5b600091825260209091200154600161067784600263ffffffff6106be16565b8154811061068157fe5b906000526020600020015410156106a35761063082600263ffffffff6106be16565b610630600161060d84600263ffffffff6106be16565b919050565b6000826106cd57506000610388565b828202828482816106da57fe5b041461038557600080fd5b8154818355818111156101d3576000838152602090206101d391810190830161024091905b8082111561071e576000815560010161070a565b509056fea265627a7a72315820eef9af2761b79039c6aab685191650dd90b9be0676920a33d33cbb294da643cd64736f6c6343000511003250726564696361746520737570706f727473206f6e6c792045524337323120746f6b656e7357495448445241575f424c4f434b5f4e4f545f415f504152545f4f465f5355424d49545445445f48454144455250726564696361746520737570706f727473206f6e6c7920455243323020746f6b656e73494e56414c49445f524f4f545f544f5f4348494c445f544f4b454e5f4d415050494e47a265627a7a723158204d8dffbc151999fd1c6483b39e4678d269e0be795d61de6c7bf09fe4ca5065f064736f6c63430005110032

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

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.