Skip to content

Repository files navigation

MEV Engineering Stack — Low-Latency Execution Engine

Low-latency, five-language MEV pipeline for real-time opportunity detection, simulation, and execution on Arbitrum.

Designed and implemented as a solo project.

RustGoC++CSolidity


Overview

  • ⚡ End-to-end pipeline: ~600 ns per opportunity (sub-microsecond internal processing, excluding network latency)
  • 🧠 Five-language architecture: Go (network I/O), Rust (detection + simulation), C++ (AMM simulation kernel + path optimizer), C (SIMD hot paths), Solidity (on-chain execution)
  • 🔄 Fault-tolerant: graceful degradation across all layers — no panics, no silent failures
  • 📊 210+ tests (163 Rust unit + 23 Go + 24 Solidity), 7 benchmark groups, multi-producer C queue stress test (4M items, 9.6 Mops/s), real-time Prometheus dashboard
  • 🔍 Full execution stack: arbitrage, backrun, liquidation detection + AMM simulation kernel with ternary-search optimal sizing

Focus: high-performance systems, lock-free concurrency, and cross-language execution depth — not trading strategies.

Designed for deterministic sub-microsecond execution under concurrent load, with bounded latency and no blocking in the hot path.


Why This Project Exists

This project explores how far a single developer can push across five languages:

  • Low-latency system design — sub-microsecond processing pipeline with Criterion-verified benchmarks
  • Lock-free concurrency — CAS queues, atomic operations, zero-allocation hot paths at 40.7 ns/op
  • Multi-language architecture tradeoffs — gRPC vs FFI, Go scheduler vs cgo, C++ templates vs Rust generics, Yul vs Solidity
  • Two-stage simulation — AMM math fast filter (~35 ns) → revm 8.0 fork execution (~50–200 µs) for full EVM validation
  • C++ simulation kernel — template-specialized AMM math with __uint128_t overflow protection, multi-hop BFS path optimizer (SoA pool graph, 256-pool cap, FNV-1a fingerprinting)
  • Production-grade fault tolerance — exponential backoff, graceful degradation, monitor-only fallback

The goal is not profitability, but engineering performance, cross-language execution depth, and system reliability.


⚙️ Key Engineering Challenges

ChallengeSolution
No public mempool on ArbitrumBlock-based transaction reconstruction with 4-byte selector classification
Sub-microsecond latency under concurrent loadLock-free Vyukov MPMC queue (per-slot sequence ticket), arena allocator, crossbeam channels
False sharing in lock-free data structuresalignas(64) cache-line isolation on head/tail pointers
Partial system failures cascadingMonitor-only fallback, exponential backoff, pure-Rust FFI fallbacks
Precision-safe 256-bit arithmeticchecked_mul/checked_add, custom div_u256_by_u128 with edge-case tests
Go ↔ Rust communication overheadgRPC over FFI — avoids cgo pinning goroutines to OS threads
Gas optimization on-chainTargeted inline Yul in hot loops only, Balancer 0% fee flash loans

Architecture

 ┌────────────────────────────────────────────────────────────────────────────┐
│ MEV Engineering Stack Pipeline │
│ │
│ Mempool ──▶ Classify ──▶ Detect ──▶ Simulate ──▶ Build ──▶ Submit │
│ (Go) (Go) (Rust) (Rust/C++) (Rust) (Go relay) │
└────────────────────────────────────────────────────────────────────────────┘
┌─────────────┐ gRPC ┌──────────────┐
│ network/ │◄═══════════════════▶│ core/ │
│ Go 1.21 │ proto/mev.proto │ Rust 2021 │
│ │ │ │
│ • mempool │ │ • detector │
│ • pipeline │ │ • simulator │
│ • relay │ │ • builder │
│ • metrics │ │ • grpc srv │
│ • gas oracle│ │ • ffi bridge │
└──────┬──────┘ └──────┬───────┘
│ │ FFI (C ABI)
│ eth_sendBundle │
┌──────┴──────┐ ┌──────┴───────┐
│ Flashbots │ │ fast/ │
│ Relay │ │ C + C++ │
│ │ │ │
│ EIP-191 │ │ • keccak256 │
│ Multi-Relay │ │ • RLP encode │
│ EIP-191 │ │ • SIMD AVX2 │
└─────────────┘ │ • lock-free Q│
│ • mem pool │
│ • AMM sim │ ◄─ C++20 templates
│ • pathfinder │ ◄─ BFS + ternary
└──────────────┘
┌─────────────┐
│ contracts/ │
│ Solidity │
│ │
│ FlashArb │ ◄── Balancer V2 flash loans (0% fee)
│ MultiDexRtr │ ◄── V2/V3/Sushi/Curve routing
└─────────────┘

Deployed Contracts (Sepolia Testnet)

ContractAddressEtherscan
FlashArbitrage0x42a372E2f161e978ee9791F399c27c56D6CB55ebVerified ✅
MultiDexRouter0xB6F5A4cd9d0f97632Ef38781A1aaef0C965CAed6Verified ✅

