Documentation Index
Fetch the complete documentation index at: https://docs.dynamic.xyz/docs/llms.txt
Use this file to discover all available pages before exploring further.
Overview
There are three ways to validate EVM signatures: Using Viem helpers, Manual validation, and EIP 6492 (necessary if you are using Kernel clients).
Validate with Viem
Viem provides verifyMessage (EIP‑191) and verifyTypedData (EIP‑712). When you pass a PublicClient, Viem can automatically validate contract wallet signatures via ERC‑1271.
EIP‑191 (message/personal_sign)
import { createPublicClient, http, verifyMessage } from 'viem';
import { mainnet } from 'viem/chains';
const publicClient = createPublicClient({ chain: mainnet, transport: http() });
type VerifyInput = {
address: `0x${string}`; // expected signer address (EOA or contract)
message: string; // exact message that was signed
signature: `0x${string}`;
};
export async function verifyEip191({ address, message, signature }: VerifyInput) {
// Returns true for EOAs and ERC-1271 contracts (if contract implements isValidSignature)
return verifyMessage(publicClient, { address, message, signature });
}
EIP‑712 (typed data)
import { createPublicClient, http, verifyTypedData } from 'viem';
import { mainnet } from 'viem/chains';
const publicClient = createPublicClient({ chain: mainnet, transport: http() });
const domain = {
name: 'Example DApp',
version: '1',
chainId: 1,
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
} as const;
const types = {
Mail: [
{ name: 'from', type: 'address' },
{ name: 'to', type: 'address' },
{ name: 'contents', type: 'string' },
],
} as const;
type VerifyTypedDataInput = {
address: `0x${string}`; // expected signer address (EOA or contract)
message: { from: `0x${string}`; to: `0x${string}`; contents: string };
signature: `0x${string}`;
};
export async function verifyEip712({ address, message, signature }: VerifyTypedDataInput) {
return verifyTypedData(publicClient, {
address,
domain,
types,
primaryType: 'Mail',
message,
signature,
});
}
Manual validation
EIP‑191 (message)
import { recoverMessageAddress } from 'viem';
export async function isValidMessageSignature({
expectedAddress,
message,
signature,
}: {
expectedAddress: `0x${string}`;
message: string;
signature: `0x${string}`;
}) {
const recovered = await recoverMessageAddress({ message, signature });
return recovered.toLowerCase() === expectedAddress.toLowerCase();
}
EIP‑712 (typed data)
import { recoverTypedDataAddress } from 'viem';
export async function isValidTypedDataSignature({
expectedAddress,
domain,
types,
primaryType,
message,
signature,
}: {
expectedAddress: `0x${string}`;
domain: Record<string, unknown>;
types: Record<string, Array<{ name: string; type: string }>>;
primaryType: string;
message: Record<string, unknown>;
signature: `0x${string}`;
}) {
const recovered = await recoverTypedDataAddress({
domain,
types,
primaryType: primaryType as any,
message,
signature,
});
return recovered.toLowerCase() === expectedAddress.toLowerCase();
}
Using EIP 6492
import { verifyEIP6492Signature } from '@zerodev/sdk'
import { hashMessage } from "viem"
const signature = await account.signMessage('hello world');
await verifyEIP6492Signature({
signer: account.address,
hash: hashMessage('hello world'),
signature: signature,
client: publicClient,
});