9.8 KiB
Full Audit Checklist — Go MEV Arbitrage Bot
Scope: a production-grade Go service that scans mempool/RPCs, finds arbitrage, constructs & signs transactions, and submits them (e.g., direct RPC, Flashbots bundles). Includes any on-chain smart-contracts the bot depends on (adapters, helpers, custom contracts).
1) Planning & scoping (before running tools)
- ✅ Identify attack surface: private keys, RPC/WS endpoints, mempool sources, bundle relays (Flashbots), third-party libs, config files.
- ✅ Define assets at risk (max ETH / tokens), operational windows, and which chains/nodes (e.g., Arbitrum, Ethereum).
- ✅ Create test accounts with funded testnet funds and a forked mainnet environment (Anvil/Hardhat/Foundry) for reproducible tests.
2) Static analysis — Go (SAST / linters / vuln DB)
Run these to find code smells, insecure patterns, and known vulnerable dependencies:
- Tools to run:
gosec,govulncheck,staticcheck,golangci-lint. (gosec and govulncheck are high-value for security.) ([GitHub][1])
Example commands:
# gosec
gosec ./...
# govulncheck (requires Go toolchain)
govulncheck ./...
# staticcheck via golangci-lint
golangci-lint run
What to look for:
- Use of
crypto/randvsmath/rand, insecure parsing of RPC responses, improper TLS skip verify, hard-coded secrets. - Unsafe use of
syncprimitives, race conditions flagged by go vet/staticcheck patterns.
3) Dynamic analysis & runtime checks — Go
- Run
go testwith race detector and fuzzing (Go 1.18+ built-in fuzz):
# race detector
go test -race ./...
# fuzzing (example fuzz target)
go test -fuzz=Fuzz -fuzztime=10m ./...
- Run integration tests on a mainnet-fork (Anvil/Foundry/Hardhat) so you can simulate chain state and mempool behaviours.
- Instrument code with pprof and capture CPU/heap profiles during simulated high-throughput runs.
What to look for:
- Race detector failures, panics, deadlocks, goroutine leaks (goroutines that grow unbounded during workload).
4) Go security & dependency checks
govulncheck(re: vulnerable dependencies). ([Go Packages][2])- Dependency graph:
go list -m alland search for unmaintained or forked packages. - Check for unsafe cgo or native crypto libraries.
5) Code quality & architecture review checklist
- Error handling: ensure errors are checked and wrapped (
%w) not ignored. - Context: all network calls accept
context.Contextwith deadlines/timeouts. - Modularization: separate mempool ingestion, strategy logic, transaction builder, and signer.
- Testability: core arbitrage logic should be pure functions with injected interfaces for RPCs and time.
- Secrets: private keys are never in repo, use a secrets manager (Vault / KMS) or env with restricted perms.
6) Concurrency & rate limiting
- Ensure tight control over goroutine lifecycle (context cancellation).
- Use worker pools for RPCs and bounded channels to avoid OOM.
- Rate-limit RPC calls and implement backoff/retry strategies with jitter.
7) Transaction building & signing (critical)
- Validate chain ID, EIP-155 protection, correct v,r,s values.
- Nonce management: centralize nonce manager; handle failed/non-broadcast txs and re-sync nonces from node on error.
- Gas estimation/testing: include sanity checks & max gas limits.
- Signing: prefer hardware/remote signers (KMS, HSM). If local private keys used, ensure file perms and encryption.
- Replay protection: verify chain ID usage and consider EIP-1559 parameterization (maxFeePerGas/maxPriorityFeePerGas).
- If using Flashbots, validate bundle assembly and simulator checks (see Flashbots docs). ([Flashbots Docs][3])
8) Smart-contract audit (if you have custom contracts or interact closely)
Run this toolchain (static + dynamic + fuzz + formal):
- Slither for static analysis.
- Mythril (symbolic analysis) / MythX for additional SAST.
- Foundry (forge) for unit & fuzz tests — Foundry supports fuzzing & is fast. ([Cyfrin][4])
- Echidna for property-based fuzzing of invariants. ([0xmacro.com][5])
- Consider Manticore/Mythril for deeper symbolic exploration, and Certora/formal approaches for critical invariants (if budget allows). ([Medium][6])
Example solidity workflow:
# slither
slither .
# Foundry fuzzing
forge test --fuzz
# Echidna (property-based)
echidna-test contracts/ --contract MyContract --config echidna.yaml
What to test:
- Reentrancy, arithmetic over/underflow (if not using SafeMath / solidity ^0.8), access-control checks, unexpected token approvals, unchecked external calls.
9) Fuzzing — exhaustive plan
Go fuzzing
-
Use Go’s native fuzz (
go test -fuzz) for core libraries (parsers, ABI decoders, bundle builders). -
Create fuzz targets focusing on:
- RPC response parsing (malformed JSON).
- ABI decoding and calldata construction.
- Signed-transaction bytes parser.
-
Run for long durations with corpus seeding from real RPC responses.
Solidity fuzzing
- Use Foundry’s
forge test --fuzzand Echidna to target invariants (balances, no-negative slippage, token conservation). - Seed fuzzers with historical tx traces & typical call sequences.
Orchestration
- Run fuzzers in CI but also schedule long runs in a buildkite/GitHub Actions runner or dedicated machine.
- Capture crashes/inputs and convert them to reproducible testcases.
References and how-to guides for solidity fuzzing and Foundry usage. ([Cyfrin][4])
10) Penetration-style tests / adversarial scenarios
- Mempool-level adversary: inject malformed or opponent transactions, test how bot reacts to reorgs & chain reorganizations.
- Time/latency: simulate delayed RPC responses and timeouts.
- Partial failures: simulate bundle reverts, tx replaced, or gas price spikes.
- Economic tests: simulate price or liquidity slippage, oracle manipulation scenarios.
11) Monitoring, metrics & observability
-
Add structured logs (JSON), trace IDs, and use OpenTelemetry or Prometheus metrics for:
- latency from detection → tx submission,
- success/failure counters,
- gas usage per tx,
- nonce mismatches.
-
Add alerts for repeated reorgs, high failure rates, or sudden profit/loss anomalies.
-
Simulate alerting (PagerDuty/Slack) in staging to ensure operational readiness.
12) CI/CD & reproducible tests
-
Integrate all static and dynamic checks into CI:
gosec,govulncheck,golangci-lint→ fail CI on new high/critical findings.- Unit tests, fuzzing smoke tests (short), Foundry tests for solidity.
-
Store fuzzing corpora and reproduce minimized crashing inputs in CI artifacts.
13) Secrets & deployment hardening
- Never commit private keys or mnemonic in code or config. Use secret manager (AWS KMS / GCP KMS / HashiCorp Vault).
- Use least-privilege for node credentials; isolate signer service from other components.
- Harden nodes: avoid public shared RPCs for production signing; prefer dedicated provider or local node.
14) Reporting format & remediation plan (what the auditor should deliver)
-
Executive summary: risk posture and amount at risk.
-
Prioritized findings: Critical / High / Medium / Low / Informational.
- For each finding: description, evidence (stack trace, log snippets, test reproducer), impact, exploitability, and line-level references.
- Fix recommendation: code patch or test to cover the case; include sample code where relevant.
-
Re-test plan: how to validate fixes (unit/regression tests, fuzzing seeds).
-
Follow-up: suggested schedule for re-audit (post-fix) and continuous scanning.
15) Severity guidance (example)
- Critical: fund-loss bug; private key compromised; unsigned tx broadcast leak.
- High: nonce desync under normal load; reentrancy in helper contract called by bot.
- Medium: panic on malformed RPC response; unbounded goroutine leak.
- Low: logging missing request IDs; non-idiomatic error handling.
- Informational: code style, minor refactors.
16) Example concrete test cases to include
- RPC returns truncated JSON → does the bot panic or gracefully retry?
- Node returns
nonce too lowmid-run → does the bot resync or keep retrying stale nonce? - Simulate mempool reordering and reorg of 2 blocks → does bot detect revert & recover?
- Flashbots bundle simulator returns revert on one tx → ensure bot doesn’t double-submit other txs.
- ABI-decoder fuzzed input causing unexpected
panicin Go (fuzzer should find).
17) Example commands / CI snippets (condensed)
# .github/workflows/ci.yml (snippets)
- name: Lint & Security
run: |
golangci-lint run ./...
gosec ./...
govulncheck ./...
- name: Unit + Race
run: go test -race ./...
- name: Go Fuzz (short)
run: go test -run TestFuzz -fuzz=Fuzz -fuzztime=1m ./...
18) Deliverables checklist for the auditor (what to hand back)
- Full report (PDF/Markdown) with prioritized findings & diffs/patches.
- Repro scripts for each failing case (docker-compose or Foundry/Anvil fork commands).
- Fuzzing corpora and minimized crashing inputs.
- CI changes / workflow proposals for enforcement.
- Suggested runtime hardening & monitoring dashboard templates.
19) Helpful references & toolset (quick links)
gosec— Go security scanner. ([GitHub][1])govulncheck— Go vulnerability scanner for dependencies. ([Go Packages][2])- Foundry (
forge) — fast solidity testing + fuzzing. ([Cyfrin][4]) - Echidna — property-based fuzzing for Solidity. ([0xmacro.com][5])
- Slither / Mythril — solidity static analysis & symbolic analysis. ([Medium][6])
20) Final notes & recommended audit cadence
- Run a full audit (code + solidity + fuzzing) before mainnet launch.
- Keep continuous scanning (gosec/govulncheck) in CI on every PR.
- Schedule quarterly security re-checks + immediate re-audit for any major dependency or logic change.