ERC-6150 Hierarchical NFT (Hierarchical NFTs)
Final · NFTs & multi-token · created 2022-12-15
An EIP-721 extension standard that creates parent and child relationships between NFTs, so that a filesystem-like tree structure can be managed within a single contract.
Why it is needed
Like a computer filesystem where folders contain folders and files, many services use hierarchical structures. eBay's categories, Reddit's boards and posts, and Twitter's lists are all examples. However, the existing NFT standard EIP-721 treats each token as independent, so there is no way to express which token belongs under which. To put such relationships on-chain, each project has to build its own approach, and external programs such as wallets and apps have no common way to read the structure. This standard defines a common interface for parent lookup, child list lookup, and checks for whether a token is a root (top) or a leaf (bottom), so that entire directories and categories can be managed as NFTs in a single contract and anyone can query the structure in the same way.
What to implement
function parentOf(uint256 tokenId) external view returns (uint256 parentId);: Looks up the parent token of the tokenId token.function isRoot(uint256 tokenId) external view returns (bool);: Checks whether the tokenId token is a root token.function isLeaf(uint256 tokenId) external view returns (bool);: Checks whether the tokenId token is a leaf token.function childrenCountOf(uint256 parentId) external view returns (uint256);: Looks up the total number of child tokens under parentId. If parentId is 0, it means the total number of root tokens.function safeBurn(uint256 tokenId) external;: Burns the tokenId token. Fails if it is not a leaf token.function safeBatchBurn(uint256[] memory tokenIds) external;: Burns multiple tokens at once. Fails if any one of them is not a leaf token.function transferParent(uint256 newParentId, uint256 tokenId) external;: Moves the parent of the tokenId token to the newParentId token.function isAdminOf(uint256 tokenId, address account) external view returns (bool);: Checks whether account is a manager of the tokenId token. A single token can have multiple managers.function canBurnTokenByAccount(uint256 tokenId, address account) external view returns (bool);: Checks whether account can burn the tokenId token.
In depth
EIP-721 extension and required interfaces
This standard is an extension of EIP-721, and a compatible contract MUST implement this proposal together with the EIP-721 and EIP-165 interfaces. The ERC-165 identifier of the core interface IERC6150 is 0x897e2c73. It is fully backward compatible with EIP-721, so existing NFT tools can also treat these tokens as ordinary NFTs.
Tree structure and token ID rules
All NFTs form a single hierarchical tree, and each token can be at any position: root, leaf, parent, or child. When a new token is minted, the parent-child relationship is announced through the Minted event, and when a root token is minted, parentId is set to 0. Therefore a token with ID 0 cannot be an actual node, and the token ID of an actual node must be greater than 0. Because looking up nodes above and below is common, parentOf is standardized to look up the parent and childrenOf to look up all children, and isRoot and isLeaf check whether a token is a root or a leaf.
Enumerable extension
An optional extension for enumerating and looking up child nodes one by one. childrenCountOf returns the number of children under a parent, childOfParentByIndex returns the token ID of the child at a given index, and indexInChildrenEnumeration returns the position of a given token in the child list. All three functions take a parentId argument, and for compatibility a parentId of 0 means the lookup targets root nodes. The ERC-165 identifier of this extension is 0xba541a2e.
Burnable extension and the leaf restriction
An optional extension that burns tokens with safeBurn and safeBatchBurn. It is defined to fail if the token to burn is not a leaf token, is not a valid NFT, or if the caller is not the owner, an approved operator, or the approved address of that token. In other words, an intermediate node that has children cannot be deleted directly. The ERC-165 identifier of this extension is 0x4ac0aa46.
ParentTransferable extension
An optional extension that lets a token's parent be changed, like moving a file or directory to another directory in a filesystem. transferParent moves one token and batchTransferParent moves multiple tokens under a new parent, and when the parent changes, the ParentTransferred event records the previous parent and the new parent. The ERC-165 identifier of this extension is 0xfa574808.
Access Control extension
In hierarchical structures, permissions for actions such as minting children, transferring, and burning are often shared among several accounts. This extension standardizes the permission check functions. isAdminOf checks whether an account is an admin of the token, and each token can have multiple admins. canMintChildren checks the permission to mint children under a given parent, and canBurnTokenByAccount checks the burn permission. If parentId is 0, the query is about the permission to mint at the root. The ERC-165 identifier of this extension is 0x1d04f0b3.
Use cases and benefits of on-chain storage
The source lists any application with a tree structure as a use case, including on-chain forums like Reddit, on-chain social media like Twitter, on-chain legal entities that manage organizational structure, and on-chain e-commerce like eBay. Because the entire hierarchy is stored on-chain, governance can be attached through a DAO contract, a single contract manages all relationships, directory ownership can be transferred as an NFT, and a frontend can read the data without permission. The source presents these as its advantages. The tokenURI of each token can hold any kind of metadata, such as another contract address or a website link.