Yield-Sage
Health Warn
- License — License: MIT
- Description — Repository has a description
- Active repo — Last push 0 days ago
- Low visibility — Only 5 GitHub stars
Code Pass
- Code scan — Scanned 12 files during light audit, no dangerous patterns found
Permissions Pass
- Permissions — No dangerous permissions requested
No AI report is available for this listing yet.
An autonomous AI agent that recommends the best yield opportunities for you on Mantle Network
YieldSage
Autonomous Yield Intelligence & Paper Trading Agent — Built on the Mantle Network
YieldSage is an industrial-grade, fully autonomous yield intelligence ecosystem purpose-built for the Mantle Network. It continuously tracks real-time liquidity pool APYs and TVLs across every major Mantle protocol, generates risk-adjusted yield recommendations through a fault-tolerant multi-provider LLM cascade, cryptographically anchors all advisory decisions on-chain for verifiability, and delivers live intelligence through both a cinematic Next.js Pro Dashboard and a conversational Telegram AI agent.
📖 Table of Contents
- 🏛️ Grand System Architecture
- ⛓️ On-Chain Verifiability
- ✨ Feature Highlights
- 🎬 Cinematic UI/UX Engine
- ⚙️ Backend — Python Agent
- 🖥️ Frontend — Next.js Dashboard
- 🗄️ Database Schema
- 📂 Project Structure
- 🔧 Tech Stack
- 🌐 Deployment Topology
- ⚙️ Environment Variables
- 🚀 Setup & Running Locally
- 📚 Documentation Library
- 🗺️ Roadmap
⛓️ On-Chain Verifiability
Every AI recommendation produced by YieldSage is permanently anchored on the Mantle Network.
How it works:
- Each recommendation batch is serialised to canonical JSON and SHA-256 hashed.
- The hash is embedded in a 0-MNT self-transaction on Mantle as
yieldsage:<hash>. - The Mantle transaction hash is stored in the database alongside every recommendation.
- The YieldSage dashboard renders a direct Mantlescan link for every recommendation row.
Sample verified recommendation:
- View on Mantlescan:
https://mantlescan.xyz/tx/0x3d8544f8365691f63bc2d614d9b4bfae498c8c50e26b15efb58e77a2f1b4a39b - Input data decodes to:
yieldsage:c45f8fdf4e877e8a93a54dcd0d9bf896cfc3d7e820c8de65d8a9f0fe3a1d1a1b
All recommendations since June 2026 are permanently auditable on-chain.
🏛️ Grand System Architecture
YieldSage is architected as a fully decoupled, service-oriented system. Data flows from on-chain Mantle liquidity contracts → through Dune Analytics → into a Python ingestion pipeline → validated and AI-scored → persisted into Supabase → served through a FastAPI REST layer → consumed by both the Next.js dashboard and the Telegram bot.
graph TD
%% DATA SOURCE & INGESTION
subgraph Ingestion ["① Ingestion & Sync Layer"]
DUNE[Dune Analytics API\nQuery #7595582]
FETCHER[DuneFetcher Service\nagent/fetcher.py]
ROTATOR[Credential Auto-Rotator\nMulti-key credit validator]
DUNE -->|CSV Data Stream| FETCHER
FETCHER --> ROTATOR
end
%% PERSISTENCE
subgraph Data ["② Database Layer"]
DB[(Supabase PostgreSQL\n8 Tables · RLS Enforced)]
RLS[Row Level Security\nPolicies]
DB <--> RLS
end
FETCHER -->|Composite-Key Upserts\nprotocol_name × pool_address| DB
%% INTEL & SCORING
subgraph Agent ["③ AI Scoring & Verifiability"]
SCORER[HourlyScorer\nagent/scorer.py]
CASCADE[Multi-LLM Cascade\nCerebras→SambaNova→Groq→NVIDIA→Gemini]
MEMO[Web3 Memo Logger\non-chain SHA-256 anchor]
DB -->|Live Yield Snapshots| SCORER
SCORER --> CASCADE
CASCADE -->|SHA-256 Hash| MEMO
MEMO -->|0 MNT Transaction| MANTLE[(Mantle Network\nRPC Validator)]
end
CASCADE -->|Write Picks & Recs| DB
%% SCHEDULER
subgraph Sched ["④ Autonomous Scheduler"]
APSched[APScheduler\nHourly Pipeline]
APSched -->|Every 60 min| FETCHER
APSched -->|Every 60 min| SCORER
APSched -->|Every 60 min| PICKS[Dashboard AI Picks]
end
%% GATEWAY
subgraph Gateway ["⑤ REST API Gateway"]
FASTAPI[FastAPI App\nagent/main.py]
AUTH[JWT Signature Authenticator\nSupabase Auth validation]
FASTAPI <--> AUTH
DB <--> FASTAPI
end
%% CLIENTS
subgraph Clients ["⑥ Client Ecosystem"]
DASH[Next.js Web Dashboard\nfrontend/]
TG[Telegram Bot Handler\nagent/bot.py]
BOT[YieldSage Bot\nt.me/YieldSageBot]
DASH <-->|JWT Auth · Yields · Trades| FASTAPI
TG <-->|Alerts · Conversational Q&A| FASTAPI
TG <--> BOT
end
✨ Feature Highlights
| Feature | Description |
|---|---|
| 🔄 Autonomous Hourly Sync | Dune Analytics query #7595582 executes and streams pool data every hour via APScheduler. No manual intervention required. |
| 🔑 Dune API Key Rotation | A pool of comma-separated Dune API keys is validated for credit usage. Exhausted keys are automatically rotated so ingestion never misses a cycle. |
| 🤖 5-Provider LLM Cascade | Cerebras → SambaNova → Groq → NVIDIA → Gemini. Falls back through each provider on rate-limit (HTTP 429) or failure. Serves cached responses if all fail. |
| ⛓️ On-Chain Proof-of-Recommendation | Every AI scoring batch is SHA-256 hashed and logged as a 0-MNT transaction on the Mantle Network. Permanently auditable on Mantle Explorer. |
| 📊 Real-Time Yield Leaderboard | Full-width filterable, searchable, sortable table with 1D / 7D / 30D trend pills, risk-tier badges, TVL, protocol logos, and on-chain links. |
| 💬 Conversational Telegram AI Agent | Multi-turn memory, slash commands (/yields, /top, /trade, /portfolio, /alerts), and natural language DeFi advisory powered by the LLM cascade. |
| 📈 Paper Trading Simulator | Open, monitor, and close mock yield-bearing positions. Continuous-time APY accrual math tracks P&L in real-time against live pool rates. |
| 🧩 Risk Tier Classification | Pools are auto-classified as stable (stablecoin pairs) or moderate (volatile asset pairs) based on asset name analysis. |
| 🔒 Supabase RLS Security | Row Level Security policies enforce that users can only read/write their own trades, alerts, and chat memory. Public yield data is read-only. |
| 📡 Personalized Hourly Alerts | The scorer evaluates each user's active paper trades against live yields and pushes tailored Telegram alerts when significant drift is detected. |
🎬 Cinematic UI/UX Engine
The visual identity of YieldSage is centered around a high-performance Scrollytelling Engine — the feature users fall in love with first. Every interaction is deliberate and kinetic.
1. Canvas Scrubbing & Spring Physics
The landing page runs a 1,300vh scroll experience that scrubs through a 480-frame, two-section 3D animation sequence rendered at high resolution.
- Canvas Scrubbing — High-resolution JPEGs rendered directly onto an HTML5
<canvas>viarequestAnimationFrame. The frame index is perfectly interpolated against Framer Motion'suseScroll+useSpringphysics. - Spring Interpolation — Scroll position is smoothed through configurable spring damping, giving the animation a natural acceleration and deceleration response — not a linear scrub.
- Cinematic Text Overlays — Text blocks are timed to exact scroll phases. They fade in, translate on the Y-axis, and fade out in sync with key 3D animation moments (plant sprouting, intelligence reveal).
- Graceful Degradation — If a user scrolls faster than frames can load, the engine falls back to the nearest cached frame — no blank flashes, no stuttering.
graph TD
A[User Scrolls] -->|useScroll + useSpring| B(Calculate Scroll Progress: 0 → 1)
B --> C{Determine Active Section}
C -->|0.00 → 0.45| D[Section 1: Plant Growth Sequence]
C -->|0.55 → 1.00| E[Section 2: Intelligence Reveal]
D --> F[Calculate Frame Index 1–240]
E --> G[Calculate Frame Index 1–240]
F --> H[Draw frame to HTML5 Canvas]
G --> H
H --> I[Sync Cinematic Text Phase Overlays]
I --> J[Fade-in / Translate-Y / Fade-out]
2. Progressive Frame Loading Architecture
Delivering 480 high-resolution images (~145MB total) without blocking the loading screen required a custom progressive streaming buffer.
- Initial Block (180 frames) — The custom loading screen holds the user until the first 180 frames of Section 1 download (~70% of the initial scroll experience), ensuring a buttery-smooth first impression.
- Background Hydration — Once unblocked, the app renders immediately. The remaining 60 Section-1 frames and all 240 Section-2 frames stream silently in the background. The canvas auto-refreshes as new frames arrive via a
Set-based registry.
sequenceDiagram
participant U as User
participant L as Loading Screen
participant P as Page (UI)
participant B as Background Loader
U->>L: Opens Site
L->>L: Fetch Frames 1–180 (Section 1 Priority Buffer)
L-->>P: 180 Frames Loaded → Unlock App
P->>U: Display Interactive Landing UI
P->>B: Trigger Background Loader
B->>B: Fetch Frames 181–240 (Section 1 tail)
B->>B: Fetch Frames 1–240 (Section 2 full set)
B-->>P: Inject New Frames → Canvas auto-refreshes
3. Cinematic Loading Screen
The loading screen is a core brand experience — not a placeholder.
- Glitch Typography — "YIELDSAGE" initializes with a cryptographic character-scramble effect that resolves into the brand text frame-by-frame.
- Laser Scanline — A glowing green gradient sweeps across the central logo, accompanied by orbiting status dots on inverse rotation paths.
- Real-time Progress — A highly stylised progress bar with a hex-grid readout tracks the exact percentage of the 180-frame initial buffer as it loads.
- Hex Grid Overlay — A faint hexagonal grid pattern (Mantle brand motif) pulses behind the logo during the load phase.
4. Ambient Micro-Interactions & Effects
Every non-canvas section of the site feels alive through layered micro-interactions:
| Effect | Implementation |
|---|---|
| Mouse Spotlight | A reactive blurred radial gradient follows the user's cursor — mouse-gradient-background.tsx |
| CRT/Vignette | Global CSS overlays apply cinematic vignetting and faint scanlines across the entire viewport |
| Floating Particles | Ambient glowing particles drift upward at emotional peaks of the scroll journey |
| Scroll-to-Explore Indicator | Glassmorphic scroll indicator with pulsating mouse wheel + bouncing chevron; fades on first scroll |
| iOS Phone Bezel | The AI agent preview is rendered inside a photo-realistic iOS bezel frame with a typewriter chat loop |
| Floating AI Bubble | An animated bouncing/pulsing AI launcher bubble pinned to the bottom-right, linking to t.me/YieldSageBot |
| Lenis Smooth Scroll | lenis library wraps the entire page for silky inertial scroll physics |
| DeFi TVL Tooltip | Glassmorphic info tooltip on the TVL card explains data coverage vs DeFiLlama with a hover |
5. Landing Page Navigation
Replaced all placeholder nav links with real, semantically meaningful anchors:
| Label | Destination |
|---|---|
| Features | #features (Core Capabilities section) |
| Intelligence | #agent (AI Agent Demo section) |
| Dashboard | /dashboard (Full Pro Dashboard) |
| Docs | /docs (Technical Documentation) |
| Launch App | /dashboard (Primary CTA) |
⚙️ Backend — Python Agent
The entire backend is a Python monorepo under agent/. It runs three concurrent processes: the FastAPI REST server, the APScheduler pipeline, and the Telegram bot thread — all managed from a single main.py lifespan.
1. Data Ingestion & Dune Key Rotation
agent/fetcher.py — DuneFetcher class.
The fetcher pulls structured pool data from Dune Analytics Query #7595582, which aggregates all active Mantle DeFi protocol pools with APY, TVL, Base APY, Reward APY, and 1D/7D/30D trend fields.
Key rotation algorithm:
- On startup, loads the last-used API key index from
fetcher_state.json. - Before each session, calls
POST /api/v1/usagefor each key in the pool to validate credit usage. - Switches to the first key that has credits remaining.
- After a successful session, rotates to the next key (saving state) to distribute usage evenly.
- If all keys are exhausted, logs a critical error but does not crash — returns the current key as fallback.
Composite-key upsert logic:
- Composite key =
(protocol_name, pool_address) - Prevents duplicate pool registration when a protocol operates multiple assets on the same contract.
- Auto-detects stablecoin pools by checking if the asset name contains
usdordai→ assignsrisk_tag = stable. - Updates
image_urlandapp_linkmetadata on existing protocols if Dune returns richer data than what's in the DB.
sequenceDiagram
autonumber
participant F as DuneFetcher
participant D as Dune Analytics API
participant DB as Supabase DB
F->>F: Load key index from fetcher_state.json
F->>D: POST /api/v1/usage (validate credits per key)
D-->>F: credits_used / credits_included
F->>D: POST /query/7595582/execute (trigger execution)
D-->>F: execution_id
loop Every 15 seconds
F->>D: GET /execution/{id}/status
D-->>F: PENDING → COMPLETED
end
F->>D: GET /query/7595582/results/csv
D-->>F: CSV Stream (Protocol, Pool Address, APY, TVL...)
Note over F,DB: Composite Key: (protocol_name, pool_address)
F->>DB: SELECT id, name, pool_address FROM protocols
DB-->>F: Existing protocol registry
rect rgb(15,30,15)
Note over F: Register new protocols (not seen before)
F->>DB: INSERT INTO protocols (slug, name, pool_name, pool_address, risk_tag, chain)
end
F->>DB: INSERT INTO yield_snapshots (apy, base_apy, reward_apy, tvl_usd, apy_1d, apy_7d, apy_30d...)
DB-->>F: Acknowledge write
F->>F: rotate_key() → save_state()
Scheduler retry policy (in scheduler.py):
- Fetcher is retried up to 3 times with exponential backoff (30s → 60s → 120s).
- If all fetch attempts fail, the scoring step is skipped entirely for that hour — the pipeline never crashes.
2. Multi-Provider LLM Cascade
agent/ai_service.py — AIService class.
To guarantee near-100% uptime for both real-time Telegram queries and background scoring, all LLM calls are routed through a cascading fallback engine across five independent providers:
Cerebras (gpt-oss-120b / zai-glm-4.7)
↓ on 429 / Exception
SambaNova (Meta-Llama-3.3-70B-Instruct / gemma-3-12b-it)
↓ on 429 / Exception
Groq (llama-3-3-70b-versatile)
↓ on 429 / Exception
NVIDIA NIM (meta/llama-3.3-70b-instruct / llama-3.1-70b-instruct)
↓ on 429 / Exception
Gemini (gemini-2.5-flash-lite / gemini-2.5-flash)
↓ if all fail
Last-Known-Good Cache (secure, locally stored fallback response)
For background scoring tasks (hourly pipeline), the priority is reversed — NVIDIA and Gemini are tried first to preserve Cerebras/SambaNova high-speed burst capacity for interactive user chats.
flowchart TD
Start([User Query or Background Score Task]) --> Build[Build System Prompt\n+ Context + Yield Data]
Build --> C1{Try Cerebras}
C1 -->|✅ Success| Out[Format & Return Response]
C1 -->|❌ 429 / Error| C2{Try SambaNova}
C2 -->|✅ Success| Out
C2 -->|❌ 429 / Error| C3{Try Groq}
C3 -->|✅ Success| Out
C3 -->|❌ 429 / Error| C4{Try NVIDIA NIM}
C4 -->|✅ Success| Out
C4 -->|❌ 429 / Error| C5{Try Gemini}
C5 -->|✅ Success| Out
C5 -->|❌ All Failed| Cache[Serve Cached\nLast-Known-Good Response]
Cache --> Out
Out --> End([Reply delivered to client])
The ai_service.py also includes:
get_recent_yields()— Fetches the latest snapshot per active pool from Supabase.generate_personalized_hourly_update()— Builds per-user context (risk preference, active trades, yield shifts) and generates tailored alert copy.generate_dashboard_picks()— Produces ranked AI recommendations for the Pro Dashboard's AI Picks panel.search_context()— Uses DuckDuckGo scraping to inject live web search context into advisory responses.- Chat memory — Reads/writes
chat_memorytable (last N turns per user) to maintain multi-turn conversation state.
3. On-Chain Verifiability Layer
agent/scorer.py (recommendation logging via web3).
Every daily recommendation batch generated by the AI Scorer is cryptographically anchored on the Mantle Network to make all advisory outputs tamper-proof and independently auditable.
- Hash Generation — The complete recommendation payload (timestamp, ranking, risk tiers, recommended APYs, model name) is serialized to JSON and SHA-256 hashed.
- On-Chain Log — A 0-value self-transaction is submitted from the YieldSage agent wallet to the Mantle RPC node. The SHA-256 hash is embedded as hexadecimal bytes in the transaction
datafield. - Hash Storage — The resulting Mantle transaction hash is written to
recommendations.on_chain_tx_hashin Supabase. - Dashboard Verification — The frontend dashboard reads this field and renders a direct hyperlink to the Mantle Explorer, allowing anyone to verify the recommendation was logged at that exact time.
graph LR
A[Daily Scorer Output\nJSON payload] -->|Serialize| B(JSON String)
B -->|SHA-256| C("Hash: 0x6e3d...")
D[YieldSage Agent Wallet\n0xABCD...] -->|"0 MNT Tx\ndata = 0x6e3d..."| E[Mantle Validator Node]
E -->|Mine & Confirm Block| F("Tx Hash: 0x82b4...")
F -->|Stored in| G[(recommendations\n.on_chain_tx_hash)]
H[Frontend Dashboard] -->|GET /api/recommendations/history| G
H -->|Renders clickable link| I["Mantle Explorer\n(Public Audit Trail)"]
4. Hourly Scoring & Personalized Alerts Pipeline
agent/scorer.py — HourlyScorer class.
Runs concurrently for ALL registered users using asyncio.gather — the pipeline time scales to the latency of one user, not N users.
graph TD
A[APScheduler fires run_pipeline] --> B[DuneFetcher.run with 3× retry]
B --> C[HourlyScorer.run]
C --> D[Fetch latest yields from DB]
C --> E[Fetch all users + risk preferences]
C --> F[Fetch all active paper trades]
C --> G[Fetch alert_preferences per user]
D & E & F & G --> H[asyncio.gather — all users in parallel]
H --> I{Is alert enabled?}
I -->|No| J[Skip user]
I -->|Yes| K[Build per-user context:\nrisk tier + active trades + yield data]
K --> L[generate_personalized_hourly_update via LLM Cascade]
L --> M[INSERT into telegram_messages table]
M --> N[Telegram Bot broadcasts pending messages]
H --> O[generate_dashboard_picks for web UI]
5. Paper Trading Simulation Engine
agent/routers/paper_trades.py
Allows any authenticated user to open simulated DeFi positions against live pool rates. Position value accrues in real-time using continuous-time APY math.
Mathematical Accrual Model:
Given:
- $I_0$ = Simulated investment (USD)
- $APY$ = Pool's current annual percentage yield (%)
- $T_{entry}$ = UNIX timestamp when trade was opened
- $T_{now}$ = Current system time
$$D = \max\left(\frac{T_{now} - T_{entry}}{86400}, \ 0\right) \quad \text{(fractional days held)}$$
$$Profit = I_0 \times \frac{APY}{100} \times \frac{D}{365}$$
$$Value_{current} = I_0 + Profit$$
stateDiagram-v2
[*] --> Active : User opens /trade or submits from Dashboard
state Active {
[*] --> EntryCaptured : Record entry_apy + simulated_investment_usd
EntryCaptured --> HourlyMonitoring : Awaiting cron run
HourlyMonitoring --> EvaluateYieldShift : Compare current APY vs entry_apy
EvaluateYieldShift --> QueueAlert : Yield drifts beyond threshold
QueueAlert --> HourlyMonitoring : Alert sent, continue monitoring
}
Active --> Closed : User closes trade (Dashboard or /close command)
Closed --> [*] : Save final P&L + closed_at timestamp
Trade lifecycle API endpoints:
POST /api/paper-trades— Open new positionGET /api/paper-trades— List all user positions with live P&LPUT /api/paper-trades/{id}/close— Close position and freeze P&L
6. FastAPI REST Gateway
agent/main.py — Manages app lifespan, CORS, and router registration.
| Router | Prefix | Purpose |
|---|---|---|
stats.py |
/api/stats |
Dashboard headline metrics (TVL, APY, protocol count, etc.) |
yields.py |
/api/yields |
Yield leaderboard, search, filters, historical chart data |
protocols.py |
/api/protocols |
Protocol registry, metadata, and individual pool detail |
recommendations.py |
/api/recommendations |
AI picks, on-chain tx hashes, recommendation history |
user.py |
/api/user |
User profile, risk preference, connection codes |
paper_trades.py |
/api/paper-trades |
Trade management: open, list, close |
CORS policy — Strictly allows only:
http://localhost:3000(local dev)http://localhost:3001(local alt port)https://yieldsageai.xyz(production)https://www.yieldsageai.xyz(production WWW)
Built-in health endpoints:
GET /— Service identity + version + timestampGET /health— Scheduler running status + bot thread alive statusGET /docs— Swagger interactive API documentation (auto-generated)GET /redoc— ReDoc alternative API reference
7. JWT Authentication & RLS Security
agent/auth.py
All protected endpoints depend on the get_current_user FastAPI dependency, which:
- Reads the
Authorization: Bearer <token>header. - Calls
supabase_admin.auth.get_user(token)to cryptographically validate the JWT against Supabase Auth. - Returns the authenticated user's UUID, or raises HTTP 401.
get_optional_user is a softer variant that returns None for unauthenticated requests — used on endpoints that return richer data for signed-in users.
Supabase Row Level Security (RLS) policies:
| Table | SELECT | INSERT / UPDATE / DELETE |
|---|---|---|
users |
auth.uid() = id |
auth.uid() = id |
paper_trades |
auth.uid() = user_id |
auth.uid() = user_id |
alert_preferences |
auth.uid() = user_id |
auth.uid() = user_id |
chat_memory |
auth.uid() = user_id OR matching telegram_chat_id |
Same |
yield_snapshots |
true (public) |
false (service_role only) |
recommendations |
true (public) |
false (service_role only) |
protocols |
true (public) |
false (service_role only) |
telegram_messages |
auth.uid() = user_id |
service_role only |
🖥️ Frontend — Next.js Pro Dashboard
Built with Next.js 16 App Router, React 19, TypeScript 5, Tailwind CSS v4, and Framer Motion 12.
1. Landing Page & Scrollytelling Engine
frontend/app/page.tsx — Orchestrates all sections.
| Component | File | Role |
|---|---|---|
LoadingScreen |
loading-screen.tsx |
Cinematic branded loader with glitch text, laser scan, hex grid, and progress |
GlobalLoadingWrapper |
global-loading-wrapper.tsx |
Gate — renders children only after initial frame buffer is ready |
ScrollytellingSection |
scrollytelling-section.tsx |
Full canvas scrubbing engine — useScroll, useSpring, frame management |
ScrollCanvas |
scroll-canvas.tsx |
HTML5 canvas renderer — draws the current frame index |
HeroSection |
hero-section.tsx |
Above-the-fold identity and CTA |
FeaturesSection |
features-section.tsx |
6-card Core Capabilities grid (3×2 even layout) |
AgentSection |
agent-section.tsx |
iOS phone bezel mockup with infinite typewriter chat animation |
StatsSection |
stats-section.tsx |
Live aggregate stats from the API |
Footer |
footer.tsx |
Site links, socials, copyright |
MouseGradientBackground |
mouse-gradient-background.tsx |
Cursor-following radial glow spotlight |
LenisProvider |
lenis-provider.tsx |
Wraps the app in Lenis smooth-scroll physics |
StorageConsent |
storage-consent.tsx |
GDPR-friendly cookie consent banner with localStorage |
2. Pro Dashboard
frontend/app/dashboard/page.tsx
A full-screen, dark-mode yield intelligence cockpit with:
- Full-width Leaderboard Table (
leaderboard-table.tsx) — No sidebars. The entire viewport is the table.- Pagination with configurable page size
- Live search by protocol name or asset
- Multi-filter: risk tier, min TVL, min APY
- Watchlist toggle with
localStoragepersistence (watchlist-provider.tsx) - Color-coded 1D / 7D / 30D trend pills — green (improving) / red (declining) / grey (neutral)
- Protocol logos, on-chain pool links (Mantle Explorer), and app deep-links
- Full responsive scroll on mobile
- Stats Cards (
stats-cards.tsx) — Live dashboard headline metrics:- Total DeFi TVL (with glassmorphic info tooltip explaining coverage vs DeFiLlama)
- Average APY across all active pools
- Median APY
- Unique Protocols Tracked (counted by unique name, not row count)
- Total Pools Tracked
- Insights Panel (tabbed, below the table):
- AI Picks tab (
recommendation-card.tsx) — AI-generated ranked recommendations with timestamp and LLM model attribution. Redirects to Telegram bot if no picks available. - TVL Distribution tab (
protocol-charts.tsx) — Recharts bar chart showing cumulative TVL grouped by protocol name across all active pools.
- AI Picks tab (
- Floating AI Bubble (
floating-ai-bubble.tsx) — Bouncing animated launcher bubble pinned bottom-right, links directly tot.me/YieldSageBot.
3. Docs Page
frontend/app/docs/page.tsx
A professional technical documentation experience:
- Scroll-spy navigation — Active section highlights in the left sidebar as the user scrolls.
- Reading Progress Bar — Thin top progress tracker.
- 6 Documentation Sections: Overview, Architecture, Database Schema, AI Engine, Security, API Reference — all with Mermaid diagrams rendered inline.
- Fully responsive across mobile, tablet, and desktop.
🗄️ Database Schema & ERD
Eight core tables in Supabase PostgreSQL. Full schema with constraints and RLS detailed in System Design Specification.
erDiagram
USERS ||--|| ALERT_PREFERENCES : "has (1-to-1)"
USERS ||--o{ PAPER_TRADES : "simulates (1-to-many)"
USERS ||--o{ TELEGRAM_MESSAGES : "receives (1-to-many)"
USERS ||--o{ CHAT_MEMORY : "owns (1-to-many)"
PROTOCOLS ||--o{ YIELD_SNAPSHOTS : "has history (1-to-many)"
PROTOCOLS ||--o{ RECOMMENDATIONS : "recommended-in (1-to-many)"
PROTOCOLS ||--o{ PAPER_TRADES : "linked-to (1-to-many)"
USERS {
uuid id PK
text email "UNIQUE NOT NULL"
text full_name
bigint telegram_chat_id "UNIQUE NULL"
text risk_preference "stable|moderate|aggressive"
timestamptz created_at
}
PROTOCOLS {
uuid id PK
text slug "UNIQUE NOT NULL"
text name "NOT NULL"
text pool_name "NOT NULL"
text pool_address "NOT NULL"
text risk_tag "stable|moderate|aggressive"
text chain "DEFAULT mantle"
text image_url
text app_link
boolean is_active "DEFAULT true"
}
YIELD_SNAPSHOTS {
uuid id PK
uuid protocol_id FK
numeric apy
numeric base_apy
numeric reward_apy
numeric tvl_usd
text reward_tokens
numeric apy_1d
numeric apy_7d
numeric apy_30d
jsonb raw_payload
timestamptz fetched_at
}
RECOMMENDATIONS {
uuid id PK
uuid protocol_id FK
text risk_tag
integer rank
numeric apy_at_time
text ai_reasoning
text ai_model
text on_chain_tx_hash "UNIQUE"
text recommendation_hash
timestamptz on_chain_logged_at
timestamptz created_at
}
PAPER_TRADES {
uuid id PK
uuid user_id FK
uuid protocol_id FK
numeric simulated_investment_usd
numeric entry_apy
text status "active|closed"
timestamptz closed_at
timestamptz created_at
}
ALERT_PREFERENCES {
uuid id PK
uuid user_id FK "UNIQUE"
numeric stable_apy_threshold
numeric moderate_apy_threshold
numeric aggressive_apy_threshold
boolean is_active "DEFAULT true"
}
CHAT_MEMORY {
uuid id PK
uuid user_id FK
bigint telegram_chat_id
text role "user|assistant"
text content
timestamptz created_at
}
TELEGRAM_MESSAGES {
uuid id PK
uuid user_id FK
bigint chat_id
text message_type "daily_push|query_response|alert"
text content
text status "pending|sent|failed"
timestamptz sent_at
}
📂 Project Structure & Module Mapping
Yield-Sage/
│
├── agent/ # Python Backend & Autonomous Agent
│ ├── main.py # FastAPI app · lifespan · CORS · router registry · health endpoints
│ ├── scheduler.py # APScheduler: hourly pipeline with exponential backoff retry
│ ├── fetcher.py # DuneFetcher: key rotation · execution polling · composite-key upserts
│ ├── scorer.py # HourlyScorer: user scoring · personalized alert queuing · asyncio.gather
│ ├── ai_service.py # AIService: 5-provider LLM cascade · chat memory · DDG search · picks gen
│ ├── bot.py # Telegram bot: command handlers · trade state machines · memory management
│ ├── auth.py # JWT FastAPI dependency: Supabase token validation · get_current_user
│ ├── ai_service_backup.py # Backup AIService snapshot (pre-migration fallback)
│ ├── anthropic_ai_service.py # Claude-specific LLM service variant
│ ├── benchmark_models.py # LLM provider benchmarking utility
│ ├── seed.py # DB seeding script for initial protocol data
│ ├── check_db.py # Quick DB inspection utility
│ ├── fetcher_state.json # Persisted Dune API key index (auto-managed)
│ ├── requirements.txt # Python dependencies
│ └── routers/
│ ├── stats.py # GET /api/stats/overview — dashboard headline metrics
│ ├── yields.py # GET /api/yields/leaderboard · /chart — pool data with filters
│ ├── protocols.py # GET /api/protocols — registry · individual pool detail
│ ├── recommendations.py # GET /api/recommendations — AI picks · on-chain tx hashes
│ ├── user.py # GET/PUT /api/user — profile · risk preference · connection codes
│ └── paper_trades.py # POST/GET/PUT /api/paper-trades — trade lifecycle management
│
├── frontend/ # Next.js 16 Web Client (App Router)
│ ├── package.json # Node dependencies (React 19, Framer Motion, Recharts, Radix UI...)
│ ├── next.config.mjs # Next.js configuration
│ ├── tsconfig.json # TypeScript strict config
│ ├── postcss.config.mjs # PostCSS / Tailwind CSS v4 pipeline
│ ├── components.json # shadcn/ui component registry config
│ │
│ ├── app/ # Next.js App Router
│ │ ├── layout.tsx # Root layout: fonts · metadata · providers · consent banner
│ │ ├── globals.css # Global CSS: dark palette · CRT overlay · vignette · scrollbar
│ │ ├── page.tsx # Landing page: scrollytelling orchestrator
│ │ ├── dashboard/
│ │ │ └── page.tsx # Pro Dashboard: full-width table · stats · insights · AI bubble
│ │ └── docs/
│ │ └── page.tsx # Technical Docs: scroll-spy · progress · mermaid sections
│ │
│ ├── components/
│ │ ├── loading-screen.tsx # Cinematic loader: glitch text · laser scan · hex grid · progress
│ │ ├── global-loading-wrapper.tsx # Gate: holds page until 180-frame buffer is ready
│ │ ├── scrollytelling-section.tsx # Canvas scrubbing engine: 480 frames · spring physics · overlays
│ │ ├── scroll-canvas.tsx # HTML5 canvas renderer: requestAnimationFrame · frame draw
│ │ ├── hero-section.tsx # Above-the-fold identity and primary CTA
│ │ ├── features-section.tsx # 6-card Core Capabilities (3×2 even grid)
│ │ ├── agent-section.tsx # iOS bezel mockup · infinite typewriter chat loop
│ │ ├── stats-section.tsx # Live aggregate stats from /api/stats/overview
│ │ ├── footer.tsx # Site footer with real anchor links
│ │ ├── mouse-gradient-background.tsx # Cursor-tracking radial glow spotlight
│ │ ├── lenis-provider.tsx # Lenis smooth scroll inertia wrapper
│ │ ├── storage-consent.tsx # GDPR cookie consent banner with localStorage
│ │ └── dashboard/
│ │ ├── stats-cards.tsx # Headline metric cards · DeFi TVL info tooltip
│ │ ├── leaderboard-table.tsx # Full-width table: search · filter · watchlist · trend pills
│ │ ├── protocol-charts.tsx # Recharts bar chart: TVL distribution by protocol
│ │ ├── recommendation-card.tsx # AI picks panel · Telegram bot redirect when empty
│ │ ├── floating-ai-bubble.tsx # Bouncing animated Telegram launcher bubble
│ │ └── watchlist-provider.tsx # React Context + localStorage watchlist hook
│ │
│ ├── contexts/ # Global React context providers
│ ├── lib/
│ │ └── api.ts # Axios API client: base URL · JWT inject · typed endpoints
│ └── public/
│ ├── logo.jpg # YieldSage brand logo
│ ├── readme_banner.png # README hero banner
│ └── frames/ # 480 high-res 3D animation frames (Section 1 + Section 2)
│
├── docs/ # Markdown Technical Documentation
│ ├── system_architecture.md # Network topology · LLM cascade · on-chain verifiability
│ ├── system_design.md # DB ERD · RLS policies · paper trading math · scoring pipeline
│ ├── api_documentation.md # REST endpoints · request/response JSON schemas · JWT lifecycle
│ ├── FAST-API-Bcakend-Walkthrough.md # FastAPI router map · endpoint list · Swagger setup
│ ├── YIELDSAGE_AI_MIGRATION.md # Multi-provider LLM migration audit · fallback cache design
│ └── dune_fetcher_retry.md # Dune CSV execution trigger · status polling · credit audit
│
├── supabase/ # Supabase schema migrations
├── data/ # Raw seed or exported data files
├── Procfile # Railway process definitions: web · worker
├── railway.toml # Railway deployment configuration
├── requirements.txt # Root-level Python dependencies
├── .env # Local environment secrets (git-ignored)
├── .gitignore # Excludes .env, node_modules, .next, __pycache__
└── README.md # ← You are here
🔧 Complete Tech Stack
Backend
| Layer | Technology | Version | Role |
|---|---|---|---|
| Language | Python | 3.11+ | Core agent runtime |
| Web Framework | FastAPI | 0.115 | REST API gateway + async endpoints |
| ASGI Server | Uvicorn | latest | Production HTTP server |
| Task Scheduler | APScheduler | latest | Hourly pipeline + cron management |
| HTTP Client | httpx | latest | Async Dune API requests |
| Telegram | python-telegram-bot | latest | Bot event loop + handlers |
| AI SDK #1 | cerebras-cloud-sdk | latest | Cerebras gpt-oss-120b integration |
| AI SDK #2 | openai ≥ 1.0 | latest | SambaNova, Groq, NVIDIA NIM (OpenAI-compatible) |
| AI SDK #3 | anthropic | latest | Claude integration (backup service) |
| Blockchain | web3 | latest | Mantle RPC · 0-value tx · SHA-256 memo logging |
| Auth | PyJWT + Supabase | latest | JWT decoding + Supabase user validation |
| Database Client | supabase-py | latest | Supabase REST + admin client |
| Environment | python-dotenv | latest | .env secret loading |
| Data Validation | pydantic | latest | FastAPI request/response models |
| ORM Layer | sqlalchemy | latest | Supplementary query building |
Frontend
| Layer | Technology | Version | Role |
|---|---|---|---|
| Framework | Next.js | 16.0.10 | App Router · SSR · static optimization |
| Language | TypeScript | 5.x | Full type safety across all components |
| UI Library | React | 19.2.0 | Component rendering |
| Animation | Framer Motion | 12.x | useScroll · useSpring · canvas scrubbing |
| Smooth Scroll | Lenis | 1.1.20 | Inertial scroll physics across the entire app |
| Charts | Recharts | 2.15.4 | TVL bar chart · yield history line charts |
| Component Kit | Radix UI | various | Accessible headless components (tabs, dialogs, tooltips, etc.) |
| Styling | Tailwind CSS | 4.x | Utility-first dark mode styling |
| Data Fetching | TanStack Query | 5.x | Client-side caching, polling, and query management |
| HTTP Client | Axios | 1.x | API calls from frontend to FastAPI backend |
| Icons | Lucide React | 0.454 | Icon system |
| Form Validation | React Hook Form + Zod | latest | Type-safe form handling |
| Supabase Client | @supabase/supabase-js | 2.x | Direct Supabase Auth + DB access from the browser |
| Analytics | Vercel Analytics | 1.3.1 | Web traffic analytics |
Infrastructure
| Layer | Technology | Role |
|---|---|---|
| Database | Supabase (PostgreSQL) | Multi-region · RLS · Auth · Realtime |
| Frontend Hosting | Vercel | Global CDN · automatic SSL · preview deployments |
| Backend Hosting | Railway | Dockerized Python · process-based deployment · env secrets |
| Blockchain | Mantle Network | On-chain recommendation memo logging |
| Data Source | Dune Analytics | SQL-queryable Mantle DeFi pool metrics |
🌐 Deployment Topology
graph TD
subgraph Vercel ["▲ Vercel (Frontend CDN)"]
NEXT[Next.js 16\nfrontend/]
end
subgraph Railway ["🚂 Railway (Backend)"]
direction TB
WEB["web — uvicorn main:app\nFastAPI REST Server\n:8000"]
SCHED["worker — APScheduler\nHourly pipeline · Fetcher · Scorer · Picks"]
BOT["bot — python bot.py\nTelegram long-poll event loop"]
end
subgraph Supabase ["🟢 Supabase (Database)"]
PG[(PostgreSQL\n8 Tables · RLS Policies)]
AUTH[Supabase Auth\nJWT Issuer]
end
subgraph External ["External Services"]
DUNE[Dune Analytics API]
TG[Telegram Bot API]
LLM[LLM Providers:\nCerebras · SambaNova\nGroq · NVIDIA · Gemini]
MANTLE[Mantle Network RPC]
end
NEXT <-->|HTTPS REST| WEB
NEXT -->|Supabase Auth SDK| AUTH
WEB <-->|service_role| PG
SCHED -->|reads / writes| PG
BOT <-->|reads / writes| PG
SCHED <-->|query execution| DUNE
SCHED <-->|LLM calls| LLM
SCHED -->|0 MNT tx| MANTLE
BOT <-->|send/receive messages| TG
Production Procfile (Procfile):
web: uvicorn agent.main:app --host 0.0.0.0 --port $PORT
⚙️ Environment Variables Reference
Create a .env file in the root directory. See agent/.env.example for the full template.
# ─── Supabase ───────────────────────────────────────────────────────────────
SUPABASE_URL=https://<your-project>.supabase.co
SUPABASE_ANON_KEY=eyJhbGc...
SUPABASE_SERVICE_ROLE_KEY=eyJhbGc...
# ─── Telegram Bot ────────────────────────────────────────────────────────────
TELEGRAM_BOT_TOKEN=8902478929:AAEMiTIt8...
# ─── LLM Providers (for active cascade fallbacks) ────────────────────────────
CEREBRAS_API_KEY=csk-...
SAMBANOVA_API_KEY=...
GROQ_API_KEY=gsk_...
NVIDIA_API_KEY=nvapi-...
GEMINI_API_KEY=...
ANTHROPIC_API_KEY=sk-ant-... # Optional — for Claude variant
# ─── Dune Analytics (comma-separated pool for key rotation) ─────────────────
DUNE_API_KEYS=key1,key2,key3
# ─── Mantle Blockchain ───────────────────────────────────────────────────────
MANTLE_RPC_URL=https://rpc.mantle.xyz
YIELDSAGE_WALLET_PRIVATE_KEY=0x...
# ─── Frontend (.env.local in frontend/) ──────────────────────────────────────
NEXT_PUBLIC_API_URL=https://your-railway-backend.up.railway.app
NEXT_PUBLIC_SUPABASE_URL=https://<your-project>.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGc...
🚀 Setup & Running Locally
Prerequisites
- Python 3.11+ with
pip - Node.js 20+ with
npm - A Supabase project with the schema applied from
supabase/ - At least one Dune API key with the Mantle yield query (ID:
7595582) - At least one LLM provider API key (Cerebras, Groq, etc.)
- A Telegram Bot Token from @BotFather
1. Clone & Configure
git clone https://github.com/joshuatochinwachi/Yield-Sage.git
cd Yield-Sage
Copy the environment template and fill in your secrets:
cp agent/.env.example .env
# Edit .env with your keys
2. Python Backend Agent
cd agent
pip install -r requirements.txt
Run the FastAPI REST server:
uvicorn main:app --host 127.0.0.1 --port 8000 --reload
In a separate terminal, start the Telegram bot:
python bot.py
Manually trigger a Dune data fetch (optional):
python fetcher.py
API docs available at: http://localhost:8000/docs
3. Next.js Web Dashboard
cd frontend
npm install
Configure the frontend environment:
cp .env.local.example .env.local # or create manually
# Set NEXT_PUBLIC_API_URL=http://localhost:8000
Start the development server:
npm run dev
Open http://localhost:3000 in your browser.
4. Copy the README Banner (First-Time Setup)
python copy_banner.py
📚 Documentation Library
| Document | Description |
|---|---|
| 📐 System Architecture Blueprint | Network topology, component decoupling, multi-provider LLM cascade flowchart, Mantle verifiability design |
| 🗄️ System Design Specification | Full DB ERD, RLS policy table, paper trading math derivations, scoring pipeline state diagrams |
| 🔌 API Reference Documentation | Every REST endpoint, request/response JSON schemas, query filter params, JWT lifecycle |
| 🐍 FastAPI Backend Walkthrough | Router map, endpoint list, Swagger interactive documentation setup |
| 🧠 AI Migration Walkthrough | Multi-provider LLM migration audit, backup cache design, provider reliability notes |
| 🔄 Dune Fetcher Retry Policies | Deep audit of the Dune CSV execution trigger, status polling, credit validation, error handling |
| 📊 Frontend UI/UX Architecture | Scrollytelling engine, progressive frame loading, cinematic loading screen, micro-interaction design |
🗺️ Roadmap
- Aggressive Risk Tier — Auto-classify volatile asset pools (non-stablecoin, non-blue-chip) as
aggressive - Multi-Chain Expansion — Extend Dune query coverage to Base, Arbitrum, and Optimism
- On-Chain Trade Settlement — Move paper trades to actual smart contract execution on Mantle
- Social Leaderboard — Public opt-in leaderboard for paper trading P&L rankings
- Alert Thresholds UI — In-dashboard slider controls for per-risk-tier alert sensitivity
- Historical APY Charts — Per-pool time-series chart on click-through from the leaderboard
- Push Notifications — Web push (PWA) alongside Telegram for browser-native alerts
- Mobile App — React Native / Expo wrapper for iOS and Android
🤝 Contributing
Contributions, bug reports, and feature ideas are welcome.
- Fork the repository
- Create your feature branch:
git checkout -b feature/your-feature - Commit your changes:
git commit -m "feat: add your feature" - Push to the branch:
git push origin feature/your-feature - Open a Pull Request
📄 License
This project is open-source under the MIT License — Copyright © 2026 Joshua Nwachukwu (Jo$h). See LICENSE for details.
👨💻 Developer
Built by Jo$h — Joshua Nwachukwu
| Channel | Link |
|---|---|
| 𝕏 Twitter | @defi__josh |
| Telegram | @joshuatochinwachi |
| [email protected] |
🌿 YieldSage Socials
| Channel | Link |
|---|---|
| 🌐 Website | yieldsageai.xyz |
| 🤖 Telegram AI Bot | @YieldSageBot |
| 𝕏 Twitter | @yieldsageai |
Built with 🌿 by Jo$h on the Mantle Network
yieldsageai.xyz ·
@YieldSageBot ·
@yieldsageai
Reviews (0)
Sign in to leave a review.
Leave a reviewNo results found