Skip to content
LogoLogo

Using TevmProvider

TevmProvider extends the ethers JsonRpcApiProvider. Everything you know about ethers providers applies; the only difference is that the JSON-RPC requests are answered by an EVM running in the same process.

Creating a provider

import {  } from '@tevm/ethers'
 
const  = await .createMemoryProvider({
	: { : 'auto' },
})
 
.(await .getBlockNumber()) // 0

createMemoryProvider accepts the full TevmNodeOptions object:

OptionPurpose
fork{ transport, blockTag } โ€” fork state lazily from another chain.
miningConfig{ type: 'auto' } mines a block per transaction; { type: 'manual' } is the default.
commonThe chain definition (defaults to tevmDefault, chain id 900).
loggingLevel`'trace'

Mining

By default Tevm mines manually: a transaction sits in the mempool until you mine. tx.wait() will hang forever if you forget.

import {  } from '@tevm/ethers'
import {  } from '@tevm/utils'
import { ,  } from 'ethers'
 
const  = await .createMemoryProvider({})
const  = new ([0], )
 
const  = await .({
	: `0x${'42'.(20)}`,
	: ('1'),
})
 
// Nothing is mined yet โ€” mine explicitly, then await the receipt.
await .tevm.mine({ : 1 })
 
const  = await .()
.(?.) // 1
.(await .getBlockNumber()) // 1

Pass miningConfig: { type: 'auto' } if you would rather have a block per transaction, which is the closest analogue to anvil in automine mode.

Signers and wallets

Tevm prefunds a set of well-known accounts with 1000 ETH each. Use them with an ordinary ethers.Wallet:

import {  } from '@tevm/ethers'
import { ,  } from '@tevm/utils'
import { ,  } from 'ethers'
 
const  = await .createMemoryProvider({ : { : 'auto' } })
 
const  = new ([0], )
 
.(. === [0].) // true
.((await .getBalance(.))) // '1000.0'

If you want an arbitrary address to be funded, give it a balance directly instead of transferring:

import {  } from '@tevm/ethers'
import { ,  } from 'ethers'
 
const  = await .createMemoryProvider({ : { : 'auto' } })
const  = `0x${'42'.(20)}`
 
await .tevm.setAccount({ , : ('100') })
 
.((await .getBalance())) // '100.0'

Raw JSON-RPC

provider.send accepts the standard eth_* methods and the Tevm tevm_* methods:

import {  } from '@tevm/ethers'
import {  } from '@tevm/utils'
 
const  = await .createMemoryProvider({})
 
.(await .send('eth_chainId', [])) // '0x384'
 
await .send('tevm_setAccount', [
	{ : `0x${'69'.(20)}`, : (1n), : (420n) },
])
 
const  = await .send('tevm_getAccount', [{ : `0x${'69'.(20)}` }])
.(.balance) // '0x1a4'

Sharing one EVM

Batching and response caching are disabled on TevmProvider (batchMaxCount: 1, cacheTimeout: -1) precisely because the node is in-process: requests are cheap, and caching would hide state you mutate through provider.tevm. That also makes it safe to point several providers at the same node.

import {  } from '@tevm/ethers'
import { ,  } from '@tevm/decorators'
import {  } from '@tevm/node'
import {  } from 'ethers'
 
const  = ({ : { : 'auto' } })
	.(())
	.(())
 
const  = new ()
const  = new ()
 
await .tevm.setAccount({ : `0x${'42'.(20)}`, : ('1') })
 
// Both providers see the same state.
.(await .getBalance(`0x${'42'.(20)}`)) // 1000000000000000000n

Next