Layer Breakdown

LayerLanguagePurposeEntry Point
network/Go 1.21Mempool monitoring, tx classification, Flashbots relay, Prometheus metricscmd/mev-node/main.go
core/Rust 2021MEV detection (arbitrage + backrun + liquidation), AMM simulation (V2 constant-product + V3 concentrated liquidity), bundle construction, gRPC serversrc/main.rs
fast/C++20 + CAMM simulation kernel (V2/V3 math), multi-hop BFS path optimizer; SIMD keccak, RLP encoding, lock-free MPSC queue, arena allocatorinclude/amm_simulator.h, src/keccak.c
contracts/Solidity + YulFlash loan arbitrage (Balancer V2, 0% fee), multi-DEX routing (direct pool calls), inline Yul assembly, YulUtils librarysrc/FlashArbitrage.sol
proto/Protocol BuffersCross-language service contract (Go ↔ Rust)mev.proto

Live Dashboard

Real-time monitoring dashboard polling Prometheus metrics every 2 seconds. Single self-contained HTML file — no build tools, no dependencies.

┌──────────────┬──────────────────────────────────────────────┬──────────────┐
│ NETWORK │ TRANSACTION PROCESSING PIPELINE │ LIVE FEED │
│ │ Ingest → Classify → Filter → Opp → Relay │ 200 events │
│ Block #450M │ 41.2K 41.2K 8.3K 8.3K 0 │ │
│ RPC 3/3 │ │ LIVE PIPELN │
│ Propagation │ CLASSIFICATION BREAKDOWN │ Classify │
│ 1023ms │ V2: 79 V3: 1.8K Transfer: 6.4K │ 1.1 µs/tx │
│ │ │ │
│ TX SOURCE │ EIP-1559 GAS ORACLE 250ms │ BENCHMARKS │
│ Classified │ Base: 0.020 Priority: 2.0 Pred: 0.0175 │ 40.7 ns/op │
│ 41.2K │ │ 425 ns/op │
│ │ │ 4 workers │
│ Buffer 0% │ │ ERRORS 0 │
└──────────────┴──────────────────────────────────────────────┴──────────────┘

Features:

  • 3-column layout: Network stats, pipeline center, live feed + metrics
  • Transaction Processing Pipeline with animated particle flow
  • Classification Breakdown (Swap V2, V3, Liquidation, Flash Loan, Transfer)
  • EIP-1559 Gas Oracle with base fee prediction gauges
  • Live Pipeline metrics: classify stage latency, block processing, RPC latency (histogram avg)
  • Engine Benchmarks: static go test -bench results (40.7 ns/op classify, 425 ns/op basefee)
  • Multi-RPC health indicator (healthy / total endpoints)
  • Live event feed with color-coded OPP / BLOCK badges
# 1. Start the full pipeline (Go network node + Rust gRPC core)# Go node serves Prometheus metrics on :9091# Dashboard polls :9091 every 2 seconds
make live
# 2. Open dashboard in browser
open dashboard/index.html
# Alternative: start components individuallycd network && go run ./cmd/mev-node/ # Go node (metrics on :9091)cd core && cargo run --release # Rust gRPC core

Performance Characteristics

All benchmarks on Intel i5-8250U @ 1.60GHz, Criterion 0.5. Production targets co-located bare-metal.

Pipeline Latency Profile

Stagep50p99p999Notes
Classification (Go)40 ns~65 ns~110 nszero alloc, branch-predictable selector dispatch
Detection (Rust)120 ns~210 ns~400 nslock-free queue input, cached pool state
Simulation (Rust)220 ns~350 ns~700 nsconstant-product fast-path, checked arithmetic
Bundle construction53 ns~80 ns~150 nsABI encode, packed 72-byte path
Full pipeline608 ns~1.1 µs~2.3 µsexcludes network

p99/p999 estimated from Criterion distribution tails. Full pipeline processes a transaction 1500× faster than Arbitrum's 250ms block time.

Tail latency dominated by:

  • Cross-thread handoff (crossbeam bounded channel)
  • Cache misses on cold pool lookups (DashMap, 10k entries)
  • Keccak-256 hashing (552 ns, address verification)

Per-Operation Benchmarks

OperationLatencyNotes
Keccak-256 (32 bytes)552 nstiny-keccak — address hashing
Constant-product swap (1 ETH)35 nsx·y = k with 30 bps fee
Two-hop arbitrage (buy DEX A → sell DEX B)69 nsCross-DEX price discrepancy
Pool lookup (10k DashMap)55 nsConcurrent read, pre-populated
ABI encode swap path (3-hop)53 ns72-byte packed path
Full pipeline (detect → simulate → build)608 nsEnd-to-end per opportunity
U256 mul + div83 nsalloy 256-bit arithmetic
Crossbeam channel send+recv23 nsBounded 4096, single item
Tx classification (Go)40.7 ns/op0 B / 0 alloc — ~24.5M tx/sec
EIP-1559 base fee calc (Go)425 ns/op152 B / 6 alloc — ~2.3M/sec

