{"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"}}