How to sign data and verify the address that generated the signature using Wagmi
In this tutorial, we are going to learn how to sign data using the wallet connected to your app and how to verify the address that generated the signature using Wagmi hooks.
In this tutorial, we are going to learn how to sign data using the wallet connected to your app and how to verify the address that generated the signature using Wagmi hooks.
Here is the code to sign a message and get the address that signed it:
import { useEffect, useState } from 'react';
import { useSignMessage } from 'wagmi';
import { utils } from 'ethers';
const messageToSign = '1234567890';
export const SignAndVerify = () => {
const [signerAddress, setSignerAddress] = useState();
const { data: signature, isLoading, isError, signMessage } = useSignMessage({
message: messageToSign,
});
useEffect(() => {
if (signature) {
// verify the signature and get the address that generated the signature for the message passed
setSignerAddress(utils.verifyMessage(messageToSign, signature));
}
}, [signature]);
if (isLoading) return <p>Please confirm on your wallet...</p>;
if (isError) return <p>Could not sign the message</p>;
return (
<div>
{signature && <p>The signature that was generated: {signature}</p>}
{signerAddress && <p>This address signed the message: {signerAddress}</p>}
<button disabled={!signMessage} onClick={() => signMessage()}>
Sign message
</button>
</div>
);
};
Now let's take a deeper look at what this code does.
How to sign a message using Wagmi
To sign a message using Wagmi, we use the useSignMessage
hook.
Like the other Wagmi hooks, it takes in parameters an object that contains config values for the hook. In that object, we pass the message that we want to sign in the message
property.
If you don't pass anything in the message
property, it won't do anything.
For example, it allows you to have the message to sign in the state of your component and when a value is set to that state variable, it generates a signature. When the message changes, it re-generates a signature.
It also takes other properties in the config object, check out the documentation to see everything you can pass.
That hook returns an object containing the following properties:
data
: the signature that was generated (an hexadecimal string)signMessage
: the function to call to sign the message you passed in the parameters. It will open a screen in the user's wallet to ask them to sign the message. It will setisLoading
totrue
while waiting for the user's confirmationisLoading
:true
while waiting for the user to sign the message on their wallet andfalse
before callingsignMessage
and after the user signed the message on their wallet.isSuccess
:true
if the user signed the data andfalse
if there was an error or ifsignMessage
hasn't been called yet.isError
:true
if signing the message failed (for example if the user rejected signing the data on their wallet) andfalse
if it succeeded or ifsignMessage
hasn't been called yet.error
: if signing the message failed, this property contains the error that was thrown when trying to sign the data. It will benull
if there was no error.
An important thing to note here is that you need a Signer
to use that hook. In other words, a wallet needs to be connected to your application to be able to use that hook.
Otherwise, the signMessage
function will be undefined
. That's why in the example above, I disable the button if signMessage
is not defined, it's to avoid calling that function when it's undefined
.
Here is an example of how to sign data:
import { useSignMessage } from 'wagmi';
const messageToSign = '1234567890';
export const SignMessage = () => {
const { data, isLoading, isError, signMessage } = useSignMessage({
message: messageToSign,
});
if (isLoading) return <p>Please confirm on your wallet...</p>;
if (isError) return <p>Could not sign the message</p>;
return (
<div>
{data && <p>The signature that was generated: {data}</p>}
<button disabled={!signMessage} onClick={() => signMessage()}>
Sign message
</button>
</div>
);
};
How to verify a signature and get the address that generated the signature
To get the address that generated the signature, we have to use Ethers JS directly. Wagmi doesn't provide a hook for that.
For that, we can use the verifyMessage
that is in the utils
of Ethers JS.
That function takes in 2 parameters:
- the message that was signed
- the signature to verify
And it returns the address that generated the signature you passed in the parameters according to the data you passed.
If you pass the same signature but different data, you won't get the same result so make sure you pass the exact same data that was used to generate the signature.
import { utils } from 'ethers'
export const VerifySignature = ({ data, signature }) => {
return (
<p>
The signature {signature},
generated from message "{data}",
was signed with {utils.verifyMessage(data, signature)}
</p>
)
}
If you want, you can also verify signatures in Solidity smart contracts. If you want to learn how to do that, check out this tutorial:
And if you want to learn how to make a complete authentication system on Ethereum using signatures like this, check out this tutorial:
And that's it 🎉
Thank you for reading this article