Skip to main content

Overview

The Broker is a service that runs within the Bento proving stack. It is responsible for market interactions including bidding on jobs, locking them, issuing job requests to the Bento proving cluster, and submitting proof fulfillments onchain.

Broker Configuration

Broker will live-reload the broker.toml when it changes. In most cases, you will not need to restart the Broker for the configuration to take effect.
Broker configuration is primarily managed through the broker.toml file in the Boundless directory. This file is mounted into the Broker container and it is used to configure the Broker daemon.

Deposit / Balance

The Boundless market requires funds (ZKC) deposited as collateral before a prover can bid on requests. Brokers must first deposit some ZKC into the market contract to fund their account. These funds cover collateral during lock-in. It is recommend that a broker keep a balance on the market >= max_collateral (configured via broker.toml).

Deposit Collateral to the Market

You will need the Boundless CLI installed to deposit/check your balance. Please see Installing the Boundless CLI for instructions.
Terminal

Check Current Collateral Balance

Terminal
You can omit the PRIVATE_KEY environment variable here and specify your wallet_address as a optional parameter to the balance command, i.e., account balance 0x000....

Settings in Broker.toml

Quotation marks matter in TOML so please pay particular attention to the quotation marks for config values.
Below are all broker.toml settings organized by section:

[market] Settings

[prover] Settings

[batcher] Settings

[price_oracle] Settings

The price oracle fetches live ETH/USD and ZKC/USD exchange rates, enabling broker config values to be specified in USD. Chainlink (on-chain, ETH/USD only) and CoinGecko (off-chain, both pairs) are enabled by default; CoinMarketCap is optionally available with an API key. Prices from multiple sources are aggregated using the configured aggregation_mode. Example configuration with USD-denominated pricing:
Example per-requestor and per-selector pricing overrides:

Chain Monitor

v2.0 introduces a rewritten chain-watching layer, ChainMonitorV2, that replaces the legacy two-service architecture (ChainMonitorService + MarketMonitor). Instead of polling eth_getLogs for market events on every tick, ChainMonitorV2 uses eth_getBlockReceipts to fetch all receipts per block in a single call, then filters for market events locally. This reduces the number of RPC calls, especially on chains like Base where eth_getLogs is expensive or rate-limited. In steady state, ChainMonitorV2 requires roughly 2 RPC requests per block:
  • eth_getBlockByNumber to follow the chain head and get the base fee
  • eth_getBlockReceipts to get all receipts and transaction fee data
It also performs local EIP-1559 gas estimation from receipt data, removing the need for separate eth_feeHistory calls. On startup, ChainMonitorV2 uses adaptive log retrieval with binary-search chunking to auto-discover the maximum block range accepted by the RPC provider, catching up on any missed events for open orders. This means the broker won’t miss events if it restarts or experiences downtime.

Selecting the chain monitor

Selection is per-chain via the rpc_mode field under [market] in broker.toml (or in chain-overrides/broker.{chain_id}.toml):
broker.toml
  • "auto" (default): chain-specific default. Uses v2 for Base and most chains, legacy for Taiko (167000), where the public RPC rate-limits eth_getBlockReceipts.
  • "v2": pin to ChainMonitorV2.
  • "legacy": pin to the old ChainMonitorService + MarketMonitor pair (eth_getLogs-based).
You can tune the RPC request timeout (default 15s) to cut off hanging requests so the retry and fallback layers can activate:
Terminal

Sequential Fallback Transport

ChainMonitorV2 uses a SequentialFallbackTransport that tries RPC providers in priority order (rather than in parallel), minimizing calls to paid or metered fallback endpoints. When multiple RPC URLs are configured, the transport includes health tracking: it skips providers after consecutive failures and periodically retries them to detect recovery. The retry and fallback layers are stacked so that on a single RPC failure, the sequential fallback immediately tries the next URL. The outer retry layer only kicks in once all URLs have been exhausted.

Analyzing RPC Usage

To analyze RPC call patterns, enable debug logging for the relevant modules and pipe the output to a log file. An analysis script is available to parse these logs:
Terminal
Not all RPC providers support the eth_getBlockReceipts method that ChainMonitorV2 relies on. If your provider doesn’t support it, set rpc_mode = "legacy" for the affected chain. Free public RPCs are unreliable; use a dedicated RPC provider for production.

