8

I'm trying to create a signed message off-chain using ethers.js and verify that message on-chain using ecrecover. I'm signing the correct message from my metamask wallet, and passing the r, s, and v from that signature into ecrecover, but not getting a match to my metamask wallet.

My solidity code should work for prefixed or non-prefixed signatures.

Here's the contract I'm using to verify signatures:

pragma solidity ^0.5.0;
contract SignatureVerifier {
    /// @dev Signature verifier
    function isSigned(address _address, bytes32 messageHash, uint8 v, bytes32 r, bytes32 s) public pure returns (bool) {
        return _isSigned(_address, messageHash, v, r, s) || _isSignedPrefixed(_address, messageHash, v, r, s);
    }

    /// @dev Checks unprefixed signatures.
    function _isSigned(address _address, bytes32 messageHash, uint8 v, bytes32 r, bytes32 s)
        internal pure returns (bool)
    {
        return ecrecover(messageHash, v, r, s) == _address;
    }

    /// @dev Checks prefixed signatures.
    function _isSignedPrefixed(address _address, bytes32 messageHash, uint8 v, bytes32 r, bytes32 s)
        internal pure returns (bool)
    {
        bytes memory prefix = "\x19Ethereum Signed Message:\n32";
        return _isSigned(_address, keccak256(abi.encodePacked(prefix, messageHash)), v, r, s);
    }
} 

From ethers, here's (a simplified version of) the code I'm using to generate the signature, which I use as parameters for the _isSigned function call.

let provider = new ethers.providers.Web3Provider(window.ethereum)
let signer = provider.getSigner()
let dataHash = '0x952d17582514a6a434234b10b8e6b681b6006c8ed225d479fa3db70828b9cd60'
let signature = await signer.signMessage(dataHash)
let sigBreakdown = ethers.utils.splitSignature(signature)
console.log(sigBreakdown)

this prompts me for a signature in matamask where I sign the correct dataHash. It then logs an r, s, and v value.

In remix, I call isSigned, passing my metamask address, the dataHash (0x952...d60), and the r, s, and v values, expecting a result of true but it's returning false. I'm fairly confident in the solidity code and the javascript code here, but clearly I'm missing something. Help is greatly appreciated!

TylerH
  • 20,799
  • 66
  • 75
  • 101
a94
  • 564
  • 1
  • 7
  • 16

1 Answers1

6

I was signing the string dataHash instead of bytes value of dataHash. I was able to get the verification by adding:

let bytesDataHash = ethers.utils.arrayify(dataHash)

and signing bytesDataHash instead of dataHash :) as usual, Richard Moore had responded to a similar questio on github because that man is incredible: https://github.com/ethers-io/ethers.js/issues/245#issuecomment-408706606

TylerH
  • 20,799
  • 66
  • 75
  • 101
a94
  • 564
  • 1
  • 7
  • 16