Files
explorer-monorepo/scripts/check-explorer-health.sh
defiQUG bdae5a9f6e feat: explorer API, wallet, CCIP scripts, and config refresh
- Backend REST/gateway/track routes, analytics, Blockscout proxy paths.
- Frontend wallet and liquidity surfaces; MetaMask token list alignment.
- Deployment docs, verification scripts, address inventory updates.

Check: go build ./... under backend/ (pass).
Made-with: Cursor
2026-04-07 23:22:12 -07:00

207 lines
6.9 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
BASE_URL="${1:-https://explorer.d-bis.org}"
python3 - "$BASE_URL" <<'PY'
import re
import sys
import requests
base = sys.argv[1].rstrip("/")
session = requests.Session()
session.headers.update({"User-Agent": "ExplorerHealthCheck/2.0"})
failed = False
html_checks = [
"/",
"/home",
"/blocks",
"/transactions",
"/addresses",
"/bridge",
"/routes",
"/weth",
"/tokens",
"/pools",
"/watchlist",
"/more",
"/analytics",
"/operator",
"/system",
"/liquidity",
"/wallet",
"/snap/",
"/docs.html",
"/privacy.html",
"/terms.html",
"/acknowledgments.html",
]
json_checks = [
"/api/v2/stats",
"/api/config/token-list",
"/api/config/networks",
"/api/config/capabilities",
"/config/CHAIN138_RPC_CAPABILITIES.json",
"/config/topology-graph.json",
"/config/mission-control-verify.example.json",
"/explorer-api/v1/features",
"/explorer-api/v1/ai/context?q=cUSDT",
"/explorer-api/v1/track1/bridge/status",
"/explorer-api/v1/mission-control/liquidity/token/0x93E66202A11B1772E55407B32B44e5Cd8eda7f22/pools",
"/token-aggregation/api/v1/routes/tree?chainId=138&tokenIn=0x93E66202A11B1772E55407B32B44e5Cd8eda7f22&tokenOut=0x004b63A7B5b0E06f6bB6adb4a5F9f590BF3182D1&amountIn=1000000",
"/token-aggregation/api/v1/routes/matrix",
"/token-aggregation/api/v1/routes/ingestion?fromChainId=138&routeType=swap",
"/token-aggregation/api/v1/routes/partner-payloads?partner=0x&amount=1000000&includeUnsupported=true",
]
asset_checks = [
"/token-icons/cUSDC.png",
"/token-icons/cUSDT.png",
"/token-icons/cXAUC.png",
"/token-icons/cXAUT.png",
]
def mark_failure(message):
global failed
failed = True
print(message)
print("== Public routes ==")
for path in html_checks:
url = base + path
try:
resp = session.get(url, timeout=20, allow_redirects=True)
ctype = resp.headers.get("content-type", "")
print(f"{resp.status_code:>3} {path} [{ctype[:60]}]")
if resp.status_code >= 400:
failed = True
except Exception as exc:
mark_failure(f"ERR {path} [{exc}]")
print("\n== JSON and API surfaces ==")
for path in json_checks:
url = base + path
try:
resp = session.get(url, timeout=20, allow_redirects=True)
ctype = resp.headers.get("content-type", "")
print(f"{resp.status_code:>3} {path} [{ctype[:60]}]")
if resp.status_code >= 400:
failed = True
continue
if "json" not in ctype:
failed = True
print(f" expected JSON content-type, got: {ctype}")
continue
payload = resp.json()
if path == "/api/config/capabilities":
if payload.get("chainId") != 138:
mark_failure(" capabilities JSON does not report chainId 138")
wallet_support = payload.get("walletSupport", {})
if wallet_support.get("walletWatchAsset") is not True:
mark_failure(" capabilities JSON does not advertise walletWatchAsset")
elif path == "/api/config/token-list":
tokens = payload.get("tokens", [])
if not tokens:
mark_failure(" token list is empty")
elif path == "/api/config/networks":
chains = payload.get("chains", [])
if not chains:
mark_failure(" networks payload does not include any chains")
elif path == "/explorer-api/v1/features":
if "features" not in payload:
mark_failure(" features payload is missing the features key")
elif path == "/explorer-api/v1/track1/bridge/status":
data = payload.get("data", {})
relays = data.get("ccip_relays", {})
expected_relays = {
"avax",
"avax_cw",
"avax_to_138",
"bsc",
"mainnet_cw",
"mainnet_weth",
}
missing = sorted(expected_relays - set(relays))
if missing:
mark_failure(f" bridge status is missing relay keys: {', '.join(missing)}")
if data.get("status") not in {"operational", "paused", "degraded"}:
mark_failure(" bridge status payload does not include a recognized overall status")
except Exception as exc:
mark_failure(f"ERR {path} [{exc}]")
print("\n== Static assets ==")
for path in asset_checks:
url = base + path
try:
resp = session.get(url, timeout=20, allow_redirects=True)
ctype = resp.headers.get("content-type", "")
print(f"{resp.status_code:>3} {path} [{ctype[:60]}]")
if resp.status_code >= 400:
failed = True
except Exception as exc:
mark_failure(f"ERR {path} [{exc}]")
print("\n== Mission-control SSE ==")
stream_url = base + "/explorer-api/v1/mission-control/stream"
try:
with session.get(stream_url, timeout=(20, 20), stream=True) as resp:
ctype = resp.headers.get("content-type", "")
print(f"{resp.status_code:>3} /explorer-api/v1/mission-control/stream [{ctype[:60]}]")
if resp.status_code >= 400:
failed = True
else:
lines = []
for raw in resp.iter_lines(decode_unicode=True):
if raw:
lines.append(raw)
if len(lines) >= 2:
break
if not any(line.startswith("event:") for line in lines):
mark_failure(" mission-control stream did not emit an event line")
if not any(line.startswith("data:") for line in lines):
mark_failure(" mission-control stream did not emit a data line")
except Exception as exc:
mark_failure(f"ERR /explorer-api/v1/mission-control/stream [{exc}]")
print("\n== Internal href targets from homepage ==")
try:
home = session.get(base + "/", timeout=20).text
hrefs = sorted(set(re.findall(r'href=\"([^\"]+)\"', home)))
for href in hrefs:
if href.startswith("/") and not href.startswith("//"):
resp = session.get(base + href, timeout=20, allow_redirects=True)
print(f"{resp.status_code:>3} {href}")
if resp.status_code >= 400:
failed = True
except Exception as exc:
mark_failure(f"ERR homepage href sweep failed: {exc}")
print("\n== External explorer roots referenced by bridge surfaces ==")
external_roots = [
"https://etherscan.io/",
"https://bscscan.com/",
"https://polygonscan.com/",
"https://subnets.avax.network/c-chain",
"https://basescan.org/",
"https://arbiscan.io/",
"https://optimistic.etherscan.io/",
]
for url in external_roots:
try:
resp = session.get(url, timeout=20, allow_redirects=True)
print(f"{resp.status_code:>3} {url}")
except Exception as exc:
print(f"ERR {url} [{exc}]")
if failed:
sys.exit(1)
PY