除了元資料擴充功能以外,為了能方便查詢發行量、能依序列出所有未被銷毀的 NFT、以及能列舉特定帳戶持有的 NFT,因此設計出這個介面。
interface ERC721Enumerable /* is ERC721 */ {
/// 回傳目前發行的 ERC721 總量
function totalSupply() external view returns (uint256);
/// 回傳第 `_index` 個未被銷毀的 NFT tokenId
function tokenByIndex(uint256 _index) external view returns (uint256);
/// 回傳第 `_index` 個由 `_owner` 帳戶持有的 NFT tokenId
function tokenOfOwnerByIndex(address _owner, uint256 _index) external view returns (uint256);
}
當然,凡事都有代價,尤其是要方便查詢的話,自然需要在區塊鏈上多儲存資訊。以 OpenZeppelin 的 ERC721 Enumerable 合約為例,我們可以發現它新增了以下幾個狀態變數:
// 映射擁有者到他所持有的 NFT 列表
// 擁有者位址 => Index => TokenId
mapping(address => mapping(uint256 => uint256)) private _ownedTokens;
// 映射 token ID 到擁有者的 NFT 列表中的 Index
// TokenId => Index of `_ownedTokens`
mapping(uint256 => uint256) private _ownedTokensIndex;
// 用來儲存所有 token ID,因此可以快速查詢總發行量,也能方便列舉
uint256[] private _allTokens;
// 映射 token ID 到所有 token ID 陣列的 Index
// token ID => Index of `_allTokens`
mapping(uint256 => uint256) private _allTokensIndex;
由於提供此功能所付出的代價不低,因此也有其他的 ERC721 的變種,就讓我們後面再來聊聊吧。