1

Hi im singing an array whit "eth_signTypedData_v4" but when i try to ecrecover my signature i get the incorrect address

here is my js code for sing the msg

      method: 'net_version',
      params: [],
      jsonrpc: "2.0"
    }, function (err, result) {
      const netId = result.result;
      console.log("netId", netId);
      const msgParams = JSON.stringify({types:
        {
        EIP712Domain:[
          {name:"name",type:"string"},
          {name:"version",type:"string"},
          {name:"verifyingContract",type:"address"}
        ],
        set:[
          {name:"from",type:"address"},
          {name:"to",type:"address"},
          {name:"nft",type:"address[]"},
          {name:"tokenid",type:"uint[]"}
        ]
      },
      primaryType:"set",
      domain:{name:"NFT",version:"1",verifyingContract:exchangeadddress},
      message:{
        from: "0xb71Ff4Db03DB070e40c90F5e2d40b32AAeff556b",
        to: "0x79158a488A704f6626C1AddC8b1A18A75Da3BDd1",
        nft: ["0xe46e2362b71C3C820a2170CdD95e9e1F1193cbc6","0x3bc62484E9Fe4CaB46289fb2F133367cE28E0457"],
        tokenid: ["1","2"]
      }
      })

      var from = signer;
    
      console.log('CLICKED, SENDING PERSONAL SIGN REQ', 'from', from, msgParams)
      var params = [from, msgParams]
      console.dir(params)
      var method = 'eth_signTypedData_v4'
    
      web3.currentProvider.sendAsync({
        method,
        params,
        from,
      }, async function (err, result) {
        if (err) return console.dir(err)
        if (result.error) {
          alert(result.error.message)
        }
        if (result.error) return console.error('ERROR', result)
        console.log('TYPED SIGNED:' + JSON.stringify(result.result))
   
  
        const signature = result.result.substring(2);
        console.log(signature)
        const r = "0x" + signature.substring(0, 64);
        const s = "0x" + signature.substring(64, 128);
        const v = parseInt(signature.substring(128, 130), 16);
        console.log("r:", r);
        console.log("s:", s);
        console.log("v:", v);
        setrA(r)
        setsA(s)
        setvA(v)


      }) 
    })

here is my solidity code.


import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";


contract fin is ReentrancyGuard {



    function Swap(
        address [] memory nft,
        address userAddressFrom, 
        address userAddressTo, 
        uint [] memory tokenId,
        uint8 v,
        bytes32 r,
        bytes32 s
   
    ) 
        external  {


        bytes32 eip712DomainHash = geteip712DomainHash ();
        bytes32 hashStruct = gethashStruct(userAddressFrom, userAddressTo, nft, tokenId);
        require (verifySignature(userAddressFrom,  eip712DomainHash,  hashStruct, v, r, s) == true,"signature of user A is invalid");

   
    }


    function geteip712DomainHash () public view  returns (bytes32) {
        return
        keccak256(
        abi.encode(
            keccak256(
                "EIP712Domain(string name,string version,address verifyingContract)"
            ),
            keccak256(bytes("NFT")),
            keccak256(bytes("1")),
            address(this)
        )
        );
    }

    function gethashStruct(address from, address to, address[] memory nft, uint[] memory tokenid)
        public
        pure
        returns (bytes32)
    {
        return
     keccak256(
      abi.encode(
          keccak256("set(address from,address to,address[] nft,uint[] tokenid)"),
          from,
          to,
          nft,
          tokenid
        )
        
    );
    }
 
    function verifySignature (address _user, bytes32 eip712DomainHash, bytes32 hashStruct, uint8 v, bytes32 r, bytes32 s)
        public
        pure returns (bool) { 
        bytes32 hash = keccak256(abi.encodePacked("\x19\x01", eip712DomainHash, hashStruct));
         return ecrecover(hash, v, r, s) == _user;
        }

   
}


1 Answer 1

0

You need to abi encodePacked the array values in the getHashStruct().

OpenSea Seaport example: https://github.com/ProjectOpenSea/seaport/blob/a62c2f8f484784735025d7b03ccb37865bc39e5a/reference/lib/ReferenceGettersAndDerivers.sol#L130

From https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md#definition-of-encodedata:

The array values are encoded as the keccak256 hash of the concatenated encodeData of their contents (i.e. the encoding of SomeType[5] is identical to that of a struct containing five members of type SomeType).

  function getHashStruct(
        address from,
        address to,
        address[] memory nft,
        uint256[] memory tokenid
    ) public pure returns (bytes32) {
        return
            keccak256(
                abi.encode(
                    keccak256('set(address from,address to,address[] nft,uint[] tokenid)'),
                    from,
                    to,
                    keccak256(abi.encodePacked(nft)),
                    keccak256(abi.encodePacked(tokenid))
                )
            );
    }

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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