1

I am creating a signature with web3.js form a hashed message that contains two numbers and an address:

const tokenIds = [1,2,3];
const state = 1;
const messageHash = web3.utils.keccak256(tokenIds.length + state + web3.utils.keccak256(fromAddress));
const sign = await web3.eth.accounts.sign(messageHash, signer.privateKey);

await contract.myFn(
  tokenIds,
  sign.v,
  sign.r,
  sign.s,
  {
    from: fromAddress,
  }
);

In my smart contract I then try to reconstruct the hash for message and verify the signature as follow:

function myFn(uint[] calldata tokenIds, uint8 v, bytes32 r, bytes32 s) external {

  require(
    _signerAddress == ecrecover(
      keccak256(abi.encodePacked(
        "\x19Ethereum Signed Message:\n32",


        // messageHash:
        // When I concat those two strings with the address
        // this hash is invalid (not the same as the on from the client). 

        keccak256(abi.encodePacked(
          // uint256 amount
          Strings.toString(tokenIds.length),
          // uint256 state
          Strings.toString(state),
          // address msg.sender is fromAddress
          keccak256(abi.encodePacked(msg.sender))
        ))

      ))
      , v, r, s
    ),
    'mint not allowed'
  );
}

Basically it seems that the string concatenation when recreating messageHash on hash doesn't match. Maybe there is a reliable way to convert the msg.sender (fromAddress) to string?

1

I figured it out thanks to this brilliant article.

The secret is to use web3.utils.soliditySha3 which will abi encode and hash like Solidity would!

const message = web3.utils.soliditySha3(
  tokenIds.length,
  state,
  fromAddress
);

and in the contract simply do:

keccak256(abi.encodePacked(
  tokenIds.length,
  state,
  msg.sender
))

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.