Ethers.js: wallet.address is not the address used to sign the message

Created on 22 Nov 2020  路  8Comments  路  Source: ethers-io/ethers.js

Here is the code to use wallet to sign message and have the signature verified:

  let privateKey = "0x8d8073c48cd4ba11c9d659dcb31f3523d13874b7b3d6d31bc0271652f9541ac0"; //32bytes and 64hex
  let wallet = new ethers.Wallet(privateKey);  // wallet address: 0xc95b6B8Ec0Eee5eBF18E3c519DBdafaE17AD568F
  //contract deployed
  // The hash we wish to sign and verify
  let messageHash = ethers.utils.id(1234);
  let messageHashBytes = ethers.utils.arrayify(messageHash)
  // Sign the binary data
  let flatSig = await wallet.signMessage(messageHashBytes); //<<==wallet is used to sign the message
  // For Solidity, we need the expanded-format of a signature
  let sig = ethers.utils.splitSignature(flatSig);
  // Call the verifyHash function
  let recovered = await contract.signedMsg(contract.address, sig.v, sig.r, sig.s, 1234); //signedMsg is contract function returns signer information
  let recoveredWait = await recovered.wait();
  console.log("Address recovered : ", recoveredWait.from == signerAddress);  //<<==true

Here is the code for signerAddress:

  let url = "http://localhost:8545";
  const provider = new ethers.providers.JsonRpcProvider(url);
  const signer = provider.getSigner(); //forJsonRPC
  let signerAddress = await signer.getAddress(); //<<==signer address: 0x7FdACa197B9D149F8BA75a6b7bbba8959b157135

Here the wallet is used to sign the message. But why the signer address returned by contract is not the wallet address? What is the relationship between wallet address and signer address?

discussion

Most helpful comment

Adding to the response by @zemse:

  1. Proving a transaction was by you; I recently had someone accidentally send me funds, and they were hoping I'd send the funds back. The signed a message with their e-mail address and request, which I was able to verify came from the same address that sent the funds. So I was able to know that the person I was communicating with was the transaction sender and able to send the funds back.

  2. If you try to sign into CryptoKitties website, they make you sign a message, from which they can determine which kitties you own.

All 8 comments

contract.signedMsg should be a view or pure method in your contract or you can use callStatic bucket, otherwise if you "sendTransactoin", then that doesn't give you the return value. That's why recoveredWait.from is the tx sender address (the JsonRpc wallet u you used for sending the tx) so that doesn't have to do with the return value.

When you do wallet.signMessage, then "\x19Ethereum Signed Message:" is prepended, so you also need to take care of that in signedMsg method in your contract.

Hello zemse, what is the purpose of the signed message? The Ethereum is transaction based and it make sense by signing transaction. Is there a real life example of using signed message to change Ethereum state?

You might want signed message signature of a user when:

  1. A wallet cannot directly call a smart contract, someone else has to make tx to contract for the user. In this case msg.sender is the relayer, which the smart contract might be least interested in. So the relayer includes a message that makes enough sense to smart contract and signature on it. You can checkout EIP-191.
  2. Offchain proof of identity that doesn't involve sending any transactions to Ethereum blockchain at all. Offchain governance platforms like Snapchot by balancer labs is an example how you use it.

There are definitely plenty of use cases. These are some that just came to mind

Adding to the response by @zemse:

  1. Proving a transaction was by you; I recently had someone accidentally send me funds, and they were hoping I'd send the funds back. The signed a message with their e-mail address and request, which I was able to verify came from the same address that sent the funds. So I was able to know that the person I was communicating with was the transaction sender and able to send the funds back.

  2. If you try to sign into CryptoKitties website, they make you sign a message, from which they can determine which kitties you own.

@ricmoo @zemse thanks for the details

@ricmoo , the code above keep throwing out the warning message about setTimeout. But there is no setTimeout in the code. What's the warning message about? Thanks.

 [Sat Nov 28 2020 23:54:21.513]  WARN     Setting a timer for a long period of time, i.e. multiple minutes, is a performance and correctness issue on Android as it keeps the timer module awake, and timers can only be called when the app is in the foreground. See https://github.com/facebook/react-native/issues/12981 for more info.
 (Saw setTimeout with duration 120000ms)
[Sat Nov 28 2020 23:54:21.591]  WARN     Setting a timer for a long period of time, i.e. multiple minutes, is a performance and correctness issue on Android as it keeps the timer module awake, and timers can only be called when the app is in the foreground. See https://github.com/facebook/react-native/issues/12981 for more info.
 (Saw setTimeout with duration 120000ms)

Looks like you are using an environment which may have an inefficient implementation of its timer event loop.

There is not much you can do about this, and I think you can safely ignore this. I do believe I鈥檝e seems a way to disable the warning before, depending on your environment, but you will have to look that up in its docs/stackexchange (for example, react native or chrome plugins).

The 120s is what ethers uses by default when connecting to web URLs (since timeouts are not portable, and ethers aims to be portable), after which a TIMEOUT exception will be thrown via a Promise reject.

React native can surpress the warning with configuration as long as it is not a bug.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

adamdossa picture adamdossa  路  3Comments

thegostep picture thegostep  路  3Comments

PhABC picture PhABC  路  3Comments

jochenonline picture jochenonline  路  3Comments

abhishekp1996 picture abhishekp1996  路  3Comments