Skip to content

Network participant branch

Searcher Integration

This guide is for searchers that build on TOOL commitments created from OFP or external builder orderflow.

Value Proposition

Searchers can observe the commitment pool, build solutions on top of source commitments, and compete to add value while TOOL enforces delivery boundaries: a callback sees only its own source's transactions, and a solution reaches only the builders every base allows. See Delivery Rules.

Searcher Position In The Architecture

Searchers participate inside the TOOL network. They are not source integrators on the same integration plane as OFPs or external builders. The source side submits private flow; TOOL turns valid source flow into commitments; searchers consume the allowed commitment view and submit native TOOL bundles back to TOOL.

flowchart TB
  subgraph SourceSide["External source side"]
    direction TB
    OFP["OFP"]
    Builder["External PBS builder"]
    SourceFlow["Private source orderflow"]
    OFP --> SourceFlow
    Builder --> SourceFlow
  end

  subgraph ToolNetwork["TOOL network"]
    direction TB
    subgraph ToolTEE["TOOL node TEE environment"]
      direction TB
      Intake["Source intake"]
      CommitmentFeed["Commitment feed<br/>policy-controlled view"]
      Validation["Simulation and validation"]
      Routing["Callback and native routing"]
      Intake -->|"create source commitment"| CommitmentFeed
      Validation -->|"accepted enriched commitment"| Routing
    end

    subgraph SearcherContext["Searcher context"]
      direction TB
      Strategy["Searcher / solver logic"]
      Bundle["Native TOOL bundle<br/>source commitments + searcher txs"]
      CommitmentFeed -->|"allowed commitment metadata"| Strategy
      Strategy -->|"construct opportunity"| Bundle
      Bundle -->|"tool_simulateBundle / tool_sendBundle"| Validation
    end
  end

  SourceFlow -->|"eth_sendBundle or source path"| Intake

  style SourceSide fill:#f8fafc,stroke:#64748b,stroke-width:2px
  style ToolNetwork fill:#edf7f5,stroke:#0f8b6f,stroke-width:2px
  style ToolTEE fill:#eef2ff,stroke:#315fbe,stroke-width:2px
  style SearcherContext fill:#fff7ed,stroke:#a56812,stroke-width:2px

Node Access

A searcher runs a TOOL node and calls the methods in Searcher API Workflow from a container inside the same TEE as the node. The TOOL API is not exposed to the internet. To set up a TOOL node, see Running a TOOL Node.

Alternatively, a searcher can send bundles over HTTPS to a node's public RPC on port 8545 with eth_sendBundle. Send an X-Flashbots-Signature header with each request to the public RPC, as described in Conventions. TEE attestation covers the public RPC (the eth, ofp and tee methods), not the TOOL API. Before sending private flow to a node's public RPC, verify the node with tee_getAttestation.

Searcher Flow

sequenceDiagram
  autonumber
  participant Source as OFP / builder
  participant TOOL as TOOL
  participant Searcher as Searcher
  participant Callback as Source callback
  participant Native as TOOL block path

  Source->>TOOL: Submit source orderflow
  TOOL->>TOOL: Validate and create source commitment
  TOOL-->>Searcher: Commitment event or allowed view
  Searcher->>TOOL: tool_simulateBundle(native bundle)
  Searcher->>TOOL: tool_sendBundle(enriched bundle)
  TOOL->>TOOL: Validate enriched bundle
  alt every base has the same callback
    TOOL->>Callback: Solution (source txs + searcher txs)
  else mixed-origin
    TOOL->>Native: Builders in the intersection, or relay-only
  end

Searcher API Workflow

Searcher integrations usually follow the same API sequence: observe the allowed commitment view, size the opportunity against the current block, simulate when latency allows, then submit before the relevant subslot deadline.

Step Surface
Observe commitments and timing events tool_subscribe
Check current block-building constraints tool_nextBlockParams
Evaluate a native bundle without propagation tool_simulateBundle
Submit a native bundle for validation and routing tool_sendBundle

The native bundle request uses the ToolBundle schema. A typical searcher bundle builds on a source commitment and adds the searcher's backrun or other signed transactions.

Submitting Solutions

tool_sendBundle creates a solution, stores it, gossips it, and starts its delivery in the background. tool_simulateBundle runs the same preparation and returns the commitment without storing or delivering anything.

A bundle needs new transactions, based commitments, or both. Blob transactions are not supported.

You send You get
New transactions only A top-of-block solution: all builders, no callback
One base plus your transactions The base's callback and the base's builders
Several bases Builders: the intersection. Callback: kept only if every base has the same one, otherwise mixed-origin

Read the returned commitment to see where the solution goes. callbackUrl in JSON is a hash of the stored value, never the URL:

callbackUrl in the response extBuilders Where the solution goes
a hash other than the mixed-origin one any that callback, and the builders if any
absent, or the mixed-origin hash non-empty the listed builders
absent, or the mixed-origin hash absent nowhere from this node: relay-only

