DefiPrice Markets is a real-time cryptocurrency price streaming platform that now combines five key building blocks:
- DexScreener SSE - Real-time price data source
- Somnia Data Streams - Decentralized data publication layer
- Next.js 14 Dashboard - Modern trading interface
- Firebase Firestore - Publisher-controlled pair registry
- Telegram Bot - Digest-style notifications for top movers
┌─────────────────────────────────────────────────────────────────┐
│ DexScreener Network │
│ (Multiple DEX Aggregators: Solana, Ethereum, Base, etc.) │
└────────────────────────┬────────────────────────────────────────┘
│ SSE Stream (Server-Sent Events)
│ Real-time price updates
▼
┌─────────────────────────────────────────────────────────────────┐
│ Price Streaming Bot │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ SSE Handler │→ │ Deduplicator │→ │ Batch Queue │ │
│ │ - Connect │ │ - Filter │ │ - Accumulate│ │
│ │ - Reconnect │ │ - Throttle │ │ - Optimize │ │
│ │ - Parse │ │ - Validate │ │ - Encode │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└────────────────────────────┬────────────────────────────────────┘
│ Batch Transactions
│ Encoded schema data
▼
┌─────────────────────────────────────────────────────────────────┐
│ Somnia Data Streams │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Schema: CryptoPriceData │ │
│ │ - timestamp (uint64) │ │
│ │ - pair (string) │ │
│ │ - chain (string) │ │
│ │ - priceUsd (uint256) │ │
│ │ - liquidity (uint256) │ │
│ │ - volume24h (uint256) │ │
│ │ - priceChange1h (int32) │ │
│ │ - priceChange24h (int32) │ │
│ └──────────────────────────────────────────────────────────┘ │
└────────────────────────────┬────────────────────────────────────┘
│ Subscribe to updates
│ Real-time pub/sub
▼
┌─────────────────────────────────────────────────────────────────┐
│ Trading Dashboard (Next.js 14) │
│ ┌─────────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Zustand Store │←─│ Somnia Hook │←─│ React Query │ │
│ │ - Price state │ │ - Subscribe │ │ - Cache │ │
│ │ - History │ │ - Decode │ │ - Hydrate │ │
│ │ - Admin pairs │ │ - Transform │ │ │ │
│ └────────┬────────┘ └──────────────┘ └──────────────┘ │
│ │ │
│ ┌────────▼─────────────────────────────────────────────────┐ │
│ │ Firestore API Route (/api/admin/pairs) │ │
│ │ - Wallet-gated CRUD │ │
│ │ - Firebase Admin SDK │ │
│ │ - Persists global pairs │ │
│ └────────┬──────────────────────────────────────────────────┘ │
│ │ │
│ ┌────────▼─────────────────────────────────────────────────┐ │
│ │ UI Components │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
│ │ │ PairList │ │ Chart │ │ Heatmap │ │ Stats │ │ │
│ │ │ Admin │ │ Watch │ │ Header │ │ Telegram │ │ │
│ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ │
│ └──────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
│
▼
Browser & Telegram Clients
Technology Stack:
- Node.js 20+ with TypeScript
- EventSource for SSE connections
- Viem for blockchain interactions
- Winston for logging
Responsibilities:
-
Connection Management
- Establish SSE connections to DexScreener
- Auto-reconnect with exponential backoff
- Handle network failures gracefully
-
Data Processing
- Parse incoming price events
- Validate data integrity
- Transform to internal schema
-
Optimization
- Deduplicate redundant updates
- Batch multiple updates
- Throttle high-frequency changes
-
Publishing
- Encode data to Somnia schema
- Write to Data Streams
- Handle write failures and retries
Key Files:
bot/src/
├── index.ts # Main entry point
├── config/index.ts # Configuration management
├── sse/handler.ts # SSE connection logic
├── streams/writer.ts # Somnia streams integration
├── schema/encoder.ts # Data encoding/decoding
└── utils/
├── logger.ts # Winston logger setup
└── deduplicator.ts # Update filtering
Schema Definition:
interface CryptoPriceData {
timestamp: uint64 // Unix timestamp (seconds)
pair: string // Trading pair symbol
chain: string // Blockchain network
priceUsd: uint256 // Price in USD (18 decimals)
liquidity: uint256 // Pool liquidity (18 decimals)
volume24h: uint256 // 24h trading volume (18 decimals)
priceChange1h: int32 // 1h % change (basis points)
priceChange24h: int32 // 24h % change (basis points)
}Data Flow:
Write Flow:
Bot → Encode Data → Transaction → Somnia Chain → Event Emission
Read Flow:
Subscribe Request → Somnia RPC → Event Stream → Dashboard
Key Operations:
registerSchema()- One-time schema registrationstreams.set()- Write price updatesstreams.subscribe()- Subscribe to updates
Technology Stack:
- Next.js 14 with App Router
- React 18 with TypeScript
- Zustand for state management
- TailwindCSS + Shadcn UI
- Framer Motion for animations
- TradingView Lightweight Charts
- Firebase Admin SDK (server routes)
- Telegram Bot API (server-side cron/digest)
Architecture Patterns:
- State Management (Zustand)
interface PriceStore {
pairs: Map<string, PairState>
updatePair: (key, data) => void
addHistoryPoint: (key, time, value) => void
isConnected: boolean
error: string | null
}- Real-time Updates
useEffect(() => {
const subscription = sdk.streams.subscribe({
schemaId,
publisher,
keys: pairKeys,
onUpdate: (update) => {
const decoded = decodePriceData(update.data)
updatePair(update.id, decoded)
}
})
return () => subscription.unsubscribe()
}, [])- Component Structure
components/
├── Header.tsx # Navigation and branding
├── PairList.tsx # Market overview grid
├── PriceHeader.tsx # Individual pair header
├── TradingChart.tsx # Price chart component
├── PairStats.tsx # Statistics panel
├── Heatmap.tsx # Market heatmap
└── ui/ # Shadcn UI components
Key Files:
dashboard/
├── app/
│ ├── layout.tsx # Root layout with wallet + registry providers
│ ├── page.tsx # Markets list page
│ ├── pair/[id]/page.tsx # Individual pair page
│ ├── heatmap/page.tsx # Heatmap page
│ ├── watch/page.tsx # Wallet-local watchlists
│ ├── admin/page.tsx # Wallet-gated admin interface
│ └── api/admin/pairs/route.ts # Firestore CRUD endpoint
├── components/ # React components
├── hooks/
│ ├── useSomniaStreams.ts # Streams subscription hook
│ └── useWalletStore.ts # Wallet connection + publisher check
└── lib/
├── store.ts # Zustand price store
├── pair-registry.ts # Base + admin pair registry state machine
├── firebase-admin.ts # Server-side Firestore bootstrap
└── utils.ts # Helper functions
Workflow:
- Publisher wallet connects via
useWalletStore. - Admin UI calls
addAdminPair/removeAdminPairfrompair-registry.ts. - Registry hits
/api/admin/pairswith the wallet address for authorization. - Route initializes Firebase Admin (shared
.envsecrets) and writes the pair to Firestore (adminPairscollection keyed bychain:address). - Registry refresh merges Firestore-administered pairs with
.envbase pairs and rehydrates Zustand/Somnia subscriptions.
Security Controls:
- Wallet gating enforced server-side (
NEXT_PUBLIC_PUBLISHER_ADDRESS). - Firestore service account keys provided via root
.envand loaded dynamically in both dev and prod. - REST calls validated for duplicates and missing data before persistence.
Bot Consideration:
- Bot still reads
.envpairs; when admins add pairs they should also sync bot config until Firestore ingestion is automated.
botprocess optionally instantiates a Telegram notifier (controlled viaTELEGRAM_NOTIFIER_ENABLED).- Every 5 minutes (configurable), it aggregates gainers/losers based on recent Somnia/DexScreener data and sends formatted markdown to
TELEGRAM_CHAT_ID. - Digest styling highlights top moves, CTA button invites users back to the dashboard.
- Notifications can be disabled without removing credentials, simplifying staging vs production toggles.
DexScreener SSE Event
↓
SSE Handler receives raw data
↓
Parse JSON to DexScreenerUpdate
↓
Transform to PriceData schema
↓
Deduplicator checks:
- Time since last update > threshold?
- Price change > threshold?
↓
Add to batch queue
↓
Batch full OR interval elapsed?
↓
Encode all updates to ABI format
↓
Write transaction to Somnia
↓
Somnia emits update event
↓
Dashboard subscription receives event
↓
Decode ABI to PriceData
↓
Update Zustand store
↓
React components re-render
↓
UI updates with new price
Publisher connects wallet
↓
`pair-registry.addAdminPair()` invoked
↓
Client POST /api/admin/pairs (wallet address, chain, address, label)
↓
Route validates publisher wallet + normalizes payload
↓
Firebase Admin writes/updates Firestore `adminPairs` doc
↓
Registry refresh merges Firestore pairs into Zustand store
↓
Components subscribe to expanded pair list and trigger Somnia subscriptions
Scheduler tick (default 5 min)
↓
Collect latest price snapshots
↓
Rank top movers (up/down)
↓
Format markdown digest + CTA deep links
↓
POST to Telegram Bot API
↓
Users receive digest in configured channel
New price arrives in store
↓
addHistoryPoint(key, time, value)
↓
Append to history array
↓
Trim to max 1000 points
↓
TradingChart useEffect triggered
↓
series.setData(history)
↓
Chart redraws with new point
-
Batch Processing
- Accumulate multiple updates
- Single transaction for efficiency
- Configurable batch size
-
Deduplication
- Compare with last price
- Check time interval
- Filter insignificant changes
-
Connection Pooling
- Reuse SSE connections
- Graceful reconnection
- Exponential backoff
-
State Management
- Zustand for lightweight state
- Map-based storage for O(1) lookups
- Dedicated pair registry store handles Firestore hydration & deduplication
-
Chart Optimization
- Limit history to 1000 points
- Efficient data updates
- Canvas-based rendering
-
Code Splitting
- Route-based splitting (markets, heatmap, pair, watch, admin)
- Dynamic imports
- Lazy loading
Bot:
- Run multiple instances with different pair subsets
- Each instance handles subset of pairs
- No shared state required
Dashboard:
- Deploy multiple instances behind load balancer
- Stateless design enables easy scaling
- CDN for static assets
Bot:
- Increase batch size for more throughput
- Add more CPU for concurrent processing
- More memory for larger batches
Dashboard:
- More connections per instance
- Larger cache for historical data
- Better hardware for chart rendering
-
Private Key Management
- Never committed to repo
- Environment variables only
- Encrypted at rest
-
RPC Security
- HTTPS only
- Rate limiting
- Error handling
-
Input Validation
- Sanitize SSE data
- Validate schema compliance
- Type checking
-
Wallet-Gated Admin
- Publisher wallet required for global pair CRUD
- Server verifies wallet matches
NEXT_PUBLIC_PUBLISHER_ADDRESS - Firestore writes never exposed to non-admin users
-
XSS Protection
- React escaping
- Content Security Policy
- Input sanitization
-
Rate Limiting
- Subscription throttling
- Request limits on admin API route
- Error boundaries
Bot:
- SSE connection status
- Update frequency per pair
- Batch sizes and intervals
- Write success/failure rates
- Memory and CPU usage
Dashboard:
- Page load time
- Component render time
- WebSocket connection status
- User interactions
- Error rates
Bot:
INFO: Normal operations
WARN: Recoverable errors
ERROR: Critical failures
DEBUG: Detailed diagnostics
Dashboard:
console.log() // Development only
Sentry // Production errors
Analytics // User behaviorSingle VPS (4GB RAM, 2 CPU)
├── Bot (PM2)
├── Dashboard (PM2)
├── Nginx (Reverse Proxy)
└── Let's Encrypt (SSL)
Pros: Simple, cost-effective Cons: Single point of failure
Bot Service (Railway)
↓ Writes to
Somnia Streams
↓ Read by
Dashboard (Vercel)
↓ Served to
Users (Global CDN)
Pros: Scalable, managed Cons: More complex, higher cost
Docker Host
├── Bot Container
├── Dashboard Container
└── Nginx Container
Pros: Portable, isolated Cons: Requires Docker knowledge
-
Historical Data
- Store price history
- Candlestick charts
- Time-range queries
-
Advanced Analytics
- Volume analysis
- Liquidity tracking
- Volatility metrics
-
Alerts System
- Price notifications
- Webhook integration
- Email/SMS alerts
-
Multi-DEX Support
- Jupiter (Solana)
- Uniswap (Ethereum)
- PancakeSwap (BSC)
-
WebSocket Alternative
- Replace SSE with WS
- Better connection handling
- Lower latency
-
Caching Layer
- Redis for hot data
- Reduce blockchain reads
- Faster dashboard loads
-
Database Integration
- PostgreSQL for history
- TimescaleDB for time-series
- Analytics queries
-
Bot Not Connecting
- Check environment variables
- Verify Somnia RPC endpoint
- Confirm private key format
-
Dashboard Not Updating
- Check browser console
- Verify subscription keys
- Confirm bot is running
-
Admin Pair Add Fails
- Ensure Firebase env vars are loaded (root
.envor deployment secrets) - Confirm wallet matches publisher address
- Check Firestore IAM permissions for the service account
- Ensure Firebase env vars are loaded (root
-
High Gas Costs
- Increase batch size
- Raise price threshold
- Extend batch interval
Last Updated: November 2025 Version: 1.0.0 Maintainer: DefiPrice Team