Signature Verification
Verifying signatures for smart contract wallets involves specific considerations since the smart contract itself cannot produce a signature. Instead, it provides a function:
_10function isValidSignature(bytes32 _hash, bytes memory _signature) returns (bytes4 magicValue);
This function, defined in EIP-1271, is called to verify if a given signature is valid.
For a Smart Wallet, a signature is valid if it is signed by a current signer (or "owner") of the wallet. For instance, a user might sign a message using their passkey. When the isValidSignature
function is called on their Smart Wallet, it validates the signature because the user's passkey is authorized as an owner.
The following section outlines how to implement both personal message signing and typed data signing using wagmi.
Message Signing#
For basic message signing (personal_sign), you can use wagmi's useSignMessage
hook. Here's an example implementation:
_28import { useSignMessage } from 'wagmi'_28_28function SignMessage() {_28 const { signMessage, data: signature, isPending, error } = useSignMessage()_28_28 const handlePersonalSign = () => {_28 signMessage({ message: 'Hello World' })_28 }_28_28 return (_28 <div>_28 <button _28 onClick={handlePersonalSign}_28 disabled={isPending}_28 >_28 {isPending ? 'Signing...' : 'Sign Message'}_28 </button>_28 _28 {signature && (_28 <div>_28 <p>Signature: {signature}</p>_28 </div>_28 )}_28 _28 {error && <div>Error: {error.message}</div>}_28 </div>_28 )_28}
Typed Data Signing#
For more complex signatures, you can use typed data signing (EIP-712) with wagmi's useSignTypedData
hook:
_54import { useSignTypedData } from 'wagmi'_54_54function SignTypedData() {_54 const { signTypedData, data: signature, isPending, error } = useSignTypedData()_54_54 const types = {_54 Mail: [_54 {name: 'from', type: 'Person'},_54 {name: 'to', type: 'Person'},_54 {name: 'content', type: 'string'},_54 ],_54 Person: [_54 {name: 'name', type: 'string'},_54 {name: 'wallet', type: 'address'},_54 ],_54 }_54_54 const handleTypedMessage = () => {_54 signTypedData({_54 domain: {_54 chainId: 1, // Replace with your chain ID_54 name: 'Example DApp',_54 verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',_54 version: '1',_54 },_54 types,_54 message: {_54 from: { name: 'Alice', wallet: '0x2111111111111111111111111111111111111111' },_54 to: { name: 'Bob', wallet: '0x3111111111111111111111111111111111111111' },_54 content: 'Hello!',_54 },_54 primaryType: 'Mail',_54 })_54 }_54_54 return (_54 <div>_54 <button _54 onClick={handleTypedMessage}_54 disabled={isPending}_54 >_54 {isPending ? 'Signing...' : 'Sign Typed Data'}_54 </button>_54 _54 {signature && (_54 <div>_54 <p>Signature: {signature}</p>_54 </div>_54 )}_54 _54 {error && <div>Error: {error.message}</div>}_54 </div>_54 )_54}
Both signing methods work seamlessly with Smart Contract Wallets that implement EIP-1271, allowing for a consistent signing experience across EOA and Smart Contract Wallets.