{"id":"ERC-7066","name":"Lockable Extension for ERC-721","status":"Final","chain":"both","category":{"id":"nft","name":"NFT Capabilities","description":"What NFTs can do beyond basic ownership"},"journeyStages":[{"id":"management","name":"Asset Management","description":"Managing assets over time"}],"uxImpact":"NFTs can be locked in the owner's wallet. While locked, ERC-721 approval and transfer are restricted, with an exception when the caller is both the approved address and the locker; other application utility is implementation-specific.","officialUrl":"https://ercs.ethereum.org/ERCS/erc-7066","lastReviewed":"2026-09-18","lastUpdated":"2026-09-18","kind":"proposal","hasDetailedContent":true,"content":{"id":"ERC-7066","specConstraints":[{"id":"locker-assignment","constraint":"Locking assigns a locker who can unlock the token, and unlocking clears that locker.","appliesTo":"application","normativity":"normative","specQuote":"Token owner MAY `lock` the token and assign `locker` to some `address` using `lock(uint256 tokenId, address _locker)` function, this MUST set `locker` to `_locker`. Token owner or approved MAY `lock` the token using `lock(uint256 tokenId)` function, this MUST set `locker` to `msg.sender`. Token MAY be `unlocked` by `locker` using `unlock` function. `unlock` function MUST delete `locker` mapping and default to `address(0)`.","specSection":"Specification — Overview","specUrl":"https://ercs.ethereum.org/ERCS/erc-7066#overview","designImplication":"Show the locker and its unlock authority as part of the NFT state. Keep owner, approved account, and locker roles distinct."},{"id":"locker-status","constraint":"`lockerOf` returns the unlocking address for a locked token and the zero address for an unlocked token.","appliesTo":"application","normativity":"normative","specQuote":"If the token is `locked`, the `lockerOf` function MUST return an address that is `locker` and can `unlock` the token. For tokens that are not `locked`, the `lockerOf` function MUST return `address(0)`.","specSection":"Specification — Overview","specUrl":"https://ercs.ethereum.org/ERCS/erc-7066#overview","designImplication":"Use explicit Locked and Unlocked states and show the address that can release the lock."},{"id":"locked-transfer-rules","constraint":"Locked tokens cannot be approved or transferred except by a caller that is both approved and locker, and transfer clears locker and approval values.","appliesTo":"application","normativity":"normative","specQuote":"`lock` function MUST revert if token is already `locked`. `unlock` function MUST revert if token is not `locked`. ERC-721 `approve` function MUST revert if token is `locked`. ERC-721 functions that transfer ownership of a token MUST revert if token is `locked`, unless `msg.sender` is `approved` and `locker` both. After ERC-721 token transfer function call, values of `locker` and `approved` MUST be purged.","specSection":"Specification — Overview","specUrl":"https://ercs.ethereum.org/ERCS/erc-7066#overview","designImplication":"Disable ordinary approval and transfer actions while locked. Explain the exceptional unlock-and-transfer authority and clear stale controls after transfer."},{"id":"transfer-and-lock","constraint":"`transferAndLock` can transfer a token while assigning the locker and is recommended where later revocation is required.","appliesTo":"application","normativity":"normative","specQuote":"Token MAY be transferred and `locked`, also assign `approval` to `locker` using `transferAndLock` function. This is RECOMMENDED for use-cases where Token transfer and subsequent revocation is REQUIRED.","specSection":"Specification — Overview","specUrl":"https://ercs.ethereum.org/ERCS/erc-7066#overview","designImplication":"Review destination, locker, and later unlock path together. Do not describe transfer as complete without the new lock state."},{"id":"erc721-lock-compatibility","constraint":"The locking extension remains compatible with ERC-721 and can be adopted by upgraded ERC-721 contracts.","appliesTo":"application","normativity":"backwards-compatibility","specQuote":"## Backwards Compatibility\n\nThis standard is compatible with [ERC-721](./eip-721.md) standards.\n\nExisting Upgradedable [ERC-721](./eip-721.md) can upgrade to this standard, enabling locking capability inherently and unlock underlying liquidity features.","specSection":"Backwards Compatibility","specUrl":"https://ercs.ethereum.org/ERCS/erc-7066#backwards-compatibility","designImplication":"Retain normal ERC-721 ownership views while adding a clear lock state and lock-specific action rules."},{"id":"inaccessible-locker-risk","constraint":"A locked token can become permanently locked when its locker is inaccessible or an unverified contract.","appliesTo":"application","normativity":"security-considerations","specQuote":"- `locked` token with `locker` as in-accesible account or un-verified contract address can lead to permanent lock of the token.","specSection":"Security Considerations — Considerations for the contracts that work with lockable tokens","specUrl":"https://ercs.ethereum.org/ERCS/erc-7066#considerations-for-the-contracts-that-work-with-lockable-tokens","designImplication":"Warn before assigning an unverified or inaccessible locker and make the recovery consequence clear."},{"id":"optional-locking-support","constraint":"ERC-721-compliant contracts MAY implement ERC-7066 to provide standard locking and unlocking methods.","appliesTo":"application","normativity":"normative","specSection":"Specification > Overview","specUrl":"https://ercs.ethereum.org/ERCS/erc-7066#overview","designImplication":"Detect locking support before showing lock or unlock controls; retain the base ERC-721 experience when the optional extension is unavailable.","specQuote":"[ERC-721](./eip-721.md) compliant contracts MAY implement this EIP to provide standard methods of locking and unlocking the token at its current owner address."}],"sources":[{"label":"Official specification","url":"https://ercs.ethereum.org/ERCS/erc-7066","type":"official-spec"}],"lastReviewed":"2026-09-18","lastUpdated":"2026-09-18","summary":"NFTs can be locked in the owner's wallet. While locked, ERC-721 approval and transfer are restricted, with an exception when the caller is both the approved address and the locker; other application utility is implementation-specific.","designerTakeaways":["You can show Locked badge with who can unlock on every locked token.","Your lock flow can recommend cold wallet as locker with safety copy.","You can block marketplace List while locked with explanation, not disabled mystery button."],"applicability":{"whenToUse":["High-value NFTs need anti-theft lock without full cold storage.","Games need custody protection while their app decides whether locked items remain usable.","Locker address is separate trusted key."],"whenToAvoid":["Soulbound tokens with no unlock path.","Users need frequent transfers — lock adds friction.","Marketplace primary use case for asset."]},"prototypeFirst":[{"screen":"Lock asset flow","why":"Owner chooses anti-theft lock before threat.","covers":["Unlocked","Select locker","Confirm lock"],"include":["Locker address field","Cold wallet tip","Transfer and approval restrictions, plus the approved-and-locker exception"]},{"screen":"Locked asset detail","why":"Daily view must show lock status clearly.","covers":["Locked by self","Locked by other locker"],"include":["Locked chip","Unlock authority","App-specific utility state"]},{"screen":"Unlock confirmation","why":"Unlocking restores transfer — high risk moment.","covers":["Unlock success","Wrong locker fails"],"include":["Scary confirm copy","2-step confirm","Explorer link"]},{"screen":"Blocked listing while locked","why":"Marketplace must pre-check lock.","covers":["List blocked"],"include":["Cannot list while locked","Unlock first CTA"]}],"mentalModel":[{"label":"Locked","description":"Approval and transfer are restricted; a caller that is both approved and locker may transfer, while other utility is app-specific."},{"label":"Locker","description":"Address authorized to unlock — often cold wallet."},{"label":"Owner","description":"Still owns token; may or may not unlock depending on config."},{"label":"Lock vs soulbound","description":"Lock is temporary and reversible; soulbound is policy-level permanent."},{"label":"transferAndLock","description":"Send to new owner already locked — preview both transfer and lock."}],"statesToDesign":[{"state":"Unlocked — normal","trigger":"No active lock.","userNeed":"Transfer and sell freely.","designResponse":"Standard actions plus optional Lock asset."},{"state":"Locked — owner can unlock","trigger":"Owner is locker.","userNeed":"Use in app; unlock when ready to sell.","designResponse":"Locked badge with Unlock CTA."},{"state":"Locked — external locker","trigger":"Cold wallet is locker.","userNeed":"Know must use cold key to unlock.","designResponse":"Locked by [address] with connect cold wallet hint."},{"state":"List blocked","trigger":"User tries marketplace list.","userNeed":"Understand lock prevents sale.","designResponse":"Unlock to list message before wallet."},{"state":"transferAndLock incoming","trigger":"Receiving locked token.","userNeed":"Know incoming asset is locked.","designResponse":"Receive preview shows Locked on arrival."}],"designDecisions":[{"question":"Recommend cold wallet as locker?","recommendation":"Yes with default suggestion and explainer.","rationale":"Hot wallet as locker defeats anti-theft purpose."},{"question":"Show locked items in marketplace search?","recommendation":"Hide or badge Locked — do not allow list flow.","rationale":"Prevent failed listings and buyer confusion."},{"question":"Explain lock vs soulbound?","recommendation":"Tooltip: Locked = you chose protection; Soulbound = issuer rule.","rationale":"Users conflate two restriction types."}],"problemsSolved":[{"problem":"Hot wallet drain steals NFTs","oldWay":"Transfer out instantly on compromise","newWay":"Lock restricts approval and transfer while the consuming app decides what utility remains","impact":"critical"},{"problem":"Cold storage removes utility","oldWay":"Move to vault, cannot use in game","newWay":"Locked custody can coexist with utility only where the connected app supports it","impact":"high"},{"problem":"Accidental listing of locked item","oldWay":"Listing fails at settlement","newWay":"Pre-check lock before list UI","impact":"medium"}],"uxPatterns":[{"name":"Lock Asset Flow","description":"Assign locker and confirm anti-theft lock.","components":["LockButton","LockerInput","SafetyCopy"],"userFlow":["User taps Lock","Sets locker","Confirms","Locked badge appears"]},{"name":"Locked Status Badge","description":"Persistent locked indicator with unlock path.","components":["LockedChip","UnlockCTA","LockerLabel"],"userFlow":["View locked NFT","See locker","Unlock when ready","Transfer enabled"]}],"antiPatterns":[{"pattern":"Lock without explaining locker role","why":"Users lock themselves out permanently","instead":"Cold wallet recommendation and locker explainer","severity":"critical"},{"pattern":"Disabled List with no reason","why":"Users think marketplace bug","instead":"Explain that listing and approval are restricted while locked, and show the configured locker or approved-and-locker exception","severity":"high"},{"pattern":"Conflating lock with soulbound","why":"Wrong recovery expectations","instead":"Distinct Locked vs Non-transferable badges, with the locker and app-specific utility policy visible","severity":"medium"}],"vocabulary":[{"use":"Locked for protection","avoid":"Transfer restricted flag","why":"Security framing."},{"use":"Unlock with [locker]","avoid":"Call unlock() from locker EOA","why":"Action and actor, not function."},{"use":"Utility depends on this app","avoid":"Lock always preserves utility","why":"The standard restricts approval and transfer, not application behavior."}],"technicalNotes":"ERC-7066 restricts ERC-721 approval and transfer while a token is locked, unless msg.sender is both the approved address and the locker. Show lockerOf(), the unlock path, and any implementation-specific utility policy; the standard does not grant universal application utility.","relatedStandards":[{"id":"ERC-6147","relationship":"Guard-based transfer restriction alternative"},{"id":"ERC-6454","relationship":"Transfer detection when locked"}]},"sources":[{"label":"Official specification","url":"https://ercs.ethereum.org/ERCS/erc-7066","type":"official-spec"},{"label":"Discussion search","url":"https://ethereum-magicians.org/search?q=ERC-7066","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-7066","markdown":"https://www.eipsfordesigners.com/standards/ERC-7066/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-7066/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-7066","official":"https://ercs.ethereum.org/ERCS/erc-7066","discussion":"https://ethereum-magicians.org/search?q=ERC-7066"},"freshness":{"lastReviewed":"2026-09-18","lastUpdated":"2026-09-18"}}