Latency Budget

┌─────────────────────────────────┬──────────────┬─────────────┐
│ Component │ Latency │ % of total │
├─────────────────────────────────┼──────────────┼─────────────┤
│ Arbitrum RPC (network) │ 1–5 ms │ ~99.9% │
│ gRPC serialization (Go↔Rust) │ 5–20 µs │ ~0.09% │
│ Internal pipeline │ ~0.6 µs │ ~0.01% │
└─────────────────────────────────┴──────────────┴─────────────┘

Network dominates by ~1000×. The system is optimized for deterministic internal latency, not network speed. Every microsecond saved in compute is meaningless if RPC adds 3ms of jitter — but deterministic execution means consistent behavior under load, which matters for queue ordering and opportunity capture.


Concurrency & Contention Model

Hot path (zero contention):

  • MPMC lock-free queue: Vyukov per-slot sequence ticket (claim → write payload → release-store sequence)
  • Eliminates the classic claim-then-write race a naive CAS-on-tail design exhibits — consumer cannot read a slot whose payload hasn't been published
  • alignas(64) head/tail → eliminates false sharing across cache lines
  • Bounded queues (4096) → prevents unbounded latency growth
  • Validated under 4M-item stress test (8 producers / 1 consumer, capacity 1024 forcing backpressure): zero loss, zero duplicates, per-producer FIFO preserved, 9.6 Mops/s on i5-8250U

Backpressure strategy:

  • Queue saturated → drop + degrade to monitor-only mode
  • No blocking in hot path — ever
  • Crossbeam bounded channels between detector→simulator→builder stages

Thread model:

  • Go: goroutine pool for classification (no cgo, scheduler-friendly)
  • Rust: Tokio multi-threaded runtime + crossbeam worker pool for parallel detection
  • C: called via FFI from Rust — single-threaded per invocation, no locking

Memory & Allocation Strategy

ComponentStrategyGC Impact
Go classifierZero allocations (40.7 ns/op, 0 B/op)None in hot path
C queue + poolArena allocator with batch rollback, preallocated slotsN/A
C tx parserStack-allocated decode buffers, length-validatedN/A
Rust detectorDashMap pre-populated pool cache, stack-local PendingTxN/A
Rust simulatorchecked_mul/checked_add on stack, no heap per simulationN/A
Go metrics/loggingStandard allocations — confined to non-hot pathsGC here only

Go GC is confined to metrics, logging, and configuration. Classification and selector dispatch are allocation-free. C arena allocator supports atomic rollback on partial batch failure.


Behavior Under Load

Scenario: burst of 10k+ transactions per block.

Failure ModeResponseGuarantee
Queue saturationBounded MPSC drops excess, switches to monitor-onlyNo unbounded memory growth
Detection lagDegrades to classify-only (skips Rust core)Pipeline never blocks
RPC lag / timeoutMulti-endpoint failover, latency-based routingNo single point of failure
gRPC overloadToken-bucket rate limiter (1000 RPS, packed AtomicU64)Predictable throughput cap
WebSocket disconnectExponential backoff (1s → 2s → 4s … 30s cap)No RPC hammering
C library missingPure-Rust fallback (keccak, RLP, price impact)Compiles and runs without C

Guarantees under all load conditions:

  • No unbounded memory growth
  • No blocking in hot path
  • No cascading failure across layers
  • Bounded queue depth = bounded worst-case latency

Non-Goals / Not Optimized

Not ImplementedWhy
Kernel bypass (DPDK / io_uring)Network latency (~ms) dominates; kernel bypass saves ~µs on a ms-bound path
NUMA pinningSingle-node assumption; would matter on multi-socket servers
FPGA / hardware accelerationCompute path is already sub-µs; hardware offload ROI is negative at this scale
Userspace networkingSame reasoning as DPDK — bottleneck is RPC, not NIC
Custom memory allocator (jemalloc)Arena allocator in C hot path is sufficient; Rust default allocator performs well

Focus is strictly on: deterministic user-space execution and minimal jitter in the compute path. Network-bound systems benefit from reliability, not raw NIC speed.


Go Network Layer — network/

Production-grade mempool monitoring used as the entry point for the MEV pipeline. See network/README.md for full documentation.

