Replies: 9 comments 9 replies
-
I'm also having this issue, I'm trying to emulate this permit verification using ethers.js but the resulting sig, and address recovered from it, are unpredictable Here is my code: const domain = {
name: "{token_name}",
version: '1',
chainId: 31337,
verifyingContract: 0x1429859428C0aBc9C2C47C8Ee9FBaf82cFA0F20f
}
const types = {
Permit : [
{name: "permitHash", type: "bytes32"},
{name: "owner", type: "address"},
{name: "spender", type: "address"},
{name: "value", type: "uint256"},
{name: "nonce", type: "uint256"},
{name: "deadline", type: "uint256"},
]
}
const value = {
permitHash: 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9,
owner: 0x17ec8597ff92C3F44523bDc65BF0f1bE632917ff,
spender: 0x63FC2aD3d021a4D7e64323529a55a9442C444dA0,
value: 2000000000000000000,
nonce: 0,
deadline: 1648077296,
}
const signature = signer._signTypedData(domain, types, value) The types for my values are verified and the only variables is the deadline, yet I'm still getting unpredictable results. |
Beta Was this translation helpful? Give feedback.
-
@liho00
You can see full source code here: https://gist.github.com/quan118/33b81f6aa612272669ba07c8fe63f296 |
Beta Was this translation helpful? Give feedback.
-
Hey, great convo! I was wondering, has anybody tested replicating this with the ecrecover functions from the implemented eip2612 contracts? I keep getting the wrong address. The fix from playing around with the raw message is to hash the message sent into ecrecover one more time (using ethers.hashmessage), but the implemented token contracts (I'm particularly looking at USDC POS on polygon sidechain) don't seem to do that with the parameters fed into the permit call such as owner, spender etc. |
Beta Was this translation helpful? Give feedback.
-
@liho00 try to add to your types properties along with for ethers produced signature you should exclude the type. then it should produce same signatures in both cases. |
Beta Was this translation helpful? Give feedback.
-
were you able to fix this? |
Beta Was this translation helpful? Give feedback.
-
I have the same issue. would be great if you could share your solution, @liho00 . thank you! |
Beta Was this translation helpful? Give feedback.
-
Same problem here |
Beta Was this translation helpful? Give feedback.
-
@acemasterjb ethers adds proper method hash based on types, so proper invocation in case of permit looks like this (note there's no permitHash thingy) const domain = {
name: token.name,
version: '1',
chainId: 31337,
verifyingContract: token.address
};
const types = {
Permit : [
{name: "owner", type: "address"},
{name: "spender", type: "address"},
{name: "value", type: "uint256"},
{name: "nonce", type: "uint256"},
{name: "deadline", type: "uint256"},
]
};
const value = {
owner: owner.address,
spender: spender.address,
value: 2000000000000000000n,
nonce: 0,
deadline: 1648077296n,
};
const rawSig = await signer._signTypedData(domain, types, value);
const signature = ethers.utils.splitSignature(rawSig); |
Beta Was this translation helpful? Give feedback.
-
it's important to note that MetaMask's const domain = {
// Name is removed in this example
version: "1", // Contract deploy version
chainId: 1, // Environment chain ID
verifyingContract: "",
};
const types = {
Test: [
{ name: "Request", type: "string" },
],
}; Correspondingly, in MetaMask, it should be: const domain = {
version: "1", // Contract deploy version
chainId: 1, // Environment chain ID
verifyingContract: "",
};
const types = {
Test: [
{ name: "Request", type: "string" },
],
EIP712Domain: [
// Include 'name' here if it's in the domain
{name: "version", type: "string"},
{name: "chainId", type: "uint256"},
{name: "verifyingContract", type: "address"},
]
}; |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Metamask sig utils SignTypedDataVersion.V4, (tested with SignTypedDataVersion.V3 same)
Metamask sig utils generated signature 0x93f39c57d7f8de7b033367cb5fa7bb68c6a339b0626c73febc57fdce5a779a8472b365951470ade9857e8bd26a3020e9088c110c931abd188034cbdd1e79f8191c
ether js signTypedData
Ether js _signTypedData 0x9655d8635d4826a1c44185acb34f7c86b286e90e70bd260626c8dd112ae8f5f348f75ce387544c1734971f6ae51ad855e98a49c7e56c3a636a90f714378aca0d1c
My question is why both produce different result of signatures? I was confusing on why these both producing different signature, does it possible both lib produce same signature?
Another comparison between metamask sig utils signtypeddata & ether signtypeddata, function is sig utils signtypedata is a synchronize function while ether signtypedata is asynchronous
Example
I think there is a scenario that we would like to generate the signature from backend and pass it to frontend, hence i think synchronous is the case.
For example we doing a nft raffle that we use owner private key to sign winner address and let winner to mint the token at frontend.
Beta Was this translation helpful? Give feedback.
All reactions