Why Run An Ethereum Node in JavaScript?
You know what would make solving all these problems trivially easy? If we just were able to use Foundry in the browser
This is what Fucory thought the day he started building Tevm. Fucory created Tevm to solve all UX and Devx issues blocking the delivery of great blockchain apps. The original idea was to put the foundry API in the browser and the library evolved from there. Because of Tevm's wide ambitious scope Tevm's use case is simply TypeScript+EVM. If you are building on the EVM and you are using TypeScript Tevm will help you. And here is why.
We believe every TypeScript user of the EVM who installs Viem will also install Tevm alongside it in the future
๐ Enhanced Performance
Execute transactions locally with near-zero latency for gas estimation, transaction simulation, and debugging.
๐ป Browser Compatibility
Enable sophisticated dApp features like offline capabilities, optimistic UI updates, and real-time simulations.
๐ Debug Superpowers
Step through EVM execution opcode by opcode to understand exactly what's happening in your smart contracts.
๐ ๏ธ Familiar Developer Experience
Works seamlessly with the libraries you already know - viem, ethers, or any EIP-1193 compatible tool.
Performance & Efficiency
โก An optimized fork mode
Tevm is benchmarked to perform better than even Anvil at executing calls in forked
mode. This is possible via more efficient storage slot retrieval.
โก Zero Network Latency
Running the EVM locally eliminates round-trip delays to remote nodes, enabling near-instantaneous transaction simulations and gas estimations.
Local-first gas estimation
Imagine not having to show a user a loading spinner when estimating gas while saving on RPC credits.
๐ Powerful JS interop
Simulate multiple transactions plugging directly into the evm with JS or even writing custom contracts in JS.
Optimistic updates
Oftentimes you want to show the user what the state of their account is expected to be. Possibly we want to show them the expected state changes from their transaction or series of transactions before they submit. Or maybe we are trying to build snappy UI so we want to show them the updated state right away with a pending icon. Tevm makes implementing optimistic state simple.
// create a client in rebase mode so it updates optimistic state as new blocks come in
const client = createMemoryClient({
fork: {
transport: http("https://mainnet.optimism.io"),
rebase: true,
},
common: optimism,
});
// When we send a transaction to the network send it to Tevm too
// We do not mine the transaction as we want it to just be in our mempool
const txHash = await client.sendRawTransaction(tx);
client.waitForTransactionReceipt({ hash: txHash }).then(() => {
// remove the tx from optimistic state after it is included in chain
const mempool = await client.transport.tevm.getTxPool();
await mempool.removeTxByHash(txHash);
});
// continue to query the latest state by default
await client.getBalance({ address, blockTag: "latest" });
// or query optimistic state with 'pending' block tag
await client.getBalance({ address, blockTag: "pending" });
Real-World Performance Benefits
The estimate_gas
example is the easiest example to illustrate this.
const gasEstimate0 = await client.estimateGas({ ... }) // ~200ms as it fetches state (unless you prewarmed the cache)
const gasEstimate0 = await client.estimateGas({ ... }) // ~Instant on future estimations with cache saved
const gasEstimate0 = await client.estimateGas({ ... }) // ~Instant on future estimations with cache saved
Note: because Tevm can plug directly into wagmi this works as well via useGasEstimate
Enhanced User Experiences
JavaScript-based EVM execution enables entirely new categories of dApp features:
Maximally hackable
Tevm gives you complete control including it's deep internals in a way no other node does. Almost all use cases can be supported.
โก Optimistic UI
Show users the likely outcome of transactions before they're mined on-chain.
๐ก๏ธ Reliable
Tevm has near 100% test coverage and a history of fixing most reported bugs in under 24 hours.
๐งฎ Transaction Simulation
Simulate complex interactions and preview results before sending transactions.
๐ Enhanced Privacy
Process sensitive data locally without sending it to external services.
Top Tier Devx
Use the tools you already know
Tevm users report the library having great devx. A lot of this is owed to it's abilility to plug directly into the tools you are already using like wagmi
, viem
, and ethers
.
Interop with contracts effortlessly
We cannot talk about developer experience in Tevm without bringing up the Tevm Bundler
.
The Tevm Bundler is an optional addon to Tevm that makes TypeScript aware of how to process and compile Solidity. It is a tool in the same category as the Wagmi CLI
or Typechain
but even more powerful and ergonomic.
The devx using the bundler is optimized in following ways:
- Natspec on hover
- Typesafe contract
- TRPC like experience. You will see red underlines before you even save a solidity file
- No need to set up external build tools. Plugs directly into your existing js pipeline
- Supports reading foundry config for remappings and lib
Import solidity directly
The Tevm Bundler doesn't require compiling your contracts as it has a compiler built in. You can import solidity directly.
import { MyContract } from "./MyContract.sol";
console.log(MyContract.abi);
You can also import from node_modules or foundry projects. Tevm supports remappings, lib, and other advanced options. Unlike Foundry Tevm supports node_module resolution by default.
Use contracts via address
If you know your contract address and it's already deployed you don't need to manually specify anything. You can simply reference it by address and Tevm will pull the ABI at build time. This even works for unverified contracts.
// create a macro file for your contracts
import { client } from "./clients.js";
export const MyContract = await client.whatsabi(`0x...`);
// import your macro using tevm and Tevm will fetch your contracts at buildtime
import {MyContract} from './MyContract.js' as {type: 'tevm'}
Low level control of the EVM
Most tools like anvil
run in a seperate process and you communicate over HTTP. Tevm runs in memory and gives you access directly to the node. This allows for powerful programmability not possible with any other tool.
Run callbacks on every EVM step ๐ฌ
Step through EVM execution opcode by opcode, inspect memory and stack, and see exactly what happens in your contracts.
// Listen to every EVM instruction
vm.evm.events.on("step", (data, next) => {
console.log(
`${data.pc.toString().padStart(5)}:`,
`${data.opcode.name.padEnd(10)}`,
`gas: ${data.gasLeft.toString().padStart(8)}`,
`stack: ${data.stack.join(", ")}`,
);
next();
});
You can even modify what the EVM is doing as it executes if you choose to.
Mock EVM contracts with JavaScript contracts
Tevm offers the advanced ability to write a contract in JavaScript which can be powerful in advanced use cases.
Precompiles are similar to foundry cheat codes but rather than a standard library of cheat codes Tevm lets you write arbitrary JavaScript to do whatever you need to do.
It works very nicely with the Tevm Bundler
import {
defineCall,
definePrecompile,
createContract,
createMemoryClient,
} from "tevm";
import { readFile } from "fs/promises";
const contract = createContract({
address: `0x${"1234".repeat(10)}`,
humanReadableAbi: ["function readFile(string fileName) returns string"],
});
const { precompile } = definePrecompile({
contract,
call: defineCall(contract.abi, {
readFile: ({ args }) => {
return {
data: await readFile(args.fileName, "utf8"),
gasUsed: 0n,
};
},
}),
});
// then add your precompile to the evm
const memoryClient = createMemoryClient({
precompiles: [precompile()],
});
Deterministic Testing ๐งช
While tevm is primarily built for applicaiton development it just so happens to be great at testing too. Create fully reproducible environments for testing with complete control over blockchain state, time, and mining.
Solidity Imports
Tevm Bundler (optional feature) creates the best devx for working with solidity files in TypeScript
// Import solidity files directly into TS files
import { MyContract } from "./MyContract.sol";
JavaScript Ecosystem Integration
๐ค TypeScript
Type-safe contract interactions with full IntelliSense support
โ๏ธ UI Frameworks
React, Vue, Svelte and other frontend libraries
๐๏ธ Build Tools
Vite, Webpack, ESBuild and other bundlers
๐งช Testing
Vitest support via Vite
๐ Runtimes
Node.js, browsers, Electron, serverless functions
๐ฆ NPM Ecosystem
Access to millions of packages and libraries in the npm registry
๐ Web APIs
Integration with browser storage, WebSockets, service workers, and more