@tevm/memory-client
Version:
MemoryClient for tevm is an in memory devnet for JavaScript
1,190 lines (1,168 loc) • 47.1 kB
text/typescript
import { Common } from '@tevm/common';
import { Address, Abi, ContractFunctionName } from '@tevm/utils';
import * as viem from 'viem';
import { PublicRpcSchema, TestRpcSchema, Chain, ClientConfig, TransportConfig, Account, Client, PublicActions, WalletActions, TestActions, RpcSchema, Transport } from 'viem';
export { createClient, publicActions, testActions, walletActions } from 'viem';
import { Prettify } from 'viem/chains';
import { TevmActionsApi, JsonRpcSchemaTevm, EIP1193RequestFn } from '@tevm/decorators';
import * as _tevm_node from '@tevm/node';
import { TevmNode, TevmNodeOptions } from '@tevm/node';
import * as _tevm_actions from '@tevm/actions';
import { ContractParams, CallEvents, ContractResult } from '@tevm/actions';
/**
* Provides powerful actions for interacting with the EVM using the TEVM API.
* These actions allow for low-level access to the EVM, managing accounts, deploying contracts, and more.
*
* @see [Actions Guide](https://tevm.sh/learn/actions/)
* @see [Viem Actions API](https://viem.sh/docs/actions/introduction)
*/
type TevmActions = {
/**
* Returns a promise that resolves when the TEVM is ready.
* This is not needed to explicitly be called as all actions will wait for the TEVM to be ready.
* @example
* ```typescript
* import { createMemoryClient } from 'tevm'
*
* const client = createMemoryClient()
*
* await client.tevmReady()
* ```
* Same as calling `client.transport.tevm.ready()`
*/
tevmReady: () => Promise<true>;
/**
* A powerful low level API for executing calls and sending transactions.
* See [CallParams](https://tevm.sh/reference/tevm/actions/type-aliases/callparams/) for options reference.
* See [CallResult](https://tevm.sh/reference/tevm/actions/type-aliases/callresult/) for return values reference.
* Remember, you must set `createTransaction: true` to send a transaction. Otherwise, it will be a call. You must also mine the transaction
* before it updates the canonical head state. This can be avoided by setting mining mode to `auto` when using createMemoryClient.
* @example
* ```typescript
* import { createMemoryClient } from 'tevm'
* import { ERC20 } from 'tevm/contract'
*
* const client = createMemoryClient()
*
* const token = ERC20.withAddress(`0x${'0721'.repeat(10)}`)
*
* await client.setAccount(token)
*
* const balance = await client.tevmCall({
* to: token.address,
* data: encodeFunctionData(token.read.balanceOf, [token.address]),
* })
* ```
* In addition to making basic calls, you can also do advanced things like:
* - Impersonate accounts via passing in `from`, `caller`, or `origin`
* - Set the call depth via `depth`
* - Create a trace or access list using `createTrace: true` or `createAccessList: true`
* - Send as a transaction with `createTransaction: true`
* For all options see [CallParams](https://tevm.sh/reference/tevm/actions/type-aliases/callparams/)
*/
tevmCall: TevmActionsApi['call'];
/**
* A powerful low level API for calling contracts. Similar to `tevmCall` but takes care of encoding and decoding data, revert messages, etc.
* See [ContractParams](https://tevm.sh/reference/tevm/actions/type-aliases/contractparams/) for options reference.
* See [ContractResult](https://tevm.sh/reference/tevm/actions/type-aliases/contractresult/) for return values reference.
* Remember, you must set `createTransaction: true` to send a transaction. Otherwise, it will be a call. You must also mine the transaction
* before it updates the canonical head state. This can be avoided by setting mining mode to `auto` when using createMemoryClient.
* @example
* ```typescript
* import { createMemoryClient } from 'tevm'
* import { ERC20 } from './MyERC721.sol'
*
* const client = createMemoryClient()
* const token = ERC20.withAddress(`0x${'0721'.repeat(10)}`)
* await client.setAccount(token)
* const balance = await client.tevmContract({
* contract: token,
* method: token.read.balanceOf,
* args: [token.address],
* })
* ```
* In addition to making basic calls, you can also do advanced things like:
* - Impersonate accounts via passing in `from`, `caller`, or `origin`
* - Set the call depth via `depth`
* - Create a trace or access list using `createTrace: true` or `createAccessList: true`
* - Send as a transaction with `createTransaction: true`
* For all options see [ContractParams](https://tevm.sh/reference/tevm/actions/type-aliases/contractparams/)
*/
tevmContract: TevmActionsApi['contract'];
/**
* Deploys a contract to the EVM with encoded constructor arguments. Extends `tevmCall` so it supports all advanced options.
* @see [DeployParams](https://tevm.sh/reference/tevm/actions/type-aliases/deployparams/) for options reference.
* @see [DeployResult](https://tevm.sh/reference/tevm/actions/type-aliases/deployresult/) for return values reference.
* Remember, you must set `createTransaction: true` to send a transaction. Otherwise, it will be a call. You must also mine the transaction
* before it updates the canonical head state. This can be avoided by setting mining mode to `auto` when using createMemoryClient.
* @example
* ```typescript
* import { createMemoryClient } from 'tevm'
* import { ERC20 } from './MyERC721.sol'
*
* const client = createMemoryClient()
* const token = ERC20.withAddress(`0x${'0721'.repeat(10)}`)
*
* const deploymentResult = await client.tevmDeploy({
* abi: token.abi,
* bytecode: token.bytecode,
* args: ['TokenName', 18, 'SYMBOL'],
* })
*
* console.log(deploymentResult.createdAddress)
* ```
*/
tevmDeploy: TevmActionsApi['deploy'];
/**
* Mines a new block with all pending transactions. In `manual` mode you must call this manually before the canonical head state is updated.
* @example
* ```typescript
* import { createMemoryClient } from 'tevm'
*
* const client = createMemoryClient()
*
* await client.tevmMine()
* ```
*/
tevmMine: TevmActionsApi['mine'];
/**
* Loads a JSON serializable state into the EVM. This can be useful for persisting and restoring state between processes.
* @example
* ```typescript
* import { createMemoryClient } from 'tevm'
* import fs from 'fs'
*
* const client = createMemoryClient()
*
* const state = fs.readFileSync('state.json', 'utf8')
*
* await client.tevmLoadState(state)
* ```
*/
tevmLoadState: TevmActionsApi['loadState'];
/**
* Dumps a JSON serializable state from the EVM. This can be useful for persisting and restoring state between processes.
* @example
* ```typescript
* import { createMemoryClient } from 'tevm'
* import fs from 'fs'
* const client = createMemoryClient()
* const state = await client.tevmDumpState()
* fs.writeFileSync('state.json', JSON.stringify(state))
* ```
*/
tevmDumpState: TevmActionsApi['dumpState'];
/**
* Sets any property of an account including its balance, nonce, contract deployedBytecode, contract state, and more.
* @see [SetAccountParams](https://tevm.sh/reference/tevm/actions/type-aliases/setaccountparams/) for options reference.
* @see [SetAccountResult](https://tevm.sh/reference/tevm/actions/type-aliases/setaccountresult/) for return values reference.
* @example
* ```typescript
* import { createMemoryClient, numberToHex } from 'tevm'
* import { SimpleContract } from 'tevm/contract'
*
* const client = createMemoryClient()
*
* await client.tevmSetAccount({
* address: `0x${'0123'.repeat(10)}`,
* balance: 100n,
* nonce: 1n,
* deployedBytecode: SimpleContract.deployedBytecode,
* state: {
* [`0x${'0'.repeat(64)}`]: numberToHex(420n),
* }
* })
* ```
*/
tevmSetAccount: TevmActionsApi['setAccount'];
/**
* Gets the account state of an account. It does not return the storage state by default but can if `returnStorage` is set to `true`.
* In forked mode, the storage is only the storage TEVM has cached and may not represent all the on-chain storage.
* @see [GetAccountParams](https://tevm.sh/reference/tevm/actions/type-aliases/getaccountparams/) for options reference.
* @see [GetAccountResult](https://tevm.sh/reference/tevm/actions/type-aliases/getaccountresult/) for return values reference.
* @example
* ```typescript
* import { createMemoryClient } from 'tevm'
*
* const client = createMemoryClient()
*
* const account = await client.tevmGetAccount({
* address: `0x${'0000'.repeat(10)}`,
* returnStorage: true,
* })
* ```
*/
tevmGetAccount: TevmActionsApi['getAccount'];
/**
* Sets the balance of an account to a specific amount of ETH or ERC20 tokens.
* A convenience method over tevmSetAccount for quickly adjusting account balances.
* @see [DealParams](https://tevm.sh/reference/tevm/actions/type-aliases/dealparams/) for options reference.
* @see [DealResult](https://tevm.sh/reference/tevm/actions/type-aliases/dealresult/) for return values reference.
* @example Deal native ETH
* ```typescript
* import { createMemoryClient } from 'tevm'
*
* const client = createMemoryClient()
*
* // Set ETH balance
* await client.tevmDeal({
* account: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
* amount: 1000000000000000000n // 1 ETH
* })
* ```
*
* @example Deal ERC20 tokens
* ```typescript
* import { createMemoryClient } from 'tevm'
*
* const client = createMemoryClient()
*
* // Set ERC20 token balance
* await client.tevmDeal({
* erc20: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', // USDC address
* account: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
* amount: 1000000n // 1 USDC (6 decimals)
* })
* ```
*/
tevmDeal: TevmActionsApi['deal'];
};
/**
* The JSON-RPC schema for TEVM.
* This type represents the JSON-RPC requests that the EIP-1193 client can handle when using TEVM.
* It includes public, test, and TEVM-specific methods.
* @example
* ```typescript
* import { createClient, http } from 'viem'
* import { optimism } from 'tevm/common'
* import { createTevmTransport } from 'tevm'
*
* const client = createClient({
* transport: createTevmTransport({
* fork: { transport: http('https://mainnet.optimism.io')({}) }
* }),
* chain: optimism,
* })
*
* async function example() {
* const result = await client.request({
* method: 'tevm_call',
* params: [{ to: '0x123...', data: '0x123...' }],
* })
* console.log(result)
* }
*
* example()
* ```
*
* @see [Tevm JSON-RPC guide](https://tevm.sh/learn/json-rpc/)
* @see [EIP-1193](https://eips.ethereum.org/EIPS/eip-1193)
* @see [Ethereum jsonrpc](https://ethereum.org/en/developers/docs/apis/json-rpc/)
*/
type TevmRpcSchema = [
...PublicRpcSchema,
...TestRpcSchema<'anvil' | 'ganache' | 'hardhat'>,
JsonRpcSchemaTevm['tevm_call'],
JsonRpcSchemaTevm['tevm_dumpState'],
JsonRpcSchemaTevm['tevm_loadState'],
JsonRpcSchemaTevm['tevm_getAccount'],
JsonRpcSchemaTevm['tevm_setAccount']
];
/**
* A type representing a custom TEVM Transport for viem.
*
* @template TName - The name of the transport.
* @template TChain - The blockchain configuration.
*
* @param {TevmTransportConfig} config - Transport configuration options.
* @returns {Object} The configured TEVM transport.
* @returns {TransportConfig<TName>} config - The transport configuration.
* @returns {EIP1193RequestFn} request - The EIP-1193 request function.
* @returns {Object} value - The transport value.
* @returns {TevmNode & { request: EIP1193RequestFn }} value.tevm - The TEVM base client with the EIP-1193 request function.
*/
type TevmTransport<TName extends string = string> = <TChain extends Chain | undefined = Chain>({ chain, pollingInterval, retryCount, timeout, }: {
chain?: TChain | undefined;
pollingInterval?: ClientConfig['pollingInterval'] | undefined;
retryCount?: TransportConfig['retryCount'] | undefined;
timeout?: TransportConfig['timeout'] | undefined;
}) => {
config: TransportConfig<TName>;
request: EIP1193RequestFn;
value: {
tevm: TevmNode & {
request: EIP1193RequestFn;
};
};
};
/**
* Represents a TEVM-enhanced viem client with an in-memory Ethereum client as its transport.
*
* The MemoryClient provides a complete in-memory Ethereum Virtual Machine implementation with
* a full suite of capabilities:
*
* - Execute contract calls directly in JavaScript with full EVM compatibility
* - Monitor EVM execution events (steps, messages, contract creation)
* - Deploy and interact with contracts, including direct Solidity imports
* - Set account states, balances, nonces, and contract storage
* - Fork from existing networks and cache remote state as needed
* - Mine blocks manually or automatically after transactions
* - Persist and restore state across sessions
*
* The client implements multiple API styles:
* - TEVM-specific methods for direct EVM interaction
* - Standard Ethereum JSON-RPC methods
* - Viem-compatible wallet, test, and public actions
*
* @type {import('./CreateMemoryClientFn.js').CreateMemoryClientFn}
*
* @example
* ```typescript
* import { createMemoryClient, http } from "tevm";
* import { optimism } from "tevm/common";
* import { parseEther } from "viem";
*
* // Create a client forking from Optimism
* const client = createMemoryClient({
* fork: {
* transport: http("https://mainnet.optimism.io")({}),
* },
* common: optimism,
* });
*
* // Wait for the client to be ready
* await client.tevmReady();
*
* // Set up account state
* const address = "0x1234567890123456789012345678901234567890";
* await client.tevmSetAccount({
* address,
* balance: parseEther("10")
* });
*
* // Deploy a contract with events tracking
* const deployResult = await client.tevmDeploy({
* bytecode: "0x608060405234801561001057600080fd5b50610150806100206000396000f3fe...",
* abi: [...],
* onStep: (step, next) => {
* console.log(`Executing ${step.opcode.name} at PC=${step.pc}`);
* next();
* }
* });
*
* // Mine a block to confirm transactions
* await client.mine({ blocks: 1 });
*
* // Get the contract address from deployment
* console.log(`Contract deployed at: ${deployResult.createdAddress}`);
* ```
*
* @see For creating a MemoryClient instance, see {@link createMemoryClient}.
* @see [Client Guide](https://tevm.sh/learn/clients/)
* @see [Actions Guide](https://tevm.sh/learn/actions/)
* @see [Reference Docs](https://tevm.sh/reference/tevm/memory-client/functions/creatememoryclient/)
*
* ## Actions API
*
* MemoryClient supports the following viem actions:
*
* - [TEVM actions API](https://tevm.sh/reference/tevm/memory-client/type-aliases/tevmactions/)
* ```typescript
* import { createMemoryClient } from "tevm";
*
* const tevm = createMemoryClient();
* await tevm.setAccount({ address: `0x${'01'.repeat(20)}`, balance: 100n });
* ```
* - [Viem public actions API](https://viem.sh/docs/actions/public/introduction) such as [getBlockNumber](https://viem.sh/docs/actions/public/getBlockNumber)
* ```typescript
* import { createMemoryClient } from "tevm";
*
* const tevm = createMemoryClient();
* const bn = await tevm.getBlockNumber();
* ```
* - [Test actions](https://viem.sh/docs/actions/test/introduction) are included by default.
* ```typescript
* import { createMemoryClient } from "tevm";
*
* const tevm = createMemoryClient();
* await tevm.setBalance({ address: `0x${'01'.repeat(20)}`, balance: 100n });
* ```
*
* ## Forking
*
* To fork an existing network, pass an EIP-1193 transport to the `fork.transport` option with an optional block tag.
* When you fork, TEVM will pin the block tag and lazily cache state from the fork transport.
* It's highly recommended to pass in a `common` object that matches the chain. This will increase the performance of forking with known values.
*
* ```typescript
* import { createMemoryClient, http } from "tevm";
* import { optimism } from "tevm/common";
*
* const forkedClient = createMemoryClient({
* fork: {
* transport: http("https://mainnet.optimism.io")({}),
* blockTag: '0xa6a63cd70fbbe396321ca6fe79e1b6735760c03538208b50d7e3a5dac5226435',
* },
* common: optimism,
* });
* ```
*
* The `common` object extends the viem chain interface with EVM-specific information. When using TEVM, you should also use `tevm/common` rather than `viem/chains` or use `createCommon` and pass in a viem chain.
*
* Viem clients, including MemoryClient, are themselves EIP-1193 transports. This means you can fork a client with another client.
*
* ## Mining Modes
*
* TEVM supports two mining modes:
* - Manual: Using `tevm.mine()`
* - Auto: Automatically mines a block after every transaction.
*
* TEVM state does not update until blocks are mined.
*
* ## Using TEVM over HTTP
*
* TEVM can be run as an HTTP server using `@tevm/server` to handle JSON-RPC requests.
*
* ```typescript
* import { createServer } from "tevm/server";
* import { createMemoryClient } from "tevm";
*
* const memoryClient = createMemoryClient();
*
* const server = createServer({
* request: memoryClient.request,
* });
*
* server.listen(8545, () => console.log("listening on 8545"));
* ```
*
* This allows you to use any Ethereum client to communicate with it, including a viem public client.
*
* ```typescript
* import { createPublicClient, http } from "viem";
* import { mainnet } from "viem/chains";
*
* const publicClient = createPublicClient({
* chain: mainnet,
* transport: http("https://localhost:8545"),
* });
*
* console.log(await publicClient.getChainId());
* ```
*
* ## State Persistence (Experimental)
*
* It is possible to persist the TEVM client to a synchronous source using the `persister` option.
*
* ```typescript
* import { createMemoryClient, createSyncPersister } from "tevm";
* import { createMemoryClient } from "tevm/sync-storage-persister";
*
* // Client state will be hydrated and persisted from/to local storage
* const clientWithLocalStoragePersistence = createMemoryClient({
* persister: createSyncPersister({
* storage: localStorage,
* }),
* });
* ```
*
* ## Network Support
*
* TEVM guarantees support for the following networks:
* - Ethereum mainnet
* - Standard OP Stack chains
*
* Other EVM chains are likely to work but do not officially carry support. More official chain support will be added in the near future.
*
* Note: Optimism deposit transactions are not currently supported but will be in a future release. TEVM filters out these transactions from blocks.
*
* ## Network and Hardfork Support
*
* TEVM supports enabling and disabling different EIPs, but the following EIPs are always turned on:
* - 1559
* - 4895
* - 4844
* - 4788
*
* Currently, only EIP-1559 Fee Market transactions are supported.
*
* ## Tree Shakeable Actions
*
* TEVM supports tree-shakeable actions using `createTevmNode()` and the `tevm/actions` package. If you are building a UI, you should use tree-shakeable actions to optimize bundle size. These are described in detail in the [actions API guide](https://tevm.sh/learn/actions/).
*
* ## Composing with TEVM Contracts and Bundler
*
* MemoryClient can compose with TEVM contracts and the TEVM bundler. For more information, see the [TEVM contracts guide](https://tevm.sh/learn/contracts/) and the [TEVM Solidity imports guide](https://tevm.sh/learn/solidity-imports/).
*
* ```typescript
* import { createMemoryClient } from "tevm";
* import { MyERC721 } from './MyERC721.sol';
*
* const tevm = createMemoryClient({
* fork: {
* transport: http("https://mainnet.optimism.io")({}),
* },
* });
*
* const address = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045';
*
* await tevm.runContractCall(
* MyERC721.write.mint({
* caller: address,
* }),
* );
*
* const balance = await tevm.runContractCall(
* MyERC721.read.balanceOf({
* caller: address,
* }),
* );
* console.log(balance); // 1n
* ```
*/
type MemoryClient<TChain extends Chain | undefined = Chain | undefined, TAccountOrAddress extends Account | Address | undefined = Account | Address | undefined> = Prettify<Client<TevmTransport, TChain, TAccountOrAddress extends Account ? Account : undefined, TevmRpcSchema, TevmActions & PublicActions<TevmTransport, TChain, TAccountOrAddress extends Account ? Account : undefined> & WalletActions<TChain, TAccountOrAddress extends Account ? Account : undefined> & TestActions>>;
/**
* Configuration options for creating a {@link MemoryClient}.
*
* This type extends `TevmNodeOptions` and includes specific options for configuring the MemoryClient,
* such as the transport type, account, polling interval, and caching behavior. It provides
* a comprehensive set of parameters to customize the behavior of the in-memory Ethereum client.
*
* @template TCommon - The common chain configuration, extending both `Common` and `Chain`.
* @template TAccountOrAddress - The account or address type for the client.
* @template TRpcSchema - The RPC schema type, defaults to `TevmRpcSchema`.
*
* @example
* ```typescript
* import { createMemoryClient, http, type MemoryClientOptions } from "tevm";
* import { optimism } from "tevm/common";
* import { createSyncPersister } from "tevm/sync-storage-persister";
*
* const options: MemoryClientOptions = {
* // Fork configuration to pull state from a live network
* fork: {
* transport: http("https://mainnet.optimism.io")({}),
* blockTag: '0xa6a63cd70fbbe396321ca6fe79e1b6735760c03538208b50d7e3a5dac5226435',
* },
* // Chain configuration
* common: optimism,
* // Client identification
* name: 'Optimism Memory Client',
* key: 'optimism-memory',
* // Mining configuration (auto mines blocks after transactions)
* miningConfig: {
* type: 'auto'
* },
* // Client performance tuning
* pollingInterval: 1000,
* cacheTime: 60000,
* // State persistence
* persister: createSyncPersister({
* storage: localStorage,
* key: 'tevm-state'
* }),
* // Enable unlimited contract sizes (for testing very large contracts)
* allowUnlimitedContractSize: true,
* // Logging level
* loggingLevel: 'info'
* };
*
* const client = createMemoryClient(options);
* ```
*
* @see {@link MemoryClient}
* @see {@link CreateMemoryClientFn}
* @see {@link TevmNodeOptions}
*
* @property {string} [type] - The type of client (defaults to 'tevm').
* @property {string} [key] - The key for the client, used for caching and identification.
* @property {string} [name] - The name of the client, used for logging and display purposes.
* @property {TAccountOrAddress} [account] - The account associated with the client for signing transactions.
* @property {number} [pollingInterval] - The interval (in milliseconds) at which the client polls for new data (for watchable actions).
* @property {number} [cacheTime] - The time (in milliseconds) to cache data from requests.
* @property {TCommon} [common] - The common chain configuration object that defines the chain and EVM parameters.
* @property {Object} [fork] - The configuration for forking a network.
* @property {Function} [fork.transport] - The transport function for connecting to the fork source network.
* @property {string|number|bigint} [fork.blockTag] - The specific block tag to fork from (can be number, hash, or named tag like 'latest').
* @property {Object} [miningConfig] - Configuration for how blocks are mined.
* @property {'manual'|'auto'|'interval'} [miningConfig.type] - The mining mode (manual requires calling mine(), auto mines after each tx, interval mines on a timer).
* @property {number} [miningConfig.interval] - For interval mining, how often to mine blocks in milliseconds.
* @property {import('@tevm/utils').SyncStoragePersister} [persister] - Handler for persisting and restoring state.
* @property {boolean} [allowUnlimitedContractSize] - Whether to remove the EIP-170 contract size limit (default: false).
* @property {'error'|'warn'|'info'|'debug'|'trace'} [loggingLevel] - Controls logging verbosity (default: 'info').
* @property {Object} [eips] - Configuration for specific Ethereum Improvement Proposals.
* @throws {Error} When configuration options are incompatible or invalid.
*/
type MemoryClientOptions<TCommon extends Common & Chain = Common & Chain, TAccountOrAddress extends Account | Address | undefined = undefined, TRpcSchema extends RpcSchema | undefined = TevmRpcSchema> = TevmNodeOptions<TCommon> & Pick<ClientConfig<Transport, TCommon, TAccountOrAddress, TRpcSchema>, 'type' | 'key' | 'name' | 'account' | 'pollingInterval' | 'cacheTime'>;
/**
* Type definition for the function that creates a {@link MemoryClient}.
*
* This function type represents `createMemoryClient`, which initializes a complete in-memory Ethereum
* virtual machine with a comprehensive API. The function supports extensive configuration options for:
*
* - Network forking from live Ethereum networks
* - Custom chain settings and EVM parameters
* - Mining behavior configuration
* - State persistence
* - Logging and debugging settings
* - Custom account injection
*
* The returned client integrates with viem's action system while providing TEVM-specific
* capabilities for more advanced EVM interaction.
*
* @template TCommon - The common chain configuration, extending both `Common` and `Chain`.
* @template TAccountOrAddress - The account or address type for the client.
* @template TRpcSchema - The RPC schema type, defaults to `TevmRpcSchema`.
*
* @param {MemoryClientOptions<TCommon, TAccountOrAddress, TRpcSchema>} [options] - The options to configure the MemoryClient.
* @returns {MemoryClient<TCommon, TAccountOrAddress>} - A configured MemoryClient instance.
* @throws {Error} When configuration is invalid or initialization fails.
*
* @example
* ```typescript
* import { createMemoryClient, http } from "tevm";
* import { optimism } from "tevm/common";
* import { parseEther } from "viem";
*
* // Basic client with default settings
* const basicClient = createMemoryClient();
*
* // Advanced client with custom configuration
* const client = createMemoryClient({
* // Fork from Optimism mainnet
* fork: {
* transport: http("https://mainnet.optimism.io")({}),
* blockTag: 'latest', // Or specific block hash/number
* },
* // Use Optimism chain configuration
* common: optimism,
* // Enable auto-mining (blocks mined after each transaction)
* miningConfig: {
* type: 'auto'
* },
* // Set client metadata
* name: 'Optimism Development Client',
* // Configure performance
* pollingInterval: 1000,
* // Modify EVM behavior
* allowUnlimitedContractSize: true,
* // Set logging verbosity
* loggingLevel: 'debug'
* });
*
* // Initialize and configure client
* await client.tevmReady();
*
* // Set up test account
* await client.tevmSetAccount({
* address: '0x1234567890123456789012345678901234567890',
* balance: parseEther('100'),
* nonce: 0n
* });
*
* // Read from forked network
* const balance = await client.getBalance({
* address: '0xd8da6bf26964af9d7eed9e03e53415d37aa96045'
* });
* ```
*
* @see {@link MemoryClient} - For the return type of this function
* @see {@link MemoryClientOptions} - For detailed configuration options
* @see [Client Guide](https://tevm.sh/learn/clients/) - Complete documentation
*/
type CreateMemoryClientFn = <TCommon extends Common & Chain = Common & Chain, TAccountOrAddress extends Account | Address | undefined = undefined, TRpcSchema extends RpcSchema | undefined = TevmRpcSchema>(options?: MemoryClientOptions<TCommon, TAccountOrAddress, TRpcSchema>) => MemoryClient<TCommon, TAccountOrAddress>;
/**
* Creates a {@link MemoryClient} - a fully-featured Ethereum development and testing environment.
*
* The MemoryClient is an all-in-one solution that combines:
* - A complete in-memory Ethereum Virtual Machine implementation
* - Full support for viem's wallet, test, and public actions
* - TEVM-specific actions for advanced state manipulation and tracing
* - Automatic handling of JSON-RPC requests through viem's client interface
*
* This provides an integrated environment for local Ethereum development with capabilities like:
* - Executing and debugging smart contracts without deploying to a testnet
* - Forking from existing networks with state caching for realistic testing
* - Direct manipulation of blockchain state for complex test scenarios
* - Complete control over mining and transaction processing
* - Compatibility with standard Ethereum tooling and libraries
*
* @type {import('./CreateMemoryClientFn.js').CreateMemoryClientFn}
*
* @example
* ```typescript
* import { createMemoryClient, http } from "tevm";
* import { optimism } from "tevm/common";
*
* // Create a memory client that forks from Optimism mainnet
* const client = createMemoryClient({
* fork: {
* transport: http("https://mainnet.optimism.io")({}),
* },
* common: optimism,
* mining: { auto: true }, // Automatically mine blocks after transactions
* });
*
* // Wait for fork initialization to complete
* await client.tevmReady();
*
* // Use standard viem actions
* const blockNumber = await client.getBlockNumber();
* console.log(`Connected to Optimism block ${blockNumber}`);
*
* // Use TEVM-specific actions
* await client.tevmSetAccount({
* address: "0x123...",
* balance: 10000000000000000000n // 10 ETH
* });
* ```
*
* @see [Client Guide](https://tevm.sh/learn/clients/)
* @see [Actions Guide](https://tevm.sh/learn/actions/)
* @see [Reference Docs](https://tevm.sh/reference/tevm/memory-client/functions/creatememoryclient/)
* @see [Viem client docs](https://viem.sh/docs/clients/introduction)
*
* ## Key Configuration Options
*
* ```typescript
* createMemoryClient({
* // Chain configuration (use tevm/common chains, not viem/chains)
* common: optimism,
*
* // Forking from an existing network
* fork: {
* transport: http("https://mainnet.optimism.io")({}),
* blockTag: 'latest', // or specific block number/hash
* },
*
* // Mining configuration
* mining: {
* auto: true, // Auto-mine after each transaction
* interval: 5000, // Mine blocks every 5 seconds (in ms)
* },
*
* // State persistence
* persister: createSyncPersister({
* storage: localStorage, // or any synchronous storage
* }),
*
* // Chain configuration
* hardfork: 'prague', // Default and recommended
*
* // EVM execution logging
* logging: {
* logLevel: 'debug',
* },
* })
* ```
*
* ## Actions API
*
* MemoryClient combines multiple action types in a single interface:
*
* ### 1. TEVM-specific actions
* ```typescript
* // Account and state manipulation
* await client.tevmSetAccount({ address: "0x123...", balance: 100n });
* await client.tevmGetAccount({ address: "0x123..." });
*
* // Contract interactions
* await client.tevmContract({
* abi: [...],
* functionName: "transfer",
* args: ["0x456...", 1000n]
* });
*
* // Contract deployment
* const result = await client.tevmDeploy({
* abi: [...],
* bytecode: "0x...",
* args: ["Constructor", "Args"]
* });
*
* // Mining control
* await client.tevmMine({ blockCount: 5, interval: 10 });
*
* // State persistence
* const state = await client.tevmDumpState();
* await client.tevmLoadState(state);
* ```
*
* ### 2. Viem public actions
* ```typescript
* const balance = await client.getBalance({ address: "0x123..." });
* const blockNumber = await client.getBlockNumber();
* const code = await client.getCode({ address: "0x123..." });
* const logs = await client.getLogs({ address: "0x123..." });
* ```
*
* ### 3. Viem test actions
* ```typescript
* await client.setBalance({ address: "0x123...", value: 100n });
* await client.impersonateAccount({ address: "0x123..." });
* await client.mine({ blocks: 1 });
* await client.setStorageAt({ address, index, value });
* ```
*
* ### 4. Viem wallet actions
* ```typescript
* const hash = await client.sendTransaction({
* from: "0x123...",
* to: "0x456...",
* value: 1000n
* });
* ```
*
* ## Forking Networks
*
* The MemoryClient can fork from any EVM-compatible network, creating a local copy that
* lazily loads state from the remote network as needed:
*
* ```typescript
* import { createMemoryClient, http } from "tevm";
* import { optimism } from "tevm/common";
*
* const forkedClient = createMemoryClient({
* // Fork specification
* fork: {
* transport: http("https://mainnet.optimism.io")({}),
* blockTag: '0xa6a63cd70fbbe396321ca6fe79e1b6735760c03538208b50d7e3a5dac5226435',
* },
* // Always specify chain configuration for optimal performance
* common: optimism,
* });
* ```
*
* The `common` object extends the viem chain interface with EVM-specific information.
* Always use `tevm/common` chains rather than `viem/chains` when working with TEVM.
*
* ## Mining Modes
*
* TEVM supports three mining modes:
*
* ```typescript
* // 1. Manual mining (default)
* const client = createMemoryClient({ mining: { auto: false } });
* await client.sendTransaction(...); // Transaction is pending
* await client.tevmMine(); // Now transaction is processed
*
* // 2. Auto-mining (mine after every transaction)
* const autoClient = createMemoryClient({ mining: { auto: true } });
* await autoClient.sendTransaction(...); // Automatically mined
*
* // 3. Interval mining (mine periodically)
* const intervalClient = createMemoryClient({
* mining: { interval: 5000 } // Mine every 5 seconds
* });
* ```
*
* ## Server Mode
*
* TEVM can be exposed as an HTTP JSON-RPC server with `@tevm/server`:
*
* ```typescript
* import { createServer } from "tevm/server";
* import { createMemoryClient } from "tevm";
*
* const memoryClient = createMemoryClient();
* const server = createServer({
* request: memoryClient.request,
* });
*
* server.listen(8545, () => console.log("TEVM running on port 8545"));
* ```
*
* This allows any Ethereum tool or library to connect to your TEVM instance:
*
* ```typescript
* import { createPublicClient, http } from "viem";
* import { mainnet } from "viem/chains";
*
* const publicClient = createPublicClient({
* chain: mainnet,
* transport: http("http://localhost:8545"),
* });
*
* console.log(await publicClient.getChainId());
* ```
*
* ## State Persistence
*
* TEVM state can be persisted between sessions with the `persister` option:
*
* ```typescript
* import { createMemoryClient } from "tevm";
* import { createSyncPersister } from "tevm/sync-storage-persister";
*
* // Browser example with localStorage
* const browserClient = createMemoryClient({
* persister: createSyncPersister({
* storage: localStorage,
* key: 'my-tevm-state'
* }),
* });
*
* // Node.js example with file system
* import { FileStorage } from "tevm/sync-storage-persister/node";
* const nodeClient = createMemoryClient({
* persister: createSyncPersister({
* storage: new FileStorage('./tevm-state.json'),
* }),
* });
* ```
*
* ## Direct Solidity Imports
*
* When used with the TEVM bundler plugins, you can import Solidity files directly:
*
* ```typescript
* import { createMemoryClient } from "tevm";
* import { MyERC721 } from './MyERC721.sol';
*
* const client = createMemoryClient();
*
* // Deploy the contract
* const deployed = await client.tevmDeploy(
* MyERC721.deploy("My NFT", "NFT")
* );
* await client.tevmMine();
*
* // Create contract instance with the deployed address
* const nft = MyERC721.withAddress(deployed.createdAddress);
*
* // Call contract methods
* await client.tevmContract({
* ...nft.write.mint('0x123...', 1),
* from: '0x123...',
* });
*
* await client.tevmMine();
*
* const balance = await client.tevmContract(nft.read.balanceOf('0x123...'));
* console.log(balance); // 1n
* ```
*
* This requires setting up one of the TEVM bundler plugins (vite, webpack, esbuild, etc.).
*
* ## Network Support
*
* TEVM officially supports:
* - Ethereum mainnet and testnets
* - OP Stack chains (Optimism, Base, etc.)
*
* Other EVM chains are likely to work but not officially tested. Chain configuration
* is available through `tevm/common`.
*
* ## Advanced EVM Features
*
* TEVM includes advanced EVM features, with the following enabled by default:
* - EIP-1559 Fee Market
* - EIP-4895 (Beacon chain withdrawals)
* - EIP-4844 (Blob transactions)
* - EIP-4788 (Beacon root in EVM)
*
* ## Optimizing Bundle Size
*
* For UI applications concerned with bundle size, use tree-shakeable actions with `createTevmNode()`
* and individual actions from `tevm/actions`. See the [actions API guide](https://tevm.sh/learn/actions/)
* for details.
*/
declare const createMemoryClient: CreateMemoryClientFn;
declare function createTevmTransport(options?: _tevm_node.TevmNodeOptions): TevmTransport;
/**
* A type representing the handler for a TEVM contract procedure.
*
* This type reuses the viem `contractRead`/`contractWrite` API to encode ABI, function name, and arguments.
*
* @template TAbi - The ABI of the contract.
* @template TFunctionName - The name of the contract function.
*
* @param {Client<TevmTransport<string>>} client - The viem client configured with TEVM transport.
* @param {ContractParams<TAbi, TFunctionName>} params - Parameters for the contract method call, including ABI, function name, and arguments.
* @returns {Promise<ContractResult<TAbi, TFunctionName>>} The result of the contract method call.
*
* @example
* ```typescript
* import { tevmContract } from 'tevm/actions'
* import { createClient, http } from 'viem'
* import { optimism } from 'tevm/common'
* import { createTevmTransport } from 'tevm'
*
* const client = createClient({
* transport: createTevmTransport({
* fork: { transport: http('https://mainnet.optimism.io')({}) }
* }),
* chain: optimism,
* })
*
* async function example() {
* const res = await tevmContract(client, {
* abi: [...],
* functionName: 'myFunction',
* args: [...],
* })
* console.log(res)
* }
*
* example()
* ```
*
* @see [ContractParams](https://tevm.sh/reference/tevm/actions/type-aliases/contractparams/) for options reference.
* @see [ContractResult](https://tevm.sh/reference/tevm/actions/type-aliases/contractresult/) for return values reference.
* @see [BaseCallParams](https://tevm.sh/reference/tevm/actions/type-aliases/basecallparams-1/) for the base call parameters.
*/
type TevmContract = <TAbi extends Abi | readonly unknown[] = Abi, TFunctionName extends ContractFunctionName<TAbi> = ContractFunctionName<TAbi>>(client: Client<TevmTransport<string>>, params: ContractParams<TAbi, TFunctionName> & CallEvents) => Promise<ContractResult<TAbi, TFunctionName>>;
/**
* A custom [viem extension](https://viem.sh/docs/clients/custom#extending-with-actions-or-configuration) for adding powerful
* Tevm specific actions to the client. These actions come preloaded with [MemoryClient](https://tevm.sh/reference/tevm/memory-client/type-aliases/memoryclient/)
* To add these actions use the `extend` method on a TevmClient with the tevmViemActions() extension.
* @example
* ```typescript
* import { createTevmClient, tevmViemActions } from 'tevm'
*
* const client = createTevmClient()
* .extend(tevmViemActions())
* ```
*/
type TevmViemActionsApi = {
tevmReady: TevmNode['ready'];
tevmCall: TevmActionsApi['call'];
tevmContract: TevmActionsApi['contract'];
tevmDeploy: TevmActionsApi['deploy'];
tevmMine: TevmActionsApi['mine'];
tevmLoadState: TevmActionsApi['loadState'];
tevmDumpState: TevmActionsApi['dumpState'];
tevmSetAccount: TevmActionsApi['setAccount'];
tevmGetAccount: TevmActionsApi['getAccount'];
tevmDeal: TevmActionsApi['deal'];
};
declare function tevmCall(client: viem.Client<TevmTransport<string>>, params: _tevm_actions.CallParams): Promise<_tevm_actions.CallResult>;
/**
* A tree-shakeable version of the `tevmContract` action for viem.
* Provides a high-level interface for contract interactions with automatic encoding/decoding and full type safety.
*
* While `tevmCall` offers a low-level interface for raw EVM execution, `tevmContract` provides a more convenient
* developer experience for standard contract interactions by:
*
* - Automatically encoding function parameters based on the ABI
* - Automatically decoding return values to the appropriate JavaScript types
* - Properly handling and decoding revert messages from failed calls
* - Maintaining full type safety with TypeScript when using properly typed ABIs
* - Simplifying complex contract interactions with a cleaner interface
*
* Internally, `tevmContract` wraps the lower-level `tevmCall` action, handling all the ABI encoding/decoding
* logic while providing access to the same advanced features like execution tracing and EVM customization.
*
* @type {import('./TevmContractType.js').TevmContract}
*
* @example
* ```typescript
* import { tevmContract } from 'tevm/actions'
* import { createClient, http, parseAbi } from 'viem'
* import { optimism } from 'tevm/common'
* import { createTevmTransport } from 'tevm'
*
* const client = createClient({
* transport: createTevmTransport({
* fork: { transport: http('https://mainnet.optimism.io')({}) }
* }),
* chain: optimism,
* })
*
* async function example() {
* // Define the contract ABI
* const abi = parseAbi([
* 'function balanceOf(address owner) view returns (uint256)',
* 'function transfer(address to, uint256 amount) returns (bool)'
* ])
*
* // Read from contract (view function)
* const balance = await tevmContract(client, {
* abi,
* address: '0x4200000000000000000000000000000000000042', // OP token
* functionName: 'balanceOf',
* args: ['0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'],
* })
* console.log(`Balance: ${balance}`) // Returns the decoded uint256 as a bigint
*
* // Write to contract (non-view function with impersonation)
* const result = await tevmContract(client, {
* abi,
* address: '0x4200000000000000000000000000000000000042', // OP token
* functionName: 'transfer',
* args: ['0x1234567890123456789012345678901234567890', 100n],
* from: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', // Impersonate this address
* createTransaction: true, // Create actual transaction that needs mining
* })
*
* // Transaction needs to be mined to take effect
* await client.mine()
*
* console.log(`Transfer result: ${result}`) // true
*
* // Optional: With execution tracing
* const tracedResult = await tevmContract(client, {
* abi,
* address: '0x4200000000000000000000000000000000000042',
* functionName: 'balanceOf',
* args: ['0x1234567890123456789012345678901234567890'],
* onStep: (step, next) => {
* console.log(`Opcode: ${step.opcode.name}`)
* next()
* }
* })
* }
*
* example()
* ```
*
* @example
* ```typescript
* // Using with TEVM contract imports from the bundler
* import { tevmContract } from 'tevm/actions'
* import { createClient } from 'viem'
* import { createTevmTransport } from 'tevm'
* import { MyToken } from './MyToken.sol' // Direct Solidity import
*
* const client = createClient({
* transport: createTevmTransport(),
* chain: {
* id: 1,
* name: 'Local TEVM'
* }
* })
*
* async function example() {
* // Deploy the contract first
* const deployResult = await tevmDeploy(client, MyToken.deploy("My Token", "MTK"))
* await client.mine()
*
* // Now use tevmContract with the imported contract
* const result = await tevmContract(client, {
* ...MyToken.read.balanceOf(), // Spread the contract's read method
* args: ['0x1234567890123456789012345678901234567890'],
* address: deployResult.createdAddress,
* })
*
* console.log(`Balance: ${result}`)
* }
* ```
*
* @see [ContractParams](https://tevm.sh/reference/tevm/actions/type-aliases/contractparams/) for options reference.
* @see [ContractResult](https://tevm.sh/reference/tevm/actions/type-aliases/contractresult/) for return values reference.
* @see [BaseCallParams](https://tevm.sh/reference/tevm/actions/type-aliases/basecallparams-1/) for the base call parameters.
* @see [tevmCall](https://tevm.sh/reference/tevm/memory-client/functions/tevmcall/) for the lower-level call interface.
* @see [TEVM Actions Guide](https://tevm.sh/learn/actions/)
* @see [TEVM Contracts Guide](https://tevm.sh/learn/contracts/)
* @throws Will throw if the contract call reverts. The error will contain the decoded revert reason when available.
*/
declare const tevmContract: TevmContract;
declare function tevmDeploy(client: viem.Client<TevmTransport<string>>, params: _tevm_actions.DeployParams & _tevm_actions.CallEvents): Promise<_tevm_actions.DeployResult>;
declare function tevmDumpState(client: viem.Client<TevmTransport<string>>): Promise<_tevm_actions.DumpStateResult>;
declare function tevmGetAccount(client: viem.Client<TevmTransport<string>>, params: _tevm_actions.GetAccountParams): Promise<_tevm_actions.GetAccountResult>;
declare function tevmLoadState(client: viem.Client<TevmTransport<string>>, params: _tevm_actions.LoadStateParams): Promise<_tevm_actions.LoadStateResult>;
declare function tevmMine(client: viem.Client<TevmTransport<string>>, params?: _tevm_actions.MineParams): Promise<_tevm_actions.MineResult>;
declare function tevmReady(client: viem.Client<TevmTransport<string>>): Promise<true>;
declare function tevmSetAccount(client: viem.Client<TevmTransport<string>>, params: _tevm_actions.SetAccountParams): Promise<_tevm_actions.SetAccountResult>;
declare function tevmViemActions(): (client: viem.Client<TevmTransport<string>>) => TevmViemActionsApi;
export { type CreateMemoryClientFn, type MemoryClient, type MemoryClientOptions, type TevmActions, type TevmContract, type TevmRpcSchema, type TevmTransport, type TevmViemActionsApi, createMemoryClient, createTevmTransport, tevmCall, tevmContract, tevmDeploy, tevmDumpState, tevmGetAccount, tevmLoadState, tevmMine, tevmReady, tevmSetAccount, tevmViemActions };