Why does _domainSeparatorV4() in EIP712 (_hashTypedDataV4 in ERC20permit) check for address and chainID?

ERC20Permit uses _hashTypedDataV4()

which then uses _domainSeparatorV4() in EIP712

But why does _domainSeparatorV4() check for address and chainID here?

We check these things to see if the cache is valid. The chainid can change if the chain forks (like Ethereum Classic), you don't want the signatures for one chain to be valid for the other.

address(this) can be different during delegatecalls. You can see the issue where we introduced that to read more about the reasoning:

1 Like

Thank you! For tokens that are not a delegated contract, checking address(this) would not be necessary?

That's right, it is not necessary in that case.

However, since EIP-155, isn't chainID info included in most transaction signatures? Is this check for chainID mainly for the very few transactions signed by some old libraries?

The chain id check makes sure that a different domain separator is used if the chain forks, to prevent replay attacks: an EIP712 signature should only valid for one chain and not for both.

Yes, but after EIP155, when the updated libraries sign "A Message", even if "A Message" does not contain the current chainID, the signer would include in the signature the chainID info? (the v value) Thus the chainID info would be there to prevent replays with or without EIP712 if the signature is the new version?

EIP155 only affects the format of transactions. Simple signatures don't include the chain id.

From here: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md

It seems chain ID is covered for things signed in this standard?

If block.number >= FORK_BLKNUM and CHAIN_ID is available, then when computing the hash of a transaction for the purposes of signing, instead of hashing only six rlp encoded elements (nonce, gasprice, startgas, to, value, data) , you SHOULD hash nine rlp encoded elements (nonce, gasprice, startgas, to, value, data, chainid, 0, 0) .`

That only covers signing of transactions, as far as I can tell.

You mean the native currency transactions only? But isn't every state modification on chain a transaction? Thus when submitting the 'Permit' signature for example, even if 'Permit' itself doesn't include chainID, the signature of the transaction would include it? Got different answers from different sources, but didn't find the related part in Ethereum github tho. Probably will check it later. BTW, thank you for the answers!

Yes, the signature of the transaction would include the chainId. But anyone could extract the permit alone from a transaction and re-send it to a different network (bundled in a separate transaction). You want to make sure that the permit is not accepted in a different network.

1 Like