Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

useSign

Hook to sign messages using the unified wallet_sign method (ERC-7871). This combines the functionality of useSignMessage and useSignTypedData into a single hook, with support for specifying a target chain.

Type: hook

Import

import { useSign } from '@jaw.id/wagmi';

Signature

function useSign(parameters?: {
  config?: Config;
  mutation?: UseMutationParameters;
}): UseMutationResult

Parameters

config

Type: Config (optional)

Wagmi config. If not provided, uses the config from WagmiProvider.

mutation

Type: UseMutationParameters (optional)

TanStack React Query mutation options.

Returns

Returns a TanStack React Query mutation result:

PropertyTypeDescription
mutatefunctionFunction to sign a message
mutateAsyncfunctionAsync version of mutate
dataHexThe signature
isPendingbooleanWhether signing is in progress
isSuccessbooleanWhether signing succeeded
isErrorbooleanWhether signing failed
errorErrorError if signing failed

Mutation Variables

When calling mutate(), pass:

request

Type: PersonalSignRequestData | TypedDataRequestData (required)

The signing request, which can be one of two types:

Personal Sign (EIP-191)

{
  type: '0x45',
  data: {
    message: string;
  }
}

Typed Data (EIP-712)

{
  type: '0x01',
  data: {
    types: Record<string, TypedDataParameter[]>;
    primaryType: string;
    domain: TypedDataDomain;
    message: Record<string, unknown>;
  }
}

Optional Parameters

ParameterTypeDescription
addressAddressSpecific account address
chainIdnumberTarget chain ID for signing
connectorConnectorSpecific connector

Why Use useSign?

Unified API

Instead of choosing between useSignMessage and useSignTypedData, use a single hook that handles both:

Signature TypeType CodeStandard
Personal Sign0x45EIP-191
Typed Data0x01EIP-712

Chain-Specific Signing

Smart accounts can produce different signatures depending on which chain they're deployed on. The chainId parameter lets you sign for a specific chain without calling wallet_switchEthereumChain first:

// Sign for Base without switching chains
signMessage({
  chainId: 8453,
  request: {
    type: '0x45',
    data: { message: 'Hello from Base' },
  },
});

Examples

Personal Sign

import { useSign } from '@jaw.id/wagmi';
 
function SignMessageButton() {
  const { mutate: signMessage, data: signature, isPending } = useSign();
 
  const handleSign = () => {
    signMessage({
      request: {
        type: '0x45',
        data: { message: 'Hello, World!' },
      },
    });
  };
 
  return (
    <div>
      <button onClick={handleSign} disabled={isPending}>
        {isPending ? 'Signing...' : 'Sign Message'}
      </button>
      {signature && <p>Signature: {signature}</p>}
    </div>
  );
}

Typed Data (EIP-712)

import { useSign } from '@jaw.id/wagmi';
 
function SignTypedDataButton() {
  const { mutate: signMessage, data: signature, isPending } = useSign();
 
  const handleSign = () => {
    signMessage({
      request: {
        type: '0x01',
        data: {
          types: {
            EIP712Domain: [
              { name: 'name', type: 'string' },
              { name: 'version', type: 'string' },
              { name: 'chainId', type: 'uint256' },
            ],
            Mail: [
              { name: 'from', type: 'string' },
              { name: 'to', type: 'string' },
              { name: 'contents', type: 'string' },
            ],
          },
          primaryType: 'Mail',
          domain: {
            name: 'My dApp',
            version: '1',
            chainId: 1,
          },
          message: {
            from: 'Alice',
            to: 'Bob',
            contents: 'Hello!',
          },
        },
      },
    });
  };
 
  return (
    <button onClick={handleSign} disabled={isPending}>
      {isPending ? 'Signing...' : 'Sign Typed Data'}
    </button>
  );
}

Cross-Chain Signing

import { useSign } from '@jaw.id/wagmi';
import { base, mainnet } from 'wagmi/chains';
 
function CrossChainSign() {
  const { mutate: signMessage, isPending } = useSign();
 
  const signForBase = () => {
    signMessage({
      chainId: base.id,
      request: {
        type: '0x45',
        data: { message: 'Signed using Base smart account' },
      },
    });
  };
 
  const signForMainnet = () => {
    signMessage({
      chainId: mainnet.id,
      request: {
        type: '0x45',
        data: { message: 'Signed using Mainnet smart account' },
      },
    });
  };
 
  return (
    <div>
      <button onClick={signForBase} disabled={isPending}>
        Sign for Base
      </button>
      <button onClick={signForMainnet} disabled={isPending}>
        Sign for Mainnet
      </button>
    </div>
  );
}

With Callbacks

import { useSign } from '@jaw.id/wagmi';
 
function SignWithCallbacks() {
  const { mutate: signMessage } = useSign({
    mutation: {
      onSuccess: (signature) => {
        console.log('Signature:', signature);
        // Send signature to your backend
      },
      onError: (error) => {
        console.error('Signing failed:', error);
      },
    },
  });
 
  // ...
}

Comparison with Wagmi Hooks

FeatureuseSignMessageuseSignTypedDatauseSign
Personal sign (EIP-191)YesNoYes
Typed data (EIP-712)NoYesYes
Target chain parameterNoNoYes
Smart account awareNoNoYes

Use Cases

  • Authentication - Sign messages to prove account ownership
  • Gasless Signatures - Sign data without sending a transaction
  • Multi-chain dApps - Sign for different chains without switching
  • Permit Signatures - Sign EIP-2612 permit messages
  • Off-chain Orders - Sign trading orders for DEX aggregators

Related