ETH Price: $2,151.08 (-2.77%)

Transaction Decoder

Block:
16615635 at Feb-12-2023 10:23:23 PM +UTC
Transaction Fee:
0.013295814737104084 ETH $28.60
Gas Used:
461,572 Gas / 28.805505397 Gwei

Emitted Events:

807 AdminUpgradeabilityProxy.0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef( 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef, 0x0000000000000000000000008e46832c36eb077efa59dd46501dfb46954b284c, 0x0000000000000000000000002272ecf43a7481088fa2d4ba9109804ed5a31901, 00000000000000000000000000000000000000000000000000000005d21dba00 )
808 AdminUpgradeabilityProxy.0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925( 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925, 0x0000000000000000000000008e46832c36eb077efa59dd46501dfb46954b284c, 0x000000000000000000000000d0c7304156af0a4be17352d8ce214222ec66e8ba, 00000000000000000000000000000000000000000000000000005aca51aa2a00 )
809 EmblemVault.Transfer( _from=0x00000000...000000000, _to=[Sender] 0x8e46832c36eb077efa59dd46501dfb46954b284c, _tokenId=59068308137908521 )

Account State Difference:

  Address   Before After State Difference Code
0x3D658390...1c30776Df
0x82C7a8f7...78a34c6ab
0x8E46832c...6954b284C
2.209965311326274568 Eth
Nonce: 33
2.196669496589170484 Eth
Nonce: 34
0.013295814737104084
0xD0C73041...2Ec66E8ba
(Flashbots: Builder)
1.607317457758611726 Eth1.607779029758611726 Eth0.000461572

Execution Trace

