eth_signTypedData_v4
Sign structured data according to EIP-712 v4 rules. Compared with raw hashes or ordinary text signatures, it allows users to see more semantic fields and is more suitable for on-chain verification of data such as authorizations, orders, or permits.
Inputs
| Index | Type | Description |
|---|---|---|
| 0 | string | The account address that initiated the signature |
| 1 | string | Typed data JSON string |
return value
string - 65-byte signature, hexadecimal string format.
typed data structure
interface TypedData {
types: {
EIP712Domain: Array<{ name: string; type: string }>;
[typeName: string]: Array<{ name: string; type: string }>;
};
primaryType: string;
domain: {
name?: string;
version?: string;
chainId?: number;
verifyingContract?: string;
salt?: string;
};
message: Record<string, any>;
}
Demo
const typedData = {
types: {
EIP712Domain: [
{ name: "name", type: "string" },
{ name: "version", type: "string" },
{ name: "chainId", type: "uint256" },
{ name: "verifyingContract", type: "address" },
],
Person: [
{ name: "name", type: "string" },
{ name: "wallet", type: "address" },
],
Mail: [
{ name: "from", type: "Person" },
{ name: "to", type: "Person" },
{ name: "contents", type: "string" },
],
},
primaryType: "Mail",
domain: {
name: "UKey Wallet Sample",
version: "1",
chainId: 1,
verifyingContract: "0x2b4d6f8091a3c5e7f9b1d3f507192b4d6f8091a3",
},
message: {
from: {
name: "Ava",
wallet: "0x4b6d8f0123456789abcdef0123456789abcdef01",
},
to: {
name: "Liam",
wallet: "0xc4d2e1f0a9876543210fedcba9876543210abcde",
},
contents: "Payment approval sample",
},
};
const signature = await window.$ukey.ethereum.request({
method: "eth_signTypedData_v4",
requestParams: [accounts[0], JSON.stringify(typedData)],
});
console.log("Generated signature:", signature);
Permit signature (ERC-2612)
const permitData = {
types: {
EIP712Domain: [
{ name: "name", type: "string" },
{ name: "version", type: "string" },
{ name: "chainId", type: "uint256" },
{ name: "verifyingContract", type: "address" },
],
Permit: [
{ name: "owner", type: "address" },
{ name: "spender", type: "address" },
{ name: "value", type: "uint256" },
{ name: "nonce", type: "uint256" },
{ name: "deadline", type: "uint256" },
],
},
primaryType: "Permit",
domain: {
name: "USDC.e",
version: "2",
chainId: 1,
verifyingContract: "0x2b4d6f8091a3c5e7f9b1d3f507192b4d6f8091a3",
},
message: {
owner: accounts[0],
spender: "0x4b6d8f0123456789abcdef0123456789abcdef01",
value: "3500000000", // sample token amount
nonce: 0,
deadline: Math.floor(Date.now() / 1000) + 3600,
},
};
const signature = await window.$ukey.ethereum.request({
method: "eth_signTypedData_v4",
requestParams: [accounts[0], JSON.stringify(permitData)],
});
error code
| Code | Message | Details |
|---|---|---|
| 4001 | User rejected the request | Signature approval was rejected by the user |
| -32602 | Parameters failed validation | Typed data structure is invalid |
illustrate
- Typed data must be parsable as valid JSON.
domain.chainIdshould be consistent with the currenteth_chainId.domain.verifyingContractshould point to the contract actually responsible for verification.- Users will see structured fields in the wallet, please use clear field names and understandable business content.
- Follows EIP-712 specification.