Track MEV multi-chain rollout validation and cutover

This commit is contained in:
defiQUG
2026-04-13 21:29:28 -07:00
parent 309843df95
commit e86744e12b
6 changed files with 217 additions and 6 deletions

Submodule MEV_Bot updated: ad5a078cce...bcb31f974b

View File

@@ -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 |

View File

@@ -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"
}
}

View File

@@ -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"

View File

@@ -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:

View File

@@ -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"