flowstate / README.md
muthuk1's picture
feat: recovery attribution, pre-churn warnings, recovery card, threshold editor, telegram alerts
f667d47
# 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.
[![Built with Torque](https://img.shields.io/badge/Built%20with-Torque-FCD535?style=flat-square)](https://torque.so)
[![Next.js](https://img.shields.io/badge/Next.js-14-black?style=flat-square)](https://nextjs.org)
[![TypeScript](https://img.shields.io/badge/TypeScript-5-3178C6?style=flat-square)](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)*