错误信息
Provided chainId "1" must match the active chainId "137"
也可能输出为
- Cannot sign messages for chainId "1", because MetaMask is switching networks.
dApps 收到的是 `eth_signTypedData_v4` 返回的 JSON-RPC 错误(MetaMask 返回代码 -32603 和这段文本)。其中的数字分别是你的域和钱包的链 ID。在 MetaMask 切换网络期间,请求会报错:“Cannot sign messages for chainId …, because MetaMask is switching networks.”。
MetaMask (eth_signTypedData_v3/v4) — validation in @metamask/signature-controller
含义
类型化数据中 EIP-712 的 `domain.chainId` 与钱包当前连接的网络不同,因此 MetaMask 拒绝显示签名请求。这条规则是为了保护用户:链 ID 是被签名内容的一部分,针对另一条链的签名可能会在那条链上被重放。第一个数字是 dApp 的 `domain.chainId`,第二个是钱包当前的活动链,都是十进制。
原因
dApp 把 chainId 写死了
常见域是用 `chainId: 1`(或某个测试网 ID)构建的,而用户连接的是 Polygon、Base、Arbitrum 等链。不在那条链上的用户,签名请求都会失败。
dApp 读取链之后,用户切换了网络
常见dApp 在连接时缓存了链 ID,却没有监听 `chainChanged`。下一次签名请求携带的就是过时的值。
chainId 是字符串,被解析成了不同的值
偶见MetaMask 只有在字符串形式的链 ID 带有 `0x` 前缀时才按十六进制解析。`"89"` 是十进制的 89,而不是 Polygon 的 0x89(137)。
修复方法
- 1.
根据钱包的当前链构建域
在签名前一刻读取链 ID,并选用部署在那条链上的验证合约。
ts const chainId = await walletClient.getChainId(); // viem // const chainId = Number(await provider.send("eth_chainId", [])); // ethers / raw EIP-1193 const domain = { name: "Example DEX", version: "1", chainId, verifyingContract: dexAddressFor(chainId) }; - 2.
或者把钱包切换到所需的链
如果订单或 Permit 只在某一条链上有效,就先请求切换网络(`wallet_switchEthereumChain`),再签名。
ts // If the signature is only valid on one chain (the verifying contract lives there), ask the wallet to switch. await walletClient.switchChain({ id: 1 }); const signature = await walletClient.signTypedData({ account, domain, types, primaryType: "Order", message });