Onchain trading terminal — Solana + Base swaps and prediction markets (Polymarket, Kalshi, Limitless), surfaced through a green-phosphor terminal UI. Microservice architecture: Rust where latency matters (chain ingest, market tracker), NestJS where developer ergonomics matter (gateway, auth, signals), Next.js for the client.
┌──────────────────────────┐
│ Next.js :3000 │ green-phosphor terminal UI
└────────────┬─────────────┘
│ HTTP / WS
┌──────▼─────────┐
│ nginx :80 │
└──────┬─────────┘
/api/* │ /ws
┌──────▼──────────────────────┐
│ NestJS gateway :4000 │ REST + WS, SIWE/JWT, NATS client
└──┬───────────┬───────────┬──┘
│ │ │
┌────────────▼─┐ ┌──────▼─────┐ │
│ users :NATS │ │ signals │ │ NATS subjects:
│ │ │ :NATS │ │ evm.heartbeat
└──────────────┘ └────────────┘ │ sol.heartbeat
│ pm.market.upsert
NATS ──────────┤
│
┌───────────────────┬───────────┴────────────┐
│ │ │
┌────────▼─────────┐ ┌──────▼─────────────┐ ┌────────▼─────────┐
│ svc-evm-indexer │ │ svc-solana-indexer │ │ svc-pm-tracker │
│ Rust + Alloy │ │ Rust + solana- │ │ Rust + reqwest │
│ Base RPC/WS │ │ client/RPC │ │ Polymarket+ │
│ │ │ │ │ Kalshi+Limitless│
└──────────┬───────┘ └────────┬───────────┘ └────────┬─────────┘
│ │ │
└──────────────────┼──────────────────────┘
▼
┌────────────────────────────────────────┐
│ TimescaleDB :5432 Redis :6379 NATS │
│ (timescale/pg16) (7.4) :4222 │
└────────────────────────────────────────┘
- Rust: 1.90.0, tokio, axum, sqlx (postgres + timescaledb + bigdecimal + chrono), alloy, solana-client, async-nats.
- Node: 22.11.0 (LTS), pnpm 9, NestJS 10.
@nestjs/microservices(NATS),@nestjs/websockets(Socket.IO), siwe + JWT. - Frontend: Next.js 15 App Router, React 19, Tailwind 3.4, socket.io-client, SWR, Zustand.
- Infra: TimescaleDB
2.17.2-pg16, Redis7.4-alpine, NATS2.10-alpine, nginx1.27-alpine. All pinned, neverlatest.
git clone https://github.com/blockzenith/eagle-eye.git
cd eagle-eye
git checkout dev
cp .env.example .env
make up # docker compose up --build -d
make logs # tail until healthy
open http://localhostOnce everything is up:
| URL | Purpose |
|---|---|
http://localhost/ |
terminal UI dashboard |
http://localhost/markets |
live polymarket feed |
http://localhost/api/v1/health |
gateway health |
http://localhost/api/v1/markets?venue=polymarket&limit=5 |
sample REST query |
ws://localhost/ws |
socket.io WebSocket |
http://localhost:8222/varz |
NATS monitoring |
The first Polymarket fetch tick lands ~60s after pm-tracker boots; expect the /markets page to populate within ~90s. Watch upserts arrive over WebSocket: rows flash on each update.
eagle-eye/
├── services-rs/ # Rust workspace
│ └── crates/{core, svc-evm-indexer, svc-solana-indexer, svc-pm-tracker}
├── services-ts/ # NestJS pnpm workspace
│ ├── apps/{gateway, users, signals}
│ └── packages/contracts # shared DTOs + NATS subject constants
├── apps-web/eagle-eye-web # Next.js 15 terminal UI
├── infra/
│ ├── nginx/nginx.conf
│ └── postgres/init/ # bind-mounted to /docker-entrypoint-initdb.d
├── docker-compose.yml # dev stack (build locally)
├── docker-compose.prod.yml # prod overlay (pull from registry)
├── Makefile # `make up | down | logs | fmt | lint | test`
└── .github/workflows/{ci,images}.yml # self-hosted runner: [self-hosted, linux, x64, eagle-eye]
dev— active development. All work lands here first.stage— receives fast-forward merges fromdevonce a version is confirmed.main— receives fast-forward merges fromstage. Tagged releases live here.
# after dev is verified for v0.x.y
git checkout stage && git merge --ff-only dev && git push
git checkout main && git merge --ff-only stage && git push
git tag -a v0.x.y -m "v0.x.y" && git push --tagsDeterministic, never latest. Every image is tagged
<registry>/eagle-eye-<service>:<VERSION>-<GIT_SHA> where:
VERSIONdefaults togit describe --tags --always --dirtyGIT_SHAdefaults togit rev-parse --short HEADREGISTRYdefaults toghcr.io/blockzenith
Override at build time:
VERSION=0.2.0 GIT_SHA=$(git rev-parse --short HEAD) make buildCI runs on a self-hosted runner registered against this repo (labels
self-hosted, linux, x64, eagle-eye). The runner installation lives at
/opt/actions-runner-eagle-eye, runs as the gha-runner user, and is managed
by systemd:
sudo systemctl status actions.runner.blockzenith-eagle-eye.eagle-eye-host.serviceThe runner has access to the host Docker daemon (member of docker group) so
the images.yml workflow can build and push images.
See docs/feature-matrix.md for the per-chain and per-venue map (indexer → gateway → UI) — the table makes the "Solana, Base, Polymarket, Kalshi, Limitless" headline concrete.
- Real EVM/Solana swap decoding — indexers heartbeat block heights and slots; per-DEX log decoding is a follow-up.
- Kalshi + Limitless market fetchers — function stubs in
svc-pm-tracker/src/{kalshi,limitless}.rs. Polymarket is live. - SIWE signature verification — gateway accepts signatures as opaque
strings; production must call
new SiweMessage(...).verify(...)with domain + nonce checks. - Wallet / token detail pages — routes exist, no data flows yet.
- Telegram / KOL signals ingestion, trade execution, multi-arch images — all deferred.
MIT — see LICENSE.