Broker Operation

Terminal

Benchmarking Bento

Start a bento cluster:
Terminal
Set the RPC_URL environment variable to the network the order is on:
Terminal
Then, run the benchmark:
Terminal
where IDS is a comma-separated list of request IDs from the network or order stream configured. It is recommended to pick a few requests of varying sizes and programs, biased towards larger proofs for a more representative benchmark. To run programs manually, and for performance optimizations, see performance optimizations.

Running the Broker service with bento

Running a broker with just will also start the Bento cluster through docker compose.
just installation instructions can be found here.
Terminal

Make sure Bento is running

A Broker needs a Bento instance to operate. Please follow the quick start guide to get Bento up and running.
To check Bento is running correctly, you can send a sample proof workload:
Before running this, install Bento CLI
Terminal

Running a standalone broker

To run broker with an already initialized Bento cluster or with a different prover, you can build and run a broker directly with the following:
Terminal

Stopping The Broker Service

Terminal
If running the broker on a network, there may be locked proofs that have not been fulfilled yet. Follow the Safe Upgrade Steps to ensure shutdown and/or restart without loss of stake.

Safe Upgrade Steps

There can be subtle breaking changes between releases that may affect your broker’s state. Following these upgrade steps helps minimize issues from state breaking changes.
When upgrading your Boundless broker to a new version, follow these steps to ensure a safe migration:
1

Stop the broker and optionally clean the database

Terminal
This will wait for any committed orders to finalize before shutting down. Avoid sending kill signals to the broker process and ensure either through the broker logs or through indexer that your broker does not have any incomplete locked orders before proceeding.
While it is generally not necessary to clear volumes unless specifically noted in release, it is recommended to avoid any potential state breaking changes.
2

Update to the new version

See releases for latest tag to use.
Terminal
3

Start the broker with the new version

Terminal

Running Multiple Brokers

You can run multiple broker instances simultaneously to serve different networks at the same time while sharing the same Bento cluster. The Docker compose setup supports this through the broker2 service example.

Multi-Broker Configuration

Each broker instance requires:
  1. Separate configuration file: Create different broker.toml files (e.g., broker.toml, broker2.toml, etc.)
  2. Different RPC URL: Use different chain endpoints via setting respective RPC_URL environment variables, or modifying the compose file manually (prover-compose.yml by default, compose.yml for the legacy stack).
  3. Optional separate private key: Use different PRIVATE_KEY variables if desired for different accounts on different networks.

Environment Variables for Multi-Broker Setup

If using the default compose file (prover-compose.yml, or compose.yml if PROVER_STACK=legacy is set) and uncommenting the second broker config:
[.env]
Then, create the new broker config file that the second broker will use:
Terminal
Then, modify configuration values for each network, keeping the following in mind:
  • The peak_prove_khz setting is shared across all brokers
    • For example, if you have benchmarked your broker to be able to prove at 500kHz, the values in each config should not sum up to be more than 500kHz.
  • max_concurrent_preflights defaults to 8 and should be set to a value that the bento cluster can keep up with
    • It is recommended that the max concurrent preflights across all networks is less than the number of exec agents you have specified in your compose file (prover-compose.yml by default, compose.yml for the legacy stack).
  • max_concurrent_proofs is a per-broker configuration, and is not shared across brokers
Then, just start the cluster as you normally would with:
Terminal

Broker Optimization

Increasing Lock-in Rate

Once your broker is running, there are a few methods to optimize the lock-in rate. These methods are aimed at making your broker service more competitive in the market through different means:
  1. Decreasing the min_mcycle_price would tune your Broker to bid at lower prices for proofs. This value can be specified in ETH (e.g., "0.00001 ETH") or USD (e.g., "0.02 USD").
  2. Increasing lockin_priority_gas expedites your market operations by consuming more gas which could help outrun other bidders.

Tuning Service Settings

The [prover] settings in broker.toml are used to configure the prover service and significantly impact the operation of the service. The most important configuration variable to monitor and iteratively tune is txn_timeout. This is the number of seconds to wait for a transaction to be confirmed before timing out. Therefore, if you see timeouts in your logs, txn_timeout can be increased to wait longer for transaction confirmations onchain.