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
21 changes: 9 additions & 12 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,23 @@ All notable changes to eth.zig will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Fixed
- DEX `getAmountIn`/`getAmountOut` are correct standard Uniswap V2; the `getAmountIn inverse` round-trip test used unrealistic tiny-reserve parameters where flooring a small output legitimately breaks the within-2-units invariant. Corrected the test to balanced reserves and un-quarantined it (#83). The full unit suite now runs with zero skips.
- BIP-39 seed derivation (`mnemonic.toSeed`) was correct; its Trezor passphrase test had a wrong expected vector. Corrected the test to the canonical vector (verified against `std.crypto` PBKDF2) and un-quarantined it (#82).
- `mulDiv` now returns the correct result when the intermediate product overflows u256 with a full-width divisor, e.g. `mulDiv(MAX, MAX, MAX)` (#81). The limb-native Knuth-D divider mis-handled this boundary; the rare overflow path now computes exactly in native u512 (the benchmarked u128 fast path is unchanged).
- Pure-Zig Keccak-256 fallback (`keccak_optimized.zig`) now produces correct digests (#80): replaced the broken lane-complementing chi optimization with the standard chi step (which lowers to ANDN anyway). Verified against pinned vectors and cross-validated with stdlib across all block sizes.
- **Unit tests now actually run.** The test step aggregated module tests via `_ = eth.module` field access, which only forces semantic analysis -- it never collected the per-module `test` blocks, so assertions compiled but never executed (`zig build test` was green even with a deliberately failing test). The test artifact is now rooted at `src/root.zig`, whose test block direct-imports every module file. This surfaced real, previously-hidden defects, now fixed: `abi_json` still used the 0.15 `ArrayList` API (broken on 0.16); `rlp.bytesToUint` failed to compile for small integer types; `mnemonic.entropyToMnemonic` had a comptime-resolution bug and a u8 overflow for 24-word phrases; `parseInputs`/`parseParam` formed an inferred-error-set dependency loop; `rlp` struct reflection used the pre-0.17 `Type.Struct.fields` layout (now via `std.meta.fieldNames`, portable across 0.16 and 0.17-dev). Fixed several stale test expectations (`formatHash`/log-address length typos, a static-tuple ABI length, a fixed-size hex length error). Vendored XKCP/secp256k1 C is now built with `-fno-sanitize=undefined` so their intentional unaligned loads do not trap the Debug UBSan runtime.
- Resolved the four pre-existing issues the revived test suite exposed: two were real code bugs (broken pure-Zig Keccak fallback #80, `mulDiv` at the u256 boundary #81) and two were bad tests (a BIP-39 passphrase seed vector #82, a DEX round-trip assumption #83). All are fixed and the full unit suite now runs with zero skips (775/775).

### Changed
- 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)
## [0.6.0] - 2026-06-10

### Added
- `nonce_manager` module: atomic nonce manager for concurrent senders (#75). `NonceManager.init` seeds lazily from the `pending` transaction count (no RPC in `init`); `next()` is a lock-free atomic fetch-and-add so multiple threads never receive the same nonce; `peek()` reads the next nonce without advancing; `resync()`/`reset()` re-fetch from chain after dropped txs; and `onFailure(nonce)` returns a nonce to the pool only when it is the most recently issued one (a middle nonce cannot be safely reused once a higher one is in flight). Also adds `provider.getTransactionCountAt(address, tag)` so the nonce count can be read at any block tag (e.g. `.pending`)
- 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)

### Changed
- 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)

### Fixed
- **Unit tests now actually run.** The test step aggregated module tests via `_ = eth.module` field access, which only forces semantic analysis -- it never collected the per-module `test` blocks, so assertions compiled but never executed (`zig build test` was green even with a deliberately failing test). The test artifact is now rooted at `src/root.zig`, whose test block direct-imports every module file. This surfaced real, previously-hidden defects, now fixed: `abi_json` still used the 0.15 `ArrayList` API (broken on 0.16); `rlp.bytesToUint` failed to compile for small integer types; `mnemonic.entropyToMnemonic` had a comptime-resolution bug and a u8 overflow for 24-word phrases; `parseInputs`/`parseParam` formed an inferred-error-set dependency loop; `rlp` struct reflection used the pre-0.17 `Type.Struct.fields` layout (now via `std.meta.fieldNames`, portable across 0.16 and 0.17-dev). Fixed several stale test expectations (`formatHash`/log-address length typos, a static-tuple ABI length, a fixed-size hex length error). Vendored XKCP/secp256k1 C is now built with `-fno-sanitize=undefined` so their intentional unaligned loads do not trap the Debug UBSan runtime.
- Pure-Zig Keccak-256 fallback (`keccak_optimized.zig`) now produces correct digests (#80): replaced the broken lane-complementing chi optimization with the standard chi step (which lowers to ANDN anyway). Verified against pinned vectors and cross-validated with stdlib across all block sizes.
- `mulDiv` now returns the correct result when the intermediate product overflows u256 with a full-width divisor, e.g. `mulDiv(MAX, MAX, MAX)` (#81). The limb-native Knuth-D divider mis-handled this boundary; the rare overflow path now computes exactly in native u512 (the benchmarked u128 fast path is unchanged).
- BIP-39 seed derivation (`mnemonic.toSeed`) was correct; its Trezor passphrase test had a wrong expected vector. Corrected the test to the canonical vector (verified against `std.crypto` PBKDF2) and un-quarantined it (#82).
- DEX `getAmountIn`/`getAmountOut` are correct standard Uniswap V2; the `getAmountIn inverse` round-trip test used unrealistic tiny-reserve parameters where flooring a small output legitimately breaks the within-2-units invariant. Corrected the test to balanced reserves and un-quarantined it (#83). The full unit suite now runs with zero skips.
- `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
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -214,15 +214,15 @@ Built something with eth.zig? Open a PR to add it here.
**One-liner:**

```bash
zig fetch --save git+https://github.com/StrobeLabs/eth.zig.git#v0.5.0
zig fetch --save git+https://github.com/StrobeLabs/eth.zig.git#v0.6.0
```

**Or add manually** to your `build.zig.zon`:

```zig
.dependencies = .{
.eth = .{
.url = "git+https://github.com/StrobeLabs/eth.zig.git#v0.5.0",
.url = "git+https://github.com/StrobeLabs/eth.zig.git#v0.6.0",
.hash = "...", // run `zig build` and it will tell you the expected hash
},
},
Expand Down
4 changes: 2 additions & 2 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

| Version | Supported |
|---------|-----------|
| 0.5.x | Yes |
| < 0.5 | No |
| 0.6.x | Yes |
| < 0.6 | No |

## Reporting a Vulnerability

Expand Down
2 changes: 1 addition & 1 deletion build.zig.zon
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
.{
.name = .eth_zig,
.version = "0.5.0",
.version = "0.6.0",
.fingerprint = 0xd0f21900fa26f179,
.minimum_zig_version = "0.16.0",
.dependencies = .{},
Expand Down
4 changes: 2 additions & 2 deletions docs/content/docs/installation.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ description: How to add eth.zig to your Zig project.
**One-liner:**

```bash
zig fetch --save git+https://github.com/StrobeLabs/eth.zig.git#v0.5.0
zig fetch --save git+https://github.com/StrobeLabs/eth.zig.git#v0.6.0
```

**Or add manually** to your `build.zig.zon`:

```zig
.dependencies = .{
.eth = .{
.url = "git+https://github.com/StrobeLabs/eth.zig.git#v0.5.0",
.url = "git+https://github.com/StrobeLabs/eth.zig.git#v0.6.0",
.hash = "...", // run `zig build` and it will tell you the expected hash
},
},
Expand Down
Loading