How do you design secure EIP-712 signing flows for dApps?
Blockchain Front-End Developer
answer
Secure signing flows start with EIP-712 typed data so users see structured, human-readable fields instead of opaque hex. To fight phishing, sign only domain-specific data with clear context and origin checks. Prevent signature malleability by hashing with eth_signTypedData_v4 and replay-protecting with nonces. Minimize token approvals by defaulting to exact amounts or session keys instead of unlimited allowances. Always show transaction simulations and risk warnings before confirm.
Long Answer
A strong signing flow balances UX and defense-in-depth. Users of DeFi and dApps often face phishing prompts, misleading approvals, or ambiguous blobs of data. Designing around EIP-712 typed data ensures clarity and protects users from blind signing.
1) EIP-712 typed data as the foundation
Traditional personal_sign exposes users to opaque hex. EIP-712 requires structured schemas, typed fields, and a domain separator. This allows wallets to show clear context: chain ID, contract, intent, and parameters. Always include name, version, chainId, and verifyingContract in the domain. This prevents cross-dapp replay and gives visual anchors. Typed data also hardens against signature malleability because hashes are deterministic and non-ambiguous.
2) Prevent phishing and consent misdirection
Never request blanket signatures like “sign to log in” without binding to a nonce, origin, and expiry. Use SIWE (Sign-In with Ethereum) or a similar pattern where the message includes domain, issuedAt, nonce, and URI. For approvals or permit signatures, embed explicit spender, amount, and deadline. Provide contextual cues in the UI: project logo, contract name, risk score. This creates friction for phishing, where attackers often present generic or misleading prompts.
3) Minimize token approvals
Unlimited ERC-20 approvals remain a major exploit vector. Instead, design flows that:
- Default to exact-amount approvals per transaction.
- Use permit (EIP-2612) signatures so approvals are gasless, time-bound, and can be revoked.
- For power users, support session keys with scoped allowances that expire automatically.
- Provide an “approval dashboard” where users can review and revoke allowances.
By surfacing explicit numbers and deadlines, you shrink the attack surface.
4) Signature integrity and replay protection
Always use eth_signTypedData_v4, not eth_sign, to avoid ambiguous encodings. Bind signatures to nonces, chain IDs, and contracts. Store nonces server-side (if backend exists) or rely on smart contract counters. Enforce deadlines (expiry) and single-use semantics. This ensures even if a signature leaks, it can’t be replayed or malleated across contexts.
5) Transaction simulations and previews
Phishing thrives when users confirm blind. Integrate a simulation engine (Tenderly, Blocknative, or in-house) to show human-readable results: “You will send 100 USDC to Uniswap V3 at address 0x… and receive ~99.5 DAI.” Highlight changes to allowances, contract calls, or risky opcodes (delegatecall, selfdestruct). Use warnings like: “This contract can spend all of your tokens” vs “This contract can spend 5 USDC until 12/31.” Previews help non-expert users spot red flags.
6) Front-end UX best practices
- Always surface the spender address and token logo in approvals.
- Color-code risk: green for bounded approvals, red for unlimited.
- Include transaction cost estimates and warnings for high slippage.
- Provide a “view on explorer” link before signing.
- For multilingual dApps, localize fields so non-English speakers don’t sign blind.
7) Continuous monitoring and education
Log signing events (without private data) and analyze patterns. Alert if an unusual approval request spikes. Offer users a one-click revoke link. Educate them via tooltips: “Never sign if you don’t understand the message.” Security is as much UX and culture as cryptography.
By combining EIP-712 typed data, contextualized SIWE messages, bounded approvals, nonce/deadline checks, and readable transaction simulations, you design signing flows that minimize token theft, stop signature malleability, and empower users to confirm with confidence.
Table
Common Mistakes
Relying on personal_sign with opaque hex blobs—users can’t tell if it’s harmless or a malicious permit. Asking for unlimited approvals by default, leaving wallets permanently exposed. Forgetting nonces/expiries in signed messages, enabling replay. Using ambiguous signing methods like eth_sign that suffer from signature malleability. Not surfacing spender addresses or amounts—so users approve attackers without realizing. Skipping transaction simulations, forcing users to “trust” contract code. Providing login signatures without binding to domain/URI, so phishing sites reuse them. Neglecting multi-chain context—signatures replayed across chains. Worst of all: over-optimizing UX at the cost of safety.
Sample Answers (Junior / Mid / Senior)
Junior:
“I’d use EIP-712 typed data instead of personal_sign so users see structured fields. I’d add nonces and expiries to stop replays, and always show spender/amount in approvals.”
Mid:
“I’d implement SIWE with domain + nonce + expiry for logins. For approvals, default to exact amounts or use permit signatures (EIP-2612). I’d integrate simulations so users see expected token flows before confirming.”
Senior:
“Our flow enforces eth_signTypedData_v4, nonces, and deadlines. Approvals are scoped and revocable via a dashboard. Every tx passes through a simulation engine (Tenderly/Blocknative) that outputs a human-readable summary. UX highlights spender, amounts, risk, and expiry. This design minimizes phishing and signature malleability, while keeping UX smooth.”
Evaluation Criteria
Interviewers look for defense-in-depth. Strong answers mention EIP-712 typed data with domain, nonce, and expiry. Replay/malleability protection: eth_signTypedData_v4, nonces, deadlines. Approval hygiene: exact amounts, EIP-2612 permits, revocation dashboards. UX: transaction simulations, spender/amount surfaced, risk warnings, explorer links. Security headers: context binding to chain ID and domain. Advanced answers: SIWE for logins, session keys with scoped allowances, integration with simulators like Tenderly. Weak answers: “just use MetaMask” or “just trust the contract.” Strong candidates detail phishing prevention, token approval minimization, and readable transaction previews.
Preparation Tips
Practice coding EIP-712 typed data schemas for login and approvals. Use eth_signTypedData_v4 with domain/nonce/expiry, test replay protection. Build a sample ERC-20 approval flow: exact-amount vs unlimited; add permit (EIP-2612) with deadlines. Integrate a simulation API (Tenderly or Blocknative) to parse a Uniswap swap into “100 USDC → ~99.5 DAI.” Create UI components that highlight spender address, token logo, and risk (∞ approvals in red). Explore SIWE libraries for authentication. Test malleability by signing with different methods. Build a revoke-approvals dashboard using Etherscan APIs. Rehearse explaining why typed data + simulations = better UX + safety.
Real-world Context
A DeFi lending app adopted EIP-712 typed data for logins, adding nonce/expiry. Phishing signatures dropped after users saw domain and purpose. A DEX switched from unlimited approvals to exact-amount + permit signatures; an exploit that drained competitors left them untouched. A DAO tool integrated Tenderly simulations; users saw “This call moves treasury USDC to 0x…” instead of opaque hex, blocking governance attacks. A wallet added an approval dashboard + red warnings for unlimited allowances; revocations spiked and attack surface shrank. Across DeFi, the combo of typed data, bounded approvals, and readable previews has cut fraud incidents measurably.
Key Takeaways
- Use EIP-712 typed data with domain, nonce, expiry to prevent phishing/replay.
- Stop signature malleability with eth_signTypedData_v4.
- Minimize risk: exact-amount approvals, EIP-2612 permits, revocation dashboards.
- Always show transaction simulations and spender/amount in UI.
Security = cryptography + human-readable UX.
Practice Exercise
Scenario:
You’re building a DeFi dApp where users swap tokens and stake liquidity. Your investors warn about phishing and over-approvals. Users must trust that they’re approving only what they intend.
Tasks:
- Replace personal_sign with EIP-712 typed data; include chainId, verifyingContract, nonce, and expiry.
- Implement SIWE login with domain + issuedAt + nonce to bind signatures.
- Change approvals: default to exact-amount; integrate EIP-2612 permits with deadlines. Flag ∞ approvals in red.
- Add a transaction simulation (Tenderly/Blocknative) showing “You will send 100 USDC to 0x… and receive ~99.5 DAI.”
- Surface spender addresses, contract names, and logos in UI. Add explorer links.
- Test replay by reusing a signature; verify nonces block it. Test malleability with eth_sign; show why eth_signTypedData_v4 is stronger.
- Provide a dashboard to review/revoke allowances.
- Educate users with tooltips: “Never sign if you don’t understand this data.”
Deliverable:
A demo + walkthrough showing how your flow prevents phishing, neutralizes signature malleability, minimizes approvals, and displays readable previews that let users make informed decisions.

