How to get transactions and bundles into rbuilder, and exactly what the mev_sendBundle adapter does and does not translate.
TEST-ONLY CREDENTIALS. Every private key, mnemonic, BLS secret and JWT in this repository is public and well known. Never use any of them on a network that holds value.
scripts/send-test-tx.sh
scripts/send-test-tx.sh --value 1000000000000000000 --priority-gwei 50
scripts/send-test-tx.sh --endpoint rbuilder # skip reth's mempoolResponse shape:
{
"tx_hash": "0x9c2f…",
"sender": "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC",
"nonce": 17,
"target_block": 154,
"endpoints": ["rbuilder", "reth-mempool"],
"responses": { "rbuilder": {"jsonrpc":"2.0","id":1,"result":"0x9c2f…"} }
}Straight to rbuilder's order-input RPC (bypasses the mempool entirely):
curl -s -X POST http://127.0.0.1:8645 \
-H 'content-type: application/json' \
--data '{"jsonrpc":"2.0","id":1,"method":"eth_sendRawTransaction","params":["0x02f8…"]}'{"jsonrpc":"2.0","id":1,"result":"0x9c2f…"}Through reth's mempool, which reaches rbuilder over IPC:
curl -s -X POST http://127.0.0.1:8545 \
-H 'content-type: application/json' \
--data '{"jsonrpc":"2.0","id":1,"method":"eth_sendRawTransaction","params":["0x02f8…"]}'curl -s -X POST http://127.0.0.1:8545 -H 'content-type: application/json' \
--data '{"jsonrpc":"2.0","id":1,"method":"eth_getTransactionReceipt","params":["0x9c2f…"]}' | jq .{
"jsonrpc": "2.0", "id": 1,
"result": {
"blockNumber": "0x9a",
"status": "0x1",
"gasUsed": "0x5208",
"effectiveGasPrice": "0x2540be400"
}
}scripts/send-test-bundle.sh # 2 txs, last one tips coinbase
scripts/send-test-bundle.sh --txs 3 --reverting # middle tx always reverts
scripts/send-test-bundle.sh --replaceable --nonce 1
scripts/send-test-bundle.sh --replaceable --uuid <UUID> --nonce 2 # replace it
scripts/cancel-test-bundle.sh --uuid <UUID> --nonce 3 # cancel itRaw:
curl -s -X POST http://127.0.0.1:8645 \
-H 'content-type: application/json' \
--data '{
"jsonrpc":"2.0","id":1,"method":"eth_sendBundle",
"params":[{
"txs":["0x02f8…","0x02f8…"],
"blockNumber":"0x9b",
"revertingTxHashes":["0xdead…"],
"replacementUuid":"7a3f0a1e-1f1a-4b2e-9c1a-1f0e2d3c4b5a",
"replacementNonce":1,
"signingAddress":"0x976EA74026E726554dB657fA54763abd0C3a0aa9"
}]
}'{"jsonrpc":"2.0","id":1,"result":{"bundleHash":"0x1f4c…"}}Notes that matter:
- Replaceable bundles need all three of
replacementUuid(oruuid),replacementNonceandsigningAddress. rbuilder'sRawBundleMetadata::decode_replacement_datarejects a partial set asIncorrectReplacementData. ignore_cancellable_ordersmust befalse. rbuilder's default istrue, which silently drops every order carrying a replacement uuid. This project sets it tofalseinconfigs/rbuilder/rbuilder.toml.tmpl.- Cancellation is
eth_sendBundlewith an emptytxsarray plus the uuid and a higherreplacementNonce(eth_cancelBundlealso works). X-Flashbots-Signatureis sent by the helpers for realism. The open-source rbuilder RPC server does not verify it.
The open-source rbuilder does not implement mev_sendBundle. At the pinned commit, crates/rbuilder/src/live_builder/order_input/rpc_server.rs registers exactly three methods (eth_sendBundle, eth_cancelBundle, eth_sendRawTransaction) and rbuilder_primitives::Order has only Bundle and Tx variants -- there is no ShareBundle type in the public tree.
Rather than pretend otherwise, this project ships the smallest reasonable adapter: orderflow-shim (workload/mev_shim.py) on port 8646. It accepts MEV-Share mev_sendBundle v0.1, rewrites it into the equivalent eth_sendBundle, and forwards everything else to rbuilder untouched.
MEV=1 scripts/send-test-bundle.shcurl -s -X POST http://127.0.0.1:8646 \
-H 'content-type: application/json' \
--data '{
"jsonrpc":"2.0","id":1,"method":"mev_sendBundle",
"params":[{
"version":"v0.1",
"inclusion":{"block":"0x9b","maxBlock":"0x9d"},
"body":[{"tx":"0x02f8…","canRevert":false},{"tx":"0x02f8…","canRevert":true}],
"metadata":{"signingAddress":"0x976EA74026E726554dB657fA54763abd0C3a0aa9"}
}]
}'| mev_sendBundle field | Handling |
|---|---|
inclusion.block |
→ blockNumber |
body[].tx |
→ txs[] |
body[].canRevert: true |
→ revertingTxHashes[] (keccak256 of the raw tx) |
replacementUuid / replacementNonce / signingAddress (top level or under metadata) |
passed through |
validity.refund (exactly one entry) + validity.refundConfig[0].address |
→ version:"v2", refundPercent, refundRecipient, refundTxHashes |
inclusion.maxBlock |
ignored -- eth_sendBundle targets one block |
privacy.* |
ignored -- meaningless on a single-builder devnet |
body[].hash (backrun a hinted tx) |
rejected with a JSON-RPC error |
body[].bundle (nested bundle) |
rejected with a JSON-RPC error |
validity.refund with >1 entry |
rejected with a JSON-RPC error |
Every translation and rejection is logged to /experiments/orderflow-shim.jsonl.