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

Bundler Overview

Key Benefits

  • Direct imports: import .sol files like any TS module.
  • Type safety: full type checking for methods, args, and return values.
  • IDE integration: go-to-definition, auto-completion, hover docs.
  • NatSpec: contract docs appear in your editor.
  • HMR: Solidity changes update during development.
  • Framework support: Vite, Webpack, Next.js, Bun, and more.

Available Plugins

BundlerPlugin Import PathRepository
Vitetevm/bundler/vite-plugin@tevm/vite-plugin
Webpacktevm/bundler/webpack-plugin@tevm/webpack-plugin
Rolluptevm/bundler/rollup-plugin@tevm/rollup-plugin
ESBuildtevm/bundler/esbuild-plugin@tevm/esbuild-plugin
Buntevm/bundler/bun-plugin@tevm/bun-plugin
Rspacktevm/bundler/rspack-plugin@tevm/rspack-plugin

For plugin configuration, see the Quickstart Guide.

Prerequisites & Key Points

  • Optional: use tevm generate contract if you don't want a bundler hook.

    tevm generate contract
    tevm generate contract "ERC20Token"
    tevm generate contract --include "contracts/**/*.sol" --output "types/"
  • TypeScript: add @tevm/ts-plugin to tsconfig for editor support.

  • .s.sol for bytecode: .sol produces ABI only; .s.sol includes deployable bytecode.

  • Cache: artifacts live in .tevm/ — add it to .gitignore. The directory is ephemeral.

  • Foundry/remappings: configure in tevm.config.json (see below).

  • Next.js: type-checker conflicts; use codegen or disable Next typechecking.

Basic Usage

import { Counter } from './Counter.sol'
import { createMemoryClient } from 'tevm'
 
const client = createMemoryClient()
const deployed = await client.deployContract(Counter)
 
const count = await deployed.read.count()
await deployed.write.increment()
await client.mine({ blocks: 1 })
const newCount = await deployed.read.count()

The imported value is a Tevm Contract instance with abi, optional bytecode, deployment helpers, .read / .write methods, and event filters.

Importing Dependencies

import { MyToken } from './contracts/MyToken.sol'
import { ERC20 } from '@openzeppelin/contracts/token/ERC20/ERC20.sol'

Integration with Viem and Ethers

viem
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
import { MyToken } from './contracts/MyToken.sol'
 
const client = createPublicClient({ chain: mainnet, transport: http() })
 
const balance = await client.readContract({
  ...MyToken.read.balanceOf('0x123...'),
  address: '0x456...',
})
 
const hash = await client.writeContract({
  ...MyToken.write.transfer('0x789...', 1000n),
  address: '0x456...',
})

Bundler Configuration

{
  "foundryProject": true,
  "libs": ["lib", "node_modules"],
  "remappings": {
    "@openzeppelin/": "node_modules/@openzeppelin/"
  },
  "debug": false,
  "cacheDir": ".tevm",
  "jsonAsConst": ["**/*.abi.json"]
}
OptionTypeDescription
foundryProjectboolean | stringEnable Foundry (true) or path to foundry.toml
libsstring[]Library paths for Solidity imports
remappingsRecord<string, string>Custom import remappings
debugbooleanExtra debug logs and files in .tevm
cacheDirstringArtifact location (default: .tevm)
jsonAsConststring | string[]Glob patterns for as const JSON imports

Coming Soon Features

Inline Solidity with sol Tag

import { sol } from 'tevm'
 
const { bytecode, abi } = sol`
  pragma solidity ^0.8.19;
 
  contract Counter {
    uint256 private count = 0;
 
    function increment() public {
      count += 1;
    }
 
    function count() public view returns (uint256) {
      return count;
    }
  }
`

Network Imports via Macros

Build-time contract imports from any chain, offering stronger type safety than runtime imports.

// contract-macros.js
import { createMemoryClient, loadContract } from 'tevm'
import { http } from 'viem'
import { SourcifyABILoader, EtherscanABILoader } from 'tevm/whatsabi'
 
const client = createMemoryClient({
  fork: {
    transport: http('https://eth-mainnet.g.alchemy.com/v2/YOUR_API_KEY'),
    blockNumber: 19000000n,
  },
})
 
export async function wethContract() {
  return loadContract(client, {
    address: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
    followProxies: true,
    loaders: [new SourcifyABILoader(), new EtherscanABILoader({ apiKey: 'YOUR_ETHERSCAN_KEY' })],
  })
}
 
// app.js
import { wethContract } from './contract-macros.js' with { type: 'macro' }

Enable macros in tevm.config.json for security:

{
  "macros": true,
  "foundryProject": true,
  "libs": ["lib", "node_modules"]
}

Full documentation: Contract Loader.

Further Reading