Skip to content
LogoLogo

createOptimisticHandler

Creates the optimistic handler: installs the storage and write interceptors, starts watching the local txpool and your Stash, and returns the optimistic read, subscription and sync APIs.

import { createOptimisticHandler } from '@tevm/mud'
 
function createOptimisticHandler<TConfig extends StoreConfig = StoreConfig>(
	options: CreateOptimisticHandlerOptions<TConfig>,
): CreateOptimisticHandlerResult<TConfig>

Parameters

CreateOptimisticHandlerOptions<TConfig>

OptionTypeDefaultDescription
clientClient | SessionClientA viem client connected to a chain. Write interception requires an EntryKit-style SessionClient.
storeAddressAddressAddress of the MUD Store / World contract.
stashStash<TConfig>The MUD Stash holding canonical state.
configTConfigundefinedYour mud.config.ts. Type-level only — it narrows TConfig so table types flow through the read APIs.
sync.enabledbooleantrueOnly read by OptimisticWrapperProvider, which uses it to decide whether to mount MUD's SyncProvider.
sync.startBlockbigint0nBlock to start syncing from, when the provider owns sync.
loggingLevel'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal''warn'Level for the handler's logger and the underlying Tevm clients.

Returns

CreateOptimisticHandlerResult<TConfig>

getOptimisticState()

getOptimisticState(): State<TConfig>

The canonical Stash state with the optimistic overlay applied. A fresh object each call — do not use identity comparison on it.

getOptimisticRecord(args)

getOptimisticRecord(args: Omit<GetRecordArgs<TTable, TDefaultValue>, 'stash'>): GetRecordResult<TTable, TDefaultValue>

Same signature as getRecord from @latticexyz/stash, minus stash. If state is omitted it defaults to the optimistic state; pass an explicit state to read a snapshot you already have. With a defaultValue, the result is non-optional.

getOptimisticRecords(args)

getOptimisticRecords(args: Omit<GetRecordsArgs<TTable>, 'stash'>): GetRecordsResult<TTable>

Same as getRecords, against the optimistic state.

subscribeOptimisticState(args)

subscribeOptimisticState(args: { subscriber: StoreUpdatesSubscriber }): Unsubscribe

Subscribes to both canonical Stash updates and optimistic overlay updates. The subscriber receives MUD's StoreUpdates ({ type: 'records' | 'config', updates }). Call the returned function to unsubscribe from both.

subscribeTx(args)

subscribeTx(args: { subscriber: TxStatusSubscriber }): Unsubscribe

Subscribes to TxStatus events for every intercepted write. See Transaction status.

syncAdapter

syncAdapter: SyncAdapter

A @latticexyz/store-sync adapter that writes canonical logs into your Stash through the same coordinator as optimistic recomputes, and reconciles canonical transactions with their optimistic counterparts. See Syncing canonical state.

_

Internal escape hatch — not covered by semver.

FieldTypeDescription
_.optimisticClientMemoryClientTevm client owning the optimistic txpool.
_.internalClientMemoryClientTevm client used to replay the pool.
_.optimisticStoreSubscribersStoreSubscribersStore-level optimistic subscribers.
_.optimisticTableSubscribersTableSubscribersTable-level optimistic subscribers.
_.cleanup() => Promise<void>Unsubscribes from txpool and Stash. Always await this on teardown.

Throws

  • Error('Client must be connected to a chain') — thrown synchronously when client.chain is undefined.

Example

optimistic.ts
import { createStash } from '@latticexyz/stash/internal'
import { createOptimisticHandler } from '@tevm/mud'
import mudConfig from './mud.config'
import { client } from './client'
 
const stash = createStash(mudConfig)
 
const optimistic = createOptimisticHandler({
	client,
	storeAddress: '0x5FbDB2315678afecb367f032d93F642f64180aa3',
	stash,
	config: mudConfig,
	loggingLevel: 'warn',
})
 
const position = optimistic.getOptimisticRecord({
	table: mudConfig.tables.app__Position,
	key: { player: '0x0000000000000000000000000000000000000001' },
	defaultValue: { x: 0, y: 0 },
})
 
const unsubscribe = optimistic.subscribeOptimisticState({
	subscriber: ({ updates }) => console.log(updates),
})
 
// teardown
unsubscribe()
await optimistic._.cleanup()