Appearance
SymbolRegistry
Global singleton Durable Object (id: "global") managing dynamic symbol metadata, categories, leverage overrides, and automated crawler recommendations.
Purpose
SymbolRegistry is the central authority for which symbols are tradable and how they're configured. It augments the static 26 core symbols with dynamic metadata from external APIs, enabling runtime addition/removal of symbols without code deploys.
- Single global instance (
id: "global") - Alarm-driven crawler on configurable interval (default: 1 hour)
- Suggest-don't-act recommendation model — crawler never auto-enables symbols
- Eventual consistency via push + periodic reconciliation to 77 downstream DOs
High-Level Design
Core Responsibilities
- Symbol Lifecycle — Maintain the canonical list of symbols with their metadata (category, leverage, decimals, price scale, rankings)
- Automated Discovery — Crawl external APIs to discover new Hyperliquid-listed symbols and recommend promotions/demotions
- Config Distribution — Fan out enabled symbol config to all downstream PriceCollector and PriceAlert DOs
- Admin Controls — Expose promote/demote/batch operations for manual symbol management
Data Flow
External APIs SymbolRegistry DO Downstream DOs
───────────── ────────────────── ──────────────
CoinMarketCap ─┐
CoinGecko ─┼─→ CrawlingManager ─→ RankingsManager
Hyperliquid ─┘ .crawlAndSync() │
│ ▼
│ symbols table (SQLite)
│ │
▼ ▼
PushNotificationManager ─→ PriceCollector (7) — full metadata
│ PriceAlert (70) — symbol list
│
Admin API ←── SymbolAdminManager (promote/demote)
│
Frontend ←── GET /symbols/enabledManagers
| Manager | Role |
|---|---|
| SymbolStorageManager | CRUD on symbols table; seeds 26 core symbols on first access |
| CrawlingManager | Fetches from CMC, CoinGecko, Hyperliquid in parallel |
| CrawlerConfigManager | Persists crawler settings (topN, interval, enabled) |
| RankingsManager | Updates CMC/CoinGecko ranks, inserts newly discovered symbols |
| PushNotificationManager | Fans out config changes to downstream DOs with retry |
| SymbolAdminManager | Promote/demote, batch ops, recommendation management |
Recommendation System (Suggest, Don't Act)
The crawler never auto-enables or auto-disables symbols. It sets recommendations (PROMOTE / DEMOTE) that require admin action:
- PROMOTE: Symbol appears in both CMC and CoinGecko top-N and is listed on Hyperliquid, but currently disabled
- DEMOTE: Symbol is enabled but has fallen out of the top-N intersection
This two-step design prevents accidental exposure of illiquid symbols to users.
Top-N Intersection Filter
Only symbols appearing in both CoinMarketCap and CoinGecko top-N rankings are considered for promotion. This cross-reference reduces noise from single-source anomalies.
Auto-Categorization
Newly discovered symbols are automatically categorized:
- Known meme tickers (DOGE, SHIB, PEPE, etc.) →
MEME - BTC, ETH →
MAJOR - CMC rank ≤ 10 →
LARGE_CAP - CMC rank ≤ 50 →
ALTCOIN - Otherwise →
EMERGING
Fail-Open Downstream Design
PriceCollector and PriceAlert store pushed config in memory. If they haven't received a push yet (fresh start, eviction):
- PriceCollector: Falls back to static
HyperliquidSymbolInfodefinitions - PriceAlert: Allows all symbols (null set = no filtering)
This ensures the system degrades gracefully rather than refusing to operate.
Eventual Consistency via Push + Reconciliation
Config changes trigger an immediate push to all 77 downstream DOs (7 PriceCollectors + 70 PriceAlerts). On top of this:
- Retry with backoff: Failed pushes retry via alarm (30s → 1m → 2m → 5m → 15m cap)
- Periodic reconciliation: Every 15 minutes, a full push runs as a safety net to correct any drift
Lazy Initialization
On first access, if the symbols table is empty, SymbolRegistry seeds all 26 core symbols from static constants (categories, display orders, CMC/CoinGecko IDs, Hyperliquid metadata). No manual bootstrapping required.
Crawler Lifecycle
The alarm handler runs on a configurable interval (default: 1 hour):
- Crawl: Fetch CMC top-N, CoinGecko top-N, and all Hyperliquid perpetuals in parallel
- Sync: Insert new symbols as disabled, update rankings, set recommendations
- Reconcile: Push current config to all downstream DOs
- Reschedule: Set next alarm
Edge Cases & Error Handling
- Partial crawl failure: Each external API (CMC, CoinGecko, Hyperliquid) is fetched via
Promise.allSettled. If one source fails, available data is still processed — the intersection filter naturally excludes symbols missing from a failed source - Downstream push failure: Individual DO push failures don't block others (
Promise.allSettled). Failed targets are retried with exponential backoff up to 5 attempts, and periodic reconciliation acts as a final safety net - Empty intersection: If both CMC and CoinGecko fail, the intersection is empty — no recommendations are generated, existing config is unchanged
See Also
- PriceCollector — Receives enabled symbol metadata for price collection
- PriceAlert — Receives enabled symbol list for alert validation