Skip to content

simulateContract

Simulates & validates a contract interaction.

The simulateContract function simulates/validates a contract interaction. This is useful for retrieving return data and revert reasons of contract write functions.

This function does not require gas to execute and does not change the state of the blockchain. It is almost identical to readContract, but also supports contract write functions.

Internally, simulateContract uses a Public Client to call the call action with ABI-encoded data.

Usage

Below is a very basic example of how to simulate a write function on a contract (with no arguments).

The mint function accepts no arguments, and returns a token ID.

import { account, publicClient } from './config'
import { wagmiAbi } from './abi'
 
const { result } = await publicClient.simulateContract({
  address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
  abi: wagmiAbi,
  functionName: 'mint',
  account,
})

Passing Arguments

If your function requires argument(s), you can pass them through with the args attribute.

TypeScript types for args will be inferred from the function name & ABI, to guard you from inserting the wrong values.

For example, the mint function name below requires a tokenId argument, and it is typed as [number].

import { account, publicClient } from './config'
import { wagmiAbi } from './abi'
 
const { result } = await publicClient.simulateContract({
  address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
  abi: wagmiAbi,
  functionName: 'mint',
  args: [69420], 
  account,
})

Pairing with writeContract

The simulateContract function also pairs well with writeContract.

In the example below, we are validating if the contract write will be successful via simulateContract. If no errors are thrown, then we are all good. After that, we perform a contract write to execute the transaction.

import { account, walletClient, publicClient } from './config'
import { wagmiAbi } from './abi'
 
const { request } = await publicClient.simulateContract({
  address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
  abi: wagmiAbi,
  functionName: 'mint',
  account,
})
const hash = await walletClient.writeContract(request)

Handling Custom Errors

In the example below, we are catching a custom error thrown by the simulateContract. It is important to include the custom error item in the contract abi.

You can access the custom error through the data attribute of the error:

import { BaseError, ContractFunctionRevertedError } from 'viem';
import { account, walletClient, publicClient } from './config'
import { wagmiAbi } from './abi'
 
try {
  await publicClient.simulateContract({
    address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
    abi: wagmiAbi,
    functionName: 'mint',
    account,
  })
} catch (err) {
  if (err instanceof BaseError) {
    const revertError = err.walk(err => err instanceof ContractFunctionRevertedError)
    if (revertError instanceof ContractFunctionRevertedError) {
      const errorName = revertError.data?.errorName ?? ''
      // do something with `errorName`
    }
  }
}

Return Value

The simulation result and write request. Type is inferred.

Parameters

address

The contract address.

const { result } = await publicClient.simulateContract({
  address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2', 
  abi: wagmiAbi,
  functionName: 'mint',
  account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
})

abi

The contract's ABI.

const { result } = await publicClient.simulateContract({
  address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
  abi: wagmiAbi, 
  functionName: 'mint',
  account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
})

functionName

  • Type: string

A function to extract from the ABI.

const { result } = await publicClient.simulateContract({
  address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
  abi: wagmiAbi,
  functionName: 'mint', 
  account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
})

account

  • Type: Account | Address

The Account to simulate the contract method from.

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

const { result } = await publicClient.simulateContract({
  address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
  abi: wagmiAbi,
  functionName: 'mint',
  account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
})

accessList (optional)

The access list.

const { result } = await publicClient.simulateContract({
  address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
  abi: wagmiAbi,
  functionName: 'mint',
  args: [69420],
  accessList: [{ 
    address: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
    storageKeys: ['0x1'],
  }],
  account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
})

args (optional)

  • Type: Inferred from ABI.

Arguments to pass to function call.

const { result } = await publicClient.simulateContract({
  address: '0x1dfe7ca09e99d10835bf73044a23b73fc20623df',
  abi: wagmiAbi,
  functionName: 'balanceOf',
  args: ['0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC'], 
  account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
})

dataSuffix

  • Type: Hex

Data to append to the end of the calldata. Useful for adding a "domain" tag.

const { result } = await publicClient.simulateContract({
  address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
  abi: wagmiAbi,
  functionName: 'mint',
  args: [69420],
  dataSuffix: '0xdeadbeef'
})

gas (optional)

  • Type: bigint

The gas limit for the transaction.

await walletClient.writeContract({
  address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
  abi: wagmiAbi,
  functionName: 'mint',
  args: [69420],
  gas: 69420n, 
})

gasPrice (optional)

  • Type: bigint

The price (in wei) to pay per gas. Only applies to Legacy Transactions.

const { result } = await publicClient.simulateContract({
  address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
  abi: wagmiAbi,
  functionName: 'mint',
  args: [69420],
  account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
  gasPrice: parseGwei('20'), 
})

maxFeePerGas (optional)

  • Type: bigint

Total fee per gas (in wei), inclusive of maxPriorityFeePerGas. Only applies to EIP-1559 Transactions

const { result } = await publicClient.simulateContract({
  address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
  abi: wagmiAbi,
  functionName: 'mint',
  args: [69420],
  account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
  maxFeePerGas: parseGwei('20'),  
})

maxPriorityFeePerGas (optional)

  • Type: bigint

Max priority fee per gas (in wei). Only applies to EIP-1559 Transactions

const { result } = await publicClient.simulateContract({
  address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
  abi: wagmiAbi,
  functionName: 'mint',
  args: [69420],
  account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
  maxFeePerGas: parseGwei('20'),
  maxPriorityFeePerGas: parseGwei('2'), 
})

nonce (optional)

  • Type: number

Unique number identifying this transaction.

const { result } = await publicClient.simulateContract({
  address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
  abi: wagmiAbi,
  functionName: 'mint',
  args: [69420],
  account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
  nonce: 69
})

value (optional)

  • Type: number

Value in wei sent with this transaction.

const { result } = await publicClient.simulateContract({
  address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
  abi: wagmiAbi,
  functionName: 'mint',
  args: [69420],
  account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
  value: parseEther('1') 
})

blockNumber (optional)

  • Type: number

The block number to perform the read against.

const { result } = await publicClient.simulateContract({
  address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
  abi: wagmiAbi,
  functionName: 'mint',
  account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
  blockNumber: 15121123n, 
})

blockTag (optional)

  • Type: 'latest' | 'earliest' | 'pending' | 'safe' | 'finalized'
  • Default: 'latest'

The block tag to perform the read against.

const { result } = await publicClient.simulateContract({
  address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
  abi: wagmiAbi,
  functionName: 'mint',
  account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
  blockTag: 'safe', 
})

Live Example

Check out the usage of simulateContract in the live Writing to Contracts Example below.