File size: 12,656 Bytes
b47444a
 
 
f667d47
b47444a
 
 
 
 
ba5804c
 
b47444a
61bb766
b47444a
c6b6c96
b47444a
c6b6c96
b47444a
 
 
 
 
c6b6c96
 
b47444a
c6b6c96
 
b47444a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c6b6c96
 
6079a60
b47444a
6079a60
b47444a
6079a60
c6b6c96
b47444a
 
 
 
 
c6b6c96
 
b47444a
 
c6b6c96
6079a60
b47444a
 
 
6079a60
b47444a
 
 
 
 
 
6079a60
b47444a
c6b6c96
 
b47444a
 
c6b6c96
 
b47444a
f667d47
b47444a
c6b6c96
 
 
 
b47444a
c6b6c96
f667d47
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b47444a
 
c6b6c96
 
b47444a
c6b6c96
b47444a
 
c6b6c96
b47444a
 
c6b6c96
b47444a
 
c6b6c96
b47444a
 
c6b6c96
 
f667d47
c6b6c96
b47444a
 
c6b6c96
 
 
 
 
 
f667d47
 
 
 
 
c6b6c96
b47444a
 
f667d47
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c6b6c96
 
 
6079a60
 
 
b47444a
 
 
f667d47
 
b47444a
f667d47
b47444a
f667d47
c6b6c96
 
6079a60
 
 
c6b6c96
b47444a
 
 
c6b6c96
f667d47
c6b6c96
6079a60
c6b6c96
f667d47
c6b6c96
b47444a
c6b6c96
b47444a
c6b6c96
b47444a
 
f667d47
c6b6c96
 
6079a60
b47444a
6079a60
b47444a
c6b6c96
 
6079a60
 
 
b47444a
 
 
 
 
 
 
 
 
c6b6c96
 
6079a60
c6b6c96
b47444a
c6b6c96
b47444a
 
c6b6c96
b47444a
f667d47
c6b6c96
 
f667d47
c6b6c96
b47444a
 
c6b6c96
b47444a
f667d47
c6b6c96
 
6079a60
b47444a
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
# 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)*