If you have used a self custody wallet for a while, you have probably noticed two very different kinds of signature popup. One shows a long unreadable string of numbers and letters. The other shows something closer to a form: a token name, an address labeled as the spender, an amount, sometimes a deadline. Both are message signatures. Both cost no gas. The difference between them is a standard called EIP-712, and understanding it makes every permit, intent, or login request you see afterward much easier to read.
This guide builds on our signature requests guide, which covers the broader difference between connecting, signing, and confirming a transaction. Here we go one level deeper into what makes a modern signature request readable in the first place.
The problem EIP-712 was built to solve
Early wallet signing had one basic tool: sign this piece of data. The data could be a plain sentence, which a wallet could display as is, or it could be arbitrary bytes that an application needed for its own internal logic, which a wallet had no way to interpret. In that second case, the wallet either showed a raw hex string or, worse, showed nothing meaningful at all. You were asked to trust that the application had told you the truth about what the bytes meant, with no way to check.
That was a real problem as applications started asking for signatures that carried actual authority, such as a token approval or a trade order, rather than just a login proof. Signing blind is fine for a harmless message. It is not fine for something that can move your funds.
EIP-712, formally titled "Ethereum typed structured data hashing and signing," gives applications a standard way to describe data as a set of named, typed fields instead of an opaque blob. A wallet that supports the standard can then render those fields directly: this field is a token address, this one is an amount, this one is a deadline. The bytes being signed under the hood are the same either way. What changes is whether your wallet can turn them into something you can actually read.
The domain: tying a signature to one app and one chain
A structured message under EIP-712 is split into two parts. There is the message itself, the fields specific to the action, and there is something called the domain, which describes the context the signature is valid in. The domain typically includes a name for the application, a version, the chain ID of the network the signature is meant for, and the address of the specific contract that is supposed to receive it.
This detail matters more than it looks. Without it, a signature you granted to one application, on one network, could potentially be replayed by a different contract, or on a different chain entirely, if the underlying message happened to look the same. Binding the signature to a chain ID and a verifying contract closes that gap. A permit you sign for a specific token contract on Base is not valid for a similarly shaped request on another network, because the domain would not match. This is one of the quieter reasons EIP-712 became the default for anything with real authority behind it, from the permits covered in our permit signatures guide to the trade orders covered in our intent based swaps guide.
Readable does not mean safe
This is the part worth sitting with. EIP-712 improves what your wallet can show you. It does not improve what an application is honest about asking for. A phishing site can build a perfectly valid, perfectly structured EIP-712 request that authorizes an attacker's contract to move your tokens, and your wallet will display it exactly as clearly as it would display a legitimate one. The fields will be readable. The spender will just be wrong, or the amount will just be far larger than it needs to be, and nothing about the standard itself flags that for you.
In other words, EIP-712 solved the readability problem, not the trust problem. Knowing what a request says is necessary but not sufficient. You still have to look at what it says and decide whether it makes sense for the action you are actually taking.
What to actually check when a structured request appears
Since your wallet is now showing you real fields instead of hex, use them. A few things are worth a second look every time:
- The domain name and contract. Does it match the application you meant to interact with, or something unfamiliar?
- The spender or recipient field. Is it an address you recognize as belonging to the app, or an unfamiliar contract?
- The amount. Is it roughly what the action requires, or unlimited, or far larger than makes sense?
- The deadline, if one is present. A very distant deadline gives a signature a long shelf life if it is ever misused later.
None of this requires understanding cryptography. It requires reading the fields your wallet is already putting in front of you, the same way you would read the fields on a form before submitting it.
Where you will run into this on Base
You do not need to seek EIP-712 out. It shows up whenever an application wants a gasless, off chain authorization rather than an on chain transaction: token permits, the trade intents used by some swap routes, off chain orders on NFT marketplaces, and increasingly the session and permission systems used by smart wallets. Our guide on smart wallets and passkeys touches on some of these newer patterns. In every case, the underlying mechanics are the same structured signing standard, just applied to a different kind of authority.
The practical takeaway is simple. A readable popup is a genuine improvement over a hex blob, and it is worth appreciating that your wallet can now tell you what you are agreeing to in plain fields. Just remember that the standard makes a request legible, not automatically legitimate. Read the fields, confirm they match what you expected, and reject anything that does not, exactly as you would with any other signature or transaction.