Skip to main content

Method API

Request builders create type-safe JSON-RPC requests with branded primitive parameters.

Request Builders

Request builders return RequestArguments objects compatible with EIP-1193 providers:
import * as Rpc from '@tevm/voltaire/jsonrpc';
import { Address } from '@tevm/voltaire/Address';

const address = Address('0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0');

// Build requests
const blockRequest = Rpc.Eth.BlockNumberRequest();
const balanceRequest = Rpc.Eth.GetBalanceRequest(address, 'latest');
const callRequest = Rpc.Eth.CallRequest(params, 'latest');

// Send through provider (throws on error)
try {
  const blockNumber = await provider.request(blockRequest);
  const balance = await provider.request(balanceRequest);
  const callResult = await provider.request(callRequest);
} catch (error) {
  console.error('RPC error:', error.code, error.message);
}

Request Pattern

All request builders follow this signature:
Rpc.Eth.MethodNameRequest(params) → RequestArguments
  • Rpc.Eth.MethodName - Request builder (e.g., CallRequest, GetBalanceRequest)
  • params - Branded primitive types (Address, Hash, Hex, etc.)
  • Returns - {method: string, params?: unknown[]} object

Branded Primitive Parameters

All parameters use Voltaire’s branded primitive types for compile-time safety:
import * as Rpc from '@tevm/voltaire/jsonrpc';
import { Address } from '@tevm/voltaire/Address';
import { Hash } from '@tevm/voltaire/Hash';
import { Hex } from '@tevm/voltaire/Hex';

// Construct branded types
const address = Address('0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0');
const blockHash = Hash('0x...');
const data = Hex('0x70a08231...');

// Build requests - type-checked at compile time
const balanceReq = Rpc.Eth.GetBalanceRequest(address, 'latest');
const blockReq = Rpc.Eth.GetBlockByHashRequest(blockHash, true);

// Send requests (throws on error)
try {
  const balance = await provider.request(balanceReq);
  const block = await provider.request(blockReq);
} catch (error) {
  console.error('Request failed:', error);
}

Type Safety Benefits

TypeScript catches errors at compile time:
import * as Rpc from '@tevm/voltaire/jsonrpc';
import { Address } from '@tevm/voltaire/Address';

// ❌ Compile error: string not assignable to Address
const badReq = Rpc.Eth.GetBalanceRequest('0x...', 'latest');

// ✅ Correct: use branded Address
const goodReq = Rpc.Eth.GetBalanceRequest(Address('0x...'), 'latest');

// ❌ Compile error: can't mix Hash and Address
const mixedReq = Rpc.Eth.GetBlockByHashRequest(address, true);

// ✅ Correct: use proper type
const hashReq = Rpc.Eth.GetBlockByHashRequest(hash, true);

Error Handling

Throwing Errors

Requests throw errors on failure:
import * as Rpc from '@tevm/voltaire/jsonrpc';

try {
  const result = await provider.request(Rpc.Eth.CallRequest(params));
  console.log('Call result:', result);
} catch (error) {
  console.error('RPC error:', error.code, error.message);
  if (error.data) {
    console.error('Error data:', error.data);
  }
}

Type Inference

Return types are automatically inferred:
import * as Rpc from '@tevm/voltaire/jsonrpc';

// TypeScript knows blockNumber is string (Quantity)
const blockNumber = await provider.request(Rpc.Eth.BlockNumberRequest());

// TypeScript knows balance is string (Quantity)
const balance = await provider.request(
  Rpc.Eth.GetBalanceRequest(address, 'latest')
);

// TypeScript knows callResult is string (Hex)
const callResult = await provider.request(Rpc.Eth.CallRequest(params));

BlockTag Parameter

Many requests accept BlockTag to specify block context:
import * as Rpc from '@tevm/voltaire/jsonrpc';
import { Address } from '@tevm/voltaire/Address';

type BlockTag =
  | 'latest'      // Most recent block
  | 'earliest'    // Genesis block
  | 'pending'     // Pending block
  | 'safe'        // Safe head block
  | 'finalized'   // Finalized block
  | string;       // Specific block number (hex)

const address = Address('0x...');

// Usage with different block tags
try {
  const latest = await provider.request(Rpc.Eth.GetBalanceRequest(address, 'latest'));
  const finalized = await provider.request(Rpc.Eth.GetBalanceRequest(address, 'finalized'));
  const historical = await provider.request(Rpc.Eth.GetBalanceRequest(address, '0x112A880'));
} catch (error) {
  console.error('Failed to get balance:', error);
}

Method Categories

Read Operations

import * as Rpc from '@tevm/voltaire/jsonrpc';
import { Address } from '@tevm/voltaire/Address';

const address = Address('0x...');

