ERC-721

This set of interfaces, contracts, and utilities are all related to the ERC-721 Non-Fungible Token Standard.

For a walk through on how to create an ERC-721 token read our ERC-721 guide.

The ERC specifies four interfaces:

  • IERC721: Core functionality required in all compliant implementation.

  • IERC721Metadata: Optional extension that adds name, symbol, and token URI, almost always included.

  • IERC721Enumerable: Optional extension that allows enumerating the tokens on chain, often not included since it requires large gas overhead.

  • IERC721Receiver: An interface that must be implemented by contracts if they want to accept tokens through safeTransferFrom.

OpenZeppelin Contracts provides implementations of all four interfaces:

  • ERC721: The core and metadata extensions, with a base URI mechanism.

  • ERC721Enumerable: The enumerable extension.

  • ERC721Holder: A bare bones implementation of the receiver interface.

Additionally there are a few of other extensions:

  • ERC721Consecutive: An implementation of ERC-2309 for minting batchs of tokens during construction, in accordance with ERC-721.

  • ERC721URIStorage: A more flexible but more expensive way of storing metadata.

  • ERC721Votes: Support for voting and vote delegation.

  • ERC721Royalty: A way to signal royalty information following ERC-2981.

  • ERC721Pausable: A primitive to pause contract operation.

  • ERC721Burnable: A way for token holders to burn their own tokens.

  • ERC721Wrapper: Wrapper to create an ERC-721 backed by another ERC-721, with deposit and withdraw methods. Useful in conjunction with ERC721Votes.

This core set of contracts is designed to be unopinionated, allowing developers to access the internal functions in ERC-721 (such as _mint) and expose them as external functions in the way they prefer.

Core

IERC721

import "@openzeppelin/contracts/token/ERC721/IERC721.sol";

Required interface of an ERC-721 compliant contract.

balanceOf(address owner) → uint256 balance external

Returns the number of tokens in owner's account.

ownerOf(uint256 tokenId) → address owner external

Returns the owner of the tokenId token.

Requirements:

  • tokenId must exist.

safeTransferFrom(address from, address to, uint256 tokenId, bytes data) external

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.

safeTransferFrom(address from, address to, uint256 tokenId) external

Safely transfers tokenId token from from to to, checking first that contract recipients are aware of the ERC-721 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.

transferFrom(address from, address to, uint256 tokenId) external

Transfers tokenId token from from to to.

Note that the caller is responsible to confirm that the recipient is capable of receiving ERC-721 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.

approve(address to, uint256 tokenId) external

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.

setApprovalForAll(address operator, bool approved) external

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.

getApproved(uint256 tokenId) → address operator external

Returns the account approved for tokenId token.

Requirements:

  • tokenId must exist.

isApprovedForAll(address owner, address operator) → bool external

Returns if the operator is allowed to manage all of the assets of owner.

Transfer(address indexed from, address indexed to, uint256 indexed tokenId) event

Emitted when tokenId token is transferred from from to to.

Approval(address indexed owner, address indexed approved, uint256 indexed tokenId) event

Emitted when owner enables approved to manage the tokenId token.

ApprovalForAll(address indexed owner, address indexed operator, bool approved) event

Emitted when owner enables or disables (approved) operator to manage all of its assets.

IERC721Metadata

import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol";

name() → string external

Returns the token collection name.

symbol() → string external

Returns the token collection symbol.

tokenURI(uint256 tokenId) → string external

Returns the Uniform Resource Identifier (URI) for tokenId token.

IERC721Enumerable

import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol";

totalSupply() → uint256 external

Returns the total amount of tokens stored by the contract.

tokenOfOwnerByIndex(address owner, uint256 index) → uint256 external

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.

tokenByIndex(uint256 index) → uint256 external

Returns a token ID at a given index of all the tokens stored by the contract. Use along with totalSupply to enumerate all tokens.

ERC721

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";

Implementation of ERC-721 Non-Fungible Token Standard, including the Metadata extension, but not including the Enumerable extension, which is available separately as ERC721Enumerable.

constructor(string name_, string symbol_) internal

