diff --git a/MEV_Bot b/MEV_Bot index ad5a078c..bcb31f97 160000 --- a/MEV_Bot +++ b/MEV_Bot @@ -1 +1 @@ -Subproject commit ad5a078cce70385d32058478551989b012b9aa10 +Subproject commit bcb31f974bdd53e463cc50d1aedb9c823861567e diff --git a/docs/04-configuration/MEV_CONTROL_DEFI_ORACLE_IO_DEPLOYMENT.md b/docs/04-configuration/MEV_CONTROL_DEFI_ORACLE_IO_DEPLOYMENT.md index d7f1fe53..901bcacb 100644 --- a/docs/04-configuration/MEV_CONTROL_DEFI_ORACLE_IO_DEPLOYMENT.md +++ b/docs/04-configuration/MEV_CONTROL_DEFI_ORACLE_IO_DEPLOYMENT.md @@ -15,7 +15,7 @@ This document describes how to publish the **MEV Control** web app (`MEV_Bot/mev | **NPMplus** | TLS termination; forwards `mev.defi-oracle.io` → `http://IP_INFO_DEFI_ORACLE_WEB:80` (or `MEV_DEFI_ORACLE_UPSTREAM_*`). | | **Cloudflare** | Optional proxied **A** or **CNAME** (tunnel) for `mev.defi-oracle.io` / `www.mev.defi-oracle.io`. | -The browser uses **same-origin** `/api` (no CORS split). Set **`MEV_ADMIN_API_HOST`** / **`MEV_ADMIN_API_PORT`** so the nginx CT can reach the backend CT where `mev-admin-api` listens. For the current recommended split topology, keep the public GUI on CT **2410** and point `/api` to a dedicated backend CT on **`r630-04`** (default recommendation: **`192.168.11.219:9090`**). Do not host the MEV backend services directly on a Proxmox node unless you are intentionally breaking the portability standard. +The browser uses **same-origin** `/api` (no CORS split). Set **`MEV_ADMIN_API_HOST`** / **`MEV_ADMIN_API_PORT`** so the nginx CT can reach the backend CT where `mev-admin-api` listens. For the current recommended split topology, keep the public GUI on CT **2410** and point `/api` to a dedicated backend CT on **`r630-04`** (current production backend: **`192.168.11.223:9090`**). Do not host the MEV backend services directly on a Proxmox node unless you are intentionally breaking the portability standard. ## Prerequisites @@ -32,7 +32,7 @@ From **proxmox** repo root (loads paths; override via env): # Recommended split topology: # public GUI on CT 2410 # admin API / pipeline inside dedicated backend CT on r630-04 -export MEV_ADMIN_API_HOST=192.168.11.219 +export MEV_ADMIN_API_HOST=192.168.11.223 export MEV_ADMIN_API_PORT=9090 bash scripts/deployment/sync-mev-control-gui-defi-oracle.sh --dry-run bash scripts/deployment/sync-mev-control-gui-defi-oracle.sh @@ -76,7 +76,7 @@ If you intentionally carry **MEV** traffic on the same Cloudflare tunnel stack a |----------|--------------------------------------------|---------| | `MEV_DEFI_ORACLE_WEB_VMID` | `2410` | Target LXC | | `MEV_DEFI_ORACLE_WEB_ROOT` | `/var/www/mev.defi-oracle.io/html` | Web root | -| `MEV_ADMIN_API_HOST` | `192.168.11.11` shared default; override to the backend CT IP (recommended `192.168.11.219`) for the contained split topology | mev-admin-api bind host (from CT) | +| `MEV_ADMIN_API_HOST` | `192.168.11.11` shared default; override to the backend CT IP (recommended `192.168.11.223`) for the contained split topology | mev-admin-api bind host (from CT) | | `MEV_ADMIN_API_PORT` | `9090` | mev-admin-api port | | `MEV_DEFI_ORACLE_UPSTREAM_IP` | `IP_INFO_DEFI_ORACLE_WEB` | NPM forward target | | `MEV_DEFI_ORACLE_UPSTREAM_PORT` | `80` | NPM forward port | diff --git a/reports/status/mev_execution_deploy_20260413_2330.json b/reports/status/mev_execution_deploy_20260413_2330.json new file mode 100644 index 00000000..62948f1b --- /dev/null +++ b/reports/status/mev_execution_deploy_20260413_2330.json @@ -0,0 +1,21 @@ +{ + "chain_id": 1, + "broadcast_artifact": "/home/intlc/projects/proxmox/MEV_Bot/mev-platform/contracts/broadcast/Deploy.s.sol/1/run-latest.json", + "config_path": "/home/intlc/projects/proxmox/MEV_Bot/mev-platform/config.dev.toml", + "executor_contract": "0x7b7790a25CD835505e43e6486eE574C744bbD9E6", + "uniswap_v2_adapter": "0xae075ee4041279AeFadDa6CC305Dc6fDB30e444E", + "flash_loan_provider": "0xDA182999F3350643a9b0C68c1fF9Ac2aC44a9b48", + "treasury": "0x4A666F96fC8764181194447A7dFdb7d471b301C8", + "deployer_address": "0x4A666F96fC8764181194447A7dFdb7d471b301C8", + "requested_executor_owner": null, + "pause_on_deploy": "true", + "aave_pool": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", + "aave_wrapper": "0xDA182999F3350643a9b0C68c1fF9Ac2aC44a9b48", + "onchain": { + "owner": "0x4A666F96fC8764181194447A7dFdb7d471b301C8", + "pending_owner": "0x0000000000000000000000000000000000000000", + "paused": "true", + "flash_loan_provider": "0xDA182999F3350643a9b0C68c1fF9Ac2aC44a9b48", + "treasury": "0x4A666F96fC8764181194447A7dFdb7d471b301C8" + } +} diff --git a/scripts/deployment/provision-mev-control-backend-lxc.sh b/scripts/deployment/provision-mev-control-backend-lxc.sh index a00aa6e0..da4bde26 100644 --- a/scripts/deployment/provision-mev-control-backend-lxc.sh +++ b/scripts/deployment/provision-mev-control-backend-lxc.sh @@ -18,7 +18,7 @@ source "${PROJECT_ROOT}/config/ip-addresses.conf" 2>/dev/null || true PROXMOX_HOST="${PROXMOX_HOST:-${PROXMOX_HOST_R630_04:-192.168.11.14}}" VMID="${MEV_CONTROL_BACKEND_VMID:-2421}" -IP_CT="${MEV_CONTROL_BACKEND_IP:-192.168.11.219}" +IP_CT="${MEV_CONTROL_BACKEND_IP:-192.168.11.223}" HOSTNAME_CT="${MEV_CONTROL_BACKEND_HOSTNAME:-mev-control-backend}" TEMPLATE_CT="${TEMPLATE:-local:vztmpl/debian-12-standard_12.12-1_amd64.tar.zst}" STORAGE="${STORAGE:-local-lvm}" @@ -71,4 +71,3 @@ ssh $SSH_OPTS "root@${PROXMOX_HOST}" "pct exec ${VMID} -- bash -lc \"set -euo pi echo "" echo "✅ Backend CT ${VMID} ready at ${IP_CT}" echo " Next: deploy the MEV stack inside the CT and point CT 2410 /api to http://${IP_CT}:9090" - diff --git a/scripts/verify/check-mev-execution-readiness.sh b/scripts/verify/check-mev-execution-readiness.sh index 5c61555e..b30fdd96 100755 --- a/scripts/verify/check-mev-execution-readiness.sh +++ b/scripts/verify/check-mev-execution-readiness.sh @@ -137,6 +137,19 @@ def run_cast_call(address: str, signature: str, rpc_url: str) -> str | None: return result.stdout.strip() or None +def run_cast_wallet_address(private_key: str) -> str | None: + try: + result = subprocess.run( + ["cast", "wallet", "address", "--private-key", private_key], + check=True, + capture_output=True, + text=True, + ) + except Exception: # noqa: BLE001 + return None + return result.stdout.strip() or None + + config = tomllib.loads(config_path.read_text()) env_values = parse_env_file(env_path) chain_key = str(chain_id) @@ -152,6 +165,7 @@ def add_row(name: str, source: str, value: str, status: str) -> None: signer_key = os.environ.get("MEV_EXECUTOR_PRIVATE_KEY") or env_values.get("MEV_EXECUTOR_PRIVATE_KEY", "") +signer_address = run_cast_wallet_address(signer_key) if signer_key else None if signer_key: add_row("MEV_EXECUTOR_PRIVATE_KEY", str(env_path), "(present, masked)", "ok") else: diff --git a/scripts/verify/run-mev-roadmap-validation.sh b/scripts/verify/run-mev-roadmap-validation.sh new file mode 100755 index 00000000..186eb0b9 --- /dev/null +++ b/scripts/verify/run-mev-roadmap-validation.sh @@ -0,0 +1,177 @@ +#!/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"