// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)pragmasolidity ^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.
*/abstractcontractContext{
function_msgSender() internalviewvirtualreturns (address) {
returnmsg.sender;
}
function_msgData() internalviewvirtualreturns (bytescalldata) {
returnmsg.data;
}
function_contextSuffixLength() internalviewvirtualreturns (uint256) {
return0;
}
}
Contract Source Code
File 2 of 17: ERC165.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)pragmasolidity ^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);
* }
* ```
*/abstractcontractERC165isIERC165{
/**
* @dev See {IERC165-supportsInterface}.
*/functionsupportsInterface(bytes4 interfaceId) publicviewvirtualreturns (bool) {
return interfaceId ==type(IERC165).interfaceId;
}
}
Contract Source Code
File 3 of 17: ERC721.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/ERC721.sol)pragmasolidity ^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}.
*/abstractcontractERC721isContext, ERC165, IERC721, IERC721Metadata, IERC721Errors{
usingStringsforuint256;
// Token namestringprivate _name;
// Token symbolstringprivate _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(stringmemory name_, stringmemory symbol_) {
_name = name_;
_symbol = symbol_;
}
/**
* @dev See {IERC165-supportsInterface}.
*/functionsupportsInterface(bytes4 interfaceId) publicviewvirtualoverride(ERC165, IERC165) returns (bool) {
return
interfaceId ==type(IERC721).interfaceId||
interfaceId ==type(IERC721Metadata).interfaceId||super.supportsInterface(interfaceId);
}
/**
* @dev See {IERC721-balanceOf}.
*/functionbalanceOf(address owner) publicviewvirtualreturns (uint256) {
if (owner ==address(0)) {
revert ERC721InvalidOwner(address(0));
}
return _balances[owner];
}
/**
* @dev See {IERC721-ownerOf}.
*/functionownerOf(uint256 tokenId) publicviewvirtualreturns (address) {
return _requireOwned(tokenId);
}
/**
* @dev See {IERC721Metadata-name}.
*/functionname() publicviewvirtualreturns (stringmemory) {
return _name;
}
/**
* @dev See {IERC721Metadata-symbol}.
*/functionsymbol() publicviewvirtualreturns (stringmemory) {
return _symbol;
}
/**
* @dev See {IERC721Metadata-tokenURI}.
*/functiontokenURI(uint256 tokenId) publicviewvirtualreturns (stringmemory) {
_requireOwned(tokenId);
stringmemory baseURI = _baseURI();
returnbytes(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() internalviewvirtualreturns (stringmemory) {
return"";
}
/**
* @dev See {IERC721-approve}.
*/functionapprove(address to, uint256 tokenId) publicvirtual{
_approve(to, tokenId, _msgSender());
}
/**
* @dev See {IERC721-getApproved}.
*/functiongetApproved(uint256 tokenId) publicviewvirtualreturns (address) {
_requireOwned(tokenId);
return _getApproved(tokenId);
}
/**
* @dev See {IERC721-setApprovalForAll}.
*/functionsetApprovalForAll(address operator, bool approved) publicvirtual{
_setApprovalForAll(_msgSender(), operator, approved);
}
/**
* @dev See {IERC721-isApprovedForAll}.
*/functionisApprovedForAll(address owner, address operator) publicviewvirtualreturns (bool) {
return _operatorApprovals[owner][operator];
}
/**
* @dev See {IERC721-transferFrom}.
*/functiontransferFrom(addressfrom, address to, uint256 tokenId) publicvirtual{
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}.
*/functionsafeTransferFrom(addressfrom, address to, uint256 tokenId) public{
safeTransferFrom(from, to, tokenId, "");
}
/**
* @dev See {IERC721-safeTransferFrom}.
*/functionsafeTransferFrom(addressfrom, address to, uint256 tokenId, bytesmemory data) publicvirtual{
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) internalviewvirtualreturns (address) {
return _owners[tokenId];
}
/**
* @dev Returns the approved address for `tokenId`. Returns 0 if `tokenId` is not minted.
*/function_getApproved(uint256 tokenId) internalviewvirtualreturns (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) internalviewvirtualreturns (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) internalviewvirtual{
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) internalvirtual{
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) internalvirtualreturns (address) {
addressfrom= _ownerOf(tokenId);
// Perform (optional) operator checkif (auth !=address(0)) {
_checkAuthorized(from, auth, tokenId);
}
// Execute the updateif (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);
returnfrom;
}
/**
* @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, bytesmemory data) internalvirtual{
_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(addressfrom, 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);
} elseif (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(addressfrom, 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(addressfrom, address to, uint256 tokenId, bytesmemory data) internalvirtual{
_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) internalvirtual{
// Avoid reading the owner unless necessaryif (emitEvent || auth !=address(0)) {
address owner = _requireOwned(tokenId);
// We do not use _isAuthorized because single-token approvals should not be able to call approveif (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) internalvirtual{
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) internalviewreturns (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(addressfrom, address to, uint256 tokenId, bytesmemory 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 (bytesmemory reason) {
if (reason.length==0) {
revert ERC721InvalidReceiver(to);
} else {
/// @solidity memory-safe-assemblyassembly {
revert(add(32, reason), mload(reason))
}
}
}
}
}
}
Contract Source Code
File 4 of 17: ERC721URIStorage.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/ERC721URIStorage.sol)pragmasolidity ^0.8.20;import {ERC721} from"../ERC721.sol";
import {Strings} from"../../../utils/Strings.sol";
import {IERC4906} from"../../../interfaces/IERC4906.sol";
import {IERC165} from"../../../interfaces/IERC165.sol";
/**
* @dev ERC721 token with storage based token URI management.
*/abstractcontractERC721URIStorageisIERC4906, ERC721{
usingStringsforuint256;
// Interface ID as defined in ERC-4906. This does not correspond to a traditional interface ID as ERC-4906 only// defines events and does not include any external function.bytes4privateconstant ERC4906_INTERFACE_ID =bytes4(0x49064906);
// Optional mapping for token URIsmapping(uint256 tokenId =>string) private _tokenURIs;
/**
* @dev See {IERC165-supportsInterface}
*/functionsupportsInterface(bytes4 interfaceId) publicviewvirtualoverride(ERC721, IERC165) returns (bool) {
return interfaceId == ERC4906_INTERFACE_ID ||super.supportsInterface(interfaceId);
}
/**
* @dev See {IERC721Metadata-tokenURI}.
*/functiontokenURI(uint256 tokenId) publicviewvirtualoverridereturns (stringmemory) {
_requireOwned(tokenId);
stringmemory _tokenURI = _tokenURIs[tokenId];
stringmemory base = _baseURI();
// If there is no base URI, return the token URI.if (bytes(base).length==0) {
return _tokenURI;
}
// If both are set, concatenate the baseURI and tokenURI (via string.concat).if (bytes(_tokenURI).length>0) {
returnstring.concat(base, _tokenURI);
}
returnsuper.tokenURI(tokenId);
}
/**
* @dev Sets `_tokenURI` as the tokenURI of `tokenId`.
*
* Emits {MetadataUpdate}.
*/function_setTokenURI(uint256 tokenId, stringmemory _tokenURI) internalvirtual{
_tokenURIs[tokenId] = _tokenURI;
emit MetadataUpdate(tokenId);
}
}
Contract Source Code
File 5 of 17: IERC165.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)pragmasolidity ^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}.
*/interfaceIERC165{
/**
* @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.
*/functionsupportsInterface(bytes4 interfaceId) externalviewreturns (bool);
}
Contract Source Code
File 6 of 17: IERC2981.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC2981.sol)pragmasolidity ^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.
*/interfaceIERC2981isIERC165{
/**
* @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.
*/functionroyaltyInfo(uint256 tokenId,
uint256 salePrice
) externalviewreturns (address receiver, uint256 royaltyAmount);
}
Contract Source Code
File 7 of 17: IERC4906.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC4906.sol)pragmasolidity ^0.8.20;import {IERC165} from"./IERC165.sol";
import {IERC721} from"./IERC721.sol";
/// @title EIP-721 Metadata Update ExtensioninterfaceIERC4906isIERC165, IERC721{
/// @dev This event emits when the metadata of a token is changed./// So that the third-party platforms such as NFT market could/// timely update the images and related attributes of the NFT.eventMetadataUpdate(uint256 _tokenId);
/// @dev This event emits when the metadata of a range of tokens is changed./// So that the third-party platforms such as NFT market could/// timely update the images and related attributes of the NFTs.eventBatchMetadataUpdate(uint256 _fromTokenId, uint256 _toTokenId);
}
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721Receiver.sol)pragmasolidity ^0.8.20;/**
* @title ERC721 token receiver interface
* @dev Interface for any contract that wants to support safeTransfers
* from ERC721 asset contracts.
*/interfaceIERC721Receiver{
/**
* @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`.
*/functiononERC721Received(address operator,
addressfrom,
uint256 tokenId,
bytescalldata data
) externalreturns (bytes4);
}
Contract Source Code
File 11 of 17: Math.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)pragmasolidity ^0.8.20;/**
* @dev Standard math utilities missing in the Solidity language.
*/libraryMath{
/**
* @dev Muldiv operation overflow.
*/errorMathOverflowedMulDiv();
enumRounding {
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.
*/functiontryAdd(uint256 a, uint256 b) internalpurereturns (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.
*/functiontrySub(uint256 a, uint256 b) internalpurereturns (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.
*/functiontryMul(uint256 a, uint256 b) internalpurereturns (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/522if (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.
*/functiontryDiv(uint256 a, uint256 b) internalpurereturns (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.
*/functiontryMod(uint256 a, uint256 b) internalpurereturns (bool, uint256) {
unchecked {
if (b ==0) return (false, 0);
return (true, a % b);
}
}
/**
* @dev Returns the largest of two numbers.
*/functionmax(uint256 a, uint256 b) internalpurereturns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/functionmin(uint256 a, uint256 b) internalpurereturns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/functionaverage(uint256 a, uint256 b) internalpurereturns (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.
*/functionceilDiv(uint256 a, uint256 b) internalpurereturns (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.
*/functionmulDiv(uint256 x, uint256 y, uint256 denominator) internalpurereturns (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 productuint256 prod1; // Most significant 256 bits of the productassembly {
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.
*/functionmulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internalpurereturns (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).
*/functionsqrt(uint256 a) internalpurereturns (uint256) {
if (a ==0) {
return0;
}
// 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.
*/functionsqrt(uint256 a, Rounding rounding) internalpurereturns (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.
*/functionlog2(uint256 value) internalpurereturns (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.
*/functionlog2(uint256 value, Rounding rounding) internalpurereturns (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.
*/functionlog10(uint256 value) internalpurereturns (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.
*/functionlog10(uint256 value, Rounding rounding) internalpurereturns (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.
*/functionlog256(uint256 value) internalpurereturns (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.
*/functionlog256(uint256 value, Rounding rounding) internalpurereturns (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.
*/functionunsignedRoundsUp(Rounding rounding) internalpurereturns (bool) {
returnuint8(rounding) %2==1;
}
}
Contract Source Code
File 12 of 17: NFT.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.19;import"@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import"@openzeppelin/contracts/access/Ownable.sol";
import"@openzeppelin/contracts/utils/Strings.sol";
import"@openzeppelin/contracts/interfaces/IERC2981.sol";
import"ReentrancyGuard.sol";
contracttinypepesisERC721URIStorage, Ownable, IERC2981, ReentrancyGuard{
uint256private _tokenIds;
uint256public cost =.00069ether;
uint256public maxTokens; // Cap on the number of tokens that can be mintedboolpublic mintingEnabled =true;
addressprivate royaltyRecipient =0x197B380aC62fA4785067cf7257c05f052776039A;
uint96private royaltyPercentage =1500; // Initial value set to 1500 (15%)uint256public maxFreeMints =500; // Maximum number of total free mints alloweduint256public maxFreeMintsToSend =500; // Maximum number of total free mints to send alloweduint256public currentFreeMints =0; // Current count of free mintsuint256public currentFreeMintsToSend =0; // Current count of free mints to senduint256public maxFreeMintsToSendPerAddress =2; // Maximum free mints to send per address, initial value set to 2boolprivate allMetadataLocked =false; // Master lock for all metadatastructFreeMintInfo {
uint256 allowed;
uint256 minted;
}
mapping(uint256=>bool) private metadataLocked;
mapping(address=> FreeMintInfo) private freeMintList;
mapping(address=> FreeMintInfo) private freeMintToSendList;
mapping(address=>uint256) private freeMintsToSendReceived;
eventTokenMinted(uint256indexed tokenId);
eventBatchMinted(uint256indexed startTokenId, uint256 count);
eventAirdropped(uint256indexed tokenId, addressindexed to);
eventBatchAirdropped(uint256[] tokenIds, address[] to);
errorNotEnoughEtherProvided(uint256 requiredCost, uint256 providedEther);
errorMaxTokensReached(uint256 maxTokens);
errorMaxFreeMintsReached();
errorMaxFreeMintsToSendReached();
errorNoFreeMintsLeft();
errorNoFreeMintsToSendLeft();
errorCannotSendToSelf();
errorMaxFreeMintsToSendReceived(address recipient);
constructor(uint256 initialMaxTokens) ERC721("tiny pepes", "tiny pepes") Ownable(msg.sender) {
maxTokens = initialMaxTokens;
}
functionsetCost(uint256 newCost) externalonlyOwner{
cost = newCost;
}
functionsetMaxTokens(uint256 newMaxTokens) externalonlyOwner{
maxTokens = newMaxTokens;
}
functionsetMaxFreeMints(uint256 newMaxFreeMints) externalonlyOwner{
maxFreeMints = newMaxFreeMints;
}
functionsetMaxFreeMintsToSend(uint256 newMaxFreeMintsToSend) externalonlyOwner{
maxFreeMintsToSend = newMaxFreeMintsToSend;
}
functionsetMaxFreeMintsToSendPerAddress(uint256 newMaxFreeMintsToSendPerAddress) externalonlyOwner{
maxFreeMintsToSendPerAddress = newMaxFreeMintsToSendPerAddress;
}
functiontoggleMinting(bool _enabled) externalonlyOwner{
mintingEnabled = _enabled;
}
functionsetRoyalties(address recipient, uint96 percentage) externalonlyOwner{
require(percentage <=10000, "Percentage too high");
royaltyRecipient = recipient;
royaltyPercentage = percentage;
}
functionmint(stringmemory base64Image,
stringmemory name,
stringmemory description,
stringmemory attributes
) externalpayablenonReentrant{
if (msg.value!= cost) {
revert NotEnoughEtherProvided(cost, msg.value);
}
require(mintingEnabled, "Minting is disabled");
require(_tokenIds < maxTokens, "Max tokens reached");
_tokenIds++;
stringmemory tokenURI = generateTokenURI(_tokenIds, base64Image, name, description, attributes);
_mint(msg.sender, _tokenIds);
_setTokenURI(_tokenIds, tokenURI);
emit TokenMinted(_tokenIds);
}
functionbatchMint(uint256 numberOfTokens,
string[] memory base64Images,
string[] memory names,
string[] memory descriptions,
string[] memory attributes
) externalpayablenonReentrant{
require(msg.value== cost * numberOfTokens, "Incorrect payment amount");
batchMint(msg.sender, numberOfTokens, base64Images, names, descriptions, attributes);
}
functionbatchMintTo(address recipient,
uint256 numberOfTokens,
string[] memory base64Images,
string[] memory names,
string[] memory descriptions,
string[] memory attributes
) externalpayablenonReentrant{
require(msg.value== cost * numberOfTokens, "Incorrect payment amount");
batchMint(recipient, numberOfTokens, base64Images, names, descriptions, attributes);
}
functionbatchMint(address recipient,
uint256 numberOfTokens,
string[] memory base64Images,
string[] memory names,
string[] memory descriptions,
string[] memory attributes
) internal{
require(mintingEnabled, "Minting is disabled");
require(_tokenIds + numberOfTokens <= maxTokens, "Minting exceeds max tokens limit");
require(
base64Images.length== numberOfTokens &&
names.length== numberOfTokens &&
descriptions.length== numberOfTokens &&
attributes.length== numberOfTokens,
"Number of metadata fields does not match number of tokens"
);
uint256 startTokenId = _tokenIds +1;
for (uint256 i =0; i < numberOfTokens; i++) {
_tokenIds++;
stringmemory tokenURI = generateTokenURI(_tokenIds, base64Images[i], names[i], descriptions[i], attributes[i]);
_mint(recipient, _tokenIds);
_setTokenURI(_tokenIds, tokenURI);
}
emit BatchMinted(startTokenId, numberOfTokens);
}
functionairdrop(address to,
stringmemory base64Image,
stringmemory name,
stringmemory description,
stringmemory attributes
) externalonlyOwner{
require(_tokenIds < maxTokens, "Max tokens reached");
_tokenIds++;
stringmemory tokenURI = generateTokenURI(_tokenIds, base64Image, name, description, attributes);
_mint(to, _tokenIds);
_setTokenURI(_tokenIds, tokenURI);
emit Airdropped(_tokenIds, to);
}
functionbatchAirdrop(address[] memory recipients,
string[] memory base64Images,
string[] memory names,
string[] memory descriptions,
string[] memory attributes
) externalonlyOwner{
require(recipients.length== base64Images.length, "Recipients and images length mismatch");
require(recipients.length== names.length, "Recipients and names length mismatch");
require(recipients.length== descriptions.length, "Recipients and descriptions length mismatch");
require(recipients.length== attributes.length, "Recipients and attributes length mismatch");
require(_tokenIds + recipients.length<= maxTokens, "Minting exceeds max tokens limit");
uint256[] memory tokenIds =newuint256[](recipients.length);
for (uint256 i =0; i < recipients.length; i++) {
_tokenIds++;
stringmemory tokenURI = generateTokenURI(_tokenIds, base64Images[i], names[i], descriptions[i], attributes[i]);
_mint(recipients[i], _tokenIds);
_setTokenURI(_tokenIds, tokenURI);
tokenIds[i] = _tokenIds;
}
emit BatchAirdropped(tokenIds, recipients);
}
functionfreemint(uint256 numberOfTokens,
string[] memory base64Images,
string[] memory names,
string[] memory descriptions,
string[] memory attributes
) externalnonReentrant{
require(mintingEnabled, "Minting is disabled");
FreeMintInfo storage info = freeMintList[msg.sender];
require(info.allowed >= info.minted + numberOfTokens, "No free mints left for this address");
require(currentFreeMints + numberOfTokens <= maxFreeMints, "Max free mints reached");
require(_tokenIds + numberOfTokens <= maxTokens, "Max tokens reached");
uint256 startTokenId = _tokenIds +1;
for (uint256 i =0; i < numberOfTokens; i++) {
_tokenIds++;
stringmemory tokenURI = generateTokenURI(_tokenIds, base64Images[i], names[i], descriptions[i], attributes[i]);
_mint(msg.sender, _tokenIds);
_setTokenURI(_tokenIds, tokenURI);
info.minted++;
currentFreeMints++;
}
emit BatchMinted(startTokenId, numberOfTokens);
}
functionfreeminttosend(address recipient,
uint256 numberOfTokens,
string[] memory base64Images,
string[] memory names,
string[] memory descriptions,
string[] memory attributes
) externalnonReentrant{
require(mintingEnabled, "Minting is disabled");
require(msg.sender!= recipient, "Cannot send to self");
FreeMintInfo storage info = freeMintToSendList[msg.sender];
require(info.allowed >= info.minted + numberOfTokens, "No free mints to send left for this address");
require(currentFreeMintsToSend + numberOfTokens <= maxFreeMintsToSend, "Max free mints to send reached");
require(_tokenIds + numberOfTokens <= maxTokens, "Max tokens reached");
require(freeMintsToSendReceived[recipient] + numberOfTokens <= maxFreeMintsToSendPerAddress, "Recipient has reached max free mints to send");
uint256 startTokenId = _tokenIds +1;
for (uint256 i =0; i < numberOfTokens; i++) {
_tokenIds++;
stringmemory tokenURI = generateTokenURI(_tokenIds, base64Images[i], names[i], descriptions[i], attributes[i]);
_mint(recipient, _tokenIds);
_setTokenURI(_tokenIds, tokenURI);
info.minted++;
currentFreeMintsToSend++;
freeMintsToSendReceived[recipient]++;
}
emit BatchMinted(startTokenId, numberOfTokens);
}
functionupdateFreeMintList(address[] memory addresses, uint256[] memory allowedAmounts) externalonlyOwner{
require(addresses.length== allowedAmounts.length, "Addresses and amounts length mismatch");
for (uint256 i =0; i < addresses.length; i++) {
freeMintList[addresses[i]].allowed = allowedAmounts[i];
freeMintList[addresses[i]].minted =0;
}
}
functionremoveFreeMintList(address[] memory addresses) externalonlyOwner{
for (uint256 i =0; i < addresses.length; i++) {
delete freeMintList[addresses[i]];
}
}
functionupdateFreeMintToSendList(address[] memory addresses, uint256[] memory allowedAmounts) externalonlyOwner{
require(addresses.length== allowedAmounts.length, "Addresses and amounts length mismatch");
for (uint256 i =0; i < addresses.length; i++) {
freeMintToSendList[addresses[i]].allowed = allowedAmounts[i];
freeMintToSendList[addresses[i]].minted =0;
}
}
functionremoveFreeMintToSendList(address[] memory addresses) externalonlyOwner{
for (uint256 i =0; i < addresses.length; i++) {
delete freeMintToSendList[addresses[i]];
}
}
functionbatchUpdateFreeMintList(address[] memory addresses, uint256[] memory allowedAmounts) externalonlyOwner{
require(addresses.length== allowedAmounts.length, "Addresses and amounts length mismatch");
for (uint256 i =0; i < addresses.length; i++) {
freeMintList[addresses[i]].allowed = allowedAmounts[i];
freeMintList[addresses[i]].minted =0;
}
}
functionbatchUpdateFreeMintToSendList(address[] memory addresses, uint256[] memory allowedAmounts) externalonlyOwner{
require(addresses.length== allowedAmounts.length, "Addresses and amounts length mismatch");
for (uint256 i =0; i < addresses.length; i++) {
freeMintToSendList[addresses[i]].allowed = allowedAmounts[i];
freeMintToSendList[addresses[i]].minted =0;
}
}
functionupdateTokenURI(uint256 tokenId, stringmemory base64Image, stringmemory name, stringmemory description, stringmemory attributes) externalonlyOwner{
require(!_isMetadataLocked(tokenId), "Metadata is locked");
require(!allMetadataLocked, "All metadata is locked");
stringmemory tokenURI = generateTokenURI(tokenId, base64Image, name, description, attributes);
_setTokenURI(tokenId, tokenURI);
}
functionlockTokenURI() externalonlyOwner{
allMetadataLocked =true;
}
functionwithdraw() publiconlyOwner{
(bool success, ) =msg.sender.call{value: address(this).balance}("");
require(success, "Transfer failed.");
}
functiongetEthBalance() publicviewreturns (uint256) {
returnaddress(this).balance;
}
functiongetFreeMintsAllowed(address account) publicviewreturns (uint256) {
return freeMintList[account].allowed;
}
functiongetFreeMintsDone(address account) publicviewreturns (uint256) {
return freeMintList[account].minted;
}
functiongetFreeMintsRemaining(address account) publicviewreturns (uint256) {
return freeMintList[account].allowed - freeMintList[account].minted;
}
functiongetFreeMintsToSendAllowed(address account) publicviewreturns (uint256) {
return freeMintToSendList[account].allowed;
}
functiongetFreeMintsToSendDone(address account) publicviewreturns (uint256) {
return freeMintToSendList[account].minted;
}
functiongetFreeMintsToSendRemaining(address account) publicviewreturns (uint256) {
return freeMintToSendList[account].allowed - freeMintToSendList[account].minted;
}
functiongetFreeMintsToSendReceived(address account) publicviewreturns (uint256) {
return freeMintsToSendReceived[account];
}
// Generate token URI based on the token ID and base64 imagefunctiongenerateTokenURI(uint256 tokenId,
stringmemory base64Image,
stringmemory name,
stringmemory description,
stringmemory attributes
) privatepurereturns (stringmemory) {
stringmemory json =string(abi.encodePacked(
'{"name":"', name, ' #', Strings.toString(tokenId), '","description":"', description, '","image":"data:image/png;base64,', base64Image, '","attributes":', attributes, '}'
));
stringmemory base64Json = base64Encode(bytes(json));
returnstring(abi.encodePacked(
"data:application/json;base64,", base64Json
));
}
// Base64 encoding functionfunctionbase64Encode(bytesmemory data) internalpurereturns (stringmemory) {
bytesmemory alphabet ="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
uint256 encodedLen =4* ((data.length+2) /3);
bytesmemory result =newbytes(encodedLen);
for (uint256 i =0; i < data.length; i +=3) {
(result[i /3*4], result[i /3*4+1], result[i /3*4+2], result[i /3*4+3]) = encode3to4(
uint8(data[i]),
i +1< data.length ? uint8(data[i +1]) : 0,
i +2< data.length ? uint8(data[i +2]) : 0,
alphabet
);
}
// Add padding if necessaryif ((data.length%3) ==1) {
result[encodedLen -1] ="=";
result[encodedLen -2] ="=";
} elseif ((data.length%3) ==2) {
result[encodedLen -1] ="=";
}
returnstring(result);
}
functionencode3to4(uint8 a, uint8 b, uint8 c, bytesmemory alphabet) privatepurereturns (bytes1, bytes1, bytes1, bytes1) {
return (
alphabet[a >>2],
alphabet[((a &3) <<4) | (b >>4)],
alphabet[((b &15) <<2) | (c >>6)],
alphabet[c &63]
);
}
// EIP-2981: NFT Royalty StandardfunctionroyaltyInfo(uint256, uint256 salePrice) externalviewoverridereturns (address receiver, uint256 royaltyAmount) {
receiver = royaltyRecipient;
royaltyAmount = (salePrice * royaltyPercentage) /10000;
}
// IERC165: Interface DetectionfunctionsupportsInterface(bytes4 interfaceId) publicviewvirtualoverride(ERC721URIStorage, IERC165) returns (bool) {
return interfaceId ==type(IERC2981).interfaceId||super.supportsInterface(interfaceId);
}
// Internal function to check if metadata is lockedfunction_isMetadataLocked(uint256 tokenId) internalviewreturns (bool) {
return metadataLocked[tokenId];
}
}
Contract Source Code
File 13 of 17: Ownable.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)pragmasolidity ^0.8.20;import {Context} from"../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/abstractcontractOwnableisContext{
addressprivate _owner;
/**
* @dev The caller account is not authorized to perform an operation.
*/errorOwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/errorOwnableInvalidOwner(address owner);
eventOwnershipTransferred(addressindexed previousOwner, addressindexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/constructor(address initialOwner) {
if (initialOwner ==address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/modifieronlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/functionowner() publicviewvirtualreturns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/function_checkOwner() internalviewvirtual{
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/functionrenounceOwnership() publicvirtualonlyOwner{
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/functiontransferOwnership(address newOwner) publicvirtualonlyOwner{
if (newOwner ==address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/function_transferOwnership(address newOwner) internalvirtual{
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
Contract Source Code
File 14 of 17: ReentrancyGuard.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*/abstractcontractReentrancyGuard{
// Booleans are more expensive than uint256 or any type that takes up a full// word because each write operation emits an extra SLOAD to first read the// slot's contents, replace the bits taken up by the boolean, and then write// back. This is the compiler's defense against contract upgrades and// pointer aliasing, and it cannot be disabled.// The values being non-zero value makes deployment a bit more expensive,// but in exchange the refund on every call to nonReentrant will be lower in// amount. Since refunds are capped to a percentage of the total// transaction's gas, it is best to keep them low in cases like this one, to// increase the likelihood of the full refund coming into effect.uint256privateconstant _NOT_ENTERED =1;
uint256privateconstant _ENTERED =2;
uint256private _status;
constructor() {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and make it call a
* `private` function that does the actual work.
*/modifiernonReentrant() {
// On the first call to nonReentrant, _notEntered will be truerequire(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
_;
// By storing the original value once again, a refund is triggered (see// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
}
Contract Source Code
File 15 of 17: SignedMath.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol)pragmasolidity ^0.8.20;/**
* @dev Standard signed math utilities missing in the Solidity language.
*/librarySignedMath{
/**
* @dev Returns the largest of two signed numbers.
*/functionmax(int256 a, int256 b) internalpurereturns (int256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two signed numbers.
*/functionmin(int256 a, int256 b) internalpurereturns (int256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two signed numbers without overflow.
* The result is rounded towards zero.
*/functionaverage(int256 a, int256 b) internalpurereturns (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.
*/functionabs(int256 n) internalpurereturns (uint256) {
unchecked {
// must be unchecked in order to support `n = type(int256).min`returnuint256(n >=0 ? n : -n);
}
}
}
Contract Source Code
File 16 of 17: Strings.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol)pragmasolidity ^0.8.20;import {Math} from"./math/Math.sol";
import {SignedMath} from"./math/SignedMath.sol";
/**
* @dev String operations.
*/libraryStrings{
bytes16privateconstant HEX_DIGITS ="0123456789abcdef";
uint8privateconstant ADDRESS_LENGTH =20;
/**
* @dev The `value` string doesn't fit in the specified `length`.
*/errorStringsInsufficientHexLength(uint256 value, uint256 length);
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/functiontoString(uint256 value) internalpurereturns (stringmemory) {
unchecked {
uint256 length = Math.log10(value) +1;
stringmemory buffer =newstring(length);
uint256 ptr;
/// @solidity memory-safe-assemblyassembly {
ptr :=add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assemblyassembly {
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.
*/functiontoStringSigned(int256 value) internalpurereturns (stringmemory) {
returnstring.concat(value <0 ? "-" : "", toString(SignedMath.abs(value)));
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/functiontoHexString(uint256 value) internalpurereturns (stringmemory) {
unchecked {
return toHexString(value, Math.log256(value) +1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/functiontoHexString(uint256 value, uint256 length) internalpurereturns (stringmemory) {
uint256 localValue = value;
bytesmemory buffer =newbytes(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);
}
returnstring(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal
* representation.
*/functiontoHexString(address addr) internalpurereturns (stringmemory) {
return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH);
}
/**
* @dev Returns true if the two strings are equal.
*/functionequal(stringmemory a, stringmemory b) internalpurereturns (bool) {
returnbytes(a).length==bytes(b).length&&keccak256(bytes(a)) ==keccak256(bytes(b));
}
}
Contract Source Code
File 17 of 17: draft-IERC6093.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol)pragmasolidity ^0.8.20;/**
* @dev Standard ERC20 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC20 tokens.
*/interfaceIERC20Errors{
/**
* @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.
*/errorERC20InsufficientBalance(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.
*/errorERC20InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/errorERC20InvalidReceiver(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.
*/errorERC20InsufficientAllowance(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.
*/errorERC20InvalidApprover(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.
*/errorERC20InvalidSpender(address spender);
}
/**
* @dev Standard ERC721 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC721 tokens.
*/interfaceIERC721Errors{
/**
* @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.
*/errorERC721InvalidOwner(address owner);
/**
* @dev Indicates a `tokenId` whose `owner` is the zero address.
* @param tokenId Identifier number of a token.
*/errorERC721NonexistentToken(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.
*/errorERC721IncorrectOwner(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.
*/errorERC721InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/errorERC721InvalidReceiver(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.
*/errorERC721InsufficientApproval(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.
*/errorERC721InvalidApprover(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.
*/errorERC721InvalidOperator(address operator);
}
/**
* @dev Standard ERC1155 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC1155 tokens.
*/interfaceIERC1155Errors{
/**
* @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.
*/errorERC1155InsufficientBalance(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.
*/errorERC1155InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/errorERC1155InvalidReceiver(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.
*/errorERC1155MissingApprovalForAll(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.
*/errorERC1155InvalidApprover(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.
*/errorERC1155InvalidOperator(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
*/errorERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
}