Overview
Creators often switch off secondary transfers for a while: during a public mint, before a reveal, during a migration. Other collections are meant to never move: credentials, memberships, achievement badges. In both cases marketplaces need to stop offering listings and sales the contract would reject.
ERC-6982 already lets a contract lock or unlock every token with one DefaultLocked event and override single tokens with Locked. ERC-8451 fills the three gaps it leaves:
- No way to tell a lock that will lift from one that never will.
- ERC-6982 requires ERC-721, so ERC-1155 contracts have no equivalent signal.
- No rule on whether minting and burning continue while tokens are locked.
ERC-5192 covers permanent locks, but with one event per token. A 10,000 token collection would need 10,000 logs at deployment. ERC-8451 needs one.
Definitions
- Holder transfer
- A transfer where neither
fromnortois the zero address. Mints and burns are not holder transfers. - Locked
locked(tokenId)returns true.- Permanently locked
- The contract has emitted
PermanentlyLocked. - ERC-1155 token
tokenIdis the token type ID. It exists while its total supply is above zero.
The additions
A compliant contract implements ERC-721 or ERC-1155, implements ERC-6982, and adds one event, one error and one view:
event PermanentlyLocked(); error TokenLocked(uint256 tokenId); function permanentlyLocked() external view returns (bool);
It reports both 0x9051c597 (ERC-8451) and 0x6b61a747 (ERC-6982) through ERC-165. Full code is on the Interface page.
Behavior rules
supportsInterfacereturns true for0x9051c597and0x6b61a747.- ERC-6982's requirements apply to ERC-1155 contracts, with
tokenIdread as the token type ID. - Locking restricts holder transfers only. A lock must not by itself block minting. Burning locked tokens is allowed.
- A holder transfer blocked by a lock should revert with
TokenLocked(tokenId). - When
PermanentlyLockedis emitted,defaultLocked()already returns true. - Before
PermanentlyLocked, the contract emitsLocked(tokenId, true)for every existing token whose latestLockedevent unlocked it. - After
PermanentlyLocked: every existing token is locked, including later mints. Every holder transfer reverts, by holder or operator. No unlock event is ever emitted again. permanentlyLocked()returns false until the event, and true from then on.approveandsetApprovalForAllshould not revert just because a token is temporarily locked.
Rules 5 and 6 are what keep old ERC-6982 indexers correct: whether they call locked or replay events, they see every token as locked.
For marketplaces and wallets
- Don't create, show or fill listings, offers or sales of a locked token.
- Orders for a locked token can be kept while
permanentlyLocked()is false, and shown again on unlock. - Tokens of a permanently locked contract can be shown as non-transferable. Other locked tokens as temporarily unavailable.
- After
PermanentlyLocked, treat every token in the contract as non-transferable, including later mints. - A transfer that reverts with
TokenLockedcan be read as a lock on that token, even without a lock event.
ERC-1155
ERC-6982 only ever talks about a tokenId, which maps straight onto an ERC-1155 type ID. The one thing ERC-1155 needed was a definition of existence, because locked reverts for tokens that don't exist. A type ID exists while its total supply is above zero, the same way a burned ERC-721 stops existing.
Permanence is contract-wide. An ERC-1155 contract that wants one type to stay non-transferable keeps it locked with Locked(tokenId, true).
Design choices
- A separate event. ERC-6982 is Final, so its events can't gain a field.
- One way only. A contract can move from locked to permanently locked, never back. Seen once, trusted forever.
- Strict reverts only when permanent. Temporary locks keep ERC-6982's flexibility, such as a protector wallet moving a locked token.
- No end time. Pauses end early or late. A stale end time would make consumers offer orders that revert.
- No range event. The default covers the collection,
Lockedcovers single tokens.
Security
- The contract reports its own status. Keep simulating fills instead of trusting the signal to approve them.
- A permanent lock is only as permanent as the code. An upgradeable proxy or swappable transfer check can make tokens move again without an unlock event. Check who controls upgrades.
- Whoever controls the lock controls the secondary market. Show holders who can change it.
- Status can change between order and fill. Check close to fulfillment.
- Bound the gas passed to
lockedandpermanentlyLocked, and handle the revert for tokens that don't exist.
Source
ERC-8451 is a Draft by Ryan Ghods (@ryanio), requiring ERC-165, 721, 1155 and 6982. Discussion is on Ethereum Magicians. Draft text can change before it is final.