# How EIP-712 domain separators prevent cross-contract signature replay

## Answer

**Fact.** EIP-712 signs the digest

```text
keccak256("\x19\x01" || domainSeparator || hashStruct(message))
```

and defines `domainSeparator` as the hash of an `EIP712Domain`. That domain may contain `name`, `version`, `chainId`, `verifyingContract`, and `salt`; `verifyingContract` is specifically the address of the contract that will verify the signature. Thus the domain is cryptographically included in what the signer signs, rather than being unsigned metadata. [EIP-712, specification](https://eips.ethereum.org/EIPS/eip-712#specification-of-the-eth_signtypeddata-json-rpc) and [domain definition](https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator).

**Inference from the specification.** Suppose contract A and contract B use the same message type and values, but each constructs the expected separator with its own address as `verifyingContract`. Their separators—and therefore their signed digests—differ. A signature made over A's digest will not authenticate the signer for B's digest (absent a break or collision in the cryptographic primitives). This is the cross-contract replay defense. The EIP's rationale says the separator keeps otherwise identical structures used by different applications from colliding, and notes that a target-contract address separates contracts. [EIP-712, rationale](https://eips.ethereum.org/EIPS/eip-712#rationale).

For isolation across chains as well, the domain should also include the current `chainId`. ERC-5805 gives the common construction using `name`, `version`, `chainId`, and `address(this)`, and says a separator unique to the contract and chain prevents replay from other domains. [ERC-5805, `delegateBySig`](https://eips.ethereum.org/EIPS/eip-5805#delegatebysig).

## Limits and uncertainty

**Fact.** The protection is not automatic merely because a signature is called “EIP-712.” A verifier must compute the expected domain consistently and actually include that separator in the digest it verifies. EIP-712 permits applications to omit domain fields, so omitting `verifyingContract`, or configuring two verifiers with the same domain, removes the claimed contract-specific binding. [EIP-712, domain definition](https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator).

**Fact.** Domain separation does not prevent replay *within* the same domain. EIP-712 explicitly leaves repeated-message handling to the application; a nonce, consumed-authorization record, deadline, or idempotent action is still needed as appropriate. ERC-5805, for example, separately requires incrementing a signer nonce. [EIP-712, security considerations](https://eips.ethereum.org/EIPS/eip-712#replay-attacks) and [ERC-5805, nonce requirement](https://eips.ethereum.org/EIPS/eip-5805#delegatebysig).

**Uncertainty / unanswered implementation question.** Whether a particular deployed system is protected cannot be determined from EIP-712 compliance alone. Its verifier code, chosen domain fields and values, proxy/delegate-call architecture, chain-ID handling, and nonce or authorization-consumption logic must be inspected.
