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.
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:
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.
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
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:
| 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 Β· platform.torque.so