import { Common } from '@tevm/common'; import { LogOptions, Logger } from '@tevm/logger'; import { Predeploy } from '@tevm/predeploys'; import * as _tevm_state from '@tevm/state'; import { StateOptions, TevmState } from '@tevm/state'; import { SyncStoragePersister } from '@tevm/sync-storage-persister'; import * as _tevm_evm from '@tevm/evm'; import { Block, JsonHeader } from '@tevm/block'; import { TxReceipt, ReceiptsManager } from '@tevm/receipt-manager'; import { TxPool } from '@tevm/txpool'; import * as _tevm_utils from '@tevm/utils'; import { Address, Hex } from '@tevm/utils'; import { Vm } from '@tevm/vm'; import { GetFilterLogsReturnType, EIP1193RequestFn } from 'viem'; import { TypedTransaction, ImpersonatedTx } from '@tevm/tx'; /** * TODO This should be publically exported from ethereumjs but isn't * Typing this by hand is tedious so we are using some typescript inference to get it * do a pr to export this from ethereumjs and then replace this with an import * TODO this should be modified to take a hex address rather than an ethjs address to be consistent with rest of Tevm */ /** * Custom precompiles allow you to run arbitrary JavaScript code in the EVM */ type CustomPrecompile = Exclude[0], undefined>['customPrecompiles'], undefined>[number]; /** * Mining configuration that creates blocks at fixed time intervals. * @example * ```typescript * import { IntervalMining } from '@tevm/node' * * const value: IntervalMining = { * type: 'interval', * interval: 5000 // Mine blocks every 5 seconds * } * ``` */ type IntervalMining = { type: 'interval'; interval: number; }; /** * Mining configuration where blocks are only created when explicitly requested. * Transactions remain in the mempool until manually mined. * @example * ```typescript * import { ManualMining } from '@tevm/node' * * const value: ManualMining = { * type: 'manual' * } * * // Later blocks can be mined manually: * // await client.mine({ blocks: 1 }) * ``` */ type ManualMining = { type: 'manual'; }; /** * Mining configuration that automatically mines blocks for every transaction. * Each transaction is immediately included in its own block. * @example * ```typescript * import { AutoMining } from '@tevm/node' * * const value: AutoMining = { * type: 'auto' * } * ``` */ type AutoMining = { type: 'auto'; }; /** * Mining configuration that mines blocks when accumulated gas usage exceeds a threshold. * Useful for simulating realistic block filling behavior. * @example * ```typescript * import { GasMining } from '@tevm/node' * * const value: GasMining = { * type: 'gas', * limit: 15000000n // Mine when gas used exceeds 15M * } * ``` */ type GasMining = { type: 'gas'; limit: BigInt; }; /** * Configuration options for controlling block mining behavior. * Union of all mining strategy types. * @example * ```typescript * import { MiningConfig } from '@tevm/node' * import { createMemoryClient } from 'tevm' * * // Choose one of the mining strategies * const miningConfig: MiningConfig = { * type: 'interval', * interval: 2000 // Mine every 2 seconds * } * * const client = createMemoryClient({ * mining: miningConfig * }) * ``` */ type MiningConfig = IntervalMining | ManualMining | AutoMining | GasMining; /** * Options for creating an Tevm MemoryClient instance */ type TevmNodeOptions = StateOptions & { /** * The common used of the blockchain. Defaults to tevmDevnet. Required for some APIs such as `getEnsAddress` to work. If not specified and a fork is provided the common chainId will be fetched from the fork * Highly recomended you always set this in fork mode as it will speed up client creation via not having to fetch the chain info * @example * ``` * import { optimism } from 'tevm/chains' * import { createMemoryClient } from 'tevm'} * * const client = createMemoryClient({ chain: optimism }) * ```` * ` */ readonly common?: TCommon; /** * Configure logging options for the client */ readonly loggingLevel?: LogOptions['level']; /** * The configuration for mining. Defaults to 'auto' * - 'auto' will mine a block on every transaction * - 'interval' will mine a block every `interval` milliseconds * - 'manual' will not mine a block automatically and requires a manual call to `mineBlock` */ readonly miningConfig?: MiningConfig; /** * Enable profiler. Defaults to false. */ readonly profiler?: boolean; /** * Custom precompiles allow you to run arbitrary JavaScript code in the EVM. * See the [Precompile guide](https://todo.todo) documentation for a deeper dive * An ever growing standard library of precompiles is provided at `tevm/precompiles` * @notice Not implemented yet {@link https://github.com/evmts/tevm-monorepo/pull/728/files | Implementation pr } * * Below example shows how to make a precompile so you can call `fs.writeFile` and `fs.readFile` in your contracts. * Note: this specific precompile is also provided in the standard library * * For security precompiles can only be added statically when the vm is created. * @example * ```ts * import { createMemoryClient, defineCall, definePrecompile } from 'tevm' * import { createContract } from '@tevm/contract' * import fs from 'fs/promises' * * const Fs = createContract({ * name: 'Fs', * humanReadableAbi: [ * 'function readFile(string path) returns (string)', * 'function writeFile(string path, string data) returns (bool)', * ] * }) * * const fsPrecompile = definePrecompile({ * contract: Fs, * address: '0xf2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2', * call: defineCall(Fs.abi, { * readFile: async ({ args }) => { * return { * returnValue: await fs.readFile(...args, 'utf8'), * executionGasUsed: 0n, * } * }, * writeFile: async ({ args }) => { * await fs.writeFile(...args) * return { returnValue: true, executionGasUsed: 0n } * }, * }), * }) * * const tevm = createMemoryClient({ customPrecompiles: [fsPrecompile] }) */ readonly customPrecompiles?: CustomPrecompile[]; /** * Custom predeploys allow you to deploy arbitrary EVM bytecode to an address. * This is a convenience method and equivalent to calling tevm.setAccount() manually * to set the contract code. * ```typescript * const tevm = createMemoryClient({ * customPredeploys: [ * // can pass a `tevm Script` here as well * { * address: '0x420420...', * abi: [...], * deployedBytecode: '0x420420...', * } * ], * }) * ``` */ readonly customPredeploys?: ReadonlyArray>; /** * Enable/disable unlimited contract size. Defaults to false. * If set to true you may still run up against block limits */ readonly allowUnlimitedContractSize?: boolean; /** * The memory client can optionally initialize and persist it's state to an external source like local storage * using `createSyncPersister` * @example * ```typescript * import { createMemoryClient, createSyncPersister } from 'tevm' * * const persister = createSyncPersister({ * storage: { * getItem: (key: string) => localStorage.getItem(key), * setItem: (key: string, value: string) => localStorage.setItem(key, value), * } * }) * * const memoryClient = createMemoryClient({ persister }) * ``` */ readonly persister?: SyncStoragePersister; }; /** * @deprecated Use {@link TevmNodeOptions} instead. */ type BaseClientOptions = TevmNodeOptions; type ProviderConnectInfo = { chainId: string; }; type ProviderMessage = { type: string; data: unknown; }; declare class ProviderRpcError extends Error { code: number; details: string; constructor(code: number, message: string); } type EIP1193EventMap = { accountsChanged(accounts: Address[]): void; chainChanged(chainId: string): void; connect(connectInfo: ProviderConnectInfo): void; disconnect(error: ProviderRpcError): void; message(message: ProviderMessage): void; newPendingTransaction(tx: TypedTransaction | ImpersonatedTx): void; newReceipt(receipt: TxReceipt): void; newBlock(block: Block): void; newLog(log: GetFilterLogsReturnType[number]): void; }; type EIP1193Events = { on(event: TEvent, listener: EIP1193EventMap[TEvent]): void; removeListener(event: TEvent, listener: EIP1193EventMap[TEvent]): void; }; /** * A very minimal EventEmitter interface */ type EIP1193EventEmitter = EIP1193Events & { /** * Emit an event. * @param {string | symbol} eventName - The event name. * @param {...any} args - Arguments to pass to the event listeners. * @returns {boolean} True if the event was emitted, false otherwise. */ emit(eventName: keyof EIP1193EventMap, ...args: any[]): boolean; }; type FilterType = 'PendingTransaction' | 'Block' | 'Log'; type TODO = any; /** * Internal representation of a registered filter */ type Filter = { /** * Id of the filter */ id: Hex; /** * The type of the filter */ type: FilterType; /** * Creation timestamp */ created: number; /** * Criteria of the logs * https://github.com/ethereum/go-ethereum/blob/master/eth/filters/filter_system.go#L329 */ logsCriteria?: TODO; /** * Stores logs */ logs: Array; /** * stores tx */ tx: Array; /** * Stores the blocks */ blocks: Array; /** * Not sure what this is yet */ installed: {}; /** * Error if any */ err: Error | undefined; /** * Listeners registered for the filter */ registeredListeners: Array<(...args: Array) => any>; }; /** * The base client used by Tevm. Add extensions to add additional functionality */ type TevmNode = { /** * The logger instance */ readonly logger: Logger; /** * Interface for querying receipts and historical state */ readonly getReceiptsManager: () => Promise; /** * The configuration for mining. Defaults to 'auto' * - 'auto' will mine a block on every transaction * - 'interval' will mine a block every `interval` milliseconds * - 'manual' will not mine a block automatically and requires a manual call to `mineBlock` */ readonly miningConfig: MiningConfig; /** * Client to make json rpc requests to a forked node * @example * ```ts * const client = createMemoryClient({ request: eip1193RequestFn }) * ``` */ readonly forkTransport?: { request: EIP1193RequestFn; }; /** * The mode the current client is running in * `fork` mode will fetch and cache all state from the block forked from the provided URL * `normal` mode will not fetch any state and will only run the EVM in memory * @example * ```ts * let client = createMemoryClient() * console.log(client.mode) // 'normal' * client = createMemoryClient({ forkUrl: 'https://mainnet.infura.io/v3/your-api-key' }) * console.log(client.mode) // 'fork' * ``` */ readonly mode: TMode; /** * Returns promise that resulves when the client is ready * The client is usable without calling this method but may * have extra latency on the first call from initialization * @example * ```ts * const client = createMemoryClient() * await client.ready() * ``` */ readonly ready: () => Promise; /** * Internal instance of the VM. Can be used for lower level operations. * Normally not recomended to use unless building libraries or extensions * on top of Tevm. */ readonly getVm: () => Promise; /** * Gets the pool of pending transactions to be included in next block */ readonly getTxPool: () => Promise; /** * The currently impersonated account. This is only used in `fork` mode */ readonly getImpersonatedAccount: () => Address | undefined; /** * Sets the account to impersonate. This will allow the client to act as if it is that account * On Ethereum JSON_RPC endpoints. Pass in undefined to stop impersonating */ readonly setImpersonatedAccount: (address: Address | undefined) => void; /** * Extends the base client with additional functionality. This enables optimal code splitting * and extensibility */ readonly extend: >(decorator: (client: TevmNode) => TExtension) => TevmNode; /** * Creates a new filter to watch for logs events and blocks */ readonly setFilter: (filter: Filter) => void; /** * Gets all registered filters mapped by id */ readonly getFilters: () => Map; /** * Removes a filter by id */ readonly removeFilter: (id: Hex) => void; /** * Returns status of the client * - INITIALIZING: The client is initializing * - READY: The client is ready to be used * - SYNCING: The client is syncing with the forked node * - MINING: The client is mining a block */ status: 'INITIALIZING' | 'READY' | 'SYNCING' | 'MINING' | 'STOPPED'; /** * Copies the current client state into a new client */ readonly deepCopy: () => Promise>; /** * Returns debug information about the current node state * including chain details, status, mode, mining config, filters, * blocks, mempool transactions, and state */ readonly debug?: () => Promise<{ chainName: string; status: 'INITIALIZING' | 'READY' | 'SYNCING' | 'MINING' | 'STOPPED'; mode: TMode; miningConfig: MiningConfig; registeredFilters: Map; blocks: { latest?: JsonHeader | undefined; forked?: JsonHeader | undefined; }; txsInMempool: number; state: TevmState; hardfork: string; eips: number[]; chainId: number; receipts: Awaited>; }>; } & EIP1193EventEmitter & TExtended; declare function createTevmNode(options?: TevmNodeOptions): TevmNode; type Extension = (client: TevmNode) => TExtended; /** * These are the same accounts hardhat and anvil start with 10000 eth * Also including zero address * @type {ReadonlyArray} */ declare const prefundedAccounts: ReadonlyArray<_tevm_utils.Address>; /** * @type {import('@tevm/state').TevmState} */ declare const GENESIS_STATE: _tevm_state.TevmState; /** * Ethereum hardfork option */ type Hardfork = 'chainstart' | 'homestead' | 'dao' | 'tangerineWhistle' | 'spuriousDragon' | 'byzantium' | 'constantinople' | 'petersburg' | 'istanbul' | 'muirGlacier' | 'berlin' | 'london' | 'arrowGlacier' | 'grayGlacier' | 'mergeForkIdTransition' | 'paris' | 'shanghai' | 'cancun' | 'prague' | 'osaka'; export { type AutoMining, type BaseClientOptions, type CustomPrecompile, type EIP1193EventEmitter, type EIP1193EventMap, type EIP1193Events, type Extension, type Filter, type FilterType, GENESIS_STATE, type Hardfork, type IntervalMining, type ManualMining, type MiningConfig, type ProviderConnectInfo, type ProviderMessage, ProviderRpcError, type TevmNode, type TevmNodeOptions, createTevmNode, prefundedAccounts };