Skip to content

JSON-RPC Support

Tevm Node provides comprehensive JSON-RPC support through an EIP-1193 compatible interface. This allows seamless integration with popular Ethereum libraries and tools.

EIP-1193 Provider

The node can be extended to expose an EIP-1193 compatible request interface:

import { createTevmNode } from 'tevm'
import { requestEip1193 } from 'tevm/decorators'
 
const node = createTevmNode().extend(requestEip1193())
 
// Use standard JSON-RPC methods
const blockNum = await node.request({
  method: 'eth_blockNumber',
  params: [],
})

Supported Methods

Core Ethereum Methods

Extended Methods

Tevm also supports additional methods commonly found in development environments:

Client Integration

Using with Viem

For more information, see the Viem Documentation.

import { createTevmNode } from 'tevm'
import { createPublicClient, custom } from 'viem'
import { requestEip1193 } from 'tevm/decorators'
 
const node = createTevmNode().extend(requestEip1193())
 
const client = createPublicClient({
  chain: mainnet,
  transport: custom(node.request),
})

Using with Ethers

For more information, see the Ethers Documentation.

import { createTevmNode } from 'tevm'
import { BrowserProvider } from 'ethers'
import { requestEip1193 } from 'tevm/decorators'
 
const node = createTevmNode().extend(requestEip1193())
const provider = new BrowserProvider(node)

Error Handling

JSON-RPC errors follow the standard format and are fully typed. See the error types documentation for more details:

interface JsonRpcError {
  code: number
  message: string
  data?: unknown
}

Common error codes (see Error Types):

For detailed error handling examples and best practices, see the Error Handling Guide.

Best Practices

  1. Error Handling: Always wrap RPC calls in try-catch blocks to handle potential errors gracefully. See Error Types for all possible errors.

  2. Gas Estimation: For transactions, use eth_estimateGas before sending to ensure sufficient gas:

const gasEstimate = await node.request({
  method: 'eth_estimateGas',
  params: [tx],
})
  1. Receipt Confirmation: Wait for transaction receipts to confirm state changes using eth_getTransactionReceipt:
const txHash = await node.request({
  method: 'eth_sendTransaction',
  params: [tx],
})
 
const receipt = await node.request({
  method: 'eth_getTransactionReceipt',
  params: [txHash],
})
  1. Event Filtering: Use filters efficiently by:

For more examples and detailed API documentation, see:

Related Topics

Using Tevm Actions

Tevm provides a set of high-level actions that can be imported from tevm/actions. See the complete actions documentation for all available actions.

import {
  tevmCall, // See: https://github.com/evmts/tevm-monorepo/blob/main/packages/actions/docs/functions/callHandler.md
  tevmMine, // See: https://github.com/evmts/tevm-monorepo/blob/main/packages/actions/docs/functions/mineHandler.md
  tevmGetAccount, // See: https://github.com/evmts/tevm-monorepo/blob/main/packages/actions/docs/functions/getAccountHandler.md
  tevmSetAccount // See: https://github.com/evmts/tevm-monorepo/blob/main/packages/actions/docs/functions/setAccountHandler.md
} from 'tevm/actions'
import { createTevmNode } from 'tevm'
 
const node = createTevmNode()
 
// Call a contract
const result = await tevmCall(node, {
  to: '0x...',
  data: '0x...',
  value: 0n,
  createTransaction: true
})
 
// Mine pending transactions
await tevmMine(node)
 
// Get account state
const account = await tevmGetAccount(node, {
  address: '0x...',
  blockTag: 'latest'
})
 
// Set account state
await tevmSetAccount(node, {
  address: '0x...',
  balance: 100n,
  nonce: 0n,
  deployedBytecode: '0x...'
})

For detailed type information, see:

Note: By default, tevm actions require manual mining via tevmMine(). If you want transactions to be automatically applied, you can either:

  1. Use the lower level API vm.runCall
  2. Configure the client with miningConfig: { type: 'auto' }

Optimistic Updates with Receipt Manager

For more information on transaction receipts and logs, see the Ethereum Receipts Documentation.

import { createTevmNode } from 'tevm'
import { tevmCall, tevmMine } from 'tevm/actions'
 
const node = createTevmNode()
const receiptsManager = await node.getReceiptsManager()
 
// Submit transaction
const { txHash } = await tevmCall(node, {
  method: 'eth_sendTransaction',
  params: [tx],
  createTransaction: true
})
 
// Get optimistic receipt
const pendingReceipt = await receiptsManager.getReceiptByTxHash(txHash)
 
// Update UI optimistically
updateUI(pendingReceipt)
 
// Wait for real receipt
const realReceipt = await node.request({
  method: 'eth_getTransactionReceipt',
  params: [txHash]
})
 
// Eject optimistic tx if real receipt differs
if (receiptsAreDifferent(pendingReceipt, realReceipt)) {
  await receiptsManager.removeReceipt(txHash)
  updateUI(realReceipt)
}
 
// Advanced: Rebase on new blocks
node.on('block', async (blockNumber) => {
  // Get new block
  const block = await node.request({
    method: 'eth_getBlockByNumber',
    params: [blockNumber, true]
  })
 
  // Get our pending transactions
  const pendingTxs = await receiptsManager.getPendingTransactions()
 
  // Rebase our transactions on top of new block
  for (const tx of pendingTxs) {
    const result = await tevmCall(node, {
      ...tx,
      blockTag: 'pending'
    })
 
    // Update receipt
    await receiptsManager.putReceipt(tx.hash, result)
  }
 
  // Mine rebased transactions
  await tevmMine(node)
})