Skip to content

simulateCalls

Simulates a set of calls for a block, and optionally provides asset changes. Internally uses the eth_simulateV1 JSON-RPC method.

Usage

example.ts
import { parseEther } from 'viem'
import { client } from './config'
 
const { results } = await client.simulateCalls({
  account: '0x5a0b54d5dc17e482fe8b0bdca5320161b95fb929',
  calls: [
    {
      to: '0xcb98643b8786950F0461f3B0edf99D88F274574D',
      value: parseEther('2'),
    },
    {
      to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
      value: parseEther('1'),
    },
  ],
})
 
console.log(results)
[
{
gasUsed: 21000n,
logs: [],
status: "success",
},
{
gasUsed: 21000n,
logs: [],
status: "success",
},
]

Contract Calls

The calls property also accepts Contract Calls, and can be used via the abi, functionName, and args properties.

example.ts
import { parseAbi, parseEther } from 'viem'
import { client } from './config'
 
const abi = parseAbi([
  'function mint()',
  'function transfer(address, uint256) returns (bool)',
])
 
const { results } = await client.simulateCalls({
  account: '0x5a0b54d5dc17e482fe8b0bdca5320161b95fb929',
  calls: [
    {
      to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
      value: parseEther('1')
    },
    {
      to: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
      abi,
      functionName: 'mint',
    },
    {
      to: '0x95aD61b0a150d79219dCF64E1E6Cc01f0B64C4cE',
      abi,
      functionName: 'transfer',
      args: [
        '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
        100n
      ],
    },
  ],
})
 
console.log(results)
[
{
gasUsed: 21000n,
logs: [],
result: undefined,
status: "success",
},
{
gasUsed: 78394n,
logs: [...],
result: undefined,
status: "success",
},
{
gasUsed: 51859n,
logs: [...],
result: true,
status: "success",
},
]

Asset Changes

Providing the traceAssetChanges parameter (with an account) will return asset balance changes for the calls.

example.ts
import { parseAbi, parseEther } from 'viem'
import { client } from './config'
 
const abi = parseAbi([
  'function mint()',
  'function transfer(address, uint256) returns (bool)',
])
 
const { assetChanges, results } = await client.simulateCalls({
  account: '0x5a0b54d5dc17e482fe8b0bdca5320161b95fb929',
  calls: [
    {
      to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
      value: parseEther('1.5')
    },
    {
      to: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
      abi,
      functionName: 'mint',
    },
    {
      to: '0x95aD61b0a150d79219dCF64E1E6Cc01f0B64C4cE',
      abi,
      functionName: 'transfer',
      args: [
        '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
        100n
      ],
    },
  ],
  traceAssetChanges: true, 
})
 
console.log(assetChanges)
[
{
token: {
address: "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
decimals: 18,
symbol: "ETH",
},
value: {
diff: -1500000000000000000n,
post: 9850000000000000000000n,
pre: 10000000000000000000000n,
},
}
{
token: {
address: "0xfba3912ca04dd458c843e2ee08967fc04f3579c2",
decimals: 1,
symbol: "WAGMI",
},
value: {
diff: 1n,
post: 1n,
pre: 0n,
},
},
{
token: {
address: "0x95ad61b0a150d79219dcf64e1e6cc01f0b64c4ce",
decimals: 18,
symbol: "SHIB",
},
value: {
diff: -1000000000000000000n,
post: 410429569258816445970930282571360n,
pre: 410429569258817445970930282571360n,
},
}
]

Reading Contracts

It is also worth noting that simulateCalls also supports "reading" contracts.

example.ts
import { parseAbi } from 'viem'
import { client } from './config'
 
const abi = parseAbi([
  'function totalSupply() returns (uint256)',
  'function ownerOf(uint256) returns (address)',
])
 
const { results } = await client.simulateCalls({
  calls: [
    {
      to: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
      abi,
      functionName: 'totalSupply',
    },
    {
      to: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
      abi,
      functionName: 'ownerOf',
      args: [69420n],
    },
    {
      to: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
      abi,
      functionName: 'ownerOf',
      args: [13371337n],
    },
  ],
})
 
console.log(results)
[
{
result: 424122n,
status: "success",
},
{
result: "0xc961145a54C96E3aE9bAA048c4F4D6b04C13916b",
status: "success",
},
{
error: [ContractFunctionExecutionError: token has no owner],
status: "failure",
},
]

Return Value

SimulateCallsReturnType

Simulation results.

