Skip to content
LogoLogo

signTypedData

Signs EIP-712 typed data via ERC-7739 TypedDataSign format.

This Action is suitable to sign messages for contracts (e.g. ERC-4337 Smart Accounts) that implement (or conform to) ERC-7739 (e.g. Solady's ERC1271.sol).

With the calculated signature, you can use verifyTypedData to verify the signature

Usage

// @filename: config.ts
import { createWalletClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { erc7739Actions } from 'viem/experimental'
 
export const walletClient = createWalletClient({
  account: privateKeyToAccount('0x...'),
  transport: http()
}).extend(erc7739Actions({ 
  verifier: '0xCB9fA1eA9b8A3bf422a8639f23Df77ea66020eC2' 
}))
// @filename: example.ts
// ---cut---
import { account, walletClient } from './config'
import { domain, types } from './data'
 
const signature = await walletClient.signTypedData({ 
  // Account used for signing.
  account,
  domain,
  types,
  primaryType: 'Mail',
  message: {
    from: {
      name: 'Cow',
      wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
    },
    to: {
      name: 'Bob',
      wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
    },
    contents: 'Hello, Bob!',
  },
  // Verifying contract address (e.g. ERC-4337 Smart Account).
  verifier: '0xCB9fA1eA9b8A3bf422a8639f23Df77ea66020eC2'
})

Account and/or Verifier Hoisting

If you do not wish to pass an account and/or verifier to every signTypedData, you can also hoist the Account and/or Verifier on the Wallet Client (see config.ts).

Learn more.

import {  } from './config'
import { ,  } from './data'
 
const  = await .({ 
  ,
  ,
  : 'Mail',
  : {
    : {
      : 'Cow',
      : '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
    },
    : {
      : 'Bob',
      : '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
    },
    : 'Hello, Bob!',
  },
})

Returns

Hex

The signed data.

Parameters

account

  • Type: Account | Address

Account to used to sign the typed data.

Accepts a JSON-RPC Account or Local Account (Private Key, etc).

import {  } from './config'
 
const  = await .({
  : '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', 
  : {
    : 'Ether Mail',
    : '1',
    : 1,
    : '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
  },
  : {
    : [
      { : 'name', : 'string' },
      { : 'wallet', : 'address' },
    ],
    : [
      { : 'from', : 'Person' },
      { : 'to', : 'Person' },
      { : 'contents', : 'string' },
    ],
  },
  : 'Mail',
  : {
    : {
      : 'Cow',
      : '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
    },
    : {
      : 'Bob',
      : '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
    },
    : 'Hello, Bob!',
  },
  : '0xCB9fA1eA9b8A3bf422a8639f23Df77ea66020eC2'
})

domain

Type: TypedDataDomain

The typed data domain.

import {  } from './config'
 
const  = await .({
  : '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
  : { 
    : 'Ether Mail',
    : '1',
    : 1,
    : '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
  },
  : {
    : [
      { : 'name', : 'string' },
      { : 'wallet', : 'address' },
    ],
    : [
      { : 'from', : 'Person' },
      { : 'to', : 'Person' },
      { : 'contents', : 'string' },
    ],
  },
  : 'Mail',
  : {
    : {
      : 'Cow',
      : '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
    },
    : {
      : 'Bob',
      : '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
    },
    : 'Hello, Bob!',
  },
  : '0xCB9fA1eA9b8A3bf422a8639f23Df77ea66020eC2'
})

types

The type definitions for the typed data.

import {  } from './config'
 
const  = await .({
  : '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
  : { 
    : 'Ether Mail',
    : '1',
    : 1,
    : '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
  },
  : { 
    : [
      { : 'name', : 'string' },
      { : 'wallet', : 'address' },
    ],
    : [
      { : 'from', : 'Person' },
      { : 'to', : 'Person' },
      { : 'contents', : 'string' },
    ],
  },
  : 'Mail',
  : {
    : {
      : 'Cow',
      : '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
    },
    : {
      : 'Bob',
      : '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
    },
    : 'Hello, Bob!',
  },
})

primaryType

Type: Inferred string.

The primary type to extract from types and use in value.

import {  } from './config'
 
const  = await .({
  : '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
  : { 
    : 'Ether Mail',
    : '1',
    : 1,
    : '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
  },
  : {
    : [
      { : 'name', : 'string' },
      { : 'wallet', : 'address' },
    ],
    : [ 
      { : 'from', : 'Person' },
      { : 'to', : 'Person' },
      { : 'contents', : 'string' },
    ],
  },
  : 'Mail', 
  : {
    : {
      : 'Cow',
      : '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
    },
    : {
      : 'Bob',
      : '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
    },
    : 'Hello, Bob!',
  },
})

message

Type: Inferred from types & primaryType.

import {  } from './config'
 
const  = await .({
  : '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
  : { 
    : 'Ether Mail',
    : '1',
    : 1,
    : '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
  },
  : {
    : [
      { : 'name', : 'string' },
      { : 'wallet', : 'address' },
    ],
    : [
      { : 'from', : 'Person' },
      { : 'to', : 'Person' },
      { : 'contents', : 'string' },
    ],
  },
  : 'Mail', 
  : { 
    : {
      : 'Cow',
      : '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
    },
    : {
      : 'Bob',
      : '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
    },
    : 'Hello, Bob!',
  },
  : '0xCB9fA1eA9b8A3bf422a8639f23Df77ea66020eC2'
})

verifier

  • Type: Address

The address of the verifying contract (e.g. a ERC-4337 Smart Account). Required if verifierDomain is not passed.

import {  } from './config'
 
const  = await .({
  : '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
  : { 
    : 'Ether Mail',
    : '1',
    : 1,
    : '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
  },
  : {
    : [
      { : 'name', : 'string' },
      { : 'wallet', : 'address' },
    ],
    : [
      { : 'from', : 'Person' },
      { : 'to', : 'Person' },
      { : 'contents', : 'string' },
    ],
  },
  : 'Mail', 
  : {
    : {
      : 'Cow',
      : '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
    },
    : {
      : 'Bob',
      : '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
    },
    : 'Hello, Bob!',
  },
  : '0xCB9fA1eA9b8A3bf422a8639f23Df77ea66020eC2'
})

verifierDomain

  • Type: TypedDataDomain

Account domain separator. Required if verifier is not passed.

// @filename: config.ts
import { createWalletClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { erc7739Actions } from 'viem/experimental'
 
export const walletClient = createWalletClient({
  account: privateKeyToAccount('0x...'),
  transport: http()
}).extend(erc7739Actions({ 
  verifier: '0xCB9fA1eA9b8A3bf422a8639f23Df77ea66020eC2' 
}))
// @filename: example.ts
// ---cut---
import { walletClient } from './config'
 
const signature = await walletClient.signTypedData({
  account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
  domain: { 
    name: 'Ether Mail',
    version: '1',
    chainId: 1,
    verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
  },
  types: {
    Person: [
      { name: 'name', type: 'string' },
      { name: 'wallet', type: 'address' },
    ],
    Mail: [
      { name: 'from', type: 'Person' },
      { name: 'to', type: 'Person' },
      { name: 'contents', type: 'string' },
    ],
  },
  primaryType: 'Mail', 
  message: {
    from: {
      name: 'Cow',
      wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
    },
    to: {
      name: 'Bob',
      wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
    },
    contents: 'Hello, Bob!',
  },
  verifierDomain: { 
    name: 'SoladyAccount', 
    version: '1', 
    chainId: 1, 
    verifyingContract: '0xCB9fA1eA9b8A3bf422a8639f23Df77ea66020eC2'
  }, 
})