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

Managing State

Tevm exposes state management via two layers: a low-level StateManager and a high-level viem-style client API.

State Management Approaches

Raw API
import { createTevmNode } from 'tevm'
import { createAddress } from 'tevm/address'
import { createAccount } from 'tevm/utils'
 
const node = createTevmNode()
const vm = await node.getVm()
const stateManager = vm.stateManager
 
// Read account state
const address = createAddress('0x1234567890123456789012345678901234567890')
const account = await stateManager.getAccount(address)
if (account) {
  console.log({
    balance: account.balance,
    nonce: account.nonce,
    codeHash: account.codeHash,
    storageRoot: account.storageRoot
  })
}
 
// Create or update an account
await stateManager.putAccount(
  address,
  createAccount({
    nonce: 0n,
    balance: 10_000_000n
  })
)
 
// Delete an account
await stateManager.deleteAccount(address)

Contract State Management

  • Deploy bytecode
  • Read deployed code
  • Read/write storage slots
  • Clear storage or delete contracts
Raw API
import { createAddress } from 'tevm/address'
import { hexToBytes } from 'tevm/utils'
 
const address = createAddress('0x1234567890123456789012345678901234567890')
 
// Deploy contract code
await stateManager.putCode(address, new Uint8Array([1, 2, 3]))
 
// Read contract code
const code = await stateManager.getCode(address)
 
// Read storage slot
const slot = hexToBytes('0x0000000000000000000000000000000000000000000000000000000000000000')
const value = await stateManager.getStorage(address, slot)
 
// Write storage
const key = hexToBytes('0x0000000000000000000000000000000000000000000000000000000000000000')
const newValue = hexToBytes('0x0000000000000000000000000000000000000000000000000000000000000001')
await stateManager.putStorage(address, key, newValue)
 
// Clear all storage
await stateManager.clearStorage(address)

Framework Integration

You can combine viem/ethers with raw state access.

Viem
import { createMemoryClient } from 'tevm'
 
const client = createMemoryClient()
 
await client.setBalance({
  address: '0x1234567890123456789012345678901234567890',
  value: 1000000000000000000n
})
 
// Drop down to raw state manager
const vm = await client.transport.tevm.getVm()
const stateManager = vm.stateManager
 
await stateManager.checkpoint()
try {
  await stateManager.putStorage(address, key, value)
  await stateManager.commit()
} catch (error) {
  await stateManager.revert()
}

Advanced Features

State Checkpoints

Atomic changes that can be committed or reverted (transaction-like semantics):

const stateManager = (await node.getVm()).stateManager
 
await stateManager.checkpoint()
try {
  await stateManager.putAccount(address, account)
  await stateManager.putStorage(address, key, value)
  await stateManager.commit()
} catch (error) {
  await stateManager.revert()
  console.error('State changes reverted:', error)
}

State Persistence

Dump and restore canonical state to any storage backend (localStorage, DB, etc.):

const state = await stateManager.dumpCanonicalGenesis()
localStorage.setItem('tevmState', JSON.stringify(state))
 
const savedState = JSON.parse(localStorage.getItem('tevmState'))
await stateManager.generateCanonicalGenesis(savedState)

Fork Mode

Forked nodes lazy-load and cache state from a remote provider:

import { createTevmNode, http } from 'tevm'
import { createAddress } from 'tevm/address'
 
const rpcUrl = process.env.MAINNET_RPC_URL
if (!rpcUrl) {
  throw new Error('MAINNET_RPC_URL is required for fork mode')
}
 
const node = createTevmNode({
  fork: { transport: http(rpcUrl)({}) }
})
 
const stateManager = (await node.getVm()).stateManager
const address = createAddress('0x1234567890123456789012345678901234567890')
 
// First access fetches from remote
const account = await stateManager.getAccount(address)
// Subsequent access uses cache
const cachedAccount = await stateManager.getAccount(address)

Best Practices

  • Handle errors from state operations.
  • Use deepCopy for isolated test scenarios.
  • Group related changes with checkpoints.
Error Handling
import { createAddress } from 'tevm/address'
 
const address = createAddress('0x1234567890123456789012345678901234567890')
 
try {
  const account = await stateManager.getAccount(address)
  if (!account) {
    console.log('Account does not exist yet')
  } else {
    console.log('Balance:', account.balance)
  }
} catch (error) {
  console.error('State operation failed:', error)
}

Related Resources

Runtime Model and ZEVM · State Manager API · Account Management · Contract Storage · Forking Guide