chore: metamask networks, explorer SPA, nginx scripts; ignore Python cache
Some checks failed
Deploy Explorer Live / deploy (push) Failing after 12s

- Dual-chain / GRU deployment JSON sync
- Frontend explorer SPA + MetaMask components
- Scripts: nginx fixes, link deploy, local SPA serve helper
- Token icon chain-138.png; .gitignore __pycache__

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
defiQUG
2026-05-10 12:56:30 -07:00
parent e5df7c2ea3
commit d4f922c26e
17 changed files with 1449 additions and 91 deletions

View File

@@ -1,13 +1,14 @@
#!/usr/bin/env bash
# Add nginx proxy for token-aggregation service at /api/v1/ on explorer.d-bis.org (VMID 5000).
# Run on the explorer VM. Requires token-aggregation running (default port 3000).
# Run on the explorer VM. Requires token-aggregation listening on TOKEN_AGG_PORT (VMID 5000
# production default 3001 per fix-nginx-conflicts-vmid5000.sh; local dev often PORT=3000).
# Chain 138 Snap companion site (GATSBY_SNAP_API_BASE_URL=https://explorer.d-bis.org) then gets
# market data, swap quotes, and bridge routes from this API.
# Usage: [TOKEN_AGG_PORT=3000] [CONFIG_FILE=/etc/nginx/sites-available/blockscout] bash apply-nginx-token-aggregation-proxy.sh
# Usage: [TOKEN_AGG_PORT=3001] [CONFIG_FILE=/etc/nginx/sites-available/blockscout] bash apply-nginx-token-aggregation-proxy.sh
set -euo pipefail
TOKEN_AGG_PORT="${TOKEN_AGG_PORT:-3000}"
TOKEN_AGG_PORT="${TOKEN_AGG_PORT:-3001}"
CONFIG_FILE="${CONFIG_FILE:-/etc/nginx/sites-available/blockscout}"
if [ ! -f "$CONFIG_FILE" ]; then

View File

@@ -128,5 +128,5 @@ echo ""
echo "If deployment still pending:"
echo " 1. Wait additional time (5-10 minutes)"
echo " 2. Use Remix IDE (instructions above)"
echo " 3. Check block explorer: https://explorer.d-bis.org/address/$ACCOUNT"
echo " 3. Check block explorer: https://explorer.d-bis.org/addresses/$ACCOUNT"
echo ""

View File

@@ -154,7 +154,7 @@ if [ "$CONFIRMED" != "true" ]; then
echo "2. Transaction may have failed"
echo "3. RPC node may be out of sync"
echo ""
echo "Check block explorer: https://explorer.d-bis.org/address/$ACCOUNT"
echo "Check block explorer: https://explorer.d-bis.org/addresses/$ACCOUNT"
exit 1
fi

View File

