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 knownmeans 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:
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:
- The node starts with TLS on and no certificate. HTTPS handshakes fail until a certificate arrives. There is no self-signed or plaintext fallback.
- The node connects to other TOOL nodes. Both sides verify each other's attestation before exchanging anything.
- A peer that holds the
*.tool.limocertificate announces the certificate, and the node requests the certificate. - 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.
- The node points
<nodeId>.tool.limoat the node's own IP address and keeps the DNS record up to date.ddns_enabledturns 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:
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"
zoneis the DNS zone that containsdomain.providerisroute53orcloudflare.acme_account.pemis the Let's Encrypt account key: a PEM private key, either RSA or ECDSA on P-256, P-384 or P-521.dns.envholdsKEY=VALUElines. Thecloudflareprovider needsCF_API_TOKEN. Theroute53provider needsAWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEYandAWS_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:
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. |