{"id":"ERC-6454","name":"Minimal Transferable Detection","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":"Tokens can be non-transferable (soulbound) or have transfer restrictions — verifiable on-chain.","officialUrl":"https://ercs.ethereum.org/ERCS/erc-6454","lastReviewed":"2026-09-18","lastUpdated":"2026-09-18","kind":"proposal","hasDetailedContent":true,"content":{"id":"ERC-6454","sources":[{"label":"Official specification","url":"https://ercs.ethereum.org/ERCS/erc-6454","type":"official-spec"}],"lastReviewed":"2026-09-18","lastUpdated":"2026-09-18","summary":"Tokens can be non-transferable (soulbound) or have transfer restrictions — verifiable on-chain.","designerTakeaways":["You can query isTransferable(tokenId, from, to) for the intended route and reserve a Non-transferable badge for a separately checked general restriction.","Your marketplace can hide List when the intended sale route is blocked instead of showing a disabled mystery button.","You can explain why transfer fails with credential, event ticket, or achievement copy."],"applicability":{"whenToUse":["Wallet displays mixed transferable and soulbound NFTs.","SBTs, credentials, or tickets block transfers.","You want one detection hook across collections."],"whenToAvoid":["All tokens in app are freely transferable.","Collection uses custom restriction without ERC-6454 interface.","Read-only display with no send UI."]},"prototypeFirst":[{"screen":"Wallet with mixed tokens","why":"Users compare tradeable vs locked items at a glance.","covers":["Soulbound badge","Transferable normal","Mixed grid"],"include":["Non-transferable chip","No send on the contextually blocked route","Filter by transferable"]},{"screen":"Blocked transfer attempt","why":"Edge cases still need education if user tries send.","covers":["Blocked with reason"],"include":["Cannot transfer modal","Reason: credential/event","No gas wasted"]},{"screen":"Marketplace listing gate","why":"List UI must not appear for a route the transfer check blocks.","covers":["List hidden","List blocked pre-check"],"include":["Pre-list transferability check","Explanation if user deep-links"]},{"screen":"Credential detail page","why":"Soulbound items emphasize achievement not resale.","covers":["SBT display"],"include":["Large Non-transferable badge after a general restriction check","Issued by","Earned date"]}],"mentalModel":[{"label":"Transferable","description":"isTransferable(tokenId, from, to) returned true for the intended context; still check approval and destination rules."},{"label":"Non-transferable","description":"The transfer check returned false for this from/to context; do not treat that result as a universal soulbound flag."},{"label":"Detection hook","description":"Standard interface lets apps ask once instead of per-collection hacks."},{"label":"Restriction reason","description":"Optional metadata explains ticket, diploma, or achievement context."},{"label":"Burn path","description":"Some soulbound tokens can still be burned — separate from transfer."}],"statesToDesign":[{"state":"Transfer allowed for this context","trigger":"isTransferable(tokenId, from, to) returns true for the intended sender and recipient.","userNeed":"Know this route can proceed.","designResponse":"Enable transfer or listing only after separately checking ERC-721 approval and the actual settlement path."},{"state":"Transfer blocked for this context","trigger":"isTransferable(tokenId, from, to) returns false for the intended sender and recipient.","userNeed":"Understand why this route is unavailable.","designResponse":"Explain the contextual restriction; reserve a general Non-transferable label for a separately checked zero-address/general case."},{"state":"Transfer attempted on a restricted route","trigger":"User finds send via deep link.","userNeed":"Clear block before wallet.","designResponse":"Modal before wallet with the checked sender/recipient context; no signature prompt."},{"state":"Burnable soulbound","trigger":"Burn allowed but not transfer.","userNeed":"Distinguish destroy from send.","designResponse":"Burn action separate with warning; no Send."},{"state":"Unknown restriction","trigger":"Check fails or unsupported.","userNeed":"Safe default.","designResponse":"Try transfer with warning or query fallback per collection."}],"designDecisions":[{"question":"Show Send button disabled or hidden?","recommendation":"Hidden for soulbound; disabled only if temporarily locked with unlock date.","rationale":"Disabled Send invites futile clicks."},{"question":"Visual treatment in grid?","recommendation":"Subtle lock icon plus Non-transferable chip, not grayed entire card.","rationale":"Soulbound credentials remain pride items."},{"question":"Filter soulbound in marketplace mode?","recommendation":"Default hide from sell flows; show in profile/credentials tab.","rationale":"Marketplace implies transferability."}],"problemsSolved":[{"problem":"Failed transfer txs on SBTs","oldWay":"User signs then reverts","newWay":"Pre-check hides or blocks send before wallet","impact":"high"},{"problem":"Inconsistent soulbound detection","oldWay":"Per-collection hacks break","newWay":"ERC-6454 standard query across tokens","impact":"medium"},{"problem":"Marketplace lists unsellable items","oldWay":"Listing fails at settlement","newWay":"Hide list UI when the intended route is non-transferable","impact":"high"}],"uxPatterns":[{"name":"Soulbound Badge","description":"Non-transferable chip after a general restriction check on token card and detail.","components":["SoulboundChip","LockIcon","ReasonTooltip"],"userFlow":["Load token","Query 6454","Show badge if the relevant general or contextual check is blocked","Hide send"]},{"name":"Transfer Gate","description":"Block send flow before wallet for restricted tokens.","components":["TransferCheck","BlockModal","ReasonCopy"],"userFlow":["User taps Send","Check fails","Modal explains","No wallet prompt"]}],"antiPatterns":[{"pattern":"Enabled Send on soulbound token","why":"Wasted gas and rage","instead":"Check ERC-6454 with the intended from/to, then separately check approval before enabling or hiding Send","severity":"critical"},{"pattern":"Generic Transfer failed after sign","why":"User paid gas for predictable revert","instead":"Block in app with the contextual transfer restriction explanation","severity":"critical"},{"pattern":"Grayed-out credential cards","why":"Implies worthless or broken","instead":"Proud display with Non-transferable badge","severity":"medium"}],"vocabulary":[{"use":"Non-transferable","avoid":"Soulbound EIP-5192 6454","why":"Plain restriction language."},{"use":"Credential","avoid":"SBT","why":"User-facing term unless audience is web3-native."},{"use":"Cannot send this item","avoid":"isTransferable returned false","why":"Outcome not API response."}],"specConstraints":[{"id":"nontransferable-check","constraint":"If isTransferable returns false, the token transfer must revert.","appliesTo":"application","normativity":"normative","specQuote":"* @dev If this function returns `false`, the transfer of the token MUST revert execution.","specSection":"Specification","specUrl":"https://ercs.ethereum.org/ERCS/erc-6454#specification","designImplication":"Check the intended transfer route before enabling List, Send, or Buy and show a specific non-transferable state instead of a generic failed transaction."},{"id":"approval-not-implied","constraint":"isTransferable does not necessarily validate approval, so clients must not rely on it as an authorization check.","appliesTo":"application","normativity":"normative","specQuote":"Implementers MAY choose to validate the approval of the token for transfer by the `from` parameter, but anyone interacting with this function SHOULD NOT rely on it as it is not mandated by the proposal. This means that the `from` parameter in such implementations validates the initiator of the transaction rather than the owner from which the token is being transferred (which can either be the owner of the token or the operator allowed to transfer the token).","specSection":"Specification","specUrl":"https://ercs.ethereum.org/ERCS/erc-6454#specification","designImplication":"Keep transferability and operator approval as separate checks in marketplace and wallet flows."},{"id":"mint-burn-exception","constraint":"General non-transferability does not prevent minting and burning, which use distinct zero-address contexts.","appliesTo":"application","normativity":"normative","specQuote":"The general transferability of a token should not be affected by the ability to mint the token (value of `from` parameter is `0x0000000000000000000000000000000000000000`) and the ability to burn the token (value of `to` parameter is `0x0000000000000000000000000000000000000000`).","specSection":"Specification","specUrl":"https://ercs.ethereum.org/ERCS/erc-6454#specification","designImplication":"Do not disable issuance or burn affordances merely because secondary transfers are blocked; label the allowed lifecycle operation."},{"id":"erc721-compat","constraint":"The minimal non-transferable interface remains compatible with ERC-721 tooling and infrastructure.","appliesTo":"application","normativity":"backwards-compatibility","specQuote":"## Backwards Compatibility\n\nThe Minimalistic Non-Transferable token standard is fully compatible with [ERC-721](./eip-721.md) and with the robust tooling available for implementations of ERC-721 as well as with the existing ERC-721 infrastructure.","specSection":"Backwards Compatibility","specUrl":"https://ercs.ethereum.org/ERCS/erc-6454#backwards-compatibility","designImplication":"Keep standard NFT identity and display patterns while adding the separately checked transferability state."},{"id":"transferability-verification","constraint":"Transferability can change and external contracts may return fraudulent values, so dApps, marketplaces, and wallets should verify the state whenever a token is displayed.","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 asset, accept asset, and more.\n\nA smart contract can implement the proposal interface but returns fraudulent values, i.e., returning `false` for `isTransferable` when the token is transferable. Such a contract would trick other contracts into thinking that the token is non-transferable when it is transferable. If such a contract exists, we suggest not interacting with it. Much like fraudulent [ERC-20](./eip-20.md) or [ERC-721](./eip-721.md) smart contracts, it is not possible to prevent such contracts from existing. We suggest that you verify all of the external smart contracts you interact with and not interact with contracts you do not trust.\n\nSince the transferability state can change over time, verifying that the state of the token is transferable before interacting with it is essential. Therefore, a dApp, marketplace, or wallet implementing this interface should verify the state of the token every time the token is displayed.\n\nCaution is advised when dealing with non-audited contracts.","specSection":"Security Considerations","specUrl":"https://ercs.ethereum.org/ERCS/erc-6454#security-considerations","designImplication":"Refresh transferability at display and action time, identify untrusted contracts, and avoid presenting a stale Non-transferable or Transferable badge as permanent."},{"id":"general-transferability-check","constraint":"To determine general transferability, isTransferable SHOULD be called with the zero address as both from and to.","appliesTo":"application","normativity":"normative","specQuote":"In order to determine whether a token is transferable or not in general, the function SHOULD return the appropriate boolean value when passing the `0x0000000000000000000000000000000000000000` address as the `to` and `from` parameter.","specSection":"Specification","specUrl":"https://ercs.ethereum.org/ERCS/erc-6454#specification","designImplication":"Use the zero-address general check for token-level transferability, then run the actual owner/recipient check before enabling a transfer action."}],"technicalNotes":"ERC-6454 defines isTransferable(tokenId, from, to); query the intended sender and recipient before Send or List UI, and separately use zero-address contexts when labeling general transferability. Approval checking is optional in the interface, so validate the actual settlement path too.","relatedStandards":[{"id":"ERC-5192","relationship":"Minimal soulbound NFT standard"},{"id":"ERC-5484","relationship":"Consensual soulbound minting"}]},"sources":[{"label":"Official specification","url":"https://ercs.ethereum.org/ERCS/erc-6454","type":"official-spec"},{"label":"Discussion search","url":"https://ethereum-magicians.org/search?q=ERC-6454","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-6454","markdown":"https://www.eipsfordesigners.com/standards/ERC-6454/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-6454/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-6454","official":"https://ercs.ethereum.org/ERCS/erc-6454","discussion":"https://ethereum-magicians.org/search?q=ERC-6454"},"freshness":{"lastReviewed":"2026-09-18","lastUpdated":"2026-09-18"}}