ERC721EnumerableLib
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._transferand the other ERC721Lib internals skip the lists. - OpenZeppelin overrides
_increaseBalanceto revertERC721EnumerableForbiddenBatchMint. HereERC721ConsecutiveLib._mintConsecutivereverts 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
| Name | Type | Description |
|---|---|---|
| $ | 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
| Name | Type | Description |
|---|---|---|
| <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
| Name | Type | Description |
|---|---|---|
| owner | address | |
| index | uint256 |
Returns
| Name | Type | Description |
|---|---|---|
| <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
| Name | Type | Description |
|---|---|---|
| index | uint256 |
Returns
| Name | Type | Description |
|---|---|---|
| <none> | uint256 |
transferFrom
ERC721Lib.transferFrom with enumeration bookkeeping.
function transferFrom(address from, address to, uint256 tokenId) internal;Parameters
| Name | Type | Description |
|---|---|---|
| from | address | |
| to | address | |
| tokenId | uint256 |
safeTransferFrom
ERC721Lib.safeTransferFrom with enumeration bookkeeping.
function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) internal;Parameters
| Name | Type | Description |
|---|---|---|
| from | address | |
| to | address | |
| tokenId | uint256 | |
| data | bytes |
_mint
ERC721Lib._mint with enumeration bookkeeping.
function _mint(address to, uint256 tokenId) internal;Parameters
| Name | Type | Description |
|---|---|---|
| to | address | |
| tokenId | uint256 |
_safeMint
ERC721Lib._safeMint with enumeration bookkeeping.
function _safeMint(address to, uint256 tokenId, bytes memory data) internal;Parameters
| Name | Type | Description |
|---|---|---|
| to | address | |
| tokenId | uint256 | |
| data | bytes |
_burn
ERC721Lib._burn with enumeration bookkeeping.
function _burn(uint256 tokenId) internal;Parameters
| Name | Type | Description |
|---|---|---|
| tokenId | uint256 |
_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
| Name | Type | Description |
|---|---|---|
| from | address | |
| to | address | |
| tokenId | uint256 |
_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
| Name | Type | Description |
|---|---|---|
| from | address | |
| to | address | |
| tokenId | uint256 | |
| data | bytes |
_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
| Name | Type | Description |
|---|---|---|
| to | address | |
| tokenId | uint256 | |
| auth | address |
Returns
| Name | Type | Description |
|---|---|---|
| previousOwner | address |
_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
| Name | Type | Description |
|---|---|---|
| to | address | |
| tokenId | uint256 |
_addTokenToAllTokensEnumeration
Appends tokenId to the global list.
function _addTokenToAllTokensEnumeration(uint256 tokenId) private;Parameters
| Name | Type | Description |
|---|---|---|
| tokenId | uint256 |
_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
| Name | Type | Description |
|---|---|---|
| from | address | |
| tokenId | uint256 |
_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
| Name | Type | Description |
|---|---|---|
| tokenId | uint256 |