Initializes the contract by setting a name and a symbol to the token collection.

supportsInterface(bytes4 interfaceId) → bool public

balanceOf(address owner) → uint256 public

ownerOf(uint256 tokenId) → address public

name() → string public

symbol() → string public

tokenURI(uint256 tokenId) → string public

_baseURI() → string internal

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.

approve(address to, uint256 tokenId) public

getApproved(uint256 tokenId) → address public

setApprovalForAll(address operator, bool approved) public

isApprovedForAll(address owner, address operator) → bool public

transferFrom(address from, address to, uint256 tokenId) public

safeTransferFrom(address from, address to, uint256 tokenId) public

safeTransferFrom(address from, address to, uint256 tokenId, bytes data) public

_ownerOf(uint256 tokenId) → address internal

Returns the owner of the tokenId. Does NOT revert if token doesn’t exist

Any overrides to this function that add ownership of tokens not tracked by the core ERC-721 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.

_getApproved(uint256 tokenId) → address internal

Returns the approved address for tokenId. Returns 0 if tokenId is not minted.

_isAuthorized(address owner, address spender, uint256 tokenId) → bool internal

Returns whether spender is allowed to manage owner’s tokens, or `tokenId in particular (ignoring whether it is owned by owner).

This function assumes that owner is the actual owner of tokenId and does not verify this assumption.

_checkAuthorized(address owner, address spender, uint256 tokenId) internal

Checks if spender can operate on tokenId, assuming the provided owner is the actual owner. Reverts if: - spender does not have approval from owner for tokenId. - spender does not have approval to manage all of `owner’s assets.

This function assumes that owner is the actual owner of tokenId and does not verify this assumption.

_increaseBalance(address account, uint128 value) internal

Unsafe write access to the balances, used by extensions that "mint" tokens using an ownerOf override.

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.
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.

_update(address to, uint256 tokenId, address auth) → address internal

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.

If overriding this function in a way that tracks balances, see also _increaseBalance.

_mint(address to, uint256 tokenId) internal

Mints tokenId and transfers it to to.

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.

_safeMint(address to, uint256 tokenId) internal

Mints tokenId, transfers it to to and checks for to acceptance.

Requirements:

Emits a Transfer event.

_safeMint(address to, uint256 tokenId, bytes data) internal

Same as _safeMint, with an additional data parameter which is forwarded in IERC721Receiver.onERC721Received to contract recipients.

_burn(uint256 tokenId) internal

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.

_transfer(address from, address to, uint256 tokenId) internal

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.

_safeTransfer(address from, address to, uint256 tokenId) internal

Safely transfers tokenId token from from to to, checking that contract recipients are aware of the ERC-721 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.

_safeTransfer(address from, address to, uint256 tokenId, bytes data) internal

Same as _safeTransfer, with an additional data parameter which is forwarded in IERC721Receiver.onERC721Received to contract recipients.

_approve(address to, uint256 tokenId, address auth) internal

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.

_approve(address to, uint256 tokenId, address auth, bool emitEvent) internal

Variant of _approve with an optional flag to enable or disable the Approval event. The event is not emitted in the context of transfers.

_setApprovalForAll(address owner, address operator, bool approved) internal

Approve operator to operate on all of owner tokens

Requirements: - operator can’t be the address zero.

Emits an ApprovalForAll event.

_requireOwned(uint256 tokenId) → address internal

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.

ERC721Enumerable

import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";

This implements an optional extension of ERC721 defined in the ERC that adds enumerability of all the token ids in the contract as well as all token ids owned by each account.

ERC721 extensions that implement custom balanceOf logic, such as ERC721Consecutive, interfere with enumerability and should not be used together with ERC721Enumerable.

supportsInterface(bytes4 interfaceId) → bool public

tokenOfOwnerByIndex(address owner, uint256 index) → uint256 public

totalSupply() → uint256 public

tokenByIndex(uint256 index) → uint256 public

_update(address to, uint256 tokenId, address auth) → address internal

_increaseBalance(address account, uint128 amount) internal

ERC721OutOfBoundsIndex(address owner, uint256 index) error

