ERC20Permit: invalid signature

Hello, Team how are you doing?
I'm creating the signature for ERC20Permit offline and when i pass the following parameters to the permit function it throws error 'invalid signature'. Can you please look over the code what i'm doing wrong?
It is the code which i write in testcase which simply deploys the contract Erc20 create the signature offchain pass it to ERC20Permit's permit function via Erc20 Contract (MyToken)

Erc20 like

contract MyToken is ERC20, ERC20Burnable, Pausable, Ownable, ERC20Permit {


it.only('should create the signature for verification', async function (){
  const { MyToken, owner } = await loadFixture(deployContractsAndReturnInstances);
      const signer = owner;
      const domainData = {
        name: "MYTOKEN",
        version: "1.0.0",
        chainId: 31337,
        verifyingContract: MyToken.address,
      const deadline = ethers.constants.MaxUint256;
      const nonce = 0;
      const val=1;
      const types = {
        Permit: [
      const value =  {
        nonce: nonce,
      const result = await signer._signTypedData(domainData, types, value);
      let sig = ethers.utils.splitSignature(result);
      const {v, r, s} =  sig;
      const data = await  MyToken.permit(owner.address,MyToken.address,val,deadline,v,r,s);

At first glance the code seems correct, you should retrieve the name, nonce, version etc from the contract just to make sure your getting the correct values and not hard code them.

Your using version 1.0.0 as version, is that the same from the contract, by default it’s normally 1 not a string like you have it.
What is your permit implementation as you code isn’t there

Hi Thanks for your reply
I also use the
MyToken.nonces(owner.address) and version 1 in contract and by doing this gives me same error

invalid Signature

The permit implementation is the default one that Erc20Permit has like

 function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) public virtual override {
        require(block.timestamp <= deadline, "ERC20Permit: expired deadline");

        bytes32 structHash = keccak256(abi.encode(_PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline));

        bytes32 hash = _hashTypedDataV4(structHash);

        address signer = ECDSA.recover(hash, v, r, s);
        require(signer == owner, "ERC20Permit: invalid signature");

        _approve(owner, spender, value);

I really don't see a problem with it, i might just be overlooking something. Its pretty similair to what we're using (although we're using an other contract, not the token itself for the permit, so had to modify some code)

describe("ERC20Permit", function () {
  it("ERC20 permit", async function () {
    const accounts = await ethers.getSigners(1)
    const signer = accounts[0]

    const Token = await ethers.getContractFactory("MyToken")
    const token = await Token.deploy()
    await token.deployed()

    const deadline = ethers.constants.MaxUint256
    const spender = token.address
    const value = 1

	const [nonce, name, version, chainId] = await Promise.all([

	const { v, r, s } = ethers.utils.splitSignature(
		await signer._signTypedData(
			verifyingContract: token.address,
			Permit: [
				name: "owner",
				type: "address",
				name: "spender",
				type: "address",
				name: "value",
				type: "uint256",
				name: "nonce",
				type: "uint256",
				name: "deadline",
				type: "uint256",
			owner: signer.address,

    const data = await token.permit(value, deadline, v, r, s)

Thanks dear i change the static values as you say and it works the problem was due to chain iD
Thanks dear you save my time
const chainId =;