Final ERC standard. The smallest possible extension of ERC-721 for non-transferable (soulbound) tokens. Adds a `locked(tokenId)` view and `Locked` / `Unlocked` events so wallets and marketplaces can render soulbound state without guessing.
- 01soulbound tokens (SBTs)
- 02credentials, attestations, badges
- 03non-transferable membership / loyalty
- 04on-chain identity tied to a single account
- 05compliance / KYC NFTs
- pnpm add @openzeppelin/contracts
Implement ERC-5192 on top of an ERC-721 base. The interface (`IERC5192`) adds one function — `locked(uint256 tokenId) external view returns (bool)` — and two events: `event Locked(uint256 tokenId)`, `event Unlocked(uint256 tokenId)`. Emit `Locked` at mint time for permanently-soulbound tokens. Block transfers by overriding `_update` (OpenZeppelin v5) or `_beforeTokenTransfer` (v4) to revert when `from != address(0)` and `to != address(0)` (i.e. allow mint and burn but not user-to-user). Add interface ID `0xb45a3c0e` to `supportsInterface`. For revocable credentials, gate `_burn` to an issuer role rather than the holder.
- ⚑ERC-5192 does not specify whether burning is allowed — wallets typically allow it, so 'soulbound' often actually means 'non-transferable but burnable'. Decide your revocation model explicitly.
- ⚑Approvals (`approve`, `setApprovalForAll`) still succeed by default but are pointless — consider reverting them to avoid misleading UI in marketplaces.
- ⚑Forgetting to register `0xb45a3c0e` in `supportsInterface` means wallets fall back to treating the token as transferable and may display misleading 'list' / 'transfer' buttons.
- ⚑Token-bound accounts (ERC-6551) on a soulbound NFT inherit the non-transferability of the parent — useful for identity, but means assets locked inside are stuck if the SBT is burned.
- ⚑Cross-chain bridges generally cannot move soulbound tokens; ensure your audience is on the deployed chain or use attestation standards (EAS) instead.