#!/usr/bin/env bash set -euo pipefail ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" MEV_ROOT="$ROOT/MEV_Bot/mev-platform" CHAIN_ID="${CHAIN_ID:-}" BASE_URL="${MEV_BASE_URL:-https://mev.defi-oracle.io}" API_KEY="${MEV_API_KEY:-${API_KEY:-}}" RUN_LIVE=0 LIVE_PER_CHAIN=0 rpc_jsonrpc() { local rpc_url="$1" local body="$2" local attempts="${3:-4}" local delay=1 local tmp_body tmp_code tmp_body="$(mktemp)" tmp_code="$(mktemp)" for ((i=1; i<=attempts; i++)); do if curl -sS -o "$tmp_body" -w '%{http_code}' -H 'content-type: application/json' -d "$body" "$rpc_url" >"$tmp_code"; then code="$(cat "$tmp_code")" if [[ "$code" == "200" ]]; then cat "$tmp_body" rm -f "$tmp_body" "$tmp_code" return 0 fi if [[ "$code" != "429" ]]; then cat "$tmp_body" >&2 || true rm -f "$tmp_body" "$tmp_code" return 1 fi fi sleep "$delay" delay=$((delay * 2)) done cat "$tmp_body" >&2 || true rm -f "$tmp_body" "$tmp_code" return 1 } while [[ $# -gt 0 ]]; do case "$1" in --chain-id) CHAIN_ID="${2:-}" shift 2 ;; --base-url) BASE_URL="${2:-}" shift 2 ;; --api-key) API_KEY="${2:-}" shift 2 ;; --live) RUN_LIVE=1 shift ;; --live-per-chain) RUN_LIVE=1 LIVE_PER_CHAIN=1 shift ;; *) echo "Unknown arg: $1" >&2 exit 2 ;; esac done echo "[1/4] Rust validation" ( cd "$MEV_ROOT" cargo test -p mev-shared cargo check -p mev-state-ingestion -p mev-liquidity-graph -p mev-opportunity-search -p mev-simulation -p mev-bundle-builder -p mev-admin-api ) echo "[2/4] Contract validation" ( cd "$MEV_ROOT/contracts" forge test ) echo "[3/4] GUI validation" ( cd "$MEV_ROOT/gui" npm run build ) echo "[4/4] Config inventory checks" python3 - "$MEV_ROOT/config.toml" "$CHAIN_ID" <<'PY' import sys, tomllib path = sys.argv[1] requested = sys.argv[2].strip() with open(path, "rb") as fh: data = tomllib.load(fh) chains = data.get("chains", {}) required = {"1", "8453", "138"} missing = sorted(required - set(chains.keys())) if missing: raise SystemExit(f"Missing required chains in config.toml: {', '.join(missing)}") targets = [requested] if requested else sorted(required) for cid in targets: chain = chains.get(cid) if not chain: raise SystemExit(f"Chain {cid} missing from config.toml") if "rpc_url" not in chain: raise SystemExit(f"Chain {cid} missing rpc_url") if "multicall" not in chain: raise SystemExit(f"Chain {cid} missing multicall") venues = chain.get("venues", []) if cid == "138" and not venues: raise SystemExit("Chain 138 requires DODO venue examples or inventory") print("Config inventory checks passed") PY if [[ "$RUN_LIVE" -eq 1 ]]; then echo "[live] API smoke" auth_header=() if [[ -n "$API_KEY" ]]; then auth_header=(-H "X-API-Key: $API_KEY") fi curl -fsS "${auth_header[@]}" "$BASE_URL/api/health" >/dev/null curl -fsS "${auth_header[@]}" "$BASE_URL/api/infra" >/dev/null curl -fsS "${auth_header[@]}" "$BASE_URL/api/stats/freshness" >/dev/null curl -fsS "${auth_header[@]}" "$BASE_URL/api/stats/venue-coverage" >/dev/null echo "Live API smoke passed" fi if [[ "$LIVE_PER_CHAIN" -eq 1 ]]; then echo "[live] Per-chain deployment validation" python3 - "$MEV_ROOT/config.toml" <<'PY' > /tmp/mev_roadmap_live_targets.json import json, sys, tomllib with open(sys.argv[1], "rb") as fh: data = tomllib.load(fh) chains = data.get("chains", {}) targets = {} for cid in ("1", "8453", "138"): chain = chains[cid] targets[cid] = { "rpc_url": chain.get("rpc_url", ""), "ws_url": chain.get("ws_url", ""), "multicall": chain.get("multicall", ""), } print(json.dumps(targets)) PY for cid in 1 8453 138; do rpc_url="$(python3 -c 'import json; import sys; data=json.load(open("/tmp/mev_roadmap_live_targets.json")); print(data[sys.argv[1]]["rpc_url"])' "$cid")" ws_url="$(python3 -c 'import json; import sys; data=json.load(open("/tmp/mev_roadmap_live_targets.json")); print(data[sys.argv[1]]["ws_url"])' "$cid")" multicall="$(python3 -c 'import json; import sys; data=json.load(open("/tmp/mev_roadmap_live_targets.json")); print(data[sys.argv[1]]["multicall"])' "$cid")" override_var="MEV_LIVE_RPC_URL_${cid}" override_rpc="${!override_var:-}" if [[ -n "$override_rpc" ]]; then rpc_url="$override_rpc" fi echo " - chain $cid" [[ -n "$rpc_url" ]] || { echo "missing rpc_url for chain $cid" >&2; exit 1; } [[ -n "$multicall" ]] || { echo "missing multicall for chain $cid" >&2; exit 1; } chain_hex="$(rpc_jsonrpc "$rpc_url" '{"jsonrpc":"2.0","id":1,"method":"eth_chainId","params":[]}' | python3 -c 'import json,sys; print(json.load(sys.stdin)["result"])')" block_hex="$(rpc_jsonrpc "$rpc_url" '{"jsonrpc":"2.0","id":1,"method":"eth_blockNumber","params":[]}' | python3 -c 'import json,sys; print(json.load(sys.stdin)["result"])')" [[ "$chain_hex" == "0x$(printf '%x' "$cid")" ]] || { echo "chainId mismatch for chain $cid: $chain_hex" >&2; exit 1; } [[ "$block_hex" != "0x0" ]] || { echo "block height invalid for chain $cid" >&2; exit 1; } if [[ -n "$ws_url" ]]; then echo " ws_url configured" else echo " ws_url missing" >&2 exit 1 fi curl -fsS "${auth_header[@]}" "$BASE_URL/api/stats/freshness" | python3 -c 'import json,sys; rows=json.load(sys.stdin); cid=int(sys.argv[1]); assert any(int(r["chain_id"])==cid for r in rows)' "$cid" >/dev/null curl -fsS "${auth_header[@]}" "$BASE_URL/api/stats/venue-coverage" | python3 -c 'import json,sys; rows=json.load(sys.stdin); cid=int(sys.argv[1]); assert any(int(r["chain_id"])==cid for r in rows)' "$cid" >/dev/null done rm -f /tmp/mev_roadmap_live_targets.json echo "Per-chain live validation passed" fi echo "MEV roadmap validation completed successfully"