EIPs
EIP-712 — Typed structured data hashing and signing
EIP-712 lets a dapp ask the user to sign structured data — domain-bound, schema-defined, human-readable in the wallet popup. Where personal_sign (EIP-191) signs an opaque byte string, EIP-712 signs a typed object whose hash is computed from declared field types.
import { hash_typed_data, type TypedData } from "@ethernauta/eip/712";
const typed: TypedData = {
types: {
Permit: [
{ name: "owner", type: "address" },
{ name: "spender", type: "address" },
{ name: "value", type: "uint256" },
{ name: "nonce", type: "uint256" },
{ name: "deadline", type: "uint256" },
],
},
primary_type: "Permit",
domain: {
name: "USD Coin",
version: "2",
chain_id: 1,
verifying_contract: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
},
message: { owner, spender, value, nonce, deadline },
};
const digest = hash_typed_data(typed); Surface
| Export | Type | Purpose |
|---|---|---|
typedDataSchema | Valibot schema | Validate a typed-data payload. |
TypedData, TypedDataDomain, TypedDataField | types | Inferred shapes. |
hash_typed_data | (td: TypedData) => Hash32 | EIP-712 digest. |
sign_typed_data | Signable<Bytes65> | Method binding for eth_signTypedData_v4. |
Signing via the wallet
import { sign_typed_data } from "@ethernauta/eip/712";
const signature = await sign_typed_data({ account, typed_data })(
signer({ chain_id: eip155_1.chain_id }),
); The signer wraps a 1193 provider; the wallet opens its sign-typed-data view, displays the field-by-field breakdown, and returns the 65-byte signature.
Verification
import { verify_typed_data } from "@ethernauta/crypto";
const ok = await verify_typed_data({
address,
typed_data,
signature,
})(reader({ chain_id: eip155_1.chain_id })); Same EOA → 1271 fallback as verify_message. Add _universal for counterfactual.
Common consumers
- ERC-2612 permit — gasless ERC-20 approvals.
- EIP-4361 SIWE — sign-in with Ethereum.
- ERC-7683 — cross-chain order signing.
- EIP-7702 authorizations — set-code delegations.
Each of those packages composes the hash_typed_data primitive rather than reimplementing the digest.