// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.2) (utils/Base64.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides a set of functions to operate with Base64 strings.
*/
library Base64 {
/**
* @dev Base64 Encoding/Decoding Table
*/
string internal constant _TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
/**
* @dev Converts a `bytes` to its Bytes64 `string` representation.
*/
function encode(bytes memory data) internal pure returns (string memory) {
/**
* Inspired by Brecht Devos (Brechtpd) implementation - MIT licence
* https://github.com/Brechtpd/base64/blob/e78d9fd951e7b0977ddca77d92dc85183770daf4/base64.sol
*/
if (data.length == 0) return "";
// Loads the table into memory
string memory table = _TABLE;
// Encoding takes 3 bytes chunks of binary data from `bytes` data parameter
// and split into 4 numbers of 6 bits.
// The final Base64 length should be `bytes` data length multiplied by 4/3 rounded up
// - `data.length + 2` -> Round up
// - `/ 3` -> Number of 3-bytes chunks
// - `4 *` -> 4 characters for each chunk
string memory result = new string(4 * ((data.length + 2) / 3));
/// @solidity memory-safe-assembly
assembly {
// Prepare the lookup table (skip the first "length" byte)
let tablePtr := add(table, 1)
// Prepare result pointer, jump over length
let resultPtr := add(result, 0x20)
let dataPtr := data
let endPtr := add(data, mload(data))
// In some cases, the last iteration will read bytes after the end of the data. We cache the value, and
// set it to zero to make sure no dirty bytes are read in that section.
let afterPtr := add(endPtr, 0x20)
let afterCache := mload(afterPtr)
mstore(afterPtr, 0x00)
// Run over the input, 3 bytes at a time
for {
} lt(dataPtr, endPtr) {
} {
// Advance 3 bytes
dataPtr := add(dataPtr, 3)
let input := mload(dataPtr)
// To write each character, shift the 3 byte (24 bits) chunk
// 4 times in blocks of 6 bits for each character (18, 12, 6, 0)
// and apply logical AND with 0x3F to bitmask the least significant 6 bits.
// Use this as an index into the lookup table, mload an entire word
// so the desired character is in the least significant byte, and
// mstore8 this least significant byte into the result and continue.
mstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F))))
resultPtr := add(resultPtr, 1) // Advance
mstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F))))
resultPtr := add(resultPtr, 1) // Advance
mstore8(resultPtr, mload(add(tablePtr, and(shr(6, input), 0x3F))))
resultPtr := add(resultPtr, 1) // Advance
mstore8(resultPtr, mload(add(tablePtr, and(input, 0x3F))))
resultPtr := add(resultPtr, 1) // Advance
}
// Reset the value that was cached
mstore(afterPtr, afterCache)
// When data `bytes` is not exactly 3 bytes long
// it is padded with `=` characters at the end
switch mod(mload(data), 3)
case 1 {
mstore8(sub(resultPtr, 1), 0x3d)
mstore8(sub(resultPtr, 2), 0x3d)
}
case 2 {
mstore8(sub(resultPtr, 1), 0x3d)
}
}
return result;
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @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;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "./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);
* }
* ```
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/common/ERC2981.sol)
pragma solidity ^0.8.20;
import {IERC2981} from "../../interfaces/IERC2981.sol";
import {IERC165, ERC165} from "../../utils/introspection/ERC165.sol";
/**
* @dev Implementation of the NFT Royalty Standard, a standardized way to retrieve royalty payment information.
*
* Royalty information can be specified globally for all token ids via {_setDefaultRoyalty}, and/or individually for
* specific token ids via {_setTokenRoyalty}. The latter takes precedence over the first.
*
* Royalty is specified as a fraction of sale price. {_feeDenominator} is overridable but defaults to 10000, meaning the
* fee is specified in basis points by default.
*
* IMPORTANT: ERC-2981 only specifies a way to signal royalty information and does not enforce its payment. See
* https://eips.ethereum.org/EIPS/eip-2981#optional-royalty-payments[Rationale] in the EIP. Marketplaces are expected to
* voluntarily pay royalties together with sales, but note that this standard is not yet widely supported.
*/
abstract contract ERC2981 is IERC2981, ERC165 {
struct RoyaltyInfo {
address receiver;
uint96 royaltyFraction;
}
RoyaltyInfo private _defaultRoyaltyInfo;
mapping(uint256 tokenId => RoyaltyInfo) private _tokenRoyaltyInfo;
/**
* @dev The default royalty set is invalid (eg. (numerator / denominator) >= 1).
*/
error ERC2981InvalidDefaultRoyalty(uint256 numerator, uint256 denominator);
/**
* @dev The default royalty receiver is invalid.
*/
error ERC2981InvalidDefaultRoyaltyReceiver(address receiver);
/**
* @dev The royalty set for an specific `tokenId` is invalid (eg. (numerator / denominator) >= 1).
*/
error ERC2981InvalidTokenRoyalty(uint256 tokenId, uint256 numerator, uint256 denominator);
/**
* @dev The royalty receiver for `tokenId` is invalid.
*/
error ERC2981InvalidTokenRoyaltyReceiver(uint256 tokenId, address receiver);
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC165) returns (bool) {
return interfaceId == type(IERC2981).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @inheritdoc IERC2981
*/
function royaltyInfo(uint256 tokenId, uint256 salePrice) public view virtual returns (address, uint256) {
RoyaltyInfo memory royalty = _tokenRoyaltyInfo[tokenId];
if (royalty.receiver == address(0)) {
royalty = _defaultRoyaltyInfo;
}
uint256 royaltyAmount = (salePrice * royalty.royaltyFraction) / _feeDenominator();
return (royalty.receiver, royaltyAmount);
}
/**
* @dev The denominator with which to interpret the fee set in {_setTokenRoyalty} and {_setDefaultRoyalty} as a
* fraction of the sale price. Defaults to 10000 so fees are expressed in basis points, but may be customized by an
* override.
*/
function _feeDenominator() internal pure virtual returns (uint96) {
return 10000;
}
/**
* @dev Sets the royalty information that all ids in this contract will default to.
*
* Requirements:
*
* - `receiver` cannot be the zero address.
* - `feeNumerator` cannot be greater than the fee denominator.
*/
function _setDefaultRoyalty(address receiver, uint96 feeNumerator) internal virtual {
uint256 denominator = _feeDenominator();
if (feeNumerator > denominator) {
// Royalty fee will exceed the sale price
revert ERC2981InvalidDefaultRoyalty(feeNumerator, denominator);
}
if (receiver == address(0)) {
revert ERC2981InvalidDefaultRoyaltyReceiver(address(0));
}
_defaultRoyaltyInfo = RoyaltyInfo(receiver, feeNumerator);
}
/**
* @dev Removes default royalty information.
*/
function _deleteDefaultRoyalty() internal virtual {
delete _defaultRoyaltyInfo;
}
/**
* @dev Sets the royalty information for a specific token id, overriding the global default.
*
* Requirements:
*
* - `receiver` cannot be the zero address.
* - `feeNumerator` cannot be greater than the fee denominator.
*/
function _setTokenRoyalty(uint256 tokenId, address receiver, uint96 feeNumerator) internal virtual {
uint256 denominator = _feeDenominator();
if (feeNumerator > denominator) {
// Royalty fee will exceed the sale price
revert ERC2981InvalidTokenRoyalty(tokenId, feeNumerator, denominator);
}
if (receiver == address(0)) {
revert ERC2981InvalidTokenRoyaltyReceiver(tokenId, address(0));
}
_tokenRoyaltyInfo[tokenId] = RoyaltyInfo(receiver, feeNumerator);
}
/**
* @dev Resets royalty information for the token id back to the global default.
*/
function _resetTokenRoyalty(uint256 tokenId) internal virtual {
delete _tokenRoyaltyInfo[tokenId];
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/ERC721.sol)
pragma solidity ^0.8.20;
import {IERC721} from "./IERC721.sol";
import {IERC721Receiver} from "./IERC721Receiver.sol";
import {IERC721Metadata} from "./extensions/IERC721Metadata.sol";
import {Context} from "../../utils/Context.sol";
import {Strings} from "../../utils/Strings.sol";
import {IERC165, ERC165} from "../../utils/introspection/ERC165.sol";
import {IERC721Errors} from "../../interfaces/draft-IERC6093.sol";
/**
* @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including
* the Metadata extension, but not including the Enumerable extension, which is available separately as
* {ERC721Enumerable}.
*/
abstract contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Errors {
using Strings for uint256;
// Token name
string private _name;
// Token symbol
string private _symbol;
mapping(uint256 tokenId => address) private _owners;
mapping(address owner => uint256) private _balances;
mapping(uint256 tokenId => address) private _tokenApprovals;
mapping(address owner => mapping(address operator => bool)) private _operatorApprovals;
/**
* @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.
*/
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
/**
* @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 ||
super.supportsInterface(interfaceId);
}
/**
* @dev See {IERC721-balanceOf}.
*/
function balanceOf(address owner) public view virtual returns (uint256) {
if (owner == address(0)) {
revert ERC721InvalidOwner(address(0));
}
return _balances[owner];
}
/**
* @dev See {IERC721-ownerOf}.
*/
function ownerOf(uint256 tokenId) public view virtual returns (address) {
return _requireOwned(tokenId);
}
/**
* @dev See {IERC721Metadata-name}.
*/
function name() public view virtual returns (string memory) {
return _name;
}
/**
* @dev See {IERC721Metadata-symbol}.
*/
function symbol() public view virtual returns (string memory) {
return _symbol;
}
/**
* @dev See {IERC721Metadata-tokenURI}.
*/
function tokenURI(uint256 tokenId) public view virtual returns (string memory) {
_requireOwned(tokenId);
string memory baseURI = _baseURI();
return bytes(baseURI).length > 0 ? string.concat(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 overridden in child contracts.
*/
function _baseURI() internal view virtual returns (string memory) {
return "";
}
/**
* @dev See {IERC721-approve}.
*/
function approve(address to, uint256 tokenId) public virtual {
_approve(to, tokenId, _msgSender());
}
/**
* @dev See {IERC721-getApproved}.
*/
function getApproved(uint256 tokenId) public view virtual returns (address) {
_requireOwned(tokenId);
return _getApproved(tokenId);
}
/**
* @dev See {IERC721-setApprovalForAll}.
*/
function setApprovalForAll(address operator, bool approved) public virtual {
_setApprovalForAll(_msgSender(), operator, approved);
}
/**
* @dev See {IERC721-isApprovedForAll}.
*/
function isApprovedForAll(address owner, address operator) public view virtual returns (bool) {
return _operatorApprovals[owner][operator];
}
/**
* @dev See {IERC721-transferFrom}.
*/
function transferFrom(address from, address to, uint256 tokenId) public virtual {
if (to == address(0)) {
revert ERC721InvalidReceiver(address(0));
}
// Setting an "auth" arguments enables the `_isAuthorized` check which verifies that the token exists
// (from != 0). Therefore, it is not needed to verify that the return value is not 0 here.
address previousOwner = _update(to, tokenId, _msgSender());
if (previousOwner != from) {
revert ERC721IncorrectOwner(from, tokenId, previousOwner);
}
}
/**
* @dev See {IERC721-safeTransferFrom}.
*/
function safeTransferFrom(address from, address to, uint256 tokenId) public {
safeTransferFrom(from, to, tokenId, "");
}
/**
* @dev See {IERC721-safeTransferFrom}.
*/
function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public virtual {
transferFrom(from, to, tokenId);
_checkOnERC721Received(from, to, tokenId, data);
}
/**
* @dev Returns the owner of the `tokenId`. Does NOT revert if token doesn't exist
*
* IMPORTANT: Any overrides to this function that add ownership of tokens not tracked by the
* core ERC721 logic MUST be matched with the use of {_increaseBalance} to keep balances
* consistent with ownership. The invariant to preserve is that for any address `a` the value returned by
* `balanceOf(a)` must be equal to the number of tokens such that `_ownerOf(tokenId)` is `a`.
*/
function _ownerOf(uint256 tokenId) internal view virtual returns (address) {
return _owners[tokenId];
}
/**
* @dev Returns the approved address for `tokenId`. Returns 0 if `tokenId` is not minted.
*/
function _getApproved(uint256 tokenId) internal view virtual returns (address) {
return _tokenApprovals[tokenId];
}
/**
* @dev Returns whether `spender` is allowed to manage `owner`'s tokens, or `tokenId` in
* particular (ignoring whether it is owned by `owner`).
*
* WARNING: This function assumes that `owner` is the actual owner of `tokenId` and does not verify this
* assumption.
*/
function _isAuthorized(address owner, address spender, uint256 tokenId) internal view virtual returns (bool) {
return
spender != address(0) &&
(owner == spender || isApprovedForAll(owner, spender) || _getApproved(tokenId) == spender);
}
/**
* @dev Checks if `spender` can operate on `tokenId`, assuming the provided `owner` is the actual owner.
* Reverts if `spender` does not have approval from the provided `owner` for the given token or for all its assets
* the `spender` for the specific `tokenId`.
*
* WARNING: This function assumes that `owner` is the actual owner of `tokenId` and does not verify this
* assumption.
*/
function _checkAuthorized(address owner, address spender, uint256 tokenId) internal view virtual {
if (!_isAuthorized(owner, spender, tokenId)) {
if (owner == address(0)) {
revert ERC721NonexistentToken(tokenId);
} else {
revert ERC721InsufficientApproval(spender, tokenId);
}
}
}
/**
* @dev Unsafe write access to the balances, used by extensions that "mint" tokens using an {ownerOf} override.
*
* NOTE: the value is limited to type(uint128).max. This protect against _balance overflow. It is unrealistic that
* a uint256 would ever overflow from increments when these increments are bounded to uint128 values.
*
* WARNING: Increasing an account's balance using this function tends to be paired with an override of the
* {_ownerOf} function to resolve the ownership of the corresponding tokens so that balances and ownership
* remain consistent with one another.
*/
function _increaseBalance(address account, uint128 value) internal virtual {
unchecked {
_balances[account] += value;
}
}
/**
* @dev Transfers `tokenId` from its current owner to `to`, or alternatively mints (or burns) if the current owner
* (or `to`) is the zero address. Returns the owner of the `tokenId` before the update.
*
* The `auth` argument is optional. If the value passed is non 0, then this function will check that
* `auth` is either the owner of the token, or approved to operate on the token (by the owner).
*
* Emits a {Transfer} event.
*
* NOTE: If overriding this function in a way that tracks balances, see also {_increaseBalance}.
*/
function _update(address to, uint256 tokenId, address auth) internal virtual returns (address) {
address from = _ownerOf(tokenId);
// Perform (optional) operator check
if (auth != address(0)) {
_checkAuthorized(from, auth, tokenId);
}
// Execute the update
if (from != address(0)) {
// Clear approval. No need to re-authorize or emit the Approval event
_approve(address(0), tokenId, address(0), false);
unchecked {
_balances[from] -= 1;
}
}
if (to != address(0)) {
unchecked {
_balances[to] += 1;
}
}
_owners[tokenId] = to;
emit Transfer(from, to, tokenId);
return from;
}
/**
* @dev Mints `tokenId` and transfers it to `to`.
*
* WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible
*
* Requirements:
*
* - `tokenId` must not exist.
* - `to` cannot be the zero address.
*
* Emits a {Transfer} event.
*/
function _mint(address to, uint256 tokenId) internal {
if (to == address(0)) {
revert ERC721InvalidReceiver(address(0));
}
address previousOwner = _update(to, tokenId, address(0));
if (previousOwner != address(0)) {
revert ERC721InvalidSender(address(0));
}
}
/**
* @dev Mints `tokenId`, transfers it to `to` and checks for `to` acceptance.
*
* Requirements:
*
* - `tokenId` must not exist.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function _safeMint(address to, uint256 tokenId) internal {
_safeMint(to, tokenId, "");
}
/**
* @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is
* forwarded in {IERC721Receiver-onERC721Received} to contract recipients.
*/
function _safeMint(address to, uint256 tokenId, bytes memory data) internal virtual {
_mint(to, tokenId);
_checkOnERC721Received(address(0), to, tokenId, data);
}
/**
* @dev Destroys `tokenId`.
* The approval is cleared when the token is burned.
* This is an internal function that does not check if the sender is authorized to operate on the token.
*
* Requirements:
*
* - `tokenId` must exist.
*
* Emits a {Transfer} event.
*/
function _burn(uint256 tokenId) internal {
address previousOwner = _update(address(0), tokenId, address(0));
if (previousOwner == address(0)) {
revert ERC721NonexistentToken(tokenId);
}
}
/**
* @dev Transfers `tokenId` from `from` to `to`.
* As opposed to {transferFrom}, this imposes no restrictions on msg.sender.
*
* 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) internal {
if (to == address(0)) {
revert ERC721InvalidReceiver(address(0));
}
address previousOwner = _update(to, tokenId, address(0));
if (previousOwner == address(0)) {
revert ERC721NonexistentToken(tokenId);
} else if (previousOwner != from) {
revert ERC721IncorrectOwner(from, tokenId, previousOwner);
}
}
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking that contract recipients
* are aware of the ERC721 standard to prevent tokens from being forever locked.
*
* `data` is additional data, it has no specified format and it is sent in call to `to`.
*
* This internal function is like {safeTransferFrom} in the sense that it invokes
* {IERC721Receiver-onERC721Received} on the receiver, and can be used to e.g.
* implement alternative mechanisms to perform token transfer, such as signature-based.
*
* Requirements:
*
* - `tokenId` token must exist and be owned by `from`.
* - `to` cannot be the zero address.
* - `from` cannot be the zero address.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function _safeTransfer(address from, address to, uint256 tokenId) internal {
_safeTransfer(from, to, tokenId, "");
}
/**
* @dev Same as {xref-ERC721-_safeTransfer-address-address-uint256-}[`_safeTransfer`], with an additional `data` parameter which is
* forwarded in {IERC721Receiver-onERC721Received} to contract recipients.
*/
function _safeTransfer(address from, address to, uint256 tokenId, bytes memory data) internal virtual {
_transfer(from, to, tokenId);
_checkOnERC721Received(from, to, tokenId, data);
}
/**
* @dev Approve `to` to operate on `tokenId`
*
* The `auth` argument is optional. If the value passed is non 0, then this function will check that `auth` is
* either the owner of the token, or approved to operate on all tokens held by this owner.
*
* Emits an {Approval} event.
*
* Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.
*/
function _approve(address to, uint256 tokenId, address auth) internal {
_approve(to, tokenId, auth, true);
}
/**
* @dev Variant of `_approve` with an optional flag to enable or disable the {Approval} event. The event is not
* emitted in the context of transfers.
*/
function _approve(address to, uint256 tokenId, address auth, bool emitEvent) internal virtual {
// Avoid reading the owner unless necessary
if (emitEvent || auth != address(0)) {
address owner = _requireOwned(tokenId);
// We do not use _isAuthorized because single-token approvals should not be able to call approve
if (auth != address(0) && owner != auth && !isApprovedForAll(owner, auth)) {
revert ERC721InvalidApprover(auth);
}
if (emitEvent) {
emit Approval(owner, to, tokenId);
}
}
_tokenApprovals[tokenId] = to;
}
/**
* @dev Approve `operator` to operate on all of `owner` tokens
*
* Requirements:
* - operator can't be the address zero.
*
* Emits an {ApprovalForAll} event.
*/
function _setApprovalForAll(address owner, address operator, bool approved) internal virtual {
if (operator == address(0)) {
revert ERC721InvalidOperator(operator);
}
_operatorApprovals[owner][operator] = approved;
emit ApprovalForAll(owner, operator, approved);
}
/**
* @dev Reverts if the `tokenId` doesn't have a current owner (it hasn't been minted, or it has been burned).
* Returns the owner.
*
* Overrides to ownership logic should be done to {_ownerOf}.
*/
function _requireOwned(uint256 tokenId) internal view returns (address) {
address owner = _ownerOf(tokenId);
if (owner == address(0)) {
revert ERC721NonexistentToken(tokenId);
}
return owner;
}
/**
* @dev Private function to invoke {IERC721Receiver-onERC721Received} on a target address. This will revert if the
* recipient doesn't accept the token transfer. 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
*/
function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory data) private {
if (to.code.length > 0) {
try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, data) returns (bytes4 retval) {
if (retval != IERC721Receiver.onERC721Received.selector) {
revert ERC721InvalidReceiver(to);
}
} catch (bytes memory reason) {
if (reason.length == 0) {
revert ERC721InvalidReceiver(to);
} else {
/// @solidity memory-safe-assembly
assembly {
revert(add(32, reason), mload(reason))
}
}
}
}
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/ERC721Enumerable.sol)
pragma solidity ^0.8.20;
import {ERC721} from "../ERC721.sol";
import {IERC721Enumerable} from "./IERC721Enumerable.sol";
import {IERC165} from "../../../utils/introspection/ERC165.sol";
/**
* @dev This implements an optional extension of {ERC721} defined in the EIP that adds enumerability
* of all the token ids in the contract as well as all token ids owned by each account.
*
* CAUTION: `ERC721` extensions that implement custom `balanceOf` logic, such as `ERC721Consecutive`,
* interfere with enumerability and should not be used together with `ERC721Enumerable`.
*/
abstract contract ERC721Enumerable is ERC721, IERC721Enumerable {
mapping(address owner => mapping(uint256 index => uint256)) private _ownedTokens;
mapping(uint256 tokenId => uint256) private _ownedTokensIndex;
uint256[] private _allTokens;
mapping(uint256 tokenId => uint256) private _allTokensIndex;
/**
* @dev An `owner`'s token query was out of bounds for `index`.
*
* NOTE: The owner being `address(0)` indicates a global out of bounds index.
*/
error ERC721OutOfBoundsIndex(address owner, uint256 index);
/**
* @dev Batch mint is not allowed.
*/
error ERC721EnumerableForbiddenBatchMint();
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC721) returns (bool) {
return interfaceId == type(IERC721Enumerable).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev See {IERC721Enumerable-tokenOfOwnerByIndex}.
*/
function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual returns (uint256) {
if (index >= balanceOf(owner)) {
revert ERC721OutOfBoundsIndex(owner, index);
}
return _ownedTokens[owner][index];
}
/**
* @dev See {IERC721Enumerable-totalSupply}.
*/
function totalSupply() public view virtual returns (uint256) {
return _allTokens.length;
}
/**
* @dev See {IERC721Enumerable-tokenByIndex}.
*/
function tokenByIndex(uint256 index) public view virtual returns (uint256) {
if (index >= totalSupply()) {
revert ERC721OutOfBoundsIndex(address(0), index);
}
return _allTokens[index];
}
/**
* @dev See {ERC721-_update}.
*/
function _update(address to, uint256 tokenId, address auth) internal virtual override returns (address) {
address previousOwner = super._update(to, tokenId, auth);
if (previousOwner == address(0)) {
_addTokenToAllTokensEnumeration(tokenId);
} else if (previousOwner != to) {
_removeTokenFromOwnerEnumeration(previousOwner, tokenId);
}
if (to == address(0)) {
_removeTokenFromAllTokensEnumeration(tokenId);
} else if (previousOwner != to) {
_addTokenToOwnerEnumeration(to, tokenId);
}
return previousOwner;
}
/**
* @dev Private function to add a token to this extension's ownership-tracking data structures.
* @param to address representing the new owner of the given token ID
* @param tokenId uint256 ID of the token to be added to the tokens list of the given address
*/
function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private {
uint256 length = balanceOf(to) - 1;
_ownedTokens[to][length] = tokenId;
_ownedTokensIndex[tokenId] = length;
}
/**
* @dev Private function to add a token to this extension's token tracking data structures.
* @param tokenId uint256 ID of the token to be added to the tokens list
*/
function _addTokenToAllTokensEnumeration(uint256 tokenId) private {
_allTokensIndex[tokenId] = _allTokens.length;
_allTokens.push(tokenId);
}
/**
* @dev Private function to remove a token from this extension's ownership-tracking data structures. Note that
* while the token is not assigned a new owner, the `_ownedTokensIndex` mapping is _not_ updated: this allows for
* gas optimizations e.g. when performing a transfer operation (avoiding double writes).
* This has O(1) time complexity, but alters the order of the _ownedTokens array.
* @param from address representing the previous owner of the given token ID
* @param tokenId uint256 ID of the token to be removed from the tokens list of the given address
*/
function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private {
// To prevent a gap in from's tokens array, we store the last token in the index of the token to delete, and
// then delete the last slot (swap and pop).
uint256 lastTokenIndex = balanceOf(from);
uint256 tokenIndex = _ownedTokensIndex[tokenId];
// When the token to delete is the last token, the swap operation is unnecessary
if (tokenIndex != lastTokenIndex) {
uint256 lastTokenId = _ownedTokens[from][lastTokenIndex];
_ownedTokens[from][tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
_ownedTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index
}
// This also deletes the contents at the last position of the array
delete _ownedTokensIndex[tokenId];
delete _ownedTokens[from][lastTokenIndex];
}
/**
* @dev Private function to remove a token from this extension's token tracking data structures.
* This has O(1) time complexity, but alters the order of the _allTokens array.
* @param tokenId uint256 ID of the token to be removed from the tokens list
*/
function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private {
// To prevent a gap in the tokens array, we store the last token in the index of the token to delete, and
// then delete the last slot (swap and pop).
uint256 lastTokenIndex = _allTokens.length - 1;
uint256 tokenIndex = _allTokensIndex[tokenId];
// When the token to delete is the last token, the swap operation is unnecessary. However, since this occurs so
// rarely (when the last minted token is burnt) that we still do the swap here to avoid the gas cost of adding
// an 'if' statement (like in _removeTokenFromOwnerEnumeration)
uint256 lastTokenId = _allTokens[lastTokenIndex];
_allTokens[tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
_allTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index
// This also deletes the contents at the last position of the array
delete _allTokensIndex[tokenId];
_allTokens.pop();
}
/**
* See {ERC721-_increaseBalance}. We need that to account tokens that were minted in batch
*/
function _increaseBalance(address account, uint128 amount) internal virtual override {
if (amount > 0) {
revert ERC721EnumerableForbiddenBatchMint();
}
super._increaseBalance(account, amount);
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/ERC721Royalty.sol)
pragma solidity ^0.8.20;
import {ERC721} from "../ERC721.sol";
import {ERC2981} from "../../common/ERC2981.sol";
/**
* @dev Extension of ERC721 with the ERC2981 NFT Royalty Standard, a standardized way to retrieve royalty payment
* information.
*
* Royalty information can be specified globally for all token ids via {ERC2981-_setDefaultRoyalty}, and/or individually
* for specific token ids via {ERC2981-_setTokenRoyalty}. The latter takes precedence over the first.
*
* IMPORTANT: ERC-2981 only specifies a way to signal royalty information and does not enforce its payment. See
* https://eips.ethereum.org/EIPS/eip-2981#optional-royalty-payments[Rationale] in the EIP. Marketplaces are expected to
* voluntarily pay royalties together with sales, but note that this standard is not yet widely supported.
*/
abstract contract ERC721Royalty is ERC2981, ERC721 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721, ERC2981) returns (bool) {
return super.supportsInterface(interfaceId);
}
}
// SPDX-License-Identifier: MIT
// Compatible with OpenZeppelin Contracts ^5.0.0
pragma solidity ^0.8.26;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Royalty.sol";
import "@openzeppelin/contracts/utils/Base64.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
contract Genuine is ERC721, ERC721Enumerable, ERC721Royalty {
address internal owner;
uint256 internal nextTokenId;
uint constant MINT_TO_SENDER = 0x20;
uint constant MINT_PRICE = 6400000 gwei;
uint constant MAX_TOKEN_ID = 0xFFF;
uint8 constant STONE = 0;
bytes constant STONE_PROBS = hex"0308101a263547596b7f93a7bbcfe7ff";
uint8 constant CUT = 1;
uint8 constant CLARITY = 2;
bytes constant CLARITY_PROBS = hex"4c99d7f2ff";
uint8 constant ALLOY = 3;
bytes constant ALLOY_PROBS = hex"7fb2d7f2ff";
uint8 constant SHIMMER = 4;
bytes constant SHIMMER_PROBS = hex"7fd7ff";
uint8 constant MAGIC = 5;
bytes constant MAGIC_PROBS = hex"54a8ff";
uint8 constant RED = 0;
uint8 constant GREEN = 1;
uint8 constant BLUE = 2;
uint8 constant METALLIC = 3;
uint8 constant ROUGHNESS = 4;
uint8 constant TRANSMISSION = 5;
uint8 constant SHAPE_CUT = 0;
uint8 constant REFLECT = 1;
uint8 constant SECTION_POSITIONS = 2; // Number of positions/vertices in one section (pre-reflections)
uint8 constant SECTION_INDICES = 3; // Number of indices in one section (pre-reflections)
uint8 constant POSITIONS_DIV_4 = 4; // Number of positions/vertices in the final shape (post-reflections)
uint8 constant INDICES_DIV_3 = 5; // Number of indices in the final shape (post-reflections)
uint8 constant POSITION_MIN_X = 6;
uint8 constant POSITION_MIN_Y = 7;
uint8 constant POSITION_MIN_Z = 8;
uint8 constant POSITION_MAX_X = 9;
uint8 constant POSITION_MAX_Y = 10;
uint8 constant POSITION_MAX_Z = 11;
uint8 constant HEADER_COUNT = 12;
bytes constant ALLOWED_VIEWS = hex"1f1f050b0b0b1f";
// Header, then section positions, then section indices
bytes constant CLASSIC =
hex"00051118446082be827e427e00be000042005442003c423c00425466362a2a36667e260072263058265830267200267e7e220072223058225830227200227e000c0d000d0e000e0f000f10010302010403020507020305030905030609030406040b06050807050908060a09060b0a070d0c07080d080e0d08090e090f0e090a0f0a100f0a0b10";
bytes constant OVOID =
hex"01051118446082bfae7e415200bf000041005e410046411e004132643b1232373c7e210078211a68213836214c0021527e1d00781d1a681d38361d4c001d52000c0d000d0e000e0f000f10010302010403020507020305030905030609030406040b06050807050908060a09060b0a070d0c07080d080e0d08090e090f0e090a0f0a100f0a0b10";
bytes constant LEGEND =
hex"0207131a98d0ae82d9527e27504a00027e00027e02504a02025b25383725005b250059273635273600270000275248005248023a35253a0025520002520000007e00007e02000102000203020403030405040607040705050708070908070a0900030b030c0b03050c050d0c0c0d0e0c0e0f0b0c0f0b0f1005080d08090d090e0d0b0c0f0b0f10020604021206011112011202";
bytes constant PEAR =
hex"03012037406ea485ba5c7b4600851e007b1e265f1e104b3e003f46443d1e1c1f4656111e38ff3e28df465cd71e34c73a1cbb4654c31e18a53e00ad4644a71e248f1e007b1a265f1a443d1a56111a5cd71a54c31a44a71a248f1a00851a00f7ba1423da2c0bda2cebda14d1da01030201040302030503040605080703060505060806090807080a08090a0a090b090c0b0a0b0d0b0c0e0b0e100c0f0e0b100d0e1110000e0f00110e040f06060f09090f0c010212021312020513051413050714071514070a150a16150a0d160d17160d1017101817101118111918110019001a19121c1b12131c131d1c13141d14151d15161d161e1d16171e17181e181f1e18191f191a1f1c1d1b1d1e1b1b1e1f1a1b1f";
bytes constant SIGIL =
hex"04031c2870a088b0c07850410000c000502700473300333f002f415050274d473345333f432f417828277024335e1a3f5a18417800277000335e003f5a0041000041005024505024782824780024004c1c000aca404c1c72001c0f00ca72201c010206010512010605020307020706030408030807041108050a0905131205141305060a050913050914060b0a06070b070c0b07080c08110c090a0e090d15090e0d0914130915140a0b0f0a0f0e0b0c100b100f0c111012131613140013171813001713181614151914191b141a00141b1a161817191a1b";
bytes constant CRIT =
hex"05010e121c249484ac6c7c5400841c007c1c6c3e1c3620540020546cc21c00c254007c186c3e186cc218008418003ed60000ac36e0d601030201040302030503060503040600050601020801080702050902090805000a050a0907080b080c0b080d0c08090d090a0d0a0c0d";
bytes constant PILLOW =
hex"0605151e547887aa8779577900aa000057004957003957390057497937005b4b2473373a6b376b244b5b3a377300377979330073333a6b336b3a337300337900116f3a1b6d6d1b3a6f1100010302010403020306020605030409030908030806040b0905060706080708090a090b0a0a0b0f0b100f080a0e0a0f0e07080d080e0d05070c070d0c0f11120f10110e0f120d0e130c0d130c131400141300130e000e12001211";
uint8 constant OUTER_MIN_R = 0;
uint8 constant OUTER_MIN_G = 1;
uint8 constant OUTER_MIN_B = 2;
uint8 constant OUTER_RANGE_R = 3;
uint8 constant OUTER_RANGE_G = 4;
uint8 constant OUTER_RANGE_B = 5;
uint8 constant INNER_MIN_R = 6;
uint8 constant INNER_MIN_G = 7;
uint8 constant INNER_MIN_B = 8;
uint8 constant INNER_RANGE_R = 9;
uint8 constant INNER_RANGE_G = 10;
uint8 constant INNER_RANGE_B = 11;
uint8 constant ATTENUATION_MIN_R = 12;
uint8 constant ATTENUATION_MIN_G = 13;
uint8 constant ATTENUATION_MIN_B = 14;
uint8 constant ATTENUATION_RANGE_R = 15;
uint8 constant ATTENUATION_RANGE_G = 16;
uint8 constant ATTENUATION_RANGE_B = 17;
uint8 constant TEXT_R = 18;
uint8 constant TEXT_G = 19;
uint8 constant TEXT_B = 20;
uint8 constant GRAD_R = 21;
uint8 constant GRAD_G = 22;
uint8 constant GRAD_B = 23;
uint8 constant NUM_COLORS = 24;
bytes constant COLORS =
hex"63605a0202025a606302020263635a020202ffffff4040405d001408080e2e00210505072e001e050507ff0b4b342228285f3406060906312306060717145e0d07070a9e881d2d2a3260490505060c2c1c050505061f1304040433cc711d2d243238600508051014310608060c102c0507053868f21d25353c32600805052116460a090918122f0706069b8aff2321385f283e060607581a33070708400a20070707fc65bc2d1d28635054020204613c44040406635054020204ffb3d22d20265d530a080f0859500f080e0859500f080e08ffe027333022144a5e070b070b3848080a0807253006070627d3fc1f3133635d5a020202624e460305035f3928060806ffd3c0332b275d0000080d0d230202040505350303050808ba0000331f2158624605030333480b090808586246050303baed582d331c5e4414070a075d400a080c08382809060706ffb531352e235e3814070907532e0a090909382009060606f77d1933272231145e090707210c3e0707074b3c610504048f36fc2b253d";
// 0, 10, 20, 40, 60 metallic (without, faint, subtle, strong, powerful)
bytes constant ALLOY_TO_METALLIC = hex"000a14283c";
// 25, 25, 20, 10, 0 roughness (standard, fine, pure, brilliant, flawless)
bytes constant CLARITY_TO_ROUGHNESS = hex"1919140a00";
// 95, 100, 100, 100, 100 transmission (standard, fine, pure, brilliant, flawless)
bytes constant CLARITY_TO_TRANSMISSION = hex"5f64646464";
// 20, 60, 100 iridescence (light, heavy, eminent)
bytes constant SHIMMER_TO_IRIDESCENCE = hex"144664";
// 0, 3.5, 7.0 dispersion (without, soft, hard)
bytes constant MAGIC_TO_DISPERSION = hex"002346";
enum Stone {
Diamond,
Ruby,
Alexandrite,
Emerald,
Sapphire,
Tanzanite,
Spinel,
Tourmaline,
Heliodor,
Aquamarine,
Morganite,
Garnet,
Peridot,
Topaz,
Citrine,
Amethyst,
Count
}
enum Cut {
Classic,
Ovoid,
Legend,
Pear,
Sigil,
Crit,
Pillow,
Count
}
enum Clarity {
Standard,
Fine,
Pure,
Brilliant,
Flawless,
Count
}
enum Alloy {
Without,
Faint,
Subtle,
Strong,
Powerful,
Count
}
enum Shimmer {
Light,
Heavy,
Eminent,
Count
}
enum Magic {
Without,
Soft,
Hard,
Count
}
enum View {
Front, // No rotation
Left, // +90deg about Y
Back, // +180deg about Y
Right, // -90deg about Y
Top, // +90deg about X
Count
}
constructor() ERC721("Genuine", "GEN") {
owner = msg.sender;
for (uint i = 0x00; i < MINT_TO_SENDER; ++i) {
_safeMint(owner, i);
}
nextTokenId = MINT_TO_SENDER;
ERC2981._setDefaultRoyalty(owner, 0x200);
}
function mint() public payable returns (uint256) {
require(msg.value >= MINT_PRICE, "Not enough ETH provided");
require(nextTokenId <= MAX_TOKEN_ID, "All tokens have been minted");
payable(owner).transfer(msg.value);
_safeMint(msg.sender, nextTokenId);
return nextTokenId++;
}
function _update(
address to,
uint256 tokenId,
address auth
) internal override(ERC721, ERC721Enumerable) returns (address) {
return super._update(to, tokenId, auth);
}
function _increaseBalance(
address account,
uint128 value
) internal override(ERC721, ERC721Enumerable) {
super._increaseBalance(account, value);
}
function supportsInterface(
bytes4 interfaceId
)
public
view
override(ERC721, ERC721Enumerable, ERC721Royalty)
returns (bool)
{
return
ERC721.supportsInterface(interfaceId) ||
ERC721Enumerable.supportsInterface(interfaceId) ||
ERC721Royalty.supportsInterface(interfaceId);
}
// 8 -> "0.08", 80 -> "0.8", 120 -> "1"
function percentageIntToFloat(
uint8 val
) internal pure returns (string memory) {
if (val <= 0) {
return "0";
} else if (val < 10) {
return string.concat("0.0", Strings.toString(val));
} else if (val < 100) {
return string.concat("0.", Strings.toString(val));
} else {
return "1";
}
}
// 80 -> "8.0", 29 -> "2.9", 6 -> "0.6"
function tenthIntToFloat(uint8 val) internal pure returns (string memory) {
return
string.concat(
Strings.toString(val / 10),
".",
Strings.toString(val % 10)
);
}
function rgb(uint8[] memory rgbs) internal pure returns (string memory) {
return
string.concat(
percentageIntToFloat(rgbs[RED]),
",",
percentageIntToFloat(rgbs[GREEN]),
",",
percentageIntToFloat(rgbs[BLUE])
);
}
function pbr(uint8[] memory pbrs) internal pure returns (string memory) {
return
string.concat(
'\\"pbrMetallicRoughness\\":{\\"baseColorFactor\\":[',
rgb(pbrs),
',1],\\"metallicFactor\\":',
percentageIntToFloat(pbrs[METALLIC]),
',\\"roughnessFactor\\":',
percentageIntToFloat(pbrs[ROUGHNESS]),
"}"
);
}
function colorFromStone(
uint8[] memory rolls,
uint8 offset, // Outer, Inner, Attenuation
bytes32 state,
uint8 state_idx,
uint8[] memory rgbs
) internal pure returns (bytes32, uint8) {
uint stoneOffset = uint(NUM_COLORS) * rolls[STONE];
uint8 adj;
for (uint i = 0; i < 3; ++i) {
(state, state_idx, adj) = randomUint8(state, state_idx);
rgbs[i] =
uint8(COLORS[stoneOffset + 6 * offset + 0 + i]) +
(adj % uint8(COLORS[stoneOffset + 6 * offset + 3 + i]));
}
return (state, state_idx);
}
function outerMaterial(
uint8[] memory rolls,
bytes32 state,
uint8 state_idx
) internal pure returns (bytes32, uint8, string memory) {
uint8[] memory pbrs = new uint8[](6); // Additional entry for transmission
uint8[] memory attenuation = new uint8[](3);
// Use `pbrs` as a scratch space for two random vars that will additively contribute
// to iridescence thickness. Gives a range of [200, 710].
uint16 iridescenceThicknessMaximum = 200;
for (uint i = 0; i < 2; i++) {
(state, state_idx, pbrs[i]) = randomUint8(state, state_idx);
iridescenceThicknessMaximum += pbrs[i];
}
(state, state_idx) = colorFromStone(
rolls,
0, // Outer color
state,
state_idx,
pbrs
);
pbrs[METALLIC] = uint8(ALLOY_TO_METALLIC[rolls[ALLOY]]);
pbrs[ROUGHNESS] = uint8(CLARITY_TO_ROUGHNESS[rolls[CLARITY]]);
pbrs[TRANSMISSION] = uint8(CLARITY_TO_TRANSMISSION[rolls[CLARITY]]);
(state, state_idx) = colorFromStone(
rolls,
2, // Attenuation color
state,
state_idx,
attenuation
);
return (
state,
state_idx,
string.concat(
pbr(pbrs),
',\\"extensions\\":{\\"KHR_materials_dispersion\\":{\\"dispersion\\":',
tenthIntToFloat(uint8(MAGIC_TO_DISPERSION[rolls[MAGIC]])),
'},\\"KHR_materials_ior\\":{\\"ior\\":1.2},\\"KHR_materials_iridescence\\":{\\"iridescenceFactor\\":',
percentageIntToFloat(
uint8(SHIMMER_TO_IRIDESCENCE[rolls[SHIMMER]])
),
',\\"iridescenceIor\\":1.6,\\"iridescenceThicknessMaximum\\":',
Strings.toString(iridescenceThicknessMaximum),
'},\\"KHR_materials_transmission\\":{\\"transmissionFactor\\":',
percentageIntToFloat(pbrs[TRANSMISSION]),
'},\\"KHR_materials_volume\\":{\\"thicknessFactor\\":128,\\"attenuationDistance\\":256,\\"attenuationColor\\":[',
rgb(attenuation),
"]}}"
)
);
}
function innerMaterial(
uint8[] memory rolls,
bytes32 state,
uint8 state_idx
) internal pure returns (bytes32, uint8, string memory) {
uint8[] memory pbrs = new uint8[](5);
(state, state_idx) = colorFromStone(
rolls,
1, // Inner color
state,
state_idx,
pbrs
);
pbrs[METALLIC] = 100;
pbrs[ROUGHNESS] = 20;
return (state, state_idx, pbr(pbrs));
}
function materials(
uint8[] memory rolls,
bytes32 state,
uint8 state_idx
) internal pure returns (string memory) {
string memory outer;
string memory inner;
(state, state_idx, outer) = outerMaterial(rolls, state, state_idx);
(state, state_idx, inner) = innerMaterial(rolls, state, state_idx);
return string.concat('\\"materials\\":[{', outer, "},{", inner, "}],");
}
function getViewParams(View v) internal pure returns (int[6] memory) {
if (v == View.Front) {
return [int(0), 1, 2, 1, 1, 1];
} else if (v == View.Left) {
return [int(2), 1, 0, 1, 1, -1];
} else if (v == View.Back) {
return [int(0), 1, 2, -1, 1, -1];
} else if (v == View.Right) {
return [int(2), 1, 0, -1, 1, 1];
} else {
return [int(0), 2, 1, 1, -1, 1];
}
}
function dynamicView(Cut cut) internal view returns (View) {
View[] memory views = new View[](uint(View.Count));
uint allowed_views = uint8(ALLOWED_VIEWS[uint(cut)]);
uint num_views = 0;
for (uint i = 0; i < uint(View.Count); ++i) {
if (allowed_views & (1 << i) != 0) {
views[num_views++] = View(i);
}
}
return views[block.timestamp % num_views];
}
function encodePositions(
bytes memory shape
) internal view returns (string memory) {
bytes memory positions = new bytes(
uint(uint8(shape[POSITIONS_DIV_4])) * 4
);
uint len = uint8(shape[SECTION_POSITIONS]);
uint sectionOffset = HEADER_COUNT;
// Start by copying the initial shape (section positions)
for (uint i = 0; i < len; i++) {
for (uint j = 0; j < 3; j++) {
positions[i * 4 + j] = shape[sectionOffset + i * 3 + j];
}
}
// Reflect X, Y, Z
for (uint8 axis = 0x01; axis <= 0x04; axis <<= 1) {
if (uint8(shape[REFLECT]) & axis == 0) continue;
int8[3] memory mults = [
axis == 0x01 ? -1 : int8(1),
axis == 0x02 ? -1 : int8(1),
axis == 0x04 ? -1 : int8(1)
];
for (uint i = 0; i < len; i++) {
for (uint j = 0; j < 3; ++j) {
positions[(len + i) * 4 + j] = bytes1(
uint8(mults[j] * int8(uint8(positions[i * 4 + j])))
);
}
}
len <<= 1;
}
// Timestamp-based view
int[6] memory params = getViewParams(
dynamicView(Cut(uint8(shape[SHAPE_CUT])))
);
for (uint i = 0; i < len; i++) {
int8[3] memory transformed = [int8(0), 0, 0];
for (uint j = 0; j < 3; ++j) {
transformed[j] =
int8(uint8(positions[i * 4 + uint(params[j])])) *
int8(params[3 + j]);
}
for (uint j = 0; j < 3; ++j) {
positions[i * 4 + j] = bytes1(uint8(transformed[j]));
}
}
return Base64.encode(positions);
}
function encodeIndices(
bytes memory shape,
bool reverse
) internal pure returns (string memory) {
bytes memory indices = new bytes(uint(uint8(shape[INDICES_DIV_3])) * 3);
uint8 sectionPosLen = uint8(shape[SECTION_POSITIONS]);
uint len = uint8(shape[SECTION_INDICES]);
uint sectionOffset = HEADER_COUNT + sectionPosLen * 3;
// Start by copying the initial indices (section indices)
for (uint i = 0; i < len; i++) {
for (uint j = 0; j < 3; j++) {
indices[i * 3 + j] = shape[
sectionOffset + i * 3 + (reverse ? 2 - j : j)
];
}
}
// Reflect X, Y, Z
for (uint8 axis = 0x01; axis <= 0x04; axis <<= 1) {
if (uint8(shape[REFLECT]) & axis == 0) continue;
for (uint i = 0; i < len; i++) {
for (uint j = 0; j < 3; ++j) {
indices[(len + i) * 3 + j] = bytes1(
uint8(indices[i * 3 + (2 - j)]) + sectionPosLen
);
}
}
len <<= 1;
sectionPosLen <<= 1;
}
return Base64.encode(indices);
}
function buffers(bytes memory shape) internal view returns (string memory) {
return
string.concat(
'\\"buffers\\":[{\\"uri\\":\\"data:application/octet-stream;base64,',
encodePositions(shape),
'\\",\\"byteLength\\":',
Strings.toString(uint16(4) * uint8(shape[POSITIONS_DIV_4])),
'},{\\"uri\\":\\"data:application/octet-stream;base64,',
encodeIndices(shape, false),
'\\",\\"byteLength\\":',
Strings.toString(uint16(3) * uint8(shape[INDICES_DIV_3])),
'},{\\"uri\\":\\"data:application/octet-stream;base64,',
encodeIndices(shape, true),
'\\",\\"byteLength\\":',
Strings.toString(uint16(3) * uint8(shape[INDICES_DIV_3])),
"}],"
);
}
function bufferViews(
bytes memory shape
) internal pure returns (string memory) {
return
string.concat(
'\\"bufferViews\\":[{\\"buffer\\":0,\\"byteOffset\\":0,\\"byteStride\\":4,\\"byteLength\\":',
Strings.toString(uint16(4) * uint8(shape[POSITIONS_DIV_4])),
',\\"target\\":34962},{\\"buffer\\":1,\\"byteOffset\\":0,\\"byteLength\\":',
Strings.toString(uint16(3) * uint8(shape[INDICES_DIV_3])),
',\\"target\\":34963},{\\"buffer\\":2,\\"byteOffset\\":0,\\"byteLength\\":',
Strings.toString(uint16(3) * uint8(shape[INDICES_DIV_3])),
',\\"target\\":34963}],'
);
}
function decTriplet(
int8[3] memory vals
) internal pure returns (string memory) {
return
string.concat(
Strings.toStringSigned(vals[0]),
",",
Strings.toStringSigned(vals[1]),
",",
Strings.toStringSigned(vals[2])
);
}
function toHexString(uint8 value) internal pure returns (string memory) {
bytes16 HEX_DIGITS = "0123456789abcdef";
bytes memory buffer = new bytes(2);
buffer[1] = HEX_DIGITS[value & 0xf];
value >>= 4;
buffer[0] = HEX_DIGITS[value & 0xf];
return string(buffer);
}
function hexTriplet(
bytes1[3] memory vals
) internal pure returns (string memory) {
return
string.concat(
toHexString(uint8(vals[0])),
toHexString(uint8(vals[1])),
toHexString(uint8(vals[2]))
);
}
function minsMaxs(
bytes memory shape,
uint unflippedIdx,
uint flippedIdx
) internal view returns (string memory) {
// Timestamp-based view
int[6] memory params = getViewParams(
dynamicView(Cut(uint8(shape[SHAPE_CUT])))
);
int8[3] memory vals = [int8(0), 0, 0];
for (uint i = 0; i < 3; ++i) {
vals[i] = int8(
uint8(
shape[
(params[3 + i] > 0 ? unflippedIdx : flippedIdx) +
uint(params[i])
]
)
);
vals[i] *= params[3 + i] > 0 ? int8(1) : -1;
}
return decTriplet(vals);
}
function accessors(
bytes memory shape
) internal view returns (string memory) {
return
string.concat(
'\\"accessors\\":[{\\"bufferView\\":0,\\"byteOffset\\":0,\\"componentType\\":5120,\\"count\\":',
Strings.toString(uint8(shape[POSITIONS_DIV_4])),
',\\"type\\":\\"VEC3\\",\\"min\\":[',
minsMaxs(shape, POSITION_MIN_X, POSITION_MAX_X),
'],\\"max\\":[',
minsMaxs(shape, POSITION_MAX_X, POSITION_MIN_X),
']},{\\"bufferView\\":1,\\"byteOffset\\":0,\\"componentType\\":5121,\\"count\\":',
Strings.toString(uint16(3) * uint8(shape[INDICES_DIV_3])),
',\\"type\\":\\"SCALAR\\",\\"min\\":[0],\\"max\\":[',
Strings.toString(uint8(shape[POSITIONS_DIV_4]) - 1),
']},{\\"bufferView\\":2,\\"byteOffset\\":0,\\"componentType\\":5121,\\"count\\":',
Strings.toString(uint16(3) * uint8(shape[INDICES_DIV_3])),
',\\"type\\":\\"SCALAR\\",\\"min\\":[0],\\"max\\":[',
Strings.toString(uint8(shape[POSITIONS_DIV_4]) - 1),
"]}]"
);
}
function getShape(Cut cut) internal pure returns (bytes memory) {
if (cut == Cut.Classic) {
return CLASSIC;
} else if (cut == Cut.Ovoid) {
return OVOID;
} else if (cut == Cut.Legend) {
return LEGEND;
} else if (cut == Cut.Pear) {
return PEAR;
} else if (cut == Cut.Sigil) {
return SIGIL;
} else if (cut == Cut.Crit) {
return CRIT;
} else {
return PILLOW;
}
}
function getModel(
uint8[] memory rolls,
bytes32 state,
uint8 state_idx
) internal view returns (string memory) {
bytes memory shape = getShape(Cut(rolls[CUT]));
return
string.concat(
"{",
'\\"asset\\":{\\"version\\":\\"2.0\\",\\"generator\\":\\"ofoid\\"},',
'\\"scenes\\":[{\\"nodes\\":[0]}],',
'\\"nodes\\":[{\\"mesh\\":0}],',
'\\"meshes\\":[{\\"primitives\\":[{\\"attributes\\":{\\"POSITION\\":0},\\"indices\\":1,\\"material\\":0},{\\"attributes\\":{\\"POSITION\\":0},\\"indices\\":2,\\"material\\":1}]}],',
'\\"extensionsUsed\\":[\\"KHR_materials_dispersion\\",\\"KHR_materials_ior\\",\\"KHR_materials_iridescence\\",\\"KHR_materials_transmission\\",\\"KHR_materials_volume\\",\\"KHR_mesh_quantization\\"],',
'\\"extensionsRequired\\":[\\"KHR_mesh_quantization\\"],',
materials(rolls, state, state_idx),
buffers(shape),
bufferViews(shape),
accessors(shape),
"}"
);
}
function randomUint8(
bytes32 state,
uint8 idx
) internal pure returns (bytes32, uint8, uint8) {
if (idx >= 32) {
state = keccak256(abi.encodePacked(state));
idx = 0;
}
return (state, idx + 1, uint8(state[idx]));
}
function stoneStr(
uint8[] memory rolls
) internal pure returns (string memory) {
string[16] memory stone = [
"Diamond",
"Ruby",
"Alexandrite",
"Emerald",
"Sapphire",
"Tanzanite",
"Spinel",
"Tourmaline",
"Heliodor",
"Aquamarine",
"Morganite",
"Garnet",
"Peridot",
"Topaz",
"Citrine",
"Amethyst"
];
return stone[rolls[STONE]];
}
function cutStr(
uint8[] memory rolls
) internal pure returns (string memory) {
string[7] memory cut = [
"Classic",
"Ovoid",
"Legend",
"Pear",
"Sigil",
"Crit",
"Pillow"
];
return cut[rolls[CUT]];
}
function clarityStr(
uint8[] memory rolls
) internal pure returns (string memory) {
string[5] memory clarity = [
"Standard",
"Fine",
"Pure",
"Brilliant",
"Flawless"
];
return clarity[rolls[CLARITY]];
}
function alloyStr(
uint8[] memory rolls
) internal pure returns (string memory) {
string[5] memory alloy = [
"Without",
"Faint",
"Subtle",
"Strong",
"Powerful"
];
return alloy[rolls[ALLOY]];
}
function shimmerStr(
uint8[] memory rolls
) internal pure returns (string memory) {
string[3] memory shimmer = ["Light", "Heavy", "Eminent"];
return shimmer[rolls[SHIMMER]];
}
function magicStr(
uint8[] memory rolls
) internal pure returns (string memory) {
string[3] memory magic = ["Without", "Soft", "Hard"];
return magic[rolls[MAGIC]];
}
function viewStr(View v) internal pure returns (string memory) {
string[5] memory views = ["Front", "Left", "Back", "Right", "Top"];
return views[uint8(v)];
}
function svg(uint8[] memory rolls) internal pure returns (string memory) {
return
string.concat(
"<svg width='1080' height='1080' xmlns='http://www.w3.org/2000/svg'><style>text{font-family:Inter,Roboto,'Helvetica Neue','Arial Nova','Nimbus Sans',Arial,system-ui,sans-serif;font-weight:bold;font-size:106px;fill:#999}</style><defs><linearGradient id='o' x1='0' x2='0' y1='0' y2='1'><stop stop-color='#0f0f0f'/><stop offset='100%' stop-color='#",
hexTriplet(
[
COLORS[uint(NUM_COLORS) * rolls[STONE] + GRAD_R],
COLORS[uint(NUM_COLORS) * rolls[STONE] + GRAD_G],
COLORS[uint(NUM_COLORS) * rolls[STONE] + GRAD_B]
]
),
"'/></linearGradient></defs><rect width='1080' height='1080' fill='url(#o)'/><g transform='translate(80, 0)'><text y='160' style='font-size:60px;fill:#4d4d4d'>Genuine</text><text y='330' style='fill:#",
hexTriplet(
[
COLORS[uint(NUM_COLORS) * rolls[STONE] + TEXT_R],
COLORS[uint(NUM_COLORS) * rolls[STONE] + TEXT_G],
COLORS[uint(NUM_COLORS) * rolls[STONE] + TEXT_B]
]
),
"'>",
stoneStr(rolls),
"</text><text y='460'>",
cutStr(rolls),
" cut</text><text y='590'>",
clarityStr(rolls),
" clarity</text><text y='720'>",
alloyStr(rolls),
" alloy</text><text y='850'>",
shimmerStr(rolls),
" shimmer</text><text y='980'>",
magicStr(rolls),
" magic</text></g>",
"</svg>"
);
}
function prob(bytes memory probs, uint8 val) internal pure returns (uint8) {
for (uint i = 0; i < probs.length; i++) {
if (val < uint8(probs[i])) {
return uint8(i);
}
}
return uint8(probs.length - 1);
}
function displayedTokenId(
uint256 tokenId
) internal pure returns (string memory) {
uint256 displayed = tokenId + 1;
if (displayed < 10) {
return string.concat("000", Strings.toString(displayed));
} else if (displayed < 100) {
return string.concat("00", Strings.toString(displayed));
} else if (displayed < 1000) {
return string.concat("0", Strings.toString(displayed));
} else {
return Strings.toString(displayed);
}
}
function tokenURI(
uint256 tokenId
) public view override returns (string memory) {
bytes32 state = keccak256(abi.encodePacked(tokenId + 0x220));
uint8 state_idx = 0;
uint8[] memory rolls = new uint8[](6);
(state, state_idx, rolls[STONE]) = randomUint8(state, state_idx);
rolls[STONE] = prob(STONE_PROBS, rolls[STONE]);
(state, state_idx, rolls[CUT]) = randomUint8(state, state_idx);
rolls[CUT] %= uint8(Cut.Count);
(state, state_idx, rolls[CLARITY]) = randomUint8(state, state_idx);
rolls[CLARITY] = prob(CLARITY_PROBS, rolls[CLARITY]);
(state, state_idx, rolls[ALLOY]) = randomUint8(state, state_idx);
rolls[ALLOY] = rolls[CLARITY] <= uint8(Clarity.Fine)
? uint8(Alloy.Without)
: prob(ALLOY_PROBS, rolls[ALLOY]);
(state, state_idx, rolls[SHIMMER]) = randomUint8(state, state_idx);
rolls[SHIMMER] = prob(SHIMMER_PROBS, rolls[SHIMMER]);
(state, state_idx, rolls[MAGIC]) = randomUint8(state, state_idx);
rolls[MAGIC] = prob(MAGIC_PROBS, rolls[MAGIC]);
return
string.concat(
'data:application/json,{"name":"'
"Genuine ",
displayedTokenId(tokenId),
'","description":"',
"Digital facets.\\n\\nForever enduring, fully on-chain.\\n\\nInitial view: ",
viewStr(dynamicView(Cut(rolls[CUT]))),
'","attributes":[{"trait_type":"Stone","value":"',
stoneStr(rolls),
'"},{"trait_type":"Cut","value":"',
cutStr(rolls),
'"},{"trait_type":"Clarity","value":"',
clarityStr(rolls),
'"},{"trait_type":"Alloy","value":"',
alloyStr(rolls),
'"},{"trait_type":"Shimmer","value":"',
shimmerStr(rolls),
'"},{"trait_type":"Magic","value":"',
magicStr(rolls),
'"}],"image_data":"',
svg(rolls),
'","animation_url":"data:model/gltf+json,',
getModel(rolls, state, state_idx),
'"}'
);
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @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: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC2981.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../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.
*/
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: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../../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 address zero.
*
* 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: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/IERC721Enumerable.sol)
pragma solidity ^0.8.20;
import {IERC721} from "../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: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/IERC721Metadata.sol)
pragma solidity ^0.8.20;
import {IERC721} from "../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: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721Receiver.sol)
pragma solidity ^0.8.20;
/**
* @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: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
/**
* @dev Muldiv operation overflow.
*/
error MathOverflowedMulDiv();
enum Rounding {
Floor, // Toward negative infinity
Ceil, // Toward positive infinity
Trunc, // Toward zero
Expand // Away from zero
}
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with an overflow flag.
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
/**
* @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 towards infinity instead
* of rounding towards zero.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
if (b == 0) {
// Guarantee the same behavior as in a regular Solidity division.
return a / b;
}
// (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 = x * y; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
if (denominator <= prod1) {
revert MathOverflowedMulDiv();
}
///////////////////////////////////////////////
// 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.
uint256 twos = denominator & (0 - denominator);
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 (unsignedRoundsUp(rounding) && 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
* towards zero.
*
* 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 + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2 of a positive value rounded towards zero.
* 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 + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10 of a positive value rounded towards zero.
* 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 + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256 of a positive value rounded towards zero.
* 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 256, 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 + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
}
}
/**
* @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
*/
function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
return uint8(rounding) % 2 == 1;
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard signed math utilities missing in the Solidity language.
*/
library SignedMath {
/**
* @dev Returns the largest of two signed numbers.
*/
function max(int256 a, int256 b) internal pure returns (int256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two signed numbers.
*/
function min(int256 a, int256 b) internal pure returns (int256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two signed numbers without overflow.
* The result is rounded towards zero.
*/
function average(int256 a, int256 b) internal pure returns (int256) {
// Formula from the book "Hacker's Delight"
int256 x = (a & b) + ((a ^ b) >> 1);
return x + (int256(uint256(x) >> 255) & (a ^ b));
}
/**
* @dev Returns the absolute unsigned value of a signed value.
*/
function abs(int256 n) internal pure returns (uint256) {
unchecked {
// must be unchecked in order to support `n = type(int256).min`
return uint256(n >= 0 ? n : -n);
}
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol)
pragma solidity ^0.8.20;
import {Math} from "./math/Math.sol";
import {SignedMath} from "./math/SignedMath.sol";
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant HEX_DIGITS = "0123456789abcdef";
uint8 private constant ADDRESS_LENGTH = 20;
/**
* @dev The `value` string doesn't fit in the specified `length`.
*/
error StringsInsufficientHexLength(uint256 value, uint256 length);
/**
* @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), HEX_DIGITS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `int256` to its ASCII `string` decimal representation.
*/
function toStringSigned(int256 value) internal pure returns (string memory) {
return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value)));
}
/**
* @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) {
uint256 localValue = value;
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] = HEX_DIGITS[localValue & 0xf];
localValue >>= 4;
}
if (localValue != 0) {
revert StringsInsufficientHexLength(value, length);
}
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);
}
/**
* @dev Returns true if the two strings are equal.
*/
function equal(string memory a, string memory b) internal pure returns (bool) {
return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b));
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard ERC20 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC20 tokens.
*/
interface IERC20Errors {
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC20InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC20InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.
* @param spender Address that may be allowed to operate on tokens without being their owner.
* @param allowance Amount of tokens a `spender` is allowed to operate with.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC20InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `spender` to be approved. Used in approvals.
* @param spender Address that may be allowed to operate on tokens without being their owner.
*/
error ERC20InvalidSpender(address spender);
}
/**
* @dev Standard ERC721 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC721 tokens.
*/
interface IERC721Errors {
/**
* @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in EIP-20.
* Used in balance queries.
* @param owner Address of the current owner of a token.
*/
error ERC721InvalidOwner(address owner);
/**
* @dev Indicates a `tokenId` whose `owner` is the zero address.
* @param tokenId Identifier number of a token.
*/
error ERC721NonexistentToken(uint256 tokenId);
/**
* @dev Indicates an error related to the ownership over a particular token. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param tokenId Identifier number of a token.
* @param owner Address of the current owner of a token.
*/
error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC721InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC721InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param tokenId Identifier number of a token.
*/
error ERC721InsufficientApproval(address operator, uint256 tokenId);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC721InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/
error ERC721InvalidOperator(address operator);
}
/**
* @dev Standard ERC1155 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC1155 tokens.
*/
interface IERC1155Errors {
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
* @param tokenId Identifier number of a token.
*/
error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC1155InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC1155InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param owner Address of the current owner of a token.
*/
error ERC1155MissingApprovalForAll(address operator, address owner);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC1155InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/
error ERC1155InvalidOperator(address operator);
/**
* @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.
* Used in batch transfers.
* @param idsLength Length of the array of token identifiers
* @param valuesLength Length of the array of token amounts
*/
error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
}
{
"compilationTarget": {
"contracts/Genuine.sol": "Genuine"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 1
},
"remappings": [],
"viaIR": true
}
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"numerator","type":"uint256"},{"internalType":"uint256","name":"denominator","type":"uint256"}],"name":"ERC2981InvalidDefaultRoyalty","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC2981InvalidDefaultRoyaltyReceiver","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"numerator","type":"uint256"},{"internalType":"uint256","name":"denominator","type":"uint256"}],"name":"ERC2981InvalidTokenRoyalty","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC2981InvalidTokenRoyaltyReceiver","type":"error"},{"inputs":[],"name":"ERC721EnumerableForbiddenBatchMint","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"owner","type":"address"}],"name":"ERC721IncorrectOwner","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC721InsufficientApproval","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC721InvalidApprover","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"ERC721InvalidOperator","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"ERC721InvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC721InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC721InvalidSender","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC721NonexistentToken","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"ERC721OutOfBoundsIndex","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"salePrice","type":"uint256"}],"name":"royaltyInfo","outputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenOfOwnerByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"}]