@@ -255,7 +255,7 @@ if [ -n "$DEPLOYED_ADDRESS" ] && [ "$DEPLOYED_ADDRESS" != "0x0000000000000000000
log_info "Next steps:"
log_info "1. Update config/address-inventory.json with LINK token address"
log_info "2. Fund bridge contracts: ./scripts/fund-bridge-contracts.sh 10"
log_info "3. Verify contract on explorer: https://explorer.d-bis.org/address/$DEPLOYED_ADDRESS"
log_info "3. Verify contract on explorer: https://explorer.d-bis.org/addresses/$DEPLOYED_ADDRESS"
exit 0
else

View File

@@ -66,6 +66,36 @@ server {
}
location = /snap { rewrite ^ /snap/ last; }
# Token-aggregation + static config on HTTP (plain :80) so /api/v1/* never hits Blockscout by mistake
location /api/v1/ {
proxy_pass http://127.0.0.1:3001/api/v1/;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 60s;
add_header Access-Control-Allow-Origin *;
}
location = /api/config/token-list {
default_type application/json;
add_header Access-Control-Allow-Origin *;
add_header Cache-Control "public, max-age=3600";
alias /var/www/html/config/DUAL_CHAIN_TOKEN_LIST.tokenlist.json;
}
location = /api/config/networks {
default_type application/json;
add_header Access-Control-Allow-Origin *;
add_header Cache-Control "public, max-age=3600";
alias /var/www/html/config/DUAL_CHAIN_NETWORKS.json;
}
location = /api/config/capabilities {
default_type application/json;
add_header Access-Control-Allow-Origin *;
add_header Cache-Control "public, max-age=3600";
alias /var/www/html/config/CHAIN138_RPC_CAPABILITIES.json;
}
location / {
if ($redirect_to_https = 1) { return 301 https://$host$request_uri; }
proxy_pass http://127.0.0.1:4000;
@@ -112,24 +142,7 @@ server {
add_header Cache-Control "no-store, no-cache, must-revalidate";
}
# Blockscout Explorer endpoint - proxy to Blockscout
location / {
proxy_pass http://127.0.0.1:4000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Connection "";
proxy_buffering off;
proxy_request_buffering off;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_read_timeout 300s;
proxy_connect_timeout 75s;
}
# Token-aggregation API at /api/v1/ (Chain 138 Snap: market data, swap quote, bridge). Service runs on port 3001.
# Token-aggregation API at /api/v1/ — define BEFORE /api/ and / so longest-prefix routing is explicit (Snap + dApps).
location /api/v1/ {
proxy_pass http://127.0.0.1:3001/api/v1/;
proxy_http_version 1.1;
@@ -162,7 +175,7 @@ server {
alias /var/www/html/config/CHAIN138_RPC_CAPABILITIES.json;
}
# API endpoint (for Blockscout API)
# Blockscout API (excludes /api/v1/ which is handled above)
location /api/ {
proxy_pass http://127.0.0.1:4000;
proxy_http_version 1.1;
@@ -184,6 +197,23 @@ server {
proxy_set_header Host $host;
add_header Content-Type application/json;
}
# Blockscout Explorer UI (catch-all)
location / {
proxy_pass http://127.0.0.1:4000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Connection "";
proxy_buffering off;
proxy_request_buffering off;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_read_timeout 300s;
proxy_connect_timeout 75s;
}
}
# WebSocket upgrade mapping

View File

@@ -1,26 +1,16 @@
#!/bin/bash
# Simple local server for explorer (fallback option)
# Usage: ./serve-explorer-local.sh [port]
#!/usr/bin/env bash
# Local static explorer with SPA path fallback (/institution, /compare, /addresses/… → index.html).
# Usage: SERVE_BIND=0.0.0.0 ./scripts/serve-explorer-local.sh [port]
# Requires: Python 3.7+
PORT=${1:-8080}
FRONTEND_DIR="$(cd "$(dirname "$0")/../frontend/public" && pwd)"
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PORT="${1:-8080}"
BIND="${SERVE_BIND:-127.0.0.1}"
if [ ! -f "$FRONTEND_DIR/index.html" ]; then
echo "❌ Frontend not found at: $FRONTEND_DIR/index.html"
exit 1
if ! command -v python3 >/dev/null 2>&1; then
echo "python3 required" >&2
exit 1
fi
echo "Serving explorer on http://localhost:$PORT"
echo "Frontend: $FRONTEND_DIR"
cd "$FRONTEND_DIR"
# Try Python 3 first, then Python 2
if command -v python3 >/dev/null 2>&1; then
python3 -m http.server "$PORT"
elif command -v python >/dev/null 2>&1; then
python -m SimpleHTTPServer "$PORT"
else
echo "❌ Python not found. Install Python to use this script."
exit 1
fi
exec python3 "$SCRIPT_DIR/serve_explorer_spa.py" "$PORT" --bind "$BIND"

56
scripts/serve_explorer_spa.py Executable file
View File

@@ -0,0 +1,56 @@
#!/usr/bin/env python3
"""Static explorer with SPA fallback: unknown paths serve index.html (client router).
API paths (/api/, /explorer-api/) are not rewritten so missing backends still 404 clearly."""
from __future__ import annotations
import argparse
import os
import sys
from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer
from urllib.parse import urlparse
def main() -> int:
p = argparse.ArgumentParser(description="Serve explorer-monorepo/frontend/public with SPA fallback.")
p.add_argument("port", nargs="?", type=int, default=8080, help="Listen port (default 8080)")
p.add_argument(
"--bind",
default="127.0.0.1",
help="Bind address (default 127.0.0.1)",
)
args = p.parse_args()
script_dir = os.path.dirname(os.path.abspath(__file__))
root = os.path.normpath(os.path.join(script_dir, "..", "frontend", "public"))
if not os.path.isfile(os.path.join(root, "index.html")):
print(f"ERROR: index.html not found under {root}", file=sys.stderr)
return 1
class Handler(SimpleHTTPRequestHandler):
def __init__(self, *a, **kw):
super().__init__(*a, directory=root, **kw)
def do_GET(self) -> None: # noqa: N802
path = urlparse(self.path).path
if path.startswith("/api/") or path.startswith("/explorer-api"):
return super().do_GET()
rel = path.lstrip("/")
if rel.startswith(".."):
self.send_error(403, "Forbidden")
return
fs = os.path.join(root, rel) if rel else root
if os.path.isfile(fs):
return super().do_GET()
self.path = "/index.html"
return super().do_GET()
httpd = ThreadingHTTPServer((args.bind, args.port), Handler)
print(f"Serving SPA explorer: http://{args.bind}:{args.port}/ (root={root})", flush=True)
try:
httpd.serve_forever()
except KeyboardInterrupt:
print("\nStopped.", flush=True)
return 0
if __name__ == "__main__":
raise SystemExit(main())