Skip to content

Getting Started with Viem

This guide will help you integrate Tevm with viem, the modern TypeScript interface for Ethereum. By the end, you'll have a working setup with Tevm Node and understand how to leverage viem's actions with Tevm.

Installation

Install Dependencies

First, install Tevm along with viem as a peer dependency:

npm
npm install tevm viem@latest

Create Your Client

For the quickest start, create a memory client:

import { createMemoryClient } from "tevm";
 
const client = createMemoryClient();

Or, to fork from an existing chain:

import { createMemoryClient } from "tevm";
import { optimism } from "tevm/chains";
import { http } from "viem";
 
const client = createMemoryClient({
  fork: {
    transport: http("https://mainnet.optimism.io"),
    common: optimism,
  },
});
 
// Wait for the node to be ready before using it
await client.tevmReady();

You're Ready!

Start using your client with familiar viem actions:

// Get the current block number
const blockNumber = await client.getBlockNumber();
console.log(`Current block: ${blockNumber}`);

Complete Example

The following example demonstrates the key capabilities of Tevm with viem:

Forking Example
import { createMemoryClient, http } from "tevm"; 
import { optimism } from "tevm/common"; 
import { parseAbi, parseEther } from "viem"; 
 
// 1. Create a memory client forked from Optimism mainnet
const client = createMemoryClient({
  fork: {
    transport: http("https://mainnet.optimism.io"), 
    common: optimism, 
  }, 
}); 
 
// Wait for the node to be ready
await client.tevmReady();
 
// 2. Get current block number (from the fork point)
const blockNumber = await client.getBlockNumber();
console.log(`Current block number: ${blockNumber}`);
 
// Setup addresses and contract interfaces
const account = `0x${"baD60A7".padStart(40, "0")}` as const;
const greeterContractAddress = "0x10ed0b176048c34d69ffc0712de06CbE95730748";
 
// Define contract interfaces with parseAbi
const greeterAbi = parseAbi([
  "function greet() view returns (string)", 
  "function setGreeting(string memory _greeting) public", 
]); 
 
// 3. Modify blockchain state with test actions
// Fund our test account with 1 ETH
await client.setBalance({
  address: account,
  value: parseEther("1"),
});
 
// Read the current greeting using viem's readContract
const currentGreeting = await client.readContract({
  address: greeterContractAddress,
  abi: greeterAbi,
  functionName: "greet",
});
console.log(`Current greeting: ${currentGreeting}`);
 
// Update the greeting with writeContract
const txHash = await client.writeContract({

  account,
  address: greeterContractAddress,
  abi: greeterAbi,
  functionName: "setGreeting",
  args: ["Hello from Tevm!"],
  chain: optimism,
});
console.log(`Transaction sent: ${txHash}`);
 
// 4. Mine a new block to include our transaction
await client.mine({ blocks: 1 }); 
 
// Verify the greeting was updated
const updatedGreeting = await client.readContract({
  address: greeterContractAddress,
  abi: greeterAbi,
  functionName: "greet",
});
console.log(`Updated greeting: ${updatedGreeting}`);
Code Walkthrough

1. Imports & Client Creation

import { createMemoryClient, http } from "tevm";
import { optimism } from "tevm/common";
import { parseAbi, parseEther } from "viem";
 
const client = createMemoryClient({
  fork: {
    transport: http("https://mainnet.optimism.io"),
    common: optimism,
  },
});
 
await client.tevmReady();
  • We create a client that forks from Optimism mainnet
  • This gives us a local sandbox with all of mainnet's state
  • client.tevmReady() ensures the fork is complete before proceeding

2. Contract Interaction

// Define the contract interface
const greeterAbi = parseAbi([
  "function greet() view returns (string)",
  "function setGreeting(string memory _greeting) public",
]);
 
// Read from contract
const currentGreeting = await client.readContract({
  address: greeterContractAddress,
  abi: greeterAbi,
  functionName: "greet",
});
 
// Write to contract
const txHash = await client.writeContract({
  account,
  address: greeterContractAddress,
  abi: greeterAbi,
  functionName: "setGreeting",
  args: ["Hello from Tevm!"],
  chain: optimism,
});
  • The API matches viem exactly - anyone familiar with viem can use this immediately
  • Write operations return a transaction hash just like on a real network

3. Mining Control

// Mine a block to include our transaction
await client.mine({ blocks: 1 });
  • Unlike real networks, you control exactly when blocks are mined
  • This gives you complete determinism for testing and development