try {
  // Get block number
  const blockNum = await provider.request(Rpc.Eth.BlockNumberRequest());

  // Get balance
  const balance = await provider.request(Rpc.Eth.GetBalanceRequest(address, 'latest'));

  // Get transaction count (nonce)
  const nonce = await provider.request(Rpc.Eth.GetTransactionCountRequest(address, 'latest'));

  // Get contract code
  const code = await provider.request(Rpc.Eth.GetCodeRequest(address, 'latest'));

  // Get storage slot
  const storage = await provider.request(Rpc.Eth.GetStorageAtRequest(address, slot, 'latest'));
} catch (error) {
  console.error('Read operation failed:', error);
}

Contract Calls

import * as Rpc from '@tevm/voltaire/jsonrpc';
import { Address } from '@tevm/voltaire/Address';
import { Hex } from '@tevm/voltaire/Hex';

try {
  // Execute read-only contract call
  const result = await provider.request(
    Rpc.Eth.CallRequest({
      to: Address('0x...'),
      data: Hex('0x70a08231...')  // Function selector + encoded params
    }, 'latest')
  );

  // Estimate gas for transaction
  const gasEstimate = await provider.request(
    Rpc.Eth.EstimateGasRequest({
      from: Address('0x...'),
      to: Address('0x...'),
      value: '0xDE0B6B3A7640000',  // 1 ETH in wei
      data: Hex('0x...')
    })
  );
} catch (error) {
  console.error('Contract call failed:', error);
}

Transaction Operations

import * as Rpc from '@tevm/voltaire/jsonrpc';
import { Hash } from '@tevm/voltaire/Hash';
import { Hex } from '@tevm/voltaire/Hex';

try {
  // Submit signed transaction
  const txHash = await provider.request(
    Rpc.Eth.SendRawTransactionRequest(Hex('0x...'))
  );

  // Get transaction by hash
  const tx = await provider.request(
    Rpc.Eth.GetTransactionByHashRequest(Hash('0x...'))
  );

  // Get transaction receipt
  const receipt = await provider.request(
    Rpc.Eth.GetTransactionReceiptRequest(Hash('0x...'))
  );
} catch (error) {
  console.error('Transaction operation failed:', error);
}

Block Operations

import * as Rpc from '@tevm/voltaire/jsonrpc';

try {
  // Get block by number
  const block = await provider.request(
    Rpc.Eth.GetBlockByNumberRequest('latest', true)
  );

  // Get block by hash
  const blockByHash = await provider.request(
    Rpc.Eth.GetBlockByHashRequest(blockHash, false)
  );

  // Get uncle count
  const uncleCount = await provider.request(
    Rpc.Eth.GetUncleCountByBlockNumberRequest('latest')
  );
} catch (error) {
  console.error('Block operation failed:', error);
}

Log Queries

import * as Rpc from '@tevm/voltaire/jsonrpc';
import { Address } from '@tevm/voltaire/Address';
import { Hash } from '@tevm/voltaire/Hash';

try {
  // Query logs
  const logs = await provider.request(
    Rpc.Eth.GetLogsRequest({
      fromBlock: 'earliest',
      toBlock: 'latest',
      address: Address('0x...'),
      topics: [Hash('0x...')]
    })
  );
} catch (error) {
  console.error('Log query failed:', error);
}

Error Codes

Common JSON-RPC error codes:
CodeMessageDescription
-32700Parse errorInvalid JSON
-32600Invalid requestMissing required fields
-32601Method not foundMethod doesn’t exist
-32602Invalid paramsWrong parameter types
-32603Internal errorServer-side error
3Execution revertedContract execution failed
See Error Handling for detailed error patterns.

Best Practices

  1. Use try/catch for error handling
  2. Use branded types for all parameters
  3. Reuse type instances - don’t reconstruct on every call
  4. Batch independent requests with Promise.all
import * as Rpc from '@tevm/voltaire/jsonrpc';
import { Address } from '@tevm/voltaire/Address';

const address = Address('0x...');

// ✅ Good: batch independent requests
try {
  const [block, balance, nonce] = await Promise.all([
    provider.request(Rpc.Eth.BlockNumberRequest()),
    provider.request(Rpc.Eth.GetBalanceRequest(address, 'latest')),
    provider.request(Rpc.Eth.GetTransactionCountRequest(address, 'latest'))
  ]);
} catch (error) {
  console.error('Batch request failed:', error);
}

// ❌ Bad: sequential requests (slower)
const block = await provider.request(Rpc.Eth.BlockNumberRequest());
const balance = await provider.request(Rpc.Eth.GetBalanceRequest(address, 'latest'));
const nonce = await provider.request(Rpc.Eth.GetTransactionCountRequest(address, 'latest'));

Method Reference