# EIP-712: Typed Structured Data Signing

Source: https://www.eipsfordesigners.com/standards/EIP-712
Agent brief: https://www.eipsfordesigners.com/standards/EIP-712/agent.md
Machine-readable JSON: https://www.eipsfordesigners.com/api/standards/EIP-712
Last reviewed: 2026-04-05
Last updated: 2026-04-05

| Field | Value |
| --- | --- |
| Status | Final |
| Chain | both |
| Category | Comprehension & Display |
| Journey stages | Authentication & Identity, Reading & Understanding |
| Detailed guide | Yes |
| Official specification | https://eips.ethereum.org/EIPS/eip-712 |
| Discussion search | https://ethereum-magicians.org/search?q=EIP-712 |

## UX Impact

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.

## 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.

## For Designers

- 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.

## Applicability

### When to Use

- 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.

### When to Avoid

- 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.

## Problems It Solves

### Users sign unreadable hex blobs

Impact: critical

Old way: Sign "0x4f8a3bc7d91e..." — what does this even mean?

New way: Sign "Swap 100 USDC for 0.05 ETH, deadline 10 minutes"

### Can't verify what you're signing

Impact: critical

Old way: Hope the dApp isn't lying about what that hex means

New way: Wallet parses and displays actual data fields

### Signatures replayable across contexts

Impact: high

Old way: Sign for Uniswap, attacker uses on SushiSwap

New way: Domain separator binds signature to specific contract

## Anti-Patterns

### Not using EIP-712 for off-chain signatures

Severity: critical

Users sign unreadable data, easy to miss attacks

Instead: Always use typed structured data

### Poor field names in typed data

Severity: high

"a1", "b2" mean nothing to users

Instead: Human-readable names: "tokenAmount", "deadline"

### Not including deadline in signatures

Severity: high

Signature valid forever, can be reused later

Instead: Always include expiration/deadline field

### Showing raw timestamps

Severity: medium

"1707123456" is not human-readable

Instead: Convert to "Feb 5, 2024 at 3:30 PM"

## Mental Model

### User intent

The dApp builds a structured message with amounts, deadlines, and permissions instead of opaque hex.

### Typed schema

Field names and types define what appears in the wallet. Use human-readable labels in your schema, not a1 or value0.

### Domain binding

The domain ties the signature to one app, chain, and verifying contract. Wallets should show this context so replays fail elsewhere.

### Wallet display

The wallet parses typed data and renders labeled fields. Your app preview should match what the wallet will show.

### Signature scope

The signed message grants exactly what the fields describe, often off-chain until submitted. Include deadlines so stale signatures are obvious.

## UI Components

### TypedDataViewer

Renders EIP-712 typed data in readable format
States: loading, parsed, error
Props: typedData, domain, primaryType

### FieldValuePair

Single field:value row with type indicator
States: normal, highlighted, warning
Props: name, value, type

### DomainVerifier

Shows and verifies signing domain
States: verified, unknown, suspicious
Props: name, chainId, verifyingContract

## On Monad

### Chain ID in Domain

Ethereum: chainId: 1

Monad: chainId: [monad-id]

Design implication: Domain separator must use Monad chain ID

### Contract Addresses

Ethereum: Ethereum mainnet addresses

Monad: Monad-specific contract addresses

Design implication: Verify contracts match expected Monad deployments

## Key Takeaways

- 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

## UX Patterns

### Typed Data Signature

Structured, readable signature request

User flow:

- dApp requests EIP-712 signature
- Wallet parses typed data structure
- Displays fields in readable format
- Shows domain/contract info
- User verifies and signs

Mockup registry key: `concept/typed-data` (React UI on the live standard page).

### Order Confirmation

Trading orders with clear terms

User flow:

- 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

Mockup registry key: `concept/typed-data` (React UI on the live standard page).

## Technical Notes

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).
