EIP-712 lets a wallet display structured fields before you sign, but readable data is not proof that the request is safe. Check the signing domain, chain, verifying contract, message fields and replay rules against the action you intended. The application that accepts the signature determines what it can authorize.
Read the request as a proposed authorization
A page says “verify your wallet.” The wallet then displays a neatly labeled message. Before signing, translate that request into a sentence: this account authorizes this action, under these conditions, for this application. If the fields cannot support that sentence, the page's explanation has left a gap.
EIP-712 defines how to hash and sign typed structured data with a signing domain. A request normally presents types, the field definitions; primaryType, the main structure; domain, its signing context; and message, the values. The standard does not define every application's authorization policy or provide automatic replay protection.
In MetaMask, eth_signTypedData_v4 is the documented method for this structured signing flow. Its documentation treats the domain name, main type name and field names as a security interface because they appear in the confirmation. Those are useful reading aids, but the names themselves are supplied by the application. See MetaMask's signing guidance.
Read the whole structure, including nested objects and arrays. A friendly title cannot explain an unfamiliar recipient, a large permission amount or an opaque nested operation. If the wallet cannot expose the material fields, obtain a trustworthy decoding before deciding whether to proceed.
Decode a harmless receipt request
Consider an original, fictional request for an isolated practice application. It only acknowledges receipt of report 84. There are no assets, token permissions or trading functions in this example. The addresses are invented placeholders; no contract is deployed and no usable signature is supplied.
The practice domain contains these fields. Their types are part of types.EIP712Domain.
| Domain field and type | Fictional value | What to compare |
|---|---|---|
name, string | PracticeReceipt | Expected application name |
version, string | 1 | Expected signing format version |
chainId, uint256 | 31337 | The exercise's chosen local chain identifier |
verifyingContract, address | 0x1111111111111111111111111111111111111111 | The exercise's expected verifier |
The primaryType is Receipt. Its ordered field definitions and message values are:
| Message field | Type | Fictional value |
|---|---|---|
reader | address | 0x2222222222222222222222222222222222222222 |
reportId | uint256 | 84 |
purpose | string | receipt-only |
nonce | uint256 | 7 |
deadline | uint256 | 1793189100 |
For this exercise, the deadline means 28 October 2026 at 12:05:00 UTC, expressed as Unix seconds. The nonce is the practice application's sequence number for this reader. It is unrelated to the reader's ordinary Ethereum transaction nonce.
The intended sentence is now specific: the reader acknowledges report 84 to this practice verifier on this local chain, once, no later than 12:05 UTC. That interpretation still needs an acceptance rule. A field named purpose does not prevent a badly designed application from using the signature for something else.
The example is harmless because of the stated application's behavior, not because the message happens to omit a token amount. This is the same boundary examined in AI tool least privilege: an understandable request still needs a component that enforces its scope.
Separate the website from the signing domain
The signing domain is not a browser hostname. Its name is not a certificate that the requester owns a particular website. Compare the website you deliberately opened with the protocol's authoritative deployment information, then compare the requested chain and full verifier address with that information.
EIP-712 permits applications to include the domain fields relevant to their design; not every valid domain includes every possible field. The specification defines chainId as the chain identifier and verifyingContract as the contract checking the signature. See the domain separator definition. An absent field therefore needs a protocol-specific explanation, rather than an assumption that the wallet silently filled it in.
For an ordinary single-chain contract action, an unexplained missing chain or verifier leaves the intended scope unresolved. Conversely, the presence of both does not prove the contract is trustworthy. It tells you which context to investigate.
Where supported, a read-only domain query can add evidence. OpenZeppelin's EIP712 implementation exposes eip712Domain() to return the fields used by its domain separator. Its helper still leaves type-specific message encoding to the protocol. That is documented library behavior, not evidence that an arbitrary deployed verifier uses it correctly.
Test replay scope with an explicit state rule
For the fictional receipt, define the verifier's rule before checking the timeline. It accepts only the expected domain, a valid signature from reader, report 84, the receipt-only purpose, the reader's current nonce and a verification time no later than the deadline. Acceptance records one receipt and advances the nonce atomically. A rejected attempt changes neither value.
These are teaching assumptions, not properties inherited from the EIP-712 label. The exercise models the signature-validity result; it does not implement cryptography.
Start at 12:00 UTC with next nonce 7 and zero receipts. The request above has a five-minute window: 1793189100 − 1793188800 = 300 seconds.
| UTC time | Fictional event | Next nonce afterward | Receipts afterward | Result |
|---|---|---|---|---|
| 12:00 | Reader signs the request; nobody submits it | 7 | 0 | No application state change |
| 12:03 | Valid request with nonce 7 reaches the expected verifier | 8 | 1 | Accepted |
| 12:04 | The same signed request is submitted again | 8 | 1 | Rejected: nonce 7 is stale |
| 12:06 | A separate unused request has nonce 8 but the same deadline | 8 | 1 | Rejected: deadline passed |
The sequence contains three submissions, one acceptance and two rejections. The accepted request arrives 180 seconds after the start, leaving 120 seconds before its deadline. The last request is 60 seconds late. Signing and accepting are separate events.
Check boundary cases independently from that sequence. With a fresh initial snapshot, verification exactly at 12:05:00 passes the exercise's inclusive deadline rule; 12:05:01 fails. A different chainId or verifyingContract value must fail the expected-domain comparison. These independent tests do not add receipts to the main timeline.
These checks compare field values and stored state. In a separate hypothetical copy of the practice verifier with identical domain values and its nonce reset to 7, the same unexpired signature could be accepted again. Domain fields cannot distinguish two environments that reuse those fields. Nonce state must also remain intact for the one-use rule to hold.
A nonce written into a message is insufficient unless the verifier checks and consumes the corresponding state. Likewise, a deadline needs a defined unit, clock and comparison. EIP-712 explicitly leaves repeated-message handling to applications, which may reject repetition or make the repeated action idempotent. See its replay considerations.
Check the effect, not just the readable fields
The fictional receipt ends at acknowledgement. Real typed data can have very different effects. ERC-2612, for example, uses a structured signature to authorize a token allowance update. Its signed fields include an owner, spender, value, nonce and deadline, and any caller can submit a valid permit. Those details belong to that specific permit standard, not every EIP-712 message.
In that design, the domain's verifier is the token contract, while spender identifies the address receiving allowance. Checking the verifier alone therefore misses another address that determines the permission.
If the request concerns spending, use the permit versus approval guide to follow that authorization into contract state. Also inspect the existing token allowance worksheet for the token, spender and remaining permission. A readable amount needs the correct asset units before it becomes an understandable limit.
Watch for these practical failures:
- Familiar name, unexpected verifier. A copied protocol name can make a substituted address easy to overlook. Use the deployment record to resolve the full address.
- Short submission window, lasting permission. A deadline may govern when a signature can be accepted. Do not infer that every resulting permission expires at the same moment; check the specific contract's resulting state.
- One visible action, nested instructions. An array or opaque bytes field can leave the important effects unexplained. A short wallet summary is incomplete evidence when those contents remain undecoded.
- Unexpected signing request. Connecting an account, authenticating to a site and granting spending authority need different explanations. The wallet connection versus approval guide separates those permission layers.
Use a before-signing worksheet
Complete this worksheet from the request and independent application evidence. “The wallet displayed no warning” does not fill an empty evidence cell.
| Check | Evidence to retain | Stop condition |
|---|---|---|
| Intended task | Plain sentence describing the requested action | Page explanation and fields disagree |
| Signer | Expected account and any account-specific restrictions | Wrong account or unexplained signer role |
| Domain | Name, version, chain and full verifier; source used to check them | Unexplained deployment or domain mismatch |
| Message | Main type, nested fields, recipients, amounts and units where relevant | Important contents cannot be interpreted |
| Reuse | Nonce scope, acceptance rule and current state where available | Repeated use or invalidation behavior is unknown |
| Time and effect | Deadline interpretation, resulting authority and cancellation route | Expiry is being assumed to cancel a continuing permission |
Retain a minimal review record and the decision, rather than pasting a usable signature into a support chat or ordinary logs. A signature is not the private key, but an unconsumed authorization may still be usable. The log redaction guide explains preserving evidence while excluding authentication material.
If a request remains unclear, reject it and return to the intended task through a verified application route. If it has already been signed, determine whether it was accepted, remains usable, expired or can be invalidated under that protocol. Those are separate states. The practical completion record is a permission sentence whose domain, effect and reuse conditions you can explain from evidence.
