fix: typed data for another chain cannot be signed (closes #519)
check / check (push) Waiting to run
e2e / e2e-chrome (push) Waiting to run
e2e / e2e-firefox (push) Waiting to run

EIP-712 has a wallet refuse typed data whose domain chainId is not the
active chain, because the signature is valid on the chain it names. The
sign screen now shows such a request with the reason on its error line
and Sign disabled, the same way it refuses a mismatched primary type.
The background checks again when the signature comes back, against the
network active then, and answers the site with that refusal instead of
the signature. A chain id is read as ethers signs it, so 1, "1" and
"0x1" are one chain. Typed data with no chainId signs as before.

Model: opus-5-5
This commit is contained in:
2026-10-14 03:25:50 +00:00
parent adff1e0b9d
commit f9379d9fb9
6 changed files with 181 additions and 6 deletions
+8 -4
View File
@@ -12,7 +12,7 @@ const {
formatFee,
tokenLabel,
} = require("./helpers");
const { state, saveState } = require("../../shared/state");
const { state, saveState, currentNetwork } = require("../../shared/state");
const {
networkById,
networkByChainId,
@@ -46,7 +46,10 @@ const {
const { decryptWithPassword } = require("../../shared/vault");
const { getSignerForAddress } = require("../../shared/wallet");
const { walletDefect } = require("../../shared/walletDefects");
const { describeSigningFailure } = require("../../shared/approvalVerify");
const {
describeSigningFailure,
typedDataChainRefusal,
} = require("../../shared/approvalVerify");
const txStatus = require("./txStatus");
const uniswap = require("../../shared/uniswap");
const { notify, runtimeApi, sendMessage } = require("../../shared/browserApi");
@@ -443,7 +446,8 @@ function signedPrimaryType(types) {
// Why a signature request cannot be signed, as a sentence for the error line,
// or null when it can. Only typed data is refused: the `primaryType` the page
// states has to be the type ethers will sign, or this screen would name one
// message while another is signed.
// message while another is signed. Its domain may name no chain but the active
// network's.
function typedDataRefusal(sp) {
if (sp.method === "personal_sign" || sp.method === "eth_sign") return null;
let data;
@@ -466,7 +470,7 @@ function typedDataRefusal(sp) {
", so it cannot be signed."
);
}
return null;
return typedDataChainRefusal(data.domain, currentNetwork());
}
// The largest amount a Permit2 allowance can hold, a uint160. Permit2 treats