{"id":"ERC-7401","name":"Parent-Governed NFT Nesting","status":"Final","chain":"both","category":{"id":"nft","name":"NFT Capabilities","description":"What NFTs can do beyond basic ownership"},"journeyStages":[{"id":"asset-display","name":"Asset Discovery & Display","description":"Seeing tokens, NFTs, and balances"},{"id":"executing","name":"Executing Transactions","description":"Performing on-chain actions"},{"id":"management","name":"Asset Management","description":"Managing assets over time"}],"uxImpact":"ERC-7401 is the Final successor to ERC-6059 for parent-governed NFT nesting. It preserves the nesting model while correcting the interface identifier; compatible collections can expose accepted and pending children, and products should verify the target implementation before promising transfer or extraction behavior.","officialUrl":"https://ercs.ethereum.org/ERCS/erc-7401","lastReviewed":"2026-09-18","lastUpdated":"2026-09-18","kind":"proposal","hasDetailedContent":true,"content":{"id":"ERC-7401","sources":[{"label":"Official specification","url":"https://ercs.ethereum.org/ERCS/erc-7401","type":"official-spec"}],"lastReviewed":"2026-09-18","lastUpdated":"2026-09-18","summary":"ERC-7401 is the Final successor to ERC-6059 for parent-governed NFT nesting. It preserves the nesting model while correcting the interface identifier; compatible collections can expose accepted and pending children, and products should verify the target implementation before promising transfer or extraction behavior.","designerTakeaways":["Design expandable trees that distinguish accepted children from pending proposals.","Preview the accepted child list before a parent transfer and explain the target contract's resulting ownership state.","Prefer ERC-7401 for new integrations; label ERC-6059 as the superseded predecessor when supporting legacy collections."],"applicability":{"whenToUse":["NFTs bundle other NFTs as packs or containers.","Parent-governed control over nested inventory matters.","You implement ERC-7401 superseding ERC-6059."],"whenToAvoid":["Flat ERC-721 collections with no nesting.","Users never compose or unpack bundles.","Indexer lacks nested ownership graph support."]},"prototypeFirst":[{"screen":"Nested tree inventory","why":"Collectors browse bundles as filesystem-like trees.","covers":["Expanded parent","Collapsed children","Deep nest"],"include":["Tree expand/collapse","Child count badge","Nested inside label"]},{"screen":"Pending child acceptance","why":"Proposed children need explicit accept.","covers":["Pending","Accepted","Declined"],"include":["Parent preview","Child preview","Accept/Decline CTAs"]},{"screen":"Bundle transfer confirmation","why":"Sending parent must list all children moving.","covers":["Single child","Many children"],"include":["Child list in confirm modal","Total items count","Irreversible note"]},{"screen":"Unnest or extract child","why":"Owners remove children from parent when allowed.","covers":["Allowed unnest","Blocked by parent rules"],"include":["Extract action","Parent permission check","Result state"]}],"mentalModel":[{"label":"Parent NFT","description":"Container token that governs nested children."},{"label":"Child NFT","description":"Token nested under parent — may show Nested inside status."},{"label":"Propose-commit","description":"Child transfer proposed first; recipient accepts to complete nest."},{"label":"Bundle transfer","description":"Moving parent drags all accepted children with it."},{"label":"Root owner","description":"Who ultimately controls the top-level parent in a deep tree."}],"statesToDesign":[{"state":"Pending child proposal","trigger":"Someone proposed nesting a child.","userNeed":"Review before accepting into bundle.","designResponse":"Inbox item with Accept/Decline and parent context."},{"state":"Nested — child inside parent","trigger":"Child accepted.","userNeed":"Find child within parent tree.","designResponse":"Nested inside badge; child hidden from flat grid or indented."},{"state":"Parent transfer with children","trigger":"Owner sends parent.","userNeed":"Know entire bundle moves.","designResponse":"Confirmation lists all child previews."},{"state":"Empty parent container","trigger":"Parent has no children.","userNeed":"Still use as container.","designResponse":"Empty slot UI with Add child action if supported."},{"state":"Deep hierarchy limit","trigger":"Tree exceeds display depth.","userNeed":"Navigate without overwhelm.","designResponse":"Truncate with View full tree link."}],"designDecisions":[{"question":"Flat grid vs tree default?","recommendation":"Tree for nest-heavy collections; flat with Nested filter for mixed.","rationale":"Flat grids hide nested assets entirely."},{"question":"Show full ancestry path?","recommendation":"Breadcrumb on child detail: Root › Pack › Item.","rationale":"Deep nests need orientation."},{"question":"Drag-drop nesting?","recommendation":"Optional power feature; always confirm with propose-commit.","rationale":"Accidental drags nest wrong items."}],"problemsSolved":[{"problem":"NFT bundles invisible in wallet","oldWay":"Only top-level tokens shown","newWay":"Tree view exposes nested children","impact":"high"},{"problem":"Surprise bundle transfers","oldWay":"Parent send moves unknown children","newWay":"Confirmation lists all nested items","impact":"critical"},{"problem":"Unwanted nested gifts","oldWay":"Children land without consent","newWay":"Accept/Decline propose-commit inbox","impact":"high"}],"uxPatterns":[{"name":"NFT Tree Navigator","description":"Expandable hierarchy for parent-child tokens.","components":["TreeView","NestBadge","ChildCount"],"userFlow":["Open collection","Expand parent","See children","Open child detail"]},{"name":"Bundle Transfer Preview","description":"List all children in parent send confirm.","components":["ChildList","BundleCount","ConfirmModal"],"userFlow":["User sends parent","Modal lists children","User confirms","Bundle moves"]}],"antiPatterns":[{"pattern":"Flat wallet hiding nested children","why":"Users think children disappeared","instead":"Tree view or Nested inside filter","severity":"critical"},{"pattern":"Parent transfer without child list","why":"Accidental loss of valuable nested items","instead":"Bundle preview on every parent send","severity":"critical"},{"pattern":"Auto-accept nested proposals","why":"Spam nesting attacks inventory","instead":"Explicit Accept/Decline inbox","severity":"high"}],"vocabulary":[{"use":"Inside this bundle","avoid":"Child token nested under parentId","why":"Bundle metaphor over graph terms."},{"use":"Accept into bundle","avoid":"Commit child nest","why":"Inbox action language."},{"use":"Moves with parent","avoid":"Inherits nesting on transfer","why":"Plain transfer consequence."}],"specConstraints":[{"id":"recursive-burn-limit","constraint":"Recursive burns must revert when the configured maximum cannot cover the children to burn.","appliesTo":"application","normativity":"normative","specQuote":"* @dev When specifying the maximum recursive burns, the execution MUST be reverted if there are more children to be","specSection":"Specification","specUrl":"https://ercs.ethereum.org/ERCS/erc-7401#specification","designImplication":"Burn confirmation should show the recursive scope and a failure state when the maximum child count is too small."},{"id":"no-descendant-cycle","constraint":"A destination token must not be a child or downstream descendant of the token being transferred.","appliesTo":"application","normativity":"normative","specQuote":"* @dev The destination token MUST NOT be a child token of the token being transferred or one of its downstream","specSection":"Specification","specUrl":"https://ercs.ethereum.org/ERCS/erc-7401#specification","designImplication":"Nested-transfer UI must prevent cyclic destinations and explain the hierarchy conflict before signing."},{"id":"safe-nest-transfer","constraint":"nestTransfer must verify IERC7401 compatibility at the destination.","appliesTo":"application","normativity":"rationale","specQuote":"6. **Why is there not a \"safe\" nest transfer method?**\\\n`nestTransfer` is always \"safe\" since it MUST check for `IERC7059` compatibility on the destination.","specSection":"Rationale","specUrl":"https://ercs.ethereum.org/ERCS/erc-7401#rationale","designImplication":"Present a compatibility check in nesting flows and keep unsupported-destination failures distinct from ordinary transfer rejection."},{"id":"pending-commit","constraint":"Child additions use a propose-commit flow, with pending state before acceptance or rejection.","appliesTo":"application","normativity":"rationale","specQuote":"Adding child tokens to a parent token MUST be done in the form of propose-commit pattern to allow for limited mutability by a 3rd party. When adding a child token to a parent token, it is first placed in a *\"Pending\"* array, and MUST be migrated to the *\"Active\"* array by the parent token's root owner. The *\"Pending\"* child tokens array SHOULD be limited to 128 slots to prevent spam and griefing.","specSection":"Rationale > Propose-Commit pattern for child token management","specUrl":"https://ercs.ethereum.org/ERCS/erc-7401#propose-commit-pattern-for-child-token-management","designImplication":"Show pending and active child states separately and give the authorized parent/root actor an explicit accept or reject action."},{"id":"pending-cap","constraint":"The pending child array should stay below its bounded capacity to reduce spam/griefing.","appliesTo":"application","normativity":"normative","specQuote":"*  - the pending array of the parent contract MUST not be full.","specSection":"Specification","specUrl":"https://ercs.ethereum.org/ERCS/erc-7401#specification","designImplication":"Surface pending-capacity pressure and prevent a parent-management UI from implying unlimited pending children."},{"id":"root-vs-direct-owner","constraint":"The standard distinguishes recursive root ownership from immediate parent ownership.","appliesTo":"application","normativity":"rationale","specQuote":"We continue to use ERC-721's `ownerOf` functionality which will now recursively look up through parents until it finds an address which is not an NFT, this is referred to as the *root owner*. Additionally we provide the `directOwnerOf` which returns the most immediate owner of a token using 3 values: the owner address, the tokenId which MUST be 0 if the direct owner is not an NFT, and a flag indicating whether or not the parent is an NFT.","specSection":"Rationale > Parent Governed pattern","specUrl":"https://ercs.ethereum.org/ERCS/erc-7401#parent-governed-pattern","designImplication":"Show both root owner and direct parent in nested-asset views; do not treat the wallet that ultimately controls the tree as the immediate transfer authority in every action."},{"id":"parent-governance","constraint":"The root owner or approved party may govern children while a nested child is controlled by its parent NFT.","appliesTo":"application","normativity":"rationale","specQuote":"The root owner or an approved party MUST be able to do the following operations on children: `acceptChild`, `rejectAllChildren` and `transferChild`.","specSection":"Rationale > Parent Governed pattern","specUrl":"https://ercs.ethereum.org/ERCS/erc-7401#parent-governed-pattern","designImplication":"Scope controls to the authority that can actually accept, reject, transfer, or burn the nested asset and explain why a child may be unavailable to the root wallet."},{"id":"erc721-ownership-compat","constraint":"Nestable ownership remains compatible with ERC-721 tooling while recursively resolving root ownership.","appliesTo":"application","normativity":"backwards-compatibility","specQuote":"## Backwards Compatibility\n\nThe Nestable token standard has been made compatible with [ERC-721](./eip-721.md) in order to take advantage of the robust tooling available for implementations of ERC-721 and to ensure compatibility with existing ERC-721 infrastructure.\n\nThe only incompatibility with ERC-721 is that Nestable tokens cannot use a token ID of 0.\n\nThere is some differentiation of how the `ownerOf` method behaves compared to ERC-721. The `ownerOf` method will now recursively look up through parent tokens until it finds an address that is not an NFT; this is referred to as the *root owner*. Additionally, we provide the `directOwnerOf`, which returns the most immediate owner of a token using 3 values: the owner address, the `tokenId`, which MUST be 0 if the direct owner is not an NFT, and a flag indicating whether or not the parent is an NFT. In case the token is owned by an EoA or an ERC-721 Receiver, the `ownerOf` method will behave the same as in ERC-721.","specSection":"Backwards Compatibility","specUrl":"https://ercs.ethereum.org/ERCS/erc-7401#backwards-compatibility","designImplication":"Reuse ERC-721 display and transfer conventions where they remain valid, but label nesting and recursive ownership explicitly."},{"id":"nested-sale-integrity","constraint":"A child set can change after a sale, and hidden implementation logic may exist in child-management operations.","appliesTo":"application","normativity":"security-considerations","specQuote":"## Security Considerations\n\nThe same security considerations as with [ERC-721](./eip-721.md) apply: hidden logic may be present in any of the functions, including burn, add child, accept child, and more.\n\nSince the current owner of the token is allowed to manage the token, there is a possibility that after the parent token is listed for sale, the seller might remove a child token just before before the sale and thus the buyer would not receive the expected child token. This is a risk that is inherent to the design of this standard. Marketplaces should take this into account and provide a way to verify the expected child tokens are present when the parent token is being sold or to guard against such a malicious behaviour in another way.\n\nIt is worth noting that `balanceOf` method only accounts for immediate tokens owned by the address; the tokens that are nested into a token owned by this address will not be reflected in this value as the recursive lookup needed in order to calculate this value is potentially too deep and might break the method.\n\nCaution is advised when dealing with non-audited contracts.","specSection":"Security Considerations","specUrl":"https://ercs.ethereum.org/ERCS/erc-7401#security-considerations","designImplication":"Marketplaces and portfolio views should recheck expected children and surface that nested composition is mutable and implementation-dependent."}],"technicalNotes":"ERC-7401 supersedes ERC-6059; always preview children on parent transfer.","relatedStandards":[{"id":"ERC-6059","relationship":"Prior nesting standard superseded by 7401"},{"id":"ERC-721","relationship":"Base NFT with nesting extension"}]},"sources":[{"label":"Official specification","url":"https://ercs.ethereum.org/ERCS/erc-7401","type":"official-spec"},{"label":"Discussion search","url":"https://ethereum-magicians.org/search?q=ERC-7401","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-7401","markdown":"https://www.eipsfordesigners.com/standards/ERC-7401/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-7401/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-7401","official":"https://ercs.ethereum.org/ERCS/erc-7401","discussion":"https://ethereum-magicians.org/search?q=ERC-7401"},"freshness":{"lastReviewed":"2026-09-18","lastUpdated":"2026-09-18"}}