I was able to figure this out after much debugging. Turns out that the chainid OPCODE is not working correctly in Ganche (if you use their UI - the fix has been released in the ganache-cli
project).
The lack of a proper functioning chainid results in the DOMAIN_TYPEHASH
being computed incorrectly which prevents ecrecover
from generating the correct address from a signature.
You can follow these issues
Chain ID opcode: hardcoded at 1? #1643
istanbul chainId opcode returns bad value #515
Hope this helps others
To resolve the error, remove the EIP712Domain
from types
object (keep only PermitSingle
and PermitDetails
there). The domain type is inbuilt in the EIP712 standard and hence TypedDataEncoder so you do not need to specify it in the types. Hence the declared type EIP712Domain
was unused and it was causing the error.
Here is a working piece of code:
let result = _TypedDataEncoder.hash(
{
name: "Permit2",
chainId: "1",
verifyingContract: "0x14a5698aeab8aa3f472c6d0a0061730f45467bd9",
},
{
PermitSingle: [
{ name: "details", type: "PermitDetails" },
{ name: "spender", type: "address" },
{ name: "sigDeadline", type: "uint256" },
],
PermitDetails: [
{ name: "token", type: "address" },
{ name: "amount", type: "uint160" },
{ name: "expiration", type: "uint48" },
{ name: "nonce", type: "uint48" },
],
},
{
details: {
token: "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
amount: "1461501637330902918203684832716283019655932542975",
expiration: "1690127209",
nonce: "0",
},
spender: "0x49c4f688ade58ad80de1ddd932db3b804fef5cef",
sigDeadline: "1687537009",
}
);
console.log(result);
// 0x3c636bc8d0efd7d4a25e31a001ea1a4743cd000a1148facaf1f60c4c5b327d40
Best Answer
The difference is that EIP-712 was started in 2017 and since then it has evolved. For example Metamask's signing API has several iterations to make it more usable and secure.