Key Viem-Compatible Features

Tevm's viem client implements the full viem API, maintaining compatibility while adding powerful features:

Standard viem API
// These standard viem actions work exactly as expected
await client.getBalance({ address: '0x...' })
await client.getBlockNumber()
await client.readContract({ ... })
await client.writeContract({ ... })
await client.estimateGas({ ... })
await client.sendTransaction({ ... })
// And all other viem actions

Tree-Shakeable API

For production applications, especially in browser environments, you may want to use Tevm's tree-shakeable API to minimize bundle size:

import { createClient, http } from "viem";
import { createTevmTransport } from "tevm/transport"; 
import { tevmCall, tevmDumpState } from "tevm/actions"; 
 
// Create a standard viem client with Tevm transport
const client = createClient({
  transport: createTevmTransport({

    fork: {

      transport: http("https://mainnet.optimism.io"), 
    }, 
  }), 
});
 
// Import only the actions you need
await tevmDumpState(client);

EVM Execution Hooks

One of Tevm's most powerful features is the ability to hook directly into EVM execution:

await client.tevmContract({
  address: greeterContractAddress,
  abi: greeterAbi,
  functionName: "setGreeting",
  args: ["Hello!"],
 
  // onStep is called for each EVM operation 
  onStep: (stepInfo, next) => {

    console.log(`Executing: ${stepInfo.opcode.name} at PC=${stepInfo.pc}`); 
    console.log(`Stack: ${stepInfo.stack.map((val) => val.toString())}`); 
    console.log(`Memory: ${stepInfo.memory.toString("hex")}`); 
 
    // You can also modify EVM state here if needed 
 
    // Call next() to continue execution 
    next?.(); 
  }, 
 
  // You can also access the detailed result after execution
  onResult: (result) => {
    console.log(`Gas used: ${result.executionGasUsed}`);
    console.log(`Return value: 0x${result.returnValue?.toString("hex")}`);
  },
});

This enables advanced use cases like:

  • Visual Debuggers: Create step-by-step transaction debuggers
  • Educational Tools: Explain EVM execution for learning purposes
  • Custom Instrumentation: Profile and analyze contract execution
  • Intercepting Execution: Modify execution behavior for testing

Tevm-Specific Actions

Tevm extends viem with powerful specialized actions, all prefixed with tevm. These actions provide direct access to Tevm's enhanced Ethereum Virtual Machine capabilities, giving you unprecedented control and visibility into blockchain execution.

The Power of tevmContract

Among all Tevm actions, tevmContract stands out as the most versatile and powerful. It can do almost anything with the Tevm EVM, combining the simplicity of high-level contract interactions with the depth of low-level EVM control:

  • Complete EVM Access: Hook into any phase of EVM execution at the opcode level
  • Rich Result Data: Get detailed execution results beyond just the return value
  • Execution Visibility: Capture traces, access lists, gas usage, and more
  • Flexible Contract Interface: Work with contracts using address+ABI or directly with bytecode
  • Layer 2 Awareness: Get L1 fee calculations and gas usage for L2 chains

When you need maximum control and insight into contract execution, tevmContract is your go-to action. It seamlessly handles everything from simple function calls to complex debugging scenarios.

Complete Action Reference

Here's the full list of Tevm-specific actions:

ActionDescriptionUse Case
tevmCallLow-level EVM call with execution hooksDeep inspection of contract execution
tevmContractEnhanced contract interaction with EVM hooksDetailed debugging of contract calls
tevmDeployDeploy with execution hooksUnderstanding deployment execution flow
tevmMineControl block miningPrecise transaction inclusion control
tevmSetAccountModify account stateTest different account scenarios
tevmGetAccountRead detailed account stateInspect nonce, code, storage
tevmDumpStateExport full EVM stateState persistence and analysis
tevmLoadStateImport saved EVM stateRestore a specific state for testing
tevmReadyWait for fork to initializeEnsure node is ready before use
tevmEnableTracingEnable detailed execution tracingCapture full execution traces
tevmResetReset node to initial stateStart fresh for new test scenarios

Next Steps

Now that you're familiar with using Tevm with viem, you can:

Explore More Tevm Features

Dive deeper into Tevm's powerful capabilities:

Check Out Examples

See how Tevm solves real-world problems:

Advanced API Usage

Master the Tevm API for more sophisticated applications:

← Back to Overview

Ethers Integration →