viem (TypeScript)Web3 钱包与签名
错误信息
Invalid primary type `Email` must be one of `["EIP712Domain","Mail"]`.
反引号中的名称分别是你的 `primaryType` 和可用的类型。viem 2.57 抛出该错误时,`err.name` 为“BaseError”;`err.shortMessage` 就是上面的文本,`err.message` 还会附上提示、文档链接(“typeddatainvalidprimarytypeerror”)和 viem 版本。
viem (TypeScript) — hashTypedData / signTypedData / verifyTypedData / recoverTypedDataAddress
含义
你传入的 `primaryType` 不是 `types` 中的键(viem 显示的列表里会额外加上 `EIP712Domain`)。EIP-712 把消息当作主类型的一个实例来计算哈希,所以 viem 不会去猜。类型化数据本身可能没有问题,只是其中不存在要签名的那个结构体名称。
原因
某一端重命名了结构体
常见合约或后端把 `Mail` 改名为 `Email`(或把 `Order` 改名为 `OrderV2`),而前端仍在发送旧名称——或者反过来。由于类型名是类型哈希的一部分,两端本来就必须同时修改。
缺少 primaryType 或其值为 undefined
偶见动态构建的载荷(例如从 JSON 构建)如果从未设置 `primaryType`,就会产生 `Invalid primary type \`undefined\``。
大小写不同
偶见`mail` 与 `Mail`:EIP-712 中的类型名区分大小写。
修复方法
- 1.
用 as const 声明类型
使用 `as const` 后,viem 的类型定义会把 `primaryType` 限定为由你的结构体名称组成的联合类型,因此名称不匹配会在编译时报错,而不是到签名时才失败。
ts const types = { Mail: [ { name: "to", type: "address" }, { name: "contents", type: "string" }, ], } as const; // "as const" lets TypeScript reject a wrong primaryType at compile time const signature = await walletClient.signTypedData({ account, domain, types, primaryType: "Mail", message });