Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

Call API

The Call API covers ~90% of use cases (with mining) and provides an EVM call interface with extensive configuration.

Basic Usage

Two API styles:

Client-based API

import { createMemoryClient } from 'tevm'
 
const client = createMemoryClient()
 
const result = await client.tevmCall({
  from: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
  to: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', // WETH
  data: '0x'
})

Tree-shakable API

import { tevmCall } from 'tevm/actions'
import { createTevmTransport } from 'tevm/memory-client'
import { createTevmNode } from 'tevm/node'
import { requestEip1193 } from 'tevm/decorators'
 
const client = createClient({ transport: createTevmTransport() })
 
const result = await tevmCall(client, {
  from: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
  to: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', // WETH
  data: '0x'
})

Parameters

type CallParams = {
  to?: Address                  // required except contract deployment
  data?: Hex
  value?: bigint                // wei
  gas?: bigint
  blockTag?: 'latest' | 'pending' | 'earliest' | number
  createTransaction?: 'on-success' | 'always' | 'never' | boolean  // DEPRECATED
  addToMempool?: 'on-success' | 'always' | 'never' | boolean       // requires mining
  addToBlockchain?: 'on-success' | 'always' | 'never' | boolean    // auto-mines
  skipBalance?: boolean
  createAccessList?: boolean
  createTrace?: boolean
  from?: Address                // defaults to first account
  maxFeePerGas?: bigint
  maxPriorityFeePerGas?: bigint
  stateOverrideSet?: StateOverrideSet
  blockOverrideSet?: BlockOverrideSet
  onStep?: (data: InterpreterStep, next?: () => void) => void
  onNewContract?: (data: NewContractEvent, next?: () => void) => void
  onBeforeMessage?: (data: Message, next?: () => void) => void
  onAfterMessage?: (data: EVMResult, next?: () => void) => void
}

Return Type

type CallResult = {
  rawData: Hex                  // return data
  executionGasUsed: bigint
  totalGasSpent?: bigint        // includes intrinsic costs
  txHash?: Hex
  logs?: Log[]
  createdAddress?: Address
  accessList?: Record<Address, Set<Hex>>
  trace?: TraceResult
  errors?: TevmCallError[]
}

Examples

Simple Contract Call

import { createMemoryClient, PREFUNDED_ACCOUNTS } from 'tevm'
import { ERC20 } from 'tevm/contract'
import { encodeFunctionData, decodeFunctionResult, parseAbi } from 'viem'
 
const abi = parseAbi(['function balanceOf(address account) view returns (uint256 balance)'])
 
const client = createMemoryClient()
 
const result = await client.tevmCall({
  to: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', // WETH
  from: PREFUNDED_ACCOUNTS[0].address,
  deployedBytecode: ERC20.deployedBytecode,
  data: encodeFunctionData({
    abi,
    functionName: 'balanceOf',
    args: [PREFUNDED_ACCOUNTS[0].address]
  })
})
 
const balance = decodeFunctionResult({ abi, functionName: 'balanceOf', data: result.rawData })

Contract Deployment

import { createMemoryClient, PREFUNDED_ACCOUNTS } from 'tevm'
import { SimpleContract } from 'tevm/contract'
import { encodeDeployData } from 'viem'
 
const client = createMemoryClient()
 
const result = await client.tevmCall({
  from: PREFUNDED_ACCOUNTS[0].address,
  data: encodeDeployData(SimpleContract.deploy(2n)),
  addToBlockchain: true // auto-mines
})
 
console.log('Deployed at:', result.createdAddress)

State Override

import { createMemoryClient, PREFUNDED_ACCOUNTS } from 'tevm'
 
const client = createMemoryClient()
 
const result = await client.tevmCall({
  from: PREFUNDED_ACCOUNTS[0].address,
  to: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2',
  data: '0x',
  stateOverrideSet: {
    [PREFUNDED_ACCOUNTS[0].address]: {
      balance: 4096n,
      nonce: 2n,
      state: {}
    }
  }
})

Debug Trace

import { createMemoryClient } from 'tevm'
 
const client = createMemoryClient()
 
const result = await client.tevmCall({
  from: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
  to: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2',
  data: '0x',
  createTrace: true
})
 
if (result.trace) {
  result.trace.structLogs.forEach(log => {
    console.log(log.op, log.stack, log.memory)
  })
}

EVM Event Handlers

Monitor execution in real-time:

import { createMemoryClient } from 'tevm'
import { encodeFunctionData } from 'viem'
 
const client = createMemoryClient()
 
const result = await client.tevmCall({
  from: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
  to: contractAddress,
  data: encodeFunctionData({ abi, functionName: 'myFunction', args: [arg1, arg2] }),
  onStep: (step, next) => {
    console.log(
      `${step.opcode.name} at PC=${step.pc}`,
      `Gas: ${step.gasLeft.toString()}`,
      `Stack depth: ${step.stack.length}`
    )
    next?.()
  },
  onNewContract: (data, next) => {
    console.log(`New contract: ${data.address.toString()}`)
    next?.()
  },
  onBeforeMessage: (message, next) => {
    console.log(`Call to: ${message.to?.toString()}`,
                `Value: ${message.value.toString()}`,
                `Gas limit: ${message.gasLimit.toString()}`)
    next?.()
  },
  onAfterMessage: (result, next) => {
    console.log(`Result: ${result.execResult.returnValue.toString('hex')}`,
                `Gas used: ${result.execResult.executionGasUsed.toString()}`)
    if (result.execResult.exceptionError) {
      console.error(`Error: ${result.execResult.exceptionError.error}`)
    }
    next?.()
  }
})

Higher Level APIs

While tevmCall