EIP-712
一、EIP-712 是什么?
📘 定义
EIP-712 全名:Ethereum Typed Structured Data Hashing and Signing
它是一种结构化数据签名标准。
🧠 用一句话解释
EIP-712 = 让钱包可以安全地签名「结构化数据」,而不是只签名一段看不懂的字符串。
二、为什么需要 EIP-712?
在 EIP-712 之前,签名是这样的:
sign("I agree to send 1 ETH to 0xabc...")
问题:
- 用户看不懂
- 容易被钓鱼
- 钱包无法解析字段
- 不知道自己签的是什么结构
EIP-712 解决方案: 签名结构化 JSON 数据,例如:
{
"domain": {
"name": "MyDApp",
"version": "1",
"chainId": 1
},
"message": {
"from": "0x123...",
"amount": "1000000000000000000"
}
}
钱包会显示:
- Send 1 ETH
- From: 0x123…
- To: MyDApp
| ✅ 用户可读 | ✅ 更安全 | ✅ 防止跨链重放攻击 |
三、EIP-712 有什么用?
它是很多核心 Web3 功能的基础。
1️⃣ ERC-20 Permit(ERC-2612)
作用:
- 不用发链上 approve 交易
- 直接签名授权
- 节省 gas
核心就是 EIP-712 签名。
2️⃣ NFT Permit
很多 NFT 市场使用 EIP-712:
- 你签名挂单
- 别人帮你执行
3️⃣ Gasless 交易 / Meta-transaction
用户:
- 只签名
- 不付 gas
Relayer 帮你发交易。底层 = EIP-712。
4️⃣ Account Abstraction (AA)
如 ERC-4337,AA 钱包的 UserOperation 就是 EIP-712 结构签名。你如果要做智能钱包,这个必须懂。
四、EIP-712 的核心结构
它有 3 个核心部分:
① Domain Separator
防止跨链重放:
{
name: "MyDApp",
version: "1",
chainId: 11155111,
verifyingContract: "0x..."
}
作用: 绑定链、绑定合约、绑定应用
② Types
定义数据结构:
types: {
Mail: [
{ name: "from", type: "address" },
{ name: "amount", type: "uint256" },
];
}
③ Message
真正签名的内容:
message: {
from: "0x123...",
amount: "1000"
}
五、怎么用?
以 MetaMask 为例。
前端调用
使用 eth_signTypedData_v4:
await window.ethereum.request({
method: "eth_signTypedData_v4",
params: [address, JSON.stringify(data)],
});
wagmi + viem
建议使用:
useSignTypedData- viem 的
signTypedData
const { signTypedData } = useSignTypedData();
signTypedData({
domain,
types,
primaryType: "Mail",
message,
});
Solidity 验证签名
用 OpenZeppelin:
import "@openzeppelin/contracts/utils/cryptography/EIP712.sol";
// 合约里
bytes32 digest = _hashTypedDataV4(structHash);
address signer = ECDSA.recover(digest, signature);
六、底层原理(核心)
签名的不是 JSON。真实签名的是:
keccak256(
"\x19\x01" ||
domainSeparator ||
structHash
)
这保证:
- 签名不可伪造
- 不可跨链
- 不可跨合约