creation_sourcecode: // SPDX-License-Identifier: MIT
  
  pragma solidity ^0.6.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);
  }
  
  
  
  pragma solidity ^0.6.2;
  
  
  /**
   * @dev Required interface of an ERC1155 compliant contract, as defined in the
   * https://eips.ethereum.org/EIPS/eip-1155[EIP].
   *
   * _Available since v3.1._
   */
  interface IERC1155 is IERC165 {
      /**
       * @dev Emitted when `value` tokens of token type `id` are transfered from `from` to `to` by `operator`.
       */
      event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);
  
      /**
       * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
       * transfers.
       */
      event TransferBatch(address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values);
  
      /**
       * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
       * `approved`.
       */
      event ApprovalForAll(address indexed account, address indexed operator, bool approved);
  
      /**
       * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
       *
       * If an {URI} event was emitted for `id`, the standard
       * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
       * returned by {IERC1155MetadataURI-uri}.
       */
      event URI(string value, uint256 indexed id);
  
      /**
       * @dev Returns the amount of tokens of token type `id` owned by `account`.
       *
       * Requirements:
       *
       * - `account` cannot be the zero address.
       */
      function balanceOf(address account, uint256 id) external view returns (uint256);
  
      /**
       * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
       *
       * Requirements:
       *
       * - `accounts` and `ids` must have the same length.
       */
      function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids) external view returns (uint256[] memory);
  
      /**
       * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
       *
       * Emits an {ApprovalForAll} event.
       *
       * Requirements:
       *
       * - `operator` cannot be the caller.
       */
      function setApprovalForAll(address operator, bool approved) external;
  
      /**
       * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
       *
       * See {setApprovalForAll}.
       */
      function isApprovedForAll(address account, address operator) external view returns (bool);
  
      /**
       * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
       *
       * Emits a {TransferSingle} event.
       *
       * Requirements:
       *
       * - `to` cannot be the zero address.
       * - If the caller is not `from`, it must be have been approved to spend ``from``'s tokens via {setApprovalForAll}.
       * - `from` must have a balance of tokens of type `id` of at least `amount`.
       * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
       * acceptance magic value.
       */
      function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes calldata data) external;
  
      /**
       * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
       *
       * Emits a {TransferBatch} event.
       *
       * Requirements:
       *
       * - `ids` and `amounts` must have the same length.
       * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
       * acceptance magic value.
       */
      function safeBatchTransferFrom(address from, address to, uint256[] calldata ids, uint256[] calldata amounts, bytes calldata data) external;
  }
  
  
  
  pragma solidity ^0.6.2;
  
  
  /**
   * @dev Interface of the optional ERC1155MetadataExtension interface, as defined
   * in the https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[EIP].
   *
   * _Available since v3.1._
   */
  interface IERC1155MetadataURI is IERC1155 {
      /**
       * @dev Returns the URI for token type `id`.
       *
       * If the `\{id\}` substring is present in the URI, it must be replaced by
       * clients with the actual token type ID.
       */
      function uri(uint256 id) external view returns (string memory);
  }
  
  
  
  pragma solidity ^0.6.0;
  
  
  /**
   * _Available since v3.1._
   */
  interface IERC1155Receiver is IERC165 {
  
      /**
          @dev Handles the receipt of a single ERC1155 token type. This function is
          called at the end of a `safeTransferFrom` after the balance has been updated.
          To accept the transfer, this must return
          `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
          (i.e. 0xf23a6e61, or its own function selector).
          @param operator The address which initiated the transfer (i.e. msg.sender)
          @param from The address which previously owned the token
          @param id The ID of the token being transferred
          @param value The amount of tokens being transferred
          @param data Additional data with no specified format
          @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed
      */
      function onERC1155Received(
          address operator,
          address from,
          uint256 id,
          uint256 value,
          bytes calldata data
      )
          external
          returns(bytes4);
  
      /**
          @dev Handles the receipt of a multiple ERC1155 token types. This function
          is called at the end of a `safeBatchTransferFrom` after the balances have
          been updated. To accept the transfer(s), this must return
          `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
          (i.e. 0xbc197c81, or its own function selector).
          @param operator The address which initiated the batch transfer (i.e. msg.sender)
          @param from The address which previously owned the token
          @param ids An array containing ids of each token being transferred (order and length must match values array)
          @param values An array containing amounts of each token being transferred (order and length must match ids array)
          @param data Additional data with no specified format
          @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed
      */
      function onERC1155BatchReceived(
          address operator,
          address from,
          uint256[] calldata ids,
          uint256[] calldata values,
          bytes calldata data
      )
          external
          returns(bytes4);
  }
  
  
  
  pragma solidity ^0.6.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;
      }
  }
  
  
  
  pragma solidity ^0.6.0;
  
  
  /**
   * @dev Implementation of the {IERC165} interface.
   *
   * Contracts may inherit from this and call {_registerInterface} to declare
   * their support of an interface.
   */
  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 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;
      }
  }
  
  
  
  pragma solidity ^0.6.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, 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) {
          return sub(a, b, "SafeMath: subtraction overflow");
      }
  
      /**
       * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
       * overflow (when the result is negative).
       *
       * 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);
          uint256 c = a - b;
  
          return c;
      }
  
      /**
       * @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) {
          // 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 0;
          }
  
          uint256 c = a * b;
          require(c / a == b, "SafeMath: multiplication overflow");
  
          return c;
      }
  
      /**
       * @dev Returns the integer division of two unsigned integers. Reverts 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) {
          return div(a, b, "SafeMath: division by zero");
      }
  
      /**
       * @dev Returns the integer division of two unsigned integers. Reverts with custom message 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, string memory errorMessage) internal pure returns (uint256) {
          require(b > 0, errorMessage);
          uint256 c = a / b;
          // assert(a == b * c + a % b); // There is no case in which this doesn't hold
  
          return c;
      }
  
      /**
       * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
       * Reverts 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) {
          return mod(a, b, "SafeMath: modulo by zero");
      }
  
      /**
       * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
       * Reverts with custom message 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, string memory errorMessage) internal pure returns (uint256) {
          require(b != 0, errorMessage);
          return a % b;
      }
  }
  
  
  
  pragma solidity ^0.6.2;
  
  /**
   * @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) {
          // According to EIP-1052, 0x0 is the value returned for not-yet created accounts
          // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
          // for accounts without code, i.e. `keccak256('')`
          bytes32 codehash;
          bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
          // solhint-disable-next-line no-inline-assembly
          assembly { codehash := extcodehash(account) }
          return (codehash != accountHash && codehash != 0x0);
      }
  
      /**
       * @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");
          return _functionCallWithValue(target, data, value, errorMessage);
      }
  
      function _functionCallWithValue(address target, bytes memory data, uint256 weiValue, string memory errorMessage) private returns (bytes memory) {
          require(isContract(target), "Address: call to non-contract");
  
          // solhint-disable-next-line avoid-low-level-calls
          (bool success, bytes memory returndata) = target.call{ value: weiValue }(data);
          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);
              }
          }
      }
  }
  
  
  
  pragma solidity ^0.6.0;
  
  
  
  
  
  
  
  
  /**
   *
   * @dev Implementation of the basic standard multi-token.
   * See https://eips.ethereum.org/EIPS/eip-1155
   * Originally based on code by Enjin: https://github.com/enjin/erc-1155
   *
   * _Available since v3.1._
   */
  contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI {
      using SafeMath for uint256;
      using Address for address;
  
      // Mapping from token ID to account balances
      mapping (uint256 => mapping(address => uint256)) private _balances;
  
      // Mapping from account to operator approvals
      mapping (address => mapping(address => bool)) private _operatorApprovals;
  
      // Used as the URI for all token types by relying on ID substition, e.g. https://token-cdn-domain/{id}.json
      string private _uri;
  
      /*
       *     bytes4(keccak256('balanceOf(address,uint256)')) == 0x00fdd58e
       *     bytes4(keccak256('balanceOfBatch(address[],uint256[])')) == 0x4e1273f4
       *     bytes4(keccak256('setApprovalForAll(address,bool)')) == 0xa22cb465
       *     bytes4(keccak256('isApprovedForAll(address,address)')) == 0xe985e9c5
       *     bytes4(keccak256('safeTransferFrom(address,address,uint256,uint256,bytes)')) == 0xf242432a
       *     bytes4(keccak256('safeBatchTransferFrom(address,address,uint256[],uint256[],bytes)')) == 0x2eb2c2d6
       *
       *     => 0x00fdd58e ^ 0x4e1273f4 ^ 0xa22cb465 ^
       *        0xe985e9c5 ^ 0xf242432a ^ 0x2eb2c2d6 == 0xd9b67a26
       */
      bytes4 private constant _INTERFACE_ID_ERC1155 = 0xd9b67a26;
  
      /*
       *     bytes4(keccak256('uri(uint256)')) == 0x0e89341c
       */
      bytes4 private constant _INTERFACE_ID_ERC1155_METADATA_URI = 0x0e89341c;
  
      /**
       * @dev See {_setURI}.
       */
      constructor (string memory uri) public {
          _setURI(uri);
  
          // register the supported interfaces to conform to ERC1155 via ERC165
          _registerInterface(_INTERFACE_ID_ERC1155);
  
          // register the supported interfaces to conform to ERC1155MetadataURI via ERC165
          _registerInterface(_INTERFACE_ID_ERC1155_METADATA_URI);
      }
  
      /**
       * @dev See {IERC1155MetadataURI-uri}.
       *
       * This implementation returns the same URI for *all* token types. It relies
       * on the token type ID substituion mechanism
       * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].
       *
       * Clients calling this function must replace the `\{id\}` substring with the
       * actual token type ID.
       */
      function uri(uint256) external view override returns (string memory) {
          return _uri;
      }
  
      /**
       * @dev See {IERC1155-balanceOf}.
       *
       * Requirements:
       *
       * - `account` cannot be the zero address.
       */
      function balanceOf(address account, uint256 id) public view override returns (uint256) {
          require(account != address(0), "ERC1155: balance query for the zero address");
          return _balances[id][account];
      }
  
      /**
       * @dev See {IERC1155-balanceOfBatch}.
       *
       * Requirements:
       *
       * - `accounts` and `ids` must have the same length.
       */
      function balanceOfBatch(
          address[] memory accounts,
          uint256[] memory ids
      )
          public
          view
          override
          returns (uint256[] memory)
      {
          require(accounts.length == ids.length, "ERC1155: accounts and ids length mismatch");
  
          uint256[] memory batchBalances = new uint256[](accounts.length);
  
          for (uint256 i = 0; i < accounts.length; ++i) {
              require(accounts[i] != address(0), "ERC1155: batch balance query for the zero address");
              batchBalances[i] = _balances[ids[i]][accounts[i]];
          }
  
          return batchBalances;
      }
  
      /**
       * @dev See {IERC1155-setApprovalForAll}.
       */
      function setApprovalForAll(address operator, bool approved) public virtual override {
          require(_msgSender() != operator, "ERC1155: setting approval status for self");
  
          _operatorApprovals[_msgSender()][operator] = approved;
          emit ApprovalForAll(_msgSender(), operator, approved);
      }
  
      /**
       * @dev See {IERC1155-isApprovedForAll}.
       */
      function isApprovedForAll(address account, address operator) public view override returns (bool) {
          return _operatorApprovals[account][operator];
      }
  
      /**
       * @dev See {IERC1155-safeTransferFrom}.
       */
      function safeTransferFrom(
          address from,
          address to,
          uint256 id,
          uint256 amount,
          bytes memory data
      )
          public
          virtual
          override
      {
          require(to != address(0), "ERC1155: transfer to the zero address");
          require(
              from == _msgSender() || isApprovedForAll(from, _msgSender()),
              "ERC1155: caller is not owner nor approved"
          );
  
          address operator = _msgSender();
  
          _beforeTokenTransfer(operator, from, to, _asSingletonArray(id), _asSingletonArray(amount), data);
  
          _balances[id][from] = _balances[id][from].sub(amount, "ERC1155: insufficient balance for transfer");
          _balances[id][to] = _balances[id][to].add(amount);
  
          emit TransferSingle(operator, from, to, id, amount);
  
          _doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data);
      }
  
      /**
       * @dev See {IERC1155-safeBatchTransferFrom}.
       */
      function safeBatchTransferFrom(
          address from,
          address to,
          uint256[] memory ids,
          uint256[] memory amounts,
          bytes memory data
      )
          public
          virtual
          override
      {
          require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");
          require(to != address(0), "ERC1155: transfer to the zero address");
          require(
              from == _msgSender() || isApprovedForAll(from, _msgSender()),
              "ERC1155: transfer caller is not owner nor approved"
          );
  
          address operator = _msgSender();
  
          _beforeTokenTransfer(operator, from, to, ids, amounts, data);
  
          for (uint256 i = 0; i < ids.length; ++i) {
              uint256 id = ids[i];
              uint256 amount = amounts[i];
  
              _balances[id][from] = _balances[id][from].sub(
                  amount,
                  "ERC1155: insufficient balance for transfer"
              );
              _balances[id][to] = _balances[id][to].add(amount);
          }
  
          emit TransferBatch(operator, from, to, ids, amounts);
  
          _doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data);
      }
  
      /**
       * @dev Sets a new URI for all token types, by relying on the token type ID
       * substituion mechanism
       * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].
       *
       * By this mechanism, any occurence of the `\{id\}` substring in either the
       * URI or any of the amounts in the JSON file at said URI will be replaced by
       * clients with the token type ID.
       *
       * For example, the `https://token-cdn-domain/\{id\}.json` URI would be
       * interpreted by clients as
       * `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json`
       * for token type ID 0x4cce0.
       *
       * See {uri}.
       *
       * Because these URIs cannot be meaningfully represented by the {URI} event,
       * this function emits no events.
       */
      function _setURI(string memory newuri) internal virtual {
          _uri = newuri;
      }
  
      /**
       * @dev Creates `amount` tokens of token type `id`, and assigns them to `account`.
       *
       * Emits a {TransferSingle} event.
       *
       * Requirements:
       *
       * - `account` cannot be the zero address.
       * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
       * acceptance magic value.
       */
      function _mint(address account, uint256 id, uint256 amount, bytes memory data) internal virtual {
          require(account != address(0), "ERC1155: mint to the zero address");
  
          address operator = _msgSender();
  
          _beforeTokenTransfer(operator, address(0), account, _asSingletonArray(id), _asSingletonArray(amount), data);
  
          _balances[id][account] = _balances[id][account].add(amount);
          emit TransferSingle(operator, address(0), account, id, amount);
  
          _doSafeTransferAcceptanceCheck(operator, address(0), account, id, amount, data);
      }
  
      /**
       * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}.
       *
       * Requirements:
       *
       * - `ids` and `amounts` must have the same length.
       * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
       * acceptance magic value.
       */
      function _mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data) internal virtual {
          require(to != address(0), "ERC1155: mint to the zero address");
          require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");
  
          address operator = _msgSender();
  
          _beforeTokenTransfer(operator, address(0), to, ids, amounts, data);
  
          for (uint i = 0; i < ids.length; i++) {
              _balances[ids[i]][to] = amounts[i].add(_balances[ids[i]][to]);
          }
  
          emit TransferBatch(operator, address(0), to, ids, amounts);
  
          _doSafeBatchTransferAcceptanceCheck(operator, address(0), to, ids, amounts, data);
      }
  
      /**
       * @dev Destroys `amount` tokens of token type `id` from `account`
       *
       * Requirements:
       *
       * - `account` cannot be the zero address.
       * - `account` must have at least `amount` tokens of token type `id`.
       */
      function _burn(address account, uint256 id, uint256 amount) internal virtual {
          require(account != address(0), "ERC1155: burn from the zero address");
  
          address operator = _msgSender();
  
          _beforeTokenTransfer(operator, account, address(0), _asSingletonArray(id), _asSingletonArray(amount), "");
  
          _balances[id][account] = _balances[id][account].sub(
              amount,
              "ERC1155: burn amount exceeds balance"
          );
  
          emit TransferSingle(operator, account, address(0), id, amount);
      }
  
      /**
       * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_burn}.
       *
       * Requirements:
       *
       * - `ids` and `amounts` must have the same length.
       */
      function _burnBatch(address account, uint256[] memory ids, uint256[] memory amounts) internal virtual {
          require(account != address(0), "ERC1155: burn from the zero address");
          require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");
  
          address operator = _msgSender();
  
          _beforeTokenTransfer(operator, account, address(0), ids, amounts, "");
  
          for (uint i = 0; i < ids.length; i++) {
              _balances[ids[i]][account] = _balances[ids[i]][account].sub(
                  amounts[i],
                  "ERC1155: burn amount exceeds balance"
              );
          }
  
          emit TransferBatch(operator, account, address(0), ids, amounts);
      }
  
      /**
       * @dev Hook that is called before any token transfer. This includes minting
       * and burning, as well as batched variants.
       *
       * The same hook is called on both single and batched variants. For single
       * transfers, the length of the `id` and `amount` arrays will be 1.
       *
       * Calling conditions (for each `id` and `amount` pair):
       *
       * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens
       * of token type `id` will be  transferred to `to`.
       * - When `from` is zero, `amount` tokens of token type `id` will be minted
       * for `to`.
       * - when `to` is zero, `amount` of ``from``'s tokens of token type `id`
       * will be burned.
       * - `from` and `to` are never both zero.
       * - `ids` and `amounts` have the same, non-zero length.
       *
       * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
       */
      function _beforeTokenTransfer(
          address operator,
          address from,
          address to,
          uint256[] memory ids,
          uint256[] memory amounts,
          bytes memory data
      )
          internal virtual
      { }
  
      function _doSafeTransferAcceptanceCheck(
          address operator,
          address from,
          address to,
          uint256 id,
          uint256 amount,
          bytes memory data
      )
          private
      {
          if (to.isContract()) {
              try IERC1155Receiver(to).onERC1155Received(operator, from, id, amount, data) returns (bytes4 response) {
                  if (response != IERC1155Receiver(to).onERC1155Received.selector) {
                      revert("ERC1155: ERC1155Receiver rejected tokens");
                  }
              } catch Error(string memory reason) {
                  revert(reason);
              } catch {
                  revert("ERC1155: transfer to non ERC1155Receiver implementer");
              }
          }
      }
  
      function _doSafeBatchTransferAcceptanceCheck(
          address operator,
          address from,
          address to,
          uint256[] memory ids,
          uint256[] memory amounts,
          bytes memory data
      )
          private
      {
          if (to.isContract()) {
              try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, amounts, data) returns (bytes4 response) {
                  if (response != IERC1155Receiver(to).onERC1155BatchReceived.selector) {
                      revert("ERC1155: ERC1155Receiver rejected tokens");
                  }
              } catch Error(string memory reason) {
                  revert(reason);
              } catch {
                  revert("ERC1155: transfer to non ERC1155Receiver implementer");
              }
          }
      }
  
      function _asSingletonArray(uint256 element) private pure returns (uint256[] memory) {
          uint256[] memory array = new uint256[](1);
          array[0] = element;
  
          return array;
      }
  }
  
  
  
  pragma solidity 0.6.6;
  
  interface IMintableERC1155 is IERC1155 {
      /**
       * @notice Creates `amount` tokens of token type `id`, and assigns them to `account`.
       * @dev Should be callable only by MintableERC1155Predicate
       * Make sure minting is done only by this function
       * @param account user address for whom token is being minted
       * @param id token which is being minted
       * @param amount amount of token being minted
       * @param data extra byte data to be accompanied with minted tokens
       */
      function mint(address account, uint256 id, uint256 amount, bytes calldata data) external;
  
      /**
       * @notice Batched version of singular token minting, where
       * for each token in `ids` respective amount to be minted from `amounts`
       * array, for address `to`.
       * @dev Should be callable only by MintableERC1155Predicate
       * Make sure minting is done only by this function
       * @param to user address for whom token is being minted
       * @param ids tokens which are being minted
       * @param amounts amount of each token being minted
       * @param data extra byte data to be accompanied with minted tokens
       */
      function mintBatch(address to, uint256[] calldata ids, uint256[] calldata amounts, bytes calldata data) external;
  }
  
  
  
  pragma solidity 0.6.6;
  
  contract Initializable {
      bool inited = false;
  
      modifier initializer() {
          require(!inited, "already inited");
          _;
          inited = true;
      }
  }
  
  
  
  pragma solidity 0.6.6;
  
  
  contract EIP712Base is Initializable {
      struct EIP712Domain {
          string name;
          string version;
          address verifyingContract;
          bytes32 salt;
      }
  
      string constant public ERC712_VERSION = "1";
  
      bytes32 internal constant EIP712_DOMAIN_TYPEHASH = keccak256(
          bytes(
              "EIP712Domain(string name,string version,address verifyingContract,bytes32 salt)"
          )
      );
      bytes32 internal domainSeperator;
  
      // supposed to be called once while initializing.
      // one of the contractsa that inherits this contract follows proxy pattern
      // so it is not possible to do this in a constructor
      function _initializeEIP712(
          string memory name
      )
          internal
          initializer
      {
          _setDomainSeperator(name);
      }
  
      function _setDomainSeperator(string memory name) internal {
          domainSeperator = keccak256(
              abi.encode(
                  EIP712_DOMAIN_TYPEHASH,
                  keccak256(bytes(name)),
                  keccak256(bytes(ERC712_VERSION)),
                  address(this),
                  bytes32(getChainId())
              )
          );
      }
  
      function getDomainSeperator() public view returns (bytes32) {
          return domainSeperator;
      }
  
      function getChainId() public pure returns (uint256) {
          uint256 id;
          assembly {
              id := chainid()
          }
          return id;
      }
  
      /**
       * Accept message hash and returns hash message in EIP712 compatible form
       * So that it can be used to recover signer from signature signed using EIP712 formatted data
       * https://eips.ethereum.org/EIPS/eip-712
       * "\\x19" makes the encoding deterministic
       * "\\x01" is the version byte to make it compatible to EIP-191
       */
      function toTypedMessageHash(bytes32 messageHash)
          internal
          view
          returns (bytes32)
      {
          return
              keccak256(
                  abi.encodePacked("\x19\x01", getDomainSeperator(), messageHash)
              );
      }
  }
  
  
  
  pragma solidity 0.6.6;
  
  
  
  contract NativeMetaTransaction is EIP712Base {
      using SafeMath for uint256;
      bytes32 private constant META_TRANSACTION_TYPEHASH = keccak256(
          bytes(
              "MetaTransaction(uint256 nonce,address from,bytes functionSignature)"
          )
      );
      event MetaTransactionExecuted(
          address indexed userAddress,
          address payable indexed relayerAddress,
          bytes functionSignature
      );
      mapping(address => uint256) nonces;
  
      /*
       * Meta transaction structure.
       * No point of including value field here as if user is doing value transfer then he has the funds to pay for gas
       * He should call the desired function directly in that case.
       */
      struct MetaTransaction {
          uint256 nonce;
          address from;
          bytes functionSignature;
      }
  
      function executeMetaTransaction(
          address userAddress,
          bytes calldata functionSignature,
          bytes32 sigR,
          bytes32 sigS,
          uint8 sigV
      ) external payable returns (bytes memory) {
          MetaTransaction memory metaTx = MetaTransaction({
              nonce: nonces[userAddress],
              from: userAddress,
              functionSignature: functionSignature
          });
  
          require(
              verify(userAddress, metaTx, sigR, sigS, sigV),
              "Signer and signature do not match"
          );
  
          // increase nonce for user (to avoid re-use)
          ++nonces[userAddress];
  
          emit MetaTransactionExecuted(
              userAddress,
              msg.sender,
              functionSignature
          );
  
          // Append userAddress and relayer address at the end to extract it from calling context
          (bool success, bytes memory returnData) = address(this).call(
              abi.encodePacked(functionSignature, userAddress)
          );
          require(success, "Function call not successful");
  
          return returnData;
      }
  
      function getNonce(address user) external view returns (uint256 nonce) {
          nonce = nonces[user];
      }
  
      function hashMetaTransaction(MetaTransaction memory metaTx)
          internal
          pure
          returns (bytes32)
      {
          return
              keccak256(
                  abi.encode(
                      META_TRANSACTION_TYPEHASH,
                      metaTx.nonce,
                      metaTx.from,
                      keccak256(metaTx.functionSignature)
                  )
              );
      }
  
      function verify(
          address signer,
          MetaTransaction memory metaTx,
          bytes32 sigR,
          bytes32 sigS,
          uint8 sigV
      ) internal view returns (bool) {
          require(signer != address(0), "NativeMetaTransaction: INVALID_SIGNER");
          return
              signer ==
              ecrecover(
                  toTypedMessageHash(hashMetaTransaction(metaTx)),
                  sigV,
                  sigR,
                  sigS
              );
      }
  }
  
  
  pragma solidity 0.6.6;
  
  abstract contract ContextMixin {
      function msgSender()
          internal
          view
          returns (address payable sender)
      {
          if (msg.sender == address(this)) {
              bytes memory array = msg.data;
              uint256 index = msg.data.length;
              assembly {
                  // Load the 32 bytes word from memory with the address on the lower 20 bytes, and mask those.
                  sender := and(
                      mload(add(array, index)),
                      0xffffffffffffffffffffffffffffffffffffffff
                  )
              }
          } else {
              sender = msg.sender;
          }
          return sender;
      }
  }
  
  
  
  pragma solidity ^0.6.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.0.0, only sets of type `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];
      }
  
      // 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(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(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(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(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));
      }
  }
  
  
  
  pragma solidity ^0.6.0;
  
  
  
  
  /**
   * @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());
          }
      }
  }
  
  
  pragma solidity 0.6.6;
  
  
  contract AccessControlMixin is AccessControl {
      string private _revertMsg;
      function _setupContractId(string memory contractId) internal {
          _revertMsg = string(abi.encodePacked(contractId, ": INSUFFICIENT_PERMISSIONS"));
      }
  
      modifier only(bytes32 role) {
          require(
              hasRole(role, _msgSender()),
              _revertMsg
          );
          _;
      }
  }
  
  
  pragma solidity 0.6.6;
  
  
  contract KeysOfGoldNFTs is ERC1155, AccessControlMixin, NativeMetaTransaction, ContextMixin, IMintableERC1155 {
  
              string public name = "Keys Of Gold";
              string public symbol = "KOG";
              
              uint256 public supply = 15000000;
  
              string public uriPrefix = "ipfs://QmYXB4mECRR516b6pcFHBxsYat7qrLje4HrsH3ossYeX3n/";
              string public uriSuffix = ".json";
  
              // string public uriPrefix = "https://aquamarine-fancy-bat-493.mypinata.cloud/ipfs/QmYXB4mECRR516b6pcFHBxsYat7qrLje4HrsH3ossYeX3n/1.json";
  
              uint256 public mintedThisMonth = 88888888;
              uint256 public monthlyAdminMint = 10000000;
  
              uint256 public initialMintTimestamp;
              uint256 public constant oneMonth =  30 days;
              uint256 public currentMonth;
          
              address public currentAdmin = 0xE3c6D31E8890aEf80a974a7B3EE23E2B10C2e859;
              bytes32 public constant minter = keccak256("minter");
              bytes32 public constant admin = keccak256("admin");
  
              string public uri_ = "ipfs://QmYXB4mECRR516b6pcFHBxsYat7qrLje4HrsH3ossYeX3n/1.json";
  
  
  
          constructor() public ERC1155 (uri_) {
              
              _setupRole(minter, address(0));
              _setupRole(admin, currentAdmin);
  
              initialMintTimestamp = block.timestamp;
  
              _initializeEIP712(uri_);
  
              _mint(currentAdmin, 1, 15000000, "uri_");
  
          }
  
  
          function mint(address account, uint256 id, uint256 amount, bytes calldata data) external override only (minter) {
              _mint(account, id, amount, data);
          }
  
          function mintBatch(address to, uint256[] calldata ids, uint256[] calldata amounts, bytes calldata data) external override only (minter) {
              _mintBatch(to, ids, amounts, data);
          }
  
  
          function adminSetNewAdmin (address newAdmin) external only (admin) {
              _setupRole(admin, newAdmin);
              currentAdmin = newAdmin;
          }
  
  
          function leftToMintThisMonth () public view returns (uint256) {
              return (monthlyAdminMint - mintedThisMonth);
          }
  
  
          function adminMint(uint256 mintAmount) external only (admin) { 
  
              if (leftToMintThisMonth () >= mintAmount) {
                  _mint(currentAdmin, 1, mintAmount, "uri_");
                  supply += mintAmount;
                  mintedThisMonth += mintAmount;
              }
  
              uint256 thisMonth = (block.timestamp - initialMintTimestamp) / oneMonth;
  
              if (thisMonth > currentMonth) {
              mintedThisMonth = 0;
              currentMonth = thisMonth;            
              }
              
          }
  
          function adminMintTo(address to, uint256 mintAmount) external only (admin) { 
  
              if (leftToMintThisMonth () >= mintAmount) {
                  _mint(to, 1, mintAmount, "uri_");
                  supply += mintAmount;
                  mintedThisMonth += mintAmount;
              }
  
              uint256 thisMonth = (block.timestamp - initialMintTimestamp) / oneMonth;
  
              if (thisMonth > currentMonth) {
              mintedThisMonth = 0;
              currentMonth = thisMonth;            
              }
              
          }
  
  
  
          function tokenURI(uint256 _tokenId) public view virtual returns (string memory) {           
  
              string memory currentBaseURI = _baseURI();
              return bytes(currentBaseURI).length > 0
                  ? string(abi.encodePacked(currentBaseURI, "1", uriSuffix))
                  : "";
          }
  
  
          function _baseURI() internal view virtual  returns (string memory) {
              return uriPrefix;
          }
  
  
          function _msgSender() internal override view returns (address payable sender) {
              return ContextMixin.msgSender();
          }
  }