{"id":"ERC-6909","name":"Minimal Multi-Token Interface","status":"Final","chain":"both","category":{"id":"nft","name":"NFT Capabilities","description":"What NFTs can do beyond basic ownership"},"journeyStages":[{"id":"asset-display","name":"Asset Discovery & Display","description":"Seeing tokens, NFTs, and balances"}],"uxImpact":"Streamlined multi-token with granular per-token-type approvals and no mandatory callbacks — simpler than ERC-1155. Design implications: show per-token-type allowance amounts (like ERC-20), remove batch transfer UI complexity if not needed, design approval UIs that distinguish 'approve specific amount' from 'operator access to all'. Design decisions: whether to expose the simpler approval model to users or abstract it, tradeoff between gas savings (no callbacks) vs safety checks that callbacks provided.","hasDetailedContent":true,"content":{"id":"ERC-6909","sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-6909","type":"official-spec"}],"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25","summary":"Streamlined multi-token with granular per-token-type approvals and no mandatory callbacks — simpler than ERC-1155.","designerTakeaways":["You can show per-token-type allowance rows mirroring ERC-20 revoke.cash patterns.","Your approval modal can distinguish Approve 50 of this type from Allow app to manage all types.","You can skip ERC-1155 batch UI when the contract only needs simple per-id transfers."],"applicability":{"whenToUse":["One contract emits many fungible-like token types.","You need ERC-20-style allowances without ERC-1155 callbacks.","Gas-efficient multi-token vaults or game currencies."],"whenToAvoid":["True batch NFT transfers with mixed metadata are required.","Contract is ERC-1155-only with existing indexer support.","Users never need granular approvals — operator suffices."]},"prototypeFirst":[{"screen":"Multi-type balance sheet","why":"Users must see each token type balance distinctly.","covers":["Multiple ids","Zero balance types","Single type"],"include":["Type name","Balance","Token id disclosure in advanced"]},{"screen":"Approve specific amount","why":"ERC-20 mental model is the anchor.","covers":["Amount approval","Unlimited toggle","Revoke"],"include":["Amount input","Spender address","Current allowance row"]},{"screen":"Operator approval warning","why":"Full operator access is high risk.","covers":["Operator grant","Revoke operator"],"include":["Scary unlimited copy","List affected types","Confirm checkbox"]},{"screen":"Transfer type picker","why":"Sending requires choosing which type.","covers":["Single type send","Insufficient balance"],"include":["Type selector","Amount","Recipient","Preview"]}],"mentalModel":[{"label":"Token type ID","description":"Each id is a distinct balance lane inside one contract address."},{"label":"Amount approval","description":"Spender can move up to N of one type — like ERC-20 allowance."},{"label":"Operator approval","description":"Spender can move all types — like ERC-1155 setApprovalForAll."},{"label":"Single contract","description":"One address on chain; UI must label types clearly to avoid confusion."},{"label":"No callbacks","description":"Transfers won't auto-notify receivers — apps track balance via events."}],"statesToDesign":[{"state":"Sufficient balance — type selected","trigger":"User picks type and amount.","userNeed":"Confirm correct type before send.","designResponse":"Type name prominent in confirmation; id in advanced."},{"state":"Approval required","trigger":"Spender lacks allowance.","userNeed":"Grant minimum needed access.","designResponse":"Suggest exact amount approval, not operator by default."},{"state":"Operator fully approved","trigger":"User previously granted operator.","userNeed":"Audit and revoke if unintended.","designResponse":"Show in permissions dashboard with high-risk badge."},{"state":"Insufficient type balance","trigger":"Amount exceeds id balance.","userNeed":"Fix amount without guessing.","designResponse":"Inline max available for this type."},{"state":"Revoked approval","trigger":"User revokes spender.","userNeed":"Confirm app may break until re-approved.","designResponse":"Success toast with Re-approve if needed link."}],"designDecisions":[{"question":"Expose token type ids to users?","recommendation":"Show friendly names; tuck numeric id behind advanced.","rationale":"Ids are implementation detail unless debugging."},{"question":"Default approval style?","recommendation":"Amount approval per action; operator requires extra confirmation.","rationale":"Operator equals unlimited across types — high risk."},{"question":"Use batch transfer UI?","recommendation":"Skip unless contract exposes batch; prefer simple single-type flows.","rationale":"6909 value is simplicity over 1155 batch complexity."}],"problemsSolved":[{"problem":"ERC-1155 approval UX too coarse","oldWay":"setApprovalForAll for entire contract","newWay":"Per-type amount allowances like ERC-20","impact":"high"},{"problem":"Multiple contracts clutter wallet","oldWay":"One ERC-20 per game currency","newWay":"Single 6909 contract with typed balances","impact":"medium"},{"problem":"Callback gas and reentrancy concerns","oldWay":"ERC-1155 onReceived hooks","newWay":"No mandatory callbacks — simpler transfer path","impact":"medium"}],"uxPatterns":[{"name":"Per-Type Allowance Row","description":"ERC-20-style allowance display per token id.","mockup":"concept/nft-gallery","components":["AllowanceRow","RevokeButton","AmountLabel"],"userFlow":["User opens permissions","Sees per-type allowances","Revokes or edits","Spender updated"]},{"name":"Type Picker Transfer","description":"Send flow with explicit token type selection.","mockup":"concept/permit-approval","components":["TypeSelector","AmountInput","ConfirmSheet"],"userFlow":["User taps Send","Picks type","Enters amount","Confirms"]}],"seenInTheWild":[{"app":"Uniswap V4","url":"https://uniswap.org/","note":"Multi-token vault patterns inform typed balance display."},{"app":"Revoke.cash","url":"https://revoke.cash/","note":"Allowance management UX applies per-type approvals."},{"app":"OpenSea","url":"https://opensea.io/","note":"Multi-token inventory patterns for id-based assets."}],"antiPatterns":[{"pattern":"Defaulting to operator approval","why":"Grants unlimited access across all types","instead":"Default amount approval with scary operator path","severity":"critical"},{"pattern":"Showing only contract address without type","why":"Users send wrong token type","instead":"Type name in every confirmation step","severity":"high"},{"pattern":"ERC-1155 batch UI on 6909 contract","why":"Unnecessary complexity","instead":"Simple single-type transfer and approve flows","severity":"medium"}],"vocabulary":[{"use":"Token type","avoid":"Token id 8472","why":"Friendly naming unless advanced view."},{"use":"Spending limit","avoid":"Allowance mapping","why":"ERC-20 familiar terms."},{"use":"Manage all types","avoid":"Operator set true","why":"Plain permission language."}],"onMonad":[{"aspect":"Multi-type transfers","ethereum":"Many approvals add gas","monad":"Lower fees enable granular per-type approvals","designImplication":"Prefer amount approvals over operator on Monad."},{"aspect":"Balance refresh","ethereum":"Multi-id indexing lag","monad":"Fast blocks need snappy balance updates per type","designImplication":"Refresh all types after any transfer event."}],"technicalNotes":"ERC-6909 uses per-id allowances; treat operator approval as high-risk unlimited grant.","relatedStandards":[{"id":"ERC-1155","relationship":"Multi-token alternative with callbacks"},{"id":"ERC-20","relationship":"Approval mental model per token type"}]},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-6909","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-6909","type":"discussion"},{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-6909","type":"official-spec"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-6909","markdown":"https://www.eipsfordesigners.com/standards/ERC-6909/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-6909/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-6909","official":"https://eips.ethereum.org/EIPS/erc-6909","discussion":"https://ethereum-magicians.org/search?q=ERC-6909"},"freshness":{"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25"}}