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