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