I am using "ethers": "^5.6.2" and this is running through a browser. I am also using "eth-permit": "^0.2.1". As to the documentation for eth-permit, I can send a Wallet object as the provider for signDaiPermit(provider, token|Domain, holderAddress, spenderAddress).

Looking in the code for eth-permit, if the Wallet has signTypedData or _signTypedData as a function (which should be provided by ethers according to their documentation) then it will use that function. When I look at the Wallet in the browser inspector I don't see either of those functions.

I am specifically looking to not connect to an ethereum network to sign this data with ethers. This is how I am setting up Wallet:

let domain = {
        "name": "Dai Stablecoin",
        "version": "1",
        "chainId": 1,
        "verifyingContract": daiAddress

let mainWallet = new ethers.Wallet("0xdf57089febbacf7ba0bc227dafbffa9fc08a93fdc68e1e42411a14efcf23656e", ethers.getDefaultProvider());

let result = await signDaiPermit(mainWallet, domain, myAddress, crowdSaleAddress);

The private key is one of the default keys for the hardhat test environment.

I would assume that this would set up the Wallet as a signer but, as I said before, no signTypedData as a function.

Can anyone tell me what I am doing wrong or what I need to create a Wallet that has signTypedData as a function?

As you can see I am attempting to create data for a "permit" in DAI. I running hardhat as a fork from mainnet and I am using the mainnet deploy of DAI. If I attempt to generate the signature from Metamask while testing it is using chainId 31337 and the DOMAIN_SEPARATOR for the mainnet deploy contract needs chainId to be 1. Metamask will refuse to sign this. I am trying to generate a signature with chainId=1 using ethers only but the transaction will be sent to the hardhat test network on its chainId.


1 Answer 1


I have resolved my issue and wanted to post that here.

First, the created wallet actually did have _signTypedData as a function. I thought that it did not because it seemed to run into a failure that came after the check to see if the function was available. Instead the function was called earlier in the process as well and was failing then. I did a better job of isolating the process inside eth_permit and found that the function actually did exist in the Wallet object.

As for how I was able to get what I needed accomplished, that is a different process.

I have Metamask connecting to my hardhat dev instance. Again, this dev instance is a fork of the mainnet. Its chainId is 31337. Metamask will not sign a typed message with the chainId 1. Instead it throws an error. The issue I was running into was that part of of message creation process queries the contract for the user's nonce. If I give the signDaiPermit function a provider that is capable of signing the message with chainId 1, then the call to retrieve the nonce fails. This is because the DAI contract was deployed to the blockchain when the chainId was 1, but now the fork is 31337.

There are two possible answers. The first is that you can do the call for the nonce outside the function with the Metamask provider and pass the nonce in as a parameter. This breaks down if the address you want to use has no permit calls in its history because 1) the nonce it needs is 0 and 2) the eth-permit library just uses if nonce as a conditional so it will default to using a call it cannot make even if you explicitly pass the value 0.

The second answer is to fork the eth-permit library to either fix the edge case described above or create a new function that takes in two providers. One provider will be used to query information to create an appropriate message (your Metamask provider) and the other provider will be used to sign the message.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.