ETH Price: $2,157.08 (+2.67%)

Transaction Decoder

Block:
16161376 at Dec-11-2022 12:10:11 PM +UTC
Transaction Fee:
0.00206737179289204 ETH $4.46
Gas Used:
145,559 Gas / 14.20298156 Gwei

Emitted Events:

Account State Difference:

  Address   Before After State Difference Code
(beaverbuild)
179.697007300251951686 Eth179.697064920386608213 Eth0.000057620134656527
0x9fad28fc...5D4A0102B
0xEb9e58d3...144f1d683
0.003910030002027734 Eth
Nonce: 17
0.001842658209135694 Eth
Nonce: 18
0.00206737179289204

Execution Trace

Prisma.mint( _req=[{name:to, type:address, order:1, indexed:false, value:0xEb9e58d3d9462061EB5c6F81bf7e36C144f1d683, valueString:0xEb9e58d3d9462061EB5c6F81bf7e36C144f1d683}, {name:reqType, type:uint256, order:2, indexed:false, value:1, valueString:1}, {name:nonce, type:uint256, order:3, indexed:false, value:69, valueString:69}], _sig=0x2CDFE5373B9E25B3FAD1CE5FE291149972B8ED04958BB099FAF4413E6A7B78855C356590E0E0262C901F89BC7CA2DA49BD5A2940640103F8F5301F2332E920B91B )
  • Prisma.verifyMintReq( mintReq=[{name:to, type:address, order:1, indexed:false, value:0xEb9e58d3d9462061EB5c6F81bf7e36C144f1d683, valueString:0xEb9e58d3d9462061EB5c6F81bf7e36C144f1d683}, {name:reqType, type:uint256, order:2, indexed:false, value:1, valueString:1}, {name:nonce, type:uint256, order:3, indexed:false, value:69, valueString:69}], signature=0x2CDFE5373B9E25B3FAD1CE5FE291149972B8ED04958BB099FAF4413E6A7B78855C356590E0E0262C901F89BC7CA2DA49BD5A2940640103F8F5301F2332E920B91B, signer=0xa59Be711181E16aE35a54848672627B204022fa6 ) => ( True, 0xa59Be711181E16aE35a54848672627B204022fa6 )
    • Prisma.hashMintReq( req=[{name:to, type:address, order:1, indexed:false, value:0xEb9e58d3d9462061EB5c6F81bf7e36C144f1d683, valueString:0xEb9e58d3d9462061EB5c6F81bf7e36C144f1d683}, {name:reqType, type:uint256, order:2, indexed:false, value:1, valueString:1}, {name:nonce, type:uint256, order:3, indexed:false, value:69, valueString:69}] ) => ( 1582D6DD52A0251618E215149C56B276EE4EDDD899C5F98AFA73A973153A9313 )
    • Null: 0x000...001.1582d6dd( )
      // SPDX-License-Identifier: AGPL-3.0-or-later
      ////// SPDX-License-Identifier-FLATTEN-SUPPRESS-WARNING: MIT
      // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)
      pragma solidity ^0.8.0;
      /**
       * @dev Standard math utilities missing in the Solidity language.
       */
      library Math {
          enum Rounding {
              Down, // Toward negative infinity
              Up, // Toward infinity
              Zero // Toward zero
          }
          /**
           * @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 Returns the average of two numbers. The result is rounded towards
           * zero.
           */
          function average(uint256 a, uint256 b) internal pure returns (uint256) {
              // (a + b) / 2 can overflow.
              return (a & b) + (a ^ b) / 2;
          }
          /**
           * @dev Returns the ceiling of the division of two numbers.
           *
           * This differs from standard division with `/` in that it rounds up instead
           * of rounding down.
           */
          function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
              // (a + b - 1) / b can overflow on addition, so we distribute.
              return a == 0 ? 0 : (a - 1) / b + 1;
          }
          /**
           * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
           * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
           * with further edits by Uniswap Labs also under MIT license.
           */
          function mulDiv(
              uint256 x,
              uint256 y,
              uint256 denominator
          ) internal pure returns (uint256 result) {
              unchecked {
                  // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
                  // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
                  // variables such that product = prod1 * 2^256 + prod0.
                  uint256 prod0; // Least significant 256 bits of the product
                  uint256 prod1; // Most significant 256 bits of the product
                  assembly {
                      let mm := mulmod(x, y, not(0))
                      prod0 := mul(x, y)
                      prod1 := sub(sub(mm, prod0), lt(mm, prod0))
                  }
                  // Handle non-overflow cases, 256 by 256 division.
                  if (prod1 == 0) {
                      return prod0 / denominator;
                  }
                  // Make sure the result is less than 2^256. Also prevents denominator == 0.
                  require(denominator > prod1);
                  ///////////////////////////////////////////////
                  // 512 by 256 division.
                  ///////////////////////////////////////////////
                  // Make division exact by subtracting the remainder from [prod1 prod0].
                  uint256 remainder;
                  assembly {
                      // Compute remainder using mulmod.
                      remainder := mulmod(x, y, denominator)
                      // Subtract 256 bit number from 512 bit number.
                      prod1 := sub(prod1, gt(remainder, prod0))
                      prod0 := sub(prod0, remainder)
                  }
                  // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
                  // See https://cs.stackexchange.com/q/138556/92363.
                  // Does not overflow because the denominator cannot be zero at this stage in the function.
                  uint256 twos = denominator & (~denominator + 1);
                  assembly {
                      // Divide denominator by twos.
                      denominator := div(denominator, twos)
                      // Divide [prod1 prod0] by twos.
                      prod0 := div(prod0, twos)
                      // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                      twos := add(div(sub(0, twos), twos), 1)
                  }
                  // Shift in bits from prod1 into prod0.
                  prod0 |= prod1 * twos;
                  // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
                  // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
                  // four bits. That is, denominator * inv = 1 mod 2^4.
                  uint256 inverse = (3 * denominator) ^ 2;
                  // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
                  // in modular arithmetic, doubling the correct bits in each step.
                  inverse *= 2 - denominator * inverse; // inverse mod 2^8
                  inverse *= 2 - denominator * inverse; // inverse mod 2^16
                  inverse *= 2 - denominator * inverse; // inverse mod 2^32
                  inverse *= 2 - denominator * inverse; // inverse mod 2^64
                  inverse *= 2 - denominator * inverse; // inverse mod 2^128
                  inverse *= 2 - denominator * inverse; // inverse mod 2^256
                  // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
                  // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
                  // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
                  // is no longer required.
                  result = prod0 * inverse;
                  return result;
              }
          }
          /**
           * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
           */
          function mulDiv(
              uint256 x,
              uint256 y,
              uint256 denominator,
              Rounding rounding
          ) internal pure returns (uint256) {
              uint256 result = mulDiv(x, y, denominator);
              if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
                  result += 1;
              }
              return result;
          }
          /**
           * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
           *
           * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
           */
          function sqrt(uint256 a) internal pure returns (uint256) {
              if (a == 0) {
                  return 0;
              }
              // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
              //
              // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
              // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
              //
              // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
              // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
              // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
              //
              // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
              uint256 result = 1 << (log2(a) >> 1);
              // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
              // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
              // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
              // into the expected uint128 result.
              unchecked {
                  result = (result + a / result) >> 1;
                  result = (result + a / result) >> 1;
                  result = (result + a / result) >> 1;
                  result = (result + a / result) >> 1;
                  result = (result + a / result) >> 1;
                  result = (result + a / result) >> 1;
                  result = (result + a / result) >> 1;
                  return min(result, a / result);
              }
          }
          /**
           * @notice Calculates sqrt(a), following the selected rounding direction.
           */
          function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
              unchecked {
                  uint256 result = sqrt(a);
                  return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
              }
          }
          /**
           * @dev Return the log in base 2, rounded down, of a positive value.
           * Returns 0 if given 0.
           */
          function log2(uint256 value) internal pure returns (uint256) {
              uint256 result = 0;
              unchecked {
                  if (value >> 128 > 0) {
                      value >>= 128;
                      result += 128;
                  }
                  if (value >> 64 > 0) {
                      value >>= 64;
                      result += 64;
                  }
                  if (value >> 32 > 0) {
                      value >>= 32;
                      result += 32;
                  }
                  if (value >> 16 > 0) {
                      value >>= 16;
                      result += 16;
                  }
                  if (value >> 8 > 0) {
                      value >>= 8;
                      result += 8;
                  }
                  if (value >> 4 > 0) {
                      value >>= 4;
                      result += 4;
                  }
                  if (value >> 2 > 0) {
                      value >>= 2;
                      result += 2;
                  }
                  if (value >> 1 > 0) {
                      result += 1;
                  }
              }
              return result;
          }
          /**
           * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
           * Returns 0 if given 0.
           */
          function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
              unchecked {
                  uint256 result = log2(value);
                  return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
              }
          }
          /**
           * @dev Return the log in base 10, rounded down, of a positive value.
           * Returns 0 if given 0.
           */
          function log10(uint256 value) internal pure returns (uint256) {
              uint256 result = 0;
              unchecked {
                  if (value >= 10**64) {
                      value /= 10**64;
                      result += 64;
                  }
                  if (value >= 10**32) {
                      value /= 10**32;
                      result += 32;
                  }
                  if (value >= 10**16) {
                      value /= 10**16;
                      result += 16;
                  }
                  if (value >= 10**8) {
                      value /= 10**8;
                      result += 8;
                  }
                  if (value >= 10**4) {
                      value /= 10**4;
                      result += 4;
                  }
                  if (value >= 10**2) {
                      value /= 10**2;
                      result += 2;
                  }
                  if (value >= 10**1) {
                      result += 1;
                  }
              }
              return result;
          }
          /**
           * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
           * Returns 0 if given 0.
           */
          function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
              unchecked {
                  uint256 result = log10(value);
                  return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);
              }
          }
          /**
           * @dev Return the log in base 256, rounded down, of a positive value.
           * Returns 0 if given 0.
           *
           * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
           */
          function log256(uint256 value) internal pure returns (uint256) {
              uint256 result = 0;
              unchecked {
                  if (value >> 128 > 0) {
                      value >>= 128;
                      result += 16;
                  }
                  if (value >> 64 > 0) {
                      value >>= 64;
                      result += 8;
                  }
                  if (value >> 32 > 0) {
                      value >>= 32;
                      result += 4;
                  }
                  if (value >> 16 > 0) {
                      value >>= 16;
                      result += 2;
                  }
                  if (value >> 8 > 0) {
                      result += 1;
                  }
              }
              return result;
          }
          /**
           * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
           * Returns 0 if given 0.
           */
          function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
              unchecked {
                  uint256 result = log256(value);
                  return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);
              }
          }
      }
      ////// SPDX-License-Identifier-FLATTEN-SUPPRESS-WARNING: MIT
      // OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)
      pragma solidity ^0.8.0;
      ////import "./math/Math.sol";
      /**
       * @dev String operations.
       */
      library Strings {
          bytes16 private constant _SYMBOLS = "0123456789abcdef";
          uint8 private constant _ADDRESS_LENGTH = 20;
          /**
           * @dev Converts a `uint256` to its ASCII `string` decimal representation.
           */
          function toString(uint256 value) internal pure returns (string memory) {
              unchecked {
                  uint256 length = Math.log10(value) + 1;
                  string memory buffer = new string(length);
                  uint256 ptr;
                  /// @solidity memory-safe-assembly
                  assembly {
                      ptr := add(buffer, add(32, length))
                  }
                  while (true) {
                      ptr--;
                      /// @solidity memory-safe-assembly
                      assembly {
                          mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
                      }
                      value /= 10;
                      if (value == 0) break;
                  }
                  return buffer;
              }
          }
          /**
           * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
           */
          function toHexString(uint256 value) internal pure returns (string memory) {
              unchecked {
                  return toHexString(value, Math.log256(value) + 1);
              }
          }
          /**
           * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
           */
          function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
              bytes memory buffer = new bytes(2 * length + 2);
              buffer[0] = "0";
              buffer[1] = "x";
              for (uint256 i = 2 * length + 1; i > 1; --i) {
                  buffer[i] = _SYMBOLS[value & 0xf];
                  value >>= 4;
              }
              require(value == 0, "Strings: hex length insufficient");
              return string(buffer);
          }
          /**
           * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
           */
          function toHexString(address addr) internal pure returns (string memory) {
              return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
          }
      }
      ////// SPDX-License-Identifier-FLATTEN-SUPPRESS-WARNING: MIT
      // OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/ECDSA.sol)
      pragma solidity ^0.8.0;
      ////import "../Strings.sol";
      /**
       * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
       *
       * These functions can be used to verify that a message was signed by the holder
       * of the private keys of a given address.
       */
      library ECDSA {
          enum RecoverError {
              NoError,
              InvalidSignature,
              InvalidSignatureLength,
              InvalidSignatureS,
              InvalidSignatureV // Deprecated in v4.8
          }
          function _throwError(RecoverError error) private pure {
              if (error == RecoverError.NoError) {
                  return; // no error: do nothing
              } else if (error == RecoverError.InvalidSignature) {
                  revert("ECDSA: invalid signature");
              } else if (error == RecoverError.InvalidSignatureLength) {
                  revert("ECDSA: invalid signature length");
              } else if (error == RecoverError.InvalidSignatureS) {
                  revert("ECDSA: invalid signature 's' value");
              }
          }
          /**
           * @dev Returns the address that signed a hashed message (`hash`) with
           * `signature` or error string. This address can then be used for verification purposes.
           *
           * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
           * this function rejects them by requiring the `s` value to be in the lower
           * half order, and the `v` value to be either 27 or 28.
           *
           * ////IMPORTANT: `hash` _must_ be the result of a hash operation for the
           * verification to be secure: it is possible to craft signatures that
           * recover to arbitrary addresses for non-hashed data. A safe way to ensure
           * this is by receiving a hash of the original message (which may otherwise
           * be too long), and then calling {toEthSignedMessageHash} on it.
           *
           * Documentation for signature generation:
           * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
           * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
           *
           * _Available since v4.3._
           */
          function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
              if (signature.length == 65) {
                  bytes32 r;
                  bytes32 s;
                  uint8 v;
                  // ecrecover takes the signature parameters, and the only way to get them
                  // currently is to use assembly.
                  /// @solidity memory-safe-assembly
                  assembly {
                      r := mload(add(signature, 0x20))
                      s := mload(add(signature, 0x40))
                      v := byte(0, mload(add(signature, 0x60)))
                  }
                  return tryRecover(hash, v, r, s);
              } else {
                  return (address(0), RecoverError.InvalidSignatureLength);
              }
          }
          /**
           * @dev Returns the address that signed a hashed message (`hash`) with
           * `signature`. This address can then be used for verification purposes.
           *
           * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
           * this function rejects them by requiring the `s` value to be in the lower
           * half order, and the `v` value to be either 27 or 28.
           *
           * ////IMPORTANT: `hash` _must_ be the result of a hash operation for the
           * verification to be secure: it is possible to craft signatures that
           * recover to arbitrary addresses for non-hashed data. A safe way to ensure
           * this is by receiving a hash of the original message (which may otherwise
           * be too long), and then calling {toEthSignedMessageHash} on it.
           */
          function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
              (address recovered, RecoverError error) = tryRecover(hash, signature);
              _throwError(error);
              return recovered;
          }
          /**
           * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
           *
           * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
           *
           * _Available since v4.3._
           */
          function tryRecover(
              bytes32 hash,
              bytes32 r,
              bytes32 vs
          ) internal pure returns (address, RecoverError) {
              bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
              uint8 v = uint8((uint256(vs) >> 255) + 27);
              return tryRecover(hash, v, r, s);
          }
          /**
           * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
           *
           * _Available since v4.2._
           */
          function recover(
              bytes32 hash,
              bytes32 r,
              bytes32 vs
          ) internal pure returns (address) {
              (address recovered, RecoverError error) = tryRecover(hash, r, vs);
              _throwError(error);
              return recovered;
          }
          /**
           * @dev Overload of {ECDSA-tryRecover} that receives the `v`,
           * `r` and `s` signature fields separately.
           *
           * _Available since v4.3._
           */
          function tryRecover(
              bytes32 hash,
              uint8 v,
              bytes32 r,
              bytes32 s
          ) internal pure returns (address, RecoverError) {
              // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
              // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
              // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
              // signatures from current libraries generate a unique signature with an s-value in the lower half order.
              //
              // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
              // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
              // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
              // these malleable signatures as well.
              if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
                  return (address(0), RecoverError.InvalidSignatureS);
              }
              // If the signature is valid (and not malleable), return the signer address
              address signer = ecrecover(hash, v, r, s);
              if (signer == address(0)) {
                  return (address(0), RecoverError.InvalidSignature);
              }
              return (signer, RecoverError.NoError);
          }
          /**
           * @dev Overload of {ECDSA-recover} that receives the `v`,
           * `r` and `s` signature fields separately.
           */
          function recover(
              bytes32 hash,
              uint8 v,
              bytes32 r,
              bytes32 s
          ) internal pure returns (address) {
              (address recovered, RecoverError error) = tryRecover(hash, v, r, s);
              _throwError(error);
              return recovered;
          }
          /**
           * @dev Returns an Ethereum Signed Message, created from a `hash`. This
           * produces hash corresponding to the one signed with the
           * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
           * JSON-RPC method as part of EIP-191.
           *
           * See {recover}.
           */
          function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
              // 32 is the length in bytes of hash,
              // enforced by the type signature above
              return keccak256(abi.encodePacked("\\x19Ethereum Signed Message:\
      32", hash));
          }
          /**
           * @dev Returns an Ethereum Signed Message, created from `s`. This
           * produces hash corresponding to the one signed with the
           * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
           * JSON-RPC method as part of EIP-191.
           *
           * See {recover}.
           */
          function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
              return keccak256(abi.encodePacked("\\x19Ethereum Signed Message:\
      ", Strings.toString(s.length), s));
          }
          /**
           * @dev Returns an Ethereum Signed Typed Data, created from a
           * `domainSeparator` and a `structHash`. This produces hash corresponding
           * to the one signed with the
           * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
           * JSON-RPC method as part of EIP-712.
           *
           * See {recover}.
           */
          function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {
              return keccak256(abi.encodePacked("\\x19\\x01", domainSeparator, structHash));
          }
      }
      ////// SPDX-License-Identifier-FLATTEN-SUPPRESS-WARNING: MIT
      // OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/EIP712.sol)
      pragma solidity ^0.8.0;
      ////import "./ECDSA.sol";
      /**
       * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.
       *
       * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible,
       * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding
       * they need in their contracts using a combination of `abi.encode` and `keccak256`.
       *
       * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding
       * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA
       * ({_hashTypedDataV4}).
       *
       * The implementation of the domain separator was designed to be as efficient as possible while still properly updating
       * the chain id to protect against replay attacks on an eventual fork of the chain.
       *
       * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method
       * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].
       *
       * _Available since v3.4._
       */
      abstract contract EIP712 {
          /* solhint-disable var-name-mixedcase */
          // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to
          // invalidate the cached domain separator if the chain id changes.
          bytes32 private immutable _CACHED_DOMAIN_SEPARATOR;
          uint256 private immutable _CACHED_CHAIN_ID;
          address private immutable _CACHED_THIS;
          bytes32 private immutable _HASHED_NAME;
          bytes32 private immutable _HASHED_VERSION;
          bytes32 private immutable _TYPE_HASH;
          /* solhint-enable var-name-mixedcase */
          /**
           * @dev Initializes the domain separator and parameter caches.
           *
           * The meaning of `name` and `version` is specified in
           * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:
           *
           * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.
           * - `version`: the current major version of the signing domain.
           *
           * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart
           * contract upgrade].
           */
          constructor(string memory name, string memory version) {
              bytes32 hashedName = keccak256(bytes(name));
              bytes32 hashedVersion = keccak256(bytes(version));
              bytes32 typeHash = keccak256(
                  "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
              );
              _HASHED_NAME = hashedName;
              _HASHED_VERSION = hashedVersion;
              _CACHED_CHAIN_ID = block.chainid;
              _CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(typeHash, hashedName, hashedVersion);
              _CACHED_THIS = address(this);
              _TYPE_HASH = typeHash;
          }
          /**
           * @dev Returns the domain separator for the current chain.
           */
          function _domainSeparatorV4() internal view returns (bytes32) {
              if (address(this) == _CACHED_THIS && block.chainid == _CACHED_CHAIN_ID) {
                  return _CACHED_DOMAIN_SEPARATOR;
              } else {
                  return _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION);
              }
          }
          function _buildDomainSeparator(
              bytes32 typeHash,
              bytes32 nameHash,
              bytes32 versionHash
          ) private view returns (bytes32) {
              return keccak256(abi.encode(typeHash, nameHash, versionHash, block.chainid, address(this)));
          }
          /**
           * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this
           * function returns the hash of the fully encoded EIP712 message for this domain.
           *
           * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:
           *
           * ```solidity
           * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
           *     keccak256("Mail(address to,string contents)"),
           *     mailTo,
           *     keccak256(bytes(mailContents))
           * )));
           * address signer = ECDSA.recover(digest, signature);
           * ```
           */
          function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
              return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash);
          }
      }
      ////// SPDX-License-Identifier-FLATTEN-SUPPRESS-WARNING: MIT
      // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
      pragma solidity ^0.8.0;
      /**
       * @dev Interface of the ERC165 standard, as defined in the
       * https://eips.ethereum.org/EIPS/eip-165[EIP].
       *
       * Implementers can declare support of contract interfaces, which can then be
       * queried by others ({ERC165Checker}).
       *
       * For an implementation, see {ERC165}.
       */
      interface IERC165 {
          /**
           * @dev Returns true if this contract implements the interface defined by
           * `interfaceId`. See the corresponding
           * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
           * to learn more about how these ids are created.
           *
           * This function call must use less than 30 000 gas.
           */
          function supportsInterface(bytes4 interfaceId) external view returns (bool);
      }
      ////// SPDX-License-Identifier-FLATTEN-SUPPRESS-WARNING: MIT
      // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
      pragma solidity ^0.8.0;
      ////import "./IERC165.sol";
      /**
       * @dev Implementation of the {IERC165} interface.
       *
       * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
       * for the additional interface id that will be supported. For example:
       *
       * ```solidity
       * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
       *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
       * }
       * ```
       *
       * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
       */
      abstract contract ERC165 is IERC165 {
          /**
           * @dev See {IERC165-supportsInterface}.
           */
          function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
              return interfaceId == type(IERC165).interfaceId;
          }
      }
      ////// SPDX-License-Identifier-FLATTEN-SUPPRESS-WARNING: MIT
      // OpenZeppelin Contracts (last updated v4.6.0) (interfaces/IERC2981.sol)
      pragma solidity ^0.8.0;
      ////import "../utils/introspection/IERC165.sol";
      /**
       * @dev Interface for the NFT Royalty Standard.
       *
       * A standardized way to retrieve royalty payment information for non-fungible tokens (NFTs) to enable universal
       * support for royalty payments across all NFT marketplaces and ecosystem participants.
       *
       * _Available since v4.5._
       */
      interface IERC2981 is IERC165 {
          /**
           * @dev Returns how much royalty is owed and to whom, based on a sale price that may be denominated in any unit of
           * exchange. The royalty amount is denominated and should be paid in that same unit of exchange.
           */
          function royaltyInfo(uint256 tokenId, uint256 salePrice)
              external
              view
              returns (address receiver, uint256 royaltyAmount);
      }
      ////// SPDX-License-Identifier-FLATTEN-SUPPRESS-WARNING: MIT
      // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/IERC721.sol)
      pragma solidity ^0.8.0;
      ////import "../../utils/introspection/IERC165.sol";
      /**
       * @dev Required interface of an ERC721 compliant contract.
       */
      interface IERC721 is IERC165 {
          /**
           * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
           */
          event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
          /**
           * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
           */
          event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
          /**
           * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
           */
          event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
          /**
           * @dev Returns the number of tokens in ``owner``'s account.
           */
          function balanceOf(address owner) external view returns (uint256 balance);
          /**
           * @dev Returns the owner of the `tokenId` token.
           *
           * Requirements:
           *
           * - `tokenId` must exist.
           */
          function ownerOf(uint256 tokenId) external view returns (address owner);
          /**
           * @dev Safely transfers `tokenId` token from `from` to `to`.
           *
           * Requirements:
           *
           * - `from` cannot be the zero address.
           * - `to` cannot be the zero address.
           * - `tokenId` token must exist and be owned by `from`.
           * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
           * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
           *
           * Emits a {Transfer} event.
           */
          function safeTransferFrom(
              address from,
              address to,
              uint256 tokenId,
              bytes calldata data
          ) external;
          /**
           * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
           * are aware of the ERC721 protocol to prevent tokens from being forever locked.
           *
           * Requirements:
           *
           * - `from` cannot be the zero address.
           * - `to` cannot be the zero address.
           * - `tokenId` token must exist and be owned by `from`.
           * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.
           * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
           *
           * Emits a {Transfer} event.
           */
          function safeTransferFrom(
              address from,
              address to,
              uint256 tokenId
          ) external;
          /**
           * @dev Transfers `tokenId` token from `from` to `to`.
           *
           * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
           * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
           * understand this adds an external call which potentially creates a reentrancy vulnerability.
           *
           * Requirements:
           *
           * - `from` cannot be the zero address.
           * - `to` cannot be the zero address.
           * - `tokenId` token must be owned by `from`.
           * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
           *
           * Emits a {Transfer} event.
           */
          function transferFrom(
              address from,
              address to,
              uint256 tokenId
          ) external;
          /**
           * @dev Gives permission to `to` to transfer `tokenId` token to another account.
           * The approval is cleared when the token is transferred.
           *
           * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
           *
           * Requirements:
           *
           * - The caller must own the token or be an approved operator.
           * - `tokenId` must exist.
           *
           * Emits an {Approval} event.
           */
          function approve(address to, uint256 tokenId) external;
          /**
           * @dev Approve or remove `operator` as an operator for the caller.
           * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
           *
           * Requirements:
           *
           * - The `operator` cannot be the caller.
           *
           * Emits an {ApprovalForAll} event.
           */
          function setApprovalForAll(address operator, bool _approved) external;
          /**
           * @dev Returns the account approved for `tokenId` token.
           *
           * Requirements:
           *
           * - `tokenId` must exist.
           */
          function getApproved(uint256 tokenId) external view returns (address operator);
          /**
           * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
           *
           * See {setApprovalForAll}
           */
          function isApprovedForAll(address owner, address operator) external view returns (bool);
      }
      ////// SPDX-License-Identifier-FLATTEN-SUPPRESS-WARNING: MIT
      // OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
      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) {
              return msg.data;
          }
      }
      ////// SPDX-License-Identifier-FLATTEN-SUPPRESS-WARNING: MIT
      // OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)
      pragma solidity ^0.8.1;
      /**
       * @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
           * ====
           *
           * [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 functionCallWithValue(target, data, 0, "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");
              (bool success, bytes memory returndata) = target.call{value: value}(data);
              return verifyCallResultFromTarget(target, 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) {
              (bool success, bytes memory returndata) = target.staticcall(data);
              return verifyCallResultFromTarget(target, 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) {
              (bool success, bytes memory returndata) = target.delegatecall(data);
              return verifyCallResultFromTarget(target, success, returndata, errorMessage);
          }
          /**
           * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
           * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
           *
           * _Available since v4.8._
           */
          function verifyCallResultFromTarget(
              address target,
              bool success,
              bytes memory returndata,
              string memory errorMessage
          ) internal view returns (bytes memory) {
              if (success) {
                  if (returndata.length == 0) {
                      // only check isContract if the call was successful and the return data is empty
                      // otherwise we already know that it was a contract
                      require(isContract(target), "Address: call to non-contract");
                  }
                  return returndata;
              } else {
                  _revert(returndata, errorMessage);
              }
          }
          /**
           * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
           * revert reason or 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 {
                  _revert(returndata, errorMessage);
              }
          }
          function _revert(bytes memory returndata, string memory errorMessage) private pure {
              // 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);
              }
          }
      }
      ////// SPDX-License-Identifier-FLATTEN-SUPPRESS-WARNING: MIT
      // OpenZeppelin Contracts (last updated v4.5.0) (token/ERC721/extensions/IERC721Enumerable.sol)
      pragma solidity ^0.8.0;
      ////import "../IERC721.sol";
      /**
       * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
       * @dev See https://eips.ethereum.org/EIPS/eip-721
       */
      interface IERC721Enumerable is IERC721 {
          /**
           * @dev Returns the total amount of tokens stored by the contract.
           */
          function totalSupply() external view returns (uint256);
          /**
           * @dev Returns a token ID owned by `owner` at a given `index` of its token list.
           * Use along with {balanceOf} to enumerate all of ``owner``'s tokens.
           */
          function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256);
          /**
           * @dev Returns a token ID at a given `index` of all the tokens stored by the contract.
           * Use along with {totalSupply} to enumerate all tokens.
           */
          function tokenByIndex(uint256 index) external view returns (uint256);
      }
      ////// SPDX-License-Identifier-FLATTEN-SUPPRESS-WARNING: MIT
      // OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol)
      pragma solidity ^0.8.0;
      ////import "../IERC721.sol";
      /**
       * @title ERC-721 Non-Fungible Token Standard, optional metadata extension
       * @dev See https://eips.ethereum.org/EIPS/eip-721
       */
      interface IERC721Metadata is IERC721 {
          /**
           * @dev Returns the token collection name.
           */
          function name() external view returns (string memory);
          /**
           * @dev Returns the token collection symbol.
           */
          function symbol() external view returns (string memory);
          /**
           * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
           */
          function tokenURI(uint256 tokenId) external view returns (string memory);
      }
      ////// SPDX-License-Identifier-FLATTEN-SUPPRESS-WARNING: MIT
      // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol)
      pragma solidity ^0.8.0;
      /**
       * @title ERC721 token receiver interface
       * @dev Interface for any contract that wants to support safeTransfers
       * from ERC721 asset contracts.
       */
      interface IERC721Receiver {
          /**
           * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
           * by `operator` from `from`, this function is called.
           *
           * It must return its Solidity selector to confirm the token transfer.
           * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
           *
           * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
           */
          function onERC721Received(
              address operator,
              address from,
              uint256 tokenId,
              bytes calldata data
          ) external returns (bytes4);
      }
      ////// SPDX-License-Identifier-FLATTEN-SUPPRESS-WARNING: MIT
      pragma solidity ^0.8.9;
      library Errors {
          error AtMostTwoToken();
          error NotOpenYet();
          error NotAllowToUseSigTwice();
          error WrongPayment();
          error NotFromEOA();
          error InvalidRequestSig();
          error MaxSupply();
          error WhitelistExpired();
          error SetAuthorAgain();
          error UnableToMint();
      }
      ////// SPDX-License-Identifier-FLATTEN-SUPPRESS-WARNING: MIT
      // @author Webx.cool
      pragma solidity ^0.8.0;
      ////import "@openzeppelin/contracts/utils/cryptography/EIP712.sol";
      ////import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
      abstract contract SigBase is EIP712{
          bytes32 private constant MINT_REQ_TYPEHASH = keccak256(
              bytes("MintReq(address to,uint256 reqType,uint256 nonce)")
          );
          address public verifySigner;
          struct MintReq{
              address to;
              uint256 reqType;
              uint256 nonce;
          }
          function setVerifySigner(address _signer) public virtual;
          function hashMintReq(MintReq memory req) external view returns (bytes32){
              return _hashTypedDataV4(keccak256(abi.encode(
                  MINT_REQ_TYPEHASH,
                  req.to,
                  req.reqType,
                  req.nonce
              )));
          }
          function getDomainSeparator()external view returns(bytes32){
              return _domainSeparatorV4();
          }
          function verifyMintReq(MintReq memory mintReq, bytes memory signature, address signer) external view returns(bool, address)  {
              bytes32 digest = this.hashMintReq(mintReq);
              address recoved = ECDSA.recover(digest, signature);
              return (signer == recoved, recoved);
          }
      }
      ////// SPDX-License-Identifier-FLATTEN-SUPPRESS-WARNING: MIT
      pragma solidity ^0.8.10;
      ////import "@openzeppelin/contracts/interfaces/IERC2981.sol";
      ////import "@openzeppelin/contracts/utils/introspection/ERC165.sol";
      abstract contract LoyaltySupport is IERC2981, ERC165 {
          bytes4 internal constant INTERFACE_ID_ERC2981 = 0x2a55205a;
          uint16 internal constant BASIS_POINTS = 10000;
          uint256 public royaltyBasisPoints;
          /**
           * @inheritdoc IERC2981
           */
          function royaltyInfo(uint256 _tokenId, uint256 _salePrice) public view virtual override returns (address, uint256);
          /**
           * @dev See {IERC165-supportsInterface}.
           */
          function supportsInterface(bytes4 interfaceId) public view virtual override (ERC165, IERC165) returns (bool){
              return interfaceId == type(IERC2981).interfaceId || super.supportsInterface(interfaceId);
          }
      }
      ////// SPDX-License-Identifier-FLATTEN-SUPPRESS-WARNING: MIT
      pragma solidity ^0.8.0;
      ////import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
      ////import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
      ////import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol";
      ////import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol";
      ////import "@openzeppelin/contracts/utils/Address.sol";
      ////import "@openzeppelin/contracts/utils/Context.sol";
      ////import "@openzeppelin/contracts/utils/Strings.sol";
      ////import "@openzeppelin/contracts/utils/introspection/ERC165.sol";
      /**
       * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including
       * the Metadata and Enumerable extension. Built to optimize for lower gas during batch mints.
       *
       * Assumes serials are sequentially minted starting at 0 (e.g. 0, 1, 2, 3..).
       *
       * Assumes the number of issuable tokens (collection size) is capped and fits in a uint128.
       *
       * Does not support burning tokens to address(0).
       */
      contract ERC721A is
      Context,
      ERC165,
      IERC721,
      IERC721Metadata,
      IERC721Enumerable
      {
          using Address for address;
          using Strings for uint256;
          struct TokenOwnership {
              address addr;
              uint64 startTimestamp;
          }
          struct AddressData {
              uint128 balance;
              uint128 numberMinted;
          }
          uint256 immutable _SELL_SUPPLY;
          /// @dev set to 1 to avoid #0 token
          uint256 internal currentIndex = 1;
          uint256 internal sellingIndex;
          uint256 internal immutable collectionSize;
          uint256 internal immutable maxBatchSize;
          string internal _BASE_URI;
          // Token name
          string private _name;
          // Token symbol
          string private _symbol;
          // Mapping from token ID to ownership details
          // An empty struct value does not necessarily mean the token is unowned. See ownershipOf implementation for details.
          mapping(uint256 => TokenOwnership) private _ownerships;
          // Mapping owner address to address data
          mapping(address => AddressData) private _addressData;
          // Mapping from token ID to approved address
          mapping(uint256 => address) private _tokenApprovals;
          // Mapping from owner to operator approvals
          mapping(address => mapping(address => bool)) private _operatorApprovals;
          /**
           * @dev
         * `maxBatchSize` refers to how much a minter can mint at a time.
         * `collectionSize_` refers to how many tokens are in the collection.
         */
          constructor(
              string memory name_,
              string memory symbol_,
              string memory baseURI_,
              uint256 maxBatchSize_,
              uint256 collectionSize_,
              uint256 sellingIndex_
          ) {
              require(
                  collectionSize_ > 0,
                  "ERC721A: collection must have a nonzero supply"
              );
              require(maxBatchSize_ > 0, "ERC721A: max batch size must be nonzero");
              _name = name_;
              _symbol = symbol_;
              _BASE_URI = baseURI_;
              maxBatchSize = maxBatchSize_;
              collectionSize = collectionSize_;
              sellingIndex = sellingIndex_;
              _SELL_SUPPLY = sellingIndex_;
          }
          /**
           * @dev See {IERC721Enumerable-totalSupply}.
         */
          function totalSupply() public view override returns (uint256) {
              return collectionSize;
          }
          /**
           * @dev See {IERC721Enumerable-tokenByIndex}.
         */
          function tokenByIndex(uint256 index) public view override returns (uint256) {
              require(index < currentIndex, "ERC721A: global index out of bounds");
              return index;
          }
          /**
           * @dev See {IERC721Enumerable-tokenOfOwnerByIndex}.
         * This read function is O(collectionSizecollectionSize). If calling from a separate contract, be sure to test gas first.
         * It may also degrade with extremely large collection sizes (e.g >> 10000), test for your use case.
         */
          function tokenOfOwnerByIndex(address owner, uint256 index)
          public
          view
          override
          returns (uint256)
          {
              require(index < balanceOf(owner), "ERC721A: owner index out of bounds");
              uint256 tokenIdsIdx = 0;
              address currOwnershipAddr = address(0);
              for (uint256 i = 0; i < collectionSize; i++) {
                  TokenOwnership memory ownership = _ownerships[i];
                  if (ownership.addr != address(0)) {
                      currOwnershipAddr = ownership.addr;
                  }
                  if (currOwnershipAddr == owner) {
                      if (tokenIdsIdx == index) {
                          return i;
                      }
                      tokenIdsIdx++;
                  }
              }
              revert("ERC721A: unable to get token of owner by index");
          }
          /**
           * @dev See {IERC165-supportsInterface}.
         */
          function supportsInterface(bytes4 interfaceId)
          public
          view
          virtual
          override(ERC165, IERC165)
          returns (bool)
          {
              return
              interfaceId == type(IERC721).interfaceId ||
              interfaceId == type(IERC721Metadata).interfaceId ||
              interfaceId == type(IERC721Enumerable).interfaceId ||
              super.supportsInterface(interfaceId);
          }
          /**
           * @dev See {IERC721-balanceOf}.
         */
          function balanceOf(address owner) public view override returns (uint256) {
              require(owner != address(0), "ERC721A: balance query for the zero address");
              return uint256(_addressData[owner].balance);
          }
          function _numberMinted(address owner) internal view returns (uint256) {
              require(
                  owner != address(0),
                  "ERC721A: number minted query for the zero address"
              );
              return uint256(_addressData[owner].numberMinted);
          }
          function ownershipOf(uint256 tokenId)
          internal
          view
          returns (TokenOwnership memory)
          {
              require(_exists(tokenId), "ERC721A: owner query for nonexistent token");
              uint256 lowestTokenToCheck;
              if (tokenId >= maxBatchSize) {
                  lowestTokenToCheck = tokenId - maxBatchSize + 1;
              }
              for (uint256 curr = tokenId; curr >= lowestTokenToCheck; curr--) {
                  TokenOwnership memory ownership = _ownerships[curr];
                  if (ownership.addr != address(0)) {
                      return ownership;
                  }
              }
              revert("ERC721A: unable to determine the owner of token");
          }
          /**
           * @dev See {IERC721-ownerOf}.
         */
          function ownerOf(uint256 tokenId) public view override returns (address) {
              return ownershipOf(tokenId).addr;
          }
          /**
           * @dev See {IERC721Metadata-name}.
         */
          function name() public view virtual override returns (string memory) {
              return _name;
          }
          /**
           * @dev See {IERC721Metadata-symbol}.
         */
          function symbol() public view virtual override returns (string memory) {
              return _symbol;
          }
          /**
           * @dev See {IERC721Metadata-tokenURI}.
         */
          function tokenURI(uint256 tokenId)
          public
          view
          virtual
          override
          returns (string memory)
          {
              require(
                  _exists(tokenId),
                  "ERC721Metadata: URI query for nonexistent token"
              );
              string memory baseURI = _baseURI();
              return
              bytes(baseURI).length > 0
              ? string(abi.encodePacked(baseURI, tokenId.toString()))
              : "";
          }
          /**
           * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each
         * token will be the concatenation of the `baseURI` and the `tokenId`. Empty
         * by default, can be overriden in child contracts.
         */
          function _baseURI() internal view virtual returns (string memory) {
              return "";
          }
          /**
           * @dev See {IERC721-approve}.
         */
          function approve(address to, uint256 tokenId) public override {
              address owner = ERC721A.ownerOf(tokenId);
              require(to != owner, "ERC721A: approval to current owner");
              require(
                  _msgSender() == owner || isApprovedForAll(owner, _msgSender()),
                  "ERC721A: approve caller is not owner nor approved for all"
              );
              _approve(to, tokenId, owner);
          }
          /**
           * @dev See {IERC721-getApproved}.
         */
          function getApproved(uint256 tokenId) public view override returns (address) {
              require(_exists(tokenId), "ERC721A: approved query for nonexistent token");
              return _tokenApprovals[tokenId];
          }
          /**
           * @dev See {IERC721-setApprovalForAll}.
         */
          function setApprovalForAll(address operator, bool approved) public override {
              require(operator != _msgSender(), "ERC721A: approve to caller");
              _operatorApprovals[_msgSender()][operator] = approved;
              emit ApprovalForAll(_msgSender(), operator, approved);
          }
          /**
           * @dev See {IERC721-isApprovedForAll}.
         */
          function isApprovedForAll(address owner, address operator)
          public
          view
          virtual
          override
          returns (bool)
          {
              return _operatorApprovals[owner][operator];
          }
          /**
           * @dev See {IERC721-transferFrom}.
         */
          function transferFrom(
              address from,
              address to,
              uint256 tokenId
          ) public override {
              _transfer(from, to, tokenId);
          }
          /**
           * @dev See {IERC721-safeTransferFrom}.
         */
          function safeTransferFrom(
              address from,
              address to,
              uint256 tokenId
          ) public override {
              safeTransferFrom(from, to, tokenId, "");
          }
          /**
           * @dev See {IERC721-safeTransferFrom}.
         */
          function safeTransferFrom(
              address from,
              address to,
              uint256 tokenId,
              bytes memory _data
          ) public override {
              _transfer(from, to, tokenId);
              require(
                  _checkOnERC721Received(from, to, tokenId, _data),
                  "ERC721A: transfer to non ERC721Receiver implementer"
              );
          }
          /**
           * @dev Returns whether `tokenId` exists.
         *
         * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.
         *
         * Tokens start existing when they are minted (`_mint`),
         */
          function _exists(uint256 tokenId) internal view returns (bool) {
              return tokenId < currentIndex || ( tokenId <= sellingIndex && tokenId > _SELL_SUPPLY );
          }
          function _safeMint(address to, uint256 quantity) internal {
              _safeMint(to, quantity, "");
          }
          /**
           * @dev Mints `quantity` tokens and transfers them to `to`.
         *
         * Requirements:
         *
         * - there must be `quantity` tokens remaining unminted in the total collection.
         * - `to` cannot be the zero address.
         * - `quantity` cannot be larger than the max batch size.
         *
         * Emits a {Transfer} event.
         */
          function _safeMint(
              address to,
              uint256 quantity,
              bytes memory _data
          ) internal {
              uint256 startTokenId = currentIndex;
              require(to != address(0), "ERC721A: mint to the zero address");
              // We know if the first token in the batch doesn't exist, the other ones don't as well, because of serial ordering.
              require(!_exists(startTokenId), "ERC721A: token already minted");
              require(quantity <= maxBatchSize, "ERC721A: quantity to mint too high");
              _beforeTokenTransfers(address(0), to, startTokenId, quantity);
              AddressData memory addressData = _addressData[to];
              _addressData[to] = AddressData(
                  addressData.balance + uint128(quantity),
                  addressData.numberMinted + uint128(quantity)
              );
              _ownerships[startTokenId] = TokenOwnership(to, uint64(block.timestamp));
              uint256 updatedIndex = startTokenId;
              for (uint256 i = 0; i < quantity; i++) {
                  emit Transfer(address(0), to, updatedIndex);
                  require(
                      _checkOnERC721Received(address(0), to, updatedIndex, _data),
                      "ERC721A: transfer to non ERC721Receiver implementer"
                  );
                  updatedIndex++;
              }
              currentIndex = updatedIndex;
              _afterTokenTransfers(address(0), to, startTokenId, quantity);
          }
          function _payAndMint(address to) internal {
              uint256 tokenId = sellingIndex + 1;
              require(tokenId <= collectionSize, "ERC721A: max supply");
              require(to != address(0), "ERC721A: mint to the zero address");
              // We know if the first token in the batch doesn't exist, the other ones don't as well, because of serial ordering.
              require(!_exists(tokenId), "ERC721A: token already minted");
              sellingIndex++;
              _beforeTokenTransfers(address(0), to, tokenId, 1);
              AddressData memory addressData = _addressData[to];
              _addressData[to] = AddressData(
                  addressData.balance + uint128(1),
                  addressData.numberMinted + uint128(1)
              );
              _ownerships[tokenId] = TokenOwnership(to, uint64(block.timestamp));
              emit Transfer(address(0), to, tokenId);
              require(
                  _checkOnERC721Received(address(0), to, tokenId, "0x00"),
                  "ERC721A: transfer to non ERC721Receiver implementer"
              );
              _afterTokenTransfers(address(0), to, tokenId, 1);
          }
          /**
           * @dev Transfers `tokenId` from `from` to `to`.
         *
         * Requirements:
         *
         * - `to` cannot be the zero address.
         * - `tokenId` token must be owned by `from`.
         *
         * Emits a {Transfer} event.
         */
          function _transfer(
              address from,
              address to,
              uint256 tokenId
          ) private {
              TokenOwnership memory prevOwnership = ownershipOf(tokenId);
              bool isApprovedOrOwner = (_msgSender() == prevOwnership.addr ||
              getApproved(tokenId) == _msgSender() ||
              isApprovedForAll(prevOwnership.addr, _msgSender()));
              require(
                  isApprovedOrOwner,
                  "ERC721A: transfer caller is not owner nor approved"
              );
              require(
                  prevOwnership.addr == from,
                  "ERC721A: transfer from incorrect owner"
              );
              require(to != address(0), "ERC721A: transfer to the zero address");
              _beforeTokenTransfers(from, to, tokenId, 1);
              // Clear approvals from the previous owner
              _approve(address(0), tokenId, prevOwnership.addr);
              _addressData[from].balance -= 1;
              _addressData[to].balance += 1;
              _ownerships[tokenId] = TokenOwnership(to, uint64(block.timestamp));
              // If the ownership slot of tokenId+1 is not explicitly set, that means the transfer initiator owns it.
              // Set the slot of tokenId+1 explicitly in storage to maintain correctness for ownerOf(tokenId+1) calls.
              uint256 nextTokenId = tokenId + 1;
              if (_ownerships[nextTokenId].addr == address(0)) {
                  if (_exists(nextTokenId)) {
                      _ownerships[nextTokenId] = TokenOwnership(
                          prevOwnership.addr,
                          prevOwnership.startTimestamp
                      );
                  }
              }
              emit Transfer(from, to, tokenId);
              _afterTokenTransfers(from, to, tokenId, 1);
          }
          /**
           * @dev Approve `to` to operate on `tokenId`
         *
         * Emits a {Approval} event.
         */
          function _approve(
              address to,
              uint256 tokenId,
              address owner
          ) private {
              _tokenApprovals[tokenId] = to;
              emit Approval(owner, to, tokenId);
          }
          uint256 public nextOwnerToExplicitlySet = 0;
          /**
           * @dev Explicitly set `owners` to eliminate loops in future calls of ownerOf().
         */
          function _setOwnersExplicit(uint256 quantity) internal {
              uint256 oldNextOwnerToSet = nextOwnerToExplicitlySet;
              require(quantity > 0, "quantity must be nonzero");
              uint256 endIndex = oldNextOwnerToSet + quantity - 1;
              if (endIndex > collectionSize - 1) {
                  endIndex = collectionSize - 1;
              }
              // We know if the last one in the group exists, all in the group exist, due to serial ordering.
              require(_exists(endIndex), "not enough minted yet for this cleanup");
              for (uint256 i = oldNextOwnerToSet; i <= endIndex; i++) {
                  if (_ownerships[i].addr == address(0)) {
                      TokenOwnership memory ownership = ownershipOf(i);
                      _ownerships[i] = TokenOwnership(
                          ownership.addr,
                          ownership.startTimestamp
                      );
                  }
              }
              nextOwnerToExplicitlySet = endIndex + 1;
          }
          /**
           * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.
         * The call is not executed if the target address is not a contract.
         *
         * @param from address representing the previous owner of the given token ID
         * @param to target address that will receive the tokens
         * @param tokenId uint256 ID of the token to be transferred
         * @param _data bytes optional data to send along with the call
         * @return bool whether the call correctly returned the expected magic value
         */
          function _checkOnERC721Received(
              address from,
              address to,
              uint256 tokenId,
              bytes memory _data
          ) private returns (bool) {
              if (to.isContract()) {
                  try
                  IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data)
                  returns (bytes4 retval) {
                      return retval == IERC721Receiver(to).onERC721Received.selector;
                  } catch (bytes memory reason) {
                      if (reason.length == 0) {
                          revert("ERC721A: transfer to non ERC721Receiver implementer");
                      } else {
                          assembly {
                              revert(add(32, reason), mload(reason))
                          }
                      }
                  }
              } else {
                  return true;
              }
          }
          /**
           * @dev Hook that is called before a set of serially-ordered token ids are about to be transferred. This includes minting.
         *
         * startTokenId - the first token id to be transferred
         * quantity - the amount to be transferred
         *
         * Calling conditions:
         *
         * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be
         * transferred to `to`.
         * - When `from` is zero, `tokenId` will be minted for `to`.
         */
          function _beforeTokenTransfers(
              address from,
              address to,
              uint256 startTokenId,
              uint256 quantity
          ) internal virtual {}
          /**
           * @dev Hook that is called after a set of serially-ordered token ids have been transferred. This includes
         * minting.
         *
         * startTokenId - the first token id to be transferred
         * quantity - the amount to be transferred
         *
         * Calling conditions:
         *
         * - when `from` and `to` are both non-zero.
         * - `from` and `to` are never both zero.
         */
          function _afterTokenTransfers(
              address from,
              address to,
              uint256 startTokenId,
              uint256 quantity
          ) internal virtual {}
      }
      ////// SPDX-License-Identifier-FLATTEN-SUPPRESS-WARNING: MIT
      // OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
      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() {
              _transferOwnership(_msgSender());
          }
          /**
           * @dev Throws if called by any account other than the owner.
           */
          modifier onlyOwner() {
              _checkOwner();
              _;
          }
          /**
           * @dev Returns the address of the current owner.
           */
          function owner() public view virtual returns (address) {
              return _owner;
          }
          /**
           * @dev Throws if the sender is not the owner.
           */
          function _checkOwner() internal view 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);
          }
      }
      ////// SPDX-License-Identifier-FLATTEN-SUPPRESS-WARNING: MIT
      pragma solidity ^0.8.9;
      ////import "@openzeppelin/contracts/access/Ownable.sol";
      ////import "@openzeppelin/contracts/utils/Strings.sol";
      ////import "./azuki/ERC721A.sol";
      ////import "./LoyaltySupport.sol";
      ////import "./SigBase.sol";
      ////import "./lib/Errors.sol";
      contract Prisma is Ownable, ERC721A, LoyaltySupport, SigBase {
          using Strings for uint256;
          string public constant version = "1.0";
          uint256 public constant MAX_SUPPLY  = 10000;
          uint256 public constant COMMUNITY_SUPPLY = 6400;
          uint256 public constant TEAM_SUPPLY = 600;
          uint256 public constant SELL_SUPPLY = MAX_SUPPLY - COMMUNITY_SUPPLY - TEAM_SUPPLY;
          uint256 constant ONE_TIME = 1;
          uint256 constant USER = 0;
          uint256 constant COMMUNITY = 1;
          uint256 public price;
          bool public isOpen;
          address payable public feeTaker;
          /// @notice checkMint[address(0)] as counter of public sell supply
          ///         checkMint[address(1)] as counter of vip supply
          mapping(address => uint256) private checkMint;
          mapping(bytes => bool) public validSig;
          /// @dev setting special author of target tokenId
          mapping(uint256 => address) public specialAuthor;
          constructor (
              uint256 _price,
              address _signer,
              address _feeTaker,
              string memory _baseURI,
              uint256 _points,
              address _team
          )
          EIP712("Prisma", version)
          ERC721A("Prisma", "PRI", _baseURI, TEAM_SUPPLY, 10000, COMMUNITY_SUPPLY + TEAM_SUPPLY)
          {
              require(_feeTaker != address(0), "err addr");
              require(_signer != address(0), "err addr");
              checkMint[address(0)] = SELL_SUPPLY;
              checkMint[address(1)] = COMMUNITY_SUPPLY;
              checkMint[address(2)] = TEAM_SUPPLY;
              price = _price;
              verifySigner = _signer;
              feeTaker = payable(_feeTaker);
              royaltyBasisPoints = _points;
              _BASE_URI= _baseURI;
              _safeMint(_team, TEAM_SUPPLY);
          }
          event LogPayAndMint(address indexed buyer, uint256 indexed tokenId, uint256 indexed price);
          event LogVipMint(address indexed receiver, uint256 indexed tokenId);
          modifier sigCheck(MintReq calldata _req, bytes calldata sig){
              if(validSig[sig]) revert Errors.NotAllowToUseSigTwice();
              validSig[sig] = true;
              (bool ok, ) = this.verifyMintReq(_req, sig, verifySigner);
              if(!ok) revert Errors.InvalidRequestSig();
              _;
          }
          modifier onlyEOA(){
              if (msg.sender != tx.origin) revert Errors.NotFromEOA();
              _;
          }
          function mint(MintReq calldata _req, bytes calldata _sig) payable external
          onlyEOA
          sigCheck(_req, _sig)
          {
              _notExceedSupply(_req.reqType);
              if(_req.reqType == COMMUNITY) {
                  _onlyMintOnce(_req.to);
                  _mint(_req.to);
                  return;
              }
              revert Errors.UnableToMint();
          }
          function payAndMint() payable external
          onlyEOA
          {
              _notExceedSupply(USER);
              _processPayment(sellingIndex + 1);
              _payAndMint(msg.sender);
              emit LogPayAndMint(msg.sender, sellingIndex, price);
          }
          function setPrice(uint256 _price) public onlyOwner {
              price = _price;
          }
          function setVerifySigner(address _signer) public override onlyOwner {
              verifySigner = _signer;
          }
          function setOpen(bool _value) public onlyOwner{
              isOpen = _value;
          }
          function setBaseUri(string memory _uri) public onlyOwner{
              _BASE_URI = _uri;
          }
          /// @dev Author can only be set once
          function setAuthor(uint256 _tokenId, address _author) public onlyOwner {
              if(specialAuthor[_tokenId] != address(0)) {
                  revert Errors.SetAuthorAgain();
              }
              specialAuthor[_tokenId] = _author;
          }
          function royaltyInfo(uint256 _tokenId, uint256 _salePrice) public view override returns (address, uint256) {
              address author = specialAuthor[_tokenId];
              if( author == address(0)) {
                  author = feeTaker;
              }
              uint256 royaltyAmount = _salePrice * royaltyBasisPoints / BASIS_POINTS;
              return (author, royaltyAmount);
          }
          /**
           * @dev See {IERC721Metadata-tokenURI}.
         */
          function tokenURI(uint256 tokenId)
          public
          view
          virtual
          override
          returns (string memory)
          {
              require(
                  _exists(tokenId),
                  "ERC721Metadata: URI query for nonexistent token"
              );
              string memory baseURI = _BASE_URI;
              return
              bytes(baseURI).length > 0
              ? string(abi.encodePacked(baseURI, tokenId.toString()))
              : "";
          }
          function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721A, LoyaltySupport) returns (bool) {
              return super.supportsInterface(interfaceId);
          }
          /// @notice white list user can mint once and got two token
          function _onlyMintOnce(address _to) internal {
              if(checkMint[_to] < ONE_TIME) {
                  checkMint[_to] = checkMint[_to] + 1;
              } else revert Errors.AtMostTwoToken();
          }
          function alreadyMinted(address _to) external view returns(bool) {
              return checkMint[_to] == ONE_TIME;
          }
          function _notExceedSupply(uint256 _tag) internal{
              address addr = address(uint160(uint256(_tag)));
              if (checkMint[address(addr)] == 0) revert Errors.MaxSupply();
              /// @dev sub 1 for one mint when payAndMint
              if(_tag == 0) {
                  checkMint[address(addr)] = checkMint[address(addr)] - 1;
                  return;
              }
              /// @dev sub 2 for one mint with 2 tokens
              checkMint[address(addr)] = checkMint[address(addr)] - 2;
          }
          function _processPayment(uint256 _tokenId) internal {
              if(!isOpen) revert Errors.NotOpenYet();
              if(msg.value != price) revert Errors.WrongPayment();
              address _feeTaker = specialAuthor[_tokenId];
              if( _feeTaker == address(0)) {
                  _feeTaker = feeTaker;
              }
              payable(_feeTaker).transfer(msg.value);
          }
          function _mint(address to) internal {
              uint256 tokenId = currentIndex;
              if( tokenId > MAX_SUPPLY) {
                  revert Errors.MaxSupply();
              }
              _safeMint(to, 2);
              emit LogVipMint(to, tokenId);
              emit LogVipMint(to, tokenId + 1);
          }
      }