A block builder for everyone.
Zund builds Ethereum blocks with one set of rules for every sender. No whitelist, no API key, no account. A searcher running a laptop bot gets the same treatment as a fund.
Live since 23 September 2026. Zund builds a full block every slot and bids it to the Flashbots, Ultra Sound, Titan, Aestus and Agnostic relays. A new builder wins few blocks until it receives flow: send yours.
What makes Zund different
| Usual builder | Zund | |
|---|---|---|
| Access | Open, but priority often comes from private deals and history | Open. Same rules for every bundle, written on this site |
| Feedback | Bundle trace available minutes later | Simulation result in the same response, in milliseconds |
| Why it failed | Status code | Plain reason: which tx reverts and why, or that it pays nothing |
| Did it land? | Check it yourself | Block, position and winning builder, updated every block |
| Your flow | Trust us | Never sandwiched, never broadcast, blocklist published (empty) |
At a glance
| Item | Value |
|---|---|
| Contact | contact@zundbuilder.com |
| RPC endpoint | https://zundbuilder.com |
| Protocol | JSON-RPC 2.0 over HTTPS, POST |
| Network | Ethereum mainnet |
| Coinbase | 0x130e5956994e4e9262161c1abb86af739d2f42e2 |
| Block extraData | zund |
| Rate limit | 30 requests / second / IP |
| Authentication | None. X-Flashbots-Signature is optional |
Quickstart
Three steps: sign, send, track. No sign-up.
1. Sign your transactions
Build and sign your transactions as usual. A bundle is a list of raw signed transactions, executed in order and all together, or not at all.
Pay the builder the way you prefer: a priority fee, or a direct ETH transfer to block.coinbase inside your transaction.
2. Send the bundle
curl -s https://zundbuilder.com \ -H 'content-type: application/json' \ -d '{ "jsonrpc": "2.0", "id": 1, "method": "eth_sendBundle", "params": [{ "txs": ["0x02f8...signed tx 1", "0x02f8...signed tx 2"], "blockNumber": "0x18d4a21" }] }'
const ZUND = "https://zundbuilder.com"; async function sendBundle(txs, blockNumber) { const res = await fetch(ZUND, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "eth_sendBundle", params: [{ txs, blockNumber: "0x" + blockNumber.toString(16) }] }) }); return (await res.json()).result; // { bundleHash, simulation } }
3. Read the answer
You get the simulation result right away, in the same response. This one is real, from a live mainnet transaction:
{
"bundleHash": "0x3e8cf25e71af056f873f777d5f269f8f3ef4d1569f9aef98178ff429a02a4cd5",
"simulation": {
"ok": true,
"reason": null,
"builderPaymentEth": 0.000006368400127368,
"ms": 9,
"txs": [{ "hash": "0xe29da8c1…0c3c", "status": "SUCCESS", "gasUsed": 127368, "error": null }]
}
}Then call zund_getBundleStats with the bundleHash to see whether it landed, in which block, and at which position.
If simulation.ok is false, reason tells you why in plain words, for example tx 2 (0x9a41c0de) reverts: execution reverted or bundle pays nothing to the builder. Fix it and send again.
Principles
Ethereum is for everyone, so its blocks should be too. These are the rules Zund follows, published so anyone can hold us to them.
1. No club
No whitelist, no API key, no account, no private priority lane. Every bundle is ranked by what it adds to the block, and by nothing else. Who sent it does not matter.
2. Your flow is yours
- Zund never front-runs, back-runs or sandwiches the transactions and bundles it receives.
- Zund does not let others do it either: a bundle that sandwiches another sender's transaction is rejected when it arrives, with the reason in the response.
- Bundles are never unbundled, broadcast to the public mempool or shown to other searchers.
- Zund runs no searcher strategies on the flow it receives.
3. No censorship
Zund's transaction blocklist is empty. Any valid transaction that pays for its place can be included.
4. Every sender gets an answer
A bundle that is rejected is never silently dropped. You get the reason in the same response, and you can track the outcome block by block.
5. A thin margin
The builder keeps a small share. Most of the value created by a bundle goes back to the people who create it. The refund rule is public: 90% of the surplus you create comes back to you, the same rule for everyone.
6. Built for the next Ethereum
Zund is designed for the protocol that is coming (ePBS, inclusion lists, encrypted mempools), not the one that is leaving. See Ready for what's next.
How blocks are built
From your request to a finished block, in four stages.
1. Gateway: instant simulation
Every eth_sendBundle is decoded and simulated on the latest mainnet state before anything else. The simulation charges the priority fee and follows ETH transfers to the Zund coinbase, so it knows exactly what the bundle pays. You get the result in the response, usually in 5 to 35 ms.
2. Engine: algorithms compete
The bundle then goes to the engine, based on rbuilder running on its own reth node. Three block-building algorithms run at the same time and the most valuable block wins:
| Algorithm | How it orders |
|---|---|
max-profit | By the total value each order adds to the block |
mev-gas-price | By value per unit of gas |
parallel | Splits orders into independent groups, solves them on 16 threads and merges |
Orders are re-simulated inside the block they are placed in, so interactions between bundles are taken into account, not only the gas price.
3. End-of-block pass
After the block is filled, bundles sent with eth_sendEndOfBlockBundle are tried on the final state of the block. This is where you back-run what happened inside the block itself. A bundle that reverts or pays nothing is dropped, and the block stays as it was.
4. Relays
Zund submits every block to the Flashbots, Ultra Sound, Titan, Aestus and Agnostic relays, paying the proposer only what is needed to beat the best competing bid.
How much the proposer gets. Zund reads the best competing bid live and offers just above it: bid = min(block value, best other bid + 0.00001 ETH). The proposer gets what it takes to win; the rest of the block value is the surplus that goes back to the senders (see Refunds). Zund never bids more than its block is worth.
API overview
Standard JSON-RPC 2.0. If you have already sent bundles to any builder, you already know how to use Zund.
Methods
| Method | What it does | Status |
|---|---|---|
eth_sendBundle | Send an atomic bundle. Returns an instant simulation | live |
eth_sendEndOfBlockBundle | Bundle tried after all other orders, on the final block state | live |
eth_sendRawTransaction | Send one private transaction | live |
zund_getBundleStats | Status, simulation and landing of a bundle | live |
zund_rules | The rules and limits, as JSON | live |
eth_cancelBundle | Cancel your bundles by replacementUuid | live |
Signing (optional)
You can add the standard Flashbots header X-Flashbots-Signature: <address>:<signature>, where the signature is the EIP-191 signature of the keccak256 hash of the request body. If it is valid, your address is shown as signer in zund_getBundleStats. It is required for replacementUuid and eth_cancelBundle.
Signing never gives priority at Zund. It only identifies you. It will be used to send refunds to the right address.
Limits and error codes: see Errors & limits.
eth_sendBundle
Send a list of signed transactions to be included together, in order, in the target block. Nothing is included unless the whole bundle is valid.
Parameters
| Field | Type | Description |
|---|---|---|
txs required | string[] | Signed raw transactions (hex), in execution order. Must not be empty. |
blockNumber optional | hex string | Target block. Without it, the bundle is valid for the next blocks and tracked for 5 minutes. |
revertingTxHashes optional | string[] | Hashes of transactions that are allowed to revert without dropping the bundle. |
droppingTxHashes optional | string[] | Hashes of transactions that may be removed from the bundle if they are invalid (for example, already included). |
minTimestamp optional | number | Minimum block timestamp for which the bundle is valid. |
maxTimestamp optional | number | Maximum block timestamp for which the bundle is valid. |
replacementUuid optional | uuid | Makes the bundle replaceable. A new bundle with the same uuid from the same signer replaces the old one. Requires X-Flashbots-Signature. Also accepted as uuid. |
replacementNonce optional | number | Sequence number of the replacement; the highest wins. Also accepted as replacementSeqNumber. If omitted, Zund uses the arrival time. |
refundRecipient optional | address | Where your refund is paid. Defaults to your identity. See Refunds. |
refundPercent optional | 0–99 | Share of what your bundle pays that is refunded to you inside the same block. On top, the surplus rule applies to everyone. |
Example
{
"jsonrpc": "2.0",
"id": 1,
"method": "eth_sendBundle",
"params": [{
"txs": ["0x02f8b1…", "0x02f8d3…"],
"blockNumber": "0x18d4a21",
"revertingTxHashes": []
}]
}
curl -s https://zundbuilder.com \ -H 'content-type: application/json' \ -d '{"jsonrpc":"2.0","id":1,"method":"eth_sendBundle","params":[{"txs":["0x02f8b1…","0x02f8d3…"],"blockNumber":"0x18d4a21"}]}'
Response
{
"jsonrpc": "2.0", "id": 1,
"result": {
"bundleHash": "0x3e8cf25e…4cd5",
"simulation": {
"ok": true,
"reason": null,
"builderPaymentEth": 0.000006368400127368,
"ms": 9,
"txs": [
{ "hash": "0xe29da8c1…0c3c", "status": "SUCCESS", "gasUsed": 127368, "error": null }
]
}
}
}| Field | Meaning |
|---|---|
bundleHash | keccak256 of the concatenated transaction hashes. Use it with zund_getBundleStats. |
simulation.ok | true if no transaction reverts (except the allowed ones) and the bundle pays the builder something. |
simulation.reason | Why it is not ok, in plain words. null when ok. |
simulation.builderPaymentEth | What the bundle pays the builder: priority fees plus direct ETH transfers to the coinbase. |
simulation.txs[] | For each transaction: status (SUCCESS / REVERT), gasUsed, error. |
simulation.ms | How long the simulation took. |
Possible reasons
| reason | What to do |
|---|---|
tx N (0x…) reverts: … | That transaction fails on the current state. Fix it, or add its hash to revertingTxHashes if the failure is acceptable. |
invalid: … | Wrong nonce, not enough balance, fee below base fee. The message comes from the node. |
bundle pays nothing to the builder | Add a priority fee or an ETH transfer to block.coinbase. |
The instant simulation runs at the top of the latest block. Inside the real block, the engine simulates again after the orders placed before yours. A bundle that is ok here can still be skipped if another order changes the state first. zund_getBundleStats tells you what happened.
eth_sendEndOfBlockBundle
A bundle placed after every other order, on the final state of the block. Use it to back-run what happens inside the block itself.
Parameters
| Field | Type | Description |
|---|---|---|
txs required | string[] | Signed raw transactions, in order. |
blockNumber required | hex string | The block to append to. |
revertingTxHashes optional | string[] | Transactions allowed to revert. |
targetPools optional | address[] | Pools the bundle depends on. Recorded today. Every end-of-block bundle is currently tried, whatever pools it targets. |
Example
{
"jsonrpc": "2.0", "id": 1,
"method": "eth_sendEndOfBlockBundle",
"params": [{
"txs": ["0x02f8…"],
"blockNumber": "0x18d4a21",
"targetPools": ["0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640"]
}]
}{ "jsonrpc": "2.0", "id": 1,
"result": { "accepted": true, "note": "will be tried after all other orders, on the final block state" } }Guarantees
- Same atomicity as a normal bundle: all transactions or none.
- If the bundle reverts or pays nothing on the final state, it is dropped and the block does not change.
- No instant simulation for this method: the state it depends on does not exist yet when you send it.
eth_sendRawTransaction
Send one signed transaction privately. It is not broadcast to the public mempool.
Parameters
| Position | Type | Description |
|---|---|---|
0 required | string | The signed raw transaction (hex). |
{ "jsonrpc": "2.0", "id": 1, "method": "eth_sendRawTransaction", "params": ["0x02f8…"] }
{ "jsonrpc": "2.0", "id": 1, "result": "0x…transaction hash" }
eth_cancelBundle
Withdraw your replaceable bundles. Only the signer who sent them can cancel them.
Parameters
| Field | Type | Description |
|---|---|---|
replacementUuid required | uuid | The uuid you set when sending the bundle. |
The request must carry a valid X-Flashbots-Signature. Zund pairs the uuid with the verified signer, so nobody else can cancel or replace your bundles, even if they learn the uuid.
{ "jsonrpc": "2.0", "id": 1, "method": "eth_cancelBundle",
"params": [{ "replacementUuid": "3b35aab2-e12a-4063-9714-877df1a0f05d" }] }
{ "jsonrpc": "2.0", "id": 1,
"result": { "cancelled": true, "replacementUuid": "3b35aab2-…", "bundles": 1 } }
bundles is how many of your pending bundles were marked CANCELLED. The engine drops them from the next rebuild of the block.
Replace instead of cancel
To update a bundle, send a new eth_sendBundle with the same replacementUuid. The previous one becomes REPLACED in zund_getBundleStats.
A cancellation sent in the last moments before a block is submitted may arrive too late for that block.
zund_getBundleStats
Everything Zund knows about your bundle. Available immediately, updated every block.
Parameters
| Position | Type | Description |
|---|---|---|
0 required | string or object | The bundleHash, or { "bundleHash": "0x…" }. |
{ "jsonrpc": "2.0", "id": 1, "method": "zund_getBundleStats",
"params": ["0x3e8cf25e71af056f873f777d5f269f8f3ef4d1569f9aef98178ff429a02a4cd5"] }{
"bundleHash": "0x3e8cf25e…4cd5",
"status": "FORWARDED",
"reason": null,
"targetBlock": 26038817,
"receivedAt": "2026-09-23T07:53:16.379Z",
"txCount": 1,
"signer": null,
"simulation": { "ok": true, "builderPaymentEth": 0.0000063684, "ms": 9, … },
"landing": {
"status": "LANDED",
"block": 26038817,
"position": 117,
"builder": "BuilderNet",
"complete": true,
"success": true
}
}Fields
| Field | Meaning |
|---|---|
status | What Zund did with it. See Bundle tracing. |
signer | Your address, if you sent a valid X-Flashbots-Signature. |
replacementUuid | The uuid of a replaceable bundle, or null. |
landing.status | PENDING, LANDED or NOT_LANDED. |
landing.builder | Who built the block where your transactions landed, read from the block's extraData. |
landing.position | Index of your first transaction in the block. |
landing.complete | true if every transaction of the bundle is in that same block. |
landing.success | true if your first transaction did not revert. |
Unknown hashes return { "status": "UNKNOWN" }. Bundles are kept for 6 hours.
zund_rules
The rules of this builder as JSON, so your bot can read them.
{
"name": "Zund",
"phase": "live: Zund bids every slot to Flashbots, Ultra Sound, Titan, Aestus and Agnostic relays",
"principle": "a builder for everyone: no whitelist, no API key, same rules for every bundle, every sender gets an answer",
"forbidden": ["sandwiching the flow Zund receives", "censorship (blocklist is empty)"],
"refunds": "90% of the surplus back to senders by contribution, 10% fee, paid in the same block (starts with bidding)",
"docs": "https://zundbuilder.com",
"limits": { "requestsPerSecondPerIp": 30, "maxBodyBytes": 1048576 }
}Errors & limits
The same limits for everyone. No paid tier.
Limits
| Limit | Value |
|---|---|
| Requests | 30 per second per IP. Above it: HTTP 429 |
| Request body | 1 MB |
| Upstream timeout | 10 s |
| Bundle memory | 6 hours |
Error codes
| Code | Message | Cause |
|---|---|---|
-32700 | invalid json | The body is not valid JSON. |
-32601 | method not supported | The method is not in the list. |
-32602 | empty bundle | txs is missing or empty. |
-32602 | transaction could not be decoded | A transaction is not valid signed RLP. |
-32602 | replacementUuid requires a valid X-Flashbots-Signature header | Replaceable bundles and cancellations must be signed. |
-32005 | too many requests | Rate limit reached. Wait one second. |
A bundle that decodes correctly but fails simulation is not an error: you get a normal result with simulation.ok: false and a reason.
Bundle tracing
Know what happened to every bundle, while it still matters: the simulation comes in the response, the landing check runs every block.
Lifecycle
status
| Value | Meaning |
|---|---|
RECEIVED | Decoded and recorded. |
INVALID | Empty, or a transaction could not be decoded. Not forwarded. |
FORWARDED | Simulated and handed to the engine for block building. |
REJECTED | The engine refused it (for example, a malformed field). reason has the engine's message. |
REPLACED | A newer bundle with the same replacementUuid and signer took its place. |
CANCELLED | You cancelled it with eth_cancelBundle. |
landing.status
| Value | When |
|---|---|
PENDING | The target block has not been produced yet. |
LANDED | Your first transaction is on chain. Zund adds the block, position and builder. |
NOT_LANDED | Two blocks after the target, it is still not on chain. Without a target block: after 5 minutes. |
Landing is checked on chain, whoever built the block.
Checklist when a bundle does not land
- Look at
simulation.reason. Most failures are there. - Check
targetBlock. A bundle for a block that has already passed cannot land. - Check the payment. Another bundle touching the same state may simply pay more.
- If a transaction may already be on chain, list it in
droppingTxHashes.
Refunds with bidding
When your bundle makes a Zund block more valuable, most of that value comes back to you. One rule, the same for everyone, written here in full.
The rule in one sentence
After paying the proposer, Zund keeps 10% of what is left and gives the other 90% back to the senders, in proportion to how much each one added to the block.
How it is computed
For every block Zund wins:
| Symbol | Meaning |
|---|---|
v | Value of the block: everything it pays the Zund coinbase. |
c | What Zund pays the proposer (the winning bid). |
S = v − c | Surplus: what is left after paying the proposer. |
μᵢ | Contribution of sender i: the value of the block with their bundles minus the value of the best block without them, capped at what their bundles pay. |
f = 10% | Zund's fee. Fixed and public. It only changes with notice on this page. |
refundᵢ = (1 − f) × min(S, Σⱼ μⱼ) × μᵢ / Σⱼ μⱼ
The builder only keeps f × min(S, Σμ), plus any surplus that no bundle created (for example, from public mempool transactions).
Example
| Step | Value |
|---|---|
Block value v | 0.100 ETH |
Paid to proposer c | 0.085 ETH |
Surplus S | 0.015 ETH |
| Contributions | Alice μ = 0.040, Bob μ = 0.020 → Σμ = 0.060 |
| To share | min(0.015, 0.060) = 0.015 → 90% = 0.0135 ETH |
| Alice | 0.0135 × 40/60 = 0.0090 ETH |
| Bob | 0.0135 × 20/60 = 0.0045 ETH |
| Zund keeps | 0.0015 ETH |
Who gets it
- Identity: the address in your
X-Flashbots-Signatureheader. Without a signature, the sender of the first transaction of the bundle. - Where it goes:
refundRecipientif you set it, otherwise your identity address. - Split identities do not pay more. A group of identities can never receive more in total than their bundles contributed to the block, so splitting your flow across many keys gains nothing.
- Everyone who sends privately to Zund qualifies: bundles, end-of-block bundles and private transactions. Transactions that were already public in the mempool do not.
When and how it is paid
- Inside the block, if you set
refundPercent(see below). - Right after the block for the surplus share. As soon as a Zund block lands, it is computed and paid by transactions from the Zund coinbase, usually within the next few blocks. Anyone can check them on chain against the block.
- Dust is kept for you, not lost. A refund smaller than the gas needed to send it is added to your balance and paid in a later block, once it is worth sending.
- Visible. Each bundle's refund will appear in
zund_getBundleStats.
Refunds inside the same block: refundPercent
Like Titan, you can also ask for a refund paid inside the same block. Add refundPercent (1–99) to eth_sendBundle: that share of what your bundle pays the builder is sent back to you by a transaction placed right after your bundle, in the same block. Its gas is taken from the refund.
| Field | Meaning |
|---|---|
refundPercent | Integer 1–99. Share of the payment of your bundle refunded in the block. |
refundRecipient | Where the refund goes. Default: the sender of the first transaction. |
refundTxHashes | At most one hash: the transaction whose payment is refunded. Default: the last one. |
Then the surplus rule still applies. What you received inside the block is subtracted from your contribution, and 90% of the remaining surplus is shared as described above. At Titan, what is left after refundPercent stays with the builder; at Zund, 90% of it comes back to the senders.
A higher refundPercent means your bundle pays the builder less, so it is ranked lower when the block is built. This is the same trade-off as at every builder.
Zund Protect live
A private RPC for your wallet. Your transactions never go to the public mempool, so nobody can sandwich them.
Add it to your wallet
| Field | Value |
|---|---|
| Network name | Zund Protect |
| RPC URL | https://zundbuilder.com/protect |
| Chain ID | 1 |
| Currency symbol | ETH |
| Block explorer | https://etherscan.io |
What happens to your transaction
- Private. Zund does not broadcast it to the public mempool.
- It lands fast. Zund puts it in its own block and also shares it privately with builders that do not sandwich private flow (Titan, Quasar, Flashbots Protect), so it is included whoever wins the slot.
- No sandwich at Zund. Bundles that sandwich another sender are rejected at the door.
- Reads are served by Zund's own node: balances, nonces, calls, gas estimates, receipts, logs (up to 1,000 blocks per query).
Refunds for Protect users (a share of the value your transaction creates) are planned.
Builder identity
How to recognise a Zund block, and where Zund will send its blocks.
| Item | Value |
|---|---|
| Coinbase (fee recipient) | 0x130e5956994e4e9262161c1abb86af739d2f42e2 |
| Block extraData | Zund (zundbuilder.com) |
| Transaction blocklist | Empty |
| Relays (when bidding) | Flashbots, Ultra Sound, Titan Relay, Aestus, Agnostic |
| BLS submission keys | 0x8d4eeeaf7a0f9cf05eb3b145c05d0e775b04481749450952f2b319bf4d69b9f16a538db7b30fb4b976e65873a57ced04Any key not listed here is not Zund. |
To pay the builder directly from a contract, transfer ETH to block.coinbase. It always points to the builder of the block your transaction is in.
Live numbers
Everything Zund does, counted in public. Updated every 5 minutes from the builder's own logs. Raw file: /stats.json.
| Metric | Value |
|---|---|
| Loading… | |
Blocks won are checked on chain (fee recipient = Zund coinbase). "Bids above block value" must always be 0: Zund never pays a proposer more than its block is worth.
Ready for what's next
Ethereum is changing how blocks are built. Zund is designed for where it is going.
Status & roadmap
What works today, and what comes next. Updated as things ship.
Live
| Feature | |
|---|---|
| Full block built every slot, 3 competing algorithms | live |
| Public HTTPS endpoint, no key | live |
Instant simulation in the eth_sendBundle response | live |
| End-of-block bundles on the final state | live |
| On-chain landing tracking, every block | live |
Bundle replacement and eth_cancelBundle, bound to the verified signer | live |
| Sandwich bundles rejected at the door (same sender trading before and after another sender on the same pool) | live |
Refunds inside the same block with refundPercent | live |
| Blob transactions (EIP-7594 sidecars), each checked against its versioned hashes before it enters a block | live |
| Compressed SSZ submissions to relays | live |
| Bidding every slot to Flashbots, Ultra Sound, Titan, Aestus and Agnostic | live |
Next
| Feature | |
|---|---|
| Refunds paid on chain right after the block (rule published, service ready) | with bidding |
| Gas sponsorship: if a sender cannot pay gas, Zund advances it and the bundle repays it in the same block (built and tested, switched on after launch) | ready |
| Regional endpoints | planned |
Changelog
| Date | Change |
|---|---|
| 2026-09-24 | Public Live numbers page (/stats.json). Blocks now carry Zund (zundbuilder.com) in extraData. BLS submission key published. |
| 2026-09-24 | Own domain zundbuilder.com. Zund Protect: private RPC for wallets at https://zundbuilder.com/protect. |
| 2026-09-23 | Zund is live: bids every slot to five relays. |
| 2026-09-23 | Sandwich bundles rejected. Same-block refunds with refundPercent. Blob transactions back on, with a strict sidecar check. Compressed SSZ submissions. Gas sponsorship built and tested. |
| 2026-09-23 | Bidding service: pays the proposer only what is needed to win (best competing bid + 0.00001 ETH), never more than the block is worth. Refund service ready, tested on real blocks. |
| 2026-09-23 | Bundle replacement (replacementUuid) and eth_cancelBundle live. Refund fields from other builders no longer drop a bundle. |
| 2026-09-23 | Refund rule published: 90% of the surplus back to senders, 10% fee, paid in the same block. |
| 2026-09-23 | Public endpoint and documentation online. English API responses. Per-IP rate limit. |
| 2026-09-23 | End-of-block bundles. On-chain landing tracking. |
| 2026-09-23 | Instant simulation in the eth_sendBundle response. |