Truthful discovery of constraints. Zero capital risk. Research-grade rigor.
A production-grade research system for validating liquidation MEV hypotheses on Aave v3 (Arbitrum). Phase A was explicitly research-first, not profit-driven. Success criteria were correctness and honesty, not positive PnL.
This repository contains the results of Phase A of the MEV Liquidation Engine research project. Phase A focused on building a truthful, reproducible simulation and backtesting framework to evaluate liquidation strategies under realistic MEV competition.
Primary Outcome: A negative but highly informative result — a latency-disadvantaged liquidator exhibits ~0% capture probability when competing against frontrunner bots operating at effective latencies of ~25ms.
This result validates both the correctness of the simulation framework and the dominant role of latency in real-world MEV liquidation markets.
Latency is not a tunable parameter — it is a structural constraint.
Beating frontrunners executing at ~25ms cannot be achieved by incremental optimization of a standard liquidation pipeline. Competing honestly in public mempools under these conditions is not viable.
| Liquidator Latency | Capture Probability |
|---|---|
| 10ms | High (>60%) |
| 20ms | Moderate (20–40%) |
| 25ms | Low (~5–10%) |
| 35ms | Near-zero |
| 50ms | ~0% |
| 75ms | ~0% |
| 100ms | ~0% |
Observed behavior: A steep, non-linear cliff around the frontrunner latency boundary. Capture probability does not degrade gradually — it collapses once the liquidator becomes even marginally slower than frontrunners.
The system did not fail to find profit — it correctly demonstrated why profit is unlikely under these conditions:
- Liquidations are winner-takes-most
- Small latency advantages dominate outcomes
- Honest, reactive liquidators are structurally disadvantaged
A simulator that consistently finds profit under these assumptions would be suspect.
Moving from Python → Rust or JS → Go may reduce local execution time, but does not overcome:
- Network propagation latency
- RPC round-trip time
- Builder/relay ordering
- Competitor pre-positioning
Latency dominance is architectural, not syntactic.
- Build a safe, deterministic MEV simulation environment
- Accurately model competitive liquidation dynamics
- Quantify the impact of latency and strategy archetypes
- Avoid optimistic bias or parameter tuning to force profitability
All objectives achieved.
┌──────────────────────────────────────────────────────────┐
│ CLI / Jupyter Dashboard (visualization & entry points) │
└──────────────────────────────────────────────────────────┘
▲
┌──────────────────────────────────────────────────────────┐
│ Core Analysis (backtest, opportunity_detector) │
│ - Rolling-window backtesting │
│ - Hypothesis testing framework │
└──────────────────────────────────────────────────────────┘
▲
┌──────────────────────────────────────────────────────────┐
│ Simulation Layer (engine, bots) │
│ - Monte Carlo engine with deterministic seeding │
│ - 10 bot archetypes │
│ - Bootstrap confidence intervals │
└──────────────────────────────────────────────────────────┘
▲
┌──────────────────────────────────────────────────────────┐
│ Data Layer (aave_v3, position_loader, health_factor) │
│ - Position ingestion (CSV, JSON, synthetic) │
│ - Verified health factor calculation │
│ - Market conditions modeling │
└──────────────────────────────────────────────────────────┘
▲
┌──────────────────────────────────────────────────────────┐
│ Safety Layer (safe_mode, logging) │
│ - SAFE_MODE enforcement (testnet/fork only) │
│ - Hash-chained logging for auditability │
│ - Strict safety checks on all execution paths │
└──────────────────────────────────────────────────────────┘
| Parameter | Value |
|---|---|
| Execution Latency | ~75ms |
| Pipeline | Honest detection → simulation → execution |
| Privileges | None (no private orderflow or builder access) |
| Parameter | Value |
|---|---|
| Frontrunner Nominal Latency | 50ms |
| Effective Execution | latency_ms * 0.5 |
| Effective Latency | ~25ms |
Effective latency reflects realistic optimizations:
- Pre-signed transactions
- Optimistic simulation
- Parallel RPC usage
- Speculative execution
| Bot Type | Strategy | Activation | Nominal Latency |
|---|---|---|---|
| Frontrunner (2) | Execute before target | 70% | 50ms (eff: 25ms) |
| Backrunner (2) | Execute after, consume liquidity | 50% | 150ms |
| Random (2) | Stochastic behavior | 30% | 100ms |
| Gas Sensitive (2) | Only when gas < threshold | 40% | 100ms |
| Slippage Aware (1) | Only when slippage acceptable | 60% | 100ms |
| Tail Event (1) | Rare but high-impact | 1% | Variable |
- Result: ~0%
- Cause: Liquidator consistently loses races to faster frontrunners
- Interpretation: Expected and correct behavior under realistic MEV competition
- Latency dominance emerges naturally from the simulation
- No artificial profit bias is introduced
- Competitive pressure behaves as observed on mainnet
- Results are reproducible and statistically grounded
- Python 3.12+
- uv or pip
# Clone the repository
git clone https://github.com/Enricrypto/mev-liquidation-phase-a.git
cd mev-liquidation-phase-a
# Create virtual environment
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
# Install dependencies
pip install -e ".[dev]"
# Set SAFE_MODE (required)
echo "SAFE_MODE=true" > .env# Run all tests (157 total)
pytest -v
# Run with coverage
pytest --cov=mev_analysis --cov-report=htmlfrom mev_analysis.core.backtest import BacktestRunner, BacktestConfig, create_synthetic_positions
from mev_analysis.data.models import MarketConditions
from datetime import datetime, timezone
from decimal import Decimal
# Generate synthetic positions
positions = create_synthetic_positions(
num_positions=100,
num_liquidatable=20,
seed=42,
)
# Create market conditions
market = MarketConditions(
block_number=1000000,
timestamp=datetime.now(timezone.utc),
gas_price_gwei=Decimal("0.1"),
eth_price_usd=Decimal("2000"),
)
# Run backtest
config = BacktestConfig(num_simulation_iterations=100, num_seeds=10)
runner = BacktestRunner(config=config)
result = runner.run(positions, market)
print(f"Opportunities detected: {result.total_opportunities_detected}")
print(f"Mean EV: {result.overall_mean_ev_eth} ETH")
print(f"Capture probability: {float(result.overall_mean_capture_prob)*100:.2f}%")jupyter notebook notebooks/backtest_dashboard.ipynbmev-liquidation-phase-a/
├── src/mev_analysis/
│ ├── core/
│ │ ├── safe_mode.py # SAFE_MODE enforcement singleton
│ │ ├── logging.py # Hash-chained experiment logging
│ │ ├── backtest.py # Rolling-window backtesting
│ │ └── opportunity_detector.py # Liquidation opportunity detection
│ ├── data/
│ │ ├── models.py # Pydantic models (Position, Opportunity, etc.)
│ │ ├── aave_v3.py # Aave v3 client interface
│ │ ├── position_loader.py # CSV/JSON/list position loading
│ │ ├── health_factor.py # HF calculation with verification
│ │ └── constants.py # Arbitrum token addresses
│ ├── simulation/
│ │ ├── engine.py # Monte Carlo simulation engine
│ │ └── bots.py # 10 bot archetypes
│ └── cli.py # Command-line interface
├── tests/ # 157 comprehensive tests
├── notebooks/
│ └── backtest_dashboard.ipynb # Jupyter visualization
├── sample_data/ # Sample position data
└── docs/
├── ALPHA_HYPOTHESES.md # Testable hypotheses
├── EXPERIMENT_DESIGN.md # Research methodology
├── PROMOTION_CRITERIA.md # Phase B criteria
├── SYSTEM_ARCHITECTURE.md # Architecture details
├── OBSERVABILITY_SPEC.md # Metrics and logging
└── FAILURE_REPLAY_AND_RISK.md # Failure analysis
Total Tests: 157/157 All Passing
| Category | Tests | Status |
|---|---|---|
| Safe Mode | 18 | ✅ |
| Logging | 11 | ✅ |
| Models | 17 | ✅ |
| Health Factor | 13 | ✅ |
| Position Loader | 6 | ✅ |
| Bots | 17 | ✅ |
| Simulation Engine | 15 | ✅ |
| Opportunity Detector | 10 | ✅ |
| Backtest | 14 | ✅ |
| CLI | 36 | ✅ |
# Environment variable required
SAFE_MODE=true # Must be set
# Runtime verification
safe_mode = SafeMode.initialize()
safe_mode.verify_environment(chain_id=421614, is_fork=False) # Arbitrum Sepolia
safe_mode.verify_ev_cap(estimated_ev_eth=0.5) # Check against cap| Chain ID | Network | Status |
|---|---|---|
| 421614 | Arbitrum Sepolia | ✅ Allowed |
| 31337 | Local Hardhat/Anvil | ✅ Allowed |
| 1337 | Local Ganache | ✅ Allowed |
| 42161 | Arbitrum Mainnet |
- ✅ SAFE_MODE env check - Fails without
SAFE_MODE=true - ✅ Chain ID verification - Blocks unknown networks
- ✅ Fork detection - Mainnet requires
is_fork=True - ✅ EV cap enforcement - Prevents oversized simulations
- ✅ Private key safety - Requires verified environment
Every log entry includes the hash of the previous entry, making tampering detectable:
LogEntry(
timestamp="2025-01-15T12:00:00Z",
experiment_id="backtest_20250115_abcd1234",
message="Opportunity detected",
data={"user": "0x123...", "ev_eth": "0.05"},
previous_hash="a1b2c3d4...",
entry_hash="e5f6g7h8...", # SHA256 of entry + previous_hash
)All simulations use explicit random seeds for reproducibility:
# Same seed = same results
engine = SimulationEngine(config=SimulationConfig(base_seed=42))
result1 = engine.simulate(opportunity, market)
engine2 = SimulationEngine(config=SimulationConfig(base_seed=42))
result2 = engine2.simulate(opportunity, market)
assert result1.capture_probability == result2.capture_probability- Bootstrap CIs: Non-parametric confidence intervals
- Bonferroni Correction: Adjusted alpha for multiple hypotheses
- Minimum Sample Size: n ≥ 30 enforced
- Rolling Windows: Out-of-sample validation
Phase A conclusively shows that purely latency-based competition is a losing game for non-privileged liquidators. Any viable strategy must therefore:
- Reduce reliance on reactive execution
- Change the timing or visibility of execution
- Exploit information, structural, or market asymmetries
- Pre-positioned or capital-at-risk strategies
- Commit–reveal or delayed execution models
- Cross-market or cross-protocol liquidations
- Tail-event strategies where competition thins
- Private orderflow or builder-level integration
| Metric | Value |
|---|---|
| Total Tests | 157 ✅ |
| Test Files | 10 |
| Source Files | 15 |
| Lines of Code | 4,500+ |
| Bot Archetypes | 10 |
| Documentation Pages | 7 |
| Coverage | 100% critical paths |
- docs/ALPHA_HYPOTHESES.md - Testable hypotheses
- docs/EXPERIMENT_DESIGN.md - Research methodology
- docs/PROMOTION_CRITERIA.md - Phase B requirements
- docs/SYSTEM_ARCHITECTURE.md - Technical architecture
- docs/OBSERVABILITY_SPEC.md - Metrics and dashboards
- docs/FAILURE_REPLAY_AND_RISK.md - Failure analysis
| Phase | Status | Key Outcome |
|---|---|---|
| Phase A | Complete ✅ | Latency dominance validated |
| System Integrity | Validated ✅ | 157 tests passing |
| Key Constraint | Identified | ~0% capture at 75ms latency |
Phase A achieved its goal: truthful discovery of constraints.
The system is complete, correct, and research-grade. The observed 0% capture probability is not a failure but a critical result that prevents wasted effort and capital in later phases.
If you are slower than frontrunners by even ~10ms, your expected capture probability collapses to ~0%.
This holds regardless of implementation language or micro-optimizations.
MIT License - See LICENSE file
Built with research-grade engineering practices for DeFi MEV analysis.
MEV Liquidation Engine - Truthful discovery of constraints.
Phase A Status: Complete - Key Constraint Identified: Latency Dominance ✅