Circuit Breaker
The circuit breaker prevents cascading RPC failures from overwhelming your agent. When simulation failures exceed a threshold, the breaker opens and blocks further simulation calls — returning immediate failures instead of waiting for timeouts.
createCircuitBreaker
import { createCircuitBreaker } from '@txfence/core'
const breaker = createCircuitBreaker({
failureThreshold: 5, // consecutive failures before opening
successThreshold: 2, // consecutive successes in half-open before closing
timeoutMs: 60000, // ms before transitioning open → half-open
onStateChange: (from, to) => {
console.log(`Circuit breaker: ${from} → ${to}`)
},
})All config fields are optional — defaults shown above.
Three states
closed — normal operation. Simulation calls pass through to the RPC.
open — breaker is tripped. Simulation returns immediately with success: false, coverageLevel: 'none' — no RPC call made. After timeoutMs, transitions to half-open.
half-open — probing. The next simulation call goes through to the RPC. If it succeeds, the success counter increments. After successThreshold consecutive successes, transitions back to closed. Any failure sends it back to open.
Wrapping an adapter
import { wrapAdapterWithCircuitBreaker } from '@txfence/core'
const protectedAdapter = wrapAdapterWithCircuitBreaker(
{ simulate: simulateEvmAction },
breaker,
'ethereum'
)
const agent = createAgent(
config,
{ ethereum: protectedAdapter },
rpcUrls,
executor
)The wrapped adapter is a drop-in replacement for the original — same interface, same usage.
Failure counting
What counts as a failure: the adapter throws an exception.
What does NOT count as a failure: simulation succeeds but wouldRevert: true. The RPC worked — the transaction would revert, which is useful information.
Manual reset
breaker.reset()For operational tooling — resets the breaker to closed state without waiting for timeoutMs.
Design
The circuit breaker is composable — wrap your adapter, not buried in the pipeline. This means you can apply different breakers to different chains, or share a breaker across multiple agents.
const ethereumBreaker = createCircuitBreaker({ failureThreshold: 3 })
const arbitrumBreaker = createCircuitBreaker({ failureThreshold: 10 })
const agent = createAgent(config, {
ethereum: wrapAdapterWithCircuitBreaker(evmAdapter, ethereumBreaker, 'ethereum'),
arbitrum: wrapAdapterWithCircuitBreaker(evmAdapter, arbitrumBreaker, 'arbitrum'),
}, rpcUrls, executor)