{"count":137,"standards":[{"id":"EIP-1193","name":"Ethereum Provider JavaScript API","status":"Final","chain":"both","category":{"id":"onboarding","name":"Onboarding & Access","description":"Getting users into web3 without friction"},"journeyStages":[{"id":"discovery","name":"Discovery & Connection","description":"Finding and connecting wallet to dApp"}],"uxImpact":"Users interact with dApps through a standardized wallet JavaScript API — all wallets expose the same request/response pattern. Design implications: build one connection flow that works with any EIP-1193 wallet, handle standard error codes (4001 for user rejection, 4100 for unauthorized, 4900 for disconnected) with consistent error messaging, listen for accountsChanged and chainChanged events to update UI state automatically. Design decisions: decide whether to show explicit 'connecting' vs 'connected' states, handle network switching prompts gracefully, consider how to surface RPC errors in human-readable form without exposing technical details.","hasDetailedContent":true,"content":{"id":"EIP-1193","summary":"EIP-1193 is the \"Connect Wallet\" standard. It defines how websites talk to browser wallet extensions like MetaMask. Every dApp that shows a connect button uses this — it specifies the window.ethereum object, how to request accounts, and how to send transactions. Without this standard, every wallet would need custom integration code.","applicability":{"whenToUse":["Web apps need a standard Connect Wallet flow with browser extensions.","You listen for accountsChanged and chainChanged to keep UI in sync.","You show truncated addresses or ENS names after connection."],"whenToAvoid":["Mobile-only flows use WalletConnect with no window.ethereum.","Embedded wallets hide provider choice entirely.","You trigger eth_requestAccounts on page load without user action."]},"designerTakeaways":["You can use one Connect Wallet pattern that works across MetaMask-class extensions.","You can react to account and network switches with clear reconnect or warning states.","You can pair EIP-1193 with EIP-6963 so users pick among multiple injected wallets."],"designDecisions":[{"question":"When do you call eth_requestAccounts?","recommendation":"Trigger on explicit Connect Wallet click, not on page load.","rationale":"Surprise wallet popups erode trust and increase rejection rates."},{"question":"How do you map provider errors?","recommendation":"Map 4001, 4100, 4900, and 4901 to consistent, human-readable messages.","rationale":"Raw error codes are meaningless to designers and users alike."},{"question":"What happens on chain change?","recommendation":"Pause actions and prompt reload or auto-refresh contract-dependent state.","rationale":"Stale chain state causes wrong balances and failed transactions."},{"question":"How is the connected account shown?","recommendation":"Truncated address, network name, and a clear disconnect control.","rationale":"Users must always know which identity and chain the app is using."}],"statesToDesign":[{"state":"No provider","trigger":"window.ethereum is missing (no extension).","userNeed":"Install or choose a wallet path.","designResponse":"Explain install steps; link to WalletConnect or mobile if supported."},{"state":"Disconnected","trigger":"User has not approved eth_requestAccounts.","userNeed":"Start the session safely.","designResponse":"Primary Connect Wallet CTA; no gated content that requires guessing."},{"state":"Connected","trigger":"Accounts array non-empty.","userNeed":"See active address and network.","designResponse":"Account chip with network badge and disconnect."},{"state":"User rejected (4001)","trigger":"User closes wallet prompt without approving.","userNeed":"Retry without feeling blocked.","designResponse":"Neutral copy: \"Connection cancelled\" with retry button."},{"state":"Wrong network","trigger":"chainId does not match app requirement.","userNeed":"Switch network or understand mismatch.","designResponse":"Block actions; offer Switch network when wallet supports it."}],"problemsSolved":[{"problem":"No standard way for dApps to communicate with wallets","oldWay":"Each wallet invented their own API, dApps wrote custom code for each","newWay":"Standard window.ethereum interface works with any wallet","impact":"critical"},{"problem":"Users couldn't use their preferred wallet","oldWay":"dApp only supports MetaMask? Too bad for Coinbase Wallet users","newWay":"Any EIP-1193 wallet works with any dApp","impact":"high"},{"problem":"Inconsistent connection experience","oldWay":"Different buttons, flows, and errors for each wallet","newWay":"Standard \"Connect Wallet\" flow everywhere","impact":"high"}],"uxPatterns":[{"name":"Connect Wallet Button","description":"The ubiquitous entry point to web3","mockup":"concept/wallet","userFlow":["User sees Connect Wallet button","Click triggers eth_requestAccounts","Wallet popup asks for permission","User approves connection","dApp receives account address"]},{"name":"Connected State","description":"Show connected wallet with truncated address","mockup":"concept/wallet","userFlow":["User connected successfully","Show truncated address","Display network name","Provide disconnect option"]}],"uiComponents":[{"name":"ConnectWalletButton","description":"Primary CTA for initiating wallet connection","states":["idle","connecting","connected","error"],"props":["onConnect","onDisconnect"]},{"name":"AddressPill","description":"Truncated address with optional ENS","states":["address-only","with-ens","loading"],"props":["address","ensName","onClick"]},{"name":"NetworkBadge","description":"Shows current connected network","states":["mainnet","testnet","unknown","wrong-network"],"props":["chainId","expectedChainId"]}],"antiPatterns":[{"pattern":"Auto-connecting without user action","why":"Privacy violation, users didn't consent to share address","instead":"Always require explicit \"Connect\" click first","severity":"critical"},{"pattern":"Not handling account/chain changes","why":"User switches account in wallet, dApp still shows old one","instead":"Listen to accountsChanged and chainChanged events","severity":"high"},{"pattern":"Showing full 42-character addresses","why":"Unreadable, wastes space, looks intimidating","instead":"Truncate: 0x7a3...f9c2 or show ENS name","severity":"medium"}],"onMonad":[{"aspect":"Provider Interface","ethereum":"window.ethereum is the standard","monad":"Same interface, different chainId","designImplication":"Works identically, just detect Monad chain"}],"keyTakeaways":["EIP-1193 = the \"Connect Wallet\" standard","Never auto-connect without user action","Listen for account and chain change events","Truncate addresses or show ENS names","Handle connection errors gracefully"],"technicalNotes":"EIP-1193 defines a Provider interface with request() method for JSON-RPC calls. Standard methods: eth_requestAccounts (connect), eth_accounts (get connected), eth_chainId (get network). Events: accountsChanged, chainChanged, connect, disconnect. The provider is typically injected as window.ethereum."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-1193","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=EIP-1193","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/EIP-1193","markdown":"https://www.eipsfordesigners.com/standards/EIP-1193/content.md","agent":"https://www.eipsfordesigners.com/standards/EIP-1193/agent.md","api":"https://www.eipsfordesigners.com/api/standards/EIP-1193","official":"https://eips.ethereum.org/EIPS/eip-1193","discussion":"https://ethereum-magicians.org/search?q=EIP-1193"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"EIP-6963","name":"Multi Injected Provider Discovery","status":"Final","chain":"both","category":{"id":"onboarding","name":"Onboarding & Access","description":"Getting users into web3 without friction"},"journeyStages":[{"id":"discovery","name":"Discovery & Connection","description":"Finding and connecting wallet to dApp"}],"uxImpact":"Users with multiple wallet extensions see all installed wallets in a selection modal — no more random 'last wallet wins' behavior. Design implications: replace single 'Connect Wallet' button with wallet picker showing icons, names, and rdns identifiers; render wallet icons as 96x96px minimum using <img> tags (SVGs must not execute scripts); design empty states for when no wallets are detected. Design decisions: choose between showing all wallets immediately vs progressive disclosure, decide wallet list ordering (alphabetical, most-used, last-connected), consider whether to remember user's preferred wallet across sessions, handle edge cases where wallets may impersonate others via rdns. 🟢 Live on 37+ wallets (Critical priority for wallet connection UX). Important limitation: solves desktop wallet conflicts but does NOT apply to mobile — mobile connection remains a known pain point (Connection Failures, Medium severity).","hasDetailedContent":true,"content":{"id":"EIP-6963","summary":"EIP-6963 solves the \"wallet conflict\" problem. When users have multiple wallets (MetaMask, Coinbase, Rainbow), they used to fight over window.ethereum. Now, each wallet announces itself, and users see a clean list to choose from. No more random wallet hijacking the connection.","applicability":{"whenToUse":["Users may have more than one browser wallet installed.","Connect flows need wallet icons, names, and explicit user choice.","The product targets desktop browsers where extensions compete for injection."],"whenToAvoid":["Mobile wallet connection uses deep links or WalletConnect only.","The product binds to one wallet provider with no user choice.","Wallet discovery is handled entirely outside your UI (embedded wallet only)."]},"designerTakeaways":["You can show every detected wallet in a picker instead of auto-connecting the last one loaded.","You can display wallet icons and names so users know which extension they are approving.","You can remember the last chosen wallet while still letting users switch on reconnect."],"mentalModel":[{"label":"Page load","description":"The dApp dispatches eip6963:requestProvider and listens for wallet announcements instead of assuming window.ethereum."},{"label":"Wallet announcement","description":"Each extension responds with its name, icon, rdns, and EIP-1193 provider. Multiple wallets can coexist without overwriting each other."},{"label":"User choice","description":"Your connect modal lists every detected wallet with branding. Never auto-connect the first provider found."},{"label":"Selected provider","description":"Connection proceeds with the chosen provider only. Remember the last choice for reconnect but keep switch visible."},{"label":"Mobile fallback","description":"When no injected wallets exist, route to WalletConnect or deep links without breaking the desktop picker pattern."}],"problemsSolved":[{"problem":"Multiple wallets fighting for window.ethereum","oldWay":"Last wallet to load wins, user can't choose","newWay":"Each wallet announces itself, user picks","impact":"critical"},{"problem":"Users forced to disable wallets to use another","oldWay":"Disable MetaMask extension to use Rabby","newWay":"All wallets coexist, choose at connection time","impact":"high"},{"problem":"No wallet branding in connection flow","oldWay":"Generic \"Connect Wallet\" with no context","newWay":"See wallet icons, names, choose your preference","impact":"medium"}],"uxPatterns":[{"name":"Wallet Selector Modal","description":"List of all available wallets to connect","mockup":"concept/wallet","userFlow":["User clicks Connect","App listens for EIP-6963 announcements","Shows list of detected wallets","User clicks preferred wallet","Connection proceeds with that wallet"]},{"name":"Wallet Discovery Badges","description":"Show which wallets are available before connect","mockup":"concept/wallet-discovery","userFlow":["Page loads, discovers wallets","Shows wallet icons as preview","User sees their wallet is supported","Clicks connect with confidence"]}],"uiComponents":[{"name":"WalletList","description":"Scrollable list of available wallets","states":["loading","discovered","empty"],"props":["wallets[]","onSelect"]},{"name":"WalletOption","description":"Single wallet row with icon, name, and status","states":["idle","selected","connecting"],"props":["wallet","onClick"]},{"name":"WalletIcon","description":"Wallet brand icon with fallback","states":["loaded","fallback"],"props":["icon","name"]}],"antiPatterns":[{"pattern":"Ignoring EIP-6963 and only using window.ethereum","why":"User has no choice, random wallet selected","instead":"Listen for eip6963:announceProvider events","severity":"high"},{"pattern":"Not showing wallet icons/branding","why":"Users can't identify their wallet in the list","instead":"Display wallet icon and name from rdns","severity":"medium"},{"pattern":"Auto-selecting first wallet found","why":"Removes user choice, may pick wrong wallet","instead":"Always let user explicitly choose","severity":"high"}],"onMonad":[{"aspect":"Wallet Discovery","ethereum":"Standard EIP-6963 discovery","monad":"Same mechanism, works identically","designImplication":"No changes needed for Monad support"}],"keyTakeaways":["EIP-6963 = multiple wallet discovery","Always show wallet selector, never auto-pick","Display wallet icons and names clearly","Fall back to WalletConnect for mobile","Handle no-wallets-detected gracefully"],"technicalNotes":"EIP-6963 uses DOM events for discovery. dApps dispatch eip6963:requestProvider, wallets respond with eip6963:announceProvider containing provider info (icon, name, rdns) and the EIP-1193 provider. This allows multiple wallets to coexist without overwriting window.ethereum."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-6963","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=EIP-6963","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/EIP-6963","markdown":"https://www.eipsfordesigners.com/standards/EIP-6963/content.md","agent":"https://www.eipsfordesigners.com/standards/EIP-6963/agent.md","api":"https://www.eipsfordesigners.com/api/standards/EIP-6963","official":"https://eips.ethereum.org/EIPS/eip-6963","discussion":"https://ethereum-magicians.org/search?q=EIP-6963"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"EIP-5749","name":"window.evmproviders Object","status":"Final","chain":"both","category":{"id":"onboarding","name":"Onboarding & Access","description":"Getting users into web3 without friction"},"journeyStages":[{"id":"discovery","name":"Discovery & Connection","description":"Finding and connecting wallet to dApp"}],"uxImpact":"Alternative to EIP-6963 using window.evmproviders object — wallets register themselves by name for easy enumeration. Design implications: iterate Object.values(window.evmproviders) to build wallet selection UI, display wallet name, description, and base64 SVG icon for each provider, use snake_case keys as stable identifiers. Design decisions: choose between EIP-5749 vs EIP-6963 (6963 has more adoption), design fallback for wallets only supporting window.ethereum, handle scenario where both standards coexist during transition period.","hasDetailedContent":true,"content":{"id":"EIP-5749","sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-5749","type":"official-spec"}],"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25","summary":"Alternative to EIP-6963 using window.evmproviders object — wallets register themselves by name for easy enumeration.","designerTakeaways":["You can build a wallet grid from window.evmproviders without hard-coding brand lists.","Your connect flow can merge 5749 and EIP-6963 discovery for maximum coverage.","You can remember the user's last wallet key for faster reconnect on return visits."],"applicability":{"whenToUse":["Desktop dApps need to list multiple browser extension wallets.","You want wallet name, description, and base64 SVG icon in the picker.","You are supporting wallets that register via window.evmproviders."],"whenToAvoid":["Mobile-only WalletConnect flows with no injected providers.","Your target wallets only support EIP-6963 and not evmproviders.","Single-wallet environments where a picker adds friction without benefit."]},"prototypeFirst":[{"screen":"Primary happy path","why":"Prove the core user promise before edge cases.","covers":["Success state","Clear outcome copy"],"include":["Primary CTA","Confirmation feedback","Next step"]},{"screen":"Blocked or unsupported state","why":"Users discover limits when wallets or chains lack support.","covers":["Unsupported wallet","Wrong network"],"include":["Plain-language reason","Fallback action"]},{"screen":"Failure recovery","why":"Trust breaks when errors look like bugs.","covers":["User rejection","Transaction revert"],"include":["Retry path","Support context"]},{"screen":"Advanced disclosure","why":"Power users need technical detail without cluttering the default path.","covers":["Contract address","Token ID","Raw status"],"include":["Expandable section","Copy buttons","Explorer link"]}],"mentalModel":[{"label":"Wallet registration","description":"Extensions add themselves to window.evmproviders with a name, icon, and provider object keyed by wallet id."},{"label":"Enumeration","description":"Your dApp reads evmproviders to build the picker grid. Merge with EIP-6963 announcements when both exist."},{"label":"User selection","description":"The user picks a wallet by name and icon. Never assume the first key in the object is their preference."},{"label":"Provider handoff","description":"Connection uses the selected entry provider only. Store the wallet key for faster reconnect on return visits."},{"label":"Missing provider","description":"When evmproviders is empty, fall back to EIP-6963 events or WalletConnect without breaking the connect flow."}],"statesToDesign":[{"state":"Ready","trigger":"Prerequisites met.","userNeed":"Understand what happens next.","designResponse":"Enable primary action with plain-language preview."},{"state":"Awaiting signature","trigger":"Wallet prompt open.","userNeed":"Know what they are approving.","designResponse":"Mirror human-readable summary in app and wallet."},{"state":"Pending","trigger":"Transaction submitted.","userNeed":"Confidence it is progressing.","designResponse":"Show status strip with explorer link."},{"state":"Succeeded","trigger":"On-chain confirmation.","userNeed":"See updated ownership or balance.","designResponse":"Celebrate outcome and show new state clearly."},{"state":"Failed or reverted","trigger":"Validation or execution failed.","userNeed":"Fix or retry without guessing.","designResponse":"Name the failed constraint and offer a concrete next step."}],"designDecisions":[{"question":"How much protocol detail do users see?","recommendation":"Lead with outcomes; tuck identifiers behind review.","rationale":"Users decide on consequences, not function selectors."},{"question":"What happens when support is missing?","recommendation":"Block with explanation and fallback path.","rationale":"Silent failure feels like a broken product."},{"question":"How do you label restricted assets?","recommendation":"Use persistent badges for non-transferable, locked, or expiring states.","rationale":"Hidden restrictions cause rage-quits at transfer time."}],"problemsSolved":[{"problem":"Inconsistent behavior across apps","oldWay":"Each team reinvents copy and edge cases","newWay":"Shared standard gives predictable UX patterns","impact":"high"},{"problem":"Users surprised by on-chain rules","oldWay":"Generic transfer UI fails at submit time","newWay":"Standard-aware UI sets expectations upfront","impact":"high"},{"problem":"Support burden from opaque errors","oldWay":"Raw revert reasons in toasts","newWay":"Mapped states explain what to do next","impact":"medium"}],"uxPatterns":[{"name":"EVM Providers Grid","description":"Wallet picker from window.evmproviders entries.","mockup":"concept/wallet-discovery","components":["WalletGrid","ProviderIcon","ProviderName"],"userFlow":["User clicks Connect","App reads evmproviders","Grid shows wallets","User selects","Connection proceeds"]},{"name":"Dual Discovery Merge","description":"Combine 5749 and EIP-6963 results.","mockup":"concept/wallet","components":["MergedWalletList","DedupeLogic"],"userFlow":["Listen for 6963 events","Read evmproviders object","Merge and dedupe","Render unified list","User connects"]}],"seenInTheWild":[{"app":"Rabby","url":"https://rabby.io/","note":"Multi-wallet products expect enumeration rather than a single injected provider."},{"app":"Rainbow","url":"https://rainbow.me/","note":"Sets expectations for wallet icon quality and naming in pickers."},{"app":"wagmi","url":"https://wagmi.sh/","note":"Connection libraries abstract multi-provider discovery for dApp teams."}],"antiPatterns":[{"pattern":"Hiding standard-imposed restrictions until submit","why":"Users feel tricked when actions fail at the last step","instead":"Show eligibility and badges before the primary CTA","severity":"critical"},{"pattern":"Protocol jargon in user-facing copy","why":"Non-technical users cannot consent informedly","instead":"Use outcome language with optional technical disclosure","severity":"high"},{"pattern":"No fallback when wallet lacks support","why":"Dead-end flows increase churn","instead":"Explain limitation and offer alternate path or network","severity":"high"}],"vocabulary":[{"use":"Your balance / Your item","avoid":"Token ID / Token contract","why":"Ownership language matches mental models."},{"use":"Cannot transfer yet","avoid":"Transfer reverted","why":"Explain restriction without EVM vocabulary."},{"use":"Confirm in wallet","avoid":"Sign transaction","why":"Matches wallet UX users already know."}],"onMonad":[{"aspect":"Confirmation speed","ethereum":"Multi-step flows can feel slow between signatures","monad":"Sub-second finality tightens feedback loops","designImplication":"Prefer inline status over long pending modals on Monad."},{"aspect":"Transaction cost","ethereum":"Gas can discourage exploratory actions","monad":"Lower fees enable lighter-weight interactions","designImplication":"Safe to offer preview retries and social actions more freely."}],"technicalNotes":"EIP-5749 registers wallets on window.evmproviders with snake_case keys. Prefer supporting EIP-6963 in parallel during transition.","relatedStandards":[{"id":"EIP-6963","relationship":"Preferred discovery with broader wallet adoption"},{"id":"EIP-1193","relationship":"Provider API used after selection"}]},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-5749","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=EIP-5749","type":"discussion"},{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-5749","type":"official-spec"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/EIP-5749","markdown":"https://www.eipsfordesigners.com/standards/EIP-5749/content.md","agent":"https://www.eipsfordesigners.com/standards/EIP-5749/agent.md","api":"https://www.eipsfordesigners.com/api/standards/EIP-5749","official":"https://eips.ethereum.org/EIPS/eip-5749","discussion":"https://ethereum-magicians.org/search?q=EIP-5749"},"freshness":{"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25"}},{"id":"EIP-2255","name":"Wallet Permissions System","status":"Final","chain":"both","category":{"id":"onboarding","name":"Onboarding & Access","description":"Getting users into web3 without friction"},"journeyStages":[{"id":"discovery","name":"Discovery & Connection","description":"Finding and connecting wallet to dApp"}],"uxImpact":"Users grant permissions once upfront instead of approving every action individually — OAuth-style consent for Web3. Design implications: design permission request screens showing all requested capabilities (eth_accounts, signing methods) in human-readable form, allow users to selectively reject individual permissions, show current granted permissions in settings, design permission expiration and revocation flows. Design decisions: balance between requesting minimal permissions (more prompts) vs bundled permissions (fewer prompts, more trust required), decide when to request additional permissions mid-session, consider showing permission-specific UI caveats like 'requires signTypedData_v3 support'.","hasDetailedContent":true,"content":{"id":"EIP-2255","summary":"EIP-2255 introduces granular wallet permissions so users can grant specific access (\"view my address\") instead of all-or-nothing. This enables progressive trust building where dApps request only what they need, when they need it.","applicability":{"whenToUse":["Your product addresses: connecting wallet exposes everything at once.","Your users can't revoke specific permissions.","The flow should deliver: dApp requests specific permissions, user grants only what's needed.","You are designing a progressive permission request experience with visible states and recovery paths."],"whenToAvoid":["Request minimal permissions first, escalate only when needed.","Provide clear context: \"Needed to list your NFT for sale\".","Gracefully degrade, show what features require the permission.","Wallet or chain support is fixed and users cannot choose providers."]},"designerTakeaways":["You can design UI that delivers dApp requests specific permissions.","You can design UI that delivers granular permission revocation for each capability.","You can clear permission list shows exactly what dApp can access in the interface."],"problemsSolved":[{"problem":"Connecting wallet exposes everything at once","oldWay":"Click \"Connect\" and dApp can see all addresses, request any transaction","newWay":"dApp requests specific permissions, user grants only what's needed","impact":"critical"},{"problem":"Users can't revoke specific permissions","oldWay":"Only option is to fully disconnect, losing all access","newWay":"Granular permission revocation for each capability","impact":"high"},{"problem":"No way to know what a dApp can do","oldWay":"Users unsure what they agreed to when connecting","newWay":"Clear permission list shows exactly what dApp can access","impact":"high"},{"problem":"Can't progressively expand trust","oldWay":"Must grant full access upfront or not connect at all","newWay":"Start with \"view address\", add \"sign messages\" later","impact":"medium"},{"problem":"Apps request more than they need","oldWay":"No incentive to request minimal permissions","newWay":"Permission prompts make over-requesting obvious to users","impact":"medium"}],"uxPatterns":[{"name":"Progressive Permission Request","description":"Request permissions as needed, not all at once","mockup":"concept/typed-data","userFlow":["User clicks Connect","Wallet shows minimal permission request","User understands exactly what's being asked","User approves minimal access","Later: dApp requests signing permission when needed","User can approve/deny each escalation"]},{"name":"Permission Escalation","description":"Request additional permissions when needed","mockup":"concept/typed-data","userFlow":["User tries to list NFT","dApp detects signing permission needed","Permission request explains why it's needed","User sees existing permissions for context","User grants additional permission","Action proceeds"]},{"name":"Permission Management Dashboard","description":"View and manage all dApp permissions in wallet","mockup":"concept/typed-data","userFlow":["User opens wallet settings","Sees list of connected sites","Each site shows granted permissions","User can revoke individual permissions","Or fully disconnect site"]},{"name":"Permission Request with Context","description":"Explain why each permission is needed","mockup":"concept/typed-data","userFlow":["Permission needed for user action","Wallet shows what permission does","dApp provides context (why needed)","User can learn more if unsure","Informed decision to grant or deny"]}],"uiComponents":[{"name":"PermissionRequestModal","description":"Modal showing permission being requested","states":["requesting","approved","denied","expired"],"props":["permissions[]","site","context","onApprove","onDeny"]},{"name":"PermissionBadge","description":"Visual indicator of permission type","states":["view","sign","transact","advanced"],"props":["permissionType","granted","canRevoke"]},{"name":"ConnectedSiteCard","description":"Card showing site with its permissions","states":["connected","limited","full-access"],"props":["site","permissions[]","connectedAt","onDisconnect"]},{"name":"PermissionToggle","description":"Toggle to grant/revoke specific permission","states":["granted","revoked","pending","required"],"props":["permission","enabled","onChange","isRequired"]},{"name":"CapabilityExplainer","description":"Explains what a permission allows","states":["collapsed","expanded"],"props":["permission","description","risks","examples"]}],"antiPatterns":[{"pattern":"Requesting all permissions upfront","why":"Users don't understand why you need everything, reduces trust","instead":"Request minimal permissions first, escalate only when needed","severity":"critical"},{"pattern":"No explanation for why permission is needed","why":"Users deny requests they don't understand","instead":"Provide clear context: \"Needed to list your NFT for sale\"","severity":"high"},{"pattern":"Breaking the app when permission denied","why":"Users feel forced to grant everything","instead":"Gracefully degrade, show what features require the permission","severity":"high"},{"pattern":"Not showing current permission state","why":"Users forget what they granted, feel out of control","instead":"Show active permissions in settings or footer","severity":"medium"},{"pattern":"Using technical permission names","why":"\"eth_signTypedData_v4\" means nothing to users","instead":"Say \"Sign messages\" with explanation of what that enables","severity":"medium"},{"pattern":"No way to revoke without full disconnect","why":"Users lose all access to revoke one thing","instead":"Allow granular permission management in wallet","severity":"medium"}],"onMonad":[{"aspect":"Permission Check Speed","ethereum":"wallet_getPermissions call may have noticeable latency","monad":"Fast responses make permission checks feel instant","designImplication":"Can check permissions inline without loading states"},{"aspect":"Transaction Permission","ethereum":"eth_sendTransaction permission is high-risk","monad":"With reserve balance, even full tx permission has limits","designImplication":"Can be more flexible with transaction permissions due to reserve safety"},{"aspect":"Session-Based Permissions","ethereum":"Permissions typically persistent until revoked","monad":"With fast finality, time-limited permissions more practical","designImplication":"Can implement \"allow for 1 hour\" permission grants"},{"aspect":"Permission for Account Abstraction","ethereum":"EIP-7702 adds new permission considerations","monad":"MONAD-7702 constraints affect what delegated code can do","designImplication":"May need new permission types for smart wallet features"}],"keyTakeaways":["Request only permissions you need right now","Explain WHY each permission is needed in context","Let users revoke individual permissions without disconnecting","Use human language: \"View address\" not \"eth_accounts\"","Gracefully handle denied permissions"],"technicalNotes":"EIP-2255 uses wallet_requestPermissions and wallet_getPermissions RPC methods. Permissions are capabilities like eth_accounts, eth_sign, eth_signTypedData_v4, eth_sendTransaction. Each permission can be restricted (e.g., specific addresses, caveats). MetaMask and other wallets implement varying subsets."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-2255","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=EIP-2255","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/EIP-2255","markdown":"https://www.eipsfordesigners.com/standards/EIP-2255/content.md","agent":"https://www.eipsfordesigners.com/standards/EIP-2255/agent.md","api":"https://www.eipsfordesigners.com/api/standards/EIP-2255","official":"https://eips.ethereum.org/EIPS/eip-2255","discussion":"https://ethereum-magicians.org/search?q=EIP-2255"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"EIP-1328","name":"WalletConnect URI Format","status":"Final","chain":"both","category":{"id":"onboarding","name":"Onboarding & Access","description":"Getting users into web3 without friction"},"journeyStages":[{"id":"discovery","name":"Discovery & Connection","description":"Finding and connecting wallet to dApp"}],"uxImpact":"QR codes and deep links connect mobile wallets to desktop dApps via standardized URI format. Design implications: generate scannable QR codes from wc: URIs, design mobile-friendly deep link buttons that open wallet apps directly, show connection status with pairing expiration timers, handle both WalletConnect v1 (bridge-based) and v2 (relay-based) protocols. Design decisions: choose QR code size and error correction level for reliable scanning, decide whether to show raw URI for manual copy, design timeout and retry flows when relay connection fails, consider showing which relay/bridge is being used for transparency.","hasDetailedContent":true,"content":{"id":"EIP-1328","summary":"EIP-1328 defines the WalletConnect URI format - the QR code that connects your mobile wallet to desktop dApps. When you scan a QR code to connect, you're scanning a URI that contains encrypted connection details. This standard ensures any WalletConnect-compatible wallet can scan any dApp's QR code.","applicability":{"whenToUse":["Your product addresses: no standard way to connect mobile wallet to desktop.","Your users couldn't use preferred wallet.","The flow should deliver: universal QR code format works with any compatible wallet.","Connect flows must list wallets with names, icons, and explicit user choice."],"whenToAvoid":["Minimum 200x200px, offer \"enlarge\" option.","Detect mobile and show wallet list with deep links.","Show countdown and auto-refresh QR before expiry.","Wallet or chain support is fixed and users cannot choose providers."]},"designerTakeaways":["You can design UI that delivers universal QR code format works with any compatible wallet.","You can design UI that delivers any WalletConnect wallet works with any WalletConnect dApp.","You can design UI that delivers scan QR, approve connection, done."],"problemsSolved":[{"problem":"No standard way to connect mobile wallet to desktop","oldWay":"Each wallet had proprietary connection methods","newWay":"Universal QR code format works with any compatible wallet","impact":"critical"},{"problem":"Users couldn't use preferred wallet","oldWay":"DApp only supported specific wallets","newWay":"Any WalletConnect wallet works with any WalletConnect dApp","impact":"high"},{"problem":"Complex pairing process","oldWay":"Manual key exchange, multiple steps","newWay":"Scan QR, approve connection, done","impact":"high"},{"problem":"Security concerns with connection","oldWay":"Unclear what permissions were being granted","newWay":"Encrypted channel, explicit approval in wallet","impact":"medium"}],"uxPatterns":[{"name":"QR Code Connection","description":"Classic WalletConnect flow with QR scanning","mockup":"concept/wallet","userFlow":["User clicks \"Connect Wallet\"","QR code displayed with WalletConnect URI","User opens mobile wallet","Scans QR code","Wallet shows connection request","User approves, connection established"]},{"name":"Mobile Deep Link Connection","description":"One-tap connection on mobile devices","mockup":"concept/wallet","userFlow":["User on mobile browser","Wallet list shown instead of QR","User taps preferred wallet","Deep link opens wallet app","Connection request shown","Approve and return to dApp"]},{"name":"Connection Status","description":"Show pairing progress and state","mockup":"generic/token-approval","userFlow":["QR scanned or deep link opened","Show pairing in progress","Guide user to approve in wallet","Update status as connection proceeds","Show connected state when complete"]},{"name":"Session Management","description":"Show and manage active WalletConnect sessions","mockup":"concept/wallet","userFlow":["User views connected sessions","See all active WalletConnect pairings","View session details and expiry","Disconnect any session","Manage multiple connections"]}],"uiComponents":[{"name":"WalletConnectQR","description":"QR code component for WalletConnect URI","states":["generating","ready","scanned","expired"],"props":["uri","size","onScanned","expiryTime"]},{"name":"ConnectionProgress","description":"Shows pairing status steps","states":["scanning","pairing","approving","connected","failed"],"props":["currentStep","onCancel"]},{"name":"WalletSelector","description":"List of compatible wallets with deep links","states":["idle","loading","selected"],"props":["wallets[]","uri","onSelect"]},{"name":"SessionManager","description":"Manage active WalletConnect sessions","states":["empty","has-sessions"],"props":["sessions[]","onDisconnect","onSwitch"]}],"antiPatterns":[{"pattern":"QR code too small to scan","why":"Mobile cameras struggle with tiny QR codes","instead":"Minimum 200x200px, offer \"enlarge\" option","severity":"high"},{"pattern":"No mobile deep link option","why":"Mobile users can't scan their own screen","instead":"Detect mobile and show wallet list with deep links","severity":"high"},{"pattern":"QR expires without warning","why":"User scans expired QR, nothing happens","instead":"Show countdown and auto-refresh QR before expiry","severity":"medium"},{"pattern":"No connection status feedback","why":"User doesn't know if QR was scanned","instead":"Show progress: scanned → pairing → approving → connected","severity":"medium"},{"pattern":"Can't copy URI for manual connection","why":"Some users prefer pasting into wallet","instead":"Offer \"Copy link\" as alternative to QR","severity":"low"}],"onMonad":[{"aspect":"Chain Support in URI","ethereum":"WalletConnect v2 includes chain ID in session","monad":"Monad chain ID included in WalletConnect session","designImplication":"Ensure Monad chain ID is properly configured in WalletConnect setup"},{"aspect":"Fast Transaction Signing","ethereum":"Transaction approval takes time, user waits","monad":"Sub-second confirmation after approval","designImplication":"Return to dApp quickly after wallet approval"},{"aspect":"Multi-Chain Sessions","ethereum":"WalletConnect v2 supports multiple chains per session","monad":"Can include Monad alongside other chains","designImplication":"Show all connected chains in session info"}],"relatedStandards":[{"id":"EIP-1193","relationship":"WalletConnect provides the transport for EIP-1193 provider API"},{"id":"EIP-6963","relationship":"EIP-6963 handles injected wallets, WalletConnect handles remote"},{"id":"EIP-155","relationship":"Chain ID in WalletConnect ensures transactions go to correct chain"},{"id":"EIP-695","relationship":"eth_chainId called over WalletConnect to verify chain"}]},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-1328","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=EIP-1328","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/EIP-1328","markdown":"https://www.eipsfordesigners.com/standards/EIP-1328/content.md","agent":"https://www.eipsfordesigners.com/standards/EIP-1328/agent.md","api":"https://www.eipsfordesigners.com/api/standards/EIP-1328","official":"https://eips.ethereum.org/EIPS/eip-1328","discussion":"https://ethereum-magicians.org/search?q=EIP-1328"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"EIP-681","name":"URL Format for Transaction Requests","status":"Final","chain":"both","category":{"id":"onboarding","name":"Onboarding & Access","description":"Getting users into web3 without friction"},"journeyStages":[{"id":"discovery","name":"Discovery & Connection","description":"Finding and connecting wallet to dApp"}],"uxImpact":"Payment requests encoded as ethereum: URLs work like bitcoin: links — scannable QR codes or clickable links trigger wallet payment flows. Design implications: generate QR codes for payment requests with pre-filled recipient, amount, and token type; support ENS names alongside hex addresses; use scientific notation (2.014e18) for human-readable amounts; design chain_id switching prompts when payment targets different network. Design decisions: decide whether to make gas parameters user-editable or hidden, handle token transfers (ERC-20 function calls) vs native ETH differently in UI, design validation for malformed URLs, consider showing fiat equivalents alongside crypto amounts.","hasDetailedContent":true,"content":{"id":"EIP-681","summary":"EIP-681 defines payment URLs and QR codes. Turn \"Send 0.1 ETH to 0x7a3...\" into a scannable QR code or clickable link. When scanned, the wallet auto-fills recipient, amount, and even contract calls. Perfect for point-of-sale payments, invoices, and donation buttons.","applicability":{"whenToUse":["Your product addresses: manual entry of payment details is error-prone.","Your product addresses: no standard for payment links.","The flow should deliver: scan QR, everything pre-filled.","You are designing a payment qr code experience with visible states and recovery paths."],"whenToAvoid":["Include chain_id parameter.","Show amount, recipient alongside QR.","Use stablecoin or calculate at scan time.","Wallet or chain support is fixed and users cannot choose providers."]},"designerTakeaways":["You can design UI that delivers scan QR, everything pre-filled.","You can design UI that delivers ethereum: URI format works everywhere.","You can design UI that delivers one QR code contains all details."],"problemsSolved":[{"problem":"Manual entry of payment details is error-prone","oldWay":"Copy address, type amount, hope you got it right","newWay":"Scan QR, everything pre-filled","impact":"critical"},{"problem":"No standard for payment links","oldWay":"Every platform different payment format","newWay":"ethereum: URI format works everywhere","impact":"high"},{"problem":"Can't share complex payment requests","oldWay":"Explain: \"send 100 USDC to this address on Polygon...\"","newWay":"One QR code contains all details","impact":"high"}],"uxPatterns":[{"name":"Payment QR Code","description":"Scannable payment request","mockup":"concept/physical-link","userFlow":["Merchant creates payment request","System generates EIP-681 URI","Displays as QR code","Customer scans with wallet","Wallet auto-fills payment"]},{"name":"Donate Button","description":"One-click donation with pre-filled amount","mockup":"concept/one-click-swap","userFlow":["User clicks donation amount","Link contains ethereum: URI","Wallet opens with amount filled","User confirms payment","Donation complete"]}],"uiComponents":[{"name":"PaymentQRGenerator","description":"Creates QR code from payment details","states":["generating","ready","error"],"props":["recipient","amount","token","chainId","memo"]},{"name":"PaymentLinkButton","description":"Button that opens wallet with payment","states":["idle","clicked","no-wallet"],"props":["uri","label","amount"]},{"name":"URIDisplay","description":"Shows raw ethereum: URI with copy","states":["visible","copied"],"props":["uri","onCopy"]}],"antiPatterns":[{"pattern":"QR codes without human-readable details","why":"User can't verify before scanning","instead":"Show amount, recipient alongside QR","severity":"high"},{"pattern":"Not specifying chain in multi-chain apps","why":"Payment goes to wrong network","instead":"Include chain_id parameter","severity":"critical"},{"pattern":"Hardcoded USD values in ETH","why":"ETH price changes, $10 becomes $8","instead":"Use stablecoin or calculate at scan time","severity":"medium"}],"onMonad":[{"aspect":"Payment Confirmation","ethereum":"Scan → pay → wait 12+ seconds","monad":"Instant confirmation after payment","designImplication":"Can show \"Paid ✓\" immediately"}],"keyTakeaways":["EIP-681 = payment QR codes and links","Always show payment details alongside QR","Include chain_id for multi-chain support","Works with any EIP-681 compatible wallet","Great for point-of-sale and donations"],"technicalNotes":"EIP-681 format: ethereum:address[@chain_id][/function]?[parameters]. Parameters: value (in wei), gas, gasPrice, and arbitrary function params. Examples: ethereum:0x7a3...?value=1e17 for 0.1 ETH, ethereum:0x7a3.../transfer?address=0x&uint256=1e18 for ERC-20 transfer. Most wallets support scanning or deep linking."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-681","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=EIP-681","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/EIP-681","markdown":"https://www.eipsfordesigners.com/standards/EIP-681/content.md","agent":"https://www.eipsfordesigners.com/standards/EIP-681/agent.md","api":"https://www.eipsfordesigners.com/api/standards/EIP-681","official":"https://eips.ethereum.org/EIPS/eip-681","discussion":"https://ethereum-magicians.org/search?q=EIP-681"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"ERC-4361","name":"Sign-In with Ethereum (SIWE)","status":"Final","chain":"both","category":{"id":"onboarding","name":"Onboarding & Access","description":"Getting users into web3 without friction"},"journeyStages":[{"id":"authentication","name":"Authentication & Identity","description":"Proving who you are and logging in"}],"uxImpact":"Users sign in to websites using their Ethereum wallet instead of email/password — self-custodied identity with no centralized IdP. Design implications: display human-readable SIWE message showing domain, statement, URI, chain ID, nonce, and expiration; design clear 'Sign-In with Ethereum' buttons distinct from transaction signing; show ENS names and avatars when available; implement session management with expiration handling. Design decisions: decide session duration and refresh strategy, choose between auto-login for returning users vs explicit sign-in, design account switching when user changes wallet address, handle signature rejection gracefully without breaking auth flow, consider showing resources array for granular permission requests.","hasDetailedContent":true,"content":{"id":"ERC-4361","summary":"ERC-4361 is \"Sign-In with Ethereum\" (SIWE). Instead of email/password, users sign a message with their wallet to authenticate. The signature proves wallet ownership without revealing private keys. One wallet = one identity across all supporting apps. No more managing dozens of passwords.","applicability":{"whenToUse":["Your product addresses: every app needs separate account/password.","Your product addresses: password reuse and database breaches.","The flow should deliver: sign message with wallet = instant authentication.","You are designing a sign-in with ethereum button experience with visible states and recovery paths."],"whenToAvoid":["Server verifies domain in message matches request origin.","Clear statement: \"Sign in to [app name]\".","Set reasonable expiration, re-authenticate periodically.","Wallet or chain support is fixed and users cannot choose providers."]},"designerTakeaways":["You can design UI that delivers sign message with wallet = instant authentication.","You can design UI that delivers no password stored anywhere, cryptographic proof.","You can design UI that delivers human-readable message: \"Sign in to app.com at [time]\"."],"problemsSolved":[{"problem":"Every app needs separate account/password","oldWay":"Create account, verify email, remember password, repeat for every site","newWay":"Sign message with wallet = instant authentication","impact":"critical"},{"problem":"Password reuse and database breaches","oldWay":"Passwords stored (hashed) on servers, can be breached","newWay":"No password stored anywhere, cryptographic proof","impact":"high"},{"problem":"Sign-in requests looked like random data","oldWay":"Sign \"0x4f8a3b...\" — what does this even mean?","newWay":"Human-readable message: \"Sign in to app.com at [time]\"","impact":"high"}],"uxPatterns":[{"name":"Sign-In with Ethereum Button","description":"One-click authentication with wallet","mockup":"concept/siwe-sign-in","userFlow":["User clicks \"Sign in with Ethereum\"","Wallet shows sign message popup","User reads and approves message","Server verifies signature","User authenticated + session created"]},{"name":"SIWE Message Preview","description":"What users see in wallet when signing","mockup":"concept/siwe-sign-in","userFlow":["App generates SIWE message","Wallet displays formatted message","User verifies domain matches","User clicks Sign","Signature returned to app"]}],"uiComponents":[{"name":"SIWEButton","description":"Primary sign-in with Ethereum button","states":["idle","connecting","signing","authenticated","error"],"props":["onAuth","domain","statement"]},{"name":"SessionIndicator","description":"Shows authenticated state with session info","states":["anonymous","authenticated","expired"],"props":["address","expiresAt","onSignOut"]},{"name":"DomainBadge","description":"Verified domain indicator in sign message","states":["verified","mismatch","unknown"],"props":["domain","expectedDomain"]}],"antiPatterns":[{"pattern":"Unclear message statement","why":"Users sign without understanding what they're agreeing to","instead":"Clear statement: \"Sign in to [app name]\"","severity":"high"},{"pattern":"No session expiration","why":"Session lives forever, security risk","instead":"Set reasonable expiration, re-authenticate periodically","severity":"high"},{"pattern":"Not verifying domain matches","why":"Phishing sites could capture signatures","instead":"Server verifies domain in message matches request origin","severity":"critical"},{"pattern":"Making SIWE the only auth option","why":"Not everyone has a wallet yet","instead":"Offer email/social as alternatives for onboarding","severity":"medium"}],"onMonad":[{"aspect":"Signature Verification","ethereum":"Chain ID 1 in message","monad":"Use Monad chain ID in message","designImplication":"Update chain ID in SIWE message for Monad users"}],"keyTakeaways":["SIWE = \"Sign in with Ethereum\" — wallet-based auth","Messages must be human-readable with clear statement","Always verify domain matches to prevent phishing","Set session expiration for security","Offer alternatives for users without wallets"],"technicalNotes":"ERC-4361 defines a message format parsed by wallets: domain, address, statement, URI, version, chain ID, nonce, issued-at, and optional expiration/not-before/resources. Server generates message, user signs with personal_sign, server verifies signature matches address in message and nonce matches stored nonce."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-4361","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-4361","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-4361","markdown":"https://www.eipsfordesigners.com/standards/ERC-4361/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-4361/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-4361","official":"https://eips.ethereum.org/EIPS/eip-4361","discussion":"https://ethereum-magicians.org/search?q=ERC-4361"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"EIP-7951","name":"Precompile for secp256r1 (Passkeys)","status":"Final","chain":"both","category":{"id":"onboarding","name":"Onboarding & Access","description":"Getting users into web3 without friction"},"journeyStages":[{"id":"authentication","name":"Authentication & Identity","description":"Proving who you are and logging in"}],"uxImpact":"Users authenticate with passkeys (Face ID, Touch ID, Windows Hello, hardware security keys) instead of seed phrases — familiar biometric login for blockchain. Design implications: design passkey registration flows using device-native prompts, show biometric authentication UI for transaction signing, remove seed phrase backup requirements for passkey-only accounts, support multiple passkeys per account for device redundancy. Design decisions: decide whether passkeys supplement or replace traditional keys, design recovery flows when passkey device is lost, handle cross-device passkey sync (iCloud Keychain, Google Password Manager), consider showing security level differences between platform vs roaming authenticators. Final on Ethereum; Monad has native secp256r1 support — design passkey-first onboarding on both chains.","hasDetailedContent":true,"content":{"id":"EIP-7951","summary":"EIP-7951 adds native support for passkeys (Face ID, Touch ID, Windows Hello) to sign blockchain transactions. Instead of managing seed phrases, users authenticate with their face or fingerprint. The browser's secure hardware generates and stores keys. This is the biggest onboarding unlock: anyone with a phone can use crypto like they use Apple Pay.","applicability":{"whenToUse":["Your product addresses: seed phrases are terrible UX and security risk.","Your product addresses: new users scared away by key management complexity.","The flow should deliver: face ID or fingerprint, backed up to iCloud/Google automatically.","Connect flows must list wallets with names, icons, and explicit user choice."],"whenToAvoid":["Require secondary recovery (guardians, backup key).","\"Face ID\", \"Touch ID\", \"Fingerprint\", \"Passkey\".","Allow device passcode as fallback authentication.","Wallet or chain support is fixed and users cannot choose providers."]},"designerTakeaways":["You can design UI that delivers face ID or fingerprint.","You can design UI that delivers \"Sign up with Face ID\", feels like any other app.","You can design UI that delivers keys in Secure Enclave/TPM, never extracted."],"problemsSolved":[{"problem":"Seed phrases are terrible UX and security risk","oldWay":"Write down 12-24 words, store them safely, never lose them","newWay":"Face ID or fingerprint, backed up to iCloud/Google automatically","impact":"critical"},{"problem":"New users scared away by key management complexity","oldWay":"Explain private keys, wallets, security... users leave","newWay":"\"Sign up with Face ID\" — feels like any other app","impact":"critical"},{"problem":"Mobile wallet apps have security vulnerabilities","oldWay":"Keys stored in app, potentially accessible to malware","newWay":"Keys in Secure Enclave/TPM, never extracted","impact":"high"},{"problem":"Hardware wallets expensive and clunky","oldWay":"Buy $100+ device, connect via USB, manage firmware","newWay":"Your phone IS the hardware wallet","impact":"high"},{"problem":"Account recovery requires seed phrase backup","oldWay":"Lose phrase = lose funds forever","newWay":"Device syncs passkey via cloud (iCloud Keychain, etc.)","impact":"high"}],"uxPatterns":[{"name":"Passkey Wallet Creation","description":"One-tap wallet creation with biometric","mockup":"concept/siwe-sign-in","userFlow":["User taps \"Create Wallet\"","System shows Face ID prompt","User authenticates with face/fingerprint","Passkey created and synced","Wallet ready to use"]},{"name":"Transaction Signing with Biometric","description":"Confirm transactions with face or touch","mockup":"concept/siwe-sign-in","userFlow":["User initiates transaction","App shows transaction details","Biometric prompt appears","User authenticates","Transaction signed and broadcast"]},{"name":"Multi-Device Passkey Sync","description":"Access wallet from any device in your ecosystem","mockup":"concept/siwe-sign-in","userFlow":["User opens app on new device","Detects existing passkey via cloud","Shows available devices","User authenticates with biometric","Wallet loaded instantly"]},{"name":"Passkey + Guardian Recovery","description":"Fallback when biometric device is lost","mockup":"concept/siwe-sign-in","userFlow":["User views recovery settings","Sees passkey as primary method","Guardians as backup","Can add additional methods","All methods shown with status"]}],"uiComponents":[{"name":"BiometricPrompt","description":"Native system prompt for Face ID/Touch ID/Windows Hello","states":["idle","prompting","success","failed","unavailable"],"props":["reason","fallbackTitle","onSuccess","onFail"]},{"name":"PasskeyCreator","description":"Creates new passkey and associates with smart wallet","states":["ready","creating","syncing","complete","error"],"props":["accountAddress","rpId","userName"]},{"name":"DeviceSyncIndicator","description":"Shows which devices have access to passkey","states":["syncing","synced","offline"],"props":["devices[]","lastSync"]},{"name":"PasskeyAuthButton","description":"Initiates passkey authentication flow","states":["idle","waiting","authenticated","error"],"props":["onAuth","fallbackOptions"]},{"name":"RecoveryMethodManager","description":"Configure and view recovery options","states":["no-backup","partial","fully-configured"],"props":["methods[]","onAddMethod","onRemoveMethod"]}],"antiPatterns":[{"pattern":"Only offering passkey with no fallback","why":"Lost all devices = lost wallet forever","instead":"Require secondary recovery (guardians, backup key)","severity":"critical"},{"pattern":"Calling it \"secp256r1\" or \"WebAuthn\" to users","why":"Technical jargon that means nothing to users","instead":"\"Face ID\", \"Touch ID\", \"Fingerprint\", \"Passkey\"","severity":"high"},{"pattern":"Not explaining cloud sync clearly","why":"Users don't understand how recovery works","instead":"Show \"Backed up to iCloud\" or \"Synced via Google\"","severity":"medium"},{"pattern":"Hiding where passkey is stored","why":"Users worried about security can't evaluate it","instead":"Explain \"Key stored in your device's secure chip\"","severity":"medium"},{"pattern":"No biometric fallback (PIN/password)","why":"Wet fingers, injuries, etc. can block biometric","instead":"Allow device passcode as fallback authentication","severity":"high"},{"pattern":"Requiring passkey for low-value actions","why":"Friction fatigue — users annoyed by constant prompts","instead":"Session keys for frequent/low-value, biometric for high-value","severity":"medium"}],"onMonad":[{"aspect":"Native Support","ethereum":"Requires ERC-4337 + custom verifier contract","monad":"EIP-7951 precompile makes verification 100x cheaper","designImplication":"Passkey wallets more economically viable on Monad"},{"aspect":"Transaction Confirmation","ethereum":"Sign → wait 12+ seconds → confirmed","monad":"Sign → instant confirmation (sub-second)","designImplication":"Biometric + instant feedback feels native"},{"aspect":"Gas for Verification","ethereum":"~250k gas for secp256r1 verification","monad":"~3k gas with precompile","designImplication":"Can use passkeys for every transaction economically"},{"aspect":"Reserve Balance","ethereum":"N/A","monad":"Passkey wallets still need 10 MON reserve; delegated accounts cannot use emptying exception","designImplication":"Show spendable vs total even for passkey accounts"}],"keyTakeaways":["Passkeys = Face ID/Touch ID for crypto","Always require backup recovery method","Use human terms: \"Face ID\" not \"secp256r1\"","Show cloud sync status clearly","On Monad: 100x cheaper passkey verification via precompile"],"technicalNotes":"EIP-7951 adds a precompile at a designated address that performs secp256r1 (P-256) signature verification. This is the curve used by WebAuthn/passkeys. Without this precompile, verification costs ~250k gas via Solidity implementation. The precompile reduces this to ~3k gas. Passkeys are created via WebAuthn API, stored in device Secure Enclave, and synced via platform keychain (iCloud, Google Password Manager)."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-7951","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=EIP-7951","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/EIP-7951","markdown":"https://www.eipsfordesigners.com/standards/EIP-7951/content.md","agent":"https://www.eipsfordesigners.com/standards/EIP-7951/agent.md","api":"https://www.eipsfordesigners.com/api/standards/EIP-7951","official":"https://eips.ethereum.org/EIPS/eip-7951","discussion":"https://ethereum-magicians.org/search?q=EIP-7951"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"ERC-2771","name":"Secure Meta Transactions","status":"Final","chain":"both","category":{"id":"onboarding","name":"Onboarding & Access","description":"Getting users into web3 without friction"},"journeyStages":[{"id":"executing","name":"Executing Transactions","description":"Performing on-chain actions"}],"uxImpact":"Users submit transactions without holding ETH — a relayer pays gas fees on their behalf (meta-transactions/gasless). Design implications: remove 'insufficient funds for gas' errors entirely, hide gas price selection for sponsored transactions, show clear indication when transactions are gasless vs user-paid, design relayer selection if multiple are available. Design decisions: decide who sponsors gas (dApp, protocol, user via different token), design fallback when relayer is unavailable or congested, consider showing original signer address vs relayer address in transaction history, handle trust model — users must understand their transaction goes through a forwarder.","hasDetailedContent":true,"content":{"id":"ERC-2771","summary":"ERC-2771 enables \"meta-transactions\" — someone else pays the gas for your transaction. A trusted forwarder relays your signed message and pays gas on your behalf. This means users can interact with dApps without holding ETH. Perfect for onboarding: the dApp sponsors the user's first transactions.","applicability":{"whenToUse":["Your product addresses: new users need ETH before doing anything.","Your product addresses: gas costs scare away new users.","The flow should deliver: sponsor pays gas, user starts immediately.","You are designing a sponsored transaction experience with visible states and recovery paths."],"whenToAvoid":["Clear: \"Sponsored by X\" and when sponsorship ends.","Offer: \"Pay gas yourself\" as fallback option.","Explain: \"Sign to authorize (no gas cost)\".","Wallet or chain support is fixed and users cannot choose providers."]},"designerTakeaways":["You can remove the buy-ETH-first dead end with sponsored or clearer fees.","You can design UI that delivers \"Claim for free\", sponsor covers gas.","You can standard trusted forwarder pattern."],"problemsSolved":[{"problem":"New users need ETH before doing anything","oldWay":"Buy ETH on exchange → wait → transfer → then interact","newWay":"Sponsor pays gas, user starts immediately","impact":"critical"},{"problem":"Gas costs scare away new users","oldWay":"\"$5 to claim free NFT? No thanks.\"","newWay":"\"Claim for free\" — sponsor covers gas","impact":"critical"},{"problem":"No standard for gasless transactions","oldWay":"Every relayer had different implementation","newWay":"Standard trusted forwarder pattern","impact":"high"}],"uxPatterns":[{"name":"Sponsored Transaction","description":"User action with no gas cost","mockup":"concept/typed-data","userFlow":["User sees reward to claim","App shows \"Sponsored\" gas","User clicks Claim","Signs message (not transaction)","Relayer submits and pays gas","User receives tokens"]},{"name":"Gasless Onboarding","description":"First actions without gas","mockup":"concept/wallet","userFlow":["New user connects wallet","No ETH required for first actions","Each action signed, not sent","Relayer pays all gas","User onboarded without friction"]}],"uiComponents":[{"name":"SponsoredGasIndicator","description":"Shows that gas is being paid by sponsor","states":["sponsored","partial","user-pays"],"props":["sponsor","savingsAmount"]},{"name":"GaslessButton","description":"Action button that uses meta-transaction","states":["idle","signing","relaying","success","error"],"props":["action","sponsor","onComplete"]},{"name":"RelayerStatus","description":"Shows relayer transaction status","states":["signing","queued","submitted","confirmed"],"props":["txHash","estimatedTime"]}],"antiPatterns":[{"pattern":"Not explaining sponsored gas","why":"Users confused when later asked to pay","instead":"Clear: \"Sponsored by X\" and when sponsorship ends","severity":"high"},{"pattern":"Hiding that it's a signature, not transaction","why":"Users don't understand what they're signing","instead":"Explain: \"Sign to authorize (no gas cost)\"","severity":"medium"},{"pattern":"No fallback when relayer is down","why":"Users stuck if relayer fails","instead":"Offer: \"Pay gas yourself\" as fallback option","severity":"high"}],"onMonad":[{"aspect":"Meta-tx Confirmation","ethereum":"Relayed tx takes 12+ seconds","monad":"Sub-second even through relayer","designImplication":"Gasless feels instant"},{"aspect":"Gas Costs","ethereum":"Sponsor saves user $5-20 per tx","monad":"Already cheap, but still useful for onboarding","designImplication":"Emphasize \"no ETH needed\" over savings"}],"keyTakeaways":["ERC-2771 = meta-transactions (someone else pays gas)","Perfect for onboarding new users","Always show who sponsors and for how long","User signs message, relayer pays gas","Have fallback for when relayer unavailable"],"technicalNotes":"ERC-2771 defines trusted forwarder pattern. User signs ForwardRequest (from, to, value, gas, nonce, data). Forwarder appends msg.sender (original signer) to calldata. Receiving contract uses _msgSender() which extracts original sender from calldata when called via trusted forwarder. isTrustedForwarder(forwarder) validates the forwarder."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-2771","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-2771","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-2771","markdown":"https://www.eipsfordesigners.com/standards/ERC-2771/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-2771/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-2771","official":"https://eips.ethereum.org/EIPS/eip-2771","discussion":"https://ethereum-magicians.org/search?q=ERC-2771"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"ERC-6492","name":"Signature Validation for Predeploy Contracts","status":"Final","chain":"both","category":{"id":"onboarding","name":"Onboarding & Access","description":"Getting users into web3 without friction"},"journeyStages":[{"id":"authentication","name":"Authentication & Identity","description":"Proving who you are and logging in"}],"uxImpact":"Smart contract wallets can sign messages before deployment — users don't need an initial transaction to start using their account. Design implications: enable 'Sign-In with Ethereum' and message signing for freshly created accounts with zero transactions, remove 'deploy wallet first' friction from onboarding, show account address even before deployment. Design decisions: decide whether to surface deployment status to users or abstract it away, design consistent verification flows that work for both deployed and counterfactual contracts, handle edge cases where signature was created pre-deployment but verified post-deployment, consider showing 'account not yet deployed' status in explorers.","hasDetailedContent":true,"content":{"id":"ERC-6492","sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-6492","type":"official-spec"}],"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25","summary":"Smart contract wallets can sign messages before deployment — users don't need an initial transaction to start using their account.","designerTakeaways":["You can offer SIWE on day zero for smart accounts that have never sent a transaction.","Your UI can hide deployment complexity unless it affects cost, timing, or risk.","You can show the same address before and after first transaction for continuity."],"applicability":{"whenToUse":["Smart wallet onboarding should not require a deploy transaction before sign-in.","Your auth flow uses SIWE or off-chain message verification.","Users connect counterfactual accounts from ERC-4337 factories."],"whenToAvoid":["You only support EOAs with on-chain history.","Your verifier cannot simulate contract deployment.","The flow requires deployed contract code for every read path."]},"prototypeFirst":[{"screen":"Primary happy path","why":"Prove the core user promise before edge cases.","covers":["Success state","Clear outcome copy"],"include":["Primary CTA","Confirmation feedback","Next step"]},{"screen":"Blocked or unsupported state","why":"Users discover limits when wallets or chains lack support.","covers":["Unsupported wallet","Wrong network"],"include":["Plain-language reason","Fallback action"]},{"screen":"Failure recovery","why":"Trust breaks when errors look like bugs.","covers":["User rejection","Transaction revert"],"include":["Retry path","Support context"]},{"screen":"Advanced disclosure","why":"Power users need technical detail without cluttering the default path.","covers":["Contract address","Token ID","Raw status"],"include":["Expandable section","Copy buttons","Explorer link"]}],"mentalModel":[{"label":"Counterfactual address","description":"The smart account address exists before deployment. Users see one consistent address from onboarding through first transaction."},{"label":"Offchain signature","description":"The wallet signs SIWE or typed data using ERC-6492 proof that wraps factory data for an undeployed contract."},{"label":"Verifier simulation","description":"Your backend or wallet simulates deployment plus signature validity. Auth succeeds without an upfront deploy transaction."},{"label":"First onchain action","description":"The initial transaction may include contract deployment. Hide deployment complexity unless it changes cost, timing, or risk."},{"label":"Continuity","description":"Before and after deploy, address and session identity stay the same. Do not make users reconnect after first transaction."}],"statesToDesign":[{"state":"Ready","trigger":"Prerequisites met.","userNeed":"Understand what happens next.","designResponse":"Enable primary action with plain-language preview."},{"state":"Awaiting signature","trigger":"Wallet prompt open.","userNeed":"Know what they are approving.","designResponse":"Mirror human-readable summary in app and wallet."},{"state":"Pending","trigger":"Transaction submitted.","userNeed":"Confidence it is progressing.","designResponse":"Show status strip with explorer link."},{"state":"Succeeded","trigger":"On-chain confirmation.","userNeed":"See updated ownership or balance.","designResponse":"Celebrate outcome and show new state clearly."},{"state":"Failed or reverted","trigger":"Validation or execution failed.","userNeed":"Fix or retry without guessing.","designResponse":"Name the failed constraint and offer a concrete next step."}],"designDecisions":[{"question":"How much protocol detail do users see?","recommendation":"Lead with outcomes; tuck identifiers behind review.","rationale":"Users decide on consequences, not function selectors."},{"question":"What happens when support is missing?","recommendation":"Block with explanation and fallback path.","rationale":"Silent failure feels like a broken product."},{"question":"How do you label restricted assets?","recommendation":"Use persistent badges for non-transferable, locked, or expiring states.","rationale":"Hidden restrictions cause rage-quits at transfer time."}],"problemsSolved":[{"problem":"Inconsistent behavior across apps","oldWay":"Each team reinvents copy and edge cases","newWay":"Shared standard gives predictable UX patterns","impact":"high"},{"problem":"Users surprised by on-chain rules","oldWay":"Generic transfer UI fails at submit time","newWay":"Standard-aware UI sets expectations upfront","impact":"high"},{"problem":"Support burden from opaque errors","oldWay":"Raw revert reasons in toasts","newWay":"Mapped states explain what to do next","impact":"medium"}],"uxPatterns":[{"name":"Counterfactual Sign-In","description":"Authenticate with a not-yet-deployed smart account.","mockup":"concept/siwe-sign-in","components":["SIWEButton","AddressChip"],"userFlow":["User connects smart account","Signs SIWE message","Server verifies via ERC-6492","Session created"]},{"name":"Deployment Status Chip","description":"Optional indicator for advanced users.","mockup":"concept/siwe-sign-in","components":["StatusBadge","Tooltip"],"userFlow":["Account connected","Query deployment status","Show Active or Activates on first use"]}],"seenInTheWild":[{"app":"Safe","url":"https://safe.global/","note":"Smart accounts commonly exist counterfactually before first execution."},{"app":"Coinbase Smart Wallet","url":"https://www.coinbase.com/wallet/smart-wallet","note":"Passkey smart wallets sign before deployment."},{"app":"Ambire","url":"https://www.ambire.com/","note":"Smart wallet onboarding emphasizes immediate use over deploy-first."}],"antiPatterns":[{"pattern":"Hiding standard-imposed restrictions until submit","why":"Users feel tricked when actions fail at the last step","instead":"Show eligibility and badges before the primary CTA","severity":"critical"},{"pattern":"Protocol jargon in user-facing copy","why":"Non-technical users cannot consent informedly","instead":"Use outcome language with optional technical disclosure","severity":"high"},{"pattern":"No fallback when wallet lacks support","why":"Dead-end flows increase churn","instead":"Explain limitation and offer alternate path or network","severity":"high"}],"vocabulary":[{"use":"Your balance / Your item","avoid":"Token ID / Token contract","why":"Ownership language matches mental models."},{"use":"Cannot transfer yet","avoid":"Transfer reverted","why":"Explain restriction without EVM vocabulary."},{"use":"Confirm in wallet","avoid":"Sign transaction","why":"Matches wallet UX users already know."}],"onMonad":[{"aspect":"Confirmation speed","ethereum":"Multi-step flows can feel slow between signatures","monad":"Sub-second finality tightens feedback loops","designImplication":"Prefer inline status over long pending modals on Monad."},{"aspect":"Transaction cost","ethereum":"Gas can discourage exploratory actions","monad":"Lower fees enable lighter-weight interactions","designImplication":"Safe to offer preview retries and social actions more freely."}],"technicalNotes":"ERC-6492 wraps a signature with factory and calldata so off-chain verifiers can simulate deployment.","relatedStandards":[{"id":"ERC-4361","relationship":"SIWE auth enabled for undeployed accounts"},{"id":"ERC-4337","relationship":"Smart accounts often verified counterfactually"}]},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-6492","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-6492","type":"discussion"},{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-6492","type":"official-spec"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-6492","markdown":"https://www.eipsfordesigners.com/standards/ERC-6492/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-6492/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-6492","official":"https://eips.ethereum.org/EIPS/erc-6492","discussion":"https://ethereum-magicians.org/search?q=ERC-6492"},"freshness":{"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25"}},{"id":"EIP-7702","name":"Set Code for EOAs","status":"Final","chain":"both","category":{"id":"transaction-friction","name":"Transaction Friction","description":"Reducing clicks, signatures, and mental overhead"},"journeyStages":[{"id":"executing","name":"Executing Transactions","description":"Performing on-chain actions"}],"uxImpact":"EOAs gain smart contract capabilities without migrating to new wallets — users keep existing addresses. Design implications: enable transaction batching UI (approve+swap in one click), show sponsored transaction options where dApps pay gas, add session key management for limited permissions (e.g., 'allow spending up to $100/day'). Design decisions: balance power vs complexity — advanced features need progressive disclosure, must clearly distinguish temporary delegations from permanent changes, consider how to surface 'who's paying for this' when sponsors are involved. 🟢 LIVE on mainnet — 9 wallets, 12.9M accounts, 117M authorizations. Bridges from EOAs to smart accounts while native AA (EIP-8141) is in draft. Addresses Gas Hurdle (Critical), Key Management (High), and Protocol Design sections.","hasDetailedContent":true,"content":{"id":"EIP-7702","summary":"EIP-7702 lets existing wallets temporarily act like smart wallets. Users keep their address but gain batching, sponsored gas, and session keys. It is the bridge that brings smart wallet UX to everyone without forcing migration.","designerTakeaways":["You can combine approve + swap into one confirmation instead of stacked wallet popups.","Your onboarding can sponsor the first transaction so new users never need ETH upfront.","Games can use a one-time permission screen, then play without a signature on every action."],"applicability":{"whenToUse":["Existing EOAs need batching, sponsorship, or session keys without a new address.","You want one signature for approve + action flows on supported networks.","Games or apps need low-friction repeat actions after an upfront authorization."],"whenToAvoid":["The wallet or chain does not support 7702-style delegation yet.","A full smart account (ERC-4337) already covers your requirements with clearer status UX.","Users only perform single low-risk transfers where delegation adds confusion."]},"designDecisions":[{"question":"When do you ask users to enable smart features?","recommendation":"Offer upgrade after value is clear, not as a gate on first connect.","rationale":"Forced delegation at onboarding creates drop-off before users see benefit."},{"question":"How do you preview batched actions?","recommendation":"Show every step with outcomes before one signature.","rationale":"Hidden batch steps feel like blind signing when something unexpected executes."},{"question":"What limits apply to session keys?","recommendation":"Require spend cap, allowed actions, and expiration with a revoke-all control.","rationale":"Unbounded session keys turn a game UX bug into a full wallet drain."},{"question":"How do you label sponsorship?","recommendation":"Use honest \"Sponsored\" copy and state when the user will pay gas again.","rationale":"Surprise fees after \"free\" transactions break trust on the next action."}],"statesToDesign":[{"state":"Delegation not enabled","trigger":"EOA has not authorized 7702 code for this session.","userNeed":"Understand optional upgrade path.","designResponse":"Benefit-led CTA; keep core flows working without delegation."},{"state":"Batch preview","trigger":"User initiates multi-step action.","userNeed":"See all consequences in order.","designResponse":"Checklist of steps with combined outcome before sign."},{"state":"Session active","trigger":"Session key authorized within limits.","userNeed":"Know what the app can still do without prompts.","designResponse":"Session badge with limits, expiry, and revoke in settings."},{"state":"Sponsored gas","trigger":"Paymaster or sponsor covers fees.","userNeed":"Know cost is covered now and later.","designResponse":"Sponsored label on fee row; note when user-paid gas returns."},{"state":"Delegation revoked","trigger":"User revokes session or delegation expires.","userNeed":"Confirm the app can no longer act silently.","designResponse":"Toast plus return to per-action signatures."}],"mentalModel":[{"label":"Existing EOA","description":"The user keeps the same address and seed phrase. Delegation adds capabilities without migration or a new receive address."},{"label":"Delegation code","description":"A type-0x04 transaction temporarily attaches smart wallet logic to the EOA. Your UI explains this as \"enable smart features,\" not delegate or authorization."},{"label":"Batched execution","description":"Multiple contract calls run in one atomic sequence after a single signature. Preview every step before the wallet prompt."},{"label":"Session keys","description":"A scoped permission lets the app act within spend and time limits without per-action popups. Always show limits and a revoke path."},{"label":"Gas sponsorship","description":"A paymaster or sponsor can cover fees for the delegated transaction. Label sponsored fees honestly and note when the user pays again."}],"problemsSolved":[{"problem":"Users must sign every transaction individually","oldWay":"Approve token, wait, confirm, swap, wait, confirm (multiple popups)","newWay":"Sign once, all steps execute atomically","impact":"critical"},{"problem":"New users need ETH before they can do anything","oldWay":"Buy ETH on exchange, transfer to wallet, wait, then interact","newWay":"App sponsors first transaction, user starts immediately","impact":"critical"},{"problem":"Games interrupted by constant signature requests","oldWay":"Sign for every sword swing, every loot pickup","newWay":"Session key pre-authorized for game actions","impact":"high"},{"problem":"Switching to smart wallet means new address","oldWay":"Deploy new contract wallet, transfer all assets, update everywhere","newWay":"Same address gains smart wallet powers instantly","impact":"high"},{"problem":"Complex DeFi operations require multiple transactions","oldWay":"Unstake, claim rewards, swap, restake (4 separate transactions)","newWay":"One batched transaction does everything","impact":"medium"}],"uxPatterns":[{"name":"One-Click Multi-Step","description":"Combine approve and action into a single user interaction.","mockup":"one-click-swap","components":["Batch preview","Step checklist","One-click button"],"userFlow":["User enters swap amount","UI shows combined preview of all steps","Single Swap button click","Wallet shows single signature request","All steps execute atomically","Success state shown"]},{"name":"Sponsored First Transaction","description":"New users transact without holding ETH.","mockup":"sponsored-claim","components":["Sponsored badge","Gas display","Claim button"],"userFlow":["New user connects wallet","App detects empty wallet (no ETH)","Shows Sponsored badge on gas fee","User clicks claim","App paymaster covers gas","User receives NFT without spending anything"]},{"name":"Session Keys for Gaming","description":"Pre-authorize game actions without per-action signatures.","mockup":"session-permissions","components":["Permission checklist","Time limit","Spend limit"],"userFlow":["User starts game","Permission selection UI shown","User configures limits","Single signature creates session key","Game plays without interruption","Session auto-expires"]}],"seenInTheWild":[{"app":"MetaMask","url":"https://metamask.io/","note":"Supports EIP-7702 delegation for batch transactions and smart account features on supported networks."},{"app":"Ambire Wallet","url":"https://www.ambire.com/","note":"Uses 7702-style delegation to batch approve + swap flows behind a single signature."},{"app":"Biconomy","url":"https://www.biconomy.io/","note":"SDK layer for gas sponsorship and batched calls that pairs with 7702-enabled accounts."},{"app":"Coinbase Smart Wallet","url":"https://www.coinbase.com/wallet/smart-wallet","note":"Smart account flows with sponsored first transactions and batched operations for new users."}],"antiPatterns":[{"pattern":"Forcing users to enable 7702 before basic actions","why":"Creates friction at worst moment (new user onboarding)","instead":"Make it optional, show benefits, let them upgrade later","severity":"critical"},{"pattern":"Hiding what batch transaction will do","why":"Users sign blind, lose trust if something unexpected happens","instead":"Show clear preview of ALL steps before signing","severity":"critical"},{"pattern":"Session keys with no limits","why":"Compromised session key drains wallet","instead":"Require spend limits and expiration times","severity":"critical"},{"pattern":"No way to revoke session keys","why":"Users feel trapped, cannot secure their account","instead":"Prominent Revoke All Sessions button in settings","severity":"high"},{"pattern":"Using technical terms like \"delegate\" or \"authorization\"","why":"Users do not understand what they are agreeing to","instead":"Say \"Enable smart features\" or \"Start gaming session\"","severity":"high"},{"pattern":"Not showing sponsored gas clearly","why":"Users confused when gas suddenly costs money","instead":"Show Sponsored badge AND explain when sponsorship ends","severity":"medium"}],"onMonad":[{"aspect":"Reserve Balance","ethereum":"Delegated code can spend entire balance","monad":"Delegated accounts enforce 10 MON reserve strictly","designImplication":"Show spendable balance vs total balance; delegated wallets have stricter constraints"},{"aspect":"Transaction Speed","ethereum":"Batch transactions may take 15+ seconds","monad":"Sub-second finality for all operations","designImplication":"Show real-time feedback, skip waiting states"},{"aspect":"Gas Costs","ethereum":"Batching saves ~21k gas per eliminated tx","monad":"Already cheap, savings less dramatic","designImplication":"Emphasize convenience over cost savings"}],"technicalNotes":"EIP-7702 adds a new transaction type (0x04) that sets an EOA's code to point to a contract. The EOA can then execute the contract's logic while maintaining its address. Delegation is per-transaction and explicitly authorized. Works with ERC-4337 paymasters for gas sponsorship."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-7702","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=EIP-7702","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/EIP-7702","markdown":"https://www.eipsfordesigners.com/standards/EIP-7702/content.md","agent":"https://www.eipsfordesigners.com/standards/EIP-7702/agent.md","api":"https://www.eipsfordesigners.com/api/standards/EIP-7702","official":"https://eips.ethereum.org/EIPS/eip-7702","discussion":"https://ethereum-magicians.org/search?q=EIP-7702"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"EIP-3074","name":"AUTH and AUTHCALL Opcodes","status":"Draft","chain":"ethereum","category":{"id":"transaction-friction","name":"Transaction Friction","description":"Reducing clicks, signatures, and mental overhead"},"journeyStages":[{"id":"executing","name":"Executing Transactions","description":"Performing on-chain actions"}],"supersededBy":"EIP-7702","uxImpact":"Predecessor to EIP-7702: introduced AUTH and AUTHCALL opcodes letting users sign an authorization so an 'invoker' contract could act on their behalf — enabling sponsored transactions, batching, and delegation without deploying a smart wallet. Superseded by EIP-7702 before mainnet deployment, so this guidance is historical: build new flows on EIP-7702, but the invoker/authorization mental model and its sponsored-transaction UX patterns informed 7702's design.","hasDetailedContent":true,"content":{"id":"EIP-3074","summary":"EIP-3074 introduced AUTH and AUTHCALL opcodes, letting users authorize a contract (invoker) to act on their behalf. Users sign an authorization message, and the invoker can then make calls as if it were the user's address. This enables sponsored transactions, batch operations, and delegation without deploying a smart wallet.","applicability":{"whenToUse":["Your product addresses: eOAs couldn't delegate actions.","Your product addresses: each operation needed separate transaction.","The flow should deliver: authorize an invoker to act on your behalf.","You are designing a authorize invoker experience with visible states and recovery paths."],"whenToAvoid":["Show invoker address, name, verification status.","Prominent authorization manager with revoke options.","Clear list of capabilities being granted."]},"designerTakeaways":["You can design UI that delivers authorize an invoker to act on your behalf.","You can collapse multi-step actions into one confirmation users understand.","You can design UI that delivers invoker submits tx, can pay gas for user."],"problemsSolved":[{"problem":"EOAs couldn't delegate actions","oldWay":"Every action required direct transaction from EOA","newWay":"Authorize an invoker to act on your behalf","impact":"critical"},{"problem":"Each operation needed separate transaction","oldWay":"Approve, then swap, then stake = 3 transactions","newWay":"Authorize invoker, batch everything in one call","impact":"high"},{"problem":"Users always paid their own gas","oldWay":"Need ETH in wallet before any action","newWay":"Invoker submits tx, can pay gas for user","impact":"high"},{"problem":"No way to revoke stuck approvals atomically","oldWay":"Multiple transactions to clean up approvals","newWay":"Invoker can batch multiple revokes in one call","impact":"medium"}],"uxPatterns":[{"name":"Authorize Invoker","description":"Grant an invoker permission to act on your behalf","mockup":"concept/physical-link","userFlow":["dApp requests authorization","Wallet shows invoker details","Permissions clearly listed","User reviews and approves","Signed auth message returned"]},{"name":"Sponsored Batch Transaction","description":"Execute multiple operations with sponsored gas","mockup":"generic/token-approval","userFlow":["User already authorized invoker","Batch transaction prepared","All steps shown clearly","Gas sponsored by invoker","One click executes all"]},{"name":"Active Authorizations","description":"View and revoke active invoker authorizations","mockup":"concept/bundled-defi","userFlow":["User views active authorizations","See which invokers are authorized","Usage stats for each","Individual or bulk revocation","Clear authorization audit trail"]},{"name":"Invoker Trust Verification","description":"Help users verify invoker trustworthiness","mockup":"concept/verify-safety","userFlow":["User considering authorization","Check invoker verification status","Review trust signals","Access audit and source","Make informed decision"]}],"uiComponents":[{"name":"InvokerAuthorization","description":"Request authorization for an invoker","states":["requesting","reviewing","authorized","rejected"],"props":["invokerAddress","invokerName","permissions[]","onAuth","onReject"]},{"name":"AuthorizationManager","description":"View and manage active authorizations","states":["loading","has-auths","no-auths"],"props":["authorizations[]","onRevoke","onRevokeAll"]},{"name":"InvokerTrustScore","description":"Display trust signals for an invoker","states":["verified","unverified","warning"],"props":["invokerAddress","signals[]","score"]},{"name":"BatchTransactionPreview","description":"Show operations that will execute via AUTH","states":["loading","ready","executing"],"props":["operations[]","gasSponsored","onExecute"]}],"antiPatterns":[{"pattern":"Not showing invoker details","why":"User authorizing unknown contract is dangerous","instead":"Show invoker address, name, verification status","severity":"critical"},{"pattern":"No way to revoke authorizations","why":"Users can't secure their account if invoker compromised","instead":"Prominent authorization manager with revoke options","severity":"critical"},{"pattern":"Hiding what invoker can do","why":"User doesn't understand scope of authorization","instead":"Clear list of capabilities being granted","severity":"high"},{"pattern":"Not validating invoker trust","why":"Users might authorize malicious invokers","instead":"Show trust signals, audit status, usage stats","severity":"high"},{"pattern":"Persistent authorizations without expiry","why":"Old authorizations become security risks","instead":"Session-based or time-limited authorizations","severity":"medium"}],"onMonad":[{"aspect":"Fast Batch Execution","ethereum":"Batch via AUTH still takes 12+ seconds","monad":"Sub-second execution of entire batch","designImplication":"Batch operations feel instant, great UX"},{"aspect":"Gas Sponsorship Value","ethereum":"Sponsored gas saves users real money","monad":"Gas already cheap, sponsorship less dramatic","designImplication":"Emphasize convenience over cost savings"},{"aspect":"EIP-7702 Overlap","ethereum":"EIP-3074 and EIP-7702 serve similar purposes","monad":"Both available, 7702 often preferred for permanence","designImplication":"Guide users to appropriate solution for their needs"}],"relatedStandards":[{"id":"EIP-7702","relationship":"EIP-7702 is successor/alternative providing similar capabilities with different tradeoffs"},{"id":"ERC-4337","relationship":"Account abstraction provides another approach to sponsored/batched transactions"},{"id":"ERC-2771","relationship":"Meta transactions offer simpler sponsorship without invoker pattern"},{"id":"EIP-712","relationship":"AUTH messages use EIP-712 for structured signing"}]},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-3074","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=EIP-3074","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/EIP-3074","markdown":"https://www.eipsfordesigners.com/standards/EIP-3074/content.md","agent":"https://www.eipsfordesigners.com/standards/EIP-3074/agent.md","api":"https://www.eipsfordesigners.com/api/standards/EIP-3074","official":"https://eips.ethereum.org/EIPS/eip-3074","discussion":"https://ethereum-magicians.org/search?q=EIP-3074"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"ERC-4337","slug":"account-abstraction","name":"Account Abstraction Using Alt Mempool","status":"Last Call","chain":"both","category":{"id":"transaction-friction","name":"Transaction Friction","description":"Reducing clicks, signatures, and mental overhead"},"journeyStages":[{"id":"executing","name":"Executing Transactions","description":"Performing on-chain actions"},{"id":"gas","name":"Gas & Fees","description":"Paying for transactions"}],"uxImpact":"Users interact with smart accounts instead of EOAs. No seed phrases required, social recovery possible, gas payable in any token. Design implications: design onboarding without 'write down 12 words', show gas payment token selector, build recovery flows (guardian management UI), display bundled operations as single actions. Design decisions: tradeoff between custodial simplicity and self-custody complexity, must handle paymaster failures gracefully, decide whether to abstract UserOperations completely or expose for power users. 54M+ smart accounts, 1B+ UserOps. Smart wallets retain 70% of users vs 60% for seed-phrase wallets . Primary solution to Gas Hurdle (Critical), Key Management Burden (High), and Forced Backup Friction (Medium). Widely deployed (Safe, Biconomy, ZeroDev).","hasDetailedContent":true,"content":{"id":"ERC-4337","summary":"ERC-4337 is the infrastructure that makes \"Account Abstraction\" work. It creates a parallel system where smart contract wallets can exist with full programmability: custom validation (passkeys, multisig), gas sponsorship via paymasters, bundled operations, and account recovery. It's the backend that powers the best wallet UX patterns.","designerTakeaways":["Checkouts can let users pay gas in USDC or have it sponsored, so \"buy ETH first\" disappears from the flow.","Account recovery can look like a password reset: guardians, an M-of-N threshold, and a cancel-able timer.","Multi-step flows (approve, swap, stake) can collapse into a single atomic confirmation instead of stacked modals."],"applicability":{"whenToUse":["New users need to act before they own ETH for gas.","The product benefits from one confirmation for approve, swap, mint, stake, or claim flows.","The account needs recovery, spending limits, passkeys, guardians, or multisig rules.","The team can support smart account infrastructure and clear fallback states."],"whenToAvoid":["The product cannot support bundler and paymaster failure paths.","The user must keep using a plain EOA with no smart account layer.","The flow is a single low-risk transaction where sponsorship, batching, or recovery adds no user value.","The team cannot explain who controls recovery or who pays fees."]},"prototypeFirst":[{"screen":"Fee selection","why":"This is where ERC-4337 removes the \"buy ETH first\" dead end, but only if the fee model is clear.","covers":["Gas sponsorship","Pay gas with another token","Paymaster unavailable"],"include":["Sponsored label with value","Fee token options","Fallback to user-paid gas"]},{"screen":"Bundled confirmation","why":"One signature can contain multiple consequences. The user still needs to understand the full action.","covers":["Approve plus action","Atomic execution","Simulation failure"],"include":["Ordered step preview","All-or-nothing copy","Blocked signing when simulation fails"]},{"screen":"Recovery setup","why":"Recovery replaces the seed phrase backup moment, so it needs to feel like account safety, not advanced settings.","covers":["Guardian invites","M-of-N threshold","Recovery inactive state"],"include":["Guardian status rows","Threshold copy","Clear \"not protected yet\" state"]},{"screen":"Recovery in progress","why":"A recovery flow is both help and risk. The owner must see what is happening and how to stop it.","covers":["Guardian approvals","Security delay","Cancel recovery"],"include":["Countdown","Approving guardians","New owner destination","Prominent cancel action"]},{"screen":"Operation status","why":"ERC-4337 adds steps between signing and confirmation. Status copy should make progress feel legible.","covers":["Signed","Bundler pending","Included","Confirmed"],"include":["Single status strip","Plain-language states","Expandable user operation hash"]}],"mentalModel":[{"label":"User intent","description":"The product still asks the user to send, swap, mint, or recover. \"UserOperation\" is only the package the app builds behind the interface."},{"label":"Smart account","description":"The account is contract code, so validation can be passkeys, guardians, multisig, session keys, or another rule the wallet supports."},{"label":"Bundler","description":"A bundler collects valid operations and submits them on-chain. Your status UI should track submission, inclusion, and confirmation as one journey."},{"label":"EntryPoint","description":"The EntryPoint checks account and paymaster rules before execution. Failed simulation belongs in the product UI before the user signs."},{"label":"Paymaster","description":"A paymaster can sponsor gas or charge another token. Designers need a clear fallback when sponsorship is unavailable."}],"statesToDesign":[{"state":"Account not deployed","trigger":"The user is using a counterfactual smart account for the first time.","userNeed":"Know whether setup is automatic, costs money, or changes timing.","designResponse":"Keep it in setup or transaction details unless deployment affects cost, time, or risk."},{"state":"Paymaster quote unavailable","trigger":"The sponsor cannot quote gas or the selected fee token is unsupported.","userNeed":"A path forward that does not feel like a broken checkout.","designResponse":"Offer another fee token, user-paid gas, or a retry with plain-language reason copy."},{"state":"Simulation failed","trigger":"The operation would fail during validation or execution.","userNeed":"Understand what to fix before signing.","designResponse":"Block signing, name the failed step, and give a concrete action such as reduce amount or remove step."},{"state":"Bundler pending","trigger":"The user signed, but the operation is waiting for inclusion.","userNeed":"Confidence that the action left their device and is still progressing.","designResponse":"Show sent, processing, included, and confirmed as one status strip with an expandable technical ID."},{"state":"Guardian invite pending","trigger":"A recovery contact has not accepted or confirmed.","userNeed":"Know whether the account is protected yet.","designResponse":"Show inactive recovery until the threshold can be reached, not just a generic pending badge."},{"state":"Security delay active","trigger":"Recovery has enough guardian approvals and is waiting out the delay.","userNeed":"Know when recovery completes and how to stop it if it is suspicious.","designResponse":"Show countdown, approving guardians, destination account, and a prominent cancel action."}],"designDecisions":[{"question":"Who pays gas in this flow?","recommendation":"Show one fee model at a time: sponsored, paid in native token, or paid in another token.","rationale":"Users need to know whether the app is covering the cost, whether their token balance will change, and what happens when sponsorship ends."},{"question":"How does the user recover the account?","recommendation":"Design guardian setup, threshold progress, a security delay, and a cancel path as first-class states.","rationale":"Recovery is not a settings footnote. It is the replacement for \"save these 12 words\", so the user must understand it before they need it."},{"question":"How much protocol detail appears in the confirmation?","recommendation":"Summarize the human action first, then expose technical details behind review or advanced disclosure.","rationale":"The protocol has many actors, but the user is approving an outcome. Showing plumbing first creates doubt instead of informed consent."},{"question":"What happens if the operation cannot be included?","recommendation":"Preflight with simulation, then give a specific recovery action: change fee token, remove a step, retry later, or pay gas yourself.","rationale":"ERC-4337 adds new failure points. Generic \"transaction failed\" copy hides the fix and makes the smart account feel unreliable."},{"question":"Does the account need to be deployed now?","recommendation":"Treat deployment as setup work unless the cost or timing changes the user decision.","rationale":"Counterfactual accounts let users begin before deployment, but first execution may still create the account and affect gas or status timing."}],"problemsSolved":[{"problem":"Users must hold ETH to do anything on-chain","oldWay":"Buy ETH → transfer → wait → then interact","newWay":"Paymaster sponsors gas, user pays in USDC or nothing at all","impact":"critical"},{"problem":"Losing seed phrase = losing everything","oldWay":"12 words is only backup, lose it and funds are gone forever","newWay":"Social recovery, guardian signatures, account restoration possible","impact":"critical"},{"problem":"Only ECDSA signatures work for authentication","oldWay":"Must sign with private key derived from seed phrase","newWay":"Custom validation: passkeys, multisig, MPC, anything","impact":"high"},{"problem":"Each operation requires separate transaction","oldWay":"Approve, wait, swap, wait, stake, wait...","newWay":"UserOps bundle multiple calls, execute atomically","impact":"high"},{"problem":"Smart wallets couldn't initiate transactions","oldWay":"Needed an EOA to trigger contract wallet actions","newWay":"Bundlers submit UserOps, wallets work independently","impact":"high"}],"uxPatterns":[{"name":"Gas Abstraction","description":"User sees final cost in their preferred token or zero","mockup":"gas-abstraction","components":["Gas token picker","Estimated cost","Order total"],"userFlow":["User initiates purchase","App fetches gas quotes from paymaster","User selects payment token","UserOp created with paymaster data","User signs once","Paymaster handles conversion"]},{"name":"Social Recovery Setup","description":"Configure guardians who can help recover account","mockup":"social-recovery-setup","components":["Guardian list","Guardian status row","Threshold control","Time-lock notice"],"userFlow":["User opens recovery settings","Adds guardian addresses or emails","Sets threshold (2 of 3)","Guardians confirm participation","Recovery becomes active"]},{"name":"Account Recovery Flow","description":"Guardian-assisted account restoration","mockup":"account-recovery","components":["Approval progress","Time-lock countdown","Recovery status"],"userFlow":["User initiates recovery from new device","Contacts guardians for approval","Guardians sign recovery request","Threshold reached","Time lock countdown begins","Recovery completes after delay"]},{"name":"Bundled DeFi Operations","description":"Complex multi-step DeFi in one interaction","mockup":"bundled-defi","components":["Step list","Savings summary","Execute-all button"],"userFlow":["User selects strategy/actions","App builds UserOp with all calls","Shows preview with savings","User signs once","All steps execute atomically"]}],"uiComponents":[{"name":"Gas token picker","description":"Choose which token to pay gas with, or use a sponsor","kind":"selector","states":["loading","ready","no sponsors","selected"],"props":["availableTokens[]","gasEstimates","selectedToken","onSelect"]},{"name":"Guardian list","description":"Add, remove, and see the status of recovery guardians","kind":"list","states":["empty","configuring","active","recovering"],"props":["guardians[]","threshold","onAdd","onRemove"]},{"name":"Transaction preview","description":"Show what a single bundled transaction will do, step by step","kind":"preview","states":["building","ready","simulating","error"],"props":["calls[]","gasEstimate","paymasterInfo"]},{"name":"Recovery progress","description":"Track guardian approvals, the time lock, and final completion","kind":"progress","states":["initiating","gathering approvals","time-locked","complete"],"props":["approvals","threshold","timelockRemaining"]},{"name":"Submission status","description":"Show submission, inclusion, and confirmation as one strip","kind":"status","states":["submitting","pending","included","confirmed","failed"],"props":["userOpHash","txHash","error"]}],"seenInTheWild":[{"app":"Coinbase Smart Wallet","url":"https://www.coinbase.com/wallet/smart-wallet","note":"Passkey signup, no seed phrase shown. App-level gas sponsorship for first-time interactions."},{"app":"Safe (Smart Account)","url":"https://safe.global/","note":"Original smart contract wallet. Multisig, modules, and 4337-compatible bundled transactions."},{"app":"Privy","url":"https://privy.io/","note":"Embedded wallets that sign in with email or social, then route transactions through a bundler so users never see ETH."},{"app":"Argent","url":"https://www.argent.xyz/","note":"Pioneered guardian-based social recovery and the cancel-able time lock UX patterns most wallets now copy."},{"app":"ZeroDev","url":"https://zerodev.app/","note":"SDK for building bundled multi-step actions (approve + swap + stake) behind a single signature."}],"antiPatterns":[{"pattern":"Exposing \"UserOperation\" terminology to users","why":"Technical jargon confuses users, they just want to \"send\" or \"swap\"","instead":"Use familiar terms: transaction, transfer, swap","severity":"high"},{"pattern":"No fallback when paymaster rejects","why":"User stuck if sponsor runs out or rejects","instead":"Graceful fallback to ETH with clear explanation","severity":"critical"},{"pattern":"Recovery with no time delay","why":"Compromised guardian could instantly steal account","instead":"Mandatory time lock (24-72h) to allow legitimate owner to cancel","severity":"critical"},{"pattern":"Single guardian recovery","why":"One compromised contact = lost account","instead":"Require M-of-N threshold (e.g., 2 of 3 guardians)","severity":"critical"},{"pattern":"Hiding gas costs in sponsored transactions","why":"Users shocked when sponsorship ends and they pay","instead":"Show \"Sponsored ($0.35 value)\" so users understand","severity":"medium"},{"pattern":"Not simulating UserOps before submission","why":"Failed UserOps waste user time and sometimes gas","instead":"Always simulate and show clear error if it would fail","severity":"high"}],"vocabulary":[{"use":"Transaction","avoid":"UserOperation, UserOp","why":"UserOp is internal protocol jargon. From the user's seat, they are sending a transaction. What happens under the hood is not their concern."},{"use":"Smart wallet, Smart account","avoid":"4337 wallet, ERC-4337 account","why":"Spec IDs do not belong in user UI. \"Smart wallet\" tells the user it can do more than a normal wallet without naming the protocol."},{"use":"Sponsored, Free for you","avoid":"Gasless, Free gas","why":"\"Gasless\" is ambiguous: does it mean truly free, or paid in another token? \"Sponsored\" is honest about someone else paying."},{"use":"Pay gas with USDC","avoid":"Use ERC-20 paymaster, Token paymaster","why":"Paymaster is the backend role. The user just sees which token they are paying with."},{"use":"Guardian","avoid":"Trustee, Recovery key, Co-signer","why":"Argent introduced \"guardian\" and the ecosystem standardized on it. Trustee sounds legal, co-signer sounds like a loan, recovery key sounds like a thing you can lose."},{"use":"Security delay","avoid":"Time lock, Timelock","why":"\"Time lock\" is engineer language. \"Security delay\" tells the user what the delay is for and why they should not be annoyed by it."},{"use":"Add a backup, Set up account recovery","avoid":"Configure social recovery, Set up your recovery module","why":"Backup is the mental model people bring from photos and passwords. \"Module\" is implementation language."},{"use":"Sent, Submitting","avoid":"Submitted to bundler, Included in mempool","why":"Bundler and mempool are plumbing. The user cares that the action left their device and is on its way."},{"use":"Cancel recovery","avoid":"Veto, Abort","why":"\"Veto\" sounds adversarial. \"Abort\" sounds like a system error. The owner pressing cancel on their own recovery is a normal, calm action."}],"onMonad":[{"aspect":"Bundler Economics","ethereum":"Bundlers need to account for MEV, price fluctuations","monad":"Fast finality reduces bundler risk, potentially lower fees","designImplication":"Gas sponsorship more economically viable on Monad"},{"aspect":"UserOp Confirmation","ethereum":"UserOp → mempool → block (12+ seconds)","monad":"Sub-second finality for bundled operations","designImplication":"Can show confirmation instantly, no long pending states"},{"aspect":"Reserve Balance","ethereum":"Smart wallet can be drained to zero","monad":"10 MON reserve required; delegated accounts cannot use emptying exception","designImplication":"Show \"spendable\" balance that accounts for reserve"},{"aspect":"Recovery Time Lock","ethereum":"48h delay feels long but necessary","monad":"Could potentially reduce with faster block times","designImplication":"May offer shorter recovery periods"}],"keyTakeaways":["ERC-4337 is the infrastructure, not the UX. Hide the complexity.","Gas abstraction: let users pay in any token or have sponsor","Social recovery needs threshold (M-of-N) AND time delay","Always simulate UserOps before asking user to sign","Never show \"UserOperation\" or \"bundler\" to users"],"technicalNotes":"ERC-4337 uses a singleton EntryPoint contract that verifies and executes UserOperations. Smart wallets implement IAccount interface with validateUserOp(). Paymasters implement IPaymaster to sponsor gas. Bundlers are off-chain relayers that submit UserOps to EntryPoint. The system is permissionless: anyone can run a bundler."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-4337","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-4337","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-4337","markdown":"https://www.eipsfordesigners.com/standards/ERC-4337/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-4337/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-4337","official":"https://eips.ethereum.org/EIPS/eip-4337","discussion":"https://ethereum-magicians.org/search?q=ERC-4337"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"ERC-5792","name":"Wallet Call API","status":"Final","chain":"both","category":{"id":"transaction-friction","name":"Transaction Friction","description":"Reducing clicks, signatures, and mental overhead"},"journeyStages":[{"id":"executing","name":"Executing Transactions","description":"Performing on-chain actions"}],"uxImpact":"Apps can request multiple calls executed atomically — approve+swap+stake in one wallet popup instead of three. Design implications: design multi-action confirmation screens showing all operations, indicate atomicity guarantees ('all or nothing'), show capability badges for wallet features, build paymaster URL configuration. Design decisions: how to present batched operations (list vs grouped), handle partial wallet support gracefully, balance information density in confirmation dialogs — too little is risky, too much causes fatigue. Referenced across 4 pain points — Signing Fatigue (High), Missing Signing Context (Medium), Redundant Token Approvals (High), and Token Approval Management (High). Batching via wallet_sendCalls is High priority.","hasDetailedContent":true,"content":{"id":"ERC-5792","summary":"ERC-5792 is the \"Wallet Call API\" — a standard way for dApps to send batched operations to wallets and discover what capabilities the wallet supports. Instead of guessing if a wallet can batch transactions or sponsor gas, dApps can ask. And wallets can execute multiple calls atomically. It bridges EIP-7702 and ERC-4337 capabilities to a consistent API.","applicability":{"whenToUse":["Your product addresses: dApps can't know what wallet supports.","Your product addresses: no standard for batched calls.","Your UI should wallet_getCapabilities() returns supported features.","You are designing a capability detection experience with visible states and recovery paths."],"whenToAvoid":["Check capabilities, fall back gracefully.","Hide unsupported features from UI.","Clear: \"If any fails, none execute\".","The flow is a single low-risk transfer where batching adds confusion."]},"designerTakeaways":["You can wallet_getCapabilities() returns supported features in the interface.","You can wallet_sendCalls() works across all supporting wallets in the interface.","You can wallet_getCallsStatus() for bundled operation status in the interface."],"problemsSolved":[{"problem":"dApps can't know what wallet supports","oldWay":"Try features, catch errors, guess based on wallet name","newWay":"wallet_getCapabilities() returns supported features","impact":"high"},{"problem":"No standard for batched calls","oldWay":"Each smart wallet has different batch interface","newWay":"wallet_sendCalls() works across all supporting wallets","impact":"high"},{"problem":"Can't check call status after submission","oldWay":"Poll blockchain, hope for the best","newWay":"wallet_getCallsStatus() for bundled operation status","impact":"medium"}],"uxPatterns":[{"name":"Capability Detection","description":"Check wallet features before offering them","mockup":"concept/session-permissions","userFlow":["dApp connects to wallet","Calls wallet_getCapabilities","Parses supported features","Shows/hides UI based on capabilities","Only offers what wallet supports"]},{"name":"Batched Transaction","description":"Multiple operations in one request","mockup":"concept/bundled-defi","userFlow":["dApp builds array of calls","Uses wallet_sendCalls","Wallet shows combined preview","User approves once","All execute atomically"]}],"uiComponents":[{"name":"CapabilityChecker","description":"Queries and displays wallet capabilities","states":["checking","ready","no-support"],"props":["walletProvider","onCapabilities"]},{"name":"BatchCallBuilder","description":"UI for building batched operations","states":["building","ready","submitting"],"props":["calls[]","onSubmit"]},{"name":"CallStatusTracker","description":"Shows status of batched call","states":["pending","confirmed","failed"],"props":["callId","onStatusChange"]}],"antiPatterns":[{"pattern":"Assuming all wallets support batching","why":"EOAs without 7702 can't batch","instead":"Check capabilities, fall back gracefully","severity":"critical"},{"pattern":"Not explaining atomicity","why":"Users don't understand all-or-nothing","instead":"Clear: \"If any fails, none execute\"","severity":"medium"},{"pattern":"Ignoring capability responses","why":"Offering features wallet doesn't support","instead":"Hide unsupported features from UI","severity":"high"}],"onMonad":[{"aspect":"Batch Execution","ethereum":"Batch confirms in 12+ seconds","monad":"Sub-second batch confirmation","designImplication":"Complex operations feel instant"}],"keyTakeaways":["ERC-5792 = standard wallet capability API","Always check capabilities before offering features","Batch calls execute atomically","Fall back gracefully for non-supporting wallets","Track batch status with wallet_getCallsStatus"],"technicalNotes":"ERC-5792 adds three methods: wallet_getCapabilities() returns supported features per chain, wallet_sendCalls({ calls[], capabilities }) submits batched operations, wallet_getCallsStatus(id) tracks completion. Capabilities include atomicBatch, paymasterService, auxiliaryFunds. Compatible with both EIP-7702 and ERC-4337 wallets."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-5792","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-5792","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-5792","markdown":"https://www.eipsfordesigners.com/standards/ERC-5792/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-5792/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-5792","official":"https://eips.ethereum.org/EIPS/eip-5792","discussion":"https://ethereum-magicians.org/search?q=ERC-5792"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"ERC-2612","name":"Permit Extension for ERC-20","status":"Final","chain":"both","category":{"id":"transaction-friction","name":"Transaction Friction","description":"Reducing clicks, signatures, and mental overhead"},"journeyStages":[{"id":"approving","name":"Approving & Permissioning","description":"Granting permissions for actions"}],"uxImpact":"Token approvals via signature instead of transaction — users sign a message, relayer submits on-chain, no ETH needed for approval step. Design implications: replace 'Approve' transaction with signature request, show 'gasless approval' badge, display permit expiry/deadline clearly, warn about permit phishing (malicious sites requesting signatures). Design decisions: tradeoff between convenience (longer deadlines) and security (shorter expiry), must educate users that signatures can be dangerous, consider revoking stale permits in UI. Live for USDC, DAI, UNI, and aTokens but not universal. Addresses Redundant Token Approvals pain point (High severity) — separate approval is where most first-time DeFi users abandon.","hasDetailedContent":true,"content":{"id":"ERC-2612","summary":"ERC-2612 adds \"permit\" to ERC-20 tokens. Instead of approve() + action as two transactions, users sign a permit message off-chain, then execute both in one transaction. The dApp submits the permit signature with the action. Result: one less transaction, one less confirmation, better UX.","designerTakeaways":["You can hide the separate approve tx by bundling permit with swap or deposit.","You can show one Swap action while permit runs in the same transaction.","You can surface token, amount, spender, and deadline in the signature preview."],"applicability":{"whenToUse":["The token implements permit() and you want one-step swap or deposit flows.","Users hesitate at separate approve transactions.","You batch permit signature with the main action via relayer or router."],"whenToAvoid":["The token does not support ERC-2612 (fall back to classic approve).","Hardware wallet flows cannot sign typed data reliably.","Regulatory or policy requirements mandate on-chain approve visibility."]},"designDecisions":[{"question":"Do users see one action or two?","recommendation":"Present a single Swap (or Deposit) action; handle permit behind the scenes.","rationale":"Exposing permit as a separate step recreates the confusion ERC-2612 removes."},{"question":"What appears in the signature preview?","recommendation":"Show human-readable token, amount, spender, and deadline.","rationale":"Typed data must read like a transaction preview, not raw EIP-712 fields."},{"question":"What if permit is unsupported?","recommendation":"Fall back to classic approve with the same UI labels where possible.","rationale":"Graceful fallback avoids dead ends on older tokens."},{"question":"How do you handle expired permits?","recommendation":"Refresh deadline and ask for a new signature with clear expiry copy.","rationale":"Silent failures on stale permits look like app bugs."}],"statesToDesign":[{"state":"Permit signing","trigger":"Wallet prompts for EIP-712 permit signature.","userNeed":"Understand this authorizes the upcoming action only.","designResponse":"Match swap preview copy; mention deadline date."},{"state":"Permit rejected","trigger":"User rejects typed data signature.","userNeed":"Retry or use classic approve path.","designResponse":"Offer retry and \"Approve in wallet\" fallback."},{"state":"Executing with permit","trigger":"Relayer or router submits permit + action.","userNeed":"Single progress indicator.","designResponse":"One loading state; do not flash separate approve step."},{"state":"Deadline expired","trigger":"Permit past deadline on chain.","userNeed":"Know to sign again.","designResponse":"Explain expiry; regenerate permit with fresh deadline."},{"state":"Non-permit token","trigger":"Token lacks DOMAIN_SEPARATOR / permit.","userNeed":"Complete flow without dead end.","designResponse":"Auto-route to standard approve flow with same CTA label."}],"problemsSolved":[{"problem":"Two transactions for any token interaction","oldWay":"Approve → wait for confirm → swap → wait for confirm","newWay":"Sign permit → swap (approval included) → done","impact":"critical"},{"problem":"Users pay gas for approval transactions","oldWay":"Pay $5 gas just to approve, before the actual swap","newWay":"Permit is a signature (free), bundled with action","impact":"high"},{"problem":"Approval UX is confusing","oldWay":"Why do I need to \"approve\" before I can \"swap\"?","newWay":"Single action from user perspective","impact":"high"}],"uxPatterns":[{"name":"Sign + Execute Pattern","description":"Approve and action in single user flow","mockup":"concept/permit-approval","userFlow":["User enters swap details","Click \"Start Swap\"","Wallet shows permit signature request","User signs permit (free)","Wallet shows transaction confirmation","User confirms transaction","Swap executes with permit"]},{"name":"Permit vs Approve Comparison","description":"Educate users on the improvement","mockup":"concept/permit-approval","userFlow":["First-time user sees \"Sign Permit\"","Clicks \"Why?\" or info icon","Modal explains gas savings","User understands and continues"]}],"uiComponents":[{"name":"PermitSignButton","description":"Button that initiates permit signature","states":["idle","signing","signed","error"],"props":["token","amount","spender","deadline","onSign"]},{"name":"TwoStepFlow","description":"Indicator showing sign → execute progress","states":["not-started","signing","signed","executing","complete"],"props":["currentStep","steps[]"]},{"name":"GasSavingsDisplay","description":"Shows how much user saves with permit","states":["calculating","ready"],"props":["withoutPermit","withPermit","savings"]}],"antiPatterns":[{"pattern":"Not explaining why there's a signature step","why":"Users confused by \"Sign\" before \"Confirm\"","instead":"Clear UI: \"Sign permit (free) then confirm swap\"","severity":"high"},{"pattern":"Falling back to approve without notice","why":"User suddenly has extra transaction, pays more gas","instead":"Warn: \"This token doesn't support permit, using approval\"","severity":"medium"},{"pattern":"Permit with no deadline","why":"Permit valid forever, replay risk","instead":"Always set reasonable deadline (minutes, not days)","severity":"critical"},{"pattern":"Not supporting permit when available","why":"Users pay unnecessary approval gas","instead":"Check for permit support, use when available","severity":"medium"}],"onMonad":[{"aspect":"Gas Savings","ethereum":"Save ~$5-10 per avoided approval","monad":"Save less (gas already cheap) but still better UX","designImplication":"Emphasize UX improvement over cost savings"},{"aspect":"Confirmation Speed","ethereum":"Sign → wait → confirm → wait","monad":"Sign → confirm → instant done","designImplication":"Flow feels much snappier"}],"keyTakeaways":["ERC-2612 = approve via signature, not transaction","Reduces two transactions to one","Always set deadline on permits","Explain the sign step clearly to users","Check if token supports permit before using"],"technicalNotes":"ERC-2612 adds permit(owner, spender, value, deadline, v, r, s) function to ERC-20. Owner signs EIP-712 typed data with nonce. Anyone can submit the permit. nonces(owner) increments to prevent replay. DOMAIN_SEPARATOR binds to contract. Compatible tokens: USDC, DAI, most new tokens."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-2612","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-2612","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-2612","markdown":"https://www.eipsfordesigners.com/standards/ERC-2612/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-2612/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-2612","official":"https://eips.ethereum.org/EIPS/eip-2612","discussion":"https://ethereum-magicians.org/search?q=ERC-2612"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"ERC-1363","name":"Payable Token","status":"Final","chain":"both","category":{"id":"transaction-friction","name":"Transaction Friction","description":"Reducing clicks, signatures, and mental overhead"},"journeyStages":[{"id":"executing","name":"Executing Transactions","description":"Performing on-chain actions"},{"id":"gas","name":"Gas & Fees","description":"Paying for transactions"}],"uxImpact":"Tokens can trigger contract actions on receipt — transfer+action in one transaction instead of approve+transferFrom pattern. Design implications: show single-step payment flows ('Pay 100 USDC' vs 'Approve then Pay'), indicate when tokens support payable callbacks, simplify subscription/purchase UIs. Design decisions: less widely adopted than permit — decide whether to feature-detect and adapt UI, balance simplicity gains against explaining why some tokens have different flows. Directly addresses the Redundant Token Approvals pain point (High severity) — ERC-20's separate approve+call is where most first-time DeFi users abandon. ERC-1363 eliminates that two-step flow at the token standard level.","hasDetailedContent":true,"content":{"id":"ERC-1363","summary":"ERC-1363 creates \"payable tokens\" that trigger automatic callbacks when transferred. Send tokens and the receiving contract automatically executes code - enabling one-step payments where \"pay\" and \"deliver service\" happen atomically.","applicability":{"whenToUse":["Your product addresses: payment and service delivery require two steps.","Your product addresses: approve + transferFrom requires two transactions.","The flow should deliver: token transfer automatically triggers service callback.","You are designing a one-click purchase experience with visible states and recovery paths."],"whenToAvoid":["Use transferAndCall or approveAndCall for single-tx flow.","Ensure callbacks always succeed or revert entire transaction.","Check msg.sender is the token contract in onTransferReceived.","The flow is a single low-risk transfer where batching adds confusion."]},"designerTakeaways":["You can design UI that delivers token transfer automatically triggers service callback.","You can design UI that delivers transferAndCall sends tokens and triggers action in one transaction.","You can design UI that delivers receive callback with payment context."],"problemsSolved":[{"problem":"Payment and service delivery require two steps","oldWay":"User sends tokens, then separately triggers service (two transactions)","newWay":"Token transfer automatically triggers service callback","impact":"critical"},{"problem":"Approve + transferFrom requires two transactions","oldWay":"Approve contract to spend tokens, then call contract to pull tokens","newWay":"transferAndCall sends tokens and triggers action in one transaction","impact":"high"},{"problem":"Payment contracts need complex state tracking","oldWay":"Track who approved, pull payments on demand, handle edge cases","newWay":"Receive callback with payment context, process immediately","impact":"high"},{"problem":"Users can approve but never complete purchase","oldWay":"Approval sits unused, confusing for users and contracts","newWay":"Atomic transfer means payment = action, no orphaned approvals","impact":"medium"},{"problem":"Can't include payment context with transfer","oldWay":"Transfer tokens, then separately communicate what it's for","newWay":"Include data parameter with transfer for context","impact":"medium"}],"uxPatterns":[{"name":"One-Click Purchase","description":"Buy item with single token transfer","mockup":"concept/bundled-defi","userFlow":["User views item for sale","Clicks \"Buy Now\"","Wallet prompts to send 500 GAME","User confirms","Token transferred AND item received in one tx","Success: item appears in inventory"]},{"name":"Subscription Activation","description":"Pay subscription and activate in one step","mockup":"concept/tx-status","userFlow":["User selects subscription tier","Clicks \"Pay & Activate\"","Token transfer includes subscription data","Contract receives tokens + callback","Subscription activated immediately","User gains premium access instantly"]},{"name":"Crowdfund Contribution","description":"Contribute to crowdfund with automatic reward tracking","mockup":"concept/nft-gallery","userFlow":["User enters contribution amount","UI shows reward tier earned","User clicks Contribute","Tokens transferred with backer data","Contract mints backer NFT in callback","User receives NFT + contribution recorded"]},{"name":"Token-Gated Access","description":"Pay entry fee and gain access atomically","mockup":"concept/bundled-defi","userFlow":["User views community details","Clicks \"Pay & Get Access\"","Token transfer includes user address","Contract receives payment","Callback whitelists user address","User has immediate access"]}],"uiComponents":[{"name":"PayableTokenButton","description":"Single-click payment button using transferAndCall","states":["ready","confirming","processing","success","error"],"props":["amount","token","recipient","callData","onSuccess"]},{"name":"AtomicPurchaseCard","description":"Product card with one-click purchase","states":["available","purchasing","owned","sold-out"],"props":["item","price","tokenSymbol","onPurchase"]},{"name":"TransferWithDataForm","description":"Form for transfers with attached data","states":["editing","reviewing","sending","complete"],"props":["recipient","amount","dataFields[]","onSubmit"]},{"name":"CallbackStatusIndicator","description":"Shows if transfer callback succeeded","states":["pending","callback-executing","success","callback-failed"],"props":["transferHash","callbackResult","error"]},{"name":"InstantActivationBadge","description":"Indicates feature uses instant activation","states":["default","highlighted"],"props":["featureName","tooltip"]}],"antiPatterns":[{"pattern":"Still requiring approve + action for ERC-1363 tokens","why":"Defeats the purpose, users still need two transactions","instead":"Use transferAndCall or approveAndCall for single-tx flow","severity":"critical"},{"pattern":"Not handling callback failure gracefully","why":"Transfer succeeds but callback fails = confusing state","instead":"Ensure callbacks always succeed or revert entire transaction","severity":"critical"},{"pattern":"Not explaining the one-click benefit","why":"Users don't know they're getting better UX","instead":"Show \"✓ No approval needed\" or \"One transaction\"","severity":"medium"},{"pattern":"Using transferAndCall without validating caller","why":"Anyone can call your callback with arbitrary data","instead":"Check msg.sender is the token contract in onTransferReceived","severity":"critical"},{"pattern":"Complex callback logic that might fail","why":"Failed callback means lost funds or stuck state","instead":"Keep callbacks simple, validate inputs, handle edge cases","severity":"high"},{"pattern":"Not showing what callback will do","why":"Users don't understand what happens after transfer","instead":"Explain \"Pay and receive [item]\" or \"Pay and activate [service]\"","severity":"medium"}],"onMonad":[{"aspect":"Callback Execution","ethereum":"Callback in same tx means all-or-nothing, which can timeout","monad":"Fast execution means callbacks complete quickly","designImplication":"More complex callbacks are viable on Monad"},{"aspect":"Gas for Callbacks","ethereum":"Complex callbacks can hit gas limits","monad":"Higher throughput means less concern about callback gas","designImplication":"Can do more in onTransferReceived callback"},{"aspect":"Confirmation Speed","ethereum":"Pay-and-activate feels slow (12+ second blocks)","monad":"Sub-second finality makes instant activation feel truly instant","designImplication":"Emphasize \"instant\" activation in UI copy"},{"aspect":"Reserve Balance","ethereum":"Can spend entire balance on transfer","monad":"10 MON reserve for async execution safety; guaranteed balance floor for callbacks","designImplication":"Show \"spendable\" balance when using payable tokens"}],"keyTakeaways":["ERC-1363 = pay and execute in one transaction","Use for purchases, subscriptions, access control","Show users the one-click benefit (\"No approval needed\")","Validate token caller in callbacks for security","Keep callbacks simple to prevent failed transactions"],"technicalNotes":"ERC-1363 extends ERC-20 with transferAndCall, transferFromAndCall, approveAndCall. Receivers implement IERC1363Receiver with onTransferReceived(operator, from, value, data). Spenders implement IERC1363Spender with onApprovalReceived(owner, value, data). Must return magic bytes4 to confirm callback handled successfully."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-1363","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-1363","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-1363","markdown":"https://www.eipsfordesigners.com/standards/ERC-1363/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-1363/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-1363","official":"https://eips.ethereum.org/EIPS/eip-1363","discussion":"https://ethereum-magicians.org/search?q=ERC-1363"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"EIP-5453","name":"Endorsement (Generalized Permit)","status":"Last Call","chain":"both","category":{"id":"transaction-friction","name":"Transaction Friction","description":"Reducing clicks, signatures, and mental overhead"},"journeyStages":[{"id":"approving","name":"Approving & Permissioning","description":"Granting permissions for actions"}],"uxImpact":"Generalized permit system — any function can accept off-chain signatures for authorization, enabling multi-sig and threshold signing in one transaction. Design implications: design multi-party approval collection UI, show endorsement status ('2 of 3 signed'), enable off-chain voting/approval workflows. Design decisions: complex signature coordination UX — must make gathering multiple signatures intuitive, handle partial endorsement states, decide how to display endorser identities and validity windows.","hasDetailedContent":true,"content":{"id":"EIP-5453","summary":"EIP-5453 is \"permit for everything.\" While ERC-2612 brought gasless approvals to ERC-20, EIP-5453 generalizes this pattern to ANY smart contract function. Users sign a message endorsing an action, and anyone can submit it on-chain. This enables gasless interactions with any protocol—not just tokens. Sign to join a DAO, register a name, or update metadata, all without holding ETH.","applicability":{"whenToUse":["Your product addresses: gasless patterns only work for token approvals.","Your users need ETH for non-financial interactions.","The flow should deliver: standard endorsement pattern works for any contract function.","Fee screens need estimates, speed options, and plain-language breakdowns."],"whenToAvoid":["Parse and display contract address, function name, all parameters.","Default to reasonable expiry (1-24 hours), show clearly.","Clear nonce increment UI with explanation.","The flow is a single low-risk transfer where batching adds confusion."]},"designerTakeaways":["You can standard endorsement pattern works for any contract function.","You can design UI that delivers sign endorsement.","You can standard endorsement format all wallets can display clearly."],"problemsSolved":[{"problem":"Gasless patterns only work for token approvals","oldWay":"ERC-2612 permit for ERC-20, but custom solutions for everything else","newWay":"Standard endorsement pattern works for any contract function","impact":"critical"},{"problem":"Users need ETH for non-financial interactions","oldWay":"Joining a DAO, voting, updating profile—all need gas","newWay":"Sign endorsement, relayer submits, protocol or user covers gas later","impact":"critical"},{"problem":"Each protocol implements gasless differently","oldWay":"Custom meta-transaction formats per protocol","newWay":"Standard endorsement format all wallets can display clearly","impact":"high"},{"problem":"Batch operations require multiple signatures","oldWay":"Sign approve, sign stake, sign claim separately","newWay":"Single endorsement can cover multiple actions","impact":"high"},{"problem":"Endorsements lack expiration and replay protection","oldWay":"Ad-hoc nonce and deadline implementations","newWay":"Built-in nonce and validUntil fields in standard format","impact":"medium"}],"uxPatterns":[{"name":"Universal Gasless Action","description":"Any protocol interaction via signature","mockup":"concept/permit-approval","userFlow":["User clicks \"Join DAO\"","UI shows action details","Indicates this is gasless","Wallet shows endorsement to sign","Relayer submits on-chain","User is now a DAO member"]},{"name":"Endorsement Signature Display","description":"Clear wallet prompt showing what user is endorsing","mockup":"concept/permit-approval","userFlow":["Wallet receives endorsement request","Parses EIP-712 typed data","Shows human-readable action description","Displays contract, function, parameters","Shows expiry and nonce","User signs or rejects"]},{"name":"Batch Endorsement Flow","description":"Multiple actions in one signature","mockup":"concept/permit-approval","userFlow":["User starts onboarding flow","Multiple actions bundled together","Single endorsement signature requested","Relayer executes all actions atomically","All onboarding steps complete"]},{"name":"Endorsement Status Tracker","description":"Track pending and executed endorsements","mockup":"concept/permit-approval","userFlow":["User views endorsement history","Sees pending endorsements with expiry","Can cancel pending by incrementing nonce","Sees executed endorsements with timestamps","Links to transaction details"]}],"uiComponents":[{"name":"EndorsementPreview","description":"Human-readable view of what will be endorsed","states":["loading","parsed","error"],"props":["endorsementData","contract","function","params"]},{"name":"GaslessActionButton","description":"CTA that indicates action is signature-only","states":["ready","signing","submitted","confirmed","error"],"props":["label","onSign","isGasless"]},{"name":"RelayerStatus","description":"Shows relayer availability and estimated execution time","states":["available","busy","offline"],"props":["estimatedTime","relayerName"]},{"name":"NonceManager","description":"Display and control endorsement nonce","states":["current","incrementing","incremented"],"props":["nonce","pendingEndorsements","onIncrement"]}],"antiPatterns":[{"pattern":"Not showing the actual function being called","why":"Users signing blind endorsements is dangerous","instead":"Parse and display contract address, function name, all parameters","severity":"critical"},{"pattern":"Very long or no expiration on endorsements","why":"Stale endorsements can be replayed unexpectedly","instead":"Default to reasonable expiry (1-24 hours), show clearly","severity":"critical"},{"pattern":"No way to cancel pending endorsements","why":"Users trapped with outstanding authorizations","instead":"Clear nonce increment UI with explanation","severity":"high"},{"pattern":"Using endorsements when regular tx would be simpler","why":"Adds complexity and relayer dependency unnecessarily","instead":"Use endorsements for gasless/sponsored flows, not everything","severity":"medium"},{"pattern":"Hiding relayer details and execution timing","why":"Users confused when endorsed action doesn't happen immediately","instead":"Show relayer status and estimated execution time","severity":"medium"}],"onMonad":[{"aspect":"Relayer Economics","ethereum":"Relayers need significant gas buffer, high costs","monad":"Cheap gas makes relayer operation more viable","designImplication":"More apps can offer gasless via endorsements"},{"aspect":"Execution Speed","ethereum":"Endorsed action may take 15+ seconds after submission","monad":"Sub-second finality after relayer submits","designImplication":"Show \"confirming...\" briefly, then success"},{"aspect":"Nonce Updates","ethereum":"Canceling via nonce increment requires gas and time","monad":"Fast, cheap nonce updates for quick cancellation","designImplication":"Cancel button can feel instant"},{"aspect":"Batch Endorsements","ethereum":"Large batches may hit gas limits","monad":"Higher throughput allows bigger batches","designImplication":"Can bundle more actions in single endorsement"}],"keyTakeaways":["EIP-5453 = gasless signature pattern for ANY function","Always show what contract/function/params user is endorsing","Include reasonable expiry and clear nonce management","Great for onboarding flows where users lack ETH","On Monad: fast finality makes endorsed actions feel instant"],"technicalNotes":"EIP-5453 defines an \"Endorsement\" as an EIP-712 typed signature authorizing a specific contract call. The endorsement includes: contract address, function selector, encoded parameters, nonce (for replay protection), and validUntil (expiry timestamp). Contracts implementing this standard expose an endorsementNonce() function and accept endorsed calls via a standard interface."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-5453","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=EIP-5453","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/EIP-5453","markdown":"https://www.eipsfordesigners.com/standards/EIP-5453/content.md","agent":"https://www.eipsfordesigners.com/standards/EIP-5453/agent.md","api":"https://www.eipsfordesigners.com/api/standards/EIP-5453","official":"https://eips.ethereum.org/EIPS/eip-5453","discussion":"https://ethereum-magicians.org/search?q=EIP-5453"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"EIP-5008","name":"ERC-721 Nonce Extension","status":"Last Call","chain":"both","category":{"id":"transaction-friction","name":"Transaction Friction","description":"Reducing clicks, signatures, and mental overhead"},"journeyStages":[{"id":"approving","name":"Approving & Permissioning","description":"Granting permissions for actions"}],"uxImpact":"NFTs have nonces that change on transfer — prevents reactivation attacks where old marketplace listings become valid again. Design implications: show listing validity warnings ('This listing may be stale'), auto-cancel orders when nonce changes detected, indicate when an NFT was recently transferred. Design decisions: tradeoff between surfacing technical details (nonces) vs abstracting them, must decide how prominently to warn about potentially dangerous legacy listings on non-5008 NFTs.","hasDetailedContent":true,"content":{"id":"EIP-5008","summary":"EIP-5008 brings the permit pattern (gasless approvals) to NFTs. Instead of paying gas to approve an NFT transfer, users sign a message off-chain. The signature can be submitted by anyone—the marketplace, buyer, or a relayer. This enables gasless NFT listings, smoother auction flows, and better mobile experiences where users shouldn't need ETH just to list an item.","applicability":{"whenToUse":["Your product addresses: listing an NFT requires a gas-paying approval transaction.","Your users need ETH before they can sell their NFTs.","The flow should deliver: sign a message (free) → List immediately.","Fee screens need estimates, speed options, and plain-language breakdowns."],"whenToAvoid":["Clear language: \"This allows X to transfer your NFT when sold\".","Show expiration prominently: \"Valid until Feb 14, 2026\".","Permit dashboard showing all active approvals with cancel buttons.","The flow is a single low-risk transfer where batching adds confusion."]},"designerTakeaways":["You can design UI that delivers sign a message (free) → List immediately.","You can design UI that delivers sign permit.","You can design UI that delivers single signature, instant listing."],"problemsSolved":[{"problem":"Listing an NFT requires a gas-paying approval transaction","oldWay":"Connect wallet → Approve marketplace → Pay $5 gas → Wait → List","newWay":"Sign a message (free) → List immediately","impact":"critical"},{"problem":"Users need ETH before they can sell their NFTs","oldWay":"New user with NFT airdrop must buy ETH first to approve and sell","newWay":"Sign permit, marketplace submits it and deducts from sale proceeds","impact":"critical"},{"problem":"Mobile UX suffers from approval transactions","oldWay":"Multiple wallet popups, gas estimation, waiting for confirmation","newWay":"Single signature, instant listing","impact":"high"},{"problem":"Batch NFT operations require multiple approvals","oldWay":"Approve each NFT individually (or set approval-for-all)","newWay":"Sign multiple permits, submit all in one transaction","impact":"high"},{"problem":"Auction bidding flows are clunky with on-chain approvals","oldWay":"Approve before bidding, approval may expire or be front-run","newWay":"Sign permit with bid, only executed if you win","impact":"medium"}],"uxPatterns":[{"name":"Gasless NFT Listing","description":"List NFTs for sale without paying gas for approval","mockup":"concept/nft-gallery","userFlow":["User selects NFT to list","Enters price and duration","Clicks \"Sign to List\"","Wallet shows signature request (not transaction)","Signature stored off-chain","Listing appears immediately"]},{"name":"Permit Signature Request","description":"Clear wallet prompt explaining the gasless approval","mockup":"concept/permit-approval","userFlow":["Wallet receives permit signature request","Shows human-readable permit details","Explains what permission is being granted","User signs or cancels","Signature returned to dApp"]},{"name":"Bulk Listing Flow","description":"List multiple NFTs with a single signature","mockup":"concept/nft-gallery","userFlow":["User selects multiple NFTs","Sets individual prices","Single signature request shown","All permits generated from one signature","All listings go live simultaneously"]},{"name":"Cancel Listing UI","description":"Revoke permit by incrementing nonce","mockup":"concept/permit-approval","userFlow":["User views active listings","Clicks cancel on listing","Chooses free (wait) or fast (on-chain)","Fast option increments nonce, invalidating permit","Listing removed immediately"]}],"uiComponents":[{"name":"GaslessListingBadge","description":"Indicates listing/approval is free via permit","states":["available","not-supported","pending-signature"],"props":["supported","onLearnMore"]},{"name":"PermitSignatureModal","description":"Explains what the permit signature authorizes","states":["loading","ready","signing","error"],"props":["tokenId","spender","deadline","onSign","onCancel"]},{"name":"NonceDisplay","description":"Shows current nonce and explains invalidation","states":["current","incrementing","incremented"],"props":["nonce","pendingPermits"]},{"name":"BulkPermitManager","description":"Handle multiple permits in one UX flow","states":["selecting","configuring","signing","complete"],"props":["tokens[]","onBulkSign","maxBatch"]}],"antiPatterns":[{"pattern":"Not explaining what permit signatures authorize","why":"Users may not understand they're pre-authorizing a transfer","instead":"Clear language: \"This allows X to transfer your NFT when sold\"","severity":"critical"},{"pattern":"Hiding the deadline/expiration of permits","why":"Users don't know how long their approval is valid","instead":"Show expiration prominently: \"Valid until Feb 14, 2026\"","severity":"high"},{"pattern":"No way to see or cancel pending permits","why":"Users lose track of what they've authorized","instead":"Permit dashboard showing all active approvals with cancel buttons","severity":"high"},{"pattern":"Requesting permits with very long deadlines","why":"Security risk if signature is leaked or user forgets","instead":"Default to reasonable durations (7-30 days), let users extend","severity":"medium"},{"pattern":"Falling back to setApprovalForAll silently","why":"User expected gasless but gets broad approval transaction","instead":"Clearly indicate if permit isn't supported and why","severity":"medium"}],"onMonad":[{"aspect":"Gas Savings Impact","ethereum":"Permits save ~$5-15 per approval on Ethereum","monad":"Transactions already cheap, savings less dramatic","designImplication":"Emphasize convenience (no transaction) over cost savings"},{"aspect":"Signature Speed","ethereum":"After signing, must wait for on-chain confirmation when used","monad":"Sub-second finality when permit is executed","designImplication":"Can show real-time sale completion after buyer uses permit"},{"aspect":"Nonce Management","ethereum":"On-chain nonce increment can take 15+ seconds","monad":"Fast nonce updates for quick permit cancellation","designImplication":"Cancel actions feel instant, UI updates immediately"},{"aspect":"Reserve Balance","ethereum":"Permit execution may use all available funds","monad":"10 MON reserve for async execution safety","designImplication":"No risk of being stranded after permit-based sale; show spendable vs total"}],"keyTakeaways":["EIP-5008 = gasless NFT approvals via signatures","Always show what the permit authorizes (token, spender, deadline)","Provide clear cancellation UI with nonce explanation","Great for mobile where gas transactions are painful","On Monad: emphasize convenience over cost savings"],"technicalNotes":"EIP-5008 adds a nonces() function and permit() function to ERC-721. The permit creates a signature authorizing a spender for a specific tokenId. Nonce prevents replay attacks—incrementing nonce invalidates all pending permits. Signatures use EIP-712 typed data for human-readable wallet prompts."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-5008","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=EIP-5008","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/EIP-5008","markdown":"https://www.eipsfordesigners.com/standards/EIP-5008/content.md","agent":"https://www.eipsfordesigners.com/standards/EIP-5008/agent.md","api":"https://www.eipsfordesigners.com/api/standards/EIP-5008","official":"https://eips.ethereum.org/EIPS/eip-5008","discussion":"https://ethereum-magicians.org/search?q=EIP-5008"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"EIP-5216","name":"ERC-1155 Allowance Extension","status":"Last Call","chain":"both","category":{"id":"transaction-friction","name":"Transaction Friction","description":"Reducing clicks, signatures, and mental overhead"},"journeyStages":[{"id":"approving","name":"Approving & Permissioning","description":"Granting permissions for actions"}],"uxImpact":"ERC-1155 tokens get granular approvals by ID and amount — no more 'approve all' for semi-fungible tokens. Design implications: design per-token-ID approval selectors, show approved quantities remaining, enable approval management dashboards for 1155 holdings. Design decisions: more control means more UI complexity — decide granularity of approval controls (per-ID, per-amount, or simplified presets), balance security benefits against approval fatigue for users with many token types.","hasDetailedContent":true,"content":{"id":"EIP-5216","summary":"EIP-5216 brings granular allowances to ERC-1155 multi-tokens. Instead of \"approve all or nothing,\" users can approve specific amounts per token ID. Want to let a game use 5 of your health potions but not your legendary sword? Now you can. This prevents the dangerous \"setApprovalForAll\" pattern and gives users fine-grained control over their multi-token collections.","applicability":{"whenToUse":["Your product addresses: eRC-1155 only offers all-or-nothing approval.","Your product addresses: no way to limit how many tokens can be spent.","The flow should deliver: approve exactly 10 health potions, nothing else.","You are designing a granular approval selector experience with visible states and recovery paths."],"whenToAvoid":["Default to exact amount needed, let user increase if wanted.","Always use granular allowances if EIP-5216 is supported.","Show \"8/10 potions remaining\" after 2 are used.","The flow is a single low-risk transfer where batching adds confusion."]},"designerTakeaways":["You can design UI that delivers approve exactly 10 health potions, nothing else.","You can design UI that delivers set allowance to specific amount (e.g., max 50 tokens).","You can design UI that delivers approve only the tokens you intend to trade."],"problemsSolved":[{"problem":"ERC-1155 only offers all-or-nothing approval","oldWay":"setApprovalForAll gives access to EVERY token in the collection","newWay":"Approve exactly 10 health potions, nothing else","impact":"critical"},{"problem":"No way to limit how many tokens can be spent","oldWay":"Operator can transfer unlimited quantity once approved","newWay":"Set allowance to specific amount (e.g., max 50 tokens)","impact":"critical"},{"problem":"Users must trust platforms with entire collection","oldWay":"Marketplace approval = access to all game items","newWay":"Approve only the tokens you intend to trade","impact":"high"},{"problem":"Revoking requires removing all access","oldWay":"Can only toggle full collection access on/off","newWay":"Reduce allowance for specific token IDs independently","impact":"medium"},{"problem":"No transparency on what's actually approved","oldWay":"\"This site has access to your collection\" - but which tokens?","newWay":"Clear list: \"5 potions, 2 scrolls approved\"","impact":"medium"}],"uxPatterns":[{"name":"Granular Approval Selector","description":"Let users choose exactly how many of each token to approve","mockup":"concept/permit-approval","userFlow":["dApp requests token approval","UI shows all tokens user owns","User sets specific amounts per token","Summary shows total approved","Single transaction sets all allowances"]},{"name":"Approval Dashboard","description":"View and manage all active allowances","mockup":"concept/permit-approval","userFlow":["User opens approval dashboard","Sees all operators with allowances","Expands to see per-token breakdown","Can edit amounts or revoke per operator","Changes reflected immediately"]},{"name":"Trade Flow with Exact Approval","description":"Approve only what's needed for this trade","mockup":"concept/permit-approval","userFlow":["User selects items to sell","UI calculates exact approvals needed","Shows clear list of what will be approved","Single click approves exact amounts","Listing created with precise allowances"]},{"name":"Allowance Increase Request","description":"Handle when more allowance is needed mid-action","mockup":"concept/permit-approval","userFlow":["User attempts action requiring more allowance","UI shows current vs required","Offers sensible preset amounts","User picks or enters custom amount","Allowance increased, action proceeds"]}],"uiComponents":[{"name":"TokenAllowanceInput","description":"Input for setting allowance per token ID","states":["empty","valid","exceeds-balance","max"],"props":["tokenId","balance","currentAllowance","onChange"]},{"name":"AllowanceProgressBar","description":"Shows used vs remaining allowance","states":["full","partial","depleted"],"props":["used","total","tokenSymbol"]},{"name":"BatchAllowanceEditor","description":"Edit multiple token allowances at once","states":["viewing","editing","saving","saved"],"props":["operator","allowances[]","onSave","onCancel"]},{"name":"ApprovalComparisonCard","description":"Compare old (all-or-nothing) vs new (granular) approach","states":["showing-old","showing-new","comparing"],"props":["collection","requestedTokens"]}],"antiPatterns":[{"pattern":"Defaulting to max allowance for convenience","why":"Defeats the security purpose of granular allowances","instead":"Default to exact amount needed, let user increase if wanted","severity":"critical"},{"pattern":"Falling back to setApprovalForAll when available","why":"Users expect granular control when they see the UI","instead":"Always use granular allowances if EIP-5216 is supported","severity":"critical"},{"pattern":"Not showing remaining allowance after partial use","why":"Users don't know how much the operator can still spend","instead":"Show \"8/10 potions remaining\" after 2 are used","severity":"high"},{"pattern":"Bundling all tokens into one approval prompt","why":"Users can't see or control individual token allowances","instead":"Itemized list with per-token amount controls","severity":"high"},{"pattern":"No indication when contract doesn't support 5216","why":"User may think they have granular control when they don't","instead":"Clear warning: \"This collection only supports all-or-nothing approval\"","severity":"medium"}],"onMonad":[{"aspect":"Batch Allowance Updates","ethereum":"Multiple allowance updates may require separate transactions","monad":"Fast finality makes multi-tx flows feel instant","designImplication":"Can offer \"edit all allowances\" without long waits"},{"aspect":"Gas for Granular Approvals","ethereum":"Each token ID approval costs gas, can add up","monad":"Lower gas costs make per-token approvals practical","designImplication":"Don't pressure users toward batch approval for gas savings"},{"aspect":"Real-time Allowance Tracking","ethereum":"May lag in showing updated allowances","monad":"Sub-second updates to allowance state","designImplication":"Dashboard can show live allowance changes"},{"aspect":"Reserve Balance","ethereum":"Setting many allowances might deplete gas funds","monad":"10 MON reserve for async execution safety","designImplication":"Users won't get stuck mid-approval flow; show spendable vs total"}],"keyTakeaways":["EIP-5216 = ERC-20 style allowances for ERC-1155","Default to exact amounts needed, not max","Show remaining allowance after partial use","Clearly indicate when collection doesn't support granular approvals","On Monad: leverage fast finality for responsive allowance management"],"technicalNotes":"EIP-5216 adds allowance(owner, operator, tokenId) and approve(operator, tokenId, amount) functions to ERC-1155. Unlike setApprovalForAll, this allows per-token-ID approval with specific amounts. The allowance decreases as tokens are transferred via transferFrom. Operators must be approved for each token ID they want to transfer."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-5216","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=EIP-5216","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/EIP-5216","markdown":"https://www.eipsfordesigners.com/standards/EIP-5216/content.md","agent":"https://www.eipsfordesigners.com/standards/EIP-5216/agent.md","api":"https://www.eipsfordesigners.com/api/standards/EIP-5216","official":"https://eips.ethereum.org/EIPS/eip-5216","discussion":"https://ethereum-magicians.org/search?q=EIP-5216"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"ERC-777","name":"Token Standard","status":"Final","chain":"both","category":{"id":"transaction-friction","name":"Transaction Friction","description":"Reducing clicks, signatures, and mental overhead"},"journeyStages":[{"id":"executing","name":"Executing Transactions","description":"Performing on-chain actions"}],"uxImpact":"Tokens with hooks notify contracts on send/receive — enables single-transaction deposits but introduces reentrancy risks that have caused major exploits. Design implications: show security warnings for 777 tokens, indicate operator permissions clearly, warn when interacting with contracts that may be vulnerable to 777 reentrancy. Design decisions: largely superseded standard — decide whether to support at all, if supporting must prominently warn users about elevated risk, consider blocking 777 interactions in high-security contexts.","supersededBy":"ERC-1363","hasDetailedContent":true,"content":{"id":"ERC-777","summary":"ERC-777 is an advanced token standard with built-in hooks for sending and receiving. Contracts can automatically react when tokens arrive (no separate notification needed) and users can authorize \"operators\" to manage tokens on their behalf. While powerful, it's largely been superseded by account abstraction (ERC-4337) which achieves similar goals more safely. Understanding ERC-777 matters for legacy integrations and learning hook patterns.","applicability":{"whenToUse":["Your product addresses: contracts can't react to incoming token transfers.","Your users must approve each contract individually.","The flow should deliver: send tokens → Contract's receive hook triggers automatically.","You are designing a automatic deposit on transfer experience with visible states and recovery paths."],"whenToAvoid":["Clear warning: \"This contract can send ALL your tokens\".","Preview hook effects before confirming transfer.","Use ERC-777 features only when hooks genuinely needed.","The flow is a single low-risk transfer where batching adds confusion."]},"designerTakeaways":["You can design UI that delivers send tokens → Contract's receive hook triggers automatically.","You can design UI that delivers authorize an operator once to manage all your tokens.","You can design UI that delivers tokensReceived hook can reject unwanted transfers."],"problemsSolved":[{"problem":"Contracts can't react to incoming token transfers","oldWay":"Approve → Call contract → Contract pulls tokens (3 steps)","newWay":"Send tokens → Contract's receive hook triggers automatically","impact":"high"},{"problem":"Users must approve each contract individually","oldWay":"Approve Uniswap, approve Aave, approve each dApp","newWay":"Authorize an operator once to manage all your tokens","impact":"high"},{"problem":"No way to reject incoming unwanted tokens","oldWay":"Anyone can send you tokens, no way to refuse","newWay":"tokensReceived hook can reject unwanted transfers","impact":"medium"},{"problem":"Token transfers don't carry context","oldWay":"Transfer is just amount, no additional data","newWay":"data and operatorData fields carry context","impact":"medium"},{"problem":"No standard way for users to be notified of sends","oldWay":"Send completes without user-side hook","newWay":"tokensToSend hook runs before tokens leave","impact":"medium"}],"uxPatterns":[{"name":"Automatic Deposit on Transfer","description":"Send tokens to contract, action happens automatically","mockup":"generic/token-approval","userFlow":["User enters stake amount","UI explains auto-deposit feature","Single transaction initiated","Pool's receive hook processes deposit","User is staking without approve step"]},{"name":"Operator Authorization","description":"Grant third party permission to manage tokens","mockup":"concept/agent-task","userFlow":["User views operator dashboard","Sees all authorized operators","Each shows permissions granted","Can revoke any operator","Add new operators with authorization tx"]},{"name":"Receive Hook Notification","description":"Show when receive hooks will trigger","mockup":"generic/token-transfer","userFlow":["Incoming transfer detected","UI shows registered hooks","Explains what each hook will do","Shows final state after hooks","User accepts or could reject"]},{"name":"Send Hook Configuration","description":"Configure pre-send hooks for outgoing transfers","mockup":"generic/token-approval","userFlow":["User opens hook configuration","Sees available send hooks","Toggles hooks on/off","Configures hook parameters","Hooks run on future sends"]}],"uiComponents":[{"name":"OperatorManager","description":"Manage operator authorizations","states":["loading","empty","has-operators","adding"],"props":["operators[]","onAuthorize","onRevoke"]},{"name":"HookPreview","description":"Show what hooks will execute","states":["no-hooks","has-hooks","simulating"],"props":["hooks[]","transfer","outcome"]},{"name":"TransferWithHooks","description":"Transfer UI showing hook involvement","states":["preparing","hooks-running","complete","hook-rejected"],"props":["amount","recipient","activeHooks"]},{"name":"HookRegistry","description":"Register and manage send/receive hooks","states":["viewing","adding","removing","configuring"],"props":["sendHooks[]","receiveHooks[]","onUpdate"]}],"antiPatterns":[{"pattern":"Not warning about operator permissions","why":"Operators have significant power, users may not understand","instead":"Clear warning: \"This contract can send ALL your tokens\"","severity":"critical"},{"pattern":"Hiding hook effects on transfers","why":"Users surprised when hooks change expected outcome","instead":"Preview hook effects before confirming transfer","severity":"high"},{"pattern":"Using ERC-777 where ERC-20 suffices","why":"Added complexity and reentrancy risks without benefit","instead":"Use ERC-777 features only when hooks genuinely needed","severity":"high"},{"pattern":"No dashboard for hook/operator management","why":"Users forget what they've authorized","instead":"Clear management UI showing all hooks and operators","severity":"medium"},{"pattern":"Not mentioning ERC-4337 as modern alternative","why":"ERC-777 has known issues, better patterns exist","instead":"Consider account abstraction for new projects","severity":"medium"}],"onMonad":[{"aspect":"Hook Execution","ethereum":"Hooks add gas cost, reentrancy concerns","monad":"Cheaper execution, but still need reentrancy guards","designImplication":"Can afford more complex hooks, maintain security"},{"aspect":"Operator Updates","ethereum":"Authorizing/revoking operators takes time","monad":"Sub-second operator management","designImplication":"Operator changes feel instant"},{"aspect":"Transfer with Hooks","ethereum":"Complex hook chains may be slow and expensive","monad":"Fast parallel execution helps multi-hook transfers","designImplication":"Can enable more sophisticated hook chains"},{"aspect":"Reserve Balance","ethereum":"Hook failures may leave tx in bad state","monad":"10 MON reserve for async execution safety; hooks execute with guaranteed balance floor","designImplication":"Safer hook execution with guaranteed resources"}],"keyTakeaways":["ERC-777 = tokens with send/receive hooks and operators","Always warn about operator power and hook effects","Preview hook outcomes before transfers","Consider ERC-4337 for new projects (safer patterns)","On Monad: faster hook execution, maintain security practices"],"technicalNotes":"ERC-777 uses hooks (tokensToSend, tokensReceived) registered via ERC-1820 registry. Operators are addresses authorized to send tokens on behalf of holders. The standard is backwards-compatible with ERC-20 but has known reentrancy risks (hooks execute during transfer). Most new projects prefer ERC-4337 account abstraction for similar functionality with better security patterns."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-777","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-777","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-777","markdown":"https://www.eipsfordesigners.com/standards/ERC-777/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-777/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-777","official":"https://eips.ethereum.org/EIPS/eip-777","discussion":"https://ethereum-magicians.org/search?q=ERC-777"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"ERC-223","name":"Token with Transaction Handling","status":"Final","chain":"both","category":{"id":"transaction-friction","name":"Transaction Friction","description":"Reducing clicks, signatures, and mental overhead"},"journeyStages":[{"id":"executing","name":"Executing Transactions","description":"Performing on-chain actions"}],"uxImpact":"Tokens notify receiving contracts and revert if handler missing — prevents tokens being permanently lost to incompatible contracts. Design implications: show 'safe transfer' indicators, remove 'tokens may be lost' warnings for 223 tokens, simplify deposit flows since callback handles everything. Design decisions: low adoption limits usefulness — must handle mixed token standards gracefully, decide whether to surface the safety difference to users or abstract it away, consider that 223 transfers to EOAs work normally. Addresses Sending to Wrong Address pain point (Critical severity) — users sending tokens to contracts that can't handle them is a permanent-loss scenario. ERC-223 addresses the contract-send case specifically (tokens bounce back), complementing ENS/address-book solutions which address the human-error case.","hasDetailedContent":true,"content":{"id":"ERC-223","summary":"ERC-223 prevents tokens from being permanently lost by adding a safety mechanism: contracts must explicitly accept tokens or the transfer reverts. Unlike ERC-20 where sending tokens to a contract that doesn't handle them means they're gone forever, ERC-223 tokens bounce back if the recipient can't process them. It also combines approve+transferFrom into a single transfer with data, reducing steps.","applicability":{"whenToUse":["Your product addresses: tokens sent to wrong contracts are lost forever.","Your product addresses: transfer to contracts requires approve + transferFrom.","The flow should deliver: transfer reverts if contract doesn't implement receiver.","You are designing a safe transfer with callback experience with visible states and recovery paths."],"whenToAvoid":["Clear message: \"Contract can't receive these tokens, yours are safe\".","Highlight \"One-step deposit\" when interacting with contracts.","Badge indicating \"Protected transfer\" for ERC-223.","The flow is a single low-risk transfer where batching adds confusion."]},"designerTakeaways":["You can design UI that delivers transfer reverts if contract doesn't implement receiver.","You can design UI that delivers single transfer() with data parameter triggers action.","You can design UI that delivers tokenReceived() callback lets contract process immediately."],"problemsSolved":[{"problem":"Tokens sent to wrong contracts are lost forever","oldWay":"Send ERC-20 to contract without handler = permanent loss","newWay":"Transfer reverts if contract doesn't implement receiver","impact":"critical"},{"problem":"Transfer to contracts requires approve + transferFrom","oldWay":"Two transactions: approve contract, then call contract","newWay":"Single transfer() with data parameter triggers action","impact":"high"},{"problem":"No way for contracts to react to incoming tokens","oldWay":"Contract has no idea tokens arrived, must be notified separately","newWay":"tokenReceived() callback lets contract process immediately","impact":"high"},{"problem":"Users accidentally send tokens to token contract itself","oldWay":"Common mistake: send USDC to USDC contract address = lost","newWay":"Token contract can reject or return accidental sends","impact":"medium"},{"problem":"Deposit flows are fragmented across transactions","oldWay":"Approve → Deposit → Contract pulls tokens (3 interactions)","newWay":"Transfer to contract triggers deposit in one action","impact":"medium"}],"uxPatterns":[{"name":"Safe Transfer with Callback","description":"One-step deposit that triggers action","mockup":"generic/token-approval","userFlow":["User enters deposit amount","UI shows this is a one-step process","User clicks deposit","Transfer with data triggers vault deposit","Vault credits user automatically"]},{"name":"Protected Address Warning","description":"Prevent sending to incompatible addresses","mockup":"generic/token-transfer","userFlow":["User enters contract address","UI detects it's a contract (not EOA)","Shows warning but explains safety","ERC-223 protection reassures user","Transaction reverts if incompatible"]},{"name":"Transfer Revert Explanation","description":"When transfer fails due to incompatible recipient","mockup":"concept/tx-status","userFlow":["Transfer to incompatible contract","Transaction reverts (tokens safe)","UI explains what happened positively","Shows balance unchanged","Suggests alternatives"]},{"name":"Token Transfer with Payload","description":"Attach data to trigger specific actions","mockup":"concept/nft-gallery","userFlow":["User clicks buy on NFT","UI shows payment will include data","Explains atomic nature","Transfer triggers NFT delivery","Both happen in one transaction"]}],"uiComponents":[{"name":"ContractCompatibilityCheck","description":"Verify if recipient handles ERC-223","states":["checking","compatible","incompatible","unknown"],"props":["address","tokenAddress","onResult"]},{"name":"TransferWithData","description":"Transfer input with optional data payload","states":["simple","with-data","encoding","ready"],"props":["amount","recipient","data","onTransfer"]},{"name":"SafetyIndicator","description":"Badge showing ERC-223 protection status","states":["protected","unprotected","unknown"],"props":["tokenStandard","recipient"]},{"name":"RevertExplainer","description":"Friendly explanation when transfer reverts","states":["displaying","dismissed"],"props":["reason","tokenName","alternatives"]}],"antiPatterns":[{"pattern":"Not explaining why transfers can fail","why":"Users confused when transaction reverts","instead":"Clear message: \"Contract can't receive these tokens, yours are safe\"","severity":"high"},{"pattern":"Hiding the callback/data functionality","why":"Users miss the one-transaction benefit","instead":"Highlight \"One-step deposit\" when interacting with contracts","severity":"high"},{"pattern":"Showing ERC-223 transfers same as ERC-20","why":"Users don't understand the safety difference","instead":"Badge indicating \"Protected transfer\" for ERC-223","severity":"medium"},{"pattern":"Not pre-checking contract compatibility","why":"Users waste gas on doomed transfers","instead":"Simulate transfer, warn if it would revert","severity":"medium"},{"pattern":"Complex data encoding exposed to users","why":"Technical details confuse users","instead":"UI constructs data payload, shows human-readable summary","severity":"medium"}],"onMonad":[{"aspect":"Callback Execution","ethereum":"tokenReceived callback may be gas-heavy","monad":"Cheap gas makes callbacks practical for complex logic","designImplication":"Can offer richer callback-triggered actions"},{"aspect":"Revert Speed","ethereum":"Failed transfer still takes time to confirm failure","monad":"Sub-second feedback on incompatible transfers","designImplication":"Instant \"tokens safe\" confirmation on revert"},{"aspect":"Simulation","ethereum":"Pre-checking compatibility requires RPC calls","monad":"Fast simulation for compatibility checking","designImplication":"Real-time compatibility indicator as user types address"},{"aspect":"Atomic Operations","ethereum":"Transfer+action atomic but slow confirmation","monad":"Atomic operations with instant finality","designImplication":"Buy NFT flow completes visibly in under 1 second"}],"keyTakeaways":["ERC-223 = tokens that can't be lost to incompatible contracts","Always explain the safety benefit vs ERC-20","Use positive messaging when transfers revert (\"tokens safe!\")","Highlight one-step contract interactions","On Monad: instant feedback on both successful and failed transfers"],"technicalNotes":"ERC-223 adds a transfer(address, uint256, bytes) function that calls tokenReceived(address, uint256, bytes) on the recipient if it's a contract. If the recipient doesn't implement this interface, the transfer reverts. This prevents tokens from being stuck in contracts that don't handle them. The data parameter allows passing arbitrary info to trigger actions."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-223","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-223","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-223","markdown":"https://www.eipsfordesigners.com/standards/ERC-223/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-223/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-223","official":"https://eips.ethereum.org/EIPS/eip-223","discussion":"https://ethereum-magicians.org/search?q=ERC-223"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"ERC-7677","name":"Paymaster Gas Sponsorship","status":"Draft","chain":"both","category":{"id":"transaction-friction","name":"Transaction Friction","description":"Reducing clicks, signatures, and mental overhead"},"journeyStages":[{"id":"executing","name":"Executing Transactions","description":"Performing on-chain actions"},{"id":"gas","name":"Gas & Fees","description":"Paying for transactions"}],"uxImpact":"Defines the standard interface for paymasters that let dApps cover gas fees — users experience 'no gas needed' onboarding. Design implications: detect empty wallets and offer gas sponsorship automatically, show clear indication when a transaction is sponsored vs user-paid, design paymaster selection if multiple are available, handle paymaster failures gracefully with fallback to user-paid. Design decisions: whether to show the sponsorship source (dApp, protocol), how to communicate the gas sponsorship model to users, fallback UX when paymaster rejects a transaction. Critical priority for gas UX — 'Detect empty wallets, offer gas sponsorship — new users transact immediately.' Modern replacement for ERC-2771 meta-transaction patterns.","hasDetailedContent":true,"content":{"id":"ERC-7677","sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-7677","type":"official-spec"}],"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25","summary":"Defines the standard interface for paymasters that let dApps cover gas fees — users experience 'no gas needed' onboarding.","designerTakeaways":["You can detect zero-balance wallets and offer sponsored gas automatically.","Your fee row can clearly distinguish sponsored vs user-paid transactions.","You can design fallback paths when paymaster quotes fail."],"applicability":{"whenToUse":["Onboarding users who lack native token for gas.","You operate ERC-4337 smart accounts with paymaster support.","Gas sponsorship is a core growth lever for your product."],"whenToAvoid":["Users always hold enough native token and prefer self-pay.","No paymaster infrastructure exists on your target chain.","Regulatory constraints forbid third-party fee payment."]},"prototypeFirst":[{"screen":"Primary happy path","why":"Prove the core user promise before edge cases.","covers":["Success state","Clear outcome copy"],"include":["Primary CTA","Confirmation feedback","Next step"]},{"screen":"Blocked or unsupported state","why":"Users discover limits when wallets or chains lack support.","covers":["Unsupported wallet","Wrong network"],"include":["Plain-language reason","Fallback action"]},{"screen":"Failure recovery","why":"Trust breaks when errors look like bugs.","covers":["User rejection","Transaction revert"],"include":["Retry path","Support context"]},{"screen":"Advanced disclosure","why":"Power users need technical detail without cluttering the default path.","covers":["Contract address","Token ID","Raw status"],"include":["Expandable section","Copy buttons","Explorer link"]}],"mentalModel":[{"label":"User operation","description":"The smart account builds an action the user wants. Gas cost would normally require native token in the wallet."},{"label":"Paymaster quote","description":"A paymaster contract quotes whether it will sponsor the fee or accept payment in another token."},{"label":"Sponsorship decision","description":"Your fee row shows Sponsored, pay-with-token, or user-paid gas. Each path needs distinct copy and fallback."},{"label":"EntryPoint validation","description":"The bundler submits the op only if account and paymaster rules pass. Quote failures belong in product UI before sign."},{"label":"User-visible outcome","description":"Success should confirm who paid and whether sponsorship continues on the next action."}],"statesToDesign":[{"state":"Ready","trigger":"Prerequisites met.","userNeed":"Understand what happens next.","designResponse":"Enable primary action with plain-language preview."},{"state":"Awaiting signature","trigger":"Wallet prompt open.","userNeed":"Know what they are approving.","designResponse":"Mirror human-readable summary in app and wallet."},{"state":"Pending","trigger":"Transaction submitted.","userNeed":"Confidence it is progressing.","designResponse":"Show status strip with explorer link."},{"state":"Succeeded","trigger":"On-chain confirmation.","userNeed":"See updated ownership or balance.","designResponse":"Celebrate outcome and show new state clearly."},{"state":"Failed or reverted","trigger":"Validation or execution failed.","userNeed":"Fix or retry without guessing.","designResponse":"Name the failed constraint and offer a concrete next step."}],"designDecisions":[{"question":"How much protocol detail do users see?","recommendation":"Lead with outcomes; tuck identifiers behind review.","rationale":"Users decide on consequences, not function selectors."},{"question":"What happens when support is missing?","recommendation":"Block with explanation and fallback path.","rationale":"Silent failure feels like a broken product."},{"question":"How do you label restricted assets?","recommendation":"Use persistent badges for non-transferable, locked, or expiring states.","rationale":"Hidden restrictions cause rage-quits at transfer time."}],"problemsSolved":[{"problem":"Inconsistent behavior across apps","oldWay":"Each team reinvents copy and edge cases","newWay":"Shared standard gives predictable UX patterns","impact":"high"},{"problem":"Users surprised by on-chain rules","oldWay":"Generic transfer UI fails at submit time","newWay":"Standard-aware UI sets expectations upfront","impact":"high"},{"problem":"Support burden from opaque errors","oldWay":"Raw revert reasons in toasts","newWay":"Mapped states explain what to do next","impact":"medium"}],"uxPatterns":[{"name":"Sponsored Fee Row","description":"Clear label when gas is covered by the app.","mockup":"erc-4337/gas-abstraction","components":["FeeRow","SponsoredBadge"],"userFlow":["User initiates action","Paymaster quotes","UI shows Sponsored","User confirms without gas token"]},{"name":"Paymaster Fallback","description":"Graceful switch when sponsorship unavailable.","mockup":"erc-4337/gas-abstraction","components":["FallbackSelector","ReasonBanner"],"userFlow":["Paymaster rejects","UI explains why","Offers user-paid or alternate token","User continues or cancels"]}],"seenInTheWild":[{"app":"Biconomy","url":"https://www.biconomy.io/","note":"Paymaster infrastructure powers gasless onboarding patterns."},{"app":"Pimlico","url":"https://pimlico.io/","note":"Bundler and paymaster services set expectations for sponsorship UX."},{"app":"Coinbase Smart Wallet","url":"https://www.coinbase.com/wallet/smart-wallet","note":"Sponsored transactions for new users on supported networks."}],"antiPatterns":[{"pattern":"Hiding standard-imposed restrictions until submit","why":"Users feel tricked when actions fail at the last step","instead":"Show eligibility and badges before the primary CTA","severity":"critical"},{"pattern":"Protocol jargon in user-facing copy","why":"Non-technical users cannot consent informedly","instead":"Use outcome language with optional technical disclosure","severity":"high"},{"pattern":"No fallback when wallet lacks support","why":"Dead-end flows increase churn","instead":"Explain limitation and offer alternate path or network","severity":"high"}],"vocabulary":[{"use":"Your balance / Your item","avoid":"Token ID / Token contract","why":"Ownership language matches mental models."},{"use":"Cannot transfer yet","avoid":"Transfer reverted","why":"Explain restriction without EVM vocabulary."},{"use":"Confirm in wallet","avoid":"Sign transaction","why":"Matches wallet UX users already know."}],"onMonad":[{"aspect":"Confirmation speed","ethereum":"Multi-step flows can feel slow between signatures","monad":"Sub-second finality tightens feedback loops","designImplication":"Prefer inline status over long pending modals on Monad."},{"aspect":"Transaction cost","ethereum":"Gas can discourage exploratory actions","monad":"Lower fees enable lighter-weight interactions","designImplication":"Safe to offer preview retries and social actions more freely."}],"technicalNotes":"ERC-7677 defines paymaster interface for gas sponsorship in account abstraction flows.","relatedStandards":[{"id":"ERC-4337","relationship":"Paymasters attach to UserOperations"},{"id":"ERC-2771","relationship":"Legacy meta-transaction pattern being replaced"}]},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-7677","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-7677","type":"discussion"},{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-7677","type":"official-spec"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-7677","markdown":"https://www.eipsfordesigners.com/standards/ERC-7677/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-7677/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-7677","official":"https://eips.ethereum.org/EIPS/erc-7677","discussion":"https://ethereum-magicians.org/search?q=ERC-7677"},"freshness":{"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25"}},{"id":"EIP-8141","name":"Native Account Abstraction (Frame Txs)","status":"Draft","chain":"ethereum","category":{"id":"transaction-friction","name":"Transaction Friction","description":"Reducing clicks, signatures, and mental overhead"},"journeyStages":[{"id":"executing","name":"Executing Transactions","description":"Performing on-chain actions"},{"id":"gas","name":"Gas & Fees","description":"Paying for transactions"}],"uxImpact":"Native protocol-level account abstraction — every Ethereum account becomes a smart account by default, no opt-in required. Design implications: design for a world where all accounts have smart wallet capabilities, remove EOA vs smart account distinction from UX, build universal recovery and key rotation flows. Design decisions: long-term architectural consideration — plan for native AA while building on ERC-4337/EIP-7702 today, consider migration paths for existing EOA users. Active draft. Long-term fix for the EOA vs smart account split — 'Native AA lets every user benefit without opting in.' High severity in Protocol Design section.","hasDetailedContent":true,"content":{"id":"EIP-8141","sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-8141","type":"official-spec"}],"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25","summary":"Native protocol-level account abstraction — every Ethereum account becomes a smart account by default, no opt-in required.","designerTakeaways":["You can design flows assuming every account supports smart features eventually.","Your product roadmap should plan migration from ERC-4337-only patterns.","You can remove EOA-specific dead ends from long-term UX architecture."],"applicability":{"whenToUse":["Long-term Ethereum product strategy spanning multiple years.","You want universal recovery and key rotation without smart account opt-in.","Protocol-level AA simplifies your wallet integration surface."],"whenToAvoid":["Shipping before native AA is finalized on mainnet.","Current stack only supports EOAs and ERC-4337 today.","Users need production-ready flows now without draft-spec risk."]},"prototypeFirst":[{"screen":"Primary happy path","why":"Prove the core user promise before edge cases.","covers":["Success state","Clear outcome copy"],"include":["Primary CTA","Confirmation feedback","Next step"]},{"screen":"Blocked or unsupported state","why":"Users discover limits when wallets or chains lack support.","covers":["Unsupported wallet","Wrong network"],"include":["Plain-language reason","Fallback action"]},{"screen":"Failure recovery","why":"Trust breaks when errors look like bugs.","covers":["User rejection","Transaction revert"],"include":["Retry path","Support context"]},{"screen":"Advanced disclosure","why":"Power users need technical detail without cluttering the default path.","covers":["Contract address","Token ID","Raw status"],"include":["Expandable section","Copy buttons","Explorer link"]}],"statesToDesign":[{"state":"Ready","trigger":"Prerequisites met.","userNeed":"Understand what happens next.","designResponse":"Enable primary action with plain-language preview."},{"state":"Awaiting signature","trigger":"Wallet prompt open.","userNeed":"Know what they are approving.","designResponse":"Mirror human-readable summary in app and wallet."},{"state":"Pending","trigger":"Transaction submitted.","userNeed":"Confidence it is progressing.","designResponse":"Show status strip with explorer link."},{"state":"Succeeded","trigger":"On-chain confirmation.","userNeed":"See updated ownership or balance.","designResponse":"Celebrate outcome and show new state clearly."},{"state":"Failed or reverted","trigger":"Validation or execution failed.","userNeed":"Fix or retry without guessing.","designResponse":"Name the failed constraint and offer a concrete next step."}],"designDecisions":[{"question":"How much protocol detail do users see?","recommendation":"Lead with outcomes; tuck identifiers behind review.","rationale":"Users decide on consequences, not function selectors."},{"question":"What happens when support is missing?","recommendation":"Block with explanation and fallback path.","rationale":"Silent failure feels like a broken product."},{"question":"How do you label restricted assets?","recommendation":"Use persistent badges for non-transferable, locked, or expiring states.","rationale":"Hidden restrictions cause rage-quits at transfer time."}],"problemsSolved":[{"problem":"Inconsistent behavior across apps","oldWay":"Each team reinvents copy and edge cases","newWay":"Shared standard gives predictable UX patterns","impact":"high"},{"problem":"Users surprised by on-chain rules","oldWay":"Generic transfer UI fails at submit time","newWay":"Standard-aware UI sets expectations upfront","impact":"high"},{"problem":"Support burden from opaque errors","oldWay":"Raw revert reasons in toasts","newWay":"Mapped states explain what to do next","impact":"medium"}],"uxPatterns":[{"name":"Universal Smart Account Assumption","description":"Design flows without EOA vs smart account branching.","mockup":"erc-4337/gas-abstraction","components":["UnifiedFlow","RecoveryPanel"],"userFlow":["User connects","Same batching and recovery UX for all","No account type selector"]},{"name":"Migration Preview","description":"Help existing EOA users understand upcoming native AA.","mockup":"erc-4337/gas-abstraction","components":["MigrationBanner","TimelineCard"],"userFlow":["User on legacy path","See upcoming native AA benefits","Optional early adopter enrollment"]}],"seenInTheWild":[{"app":"Ethereum Foundation","url":"https://eips.ethereum.org/EIPS/eip-8141","note":"Active draft defining native AA direction for protocol designers."},{"app":"Safe","url":"https://safe.global/","note":"Smart account UX patterns inform what native AA should feel like."},{"app":"MetaMask","url":"https://metamask.io/","note":"Wallet teams planning for native AA alongside EIP-7702."}],"antiPatterns":[{"pattern":"Hiding standard-imposed restrictions until submit","why":"Users feel tricked when actions fail at the last step","instead":"Show eligibility and badges before the primary CTA","severity":"critical"},{"pattern":"Protocol jargon in user-facing copy","why":"Non-technical users cannot consent informedly","instead":"Use outcome language with optional technical disclosure","severity":"high"},{"pattern":"No fallback when wallet lacks support","why":"Dead-end flows increase churn","instead":"Explain limitation and offer alternate path or network","severity":"high"}],"vocabulary":[{"use":"Your balance / Your item","avoid":"Token ID / Token contract","why":"Ownership language matches mental models."},{"use":"Cannot transfer yet","avoid":"Transfer reverted","why":"Explain restriction without EVM vocabulary."},{"use":"Confirm in wallet","avoid":"Sign transaction","why":"Matches wallet UX users already know."}],"technicalNotes":"EIP-8141 is an active draft for native account abstraction via frame transactions.","relatedStandards":[{"id":"EIP-7702","relationship":"Near-term bridge to smart account UX"},{"id":"ERC-4337","relationship":"Current account abstraction implementation"}]},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-8141","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=EIP-8141","type":"discussion"},{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-8141","type":"official-spec"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/EIP-8141","markdown":"https://www.eipsfordesigners.com/standards/EIP-8141/content.md","agent":"https://www.eipsfordesigners.com/standards/EIP-8141/agent.md","api":"https://www.eipsfordesigners.com/api/standards/EIP-8141","official":"https://eips.ethereum.org/EIPS/eip-8141","discussion":"https://ethereum-magicians.org/search?q=EIP-8141"},"freshness":{"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25"}},{"id":"ERC-7715","name":"Session Keys","status":"Draft","chain":"both","category":{"id":"transaction-friction","name":"Transaction Friction","description":"Reducing clicks, signatures, and mental overhead"},"journeyStages":[{"id":"approving","name":"Approving & Permissioning","description":"Granting permissions for actions"},{"id":"executing","name":"Executing Transactions","description":"Performing on-chain actions"}],"uxImpact":"Users pre-authorize a scope of actions so they don't sign every interaction — 'approve once, interact freely' for gaming, trading, and social apps. Design implications: design session key creation flows with clear scope display (which actions, spending limits, duration), show active session indicators, add session revocation UI, display remaining session budget/time. Design decisions: balance between permissiveness (fewer prompts) and security (tighter scopes), how to visualize session boundaries to users, whether to auto-expire sessions or require manual revocation. Primary solution to Signing Fatigue (High severity). MetaMask Delegation Toolkit and Viem implementing.","hasDetailedContent":true,"content":{"id":"ERC-7715","sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-7715","type":"official-spec"}],"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25","summary":"Users pre-authorize a scope of actions so they don't sign every interaction — 'approve once, interact freely' for gaming, trading, and social apps.","designerTakeaways":["You can show session scope as a plain-language permission card before approval.","Your app can display active session badge with remaining budget and time.","You can offer one-tap revoke-all in settings for peace of mind."],"applicability":{"whenToUse":["High-frequency interactions cause signing fatigue.","Actions fit clear scopes like in-game moves or limit orders.","Users understand upfront what the app can do without prompts."],"whenToAvoid":["Every action is high-value and needs individual confirmation.","Wallet or chain lacks session key support.","Scopes cannot be explained simply to non-technical users."]},"prototypeFirst":[{"screen":"Primary happy path","why":"Prove the core user promise before edge cases.","covers":["Success state","Clear outcome copy"],"include":["Primary CTA","Confirmation feedback","Next step"]},{"screen":"Blocked or unsupported state","why":"Users discover limits when wallets or chains lack support.","covers":["Unsupported wallet","Wrong network"],"include":["Plain-language reason","Fallback action"]},{"screen":"Failure recovery","why":"Trust breaks when errors look like bugs.","covers":["User rejection","Transaction revert"],"include":["Retry path","Support context"]},{"screen":"Advanced disclosure","why":"Power users need technical detail without cluttering the default path.","covers":["Contract address","Token ID","Raw status"],"include":["Expandable section","Copy buttons","Explorer link"]}],"mentalModel":[{"label":"Scope request","description":"The app asks for a bounded permission: allowed actions, spend cap, and duration. Frame it like app permissions, not cryptographic jargon."},{"label":"User approval","description":"One signature creates a session key within those limits. The permission card must list every capability in plain language."},{"label":"Silent actions","description":"Within scope, the app executes without per-action wallet popups. Show an active session badge so silent actions never feel hidden."},{"label":"Limit enforcement","description":"When spend or time limits are hit, the app must re-prompt or stop. Never let the UI imply unlimited authority."},{"label":"Revoke","description":"Users can end the session from settings or the badge. Revoke all should be one tap for peace of mind."}],"statesToDesign":[{"state":"Ready","trigger":"Prerequisites met.","userNeed":"Understand what happens next.","designResponse":"Enable primary action with plain-language preview."},{"state":"Awaiting signature","trigger":"Wallet prompt open.","userNeed":"Know what they are approving.","designResponse":"Mirror human-readable summary in app and wallet."},{"state":"Pending","trigger":"Transaction submitted.","userNeed":"Confidence it is progressing.","designResponse":"Show status strip with explorer link."},{"state":"Succeeded","trigger":"On-chain confirmation.","userNeed":"See updated ownership or balance.","designResponse":"Celebrate outcome and show new state clearly."},{"state":"Failed or reverted","trigger":"Validation or execution failed.","userNeed":"Fix or retry without guessing.","designResponse":"Name the failed constraint and offer a concrete next step."}],"designDecisions":[{"question":"How much protocol detail do users see?","recommendation":"Lead with outcomes; tuck identifiers behind review.","rationale":"Users decide on consequences, not function selectors."},{"question":"What happens when support is missing?","recommendation":"Block with explanation and fallback path.","rationale":"Silent failure feels like a broken product."},{"question":"How do you label restricted assets?","recommendation":"Use persistent badges for non-transferable, locked, or expiring states.","rationale":"Hidden restrictions cause rage-quits at transfer time."}],"problemsSolved":[{"problem":"Inconsistent behavior across apps","oldWay":"Each team reinvents copy and edge cases","newWay":"Shared standard gives predictable UX patterns","impact":"high"},{"problem":"Users surprised by on-chain rules","oldWay":"Generic transfer UI fails at submit time","newWay":"Standard-aware UI sets expectations upfront","impact":"high"},{"problem":"Support burden from opaque errors","oldWay":"Raw revert reasons in toasts","newWay":"Mapped states explain what to do next","impact":"medium"}],"uxPatterns":[{"name":"Session Permission Card","description":"Plain-language scope before one-time approval.","mockup":"concept/permit-approval","components":["ScopeList","SpendCap","ExpiryTimer"],"userFlow":["App requests session","User reviews scope","Approves once","Actions proceed silently within limits"]},{"name":"Active Session Badge","description":"Persistent indicator of ongoing authorization.","mockup":"eip-7702/session-permissions","components":["SessionBadge","RevokeButton"],"userFlow":["Session active","Badge shows limits","User can revoke anytime","App returns to per-action signing"]}],"seenInTheWild":[{"app":"MetaMask Delegation Toolkit","url":"https://docs.metamask.io/delegation-toolkit/","note":"Session key implementation reference for wallet teams."},{"app":"Viem","url":"https://viem.sh/","note":"Developer tooling for session permission patterns."},{"app":"Parallel","url":"https://parallel.life/","note":"Games benefit from reduced signing friction during gameplay."}],"antiPatterns":[{"pattern":"Hiding standard-imposed restrictions until submit","why":"Users feel tricked when actions fail at the last step","instead":"Show eligibility and badges before the primary CTA","severity":"critical"},{"pattern":"Protocol jargon in user-facing copy","why":"Non-technical users cannot consent informedly","instead":"Use outcome language with optional technical disclosure","severity":"high"},{"pattern":"No fallback when wallet lacks support","why":"Dead-end flows increase churn","instead":"Explain limitation and offer alternate path or network","severity":"high"}],"vocabulary":[{"use":"Your balance / Your item","avoid":"Token ID / Token contract","why":"Ownership language matches mental models."},{"use":"Cannot transfer yet","avoid":"Transfer reverted","why":"Explain restriction without EVM vocabulary."},{"use":"Confirm in wallet","avoid":"Sign transaction","why":"Matches wallet UX users already know."}],"onMonad":[{"aspect":"Confirmation speed","ethereum":"Multi-step flows can feel slow between signatures","monad":"Sub-second finality tightens feedback loops","designImplication":"Prefer inline status over long pending modals on Monad."},{"aspect":"Transaction cost","ethereum":"Gas can discourage exploratory actions","monad":"Lower fees enable lighter-weight interactions","designImplication":"Safe to offer preview retries and social actions more freely."}],"technicalNotes":"ERC-7715 session keys require clear scope UI — balance permissiveness with security.","relatedStandards":[{"id":"EIP-7702","relationship":"EOA delegation enables session patterns"},{"id":"ERC-4337","relationship":"Smart accounts can hold session keys"}]},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-7715","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-7715","type":"discussion"},{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-7715","type":"official-spec"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-7715","markdown":"https://www.eipsfordesigners.com/standards/ERC-7715/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-7715/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-7715","official":"https://eips.ethereum.org/EIPS/erc-7715","discussion":"https://ethereum-magicians.org/search?q=ERC-7715"},"freshness":{"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25"}},{"id":"ERC-8019","name":"Auto-Login","status":"Draft","chain":"both","category":{"id":"transaction-friction","name":"Transaction Friction","description":"Reducing clicks, signatures, and mental overhead"},"journeyStages":[{"id":"authentication","name":"Authentication & Identity","description":"Proving who you are and logging in"}],"uxImpact":"Persistent wallet authentication across sessions — eliminates repeated login signatures when returning to dApps. Design implications: implement automatic session restoration on return visits, show 'remembered' connection status, design opt-in/opt-out for persistent auth, handle session expiration gracefully. Design decisions: security tradeoffs of persistent auth (convenience vs risk on shared devices), whether to require re-authentication for sensitive actions, how to handle multiple wallets with persistent sessions. Draft standard, Ambire implementing. Listed as a solution to Signing Fatigue — competes with/complements ERC-4361 (SIWE) for the auth flow.","hasDetailedContent":true,"content":{"id":"ERC-8019","sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-8019","type":"official-spec"}],"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25","summary":"Persistent wallet authentication across sessions — eliminates repeated login signatures when returning to dApps.","designerTakeaways":["You can restore wallet sessions automatically on return visits.","Your settings can offer Remember me with clear security tradeoff copy.","You can require re-authentication for withdrawals or settings changes."],"applicability":{"whenToUse":["Returning users dominate your traffic.","Repeated SIWE signatures cause drop-off.","Your app can store session state securely server-side."],"whenToAvoid":["Shared-device or kiosk contexts where persistence is dangerous.","Regulatory requirements mandate fresh auth every session.","Wallet does not support persistent auth extension."]},"prototypeFirst":[{"screen":"Primary happy path","why":"Prove the core user promise before edge cases.","covers":["Success state","Clear outcome copy"],"include":["Primary CTA","Confirmation feedback","Next step"]},{"screen":"Blocked or unsupported state","why":"Users discover limits when wallets or chains lack support.","covers":["Unsupported wallet","Wrong network"],"include":["Plain-language reason","Fallback action"]},{"screen":"Failure recovery","why":"Trust breaks when errors look like bugs.","covers":["User rejection","Transaction revert"],"include":["Retry path","Support context"]},{"screen":"Advanced disclosure","why":"Power users need technical detail without cluttering the default path.","covers":["Contract address","Token ID","Raw status"],"include":["Expandable section","Copy buttons","Explorer link"]}],"mentalModel":[{"label":"First visit sign-in","description":"The user signs once with SIWE to prove wallet ownership. This is the only signature required if they opt into persistence."},{"label":"Session credential","description":"The app and server store a scoped session token tied to wallet and expiry. It replaces repeated sign-in on return visits."},{"label":"Auto-restore","description":"On return, the app validates the stored session before showing account content. Show a brief restoring state, not a blank error."},{"label":"Sensitive re-auth","description":"Withdrawals, settings changes, or high-value actions trigger a fresh signature even when Remember me is on."},{"label":"Revoke and logout","description":"Clear server session and local storage on logout. Users need a visible path to end persistence on shared devices."}],"statesToDesign":[{"state":"Ready","trigger":"Prerequisites met.","userNeed":"Understand what happens next.","designResponse":"Enable primary action with plain-language preview."},{"state":"Awaiting signature","trigger":"Wallet prompt open.","userNeed":"Know what they are approving.","designResponse":"Mirror human-readable summary in app and wallet."},{"state":"Pending","trigger":"Transaction submitted.","userNeed":"Confidence it is progressing.","designResponse":"Show status strip with explorer link."},{"state":"Succeeded","trigger":"On-chain confirmation.","userNeed":"See updated ownership or balance.","designResponse":"Celebrate outcome and show new state clearly."},{"state":"Failed or reverted","trigger":"Validation or execution failed.","userNeed":"Fix or retry without guessing.","designResponse":"Name the failed constraint and offer a concrete next step."}],"designDecisions":[{"question":"How much protocol detail do users see?","recommendation":"Lead with outcomes; tuck identifiers behind review.","rationale":"Users decide on consequences, not function selectors."},{"question":"What happens when support is missing?","recommendation":"Block with explanation and fallback path.","rationale":"Silent failure feels like a broken product."},{"question":"How do you label restricted assets?","recommendation":"Use persistent badges for non-transferable, locked, or expiring states.","rationale":"Hidden restrictions cause rage-quits at transfer time."}],"problemsSolved":[{"problem":"Inconsistent behavior across apps","oldWay":"Each team reinvents copy and edge cases","newWay":"Shared standard gives predictable UX patterns","impact":"high"},{"problem":"Users surprised by on-chain rules","oldWay":"Generic transfer UI fails at submit time","newWay":"Standard-aware UI sets expectations upfront","impact":"high"},{"problem":"Support burden from opaque errors","oldWay":"Raw revert reasons in toasts","newWay":"Mapped states explain what to do next","impact":"medium"}],"uxPatterns":[{"name":"Silent Reconnect","description":"Restore session on page load without modal.","mockup":"concept/siwe-sign-in","components":["SessionRestore","AccountChip"],"userFlow":["User returns","Session restored","Account chip appears","Optional re-auth for sensitive actions"]},{"name":"Remember Me Toggle","description":"Explicit opt-in for persistent auth.","mockup":"concept/siwe-sign-in","components":["RememberToggle","SecurityNote"],"userFlow":["First sign-in","User opts into remember","Future visits skip sign-in","User can disable in settings"]}],"seenInTheWild":[{"app":"Ambire","url":"https://www.ambire.com/","note":"Implementing persistent auth for smoother return visits."},{"app":"OpenSea","url":"https://opensea.io/","note":"Session persistence patterns for marketplace return users."},{"app":"Zora","url":"https://zora.co/","note":"Creator platforms benefit from reduced re-auth friction."}],"antiPatterns":[{"pattern":"Hiding standard-imposed restrictions until submit","why":"Users feel tricked when actions fail at the last step","instead":"Show eligibility and badges before the primary CTA","severity":"critical"},{"pattern":"Protocol jargon in user-facing copy","why":"Non-technical users cannot consent informedly","instead":"Use outcome language with optional technical disclosure","severity":"high"},{"pattern":"No fallback when wallet lacks support","why":"Dead-end flows increase churn","instead":"Explain limitation and offer alternate path or network","severity":"high"}],"vocabulary":[{"use":"Your balance / Your item","avoid":"Token ID / Token contract","why":"Ownership language matches mental models."},{"use":"Cannot transfer yet","avoid":"Transfer reverted","why":"Explain restriction without EVM vocabulary."},{"use":"Confirm in wallet","avoid":"Sign transaction","why":"Matches wallet UX users already know."}],"onMonad":[{"aspect":"Confirmation speed","ethereum":"Multi-step flows can feel slow between signatures","monad":"Sub-second finality tightens feedback loops","designImplication":"Prefer inline status over long pending modals on Monad."},{"aspect":"Transaction cost","ethereum":"Gas can discourage exploratory actions","monad":"Lower fees enable lighter-weight interactions","designImplication":"Safe to offer preview retries and social actions more freely."}],"technicalNotes":"ERC-8019 is a draft standard for auto-login; balance convenience with shared-device risk.","relatedStandards":[{"id":"ERC-4361","relationship":"SIWE auth that 8019 extends with persistence"},{"id":"ERC-6492","relationship":"Auth for undeployed smart accounts"}]},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-8019","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-8019","type":"discussion"},{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-8019","type":"official-spec"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-8019","markdown":"https://www.eipsfordesigners.com/standards/ERC-8019/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-8019/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-8019","official":"https://eips.ethereum.org/EIPS/erc-8019","discussion":"https://ethereum-magicians.org/search?q=ERC-8019"},"freshness":{"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25"}},{"id":"EIP-712","name":"Typed Structured Data Signing","status":"Final","chain":"both","category":{"id":"comprehension","name":"Comprehension & Display","description":"Making blockchain data readable to humans"},"journeyStages":[{"id":"authentication","name":"Authentication & Identity","description":"Proving who you are and logging in"},{"id":"reading","name":"Reading & Understanding","description":"Interpreting what you're being asked to do"}],"uxImpact":"Users see human-readable signing requests instead of confusing hex strings — they can verify 'Send 100 USDC to vitalik.eth' rather than raw bytes. Design implications: display typed data fields clearly in a structured table/card format, show domain name prominently to prevent phishing, group related fields logically, highlight high-risk fields (amounts, recipients) with visual emphasis. Design decisions: balance between showing all fields (completeness) vs. summarizing (readability), decide how to handle nested structs and arrays, consider progressive disclosure for complex messages.","hasDetailedContent":true,"content":{"id":"EIP-712","summary":"EIP-712 makes signature requests readable. Instead of signing a blob of hex like \"0x4f8a3bc7...\", users see structured data: \"Swap 100 USDC for 0.05 ETH on Uniswap\". This transforms scary signature popups into understandable confirmations that users can actually verify before signing.","applicability":{"whenToUse":["Users sign off-chain messages and wallets should show readable intent.","Permit, vote, or order flows need domain-bound typed data (EIP-712).","You must show amounts, tokens, deadlines, and contract context before sign."],"whenToAvoid":["Flows use on-chain transactions only with no typed-data signatures.","You cannot control poor field labels returned by the protocol.","Hardware wallets or platforms block structured signing reliably."]},"designerTakeaways":["You can replace hex blobs with labeled fields users can verify before signing.","You can bind signatures to app, chain, and contract so replays fail elsewhere.","You can add deadlines and human copy so stale signatures are obvious."],"mentalModel":[{"label":"User intent","description":"The dApp builds a structured message with amounts, deadlines, and permissions instead of opaque hex."},{"label":"Typed schema","description":"Field names and types define what appears in the wallet. Use human-readable labels in your schema, not a1 or value0."},{"label":"Domain binding","description":"The domain ties the signature to one app, chain, and verifying contract. Wallets should show this context so replays fail elsewhere."},{"label":"Wallet display","description":"The wallet parses typed data and renders labeled fields. Your app preview should match what the wallet will show."},{"label":"Signature scope","description":"The signed message grants exactly what the fields describe, often off-chain until submitted. Include deadlines so stale signatures are obvious."}],"problemsSolved":[{"problem":"Users sign unreadable hex blobs","oldWay":"Sign \"0x4f8a3bc7d91e...\" — what does this even mean?","newWay":"Sign \"Swap 100 USDC for 0.05 ETH, deadline 10 minutes\"","impact":"critical"},{"problem":"Can't verify what you're signing","oldWay":"Hope the dApp isn't lying about what that hex means","newWay":"Wallet parses and displays actual data fields","impact":"critical"},{"problem":"Signatures replayable across contexts","oldWay":"Sign for Uniswap, attacker uses on SushiSwap","newWay":"Domain separator binds signature to specific contract","impact":"high"}],"uxPatterns":[{"name":"Typed Data Signature","description":"Structured, readable signature request","mockup":"concept/typed-data","userFlow":["dApp requests EIP-712 signature","Wallet parses typed data structure","Displays fields in readable format","Shows domain/contract info","User verifies and signs"]},{"name":"Order Confirmation","description":"Trading orders with clear terms","mockup":"concept/typed-data","userFlow":["User creates sell order","App generates EIP-712 typed order","Wallet shows order terms clearly","User signs off-chain order","Order stored, executed when matched"]}],"uiComponents":[{"name":"TypedDataViewer","description":"Renders EIP-712 typed data in readable format","states":["loading","parsed","error"],"props":["typedData","domain","primaryType"]},{"name":"FieldValuePair","description":"Single field:value row with type indicator","states":["normal","highlighted","warning"],"props":["name","value","type"]},{"name":"DomainVerifier","description":"Shows and verifies signing domain","states":["verified","unknown","suspicious"],"props":["name","chainId","verifyingContract"]}],"antiPatterns":[{"pattern":"Not using EIP-712 for off-chain signatures","why":"Users sign unreadable data, easy to miss attacks","instead":"Always use typed structured data","severity":"critical"},{"pattern":"Poor field names in typed data","why":"\"a1\", \"b2\" mean nothing to users","instead":"Human-readable names: \"tokenAmount\", \"deadline\"","severity":"high"},{"pattern":"Not including deadline in signatures","why":"Signature valid forever, can be reused later","instead":"Always include expiration/deadline field","severity":"high"},{"pattern":"Showing raw timestamps","why":"\"1707123456\" is not human-readable","instead":"Convert to \"Feb 5, 2024 at 3:30 PM\"","severity":"medium"}],"onMonad":[{"aspect":"Chain ID in Domain","ethereum":"chainId: 1","monad":"chainId: [monad-id]","designImplication":"Domain separator must use Monad chain ID"},{"aspect":"Contract Addresses","ethereum":"Ethereum mainnet addresses","monad":"Monad-specific contract addresses","designImplication":"Verify contracts match expected Monad deployments"}],"keyTakeaways":["EIP-712 = readable signature requests","Always use typed data for off-chain signatures","Include deadlines to prevent replay attacks","Use human-readable field names","Format timestamps as readable dates"],"technicalNotes":"EIP-712 defines a typed structured data format with domain separator (name, version, chainId, verifyingContract) and typed message. Signature uses eth_signTypedData_v4 RPC method. Domain prevents cross-contract replay. Types define schema for nested structs. Hash is keccak256(prefix || domainSeparator || structHash)."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-712","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=EIP-712","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/EIP-712","markdown":"https://www.eipsfordesigners.com/standards/EIP-712/content.md","agent":"https://www.eipsfordesigners.com/standards/EIP-712/agent.md","api":"https://www.eipsfordesigners.com/api/standards/EIP-712","official":"https://eips.ethereum.org/EIPS/eip-712","discussion":"https://ethereum-magicians.org/search?q=EIP-712"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"ERC-7730","name":"Clear Signing Metadata","status":"Draft","chain":"both","category":{"id":"comprehension","name":"Comprehension & Display","description":"Making blockchain data readable to humans"},"journeyStages":[{"id":"reading","name":"Reading & Understanding","description":"Interpreting what you're being asked to do"},{"id":"approving","name":"Approving & Permissioning","description":"Granting permissions for actions"}],"uxImpact":"Builds on EIP-712 to provide full human-readable transaction summaries — transforms 'sign this hex blob' into 'Send 100 USDC to vitalik.eth.' Design implications: display complete transaction summaries in plain language, show contract interaction details (function name, parameters) in human terms, enable 'Domain verified on-chain' indicators, integrate with transaction simulation for balance change previews. Design decisions: how to handle contracts without clear signing metadata (fallback to raw data vs blocking), trust model for metadata providers, how prominently to warn when clear signing data is unavailable. Critical priority across 5+ pain points (blind signing, blanket warnings, scam prevention). The standard that powers the clear-signing movement (clear-signing.org). ","hasDetailedContent":true,"content":{"id":"ERC-7730","sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-7730","type":"official-spec"}],"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25","summary":"Builds on EIP-712 to provide full human-readable transaction summaries — transforms 'sign this hex blob' into 'Send 100 USDC to vitalik.eth.","designerTakeaways":["You can show complete transaction summaries in plain language before wallet prompts.","Your UI can warn prominently when clear-signing data is unavailable.","You can integrate domain verification indicators for trust."],"applicability":{"whenToUse":["Users sign complex contract interactions.","Blind signing is a support and security risk.","Your contracts can publish ERC-7730 metadata."],"whenToAvoid":["Simple native token sends need no metadata layer.","Target contracts lack clear-signing registration.","You cannot block or warn on missing metadata."]},"prototypeFirst":[{"screen":"Primary happy path","why":"Prove the core user promise before edge cases.","covers":["Success state","Clear outcome copy"],"include":["Primary CTA","Confirmation feedback","Next step"]},{"screen":"Blocked or unsupported state","why":"Users discover limits when wallets or chains lack support.","covers":["Unsupported wallet","Wrong network"],"include":["Plain-language reason","Fallback action"]},{"screen":"Failure recovery","why":"Trust breaks when errors look like bugs.","covers":["User rejection","Transaction revert"],"include":["Retry path","Support context"]},{"screen":"Advanced disclosure","why":"Power users need technical detail without cluttering the default path.","covers":["Contract address","Token ID","Raw status"],"include":["Expandable section","Copy buttons","Explorer link"]}],"mentalModel":[{"label":"Contract intent","description":"The smart contract defines what the transaction will do. Without metadata, wallets fall back to calldata hex."},{"label":"ERC-7730 registry","description":"Contracts publish clear-signing metadata that maps function calls to human-readable summaries and field labels."},{"label":"Wallet fetch","description":"Before the sign prompt, the wallet loads metadata for the target contract and function. Missing metadata is a design failure state."},{"label":"Plain-language preview","description":"Your app and wallet should show the same summary, e.g. Send 100 USDC to vitalik.eth, before anything is irreversible."},{"label":"Verification","description":"Domain and contract context confirm the summary matches the intended app. Block or warn when clear-signing data is unavailable."}],"statesToDesign":[{"state":"Ready","trigger":"Prerequisites met.","userNeed":"Understand what happens next.","designResponse":"Enable primary action with plain-language preview."},{"state":"Awaiting signature","trigger":"Wallet prompt open.","userNeed":"Know what they are approving.","designResponse":"Mirror human-readable summary in app and wallet."},{"state":"Pending","trigger":"Transaction submitted.","userNeed":"Confidence it is progressing.","designResponse":"Show status strip with explorer link."},{"state":"Succeeded","trigger":"On-chain confirmation.","userNeed":"See updated ownership or balance.","designResponse":"Celebrate outcome and show new state clearly."},{"state":"Failed or reverted","trigger":"Validation or execution failed.","userNeed":"Fix or retry without guessing.","designResponse":"Name the failed constraint and offer a concrete next step."}],"designDecisions":[{"question":"How much protocol detail do users see?","recommendation":"Lead with outcomes; tuck identifiers behind review.","rationale":"Users decide on consequences, not function selectors."},{"question":"What happens when support is missing?","recommendation":"Block with explanation and fallback path.","rationale":"Silent failure feels like a broken product."},{"question":"How do you label restricted assets?","recommendation":"Use persistent badges for non-transferable, locked, or expiring states.","rationale":"Hidden restrictions cause rage-quits at transfer time."}],"problemsSolved":[{"problem":"Inconsistent behavior across apps","oldWay":"Each team reinvents copy and edge cases","newWay":"Shared standard gives predictable UX patterns","impact":"high"},{"problem":"Users surprised by on-chain rules","oldWay":"Generic transfer UI fails at submit time","newWay":"Standard-aware UI sets expectations upfront","impact":"high"},{"problem":"Support burden from opaque errors","oldWay":"Raw revert reasons in toasts","newWay":"Mapped states explain what to do next","impact":"medium"}],"uxPatterns":[{"name":"Human Transaction Summary","description":"Plain-language preview of every parameter.","mockup":"concept/typed-data","components":["SummaryCard","ParameterList","DomainBadge"],"userFlow":["User initiates action","App fetches 7730 metadata","Summary renders","User confirms with understanding"]},{"name":"Missing Metadata Gate","description":"Block or warn when clear signing unavailable.","mockup":"concept/typed-data","components":["WarningBanner","AdvancedToggle"],"userFlow":["Metadata missing","UI warns user","Offers cancel or advanced view","Never silent blind sign"]}],"seenInTheWild":[{"app":"Ledger Live","url":"https://www.ledger.com/ledger-live","note":"Hardware wallets pioneered clear signing for security."},{"app":"Clear Signing","url":"https://www.clear-signing.org/","note":"Industry movement ERC-7730 powers."},{"app":"Safe","url":"https://safe.global/","note":"Multi-sig flows depend on readable transaction previews."}],"antiPatterns":[{"pattern":"Hiding standard-imposed restrictions until submit","why":"Users feel tricked when actions fail at the last step","instead":"Show eligibility and badges before the primary CTA","severity":"critical"},{"pattern":"Protocol jargon in user-facing copy","why":"Non-technical users cannot consent informedly","instead":"Use outcome language with optional technical disclosure","severity":"high"},{"pattern":"No fallback when wallet lacks support","why":"Dead-end flows increase churn","instead":"Explain limitation and offer alternate path or network","severity":"high"}],"vocabulary":[{"use":"Your balance / Your item","avoid":"Token ID / Token contract","why":"Ownership language matches mental models."},{"use":"Cannot transfer yet","avoid":"Transfer reverted","why":"Explain restriction without EVM vocabulary."},{"use":"Confirm in wallet","avoid":"Sign transaction","why":"Matches wallet UX users already know."}],"onMonad":[{"aspect":"Confirmation speed","ethereum":"Multi-step flows can feel slow between signatures","monad":"Sub-second finality tightens feedback loops","designImplication":"Prefer inline status over long pending modals on Monad."},{"aspect":"Transaction cost","ethereum":"Gas can discourage exploratory actions","monad":"Lower fees enable lighter-weight interactions","designImplication":"Safe to offer preview retries and social actions more freely."}],"technicalNotes":"ERC-7730 extends EIP-712 with contract-specific human-readable metadata.","relatedStandards":[{"id":"EIP-712","relationship":"Typed data foundation for clear signing"},{"id":"ERC-6093","relationship":"Standardized error messages complement previews"}]},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-7730","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-7730","type":"discussion"},{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-7730","type":"official-spec"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-7730","markdown":"https://www.eipsfordesigners.com/standards/ERC-7730/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-7730/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-7730","official":"https://eips.ethereum.org/EIPS/erc-7730","discussion":"https://ethereum-magicians.org/search?q=ERC-7730"},"freshness":{"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25"}},{"id":"ERC-137","name":"Ethereum Name Service (ENS)","status":"Final","chain":"ethereum","category":{"id":"comprehension","name":"Comprehension & Display","description":"Making blockchain data readable to humans"},"journeyStages":[{"id":"authentication","name":"Authentication & Identity","description":"Proving who you are and logging in"},{"id":"asset-display","name":"Asset Discovery & Display","description":"Seeing tokens, NFTs, and balances"}],"uxImpact":"Users can send to 'vitalik.eth' instead of '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045' — memorable names replace error-prone addresses. Design implications: always show ENS names where available, provide autocomplete for .eth names, display both name AND resolved address for verification, show avatar/profile data from ENS records, handle subdomains gracefully. Design decisions: when to show address vs name (trust tradeoff), how to handle unregistered/expired names, whether to require re-resolution before transactions, loading states for async resolution. 910K+ active domains. ENS is a primary solution to Sending to Wrong Address (Critical severity). Showing ENS names alongside addresses is High priority for safety UX.","hasDetailedContent":true,"content":{"id":"ERC-137","summary":"ERC-137 is the Ethereum Name Service (ENS) standard. It turns \"0xd8dA6BF26964aF...\" into \"vitalik.eth\". Human-readable names for addresses, just like DNS for the internet. Users can send to \"alice.eth\" instead of copying 42-character hex strings. It's the foundation of human-readable web3 identity.","applicability":{"whenToUse":["Your product addresses: addresses are unreadable hex strings.","Your product addresses: easy to make typos in addresses.","The flow should deliver: type \"alice.eth\" or scan ENS name.","You are designing a ens input field experience with visible states and recovery paths."],"whenToAvoid":["Always show the resolved address.","Accept both ENS names and addresses.","Verify resolution on intended network.","Users never see addresses, amounts, or signing payloads in your UI."]},"designerTakeaways":["You can design UI that delivers type \"alice.eth\" or scan ENS name.","You can design UI that delivers names are memorable, typos are obvious.","You can design UI that delivers your .eth name works everywhere."],"problemsSolved":[{"problem":"Addresses are unreadable hex strings","oldWay":"Copy-paste \"0x7a3d8f2c9e1b4a5c6d7e8f9a0b1c2d3e4f5a6b7c\"","newWay":"Type \"alice.eth\" or scan ENS name","impact":"critical"},{"problem":"Easy to make typos in addresses","oldWay":"One wrong character = funds lost forever","newWay":"Names are memorable, typos are obvious","impact":"critical"},{"problem":"No portable identity across dApps","oldWay":"Different username on every platform","newWay":"Your .eth name works everywhere","impact":"high"}],"uxPatterns":[{"name":"ENS Input Field","description":"Accept both ENS names and addresses","mockup":"generic/token-transfer","userFlow":["User types ENS name","App resolves to address","Shows resolved address","Validates on correct network","User confirms and continues"]},{"name":"Profile with ENS","description":"Display user identity with ENS details","mockup":"generic/list-selector","userFlow":["User views address","App does reverse lookup","Fetches ENS name if exists","Loads avatar and records","Displays complete profile"]}],"uiComponents":[{"name":"ENSInput","description":"Input that accepts and resolves ENS names","states":["empty","typing","resolving","resolved","invalid"],"props":["value","resolvedAddress","onResolve"]},{"name":"ENSAvatar","description":"Displays ENS avatar or generates placeholder","states":["loading","loaded","fallback"],"props":["ensName","address","size"]},{"name":"AddressDisplay","description":"Shows address with ENS when available","states":["address-only","with-ens","loading"],"props":["address","ensName","truncate"]}],"antiPatterns":[{"pattern":"Only accepting raw addresses","why":"Users forced to copy long hex strings","instead":"Accept both ENS names and addresses","severity":"high"},{"pattern":"Not showing resolved address","why":"User can't verify where funds will go","instead":"Always show the resolved address","severity":"critical"},{"pattern":"Displaying addresses without ENS lookup","why":"User sees hex when human name exists","instead":"Do reverse resolution, show name if found","severity":"medium"},{"pattern":"Not checking resolution network","why":"ENS name might resolve differently on L2","instead":"Verify resolution on intended network","severity":"high"}],"onMonad":[{"aspect":"ENS Resolution","ethereum":"ENS is native to Ethereum mainnet","monad":"May need cross-chain resolution or Monad native names","designImplication":"Check if ENS works or use Monad equivalent"}],"keyTakeaways":["ENS = human-readable .eth names","Accept both ENS names and addresses in inputs","Always show resolved address for verification","Do reverse lookup to display names instead of hex","Verify resolution on the correct network"],"technicalNotes":"ERC-137 defines ENS registry with resolver pattern. namehash(name) produces deterministic node ID. Registry maps nodes to owners and resolvers. Resolvers implement addr() for address resolution, text() for records. ERC-181 adds reverse resolution via [address].addr.reverse. CCIP-read enables off-chain and L2 resolution."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-137","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-137","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-137","markdown":"https://www.eipsfordesigners.com/standards/ERC-137/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-137/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-137","official":"https://eips.ethereum.org/EIPS/eip-137","discussion":"https://ethereum-magicians.org/search?q=ERC-137"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"ERC-181","name":"ENS Reverse Resolution","status":"Final","chain":"ethereum","category":{"id":"comprehension","name":"Comprehension & Display","description":"Making blockchain data readable to humans"},"journeyStages":[{"id":"authentication","name":"Authentication & Identity","description":"Proving who you are and logging in"},{"id":"asset-display","name":"Asset Discovery & Display","description":"Seeing tokens, NFTs, and balances"}],"uxImpact":"Any wallet address can display a human name — '0xabc...' shows as 'alice.eth' in transaction histories and dashboards. Design implications: fetch reverse records for all displayed addresses, show names in activity feeds/transaction lists, display name in connected wallet UI, cache resolved names for performance. Design decisions: fallback display when no reverse record exists (truncated address vs full), handling mismatches between forward/reverse resolution (possible impersonation), refresh frequency for cached names.","hasDetailedContent":true,"content":{"id":"ERC-181","sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-181","type":"official-spec"}],"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25","summary":"ERC-181 enables reverse ENS resolution so wallet addresses display human-readable names like alice.eth instead of hex. Apps query reverse records to label senders and recipients in activity feeds, send flows, and connected wallet UI. Always pair names with address fallback and warn when forward and reverse resolution mismatch to prevent impersonation.","designerTakeaways":["You can fetch reverse records for every displayed address.","Your activity feeds can show ENS names with address fallback.","You can warn when forward and reverse resolution mismatch."],"applicability":{"whenToUse":["Addresses appear in feeds, send flows, or leaderboards.","Users benefit from human-readable identity.","ENS reverse records exist on your target chain."],"whenToAvoid":["Internal-only addresses never shown to users.","Performance constraints forbid reverse lookups.","Chain lacks ENS or compatible naming."]},"prototypeFirst":[{"screen":"Primary happy path","why":"Prove the core user promise before edge cases.","covers":["Success state","Clear outcome copy"],"include":["Primary CTA","Confirmation feedback","Next step"]},{"screen":"Blocked or unsupported state","why":"Users discover limits when wallets or chains lack support.","covers":["Unsupported wallet","Wrong network"],"include":["Plain-language reason","Fallback action"]},{"screen":"Failure recovery","why":"Trust breaks when errors look like bugs.","covers":["User rejection","Transaction revert"],"include":["Retry path","Support context"]},{"screen":"Advanced disclosure","why":"Power users need technical detail without cluttering the default path.","covers":["Contract address","Token ID","Raw status"],"include":["Expandable section","Copy buttons","Explorer link"]}],"statesToDesign":[{"state":"Ready","trigger":"Prerequisites met.","userNeed":"Understand what happens next.","designResponse":"Enable primary action with plain-language preview."},{"state":"Awaiting signature","trigger":"Wallet prompt open.","userNeed":"Know what they are approving.","designResponse":"Mirror human-readable summary in app and wallet."},{"state":"Pending","trigger":"Transaction submitted.","userNeed":"Confidence it is progressing.","designResponse":"Show status strip with explorer link."},{"state":"Succeeded","trigger":"On-chain confirmation.","userNeed":"See updated ownership or balance.","designResponse":"Celebrate outcome and show new state clearly."},{"state":"Failed or reverted","trigger":"Validation or execution failed.","userNeed":"Fix or retry without guessing.","designResponse":"Name the failed constraint and offer a concrete next step."}],"designDecisions":[{"question":"How much protocol detail do users see?","recommendation":"Lead with outcomes; tuck identifiers behind review.","rationale":"Users decide on consequences, not function selectors."},{"question":"What happens when support is missing?","recommendation":"Block with explanation and fallback path.","rationale":"Silent failure feels like a broken product."},{"question":"How do you label restricted assets?","recommendation":"Use persistent badges for non-transferable, locked, or expiring states.","rationale":"Hidden restrictions cause rage-quits at transfer time."}],"problemsSolved":[{"problem":"Inconsistent behavior across apps","oldWay":"Each team reinvents copy and edge cases","newWay":"Shared standard gives predictable UX patterns","impact":"high"},{"problem":"Users surprised by on-chain rules","oldWay":"Generic transfer UI fails at submit time","newWay":"Standard-aware UI sets expectations upfront","impact":"high"},{"problem":"Support burden from opaque errors","oldWay":"Raw revert reasons in toasts","newWay":"Mapped states explain what to do next","impact":"medium"}],"uxPatterns":[{"name":"Name-First Address Chip","description":"Show ENS name with truncated address on hover.","mockup":"concept/nft-gallery","components":["AddressChip","ENSResolver","AvatarFallback"],"userFlow":["Address displayed","Reverse lookup runs","Name shown if exists","Address available on expand"]},{"name":"Mismatch Warning","description":"Flag when forward and reverse disagree.","mockup":"concept/verify-safety","components":["MismatchBanner","VerifyLink"],"userFlow":["Name resolves","Forward check fails","Warning shown","User verifies before sending"]}],"seenInTheWild":[{"app":"ENS App","url":"https://app.ens.domains/","note":"Reference for reverse record setup and display."},{"app":"Etherscan","url":"https://etherscan.io/","note":"Shows ENS names on address pages and transaction lists."},{"app":"Rainbow","url":"https://rainbow.me/","note":"Wallet UI resolves names in send and receive flows."}],"antiPatterns":[{"pattern":"Hiding standard-imposed restrictions until submit","why":"Users feel tricked when actions fail at the last step","instead":"Show eligibility and badges before the primary CTA","severity":"critical"},{"pattern":"Protocol jargon in user-facing copy","why":"Non-technical users cannot consent informedly","instead":"Use outcome language with optional technical disclosure","severity":"high"},{"pattern":"No fallback when wallet lacks support","why":"Dead-end flows increase churn","instead":"Explain limitation and offer alternate path or network","severity":"high"}],"vocabulary":[{"use":"Your balance / Your item","avoid":"Token ID / Token contract","why":"Ownership language matches mental models."},{"use":"Cannot transfer yet","avoid":"Transfer reverted","why":"Explain restriction without EVM vocabulary."},{"use":"Confirm in wallet","avoid":"Sign transaction","why":"Matches wallet UX users already know."}],"technicalNotes":"ERC-181 reverse resolution maps address to primary ENS name; cache with refresh strategy.","relatedStandards":[{"id":"ERC-137","relationship":"Forward ENS resolution complement"},{"id":"ERC-162","relationship":"ENS name acquisition via registrar"}]},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-181","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-181","type":"discussion"},{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-181","type":"official-spec"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-181","markdown":"https://www.eipsfordesigners.com/standards/ERC-181/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-181/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-181","official":"https://eips.ethereum.org/EIPS/erc-181","discussion":"https://ethereum-magicians.org/search?q=ERC-181"},"freshness":{"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25"}},{"id":"ERC-55","name":"Mixed-case Address Checksum","status":"Final","chain":"both","category":{"id":"comprehension","name":"Comprehension & Display","description":"Making blockchain data readable to humans"},"journeyStages":[{"id":"authentication","name":"Authentication & Identity","description":"Proving who you are and logging in"}],"uxImpact":"Mixed-case addresses (0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed) catch typos before funds are lost — ~0.02% chance a random typo passes checksum. Design implications: always display checksummed addresses, validate checksum on paste/input with instant feedback, show clear error states for invalid checksums, consider case-preserving copy functionality. Design decisions: whether to auto-correct lowercase addresses or require exact match, how prominently to warn on checksum failure, whether to block or just warn on invalid checksums. Safety & Security Checklist rates verifying addresses with ERC-55 checksum as High priority — detects typos before sending.","hasDetailedContent":true,"content":{"id":"ERC-55","sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-55","type":"official-spec"}],"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25","summary":"Mixed-case addresses (0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed) catch typos before funds are lost — ~0.02% chance a random typo passes checksum.","designerTakeaways":["You can always display checksummed addresses in your UI.","Your paste handler can validate checksum with instant feedback.","You can preserve exact casing on copy for power users."],"applicability":{"whenToUse":["Users paste or type addresses manually.","Wrong-address sends are irreversible.","Your app displays addresses anywhere."],"whenToAvoid":["Addresses come only from QR scan with embedded checksum.","Non-EVM address formats use different validation.","Read-only display with no user input."]},"prototypeFirst":[{"screen":"Primary happy path","why":"Prove the core user promise before edge cases.","covers":["Success state","Clear outcome copy"],"include":["Primary CTA","Confirmation feedback","Next step"]},{"screen":"Blocked or unsupported state","why":"Users discover limits when wallets or chains lack support.","covers":["Unsupported wallet","Wrong network"],"include":["Plain-language reason","Fallback action"]},{"screen":"Failure recovery","why":"Trust breaks when errors look like bugs.","covers":["User rejection","Transaction revert"],"include":["Retry path","Support context"]},{"screen":"Advanced disclosure","why":"Power users need technical detail without cluttering the default path.","covers":["Contract address","Token ID","Raw status"],"include":["Expandable section","Copy buttons","Explorer link"]}],"statesToDesign":[{"state":"Ready","trigger":"Prerequisites met.","userNeed":"Understand what happens next.","designResponse":"Enable primary action with plain-language preview."},{"state":"Awaiting signature","trigger":"Wallet prompt open.","userNeed":"Know what they are approving.","designResponse":"Mirror human-readable summary in app and wallet."},{"state":"Pending","trigger":"Transaction submitted.","userNeed":"Confidence it is progressing.","designResponse":"Show status strip with explorer link."},{"state":"Succeeded","trigger":"On-chain confirmation.","userNeed":"See updated ownership or balance.","designResponse":"Celebrate outcome and show new state clearly."},{"state":"Failed or reverted","trigger":"Validation or execution failed.","userNeed":"Fix or retry without guessing.","designResponse":"Name the failed constraint and offer a concrete next step."}],"designDecisions":[{"question":"How much protocol detail do users see?","recommendation":"Lead with outcomes; tuck identifiers behind review.","rationale":"Users decide on consequences, not function selectors."},{"question":"What happens when support is missing?","recommendation":"Block with explanation and fallback path.","rationale":"Silent failure feels like a broken product."},{"question":"How do you label restricted assets?","recommendation":"Use persistent badges for non-transferable, locked, or expiring states.","rationale":"Hidden restrictions cause rage-quits at transfer time."}],"problemsSolved":[{"problem":"Inconsistent behavior across apps","oldWay":"Each team reinvents copy and edge cases","newWay":"Shared standard gives predictable UX patterns","impact":"high"},{"problem":"Users surprised by on-chain rules","oldWay":"Generic transfer UI fails at submit time","newWay":"Standard-aware UI sets expectations upfront","impact":"high"},{"problem":"Support burden from opaque errors","oldWay":"Raw revert reasons in toasts","newWay":"Mapped states explain what to do next","impact":"medium"}],"uxPatterns":[{"name":"Instant Checksum Validation","description":"Validate on paste with clear error state.","mockup":"concept/verify-safety","components":["AddressInput","ChecksumValidator","ErrorInline"],"userFlow":["User pastes address","Checksum validated","Green check or red error","Send blocked on invalid"]},{"name":"Checksummed Display","description":"Always render proper mixed-case.","mockup":"concept/verify-safety","components":["ChecksummedText","CopyButton"],"userFlow":["Address loaded","Checksummed format applied","User copies valid format","Recipient apps validate successfully"]}],"seenInTheWild":[{"app":"MetaMask","url":"https://metamask.io/","note":"Validates checksum on send and warns on invalid addresses."},{"app":"Etherscan","url":"https://etherscan.io/","note":"Displays checksummed addresses on all pages."},{"app":"MyCrypto","url":"https://www.mycrypto.com/","note":"Early advocate for checksum validation in send flows."}],"antiPatterns":[{"pattern":"Hiding standard-imposed restrictions until submit","why":"Users feel tricked when actions fail at the last step","instead":"Show eligibility and badges before the primary CTA","severity":"critical"},{"pattern":"Protocol jargon in user-facing copy","why":"Non-technical users cannot consent informedly","instead":"Use outcome language with optional technical disclosure","severity":"high"},{"pattern":"No fallback when wallet lacks support","why":"Dead-end flows increase churn","instead":"Explain limitation and offer alternate path or network","severity":"high"}],"vocabulary":[{"use":"Your balance / Your item","avoid":"Token ID / Token contract","why":"Ownership language matches mental models."},{"use":"Cannot transfer yet","avoid":"Transfer reverted","why":"Explain restriction without EVM vocabulary."},{"use":"Confirm in wallet","avoid":"Sign transaction","why":"Matches wallet UX users already know."}],"onMonad":[{"aspect":"Confirmation speed","ethereum":"Multi-step flows can feel slow between signatures","monad":"Sub-second finality tightens feedback loops","designImplication":"Prefer inline status over long pending modals on Monad."},{"aspect":"Transaction cost","ethereum":"Gas can discourage exploratory actions","monad":"Lower fees enable lighter-weight interactions","designImplication":"Safe to offer preview retries and social actions more freely."}],"technicalNotes":"ERC-55 checksum uses mixed case; ~0.02% of random typos pass — still validate.","relatedStandards":[{"id":"EIP-1191","relationship":"Chain-specific checksum extension"},{"id":"ERC-7930","relationship":"Chain-aware address format complement"}]},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-55","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-55","type":"discussion"},{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-55","type":"official-spec"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-55","markdown":"https://www.eipsfordesigners.com/standards/ERC-55/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-55/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-55","official":"https://eips.ethereum.org/EIPS/erc-55","discussion":"https://ethereum-magicians.org/search?q=ERC-55"},"freshness":{"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25"}},{"id":"EIP-1191","name":"Chain-specific Address Checksum","status":"Last Call","chain":"both","category":{"id":"comprehension","name":"Comprehension & Display","description":"Making blockchain data readable to humans"},"journeyStages":[{"id":"status","name":"Status & Confirmation","description":"Waiting for and confirming outcomes"}],"uxImpact":"Addresses have different checksums per chain — prevents sending mainnet funds to a testnet address that happens to be valid. Design implications: validate addresses against current network's chain ID, show chain badge alongside addresses, warn when address checksum doesn't match current network. Design decisions: which chains to support (RSK uses this, Ethereum mainnet doesn't), whether to treat cross-chain checksum mismatch as error or warning, how to handle chains that don't adopt this standard.","hasDetailedContent":true,"content":{"id":"EIP-1191","summary":"EIP-1191 extends address checksums to include the chain ID. The same address looks slightly different on each chain (different letter capitalizations). This prevents users from accidentally sending funds to the right address but on the wrong network - a common and costly mistake in multi-chain world.","applicability":{"whenToUse":["Your product addresses: same checksum valid on all chains.","Your product addresses: cross-chain address confusion.","The flow should deliver: checksum differs by chain, wrong-chain addresses fail validation.","You are designing a chain-specific address display experience with visible states and recovery paths."],"whenToAvoid":["Always validate checksum and warn on mismatch.","Show what was corrected and why.","Offer chain-specific copy buttons when relevant.","Users never see addresses, amounts, or signing payloads in your UI."]},"designerTakeaways":["You can design UI that delivers checksum differs by chain.","You can design UI that delivers chain-specific checksum catches the mistake.","You can design UI that delivers different capitalizations hint at different chains."],"problemsSolved":[{"problem":"Same checksum valid on all chains","oldWay":"Address looks identical on Ethereum and Polygon, easy to send to wrong chain","newWay":"Checksum differs by chain, wrong-chain addresses fail validation","impact":"high"},{"problem":"Cross-chain address confusion","oldWay":"Copy address from one chain, paste to another, funds go to wrong place","newWay":"Chain-specific checksum catches the mistake","impact":"high"},{"problem":"No visual indicator of intended chain","oldWay":"All addresses look the same regardless of chain","newWay":"Different capitalizations hint at different chains","impact":"medium"}],"uxPatterns":[{"name":"Chain-Specific Address Display","description":"Show address with checksum matching current chain","mockup":"concept/typed-data","userFlow":["User views their address","Address shown with chain-specific checksum","Copy button labeled with chain name","Explanation of why they differ"]},{"name":"Wrong Chain Address Warning","description":"Detect and warn about chain mismatch","mockup":"concept/typed-data","userFlow":["User pastes address","Checksum validated against current chain","Mismatch detected","Warning shown with detected chain","User can proceed with caution or cancel"]},{"name":"Address Input with Chain Validation","description":"Validate address format matches current chain","mockup":"concept/typed-data","userFlow":["User enters recipient address","Checksum validated in real-time","Green check if matches current chain","Warning if different chain checksum","Proceed only with valid checksum"]}],"uiComponents":[{"name":"ChainAwareAddressInput","description":"Address input that validates checksum for current chain","states":["empty","valid","invalid","wrong-chain"],"props":["chainId","value","onChange","onValidation"]},{"name":"ChecksumMismatchWarning","description":"Warning modal for chain-mismatched addresses","states":["detected","confirmed","cancelled"],"props":["detectedChain","currentChain","address","onProceed","onCancel"]},{"name":"MultiChainAddressDisplay","description":"Shows same address with different chain checksums","states":["single","multiple"],"props":["address","chains[]","onCopy"]}],"antiPatterns":[{"pattern":"Ignoring checksum validation","why":"Misses opportunity to catch wrong-chain mistakes","instead":"Always validate checksum and warn on mismatch","severity":"high"},{"pattern":"Silently correcting checksum","why":"User doesn't learn about the safety feature","instead":"Show what was corrected and why","severity":"medium"},{"pattern":"Only showing one address format","why":"User might copy and paste to wrong chain","instead":"Offer chain-specific copy buttons when relevant","severity":"medium"},{"pattern":"Blocking wrong-chain addresses entirely","why":"Sometimes user knows what they're doing (same address, different chain)","instead":"Warn but allow proceeding with confirmation","severity":"medium"}],"onMonad":[{"aspect":"Monad-Specific Checksum","ethereum":"Checksum includes chain ID 1","monad":"Monad checksum uses Monad's chain ID","designImplication":"Show Monad-formatted addresses when on Monad network"},{"aspect":"Cross-Chain Transfers","ethereum":"Users often bridge between L1 and L2s","monad":"Users may bridge between Ethereum and Monad","designImplication":"Extra clarity needed when copying addresses for bridge operations"}],"relatedStandards":[{"id":"ERC-55","relationship":"ERC-55 is the base checksum standard, EIP-1191 extends it with chain ID"},{"id":"EIP-155","relationship":"EIP-155 introduced chain ID concept that EIP-1191 uses in checksums"},{"id":"EIP-695","relationship":"eth_chainId provides the chain ID used for checksum calculation"}]},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-1191","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=EIP-1191","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/EIP-1191","markdown":"https://www.eipsfordesigners.com/standards/EIP-1191/content.md","agent":"https://www.eipsfordesigners.com/standards/EIP-1191/agent.md","api":"https://www.eipsfordesigners.com/api/standards/EIP-1191","official":"https://eips.ethereum.org/EIPS/eip-1191","discussion":"https://ethereum-magicians.org/search?q=EIP-1191"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"ERC-162","name":"ENS .eth Registrar","status":"Final","chain":"ethereum","category":{"id":"comprehension","name":"Comprehension & Display","description":"Making blockchain data readable to humans"},"journeyStages":[{"id":"authentication","name":"Authentication & Identity","description":"Proving who you are and logging in"}],"uxImpact":"Users acquire ENS names through blind auctions — bid privately, highest bidder wins, pays second-highest price. Design implications: guide users through 3-day bid reveal process with timeline UI, show deposit/refund status clearly, explain Vickrey auction mechanics simply, countdown timers for auction phases. Design decisions: how much auction complexity to expose vs abstract away, whether to show competitor activity, handling the 72hr bidding + 48hr reveal lifecycle, surfacing name availability timing.","hasDetailedContent":true,"content":{"id":"ERC-162","sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-162","type":"official-spec"}],"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25","summary":"Users acquire ENS names through blind auctions — bid privately, highest bidder wins, pays second-highest price.","designerTakeaways":["You can show auction phases on a timeline with countdown timers.","Your reveal flow can explain why revealing matters before deadline.","You can surface deposit and refund status clearly."],"applicability":{"whenToUse":["Your product helps users acquire ENS .eth names.","Auction mechanics need step-by-step guidance.","Users must manage bid reveal deadlines."],"whenToAvoid":["Names acquired via direct purchase or L2 gateways only.","Your app does not touch ENS registration.","Users only resolve names, never register."]},"prototypeFirst":[{"screen":"Primary happy path","why":"Prove the core user promise before edge cases.","covers":["Success state","Clear outcome copy"],"include":["Primary CTA","Confirmation feedback","Next step"]},{"screen":"Blocked or unsupported state","why":"Users discover limits when wallets or chains lack support.","covers":["Unsupported wallet","Wrong network"],"include":["Plain-language reason","Fallback action"]},{"screen":"Failure recovery","why":"Trust breaks when errors look like bugs.","covers":["User rejection","Transaction revert"],"include":["Retry path","Support context"]},{"screen":"Advanced disclosure","why":"Power users need technical detail without cluttering the default path.","covers":["Contract address","Token ID","Raw status"],"include":["Expandable section","Copy buttons","Explorer link"]}],"mentalModel":[{"label":"Commit phase","description":"Bidders submit a hidden hash of their bid plus deposit. The UI must explain that bids are sealed until reveal."},{"label":"Reveal phase","description":"Before deadline, bidders reveal actual bid amount. Missing reveal loses the deposit, so countdown UX is critical."},{"label":"Auction close","description":"Highest valid bid wins the name. Second-price rules mean the winner pays one increment above the second-highest bid."},{"label":"Settlement","description":"Winner receives the name registration, losers get deposits back minus gas. Show refund status for non-winners."},{"label":"Registration","description":"After winning, the name follows normal ENS lifecycle. Connect auction outcome to name management in your product."}],"statesToDesign":[{"state":"Ready","trigger":"Prerequisites met.","userNeed":"Understand what happens next.","designResponse":"Enable primary action with plain-language preview."},{"state":"Awaiting signature","trigger":"Wallet prompt open.","userNeed":"Know what they are approving.","designResponse":"Mirror human-readable summary in app and wallet."},{"state":"Pending","trigger":"Transaction submitted.","userNeed":"Confidence it is progressing.","designResponse":"Show status strip with explorer link."},{"state":"Succeeded","trigger":"On-chain confirmation.","userNeed":"See updated ownership or balance.","designResponse":"Celebrate outcome and show new state clearly."},{"state":"Failed or reverted","trigger":"Validation or execution failed.","userNeed":"Fix or retry without guessing.","designResponse":"Name the failed constraint and offer a concrete next step."}],"designDecisions":[{"question":"How much protocol detail do users see?","recommendation":"Lead with outcomes; tuck identifiers behind review.","rationale":"Users decide on consequences, not function selectors."},{"question":"What happens when support is missing?","recommendation":"Block with explanation and fallback path.","rationale":"Silent failure feels like a broken product."},{"question":"How do you label restricted assets?","recommendation":"Use persistent badges for non-transferable, locked, or expiring states.","rationale":"Hidden restrictions cause rage-quits at transfer time."}],"problemsSolved":[{"problem":"Inconsistent behavior across apps","oldWay":"Each team reinvents copy and edge cases","newWay":"Shared standard gives predictable UX patterns","impact":"high"},{"problem":"Users surprised by on-chain rules","oldWay":"Generic transfer UI fails at submit time","newWay":"Standard-aware UI sets expectations upfront","impact":"high"},{"problem":"Support burden from opaque errors","oldWay":"Raw revert reasons in toasts","newWay":"Mapped states explain what to do next","impact":"medium"}],"uxPatterns":[{"name":"Auction Phase Timeline","description":"Visual timeline of bid, reveal, and settlement.","mockup":"concept/nft-gallery","components":["PhaseTimeline","CountdownTimer","PhaseLabel"],"userFlow":["User starts bid","Timeline shows current phase","Countdown to reveal deadline","Settlement shows final price"]},{"name":"Reveal Reminder","description":"Prominent reminder before reveal deadline.","mockup":"concept/verify-safety","components":["RevealBanner","RevealCTA"],"userFlow":["Bid period ends","Reminder appears","User reveals bid","Avoids lost deposit"]}],"seenInTheWild":[{"app":"ENS App","url":"https://app.ens.domains/","note":"Primary interface for .eth name registration and auctions."},{"app":"ENS Vision","url":"https://ens.vision/","note":"Market analytics for ENS name availability and pricing."},{"app":"OpenSea ENS","url":"https://opensea.io/collection/ens","note":"Secondary market for acquired ENS names."}],"antiPatterns":[{"pattern":"Hiding standard-imposed restrictions until submit","why":"Users feel tricked when actions fail at the last step","instead":"Show eligibility and badges before the primary CTA","severity":"critical"},{"pattern":"Protocol jargon in user-facing copy","why":"Non-technical users cannot consent informedly","instead":"Use outcome language with optional technical disclosure","severity":"high"},{"pattern":"No fallback when wallet lacks support","why":"Dead-end flows increase churn","instead":"Explain limitation and offer alternate path or network","severity":"high"}],"vocabulary":[{"use":"Your balance / Your item","avoid":"Token ID / Token contract","why":"Ownership language matches mental models."},{"use":"Cannot transfer yet","avoid":"Transfer reverted","why":"Explain restriction without EVM vocabulary."},{"use":"Confirm in wallet","avoid":"Sign transaction","why":"Matches wallet UX users already know."}],"technicalNotes":"ERC-162 Vickrey auctions require reveal within 48 hours or bids are lost.","relatedStandards":[{"id":"ERC-137","relationship":"Forward resolution for registered names"},{"id":"ERC-181","relationship":"Reverse resolution after registration"}]},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-162","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-162","type":"discussion"},{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-162","type":"official-spec"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-162","markdown":"https://www.eipsfordesigners.com/standards/ERC-162/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-162/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-162","official":"https://eips.ethereum.org/EIPS/erc-162","discussion":"https://ethereum-magicians.org/search?q=ERC-162"},"freshness":{"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25"}},{"id":"EIP-695","name":"eth_chainId Method","status":"Final","chain":"both","category":{"id":"comprehension","name":"Comprehension & Display","description":"Making blockchain data readable to humans"},"journeyStages":[{"id":"discovery","name":"Discovery & Connection","description":"Finding and connecting wallet to dApp"},{"id":"status","name":"Status & Confirmation","description":"Waiting for and confirming outcomes"}],"uxImpact":"Wallets reliably detect which chain they're connected to — prevents transaction replay attacks across chains. Design implications: display current chain prominently in UI, show chain ID in network selector, validate chain consistency before transactions, alert users to chain mismatches. Design decisions: how to handle unknown chain IDs, whether to auto-switch chains or require manual confirmation, prominence of chain indicator (always visible vs on-demand).","hasDetailedContent":true,"content":{"id":"EIP-695","summary":"EIP-695 introduced the eth_chainId RPC method, giving dApps a reliable way to ask \"which network am I connected to?\" Before this, apps had to use net_version which was inconsistent and confusing. Now wallets can clearly tell users \"Connected to Ethereum Mainnet (Chain ID: 1)\" and apps can verify they're on the right network.","applicability":{"whenToUse":["Your product addresses: no reliable way to identify the network.","Your product addresses: apps couldn't verify correct network connection.","The flow should deliver: eth_chainId returns the actual chain ID used in signatures.","Connect flows must list wallets with names, icons, and explicit user choice."],"whenToAvoid":["Always call eth_chainId after wallet connection.","Show both name AND chain ID for verification.","Always use eth_chainId for network identification.","Users never see addresses, amounts, or signing payloads in your UI."]},"designerTakeaways":["You can design UI that delivers eth_chainId returns the actual chain ID used in signatures.","You can design UI that delivers direct query: \"What chain ID is this?\".","You can all wallets use standardized chain ID in the interface."],"problemsSolved":[{"problem":"No reliable way to identify the network","oldWay":"net_version returned network ID which differed from chain ID","newWay":"eth_chainId returns the actual chain ID used in signatures","impact":"critical"},{"problem":"Apps couldn't verify correct network connection","oldWay":"Guess based on other RPC calls, often wrong","newWay":"Direct query: \"What chain ID is this?\"","impact":"high"},{"problem":"Wallet network display was inconsistent","oldWay":"Different wallets showed different identifiers","newWay":"All wallets use standardized chain ID","impact":"high"},{"problem":"Wrong network transactions were common","oldWay":"User thinks they're on mainnet, actually on testnet","newWay":"Apps verify chain ID before any transaction","impact":"medium"}],"uxPatterns":[{"name":"Network Connection Status","description":"Show current network with chain ID verification","mockup":"concept/verify-safety","userFlow":["User connects wallet","App calls eth_chainId","Network name + chain ID displayed","Verification badge shows match","User confident they're on correct network"]},{"name":"Network Verification Gate","description":"Block actions until correct network confirmed","mockup":"concept/verify-safety","userFlow":["App requires specific chain ID","User connected to different chain","Clear comparison shown","One-click switch option","App unblocks after switch"]},{"name":"Network Selector Dropdown","description":"Easy network switching with chain IDs visible","mockup":"concept/verify-safety","userFlow":["User clicks network selector","All available networks shown","Chain ID visible for each","Click to switch","Wallet handles the switch"]}],"uiComponents":[{"name":"ChainIdDisplay","description":"Shows chain ID with optional verification","states":["verified","unverified","mismatch"],"props":["chainId","chainName","showVerification"]},{"name":"NetworkSelector","description":"Dropdown for switching networks","states":["idle","open","switching"],"props":["networks[]","currentChainId","onSelect"]},{"name":"NetworkGate","description":"Blocks UI until correct network selected","states":["blocked","switching","unblocked"],"props":["requiredChainId","currentChainId","onSwitch"]}],"antiPatterns":[{"pattern":"Not verifying chain ID after connection","why":"User might connect on wrong network, lose funds or get errors","instead":"Always call eth_chainId after wallet connection","severity":"critical"},{"pattern":"Only showing network name without chain ID","why":"Malicious RPCs could claim to be mainnet","instead":"Show both name AND chain ID for verification","severity":"high"},{"pattern":"Using net_version instead of eth_chainId","why":"net_version can differ from chain ID used in signatures","instead":"Always use eth_chainId for network identification","severity":"high"},{"pattern":"Silently failing on wrong network","why":"User doesn't know why app isn't working","instead":"Clear \"Please switch to [Network]\" message with action button","severity":"medium"}],"onMonad":[{"aspect":"Monad Chain ID","ethereum":"Mainnet = 1, various L2s have different IDs","monad":"Monad has its own unique chain ID","designImplication":"Add Monad to network selectors with proper chain ID"},{"aspect":"Network Discovery","ethereum":"Popular networks are well-known","monad":"May need \"Add Monad\" helper for new users","designImplication":"Provide easy one-click \"Add Monad Network\" button"},{"aspect":"Multi-Chain Users","ethereum":"Users often switch between L1 and L2s","monad":"Users may switch between Ethereum and Monad frequently","designImplication":"Make network switching prominent and easy"}],"relatedStandards":[{"id":"EIP-155","relationship":"EIP-155 introduced chain ID in signatures, EIP-695 provides the query method"},{"id":"EIP-1344","relationship":"EIP-1344 makes chain ID available to smart contracts via opcode"},{"id":"EIP-1193","relationship":"The provider API through which eth_chainId is called"}]},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-695","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=EIP-695","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/EIP-695","markdown":"https://www.eipsfordesigners.com/standards/EIP-695/content.md","agent":"https://www.eipsfordesigners.com/standards/EIP-695/agent.md","api":"https://www.eipsfordesigners.com/api/standards/EIP-695","official":"https://eips.ethereum.org/EIPS/eip-695","discussion":"https://ethereum-magicians.org/search?q=EIP-695"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"ERC-1046","name":"Token Metadata","status":"Final","chain":"both","category":{"id":"comprehension","name":"Comprehension & Display","description":"Making blockchain data readable to humans"},"journeyStages":[{"id":"asset-display","name":"Asset Discovery & Display","description":"Seeing tokens, NFTs, and balances"}],"uxImpact":"ERC-20 tokens get rich metadata like NFTs — icons, descriptions, and images without manual token list curation. Design implications: fetch and display token images/icons from tokenURI, show descriptions in token detail views, support interop field to identify token type, handle missing/broken metadata gracefully. Design decisions: trust level for fetched metadata (SSRF risks), caching strategy for metadata, fallback displays when tokenURI fails, whether to prefer on-chain name() or metadata name.","hasDetailedContent":true,"content":{"id":"ERC-1046","summary":"ERC-1046 standardizes how tokens expose metadata—name, symbol, decimals, icon, description, and more via a URI. Instead of hardcoding token info or relying on centralized lists, wallets can fetch rich metadata directly from the token contract. This enables consistent branding, reduces reliance on token lists, and ensures users always see up-to-date token information.","applicability":{"whenToUse":["Your product addresses: token info depends on centralized token lists.","Your product addresses: fake tokens can impersonate real ones.","The flow should deliver: token contract points to authoritative metadata.","You are designing a rich token display experience with visible states and recovery paths."],"whenToAvoid":["Cross-reference with known contracts, show verification status.","Visual distinction: verified badge, warning for unknown.","Cache with reasonable TTL, refresh periodically.","Users never see addresses, amounts, or signing payloads in your UI."]},"designerTakeaways":["You can design UI that delivers token contract points to authoritative metadata.","You can design UI that delivers metadata URI verifiable from contract address.","You can standard icon field in metadata JSON."],"problemsSolved":[{"problem":"Token info depends on centralized token lists","oldWay":"Wallet fetches name/icon from Coingecko or static lists","newWay":"Token contract points to authoritative metadata","impact":"high"},{"problem":"Fake tokens can impersonate real ones","oldWay":"Scam token shows same name/symbol, users confused","newWay":"Metadata URI verifiable from contract address","impact":"high"},{"problem":"No standard way to include token icons","oldWay":"Icon lookup varies by wallet, often missing","newWay":"Standard icon field in metadata JSON","impact":"medium"},{"problem":"Token descriptions aren't available on-chain","oldWay":"Users must search externally to understand token","newWay":"Description in metadata, shown in wallet","impact":"medium"},{"problem":"Updating token info requires list maintainer action","oldWay":"Submit PR to token list, wait for merge","newWay":"Project updates their metadata URI directly","impact":"medium"}],"uxPatterns":[{"name":"Rich Token Display","description":"Show complete token info from metadata","mockup":"concept/nft-gallery","userFlow":["User taps on token in wallet","Wallet fetches tokenURI from contract","Parses JSON metadata","Displays rich token information","Shows verification that data is from contract"]},{"name":"Token Discovery with Metadata","description":"Add new tokens with auto-fetched info","mockup":"concept/nft-gallery","userFlow":["User pastes token address","Wallet checks for tokenURI function","Fetches and parses metadata","Shows preview with verification status","User adds token with confidence"]},{"name":"Scam Token Warning","description":"Detect potential impersonation attempts","mockup":"concept/nft-gallery","userFlow":["Token appears in wallet/dApp","Metadata claims to be known token","Contract address doesn't match","Clear warning displayed","Options to block or report"]},{"name":"Balance Display with Branding","description":"Token list with proper logos and info","mockup":"concept/nft-gallery","userFlow":["Wallet loads token balances","Fetches metadata for each token","Displays logo from metadata or placeholder","Shows verification status per token","Users can identify trusted vs unknown"]}],"uiComponents":[{"name":"TokenMetadataFetcher","description":"Fetch and parse token metadata from URI","states":["idle","fetching","parsed","error","no-metadata"],"props":["contractAddress","onMetadata","fallback"]},{"name":"TokenLogo","description":"Display token icon from metadata","states":["loading","loaded","fallback","error"],"props":["uri","symbol","size"]},{"name":"MetadataVerificationBadge","description":"Show metadata source and trust level","states":["verified","from-contract","from-list","unknown","suspicious"],"props":["source","contractAddress"]},{"name":"TokenDescription","description":"Expandable token description display","states":["collapsed","expanded","no-description"],"props":["description","maxLength"]}],"antiPatterns":[{"pattern":"Trusting metadata without verification","why":"Scam tokens can claim any name/logo","instead":"Cross-reference with known contracts, show verification status","severity":"critical"},{"pattern":"Showing unknown tokens same as verified ones","why":"Users can't distinguish trusted from suspicious","instead":"Visual distinction: verified badge, warning for unknown","severity":"critical"},{"pattern":"Not caching metadata","why":"Slow/expensive to fetch metadata on every view","instead":"Cache with reasonable TTL, refresh periodically","severity":"high"},{"pattern":"Hiding token contract address","why":"Address is ultimate source of truth","instead":"Always show contract address with easy copy","severity":"medium"},{"pattern":"Not handling missing metadata gracefully","why":"Many tokens won't have ERC-1046 metadata","instead":"Graceful fallback to on-chain name/symbol or \"Unknown\"","severity":"medium"}],"onMonad":[{"aspect":"Metadata Fetching","ethereum":"Fetching metadata may be slow if URI is on-chain","monad":"Fast reads for on-chain metadata URIs","designImplication":"Can fetch metadata in real-time without lag"},{"aspect":"Token Discovery","ethereum":"Indexing all tokens with metadata is slow","monad":"Faster indexing enables better token discovery","designImplication":"Can show \"all tokens with metadata\" views"},{"aspect":"Verification","ethereum":"Cross-referencing takes RPC calls","monad":"Fast verification checks","designImplication":"Real-time scam detection as tokens appear"},{"aspect":"New Token Support","ethereum":"Must wait for token list updates","monad":"Direct metadata enables instant new token support","designImplication":"New Monad tokens immediately show branding"}],"keyTakeaways":["ERC-1046 = standard way for tokens to expose metadata","Always verify metadata against contract address","Show clear distinction between verified and unknown tokens","Cache metadata but refresh periodically","On Monad: leverage fast reads for real-time metadata fetching"],"technicalNotes":"ERC-1046 adds a tokenURI() function returning a URI pointing to JSON metadata. The JSON follows a schema including: name, symbol, decimals, description, image (logo), external_url, and optional social links. This is similar to ERC-721/1155 metadata but for fungible tokens. Wallets should cache and periodically refresh metadata."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-1046","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-1046","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-1046","markdown":"https://www.eipsfordesigners.com/standards/ERC-1046/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-1046/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-1046","official":"https://eips.ethereum.org/EIPS/eip-1046","discussion":"https://ethereum-magicians.org/search?q=ERC-1046"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"ERC-6093","name":"Custom Errors for Common Tokens","status":"Final","chain":"both","category":{"id":"comprehension","name":"Comprehension & Display","description":"Making blockchain data readable to humans"},"journeyStages":[{"id":"reading","name":"Reading & Understanding","description":"Interpreting what you're being asked to do"}],"uxImpact":"Token errors become specific and actionable — 'Insufficient balance: have 50, need 100' instead of generic 'transfer failed'. Design implications: parse custom errors to show precise failure reasons, display relevant values (balances, allowances) in error messages, suggest fixes inline (e.g., 'Approve more tokens'). Design decisions: which error details to expose to users vs log internally, how to present technical info accessibly, fallback handling for non-standard errors, translating error codes to user-friendly language. Addresses the Blanket Warnings pain point (Medium severity, Unsolved) — identical warnings for routine and catastrophic actions train users to ignore all alerts. ERC-6093 enables contextual, specific error messages.","hasDetailedContent":true,"content":{"id":"ERC-6093","summary":"ERC-6093 standardizes error messages for tokens. Instead of \"execution reverted\", you get \"ERC20InsufficientBalance: have 5 USDC, need 10 USDC\". Human-readable errors that explain exactly what went wrong and often how to fix it. This transforms cryptic failures into actionable feedback.","applicability":{"whenToUse":["Your product addresses: error messages are unhelpful hex or generic text.","Your users don't know how to fix failed transactions.","The flow should deliver: \"ERC20InsufficientBalance(sender, balance, needed)\".","You are designing a actionable error message experience with visible states and recovery paths."],"whenToAvoid":["Decode and display human message.","Parse error, show specific reason.","Offer actions: \"Approve more\" or \"Get tokens\".","Users never see addresses, amounts, or signing payloads in your UI."]},"designerTakeaways":["You can design UI that delivers \"ERC20InsufficientBalance(sender, balance, needed)\".","You can design UI that delivers \"Need 10 more USDC. Current balance: 5 USDC\".","You can standard error signatures work everywhere."],"problemsSolved":[{"problem":"Error messages are unhelpful hex or generic text","oldWay":"\"execution reverted\" or \"0x4e487b71...\"","newWay":"\"ERC20InsufficientBalance(sender, balance, needed)\"","impact":"critical"},{"problem":"Users don't know how to fix failed transactions","oldWay":"\"Transaction failed. Try again?\" (why?)","newWay":"\"Need 10 more USDC. Current balance: 5 USDC\"","impact":"critical"},{"problem":"Each token had different error formats","oldWay":"Parse custom errors for each protocol","newWay":"Standard error signatures work everywhere","impact":"high"}],"uxPatterns":[{"name":"Actionable Error Message","description":"Clear error with solution","mockup":"concept/verify-safety","userFlow":["Transaction reverts with custom error","App decodes error using ERC-6093 ABI","Extracts balance, needed amount","Shows clear comparison","Offers ways to resolve"]},{"name":"Approval Error","description":"Handle insufficient allowance clearly","mockup":"generic/token-approval","userFlow":["Swap fails with allowance error","Decode ERC20InsufficientAllowance","Show current vs needed","One-click approve more","Retry original action"]}],"uiComponents":[{"name":"ErrorDecoder","description":"Parses ERC-6093 errors into readable format","states":["parsing","decoded","unknown"],"props":["errorData","onDecode"]},{"name":"BalanceErrorCard","description":"Shows balance shortfall with context","states":["insufficient-balance","insufficient-allowance"],"props":["have","need","token","actionSuggestions"]},{"name":"ErrorRecoveryActions","description":"Buttons to resolve the error","states":["ready","resolving","resolved"],"props":["actions[]","onAction"]}],"antiPatterns":[{"pattern":"Showing raw error hex to users","why":"\"0x4e487b71...\" means nothing","instead":"Decode and display human message","severity":"critical"},{"pattern":"Generic \"Transaction failed\" without details","why":"User has no idea what went wrong","instead":"Parse error, show specific reason","severity":"critical"},{"pattern":"No recovery suggestions","why":"User stuck, doesn't know next step","instead":"Offer actions: \"Approve more\" or \"Get tokens\"","severity":"high"}],"onMonad":[{"aspect":"Error Format","ethereum":"ERC-6093 custom errors standard","monad":"Same error format, works identically","designImplication":"Same error handling code works"}],"keyTakeaways":["ERC-6093 = human-readable token errors","Always decode errors, never show raw hex","Show what user has vs what they need","Offer clear recovery actions","Common errors: InsufficientBalance, InsufficientAllowance"],"technicalNotes":"ERC-6093 defines custom errors: ERC20InsufficientBalance(sender, balance, needed), ERC20InsufficientAllowance(spender, allowance, needed), ERC721InsufficientApproval(operator, tokenId), etc. Decode using error selector (first 4 bytes) and ABI decode parameters. OpenZeppelin contracts v5+ use these errors."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-6093","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-6093","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-6093","markdown":"https://www.eipsfordesigners.com/standards/ERC-6093/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-6093/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-6093","official":"https://eips.ethereum.org/EIPS/eip-6093","discussion":"https://ethereum-magicians.org/search?q=ERC-6093"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"ERC-7751","name":"Wrapping of Bubbled Up Reverts","status":"Draft","chain":"both","category":{"id":"comprehension","name":"Comprehension & Display","description":"Making blockchain data readable to humans"},"journeyStages":[{"id":"reading","name":"Reading & Understanding","description":"Interpreting what you're being asked to do"}],"uxImpact":"Nested contract call failures show full error chain — see exactly which contract in a multi-hop transaction failed and why. Design implications: display error stack traces for complex transactions, show failing contract address and function, preserve original error context through wrapping, visualize call hierarchy. Design decisions: depth of error chain to display (can get verbose), technical vs simplified error presentation, whether to show intermediate contract addresses, integration with block explorers for debugging. Complements ERC-6093 for the same Blanket Warnings problem — preserves error context through nested contract calls so users see 'Swap failed: insufficient liquidity' instead of generic reverts.","hasDetailedContent":true,"content":{"id":"ERC-7751","summary":"ERC-7751 standardizes wrapping of error types, enabling nested errors with full context about what went wrong and why. Instead of \"execution reverted\", users see \"Swap failed: insufficient liquidity in pool (needed 100 ETH, available 50 ETH)\". Errors chain together to tell the complete story.","applicability":{"whenToUse":["Your product addresses: error messages lose context as they propagate.","Your users can't take action on vague errors.","The flow should deliver: full error chain: \"Swap failed → Pool error → Insufficient liquidity\".","You are designing a contextual error display experience with visible states and recovery paths."],"whenToAvoid":["Translate to human-readable: \"Insufficient liquidity\".","Show friendly message + expandable technical details.","Parse error type, suggest specific resolution.","Users never see addresses, amounts, or signing payloads in your UI."]},"designerTakeaways":["You can design UI that delivers full error chain: \"Swap failed → Pool error → Insufficient liquidity\".","You can design UI that delivers \"Approval expired 2 minutes ago, please approve again\".","You can design UI that delivers error shows exact step that failed and why."],"problemsSolved":[{"problem":"Error messages lose context as they propagate","oldWay":"\"execution reverted\" - no idea what failed or why","newWay":"Full error chain: \"Swap failed → Pool error → Insufficient liquidity\"","impact":"critical"},{"problem":"Users can't take action on vague errors","oldWay":"\"Transaction failed\" - what should user do?","newWay":"\"Approval expired 2 minutes ago - please approve again\"","impact":"critical"},{"problem":"Debugging requires guessing what went wrong","oldWay":"Trial and error, check each step manually","newWay":"Error shows exact step that failed and why","impact":"high"},{"problem":"Different contracts return different error formats","oldWay":"Parse error differently for each protocol","newWay":"Standard wrapping format enables consistent parsing","impact":"medium"}],"uxPatterns":[{"name":"Contextual Error Display","description":"Show error with full context chain","mockup":"concept/verify-safety","userFlow":["Transaction fails","Parse wrapped error chain","Display hierarchy of what failed","Extract actionable suggestion","Offer relevant next steps"]},{"name":"Approval Expiry Error","description":"Handle common approval-related failures","mockup":"generic/token-approval","userFlow":["Swap fails with approval error","Parse to find root cause","Show specific approval issue","One-click re-approve action","Suggest prevention for future"]},{"name":"Multi-Step Error Tracing","description":"Show which step in a batch failed","mockup":"generic/token-approval","userFlow":["Multi-step batch fails mid-way","Identify which step failed","Show completed vs failed vs skipped","Explain root cause from error","Offer fix for specific failure"]},{"name":"Developer Debug View","description":"Technical error details for power users","mockup":"concept/verify-safety","userFlow":["User clicks \"Show details\"","Display full technical error chain","Show contract addresses and selectors","Allow copy for bug reports","Link to transaction explorer"]}],"uiComponents":[{"name":"ErrorChainDisplay","description":"Nested display of wrapped errors","states":["collapsed","expanded","highlighted"],"props":["errors[]","onExpand","highlightRoot"]},{"name":"ActionableError","description":"Error with suggested resolution action","states":["error","suggesting","resolving"],"props":["error","suggestion","action","onAction"]},{"name":"BatchStepIndicator","description":"Show progress through batch with failure point","states":["pending","success","failed","skipped"],"props":["steps[]","failedStep","errorDetail"]},{"name":"TechnicalErrorView","description":"Developer-focused error details","states":["collapsed","expanded"],"props":["error","contract","selector","params"]}],"antiPatterns":[{"pattern":"Showing raw error selector codes","why":"\"0x4e487b71\" means nothing to users","instead":"Translate to human-readable: \"Insufficient liquidity\"","severity":"critical"},{"pattern":"Hiding error details entirely","why":"Power users need details for debugging","instead":"Show friendly message + expandable technical details","severity":"high"},{"pattern":"No suggested actions","why":"User sees error but doesn't know what to do","instead":"Parse error type, suggest specific resolution","severity":"high"},{"pattern":"Losing nested error context","why":"Root cause hidden, only surface error shown","instead":"Preserve and display full error chain","severity":"medium"}],"onMonad":[{"aspect":"Error Introspection","ethereum":"Limited error detail available","monad":"Enhanced error introspection in EVM","designImplication":"Can show more detailed error context on Monad"},{"aspect":"Retry Speed","ethereum":"Retry takes 15+ seconds to confirm","monad":"Sub-second retry confirmation","designImplication":"Retry buttons can show instant feedback"},{"aspect":"Simulation","ethereum":"Simulation to check errors is expensive","monad":"Cheap simulation for pre-flight checks","designImplication":"Can simulate before sending, catch errors earlier"},{"aspect":"Reserve-Related Errors","ethereum":"N/A","monad":"New error type: InsufficientSpendableBalance","designImplication":"Handle Monad-specific reserve errors gracefully"}],"keyTakeaways":["Wrapped errors tell the complete story of what went wrong","Always translate technical errors to human-readable messages","Provide specific, actionable suggestions based on error type","Show error chain hierarchy for transparency","On Monad: better error introspection + reserve balance errors"],"technicalNotes":"ERC-7751 defines a WrappedError structure that contains an inner error plus context. Contracts use try/catch to wrap lower-level errors with higher-level context. The standard defines encoding/decoding for error chains. Frontends parse the chain to extract the root cause and each layer of context."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-7751","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-7751","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-7751","markdown":"https://www.eipsfordesigners.com/standards/ERC-7751/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-7751/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-7751","official":"https://eips.ethereum.org/EIPS/eip-7751","discussion":"https://ethereum-magicians.org/search?q=ERC-7751"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"EIP-2718","name":"Typed Transaction Envelope","status":"Final","chain":"both","category":{"id":"comprehension","name":"Comprehension & Display","description":"Making blockchain data readable to humans"},"journeyStages":[{"id":"status","name":"Status & Confirmation","description":"Waiting for and confirming outcomes"}],"uxImpact":"Different transaction types (legacy, EIP-1559, EIP-4844 blobs) coexist seamlessly — users don't need to understand encoding differences. Design implications: abstract transaction type complexity from users, show relevant fields per type (maxFeePerGas vs gasPrice), indicate transaction type in history views for debugging. Design decisions: whether to expose transaction type in UI at all, how to handle wallets that don't support newer types, default type selection logic, backwards compatibility messaging.","hasDetailedContent":true,"content":{"id":"EIP-2718","summary":"EIP-2718 introduced typed transaction envelopes - a way to define different transaction formats. Instead of one transaction format forever, new types can be added: Type 0 (legacy), Type 1 (access lists), Type 2 (EIP-1559), Type 4 (EIP-7702). Wallets show different UIs based on transaction type, and the ecosystem can evolve without breaking old transactions.","applicability":{"whenToUse":["Your product addresses: no way to add new transaction features.","Your product addresses: backwards compatibility concerns.","The flow should deliver: new transaction types can be added (Type 2, Type 4, etc.).","You are designing a transaction type indicator experience with visible states and recovery paths."],"whenToAvoid":["Default to Type 2 unless compatibility requires legacy.","Show type badge with brief explanation.","Type-specific gas inputs and explanations.","Users never see addresses, amounts, or signing payloads in your UI."]},"designerTakeaways":["You can design UI that delivers new transaction types can be added (Type 2.","You can design UI that delivers old types still work, new types opt-in.","You can design UI that delivers type byte tells wallets how to parse and display."],"problemsSolved":[{"problem":"No way to add new transaction features","oldWay":"Transaction format was fixed, new features impossible","newWay":"New transaction types can be added (Type 2, Type 4, etc.)","impact":"critical"},{"problem":"Backwards compatibility concerns","oldWay":"Changing tx format would break everything","newWay":"Old types still work, new types opt-in","impact":"high"},{"problem":"No context for transaction interpretation","oldWay":"All transactions looked the same","newWay":"Type byte tells wallets how to parse and display","impact":"high"},{"problem":"Gas pricing couldn't evolve","oldWay":"Single gas price field forever","newWay":"Type 2 added base fee + priority fee via new format","impact":"high"}],"uxPatterns":[{"name":"Transaction Type Indicator","description":"Show users which transaction type they're signing","mockup":"concept/gas-abstraction","userFlow":["User initiates transaction","Wallet detects/selects transaction type","Type-specific UI shown","User sees relevant gas options","Confirms with full context"]},{"name":"Legacy vs Modern Transaction Choice","description":"Let users choose transaction type when relevant","mockup":"concept/gas-abstraction","userFlow":["User opens advanced settings","Transaction types explained","Recommendation highlighted","User selects appropriate type","Type determines gas UI"]},{"name":"Transaction History by Type","description":"Filter and view transactions by type","mockup":"concept/gas-abstraction","userFlow":["User views transaction history","Each tx shows its type","Can filter by type","Understand different tx behaviors"]},{"name":"EIP-7702 Transaction","description":"Special UI for account upgrade transactions","mockup":"generic/instant-confirm","userFlow":["User enables smart wallet","Type 4 transaction created","Features explained clearly","Address confirmation shown","Upgrade executed"]}],"uiComponents":[{"name":"TransactionTypeBadge","description":"Visual indicator of transaction type","states":["type-0","type-1","type-2","type-4"],"props":["type","showName","showDescription"]},{"name":"TypeSpecificGasUI","description":"Gas settings appropriate for transaction type","states":["legacy","eip1559","eip7702"],"props":["type","gasParams","onChange"]},{"name":"TransactionTypeSelector","description":"Advanced option to choose transaction type","states":["collapsed","expanded"],"props":["availableTypes[]","selected","onSelect","recommendation"]}],"antiPatterns":[{"pattern":"Hiding transaction type from users","why":"Users can't understand why gas UI differs","instead":"Show type badge with brief explanation","severity":"medium"},{"pattern":"Using legacy (Type 0) by default","why":"Misses EIP-1559 benefits, wastes user money","instead":"Default to Type 2 unless compatibility requires legacy","severity":"high"},{"pattern":"Same gas UI for all types","why":"Type 2 has different fields than Type 0","instead":"Type-specific gas inputs and explanations","severity":"medium"},{"pattern":"Not explaining new transaction types","why":"Users confused by Type 4 (7702) when it appears","instead":"Clear explanation of what new types enable","severity":"medium"}],"onMonad":[{"aspect":"Transaction Type Support","ethereum":"Types 0, 1, 2, 4 all supported","monad":"Monad supports the same transaction types","designImplication":"Same type-based UI works on Monad"},{"aspect":"EIP-1559 on Monad","ethereum":"Type 2 widely used for predictable fees","monad":"Type 2 works but fees already very low","designImplication":"Still recommend Type 2 for consistency"},{"aspect":"EIP-7702 Benefits","ethereum":"Type 4 for smart wallet upgrades","monad":"Same benefits plus faster execution","designImplication":"Encourage Type 4 adoption for smart wallet features"}],"relatedStandards":[{"id":"EIP-1559","relationship":"EIP-1559 introduced Type 2 transactions via EIP-2718"},{"id":"EIP-7702","relationship":"EIP-7702 introduced Type 4 transactions for account upgrades"},{"id":"EIP-658","relationship":"Transaction receipts include type for proper parsing"},{"id":"EIP-155","relationship":"Chain ID included in typed transaction encoding"}]},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-2718","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=EIP-2718","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/EIP-2718","markdown":"https://www.eipsfordesigners.com/standards/EIP-2718/content.md","agent":"https://www.eipsfordesigners.com/standards/EIP-2718/agent.md","api":"https://www.eipsfordesigners.com/api/standards/EIP-2718","official":"https://eips.ethereum.org/EIPS/eip-2718","discussion":"https://ethereum-magicians.org/search?q=EIP-2718"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"EIP-2124","name":"Fork Identifier","status":"Final","chain":"both","category":{"id":"comprehension","name":"Comprehension & Display","description":"Making blockchain data readable to humans"},"journeyStages":[{"id":"status","name":"Status & Confirmation","description":"Waiting for and confirming outcomes"}],"uxImpact":"Nodes quickly identify compatible peers — faster sync, no wasted connections to wrong networks (ETH vs ETC). Design implications: mostly invisible to end users but affects sync progress UIs, show network compatibility status in node dashboards, display fork identifier in developer tools. Design decisions: how to surface peer compatibility issues to users running nodes, whether to show 'searching for peers' vs specific incompatibility reasons, handling stale nodes gracefully.","hasDetailedContent":true,"content":{"id":"EIP-2124","summary":"EIP-2124 introduced fork identifiers - a way for nodes to quickly check if they're compatible with each other. The fork ID combines the chain's genesis hash with activated fork block numbers. This lets nodes immediately know \"we're on the same chain and have the same upgrades\" without exchanging lots of data.","applicability":{"whenToUse":["Your product addresses: nodes couldn't quickly verify compatibility.","Your product addresses: network partitions after hard forks.","The flow should deliver: fork ID comparison in initial handshake.","You are designing a network upgrade status experience with visible states and recovery paths."],"whenToAvoid":["Warn when connected to incompatible RPC.","Show upgrade countdown with feature summary.","Show fork name (Shanghai) with ID as technical detail.","Users never see addresses, amounts, or signing payloads in your UI."]},"designerTakeaways":["You can design UI that delivers fork ID comparison in initial handshake.","You can design UI that delivers nodes disconnect immediately if fork IDs don't match.","You can design UI that delivers mismatch detected at connection time."],"problemsSolved":[{"problem":"Nodes couldn't quickly verify compatibility","oldWay":"Exchange full chain history to detect incompatibility","newWay":"Fork ID comparison in initial handshake","impact":"high"},{"problem":"Network partitions after hard forks","oldWay":"Incompatible nodes stayed connected, causing issues","newWay":"Nodes disconnect immediately if fork IDs don't match","impact":"high"},{"problem":"Difficult to detect wrong network connections","oldWay":"Errors occurred deep in sync process","newWay":"Mismatch detected at connection time","impact":"medium"},{"problem":"Post-fork network confusion","oldWay":"Old nodes confused new nodes and vice versa","newWay":"Clean separation of incompatible networks","impact":"medium"}],"uxPatterns":[{"name":"Network Upgrade Status","description":"Show users current network fork status","mockup":"concept/verify-safety","userFlow":["User checks network status","Current fork name and ID displayed","Historical upgrades shown","Upcoming upgrades if scheduled","User understands network state"]},{"name":"Node Compatibility Warning","description":"Alert when connecting to incompatible node","mockup":"concept/verify-safety","userFlow":["dApp connects to RPC","Fork ID mismatch detected","Warning shown to user","Explanation of the issue","Option to switch RPC"]},{"name":"Upgrade Countdown","description":"Show upcoming network upgrades","mockup":"concept/verify-safety","userFlow":["Upcoming upgrade detected","Countdown displayed to users","New features explained","Users informed before changes"]}],"uiComponents":[{"name":"ForkIdDisplay","description":"Shows current fork identifier","states":["synced","syncing","outdated"],"props":["forkId","forkName","blockNumber"]},{"name":"UpgradeTimeline","description":"Visual timeline of network upgrades","states":["loading","loaded"],"props":["upgrades[]","currentBlock","onSelect"]},{"name":"CompatibilityCheck","description":"Shows node/RPC compatibility status","states":["compatible","incompatible","checking"],"props":["localForkId","remoteForkId","onSwitch"]}],"antiPatterns":[{"pattern":"Ignoring fork ID mismatches","why":"User may see incorrect data or failed transactions","instead":"Warn when connected to incompatible RPC","severity":"high"},{"pattern":"Not informing users about upcoming upgrades","why":"Users surprised when things change","instead":"Show upgrade countdown with feature summary","severity":"medium"},{"pattern":"Showing raw fork ID without context","why":"0xdce96c2d means nothing to users","instead":"Show fork name (Shanghai) with ID as technical detail","severity":"low"}],"onMonad":[{"aspect":"Monad Fork Schedule","ethereum":"Upgrades happen roughly yearly","monad":"Monad may have its own upgrade schedule","designImplication":"Track Monad-specific fork IDs and upgrade timeline"},{"aspect":"Fork ID Format","ethereum":"Based on genesis + fork blocks","monad":"Same format, Monad-specific values","designImplication":"Use Monad genesis and fork data for ID calculation"},{"aspect":"Node Compatibility","ethereum":"Many public RPCs with varying update speeds","monad":"Ensure RPC providers stay updated with Monad forks","designImplication":"Verify RPC fork ID matches expected Monad fork"}],"relatedStandards":[{"id":"EIP-155","relationship":"Chain ID identifies the chain, fork ID identifies the fork state"},{"id":"EIP-695","relationship":"eth_chainId returns chain ID, separate from fork ID"}]},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-2124","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=EIP-2124","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/EIP-2124","markdown":"https://www.eipsfordesigners.com/standards/EIP-2124/content.md","agent":"https://www.eipsfordesigners.com/standards/EIP-2124/agent.md","api":"https://www.eipsfordesigners.com/api/standards/EIP-2124","official":"https://eips.ethereum.org/EIPS/eip-2124","discussion":"https://ethereum-magicians.org/search?q=EIP-2124"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"ERC-4804","name":"Web3 URL to EVM Call","status":"Final","chain":"both","category":{"id":"comprehension","name":"Comprehension & Display","description":"Making blockchain data readable to humans"},"journeyStages":[{"id":"specialized","name":"Specialized Interactions","description":"Physical items, AI, social, gaming"}],"uxImpact":"Access blockchain data via URLs like 'web3://uniswap.eth/swap' — browsers can render on-chain content directly. Design implications: support web3:// URL scheme in address bars, display on-chain HTML/SVG content natively, show ENS-based URLs alongside traditional links, handle cross-chain URLs with chainid syntax. Design decisions: security model for executing on-chain content, how to display web3:// URLs to users unfamiliar with the concept, fallback when content fails to load, gateway vs native resolution.","hasDetailedContent":true,"content":{"id":"ERC-4804","summary":"ERC-4804 creates a standard URL format for accessing blockchain data directly from a browser. Type \"web3://uniswap.eth/swap\" and your browser fetches content from the blockchain instead of a web server. This enables truly decentralized frontends where the UI itself lives on-chain, eliminating server dependencies and censorship risks.","applicability":{"whenToUse":["Your product addresses: dApp frontends are centralized and can be taken down.","Your product addresses: no standard way to link to on-chain content.","The flow should deliver: uI served from blockchain, censorship-resistant like the contracts.","You are designing a web3 url bar experience with visible states and recovery paths."],"whenToAvoid":["Always provide HTTPS gateway link as alternative.","Show clear badge: \"Served from Ethereum\" or similar.","Show loading progress with chain/contract info.","Users never see addresses, amounts, or signing payloads in your UI."]},"designerTakeaways":["You can design UI that delivers uI served from blockchain.","You can design UI that delivers share web3://contract.eth/path like any normal URL.","You can design UI that delivers click a link, browser handles the blockchain query."],"problemsSolved":[{"problem":"dApp frontends are centralized and can be taken down","oldWay":"Frontend hosted on AWS/Vercel, smart contract decentralized but UI isn't","newWay":"UI served from blockchain, censorship-resistant like the contracts","impact":"critical"},{"problem":"No standard way to link to on-chain content","oldWay":"Share contract address + instructions to call specific functions","newWay":"Share web3://contract.eth/path like any normal URL","impact":"high"},{"problem":"Reading blockchain data requires developer knowledge","oldWay":"Use Etherscan, understand ABI, manually call functions","newWay":"Click a link, browser handles the blockchain query","impact":"high"},{"problem":"ENS names can't serve actual content","oldWay":"ENS resolves to address, still need separate frontend","newWay":"web3://vitalik.eth serves actual webpage from blockchain","impact":"medium"}],"uxPatterns":[{"name":"Web3 URL Bar","description":"Browser or extension interprets web3:// URLs","mockup":"concept/physical-link","userFlow":["User types or clicks web3:// URL","Browser/extension parses URL","Makes EVM call to specified contract","Contract returns HTML/JSON/binary content","Browser renders the response","Shows decentralized origin badge"]},{"name":"Decentralized App Page","description":"Full dApp UI served from smart contract","mockup":"concept/physical-link","userFlow":["User visits web3:// URL","Full HTML/CSS/JS loaded from contract","Interactive UI rendered in browser","User interacts with dApp","Transactions submitted normally","UI cannot be censored or modified"]},{"name":"On-Chain Resource Link","description":"Share links to specific on-chain data","mockup":"concept/nft-gallery","userFlow":["User wants to share on-chain content","App generates web3:// URL","Also provides HTTPS gateway fallback","Recipient clicks link","Content loads from blockchain","Works even if original site is down"]},{"name":"ENS Content Resolution","description":"ENS names that serve actual web content","mockup":"concept/physical-link","userFlow":["User owns ENS name","Configure content resolver","Point to on-chain contract","Contract implements web3:// interface","web3://name.eth serves that content","Visitors see decentralized website"]}],"uiComponents":[{"name":"Web3UrlInput","description":"Input field for web3:// URLs with validation","states":["empty","typing","valid","invalid","loading"],"props":["value","onChange","onNavigate","showChain"]},{"name":"DecentralizedBadge","description":"Indicates content is served from blockchain","states":["verified","gateway","hybrid"],"props":["chain","contract","contentType"]},{"name":"Web3ContentFrame","description":"Renders content fetched from on-chain","states":["loading","loaded","error","unsupported"],"props":["url","sandbox","onLoad","onError"]},{"name":"GatewayFallback","description":"HTTPS gateway link for non-web3 browsers","states":["available","generating","copied"],"props":["web3Url","gatewayDomain","onCopy"]}],"antiPatterns":[{"pattern":"Only supporting web3:// without gateway fallback","why":"Most users don't have web3:// capable browsers","instead":"Always provide HTTPS gateway link as alternative","severity":"critical"},{"pattern":"Not indicating content source","why":"Users don't know if content is decentralized or traditional","instead":"Show clear badge: \"Served from Ethereum\" or similar","severity":"high"},{"pattern":"Slow-loading on-chain content without progress","why":"Users think page is broken","instead":"Show loading progress with chain/contract info","severity":"high"},{"pattern":"Mixing centralized and decentralized content silently","why":"False sense of decentralization security","instead":"Clearly mark which parts are on-chain vs off-chain","severity":"medium"},{"pattern":"Using web3:// URLs without explaining the benefit","why":"Users don't understand why they should use unfamiliar URLs","instead":"Explain: \"This link works forever, even if we disappear\"","severity":"medium"}],"onMonad":[{"aspect":"Content Loading Speed","ethereum":"On-chain content can take 5-15 seconds to load","monad":"Sub-second content delivery","designImplication":"Web3 URLs feel as fast as traditional websites"},{"aspect":"Dynamic Content","ethereum":"Real-time data queries are slow and expensive","monad":"Live data updates feasible","designImplication":"Can build more interactive on-chain UIs"},{"aspect":"Storage Costs","ethereum":"Storing UI on-chain is very expensive","monad":"Lower costs make larger on-chain UIs practical","designImplication":"More comprehensive dApps can go fully on-chain"},{"aspect":"Contract Calls","ethereum":"Multiple calls to render page are slow","monad":"Parallel execution speeds multi-call pages","designImplication":"Complex pages with many data sources still fast"}],"keyTakeaways":["ERC-4804 = URLs that fetch content from blockchain","web3://name.eth/path like normal URLs but decentralized","Always provide HTTPS gateway fallback for compatibility","Show clear indicators when content is served from chain","On Monad: fast enough for interactive on-chain UIs"],"technicalNotes":"ERC-4804 defines the web3:// URL scheme that maps to EVM calls. The URL format is web3://contract.eth/path?query. The browser translates this to a call to the contract's resolve(path, query) function which returns MIME type and content. Supports both human-readable (ENS) and hex addresses. Works with ERC-5219 for more complex contract resource serving."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-4804","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-4804","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-4804","markdown":"https://www.eipsfordesigners.com/standards/ERC-4804/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-4804/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-4804","official":"https://eips.ethereum.org/EIPS/eip-4804","discussion":"https://ethereum-magicians.org/search?q=ERC-4804"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"ERC-5219","name":"Contract Resource Requests","status":"Final","chain":"both","category":{"id":"comprehension","name":"Comprehension & Display","description":"Making blockchain data readable to humans"},"journeyStages":[{"id":"specialized","name":"Specialized Interactions","description":"Physical items, AI, social, gaming"}],"uxImpact":"Smart contracts serve web content directly — fully decentralized frontends without centralized hosting. Design implications: render contract-served HTML/CSS/JS in app frames, show content source (contract address), handle HTTP-like status codes and redirects from contracts. Design decisions: sandboxing/security for contract-served content, performance expectations vs traditional hosting, how to indicate decentralized vs centralized content to users, caching strategies for immutable content.","hasDetailedContent":true,"content":{"id":"ERC-5219","summary":"ERC-5219 defines how smart contracts can serve web resources like a traditional web server. A contract can respond to resource requests with HTML, CSS, JavaScript, images, or any content type. Combined with ERC-4804's web3:// URLs, this enables fully decentralized websites where the entire frontend lives on the blockchain, immune to takedowns and censorship.","applicability":{"whenToUse":["Your product addresses: smart contracts can't serve complex web content.","Your product addresses: no standard interface for contract-as-server.","The flow should deliver: contract serves complete HTML pages, CSS, JS, everything.","You are designing a decentralized static site experience with visible states and recovery paths."],"whenToAvoid":["Always return proper Content-Type with every response.","Return proper 404 with helpful \"resource not found\" page.","Chunk large resources, use SSTORE2/SSTORE3 patterns.","Users never see addresses, amounts, or signing payloads in your UI."]},"designerTakeaways":["You can design UI that delivers contract serves complete HTML pages.","You can standard request(path) interface all browsers/clients understand.","You can design UI that delivers route different paths to different resources: /about."],"problemsSolved":[{"problem":"Smart contracts can't serve complex web content","oldWay":"Contracts return raw data, external frontend interprets it","newWay":"Contract serves complete HTML pages, CSS, JS - everything","impact":"critical"},{"problem":"No standard interface for contract-as-server","oldWay":"Each project invents custom resource serving","newWay":"Standard request(path) interface all browsers/clients understand","impact":"high"},{"problem":"Can't host multiple pages/resources in one contract","oldWay":"Single response, single endpoint","newWay":"Route different paths to different resources: /about, /docs, /app","impact":"high"},{"problem":"No content type negotiation on-chain","oldWay":"Clients guess content type","newWay":"Contract specifies MIME type with each response","impact":"medium"}],"uxPatterns":[{"name":"Decentralized Static Site","description":"Multi-page website served from smart contract","mockup":"concept/physical-link","userFlow":["User visits web3:// URL","Browser requests / (home) from contract","Contract returns HTML with nav links","User clicks \"About\"","Browser requests /about from contract","Contract returns about page HTML"]},{"name":"Contract Resource Browser","description":"Explore available resources in a contract","mockup":"concept/physical-link","userFlow":["Developer opens explorer","Enter contract address or ENS","See all available resources","Preview each resource","Check MIME types and sizes","Link directly to any resource"]},{"name":"Decentralized App Interface","description":"Interactive dApp with on-chain UI","mockup":"concept/physical-link","userFlow":["User visits web3:// URL","Contract serves its own UI","UI shows real-time contract state","User enters action (deposit, etc)","Transaction goes to same contract","No frontend/backend trust gap"]},{"name":"Resource Upload Interface","description":"Developer tool to deploy resources to contract","mockup":"concept/physical-link","userFlow":["Developer connects wallet","Drop files to upload","Map files to URL paths","Review gas costs","Deploy to contract storage","Resources now served at web3:// URLs"]}],"uiComponents":[{"name":"ResourceRequest","description":"Makes and displays contract resource requests","states":["idle","loading","loaded","error","404"],"props":["contract","path","onLoad","onError"]},{"name":"ContentRenderer","description":"Renders content based on MIME type","states":["loading","rendered","unsupported"],"props":["content","mimeType","sandbox"]},{"name":"ResourceExplorer","description":"Browse contract's available resources","states":["loading","loaded","empty","error"],"props":["contract","onSelect"]},{"name":"DeploymentWizard","description":"Upload resources to ERC-5219 contract","states":["selecting","mapping","estimating","deploying","complete"],"props":["contract","files","onDeploy"]}],"antiPatterns":[{"pattern":"Not handling 404s gracefully","why":"Users see cryptic errors when resource doesn't exist","instead":"Return proper 404 with helpful \"resource not found\" page","severity":"high"},{"pattern":"Serving large resources without chunking","why":"Gas limits prevent loading large pages","instead":"Chunk large resources, use SSTORE2/SSTORE3 patterns","severity":"high"},{"pattern":"Missing MIME types in responses","why":"Browsers don't know how to render content","instead":"Always return proper Content-Type with every response","severity":"critical"},{"pattern":"No caching headers for static content","why":"Same content re-fetched on every visit","instead":"Include cache-control hints, content hashes for versioning","severity":"medium"},{"pattern":"Hardcoding external dependencies","why":"Defeats purpose if UI needs external CDN","instead":"Bundle all dependencies, or reference other on-chain resources","severity":"medium"}],"onMonad":[{"aspect":"Resource Loading","ethereum":"Large pages take 5-15 seconds to load","monad":"Sub-second page loads","designImplication":"On-chain websites feel as fast as traditional web"},{"aspect":"Storage Costs","ethereum":"Very expensive to store UI on-chain","monad":"Lower costs make larger sites practical","designImplication":"Can store more comprehensive UIs, more resources"},{"aspect":"Dynamic Content","ethereum":"Server-rendered dynamic content is slow","monad":"Dynamic contract responses remain fast","designImplication":"Can build more interactive, personalized on-chain UIs"},{"aspect":"Multi-Resource Pages","ethereum":"Page with 10 resources = 10 slow calls","monad":"Parallel resource fetching stays fast","designImplication":"Rich pages with many assets still load quickly"}],"keyTakeaways":["ERC-5219 = contracts serve web resources like servers","Combined with ERC-4804 enables fully decentralized frontends","Always return proper MIME types with responses","Handle missing resources with graceful 404 pages","On Monad: on-chain UIs load fast enough for real use"],"technicalNotes":"ERC-5219 defines the request(string[] memory resource) function that contracts implement to serve resources. It returns (uint16 statusCode, string memory body, KeyValue[] memory headers). Status codes follow HTTP conventions (200, 404, etc). Resources can be stored using efficient patterns like SSTORE2 for larger content. Works with ERC-4804 for the complete web3:// URL solution."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-5219","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-5219","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-5219","markdown":"https://www.eipsfordesigners.com/standards/ERC-5219/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-5219/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-5219","official":"https://eips.ethereum.org/EIPS/eip-5219","discussion":"https://ethereum-magicians.org/search?q=ERC-5219"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"EIP-747","name":"wallet_watchAsset","status":"Final","chain":"both","category":{"id":"comprehension","name":"Comprehension & Display","description":"Making blockchain data readable to humans"},"journeyStages":[{"id":"asset-display","name":"Asset Discovery & Display","description":"Seeing tokens, NFTs, and balances"}],"uxImpact":"DApps prompt users to add tokens with one click — no manual contract address copying. Design implications: show token add prompt with icon/name/symbol preview, verify token against known lists before suggesting, display security warnings for suspicious tokens. Design decisions: permission model (always prompt vs remember preference), how to handle spam token add requests, verification level before showing token (metadata fetch vs trust dapp), blocking malicious token suggestions.","hasDetailedContent":true,"content":{"id":"EIP-747","summary":"EIP-747 is the \"Add Token\" button. It lets dApps request that wallets track a new token. User swaps for a new token, clicks \"Add to Wallet\", and the token appears in their balance. Without this, users would have to manually enter contract addresses to see new tokens.","applicability":{"whenToUse":["Your product addresses: new tokens don't show in wallet.","Your users think tokens are lost.","The flow should deliver: click \"Add to Wallet\", token appears.","You are designing a add token after swap experience with visible states and recovery paths."],"whenToAvoid":["Auto-prompt add token after receiving new asset.","Always require user action to add.","Display address and verification status.","Users never see addresses, amounts, or signing payloads in your UI."]},"designerTakeaways":["You can design UI that delivers click \"Add to Wallet\", token appears.","You can design UI that delivers prompt to add token immediately after swap.","You can design UI that delivers app provides verified contract address."],"problemsSolved":[{"problem":"New tokens don't show in wallet","oldWay":"Find contract address, copy it, add token manually","newWay":"Click \"Add to Wallet\", token appears","impact":"high"},{"problem":"Users think tokens are lost","oldWay":"\"I swapped but don't see anything!\" (token not tracked)","newWay":"Prompt to add token immediately after swap","impact":"high"},{"problem":"Wrong tokens added by mistake","oldWay":"User adds scam token with similar name","newWay":"App provides verified contract address","impact":"medium"}],"uxPatterns":[{"name":"Add Token After Swap","description":"Prompt to track new token post-transaction","mockup":"concept/nft-gallery","userFlow":["User completes swap","App detects new token received","Prompts to add to wallet","User clicks \"Add Token\"","Calls wallet_watchAsset","Token now visible in wallet"]},{"name":"Token Page Add Button","description":"Add token from info/detail page","mockup":"concept/verify-safety","userFlow":["User views token page","Clicks \"Add to Wallet\"","Wallet shows add token popup","User approves","Token tracked in wallet"]}],"uiComponents":[{"name":"AddToWalletButton","description":"Button to trigger wallet_watchAsset","states":["idle","adding","added","error","no-wallet"],"props":["token","onAdd","onError"]},{"name":"TokenAddedConfirmation","description":"Success message after token added","states":["hidden","shown"],"props":["token","onDismiss"]},{"name":"TokenPreview","description":"Shows token details before adding","states":["loading","loaded"],"props":["address","symbol","decimals","image"]}],"antiPatterns":[{"pattern":"Not prompting to add after swap","why":"User doesn't see new token, thinks it failed","instead":"Auto-prompt add token after receiving new asset","severity":"high"},{"pattern":"Adding tokens without user consent","why":"Spam tokens could fill wallet","instead":"Always require user action to add","severity":"medium"},{"pattern":"Not showing contract address","why":"User can't verify it's the right token","instead":"Display address and verification status","severity":"medium"}],"onMonad":[{"aspect":"Token Tracking","ethereum":"Standard wallet_watchAsset","monad":"Same API, may need Monad-specific logo URLs","designImplication":"Works identically"}],"keyTakeaways":["EIP-747 = \"Add to Wallet\" button","Prompt to add tokens after swaps/receives","Always show contract address for verification","Never add tokens without user consent","Use wallet_watchAsset RPC method"],"technicalNotes":"EIP-747 defines wallet_watchAsset RPC method. Parameters: { type: \"ERC20\", options: { address, symbol, decimals, image } }. Returns boolean success. Most wallets show confirmation popup. Image should be publicly accessible URL (IPFS or HTTPS). Only ERC-20 widely supported, NFT support varies."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-747","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=EIP-747","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/EIP-747","markdown":"https://www.eipsfordesigners.com/standards/EIP-747/content.md","agent":"https://www.eipsfordesigners.com/standards/EIP-747/agent.md","api":"https://www.eipsfordesigners.com/api/standards/EIP-747","official":"https://eips.ethereum.org/EIPS/eip-747","discussion":"https://ethereum-magicians.org/search?q=EIP-747"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"EIP-3668","name":"CCIP Read (Offchain Data Retrieval)","status":"Final","chain":"both","category":{"id":"comprehension","name":"Comprehension & Display","description":"Making blockchain data readable to humans"},"journeyStages":[{"id":"asset-display","name":"Asset Discovery & Display","description":"Seeing tokens, NFTs, and balances"},{"id":"reading","name":"Reading & Understanding","description":"Interpreting what you're being asked to do"}],"uxImpact":"Contracts fetch offchain data transparently — ENS names can resolve from L2s or external sources without users knowing. Design implications: show loading states during offchain lookups, indicate data source in advanced views (on-chain vs gateway), handle gateway failures gracefully with retries. Design decisions: which gateways to trust (security/privacy tradeoff), timeout handling for slow gateways, whether to show users that offchain lookup occurred, caching validated responses.","hasDetailedContent":true,"content":{"id":"EIP-3668","sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-3668","type":"official-spec"}],"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25","summary":"Contracts fetch offchain data transparently — ENS names can resolve from L2s or external sources without users knowing.","designerTakeaways":["You can show loading states during offchain lookups without exposing CCIP jargon.","Your advanced view can indicate data source when relevant.","You can retry gracefully when gateways fail."],"applicability":{"whenToUse":["ENS or contract data requires offchain resolution.","Users expect fast name or metadata lookups.","Your app uses CCIP-enabled contracts."],"whenToAvoid":["All data is fully onchain with no gateway dependency.","Gateway infrastructure is unreliable without fallback.","Privacy requirements forbid offchain lookups."]},"prototypeFirst":[{"screen":"Primary happy path","why":"Prove the core user promise before edge cases.","covers":["Success state","Clear outcome copy"],"include":["Primary CTA","Confirmation feedback","Next step"]},{"screen":"Blocked or unsupported state","why":"Users discover limits when wallets or chains lack support.","covers":["Unsupported wallet","Wrong network"],"include":["Plain-language reason","Fallback action"]},{"screen":"Failure recovery","why":"Trust breaks when errors look like bugs.","covers":["User rejection","Transaction revert"],"include":["Retry path","Support context"]},{"screen":"Advanced disclosure","why":"Power users need technical detail without cluttering the default path.","covers":["Contract address","Token ID","Raw status"],"include":["Expandable section","Copy buttons","Explorer link"]}],"mentalModel":[{"label":"Onchain request","description":"A contract call triggers a revert with instructions to fetch data that is not stored onchain."},{"label":"Gateway fetch","description":"The client calls an offchain gateway URL from the revert payload. This lookup is invisible to users if your loading state is clear."},{"label":"Verified response","description":"The gateway returns data plus proof the contract can verify. Failed gateways need retry copy, not opaque errors."},{"label":"Transparent resolution","description":"The call resumes with fetched data. Users see ENS names or metadata resolve without CCIP jargon in the default path."},{"label":"Source disclosure","description":"Advanced views can note offchain source when trust or privacy matters. Default UX should feel like instant lookup."}],"statesToDesign":[{"state":"Ready","trigger":"Prerequisites met.","userNeed":"Understand what happens next.","designResponse":"Enable primary action with plain-language preview."},{"state":"Awaiting signature","trigger":"Wallet prompt open.","userNeed":"Know what they are approving.","designResponse":"Mirror human-readable summary in app and wallet."},{"state":"Pending","trigger":"Transaction submitted.","userNeed":"Confidence it is progressing.","designResponse":"Show status strip with explorer link."},{"state":"Succeeded","trigger":"On-chain confirmation.","userNeed":"See updated ownership or balance.","designResponse":"Celebrate outcome and show new state clearly."},{"state":"Failed or reverted","trigger":"Validation or execution failed.","userNeed":"Fix or retry without guessing.","designResponse":"Name the failed constraint and offer a concrete next step."}],"designDecisions":[{"question":"How much protocol detail do users see?","recommendation":"Lead with outcomes; tuck identifiers behind review.","rationale":"Users decide on consequences, not function selectors."},{"question":"What happens when support is missing?","recommendation":"Block with explanation and fallback path.","rationale":"Silent failure feels like a broken product."},{"question":"How do you label restricted assets?","recommendation":"Use persistent badges for non-transferable, locked, or expiring states.","rationale":"Hidden restrictions cause rage-quits at transfer time."}],"problemsSolved":[{"problem":"Inconsistent behavior across apps","oldWay":"Each team reinvents copy and edge cases","newWay":"Shared standard gives predictable UX patterns","impact":"high"},{"problem":"Users surprised by on-chain rules","oldWay":"Generic transfer UI fails at submit time","newWay":"Standard-aware UI sets expectations upfront","impact":"high"},{"problem":"Support burden from opaque errors","oldWay":"Raw revert reasons in toasts","newWay":"Mapped states explain what to do next","impact":"medium"}],"uxPatterns":[{"name":"Resolving Indicator","description":"Loading state during CCIP lookup.","mockup":"concept/typed-data","components":["ResolveSpinner","RetryButton"],"userFlow":["User triggers lookup","Spinner shows","Data resolves or retries","Result displayed"]},{"name":"Gateway Fallback","description":"Switch gateways on failure.","mockup":"concept/typed-data","components":["FallbackGateway","ErrorBanner"],"userFlow":["Primary gateway fails","App tries alternate","User sees progress","Success or clear error"]}],"seenInTheWild":[{"app":"ENS App","url":"https://app.ens.domains/","note":"CCIP Read enables L2 and offchain ENS resolution."},{"app":"Uniswap","url":"https://app.uniswap.org/","note":"Offchain data fetching patterns in DeFi interfaces."},{"app":"Chainlink","url":"https://chain.link/","note":"Oracle and CCIP infrastructure for offchain data."}],"antiPatterns":[{"pattern":"Hiding standard-imposed restrictions until submit","why":"Users feel tricked when actions fail at the last step","instead":"Show eligibility and badges before the primary CTA","severity":"critical"},{"pattern":"Protocol jargon in user-facing copy","why":"Non-technical users cannot consent informedly","instead":"Use outcome language with optional technical disclosure","severity":"high"},{"pattern":"No fallback when wallet lacks support","why":"Dead-end flows increase churn","instead":"Explain limitation and offer alternate path or network","severity":"high"}],"vocabulary":[{"use":"Your balance / Your item","avoid":"Token ID / Token contract","why":"Ownership language matches mental models."},{"use":"Cannot transfer yet","avoid":"Transfer reverted","why":"Explain restriction without EVM vocabulary."},{"use":"Confirm in wallet","avoid":"Sign transaction","why":"Matches wallet UX users already know."}],"onMonad":[{"aspect":"Confirmation speed","ethereum":"Multi-step flows can feel slow between signatures","monad":"Sub-second finality tightens feedback loops","designImplication":"Prefer inline status over long pending modals on Monad."},{"aspect":"Transaction cost","ethereum":"Gas can discourage exploratory actions","monad":"Lower fees enable lighter-weight interactions","designImplication":"Safe to offer preview retries and social actions more freely."}],"technicalNotes":"EIP-3668 CCIP Read requires gateway trust decisions and timeout handling in UI.","relatedStandards":[{"id":"ERC-137","relationship":"ENS resolution uses CCIP Read"},{"id":"EIP-5169","relationship":"TokenScript may use offchain resources"}]},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-3668","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=EIP-3668","type":"discussion"},{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-3668","type":"official-spec"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/EIP-3668","markdown":"https://www.eipsfordesigners.com/standards/EIP-3668/content.md","agent":"https://www.eipsfordesigners.com/standards/EIP-3668/agent.md","api":"https://www.eipsfordesigners.com/api/standards/EIP-3668","official":"https://eips.ethereum.org/EIPS/eip-3668","discussion":"https://ethereum-magicians.org/search?q=EIP-3668"},"freshness":{"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25"}},{"id":"EIP-5169","name":"Client Script URI (TokenScript)","status":"Final","chain":"both","category":{"id":"comprehension","name":"Comprehension & Display","description":"Making blockchain data readable to humans"},"journeyStages":[{"id":"specialized","name":"Specialized Interactions","description":"Physical items, AI, social, gaming"}],"uxImpact":"Tokens can link to official scripts/mini-dapps — wallets auto-discover functionality like 'Mint', 'Stake', or smart-lock controls. Design implications: fetch and display scriptURI-linked functionality, show available token actions dynamically, indicate script authenticity/source, sandbox script execution. Design decisions: trust model for token-linked scripts (massive security surface), user consent before running scripts, how to present discovered functionality vs built-in features, handling script updates/versioning.","hasDetailedContent":true,"content":{"id":"EIP-5169","sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-5169","type":"official-spec"}],"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25","summary":"Tokens can link to official scripts/mini-dapps — wallets auto-discover functionality like 'Mint', 'Stake', or smart-lock controls.","designerTakeaways":["You can display scriptURI-linked actions dynamically per token.","Your UI can show script source and authenticity before execution.","You can require explicit user consent before running token scripts."],"applicability":{"whenToUse":["Tokens have official client scripts for custom actions.","Wallets want dynamic action discovery.","You can sandbox and verify script sources."],"whenToAvoid":["Token actions are fully covered by built-in wallet features.","Script trust model cannot be explained to users.","Security review cannot vet linked scripts."]},"prototypeFirst":[{"screen":"Primary happy path","why":"Prove the core user promise before edge cases.","covers":["Success state","Clear outcome copy"],"include":["Primary CTA","Confirmation feedback","Next step"]},{"screen":"Blocked or unsupported state","why":"Users discover limits when wallets or chains lack support.","covers":["Unsupported wallet","Wrong network"],"include":["Plain-language reason","Fallback action"]},{"screen":"Failure recovery","why":"Trust breaks when errors look like bugs.","covers":["User rejection","Transaction revert"],"include":["Retry path","Support context"]},{"screen":"Advanced disclosure","why":"Power users need technical detail without cluttering the default path.","covers":["Contract address","Token ID","Raw status"],"include":["Expandable section","Copy buttons","Explorer link"]}],"mentalModel":[{"label":"Token script link","description":"The token contract points to scriptURI, a hosted TokenScript that describes extra actions beyond send and receive."},{"label":"Discovery","description":"Wallets and apps fetch the script to render dynamic buttons like Mint, Stake, or Redeem for that token."},{"label":"Trust review","description":"Show script source, publisher, and version before execution. Users must understand who authored the actions."},{"label":"User consent","description":"Each script-driven action needs explicit approval with plain-language preview, same as any transaction."},{"label":"Execution","description":"The script builds the contract call your UI submits. Failed or unverified scripts should disable actions, not fail silently."}],"statesToDesign":[{"state":"Ready","trigger":"Prerequisites met.","userNeed":"Understand what happens next.","designResponse":"Enable primary action with plain-language preview."},{"state":"Awaiting signature","trigger":"Wallet prompt open.","userNeed":"Know what they are approving.","designResponse":"Mirror human-readable summary in app and wallet."},{"state":"Pending","trigger":"Transaction submitted.","userNeed":"Confidence it is progressing.","designResponse":"Show status strip with explorer link."},{"state":"Succeeded","trigger":"On-chain confirmation.","userNeed":"See updated ownership or balance.","designResponse":"Celebrate outcome and show new state clearly."},{"state":"Failed or reverted","trigger":"Validation or execution failed.","userNeed":"Fix or retry without guessing.","designResponse":"Name the failed constraint and offer a concrete next step."}],"designDecisions":[{"question":"How much protocol detail do users see?","recommendation":"Lead with outcomes; tuck identifiers behind review.","rationale":"Users decide on consequences, not function selectors."},{"question":"What happens when support is missing?","recommendation":"Block with explanation and fallback path.","rationale":"Silent failure feels like a broken product."},{"question":"How do you label restricted assets?","recommendation":"Use persistent badges for non-transferable, locked, or expiring states.","rationale":"Hidden restrictions cause rage-quits at transfer time."}],"problemsSolved":[{"problem":"Inconsistent behavior across apps","oldWay":"Each team reinvents copy and edge cases","newWay":"Shared standard gives predictable UX patterns","impact":"high"},{"problem":"Users surprised by on-chain rules","oldWay":"Generic transfer UI fails at submit time","newWay":"Standard-aware UI sets expectations upfront","impact":"high"},{"problem":"Support burden from opaque errors","oldWay":"Raw revert reasons in toasts","newWay":"Mapped states explain what to do next","impact":"medium"}],"uxPatterns":[{"name":"Dynamic Token Actions","description":"Discover actions from scriptURI.","mockup":"concept/typed-data","components":["ActionList","ScriptBadge"],"userFlow":["User views token","Wallet fetches scriptURI","Actions appear","User selects action"]},{"name":"Script Consent Modal","description":"Explicit approval before script execution.","mockup":"concept/verify-safety","components":["ConsentModal","SourceIndicator"],"userFlow":["Action selected","Script source shown","User approves","Script runs sandboxed"]}],"seenInTheWild":[{"app":"AlphaWallet","url":"https://alphawallet.com/","note":"TokenScript pioneer for dynamic token functionality."},{"app":"TokenScript","url":"https://tokenscript.org/","note":"Framework for token-linked client scripts."},{"app":"Rainbow","url":"https://rainbow.me/","note":"Wallet action discovery patterns for tokens."}],"antiPatterns":[{"pattern":"Hiding standard-imposed restrictions until submit","why":"Users feel tricked when actions fail at the last step","instead":"Show eligibility and badges before the primary CTA","severity":"critical"},{"pattern":"Protocol jargon in user-facing copy","why":"Non-technical users cannot consent informedly","instead":"Use outcome language with optional technical disclosure","severity":"high"},{"pattern":"No fallback when wallet lacks support","why":"Dead-end flows increase churn","instead":"Explain limitation and offer alternate path or network","severity":"high"}],"vocabulary":[{"use":"Your balance / Your item","avoid":"Token ID / Token contract","why":"Ownership language matches mental models."},{"use":"Cannot transfer yet","avoid":"Transfer reverted","why":"Explain restriction without EVM vocabulary."},{"use":"Confirm in wallet","avoid":"Sign transaction","why":"Matches wallet UX users already know."}],"onMonad":[{"aspect":"Confirmation speed","ethereum":"Multi-step flows can feel slow between signatures","monad":"Sub-second finality tightens feedback loops","designImplication":"Prefer inline status over long pending modals on Monad."},{"aspect":"Transaction cost","ethereum":"Gas can discourage exploratory actions","monad":"Lower fees enable lighter-weight interactions","designImplication":"Safe to offer preview retries and social actions more freely."}],"technicalNotes":"EIP-5169 scriptURI links require strict trust model and user consent before execution.","relatedStandards":[{"id":"ERC-1046","relationship":"Token logo and metadata complement"},{"id":"EIP-747","relationship":"Token icon and metadata standards"}]},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-5169","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=EIP-5169","type":"discussion"},{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-5169","type":"official-spec"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/EIP-5169","markdown":"https://www.eipsfordesigners.com/standards/EIP-5169/content.md","agent":"https://www.eipsfordesigners.com/standards/EIP-5169/agent.md","api":"https://www.eipsfordesigners.com/api/standards/EIP-5169","official":"https://eips.ethereum.org/EIPS/eip-5169","discussion":"https://ethereum-magicians.org/search?q=EIP-5169"},"freshness":{"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25"}},{"id":"EIP-191","name":"Signed Data Standard","status":"Final","chain":"both","category":{"id":"security","name":"Security & Trust","description":"Helping users verify, control, and protect their assets"},"journeyStages":[{"id":"authentication","name":"Authentication & Identity","description":"Proving who you are and logging in"}],"uxImpact":"Users sign off-chain messages to authorize actions without gas — login, approve listings, multisig confirmations. Design implications: show clear 'Sign Message' vs 'Approve Transaction' distinction, display human-readable message content before signing, indicate which dApp/contract will validate the signature. Design decisions: balance security warnings (phishing risk) against friction — too many warnings cause blindness, too few enable exploits.","hasDetailedContent":true,"content":{"id":"EIP-191","summary":"EIP-191 standardizes how messages are signed by wallets, adding a prefix that prevents signed messages from being replayed as transactions. This is the foundation of \"Sign-In with Ethereum\" and all safe off-chain signing.","applicability":{"whenToUse":["Your product addresses: signed messages could be replayed as transactions.","Your product addresses: no standard format for signed data.","The flow should deliver: prefix \"\\x19Ethereum Signed Message:\" makes it invalid as a transaction.","You are designing a personal message signing experience with visible states and recovery paths."],"whenToAvoid":["Always show human-readable message with clear purpose.","Include timestamp and/or nonce, enforce expiration.","Wallet should warn if message looks like encoded function call.","Wrong-address or approval mistakes are not recoverable in your product context."]},"designerTakeaways":["You can design UI that delivers prefix \"\\x19Ethereum Signed Message:\" makes it invalid as a transaction.","You can standard prefix + version byte = consistent.","You can design UI that delivers version byte indicates: personal message."],"problemsSolved":[{"problem":"Signed messages could be replayed as transactions","oldWay":"Sign a message, attacker replays it as a transaction draining funds","newWay":"Prefix \"\\x19Ethereum Signed Message:\" makes it invalid as a transaction","impact":"critical"},{"problem":"No standard format for signed data","oldWay":"Each app invented own signing format, security varied wildly","newWay":"Standard prefix + version byte = consistent, auditable signing","impact":"high"},{"problem":"Can't verify what type of signature it is","oldWay":"Raw signature could be anything, hard to validate","newWay":"Version byte indicates: personal message, typed data, or validator","impact":"high"},{"problem":"Signing requests look the same regardless of purpose","oldWay":"User signs hex blob, no idea if it's login or permission grant","newWay":"Different prefixes enable different wallet UI treatments","impact":"medium"},{"problem":"Cross-protocol signature collision","oldWay":"Signature for App A might be valid for unrelated use in App B","newWay":"Version 0x45 includes validator address for protocol-specific signing","impact":"medium"}],"uxPatterns":[{"name":"Personal Message Signing","description":"Standard wallet UI for human-readable message signing","mockup":"concept/typed-data","userFlow":["dApp calls personal_sign with message","Wallet shows readable message content","User reads and understands what they're signing","User clicks Sign","Wallet prepends EIP-191 prefix and signs","Signature returned to dApp"]},{"name":"Login Signature","description":"Sign-in authentication flow","mockup":"concept/siwe-sign-in","userFlow":["User clicks \"Connect\" or \"Sign In\"","Wallet explains what signature does and doesn't do","User understands this is just authentication","User signs","Backend verifies signature, creates session"]},{"name":"Proof of Ownership","description":"Verify wallet ownership for external systems","mockup":"concept/typed-data","userFlow":["External service needs wallet verification","Presents message with context (what, why)","User understands linking purpose","User signs message","Service verifies signature, grants access"]},{"name":"Dangerous Signature Warning","description":"Wallet warns about suspicious signing requests","mockup":"concept/typed-data","userFlow":["Suspicious site requests signature","Wallet detects non-readable content","Shows warning about potential attack","User encouraged to reject","If user proceeds, extra confirmation required"]}],"uiComponents":[{"name":"MessageDisplay","description":"Render signed message content","states":["readable","hex","mixed","suspicious"],"props":["message","encoding","maxLength","expanded"]},{"name":"SignatureTypeIndicator","description":"Show what type of signature this is","states":["personal","typed","login","unknown"],"props":["type","version","tooltip"]},{"name":"OriginBadge","description":"Show requesting site with trust level","states":["trusted","unknown","suspicious","known-malicious"],"props":["origin","trustLevel","previousInteractions"]},{"name":"ScopeExplainer","description":"Explain what signature grants and doesn't grant","states":["collapsed","expanded"],"props":["grants[]","doesNotGrant[]","expiresAt"]},{"name":"NonceDisplay","description":"Show nonce/timestamp for replay protection","states":["valid","expired","missing"],"props":["nonce","timestamp","expiresAt"]}],"antiPatterns":[{"pattern":"Asking users to sign raw hex data","why":"Users can't verify what they're signing, easy to trick them","instead":"Always show human-readable message with clear purpose","severity":"critical"},{"pattern":"No timestamp or nonce in signed messages","why":"Signature can be replayed indefinitely","instead":"Include timestamp and/or nonce, enforce expiration","severity":"critical"},{"pattern":"Signing messages that look like transaction data","why":"Could be tricking user into signing malicious permit/approval","instead":"Wallet should warn if message looks like encoded function call","severity":"critical"},{"pattern":"Not explaining what signing does vs doesn't do","why":"Users fear any signature might drain their wallet","instead":"Clearly state \"This will NOT approve transactions or spend funds\"","severity":"high"},{"pattern":"Same UI for login signatures and permits","why":"Permit signatures ARE dangerous, login signatures are safe","instead":"Use EIP-712 for permits with different, scarier UI","severity":"high"},{"pattern":"Not showing the requesting origin","why":"Phishing sites can pretend to be legitimate","instead":"Always show full URL of requesting site prominently","severity":"high"}],"onMonad":[{"aspect":"Signature Format","ethereum":"EIP-191 is chain-agnostic, works everywhere","monad":"Same EIP-191 format, full compatibility","designImplication":"No changes needed for basic signing on Monad"},{"aspect":"Verification Speed","ethereum":"Signature verification is fast (off-chain)","monad":"On-chain verification also fast due to precompiles","designImplication":"Can do on-chain sig verification without UX penalty"},{"aspect":"Domain Binding","ethereum":"Messages should include chain ID for multi-chain apps","monad":"Include Monad chain ID when signature is chain-specific","designImplication":"Multi-chain apps need chain-aware message formats"},{"aspect":"Smart Wallet Signing","ethereum":"EIP-191 works with ERC-1271 for smart wallets","monad":"Same compatibility, verify via isValidSignature()","designImplication":"Support both EOA and smart wallet signatures"}],"keyTakeaways":["EIP-191 prefix prevents message-to-transaction replay attacks","Always show human-readable message content","Include timestamp/nonce for replay protection","Clearly explain what signing does and doesn't do","Warn loudly about hex/encoded messages"],"technicalNotes":"EIP-191 format: 0x19 <version> <data>. Version 0x01 = structured data (EIP-712). Version 0x00 = validator address + data. Version 0x45 (E) = personal_sign with \"Ethereum Signed Message:\\n\" + length + message. The 0x19 byte is invalid as transaction start, preventing replay."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-191","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=EIP-191","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/EIP-191","markdown":"https://www.eipsfordesigners.com/standards/EIP-191/content.md","agent":"https://www.eipsfordesigners.com/standards/EIP-191/agent.md","api":"https://www.eipsfordesigners.com/api/standards/EIP-191","official":"https://eips.ethereum.org/EIPS/eip-191","discussion":"https://ethereum-magicians.org/search?q=EIP-191"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"EIP-155","name":"Simple Replay Protection","status":"Final","chain":"both","category":{"id":"security","name":"Security & Trust","description":"Helping users verify, control, and protect their assets"},"journeyStages":[{"id":"status","name":"Status & Confirmation","description":"Waiting for and confirming outcomes"}],"uxImpact":"Transactions include chain ID preventing replay across networks — signing on Ethereum won't accidentally work on Polygon. Design implications: show network badge prominently during signing, warn if signing for unexpected chain, auto-detect chain mismatches between wallet and dApp. Design decisions: whether to block cross-chain mistakes entirely or allow with confirmation — power users want flexibility, novices need protection.","hasDetailedContent":true,"content":{"id":"EIP-155","summary":"EIP-155 prevents replay attacks by including the chain ID in transaction signatures. Before this, a transaction signed on Ethereum mainnet could be \"replayed\" on Ethereum Classic (or any fork) to steal funds. Now every signature is bound to a specific chain, protecting users when networks fork or when using multiple chains.","applicability":{"whenToUse":["Your product addresses: transactions could be replayed across chains.","Your product addresses: network forks created security risks.","The flow should deliver: signature includes chain ID, invalid on other chains.","You are designing a network indicator in transaction experience with visible states and recovery paths."],"whenToAvoid":["Always show network name AND chain ID in transaction confirmations.","Always confirm network switches before signing.","Show both name and numeric chain ID.","Wrong-address or approval mistakes are not recoverable in your product context."]},"designerTakeaways":["You can design UI that delivers signature includes chain ID, invalid on other chains.","You can each chain has unique ID, signatures are chain-specific in the interface.","You can design UI that delivers same address."],"problemsSolved":[{"problem":"Transactions could be replayed across chains","oldWay":"Sign a transaction on mainnet, attacker replays it on Classic to drain the same address","newWay":"Signature includes chain ID, invalid on other chains","impact":"critical"},{"problem":"Network forks created security risks","oldWay":"Every fork meant potential replay attacks on both chains","newWay":"Each chain has unique ID, signatures are chain-specific","impact":"critical"},{"problem":"Users couldn't safely use multiple EVM chains","oldWay":"Using same address on multiple chains was risky","newWay":"Same address, different chain IDs, transactions isolated","impact":"high"},{"problem":"No way to verify which chain a transaction was meant for","oldWay":"Wallet showed transaction but not target network","newWay":"Chain ID in signature proves intended network","impact":"medium"}],"uxPatterns":[{"name":"Network Indicator in Transaction","description":"Always show which network a transaction is being signed for","mockup":"concept/verify-safety","userFlow":["User initiates transaction","Wallet shows network prominently","Chain ID displayed for verification","User confirms on correct network","Transaction signed with chain ID embedded"]},{"name":"Wrong Network Warning","description":"Alert when user tries to sign for unexpected chain","mockup":"concept/verify-safety","userFlow":["DApp requests transaction for specific chain","Wallet detects mismatch with connected chain","Warning modal shown before signing","User can switch networks or cancel","Prevents accidental wrong-chain transactions"]},{"name":"Multi-Chain Transaction History","description":"Show chain context for all historical transactions","mockup":"concept/verify-safety","userFlow":["User opens transaction history","Each transaction shows its chain","Chain ID visible for verification","Clear which network each tx occurred on"]}],"uiComponents":[{"name":"ChainIdBadge","description":"Visual indicator of chain ID with network name","states":["mainnet","testnet","l2","unknown"],"props":["chainId","chainName","icon","color"]},{"name":"NetworkMismatchAlert","description":"Warning when requested chain differs from connected","states":["mismatch","matched","switching"],"props":["requestedChain","connectedChain","onSwitch","onCancel"]},{"name":"TransactionChainContext","description":"Shows chain context for a transaction","states":["pending","confirmed","failed"],"props":["chainId","txHash","explorerUrl"]}],"antiPatterns":[{"pattern":"Hiding chain ID from users","why":"Users can't verify they're signing for the right network","instead":"Always show network name AND chain ID in transaction confirmations","severity":"critical"},{"pattern":"Auto-switching networks without confirmation","why":"User might accidentally transact on wrong chain","instead":"Always confirm network switches before signing","severity":"high"},{"pattern":"Using only chain name without ID","why":"Fake networks could use same name as real ones","instead":"Show both name and numeric chain ID","severity":"high"},{"pattern":"No indication of replay protection","why":"Users don't know their transaction is protected","instead":"Show \"Protected on [Network]\" badge","severity":"medium"}],"onMonad":[{"aspect":"Monad Chain ID","ethereum":"Chain ID 1 for mainnet","monad":"Monad has its own unique chain ID","designImplication":"Display \"Monad\" name with chain ID in all transaction confirmations"},{"aspect":"Cross-Chain Operations","ethereum":"Each chain requires separate transactions","monad":"Same requirement, but faster confirmation","designImplication":"Show chain context even more prominently in fast-finality environment"}],"relatedStandards":[{"id":"EIP-695","relationship":"EIP-695 provides the RPC method to query chain ID that EIP-155 introduced"},{"id":"EIP-1344","relationship":"EIP-1344 adds chain ID opcode so smart contracts can also verify chain"},{"id":"EIP-1191","relationship":"EIP-1191 extends checksums to include chain ID for address validation"},{"id":"EIP-2718","relationship":"Typed transactions include chain ID in the envelope structure"}]},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-155","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=EIP-155","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/EIP-155","markdown":"https://www.eipsfordesigners.com/standards/EIP-155/content.md","agent":"https://www.eipsfordesigners.com/standards/EIP-155/agent.md","api":"https://www.eipsfordesigners.com/api/standards/EIP-155","official":"https://eips.ethereum.org/EIPS/eip-155","discussion":"https://ethereum-magicians.org/search?q=EIP-155"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"EIP-1344","name":"ChainID Opcode","status":"Final","chain":"both","category":{"id":"security","name":"Security & Trust","description":"Helping users verify, control, and protect their assets"},"journeyStages":[{"id":"status","name":"Status & Confirmation","description":"Waiting for and confirming outcomes"}],"uxImpact":"Smart contracts can verify which chain they're on, enabling chain-aware logic for bridges and L2s. Design implications: display chain context in multi-chain interfaces, show 'Supported Networks' clearly, indicate when contract behavior varies by chain. Design decisions: whether to expose chain-specific features or abstract them away — transparency vs simplicity tradeoff.","hasDetailedContent":true,"content":{"id":"EIP-1344","summary":"EIP-1344 added a CHAINID opcode so smart contracts can read the chain ID directly. Before this, contracts had to trust users or oracles to tell them which chain they were on. Now contracts can verify \"I'm on Ethereum mainnet\" themselves, enabling secure cross-chain aware logic and built-in replay protection.","applicability":{"whenToUse":["Your product addresses: contracts couldn't verify which chain they were on.","Your product addresses: smart contract replay attacks.","The flow should deliver: contract reads chain ID directly from the EVM.","You are designing a chain-aware transaction validation experience with visible states and recovery paths."],"whenToAvoid":["Parse error and explain \"This was signed for a different chain\".","Show \"Chain-verified\" badge for secure contracts.","Always display chain ID/name in signature UI.","Wrong-address or approval mistakes are not recoverable in your product context."]},"designerTakeaways":["You can design UI that delivers contract reads chain ID directly from the EVM.","You can design UI that delivers contracts verify chain ID before executing sensitive operations.","You can design UI that delivers contract checks if message is meant for this chain."],"problemsSolved":[{"problem":"Contracts couldn't verify which chain they were on","oldWay":"Pass chain ID as parameter, hope nobody lies","newWay":"Contract reads chain ID directly from the EVM","impact":"critical"},{"problem":"Smart contract replay attacks","oldWay":"Contract logic could be tricked across chains","newWay":"Contracts verify chain ID before executing sensitive operations","impact":"high"},{"problem":"Cross-chain message verification was complex","oldWay":"Needed trusted oracles or complex verification","newWay":"Contract checks if message is meant for this chain","impact":"high"},{"problem":"Hardcoded chain IDs were fragile","oldWay":"Contract deployed with hardcoded chain ID, breaks on forks","newWay":"Dynamic chain ID reading works after forks","impact":"medium"}],"uxPatterns":[{"name":"Chain-Aware Transaction Validation","description":"Contract rejects transactions meant for other chains","mockup":"concept/verify-safety","userFlow":["User tries to use cross-chain message","Contract checks chain ID via opcode","Mismatch detected, transaction reverts","Clear error explains the issue","User guided to correct network"]},{"name":"Multi-Chain Contract Status","description":"Show contract awareness of its chain","mockup":"concept/verify-safety","userFlow":["User views bridge or cross-chain contract","Contract chain awareness displayed","Security features explained","User confident in contract protection"]},{"name":"Permit Chain Verification","description":"Show that permit signatures include chain verification","mockup":"concept/permit-approval","userFlow":["User signing permit for token approval","Chain ID shown as part of permit data","Contract will verify chain before accepting","User understands signature is chain-locked"]}],"uiComponents":[{"name":"ChainVerificationBadge","description":"Shows contract uses chain ID verification","states":["verified","unverified","checking"],"props":["chainId","isVerified","contractType"]},{"name":"ChainMismatchError","description":"Error display for chain ID rejection","states":["error","suggestion"],"props":["expectedChain","actualChain","onSwitch"]},{"name":"SignatureChainContext","description":"Shows chain context for signatures","states":["current","different","unknown"],"props":["signatureChainId","currentChainId"]}],"antiPatterns":[{"pattern":"Not explaining chain mismatch errors","why":"User sees \"execution reverted\" with no context","instead":"Parse error and explain \"This was signed for a different chain\"","severity":"high"},{"pattern":"Hiding chain verification status","why":"Users don't know if contract is protected","instead":"Show \"Chain-verified\" badge for secure contracts","severity":"medium"},{"pattern":"Not showing chain ID in signature requests","why":"User signs without knowing which chain it's for","instead":"Always display chain ID/name in signature UI","severity":"medium"}],"onMonad":[{"aspect":"Monad Chain ID Verification","ethereum":"Contracts check for chain ID 1","monad":"Monad contracts check for Monad's chain ID","designImplication":"Ensure Monad-deployed contracts use correct chain ID checks"},{"aspect":"Cross-Chain Bridges","ethereum":"Bridge contracts verify source chain","monad":"Bridges to/from Monad use CHAINID opcode","designImplication":"Clear indication of source/destination chain in bridge UIs"},{"aspect":"Fast Verification","ethereum":"Chain ID check is cheap (2 gas for opcode)","monad":"Same minimal cost, no UX impact","designImplication":"No need to show \"verifying chain\" loading states"}],"relatedStandards":[{"id":"EIP-155","relationship":"EIP-155 puts chain ID in transaction signatures, EIP-1344 lets contracts read it"},{"id":"EIP-712","relationship":"EIP-712 typed data includes chain ID, contracts verify with CHAINID opcode"},{"id":"EIP-695","relationship":"eth_chainId for dApps, CHAINID opcode for contracts"},{"id":"ERC-2612","relationship":"Permit signatures include chain ID, verified by contract"}]},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-1344","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=EIP-1344","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/EIP-1344","markdown":"https://www.eipsfordesigners.com/standards/EIP-1344/content.md","agent":"https://www.eipsfordesigners.com/standards/EIP-1344/agent.md","api":"https://www.eipsfordesigners.com/api/standards/EIP-1344","official":"https://eips.ethereum.org/EIPS/eip-1344","discussion":"https://ethereum-magicians.org/search?q=EIP-1344"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"ERC-1271","name":"Standard Signature Validation for Contracts","status":"Final","chain":"both","category":{"id":"security","name":"Security & Trust","description":"Helping users verify, control, and protect their assets"},"journeyStages":[{"id":"authentication","name":"Authentication & Identity","description":"Proving who you are and logging in"}],"uxImpact":"Smart contract wallets (Safe, Argent) can sign messages like EOAs — unlocks gasless listings, off-chain voting for multisigs. Design implications: don't assume signer = EOA, show 'Wallet Type: Smart Contract' indicator, support signature verification loading states. Design decisions: how to handle async signature verification vs instant EOA checks — may need pending/confirming states in UI.","hasDetailedContent":true,"content":{"id":"ERC-1271","summary":"ERC-1271 lets smart contract wallets (like multisigs and account abstraction wallets) sign messages just like regular wallets. This enables \"Login with Smart Wallet\" and signature-based permissions for users who don't have traditional seed phrase wallets.","applicability":{"whenToUse":["Your product addresses: smart wallets can't sign messages for login.","Your product addresses: multisig users locked out of dApps.","The flow should deliver: any contract can implement isValidSignature() to verify signatures.","Connect flows must list wallets with names, icons, and explicit user choice."],"whenToAvoid":["Always check for contract code and support ERC-1271 verification.","Check EOA first, then fall back to isValidSignature() for contracts.","Display how many signatures collected vs required.","Wrong-address or approval mistakes are not recoverable in your product context."]},"designerTakeaways":["You can design UI that delivers any contract can implement isValidSignature() to verify signatures.","You can design UI that delivers multisigs implement ERC-1271 to validate collected signatures.","You can design UI that delivers contracts check ERC-1271 for smart wallet signatures."],"problemsSolved":[{"problem":"Smart wallets can't sign messages for login","oldWay":"Only EOAs (seed phrase wallets) could sign messages, excluding smart wallet users","newWay":"Any contract can implement isValidSignature() to verify signatures","impact":"critical"},{"problem":"Multisig users locked out of dApps","oldWay":"Gnosis Safe users couldn't use \"Sign-In with Ethereum\" or permit","newWay":"Multisigs implement ERC-1271 to validate collected signatures","impact":"critical"},{"problem":"Permit/gasless approvals don't work for smart wallets","oldWay":"ERC-2612 permit only worked with EOA ECDSA signatures","newWay":"Contracts check ERC-1271 for smart wallet signatures","impact":"high"},{"problem":"Off-chain order signing excludes smart wallet users","oldWay":"OpenSea, 0x orders required EOA signatures, excluding multisigs","newWay":"Marketplaces verify signatures via isValidSignature()","impact":"high"},{"problem":"Each smart wallet has different signature validation","oldWay":"Every multisig had its own signature scheme, apps couldn't support all","newWay":"Standard interface means one integration works for all smart wallets","impact":"medium"}],"uxPatterns":[{"name":"Smart Wallet Login","description":"Sign-in flow that works for both EOAs and smart wallets","mockup":"concept/siwe-sign-in","userFlow":["User connects smart wallet","App detects contract wallet (no code at EOA = EOA, code = smart wallet)","Shows appropriate signing flow (single vs multisig)","User initiates signature request","Other signers approve if needed","App verifies via isValidSignature()","User logged in"]},{"name":"Multisig Signature Progress","description":"Track signature collection for multisig operations","mockup":"concept/siwe-sign-in","userFlow":["Signature request created","First signer signs","Progress updates in real-time","Second signer notified","Threshold reached","Signature validated, action proceeds"]},{"name":"Gasless Listing (Permit + 1271)","description":"Create marketplace listings without gas for smart wallet users","mockup":"concept/permit-approval","userFlow":["User fills listing details","App checks wallet type","Gasless option available for all wallet types","User signs listing order","Smart wallet validates via 1271","Listing goes live without gas spent"]},{"name":"Universal Signature Verification","description":"Detect wallet type and verify appropriately","mockup":"concept/verify-safety","userFlow":["App receives signature from unknown wallet","Check if address has code (smart wallet) or not (EOA)","For EOA: use ecrecover","For smart wallet: call isValidSignature()","Check return value equals magic value","Display verification result"]}],"uiComponents":[{"name":"WalletTypeIndicator","description":"Show whether connected wallet is EOA or smart wallet","states":["eoa","smart-wallet","multisig","unknown"],"props":["walletAddress","walletType","walletName","threshold"]},{"name":"SignatureProgress","description":"Track multisig signature collection","states":["pending","partial","complete","expired"],"props":["collected","required","signers[]","deadline"]},{"name":"SmartWalletBadge","description":"Indicate smart wallet compatibility","states":["compatible","incompatible","checking"],"props":["walletType","supportedFeatures[]"]},{"name":"SignerList","description":"List multisig signers and their status","states":["waiting","signed","rejected"],"props":["signers[]","signedBy[]","requiredCount"]},{"name":"UniversalSignButton","description":"Sign button that adapts to wallet type","states":["ready","awaiting-signatures","complete","error"],"props":["message","walletType","onSign","signaturesNeeded"]}],"antiPatterns":[{"pattern":"Assuming all wallets are EOAs","why":"Smart wallet users get \"invalid signature\" errors and can't use your app","instead":"Always check for contract code and support ERC-1271 verification","severity":"critical"},{"pattern":"Only using ecrecover for signature validation","why":"Excludes multisigs, Argent, Safe, and all ERC-4337 wallets","instead":"Check EOA first, then fall back to isValidSignature() for contracts","severity":"critical"},{"pattern":"Not showing multisig signature progress","why":"Users don't know if their request is pending or failed","instead":"Display how many signatures collected vs required","severity":"high"},{"pattern":"Hiding wallet type from users","why":"Smart wallet users don't know why signing flow is different","instead":"Show \"Multisig detected\" and explain the multi-signer flow","severity":"high"},{"pattern":"Short signature timeouts for multisigs","why":"Multisigs need time to collect signatures from multiple parties","instead":"Allow longer validity periods or refreshable signatures","severity":"medium"},{"pattern":"Not providing reminder/notification for pending signatures","why":"Signatures stall because other signers don't know they're needed","instead":"Integrate with Safe notification API or provide reminder button","severity":"medium"}],"onMonad":[{"aspect":"Signature Verification Speed","ethereum":"isValidSignature() call can be slow (RPC latency)","monad":"Sub-second RPC responses make verification feel instant","designImplication":"Can verify signatures inline without loading states"},{"aspect":"Gas for Verification","ethereum":"On-chain verification in contracts costs significant gas","monad":"Lower gas costs make on-chain verification more viable","designImplication":"Can do on-chain signature checks in transaction flow"},{"aspect":"Smart Wallet Adoption","ethereum":"Smart wallets common for treasuries, less for consumers","monad":"EIP-7702 makes smart wallet features common on regular EOAs","designImplication":"More users will have contract code, always check 1271"},{"aspect":"Multisig Confirmation","ethereum":"Waiting for block confirmations adds latency","monad":"Fast finality means signature status updates nearly instantly","designImplication":"Real-time signature progress without polling delays"}],"keyTakeaways":["ERC-1271 = smart wallets can sign messages","Always support both ecrecover AND isValidSignature()","Check if address has code to detect smart wallets","Show multisig progress: \"2 of 3 signatures collected\"","Allow longer timeouts for multi-party signing"],"technicalNotes":"ERC-1271 defines a single function: isValidSignature(bytes32 hash, bytes signature) returns (bytes4). If valid, returns magic value 0x1626ba7e. To check if address is smart wallet: if (address.code.length > 0) use 1271, else use ecrecover. Most smart wallets (Safe, Argent, Sequence, etc.) implement this standard."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-1271","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-1271","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-1271","markdown":"https://www.eipsfordesigners.com/standards/ERC-1271/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-1271/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-1271","official":"https://eips.ethereum.org/EIPS/eip-1271","discussion":"https://ethereum-magicians.org/search?q=ERC-1271"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"ERC-5507","name":"Refundable Tokens","status":"Final","chain":"both","category":{"id":"security","name":"Security & Trust","description":"Helping users verify, control, and protect their assets"},"journeyStages":[{"id":"management","name":"Asset Management","description":"Managing assets over time"}],"uxImpact":"NFT/token purchases include refund windows like traditional e-commerce — buyers can return within deadline. Design implications: show 'Refundable until [date]' badge on listings, add 'Request Refund' button in owned items, display refund countdown timer. Design decisions: whether refund status affects resale UI — should refundable items show different on marketplaces, how to handle partial refund eligibility.","hasDetailedContent":true,"content":{"id":"ERC-5507","sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-5507","type":"official-spec"}],"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25","summary":"NFT/token purchases include refund windows like traditional e-commerce — buyers can return within deadline.","designerTakeaways":["You can show Refundable until [date] badges on every listing before purchase.","Your owned-items view can offer a one-tap Request Refund while the window is open.","You can differentiate refundable inventory from final-sale items in wallet and marketplace grids."],"applicability":{"whenToUse":["Primary sales include buyer protection or regulatory cooling-off periods.","Your marketplace sells high-ticket NFTs where purchase regret is common.","Refund eligibility is enforced on-chain and your UI must mirror it."],"whenToAvoid":["Secondary market trades where refunds are not part of the contract.","Low-value drops where refund UX adds friction without legal need.","Contracts do not implement ERC-5507 refund hooks."]},"prototypeFirst":[{"screen":"Listing with refund badge","why":"Buyers decide with refund terms visible before they connect a wallet.","covers":["Refund deadline","Final sale vs refundable"],"include":["Refundable until date chip","Tooltip explaining window","Price and CTA"]},{"screen":"Owned item refund request","why":"The return moment must feel as clear as requesting a refund on Amazon.","covers":["Eligible","Expired","Pending refund"],"include":["Countdown timer","Request Refund CTA","What happens next copy"]},{"screen":"Refund confirmation","why":"Users need certainty about what they lose and regain.","covers":["Success","Reverted","Partial eligibility"],"include":["Item preview","Refund amount","Irreversible warning"]},{"screen":"Marketplace resale with active refund","why":"Resale while refundable creates confusion about who can still return.","covers":["Refundable badge on listing","Transfer during window"],"include":["Refund transfers with item note","Disabled refund for new owner if applicable"]}],"mentalModel":[{"label":"Purchase moment","description":"The clock starts when the buyer receives the token — that timestamp anchors every refund decision."},{"label":"Refund window","description":"A fixed period where return is allowed; after it closes, ownership is final like any other NFT."},{"label":"Refund action","description":"Returning the token triggers contract rules — burn, escrow release, or seller clawback depending on implementation."},{"label":"Resale overlap","description":"Selling during the refund window may transfer refund rights or end them; the UI must say which."},{"label":"Marketplace mirror","description":"Aggregators must read the same on-chain eligibility — badges should match the primary sale site."}],"statesToDesign":[{"state":"Refundable — window open","trigger":"User owns token within refund period.","userNeed":"Know how long they have and how to return.","designResponse":"Show countdown and prominent Request Refund on item detail."},{"state":"Refund pending","trigger":"User submitted refund transaction.","userNeed":"Track progress like an order return.","designResponse":"Status strip: submitted, confirmed, completed with explorer link."},{"state":"Refund window expired","trigger":"Deadline passed.","userNeed":"Understand ownership is now final.","designResponse":"Replace refund CTA with Final sale badge; enable normal transfer/sell."},{"state":"Non-refundable listing","trigger":"Token or sale type excludes refunds.","userNeed":"Not discover refund option at checkout.","designResponse":"Final sale badge before purchase; no refund CTA in owned view."},{"state":"Refund rejected","trigger":"Contract reverts refund attempt.","userNeed":"Know why return failed.","designResponse":"Plain-language reason: expired, already used, or not eligible."}],"designDecisions":[{"question":"Should refundable items look different on secondary marketplaces?","recommendation":"Show a subtle Refundable until badge on listings; hide refund CTA for buyers who did not purchase from primary.","rationale":"Secondary buyers may not have refund rights — confusing badges cause support tickets."},{"question":"How prominent should the countdown be?","recommendation":"Show deadline on listing and owned-item header, not buried in terms.","rationale":"Refund windows are a purchase factor; hiding them feels deceptive."},{"question":"What happens to refund UI after a resale?","recommendation":"Re-query eligibility for the new owner; default to no refund unless contract grants it.","rationale":"Ownership change resets buyer relationship with the primary seller."}],"problemsSolved":[{"problem":"NFT purchases feel irreversible and risky","oldWay":"Buyers hesitate on expensive mints with no recourse","newWay":"On-chain refund window mirrors e-commerce buyer protection","impact":"high"},{"problem":"Refund rules buried in fine print","oldWay":"Users discover no returns after connecting wallet","newWay":"Badges and countdowns surface policy before payment","impact":"high"},{"problem":"Marketplaces show identical UI for final-sale items","oldWay":"All listings look equally permanent","newWay":"Refundable vs final-sale visual treatment sets expectations","impact":"medium"}],"uxPatterns":[{"name":"Refund Window Badge","description":"Listing chip showing deadline before purchase.","mockup":"concept/nft-gallery","components":["RefundBadge","DeadlineTooltip","ListingCard"],"userFlow":["User browses","Sees Refundable until date","Reads policy","Purchases informed"]},{"name":"Return Request Flow","description":"Owned-item refund with countdown and confirmation.","mockup":"concept/verify-safety","components":["CountdownTimer","RefundButton","ConfirmModal"],"userFlow":["User opens owned item","Timer shows days left","Taps Request Refund","Confirms","Token returned"]}],"seenInTheWild":[{"app":"OpenSea","url":"https://opensea.io/","note":"Marketplace listing patterns inform how refund badges should appear alongside price."},{"app":"Zora","url":"https://zora.co/","note":"Creator primary sales set expectations for purchase protection copy."},{"app":"Nifty Gateway","url":"https://www.niftygateway.com/","note":"High-ticket drops benefit from clear buyer protection messaging."},{"app":"Shopify","url":"https://www.shopify.com/","note":"Return window UX is the mental model users already understand."}],"antiPatterns":[{"pattern":"Showing Refund button after window expired","why":"Users waste gas on doomed transactions","instead":"Disable CTA and show Final sale with expired date","severity":"high"},{"pattern":"Hiding refund terms until after mint","why":"Feels like bait-and-switch at checkout","instead":"Badge on listing and confirm step before signature","severity":"critical"},{"pattern":"Identical cards for refundable and final-sale items","why":"Users cannot compare purchase risk","instead":"Distinct badge treatment in grid and detail views","severity":"medium"}],"vocabulary":[{"use":"Return by [date]","avoid":"Refund window epoch","why":"Deadline language matches shopping habits."},{"use":"Final sale","avoid":"Non-refundable token state","why":"Plain commerce terms over protocol jargon."},{"use":"Request return","avoid":"Execute refund()","why":"Action language users recognize from retail."}],"onMonad":[{"aspect":"Confirmation speed","ethereum":"Refund status may take minutes to confirm","monad":"Sub-second finality makes return confirmation feel instant","designImplication":"Use inline success states instead of long pending modals."},{"aspect":"Transaction cost","ethereum":"Refund attempts cost meaningful gas","monad":"Lower fees reduce friction for trying returns","designImplication":"Safe to show retry on failed refund without heavy cost anxiety."}],"technicalNotes":"ERC-5507 adds refund windows to token purchases; always re-query eligibility after transfers.","relatedStandards":[{"id":"ERC-5528","relationship":"Fungible token escrow refunds complement NFT returns"},{"id":"ERC-721","relationship":"Base NFT standard extended with refund hooks"}]},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-5507","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-5507","type":"discussion"},{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-5507","type":"official-spec"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-5507","markdown":"https://www.eipsfordesigners.com/standards/ERC-5507/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-5507/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-5507","official":"https://eips.ethereum.org/EIPS/erc-5507","discussion":"https://ethereum-magicians.org/search?q=ERC-5507"},"freshness":{"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25"}},{"id":"ERC-5528","name":"Refundable Fungible Token","status":"Final","chain":"both","category":{"id":"security","name":"Security & Trust","description":"Helping users verify, control, and protect their assets"},"journeyStages":[{"id":"management","name":"Asset Management","description":"Managing assets over time"}],"uxImpact":"Token sales use escrow with built-in refund mechanism — funds locked until conditions met, buyers protected from rugpulls. Design implications: show escrow status (Funded/Running/Success/Failed), display refund eligibility, visualize lock period timeline. Design decisions: how much escrow complexity to expose — show full state machine or simplified status, balance transparency with cognitive load.","hasDetailedContent":true,"content":{"id":"ERC-5528","sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-5528","type":"official-spec"}],"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25","summary":"Token sales use escrow with built-in refund mechanism — funds locked until conditions met, buyers protected from rugpulls.","designerTakeaways":["You can show escrow status as a simple progress bar: Funded → Running → Success or Refund.","Your contributor view can display locked amount with expected release or refund date.","You can explain failed sales with a clear Your refund is available CTA instead of raw revert text."],"applicability":{"whenToUse":["Token launches use on-chain escrow with conditional release.","Buyers need protection when sale outcome is uncertain.","Your UI surfaces crowd-sale or IDO participation."],"whenToAvoid":["Direct swap or AMM purchases with no escrow phase.","Sale contracts do not implement ERC-5528.","Users only hold tokens post-settlement with no escrow period."]},"prototypeFirst":[{"screen":"Sale escrow dashboard","why":"Contributors check status repeatedly during a live sale.","covers":["Funded","Running","Cap reached"],"include":["Status pill","Locked amount","Timeline","Your contribution row"]},{"screen":"Failed sale refund","why":"The refund moment is when trust is won or lost.","covers":["Failed state","Refund available","Refund claimed"],"include":["Plain-language failure reason","Claim refund CTA","Amount returned"]},{"screen":"Successful settlement","why":"Users must see tokens received and escrow released.","covers":["Success","Token delivery","Escrow closed"],"include":["Tokens received summary","Escrow released badge","Explorer link"]},{"screen":"Contribution during lock","why":"New buyers need to understand funds are not immediately spendable.","covers":["Active lock","Cannot withdraw early"],"include":["Funds held securely copy","Release conditions","No panic empty-wallet state"]}],"mentalModel":[{"label":"Contribution","description":"User sends funds into escrow — they do not own tokens yet, they own a claim."},{"label":"Escrow lock","description":"Funds stay in the contract until success conditions or failure triggers refund."},{"label":"Success path","description":"Sale completes → tokens mint or transfer → escrow releases to project."},{"label":"Failure path","description":"Conditions unmet → contributors reclaim full contribution from escrow."},{"label":"State machine","description":"Funded, Running, Success, Failed are user-visible milestones, not internal enum names."}],"statesToDesign":[{"state":"Escrow funded — sale open","trigger":"User contributed; sale still accepting.","userNeed":"Know funds are locked but safe.","designResponse":"Show locked amount with Running status and sale end time."},{"state":"Awaiting outcome","trigger":"Sale closed; settlement pending.","userNeed":"Understand nothing is lost during processing.","designResponse":"Processing status with expected resolution window."},{"state":"Success — tokens received","trigger":"Sale succeeded.","userNeed":"See tokens and closed escrow.","designResponse":"Success card with token balance and escrow released note."},{"state":"Failed — refund available","trigger":"Sale failed conditions.","userNeed":"Get money back quickly and clearly.","designResponse":"Failed badge with Claim refund CTA and full amount."},{"state":"Refund claimed","trigger":"User reclaimed escrow.","userNeed":"Confirm funds returned.","designResponse":"Completed refund receipt with amount and timestamp."}],"designDecisions":[{"question":"How much escrow complexity to expose?","recommendation":"Show simplified four-state timeline; tuck contract addresses behind advanced.","rationale":"Contributors need confidence, not Solidity architecture."},{"question":"Should locked funds appear in wallet balance?","recommendation":"Show separate Escrowed line item, not merged with spendable balance.","rationale":"Merged balances cause panic sends and support tickets."},{"question":"How to communicate failed sales?","recommendation":"Lead with You get a full refund, then explain why the sale failed.","rationale":"Money-back clarity reduces FUD faster than technical reasons."}],"problemsSolved":[{"problem":"Token sale rug pulls","oldWay":"Funds sent directly to team wallet with no recourse","newWay":"Escrow holds funds until verifiable success conditions","impact":"critical"},{"problem":"Users think contributed ETH disappeared","oldWay":"Wallet shows lower balance with no explanation","newWay":"Escrowed amount labeled with status and release path","impact":"high"},{"problem":"Failed launches leave contributors stranded","oldWay":"Manual refunds or social pressure on team","newWay":"Automatic on-chain refund path when sale fails","impact":"high"}],"uxPatterns":[{"name":"Escrow Status Timeline","description":"Visual Funded → Running → Success/Failed progression.","mockup":"concept/verify-safety","components":["StatusTimeline","ContributionCard","LockAmount"],"userFlow":["User contributes","Timeline updates","Outcome resolves","Tokens or refund shown"]},{"name":"Claim Refund Flow","description":"One-tap refund when sale fails.","mockup":"concept/nft-gallery","components":["FailedBanner","RefundCTA","ReceiptModal"],"userFlow":["Sale fails","User sees refund available","Claims","Balance restored"]}],"seenInTheWild":[{"app":"CoinList","url":"https://coinlist.co/","note":"Token sale escrow patterns set user expectations for locked contributions."},{"app":"Fjord Foundry","url":"https://fjordfoundry.com/","note":"Fair launch interfaces show contribution and settlement states."},{"app":"ENS App","url":"https://app.ens.domains/","note":"Commit-reveal and escrow-adjacent deposit patterns inform timeline UX."},{"app":"Gitcoin","url":"https://gitcoin.co/","note":"Quadratic funding rounds use similar held-funds mental models."}],"antiPatterns":[{"pattern":"Showing zero balance with no escrow explanation","why":"Users assume funds were stolen","instead":"Separate Escrowed row with status and amount","severity":"critical"},{"pattern":"Hiding failed state behind generic transaction error","why":"Contributors cannot find refund path","instead":"Dedicated Failed sale screen with Claim refund","severity":"critical"},{"pattern":"Exposing raw state enum names (FUNDED, RUNNING)","why":"Protocol jargon erodes trust","instead":"Human labels: Sale open, Processing, Complete, Refunded","severity":"high"}],"vocabulary":[{"use":"Funds held safely","avoid":"Locked in escrow contract","why":"Reassurance over smart-contract vocabulary."},{"use":"Claim your refund","avoid":"Trigger refund()","why":"Action-oriented commerce language."},{"use":"Sale succeeded","avoid":"State SUCCESS","why":"Outcome language, not enum values."}],"onMonad":[{"aspect":"Settlement speed","ethereum":"Escrow resolution may take multiple blocks","monad":"Fast finality tightens feedback after sale closes","designImplication":"Prefer inline status updates over long polling modals."},{"aspect":"Contribution cost","ethereum":"Gas may deter small contributions","monad":"Lower fees enable broader participation tiers","designImplication":"Show micro-contribution options without gas warnings."}],"technicalNotes":"ERC-5528 escrow sales use explicit state machine; never merge escrowed funds with wallet spendable balance.","relatedStandards":[{"id":"ERC-5507","relationship":"NFT refund windows complement fungible escrow"},{"id":"ERC-20","relationship":"Fungible tokens sold through escrow mechanism"}]},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-5528","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-5528","type":"discussion"},{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-5528","type":"official-spec"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-5528","markdown":"https://www.eipsfordesigners.com/standards/ERC-5528/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-5528/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-5528","official":"https://eips.ethereum.org/EIPS/erc-5528","discussion":"https://ethereum-magicians.org/search?q=ERC-5528"},"freshness":{"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25"}},{"id":"ERC-6147","name":"Guard of NFT/SBT","status":"Final","chain":"both","category":{"id":"security","name":"Security & Trust","description":"Helping users verify, control, and protect their assets"},"journeyStages":[{"id":"management","name":"Asset Management","description":"Managing assets over time"}],"uxImpact":"NFT owners can set a 'guard' address that controls transfers — enables anti-theft (cold wallet guard), lending collateral, SBT recovery. Design implications: show 'Protected by Guard' indicator, display guard expiry, add guard management UI for setting/removing. Design decisions: how to communicate transfer restrictions — warning when guard active, explain why transfer button disabled, guard vs owner permission clarity.","hasDetailedContent":true,"content":{"id":"ERC-6147","summary":"ERC-6147 adds a \"guard\" role to NFTs that can prevent transfers even by the owner. Think of it as a freeze switch that protects against theft, enables recovery mechanisms, and supports safe lending. The guard can allow or block transfers without taking ownership, perfect for custodians, security services, or recovery systems.","applicability":{"whenToUse":["Your product addresses: stolen NFT can be transferred before owner reacts.","Your product addresses: no way to freeze NFT without giving up ownership.","The flow should deliver: guard blocks transfers, gives owner time to recover.","You are designing a guard status display experience with visible states and recovery paths."],"whenToAvoid":["Explain: \"Guard can block ALL transfers but cannot take ownership\".","Require expiration or backup recovery mechanism.","Prominent warning: \"This NFT has transfer restrictions\".","Wrong-address or approval mistakes are not recoverable in your product context."]},"designerTakeaways":["You can design UI that delivers guard blocks transfers, gives owner time to recover.","You can design UI that delivers guard can freeze while owner retains full ownership.","You can design UI that delivers set yourself as guard."],"problemsSolved":[{"problem":"Stolen NFT can be transferred before owner reacts","oldWay":"Thief immediately sells or transfers stolen NFT, owner loses it","newWay":"Guard blocks transfers, gives owner time to recover","impact":"critical"},{"problem":"No way to freeze NFT without giving up ownership","oldWay":"To prevent transfers, must transfer to custodian (lose ownership)","newWay":"Guard can freeze while owner retains full ownership","impact":"high"},{"problem":"Lending NFT risks losing it to bad actor","oldWay":"Lend to friend, they refuse to return it","newWay":"Set yourself as guard, can always recover even if \"owner\" changes","impact":"high"},{"problem":"No recovery mechanism for lost access","oldWay":"Lost wallet key = lost NFTs forever","newWay":"Trusted guard can facilitate recovery to new wallet","impact":"medium"}],"uxPatterns":[{"name":"Guard Status Display","description":"Show protection status on NFT","mockup":"concept/nft-gallery","userFlow":["User views guarded NFT","See protection status prominently","View who the guard is","Understand transfer restrictions","Can request transfer (guard must approve)","Feel secure against theft"]},{"name":"Set Guard Interface","description":"Enable protection by assigning guard","mockup":"concept/wallet","userFlow":["User wants to protect valuable NFT","Choose guard type","Select protection service or enter address","Review service details","Enable protection on-chain","NFT now requires guard approval for transfers"]},{"name":"Transfer Request Flow","description":"Request guard approval for transfer","mockup":"concept/nft-gallery","userFlow":["Owner initiates transfer of guarded NFT","System submits request to guard","Guard verifies ownership","Optional cooldown period","Guard approves or denies","Transfer completes if approved"]},{"name":"Guard Dashboard","description":"Guard manages protected NFTs","mockup":"concept/nft-gallery","userFlow":["Guard opens dashboard","See all protected NFTs","Review pending transfer requests","Approve legitimate transfers","Emergency lock if theft reported","Manage protection settings"]}],"uiComponents":[{"name":"GuardStatusIndicator","description":"Shows protection status on NFT","states":["unguarded","guarded","locked","pending-transfer"],"props":["guard","expiration","status"]},{"name":"SetGuardForm","description":"UI for assigning guard to NFT","states":["selecting","confirming","setting","active"],"props":["nft","guardOptions","onSetGuard"]},{"name":"TransferRequestFlow","description":"Request and track transfer approval","states":["requesting","pending","approved","denied"],"props":["nft","recipient","guard","status"]},{"name":"GuardControlPanel","description":"Guard manages protected assets","states":["idle","reviewing","locking","unlocking"],"props":["guardedNFTs","pendingRequests","onAction"]}],"antiPatterns":[{"pattern":"Not explaining what guard role means","why":"Users don't understand the power they're granting","instead":"Explain: \"Guard can block ALL transfers but cannot take ownership\"","severity":"critical"},{"pattern":"Setting guard without recovery option","why":"If guard address is lost, NFT stuck forever","instead":"Require expiration or backup recovery mechanism","severity":"critical"},{"pattern":"Hiding guard status on marketplaces","why":"Buyer doesn't know they can't transfer after purchase","instead":"Prominent warning: \"This NFT has transfer restrictions\"","severity":"critical"},{"pattern":"Making transfer requests confusing","why":"Users don't understand the approval process","instead":"Clear step-by-step: request → verification → approval → transfer","severity":"high"},{"pattern":"No emergency lock for theft situations","why":"Guard can't react fast enough to theft","instead":"Instant lock capability for guards, unlock requires verification","severity":"high"}],"onMonad":[{"aspect":"Guard Actions","ethereum":"Lock/unlock takes 15+ seconds","monad":"Sub-second guard actions","designImplication":"Emergency locks can be truly instant"},{"aspect":"Transfer Approval","ethereum":"Approval + transfer = 2 slow transactions","monad":"Both actions feel instant","designImplication":"Smoother transfer request flow"},{"aspect":"Status Queries","ethereum":"Checking guard status can be slow","monad":"Instant guard status checks","designImplication":"Real-time protection status in all views"},{"aspect":"Batch Protection","ethereum":"Guarding multiple NFTs is expensive/slow","monad":"Batch guard assignment practical","designImplication":"Protect entire collection with one action"}],"keyTakeaways":["ERC-6147 = guard role can block transfers without ownership","Perfect for theft protection and recovery","Always explain guard powers clearly to users","Show guard status prominently on marketplaces","On Monad: instant emergency locks for theft response"],"technicalNotes":"ERC-6147 extends ERC-721 with setGuard(tokenId, guard) and getGuard(tokenId). When a guard is set, transferFrom checks guard approval before executing. Guard can call approve transfers or remove themselves. The standard includes an optional expires field for time-limited guard assignments. Works with soulbound tokens for permanent non-transferability."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-6147","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-6147","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-6147","markdown":"https://www.eipsfordesigners.com/standards/ERC-6147/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-6147/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-6147","official":"https://eips.ethereum.org/EIPS/eip-6147","discussion":"https://ethereum-magicians.org/search?q=ERC-6147"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"ERC-5375","name":"Author NFTs","status":"Final","chain":"both","category":{"id":"security","name":"Security & Trust","description":"Helping users verify, control, and protect their assets"},"journeyStages":[{"id":"authentication","name":"Authentication & Identity","description":"Proving who you are and logging in"}],"uxImpact":"NFT metadata includes verified author consent signatures — proves creator agreed to be credited, prevents fake attributions. Design implications: show 'Verified Author' badge with proof link, display multiple co-authors, indicate consent verification status. Design decisions: how to handle unverified vs verified authors — warning indicators, whether to allow display of unverified claims.","hasDetailedContent":true,"content":{"id":"ERC-5375","summary":"ERC-5375 provides a standard way to cryptographically prove who created an NFT. The creator signs the token metadata or creation transaction, and this signature is stored with the NFT. Anyone can verify that the claimed author actually approved this specific NFT, preventing fake collections and impersonation.","applicability":{"whenToUse":["Your product addresses: no way to verify if NFT is from the claimed creator.","Your product addresses: fake collections impersonate famous artists.","The flow should deliver: cryptographic signature proves specific address created this NFT.","You are designing a verified creator badge experience with visible states and recovery paths."],"whenToAvoid":["Require cryptographic signature from actual creator.","Clear verified vs unverified indicators on every NFT.","Always show \"Verify Authorship\" option, even if unverified.","Wrong-address or approval mistakes are not recoverable in your product context."]},"designerTakeaways":["You can design UI that delivers cryptographic signature proves specific address created this NFT.","You can design UI that delivers verify signature against known artist address.","You can design UI that delivers multiple author signatures prove each collaborator approved."],"problemsSolved":[{"problem":"No way to verify if NFT is from the claimed creator","oldWay":"Trust collection name, check social media, hope it's real","newWay":"Cryptographic signature proves specific address created this NFT","impact":"critical"},{"problem":"Fake collections impersonate famous artists","oldWay":"Scammers create \"Official Beeple\" collection, buyers fooled","newWay":"Verify signature against known artist address, fakes exposed","impact":"critical"},{"problem":"Collaborations have no provable attribution","oldWay":"Metadata says \"by Alice and Bob\" but no proof","newWay":"Multiple author signatures prove each collaborator approved","impact":"high"},{"problem":"Creator identity can't be verified post-purchase","oldWay":"Original listing is gone, can't prove authenticity","newWay":"Signature is on-chain forever, always verifiable","impact":"high"}],"uxPatterns":[{"name":"Verified Creator Badge","description":"Show proof of authorship on NFT displays","mockup":"concept/nft-gallery","userFlow":["User views NFT page","See \"Created by\" section","Verified checkmark indicates signature exists","Click to see signature proof","Signature verified against creator address","Trust the attribution is genuine"]},{"name":"Signature Verification Panel","description":"Deep dive into authorship proof","mockup":"concept/verify-safety","userFlow":["User wants to verify authorship","Open verification panel","See exact data that was signed","See signature and recovered address","Confirm address matches claimed creator","Option to verify independently"]},{"name":"Multi-Author Attribution","description":"Show multiple collaborator signatures","mockup":"concept/nft-gallery","userFlow":["User views collaborative NFT","See list of all collaborators","Each shows their role in creation","Each has verified signature","Click to see individual proofs","Trust all listed creators participated"]},{"name":"Collection Verification","description":"Verify entire collection is from claimed creator","mockup":"concept/verify-safety","userFlow":["User encounters suspicious collection","Check verification status","See warning: no author signature","Deployer address doesn't match","Link to genuine collection for comparison","Avoid potential scam"]}],"uiComponents":[{"name":"AuthorVerificationBadge","description":"Shows author verification status","states":["verified","unverified","checking","invalid"],"props":["signature","expectedAuthor","onVerify"]},{"name":"SignatureProofPanel","description":"Detailed signature verification display","states":["collapsed","expanded","verifying"],"props":["signedData","signature","recoveredAddress"]},{"name":"CollaboratorList","description":"Lists multiple verified authors","states":["loading","loaded","partial-verified"],"props":["authors","roles","signatures"]},{"name":"FakeCollectionWarning","description":"Alert for unverified/suspicious collections","states":["warning","danger","suspicious"],"props":["claimedCreator","actualDeployer","hasSignature"]}],"antiPatterns":[{"pattern":"Treating deployer address as creator","why":"Anyone can deploy a contract claiming to be someone","instead":"Require cryptographic signature from actual creator","severity":"critical"},{"pattern":"Not showing verification status prominently","why":"Users assume all NFTs are verified, get scammed","instead":"Clear verified vs unverified indicators on every NFT","severity":"critical"},{"pattern":"Hiding that verification is available","why":"Users don't know they can check authorship","instead":"Always show \"Verify Authorship\" option, even if unverified","severity":"high"},{"pattern":"Complex signature verification UI","why":"Only technical users can verify, others still at risk","instead":"Simple verified/unverified badge with optional deep dive","severity":"high"},{"pattern":"Not warning about missing signatures","why":"Users don't know unverified = higher risk","instead":"Show warning: \"This NFT has no authorship proof\"","severity":"medium"}],"onMonad":[{"aspect":"Verification Speed","ethereum":"Signature verification queries take 1-3 seconds","monad":"Instant verification responses","designImplication":"Can verify every NFT in a gallery view, not just on click"},{"aspect":"Batch Verification","ethereum":"Verifying collection of 100 NFTs is slow/expensive","monad":"Batch verify entire collections quickly","designImplication":"\"Verify all NFTs in collection\" feature practical"},{"aspect":"Multi-Author","ethereum":"Many signatures = many slow checks","monad":"Multi-author verification still instant","designImplication":"Complex collaborations verified as fast as single author"},{"aspect":"Storage","ethereum":"Storing signatures on-chain is expensive","monad":"Lower costs make on-chain signatures more practical","designImplication":"More NFTs can have author signatures stored on-chain"}],"keyTakeaways":["ERC-5375 = cryptographic proof of NFT authorship","Creator signature stored with NFT, verifiable forever","Show verified/unverified status prominently","Warn users when author signature is missing","On Monad: instant verification enables batch checking"],"technicalNotes":"ERC-5375 stores an author signature in NFT metadata or on-chain. The signature is over a hash of the token URI (or specific metadata fields). Verification recovers the signer address and compares to the claimed author. Multiple signatures support collaborations. The standard is compatible with EIP-712 typed data signing for readable author signing flows."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-5375","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-5375","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-5375","markdown":"https://www.eipsfordesigners.com/standards/ERC-5375/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-5375/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-5375","official":"https://eips.ethereum.org/EIPS/eip-5375","discussion":"https://ethereum-magicians.org/search?q=ERC-5375"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"ERC-7007","name":"Verifiable AI-Generated Content Token","status":"Draft","chain":"both","category":{"id":"security","name":"Security & Trust","description":"Helping users verify, control, and protect their assets"},"journeyStages":[{"id":"specialized","name":"Specialized Interactions","description":"Physical items, AI, social, gaming"}],"uxImpact":"AI-generated NFTs include cryptographic proof linking output to specific model and prompt — verifiable provenance for AI art. Design implications: show 'AI-Generated' label with model info, display original prompt, add 'Verify Proof' button. Design decisions: how prominent to make AI disclosure — regulatory requirements vs aesthetic concerns, whether to filter/highlight AI content separately.","hasDetailedContent":true,"content":{"id":"ERC-7007","sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-7007","type":"official-spec"}],"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25","summary":"AI-generated NFTs include cryptographic proof linking output to specific model and prompt — verifiable provenance for AI art.","designerTakeaways":["You can show AI-Generated labels with model name and a Verify proof action on every eligible item.","Your detail pages can display the original prompt behind an expandable section for collectors who care.","You can offer marketplace filters for AI vs human-made without shaming either category."],"applicability":{"whenToUse":["Platform sells or displays AI-generated NFTs.","Regulatory or community norms require AI disclosure.","Provenance verification is a collector feature."],"whenToAvoid":["Collection is exclusively human-made with no AI pipeline.","Proof infrastructure is not wired to your indexer.","Draft spec risk is unacceptable for production claims."]},"prototypeFirst":[{"screen":"AI provenance detail panel","why":"Collectors decide authenticity at the item page.","covers":["Verified proof","Missing proof","Tampered proof"],"include":["Model name","Prompt expander","Verify button","Proof status chip"]},{"screen":"Gallery with AI filter","why":"Browsers need to discover or avoid AI content intentionally.","covers":["Filter on","Filter off","Mixed grid"],"include":["AI-Generated chip","Filter toggle","Empty filter state"]},{"screen":"Mint disclosure step","why":"Creators must attest AI use before listing.","covers":["AI mint","Non-AI mint"],"include":["Disclosure checkbox","Model selector","Preview label"]},{"screen":"Verify proof result","why":"Verification must feel definitive, not technical.","covers":["Valid","Invalid","Unavailable"],"include":["Green verified or red failed","Plain explanation","Link to spec"]}],"mentalModel":[{"label":"Generation record","description":"Model + prompt + parameters produce an output that gets hashed and linked to the token."},{"label":"On-chain proof","description":"The token carries a verifiable claim that this output matches that generation record."},{"label":"Verification","description":"Anyone can re-check the proof — trust moves from brand promise to math."},{"label":"Disclosure","description":"AI-Generated is a transparency label, not a quality judgment."},{"label":"Creator attestation","description":"Minter submits proof at mint; marketplaces inherit the label from chain data."}],"statesToDesign":[{"state":"Verified AI provenance","trigger":"Proof checks pass.","userNeed":"Trust the AI label.","designResponse":"Verified badge with model info and optional prompt preview."},{"state":"Unverified or missing proof","trigger":"Token lacks valid proof.","userNeed":"Not be misled about origin.","designResponse":"No AI badge; optional Unknown provenance warning for claimed AI pieces."},{"state":"Proof verification failed","trigger":"Hash or model mismatch.","userNeed":"Understand label is unreliable.","designResponse":"Verification failed banner; do not show verified AI chip."},{"state":"Prompt hidden by creator","trigger":"Proof valid but prompt redacted.","userNeed":"Know proof exists without seeing prompt.","designResponse":"Verified with prompt private note."},{"state":"Regulatory filter active","trigger":"User filters to human-only art.","userNeed":"Clean results without AI items.","designResponse":"Filter excludes unverified and verified AI; show count removed."}],"designDecisions":[{"question":"How prominent should AI labels be?","recommendation":"Chip on thumbnail plus detail panel; avoid full-overlay warnings on art.","rationale":"Disclosure must be visible without vandalizing the artwork."},{"question":"Show prompt by default?","recommendation":"Collapsed behind View prompt; never auto-expand on gallery cards.","rationale":"Prompts can be long, personal, or spoil the piece."},{"question":"Filter AI content separately?","recommendation":"Offer optional filter and sort, default to show all with labels.","rationale":"Hiding by default angers creators; unlabeled browsing hides disclosure."}],"problemsSolved":[{"problem":"Fake human-made claims for AI art","oldWay":"Metadata says artist with no proof","newWay":"Verifiable link from token to model and prompt","impact":"high"},{"problem":"Regulatory AI disclosure gaps","oldWay":"Platforms guess from metadata","newWay":"Standardized on-chain provenance fields","impact":"high"},{"problem":"Collectors cannot audit origin","oldWay":"Trust the marketplace description","newWay":"One-click verify proof on detail page","impact":"medium"}],"uxPatterns":[{"name":"AI Provenance Panel","description":"Model, proof status, and verify action on NFT detail.","mockup":"concept/agent-task","components":["AIChip","ModelRow","VerifyButton","PromptExpander"],"userFlow":["User opens NFT","Sees AI-Generated","Taps Verify","Result shown"]},{"name":"AI Content Filter","description":"Gallery toggle for AI-labeled items.","mockup":"concept/nft-gallery","components":["FilterToggle","LabeledThumbnail","EmptyState"],"userFlow":["User opens gallery","Toggles AI filter","Grid updates","Labels remain on items"]}],"seenInTheWild":[{"app":"OpenSea","url":"https://opensea.io/","note":"Content credentials and AI disclosure patterns emerging on major marketplaces."},{"app":"Foundation","url":"https://foundation.app/","note":"Creator-centric provenance display sets bar for authenticity UI."},{"app":"Art Blocks","url":"https://www.artblocks.io/","note":"Generative art platforms already expose algorithm provenance to collectors."},{"app":"C2PA","url":"https://c2pa.org/","note":"Cross-industry content credentials inform AI disclosure UX."}],"antiPatterns":[{"pattern":"AI label without verify path","why":"Unverifiable claims are worthless","instead":"Show Verify proof or omit verified badge","severity":"critical"},{"pattern":"Hiding AI status in metadata only","why":"Buyers never see disclosure before purchase","instead":"Thumbnail chip visible in browse and checkout","severity":"high"},{"pattern":"Scare-banner overlay on all AI art","why":"Alienates legitimate AI creators","instead":"Neutral AI-Generated chip with optional detail","severity":"medium"}],"vocabulary":[{"use":"AI-generated","avoid":"Synthetic token mint","why":"Plain disclosure language."},{"use":"Verify proof","avoid":"Validate zk attestation","why":"User action, not cryptography lecture."},{"use":"Created with [model]","avoid":"Inference pipeline ID","why":"Human-readable model naming."}],"onMonad":[{"aspect":"Verification cost","ethereum":"On-chain verify may be gas-heavy","monad":"Lower fees enable verify-on-view in gallery","designImplication":"Offer inline verify without discouraging clicks."},{"aspect":"AI mint throughput","ethereum":"Batch AI drops congested","monad":"Higher throughput supports large generative drops","designImplication":"Design for rapid mint status updates during AI launches."}],"technicalNotes":"ERC-7007 is draft; pair visible disclosure with working verify infrastructure before production claims.","relatedStandards":[{"id":"ERC-721","relationship":"NFT base extended with AI provenance fields"},{"id":"ERC-4906","relationship":"Metadata updates when proof is amended"}]},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-7007","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-7007","type":"discussion"},{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-7007","type":"official-spec"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-7007","markdown":"https://www.eipsfordesigners.com/standards/ERC-7007/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-7007/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-7007","official":"https://eips.ethereum.org/EIPS/erc-7007","discussion":"https://ethereum-magicians.org/search?q=ERC-7007"},"freshness":{"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25"}},{"id":"ERC-7439","name":"Prevent Ticket Touting","status":"Draft","chain":"both","category":{"id":"security","name":"Security & Trust","description":"Helping users verify, control, and protect their assets"},"journeyStages":[{"id":"specialized","name":"Specialized Interactions","description":"Physical items, AI, social, gaming"}],"uxImpact":"Event tickets can only be transferred through authorized resellers — prevents scalping, enables price caps on secondary sales. Design implications: show 'Official Resale Only' indicator, direct to authorized resale channels, display ticket status (Sold/Resell/Void/Redeemed). Design decisions: how to handle unauthorized transfer attempts — educational messaging about why blocked, clear path to legitimate resale options.","hasDetailedContent":true,"content":{"id":"ERC-7439","sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-7439","type":"official-spec"}],"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25","summary":"Event tickets can only be transferred through authorized resellers — prevents scalping, enables price caps on secondary sales.","designerTakeaways":["You can badge Official resale only on every ticket before first purchase.","Your transfer UI can route fans to authorized resale instead of a disabled send button with no path.","You can show ticket lifecycle status so fans know if a pass is valid, listed, or already scanned."],"applicability":{"whenToUse":["Event tickets are NFTs with anti-scalping policy.","Primary issuer controls authorized resale network.","Transfer restrictions are enforced on-chain."],"whenToAvoid":["Collectible tickets meant to trade freely on open marketplaces.","Contract does not implement ERC-7439 transfer hooks.","Jurisdiction forbids transfer restrictions you must disclose."]},"prototypeFirst":[{"screen":"Ticket purchase with resale policy","why":"Fans must accept resale rules before paying.","covers":["Policy summary","Authorized partners"],"include":["Official resale only badge","Price cap explanation","Partner marketplace links"]},{"screen":"Blocked peer transfer","why":"The most rage-inducing moment needs education, not silence.","covers":["Transfer blocked","Education modal"],"include":["Why blocked copy","Go to official resale CTA","Support link"]},{"screen":"Official resale listing","why":"Legitimate resale must feel easier than gray market.","covers":["List for resale","Cap enforced","Sold through partner"],"include":["Max price display","Partner picker","Listing confirmation"]},{"screen":"Venue redemption scan","why":"Door staff and fans need Redeemed vs Valid at a glance.","covers":["Valid","Redeemed","Void"],"include":["Large status badge","QR display","Scan timestamp"]}],"mentalModel":[{"label":"Ticket NFT","description":"A token representing event entry with lifecycle state, not just art."},{"label":"Authorized resale","description":"Only approved marketplaces can change ownership — caps and fees apply."},{"label":"Transfer block","description":"Wallet-to-wallet sends revert; this is policy, not a bug."},{"label":"Redemption","description":"Scanning at venue marks ticket used — resale typically ends."},{"label":"Void state","description":"Cancelled or fraudulent tickets must show unusable clearly."}],"statesToDesign":[{"state":"Valid — not yet used","trigger":"Ticket owned, event upcoming.","userNeed":"See date, seat, and resale options.","designResponse":"Valid badge with Resell officially CTA if allowed."},{"state":"Listed on official resale","trigger":"User listed through partner.","userNeed":"Track listing without losing entry proof.","designResponse":"Listed for resale status with cancel listing action."},{"state":"Transfer blocked","trigger":"User attempts unauthorized send.","userNeed":"Understand why and what to do.","designResponse":"Modal explaining policy with partner link."},{"state":"Redeemed at venue","trigger":"Ticket scanned.","userNeed":"Confirm entry used; no false hope of resale.","designResponse":"Redeemed badge; gray card in wallet."},{"state":"Void or cancelled","trigger":"Event cancelled or ticket invalidated.","userNeed":"Know refund or replacement path.","designResponse":"Void badge with issuer message and refund CTA if applicable."}],"designDecisions":[{"question":"How to handle unauthorized transfer attempts?","recommendation":"Block with educational modal and official resale link, never silent disabled button.","rationale":"Fans blame the app unless policy is explained at failure moment."},{"question":"Show price caps in UI?","recommendation":"Display max resale price before listing.","rationale":"Cap surprises cause abandoned listings and support load."},{"question":"Peer-to-peer send button at all?","recommendation":"Hide or replace with Resell officially; do not show broken Send.","rationale":"Visible but disabled Send feels like a bug."}],"problemsSolved":[{"problem":"Scalpers arbitrage fan tickets","oldWay":"Open transfers to highest bidder instantly","newWay":"Authorized resale with price caps and audit trail","impact":"critical"},{"problem":"Fans buy invalid or duplicate tickets","oldWay":"Gray market with no issuer verification","newWay":"On-chain status shows Valid, Listed, or Redeemed","impact":"high"},{"problem":"Surprise blocks at transfer time","oldWay":"Marketplaces allow list then fail on chain","newWay":"Policy visible at purchase and resale entry","impact":"high"}],"uxPatterns":[{"name":"Official Resale Router","description":"Replace send with partner resale flow.","mockup":"concept/reactions","components":["ResaleBadge","PartnerLink","PriceCapLabel"],"userFlow":["User taps Resell","Sees cap and partner","Lists officially","Buyer purchases through channel"]},{"name":"Transfer Block Education","description":"Explain policy when unauthorized send attempted.","mockup":"concept/verify-safety","components":["BlockModal","PolicySummary","ResaleCTA"],"userFlow":["User tries send","Modal explains","Routes to resale","User lists instead"]}],"seenInTheWild":[{"app":"Ticketmaster","url":"https://www.ticketmaster.com/","note":"Official resale and face-value cap patterns fans already understand."},{"app":"GET Protocol","url":"https://www.get-protocol.io/","note":"NFT ticketing with controlled secondary market."},{"app":"SeatGeek","url":"https://seatgeek.com/","note":"Ticket status and verified resale UX reference."},{"app":"Coachella NFT","url":"https://www.coachella.com/","note":"Festival NFT experiments inform redemption status display."}],"antiPatterns":[{"pattern":"Disabled Send with no explanation","why":"Users think wallet is broken","instead":"Official resale only label and guided resale CTA","severity":"critical"},{"pattern":"Allowing OpenSea list then on-chain fail","why":"Wasted gas and rage quits","instead":"Pre-check transfer rights before listing UI","severity":"critical"},{"pattern":"Hiding resale caps until checkout","why":"Fans abandon when cap lower than expected","instead":"Show max resale price on ticket detail","severity":"high"}],"vocabulary":[{"use":"Official resale","avoid":"Whitelisted transfer destination","why":"Fan-friendly policy language."},{"use":"Ticket used","avoid":"Redeemed state flag","why":"Venue language over enum names."},{"use":"Face-value cap","avoid":"Max transfer price parameter","why":"Policy users understand from traditional ticketing."}],"onMonad":[{"aspect":"Redemption speed","ethereum":"Scan confirmation may lag","monad":"Fast finality updates Valid → Redeemed instantly at gate","designImplication":"Gate apps can show live status without refresh anxiety."},{"aspect":"Resale listing cost","ethereum":"Listing gas adds friction","monad":"Lower fees make official resale competitive with gray market","designImplication":"Emphasize free or cheap official resale in copy."}],"technicalNotes":"ERC-7439 is draft; surface resale policy before primary sale and pre-check transfers before marketplace listing.","relatedStandards":[{"id":"ERC-721","relationship":"Ticket represented as NFT with transfer hooks"},{"id":"ERC-6454","relationship":"Transfer restriction detection complement"}]},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-7439","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-7439","type":"discussion"},{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-7439","type":"official-spec"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-7439","markdown":"https://www.eipsfordesigners.com/standards/ERC-7439/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-7439/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-7439","official":"https://eips.ethereum.org/EIPS/erc-7439","discussion":"https://ethereum-magicians.org/search?q=ERC-7439"},"freshness":{"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25"}},{"id":"ERC-7820","name":"Access Control Registry","status":"Draft","chain":"both","category":{"id":"security","name":"Security & Trust","description":"Helping users verify, control, and protect their assets"},"journeyStages":[{"id":"approving","name":"Approving & Permissioning","description":"Granting permissions for actions"}],"uxImpact":"Centralized registry manages roles across multiple contracts — admins grant/revoke permissions from single dashboard. Design implications: build unified permission management UI, show role assignments across contracts, display audit trail of permission changes. Design decisions: how granular to make role visibility — show all roles or just relevant ones, balance admin power with principle of least privilege.","hasDetailedContent":true,"content":{"id":"ERC-7820","summary":"ERC-7820 adds role-based access control to NFTs. Instead of just \"owner\" and \"approved\", tokens can have multiple roles like admin, operator, minter, and burner. Each role has specific permissions, and users can delegate specific abilities without giving full control. Think file permissions but for NFTs.","applicability":{"whenToUse":["Your product addresses: nFT permissions are all-or-nothing.","Your product addresses: dAOs can't manage NFTs with nuanced permissions.","The flow should deliver: grant specific roles: \"can transfer\" but not \"can burn\".","You are designing a role management dashboard experience with visible states and recovery paths."],"whenToAvoid":["Show friendly names: \"🎨 Can Create New NFTs\".","List specific permissions for each role.","Show all role holders prominently.","Wrong-address or approval mistakes are not recoverable in your product context."]},"designerTakeaways":["You can design UI that delivers grant specific roles: \"can transfer\" but not \"can burn\".","You can design UI that delivers treasury manager can transfer, but only admin can burn.","You can design UI that delivers platform gets \"lend\" permission only, can't sell."],"problemsSolved":[{"problem":"NFT permissions are all-or-nothing","oldWay":"Approve = full control over the NFT, can't limit","newWay":"Grant specific roles: \"can transfer\" but not \"can burn\"","impact":"critical"},{"problem":"DAOs can't manage NFTs with nuanced permissions","oldWay":"One multisig owns everything, bottleneck","newWay":"Treasury manager can transfer, but only admin can burn","impact":"high"},{"problem":"Rental/lending permissions too broad","oldWay":"Give rental platform full approval","newWay":"Platform gets \"lend\" permission only, can't sell","impact":"high"},{"problem":"No audit trail of who can do what","oldWay":"Check approvals manually, no clear role structure","newWay":"Query roles directly: \"who has minter role?\"","impact":"medium"}],"uxPatterns":[{"name":"Role Management Dashboard","description":"View and manage roles for an NFT or collection","mockup":"concept/nft-gallery","userFlow":["View all roles for NFT/collection","See who has which permissions","Revoke roles with one click","Add new role assignments","View role capabilities"]},{"name":"Grant Role Flow","description":"Assign specific permission to an address","mockup":"concept/nft-gallery","userFlow":["Select role type to grant","See what permissions it includes","Enter recipient address","Confirm what they CAN'T do","Sign transaction to grant"]},{"name":"Role-Gated Actions","description":"Show available actions based on user's role","mockup":"concept/nft-gallery","userFlow":["User views NFT they have role for","Show their specific role","List what they CAN do","Show what they CANNOT do and why","Only enabled buttons for permitted actions"]},{"name":"Collection Role Admin","description":"Manage roles at collection level","mockup":"concept/nft-gallery","userFlow":["Admin views collection roles","See all role holders grouped by role","Add new role holders","Bulk revoke if needed","Audit complete permission structure"]}],"uiComponents":[{"name":"RoleBadge","description":"Visual indicator of a role type","states":["active","pending","revoked"],"props":["roleType","icon","color"]},{"name":"PermissionMatrix","description":"Grid showing what each role can do","states":["viewing","editing"],"props":["roles[]","permissions[]","assignments{}"]},{"name":"RoleAssignmentForm","description":"Form for granting roles to addresses","states":["selecting-role","entering-address","confirming","granting"],"props":["availableRoles[]","onGrant"]},{"name":"RoleAuditLog","description":"History of role changes","states":["loading","loaded"],"props":["events[]","filters"]}],"antiPatterns":[{"pattern":"Using technical role names","why":"\"MINTER_ROLE\" means nothing to most users","instead":"Show friendly names: \"🎨 Can Create New NFTs\"","severity":"critical"},{"pattern":"Not explaining what each role allows","why":"Users grant roles without understanding implications","instead":"List specific permissions for each role","severity":"high"},{"pattern":"Hiding roles granted to others","why":"Owners don't know who has access to their NFTs","instead":"Show all role holders prominently","severity":"high"},{"pattern":"No revocation UI","why":"Users can't easily remove permissions","instead":"One-click revoke with confirmation","severity":"medium"}],"onMonad":[{"aspect":"Role Queries","ethereum":"Checking roles costs gas","monad":"Cheap reads for real-time role checks","designImplication":"Can show live role status without caching"},{"aspect":"Granting Speed","ethereum":"Role grants take 15+ seconds","monad":"Sub-second role assignment","designImplication":"Role changes feel instant, can enable quick permission adjustments"},{"aspect":"Bulk Operations","ethereum":"Granting multiple roles very expensive","monad":"Bulk role management affordable","designImplication":"Can offer \"Grant roles to multiple addresses\" features"},{"aspect":"Audit Trail","ethereum":"Fetching role history expensive","monad":"Fast event queries for audit logs","designImplication":"Can show complete role change history"}],"keyTakeaways":["Roles = granular permissions beyond just \"approved\"","Show what each role CAN and CANNOT do clearly","Make role holders visible to NFT owners","Provide easy revocation UI","On Monad: fast/cheap enables real-time role management"],"technicalNotes":"ERC-7820 defines standard roles (admin, operator, minter, burner) and allows custom roles. The contract stores role→address mappings with methods to grant, revoke, and check roles. Roles can be per-token or collection-wide. The standard integrates with ERC-721's approval system, with roles taking precedence for finer control."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-7820","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-7820","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-7820","markdown":"https://www.eipsfordesigners.com/standards/ERC-7820/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-7820/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-7820","official":"https://eips.ethereum.org/EIPS/eip-7820","discussion":"https://ethereum-magicians.org/search?q=ERC-7820"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"EIP-5496","name":"Multi-privilege Management NFT","status":"Last Call","chain":"both","category":{"id":"security","name":"Security & Trust","description":"Helping users verify, control, and protect their assets"},"journeyStages":[{"id":"approving","name":"Approving & Permissioning","description":"Granting permissions for actions"}],"uxImpact":"NFTs carry multiple transferable privileges (discounts, access, votes) that can be shared or assigned separately from ownership. Design implications: show privilege list with individual expiry dates, add 'Share Privilege' action, display privilege holder vs token owner. Design decisions: how to visualize privilege spreading/cloning — referral tree view, privilege inheritance tracking, balance utility discovery with UI complexity.","hasDetailedContent":true,"content":{"id":"EIP-5496","summary":"EIP-5496 lets a single NFT carry multiple distinct privileges. Instead of one NFT = one permission, you can track \"VIP access,\" \"backstage pass,\" \"merch discount,\" and \"meet & greet\" all on the same token. Each privilege can be granted, revoked, or transferred independently. Perfect for event tickets, membership cards, and subscription bundles where users expect multiple perks from one token.","applicability":{"whenToUse":["Your product addresses: nFTs represent only single permissions.","Your product must handle: can't grant temporary access without full transfer.","The flow should deliver: one NFT holds all privileges as separate attributes.","You are designing a multi-privilege nft card experience with visible states and recovery paths."],"whenToAvoid":["Clear \"delegated to X\" indicator on each privilege.","Pre-check expiry and warn before user tries to use.","Prominent revoke button next to each delegation.","Wrong-address or approval mistakes are not recoverable in your product context."]},"designerTakeaways":["You can design UI that delivers one NFT holds all privileges as separate attributes.","You can design UI that delivers grant specific privilege to someone without transferring NFT.","You can standard hasPrivilege(tokenId, privilegeId) check."],"problemsSolved":[{"problem":"NFTs represent only single permissions","oldWay":"Need separate NFTs for VIP access, parking, and merch discount","newWay":"One NFT holds all privileges as separate attributes","impact":"critical"},{"problem":"Can't grant temporary access without full transfer","oldWay":"Lend entire NFT (and all privileges) or nothing","newWay":"Grant specific privilege to someone without transferring NFT","impact":"high"},{"problem":"No standard way to check multiple perks","oldWay":"Custom logic per project to track entitlements","newWay":"Standard hasPrivilege(tokenId, privilegeId) check","impact":"high"},{"problem":"Privileges can't expire independently","oldWay":"Whole NFT valid or invalid, no per-perk expiry","newWay":"Each privilege has its own expiration timestamp","impact":"medium"},{"problem":"Hard to revoke specific access without burning NFT","oldWay":"Must issue new NFT with reduced privileges","newWay":"Revoke individual privilege, keep others intact","impact":"medium"}],"uxPatterns":[{"name":"Multi-Privilege NFT Card","description":"Display all privileges on a single NFT","mockup":"concept/nft-gallery","userFlow":["User views their NFT","UI queries all privilege IDs for token","Fetches status/expiry for each privilege","Displays clear list with visual indicators","Used/expired privileges shown differently"]},{"name":"Privilege Delegation","description":"Grant specific privilege to another user","mockup":"generic/vault-deposit","userFlow":["User selects NFT to share from","Picks specific privilege to delegate","Enters recipient address","Sets duration/expiry for delegation","Confirms transaction","Recipient gains privilege access"]},{"name":"Privilege Verification Gate","description":"Check privilege at entry point","mockup":"concept/wallet","userFlow":["Gate displays required privilege","User scans QR or connects wallet","System checks hasPrivilege()","Verifies not expired","Shows if direct ownership or delegated","Grants or denies access"]},{"name":"Privilege Management Dashboard","description":"View and manage all delegations","mockup":"generic/token-transfer","userFlow":["User opens privilege manager","Sees all outgoing delegations","Can revoke any active delegation","Sees received delegations from others","Can create new delegations"]}],"uiComponents":[{"name":"PrivilegeBadge","description":"Visual indicator for a single privilege status","states":["active","expiring-soon","expired","used","delegated"],"props":["privilegeId","name","expiresAt","isDelegated"]},{"name":"PrivilegeTimeline","description":"Visual timeline of privilege validity","states":["before","active","ended"],"props":["startDate","endDate","privilegeName"]},{"name":"DelegationCard","description":"Shows delegation details with revoke option","states":["active","expiring","revoked"],"props":["privilege","delegatee","expiresAt","onRevoke"]},{"name":"PrivilegeVerifier","description":"Real-time privilege checking component","states":["checking","verified","denied","expired"],"props":["tokenId","privilegeId","address"]}],"antiPatterns":[{"pattern":"Not showing which privileges are delegated vs owned","why":"Users confused about what they can actually use vs lend","instead":"Clear \"delegated to X\" indicator on each privilege","severity":"critical"},{"pattern":"Allowing privilege use after expiry without clear error","why":"Frustrating when access fails at the gate","instead":"Pre-check expiry and warn before user tries to use","severity":"high"},{"pattern":"No revocation UI for delegated privileges","why":"Users can't retract access they granted","instead":"Prominent revoke button next to each delegation","severity":"high"},{"pattern":"Bundling all privileges into one indistinguishable token","why":"Users can't see or manage individual perks","instead":"Itemized privilege list with individual management","severity":"medium"},{"pattern":"Not showing remaining uses for consumable privileges","why":"User doesn't know if they have uses left","instead":"Show \"2/5 uses remaining\" for limited privileges","severity":"medium"}],"onMonad":[{"aspect":"Delegation Speed","ethereum":"Delegating a privilege may take 15+ seconds","monad":"Sub-second finality for instant delegation","designImplication":"Sharing privilege can feel instant, like sharing a link"},{"aspect":"Verification at Scale","ethereum":"Multiple privilege checks may be slow/expensive","monad":"Fast parallel verification for complex entitlements","designImplication":"Can check many privileges at once for gates"},{"aspect":"Revocation","ethereum":"Revoking delegation requires gas and wait","monad":"Instant revocation with fast finality","designImplication":"Revoke button can show immediate effect"},{"aspect":"Gas for Multi-Privilege","ethereum":"Managing many privileges can cost significant gas","monad":"Cheap operations make fine-grained privileges practical","designImplication":"Can offer more granular privilege management"}],"keyTakeaways":["EIP-5496 = multiple independent privileges per NFT","Always show delegation status (owned vs delegated vs received)","Display expiry prominently, warn before expiry","Provide clear revocation UI for delegated privileges","On Monad: leverage fast finality for instant sharing/revoking"],"technicalNotes":"EIP-5496 adds privilegeIds to ERC-721, where each NFT can have multiple privileges. Key functions: hasPrivilege(tokenId, privilegeId) checks access, setPrivilege(tokenId, privilegeId, address, expiresAt) grants access. Privileges can be delegated to addresses other than the NFT owner with optional expiration. The owner retains the right to revoke delegations."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-5496","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=EIP-5496","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/EIP-5496","markdown":"https://www.eipsfordesigners.com/standards/EIP-5496/content.md","agent":"https://www.eipsfordesigners.com/standards/EIP-5496/agent.md","api":"https://www.eipsfordesigners.com/api/standards/EIP-5496","official":"https://eips.ethereum.org/EIPS/eip-5496","discussion":"https://ethereum-magicians.org/search?q=EIP-5496"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"ERC-5192","name":"Minimal Soulbound NFTs","status":"Final","chain":"both","category":{"id":"identity","name":"Identity & Privacy","description":"Who you are on-chain, and what you choose to reveal"},"journeyStages":[{"id":"approving","name":"Approving & Permissioning","description":"Granting permissions for actions"},{"id":"management","name":"Asset Management","description":"Managing assets over time"}],"uxImpact":"Tokens marked as 'locked' cannot be transferred — minimal soulbound implementation for credentials, memberships, achievements. Design implications: show 'Soulbound' or 'Non-transferable' badge, hide/disable transfer buttons, explain permanence clearly. Design decisions: whether to show soulbound tokens in trading contexts at all — filter out or display with clear 'Not for Sale' status.","hasDetailedContent":true,"content":{"id":"ERC-5192","summary":"ERC-5192 defines \"soulbound\" NFTs — tokens that cannot be transferred once received. They're locked to your address forever. Perfect for credentials (diplomas, certifications), reputation tokens, proof of attendance, and anything that shouldn't be tradeable. The badge shows \"non-transferable\" and the transfer button is disabled.","applicability":{"whenToUse":["Your product addresses: credentials can be sold/transferred.","Your product addresses: no standard way to mark NFTs as non-transferable.","The flow should deliver: soulbound = locked to recipient forever.","You are designing a soulbound badge experience with visible states and recovery paths."],"whenToAvoid":["Check locked(), hide/disable transfer entirely.","Clear 🔒 icon and \"Soulbound\" label.","Explain: \"This is a credential locked to your address\".","The product has no sign-in, attestation, or identity verification step."]},"designerTakeaways":["You can design UI that delivers soulbound = locked to recipient forever.","You can design UI that delivers locked() function = universal check.","You can design UI that delivers check locked(), disable transfer button."],"problemsSolved":[{"problem":"Credentials can be sold/transferred","oldWay":"Degree NFT could be sold to someone who didn't earn it","newWay":"Soulbound = locked to recipient forever","impact":"critical"},{"problem":"No standard way to mark NFTs as non-transferable","oldWay":"Each project invented own locking mechanism","newWay":"locked() function = universal check","impact":"high"},{"problem":"UIs don't know to hide transfer option","oldWay":"User tries to transfer, gets confusing error","newWay":"Check locked(), disable transfer button","impact":"high"}],"uxPatterns":[{"name":"Soulbound Badge","description":"Clear indicator that NFT is non-transferable","mockup":"concept/siwe-sign-in","userFlow":["User views NFT","App checks locked(tokenId)","Shows soulbound indicator","Hides/disables transfer button","Explains why non-transferable"]},{"name":"Credential Gallery","description":"Collection of soulbound achievements","mockup":"concept/siwe-sign-in","userFlow":["User views credentials","All show soulbound lock icon","Click to view details","No transfer option anywhere","Share/prove ownership options"]}],"uiComponents":[{"name":"SoulboundIndicator","description":"Lock icon and label for soulbound tokens","states":["locked","unlocked","checking"],"props":["tokenId","showLabel"]},{"name":"CredentialCard","description":"Display card for non-transferable credentials","states":["verified","unverified","expired"],"props":["metadata","issuer","issuedAt"]},{"name":"TransferBlockedNotice","description":"Explanation when transfer attempted","states":["hidden","shown"],"props":["reason","onDismiss"]}],"antiPatterns":[{"pattern":"Showing transfer button for soulbound NFTs","why":"User clicks, gets error, confused","instead":"Check locked(), hide/disable transfer entirely","severity":"high"},{"pattern":"No visual indicator of soulbound status","why":"User doesn't know it can't be transferred","instead":"Clear 🔒 icon and \"Soulbound\" label","severity":"high"},{"pattern":"Not explaining why it's soulbound","why":"Users think something is broken","instead":"Explain: \"This is a credential locked to your address\"","severity":"medium"}],"onMonad":[{"aspect":"Minting","ethereum":"Soulbound mint takes 12+ seconds","monad":"Instant credential issuance","designImplication":"Real-time badge awarding at events"}],"keyTakeaways":["ERC-5192 = non-transferable \"soulbound\" NFTs","Always check locked() before showing transfer UI","Show clear visual indicator: 🔒 Soulbound","Explain WHY it's non-transferable","Perfect for credentials, attendance, reputation"],"technicalNotes":"ERC-5192 extends ERC-721 with locked(uint256 tokenId) view function returning bool. True = cannot be transferred. Emits Locked(tokenId) and Unlocked(tokenId) events. Wallets/marketplaces check locked() before enabling transfer. Compatible with ERC-5484 for consensual binding."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-5192","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-5192","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-5192","markdown":"https://www.eipsfordesigners.com/standards/ERC-5192/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-5192/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-5192","official":"https://eips.ethereum.org/EIPS/eip-5192","discussion":"https://ethereum-magicians.org/search?q=ERC-5192"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"ERC-5484","name":"Consensual Soulbound Tokens","status":"Final","chain":"both","category":{"id":"identity","name":"Identity & Privacy","description":"Who you are on-chain, and what you choose to reveal"},"journeyStages":[{"id":"approving","name":"Approving & Permissioning","description":"Granting permissions for actions"},{"id":"management","name":"Asset Management","description":"Managing assets over time"}],"uxImpact":"Soulbound tokens require recipient consent before minting and have predetermined burn rules (issuer-only, owner-only, both, neither). Design implications: show consent flow before accepting SBT, display burn authority clearly, add 'Request Burn' action where applicable. Design decisions: how to present burn authority — affects user understanding of permanence, recovery options if keys lost.","hasDetailedContent":true,"content":{"id":"ERC-5484","summary":"ERC-5484 creates soulbound tokens that require consent before binding. Unlike tokens that are pushed to your wallet, you must explicitly accept these credentials before they become non-transferable and permanently attached to your identity.","applicability":{"whenToUse":["Your product addresses: soulbound tokens can be sent without permission.","Your product must handle: can't refuse spam soulbound tokens.","The flow should deliver: must explicitly accept before token binds to you.","You are designing a credential acceptance flow experience with visible states and recovery paths."],"whenToAvoid":["Always require explicit user action to accept.","Clear warning: \"Cannot be transferred after acceptance\".","Prominently show who can burn before acceptance.","The product has no sign-in, attestation, or identity verification step."]},"designerTakeaways":["You can design UI that delivers must explicitly accept before token binds to you.","You can design UI that delivers pending state allows rejection before binding.","You can design UI that delivers accept ceremony makes credential meaningful."],"problemsSolved":[{"problem":"Soulbound tokens can be sent without permission","oldWay":"Anyone can mint unwanted credentials/badges to your wallet","newWay":"Must explicitly accept before token binds to you","impact":"critical"},{"problem":"Can't refuse spam soulbound tokens","oldWay":"Wallet polluted with unwanted non-transferable junk","newWay":"Pending state allows rejection before binding","impact":"high"},{"problem":"No ceremony for important credentials","oldWay":"Diploma just appears in wallet, anticlimactic","newWay":"Accept ceremony makes credential meaningful","impact":"medium"},{"problem":"Unclear who can burn soulbound tokens","oldWay":"Stuck with token forever? Can issuer revoke?","newWay":"BurnAuth specifies: issuer-only, owner-only, both, or neither","impact":"medium"},{"problem":"No way to verify consent was given","oldWay":"Can't prove recipient agreed to credential","newWay":"On-chain accept transaction proves consent","impact":"medium"}],"uxPatterns":[{"name":"Credential Acceptance Flow","description":"User explicitly accepts soulbound credential","mockup":"concept/siwe-sign-in","userFlow":["Issuer mints credential to user (pending state)","User receives notification of pending credential","Reviews credential details and binding terms","Understands burn authority (who can revoke)","Explicitly accepts to bind","Credential becomes non-transferable"]},{"name":"Pending Credentials Inbox","description":"View and manage pending credential offers","mockup":"concept/siwe-sign-in","userFlow":["User opens pending credentials","Sees list of credentials waiting for acceptance","Unknown issuers flagged as potential spam","Can accept legitimate credentials","Can decline unwanted ones","Declined tokens never bind"]},{"name":"Burn Authority Explanation","description":"Explain who can burn the soulbound token","mockup":"concept/siwe-sign-in","userFlow":["User reviews credential before accepting","Sees burn authority explanation","Understands implications of each option","Makes informed decision to accept or not"]},{"name":"Bound Credential Display","description":"Show accepted soulbound credential","mockup":"concept/siwe-sign-in","userFlow":["User views accepted credential","Clear soulbound indicator","Shows when it was accepted","Burn option available if auth allows","Warning before burning"]}],"uiComponents":[{"name":"ConsentModal","description":"Modal for accepting soulbound token","states":["reviewing","confirming","accepting","bound"],"props":["credential","issuer","burnAuth","onAccept","onDecline"]},{"name":"PendingCredentialBadge","description":"Badge showing credentials awaiting acceptance","states":["none","few","many"],"props":["count","onClick"]},{"name":"BurnAuthIndicator","description":"Shows who can burn the token","states":["issuer-only","owner-only","both","neither"],"props":["burnAuth","issuer","showDetails"]},{"name":"SoulboundBadge","description":"Visual indicator that token is soulbound","states":["pending","bound","revoked"],"props":["status","tooltip"]},{"name":"CredentialInbox","description":"List of pending credential offers","states":["empty","has-pending","has-spam"],"props":["credentials[]","onAccept","onDecline"]}],"antiPatterns":[{"pattern":"Auto-accepting soulbound tokens","why":"Defeats the entire point of consent","instead":"Always require explicit user action to accept","severity":"critical"},{"pattern":"Not explaining soulbound implications","why":"Users don't realize token is permanent","instead":"Clear warning: \"Cannot be transferred after acceptance\"","severity":"critical"},{"pattern":"Hiding burn authority information","why":"User should know if issuer can revoke","instead":"Prominently show who can burn before acceptance","severity":"high"},{"pattern":"No way to decline unwanted credentials","why":"Spam tokens clutter pending inbox forever","instead":"Easy decline button that hides/rejects token","severity":"high"},{"pattern":"Mixing pending and bound credentials","why":"Unclear which credentials are active","instead":"Separate sections for pending vs bound","severity":"medium"},{"pattern":"Burn without confirmation","why":"Accidental burns can't be undone","instead":"Require confirmation: \"Are you sure? This is permanent\"","severity":"high"}],"onMonad":[{"aspect":"Accept Transaction","ethereum":"Accept tx costs gas, might discourage acceptance","monad":"Low gas makes acceptance friction minimal","designImplication":"Can encourage accepting even minor credentials"},{"aspect":"Consent Verification","ethereum":"Check accept tx on-chain to verify consent","monad":"Fast queries make consent verification easy","designImplication":"Can verify consent in real-time for access control"},{"aspect":"Credential Issuance","ethereum":"Gas limits bulk issuance","monad":"Can issue credentials to many users economically","designImplication":"Event organizers can issue to all attendees cheaply"},{"aspect":"Burn Speed","ethereum":"Burn takes a block, credential lingers briefly","monad":"Sub-second burn means instant revocation","designImplication":"Credentials revoke truly instantly"}],"keyTakeaways":["ERC-5484 = soulbound tokens WITH consent","Must accept before token binds to wallet","Always show burn authority before acceptance","Separate pending from bound credentials in UI","Make decline easy to avoid credential spam"],"technicalNotes":"ERC-5484 extends ERC-5192 (minimal soulbound) with consent mechanism. BurnAuth enum: IssuerOnly, OwnerOnly, Both, Neither. Token starts in pending state, becomes bound after acceptPendingToken(). Events: Issued(address, uint256, BurnAuth), TokenBound(address, uint256). Issuer can set any BurnAuth when minting."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-5484","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-5484","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-5484","markdown":"https://www.eipsfordesigners.com/standards/ERC-5484/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-5484/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-5484","official":"https://eips.ethereum.org/EIPS/eip-5484","discussion":"https://ethereum-magicians.org/search?q=ERC-5484"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"EIP-5114","name":"Soulbound Badge","status":"Last Call","chain":"both","category":{"id":"identity","name":"Identity & Privacy","description":"Who you are on-chain, and what you choose to reveal"},"journeyStages":[{"id":"management","name":"Asset Management","description":"Managing assets over time"}],"uxImpact":"Badges bound to other NFTs (not wallets) — achievements tied to your PFP, credentials attached to identity NFT. Design implications: show badge hierarchy (which NFT owns which badges), display nested ownership, indicate badge permanence. Design decisions: how deep to visualize badge chains — could be complex graphs, need to handle loops, balance completeness with comprehension.","hasDetailedContent":true,"content":{"id":"EIP-5114","summary":"EIP-5114 creates soulbound badges that attach to other NFTs rather than directly to wallets. Your achievement badge binds to your avatar NFT, not your address—so your digital identity carries its credentials wherever the NFT goes.","applicability":{"whenToUse":["Your product addresses: credentials tied to wallet, not identity.","Your product addresses: identity fragmented across multiple wallets.","The flow should deliver: badge attached to your avatar NFT as your identity.","You are designing a badge-on-avatar display experience with visible states and recovery paths."],"whenToAvoid":["Always show badges IN CONTEXT of the NFT they're attached to.","Clear warning: \"Selling this NFT transfers all 3 badges\".","Always ask \"which NFT should receive this badge\".","The product has no sign-in, attestation, or identity verification step."]},"designerTakeaways":["You can design UI that delivers badge attached to your avatar NFT as your identity.","You can all badges on one NFT that represents you in the interface.","You can design UI that delivers transfer the parent NFT, badges follow."],"problemsSolved":[{"problem":"Credentials tied to wallet, not identity","oldWay":"Achievement badge bound to 0x7a3... address","newWay":"Badge attached to your avatar NFT as your identity","impact":"critical"},{"problem":"Identity fragmented across multiple wallets","oldWay":"Different credentials on different wallets, no unified profile","newWay":"All badges on one NFT that represents you","impact":"high"},{"problem":"Can't transfer identity with credentials","oldWay":"Soulbound tokens stuck at old address forever","newWay":"Transfer the parent NFT, badges follow","impact":"high"},{"problem":"No visual hierarchy for credentials","oldWay":"Flat list of soulbound tokens in wallet","newWay":"Badges displayed ON the NFT they're attached to","impact":"medium"},{"problem":"Badge spam pollutes wallet","oldWay":"Unwanted badges sent directly to address","newWay":"Badges attach to specific NFT, easier to manage","impact":"medium"}],"uxPatterns":[{"name":"Badge-on-Avatar Display","description":"Show badges attached to an NFT identity","mockup":"concept/nft-gallery","userFlow":["User views their identity NFT","Badges displayed visually on the NFT","Can expand to see full badge list","Each badge shows soulbound status","Clear indication badges move with NFT"]},{"name":"Badge Issuance to NFT","description":"Issue a badge that attaches to a specific NFT","mockup":"concept/nft-gallery","userFlow":["Issuer creates badge","Searches for recipient's identity NFT","Selects which NFT to attach badge to","Confirms permanent attachment","Badge minted and bound to NFT"]},{"name":"Identity NFT Selection","description":"User chooses which NFT represents their identity","mockup":"concept/nft-gallery","userFlow":["User opens identity settings","Views NFTs they own","Sees which has existing badges","Selects primary identity NFT","Shares NFT address for future badges"]},{"name":"Badge Verification","description":"Verify someone's badges through their NFT","mockup":"concept/verify-safety","userFlow":["Enter NFT address or ID","System fetches attached badges","Each badge verified against issuer","Shows validity status","Flags unverified issuers"]}],"uiComponents":[{"name":"BadgeOnNFT","description":"Visual overlay showing badges on parent NFT","states":["no-badges","has-badges","loading"],"props":["parentNFT","badges[]","maxDisplay","onBadgeClick"]},{"name":"IdentityNFTSelector","description":"Choose which NFT receives badges","states":["selecting","selected","confirming"],"props":["ownedNFTs[]","currentIdentity","onSelect"]},{"name":"BadgeAttachmentForm","description":"Form for issuing badge to specific NFT","states":["selecting-nft","confirming","issuing","complete"],"props":["badge","recipientNFTs[]","onIssue"]},{"name":"AttachedBadgeCard","description":"Display card for badge attached to NFT","states":["valid","revoked","unverified"],"props":["badge","parentNFT","issuer","issuedDate"]},{"name":"NFTCredentialProfile","description":"Full profile showing NFT with all badges","states":["loading","loaded","empty"],"props":["nft","badges[]","owner"]}],"antiPatterns":[{"pattern":"Showing badges separate from their parent NFT","why":"Loses the visual connection that makes this powerful","instead":"Always show badges IN CONTEXT of the NFT they're attached to","severity":"critical"},{"pattern":"Not explaining badges follow the NFT","why":"User sells NFT and loses credentials unknowingly","instead":"Clear warning: \"Selling this NFT transfers all 3 badges\"","severity":"critical"},{"pattern":"Issuing to wallet address instead of NFT","why":"Defeats the purpose, badge isn't attached to identity","instead":"Always ask \"which NFT should receive this badge\"","severity":"high"},{"pattern":"No verification of issuer legitimacy","why":"Fake credentials pollute identity","instead":"Show verified issuer status, flag unknowns","severity":"high"},{"pattern":"Hiding which NFT a badge is attached to","why":"User can't find their credentials","instead":"Always show \"Attached to: [NFT name]\"","severity":"medium"}],"onMonad":[{"aspect":"Badge Issuance","ethereum":"Each badge mint costs meaningful gas","monad":"Bulk badge issuance economically viable","designImplication":"Event organizers can issue badges to all attendees' NFTs cheaply"},{"aspect":"Verification Speed","ethereum":"Checking badges requires multiple calls","monad":"Fast parallel queries for all badges on an NFT","designImplication":"Can verify full credential profile in real-time"},{"aspect":"Transfer Detection","ethereum":"Need to index transfers to track badge movement","monad":"Sub-second finality means immediate badge tracking","designImplication":"Badge ownership updates instantly on NFT transfer"},{"aspect":"Profile Loading","ethereum":"Loading NFT + all badges may be slow","monad":"Parallel execution loads everything fast","designImplication":"Can show full decorated avatar instantly"}],"keyTakeaways":["EIP-5114 = badges attached to NFTs, not wallets","Your identity NFT carries all your credentials","Transferring the NFT transfers all badges","Always show badges visually ON their parent NFT","Warn users before selling NFT with badges attached"],"technicalNotes":"EIP-5114 defines a Badge that references a specific NFT (collection address + token ID) as its \"soul\". The badge cannot be transferred independently—it follows the parent NFT. Unlike ERC-5192 which binds to addresses, this binds to another token. Useful for identity NFTs like ENS names or avatars that represent a person."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-5114","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=EIP-5114","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/EIP-5114","markdown":"https://www.eipsfordesigners.com/standards/EIP-5114/content.md","agent":"https://www.eipsfordesigners.com/standards/EIP-5114/agent.md","api":"https://www.eipsfordesigners.com/api/standards/EIP-5114","official":"https://eips.ethereum.org/EIPS/eip-5114","discussion":"https://ethereum-magicians.org/search?q=EIP-5114"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"ERC-7231","name":"Identity-aggregated NFT","status":"Final","chain":"both","category":{"id":"identity","name":"Identity & Privacy","description":"Who you are on-chain, and what you choose to reveal"},"journeyStages":[{"id":"authentication","name":"Authentication & Identity","description":"Proving who you are and logging in"}],"uxImpact":"NFTs aggregate multiple verified identities (Twitter, Discord, wallet addresses) into single on-chain profile — portable reputation. Design implications: show connected identities with verification status, add 'Link Identity' flow, display identity proofs. Design decisions: privacy controls for which identities visible — selective disclosure UI, granular sharing permissions, balance transparency with privacy.","hasDetailedContent":true,"content":{"id":"ERC-7231","summary":"ERC-7231 creates identity-aggregated NFTs that bind multiple social accounts (Twitter, Discord, GitHub, etc.) to a single on-chain identity. Users can prove ownership of all their accounts with one NFT, enabling unified social proof without repeatedly re-verifying across dApps.","applicability":{"whenToUse":["Your users must verify social accounts repeatedly on each dApp.","Your product addresses: no portable proof of social reputation.","The flow should deliver: verify once, mint identity NFT, show proof anywhere.","You are designing a identity aggregation flow experience with visible states and recovery paths."],"whenToAvoid":["Allow minting with any verified accounts, add more later.","Provide clear update flow to modify connected accounts.","Display friendly account names with verified badges.","The product has no sign-in, attestation, or identity verification step."]},"designerTakeaways":["You can design UI that delivers verify once, mint identity NFT, show proof anywhere.","You can design UI that delivers single NFT proves all your verified social connections.","You can design UI that delivers aggregated identity shows real human with real accounts."],"problemsSolved":[{"problem":"Users must verify social accounts repeatedly on each dApp","oldWay":"Connect Twitter to App A, connect again to App B, connect again to App C...","newWay":"Verify once, mint identity NFT, show proof anywhere","impact":"critical"},{"problem":"No portable proof of social reputation","oldWay":"Each platform has isolated identity, reputation doesn't travel","newWay":"Single NFT proves all your verified social connections","impact":"high"},{"problem":"Sybil attacks with fake accounts","oldWay":"Create unlimited wallets, no way to verify uniqueness","newWay":"Aggregated identity shows real human with real accounts","impact":"high"},{"problem":"Complex identity verification flows","oldWay":"OAuth redirects, popup hell, different flows per platform","newWay":"Mint once with all verifications, use NFT as proof","impact":"medium"}],"uxPatterns":[{"name":"Identity Aggregation Flow","description":"Guide users through connecting multiple social accounts to mint unified identity NFT","mockup":"concept/nft-gallery","userFlow":["User starts identity creation","Select first social platform to connect","OAuth flow verifies ownership","Repeat for additional platforms","Preview aggregated identity","Sign and mint identity NFT","NFT shows all verified accounts"]},{"name":"Identity Verification Display","description":"Show verified social accounts from identity NFT","mockup":"concept/nft-gallery","userFlow":["dApp reads user's identity NFT","Display verified social accounts","Show verification badges","Allow identity updates if owned"]},{"name":"Quick Identity Check","description":"Verify user identity for gated access","mockup":"concept/verify-safety","userFlow":["User attempts to access gated content","System reads their identity NFT","Compare against requirements","Grant or deny access with clear feedback"]}],"uiComponents":[{"name":"AccountConnector","description":"OAuth-style button for connecting social accounts","states":["disconnected","connecting","connected","error"],"props":["platform","username","onConnect","onDisconnect"]},{"name":"IdentityCard","description":"Display aggregated identity with all verified accounts","states":["loading","verified","partial","expired"],"props":["nftId","accounts[]","lastUpdated","owner"]},{"name":"VerificationBadge","description":"Small badge showing verified status for an account","states":["verified","pending","expired","unverified"],"props":["platform","username","verifiedAt"]},{"name":"IdentityRequirements","description":"List of required verifications for access","states":["checking","met","unmet","partial"],"props":["requirements[]","userIdentity","onMeetRequirements"]}],"antiPatterns":[{"pattern":"Requiring all platforms before minting","why":"Users may not have accounts on every platform, blocks adoption","instead":"Allow minting with any verified accounts, add more later","severity":"critical"},{"pattern":"No way to update identity after minting","why":"Users change usernames, create new accounts, need to add platforms","instead":"Provide clear update flow to modify connected accounts","severity":"high"},{"pattern":"Showing raw verification data","why":"Users don't understand technical proofs","instead":"Display friendly account names with verified badges","severity":"high"},{"pattern":"Forcing public display of all accounts","why":"Privacy concerns - users may want some accounts private","instead":"Allow selective disclosure of which accounts to show","severity":"medium"}],"onMonad":[{"aspect":"Verification Speed","ethereum":"Identity mint takes 15-30 seconds to confirm","monad":"Sub-second finality means instant identity creation","designImplication":"Can show live verification status, no \"waiting\" screens"},{"aspect":"Update Frequency","ethereum":"Expensive to update identity, users hesitate","monad":"Cheap updates enable frequent identity refreshes","designImplication":"Show \"Refresh Identity\" button prominently, encourage updates"},{"aspect":"Gas for Verification","ethereum":"Each account addition costs significant gas","monad":"Negligible cost for adding accounts","designImplication":"Can prompt users to add more accounts without cost concerns"}],"keyTakeaways":["Identity aggregation = one NFT proves all your social accounts","Allow incremental building - start with one account, add more","Make verification status instantly clear with badges","Provide update mechanisms for changing accounts","On Monad: leverage cheap updates for dynamic identities"],"technicalNotes":"ERC-7231 extends ERC-721 to include identity aggregation. Each NFT stores an array of bound identities with platform identifiers and verification proofs. The standard defines methods for adding, removing, and querying bound identities. Verification typically happens off-chain via signed messages from each platform, with proofs stored on-chain."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-7231","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-7231","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-7231","markdown":"https://www.eipsfordesigners.com/standards/ERC-7231/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-7231/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-7231","official":"https://eips.ethereum.org/EIPS/eip-7231","discussion":"https://ethereum-magicians.org/search?q=ERC-7231"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"ERC-5564","name":"Stealth Addresses","status":"Final","chain":"both","category":{"id":"identity","name":"Identity & Privacy","description":"Who you are on-chain, and what you choose to reveal"},"journeyStages":[{"id":"authentication","name":"Authentication & Identity","description":"Proving who you are and logging in"}],"uxImpact":"Senders generate one-time stealth addresses for recipients — receive funds privately without revealing main wallet. Design implications: show 'Send Privately' option, explain stealth address concept simply, add stealth transaction scanner for recipients. Design decisions: how to onboard users to stealth — complexity vs privacy benefit, whether to default to private or make it opt-in, scanning UX for finding received funds. 77K addresses deployed via Umbra. Part of the On-Chain Activity Is Public by Default pain point (High severity, Research status). Users often don't realize their complete financial history is visible — stealth addresses are one of four leading privacy solutions.","hasDetailedContent":true,"content":{"id":"ERC-5564","sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-5564","type":"official-spec"}],"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25","summary":"Senders generate one-time stealth addresses for recipients — receive funds privately without revealing main wallet.","partialDeployment":{"body":"Many wallets support sending to a private receiving profile, but inbox scanning and claim flows are not universal yet. Label what each wallet can do, offer Rescan, and never imply funds are lost when a payment has not appeared."},"designerTakeaways":["You can offer Send privately alongside normal send with plain-language privacy benefit.","Your receive flow can show a stealth receiving address separate from your public wallet.","You can build a stealth payment inbox that scans and surfaces incoming deposits."],"applicability":{"whenToUse":["Privacy is a core product value.","Users receive donations, salary, or payments without public linkage.","Wallet supports stealth key generation and scanning."],"whenToAvoid":["Compliance requires transparent recipient identity on every transfer.","Wallet lacks scanning infrastructure — users would miss funds.","Simple public address send meets the need with less risk."]},"prototypeFirst":[{"screen":"Send privately composer","why":"Senders need privacy without learning stealth jargon.","covers":["Stealth recipient","Amount","Confirmation"],"include":["Send privately toggle","Recipient stealth address field","Privacy explainer one-liner"]},{"screen":"Stealth receive setup","why":"Recipients must register and share the right meta-address.","covers":["Unregistered","Registered","Share sheet"],"include":["Register for private payments CTA","Meta-address copy","QR for stealth receiving"]},{"screen":"Stealth payment inbox","why":"Funds are invisible until scanned — inbox is critical.","covers":["Scanning","New payment found","Empty"],"include":["Scan now button","Incoming payment rows","Claim or acknowledge flow"]},{"screen":"Privacy onboarding","why":"First-time users need metaphor before math.","covers":["Opt-in education","Skip"],"include":["One-time address analogy","When to use public vs private","Do not show keys by default"]}],"mentalModel":[{"label":"Public wallet","description":"Your normal address — full history visible on explorers."},{"label":"Stealth meta-address","description":"A receiving profile from which one-time addresses are derived — not where funds sit."},{"label":"Ephemeral deposit address","description":"Sender pays to a unique address linked only to recipient via cryptography."},{"label":"Scanning","description":"Recipient wallet scans chain to detect payments to addresses only they can recognize."},{"label":"Spending","description":"Detected funds move to spendable balance after recipient claims with derived keys."}],"statesToDesign":[{"state":"Stealth not set up","trigger":"User has no stealth keys.","userNeed":"Start receiving private payments.","designResponse":"Onboarding card with Register for private payments."},{"state":"Scanning for payments","trigger":"User opens inbox or background scan runs.","userNeed":"Know scan is working.","designResponse":"Scanning indicator with last checked time."},{"state":"New stealth payment detected","trigger":"Scan finds incoming deposit.","userNeed":"See amount and sender hint if available.","designResponse":"Inbox row with Accept or Review action."},{"state":"Send privately confirmation","trigger":"Sender submits stealth payment.","userNeed":"Confirm sent without exposing recipient main wallet.","designResponse":"Sent privately confirmation; no link to recipient public address."},{"state":"Scan failed or missed payment","trigger":"Indexer lag or user on new device.","userNeed":"Recover without panic.","designResponse":"Rescan CTA and support path; never imply funds are lost."}],"designDecisions":[{"question":"Default to private or opt-in?","recommendation":"Opt-in with clear Send privately toggle; keep public send default for familiarity.","rationale":"Stealth misses funds if scanning fails — defaulting private is risky."},{"question":"How much cryptography to show?","recommendation":"Meta-address copy button only; hide derivation details.","rationale":"Keys and schemes overwhelm; outcomes matter."},{"question":"Automatic background scan?","recommendation":"Yes with manual Rescan and notification on new payment.","rationale":"Users will not manually scan every session."}],"problemsSolved":[{"problem":"All wallet activity is public","oldWay":"Single address reveals full financial history","newWay":"One-time deposit addresses unlink payments from main wallet","impact":"critical"},{"problem":"Sharing address reveals entire history","oldWay":"Give address to receive payment, they see all your transactions","newWay":"Generate fresh address per sender","impact":"critical"},{"problem":"Donation and salary privacy","oldWay":"Recipients expose net worth on chain","newWay":"Stealth receive hides incoming payment graph","impact":"high"},{"problem":"Sender links to recipient forever","oldWay":"Permanent address ties parties in explorer graph","newWay":"Ephemeral address breaks long-term linkability","impact":"high"},{"problem":"Reusing addresses destroys privacy","oldWay":"Manual new address per payment = terrible UX","newWay":"Automatic stealth address generation","impact":"high"}],"uxPatterns":[{"name":"Share Stealth Meta-Address","description":"Give out a receiving profile that enables private payments.","mockup":"concept/stealth-receive","components":["StealthMetaAddressDisplay"],"userFlow":["User wants to receive payment privately","Opens private receiving setup","Copies or shows QR of meta-address","Shares with sender"]},{"name":"Send Privately Toggle","description":"Optional stealth send in transfer composer.","mockup":"concept/stealth-address","components":["PrivacyToggle","StealthAddressInput","SendButton"],"userFlow":["User composes send","Enables Send privately","Enters meta-address","Confirms","Payment sent to ephemeral address"]},{"name":"Send to Stealth Address","description":"Send payment privately to a recipient meta-address.","mockup":"concept/stealth-address","components":["StealthSendForm","PrivacyIndicator"],"userFlow":["User pastes recipient meta-address","Enters amount","System generates unique deposit address","Shows privacy assurances","Sends and publishes announcement for recipient"]},{"name":"Stealth Payment Inbox","description":"Scan and list incoming private payments.","mockup":"concept/stealth-inbox","components":["ScanButton","PaymentList","AcceptAction"],"userFlow":["User opens inbox","Scan runs","Payments appear","User accepts into balance"]},{"name":"Claim Stealth Payment","description":"Move funds from a stealth deposit to a spendable wallet.","mockup":"concept/stealth-inbox","components":["ClaimDestinationPicker","PrivacyIndicator"],"userFlow":["User selects payment to claim","Sees payment details","Chooses destination (main vs fresh wallet)","Warned if main wallet breaks privacy","Claims to chosen destination"]}],"uiComponents":[{"name":"StealthMetaAddressDisplay","description":"Show and share private receiving profile","states":["generating","ready","copied"],"props":["metaAddress","onCopy","showQR"]},{"name":"StealthInbox","description":"Scan and list stealth payments","states":["scanning","found-payments","no-payments","error"],"props":["payments[]","onClaim","scanProgress"]},{"name":"StealthSendForm","description":"Form for sending to a stealth meta-address","states":["entering","generating","confirming","sent"],"props":["recipientMetaAddress","amount","generatedAddress","onSend"]},{"name":"ClaimDestinationPicker","description":"Choose where to claim a stealth payment","states":["selecting","warning","confirmed"],"props":["mainWallet","freshAddressOption","onSelect"]},{"name":"PrivacyIndicator","description":"Show privacy level of an action","states":["private","partially-private","public"],"props":["privacyLevel","explanation"]}],"seenInTheWild":[{"app":"Umbra","url":"https://umbra.cash/","note":"Stealth address pioneer with 77K+ deployments; reference for scan UX."},{"app":"Railgun","url":"https://railgun.org/","note":"Private transfer patterns inform send/receive mental models."},{"app":"Safe","url":"https://safe.global/","note":"Multi-chain wallets exploring privacy receive flows."},{"app":"Vitalik blog","url":"https://vitalik.eth.limo/","note":"Stealth address explainer shapes user-facing metaphors."}],"antiPatterns":[{"pattern":"Stealth receive with no scanner","why":"Users never see incoming funds","instead":"Mandatory inbox with auto-scan and notifications","severity":"critical"},{"pattern":"Claiming to main wallet by default","why":"Links stealth payment to main identity and defeats privacy","instead":"Default to fresh address; warn if main wallet selected","severity":"critical"},{"pattern":"Showing stealth and public address interchangeably","why":"Senders pay to wrong target","instead":"Distinct labels: Public address vs Private receiving profile","severity":"critical"},{"pattern":"Auto-claiming to main wallet","why":"User loses privacy without knowing","instead":"Always ask where to claim and explain implications","severity":"critical"},{"pattern":"No scanning progress indicator","why":"Scanning can take time; users think the inbox is broken","instead":"Show scanning progress and found count","severity":"high"},{"pattern":"Privacy jargon in primary CTA","why":"Users avoid feature they do not understand","instead":"Send privately with one-line benefit copy","severity":"high"}],"vocabulary":[{"use":"Send privately","avoid":"Generate stealth address","why":"Outcome language over cryptography."},{"use":"Private receiving profile","avoid":"Stealth meta-address","why":"Metaphor before protocol terms."},{"use":"Check for incoming payments","avoid":"Scan stealth tags","why":"Action users understand."}],"onMonad":[{"aspect":"Scan throughput","ethereum":"Scanning large history is slow","monad":"High throughput chains need efficient scan indexing","designImplication":"Invest in fast inbox scan; show progress for large histories."},{"aspect":"Claim cost","ethereum":"Each claim costs gas, discouraging small payments","monad":"Cheap claims make small stealth payments viable","designImplication":"Small private tips and donations become practical."},{"aspect":"Private send cost","ethereum":"Stealth txs may cost more","monad":"Lower fees reduce barrier to privacy opt-in","designImplication":"Do not warn heavily about gas for private sends on Monad."},{"aspect":"Claim finality","ethereum":"Claim tx takes ~15 seconds","monad":"Sub-second claim finality","designImplication":"Instant access to received funds after claim."}],"keyTakeaways":["ERC-5564 = privacy through one-time deposit addresses","Share a private receiving profile; receive to unlinkable addresses","Default claims to a fresh wallet; warn before claiming to main","Show scanning progress when checking the inbox","Explain privacy benefits in plain language, not cryptography"],"technicalNotes":"ERC-5564 stealth requires reliable scanning; never ship receive-only stealth without inbox UX.","relatedStandards":[{"id":"ERC-6538","relationship":"Registry for discovering stealth meta-addresses"},{"id":"ERC-721","relationship":"Optional NFT privacy extensions"}]},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-5564","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-5564","type":"discussion"},{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-5564","type":"official-spec"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-5564","markdown":"https://www.eipsfordesigners.com/standards/ERC-5564/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-5564/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-5564","official":"https://eips.ethereum.org/EIPS/erc-5564","discussion":"https://ethereum-magicians.org/search?q=ERC-5564"},"freshness":{"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25"}},{"id":"ERC-6538","name":"Stealth Meta-Address Registry","status":"Final","chain":"both","category":{"id":"identity","name":"Identity & Privacy","description":"Who you are on-chain, and what you choose to reveal"},"journeyStages":[{"id":"authentication","name":"Authentication & Identity","description":"Proving who you are and logging in"}],"uxImpact":"Users register stealth meta-addresses in central registry — senders look up recipient's stealth keys to send privately. Design implications: add 'Register for Private Payments' onboarding, show registration status, enable ENS-like stealth address lookup. Design decisions: registry discoverability vs privacy — registered users are known to want privacy, balance convenience with metadata exposure.","hasDetailedContent":true,"content":{"id":"ERC-6538","sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-6538","type":"official-spec"}],"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25","summary":"Users register stealth meta-addresses in central registry — senders look up recipient's stealth keys to send privately.","designerTakeaways":["You can add Register for private payments in wallet setup with clear discoverability tradeoff.","Your send flow can resolve ENS or handle to stealth meta-address from registry lookup.","You can show registration status so users know if they appear in private payment search."],"applicability":{"whenToUse":["Product supports ERC-5564 stealth sends.","Users want discoverable private receive without sharing keys manually.","Registry exists on target chain."],"whenToAvoid":["Users need maximum anonymity — registry reveals privacy preference.","Stealth sending is not implemented end-to-end.","Manual key exchange is preferred for high-security contexts."]},"prototypeFirst":[{"screen":"Private payments registration","why":"Users opt in with informed discoverability tradeoff.","covers":["Unregistered","Registering","Registered"],"include":["Benefit copy","Discoverability note","Confirm registration"]},{"screen":"Send lookup by name","why":"Senders find recipients like ENS but for private pay.","covers":["Found in registry","Not registered","Multiple matches"],"include":["Search field","Registry result row","Send privately CTA"]},{"screen":"Registry profile settings","why":"Users control public visibility of private payment preference.","covers":["Registered visible","Unregister"],"include":["Status toggle","What others see","Unregister warning"]},{"screen":"Recipient not in registry fallback","why":"Manual meta-address entry must remain for unlisted users.","covers":["Paste meta-address","Invalid format"],"include":["Advanced paste field","Validation feedback"]}],"mentalModel":[{"label":"Registry entry","description":"Maps identity (ENS, address) to stealth meta-address for lookup."},{"label":"Discoverability tradeoff","description":"Registration helps senders find you but signals you use privacy features."},{"label":"Lookup before send","description":"Sender queries registry, then ERC-5564 derivation produces deposit address."},{"label":"Public profile vs private payments","description":"Registry is about finding how to pay privately, not seeing private history."},{"label":"Unregister","description":"Removing registry entry stops discovery; existing stealth keys may still work."}],"statesToDesign":[{"state":"Not registered","trigger":"User has stealth keys but no registry entry.","userNeed":"Choose whether to be discoverable.","designResponse":"Prompt with Register benefits and privacy note."},{"state":"Registered — discoverable","trigger":"Entry live on registry.","userNeed":"Know others can find them for private pay.","designResponse":"Registered badge in settings with unregister option."},{"state":"Lookup success in send","trigger":"Sender searches name.","userNeed":"Confidence correct person found.","designResponse":"Show avatar, name, Private payments enabled, continue."},{"state":"Lookup miss","trigger":"Name not in registry.","userNeed":"Alternative path.","designResponse":"Not registered for private payments with paste meta-address option."},{"state":"Unregister pending","trigger":"User removes registry entry.","userNeed":"Understand senders cannot find them via lookup.","designResponse":"Confirmation modal with unregister consequences."}],"designDecisions":[{"question":"Surface registry in global search?","recommendation":"Show Private payments available badge on resolved profiles.","rationale":"Senders discover capability at moment of payment."},{"question":"Explain discoverability paradox?","recommendation":"One sentence: Helps friends pay you privately; shows you use privacy features.","rationale":"Informed consent prevents backlash from privacy purists."},{"question":"Require registration for stealth receive?","recommendation":"No — allow manual meta-address share without registry.","rationale":"Registry is convenience, not gate."}],"problemsSolved":[{"problem":"Stealth keys shared through insecure DMs","oldWay":"Copy-paste meta-address in Twitter DM","newWay":"Registry lookup by ENS or handle","impact":"high"},{"problem":"Senders cannot find stealth-capable recipients","oldWay":"Assume everyone uses public address only","newWay":"Registry signals private payment endpoint","impact":"medium"},{"problem":"Wrong meta-address pasted","oldWay":"Typo sends funds to unrecoverable address","newWay":"Verified lookup from registry reduces manual entry","impact":"high"}],"uxPatterns":[{"name":"Private Payments Registration","description":"Opt-in registry onboarding with tradeoff copy.","mockup":"concept/siwe-sign-in","components":["RegisterCTA","DiscoverabilityNote","StatusBadge"],"userFlow":["User opens privacy settings","Reads tradeoff","Registers","Badge shows active"]},{"name":"Registry Lookup Send","description":"Find recipient stealth profile by name.","mockup":"concept/verify-safety","components":["SearchInput","RegistryResult","PrivateSendCTA"],"userFlow":["Sender searches name","Registry returns meta-address","Send privately pre-filled","Payment sent"]}],"seenInTheWild":[{"app":"Umbra","url":"https://umbra.cash/","note":"Stealth registry patterns with ENS integration."},{"app":"ENS App","url":"https://app.ens.domains/","note":"Name resolution UX extends to stealth lookup."},{"app":"Rainbow","url":"https://rainbow.me/","note":"Send flow name resolution sets lookup interaction bar."},{"app":"Lens Protocol","url":"https://lens.xyz/","note":"Profile-based payment discovery parallels registry model."}],"antiPatterns":[{"pattern":"Auto-register without consent","why":"Privacy preference leaked without opt-in","instead":"Explicit registration with discoverability explanation","severity":"critical"},{"pattern":"Registry lookup without identity confirmation","why":"Funds sent to wrong person","instead":"Show avatar, ENS, and confirm screen before send","severity":"critical"},{"pattern":"Hiding manual meta-address entry","why":"Unregistered recipients cannot get paid","instead":"Advanced paste path always available","severity":"high"}],"vocabulary":[{"use":"Private payments profile","avoid":"Stealth meta-address registry entry","why":"Profile language over registry jargon."},{"use":"Find by name","avoid":"Query registry mapping","why":"Search interaction users know."},{"use":"Accepts private payments","avoid":"6538 registered","why":"Capability label, not standard number."}],"onMonad":[{"aspect":"Registry freshness","ethereum":"Lookup may lag behind registration tx","monad":"Fast finality shows registered status quickly","designImplication":"Refresh lookup immediately after registration success."},{"aspect":"Privacy feature adoption","ethereum":"Gas may deter registration","monad":"Low-cost registration encourages opt-in","designImplication":"Bundle registration into wallet setup on Monad."}],"technicalNotes":"ERC-6538 registry trades discoverability for convenience; always explain paradox and keep manual meta-address path.","relatedStandards":[{"id":"ERC-5564","relationship":"Stealth addresses registered for discovery"},{"id":"ERC-137","relationship":"ENS names as registry lookup keys"}]},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-6538","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-6538","type":"discussion"},{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-6538","type":"official-spec"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-6538","markdown":"https://www.eipsfordesigners.com/standards/ERC-6538/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-6538/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-6538","official":"https://eips.ethereum.org/EIPS/erc-6538","discussion":"https://ethereum-magicians.org/search?q=ERC-6538"},"freshness":{"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25"}},{"id":"ERC-3643","name":"T-REX (Regulated Exchanges)","status":"Final","chain":"both","category":{"id":"identity","name":"Identity & Privacy","description":"Who you are on-chain, and what you choose to reveal"},"journeyStages":[{"id":"management","name":"Asset Management","description":"Managing assets over time"}],"uxImpact":"Security tokens enforce compliance at transfer — only verified investors can hold, automatic checks against regulations. Design implications: show verification status prominently, guide through KYC/identity verification, display transfer eligibility before attempting. Design decisions: how to handle failed compliance checks — educational messaging, clear next steps for verification, balance regulatory requirements with user frustration.","hasDetailedContent":true,"content":{"id":"ERC-3643","sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-3643","type":"official-spec"}],"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25","summary":"Security tokens enforce compliance at transfer — only verified investors can hold, automatic checks against regulations.","designerTakeaways":["You can show Verified investor badge prominently on portfolio and send screens.","Your send flow can pre-check recipient eligibility before the user signs.","You can guide rejected users through KYC next steps instead of raw revert reasons."],"applicability":{"whenToUse":["Tokenized securities or regulated assets.","Transfers must fail for non-verified wallets.","Issuer operates T-REX compliance stack."],"whenToAvoid":["Fully permissionless tokens with no compliance requirement.","Target chain lacks identity registry infrastructure.","Product cannot host or link KYC flow."]},"prototypeFirst":[{"screen":"KYC verification onboarding","why":"Users cannot invest without completing identity verification.","covers":["Unverified","Pending","Verified","Rejected"],"include":["Step list","Document upload","Status tracker","Retry path"]},{"screen":"Pre-transfer eligibility check","why":"Catch compliance failure before wallet signature.","covers":["Both verified","Recipient not verified","Sender restricted"],"include":["Recipient address field","Eligibility result","Block send with reason"]},{"screen":"Verified portfolio view","why":"Holdings should reinforce trusted status.","covers":["Verified holdings","Restricted token"],"include":["Verification badge","Transfer button gated","Contact issuer link"]},{"screen":"Compliance failure recovery","why":"Rejected transfers need human next steps.","covers":["KYC expired","Jurisdiction block"],"include":["Plain reason","Renew verification CTA","Support contact"]}],"mentalModel":[{"label":"Security token","description":"Regulated asset — not every wallet may hold it."},{"label":"Identity registry","description":"On-chain record of which addresses passed KYC."},{"label":"Compliance check","description":"Every transfer validates both parties against rules before execution."},{"label":"Verification lifecycle","description":"KYC can expire or revoke — status is not permanent by default."},{"label":"Transfer eligibility","description":"Pre-check answers will this send succeed before user commits."}],"statesToDesign":[{"state":"Unverified — cannot hold","trigger":"User lacks KYC.","userNeed":"Complete verification to invest.","designResponse":"Full-screen Verify to continue with step tracker."},{"state":"Verification pending","trigger":"KYC submitted, awaiting review.","userNeed":"Know timeline and that funds are safe.","designResponse":"Pending badge with estimated review time."},{"state":"Verified — can transfer","trigger":"User and counterparty eligible.","userNeed":"Normal send experience with confidence.","designResponse":"Verified badges on both parties; enabled Send."},{"state":"Recipient not verified","trigger":"Pre-check fails on recipient.","userNeed":"Understand block before signing.","designResponse":"Recipient cannot receive this asset yet with explanation."},{"state":"Verification expired","trigger":"KYC lapsed.","userNeed":"Renew without losing holdings view.","designResponse":"Expired badge; transfers disabled until renewal."}],"designDecisions":[{"question":"When to run eligibility check?","recommendation":"On address paste and before review step.","rationale":"Late failures waste signatures and trust."},{"question":"How to message failed compliance?","recommendation":"This wallet is not verified for this asset — not You are not allowed.","rationale":"Neutral compliance language reduces offense."},{"question":"Show verification in public address display?","recommendation":"Optional Verified chip on known counterparties only.","rationale":"Do not leak KYC status broadly without consent."}],"problemsSolved":[{"problem":"Regulated transfers fail mysteriously","oldWay":"Revert after user signs full transaction","newWay":"Pre-transfer eligibility check with clear reason","impact":"critical"},{"problem":"Investors unsure if they qualify","oldWay":"Discover blocks at purchase","newWay":"Verification status visible in portfolio at all times","impact":"high"},{"problem":"Issuer support overwhelmed by KYC questions","oldWay":"Opaque compliance errors","newWay":"Guided renewal and rejection flows with next steps","impact":"medium"}],"uxPatterns":[{"name":"Verification Status Badge","description":"Persistent KYC state on portfolio and profile.","mockup":"concept/siwe-sign-in","components":["VerifiedBadge","PendingState","RenewCTA"],"userFlow":["User opens portfolio","Sees verification status","Renews if expired","Transfers enabled"]},{"name":"Transfer Eligibility Pre-Check","description":"Validate recipient before send confirmation.","mockup":"concept/verify-safety","components":["AddressInput","EligibilityResult","SendGate"],"userFlow":["User pastes address","Check runs","Pass enables Send","Fail shows reason"]}],"seenInTheWild":[{"app":"Tokeny","url":"https://tokeny.com/","note":"T-REX implementation reference for compliance UX."},{"app":"Securitize","url":"https://securitize.io/","note":"Tokenized securities onboarding and KYC patterns."},{"app":"tZERO","url":"https://www.tzero.com/","note":"Regulated trading sets verification expectations."},{"app":"Polymesh","url":"https://polymesh.network/","note":"Identity-first chain informs verification badge UX."}],"antiPatterns":[{"pattern":"Allowing sign then compliance revert","why":"Wasted gas and legal frustration","instead":"Pre-check eligibility before wallet prompt","severity":"critical"},{"pattern":"Generic Transfer failed toast","why":"Users cannot fix KYC or pick new recipient","instead":"Specific compliance reason with renewal or support CTA","severity":"high"},{"pattern":"Hiding verification requirement until checkout","why":"Drop-off at payment after emotional investment","instead":"Verify gate at portfolio entry and asset page","severity":"high"}],"vocabulary":[{"use":"Verified investor","avoid":"Whitelisted ONCHAINID","why":"Regulatory-friendly status language."},{"use":"Cannot receive this asset","avoid":"Compliance module revert","why":"Outcome without Solidity terms."},{"use":"Complete verification","avoid":"Submit KYC claim","why":"Action-oriented onboarding copy."}],"onMonad":[{"aspect":"KYC refresh","ethereum":"Re-verification txs may feel costly","monad":"Low fees reduce friction for status updates","designImplication":"Encourage periodic re-check without gas anxiety."},{"aspect":"Transfer pre-check speed","ethereum":"Eligibility queries may lag","monad":"Fast reads enable instant paste validation","designImplication":"Validate recipient on every keystroke debounce."}],"technicalNotes":"ERC-3643 T-REX requires identity registry integration; never allow send UI without eligibility pre-check.","relatedStandards":[{"id":"ERC-20","relationship":"Fungible token with compliance hooks"}]},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-3643","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-3643","type":"discussion"},{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-3643","type":"official-spec"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-3643","markdown":"https://www.eipsfordesigners.com/standards/ERC-3643/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-3643/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-3643","official":"https://eips.ethereum.org/EIPS/erc-3643","discussion":"https://ethereum-magicians.org/search?q=ERC-3643"},"freshness":{"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25"}},{"id":"ERC-7627","name":"Secure Messaging Protocol","status":"Draft","chain":"both","category":{"id":"identity","name":"Identity & Privacy","description":"Who you are on-chain, and what you choose to reveal"},"journeyStages":[{"id":"specialized","name":"Specialized Interactions","description":"Physical items, AI, social, gaming"}],"uxImpact":"End-to-end encrypted messaging between wallet addresses — private on-chain communication with session support. Design implications: show encryption status indicator, display message history by session, add public key registration flow. Design decisions: key management UX — how to handle key rotation, session organization, balance security (key expiry) with convenience (persistent conversations).","hasDetailedContent":true,"content":{"id":"ERC-7627","summary":"ERC-7627 defines a secure messaging protocol for on-chain communication between wallet addresses. Messages are end-to-end encrypted, stored on-chain, and only readable by the intended recipient. It enables private DMs between wallets without relying on centralized messaging services.","applicability":{"whenToUse":["Your product addresses: no standard way to message a wallet address.","Your product addresses: on-chain messages are public and readable by anyone.","The flow should deliver: message 0xABC directly, cryptographically verified.","Connect flows must list wallets with names, icons, and explicit user choice."],"whenToAvoid":["Always encrypt before storing on-chain.","Decrypt client-side only, never send plaintext to server.","Implement filtering, blocking, and allow-lists.","The product has no sign-in, attestation, or identity verification step."]},"designerTakeaways":["You can design UI that delivers message 0xABC directly, cryptographically verified.","You can design UI that delivers encrypted messages only decryptable by recipient.","You can design UI that delivers messages stored on-chain, censorship-resistant."],"problemsSolved":[{"problem":"No standard way to message a wallet address","oldWay":"Find their Twitter/Discord, hope it's the right person, no verification","newWay":"Message 0xABC directly, cryptographically verified","impact":"critical"},{"problem":"On-chain messages are public and readable by anyone","oldWay":"Send a transaction with data field = your message (visible to all)","newWay":"Encrypted messages only decryptable by recipient","impact":"critical"},{"problem":"Centralized messaging platforms control communication","oldWay":"Discord/Twitter can ban, delete messages, read content","newWay":"Messages stored on-chain, censorship-resistant","impact":"high"},{"problem":"NFT buyers can't negotiate with sellers privately","oldWay":"Public comments, DM through social platforms","newWay":"Private offer negotiation directly wallet-to-wallet","impact":"medium"}],"uxPatterns":[{"name":"Wallet-to-Wallet Messaging","description":"Send encrypted message to any wallet address","mockup":"concept/nft-gallery","userFlow":["Enter recipient address or ENS","Compose message","Message encrypted client-side","Sign transaction to send","Message stored on-chain encrypted","Only recipient can decrypt"]},{"name":"Inbox Interface","description":"View and manage encrypted messages","mockup":"concept/session-permissions","userFlow":["User opens inbox","Messages fetched from chain","Decrypted locally with wallet key","Display previews and timestamps","Click to read full message"]},{"name":"Message Thread View","description":"Conversation view with reply functionality","mockup":"concept/nft-gallery","userFlow":["Click on message to open thread","See full conversation history","Compose reply","Each message is separate transaction","Option to block sender"]},{"name":"Spam Filtering","description":"Filter unwanted messages","mockup":"concept/session-permissions","userFlow":["User configures message filters","Select who can send messages","Manage blocked addresses","Settings stored on-chain or locally","Filter applied to incoming messages"]}],"uiComponents":[{"name":"EncryptedMessageComposer","description":"Text input that encrypts before sending","states":["composing","encrypting","sending","sent","error"],"props":["recipient","onSend","maxLength"]},{"name":"DecryptedMessageViewer","description":"Displays decrypted message content","states":["decrypting","decrypted","decrypt-error"],"props":["encryptedData","sender","timestamp"]},{"name":"InboxList","description":"List of received messages with previews","states":["loading","loaded","empty","filtered"],"props":["messages[]","filter","onSelect"]},{"name":"EncryptionBadge","description":"Visual indicator that message is encrypted","states":["encrypted","decrypting","decrypted"],"props":["status"]}],"antiPatterns":[{"pattern":"Sending messages unencrypted","why":"Defeats the purpose, messages readable by anyone","instead":"Always encrypt before storing on-chain","severity":"critical"},{"pattern":"No spam protection","why":"Inbox flooded with unwanted messages, unusable","instead":"Implement filtering, blocking, and allow-lists","severity":"high"},{"pattern":"Storing decrypted messages on server","why":"Breaks end-to-end encryption promise","instead":"Decrypt client-side only, never send plaintext to server","severity":"critical"},{"pattern":"No indication of encryption status","why":"Users don't know if message is private","instead":"Show clear 🔒 indicator when encrypted","severity":"high"}],"onMonad":[{"aspect":"Message Delivery","ethereum":"Message takes 15+ seconds to be \"sent\"","monad":"Sub-second delivery, feels like regular chat","designImplication":"Can build real-time-feeling chat experience"},{"aspect":"Cost Per Message","ethereum":"Each message costs $1-5+ in gas","monad":"Negligible cost enables casual conversation","designImplication":"Can encourage back-and-forth communication"},{"aspect":"Message History","ethereum":"Fetching history is slow/expensive","monad":"Fast reads enable real-time inbox refresh","designImplication":"Can show \"last seen\" and real-time typing indicators"},{"aspect":"Throughput","ethereum":"Limited messages per block","monad":"High throughput enables busy messaging apps","designImplication":"Can support group chats and high-volume communication"}],"keyTakeaways":["End-to-end encryption is mandatory - message only readable by recipient","Decrypt client-side only, never on server","Show clear encryption indicators (🔒)","Implement spam filtering - allow-lists, blocking, filters","On Monad: cheap + fast enables actual chat-like experience"],"technicalNotes":"ERC-7627 uses asymmetric encryption where the sender encrypts with recipient's public key. Messages are stored on-chain as encrypted bytes. The recipient's wallet decrypts using their private key. The standard defines message format, key derivation, and inbox querying. Integration with ENS allows addressing by name instead of address."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-7627","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-7627","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-7627","markdown":"https://www.eipsfordesigners.com/standards/ERC-7627/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-7627/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-7627","official":"https://eips.ethereum.org/EIPS/eip-7627","discussion":"https://ethereum-magicians.org/search?q=ERC-7627"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"ERC-721","name":"Non-Fungible Token Standard","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":"Each token is unique with distinct ownership — the foundation of all NFT UX. Design implications: show single-item detail views with ownership info and provenance history, display unique token IDs prominently, design 1:1 transfer flows (not quantity selectors), implement approval flows for marketplace listings with clear 'Approve' vs 'Approve All' distinction. Design decisions: balance between showing technical token IDs vs friendly names, whether to expose raw contract addresses or use ENS/profiles, how much provenance history to surface without overwhelming users.","hasDetailedContent":true,"content":{"id":"ERC-721","summary":"ERC-721 defines non-fungible tokens (NFTs). Unlike ERC-20 where every token is identical, each ERC-721 token has a unique ID. This enables digital art, collectibles, game items, membership passes, and anything where each item is distinct. It specifies ownership, transfers, approvals, and metadata linking — the foundation of the NFT ecosystem.","designerTakeaways":["You can preview image, collection name, and token id before irreversible transfers.","You can use per-token approval unless marketplace trust justifies operator approve.","You can lazy-load metadata with placeholders when images or traits fail to load."],"applicability":{"whenToUse":["Each asset has a unique id and separate ownership.","Marketplaces or wallets must list, transfer, or approve single items.","Metadata (image, traits) is tied to tokenURI per token."],"whenToAvoid":["Large quantities of identical items (prefer ERC-1155).","Fungible positions or vault shares (use ERC-20 or ERC-4626).","You only need off-chain collectibles with no wallet transfers."]},"designDecisions":[{"question":"Single-token approve or operator approve?","recommendation":"Use setApprovalForAll only with marketplace trust copy; default to per-token approve for unknown spenders.","rationale":"Operator approval grants control over the entire collection, not one listing."},{"question":"How is metadata failure shown?","recommendation":"Placeholder art plus \"metadata unavailable\" instead of a broken image tile.","rationale":"Broken media reads as a scam or bug during high-intent purchase moments."},{"question":"What does the transfer confirmation show?","recommendation":"Preview image, collection name, token id, and recipient before sign.","rationale":"NFT transfers are irreversible; users need identity checks beyond a hex address."},{"question":"How do you surface collection-level risk?","recommendation":"Flag unverified collections and spoofed names separately from verified badges.","rationale":"Users confuse lookalike collections when browsing quickly."}],"statesToDesign":[{"state":"Metadata loading","trigger":"tokenURI fetch or image CDN request pending.","userNeed":"Know the item exists while media loads.","designResponse":"Skeleton tile with collection name and token id visible."},{"state":"Not owner","trigger":"User attempts action on a token they do not hold.","userNeed":"Understand why buy, list, or transfer is disabled.","designResponse":"Disable primary action with \"You do not own this item\" copy."},{"state":"Approval for marketplace","trigger":"Marketplace needs operator or token approval.","userNeed":"Know scope of access being granted.","designResponse":"State whether approval is for one token or all items in the collection."},{"state":"Transfer in progress","trigger":"safeTransferFrom submitted.","userNeed":"Confidence the item is leaving the wallet.","designResponse":"Pending state on item card; remove or dim after confirmation."},{"state":"Received airdrop","trigger":"Unexpected token appears in wallet.","userNeed":"Avoid interacting with malicious airdrops.","designResponse":"Hide or quarantine unverified drops; warn before first interaction."}],"problemsSolved":[{"problem":"No standard for unique digital items","oldWay":"Each project invented its own ownership system","newWay":"ERC-721: universal interface for unique tokens","impact":"critical"},{"problem":"Marketplaces couldn't support all NFTs","oldWay":"Custom integration for each NFT contract","newWay":"Any ERC-721 works on OpenSea, Blur, etc.","impact":"critical"},{"problem":"No standard way to link NFT to its image/metadata","oldWay":"Random ways to store and retrieve NFT info","newWay":"tokenURI() returns metadata JSON with image, attributes","impact":"high"},{"problem":"Couldn't approve operators for all NFTs at once","oldWay":"Approve each NFT individually before selling","newWay":"setApprovalForAll() for marketplace integration","impact":"high"}],"uxPatterns":[{"name":"NFT Collection Gallery","description":"Display user's NFT holdings in a visual grid","mockup":"concept/nft-gallery","userFlow":["App queries user's NFT holdings","Fetches tokenURI for each","Loads and caches images","Displays in responsive grid","Lazy loads as user scrolls"]},{"name":"NFT Detail View","description":"Single NFT with full metadata and actions","mockup":"concept/nft-gallery","userFlow":["User selects NFT from gallery","App fetches tokenURI metadata","Parses JSON for attributes","Shows rarity percentages","Displays action buttons"]},{"name":"NFT Transfer","description":"Send NFT to another address","mockup":"concept/nft-gallery","userFlow":["User selects NFT to transfer","Enters recipient address","App validates address format","Shows value and warning","User confirms transfer","Calls safeTransferFrom()"]},{"name":"Marketplace Approval","description":"Approve marketplace to list NFTs","mockup":"generic/token-approval","userFlow":["User tries to list NFT","Marketplace detects no approval","Shows approval options","User selects scope","Calls approve() or setApprovalForAll()","Can now list NFTs"]}],"uiComponents":[{"name":"NFTCard","description":"Thumbnail card showing NFT image, name, collection","states":["loading","loaded","error","selected"],"props":["tokenId","contractAddress","metadata","onClick"]},{"name":"NFTImage","description":"Handles various media types (image, video, audio, 3D)","states":["loading","loaded","error","fallback"],"props":["uri","type","fallbackImage"]},{"name":"AttributeList","description":"Displays NFT traits with rarity percentages","states":["loading","loaded","no-attributes"],"props":["attributes[]","showRarity"]},{"name":"CollectionBadge","description":"Shows collection name with verified checkmark","states":["verified","unverified","flagged"],"props":["name","address","isVerified"]},{"name":"NFTTransferForm","description":"Form for transferring NFT to another address","states":["input","validating","ready","sending","success"],"props":["nft","onTransfer"]}],"antiPatterns":[{"pattern":"Not validating recipient can receive NFTs","why":"Some contracts can't receive NFTs, tokens get stuck","instead":"Use safeTransferFrom() which checks ERC-721Receiver","severity":"critical"},{"pattern":"Loading all NFT images at once","why":"Large collections crash browser, waste bandwidth","instead":"Virtualize list, lazy load images as they scroll into view","severity":"high"},{"pattern":"Trusting tokenURI without validation","why":"Malicious metadata can include XSS, phishing links","instead":"Sanitize metadata, validate URLs, sandbox iframes","severity":"critical"},{"pattern":"Not caching metadata","why":"Every view re-fetches from IPFS/HTTP, slow and wasteful","instead":"Cache tokenURI responses, invalidate on transfer","severity":"medium"},{"pattern":"Assuming all NFTs have metadata","why":"Some contracts return empty tokenURI or fail","instead":"Graceful fallback: show token ID, placeholder image","severity":"high"},{"pattern":"Not explaining setApprovalForAll risks","why":"Users don't realize they're approving ALL NFTs in collection","instead":"Clear warning: \"This approves ALL your [collection] NFTs\"","severity":"high"}],"onMonad":[{"aspect":"Transfer Speed","ethereum":"Transfer takes 12+ seconds to confirm","monad":"Sub-second finality","designImplication":"Instant ownership updates in UI"},{"aspect":"Minting Experience","ethereum":"Mint transaction → wait → check if succeeded","monad":"Mint → instant confirmation","designImplication":"Can show NFT immediately after mint"},{"aspect":"Batch Operations","ethereum":"Each transfer is separate transaction","monad":"Batch transfers via 7702 possible","designImplication":"Enable \"Send multiple NFTs\" feature"},{"aspect":"Gas for Transfers","ethereum":"Transfer costs significant gas","monad":"Much cheaper per transfer","designImplication":"More viable to move NFTs frequently"}],"keyTakeaways":["ERC-721 = unique tokens, each with distinct ID","Always use safeTransferFrom() to prevent stuck NFTs","Lazy load images, cache metadata","Sanitize tokenURI metadata for security","Explain setApprovalForAll risks clearly"],"technicalNotes":"ERC-721 specifies: balanceOf, ownerOf, safeTransferFrom, transferFrom, approve, setApprovalForAll, getApproved, isApprovedForAll. Events: Transfer, Approval, ApprovalForAll. Optional: name(), symbol(), tokenURI(). Metadata JSON format: { name, description, image, attributes[] }. safeTransferFrom checks if recipient is contract and calls onERC721Received()."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-721","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-721","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-721","markdown":"https://www.eipsfordesigners.com/standards/ERC-721/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-721/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-721","official":"https://eips.ethereum.org/EIPS/eip-721","discussion":"https://ethereum-magicians.org/search?q=ERC-721"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"ERC-1155","name":"Multi Token Standard","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":"Single contract holds multiple token types (fungible and non-fungible) with batch operations. Design implications: design inventory views supporting both unique items and stackable quantities, show quantity selectors for semi-fungible tokens, enable multi-select batch transfers to save gas, display mixed collections (1/1s alongside editions) coherently. Design decisions: how to visually differentiate unique vs edition tokens, whether batch operations should be default or advanced feature, balancing simplified UI against power-user batch capabilities.","hasDetailedContent":true,"content":{"id":"ERC-1155","summary":"ERC-1155 is the \"multi-token\" standard. One contract can hold many different token types — both fungible (like gold coins, 1000 of them) and non-fungible (unique sword #47). Users can transfer multiple items in a single transaction. Perfect for games, where you have 50 health potions, 3 rare swords, and 1 legendary armor.","applicability":{"whenToUse":["One contract holds many item types with different balances per id.","Games or marketplaces need batch send, burn, or trade in one step.","You mix fungible stacks and unique items without separate ERC-20/721 contracts."],"whenToAvoid":["Every asset is a single unique NFT (ERC-721 is simpler).","Users only swap fungible tokens with no per-id inventory.","Wallets cannot render quantity balances per id clearly."]},"designerTakeaways":["You can show stacked quantities (x50 potions) plus unique items in one inventory.","You can batch-transfer multiple ids in one confirmation to cut gas and taps.","You can separate fungible stacks from one-of-one items in the same contract UI."],"problemsSolved":[{"problem":"Separate contracts for each item type","oldWay":"Deploy contract for swords, another for shields, another for potions...","newWay":"One contract holds all items with different IDs","impact":"critical"},{"problem":"Transferring multiple NFTs is expensive","oldWay":"Send 10 items = 10 transactions = 10x gas","newWay":"Batch transfer: send 10 items in one transaction","impact":"high"},{"problem":"Can't have \"semi-fungible\" items","oldWay":"Item is either unique (ERC-721) or identical (ERC-20)","newWay":"ID 1 = common sword (1000 exist), ID 2 = legendary (1 exists)","impact":"high"}],"uxPatterns":[{"name":"Game Inventory","description":"Display mixed item types in one view","mockup":"concept/nft-gallery","userFlow":["User opens inventory","App fetches all token IDs + balances","Groups by category/type","Shows quantity for each ID","Marks unique items specially"]},{"name":"Batch Transfer","description":"Send multiple items in one transaction","mockup":"concept/nft-gallery","userFlow":["User selects multiple items","Adjusts quantities for each","App shows batch preview","Displays gas savings","Single transaction sends all"]},{"name":"Collection Overview","description":"Show collection with supply info","mockup":"concept/nft-gallery","userFlow":["User views collection page","App lists all token IDs","Shows total supply per ID","Shows user balance per ID","Highlights rare/unique items"]}],"uiComponents":[{"name":"ItemCard","description":"Single item with quantity badge","states":["owned","not-owned","selected","transferring"],"props":["tokenId","metadata","balance","onSelect"]},{"name":"QuantitySelector","description":"Adjust quantity for transfer/use","states":["idle","editing","max-reached"],"props":["value","max","onChange"]},{"name":"BatchTransferForm","description":"Select multiple items + quantities","states":["selecting","ready","sending","complete"],"props":["items[]","recipient","onTransfer"]},{"name":"SupplyBadge","description":"Shows total supply and rarity","states":["unlimited","limited","unique"],"props":["supply","maxSupply"]}],"antiPatterns":[{"pattern":"Not showing quantities clearly","why":"User doesn't know they have 50 of something","instead":"Always show \"x50\" or quantity badge","severity":"high"},{"pattern":"Treating all 1155 tokens as unique","why":"Fungible items (potions) don't need individual cards","instead":"Stack same IDs, show quantity","severity":"medium"},{"pattern":"Only offering single-item transfers","why":"Wastes gas, poor UX for games","instead":"Always offer batch transfer option","severity":"high"},{"pattern":"Not indicating rarity/uniqueness","why":"User doesn't know Dragon Blade is 1-of-1","instead":"Show supply: \"1 of 1\" vs \"42 of 10,000\"","severity":"medium"}],"onMonad":[{"aspect":"Batch Gas Costs","ethereum":"Batch saves ~70% vs individual transfers","monad":"Same savings ratio, lower absolute costs","designImplication":"Still emphasize batching for UX convenience"},{"aspect":"Transfer Speed","ethereum":"Batch takes 12+ seconds to confirm","monad":"Sub-second confirmation","designImplication":"Inventory updates feel instant"}],"keyTakeaways":["ERC-1155 = multiple token types in one contract","Always show quantities (x50, x100)","Offer batch transfers by default","Indicate rarity: \"1 of 1\" vs \"1 of 10,000\"","Stack fungible items, don't show individual cards"],"technicalNotes":"ERC-1155 defines balanceOf(account, id), balanceOfBatch, safeTransferFrom, safeBatchTransferFrom, and approval via setApprovalForAll. URI can be dynamic with {id} placeholder. Events: TransferSingle, TransferBatch, ApprovalForAll, URI. Receiver contracts must implement onERC1155Received and onERC1155BatchReceived."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-1155","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-1155","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-1155","markdown":"https://www.eipsfordesigners.com/standards/ERC-1155/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-1155/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-1155","official":"https://eips.ethereum.org/EIPS/eip-1155","discussion":"https://ethereum-magicians.org/search?q=ERC-1155"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"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"}},{"id":"ERC-4907","name":"Rental NFT","status":"Final","chain":"both","category":{"id":"nft","name":"NFT Capabilities","description":"What NFTs can do beyond basic ownership"},"journeyStages":[{"id":"approving","name":"Approving & Permissioning","description":"Granting permissions for actions"},{"id":"management","name":"Asset Management","description":"Managing assets over time"}],"uxImpact":"NFTs have separate 'owner' and 'user' roles with automatic expiration — enabling trustless rentals. Design implications: display dual ownership badges (Owner vs User), show rental expiration countdown timers, design rental listing flows with duration pickers, indicate 'rented out' status on owned items, auto-update UI when rental expires without transaction. Design decisions: how prominently to show rental status vs ownership, whether to notify users before rental expiry, handling edge cases where user tries owner-only actions.","hasDetailedContent":true,"content":{"id":"ERC-4907","summary":"ERC-4907 adds rental functionality to NFTs. The owner can rent out their NFT to a \"user\" for a set time period. The renter gets usage rights without ownership. When the rental expires, usage rights automatically revert. Perfect for game items, virtual land, or any NFT with utility that can be temporarily shared.","applicability":{"whenToUse":["Your product addresses: no standard way to rent NFTs.","Your product addresses: renter could sell/transfer the NFT.","The flow should deliver: set user + expiration, owner keeps ownership.","You are designing a rental listing experience with visible states and recovery paths."],"whenToAvoid":["Always show countdown, warn as expiration approaches.","Always check userOf() AND userExpires() > now.","Clear badges: \"You OWN this\" vs \"You RENT this\".","Assets are fungible tokens only with no unique-item semantics."]},"designerTakeaways":["You can design UI that delivers set user + expiration, owner keeps ownership.","You can design UI that delivers owner retains ownership, only usage is delegated.","You can design UI that delivers simple setUser() call with expiration."],"problemsSolved":[{"problem":"No standard way to rent NFTs","oldWay":"Transfer NFT, trust renter to return it (they often don't)","newWay":"Set user + expiration, owner keeps ownership","impact":"critical"},{"problem":"Expensive to \"loan\" NFTs safely","oldWay":"Use escrow contracts, complex collateral systems","newWay":"Simple setUser() call with expiration","impact":"high"},{"problem":"Renter could sell/transfer the NFT","oldWay":"Owner loses asset if they transfer ownership for rental","newWay":"Owner retains ownership, only usage is delegated","impact":"critical"}],"uxPatterns":[{"name":"Rental Listing","description":"List NFT for rent with price and duration","mockup":"concept/nft-gallery","userFlow":["Owner selects NFT to rent","Sets price per day","Sets maximum duration","Signs rental listing","NFT available for rent"]},{"name":"Rental Marketplace","description":"Browse and rent NFTs","mockup":"concept/nft-gallery","userFlow":["User browses available rentals","Clicks \"Rent\" on desired item","Selects rental duration","Pays rental fee","Becomes \"user\" of NFT"]},{"name":"Active Rental Status","description":"View current rental with countdown","mockup":"concept/nft-gallery","userFlow":["User views their rental","Sees time remaining","Progress bar shows rental period","Option to extend before expiry","Warning as expiration approaches"]}],"uiComponents":[{"name":"RentalCard","description":"NFT card with rental info","states":["available","rented-by-you","rented-by-other","your-listing"],"props":["nft","price","duration","user","expires"]},{"name":"ExpirationTimer","description":"Countdown to rental expiration","states":["plenty-of-time","expiring-soon","expired"],"props":["expiresAt","onExpire"]},{"name":"RentalDurationPicker","description":"Select how long to rent","states":["selecting","selected"],"props":["minDuration","maxDuration","pricePerDay","onChange"]},{"name":"UserRoleBadge","description":"Shows if you're owner vs user","states":["owner","user","both","neither"],"props":["owner","user","currentAccount"]}],"antiPatterns":[{"pattern":"Not showing expiration prominently","why":"User loses access unexpectedly","instead":"Always show countdown, warn as expiration approaches","severity":"critical"},{"pattern":"Confusing \"owner\" and \"user\" roles","why":"Users don't understand their rights","instead":"Clear badges: \"You OWN this\" vs \"You RENT this\"","severity":"high"},{"pattern":"Not checking user() before granting access","why":"Expired rentals could still access utility","instead":"Always check userOf() AND userExpires() > now","severity":"critical"},{"pattern":"No reminder before expiration","why":"User surprised when access revoked","instead":"Notify at 24h, 1h, and near expiration","severity":"high"}],"onMonad":[{"aspect":"Rental Start","ethereum":"setUser() takes 12+ seconds","monad":"Instant rental activation","designImplication":"Renter can start using immediately"},{"aspect":"Expiration Checks","ethereum":"Block timestamp granularity","monad":"Faster blocks = more precise expiration","designImplication":"Can show more accurate countdown"}],"keyTakeaways":["ERC-4907 = NFT rentals with automatic expiration","Owner keeps ownership, user gets usage rights","Always check expiration before granting access","Show clear countdown to expiration","Distinguish \"owner\" vs \"user\" roles clearly"],"technicalNotes":"ERC-4907 extends ERC-721 with setUser(tokenId, user, expires) and userOf(tokenId), userExpires(tokenId) view functions. The \"user\" has usage rights but cannot transfer. When block.timestamp > expires, userOf returns address(0). UpdateUser event emitted on changes. Backward compatible — non-4907-aware contracts just see regular ERC-721."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-4907","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-4907","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-4907","markdown":"https://www.eipsfordesigners.com/standards/ERC-4907/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-4907/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-4907","official":"https://eips.ethereum.org/EIPS/eip-4907","discussion":"https://ethereum-magicians.org/search?q=ERC-4907"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"ERC-5006","name":"Rental NFT for ERC-1155","status":"Final","chain":"both","category":{"id":"nft","name":"NFT Capabilities","description":"What NFTs can do beyond basic ownership"},"journeyStages":[{"id":"approving","name":"Approving & Permissioning","description":"Granting permissions for actions"},{"id":"management","name":"Asset Management","description":"Managing assets over time"}],"uxImpact":"Rental system for ERC-1155 tokens with quantity-based user records and expiration. Design implications: show 'usable balance' vs 'frozen balance' separately, display rental records with amount/expiry per record, enable partial quantity rentals, design rental management dashboards showing multiple active rentals. Design decisions: how to visualize frozen vs usable tokens in inventory, complexity of supporting multiple concurrent rental records, whether to auto-consolidate expired records.","hasDetailedContent":true,"content":{"id":"ERC-5006","summary":"ERC-5006 enables renting ERC-1155 multi-tokens with quantity tracking. Rent 10 of your 100 gaming items to another player - they get usage rights, you keep ownership, and rentals auto-expire. Perfect for game item lending and partial asset rentals.","applicability":{"whenToUse":["Your product must handle: can't rent partial amounts of multi-token holdings.","Your product addresses: no standard rental interface for ERC-1155.","The flow should deliver: rent exactly 10 swords while keeping 90 for yourself.","You are designing a partial rental listing experience with visible states and recovery paths."],"whenToAvoid":["Show: \"Owned: 100 | Available: 85 | Rented Out: 15\".","Disable/limit quantity selector to available amount.","Warn \"Rental expires in 2 hours\" with option to extend.","Assets are fungible tokens only with no unique-item semantics."]},"designerTakeaways":["You can design UI that delivers rent exactly 10 swords while keeping 90 for yourself.","You can standard setUser/userOf interface works across all games.","You can design UI that delivers built-in expiration."],"problemsSolved":[{"problem":"Can't rent partial amounts of multi-token holdings","oldWay":"Own 100 swords but can only rent all or nothing","newWay":"Rent exactly 10 swords while keeping 90 for yourself","impact":"critical"},{"problem":"No standard rental interface for ERC-1155","oldWay":"Each game invents custom lending, inconsistent UX","newWay":"Standard setUser/userOf interface works across all games","impact":"high"},{"problem":"Rentals don't auto-expire","oldWay":"Manual reclaim process, renter might not return items","newWay":"Built-in expiration, items automatically return on expiry","impact":"high"},{"problem":"Can't track who has usage rights vs ownership","oldWay":"Transfer token to lend it, risky and permanent","newWay":"Owner and user are separate roles with clear tracking","impact":"medium"},{"problem":"Guild item sharing is complex","oldWay":"Trust someone with your items or don't share at all","newWay":"Grant time-limited usage rights without losing ownership","impact":"medium"}],"uxPatterns":[{"name":"Partial Rental Listing","description":"List some of your items for rent while keeping others","mockup":"generic/list-selector","userFlow":["User views their multi-token inventory","Selects quantity to rent (not all)","Sets duration and price","Creates listing","Items available but user still owns all 100"]},{"name":"Guild Item Lending","description":"Share items with guild members temporarily","mockup":"generic/vault-deposit","userFlow":["Guild leader views armory","Selects items and quantities to lend","Chooses duration (free for guild)","Confirms lending","Member can use items until expiry"]},{"name":"Active Rentals Dashboard","description":"Track items you're renting and items rented out","mockup":"generic/balance-display","userFlow":["User views rental dashboard","Sees items they're renting out + earnings","Sees items they're renting + costs","Can extend rentals before expiry","Expired rentals auto-return"]},{"name":"Rental Marketplace","description":"Browse and rent items from other players","mockup":"generic/list-selector","userFlow":["User browses rental marketplace","Sees available quantities and prices","Selects desired quantity","Confirms rental duration","Gets usage rights, items appear in inventory"]}],"uiComponents":[{"name":"PartialQuantitySelector","description":"Select quantity from available balance","states":["selecting","max-reached","min-reached"],"props":["available","selected","min","max","onChange"]},{"name":"RentalExpiryTimer","description":"Countdown to rental expiration","states":["plenty-time","expiring-soon","expired"],"props":["expiresAt","onExpiringSoon","showExtend"]},{"name":"OwnerUserDisplay","description":"Show owner vs current user of items","states":["owner-using","rented-out","renting-in"],"props":["owner","user","quantity","expiresAt"]},{"name":"RentalListingForm","description":"Create rental listing for multi-tokens","states":["editing","previewing","listing","active"],"props":["tokenId","maxQuantity","pricePerDay","minDuration"]},{"name":"InventoryWithRentals","description":"Inventory showing owned vs rented vs rented-out","states":["all","owned","renting","rented-out"],"props":["items[]","filter","onItemClick"]}],"antiPatterns":[{"pattern":"Not showing quantity breakdown clearly","why":"User doesn't know how many they own vs have rented out","instead":"Show: \"Owned: 100 | Available: 85 | Rented Out: 15\"","severity":"critical"},{"pattern":"No expiration warning before rental ends","why":"User loses access suddenly, bad for gameplay","instead":"Warn \"Rental expires in 2 hours\" with option to extend","severity":"high"},{"pattern":"Hiding who the current user is","why":"Games need to know who can USE items, not just who owns","instead":"Clearly show: \"Owner: alice | User: bob (until Feb 10)\"","severity":"high"},{"pattern":"Allowing negative available balance","why":"Can't rent more than you own minus already rented","instead":"Disable/limit quantity selector to available amount","severity":"critical"},{"pattern":"No rental history","why":"Users want to see their lending/borrowing track record","instead":"Show rental history with earnings and costs","severity":"medium"},{"pattern":"Complex rental extension flow","why":"Users should easily extend before expiry","instead":"One-click \"Extend 7 more days\" button","severity":"medium"}],"onMonad":[{"aspect":"Rental Transactions","ethereum":"Each rental is a transaction, costs add up","monad":"Low gas makes frequent short-term rentals viable","designImplication":"Can offer hourly rentals economically"},{"aspect":"Expiration Check","ethereum":"Block timestamps for expiry, 12-second granularity","monad":"Sub-second blocks allow precise rental durations","designImplication":"Can show \"expires in X minutes\" accurately"},{"aspect":"Real-time Inventory","ethereum":"Querying rental state can be slow","monad":"Fast queries enable real-time inventory updates","designImplication":"Inventory updates instantly as rentals change"},{"aspect":"Gaming Integration","ethereum":"Rental UX often separate from game","monad":"Fast finality enables in-game rental flows","designImplication":"Integrate rental directly into gameplay"}],"keyTakeaways":["ERC-5006 = ERC-1155 rental with quantities","Owner keeps ownership, user gets time-limited usage","Show available vs rented-out quantities clearly","Rentals auto-expire, no manual reclaim needed","Warn users before rental expiration"],"technicalNotes":"ERC-5006 extends ERC-1155 with setUser(tokenId, user, amount, expiry) and usableBalanceOf(user, tokenId). The owner retains balanceOf, while usableBalanceOf tracks who can actually use tokens. After expiry block, usableBalanceOf returns to owner automatically. Useful for gaming items, utility tokens, and time-limited access."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-5006","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-5006","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-5006","markdown":"https://www.eipsfordesigners.com/standards/ERC-5006/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-5006/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-5006","official":"https://eips.ethereum.org/EIPS/eip-5006","discussion":"https://ethereum-magicians.org/search?q=ERC-5006"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"ERC-5007","name":"Time NFT Extension","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 have built-in start and end times — tokens can be time-bounded or represent time periods. Design implications: show validity period badges ('Valid: Jan 1 - Dec 31'), gray out or hide expired tokens, display countdown to activation/expiration, support time-range visualization for event tickets or subscriptions. Design decisions: whether to completely hide invalid-period tokens or show them disabled, how to handle timezone display, whether to allow splitting/merging time-bounded tokens if composable extension used.","hasDetailedContent":true,"content":{"id":"ERC-5007","summary":"ERC-5007 adds time validity to NFTs with built-in start and end times. Perfect for subscriptions, season passes, time-limited memberships, and access tokens that automatically become invalid after expiration.","applicability":{"whenToUse":["Your product addresses: subscriptions require off-chain expiration tracking.","Your product addresses: expired access tokens still appear in wallets.","The flow should deliver: nFT has on-chain startTime/endTime, contracts can check directly.","You are designing a subscription card experience with visible states and recovery paths."],"whenToAvoid":["Always show \"Valid until [date]\" prominently.","Visually distinguish expired tokens (gray out, badge).","Warn at 30, 7, and 1 day before expiry.","Assets are fungible tokens only with no unique-item semantics."]},"designerTakeaways":["You can design UI that delivers nFT has on-chain startTime/endTime.","You can design UI that delivers uI can show \"Valid until Dec 31\" or \"Expired\" clearly.","You can design UI that delivers set startTime in future: \"Valid Jan 1, Dec 31, 2027\"."],"problemsSolved":[{"problem":"Subscriptions require off-chain expiration tracking","oldWay":"NFT exists forever, backend checks if subscription is active","newWay":"NFT has on-chain startTime/endTime, contracts can check directly","impact":"critical"},{"problem":"Expired access tokens still appear in wallets","oldWay":"User sees membership NFT but it's actually expired","newWay":"UI can show \"Valid until Dec 31\" or \"Expired\" clearly","impact":"high"},{"problem":"Can't create future-starting access","oldWay":"NFT is valid from mint time, can't pre-sell future access","newWay":"Set startTime in future: \"Valid Jan 1 - Dec 31, 2027\"","impact":"high"},{"problem":"Renewal requires burn and remint","oldWay":"Extend subscription by burning old NFT, minting new one","newWay":"Just update endTime to extend validity period","impact":"medium"},{"problem":"Smart contracts can't verify time-based access","oldWay":"Off-chain oracle needed to verify subscription status","newWay":"On-chain time check: if (block.timestamp < endTime) grant access","impact":"medium"}],"uxPatterns":[{"name":"Subscription Card","description":"Display time-limited NFT with validity period","mockup":"concept/nft-gallery","userFlow":["User views their membership NFT","Sees validity period and time remaining","Progress bar shows how much time used","Can renew before expiration","After expiry, card shows \"Expired\" status"]},{"name":"Season Pass Timeline","description":"Show season pass with start and end dates","mockup":"concept/nft-gallery","userFlow":["User purchases season pass","Sees exact start and end dates","Timeline shows current position","Tracks progress toward rewards","Pass automatically expires at season end"]},{"name":"Future Access Pre-Sale","description":"Sell access that starts in the future","mockup":"generic/token-transfer","userFlow":["User sees pre-sale for future access","Pass has startTime in the future","User purchases at discount","NFT minted but not yet active","Automatically activates on startTime"]},{"name":"Expired Token Display","description":"Clear indication when time-limited NFT has expired","mockup":"concept/nft-gallery","userFlow":["User views expired NFT","Card clearly shown as expired (grayed out)","Shows when it expired","Option to hide or renew","Renewal extends endTime"]}],"uiComponents":[{"name":"ValidityPeriodDisplay","description":"Show start and end time of NFT","states":["not-started","active","expiring-soon","expired"],"props":["startTime","endTime","showProgress"]},{"name":"ExpiryCountdown","description":"Countdown to expiration","states":["plenty-time","warning","critical","expired"],"props":["endTime","warningThreshold","criticalThreshold"]},{"name":"TimelineBadge","description":"Visual timeline showing validity period","states":["past","present","future"],"props":["startTime","endTime","currentTime"]},{"name":"RenewalPrompt","description":"Prompt to renew expiring NFT","states":["hidden","suggested","urgent"],"props":["daysUntilExpiry","renewalPrice","onRenew"]},{"name":"ExpiredOverlay","description":"Overlay for expired NFT display","states":["expired","renewable","permanently-expired"],"props":["expiredAt","canRenew","onRenew","onHide"]}],"antiPatterns":[{"pattern":"Hiding validity period from users","why":"Users surprised when access suddenly revoked","instead":"Always show \"Valid until [date]\" prominently","severity":"critical"},{"pattern":"No warning before expiration","why":"Users miss renewal window, lose access","instead":"Warn at 30, 7, and 1 day before expiry","severity":"high"},{"pattern":"Treating expired NFTs same as active","why":"Confusing when NFT appears valid but doesn't work","instead":"Visually distinguish expired tokens (gray out, badge)","severity":"critical"},{"pattern":"Not showing future-starting passes clearly","why":"User thinks NFT is broken when it's just not active yet","instead":"Show \"Activates in X days\" with clear start date","severity":"high"},{"pattern":"Complex renewal process","why":"Users give up on renewing, churn increases","instead":"One-click renewal that extends endTime","severity":"medium"},{"pattern":"Burning expired NFTs automatically","why":"Users lose collectible/proof they had membership","instead":"Keep expired NFT visible, just mark as expired","severity":"medium"}],"onMonad":[{"aspect":"Timestamp Precision","ethereum":"12-second blocks, timestamps approximate","monad":"Sub-second blocks, more precise timing possible","designImplication":"Can show \"expires in X hours\" with higher accuracy"},{"aspect":"Renewal Transactions","ethereum":"Renewal costs gas, users might delay","monad":"Low gas makes last-minute renewals easy","designImplication":"Can offer \"renew instantly\" even at expiry"},{"aspect":"Access Checks","ethereum":"On-chain time checks in contracts","monad":"Fast finality means access revocation is instant","designImplication":"Access changes the moment endTime passes"},{"aspect":"Short-Duration Passes","ethereum":"Gas cost limits viability of daily passes","monad":"Low cost enables hourly or daily access tokens","designImplication":"Can design micro-duration access products"}],"keyTakeaways":["ERC-5007 = NFT with built-in start and end time","Perfect for subscriptions, season passes, memberships","Always show validity period prominently","Warn before expiration (30/7/1 day)","Keep expired NFTs visible, just marked as expired"],"technicalNotes":"ERC-5007 extends ERC-721 with startTime() and endTime() returning uint64 timestamps. Interface includes IERC5007 with these two functions. Contracts can check if (block.timestamp >= startTime && block.timestamp <= endTime) to verify validity. Common to pair with ERC-4907 for rental time windows or standalone for subscriptions."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-5007","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-5007","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-5007","markdown":"https://www.eipsfordesigners.com/standards/ERC-5007/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-5007/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-5007","official":"https://eips.ethereum.org/EIPS/eip-5007","discussion":"https://ethereum-magicians.org/search?q=ERC-5007"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"ERC-7432","name":"Non-Fungible Token Roles","status":"Final","chain":"both","category":{"id":"nft","name":"NFT Capabilities","description":"What NFTs can do beyond basic ownership"},"journeyStages":[{"id":"approving","name":"Approving & Permissioning","description":"Granting permissions for actions"},{"id":"management","name":"Asset Management","description":"Managing assets over time"}],"uxImpact":"Multiple custom roles (not just user/owner) can be assigned to NFTs with expiration and custom data. Design implications: display role badges per NFT (e.g., 'Manager', 'Tenant', 'Beneficiary'), show role assignment/revocation flows, visualize role hierarchies and permissions, design role marketplace for granting/revoking. Design decisions: how many roles to display before truncating, whether to show technical role IDs or friendly names, complexity of multi-role management UI vs simplified views.","hasDetailedContent":true,"content":{"id":"ERC-7432","sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-7432","type":"official-spec"}],"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25","summary":"Multiple custom roles (not just user/owner) can be assigned to NFTs with expiration and custom data.","designerTakeaways":["You can display role chips on every NFT card — Manager until Mar 12, not raw role id 3.","Your assign flow can pick role type, recipient, and expiry in one guided sheet.","You can disable owner-only actions for role holders with clear This requires owner copy."],"applicability":{"whenToUse":["NFTs represent assets with delegated permissions.","Multiple parties interact with same token differently.","Roles have expiry or custom metadata worth showing."],"whenToAvoid":["Simple ERC-721 with owner-only actions.","Only user/owner dual roles — ERC-4907 suffices.","Role count would overwhelm UI without truncation strategy."]},"prototypeFirst":[{"screen":"NFT detail role roster","why":"Everyone opens detail to see who holds which role.","covers":["Multiple roles","Expired role","Empty"],"include":["Role chips","Holder address","Expiry per role","Assign role CTA"]},{"screen":"Assign role sheet","why":"Owners delegate without transferring NFT.","covers":["Pick role","Set expiry","Confirm"],"include":["Role picker","Recipient field","Expiry date","Permission summary"]},{"screen":"Role holder view","why":"Delegates see what they can do.","covers":["Active role","Expired","Revoked"],"include":["You are Manager banner","Allowed actions list","Expiry countdown"]},{"screen":"Role marketplace listing","why":"Some products grant roles without selling NFT.","covers":["Grant role listing","Purchase role"],"include":["Role type","Duration","Price","NFT reference"]}],"mentalModel":[{"label":"Owner","description":"Ultimate control — can assign and revoke roles."},{"label":"Role assignment","description":"Permission bundle granted to another address for a period."},{"label":"Role expiry","description":"Automatic revocation — UI must countdown and update without user tx."},{"label":"Custom role data","description":"Extra fields per role — show human summary, not raw bytes."},{"label":"Action gating","description":"Buttons enable based on caller role, not just ownership."}],"statesToDesign":[{"state":"Owner — full control","trigger":"Viewer is token owner.","userNeed":"Assign, revoke, transfer.","designResponse":"All actions enabled; role management section visible."},{"state":"Active role holder","trigger":"Viewer holds non-owner role.","userNeed":"Know permitted actions and expiry.","designResponse":"Role banner with allowed actions; owner actions hidden."},{"state":"Role expiring soon","trigger":"Expiry within warning window.","userNeed":"Renew or finish tasks.","designResponse":"Amber countdown on role chip and notification."},{"state":"Expired role","trigger":"Past expiry block.","userNeed":"Understand permissions ended.","designResponse":"Expired badge; disabled former actions with explanation."},{"state":"Revoked by owner","trigger":"Owner revoked role early.","userNeed":"Not assume access remains.","designResponse":"Access ended notice; remove role from active roster."}],"designDecisions":[{"question":"How many roles to show on thumbnail?","recommendation":"Max two chips plus +N more on card.","rationale":"Dense role lists clutter grids."},{"question":"Friendly names vs role ids?","recommendation":"Map ids to names from contract metadata or app config.","rationale":"Role id 4 means nothing to users."},{"question":"Notify on expiry?","recommendation":"Push or email before expiry for high-value roles.","rationale":"Silent expiry causes failed critical actions."}],"problemsSolved":[{"problem":"Only owner can act on NFT","oldWay":"Transfer NFT to delegate temporarily","newWay":"Grant Manager role while retaining ownership","impact":"high"},{"problem":"Unclear who can use an asset","oldWay":"Try action and revert","newWay":"Role roster visible before interaction","impact":"high"},{"problem":"Forgotten delegations","oldWay":"Roles linger without visibility","newWay":"Expiry countdowns and revoke controls","impact":"medium"}],"uxPatterns":[{"name":"Role Roster Panel","description":"List roles, holders, and expiry on NFT detail.","mockup":"concept/nft-gallery","components":["RoleChip","HolderRow","ExpiryTimer","AssignButton"],"userFlow":["Open NFT","See roles","Assign or revoke","Roster updates"]},{"name":"Role-Gated Actions","description":"Enable buttons based on viewer role.","mockup":"concept/permit-approval","components":["ActionButton","RoleGate","OwnerOnlyTooltip"],"userFlow":["User views NFT","UI checks role","Permitted actions enabled","Blocked show reason"]}],"seenInTheWild":[{"app":"ReNFT","url":"https://renft.io/","note":"Rental and delegation patterns inform role assignment UX."},{"app":"OpenSea","url":"https://opensea.io/","note":"Ownership display extends to delegated permission models."},{"app":"Decentraland","url":"https://decentraland.org/","note":"Land manager roles parallel custom NFT roles."}],"antiPatterns":[{"pattern":"Showing only owner with no role list","why":"Delegates discover limits at revert","instead":"Role roster on every detail page","severity":"high"},{"pattern":"Displaying raw role id integers","why":"Meaningless to users","instead":"Friendly role names from metadata","severity":"medium"},{"pattern":"No expiry warning","why":"Silent permission loss mid-task","instead":"Countdown and notification before expiry","severity":"high"}],"vocabulary":[{"use":"Manager until [date]","avoid":"Role 0x3 assigned","why":"Human role labels with expiry."},{"use":"Assign access","avoid":"Grant role bitmap","why":"Permission language over encoding."},{"use":"Requires owner","avoid":"onlyOwner modifier revert","why":"Plain gating explanation."}],"onMonad":[{"aspect":"Role assignment cost","ethereum":"Multiple role txs add up","monad":"Low fees encourage granular delegation","designImplication":"Offer batch assign in UI on Monad."},{"aspect":"Expiry updates","ethereum":"UI may lag after expiry block","monad":"Fast finality refreshes role state quickly","designImplication":"Auto-refresh detail page on expiry without manual reload."}],"technicalNotes":"ERC-7432 supports arbitrary roles; map ids to friendly names and always show expiry.","relatedStandards":[{"id":"ERC-4907","relationship":"Simpler user/owner dual role model"},{"id":"ERC-721","relationship":"NFT base with extended roles"}]},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-7432","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-7432","type":"discussion"},{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-7432","type":"official-spec"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-7432","markdown":"https://www.eipsfordesigners.com/standards/ERC-7432/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-7432/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-7432","official":"https://eips.ethereum.org/EIPS/erc-7432","discussion":"https://ethereum-magicians.org/search?q=ERC-7432"},"freshness":{"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25"}},{"id":"ERC-6059","name":"Parent-Governed Nestable NFTs","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 own other NFTs in parent-child hierarchies — enabling bundling, delegation, and composability. Design implications: show nested tree views of NFT hierarchies, design 'pending child' acceptance flows (propose-commit pattern), visualize bundle contents expandable within parent, indicate 'nested inside' status. Design decisions: depth limit for hierarchy display, whether dragging NFTs into others is intuitive, how to handle cross-collection nesting, showing root owner vs immediate parent.","hasDetailedContent":true,"content":{"id":"ERC-6059","summary":"ERC-6059 enables NFTs to own other NFTs in parent-child hierarchies. Your character NFT can own sword, armor, and potion NFTs inside it—transfer the character and everything it owns moves together. Perfect for gaming, bundles, and composable digital assets.","applicability":{"whenToUse":["Your product addresses: related NFTs scattered across wallet.","Your product must handle: can't transfer bundle atomically.","The flow should deliver: sword and armor nested INSIDE character NFT.","You are designing a nested nft tree view experience with visible states and recovery paths."],"whenToAvoid":["Tree view with expand/collapse for nested items.","Always expand and show ALL contents before sale.","Require explicit accept for incoming nest requests.","Assets are fungible tokens only with no unique-item semantics."]},"designerTakeaways":["You can design UI that delivers sword and armor nested INSIDE character NFT.","You can design UI that delivers transfer character = everything inside moves too.","You can design UI that delivers tree structure: Character → Equipment → Gems."],"problemsSolved":[{"problem":"Related NFTs scattered across wallet","oldWay":"Character, sword, armor all separate items in flat list","newWay":"Sword and armor nested INSIDE character NFT","impact":"critical"},{"problem":"Can't transfer bundle atomically","oldWay":"Transfer character, sword, armor in 3 separate transactions","newWay":"Transfer character = everything inside moves too","impact":"critical"},{"problem":"No visual hierarchy for collections","oldWay":"All NFTs shown at same level","newWay":"Tree structure: Character → Equipment → Gems","impact":"high"},{"problem":"Complex inventory management","oldWay":"Search entire wallet to find items for specific character","newWay":"Click character, see everything it owns","impact":"high"},{"problem":"Selling bundle requires escrow","oldWay":"Trust marketplace to hold items during multi-item sale","newWay":"Sell parent NFT, children transfer automatically","impact":"medium"}],"uxPatterns":[{"name":"Nested NFT Tree View","description":"Hierarchical display of NFTs owning NFTs","mockup":"concept/nft-gallery","userFlow":["User opens inventory","Sees top-level NFTs","Expands to see children","Children can have their own children","Total value includes all nested items"]},{"name":"Add Child to NFT","description":"Nest one NFT inside another","mockup":"concept/nft-gallery","userFlow":["User selects parent NFT","Views available items to nest","Selects items to add","Confirms ownership transfer to NFT","Items now inside parent NFT"]},{"name":"Remove from Parent","description":"Extract nested NFT back to wallet","mockup":"concept/nft-gallery","userFlow":["User opens parent NFT inventory","Selects items to remove","Chooses destination (wallet or another NFT)","Sees warning about nested children","Confirms removal"]},{"name":"Bundle Sale","description":"Sell parent with all children","mockup":"concept/bundled-defi","userFlow":["User selects NFT to sell","System shows all nested contents","Displays floor prices for each item","Suggests bundle pricing","User sets price and lists","Buyer gets everything atomically"]},{"name":"Pending Child Request","description":"Accept or reject NFT being nested","mockup":"concept/nft-gallery","userFlow":["Someone sends NFT to be nested","Parent owner sees pending request","Reviews the item and sender","Accepts legitimate items","Rejects spam or unwanted items"]}],"uiComponents":[{"name":"NFTTreeView","description":"Expandable tree showing nested NFT hierarchy","states":["collapsed","expanded","loading","empty"],"props":["rootNFT","depth","onExpand","onSelect"]},{"name":"NestingModal","description":"Dialog for adding NFT as child","states":["selecting","confirming","nesting","complete"],"props":["parentNFT","availableChildren[]","onNest"]},{"name":"BundleValueCalculator","description":"Shows total value of NFT including nested","states":["calculating","ready","no-price-data"],"props":["parentNFT","children[]","showBreakdown"]},{"name":"PendingNestRequest","description":"Card for approving/rejecting nest requests","states":["pending","accepted","rejected"],"props":["childNFT","parentNFT","sender","onAccept","onReject"]},{"name":"NestedBreadcrumb","description":"Shows path: Wizard > Backpack > Potion","states":["shallow","deep"],"props":["path[]","onNavigate"]}],"antiPatterns":[{"pattern":"Flat list hiding nested structure","why":"User can't see what's inside their NFTs","instead":"Tree view with expand/collapse for nested items","severity":"critical"},{"pattern":"Not showing nested items when selling","why":"Buyer doesn't know what they're getting","instead":"Always expand and show ALL contents before sale","severity":"critical"},{"pattern":"Auto-accepting nested children","why":"NFT gets filled with spam","instead":"Require explicit accept for incoming nest requests","severity":"high"},{"pattern":"Hiding nested item value","why":"User undersells valuable bundle","instead":"Calculate and display total nested value","severity":"high"},{"pattern":"No way to see deep nesting","why":"Items buried 3+ levels deep become lost","instead":"Breadcrumb navigation and full expand option","severity":"medium"},{"pattern":"Transfer child without warning","why":"User moves item and loses track of it","instead":"Confirm with \"This will move INTO [NFT name]\"","severity":"medium"}],"onMonad":[{"aspect":"Nesting Transactions","ethereum":"Each nest/unnest costs gas","monad":"Cheap nesting enables frequent inventory changes","designImplication":"Players can reorganize inventory freely"},{"aspect":"Deep Nesting","ethereum":"Fetching deep trees is slow and expensive","monad":"Fast parallel queries for entire hierarchy","designImplication":"Can show full tree instantly, not lazy-load"},{"aspect":"Bundle Transfers","ethereum":"Large bundles still one transaction","monad":"Sub-second transfer of entire inventory","designImplication":"Trading full characters feels instant"},{"aspect":"Real-time Updates","ethereum":"Nesting confirmation takes time","monad":"Inventory updates in under a second","designImplication":"Game UIs can update immediately after action"}],"keyTakeaways":["ERC-6059 = NFTs that own other NFTs","Transfer parent = transfer all children","Always show nested structure, not flat list","Calculate bundle value including all nested items","Require accept for incoming nest requests"],"technicalNotes":"ERC-6059 adds childOf() and parentOf() tracking. Children can be added via nestTransfer() which requires parent owner approval. Pending children exist in limbo until accepted. ownerOf() returns immediate parent, while rootOwner() traverses up to the wallet. Events: ChildProposed, ChildAccepted, ChildTransferred."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-6059","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-6059","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-6059","markdown":"https://www.eipsfordesigners.com/standards/ERC-6059/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-6059/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-6059","official":"https://eips.ethereum.org/EIPS/eip-6059","discussion":"https://ethereum-magicians.org/search?q=ERC-6059"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"ERC-7401","name":"Parent-Governed NFT Nesting","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":"Improved NFT nesting standard (supersedes ERC-6059) — NFTs own NFTs with parent-governed control. Design implications: same as ERC-6059 plus cleaner interfaces — tree visualizations, child acceptance flows, bundle management, transfer-with-children behavior. Design decisions: whether to show full ancestry path, how to indicate pending vs accepted children, UX for transferring parent (children follow automatically), visual hierarchy depth limits.","hasDetailedContent":true,"content":{"id":"ERC-7401","sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-7401","type":"official-spec"}],"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25","summary":"Improved NFT nesting standard (supersedes ERC-6059) — NFTs own NFTs with parent-governed control.","designerTakeaways":["You can render expandable tree views showing parent NFTs and their nested children.","Your inbox can surface pending child proposals with Accept or Decline before they nest.","You can warn Transfer includes 3 nested items on every parent send confirmation."],"applicability":{"whenToUse":["NFTs bundle other NFTs as packs or containers.","Parent-governed control over nested inventory matters.","You implement ERC-7401 superseding ERC-6059."],"whenToAvoid":["Flat ERC-721 collections with no nesting.","Users never compose or unpack bundles.","Indexer lacks nested ownership graph support."]},"prototypeFirst":[{"screen":"Nested tree inventory","why":"Collectors browse bundles as filesystem-like trees.","covers":["Expanded parent","Collapsed children","Deep nest"],"include":["Tree expand/collapse","Child count badge","Nested inside label"]},{"screen":"Pending child acceptance","why":"Proposed children need explicit accept.","covers":["Pending","Accepted","Declined"],"include":["Parent preview","Child preview","Accept/Decline CTAs"]},{"screen":"Bundle transfer confirmation","why":"Sending parent must list all children moving.","covers":["Single child","Many children"],"include":["Child list in confirm modal","Total items count","Irreversible note"]},{"screen":"Unnest or extract child","why":"Owners remove children from parent when allowed.","covers":["Allowed unnest","Blocked by parent rules"],"include":["Extract action","Parent permission check","Result state"]}],"mentalModel":[{"label":"Parent NFT","description":"Container token that governs nested children."},{"label":"Child NFT","description":"Token nested under parent — may show Nested inside status."},{"label":"Propose-commit","description":"Child transfer proposed first; recipient accepts to complete nest."},{"label":"Bundle transfer","description":"Moving parent drags all accepted children with it."},{"label":"Root owner","description":"Who ultimately controls the top-level parent in a deep tree."}],"statesToDesign":[{"state":"Pending child proposal","trigger":"Someone proposed nesting a child.","userNeed":"Review before accepting into bundle.","designResponse":"Inbox item with Accept/Decline and parent context."},{"state":"Nested — child inside parent","trigger":"Child accepted.","userNeed":"Find child within parent tree.","designResponse":"Nested inside badge; child hidden from flat grid or indented."},{"state":"Parent transfer with children","trigger":"Owner sends parent.","userNeed":"Know entire bundle moves.","designResponse":"Confirmation lists all child previews."},{"state":"Empty parent container","trigger":"Parent has no children.","userNeed":"Still use as container.","designResponse":"Empty slot UI with Add child action if supported."},{"state":"Deep hierarchy limit","trigger":"Tree exceeds display depth.","userNeed":"Navigate without overwhelm.","designResponse":"Truncate with View full tree link."}],"designDecisions":[{"question":"Flat grid vs tree default?","recommendation":"Tree for nest-heavy collections; flat with Nested filter for mixed.","rationale":"Flat grids hide nested assets entirely."},{"question":"Show full ancestry path?","recommendation":"Breadcrumb on child detail: Root › Pack › Item.","rationale":"Deep nests need orientation."},{"question":"Drag-drop nesting?","recommendation":"Optional power feature; always confirm with propose-commit.","rationale":"Accidental drags nest wrong items."}],"problemsSolved":[{"problem":"NFT bundles invisible in wallet","oldWay":"Only top-level tokens shown","newWay":"Tree view exposes nested children","impact":"high"},{"problem":"Surprise bundle transfers","oldWay":"Parent send moves unknown children","newWay":"Confirmation lists all nested items","impact":"critical"},{"problem":"Unwanted nested gifts","oldWay":"Children land without consent","newWay":"Accept/Decline propose-commit inbox","impact":"high"}],"uxPatterns":[{"name":"NFT Tree Navigator","description":"Expandable hierarchy for parent-child tokens.","mockup":"concept/nft-gallery","components":["TreeView","NestBadge","ChildCount"],"userFlow":["Open collection","Expand parent","See children","Open child detail"]},{"name":"Bundle Transfer Preview","description":"List all children in parent send confirm.","mockup":"concept/verify-safety","components":["ChildList","BundleCount","ConfirmModal"],"userFlow":["User sends parent","Modal lists children","User confirms","Bundle moves"]}],"seenInTheWild":[{"app":"Nested NFT demos","url":"https://eips.ethereum.org/EIPS/eip-7401","note":"Spec examples inform tree visualization patterns."},{"app":"OpenSea","url":"https://opensea.io/","note":"Bundle display patterns for grouped listings."},{"app":"Rarible","url":"https://rarible.com/","note":"Collection hierarchy UX reference."}],"antiPatterns":[{"pattern":"Flat wallet hiding nested children","why":"Users think children disappeared","instead":"Tree view or Nested inside filter","severity":"critical"},{"pattern":"Parent transfer without child list","why":"Accidental loss of valuable nested items","instead":"Bundle preview on every parent send","severity":"critical"},{"pattern":"Auto-accept nested proposals","why":"Spam nesting attacks inventory","instead":"Explicit Accept/Decline inbox","severity":"high"}],"vocabulary":[{"use":"Inside this bundle","avoid":"Child token nested under parentId","why":"Bundle metaphor over graph terms."},{"use":"Accept into bundle","avoid":"Commit child nest","why":"Inbox action language."},{"use":"Moves with parent","avoid":"Inherits nesting on transfer","why":"Plain transfer consequence."}],"onMonad":[{"aspect":"Nest operations","ethereum":"Multi-step nest txs costly","monad":"Lower fees enable interactive tree management","designImplication":"Allow drag-drop nest experiments on Monad."},{"aspect":"Tree indexing","ethereum":"Deep graphs slow to load","monad":"Fast RPC enables snappy tree expand","designImplication":"Prefetch children on parent hover."}],"technicalNotes":"ERC-7401 supersedes ERC-6059; always preview children on parent transfer.","relatedStandards":[{"id":"ERC-6059","relationship":"Prior nesting standard superseded by 7401"},{"id":"ERC-721","relationship":"Base NFT with nesting extension"}]},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-7401","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-7401","type":"discussion"},{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-7401","type":"official-spec"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-7401","markdown":"https://www.eipsfordesigners.com/standards/ERC-7401/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-7401/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-7401","official":"https://eips.ethereum.org/EIPS/erc-7401","discussion":"https://ethereum-magicians.org/search?q=ERC-7401"},"freshness":{"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25"}},{"id":"ERC-6220","name":"Composable NFTs with Equippable Parts","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 equip other NFTs into defined slots using a Catalog system — true on-chain composability. Design implications: show equippable slots on NFTs (e.g., 'Weapon Slot: Empty'), design drag-drop equip interfaces, display composed NFT preview combining base + equipped assets, catalog browsing for compatible equipment. Design decisions: real-time vs on-save composition rendering, how to show slot compatibility constraints, inventory vs equipped views, handling unequip gas costs.","hasDetailedContent":true,"content":{"id":"ERC-6220","summary":"ERC-6220 enables NFTs with slots where other NFTs can be equipped. Think of an avatar with a \"weapon slot\" where you can equip different sword NFTs, each changing the visual appearance. Parts can be fixed (built into the base) or equippable (swappable NFTs). When equipped, child NFTs visually compose with the parent, creating dynamic, customizable digital assets.","applicability":{"whenToUse":["Your product addresses: nFTs are static, can't customize appearance.","Your product addresses: gaming items can't attach to characters.","The flow should deliver: equip different items to change appearance dynamically.","You are designing a equipment slot interface experience with visible states and recovery paths."],"whenToAvoid":["Show compatibility before purchase, filter by what user owns.","Always show preview of composed appearance before confirming.","Clear \"Equipped to X\" label on items, confirm before listing.","Assets are fungible tokens only with no unique-item semantics."]},"designerTakeaways":["You can design UI that delivers equip different items to change appearance dynamically.","You can design UI that delivers equip sword to character.","You can standard slots and equip interface across all platforms."],"problemsSolved":[{"problem":"NFTs are static, can't customize appearance","oldWay":"Buy different NFT for each look, no customization","newWay":"Equip different items to change appearance dynamically","impact":"critical"},{"problem":"Gaming items can't attach to characters","oldWay":"Character NFT shows default look, inventory separate","newWay":"Equip sword to character, sword appears on character image","impact":"critical"},{"problem":"Wearables have no standard equipment system","oldWay":"Each game invents custom equip mechanics","newWay":"Standard slots and equip interface across all platforms","impact":"high"},{"problem":"Can't prove what's equipped to an NFT","oldWay":"Off-chain metadata claims equipment, not verifiable","newWay":"Equipment is on-chain, queryable by anyone","impact":"medium"}],"uxPatterns":[{"name":"Equipment Slot Interface","description":"Visual slots showing equipped items","mockup":"concept/nft-gallery","userFlow":["User views character NFT","See slots for different body parts","Some slots filled, some empty","Tap empty slot to see compatible items","Tap filled slot to unequip or swap","Changes reflect in character appearance"]},{"name":"Equip Item Flow","description":"Drag-and-drop or select to equip","mockup":"generic/list-selector","userFlow":["User taps empty or filled slot","See compatible items from inventory","Browse and select item","Preview how it looks equipped","Confirm equip","On-chain state updated"]},{"name":"Composed View","description":"Show NFT with all equipment rendered","mockup":"concept/nft-gallery","userFlow":["View NFT on marketplace or gallery","See composed image with all equipment","Equipment list shows what's attached","Click items to see individual NFT details","Owner can edit equipment","Image updates when equipment changes"]},{"name":"Slot Compatibility Guide","description":"Help users understand what fits where","mockup":"concept/nft-gallery","userFlow":["User wants to know what they can equip","View slot compatibility guide","See each slot and what it accepts","See which collections are compatible","Browse to find equipment to buy","Purchase compatible items"]}],"uiComponents":[{"name":"EquipmentSlotGrid","description":"Visual grid of equipment slots","states":["viewing","editing","equipping"],"props":["slots","equipped","onSlotClick"]},{"name":"EquipModal","description":"Select and preview equipment","states":["browsing","previewing","confirming","equipping"],"props":["slot","compatibleItems","onEquip","onCancel"]},{"name":"ComposedNFTView","description":"Renders base + all equipment as one image","states":["loading","rendered","error"],"props":["baseNFT","equipment","renderMode"]},{"name":"CompatibilityChecker","description":"Shows if item fits slot","states":["compatible","incompatible","checking"],"props":["item","slot","baseNFT"]}],"antiPatterns":[{"pattern":"Not previewing equipment before equipping","why":"User equips, doesn't like look, has to unequip (costs gas)","instead":"Always show preview of composed appearance before confirming","severity":"high"},{"pattern":"Unclear slot compatibility","why":"User buys item, discovers it doesn't fit their NFT","instead":"Show compatibility before purchase, filter by what user owns","severity":"critical"},{"pattern":"No indication of equipped vs unequipped items","why":"User sells item, didn't realize it was equipped to their character","instead":"Clear \"Equipped to X\" label on items, confirm before listing","severity":"high"},{"pattern":"Hiding that equipment is on-chain","why":"Users don't realize equipping costs gas","instead":"Show \"Equipping requires transaction\" before action","severity":"medium"},{"pattern":"Not showing composed image on marketplaces","why":"Buyer sees only base NFT, misses equipped value","instead":"Always show composed view with option to see base","severity":"medium"}],"onMonad":[{"aspect":"Equip/Unequip Speed","ethereum":"Each equip action takes 15+ seconds","monad":"Sub-second equipment changes","designImplication":"Can rapidly try different combinations"},{"aspect":"Gas Costs","ethereum":"Changing equipment costs $5-20 per action","monad":"Negligible costs for all equipment changes","designImplication":"Encourage experimentation, frequent changes"},{"aspect":"Batch Equipment","ethereum":"Equipping full loadout = many slow transactions","monad":"Equip all slots in one fast transaction","designImplication":"Can have \"Apply Loadout\" for preset combinations"},{"aspect":"Real-time Preview","ethereum":"Checking equipment state is slow","monad":"Instant equipment state queries","designImplication":"Live updating character preview as you browse"}],"keyTakeaways":["ERC-6220 = NFTs with slots for equipping other NFTs","Equipped items change the visual appearance","Always preview composed look before equipping","Show compatibility clearly before item purchase","On Monad: rapid equipment experimentation is cheap"],"technicalNotes":"ERC-6220 defines slots as (slotId, partType, z-index, assetCatalog). Assets can be fixed (built-in) or equippable (swappable NFTs). equip(tokenId, slotId, childId) attaches child NFT to slot. The standard includes asset catalogs that define which collections are compatible with which slots. Rendering combines base + all equipped parts by z-index."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-6220","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-6220","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-6220","markdown":"https://www.eipsfordesigners.com/standards/ERC-6220/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-6220/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-6220","official":"https://eips.ethereum.org/EIPS/eip-6220","discussion":"https://ethereum-magicians.org/search?q=ERC-6220"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"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. Design implications: show clear 'Non-Transferable' or 'Soulbound' badges, hide/disable transfer buttons for locked tokens, differentiate mintable vs burnable vs transferable states, display restriction reason if available. Design decisions: whether to show transfer button at all for soulbound tokens, how to explain why transfer fails, visual treatment of soulbound vs tradeable tokens in same wallet.","hasDetailedContent":true,"content":{"id":"ERC-6454","sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-6454","type":"official-spec"}],"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25","summary":"Tokens can be non-transferable (soulbound) or have transfer restrictions — verifiable on-chain.","designerTakeaways":["You can query transferability on load and badge Non-transferable on every restricted token.","Your marketplace can hide List button entirely for soulbound items instead of disabled gray buttons.","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 soulbound","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 soulbound.","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","Issued by","Earned date"]}],"mentalModel":[{"label":"Transferable","description":"Normal NFT — can send and sell subject to other rules."},{"label":"Non-transferable","description":"Soulbound — ownership may change via mint/burn only, not user send."},{"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":"Transferable — normal","trigger":"isTransferable true.","userNeed":"Send and sell freely.","designResponse":"Standard transfer and list actions."},{"state":"Non-transferable — soulbound","trigger":"isTransferable false.","userNeed":"Understand cannot sell or send.","designResponse":"Persistent badge; hide transfer CTAs."},{"state":"Transfer attempted on soulbound","trigger":"User finds send via deep link.","userNeed":"Clear block before wallet.","designResponse":"Modal before wallet; 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 non-transferable","impact":"high"}],"uxPatterns":[{"name":"Soulbound Badge","description":"Non-transferable chip on token card and detail.","mockup":"concept/nft-gallery","components":["SoulboundChip","LockIcon","ReasonTooltip"],"userFlow":["Load token","Query 6454","Show badge if locked","Hide send"]},{"name":"Transfer Gate","description":"Block send flow before wallet for restricted tokens.","mockup":"concept/verify-safety","components":["TransferCheck","BlockModal","ReasonCopy"],"userFlow":["User taps Send","Check fails","Modal explains","No wallet prompt"]}],"seenInTheWild":[{"app":"POAP","url":"https://poap.xyz/","note":"Soulbound attendance badges — non-transferable by design."},{"app":"Gitcoin Passport","url":"https://passport.gitcoin.co/","note":"Credential stamps use soulbound patterns."},{"app":"OpenSea","url":"https://opensea.io/","note":"Transfer restrictions surfaced on collection pages."}],"antiPatterns":[{"pattern":"Enabled Send on soulbound token","why":"Wasted gas and rage","instead":"Pre-check ERC-6454 and hide Send","severity":"critical"},{"pattern":"Generic Transfer failed after sign","why":"User paid gas for predictable revert","instead":"Block in app with soulbound 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."}],"onMonad":[{"aspect":"Pre-check cost","ethereum":"Extra read call may feel heavy on slow networks","monad":"Fast reads make transferability check on every card cheap","designImplication":"Query 6454 on all NFT loads on Monad."},{"aspect":"Soulbound mint volume","ethereum":"Event drops congested","monad":"High throughput for mass credential mints","designImplication":"Design batch mint status for large SBT drops."}],"technicalNotes":"ERC-6454 minimal transfer detection; call before any Send or List UI renders.","relatedStandards":[{"id":"ERC-5192","relationship":"Minimal soulbound NFT standard"},{"id":"ERC-5484","relationship":"Consensual soulbound minting"}]},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-6454","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-6454","type":"discussion"},{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-6454","type":"official-spec"}],"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://eips.ethereum.org/EIPS/erc-6454","discussion":"https://ethereum-magicians.org/search?q=ERC-6454"},"freshness":{"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25"}},{"id":"ERC-7858","name":"Expirable NFTs and SBTs","status":"Draft","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 and SBTs have built-in expiration (block-based or time-based) — tokens become invalid automatically. Design implications: show expiration countdown prominently, display 'Expired' badge on invalid tokens, filter views by active/expired status, indicate expiry type (blocks vs timestamp). Design decisions: whether expired tokens remain visible or get hidden, renewal flow if supported, how to communicate 'expired but still owned' status, handling epoch-based batch expiration.","hasDetailedContent":true,"content":{"id":"ERC-7858","sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-7858","type":"official-spec"}],"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25","summary":"NFTs and SBTs have built-in expiration (block-based or time-based) — tokens become invalid automatically.","designerTakeaways":["You can show Expires in 14 days prominently on every expiring token card.","Your filters can split Active and Expired without hiding expired items by surprise.","You can block utility actions on expired tokens with Renew to continue CTA if supported."],"applicability":{"whenToUse":["Passes, licenses, subscriptions, or seasonal badges expire.","Validity is enforced on-chain by time or block.","Renewal or re-mint extends expiry."],"whenToAvoid":["Permanent collectibles with no expiry concept.","Draft spec not deployed on target chain.","Expiry handled off-chain only."]},"prototypeFirst":[{"screen":"Expiring pass detail","why":"Holder checks validity before showing up at event.","covers":["Active countdown","Expires today","Expired"],"include":["Large expiry date","Countdown","Expired overlay"]},{"screen":"Active vs expired filter","why":"Wallets fill with old passes over time.","covers":["Filter active","Show expired archive"],"include":["Tab toggle","Expired gray treatment","Count badges"]},{"screen":"Renewal flow","why":"Extend expiry without losing identity of token if supported.","covers":["Renew available","Renew completed"],"include":["Renew CTA","New expiry preview","Payment step"]},{"screen":"Batch epoch expiry","why":"Many tokens expire together — communicate scale.","covers":["Epoch warning","Post-epoch expired set"],"include":["Batch expiry notice","Affected count","Bulk renew if offered"]}],"mentalModel":[{"label":"Expiry timestamp","description":"On-chain moment after which token is invalid for utility."},{"label":"Active vs expired","description":"Binary validity state — UI must reflect on every load."},{"label":"Still owned but expired","description":"User keeps NFT in wallet; it just no longer works."},{"label":"Renewal","description":"Optional path to extend expiry without new mint."},{"label":"Epoch batch","description":"Group expiry — many tokens die together at season end."}],"statesToDesign":[{"state":"Active — far from expiry","trigger":"Valid with long runway.","userNeed":"Glance validity.","designResponse":"Subtle Expires [date] on card."},{"state":"Expiring soon","trigger":"Within warning window.","userNeed":"Renew or use before deadline.","designResponse":"Amber countdown and notification."},{"state":"Expired — still in wallet","trigger":"Past expiry.","userNeed":"Know unusable; optional archive.","designResponse":"Expired badge; utility actions disabled."},{"state":"Renewal in progress","trigger":"User extending expiry.","userNeed":"Track new date.","designResponse":"Pending renewal with new expiry preview."},{"state":"Epoch batch expired","trigger":"Season ended.","userNeed":"Understand all related tokens expired.","designResponse":"Banner on collection: Season ended; passes expired."}],"designDecisions":[{"question":"Hide expired tokens?","recommendation":"Default Active filter; Expired tab for archive.","rationale":"Hiding surprises users who expect history."},{"question":"How alarming is expiry UI?","recommendation":"Amber at 30 days; red only day-of and after.","rationale":"Constant red creates alert fatigue."},{"question":"Show block-based expiry to users?","recommendation":"Convert to approximate time with Block-based note in advanced.","rationale":"Block numbers are meaningless to most users."}],"problemsSolved":[{"problem":"Expired passes still look valid","oldWay":"Same artwork with no date","newWay":"Expired badge and disabled utility","impact":"high"},{"problem":"Missed renewals","oldWay":"No countdown on subscription NFTs","newWay":"Prominent expiry and notifications","impact":"high"},{"problem":"Wallet clutter from dead tokens","oldWay":"All tokens mixed together","newWay":"Active/Expired filters","impact":"medium"}],"uxPatterns":[{"name":"Expiry Countdown Chip","description":"Prominent deadline on expiring tokens.","mockup":"concept/nft-gallery","components":["ExpiryChip","CountdownTimer","ExpiredOverlay"],"userFlow":["Load token","Read expiry","Show countdown","Switch to Expired after date"]},{"name":"Active Expired Filter","description":"Split wallet views by validity.","mockup":"concept/verify-safety","components":["FilterTabs","ExpiredArchive","RenewCTA"],"userFlow":["Open wallet","Default Active","Switch to Expired","Optional renew"]}],"seenInTheWild":[{"app":"POAP","url":"https://poap.xyz/","note":"Event badges with implicit time bounds inform expiry UX."},{"app":"Unlock Protocol","url":"https://unlock-protocol.com/","note":"Time-bound membership NFTs with renewal patterns."},{"app":"Guild","url":"https://guild.xyz/","note":"Role passes with expiration inform countdown design."}],"antiPatterns":[{"pattern":"No expiry visible on pass NFT","why":"Users denied entry at door","instead":"Expiry date on thumbnail and detail header","severity":"critical"},{"pattern":"Deleting expired tokens from wallet UI","why":"Users lose proof they held pass","instead":"Expired archive tab","severity":"medium"},{"pattern":"Showing block number as expiry","why":"Meaningless to users","instead":"Human datetime with advanced block note","severity":"high"}],"vocabulary":[{"use":"Valid until [date]","avoid":"Expiry block 18293482","why":"Human deadlines."},{"use":"Expired","avoid":"Validity epoch ended","why":"Plain status."},{"use":"Renew pass","avoid":"Extend expiration timestamp","why":"Subscription-familiar action."}],"onMonad":[{"aspect":"Expiry precision","ethereum":"Block time variance affects countdown","monad":"Consistent block times improve countdown accuracy","designImplication":"Show tighter countdown windows on Monad."},{"aspect":"Renewal txs","ethereum":"Users skip renew due to gas","monad":"Low fees encourage proactive renewal","designImplication":"One-tap renew without gas warning modal."}],"technicalNotes":"ERC-7858 is draft; re-read expiry on every view — do not cache past validity.","relatedStandards":[{"id":"ERC-5192","relationship":"Soulbound tokens often expire"},{"id":"ERC-4907","relationship":"Rental expiry separate from token expiry"}]},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-7858","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-7858","type":"discussion"},{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-7858","type":"official-spec"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-7858","markdown":"https://www.eipsfordesigners.com/standards/ERC-7858/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-7858/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-7858","official":"https://eips.ethereum.org/EIPS/erc-7858","discussion":"https://ethereum-magicians.org/search?q=ERC-7858"},"freshness":{"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25"}},{"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 owner's wallet — usable but non-transferable until unlocked. Design implications: show 'Locked' status badge with locker address, enable lock/unlock flows with locker assignment, indicate locked tokens differently from transferable ones, show who can unlock. Design decisions: how to explain lock vs soulbound difference, whether locked tokens appear in marketplace listings, transferAndLock flow complexity, safety messaging about cold wallet as unlocker.","hasDetailedContent":true,"content":{"id":"ERC-7066","sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-7066","type":"official-spec"}],"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25","summary":"NFTs can be locked in owner's wallet — usable but non-transferable until unlocked.","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 require usable but non-transferable state.","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","Usable but not transferable note"]},{"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","Use in app still enabled"]},{"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":"Token cannot transfer; may still work in approved apps."},{"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 blocks transfer while app use continues","impact":"critical"},{"problem":"Cold storage removes utility","oldWay":"Move to vault, cannot use in game","newWay":"Locked but usable in connected apps","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.","mockup":"concept/nft-gallery","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.","mockup":"concept/verify-safety","components":["LockedChip","UnlockCTA","LockerLabel"],"userFlow":["View locked NFT","See locker","Unlock when ready","Transfer enabled"]}],"seenInTheWild":[{"app":"ERC-6147 Guard","url":"https://eips.ethereum.org/EIPS/eip-6147","note":"Related guard patterns for transfer restriction UX."},{"app":"OpenSea","url":"https://opensea.io/","note":"Listing restriction patterns for non-transferable states."},{"app":"MetaMask","url":"https://metamask.io/","note":"Wallet security flows inform locker assignment copy."}],"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":"Cannot list while locked — Unlock first","severity":"high"},{"pattern":"Conflating lock with soulbound","why":"Wrong recovery expectations","instead":"Distinct Locked vs Non-transferable badges","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":"Still usable here","avoid":"Lock does not affect utility hook","why":"Reassurance for gamers."}],"onMonad":[{"aspect":"Lock/unlock cost","ethereum":"Users hesitate to lock due to gas","monad":"Cheap lock/unlock enables proactive protection","designImplication":"Promote lock after high-value mint on Monad."},{"aspect":"Game integration","ethereum":"Locked state sync lag","monad":"Fast finality keeps game and wallet lock state aligned","designImplication":"Refresh lock status after every game session."}],"technicalNotes":"ERC-7066 lock differs from soulbound — always show locker and unlock path.","relatedStandards":[{"id":"ERC-6147","relationship":"Guard-based transfer restriction alternative"},{"id":"ERC-6454","relationship":"Transfer detection when locked"}]},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-7066","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-7066","type":"discussion"},{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-7066","type":"official-spec"}],"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://eips.ethereum.org/EIPS/erc-7066","discussion":"https://ethereum-magicians.org/search?q=ERC-7066"},"freshness":{"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25"}},{"id":"EIP-7634","name":"Limited Transfer Count NFT","status":"Draft","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 have maximum transfer count — after N transfers, token becomes non-transferable or burns. Design implications: show 'Transfers Remaining: 3/5' counter prominently, warn before final transfer, indicate transfer-exhausted tokens, display transfer history count. Design decisions: whether to show transfer limit upfront during purchase, how alarming the 'last transfer' warning should be, treatment of exhausted tokens (greyed vs hidden vs special badge).","hasDetailedContent":true,"content":{"id":"EIP-7634","sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-7634","type":"official-spec"}],"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25","summary":"NFTs have maximum transfer count — after N transfers, token becomes non-transferable or burns.","designerTakeaways":["You can show Transfers remaining: 2 of 5 on listing and detail before purchase.","Your send confirmation can warn This is the last transfer when one remains.","You can badge Transfer exhausted on tokens that can never move again."],"applicability":{"whenToUse":["Collectibles intentionally scarce in secondary circulation.","Artist policy limits flips.","Draft EIP deployed with transfer cap."],"whenToAvoid":["Standard freely tradable NFTs.","Cap not enforced on-chain.","Users expect infinite liquidity."]},"prototypeFirst":[{"screen":"Listing with transfer counter","why":"Secondary buyers price scarcity of remaining transfers.","covers":["5 of 5","1 remaining","Exhausted"],"include":["Counter chip","Tooltip explaining cap","Price context"]},{"screen":"Last transfer warning","why":"Final move needs explicit consent.","covers":["Last transfer confirm"],"include":["Scary warning modal","After this cannot transfer","Confirm checkbox"]},{"screen":"Exhausted token view","why":"Permanent hold state needs distinct treatment.","covers":["Transfer exhausted"],"include":["Exhausted badge","Transfer history count","No Send button"]},{"screen":"Primary mint disclosure","why":"First buyers accept transfer policy.","covers":["Policy at mint"],"include":["Max transfers stated","Acknowledge checkbox"]}],"mentalModel":[{"label":"Transfer budget","description":"Finite number of allowed moves — like lives in a game."},{"label":"Decrement on transfer","description":"Each successful send reduces remaining count."},{"label":"Exhausted state","description":"Zero remaining — token locked or burned per rules."},{"label":"Primary vs secondary","description":"Mint may start count at max; secondary sees what's left."},{"label":"Burn on exhaust","description":"Some implementations destroy token — must disclose upfront."}],"statesToDesign":[{"state":"Full transfer budget","trigger":"New mint, all transfers available.","userNeed":"Know policy exists.","designResponse":"Up to N transfers badge on detail."},{"state":"Low remaining","trigger":"1-2 transfers left.","userNeed":"Factor into sell/buy decision.","designResponse":"Amber counter on card and listing."},{"state":"Last transfer confirmation","trigger":"User sends with 1 left.","userNeed":"Explicit consent.","designResponse":"Modal with irreversible warning."},{"state":"Transfer exhausted","trigger":"Zero remaining.","userNeed":"Know permanent hold.","designResponse":"Exhausted badge; Send hidden."},{"state":"Burned on exhaust","trigger":"Token burned after final transfer.","userNeed":"Extreme warning before last send.","designResponse":"This transfer will destroy token copy."}],"designDecisions":[{"question":"How alarming is last transfer?","recommendation":"Require checkbox acknowledgment in modal.","rationale":"Accidental final transfer is irreversible regret."},{"question":"Show counter on thumbnail?","recommendation":"Yes when ≤2 remain; always on detail.","rationale":"Scarcity affects price — surface early."},{"question":"Exhausted visual treatment?","recommendation":"Distinct badge, not hidden — collectors may still display.","rationale":"Proof of permanent collection piece."}],"problemsSolved":[{"problem":"Unlimited flipping undermines artist intent","oldWay":"No transfer limits","newWay":"On-chain cap enforces scarcity of movement","impact":"medium"},{"problem":"Buyers unaware of remaining liquidity","oldWay":"Discover cannot resell after buy","newWay":"Transfers remaining on listing","impact":"high"},{"problem":"Accidental final transfer","oldWay":"Send then token locks unexpectedly","newWay":"Last transfer warning modal","impact":"high"}],"uxPatterns":[{"name":"Transfer Budget Counter","description":"Remaining transfers on card and detail.","mockup":"concept/nft-gallery","components":["TransferCounter","WarningChip","PolicyTooltip"],"userFlow":["View NFT","See 2 of 5","Decide to buy","Counter updates on transfer"]},{"name":"Last Transfer Gate","description":"Confirmation when one transfer remains.","mockup":"concept/verify-safety","components":["LastTransferModal","AckCheckbox","ConfirmSend"],"userFlow":["User sends","One left detected","Modal warns","User acknowledges","Transfer proceeds"]}],"seenInTheWild":[{"app":"Art Blocks","url":"https://www.artblocks.io/","note":"Artist policy on secondary markets informs transfer limit UX."},{"app":"Foundation","url":"https://foundation.app/","note":"Creator royalties and transfer policy display patterns."},{"app":"Zora","url":"https://zora.co/","note":"Creator-centric metadata for collection rules."}],"antiPatterns":[{"pattern":"Hiding transfer cap until send fails","why":"Surprise lock destroys trust","instead":"Counter visible at purchase and send","severity":"critical"},{"pattern":"Last transfer without extra confirm","why":"Irreversible user error","instead":"Acknowledgment modal for final transfer","severity":"critical"},{"pattern":"Same UI for exhausted and soulbound","why":"Different implications confused","instead":"Transfer exhausted vs Non-transferable labels","severity":"medium"}],"vocabulary":[{"use":"2 transfers left","avoid":"Transfer count decrement remaining","why":"Game-life metaphor."},{"use":"Final transfer","avoid":"Last allowed transfer before lock","why":"Short warning label."},{"use":"Cannot move again","avoid":"Transfer budget exhausted","why":"Plain permanence language."}],"onMonad":[{"aspect":"Transfer counting","ethereum":"Counter update waits for confirmations","monad":"Instant counter refresh after send","designImplication":"Update UI immediately post-transfer on Monad."},{"aspect":"Scarce transfer drops","ethereum":"High gas discourages flips","monad":"Low fees — counter more likely to deplete","designImplication":"Emphasize counter prominently on Monad marketplaces."}],"technicalNotes":"EIP-7634 is draft; treat last transfer as irreversible consent moment.","relatedStandards":[{"id":"ERC-6454","relationship":"Transfer restriction detection"},{"id":"ERC-721","relationship":"NFT with transfer cap extension"}]},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-7634","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=EIP-7634","type":"discussion"},{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-7634","type":"official-spec"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/EIP-7634","markdown":"https://www.eipsfordesigners.com/standards/EIP-7634/content.md","agent":"https://www.eipsfordesigners.com/standards/EIP-7634/agent.md","api":"https://www.eipsfordesigners.com/api/standards/EIP-7634","official":"https://eips.ethereum.org/EIPS/eip-7634","discussion":"https://ethereum-magicians.org/search?q=EIP-7634"},"freshness":{"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25"}},{"id":"ERC-7631","name":"Dual Nature Token Pair","status":"Draft","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":"Paired ERC-20 and ERC-721 tokens that sync — buying fungible tokens auto-mints NFTs proportionally. Design implications: show linked token pairs together, indicate NFT skip status, display 'X tokens = Y NFTs' conversion ratio, toggle for skip-NFT preference. Design decisions: whether to surface the dual nature prominently or abstract it, explaining skip-NFT for gas savings vs collectibility, handling marketplace display of both representations.","hasDetailedContent":true,"content":{"id":"ERC-7631","sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-7631","type":"official-spec"}],"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25","summary":"Paired ERC-20 and ERC-721 tokens that sync — buying fungible tokens auto-mints NFTs proportionally.","designerTakeaways":["You can show X tokens = Y NFTs ratio on every purchase screen.","Your settings can offer Skip NFT mint for gas savings with collectibility tradeoff explained.","You can display linked NFT and token together in one portfolio row."],"applicability":{"whenToUse":["Project issues both fungible and NFT representation.","Auto-mint NFT on token purchase is on-chain rule.","Skip-NFT option exists for gas-conscious users."],"whenToAvoid":["Separate unrelated ERC-20 and ERC-721.","Pair sync not implemented.","Users only ever interact with one side."]},"prototypeFirst":[{"screen":"Dual asset portfolio row","why":"Users must see both legs of pair.","covers":["Both held","Token only skipped NFT","NFT only"],"include":["Linked icon","Token balance","NFT thumbnail","Ratio label"]},{"screen":"Purchase with skip-NFT toggle","why":"Gas vs collectibility decision at checkout.","covers":["Skip on","Skip off"],"include":["Toggle with cost estimate","What you miss copy","Confirm purchase"]},{"screen":"Marketplace dual listing","why":"Buyers see both representations.","covers":["Listed as pair","Partial listing"],"include":["Pair badge","Conversion ratio","Linked item links"]},{"screen":"Sync status indicator","why":"When pair desyncs users panic.","covers":["Synced","NFT skipped","Pending mint"],"include":["Sync chip","Mint pending state","Link to mint NFT"]}],"mentalModel":[{"label":"Dual nature","description":"One economic position, two on-chain representations."},{"label":"Conversion ratio","description":"Fixed formula maps token amount to NFT count."},{"label":"Skip NFT","description":"User opts out of collectible mint — holds tokens only."},{"label":"Auto-mint","description":"Buying tokens triggers NFT mint when skip off."},{"label":"Pair sync","description":"Burning or transferring may affect both sides — read rules."}],"statesToDesign":[{"state":"Fully synced pair","trigger":"User holds matching token and NFT amounts.","userNeed":"See unified position.","designResponse":"Single row with both previews."},{"state":"Skipped NFT","trigger":"User bought with skip on.","userNeed":"Know can mint later or not.","designResponse":"Tokens only with Mint collectible CTA if allowed."},{"state":"Pending NFT mint","trigger":"Purchase confirmed, NFT minting.","userNeed":"Track mint progress.","designResponse":"Minting collectible status strip."},{"state":"Ratio display at purchase","trigger":"Checkout.","userNeed":"Predict what they receive.","designResponse":"You get 100 TOKEN + 1 NFT preview."},{"state":"Partial side only in wallet","trigger":"Indexer missed one leg.","userNeed":"Not think asset lost.","designResponse":"Loading linked asset or manual refresh."}],"designDecisions":[{"question":"Prominent dual nature or abstract?","recommendation":"Show pair on detail; simplify to primary asset in grid.","rationale":"Grid clutter if always dual."},{"question":"Default skip-NFT on or off?","recommendation":"Off for collectors; remember user preference.","rationale":"Gas savings vs collectibility is personal."},{"question":"Marketplace show one or two listings?","recommendation":"Single listing with pair badge linking both.","rationale":"Split listings confuse price discovery."}],"problemsSolved":[{"problem":"Users unaware of linked NFT","oldWay":"Only token shows in wallet","newWay":"Dual row shows both representations","impact":"high"},{"problem":"Unexpected NFT mint gas","oldWay":"Surprise second transaction","newWay":"Skip-NFT toggle at purchase with estimate","impact":"high"},{"problem":"Marketplace lists only one side","oldWay":"Buyer misses collectible component","newWay":"Pair badge with ratio on listing","impact":"medium"}],"uxPatterns":[{"name":"Dual Asset Row","description":"Portfolio entry showing linked token and NFT.","mockup":"concept/nft-gallery","components":["PairLink","TokenBalance","NFTThumb","RatioLabel"],"userFlow":["Load portfolio","Pair detected","Show unified row","Expand for both"]},{"name":"Skip NFT Toggle","description":"Checkout option to skip collectible mint.","mockup":"concept/permit-approval","components":["SkipToggle","GasEstimate","TradeoffCopy"],"userFlow":["User buys","Toggles skip","Sees savings","Confirms","Receives tokens only"]}],"seenInTheWild":[{"app":"Uniswap","url":"https://app.uniswap.org/","note":"LP position NFT pairs inform dual-asset display."},{"app":"OpenSea","url":"https://opensea.io/","note":"Bundled item display for related assets."},{"app":"Zora","url":"https://zora.co/","note":"Creator coin + NFT experiments."}],"antiPatterns":[{"pattern":"Showing only ERC-20 after paired purchase","why":"Users think NFT failed to mint","instead":"Dual row or mint pending status","severity":"high"},{"pattern":"Skip-NFT hidden in advanced","why":"Surprise gas for unwanted mint","instead":"Checkout toggle with clear default","severity":"high"},{"pattern":"Separate listings without link","why":"Price arbitrage confusion","instead":"Single pair listing with ratio","severity":"medium"}],"vocabulary":[{"use":"Linked collectible","avoid":"ERC-721 side of pair","why":"Collectible language."},{"use":"100 tokens = 1 NFT","avoid":"Sync ratio constant","why":"Conversion plain math."},{"use":"Skip collectible mint","avoid":"Set skipNFT flag","why":"Checkout option language."}],"onMonad":[{"aspect":"Dual mint cost","ethereum":"Token + NFT mint gas stacks","monad":"Lower fees make skip less critical but toggle still valuable","designImplication":"Show combined mint estimate on Monad checkout."},{"aspect":"Sync refresh","ethereum":"Pair index lag","monad":"Fast mint confirmation updates dual row quickly","designImplication":"Inline minting status without long poll."}],"technicalNotes":"ERC-7631 is draft; always show conversion ratio at purchase and linked asset in portfolio.","relatedStandards":[{"id":"ERC-20","relationship":"Fungible leg of pair"},{"id":"ERC-721","relationship":"NFT leg of pair"}]},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-7631","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-7631","type":"discussion"},{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-7631","type":"official-spec"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-7631","markdown":"https://www.eipsfordesigners.com/standards/ERC-7631/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-7631/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-7631","official":"https://eips.ethereum.org/EIPS/erc-7631","discussion":"https://ethereum-magicians.org/search?q=ERC-7631"},"freshness":{"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25"}},{"id":"ERC-2981","name":"NFT Royalty Standard","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":"Standardized royalty info — marketplaces can query royalty percentage and recipient for any NFT. Design implications: show royalty percentage on listings (e.g., '5% creator royalty'), display royalty recipient/creator info, calculate and preview royalty amount during purchase, indicate if marketplace honors royalties. Design decisions: whether to show royalties as percentage or absolute amount, how prominently to display (affects buyer decisions), handling marketplaces that don't enforce royalties.","hasDetailedContent":true,"content":{"id":"ERC-2981","summary":"ERC-2981 standardizes NFT royalties. Creators set a percentage (e.g., 5%), and any marketplace can query it via royaltyInfo(). When an NFT sells, the marketplace knows who gets royalties and how much. Before this, every marketplace had different royalty systems. Now there's one source of truth: the NFT contract itself.","applicability":{"whenToUse":["Your product addresses: no standard way to specify royalties.","Your product addresses: royalties differ across platforms.","The flow should deliver: one royaltyInfo() function, all marketplaces read it.","You are designing a royalty display on listing experience with visible states and recovery paths."],"whenToAvoid":["Show royalty prominently in fee breakdown.","Always call royaltyInfo() for current settings.","Honor on-chain royalties or disclose clearly.","Assets are fungible tokens only with no unique-item semantics."]},"designerTakeaways":["You can design UI that delivers one royaltyInfo() function, all marketplaces read it.","You can design UI that delivers contract specifies rate.","You can design UI that delivers on-chain, verifiable, queryable royalty info."],"problemsSolved":[{"problem":"No standard way to specify royalties","oldWay":"Set royalties separately on OpenSea, Rarible, each marketplace","newWay":"One royaltyInfo() function, all marketplaces read it","impact":"critical"},{"problem":"Royalties differ across platforms","oldWay":"5% on OpenSea, 10% on LooksRare, 0% on SudoSwap","newWay":"Contract specifies rate, marketplaces honor it (ideally)","impact":"high"},{"problem":"Creators can't verify royalty settings","oldWay":"Check each marketplace dashboard separately","newWay":"On-chain, verifiable, queryable royalty info","impact":"medium"}],"uxPatterns":[{"name":"Royalty Display on Listing","description":"Show creator royalty when listing NFT","mockup":"concept/nft-gallery","userFlow":["User lists NFT","Marketplace queries royaltyInfo()","Shows royalty % and recipient","Calculates user proceeds","User sees clear breakdown"]},{"name":"Purchase with Royalty","description":"Show buyer where funds go","mockup":"generic/list-selector","userFlow":["User clicks buy","Shows payment distribution","Creator gets royalty","User understands where ETH goes","Completes purchase"]}],"uiComponents":[{"name":"RoyaltyBadge","description":"Shows royalty percentage on NFT card","states":["has-royalty","no-royalty","loading"],"props":["percentage","recipient"]},{"name":"FeeBreakdown","description":"Detailed breakdown of sale/purchase fees","states":["collapsed","expanded"],"props":["salePrice","royalty","platformFee","proceeds"]},{"name":"CreatorRoyaltyInfo","description":"Shows creator address and royalty settings","states":["verified","unverified"],"props":["creator","percentage","isVerified"]}],"antiPatterns":[{"pattern":"Hiding royalty in fine print","why":"Sellers surprised by lower proceeds","instead":"Show royalty prominently in fee breakdown","severity":"high"},{"pattern":"Not querying on-chain royalty","why":"May show outdated or wrong royalty info","instead":"Always call royaltyInfo() for current settings","severity":"medium"},{"pattern":"Offering 0% royalty override","why":"Undermines creator compensation model","instead":"Honor on-chain royalties or disclose clearly","severity":"medium"}],"onMonad":[{"aspect":"Royalty Query","ethereum":"royaltyInfo() call is standard","monad":"Same interface, no changes needed","designImplication":"Works identically on Monad"}],"keyTakeaways":["ERC-2981 = on-chain NFT royalty standard","Query royaltyInfo(tokenId, salePrice) for royalty data","Show royalty in fee breakdown, not hidden","Display creator/recipient address clearly","Enforcement varies by marketplace"],"technicalNotes":"ERC-2981 adds royaltyInfo(uint256 tokenId, uint256 salePrice) returns (address receiver, uint256 royaltyAmount). Returns royalty recipient and absolute amount based on sale price. Interface ID: 0x2a55205a. Note: ERC-2981 is informational — marketplaces choose whether to enforce. Some bypass via aggregators or direct transfers."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-2981","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-2981","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-2981","markdown":"https://www.eipsfordesigners.com/standards/ERC-2981/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-2981/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-2981","official":"https://eips.ethereum.org/EIPS/eip-2981","discussion":"https://ethereum-magicians.org/search?q=ERC-2981"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"ERC-4910","name":"Royalty Bearing NFT","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":"Hierarchical on-chain royalty distribution — derivative NFTs pay royalties up the ancestry chain automatically. Design implications: show royalty tree visualization (who gets paid from this sale), display ancestor relationships, indicate derivative status, show accumulated royalty earnings. Design decisions: complexity of showing multi-level royalty splits, whether to expose full royalty hierarchy or summarize, handling deep ancestry chains in UI.","hasDetailedContent":true,"content":{"id":"ERC-4910","summary":"ERC-4910 creates a comprehensive on-chain royalty system for NFTs. Unlike ERC-2981 which only provides royalty information, ERC-4910 actually tracks and distributes royalties. It maintains a royalty tree showing who gets paid what, handles multi-level splits (original creator, collaborators, resellers), and enables royalties to be queried, claimed, and even traded as their own assets.","applicability":{"whenToUse":["Your product addresses: eRC-2981 royalties aren't enforced, marketplaces can ignore them.","Your product addresses: no way to split royalties between multiple creators.","The flow should deliver: royalty entitlements tracked on-chain, claimable by rights holders.","You are designing a creator royalty dashboard experience with visible states and recovery paths."],"whenToAvoid":["Show complete breakdown: price + royalties + who receives what.","Prominent \"Claim\" button, notifications when royalties available.","Badge: \"On-chain enforced\" vs \"Marketplace dependent\".","Assets are fungible tokens only with no unique-item semantics."]},"designerTakeaways":["You can design UI that delivers royalty entitlements tracked on-chain.","You can design UI that delivers on-chain royalty tree with automatic distribution.","You can design UI that delivers royalty bearer tokens can be transferred like any asset."],"problemsSolved":[{"problem":"ERC-2981 royalties aren't enforced, marketplaces can ignore them","oldWay":"Marketplace queries royalty info, may or may not pay it","newWay":"Royalty entitlements tracked on-chain, claimable by rights holders","impact":"critical"},{"problem":"No way to split royalties between multiple creators","oldWay":"Single royalty recipient, manual off-chain splitting","newWay":"On-chain royalty tree with automatic distribution","impact":"high"},{"problem":"Royalty rights can't be transferred or traded","oldWay":"Royalties locked to original address forever","newWay":"Royalty bearer tokens can be transferred like any asset","impact":"high"},{"problem":"No transparency on royalty accumulation","oldWay":"Creators don't know what they're owed until payment arrives","newWay":"Query pending royalties anytime, claim when ready","impact":"medium"}],"uxPatterns":[{"name":"Creator Royalty Dashboard","description":"Track all royalties across collections","mockup":"concept/nft-gallery","userFlow":["Creator opens royalty dashboard","See total claimable across all NFTs","View breakdown by collection","See share percentage for each","Claim individual or all at once","Funds transfer to wallet"]},{"name":"Royalty Split Configuration","description":"Set up multi-party royalty distribution","mockup":"generic/vault-deposit","userFlow":["Creator sets total royalty percentage","Add recipients with addresses","Allocate share to each recipient","Visualize distribution","Save configuration on-chain","All parties can claim their share"]},{"name":"Royalty Bearer Token","description":"View and transfer royalty rights","mockup":"concept/tx-status","userFlow":["User holds royalty bearer token","View allocation percentage","See pending and historical earnings","Claim accumulated royalties","Or transfer/sell the rights to someone else","New holder receives future royalties"]},{"name":"Buyer Royalty Transparency","description":"Show buyers where royalties go","mockup":"concept/nft-gallery","userFlow":["Buyer views NFT listing","See complete price breakdown","Royalty recipients shown transparently","Understand where money goes","On-chain enforcement indicator","Complete purchase with confidence"]}],"uiComponents":[{"name":"RoyaltyClaimWidget","description":"Shows claimable royalties with claim action","states":["loading","has-royalties","empty","claiming","claimed"],"props":["balance","collections","onClaim","onClaimAll"]},{"name":"SplitConfigurator","description":"UI for setting up multi-party splits","states":["editing","validating","saving","locked"],"props":["recipients","totalPercentage","onChange","onSave"]},{"name":"RoyaltyTreeView","description":"Visual hierarchy of royalty distribution","states":["collapsed","expanded","loading"],"props":["root","recipients","amounts","depth"]},{"name":"RoyaltyBearerCard","description":"Displays royalty token as tradeable asset","states":["owned","for-sale","pending-claim"],"props":["token","allocation","earnings","onAction"]}],"antiPatterns":[{"pattern":"Not showing royalty split before purchase","why":"Buyers surprised by hidden fees, lose trust","instead":"Show complete breakdown: price + royalties + who receives what","severity":"critical"},{"pattern":"Making royalty claiming complicated","why":"Creators don't claim, lose money","instead":"Prominent \"Claim\" button, notifications when royalties available","severity":"high"},{"pattern":"Hiding that royalty rights can be transferred","why":"Creators don't know they can monetize rights now vs waiting","instead":"Clearly show \"Transfer\" and \"Sell\" options for royalty tokens","severity":"medium"},{"pattern":"No visualization of split percentages","why":"Hard to understand complex multi-party splits","instead":"Use visual bars, charts showing distribution clearly","severity":"medium"},{"pattern":"Not distinguishing enforced vs suggested royalties","why":"Creators think all royalties are enforced when they're not","instead":"Badge: \"On-chain enforced\" vs \"Marketplace dependent\"","severity":"high"}],"onMonad":[{"aspect":"Royalty Distribution Speed","ethereum":"Royalties may take multiple transactions to distribute","monad":"Instant distribution to all parties in split","designImplication":"Real-time royalty updates, no distribution delays"},{"aspect":"Claim Costs","ethereum":"Gas costs may exceed small royalty amounts","monad":"Even tiny royalties worth claiming","designImplication":"Can show \"Claim\" for any amount, not just minimum thresholds"},{"aspect":"Complex Splits","ethereum":"Deep royalty trees expensive to process","monad":"Complex distributions remain cheap","designImplication":"Support more sophisticated revenue sharing models"},{"aspect":"Real-time Tracking","ethereum":"Querying royalty state is slow","monad":"Sub-second queries for balances","designImplication":"Live updating royalty dashboards feasible"}],"keyTakeaways":["ERC-4910 = on-chain tracked and distributed royalties","Supports multi-party splits with visual representation","Royalty rights are tradeable as bearer tokens","Always show buyers the complete royalty breakdown","On Monad: instant distribution, micro-royalties viable"],"technicalNotes":"ERC-4910 extends ERC-721 with royalty tracking infrastructure. It maintains a royalty tree where each node represents a recipient and their percentage. Royalty bearer tokens (RBTs) represent ownership of future royalty payments and can be transferred. The standard defines getRoyalties(), claimRoyalties(), and royaltyBalanceOf() for comprehensive royalty management."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-4910","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-4910","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-4910","markdown":"https://www.eipsfordesigners.com/standards/ERC-4910/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-4910/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-4910","official":"https://eips.ethereum.org/EIPS/eip-4910","discussion":"https://ethereum-magicians.org/search?q=ERC-4910"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"ERC-6105","name":"No Intermediary NFT Trading","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":"Built-in marketplace functionality — list, buy, and sell NFTs directly from the contract without intermediary. Design implications: show 'List for Sale' directly in wallet UI, display listing price/expiry on owned tokens, enable direct purchase without marketplace approval, show benchmarkPrice for royalty calculation. Design decisions: whether to compete with external marketplaces in UI, simplicity of direct listing vs marketplace features, handling multiple payment tokens.","hasDetailedContent":true,"content":{"id":"ERC-6105","summary":"ERC-6105 enables peer-to-peer NFT trading without marketplace intermediaries. Sellers can list NFTs directly from the contract with price, buyer restrictions, and expiration. Buyers purchase directly on-chain with enforced royalties. This removes marketplace fees, ensures creator royalties are always paid, and enables truly decentralized NFT trading.","applicability":{"whenToUse":["Your product addresses: marketplaces charge 2-5% fees on every sale.","Your product addresses: marketplaces can skip royalties.","The flow should deliver: direct on-chain listing, no intermediary fees.","You are designing a direct listing interface experience with visible states and recovery paths."],"whenToAvoid":["Show explicit comparison: \"Marketplace fee: $0 (normally 2.5%)\".","Prominently show \"Creator royalty enforced on-chain\".","Explain: \"Only specified buyer can purchase\" + show buyer address.","Assets are fungible tokens only with no unique-item semantics."]},"designerTakeaways":["You can design UI that delivers direct on-chain listing, no intermediary fees.","You can design UI that delivers royalties enforced at contract level, can't be bypassed.","You can design UI that delivers atomic on-chain swap: payment and NFT transfer together."],"problemsSolved":[{"problem":"Marketplaces charge 2-5% fees on every sale","oldWay":"List on OpenSea, pay 2.5% even for peer-to-peer trade","newWay":"Direct on-chain listing, no intermediary fees","impact":"critical"},{"problem":"Marketplaces can skip royalties","oldWay":"Some platforms set royalties to 0 to attract volume","newWay":"Royalties enforced at contract level, can't be bypassed","impact":"critical"},{"problem":"Direct peer trades require trust or escrow","oldWay":"Send NFT and hope buyer pays, or use expensive escrow","newWay":"Atomic on-chain swap: payment and NFT transfer together","impact":"high"},{"problem":"Private sales are awkward","oldWay":"List publicly, hope only intended buyer sees it quickly","newWay":"List for specific buyer address only","impact":"medium"}],"uxPatterns":[{"name":"Direct Listing Interface","description":"List NFT for sale without marketplace","mockup":"concept/nft-gallery","userFlow":["User selects NFT to sell","Enter sale price","Choose public or private sale","See fee breakdown (no marketplace fee)","Set expiration time","Create on-chain listing"]},{"name":"Private Sale to Friend","description":"Sell directly to specific address","mockup":"generic/vault-deposit","userFlow":["User chooses private sale","Enter buyer ENS or address","Confirm sale details","Create on-chain listing","Share link with intended buyer","Only that address can purchase"]},{"name":"Direct Purchase Flow","description":"Buy NFT directly from on-chain listing","mockup":"concept/nft-gallery","userFlow":["Buyer opens listing link","See NFT details and price","Notice \"Direct On-Chain Sale\" badge","Review payment breakdown","Click buy","Single transaction completes purchase"]},{"name":"Active Listings Manager","description":"Manage your on-chain listings","mockup":"generic/list-selector","userFlow":["Seller views active listings","See all on-chain listings","Check expiration status","Edit price if needed","Cancel listing (NFT unlocks)","Relist expired items"]}],"uiComponents":[{"name":"DirectListingForm","description":"Create on-chain NFT listing","states":["editing","confirming","listing","listed"],"props":["nft","onList","defaultPrice","showRoyalty"]},{"name":"PrivateSaleConfig","description":"Configure buyer-restricted sale","states":["public","private","validating-address"],"props":["buyerAddress","onBuyerChange","resolved"]},{"name":"DirectPurchaseCard","description":"Purchase UI for on-chain listings","states":["available","expired","sold","purchasing"],"props":["listing","onPurchase","showBreakdown"]},{"name":"ListingManager","description":"Dashboard for managing active listings","states":["loading","has-listings","empty"],"props":["listings","onEdit","onCancel"]}],"antiPatterns":[{"pattern":"Not explaining the no-marketplace advantage","why":"Users don't realize they're saving 2-5% fees","instead":"Show explicit comparison: \"Marketplace fee: $0 (normally 2.5%)\"","severity":"high"},{"pattern":"Hiding that royalties are enforced","why":"Creators don't know their royalties are protected","instead":"Prominently show \"Creator royalty enforced on-chain\"","severity":"high"},{"pattern":"Making private sales look suspicious","why":"Looks like a scam link","instead":"Explain: \"Only specified buyer can purchase\" + show buyer address","severity":"medium"},{"pattern":"No confirmation before listing","why":"User lists at wrong price by accident","instead":"Show full summary + confirmation before on-chain listing","severity":"medium"},{"pattern":"Not showing listing expiration clearly","why":"Seller forgets listing exists, price becomes stale","instead":"Notify when listings near expiration, show clear countdown","severity":"medium"}],"onMonad":[{"aspect":"Listing Speed","ethereum":"Creating listing takes 15-30 seconds","monad":"Instant listing creation","designImplication":"List multiple items rapidly, batch listing UI practical"},{"aspect":"Purchase Confirmation","ethereum":"Buyer waits 15+ seconds to confirm ownership","monad":"Sub-second purchase confirmation","designImplication":"Can show \"You own it!\" immediately"},{"aspect":"Gas Costs","ethereum":"Each listing/purchase costs $5-50","monad":"Negligible costs for all operations","designImplication":"Price edits, relisting, cancellation all cheap"},{"aspect":"Royalty Distribution","ethereum":"Royalty payment in same tx can add cost","monad":"Complex distribution still fast and cheap","designImplication":"Multi-recipient royalty splits practical"}],"keyTakeaways":["ERC-6105 = peer-to-peer NFT trading without marketplace","Zero platform fees, enforced royalties","Private sales to specific addresses supported","Highlight savings vs marketplace fees clearly","On Monad: instant listing and purchase"],"technicalNotes":"ERC-6105 extends ERC-721 with setListing(tokenId, price, expiration, buyer) and purchase(tokenId) functions. The listing is stored on-chain with optional buyer restriction. Purchase atomically transfers NFT to buyer and distributes payment to seller + royalty recipients. Compatible with ERC-2981 for royalty information. Listings can be cancelled or updated by the seller."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-6105","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-6105","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-6105","markdown":"https://www.eipsfordesigners.com/standards/ERC-6105/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-6105/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-6105","official":"https://eips.ethereum.org/EIPS/eip-6105","discussion":"https://ethereum-magicians.org/search?q=ERC-6105"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"ERC-2309","name":"ERC-721 Consecutive Transfer Extension","status":"Final","chain":"both","category":{"id":"nft","name":"NFT Capabilities","description":"What NFTs can do beyond basic ownership"},"journeyStages":[{"id":"executing","name":"Executing Transactions","description":"Performing on-chain actions"}],"uxImpact":"Batch minting/transfer events — efficiently create or move thousands of consecutive tokens in one transaction. Design implications: show batch mint/transfer notifications (e.g., 'Received tokens #1-1000'), handle large collection imports without individual events, efficient indexing of mass distributions. Design decisions: how to display large batch receipts without overwhelming, progress indicators for indexing large transfers, summarizing vs listing individual tokens.","hasDetailedContent":true,"content":{"id":"ERC-2309","sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-2309","type":"official-spec"}],"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25","summary":"Batch minting/transfer events — efficiently create or move thousands of consecutive tokens in one transaction.","designerTakeaways":["You can collapse consecutive mints into one Received #1–1000 activity row with expand option.","Your import progress can show Indexing 847 of 1000 tokens during large batch processing.","You can offer summary-first gallery with expand to id list for power users."],"applicability":{"whenToUse":["Mass airdrops or batch mints use consecutive ids.","Activity feed would choke on individual events.","Indexer supports range expansion."],"whenToAvoid":["Single NFT mints with no batch events.","Non-consecutive token ids in batch.","Users need immediate per-id detail without indexing wait."]},"prototypeFirst":[{"screen":"Batch receipt notification","why":"First touch after airdrop sets expectations.","covers":["Range summary","Expand ids"],"include":["You received #1–1000","Collection name","View collection CTA"]},{"screen":"Indexing progress","why":"Large batches take time to appear in gallery.","covers":["Indexing","Complete","Partial failure"],"include":["Progress bar","Count label","Retry indexing"]},{"screen":"Activity feed aggregation","why":"Feed readability for whale airdrops.","covers":["Collapsed batch","Expanded id list"],"include":["Summary row","Expand chevron","Max expand limit"]},{"screen":"Collection grid after batch","why":"Gallery must load performantly.","covers":["Virtualized grid","Representative thumbnails"],"include":["Lazy load","Sample preview strip","View all"]}],"mentalModel":[{"label":"Consecutive range","description":"Tokens #start–#end moved in one on-chain event."},{"label":"Batch event","description":"One log line represents many tokens — UI summarizes."},{"label":"Indexer expansion","description":"Backend expands range into individual holdings asynchronously."},{"label":"Summary vs detail","description":"Default summary; expand for id list when needed."},{"label":"Airdrop receipt","description":"User cares they got the drop, not 1000 duplicate lines."}],"statesToDesign":[{"state":"Batch received — indexing","trigger":"Event seen, gallery loading.","userNeed":"Know tokens are coming.","designResponse":"Indexing N tokens progress indicator."},{"state":"Batch complete in gallery","trigger":"Indexer finished.","userNeed":"Browse collection.","designResponse":"Full grid with count badge on collection."},{"state":"Activity feed collapsed","trigger":"Default view.","userNeed":"Scan history quickly.","designResponse":"Single batch row with range."},{"state":"Expanded id list","trigger":"User expands batch row.","userNeed":"Find specific id.","designResponse":"Paginated id list or search within range."},{"state":"Partial index failure","trigger":"Indexer timeout.","userNeed":"Recover without panic.","designResponse":"Retry indexing with support link."}],"designDecisions":[{"question":"Summary or list by default?","recommendation":"Summary in feed; full grid in collection view.","rationale":"Feed chokes on thousands of rows."},{"question":"How many ids in expand?","recommendation":"Paginate at 50; offer search by id.","rationale":"Rendering 1000 rows crashes mobile."},{"question":"Notification for batch?","recommendation":"One push: You received 1000 [Collection] tokens.","rationale":"1000 pushes would spam."}],"problemsSolved":[{"problem":"Activity feed unusable after airdrop","oldWay":"1000 identical transfer lines","newWay":"Single batch summary row","impact":"high"},{"problem":"Slow gallery after mass mint","oldWay":"UI freezes loading all items","newWay":"Progressive indexing with progress UI","impact":"high"},{"problem":"Users miss airdrop happened","oldWay":"Buried in noise or invisible","newWay":"Clear batch receipt notification","impact":"medium"}],"uxPatterns":[{"name":"Batch Activity Summary","description":"Collapsed range row in transaction history.","mockup":"concept/nft-gallery","components":["BatchRow","RangeLabel","ExpandToggle"],"userFlow":["Airdrop lands","Feed shows one row","User expands optional","Ids paginate"]},{"name":"Collection Index Progress","description":"Progress while indexer expands token range.","mockup":"concept/tx-status","components":["ProgressBar","CountLabel","RetryButton"],"userFlow":["Batch detected","Progress shown","Grid populates","Complete state"]}],"seenInTheWild":[{"app":"OpenSea","url":"https://opensea.io/","note":"Large collection import and activity aggregation patterns."},{"app":"Blur","url":"https://blur.io/","note":"Batch bid and airdrop UX for high-volume collections."},{"app":"Etherscan","url":"https://etherscan.io/","note":"Batch transfer event display on explorer."}],"antiPatterns":[{"pattern":"1000 separate activity notifications","why":"UI freeze and notification spam","instead":"Single batch summary with optional expand","severity":"critical"},{"pattern":"Empty gallery during indexing with no progress","why":"Users think airdrop failed","instead":"Indexing N tokens progress bar","severity":"high"},{"pattern":"Rendering full id list on mobile expand","why":"Browser crash","instead":"Paginated expand with search","severity":"high"}],"vocabulary":[{"use":"Received 500 tokens","avoid":"ConsecutiveTransfer event id 1-500","why":"Outcome not event name."},{"use":"Loading your collection","avoid":"Indexer expanding range","why":"User-facing wait copy."},{"use":"Show token IDs","avoid":"Expand batch mint log","why":"Power user optional action."}],"onMonad":[{"aspect":"Batch mint throughput","ethereum":"Large drops congest indexers","monad":"High TPS enables faster batch indexing","designImplication":"Shorter indexing progress on Monad airdrops."},{"aspect":"Activity volume","ethereum":"Feed lag on big batches","monad":"Fast blocks still need UI aggregation","designImplication":"Always summarize batches regardless of chain speed."}],"technicalNotes":"ERC-2309 consecutive events require indexer range expansion; never render unbounded id lists.","relatedStandards":[{"id":"ERC-721","relationship":"Consecutive transfer extension for ERC-721"},{"id":"ERC-1155","relationship":"Batch transfers in multi-token standard"}]},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-2309","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-2309","type":"discussion"},{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-2309","type":"official-spec"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-2309","markdown":"https://www.eipsfordesigners.com/standards/ERC-2309/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-2309/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-2309","official":"https://eips.ethereum.org/EIPS/erc-2309","discussion":"https://ethereum-magicians.org/search?q=ERC-2309"},"freshness":{"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25"}},{"id":"ERC-6551","name":"Non-fungible Token Bound Accounts","status":"Review","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"},{"id":"management","name":"Asset Management","description":"Managing assets over time"}],"uxImpact":"NFTs have their own wallet addresses — tokens can own assets, sign messages, and interact with dApps. Design implications: show 'Token Bound Account' with address and contained assets, enable NFT-as-wallet interactions, display nested inventory inside NFT, indicate TBA-enabled tokens. Design decisions: how to visualize 'wallet inside NFT' concept, whether to expose TBA address or abstract it, complexity of NFT-initiated transactions, handling ownership transfers (assets follow NFT). 🟢 Widely deployed (tokenbound.org registry live).","hasDetailedContent":true,"content":{"id":"ERC-6551","summary":"ERC-6551 gives every NFT its own wallet address. Your character NFT can own a sword NFT, gold tokens, and other items. When you sell or transfer the character, everything inside goes with it. This transforms NFTs from static images into portable, composable identities and inventories.","applicability":{"whenToUse":["Your product addresses: game characters and inventory disconnected.","Your product addresses: nFT profiles can't hold assets.","The flow should deliver: character owns items, sell character = sell everything.","Inventory or transfer UI must show quantities and support multi-item actions."],"whenToAvoid":["Always fetch and display token bound account contents.","Clear warning: \"Goes to NFT, not current owner\".","Check if TBA exists, offer to create if not.","Assets are fungible tokens only with no unique-item semantics."]},"designerTakeaways":["You can design UI that delivers character owns items, sell character = sell everything.","You can design UI that delivers your NFT collects airdrops, tips, achievements.","You can design UI that delivers on-chain ownership: sword.owner = character.address."],"problemsSolved":[{"problem":"Game characters and inventory disconnected","oldWay":"Character is one NFT, items are separate, manually bundle for sale","newWay":"Character owns items, sell character = sell everything","impact":"critical"},{"problem":"NFT profiles can't hold assets","oldWay":"PFP NFT is just an image, can't accumulate value","newWay":"Your NFT collects airdrops, tips, achievements","impact":"high"},{"problem":"Tracking what belongs to what asset","oldWay":"Off-chain databases, manual tracking, trust the game server","newWay":"On-chain ownership: sword.owner = character.address","impact":"high"},{"problem":"NFT trading doesn't include accessories","oldWay":"Buy ape, separately negotiate for hat, shirt, chain","newWay":"Buy ape, hat comes with it because ape owns hat","impact":"medium"},{"problem":"Proving ownership history of nested assets","oldWay":"Trust marketplace metadata, often wrong","newWay":"On-chain trail: this sword was owned by THIS hero","impact":"medium"}],"uxPatterns":[{"name":"NFT Inventory View","description":"Show what an NFT owns inside its wallet","mockup":"concept/nft-gallery","userFlow":["User selects NFT in collection","App fetches NFT's token bound account","Queries account for owned assets","Displays inventory and balances","User can manage items"]},{"name":"Send to NFT","description":"Send assets directly to an NFT's wallet","mockup":"concept/nft-gallery","userFlow":["User selects \"Send to NFT\"","Enters NFT ID or scans","App resolves token bound account","Shows ownership warning","User confirms send"]},{"name":"NFT Marketplace with Inventory","description":"List NFTs showing what's bundled inside","mockup":"concept/nft-gallery","userFlow":["Marketplace lists NFT for sale","Fetches NFT's TBA contents","Shows bundle value estimate","Buyer sees total value","Single purchase gets everything"]},{"name":"Airdrop to NFT Holders","description":"Send rewards directly to NFTs, not wallets","mockup":"concept/nft-gallery","userFlow":["Project selects collection","Configures airdrop amount","System calculates all TBAs","Shows preview","Batch sends to all NFT wallets"]}],"uiComponents":[{"name":"TokenBoundAccountView","description":"Displays contents of an NFT's wallet","states":["loading","empty","has-assets","error"],"props":["nftContract","tokenId","chainId"]},{"name":"NFTInventory","description":"Grid/list of NFTs owned by another NFT","states":["loading","empty","populated"],"props":["tbaAddress","onSelect","onTransfer"]},{"name":"SendToNFTForm","description":"Form to send assets to an NFT's TBA","states":["input","resolving","ready","sending","complete"],"props":["asset","onSend"]},{"name":"BundleValueEstimate","description":"Calculates and displays total value of NFT + contents","states":["calculating","ready","partial-data"],"props":["nftValue","bundledAssets[]"]},{"name":"TBACreator","description":"Creates token bound account for NFT if not exists","states":["checking","not-created","creating","exists"],"props":["nftContract","tokenId","implementation"]}],"antiPatterns":[{"pattern":"Not showing TBA contents on NFT detail pages","why":"Buyers don't know what they're getting","instead":"Always fetch and display token bound account contents","severity":"critical"},{"pattern":"Allowing send to NFT without ownership warning","why":"User sends to NFT thinking owner will get it; NFT sells, assets gone","instead":"Clear warning: \"Goes to NFT, not current owner\"","severity":"critical"},{"pattern":"Assuming all NFTs have TBAs","why":"TBAs must be deployed; some NFTs may not have one yet","instead":"Check if TBA exists, offer to create if not","severity":"high"},{"pattern":"Hiding that NFTs can own assets","why":"Users don't realize their NFT has unclaimed value","instead":"Proactive notification: \"Your NFT received an airdrop\"","severity":"high"},{"pattern":"Not valuing bundled assets in listings","why":"Mispriced NFTs, buyer/seller confusion","instead":"Show estimated bundle value alongside NFT price","severity":"medium"},{"pattern":"Using technical term \"Token Bound Account\"","why":"Users don't understand what it means","instead":"\"NFT Wallet\", \"NFT Inventory\", \"What's Inside\"","severity":"medium"}],"onMonad":[{"aspect":"TBA Deployment Cost","ethereum":"~50k gas to deploy TBA","monad":"Same cost but much cheaper in USD","designImplication":"Can deploy TBAs liberally, even proactively"},{"aspect":"Inventory Queries","ethereum":"Multiple RPC calls, can be slow","monad":"Parallel execution makes queries faster","designImplication":"Can show real-time inventory updates"},{"aspect":"Bundle Transfers","ethereum":"One NFT transfer = one transaction","monad":"Sub-second finality for complex transfers","designImplication":"Instant feedback on inventory changes"},{"aspect":"Reserve Balance","ethereum":"TBA can be drained to zero","monad":"TBA EOAs maintain 10 MON reserve for async execution safety","designImplication":"Show spendable balance in NFT inventory"}],"keyTakeaways":["ERC-6551 = every NFT gets a wallet","Always show what's inside an NFT before purchase","Warn users when sending TO an NFT (not the owner)","Check if TBA exists before assuming it does","Use \"NFT Inventory\" not \"Token Bound Account\""],"technicalNotes":"ERC-6551 defines a registry contract that deploys minimal proxy accounts (ERC-1167) for any NFT. The account address is deterministic based on chain ID, token contract, token ID, salt, and implementation. Anyone can deploy a TBA for any NFT. The TBA implements ERC-165, ERC-1271 for signatures, and has an execute() function for the NFT owner to control it."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-6551","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-6551","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-6551","markdown":"https://www.eipsfordesigners.com/standards/ERC-6551/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-6551/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-6551","official":"https://eips.ethereum.org/EIPS/eip-6551","discussion":"https://ethereum-magicians.org/search?q=ERC-6551"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"ERC-4906","name":"NFT Metadata Update Extension","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":"Standardized metadata update events — platforms know when to refresh NFT images/attributes. Design implications: implement real-time metadata refresh on update events, show 'Updated' indicators, handle batch metadata updates efficiently, display metadata version/history if tracked. Design decisions: how quickly to refresh after events, caching strategies, whether to notify users of updates to owned tokens, handling frequent updates without UI flicker.","hasDetailedContent":true,"content":{"id":"ERC-4906","sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-4906","type":"official-spec"}],"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25","summary":"Standardized metadata update events — platforms know when to refresh NFT images/attributes.","designerTakeaways":["You can subscribe to 4906 events and refetch metadata automatically on update.","Your gallery can show subtle Updated chip after refresh completes.","You can debounce batch metadata updates to avoid image flicker during mass changes."],"applicability":{"whenToUse":["NFT metadata changes post-mint (reveals, evolving art).","Collection uses ERC-4906 update events.","Marketplaces must show fresh images."],"whenToAvoid":["Immutable metadata frozen at mint.","No event subscription infrastructure.","Updates so frequent UI cannot stabilize."]},"prototypeFirst":[{"screen":"Reveal moment refresh","why":"Pre-reveal to post-reveal is highest-stakes update.","covers":["Placeholder","Updating","Revealed"],"include":["Skeleton art","Refreshing spinner","New image fade-in"]},{"screen":"Updated badge on owned item","why":"Owners should know their NFT changed.","covers":["First view after update","Dismissed badge"],"include":["Updated chip","View changes link","Optional history"]},{"screen":"Batch metadata update","why":"Whole collection updates at once.","covers":["Batch event","Progress refresh"],"include":["Refreshing collection banner","Count updated","Done state"]},{"screen":"Stale cache fallback","why":"When refetch fails show honest state.","covers":["Fetch failed","Retry"],"include":["Could not refresh","Retry button","Last updated timestamp"]}],"mentalModel":[{"label":"Static metadata","description":"Old world — image never changes unless off-chain hack."},{"label":"Update event","description":"On-chain signal that tokenURI or attributes changed."},{"label":"Refetch","description":"App pulls new JSON and image after event."},{"label":"Reveal","description":"Special case of update — placeholder to final art."},{"label":"Batch update","description":"Many tokens updated — refresh without N separate spinners."}],"statesToDesign":[{"state":"Current metadata displayed","trigger":"Cache valid.","userNeed":"See accurate art.","designResponse":"Normal card display."},{"state":"Update detected — refreshing","trigger":"4906 event received.","userNeed":"Know image may change.","designResponse":"Subtle spinner overlay; keep old until new loads."},{"state":"Refresh complete","trigger":"New metadata fetched.","userNeed":"Notice change if owned.","designResponse":"Fade to new image; Updated badge optional."},{"state":"Batch collection refresh","trigger":"BatchMetadataUpdate.","userNeed":"Not see 1000 flickers.","designResponse":"Collection-level banner; debounced grid refresh."},{"state":"Refetch failed","trigger":"Gateway timeout.","userNeed":"Trust or retry.","designResponse":"Stale indicator with Retry refresh."}],"designDecisions":[{"question":"Notify owner on metadata update?","recommendation":"Optional push for owned tokens; silent for listings.","rationale":"Owners care; browsers do not need spam."},{"question":"Crossfade or hard swap?","recommendation":"Crossfade on reveal; instant on minor trait fix.","rationale":"Reveal is ceremonial; typo fix should be invisible."},{"question":"Cache TTL when no events?","recommendation":"Long cache with manual pull-to-refresh.","rationale":"4906 makes events primary refresh trigger."}],"problemsSolved":[{"problem":"Stale NFT images after reveal","oldWay":"Cache shows placeholder forever","newWay":"Event-driven refetch on MetadataUpdate","impact":"critical"},{"problem":"Platforms poll constantly","oldWay":"Wasteful polling every N seconds","newWay":"Update only on 4906 events","impact":"medium"},{"problem":"Users unaware metadata changed","oldWay":"Silent swap confuses owners","newWay":"Updated badge after refresh","impact":"medium"}],"uxPatterns":[{"name":"Event-Driven Refresh","description":"Auto-refetch on ERC-4906 metadata events.","mockup":"concept/nft-gallery","components":["EventListener","RefreshOverlay","UpdatedBadge"],"userFlow":["Event fires","Refetch starts","New art loads","Badge shows"]},{"name":"Reveal Transition","description":"Placeholder to final art crossfade.","mockup":"concept/nft-gallery","components":["PlaceholderArt","Crossfade","RevealBanner"],"userFlow":["Pre-reveal","Event received","Crossfade","Revealed state"]}],"seenInTheWild":[{"app":"OpenSea","url":"https://opensea.io/","note":"Refresh metadata button and reveal handling."},{"app":"Art Blocks","url":"https://www.artblocks.io/","note":"Generative reveal moments depend on metadata updates."},{"app":"Zora","url":"https://zora.co/","note":"Creator metadata updates on minted works."}],"antiPatterns":[{"pattern":"Never refetching after mint cache","why":"Permanent stale images post-reveal","instead":"Subscribe to 4906 and refetch","severity":"critical"},{"pattern":"Full grid flicker on batch update","why":"Epilepsy and distrust","instead":"Debounced batch refresh with banner","severity":"high"},{"pattern":"Hard swap without loading state","why":"Jarring image jump","instead":"Crossfade or skeleton during fetch","severity":"medium"}],"vocabulary":[{"use":"Artwork updated","avoid":"MetadataUpdate event emitted","why":"User-visible outcome."},{"use":"Refreshing","avoid":"Refetching tokenURI","why":"Loading state language."},{"use":"Reveal","avoid":"Batch metadata transition","why":"Collectible culture term."}],"onMonad":[{"aspect":"Update latency","ethereum":"Reveal wait feels long","monad":"Fast events enable snappier reveal UX","designImplication":"Tighter reveal animation timing on Monad."},{"aspect":"Batch updates","ethereum":"Mass refresh stresses gateways","monad":"High throughput collections need same debounce","designImplication":"Batch debounce still required on Monad."}],"technicalNotes":"ERC-4906 events are the refresh trigger; debounce BatchMetadataUpdate for grid stability.","relatedStandards":[{"id":"ERC-721","relationship":"Metadata update extension"},{"id":"ERC-5773","relationship":"Multi-asset tokens may update per asset"}]},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-4906","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-4906","type":"discussion"},{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-4906","type":"official-spec"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-4906","markdown":"https://www.eipsfordesigners.com/standards/ERC-4906/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-4906/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-4906","official":"https://eips.ethereum.org/EIPS/erc-4906","discussion":"https://ethereum-magicians.org/search?q=ERC-4906"},"freshness":{"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25"}},{"id":"ERC-5773","name":"Context-Dependent Multi-Asset Tokens","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":"NFTs have multiple assets (files) — different outputs based on context (PDF for readers, 3D for games, image for marketplaces). Design implications: show asset selector/tabs per NFT, display context-appropriate asset automatically, indicate available formats, allow owner to reorder asset priority. Design decisions: auto-detection of context vs manual selection, how to preview multiple assets, handling asset acceptance (propose-commit pattern), storage of multiple asset versions.","hasDetailedContent":true,"content":{"id":"ERC-5773","sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-5773","type":"official-spec"}],"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25","summary":"NFTs have multiple assets (files) — different outputs based on context (PDF for readers, 3D for games, image for marketplaces).","designerTakeaways":["You can auto-select marketplace image vs game 3D model based on app context.","Your detail page can show asset format tabs with preview for each accepted asset.","You can surface pending asset proposals with Accept for owners before they display publicly."],"applicability":{"whenToUse":["NFTs ship multiple file types for different platforms.","Games need 3D while marketplaces need PNG.","Owner curates asset priority order."],"whenToAvoid":["Single static image metadata only.","No multi-asset indexer support.","One format suffices everywhere."]},"prototypeFirst":[{"screen":"Context-aware display","why":"Same NFT must look right in marketplace vs game.","covers":["Marketplace context","Game context","Reader PDF"],"include":["Auto format pick","Context label in advanced","Fallback image"]},{"screen":"Asset tabs on detail","why":"Collectors browse all formats intentionally.","covers":["Image tab","3D tab","PDF tab"],"include":["Tab bar","Preview pane","Format badge"]},{"screen":"Owner asset priority editor","why":"Owners decide which asset shows first where.","covers":["Reorder list","Save priority"],"include":["Drag reorder","Context mapping","Save confirmation"]},{"screen":"Pending asset proposal","why":"New assets need acceptance before public display.","covers":["Proposed","Accepted","Rejected"],"include":["Proposal inbox","Preview","Accept/Decline"]}],"mentalModel":[{"label":"Multi-asset token","description":"One NFT id, many files attached with metadata."},{"label":"Context","description":"Marketplace, game, or reader — each picks appropriate asset."},{"label":"Priority order","description":"Owner-ranked fallback when context ambiguous."},{"label":"Propose-commit","description":"New assets proposed then accepted like nested NFT flow."},{"label":"Accepted vs pending","description":"Only accepted assets show in public views."}],"statesToDesign":[{"state":"Single context render","trigger":"App knows context.","userNeed":"See right format automatically.","designResponse":"Render best asset silently."},{"state":"Multi-tab browse","trigger":"User on detail page.","userNeed":"Compare formats.","designResponse":"Tabs with previews per format."},{"state":"Pending asset proposal","trigger":"Creator proposed new file.","userNeed":"Review before public.","designResponse":"Owner inbox with Accept/Decline."},{"state":"Missing format for context","trigger":"Game wants 3D but none accepted.","userNeed":"Graceful fallback.","designResponse":"Fallback image plus 3D not available note."},{"state":"Priority reorder saved","trigger":"Owner changed order.","userNeed":"Confirm public display updated.","designResponse":"Saved toast; refresh previews."}],"designDecisions":[{"question":"Auto context vs manual tabs?","recommendation":"Auto in embedded contexts; tabs on detail page.","rationale":"Games should not force users to pick PNG vs GLB."},{"question":"How many tabs visible?","recommendation":"Max 4 visible plus More menu.","rationale":"Format sprawl overwhelms collectors."},{"question":"Preview 3D in marketplace?","recommendation":"Static poster with Open 3D viewer optional.","rationale":"Auto-spin 3D hurts grid performance."}],"problemsSolved":[{"problem":"Wrong file in wrong app","oldWay":"Marketplace shows GLB broken","newWay":"Context selects PNG for marketplace, GLB for game","impact":"high"},{"problem":"One metadata URL limitation","oldWay":"Single JSON cannot serve all platforms","newWay":"Multiple assets per token with priority","impact":"high"},{"problem":"Unauthorized asset swaps","oldWay":"Metadata hijack fears","newWay":"Propose-commit acceptance for new assets","impact":"medium"}],"uxPatterns":[{"name":"Context Asset Picker","description":"Auto-render format by app context.","mockup":"concept/nft-gallery","components":["ContextResolver","AssetRenderer","FallbackImage"],"userFlow":["App loads NFT","Context detected","Best asset renders","Fallback if missing"]},{"name":"Multi-Asset Tabs","description":"Browse all accepted formats on detail.","mockup":"concept/nft-gallery","components":["AssetTabs","PreviewPane","FormatBadge"],"userFlow":["Open detail","Switch tabs","Preview each format","Optional download"]}],"seenInTheWild":[{"app":"Decentraland","url":"https://decentraland.org/","note":"3D wearables need different assets than marketplace thumbnails."},{"app":"OpenSea","url":"https://opensea.io/","note":"Media type handling for video, 3D, and HTML NFTs."},{"app":"Art Blocks","url":"https://www.artblocks.io/","note":"Generative outputs multi-format display."}],"antiPatterns":[{"pattern":"Showing GLB spin in grid thumbnails","why":"Performance collapse","instead":"Poster image in grid; 3D in viewer only","severity":"high"},{"pattern":"Displaying unaccepted proposed assets publicly","why":"Spam or malicious files shown","instead":"Owner accept gate before public","severity":"critical"},{"pattern":"Eight equal tabs with no default","why":"Decision paralysis","instead":"Context auto-pick plus optional tabs","severity":"medium"}],"vocabulary":[{"use":"3D model","avoid":"GLB asset entry","why":"Format name users know."},{"use":"Display version","avoid":"Context priority index","why":"Curatorial language."},{"use":"Accept new file","avoid":"Commit asset proposal","why":"Inbox action language."}],"onMonad":[{"aspect":"Multi-asset loading","ethereum":"Large 3D fetches slow grids","monad":"Fast network does not fix CDN — same lazy load rules","designImplication":"Lazy load all non-image assets on Monad too."},{"aspect":"Asset updates","ethereum":"Priority reorder txs costly","monad":"Cheap reorder encourages owner curation","designImplication":"Inline priority editor on Monad."}],"technicalNotes":"ERC-5773 requires context parameter on render; gate proposed assets behind owner acceptance.","relatedStandards":[{"id":"ERC-4906","relationship":"Metadata updates when assets change"},{"id":"ERC-721","relationship":"Multi-asset extension to NFT"}]},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-5773","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-5773","type":"discussion"},{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-5773","type":"official-spec"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-5773","markdown":"https://www.eipsfordesigners.com/standards/ERC-5773/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-5773/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-5773","official":"https://eips.ethereum.org/EIPS/erc-5773","discussion":"https://ethereum-magicians.org/search?q=ERC-5773"},"freshness":{"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25"}},{"id":"ERC-6150","name":"Hierarchical NFTs","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"},{"id":"management","name":"Asset Management","description":"Managing assets over time"}],"uxImpact":"Filesystem-like hierarchical NFTs — tokens have parent/child relationships like folders and files. Design implications: show folder tree navigation, display breadcrumb paths, enable create-under-parent flows, indicate root vs leaf tokens, show children count. Design decisions: max depth visualization, whether to support drag-drop reorganization, handling permission inheritance in hierarchy, folder vs file visual treatment.","hasDetailedContent":true,"content":{"id":"ERC-6150","sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-6150","type":"official-spec"}],"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25","summary":"Filesystem-like hierarchical NFTs — tokens have parent/child relationships like folders and files.","designerTakeaways":["You can show folder icon for parent tokens and file icon for leaves in tree sidebar.","Your breadcrumbs can read Collection › Season › Episode › Item for orientation.","You can offer Create inside folder with parent pre-selected in mint flow."],"applicability":{"whenToUse":["Collection has natural hierarchy — courses, seasons, albums.","Users navigate hundreds of related tokens.","Parent-child minting is on-chain."],"whenToAvoid":["Flat 10k PFP drop with no structure.","Hierarchy depth breaks mobile layout without design.","No parent id in contract."]},"prototypeFirst":[{"screen":"Tree sidebar navigation","why":"Primary navigation for hierarchical collections.","covers":["Expand folders","Select leaf","Deep path"],"include":["Tree component","Icons folder/file","Selected highlight"]},{"screen":"Breadcrumb header","why":"Deep items need path context.","covers":["3-level path","Root item"],"include":["Clickable crumbs","Truncate middle on mobile"]},{"screen":"Create under parent","why":"Creators mint into folder structure.","covers":["Pick parent","Mint child"],"include":["Parent selector","Child preview","Confirm mint"]},{"screen":"Folder detail with children grid","why":"Opening folder shows contained items.","covers":["Empty folder","Many children"],"include":["Children count","Grid of leaves","Back to parent"]}],"mentalModel":[{"label":"Root token","description":"Top of tree — collection or volume."},{"label":"Folder token","description":"Parent with children — may not be tradable art itself."},{"label":"Leaf token","description":"Item with no children — the actual collectible."},{"label":"Path","description":"Root to current token — breadcrumbs encode this."},{"label":"Inherited permissions","description":"Rules on parent may affect children — disclose if applicable."}],"statesToDesign":[{"state":"Viewing root collection","trigger":"User at tree top.","userNeed":"See top-level folders.","designResponse":"Grid or tree of root children only."},{"state":"Inside folder","trigger":"Opened parent token.","userNeed":"See children and navigate up.","designResponse":"Breadcrumb plus children grid."},{"state":"Deep leaf detail","trigger":"Selected leaf at depth 4+.","userNeed":"Know location in hierarchy.","designResponse":"Full breadcrumb; sidebar sync."},{"state":"Empty folder","trigger":"Parent with zero children.","userNeed":"Understand empty not error.","designResponse":"Empty folder illustration plus Mint here if allowed."},{"state":"Mobile depth limit","trigger":"Tree too deep for screen.","userNeed":"Still navigate.","designResponse":"Breadcrumb-only mode; sidebar as drill-down pages."}],"designDecisions":[{"question":"Max tree depth in sidebar?","recommendation":"Indent max 4 levels then breadcrumb-only.","rationale":"Mobile cannot fit deeper indents."},{"question":"Drag-drop reorganize?","recommendation":"Avoid unless contract supports; use explicit Move to folder.","rationale":"Accidental drags restructure valuable trees."},{"question":"Folder tokens tradable?","recommendation":"If yes, warn Selling folder includes N children.","rationale":"Bundle sale surprise otherwise."}],"problemsSolved":[{"problem":"Flat grid unusable for structured collections","oldWay":"1000 items one page","newWay":"Folder tree navigation","impact":"high"},{"problem":"Users lost in deep collections","oldWay":"No idea where item lives","newWay":"Breadcrumb path on every detail","impact":"medium"},{"problem":"Minting without structure","oldWay":"All tokens sibling flat","newWay":"Create under parent mint flow","impact":"medium"}],"uxPatterns":[{"name":"NFT Folder Tree","description":"Sidebar tree with folder and leaf icons.","mockup":"concept/nft-gallery","components":["TreeSidebar","FolderIcon","Breadcrumb"],"userFlow":["Open collection","Expand folders","Select item","Breadcrumb updates"]},{"name":"Create Under Parent","description":"Mint child token into selected folder.","mockup":"concept/permit-approval","components":["ParentPicker","MintForm","PathPreview"],"userFlow":["Select folder","Tap Create here","Mint child","Appears in folder"]}],"seenInTheWild":[{"app":"Google Drive","url":"https://drive.google.com/","note":"Folder tree mental model users already have."},{"app":"OpenSea","url":"https://opensea.io/","note":"Collection hierarchy patterns for large sets."},{"app":"Catalog","url":"https://catalog.works/","note":"Music NFT organization informs hierarchical browsing."}],"antiPatterns":[{"pattern":"Flat grid for 500-item hierarchical collection","why":"Unbrowseable","instead":"Tree or folder drill-down","severity":"high"},{"pattern":"Drag-drop reorg without confirm","why":"Accidental structure changes","instead":"Explicit Move with confirmation","severity":"high"},{"pattern":"No breadcrumb on deep items","why":"Disorientation","instead":"Always show path to root","severity":"medium"}],"vocabulary":[{"use":"Folder","avoid":"Parent token node","why":"Filesystem metaphor."},{"use":"Collection path","avoid":"Parent id chain","why":"Breadcrumb language."},{"use":"Create here","avoid":"Mint with parentId","why":"Creator action language."}],"onMonad":[{"aspect":"Tree loading","ethereum":"Deep tree queries slow","monad":"Fast reads enable eager tree prefetch","designImplication":"Prefetch one level of children on folder hover."},{"aspect":"Structured mints","ethereum":"Many child mints costly","monad":"Lower fees enable building deep trees on-chain","designImplication":"Bulk create-under-parent on Monad."}],"technicalNotes":"ERC-6150 hierarchy uses parent pointers; cap sidebar depth and always show breadcrumbs.","relatedStandards":[{"id":"ERC-7401","relationship":"Alternative nesting model owning child NFTs"},{"id":"ERC-721","relationship":"Hierarchical extension"}]},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-6150","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-6150","type":"discussion"},{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-6150","type":"official-spec"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-6150","markdown":"https://www.eipsfordesigners.com/standards/ERC-6150/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-6150/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-6150","official":"https://eips.ethereum.org/EIPS/erc-6150","discussion":"https://ethereum-magicians.org/search?q=ERC-6150"},"freshness":{"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25"}},{"id":"ERC-5489","name":"NFT Hyperlink Extension","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"},{"id":"specialized","name":"Specialized Interactions","description":"Physical items, AI, social, gaming"}],"uxImpact":"NFTs have authorized hyperlink slots — owners grant addresses permission to set links on their tokens. Design implications: show attached hyperlinks on NFT display, indicate slot authorization status, design slot management UI (authorize/revoke addresses), display link metadata (icon, description, target). Design decisions: how prominently to show attached links (ad-like), trust indicators for link destinations, multiple slots management complexity, authorization flow UX.","hasDetailedContent":true,"content":{"id":"ERC-5489","sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-5489","type":"official-spec"}],"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25","summary":"NFTs have authorized hyperlink slots — owners grant addresses permission to set links on their tokens.","designerTakeaways":["You can show attached links as a curated Links section with icon and description, not raw URLs.","Your owner settings can authorize or revoke addresses per slot with clear permission scope.","You can warn on external link click with destination preview before opening new tab."],"applicability":{"whenToUse":["NFTs need official links — artist site, merch, license.","Multiple parties may update different slots.","On-chain link authorization is required."],"whenToAvoid":["Metadata JSON off-chain links suffice.","No slot management in product scope.","Cannot vet link destinations safely."]},"prototypeFirst":[{"screen":"NFT links section","why":"Visitors discover official related URLs from token page.","covers":["One link","Multiple slots","Empty slots"],"include":["Link cards with icon","Description","External link icon","Empty slot placeholder"]},{"screen":"Authorize slot setter","why":"Owner delegates who can set link without transferring NFT.","covers":["Authorize","Revoke"],"include":["Slot picker","Address field","Permission summary","Revoke list"]},{"screen":"Set link as authorized party","why":"Brand or collaborator updates their slot.","covers":["Edit link","Submit"],"include":["URL field","Icon upload","Description","Preview card"]},{"screen":"External link safety interstitial","why":"Phishing risk on any clickable URL.","covers":["Leaving site warning"],"include":["Destination domain","Continue button","Report link"]}],"mentalModel":[{"label":"Hyperlink slot","description":"Fixed position on NFT for one curated link."},{"label":"Authorized setter","description":"Only listed addresses can update that slot."},{"label":"Owner control","description":"Owner grants/revokes setter permissions per slot."},{"label":"Link metadata","description":"Icon and description make links trustworthy and scannable."},{"label":"Viewer trust","description":"Links appear official because setter was authorized."}],"statesToDesign":[{"state":"Links displayed","trigger":"Slots filled.","userNeed":"Scan official resources.","designResponse":"Curated link cards below art."},{"state":"Empty slot","trigger":"Authorized but unset.","userNeed":"Owner or setter knows to fill.","designResponse":"Empty slot dashed card for authorized users only."},{"state":"Unauthorized edit attempt","trigger":"Non-setter tries update.","userNeed":"Clear block.","designResponse":"You are not authorized for this slot."},{"state":"Revoked setter","trigger":"Owner revoked address.","userNeed":"Setter knows access ended.","designResponse":"Access removed; existing link may remain until cleared per rules."},{"state":"External click","trigger":"Viewer clicks link.","userNeed":"Safe navigation.","designResponse":"Interstitial with domain highlight."}],"designDecisions":[{"question":"How prominent are links?","recommendation":"Below fold Links section, not overlay on art.","rationale":"Ad-like overlays hurt aesthetic and trust."},{"question":"Show raw URL?","recommendation":"Description primary; URL on hover or expand.","rationale":"Raw URLs look like phishing."},{"question":"Multiple slots UI?","recommendation":"Max 3 visible plus Manage slots for owner.","rationale":"Slot sprawl looks spammy."}],"problemsSolved":[{"problem":"Official links buried in metadata","oldWay":"Users never find artist site","newWay":"Structured link slots on detail page","impact":"medium"},{"problem":"Anyone could claim fake links in description","oldWay":"Scam links in off-chain metadata","newWay":"Authorized setter per slot on-chain","impact":"high"},{"problem":"Collaborators need link update without ownership","oldWay":"Transfer NFT or share keys","newWay":"Grant slot authorization to brand address","impact":"medium"}],"uxPatterns":[{"name":"Curated Link Cards","description":"Icon, description, and safe external open.","mockup":"concept/nft-gallery","components":["LinkCard","DomainPreview","ExternalIcon"],"userFlow":["View NFT","See links section","Click card","Interstitial","Opens site"]},{"name":"Slot Authorization Panel","description":"Owner grants/revokes link setters per slot.","mockup":"concept/verify-safety","components":["SlotList","AuthorizeForm","RevokeButton"],"userFlow":["Owner opens settings","Picks slot","Authorizes address","Setter can edit link"]}],"seenInTheWild":[{"app":"OpenSea","url":"https://opensea.io/","note":"External links section on collection pages."},{"app":"Zora","url":"https://zora.co/","note":"Creator profile links on token pages."},{"app":"Foundation","url":"https://foundation.app/","note":"Artist attribution and link patterns."}],"antiPatterns":[{"pattern":"Banner ads overlaying NFT art","why":"Destroys aesthetic; feels scammy","instead":"Links section below art","severity":"high"},{"pattern":"Direct open with no domain preview","why":"Phishing via authorized compromised setter","instead":"Interstitial showing destination domain","severity":"critical"},{"pattern":"Ten link slots equally prominent","why":"Link farm appearance","instead":"Cap visible slots; manage overflow in settings","severity":"medium"}],"vocabulary":[{"use":"Official links","avoid":"Hyperlink slots","why":"Curatorial not technical."},{"use":"Allow [brand] to update link","avoid":"Authorize slot setter","why":"Permission plain language."},{"use":"You are leaving for [domain]","avoid":"External URI navigation","why":"Safety interstitial copy."}],"onMonad":[{"aspect":"Link updates","ethereum":"Slot edits cost gas","monad":"Cheap updates encourage fresh official links","designImplication":"Inline link edit for authorized setters on Monad."},{"aspect":"Click-through safety","ethereum":"Same interstitial need","monad":"Same — speed does not reduce phishing risk","designImplication":"Always show domain interstitial on Monad."}],"technicalNotes":"ERC-5489 slot authorization is per-address; use link interstitials for all external opens.","relatedStandards":[{"id":"ERC-721","relationship":"Hyperlink extension on NFTs"},{"id":"ERC-5521","relationship":"Reference graph complements outbound links"}]},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-5489","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-5489","type":"discussion"},{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-5489","type":"official-spec"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-5489","markdown":"https://www.eipsfordesigners.com/standards/ERC-5489/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-5489/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-5489","official":"https://eips.ethereum.org/EIPS/erc-5489","discussion":"https://ethereum-magicians.org/search?q=ERC-5489"},"freshness":{"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25"}},{"id":"ERC-5521","name":"Referable NFT","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"},{"id":"management","name":"Asset Management","description":"Managing assets over time"}],"uxImpact":"NFTs can reference other NFTs — creating a directed graph of relationships (remixes, derivatives, citations). Design implications: show 'References' and 'Referenced By' lists, visualize reference graph/network, indicate derivative relationships, display creation timestamps for ordering. Design decisions: graph visualization complexity, how deep to show reference chains, handling cross-contract references, attribution/citation display format.","hasDetailedContent":true,"content":{"id":"ERC-5521","sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-5521","type":"official-spec"}],"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25","summary":"NFTs can reference other NFTs — creating a directed graph of relationships (remixes, derivatives, citations).","designerTakeaways":["You can show References and Referenced by lists on every derivative NFT detail page.","Your graph view can limit depth to 2 hops with View full graph for explorers.","You can link cross-contract references to correct collection with verification badge."],"applicability":{"whenToUse":["Remix and derivative culture is core to product.","On-chain citation between tokens matters.","Attribution disputes need transparent lineage."],"whenToAvoid":["Flat unrelated collectibles.","Graph would have single node always.","Indexer cannot resolve cross-contract refs."]},"prototypeFirst":[{"screen":"Reference lists on detail","why":"Default view for lineage without graph complexity.","covers":["Has references","Referenced by others","None"],"include":["References list with thumbs","Referenced by list","Tap to navigate"]},{"screen":"Lineage graph preview","why":"Visual learners see remix tree.","covers":["2-hop graph","Deep graph"],"include":["Mini graph","Expand to full screen","Depth limit label"]},{"screen":"Cross-contract reference link","why":"References span collections.","covers":["Same chain ref","Broken ref"],"include":["Collection name","Verify resolved","Broken link message"]},{"screen":"Remix creation flow","why":"Minter selects parent references at create.","covers":["Pick references","Confirm lineage"],"include":["Reference picker","Preview lineage","Mint with refs"]}],"mentalModel":[{"label":"Reference","description":"This token points to sources it derives from."},{"label":"Referenced by","description":"Other tokens point here — downstream derivatives."},{"label":"Directed graph","description":"Edges one-way — remix points to original, not always reverse indexed automatically."},{"label":"Cross-contract","description":"Reference may be different collection address — link must resolve both."},{"label":"Timestamp ordering","description":"Creation time orders citation chronology."}],"statesToDesign":[{"state":"Has references only","trigger":"Derivative of others.","userNeed":"See sources.","designResponse":"References list prominent."},{"state":"Referenced by many","trigger":"Popular original.","userNeed":"Discover derivatives.","designResponse":"Referenced by with count and preview thumbs."},{"state":"Graph expanded","trigger":"User opens full graph.","userNeed":"Explore without overwhelm.","designResponse":"Pan/zoom with depth filter."},{"state":"Broken reference","trigger":"Burned or invalid ref.","userNeed":"Not broken UI.","designResponse":"Reference unavailable gray node."},{"state":"No references","trigger":"Original work.","userNeed":"Still see if referenced by others.","designResponse":"Original badge; Referenced by if any."}],"designDecisions":[{"question":"Graph or lists default?","recommendation":"Lists default; graph optional expand.","rationale":"Graph overwhelms casual collectors."},{"question":"Max graph depth?","recommendation":"2 hops default; slider to 4 max.","rationale":"Citation chains explode combinatorially."},{"question":"Citation format?","recommendation":"Remixed from [thumb] [name] with date.","rationale":"Academic citation too cold for art."}],"problemsSolved":[{"problem":"Remix attribution disputes","oldWay":"He-said she-said off-chain","newWay":"On-chain reference list on token","impact":"high"},{"problem":"Discovering derivative works","oldWay":"Manual search","newWay":"Referenced by index on originals","impact":"medium"},{"problem":"Cross-collection lineage invisible","oldWay":"Refs only in metadata text","newWay":"Resolvable cross-contract reference links","impact":"medium"}],"uxPatterns":[{"name":"Reference Lineage Lists","description":"References and Referenced by on detail.","mockup":"concept/nft-gallery","components":["ReferenceList","ThumbRow","DateLabel"],"userFlow":["Open NFT","See references","Tap source","Navigate to parent"]},{"name":"Remix Graph Explorer","description":"Optional 2-hop visual graph.","mockup":"concept/reactions","components":["GraphCanvas","DepthControl","NodeCard"],"userFlow":["Tap View graph","See 2-hop","Expand depth","Tap node to open"]}],"seenInTheWild":[{"app":"Sound.xyz","url":"https://www.sound.xyz/","note":"Musical remix lineage and attribution patterns."},{"app":"Zora","url":"https://zora.co/","note":"Creator remix culture on-chain."},{"app":"Foundation","url":"https://foundation.app/","note":"Artist attribution on secondary works."}],"antiPatterns":[{"pattern":"Full graph as only view","why":"Casual users bounce","instead":"Lists first; graph optional","severity":"high"},{"pattern":"Unbounded graph depth render","why":"Browser hang","instead":"Depth limit with expand control","severity":"critical"},{"pattern":"Broken refs shown as active links","why":"404 confusion","instead":"Reference unavailable state","severity":"medium"}],"vocabulary":[{"use":"Remixed from","avoid":"Reference array entry","why":"Creative attribution language."},{"use":"Derivatives","avoid":"Referenced-by subgraph","why":"Collector-friendly term."},{"use":"View lineage","avoid":"Open citation graph","why":"Discovery action language."}],"onMonad":[{"aspect":"Graph indexing","ethereum":"Cross-contract graph slow to build","monad":"Fast indexing enables snappier lineage loads","designImplication":"Prefetch references on detail hover on Monad."},{"aspect":"Remix mints","ethereum":"Reference-heavy mints gas costly","monad":"Lower cost encourages on-chain citation at mint","designImplication":"Reference picker in mint flow on Monad."}],"technicalNotes":"ERC-5521 graph UI needs depth limits; resolve cross-contract refs before showing links.","relatedStandards":[{"id":"ERC-5489","relationship":"Outbound links complement reference graph"},{"id":"ERC-721","relationship":"Referable extension"}]},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-5521","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-5521","type":"discussion"},{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-5521","type":"official-spec"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-5521","markdown":"https://www.eipsfordesigners.com/standards/ERC-5521/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-5521/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-5521","official":"https://eips.ethereum.org/EIPS/erc-5521","discussion":"https://ethereum-magicians.org/search?q=ERC-5521"},"freshness":{"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25"}},{"id":"ERC-20","name":"Token Standard","status":"Final","chain":"both","category":{"id":"defi","name":"DeFi Patterns","description":"Vaults, bonds, and financial primitives"},"journeyStages":[{"id":"asset-display","name":"Asset Discovery & Display","description":"Seeing tokens, NFTs, and balances"}],"uxImpact":"Users experience token balances as simple numbers with transfer and approval mechanics — the foundation of all DeFi. Design implications: always show token symbol + decimals-adjusted balances, display allowance amounts before swap/stake actions, implement two-step approval flows (approve then execute) or use permit for gasless approvals, show pending approval transactions distinctly. Design decisions: whether to show infinite approvals as 'Unlimited' vs actual large number, whether to prompt users to revoke old approvals, how to handle the approve-to-zero-first pattern for tokens that require it.","hasDetailedContent":true,"content":{"id":"ERC-20","summary":"ERC-20 defines how fungible tokens work on Ethereum. Every USDC, USDT, UNI, and most other tokens follow this standard. It specifies balances, transfers, and approvals — the basic building blocks that let any wallet show your tokens and any DEX swap them. It's the most widely implemented standard in crypto.","designerTakeaways":["You can show balances using each token decimals, never raw uint256 values.","You can default approvals to the exact spend for this action, not unlimited.","You can add an approvals screen where users review and revoke active spenders."],"applicability":{"whenToUse":["Wallets or apps display fungible token balances, sends, or swaps.","DEX, lending, or payment flows need approve + transferFrom.","You integrate contracts that assume the universal ERC-20 interface."],"whenToAvoid":["Each asset must be unique by id (use ERC-721 or ERC-1155).","Users only move native chain currency with no token layer.","Tokens are non-transferable or soulbound with no standard wallet UX."]},"designDecisions":[{"question":"What is the default approval amount?","recommendation":"Default to the exact amount needed for the current action; make unlimited opt-in with a warning.","rationale":"Unlimited approvals are the top theft vector when spenders are compromised."},{"question":"How do you show token amounts?","recommendation":"Always apply decimals() before display; never show raw uint256 values.","rationale":"Wrong decimals misstate balances and break trust at confirmation time."},{"question":"Do users get an approvals management surface?","recommendation":"Provide a list of active allowances with revoke actions and risk labels.","rationale":"Users cannot clean up risky approvals they granted months ago without this UI."},{"question":"How does MAX behave for the gas token?","recommendation":"Reserve a small buffer when the ERC-20 is also used to pay gas on that chain.","rationale":"Send-max otherwise fails when the wallet needs leftover balance for fees."}],"statesToDesign":[{"state":"Balance loading","trigger":"Token list or balance query is in flight.","userNeed":"Know whether funds are still syncing.","designResponse":"Skeleton rows; avoid showing zero until the query settles."},{"state":"Insufficient balance","trigger":"User enters more than wallet balance.","userNeed":"Understand why send or swap is blocked.","designResponse":"Inline error with max available and a one-tap fill-max that respects gas reserve."},{"state":"Approval required","trigger":"Spender allowance is lower than the action amount.","userNeed":"Understand why an extra step appears before swap.","designResponse":"Explain approval in plain language with amount strategy choices."},{"state":"Unlimited allowance active","trigger":"User views approvals or connects to a high-risk spender.","userNeed":"See elevated risk clearly.","designResponse":"Warning badge on unlimited rows; offer revoke and safer limited re-approval."},{"state":"Transfer pending","trigger":"transfer() submitted but not finalized.","userNeed":"Track progress without refreshing.","designResponse":"Pending row with explorer link; update balance on confirmation."}],"problemsSolved":[{"problem":"Every token had different interfaces","oldWay":"Each token contract did things differently, wallets couldn't support them all","newWay":"Standard interface: any ERC-20 works in any wallet/DEX automatically","impact":"critical"},{"problem":"No standard way to check balances","oldWay":"Each token invented its own balance function","newWay":"balanceOf(address) works the same everywhere","impact":"critical"},{"problem":"Approving contracts to spend tokens was inconsistent","oldWay":"Random approval mechanisms, security risks","newWay":"approve() + transferFrom() pattern is universal","impact":"high"},{"problem":"Token metadata (name, symbol) not standardized","oldWay":"Some had name(), some had getName(), some had nothing","newWay":"name(), symbol(), decimals() everywhere","impact":"medium"}],"uxPatterns":[{"name":"Token Balance Display","description":"Show user's token holdings with proper formatting","mockup":"generic/balance-display","userFlow":["App queries known token contracts","Calls balanceOf(userAddress) on each","Applies decimals for human-readable amounts","Fetches price data for fiat conversion","Displays formatted list"]},{"name":"Token Approval Flow","description":"Let user approve token spending with clear limits","mockup":"generic/token-approval","userFlow":["DEX detects insufficient allowance","Shows approval modal","User selects amount strategy","Calls approve(spender, amount)","User signs transaction","Allowance updated"]},{"name":"Token Transfer","description":"Simple send tokens to another address","mockup":"generic/token-transfer","userFlow":["User enters recipient (address or ENS)","Enters amount","App validates against balance","Shows fee estimate","User confirms send","Calls transfer(to, amount)"]},{"name":"Allowance Management","description":"View and revoke token approvals","mockup":"generic/token-approval","userFlow":["User opens approvals page","App scans Approval events","Shows all active allowances","Highlights risky (unlimited, unknown)","User can revoke individually or batch"]}],"uiComponents":[{"name":"TokenBalanceDisplay","description":"Shows token amount with proper decimal formatting","states":["loading","loaded","zero","error"],"props":["balance","decimals","symbol","showFiat","price"]},{"name":"TokenAmountInput","description":"Input field for token amounts with MAX button","states":["empty","valid","exceeds-balance","invalid"],"props":["value","max","decimals","onChange"]},{"name":"ApprovalSelector","description":"Choose approval amount strategy","states":["exact","unlimited","custom"],"props":["suggestedAmount","onSelect"]},{"name":"AllowanceDisplay","description":"Shows current approval amount for a spender","states":["loading","none","limited","unlimited"],"props":["token","spender","amount"]},{"name":"TokenSelector","description":"Dropdown/modal to select from available tokens","states":["closed","open","searching","selected"],"props":["tokens[]","selected","onSelect"]}],"antiPatterns":[{"pattern":"Defaulting to unlimited approvals","why":"Exposes user to maximum risk if contract is compromised","instead":"Default to exact amount needed, make unlimited opt-in","severity":"critical"},{"pattern":"Not checking decimals before displaying","why":"USDC has 6 decimals, ETH has 18; wrong math = wrong amounts shown","instead":"Always fetch and apply token's decimals()","severity":"critical"},{"pattern":"Showing raw uint256 values to users","why":"\"1000000000000000000\" is 1 ETH, not a billion ETH","instead":"Always format with decimals: ethers.formatUnits()","severity":"critical"},{"pattern":"No allowance management UI","why":"Users have no way to see or revoke old approvals","instead":"Provide approvals page with revoke functionality","severity":"high"},{"pattern":"Not explaining what approval means","why":"Users approve without understanding the risk","instead":"Clear explanation: \"This lets them transfer without asking\"","severity":"high"},{"pattern":"MAX button without dust accounting","why":"Sending MAX may fail if gas is needed from same balance","instead":"Reserve small amount for gas when token is gas token","severity":"medium"}],"onMonad":[{"aspect":"Transfer Confirmation","ethereum":"Transfer takes 12+ seconds to confirm","monad":"Sub-second finality","designImplication":"Balance updates feel instant"},{"aspect":"Approval Transactions","ethereum":"Approve is a separate transaction, costs gas","monad":"Same but cheaper; consider ERC-2612 permit pattern","designImplication":"Batch approve + action via 7702 when possible"},{"aspect":"Reserve Balance","ethereum":"Can transfer entire balance","monad":"10 MON reserve required for async execution safety","designImplication":"MAX button should account for reserve"},{"aspect":"Token List","ethereum":"Token lists are chain-specific","monad":"Monad-specific tokens exist alongside bridged","designImplication":"Show chain badge on tokens when multi-chain"}],"keyTakeaways":["ERC-20 is the universal token standard","ALWAYS check decimals() before displaying amounts","Default to exact approval amounts, not unlimited","Provide allowance management UI","Format amounts for humans, store raw for contracts"],"technicalNotes":"ERC-20 specifies 6 functions (totalSupply, balanceOf, transfer, allowance, approve, transferFrom) and 2 events (Transfer, Approval). Optional: name(), symbol(), decimals(). Decimals is typically 18 but varies (USDC = 6). Always check. Approval pattern: user approves spender for X tokens, spender can then transferFrom. Common extensions: ERC-2612 (permit), ERC-1363 (payable)."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-20","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-20","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-20","markdown":"https://www.eipsfordesigners.com/standards/ERC-20/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-20/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-20","official":"https://eips.ethereum.org/EIPS/eip-20","discussion":"https://ethereum-magicians.org/search?q=ERC-20"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"ERC-4626","name":"Tokenized Vaults","status":"Final","chain":"both","category":{"id":"defi","name":"DeFi Patterns","description":"Vaults, bonds, and financial primitives"},"journeyStages":[{"id":"management","name":"Asset Management","description":"Managing assets over time"}],"uxImpact":"Users deposit assets into yield-generating vaults and receive shares representing their proportional ownership — standardized DeFi yield. Design implications: show both share balance AND underlying asset value side-by-side, display real-time APY/yield earned, use previewDeposit/previewRedeem to show exact conversion rates before transactions, indicate deposit/withdrawal limits via maxDeposit/maxWithdraw, show fees transparently (entry/exit/management). Design decisions: whether to default UI to 'assets' or 'shares' view, how to represent slippage between preview and actual execution, whether to show historical yield vs projected yield, handling vaults with transfer restrictions.","hasDetailedContent":true,"content":{"id":"ERC-4626","summary":"ERC-4626 standardizes yield-bearing vaults. Deposit tokens, receive shares that grow in value. Whether it's Aave, Yearn, or Compound — same interface: deposit(), withdraw(), shares, assets. Users learn one pattern and can use any vault. Wallets can show all vault positions uniformly.","applicability":{"whenToUse":["Users deposit into yield vaults and need share-to-asset value clarity.","Your product lists vault positions from multiple protocols with one pattern.","Deposit and withdraw previews must show expected assets after fees."],"whenToAvoid":["Yield is informational only with no deposit or withdraw actions.","Each vault uses a bespoke API you cannot normalize to ERC-4626.","Users never see share balances or underlying asset equivalence."]},"designerTakeaways":["You can show vault value in assets users understand, not opaque share units.","You can reuse one deposit and withdraw flow across Aave, Yearn, and similar vaults.","You can label fees and post-deposit value so yield feels earned, not magical."],"designDecisions":[{"question":"Do you show shares, assets, or both?","recommendation":"Lead with asset value (USDC); expose share count in advanced details.","rationale":"Users think in deposits and dollar value, not internal share units."},{"question":"How is APY presented?","recommendation":"Label as estimated APY with source and update time.","rationale":"Vault yields change; over-precise APY feels guaranteed."},{"question":"What does withdraw preview include?","recommendation":"Show assets out, shares burned, and any delay or fee.","rationale":"Withdrawals can be async or penalized; surprises cause support load."},{"question":"How do you handle insolvency or pause?","recommendation":"Block deposit/withdraw with protocol-specific reason, not generic errors.","rationale":"Vault pauses are common; users need to know funds are safe but gated."}],"statesToDesign":[{"state":"Deposit preview","trigger":"User enters deposit amount.","userNeed":"Know expected shares and post-deposit balance.","designResponse":"Show assets in, estimated shares, and current exchange rate."},{"state":"Withdraw preview","trigger":"User enters withdraw amount.","userNeed":"Know assets received and timing.","designResponse":"Assets out, shares burned, cooldown if applicable."},{"state":"Position accruing","trigger":"Share price increases over time.","userNeed":"See earnings without manual refresh.","designResponse":"Live asset value; optional earned since deposit metric."},{"state":"Insufficient liquidity","trigger":"Vault cannot fulfill full withdraw instantly.","userNeed":"Queue or partial withdraw path.","designResponse":"Explain delay, queue position, or max instant amount."},{"state":"Vault paused","trigger":"Protocol pauses deposits or withdrawals.","userNeed":"Understand funds are locked temporarily.","designResponse":"Banner with reason link; disable actions with explanation."}],"problemsSolved":[{"problem":"Every DeFi protocol has different vault interface","oldWay":"Aave: deposit(), Yearn: stake(), Compound: mint() — all different","newWay":"Standard deposit/withdraw interface everywhere","impact":"critical"},{"problem":"Hard to calculate actual value of vault shares","oldWay":"Each vault has custom math for share→asset conversion","newWay":"convertToAssets(shares) and convertToShares(assets) standard","impact":"high"},{"problem":"Can't aggregate vault positions across protocols","oldWay":"Custom integration for each vault type","newWay":"One interface queries any ERC-4626 vault","impact":"high"}],"uxPatterns":[{"name":"Vault Deposit","description":"Standard deposit flow with share preview","mockup":"generic/vault-deposit","userFlow":["User enters deposit amount","App calls convertToShares(assets)","Shows expected share amount","Displays current exchange rate","User confirms deposit"]},{"name":"Vault Position","description":"Show current position with earnings","mockup":"generic/vault-position","userFlow":["User views positions","App queries share balances","Calls convertToAssets for value","Calculates earnings vs deposit","Shows profit/loss"]},{"name":"Withdraw Flow","description":"Redeem shares for underlying assets","mockup":"generic/vault-position","userFlow":["User chooses withdraw mode","Enter shares OR assets amount","App calculates other side","Shows shares to burn","User confirms withdrawal"]}],"uiComponents":[{"name":"VaultCard","description":"Summary of a vault position","states":["no-position","deposited","earning","losing"],"props":["vault","shares","assets","apy"]},{"name":"ShareAssetConverter","description":"Input that converts between shares and assets","states":["shares-mode","assets-mode"],"props":["shares","assets","exchangeRate","onChange"]},{"name":"APYIndicator","description":"Shows vault annual percentage yield","states":["positive","negative","loading"],"props":["apy","timeframe"]},{"name":"EarningsDisplay","description":"Shows profit/loss vs deposited amount","states":["profit","loss","break-even"],"props":["deposited","currentValue","earned"]}],"antiPatterns":[{"pattern":"Only showing share balance","why":"\"952.38 yvUSDC\" means nothing without conversion","instead":"Always show asset value: \"952.38 yvUSDC (~$1,050)\"","severity":"critical"},{"pattern":"Not explaining share price changes","why":"Users confused when share count doesn't match deposits","instead":"Explain: \"You deposited $1000, now worth $1050\"","severity":"high"},{"pattern":"Hiding withdrawal fees/slippage","why":"User expects $1000, gets $950","instead":"Show expected output AFTER fees clearly","severity":"critical"},{"pattern":"Not showing historical earnings","why":"Users can't see if vault is performing well","instead":"Track and display total earned over time","severity":"medium"}],"onMonad":[{"aspect":"Deposit Confirmation","ethereum":"Deposit takes 12+ seconds","monad":"Sub-second deposit confirmation","designImplication":"Position updates instantly"},{"aspect":"Yield Updates","ethereum":"Yield accrues per block (12s)","monad":"More frequent yield updates","designImplication":"Can show real-time yield accumulation"},{"aspect":"Reserve Consideration","ethereum":"Can deposit entire balance","monad":"10 MON reserve required for async execution safety","designImplication":"MAX deposit should subtract reserve"}],"keyTakeaways":["ERC-4626 = standard vault interface","ALWAYS show asset value, not just share balance","Provide both deposit-by-assets and withdraw-by-assets","Show earnings vs deposited amount clearly","Display fees/slippage before withdrawal"],"technicalNotes":"ERC-4626 extends ERC-20 (shares are tokens). Key functions: deposit(assets, receiver), mint(shares, receiver), withdraw(assets, receiver, owner), redeem(shares, receiver, owner). View functions: convertToShares, convertToAssets, previewDeposit, previewMint, previewWithdraw, previewRedeem, maxDeposit, maxMint, maxWithdraw, maxRedeem."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-4626","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-4626","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-4626","markdown":"https://www.eipsfordesigners.com/standards/ERC-4626/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-4626/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-4626","official":"https://eips.ethereum.org/EIPS/eip-4626","discussion":"https://ethereum-magicians.org/search?q=ERC-4626"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"ERC-7535","name":"Native Asset ERC-4626 Vault","status":"Draft","chain":"both","category":{"id":"defi","name":"DeFi Patterns","description":"Vaults, bonds, and financial primitives"},"journeyStages":[{"id":"management","name":"Asset Management","description":"Managing assets over time"}],"uxImpact":"Users can deposit native ETH directly into 4626-compatible vaults without wrapping to WETH first — simpler onboarding for liquid staking. Design implications: show ETH balance directly in vault deposit UI, use msg.value for deposits (no approval step needed), handle excess ETH refunds gracefully, display the special 0xEeee...EEeE address as 'ETH' not an address. Design decisions: whether to offer WETH alternative path, how to communicate the gas cost difference vs WETH vaults, handling the edge case where assets parameter may be ignored in favor of msg.value.","hasDetailedContent":true,"content":{"id":"ERC-7535","summary":"ERC-7535 extends the ERC-4626 vault standard to accept native assets (ETH) directly without requiring users to wrap them first. Users can deposit ETH straight into yield vaults, skipping the WETH wrapping step that adds friction and confusion to DeFi onboarding.","applicability":{"whenToUse":["Your users must wrap ETH to WETH before depositing.","Your product addresses: new users don't understand WETH.","The flow should deliver: eTH → deposit directly (1 step).","You are designing a direct eth deposit experience with visible states and recovery paths."],"whenToAvoid":["Hide wrapping entirely, deposit ETH directly.","Skip approval step entirely for ETH deposits.","Default to ETH, show WETH as alternative option.","No token balances, swaps, lending, or yield flows appear in the product."]},"designerTakeaways":["You can design UI that delivers eTH → deposit directly (1 step).","You can design UI that delivers deposit ETH, get shares. No wrapper tokens to explain.","You can design UI that delivers direct deposit saves wrapping gas entirely."],"problemsSolved":[{"problem":"Users must wrap ETH to WETH before depositing","oldWay":"ETH → approve → wrap to WETH → approve again → deposit to vault (4 steps)","newWay":"ETH → deposit directly (1 step)","impact":"critical"},{"problem":"New users don't understand WETH","oldWay":"\"What is WETH? Why do I need it? Where did my ETH go?\"","newWay":"Deposit ETH, get shares. No wrapper tokens to explain","impact":"critical"},{"problem":"Extra gas costs for wrapping","oldWay":"Wrapping costs ~45k gas, plus approval costs","newWay":"Direct deposit saves wrapping gas entirely","impact":"medium"},{"problem":"Fragmented ETH balance","oldWay":"Users have ETH + WETH + vault shares, confusing portfolio","newWay":"ETH → vault shares directly, cleaner balance view","impact":"medium"}],"uxPatterns":[{"name":"Direct ETH Deposit","description":"One-step deposit of native ETH into vault","mockup":"generic/vault-deposit","userFlow":["User enters ETH amount to deposit","Preview shows expected vault shares","Click deposit (no approve step)","Sign single transaction","ETH converts to vault shares directly"]},{"name":"Unified Deposit Interface","description":"Accept both ETH and WETH with same UI","mockup":"generic/vault-deposit","userFlow":["User chooses between ETH or WETH","Show approval requirements for each","ETH path is faster (no approval)","WETH accepted for users with existing balance","Same vault shares regardless of input"]},{"name":"Native Withdrawal","description":"Withdraw back to ETH directly","mockup":"generic/vault-position","userFlow":["User sees current position and earnings","Select withdrawal amount","Choose ETH or WETH output","Sign withdrawal transaction","Receive ETH directly to wallet"]}],"uiComponents":[{"name":"NativeAssetInput","description":"Input field that handles native ETH amounts","states":["empty","valid","insufficient","max"],"props":["balance","value","onChange","onMax"]},{"name":"AssetToggle","description":"Switch between ETH and WETH","states":["eth-selected","weth-selected"],"props":["ethBalance","wethBalance","onSelect"]},{"name":"VaultSharesPreview","description":"Show expected shares from deposit","states":["loading","ready","slippage-warning"],"props":["inputAmount","expectedShares","exchangeRate"]},{"name":"NoApprovalBadge","description":"Indicate no approval needed for native asset","states":["native","needs-approval","approved"],"props":["assetType","approvalStatus"]}],"antiPatterns":[{"pattern":"Still showing WETH wrapping in the UI","why":"Defeats the purpose of native asset support","instead":"Hide wrapping entirely, deposit ETH directly","severity":"critical"},{"pattern":"Requiring approval for ETH deposits","why":"Native ETH doesn't need approval - confuses users","instead":"Skip approval step entirely for ETH deposits","severity":"critical"},{"pattern":"Defaulting to WETH over ETH","why":"ETH is more familiar to users, WETH adds confusion","instead":"Default to ETH, show WETH as alternative option","severity":"high"},{"pattern":"Not showing \"no approval needed\" benefit","why":"Users don't realize ETH deposit is simpler","instead":"Highlight \"✓ No approval needed\" for ETH path","severity":"medium"}],"onMonad":[{"aspect":"Native Asset","ethereum":"ETH is the native asset","monad":"MON is the native asset","designImplication":"Update UI to show MON deposits, same UX pattern applies"},{"aspect":"Deposit Speed","ethereum":"Deposit takes 12-15 seconds to confirm","monad":"Sub-second finality, shares appear instantly","designImplication":"Can show shares balance updating in real-time"},{"aspect":"Gas Savings","ethereum":"Avoiding WETH wrap saves ~45k gas (~$5-20)","monad":"Gas already cheap, but still saves a transaction step","designImplication":"Emphasize simplicity over gas savings"},{"aspect":"Reserve Balance","ethereum":"Can deposit entire ETH balance","monad":"Must keep 10 MON reserve, adjust MAX button","designImplication":"MAX button should account for reserve: show \"Max: X MON (10 MON reserved)\""}],"keyTakeaways":["Native asset vaults eliminate the confusing WETH step","ETH deposits need no approval - highlight this benefit","Default to native asset, offer wrapped as alternative","Show clear \"You'll receive X shares\" preview","On Monad: account for reserve balance in MAX calculations"],"technicalNotes":"ERC-7535 extends ERC-4626 by adding receive() and depositETH() functions. The vault accepts msg.value as the deposit amount for native assets. Internally, vaults may still use WETH for accounting, but this is abstracted away from users. The standard maintains full compatibility with ERC-4626 for wrapped asset deposits."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-7535","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-7535","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-7535","markdown":"https://www.eipsfordesigners.com/standards/ERC-7535/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-7535/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-7535","official":"https://eips.ethereum.org/EIPS/eip-7535","discussion":"https://ethereum-magicians.org/search?q=ERC-7535"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"ERC-7540","name":"Asynchronous ERC-4626 Vaults","status":"Draft","chain":"both","category":{"id":"defi","name":"DeFi Patterns","description":"Vaults, bonds, and financial primitives"},"journeyStages":[{"id":"management","name":"Asset Management","description":"Managing assets over time"}],"uxImpact":"Users request deposits/withdrawals that process asynchronously over time — necessary for RWA, cross-chain, and illiquid strategies. Design implications: design three-state UI (Pending → Claimable → Claimed), show estimated wait times, display pending request status prominently, add 'Claim' button that appears when requests become claimable, remove instant preview quotes (previewDeposit/Redeem revert). Design decisions: whether to show queue position, how to communicate yield accrual during pending state, whether to allow request cancellation if protocol supports it, notification strategy for when claims become available.","hasDetailedContent":true,"content":{"id":"ERC-7540","summary":"ERC-7540 adds asynchronous deposit and redemption to ERC-4626 vaults. Instead of instant deposits/withdrawals, users submit requests that are fulfilled later. This enables vaults with real-world assets, illiquid investments, or settlement delays to use the standard vault interface while being honest about timing.","applicability":{"whenToUse":["Your users expect instant withdrawal but vault has illiquid assets.","Your product addresses: real-world asset vaults can't use ERC-4626.","Your UI should clear \"request → wait → claim\" flow sets proper expectations.","You are designing a request-wait-claim flow experience with visible states and recovery paths."],"whenToAvoid":["Show settlement timeline BEFORE they submit request.","Show percentage progress and estimated time remaining.","Notify user and let them claim when ready.","No token balances, swaps, lending, or yield flows appear in the product."]},"designerTakeaways":["You can clear \"request → wait → claim\" flow sets proper expectations in the interface.","You can standardized async interface works for RWA vaults.","You can design UI that delivers trackable request status with estimated completion."],"problemsSolved":[{"problem":"Users expect instant withdrawal but vault has illiquid assets","oldWay":"Transaction reverts with confusing error, or vault has exit penalties","newWay":"Clear \"request → wait → claim\" flow sets proper expectations","impact":"critical"},{"problem":"Real-world asset vaults can't use ERC-4626","oldWay":"Custom vault interfaces, each with different UX","newWay":"Standardized async interface works for RWA vaults","impact":"high"},{"problem":"Users don't know when their withdrawal will complete","oldWay":"Vague \"processing\" messages with no timeline","newWay":"Trackable request status with estimated completion","impact":"high"},{"problem":"No standard way to show pending positions","oldWay":"Each vault has custom UI for pending deposits/withdrawals","newWay":"Standardized pending request queries enable consistent UI","impact":"medium"}],"uxPatterns":[{"name":"Request-Wait-Claim Flow","description":"Three-phase withdrawal with clear status at each stage","mockup":"generic/vault-deposit","userFlow":["User submits withdrawal request","System shows pending status with timeline","User can track request progress","Notification when claimable","User claims when ready"]},{"name":"Pending Requests Dashboard","description":"Overview of all pending deposits and withdrawals","mockup":"concept/tx-status","userFlow":["User views dashboard of pending requests","Each request shows progress and timeline","Ready requests have prominent claim button","Completed requests move to history"]},{"name":"Async Deposit Flow","description":"Deposit with delayed share minting","mockup":"generic/vault-deposit","userFlow":["User enters deposit amount","Show clear settlement timeline","User understands it's not instant","Submit request locks funds","Track progress until claimable","Claim shares when ready"]},{"name":"Request Cancellation","description":"Allow users to cancel pending requests when possible","mockup":"concept/tx-status","userFlow":["User wants to cancel pending request","Check if still in cancellation window","Show deadline for cancellation","Confirm cancellation","Funds returned to original state"]}],"uiComponents":[{"name":"RequestProgressStepper","description":"Visual progress through request → wait → claim","states":["requested","processing","claimable","claimed"],"props":["currentStep","estimatedTime","requestId"]},{"name":"PendingRequestCard","description":"Card showing single pending request details","states":["pending","processing","ready","claiming"],"props":["requestType","amount","vault","progress","eta"]},{"name":"SettlementTimeline","description":"Visual timeline of settlement process","states":["upcoming","in-progress","completed"],"props":["steps[]","currentStep","estimatedDates"]},{"name":"ClaimableAlert","description":"Notification that request is ready to claim","states":["ready","claiming","claimed"],"props":["requestId","amount","vaultName","onClaim"]}],"antiPatterns":[{"pattern":"Hiding that deposits/withdrawals are async","why":"Users expect instant fulfillment, feel trapped when delayed","instead":"Show settlement timeline BEFORE they submit request","severity":"critical"},{"pattern":"No progress updates while waiting","why":"Users anxious about their funds, support tickets","instead":"Show percentage progress and estimated time remaining","severity":"high"},{"pattern":"Auto-claiming without user action","why":"User may want control over when shares/assets enter wallet","instead":"Notify user and let them claim when ready","severity":"high"},{"pattern":"Using DeFi-instant language for async vaults","why":"\"Deposit\" implies instant, misleading for async","instead":"Use \"Request Deposit\" or \"Submit Request\" language","severity":"medium"}],"onMonad":[{"aspect":"Transaction Speed","ethereum":"Request submission takes 15+ seconds","monad":"Request confirms in under 1 second","designImplication":"Even async vaults feel snappier at request step"},{"aspect":"Checking Status","ethereum":"Polling for status updates is expensive","monad":"Cheap reads enable real-time status updates","designImplication":"Can show live progress bar updating"},{"aspect":"Claim Transaction","ethereum":"Claiming has typical 15s+ wait","monad":"Instant claim confirmation","designImplication":"Claim feels instant even if request was async"},{"aspect":"Multiple Requests","ethereum":"Managing multiple requests expensive","monad":"Cheap transactions enable request management","designImplication":"Can offer batch claim and request modifications"}],"keyTakeaways":["Async vaults need clear Request → Wait → Claim flow","Show settlement timeline BEFORE user commits","Provide trackable progress with time estimates","Notify users when requests become claimable","On Monad: fast finality makes request/claim steps instant"],"technicalNotes":"ERC-7540 extends ERC-4626 with requestDeposit(), requestRedeem(), pendingDepositRequest(), and claimableDepositRequest() functions. Requests return a request ID that users track. Vaults can implement their own settlement logic - from instant (mimicking sync vaults) to multi-day delays for RWA. The standard maintains share price integrity during settlement."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-7540","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-7540","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-7540","markdown":"https://www.eipsfordesigners.com/standards/ERC-7540/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-7540/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-7540","official":"https://eips.ethereum.org/EIPS/eip-7540","discussion":"https://ethereum-magicians.org/search?q=ERC-7540"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"ERC-7575","name":"Multi-Asset ERC-4626 Vaults","status":"Draft","chain":"both","category":{"id":"defi","name":"DeFi Patterns","description":"Vaults, bonds, and financial primitives"},"journeyStages":[{"id":"management","name":"Asset Management","description":"Managing assets over time"}],"uxImpact":"Users interact with vaults supporting multiple entry assets for the same share token — like LP tokens or multi-collateral vaults. Design implications: show asset selector dropdown for deposit, display all supported entry points with their respective rates, use share() method to show the common output token, implement vault() lookup on share token for discovery. Design decisions: whether to recommend optimal entry asset based on rates/liquidity, how to represent the relationship between multiple vault contracts and single share token, handling different deposit limits per asset.","hasDetailedContent":true,"content":{"id":"ERC-7575","summary":"ERC-7575 enables ERC-4626 vaults to accept multiple different assets for deposit while issuing a single share token. Users can deposit ETH, USDC, DAI, or other supported assets into the same vault and receive the same shares. This simplifies UX by accepting \"whatever the user has\" instead of forcing a specific input asset.","applicability":{"whenToUse":["Your users must swap to the exact asset a vault accepts.","Your product addresses: different vaults for same strategy but different assets.","The flow should deliver: deposit USDC directly, vault handles conversion internally.","You are designing a multi-asset deposit selector experience with visible states and recovery paths."],"whenToAvoid":["List all accepted assets prominently on vault page.","Show rate comparison and highlight best option.","Show asset selector as primary deposit interface.","No token balances, swaps, lending, or yield flows appear in the product."]},"designerTakeaways":["You can design UI that delivers deposit USDC directly.","You can design UI that delivers one vault accepts all related assets.","You can design UI that delivers \"Deposit any stablecoin you have\", clear and flexible."],"problemsSolved":[{"problem":"Users must swap to the exact asset a vault accepts","oldWay":"Have USDC, vault wants DAI → swap first → then deposit (2 steps)","newWay":"Deposit USDC directly, vault handles conversion internally","impact":"critical"},{"problem":"Different vaults for same strategy but different assets","oldWay":"ETH vault, WETH vault, stETH vault - fragmented liquidity","newWay":"One vault accepts all related assets","impact":"high"},{"problem":"Users confused about which asset to use","oldWay":"\"Should I deposit DAI or USDC?\" - arbitrary choice anxiety","newWay":"\"Deposit any stablecoin you have\" - clear and flexible","impact":"high"},{"problem":"Extra gas for pre-swap before deposit","oldWay":"Swap on DEX → approve → deposit (3 transactions)","newWay":"Deposit directly (1-2 transactions)","impact":"medium"}],"uxPatterns":[{"name":"Multi-Asset Deposit Selector","description":"Choose any supported asset to deposit","mockup":"concept/agent-task","userFlow":["User sees list of accepted assets","Balances shown for each asset","Select asset they have most of","Enter amount to deposit","See share conversion rate","Deposit directly"]},{"name":"Best Asset Suggestion","description":"Recommend optimal deposit asset based on user balances","mockup":"concept/agent-task","userFlow":["Analyze user's wallet balances","Compare rates for each accepted asset","Suggest best option based on balance + rate","One-click deposit with suggested asset","Allow override if user prefers different asset"]},{"name":"Multi-Asset Withdrawal","description":"Choose which asset to receive on withdrawal","mockup":"concept/agent-task","userFlow":["User sees their share balance","Choose output asset","Compare rates between assets","Select amount to withdraw","Receive chosen asset directly"]},{"name":"Accepted Assets Display","description":"Show all assets a vault accepts","mockup":"concept/agent-task","userFlow":["User browses vault details","See all accepted assets at a glance","Understand vault composition","Decide to deposit based on flexibility"]}],"uiComponents":[{"name":"MultiAssetSelector","description":"Dropdown/list for selecting from multiple deposit assets","states":["collapsed","expanded","selected","disabled"],"props":["assets[]","balances{}","rates{}","onSelect"]},{"name":"AssetRateComparison","description":"Show conversion rates for each accepted asset","states":["loading","loaded","stale"],"props":["assets[]","rates{}","bestRate"]},{"name":"AcceptedAssetsBadge","description":"Compact display of all accepted assets","states":["compact","expanded"],"props":["assets[]","maxDisplay"]},{"name":"SmartAssetSuggestion","description":"AI/logic based suggestion for best deposit asset","states":["analyzing","suggested","overridden"],"props":["userBalances{}","vaultRates{}","onAccept","onOverride"]}],"antiPatterns":[{"pattern":"Not showing all accepted assets upfront","why":"Users may not realize they can use their existing balance","instead":"List all accepted assets prominently on vault page","severity":"critical"},{"pattern":"Hiding conversion rate differences","why":"Users may get worse rate without knowing","instead":"Show rate comparison and highlight best option","severity":"high"},{"pattern":"Forcing single asset deposit first","why":"User has to discover multi-asset later, friction","instead":"Show asset selector as primary deposit interface","severity":"high"},{"pattern":"No indication of vault composition","why":"Users can't understand diversification risk","instead":"Show what % of vault is in each asset","severity":"medium"}],"onMonad":[{"aspect":"Rate Updates","ethereum":"Rates may change between view and deposit","monad":"Fast finality means rate shown = rate received","designImplication":"Can show rates as \"guaranteed for 30 seconds\""},{"aspect":"Asset Swapping","ethereum":"Internal swaps add 15+ seconds to deposit","monad":"Internal conversion nearly instant","designImplication":"Multi-asset deposit feels as fast as single-asset"},{"aspect":"Reserve Impact","ethereum":"N/A for deposit assets","monad":"Native MON deposits must account for reserve","designImplication":"If MON is accepted, show spendable vs reserved balance"},{"aspect":"Rate Arbitrage","ethereum":"Users may try to game rate differences","monad":"Fast blocks make arbitrage harder","designImplication":"Can show more stable, reliable rates"}],"keyTakeaways":["Multi-asset vaults accept \"whatever you have\" - major UX win","Always show all accepted assets and user's balance in each","Compare rates between assets, highlight best option","Allow choosing withdrawal asset, not just deposit asset","On Monad: fast finality means rate shown = rate you get"],"technicalNotes":"ERC-7575 extends ERC-4626 to allow multiple entry assets. The vault tracks a \"share\" asset (the vault token) separate from the underlying accounting unit. deposit() and mint() accept different input assets with internal conversion. The standard defines asset listing and preview functions for each accepted asset."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-7575","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-7575","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-7575","markdown":"https://www.eipsfordesigners.com/standards/ERC-7575/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-7575/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-7575","official":"https://eips.ethereum.org/EIPS/eip-7575","discussion":"https://ethereum-magicians.org/search?q=ERC-7575"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"ERC-3156","name":"Flash Loans","status":"Final","chain":"both","category":{"id":"defi","name":"DeFi Patterns","description":"Vaults, bonds, and financial primitives"},"journeyStages":[{"id":"executing","name":"Executing Transactions","description":"Performing on-chain actions"}],"uxImpact":"Users (typically developers/arbitrageurs) borrow tokens with zero collateral, use them within a single transaction, then repay with fee — enabling complex DeFi strategies. Design implications: show maxFlashLoan available per token, display flashFee upfront, this is primarily a developer/power-user feature — most retail UIs won't expose it directly, but aggregators might use it under the hood. Design decisions: whether to expose flash loan functionality in consumer UI at all, how to explain the atomic single-transaction constraint, whether to show protocol's flash loan usage in transaction breakdowns.","hasDetailedContent":true,"content":{"id":"ERC-3156","summary":"ERC-3156 standardizes flash loans - borrowing millions in crypto with zero collateral, using it, and repaying all in one transaction. If you don't repay, the entire transaction reverts. This enables one-click arbitrage, collateral swaps, and self-liquidation protection.","applicability":{"whenToUse":["Your product addresses: arbitrage requires upfront capital.","Your product addresses: each protocol has different flash loan interfaces.","The flow should deliver: borrow $100K, arbitrage, repay + fee, keep profit. Zero capital needed.","You are designing a one-click collateral swap experience with visible states and recovery paths."],"whenToAvoid":["Emphasize: \"If any step fails, entire transaction reverts. Your funds are safe.\".","Disable execute button if net profit is negative.","Explain: \"Borrow → use → repay all in one transaction. If it fails, nothing happens.\".","No token balances, swaps, lending, or yield flows appear in the product."]},"designerTakeaways":["You can design UI that delivers borrow $100K.","You can standard interface works across all ERC-3156 lenders.","You can design UI that delivers flash loan to swap collateral atomically in one transaction."],"problemsSolved":[{"problem":"Arbitrage requires upfront capital","oldWay":"Need $100K to capture $100K arbitrage opportunity","newWay":"Borrow $100K, arbitrage, repay + fee, keep profit. Zero capital needed.","impact":"critical"},{"problem":"Each protocol has different flash loan interfaces","oldWay":"Aave, dYdX, Uniswap all have different flash loan APIs","newWay":"Standard interface works across all ERC-3156 lenders","impact":"high"},{"problem":"Swapping collateral requires complex multi-step process","oldWay":"Withdraw collateral → sell → buy new → redeposit (risky)","newWay":"Flash loan to swap collateral atomically in one transaction","impact":"high"},{"problem":"Self-liquidation is expensive and slow","oldWay":"Find capital to repay debt before liquidation hits","newWay":"Flash loan to repay, withdraw collateral, sell enough, repay flash loan","impact":"high"},{"problem":"Building flash loan integrations is complex","oldWay":"Custom code for each lending protocol","newWay":"Standard receiver callback simplifies integration","impact":"medium"}],"uxPatterns":[{"name":"One-Click Collateral Swap","description":"Change your collateral type without closing position","mockup":"concept/one-click-swap","userFlow":["User views current position","Selects new collateral type","Clicks \"Swap Collateral\"","Behind scenes: flash loan repays debt, withdraw ETH, swap to wstETH, redeposit, reborrow, repay flash loan","All happens in one transaction","User sees new collateral, same debt"]},{"name":"Self-Liquidation Protection","description":"Close position before liquidators take penalty","mockup":"generic/vault-position","userFlow":["User alerted to low health factor","Sees comparison: external liquidation vs self-liquidation","Clicks \"Self-Liquidate\"","Flash loan: borrow USDC → repay debt → withdraw collateral → sell enough for flash loan + fee → repay flash loan","User receives remaining collateral minus small fee","Avoided 10% liquidation penalty"]},{"name":"Leverage Adjustment","description":"Increase or decrease leverage in one click","mockup":"concept/one-click-swap","userFlow":["User views current leverage","Adjusts slider to desired leverage","UI shows position change preview","User confirms","Flash loan executes complex rebalance","Position updated in one transaction"]},{"name":"Arbitrage Opportunity","description":"Capture price differences across DEXs","mockup":"concept/one-click-swap","userFlow":["System detects price difference","Shows opportunity to user","User reviews profit/fee breakdown","Clicks Execute","Flash loan: borrow → buy low → sell high → repay + keep profit","Profit deposited to user wallet"]}],"uiComponents":[{"name":"FlashLoanIndicator","description":"Shows operation uses flash loan","states":["using-flash-loan","direct-capital","hybrid"],"props":["lender","amount","fee","tooltip"]},{"name":"AtomicOperationPreview","description":"Shows all steps that happen in one transaction","states":["loading","ready","executing","complete"],"props":["steps[]","netResult","gasEstimate"]},{"name":"CollateralSwapForm","description":"Interface for collateral type changes","states":["editing","simulating","executing","success"],"props":["fromAsset","toAsset","position","onSwap"]},{"name":"LeverageAdjuster","description":"Slider for leverage changes","states":["idle","adjusting","confirming","applied"],"props":["currentLeverage","maxLeverage","onChange","healthFactor"]},{"name":"ProfitBreakdown","description":"Shows gross profit, fees, net result","states":["profitable","break-even","unprofitable"],"props":["grossProfit","flashLoanFee","gasCost","netProfit"]}],"antiPatterns":[{"pattern":"Not explaining what a flash loan is","why":"Users scared of \"borrowing millions\" language","instead":"Explain: \"Borrow → use → repay all in one transaction. If it fails, nothing happens.\"","severity":"high"},{"pattern":"Hiding the flash loan fee","why":"Users surprised by unexpected cost","instead":"Show fee prominently: \"Flash loan fee: 0.05% ($50)\"","severity":"high"},{"pattern":"Not showing all-or-nothing guarantee","why":"Users fear losing funds if something fails","instead":"Emphasize: \"If any step fails, entire transaction reverts. Your funds are safe.\"","severity":"critical"},{"pattern":"Complex multi-step explanations","why":"Users don't need to understand 7-step atomic operation","instead":"Show outcome: \"Swap collateral from ETH to wstETH\"","severity":"medium"},{"pattern":"Letting users execute unprofitable arbitrage","why":"Gas + fee exceeds profit = user loses money","instead":"Disable execute button if net profit is negative","severity":"critical"},{"pattern":"Not simulating the transaction first","why":"Flash loan txs are complex, may fail unexpectedly","instead":"Always simulate and show expected outcome before execution","severity":"high"}],"onMonad":[{"aspect":"Flash Loan Speed","ethereum":"Complex flash loan tx may timeout or hit gas limits","monad":"High throughput handles complex atomic operations easily","designImplication":"Can offer more complex flash loan strategies"},{"aspect":"Arbitrage Windows","ethereum":"Price differences last multiple blocks","monad":"Fast finality means opportunities close faster","designImplication":"Arbitrage UI needs faster execution, less time to decide"},{"aspect":"Flash Loan Economics","ethereum":"High gas can eat into flash loan profits","monad":"Lower gas makes smaller arbitrage profitable","designImplication":"Show smaller opportunities that would be unprofitable on Ethereum"},{"aspect":"MEV Considerations","ethereum":"Flash loan arbitrage often front-run by MEV bots","monad":"Local mempools may reduce front-running","designImplication":"Arbitrage success rate may be higher on Monad"}],"keyTakeaways":["Flash loans = borrow → use → repay in one transaction","Zero collateral, zero risk if it fails (atomic)","Always show the fee and net profit clearly","Simulate before executing to catch failures","Abstract complexity: show outcome, not the 7 steps"],"technicalNotes":"ERC-3156 defines flashLoan(receiver, token, amount, data) on lenders and onFlashLoan(initiator, token, amount, fee, data) callback on receivers. Receiver must approve lender to pull back amount + fee. If approval fails or callback reverts, entire transaction reverts. Standard fee is typically 0.05-0.09%."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-3156","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-3156","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-3156","markdown":"https://www.eipsfordesigners.com/standards/ERC-3156/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-3156/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-3156","official":"https://eips.ethereum.org/EIPS/eip-3156","discussion":"https://ethereum-magicians.org/search?q=ERC-3156"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"ERC-3525","name":"Semi-Fungible Token","status":"Final","chain":"both","category":{"id":"defi","name":"DeFi Patterns","description":"Vaults, bonds, and financial primitives"},"journeyStages":[{"id":"asset-display","name":"Asset Discovery & Display","description":"Seeing tokens, NFTs, and balances"}],"uxImpact":"Users hold tokens with both NFT-like uniqueness (ID) and fungible-like quantities (value) within slots — think financial instruments with face values. Design implications: display three properties: token ID, slot category, and value amount, enable partial value transfers between tokens of same slot, show value decimals properly, implement slot-based filtering/grouping in portfolio views. Design decisions: whether to visualize as NFT cards with value badges or as table rows, how to handle split/merge operations UX, representing slot compatibility for transfers.","hasDetailedContent":true,"content":{"id":"ERC-3525","summary":"ERC-3525 creates \"semi-fungible tokens\" - NFTs that have both an ID (uniqueness) and a value (quantity). Perfect for bonds, invoices, DeFi positions, and structured products where you need unique tokens that also represent amounts.","applicability":{"whenToUse":["Your product addresses: nFTs can't represent partial amounts.","Your product addresses: eRC-1155 can't track per-token attributes.","The flow should deliver: sFT has ID + value. Token #123 can hold 50 units, split into two 25-unit tokens.","You are designing a bond portfolio display experience with visible states and recovery paths."],"whenToAvoid":["Always show token ID AND value prominently.","Only show compatible (same-slot) tokens for value transfer.","Show original token continues to exist with reduced value.","No token balances, swaps, lending, or yield flows appear in the product."]},"designerTakeaways":["You can design UI that delivers sFT has ID + value. Token #123 can hold 50 units.","You can each SFT ID is unique but shares \"slot\" (category) with similar tokens in the interface.","You can design UI that delivers one SFT represents unique position with value in single token."],"problemsSolved":[{"problem":"NFTs can't represent partial amounts","oldWay":"Own 100% of an NFT or nothing. Can't own \"50 units of Bond #123\"","newWay":"SFT has ID + value. Token #123 can hold 50 units, split into two 25-unit tokens","impact":"critical"},{"problem":"ERC-1155 can't track per-token attributes","oldWay":"All token ID 5 are identical. Can't have Bond #5 with different maturity dates","newWay":"Each SFT ID is unique but shares \"slot\" (category) with similar tokens","impact":"high"},{"problem":"Complex DeFi positions need multiple tokens","oldWay":"Represent bond position with ERC-721 for ID + ERC-20 for value","newWay":"One SFT represents unique position with value in single token","impact":"high"},{"problem":"Can't merge or split positions easily","oldWay":"Burning and reminting required to combine positions","newWay":"Native transfer value between same-slot tokens, or split/merge","impact":"medium"},{"problem":"Invoice/receivable tokenization is awkward","oldWay":"Invoice as NFT can't be partially assigned or valued","newWay":"Invoice token with face value, can be split or partially transferred","impact":"medium"}],"uxPatterns":[{"name":"Bond Portfolio Display","description":"Show bonds with their values and categories","mockup":"generic/vault-deposit","userFlow":["User views bond portfolio","Bonds grouped by slot (category)","Each bond shows unique ID + value","User can split, transfer value, or redeem"]},{"name":"Split Token Flow","description":"Divide one token into two with split values","mockup":"concept/tx-status","userFlow":["User selects bond to split","Enters amount for new token","UI shows resulting two tokens","User confirms split","Two bonds now exist with split values"]},{"name":"Value Transfer Between Tokens","description":"Move value from one token to another in same slot","mockup":"generic/token-transfer","userFlow":["User has multiple tokens in same slot","Selects source and destination","Enters value amount to transfer","Preview shows result","Value moves, token IDs preserved"]},{"name":"DeFi Position Card","description":"Display complex DeFi position as SFT","mockup":"generic/vault-position","userFlow":["User views LP position (SFT)","Sees unique position ID + value (liquidity)","Range and current price shown","Can add/remove partial liquidity","Transfer value to split position"]}],"uiComponents":[{"name":"SFTCard","description":"Display semi-fungible token with ID and value","states":["normal","selected","splitting","transferring"],"props":["tokenId","slot","value","metadata","onAction"]},{"name":"SlotGroup","description":"Group tokens by their slot (category)","states":["collapsed","expanded"],"props":["slot","tokens[]","totalValue"]},{"name":"SplitInterface","description":"UI for splitting token into two","states":["editing","previewing","confirming","complete"],"props":["sourceToken","splitAmount","onSplit"]},{"name":"ValueTransferFlow","description":"Move value between same-slot tokens","states":["selecting","amount-entry","confirming","complete"],"props":["fromToken","toToken","amount","onTransfer"]},{"name":"MergeSelector","description":"Select tokens to merge into one","states":["selecting","ready","merging","complete"],"props":["eligibleTokens[]","selectedTokens[]","onMerge"]}],"antiPatterns":[{"pattern":"Displaying SFTs like regular NFTs (no value shown)","why":"The value IS the key differentiator, hiding it loses the point","instead":"Always show token ID AND value prominently","severity":"critical"},{"pattern":"Allowing transfers between different slots","why":"Slots represent different categories, can't mix bond types","instead":"Only show compatible (same-slot) tokens for value transfer","severity":"high"},{"pattern":"Confusing split with burn-and-mint","why":"Split preserves the original token (with less value)","instead":"Show original token continues to exist with reduced value","severity":"medium"},{"pattern":"Not grouping by slot","why":"Users can't see which tokens are compatible for operations","instead":"Group tokens by slot in portfolio view","severity":"medium"},{"pattern":"Complex slot IDs shown to users","why":"Slot is often a technical hash, meaningless to users","instead":"Map slots to human-readable categories: \"Corporate Bonds\"","severity":"medium"},{"pattern":"Not explaining what slot means","why":"Users don't understand why some tokens can interact and others can't","instead":"Explain: \"Tokens in same category can share value\"","severity":"low"}],"onMonad":[{"aspect":"Split/Merge Gas","ethereum":"Complex operations can be expensive","monad":"Lower gas makes frequent splits/merges viable","designImplication":"Can offer more granular position management"},{"aspect":"Value Transfer Speed","ethereum":"Value transfers are single-block atomic","monad":"Sub-second finality makes transfers feel instant","designImplication":"Can design real-time position rebalancing UX"},{"aspect":"Complex Position Display","ethereum":"Querying multiple SFTs can be slow","monad":"Parallel execution speeds up portfolio queries","designImplication":"Can show larger portfolios without pagination"},{"aspect":"DeFi Integration","ethereum":"SFTs common for Uniswap V3 positions","monad":"Same patterns apply, potentially more complex positions viable","designImplication":"Design for sophisticated position management"}],"keyTakeaways":["ERC-3525 = NFT with a value (ID + amount)","Slot groups compatible tokens (same category)","Can split one token into two with divided value","Can transfer value between same-slot tokens","Always display both token ID and value"],"technicalNotes":"ERC-3525 adds slot (uint256) and value (uint256) to ERC-721. transferValueFrom moves value between tokens without changing ownership. Tokens in same slot are fungible with each other in terms of value. allowance() and approve() work on value, not token. Commonly used for Uniswap V3 LP positions, bonds, and financial instruments."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-3525","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-3525","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-3525","markdown":"https://www.eipsfordesigners.com/standards/ERC-3525/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-3525/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-3525","official":"https://eips.ethereum.org/EIPS/eip-3525","discussion":"https://ethereum-magicians.org/search?q=ERC-3525"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"ERC-5725","name":"Transferable Vesting NFT","status":"Final","chain":"both","category":{"id":"defi","name":"DeFi Patterns","description":"Vaults, bonds, and financial primitives"},"journeyStages":[{"id":"management","name":"Asset Management","description":"Managing assets over time"}],"uxImpact":"Users hold NFTs representing vesting schedules that can be traded — unlocking liquidity for locked tokens. Design implications: show vesting curve visualization (linear/cliff/exponential), display claimable vs locked amounts, add 'Claim' action for vested tokens, show vesting end date and total allocation, enable NFT transfer/listing while maintaining vesting data. Design decisions: pricing display for secondary markets (discount to fully-vested value), whether to show implied discount rate, how to communicate that buying a vesting NFT means inheriting the vesting schedule.","hasDetailedContent":true,"content":{"id":"ERC-5725","summary":"ERC-5725 turns vesting schedules into tradeable NFTs. Your employee token grant, investor allocation, or airdrop vesting becomes a transferable position—sell your future tokens now at a discount, or buy someone's unvested allocation for a deal.","applicability":{"whenToUse":["Your product addresses: vesting tokens locked until schedule complete.","Your product must handle: can't trade unvested allocations.","The flow should deliver: sell vesting NFT for immediate liquidity.","You are designing a vesting nft dashboard experience with visible states and recovery paths."],"whenToAvoid":["Clearly show cliff date and whether it's passed.","Show both: \"Vested: X | Claimable: Y\".","Show market value and % discount.","No token balances, swaps, lending, or yield flows appear in the product."]},"designerTakeaways":["You can design UI that delivers sell vesting NFT for immediate liquidity.","You can design UI that delivers secondary market for vesting positions.","You can design UI that delivers nFT shows total, vested, claimable clearly."],"problemsSolved":[{"problem":"Vesting tokens locked until schedule complete","oldWay":"Wait 4 years to access full allocation","newWay":"Sell vesting NFT for immediate liquidity","impact":"critical"},{"problem":"Can't trade unvested allocations","oldWay":"No market for future tokens","newWay":"Secondary market for vesting positions","impact":"critical"},{"problem":"Vesting progress not visible","oldWay":"Check protocol, do math for unlocked amount","newWay":"NFT shows total, vested, claimable clearly","impact":"high"},{"problem":"Early employees need liquidity","oldWay":"Wait or borrow against promise","newWay":"Sell portion of vesting NFT","impact":"high"},{"problem":"Vesting terms not standardized","oldWay":"Each protocol different interface","newWay":"Standard functions: claimable, vested, claim","impact":"medium"}],"uxPatterns":[{"name":"Vesting NFT Dashboard","description":"View all vesting positions as NFTs","mockup":"concept/nft-gallery","userFlow":["User views vesting dashboard","Sees all vesting NFTs they own","Progress bar shows vested portion","Claimable amount shown in tokens and USD","Can claim vested or sell entire position"]},{"name":"Vesting Schedule Visualization","description":"Show unlock schedule over time","mockup":"generic/vault-deposit","userFlow":["User opens vesting details","Sees visual unlock curve","Current position marked","Key milestones highlighted","Daily unlock rate shown"]},{"name":"Sell Vesting Position","description":"List vesting NFT for sale","mockup":"concept/nft-gallery","userFlow":["User selects vesting NFT to sell","Sees current vesting state","Market value calculated","Sets asking price","Discount from market shown","Lists for sale"]},{"name":"Buy Vesting Position","description":"Purchase someone's vesting NFT","mockup":"concept/nft-gallery","userFlow":["User browses vesting marketplace","Selects interesting position","Sees exactly what they get","Analyzes discount and break-even","Understands time risk","Purchases vesting NFT"]},{"name":"Claim Vested Tokens","description":"Withdraw unlocked tokens","mockup":"generic/vault-position","userFlow":["User views claimable amount","Sees when they last claimed","Chooses amount to claim","Selects destination","Claims tokens to wallet"]}],"uiComponents":[{"name":"VestingProgressBar","description":"Visual progress of vesting schedule","states":["before-cliff","vesting","fully-vested"],"props":["total","vested","claimed","cliffDate","endDate"]},{"name":"VestingNFTCard","description":"Card displaying vesting position","states":["loading","active","fully-vested","transferred"],"props":["vestingNFT","currentPrice","onClaim","onTransfer","onSell"]},{"name":"UnlockScheduleChart","description":"Graph showing tokens unlocking over time","states":["loading","ready"],"props":["schedule","currentDate","milestones[]"]},{"name":"VestingMarketplace","description":"Buy/sell vesting positions","states":["loading","listings","no-listings"],"props":["token","listings[]","onBuy","onList"]},{"name":"ClaimInterface","description":"Interface for claiming vested tokens","states":["nothing-claimable","claimable","claiming","claimed"],"props":["claimableAmount","onClaim","destinationOptions[]"]}],"antiPatterns":[{"pattern":"Not showing cliff status","why":"User thinks they can claim but cliff hasn't passed","instead":"Clearly show cliff date and whether it's passed","severity":"critical"},{"pattern":"Confusing vested vs claimable","why":"Vested might not equal claimable in some schedules","instead":"Show both: \"Vested: X | Claimable: Y\"","severity":"high"},{"pattern":"No sell discount context","why":"Seller doesn't know if their price is reasonable","instead":"Show market value and % discount","severity":"high"},{"pattern":"Hiding time risk for buyers","why":"Buyer doesn't understand they're taking price risk","instead":"Explicit warning: \"Token may decrease during vesting\"","severity":"high"},{"pattern":"No daily/hourly unlock rate","why":"User doesn't know how fast tokens vest","instead":"Show \"~68 PROTO unlock per day\"","severity":"medium"}],"onMonad":[{"aspect":"Claim Frequency","ethereum":"Claiming costs gas, so users batch claims","monad":"Cheap claims enable daily/hourly claiming","designImplication":"Can show \"Claim\" button always enabled"},{"aspect":"Real-time Vesting","ethereum":"Vested amount updates per block (~12s)","monad":"Sub-second blocks show near-continuous vesting","designImplication":"Progress bar can animate smoothly"},{"aspect":"Marketplace Trading","ethereum":"High gas discourages small trades","monad":"Active trading market viable","designImplication":"Can have liquid vesting marketplaces"},{"aspect":"Partial Claims","ethereum":"Claiming partial amounts costs same gas","monad":"Cheap partial claims for DCA-style withdrawal","designImplication":"Offer flexible claim amounts"}],"keyTakeaways":["ERC-5725 = vesting schedules as tradeable NFTs","Show vested, claimable, and claimed separately","Cliff date must be prominent","Help sellers and buyers understand discount/risk","Display unlock rate (daily/hourly)"],"technicalNotes":"ERC-5725 extends ERC-721 with vestedPayoutAtTime(tokenId, timestamp), pendingPayout(tokenId), and claimablePayout(tokenId). The payoutToken() specifies what's vesting. claim() withdraws to owner. Transfers move entire position. Standard enables secondary markets for unvested allocations."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-5725","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-5725","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-5725","markdown":"https://www.eipsfordesigners.com/standards/ERC-5725/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-5725/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-5725","official":"https://eips.ethereum.org/EIPS/eip-5725","discussion":"https://ethereum-magicians.org/search?q=ERC-5725"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"ERC-3475","name":"Abstract Storage Bonds","status":"Final","chain":"both","category":{"id":"defi","name":"DeFi Patterns","description":"Vaults, bonds, and financial primitives"},"journeyStages":[{"id":"management","name":"Asset Management","description":"Managing assets over time"}],"uxImpact":"Users hold complex bond instruments with multiple classes and nonces — each representing different maturity conditions and metadata. Design implications: display bond class/nonce hierarchy, show maturity conditions per bond series, implement batch operations UI for efficiency, display on-chain metadata (coupon rates, redemption conditions). Design decisions: how to simplify the class/nonce abstraction for retail users, whether to group by maturity date or class, representing the difference between issue and redeem actions.","hasDetailedContent":true,"content":{"id":"ERC-3475","summary":"ERC-3475 enables complex financial bonds as NFTs with multiple classes, tranches, and metadata. A single contract can represent bonds with different rates, maturities, and risk levels—bringing structured DeFi products into a standard, tradeable format.","applicability":{"whenToUse":["Your product addresses: deFi positions are opaque.","Your product must handle: can't trade DeFi positions easily.","The flow should deliver: position = NFT with rate, maturity, terms visible.","You are designing a bond portfolio dashboard experience with visible states and recovery paths."],"whenToAvoid":["Clearly explain seniority and what it means for risk.","Maturity date should be prominent with countdown.","Show \"Face: $1000 | Price: $980 (2% discount)\".","No token balances, swaps, lending, or yield flows appear in the product."]},"designerTakeaways":["You can design UI that delivers position = NFT with rate, maturity, terms visible.","You can design UI that delivers transfer position NFT directly.","You can design UI that delivers one contract holds all classes and tranches."],"problemsSolved":[{"problem":"DeFi positions are opaque","oldWay":"Position = balance in protocol, no details visible","newWay":"Position = NFT with rate, maturity, terms visible","impact":"critical"},{"problem":"Can't trade DeFi positions easily","oldWay":"Withdraw, transfer tokens, re-deposit","newWay":"Transfer position NFT directly","impact":"critical"},{"problem":"Multiple bond classes need multiple contracts","oldWay":"Deploy new contract for each bond series","newWay":"One contract holds all classes and tranches","impact":"high"},{"problem":"Bond terms not machine-readable","oldWay":"Check docs/UI for rate, maturity, terms","newWay":"On-chain metadata: rate, maturity, all terms","impact":"high"},{"problem":"Can't create bond derivatives","oldWay":"No standard for splitting/combining positions","newWay":"Split bond into tranches, bundle classes together","impact":"medium"}],"uxPatterns":[{"name":"Bond Portfolio Dashboard","description":"Display multiple bond classes and user positions","mockup":"generic/vault-position","userFlow":["User views bond portfolio","Sees all classes they hold","Each shows rate, maturity, risk level","Accrued yield displayed per position","Actions available for each class"]},{"name":"Bond Issuance","description":"Create bonds with multiple classes","mockup":"generic/vault-deposit","userFlow":["Issuer names bond series","Configures multiple classes","Sets rate, capacity, maturity per class","Adds additional classes as needed","Creates bond contract with all classes"]},{"name":"Bond Purchase","description":"Buy into specific bond class","mockup":"concept/nft-gallery","userFlow":["User browses bond series","Sees available classes with terms","Selects preferred risk/yield class","Enters purchase amount","Sees projected returns","Purchases, receives bond NFT"]},{"name":"Bond Trading","description":"Secondary market for bond positions","mockup":"generic/vault-position","userFlow":["User browses bond marketplace","Sees listings with price/face value","Understands discount = extra yield","Buys position at market price","Or lists their own position for sale"]},{"name":"Bond Maturity & Redemption","description":"Redeem bonds at maturity","mockup":"concept/nft-gallery","userFlow":["Bond reaches maturity date","User notified of redemption","Sees principal + interest breakdown","Chooses destination for funds","Redeems, bond NFT burns"]}],"uiComponents":[{"name":"BondClassCard","description":"Display card for a bond class","states":["available","full","matured","defaulted"],"props":["classId","rate","maturity","capacity","filled","riskLevel"]},{"name":"BondPositionNFT","description":"Visual representation of bond position","states":["active","matured","redeemed"],"props":["class","amount","purchaseDate","maturityDate","accruedYield"]},{"name":"RiskIndicator","description":"Visual risk level for bond class","states":["low","medium","high"],"props":["riskLevel","seniorityRank","showExplanation"]},{"name":"YieldCalculator","description":"Project returns over time","states":["calculating","ready"],"props":["principal","rate","startDate","maturityDate","compounding"]},{"name":"BondMarketplace","description":"Secondary market for bond trading","states":["loading","active","no-listings"],"props":["bondContract","classFilter","listings[]","onBuy","onList"]}],"antiPatterns":[{"pattern":"Hiding bond class differences","why":"Senior vs junior has very different risk profiles","instead":"Clearly explain seniority and what it means for risk","severity":"critical"},{"pattern":"Not showing maturity date prominently","why":"User doesn't know when they can redeem","instead":"Maturity date should be prominent with countdown","severity":"high"},{"pattern":"Confusing face value with market price","why":"User pays $980 for $1000 bond, doesn't understand","instead":"Show \"Face: $1000 | Price: $980 (2% discount)\"","severity":"high"},{"pattern":"No accrued interest display","why":"User doesn't see yield accumulating","instead":"Live counter showing accrued yield","severity":"medium"},{"pattern":"Hiding default risk","why":"Bonds can default, users need to understand","instead":"Show issuer info and default protection mechanisms","severity":"high"}],"onMonad":[{"aspect":"Yield Calculations","ethereum":"Real-time yield requires off-chain calc or multiple calls","monad":"Fast on-chain queries for live accrued interest","designImplication":"Can show real-time yield ticking up"},{"aspect":"Bond Trading","ethereum":"Secondary market trades cost significant gas","monad":"Cheap trades enable active bond market","designImplication":"Can build liquid secondary markets"},{"aspect":"Multi-Class Operations","ethereum":"Cross-class queries expensive","monad":"Parallel queries for portfolio views","designImplication":"Full portfolio dashboard loads instantly"},{"aspect":"Redemption","ethereum":"Redemption tx takes time to confirm","monad":"Sub-second redemption to wallet","designImplication":"Instant gratification on maturity"}],"keyTakeaways":["ERC-3475 = DeFi positions as structured bond NFTs","Multiple classes with different risk/reward in one contract","Always explain seniority and what it means","Show face value vs market price clearly","Display accrued yield and maturity countdown"],"technicalNotes":"ERC-3475 uses a multi-dimensional token model: (classId, nonceId, amount). Classes define bond terms (rate, maturity). Nonces are issuance batches. Metadata functions expose all terms on-chain. Supports issue(), redeem(), burn(), and transfer(). Built for structured products with tranches."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-3475","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-3475","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-3475","markdown":"https://www.eipsfordesigners.com/standards/ERC-3475/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-3475/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-3475","official":"https://eips.ethereum.org/EIPS/eip-3475","discussion":"https://ethereum-magicians.org/search?q=ERC-3475"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"ERC-7092","name":"Financial Bonds","status":"Final","chain":"both","category":{"id":"defi","name":"DeFi Patterns","description":"Vaults, bonds, and financial primitives"},"journeyStages":[{"id":"management","name":"Asset Management","description":"Managing assets over time"}],"uxImpact":"Users hold traditional financial bonds on-chain with familiar terms — ISIN, coupon rate, maturity date, denomination, principal. Design implications: use familiar bond terminology (coupon, maturity, ISIN), display denomination-based minimum amounts, show coupon payment schedules, enable principal/interest tracking, support callable/puttable/convertible bond variants. Design decisions: whether to show yields in basis points or percentages, how to display accrued interest, representing cross-chain bond operations for multi-chain deployments.","hasDetailedContent":true,"content":{"id":"ERC-7092","sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-7092","type":"official-spec"}],"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25","summary":"Users hold traditional financial bonds on-chain with familiar terms — ISIN, coupon rate, maturity date, denomination, principal.","designerTakeaways":["You can label fields ISIN, Coupon, Maturity, Denomination on bond detail using traditional finance layout.","Your portfolio can show accrued interest and next coupon date per holding.","You can badge Callable or Puttable variants with explainer tooltips."],"applicability":{"whenToUse":["Product lists tokenized bonds or structured debt.","Investors expect capital-markets terminology.","ERC-7092 contracts power holdings."],"whenToAvoid":["Generic yield tokens without bond structure.","Retail users with no bond literacy and no education layer.","Contract lacks ISIN and schedule fields."]},"prototypeFirst":[{"screen":"Bond detail card","why":"Investors diligence terms before buy.","covers":["Plain bond","Callable","Convertible"],"include":["ISIN row","Coupon rate","Maturity date","Denomination minimum"]},{"screen":"Coupon schedule","why":"Income investors track payment dates.","covers":["Upcoming coupon","Paid history"],"include":["Schedule table","Next payment highlight","Accrued interest"]},{"screen":"Purchase denomination gate","why":"Bonds trade in minimum chunks.","covers":["Below minimum","Valid lot"],"include":["Minimum denomination callout","Lot size stepper","Total cost preview"]},{"screen":"Callable notice","why":"Issuer may redeem early — surprise if hidden.","covers":["Callable date approaching","Called"],"include":["Callable badge","Notice period","Redemption amount"]}],"mentalModel":[{"label":"ISIN","description":"Standard security identifier — trust and reconciliation anchor."},{"label":"Coupon","description":"Periodic interest payment — show rate and schedule."},{"label":"Maturity","description":"Principal return date — countdown matters."},{"label":"Denomination","description":"Minimum trade size — not fractional like typical tokens."},{"label":"Variant flags","description":"Callable, puttable, convertible change risk — badge each."}],"statesToDesign":[{"state":"Active holding","trigger":"User owns bond before maturity.","userNeed":"Track income and maturity.","designResponse":"Coupon schedule and accrued interest on card."},{"state":"Below minimum purchase","trigger":"User enters invalid lot.","userNeed":"Fix before submit.","designResponse":"Minimum denomination is X inline error."},{"state":"Coupon payment due","trigger":"Payment date approaching.","userNeed":"Expect cash flow.","designResponse":"Next coupon in N days notification."},{"state":"Matured","trigger":"Past maturity date.","userNeed":"See principal returned.","designResponse":"Matured badge with redemption summary."},{"state":"Called by issuer","trigger":"Callable bond redeemed early.","userNeed":"Understand early exit.","designResponse":"Called notice with proceeds breakdown."}],"designDecisions":[{"question":"Yield as APY or coupon?","recommendation":"Coupon rate % plus payment frequency for bonds.","rationale":"DeFi APY mental model misprices fixed income."},{"question":"Basis points or percent?","recommendation":"Percent for retail; bps toggle for institutional.","rationale":"Dual audience common in tokenized RWAs."},{"question":"Accrued interest on screen?","recommendation":"Yes on detail; optional on portfolio row.","rationale":"Accrual affects purchase price in secondary."}],"problemsSolved":[{"problem":"Crypto UI on traditional securities","oldWay":"APY and token amount only","newWay":"ISIN, coupon, maturity bond card","impact":"high"},{"problem":"Wrong lot size submissions","oldWay":"Revert at settlement","newWay":"Denomination gate before sign","impact":"high"},{"problem":"Missed callable events","oldWay":"Surprise early redemption","newWay":"Callable badge and notice period UI","impact":"medium"}],"uxPatterns":[{"name":"Bond Term Sheet Card","description":"Traditional finance layout for on-chain bond.","mockup":"erc-4337/bundled-defi","components":["ISINRow","CouponRate","MaturityDate","VariantBadge"],"userFlow":["Open bond","Read terms","Check schedule","Purchase valid lot"]},{"name":"Coupon Schedule View","description":"Payment dates and accrued interest.","mockup":"erc-4337/bundled-defi","components":["ScheduleTable","AccruedInterest","NextCouponHighlight"],"userFlow":["View holding","Open schedule","See next payment","Track history"]}],"seenInTheWild":[{"app":"Ondo Finance","url":"https://ondo.finance/","note":"Tokenized RWAs with traditional instrument display."},{"app":"Backed Finance","url":"https://backed.fi/","note":"Bond and equity token terminology patterns."},{"app":"Bloomberg","url":"https://www.bloomberg.com/","note":"Reference layout for ISIN and coupon presentation."}],"antiPatterns":[{"pattern":"Showing bond as generic yield farm","why":"Mispriced risk and tax treatment","instead":"Bond term sheet with ISIN and maturity","severity":"critical"},{"pattern":"Fractional buy below denomination","why":"Revert after user signs","instead":"Lot stepper locked to denomination multiples","severity":"high"},{"pattern":"Hiding callable/puttable flags","why":"Investors miss early redemption risk","instead":"Variant badges on card and confirm","severity":"high"}],"vocabulary":[{"use":"Coupon rate","avoid":"Yield APY","why":"Fixed income correct term."},{"use":"Maturity date","avoid":"Expiry timestamp","why":"Finance language."},{"use":"Minimum investment","avoid":"Denomination unit","why":"Retail investor term."}],"onMonad":[{"aspect":"Bond settlement","ethereum":"Coupon claim txs costly","monad":"Lower fees for frequent coupon claims","designImplication":"One-tap claim coupon on Monad."},{"aspect":"Institutional dashboards","ethereum":"Multi-bond refresh slow","monad":"Fast reads for portfolio bond grids","designImplication":"Live accrued interest updates on Monad."}],"technicalNotes":"ERC-7092 bonds use capital-markets fields; never present as DeFi yield without term disclosure.","relatedStandards":[{"id":"ERC-3643","relationship":"Regulated bond transfers may need compliance"},{"id":"ERC-20","relationship":"Some bond legs tokenized as ERC-20"}]},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-7092","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-7092","type":"discussion"},{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-7092","type":"official-spec"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-7092","markdown":"https://www.eipsfordesigners.com/standards/ERC-7092/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-7092/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-7092","official":"https://eips.ethereum.org/EIPS/erc-7092","discussion":"https://ethereum-magicians.org/search?q=ERC-7092"},"freshness":{"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25"}},{"id":"ERC-7818","name":"Expirable ERC-20","status":"Draft","chain":"both","category":{"id":"defi","name":"DeFi Patterns","description":"Vaults, bonds, and financial primitives"},"journeyStages":[{"id":"asset-display","name":"Asset Discovery & Display","description":"Seeing tokens, NFTs, and balances"},{"id":"management","name":"Asset Management","description":"Managing assets over time"}],"uxImpact":"Users hold tokens that expire after a validity period — for rewards, prepaid credits, or time-limited assets. Design implications: prominently show expiration date/countdown per token epoch, display both current-epoch and total usable balance, add 'expiring soon' warnings, enable epoch-specific transfers, gray out or hide expired balances. Design decisions: how aggressively to warn about upcoming expiration, whether to auto-hide expired epochs or show them struck-through, FIFO vs user-selected epoch for spending, notification timing for expiring tokens.","hasDetailedContent":true,"content":{"id":"ERC-7818","summary":"ERC-7818 adds expiration to ERC-20 tokens. Tokens have a validity period and become unusable after expiration. Perfect for loyalty points that expire, time-limited rewards, promotional tokens, or any fungible asset that shouldn't last forever. Users see clear \"expires in X days\" messaging.","applicability":{"whenToUse":["Your product addresses: loyalty points that should expire never do on-chain.","Your product addresses: promotional tokens remain valid forever.","The flow should deliver: on-chain expiration, tokens automatically become unusable.","You are designing a expiration warning display experience with visible states and recovery paths."],"whenToAvoid":["Show expiration prominently from day one.","Send reminders at 7 days, 3 days, 1 day before.","FIFO: always use soonest-expiring first.","No token balances, swaps, lending, or yield flows appear in the product."]},"designerTakeaways":["You can design UI that delivers on-chain expiration.","You can design UI that delivers promotion expires, tokens have clear end date.","You can design UI that delivers \"Use before Jan 31\" creates healthy urgency."],"problemsSolved":[{"problem":"Loyalty points that should expire never do on-chain","oldWay":"Off-chain expiration tracking, inconsistent enforcement","newWay":"On-chain expiration, tokens automatically become unusable","impact":"critical"},{"problem":"Promotional tokens remain valid forever","oldWay":"One-time rewards circulate indefinitely, diluting value","newWay":"Promotion expires, tokens have clear end date","impact":"high"},{"problem":"No urgency to use rewards","oldWay":"Users hoard rewards, never engage","newWay":"\"Use before Jan 31\" creates healthy urgency","impact":"high"},{"problem":"Complex backend for expiring balances","oldWay":"Track expiration per-user off-chain, sync issues","newWay":"Built into token contract, consistent behavior","impact":"medium"}],"uxPatterns":[{"name":"Expiration Warning Display","description":"Show tokens with approaching expiration","mockup":"concept/proxy-pattern","userFlow":["User views reward balance","Tokens sorted by expiration (soonest first)","Visual countdown for each batch","Warning highlights urgent expirations","Quick action to use expiring tokens"]},{"name":"Batch Expiration View","description":"Show multiple token batches with different expirations","mockup":"concept/proxy-pattern","userFlow":["Query all token batches for user","Group by expiration date","Color-code by urgency","Suggest using oldest first","Auto-select expiring tokens for transactions"]},{"name":"Spending with Auto-Select","description":"Automatically use soonest-expiring tokens first","mockup":"concept/tx-status","userFlow":["User initiates purchase","System auto-selects expiring tokens first","Show which batches will be used","Display remaining balance by batch","Confirm transaction"]},{"name":"Expiration Notification","description":"Alert users before tokens expire","mockup":"concept/proxy-pattern","userFlow":["System checks for expiring tokens","Send notification before expiration","Show clear deadline","Provide direct link to use tokens","Allow snooze for reminder"]}],"uiComponents":[{"name":"ExpirationBadge","description":"Small indicator showing expiration status","states":["valid","expiring-soon","expired"],"props":["expirationDate","urgencyThreshold"]},{"name":"TokenBatchList","description":"List tokens grouped by expiration date","states":["loading","loaded","empty"],"props":["batches[]","sortBy","onSelectBatch"]},{"name":"ExpirationCountdown","description":"Visual countdown timer to expiration","states":["days","hours","minutes","expired"],"props":["expirationDate","format"]},{"name":"AutoSelectPreview","description":"Show which batches will be auto-selected for spend","states":["calculating","selected","modified"],"props":["amount","batches[]","selectedBatches[]"]}],"antiPatterns":[{"pattern":"Hiding expiration until it's too late","why":"Users feel tricked when tokens suddenly expire","instead":"Show expiration prominently from day one","severity":"critical"},{"pattern":"No notification before expiration","why":"Users may not check balances, lose tokens unknowingly","instead":"Send reminders at 7 days, 3 days, 1 day before","severity":"high"},{"pattern":"Using newest tokens first","why":"Old tokens expire unused while new ones get spent","instead":"FIFO: always use soonest-expiring first","severity":"high"},{"pattern":"Showing only total balance without breakdown","why":"Users don't know some of their balance expires soon","instead":"Show balance breakdown by expiration date","severity":"medium"}],"onMonad":[{"aspect":"Expiration Check","ethereum":"Each expiration check costs gas","monad":"Cheap reads for frequent expiration checks","designImplication":"Can show real-time expiration status"},{"aspect":"Batch Updates","ethereum":"Updating multiple batches expensive","monad":"Cheap batch operations","designImplication":"Can process many expiration batches efficiently"},{"aspect":"Transaction Speed","ethereum":"Using expiring tokens takes 15+ seconds","monad":"Sub-second use of expiring tokens","designImplication":"Last-minute redemption actually works"},{"aspect":"Time Precision","ethereum":"Block time ~12 seconds, timing approximate","monad":"Faster blocks, more precise expiration","designImplication":"Can show \"expires in X minutes\" more accurately"}],"keyTakeaways":["Always show expiration prominently - no surprises","Use FIFO: spend soonest-expiring tokens first","Send notifications before tokens expire","Show breakdown by expiration date, not just total","On Monad: fast transactions enable last-minute redemption"],"technicalNotes":"ERC-7818 extends ERC-20 with expiration timestamps per token batch. The contract tracks multiple batches with different expirations for each holder. balanceOf returns only non-expired tokens. The standard defines methods to query expiration dates and batch details. Expired tokens can optionally be burned or recycled."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-7818","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-7818","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-7818","markdown":"https://www.eipsfordesigners.com/standards/ERC-7818/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-7818/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-7818","official":"https://eips.ethereum.org/EIPS/eip-7818","discussion":"https://ethereum-magicians.org/search?q=ERC-7818"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"EIP-2266","name":"Atomic Swap Contract","status":"Last Call","chain":"both","category":{"id":"defi","name":"DeFi Patterns","description":"Vaults, bonds, and financial primitives"},"journeyStages":[{"id":"management","name":"Asset Management","description":"Managing assets over time"}],"uxImpact":"Users perform trustless cross-party token swaps using HTLC-based atomic swaps — also functions as American Call Options. Design implications: show swap timeline with initiate/participate/redeem/refund stages, display timelock countdowns for each phase, show premium amount for option-like behavior, guide through the multi-step swap process. Design decisions: how to communicate the optionality risk to counterparty, representing the secret/secretHash mechanism simply, whether to frame as 'swap' or 'option' based on use case.","hasDetailedContent":true,"content":{"id":"EIP-2266","summary":"EIP-2266 defines a standard for atomic swap contracts - trustless peer-to-peer token exchanges without intermediaries. Using hash time-locked contracts (HTLCs), two parties can swap tokens knowing that either both transfers complete or neither does. No middleman, no counterparty risk, just direct trading.","applicability":{"whenToUse":["Your product addresses: peer-to-peer trades required trust.","Your product addresses: dEXs charge fees and require liquidity.","The flow should deliver: atomic swap ensures both sides execute or neither does.","You are designing a create swap offer experience with visible states and recovery paths."],"whenToAvoid":["Clearly explain \"Either both complete or neither does\".","Prominent countdown and clear expiry explanation.","One-click refund with clear instructions.","No token balances, swaps, lending, or yield flows appear in the product."]},"designerTakeaways":["You can design UI that delivers atomic swap ensures both sides execute or neither does.","You can design UI that delivers direct swap with counterparty, no intermediary fees.","You can design UI that delivers smart contract enforces the swap trustlessly."],"problemsSolved":[{"problem":"Peer-to-peer trades required trust","oldWay":"One party sends first, hopes other party sends back","newWay":"Atomic swap ensures both sides execute or neither does","impact":"critical"},{"problem":"DEXs charge fees and require liquidity","oldWay":"Pay 0.3% fee to Uniswap, plus slippage on large trades","newWay":"Direct swap with counterparty, no intermediary fees","impact":"high"},{"problem":"Escrow services needed for large trades","oldWay":"Trust third party to hold funds, pay escrow fees","newWay":"Smart contract enforces the swap trustlessly","impact":"high"},{"problem":"No standard for OTC trades","oldWay":"Each platform had custom swap mechanics","newWay":"Standard interface for all atomic swap implementations","impact":"medium"}],"uxPatterns":[{"name":"Create Swap Offer","description":"Initiate an atomic swap with another party","mockup":"concept/one-click-swap","userFlow":["User specifies tokens to swap","Enters counterparty address","Sets time lock duration","Creates and funds the swap","Shares swap ID with counterparty"]},{"name":"Accept Swap","description":"Counterparty accepts and completes the swap","mockup":"concept/one-click-swap","userFlow":["Counterparty receives swap notification","Reviews offer details","Sees funds are locked","Accepts swap, sending their tokens","Both sides complete atomically"]},{"name":"Swap Status Tracker","description":"Track swap progress through stages","mockup":"concept/tx-status","userFlow":["User checks swap status","Progress shown visually","Both sides' status displayed","Time remaining shown","Refund option if counterparty doesn't act"]},{"name":"Expired Swap Refund","description":"Claim refund when swap expires","mockup":"concept/one-click-swap","userFlow":["Time lock expires without completion","User notified of expiry","Refund available to claim","One-click refund process","Funds returned to user"]}],"uiComponents":[{"name":"SwapCreator","description":"Form to create new atomic swap","states":["configuring","confirming","creating","created"],"props":["sendToken","receiveToken","counterparty","timelock","onCreate"]},{"name":"SwapAcceptor","description":"UI to review and accept incoming swap","states":["reviewing","accepting","completed"],"props":["swapDetails","onAccept","onDecline"]},{"name":"SwapStatusTracker","description":"Shows progress of active swap","states":["pending","funded","accepted","completed","expired"],"props":["swapId","stages[]","timeRemaining","onRefund"]},{"name":"TimeLockIndicator","description":"Shows time remaining for swap","states":["active","warning","expired"],"props":["expiryTime","warningThreshold"]}],"antiPatterns":[{"pattern":"Not explaining atomic swap protection","why":"Users don't understand why it's safe","instead":"Clearly explain \"Either both complete or neither does\"","severity":"high"},{"pattern":"Hiding time lock details","why":"User doesn't know when funds could be stuck","instead":"Prominent countdown and clear expiry explanation","severity":"high"},{"pattern":"Complex refund process","why":"User's funds stuck if they can't figure out refund","instead":"One-click refund with clear instructions","severity":"high"},{"pattern":"No notification when counterparty acts","why":"User misses window to complete","instead":"Push notification or email when swap is funded by counterparty","severity":"medium"}],"onMonad":[{"aspect":"Fast Swap Completion","ethereum":"Each step takes 12+ seconds","monad":"Sub-second confirmation for each step","designImplication":"Swaps complete almost instantly, show real-time progress"},{"aspect":"Lower Time Locks","ethereum":"24h locks common due to slow finality","monad":"Could use shorter locks (1-2 hours) safely","designImplication":"Offer shorter time lock options for faster swaps"},{"aspect":"Gas Costs","ethereum":"Multiple transactions can be expensive","monad":"Cheap transactions make atomic swaps more viable","designImplication":"Emphasize cost savings vs CEX/DEX alternatives"}],"relatedStandards":[{"id":"ERC-20","relationship":"Atomic swaps typically exchange ERC-20 tokens"},{"id":"ERC-721","relationship":"Can also swap NFTs atomically"},{"id":"ERC-6105","relationship":"ERC-6105 provides another approach to peer-to-peer NFT trading"},{"id":"ERC-7683","relationship":"Cross-chain intents offer alternative to atomic swaps for bridging"}]},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-2266","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=EIP-2266","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/EIP-2266","markdown":"https://www.eipsfordesigners.com/standards/EIP-2266/content.md","agent":"https://www.eipsfordesigners.com/standards/EIP-2266/agent.md","api":"https://www.eipsfordesigners.com/api/standards/EIP-2266","official":"https://eips.ethereum.org/EIPS/eip-2266","discussion":"https://ethereum-magicians.org/search?q=EIP-2266"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"EIP-7994","name":"Purpose Bound Money","status":"Draft","chain":"both","category":{"id":"defi","name":"DeFi Patterns","description":"Vaults, bonds, and financial primitives"},"journeyStages":[{"id":"management","name":"Asset Management","description":"Managing assets over time"}],"uxImpact":"Users receive tokens locked until multiple conditions are met — time, KYC, whitelist, or custom requirements. Design implications: show all unlock conditions as a checklist, display which conditions are satisfied vs pending, show expiry date if set, indicate claim eligibility clearly, design condition-specific UI (KYC verification link, time countdown). Design decisions: how to handle partially-met conditions, whether to show locked funds in main balance or separate, progressive disclosure of complex condition requirements, notification when all conditions met.","hasDetailedContent":true,"content":{"id":"EIP-7994","summary":"EIP-7994 creates \"purpose-bound money\"—tokens that can only be spent at approved merchants or for specific purposes. Think corporate expense cards, food stamps, or student stipends as tokens. The issuer defines where and how tokens can be used, ensuring funds go exactly where intended. Perfect for grants, benefits programs, corporate expenses, and any scenario requiring spending restrictions.","applicability":{"whenToUse":["Your product addresses: no way to restrict how tokens are spent.","Your product addresses: corporate cards require centralized control.","The flow should deliver: tokens only work at approved merchants/purposes.","Connect flows must list wallets with names, icons, and explicit user choice."],"whenToAvoid":["Always show valid merchants/categories alongside balance.","Pre-check validity, disable payment button if invalid.","Highlight expiring tokens, send notifications.","No token balances, swaps, lending, or yield flows appear in the product."]},"designerTakeaways":["You can design UI that delivers tokens only work at approved merchants/purposes.","You can design UI that delivers on-chain rules enforce spending limits and categories.","You can design UI that delivers smart contract enforces valid merchant list."],"problemsSolved":[{"problem":"No way to restrict how tokens are spent","oldWay":"Send tokens, hope recipient uses them correctly","newWay":"Tokens only work at approved merchants/purposes","impact":"critical"},{"problem":"Corporate cards require centralized control","oldWay":"Visa/corporate card with bank managing restrictions","newWay":"On-chain rules enforce spending limits and categories","impact":"high"},{"problem":"Benefits programs can't ensure proper use","oldWay":"Issue vouchers, verify manually, prone to fraud","newWay":"Smart contract enforces valid merchant list","impact":"high"},{"problem":"Grants require trust or complex escrow","oldWay":"Send grant money, request receipts, manual auditing","newWay":"Tokens only spendable on approved categories","impact":"medium"},{"problem":"Can't combine spending restrictions with expiry","oldWay":"Separate systems for spend categories and time limits","newWay":"Token encodes both: \"Food only, expires Dec 31\"","impact":"medium"}],"uxPatterns":[{"name":"Purpose-Bound Wallet View","description":"Show tokens with their spending restrictions","mockup":"concept/tx-status","userFlow":["User opens wallet","UI separates regular vs purpose-bound tokens","Each restricted token shows its constraints","Expiry and limits displayed clearly","Tap to see valid merchants"]},{"name":"Merchant Payment Flow","description":"Pay with purpose-bound tokens at valid merchant","mockup":"generic/balance-display","userFlow":["User at checkout","UI checks which tokens valid at this merchant","Purpose-bound tokens shown with validity indicator","User selects appropriate token type","Payment succeeds if constraints satisfied"]},{"name":"Invalid Merchant Warning","description":"Clear feedback when tokens can't be used","mockup":"concept/verify-safety","userFlow":["User at non-eligible merchant","Purpose-bound token shown as invalid","Clear explanation of why","Link to find valid merchants","Alternative payment methods highlighted"]},{"name":"Expense Token with Receipt","description":"Corporate expense requiring documentation","mockup":"concept/tx-status","userFlow":["User initiates expense payment","UI shows all requirements","Upload receipt if needed","Verify category and limits","Payment processed with documentation"]}],"uiComponents":[{"name":"PurposeBoundBalance","description":"Token balance with restriction summary","states":["loading","loaded","restricted","expiring-soon"],"props":["amount","symbol","validMerchants","expiresAt","restrictions"]},{"name":"MerchantValidityChecker","description":"Real-time check if token valid at merchant","states":["checking","valid","invalid","unknown"],"props":["tokenId","merchantAddress","category"]},{"name":"SpendingLimitTracker","description":"Show used vs available within limits","states":["available","approaching-limit","at-limit"],"props":["used","limit","period","resetsAt"]},{"name":"MerchantDirectorySearch","description":"Find valid merchants for a token type","states":["searching","results","no-results","loading"],"props":["tokenType","location","categories"]}],"antiPatterns":[{"pattern":"Showing restricted tokens without explaining restrictions","why":"Users confused why payment fails","instead":"Always show valid merchants/categories alongside balance","severity":"critical"},{"pattern":"Letting users attempt invalid payments","why":"Wasted gas and frustrating experience","instead":"Pre-check validity, disable payment button if invalid","severity":"critical"},{"pattern":"Not showing expiry prominently","why":"Users lose tokens they forgot about","instead":"Highlight expiring tokens, send notifications","severity":"high"},{"pattern":"Hiding spending limits until exceeded","why":"Surprise rejections damage trust","instead":"Show limit progress: \"320/500 monthly remaining\"","severity":"high"},{"pattern":"No way to find valid merchants","why":"Users have tokens but don't know where to spend them","instead":"Merchant directory searchable by token type","severity":"medium"}],"onMonad":[{"aspect":"Validity Checking","ethereum":"On-chain validity checks may be slow/expensive","monad":"Fast, cheap checks enable real-time validation","designImplication":"Can check validity as user browses checkout"},{"aspect":"Payment Speed","ethereum":"Purpose-bound payment may take 15+ seconds","monad":"Sub-second finality for instant purchase confirmation","designImplication":"Receipt/confirmation appears immediately"},{"aspect":"Limit Updates","ethereum":"Checking remaining limits may lag","monad":"Real-time limit updates after each purchase","designImplication":"Dashboard shows live spending progress"},{"aspect":"Batch Payments","ethereum":"Multiple items might need separate constraint checks","monad":"Parallel verification for complex carts","designImplication":"Can validate entire cart at once"}],"keyTakeaways":["EIP-7994 = tokens with built-in spending rules","Always show restrictions, valid merchants, and expiry clearly","Pre-validate before attempting payment","Provide merchant discovery for restricted tokens","On Monad: leverage fast finality for instant validity checks"],"technicalNotes":"EIP-7994 defines purpose-bound tokens with isValidTransfer(from, to, amount, purpose) checks. The contract stores valid merchants/categories, spending limits, and expiry. Transfers only succeed if the recipient (merchant) is approved for the token's purpose. Additional metadata can require documentation (receipts) via off-chain attestation."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-7994","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=EIP-7994","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/EIP-7994","markdown":"https://www.eipsfordesigners.com/standards/EIP-7994/content.md","agent":"https://www.eipsfordesigners.com/standards/EIP-7994/agent.md","api":"https://www.eipsfordesigners.com/api/standards/EIP-7994","official":"https://eips.ethereum.org/EIPS/eip-7994","discussion":"https://ethereum-magicians.org/search?q=EIP-7994"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"EIP-1153","name":"Transient Storage Opcodes","status":"Final","chain":"both","category":{"id":"defi","name":"DeFi Patterns","description":"Vaults, bonds, and financial primitives"},"journeyStages":[{"id":"gas","name":"Gas & Fees","description":"Paying for transactions"}],"uxImpact":"Transactions use cheaper temporary storage that persists only within the transaction — invisible to users but enables lower gas costs. Design implications: not directly user-facing, but enables cheaper reentrancy-protected swaps, lower gas estimates for complex multi-step transactions, simpler single-tx approval patterns. Design decisions: when to show gas savings from transient storage vs traditional storage, whether to surface this as a 'gas optimized' badge on protocols using it, no direct UI needed but affects gas estimation accuracy.","hasDetailedContent":true,"content":{"id":"EIP-1153","summary":"EIP-1153 introduced transient storage - data that exists only for a single transaction and is automatically cleared afterward. This is much cheaper than regular storage for temporary values like reentrancy locks. For users, this means lower gas costs on DeFi operations that use callbacks and complex multi-step transactions.","applicability":{"whenToUse":["Your product addresses: temporary data was expensive to store.","Your product addresses: callback patterns wasted gas.","The flow should deliver: transient storage costs ~100 gas for same operation.","Fee screens need estimates, speed options, and plain-language breakdowns."],"whenToAvoid":["Show \"Optimized\" badge and savings amount.","Show \"Saved $X vs legacy\" when meaningful.","Just show \"Gas Optimized\" or \"Efficient\" badge.","No token balances, swaps, lending, or yield flows appear in the product."]},"designerTakeaways":["You can design UI that delivers transient storage costs ~100 gas for same operation.","You can design UI that delivers transient storage auto-clears, no cleanup cost.","You can design UI that delivers pass data between calls cheaply via transient storage."],"problemsSolved":[{"problem":"Temporary data was expensive to store","oldWay":"Reentrancy locks cost 20,000 gas to set, 5,000 to clear","newWay":"Transient storage costs ~100 gas for same operation","impact":"high"},{"problem":"Callback patterns wasted gas","oldWay":"Flash loans and callbacks stored then deleted state","newWay":"Transient storage auto-clears, no cleanup cost","impact":"high"},{"problem":"Complex transactions were expensive","oldWay":"Multi-step DeFi needed multiple storage writes","newWay":"Pass data between calls cheaply via transient storage","impact":"medium"},{"problem":"Reentrancy protection added significant gas overhead","oldWay":"Every protected function paid storage costs","newWay":"Near-free reentrancy guards","impact":"medium"}],"uxPatterns":[{"name":"Gas Savings Display","description":"Show users when transient storage reduces their costs","mockup":"concept/gas-abstraction","userFlow":["User sets up flash loan strategy","Gas estimated with transient storage optimizations","Savings shown compared to legacy approach","User sees net profit including optimized gas","Execute with confidence in lower costs"]},{"name":"DeFi Action Breakdown","description":"Show gas breakdown including transient storage benefits","mockup":"concept/one-click-swap","userFlow":["User views transaction details","Gas breakdown shows individual costs","Transient storage optimizations highlighted","Total cost displayed","User understands where gas goes"]},{"name":"Protocol Efficiency Badge","description":"Show which protocols use gas-efficient patterns","mockup":"concept/one-click-swap","userFlow":["User comparing DEX options","Optimized protocols marked","Gas costs clearly compared","User can factor efficiency into choice"]}],"uiComponents":[{"name":"GasSavingsBadge","description":"Shows when transaction benefits from EIP-1153","states":["optimized","standard","unknown"],"props":["savingsAmount","savingsPercent","showTooltip"]},{"name":"GasBreakdownList","description":"Itemized gas costs with optimization highlighting","states":["loading","loaded","error"],"props":["items[]","total","optimizations[]"]},{"name":"ProtocolEfficiencyBadge","description":"Indicates protocol uses gas-efficient patterns","states":["optimized","standard"],"props":["optimizations[]","tooltip"]}],"antiPatterns":[{"pattern":"Hiding gas optimization benefits","why":"Users don't know they're getting better deal","instead":"Show \"Optimized\" badge and savings amount","severity":"medium"},{"pattern":"Not comparing to legacy costs","why":"Users can't appreciate the improvement","instead":"Show \"Saved $X vs legacy\" when meaningful","severity":"low"},{"pattern":"Over-explaining technical details","why":"Users don't need to know about TSTORE/TLOAD opcodes","instead":"Just show \"Gas Optimized\" or \"Efficient\" badge","severity":"low"}],"onMonad":[{"aspect":"Already Low Gas Costs","ethereum":"Transient storage savings very noticeable","monad":"Gas already cheap, savings less dramatic","designImplication":"Focus on speed benefits rather than cost savings"},{"aspect":"Transaction Throughput","ethereum":"Cheaper callbacks mean more complex txs viable","monad":"Already supports complex transactions efficiently","designImplication":"Transient storage still helps but impact less visible to users"},{"aspect":"DeFi Patterns","ethereum":"Flash loans much cheaper with EIP-1153","monad":"Same patterns work, optimizations compounded","designImplication":"Monad DeFi protocols should still use transient storage"}],"relatedStandards":[{"id":"ERC-3156","relationship":"Flash loans benefit significantly from transient storage for callbacks"},{"id":"EIP-1559","relationship":"Base fee + EIP-1153 together make DeFi more predictable and cheaper"},{"id":"ERC-4337","relationship":"Account abstraction operations can use transient storage for validation data"}]},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-1153","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=EIP-1153","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/EIP-1153","markdown":"https://www.eipsfordesigners.com/standards/EIP-1153/content.md","agent":"https://www.eipsfordesigners.com/standards/EIP-1153/agent.md","api":"https://www.eipsfordesigners.com/api/standards/EIP-1153","official":"https://eips.ethereum.org/EIPS/eip-1153","discussion":"https://ethereum-magicians.org/search?q=EIP-1153"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"EIP-5164","name":"Cross-Chain Execution","status":"Last Call","chain":"both","category":{"id":"cross-chain","name":"Cross-Chain","description":"Moving assets and messages between chains"},"journeyStages":[{"id":"executing","name":"Executing Transactions","description":"Performing on-chain actions"}],"uxImpact":"Users send transactions on one chain that execute on another without switching networks or managing multiple wallets. Design implications: show source/destination chain selectors prominently, display estimated bridge time and execution status, provide clear message delivery tracking with unique IDs, design pending state indicators for cross-chain messages. Design decisions: how to handle failed message execution (retry UI vs auto-refund), whether to show bridge security/trust profiles to users, balancing simplicity vs advanced options for power users who want to select specific bridges.","hasDetailedContent":true,"content":{"id":"EIP-5164","summary":"EIP-5164 standardizes how to send messages and execute transactions across different blockchains. Apps can trigger actions on Arbitrum from Ethereum using a consistent interface, regardless of which bridge they use underneath.","applicability":{"whenToUse":["Your product addresses: each bridge has different interface.","Your product addresses: cross-chain UX is confusing.","The flow should deliver: one interface works across all bridges.","You are designing a cross-chain action experience with visible states and recovery paths."],"whenToAvoid":["Always show estimated time prominently.","Bold chain indicators at all times.","Clear failure notification with recovery steps.","The product never moves assets or state across chains."]},"designerTakeaways":["You can design UI that delivers one interface works across all bridges.","You can design UI that delivers consistent cross-chain action UI.","You can design UI that delivers dispatchMessage() triggers remote execution."],"problemsSolved":[{"problem":"Each bridge has different interface","oldWay":"Learn Arbitrum bridge API, then Optimism, then Polygon...","newWay":"One interface works across all bridges","impact":"critical"},{"problem":"Cross-chain UX is confusing","oldWay":"Different UI patterns for each chain","newWay":"Consistent cross-chain action UI","impact":"critical"},{"problem":"Can't execute contracts across chains easily","oldWay":"Manual bridging, then manual execution","newWay":"dispatchMessage() triggers remote execution","impact":"high"},{"problem":"Hard to track cross-chain transactions","oldWay":"Check source chain, then destination, manually","newWay":"Standard message ID tracks across chains","impact":"high"},{"problem":"Bridge-specific lock-in","oldWay":"App only works with one bridge","newWay":"Swap bridges without changing app code","impact":"medium"}],"uxPatterns":[{"name":"Cross-Chain Action","description":"Execute action on another chain","mockup":"concept/bridge","userFlow":["User wants to stake on different chain","Sees current chain and destination","Views action journey (steps)","Sees time and fee estimates","Signs transaction on source chain","Message bridged to destination","Action executes automatically"]},{"name":"Cross-Chain Transaction Tracker","description":"Track message as it crosses chains","mockup":"concept/bridge","userFlow":["User initiates cross-chain action","Sees progress through each stage","Source chain confirmed first","Bridge transit shows time remaining","Destination execution completes","Links to explorers for verification"]},{"name":"Bridge Selector","description":"Choose which bridge to use","mockup":"concept/bridge","userFlow":["User needs to cross chains","Views available bridge options","Compares time, cost, security","Selects preferred bridge","Proceeds with cross-chain action"]},{"name":"Cross-Chain Error Handling","description":"Show when cross-chain action fails","mockup":"generic/token-approval","userFlow":["Cross-chain action fails on destination","User sees where failure occurred","Clear error explanation","Assured funds are safe","Given recovery options"]},{"name":"Governance Cross-Chain","description":"DAO votes execute on multiple chains","mockup":"concept/bridge","userFlow":["DAO proposal passes","Execution begins on all chains","User sees status per chain","Each chain updates as executed","New parameters active when complete"]}],"uiComponents":[{"name":"CrossChainProgress","description":"Multi-step progress for cross-chain tx","states":["source-pending","bridging","destination-pending","complete","failed"],"props":["sourceChain","destChain","bridge","currentStep","timeRemaining"]},{"name":"BridgePicker","description":"Select from available bridges","states":["loading","ready","selected"],"props":["bridges[]","selectedBridge","onSelect"]},{"name":"ChainPairIndicator","description":"Visual showing source → destination","states":["connecting","connected","error"],"props":["sourceChain","destChain","status"]},{"name":"MessageTracker","description":"Track cross-chain message by ID","states":["searching","found","in-transit","delivered","failed"],"props":["messageId","sourceChain","destChain","status"]},{"name":"CrossChainError","description":"Display cross-chain failure with recovery","states":["source-failed","bridge-failed","dest-failed"],"props":["error","failedStep","recoveryOptions[]"]}],"antiPatterns":[{"pattern":"Not showing bridging time","why":"User expects instant, gets confused by delay","instead":"Always show estimated time prominently","severity":"critical"},{"pattern":"Hiding which chain user is on","why":"User signs thinking they're on destination","instead":"Bold chain indicators at all times","severity":"critical"},{"pattern":"No progress tracking after sign","why":"User doesn't know if it worked","instead":"Real-time progress through all stages","severity":"high"},{"pattern":"Silent cross-chain failures","why":"User thinks it worked, funds stuck","instead":"Clear failure notification with recovery steps","severity":"critical"},{"pattern":"Auto-selecting bridge without showing","why":"User can't make informed time/cost choice","instead":"Show bridge options with tradeoffs","severity":"medium"}],"onMonad":[{"aspect":"Destination Execution","ethereum":"Execution on dest chain takes 12+ seconds","monad":"Sub-second execution once message arrives","designImplication":"Bridge time dominates, dest feels instant"},{"aspect":"Multi-Chain Governance","ethereum":"Slow execution on each chain","monad":"Fast execution for Monad legs of governance","designImplication":"Governance changes apply faster to Monad"},{"aspect":"Bridge Message Costs","ethereum":"Execution fee varies by destination gas","monad":"Low execution cost on Monad as destination","designImplication":"Cheaper to bridge TO Monad"},{"aspect":"Confirmation Display","ethereum":"Multiple confirmations needed before \"done\"","monad":"Single-slot finality = instant confirmation","designImplication":"Can show \"Complete\" immediately on Monad side"}],"keyTakeaways":["EIP-5164 = standard interface for cross-chain messaging","Always show source chain, destination chain clearly","Display estimated bridging time prominently","Track progress through all stages (source → bridge → dest)","Handle failures gracefully with recovery options"],"technicalNotes":"EIP-5164 defines CrossChainDispatcher with dispatchMessage(toChainId, target, data) and CrossChainReceiver with processMessage(fromChainId, sender, data). Bridges implement these interfaces. messageId tracks messages across chains. Each bridge has different security assumptions and timing."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-5164","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=EIP-5164","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/EIP-5164","markdown":"https://www.eipsfordesigners.com/standards/EIP-5164/content.md","agent":"https://www.eipsfordesigners.com/standards/EIP-5164/agent.md","api":"https://www.eipsfordesigners.com/api/standards/EIP-5164","official":"https://eips.ethereum.org/EIPS/eip-5164","discussion":"https://ethereum-magicians.org/search?q=EIP-5164"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"EIP-7786","name":"Cross-Chain Messaging Gateway","status":"Last Call","chain":"both","category":{"id":"cross-chain","name":"Cross-Chain","description":"Moving assets and messages between chains"},"journeyStages":[{"id":"executing","name":"Executing Transactions","description":"Performing on-chain actions"}],"uxImpact":"Users interact with a unified cross-chain messaging interface that works across EVM and non-EVM chains without knowing which bridge is being used underneath. Design implications: abstract bridge selection behind the scenes or offer it as advanced option, design address input fields that handle different chain address formats (EVM vs Solana vs others), show message attributes as optional settings, display sender/recipient clearly with chain context. Design decisions: whether to expose bridge choice to users (simpler UX vs transparency tradeoff), how to visualize non-EVM addresses, whether to show post-processing steps (like gas payment) inline or as separate flow.","hasDetailedContent":true,"content":{"id":"EIP-7786","summary":"EIP-7786 standardizes how apps send messages across chains. Instead of integrating separately with LayerZero, Wormhole, Axelar, etc., apps implement one interface. The standard abstracts bridge-specific details behind a common \"gateway,\" so users get consistent UX regardless of which bridge routes their message. Developers integrate once, users switch bridges seamlessly.","applicability":{"whenToUse":["Your product addresses: each bridge has different integration requirements.","Your users see inconsistent cross-chain UI across apps.","Your UI should single gateway interface works with any compliant bridge.","You are designing a bridge-agnostic transfer experience with visible states and recovery paths."],"whenToAvoid":["Show bridge name with link to their status page.","Real-time progress with stage indicators and ETA.","Clear recovery UI with retry and refund options.","The product never moves assets or state across chains."]},"designerTakeaways":["You can design UI that delivers single gateway interface works with any compliant bridge.","You can standard message format enables consistent UX patterns.","You can design UI that delivers swap bridge adapters without changing app logic."],"problemsSolved":[{"problem":"Each bridge has different integration requirements","oldWay":"Custom code for LayerZero, different code for Wormhole, etc.","newWay":"Single gateway interface works with any compliant bridge","impact":"critical"},{"problem":"Users see inconsistent cross-chain UI across apps","oldWay":"Every app shows bridges differently, different confirmations","newWay":"Standard message format enables consistent UX patterns","impact":"high"},{"problem":"Switching bridges requires code changes","oldWay":"Hardcoded bridge dependency, risky to change","newWay":"Swap bridge adapters without changing app logic","impact":"high"},{"problem":"No standard way to track cross-chain message status","oldWay":"Each bridge has different tracking APIs","newWay":"Standard events and status checking interface","impact":"medium"},{"problem":"Bridge failures handled inconsistently","oldWay":"Some bridges auto-retry, some fail silently, some refund","newWay":"Standard error handling and retry patterns","impact":"medium"}],"uxPatterns":[{"name":"Bridge-Agnostic Transfer","description":"User picks destination, not bridge","mockup":"concept/bridge","userFlow":["User enters amount and destination chain","UI queries available bridges via gateway","Shows routes sorted by user preference","User picks route (or accepts default)","Single interface sends regardless of bridge"]},{"name":"Cross-Chain Message Tracker","description":"Unified status view for any bridge","mockup":"concept/bridge","userFlow":["User sends cross-chain message","Redirected to status page","Polls gateway for standard status updates","Progress bar advances through stages","Shows bridge-specific details where helpful"]},{"name":"Bridge Health Dashboard","description":"Show bridge reliability and status","mockup":"concept/bridge","userFlow":["User views bridge dashboard","Gateway aggregates bridge health data","Shows status, speed, and reliability metrics","Alerts highlight any issues","Helps user choose appropriate bridge"]},{"name":"Failed Message Recovery","description":"Handle and retry failed cross-chain messages","mockup":"concept/bridge","userFlow":["Message fails to deliver","User sees notification of issue","UI explains what happened clearly","Offers retry or refund options","Standard interface regardless of bridge"]}],"uiComponents":[{"name":"CrossChainProgress","description":"Visual progress indicator for cross-chain messages","states":["pending","confirming","relaying","executing","complete","failed"],"props":["sourceChain","destChain","currentStage","estimatedTime"]},{"name":"BridgeSelector","description":"Choose between available bridge routes","states":["loading","available","comparing","selected"],"props":["routes[]","sortBy","onSelect"]},{"name":"MessageStatusPoller","description":"Auto-updating status component","states":["polling","updated","complete","error"],"props":["messageId","pollInterval","gateway"]},{"name":"BridgeHealthBadge","description":"Quick status indicator for a bridge","states":["healthy","degraded","down","unknown"],"props":["bridgeName","status","lastCheck"]}],"antiPatterns":[{"pattern":"Hiding which bridge is being used","why":"Users need to know for troubleshooting and trust","instead":"Show bridge name with link to their status page","severity":"critical"},{"pattern":"No status updates during bridging","why":"Users anxious when large value transfers show no progress","instead":"Real-time progress with stage indicators and ETA","severity":"critical"},{"pattern":"Abandoning users when messages fail","why":"Stuck funds cause panic and support tickets","instead":"Clear recovery UI with retry and refund options","severity":"critical"},{"pattern":"Auto-selecting bridge without explanation","why":"Users surprised by speed or cost differences","instead":"Show why this bridge was chosen (price/speed/security)","severity":"high"},{"pattern":"Not showing estimated completion time","why":"Users don't know if 5 minutes or 5 hours","instead":"Clear ETA based on bridge historical performance","severity":"medium"}],"onMonad":[{"aspect":"Destination Finality","ethereum":"Arriving on Ethereum may need 15+ seconds finality","monad":"Messages to Monad finalize in under 1 second","designImplication":"Fast final step—show quick completion animation"},{"aspect":"Message Execution","ethereum":"Executing arrived message may cost significant gas","monad":"Cheap execution on Monad side","designImplication":"Include execution cost in fee estimates"},{"aspect":"Retry Speed","ethereum":"Retrying failed message can take time/gas","monad":"Fast, cheap retries on Monad","designImplication":"Retry button can feel responsive"},{"aspect":"Reserve Balance","ethereum":"May need ETH to execute arrived message","monad":"10 MON reserve ensures accounts can always receive cross-chain messages","designImplication":"Users won't be stranded receiving cross-chain messages"}],"keyTakeaways":["EIP-7786 = one interface for all cross-chain messaging","Always show which bridge is used and estimated time","Provide clear status tracking through all stages","Build robust error handling with retry/refund options","On Monad: fast finality makes receiving messages feel instant"],"technicalNotes":"EIP-7786 defines a Gateway interface that abstracts bridge-specific implementations. Key components: send(destChain, receiver, message) for sending, messageStatus(messageId) for tracking, and standard events (MessageSent, MessageReceived, MessageExecuted). Bridge adapters implement the gateway interface, allowing apps to switch bridges by changing the adapter address."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-7786","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=EIP-7786","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/EIP-7786","markdown":"https://www.eipsfordesigners.com/standards/EIP-7786/content.md","agent":"https://www.eipsfordesigners.com/standards/EIP-7786/agent.md","api":"https://www.eipsfordesigners.com/api/standards/EIP-7786","official":"https://eips.ethereum.org/EIPS/eip-7786","discussion":"https://ethereum-magicians.org/search?q=EIP-7786"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"ERC-7683","name":"Cross Chain Intents Standard","status":"Draft","chain":"both","category":{"id":"cross-chain","name":"Cross-Chain","description":"Moving assets and messages between chains"},"journeyStages":[{"id":"executing","name":"Executing Transactions","description":"Performing on-chain actions"}],"uxImpact":"Users express what they want (intent) rather than how to execute it — fillers compete to fulfill cross-chain swaps/transfers at best rates. Design implications: show intent parameters clearly (destination, token, amount, deadline), display competing filler quotes or best rate automatically, design gasless flow for signed orders vs on-chain flow, show fill status across origin and destination chains. Design decisions: whether to show filler identity/reputation, how to communicate dutch auction price dynamics, deadline selection UI (time picker vs relative time), handling partial fills or failed settlements gracefully. 🟢 Live with $35B+ lifetime volume via Across. Bridging Pain is Critical — 70% of onboarded users never complete a bridge transaction. Intent-based protocols are replacing manual bridging as the primary cross-chain UX.","hasDetailedContent":true,"content":{"id":"ERC-7683","summary":"ERC-7683 standardizes cross-chain intents - letting users express what they want to achieve (\"swap 1 ETH on Arbitrum for USDC on Base\") without specifying how. Solvers compete to fulfill intents, finding the best routes and prices. Users get simpler cross-chain UX without manually bridging, swapping, and managing multiple chains.","applicability":{"whenToUse":["Your users must manually navigate cross-chain operations.","Your product addresses: finding best route across chains is complex.","The flow should deliver: express intent \"get USDC on Base\", solver handles everything.","You are designing a intent-based cross-chain swap experience with visible states and recovery paths."],"whenToAvoid":["Show multiple solver offers with comparison.","Show bridge/DEX route for transparency.","Show countdown timer, refresh quotes automatically.","The product never moves assets or state across chains."]},"designerTakeaways":["You can design UI that delivers express intent \"get USDC on Base\".","You can design UI that delivers solvers compete, user gets best execution automatically.","You can design UI that delivers intent either fills completely or refunds."],"problemsSolved":[{"problem":"Users must manually navigate cross-chain operations","oldWay":"Bridge ETH to Arbitrum → wait → swap on Arbitrum → bridge to Base → wait...","newWay":"Express intent \"get USDC on Base\", solver handles everything","impact":"critical"},{"problem":"Finding best route across chains is complex","oldWay":"Compare bridge fees, DEX rates, gas costs across chains manually","newWay":"Solvers compete, user gets best execution automatically","impact":"critical"},{"problem":"Stuck transactions on bridges","oldWay":"TX stuck mid-bridge, unclear status, manual recovery","newWay":"Intent either fills completely or refunds, no partial states","impact":"high"},{"problem":"Different bridges = different interfaces","oldWay":"Learn Hop, learn Across, learn Stargate... all different UX","newWay":"Standard intent format works with any solver/bridge","impact":"high"}],"uxPatterns":[{"name":"Intent-Based Cross-Chain Swap","description":"Express desired outcome, let solvers compete","mockup":"concept/bridge","userFlow":["User specifies what they have and where","User specifies what they want and where","Solvers compete to offer best rate","User accepts best offer","Sign intent transaction","Solver executes cross-chain operation","User receives output on destination chain"]},{"name":"Intent Status Tracking","description":"Track cross-chain intent fulfillment","mockup":"concept/bridge","userFlow":["Intent signed and submitted","Solver claims and begins filling","Track progress across chains","See route taken by solver","Confirm delivery on destination"]},{"name":"Multi-Solver Comparison","description":"Compare offers from competing solvers","mockup":"concept/bridge","userFlow":["Request quotes from multiple solvers","Display ranked by output amount","Show route and time for each","User selects preferred offer","Offers have expiration time"]},{"name":"Intent History","description":"View past cross-chain intents","mockup":"concept/bridge","userFlow":["View list of past intents","See completed, pending, expired","Expired intents show refund status","Click to view full details"]}],"uiComponents":[{"name":"CrossChainInput","description":"Input with chain and asset selection","states":["empty","valid","insufficient","chain-mismatch"],"props":["chains[]","assets[]","balance","onChainChange","onAssetChange"]},{"name":"SolverOfferCard","description":"Display solver quote with route details","states":["loading","quoted","expired","accepted"],"props":["solver","outputAmount","route","estimatedTime","onAccept"]},{"name":"IntentStatusTracker","description":"Track intent through signing → filling → delivery","states":["pending","claimed","filling","delivered","expired"],"props":["intentId","steps[]","currentStep"]},{"name":"ChainRouteDisplay","description":"Visual representation of cross-chain path","states":["preview","in-progress","completed"],"props":["sourceChain","destChain","intermediateSteps[]"]}],"antiPatterns":[{"pattern":"Showing only one solver option","why":"User can't compare, may get worse rate","instead":"Show multiple solver offers with comparison","severity":"high"},{"pattern":"Hiding the route taken","why":"Users can't understand where their funds are","instead":"Show bridge/DEX route for transparency","severity":"high"},{"pattern":"No expiration on quotes","why":"Stale quotes lead to failed fills or bad rates","instead":"Show countdown timer, refresh quotes automatically","severity":"high"},{"pattern":"Unclear refund mechanism for unfilled intents","why":"Users panic if intent expires, don't know about refund","instead":"Explain upfront: \"If not filled in X time, funds refunded\"","severity":"medium"}],"onMonad":[{"aspect":"Intent Signing","ethereum":"Intent confirmation takes 15+ seconds","monad":"Sub-second intent confirmation","designImplication":"Solver auction can happen in real-time"},{"aspect":"Monad as Source","ethereum":"N/A","monad":"Fast finality means solvers get certainty quickly","designImplication":"Intents from Monad fill faster"},{"aspect":"Monad as Destination","ethereum":"Delivery takes 15+ seconds to confirm","monad":"Delivery confirms instantly","designImplication":"Show instant \"Delivered!\" for Monad destinations"},{"aspect":"Reserve Balance","ethereum":"Can spend full ETH balance","monad":"Must keep 10 MON reserve when sending from Monad","designImplication":"MAX button must account for reserve on Monad source"}],"keyTakeaways":["Intents = user says WHAT they want, not HOW to get it","Show multiple solver offers with rate comparison","Display route and estimated time for transparency","Handle expiration/refund clearly - no stuck states","On Monad: fast finality on either end improves overall experience"],"technicalNotes":"ERC-7683 defines a CrossChainOrder struct with input/output tokens, chains, amounts, and expiration. Orders are signed off-chain and submitted to a settlement contract. Solvers monitor for orders, compete to fill them, and execute the cross-chain transfer. The standard supports partial fills, Dutch auctions for price discovery, and guarantee mechanisms."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-7683","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-7683","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-7683","markdown":"https://www.eipsfordesigners.com/standards/ERC-7683/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-7683/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-7683","official":"https://eips.ethereum.org/EIPS/eip-7683","discussion":"https://ethereum-magicians.org/search?q=ERC-7683"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"EIP-7811","name":"Unified Cross-Chain Balances","status":"Draft","chain":"both","category":{"id":"cross-chain","name":"Cross-Chain","description":"Moving assets and messages between chains"},"journeyStages":[{"id":"asset-display","name":"Asset Discovery & Display","description":"Seeing tokens, NFTs, and balances"}],"uxImpact":"Users see their true net worth across all chains in a single view — no more manually switching networks to check balances. Design implications: aggregate balances across chains into a unified portfolio display, show per-chain breakdown on expand, handle loading states for multi-chain queries, display total value in fiat. Design decisions: whether to show chain badges on individual assets or group by chain, how to handle stale data from slow chains, real-time vs periodic refresh strategy, whether to show 'available on chain X' indicators for cross-chain actions. Multi-Chain Checklist rates this Critical priority — 'True net worth in one view.' Draft status, no implementations yet, but addresses the Single-Chain Balance Display pain point.","hasDetailedContent":true,"content":{"id":"EIP-7811","sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-7811","type":"official-spec"}],"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25","summary":"Users see their true net worth across all chains in a single view — no more manually switching networks to check balances.","designerTakeaways":["You can show single Total balance header with expandable per-chain breakdown rows.","Your loading UI can skeleton each chain row independently as data arrives.","You can mark stale chain data with Last updated 5m ago when RPC lags."],"applicability":{"whenToUse":["Multi-chain users are primary audience.","Product positioning is omnichain portfolio.","Aggregator infrastructure exists for target chains."],"whenToAvoid":["Single-chain-only product.","Cannot solve double-count on bridged assets.","Draft spec with no reliable data pipeline."]},"prototypeFirst":[{"screen":"Unified portfolio header","why":"First screen answer: how much am I worth total?","covers":["All chains loaded","Partial load","Fiat toggle"],"include":["Total USD/EUR","Chain expand chevron","Partial data warning"]},{"screen":"Per-chain breakdown expand","why":"Power users verify which chain holds what.","covers":["Expand row","Zero balance chain hidden"],"include":["Chain icon","Chain subtotal","Asset list per chain"]},{"screen":"Stale chain indicator","why":"Wrong totals destroy trust.","covers":["Stale","Refreshing","Failed chain"],"include":["Timestamp","Refresh button","Exclude from total option"]},{"screen":"Cross-chain action hint","why":"User may need asset on specific chain to act.","covers":["Available on Ethereum only"],"include":["Chain availability chip","Bridge CTA if needed"]}],"mentalModel":[{"label":"Unified total","description":"Sum across chains — what users want first."},{"label":"Chain slice","description":"Each network contributes a portion — expand to see."},{"label":"Same asset multi-chain","description":"ETH on L1 and L2 is one logical asset — merge or split per product rules."},{"label":"Bridged double count","description":"Same economic exposure twice if bridge not deduped — must handle."},{"label":"Stale slice","description":"Slow chain data old — total may be approximate."}],"statesToDesign":[{"state":"Full portfolio loaded","trigger":"All chains responded.","userNeed":"Trust total.","designResponse":"Complete header and breakdown."},{"state":"Partial load","trigger":"Some chains pending.","userNeed":"Not think money vanished.","designResponse":"Skeleton rows; partial total label."},{"state":"Stale chain data","trigger":"RPC lag.","userNeed":"Know total approximate.","designResponse":"Amber stale badge on chain row."},{"state":"Chain query failed","trigger":"RPC down.","userNeed":"Retry or exclude.","designResponse":"Failed to load Chain X with retry."},{"state":"Asset only on one chain","trigger":"User tries action needing other chain.","userNeed":"Bridge path.","designResponse":"Available on Polygon only chip."}],"designDecisions":[{"question":"Merge same symbol across chains?","recommendation":"Single ETH row with chain sub-badges in expand.","rationale":"Users think one ETH, multiple locations."},{"question":"Show zero-balance chains?","recommendation":"Hide in default; show in chain manager settings.","rationale":"Clutter without value."},{"question":"Include stale in total?","recommendation":"Yes with ~ approximate label or exclude with user toggle.","rationale":"Honesty over false precision."}],"problemsSolved":[{"problem":"Manual network switching to check balances","oldWay":"Switch MetaMask network 8 times","newWay":"One portfolio total with chain expand","impact":"critical"},{"problem":"Misstated net worth from missing chains","oldWay":"Forgot assets on L2","newWay":"Aggregator includes all connected chains","impact":"high"},{"problem":"Slow chain hides behind fast total","oldWay":"Total looks complete while L2 stale","newWay":"Per-chain stale indicators","impact":"medium"}],"uxPatterns":[{"name":"Unified Net Worth Header","description":"Single total with expandable chain rows.","mockup":"concept/bridge","components":["TotalBalance","ChainExpand","FiatToggle"],"userFlow":["Open portfolio","See total","Expand chain","Per-chain assets"]},{"name":"Incremental Chain Load","description":"Skeleton rows as each chain resolves.","mockup":"concept/tx-status","components":["ChainSkeleton","StaleBadge","RefreshButton"],"userFlow":["Load starts","Chains populate","Stale flagged","User refreshes"]}],"seenInTheWild":[{"app":"Zerion","url":"https://zerion.io/","note":"Multi-chain portfolio aggregation reference."},{"app":"DeBank","url":"https://debank.com/","note":"Cross-chain net worth dashboard patterns."},{"app":"Rainbow","url":"https://rainbow.me/","note":"Wallet multi-chain balance display."},{"app":"MetaMask Portfolio","url":"https://portfolio.metamask.io/","note":"Unified view across networks."}],"antiPatterns":[{"pattern":"Total without loading partial state","why":"Understated wealth while chains load","instead":"Partial total label until all chains resolve","severity":"high"},{"pattern":"Double-counting bridged same asset","why":"Inflated net worth","instead":"Dedupe bridge pairs in aggregation logic","severity":"critical"},{"pattern":"Hiding which chain holds asset","why":"User cannot act on holding","instead":"Chain badge on expand and action hints","severity":"medium"}],"vocabulary":[{"use":"Total across networks","avoid":"Aggregated multichain balance","why":"Plain wealth language."},{"use":"On [chain name]","avoid":"Chain ID 42161 slice","why":"Network names not ids."},{"use":"Updating…","avoid":"RPC query pending","why":"Loading copy not infra jargon."}],"onMonad":[{"aspect":"Monad slice in total","ethereum":"New chain may be omitted from aggregators","monad":"Include Monad in unified view from day one","designImplication":"Monad row in chain breakdown with fast refresh."},{"aspect":"Refresh speed","ethereum":"Slow chains dominate stale warnings","monad":"Monad slice stays fresh — highlight as reliable","designImplication":"Prefer Monad-held assets for quick actions in UI."}],"technicalNotes":"EIP-7811 is draft Critical priority for multi-chain checklist; dedupe bridged assets in totals.","relatedStandards":[{"id":"ERC-7828","relationship":"Chain-aware addresses complement balance view"},{"id":"EIP-5164","relationship":"Cross-chain messaging for balance sync"}]},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-7811","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=EIP-7811","type":"discussion"},{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-7811","type":"official-spec"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/EIP-7811","markdown":"https://www.eipsfordesigners.com/standards/EIP-7811/content.md","agent":"https://www.eipsfordesigners.com/standards/EIP-7811/agent.md","api":"https://www.eipsfordesigners.com/api/standards/EIP-7811","official":"https://eips.ethereum.org/EIPS/eip-7811","discussion":"https://ethereum-magicians.org/search?q=EIP-7811"},"freshness":{"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25"}},{"id":"ERC-7828","name":"Chain-Specific Address Resolution","status":"Draft","chain":"both","category":{"id":"cross-chain","name":"Cross-Chain","description":"Moving assets and messages between chains"},"journeyStages":[{"id":"authentication","name":"Authentication & Identity","description":"Proving who you are and logging in"},{"id":"executing","name":"Executing Transactions","description":"Performing on-chain actions"}],"uxImpact":"Chain-aware addresses route to the correct network automatically — no manual chain switching required when interacting. Design implications: resolve addresses to their target chain context, auto-switch or prompt for network change when interacting with chain-specific addresses, show chain indicator alongside resolved addresses. Design decisions: whether to auto-switch silently or confirm with users, how to display chain context in address fields, fallback behavior when target chain is not supported by wallet. High priority — 'Auto-switch networks on interaction — no manual chain switching.' Resolves the Manual Network Switching pain point.","hasDetailedContent":true,"content":{"id":"ERC-7828","sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-7828","type":"official-spec"}],"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25","summary":"Chain-aware addresses route to the correct network automatically — no manual chain switching required when interacting.","designerTakeaways":["You can detect chain context when address is pasted and show Target network: Arbitrum chip.","Your switch prompt can explain Switch to Arbitrum to continue with confirm, not silent hop.","You can block send when current network mismatches with Switch network CTA."],"applicability":{"whenToUse":["Multi-chain wallet or dApp.","Addresses encode or map to specific chains.","Wrong-chain sends are support burden."],"whenToAvoid":["Single-chain product.","Address format ambiguous without ERC-7828.","User explicitly pinned to one network."]},"prototypeFirst":[{"screen":"Paste address chain detect","why":"Immediate feedback when address entered.","covers":["Detected chain","Ambiguous","Unsupported chain"],"include":["Chain chip on field","Detecting spinner","Unsupported message"]},{"screen":"Network switch prompt","why":"User must consent to network change.","covers":["Switch needed","User declines"],"include":["Switch to [chain] modal","Reason copy","Switch / Stay buttons"]},{"screen":"Wrong network block","why":"Prevent send on current chain when mismatch.","covers":["Blocked send"],"include":["Wrong network banner","Switch CTA","Disabled confirm until match"]},{"screen":"Interaction deep link","why":"Link opens app on correct chain.","covers":["Auto route","Wallet lacks chain"],"include":["Add network if missing","Switch then continue"]}],"mentalModel":[{"label":"Chain-aware address","description":"Address implies or maps to target network."},{"label":"Current network","description":"Wallet active chain — must match for success."},{"label":"Resolution","description":"App reads address → determines target chain."},{"label":"Switch prompt","description":"User approves network change — not silent."},{"label":"Fallback","description":"Unknown address → ask user to pick chain manually."}],"statesToDesign":[{"state":"Chain detected — match","trigger":"Wallet already on target.","userNeed":"Proceed smoothly.","designResponse":"Green chain chip; enable send."},{"state":"Chain detected — mismatch","trigger":"Wrong network active.","userNeed":"Switch safely.","designResponse":"Banner plus Switch to [chain] CTA."},{"state":"Switch in progress","trigger":"User approved switch.","userNeed":"Know wallet prompting.","designResponse":"Switching network… status."},{"state":"Unsupported chain","trigger":"Wallet lacks chain.","userNeed":"Add network path.","designResponse":"Add [chain] to wallet flow."},{"state":"Detection failed","trigger":"Ambiguous address.","userNeed":"Pick chain manually.","designResponse":"Select network dropdown required."}],"designDecisions":[{"question":"Auto-switch silent or prompt?","recommendation":"Always confirm switch unless user enabled auto in settings.","rationale":"Silent switch disorients and enables phishing."},{"question":"Chain chip in address field?","recommendation":"Yes after detection resolves.","rationale":"Constant context during compose."},{"question":"Fallback when detection fails?","recommendation":"Require manual chain pick before enable send.","rationale":"Better delay than wrong-chain loss."}],"problemsSolved":[{"problem":"Wrong-chain sends lose funds","oldWay":"Send USDC on Ethereum to Arbitrum address","newWay":"Detect chain and switch before send","impact":"critical"},{"problem":"Manual network switching friction","oldWay":"User guesses chain from context","newWay":"Address resolution suggests target network","impact":"high"},{"problem":"dApp on wrong network empty state","oldWay":"Broken UI with no explanation","newWay":"Switch network banner on mismatch","impact":"medium"}],"uxPatterns":[{"name":"Chain Detect on Paste","description":"Resolve target chain when address entered.","mockup":"concept/bridge","components":["AddressInput","ChainChip","DetectSpinner"],"userFlow":["Paste address","Chain detected","Chip shows","Switch if needed"]},{"name":"Switch Network Prompt","description":"Confirm before changing active chain.","mockup":"concept/verify-safety","components":["SwitchModal","ChainIcon","ConfirmSwitch"],"userFlow":["Mismatch detected","Modal appears","User confirms","Wallet switches"]}],"seenInTheWild":[{"app":"Rainbow","url":"https://rainbow.me/","note":"Network switch prompts on chain mismatch."},{"app":"MetaMask","url":"https://metamask.io/","note":"Switch network when dApp requests different chain."},{"app":"Across","url":"https://across.to/","note":"Cross-chain address context in bridge flows."}],"antiPatterns":[{"pattern":"Silent auto network switch","why":"User loses context; phishing vector","instead":"Confirm switch modal every time unless opted in","severity":"critical"},{"pattern":"Send enabled on wrong chain","why":"Funds stuck or lost","instead":"Block confirm until network matches","severity":"critical"},{"pattern":"No chain indicator on address field","why":"User assumes current network is correct","instead":"Target chain chip after detection","severity":"high"}],"vocabulary":[{"use":"This address is on [chain]","avoid":"Chain context resolved","why":"Plain routing language."},{"use":"Switch network","avoid":"Change chainId","why":"Wallet-familiar terms."},{"use":"Add [chain] to wallet","avoid":"Register network RPC","why":"Setup action users know."}],"onMonad":[{"aspect":"Monad detection","ethereum":"New chains missing from resolution tables","monad":"Register Monad in resolution from launch","designImplication":"Monad chip appears on Monad-native addresses immediately."},{"aspect":"Switch speed","ethereum":"Switch feels sluggish","monad":"Fast switch-to-confirm loop after user approves","designImplication":"Inline switching status on Monad without long modal."}],"technicalNotes":"ERC-7828 is draft High priority; never enable send on chain mismatch without user-confirmed switch.","relatedStandards":[{"id":"ERC-7930","relationship":"Chain-encoded address format"},{"id":"EIP-695","relationship":"Chain ID standard complement"}]},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-7828","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-7828","type":"discussion"},{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-7828","type":"official-spec"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-7828","markdown":"https://www.eipsfordesigners.com/standards/ERC-7828/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-7828/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-7828","official":"https://eips.ethereum.org/EIPS/erc-7828","discussion":"https://ethereum-magicians.org/search?q=ERC-7828"},"freshness":{"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25"}},{"id":"ERC-7930","name":"Chain-Specific Address Format","status":"Draft","chain":"both","category":{"id":"cross-chain","name":"Cross-Chain","description":"Moving assets and messages between chains"},"journeyStages":[{"id":"authentication","name":"Authentication & Identity","description":"Proving who you are and logging in"},{"id":"status","name":"Status & Confirmation","description":"Waiting for and confirming outcomes"}],"uxImpact":"Address format that makes the target chain explicit to users — prevents wrong-chain sends by encoding chain context directly in the address. Design implications: display chain-specific addresses with visible chain identifiers, validate address format against target chain before sending, show clear warnings when address chain doesn't match current network. Design decisions: how to display the chain prefix (icon, name, or code), whether to auto-convert between formats, handling addresses that exist on multiple chains. High priority — 'Prevents wrong-chain sends.' Complements EIP-1191 (chain-specific checksum) — while 1191 encodes chain ID in the checksum, 7930 provides a full address format standard that makes the chain explicit.","hasDetailedContent":true,"content":{"id":"ERC-7930","sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-7930","type":"official-spec"}],"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25","summary":"Address format that makes the target chain explicit to users — prevents wrong-chain sends by encoding chain context directly in the address.","designerTakeaways":["You can display chain icon plus shortened address with chain prefix visible in confirm step.","Your paste validator can reject format when prefix chain mismatches wallet network.","You can offer copy as chain-specific or universal format with user preference."],"applicability":{"whenToUse":["Multi-chain send and receive flows.","Wrong-chain sends are critical risk.","Wallets adopt ERC-7930 formatted addresses."],"whenToAvoid":["Legacy hex-only addresses only.","Single-chain app with no cross-chain send.","Format not supported by target wallets."]},"prototypeFirst":[{"screen":"Formatted address display","why":"Every address shown should encode chain context.","covers":["With prefix","Legacy fallback"],"include":["Chain icon","Prefix label","Truncated hex","Copy button"]},{"screen":"Paste validation mismatch","why":"Catch wrong chain before compose completes.","covers":["Match","Mismatch","Invalid format"],"include":["Red inline error","Expected vs got chain","Switch or fix CTA"]},{"screen":"Send confirm with chain emphasis","why":"Last chance before irreversible send.","covers":["Confirm step"],"include":["Large chain badge","Full formatted address","This sends on [chain] copy"]},{"screen":"Copy format picker","why":"Power users need universal vs chain-specific copy.","covers":["Settings preference"],"include":["Copy format toggle","Preview string","Save preference"]}],"mentalModel":[{"label":"Chain prefix","description":"Part of address string identifying target network."},{"label":"Legacy address","description":"Raw 0x hex — ambiguous across chains."},{"label":"Formatted address","description":"7930 string — chain explicit to human and parser."},{"label":"Validation","description":"Parser checks prefix matches intended send chain."},{"label":"Conversion","description":"Wallets may convert between legacy and formatted views."}],"statesToDesign":[{"state":"Valid formatted address — match","trigger":"Prefix matches active chain.","userNeed":"Send confidently.","designResponse":"Green validation; proceed."},{"state":"Prefix mismatch","trigger":"Address for different chain.","userNeed":"Not send on wrong chain.","designResponse":"Block with This address is for [chain] message."},{"state":"Legacy address pasted","trigger":"No prefix.","userNeed":"Pick chain or convert.","designResponse":"Prompt select network or upgrade format."},{"state":"Invalid format","trigger":"Malformed string.","userNeed":"Fix paste.","designResponse":"Invalid address format inline error."},{"state":"Copy formatted","trigger":"User copies receive address.","userNeed":"Share unambiguous address.","designResponse":"Copy includes chain prefix by default."}],"designDecisions":[{"question":"Display prefix as icon, name, or code?","recommendation":"Icon plus short name in UI; code in advanced.","rationale":"Icons scan fast; chainId codes confuse."},{"question":"Auto-convert legacy to formatted?","recommendation":"Suggest upgrade on paste, do not silent convert.","rationale":"Conversion errors send to wrong encoding."},{"question":"Hide prefix in compact views?","recommendation":"Never on send confirm; optional in lists with chain column.","rationale":"Confirm step needs maximum clarity."}],"problemsSolved":[{"problem":"Ambiguous 0x address across chains","oldWay":"Same hex valid everywhere","newWay":"Chain embedded in address format","impact":"critical"},{"problem":"Wrong-chain loss from copy-paste","oldWay":"Sent ETH mainnet to Base user address","newWay":"Prefix mismatch blocks before sign","impact":"critical"},{"problem":"Support cannot tell intended chain","oldWay":"User sends hex only","newWay":"Formatted address self-documents chain","impact":"medium"}],"uxPatterns":[{"name":"Chain-Prefixed Address Display","description":"Icon and prefix with truncated hex.","mockup":"concept/bridge","components":["ChainIcon","AddressPrefix","CopyButton"],"userFlow":["Display address","Prefix visible","User copies","Recipient parses chain"]},{"name":"Format Validation Gate","description":"Block send on prefix mismatch.","mockup":"concept/verify-safety","components":["FormatValidator","MismatchBanner","SwitchChainCTA"],"userFlow":["Paste address","Validate prefix","Mismatch blocks","User fixes or switches"]}],"seenInTheWild":[{"app":"CAIP-10","url":"https://github.com/ChainAgnostic/CAIPs/blob/master/CAIPs/caip-10.md","note":"Chain-agnostic account ID patterns inform prefix display."},{"app":"EIP-1191","url":"https://eips.ethereum.org/EIPS/eip-1191","note":"Chain-specific checksum complement to format standard."},{"app":"Ledger","url":"https://www.ledger.com/","note":"Hardware wallet chain verification on confirm."}],"antiPatterns":[{"pattern":"Stripping prefix on display","why":"Defeats purpose of format","instead":"Always show prefix on send and receive","severity":"critical"},{"pattern":"Silent legacy conversion","why":"Wrong encoding sends to void","instead":"Explicit convert with preview","severity":"high"},{"pattern":"Chain id number as only prefix","why":"Users do not know chain ids","instead":"Icon plus network name","severity":"medium"}],"vocabulary":[{"use":"[Chain] address","avoid":"7930-encoded CAIP string","why":"Human chain attribution."},{"use":"Wrong network for this address","avoid":"Prefix chainId mismatch","why":"Plain error language."},{"use":"Copy with network","avoid":"Export formatted blob","why":"Share action language."}],"onMonad":[{"aspect":"Monad prefix adoption","ethereum":"New format rollout uneven","monad":"Ship Monad prefix in receive flows at launch","designImplication":"Default copy includes monad: prefix on Monad wallet."},{"aspect":"Validation speed","ethereum":"Format check negligible","monad":"Same — validate on every paste instantly","designImplication":"Real-time prefix validation on Monad send forms."}],"technicalNotes":"ERC-7930 is draft High priority; show chain prefix on confirm step always.","relatedStandards":[{"id":"ERC-7828","relationship":"Resolution uses formatted addresses"},{"id":"EIP-1191","relationship":"Chain-specific checksum"}]},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-7930","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-7930","type":"discussion"},{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-7930","type":"official-spec"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-7930","markdown":"https://www.eipsfordesigners.com/standards/ERC-7930/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-7930/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-7930","official":"https://eips.ethereum.org/EIPS/erc-7930","discussion":"https://ethereum-magicians.org/search?q=ERC-7930"},"freshness":{"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25"}},{"id":"ERC-7950","name":"Chain ID with Tx Hash","status":"Draft","chain":"both","category":{"id":"cross-chain","name":"Cross-Chain","description":"Moving assets and messages between chains"},"journeyStages":[{"id":"status","name":"Status & Confirmation","description":"Waiting for and confirming outcomes"}],"uxImpact":"Users can share or receive transaction references as a single portable string that includes chain context — no more 'which chain was this on?' confusion. Design implications: generate shareable tx links in format '1:0xabc123...:tx', auto-detect chain ID when pasting tx references, show chain icon/name when displaying decoded references. Design decisions: whether to auto-redirect to appropriate block explorer, how to handle unrecognized chain IDs, displaying the chain-prefixed format vs hiding complexity behind copy button.","hasDetailedContent":true,"content":{"id":"ERC-7950","sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-7950","type":"official-spec"}],"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25","summary":"Users can share or receive transaction references as a single portable string that includes chain context — no more 'which chain was this on?","designerTakeaways":["You can generate share links in standard format while showing friendly tx status in UI.","Your paste field can decode chain-prefixed references and open correct explorer.","You can hide encoded format behind Copy transaction link button."],"applicability":{"whenToUse":["Support and social sharing of transactions across chains.","Activity feeds span multiple networks.","Users paste tx refs from other users frequently."],"whenToAvoid":["Single-chain app with native explorer links only.","No multi-chain explorer routing.","Users never share raw tx references."]},"prototypeFirst":[{"screen":"Transaction status with share","why":"User shares proof of payment cross-chain.","covers":["Confirmed","Pending","Failed"],"include":["Status strip","Copy transaction link","Chain badge on status"]},{"screen":"Paste tx reference lookup","why":"Support and power users paste refs from tickets.","covers":["Valid decode","Unknown chain","Malformed"],"include":["Paste field","Decoded chain + hash","Open explorer CTA"]},{"screen":"Activity feed tx row","why":"Each row must show chain context.","covers":["Multi-chain feed"],"include":["Chain icon on row","Share icon","Explorer link"]},{"screen":"Unrecognized chain ID","why":"New chains appear before explorer list updates.","covers":["Unknown chain"],"include":["Unknown network message","Raw hash fallback","Add explorer config admin"]}],"mentalModel":[{"label":"Tx reference","description":"Portable string tying hash to chain."},{"label":"Decode","description":"Parser splits chain id and hash from paste."},{"label":"Explorer routing","description":"Correct block explorer opens from decoded chain."},{"label":"User-facing link","description":"Copy button hides encoding complexity."},{"label":"Cross-app paste","description":"Same string works in wallet, support bot, and explorer."}],"statesToDesign":[{"state":"Tx confirmed — share ready","trigger":"Inclusion complete.","userNeed":"Share proof.","designResponse":"Copy transaction link with chain context embedded."},{"state":"Paste valid reference","trigger":"User pastes encoded ref.","userNeed":"See tx details.","designResponse":"Decode show chain badge and hash; load status."},{"state":"Malformed paste","trigger":"Invalid format.","userNeed":"Fix input.","designResponse":"Could not read transaction reference inline error."},{"state":"Unknown chain in reference","trigger":"Chain id not in app registry.","userNeed":"Still access hash.","designResponse":"Unknown network — show hash with generic explorer search link."},{"state":"Pending tx share","trigger":"User shares before confirm.","userNeed":"Recipient knows may pending.","designResponse":"Share link plus Pending label in copied message template."}],"designDecisions":[{"question":"Show encoded string in UI?","recommendation":"Hide behind copy; show chain badge plus truncated hash.","rationale":"1:0xabc…:tx frightens non-technical users."},{"question":"Auto-open explorer on paste?","recommendation":"Load in-app status first; explorer as secondary action.","rationale":"Keep users in app when possible."},{"question":"Pending tx shareable?","recommendation":"Yes with Pending disclaimer in share template.","rationale":"Support needs refs before confirmation."}],"problemsSolved":[{"problem":"Which chain was this tx on?","oldWay":"Support asks back and forth","newWay":"Encoded reference self-documents chain","impact":"high"},{"problem":"Wrong explorer opened","oldWay":"Etherscan link for Arbitrum tx","newWay":"Decode routes to correct explorer","impact":"high"},{"problem":"Ugly tx hash only shares","oldWay":"0x hash ambiguous","newWay":"One copy button produces portable reference","impact":"medium"}],"uxPatterns":[{"name":"Copy Transaction Link","description":"One button produces chain-prefixed reference.","mockup":"concept/tx-status","components":["ShareButton","ChainBadge","TxHashTruncate"],"userFlow":["Tx confirms","User taps copy link","Encoded ref copied","Recipient pastes and decodes"]},{"name":"Paste Tx Reference Lookup","description":"Decode pasted reference to status view.","mockup":"concept/bridge","components":["PasteField","DecodePreview","ExplorerLink"],"userFlow":["Paste reference","Decode succeeds","Status loads","Optional open explorer"]}],"seenInTheWild":[{"app":"Etherscan","url":"https://etherscan.io/","note":"Chain-specific explorer link patterns."},{"app":"Blockscout","url":"https://www.blockscout.com/","note":"Multi-chain explorer routing."},{"app":"Socketscan","url":"https://socketscan.io/","note":"Cross-chain tx tracking UX."}],"antiPatterns":[{"pattern":"Showing raw encoded string as primary UI","why":"Users cannot read or verify","instead":"Chain badge plus hash; encode only on copy","severity":"high"},{"pattern":"Paste hash only without chain decode","why":"Wrong chain lookup","instead":"Accept and decode 7950 format on paste field","severity":"critical"},{"pattern":"Dead end on unknown chain id","why":"New chains break support flow","instead":"Fallback hash display and generic search","severity":"medium"}],"vocabulary":[{"use":"Transaction link","avoid":"7950-encoded reference","why":"Share artifact language."},{"use":"On [chain name]","avoid":"ChainId prefix","why":"Network name on status rows."},{"use":"Look up transaction","avoid":"Decode tx reference","why":"Paste field action label."}],"onMonad":[{"aspect":"Monad tx shares","ethereum":"Monad txs need chain id in reference","monad":"Include Monad chain id in all share links from day one","designImplication":"Copy link on Monad always produces monad-prefixed reference."},{"aspect":"Confirm speed","ethereum":"Pending share window long","monad":"Quick confirm reduces pending share confusion","designImplication":"Shorter pending state before share on Monad."}],"technicalNotes":"ERC-7950 is draft; hide encoded format in UI, use on copy and paste decode paths.","relatedStandards":[{"id":"ERC-7930","relationship":"Chain-aware addresses complement tx refs"},{"id":"EIP-695","relationship":"Chain ID in encoded reference"}]},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-7950","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-7950","type":"discussion"},{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-7950","type":"official-spec"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-7950","markdown":"https://www.eipsfordesigners.com/standards/ERC-7950/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-7950/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-7950","official":"https://eips.ethereum.org/EIPS/erc-7950","discussion":"https://ethereum-magicians.org/search?q=ERC-7950"},"freshness":{"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25"}},{"id":"ERC-2135","name":"Consumable Interface","status":"Final","chain":"both","category":{"id":"gaming","name":"Gaming & Composability","description":"Building complex interactive NFT systems"},"journeyStages":[{"id":"specialized","name":"Specialized Interactions","description":"Physical items, AI, social, gaming"}],"uxImpact":"Users hold NFT tickets/passes that can be 'used' or 'consumed' — once consumed, the token is burned or marked used (like tearing a concert ticket). Design implications: show clear 'consumable' badge on eligible NFTs, design prominent 'Use/Redeem' button, display consumption history and remaining uses, show who can consume (owner vs delegated consumer). Design decisions: whether consumption is reversible (affects undo UI), how to visualize partially consumed multi-use tokens, confirmation flow strength for irreversible consumption, showing consumed tokens in wallet (grayed out vs hidden).","hasDetailedContent":true,"content":{"id":"ERC-2135","sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-2135","type":"official-spec"}],"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25","summary":"Users hold NFT tickets/passes that can be 'used' or 'consumed' — once consumed, the token is burned or marked used (like tearing a concert ticket).","designerTakeaways":["You can badge Consumable on eligible items and lead with a prominent Use pass button.","Your confirm step can state This cannot be undone before wallet signature on single-use items.","You can show Uses remaining: 2 of 3 on multi-use consumables."],"applicability":{"whenToUse":["Event tickets, coupons, or in-game passes are single or limited use.","Consumption is on-chain and irreversible or counted.","Games or venues need redeem UX."],"whenToAvoid":["Permanent collectibles never consumed.","Consumption handled off-chain only.","Reversible use without burn semantics."]},"prototypeFirst":[{"screen":"Consumable pass detail","why":"Holder decides to use at venue or in-game.","covers":["Unused","Multi-use partial","Fully consumed"],"include":["Consumable badge","Use CTA","Uses remaining","Consumed overlay"]},{"screen":"Irreversible use confirm","why":"Single-use needs strong consent.","covers":["Confirm modal"],"include":["Cannot undo copy","Ack checkbox","Confirm use"]},{"screen":"Consumption history","why":"Multi-use and audit need timeline.","covers":["History list"],"include":["Used dates","Remaining count","Consumer address if delegated"]},{"screen":"Fully consumed archive","why":"Used tickets may stay as mementos.","covers":["Grayed consumed"],"include":["Used on [date]","No Use button","Optional hide filter"]}],"mentalModel":[{"label":"Consumable","description":"Token exists to be used, not traded indefinitely."},{"label":"Use action","description":"On-chain consume — may burn or decrement counter."},{"label":"Single vs multi-use","description":"One shot or N remaining — UI must show count."},{"label":"Consumer permission","description":"Owner or delegated address may trigger use."},{"label":"Irreversibility","description":"Most consumption cannot undo — confirm accordingly."}],"statesToDesign":[{"state":"Ready to use","trigger":"Unused consumable.","userNeed":"Clear primary action.","designResponse":"Prominent Use pass CTA."},{"state":"Confirm consumption","trigger":"User tapped Use.","userNeed":"Understand permanence.","designResponse":"Modal with irreversible warning."},{"state":"Partially used","trigger":"Multi-use with remaining.","userNeed":"Track count.","designResponse":"Uses remaining chip."},{"state":"Fully consumed","trigger":"No uses left.","userNeed":"See memento not active pass.","designResponse":"Used badge; disable Use."},{"state":"Wrong consumer","trigger":"Non-authorized address tries use.","userNeed":"Plain block.","designResponse":"Only the pass holder can use this."}],"designDecisions":[{"question":"Reversible consumption UI?","recommendation":"Never imply undo unless contract supports it.","rationale":"False undo hope causes disputes at venue."},{"question":"Show consumed in wallet?","recommendation":"Gray archive tab, not hidden delete.","rationale":"Proof of attendance matters."},{"question":"Confirm strength for multi-use?","recommendation":"Lighter confirm when uses remain; full warning on last use.","rationale":"Friction scales with finality."}],"problemsSolved":[{"problem":"Fake reuse of spent tickets","oldWay":"Screenshot of QR reused","newWay":"On-chain consume marks spent","impact":"critical"},{"problem":"Users unsure if pass still valid","oldWay":"Ambiguous metadata","newWay":"Consumable badge and remaining uses","impact":"high"},{"problem":"Accidental tap burns pass","oldWay":"One tap consume","newWay":"Confirm modal with ack","impact":"high"}],"uxPatterns":[{"name":"Use Pass Flow","description":"Consumable redeem with irreversible confirm.","mockup":"eip-7702/session-permissions","components":["UseButton","ConfirmModal","ConsumedBadge"],"userFlow":["Open pass","Tap Use","Confirm","Marked consumed"]},{"name":"Uses Remaining Counter","description":"Multi-use consumable countdown.","mockup":"concept/nft-gallery","components":["UsesCounter","HistoryList"],"userFlow":["View pass","See 2 of 3","Use once","Counter updates"]}],"seenInTheWild":[{"app":"POAP","url":"https://poap.xyz/","note":"Redeem and claim patterns for event tokens."},{"app":"Unlock Protocol","url":"https://unlock-protocol.com/","note":"Membership key redemption UX."},{"app":"Immutable","url":"https://www.immutable.com/","note":"In-game consumable item patterns."}],"antiPatterns":[{"pattern":"Use button with no confirm on single-use","why":"Accidental burn at venue","instead":"Ack modal before signature","severity":"critical"},{"pattern":"Hiding remaining uses on multi-use","why":"Surprise when last use gone","instead":"Uses remaining on card and detail","severity":"high"},{"pattern":"Identical UI for consumed and active","why":"Gate staff confusion","instead":"Used overlay and disabled Use","severity":"high"}],"vocabulary":[{"use":"Use pass","avoid":"Call consume()","why":"Venue-friendly action."},{"use":"Uses remaining","avoid":"Consumption counter","why":"Plain counting language."},{"use":"Used — cannot reuse","avoid":"Token burned","why":"Outcome not EVM term."}],"onMonad":[{"aspect":"Redeem speed","ethereum":"Venue line waits for confirm","monad":"Sub-second consume confirmation at gate","designImplication":"Inline success at scan without long modal."},{"aspect":"Multi-use games","ethereum":"Per-use gas adds up","monad":"Cheap consume enables frequent in-game use","designImplication":"Lighter confirm for non-final uses on Monad."}],"technicalNotes":"ERC-2135 consumption is often irreversible; match confirm strength to single vs last use.","relatedStandards":[{"id":"ERC-4400","relationship":"Consumer role extension for consumables"},{"id":"ERC-721","relationship":"Consumable NFT interface"}]},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-2135","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-2135","type":"discussion"},{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-2135","type":"official-spec"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-2135","markdown":"https://www.eipsfordesigners.com/standards/ERC-2135/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-2135/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-2135","official":"https://eips.ethereum.org/EIPS/erc-2135","discussion":"https://ethereum-magicians.org/search?q=ERC-2135"},"freshness":{"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25"}},{"id":"ERC-4400","name":"Consumable NFT Extension","status":"Final","chain":"both","category":{"id":"gaming","name":"Gaming & Composability","description":"Building complex interactive NFT systems"},"journeyStages":[{"id":"specialized","name":"Specialized Interactions","description":"Physical items, AI, social, gaming"}],"uxImpact":"Users can assign a 'consumer' to their NFT who can use it without owning it — like lending your metaverse land to a builder while keeping ownership. Design implications: show separate 'owner' and 'consumer' roles on NFT detail pages, design 'Assign Consumer' action distinct from transfer, display consumer address/ENS with clear role label, show 'You are consumer' vs 'You are owner' states. Design decisions: whether to show consumer history, how to handle consumer permissions expiration (if implemented), UX for revoking consumer access, visualizing the owner-consumer relationship in collection views.","hasDetailedContent":true,"content":{"id":"ERC-4400","sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-4400","type":"official-spec"}],"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25","summary":"Users can assign a 'consumer' to their NFT who can use it without owning it — like lending your metaverse land to a builder while keeping ownership.","designerTakeaways":["You can show dual badges Owner: you and Consumer: builder.eth on detail pages.","Your Assign consumer flow stays distinct from Transfer — different copy and confirmation.","You can list active consumers on owner settings with one-tap Revoke access."],"applicability":{"whenToUse":["Metaverse land, game items, or equipment need use-without-transfer.","Owner-consumer split is on-chain via ERC-4400.","Both parties use same dApp."],"whenToAvoid":["ERC-4907 rental with expiry suffices.","No consumer utilities implemented.","Simple ownership-only NFTs."]},"prototypeFirst":[{"screen":"Dual role detail header","why":"Instant clarity on owner vs consumer.","covers":["You are owner","You are consumer","Third party viewing"],"include":["Role banners","Owner row","Consumer row","Role-specific CTAs"]},{"screen":"Assign consumer sheet","why":"Delegation must not feel like sale.","covers":["Assign","Replace consumer"],"include":["Consumer address","Not a transfer callout","Confirm assign"]},{"screen":"Consumer action view","why":"Consumer sees permitted in-app actions only.","covers":["Allowed build","Blocked transfer"],"include":["You can use","Owner-only actions grayed"]},{"screen":"Revoke consumer access","why":"Owner ends delegation.","covers":["Revoke confirm"],"include":["Consumer name","Revoke warning","Immediate effect note"]}],"mentalModel":[{"label":"Owner","description":"Legal/on-chain holder — can transfer and assign consumer."},{"label":"Consumer","description":"Granted user rights without ownership."},{"label":"Assign vs transfer","description":"Assign keeps owner; transfer changes owner."},{"label":"Revoke","description":"Owner removes consumer — access ends on-chain."},{"label":"Viewer context","description":"UI adapts to You are owner / You are consumer."}],"statesToDesign":[{"state":"Owner, no consumer","trigger":"Default holding.","userNeed":"Assign or use as owner.","designResponse":"Assign consumer optional CTA."},{"state":"Owner with active consumer","trigger":"Consumer set.","userNeed":"Monitor and revoke.","designResponse":"Consumer row in settings with Revoke."},{"state":"You are consumer","trigger":"Connected as consumer.","userNeed":"Use without transfer options.","designResponse":"Consumer banner; owner actions hidden."},{"state":"Revoked consumer","trigger":"Owner revoked.","userNeed":"Consumer knows access ended.","designResponse":"Access ended notice on next load."},{"state":"Third party viewer","trigger":"Neither owner nor consumer.","userNeed":"See both roles.","designResponse":"Owner and Consumer rows read-only."}],"designDecisions":[{"question":"Show consumer history?","recommendation":"Last 3 consumers in owner settings.","rationale":"Audit without full explorer."},{"question":"Consumer can transfer?","recommendation":"Never — hide transfer for consumer role.","rationale":"Prevents confusion and exploits."},{"question":"Assign vs rent (4907)?","recommendation":"4400 for indefinite use grant; 4907 for time rental.","rationale":"Pick standard matching product semantics."}],"problemsSolved":[{"problem":"Full transfer to lend utility","oldWay":"Temporary transfer risks not getting back","newWay":"Consumer role without ownership change","impact":"high"},{"problem":"Consumer thinks they own NFT","oldWay":"Same UI for all connected wallets","newWay":"You are consumer banner","impact":"high"},{"problem":"Forgotten open delegations","oldWay":"Consumer retains access silently","newWay":"Active consumer row with revoke","impact":"medium"}],"uxPatterns":[{"name":"Owner Consumer Dual Badge","description":"Parallel role display on NFT detail.","mockup":"eip-7702/session-permissions","components":["OwnerBadge","ConsumerBadge","RoleBanner"],"userFlow":["Open NFT","See roles","Actions gated by role"]},{"name":"Assign Consumer Flow","description":"Delegate use without transfer.","mockup":"concept/permit-approval","components":["AssignSheet","NotTransferCallout","RevokeButton"],"userFlow":["Owner taps Assign","Enters address","Confirms","Consumer can use"]}],"seenInTheWild":[{"app":"Decentraland","url":"https://decentraland.org/","note":"Land operator patterns without ownership transfer."},{"app":"ReNFT","url":"https://renft.io/","note":"Rental vs use delegation UX reference."},{"app":"Sandbox","url":"https://www.sandbox.game/","note":"Game asset usage without sale."}],"antiPatterns":[{"pattern":"Assign consumer copy says Transfer","why":"Owner accidentally sells","instead":"Assign use access — you keep ownership","severity":"critical"},{"pattern":"Consumer sees Transfer button","why":"Failed txs and confusion","instead":"Hide owner-only actions for consumer role","severity":"high"},{"pattern":"No active consumer indicator for owner","why":"Forgotten delegations","instead":"Consumer row in owner settings always visible","severity":"medium"}],"vocabulary":[{"use":"Assign someone to use","avoid":"Set consumer address","why":"Delegation language."},{"use":"You are using this","avoid":"Consumer role active","why":"Second-person clarity."},{"use":"Revoke access","avoid":"Clear consumer","why":"Permission language."}],"onMonad":[{"aspect":"Assign/revoke cost","ethereum":"Owners skip revoke due to gas","monad":"Cheap revoke encourages hygiene","designImplication":"Prominent revoke in owner settings on Monad."},{"aspect":"In-game sync","ethereum":"Role lag after assign","monad":"Fast finality updates consumer permissions quickly","designImplication":"Refresh role banner immediately post-tx on Monad."}],"technicalNotes":"ERC-4400 consumer is not owner; never show transfer to consumer role.","relatedStandards":[{"id":"ERC-4907","relationship":"Time-bound rental alternative"},{"id":"ERC-2135","relationship":"Consumer may trigger consumable use"}]},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-4400","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-4400","type":"discussion"},{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-4400","type":"official-spec"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-4400","markdown":"https://www.eipsfordesigners.com/standards/ERC-4400/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-4400/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-4400","official":"https://eips.ethereum.org/EIPS/erc-4400","discussion":"https://ethereum-magicians.org/search?q=ERC-4400"},"freshness":{"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25"}},{"id":"ERC-4519","name":"NFTs Tied to Physical Assets","status":"Final","chain":"both","category":{"id":"physical","name":"Physical & Real World","description":"Connecting NFTs to physical items"},"journeyStages":[{"id":"specialized","name":"Specialized Interactions","description":"Physical items, AI, social, gaming"}],"uxImpact":"Users own NFTs cryptographically tied to physical IoT devices — the device itself has an Ethereum address and must authenticate with the owner before it can be used. Design implications: show device authentication status (waitingForOwner → engagedWithOwner → engagedWithUser), design pairing flow UI, display physical asset address alongside owner address, show timeout warnings if device hasn't checked in. Design decisions: how technical to make the key exchange UI, whether to visualize the mutual authentication handshake, handling authentication failures gracefully, UX for transferring ownership (requires re-authentication).","hasDetailedContent":true,"content":{"id":"ERC-4519","summary":"ERC-4519 creates a standard for NFTs that are cryptographically linked to physical assets. Each physical item contains a secure chip (like NFC) that can prove the NFT-to-item binding. The physical item can verify ownership and even initiate state changes on the blockchain, enabling authentic luxury goods, IoT devices, and physical collectibles with provable on-chain ownership.","applicability":{"whenToUse":["Your product addresses: no way to verify if NFT actually represents a physical item.","Your product addresses: counterfeit physical goods sold with fake NFT certificates.","The flow should deliver: tap NFC chip on item → cryptographic proof of NFT binding.","You are designing a physical item verification experience with visible states and recovery paths."],"whenToAvoid":["Require NFC scan from physical item for any transfer.","Clearly explain \"this proves item is genuine AND you possess it\".","Always show clear state: \"You\", \"Operator\", \"Awaiting\".","No link between physical items and on-chain records is required."]},"designerTakeaways":["You can design UI that delivers tap NFC chip on item → cryptographic proof of NFT binding.","You can design UI that delivers physical chip signs challenge.","You can design UI that delivers physical asset can query and verify its current NFT owner."],"problemsSolved":[{"problem":"No way to verify if NFT actually represents a physical item","oldWay":"Trust certificate, seller claims, or central authority","newWay":"Tap NFC chip on item → cryptographic proof of NFT binding","impact":"critical"},{"problem":"Counterfeit physical goods sold with fake NFT certificates","oldWay":"Hope the serial number matches, check paper authenticity","newWay":"Physical chip signs challenge, only genuine items can prove ownership","impact":"critical"},{"problem":"Physical asset ownership disconnected from NFT ownership","oldWay":"Transfer NFT separately from physical item, hope they stay together","newWay":"Physical asset can query and verify its current NFT owner","impact":"high"},{"problem":"No standard for physical asset state management","oldWay":"Each project invents custom verification systems","newWay":"Standard states: WaitingForOwner, EngagedWithOwner, EngagedWithOperator","impact":"medium"}],"uxPatterns":[{"name":"Physical Item Verification","description":"Tap NFC on physical item to verify authenticity and ownership","mockup":"concept/verify-safety","userFlow":["User opens verification app","App prompts NFC scan","User taps phone on physical item","Chip signs cryptographic challenge","App verifies signature against NFT","Shows authenticity result with details"]},{"name":"Verification Result Display","description":"Show clear authenticity and ownership status","mockup":"concept/nft-gallery","userFlow":["Verification completes successfully","Show prominent verified badge","Display item details from NFT metadata","Show current owner information","Provide link to ownership history"]},{"name":"Ownership Transfer with Physical","description":"Transfer ownership requires both NFT and physical presence","mockup":"concept/verify-safety","userFlow":["Seller initiates transfer","Seller scans item to prove possession","Buyer receives item physically","Buyer scans to confirm receipt","NFT ownership transfers on-chain","Both parties see confirmation"]},{"name":"Asset State Dashboard","description":"View and manage physical asset engagement states","mockup":"concept/verify-safety","userFlow":["User views dashboard of physical assets","Each shows current engagement state","Different actions based on state","Can lend to operators","Track items not in possession"]}],"uiComponents":[{"name":"NFCVerificationScanner","description":"Initiates and manages NFC scanning for item verification","states":["ready","scanning","verifying","success","failed","unsupported"],"props":["onVerify","timeout","challengeProvider"]},{"name":"AuthenticityBadge","description":"Shows verification status prominently","states":["verified","unverified","suspicious","unknown"],"props":["status","timestamp","verificationDetails"]},{"name":"PhysicalAssetCard","description":"Displays physical asset with state and actions","states":["engaged","waiting","lent","transferring"],"props":["asset","state","operator","onAction"]},{"name":"TransferCeremony","description":"Multi-step physical+NFT transfer flow","states":["seller-verify","buyer-verify","confirming","complete"],"props":["seller","buyer","asset","onComplete"]}],"antiPatterns":[{"pattern":"Allowing NFT transfer without physical verification","why":"Breaks the physical-digital link, enables fraud","instead":"Require NFC scan from physical item for any transfer","severity":"critical"},{"pattern":"Not explaining what NFC verification proves","why":"Users don't understand the security guarantees","instead":"Clearly explain \"this proves item is genuine AND you possess it\"","severity":"high"},{"pattern":"Hiding engagement state from users","why":"Users confused about who can use the physical item","instead":"Always show clear state: \"You\", \"Operator\", \"Awaiting\"","severity":"high"},{"pattern":"No fallback for NFC-disabled phones","why":"Some users can't verify their purchases","instead":"Provide QR code + manual verification options","severity":"medium"},{"pattern":"Requiring verification for every view","why":"Friction for legitimate owners checking their items","instead":"Cache verification with clear \"last verified\" timestamp","severity":"medium"}],"onMonad":[{"aspect":"Verification Speed","ethereum":"On-chain verification query takes 1-15 seconds","monad":"Sub-second verification responses","designImplication":"Tap-and-verify feels instant, can verify multiple items quickly"},{"aspect":"State Changes","ethereum":"Engaging/disengaging takes 15+ seconds","monad":"State changes in <1 second","designImplication":"Real-time state toggle, no waiting spinner needed"},{"aspect":"Gas for State Updates","ethereum":"Each state change costs $2-10 in gas","monad":"State changes cost fractions of a cent","designImplication":"Can update state frequently, enable IoT-style continuous verification"},{"aspect":"Batch Verification","ethereum":"Verifying collection of items is expensive","monad":"Batch verify entire inventory cheaply","designImplication":"Enable \"scan all items\" for collectors and retailers"}],"keyTakeaways":["ERC-4519 = cryptographic link between physical items and NFTs","NFC chip in item can prove authenticity AND possession","Three states: WaitingForOwner, EngagedWithOwner, EngagedWithOperator","Always show verification status and engagement state clearly","On Monad: instant verification enables new UX patterns"],"technicalNotes":"ERC-4519 defines a secure link between an NFT and a physical asset containing a chip with an asymmetric cryptographic key pair. The chip's address is derived from its public key. The standard extends ERC-721 with user management (owner vs user), timestamp tracking, and state machine for engagement. Physical assets can sign challenges to prove possession without exposing private keys."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-4519","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-4519","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-4519","markdown":"https://www.eipsfordesigners.com/standards/ERC-4519/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-4519/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-4519","official":"https://eips.ethereum.org/EIPS/eip-4519","discussion":"https://ethereum-magicians.org/search?q=ERC-4519"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"ERC-7578","name":"Physical Asset Redemption","status":"Final","chain":"both","category":{"id":"physical","name":"Physical & Real World","description":"Connecting NFTs to physical items"},"journeyStages":[{"id":"specialized","name":"Specialized Interactions","description":"Physical items, AI, social, gaming"}],"uxImpact":"Users holding physical-asset-backed NFTs can see verified real-world details: who issued it, who holds the physical item, where it's stored, legal terms, and declared value. Design implications: display token issuer, asset holder, storage location as structured fields, link to legal terms (IPFS), show jurisdiction and declared value prominently, design verification badges for issuer reputation. Design decisions: how much legal info to surface upfront vs expandable sections, whether to show issuer verification status, formatting currency/value display, handling missing optional fields gracefully.","hasDetailedContent":true,"content":{"id":"ERC-7578","sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-7578","type":"official-spec"}],"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25","summary":"Users holding physical-asset-backed NFTs can see verified real-world details: who issued it, who holds the physical item, where it's stored, legal terms, and declared value.","designerTakeaways":["You can layout issuer, custodian, storage, and declared value as scannable rows above the fold.","Your legal section can collapse behind View terms with IPFS link and jurisdiction chip.","You can badge Verified issuer when reputation attestation exists."],"applicability":{"whenToUse":["NFTs represent vaulted gold, watches, wine, or redeemable physical goods.","RWA platform uses ERC-7578 metadata schema.","Trust requires issuer and custody transparency."],"whenToAvoid":["Pure digital art with no physical claim.","Metadata lacks structured RWA fields.","Regulatory review cannot support displayed claims."]},"prototypeFirst":[{"screen":"Physical backing summary","why":"Buyer diligence starts at structured fields.","covers":["Full metadata","Missing optional fields"],"include":["Issuer row","Custodian","Storage location","Declared value","Jurisdiction"]},{"screen":"Legal terms expand","why":"Lawyers need access; users need skim.","covers":["Terms linked","Missing terms"],"include":["Collapsed legal section","IPFS link","Jurisdiction badge"]},{"screen":"Redeem physical flow","why":"Holder claims real item.","covers":["Eligible","In transit","Redeemed"],"include":["Redeem CTA","Shipping form","Status tracker"]},{"screen":"Unverified issuer warning","why":"Not all issuers equal trust.","covers":["Verified","Unverified"],"include":["Issuer badge tier","Verify issuer link","Risk disclaimer"]}],"mentalModel":[{"label":"Token","description":"Digital claim on physical asset."},{"label":"Issuer","description":"Entity that minted claim — trust anchor."},{"label":"Custodian","description":"Who physically holds the item."},{"label":"Declared value","description":"Stated worth — not guaranteed market price."},{"label":"Redemption","description":"Process to receive physical item."}],"statesToDesign":[{"state":"Fully documented asset","trigger":"All key fields present.","userNeed":"Trust and compare.","designResponse":"Complete summary card."},{"state":"Missing optional field","trigger":"Storage or terms absent.","userNeed":"Not think broken.","designResponse":"Not provided gray state."},{"state":"Unverified issuer","trigger":"No attestation.","userNeed":"Extra caution.","designResponse":"Unverified issuer warning banner."},{"state":"Redemption in progress","trigger":"User started claim.","userNeed":"Track shipment.","designResponse":"Redemption status stepper."},{"state":"Redeemed — NFT burned or locked","trigger":"Physical delivered.","userNeed":"See completion.","designResponse":"Redeemed archive state."}],"designDecisions":[{"question":"Legal terms upfront?","recommendation":"Collapsed with summary bullets upfront.","rationale":"Compliance accessible without wall of text."},{"question":"Currency display for value?","recommendation":"ISO currency plus formatted amount.","rationale":"Declared value needs unit clarity."},{"question":"Issuer verification tiers?","recommendation":"Verified / Unverified / Unknown badges.","rationale":"Binary verified-only hides nuance."}],"problemsSolved":[{"problem":"Opaque RWA NFTs","oldWay":"JPEG with vague description","newWay":"Structured issuer custody value fields","impact":"critical"},{"problem":"Legal terms inaccessible","oldWay":"Buried broken link","newWay":"IPFS terms with jurisdiction","impact":"high"},{"problem":"Redemption status unknown","oldWay":"Email support only","newWay":"On-app redemption tracker","impact":"medium"}],"uxPatterns":[{"name":"RWA Summary Card","description":"Structured physical backing fields.","mockup":"concept/physical-link","components":["IssuerRow","CustodianRow","ValueDisplay","TermsExpand"],"userFlow":["Open token","Scan backing","Expand legal","Decide trust"]},{"name":"Physical Redemption Tracker","description":"Claim status from request to delivery.","mockup":"concept/physical-link","components":["RedeemCTA","StatusStepper","ShippingForm"],"userFlow":["Tap Redeem","Submit details","Track steps","Mark complete"]}],"seenInTheWild":[{"app":"Courtyard","url":"https://courtyard.io/","note":"Physical collectibles vault and redemption UX."},{"app":"4K","url":"https://4k.com/","note":"Vaulted asset tokenization display patterns."},{"app":"Tether Gold","url":"https://gold.tether.to/","note":"Declared value and custody disclosure."}],"antiPatterns":[{"pattern":"No issuer row on RWA detail","why":"Cannot assess trust","instead":"Issuer first row with verification badge","severity":"critical"},{"pattern":"Declared value without currency","why":"Ambiguous amount","instead":"USD 12,400 formatted","severity":"high"},{"pattern":"Legal terms only as raw IPFS hash","why":"Users cannot access","instead":"View terms button with fetch preview","severity":"medium"}],"vocabulary":[{"use":"Issued by","avoid":"Token issuer address","why":"Entity name primary."},{"use":"Stored at","avoid":"Custodial storage URI","why":"Location language."},{"use":"Declared value","avoid":"Oracle price feed","why":"Legal distinction from market price."}],"onMonad":[{"aspect":"RWA redemption txs","ethereum":"Redeem gas discourages claims","monad":"Lower fees ease physical claim flow","designImplication":"Single-tap redeem start on Monad."},{"aspect":"Metadata refresh","ethereum":"Custody updates slow to show","monad":"Fast updates after custody change events","designImplication":"Inline refresh on issuer status change."}],"technicalNotes":"ERC-7578 RWA fields must distinguish declared value from market price; verify issuer when possible.","relatedStandards":[{"id":"ERC-6672","relationship":"Multi-redemption perks on same NFT"},{"id":"ERC-721","relationship":"Physical asset metadata extension"}]},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-7578","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-7578","type":"discussion"},{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-7578","type":"official-spec"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-7578","markdown":"https://www.eipsfordesigners.com/standards/ERC-7578/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-7578/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-7578","official":"https://eips.ethereum.org/EIPS/erc-7578","discussion":"https://ethereum-magicians.org/search?q=ERC-7578"},"freshness":{"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25"}},{"id":"ERC-6672","name":"Multi-redeemable NFTs","status":"Final","chain":"both","category":{"id":"physical","name":"Physical & Real World","description":"Connecting NFTs to physical items"},"journeyStages":[{"id":"specialized","name":"Specialized Interactions","description":"Physical items, AI, social, gaming"}],"uxImpact":"Users can redeem the same NFT for multiple different perks across different campaigns — a concert ticket NFT might be redeemable for entry, merchandise, and a meet-and-greet separately. Design implications: show list of available redemptions per NFT with status (available/redeemed/shipping), display operator-specific redemption flows, design redemption history view, show which campaigns/operators have active redemptions. Design decisions: how to organize multiple redemptions visually, whether to show redemption status progression (redeemed → paid → shipping), handling operator-specific metadata display, UX for discovering new redemption opportunities.","hasDetailedContent":true,"content":{"id":"ERC-6672","sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-6672","type":"official-spec"}],"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25","summary":"Users can redeem the same NFT for multiple different perks across different campaigns — a concert ticket NFT might be redeemable for entry, merchandise, and a meet-and-greet separately.","designerTakeaways":["You can list Available redemptions as cards with operator name and status per perk.","Your history view can group by campaign with Redeemed → Shipped progression.","You can notify when new redemption opportunities attach to owned tokens."],"applicability":{"whenToUse":["Event or membership NFTs unlock multiple perks over time.","Different operators run separate redemption campaigns.","ERC-6672 tracks per-redemption state."],"whenToAvoid":["Single redeem-then-burn only.","One operator one perk.","Off-chain redemption only with no on-chain status."]},"prototypeFirst":[{"screen":"Multi-redemption dashboard","why":"Holder sees all perks at once.","covers":["3 available","Mixed status","All redeemed"],"include":["Perk cards","Status pills","Operator label","Redeem CTA each"]},{"screen":"Single perk redeem flow","why":"Each operator flow may differ.","covers":["Digital perk","Physical ship"],"include":["Operator branding","Form fields","Confirm redeem"]},{"screen":"Redemption history timeline","why":"Audit past claims across campaigns.","covers":["History list"],"include":["Date","Perk name","Status progression"]},{"screen":"New perk discovery","why":"Campaigns add redemptions post-mint.","covers":["New badge on perk"],"include":["New redemption available toast","Highlight in list"]}],"mentalModel":[{"label":"One NFT","description":"Single token holds multiple redemption rights."},{"label":"Redemption slot","description":"Independent perk with own status."},{"label":"Operator","description":"Party fulfilling specific redemption."},{"label":"Status progression","description":"Available → Redeemed → Shipped per perk."},{"label":"Exhaustion","description":"Each perk redeem once unless multi-use defined."}],"statesToDesign":[{"state":"Perk available","trigger":"Not yet redeemed.","userNeed":"Claim clearly.","designResponse":"Green Available with Redeem CTA."},{"state":"Redeemed — processing","trigger":"On-chain redeem done; fulfillment pending.","userNeed":"Track fulfillment.","designResponse":"Redeemed — preparing shipment."},{"state":"Shipped / fulfilled","trigger":"Operator completed.","userNeed":"See done.","designResponse":"Fulfilled checkmark; no CTA."},{"state":"New perk added","trigger":"Campaign update.","userNeed":"Discover new value.","designResponse":"New badge and notification."},{"state":"All perks exhausted","trigger":"Every slot used.","userNeed":"See memento value.","designResponse":"All rewards claimed summary."}],"designDecisions":[{"question":"Organize by operator or perk type?","recommendation":"Group by operator with perk subtitles.","rationale":"Support routes to operator."},{"question":"Show shipping progression?","recommendation":"Yes for physical; instant for digital.","rationale":"Different expectations per perk type."},{"question":"Discovery of new redemptions?","recommendation":"Push plus in-app New on token card.","rationale":"Post-mint campaigns add value."}],"problemsSolved":[{"problem":"One redeem burns all perks","oldWay":"Single consume destroys other rights","newWay":"Independent redemption slots per perk","impact":"high"},{"problem":"Confusion which vendor fulfills what","oldWay":"Single support email","newWay":"Operator label on each redemption card","impact":"medium"},{"problem":"Lost track of claimed perks","oldWay":"No history","newWay":"Redemption timeline per NFT","impact":"medium"}],"uxPatterns":[{"name":"Multi-Redemption List","description":"Per-perk cards with status and operator.","mockup":"concept/physical-link","components":["PerkCard","StatusPill","OperatorLabel"],"userFlow":["Open NFT","See perks","Redeem one","Status updates independently"]},{"name":"Redemption History","description":"Timeline of claims across campaigns.","mockup":"concept/reactions","components":["HistoryTimeline","StatusProgress"],"userFlow":["Open history","See past redeems","Track shipping"]}],"seenInTheWild":[{"app":"VeeFriends","url":"https://veefriends.com/","note":"Multi-benefit token experiences."},{"app":"Courtyard","url":"https://courtyard.io/","note":"Physical redemption status tracking."},{"app":"Ticketmaster NFT","url":"https://www.ticketmaster.com/","note":"Event perk redemption patterns."}],"antiPatterns":[{"pattern":"Single Redeem button for all perks","why":"Claims wrong perk or all at once","instead":"Separate CTA per perk card","severity":"critical"},{"pattern":"No operator label","why":"Support chaos","instead":"Operator name on every perk row","severity":"high"},{"pattern":"Hiding fulfilled perks","why":"User cannot prove attendance","instead":"History tab with fulfilled state","severity":"medium"}],"vocabulary":[{"use":"Available reward","avoid":"Redemption slot 2","why":"Perk language."},{"use":"Claimed","avoid":"Redemption executed","why":"User past tense."},{"use":"Fulfilled by [operator]","avoid":"Operator callback complete","why":"Plain fulfillment copy."}],"onMonad":[{"aspect":"Multiple redeem txs","ethereum":"Gas discourages claiming all perks","monad":"Low fees enable claiming every perk","designImplication":"Batch redeem optional on Monad."},{"aspect":"Status updates","ethereum":"Shipping status lag","monad":"Fast on-chain redeem confirmation","designImplication":"Instant Redeemed state after claim on Monad."}],"technicalNotes":"ERC-6672 tracks independent redemption states; never use one button for all perks.","relatedStandards":[{"id":"ERC-7578","relationship":"Physical asset backing complement"},{"id":"ERC-2135","relationship":"Single consumable redeem pattern"}]},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-6672","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-6672","type":"discussion"},{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-6672","type":"official-spec"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-6672","markdown":"https://www.eipsfordesigners.com/standards/ERC-6672/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-6672/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-6672","official":"https://eips.ethereum.org/EIPS/erc-6672","discussion":"https://ethereum-magicians.org/search?q=ERC-6672"},"freshness":{"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25"}},{"id":"ERC-5570","name":"Digital Receipt NFTs","status":"Final","chain":"both","category":{"id":"physical","name":"Physical & Real World","description":"Connecting NFTs to physical items"},"journeyStages":[{"id":"specialized","name":"Specialized Interactions","description":"Physical items, AI, social, gaming"}],"uxImpact":"Users receive NFT receipts for purchases containing structured transaction data — vendor info, line items, prices, tax, serial numbers — all on-chain and parseable by financial software. Design implications: render receipt metadata as formatted document view, show vendor branding (logo, contact), display itemized list with quantities/prices/tax, provide print/export functionality, show digital signature verification. Design decisions: how receipt-like vs NFT-like to make the display, handling PII privacy (encryption indicators), whether to integrate with accounting software exports, mobile-friendly receipt viewing.","hasDetailedContent":true,"content":{"id":"ERC-5570","sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-5570","type":"official-spec"}],"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25","summary":"Users receive NFT receipts for purchases containing structured transaction data — vendor info, line items, prices, tax, serial numbers — all on-chain and parseable by financial software.","designerTakeaways":["You can render receipt NFTs as formatted documents with vendor logo and itemized rows.","Your export can offer PDF/CSV for accounting without exposing raw JSON.","You can show Verified receipt when digital signature validates."],"applicability":{"whenToUse":["On-chain purchase proofs for commerce or B2B.","ERC-5570 receipt schema in metadata.","Users need print/export for expenses."],"whenToAvoid":["Generic NFT without receipt structure.","PII cannot be handled compliantly on-chain.","Receipt data off-chain only."]},"prototypeFirst":[{"screen":"Receipt document view","why":"Primary read mode is document not art.","covers":["Full receipt","Mobile narrow"],"include":["Vendor header","Line items","Tax total","Serial numbers"]},{"screen":"Print and export","why":"Expense reporting needs offline copy.","covers":["Print","PDF export"],"include":["Print stylesheet","Export PDF","Export CSV"]},{"screen":"Signature verification","why":"Trust tamper-evidence.","covers":["Valid","Invalid"],"include":["Verified receipt badge","Verify action","Issuer key info collapsed"]},{"screen":"PII encryption indicator","why":"Sensitive fields need trust cues.","covers":["Encrypted fields"],"include":["Lock icon on PII","Decrypt if authorized"]}],"mentalModel":[{"label":"Receipt NFT","description":"Proof of purchase, not primarily art."},{"label":"Line items","description":"Structured rows — qty, price, tax."},{"label":"Vendor block","description":"Seller identity and contact."},{"label":"Verification","description":"Signature proves issuer authenticity."},{"label":"Export","description":"Bridge to accounting tools off-chain."}],"statesToDesign":[{"state":"Standard receipt display","trigger":"Valid metadata.","userNeed":"Read like paper receipt.","designResponse":"Document layout default."},{"state":"Verified signature","trigger":"Sig valid.","userNeed":"Trust document.","designResponse":"Verified receipt chip."},{"state":"Verification failed","trigger":"Tampered or bad sig.","userNeed":"Not trust blindly.","designResponse":"Verification failed warning."},{"state":"Encrypted PII","trigger":"Sensitive fields encrypted.","userNeed":"Know privacy protected.","designResponse":"Encrypted field indicators."},{"state":"Export in progress","trigger":"User exports PDF.","userNeed":"Get file.","designResponse":"Generating export spinner."}],"designDecisions":[{"question":"Receipt-like vs NFT-art layout?","recommendation":"Document default; art tab secondary if dual media.","rationale":"Use case is record-keeping."},{"question":"Accounting software integration?","recommendation":"CSV export first; direct integrations later.","rationale":"Export lowest common denominator."},{"question":"Mobile receipt view?","recommendation":"Single column stacked rows; sticky total.","rationale":"Receipts read on phone at returns desk."}],"problemsSolved":[{"problem":"No standard on-chain receipt format","oldWay":"Screenshot or email lost","newWay":"Structured parseable receipt NFT","impact":"high"},{"problem":"Expense report friction","oldWay":"Manual entry from tx hash","newWay":"Export PDF/CSV from receipt view","impact":"medium"},{"problem":"Fake receipt claims","oldWay":"Editable metadata","newWay":"Signature verification badge","impact":"high"}],"uxPatterns":[{"name":"Receipt Document Renderer","description":"Formatted vendor line items and totals.","mockup":"concept/physical-link","components":["VendorHeader","LineItemTable","TaxRow","TotalBar"],"userFlow":["Open receipt NFT","Read document","Print or export"]},{"name":"Receipt Verification Badge","description":"Signature verify on detail.","mockup":"concept/verify-safety","components":["VerifyButton","VerifiedChip"],"userFlow":["Tap Verify","Check sig","Show verified or failed"]}],"seenInTheWild":[{"app":"Shopify","url":"https://www.shopify.com/","note":"Email receipt layout reference."},{"app":"Flexa","url":"https://flexa.network/","note":"Commerce payment receipt patterns."},{"app":"Etherscan","url":"https://etherscan.io/","note":"Transaction detail labeling for line-item metaphors."}],"antiPatterns":[{"pattern":"Receipt NFT as square art only","why":"Misses document utility","instead":"Document layout as default view","severity":"high"},{"pattern":"PII in plaintext on public explorer","why":"Privacy violation","instead":"Encryption indicators and redaction","severity":"critical"},{"pattern":"No export path","why":"Cannot use for accounting","instead":"Print and CSV export actions","severity":"medium"}],"vocabulary":[{"use":"Receipt","avoid":"Digital receipt NFT metadata","why":"Commerce term."},{"use":"Line items","avoid":"Structured calldata array","why":"Shopping language."},{"use":"Verified receipt","avoid":"Signature valid","why":"Trust badge language."}],"onMonad":[{"aspect":"Receipt mint at checkout","ethereum":"Gas adds checkout friction","monad":"Cheap receipt mint at point of sale","designImplication":"Auto-mint receipt NFT on Monad checkout."},{"aspect":"Export after purchase","ethereum":"Slow confirm before export","monad":"Instant export after sub-second mint","designImplication":"Show export immediately post-purchase on Monad."}],"technicalNotes":"ERC-5570 receipt view should default to document layout; handle PII with encryption indicators.","relatedStandards":[{"id":"ERC-7578","relationship":"Physical asset backing on other RWAs"},{"id":"ERC-721","relationship":"Receipt as NFT metadata schema"}]},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-5570","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-5570","type":"discussion"},{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-5570","type":"official-spec"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-5570","markdown":"https://www.eipsfordesigners.com/standards/ERC-5570/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-5570/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-5570","official":"https://eips.ethereum.org/EIPS/erc-5570","discussion":"https://ethereum-magicians.org/search?q=ERC-5570"},"freshness":{"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25"}},{"id":"ERC-7857","name":"AI Agents NFT with Private Metadata","status":"Draft","chain":"both","category":{"id":"ai","name":"AI & Agents","description":"AI-generated content and agent coordination"},"journeyStages":[{"id":"specialized","name":"Specialized Interactions","description":"Physical items, AI, social, gaming"}],"uxImpact":"Users own AI agent NFTs where the valuable data (model weights, memory, personality) is private and encrypted — transferring the NFT securely transfers the encrypted agent data with verified handoff. Design implications: show agent capabilities/description publicly, indicate private metadata exists without revealing it, design secure transfer flow with proof verification, display data ownership proofs, show authorized users who can run the agent. Design decisions: how to visualize TEE vs ZKP verification status, UX for cloning agents (vs full transfer), managing authorized users list, handling transfer failures in proof verification, showing sealed key delivery status.","hasDetailedContent":true,"content":{"id":"ERC-7857","summary":"ERC-7857 creates NFTs that represent AI agents with private metadata. The public NFT shows the agent's identity and capabilities, while encrypted metadata stores configuration, API keys, and training data. Only the NFT owner can access the private data, enabling tradeable AI agents with protected intellectual property.","applicability":{"whenToUse":["Your product addresses: aI agent configuration isn't portable or tradeable.","Your product addresses: sensitive AI config exposed on-chain.","The flow should deliver: agent as NFT, transfer ownership = transfer agent.","You are designing a agent nft profile experience with visible states and recovery paths."],"whenToAvoid":["Verify ownership before any decryption.","Explicit warning about what transfers with NFT.","Always use private encrypted metadata for secrets.","No agent, automation, or delegated task UX is in scope."]},"designerTakeaways":["You can design UI that delivers agent as NFT, transfer ownership = transfer agent.","You can design UI that delivers private metadata encrypted, only owner can decrypt.","You can design UI that delivers on-chain record of creator, transfers, modifications."],"problemsSolved":[{"problem":"AI agent configuration isn't portable or tradeable","oldWay":"Agent settings stuck on one platform, can't transfer","newWay":"Agent as NFT - transfer ownership = transfer agent","impact":"critical"},{"problem":"Sensitive AI config exposed on-chain","oldWay":"API keys and prompts visible to everyone","newWay":"Private metadata encrypted, only owner can decrypt","impact":"critical"},{"problem":"No provenance for AI agents","oldWay":"Can't verify who created an agent or its history","newWay":"On-chain record of creator, transfers, modifications","impact":"high"},{"problem":"AI agents can't have on-chain identity","oldWay":"Agents are anonymous off-chain processes","newWay":"Agent NFT = verifiable identity for the agent","impact":"high"}],"uxPatterns":[{"name":"Agent NFT Profile","description":"Public profile of an AI agent","mockup":"concept/nft-gallery","userFlow":["Browse AI agent marketplace","View public agent profile","See capabilities and performance","Private config hidden unless owner","Make offer to purchase agent"]},{"name":"Owner Dashboard","description":"Manage owned agent with private config access","mockup":"concept/agent-task","userFlow":["Owner views their agent","Decrypt private metadata","See full configuration","Edit config if needed","Option to export or transfer"]},{"name":"Agent Deployment","description":"Deploy agent to execution environment","mockup":"generic/token-approval","userFlow":["Select where to run agent","Configure permissions/limits","Private config sent securely","Agent starts operating","Monitor performance"]},{"name":"Agent Transfer Warning","description":"Clear disclosure when selling agent","mockup":"concept/nft-gallery","userFlow":["User initiates agent transfer","Show what buyer will receive","Warn about sensitive data transfer","Suggest API key rotation","Confirm with clear understanding"]}],"uiComponents":[{"name":"AgentProfileCard","description":"Public-facing agent NFT display","states":["loading","public-view","owner-view"],"props":["agentId","publicMetadata","isOwner"]},{"name":"PrivateConfigViewer","description":"Decrypt and display private metadata","states":["locked","decrypting","unlocked","error"],"props":["encryptedData","onDecrypt"]},{"name":"CapabilityBadges","description":"Visual representation of agent capabilities","states":["verified","unverified","claimed"],"props":["capabilities[]"]},{"name":"AgentDeploymentPanel","description":"Configure and deploy agent","states":["configuring","deploying","running","stopped"],"props":["agent","targets[]","permissions[]","onDeploy"]}],"antiPatterns":[{"pattern":"Showing decrypted config to non-owners","why":"Violates the core privacy promise of the standard","instead":"Verify ownership before any decryption","severity":"critical"},{"pattern":"Not warning about config transfer on sale","why":"Sellers may not realize buyer gets their secrets","instead":"Explicit warning about what transfers with NFT","severity":"critical"},{"pattern":"Storing API keys in plain metadata","why":"Keys visible to everyone, security nightmare","instead":"Always use private encrypted metadata for secrets","severity":"critical"},{"pattern":"No capability verification","why":"Agents can claim abilities they don't have","instead":"Show verified vs claimed capabilities differently","severity":"high"}],"onMonad":[{"aspect":"Agent Execution","ethereum":"Agent actions take 15+ seconds","monad":"Sub-second agent actions","designImplication":"Agents can respond to market conditions in real-time"},{"aspect":"On-chain Agents","ethereum":"Too expensive for frequent agent operations","monad":"Affordable on-chain agent execution","designImplication":"Can run agent logic directly on-chain"},{"aspect":"Metadata Updates","ethereum":"Updating agent config expensive","monad":"Cheap config updates","designImplication":"Agents can evolve and update frequently"},{"aspect":"Agent Communication","ethereum":"Agent-to-agent messaging expensive","monad":"Cheap inter-agent communication","designImplication":"Enable agent collaboration and coordination"}],"keyTakeaways":["Agent NFT = tradeable AI with protected secrets","Private metadata ONLY accessible by owner","Warn clearly about what transfers with ownership","Show verified vs claimed capabilities","On Monad: cheap/fast enables responsive on-chain agents"],"technicalNotes":"ERC-7857 extends ERC-721 with private metadata storage. Private data is encrypted with owner's public key and stored on-chain (or IPFS with on-chain hash). On transfer, the new owner re-encrypts with their key. The standard defines capability attestations and a registry for agent coordination. Integrates with ERC-8001 for agent-to-agent communication."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-7857","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-7857","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-7857","markdown":"https://www.eipsfordesigners.com/standards/ERC-7857/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-7857/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-7857","official":"https://eips.ethereum.org/EIPS/eip-7857","discussion":"https://ethereum-magicians.org/search?q=ERC-7857"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"ERC-8001","name":"Agent Coordination Framework","status":"Draft","chain":"both","category":{"id":"ai","name":"AI & Agents","description":"AI-generated content and agent coordination"},"journeyStages":[{"id":"specialized","name":"Specialized Interactions","description":"Physical items, AI, social, gaming"}],"uxImpact":"Users (or their AI agents) coordinate multi-party actions on-chain — an initiator proposes an intent, all required participants sign acceptances, then the coordinated action executes atomically. Design implications: show coordination status flow (Proposed → Ready → Executed), display participant list with acceptance status checkmarks, show intent expiry countdown, design acceptance signing flow for participants. Design decisions: how to present coordination to non-technical users, visualizing multi-party consent gathering, handling partial acceptance states, showing coordination type/purpose clearly, timeout and cancellation flows.","hasDetailedContent":true,"content":{"id":"ERC-8001","sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-8001","type":"official-spec"}],"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25","summary":"Users (or their AI agents) coordinate multi-party actions on-chain — an initiator proposes an intent, all required participants sign acceptances, then the coordinated action executes atomically.","designerTakeaways":["You can show Proposed → Ready → Executed timeline with checkmarks per participant.","Your acceptance flow uses plain language: Agree to this group action, not Sign coordination payload.","You can display intent expiry countdown and Cancel coordination for initiator."],"applicability":{"whenToUse":["Multi-party atomic actions need explicit consent gathering.","AI agents or humans co-sign coordinated intents.","ERC-8001 coordinator contracts power flow."],"whenToAvoid":["Single-signer transactions.","Draft spec without working coordinator.","Users cannot understand multi-party consent."]},"prototypeFirst":[{"screen":"Coordination proposal detail","why":"Participants review what group will do.","covers":["Proposed","Partial accept","Ready"],"include":["Human intent summary","Participant list","Expiry timer","Accept button"]},{"screen":"Initiator create coordination","why":"Proposer sets participants and intent.","covers":["Create","Submit proposal"],"include":["Intent description","Participant picker","Expiry setting"]},{"screen":"Participant acceptance sign","why":"Each party confirms individually.","covers":["Pending your sign","You accepted"],"include":["Summary mirror","Accept/Decline","Your checkmark on list"]},{"screen":"Executed or expired outcome","why":"Terminal states need closure.","covers":["Executed success","Expired cancel"],"include":["Outcome banner","Explorer link","Retry or new proposal"]}],"mentalModel":[{"label":"Intent","description":"Plain-language description of group outcome."},{"label":"Participants","description":"Addresses that must accept."},{"label":"Acceptance","description":"Each signature adds checkmark — not execution yet."},{"label":"Ready","description":"All accepted — execution can proceed."},{"label":"Expiry","description":"Timer cancels if not complete — prevents limbo."}],"statesToDesign":[{"state":"Proposed — awaiting accepts","trigger":"Some participants pending.","userNeed":"See who missing.","designResponse":"Checklist with pending avatars."},{"state":"Your acceptance required","trigger":"Connected user is pending participant.","userNeed":"Review and agree.","designResponse":"Prominent Accept this group action CTA."},{"state":"Ready to execute","trigger":"All accepted.","userNeed":"Know execution imminent.","designResponse":"Ready banner; auto or manual execute per rules."},{"state":"Executed","trigger":"On-chain success.","userNeed":"Confirmation.","designResponse":"Completed with outcome summary."},{"state":"Expired","trigger":"Timer elapsed.","userNeed":"Not think stuck.","designResponse":"Expired — not enough approvals in time."}],"designDecisions":[{"question":"How technical is intent summary?","recommendation":"Human outcome first; calldata in advanced.","rationale":"Agents still need human-readable consent."},{"question":"Visualize partial acceptance?","recommendation":"Progress bar N of M accepted.","rationale":"Limbo needs progress not static pending."},{"question":"Initiator cancel before expiry?","recommendation":"Allow cancel with notify participants.","rationale":"Plans change — need escape hatch."}],"problemsSolved":[{"problem":"Multi-party txs require manual sequencing","oldWay":"Sign one by one hope others follow","newWay":"Atomic execution after all accept","impact":"high"},{"problem":"Unclear who blocked coordination","oldWay":"Stuck pending forever","newWay":"Participant checklist with pending labels","impact":"high"},{"problem":"Agent intents opaque to humans","oldWay":"Raw calldata only","newWay":"Human intent summary layer","impact":"medium"}],"uxPatterns":[{"name":"Coordination Checklist","description":"Participant acceptance progress toward Ready.","mockup":"concept/agent-task","components":["ParticipantRow","AcceptCheckmark","ExpiryTimer"],"userFlow":["Proposal live","Participants accept","All checkmarks","Executes"]},{"name":"Group Action Accept Flow","description":"Plain-language accept for participants.","mockup":"concept/permit-approval","components":["IntentSummary","AcceptButton","DeclineOption"],"userFlow":["Review intent","Accept","Checkmark appears","Wait for others"]}],"seenInTheWild":[{"app":"Safe","url":"https://safe.global/","note":"Multi-sig approval checklist patterns."},{"app":"CowSwap","url":"https://cow.fi/","note":"Coordinated settlement consent UX."},{"app":"Virtuals Protocol","url":"https://virtuals.io/","note":"Agent coordination on-chain experiments."}],"antiPatterns":[{"pattern":"Coordination without expiry timer","why":"Infinite limbo","instead":"Countdown and expired terminal state","severity":"critical"},{"pattern":"Raw intent calldata as only preview","why":"Humans cannot consent","instead":"Human summary with advanced disclosure","severity":"high"},{"pattern":"No initiator cancel","why":"Stuck proposals","instead":"Cancel coordination action","severity":"medium"}],"vocabulary":[{"use":"Group action","avoid":"Coordination intent hash","why":"Plain multi-party language."},{"use":"Waiting for [name]","avoid":"Participant pending signature","why":"Checklist copy."},{"use":"Everyone agreed","avoid":"Threshold reached","why":"Human ready state."}],"onMonad":[{"aspect":"Multi-party gather speed","ethereum":"Slow blocks extend coordination window","monad":"Fast acceptance updates refresh checklist quickly","designImplication":"Live checklist refresh on Monad without manual reload."},{"aspect":"Agent coordination cost","ethereum":"Proposal and accept txs costly","monad":"Lower fees for agent-heavy coordination loops","designImplication":"Enable lighter-weight agent proposals on Monad."}],"technicalNotes":"ERC-8001 is draft; always show expiry and human intent summary for every coordination.","relatedStandards":[{"id":"ERC-4337","relationship":"Smart accounts may participate as agents"},{"id":"EIP-712","relationship":"Typed data for acceptance signatures"}]},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-8001","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-8001","type":"discussion"},{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-8001","type":"official-spec"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-8001","markdown":"https://www.eipsfordesigners.com/standards/ERC-8001/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-8001/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-8001","official":"https://eips.ethereum.org/EIPS/erc-8001","discussion":"https://ethereum-magicians.org/search?q=ERC-8001"},"freshness":{"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25"}},{"id":"ERC-6381","name":"Public NFT Emote Repository","status":"Final","chain":"both","category":{"id":"social","name":"Social & Messaging","description":"Communication and reactions"},"journeyStages":[{"id":"specialized","name":"Specialized Interactions","description":"Physical items, AI, social, gaming"}],"uxImpact":"Users can react to any NFT with emoji (like social media reactions) — reactions are stored on-chain in a public repository, enabling social signals around NFT value and desirability. Design implications: show emoji reaction counts on NFT cards, design emoji picker for reacting, display top reactions and total counts, show 'you reacted' state for user's own reactions, enable bulk reactions across multiple NFTs. Design decisions: which emojis to feature prominently, whether to show who reacted (privacy vs transparency), handling presigned reactions for gasless UX, reaction count display (exact vs abbreviated), emoji display consistency across platforms.","hasDetailedContent":true,"content":{"id":"ERC-6381","summary":"ERC-6381 creates a universal reaction system for NFTs - like social media reactions but on-chain. Anyone can \"emote\" on any NFT (❤️, 🔥, 😂, etc.) and these reactions are stored permanently on the blockchain. Collections can see engagement metrics, owners can showcase popular items, and the social layer becomes part of the NFT itself.","applicability":{"whenToUse":["Your product addresses: nFT engagement lives on Twitter/Discord, not with the NFT.","Your product addresses: no standard way to show NFT popularity.","The flow should deliver: reactions permanently attached to NFT, always visible.","You are designing a nft reaction bar experience with visible states and recovery paths."],"whenToAvoid":["Show \"~$0.02\" or similar before sending reaction.","Show reaction summary on marketplace listings.","Show top 8-12 popular emojis, expandable for more.","No social graph, messaging, or public profile surfaces exist."]},"designerTakeaways":["You can design UI that delivers reactions permanently attached to NFT, always visible.","You can design UI that delivers on-chain reaction counts show real community sentiment.","You can design UI that delivers fully on-chain, works everywhere, censorship resistant."],"problemsSolved":[{"problem":"NFT engagement lives on Twitter/Discord, not with the NFT","oldWay":"Reactions scattered across platforms, lost when posts deleted","newWay":"Reactions permanently attached to NFT, always visible","impact":"high"},{"problem":"No standard way to show NFT popularity","oldWay":"Check sales, followers, guess at engagement","newWay":"On-chain reaction counts show real community sentiment","impact":"high"},{"problem":"Social features require centralized services","oldWay":"Like buttons need backend, database, APIs","newWay":"Fully on-chain, works everywhere, censorship resistant","impact":"medium"},{"problem":"Can't verify if engagement is authentic","oldWay":"Bots can spam likes on centralized platforms","newWay":"Each reaction from real wallet, costs gas, verifiable","impact":"medium"}],"uxPatterns":[{"name":"NFT Reaction Bar","description":"Show reactions below NFT like social media","mockup":"concept/nft-gallery","userFlow":["User views NFT","See reaction counts below image","Click emoji to add same reaction","Or click \"Add Reaction\" for picker","Sign transaction to record reaction","Count updates, user in reactors list"]},{"name":"Reaction Picker","description":"Choose which emote to send","mockup":"concept/nft-gallery","userFlow":["User clicks \"Add Reaction\"","Emoji picker opens","Select desired emoji","See cost estimate","Click send","Sign transaction, reaction recorded"]},{"name":"Collection Engagement Dashboard","description":"Analytics for collection reactions","mockup":"concept/nft-gallery","userFlow":["Collection owner views dashboard","See total reactions across collection","Breakdown by emoji type","See most popular NFTs","Track engagement over time","Use data for community insights"]},{"name":"My Reactions Feed","description":"Track your reactions across NFTs","mockup":"concept/nft-gallery","userFlow":["User views their profile","See all NFTs they've reacted to","Each shows which emotes they sent","Can remove reactions if desired","See personal emoji usage stats"]}],"uiComponents":[{"name":"ReactionBar","description":"Displays reactions with counts","states":["loading","loaded","updating"],"props":["reactions","onReact","userReactions"]},{"name":"EmojiPicker","description":"Select emoji to react with","states":["closed","open","selecting","sending"],"props":["allowedEmojis","onSelect","disabled"]},{"name":"ReactionCounter","description":"Single emoji with count","states":["inactive","active","user-reacted"],"props":["emoji","count","onClick","highlighted"]},{"name":"CollectionEngagement","description":"Dashboard for collection reaction stats","states":["loading","loaded","empty"],"props":["collection","reactions","timeRange"]}],"antiPatterns":[{"pattern":"Not showing that reactions cost gas","why":"Users surprised by transaction popup for \"free\" action","instead":"Show \"~$0.02\" or similar before sending reaction","severity":"high"},{"pattern":"Hiding reaction counts on listings","why":"Engagement signals hidden from buyers","instead":"Show reaction summary on marketplace listings","severity":"medium"},{"pattern":"Too many emoji options overwhelming users","why":"Analysis paralysis, users don't react","instead":"Show top 8-12 popular emojis, expandable for more","severity":"medium"},{"pattern":"No way to remove reactions","why":"Mistaken reactions stuck forever","instead":"Allow unreacting (also on-chain transaction)","severity":"low"},{"pattern":"Not explaining permanence","why":"Users think it's like Twitter likes","instead":"Note: \"On-chain reactions are permanent and public\"","severity":"medium"}],"onMonad":[{"aspect":"Reaction Speed","ethereum":"Reaction takes 15+ seconds to confirm","monad":"Sub-second reaction recording","designImplication":"Feels like normal social media, instant feedback"},{"aspect":"Cost per Reaction","ethereum":"Each reaction costs $0.50-5","monad":"Reactions cost fractions of a cent","designImplication":"Users can react freely without financial concern"},{"aspect":"Multiple Reactions","ethereum":"Adding several emojis is expensive","monad":"React with many emojis cheaply","designImplication":"Enable multi-emoji reactions in single transaction"},{"aspect":"Real-time Updates","ethereum":"Polling for new reactions is slow","monad":"Near real-time reaction updates","designImplication":"Live reaction counts as people engage"}],"keyTakeaways":["ERC-6381 = on-chain emoji reactions for NFTs","Engagement metrics become part of the NFT itself","Show costs clearly before sending reactions","Display reaction counts on marketplace listings","On Monad: cheap enough for casual social engagement"],"technicalNotes":"ERC-6381 defines a public repository contract where anyone can call emote(collection, tokenId, emoji, state). The emoji is stored as bytes4 (UTF-8 encoded). State is boolean for react/unreact. Events are emitted for indexing. Collections can optionally restrict allowed emojis. getEmoteCount(collection, tokenId, emoji) returns current count."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-6381","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-6381","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-6381","markdown":"https://www.eipsfordesigners.com/standards/ERC-6381/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-6381/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-6381","official":"https://eips.ethereum.org/EIPS/eip-6381","discussion":"https://ethereum-magicians.org/search?q=ERC-6381"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"ERC-7409","name":"Public NFT Emote Repository V2","status":"Final","chain":"both","category":{"id":"social","name":"Social & Messaging","description":"Communication and reactions"},"journeyStages":[{"id":"specialized","name":"Specialized Interactions","description":"Physical items, AI, social, gaming"}],"uxImpact":"Users can react to any NFT with full Unicode emoji support including skin tones and variations — supersedes ERC-6381 with string-based emoji encoding for future compatibility. Design implications: same as ERC-6381 but with full emoji picker including skin tone variants, handle variable-length emoji rendering, show diverse emoji options. Design decisions: whether to group emoji variants or show individually, handling emoji that render differently across devices, search/filter in expanded emoji set, backwards compatibility display for collections using both standards.","hasDetailedContent":true,"content":{"id":"ERC-7409","sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-7409","type":"official-spec"}],"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25","summary":"Users can react to any NFT with full Unicode emoji support including skin tones and variations — supersedes ERC-6381 with string-based emoji encoding for future compatibility.","designerTakeaways":["You can attach reaction bar below any NFT with recent emoji shortcuts plus full picker.","Your picker includes skin tone modifiers on people emoji per Unicode standards.","You can group variant emoji in picker while showing individual counts on display."],"applicability":{"whenToUse":["Social layer on NFT galleries or feeds.","Platform adopts ERC-7409 emote registry.","Full Unicode emoji expression matters."],"whenToAvoid":["No social reactions in product.","Only legacy ERC-6381 without migration plan.","On-chain storage cost prohibitive for reactions."]},"prototypeFirst":[{"screen":"NFT reaction bar","why":"Primary social interaction surface.","covers":["No reactions","Popular reactions","Your reaction"],"include":["Quick emoji row","Add reaction","Count badges"]},{"screen":"Full emoji picker","why":"7409 value is full Unicode including skin tones.","covers":["Picker open","Skin tone select"],"include":["Category tabs","Skin tone long-press","Search"]},{"screen":"Reaction list expand","why":"See who reacted with what.","covers":["Reaction aggregations"],"include":["Emoji group headers","User list per emoji","Remove your reaction"]},{"screen":"Legacy 6381 fallback display","why":"Collections may mix standards.","covers":["6381 only","7409 only","Mixed"],"include":["Unified display layer","Migration note in advanced"]}],"mentalModel":[{"label":"Reaction","description":"Unicode emoji string attached to NFT by user."},{"label":"Registry","description":"Public repository aggregating reactions cross-app."},{"label":"Skin tone modifier","description":"Fitzpatrick codes combine with base emoji."},{"label":"Variable length","description":"Some emoji multi-codepoint — render as single glyph."},{"label":"6381 legacy","description":"Older encoding — migrate display for compatibility."}],"statesToDesign":[{"state":"No reactions yet","trigger":"First visitor.","userNeed":"Discover feature.","designResponse":"Subtle Add reaction affordance."},{"state":"User reacted","trigger":"Connected wallet reacted.","userNeed":"Change or remove.","designResponse":"Highlight your emoji; tap to change."},{"state":"Picker open","trigger":"User adds reaction.","userNeed":"Find emoji including tones.","designResponse":"Full picker with search."},{"state":"Cross-device render diff","trigger":"Unsupported glyph.","userNeed":"Not broken boxes.","designResponse":"Fallback placeholder with tooltip."},{"state":"Reaction tx pending","trigger":"On-chain reaction submitting.","userNeed":"Optimistic UI.","designResponse":"Show pending reaction gray until confirm."}],"designDecisions":[{"question":"Group skin tone variants in counts?","recommendation":"Separate counts per exact string; optional rollup in analytics only.","rationale":"👍 vs 👍🏽 are distinct user expressions."},{"question":"On-chain vs off-chain reactions?","recommendation":"Match product — if on-chain show pending tx state.","rationale":"Cost vs permanence tradeoff."},{"question":"Picker search?","recommendation":"Required for expanded set.","rationale":"Full Unicode too large to browse only."}],"problemsSolved":[{"problem":"Limited reaction set","oldWay":"6381 constrained encoding","newWay":"Full Unicode string emoji","impact":"medium"},{"problem":"No skin tone representation","oldWay":"Yellow only emoji","newWay":"Tone modifiers in picker","impact":"medium"},{"problem":"Silent NFT social layer","oldWay":"No reactions on art","newWay":"Cross-app emote registry on any NFT","impact":"low"}],"uxPatterns":[{"name":"NFT Emoji Reaction Bar","description":"Quick react plus counts under NFT.","mockup":"concept/reactions","components":["ReactionBar","EmojiCount","AddButton"],"userFlow":["View NFT","Tap emoji","Count updates","Others see reaction"]},{"name":"Full Unicode Picker","description":"Skin tone support and search.","mockup":"concept/reactions","components":["EmojiPicker","SkinTonePopover","SearchField"],"userFlow":["Open picker","Long press for tone","Select","Reaction posts"]}],"seenInTheWild":[{"app":"Lens Protocol","url":"https://lens.xyz/","note":"Social reactions on content."},{"app":"Farcaster","url":"https://farcaster.xyz/","note":"Emoji reaction patterns in feeds."},{"app":"OpenSea","url":"https://opensea.io/","note":"NFT engagement feature experiments."}],"antiPatterns":[{"pattern":"6381-only picker without tones","why":"7409 upgrade value lost","instead":"Full Unicode picker with modifiers","severity":"medium"},{"pattern":"Broken tofu boxes for valid emoji","why":"Looks broken","instead":"Font fallback stack and placeholder","severity":"high"},{"pattern":"Reactions without remove/change","why":"Regret permanent wrong emoji","instead":"Tap your reaction to edit","severity":"medium"}],"vocabulary":[{"use":"React","avoid":"Post emote to registry","why":"Social verb."},{"use":"Reactions","avoid":"Emote repository entries","why":"Familiar social term."},{"use":"Change reaction","avoid":"Update emote string","why":"Edit action language."}],"onMonad":[{"aspect":"On-chain reactions","ethereum":"Gas per reaction limits spam but adds cost","monad":"Low fees enable reactive social layers","designImplication":"On-chain reactions viable on Monad galleries."},{"aspect":"Reaction confirm speed","ethereum":"Slow pending reaction state","monad":"Quick confirm for optimistic UI","designImplication":"Short pending window on reaction bar."}],"technicalNotes":"ERC-7409 uses string emoji; handle multi-codepoint glyphs and 6381 legacy display.","relatedStandards":[{"id":"ERC-6381","relationship":"Prior emote standard superseded"},{"id":"ERC-721","relationship":"Reactions attach to any NFT"}]},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-7409","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-7409","type":"discussion"},{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-7409","type":"official-spec"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-7409","markdown":"https://www.eipsfordesigners.com/standards/ERC-7409/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-7409/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-7409","official":"https://eips.ethereum.org/EIPS/erc-7409","discussion":"https://ethereum-magicians.org/search?q=ERC-7409"},"freshness":{"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25"}},{"id":"EIP-1014","name":"Skinny CREATE2","status":"Final","chain":"both","category":{"id":"infrastructure","name":"Infrastructure","description":"Foundational patterns enabling other standards"},"journeyStages":[{"id":"infra","name":"Infrastructure","description":"Foundational patterns"}],"uxImpact":"Contract addresses are predictable before deployment — enables 'pay to future address' patterns. Design implications: show users their contract address upfront during deployment flows, enable deposit UIs for addresses that don't exist yet, support counterfactual wallet onboarding where users can receive funds before activating their wallet. Design decisions: balance showing predictable addresses (builds trust) vs. complexity of explaining 'this address exists but has no code yet'. Multi-Chain Checklist recommends CREATE2 at Medium priority for consistent addresses across L2s ('one address everywhere'). Cross-chain address consistency is a designer-facing decision — users expect the same address on every network.","hasDetailedContent":true,"content":{"id":"EIP-1014","summary":"EIP-1014 introduced CREATE2, allowing contracts to be deployed to predictable addresses. Instead of addresses depending on the deployer's nonce, CREATE2 uses a formula: address = hash(deployer, salt, bytecode). This means you can know an address before the contract exists, enabling counterfactual wallets, gasless onboarding, and trustless contract deployments.","applicability":{"whenToUse":["Your product addresses: contract addresses were unpredictable.","Your users needed deployed wallet before receiving funds.","The flow should deliver: address is deterministic: same inputs = same address always.","Connect flows must list wallets with names, icons, and explicit user choice."],"whenToAvoid":["Clear messaging: \"Address reserved, wallet deploys on first use\".","Show \"Deployed ✓\" or \"Not deployed, will deploy on first tx\".","Use CREATE2 for consistent cross-chain addresses when possible.","Protocol plumbing is invisible and never surfaces in user-facing UI."]},"designerTakeaways":["You can address is deterministic: same inputs = same address always.","You can design UI that delivers share future wallet address.","You can design UI that delivers same CREATE2 params = same address on every EVM chain."],"problemsSolved":[{"problem":"Contract addresses were unpredictable","oldWay":"Address depends on deployer nonce, changes if any tx happens first","newWay":"Address is deterministic: same inputs = same address always","impact":"critical"},{"problem":"Users needed deployed wallet before receiving funds","oldWay":"Deploy wallet first, then share address, then receive funds","newWay":"Share future wallet address, receive funds, deploy later","impact":"critical"},{"problem":"Cross-chain address consistency was impossible","oldWay":"Same wallet had different addresses on each chain","newWay":"Same CREATE2 params = same address on every EVM chain","impact":"high"},{"problem":"Factory contracts couldn't guarantee addresses","oldWay":"User deploys, gets whatever address results","newWay":"User knows exact address before deployment","impact":"high"}],"uxPatterns":[{"name":"Counterfactual Wallet Setup","description":"Show user their wallet address before deployment","mockup":"concept/proxy-pattern","userFlow":["User starts wallet creation","CREATE2 address calculated immediately","Address shown before any transaction","User can receive funds right away","Wallet deploys on first outgoing tx"]},{"name":"Same Address Everywhere","description":"Show consistent address across chains","mockup":"concept/bridge","userFlow":["User views their universal address","See deployment status per chain","Same address shown for all chains","Can deploy to new chains on demand","Receive funds on any chain with same address"]},{"name":"Pre-Deployment Fund Receipt","description":"Receive and display funds before wallet deployment","mockup":"concept/tx-status","userFlow":["Funds sent to CREATE2 address","User notified of incoming funds","Balance shown even without deployment","Clear explanation funds are safe","Option to deploy and access immediately"]}],"uiComponents":[{"name":"PredictedAddressDisplay","description":"Shows address that will be created via CREATE2","states":["calculated","deployed","has-balance"],"props":["address","isDeployed","balance","onCopy"]},{"name":"DeploymentStatusBadge","description":"Shows whether address is deployed or counterfactual","states":["not-deployed","deploying","deployed"],"props":["isDeployed","chainId","deployedAt"]},{"name":"CrossChainAddressView","description":"Shows same address with deployment status per chain","states":["loading","loaded","error"],"props":["address","chains[]","deploymentStatus{}"]}],"antiPatterns":[{"pattern":"Not explaining counterfactual addresses","why":"Users confused why address exists but wallet doesn't","instead":"Clear messaging: \"Address reserved, wallet deploys on first use\"","severity":"high"},{"pattern":"Hiding deployment status","why":"Users don't know if they can transact yet","instead":"Show \"Deployed ✓\" or \"Not deployed - will deploy on first tx\"","severity":"high"},{"pattern":"Showing different addresses per chain for same wallet","why":"Users think they have multiple wallets, send to wrong address","instead":"Use CREATE2 for consistent cross-chain addresses when possible","severity":"medium"},{"pattern":"Requiring deployment before showing address","why":"Adds friction, costs gas before user even receives funds","instead":"Show CREATE2 address immediately, deploy lazily","severity":"medium"}],"onMonad":[{"aspect":"Fast Deployment","ethereum":"Deployment transaction takes 12+ seconds","monad":"Sub-second deployment confirmation","designImplication":"Deployment feels instant, can happen transparently on first tx"},{"aspect":"Same Address on Monad","ethereum":"CREATE2 gives same address on all EVM chains","monad":"Works identically, same address available on Monad","designImplication":"Emphasize \"same address on Monad\" for cross-chain users"},{"aspect":"Deployment Cost","ethereum":"Deployment can be expensive ($50+ in high gas)","monad":"Much cheaper deployment costs","designImplication":"Can be more aggressive about deploying rather than counterfactual"}],"relatedStandards":[{"id":"ERC-4337","relationship":"Account abstraction uses CREATE2 for counterfactual wallet addresses"},{"id":"EIP-1167","relationship":"Minimal proxies often deployed via CREATE2 for deterministic addresses"},{"id":"EIP-5202","relationship":"Blueprint contracts use CREATE2 for efficient contract deployment"},{"id":"EIP-7702","relationship":"Smart wallet features work with CREATE2-deployed wallets"}]},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-1014","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=EIP-1014","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/EIP-1014","markdown":"https://www.eipsfordesigners.com/standards/EIP-1014/content.md","agent":"https://www.eipsfordesigners.com/standards/EIP-1014/agent.md","api":"https://www.eipsfordesigners.com/api/standards/EIP-1014","official":"https://eips.ethereum.org/EIPS/eip-1014","discussion":"https://ethereum-magicians.org/search?q=EIP-1014"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"EIP-1167","name":"Minimal Proxy Contract","status":"Final","chain":"both","category":{"id":"infrastructure","name":"Infrastructure","description":"Foundational patterns enabling other standards"},"journeyStages":[{"id":"infra","name":"Infrastructure","description":"Foundational patterns"}],"uxImpact":"Many contracts share identical code via lightweight clones — same interface, different addresses. Design implications: when displaying contract info, detect clones and show the 'master' contract's verified source/audit status, group clone contracts in portfolio views, indicate 'Clone of [verified contract]' badges. Design decisions: whether to surface clone relationships prominently (transparency) or hide complexity (simplicity); how to handle trust signals when master contract upgrades.","hasDetailedContent":true,"content":{"id":"EIP-1167","summary":"EIP-1167 defines minimal proxy contracts (clones) that delegate all calls to an implementation contract. This lets you deploy many contracts cheaply by creating tiny proxies pointing to shared code—why creating an NFT collection or DAO doesn't cost $500 in gas.","applicability":{"whenToUse":["Your product addresses: deploying contracts is expensive.","Your product addresses: factory patterns cost too much.","The flow should deliver: tiny 45-byte proxy cloned for ~$5-10.","You are designing a one-click contract creation experience with visible states and recovery paths."],"whenToAvoid":["Show \"Powered by [Implementation]\" with link.","Always link to implementation on block explorer.","Clearly label \"Your contract\" vs \"Implementation\".","Protocol plumbing is invisible and never surfaces in user-facing UI."]},"designerTakeaways":["You can design UI that delivers tiny 45-byte proxy cloned for ~$5-10.","You can design UI that delivers clone factory creates instances cheaply.","You can each user gets their own contract cheaply in the interface."],"problemsSolved":[{"problem":"Deploying contracts is expensive","oldWay":"Full contract bytecode deployed each time (~$200-500)","newWay":"Tiny 45-byte proxy cloned for ~$5-10","impact":"critical"},{"problem":"Factory patterns cost too much","oldWay":"Each user's vault/collection is full deployment","newWay":"Clone factory creates instances cheaply","impact":"critical"},{"problem":"Can't afford per-user contracts","oldWay":"Share one contract, complex accounting","newWay":"Each user gets their own contract cheaply","impact":"high"},{"problem":"Code duplication on chain","oldWay":"Same bytecode stored thousands of times","newWay":"One implementation, many proxies","impact":"medium"}],"uxPatterns":[{"name":"One-Click Contract Creation","description":"User creates their own contract instantly","mockup":"concept/nft-gallery","userFlow":["User fills in contract parameters","Sees cost comparison (clone vs full)","Clicks create","Clone deployed in seconds","Gets their own contract address"]},{"name":"Factory Dashboard","description":"View all clones created from a factory","mockup":"concept/nft-gallery","userFlow":["Admin views factory dashboard","Sees all clones created","Monitors adoption and gas savings","Links to implementation for verification"]},{"name":"Clone Verification","description":"Show user their clone points to verified code","mockup":"concept/proxy-pattern","userFlow":["User checks their contract","Sees it's a proxy (not full code)","Views implementation it delegates to","Confirms implementation is verified/audited","Trusts their clone is safe"]},{"name":"Personal Vault Creation","description":"User gets their own vault contract","mockup":"concept/proxy-pattern","userFlow":["User selects vault type","Sees low deployment cost","Can learn why it's cheap (clone pattern)","Creates vault","Gets personal contract address"]}],"uiComponents":[{"name":"CloneDeployer","description":"Form for creating new clone instance","states":["configuring","deploying","deployed","error"],"props":["factoryAddress","initParams","onDeploy"]},{"name":"GasSavingsIndicator","description":"Shows savings from using clone vs full deploy","states":["calculating","ready"],"props":["fullDeployCost","cloneCost","savings"]},{"name":"ProxyVerificationBadge","description":"Badge showing proxy points to verified impl","states":["verified","unverified","loading"],"props":["proxyAddress","implementationAddress","isVerified"]},{"name":"FactoryCloneList","description":"List of all clones from a factory","states":["loading","loaded","empty"],"props":["clones[]","onCloneClick"]},{"name":"CloneExplainerTooltip","description":"Explains how minimal proxy works","states":["collapsed","expanded"],"props":["showDiagram"]}],"antiPatterns":[{"pattern":"Hiding that contract is a proxy","why":"Users deserve to know how their contract works","instead":"Show \"Powered by [Implementation]\" with link","severity":"high"},{"pattern":"Not linking to verified implementation","why":"User can't verify the code their proxy uses","instead":"Always link to implementation on block explorer","severity":"high"},{"pattern":"Confusing proxy address with implementation","why":"User looks up wrong address, sees weird bytecode","instead":"Clearly label \"Your contract\" vs \"Implementation\"","severity":"medium"},{"pattern":"Not explaining gas savings","why":"User doesn't understand the value they're getting","instead":"Show \"Saved ~$150 using clone pattern\"","severity":"medium"},{"pattern":"Using clones for upgradeable contracts","why":"EIP-1167 clones are immutable, confuses with upgradeable","instead":"Clarify: \"Your clone points to fixed implementation\"","severity":"medium"}],"onMonad":[{"aspect":"Clone Deployment","ethereum":"Clone deploy still costs ~$5-10","monad":"Near-zero cost clone creation","designImplication":"Can create per-transaction contracts if needed"},{"aspect":"Factory Throughput","ethereum":"Factory limited by block gas limits","monad":"Parallel execution enables high clone throughput","designImplication":"Bulk clone creation for airdrops/onboarding viable"},{"aspect":"User Contract Pattern","ethereum":"Still consider shared contracts for cost","monad":"Per-user contracts always affordable","designImplication":"Every user can have isolated contract by default"},{"aspect":"Delegate Call Speed","ethereum":"Delegate call adds small overhead","monad":"Optimized execution minimizes proxy overhead","designImplication":"Proxy pattern has negligible performance cost"}],"keyTakeaways":["EIP-1167 = tiny proxy pointing to shared implementation","Creates contracts cheaply (95%+ savings)","Always link to the verified implementation","Explain to users their clone uses audited code","Clones are immutable—not upgradeable proxies"],"technicalNotes":"EIP-1167 minimal proxy is exactly 45 bytes of bytecode that delegatecalls to a hardcoded implementation address. All storage lives in the proxy, logic in the implementation. The proxy cannot be upgraded—it permanently points to one implementation. This is different from upgradeable proxies (EIP-1967) where the implementation can change."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-1167","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=EIP-1167","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/EIP-1167","markdown":"https://www.eipsfordesigners.com/standards/EIP-1167/content.md","agent":"https://www.eipsfordesigners.com/standards/EIP-1167/agent.md","api":"https://www.eipsfordesigners.com/api/standards/EIP-1167","official":"https://eips.ethereum.org/EIPS/eip-1167","discussion":"https://ethereum-magicians.org/search?q=EIP-1167"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"EIP-1967","name":"Proxy Storage Slots","status":"Final","chain":"both","category":{"id":"infrastructure","name":"Infrastructure","description":"Foundational patterns enabling other standards"},"journeyStages":[{"id":"infra","name":"Infrastructure","description":"Foundational patterns"}],"uxImpact":"Proxy contracts have standardized slots revealing implementation address and admin — enables reliable upgrade detection. Design implications: show 'Upgradeable' badges on proxy contracts, display both proxy and implementation addresses in contract details, alert users when implementation changes, show admin address for governance transparency. Design decisions: how prominently to warn about upgradeability risks vs. normalizing the pattern; whether to show upgrade history timeline.","hasDetailedContent":true,"content":{"id":"EIP-1967","summary":"EIP-1967 standardizes where proxy contracts store their implementation address. This lets block explorers like Etherscan show \"Read as Proxy\" so users see actual functions instead of confusing wrapper code. Essential for making upgradeable contracts usable.","applicability":{"whenToUse":["Your product addresses: block explorers show proxy bytecode, not real functions.","Your product must handle: can't verify what code proxy is running.","The flow should deliver: explorer detects proxy, shows implementation interface.","You are designing a block explorer proxy view experience with visible states and recovery paths."],"whenToAvoid":["Detect proxy, show implementation source.","Prominently show admin and their permissions.","Notify users when implementation changes.","Protocol plumbing is invisible and never surfaces in user-facing UI."]},"designerTakeaways":["You can design UI that delivers explorer detects proxy, shows implementation interface.","You can standard slot, anyone can verify implementation address.","You can standard slots: all tools work universally."],"problemsSolved":[{"problem":"Block explorers show proxy bytecode, not real functions","oldWay":"User sees confusing proxy code, can't interact","newWay":"Explorer detects proxy, shows implementation interface","impact":"critical"},{"problem":"Can't verify what code proxy is running","oldWay":"Trust that proxy points to claimed implementation","newWay":"Standard slot, anyone can verify implementation address","impact":"critical"},{"problem":"Different proxies store implementation differently","oldWay":"Each proxy pattern needs custom detection","newWay":"Standard slots: all tools work universally","impact":"high"},{"problem":"Admin address hidden or unpredictable","oldWay":"Who can upgrade this? Check code manually","newWay":"Standard admin slot reveals upgrade authority","impact":"high"}],"uxPatterns":[{"name":"Block Explorer Proxy View","description":"Etherscan \"Read as Proxy\" interface","mockup":"generic/token-approval","userFlow":["User visits proxy contract on explorer","Sees \"This is a Proxy Contract\" banner","Views implementation address","Sees admin who can upgrade","Clicks \"Read as Proxy\" for real functions","Interacts with actual interface"]},{"name":"Contract Upgrade Notice","description":"Inform users about proxy upgrade","mockup":"concept/permit-approval","userFlow":["Protocol upgrades implementation","Users notified of change","See what changed (new features/fixes)","Understand their assets are safe","Can verify upgrade transaction"]},{"name":"Proxy Trust Verification","description":"Help users verify proxy safety","mockup":"concept/verify-safety","userFlow":["User pastes contract address","System detects EIP-1967 proxy","Fetches implementation from standard slot","Checks verification and audit status","Analyzes admin permissions","Shows overall risk assessment"]},{"name":"Upgrade Governance","description":"Admin interface for proposing upgrades","mockup":"concept/proxy-pattern","userFlow":["Admin enters new implementation address","System runs verification checks","Warns about missing requirements","Admin proposes upgrade","Other signers approve","Timelock countdown begins","Upgrade executes after delay"]}],"uiComponents":[{"name":"ProxyBanner","description":"Banner indicating contract is a proxy","states":["proxy-detected","not-proxy","unknown"],"props":["implementationAddress","adminAddress","proxyType"]},{"name":"ImplementationViewer","description":"Shows what implementation proxy points to","states":["loading","verified","unverified","error"],"props":["proxyAddress","implementationAddress","isVerified"]},{"name":"AdminAnalyzer","description":"Analyzes who controls proxy upgrades","states":["eoa","multisig","timelock","renounced"],"props":["adminAddress","adminType","signers[]","timelockDuration"]},{"name":"UpgradeNotification","description":"Alert showing contract was upgraded","states":["pending","executed","cancelled"],"props":["oldImplementation","newImplementation","changelog"]},{"name":"ProxyReadWrite","description":"Interface for interacting via proxy","states":["loading","ready","submitting"],"props":["proxyAddress","abiFromImplementation","onCall"]}],"antiPatterns":[{"pattern":"Showing proxy bytecode as \"contract source\"","why":"Users can't understand or verify what code runs","instead":"Detect proxy, show implementation source","severity":"critical"},{"pattern":"Hiding admin address","why":"Users don't know who can change the contract","instead":"Prominently show admin and their permissions","severity":"critical"},{"pattern":"No upgrade notifications","why":"Users surprised by changed behavior","instead":"Notify users when implementation changes","severity":"high"},{"pattern":"Single EOA as admin","why":"One compromised key = protocol compromised","instead":"Show warning when admin is single address","severity":"high"},{"pattern":"Not linking to implementation on explorer","why":"User can't verify the actual code","instead":"Always provide clickable link to implementation","severity":"medium"}],"onMonad":[{"aspect":"Upgrade Speed","ethereum":"Upgrade tx takes a block","monad":"Sub-second upgrade finality","designImplication":"Emergency upgrades can be truly instant"},{"aspect":"Slot Reading","ethereum":"Reading storage slots is cheap but requires RPC","monad":"Fast parallel reads for proxy detection","designImplication":"Can check many contracts for proxy status quickly"},{"aspect":"Timelock Precision","ethereum":"Timelocks based on block numbers","monad":"Precise second-level timelocks possible","designImplication":"More accurate upgrade scheduling"},{"aspect":"Proxy Overhead","ethereum":"Delegatecall adds small gas overhead","monad":"Optimized execution reduces proxy cost","designImplication":"Proxy pattern even more efficient"}],"keyTakeaways":["EIP-1967 = standardized storage for proxy info","Enables \"Read as Proxy\" on block explorers","Always show implementation AND admin addresses","Warn users about admin trust assumptions","Notify on upgrades so users aren't surprised"],"technicalNotes":"EIP-1967 defines three storage slots: implementation (0x360894...), admin (0xb531...), and beacon (0xa3f0...). These specific slots are chosen to avoid collisions with normal storage. Block explorers read these slots to detect proxies and show the correct interface. UUPS and Transparent proxies both use these slots."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-1967","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=EIP-1967","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/EIP-1967","markdown":"https://www.eipsfordesigners.com/standards/EIP-1967/content.md","agent":"https://www.eipsfordesigners.com/standards/EIP-1967/agent.md","api":"https://www.eipsfordesigners.com/api/standards/EIP-1967","official":"https://eips.ethereum.org/EIPS/eip-1967","discussion":"https://ethereum-magicians.org/search?q=EIP-1967"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"ERC-2535","name":"Diamonds, Multi-Facet Proxy","status":"Final","chain":"both","category":{"id":"infrastructure","name":"Infrastructure","description":"Foundational patterns enabling other standards"},"journeyStages":[{"id":"infra","name":"Infrastructure","description":"Foundational patterns"}],"uxImpact":"Diamond contracts can have unlimited functionality via multiple facets, all at one address. Design implications: show facet breakdown in contract explorers (which functions come from which facet), display upgrade history per-facet, indicate 'Diamond Contract' with expandable facet list. Design decisions: how to present complex multi-facet contracts without overwhelming users; balance between showing full architecture (power users) and simplified 'single contract' view (regular users).","hasDetailedContent":true,"content":{"id":"ERC-2535","sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-2535","type":"official-spec"}],"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25","summary":"Diamond contracts can have unlimited functionality via multiple facets, all at one address.","designerTakeaways":["You can badge Diamond contract on address pages with optional View facets expand.","Your default send flow treats diamond like any address — complexity only in advanced explorer.","You can show per-facet upgrade history for auditors without showing it on every confirm screen."],"applicability":{"whenToUse":["Contract explorer or developer tools display proxy diamonds.","Users interact with known diamond deployments.","Upgrade transparency is product value."],"whenToAvoid":["End-user retail flows with no inspect need.","Plain non-diamond contracts.","Cannot resolve facet selector mapping."]},"prototypeFirst":[{"screen":"Diamond address overview","why":"Default view for regular users stays simple.","covers":["Simple mode","Power expand"],"include":["Single address chip","Diamond badge","Expand facets link"]},{"screen":"Facet breakdown panel","why":"Power users audit which code runs.","covers":["Multiple facets","Single facet"],"include":["Facet name rows","Function count","Facet address copy"]},{"screen":"Upgrade history timeline","why":"Track facet adds and replacements.","covers":["Recent upgrade","Empty history"],"include":["Timeline","Facet affected","Tx link"]},{"screen":"Send to diamond confirm","why":"Confirm stays human — no facet dump.","covers":["Standard send"],"include":["Human action summary","Contract address","Facets in advanced only"]}],"mentalModel":[{"label":"Diamond address","description":"One URL users save — never changes across upgrades."},{"label":"Facet","description":"Module holding subset of functions."},{"label":"Selector routing","description":"Function call hits correct facet — invisible to user."},{"label":"Upgrade","description":"Facet swap changes behavior without new address."},{"label":"Simple vs power view","description":"Retail default simple; auditors expand facets."}],"statesToDesign":[{"state":"Simple contract view","trigger":"Default user path.","userNeed":"Send/interact normally.","designResponse":"No facet UI on confirm."},{"state":"Facets expanded","trigger":"User taps View facets.","userNeed":"Audit architecture.","designResponse":"Facet list with function groups."},{"state":"Recent upgrade","trigger":"Facet changed.","userNeed":"Know behavior may differ.","designResponse":"Recently upgraded banner on explorer."},{"state":"Unknown selector","trigger":"Function not in known facet map.","userNeed":"Not broken UI.","designResponse":"Unknown function — check latest facet map."},{"state":"Developer upgrade sim","trigger":"Simulating facet add.","userNeed":"Clear diff.","designResponse":"Before/after facet table."}],"designDecisions":[{"question":"Show facets on wallet confirm?","recommendation":"No — address and human summary only.","rationale":"Facets are auditor detail not consent detail."},{"question":"Diamond badge everywhere?","recommendation":"Explorer and contract pages only.","rationale":"Badge on send form adds noise."},{"question":"Facet naming?","recommendation":"Human labels from manifest; addresses in advanced.","rationale":"0x facet addresses meaningless."}],"problemsSolved":[{"problem":"Contract size limit blocks features","oldWay":"Deploy new address each upgrade","newWay":"Diamond adds facets same address","impact":"high"},{"problem":"Users confused by changing bytecode same address","oldWay":"Looks like same contract different behavior","newWay":"Upgrade history explains facet changes","impact":"medium"},{"problem":"Auditors cannot map functions to code","oldWay":"Opaque proxy","newWay":"Facet breakdown panel","impact":"medium"}],"uxPatterns":[{"name":"Diamond Facet Explorer","description":"Expandable facet list on contract page.","mockup":"concept/proxy-pattern","components":["DiamondBadge","FacetList","UpgradeTimeline"],"userFlow":["Open contract","See diamond badge","Expand facets","Inspect functions"]},{"name":"Simple Send to Diamond","description":"Standard confirm without facet noise.","mockup":"concept/verify-safety","components":["AddressChip","ActionSummary","AdvancedToggle"],"userFlow":["Send to diamond","Human summary","Confirm","Success"]}],"seenInTheWild":[{"app":"Etherscan","url":"https://etherscan.io/","note":"Proxy and implementation contract display patterns."},{"app":"OpenZeppelin","url":"https://www.openzeppelin.com/","note":"Diamond pattern documentation for developers."},{"app":"Louper","url":"https://louper.dev/","note":"Diamond facet explorer reference UI."}],"antiPatterns":[{"pattern":"Facet list on every wallet confirm","why":"Overwhelms non-technical users","instead":"Facets only in contract explorer advanced","severity":"high"},{"pattern":"No upgrade history on diamond","why":"Same address different behavior surprises","instead":"Upgrade timeline on contract page","severity":"medium"},{"pattern":"Raw selector hex in default view","why":"Meaningless to users","instead":"Function names grouped by facet","severity":"medium"}],"vocabulary":[{"use":"Multi-part contract","avoid":"Diamond proxy facets","why":"Simpler architecture hint."},{"use":"View components","avoid":"List facets","why":"Explorer action language."},{"use":"Recently updated","avoid":"Facet replaced via diamondCut","why":"Plain upgrade notice."}],"onMonad":[{"aspect":"Diamond deployments","ethereum":"Same UX patterns apply","monad":"Facet upgrades same address on Monad","designImplication":"Support diamond badge in Monad explorers."},{"aspect":"Upgrade tx cost","ethereum":"Facet cuts costly","monad":"Cheaper upgrades enable iterative facet releases","designImplication":"Show upgrade history more frequently on Monad."}],"technicalNotes":"ERC-2535 diamonds: simple default UX for send; facet breakdown for explorers only.","relatedStandards":[{"id":"EIP-1967","relationship":"Proxy storage slot standard"},{"id":"EIP-1167","relationship":"Minimal proxy alternative"}]},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-2535","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-2535","type":"discussion"},{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-2535","type":"official-spec"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-2535","markdown":"https://www.eipsfordesigners.com/standards/ERC-2535/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-2535/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-2535","official":"https://eips.ethereum.org/EIPS/erc-2535","discussion":"https://ethereum-magicians.org/search?q=ERC-2535"},"freshness":{"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25"}},{"id":"ERC-7201","name":"Namespaced Storage Layout","status":"Final","chain":"both","category":{"id":"infrastructure","name":"Infrastructure","description":"Foundational patterns enabling other standards"},"journeyStages":[{"id":"infra","name":"Infrastructure","description":"Foundational patterns"}],"uxImpact":"Storage is organized into named namespaces preventing upgrade collisions — enables safer contract evolution. Design implications: in developer tools, show storage namespace annotations, display namespace IDs in storage explorers, indicate namespace-safe upgrades. Design decisions: mostly invisible to end users but critical for developer UX; surface namespace conflicts as clear errors during upgrade simulations rather than cryptic storage collision warnings.","hasDetailedContent":true,"content":{"id":"ERC-7201","sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-7201","type":"official-spec"}],"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25","summary":"Storage is organized into named namespaces preventing upgrade collisions — enables safer contract evolution.","designerTakeaways":["You can annotate storage views with namespace labels in developer explorers.","Your upgrade simulator can block publish on namespace conflict with plain English error.","You can keep end-user transaction UI unchanged — 7201 is dev-facing infrastructure."],"applicability":{"whenToUse":["Developer tools for upgradeable contracts using ERC-7201.","Upgrade simulation before mainnet deploy.","Storage layout documentation products."],"whenToAvoid":["End-user consumer wallets with no upgrade tools.","Non-upgradeable contracts.","No dev mode in product."]},"prototypeFirst":[{"screen":"Storage namespace explorer","why":"Devs inspect layout before upgrade.","covers":["Multiple namespaces","Single namespace"],"include":["Namespace id label","Slot ranges","Variable names"]},{"screen":"Upgrade simulation conflict","why":"Catch collision pre-deploy.","covers":["Conflict detected","Clean sim"],"include":["Red conflict banner","Colliding namespaces named","Fix suggestion"]},{"screen":"Upgrade diff preview","why":"Show which namespaces change.","covers":["Namespace added","Unchanged"],"include":["Diff table","Safe badge","Deploy blocked if conflict"]},{"screen":"End-user tx (unchanged)","why":"Confirm dev tools do not leak to retail.","covers":["Normal send"],"include":["Standard confirm — no namespace UI"]}],"mentalModel":[{"label":"Namespace","description":"Isolated storage bucket with unique id."},{"label":"Collision","description":"Two layouts claim same namespace — upgrade unsafe."},{"label":"Simulation","description":"Test upgrade off-chain before users hit reverts."},{"label":"End user","description":"Never sees namespaces — feels single contract."},{"label":"Annotation","description":"Dev tools label slots by namespace for readability."}],"statesToDesign":[{"state":"Clean upgrade sim","trigger":"No namespace conflict.","userNeed":"Deploy confidence.","designResponse":"Safe to upgrade green state."},{"state":"Namespace conflict","trigger":"Collision detected.","userNeed":"Fix before ship.","designResponse":"Block deploy; name conflicting namespaces."},{"state":"Storage explorer browse","trigger":"Dev inspects contract.","userNeed":"Map variables to namespaces.","designResponse":"Labeled namespace groups."},{"state":"Post-upgrade","trigger":"Upgrade live.","userNeed":"End users unaffected.","designResponse":"No change to retail confirm UI."},{"state":"Missing annotation","trigger":"Legacy contract.","userNeed":"Graceful fallback.","designResponse":"Unlabeled storage with docs link."}],"designDecisions":[{"question":"Show namespaces to end users?","recommendation":"Never on send/confirm flows.","rationale":"7201 is implementation detail."},{"question":"Conflict error copy?","recommendation":"Namespace [name] already used by [module] — pick new id.","rationale":"Actionable dev errors reduce incidents."},{"question":"Integrate with Tenderly-style sim?","recommendation":"Yes — conflict gate before deploy button enables.","rationale":"Simulation is the UX surface."}],"problemsSolved":[{"problem":"Storage collision brick upgrades","oldWay":"Cryptic storage overlap revert on mainnet","newWay":"Namespace ids prevent collision; sim catches early","impact":"critical"},{"problem":"Opaque storage layouts","oldWay":"Raw slot hex in explorers","newWay":"Namespace annotations in dev tools","impact":"medium"},{"problem":"User-facing upgrade failures","oldWay":"Surprise reverts after bad upgrade","newWay":"Dev tooling blocks bad deploys first","impact":"high"}],"uxPatterns":[{"name":"Namespace Storage Explorer","description":"Dev view of labeled storage namespaces.","mockup":"concept/proxy-pattern","components":["NamespaceLabel","SlotTable","VariableRow"],"userFlow":["Open dev explorer","Browse namespaces","Inspect slots"]},{"name":"Upgrade Conflict Gate","description":"Block deploy on namespace collision.","mockup":"concept/typed-data","components":["SimResult","ConflictBanner","DeployBlock"],"userFlow":["Run upgrade sim","Conflict found","Error shown","Fix and retry"]}],"seenInTheWild":[{"app":"Tenderly","url":"https://tenderly.co/","note":"Upgrade simulation and storage inspection."},{"app":"OpenZeppelin Defender","url":"https://www.openzeppelin.com/defender","note":"Upgrade admin tooling patterns."},{"app":"Etherscan","url":"https://etherscan.io/","note":"Contract read/write tab for devs."}],"antiPatterns":[{"pattern":"Namespace jargon on wallet confirm","why":"Confuses retail users","instead":"Dev tools only","severity":"high"},{"pattern":"Generic storage collision hex error","why":"Devs cannot fix","instead":"Name both conflicting namespaces","severity":"critical"},{"pattern":"Deploy enabled despite sim conflict","why":"User-facing reverts ship","instead":"Hard block deploy until clean sim","severity":"critical"}],"vocabulary":[{"use":"Storage section","avoid":"Namespace id 0x...","why":"Dev-friendly grouping term."},{"use":"Conflict between sections","avoid":"Storage slot collision","why":"Plain error headline."},{"use":"Upgrade simulation","avoid":"dry-run diamondCut","why":"Dev action language."}],"onMonad":[{"aspect":"Upgrade tooling","ethereum":"Same dev UX need","monad":"Namespace layout equally critical on Monad deploys","designImplication":"Include Monad in upgrade simulators day one."},{"aspect":"Sim speed","ethereum":"Slow sim loops","monad":"Fast sim encourages pre-deploy checks","designImplication":"Inline sim on every upgrade PR on Monad."}],"technicalNotes":"ERC-7201 is dev-facing; never expose namespace ids in end-user transaction UI.","relatedStandards":[{"id":"ERC-2535","relationship":"Diamond upgrades use namespaced storage"},{"id":"EIP-1967","relationship":"Proxy storage standard family"}]},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-7201","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-7201","type":"discussion"},{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/erc-7201","type":"official-spec"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-7201","markdown":"https://www.eipsfordesigners.com/standards/ERC-7201/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-7201/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-7201","official":"https://eips.ethereum.org/EIPS/erc-7201","discussion":"https://ethereum-magicians.org/search?q=ERC-7201"},"freshness":{"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25"}},{"id":"EIP-5202","name":"Blueprint Contract Format","status":"Final","chain":"both","category":{"id":"infrastructure","name":"Infrastructure","description":"Foundational patterns enabling other standards"},"journeyStages":[{"id":"infra","name":"Infrastructure","description":"Foundational patterns"}],"uxImpact":"Blueprint contracts store deployment code on-chain but cannot be called directly — they're templates. Design implications: mark blueprint contracts distinctly in explorers ('Blueprint - Not Callable'), prevent interaction UI from rendering for blueprints, show 'deployed from blueprint' lineage for contracts. Design decisions: whether to hide blueprints from regular contract lists (cleaner) or show them with clear non-interactive status (complete).","hasDetailedContent":true,"content":{"id":"EIP-5202","sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-5202","type":"official-spec"}],"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25","summary":"Blueprint contracts store deployment code on-chain but cannot be called directly — they're templates.","designerTakeaways":["You can badge Blueprint — not callable on blueprint addresses in explorers.","Your interact panel can hide entirely for blueprints with Deploy instance CTA for devs instead.","You can show Deployed from blueprint link on live contract pages."],"applicability":{"whenToUse":["Contract explorer shows factory/blueprint patterns.","Users might land on blueprint via explorer search.","Clone/minimal proxy deployments from blueprint."],"whenToAvoid":["No blueprint contracts in indexed set.","Pure end-user wallet with no explorer.","Only live instance addresses exposed."]},"prototypeFirst":[{"screen":"Blueprint contract page","why":"Prevent interact attempts on template.","covers":["Blueprint detected"],"include":["Blueprint badge","Not callable message","List instances link"]},{"screen":"Live instance with lineage","why":"Trace which template spawned contract.","covers":["Has blueprint parent"],"include":["Deployed from chip","Link to blueprint","Factory tx"]},{"screen":"Contract list filter","why":"Devs want completeness; users want clarity.","covers":["Hide blueprints toggle"],"include":["Filter setting","Blueprint gray rows when shown"]},{"screen":"Blocked interact attempt","why":"Deep link to interact tab still happens.","covers":["Interact disabled"],"include":["This is a template only","View deployments instead"]}],"mentalModel":[{"label":"Blueprint","description":"Template bytecode — not a live app contract."},{"label":"Instance","description":"Deployed callable contract from blueprint."},{"label":"Factory","description":"Contract that deploys instances from blueprint."},{"label":"Lineage","description":"Link instance back to blueprint source."},{"label":"Non-callable","description":"Any interact tx will fail — block in UI first."}],"statesToDesign":[{"state":"Blueprint page view","trigger":"User opens blueprint address.","userNeed":"Not try to call functions.","designResponse":"Blueprint badge; no interact form."},{"state":"Instance page view","trigger":"Live deployed contract.","userNeed":"Normal interact.","designResponse":"Standard UI plus lineage chip."},{"state":"Search hits blueprint","trigger":"Search returns template.","userNeed":"Distinguish from instance.","designResponse":"Blueprint in search results styling."},{"state":"List with blueprints shown","trigger":"Dev toggle on.","userNeed":"Scan templates.","designResponse":"Gray non-interactive rows."},{"state":"List blueprints hidden","trigger":"Default user filter.","userNeed":"Only callable contracts.","designResponse":"Instances only in default list."}],"designDecisions":[{"question":"Hide blueprints from default lists?","recommendation":"Yes default hide; dev toggle show.","rationale":"Cleaner for users; completeness for devs."},{"question":"Interact tab on blueprint?","recommendation":"Remove tab entirely.","rationale":"Empty or error tab feels broken."},{"question":"Lineage on every instance?","recommendation":"Chip linking blueprint if known.","rationale":"Audit and support traceability."}],"problemsSolved":[{"problem":"Users call blueprint and revert","oldWay":"Interact UI on template address","newWay":"Blueprint badge blocks interact","impact":"high"},{"problem":"Cannot trace clone source","oldWay":"Instance appears from nowhere","newWay":"Deployed from blueprint lineage","impact":"medium"},{"problem":"Explorer lists cluttered with templates","oldWay":"Templates mixed with live apps","newWay":"Filter hide blueprints default","impact":"low"}],"uxPatterns":[{"name":"Blueprint Badge Block","description":"Non-callable template contract page.","mockup":"concept/proxy-pattern","components":["BlueprintBadge","NoInteractPanel","InstancesLink"],"userFlow":["Open blueprint","See badge","No interact","Browse instances"]},{"name":"Deployed From Lineage","description":"Instance links back to blueprint.","mockup":"concept/proxy-pattern","components":["LineageChip","BlueprintLink"],"userFlow":["Open instance","See deployed from","Jump to blueprint"]}],"seenInTheWild":[{"app":"Etherscan","url":"https://etherscan.io/","note":"Contract page patterns for proxies and factories."},{"app":"Tenderly","url":"https://tenderly.co/","note":"Contract classification in dev tools."},{"app":"EIP-1167","url":"https://eips.ethereum.org/EIPS/eip-1167","note":"Minimal proxy clone lineage patterns."}],"antiPatterns":[{"pattern":"Full interact UI on blueprint","why":"Guaranteed revert wastes gas","instead":"Remove interact; show template badge","severity":"critical"},{"pattern":"Blueprint identical styling to live contract","why":"Users cannot distinguish","instead":"Distinct blueprint badge and gray styling","severity":"high"},{"pattern":"No lineage on instances","why":"Audit trail broken","instead":"Deployed from chip on instance pages","severity":"medium"}],"vocabulary":[{"use":"Template contract","avoid":"Blueprint bytecode","why":"Plain template language."},{"use":"Not callable","avoid":"Execute disabled on blueprint","why":"Direct user message."},{"use":"Deployed from","avoid":"Clone initCode reference","why":"Lineage language."}],"onMonad":[{"aspect":"Blueprint deploys","ethereum":"Same factory patterns","monad":"Cheap instance deploys from blueprints","designImplication":"Show instance lists on Monad blueprint pages."},{"aspect":"Explorer indexing","ethereum":"Blueprint detection varies","monad":"Tag blueprints at indexing on Monad launch","designImplication":"Blueprint badge in Monad explorer from day one."}],"technicalNotes":"EIP-5202 blueprints: never render interact UI; default-hide in contract lists.","relatedStandards":[{"id":"EIP-1167","relationship":"Minimal proxy clones from templates"},{"id":"EIP-1014","relationship":"CREATE2 deterministic deploys"}]},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-5202","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=EIP-5202","type":"discussion"},{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-5202","type":"official-spec"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/EIP-5202","markdown":"https://www.eipsfordesigners.com/standards/EIP-5202/content.md","agent":"https://www.eipsfordesigners.com/standards/EIP-5202/agent.md","api":"https://www.eipsfordesigners.com/api/standards/EIP-5202","official":"https://eips.ethereum.org/EIPS/eip-5202","discussion":"https://ethereum-magicians.org/search?q=EIP-5202"},"freshness":{"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25"}},{"id":"EIP-1559","name":"Fee Market Change","status":"Final","chain":"both","category":{"id":"infrastructure","name":"Infrastructure","description":"Foundational patterns enabling other standards"},"journeyStages":[{"id":"gas","name":"Gas & Fees","description":"Paying for transactions"}],"uxImpact":"Gas fees have a predictable base fee plus optional priority tip — wallets can auto-estimate reliably. Design implications: show base fee (burns) separately from priority fee (to validator), display 'max fee' cap for user peace of mind, auto-suggest priority fees based on urgency ('Slow/Normal/Fast'), show real-time base fee trends. Design decisions: whether to expose full fee breakdown (transparency) or single 'estimated fee' (simplicity); how to handle fee spikes without alarming users. Live and universal. Gas & Fees Checklist rates fee breakdown display as Medium priority for 'transparency when fees spike.' Mainnet at ~3 gwei but the UX problem persists: users can't predict costs before committing.","hasDetailedContent":true,"content":{"id":"EIP-1559","summary":"EIP-1559 reformed Ethereum's fee market. Instead of bidding blindly, there's now a predictable base fee that adjusts with network demand, plus an optional priority fee (tip) for faster inclusion. This makes gas costs predictable, reduces overpaying, and burns part of the fee. Most importantly: users finally understand what they'll pay.","applicability":{"whenToUse":["Users need fee estimates before they sign transactions.","The product shows gas breakdown, speed options, or network congestion.","Max fee caps and priority tips need plain-language explanation."],"whenToAvoid":["The chain does not use EIP-1559 style base fee markets.","Users only see a single opaque fee with no breakdown possible.","Gas is fully sponsored and users never choose speed or fee level."]},"designerTakeaways":["You can show base fee, priority tip, and max fee as separate readable rows.","You can offer Slow, Normal, and Fast speed presets tied to tip amounts.","You can explain refunds when the actual fee is below the max cap users approved."],"mentalModel":[{"label":"Network demand","description":"Block usage vs target drives the base fee up or down each block. Users do not set the base fee directly."},{"label":"Base fee","description":"The protocol-calculated network fee, burned after inclusion. Show it as the predictable part of the cost estimate."},{"label":"Priority tip","description":"An optional tip to validators for faster inclusion. Speed presets map to tip amounts in plain language."},{"label":"Max fee cap","description":"The highest fee the user approves. Actual payment is min(max, base + tip), with unused headroom refunded."},{"label":"Confirmation UX","description":"Show estimated cost early, separate max from expected, and explain refunds so users are not scared by the ceiling number."}],"problemsSolved":[{"problem":"Users had no idea what gas price to set","oldWay":"Guess gas price, overpay by 10x or underpay and fail","newWay":"Base fee is known, just add small tip","impact":"critical"},{"problem":"Transaction costs unpredictable","oldWay":"\"Will this cost $5 or $50? Who knows!\"","newWay":"Clear estimate: base fee + tip = predictable cost","impact":"critical"},{"problem":"Users overpaid during gas spikes","oldWay":"Set high gas to ensure inclusion, pay 5x market rate","newWay":"Max fee as ceiling, only pay actual base + tip","impact":"high"}],"uxPatterns":[{"name":"Gas Fee Display","description":"Clear breakdown of transaction cost","mockup":"concept/fee-market","userFlow":["User initiates transaction","App fetches current base fee","Suggests reasonable priority fee","Shows max fee as safety cap","User sees clear cost estimate"]},{"name":"Speed Selector","description":"Choose transaction priority","mockup":"concept/fee-speed","userFlow":["User sees speed options","Each shows tip, time, cost","Selects preferred speed","Max fee calculated automatically","Confirms transaction"]},{"name":"Gas Tracker","description":"Real-time network gas status","mockup":"concept/gas-tracker","userFlow":["User checks gas before transacting","Sees current base fee","Views trend direction","Decides to wait or proceed","Historical context helps timing"]}],"uiComponents":[{"name":"GasFeeEstimate","description":"Shows estimated transaction cost","states":["loading","ready","congested","low"],"props":["baseFee","priorityFee","maxFee","estimatedCost"]},{"name":"SpeedSelector","description":"Choose transaction speed/priority","states":["slow","standard","fast","custom"],"props":["options[]","selected","onSelect"]},{"name":"BaseFeeIndicator","description":"Current base fee with context","states":["low","normal","high","very-high"],"props":["baseFee","trend","historical"]},{"name":"MaxFeeWarning","description":"Explains max fee vs actual fee","states":["hidden","shown"],"props":["maxFee","estimatedFee"]}],"antiPatterns":[{"pattern":"Only showing max fee without context","why":"Users think they'll pay max, scared by high number","instead":"Show \"Estimated: $2.50 (max: $4.00)\" with explanation","severity":"high"},{"pattern":"Not explaining base vs priority fee","why":"Users confused by multiple fee components","instead":"Simple breakdown: \"Network fee + tip\"","severity":"medium"},{"pattern":"Setting max fee too close to base fee","why":"Transaction fails if base fee rises","instead":"Buffer max fee above expected base fee","severity":"high"},{"pattern":"Hiding fee until confirmation screen","why":"User shocked by cost at last moment","instead":"Show estimated cost early in flow","severity":"medium"}],"onMonad":[{"aspect":"Gas Price Volatility","ethereum":"Base fee can spike 12.5% per block","monad":"More stable due to high throughput","designImplication":"Estimates are more reliable"},{"aspect":"Confirmation Time","ethereum":"12-15 seconds per block","monad":"Sub-second finality","designImplication":"\"Speed\" selector less relevant"},{"aspect":"Base Fee Level","ethereum":"Can be very high during congestion","monad":"Generally low due to capacity","designImplication":"Gas costs less of a concern"}],"keyTakeaways":["EIP-1559 = predictable gas fees","Show \"estimated\" not just \"max\" fee","Explain: you pay actual fee, not max","Offer speed options (slow/standard/fast)","On Monad: fees are more stable, less anxiety"],"technicalNotes":"EIP-1559 introduces type-2 transactions with maxFeePerGas (ceiling) and maxPriorityFeePerGas (tip). Actual payment = min(maxFeePerGas, baseFee + priorityFee). Base fee adjusts ±12.5% per block based on gas usage vs target. Base fee is burned, priority fee goes to validator. effective_gas_price * gas_used = total fee."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-1559","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=EIP-1559","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/EIP-1559","markdown":"https://www.eipsfordesigners.com/standards/EIP-1559/content.md","agent":"https://www.eipsfordesigners.com/standards/EIP-1559/agent.md","api":"https://www.eipsfordesigners.com/api/standards/EIP-1559","official":"https://eips.ethereum.org/EIPS/eip-1559","discussion":"https://ethereum-magicians.org/search?q=EIP-1559"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"EIP-4844","name":"Shard Blob Transactions","status":"Final","chain":"ethereum","category":{"id":"infrastructure","name":"Infrastructure","description":"Foundational patterns enabling other standards"},"journeyStages":[{"id":"gas","name":"Gas & Fees","description":"Paying for transactions"}],"uxImpact":"L2 rollups can post data cheaply via blobs — dramatically lower L2 fees but blob data is temporary. Design implications: on L2 UIs, show 'Secured by Ethereum blobs' badge, indicate blob fee separately from execution gas on L2 fee breakdowns, for data-heavy L2 txs show potential savings vs. calldata. Design decisions: whether to expose blob mechanics to users (educational) or abstract as 'L2 data fee' (simple); how to communicate temporary blob availability for archival use cases. Live on all major L2s. Slashed L2 fees 10-100x. Unpredictable Gas Fees (Medium) remains a prediction and transparency UX gap despite dramatically lower costs.","hasDetailedContent":true,"content":{"id":"EIP-4844","summary":"EIP-4844 introduces \"blob transactions\" - a new way to post data to Ethereum that's 10-100x cheaper. This slashed Layer 2 fees dramatically, making Arbitrum, Base, and Optimism transactions cost pennies instead of dollars.","applicability":{"whenToUse":["Your product addresses: l2 transactions are expensive because of L1 data costs.","Your product addresses: l1 calldata competes with regular transactions.","The flow should deliver: blob space costs ~90% less, L2 txs drop to $0.01-0.10.","Fee screens need estimates, speed options, and plain-language breakdowns."],"whenToAvoid":["Clear network indicator: \"You're on Base (L2)\".","Monitor blob utilization, warn users during high usage.","Always show comparison or savings percentage.","Protocol plumbing is invisible and never surfaces in user-facing UI."]},"designerTakeaways":["You can design UI that delivers blob space costs ~90% less, L2 txs drop to $0.01-0.10.","You can design UI that delivers blobs have separate fee market.","You can design UI that delivers sub-penny fees make micro-transactions viable."],"problemsSolved":[{"problem":"L2 transactions are expensive because of L1 data costs","oldWay":"L2s post transaction data to L1 calldata at ~$0.50-5 per tx","newWay":"Blob space costs ~90% less, L2 txs drop to $0.01-0.10","impact":"critical"},{"problem":"L1 calldata competes with regular transactions","oldWay":"L2 batch posts compete for same gas, driving up all fees","newWay":"Blobs have separate fee market, don't affect regular txs","impact":"high"},{"problem":"Small transactions not economically viable on L2","oldWay":"$2 in fees for a $5 NFT mint makes no sense","newWay":"Sub-penny fees make micro-transactions viable","impact":"high"},{"problem":"L2 fee spikes during L1 congestion","oldWay":"When L1 is busy, L2 fees spike proportionally","newWay":"Blob fees have independent market, more stable L2 costs","impact":"medium"},{"problem":"Users confused about L2 vs L1 fee relationship","oldWay":"Hard to explain why L2 fees track L1 gas prices","newWay":"L2 fees mostly independent, easier to predict","impact":"medium"}],"uxPatterns":[{"name":"L2 Fee Display","description":"Show users how cheap L2 transactions are","mockup":"concept/one-click-swap","userFlow":["User initiates swap on L2","Fee shown prominently (it's impressively low)","Comparison to L1 shown for context","User confirms, pays fraction of a cent","Transaction confirms quickly"]},{"name":"Network Comparison","description":"Help users choose network based on cost","mockup":"concept/nft-gallery","userFlow":["User wants to mint/trade/interact","App shows available networks","Clear fee comparison displayed","Recommendation based on cost vs security tradeoffs","User selects cheapest suitable option"]},{"name":"Blob Fee Tracker","description":"Show current blob fee market status","mockup":"concept/gas-abstraction","userFlow":["User views fee dashboard","Sees L1 gas and blob gas separately","Understands blob utilization affects L2 costs","Can time transactions for lower fees"]},{"name":"Micro-Transaction UI","description":"Design for viable small transactions","mockup":"generic/list-selector","userFlow":["User wants to send small amount","Preset small amounts shown (now viable!)","Fee is fraction of tip amount","User sends micro-payment","Creator receives almost full amount"]}],"uiComponents":[{"name":"L2FeeDisplay","description":"Show L2 transaction fee with L1 comparison","states":["loading","cheap","moderate","expensive"],"props":["fee","feeUsd","l1Comparison","savings"]},{"name":"NetworkSelector","description":"Choose network with fee comparison","states":["loading","ready","selected"],"props":["networks[]","fees[]","recommended","onSelect"]},{"name":"BlobStatusIndicator","description":"Show blob space utilization","states":["low","moderate","high","full"],"props":["utilization","blobGas","trend"]},{"name":"MicroTxAmount","description":"Amount selector for small transactions","states":["selecting","selected","custom"],"props":["presets[]","minViable","fee","onSelect"]},{"name":"SavingsBadge","description":"Highlight fee savings vs L1","states":["minimal","good","great","amazing"],"props":["percentSaved","amountSaved","comparison"]}],"antiPatterns":[{"pattern":"Showing L2 fees without context","why":"\"$0.02\" means nothing without knowing L1 would be \"$2.00\"","instead":"Always show comparison or savings percentage","severity":"medium"},{"pattern":"Hiding which network user is on","why":"Users may think they're on L1 and be confused by low fees","instead":"Clear network indicator: \"You're on Base (L2)\"","severity":"high"},{"pattern":"Not recommending L2 when appropriate","why":"Users pay 100x more on L1 unnecessarily","instead":"Suggest L2 for transactions that don't need L1 security","severity":"medium"},{"pattern":"Designing for $5+ transaction fees","why":"L2 fees are often sub-cent, old patterns wasteful","instead":"Enable micro-transactions, small tips, frequent interactions","severity":"medium"},{"pattern":"Ignoring blob fee spikes","why":"When blob space is full, L2 fees can spike temporarily","instead":"Monitor blob utilization, warn users during high usage","severity":"high"},{"pattern":"Not explaining L1 vs L2 security tradeoffs","why":"Users should know L2 inherits security from L1 with delay","instead":"Explain when L1 is worth the cost (large amounts, long-term storage)","severity":"low"}],"onMonad":[{"aspect":"L2 Relationship","ethereum":"EIP-4844 reduces costs for L2s posting to L1","monad":"Monad is L1, doesn't post to Ethereum","designImplication":"Monad fees are its own thing, not affected by EIP-4844"},{"aspect":"Fee Predictability","ethereum":"Blob fees can be volatile based on L2 demand","monad":"Monad has its own fee market, typically stable and low","designImplication":"Different fee display patterns needed for Monad"},{"aspect":"Transaction Cost","ethereum":"L2 post-4844: $0.01-0.10 per tx","monad":"Native L1 with similar or lower costs due to parallelism","designImplication":"Can offer L2-like prices with L1 security on Monad"},{"aspect":"Micro-transactions","ethereum":"L2s via 4844 enable micro-tx use cases","monad":"Native micro-tx viability without L2 complexity","designImplication":"Build micro-tx UX patterns for Monad directly"}],"keyTakeaways":["EIP-4844 = cheap data posting = cheap L2 transactions","L2 fees dropped 90%+ after 4844","Always show fee context (comparison to L1)","Design for micro-transactions (they're viable now)","Monitor blob utilization for fee spikes"],"technicalNotes":"EIP-4844 introduces Type 3 (blob) transactions with up to 6 blobs of 128KB each. Blobs are only guaranteed available for ~18 days, not permanent. Blob gas has separate fee market from regular gas using EIP-1559 mechanism. Target is 3 blobs per block, max 6. L2s use blobs to post compressed transaction data instead of calldata."},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-4844","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=EIP-4844","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/EIP-4844","markdown":"https://www.eipsfordesigners.com/standards/EIP-4844/content.md","agent":"https://www.eipsfordesigners.com/standards/EIP-4844/agent.md","api":"https://www.eipsfordesigners.com/api/standards/EIP-4844","official":"https://eips.ethereum.org/EIPS/eip-4844","discussion":"https://ethereum-magicians.org/search?q=EIP-4844"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"EIP-658","name":"Transaction Status Code in Receipts","status":"Final","chain":"both","category":{"id":"infrastructure","name":"Infrastructure","description":"Foundational patterns enabling other standards"},"journeyStages":[{"id":"status","name":"Status & Confirmation","description":"Waiting for and confirming outcomes"}],"uxImpact":"Transaction receipts include explicit success (1) or failure (0) status — no more guessing from gas usage. Design implications: show clear green checkmark/red X for transaction outcomes, display revert reason when available, distinguish between 'transaction included but failed' vs. 'transaction not included'. Design decisions: how to present failed transactions (some users expect failed = not charged, need education); whether to auto-expand failure details or keep UI clean.","hasDetailedContent":true,"content":{"id":"EIP-658","summary":"EIP-658 added a simple status field to transaction receipts: 1 for success, 0 for failure. Before this, wallets had to use hacky methods to determine if a transaction actually worked. Now every wallet can show a clear checkmark or X after any transaction, making blockchain feel more like normal software.","applicability":{"whenToUse":["Your product addresses: no reliable way to know if transaction succeeded.","Your users saw \"confirmed\" but funds didn't move.","The flow should deliver: receipt contains explicit status: 1 = success, 0 = failure.","You are designing a transaction status indicator experience with visible states and recovery paths."],"whenToAvoid":["Always check status field and show Success or Failed explicitly.","Parse revert reason and show actionable suggestion.","Clearly show \"Gas charged: 0.01 ETH (transaction failed but gas was used)\".","Protocol plumbing is invisible and never surfaces in user-facing UI."]},"designerTakeaways":["You can design UI that delivers receipt contains explicit status: 1 = success.","You can clear \"Transaction Failed\" message with status in the interface.","You can design UI that delivers simple boolean check: receipt.status === 1."],"problemsSolved":[{"problem":"No reliable way to know if transaction succeeded","oldWay":"Compare gas used to gas limit, hope remaining gas indicated success","newWay":"Receipt contains explicit status: 1 = success, 0 = failure","impact":"critical"},{"problem":"Users saw \"confirmed\" but funds didn't move","oldWay":"Transaction confirmed but reverted, user confused why nothing happened","newWay":"Clear \"Transaction Failed\" message with status","impact":"critical"},{"problem":"Apps couldn't reliably track transaction outcomes","oldWay":"Complex heuristics to guess success, sometimes wrong","newWay":"Simple boolean check: receipt.status === 1","impact":"high"},{"problem":"Block explorers showed ambiguous results","oldWay":"\"Transaction included in block\" with unclear outcome","newWay":"Green checkmark for success, red X for failure","impact":"high"}],"uxPatterns":[{"name":"Transaction Status Indicator","description":"Clear visual feedback for transaction outcome","mockup":"concept/verify-safety","userFlow":["User submits transaction","Pending state shown while waiting","Receipt received with status field","Clear success/failure indicator displayed","User knows exactly what happened"]},{"name":"Failed Transaction Explanation","description":"Help users understand why transaction failed","mockup":"concept/verify-safety","userFlow":["Transaction reverts on-chain","Receipt shows status = 0","UI displays clear failure message","Reason explained in plain language","Retry option offered"]},{"name":"Transaction History with Status","description":"Show success/failure status for all past transactions","mockup":"generic/token-approval","userFlow":["User views transaction history","Each transaction shows status icon","Success = checkmark, Failed = X","At-a-glance understanding of outcomes"]}],"uiComponents":[{"name":"TransactionStatusBadge","description":"Visual indicator of transaction success/failure","states":["pending","success","failed"],"props":["status","showLabel","size"]},{"name":"ReceiptDisplay","description":"Show full transaction receipt details","states":["loading","success","failed"],"props":["receipt","showTechnical","onRetry"]},{"name":"FailureExplanation","description":"Human-readable failure reason","states":["generic","specific","actionable"],"props":["errorCode","errorMessage","suggestion"]}],"antiPatterns":[{"pattern":"Showing \"Confirmed\" for failed transactions","why":"Confirmation means included in block, not success. Users think it worked.","instead":"Always check status field and show Success or Failed explicitly","severity":"critical"},{"pattern":"Not explaining why transaction failed","why":"User knows it failed but not what to do about it","instead":"Parse revert reason and show actionable suggestion","severity":"high"},{"pattern":"Hiding gas charges on failed transactions","why":"Users don't understand why they lost money on a failed tx","instead":"Clearly show \"Gas charged: 0.01 ETH (transaction failed but gas was used)\"","severity":"high"},{"pattern":"Using same color for pending and success","why":"Users can't distinguish waiting from done","instead":"Distinct colors: yellow=pending, green=success, red=failed","severity":"medium"}],"onMonad":[{"aspect":"Fast Status Updates","ethereum":"Wait 12+ seconds for receipt with status","monad":"Sub-second finality means instant status feedback","designImplication":"Can skip elaborate \"waiting\" animations, show status almost immediately"},{"aspect":"Error Recovery","ethereum":"Failed tx means wait and retry manually","monad":"Fast enough to auto-retry failed transactions","designImplication":"Consider \"Auto-retry on failure\" option for common error types"},{"aspect":"Status Display Duration","ethereum":"Show pending state for 15+ seconds","monad":"Pending state lasts <1 second","designImplication":"Pending indicator may flash by too fast, ensure success state is prominent"}],"relatedStandards":[{"id":"EIP-2718","relationship":"Typed transactions still use the same receipt status format"},{"id":"ERC-6093","relationship":"Custom errors provide detailed failure reasons beyond just status=0"},{"id":"ERC-7751","relationship":"Wrapped errors give even more context about why transactions failed"}]},"sources":[{"label":"Official specification","url":"https://eips.ethereum.org/EIPS/eip-658","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=EIP-658","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/EIP-658","markdown":"https://www.eipsfordesigners.com/standards/EIP-658/content.md","agent":"https://www.eipsfordesigners.com/standards/EIP-658/agent.md","api":"https://www.eipsfordesigners.com/api/standards/EIP-658","official":"https://eips.ethereum.org/EIPS/eip-658","discussion":"https://ethereum-magicians.org/search?q=EIP-658"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"MONAD-RESERVE","name":"Reserve Balance Mechanism","status":"Active","chain":"monad","category":{"id":"transaction-friction","name":"Transaction Friction","description":"Reducing clicks, signatures, and mental overhead"},"journeyStages":[{"id":"asset-display","name":"Asset Discovery & Display","description":"Seeing tokens, NFTs, and balances"},{"id":"executing","name":"Executing Transactions","description":"Performing on-chain actions"},{"id":"gas","name":"Gas & Fees","description":"Paying for transactions"}],"uxImpact":"Every EOA must maintain a 10 MON reserve for async execution safety. Two-layer enforcement: consensus-time (inflight tx budget) and execution-time (revert if ending balance < reserve). Undelegated accounts get one emptying transaction per ~3 blocks that bypasses the reserve; delegated accounts (EIP-7702) cannot. Design implications: show spendable vs total balance, account for reserve in MAX buttons, detect delegation status for emptying tx eligibility, handle transactions that revert after block inclusion, warn when approaching reserve threshold. Design decisions: whether to surface emptying transaction option for sub-10-MON balances vs. simply prompting to add funds.","hasDetailedContent":true,"content":{"id":"MONAD-RESERVE","summary":"Monad requires every EOA to maintain a 10 MON reserve balance to preserve safety under asynchronous execution. During execution, transactions revert if the account's ending balance dips below the reserve — preventing race conditions where concurrent transactions drain an account. Undelegated accounts get one exception: an \"emptying transaction\" that can bypass the reserve once per k-block period (k=3 blocks). Delegated accounts (EIP-7702) cannot use this exception. Wallets must show \"spendable balance\" not just \"total balance\" so users understand what they can actually use.","applicability":{"whenToUse":["Your product addresses: async execution can cause concurrent balance drains.","Your users accidentally drain accounts completely.","The flow should deliver: reserve balance guarantees a gas budget even under concurrent execution.","You are designing a balance display with reserve experience with visible states and recovery paths."],"whenToAvoid":["Always show spendable as primary, total as secondary.","MAX = spendable, estimated gas.","Detect reverts, explain the cause, and offer retry with updated amounts.","The flow is a single low-risk transfer where batching adds confusion."]},"designerTakeaways":["You can design UI that delivers reserve balance guarantees a gas budget even under concurrent execution.","You can design UI that delivers can't spend below reserve (unless using emptying transaction).","You can design UI that delivers \"100 MON total, 90 MON spendable\" is explicit."],"problemsSolved":[{"problem":"Async execution can cause concurrent balance drains","oldWay":"Sequential execution prevents double-spend by ordering","newWay":"Reserve balance guarantees a gas budget even under concurrent execution","impact":"critical"},{"problem":"Users accidentally drain accounts completely","oldWay":"MAX button sends everything, account now useless","newWay":"Can't spend below reserve (unless using emptying transaction)","impact":"high"},{"problem":"New users confused by different balance types","oldWay":"\"I have 100 ETH\" (but actually 100 is fully spendable)","newWay":"\"100 MON total, 90 MON spendable\" is explicit","impact":"medium"},{"problem":"DeFi positions risk trapping users","oldWay":"Stake everything, can't afford gas to unstake","newWay":"Reserve prevents full lockup for most transactions","impact":"medium"}],"uxPatterns":[{"name":"Balance Display with Reserve","description":"Show both total and spendable balances","mockup":"concept/gas-abstraction","userFlow":["User opens wallet","App fetches total balance","Subtracts reserve amount","Displays both clearly","Tooltip explains reserve"]},{"name":"Reserve-Aware Send Form","description":"Prevent sending more than spendable","mockup":"concept/gas-abstraction","userFlow":["User opens send form","Shows spendable, not total","MAX calculates safely","Validates against spendable","Prevents invalid sends"]},{"name":"Low Balance Warning","description":"Alert when approaching reserve threshold","mockup":"generic/balance-display","userFlow":["App monitors spendable balance","When below threshold, show warning","Estimate remaining transactions","Offer easy add funds action","User can dismiss or act"]},{"name":"Emptying Transaction Flow","description":"Allow undelegated accounts to send their full balance once per k-block period","mockup":"generic/balance-display","userFlow":["User has balance below 10 MON reserve","App checks emptying tx eligibility (undelegated, no recent txs)","Shows explanation of emptying transaction rules","User sends full balance in single transaction","App shows cooldown notice: wait ~3 blocks before next tx"]},{"name":"Transaction Revert Notice","description":"Handle transactions that are included in a block but revert during execution","mockup":"concept/gas-abstraction","userFlow":["Transaction submitted and included in block","Execution reverts due to balance falling below reserve","App detects revert and shows clear explanation","Shows current spendable balance for context","Offers retry with updated amounts"]},{"name":"Reserve Explanation Modal","description":"Educate users on why reserve exists","mockup":"concept/gas-abstraction","userFlow":["User clicks \"?\" on reserve","Modal explains concept","Shows with/without comparison","User understands and dismisses"]}],"uiComponents":[{"name":"BalanceBreakdown","description":"Shows total, spendable, and reserved amounts","states":["loading","healthy","low","critical"],"props":["total","spendable","reserved","showDetails"]},{"name":"ReserveIndicator","description":"Visual indicator of reserved amount","states":["normal","highlighted","tooltip-open"],"props":["amount","onClick"]},{"name":"SpendableAmountInput","description":"Input that validates against spendable balance","states":["valid","exceeds-spendable","exceeds-total"],"props":["value","spendable","onChange","onMax"]},{"name":"LowBalanceAlert","description":"Warning banner for low spendable balance","states":["hidden","warning","critical"],"props":["spendable","threshold","onAddFunds","onDismiss"]},{"name":"ReserveExplainerModal","description":"Educational modal about reserve system","states":["closed","open"],"props":["reserveAmount","onClose"]},{"name":"EmptyingTxBanner","description":"Shows emptying transaction eligibility and rules for sub-reserve accounts","states":["eligible","ineligible-delegated","ineligible-cooldown","hidden"],"props":["balance","isDelegated","blocksSinceLastTx","kBlocks"]},{"name":"TransactionRevertNotice","description":"Explains why a transaction was included in a block but reverted during execution","states":["hidden","shown"],"props":["txHash","revertReason","currentSpendable","gasUsed","onRetry"]}],"antiPatterns":[{"pattern":"Showing only total balance","why":"Users think they can spend 100 MON when only 90 is spendable","instead":"Always show spendable as primary, total as secondary","severity":"critical"},{"pattern":"MAX button sending total balance","why":"Transaction will revert during execution, user loses gas fees","instead":"MAX = spendable - estimated gas","severity":"critical"},{"pattern":"Ignoring transaction reverts from concurrent execution","why":"Under async execution, balance can change between submission and execution — valid transactions can be included in a block but still revert","instead":"Detect reverts, explain the cause, and offer retry with updated amounts","severity":"high"},{"pattern":"No explanation of reserve","why":"Users confused why balance is \"locked\"","instead":"Clear info icon explaining reserve protects against async execution risks","severity":"high"},{"pattern":"Hiding the emptying transaction option","why":"Users with <10 MON think they can't transact at all","instead":"Show emptying transaction eligibility and cooldown for undelegated accounts","severity":"high"},{"pattern":"Treating delegated and undelegated accounts the same","why":"Delegated accounts (EIP-7702) cannot use emptying transactions — different rules apply","instead":"Check delegation status and show appropriate balance/send constraints","severity":"high"},{"pattern":"Using Ethereum wallet UX patterns unchanged","why":"Monad has different balance semantics and two-layer enforcement (consensus + execution)","instead":"Design specifically for reserve model","severity":"high"},{"pattern":"Letting users feel \"trapped\" by reserve","why":"Negative UX, feels like funds are inaccessible","instead":"Frame positively: \"Always able to transact\" and mention emptying tx escape hatch","severity":"medium"}],"onMonad":[{"aspect":"Balance Model","ethereum":"Balance is fully spendable","monad":"10 MON minimum reserve required per EOA","designImplication":"All balance UIs must show spendable vs total"},{"aspect":"Enforcement","ethereum":"Sequential execution prevents double-spend by ordering","monad":"Two-layer enforcement: consensus-time (inflight tx budget over k=3 blocks) and execution-time (revert if ending balance < reserve)","designImplication":"Transactions can be included in blocks but still revert — design for this edge case"},{"aspect":"Emptying Exception","ethereum":"No concept — balance fully spendable down to zero","monad":"Undelegated accounts get one emptying tx per k-block period that bypasses reserve","designImplication":"Show emptying tx eligibility for sub-10-MON accounts; explain cooldown period"},{"aspect":"MAX Calculations","ethereum":"MAX = balance - gas","monad":"MAX = balance - reserve - gas (or full balance via emptying tx if eligible)","designImplication":"MAX button logic must check delegation status and emptying tx eligibility"},{"aspect":"Smart Wallets (EIP-7702)","ethereum":"Can delegate entire balance","monad":"Delegated accounts cannot use emptying exception — reserve strictly enforced","designImplication":"Delegated accounts have stricter constraints; session keys can't bypass reserve"}],"keyTakeaways":["Monad requires 10 MON minimum reserve per EOA for async execution safety","ALWAYS show spendable balance, not just total","MAX button must account for reserve AND check emptying tx eligibility","Undelegated accounts can bypass reserve once per ~3 blocks (emptying transaction)","Delegated accounts (EIP-7702) cannot use the emptying exception","Transactions can be included in blocks but revert during execution — handle this gracefully","Frame reserve as benefit: \"Always able to transact\""],"technicalNotes":"Monad enforces a minimum balance reserve (10 MON per EOA) to preserve safety under asynchronous execution. Enforcement happens at two layers: (1) Consensus-time — validates that inflight transactions (included less than k=3 blocks ago) don't exceed a gas spend budget equal to the reserve balance or the account's lagged-state balance, whichever is lower. (2) Execution-time — transactions revert when the account's ending balance (before refunds) dips below the reserve, except for emptying transactions. Emptying transactions allow undelegated accounts to bypass the reserve once per k-block period, provided: the account has been undelegated for k blocks, has no pending delegation changes, and hasn't sent a transaction in the last k blocks. Delegated accounts (EIP-7702) cannot use the emptying exception and are strictly bound by the reserve. Note: valid transactions can be included in blocks but still revert during execution because consensus cannot access current state during validation."},"sources":[],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/MONAD-RESERVE","markdown":"https://www.eipsfordesigners.com/standards/MONAD-RESERVE/content.md","agent":"https://www.eipsfordesigners.com/standards/MONAD-RESERVE/agent.md","api":"https://www.eipsfordesigners.com/api/standards/MONAD-RESERVE"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"MONAD-ASYNC","name":"Asynchronous Execution","status":"Active","chain":"monad","category":{"id":"infrastructure","name":"Infrastructure","description":"Foundational patterns enabling other standards"},"journeyStages":[{"id":"status","name":"Status & Confirmation","description":"Waiting for and confirming outcomes"}],"uxImpact":"Consensus finalizes before execution completes — transactions are 'in' but state updates follow. Design implications: show transaction stages (Proposed → Voted → Finalized → Verified), display 'Awaiting execution' status after inclusion, indicate state root finality separately from transaction finality. Design decisions: whether to show Finalized (800ms, safe for most) or wait for Verified (1.6s, guaranteed state) for confirmations; how to explain the 3-block execution lag simply.","hasDetailedContent":true,"content":{"id":"MONAD-ASYNC","summary":"Monad uses asynchronous execution — transactions are executed optimistically before consensus is complete, then validated. This is why Monad feels instant. For UX, this means showing \"Confirming...\" briefly (~400ms), then \"Confirmed\" (~800ms). The two-phase feedback model replaces Ethereum's long pending state.","applicability":{"whenToUse":["Your product addresses: long wait times feel like something is broken.","Your product addresses: no intermediate feedback during execution.","The flow should deliver: \"Confirming...\" → \"Confirmed\" in under a second.","You are designing a two-phase confirmation experience with visible states and recovery paths."],"whenToAvoid":["Match animation speed to actual ~1s confirmation.","Design for instant, not for waiting.","Subtle phase labels or just smooth fast transition.","Protocol plumbing is invisible and never surfaces in user-facing UI."]},"designerTakeaways":["You can design UI that delivers \"Confirming...\" → \"Confirmed\" in under a second.","You can design UI that delivers two clear phases: executing → confirming → done.","You can design UI that delivers fast feedback, no confusion about status."],"problemsSolved":[{"problem":"Long wait times feel like something is broken","oldWay":"15 seconds of \"Pending...\" — is it stuck?","newWay":"\"Confirming...\" → \"Confirmed\" in under a second","impact":"critical"},{"problem":"No intermediate feedback during execution","oldWay":"Spinner spins, user waits, no idea what's happening","newWay":"Two clear phases: executing → confirming → done","impact":"high"},{"problem":"Users retry transactions thinking they failed","oldWay":"Slow = must be broken, click again","newWay":"Fast feedback, no confusion about status","impact":"high"}],"uxPatterns":[{"name":"Two-Phase Confirmation","description":"Show execution then confirmation phases","mockup":"generic/instant-confirm","userFlow":["User submits transaction","Phase 1: Execution (optimistic)","Phase 2: Consensus confirmation","Phase 3: Final confirmation","Show completion time"]},{"name":"Inline Quick Confirmation","description":"Minimal inline status for fast transactions","mockup":"generic/instant-confirm","userFlow":["User clicks confirm","Button shows \"Sending...\"","Updates to \"Confirming...\"","Shows \"Sent! (0.8s)\"","No page change needed"]}],"uiComponents":[{"name":"AsyncStatusIndicator","description":"Shows current phase of async execution","states":["submitting","executing","confirming","confirmed","failed"],"props":["currentPhase","estimatedTime"]},{"name":"PhaseProgressBar","description":"Visual progress through execution phases","states":["phase-1","phase-2","complete"],"props":["phase","progress"]},{"name":"FastConfirmAnimation","description":"Quick animation for sub-second confirmations","states":["idle","animating","complete"],"props":["duration","onComplete"]}],"antiPatterns":[{"pattern":"Long loading animations on Monad","why":"Animation takes longer than actual confirmation","instead":"Match animation speed to actual ~1s confirmation","severity":"high"},{"pattern":"Not showing phase distinction","why":"Users don't understand why there are two steps","instead":"Subtle phase labels or just smooth fast transition","severity":"medium"},{"pattern":"Using Ethereum-speed expectations","why":"Designing for 15s when reality is <1s","instead":"Design for instant, not for waiting","severity":"high"}],"onMonad":[{"aspect":"Execution Model","ethereum":"Sequential: execute after consensus","monad":"Async: execute optimistically, confirm after","designImplication":"Show two quick phases instead of one long wait"},{"aspect":"Total Time","ethereum":"12-15 seconds for block + execution","monad":"~800ms total","designImplication":"Feedback should be nearly instant"},{"aspect":"Optimistic Display","ethereum":"Wait for block before showing result","monad":"Can show likely result after execution phase","designImplication":"Optimistic UI updates are safe"}],"keyTakeaways":["Monad = async execution (execute then confirm)","Total time: ~800ms (execution + confirmation)","Show quick two-phase feedback, not long spinner","Design for instant, not for waiting","Animation should match actual speed"],"technicalNotes":"Monad executes transactions optimistically before consensus is finalized. Execution happens in parallel across transactions without conflicts. Consensus confirms the execution was valid. If conflicts detected, transactions re-execute. Result: apparent instant confirmation because execution begins immediately on submission. Finality in single slot."},"sources":[],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/MONAD-ASYNC","markdown":"https://www.eipsfordesigners.com/standards/MONAD-ASYNC/content.md","agent":"https://www.eipsfordesigners.com/standards/MONAD-ASYNC/agent.md","api":"https://www.eipsfordesigners.com/api/standards/MONAD-ASYNC"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"MONAD-PARALLEL","name":"Parallel Execution","status":"Active","chain":"monad","category":{"id":"infrastructure","name":"Infrastructure","description":"Foundational patterns enabling other standards"},"journeyStages":[{"id":"executing","name":"Executing Transactions","description":"Performing on-chain actions"}],"uxImpact":"Transactions execute in parallel but results are identical to serial execution — same guarantees, faster throughput. Design implications: no UI changes needed for parallel execution (it's transparent), can show 10,000 TPS capability in network stats, transaction ordering guarantees remain — display order matches execution order. Design decisions: whether to surface parallel execution as a feature (marketing) or keep invisible (it just works); avoid implying transactions can 'race' each other.","hasDetailedContent":true,"content":{"id":"MONAD-PARALLEL","sources":[{"label":"Official specification","url":"https://docs.monad.xyz","type":"official-spec"}],"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25","summary":"Transactions execute in parallel but results are identical to serial execution — same guarantees, faster throughput.","designerTakeaways":["You can use inline status updates instead of long pending modals because finality is sub-second.","Your activity feed order should match block inclusion order — do not suggest random reordering.","You can cite high throughput in network stats without teaching parallel execution mechanics."],"applicability":{"whenToUse":["Building Monad-native apps.","Designing status and confirmation UX on Monad.","Marketing Monad speed responsibly."],"whenToAvoid":["Ethereum-only products with no Monad deployment.","Explaining execution internals to end users."]},"prototypeFirst":[{"screen":"Inline transaction status","why":"Sub-second finality replaces long pending modals.","covers":["Submit","Included","Done"],"include":["Compact status strip","No 12-block progress bar","Instant success state"]},{"screen":"Activity feed ordering","why":"Feed order must match user trust in sequence.","covers":["Multiple txs same block"],"include":["Deterministic order label","Same-block grouping","No race wording"]},{"screen":"Network stats marketing panel","why":"Optional speed story without internals.","covers":["TPS stat","Finality stat"],"include":["10000+ TPS optional","Sub-second finality","No parallel jargon"]},{"screen":"Multi-action session","why":"Fast chain enables rapid sequential user actions.","covers":["Swap then stake quickly"],"include":["No artificial delay between steps","Fresh balance after each"]}],"mentalModel":[{"label":"Same guarantees","description":"Parallel execution equals serial results — users trust outcomes unchanged."},{"label":"Faster confirmation","description":"Only user-visible difference is speed."},{"label":"Order","description":"Block order is deterministic — not a free-for-all race."},{"label":"Invisible infra","description":"Parallel is implementation — not a user setting."},{"label":"Throughput","description":"More txs per second — optional marketing stat."}],"statesToDesign":[{"state":"Submitted","trigger":"Tx sent.","userNeed":"Brief progress.","designResponse":"Short submitting strip — not modal."},{"state":"Included","trigger":"Sub-second inclusion.","userNeed":"Immediate feedback.","designResponse":"Inline success within same view."},{"state":"Same-block batch","trigger":"User sends multiple txs quickly.","userNeed":"Understand sequence.","designResponse":"Group with consistent order in feed."},{"state":"Failed fast","trigger":"Revert quickly visible.","userNeed":"Fix immediately.","designResponse":"Fast error with retry — no long wait."},{"state":"Network stats view","trigger":"User views about network.","userNeed":"Optional speed context.","designResponse":"Throughput/finality stats without parallel lecture."}],"designDecisions":[{"question":"Surface parallel execution in UI?","recommendation":"No in product flows; optional in technical docs.","rationale":"Invisible infra reduces anxiety."},{"question":"Marketing TPS claims?","recommendation":"Optional stats page; not on every confirm.","rationale":"Speed felt through UX not numbers."},{"question":"Pending modal duration?","recommendation":"Eliminate or shorten to inline strip.","rationale":"Sub-second finality makes modals obsolete."}],"problemsSolved":[{"problem":"Slow confirmation UX copied from Ethereum","oldWay":"Long pending modals","newWay":"Inline sub-second status on Monad","impact":"high"},{"problem":"False race narrative","oldWay":"Users fear tx reordering games","newWay":"Never imply racing; show deterministic order","impact":"medium"},{"problem":"Under-marketing speed","oldWay":"Feels like any chain","newWay":"Optional throughput stats for context","impact":"low"}],"uxPatterns":[{"name":"Inline Fast Status","description":"Sub-second status strip not modal.","mockup":"concept/tx-status","components":["StatusStrip","QuickSuccess","ExplorerLink"],"userFlow":["Submit tx","Brief submitting","Success inline","Continue"]},{"name":"Ordered Activity Feed","description":"Deterministic tx order same block.","mockup":"concept/tx-status","components":["FeedList","BlockGroup","OrderLabel"],"userFlow":["Multiple txs","Grouped by block","Stable order shown"]}],"seenInTheWild":[{"app":"Monad","url":"https://monad.xyz/","note":"Parallel execution and throughput positioning."},{"app":"Solana","url":"https://solana.com/","note":"Fast finality UX patterns — speed without internals."},{"app":"Stripe","url":"https://stripe.com/","note":"Inline payment success — no long pending for fast systems."}],"antiPatterns":[{"pattern":"Teaching parallel execution in send flow","why":"Confuses non-technical users","instead":"Just show fast confirmation","severity":"high"},{"pattern":"Race your transaction copy","why":"Implies MEV-style reordering games","instead":"Transactions confirm in block order","severity":"critical"},{"pattern":"Ethereum-style 12-block pending bar","why":"Misleading on sub-second chain","instead":"Inline status tuned to Monad finality","severity":"high"}],"vocabulary":[{"use":"Confirmed","avoid":"Parallel executed","why":"Normal tx language."},{"use":"Fast confirmation","avoid":"Parallel throughput","why":"User benefit not mechanism."},{"use":"Transaction order","avoid":"Serial equivalence guarantee","why":"Plain ordering language."}],"onMonad":[{"aspect":"Native behavior","ethereum":"Serial execution slower finality","monad":"Parallel execution with serial-equivalent results","designImplication":"Design Monad-first: inline status, no long pending modals."},{"aspect":"Confirmation speed","ethereum":"Multi-step pending UX","monad":"Sub-second finality","designImplication":"Replace modals with inline strips."},{"aspect":"Throughput","ethereum":"Congestion periods","monad":"High TPS headroom","designImplication":"Optional network stats; never imply tx racing."}],"technicalNotes":"MONAD-PARALLEL is transparent to users; design for speed, never imply transaction races.","relatedStandards":[{"id":"MONAD-MEMPOOL","relationship":"Local mempools complement parallel execution"},{"id":"MONAD-OPCODE","relationship":"Gas pricing differs on Monad"}]},"sources":[{"label":"Official specification","url":"https://docs.monad.xyz","type":"official-spec"},{"label":"Official specification","url":"https://docs.monad.xyz","type":"official-spec"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/MONAD-PARALLEL","markdown":"https://www.eipsfordesigners.com/standards/MONAD-PARALLEL/content.md","agent":"https://www.eipsfordesigners.com/standards/MONAD-PARALLEL/agent.md","api":"https://www.eipsfordesigners.com/api/standards/MONAD-PARALLEL","official":"https://docs.monad.xyz"},"freshness":{"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25"}},{"id":"MONAD-MEMPOOL","name":"Local Validator Mempools","status":"Active","chain":"monad","category":{"id":"security","name":"Security & Trust","description":"Helping users verify, control, and protect their assets"},"journeyStages":[{"id":"reading","name":"Reading & Understanding","description":"Interpreting what you're being asked to do"},{"id":"executing","name":"Executing Transactions","description":"Performing on-chain actions"}],"uxImpact":"No global mempool — transactions go directly to upcoming block leaders, reducing MEV and improving inclusion times. Design implications: remove 'pending in mempool' states (transactions either included or not), no sandwich attack warnings needed, use lower default slippage (0.5% vs 1-3%), show confident price quotes without 'may change due to MEV' caveats. Design decisions: remove MEV protection toggles entirely (cleaner) vs. keep for cross-chain consistency; how to explain faster inclusion without complex mempool concepts.","hasDetailedContent":true,"content":{"id":"MONAD-MEMPOOL","sources":[{"label":"Official specification","url":"https://docs.monad.xyz","type":"official-spec"}],"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25","summary":"No global mempool — transactions go directly to upcoming block leaders, reducing MEV and improving inclusion times.","designerTakeaways":["You can remove MEV protection toggles on Monad-native swap flows.","Your default slippage can start at 0.5% not 1-3% with clear explanation on Monad.","You can simplify pending to Submitting → Included without mempool pending stage."],"applicability":{"whenToUse":["Monad-native DeFi and swap products.","Designing slippage and MEV copy for Monad.","Transaction status UX on Monad."],"whenToAvoid":["Cross-chain flows where Ethereum MEV still applies.","Ethereum-only interfaces."]},"prototypeFirst":[{"screen":"Swap with Monad slippage defaults","why":"Lower slippage safe without global mempool.","covers":["0.5% default","User raises slippage"],"include":["Default 0.5% chip","Explain why lower on Monad","Advanced override"]},{"screen":"Simplified pending states","why":"No mempool pending phase.","covers":["Submitting","Included","Failed"],"include":["Two-step status","No mempool pending label"]},{"screen":"DeFi settings without MEV toggle","why":"Remove dead controls on Monad.","covers":["Monad network","Ethereum network compare"],"include":["Clean settings on Monad","MEV section only on Ethereum"]},{"screen":"Price quote confidence","why":"Quotes without MEV caveat clutter.","covers":["Quote display"],"include":["Clean quote","No may be sandwiched footnote on Monad"]}],"mentalModel":[{"label":"No global mempool","description":"Txs not publicly visible pre-inclusion — different from Ethereum."},{"label":"Direct to leader","description":"Faster inclusion path — less pending limbo."},{"label":"Reduced sandwich","description":"Not zero everywhere — but Monad-native swaps simpler."},{"label":"Slippage","description":"Can be tighter by default on Monad."},{"label":"Cross-chain caveat","description":"Bridges from Ethereum still have Ethereum MEV rules."}],"statesToDesign":[{"state":"Submitting","trigger":"Tx broadcast.","userNeed":"Brief wait.","designResponse":"Submitting — not mempool pending."},{"state":"Included fast","trigger":"Leader includes tx.","userNeed":"Quick success.","designResponse":"Included within sub-second UX."},{"state":"Not included retry","trigger":"Tx dropped not included.","userNeed":"Retry path.","designResponse":"Not included — retry with explanation not mempool stuck."},{"state":"Swap on Monad","trigger":"DeFi flow.","userNeed":"Simple slippage.","designResponse":"0.5% default; no MEV toggle."},{"state":"Cross-chain bridge in","trigger":"Asset from Ethereum.","userNeed":"MEV context if relevant.","designResponse":"Ethereum leg may differ — show on bridge source only."}],"designDecisions":[{"question":"Keep MEV toggle for parity?","recommendation":"Remove on Monad; keep on Ethereum cross-chain views.","rationale":"Dead toggle erodes trust."},{"question":"Default slippage?","recommendation":"0.5% Monad; preserve higher default on Ethereum.","rationale":"Match risk profile to mempool model."},{"question":"Explain no mempool to users?","recommendation":"Only in help doc — not swap form.","rationale":"Outcome is simpler UX not lecture."}],"problemsSolved":[{"problem":"Scary MEV copy on every swap","oldWay":"May be frontrun warnings everywhere","newWay":"Clean quotes on Monad-native swaps","impact":"high"},{"problem":"Inflated slippage defaults","oldWay":"1-3% for Ethereum MEV","newWay":"0.5% default on Monad","impact":"medium"},{"problem":"Misleading mempool pending UI","oldWay":"Pending in mempool state never resolves same way","newWay":"Submitting → Included binary","impact":"medium"}],"uxPatterns":[{"name":"Monad Swap Defaults","description":"Lower slippage without MEV toggle.","mockup":"eip-7702/one-click-swap","components":["SlippageChip","CleanQuote","SwapButton"],"userFlow":["Open swap on Monad","See 0.5% default","Quote clean","Confirm"]},{"name":"Binary Inclusion Status","description":"No mempool pending stage.","mockup":"concept/tx-status","components":["SubmittingLabel","IncludedLabel"],"userFlow":["Submit","Submitting briefly","Included or retry"]}],"seenInTheWild":[{"app":"Uniswap","url":"https://app.uniswap.org/","note":"Slippage and MEV settings reference — simplify on Monad."},{"app":"CowSwap","url":"https://cow.fi/","note":"MEV-aware UX contrast for Ethereum."},{"app":"Monad docs","url":"https://docs.monad.xyz/","note":"Local mempool architecture context."}],"antiPatterns":[{"pattern":"MEV protection toggle on Monad swaps","why":"Implies Ethereum mempool model","instead":"Remove toggle; clean quote UI","severity":"high"},{"pattern":"Pending in public mempool copy","why":"State does not exist on Monad","instead":"Submitting → Included","severity":"high"},{"pattern":"3% default slippage on Monad","why":"Unnecessary user cost","instead":"0.5% default with advanced override","severity":"medium"}],"vocabulary":[{"use":"Submitting","avoid":"Pending in mempool","why":"Accurate Monad state."},{"use":"Included","avoid":"Mined from mempool","why":"Leader inclusion language."},{"use":"Slippage tolerance","avoid":"MEV protection buffer","why":"Standard DeFi term."}],"onMonad":[{"aspect":"Mempool model","ethereum":"Global public mempool MEV surface","monad":"Local validator mempools direct to leader","designImplication":"Remove MEV toggles; simplify pending on Monad."},{"aspect":"Slippage defaults","ethereum":"1-3% common for sandwich protection","monad":"0.5% reasonable default","designImplication":"Network-aware slippage presets."},{"aspect":"Inclusion time","ethereum":"Mempool pending variable","monad":"Fast leader inclusion","designImplication":"Binary submitting/included status."}],"technicalNotes":"MONAD-MEMPOOL: no global mempool UX; remove MEV toggles and lower default slippage on Monad-native flows.","relatedStandards":[{"id":"MONAD-PARALLEL","relationship":"Fast inclusion complements parallel execution"},{"id":"ERC-7683","relationship":"Cross-chain still has source-chain MEV"}]},"sources":[{"label":"Official specification","url":"https://docs.monad.xyz","type":"official-spec"},{"label":"Official specification","url":"https://docs.monad.xyz","type":"official-spec"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/MONAD-MEMPOOL","markdown":"https://www.eipsfordesigners.com/standards/MONAD-MEMPOOL/content.md","agent":"https://www.eipsfordesigners.com/standards/MONAD-MEMPOOL/agent.md","api":"https://www.eipsfordesigners.com/api/standards/MONAD-MEMPOOL","official":"https://docs.monad.xyz"},"freshness":{"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25"}},{"id":"MONAD-7702","name":"EIP-7702 Constraints","status":"Active","chain":"monad","category":{"id":"transaction-friction","name":"Transaction Friction","description":"Reducing clicks, signatures, and mental overhead"},"journeyStages":[{"id":"executing","name":"Executing Transactions","description":"Performing on-chain actions"},{"id":"gas","name":"Gas & Fees","description":"Paying for transactions"}],"uxImpact":"EIP-7702 account abstraction supported with reserve balance constraints — delegated EOAs can't drain below 10 MON. Design implications: show clear warnings when delegating EOA ('10 MON minimum balance required while delegated'), indicate delegation status in account views, warn if attempting to send all funds from delegated account. Design decisions: whether delegation UI should enforce 10 MON check upfront or allow and show clear revert reasons; how to explain the CREATE/CREATE2 restriction for advanced users.","hasDetailedContent":true,"content":{"id":"MONAD-7702","sources":[{"label":"Official specification","url":"https://docs.monad.xyz","type":"official-spec"}],"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25","summary":"EIP-7702 account abstraction supported with reserve balance constraints — delegated EOAs can't drain below 10 MON.","designerTakeaways":["You can show Delegated badge with 10 MON minimum balance required while delegated in account header.","Your send-max flow can cap at balance minus 10 MON when delegation active with explanation.","You can block send-all with clear You must keep 10 MON while delegated copy before wallet opens."],"applicability":{"whenToUse":["Monad wallet supports EIP-7702 delegation.","Users delegate EOAs to smart account code.","Send and gas flows must respect reserve."],"whenToAvoid":["Non-delegated plain EOA flows.","Ethereum 7702 without Monad reserve rules.","Products not on Monad."]},"prototypeFirst":[{"screen":"Delegation setup confirm","why":"User must accept reserve rule before delegate.","covers":["Pre-delegate"],"include":["10 MON minimum callout","While delegated explainer","Confirm delegate"]},{"screen":"Delegated account header","why":"Persistent status while delegation active.","covers":["Delegated active"],"include":["Delegated badge","Reserve requirement link","Undelegate path"]},{"screen":"Send max with reserve cap","why":"Prevent revert on send-all.","covers":["Send max","Over cap blocked"],"include":["Max sendable amount","10 MON kept copy","Adjust amount inline"]},{"screen":"Advanced CREATE restriction note","why":"Power users hit deploy limits.","covers":["Deploy attempt blocked"],"include":["Advanced accordion","CREATE restricted while delegated","Undelegate to deploy"]}],"mentalModel":[{"label":"Delegation","description":"EOA temporarily uses smart account code via 7702."},{"label":"10 MON reserve","description":"Minimum balance floor while delegated — not optional."},{"label":"Send max","description":"Max out is balance minus reserve not full balance."},{"label":"Undelegate","description":"Removing delegation lifts reserve requirement."},{"label":"CREATE restriction","description":"Contract deploy from delegated EOA blocked — advanced edge."}],"statesToDesign":[{"state":"Not delegated","trigger":"Plain EOA.","userNeed":"Normal send.","designResponse":"Standard send; optional Enable smart features."},{"state":"Delegated active","trigger":"7702 delegation live.","userNeed":"Know reserve rule.","designResponse":"Delegated badge and reserve callout."},{"state":"Send exceeds reserve","trigger":"User tries send all.","userNeed":"Fix before sign.","designResponse":"Inline cap with 10 MON must remain."},{"state":"Undelegate flow","trigger":"User removes delegation.","userNeed":"Know reserve lifts.","designResponse":"After undelegate full balance sendable."},{"state":"CREATE blocked","trigger":"Deploy attempt.","userNeed":"Advanced explanation.","designResponse":"Deploy not available while delegated."}],"designDecisions":[{"question":"Enforce reserve in UI or rely on revert?","recommendation":"Cap in UI before wallet.","rationale":"Revert after sign feels like bug."},{"question":"When show 10 MON rule?","recommendation":"Delegation confirm and every send-max while delegated.","rationale":"Surprise reserve causes support tickets."},{"question":"CREATE restriction visibility?","recommendation":"Advanced only unless user attempts deploy.","rationale":"Retail users never hit CREATE."}],"problemsSolved":[{"problem":"Send-all revert on delegated EOA","oldWay":"Max send fails mysteriously","newWay":"UI caps at balance minus 10 MON","impact":"high"},{"problem":"Delegation risks unclear","oldWay":"User delegates blindly","newWay":"Reserve rule at delegate confirm","impact":"high"},{"problem":"Delegated state invisible","oldWay":"Same account UI","newWay":"Delegated badge and reserve link","impact":"medium"}],"uxPatterns":[{"name":"Delegation Reserve Warning","description":"10 MON floor explained at delegate and send.","mockup":"erc-4337/gas-abstraction","components":["DelegateBadge","ReserveCallout","SendCap"],"userFlow":["Delegate","See 10 MON rule","Send max capped","No revert"]},{"name":"Delegated Account Header","description":"Persistent delegation status on account.","mockup":"eip-7702/session-permissions","components":["DelegatedChip","UndelegateLink","ReserveTooltip"],"userFlow":["Account delegated","Badge visible","Send respects reserve","Undelegate optional"]}],"seenInTheWild":[{"app":"MetaMask","url":"https://metamask.io/","note":"EIP-7702 delegation UX emerging."},{"app":"Monad docs","url":"https://docs.monad.xyz/","note":"7702 reserve constraint documentation."},{"app":"EIP-7702","url":"https://eips.ethereum.org/EIPS/eip-7702","note":"Base delegation patterns."}],"antiPatterns":[{"pattern":"Send max without reserve cap","why":"Revert after full amount entered","instead":"Cap sendable amount with explanation","severity":"critical"},{"pattern":"Delegate without reserve disclosure","why":"User discovers rule at failed send","instead":"10 MON minimum at delegate confirm","severity":"critical"},{"pattern":"Hidden delegated state","why":"User forgets constraints active","instead":"Persistent Delegated badge","severity":"high"}],"vocabulary":[{"use":"Keep 10 MON while delegated","avoid":"Reserve balance constraint","why":"Plain rule language."},{"use":"Smart account mode","avoid":"7702 delegation active","why":"User-facing mode name."},{"use":"Maximum you can send","avoid":"Balance minus reserve constant","why":"Send form copy."}],"onMonad":[{"aspect":"7702 reserve","ethereum":"7702 rules differ on Ethereum","monad":"10 MON minimum while delegated — Monad-specific","designImplication":"Always show Monad reserve rule on delegate and send-max."},{"aspect":"Delegation cost","ethereum":"Delegation txs vary","monad":"Low fees ease delegate/undelegate trials","designImplication":"Inline undelegate option without gas scare."},{"aspect":"CREATE restriction","ethereum":"Varies by implementation","monad":"CREATE/CREATE2 blocked while delegated","designImplication":"Surface in advanced on deploy attempt only."}],"technicalNotes":"MONAD-7702: enforce 10 MON reserve in send UI; disclose at delegation confirm.","relatedStandards":[{"id":"EIP-7702","relationship":"Base EOA delegation standard"},{"id":"ERC-4337","relationship":"Smart account feature parity target"}]},"sources":[{"label":"Official specification","url":"https://docs.monad.xyz","type":"official-spec"},{"label":"Official specification","url":"https://docs.monad.xyz","type":"official-spec"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/MONAD-7702","markdown":"https://www.eipsfordesigners.com/standards/MONAD-7702/content.md","agent":"https://www.eipsfordesigners.com/standards/MONAD-7702/agent.md","api":"https://www.eipsfordesigners.com/api/standards/MONAD-7702","official":"https://docs.monad.xyz"},"freshness":{"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25"}},{"id":"MONAD-FINALITY","name":"Fast Finality","status":"Active","chain":"monad","category":{"id":"infrastructure","name":"Infrastructure","description":"Foundational patterns enabling other standards"},"journeyStages":[{"id":"status","name":"Status & Confirmation","description":"Waiting for and confirming outcomes"}],"uxImpact":"Transactions finalize in 800ms (2 blocks), with speculative finality at 400ms — near-instant confirmation UX. Design implications: show confirmation in under 1 second, remove 'waiting for confirmations' multi-block progress bars, enable real-time trading UIs, display 'Finalized' badge quickly. Design decisions: whether to confirm at speculative finality (400ms, extremely rare reverts) or full finality (800ms, guaranteed) — most apps should use speculative for responsiveness.","hasDetailedContent":true,"content":{"id":"MONAD-FINALITY","summary":"Monad confirms transactions in under 1 second. Where Ethereum takes 12+ seconds for a block and minutes for finality, Monad gives you a confirmation checkmark almost instantly. This transforms UX from \"waiting for blockchain\" to \"feels like Venmo.\" Designers can finally build responsive interfaces without artificial loading states.","applicability":{"whenToUse":["Your product addresses: long wait times for transaction confirmation.","Your users abandon during waiting states.","The flow should deliver: click send → checkmark in <1 second.","You are designing a instant confirmation experience with visible states and recovery paths."],"whenToAvoid":["Inline confirmation, continue the flow.","Redesign flows for instant confirmation.","Show actual speed, it's a feature!.","Protocol plumbing is invisible and never surfaces in user-facing UI."]},"designerTakeaways":["You can design UI that delivers click send → checkmark in <1 second.","You can design UI that delivers instant feedback keeps users engaged.","You can design UI that delivers real-time on-chain interactions possible."],"problemsSolved":[{"problem":"Long wait times for transaction confirmation","oldWay":"Click send → spinner for 15+ seconds → maybe it worked?","newWay":"Click send → checkmark in <1 second","impact":"critical"},{"problem":"Users abandon during waiting states","oldWay":"30% drop-off during \"Confirming...\" screen","newWay":"Instant feedback keeps users engaged","impact":"critical"},{"problem":"Can't build responsive real-time apps","oldWay":"Games, social apps feel sluggish on-chain","newWay":"Real-time on-chain interactions possible","impact":"high"},{"problem":"Uncertainty during pending state","oldWay":"\"Did it work? Should I retry? Is it stuck?\"","newWay":"Know immediately if it succeeded or failed","impact":"high"}],"uxPatterns":[{"name":"Instant Confirmation","description":"Transaction confirmed before user can blink","mockup":"generic/instant-confirm","userFlow":["User confirms transaction","Submit to network","<1 second passes","Show success immediately","Update balance in place"]},{"name":"Real-Time Balance Updates","description":"Balances update instantly as transactions confirm","mockup":"generic/instant-confirm","userFlow":["Transaction submitted","Balance animates to pending state","Confirmation received (<1s)","Balance snaps to new value","Activity feed updates live"]},{"name":"No-Wait Gaming Actions","description":"In-game actions feel instant","mockup":"generic/instant-confirm","userFlow":["Player clicks Attack","Action submitted","Visual feedback immediately","Chain confirms in <1s","State updates, next action ready"]},{"name":"Skip the Loading Screen","description":"Design patterns without artificial waits","mockup":"generic/instant-confirm","userFlow":["User confirms action","Inline success indicator","No separate loading page","Continue flow immediately"]}],"uiComponents":[{"name":"InstantConfirmation","description":"Success state shown immediately on confirmation","states":["sending","confirmed","failed"],"props":["txHash","confirmationTime","onComplete"]},{"name":"AnimatedBalanceUpdate","description":"Balance that animates smoothly between values","states":["stable","updating","updated"],"props":["previousValue","newValue","animationDuration"]},{"name":"LiveActivityFeed","description":"Real-time transaction feed with instant updates","states":["empty","loading","live"],"props":["transactions[]","onNewTransaction"]},{"name":"InlineStatus","description":"Tiny status indicator instead of full-page loading","states":["hidden","pending","success","error"],"props":["message","duration"]}],"antiPatterns":[{"pattern":"Full-page loading screens for transactions","why":"Unnecessary on Monad — confirmation is faster than page load","instead":"Inline confirmation, continue the flow","severity":"high"},{"pattern":"Artificial \"Confirming...\" delays","why":"Some apps add fake delay to seem \"blockchain-y\"","instead":"Show actual speed — it's a feature!","severity":"medium"},{"pattern":"Multiple confirmation stages in UI","why":"\"Pending... Submitted... Confirming...\" overkill for <1s total","instead":"Single transition: action → done","severity":"medium"},{"pattern":"Not showing confirmation time","why":"Users don't realize how fast Monad is","instead":"Show \"Confirmed in 0.4s\" — it's impressive!","severity":"medium"},{"pattern":"Using Ethereum timing expectations","why":"Design for 15s wait doesn't fit <1s reality","instead":"Redesign flows for instant confirmation","severity":"high"}],"onMonad":[{"aspect":"Confirmation Time","ethereum":"12-15 seconds for block, 12+ min for finality","monad":"<1 second to finality","designImplication":"Design for instant, not for waiting"},{"aspect":"Loading States","ethereum":"Essential — user needs to wait","monad":"Often unnecessary — confirmation faster than animation","designImplication":"Use inline indicators, skip loading pages"},{"aspect":"User Expectations","ethereum":"Users expect blockchain to be slow","monad":"Feels like Web2 app","designImplication":"Surprise and delight with speed"},{"aspect":"Real-Time Features","ethereum":"Difficult due to slow blocks","monad":"Viable — games, chat, live updates","designImplication":"Build features impossible on Ethereum"}],"keyTakeaways":["Monad confirms in <1 second — design for instant","Skip full-page loading screens","Use inline success indicators","Show confirmation time to highlight speed","Build real-time features that would be impossible on Ethereum"],"technicalNotes":"Monad achieves fast finality through pipelined execution and optimistic parallelism. Transactions are executed speculatively before consensus is complete, then validated. The result is sub-second confirmation times compared to Ethereum's 12-second block times. Finality on Monad is reached in a single slot, unlike Ethereum's epochs. This enables UX patterns previously impossible on blockchain."},"sources":[],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/MONAD-FINALITY","markdown":"https://www.eipsfordesigners.com/standards/MONAD-FINALITY/content.md","agent":"https://www.eipsfordesigners.com/standards/MONAD-FINALITY/agent.md","api":"https://www.eipsfordesigners.com/api/standards/MONAD-FINALITY"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"MONAD-OPCODE","name":"Opcode Repricing","status":"Active","chain":"monad","category":{"id":"infrastructure","name":"Infrastructure","description":"Foundational patterns enabling other standards"},"journeyStages":[{"id":"gas","name":"Gas & Fees","description":"Paying for transactions"}],"uxImpact":"Cold storage access costs ~4x more gas than Ethereum to reflect Monad's optimized compute vs. storage ratio. Design implications: gas estimates may differ from Ethereum for storage-heavy operations, show Monad-specific gas estimates (not Ethereum defaults), first-touch storage operations cost more. Design decisions: whether to surface repricing details in advanced gas settings or just show accurate Monad estimates; ensure gas estimation tools use Monad-specific pricing.","hasDetailedContent":true,"content":{"id":"MONAD-OPCODE","sources":[{"label":"Official specification","url":"https://docs.monad.xyz","type":"official-spec"}],"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25","summary":"Monad reprices EVM opcodes so cold storage reads and writes cost roughly four times more than on Ethereum, while compute stays relatively cheaper. Gas previews built for mainnet will under-estimate first-touch storage on Monad and surprise users at sign. Label estimates as Monad-specific and surface when a transaction's first storage operation will cost more.","designerTakeaways":["You can label estimates as Monad network in gas preview footers.","Your advanced gas panel can note First-time storage costs more on Monad when relevant.","You can validate estimation RPC uses Monad opcode table not mainnet fork defaults."],"applicability":{"whenToUse":["Gas estimation on Monad deployments.","Storage-heavy contract interactions.","Advanced gas settings for power users."],"whenToAvoid":["Ethereum-only flows.","Flat fee sponsorship hiding gas entirely.","Users never see gas breakdown."]},"prototypeFirst":[{"screen":"Monad gas estimate row","why":"Every confirm shows chain-accurate fee.","covers":["Simple send","Storage-heavy call"],"include":["Network: Monad label","Estimate amount","Refresh estimate"]},{"screen":"First storage operation hint","why":"Cold storage premium surprises users.","covers":["First SSTORE-like op"],"include":["One-time setup cost note","Lower follow-up txs footnote"]},{"screen":"Advanced gas breakdown","why":"Power users audit estimate components.","covers":["Expand advanced"],"include":["Opcode-weight hint","Monad pricing source","Compare disabled Ethereum default"]},{"screen":"Wrong estimate error recovery","why":"When estimate drifted at sign.","covers":["Estimate too low revert"],"include":["Estimate was wrong — refreshed","Retry with updated estimate"]}],"mentalModel":[{"label":"Monad gas schedule","description":"Different opcode prices than Ethereum."},{"label":"Cold storage premium","description":"First touch storage costs more — like Ethereum cold access amplified."},{"label":"Compute vs storage ratio","description":"Monad optimizes compute; storage relatively pricier."},{"label":"Estimate source","description":"Must call Monad-aware estimator not Ethereum default."},{"label":"User visibility","description":"Accurate total matters; opcode detail optional advanced."}],"statesToDesign":[{"state":"Normal estimate","trigger":"Standard tx.","userNeed":"Trust fee.","designResponse":"Monad-labeled estimate row."},{"state":"High storage estimate","trigger":"Storage-heavy op detected.","userNeed":"Understand spike.","designResponse":"Includes one-time storage setup cost note."},{"state":"Estimate loading","trigger":"Sim running.","userNeed":"Wait signal.","designResponse":"Estimating on Monad spinner."},{"state":"Estimate failed","trigger":"Sim error.","userNeed":"Not blind sign.","designResponse":"Cannot estimate — fix tx or retry."},{"state":"Estimate refreshed after revert","trigger":"Prior estimate wrong.","userNeed":"Updated number.","designResponse":"New estimate shown before retry."}],"designDecisions":[{"question":"Show opcode repricing details?","recommendation":"Advanced only; total estimate default.","rationale":"Users need accurate total not lecture."},{"question":"Footnote cold storage on first write?","recommendation":"Yes when estimate spike detected.","rationale":"Explains one-time premium."},{"question":"Cross-chain estimate UI?","recommendation":"Separate Monad and Ethereum estimators — never mix.","rationale":"Mixed tables cause systematic wrong estimates."}],"problemsSolved":[{"problem":"Wrong gas previews on Monad","oldWay":"Ethereum estimator on Monad txs","newWay":"Monad opcode table in estimator","impact":"critical"},{"problem":"Surprise storage setup cost","oldWay":"Estimate low then sign higher","newWay":"First storage cost footnote","impact":"high"},{"problem":"User distrust after revert","oldWay":"Generic failed","newWay":"Refresh estimate and explain storage premium","impact":"medium"}],"uxPatterns":[{"name":"Monad Gas Estimate Row","description":"Chain-labeled accurate fee preview.","mockup":"erc-4337/gas-abstraction","components":["NetworkLabel","EstimateAmount","RefreshButton"],"userFlow":["Compose tx","Monad estimate loads","User sees fee","Sign accurate amount"]},{"name":"Storage Premium Footnote","description":"Explain cold storage spike on Monad.","mockup":"concept/typed-data","components":["EstimateFootnote","StorageHint"],"userFlow":["Heavy storage tx","Estimate high","Footnote explains","User accepts informed"]}],"seenInTheWild":[{"app":"MetaMask","url":"https://metamask.io/","note":"Network-specific gas estimation patterns."},{"app":"Blocknative","url":"https://www.blocknative.com/","note":"Gas estimation API chain awareness."},{"app":"Monad docs","url":"https://docs.monad.xyz/","note":"Opcode repricing documentation."}],"antiPatterns":[{"pattern":"Ethereum gas defaults on Monad","why":"Systematic wrong estimates","instead":"Monad-specific estimator always","severity":"critical"},{"pattern":"No explanation when storage estimate spikes","why":"User thinks bug or scam","instead":"First-time storage cost footnote","severity":"high"},{"pattern":"Hiding network on estimate row","why":"User assumes Ethereum pricing","instead":"Network: Monad label on fee row","severity":"medium"}],"vocabulary":[{"use":"Estimated fee on Monad","avoid":"Opcode repricing adjusted gas","why":"Simple fee language."},{"use":"One-time setup cost","avoid":"Cold SSTORE premium","why":"Plain storage hint."},{"use":"Refresh estimate","avoid":"Re-simulate with Monad schedule","why":"User action language."}],"onMonad":[{"aspect":"Opcode pricing","ethereum":"Ethereum gas schedule baseline","monad":"Repriced opcodes — cold storage ~4x relative premium vs compute","designImplication":"Never use Ethereum gas tables for Monad estimates."},{"aspect":"Storage-heavy txs","ethereum":"Storage cost familiar ratio","monad":"Storage relatively costlier — footnote first-touch ops","designImplication":"Detect storage spikes and explain in UI."},{"aspect":"Overall fees","ethereum":"Higher absolute gas many ops","monad":"Lower fees overall but storage premium still matters","designImplication":"Accurate relative estimate more than absolute warning."}],"technicalNotes":"MONAD-OPCODE: wire Monad opcode pricing into all estimators; footnote cold storage on estimate spikes.","relatedStandards":[{"id":"MONAD-PARALLEL","relationship":"Fast inclusion after sign"},{"id":"MONAD-7702","relationship":"Delegation txs need Monad estimates too"}]},"sources":[{"label":"Official specification","url":"https://docs.monad.xyz","type":"official-spec"},{"label":"Official specification","url":"https://docs.monad.xyz","type":"official-spec"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/MONAD-OPCODE","markdown":"https://www.eipsfordesigners.com/standards/MONAD-OPCODE/content.md","agent":"https://www.eipsfordesigners.com/standards/MONAD-OPCODE/agent.md","api":"https://www.eipsfordesigners.com/api/standards/MONAD-OPCODE","official":"https://docs.monad.xyz"},"freshness":{"lastReviewed":"2026-05-25","lastUpdated":"2026-05-25"}},{"id":"MIP-3","name":"Linear Memory","status":"Proposed","chain":"monad","category":{"id":"infrastructure","name":"Infrastructure","description":"Foundational patterns enabling other standards"},"journeyStages":[{"id":"gas","name":"Gas & Fees","description":"Paying for transactions"}],"uxImpact":"Linear memory pricing replaces Ethereum's quadratic model — gas costs scale predictably with operation size. Design implications: show tighter estimate ranges with higher confidence, use Monad-specific gas estimation (not Ethereum defaults), enable batch and data-heavy flows without surprise fee jumps. Design decisions: whether to explain linear scaling to users or just show accurate estimates; how to present confidence levels on fee previews.","officialUrl":"https://github.com/monad-crypto/MIPs/blob/main/MIPS/MIP-3.md","hasDetailedContent":true,"content":{"id":"MIP-3","summary":"MIP-3 changes how Monad charges for memory usage. Instead of quadratic pricing (where doubling memory costs 4x), it uses linear pricing (doubling costs 2x). This makes gas costs more predictable and prevents certain contract patterns from being prohibitively expensive. For users, it means gas estimates are more accurate and fewer surprise fee jumps.","applicability":{"whenToUse":["Your product addresses: gas estimates often wrong for memory-heavy operations.","Your product addresses: some operations unexpectedly expensive.","The flow should deliver: linear pricing = estimates match actuals more closely.","Fee screens need estimates, speed options, and plain-language breakdowns."],"whenToAvoid":["Use Monad-specific gas estimation.","Show confidence level, range when uncertain.","Show per-item cost comparison."]},"designerTakeaways":["You can design UI that delivers linear pricing = estimates match actuals more closely.","You can design UI that delivers predictable cost scaling for data-heavy operations.","You can collapse multi-step actions into one confirmation users understand."],"problemsSolved":[{"problem":"Gas estimates often wrong for memory-heavy operations","oldWay":"Estimate shows $2, actual cost is $8 due to quadratic memory pricing","newWay":"Linear pricing = estimates match actuals more closely","impact":"high"},{"problem":"Some operations unexpectedly expensive","oldWay":"Returning large arrays costs exponentially more","newWay":"Predictable cost scaling for data-heavy operations","impact":"high"},{"problem":"DeFi protocols avoid certain patterns","oldWay":"Can't efficiently process large batches on-chain","newWay":"Batch operations economically viable","impact":"medium"},{"problem":"Users hit gas limits unexpectedly","oldWay":"Transaction fails partway through due to memory cost spike","newWay":"More consistent gas consumption","impact":"medium"}],"uxPatterns":[{"name":"Predictable Gas Estimates","description":"Show users accurate cost predictions","mockup":"concept/nft-gallery","userFlow":["User initiates batch operation","App estimates gas (linear scaling)","Shows high-confidence estimate","Explains predictable pricing","User confirms with accurate expectation"]},{"name":"Batch Size Slider","description":"Let users choose batch size with live cost preview","mockup":"concept/bundled-defi","userFlow":["User adjusts batch size slider","Live cost updates (linearly)","User sees predictable scaling","Chooses optimal batch size","Confirms with known cost"]}],"uiComponents":[{"name":"LinearGasEstimate","description":"Shows gas estimate with confidence indicator","states":["estimating","confident","uncertain"],"props":["gasUnits","gasPrice","confidence"]},{"name":"BatchSizeSelector","description":"Slider or input for selecting batch size","states":["single","batch","max"],"props":["min","max","value","costPerItem","onChange"]},{"name":"CostScaleExplainer","description":"Visual explanation of linear cost scaling","states":["collapsed","expanded"],"props":["baseCount","selectedCount","baseCost"]}],"antiPatterns":[{"pattern":"Using Ethereum gas estimates on Monad","why":"Different pricing models lead to wrong estimates","instead":"Use Monad-specific gas estimation","severity":"high"},{"pattern":"Showing low confidence estimates as precise","why":"Users budget wrong, get frustrated","instead":"Show confidence level, range when uncertain","severity":"medium"},{"pattern":"Not explaining why batch is cheaper per-item","why":"Users don't understand value of batching","instead":"Show per-item cost comparison","severity":"medium"}],"onMonad":[{"aspect":"Memory Pricing","ethereum":"Quadratic: memory_cost = a × size²","monad":"Linear: memory_cost = b × size","designImplication":"Batch operations much more predictable in cost"},{"aspect":"Estimate Accuracy","ethereum":"±20-50% common for complex operations","monad":"±5-10% typical with linear model","designImplication":"Can show tighter ranges, higher confidence"},{"aspect":"Large Data Operations","ethereum":"Often prohibitively expensive","monad":"Economically viable","designImplication":"Enable features like batch claims, large airdrops"}],"keyTakeaways":["MIP-3 = linear memory pricing (more predictable)","Gas estimates are more accurate on Monad","Batch operations scale predictably","Use Monad-specific gas estimation, not Ethereum's","Show confidence levels when displaying estimates"],"technicalNotes":"MIP-3 modifies the EVM memory expansion cost formula. Ethereum uses: memory_cost = (size² / 512) + (3 × size). Monad uses linear pricing: memory_cost = k × size. This primarily affects contracts that allocate large memory regions, like those processing arrays or returning large data structures."},"sources":[{"label":"Official specification","url":"https://github.com/monad-crypto/MIPs/blob/main/MIPS/MIP-3.md","type":"official-spec"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/MIP-3","markdown":"https://www.eipsfordesigners.com/standards/MIP-3/content.md","agent":"https://www.eipsfordesigners.com/standards/MIP-3/agent.md","api":"https://www.eipsfordesigners.com/api/standards/MIP-3","official":"https://github.com/monad-crypto/MIPs/blob/main/MIPS/MIP-3.md"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}},{"id":"MIP-4","name":"Reserve Balance Introspection","status":"Proposed","chain":"monad","category":{"id":"transaction-friction","name":"Transaction Friction","description":"Reducing clicks, signatures, and mental overhead"},"journeyStages":[{"id":"asset-display","name":"Asset Discovery & Display","description":"Seeing tokens, NFTs, and balances"},{"id":"executing","name":"Executing Transactions","description":"Performing on-chain actions"},{"id":"gas","name":"Gas & Fees","description":"Paying for transactions"}],"uxImpact":"Pre-check if a transaction would fail before sending — apps can query spendable balance accounting for the 10 MON reserve. Design implications: show spendable vs total balance, disable send when amount exceeds spendable, pre-validate before wallet popup, explain reserve with clear tooltips. Design decisions: whether MAX subtracts reserve + gas automatically; how to surface pre-check failures without blocking power users.","officialUrl":"https://github.com/monad-crypto/MIPs/blob/main/MIPS/MIP-4.md","hasDetailedContent":true,"content":{"id":"MIP-4","summary":"MIP-4 adds a way to check if a transaction would fail BEFORE sending it. Specifically, it lets apps check if your account has enough \"spendable\" balance (accounting for the reserve requirement). Instead of sending a transaction and having it revert, wallets can pre-check and show \"Insufficient spendable balance\" before you waste time or gas.","applicability":{"whenToUse":["Your product addresses: transactions fail after user confirms.","Your product addresses: confusing when balance looks sufficient but tx fails.","The flow should deliver: check fails instantly before submission.","You are designing a pre-send validation experience with visible states and recovery paths."],"whenToAvoid":["Always subtract reserve for spendable amount.","MAX = balance, reserve, gas.","Clear tooltip: \"Reserved for async execution safety\"."]},"designerTakeaways":["You can design UI that delivers check fails instantly before submission.","You can shows \"Spendable: 90 MON\" (10 reserved for async execution safety) in the interface.","You can design UI that delivers light introspection without full simulation."],"problemsSolved":[{"problem":"Transactions fail after user confirms","oldWay":"Click send → wait → \"Transaction reverted: insufficient funds\"","newWay":"Check fails instantly before submission","impact":"high"},{"problem":"Confusing when balance looks sufficient but tx fails","oldWay":"\"I have 100 MON, why can't I send 100 MON?\"","newWay":"Shows \"Spendable: 90 MON\" (10 reserved for async execution safety)","impact":"high"},{"problem":"No way to pre-validate complex operations","oldWay":"Submit and pray, or use expensive simulation","newWay":"Light introspection without full simulation","impact":"medium"},{"problem":"Smart wallets can't predict failures accurately","oldWay":"UserOp submitted, bundler rejects, user confused","newWay":"Pre-check reserve before UserOp creation","impact":"medium"}],"uxPatterns":[{"name":"Pre-Send Validation","description":"Check if transaction would succeed before sending","mockup":"concept/gas-abstraction","userFlow":["User enters amount","App calls reserve introspection","Calculates spendable = balance - reserve","If amount > spendable: show error","Prevent submission of failing tx"]},{"name":"Smart MAX Button","description":"MAX accounts for reserve and gas","mockup":"concept/gas-abstraction","userFlow":["User clicks MAX","App queries total balance","Subtracts reserve (from MIP-4)","Subtracts estimated gas","Fills in maximum safe amount"]},{"name":"Transaction Pre-Check","description":"Validate before wallet popup","mockup":"generic/token-approval","userFlow":["User initiates swap","App runs pre-checks","Includes reserve balance check","Shows pass/fail for each","Only enable confirm if all pass"]}],"uiComponents":[{"name":"SpendableBalanceDisplay","description":"Shows spendable vs total balance with reserve","states":["loading","healthy","low","insufficient"],"props":["totalBalance","reserveAmount","spendable"]},{"name":"ReserveExplainer","description":"Tooltip explaining what reserve is for","states":["collapsed","expanded"],"props":["reserveAmount","reason"]},{"name":"PreTransactionCheck","description":"Checklist of validations before sending","states":["checking","passed","failed"],"props":["checks[]","onRetry"]},{"name":"SmartMaxButton","description":"Calculates max considering reserve and gas","states":["calculating","ready","zero"],"props":["balance","reserve","estimatedGas","onMax"]}],"antiPatterns":[{"pattern":"Using total balance for validation","why":"Ignores reserve, tx will fail","instead":"Always subtract reserve for spendable amount","severity":"critical"},{"pattern":"MAX button ignoring reserve","why":"User sends MAX → tx fails → frustration","instead":"MAX = balance - reserve - gas","severity":"critical"},{"pattern":"No explanation of reserve","why":"User confused why they can't spend their balance","instead":"Clear tooltip: \"Reserved for async execution safety\"","severity":"high"},{"pattern":"Only checking balance client-side","why":"Race conditions, stale data","instead":"Call introspection function for real-time check","severity":"medium"}],"onMonad":[{"aspect":"Reserve Introspection","ethereum":"No equivalent — balance is fully spendable","monad":"Can query exact reserve amount","designImplication":"Always show spendable vs total on Monad"},{"aspect":"Pre-validation","ethereum":"Simulate with eth_call (expensive)","monad":"Light introspection available","designImplication":"Pre-validate all transactions efficiently"},{"aspect":"Smart Wallet Integration","ethereum":"UserOps can drain to zero","monad":"Must account for reserve in UserOps","designImplication":"Paymaster logic needs reserve awareness"}],"keyTakeaways":["MIP-4 = pre-check if transaction would fail","On Monad, always show SPENDABLE balance, not total","MAX button must subtract reserve + gas","Pre-validate before showing wallet popup","Explain reserve with clear UI tooltips"],"technicalNotes":"MIP-4 adds an introspection method to query account reserve requirements. On Monad, EOAs must maintain a 10 MON minimum reserve to preserve safety under asynchronous execution — preventing race conditions where concurrent transactions drain an account. The introspection returns the current reserve amount, allowing apps to calculate spendable = balance - reserve. Undelegated accounts can bypass the reserve via a one-time \"emptying transaction\" per k-block period (k=3), but delegated accounts (EIP-7702) cannot."},"sources":[{"label":"Official specification","url":"https://github.com/monad-crypto/MIPs/blob/main/MIPS/MIP-4.md","type":"official-spec"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/MIP-4","markdown":"https://www.eipsfordesigners.com/standards/MIP-4/content.md","agent":"https://www.eipsfordesigners.com/standards/MIP-4/agent.md","api":"https://www.eipsfordesigners.com/api/standards/MIP-4","official":"https://github.com/monad-crypto/MIPs/blob/main/MIPS/MIP-4.md"},"freshness":{"lastReviewed":"2026-04-05","lastUpdated":"2026-04-05"}}]}