The mixed-origin marker appears as 0x412ef0d083d26bfee59b608aa779a3b180b7b1c2f59dbb9b944c2df04be67fcf (keccak256 of its RLP encoding).

Your transactions are not private

The OFP sees them in the quote and in the signed callback, and builders receive them.

Callback and Builders of a Solution

A callback sees only its own source's transactions. Bases are processed in order: the first base sets the callback, and any later base with a different callback, including empty against non-empty, turns it into mixed-origin. mixed-origin is irreversible, so a base without a callback is not neutral.

Bases Callback of the solution
X X
X and X X
X and a base without a callback mixed-origin
X and Y mixed-origin
two bases without a callback empty
anything with a mixed-origin base mixed-origin

Builders. The first base's list is copied; each next base removes the names it lacks. An empty result is not an error by itself, but a solution with no callback and no builders is relay-only: relay merging nodes hand it to the external relay, other nodes reject it.

Other base rules. A base with unsigned (quote-flow) transactions must be first. A base may not expire earlier than the bundle.

The decision path is drawn in the Searcher view of Delivery by Participant.

Rejection Checks

Unsigned bases. A quote-flow commitment can be a base only if the solution keeps a single callback:

  • it must be the first base;
  • every other base must have the same callback;
  • otherwise: unsigned commitment requires callback mode and a single callback URL (...). This merge is rejected on every node, relay merging nodes included.

Delivery target. A solution with no usable callback and no common builder is accepted only on a relay merging node. Elsewhere: commitment has no delivery target (...). Typical case: merging a callback-only OFP bundle with anything that has no callback. Submit it to a relay merging node, or merge only bundles that share a builder.

Worked cases are in Delivery by Participant (Searcher view).

Retries and Missing Transactions

  • The response does not tell you whether the solution was delivered. The call returns as soon as the solution is stored and gossiped. Delivery to the callback and the builders runs in the background; a failure is logged on the node and never returned to you.
  • already known means the solution is already in the network. Do not resubmit it.
  • A base can arrive before its transactions. Delivery then waits for them. If the block is sealed or changes first, or the solution leaves the pool, nothing is delivered.
  • The call is bounded by the node's RPC execution timeout, which covers preparation and execution but not delivery.
  • A conflicting base needs its transactions while your bundle is prepared. The node waits up to one second for them and prepares the bundle again for the subslot that is current by then. If they do not arrive: access lists are not compatible and N based txs not found; try again a moment later.

Commitment View

Commitments live in the node's pool and are gossiped to all nodes. Searchers read pooled transactions to build solutions: builders limits builders and callbacks, not the network, so it does not hide transactions from TOOL nodes and searchers. Exceptions are unsigned (quote-flow) transactions, whose hashes and execution effects are visible while bodies stay on the origin node, and the callback URL, which appears as a hash in JSON. See Delivery by Participant.

Simulation and Submission Workflow

Subscribe

Use tool_subscribe commitments with filters that match the strategy's target accounts and timing needs.

Build

Create a native TOOL bundle that builds on the source commitment and adds the searcher's signed transactions.

Simulate

Call tool_simulateBundle when latency allows and use the result to avoid invalid or conflicting submissions.

Submit

Call tool_sendBundle before the relevant subslot or expiry deadline, then observe accepted subslots, next headers, or downstream inclusion signals.

Searchers should expect low-latency constraints. Bundle size, simulation cost, and request rate can affect whether a strategy lands before the active deadline.

Failure Modes

Failure mode Behavior
Commitment expires before submission The searcher bundle is stale and should be rejected or ignored.
Bundle references an unknown commitment Reject as invalid or unavailable.
already known The solution is already in the network; do not resubmit.
commitment has no delivery target (...) No usable callback and no common builder on a non-relay-merging node. Submit to a relay merging node, or merge only bundles that share a builder.
unsigned commitment requires callback mode and a single callback URL (...) Unsigned base not first, or other bases have a different callback. Rejected on every node.
access lists are not compatible and N based txs not found A conflicting base's transactions did not arrive within one second; try again a moment later.
Searcher transaction conflicts with base commitment state Simulation or validation should fail.
Searcher submits after the subslot deadline Reject or miss inclusion for that subslot.
Simulation capacity is saturated Searcher may need to retry, submit without simulation, reduce request rate, or prioritize opportunities.

All error strings: Errors.

Running a TOOL Node

Every TOOL node runs the same node image inside a TEE. The TOOL team provides the image.

The image and the node's startup command, including every flag, are measured: a hash of the image and the startup command is part of the node's attestation, and TOOL nodes only peer with nodes whose attestation has the expected hash. An operator cannot change the node's code or startup flags.

Settings that differ between nodes, such as credentials and domain names, go in unmeasured files that the operator supplies at deploy time. Unmeasured files are not part of the attestation and are under /atakit-portal/unmeasured-data/ inside the node.