Parameters

calls

  • Type: Calls

Calls to simulate.

const { results } = await client.simulateCalls({
  account: '0x5a0b54d5dc17e482fe8b0bdca5320161b95fb929',
  calls: [ 
    { 
      to: '0xcb98643b8786950F0461f3B0edf99D88F274574D', 
      value: parseEther('2'), 
    }, 
    { 
      to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', 
      value: parseEther('1'), 
    }, 
  ], 
})

calls.data

  • Type: Hex

Calldata to broadcast (typically a contract function selector with encoded arguments, or contract deployment bytecode).

const { results } = await client.simulateCalls({
  account: '0x5a0b54d5dc17e482fe8b0bdca5320161b95fb929',
  calls: [ 
    { 
      data: '0xdeadbeef', 
      to: '0xcb98643b8786950F0461f3B0edf99D88F274574D', 
      value: parseEther('2'), 
    },  
  ], 
})

calls.to

  • Type: Address

The recipient address.

const { results } = await client.simulateCalls({
  account: '0x5a0b54d5dc17e482fe8b0bdca5320161b95fb929',
  calls: [ 
    { 
      to: '0xcb98643b8786950F0461f3B0edf99D88F274574D', 
      value: parseEther('2'),
    },  
  ], 
})

calls.value

  • Type: Address

Value to send with the call.

const { results } = await client.simulateCalls({
  account: '0x5a0b54d5dc17e482fe8b0bdca5320161b95fb929',
  calls: [ 
    { 
      to: '0xcb98643b8786950F0461f3B0edf99D88F274574D',
      value: parseEther('2'), 
    },  
  ], 
})

account (optional)

  • Type: Account | Address

The account to simulate the calls from.

const { results } = await client.simulateCalls({
  account: '0x5a0b54d5dc17e482fe8b0bdca5320161b95fb929', 
  calls: [ 
    { 
      to: '0xcb98643b8786950F0461f3B0edf99D88F274574D',
      value: parseEther('2'),
    },  
  ], 
})

blockNumber (optional)

  • Type: bigint

The block number to simulate the calls at.

const { results } = await client.simulateCalls({
  blockNumber: 17030000n, 
  calls: [ 
    { 
      to: '0xcb98643b8786950F0461f3B0edf99D88F274574D',
      value: parseEther('2'),
    },  
  ], 
})

blockTag (optional)

  • Type: BlockTag

The block tag to simulate the calls at.

const { results } = await client.simulateCalls({
  blockTag: 'pending', 
  calls: [ 
    { 
      to: '0xcb98643b8786950F0461f3B0edf99D88F274574D',
      value: parseEther('2'),
    },  
  ], 
})

stateOverrides (optional)

  • Type: StateOverride

The state overrides to simulate the calls with.

const { results } = await client.simulateCalls({
  account: '0x5a0b54d5dc17e482fe8b0bdca5320161b95fb929',
  calls: [ 
    { 
      to: '0xcb98643b8786950F0461f3B0edf99D88F274574D',
      value: parseEther('2'),
    },  
  ], 
  stateOverrides: [{ 
    address: '0x5a0b54d5dc17e482fe8b0bdca5320161b95fb929', 
    balance: parseEther('10000'), 
  }], 
})

traceAssetChanges (optional)

  • Type: boolean

Whether to trace asset changes.

const { results } = await client.simulateCalls({
  account: '0x5a0b54d5dc17e482fe8b0bdca5320161b95fb929',
  calls: [ 
    { 
      to: '0xcb98643b8786950F0461f3B0edf99D88F274574D',
      value: parseEther('2'),
    },  
  ], 
  traceAssetChanges: true, 
})

traceTransfers (optional)

  • Type: boolean

Whether to trace transfers.

const { results } = await client.simulateCalls({
  account: '0x5a0b54d5dc17e482fe8b0bdca5320161b95fb929',
  calls: [ 
    { 
      to: '0xcb98643b8786950F0461f3B0edf99D88F274574D',
      value: parseEther('2'),
    },  
  ], 
  traceTransfers: true, 
})

validation (optional)

  • Type: boolean

Whether to enable validation mode.

const { results } = await client.simulateCalls({
  account: '0x5a0b54d5dc17e482fe8b0bdca5320161b95fb929',
  calls: [ 
    { 
      to: '0xcb98643b8786950F0461f3B0edf99D88F274574D',
      value: parseEther('2'),
    },  
  ], 
  validation: true, 
})