VaultHandlerV7a.buyWithSignature2( _to=0x8E46832c36Eb077EFa59DD46501dfB46954b284C, _tokenId=59068308137908521, _payload=0x89dB316b5a79BfE8B9597B3473D619cDbA79c972, _nonce=461388757099207, signedBlock=16615634, _signature=0x6570EDA8612935EA9DBB602BB7C927FB9A97C2A54292AB4C13AAFE94C73CC8A95CC361CCA04BC7228181ADAB4A67DC01A017FE8C40CA1265CD05613D549AE2F01B )
  • TransparentUpgradeableProxy.17ef7c54( )
    • ClaimedUpgradable.isClaimed( ) => ( False )
      • EmblemVault.ownerOf( _tokenId=59068308137908521 ) => ( _owner=0x0000000000000000000000000000000000000000 )
      • AdminUpgradeabilityProxy.23b872dd( )
        • CircuitsOfValue.transferFrom( from=0x8E46832c36Eb077EFa59DD46501dfB46954b284C, to=0x2272ECf43A7481088FA2d4Ba9109804ED5A31901, value=25000000000 ) => ( True )
        • Null: 0x000...001.8023f09a( )
        • EmblemVault.mint( _to=0x8E46832c36Eb077EFa59DD46501dfB46954b284C, _tokenId=59068308137908521, _uri=https://api.emblemvault.io/s:evmetadata/meta/59068308137908521, _payload=0x89dB316b5a79BfE8B9597B3473D619cDbA79c972 )
          File 1 of 6: VaultHandlerV7a
          /**
           *Submitted for verification at Etherscan.io on 2021-07-14
          */
          // ___________      ___.   .__                                          
          // \\_   _____/ _____\\_ |__ |  |   ____   _____                          
          //  |    __)_ /     \\| __ \\|  | _/ __ \\ /     \\                         
          //  |        \\  Y Y  \\ \\_\\ \\  |_\\  ___/|  Y Y  \\                        
          // /_______  /__|_|  /___  /____/\\___  >__|_|  /                        
          //         \\/      \\/    \\/          \\/      \\/                         
          //     ____   ____            .__   __                                  
          //     \\   \\ /   /____   __ __|  |_/  |_                                
          //      \\   Y   /\\__  \\ |  |  \\  |\\   __\\                               
          //       \\     /  / __ \\|  |  /  |_|  |                                 
          //       \\___/  (____  /____/|____/__|                                 
          //                   \\/                                                
          //   ___ ___                    .___.__                          _________ a
          //  /   |   \\_____    ____    __| _/|  |   ___________  ___  __ |  ____  /
          // /    ~    \\__  \\  /    \\  / __ | |  | _/ __ \\_  __ \\ \\  \\/   /    / /
          // \\    Y    // __ \\|   |  \\/ /_/ | |  |_\\  ___/|  | \\/  \\    /    / /
          //  \\___|_  /(____  /___|  /\\____ | |____/\\___  >__|      \\_/    /_/
          //       \\/      \\/     \\/      \\/           \\/                     
            
          // File: browser/ReentrancyGuard.sol
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.8.4;
          /**
           * @dev Contract module that helps prevent reentrant calls to a function.
           *
           * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
           * available, which can be applied to functions to make sure there are no nested
           * (reentrant) calls to them.
           *
           * Note that because there is a single `nonReentrant` guard, functions marked as
           * `nonReentrant` may not call one another. This can be worked around by making
           * those functions `private`, and then adding `external` `nonReentrant` entry
           * points to them.
           *
           * TIP: If you would like to learn more about reentrancy and alternative ways
           * to protect against it, check out our blog post
           * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
           */
          contract ReentrancyGuard {
              // Booleans are more expensive than uint256 or any type that takes up a full
              // word because each write operation emits an extra SLOAD to first read the
              // slot's contents, replace the bits taken up by the boolean, and then write
              // back. This is the compiler's defense against contract upgrades and
              // pointer aliasing, and it cannot be disabled.
              // The values being non-zero value makes deployment a bit more expensive,
              // but in exchange the refund on every call to nonReentrant will be lower in
              // amount. Since refunds are capped to a percentage of the total
              // transaction's gas, it is best to keep them low in cases like this one, to
              // increase the likelihood of the full refund coming into effect.
              uint256 private constant _NOT_ENTERED = 1;
              uint256 private constant _ENTERED = 2;
              uint256 private _status;
              constructor () {
                  _status = _NOT_ENTERED;
              }
              /**
               * @dev Prevents a contract from calling itself, directly or indirectly.
               * Calling a `nonReentrant` function from another `nonReentrant`
               * function is not supported. It is possible to prevent this from happening
               * by making the `nonReentrant` function external, and make it call a
               * `private` function that does the actual work.
               */
              modifier nonReentrant() {
                  // On the first call to nonReentrant, _notEntered will be true
                  require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
                  // Any calls to nonReentrant after this point will fail
                  _status = _ENTERED;
                  _;
                  // By storing the original value once again, a refund is triggered (see
                  // https://eips.ethereum.org/EIPS/eip-2200)
                  _status = _NOT_ENTERED;
              }
          }
          // File: browser/IERC20Token.sol
          pragma solidity ^0.8.4;
          interface IERC20Token {
              function transfer(address to, uint256 value) external returns (bool);
              function approve(address spender, uint256 value) external returns (bool);
              function transferFrom(address from, address to, uint256 value) external returns (bool);
              function totalSupply() external view returns (uint256);
              function balanceOf(address who) external view returns (uint256);
              function allowance(address owner, address spender) external view returns (uint256);
              event Transfer(address indexed from, address indexed to, uint256 value);
              event Approval(address indexed owner, address indexed spender, uint256 value);
          }
          // File: browser/SafeMath.sol
          pragma solidity ^0.8.4;
          /**
           * @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;
              }
          }
          // File: browser/VaultHandler_v4.sol
          pragma solidity ^0.8.4;
          interface IClaimed {
              function isClaimed(address nftAddress, uint tokenId, bytes32[] calldata proof) external returns(bool);
              function claim(address nftAddress, uint tokenId, address _claimedBy) external;
          }
          pragma experimental ABIEncoderV2;
          pragma solidity ^0.8.4;
          interface IERC721 {
              function burn(uint256 tokenId) external;
              function transferFrom(address from, address to, uint256 tokenId) external;
              function mint( address _to, uint256 _tokenId, string calldata _uri, string calldata _payload) external;
              function changeName(string calldata name, string calldata symbol) external;
              function updateTokenUri(uint256 _tokenId,string memory _uri) external;
              function tokenPayload(uint256 _tokenId) external view returns (string memory);
              function ownerOf(uint256 _tokenId) external returns (address _owner);
              function getApproved(uint256 _tokenId) external returns (address);
              function safeTransferFrom(address _from, address _to, uint256 _tokenId) external;
          }
          interface Ownable {
              function transferOwnership(address newOwner) external;
          }
          interface BasicERC20 {
              function burn(uint256 value) external;
              function mint(address account, uint256 amount) external;
              function decimals() external view returns (uint8);
          }
          contract Context {
              constructor() {}
              // solhint-disable-previous-line no-empty-blocks
              function _msgSender() internal view returns (address payable) {
                  return payable(msg.sender);
              }
          }
          contract Bridged is Context {
              using SafeMath for uint256;
              using SafeMath for uint8;
              using SafeMath for uint;
              address public paymentAddress;
              
              mapping(uint => bool) public chainIds;
              mapping(uint => uint256) public chainBalances;
              
              constructor () {
                  chainIds[1] = true;
                  chainBalances[1] = 200000000000000000;
                  chainIds[137] = true;
                  chainBalances[137] = 200000000000000000;
                  chainIds[80001] = true;
                  chainBalances[80001] = 200000000000000000;
                  chainIds[100] = true;
                  chainBalances[100] = 200000000000000000;
                  chainIds[56] = true;
                  chainBalances[56] = 200000000000000000;
                  chainIds[250] = true;
                  chainBalances[250] = 200000000000000000;
              }
              
              function transferToChain(uint chainId, uint256 amount) public returns (bool) {
                  require(chainIds[chainId], 'Invalid Chain ID');
                  IERC20Token paymentToken = IERC20Token(paymentAddress);
                  require(paymentToken.allowance(_msgSender(), address(this)) >= amount, 'Handler unable to spend ');
                  require(paymentToken.transferFrom(_msgSender(), address(this), amount), 'Transfer ERROR');
                  BasicERC20(paymentAddress).burn(amount);
                  chainBalances[chainId] = chainBalances[chainId].add(amount);
                  emit BridgeDeposit(_msgSender(), amount, chainId);
                  
                  return true;
              }
              
              function _transferFromChain(address _to, uint chainId, uint256 amount) internal returns (bool) {
                  require(chainBalances[chainId] >= amount, 'Can not transfer more than deposited');
                  require(chainIds[chainId], 'Invalid Chain ID');
                  BasicERC20 paymentToken = BasicERC20(paymentAddress);
                  paymentToken.mint(_to, amount);
                  chainBalances[chainId] = chainBalances[chainId].sub(amount);
                  emit BridgeWithdrawal(_msgSender(), amount, chainId);
                  
                  return true;
              }
              
              event BridgeDeposit(address indexed sender, uint256 indexed amount, uint chainId);
              event BridgeWithdrawal(address indexed sender, uint256 indexed amount, uint chainId);
              
              function _addChainId(uint chainId) internal returns (bool) {
                  chainIds[chainId] = true;
                  return true;
              }
              
              function _removeChainId(uint chainId) internal returns (bool) {
                  chainIds[chainId] = false;
                  return true;
              }
              
          }
          contract VaultHandlerV7a is ReentrancyGuard, Bridged { 
              
              using SafeMath for uint256;
              using SafeMath for uint8;
              address payable private owner;
              string public metadataBaseUri;
              bool public initialized;
              address public nftAddress;
              address public recipientAddress;
              address public claimAddress;
              uint256 public price;
              bool public shouldBurn = false;
              uint internal blockWindow = 3;
              
              struct PreMint {
                  string payload;
                  bytes32 preImage;
              }
              
              struct PreTransfer {
                  string payload;
                  bytes32 preImage;
                  address _from;
              }
              
              struct Offer {
                  uint tokenId;
                  address _from;
              }
              mapping(address => mapping(uint => PreMint)) preMints;
              mapping(address => mapping(uint => PreMint)) preMintsByIndex;
              mapping(address => uint) preMintCounts;
              
              mapping(uint => PreTransfer) preTransfers;
              mapping(uint => mapping(uint => PreTransfer)) preTransfersByIndex;
              mapping(uint => uint) preTransferCounts;
              
              mapping(uint => Offer[]) offers;
              mapping(uint => Offer[]) rejected;
              mapping(address => mapping(uint => Offer)) offered;
              
              mapping(address => bool) public blacklisted;
              mapping(address => bool) public witnesses;
              mapping(uint256 => bool) usedNonces;
              mapping(uint256 => bool) public usedTokenIds;
              
              // event for EVM logging
              event OwnerSet(address indexed oldOwner, address indexed newOwner);
              
              // modifier to check if caller is owner
              modifier isOwner() {
                  // If the first argument of 'require' evaluates to 'false', execution terminates and all
                  // changes to the state and to Ether balances are reverted.
                  // This used to consume all gas in old EVM versions, but not anymore.
                  // It is often a good idea to use 'require' to check if functions are called correctly.
                  // As a second argument, you can also provide an explanation about what went wrong.
                  require(msg.sender == owner, "Caller is not owner");
                  _;
              }
              // modifier to check if caller blacklisted
              modifier notBlacklisted() {
                  require(!blacklisted[msg.sender], "Caller is blacklisted");
                  _;
              }
              
              /**
               * @dev Change owner
               * @param newOwner address of new owner
               */
              function transferOwnership(address payable newOwner) public isOwner {
                  emit OwnerSet(owner, newOwner);
                  owner = newOwner;
              }
              
              /**
               * @dev Return owner address 
               * @return address of owner
               */
              function getOwner() external view returns (address) {
                  return owner;
              }
              
              constructor(address _nftAddress, address _paymentAddress, address _recipientAddress, uint256 _price) {
                  owner = _msgSender(); // 'msg.sender' is sender of current call, contract deployer for a constructor
                  emit OwnerSet(address(0), owner);
                  addWitness(owner);
                  metadataBaseUri = "https://api.emblemvault.io/s:evmetadata/meta/";
                  nftAddress = _nftAddress;
                  paymentAddress = _paymentAddress;
                  recipientAddress = _recipientAddress;
                  initialized = true;
                  uint decimals = BasicERC20(paymentAddress).decimals();
                  price = _price * 10 ** decimals;
              }
              
              function claim(uint256 tokenId) public isOwner {
                  bytes32[] memory proof;
                  IClaimed claimer = IClaimed(claimAddress);
                  require(!claimer.isClaimed(nftAddress, tokenId, proof), "Already Claimed");
                  
                  IERC721 token = IERC721(nftAddress);
                  token.burn(tokenId);
              }
              function claimOnChain(uint256 tokenId) public nonReentrant notBlacklisted {
                  bytes32[] memory proof;
                  IClaimed claimer = IClaimed(claimAddress);
                  require(!claimer.isClaimed(nftAddress, tokenId, proof), "Already Claimed");
                  IERC721 token = IERC721(nftAddress);
                  require(token.ownerOf(tokenId) == _msgSender(), "Not Token Owner");
                  token.burn(tokenId);
                  claimer.claim(nftAddress, tokenId, _msgSender());
              }
              function addClaimAddress(address _address) public isOwner {
                  claimAddress = _address;
              }
              function toggleBlacklist(address _address) public isOwner {
                  blacklisted[_address] = !blacklisted[_address];
              }
              function adjustBlockWindow(uint size) public isOwner {
                  blockWindow = size;
              }
              function buyWithSignature2(address _to, uint256 _tokenId, string calldata _payload, uint256 _nonce, uint signedBlock, bytes calldata _signature) public payable notBlacklisted {
                  bytes32[] memory proof;
                  require(signedBlock.add(blockWindow) > block.number, 'Signature expired');
                  require(!IClaimed(claimAddress).isClaimed(nftAddress, _tokenId, proof) && !usedTokenIds[_tokenId], "Already claimed");
                  IERC721 nftToken = IERC721(nftAddress);
                  if (shouldBurn) {
                      require(IERC20Token(paymentAddress).transferFrom(msg.sender, address(this), price), 'Transfer ERROR'); // Payment sent to recipient
                      BasicERC20(paymentAddress).burn(price);
                  } else {
                      require(IERC20Token(paymentAddress).transferFrom(msg.sender, address(recipientAddress), price), 'Transfer ERROR'); // Payment sent to recipient
                  }
                  
                  address signer = getAddressFromSignature(_tokenId, _nonce, _payload, signedBlock, _signature);
                  require(witnesses[signer], 'Not Witnessed');
                  usedNonces[_nonce] = true;
                  string memory _uri = concat(metadataBaseUri, uintToStr(_tokenId));
                  nftToken.mint(_to, _tokenId, _uri, _payload);
                  usedTokenIds[_tokenId] = true;
              }
              
              
              function buyWithSignature(address _to, uint256 _tokenId, string calldata _payload, uint256 _nonce, bytes calldata _signature) public isOwner payable {
                  IERC20Token paymentToken = IERC20Token(paymentAddress);
                  IERC721 nftToken = IERC721(nftAddress);
                  if (shouldBurn) {
                      require(paymentToken.transferFrom(msg.sender, address(this), price), 'Transfer ERROR'); // Payment sent to recipient
                      BasicERC20(paymentAddress).burn(price);
                  } else {
                      require(paymentToken.transferFrom(msg.sender, address(recipientAddress), price), 'Transfer ERROR'); // Payment sent to recipient
                  }        
                  address signer = getAddressFromSignature(_tokenId, _nonce, _payload, _signature);
                  require(witnesses[signer], 'Not Witnessed');
                  usedNonces[_nonce] = true;
                  string memory _uri = concat(metadataBaseUri, uintToStr(_tokenId));
                  nftToken.mint(_to, _tokenId, _uri, _payload);
              }
              
              
              function addPreMint(address _for, string calldata _payload, uint256 _tokenId, bytes32 preImage) public isOwner {
                  try IERC721(nftAddress).tokenPayload(_tokenId) returns (string memory) {
                      revert('NFT Exists with this ID');
                  } catch {
                      require(!_duplicatePremint(_for, _tokenId), 'Duplicate PreMint');
                      preMintCounts[_for] = preMintCounts[_for].add(1);
                      preMints[_for][_tokenId] = PreMint(_payload, preImage);
                      preMintsByIndex[_for][preMintCounts[_for]] = preMints[_for][_tokenId];
                  }
              }
              
              function _duplicatePremint(address _for, uint256 _tokenId) internal view returns (bool) {
                  string memory data = preMints[_for][_tokenId].payload;
                  bytes32 NULL = keccak256(bytes(''));
                  return keccak256(bytes(data)) != NULL;
              }
              
              function deletePreMint(address _for, uint256 _tokenId) public isOwner {
                  delete preMintsByIndex[_for][preMintCounts[_for]];
                  preMintCounts[_for] = preMintCounts[_for].sub(1);
                  delete preMints[_for][_tokenId];
              }
              
              function getPreMint(address _for, uint256 _tokenId) public view returns (PreMint memory) {
                  return preMints[_for][_tokenId];
              }
              
              function checkPreMintImage(string memory image, bytes32 preImage) public pure returns (bytes32, bytes32, bool) {
                  bytes32 calculated = sha256(abi.encodePacked(image));
                  bytes32 preBytes = preImage;
                  return (calculated, preBytes, calculated == preBytes);
              }
              
              function getPreMintCount(address _for) public view returns (uint length) {
                  return preMintCounts[_for];
              }
              
              function getPreMintByIndex(address _for, uint index) public view returns (PreMint memory) {
                  return preMintsByIndex[_for][index];
              }
              
              function toggleShouldBurn() public isOwner {
                  shouldBurn = !shouldBurn;
              }
              
              /* Transfer with code */
              function addWitness(address _witness) public isOwner {
                  witnesses[_witness] = true;
              }
              function removeWitness(address _witness) public isOwner {
                  witnesses[_witness] = false;
              }
              
              function getAddressFromSignature(uint256 _tokenId, uint256 _nonce, bytes memory signature) public view returns (address) {
                  require(!usedNonces[_nonce]);
                  bytes32 hash = keccak256(abi.encodePacked(concat(uintToStr(_tokenId), uintToStr(_nonce))));
                  address addressFromSig = recoverSigner(hash, signature);
                  return addressFromSig;
              }
              
              function getAddressFromSignature(uint256 _tokenId, uint256 _nonce, string calldata payload, bytes memory signature) public view returns (address) {
                  require(!usedNonces[_nonce]);
                  string memory combined = concat(uintToStr(_tokenId), payload);
                  bytes32 hash = keccak256(abi.encodePacked(concat(combined, uintToStr(_nonce))));
                  address addressFromSig = recoverSigner(hash, signature);
                  return addressFromSig;
              }
              function getAddressFromSignature(uint256 _tokenId, uint256 _nonce, string calldata payload, uint blockNumber, bytes memory signature) public view returns (address) {
                  require(!usedNonces[_nonce]);
                  string memory combined = concat(concat(uintToStr(_tokenId), payload), uintToStr(blockNumber));
                  bytes32 hash = keccak256(abi.encodePacked(concat(combined, uintToStr(_nonce))));
                  address addressFromSig = recoverSigner(hash, signature);
                  return addressFromSig;
              }
              
              function getAddressFromSignature(bytes32 _hash, bytes calldata signature) public pure returns (address) {
                  address addressFromSig = recoverSigner(_hash, signature);
                  return addressFromSig;
              }
              
              function getHash(string calldata _payload) public pure returns (bytes32) {
                  bytes32 hash = keccak256(abi.encodePacked(_payload));
                  return hash;
              }
              
              function transferWithCode(uint256 _tokenId, string calldata code, address _to, uint256 _nonce,  bytes memory signature) public payable notBlacklisted {
                  require(witnesses[getAddressFromSignature(_tokenId, _nonce, signature)], 'Not Witnessed');
                  IERC721 nftToken = IERC721(nftAddress);
                  PreTransfer memory preTransfer = preTransfers[_tokenId];
                  require(preTransfer.preImage == sha256(abi.encodePacked(code)), 'Code does not match'); // Payload should match
                  nftToken.transferFrom(preTransfer._from, _to,  _tokenId);
                  delete preTransfers[_tokenId];
                  delete preTransfersByIndex[_tokenId][preTransferCounts[_tokenId]];
                  preTransferCounts[_tokenId] = preTransferCounts[_tokenId].sub(1);
                  usedNonces[_nonce] = true;
              }
              
              function addPreTransfer(uint256 _tokenId, bytes32 preImage) public {
                  require(!_duplicatePretransfer(_tokenId), 'Duplicate PreTransfer');
                  preTransferCounts[_tokenId] = preTransferCounts[_tokenId].add(1);
                  preTransfers[_tokenId] = PreTransfer("payload", preImage, msg.sender);
                  preTransfersByIndex[_tokenId][preTransferCounts[_tokenId]] = preTransfers[_tokenId];
              }
              
              function _duplicatePretransfer(uint256 _tokenId) internal view returns (bool) {
                  string memory data = preTransfers[_tokenId].payload;
                  bytes32 NULL = keccak256(bytes(''));
                  return keccak256(bytes(data)) != NULL;
              }
              
              function deletePreTransfer(uint256 _tokenId) public {
                  require(preTransfers[_tokenId]._from == msg.sender, 'PreTransfer does not belong to sender');
                  delete preTransfersByIndex[_tokenId][preTransferCounts[_tokenId]];
                  preTransferCounts[_tokenId] = preTransferCounts[_tokenId].sub(1);
                  delete preTransfers[_tokenId];
              }
              
              function getPreTransfer(uint256 _tokenId) public view returns (PreTransfer memory) {
                  return preTransfers[_tokenId];
              }
              
              function checkPreTransferImage(string memory image, bytes32 preImage) public pure returns (bytes32, bytes32, bool) {
                  bytes32 calculated = sha256(abi.encodePacked(image));
                  bytes32 preBytes = preImage;
                  return (calculated, preBytes, calculated == preBytes);
              }
              
              function getPreTransferCount(uint256 _tokenId) public view returns (uint length) {
                  return preTransferCounts[_tokenId];
              }
              
              function getPreTransferByIndex(uint256 _tokenId, uint index) public view returns (PreTransfer memory) {
                  return preTransfersByIndex[_tokenId][index];
              }
              
              function changeMetadataBaseUri(string calldata _uri) public isOwner {
                  metadataBaseUri = _uri;
              }
              
              function transferPaymentOwnership(address newOwner) external isOwner {
                  Ownable paymentToken = Ownable(paymentAddress);
                  paymentToken.transferOwnership(newOwner);
              }
              
              function transferNftOwnership(address newOwner) external isOwner {
                  Ownable nftToken = Ownable(nftAddress);
                  nftToken.transferOwnership(newOwner);
              }
              
              function mint( address _to, uint256 _tokenId, string calldata _uri, string calldata _payload) external isOwner {
                  IERC721 nftToken = IERC721(nftAddress);
                  nftToken.mint(_to, _tokenId, _uri, _payload);
              }
              
              function changeName(string calldata name, string calldata symbol) external isOwner {
                  IERC721 nftToken = IERC721(nftAddress);
                  nftToken.changeName(name, symbol);
              }
              
              function updateTokenUri(uint256 _tokenId,string memory _uri) external isOwner {
                  IERC721 nftToken = IERC721(nftAddress);
                  nftToken.updateTokenUri(_tokenId, _uri);
              }
              
              function getPaymentDecimals() public view returns (uint8){
                  BasicERC20 token = BasicERC20(paymentAddress);
                  return token.decimals();
              }
              
              function changePayment(address payment) public isOwner {
                 paymentAddress = payment;
              }
              
              // function changeCoupon(address coupon) public isOwner {
              //   couponAddress = coupon;
              // }
              
              function changeRecipient(address _recipient) public isOwner {
                 recipientAddress = _recipient;
              }
              
              function changeNft(address token) public isOwner {
                  nftAddress = token;
              }
              
              function changePrice(uint256 _price) public isOwner {
                  uint decimals = BasicERC20(paymentAddress).decimals();
                  price = _price * 10 ** decimals;
              }
              
              // function changeOfferPrice(uint256 _price) public isOwner {
              //     uint decimals = BasicERC20(couponAddress).decimals();
              //     offerPrice = _price * 10 ** decimals;
              // }
              
              function addChainId(uint chainId) public isOwner returns (bool) {
                  return (_addChainId(chainId));
              }
              
              function removeChainId(uint chainId) public isOwner returns (bool) {
                  return (_removeChainId(chainId));
              }
              
              function transferFromChain(address _to, uint chainId, uint256 amount) public isOwner returns (bool) {
                  return _transferFromChain(_to, chainId, amount);
              }
              
              function concat(string memory a, string memory b) internal pure returns (string memory) {
                  return string(abi.encodePacked(a, b));
              }
              /**
              * @dev Recover signer address from a message by using their signature
              * @param hash bytes32 message, the hash is the signed message. What is recovered is the signer address.
              * @param sig bytes signature, the signature is generated using web3.eth.sign(). Inclusive "0x..."
              */
              function recoverSigner(bytes32 hash, bytes memory sig) internal pure returns (address) {
                  require(sig.length == 65, "Require correct length");
                  bytes32 r;
                  bytes32 s;
                  uint8 v;
                  // Divide the signature in r, s and v variables
                  assembly {
                      r := mload(add(sig, 32))
                      s := mload(add(sig, 64))
                      v := byte(0, mload(add(sig, 96)))
                  }
                  // Version of signature should be 27 or 28, but 0 and 1 are also possible versions
                  if (v < 27) {
                      v += 27;
                  }
                  require(v == 27 || v == 28, "Signature version not match");
                  return recoverSigner2(hash, v, r, s);
              }
              function recoverSigner2(bytes32 h, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
                  bytes memory prefix = "\\x19Ethereum Signed Message:\
          32";
                  bytes32 prefixedHash = keccak256(abi.encodePacked(prefix, h));
                  address addr = ecrecover(prefixedHash, v, r, s);
                  return addr;
              }
              
              function uintToStr(uint256 value) internal pure returns (string memory) {
                  // Inspired by OraclizeAPI's implementation - MIT licence
                  // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
                  if (value == 0) {
                      return "0";
                  }
                  uint256 temp = value;
                  uint256 digits;
                  while (temp != 0) {
                      digits++;
                      temp /= 10;
                  }
                  bytes memory buffer = new bytes(digits);
                  while (value != 0) {
                      digits -= 1;
                      buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
                      value /= 10;
                  }
                  return string(buffer);
              }
              
              function stringToBytes32(string memory source) internal pure returns (bytes32 result) {
                  bytes memory tempEmptyStringTest = bytes(source);
                  if (tempEmptyStringTest.length == 0) {
                      return 0x0;
                  }
              
                  assembly {
                      result := mload(add(source, 32))
                  }
              }
              function bytes32ToStr(bytes32 _bytes32) internal pure returns (string memory) {
                  // string memory str = string(_bytes32);
                  // TypeError: Explicit type conversion not allowed from "bytes32" to "string storage pointer"
                  // thus we should fist convert bytes32 to bytes (to dynamically-sized byte array)
              
                  bytes memory bytesArray = new bytes(32);
                  for (uint256 i; i < 32; i++) {
                      bytesArray[i] = _bytes32[i];
                      }
                  return string(bytesArray);
              }
              function asciiToInteger(bytes32 x) public pure returns (uint256) {
                  uint256 y;
                  for (uint256 i = 0; i < 32; i++) {
                      uint256 c = (uint256(x) >> (i * 8)) & 0xff;
                      if (48 <= c && c <= 57)
                          y += (c - 48) * 10 ** i;
                      else
                          break;
                  }
                  return y;
              }
              function toString(address account) public pure returns(string memory) {
                  return toString(abi.encodePacked(account));
              }
              
              function toString(uint256 value) public pure returns(string memory) {
                  return toString(abi.encodePacked(value));
              }
              
              function toString(bytes32 value) public pure returns(string memory) {
                  return toString(abi.encodePacked(value));
              }
              
              function toString(bytes memory data) public pure returns(string memory) {
                  bytes memory alphabet = "0123456789abcdef";
              
                  bytes memory str = new bytes(2 + data.length * 2);
                  str[0] = "0";
                  str[1] = "x";
                  for (uint i = 0; i < data.length; i++) {
                      str[2+i*2] = alphabet[uint(uint8(data[i] >> 4))];
                      str[3+i*2] = alphabet[uint(uint8(data[i] & 0x0f))];
                  }
                  return string(str);
              }
          }

          File 2 of 6: AdminUpgradeabilityProxy
          // File: zos-lib/contracts/upgradeability/Proxy.sol
          
          pragma solidity ^0.5.0;
          
          /**
           * @title Proxy
           * @dev Implements delegation of calls to other contracts, with proper
           * forwarding of return values and bubbling of failures.
           * It defines a fallback function that delegates all calls to the address
           * returned by the abstract _implementation() internal function.
           */
          contract Proxy {
            /**
             * @dev Fallback function.
             * Implemented entirely in `_fallback`.
             */
            function () payable external {
              _fallback();
            }
          
            /**
             * @return The Address of the implementation.
             */
            function _implementation() internal view returns (address);
          
            /**
             * @dev Delegates execution to an implementation contract.
             * This is a low level function that doesn't return to its internal call site.
             * It will return to the external caller whatever the implementation returns.
             * @param implementation Address to delegate.
             */
            function _delegate(address implementation) internal {
              assembly {
                // Copy msg.data. We take full control of memory in this inline assembly
                // block because it will not return to Solidity code. We overwrite the
                // Solidity scratch pad at memory position 0.
                calldatacopy(0, 0, calldatasize)
          
                // Call the implementation.
                // out and outsize are 0 because we don't know the size yet.
                let result := delegatecall(gas, implementation, 0, calldatasize, 0, 0)
          
                // Copy the returned data.
                returndatacopy(0, 0, returndatasize)
          
                switch result
                // delegatecall returns 0 on error.
                case 0 { revert(0, returndatasize) }
                default { return(0, returndatasize) }
              }
            }
          
            /**
             * @dev Function that is run as the first thing in the fallback function.
             * Can be redefined in derived contracts to add functionality.
             * Redefinitions must call super._willFallback().
             */
            function _willFallback() internal {
            }
          
            /**
             * @dev fallback implementation.
             * Extracted to enable manual triggering.
             */
            function _fallback() internal {
              _willFallback();
              _delegate(_implementation());
            }
          }
          
          // File: zos-lib/contracts/utils/Address.sol
          
          pragma solidity ^0.5.0;
          
          /**
           * Utility library of inline functions on addresses
           *
           * Source https://raw.githubusercontent.com/OpenZeppelin/openzeppelin-solidity/v2.1.3/contracts/utils/Address.sol
           * This contract is copied here and renamed from the original to avoid clashes in the compiled artifacts
           * when the user imports a zos-lib contract (that transitively causes this contract to be compiled and added to the
           * build/artifacts folder) as well as the vanilla Address implementation from an openzeppelin version.
           */
          library ZOSLibAddress {
              /**
               * Returns whether the target address is a contract
               * @dev This function will return false if invoked during the constructor of a contract,
               * as the code is not actually created until after the constructor finishes.
               * @param account address of the account to check
               * @return whether the target address is a contract
               */
              function isContract(address account) internal view returns (bool) {
                  uint256 size;
                  // XXX Currently there is no better way to check if there is a contract in an address
                  // than to check the size of the code at that address.
                  // See https://ethereum.stackexchange.com/a/14016/36603
                  // for more details about how this works.
                  // TODO Check this again before the Serenity release, because all addresses will be
                  // contracts then.
                  // solhint-disable-next-line no-inline-assembly
                  assembly { size := extcodesize(account) }
                  return size > 0;
              }
          }
          
          // File: zos-lib/contracts/upgradeability/BaseUpgradeabilityProxy.sol
          
          pragma solidity ^0.5.0;
          
          
          
          /**
           * @title BaseUpgradeabilityProxy
           * @dev This contract implements a proxy that allows to change the
           * implementation address to which it will delegate.
           * Such a change is called an implementation upgrade.
           */
          contract BaseUpgradeabilityProxy is Proxy {
            /**
             * @dev Emitted when the implementation is upgraded.
             * @param implementation Address of the new implementation.
             */
            event Upgraded(address indexed implementation);
          
            /**
             * @dev Storage slot with the address of the current implementation.
             * This is the keccak-256 hash of "org.zeppelinos.proxy.implementation", and is
             * validated in the constructor.
             */
            bytes32 internal constant IMPLEMENTATION_SLOT = 0x7050c9e0f4ca769c69bd3a8ef740bc37934f8e2c036e5a723fd8ee048ed3f8c3;
          
            /**
             * @dev Returns the current implementation.
             * @return Address of the current implementation
             */
            function _implementation() internal view returns (address impl) {
              bytes32 slot = IMPLEMENTATION_SLOT;
              assembly {
                impl := sload(slot)
              }
            }
          
            /**
             * @dev Upgrades the proxy to a new implementation.
             * @param newImplementation Address of the new implementation.
             */
            function _upgradeTo(address newImplementation) internal {
              _setImplementation(newImplementation);
              emit Upgraded(newImplementation);
            }
          
            /**
             * @dev Sets the implementation address of the proxy.
             * @param newImplementation Address of the new implementation.
             */
            function _setImplementation(address newImplementation) internal {
              require(ZOSLibAddress.isContract(newImplementation), "Cannot set a proxy implementation to a non-contract address");
          
              bytes32 slot = IMPLEMENTATION_SLOT;
          
              assembly {
                sstore(slot, newImplementation)
              }
            }
          }
          
          // File: zos-lib/contracts/upgradeability/UpgradeabilityProxy.sol
          
          pragma solidity ^0.5.0;
          
          
          /**
           * @title UpgradeabilityProxy
           * @dev Extends BaseUpgradeabilityProxy with a constructor for initializing
           * implementation and init data.
           */
          contract UpgradeabilityProxy is BaseUpgradeabilityProxy {
            /**
             * @dev Contract constructor.
             * @param _logic Address of the initial implementation.
             * @param _data Data to send as msg.data to the implementation to initialize the proxied contract.
             * It should include the signature and the parameters of the function to be called, as described in
             * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.
             * This parameter is optional, if no data is given the initialization call to proxied contract will be skipped.
             */
            constructor(address _logic, bytes memory _data) public payable {
              assert(IMPLEMENTATION_SLOT == keccak256("org.zeppelinos.proxy.implementation"));
              _setImplementation(_logic);
              if(_data.length > 0) {
                (bool success,) = _logic.delegatecall(_data);
                require(success);
              }
            }  
          }
          
          // File: zos-lib/contracts/upgradeability/BaseAdminUpgradeabilityProxy.sol
          
          pragma solidity ^0.5.0;
          
          
          /**
           * @title BaseAdminUpgradeabilityProxy
           * @dev This contract combines an upgradeability proxy with an authorization
           * mechanism for administrative tasks.
           * All external functions in this contract must be guarded by the
           * `ifAdmin` modifier. See ethereum/solidity#3864 for a Solidity
           * feature proposal that would enable this to be done automatically.
           */
          contract BaseAdminUpgradeabilityProxy is BaseUpgradeabilityProxy {
            /**
             * @dev Emitted when the administration has been transferred.
             * @param previousAdmin Address of the previous admin.
             * @param newAdmin Address of the new admin.
             */
            event AdminChanged(address previousAdmin, address newAdmin);
          
            /**
             * @dev Storage slot with the admin of the contract.
             * This is the keccak-256 hash of "org.zeppelinos.proxy.admin", and is
             * validated in the constructor.
             */
            bytes32 internal constant ADMIN_SLOT = 0x10d6a54a4754c8869d6886b5f5d7fbfa5b4522237ea5c60d11bc4e7a1ff9390b;
          
            /**
             * @dev Modifier to check whether the `msg.sender` is the admin.
             * If it is, it will run the function. Otherwise, it will delegate the call
             * to the implementation.
             */
            modifier ifAdmin() {
              if (msg.sender == _admin()) {
                _;
              } else {
                _fallback();
              }
            }
          
            /**
             * @return The address of the proxy admin.
             */
            function admin() external ifAdmin returns (address) {
              return _admin();
            }
          
            /**
             * @return The address of the implementation.
             */
            function implementation() external ifAdmin returns (address) {
              return _implementation();
            }
          
            /**
             * @dev Changes the admin of the proxy.
             * Only the current admin can call this function.
             * @param newAdmin Address to transfer proxy administration to.
             */
            function changeAdmin(address newAdmin) external ifAdmin {
              require(newAdmin != address(0), "Cannot change the admin of a proxy to the zero address");
              emit AdminChanged(_admin(), newAdmin);
              _setAdmin(newAdmin);
            }
          
            /**
             * @dev Upgrade the backing implementation of the proxy.
             * Only the admin can call this function.
             * @param newImplementation Address of the new implementation.
             */
            function upgradeTo(address newImplementation) external ifAdmin {
              _upgradeTo(newImplementation);
            }
          
            /**
             * @dev Upgrade the backing implementation of the proxy and call a function
             * on the new implementation.
             * This is useful to initialize the proxied contract.
             * @param newImplementation Address of the new implementation.
             * @param data Data to send as msg.data in the low level call.
             * It should include the signature and the parameters of the function to be called, as described in
             * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.
             */
            function upgradeToAndCall(address newImplementation, bytes calldata data) payable external ifAdmin {
              _upgradeTo(newImplementation);
              (bool success,) = newImplementation.delegatecall(data);
              require(success);
            }
          
            /**
             * @return The admin slot.
             */
            function _admin() internal view returns (address adm) {
              bytes32 slot = ADMIN_SLOT;
              assembly {
                adm := sload(slot)
              }
            }
          
            /**
             * @dev Sets the address of the proxy admin.
             * @param newAdmin Address of the new proxy admin.
             */
            function _setAdmin(address newAdmin) internal {
              bytes32 slot = ADMIN_SLOT;
          
              assembly {
                sstore(slot, newAdmin)
              }
            }
          
            /**
             * @dev Only fall back when the sender is not the admin.
             */
            function _willFallback() internal {
              require(msg.sender != _admin(), "Cannot call fallback function from the proxy admin");
              super._willFallback();
            }
          }
          
          // File: zos-lib/contracts/upgradeability/AdminUpgradeabilityProxy.sol
          
          pragma solidity ^0.5.0;
          
          
          /**
           * @title AdminUpgradeabilityProxy
           * @dev Extends from BaseAdminUpgradeabilityProxy with a constructor for 
           * initializing the implementation, admin, and init data.
           */
          contract AdminUpgradeabilityProxy is BaseAdminUpgradeabilityProxy, UpgradeabilityProxy {
            /**
             * Contract constructor.
             * @param _logic address of the initial implementation.
             * @param _admin Address of the proxy administrator.
             * @param _data Data to send as msg.data to the implementation to initialize the proxied contract.
             * It should include the signature and the parameters of the function to be called, as described in
             * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.
             * This parameter is optional, if no data is given the initialization call to proxied contract will be skipped.
             */
            constructor(address _logic, address _admin, bytes memory _data) UpgradeabilityProxy(_logic, _data) public payable {
              assert(ADMIN_SLOT == keccak256("org.zeppelinos.proxy.admin"));
              _setAdmin(_admin);
            }
          }

          File 3 of 6: EmblemVault
          // File: browser/github/0xcert/ethereum-erc721/src/contracts/ownership/ownable.sol
          
          pragma solidity 0.6.2;
          
          /**
           * @dev The contract has an owner address, and provides basic authorization control whitch
           * simplifies the implementation of user permissions. This contract is based on the source code at:
           * https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/ownership/Ownable.sol
           */
          contract Ownable
          {
          
            /**
             * @dev Error constants.
             */
            string public constant NOT_CURRENT_OWNER = "018001";
            string public constant CANNOT_TRANSFER_TO_ZERO_ADDRESS = "018002";
          
            /**
             * @dev Current owner address.
             */
            address public owner;
          
            /**
             * @dev An event which is triggered when the owner is changed.
             * @param previousOwner The address of the previous owner.
             * @param newOwner The address of the new owner.
             */
            event OwnershipTransferred(
              address indexed previousOwner,
              address indexed newOwner
            );
          
            /**
             * @dev The constructor sets the original `owner` of the contract to the sender account.
             */
            constructor()
              public
            {
              owner = msg.sender;
            }
          
            /**
             * @dev Throws if called by any account other than the owner.
             */
            modifier onlyOwner()
            {
              require(msg.sender == owner, NOT_CURRENT_OWNER);
              _;
            }
          
            /**
             * @dev Allows the current owner to transfer control of the contract to a newOwner.
             * @param _newOwner The address to transfer ownership to.
             */
            function transferOwnership(
              address _newOwner
            )
              public
              onlyOwner
            {
              require(_newOwner != address(0), CANNOT_TRANSFER_TO_ZERO_ADDRESS);
              emit OwnershipTransferred(owner, _newOwner);
              owner = _newOwner;
            }
          
          }
          
          // File: browser/github/0xcert/ethereum-erc721/src/contracts/tokens/erc721-enumerable.sol
          
          pragma solidity 0.6.2;
          
          /**
           * @dev Optional enumeration extension for ERC-721 non-fungible token standard.
           * See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md.
           */
          interface ERC721Enumerable
          {
          
            /**
             * @dev Returns a count of valid NFTs tracked by this contract, where each one of them has an
             * assigned and queryable owner not equal to the zero address.
             * @return Total supply of NFTs.
             */
            function totalSupply()
              external
              view
              returns (uint256);
          
            /**
             * @dev Returns the token identifier for the `_index`th NFT. Sort order is not specified.
             * @param _index A counter less than `totalSupply()`.
             * @return Token id.
             */
            function tokenByIndex(
              uint256 _index
            )
              external
              view
              returns (uint256);
          
            /**
             * @dev Returns the token identifier for the `_index`th NFT assigned to `_owner`. Sort order is
             * not specified. It throws if `_index` >= `balanceOf(_owner)` or if `_owner` is the zero address,
             * representing invalid NFTs.
             * @param _owner An address where we are interested in NFTs owned by them.
             * @param _index A counter less than `balanceOf(_owner)`.
             * @return Token id.
             */
            function tokenOfOwnerByIndex(
              address _owner,
              uint256 _index
            )
              external
              view
              returns (uint256);
          
          }
          
          // File: browser/github/0xcert/ethereum-erc721/src/contracts/tokens/erc721-metadata.sol
          
          pragma solidity 0.6.2;
          
          /**
           * @dev Optional metadata extension for ERC-721 non-fungible token standard.
           * See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md.
           */
          interface ERC721Metadata
          {
          
            /**
             * @dev Returns a descriptive name for a collection of NFTs in this contract.
             * @return _name Representing name.
             */
            function name()
              external
              view
              returns (string memory _name);
          
            /**
             * @dev Returns a abbreviated name for a collection of NFTs in this contract.
             * @return _symbol Representing symbol.
             */
            function symbol()
              external
              view
              returns (string memory _symbol);
          
            /**
             * @dev Returns a distinct Uniform Resource Identifier (URI) for a given asset. It Throws if
             * `_tokenId` is not a valid NFT. URIs are defined in RFC3986. The URI may point to a JSON file
             * that conforms to the "ERC721 Metadata JSON Schema".
             * @return URI of _tokenId.
             */
            function tokenURI(uint256 _tokenId)
              external
              view
              returns (string memory);
          
          }
          
          // File: browser/github/0xcert/ethereum-erc721/src/contracts/utils/address-utils.sol
          
          pragma solidity 0.6.2;
          
          /**
           * @dev Utility library of inline functions on addresses.
           * @notice Based on:
           * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Address.sol
           * Requires EIP-1052.
           */
          library AddressUtils
          {
          
            /**
             * @dev Returns whether the target address is a contract.
             * @param _addr Address to check.
             * @return addressCheck True if _addr is a contract, false if not.
             */
            function isContract(
              address _addr
            )
              internal
              view
              returns (bool addressCheck)
            {
              // This method relies in extcodesize, which returns 0 for contracts in
              // construction, since the code is only stored at the end of the
              // constructor execution.
          
              // 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;
              assembly { codehash := extcodehash(_addr) } // solhint-disable-line
              addressCheck = (codehash != 0x0 && codehash != accountHash);
            }
          
          }
          
          // File: browser/github/0xcert/ethereum-erc721/src/contracts/utils/erc165.sol
          
          pragma solidity 0.6.2;
          
          /**
           * @dev A standard for detecting smart contract interfaces. 
           * See: https://eips.ethereum.org/EIPS/eip-165.
           */
          interface ERC165
          {
          
            /**
             * @dev Checks if the smart contract includes a specific interface.
             * @notice This function uses less than 30,000 gas.
             * @param _interfaceID The interface identifier, as specified in ERC-165.
             * @return True if _interfaceID is supported, false otherwise.
             */
            function supportsInterface(
              bytes4 _interfaceID
            )
              external
              view
              returns (bool);
              
          }
          
          // File: browser/github/0xcert/ethereum-erc721/src/contracts/utils/supports-interface.sol
          
          pragma solidity 0.6.2;
          
          
          /**
           * @dev Implementation of standard for detect smart contract interfaces.
           */
          contract SupportsInterface is
            ERC165
          {
          
            /**
             * @dev Mapping of supported intefraces.
             * @notice You must not set element 0xffffffff to true.
             */
            mapping(bytes4 => bool) internal supportedInterfaces;
          
            /**
             * @dev Contract constructor.
             */
            constructor()
              public
            {
              supportedInterfaces[0x01ffc9a7] = true; // ERC165
            }
          
            /**
             * @dev Function to check which interfaces are suported by this contract.
             * @param _interfaceID Id of the interface.
             * @return True if _interfaceID is supported, false otherwise.
             */
            function supportsInterface(
              bytes4 _interfaceID
            )
              external
              override
              view
              returns (bool)
            {
              return supportedInterfaces[_interfaceID];
            }
          
          }
          
          // File: browser/github/0xcert/ethereum-erc721/src/contracts/math/safe-math.sol
          
          pragma solidity 0.6.2;
          
          /**
           * @dev Math operations with safety checks that throw on error. This contract is based on the
           * source code at:
           * https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/math/SafeMath.sol.
           */
          library SafeMath
          {
            /**
             * List of revert message codes. Implementing dApp should handle showing the correct message.
             * Based on 0xcert framework error codes.
             */
            string constant OVERFLOW = "008001";
            string constant SUBTRAHEND_GREATER_THEN_MINUEND = "008002";
            string constant DIVISION_BY_ZERO = "008003";
          
            /**
             * @dev Multiplies two numbers, reverts on overflow.
             * @param _factor1 Factor number.
             * @param _factor2 Factor number.
             * @return product The product of the two factors.
             */
            function mul(
              uint256 _factor1,
              uint256 _factor2
            )
              internal
              pure
              returns (uint256 product)
            {
              // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
              // benefit is lost if 'b' is also tested.
              // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
              if (_factor1 == 0)
              {
                return 0;
              }
          
              product = _factor1 * _factor2;
              require(product / _factor1 == _factor2, OVERFLOW);
            }
          
            /**
             * @dev Integer division of two numbers, truncating the quotient, reverts on division by zero.
             * @param _dividend Dividend number.
             * @param _divisor Divisor number.
             * @return quotient The quotient.
             */
            function div(
              uint256 _dividend,
              uint256 _divisor
            )
              internal
              pure
              returns (uint256 quotient)
            {
              // Solidity automatically asserts when dividing by 0, using all gas.
              require(_divisor > 0, DIVISION_BY_ZERO);
              quotient = _dividend / _divisor;
              // assert(_dividend == _divisor * quotient + _dividend % _divisor); // There is no case in which this doesn't hold.
            }
          
            /**
             * @dev Substracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
             * @param _minuend Minuend number.
             * @param _subtrahend Subtrahend number.
             * @return difference Difference.
             */
            function sub(
              uint256 _minuend,
              uint256 _subtrahend
            )
              internal
              pure
              returns (uint256 difference)
            {
              require(_subtrahend <= _minuend, SUBTRAHEND_GREATER_THEN_MINUEND);
              difference = _minuend - _subtrahend;
            }
          
            /**
             * @dev Adds two numbers, reverts on overflow.
             * @param _addend1 Number.
             * @param _addend2 Number.
             * @return sum Sum.
             */
            function add(
              uint256 _addend1,
              uint256 _addend2
            )
              internal
              pure
              returns (uint256 sum)
            {
              sum = _addend1 + _addend2;
              require(sum >= _addend1, OVERFLOW);
            }
          
            /**
              * @dev Divides two numbers and returns the remainder (unsigned integer modulo), reverts when
              * dividing by zero.
              * @param _dividend Number.
              * @param _divisor Number.
              * @return remainder Remainder.
              */
            function mod(
              uint256 _dividend,
              uint256 _divisor
            )
              internal
              pure
              returns (uint256 remainder)
            {
              require(_divisor != 0, DIVISION_BY_ZERO);
              remainder = _dividend % _divisor;
            }
          
          }
          
          // File: browser/github/0xcert/ethereum-erc721/src/contracts/tokens/erc721-token-receiver.sol
          
          pragma solidity 0.6.2;
          
          /**
           * @dev ERC-721 interface for accepting safe transfers.
           * See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md.
           */
          interface ERC721TokenReceiver
          {
          
            /**
             * @dev Handle the receipt of a NFT. The ERC721 smart contract calls this function on the
             * recipient after a `transfer`. This function MAY throw to revert and reject the transfer. Return
             * of other than the magic value MUST result in the transaction being reverted.
             * Returns `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` unless throwing.
             * @notice The contract address is always the message sender. A wallet/broker/auction application
             * MUST implement the wallet interface if it will accept safe transfers.
             * @param _operator The address which called `safeTransferFrom` function.
             * @param _from The address which previously owned the token.
             * @param _tokenId The NFT identifier which is being transferred.
             * @param _data Additional data with no specified format.
             * @return Returns `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`.
             */
            function onERC721Received(
              address _operator,
              address _from,
              uint256 _tokenId,
              bytes calldata _data
            )
              external
              returns(bytes4);
          
          }
          
          // File: browser/github/0xcert/ethereum-erc721/src/contracts/tokens/erc721.sol
          
          pragma solidity 0.6.2;
          
          /**
           * @dev ERC-721 non-fungible token standard.
           * See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md.
           */
          interface ERC721
          {
          
            /**
             * @dev Emits when ownership of any NFT changes by any mechanism. This event emits when NFTs are
             * created (`from` == 0) and destroyed (`to` == 0). Exception: during contract creation, any
             * number of NFTs may be created and assigned without emitting Transfer. At the time of any
             * transfer, the approved address for that NFT (if any) is reset to none.
             */
            event Transfer(
              address indexed _from,
              address indexed _to,
              uint256 indexed _tokenId
            );
          
            /**
             * @dev This emits when the approved address for an NFT is changed or reaffirmed. The zero
             * address indicates there is no approved address. When a Transfer event emits, this also
             * indicates that the approved address for that NFT (if any) is reset to none.
             */
            event Approval(
              address indexed _owner,
              address indexed _approved,
              uint256 indexed _tokenId
            );
          
            /**
             * @dev This emits when an operator is enabled or disabled for an owner. The operator can manage
             * all NFTs of the owner.
             */
            event ApprovalForAll(
              address indexed _owner,
              address indexed _operator,
              bool _approved
            );
          
            /**
             * @dev Transfers the ownership of an NFT from one address to another address.
             * @notice Throws unless `msg.sender` is the current owner, an authorized operator, or the
             * approved address for this NFT. Throws if `_from` is not the current owner. Throws if `_to` is
             * the zero address. Throws if `_tokenId` is not a valid NFT. When transfer is complete, this
             * function checks if `_to` is a smart contract (code size > 0). If so, it calls
             * `onERC721Received` on `_to` and throws if the return value is not
             * `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`.
             * @param _from The current owner of the NFT.
             * @param _to The new owner.
             * @param _tokenId The NFT to transfer.
             * @param _data Additional data with no specified format, sent in call to `_to`.
             */
            function safeTransferFrom(
              address _from,
              address _to,
              uint256 _tokenId,
              bytes calldata _data
            )
              external;
          
            /**
             * @dev Transfers the ownership of an NFT from one address to another address.
             * @notice This works identically to the other function with an extra data parameter, except this
             * function just sets data to ""
             * @param _from The current owner of the NFT.
             * @param _to The new owner.
             * @param _tokenId The NFT to transfer.
             */
            function safeTransferFrom(
              address _from,
              address _to,
              uint256 _tokenId
            )
              external;
          
            /**
             * @dev Throws unless `msg.sender` is the current owner, an authorized operator, or the approved
             * address for this NFT. Throws if `_from` is not the current owner. Throws if `_to` is the zero
             * address. Throws if `_tokenId` is not a valid NFT.
             * @notice The caller is responsible to confirm that `_to` is capable of receiving NFTs or else
             * they mayb be permanently lost.
             * @param _from The current owner of the NFT.
             * @param _to The new owner.
             * @param _tokenId The NFT to transfer.
             */
            function transferFrom(
              address _from,
              address _to,
              uint256 _tokenId
            )
              external;
          
            /**
             * @dev Set or reaffirm the approved address for an NFT.
             * @notice The zero address indicates there is no approved address. Throws unless `msg.sender` is
             * the current NFT owner, or an authorized operator of the current owner.
             * @param _approved The new approved NFT controller.
             * @param _tokenId The NFT to approve.
             */
            function approve(
              address _approved,
              uint256 _tokenId
            )
              external;
          
            /**
             * @dev Enables or disables approval for a third party ("operator") to manage all of
             * `msg.sender`'s assets. It also emits the ApprovalForAll event.
             * @notice The contract MUST allow multiple operators per owner.
             * @param _operator Address to add to the set of authorized operators.
             * @param _approved True if the operators is approved, false to revoke approval.
             */
            function setApprovalForAll(
              address _operator,
              bool _approved
            )
              external;
          
            /**
             * @dev Returns the number of NFTs owned by `_owner`. NFTs assigned to the zero address are
             * considered invalid, and this function throws for queries about the zero address.
             * @param _owner Address for whom to query the balance.
             * @return Balance of _owner.
             */
            function balanceOf(
              address _owner
            )
              external
              view
              returns (uint256);
          
            /**
             * @dev Returns the address of the owner of the NFT. NFTs assigned to zero address are considered
             * invalid, and queries about them do throw.
             * @param _tokenId The identifier for an NFT.
             * @return Address of _tokenId owner.
             */
            function ownerOf(
              uint256 _tokenId
            )
              external
              view
              returns (address);
          
            /**
             * @dev Get the approved address for a single NFT.
             * @notice Throws if `_tokenId` is not a valid NFT.
             * @param _tokenId The NFT to find the approved address for.
             * @return Address that _tokenId is approved for.
             */
            function getApproved(
              uint256 _tokenId
            )
              external
              view
              returns (address);
          
            /**
             * @dev Returns true if `_operator` is an approved operator for `_owner`, false otherwise.
             * @param _owner The address that owns the NFTs.
             * @param _operator The address that acts on behalf of the owner.
             * @return True if approved for all, false otherwise.
             */
            function isApprovedForAll(
              address _owner,
              address _operator
            )
              external
              view
              returns (bool);
          
          }
          
          // File: browser/github/0xcert/ethereum-erc721/src/contracts/tokens/nf-token.sol
          
          pragma solidity 0.6.2;
          
          
          
          
          
          
          /**
           * @dev Implementation of ERC-721 non-fungible token standard.
           */
          contract NFToken is
            ERC721,
            SupportsInterface
          {
            using SafeMath for uint256;
            using AddressUtils for address;
          
            /**
             * List of revert message codes. Implementing dApp should handle showing the correct message.
             * Based on 0xcert framework error codes.
             */
            string constant ZERO_ADDRESS = "003001";
            string constant NOT_VALID_NFT = "003002";
            string constant NOT_OWNER_OR_OPERATOR = "003003";
            string constant NOT_OWNER_APPROWED_OR_OPERATOR = "003004";
            string constant NOT_ABLE_TO_RECEIVE_NFT = "003005";
            string constant NFT_ALREADY_EXISTS = "003006";
            string constant NOT_OWNER = "003007";
            string constant IS_OWNER = "003008";
          
            /**
             * @dev Magic value of a smart contract that can recieve NFT.
             * Equal to: bytes4(keccak256("onERC721Received(address,address,uint256,bytes)")).
             */
            bytes4 internal constant MAGIC_ON_ERC721_RECEIVED = 0x150b7a02;
          
            /**
             * @dev A mapping from NFT ID to the address that owns it.
             */
            mapping (uint256 => address) internal idToOwner;
          
            /**
             * @dev Mapping from NFT ID to approved address.
             */
            mapping (uint256 => address) internal idToApproval;
          
             /**
             * @dev Mapping from owner address to count of his tokens.
             */
            mapping (address => uint256) private ownerToNFTokenCount;
          
            /**
             * @dev Mapping from owner address to mapping of operator addresses.
             */
            mapping (address => mapping (address => bool)) internal ownerToOperators;
          
            /**
             * @dev Emits when ownership of any NFT changes by any mechanism. This event emits when NFTs are
             * created (`from` == 0) and destroyed (`to` == 0). Exception: during contract creation, any
             * number of NFTs may be created and assigned without emitting Transfer. At the time of any
             * transfer, the approved address for that NFT (if any) is reset to none.
             * @param _from Sender of NFT (if address is zero address it indicates token creation).
             * @param _to Receiver of NFT (if address is zero address it indicates token destruction).
             * @param _tokenId The NFT that got transfered.
             */
            event Transfer(
              address indexed _from,
              address indexed _to,
              uint256 indexed _tokenId
            );
          
            /**
             * @dev This emits when the approved address for an NFT is changed or reaffirmed. The zero
             * address indicates there is no approved address. When a Transfer event emits, this also
             * indicates that the approved address for that NFT (if any) is reset to none.
             * @param _owner Owner of NFT.
             * @param _approved Address that we are approving.
             * @param _tokenId NFT which we are approving.
             */
            event Approval(
              address indexed _owner,
              address indexed _approved,
              uint256 indexed _tokenId
            );
          
            /**
             * @dev This emits when an operator is enabled or disabled for an owner. The operator can manage
             * all NFTs of the owner.
             * @param _owner Owner of NFT.
             * @param _operator Address to which we are setting operator rights.
             * @param _approved Status of operator rights(true if operator rights are given and false if
             * revoked).
             */
            event ApprovalForAll(
              address indexed _owner,
              address indexed _operator,
              bool _approved
            );
          
            /**
             * @dev Guarantees that the msg.sender is an owner or operator of the given NFT.
             * @param _tokenId ID of the NFT to validate.
             */
            modifier canOperate(
              uint256 _tokenId
            )
            {
              address tokenOwner = idToOwner[_tokenId];
              require(tokenOwner == msg.sender || ownerToOperators[tokenOwner][msg.sender], NOT_OWNER_OR_OPERATOR);
              _;
            }
          
            /**
             * @dev Guarantees that the msg.sender is allowed to transfer NFT.
             * @param _tokenId ID of the NFT to transfer.
             */
            modifier canTransfer(
              uint256 _tokenId
            )
            {
              address tokenOwner = idToOwner[_tokenId];
              require(
                tokenOwner == msg.sender
                || idToApproval[_tokenId] == msg.sender
                || ownerToOperators[tokenOwner][msg.sender],
                NOT_OWNER_APPROWED_OR_OPERATOR
              );
              _;
            }
          
            /**
             * @dev Guarantees that _tokenId is a valid Token.
             * @param _tokenId ID of the NFT to validate.
             */
            modifier validNFToken(
              uint256 _tokenId
            )
            {
              require(idToOwner[_tokenId] != address(0), NOT_VALID_NFT);
              _;
            }
          
            /**
             * @dev Contract constructor.
             */
            constructor()
              public
            {
              supportedInterfaces[0x80ac58cd] = true; // ERC721
            }
          
            /**
             * @dev Transfers the ownership of an NFT from one address to another address. This function can
             * be changed to payable.
             * @notice Throws unless `msg.sender` is the current owner, an authorized operator, or the
             * approved address for this NFT. Throws if `_from` is not the current owner. Throws if `_to` is
             * the zero address. Throws if `_tokenId` is not a valid NFT. When transfer is complete, this
             * function checks if `_to` is a smart contract (code size > 0). If so, it calls
             * `onERC721Received` on `_to` and throws if the return value is not
             * `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`.
             * @param _from The current owner of the NFT.
             * @param _to The new owner.
             * @param _tokenId The NFT to transfer.
             * @param _data Additional data with no specified format, sent in call to `_to`.
             */
            function safeTransferFrom(
              address _from,
              address _to,
              uint256 _tokenId,
              bytes calldata _data
            )
              external
              override
            {
              _safeTransferFrom(_from, _to, _tokenId, _data);
            }
          
            /**
             * @dev Transfers the ownership of an NFT from one address to another address. This function can
             * be changed to payable.
             * @notice This works identically to the other function with an extra data parameter, except this
             * function just sets data to ""
             * @param _from The current owner of the NFT.
             * @param _to The new owner.
             * @param _tokenId The NFT to transfer.
             */
            function safeTransferFrom(
              address _from,
              address _to,
              uint256 _tokenId
            )
              external
              override
            {
              _safeTransferFrom(_from, _to, _tokenId, "");
            }
          
            /**
             * @dev Throws unless `msg.sender` is the current owner, an authorized operator, or the approved
             * address for this NFT. Throws if `_from` is not the current owner. Throws if `_to` is the zero
             * address. Throws if `_tokenId` is not a valid NFT. This function can be changed to payable.
             * @notice The caller is responsible to confirm that `_to` is capable of receiving NFTs or else
             * they maybe be permanently lost.
             * @param _from The current owner of the NFT.
             * @param _to The new owner.
             * @param _tokenId The NFT to transfer.
             */
            function transferFrom(
              address _from,
              address _to,
              uint256 _tokenId
            )
              external
              override
              canTransfer(_tokenId)
              validNFToken(_tokenId)
            {
              address tokenOwner = idToOwner[_tokenId];
              require(tokenOwner == _from, NOT_OWNER);
              require(_to != address(0), ZERO_ADDRESS);
          
              _transfer(_to, _tokenId);
            }
          
            /**
             * @dev Set or reaffirm the approved address for an NFT. This function can be changed to payable.
             * @notice The zero address indicates there is no approved address. Throws unless `msg.sender` is
             * the current NFT owner, or an authorized operator of the current owner.
             * @param _approved Address to be approved for the given NFT ID.
             * @param _tokenId ID of the token to be approved.
             */
            function approve(
              address _approved,
              uint256 _tokenId
            )
              external
              override
              canOperate(_tokenId)
              validNFToken(_tokenId)
            {
              address tokenOwner = idToOwner[_tokenId];
              require(_approved != tokenOwner, IS_OWNER);
          
              idToApproval[_tokenId] = _approved;
              emit Approval(tokenOwner, _approved, _tokenId);
            }
          
            /**
             * @dev Enables or disables approval for a third party ("operator") to manage all of
             * `msg.sender`'s assets. It also emits the ApprovalForAll event.
             * @notice This works even if sender doesn't own any tokens at the time.
             * @param _operator Address to add to the set of authorized operators.
             * @param _approved True if the operators is approved, false to revoke approval.
             */
            function setApprovalForAll(
              address _operator,
              bool _approved
            )
              external
              override
            {
              ownerToOperators[msg.sender][_operator] = _approved;
              emit ApprovalForAll(msg.sender, _operator, _approved);
            }
          
            /**
             * @dev Returns the number of NFTs owned by `_owner`. NFTs assigned to the zero address are
             * considered invalid, and this function throws for queries about the zero address.
             * @param _owner Address for whom to query the balance.
             * @return Balance of _owner.
             */
            function balanceOf(
              address _owner
            )
              external
              override
              view
              returns (uint256)
            {
              require(_owner != address(0), ZERO_ADDRESS);
              return _getOwnerNFTCount(_owner);
            }
          
            /**
             * @dev Returns the address of the owner of the NFT. NFTs assigned to zero address are considered
             * invalid, and queries about them do throw.
             * @param _tokenId The identifier for an NFT.
             * @return _owner Address of _tokenId owner.
             */
            function ownerOf(
              uint256 _tokenId
            )
              external
              override
              view
              returns (address _owner)
            {
              _owner = idToOwner[_tokenId];
              require(_owner != address(0), NOT_VALID_NFT);
            }
          
            /**
             * @dev Get the approved address for a single NFT.
             * @notice Throws if `_tokenId` is not a valid NFT.
             * @param _tokenId ID of the NFT to query the approval of.
             * @return Address that _tokenId is approved for.
             */
            function getApproved(
              uint256 _tokenId
            )
              external
              override
              view
              validNFToken(_tokenId)
              returns (address)
            {
              return idToApproval[_tokenId];
            }
          
            /**
             * @dev Checks if `_operator` is an approved operator for `_owner`.
             * @param _owner The address that owns the NFTs.
             * @param _operator The address that acts on behalf of the owner.
             * @return True if approved for all, false otherwise.
             */
            function isApprovedForAll(
              address _owner,
              address _operator
            )
              external
              override
              view
              returns (bool)
            {
              return ownerToOperators[_owner][_operator];
            }
          
            /**
             * @dev Actually preforms the transfer.
             * @notice Does NO checks.
             * @param _to Address of a new owner.
             * @param _tokenId The NFT that is being transferred.
             */
            function _transfer(
              address _to,
              uint256 _tokenId
            )
              internal
            {
              address from = idToOwner[_tokenId];
              _clearApproval(_tokenId);
          
              _removeNFToken(from, _tokenId);
              _addNFToken(_to, _tokenId);
          
              emit Transfer(from, _to, _tokenId);
            }
          
            /**
             * @dev Mints a new NFT.
             * @notice This is an internal function which should be called from user-implemented external
             * mint function. Its purpose is to show and properly initialize data structures when using this
             * implementation.
             * @param _to The address that will own the minted NFT.
             * @param _tokenId of the NFT to be minted by the msg.sender.
             */
            function _mint(
              address _to,
              uint256 _tokenId
            )
              internal
              virtual
            {
              require(_to != address(0), ZERO_ADDRESS);
              require(idToOwner[_tokenId] == address(0), NFT_ALREADY_EXISTS);
          
              _addNFToken(_to, _tokenId);
          
              emit Transfer(address(0), _to, _tokenId);
            }
          
            /**
             * @dev Burns a NFT.
             * @notice This is an internal function which should be called from user-implemented external burn
             * function. Its purpose is to show and properly initialize data structures when using this
             * implementation. Also, note that this burn implementation allows the minter to re-mint a burned
             * NFT.
             * @param _tokenId ID of the NFT to be burned.
             */
            function _burn(
              uint256 _tokenId
            )
              internal
              virtual
              validNFToken(_tokenId)
            {
              address tokenOwner = idToOwner[_tokenId];
              _clearApproval(_tokenId);
              _removeNFToken(tokenOwner, _tokenId);
              emit Transfer(tokenOwner, address(0), _tokenId);
            }
          
            /**
             * @dev Removes a NFT from owner.
             * @notice Use and override this function with caution. Wrong usage can have serious consequences.
             * @param _from Address from wich we want to remove the NFT.
             * @param _tokenId Which NFT we want to remove.
             */
            function _removeNFToken(
              address _from,
              uint256 _tokenId
            )
              internal
              virtual
            {
              require(idToOwner[_tokenId] == _from, NOT_OWNER);
              ownerToNFTokenCount[_from] = ownerToNFTokenCount[_from] - 1;
              delete idToOwner[_tokenId];
            }
          
            /**
             * @dev Assignes a new NFT to owner.
             * @notice Use and override this function with caution. Wrong usage can have serious consequences.
             * @param _to Address to wich we want to add the NFT.
             * @param _tokenId Which NFT we want to add.
             */
            function _addNFToken(
              address _to,
              uint256 _tokenId
            )
              internal
              virtual
            {
              require(idToOwner[_tokenId] == address(0), NFT_ALREADY_EXISTS);
          
              idToOwner[_tokenId] = _to;
              ownerToNFTokenCount[_to] = ownerToNFTokenCount[_to].add(1);
            }
          
            /**
             * @dev Helper function that gets NFT count of owner. This is needed for overriding in enumerable
             * extension to remove double storage (gas optimization) of owner nft count.
             * @param _owner Address for whom to query the count.
             * @return Number of _owner NFTs.
             */
            function _getOwnerNFTCount(
              address _owner
            )
              internal
              virtual
              view
              returns (uint256)
            {
              return ownerToNFTokenCount[_owner];
            }
          
            /**
             * @dev Actually perform the safeTransferFrom.
             * @param _from The current owner of the NFT.
             * @param _to The new owner.
             * @param _tokenId The NFT to transfer.
             * @param _data Additional data with no specified format, sent in call to `_to`.
             */
            function _safeTransferFrom(
              address _from,
              address _to,
              uint256 _tokenId,
              bytes memory _data
            )
              private
              canTransfer(_tokenId)
              validNFToken(_tokenId)
            {
              address tokenOwner = idToOwner[_tokenId];
              require(tokenOwner == _from, NOT_OWNER);
              require(_to != address(0), ZERO_ADDRESS);
          
              _transfer(_to, _tokenId);
          
              if (_to.isContract())
              {
                bytes4 retval = ERC721TokenReceiver(_to).onERC721Received(msg.sender, _from, _tokenId, _data);
                require(retval == MAGIC_ON_ERC721_RECEIVED, NOT_ABLE_TO_RECEIVE_NFT);
              }
            }
          
            /**
             * @dev Clears the current approval of a given NFT ID.
             * @param _tokenId ID of the NFT to be transferred.
             */
            function _clearApproval(
              uint256 _tokenId
            )
              private
            {
              if (idToApproval[_tokenId] != address(0))
              {
                delete idToApproval[_tokenId];
              }
            }
          
          }
          
          // File: browser/github/0xcert/ethereum-erc721/src/contracts/tokens/nf-token-enumerable-metadata.sol
          
          pragma solidity 0.6.2;
          
          
          
          
          /**
           * @dev Optional metadata implementation for ERC-721 non-fungible token standard.
           */
          abstract contract NFTokenEnumerableMetadata is
              NFToken,
              ERC721Metadata,
              ERC721Enumerable
          {
          
            /**
             * @dev A descriptive name for a collection of NFTs.
             */
            string internal nftName;
          
            /**
             * @dev An abbreviated name for NFTokens.
             */
            string internal nftSymbol;
            
              /**
             * @dev An uri to represent the metadata for this contract.
             */
            string internal nftContractMetadataUri;
          
            /**
             * @dev Mapping from NFT ID to metadata uri.
             */
            mapping (uint256 => string) internal idToUri;
            
            /**
             * @dev Mapping from NFT ID to encrypted value.
             */
            mapping (uint256 => string) internal idToPayload;
          
            /**
             * @dev Contract constructor.
             * @notice When implementing this contract don't forget to set nftName and nftSymbol.
             */
            constructor()
              public
            {
              supportedInterfaces[0x5b5e139f] = true; // ERC721Metadata
              supportedInterfaces[0x780e9d63] = true; // ERC721Enumerable
            }
          
            /**
             * @dev Returns a descriptive name for a collection of NFTokens.
             * @return _name Representing name.
             */
            function name()
              external
              override
              view
              returns (string memory _name)
            {
              _name = nftName;
            }
          
            /**
             * @dev Returns an abbreviated name for NFTokens.
             * @return _symbol Representing symbol.
             */
            function symbol()
              external
              override
              view
              returns (string memory _symbol)
            {
              _symbol = nftSymbol;
            }
          
            /**
             * @dev A distinct URI (RFC 3986) for a given NFT.
             * @param _tokenId Id for which we want uri.
             * @return URI of _tokenId.
             */
            function tokenURI(
              uint256 _tokenId
            )
              external
              override
              view
              validNFToken(_tokenId)
              returns (string memory)
            {
              return idToUri[_tokenId];
            }
            
              /**
             * @dev A distinct URI (RFC 3986) for a given NFT.
             * @param _tokenId Id for which we want uri.
             * @return URI of _tokenId.
             */
            function tokenPayload(
              uint256 _tokenId
            )
              external
              view
              validNFToken(_tokenId)
              returns (string memory)
            {
              return idToPayload[_tokenId];
            }
          
            /**
             * @dev Set a distinct URI (RFC 3986) for a given NFT ID.
             * @notice This is an internal function which should be called from user-implemented external
             * function. Its purpose is to show and properly initialize data structures when using this
             * implementation.
             * @param _tokenId Id for which we want URI.
             * @param _uri String representing RFC 3986 URI.
             */
            function _setTokenUri(
              uint256 _tokenId,
              string memory _uri
            )
              internal
              validNFToken(_tokenId)
            {
              idToUri[_tokenId] = _uri;
            }
            
          function _setTokenPayload(
              uint256 _tokenId,
              string memory _uri
            )
              internal
              validNFToken(_tokenId)
            {
              idToPayload[_tokenId] = _uri;
            }
            
            /**
             * List of revert message codes. Implementing dApp should handle showing the correct message.
             * Based on 0xcert framework error codes.
             */
            string constant INVALID_INDEX = "005007";
          
            /**
             * @dev Array of all NFT IDs.
             */
            uint256[] internal tokens;
          
            /**
             * @dev Mapping from token ID to its index in global tokens array.
             */
            mapping(uint256 => uint256) internal idToIndex;
          
            /**
             * @dev Mapping from owner to list of owned NFT IDs.
             */
            mapping(address => uint256[]) internal ownerToIds;
          
            /**
             * @dev Mapping from NFT ID to its index in the owner tokens list.
             */
            mapping(uint256 => uint256) internal idToOwnerIndex;
            
            /**
             * @dev Returns the count of all existing NFTokens.
             * @return Total supply of NFTs.
             */
            function totalSupply()
              external
              override
              view
              returns (uint256)
            {
              return tokens.length;
            }
          
            /**
             * @dev Returns NFT ID by its index.
             * @param _index A counter less than `totalSupply()`.
             * @return Token id.
             */
            function tokenByIndex(
              uint256 _index
            )
              external
              override
              view
              returns (uint256)
            {
              require(_index < tokens.length, INVALID_INDEX);
              return tokens[_index];
            }
          
            /**
             * @dev returns the n-th NFT ID from a list of owner's tokens.
             * @param _owner Token owner's address.
             * @param _index Index number representing n-th token in owner's list of tokens.
             * @return Token id.
             */
            function tokenOfOwnerByIndex(
              address _owner,
              uint256 _index
            )
              external
              override
              view
              returns (uint256)
            {
              require(_index < ownerToIds[_owner].length, INVALID_INDEX);
              return ownerToIds[_owner][_index];
            }
          
            /**
             * @dev Mints a new NFT.
             * @notice This is an internal function which should be called from user-implemented external
             * mint function. Its purpose is to show and properly initialize data structures when using this
             * implementation.
             * @param _to The address that will own the minted NFT.
             * @param _tokenId of the NFT to be minted by the msg.sender.
             */
            function _mint(
              address _to,
              uint256 _tokenId
            )
              internal
              override
              virtual
            {
              super._mint(_to, _tokenId);
              tokens.push(_tokenId);
              idToIndex[_tokenId] = tokens.length - 1;
            }
          
            /**
             * @dev Burns a NFT.
             * @notice This is an internal function which should be called from user-implemented external
             * burn function. Its purpose is to show and properly initialize data structures when using this
             * implementation. Also, note that this burn implementation allows the minter to re-mint a burned
             * NFT.
             * @param _tokenId ID of the NFT to be burned.
             */
            function _burn(
              uint256 _tokenId
            )
              internal
              override
              virtual
            {
              super._burn(_tokenId);
              
              if (bytes(idToUri[_tokenId]).length != 0)
              {
                delete idToUri[_tokenId];
              }
              
              if (bytes(idToPayload[_tokenId]).length != 0)
              {
                delete idToPayload[_tokenId];
              }
              
              uint256 tokenIndex = idToIndex[_tokenId];
              uint256 lastTokenIndex = tokens.length - 1;
              uint256 lastToken = tokens[lastTokenIndex];
          
              tokens[tokenIndex] = lastToken;
          
              tokens.pop();
              // This wastes gas if you are burning the last token but saves a little gas if you are not.
              idToIndex[lastToken] = tokenIndex;
              idToIndex[_tokenId] = 0;
            }
          
            /**
             * @dev Removes a NFT from an address.
             * @notice Use and override this function with caution. Wrong usage can have serious consequences.
             * @param _from Address from wich we want to remove the NFT.
             * @param _tokenId Which NFT we want to remove.
             */
            function _removeNFToken(
              address _from,
              uint256 _tokenId
            )
              internal
              override
              virtual
            {
              require(idToOwner[_tokenId] == _from, NOT_OWNER);
              delete idToOwner[_tokenId];
          
              uint256 tokenToRemoveIndex = idToOwnerIndex[_tokenId];
              uint256 lastTokenIndex = ownerToIds[_from].length - 1;
          
              if (lastTokenIndex != tokenToRemoveIndex)
              {
                uint256 lastToken = ownerToIds[_from][lastTokenIndex];
                ownerToIds[_from][tokenToRemoveIndex] = lastToken;
                idToOwnerIndex[lastToken] = tokenToRemoveIndex;
              }
          
              ownerToIds[_from].pop();
            }
          
            /**
             * @dev Assignes a new NFT to an address.
             * @notice Use and override this function with caution. Wrong usage can have serious consequences.
             * @param _to Address to wich we want to add the NFT.
             * @param _tokenId Which NFT we want to add.
             */
            function _addNFToken(
              address _to,
              uint256 _tokenId
            )
              internal
              override
              virtual
            {
              require(idToOwner[_tokenId] == address(0), NFT_ALREADY_EXISTS);
              idToOwner[_tokenId] = _to;
          
              ownerToIds[_to].push(_tokenId);
              idToOwnerIndex[_tokenId] = ownerToIds[_to].length - 1;
            }
          
            /**
             * @dev Helper function that gets NFT count of owner. This is needed for overriding in enumerable
             * extension to remove double storage(gas optimization) of owner nft count.
             * @param _owner Address for whom to query the count.
             * @return Number of _owner NFTs.
             */
            function _getOwnerNFTCount(
              address _owner
            )
              internal
              override
              virtual
              view
              returns (uint256)
            {
              return ownerToIds[_owner].length;
            }
          
          }
          
          // File: browser/EmblemVault_v2.sol
          
          pragma experimental ABIEncoderV2;
          pragma solidity 0.6.2;
          
          
          
          /**
           * @dev This is an example contract implementation of NFToken with metadata extension.
           */
          contract EmblemVault is
            NFTokenEnumerableMetadata,
            Ownable
          {
          
            /**
             * @dev Contract constructor. Sets metadata extension `name` and `symbol`.
             */
            constructor() public {
              nftName = "Emblem Vault V2";
              nftSymbol = "Emblem.pro";
            }
            
            function changeName(string calldata name, string calldata symbol) external onlyOwner {
                nftName = name;
                nftSymbol = symbol;
            }
          
            /**
             * @dev Mints a new NFT.
             * @param _to The address that will own the minted NFT.
             * @param _tokenId of the NFT to be minted by the msg.sender.
             * @param _uri String representing RFC 3986 URI.
             */
            function mint( address _to, uint256 _tokenId, string calldata _uri, string calldata _payload) external onlyOwner {
              super._mint(_to, _tokenId);
              super._setTokenUri(_tokenId, _uri);
              super._setTokenPayload(_tokenId, _payload);
            }
            
            function burn(uint256 _tokenId) external canTransfer(_tokenId) {
              super._burn(_tokenId);
            }
            
            function contractURI() public view returns (string memory) {
              return nftContractMetadataUri;
            }
            
            event UpdatedContractURI(string _from, string _to);
            function updateContractURI(string memory uri) public onlyOwner {
              emit UpdatedContractURI(nftContractMetadataUri, uri);
              nftContractMetadataUri = uri;
            }
            
            function getOwnerNFTCount(address _owner) public view returns (uint256) {
                return NFTokenEnumerableMetadata._getOwnerNFTCount(_owner);
            }
            
            function updateTokenUri(
              uint256 _tokenId,
              string memory _uri
            )
              public
              validNFToken(_tokenId)
              onlyOwner
            {
              idToUri[_tokenId] = _uri;
            }
            
            
          
          }

          File 4 of 6: TransparentUpgradeableProxy
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.8.0;
          import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
          import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
          import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";
          // Kept for backwards compatibility with older versions of Hardhat and Truffle plugins.
          contract AdminUpgradeabilityProxy is TransparentUpgradeableProxy {
              constructor(address logic, address admin, bytes memory data) payable TransparentUpgradeableProxy(logic, admin, data) {}
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.8.0;
          import "../Proxy.sol";
          import "./ERC1967Upgrade.sol";
          /**
           * @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an
           * implementation address that can be changed. This address is stored in storage in the location specified by
           * https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the
           * implementation behind the proxy.
           */
          contract ERC1967Proxy is Proxy, ERC1967Upgrade {
              /**
               * @dev Initializes the upgradeable proxy with an initial implementation specified by `_logic`.
               *
               * If `_data` is nonempty, it's used as data in a delegate call to `_logic`. This will typically be an encoded
               * function call, and allows initializating the storage of the proxy like a Solidity constructor.
               */
              constructor(address _logic, bytes memory _data) payable {
                  assert(_IMPLEMENTATION_SLOT == bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1));
                  _upgradeToAndCall(_logic, _data, false);
              }
              /**
               * @dev Returns the current implementation address.
               */
              function _implementation() internal view virtual override returns (address impl) {
                  return ERC1967Upgrade._getImplementation();
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.8.0;
          import "../ERC1967/ERC1967Proxy.sol";
          /**
           * @dev This contract implements a proxy that is upgradeable by an admin.
           *
           * To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector
           * clashing], which can potentially be used in an attack, this contract uses the
           * https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two
           * things that go hand in hand:
           *
           * 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if
           * that call matches one of the admin functions exposed by the proxy itself.
           * 2. If the admin calls the proxy, it can access the admin functions, but its calls will never be forwarded to the
           * implementation. If the admin tries to call a function on the implementation it will fail with an error that says
           * "admin cannot fallback to proxy target".
           *
           * These properties mean that the admin account can only be used for admin actions like upgrading the proxy or changing
           * the admin, so it's best if it's a dedicated account that is not used for anything else. This will avoid headaches due
           * to sudden errors when trying to call a function from the proxy implementation.
           *
           * Our recommendation is for the dedicated account to be an instance of the {ProxyAdmin} contract. If set up this way,
           * you should think of the `ProxyAdmin` instance as the real administrative interface of your proxy.
           */
          contract TransparentUpgradeableProxy is ERC1967Proxy {
              /**
               * @dev Initializes an upgradeable proxy managed by `_admin`, backed by the implementation at `_logic`, and
               * optionally initialized with `_data` as explained in {ERC1967Proxy-constructor}.
               */
              constructor(address _logic, address admin_, bytes memory _data) payable ERC1967Proxy(_logic, _data) {
                  assert(_ADMIN_SLOT == bytes32(uint256(keccak256("eip1967.proxy.admin")) - 1));
                  _changeAdmin(admin_);
              }
              /**
               * @dev Modifier used internally that will delegate the call to the implementation unless the sender is the admin.
               */
              modifier ifAdmin() {
                  if (msg.sender == _getAdmin()) {
                      _;
                  } else {
                      _fallback();
                  }
              }
              /**
               * @dev Returns the current admin.
               *
               * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyAdmin}.
               *
               * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
               * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
               * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
               */
              function admin() external ifAdmin returns (address admin_) {
                  admin_ = _getAdmin();
              }
              /**
               * @dev Returns the current implementation.
               *
               * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyImplementation}.
               *
               * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
               * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
               * `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc`
               */
              function implementation() external ifAdmin returns (address implementation_) {
                  implementation_ = _implementation();
              }
              /**
               * @dev Changes the admin of the proxy.
               *
               * Emits an {AdminChanged} event.
               *
               * NOTE: Only the admin can call this function. See {ProxyAdmin-changeProxyAdmin}.
               */
              function changeAdmin(address newAdmin) external virtual ifAdmin {
                  _changeAdmin(newAdmin);
              }
              /**
               * @dev Upgrade the implementation of the proxy.
               *
               * NOTE: Only the admin can call this function. See {ProxyAdmin-upgrade}.
               */
              function upgradeTo(address newImplementation) external ifAdmin {
                  _upgradeToAndCall(newImplementation, bytes(""), false);
              }
              /**
               * @dev Upgrade the implementation of the proxy, and then call a function from the new implementation as specified
               * by `data`, which should be an encoded function call. This is useful to initialize new storage variables in the
               * proxied contract.
               *
               * NOTE: Only the admin can call this function. See {ProxyAdmin-upgradeAndCall}.
               */
              function upgradeToAndCall(address newImplementation, bytes calldata data) external payable ifAdmin {
                  _upgradeToAndCall(newImplementation, data, true);
              }
              /**
               * @dev Returns the current admin.
               */
              function _admin() internal view virtual returns (address) {
                  return _getAdmin();
              }
              /**
               * @dev Makes sure the admin cannot access the fallback function. See {Proxy-_beforeFallback}.
               */
              function _beforeFallback() internal virtual override {
                  require(msg.sender != _getAdmin(), "TransparentUpgradeableProxy: admin cannot fallback to proxy target");
                  super._beforeFallback();
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.8.0;
          import "./TransparentUpgradeableProxy.sol";
          import "../../access/Ownable.sol";
          /**
           * @dev This is an auxiliary contract meant to be assigned as the admin of a {TransparentUpgradeableProxy}. For an
           * explanation of why you would want to use this see the documentation for {TransparentUpgradeableProxy}.
           */
          contract ProxyAdmin is Ownable {
              /**
               * @dev Returns the current implementation of `proxy`.
               *
               * Requirements:
               *
               * - This contract must be the admin of `proxy`.
               */
              function getProxyImplementation(TransparentUpgradeableProxy proxy) public view virtual returns (address) {
                  // We need to manually run the static call since the getter cannot be flagged as view
                  // bytes4(keccak256("implementation()")) == 0x5c60da1b
                  (bool success, bytes memory returndata) = address(proxy).staticcall(hex"5c60da1b");
                  require(success);
                  return abi.decode(returndata, (address));
              }
              /**
               * @dev Returns the current admin of `proxy`.
               *
               * Requirements:
               *
               * - This contract must be the admin of `proxy`.
               */
              function getProxyAdmin(TransparentUpgradeableProxy proxy) public view virtual returns (address) {
                  // We need to manually run the static call since the getter cannot be flagged as view
                  // bytes4(keccak256("admin()")) == 0xf851a440
                  (bool success, bytes memory returndata) = address(proxy).staticcall(hex"f851a440");
                  require(success);
                  return abi.decode(returndata, (address));
              }
              /**
               * @dev Changes the admin of `proxy` to `newAdmin`.
               *
               * Requirements:
               *
               * - This contract must be the current admin of `proxy`.
               */
              function changeProxyAdmin(TransparentUpgradeableProxy proxy, address newAdmin) public virtual onlyOwner {
                  proxy.changeAdmin(newAdmin);
              }
              /**
               * @dev Upgrades `proxy` to `implementation`. See {TransparentUpgradeableProxy-upgradeTo}.
               *
               * Requirements:
               *
               * - This contract must be the admin of `proxy`.
               */
              function upgrade(TransparentUpgradeableProxy proxy, address implementation) public virtual onlyOwner {
                  proxy.upgradeTo(implementation);
              }
              /**
               * @dev Upgrades `proxy` to `implementation` and calls a function on the new implementation. See
               * {TransparentUpgradeableProxy-upgradeToAndCall}.
               *
               * Requirements:
               *
               * - This contract must be the admin of `proxy`.
               */
              function upgradeAndCall(TransparentUpgradeableProxy proxy, address implementation, bytes memory data) public payable virtual onlyOwner {
                  proxy.upgradeToAndCall{value: msg.value}(implementation, data);
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.8.0;
          /**
           * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
           * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
           * be specified by overriding the virtual {_implementation} function.
           *
           * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
           * different contract through the {_delegate} function.
           *
           * The success and return data of the delegated call will be returned back to the caller of the proxy.
           */
          abstract contract Proxy {
              /**
               * @dev Delegates the current call to `implementation`.
               *
               * This function does not return to its internall call site, it will return directly to the external caller.
               */
              function _delegate(address implementation) internal virtual {
                  // solhint-disable-next-line no-inline-assembly
                  assembly {
                      // Copy msg.data. We take full control of memory in this inline assembly
                      // block because it will not return to Solidity code. We overwrite the
                      // Solidity scratch pad at memory position 0.
                      calldatacopy(0, 0, calldatasize())
                      // Call the implementation.
                      // out and outsize are 0 because we don't know the size yet.
                      let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
                      // Copy the returned data.
                      returndatacopy(0, 0, returndatasize())
                      switch result
                      // delegatecall returns 0 on error.
                      case 0 { revert(0, returndatasize()) }
                      default { return(0, returndatasize()) }
                  }
              }
              /**
               * @dev This is a virtual function that should be overriden so it returns the address to which the fallback function
               * and {_fallback} should delegate.
               */
              function _implementation() internal view virtual returns (address);
              /**
               * @dev Delegates the current call to the address returned by `_implementation()`.
               *
               * This function does not return to its internall call site, it will return directly to the external caller.
               */
              function _fallback() internal virtual {
                  _beforeFallback();
                  _delegate(_implementation());
              }
              /**
               * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
               * function in the contract matches the call data.
               */
              fallback () external payable virtual {
                  _fallback();
              }
              /**
               * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data
               * is empty.
               */
              receive () external payable virtual {
                  _fallback();
              }
              /**
               * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`
               * call, or as part of the Solidity `fallback` or `receive` functions.
               *
               * If overriden should call `super._beforeFallback()`.
               */
              function _beforeFallback() internal virtual {
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.8.2;
          import "../beacon/IBeacon.sol";
          import "../../utils/Address.sol";
          import "../../utils/StorageSlot.sol";
          /**
           * @dev This abstract contract provides getters and event emitting update functions for
           * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
           *
           * _Available since v4.1._
           *
           * @custom:oz-upgrades-unsafe-allow delegatecall
           */
          abstract contract ERC1967Upgrade {
              // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
              bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;
              /**
               * @dev Storage slot with the address of the current implementation.
               * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
               * validated in the constructor.
               */
              bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
              /**
               * @dev Emitted when the implementation is upgraded.
               */
              event Upgraded(address indexed implementation);
              /**
               * @dev Returns the current implementation address.
               */
              function _getImplementation() internal view returns (address) {
                  return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
              }
              /**
               * @dev Stores a new address in the EIP1967 implementation slot.
               */
              function _setImplementation(address newImplementation) private {
                  require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
                  StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
              }
              /**
               * @dev Perform implementation upgrade
               *
               * Emits an {Upgraded} event.
               */
              function _upgradeTo(address newImplementation) internal {
                  _setImplementation(newImplementation);
                  emit Upgraded(newImplementation);
              }
              /**
               * @dev Perform implementation upgrade with additional setup call.
               *
               * Emits an {Upgraded} event.
               */
              function _upgradeToAndCall(address newImplementation, bytes memory data, bool forceCall) internal {
                  _setImplementation(newImplementation);
                  emit Upgraded(newImplementation);
                  if (data.length > 0 || forceCall) {
                      Address.functionDelegateCall(newImplementation, data);
                  }
              }
              /**
               * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
               *
               * Emits an {Upgraded} event.
               */
              function _upgradeToAndCallSecure(address newImplementation, bytes memory data, bool forceCall) internal {
                  address oldImplementation = _getImplementation();
                  // Initial upgrade and setup call
                  _setImplementation(newImplementation);
                  if (data.length > 0 || forceCall) {
                      Address.functionDelegateCall(newImplementation, data);
                  }
                  // Perform rollback test if not already in progress
                  StorageSlot.BooleanSlot storage rollbackTesting = StorageSlot.getBooleanSlot(_ROLLBACK_SLOT);
                  if (!rollbackTesting.value) {
                      // Trigger rollback using upgradeTo from the new implementation
                      rollbackTesting.value = true;
                      Address.functionDelegateCall(
                          newImplementation,
                          abi.encodeWithSignature(
                              "upgradeTo(address)",
                              oldImplementation
                          )
                      );
                      rollbackTesting.value = false;
                      // Check rollback was effective
                      require(oldImplementation == _getImplementation(), "ERC1967Upgrade: upgrade breaks further upgrades");
                      // Finally reset to the new implementation and log the upgrade
                      _setImplementation(newImplementation);
                      emit Upgraded(newImplementation);
                  }
              }
              /**
               * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
               * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
               *
               * Emits a {BeaconUpgraded} event.
               */
              function _upgradeBeaconToAndCall(address newBeacon, bytes memory data, bool forceCall) internal {
                  _setBeacon(newBeacon);
                  emit BeaconUpgraded(newBeacon);
                  if (data.length > 0 || forceCall) {
                      Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
                  }
              }
              /**
               * @dev Storage slot with the admin of the contract.
               * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
               * validated in the constructor.
               */
              bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
              /**
               * @dev Emitted when the admin account has changed.
               */
              event AdminChanged(address previousAdmin, address newAdmin);
              /**
               * @dev Returns the current admin.
               */
              function _getAdmin() internal view returns (address) {
                  return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;
              }
              /**
               * @dev Stores a new address in the EIP1967 admin slot.
               */
              function _setAdmin(address newAdmin) private {
                  require(newAdmin != address(0), "ERC1967: new admin is the zero address");
                  StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
              }
              /**
               * @dev Changes the admin of the proxy.
               *
               * Emits an {AdminChanged} event.
               */
              function _changeAdmin(address newAdmin) internal {
                  emit AdminChanged(_getAdmin(), newAdmin);
                  _setAdmin(newAdmin);
              }
              /**
               * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
               * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
               */
              bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
              /**
               * @dev Emitted when the beacon is upgraded.
               */
              event BeaconUpgraded(address indexed beacon);
              /**
               * @dev Returns the current beacon.
               */
              function _getBeacon() internal view returns (address) {
                  return StorageSlot.getAddressSlot(_BEACON_SLOT).value;
              }
              /**
               * @dev Stores a new beacon in the EIP1967 beacon slot.
               */
              function _setBeacon(address newBeacon) private {
                  require(
                      Address.isContract(newBeacon),
                      "ERC1967: new beacon is not a contract"
                  );
                  require(
                      Address.isContract(IBeacon(newBeacon).implementation()),
                      "ERC1967: beacon implementation is not a contract"
                  );
                  StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.8.0;
          /**
           * @dev This is the interface that {BeaconProxy} expects of its beacon.
           */
          interface IBeacon {
              /**
               * @dev Must return an address that can be used as a delegate call target.
               *
               * {BeaconProxy} will check that this address is a contract.
               */
              function implementation() external view returns (address);
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^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);
                      }
                  }
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.8.0;
          /**
           * @dev Library for reading and writing primitive types to specific storage slots.
           *
           * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
           * This library helps with reading and writing to such slots without the need for inline assembly.
           *
           * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
           *
           * Example usage to set ERC1967 implementation slot:
           * ```
           * contract ERC1967 {
           *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
           *
           *     function _getImplementation() internal view returns (address) {
           *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
           *     }
           *
           *     function _setImplementation(address newImplementation) internal {
           *         require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
           *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
           *     }
           * }
           * ```
           *
           * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._
           */
          library StorageSlot {
              struct AddressSlot {
                  address value;
              }
              struct BooleanSlot {
                  bool value;
              }
              struct Bytes32Slot {
                  bytes32 value;
              }
              struct Uint256Slot {
                  uint256 value;
              }
              /**
               * @dev Returns an `AddressSlot` with member `value` located at `slot`.
               */
              function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
                  assembly {
                      r.slot := slot
                  }
              }
              /**
               * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
               */
              function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
                  assembly {
                      r.slot := slot
                  }
              }
              /**
               * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
               */
              function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
                  assembly {
                      r.slot := slot
                  }
              }
              /**
               * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
               */
              function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
                  assembly {
                      r.slot := slot
                  }
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^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 () {
                  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;
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^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 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) {
                  return msg.sender;
              }
              function _msgData() internal view virtual returns (bytes calldata) {
                  this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
                  return msg.data;
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.8.0;
          import "../ERC1967/ERC1967Upgrade.sol";
          /**
           * @dev Base contract for building openzeppelin-upgrades compatible implementations for the {ERC1967Proxy}. It includes
           * publicly available upgrade functions that are called by the plugin and by the secure upgrade mechanism to verify
           * continuation of the upgradability.
           *
           * The {_authorizeUpgrade} function MUST be overridden to include access restriction to the upgrade mechanism.
           *
           * _Available since v4.1._
           */
          abstract contract UUPSUpgradeable is ERC1967Upgrade {
              function upgradeTo(address newImplementation) external virtual {
                  _authorizeUpgrade(newImplementation);
                  _upgradeToAndCallSecure(newImplementation, bytes(""), false);
              }
              function upgradeToAndCall(address newImplementation, bytes memory data) external payable virtual {
                  _authorizeUpgrade(newImplementation);
                  _upgradeToAndCallSecure(newImplementation, data, true);
              }
              function _authorizeUpgrade(address newImplementation) internal virtual;
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.8.2;
          import "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol";
          abstract contract Proxiable is UUPSUpgradeable {
              function _authorizeUpgrade(address newImplementation) internal override {
                  _beforeUpgrade(newImplementation);
              }
              function _beforeUpgrade(address newImplementation) internal virtual;
          }
          contract ChildOfProxiable is Proxiable {
              function _beforeUpgrade(address newImplementation) internal virtual override {}
          }
          

          File 5 of 6: ClaimedUpgradable
          // SPDX-License-Identifier: CLOSED - Pending Licensing Audit
          pragma solidity ^0.8.4;
          import "./IERC721.sol";
          import "./ReentrancyGuardUpgradable.sol";
          import "./HasRegistration.sol";
          contract ClaimedUpgradable is ReentrancyGuardUpgradable, HasRegistration {
              
              bool canClaim;
              mapping(address => bytes32) LegacyClaims;
              mapping(address => bytes32) LegacyClaimsBy;
              mapping(address => mapping(uint => address)) Claims;
              mapping(address => uint256[]) ClaimsFor;
              address[] BurnAddresses;
              
              function initialize() public initializer {
                  __Ownable_init();
                  ReentrancyGuardUpgradable.init();
                  canClaim = true;
                  BurnAddresses.push(address(0));
                  BurnAddresses.push(0x5D152dd902CC9198B97E5b6Cf5fc23a8e4330180);
              }
              function version() public pure returns (uint256) {
                  return 3;
              }
              
              function isBurnAddress(address needle) public view returns (bool) {
                  address[] memory burnAddresses = getBurnAddresses();
                  for (uint i=0; i < burnAddresses.length; i++) {
                      if (burnAddresses[i] == needle) {
                          return true;
                      }
                  }
                  return false;
              }
              function toggleCanClaim() public onlyOwner {
                  canClaim = !canClaim;
              }
              
              function claim(address nftAddress, uint tokenId, address _claimedBy) public nonReentrant isRegisteredContract(_msgSender()) {        
                  if (canClaim) {
                      addToClaims(nftAddress, tokenId, _claimedBy);
                  } else { 
                      revert("Claiming is turned off");
                  }
              }
              
              function isClaimed(address nftAddress, uint tokenId, bytes32[] calldata proof ) public view returns(bool) {
                  bytes32 _hash = keccak256(abi.encodePacked(tokenId));
                  IERC721 token = IERC721(nftAddress);        
                  if (proof.length == 0) {
                      bool claimed = getClaims(nftAddress, tokenId) != address(0);
                      bool addressClaimed = false;
                      try token.ownerOf(tokenId) returns (address _owner) {
                          if (isBurnAddress(_owner)) {
                              addressClaimed = true;
                          }
                      } catch {}
                      return addressClaimed || claimed;
                  } else {
                      bytes32 root = getLegacyClaims(nftAddress);
                      return verifyScript(root, _hash, proof);
                  }
              }
              function getClaimsFor(address _owner) public view returns (uint256[] memory) {
                  return ClaimsFor[_owner];
              }
              function getLegacyClaims(address nftAddress) public view returns(bytes32) {
                  return LegacyClaims[nftAddress];
              }
              
              function claimedBy(address nftAddress, uint tokenId) public view returns (address _owner, string memory _type) {
                  address claimed = getClaims(nftAddress, tokenId);
                  if (claimed != address(0)) {
                      return (claimed, "record");
                  } else {
                      return (address(0), "unknown");
                  }
              }
              function legacyClaimedBy(address nftAddress, address claimant, uint tokenId, bytes32[] calldata proof) public view returns (address _owner, string memory _type) {
                  bytes32 root = getLegacyClaimsBy(nftAddress);
                  bytes32 _hash = keccak256(abi.encodePacked(claimant, tokenId));
                  require(verifyScript(root, _hash, proof), "invalid proof");
                  return (claimant, 'legacy');
              }
              function addLegacy(address nftAddress, bytes32 root) onlyOwner public {
                  LegacyClaims[nftAddress] = root;      
              }
              function addLegacyClaimedBy(address nftAddress, bytes32 root) onlyOwner public {
                  LegacyClaimsBy[nftAddress] = root;
              }
              function getBurnAddresses() internal view returns (address[] memory){
                  return BurnAddresses;
              }
              function getLegacyClaimsBy(address nftAddress) internal view returns(bytes32) {
                  return LegacyClaimsBy[nftAddress];
              }
              
              function getClaims(address nftAddress, uint tokenId) internal view returns (address) {
                  return Claims[nftAddress][tokenId];
              }
              
              function addToBurnAddresses(address burnAddress) internal onlyOwner {
                   BurnAddresses.push(burnAddress);
              }
              
              function addToClaims(address nftAddress, uint tokenId, address _owner) internal {
                  Claims[nftAddress][tokenId] = _owner;
                  ClaimsFor[_owner].push(tokenId);
              }
              function verifyScript(bytes32 root, bytes32 _hash, bytes32[] calldata proof) public pure returns (bool) {
                  for (uint256 i = 0; i < proof.length; i++) {
                      bytes32 proofElement = proof[i];
                      if (_hash <= proofElement) {
                          _hash = optihash(_hash, proofElement);
                      } else {
                          _hash = optihash(proofElement, _hash);
                      }
                  }
                  return _hash == root;
              }
              // memory optimization from: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3039
              function optihash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {
                  assembly {
                  mstore(0x00, a)
                  mstore(0x20, b)
                  value := keccak256(0x00, 0x40)
                  }
              }
          }// SPDX-License-Identifier: MIT
          pragma solidity ^0.8.4;
          interface IERC721 {
              function burn(uint256 tokenId) external;
              function transferFrom(address from, address to, uint256 tokenId) external;
              function mint( address _to, uint256 _tokenId, string calldata _uri, string calldata _payload) external;
              function changeName(string calldata name, string calldata symbol) external;
              function updateTokenUri(uint256 _tokenId,string memory _uri) external;
              function tokenPayload(uint256 _tokenId) external view returns (string memory);
              function ownerOf(uint256 _tokenId) external view returns (address _owner);
              function getApproved(uint256 _tokenId) external returns (address);
              function safeTransferFrom(address _from, address _to, uint256 _tokenId) external;
              function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes calldata data) external;
              function totalSupply() external view returns (uint256);
              function tokenOfOwnerByIndex(address _owner, uint256 _index) external view returns (uint256);
              function tokenByIndex(uint256 _index) external view returns (uint256);
              function balanceOf(address account, uint256 id) external view returns (uint256);
              function isApprovedForAll(address _owner, address _operator) external view returns (bool);
              function setApprovalForAll( address _operator, bool _approved) external;
          }
          /**
           * @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);
          }// SPDX-License-Identifier: CLOSED - Pending Licensing Audit
          pragma solidity ^0.8.4;
          /**
           * @dev Contract module that helps prevent reentrant calls to a function.
           *
           * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
           * available, which can be applied to functions to make sure there are no nested
           * (reentrant) calls to them.
           *
           * Note that because there is a single `nonReentrant` guard, functions marked as
           * `nonReentrant` may not call one another. This can be worked around by making
           * those functions `private`, and then adding `external` `nonReentrant` entry
           * points to them.
           *
           * TIP: If you would like to learn more about reentrancy and alternative ways
           * to protect against it, check out our blog post
           * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
           */
          contract ReentrancyGuardUpgradable {
              // Booleans are more expensive than uint256 or any type that takes up a full
              // word because each write operation emits an extra SLOAD to first read the
              // slot's contents, replace the bits taken up by the boolean, and then write
              // back. This is the compiler's defense against contract upgrades and
              // pointer aliasing, and it cannot be disabled.
              // The values being non-zero value makes deployment a bit more expensive,
              // but in exchange the refund on every call to nonReentrant will be lower in
              // amount. Since refunds are capped to a percentage of the total
              // transaction's gas, it is best to keep them low in cases like this one, to
              // increase the likelihood of the full refund coming into effect.
              uint256 private _NOT_ENTERED;
              uint256 private _ENTERED;
              uint256 private _status;
              function init() internal {
                   _NOT_ENTERED = 1;
                   _ENTERED = 2;
                  _status = _NOT_ENTERED;
              }
              /**
               * @dev Prevents a contract from calling itself, directly or indirectly.
               * Calling a `nonReentrant` function from another `nonReentrant`
               * function is not supported. It is possible to prevent this from happening
               * by making the `nonReentrant` function external, and make it call a
               * `private` function that does the actual work.
               */
              modifier nonReentrant() {
                  // On the first call to nonReentrant, _notEntered will be true
                  require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
                  // Any calls to nonReentrant after this point will fail
                  _status = _ENTERED;
                  _;
                  // By storing the original value once again, a refund is triggered (see
                  // https://eips.ethereum.org/EIPS/eip-2200)
                  _status = _NOT_ENTERED;
              }
          }// SPDX-License-Identifier: CLOSED - Pending Licensing Audit
          pragma solidity ^0.8.4;
          import "./IsBypassable.sol";
          contract HasRegistration is IsBypassable {
              mapping(address => uint256) public registeredContracts; // 0 EMPTY, 1 ERC1155, 2 ERC721, 3 HANDLER, 4 ERC20, 5 BALANCE, 6 CLAIM, 7 UNKNOWN, 8 FACTORY, 9 STAKING, 10 BYPASS
              mapping(uint256 => address[]) internal registeredOfType;
              modifier isRegisteredContract(address _contract) {
                  require(registeredContracts[_contract] > 0, "Contract is not registered");
                  _;
              }
              modifier isRegisteredContractOrOwner(address _contract) {
                  require(registeredContracts[_contract] > 0 || owner() == _msgSender(), "Contract is not registered nor Owner");
                  _;
              }
              function registerContract(address _contract, uint _type) public isRegisteredContractOrOwner(_msgSender()) {
                  registeredContracts[_contract] = _type;
                  registeredOfType[_type].push(_contract);
              }
              function unregisterContract(address _contract, uint256 index) public onlyOwner isRegisteredContract(_contract) {
                  address[] storage arr = registeredOfType[registeredContracts[_contract]];
                  arr[index] = arr[arr.length - 1];
                  arr.pop();
                  delete registeredContracts[_contract];
              }
              function isRegistered(address _contract, uint256 _type) public view returns (bool) {
                  return registeredContracts[_contract] == _type;
              }
              function getAllRegisteredContractsOfType(uint256 _type) public view returns (address[] memory) {
                  return registeredOfType[_type];
              }
          }// SPDX-License-Identifier: CLOSED - Pending Licensing Audit
          pragma solidity ^0.8.4;
          import "./IsClaimable.sol";
          abstract contract IsBypassable is IsClaimable {
              bool byPassable;
              mapping(address => mapping(bytes4 => bool)) byPassableFunction;
              mapping(address => mapping(uint256 => bool)) byPassableIds;
              modifier onlyOwner virtual override {
                  bool _canBypass = byPassable && byPassableFunction[_msgSender()][msg.sig];
                  require(owner() == _msgSender() || _canBypass, "Not owner or able to bypass");
                      _;
              }
              modifier onlyOwnerOrBypassWithId(uint256 id) {
                  require (owner() == _msgSender() || (id != 0 && byPassableIds[_msgSender()][id] ), "Invalid id");
                      _;
              }
              function canBypass() internal view returns(bool) {
                  return (byPassable && byPassableFunction[_msgSender()][msg.sig]);
              }
              function canBypassForTokenId(uint256 id) internal view returns(bool) {
                  return (byPassable && canBypass() && byPassableIds[_msgSender()][id]);
              }
              function toggleBypassability() public onlyOwner {
                byPassable = !byPassable;
              }
              function addBypassRule(address who, bytes4 functionSig, uint256 id) public onlyOwner {
                  byPassableFunction[who][functionSig] = true;
                  if (id != 0) {
                      byPassableIds[who][id] = true;
                  }        
              }
              function removeBypassRule(address who, bytes4 functionSig, uint256 id) public onlyOwner {
                  byPassableFunction[who][functionSig] = false;
                  if (id !=0) {
                      byPassableIds[who][id] = true;
                  }
              }
          }// SPDX-License-Identifier: CLOSED - Pending Licensing Audit
          pragma solidity ^0.8.4;
          import "./OwnableUpgradeable.sol";
          abstract contract IsClaimable is OwnableUpgradeable {
              bool public isClaimable;
              function toggleClaimable() public onlyOwner {
                  isClaimable = !isClaimable;
              }
             
          }// SPDX-License-Identifier: MIT
          pragma solidity ^0.8.0;
          import "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol";
          import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.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 OwnableUpgradeable is Initializable, ContextUpgradeable {
              address private _owner;
              event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
              /**
               * @dev Initializes the contract setting the deployer as the initial owner.
               */
              function __Ownable_init() internal onlyInitializing {
                  __Ownable_init_unchained();
              }
              function __Ownable_init_unchained() internal onlyInitializing {
                  _transferOwnership(_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() virtual {
                  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 {
                  _transferOwnership(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");
                  _transferOwnership(newOwner);
              }
              /**
               * @dev Transfers ownership of the contract to a new account (`newOwner`).
               * Internal function without access restriction.
               */
              function _transferOwnership(address newOwner) internal virtual {
                  address oldOwner = _owner;
                  _owner = newOwner;
                  emit OwnershipTransferred(oldOwner, newOwner);
              }
              /**
               * @dev This empty reserved space is put in place to allow future versions to add new
               * variables without shifting down storage in the inheritance chain.
               * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
               */
              uint256[49] private __gap;
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
          pragma solidity ^0.8.0;
          import "../proxy/utils/Initializable.sol";
          /**
           * @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 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 ContextUpgradeable is Initializable {
              function __Context_init() internal onlyInitializing {
              }
              function __Context_init_unchained() internal onlyInitializing {
              }
              function _msgSender() internal view virtual returns (address) {
                  return msg.sender;
              }
              function _msgData() internal view virtual returns (bytes calldata) {
                  return msg.data;
              }
              /**
               * @dev This empty reserved space is put in place to allow future versions to add new
               * variables without shifting down storage in the inheritance chain.
               * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
               */
              uint256[50] private __gap;
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts (last updated v4.7.0) (proxy/utils/Initializable.sol)
          pragma solidity ^0.8.2;
          import "../../utils/AddressUpgradeable.sol";
          /**
           * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
           * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
           * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
           * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
           *
           * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
           * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
           * case an upgrade adds a module that needs to be initialized.
           *
           * For example:
           *
           * [.hljs-theme-light.nopadding]
           * ```
           * contract MyToken is ERC20Upgradeable {
           *     function initialize() initializer public {
           *         __ERC20_init("MyToken", "MTK");
           *     }
           * }
           * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
           *     function initializeV2() reinitializer(2) public {
           *         __ERC20Permit_init("MyToken");
           *     }
           * }
           * ```
           *
           * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
           * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
           *
           * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
           * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
           *
           * [CAUTION]
           * ====
           * Avoid leaving a contract uninitialized.
           *
           * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
           * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
           * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
           *
           * [.hljs-theme-light.nopadding]
           * ```
           * /// @custom:oz-upgrades-unsafe-allow constructor
           * constructor() {
           *     _disableInitializers();
           * }
           * ```
           * ====
           */
          abstract contract Initializable {
              /**
               * @dev Indicates that the contract has been initialized.
               * @custom:oz-retyped-from bool
               */
              uint8 private _initialized;
              /**
               * @dev Indicates that the contract is in the process of being initialized.
               */
              bool private _initializing;
              /**
               * @dev Triggered when the contract has been initialized or reinitialized.
               */
              event Initialized(uint8 version);
              /**
               * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
               * `onlyInitializing` functions can be used to initialize parent contracts. Equivalent to `reinitializer(1)`.
               */
              modifier initializer() {
                  bool isTopLevelCall = !_initializing;
                  require(
                      (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
                      "Initializable: contract is already initialized"
                  );
                  _initialized = 1;
                  if (isTopLevelCall) {
                      _initializing = true;
                  }
                  _;
                  if (isTopLevelCall) {
                      _initializing = false;
                      emit Initialized(1);
                  }
              }
              /**
               * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
               * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
               * used to initialize parent contracts.
               *
               * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original
               * initialization step. This is essential to configure modules that are added through upgrades and that require
               * initialization.
               *
               * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
               * a contract, executing them in the right order is up to the developer or operator.
               */
              modifier reinitializer(uint8 version) {
                  require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
                  _initialized = version;
                  _initializing = true;
                  _;
                  _initializing = false;
                  emit Initialized(version);
              }
              /**
               * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
               * {initializer} and {reinitializer} modifiers, directly or indirectly.
               */
              modifier onlyInitializing() {
                  require(_initializing, "Initializable: contract is not initializing");
                  _;
              }
              /**
               * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
               * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
               * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
               * through proxies.
               */
              function _disableInitializers() internal virtual {
                  require(!_initializing, "Initializable: contract is initializing");
                  if (_initialized < type(uint8).max) {
                      _initialized = type(uint8).max;
                      emit Initialized(type(uint8).max);
                  }
              }
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)
          pragma solidity ^0.8.1;
          /**
           * @dev Collection of functions related to the address type
           */
          library AddressUpgradeable {
              /**
               * @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
               * ====
               *
               * [IMPORTANT]
               * ====
               * You shouldn't rely on `isContract` to protect against flash loan attacks!
               *
               * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
               * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
               * constructor.
               * ====
               */
              function isContract(address account) internal view returns (bool) {
                  // This method relies on extcodesize/address.code.length, which returns 0
                  // for contracts in construction, since the code is only stored at the end
                  // of the constructor execution.
                  return account.code.length > 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");
                  (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");
                  (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");
                  (bool success, bytes memory returndata) = target.staticcall(data);
                  return verifyCallResult(success, returndata, errorMessage);
              }
              /**
               * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
               * revert reason using the provided one.
               *
               * _Available since v4.3._
               */
              function verifyCallResult(
                  bool success,
                  bytes memory returndata,
                  string memory errorMessage
              ) internal 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
                          /// @solidity memory-safe-assembly
                          assembly {
                              let returndata_size := mload(returndata)
                              revert(add(32, returndata), returndata_size)
                          }
                      } else {
                          revert(errorMessage);
                      }
                  }
              }
          }
          

          File 6 of 6: CircuitsOfValue
          // File: zos-lib/contracts/Initializable.sol
          
          pragma solidity >=0.4.24 <0.6.0;
          
          
          /**
           * @title Initializable
           *
           * @dev Helper contract to support initializer functions. To use it, replace
           * the constructor with a function that has the `initializer` modifier.
           * WARNING: Unlike constructors, initializer functions must be manually
           * invoked. This applies both to deploying an Initializable contract, as well
           * as extending an Initializable contract via inheritance.
           * WARNING: When used with inheritance, manual care must be taken to not invoke
           * a parent initializer twice, or ensure that all initializers are idempotent,
           * because this is not dealt with automatically as with constructors.
           */
          contract Initializable {
          
            /**
             * @dev Indicates that the contract has been initialized.
             */
            bool private initialized;
          
            /**
             * @dev Indicates that the contract is in the process of being initialized.
             */
            bool private initializing;
          
            /**
             * @dev Modifier to use in the initializer function of a contract.
             */
            modifier initializer() {
              require(initializing || isConstructor() || !initialized, "Contract instance has already been initialized");
          
              bool isTopLevelCall = !initializing;
              if (isTopLevelCall) {
                initializing = true;
                initialized = true;
              }
          
              _;
          
              if (isTopLevelCall) {
                initializing = false;
              }
            }
          
            /// @dev Returns true if and only if the function is running in the constructor
            function isConstructor() private view returns (bool) {
              // extcodesize checks the size of the code stored in an address, and
              // address returns the current address. Since the code is still not
              // deployed when running a constructor, any checks on its code size will
              // yield zero, making it an effective way to detect if a contract is
              // under construction or not.
              uint256 cs;
              assembly { cs := extcodesize(address) }
              return cs == 0;
            }
          
            // Reserved storage space to allow for layout changes in the future.
            uint256[50] private ______gap;
          }
          
          // File: openzeppelin-eth/contracts/token/ERC20/IERC20.sol
          
          pragma solidity ^0.5.2;
          
          /**
           * @title ERC20 interface
           * @dev see https://eips.ethereum.org/EIPS/eip-20
           */
          interface IERC20 {
              function transfer(address to, uint256 value) external returns (bool);
          
              function approve(address spender, uint256 value) external returns (bool);
          
              function transferFrom(address from, address to, uint256 value) external returns (bool);
          
              function totalSupply() external view returns (uint256);
          
              function balanceOf(address who) external view returns (uint256);
          
              function allowance(address owner, address spender) external view returns (uint256);
          
              event Transfer(address indexed from, address indexed to, uint256 value);
          
              event Approval(address indexed owner, address indexed spender, uint256 value);
          }
          
          // File: openzeppelin-eth/contracts/math/SafeMath.sol
          
          pragma solidity ^0.5.2;
          
          /**
           * @title SafeMath
           * @dev Unsigned math operations with safety checks that revert on error
           */
          library SafeMath {
              /**
               * @dev Multiplies two unsigned integers, reverts on overflow.
               */
              function mul(uint256 a, uint256 b) internal pure returns (uint256) {
                  // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
                  // benefit is lost if 'b' is also tested.
                  // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
                  if (a == 0) {
                      return 0;
                  }
          
                  uint256 c = a * b;
                  require(c / a == b);
          
                  return c;
              }
          
              /**
               * @dev Integer division of two unsigned integers truncating the quotient, reverts on division by zero.
               */
              function div(uint256 a, uint256 b) internal pure returns (uint256) {
                  // Solidity only automatically asserts when dividing by 0
                  require(b > 0);
                  uint256 c = a / b;
                  // assert(a == b * c + a % b); // There is no case in which this doesn't hold
          
                  return c;
              }
          
              /**
               * @dev Subtracts two unsigned integers, reverts on overflow (i.e. if subtrahend is greater than minuend).
               */
              function sub(uint256 a, uint256 b) internal pure returns (uint256) {
                  require(b <= a);
                  uint256 c = a - b;
          
                  return c;
              }
          
              /**
               * @dev Adds two unsigned integers, reverts on overflow.
               */
              function add(uint256 a, uint256 b) internal pure returns (uint256) {
                  uint256 c = a + b;
                  require(c >= a);
          
                  return c;
              }
          
              /**
               * @dev Divides two unsigned integers and returns the remainder (unsigned integer modulo),
               * reverts when dividing by zero.
               */
              function mod(uint256 a, uint256 b) internal pure returns (uint256) {
                  require(b != 0);
                  return a % b;
              }
          }
          
          // File: openzeppelin-eth/contracts/token/ERC20/ERC20.sol
          
          pragma solidity ^0.5.2;
          
          
          
          
          /**
           * @title Standard ERC20 token
           *
           * @dev Implementation of the basic standard token.
           * https://eips.ethereum.org/EIPS/eip-20
           * Originally based on code by FirstBlood:
           * https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
           *
           * This implementation emits additional Approval events, allowing applications to reconstruct the allowance status for
           * all accounts just by listening to said events. Note that this isn't required by the specification, and other
           * compliant implementations may not do it.
           */
          contract ERC20 is Initializable, IERC20 {
              using SafeMath for uint256;
          
              mapping (address => uint256) private _balances;
          
              mapping (address => mapping (address => uint256)) private _allowed;
          
              uint256 private _totalSupply;
          
              /**
               * @dev Total number of tokens in existence
               */
              function totalSupply() public view returns (uint256) {
                  return _totalSupply;
              }
          
              /**
               * @dev Gets the balance of the specified address.
               * @param owner The address to query the balance of.
               * @return A uint256 representing the amount owned by the passed address.
               */
              function balanceOf(address owner) public view returns (uint256) {
                  return _balances[owner];
              }
          
              /**
               * @dev Function to check the amount of tokens that an owner allowed to a spender.
               * @param owner address The address which owns the funds.
               * @param spender address The address which will spend the funds.
               * @return A uint256 specifying the amount of tokens still available for the spender.
               */
              function allowance(address owner, address spender) public view returns (uint256) {
                  return _allowed[owner][spender];
              }
          
              /**
               * @dev Transfer token to a specified address
               * @param to The address to transfer to.
               * @param value The amount to be transferred.
               */
              function transfer(address to, uint256 value) public returns (bool) {
                  _transfer(msg.sender, to, value);
                  return true;
              }
          
              /**
               * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
               * Beware that changing an allowance with this method brings the risk that someone may use both the old
               * and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this
               * race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:
               * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
               * @param spender The address which will spend the funds.
               * @param value The amount of tokens to be spent.
               */
              function approve(address spender, uint256 value) public returns (bool) {
                  _approve(msg.sender, spender, value);
                  return true;
              }
          
              /**
               * @dev Transfer tokens from one address to another.
               * Note that while this function emits an Approval event, this is not required as per the specification,
               * and other compliant implementations may not emit the event.
               * @param from address The address which you want to send tokens from
               * @param to address The address which you want to transfer to
               * @param value uint256 the amount of tokens to be transferred
               */
              function transferFrom(address from, address to, uint256 value) public returns (bool) {
                  _transfer(from, to, value);
                  _approve(from, msg.sender, _allowed[from][msg.sender].sub(value));
                  return true;
              }
          
              /**
               * @dev Increase the amount of tokens that an owner allowed to a spender.
               * approve should be called when _allowed[msg.sender][spender] == 0. To increment
               * allowed value is better to use this function to avoid 2 calls (and wait until
               * the first transaction is mined)
               * From MonolithDAO Token.sol
               * Emits an Approval event.
               * @param spender The address which will spend the funds.
               * @param addedValue The amount of tokens to increase the allowance by.
               */
              function increaseAllowance(address spender, uint256 addedValue) public returns (bool) {
                  _approve(msg.sender, spender, _allowed[msg.sender][spender].add(addedValue));
                  return true;
              }
          
              /**
               * @dev Decrease the amount of tokens that an owner allowed to a spender.
               * approve should be called when _allowed[msg.sender][spender] == 0. To decrement
               * allowed value is better to use this function to avoid 2 calls (and wait until
               * the first transaction is mined)
               * From MonolithDAO Token.sol
               * Emits an Approval event.
               * @param spender The address which will spend the funds.
               * @param subtractedValue The amount of tokens to decrease the allowance by.
               */
              function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) {
                  _approve(msg.sender, spender, _allowed[msg.sender][spender].sub(subtractedValue));
                  return true;
              }
          
              /**
               * @dev Transfer token for a specified addresses
               * @param from The address to transfer from.
               * @param to The address to transfer to.
               * @param value The amount to be transferred.
               */
              function _transfer(address from, address to, uint256 value) internal {
                  require(to != address(0));
          
                  _balances[from] = _balances[from].sub(value);
                  _balances[to] = _balances[to].add(value);
                  emit Transfer(from, to, value);
              }
          
              /**
               * @dev Internal function that mints an amount of the token and assigns it to
               * an account. This encapsulates the modification of balances such that the
               * proper events are emitted.
               * @param account The account that will receive the created tokens.
               * @param value The amount that will be created.
               */
              function _mint(address account, uint256 value) internal {
                  require(account != address(0));
          
                  _totalSupply = _totalSupply.add(value);
                  _balances[account] = _balances[account].add(value);
                  emit Transfer(address(0), account, value);
              }
          
              /**
               * @dev Internal function that burns an amount of the token of a given
               * account.
               * @param account The account whose tokens will be burnt.
               * @param value The amount that will be burnt.
               */
              function _burn(address account, uint256 value) internal {
                  require(account != address(0));
          
                  _totalSupply = _totalSupply.sub(value);
                  _balances[account] = _balances[account].sub(value);
                  emit Transfer(account, address(0), value);
              }
          
              /**
               * @dev Approve an address to spend another addresses' tokens.
               * @param owner The address that owns the tokens.
               * @param spender The address that will spend the tokens.
               * @param value The number of tokens that can be spent.
               */
              function _approve(address owner, address spender, uint256 value) internal {
                  require(spender != address(0));
                  require(owner != address(0));
          
                  _allowed[owner][spender] = value;
                  emit Approval(owner, spender, value);
              }
          
              /**
               * @dev Internal function that burns an amount of the token of a given
               * account, deducting from the sender's allowance for said account. Uses the
               * internal burn function.
               * Emits an Approval event (reflecting the reduced allowance).
               * @param account The account whose tokens will be burnt.
               * @param value The amount that will be burnt.
               */
              function _burnFrom(address account, uint256 value) internal {
                  _burn(account, value);
                  _approve(account, msg.sender, _allowed[account][msg.sender].sub(value));
              }
          
              uint256[50] private ______gap;
          }
          
          // File: openzeppelin-eth/contracts/token/ERC20/ERC20Detailed.sol
          
          pragma solidity ^0.5.2;
          
          
          
          /**
           * @title ERC20Detailed token
           * @dev The decimals are only for visualization purposes.
           * All the operations are done using the smallest and indivisible token unit,
           * just as on Ethereum all the operations are done in wei.
           */
          contract ERC20Detailed is Initializable, IERC20 {
              string private _name;
              string private _symbol;
              uint8 private _decimals;
          
              function initialize(string memory name, string memory symbol, uint8 decimals) public initializer {
                  _name = name;
                  _symbol = symbol;
                  _decimals = decimals;
              }
          
              /**
               * @return the name of the token.
               */
              function name() public view returns (string memory) {
                  return _name;
              }
          
              /**
               * @return the symbol of the token.
               */
              function symbol() public view returns (string memory) {
                  return _symbol;
              }
          
              /**
               * @return the number of decimals of the token.
               */
              function decimals() public view returns (uint8) {
                  return _decimals;
              }
          
              uint256[50] private ______gap;
          }
          
          // File: openzeppelin-eth/contracts/token/ERC20/ERC20Burnable.sol
          
          pragma solidity ^0.5.2;
          
          
          
          /**
           * @title Burnable Token
           * @dev Token that can be irreversibly burned (destroyed).
           */
          contract ERC20Burnable is Initializable, ERC20 {
              /**
               * @dev Burns a specific amount of tokens.
               * @param value The amount of token to be burned.
               */
              function burn(uint256 value) public {
                  _burn(msg.sender, value);
              }
          
              /**
               * @dev Burns a specific amount of tokens from the target address and decrements allowance
               * @param from address The account whose tokens will be burned.
               * @param value uint256 The amount of token to be burned.
               */
              function burnFrom(address from, uint256 value) public {
                  _burnFrom(from, value);
              }
          
              uint256[50] private ______gap;
          }
          
          // File: openzeppelin-eth/contracts/access/Roles.sol
          
          pragma solidity ^0.5.2;
          
          /**
           * @title Roles
           * @dev Library for managing addresses assigned to a Role.
           */
          library Roles {
              struct Role {
                  mapping (address => bool) bearer;
              }
          
              /**
               * @dev give an account access to this role
               */
              function add(Role storage role, address account) internal {
                  require(account != address(0));
                  require(!has(role, account));
          
                  role.bearer[account] = true;
              }
          
              /**
               * @dev remove an account's access to this role
               */
              function remove(Role storage role, address account) internal {
                  require(account != address(0));
                  require(has(role, account));
          
                  role.bearer[account] = false;
              }
          
              /**
               * @dev check if an account has this role
               * @return bool
               */
              function has(Role storage role, address account) internal view returns (bool) {
                  require(account != address(0));
                  return role.bearer[account];
              }
          }
          
          // File: openzeppelin-eth/contracts/access/roles/PauserRole.sol
          
          pragma solidity ^0.5.2;
          
          
          
          
          contract PauserRole is Initializable {
              using Roles for Roles.Role;
          
              event PauserAdded(address indexed account);
              event PauserRemoved(address indexed account);
          
              Roles.Role private _pausers;
          
              function initialize(address sender) public initializer {
                  if (!isPauser(sender)) {
                      _addPauser(sender);
                  }
              }
          
              modifier onlyPauser() {
                  require(isPauser(msg.sender));
                  _;
              }
          
              function isPauser(address account) public view returns (bool) {
                  return _pausers.has(account);
              }
          
              function addPauser(address account) public onlyPauser {
                  _addPauser(account);
              }
          
              function renouncePauser() public {
                  _removePauser(msg.sender);
              }
          
              function _addPauser(address account) internal {
                  _pausers.add(account);
                  emit PauserAdded(account);
              }
          
              function _removePauser(address account) internal {
                  _pausers.remove(account);
                  emit PauserRemoved(account);
              }
          
              uint256[50] private ______gap;
          }
          
          // File: openzeppelin-eth/contracts/lifecycle/Pausable.sol
          
          pragma solidity ^0.5.2;
          
          
          
          /**
           * @title Pausable
           * @dev Base contract which allows children to implement an emergency stop mechanism.
           */
          contract Pausable is Initializable, PauserRole {
              event Paused(address account);
              event Unpaused(address account);
          
              bool private _paused;
          
              function initialize(address sender) public initializer {
                  PauserRole.initialize(sender);
          
                  _paused = false;
              }
          
              /**
               * @return true if the contract is paused, false otherwise.
               */
              function paused() public view returns (bool) {
                  return _paused;
              }
          
              /**
               * @dev Modifier to make a function callable only when the contract is not paused.
               */
              modifier whenNotPaused() {
                  require(!_paused);
                  _;
              }
          
              /**
               * @dev Modifier to make a function callable only when the contract is paused.
               */
              modifier whenPaused() {
                  require(_paused);
                  _;
              }
          
              /**
               * @dev called by the owner to pause, triggers stopped state
               */
              function pause() public onlyPauser whenNotPaused {
                  _paused = true;
                  emit Paused(msg.sender);
              }
          
              /**
               * @dev called by the owner to unpause, returns to normal state
               */
              function unpause() public onlyPauser whenPaused {
                  _paused = false;
                  emit Unpaused(msg.sender);
              }
          
              uint256[50] private ______gap;
          }
          
          // File: openzeppelin-eth/contracts/token/ERC20/ERC20Pausable.sol
          
          pragma solidity ^0.5.2;
          
          
          
          
          /**
           * @title Pausable token
           * @dev ERC20 modified with pausable transfers.
           */
          contract ERC20Pausable is Initializable, ERC20, Pausable {
              function initialize(address sender) public initializer {
                  Pausable.initialize(sender);
              }
          
              function transfer(address to, uint256 value) public whenNotPaused returns (bool) {
                  return super.transfer(to, value);
              }
          
              function transferFrom(address from, address to, uint256 value) public whenNotPaused returns (bool) {
                  return super.transferFrom(from, to, value);
              }
          
              function approve(address spender, uint256 value) public whenNotPaused returns (bool) {
                  return super.approve(spender, value);
              }
          
              function increaseAllowance(address spender, uint addedValue) public whenNotPaused returns (bool success) {
                  return super.increaseAllowance(spender, addedValue);
              }
          
              function decreaseAllowance(address spender, uint subtractedValue) public whenNotPaused returns (bool success) {
                  return super.decreaseAllowance(spender, subtractedValue);
              }
          
              uint256[50] private ______gap;
          }
          
          // File: openzeppelin-eth/contracts/math/Math.sol
          
          pragma solidity ^0.5.2;
          
          /**
           * @title Math
           * @dev Assorted math operations
           */
          library Math {
              /**
               * @dev Returns the largest of two numbers.
               */
              function max(uint256 a, uint256 b) internal pure returns (uint256) {
                  return a >= b ? a : b;
              }
          
              /**
               * @dev Returns the smallest of two numbers.
               */
              function min(uint256 a, uint256 b) internal pure returns (uint256) {
                  return a < b ? a : b;
              }
          
              /**
               * @dev Calculates the average of two numbers. Since these are integers,
               * averages of an even and odd number cannot be represented, and will be
               * rounded down.
               */
              function average(uint256 a, uint256 b) internal pure returns (uint256) {
                  // (a + b) / 2 can overflow, so we distribute
                  return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2);
              }
          }
          
          // File: openzeppelin-eth/contracts/utils/Arrays.sol
          
          pragma solidity ^0.5.2;
          
          
          
          /**
           * @title Arrays
           * @dev Utility library of inline array functions
           */
          library Arrays {
              /**
               * @dev Upper bound search function which is kind of binary search algorithm. It searches sorted
               * array to find index of the element value. If element is found then returns its index otherwise
               * it returns index of first element which is greater than searched value. If searched element is
               * bigger than any array element function then returns first index after last element (i.e. all
               * values inside the array are smaller than the target). Complexity O(log n).
               * @param array The array sorted in ascending order.
               * @param element The element's value to be found.
               * @return The calculated index value. Returns 0 for empty array.
               */
              function findUpperBound(uint256[] storage array, uint256 element) internal view returns (uint256) {
                  if (array.length == 0) {
                      return 0;
                  }
          
                  uint256 low = 0;
                  uint256 high = array.length;
          
                  while (low < high) {
                      uint256 mid = Math.average(low, high);
          
                      // Note that mid will always be strictly less than high (i.e. it will be a valid array index)
                      // because Math.average rounds down (it does integer division with truncation).
                      if (array[mid] > element) {
                          high = mid;
                      } else {
                          low = mid + 1;
                      }
                  }
          
                  // At this point `low` is the exclusive upper bound. We will return the inclusive upper bound.
                  if (low > 0 && array[low - 1] == element) {
                      return low - 1;
                  } else {
                      return low;
                  }
              }
          }
          
          // File: openzeppelin-eth/contracts/drafts/Counters.sol
          
          pragma solidity ^0.5.2;
          
          
          /**
           * @title Counters
           * @author Matt Condon (@shrugs)
           * @dev Provides counters that can only be incremented or decremented by one. This can be used e.g. to track the number
           * of elements in a mapping, issuing ERC721 ids, or counting request ids
           *
           * Include with `using Counters for Counters.Counter;`
           * Since it is not possible to overflow a 256 bit integer with increments of one, `increment` can skip the SafeMath
           * overflow check, thereby saving gas. This does assume however correct usage, in that the underlying `_value` is never
           * directly accessed.
           */
          library Counters {
              using SafeMath for uint256;
          
              struct Counter {
                  // This variable should never be directly accessed by users of the library: interactions must be restricted to
                  // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add
                  // this feature: see https://github.com/ethereum/solidity/issues/4637
                  uint256 _value; // default: 0
              }
          
              function current(Counter storage counter) internal view returns (uint256) {
                  return counter._value;
              }
          
              function increment(Counter storage counter) internal {
                  counter._value += 1;
              }
          
              function decrement(Counter storage counter) internal {
                  counter._value = counter._value.sub(1);
              }
          }
          
          // File: openzeppelin-eth/contracts/drafts/ERC20Snapshot.sol
          
          pragma solidity ^0.5.2;
          
          
          
          
          
          
          /**
           * @title ERC20 token with snapshots.
           * @dev Inspired by Jordi Baylina's MiniMeToken to record historical balances:
           * https://github.com/Giveth/minime/blob/ea04d950eea153a04c51fa510b068b9dded390cb/contracts/MiniMeToken.sol
           * When a snapshot is made, the balances and totalSupply at the time of the snapshot are recorded for later
           * access.
           *
           * To make a snapshot, call the `snapshot` function, which will emit the `Snapshot` event and return a snapshot id.
           * To get the total supply from a snapshot, call the function `totalSupplyAt` with the snapshot id.
           * To get the balance of an account from a snapshot, call the `balanceOfAt` function with the snapshot id and the
           * account address.
           * @author Validity Labs AG <info@validitylabs.org>
           */
          contract ERC20Snapshot is Initializable, ERC20 {
              using SafeMath for uint256;
              using Arrays for uint256[];
              using Counters for Counters.Counter;
          
              // Snapshotted values have arrays of ids and the value corresponding to that id. These could be an array of a
              // Snapshot struct, but that would impede usage of functions that work on an array.
              struct Snapshots {
                  uint256[] ids;
                  uint256[] values;
              }
          
              mapping (address => Snapshots) private _accountBalanceSnapshots;
              Snapshots private _totalSupplySnaphots;
          
              // Snapshot ids increase monotonically, with the first value being 1. An id of 0 is invalid.
              Counters.Counter private _currentSnapshotId;
          
              event Snapshot(uint256 id);
          
              // Creates a new snapshot id. Balances are only stored in snapshots on demand: unless a snapshot was taken, a
              // balance change will not be recorded. This means the extra added cost of storing snapshotted balances is only paid
              // when required, but is also flexible enough that it allows for e.g. daily snapshots.
              function snapshot() public returns (uint256) {
                  _currentSnapshotId.increment();
          
                  uint256 currentId = _currentSnapshotId.current();
                  emit Snapshot(currentId);
                  return currentId;
              }
          
              function balanceOfAt(address account, uint256 snapshotId) public view returns (uint256) {
                  (bool snapshotted, uint256 value) = _valueAt(snapshotId, _accountBalanceSnapshots[account]);
          
                  return snapshotted ? value : balanceOf(account);
              }
          
              function totalSupplyAt(uint256 snapshotId) public view returns(uint256) {
                  (bool snapshotted, uint256 value) = _valueAt(snapshotId, _totalSupplySnaphots);
          
                  return snapshotted ? value : totalSupply();
              }
          
              // _transfer, _mint and _burn are the only functions where the balances are modified, so it is there that the
              // snapshots are updated. Note that the update happens _before_ the balance change, with the pre-modified value.
              // The same is true for the total supply and _mint and _burn.
              function _transfer(address from, address to, uint256 value) internal {
                  _updateAccountSnapshot(from);
                  _updateAccountSnapshot(to);
          
                  super._transfer(from, to, value);
              }
          
              function _mint(address account, uint256 value) internal {
                  _updateAccountSnapshot(account);
                  _updateTotalSupplySnapshot();
          
                  super._mint(account, value);
              }
          
              function _burn(address account, uint256 value) internal {
                  _updateAccountSnapshot(account);
                  _updateTotalSupplySnapshot();
          
                  super._burn(account, value);
              }
          
              // When a valid snapshot is queried, there are three possibilities:
              //  a) The queried value was not modified after the snapshot was taken. Therefore, a snapshot entry was never
              //  created for this id, and all stored snapshot ids are smaller than the requested one. The value that corresponds
              //  to this id is the current one.
              //  b) The queried value was modified after the snapshot was taken. Therefore, there will be an entry with the
              //  requested id, and its value is the one to return.
              //  c) More snapshots were created after the requested one, and the queried value was later modified. There will be
              //  no entry for the requested id: the value that corresponds to it is that of the smallest snapshot id that is
              //  larger than the requested one.
              //
              // In summary, we need to find an element in an array, returning the index of the smallest value that is larger if
              // it is not found, unless said value doesn't exist (e.g. when all values are smaller). Arrays.findUpperBound does
              // exactly this.
              function _valueAt(uint256 snapshotId, Snapshots storage snapshots)
                  private view returns (bool, uint256)
              {
                  require(snapshotId > 0);
                  require(snapshotId <= _currentSnapshotId.current());
          
                  uint256 index = snapshots.ids.findUpperBound(snapshotId);
          
                  if (index == snapshots.ids.length) {
                      return (false, 0);
                  } else {
                      return (true, snapshots.values[index]);
                  }
              }
          
              function _updateAccountSnapshot(address account) private {
                  _updateSnapshot(_accountBalanceSnapshots[account], balanceOf(account));
              }
          
              function _updateTotalSupplySnapshot() private {
                  _updateSnapshot(_totalSupplySnaphots, totalSupply());
              }
          
              function _updateSnapshot(Snapshots storage snapshots, uint256 currentValue) private {
                  uint256 currentId = _currentSnapshotId.current();
                  if (_lastSnapshotId(snapshots.ids) < currentId) {
                      snapshots.ids.push(currentId);
                      snapshots.values.push(currentValue);
                  }
              }
          
              function _lastSnapshotId(uint256[] storage ids) private view returns (uint256) {
                  if (ids.length == 0) {
                      return 0;
                  } else {
                      return ids[ids.length - 1];
                  }
              }
          
              uint256[50] private ______gap;
          }
          
          // File: openzeppelin-eth/contracts/access/roles/MinterRole.sol
          
          pragma solidity ^0.5.2;
          
          
          
          
          contract MinterRole is Initializable {
              using Roles for Roles.Role;
          
              event MinterAdded(address indexed account);
              event MinterRemoved(address indexed account);
          
              Roles.Role private _minters;
          
              function initialize(address sender) public initializer {
                  if (!isMinter(sender)) {
                      _addMinter(sender);
                  }
              }
          
              modifier onlyMinter() {
                  require(isMinter(msg.sender));
                  _;
              }
          
              function isMinter(address account) public view returns (bool) {
                  return _minters.has(account);
              }
          
              function addMinter(address account) public onlyMinter {
                  _addMinter(account);
              }
          
              function renounceMinter() public {
                  _removeMinter(msg.sender);
              }
          
              function _addMinter(address account) internal {
                  _minters.add(account);
                  emit MinterAdded(account);
              }
          
              function _removeMinter(address account) internal {
                  _minters.remove(account);
                  emit MinterRemoved(account);
              }
          
              uint256[50] private ______gap;
          }
          
          // File: openzeppelin-eth/contracts/token/ERC20/ERC20Mintable.sol
          
          pragma solidity ^0.5.2;
          
          
          
          
          /**
           * @title ERC20Mintable
           * @dev ERC20 minting logic
           */
          contract ERC20Mintable is Initializable, ERC20, MinterRole {
              function initialize(address sender) public initializer {
                  MinterRole.initialize(sender);
              }
          
              /**
               * @dev Function to mint tokens
               * @param to The address that will receive the minted tokens.
               * @param value The amount of tokens to mint.
               * @return A boolean that indicates if the operation was successful.
               */
              function mint(address to, uint256 value) public onlyMinter returns (bool) {
                  _mint(to, value);
                  return true;
              }
          
              uint256[50] private ______gap;
          }
          
          // File: contracts/CircuitsOfValue.sol
          
          // contracts/CustomERC20.sol
          pragma solidity ^0.5.0;
          
          
          
          
          
          
          
          
          contract CircuitsOfValue is Initializable, ERC20, ERC20Detailed, ERC20Burnable, ERC20Pausable, ERC20Snapshot, ERC20Mintable {
          
            bool private _pausableInitialized;
          
            function initialize( string memory name, string memory symbol, uint8 decimals, uint256 initialSupply, address initialHolder )
             public initializer {
              // require(initialSupply > 0, "");
              ERC20Detailed.initialize(name, symbol, decimals);
              ERC20Mintable.initialize(msg.sender);
              initializePausable(msg.sender);
              // _mint(initialHolder, initialSupply);
            }
          
            function initializePausable(address sender) public {
                  require(!_pausableInitialized, "pausable has already been initialized");
                  _pausableInitialized = true;
                  _addPauser(sender);
              }
          }