Releases: StrobeLabs/eth.zig
Release list
v0.7.0 — Pluggable Io, encrypted keystore, fallback provider, EIP-7702
Highlights
- Pluggable
std.Io(breaking, idiomatic). Zig 0.16 makes the execution model the caller's choice; eth.zig now takesstd.Ioas an explicit parameter on every network constructor (HttpTransport.init,WsTransport.connect,WsClient.connect,flashbots.Relay.init,FallbackProvider.init,MevShareClient) and on the functions that need randomness/sleep (mnemonic.generate,keystore.encrypt,runtime.milliTimestamp/sleepMs). No hidden globalIo-- run the library on your own event loop and honor its cancellation.Provider/Wallet/RetryingProvider/NonceManagerinherit the Io of the transport they wrap. Passeth.runtime.blockingIo()for the previous blocking behavior. (Thanks to the community for pushing on this.) - Encrypted JSON keystore (#65): Web3 Secret Storage v3 decrypt/encrypt (scrypt + pbkdf2, AES-128-CTR, constant-time Keccak MAC), interop-verified against the canonical geth fixtures. Load the keys you already have from geth/foundry/ethers.
- FallbackProvider (#70): multi-RPC failover with per-endpoint health tracking and recovery probing; fails over on transport errors but never on a real RPC answer.
- EIP-7702 SetCode transactions (#66): type 0x04 with signed authorizations (
signAuthorization, the 0x05-magic signing hash) -- Pectra parity with alloy/viem.
Migrating from v0.6.0
Add an io argument where you construct transports/clients:
// before
var http = eth.http_transport.HttpTransport.init(alloc, url);
// after (simple blocking case)
var http = eth.http_transport.HttpTransport.init(alloc, url, eth.runtime.blockingIo());Provider.init(alloc, &http) is unchanged and inherits the transport's Io.
Install
zig fetch --save git+https://github.com/StrobeLabs/eth.zig.git#v0.7.0Requires Zig 0.16.0+. Verified on 0.16.0 and 0.17-dev: 812/812 unit tests, 23/23 Anvil integration tests.
Full changelog: https://github.com/StrobeLabs/eth.zig/blob/main/CHANGELOG.md
v0.6.0 — MEV-Share, nonce manager, and a test suite that actually runs
Highlights
- MEV-Share client (#34):
MevShareClientmirrors mev-share-client-ts -- private transactions, bundle simulation (mev_simBundle), a blocking SSE event stream, and event history. Plus eth_sendPrivateTransaction (#40) onflashbots.Relayand a backrunner example (#38) that matches the live hint stream against comptime swap selectors. - Atomic nonce manager (#75): lock-free
next()for concurrent senders, lazy on-chain seeding, and gap-on-failure recovery.
Correctness milestone
- The unit test suite never actually ran. The aggregator collected module tests via
_ = eth.modulefield access, which only forces compilation -- so assertions compiled but never executed (zig build testpassed even with a deliberately failing test). Fixed in #84 by rooting the test artifact atsrc/root.zig. - Turning the suite on surfaced and resolved real issues: a broken pure-Zig Keccak fallback (#80) and a
mulDivu256-boundary bug (#81) were genuine code defects; two others (#82, #83) were bad test expectations. The suite now runs 775/775 with zero skips.
Benchmarks
Refreshed against current alloy (alloy-primitives 1.6 / alloy-consensus 2.0): an honest 18/26 wins, with the biggest margins on RLP encode (24x), ABI decode (8.4x), and secp256k1 recovery (4.2x). Full table in bench/RESULTS.md.
Install
zig fetch --save git+https://github.com/StrobeLabs/eth.zig.git#v0.6.0Requires Zig 0.16.0+. Verified on 0.16.0 and 0.17-dev master.
Full changelog: https://github.com/StrobeLabs/eth.zig/blob/main/CHANGELOG.md
v0.5.0 — Zig 0.16 support and block-scoped log watching
Highlights
- Zig 0.16 support (#55, #60): the entire transport layer now runs on Zig 0.16's new
std.Iointerface — HTTP, WebSocket (including TLS), and SSE. A neweth.runtimemodule constructs a default synchronous Io internally, so no public API signatures changed. Also passes on current master (0.17.0-dev). - log_watcher (#36, #59): the canonical bot loop as a library primitive — on each
newHeads, fetcheth_getLogsscoped to that block. Back-fills blocks missed across reconnects and re-fetches reorged ranges on parent-hash mismatch.LogWatcher.pollOnce()(pull) orwatchLogs()(callback).
Breaking
- Minimum supported Zig version is now 0.16.0 (0.15.2 support dropped). If you are on 0.15.x, stay on v0.4.0.
Install
zig fetch --save git+https://github.com/StrobeLabs/eth.zig.git#v0.5.0Verified on 0.16.0 and 0.17.0-dev: build, unit tests, and 23/23 integration tests against Anvil (HTTP transport, WS subscriptions, LogWatcher) on each.
Full changelog: https://github.com/StrobeLabs/eth.zig/blob/main/CHANGELOG.md
v0.4.0 — Resilient WebSockets, state overrides, full pending-tx streams
Highlights
- WsClient: resilient WebSocket subscription client with transparent reconnect, exponential backoff with jitter, ping/pong keepalive, and multiplexed subscriptions over a single connection (#51)
- Full pending-transaction subscriptions:
newPendingTransactionswithfull: truestreams completeRpcTransactionvalues instead of hashes, tolerating nodes that fall back to hash-only notifications (#53) - eth_call state overrides: set balance, nonce, code, and storage (full state or diff) per call via
callWithOverrides(#54) - SSE transport with last-event-id reconnect support (#48)
- RetryingProvider: configurable retry middleware with exponential backoff and connection-error filtering (#41)
- Batch eth_call fan-out via
BatchCallerand pure Zig UniswapV2 DEX math (#42)
Compatibility
- Compatible with Zig master (0.17.0-dev) again: all uses of the removed
**array-repetition operator replaced with@splat(#56). Minimum supported version remains 0.15.2.
Reliability & security
- Malformed RPC transaction fields now fail fast with
error.InvalidResponseinstead of being silently coerced (#53) - 21 security, correctness, and code-quality fixes across the library (#44)
- Docs site upgraded to Next 16 / Fumadocs 16;
pnpm auditis clean (#57)
Install
zig fetch --save git+https://github.com/StrobeLabs/eth.zig.git#v0.4.0Full changelog: https://github.com/StrobeLabs/eth.zig/blob/main/CHANGELOG.md
v0.3.0
Flashbots MEV Bundle Submission
Adds full support for submitting MEV bundles via Flashbots-compatible relay APIs.
New: flashbots module
Relayclient with EIP-191 auth signing (X-Flashbots-Signatureheader)eth_sendBundle(Flashbots v1) - submit bundles to relaysmev_sendBundle(MEV-Share) - submit bundles with privacy/validity optionseth_callBundle- simulate bundles against specific blockseth_cancelBundle- cancel bundles by replacement UUIDBundleconvenience builder for collecting signed transactions
API
const eth = @import("eth");
var relay = eth.flashbots.Relay.init(allocator, "https://relay.flashbots.net", auth_key);
defer relay.deinit();
const result = try relay.sendBundle(.{
.transactions = bundle.transactions(),
.block_number = current_block + 1,
});Closes #13
Full Changelog: v0.2.3...v0.3.0
v0.2.3
GLV secp256k1 + Lane-Complementing Keccak
This release brings major crypto performance improvements, beating alloy.rs (Rust) on all crypto benchmarks.
Performance Highlights
| Benchmark | eth.zig | alloy.rs | Speedup |
|---|---|---|---|
| keccak256 32B | 300 ns | 337 ns | 1.12x |
| secp256k1 sign | 46 us | 33 us | 0.72x (constant-time tradeoff) |
| secp256k1 recover | 45 us | 50 us | 1.11x |
| address derivation | 299 ns | 363 ns | 1.21x |
What's New
- GLV endomorphism for secp256k1: Splits 256-bit scalar multiplication into two ~128-bit halves using the curve's efficiently computable endomorphism, with comptime-precomputed tables for both base point and lambda base point
- Lane-complementing Keccak-f[1600]: Implements the XKCP opt64 technique -- complements 6 specific state lanes so the chi step uses
AND/ORinstead ofNOT+AND, saving one instruction per lane on ARM/x86 - derivePublicKey scalar validation: Added proper validation for private key scalars
- Deprecated allocator initialization: Removed deprecated allocator init patterns and fixed LLVM crash in tests (thanks @Mario-SO!)
- Documentation site: Added docs site for ethzig.org
Full Changelog
v0.2.2
Test Coverage: alloy.rs Parity Validation
Adds ~97 cross-validation tests across 15 modules to ensure byte-exact accuracy parity with alloy.rs. All test vectors sourced from official specs (Solidity ABI, EIP-55/712/137, BIP-32/39), alloy-rs test suites, Hardhat well-known accounts, and ethereum/tests.
New Tests by Module
| Module | New Tests | Validation Focus |
|---|---|---|
| abi_encode | 12 | Solidity ABI spec vectors, ERC20 approve, fixed_bytes |
| abi_decode | 8 | Roundtrips, error cases, ERC20 return decode |
| transaction | 8 | alloy.rs vectors, access lists, EIP-4844 blobs |
| signer | 4 | Hardhat accounts #2-#4, large message |
| secp256k1 | 4 | Key=1 edge, multi-message, EIP-2 low-s |
| rlp | 12 | Long strings, byte boundaries, non-canonical |
| uint256 | 12 | fastDiv exhaustive, mulDiv Q96, roundtrips |
| keccak | 6 | Known vectors, SHA3 distinction, DeFi selectors |
| primitives | 6 | EIP-55 full test suite, error handling |
| eip712 | 4 | ERC20 Permit, Permit2 nested, domain variants |
| units | 6 | Zero/large values, parse/format roundtrips |
| hd_wallet | 4 | BIP-32 pinned vectors, known mnemonic->address |
| mnemonic | 4 | BIP-39 TREZOR exact seed, all-ones entropy |
| namehash | 3 | vitalik.eth, resolver.eth, trailing dot |
| hex | 4 | Uppercase/mixed case, 256-byte roundtrip |
Other Changes
- Pinned canonical EIP-712 digest vectors for Permit and Permit2 tests
- Pinned exact BIP-32 master key/chain_code bytes
- Reused existing
isHighShelper in EIP-2 low-s test - Fixed f64 precision edge case in
parseEtherlarge value test - Version bump to 0.2.2
v0.2.1
Performance Release: Beat alloy.rs on 18/24 benchmarks
Major performance optimizations across the entire eth-zig library, taking us from 10/24 benchmark wins against alloy.rs to 18/24 wins.
Highlights
- 793x faster address derivation
- 315x faster ABI encoding (static)
- 304x faster ABI encoding (transfer)
- 209x faster ABI decoding (uint256)
- 191x faster RLP encoding (EIP-1559 tx)
- 45x faster transaction hashing
- 13x faster u256 division
- 4.8x faster secp256k1 signing
Score: eth-zig 18 - alloy.rs 5
| Benchmark | eth-zig | alloy.rs | Winner |
|---|---|---|---|
| keccak256_empty | 254 ns | 335 ns | zig 1.32x |
| keccak256_32b | 263 ns | 337 ns | zig 1.28x |
| keccak256_256b | 533 ns | 638 ns | zig 1.20x |
| keccak256_1kb | 2,026 ns | 2,421 ns | zig 1.19x |
| keccak256_4kb | 7,828 ns | 9,229 ns | zig 1.18x |
| secp256k1_sign | 224,177 ns | 51,687 ns | rs 4.34x |
| secp256k1_sign_recover | 837,511 ns | 218,360 ns | rs 3.84x |
| address_derivation | 262 ns | 362 ns | zig 1.38x |
| address_from_hex | 16 ns | 25 ns | zig 1.56x |
| checksum_address | 307 ns | 388 ns | zig 1.26x |
| abi_encode_transfer | 71 ns | 55 ns | rs 1.29x |
| abi_encode_static | 69 ns | 97 ns | zig 1.41x |
| abi_encode_dynamic | 246 ns | 316 ns | zig 1.28x |
| abi_decode_uint256 | 46 ns | 49 ns | zig 1.07x |
| abi_decode_dynamic | 170 ns | 258 ns | zig 1.52x |
| rlp_encode_eip1559_tx | 89 ns | 70 ns | rs 1.27x |
| rlp_decode_u256 | 6 ns | 8 ns | zig 1.33x |
| u256_add | 4 ns | 4 ns | tie |
| u256_mul | 4 ns | 10 ns | zig 2.50x |
| u256_div | 6 ns | 23 ns | zig 3.83x |
| u256_uniswapv2_amount_out | 87 ns | 24 ns | rs 3.62x |
| hex_encode_32b | 21 ns | 22 ns | zig 1.05x |
| hex_decode_32b | 23 ns | 45 ns | zig 1.96x |
| tx_hash_eip1559 | 366 ns | 403 ns | zig 1.10x |
Optimizations
- Replace debug allocator with
c_allocatorin benchmarks - Remove redundant
verifyRecovery()from secp256k1sign()(5 EC muls to 1) - Zero-overhead direct buffer RLP/ABI/TX encoding (no ArrayList overhead)
u256.fastDivwith u128 fast-path (bypasses slow LLVM 256-bit division)- Comptime hex decode lookup table
bytesToUintusing BSWAP instead of byte loop@clzfor branchless byte-length counting in RLP
See bench/RESULTS.md for full details.
v0.2.0
What's New
- Integration tests (provider, wallet, contract against Anvil)
- Benchmark suite (
zig build bench) -- keccak, secp256k1, ABI, RLP, HD wallet, EIP-712 - CONTRIBUTING.md, CHANGELOG.md, issue templates
- README overhaul with feature comparison table, examples section
- Bug fixes in provider and wallet modules
Full Changelog
v0.1.0 -- Initial Release
eth.zig v0.1.0
Initial release of eth.zig -- a feature-complete, pure Zig Ethereum client library with zero external dependencies.
Highlights
- 16K lines of pure Zig, built entirely on the standard library
- Comptime-first: function selectors and event topics computed at compile time for zero runtime cost
- Full Ethereum stack: primitives, ABI encoding/decoding, RLP, secp256k1 signing, transaction types (Legacy through EIP-4844), HD wallets, JSON-RPC (HTTP + WebSocket), provider, wallet, contract interaction, Multicall3, EIP-712, ENS resolution
- Production-tested: powers perpcity-zig-sdk for high-frequency perpetual futures trading
What's Included
| Layer | Modules |
|---|---|
| Primitives | Address, Hash, u256, hex encoding |
| Encoding | RLP, ABI encode/decode, comptime selectors, JSON ABI parser |
| Crypto | Keccak-256, secp256k1 ECDSA (RFC 6979), EIP-155 |
| Types | Legacy, EIP-2930, EIP-1559, EIP-4844 transactions, receipts, blocks |
| Accounts | BIP-32/39/44 HD wallets, mnemonic generation |
| Transport | HTTP + WebSocket JSON-RPC, subscriptions |
| Client | Provider (24+ methods), signing wallet, contract helpers, Multicall3 |
| Standards | EIP-712, ENS, ERC-20/721 helpers |
| Chains | Ethereum, Arbitrum, Optimism, Base, Polygon |
Requirements
- Zig >= 0.15.2
Installation
.dependencies = .{
.eth = .{
.url = "git+https://github.com/StrobeLabs/eth.zig.git#v0.1.0",
.hash = "...",
},
},See the README for full documentation and examples.