Contract 0xd859bc152d041b4b6486e55f8635473b86f3b4ee 1

Contract Overview

Balance:
0 BNB
Txn Hash Method
Block
From
To
Value [Txn Fee]
0x582c7b46e5799f7ec456f33577d9cc4a16db0f3913f436a5ed7386ebb5719c11Set Approval For...121817892021-09-08 7:50:0515 days 10 hrs ago0x704de6e10336c93b53755af1fb7d020149489213 IN  0xd859bc152d041b4b6486e55f8635473b86f3b4ee0 BNB0.00044878
0x245cd246c674bc4156c1fd4b5011a65548ee6af273df8cb4a99f4624b5c2c58bSet Approval For...121571352021-09-07 11:16:2216 days 7 hrs ago0x08e3befef131a1c1526bc8f81ab209099a9c0b4a IN  0xd859bc152d041b4b6486e55f8635473b86f3b4ee0 BNB0.00044878
0xea76e5bf17883e7dab5d5012b2307d00e9a45fe2a8b0082caa72099ffea5c0d0Set Approval For...116469422021-08-20 15:21:4134 days 3 hrs ago0x0bb2b5436daea4340754ec579f0c38d12e987ca0 IN  0xd859bc152d041b4b6486e55f8635473b86f3b4ee0 BNB0.00044878
0x36cd8b5e2fcfa18d436ed95d2c22a4d3fd94b24344bedba987e04b16cb38b1a9Transfer For116454392021-08-20 14:05:3734 days 4 hrs ago0x5c9c39dfe868be7ee04edb425957be479c3dc356 IN  0xd859bc152d041b4b6486e55f8635473b86f3b4ee0 BNB0.00076696
0x8a7635a8527cac89563c8a9f385396e680314b16b821acfa2f667cb02e3a2222Set Approval For...116453512021-08-20 14:01:1334 days 4 hrs ago0x5c9c39dfe868be7ee04edb425957be479c3dc356 IN  0xd859bc152d041b4b6486e55f8635473b86f3b4ee0 BNB0.00044878
0xd8a1d2bc2fd547ab9e23c46a23aa9dc2d3b323571e9a7a747b1d47d107f2ab11Set Approval For...116445272021-08-20 13:20:0134 days 5 hrs ago0x89fca750687b2461d810d5efc35c43a1cd4b4af6 IN  0xd859bc152d041b4b6486e55f8635473b86f3b4ee0 BNB0.00044878
0x2ec70eb9e2dc72ff562a3a7b35c44aaabd48f005977e9588140cc5c70108b5f5Set Approval For...116443022021-08-20 13:08:2734 days 5 hrs ago0xca6a2d72869f69b0086105b2e8242463d4fe70af IN  0xd859bc152d041b4b6486e55f8635473b86f3b4ee0 BNB0.00044878
0xb7c30eee6f51a72cd672291d17fdfd47e26e718543195961716311a764ed1442Transfer For116427802021-08-20 11:51:1034 days 6 hrs ago0x5ea26ee74728f1d76fa00847fc54265a253a606b IN  0xd859bc152d041b4b6486e55f8635473b86f3b4ee0 BNB0.00056262
0x9b7ffdb5dbc4bdb5c091aa74fd99e8e30ae7b4032564b6884f64b15460221e4bTransfer For116427492021-08-20 11:49:3734 days 6 hrs ago0x89fca750687b2461d810d5efc35c43a1cd4b4af6 IN  0xd859bc152d041b4b6486e55f8635473b86f3b4ee0 BNB0.00056262
0x51cc4686163faa12c90ffbf351285095e1bfe8bc0984cba0704cba7e44141308Transfer For116427172021-08-20 11:48:0134 days 6 hrs ago0x5ea26ee74728f1d76fa00847fc54265a253a606b IN  0xd859bc152d041b4b6486e55f8635473b86f3b4ee0 BNB0.00056262
0xb32e6ba9eb125d7a18f37dec141529d455743dc250507c6f90d2dcb2b51a6793Transfer For116426952021-08-20 11:46:5534 days 6 hrs ago0x89fca750687b2461d810d5efc35c43a1cd4b4af6 IN  0xd859bc152d041b4b6486e55f8635473b86f3b4ee0 BNB0.00056262
0xba90d9cace4242ef695bc7ff812f7a99c5e52a57ae94c8d0b953a1a40e47336bTransfer For116426662021-08-20 11:45:2834 days 6 hrs ago0x5ea26ee74728f1d76fa00847fc54265a253a606b IN  0xd859bc152d041b4b6486e55f8635473b86f3b4ee0 BNB0.00056262
0x140cf89017e452d8ddeaf56509d36eb0277177e1c0bfef694e482a1b5830c12aTransfer For116426212021-08-20 11:43:1334 days 6 hrs ago0x89fca750687b2461d810d5efc35c43a1cd4b4af6 IN  0xd859bc152d041b4b6486e55f8635473b86f3b4ee0 BNB0.00056262
0x7db3677c9aeb6736c7a61efbf7075faf74e2f7a0cbc1f537fb22e5746f628e1cTransfer For116425142021-08-20 11:37:5134 days 6 hrs ago0x5ea26ee74728f1d76fa00847fc54265a253a606b IN  0xd859bc152d041b4b6486e55f8635473b86f3b4ee0 BNB0.00056262
0x47704fbfd8690f61e4afe58f43dd4fa890aba53d8cabb674fa066d8bfd89af8cTransfer For116424962021-08-20 11:36:5734 days 6 hrs ago0x89fca750687b2461d810d5efc35c43a1cd4b4af6 IN  0xd859bc152d041b4b6486e55f8635473b86f3b4ee0 BNB0.00056262
0xd51a878a94f851d3cc81f5e520bd0b1eb515f0c005ff7c78a8f6a429e1bf071bTransfer For116424392021-08-20 11:34:0634 days 6 hrs ago0x5ea26ee74728f1d76fa00847fc54265a253a606b IN  0xd859bc152d041b4b6486e55f8635473b86f3b4ee0 BNB0.00056262
0x9ea99f50e80f342afc0eb8136cf8b819e44f3a9f8f4a0451da573ffe765bda3bTransfer For116424252021-08-20 11:33:2434 days 6 hrs ago0x89fca750687b2461d810d5efc35c43a1cd4b4af6 IN  0xd859bc152d041b4b6486e55f8635473b86f3b4ee0 BNB0.00056262
0xb308c70b459889dcc2291ab0b0303833c3a9729a958846577e78255b575b53f7Transfer For116424052021-08-20 11:32:2434 days 6 hrs ago0x5ea26ee74728f1d76fa00847fc54265a253a606b IN  0xd859bc152d041b4b6486e55f8635473b86f3b4ee0 BNB0.00056262
0x5f10fd56b40e848ac04041c2386a1910e3cd210347b263bff17f1f15b369884cTransfer For116420552021-08-20 11:14:2534 days 7 hrs ago0x89fca750687b2461d810d5efc35c43a1cd4b4af6 IN  0xd859bc152d041b4b6486e55f8635473b86f3b4ee0 BNB0.00056262
0xd3c714a5dce27b59babbf25539cb8fd354599f9620291c96c93d5a9b78139be4Transfer For116420282021-08-20 11:13:0434 days 7 hrs ago0x5ea26ee74728f1d76fa00847fc54265a253a606b IN  0xd859bc152d041b4b6486e55f8635473b86f3b4ee0 BNB0.00056262
0x6f89302271409def4a2e25568f2e8f794870d122f239bb82094d90eb7bf6180fTransfer For116417972021-08-20 11:01:3134 days 7 hrs ago0x89fca750687b2461d810d5efc35c43a1cd4b4af6 IN  0xd859bc152d041b4b6486e55f8635473b86f3b4ee0 BNB0.00056262
0xdae761a6d1d7964bb4715c27e575d67d1bd3b959a5c40d62737f0829c66ed355Set Approval For...115853732021-08-18 11:20:1936 days 7 hrs ago0x7256d01695a1d03e96fc75d32215b0519b08e0ba IN  0xd859bc152d041b4b6486e55f8635473b86f3b4ee0 BNB0.00044878
0x2a946c0b3d69f4262d57e3d7a451be4e08c39febd4085a1855100c5f49c16e66Transfer For115852772021-08-18 11:15:3136 days 7 hrs ago0x89fca750687b2461d810d5efc35c43a1cd4b4af6 IN  0xd859bc152d041b4b6486e55f8635473b86f3b4ee0 BNB0.00072004
0x5e2707d7beebd92a7a89db28c1a73a4cf0cad38c6bb6ee19712533cb4d95418d_mint115831852021-08-18 9:30:5536 days 8 hrs ago0xca6a2d72869f69b0086105b2e8242463d4fe70af IN  0xd859bc152d041b4b6486e55f8635473b86f3b4ee0 BNB0.0005661
0x57f17aee25574f00815c090cbbd14f913495ee527dec8cb32abf62954bb7b61c_mint115831812021-08-18 9:30:4336 days 8 hrs ago0xca6a2d72869f69b0086105b2e8242463d4fe70af IN  0xd859bc152d041b4b6486e55f8635473b86f3b4ee0 BNB0.0005661
[ Download CSV Export 
Latest 25 internal transaction
Parent Txn Hash Block From To Value
0xab575f73c93822df6954ea970b47e55df6eccc8f75f828c68d719ae55e60408b123333922021-09-13 14:52:0810 days 3 hrs ago 0xa4c3a4059423f9f0594e323babe0573161de8611 0xd859bc152d041b4b6486e55f8635473b86f3b4ee0 BNB
0xc8bf09b0214f69c94c5cdf7514a455163fe56b95a3e57aebd6bc7494303b924c123333712021-09-13 14:51:0510 days 3 hrs ago 0xa4c3a4059423f9f0594e323babe0573161de8611 0xd859bc152d041b4b6486e55f8635473b86f3b4ee0 BNB
0x0959c2ea585e70232f74cc6bbfca3e8a5079f0d50166bd424a2432a0a18df00c123287482021-09-13 10:59:5610 days 7 hrs ago 0xa4c3a4059423f9f0594e323babe0573161de8611 0xd859bc152d041b4b6486e55f8635473b86f3b4ee0 BNB
0x433f1b26ea2edc0c1e21172ea8593770253b31a981a84b3ff64692cad9593da6121914242021-09-08 15:53:1515 days 2 hrs ago 0xa4c3a4059423f9f0594e323babe0573161de8611 0xd859bc152d041b4b6486e55f8635473b86f3b4ee0 BNB
0x14c92feb105f33e143efaca35a3a5220b430f64fc3af9ed321b022a092ea538c121851022021-09-08 10:37:0915 days 7 hrs ago 0xa4c3a4059423f9f0594e323babe0573161de8611 0xd859bc152d041b4b6486e55f8635473b86f3b4ee0 BNB
0x2ad2282e5c39012323bbb6e711eddba87b514b3e2e74044c12b46f3a7a14f78a121806622021-09-08 6:53:4415 days 11 hrs ago 0xa4c3a4059423f9f0594e323babe0573161de8611 0xd859bc152d041b4b6486e55f8635473b86f3b4ee0 BNB
0xc518e574671484caf31581c8c494d8eaa1ce5ddd1d4290c2e31019486c91feff121791622021-09-08 5:38:4415 days 12 hrs ago 0xa4c3a4059423f9f0594e323babe0573161de8611 0xd859bc152d041b4b6486e55f8635473b86f3b4ee0 BNB
0x75279db087e58ff141b2a46236d7fa7c8f79abfd0522db35187cf76e0ee8aff8121791242021-09-08 5:36:5015 days 12 hrs ago 0xa4c3a4059423f9f0594e323babe0573161de8611 0xd859bc152d041b4b6486e55f8635473b86f3b4ee0 BNB
0x38c57d8eaffd3a59a3133a8b00e5bf5ecb0f6c734c3db6e6884d687c9c51d0b5121673342021-09-07 19:47:2015 days 22 hrs ago 0xa4c3a4059423f9f0594e323babe0573161de8611 0xd859bc152d041b4b6486e55f8635473b86f3b4ee0 BNB
0x74e9ecb3054208a591b0f81f30eeeb339a6a4fb27ed511953af75669191eb3f6121646292021-09-07 17:32:0516 days 54 mins ago 0xa4c3a4059423f9f0594e323babe0573161de8611 0xd859bc152d041b4b6486e55f8635473b86f3b4ee0 BNB
0x5da83474e1145a39080dcbda5cb7b0d143b7877d9b927b48a5d539a209941b9b121638792021-09-07 16:54:3116 days 1 hr ago 0xa4c3a4059423f9f0594e323babe0573161de8611 0xd859bc152d041b4b6486e55f8635473b86f3b4ee0 BNB
0x7408c52c47f15a678a57c95b95932f89cdf78e48fe554b90f2e085a221e704aa121584352021-09-07 12:21:2216 days 6 hrs ago 0xa4c3a4059423f9f0594e323babe0573161de8611 0xd859bc152d041b4b6486e55f8635473b86f3b4ee0 BNB
0x9978883546dd77784ed62cf1d9b186a9285513968f7f7ca508a998c830e44e53121582622021-09-07 12:12:4316 days 6 hrs ago 0xa4c3a4059423f9f0594e323babe0573161de8611 0xd859bc152d041b4b6486e55f8635473b86f3b4ee0 BNB
0x7ac7f6effc45720232350a8f076341c991de933ce4749e0fa06a01e6bab5966c121571492021-09-07 11:17:0416 days 7 hrs ago 0xa4c3a4059423f9f0594e323babe0573161de8611 0xd859bc152d041b4b6486e55f8635473b86f3b4ee0 BNB
0x68812e6b233a334a01ba73c1e9161e421200cdf2ccad76afb17bcfc7cccc0807117891662021-08-25 14:42:1429 days 3 hrs ago 0xa4c3a4059423f9f0594e323babe0573161de8611 0xd859bc152d041b4b6486e55f8635473b86f3b4ee0 BNB
0x5ba76068bc15759b2639adfac793a315d31d781c323bab02b6d5f6df1c6f834b116480182021-08-20 16:15:4234 days 2 hrs ago 0xa4c3a4059423f9f0594e323babe0573161de8611 0xd859bc152d041b4b6486e55f8635473b86f3b4ee0 BNB
0x030c6a6c1f778bd880e1e56a5df1a73b4359276107bd9c1cf1f92c5d3c3ab4e9116479952021-08-20 16:14:3334 days 2 hrs ago 0xa4c3a4059423f9f0594e323babe0573161de8611 0xd859bc152d041b4b6486e55f8635473b86f3b4ee0 BNB
0x865ee20a6b89e807eef687ce81c1da5bced61211baa214fedb3728befd1c5283116469492021-08-20 15:22:0234 days 3 hrs ago 0xa4c3a4059423f9f0594e323babe0573161de8611 0xd859bc152d041b4b6486e55f8635473b86f3b4ee0 BNB
0xe506de9700b6c8e1db4f8cca3014bc675474f5c9bc8534996c6098474a23ea21116466272021-08-20 15:05:5634 days 3 hrs ago 0xa4c3a4059423f9f0594e323babe0573161de8611 0xd859bc152d041b4b6486e55f8635473b86f3b4ee0 BNB
0xba239891509a596c2a939ed878a5847e2ba828cbb5fe5c32373c74a0fc56e95d116465802021-08-20 15:03:3534 days 3 hrs ago 0xa4c3a4059423f9f0594e323babe0573161de8611 0xd859bc152d041b4b6486e55f8635473b86f3b4ee0 BNB
0x1cb54893ba59e11f320bc638ece92d11f2183973cad639e7657b119087e82d75116464922021-08-20 14:59:0134 days 3 hrs ago 0xa4c3a4059423f9f0594e323babe0573161de8611 0xd859bc152d041b4b6486e55f8635473b86f3b4ee0 BNB
0xd043deaded393702b7e622f44ea0687cf39fe09dbf287b60ce26f405643c0211116464842021-08-20 14:58:3734 days 3 hrs ago 0xa4c3a4059423f9f0594e323babe0573161de8611 0xd859bc152d041b4b6486e55f8635473b86f3b4ee0 BNB
0xc588a0a0cbe379548b2c880bf7ad36963a3e2d083c018b7db39119446db13cf9116464412021-08-20 14:56:2834 days 3 hrs ago 0xa4c3a4059423f9f0594e323babe0573161de8611 0xd859bc152d041b4b6486e55f8635473b86f3b4ee0 BNB
0xf7896ea1145e7e3895e0d8b0128f9429a60ef8af46874dca80e453ecabdab9d5116461622021-08-20 14:42:2934 days 3 hrs ago 0xbc1e512266c48501672e011817127accb731e9f3 0xd859bc152d041b4b6486e55f8635473b86f3b4ee0 BNB
0x5d9bc7933b84dacefbd100759227faab4936537c41a89f281d6e02d435256b4f116454052021-08-20 14:03:5534 days 4 hrs ago 0xa4c3a4059423f9f0594e323babe0573161de8611 0xd859bc152d041b4b6486e55f8635473b86f3b4ee0 BNB
[ Download CSV Export 
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
GravisCollectible

Compiler Version
v0.6.2+commit.bacdbe57

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 15 : GravisCollectible.sol
pragma solidity =0.6.2;

import "@openzeppelin/contracts/introspection/ERC165.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721Enumerable.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721Metadata.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import "./GravisCollectionMintable.sol";
import "./Whitelist.sol";

/**
 * @title GravisCollectible - Collectible token implementation,
 * from Gravis project, based on OpenZeppelin eip-721 implementation.
 *
 * @author Darth Andeddu <[email protected]>
 */
contract GravisCollectible is GravisCollectionMintable, Whitelist, ERC165, IERC721, IERC721Metadata, IERC721Enumerable {
    using SafeMath for uint256;

    // Bitmask size in slots (256 bit words) to fit all NFTs in the round
    uint256 internal constant VAULT_SIZE_SLOTS = 10;

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

    struct TokenVault {
        uint256[VAULT_SIZE_SLOTS] data;
    }
    struct TypeData {
        address minterOnly;
        string info;
        uint256 nominalPrice;
        uint256 totalSupply;
        uint256 maxSupply;
        TokenVault vault;
        string uri;
    }

    TypeData[] private typeData;
    mapping(address => TokenVault) private tokens;
    mapping(uint256 => address) private _tokenApprovals;
    mapping(address => mapping(address => bool)) private _operatorApprovals;
    uint256 public last = 0;
    string public baseURI;

    /*
     *     bytes4(keccak256('balanceOf(address)')) == 0x70a08231
     *     bytes4(keccak256('ownerOf(uint256)')) == 0x6352211e
     *     bytes4(keccak256('approve(address,uint256)')) == 0x095ea7b3
     *     bytes4(keccak256('getApproved(uint256)')) == 0x081812fc
     *     bytes4(keccak256('setApprovalForAll(address,bool)')) == 0xa22cb465
     *     bytes4(keccak256('isApprovedForAll(address,address)')) == 0xe985e9c5
     *     bytes4(keccak256('transferFrom(address,address,uint256)')) == 0x23b872dd
     *     bytes4(keccak256('safeTransferFrom(address,address,uint256)')) == 0x42842e0e
     *     bytes4(keccak256('safeTransferFrom(address,address,uint256,bytes)')) == 0xb88d4fde
     *
     *     => 0x70a08231 ^ 0x6352211e ^ 0x095ea7b3 ^ 0x081812fc ^
     *        0xa22cb465 ^ 0xe985e9c5 ^ 0x23b872dd ^ 0x42842e0e ^ 0xb88d4fde == 0x80ac58cd
     */
    bytes4 private constant _INTERFACE_ID_ERC721 = 0x80ac58cd;

    /*
     *     bytes4(keccak256('name()')) == 0x06fdde03
     *     bytes4(keccak256('symbol()')) == 0x95d89b41
     *     bytes4(keccak256('tokenURI(uint256)')) == 0xc87b56dd
     *
     *     => 0x06fdde03 ^ 0x95d89b41 ^ 0xc87b56dd == 0x5b5e139f
     */
    bytes4 private constant _INTERFACE_ID_ERC721_METADATA = 0x5b5e139f;

    /*
     *     bytes4(keccak256('totalSupply()')) == 0x18160ddd
     *     bytes4(keccak256('tokenOfOwnerByIndex(address,uint256)')) == 0x2f745c59
     *     bytes4(keccak256('tokenByIndex(uint256)')) == 0x4f6ccce7
     *
     *     => 0x18160ddd ^ 0x2f745c59 ^ 0x4f6ccce7 == 0x780e9d63
     */
    bytes4 private constant _INTERFACE_ID_ERC721_ENUMERABLE = 0x780e9d63;

    /**
     * @dev Initializes the contract.
     */
    constructor() public {
        // register the supported interfaces to conform to ERC721 via ERC165
        _registerInterface(_INTERFACE_ID_ERC721);
        _registerInterface(_INTERFACE_ID_ERC721_METADATA);
        _registerInterface(_INTERFACE_ID_ERC721_ENUMERABLE);
    }

    /**
     * @dev Returns the token collection name.
     */
    function name() external view override returns (string memory) {
        return "Gravis Cards Collection";
    }

    /**
     * @dev Returns the token collection symbol.
     */
    function symbol() external view override returns (string memory) {
        return "GRVSNFT";
    }

    /**
     * @dev Returns the number of decimals used to get its user representation.
     */
    function decimals() public pure virtual returns (uint8) {
        return 0;
    }

    /**
     * @dev Default transfer from ERC20 is not possible so disabled.
     */
    function transfer(address, uint256) public pure virtual returns (bool) {
        require(false, "This type of token cannot be transferred from this type of wallet");
    }

    /**
     * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
     */
    function tokenURI(uint256 _tokenId) external view override returns (string memory) {
        uint256 typ = getTokenType(_tokenId);
        require(typ != uint256(-1), "ERC721Metadata: URI query for nonexistent token");

        return string(abi.encodePacked(baseURI, typeData[typ].uri));
    }

    /**
     * @dev Returns the balance for the `_who` address.
     */
    function balanceOf(address _who) public view override returns (uint256 res) {
        TokenVault storage cur = tokens[_who];
        for (uint256 index = 0; index < VAULT_SIZE_SLOTS; ++index) {
            uint256 val = cur.data[index];
            while (val != 0) {
                val &= val - 1;
                ++res;
            }
        }
    }

    /**
     * @dev See {IERC721Enumerable-tokenOfOwnerByIndex}.
     */
    function tokenOfOwnerByIndex(address _who, uint256 _index) public view virtual override returns (uint256) {
        TokenVault storage vault = tokens[_who];
        uint256 index = 0;
        uint256 bit = 0;
        uint256 cnt = 0;
        while (true) {
            uint256 val = vault.data[index];
            if (val != 0) {
                while (bit < 256 && (val & (1 << bit) == 0)) ++bit;
            }
            if (val == 0 || bit == 256) {
                bit = 0;
                ++index;
                require(index < VAULT_SIZE_SLOTS, "GravisCollectible: not enough tokens");
                continue;
            }
            if (cnt == _index) break;
            ++cnt;
            ++bit;
        }
        return index * 256 + bit;
    }

    /**
     * @dev See {IERC721Enumerable-totalSupply}.
     */
    function totalSupply() public view virtual override returns (uint256 res) {
        for (uint256 i = 0; i < typeData.length; ++i) {
            res += typeData[i].totalSupply;
        }
    }

    /**
     * @dev See {IERC721Enumerable-tokenByIndex}.
     */
    function tokenByIndex(uint256 index) public view virtual override returns (uint256) {
        return index;
    }

    /**
     * @dev Returns data about token collection by type id `_typeId`.
     */
    function getTypeInfo(uint256 _typeId)
        public
        view
        returns (
            uint256 nominalPrice,
            uint256 capSupply,
            uint256 maxSupply,
            string memory info,
            address minterOnly,
            string memory uri
        )
    {
        TypeData memory t = typeData[_typeId];

        return (t.nominalPrice, t.totalSupply, t.maxSupply, t.info, t.minterOnly, t.uri);
    }

    /**
     * @dev Returns token type by token id `_tokenId`.
     */
    function getTokenType(uint256 _tokenId) public view returns (uint256) {
        if (_tokenId < last) {
            (uint256 index, uint256 mask) = _position(_tokenId);
            for (uint256 i = 0; i < typeData.length; ++i) {
                if (typeData[i].vault.data[index] & mask != 0) return i;
            }
        }
        return uint256(-1);
    }

    /**
     * @dev See {IERC721-approve}.
     */
    function approve(address _to, uint256 _tokenId) public virtual override {
        require(_to != _msgSender(), "ERC721: approval to current owner");
        require(isOwner(_msgSender(), _tokenId), "ERC721: approve caller is not owner");

        _approve(_to, _tokenId);
    }

    /**
     * @dev See {IERC721-getApproved}.
     */
    function getApproved(uint256 _tokenId) public view virtual override returns (address) {
        require(exists(_tokenId), "ERC721: approved query for nonexistent token");

        return _tokenApprovals[_tokenId];
    }

    /**
     * @dev See {IERC721-setApprovalForAll}.
     */
    function setApprovalForAll(address _operator, bool _approved) public virtual override {
        require(_operator != _msgSender(), "ERC721: approve to caller");

        _operatorApprovals[_msgSender()][_operator] = _approved;
        emit ApprovalForAll(_msgSender(), _operator, _approved);
    }

    /**
     * @dev See {IERC721-isApprovedForAll}.
     */
    function isApprovedForAll(address _owner, address _operator) public view virtual override returns (bool) {
        return _operatorApprovals[_owner][_operator];
    }

    /**
     * @dev See {IERC721-transferFrom}.
     */
    function transferFrom(
        address _from,
        address _to,
        uint256 _tokenId
    ) public virtual override {
        require(_isApprovedOrOwner(_msgSender(), _tokenId), "ERC721: transfer caller is not owner nor approved");

        _transfer(_from, _to, _tokenId);
    }

    /**
     * @dev See {IERC721-safeTransferFrom}.
     */
    function safeTransferFrom(
        address _from,
        address _to,
        uint256 _tokenId
    ) public virtual override {
        safeTransferFrom(_from, _to, _tokenId, "");
    }

    /**
     * @dev See {IERC721-safeTransferFrom}.
     */
    function safeTransferFrom(
        address _from,
        address _to,
        uint256 _tokenId,
        bytes memory _data
    ) public virtual override {
        require(_isApprovedOrOwner(_msgSender(), _tokenId), "ERC721: transfer caller is not owner nor approved");

        _safeTransfer(_from, _to, _tokenId, _data);
    }

    /**
     * @dev See {ERC71-_exists}.
     */
    function exists(uint256 _tokenId) public view returns (bool) {
        return getTokenType(_tokenId) != uint256(-1);
    }

    /**
     * @dev See {ERC71-_setBaseURI}.
     */
    function setBaseURI(string memory _baseURI) public onlyAdmin {
        baseURI = _baseURI;
    }

    /**
     * @dev Create new token collection, with uniq id.
     *
     * Permission: onlyAdmin
     *
     * @param _nominalPrice - nominal price per item, should be set in USD,
     *        with decimal zero
     * @param _maxTotal - maximum total amount items in collection
     * @param _info - general information about collection
     * @param _uri - JSON metadata address based on `baseURI`
     */
    function createNewTokenType(
        uint256 _nominalPrice,
        uint256 _maxTotal,
        string memory _info,
        string memory _uri
    ) public onlyAdmin {
        require(_nominalPrice != 0, "GravisCollectible: nominal price is zero");

        TypeData memory t;
        t.nominalPrice = _nominalPrice;
        t.maxSupply = _maxTotal;
        t.info = _info;
        t.uri = _uri;

        typeData.push(t);
    }

    /**
     * @dev Setter for lock minter rights by `_minter` and `_type`.
     *
     * Permission: onlyAdmin
     */
    function setMinterOnly(address _minter, uint256 _type) external onlyAdmin {
        require(typeData[_type].minterOnly == address(0), "GravisCollectible: minter locked already");

        typeData[_type].minterOnly = _minter;
    }

    /**
     * @dev Add new user with MINTER_ROLE permission.
     *
     * Permission: onlyAdmin
     */
    function addMinter(address _newMinter) public onlyAdmin {
        _setupRole(MINTER_ROLE, _newMinter);
    }

    /**
     * @dev Mint one NFT token to specific address `_to` with specific type id `_type`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function mint(
        address _to,
        uint256 _type,
        uint256 _amount
    ) public returns (uint256) {
        require(hasRole(MINTER_ROLE, _msgSender()), "GravisCollectible: must have minter role to mint");
        require(_type < typeData.length, "GravisCollectible: type not exist");
        TypeData storage currentType = typeData[_type];
        if (currentType.minterOnly != address(0)) {
            require(typeData[_type].minterOnly == _msgSender(), "GravisCollectible: minting locked by another account");
        }

        return _mint(_to, _type, _amount);
    }

    function mintFor(address[] calldata _to, uint256[] calldata _amount, uint256 _type) external {
        require(hasRole(MINTER_ROLE, _msgSender()), "GravisCollectible: must have minter role to mint");
        require(_to.length == _amount.length, "GravisCollectible: input arrays don't match");
        require(_type < typeData.length, "GravisCollectible: type not exist");
        TypeData storage currentType = typeData[_type];
        if (currentType.minterOnly != address(0)) {
            require(typeData[_type].minterOnly == _msgSender(), "GravisCollectible: minting locked by another account");
        }

        for (uint256 i = 0; i < _to.length; ++i) {
            _mint(_to[i], _type, _amount[i]);
        }
    }

    function _mint(
        address _to,
        uint256 _type,
        uint256 _amount
    ) public returns (uint256) {
        require(_to != address(0), "GravisCollectible: mint to the zero address");

        TypeData storage currentType = typeData[_type];
        TokenVault storage currentOwner = tokens[_to];
        uint256 tokenId = last;
        (uint256 index, uint256 mask) = _position(tokenId);
        while (tokenId < last.add(_amount)) {
            currentType.vault.data[index] |= mask;
            currentOwner.data[index] |= mask;
            mask <<= 1;
            if (mask == 0) {
                mask = 1;
                ++index;
            }
            emit Transfer(address(0), _to, tokenId);
            ++tokenId;
        }
        last = tokenId;
        typeData[_type].totalSupply = typeData[_type].totalSupply.add(_amount);

        require(typeData[_type].totalSupply <= typeData[_type].maxSupply, "GravisCollectible: max supply reached");

        return last;
    }

    /**
     * @dev Moves one NFT token to specific address `_to` with specific token id `_tokenId`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFromContract(address _to, uint256 _tokenId) public onlyAdmin returns (bool) {
        _transfer(address(this), _to, _tokenId);

        return true;
    }

    /**
     * @dev Returns address of the caller if the token `_tokenId` belongs to her, 0 otherwise.
     */
    function ownerOf(uint256 _tokenId) public view override returns (address) {
        if (isOwner(_msgSender(), _tokenId)) return _msgSender();
        return address(0);
    }

    /**
     * @dev Returns true if `_who` owns token `_tokenId`.
     */
    function isOwner(address _who, uint256 _tokenId) public view returns (bool) {
        (uint256 index, uint256 mask) = _position(_tokenId);
        return tokens[_who].data[index] & mask != 0;
    }

    /**
     * @dev See {ERC71-_burn}.
     */
    function burn(uint256 _tokenId) public {
        _burnFor(_msgSender(), _tokenId);
    }

    /**
     * @dev Burn `_amount` tokens ot type `_type` for account `_who`.
     */
    function burnFor(
        address _who,
        uint256 _type,
        uint256 _amount
    ) public {
        require(_who == _msgSender() || isApprovedForAll(_who, _msgSender()), "GravisCollectible: must have approval");
        require(_type < typeData.length, "GravisCollectible: type not exist");

        TokenVault storage vaultUser = tokens[_who];
        TokenVault storage vaultType = typeData[_type].vault;
        uint256 index = 0;
        uint256 bit = 0;
        uint256 burned = 0;
        while (burned < _amount) {
            uint256 val = vaultUser.data[index];
            if (val != 0) {
                while (bit < 256 && (val & (1 << bit) == 0 || vaultType.data[index] & (1 << bit) == 0)) ++bit;
            }
            if (val == 0 || bit == 256) {
                bit = 0;
                ++index;
                require(index < VAULT_SIZE_SLOTS, "GravisCollectible: not enough tokens");
                continue;
            }
            uint256 tokenId = index * 256 + bit;
            _approve(address(0), tokenId);
            uint256 mask = ~(1 << bit);
            vaultUser.data[index] &= mask;
            vaultType.data[index] &= mask;
            emit Transfer(_who, address(0), tokenId);
            ++burned;
        }
    }

    /**
     * @dev Transfer `_amount` tokens ot type `_type` between accounts `_from` and `_to`.
     */
    function transferFor(
        address _from,
        address _to,
        uint256 _type,
        uint256 _amount
    ) public {
        require(_from == _msgSender() || isApprovedForAll(_from, _msgSender()), "GravisCollectible: must have approval");
        require(_type < typeData.length, "GravisCollectible: type not exist");

        TokenVault storage vaultFrom = tokens[_from];
        TokenVault storage vaultTo = tokens[_to];
        TokenVault storage vaultType = typeData[_type].vault;
        uint256 index = 0;
        uint256 bit = 0;
        uint256 transfered = 0;
        while (transfered < _amount) {
            uint256 val = vaultFrom.data[index];
            if (val != 0) {
                while (bit < 256 && (val & (1 << bit) == 0 || vaultType.data[index] & (1 << bit) == 0)) ++bit;
            }
            if (val == 0 || bit == 256) {
                bit = 0;
                ++index;
                require(index < VAULT_SIZE_SLOTS, "GravisCollectible: not enough tokens");
                continue;
            }
            uint256 tokenId = index * 256 + bit;
            _approve(address(0), tokenId);
            uint256 mask = 1 << bit;
            vaultTo.data[index] |= mask;
            vaultFrom.data[index] &= ~mask;
            emit Transfer(_from, _to, tokenId);
            ++transfered;
        }
    }

    /**
     * @dev Approve `_to` to operate on `_tokenId`
     *
     * Emits an {Approval} event.
     */
    function _approve(address _to, uint256 _tokenId) internal virtual {
        if (_tokenApprovals[_tokenId] != _to) {
            _tokenApprovals[_tokenId] = _to;
            emit Approval(_msgSender(), _to, _tokenId); // internal owner
        }
    }

    /**
     * @dev Burn a single token `_tokenId` for address `_who`.
     */
    function _burnFor(address _who, uint256 _tokenId) internal virtual {
        (uint256 index, uint256 mask) = _position(_tokenId);
        require(tokens[_who].data[index] & mask != 0, "not owner");

        _approve(address(0), _tokenId);

        mask = ~mask;
        tokens[_who].data[index] &= mask;
        for (uint256 i = 0; i < typeData.length; ++i) {
            typeData[i].vault.data[index] &= mask;
        }

        emit Transfer(_who, address(0), _tokenId);
    }

    /**
     * @dev Transfers `_tokenId` from `_from` to `_to`.
     *  As opposed to {transferFrom}, this imposes no restrictions on msg.sender.
     *
     * Emits a {Transfer} event.
     */
    function _transfer(
        address _from,
        address _to,
        uint256 _tokenId
    ) internal virtual {
        require(isOwner(_from, _tokenId), "ERC721: transfer of token that is not own"); // internal owner
        require(_to != address(0), "ERC721: transfer to the zero address");

        // Clear approvals from the previous owner
        _approve(address(0), _tokenId);

        (uint256 index, uint256 mask) = _position(_tokenId);
        tokens[_from].data[index] &= ~mask;
        tokens[_to].data[index] |= mask;

        emit Transfer(_from, _to, _tokenId);
    }

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
     * are aware of the ERC721 protocol to prevent tokens from being forever locked.
     *
     * `_data` is additional data, it has no specified format and it is sent in call to `to`.
     *
     * Emits a {Transfer} event.
     */
    function _safeTransfer(
        address _from,
        address _to,
        uint256 _tokenId,
        bytes memory _data
    ) internal virtual {
        _transfer(_from, _to, _tokenId);
        require(
            _checkOnERC721Received(_from, _to, _tokenId, _data),
            "ERC721: transfer to non ERC721Receiver implementer"
        );
    }

    /**
     * @dev Internal function to invoke {IERC721Receiver-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
    ) private returns (bool) {
        if (!_to.isContract()) {
            return true;
        }
        bytes memory returndata =
            _to.functionCall(
                abi.encodeWithSelector(
                    IERC721Receiver(_to).onERC721Received.selector,
                    _msgSender(),
                    _from,
                    _tokenId,
                    _data
                ),
                "ERC721: transfer to non ERC721Receiver implementer"
            );
        bytes4 retval = abi.decode(returndata, (bytes4));
        return (retval == _ERC721_RECEIVED);
    }

    /**
     * @dev Returns whether `_spender` is allowed to manage `_tokenId`.
     */
    function _isApprovedOrOwner(address _spender, uint256 _tokenId) internal view virtual returns (bool) {
        if (isOwner(_spender, _tokenId)) return true;
        return (getApproved(_tokenId) == _spender);
    }

    function _position(uint256 _tokenId) internal pure returns (uint256 index, uint256 mask) {
        index = _tokenId / 256;
        require(index < VAULT_SIZE_SLOTS, "GravisCollectible: OOB");
        mask = uint256(1 << (_tokenId % 256));
    }
}

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

pragma solidity >=0.6.0 <0.8.0;

import "./IERC165.sol";

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts may inherit from this and call {_registerInterface} to declare
 * their support of an interface.
 */
abstract contract ERC165 is IERC165 {
    /*
     * bytes4(keccak256('supportsInterface(bytes4)')) == 0x01ffc9a7
     */
    bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7;

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

    constructor () internal {
        // Derived contracts need only register support for their own interfaces,
        // we register support for ERC165 itself here
        _registerInterface(_INTERFACE_ID_ERC165);
    }

    /**
     * @dev See {IERC165-supportsInterface}.
     *
     * Time complexity O(1), guaranteed to always use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return _supportedInterfaces[interfaceId];
    }

    /**
     * @dev Registers the contract as an implementer of the interface defined by
     * `interfaceId`. Support of the actual ERC165 interface is automatic and
     * registering its interface id is not required.
     *
     * See {IERC165-supportsInterface}.
     *
     * Requirements:
     *
     * - `interfaceId` cannot be the ERC165 invalid interface (`0xffffffff`).
     */
    function _registerInterface(bytes4 interfaceId) internal virtual {
        require(interfaceId != 0xffffffff, "ERC165: invalid interface id");
        _supportedInterfaces[interfaceId] = true;
    }
}

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

pragma solidity >=0.6.0 <0.8.0;

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

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

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

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

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

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

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

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

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

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

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

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

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

File 4 of 15 : IERC721.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.2 <0.8.0;

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

/**
 * @dev Required interface of an ERC721 compliant contract.
 */
interface IERC721 is IERC165 {
    /**
     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
     */
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
     */
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
     */
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    /**
     * @dev Returns the number of tokens in ``owner``'s account.
     */
    function balanceOf(address owner) external view returns (uint256 balance);

    /**
     * @dev Returns the owner of the `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function ownerOf(uint256 tokenId) external view returns (address owner);

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
     * are aware of the ERC721 protocol to prevent tokens from being forever locked.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId) external;

    /**
     * @dev Transfers `tokenId` token from `from` to `to`.
     *
     * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 tokenId) external;

    /**
     * @dev Gives permission to `to` to transfer `tokenId` token to another account.
     * The approval is cleared when the token is transferred.
     *
     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
     *
     * Requirements:
     *
     * - The caller must own the token or be an approved operator.
     * - `tokenId` must exist.
     *
     * Emits an {Approval} event.
     */
    function approve(address to, uint256 tokenId) external;

    /**
     * @dev Returns the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) external view returns (address operator);

    /**
     * @dev Approve or remove `operator` as an operator for the caller.
     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
     *
     * Requirements:
     *
     * - The `operator` cannot be the caller.
     *
     * Emits an {ApprovalForAll} event.
     */
    function setApprovalForAll(address operator, bool _approved) external;

    /**
     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
     *
     * See {setApprovalForAll}
     */
    function isApprovedForAll(address owner, address operator) external view returns (bool);

    /**
      * @dev Safely transfers `tokenId` token from `from` to `to`.
      *
      * Requirements:
      *
      * - `from` cannot be the zero address.
      * - `to` cannot be the zero address.
      * - `tokenId` token must exist and be owned by `from`.
      * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
      * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
      *
      * Emits a {Transfer} event.
      */
    function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
}

File 5 of 15 : IERC721Enumerable.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.2 <0.8.0;

import "./IERC721.sol";

/**
 * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
 * @dev See https://eips.ethereum.org/EIPS/eip-721
 */
interface IERC721Enumerable is IERC721 {

    /**
     * @dev Returns the total amount of tokens stored by the contract.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns a token ID owned by `owner` at a given `index` of its token list.
     * Use along with {balanceOf} to enumerate all of ``owner``'s tokens.
     */
    function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256 tokenId);

    /**
     * @dev Returns a token ID at a given `index` of all the tokens stored by the contract.
     * Use along with {totalSupply} to enumerate all tokens.
     */
    function tokenByIndex(uint256 index) external view returns (uint256);
}

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

pragma solidity >=0.6.2 <0.8.0;

import "./IERC721.sol";

/**
 * @title ERC-721 Non-Fungible Token Standard, optional metadata extension
 * @dev See https://eips.ethereum.org/EIPS/eip-721
 */
interface IERC721Metadata is IERC721 {

    /**
     * @dev Returns the token collection name.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the token collection symbol.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
     */
    function tokenURI(uint256 tokenId) external view returns (string memory);
}

File 7 of 15 : IERC721Receiver.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @title ERC721 token receiver interface
 * @dev Interface for any contract that wants to support safeTransfers
 * from ERC721 asset contracts.
 */
interface IERC721Receiver {
    /**
     * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
     * by `operator` from `from`, this function is called.
     *
     * It must return its Solidity selector to confirm the token transfer.
     * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
     *
     * The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`.
     */
    function onERC721Received(address operator, address from, uint256 tokenId, bytes calldata data) external returns (bytes4);
}

File 8 of 15 : GravisCollectionMintable.sol
pragma solidity =0.6.2;

import {Context, AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol";

contract GravisCollectionMintable is Context, AccessControl {
    bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");

    constructor() public {
        _setupRole(DEFAULT_ADMIN_ROLE, _msgSender());
    }

    modifier onlyAdmin() {
        require(hasRole(DEFAULT_ADMIN_ROLE, _msgSender()), "GravisCollectible: must have admin role");
        _;
    }
}

File 9 of 15 : Whitelist.sol
pragma solidity =0.6.2;

import "@openzeppelin/contracts/access/Ownable.sol";

/**
 * @title Whitelist
 * @author Alberto Cuesta Canada
 * @dev Implements a simple whitelist of addresses.
 */
contract Whitelist is Ownable {
    event MemberAdded(address member);
    event MemberRemoved(address member);

    mapping(address => bool) private members;
    uint256 public whitelisted;

    /**
     * @dev A method to verify whether an address is a member of the whitelist
     * @param _member The address to verify.
     * @return Whether the address is a member of the whitelist.
     */
    function isMember(address _member) public view returns (bool) {
        return members[_member];
    }

    /**
     * @dev A method to add a member to the whitelist
     * @param _member The member to add as a member.
     */
    function addMember(address _member) public onlyOwner {
        address[] memory mem = new address[](1);
        mem[0] = _member;
        _addMembers(mem);
    }

    /**
     * @dev A method to add a member to the whitelist
     * @param _members The members to add as a member.
     */
    function addMembers(address[] memory _members) public onlyOwner {
        _addMembers(_members);
    }

    /**
     * @dev A method to remove a member from the whitelist
     * @param _member The member to remove as a member.
     */
    function removeMember(address _member) public onlyOwner {
        require(isMember(_member), "Whitelist: Not member of whitelist");

        delete members[_member];
        --whitelisted;
        emit MemberRemoved(_member);
    }

    function _addMembers(address[] memory _members) internal {
        uint256 l = _members.length;
        for (uint256 i = 0; i < l; i++) {
            require(!isMember(_members[i]), "Whitelist: Address is member already");

            members[_members[i]] = true;
            emit MemberAdded(_members[i]);
        }
        whitelisted += _members.length;
    }

    /**
     * @dev Access modifier for whitelisted members.
     */
    modifier canParticipate() {
        require(whitelisted == 0 || isMember(msg.sender), "Seller: not from private list");
        _;
    }
}

File 10 of 15 : IERC165.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

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

pragma solidity >=0.6.0 <0.8.0;

import "../utils/EnumerableSet.sol";
import "../utils/Address.sol";
import "../utils/Context.sol";

/**
 * @dev Contract module that allows children to implement role-based access
 * control mechanisms.
 *
 * Roles are referred to by their `bytes32` identifier. These should be exposed
 * in the external API and be unique. The best way to achieve this is by
 * using `public constant` hash digests:
 *
 * ```
 * bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
 * ```
 *
 * Roles can be used to represent a set of permissions. To restrict access to a
 * function call, use {hasRole}:
 *
 * ```
 * function foo() public {
 *     require(hasRole(MY_ROLE, msg.sender));
 *     ...
 * }
 * ```
 *
 * Roles can be granted and revoked dynamically via the {grantRole} and
 * {revokeRole} functions. Each role has an associated admin role, and only
 * accounts that have a role's admin role can call {grantRole} and {revokeRole}.
 *
 * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
 * that only accounts with this role will be able to grant or revoke other
 * roles. More complex role relationships can be created by using
 * {_setRoleAdmin}.
 *
 * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
 * grant and revoke this role. Extra precautions should be taken to secure
 * accounts that have been granted it.
 */
abstract contract AccessControl is Context {
    using EnumerableSet for EnumerableSet.AddressSet;
    using Address for address;

    struct RoleData {
        EnumerableSet.AddressSet members;
        bytes32 adminRole;
    }

    mapping (bytes32 => RoleData) private _roles;

    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;

    /**
     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
     *
     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
     * {RoleAdminChanged} not being emitted signaling this.
     *
     * _Available since v3.1._
     */
    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);

    /**
     * @dev Emitted when `account` is granted `role`.
     *
     * `sender` is the account that originated the contract call, an admin role
     * bearer except when using {_setupRole}.
     */
    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Emitted when `account` is revoked `role`.
     *
     * `sender` is the account that originated the contract call:
     *   - if using `revokeRole`, it is the admin role bearer
     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
     */
    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) public view returns (bool) {
        return _roles[role].members.contains(account);
    }

    /**
     * @dev Returns the number of accounts that have `role`. Can be used
     * together with {getRoleMember} to enumerate all bearers of a role.
     */
    function getRoleMemberCount(bytes32 role) public view returns (uint256) {
        return _roles[role].members.length();
    }

    /**
     * @dev Returns one of the accounts that have `role`. `index` must be a
     * value between 0 and {getRoleMemberCount}, non-inclusive.
     *
     * Role bearers are not sorted in any particular way, and their ordering may
     * change at any point.
     *
     * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
     * you perform all queries on the same block. See the following
     * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]
     * for more information.
     */
    function getRoleMember(bytes32 role, uint256 index) public view returns (address) {
        return _roles[role].members.at(index);
    }

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) public view returns (bytes32) {
        return _roles[role].adminRole;
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function grantRole(bytes32 role, address account) public virtual {
        require(hasRole(_roles[role].adminRole, _msgSender()), "AccessControl: sender must be an admin to grant");

        _grantRole(role, account);
    }

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function revokeRole(bytes32 role, address account) public virtual {
        require(hasRole(_roles[role].adminRole, _msgSender()), "AccessControl: sender must be an admin to revoke");

        _revokeRole(role, account);
    }

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been granted `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `account`.
     */
    function renounceRole(bytes32 role, address account) public virtual {
        require(account == _msgSender(), "AccessControl: can only renounce roles for self");

        _revokeRole(role, account);
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event. Note that unlike {grantRole}, this function doesn't perform any
     * checks on the calling account.
     *
     * [WARNING]
     * ====
     * This function should only be called from the constructor when setting
     * up the initial roles for the system.
     *
     * Using this function in any other way is effectively circumventing the admin
     * system imposed by {AccessControl}.
     * ====
     */
    function _setupRole(bytes32 role, address account) internal virtual {
        _grantRole(role, account);
    }

    /**
     * @dev Sets `adminRole` as ``role``'s admin role.
     *
     * Emits a {RoleAdminChanged} event.
     */
    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
        emit RoleAdminChanged(role, _roles[role].adminRole, adminRole);
        _roles[role].adminRole = adminRole;
    }

    function _grantRole(bytes32 role, address account) private {
        if (_roles[role].members.add(account)) {
            emit RoleGranted(role, account, _msgSender());
        }
    }

    function _revokeRole(bytes32 role, address account) private {
        if (_roles[role].members.remove(account)) {
            emit RoleRevoked(role, account, _msgSender());
        }
    }
}

File 12 of 15 : EnumerableSet.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Library for managing
 * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
 * types.
 *
 * Sets have the following properties:
 *
 * - Elements are added, removed, and checked for existence in constant time
 * (O(1)).
 * - Elements are enumerated in O(n). No guarantees are made on the ordering.
 *
 * ```
 * contract Example {
 *     // Add the library methods
 *     using EnumerableSet for EnumerableSet.AddressSet;
 *
 *     // Declare a set state variable
 *     EnumerableSet.AddressSet private mySet;
 * }
 * ```
 *
 * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
 * and `uint256` (`UintSet`) are supported.
 */
library EnumerableSet {
    // To implement this library for multiple types with as little code
    // repetition as possible, we write it in terms of a generic Set type with
    // bytes32 values.
    // The Set implementation uses private functions, and user-facing
    // implementations (such as AddressSet) are just wrappers around the
    // underlying Set.
    // This means that we can only create new EnumerableSets for types that fit
    // in bytes32.

    struct Set {
        // Storage of set values
        bytes32[] _values;

        // Position of the value in the `values` array, plus 1 because index 0
        // means a value is not in the set.
        mapping (bytes32 => uint256) _indexes;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function _add(Set storage set, bytes32 value) private returns (bool) {
        if (!_contains(set, value)) {
            set._values.push(value);
            // The value is stored at length-1, but we add 1 to all indexes
            // and use 0 as a sentinel value
            set._indexes[value] = set._values.length;
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function _remove(Set storage set, bytes32 value) private returns (bool) {
        // We read and store the value's index to prevent multiple reads from the same storage slot
        uint256 valueIndex = set._indexes[value];

        if (valueIndex != 0) { // Equivalent to contains(set, value)
            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
            // the array, and then remove the last element (sometimes called as 'swap and pop').
            // This modifies the order of the array, as noted in {at}.

            uint256 toDeleteIndex = valueIndex - 1;
            uint256 lastIndex = set._values.length - 1;

            // When the value to delete is the last one, the swap operation is unnecessary. However, since this occurs
            // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement.

            bytes32 lastvalue = set._values[lastIndex];

            // Move the last value to the index where the value to delete is
            set._values[toDeleteIndex] = lastvalue;
            // Update the index for the moved value
            set._indexes[lastvalue] = toDeleteIndex + 1; // All indexes are 1-based

            // Delete the slot where the moved value was stored
            set._values.pop();

            // Delete the index for the deleted slot
            delete set._indexes[value];

            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function _contains(Set storage set, bytes32 value) private view returns (bool) {
        return set._indexes[value] != 0;
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function _length(Set storage set) private view returns (uint256) {
        return set._values.length;
    }

   /**
    * @dev Returns the value stored at position `index` in the set. O(1).
    *
    * Note that there are no guarantees on the ordering of values inside the
    * array, and it may change when more values are added or removed.
    *
    * Requirements:
    *
    * - `index` must be strictly less than {length}.
    */
    function _at(Set storage set, uint256 index) private view returns (bytes32) {
        require(set._values.length > index, "EnumerableSet: index out of bounds");
        return set._values[index];
    }

    // Bytes32Set

    struct Bytes32Set {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _add(set._inner, value);
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _remove(set._inner, value);
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
        return _contains(set._inner, value);
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(Bytes32Set storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

   /**
    * @dev Returns the value stored at position `index` in the set. O(1).
    *
    * Note that there are no guarantees on the ordering of values inside the
    * array, and it may change when more values are added or removed.
    *
    * Requirements:
    *
    * - `index` must be strictly less than {length}.
    */
    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
        return _at(set._inner, index);
    }

    // AddressSet

    struct AddressSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(AddressSet storage set, address value) internal returns (bool) {
        return _add(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(AddressSet storage set, address value) internal returns (bool) {
        return _remove(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(AddressSet storage set, address value) internal view returns (bool) {
        return _contains(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(AddressSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

   /**
    * @dev Returns the value stored at position `index` in the set. O(1).
    *
    * Note that there are no guarantees on the ordering of values inside the
    * array, and it may change when more values are added or removed.
    *
    * Requirements:
    *
    * - `index` must be strictly less than {length}.
    */
    function at(AddressSet storage set, uint256 index) internal view returns (address) {
        return address(uint160(uint256(_at(set._inner, index))));
    }


    // UintSet

    struct UintSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(UintSet storage set, uint256 value) internal returns (bool) {
        return _add(set._inner, bytes32(value));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(UintSet storage set, uint256 value) internal returns (bool) {
        return _remove(set._inner, bytes32(value));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(UintSet storage set, uint256 value) internal view returns (bool) {
        return _contains(set._inner, bytes32(value));
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function length(UintSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

   /**
    * @dev Returns the value stored at position `index` in the set. O(1).
    *
    * Note that there are no guarantees on the ordering of values inside the
    * array, and it may change when more values are added or removed.
    *
    * Requirements:
    *
    * - `index` must be strictly less than {length}.
    */
    function at(UintSet storage set, uint256 index) internal view returns (uint256) {
        return uint256(_at(set._inner, index));
    }
}

File 13 of 15 : Address.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.2 <0.8.0;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

pragma solidity >=0.6.0 <0.8.0;

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

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

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

pragma solidity >=0.6.0 <0.8.0;

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

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

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

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

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

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

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

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

Contract ABI

[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"member","type":"address"}],"name":"MemberAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"member","type":"address"}],"name":"MemberRemoved","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":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MINTER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_type","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"_mint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_member","type":"address"}],"name":"addMember","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_members","type":"address[]"}],"name":"addMembers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newMinter","type":"address"}],"name":"addMinter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_who","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"res","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_who","type":"address"},{"internalType":"uint256","name":"_type","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"burnFor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nominalPrice","type":"uint256"},{"internalType":"uint256","name":"_maxTotal","type":"uint256"},{"internalType":"string","name":"_info","type":"string"},{"internalType":"string","name":"_uri","type":"string"}],"name":"createNewTokenType","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"exists","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"getTokenType","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_typeId","type":"uint256"}],"name":"getTypeInfo","outputs":[{"internalType":"uint256","name":"nominalPrice","type":"uint256"},{"internalType":"uint256","name":"capSupply","type":"uint256"},{"internalType":"uint256","name":"maxSupply","type":"uint256"},{"internalType":"string","name":"info","type":"string"},{"internalType":"address","name":"minterOnly","type":"address"},{"internalType":"string","name":"uri","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_member","type":"address"}],"name":"isMember","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_who","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"isOwner","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"last","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_type","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"mint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_to","type":"address[]"},{"internalType":"uint256[]","name":"_amount","type":"uint256[]"},{"internalType":"uint256","name":"_type","type":"uint256"}],"name":"mintFor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_member","type":"address"}],"name":"removeMember","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_operator","type":"address"},{"internalType":"bool","name":"_approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_baseURI","type":"string"}],"name":"setBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_minter","type":"address"},{"internalType":"uint256","name":"_type","type":"uint256"}],"name":"setMinterOnly","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_who","type":"address"},{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"tokenOfOwnerByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"res","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_type","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"transferFor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"transferFromContract","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"whitelisted","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]

608060405260006009553480156200001657600080fd5b506200003f6000620000306001600160e01b036200011416565b6001600160e01b036200011816565b6000620000546001600160e01b036200011416565b600180546001600160a01b0319166001600160a01b038316908117909155604051919250906000907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a350620000bd6301ffc9a760e01b6001600160e01b036200013116565b620000d86380ac58cd60e01b6001600160e01b036200013116565b620000f3635b5e139f60e01b6001600160e01b036200013116565b6200010e63780e9d6360e01b6001600160e01b036200013116565b620002d1565b3390565b6200012d82826001600160e01b03620001b616565b5050565b6001600160e01b0319808216141562000191576040805162461bcd60e51b815260206004820152601c60248201527f4552433136353a20696e76616c696420696e7465726661636520696400000000604482015290519081900360640190fd5b6001600160e01b0319166000908152600460205260409020805460ff19166001179055565b600082815260208181526040909120620001db918390620032d462000238821b17901c565b156200012d57620001f46001600160e01b036200011416565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b600062000258836001600160a01b0384166001600160e01b036200026116565b90505b92915050565b60006200027883836001600160e01b03620002b916565b620002b0575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556200025b565b5060006200025b565b60009081526001919091016020526040902054151590565b613e0580620002e16000396000f3fe608060405234801561001057600080fd5b506004361061030b5760003560e01c80636c0360eb1161019d578063a22cb465116100e9578063ca15c873116100a2578063d547741f1161007c578063d547741f14610e35578063e327a6af14610e61578063e985e9c514610e8d578063f2fde38b14610ebb5761030b565b8063ca15c87314610dea578063ca6d56dc14610e07578063d539139314610e2d5761030b565b8063a22cb46514610bcb578063a230c52414610bf9578063a9059cbb14610c1f578063b88d4fde14610c4b578063bdb6836914610d0f578063c87b56dd14610dcd5761030b565b80638da5cb5b1161015657806395d89b411161013057806395d89b4114610a6c578063983b2d5614610a745780639bd993ff14610a9a578063a217fddf14610bc35761030b565b80638da5cb5b14610a155780639010d07c14610a1d57806391d1485414610a405761030b565b80636c0360eb146108ef5780636f4d469b146108f757806370a0823114610998578063715018a6146109be57806376aed2e1146109c65780637776afa0146109e35761030b565b8063313ce5671161025c578063473360a1116102155780634f6ccce7116101ef5780634f6ccce7146107e557806350a2388f1461080257806355f804b31461082e5780636352211e146108d25761030b565b8063473360a11461068b57806347799da8146107c05780634f558e79146107c85761030b565b8063313ce567146105aa57806336568abe146105c85780633d9287fa146105f45780633ee9f8bb146105fc57806342842e0e1461063857806342966c681461066e5761030b565b8063156e29f6116102c957806323b872dd116102a357806323b872dd146104ff578063248a9ca3146105355780632f2ff15d146105525780632f745c591461057e5761030b565b8063156e29f61461048757806318160ddd146104cb5780631a88f306146104d35761030b565b8062c2a9451461031057806301ffc9a71461034457806306fdde031461037f578063081812fc146103fc578063095ea7b3146104355780630b1ca49a14610461575b600080fd5b6103426004803603606081101561032657600080fd5b506001600160a01b038135169060208101359060400135610ee1565b005b61036b6004803603602081101561035a57600080fd5b50356001600160e01b03191661110f565b604080519115158252519081900360200190f35b610387611132565b6040805160208082528351818301528351919283929083019185019080838360005b838110156103c15781810151838201526020016103a9565b50505050905090810190601f1680156103ee5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6104196004803603602081101561041257600080fd5b503561116a565b604080516001600160a01b039092168252519081900360200190f35b6103426004803603604081101561044b57600080fd5b506001600160a01b0381351690602001356111cc565b6103426004803603602081101561047757600080fd5b50356001600160a01b031661127e565b6104b96004803603606081101561049d57600080fd5b506001600160a01b038135169060208101359060400135611386565b60408051918252519081900360200190f35b6104b96114f1565b61036b600480360360408110156104e957600080fd5b506001600160a01b038135169060200135611531565b6103426004803603606081101561051557600080fd5b506001600160a01b0381358116916020810135909116906040013561158f565b6104b96004803603602081101561054b57600080fd5b50356115eb565b6103426004803603604081101561056857600080fd5b50803590602001356001600160a01b0316611600565b6104b96004803603604081101561059457600080fd5b506001600160a01b038135169060200135611663565b6105b261174a565b6040805160ff9092168252519081900360200190f35b610342600480360360408110156105de57600080fd5b50803590602001356001600160a01b031661174f565b6104b96117b0565b6103426004803603608081101561061257600080fd5b506001600160a01b038135811691602081013590911690604081013590606001356117b6565b6103426004803603606081101561064e57600080fd5b506001600160a01b038135811691602081013590911690604001356119f9565b6103426004803603602081101561068457600080fd5b5035611a14565b610342600480360360808110156106a157600080fd5b813591602081013591810190606081016040820135600160201b8111156106c757600080fd5b8201836020820111156106d957600080fd5b803590602001918460018302840111600160201b831117156106fa57600080fd5b91908080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509295949360208101935035915050600160201b81111561074c57600080fd5b82018360208201111561075e57600080fd5b803590602001918460018302840111600160201b8311171561077f57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550611a28945050505050565b6104b9611bb3565b61036b600480360360208110156107de57600080fd5b5035611bb9565b6104b9600480360360208110156107fb57600080fd5b5035611167565b6103426004803603604081101561081857600080fd5b506001600160a01b038135169060200135611bcf565b6103426004803603602081101561084457600080fd5b810190602081018135600160201b81111561085e57600080fd5b82018360208201111561087057600080fd5b803590602001918460018302840111600160201b8311171561089157600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550611cc5945050505050565b610419600480360360208110156108e857600080fd5b5035611d20565b610387611d4f565b6103426004803603602081101561090d57600080fd5b810190602081018135600160201b81111561092757600080fd5b82018360208201111561093957600080fd5b803590602001918460208302840111600160201b8311171561095a57600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550611ddd945050505050565b6104b9600480360360208110156109ae57600080fd5b50356001600160a01b0316611e48565b610342611ea6565b6104b9600480360360208110156109dc57600080fd5b5035611f52565b6104b9600480360360608110156109f957600080fd5b506001600160a01b038135169060208101359060400135611fd0565b6104196121cf565b61041960048036036040811015610a3357600080fd5b50803590602001356121de565b61036b60048036036040811015610a5657600080fd5b50803590602001356001600160a01b03166121fc565b61038761221a565b61034260048036036020811015610a8a57600080fd5b50356001600160a01b031661223b565b610ab760048036036020811015610ab057600080fd5b50356122ad565b6040518087815260200186815260200185815260200180602001846001600160a01b03166001600160a01b0316815260200180602001838103835286818151815260200191508051906020019080838360005b83811015610b22578181015183820152602001610b0a565b50505050905090810190601f168015610b4f5780820380516001836020036101000a031916815260200191505b50838103825284518152845160209182019186019080838360005b83811015610b82578181015183820152602001610b6a565b50505050905090810190601f168015610baf5780820380516001836020036101000a031916815260200191505b509850505050505050505060405180910390f35b6104b96124c2565b61034260048036036040811015610be157600080fd5b506001600160a01b03813516906020013515156124c7565b61036b60048036036020811015610c0f57600080fd5b50356001600160a01b03166125cc565b61036b60048036036040811015610c3557600080fd5b506001600160a01b0381351690602001356125ea565b61034260048036036080811015610c6157600080fd5b6001600160a01b03823581169260208101359091169160408201359190810190608081016060820135600160201b811115610c9b57600080fd5b820183602082011115610cad57600080fd5b803590602001918460018302840111600160201b83111715610cce57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550612623945050505050565b61034260048036036060811015610d2557600080fd5b810190602081018135600160201b811115610d3f57600080fd5b820183602082011115610d5157600080fd5b803590602001918460208302840111600160201b83111715610d7257600080fd5b919390929091602081019035600160201b811115610d8f57600080fd5b820183602082011115610da157600080fd5b803590602001918460208302840111600160201b83111715610dc257600080fd5b919350915035612681565b61038760048036036020811015610de357600080fd5b5035612861565b6104b960048036036020811015610e0057600080fd5b50356129a4565b61034260048036036020811015610e1d57600080fd5b50356001600160a01b03166129bb565b6104b9612a76565b61034260048036036040811015610e4b57600080fd5b50803590602001356001600160a01b0316612a99565b61036b60048036036040811015610e7757600080fd5b506001600160a01b038135169060200135612af2565b61036b60048036036040811015610ea357600080fd5b506001600160a01b0381358116916020013516612b38565b61034260048036036020811015610ed157600080fd5b50356001600160a01b0316612b66565b610ee9612c69565b6001600160a01b0316836001600160a01b03161480610f145750610f1483610f0f612c69565b612b38565b610f4f5760405162461bcd60e51b8152600401808060200182810382526025815260200180613c5a6025913960400191505060405180910390fd5b6005548210610f8f5760405162461bcd60e51b81526004018080602001828103825260218152602001806139246021913960400191505060405180910390fd5b6001600160a01b03831660009081526006602052604081206005805491929185908110610fb857fe5b600091825260208220600560109092020101915080805b858110156111055760008584600a8110610fe557fe5b01549050801561102e575b6101008310801561101e57506001831b8116158061101e57506001831b8585600a811061101957fe5b015416155b1561102e57826001019250610ff0565b80158061103c575082610100145b156110905760009250836001019350600a841061108a5760405162461bcd60e51b8152600401808060200182810382526024815260200180613d186024913960400191505060405180910390fd5b50610fcf565b610100840283016110a2600082612c6d565b6001841b19808887600a81106110b457fe5b0180549091169055808787600a81106110c957fe5b018054909116905560405182906000906001600160a01b038e1690600080516020613cd7833981519152908390a4836001019350505050610fcf565b5050505050505050565b6001600160e01b0319811660009081526004602052604090205460ff165b919050565b60408051808201909152601781527f47726176697320436172647320436f6c6c656374696f6e00000000000000000060208201525b90565b600061117582611bb9565b6111b05760405162461bcd60e51b815260040180806020018281038252602c815260200180613be3602c913960400191505060405180910390fd5b506000908152600760205260409020546001600160a01b031690565b6111d4612c69565b6001600160a01b0316826001600160a01b031614156112245760405162461bcd60e51b8152600401808060200182810382526021815260200180613cf76021913960400191505060405180910390fd5b61123561122f612c69565b82612af2565b6112705760405162461bcd60e51b8152600401808060200182810382526023815260200180613ab66023913960400191505060405180910390fd5b61127a8282612c6d565b5050565b611286612c69565b6001600160a01b03166112976121cf565b6001600160a01b0316146112e0576040805162461bcd60e51b81526020600482018190526024820152600080516020613c3a833981519152604482015290519081900360640190fd5b6112e9816125cc565b6113245760405162461bcd60e51b8152600401808060200182810382526022815260200180613b586022913960400191505060405180910390fd5b6001600160a01b038116600081815260026020908152604091829020805460ff1916905560038054600019019055815192835290517f6e76fb4c77256006d9c38ec7d82b45a8c8f3c27b1d6766fffc42dfb8de6844929281900390910190a150565b604080516a4d494e5445525f524f4c4560a81b8152905190819003600b0190206000906113ba906113b5612c69565b6121fc565b6113f55760405162461bcd60e51b8152600401808060200182810382526030815260200180613a136030913960400191505060405180910390fd5b60055483106114355760405162461bcd60e51b81526004018080602001828103825260218152602001806139246021913960400191505060405180910390fd5b60006005848154811061144457fe5b6000918252602090912060109091020180549091506001600160a01b0316156114db5761146f612c69565b6001600160a01b03166005858154811061148557fe5b60009182526020909120601090910201546001600160a01b0316146114db5760405162461bcd60e51b8152600401808060200182810382526034815260200180613d6d6034913960400191505060405180910390fd5b6114e6858585611fd0565b9150505b9392505050565b6000805b60055481101561152d576005818154811061150c57fe5b906000526020600020906010020160030154820191508060010190506114f5565b5090565b600061153f816113b5612c69565b61157a5760405162461bcd60e51b8152600401808060200182810382526027815260200180613a6b6027913960400191505060405180910390fd5b611585308484612cfb565b5060015b92915050565b6115a061159a612c69565b82612e2c565b6115db5760405162461bcd60e51b8152600401808060200182810382526031815260200180613d3c6031913960400191505060405180910390fd5b6115e6838383612cfb565b505050565b60009081526020819052604090206002015490565b60008281526020819052604090206002015461161e906113b5612c69565b6116595760405162461bcd60e51b815260040180806020018281038252602f81526020018061398c602f913960400191505060405180910390fd5b61127a8282612e69565b6001600160a01b03821660009081526006602052604081208180805b60008484600a811061168d57fe5b0154905080156116bc575b610100831080156116ac57506001831b8116155b156116bc57826001019250611698565b8015806116ca575082610100145b1561171e5760009250836001019350600a84106117185760405162461bcd60e51b8152600401808060200182810382526024815260200180613d186024913960400191505060405180910390fd5b5061167f565b8682141561172c5750611739565b506001918201910161167f565b506101009091020191505092915050565b600090565b611757612c69565b6001600160a01b0316816001600160a01b0316146117a65760405162461bcd60e51b815260040180806020018281038252602f815260200180613da1602f913960400191505060405180910390fd5b61127a8282612ed8565b60035481565b6117be612c69565b6001600160a01b0316846001600160a01b031614806117e457506117e484610f0f612c69565b61181f5760405162461bcd60e51b8152600401808060200182810382526025815260200180613c5a6025913960400191505060405180910390fd5b600554821061185f5760405162461bcd60e51b81526004018080602001828103825260218152602001806139246021913960400191505060405180910390fd5b6001600160a01b0380851660009081526006602052604080822092861682528120600580549192918690811061189157fe5b600091825260208220600560109092020101915080805b868110156119ed5760008684600a81106118be57fe5b015490508015611907575b610100831080156118f757506001831b811615806118f757506001831b8585600a81106118f257fe5b015416155b15611907578260010192506118c9565b801580611915575082610100145b156119695760009250836001019350600a84106119635760405162461bcd60e51b8152600401808060200182810382526024815260200180613d186024913960400191505060405180910390fd5b506118a8565b6101008402830161197b600082612c6d565b6001841b808887600a811061198c57fe5b018054909117905580198987600a81106119a257fe5b0160008282541692505081905550818c6001600160a01b03168e6001600160a01b0316600080516020613cd783398151915260405160405180910390a48360010193505050506118a8565b50505050505050505050565b6115e683838360405180602001604052806000815250612623565b611a25611a1f612c69565b82612f47565b50565b611a3560006113b5612c69565b611a705760405162461bcd60e51b8152600401808060200182810382526027815260200180613a6b6027913960400191505060405180910390fd5b83611aac5760405162461bcd60e51b8152600401808060200182810382526028815260200180613bbb6028913960400191505060405180910390fd5b611ab46137df565b6040810185905260808101849052602080820184815260c083018490526005805460018101825560009190915283517f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db0601090920291820180546001600160a01b0319166001600160a01b03909216919091178155915180518594611b5d937f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db10192019061382b565b5060408201516002820155606082015160038201556080820151600482015560a082015180516005830190611b95908290600a6138a5565b50505060c0820151805161110591600f84019160209091019061382b565b60095481565b6000600019611bc783611f52565b141592915050565b611bdc60006113b5612c69565b611c175760405162461bcd60e51b8152600401808060200182810382526027815260200180613a6b6027913960400191505060405180910390fd5b60006001600160a01b031660058281548110611c2f57fe5b60009182526020909120601090910201546001600160a01b031614611c855760405162461bcd60e51b8152600401808060200182810382526028815260200180613a436028913960400191505060405180910390fd5b8160058281548110611c9357fe5b6000918252602090912060109091020180546001600160a01b0319166001600160a01b03929092169190911790555050565b611cd260006113b5612c69565b611d0d5760405162461bcd60e51b8152600401808060200182810382526027815260200180613a6b6027913960400191505060405180910390fd5b805161127a90600a90602084019061382b565b6000611d33611d2d612c69565b83612af2565b15611d4757611d40612c69565b905061112d565b506000919050565b600a805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015611dd55780601f10611daa57610100808354040283529160200191611dd5565b820191906000526020600020905b815481529060010190602001808311611db857829003601f168201915b505050505081565b611de5612c69565b6001600160a01b0316611df66121cf565b6001600160a01b031614611e3f576040805162461bcd60e51b81526020600482018190526024820152600080516020613c3a833981519152604482015290519081900360640190fd5b611a258161306f565b6001600160a01b0381166000908152600660205260408120815b600a811015611e9f5760008282600a8110611e7957fe5b015490505b8015611e965760019390930192600019810116611e7e565b50600101611e62565b5050919050565b611eae612c69565b6001600160a01b0316611ebf6121cf565b6001600160a01b031614611f08576040805162461bcd60e51b81526020600482018190526024820152600080516020613c3a833981519152604482015290519081900360640190fd5b6001546040516000916001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600180546001600160a01b0319169055565b6000600954821015611fc757600080611f6a84613197565b909250905060005b600554811015611fc3578160058281548110611f8a57fe5b906000526020600020906010020160050160000184600a8110611fa957fe5b01541615611fbb57925061112d915050565b600101611f72565b5050505b50600019919050565b60006001600160a01b0384166120175760405162461bcd60e51b815260040180806020018281038252602b815260200180613ad9602b913960400191505060405180910390fd5b60006005848154811061202657fe5b600091825260208083206001600160a01b038916845260069091526040832060095460109093029091019350918061205d83613197565b915091505b600954612075908863ffffffff6131fc16565b8310156120ea57806005860183600a811061208c57fe5b0180549091179055808483600a81106120a157fe5b018054909117905560011b806120b957506001908101905b60405183906001600160a01b038b1690600090600080516020613cd7833981519152908290a4826001019250612062565b826009819055506121228760058a8154811061210257fe5b9060005260206000209060100201600301546131fc90919063ffffffff16565b6005898154811061212f57fe5b9060005260206000209060100201600301819055506005888154811061215157fe5b9060005260206000209060100201600401546005898154811061217057fe5b90600052602060002090601002016003015411156121bf5760405162461bcd60e51b81526004018080602001828103825260258152602001806139676025913960400191505060405180910390fd5b5050600954979650505050505050565b6001546001600160a01b031690565b60008281526020819052604081206114ea908363ffffffff61325616565b60008281526020819052604081206114ea908363ffffffff61326216565b60408051808201909152600781526611d49594d3919560ca1b602082015290565b61224860006113b5612c69565b6122835760405162461bcd60e51b8152600401808060200182810382526027815260200180613a6b6027913960400191505060405180910390fd5b604080516a4d494e5445525f524f4c4560a81b8152905190819003600b019020611a259082611659565b60008060006060600060606122c06137df565b600588815481106122cd57fe5b60009182526020918290206040805160e081018252601090930290910180546001600160a01b03168352600180820180548451601f6002600019958416156101000295909501909216939093049081018790048702830187019094528382529394919385830193919290919083018282801561238a5780601f1061235f5761010080835404028352916020019161238a565b820191906000526020600020905b81548152906001019060200180831161236d57829003601f168201915b50505091835250506002820154602080830191909152600383015460408084019190915260048401546060840152805161016081019182905260809093019291600585019183918201908390600a9082845b8154815260200190600101908083116123dc57505050919092525050508152600f8201805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529382019392918301828280156124875780601f1061245c57610100808354040283529160200191612487565b820191906000526020600020905b81548152906001019060200180831161246a57829003601f168201915b505050919092525050506040810151606082015160808301516020840151845160c090950151939d929c50909a509850919650945092505050565b600081565b6124cf612c69565b6001600160a01b0316826001600160a01b03161415612535576040805162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c657200000000000000604482015290519081900360640190fd5b8060086000612542612c69565b6001600160a01b03908116825260208083019390935260409182016000908120918716808252919093529120805460ff191692151592909217909155612586612c69565b60408051841515815290516001600160a01b0392909216917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c319181900360200190a35050565b6001600160a01b031660009081526002602052604090205460ff1690565b600060405162461bcd60e51b8152600401808060200182810382526041815260200180613b7a6041913960600191505060405180910390fd5b61263461262e612c69565b83612e2c565b61266f5760405162461bcd60e51b8152600401808060200182810382526031815260200180613d3c6031913960400191505060405180910390fd5b61267b84848484613277565b50505050565b604080516a4d494e5445525f524f4c4560a81b8152905190819003600b0190206126ad906113b5612c69565b6126e85760405162461bcd60e51b8152600401808060200182810382526030815260200180613a136030913960400191505060405180910390fd5b8382146127265760405162461bcd60e51b815260040180806020018281038252602b815260200180613c0f602b913960400191505060405180910390fd5b60055481106127665760405162461bcd60e51b81526004018080602001828103825260218152602001806139246021913960400191505060405180910390fd5b60006005828154811061277557fe5b6000918252602090912060109091020180549091506001600160a01b03161561280c576127a0612c69565b6001600160a01b0316600583815481106127b657fe5b60009182526020909120601090910201546001600160a01b03161461280c5760405162461bcd60e51b8152600401808060200182810382526034815260200180613d6d6034913960400191505060405180910390fd5b60005b858110156128585761284f87878381811061282657fe5b905060200201356001600160a01b03168487878581811061284357fe5b90506020020135611fd0565b5060010161280f565b50505050505050565b6060600061286e83611f52565b90506000198114156128b15760405162461bcd60e51b815260040180806020018281038252602f815260200180613ca8602f913960400191505060405180910390fd5b600a600582815481106128c057fe5b9060005260206000209060100201600f01604051602001808380546001816001161561010002031660029004801561292f5780601f1061290d57610100808354040283529182019161292f565b820191906000526020600020905b81548152906001019060200180831161291b575b5050828054600181600116156101000203166002900480156129885780601f10612966576101008083540402835291820191612988565b820191906000526020600020905b815481529060010190602001808311612974575b505060408051601f198184030181529190529695505050505050565b6000818152602081905260408120611589906132c9565b6129c3612c69565b6001600160a01b03166129d46121cf565b6001600160a01b031614612a1d576040805162461bcd60e51b81526020600482018190526024820152600080516020613c3a833981519152604482015290519081900360640190fd5b604080516001808252818301909252606091602080830190803883390190505090508181600081518110612a4d57fe5b60200260200101906001600160a01b031690816001600160a01b03168152505061127a8161306f565b604080516a4d494e5445525f524f4c4560a81b8152905190819003600b01902081565b600082815260208190526040902060020154612ab7906113b5612c69565b6117a65760405162461bcd60e51b8152600401808060200182810382526030815260200180613b046030913960400191505060405180910390fd5b6000806000612b0084613197565b6001600160a01b03871660009081526006602052604090209193509150819083600a8110612b2a57fe5b015416151595945050505050565b6001600160a01b03918216600090815260086020908152604080832093909416825291909152205460ff1690565b612b6e612c69565b6001600160a01b0316612b7f6121cf565b6001600160a01b031614612bc8576040805162461bcd60e51b81526020600482018190526024820152600080516020613c3a833981519152604482015290519081900360640190fd5b6001600160a01b038116612c0d5760405162461bcd60e51b81526004018080602001828103825260268152602001806139ed6026913960400191505060405180910390fd5b6001546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600180546001600160a01b0319166001600160a01b0392909216919091179055565b3390565b6000818152600760205260409020546001600160a01b0383811691161461127a57600081815260076020526040902080546001600160a01b0319166001600160a01b0384169081179091558190612cc2612c69565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b612d058382612af2565b612d405760405162461bcd60e51b8152600401808060200182810382526029815260200180613c7f6029913960400191505060405180910390fd5b6001600160a01b038216612d855760405162461bcd60e51b8152600401808060200182810382526024815260200180613a926024913960400191505060405180910390fd5b612d90600082612c6d565b600080612d9c83613197565b6001600160a01b0387166000908152600660205260409020919350915081199083600a8110612dc757fe5b01805490911690556001600160a01b0384166000908152600660205260409020819083600a8110612df457fe5b018054909117905560405183906001600160a01b038087169190881690600080516020613cd783398151915290600090a45050505050565b6000612e388383612af2565b15612e4557506001611589565b826001600160a01b0316612e588361116a565b6001600160a01b0316149392505050565b6000828152602081905260409020612e87908263ffffffff6132d416565b1561127a57612e94612c69565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6000828152602081905260409020612ef6908263ffffffff6132e916565b1561127a57612f03612c69565b6001600160a01b0316816001600160a01b0316837ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b60405160405180910390a45050565b600080612f5383613197565b6001600160a01b03861660009081526006602052604090209193509150819083600a8110612f7d57fe5b015416612fbd576040805162461bcd60e51b81526020600482015260096024820152683737ba1037bbb732b960b91b604482015290519081900360640190fd5b612fc8600084612c6d565b6001600160a01b0384166000908152600660205260409020901990819083600a8110612ff057fe5b018054909116905560005b60055481101561304257816005828154811061301357fe5b906000526020600020906010020160050160000184600a811061303257fe5b0180549091169055600101612ffb565b5060405183906000906001600160a01b03871690600080516020613cd7833981519152908390a450505050565b805160005b818110156131895761309883828151811061308b57fe5b60200260200101516125cc565b156130d45760405162461bcd60e51b8152600401808060200182810382526024815260200180613b346024913960400191505060405180910390fd5b6001600260008584815181106130e657fe5b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff0219169083151502179055507fb251eb052afc73ffd02ffe85ad79990a8b3fed60d76dbc2fa2fdd7123dffd91483828151811061315257fe5b602002602001015160405180826001600160a01b03166001600160a01b0316815260200191505060405180910390a1600101613074565b505051600380549091019055565b61010081046000600a82106131ec576040805162461bcd60e51b815260206004820152601660248201527523b930bb34b9a1b7b63632b1ba34b136329d1027a7a160511b604482015290519081900360640190fd5b61010083066001901b9050915091565b6000828201838110156114ea576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b60006114ea83836132fe565b60006114ea836001600160a01b038416613362565b613282848484612cfb565b61328e8484848461337a565b61267b5760405162461bcd60e51b81526004018080602001828103825260328152602001806139bb6032913960400191505060405180910390fd5b6000611589826134fb565b60006114ea836001600160a01b0384166134ff565b60006114ea836001600160a01b038416613549565b815460009082106133405760405162461bcd60e51b81526004018080602001828103825260228152602001806139456022913960400191505060405180910390fd5b82600001828154811061334f57fe5b9060005260206000200154905092915050565b60009081526001919091016020526040902054151590565b600061338e846001600160a01b031661360f565b61339a575060016134f3565b60606134c0630a85bd0160e11b6133af612c69565b88878760405160240180856001600160a01b03166001600160a01b03168152602001846001600160a01b03166001600160a01b0316815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b83811015613428578181015183820152602001613410565b50505050905090810190601f1680156134555780820380516001836020036101000a031916815260200191505b5095505050505050604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b0383818316178352505050506040518060600160405280603281526020016139bb603291396001600160a01b038816919063ffffffff61361516565b905060008180602001905160208110156134d957600080fd5b50516001600160e01b031916630a85bd0160e11b14925050505b949350505050565b5490565b600061350b8383613362565b61354157508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155611589565b506000611589565b60008181526001830160205260408120548015613605578354600019808301919081019060009087908390811061357c57fe5b906000526020600020015490508087600001848154811061359957fe5b6000918252602080832090910192909255828152600189810190925260409020908401905586548790806135c957fe5b60019003818190600052602060002001600090559055866001016000878152602001908152602001600020600090556001945050505050611589565b6000915050611589565b3b151590565b60606134f38484600085856136298561360f565b61367a576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015290519081900360640190fd5b60006060866001600160a01b031685876040518082805190602001908083835b602083106136b95780518252601f19909201916020918201910161369a565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d806000811461371b576040519150601f19603f3d011682016040523d82523d6000602084013e613720565b606091505b509150915061373082828661373b565b979650505050505050565b6060831561374a5750816114ea565b82511561375a5782518084602001fd5b8160405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156137a457818101518382015260200161378c565b50505050905090810190601f1680156137d15780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b6040518060e0016040528060006001600160a01b031681526020016060815260200160008152602001600081526020016000815260200161381e6138d2565b8152602001606081525090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061386c57805160ff1916838001178555613899565b82800160010185558215613899579182015b8281111561389957825182559160200191906001019061387e565b5061152d9291506138ea565b82600a8101928215613899579160200282018281111561389957825182559160200191906001019061387e565b60405180602001604052806138e5613904565b905290565b61116791905b8082111561152d57600081556001016138f0565b604051806101400160405280600a90602082028038833950919291505056fe477261766973436f6c6c65637469626c653a2074797065206e6f74206578697374456e756d657261626c655365743a20696e646578206f7574206f6620626f756e6473477261766973436f6c6c65637469626c653a206d617820737570706c792072656163686564416363657373436f6e74726f6c3a2073656e646572206d75737420626520616e2061646d696e20746f206772616e744552433732313a207472616e7366657220746f206e6f6e20455243373231526563656976657220696d706c656d656e7465724f776e61626c653a206e6577206f776e657220697320746865207a65726f2061646472657373477261766973436f6c6c65637469626c653a206d7573742068617665206d696e74657220726f6c6520746f206d696e74477261766973436f6c6c65637469626c653a206d696e746572206c6f636b656420616c7265616479477261766973436f6c6c65637469626c653a206d75737420686176652061646d696e20726f6c654552433732313a207472616e7366657220746f20746865207a65726f20616464726573734552433732313a20617070726f76652063616c6c6572206973206e6f74206f776e6572477261766973436f6c6c65637469626c653a206d696e7420746f20746865207a65726f2061646472657373416363657373436f6e74726f6c3a2073656e646572206d75737420626520616e2061646d696e20746f207265766f6b6557686974656c6973743a2041646472657373206973206d656d62657220616c726561647957686974656c6973743a204e6f74206d656d626572206f662077686974656c697374546869732074797065206f6620746f6b656e2063616e6e6f74206265207472616e736665727265642066726f6d20746869732074797065206f662077616c6c6574477261766973436f6c6c65637469626c653a206e6f6d696e616c207072696365206973207a65726f4552433732313a20617070726f76656420717565727920666f72206e6f6e6578697374656e7420746f6b656e477261766973436f6c6c65637469626c653a20696e7075742061727261797320646f6e2774206d617463684f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572477261766973436f6c6c65637469626c653a206d757374206861766520617070726f76616c4552433732313a207472616e73666572206f6620746f6b656e2074686174206973206e6f74206f776e4552433732314d657461646174613a2055524920717565727920666f72206e6f6e6578697374656e7420746f6b656eddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef4552433732313a20617070726f76616c20746f2063757272656e74206f776e6572477261766973436f6c6c65637469626c653a206e6f7420656e6f75676820746f6b656e734552433732313a207472616e736665722063616c6c6572206973206e6f74206f776e6572206e6f7220617070726f766564477261766973436f6c6c65637469626c653a206d696e74696e67206c6f636b656420627920616e6f74686572206163636f756e74416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636520726f6c657320666f722073656c66a26469706673582212204d359a2466384990b30f51fe90be1d8742347e42ccc5fabbb379b685aded881064736f6c63430006020033

Block Transaction Gas Used Reward
Age Block Fee Address BC Fee Address Voting Power Jailed Incoming
Block Uncle Number Difficulty Gas Used Reward
Loading