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

Creating a MemoryClient

createMemoryClient bootstraps a complete Ethereum execution environment in JavaScript.

Basic usage

import { createMemoryClient } from "tevm";
 
const client = createMemoryClient();
 
// Optional: wait for ready (useful for profiling/debugging)
await client.ready();

With configuration

import { createMemoryClient, http } from "tevm";
 
const rpcUrl = process.env.MAINNET_RPC_URL;
if (!rpcUrl) {
  throw new Error("MAINNET_RPC_URL is required for fork mode");
}
 
const client = createMemoryClient({
  fork: { transport: http(rpcUrl)({}) },
  miningConfig: { type: "auto" },
  loggingLevel: "debug",
});
 
await client.ready();

Configuration Options

Fork Configuration

import { createMemoryClient, http } from "tevm";
 
const rpcUrl = process.env.MAINNET_RPC_URL;
if (!rpcUrl) {
  throw new Error("MAINNET_RPC_URL is required for fork mode");
}
 
const node = createMemoryClient({
  fork: {
    transport: http(rpcUrl)({}),
    blockTag: 17_000_000n, // optional
  },
});
await node.ready();

Mining Configuration

// Auto: mine after each tx
const node = createMemoryClient({ miningConfig: { type: "auto" } });
 
// Interval: mine every N ms
const intervalNode = createMemoryClient({
  miningConfig: { type: "interval", interval: 12_000 },
});

Chain Configuration

import { createMemoryClient } from "tevm";
import { Common } from "tevm/common";
 
const customNode = createMemoryClient({
  common: Common.custom({ chainId: 1337, networkId: 1337 }),
});

Or use a preset:

import { createMemoryClient } from "tevm";
import { mainnet, optimism, arbitrum, base } from "tevm/common";
 
const optimismNode = createMemoryClient({ common: optimism });

Want to add your own network? Add it to viem/chains first, then open an issue on the Tevm repo to request inclusion.

Logging Configuration

const node = createMemoryClient({
  loggingLevel: "debug", // 'fatal' | 'error' | 'warn' | 'info' | 'debug' | 'trace'
});
 
node.logger.debug("Detailed debugging information");
node.logger.info("Informational message");
node.logger.warn("Warning!");
node.logger.error("Error encountered", { details: "Something went wrong" });

Custom Precompiles

import { definePrecompile, createContract, parseAbi } from "tevm";
 
const calculatorPrecompile = definePrecompile({
  contract: createContract({
    abi: parseAbi([
      "function add(uint256 a, uint256 b) returns (uint256)",
      "function subtract(uint256 a, uint256 b) returns (uint256)",
    ]),
    address: "0xf2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2",
  }),
  call: async ({ data, gasLimit }) => {
    return {
      returnValue: new Uint8Array([0x01]),
      executionGasUsed: 200n,
    };
  },
});
 
const node = createMemoryClient({
  customPrecompiles: [calculatorPrecompile.precompile()],
});

Performance Profiling

const node = createMemoryClient({ profiler: true });
await node.ready();
 
const vm = await node.getVm();
const performanceLogs = vm.evm.getPerformanceLogs();

Complete Configuration Reference

PropertyTypeDefaultDescription
fork{ transport: EIP1193RequestFn; blockTag?: BlockTag; }-Enables forking from a live network or another Tevm instance
commonCommontevmDevnetChain configuration object
loggingLevel"fatal" | "error" | "warn" | "info" | "debug" | "trace""info"Logging verbosity level
miningConfig{ type: 'auto' } | { type: 'interval', interval: number }{ type: 'auto' }Block mining behavior
customPrecompilesPrecompile[][]Additional precompiled contracts
allowUnlimitedContractSizebooleanfalseDisables EIP-170 contract size checks

Best Practices

Always pass a common when forking

  • Faster init (no chainId fetch).
  • Correct hardfork/EIP behavior per chain.

Without one, tevmDefault is used.

import { createMemoryClient, http } from "tevm";
import { optimism } from "tevm/common";
 
const client = createMemoryClient({
  common: optimism,
  fork: { transport: http() },
});
 
// op-stack-aware: enables l1DataFee calculation
const { l1DataFee } = await client.call({ data });

Choose the right mining config

Default is manual mining (recommended). auto mines on each tx; interval mines every N ms; gas mines when a gas threshold is hit.

const testNode = createMemoryClient({ miningConfig: { type: "auto" } });
const simulationNode = createMemoryClient({
  miningConfig: { type: "interval", interval: 12_000 },
});

Use debug logging when stuck

Tevm produces many debug logs — pipe them through an LLM to triage.

const client = createMemoryClient({ loggingLevel: "debug" });

Call client.ready() when profiling

Otherwise the first action absorbs init time. Tevm init is fast (no sync).

Next Steps

Runtime Model · Node Interface · Forking · State · Custom Precompiles