{"id":"ERC-6147","name":"Guard of NFT/SBT","status":"Final","chain":"both","category":{"id":"security","name":"Security & Trust","description":"Helping users verify, control, and protect their assets"},"journeyStages":[{"id":"management","name":"Asset Management","description":"Managing assets over time"}],"uxImpact":"ERC-6147 extends ERC-721 with a guard role and an expiry timestamp that separate holding from transfer authority. While a guard is valid, the owner, approved address, and operators cannot transfer or change the guard; the guard can change or remove itself and can transfer the token through transferAndRemove. It does not define a pending owner request or approval queue.","officialUrl":"https://ercs.ethereum.org/ERCS/erc-6147","lastReviewed":"2026-09-18","lastUpdated":"2026-09-18","kind":"proposal","hasDetailedContent":true,"content":{"id":"ERC-6147","summary":"ERC-6147 extends ERC-721 with a guard role and an expiry timestamp that separate holding from transfer authority. While a guard is valid, the owner, approved address, and operators cannot transfer or change the guard; the guard can change or remove itself and can transfer the token through transferAndRemove. It does not define a pending owner request or approval queue.","applicability":{"whenToUse":["An NFT needs a guard that can directly control transfer/removal while the owner retains the token.","The product can show guardInfo, expiry, and owner/operator restrictions.","Any request queue, recovery service, or cooldown is implemented and labeled as application behavior."],"whenToAvoid":["The NFT does not implement guardInfo, changeGuard, removeGuard, and transferAndRemove.","The product requires an owner-request and guard-approval queue as a protocol guarantee.","The app cannot show guard-controlled transfer/removal and owner/operator restrictions."]},"designerTakeaways":["Show guardInfo(tokenId), including the guard address and its expiry, before offering transfer controls.","Model a valid guard as direct transfer/removal authority and explain that owner/operator paths are blocked while it is valid.","Label any request queue, recovery service, or cooldown as application behavior layered on the guard interface."],"problemsSolved":[{"problem":"An owner wants transfer protection without moving the NFT to a custodian","oldWay":"Transfer to a protection or lending contract and lose the normal holding path","newWay":"Assign a guard that controls transfer while the owner retains the token","impact":"high"},{"problem":"A lending or recovery arrangement needs a time bound","oldWay":"Keep a separate off-chain deadline that the contract cannot expose","newWay":"Read the guard address and expires value from guardInfo","impact":"high"},{"problem":"A valid guard must move or release a token","oldWay":"Invent an owner request and approval workflow","newWay":"Use the guard-authorized changeGuard, removeGuard, or transferAndRemove paths","impact":"high"},{"problem":"Users cannot tell why a transfer is blocked","oldWay":"Show a generic transaction failure","newWay":"Explain the active guard, expiry, and authority that can act","impact":"medium"}],"uxPatterns":[{"name":"Guard Status Display","description":"Show the guard address, valid-until timestamp, and transfer authority on the NFT detail view.","userFlow":["User views the NFT","App reads guardInfo(tokenId)","Shows guard address and expiry or no active guard","Explains which account can transfer or remove the guard"]},{"name":"Change Guard Interface","description":"Expose changeGuard only when the connected account is authorized by the current guard state.","userFlow":["User selects a new guard and expiry","App explains whether owner, operator, approved address, or current guard may act","User reviews the exact changeGuard call","Receipt updates guardInfo"]},{"name":"Guard-Controlled Transfer","description":"Make the direct guard transfer path visible; any request or service queue is an application layer.","userFlow":["Guard opens a guarded NFT","App confirms the current guard and expiry","Guard reviews recipient and transferAndRemove","Receipt shows the guard removed and ownership changed"]},{"name":"Guard Dashboard","description":"List guarded NFTs and the direct actions available to the guard.","userFlow":["Guard opens the dashboard","Sees active guards and expiry","Chooses removeGuard, changeGuard, or transferAndRemove where authorized","App shows the resulting event and state"]}],"uiComponents":[{"name":"GuardStatusCard","description":"Current guardInfo and authority disclosure.","states":["No guard","Guard active","Guard expired"],"props":["guard address","expires","owner/operator transfer status"]},{"name":"ChangeGuardForm","description":"Form for the exact changeGuard(tokenId, newGuard, expires) call.","states":["Editable","Wallet confirmation","Updated","Rejected"],"props":["token ID","new guard","expiry"]},{"name":"GuardActionFlow","description":"Direct guard actions for removal or transfer.","states":["Guard action available","Submitting","Confirmed","Failed"],"props":["recipient","action","guardInfo","implementation policy"]},{"name":"TransferRestrictionNotice","description":"Explains owner/operator limits while a valid guard is active.","states":["Blocked for owner","Guard can act","Guard expired"],"props":["guard","expiry","recovery guidance"]}],"antiPatterns":[{"pattern":"Showing an owner request and guard approval queue as the protocol flow","why":"ERC-6147 does not define request, approve, or deny functions; a valid guard directly controls transfer and removal.","instead":"Show the exact guard authority and label any queue as application behavior.","severity":"critical"},{"pattern":"Calling setGuard or getGuard","why":"The required interface names are changeGuard, removeGuard, transferAndRemove, and guardInfo.","instead":"Use the exact interface names and read the returned address and uint64 expiry.","severity":"critical"},{"pattern":"Promising a guard can block every action forever","why":"Guard validity ends at expires and implementation integrations can add their own behavior.","instead":"Show the current guardInfo state and issuer-defined recovery policy.","severity":"high"},{"pattern":"Hiding direct guard authority behind a generic transfer error","why":"The owner may be blocked while the guard can act directly.","instead":"Explain the active guard and which actions are available to each role.","severity":"high"}],"keyTakeaways":["ERC-6147 separates holding from transfer authority through a guard and expires timestamp.","Use changeGuard, removeGuard, transferAndRemove, and guardInfo; do not invent an approval queue.","A valid guard blocks owner/operator/approved transfers and can act directly.","Show the current guard and expiry at render and action time."],"specConstraints":[{"id":"erc-6147-guard-expiry","constraint":"A guard is valid only before its expires time.","appliesTo":"application","normativity":"normative","specQuote":"A guard Must be valid only before expires.","specSection":"Specification","specUrl":"https://ercs.ethereum.org/ERCS/erc-6147#specification","designImplication":"Re-read guardInfo and compare expiry at render and action time; show an expired guard as inactive rather than as permanent authority."},{"id":"erc-6147-empty-guard-info","constraint":"With no guard or an expired guard, guardInfo returns the zero address and zero expiry.","appliesTo":"application","normativity":"normative","specQuote":"When a token has no guard or the guard is expired, `guardInfo` MUST return `(address(0), 0)`.","specSection":"Specification","specUrl":"https://ercs.ethereum.org/ERCS/erc-6147#specification","designImplication":"Use the specified zero tuple for the no-active-guard state and do not leave stale guard identity in the UI after expiry."},{"id":"erc-6147-expired-guard-authority","constraint":"When no guard is active, the owner, authorized operators, and approved address may set guard and expiry.","appliesTo":"wallet","normativity":"normative","specQuote":"When a token has no guard or the guard is expired, owner, authorised operators and approved address of the token MUST have permission to set guard and expires.","specSection":"Specification","specUrl":"https://ercs.ethereum.org/ERCS/erc-6147#specification","designImplication":"Show which ERC-721 authority can assign a new guard after expiry and keep that path separate from the active-guard path."},{"id":"erc-6147-valid-guard-blocks-owner","constraint":"While a guard is valid, the owner, authorized operators, and approved address cannot change guard/expiry or transfer the token.","appliesTo":"wallet","normativity":"normative","specQuote":"When a token has a valid guard, owner, authorised operators and approved address of the token MUST NOT be able to change guard and expires, and they MUST NOT be able to transfer the token.","specSection":"Specification","specUrl":"https://ercs.ethereum.org/ERCS/erc-6147#specification","designImplication":"Explain a blocked owner/operator transfer as active guard authority, not a generic wallet failure, and show the expiry that ends the restriction."},{"id":"erc-6147-valid-guard-info","constraint":"With a valid guard, guardInfo returns that guard address and its expiry.","appliesTo":"application","normativity":"normative","specQuote":"When a token has a valid guard, `guardInfo` MUST return the address and expires of the guard.","specSection":"Specification","specUrl":"https://ercs.ethereum.org/ERCS/erc-6147#specification","designImplication":"Display the active guard and exact expiry as the source of transfer authority before a user signs or relies on the restriction."},{"id":"erc-6147-guard-direct-authority","constraint":"A valid guard can remove or change the guard and transfer the token.","appliesTo":"wallet","normativity":"normative","specQuote":"When a token has a valid guard, the guard MUST be able to remove guard and expires, change guard and expires, and transfer the token.","specSection":"Specification","specUrl":"https://ercs.ethereum.org/ERCS/erc-6147#specification","designImplication":"Present direct guard actions and their recipient/expiry consequences; do not invent an owner request queue as the protocol flow."},{"id":"erc-6147-burn-clears-guard","constraint":"Burning a guarded token deletes its guard.","appliesTo":"account-implementation","normativity":"normative","specQuote":"When a token has a valid guard, if the token burns, the guard MUST be deleted.","specSection":"Specification","specUrl":"https://ercs.ethereum.org/ERCS/erc-6147#specification","designImplication":"Remove guard status from burned-token views and history state instead of leaving a guard attached to a nonexistent asset."},{"id":"erc-6147-update-event","constraint":"UpdateGuardLog is emitted when a guard changes.","appliesTo":"application","normativity":"normative","specQuote":"The `UpdateGuardLog` event MUST be emitted when a guard is changed.","specSection":"Specification — Contract Interface","specUrl":"https://ercs.ethereum.org/ERCS/erc-6147#contract-interface","designImplication":"Use guard-update events to refresh the NFT status and show who changed the guard, the new address, and expiry."},{"id":"erc-6147-interface-detection","constraint":"supportsInterface returns true for ERC-6147 interface id 0xb61d1057.","appliesTo":"application","normativity":"normative","specQuote":"The `supportsInterface` method MUST return `true` when called with `0xb61d1057`.","specSection":"Specification — Contract Interface","specUrl":"https://ercs.ethereum.org/ERCS/erc-6147#contract-interface","designImplication":"Use the ERC-165 identifier as the minimum capability gate before showing guard controls."},{"id":"erc-6147-erc721-compatibility","constraint":"Without a guard, an ERC-6147 extension remains compatible with existing ERC-721 behavior.","appliesTo":"application","normativity":"backwards-compatibility","specQuote":"This standard can be fully ERC-721 compatible by adding an extension function set.\n\nIf an NFT issued based on the above standard does not set a `guard`, then it is no different in the existing functions from the current NFT issued based on the ERC-721 standard.","specSection":"Backwards Compatibility","specUrl":"https://ercs.ethereum.org/ERCS/erc-6147#backwards-compatibility","designImplication":"Keep the unguarded NFT path familiar and introduce the extra guard status only when the contract reports an active guard."},{"id":"erc-6147-expiry-policy","constraint":"The guard expiry should be appropriate to the specific application scenario.","appliesTo":"application","normativity":"security-considerations","specQuote":"Make sure to set an appropriate `expires` for the `guard`, based on the specific application scenario.","specSection":"Security Considerations","specUrl":"https://ercs.ethereum.org/ERCS/erc-6147#security-considerations","designImplication":"Explain the chosen expiry and the recovery behavior after it, rather than presenting a default duration as universally safe."},{"id":"erc-6147-market-transfer-block","constraint":"A valid guard blocks operator and owner transfer/sale paths, including approvals used by trading platforms.","appliesTo":"application","normativity":"security-considerations","specQuote":"When an NFT has a valid guard, even if an address is authorized as an operator through `approve` or `setApprovalForAll`, the operator still has no right to transfer the NFT.\n\nWhen an NFT has a valid guard, the `owner` cannot sell the NFT.","specSection":"Security Considerations","specUrl":"https://ercs.ethereum.org/ERCS/erc-6147#security-considerations","designImplication":"Keep marketplace listing and transfer states aligned with guardInfo; do not show an active listing as executable while the valid guard blocks sale."},{"id":"erc-6147-listing-check","constraint":"Trading platforms are recommended to prevent listing guarded NFTs by checking guardInfo.","appliesTo":"application","normativity":"security-considerations","specQuote":"Some trading platforms list NFTs through `setApprovalForAll` and owners' signature. It is recommended to prevent listing these NFTs by checking `guardInfo`.","specSection":"Security Considerations","specUrl":"https://ercs.ethereum.org/ERCS/erc-6147#security-considerations","designImplication":"At listing time, read guardInfo and show a guarded/unlistable state; preserve the source's recommendation strength rather than calling it a protocol MUST."},{"id":"erc-6147-sbt-recovery","constraint":"An SBT SHOULD have a recovery path when the wallet holding it is lost, stolen, or unavailable.","appliesTo":"application","normativity":"rationale","specQuote":"The SBTs essentially realizes the separation of NFT holding right and transfer right. When the wallet where SBT is located is stolen or unavailable, SBT should be able to be recoverable.","specSection":"Motivation","specUrl":"https://ercs.ethereum.org/ERCS/erc-6147#motivation","designImplication":"Expose the recovery authority and its conditions as policy layered on the guard interface; do not imply that the base standard supplies a recovery service."},{"id":"erc-6147-issuer-retrieval","constraint":"An SBT issuer SHOULD have a policy-backed ability to retrieve the token when its governing institution requires revocation.","appliesTo":"application","normativity":"rationale","specQuote":"In addition, SBTs still need to be managed in use. For example, if a university issues diploma-based SBTs to its graduates, and if the university later finds that a graduate has committed academic misconduct or jeopardized the reputation of the university, it should have the ability to retrieve the diploma-based SBTs.","specSection":"Motivation","specUrl":"https://ercs.ethereum.org/ERCS/erc-6147#motivation","designImplication":"Make issuer retrieval a visible, policy-backed administrative path with clear consequences; avoid presenting it as an unqualified holder transfer."},{"id":"erc-6147-erc721-extension-optionality","constraint":"ERC-721 compliant contracts MAY implement the ERC-6147 extension.","appliesTo":"account-implementation","normativity":"normative","specQuote":"ERC-721 compliant contracts MAY implement this EIP.","specSection":"Specification","specUrl":"https://ercs.ethereum.org/ERCS/erc-6147#specification","designImplication":"Detect the ERC-6147 interface before showing guard controls; an ERC-721 token does not imply guard support."},{"id":"erc-6147-designated-sbt-guard","constraint":"When issuing or minting SBTs, the guard MAY be uniformly set to a designated address to facilitate management.","appliesTo":"account-implementation","normativity":"normative","specQuote":"If issuing or minting SBTs, the guard MAY be uniformly set to the designated address to facilitate management.","specSection":"Specification","specUrl":"https://ercs.ethereum.org/ERCS/erc-6147#specification","designImplication":"If an issuer uses a uniform guard, disclose that designated authority and its management role while keeping the choice visibly implementation-specific."}],"technicalNotes":"ERC-6147 extends ERC-721 with changeGuard(uint256 tokenId, address newGuard, uint64 expires), removeGuard(uint256 tokenId), transferAndRemove(address from, address to, uint256 tokenId), and guardInfo(uint256 tokenId) returning (address guard, uint64 expires). With a valid guard, the owner, authorized operators, and approved address cannot change the guard or transfer; the guard can change/remove the guard and transfer. The standard defines no pending request, approve, deny, setGuard, or getGuard function.","lastUpdated":"2026-09-18","sources":[{"label":"ERC-6147 official specification","url":"https://ercs.ethereum.org/ERCS/erc-6147","type":"official-spec"}],"lastReviewed":"2026-09-18","partialDeployment":{"body":"This guide describes an interface-specific integration. A live deployment has not been verified here. Confirm the target contract, network, and client support before offering these actions; Final describes the specification, not product availability."}},"sources":[{"label":"Official specification","url":"https://ercs.ethereum.org/ERCS/erc-6147","type":"official-spec"},{"label":"Discussion search","url":"https://ethereum-magicians.org/search?q=ERC-6147","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-6147","markdown":"https://www.eipsfordesigners.com/standards/ERC-6147/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-6147/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-6147","official":"https://ercs.ethereum.org/ERCS/erc-6147","discussion":"https://ethereum-magicians.org/search?q=ERC-6147"},"freshness":{"lastReviewed":"2026-09-18","lastUpdated":"2026-09-18"}}