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

# Simulate Plugin

## Overview

[`Relay.simulate`](#relaysimulate) adds balance changes and estimated fees to
filled transactions. It simulates calls with `tempo_simulateV1` and falls back
to `eth_simulateV1` when the Tempo method is unavailable.

## Recipes

Choose a local relay to run plugins in your application, or connect to a remote
relay at `/relay`. For remote mode, [configure the server](/tempo/guides/relay/run#add-plugins)
with the plugins shown in the local configuration.

These examples use Tempo mainnet. Replace the sender and recipient with your
addresses. The sender needs pathUSD for fees and enough USDC.e for successful
transfers. [`prepareTransactionRequest`](/docs/actions/wallet/prepareTransactionRequest)
prepares a transaction without signing or broadcasting it.

### Preview Balance Diffs

:::code-group
```ts twoslash [example.ts]
import { parseUnits } from 'viem'
import { prepareTransactionRequest } from 'viem/actions'
import { Actions, Addresses } from 'viem/tempo'
import { client } from './viem.config'

const { _capabilities: capabilities } = await prepareTransactionRequest(client, {
  account: '0x1111111111111111111111111111111111111111',
  feeToken: Addresses.pathUsd,
  calls: [Actions.token.transfer.call(client, {
    token: '0x20c000000000000000000000b9537d11c60e8b50', // USDC.e on Tempo mainnet
    to: '0x2222222222222222222222222222222222222222',
    amount: parseUnits('100', 6),
  })],
})

// [!code focus:start]
capabilities?.balanceDiffs
// @log: {
// @log:   '0x1111111111111111111111111111111111111111': [{
// @log:     address: '0x20c000000000000000000000b9537d11c60e8b50',
// @log:     decimals: 6,
// @log:     direction: 'outgoing',
// @log:     formatted: '100',
// @log:     name: 'Bridged USDC (Stargate)',
// @log:     recipients: ['0x2222222222222222222222222222222222222222'],
// @log:     symbol: 'USDC.e',
// @log:     value: '0x5f5e100',
// @log:   }],
// @log: }
// [!code focus:end]
```

```ts twoslash [viem.config.ts (Local Relay)] filename="viem.config.ts"
import { http } from 'viem'
import { createClient, Relay, withRelay } from 'viem/tempo'

export const client = createClient({
  transport: withRelay(http(), {
    plugins: [Relay.simulate()], // [!code focus]
  }),
})
```

```ts twoslash [viem.config.ts (Remote Relay)] filename="viem.remote.config.ts"
import { http } from 'viem'
import { createClient, withRelay } from 'viem/tempo'

// See https://viem.sh/tempo/guides/relay/run for instructions on running a relay.
export const client = createClient({
  transport: withRelay(http(), http('/relay')), // [!code focus]
})
```
:::

`balanceDiffs` groups net token transfers and final approval exposure by account.
Outgoing amounts include approval exposure. Incoming funds use a separate entry
for the same token, so they do not cancel outgoing approval exposure.

### Report Missing Funds

If the sender holds 40 USDC.e and attempts to transfer 100, the deficit is
60 USDC.e. Set `errors: true` to receive that deficit in the response instead of
an RPC error. The sender still needs pathUSD to pay fees.

:::code-group
```ts twoslash [example.ts]
import { parseUnits } from 'viem'
import { fillTransaction } from 'viem/actions'
import { Actions, Addresses } from 'viem/tempo'
import { client } from './viem.config'

const { capabilities } = await fillTransaction(client, {
  account: '0x1111111111111111111111111111111111111111',
  feeToken: Addresses.pathUsd,
  capabilities: { errors: true }, // [!code focus]
  calls: [Actions.token.transfer.call(client, {
    token: '0x20c000000000000000000000b9537d11c60e8b50', // USDC.e on Tempo mainnet
    to: '0x2222222222222222222222222222222222222222',
    amount: parseUnits('100', 6),
  })],
})

// [!code focus:start]
capabilities?.insufficientFunds
// @log: {
// @log:   amount: '0x3938700',
// @log:   decimals: 6,
// @log:   formatted: '60',
// @log:   token: '0x20c000000000000000000000b9537d11c60e8b50',
// @log:   symbol: 'USDC.e',
// @log: }
capabilities?.error?.errorName
// @log: 'InsufficientBalance'
// [!code focus:end]
```

```ts twoslash [viem.config.ts (Local Relay)] filename="viem.config.ts"
import { http } from 'viem'
import { createClient, Relay, withRelay } from 'viem/tempo'

export const client = createClient({
  transport: withRelay(http(), {
    plugins: [Relay.simulate()], // [!code focus]
  }),
})
```

```ts twoslash [viem.config.ts (Remote Relay)] filename="viem.remote.config.ts"
import { http } from 'viem'
import { createClient, withRelay } from 'viem/tempo'

// See https://viem.sh/tempo/guides/relay/run for instructions on running a relay.
export const client = createClient({
  transport: withRelay(http(), http('/relay')), // [!code focus]
})
```
:::

`insufficientFunds` reports the missing amount when token metadata is available.
Optimistic balance diffs on a failed fill depend on the execution node and can
be empty.

### Handle Execution Errors

With `errors: true`, execution reverts return a transaction stub and a decoded
`capabilities.error`. Inspect its `errorName`, `message`, and, for known errors,
`abiItem` and `data`. A failed fill is not a transaction ready to sign.

This example attempts to mint tokens without permission and inspects the decoded
revert. The sender still needs pathUSD for fees.

:::code-group
```ts twoslash [example.ts]
import { parseUnits } from 'viem'
import { prepareTransactionRequest } from 'viem/actions'
import { Actions, Addresses } from 'viem/tempo'
import { client } from './viem.config'

const { _capabilities: capabilities } = await prepareTransactionRequest(client, {
  account: '0x1111111111111111111111111111111111111111',
  feeToken: Addresses.pathUsd,
  capabilities: { errors: true }, // [!code focus]
  calls: [Actions.token.mint.call(client, {
    token: '0x20c000000000000000000000b9537d11c60e8b50', // USDC.e on Tempo mainnet
    to: '0x2222222222222222222222222222222222222222',
    amount: parseUnits('100', 6),
  })],
})

// [!code focus:start]
console.error(capabilities?.error)
// @log: {
// @log:   errorName: 'Unauthorized',
// @log:   abiItem: { type: 'error', name: 'Unauthorized', inputs: [] },
// @log:   message: 'Unauthorized.',
// @log:   data: '0x82b42900',
// @log: }
// [!code focus:end]
```

```ts twoslash [viem.config.ts (Local Relay)] filename="viem.config.ts"
import { http } from 'viem'
import { createClient, Relay, withRelay } from 'viem/tempo'

export const client = createClient({
  transport: withRelay(http(), {
    plugins: [Relay.simulate()], // [!code focus]
  }),
})
```

```ts twoslash [viem.config.ts (Remote Relay)] filename="viem.remote.config.ts"
import { http } from 'viem'
import { createClient, withRelay } from 'viem/tempo'

// See https://viem.sh/tempo/guides/relay/run for instructions on running a relay.
export const client = createClient({
  transport: withRelay(http(), http('/relay')), // [!code focus]
})
```
:::

Omitting `errors` or setting it to `false` preserves RPC errors. Invalid requests
and operational failures remain RPC errors in either mode. Unexpected callback
and storage errors return `Internal error`.

Simulation failures do not block a successful fill; unavailable balance changes
are omitted. Place `simulate` before plugins that change the transaction so it
reports their final calls and fee estimate.

## `Relay.simulate`

Creates a transaction simulation plugin.

### Usage

```ts twoslash
import { Relay } from 'viem/tempo'

const plugin = Relay.simulate()
```

### Parameters

#### options.store

* **Type:** `Store.Store`

Optional [store](/tempo/utilities/Store) for token metadata, cached for 24 hours.
Simulation results are never cached.

```ts twoslash
import { Relay, Store } from 'viem/tempo'
// ---cut---
Relay.simulate({ store: Store.memory() }) // [!code focus]
```

### Return Value

`Relay.Plugin`

A plugin for `Relay.create`, `Relay.handleRequest`, or local `withRelay`.
