Skip to content
Lattice

ERC721EnumerableLib

Git Source

Title: ERC721EnumerableLib

Authors: David Dada <daveproxy80@gmail.com> (https://github.com/dadadave80), Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC721/extensions/ERC721Enumerable.sol)

Library implementing the EIP-721 enumeration extension: every token id, and each owner's ids, in O(1) swap-and-pop lists. All logic lives here; the facet delegates.

The base ERC721Lib has no hook (D25, option (a)), so enumeration stays correct only while every token movement goes through _update here. The ERC721Enumerable facet replaces the base transfer selectors to do that. Any other code that moves a token on an enumerable diamond (a mint, a burn, or an authorization-free transfer) must call this library's _mint, _safeMint, _burn, _transfer, _safeTransfer or _update, never ERC721Lib's. ERC721Burnable and ERC721Wrapper call ERC721Lib directly, so they are mutually exclusive with this extension. The CCTPHookReceipt example also mints through ERC721Lib._mint; it is a standalone contract that cannot take this facet, and a fork of it that adds enumeration must mint here. Differences from OpenZeppelin v5.6.1:

  • OpenZeppelin overrides _update, so every internal path (_mint, _burn, _transfer, _safeTransfer) is enumerated automatically. Here only this library's wrappers are: ERC721Lib._transfer and the other ERC721Lib internals skip the lists.
  • OpenZeppelin overrides _increaseBalance to revert ERC721EnumerableForbiddenBatchMint. Here ERC721ConsecutiveLib._mintConsecutive reverts with it when this extension is registered, and __ERC721Enumerable_init reverts with it after batch minting was initialized, so either init order fails.
  • The enumeration lists start empty when the extension is initialized. Cut it into a fresh diamond: on a diamond that already holds tokens it would not list them.

Functions

erc721EnumerableStorage

function erc721EnumerableStorage() internal pure returns (ERC721EnumerableStorage storage $);

Returns

NameTypeDescription
$ERC721EnumerableStorage

__ERC721Enumerable_init

Registers the IERC721Enumerable interface for ERC-165 discovery.

Must be called inside a pre/postInitializer block. The lists start empty, so there is nothing to seed. Reverts IERC721Enumerable.ERC721EnumerableForbiddenBatchMint on a diamond that initialized batch minting (ERC721ConsecutiveLib), whose batches the lists would miss.

function __ERC721Enumerable_init() internal;

registerInterface

Registers support for the IERC721Enumerable interface via ERC-165.

function registerInterface() internal;

totalSupply

The number of tokens in existence.

function totalSupply() internal view returns (uint256);

Returns

NameTypeDescription
<none>uint256

tokenOfOwnerByIndex

The id at index of owner's tokens. Reverts IERC721Enumerable.ERC721OutOfBoundsIndex when index is past the owner's balance, and IERC721.ERC721InvalidOwner for a zero owner.

function tokenOfOwnerByIndex(address owner, uint256 index) internal view returns (uint256);

Parameters

NameTypeDescription
owneraddress
indexuint256

Returns

NameTypeDescription
<none>uint256

tokenByIndex

The id at index of all tokens. Reverts IERC721Enumerable.ERC721OutOfBoundsIndex with a zero owner when index is past totalSupply.

function tokenByIndex(uint256 index) internal view returns (uint256);

Parameters

NameTypeDescription
indexuint256

Returns

NameTypeDescription
<none>uint256

transferFrom

ERC721Lib.transferFrom with enumeration bookkeeping.

function transferFrom(address from, address to, uint256 tokenId) internal;

Parameters

NameTypeDescription
fromaddress
toaddress
tokenIduint256

safeTransferFrom

ERC721Lib.safeTransferFrom with enumeration bookkeeping.

function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) internal;

Parameters

NameTypeDescription
fromaddress
toaddress
tokenIduint256
databytes

_mint

ERC721Lib._mint with enumeration bookkeeping.

function _mint(address to, uint256 tokenId) internal;

Parameters

NameTypeDescription
toaddress
tokenIduint256

_safeMint

ERC721Lib._safeMint with enumeration bookkeeping.

function _safeMint(address to, uint256 tokenId, bytes memory data) internal;

Parameters

NameTypeDescription
toaddress
tokenIduint256
databytes

_burn

ERC721Lib._burn with enumeration bookkeeping.

function _burn(uint256 tokenId) internal;

Parameters

NameTypeDescription
tokenIduint256

_transfer

ERC721Lib._transfer with enumeration bookkeeping: moves tokenId without an authorization check, for permissioned or signature-based transfer paths.

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

Parameters

NameTypeDescription
fromaddress
toaddress
tokenIduint256

_safeTransfer

ERC721Lib._safeTransfer with enumeration bookkeeping. The receiver sees msg.sender as operator.

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

Parameters

NameTypeDescription
fromaddress
toaddress
tokenIduint256
databytes

_update

ERC721Lib._update followed by OpenZeppelin's enumeration bookkeeping. Returns the previous owner.

Runs after the base update, so _balances already holds the post-move balances the list indices use.

function _update(address to, uint256 tokenId, address auth) internal returns (address previousOwner);

Parameters

NameTypeDescription
toaddress
tokenIduint256
authaddress

Returns

NameTypeDescription
previousOwneraddress

_addTokenToOwnerEnumeration

Appends tokenId to to's list. to's balance already counts it, so its slot is balance - 1.

function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private;

Parameters

NameTypeDescription
toaddress
tokenIduint256

_addTokenToAllTokensEnumeration

Appends tokenId to the global list.

function _addTokenToAllTokensEnumeration(uint256 tokenId) private;

Parameters

NameTypeDescription
tokenIduint256

_removeTokenFromOwnerEnumeration

Swap-and-pop tokenId out of from's list. from's balance already excludes it, so the balance is the index of the last entry. _ownedTokensIndex[tokenId] is cleared here and rewritten by the add.

function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private;

Parameters

NameTypeDescription
fromaddress
tokenIduint256

_removeTokenFromAllTokensEnumeration

Swap-and-pop tokenId out of the global list. Like OpenZeppelin, it swaps even when tokenId is last.

function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private;

Parameters

NameTypeDescription
tokenIduint256