⚠️ Notice: This is entirely vibed by a mediocre engineer who didn't even read the code. Treat it accordingly. (Product VibeCoder)
Autonomous cyclic arbitrage searcher built on Fynd's market data infrastructure.
Based on Janos Tapolcai's simulation-based Bellman-Ford arbitrage searcher.
Unlike Fynd's solver (which finds A-to-B routes for incoming orders), the atomic searcher proactively scans for profitable arbitrage cycles:
WETH -> Token_1 -> Token_2 -> ... -> WETH
If it ends up with more WETH than it started with (after gas), the cycle is profitable.
- Subscribe to Tycho market updates via Fynd's
TychoFeed - Extract subgraph around WETH (BFS to
max_hopsdepth) - Bellman-Ford cycle detection: Layered BF relaxation with SPFA optimization, calling
get_amount_out()on actual pool simulations. After relaxation, check all edges pointing back to the source for cycles whereamount_out > amount_in - Golden section search: For each candidate cycle, optimize the input amount to maximize
profit = amount_out - amount_in - gas_cost - Log results: Print all cycles with path, optimal amount, profit, and gas cost
| Fynd's solver | Atomic Searcher | |
|---|---|---|
| Trigger | External order (token_in, token_out, amount) | Autonomous, every block |
| Objective | Maximize amount_out - gas for A to B |
Maximize amount_out - amount_in - gas for A to A |
| Input amount | Fixed (from order) | Optimized via golden section search |
| Output | Single best route | All profitable cycles |
# Set your Tycho API key (must have beta-feed access)
export TYCHO_API_KEY="your-key"
# Run with defaults (Ethereum, WETH, 4 hops, 0.001 ETH seed)
cargo run --release
# Customize
cargo run --release -- \
--chain ethereum \
--tycho-url tycho-beta.propellerheads.xyz \
--protocols uniswap_v2,uniswap_v3,sushiswap_v2 \
--max-hops 4 \
--seed-eth 1.0 \
--min-tvl 10.0
# Verbose logging
RUST_LOG=atomic_searcher=debug,fynd=info cargo run --releaseINFO Starting atomic searcher chain=Ethereum source_token=c02a...6cc2 max_hops=4
INFO Initial sync complete, starting search block=21234567 nodes=1842 edges=9234
INFO block search complete block=21234568 candidates=3 profitable=1 time_ms=12
INFO [PROFITABLE] #0: c02a.. -> 6b17.. -> c02a.. | optimal_in: 0.4200 ETH | net_profit: 0.000142 ETH | gas: 0.003200 ETH | hops: 3
INFO [unprofitable] #1: c02a.. -> a0b8.. -> c02a.. | optimal_in: 0.1500 ETH | net_profit: -0.001200 ETH | gas: 0.004100 ETH | hops: 2
src/
main.rs Entry point, CLI, Tycho feed, per-block search loop
cycle_detector.rs Modified Bellman-Ford for cycle detection
amount_optimizer.rs Golden section search for optimal trade size
executor.rs Encode / simulate / submit cycles (all execution modes)
flash_loan.rs Flash-strategy selection and FlashArbExecutor calldata
types.rs CycleCandidate, EvaluatedCycle, ExecutionMode, ...
contracts/
FlashArbExecutor.sol Flash-loan executor contract (UniV2 flash swap + Balancer flash loan)
test/ Foundry tests for FlashArbExecutor
The binary reuses Fynd library components (TychoFeed, SharedMarketData, PetgraphStableDiGraphManager) but implements its own search loop since it is not responding to external orders. Execution (optional, off by default) is encoded via tycho-execution and submitted either directly or through the flash-loan contract.
- Janos Tapolcai's original implementation: https://github.com/jtapolcai/tycho-searcher
- Fynd BellmanFord solver (A-to-B routing):
src/algorithm/bellman_ford.rs - Paper: https://www.overleaf.com/read/ksqhzzmndmqh
This is a showcase/educational tool, not production MEV software.
- Execution is opt-in and off by default (
--execution-mode log-only). Modes range fromsimulatethrough public-mempool, Flashbots-protected, and flash-loan execution. See GUIDE.md §4. - No cycle merging (shared-edge gas optimization, planned as follow-up)
- No MEV-Share auction integration (the
execute-protectedmode uses Flashbots Protect, a private mempool, but does not bid in MEV-Share) - Single-block horizon: no state prediction or multi-block strategies
- In current saturated markets, profitable cycles are rare (see Tapolcai et al., FC 2026)
The full pipeline has been exercised end to end with real Ethereum mainnet transactions (deliberately tiny, net-negative-after-gas trades run with --force-execute):
| Path | Transaction | Result |
|---|---|---|
execute-public swap |
0xcc0621f0…d151ce |
Success. Cyclic arb settled via TychoRouter; +0.0000511 WETH gross, net about −$0.32 (gas). |
FlashArbExecutor deploy |
0x054d7315…2cf924 |
Deployed to 0x9F56Db5E…cF891. |
execute-flash (Balancer flash loan) |
0x57946cee…faa947 |
Reverted at inclusion (state moved between snapshot and mined block). Atomic: gas only, no funds at risk. |
execute-flash (Balancer flash loan) |
0xac1277be…b34c0c |
Success. FlashArbExecuted(tier=2): borrow from Balancer Vault, cycle via TychoRouter, repay, sweep profit to owner. Contract left holding nothing. |
execute-flash (Balancer flash loan, current TychoRouter) |
0x34f4f533…d5cd3 |
Success. Settled through the current TychoRouter 0xdA892C…5736 (tycho-execution 0.302), the version this repo now targets. |
The reverted flash tx demonstrates the safety model: the on-chain min-out guard reverts the whole atomic transaction when the opportunity has already been taken, so a failed race costs only gas. Landing a successful flash trade used wider slippage (--slippage-bps 300) plus --verify-top-n (an eth_call pre-check) to skip cycles that would revert.
This repo targets the current Tycho monorepo release (tycho-execution 0.302), so execution routes through the current TychoRouter. That router takes an automatic protocol fee on output (set by its FeeCalculator); this searcher does not stack an additional client fee on top (ClientFeeParams is left empty, which also avoids the router's per-call EIP-712 signature requirement for a non-zero client receiver). Flash execution uses the Balancer flash-loan path only; the UniV2 flash-swap path is disabled because the current router pulls input via transferFrom while the contract's uniswapV2Call pushes it. Re-enabling the UniV2 flash-swap path needs an approve(router) added to the contract callback plus a redeploy.