PackageRole
internal/mempoolWebSocket pending-tx subscription (gethclient), selector filtering, gRPC forwarding to Rust core with 100ms timeout and graceful fallback
internal/pipelineMulti-worker classifier — UniswapV2 (6 selectors), V3 (4), ERC20, Aave, flash loans. Zero-allocation hot path at 40.7 ns/op
internal/blockNew-head subscription with reorg detection, polling fallback. BlockTxChan() for block-based tx feed on L2 without public mempool
internal/gasEIP-1559 base fee oracle with multi-block prediction
internal/relayFlashbots eth_sendBundle + multi-relay manager (Race / Primary / All). EIP-191 bundle signing, eth_callBundle dry-run, flashbots_getBundleStats
internal/rpcConnection pool, health checks, latency-based routing, automatic reconnection
internal/metrics20+ Prometheus metrics: RPC latency histograms, mempool buffer usage, pipeline classification breakdown, relay submission success/failure, gas oracle tracking, node health
cmd/mev-nodeMain binary — pipeline orchestration
cmd/testnet-verifyTestnet signing verification (EIP-1559 tx + EIP-191 bundle proof)
cd network
go build ./... # compile all binaries
go test ./... -v # 23 tests across 4 packages
go test -bench . ./... # selector + gas oracle benchmarks

Rust Core Engine — core/

High-performance detection, simulation, and bundle construction. See core/README.md for full documentation.

  • revm 8.0 — two-stage simulation: AMM math fast filter (35 ns) + fork-mode EVM execution for full state validation
  • Tokio 1.35 — async multi-threaded runtime
  • crossbeam — lock-free channels for detector→simulator pipeline
  • alloy + ethers — type-safe Ethereum primitives and ABI encoding
  • Prometheusmetrics-exporter-prometheus with custom TCP server (:9091, CORS-enabled) for real-time dashboard
  • Block-based TX classifier — classifies every transaction by 4-byte selector (V2/V3 swaps, transfers) since Arbitrum has no public mempool
  • tonic + prost — gRPC server exposing detection pipeline to Go
cd core
cargo build --release # opt-level=3, lto=fat, codegen-units=1
cargo test --lib # 163 unit tests
cargo test# full suite incl. integration + proptest
cargo bench # 7 Criterion benchmark groups

Detection Pipeline

PendingTx → parse_swap() → ArbitrageDetector ──┐
(8 selectors, BackrunDetector ────┼─▶ Stage 1: AMM Math ──▶ Stage 2: revm Fork ──▶ BundleBuilder ──▶ Bundle
checked math) LiquidationDetector─┘ (35 ns filter) (full EVM validate) (ABI encode)
  • ArbitrageDetector: Cross-DEX price discrepancy with cached pool state, checked arithmetic
  • BackrunDetector: Price recovery capture after large swaps with impact threshold
  • LiquidationDetector: Aave V3, Compound V3, Morpho position tracking with close factor limits
  • MultiThreaded: Parallel worker pool via crossbeam channels
  • Simulator (two-stage): Stage 1 — V2 constant-product (35 ns) + V3 concentrated liquidity via sqrtPriceX96, auto-routing by pool type. Stage 2 — EvmForkSimulator runs survivors through revm 8.0 fork execution with CacheDB, full state diff extraction, and revert decoding

gRPC Bridge (Go ↔ Rust)

ComponentLocationProtocol
Service definitionproto/mev.protoMevEngine — 3 RPCs
Rust servercore/src/grpc/server.rstonic 0.11
Go clientnetwork/internal/strategy/client.gogoogle.golang.org/grpc 1.60

RPCs: DetectOpportunity (unary detect+simulate+build), StreamOpportunities (server-streaming via tokio::broadcast with profit threshold filter), GetStatus (health + uptime + counters)

Target: < 10ms round-trip for detect + simulate + bundle on co-located infra.


Smart Contracts — contracts/

Solidity + targeted inline Yul assembly. Foundry-based build, 26 tests (access control, callback hardening, fuzz, invariant, YulUtils 512-bit math).

