luxd serves /v1 only — server/http/server.go pins baseURL="/v1" — so every /ext call in this repo was a silent no-op. The fleet collector's _rpc() returns None on non-200, so the lux.cloud dashboard rendered nodes_rpc_ok:0, version:null and every node rpc_reachable:false while the fleet was in fact running luxd/1.36.2 (mainnet), 1.36.24 (testnet), 1.36.25 (devnet). Fixing the path alone would not have helped: the collector addressed each validator by a hardcoded public LoadBalancer IP, and there are now zero LoadBalancer Services in lux-mainnet/testnet/devnet. Those IPs time out. So node addressing is no longer configured — it is derived from the cluster on every collection, and the one way to reach a validator is the lux-k8s API server's pod proxy, since luxd RPC is cluster-internal. That collapses the old MODE A / MODE B split into a single path: read the CR for the declared shape, the pods for phase/readiness/IP, then each pod's JSON-RPC through the proxy. One credential authenticates both. Deleting the endpoint ConfigMap and its 15 baked-in IPs removes the failure mode where infrastructure moves and a dashboard quietly reports zeros. Probes move to /v1/health/liveness, not /v1/health: a degraded-but-running validator answers /v1/health with 503, so probing it would restart nodes that are merely behind. Any fleet from charts/lux could never have gone Ready. LuxNode.external_ip becomes .ip — with no public per-pod endpoint, the honest value is the pod IP. Avalanche endpoints keep /ext; that is their API, not ours. Measured, with controls: pod-proxy POST /v1/info -> 200 on all 15 pods; /ext/health -> 404; /zzz/health -> 404; nonexistent pod -> 404. A test asserts every probe path is under /v1 and fails if /ext returns. Co-authored-by: Hanzo Dev <[email protected]>
Bootnode
Web3 Backend in a Box - Run locally or deploy to cloud.
Go rewrite (HIP-0106) in progress. The current production service is the Python FastAPI app under
api/. A Go scaffold that mounts intosuperbaseper HIP-0106 lives alongside it —api/,cmd/bootnode/,schema/,zap/. Seedocs/PYTHON_TO_GO_PORT.mdfor the endpoint-by-endpoint port map and the new Go README section below.
Quick Start
docker compose up -d
Done. Your Web3 backend is running:
- API: http://localhost:8000
- Dashboard: http://localhost:3001
- API Docs: http://localhost:8000/docs
Features
| API | Description |
|---|---|
POST /v1/rpc/{chain} |
Multi-chain JSON-RPC proxy |
WS /v1/ws/{chain} |
Real-time blockchain subscriptions |
GET /v1/tokens/{chain}/balances/{address} |
Token balances & metadata |
GET /v1/nfts/{chain}/owned/{address} |
NFT ownership & metadata |
POST /v1/webhooks |
Event-driven notifications |
POST /v1/wallets/create |
ERC-4337 smart wallets |
POST /v1/bundler/{chain} |
UserOp bundling |
POST /v1/gas/sponsor |
Gas sponsorship |
Supported Chains
L1: Ethereum, BNB Chain, Avalanche, Solana, Bitcoin
L2: Arbitrum, Optimism, Base, Polygon, zkSync, Scroll, Linea, Blast
Development
# API (Python 3.12+)
cd api && uv sync && uvicorn bootnode.main:app --reload --port 8000
# Dashboard (Node 22+)
cd web && pnpm install && pnpm dev
Deploy
Self-hosted
docker compose -f docker-compose.prod.yml up -d
# or
kubectl apply -f infra/k8s/
Hanzo Cloud
hanzo deploy
Visit web3.hanzo.ai for managed hosting.
License
Apache-2.0
Go rewrite (HIP-0106)
The Go subsystem mounts into superbase (the unified Hanzo Cloud
binary). It exposes a single Mount(r chi.Router, deps api.Deps) error
entry point and a public ZAP schema (schema/bootnode.zap) covering
every cross-subsystem type.
bootnode/
schema/bootnode.zap # public typed surface (ZAP)
zap/gen/ # zapc-generated Go (hand-stubs today)
api/ # subsystem code (chi handlers + store)
mount.go # HIP-0106 contract
deps.go # IAM/KMS/Base/O11y/Commerce interfaces
handlers/ # one MountXxx per FastAPI route group
middleware/ # auth, telemetry, rate-limit
store/ # per-tenant SQLite via deps.Base
web3/ # chain registry + RPC pool
cmd/bootnode/main.go # standalone dev shim
docs/PYTHON_TO_GO_PORT.md # endpoint-by-endpoint mapping
Build
go build ./...
go vet ./...
go run ./cmd/bootnode # listens on :8100 (BOOTNODE_ADDR to override)
Generate ZAP bindings
cd zap && make gen # no-op if zapc isn't installed
zapc lives at ~/work/hanzo/zap/zapc-rs/. Brand policy: no
.capnp files, no "Cap'n Proto" references on the public surface
(HIP-0106).