Skip to content

Creating a Tevm Node

createTevmNode is the main entry point for spinning up a local Tevm Node instance. With a flexible configuration API, you can customize your node's behavior to fit various development, testing, and production scenarios.

Install Dependencies

First, install the required packages:

npm install tevm
Using Yarn or pnpm?
# Yarn
yarn add tevm
 
# pnpm
pnpm add tevm

Create a Basic Node

Instantiate a node with default configuration:

import { createTevmNode } from 'tevm'
 
// Create the node instance
const node = createTevmNode()
 
// Always wait for the node to be ready before using it
await node.ready()
 
// Your node is now ready to use!

Configure to Your Needs

Tailor the node with powerful configuration options:

import { createTevmNode, http } from 'tevm'
 
const node = createTevmNode({
  // Fork from a live network
  fork: {
    transport: http('https://mainnet.infura.io/v3/YOUR-KEY'),
  },
  // Configure automatic mining
  miningConfig: { type: 'auto' },
  // Set logging verbosity
  loggingLevel: 'debug'
})
 
await node.ready()

Configuration Options

Tevm Node offers extensive configuration options to adapt to different use cases. Here's a complete breakdown:

Fork Configuration

The fork option creates a node that connects to an existing network:

import { createTevmNode, http } from 'tevm'
 
const node = createTevmNode({
  fork: {
    // Use any EIP-1193 compatible provider
    transport: http('https://mainnet.infura.io/v3/YOUR-KEY'),
    // Optional: Fork from a specific block
    blockTag: 17_000_000n,
  },
})
 
await node.ready()

Mining Configuration

Control how and when blocks are produced with various mining modes:

// Auto-mining: Mine a block for every transaction
const node = createTevmNode({
  miningConfig: {
    type: 'auto',
  },
})
 
// Interval-based mining: Mine at regular intervals
const intervalNode = createTevmNode({
  miningConfig: {
    type: 'interval',
    interval: 12_000, // Mine every 12 seconds
  },
})
 
await node.ready()
await intervalNode.ready()

Chain Configuration

Customize the chain parameters or use pre-configured chains:

import { createTevmNode } from 'tevm'
import { Common } from 'tevm/common'
 
// Custom chain configuration
const customNode = createTevmNode({
  common: Common.custom({
    chainId: 1337,
    networkId: 1337,
    // Other chain parameters
  }),
})
 
await customNode.ready()

Or use one of the pre-configured chains:

import { createTevmNode } from 'tevm'
import { mainnet, optimism, arbitrum, base } from 'tevm/common'
 
// Create a node with Optimism chain configuration
const optimismNode = createTevmNode({
  common: optimism,
})
 
await optimismNode.ready()

Want to add your own network? If you need support for a network not included in Tevm, first add it to viem/chains and then open an issue on the Tevm repository to request the network to be added.

Logging Configuration

Configure the internal logger to match your needs:

const node = createTevmNode({
  loggingLevel: 'debug', // 'fatal' | 'error' | 'warn' | 'info' | 'debug' | 'trace'
})
 
// Later use the logger directly
node.logger.debug('Detailed debugging information')
node.logger.info('Informational message')
node.logger.warn('Warning!')
node.logger.error('Error encountered', { details: 'Something went wrong' })
 
await node.ready()

Custom Precompiles

Add your own precompiled contracts to unlock powerful capabilities:

import { definePrecompile, createContract, parseAbi } from 'tevm'
 
const calculatorPrecompile = definePrecompile({
  // Define contract interface
  contract: createContract({
    abi: parseAbi([
      'function add(uint256 a, uint256 b) returns (uint256)',
      'function subtract(uint256 a, uint256 b) returns (uint256)'
    ]),
    address: '0xf2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2'
  }),
  // Implement the precompile logic
  call: async ({ data, gasLimit }) => {
    // Precompile implementation goes here
    console.log('Precompile called with data:', data, 'gas limit:', gasLimit)
    
    return {
      returnValue: new Uint8Array([0x01]), // Example return value
      executionGasUsed: 200n,
    }
  },
})
 
// Register the precompile with the node
const node = createTevmNode({
  customPrecompiles: [calculatorPrecompile.precompile()],
})
 
await node.ready()

Performance Profiling

Enable the built-in profiler for detailed execution metrics:

const node = createTevmNode({
  profiler: true,
})
 
await node.ready()
 
// Run a transaction or call
// ...
 
// Access profiling data
const vm = await node.getVm()
const performanceLogs = vm.evm.getPerformanceLogs()
console.log('Performance data:', performanceLogs)

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
profilerbooleanfalseEnables performance logging
customPrecompilesPrecompile[][]Additional precompiled contracts
allowUnlimitedContractSizebooleanfalseDisables EIP-170 contract size checks

Best Practices

Always await node.ready()

const node = createTevmNode()
await node.ready() // Essential: Ensures node is fully initialized
// Now safe to use the node

Choose the Right Mining Configuration

// For testing: Mine after each transaction
const testNode = createTevmNode({
  miningConfig: { type: 'auto' }
})
 
// For simulation: Mine at intervals to mimic real networks
const simulationNode = createTevmNode({
  miningConfig: { type: 'interval', interval: 12_000 } // 12 seconds like Ethereum
})
 
await testNode.ready()
await simulationNode.ready()

Handle Initialization Errors

try {
  const node = createTevmNode()
  await node.ready()
  console.log('Node successfully initialized')
} catch (error) {
  console.error('Node initialization failed:', error)
  // Implement proper error handling
}

Usage Scenarios

  • Fresh Node: Fast, auto-mining configuration with unlimited contract sizes for rapid local development
  • Forked Node: Realistic forked environment with precise error handling for production simulation
  • Testing Environment: Performance-focused configuration for CI/CD and test automation

Fresh Node

import { createTevmNode } from 'tevm'
 
const freshNode = createTevmNode({
  miningConfig: { type: 'auto' },
  loggingLevel: 'debug',        // See detailed logs during development
  allowUnlimitedContractSize: true, // No contract size limits during development
})
 
await freshNode.ready()
 
// Node is ready for local development
console.log('Fresh node ready!')

Forked Node

import { createTevmNode, http } from 'tevm'
 
const forkedNode = createTevmNode({
  fork: {
    transport: http('https://mainnet.infura.io/v3/YOUR-KEY'),
    blockTag: 'latest',  // Always use the latest block
  },
  miningConfig: { 
    type: 'interval', 
    interval: 12000     // Mine every 12 seconds like Ethereum mainnet
  },
  loggingLevel: 'error', // Only show errors
})
 
await forkedNode.ready()
 
console.log('Forked node ready!')

Testing Node

import { createTevmNode } from 'tevm'
 
const testNode = createTevmNode({
  miningConfig: { type: 'auto' }, // Immediate mining for faster tests
  profiler: true,                 // Enable profiling for performance testing
})
 
await testNode.ready()
 
// Run your tests with profiling enabled
console.log('Testing node with profiling ready!')

Next Steps