Сообщение об ошибке
Provided chainId "1" must match the active chainId "137"
Также выводится как
- Cannot sign messages for chainId "1", because MetaMask is switching networks.
dApps получают это сообщение как ошибку JSON-RPC от `eth_signTypedData_v4` (MetaMask возвращает код -32603 с этим текстом). Числа — chain ID вашего домена и кошелька. Пока MetaMask переключает сеть, запрос завершается ошибкой «Cannot sign messages for chainId …, because MetaMask is switching networks.».
MetaMask (eth_signTypedData_v3/v4) — validation in @metamask/signature-controller
Что это означает
`domain.chainId` по EIP-712 в типизированных данных отличается от сети, к которой сейчас подключён кошелёк, и MetaMask отказывается показывать запрос подписи. Это правило защищает пользователей: chain ID входит в подписываемые данные, и подпись для другой сети можно было бы повторно использовать в той сети. Первое число — `domain.chainId` из dApp, второе — активная сеть кошелька, оба в десятичной записи.
Почему это происходит
chainId жёстко прописан в коде dApp
частоДомен собран с `chainId: 1` (или с ID тестовой сети), а пользователи подключаются к Polygon, Base, Arbitrum… Запрос подписи не проходит у каждого пользователя, который не в этой сети.
Пользователь сменил сеть после того, как dApp её определило
частоdApp закешировало chain ID при подключении и не отслеживало `chainChanged`. Следующий запрос подписи уходит с устаревшим значением.
chainId в виде строки разбирается иначе
иногдаMetaMask разбирает chain ID, заданные строкой, как шестнадцатеричные, только если есть префикс `0x`. `"89"` — это десятичное 89, а не 0x89 (137) сети Polygon.
Как исправить
- 1.
Формируйте домен по текущей сети кошелька
Считывайте chain 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 });