How to verify message in wallet connect with ethers primarily on ambire wallet?
Asked Answered
K

1

5

I am trying to sign a message with wallet connect using ethers, but I am facing an issue when verifying the message with ambire wallet, it's not returning any response.

const signMessage = async () => {
    try {
      console.log("started");
      // 1.] create a provider
      const walletConnectProvider = new WalletConnectProvider({
        infuraId: "3cd774e14cf34ff78167908f8377051c", // Required
        // qrcode: true
      });

      //  2.] enable provider
      await walletConnectProvider.enable();
      // console.log(walletConnectProvider.wc.accounts[0]);
      let rawMessage = "Hello World";
      let rawMessageLength = new Blob([rawMessage]).size;
      let message = ethers.utils.toUtf8Bytes(
        "\x19Ethereum Signed Message:\n" + rawMessageLength + rawMessage
      );
      message = ethers.utils.keccak256(message);
      var params = [
        walletConnectProvider.wc.accounts[0],
        message,
      ];

      //  3.] sign message
      const provider = new providers.Web3Provider(walletConnectProvider);
      const signer = provider.getSigner();

      let signature = await signer.signMessage(message);
      console.log("signature", signature);

      //  4.] verify message
      let verified = await ethers.utils.verifyMessage(message, signature);
      console.log("verified", verified);
    } catch (err) {}
  };
Kiyokokiyoshi answered 14/4, 2022 at 5:28 Comment(0)
K
14

there are a couple of things you additionally need:

  1. You need to pass the original message (before prefix) to signer.signMessage, in other words the rawMessage: await signer.signMessage(rawMessage) - because the wallet (no matter if it's Ambire or not) will add the prefix
  2. In order to support smart wallets like Ambire, Gnosis Safe, Argent and others, you need to implement EIP 1271.

In JS (warning: not tested), this will look somewhat like this:

const signerAddr = await signer.getAddress();
if (provider.getCode(signerAddr) === '0x') {
    // Regular RSV sig verification
    verified = signerAddr === (await ethers.utils.verifyMessage(message, signature));
} else {
    // Smart contract wallet (EIP 1271) verification: see https://eips.ethereum.org/EIPS/eip-1271 for more info
    const EIP1271ABI = ['function isValidSignature(bytes32 _hash, bytes memory _signature) public view returns (bytes4 magicValue)'];
    const EIP1271MagicValue = '0x1626ba7e';
    const signerEIP1271Contract = new ethers.Contract(signerAddr, EIP1271ABI, provider);
    const rawMessageLength = new Blob([rawMessage]).size;
    const message = ethers.utils.toUtf8Bytes(
        "\x19Ethereum Signed Message:\n" + rawMessageLength + rawMessage
    );
    const messageHash = ethers.utils.keccak256(message);
    verified = EIP1271MagicValue === (await signerEIP1271Contract.isValidSignature(messageHash, signature));
} 

NOTE: We, the Ambire team, are currently working on a comprehensive guide on how to verify all styles of signature (EIP1271, EIP712, 712+1271, regular), which will hopefully be linked by the ethers.js documentation.

EDIT: We've published a library that makes this a whole lot easier, please check it out: https://github.com/AmbireTech/signature-validator/ - we recommend that you use that

Kindle answered 15/4, 2022 at 10:21 Comment(2)
The code works, Thanks Ivo.Passerby
@Passerby following a discussion with other smart wallet providers we have created a library to verify all signature types at once, it's very easy to use: github.com/AmbireTech/signature-validatorKindle

© 2022 - 2024 — McMap. All rights reserved.