> **Can't find what you're looking for?** Use `search_docs` on the docs MCP server at `https://v3.viem.sh/api/mcp` to find what you need.

# Sign Typed Data \[typedData.sign]

Signs [EIP-712](https://eips.ethereum.org/EIPS/eip-712) typed data.

* **Local Accounts**: signs locally (no JSON-RPC request).
* **JSON-RPC Accounts**: signs via `eth_signTypedData_v4`.

## Usage

This example signs [EIP-712](https://eips.ethereum.org/EIPS/eip-712) typed data.

:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'

const signature = await client.typedData.sign({
  domain: { name: 'Ether Mail', version: '1' },
  types: {
    Mail: [{ name: 'contents', type: 'string' }],
  },
  primaryType: 'Mail',
  message: { contents: 'hello world' },
})
// @log: '0x66eece9e5f6d38fbe22ecacd3f95f80217e47b13b02f5b6a86e5b9f0e2b7...'
```

```ts twoslash [viem.config.ts] filename="viem.config.ts"
import { Account, Client, http, walletActions } from 'viem'
import { mainnet } from 'viem/chains'

export const client = Client.create({
  account: Account.fromPrivateKey('0x…'),
  chain: mainnet,
  transport: http(),
}).extend(walletActions())
```
:::

### Standalone Action

Call `Actions.typedData.sign` directly by passing the Client as the first argument.

:::code-group
```ts twoslash [example.ts]
import { Actions } from 'viem'
import { client } from './viem.config'

const signature = await Actions.typedData.sign(client, {
  domain: { name: 'Ether Mail', version: '1' },
  types: {
    Mail: [{ name: 'contents', type: 'string' }],
  },
  primaryType: 'Mail',
  message: { contents: 'hello world' },
})
// @log: '0x66eece9e5f6d38fbe22ecacd3f95f80217e47b13b02f5b6a86e5b9f0e2b7...'
```

```ts twoslash [viem.config.ts] filename="viem.config.ts"
import { Account, Client, http } from 'viem'
import { mainnet } from 'viem/chains'

export const client = Client.create({
  account: Account.fromPrivateKey('0x…'),
  chain: mainnet,
  transport: http(),
})
```
:::

## Recipes

### Bind a Signature to a Contract

Include a chain ID and verifying contract in the domain when the signature must be specific to that
contract deployment.

:::code-group
```ts twoslash [example.ts]
import { mainnet } from 'viem/chains'
import { Address } from 'viem/utils'
import { client } from './viem.config'

export function signForContract(verifyingContract: Address.Address) {
  return client.typedData.sign({
    domain: {
      chainId: mainnet.id, // [!code focus]
      name: 'Ether Mail',
      verifyingContract, // [!code focus]
      version: '1',
    },
    types: {
      Mail: [{ name: 'contents', type: 'string' }],
    },
    primaryType: 'Mail',
    message: { contents: 'hello world' },
  })
}
```

```ts twoslash [viem.config.ts] filename="viem.config.ts"
import { Account, Client, http, walletActions } from 'viem'
import { mainnet } from 'viem/chains'

export const client = Client.create({
  account: Account.fromPrivateKey('0x…'),
  chain: mainnet,
  transport: http(),
}).extend(walletActions())
```
:::

### Request a Signature from a Connected Wallet

Use a JSON-RPC Account when a connected wallet holds the signing key. The wallet receives an
`eth_signTypedData_v4` request.

:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'

const signature = await client.typedData.sign({
  domain: { name: 'Ether Mail', version: '1' },
  types: {
    Mail: [{ name: 'contents', type: 'string' }],
  },
  primaryType: 'Mail',
  message: { contents: 'hello world' },
})
// @log: '0x66eece9e5f6d38fbe22ecacd3f95f80217e47b13b02f5b6a86e5b9f0e2b7...'
```

```ts twoslash [viem.config.ts] filename="viem.config.ts"
import { Client, custom, walletActions } from 'viem'
import { mainnet } from 'viem/chains'
import 'viem/window'

export const client = Client.create({
  account: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e', // [!code focus]
  chain: mainnet,
  transport: custom(window.ethereum!),
}).extend(walletActions())
```
:::

## Return Value

`Hex`

The signed typed data.

## Parameters

### account

* **Type:** `Account | Address`
* **Default:** `client.account`

Account (or address) to sign with.

```ts twoslash
import { Account, Actions } from 'viem'
// [!include ~/snippets/docs/reference-client.ts:setup]
// ---cut---
const signature = await Actions.typedData.sign(client, {
  account: Account.fromPrivateKey('0x…'), // [!code focus]
  types: { Mail: [{ name: 'contents', type: 'string' }] },
  primaryType: 'Mail',
  message: { contents: 'hello world' },
})
```

### domain

* **Type:** `TypedDataDomain`

The typed data domain.

```ts twoslash
import { Actions } from 'viem'
// [!include ~/snippets/docs/reference-client.ts:setup]
// ---cut---
const signature = await Actions.typedData.sign(client, {
  domain: { name: 'Ether Mail', version: '1', chainId: 1 }, // [!code focus]
  types: { Mail: [{ name: 'contents', type: 'string' }] },
  primaryType: 'Mail',
  message: { contents: 'hello world' },
})
```

### message

* **Type:** Inferred from `types` and `primaryType`

The message to sign.

```ts twoslash
import { Actions } from 'viem'
// [!include ~/snippets/docs/reference-client.ts:setup]
// ---cut---
const signature = await Actions.typedData.sign(client, {
  types: { Mail: [{ name: 'contents', type: 'string' }] },
  primaryType: 'Mail',
  message: { contents: 'hello world' }, // [!code focus]
})
```

### primaryType

* **Type:** Inferred from `types`

The primary type to extract from `types` and use in `message`.

```ts twoslash
import { Actions } from 'viem'
// [!include ~/snippets/docs/reference-client.ts:setup]
// ---cut---
const signature = await Actions.typedData.sign(client, {
  types: { Mail: [{ name: 'contents', type: 'string' }] },
  primaryType: 'Mail', // [!code focus]
  message: { contents: 'hello world' },
})
```

### requestOptions

* **Type:** `{ dedupe?: boolean; signal?: AbortSignal; ... }`

Options forwarded to the `eth_signTypedData_v4` request for a JSON-RPC Account.

```ts twoslash
import { Actions, Client, http } from 'viem'
import { mainnet } from 'viem/chains'

const client = Client.create({ chain: mainnet, transport: http() })
// ---cut---
const controller = new AbortController()
const signature = await Actions.typedData.sign(client, {
  message: { contents: 'hello world' },
  primaryType: 'Mail',
  requestOptions: { signal: controller.signal }, // [!code focus]
  types: { Mail: [{ name: 'contents', type: 'string' }] },
})
```

### types

* **Type:** `TypedData`

The typed data type definitions.

```ts twoslash
import { Actions } from 'viem'
// [!include ~/snippets/docs/reference-client.ts:setup]
// ---cut---
const signature = await Actions.typedData.sign(client, {
  types: { Mail: [{ name: 'contents', type: 'string' }] }, // [!code focus]
  primaryType: 'Mail',
  message: { contents: 'hello world' },
})
```

## Errors

| Error | Description |
| --- | --- |
| `Account.NotFoundError` | No `account` was provided and the client has no account. |
