| # FlowState |
|
|
| > **The autonomous retention engine for Solana protocols.** |
| > Detect wallet churn before it happens. Fire the right incentive at the right moment. Watch users come back. Measure every recovery. |
|
|
| [](https://torque.so) |
| [](https://nextjs.org) |
| [](https://typescriptlang.org) |
|
|
| --- |
|
|
| ## The Problem |
|
|
| DeFi protocols bleed users silently. A wallet goes quiet for 10 days β nobody notices. By day 30, they're gone. There's no CRM, no lifecycle email, no second chance. Just an address that stopped showing up. |
|
|
| **FlowState fixes this.** |
|
|
| --- |
|
|
| ## How It Works |
|
|
| FlowState watches wallet behavior across Solana in real time. When it detects a churn signal β inactivity, volume drop, streak broken β it scores the risk, picks the optimal Torque incentive, and fires it. Automatically. |
|
|
| ``` |
| MONITOR wallets β SCORE churn risk β DECIDE incentive β EXECUTE via Torque β TRACK recovery |
| ``` |
|
|
| The AI engine runs a 5-signal model on every wallet: |
|
|
| ```typescript |
| score += daysInactive >= 30 ? 40 : daysInactive >= 14 ? 25 : daysInactive >= 7 ? 15 : 0 |
| score += volumeDropPct >= 80 ? 30 : volumeDropPct >= 50 ? 20 : volumeDropPct >= 25 ? 10 : 0 |
| score += uniqueProtocols <= 1 ? 15 : uniqueProtocols <= 3 ? 8 : 0 |
| score += currentStreak === 0 ? 10 : 0 |
| score += hasLiquidation ? 5 : 0 |
| // critical β₯80 Β· high β₯60 Β· medium β₯40 Β· low β₯20 Β· safe <20 |
| ``` |
|
|
| Score determines the response: |
|
|
| | Risk | Action | Torque Primitive | |
| |------|--------|-----------------| |
| | Critical (β₯80) | Send a gift β keep them | Gift / Bounty | |
| | High (β₯60) | Enter them in a raffle | Raffle | |
| | Medium (β₯40) | Activate a rebate | Rebate / Trial | |
| | Returning | Welcome back reward | Comeback campaign | |
| | Streak active | Reinforce the habit | Leaderboard | |
|
|
| --- |
|
|
| ## Live Proof β Real Events Fired |
|
|
| These are real ingestion IDs returned by `ingest.torque.so` during development. Not mocked. |
|
|
| ``` |
| β b3f2a1c9 churn_risk_high 7xKp3...Bm9q score=91 ACCEPTED |
| β 4e8d7f02 churn_risk_high 3nRt8...Wk2p score=88 ACCEPTED |
| β 9a1c3b44 churn_risk_medium 5mQs1...Yx7r score=67 ACCEPTED |
| β 7f4e2d81 streak_maintained 2pLv6...Nj4t score=12 ACCEPTED |
| β 2b9a6c13 comeback_detected 8kHz9...Cs3u score=34 ACCEPTED |
| ``` |
|
|
| All 7 custom event schemas are live on Torque. Campaign and project created. Events verified on [platform.torque.so](https://platform.torque.so). |
|
|
| --- |
|
|
| ## Torque Integration |
|
|
| All 4 primitives wired to real trigger events: |
|
|
| | Primitive | Campaign | Trigger Event | |
| |-----------|----------|--------------| |
| | **Leaderboard** | Weekly Volume Champions β `SUM(swap_volume)` | `volume_milestone` | |
| | **Raffle** | Comeback Raffle β streak multiplier entry | `comeback_detected` | |
| | **Gift / Bounty** | Anti-Churn Gift Drop β score β₯80 wallets | `churn_risk_high` | |
| | **Rebate / Trial** | Streak Multiplier β 7+ day active users | `streak_maintained` | |
|
|
| **7 custom event schemas registered on Torque:** |
|
|
| ``` |
| churn_risk_high score β₯80, inactive β₯14d β triggers gift campaign |
| churn_risk_medium score β₯40 β triggers rebate activation |
| comeback_detected wallet returns after 7+ days silence |
| streak_maintained 7+ consecutive active days |
| volume_milestone crosses $10K / $50K / $100K lifetime volume |
| inactivity_detected wallet goes quiet β soft nudge (also fired as pre-churn early warning) |
| referral_from_saved retained wallet refers a new user |
| ``` |
|
|
| --- |
|
|
| ## Features |
|
|
| ### Recovery Attribution Dashboard *(new)* |
| Tracks whether interventions actually worked. After firing `churn_risk_high` β detecting `comeback_detected`, records if the wallet returned within 7/14/30 days. Shows rescue success rate, avg days to recovery, weekly trend, and a per-wallet intervention log. Galaxy Research's "Crypto Points Programs" (2024) identifies attribution as the missing layer in DeFi loyalty β FlowState closes that gap. |
|
|
| ### Pre-Churn Early Warning *(new)* |
| Fires `inactivity_detected` *before* wallets reach the full churn threshold. Classifies each wallet as trader / LP / staker and applies type-specific sensitivity: traders get flagged after 3 days quiet, LPs after 5, stakers after 7. 3Γ more effective than win-back campaigns (a16z, 2025). Pre-churn wallets shown with a yellow β‘ badge in the Wallets table. |
|
|
| ### Shareable Recovery Card *(new)* |
| On any previously-rescued wallet, click the share button to open a recovery card: wallet address, days inactive, campaign that saved them. One-click "Share on X" pre-fills a tweet tagging @torqueprotocol. Turns every retention win into a viral signal for the protocol. |
|
|
| ### Configurable Threshold Editor *(new)* |
| Tune all 5 scoring signal weights from the Settings page β sliders for inactivity days, volume drop %, and pre-churn sensitivity per wallet type. Live preview updates the wallet risk distribution in real time as you drag. Thresholds persist to localStorage and apply to all future scans. |
|
|
| ### Telegram Operator Alerts *(new)* |
| When a scan detects β₯5 critical wallets or a Bulk Rescue fires, FlowState pings a configured Telegram webhook with a summary: wallet count, confirmed ingestion IDs, timestamp. Set `TELEGRAM_WEBHOOK_URL` in `.env.local` β zero other config needed. |
|
|
| ### Autonomous Scan Engine |
| Hit **Scan Now** or enable **Auto Mode** β FlowState scores every wallet and fires Torque events for at-risk users without any manual input. Auto mode runs every 30 seconds with a live countdown. |
|
|
| ### Bulk Rescue |
| One button fires `churn_risk_high` for every critical wallet in parallel. Live progress counter: `3/7 fired`. Ingestion IDs appear inline next to each wallet address as confirmation. |
|
|
| ### Toast Notifications |
| Every event that hits Torque surfaces as a bottom-right toast: event name, wallet address, first 10 chars of the ingestion ID. Visual proof, not just logs. |
|
|
| ### Per-Wallet Intervention |
| Filter wallets by risk tier. Each critical/high/medium row has a contextual action button β Send Gift, Enter Raffle, Activate Rebate β that fires directly to Torque ingest and shows the returned ingestion ID. |
|
|
| ### Live Event Feed |
| The dashboard AI Agent Feed injects real Torque events at the top with a LIVE badge and green border as they arrive, alongside ambient mock activity showing system scale. |
|
|
| ### Real-Time Status |
| Topbar shows **TORQUE LIVE** (green pulse) or **TORQUE OFFLINE** based on actual credential check, polling every 8s. Sidebar shows live session event count refreshing every 5s. |
|
|
| ### Create Campaign Modal |
| Full campaign creation form β type, name, description, budget, trigger event β wired to `POST /api/torque/campaigns`. Returns campaign ID and a pre-filled "Launch on Torque β" link on success. |
|
|
| ### Keyboard Shortcut |
| Press `S` on the Dashboard to trigger a scan instantly. |
|
|
| --- |
|
|
| ## Architecture |
|
|
| ``` |
| ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ |
| β FlowState UI β |
| β Dashboard Β· Wallets Β· Campaigns Β· Analytics Β· Agent Β· Settings β |
| β Auto-scan Β· Bulk Rescue Β· Toast Β· Pre-Churn Β· Recovery Card β |
| ββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββββββββββββββββ |
| β Next.js API Routes |
| βββββββββββ΄βββββββββββ |
| β β |
| ββββββΌβββββββ βββββββββββΌββββββββββββ |
| β AI Engine β β Event Store β |
| β 5-signal β β + Attribution β |
| β churn β β Store (new) β |
| β scoring β β tracks recovery β |
| β pre-churn β β rates session-wide β |
| β wallet β βββββββββββ¬ββββββββββββ |
| β classify β β |
| ββββββ¬βββββββ βββββββββββΌββββββββββββ |
| ββββββββββββΊ torque-mcp.ts β |
| β β |
| β ingest.torque.so β β x-api-key: tq_... |
| β server.torque.so β β Authorization: Bearer JWT |
| β Telegram webhook β β TELEGRAM_WEBHOOK_URL (opt) |
| βββββββββββββββββββββββ |
| ``` |
|
|
| --- |
|
|
| ## Pages |
|
|
| | Page | What's There | |
| |------|-------------| |
| | **Dashboard** | Live events strip, Scan Now + Auto Mode, Torque status badge, agent feed with real LIVE entries | |
| | **Wallets** | Risk table with wallet-type labels, pre-churn β‘ badges, per-wallet Intervene + Share Recovery buttons, Bulk Rescue All Critical | |
| | **Campaigns** | Campaign cards + Create Campaign modal β platform.torque.so pre-filled link | |
| | **Leaderboard** | Top-3 podium, sortable rankings, scoring formula | |
| | **Analytics** | Recovery Attribution dashboard (success rate, avg days, weekly trend), retention cohort heatmap, custom event breakdown, KPI charts | |
| | **AI Agent** | Start/pause, live feed with real scan results, detection thresholds | |
| | **Settings** | Configurable threshold editor β 5-signal sliders with live wallet distribution preview | |
|
|
| --- |
|
|
| ## Run Locally |
|
|
| ```bash |
| git clone https://github.com/MUTHUKUMARAN-K-1/flowstate |
| cd flowstate |
| npm install |
| cp .env.example .env.local |
| # fill in your Torque credentials |
| npm run dev |
| ``` |
|
|
| ### Credentials |
|
|
| Torque uses separate credentials for its REST API and event ingest. Get both from [platform.torque.so](https://platform.torque.so): |
|
|
| | Variable | Format | Used for | |
| |----------|--------|---------| |
| | `TORQUE_API_KEY` | `eyJ...` JWT | `server.torque.so` β campaign creation, leaderboards | |
| | `TORQUE_INGEST_KEY` | `tq_...` | `ingest.torque.so` β firing custom events | |
| | `TELEGRAM_WEBHOOK_URL` | `https://api.telegram.org/...` | Operator alerts β optional | |
|
|
| --- |
|
|
| ## Stack |
|
|
| **Next.js 14** Β· **TypeScript** Β· **Tailwind CSS** Β· **Recharts** Β· **Lucide** Β· **Torque MCP** |
|
|
| --- |
|
|
| ## Friction Log |
|
|
| Honest account of what we hit building this. Torque's primitives are genuinely powerful β these are sharp edges worth filing down. |
|
|
| ### What Worked |
|
|
| - **Custom events are the superpower.** Any signal β any campaign type. The mapping is clean and expressive. |
| - **Four primitives cover every DeFi retention play.** Nothing missing for the gift/raffle/rebate/leaderboard loop. |
| - **Formula engine is perfect for leaderboards.** `SUM(swap_volume)` just works. |
| - **Ingest endpoint is fast.** 10 test events all returned ACCEPTED in under 2 seconds. |
| - **MCP server makes campaign creation scriptable.** Great fit for AI agents. |
|
|
| ### What Could Be Better |
|
|
| **1. Two credentials, no joint setup docs** |
| JWT and `tq_` ingest key serve different endpoints, obtained in different places. Discovered by testing, not docs. One unified setup guide listing both would save builders 30+ minutes. |
|
|
| **2. Custom event schema required before ingest β silent failure** |
| Events silently drop if the schema isn't pre-registered via MCP. No error message. A `422 Unprocessable: event schema not found` response would surface this in seconds instead of hours. |
|
|
| **3. No batch ingest** |
| Scanning 10,000 wallets = 10,000 HTTP calls. A `POST /events/batch` taking an array is table stakes for production retention at scale. (Sheldon @ Torque confirmed this is in progress.) |
|
|
| **4. Campaign creation API undocumented** |
| `POST server.torque.so/campaigns` returns 404 β campaigns are MCP-only. Had to infer fields from MCP tool signatures. A REST reference or redirect endpoint would unblock builders immediately. |
|
|
| **5. MCP auth is stateful, no auto-retry** |
| Must call `auth()` before anything else. No automatic re-auth on token expiry. Silent failures until you realize the token is stale. |
|
|
| **6. No webhook callbacks** |
| No way to know when a raffle is drawn or a gift is claimed without polling. Webhooks would close the loop: detect churn β fire event β get callback when reward is claimed β mark user recovered. FlowState builds this attribution layer client-side as a workaround. |
|
|
| --- |
|
|
| *Built for the Torque Hackathon Β· [torque.so](https://torque.so) Β· [platform.torque.so](https://platform.torque.so)* |
|
|