An owner’s token query was out of bounds for `index.

The owner being address(0) indicates a global out of bounds index.

ERC721EnumerableForbiddenBatchMint() error

Batch mint is not allowed.

IERC721Receiver

import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";

Interface for any contract that wants to support safeTransfers from ERC-721 asset contracts.

onERC721Received(address operator, address from, uint256 tokenId, bytes data) → bytes4 external

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.

Extensions

ERC721Pausable

import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Pausable.sol";

ERC-721 token with pausable token transfers, minting and burning.

Useful for scenarios such as preventing trades until the end of an evaluation period, or having an emergency switch for freezing all token transfers in the event of a large bug.

This contract does not include public pause and unpause functions. In addition to inheriting this contract, you must define both functions, invoking the Pausable._pause and Pausable._unpause internal functions, with appropriate access control, e.g. using AccessControl or Ownable. Not doing so will make the contract pause mechanism of the contract unreachable, and thus unusable.

_update(address to, uint256 tokenId, address auth) → address internal

Requirements:

  • the contract must not be paused.

ERC721Burnable

import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol";

ERC-721 Token that can be burned (destroyed).

burn(uint256 tokenId) public

Burns tokenId. See ERC721._burn.

Requirements:

  • The caller must own tokenId or be an approved operator.

ERC721Consecutive

import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Consecutive.sol";

Implementation of the ERC-2309 "Consecutive Transfer Extension" as defined in ERC-2309.

This extension allows the minting of large batches of tokens, during contract construction only. For upgradeable contracts this implies that batch minting is only available during proxy deployment, and not in subsequent upgrades. These batches are limited to 5000 tokens at a time by default to accommodate off-chain indexers.

Using this extension removes the ability to mint single tokens during contract construction. This ability is regained after construction. During construction, only batch minting is allowed.

This extension does not call the _update function for tokens minted in batch. Any logic added to this function through overrides will not be triggered when token are minted in batch. You may want to also override _increaseBalance or _mintConsecutive to account for these mints.
When overriding _mintConsecutive, be careful about call ordering. ownerOf may return invalid values during the _mintConsecutive execution if the super call is not called first. To be safe, execute the super call before your custom logic.

_maxBatchSize() → uint96 internal

Maximum size of a batch of consecutive tokens. This is designed to limit stress on off-chain indexing services that have to record one entry per token, and have protections against "unreasonably large" batches of tokens.

Overriding the default value of 5000 will not cause on-chain issues, but may result in the asset not being correctly supported by off-chain indexing services (including marketplaces).

_ownerOf(uint256 tokenId) → address internal

See ERC721._ownerOf. Override that checks the sequential ownership structure for tokens that have been minted as part of a batch, and not yet transferred.

_mintConsecutive(address to, uint96 batchSize) → uint96 internal

Mint a batch of tokens of length batchSize for to. Returns the token id of the first token minted in the batch; if batchSize is 0, returns the number of consecutive ids minted so far.

Requirements:

  • batchSize must not be greater than _maxBatchSize.

  • The function is called in the constructor of the contract (directly or indirectly).

Does not emit a Transfer event. This is ERC-721 compliant as long as it is done inside of the constructor, which is enforced by this function.
Does not invoke onERC721Received on the receiver.

_update(address to, uint256 tokenId, address auth) → address internal

See ERC721._update. Override version that restricts normal minting to after construction.

Using ERC721Consecutive prevents minting during construction in favor of _mintConsecutive. After construction, _mintConsecutive is no longer available and minting through _update becomes available.

_firstConsecutiveId() → uint96 internal

Used to offset the first token id in {_nextConsecutiveId}

ERC721ForbiddenBatchMint() error

Batch mint is restricted to the constructor. Any batch mint not emitting the IERC721.Transfer event outside of the constructor is non ERC-721 compliant.

ERC721ExceededMaxBatchMint(uint256 batchSize, uint256 maxBatch) error

Exceeds the max amount of mints per batch.

ERC721ForbiddenMint() error

Individual minting is not allowed.

ERC721ForbiddenBatchBurn() error

Batch burn is not supported.

ERC721URIStorage

import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";

ERC-721 token with storage based token URI management.

supportsInterface(bytes4 interfaceId) → bool public

tokenURI(uint256 tokenId) → string public

_setTokenURI(uint256 tokenId, string _tokenURI) internal

Sets _tokenURI as the tokenURI of tokenId.

Emits {MetadataUpdate}.

ERC721Votes

import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Votes.sol";

Extension of ERC-721 to support voting and delegation as implemented by Votes, where each individual NFT counts as 1 vote unit.

Tokens do not count as votes until they are delegated, because votes must be tracked which incurs an additional cost on every transfer. Token holders can either delegate to a trusted representative who will decide how to make use of the votes in governance decisions, or they can delegate to themselves to be their own representative.

_update(address to, uint256 tokenId, address auth) → address internal

See ERC721._update. Adjusts votes when tokens are transferred.

_getVotingUnits(address account) → uint256 internal

Returns the balance of account.

Overriding this function will likely result in incorrect vote tracking.

_increaseBalance(address account, uint128 amount) internal

See ERC721._increaseBalance. We need that to account tokens that were minted in batch.

ERC721Royalty

import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Royalty.sol";

Extension of ERC-721 with the ERC-2981 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.

ERC-2981 only specifies a way to signal royalty information and does not enforce its payment. See Rationale in the ERC. Marketplaces are expected to voluntarily pay royalties together with sales, but note that this standard is not yet widely supported.

supportsInterface(bytes4 interfaceId) → bool public

ERC721Wrapper

import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Wrapper.sol";

Extension of the ERC-721 token contract to support token wrapping.

Users can deposit and withdraw an "underlying token" and receive a "wrapped token" with a matching tokenId. This is useful in conjunction with other modules. For example, combining this wrapping mechanism with ERC721Votes will allow the wrapping of an existing "basic" ERC-721 into a governance token.

constructor(contract IERC721 underlyingToken) internal

depositFor(address account, uint256[] tokenIds) → bool public

Allow a user to deposit underlying tokens and mint the corresponding tokenIds.

withdrawTo(address account, uint256[] tokenIds) → bool public

Allow a user to burn wrapped tokens and withdraw the corresponding tokenIds of the underlying tokens.

onERC721Received(address, address from, uint256 tokenId, bytes) → bytes4 public

Overrides IERC721Receiver.onERC721Received to allow minting on direct ERC-721 transfers to this contract.

In case there’s data attached, it validates that the operator is this contract, so only trusted data is accepted from depositFor.

Doesn’t work with unsafe transfers (eg. IERC721.transferFrom). Use ERC721Wrapper._recover for recovering in that scenario.

_recover(address account, uint256 tokenId) → uint256 internal

Mint a wrapped token to cover any underlyingToken that would have been transferred by mistake. Internal function that can be exposed with access control if desired.

underlying() → contract IERC721 public

Returns the underlying token.

ERC721UnsupportedToken(address token) error

The received ERC-721 token couldn’t be wrapped.

Utilities

ERC721Holder

import "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol";

Implementation of the IERC721Receiver interface.

Accepts all token transfers. Make sure the contract is able to use its token with IERC721.safeTransferFrom, IERC721.approve or IERC721.setApprovalForAll.

onERC721Received(address, address, uint256, bytes) → bytes4 public

Always returns IERC721Receiver.onERC721Received.selector.

ERC721Utils

import "@openzeppelin/contracts/token/ERC721/utils/ERC721Utils.sol";

Library that provide common ERC-721 utility functions.

See ERC-721.

Available since v5.1.

checkOnERC721Received(address operator, address from, address to, uint256 tokenId, bytes data) internal

Performs an acceptance check for the provided operator by calling {IERC721-onERC721Received} on the to address. The operator is generally the address that initiated the token transfer (i.e. msg.sender).

The acceptance call is not executed and treated as a no-op if the target address doesn’t contain code (i.e. an EOA). Otherwise, the recipient must implement IERC721Receiver.onERC721Received and return the acceptance magic value to accept the transfer.