Files
mev-beta/docs/8_reports/code_review_2025-10-27.md
Krypto Kajun c7142ef671 fix(critical): fix empty token graph + aggressive settings for 24h execution
CRITICAL BUG FIX:
- MultiHopScanner.updateTokenGraph() was EMPTY - adding no pools!
- Result: Token graph had 0 pools, found 0 arbitrage paths
- All opportunities showed estimatedProfitETH: 0.000000

FIX APPLIED:
- Populated token graph with 8 high-liquidity Arbitrum pools:
  * WETH/USDC (0.05% and 0.3% fees)
  * USDC/USDC.e (0.01% - common arbitrage)
  * ARB/USDC, WETH/ARB, WETH/USDT
  * WBTC/WETH, LINK/WETH
- These are REAL verified pool addresses with high volume

AGGRESSIVE THRESHOLD CHANGES:
- Min profit: 0.0001 ETH → 0.00001 ETH (10x lower, ~$0.02)
- Min ROI: 0.05% → 0.01% (5x lower)
- Gas multiplier: 5x → 1.5x (3.3x lower safety margin)
- Max slippage: 3% → 5% (67% higher tolerance)
- Max paths: 100 → 200 (more thorough scanning)
- Cache expiry: 2min → 30sec (fresher opportunities)

EXPECTED RESULTS (24h):
- 20-50 opportunities with profit > $0.02 (was 0)
- 5-15 execution attempts (was 0)
- 1-2 successful executions (was 0)
- $0.02-$0.20 net profit (was $0)

WARNING: Aggressive settings may result in some losses
Monitor closely for first 6 hours and adjust if needed

Target: First profitable execution within 24 hours

🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-29 04:18:27 -05:00

4.8 KiB
Raw Permalink Blame History

MEV Bot Code Review — October 27, 2025

Overview

  • Scope: Core arbitrage execution path, security/key management, operational configuration.
  • Reviewer: Codex (GPT-5)
  • Tests Run: go test ./... (fails — see Findings #6)
  • Status: Blocking issues identified; remediation required before further rollout.

Critical Findings

1. Live framework constructed with nil dependencies

  • Location: pkg/arbitrage/service.go:247-276, pkg/arbitrage/service.go:1668-1767
  • Whats wrong: FlashSwapExecutor and LiveExecutionFramework are instantiated with a nil KeyManager and zeroed contract addresses, yet StartLiveMode / ExecuteOpportunityLive invoke them during runtime.
  • Impact: First execution attempts call getTransactionOptionsexecutor.keyManager.GetActivePrivateKey() and crash with “key manager not configured,” disabling live/monitor modes in production.
  • Fix: Pass the real security.KeyManager and configured contract addresses into NewFlashSwapExecutor / NewLiveExecutionFramework, or guard live mode until those dependencies exist.

2. Shared TransactOpts causes race conditions & nonce reuse

  • Location: pkg/arbitrage/executor.go:384-407, pkg/arbitrage/service.go:636-674, config/arbitrum_production.yaml:255
  • Whats wrong: A single *bind.TransactOpts is stored on ArbitrageExecutor and mutated inside ExecuteArbitrage. Multiple opportunities are launched concurrently (config allows 3), so goroutines share and overwrite nonce, gas limit, and fee fields.
  • Impact: High probability of duplicate nonces, incorrect gas bids, and data races leading to reverted or invalid transactions under load.
  • Fix: Create a fresh TransactOpts per execution (clone signer) and guard shared state; ensure concurrency-safe nonce management.

3. Key derivation invalidates keystore on restart

  • Location: pkg/security/keymanager.go:1295-1314, pkg/security/keymanager.go:303-336, pkg/security/security_manager.go:129-138
  • Whats wrong: deriveEncryptionKey generates a new random salt each time the process starts, producing a different AES key for the same master secret. Stored encrypted keys/backups become unreadable, and the security managers separately constructed key manager derives yet another key.
  • Impact: Keys created in one run cannot be decrypted after restart; signing fails, and backups are useless. Production restart equals outage.
  • Fix: Persist the salt (e.g., alongside keystore) so the derived key is stable, or accept a user-provided salt. Ensure a single key-manager instance per keystore.

4. Production config silently overrides local runs

  • Location: cmd/mev-bot/main.go:83-89
  • Whats wrong: If config/arbitrum_production.yaml exists, it is always loaded—even in development—overriding config/local.yaml.
  • Impact: Local tests default to live Arbitrum RPC endpoints and contracts, risking quota drain or unwanted on-chain activity.
  • Fix: Respect GO_ENV (development vs production) before loading the production config; make the override explicit via CLI flag or env var.

5. Public repo leaks Chainstack endpoint token

  • Location: config/providers.yaml:36-55, docker-compose.production.yaml:17-19
  • Whats wrong: Hard-coded Chainstack URL includes an active access token.
  • Impact: Anyone cloning the repo can consume RPC quota or launch attacks through that endpoint; provider may revoke access.
  • Fix: Rotate the credential immediately and remove it from version control. Replace with placeholder variables documented for operators.

Additional Findings

6. Test suite failing due to duplicate main packages

  • Location: scripts/load-pools.go:1-89, scripts/generate-key.go:1-70
  • Whats wrong: Multiple standalone utilities share the github.com/fraktal/mev-beta/scripts package, so go test ./... fails with “main redeclared.”
  • Impact: CI cannot stay green; future regressions wont surface automatically.
  • Fix: Move each tool into its own module/folder (e.g., scripts/cmd/...) or add build tags to exclude them from the main module tests.
  1. Wire live execution components to real contract/key dependencies or gate the feature.
  2. Refactor transaction signing to use isolated TransactOpts and robust nonce management.
  3. Stabilize key derivation and consolidate key-manager ownership.
  4. Adjust config loading logic; require explicit opt-in for production settings.
  5. Rotate the leaked Chainstack token and scrub it from history/configs.
  6. Reorganize Go scripts so go test ./... passes again; rerun full regression afterward.

Test Status

  • go test ./...FAILED: build error (github.com/fraktal/mev-beta/scripts contains multiple main definitions).