RELAY_SECRET_KEY_HEX must be set in the unmeasured geth.env file, or the node does not start. Most searcher nodes can use any 64 hex characters without a 0x prefix, for example the output of openssl rand -hex 32.

Four unmeasured files set up TLS: CERTDIST.toml, op_priv, acme_account.pem and dns.env. Most searchers need only Quick TLS Setup, which uses CERTDIST.toml alone.

Quick TLS Setup

The node serves the public RPC on port 8545 only over HTTPS, so the node needs a TLS certificate. Supply a CERTDIST.toml with this content:

[network]
ddns_enabled = true

[network.dns]
provider = "route53"

The quick TLS setup needs no keys or credentials. The node receives the *.tool.limo certificate from other TOOL nodes and is reachable at <nodeId>.tool.limo, where <nodeId> is the first 12 hex characters of the node's p2p node ID.

The node ID changes every time the node starts, and so does the hostname. The current hostname is in the CertDist DDNS updated log line. For a hostname that does not change, see Using Your Own Domain.

Without CERTDIST.toml, the node does not start.

How the Node Gets a Certificate

CertDist (certificate distribution) is the protocol TOOL nodes use to share TLS certificates. With the quick TLS setup:

  1. The node starts with TLS on and no certificate. HTTPS handshakes fail until a certificate arrives. There is no self-signed or plaintext fallback.
  2. The node connects to other TOOL nodes. Both sides verify each other's attestation before exchanging anything.
  3. A peer that holds the *.tool.limo certificate announces the certificate, and the node requests the certificate.
  4. The node receives the certificate and the certificate's private key over the attested connection. The private key exists only inside TEEs, so no operator can read the private key.
  5. The node points <nodeId>.tool.limo at the node's own IP address and keeps the DNS record up to date. ddns_enabled turns on this DNS update.

Using Your Own Domain

A node can also serve HTTPS under your own domain, such as tool.example.com, in addition to the node's tool.limo hostname. In CERTDIST.toml, the [network] section sets up the tool.limo hostname and the [operator] section sets up your own domain.

Add an [operator] section to CERTDIST.toml on each of your nodes:

[operator]
domain = "tool.example.com"
op_priv_path = "/atakit-portal/unmeasured-data/op_priv"

op_priv is a secp256k1 private key written as 64 hex characters. Generate the key once and put the same file on each of your nodes. Your nodes use op_priv to recognize each other.

At least one of your nodes must get the certificate for domain from Let's Encrypt. Let's Encrypt checks that you control the domain with a DNS TXT record (a DNS-01 challenge), which the issuing node creates through your DNS provider's API. The issuing node needs two more files, your Let's Encrypt account key and your DNS provider credentials, plus these lines in CERTDIST.toml:

[operator.acme]
account_key_path = "/atakit-portal/unmeasured-data/acme_account.pem"

[operator.dns]
provider = "route53"
zone = "example.com"
credentials_path = "/atakit-portal/unmeasured-data/dns.env"
  • zone is the DNS zone that contains domain.
  • provider is route53 or cloudflare.
  • acme_account.pem is the Let's Encrypt account key: a PEM private key, either RSA or ECDSA on P-256, P-384 or P-521.
  • dns.env holds KEY=VALUE lines. The cloudflare provider needs CF_API_TOKEN. The route53 provider needs AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY and AWS_REGION.

Your other nodes receive the certificate from the issuing node after proving possession of the same op_priv. The Let's Encrypt account key and the DNS credentials stay on the issuing node. The node does not create DNS records for your domain, so point domain at your nodes yourself.

Connecting Your Nodes to Each Other

If more than one of your nodes uses your own domain, your nodes must be connected to each other to share the certificate. Your nodes can connect to each other on their own through peer discovery, but that connection is not guaranteed. The issuing node is the node whose CERTDIST.toml has the [operator.acme] section. On each of your nodes that is not the issuing node, you can set STATIC_NODES in the unmeasured geth.env file to the issuing node's enode URL:

STATIC_NODES=enode://<public key>@<IP address>:30303

A node with STATIC_NODES set connects to the issuing node at startup and does not depend on peer discovery for that connection.

To find the enode URL, look for the Started P2P networking line in the issuing node's log. The enode URL changes every time the issuing node starts.

STATIC_NODES takes enode URLs separated by commas. An invalid enode URL stops the node at startup.

File Reference

CERTDIST.toml and geth.env are required. The node reads each of the other three files only when CERTDIST.toml sets that file's path.

File Required Read when If omitted
geth.env Yes Always The node does not start, because RELAY_SECRET_KEY_HEX is not set.
CERTDIST.toml Yes Always The node does not start, because the node's startup command sets --rpc.force-tls. The same happens if the file sets up neither the tool.limo hostname nor your own domain.
op_priv With an [operator] section CERTDIST.toml has an [operator] section The node does not start.
acme_account.pem On the issuing node CERTDIST.toml sets account_key_path The node receives the certificate from a peer.
dns.env On the issuing node CERTDIST.toml sets account_key_path The issuing node does not start.