stablerates tracks and compares Solana stablecoin borrow APYs across protocols.
| Workspace | Purpose |
|---|---|
apps/indexer |
Periodically fetches configured borrow-market APYs and stores observations. |
apps/api |
Serves health, metadata, latest-rate, and historical-rate endpoints. |
apps/web |
Browser dashboard with market filtering, chart ranges, table sorting, and rate history. |
packages/core |
Shared domain types, protocol metadata, and server-only protocol adapters. |
packages/clickhouse |
ClickHouse client, registry access, observation writes, and rate repository. |
packages/logger |
Structured Pino logger for services. |
packages/ui |
Shared React/shadcn UI primitives and styles. |
The market registry and persisted data contract are documented in clickhouse/README.md.
- Bun 1.3.14 or later
- Docker and Docker Compose for the local ClickHouse stack
- A Solana RPC endpoint for reliable indexing (the public mainnet endpoint is the development default)
- The Kora CLI and
envsubstfor the local x402 E2E test
Install workspace dependencies and create service environment files from their examples:
bun install
cp apps/api/.env.example apps/api/.env
cp apps/indexer/.env.example apps/indexer/.env
cp apps/web/.env.example apps/web/.envStart ClickHouse, load the registry data, then run the services in separate terminals:
docker compose up -d
clickhouse/scripts/init-mints.sh clickhouse/mints.csv
clickhouse/scripts/init-borrow-markets.sh clickhouse/borrow-markets.csv
bun run --cwd apps/api dev
bun run --cwd apps/indexer dev
bun run --cwd apps/web devbun run typecheck
bun run test
bun run buildbun run test:e2e runs every E2E test under e2e/. The x402 suite starts an in-process Surfnet instance, renders a temporary Kora configuration with isolated ports, and launches Kora against Surfnet’s dynamic RPC URL. It then exercises the real API → facilitator → Kora payment flow using the checked-in local keypairs, airdrops SOL to the treasury, Kora signer, and x402 user, and initializes/funds the treasury and user ATAs for every mint Kora supports.
Start Redis and ClickHouse before running the suite:
docker compose up -d redis clickhouse
bun run test:e2eThe test uses the repository .env.test configuration and only seeds/removes its own rate rows. Surfnet reads required account state from mainnet, but every payment transaction settles locally. x402 advertises the devnet CAIP identifier because that is the identifier supported by the current x402 SVM client.
flowchart LR
registry["ClickHouse market registry"] --> indexer["apps/indexer"]
indexer <--> sources["Kamino / Jupiter / Project 0 / Save"]
indexer --> observations["ClickHouse rate observations"]
observations --> api["apps/api"]
redis["Redis"] --> api
browser["Browser"] -->|"public REST API"| api
client["x402 client"] -->|"paid /v1/x402/* request"| api
api -->|"verify / settle"| facilitator["apps/facilitator"]
redis --> facilitator
facilitator --> kora["Kora"]
kora --> solana["Solana"]
api --> payments["ClickHouse x402 payments"]
apps/indexerreads the ClickHouse market registry, obtains one rate per market through protocol adapters, and appends observations.apps/apiexposes health, readiness, metadata, free rate endpoints, and paid x402 rate endpoints. It reads ClickHouse, applies Redis-backed rate limiting to/v1/*, and records settled x402 payments in ClickHouse.apps/facilitatorimplements the x402 facilitatorsupported,verify, andsettleoperations. It enforces the configured Solana network, treasury, and mint allowlist before asking Kora to sign or broadcast a payment.apps/webis a TanStack Start/Vite dashboard. Browser code calls the public API directly using the publicVITE_API_BASE_URL; it is not a BFF.packages/clickhouseowns the ClickHouse client plus registry, observation, rate-query, and x402-payment persistence helpers.packages/redisowns the shared Redis client factory. The API and facilitator each own their rate-limit middleware and connection lifecycle.packages/coreowns shared protocol identifiers, metadata, API/domain types, and server-only protocol adapters.packages/loggerowns structured service logging, andpackages/uiowns reusable React/shadcn components and styles.