Bundler Overview
Key Benefits
The Tevm bundler offers numerous advantages for Ethereum developers:
- Direct Imports: Import Solidity files just like any other TypeScript module
- Type Safety: Full TypeScript type checking for contract methods, arguments, and return values
- IDE Integration: Go-to-definition, auto-completion, and hover documentation
- NatSpec Support: Contract documentation appears in your editor
- Hot Module Reloading: Changes to Solidity files update immediately during development
- Framework Integration: Works with popular bundlers like Vite, Webpack, Next.js, Bun, and more
Available Plugins
Tevm provides plugins for most popular JavaScript bundlers:
Bundler | Plugin Import Path | Repository |
---|---|---|
Vite | tevm/bundler/vite-plugin | @tevm/vite-plugin |
Webpack | tevm/bundler/webpack-plugin | @tevm/webpack-plugin |
Rollup | tevm/bundler/rollup-plugin | @tevm/rollup-plugin |
ESBuild | tevm/bundler/esbuild-plugin | @tevm/esbuild-plugin |
Bun | tevm/bundler/bun-plugin | @tevm/bun-plugin |
Rspack | tevm/bundler/rspack-plugin | @tevm/rspack-plugin |
All plugins share a similar usage pattern and a single configuration interface. For detailed plugin configuration, see the Quickstart Guide.
Prerequisites & Key Points
Optional Bundler
You can compile contracts manually or use npx tevm gen
. The plugins are purely optional if you prefer a different workflow.
TypeScript Integration
For best results, add the Tevm TS plugin to your tsconfig.json. This allows your editor to resolve Solidity imports, provide NatSpec docs on hover, go-to-definition on solidity methods, and more.
.s.sol for Bytecode
By default, Tevm only generates bytecode for Solidity files ending in .s.sol
. Regular .sol
files still compile for ABIs, but omit deployable bytecode. This helps differentiate purely interface-like contracts from ones you intend to deploy or call as scripts.
Tevm Cache
Compiled artifacts and metadata are stored in a .tevm
folder. It is strongly recommended to .gitignore
this directory. The cache directory is ephemeral - you can safely delete it if you encounter stale builds or caching issues.
Foundry/Remappings
If you have a Foundry setup or custom remappings, you can enable them in a tevm.config.json
. For detailed configuration, see the Bundler Configuration section.
Next.js
Next.js can conflict with the TS plugin's type-checking. If you wish to keep type-checking turned on for Next.js, consider the Codegen Approach. Otherwise, you may disable type-checking in your Next config.
Basic Usage
Once configured, you can import Solidity contracts directly:
// Import a contract directly from a .sol file
import { Counter } from './Counter.sol'
import { createMemoryClient } from 'tevm'
// Create a client to interact with the contract
const client = createMemoryClient()
// Deploy the contract
const deployed = await client.deployContract(Counter)
// Call read methods
const count = await deployed.read.count()
// Call write methods
const tx = await deployed.write.increment()
await client.mine({ blocks: 1 })
// Check the updated state
const newCount = await deployed.read.count()
The imported Counter
object is a Tevm Contract instance that provides:
- Type-safe access to all contract methods
- Contract ABI and bytecode
- Deployment helpers
- Read and write method interfaces
- Event filters
Importing Dependencies
You can import contracts from:
- Local
.sol
files in your project - npm packages like OpenZeppelin contracts
- External libraries
// Local import
import { MyToken } from './contracts/MyToken.sol'
// npm package import
import { ERC20 } from '@openzeppelin/contracts/token/ERC20/ERC20.sol'
Integration with Viem and Ethers
Tevm contracts work seamlessly with popular Ethereum libraries:
Viem Example
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
import { MyToken } from './contracts/MyToken.sol'
const client = createPublicClient({
chain: mainnet,
transport: http(),
})
// Read methods
const balance = await client.readContract({
...MyToken.read.balanceOf('0x123...'),
address: '0x456...',
})
// Write methods
const hash = await client.writeContract({
...MyToken.write.transfer('0x789...', 1000n),
address: '0x456...',
})
Ethers Example
import { ethers } from 'ethers'
import { MyToken } from './contracts/MyToken.sol'
const provider = new ethers.BrowserProvider(window.ethereum)
const signer = await provider.getSigner()
// Create contract instance
const tokenContract = new ethers.Contract(
'0x456...',
MyToken.abi,
signer
)
// Call methods
const balance = await tokenContract.balanceOf('0x123...')
const tx = await tokenContract.transfer('0x789...', 1000n)
Bundler Configuration
For complex projects, create a tevm.config.json
file in your project root:
{
"foundryProject": true,
"libs": ["lib", "node_modules"],
"remappings": {
"@openzeppelin/": "node_modules/@openzeppelin/"
},
"debug": false,
"cacheDir": ".tevm",
"jsonAsConst": ["**/*.abi.json"]
}
Configuration Options
Option | Type | Description |
---|---|---|
foundryProject | boolean | string | Enable Foundry integration (true ) or path to foundry.toml |
libs | string[] | Library paths for Solidity imports (used alongside Foundry libs) |
remappings | Record<string, string> | Custom import remappings |
debug | boolean | Output extra debug logs and files in .tevm |
cacheDir | string | Location for compiled artifacts (default: .tevm ) |
jsonAsConst | string | string[] | Glob patterns for JSON files to be typed as const in TS |
Coming Soon Features
Inline Solidity with sol
Tag
For quick prototyping or one-off contracts, you'll soon be able to use the sol
tag to define Solidity code inline:
import { sol } from 'tevm'
// Define contract inline
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;
}
}
`
// Use with client.readContract, writeContract, etc.
CAIP-10 Contract Imports
Tevm will soon support importing contracts based on the CAIP-10 Account ID Specification, which will allow you to import contracts from any chain using a standardized identifier format:
// Import a contract from Ethereum mainnet using a CAIP-10 identifier
import { WETH } from 'caip10:eip155:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'
Further Reading
- Bundler Internals - Learn how the bundler works under the hood
- Methods & Exports - Advanced APIs for custom implementations
- Troubleshooting - Solve common issues with the bundler