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?
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:
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.There are definitely plenty of use cases. These are some that just came to mind
Adding to the response by @zemse:
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.
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.
Most helpful comment
Adding to the response by @zemse:
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.
If you try to sign into CryptoKitties website, they make you sign a message, from which they can determine which kitties you own.