Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Benchmark comparison refreshed against current alloy crates (alloy-primitives 1.6.0, alloy-sol-types 1.6.0, alloy-dyn-abi 1.6.0, alloy-consensus 2.0.5, alloy-signer 2.0.5, alloy-rlp 0.3.15); bench/alloy-bench migrated from alloy-primitives 0.8 / alloy 0.6. New score: eth.zig wins 18/26 (alloy improved Keccak on larger inputs, hex encoding, RLP u256 decoding, and UniswapV4-style swap math)

### Added
- MEV-Share backrunner example (`examples/08_mev_share_backrunner.zig`): a teaching bot that matches the MEV-Share SSE event stream against comptime-computed Uniswap V2/V3 swap selectors and composes a backrun bundle (user tx hash + signed EIP-1559 backrun tx), with a safe `DRY_RUN` default that prints the `mev_sendBundle` params instead of submitting (#38)
- `mev_share` module: MEV-Share client mirroring `mev-share-client-ts` -- `sendTransaction` (eth_sendPrivateTransaction via `flashbots.Relay`), `simulateBundle` (mev_simBundle with `SimBundleOpts`/`SimBundleResult`), blocking SSE event stream subscription (`MevShareClient.on` with `PendingEvent`/`PendingTransaction`/`PendingBundle` and pure `parseEventData`), and `getEventHistory` (GET /api/v1/history) (#34)
- `eth_sendPrivateTransaction` (MEV-Share private transactions) on `flashbots.Relay`: submit a single private transaction with hint preferences (calldata, contract_address, logs, function_selector), builder selection, fast mode, and max inclusion block (#40)

### Fixed
- `sse_transport.SseParser.feedLine`: replaced the removed `std.mem.trimRight` with `std.mem.trimEnd` and gave the line-parse result an explicit struct type. These were latent Zig 0.16 migration misses that only surfaced when `feedLine` was semantically analyzed (it is not referenced by the unit-test root), and broke any consumer of `MevShareClient.on` -- surfaced while building the MEV-Share backrunner example (#38)

## [0.5.0] - 2026-06-10

### Changed
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,7 @@ The [`examples/`](examples/) directory contains self-contained programs demonstr
| `05_read_erc20` | ERC-20 module API showcase | Yes |
| `06_hd_wallet` | BIP-44 HD wallet derivation | No |
| `07_comptime_selectors` | Comptime function selectors | No |
| `08_mev_share_backrunner` | MEV-Share backrunner bot (SSE stream + bundle) | No (dry-run) |

Run any example:

Expand Down
43 changes: 43 additions & 0 deletions docs/content/docs/examples.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ The [`examples/`](https://github.com/StrobeLabs/eth.zig/tree/main/examples) dire
| `05_read_erc20` | ERC-20 module API showcase | Yes |
| `06_hd_wallet` | BIP-44 HD wallet derivation | No |
| `07_comptime_selectors` | Comptime function selectors | No |
| `08_mev_share_backrunner` | MEV-Share backrunner bot (SSE stream + bundle) | No (dry-run) |

Run any example:

Expand Down Expand Up @@ -111,3 +112,45 @@ try mc.addCall(token_addr, eth.erc20.selectors.balanceOf, .{holder_addr});
try mc.addCall(token_addr, eth.erc20.selectors.totalSupply, .{});
const results = try mc.execute();
```

## MEV-Share Backrunner

`08_mev_share_backrunner` is a teaching example that ties together comptime
selectors, the MEV-Share SSE stream, EIP-1559 signing, and bundle composition.
It subscribes to the pending-transaction event stream, matches hints against a
comptime-computed table of Uniswap swap selectors, and builds a backrun bundle
(the user's tx hash followed by a signed backrun tx). It defaults to a safe
`DRY_RUN` mode that prints the `mev_sendBundle` params it would submit, and
points at Sepolia by default so the subscription flow can be exercised with no
mainnet funds.

```zig
const eth = @import("eth");

// Comptime: the swap selector is hashed by the compiler.
const v2_swap = comptime eth.keccak.selector(
"swapExactTokensForTokens(uint256,uint256,address[],address,uint256)",
);

var client = eth.mev_share.MevShareClient.init(allocator, relay_url, stream_url, auth_key);
defer client.deinit();

// Subscribe to the SSE stream; the callback fires per pending-tx hint.
try client.on(&onEvent);

// Inside onEvent: match the revealed selector, then compose the bundle.
const body = [_]eth.flashbots.MevBundleBody{
.{ .hash = user_tx_hash }, // the user's pending swap
.{ .tx = .{ .data = signed_backrun_tx } }, // our backrun
};
_ = try client.relay.mevSendBundle(.{
.body = &body,
.inclusion = .{ .block = target_block, .max_block = target_block + 2 },
});
```

Run it (dry-run, against the Sepolia matchmaker):

```bash
cd examples && zig build && DRY_RUN=1 ./zig-out/bin/08_mev_share_backrunner
```
Loading
Loading