Architecture: Balancer V2 flash loan (0% fee vs Aave's 0.09%) → multi-hop atomic swaps → profit check → repay. Single-tx execution, reverts if unprofitable.

Contract Overview

ContractPurposeGas Optimization
FlashArbitrage.solBalancer V2 flash loan → multi-DEX routing, callback hardeningInline Yul: _balanceOf(), _safeTransfer(), _safeApprove() skip ABI encoder/decoder
MultiDexRouter.solV2/V3/Sushi direct pool calls (bypasses routers), packed calldata pathsUses YulUtils.sol for all AMM math + calldata parsing
YulUtils.solPure Yul assembly library — 15+ functions, internal pure for compiler inliningZero external call overhead: mulDiv(), sqrt(), getAmountOut(), hash2(), loadCalldataAddress()

Why Yul

In MEV, gas saved = profit captured. Yul is used only in the hot loop (ERC20 ops called per swap, AMM math per hop), not in business logic:

executeArbitrage() ← Solidity (readable, auditable)
└─ receiveFlashLoan() ← Solidity (5-field callback validation)
└─ _executeSwaps() ← Solidity (routing logic)
├─ _swapUniV2() ← Solidity + Yul (_safeApprove, _safeTransfer)
├─ _swapUniV3() ← Solidity + Yul (_safeTransfer in callback)
└─ getAmountOut() ← YulUtils (pure assembly, constant-product)

Callback Security Model

5-field execution context prevents forged callbacks — even if attacker controls a malicious token:

executeArbitrage() sets: executionActive, pendingExecutor, pendingToken, pendingAmount, pendingSwapHash
→ Vault calls receiveFlashLoan()
→ Validates: msg.sender == BALANCER_VAULT
→ Validates: executionActive == true
→ Validates: keccak256(executor, token, amount, nonce) == pendingSwapHash
→ Executes swaps → checks profit ≥ MIN_PROFIT_BPS (0.1%) → repays loan
→ Clears context + increments nonce (replay protection)

Packed Calldata (MultiDexRouter)

executeSwapPath() uses custom-packed encoding instead of ABI — parsed with Yul loadCalldataAddress():

[amountIn: 32B][tokenIn: 20B][numSwaps: 1B][swapType: 1B][pool: 20B][tokenOut: 20B] × N

Interfaces

InterfaceCoverage
IBalancerVault.solflashLoan() + IFlashLoanRecipient callback
IERC20.solStandard ERC20 + IWETH (deposit/withdraw)
IUniswapV2.solPair (swap, getReserves), Router, Factory
IUniswapV3.solPool (swap, slot0, observe), Factory, SwapRouter, QuoterV2

Deploy & Test

cd contracts
forge build # Compile all
forge test -vvv # 24 tests — FlashArbitrage (14), MultiDexRouter, YulUtils (10)
forge test --gas-report # Per-function gas usage
forge script script/DeployArbitrum.s.sol:DeployArbitrumSepolia --rpc-url $RPC --broadcast # Testnet deploy

Folder Structure

contracts/
├── src/
│ ├── FlashArbitrage.sol # Flash loan + multi-DEX execution
│ ├── MultiDexRouter.sol # Direct pool routing + packed calldata
│ ├── interfaces/ # IBalancerVault, IERC20/IWETH, IUniswapV2, IUniswapV3
│ └── libraries/
│ └── YulUtils.sol # Pure Yul assembly: mulDiv, sqrt, getAmountOut, hash2, calldata parsing (15+ fns)
├── test/
│ ├── FlashArbitrage.t.sol # Foundry test suite (14 tests)
│ ├── MultiDexRouter.t.sol # Router tests
│ └── YulUtils.t.sol # 512-bit mulDiv precision + fuzz tests (10 tests)
├── script/
│ ├── Deploy.s.sol # Generic deploy script
│ └── DeployArbitrum.s.sol # Arbitrum Sepolia + Mainnet deploy
└── foundry.toml # Optimizer: 1M runs, via-ir enabled

C Hot Path — fast/

SIMD-accelerated C primitives plus C++20 AMM simulation kernel, all linked into Rust via FFI (core/src/ffi/).

C Files

FileFunctionOptimizationSafety
keccak.cKeccak-256 (24-round permutation, Ethereum 0x01 padding)Batch hashingmemcpy absorb — no alignment UB
rlp.cRLP encoding (tx serialization)Zero-copy outputBounds-checked length prefixes
simd_utils.cByte comparison, address matching, batch price impact (__uint128_t)AVX2 + SSE4.2, _mm_prefetch binary search, non-temporal storesMixed-case hex decode (A-F + a-f)
lockfree_queue.cMPSC queue (detector→simulator)CAS-only, no mutexalignas(64) head/tail — no false sharing, CAS slot-claim before write
memory_pool.cArena allocator (3 specialized pools)Zero-alloc per tx, batch allocAtomic rollback on partial batch failure
parser.cBinary calldata parsing (V2/V3 ABI)Unrolled loopsLength validation before decode

C++20 Files

FileFunctionTechniqueC ABI Export
amm_simulator.h/cppV2 constant-product + V3 approximate AMM math__uint128_t intermediate overflow protection, template specialization V2/V3amm_v2_amount_out, amm_v2_amount_in, amm_v3_amount_out
pathfinder.h/cppMulti-hop BFS path finder (SoA pool graph, 256-pool cap, 48-iter ternary search)FNV-1a address fingerprints, struct-of-arrays pool graph, stack-allocated BFS queuepathfinder_find_best, pathfinder_graph_upsert, pathfinder_graph_reset

Compile flags: -O3 -march=native -mavx2 -msse4.2 -flto -falign-functions=64

cd fast
make # → lib/libmev_fast.a + lib/libmev_fast.so
make test# correctness + SIMD validation
make bench # hot-path benchmarks

Quick Start

Prerequisites

ToolVersionPurpose
Rust1.75+Core engine
Go1.21+Network layer
FoundryLatestContract compilation + testing
GCC / Clang13+C hot path (AVX2 support) + C++20 simulation kernel (amm_simulator, pathfinder)

Build & Run

# 1. Clone
git clone https://github.com/Faraone-Dev/mev-engineering-stack.git
cd mev-engineering-stack
# 2. Configure
cp .env.example .env
# Edit .env with your RPC endpoints and signing key# 3. Build
make build # all layers (or build individually below)# 4. Test
make test# all layers# 5. Runcd network && go run ./cmd/mev-node/
# 6. Benchmarkcd core && cargo bench

Environment Variables

VariableDescriptionDefault
MEV_RPC_ENDPOINTSComma-separated WebSocket RPC URLs
ARBITRUM_RPC_URLArbitrum HTTP endpoint
ARBITRUM_WS_URLArbitrum WebSocket endpoint
EXECUTE_MODEBundle execution mode (simulate or live)simulate
PRIVATE_KEYEOA key used to sign EIP-1559 executor transactions
FLASHBOTS_SIGNING_KEYECDSA key for bundle signing (EIP-191)
MEV_USE_FFIEnable C fast-path wrappers (1/true) when availablefalse
MEV_PIPELINE_WORKERSParallel classification workers4
MEV_METRICS_ADDRPrometheus metrics bind address:9090

See .env.example for the full list. See CONFIG.md for detailed field descriptions of all configuration files.


Testnet Verification

The testnet-verify tool proves the entire signing + bundle pipeline end-to-end against Arbitrum Sepolia without spending gas:

cd network
go run ./cmd/testnet-verify/
# Output:# ✓ Signing Key : 0xa2F3...# ✓ Chain : Arbitrum Sepolia (421614)# ✓ EIP-1559 Tx : Signed (111 bytes)# ✓ EIP-191 Sign : Verified (Flashbots format)# ✓ Bundle : Target block N+1# ○ Submission : Dry-run (use --submit)

Flags: --key (reuse signing key), --rpc (custom RPC), --submit (live submission).


Test Coverage

LayerTestsFrameworkWhat's Tested
Rust core192 tests (158 unit + 11 integration + 23 proptest)cargo test + proptest + CriterionSee breakdown below
Go network23 tests, 2 benchmarksgo testConfig parsing, EIP-1559 oracle, tx classification (V2/V3 selectors), multi-relay strategies
Rust bench7 groupsCriterion 0.5Full pipeline, keccak, AMM, pool lookup, ABI, U256, crossbeam
Solidity24 testsforge testFlash arbitrage execution, multi-DEX routing, callback validation, YulUtils 512-bit mulDiv
C hot pathmake testCustom runnerKeccak correctness, RLP encoding, SIMD validation

Rust Core — 192 Tests Breakdown

ModuleTestsCoverage
detector/arbitrage26V2/V3/V3-output calldata parsing, ABI word decoders, decode_addr, dex_from_fee, match_pool_to_swap, profit calc (profitable/gas-exceeds/no-arb), truncated calldata
detector/backrun3Swap selectors, price impact, small-swap filter
detector/liquidation4Liquidation detection, healthy skip, close factor, stale pruning
detector/multi_threaded1Parallel swap simulation
simulator19Constant-product math (happy/zero/overflow/fee=100%), pool cache (load/update/get/reserves fallback), simulate (arb/backrun/liquidation/bundle), success rate
simulator/evm9ForkDB insert/query + storage slots, revm ETH transfer, revert/panic decoding, calldata encode roundtrip, profit extraction, metrics counter, BlockContext update
builder16ABI encoding, all 3 bundle types, swap path (2-hop/empty/missing pool), no-contract error, count
config9Serde roundtrip, save/reload, from_env fallback, chain defaults, strategy, performance
ffi/hot_path24Keccak-256 known vectors, function selectors (transfer/approve/V2 swap), address_eq, RLP encoding, OpportunityQueue FIFO, TxBuffer cap, SwapInfoFFI
ffi/simulator4v2_amount_out basic/mainnet-scale reserves, token fingerprint stable/distinct
ffi3Keccak fallback, RLP single byte, RLP short string
grpc/server3bytes_to_u128 edge cases
mempool/ultra_ws11Tx hash extraction, swap classification (V2/V3/Universal Router), non-swap rejection
arbitrum/pools12AMM get_amount_out (basic/reverse/zero/high-fee), get_price, token list validation
types8estimate_gas for all DexType × OpportunityType combinations
proptest23Constant-product invariants (7), ABI roundtrip (3), gas bounds (5), keccak (3), data structures (2), swap selectors (1), overflow safety (2)
integration11Full pipeline end-to-end, engine lifecycle, all bundle types, simulator count, gRPC E2E

CI/CD

GitHub Actions pipeline with 4 parallel jobs — each layer builds and tests independently:

JobStepsToolchain
Rust Corecargo fmt --checkcargo clippy -D warningscargo testcargo build --releasedtolnay/rust-toolchain@stable + rust-cache
Go Networkgo vetgo test ./...go build ./cmd/mev-nodeGo 1.21
Solidity Contractsforge buildforge test -vvFoundry nightly
C/C++ KernelCompiled via cc crate in build.rs during Rust buildWindows: MSVC /std:c++20, Linux/Mac: -std=c++20 -fno-exceptions -fno-rtti

Bugs Found & Fixed

BugSeverityModuleFix
is_likely_swap() — OR condition classified all non-zero-first-byte txs as swapsCriticalmempool/ultra_wsRemoved || (selector[0] != 0x00)
constant_product_swap() — unchecked u128 arithmetic silently overflowed on whale tradesHighsimulatorchecked_mul/checked_add, returns 0 on overflow
Proptest tested local copy of AMM function, not production codeHightests/proptestNow imports mev_core::simulator::constant_product_swap directly
div_u256_by_u128 — Knuth division produced wrong quotient on large dividendsHighsimulatorReplaced with standalone loop-based algorithm, 3 edge-case tests
pool_put() — race condition: count incremented before data writtenHighfast/memory_pool.cCAS slot-claim → write → release fence → atomic count increment
WebSocket reconnection — no backoff on disconnect, hammered RPC on failureMediummempool/ultra_wsExponential backoff (1s → 2s → 4s … 30s cap)
gRPC server — no rate limiting, vulnerable to request floodingMediumgrpc/serverToken-bucket rate limiter (1000 RPS, packed AtomicU64)
FlashArbitrage require(string) — wastes gas on revert stringsLowcontractsCustom error ContractPaused() replaces require string
Dashboard unauthenticated — no mention in security docsInfoSECURITY.mdAdded dashboard authentication section

Design Decisions

DecisionRationaleTradeoff
5 languagesGo for concurrent network I/O, Rust for safe high-perf compute, C++ for AMM simulation kernel + path optimizer, C for SIMD hot paths, Solidity for on-chainOperational complexity vs optimal tool per domain
gRPC over FFI for Go↔RustAvoids cgo thread pinning → preserves Go scheduler fairness. Isolates failure domains (process boundary)Adds ~5–20 µs overhead, acceptable vs ms-level network latency
C++ AMM kernel over pure Rust__uint128_t overflow safety for V2 math at live reserve scale (1e20), compiles with MSVC + GCC + ClangAdds build dependency on C++20 compiler; cc crate handles cross-platform compilation
revm over forked gethPure Rust, no cgo dependency, deterministic gas. Two-stage: AMM math filter (35 ns) screens candidates, revm fork execution validates survivorsrevm fork adds ~50–200 µs per call, justified only for Stage 1 survivors
Balancer flash loans0% fee vs Aave's 0.09%. When margins are basis points, eliminating the fee is criticalBalancer pool TVL limits flash loan size
Constant-product fast filterx·y=k at 35 ns screens candidates before expensive simulation. Only survivors hit EVMMisses V3 concentrated liquidity edge cases
Arbitrum-first10–100× cheaper gas, 250ms blocks, less MEV competitionNo public mempool → requires block-based reconstruction
Monitor-only fallbackGo node degrades gracefully when Rust core is offline — logs, doesn't crashMisses opportunities during degraded mode
Bounded queues everywherePrevents unbounded memory growth, gives worst-case latency guaranteesDrops excess transactions under extreme load

Fault Tolerance

Every layer degrades gracefully. No panics, no silent failures.

FailureResponseRecovery
RPC endpoint downHealth check detects within 30s, routes to lowest-latency healthy clientAuto-failover to remaining endpoints
All RPCs unhealthyFalls back to first available clientContinues operating in degraded mode
WebSocket disconnectsLogs error, sleeps 1s, reconnects automaticallyMempool monitor self-heals
WS subscription failsBlock watcher falls back to HTTP polling (250ms interval)Transparent — no data loss
Rust gRPC core offlineGo node enters monitor-only mode — classifies without detectionResumes full pipeline when core reconnects
C library missingRust FFI auto-switches to pure-Rust fallbacks (keccak, RLP, price impact)Compiles and runs without C toolchain
Pool cache coldArbitrage detector uses estimate_cross_dex_prices() with typical reservesBootstraps until live data populates cache
Block fetch overloadSemaphore limits to 4 concurrent goroutines, 10s timeoutPrevents RPC saturation on fast chains
Primary relay failsMulti-relay manager tries fallback relays sequentiallyRace / Primary+Fallback / All strategies
Config missingenvString(key, fallback) pattern on every variableSensible defaults — never crashes on missing env

MEV Ethics

This stack extracts constructive MEV only:

TypeStatusImpact
Arbitrage✅ SupportedAligns prices across DEXs — improves market efficiency
Backrun✅ SupportedCaptures residual slippage after large swaps — no harm to original trader
Liquidation✅ SupportedCloses undercollateralized positions — maintains protocol solvency
Front-running❌ Not implementedCopy and front-run pending transactions — predatory
JIT liquidity❌ Not implementedTemporary liquidity manipulation — market distortion

All detected opportunities are non-predatory. No user transactions are harmed or front-run.


Project Structure

mev-engineering-stack/
├── core/ # Rust — detection, simulation, bundle construction
│ ├── src/
│ │ ├── detector/ # ArbitrageDetector, BackrunDetector, LiquidationDetector
│ │ ├── simulator/ # EvmSimulator — V2 constant-product (35 ns) + V3 concentrated liquidity (sqrtPriceX96), auto-routing
│ │ ├── builder/ # BundleBuilder (ABI encoding, gas pricing)
│ │ ├── grpc/ # tonic server — DetectOpportunity, StreamOpportunities (broadcast channel + profit filter), GetStatus
│ │ ├── arbitrum/ # Arbitrum L2 engine: 3-DEX pool discovery (V3/Sushi/Camelot), triangular arb, Balancer V2 flash executor
│ │ ├── ffi/
│ │ │ ├── hot_path.rs # C FFI bindings (keccak, RLP, SIMD, queue, address ops)
│ │ │ └── simulator.rs # C++ AMM FFI bindings (v2_amount_out, v2_amount_in, v3_amount_out) + pure-Rust fallbacks
│ │ └── mempool/ # WebSocket data handling
│ └── benches/ # Criterion benchmarks (7 groups)
├── network/ # Go — mempool monitor, pipeline, relay
│ ├── cmd/mev-node/ # Main binary
│ ├── cmd/testnet-verify/ # Testnet signing verification tool
│ ├── internal/ # block, gas, mempool, pipeline, relay, rpc, metrics
│ └── pkg/ # config, types (public packages)
├── contracts/ # Solidity + Yul — flash arbitrage, multi-DEX routing
│ ├── src/
│ │ ├── FlashArbitrage.sol # Balancer V2 flash loan (0% fee), 5-field callback hardening, inline Yul ERC20
│ │ ├── MultiDexRouter.sol # Direct pool calls (V2/V3/Sushi), packed calldata encoding
│ │ ├── libraries/
│ │ │ └── YulUtils.sol # Pure Yul assembly: mulDiv, sqrt, getAmountOut, hash2, calldata parsing (15+ fns)
│ │ └── interfaces/ # IBalancerVault, IERC20/IWETH, IUniswapV2, IUniswapV3
│ ├── test/
│ │ ├── FlashArbitrage.t.sol # 14 tests
│ │ ├── MultiDexRouter.t.sol
│ │ └── YulUtils.t.sol # 10 tests: 512-bit mulDiv precision + fuzz
│ └── script/
│ ├── Deploy.s.sol
│ └── DeployArbitrum.s.sol # Arbitrum Sepolia + Mainnet
├── fast/ # C + C++20 — SIMD hot paths + AMM simulation kernel
│ ├── include/
│ │ ├── keccak.h
│ │ ├── rlp.h
│ │ ├── simd_utils.h
│ │ ├── lockfree_queue.h
│ │ ├── memory_pool.h
│ │ ├── parser.h
│ │ ├── amm_simulator.h # C++20 V2/V3 AMM kernel: ternary-search, __uint128_t, C ABI
│ │ └── pathfinder.h # C++20 BFS pathfinder: SoA graph, FNV-1a fingerprints, C ABI
│ └── src/
│ ├── keccak.c
│ ├── rlp.c
│ ├── simd_utils.c
│ ├── lockfree_queue.c
│ ├── memory_pool.c
│ ├── parser.c
│ ├── amm_simulator.cpp # C++ translation unit
│ └── pathfinder.cpp # C++ translation unit
├── proto/ # gRPC service definition
├── dashboard/ # Real-time monitoring (HTML/JS)
├── config/ # Chain + DEX + token configs (JSON)
├── docker/ # Dockerfile, docker-compose, prometheus.yml
├── scripts/ # Build and deploy automation
├── Makefile # Top-level build orchestration
└── .env.example # Environment template (no secrets)

License

Proprietary. See LICENSE for details.


⚠️ Execution Modes & Risk Posture

This stack supports both read-only simulation and signed relay submission:

  • simulate (default): detect, simulate, build, and dry-run without sending signed bundles.
  • live: signs EIP-1559 executor transactions and submits bundles to configured relays.

Live Mode Requirements

  • EXECUTE_MODE=live
  • PRIVATE_KEY present (executor transaction signer)
  • FLASHBOTS_SIGNING_KEY present (bundle auth signer)
  • Deployed and configured contracts (FlashArbitrage, MultiDexRouter) on target chain

The launcher and node configuration fail fast if required live credentials are missing.

Current Readiness

  • ✅ End-to-end pipeline: ingest → classify → detect → simulate → build → relay handling
  • ✅ Preflight relay simulation (eth_callBundle) before live submission
  • ✅ Real-time metrics and dashboard for operational visibility
  • ⚠️ Not audited for real funds; run with testnet/simulation defaults unless you accept production risk

Recommended workflow: validate strategy changes in simulate, then promote selectively to live with audited contracts and strict key management.

About

MEV Engineering Stack | Rust + Go + C + Solidity | Flashbots Integration | Low-Latency Mempool Analysis | DEX Arbitrage | High-Performance EVM Trading Infrastructure

Topics

Resources

Contributing

Security policy

Stars

19 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages