Call API
The Call API is one of the most important APIs in Tevm, covering 90% of use cases along with mining. It provides a powerful interface for executing EVM calls with extensive configuration options.
Basic Usage
Tevm offers two API styles for using the Call API:
Client-based API (batteries included)
import { createMemoryClient } from 'tevm'
const client = createMemoryClient()
// Use tevmCall directly on the client object
const result = await client.tevmCall({
from: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // Default account
to: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', // WETH on mainnet
data: '0x' // Empty call
})
Tree-shakable API
import { tevmCall } from 'tevm/actions'
import { createClient, custom } from 'viem'
import { createTevmNode } from 'tevm/node'
import { requestEip1193 } from 'tevm/decorators'
// Create Tevm Node with EIP-1193 support
const node = createTevmNode().extend(requestEip1193())
// Create Viem client
const client = createClient({
transport: custom(node),
})
// Use the tree-shakable action
const result = await tevmCall(client, {
from: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // Default account
to: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', // WETH on mainnet
data: '0x' // Empty call
})
Parameters
The CallParams
type includes:
type CallParams = {
// Required for most calls (except contract deployment)
to?: Address
// Input data for the call
data?: Hex
// Value in wei to send
value?: bigint
// Gas limit for the call
gas?: bigint
// Block tag to execute against
blockTag?: 'latest' | 'pending' | 'earliest' | number
// Whether to create a transaction
createTransaction?: 'on-success' | 'always' | 'never' | boolean
// Whether to skip balance checks
skipBalance?: boolean
// Whether to create an access list
createAccessList?: boolean
// Whether to create a debug trace
createTrace?: boolean
// From address (defaults to first account)
from?: Address
// Gas price settings
maxFeePerGas?: bigint
maxPriorityFeePerGas?: bigint
// State overrides
stateOverrideSet?: StateOverrideSet
// Block overrides
blockOverrideSet?: BlockOverrideSet
// Event handlers for EVM execution
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
The CallResult
includes:
type CallResult = {
// Return data from the call
rawData: Hex
// Gas used by the EVM
executionGasUsed: bigint
// Total gas including intrinsic costs
totalGasSpent?: bigint
// Transaction hash if created
txHash?: Hex
// Logs emitted
logs?: Log[]
// Created contract address
createdAddress?: Address
// Access list if requested
accessList?: Record<Address, Set<Hex>>
// Debug trace if requested
trace?: DebugTraceCallResult
// Any errors that occurred
errors?: TevmCallError[]
}
Examples
1. Simple Contract Call
Using client-based API:
import { createMemoryClient } from 'tevm'
import { encodeFunctionData, decodeFunctionResult, parseAbi } from 'viem'
// Example ERC20 ABI for 'balanceOf'
const abi = parseAbi([
'function balanceOf(address account) view returns (uint256 balance)'
])
const client = createMemoryClient()
const result = await client.tevmCall({
to: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', // WETH
from: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
data: encodeFunctionData({
abi,
functionName: 'balanceOf',
args: ['0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266']
})
})
const balance = decodeFunctionResult({
abi,
functionName: 'balanceOf',
data: result.rawData
})
2. Contract Deployment
Using client-based API:
import { createMemoryClient } from 'tevm'
// Simple contract bytecode (returns 42)
const bytecode = '0x6080604052348015600f57600080fd5b50602a60808190526040516100929190810190830190829052565b604051601f19601f830116810160405280815292829060208401853c80601f830112156100c057600080fd5b505b50505050610047806100d36000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c80632096525514602d575b600080fd5b60336047565b604051603e91906059565b60405180910390f35b602a81565b6000819050919050565b6053816040565b82525050565b6000602082019050606c6000830184604c565b9291505056fea2646970667358221220f1c69e125f1a9f0c5e22a6fb4f9cb134c5b43496922c563e13731844a6e4d12d64736f6c63430008130033'
const client = createMemoryClient()
const result = await client.tevmCall({
from: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
data: bytecode,
createTransaction: true
})
console.log('Contract deployed at:', result.createdAddress)
3. State Override
Using client-based API:
import { createMemoryClient } from 'tevm'
const client = createMemoryClient()
const result = await client.tevmCall({
from: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
to: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', // WETH
data: '0x',
stateOverrideSet: {
['0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266']: {
balance: 4096n, // 0x1000 as bigint
nonce: 2n,
code: '0x',
state: {}
}
}
})
4. Debug Trace
Using client-based API:
import { createMemoryClient } from 'tevm'
const client = createMemoryClient()
const result = await client.tevmCall({
from: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
to: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', // WETH
data: '0x',
createTrace: true
})
// Analyze the execution trace
if (result.trace) {
result.trace.structLogs.forEach(log => {
console.log(log.op, log.stack, log.memory)
})
}
5. EVM Event Handlers
You can attach event handlers to monitor EVM execution in real-time.
Using client-based API:
import { createMemoryClient } from 'tevm'
import { encodeFunctionData } from 'viem'
const client = createMemoryClient()
// Use EVM event handlers to monitor execution
const result = await client.tevmCall({
from: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
to: contractAddress,
data: encodeFunctionData({
abi,
functionName: 'myFunction',
args: [arg1, arg2]
}),
// Monitor each EVM step
onStep: (step, next) => {
console.log(
`Executing ${step.opcode.name} at PC=${step.pc}`,
`Gas left: ${step.gasLeft.toString()}`,
`Stack depth: ${step.stack.length}`
)
// Important: Call next to continue execution
next?.()
},
// Monitor contract creation events
onNewContract: (data, next) => {
console.log(`New contract created at: ${data.address.toString()}`)
next?.()
},
// Monitor messages (calls) before execution
onBeforeMessage: (message, next) => {
console.log(`Call to: ${message.to?.toString()}`,
`Value: ${message.value.toString()}`,
`Gas limit: ${message.gasLimit.toString()}`)
next?.()
},
// Monitor messages (calls) after execution
onAfterMessage: (result, next) => {
console.log(`Call 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