@0xprotovox/deficlaw 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +230 -0
  2. package/dist/analysis/formatOutput.d.ts +4 -0
  3. package/dist/analysis/formatOutput.js +209 -0
  4. package/dist/analysis/formatOutput.js.map +1 -0
  5. package/dist/analysis/riskScorer.d.ts +6 -0
  6. package/dist/analysis/riskScorer.js +104 -0
  7. package/dist/analysis/riskScorer.js.map +1 -0
  8. package/dist/analysis/summaryGenerator.d.ts +68 -0
  9. package/dist/analysis/summaryGenerator.js +171 -0
  10. package/dist/analysis/summaryGenerator.js.map +1 -0
  11. package/dist/cache/memoryCache.d.ts +13 -0
  12. package/dist/cache/memoryCache.js +31 -0
  13. package/dist/cache/memoryCache.js.map +1 -0
  14. package/dist/index.d.ts +2 -0
  15. package/dist/index.js +12 -0
  16. package/dist/index.js.map +1 -0
  17. package/dist/server.d.ts +7 -0
  18. package/dist/server.js +76 -0
  19. package/dist/server.js.map +1 -0
  20. package/dist/sources/dexscreener.d.ts +20 -0
  21. package/dist/sources/dexscreener.js +117 -0
  22. package/dist/sources/dexscreener.js.map +1 -0
  23. package/dist/sources/gmgn.d.ts +8 -0
  24. package/dist/sources/gmgn.js +210 -0
  25. package/dist/sources/gmgn.js.map +1 -0
  26. package/dist/sources/solanaRpc.d.ts +14 -0
  27. package/dist/sources/solanaRpc.js +60 -0
  28. package/dist/sources/solanaRpc.js.map +1 -0
  29. package/dist/tools/analyzeToken.d.ts +8 -0
  30. package/dist/tools/analyzeToken.js +253 -0
  31. package/dist/tools/analyzeToken.js.map +1 -0
  32. package/dist/tools/getPrice.d.ts +17 -0
  33. package/dist/tools/getPrice.js +13 -0
  34. package/dist/tools/getPrice.js.map +1 -0
  35. package/dist/tools/getTopTraders.d.ts +45 -0
  36. package/dist/tools/getTopTraders.js +44 -0
  37. package/dist/tools/getTopTraders.js.map +1 -0
  38. package/dist/tools/getTrending.d.ts +9 -0
  39. package/dist/tools/getTrending.js +16 -0
  40. package/dist/tools/getTrending.js.map +1 -0
  41. package/dist/types/index.d.ts +127 -0
  42. package/dist/types/index.js +2 -0
  43. package/dist/types/index.js.map +1 -0
  44. package/package.json +46 -0
package/README.md ADDED
@@ -0,0 +1,230 @@
1
+ # DefiClaw
2
+
3
+ **The first open-source DeFi MCP server for Claude Code.**
4
+
5
+ Analyze any Solana token in seconds. Holder intelligence, risk scoring, smart money tracking, KOL detection. Zero API keys required.
6
+
7
+ ```
8
+ > "analyze token 3oQwNvAfZMuPWjVPC12ukY7RPA9JiGwLod6Pr4Lkpump"
9
+
10
+ ═══ SUMMARY ═══
11
+ POKE6900 is a 9mo old PumpSwap token with $25.9K liquidity and $34.5K market cap.
12
+ 53 diamond hands (53.0%), strong holder conviction.
13
+ Only 18.0% of holders are in profit, most are underwater with avg loss of $844 per wallet.
14
+ Buy pressure is strong at 3.3:1 ratio (1093 buys vs 395 sells), accumulation phase.
15
+ Contract looks safe: mint and freeze authorities revoked.
16
+ 🟢 Lower risk profile based on available data.
17
+ ```
18
+
19
+ ## Why deficlaw?
20
+
21
+ Claude Code can write code, fix bugs, deploy apps. But ask it "what's the price of BONK?" and it says *"I don't have real-time data."*
22
+
23
+ **deficlaw fixes that.** It gives Claude Code real-time access to DeFi data across Solana and 10+ chains.
24
+
25
+ - **Token Analysis** with holder intelligence, risk scoring, KOL tracking
26
+ - **Real-time Prices** from DexScreener across all major chains
27
+ - **Trending Tokens** with volume, liquidity, and boost data
28
+ - **Top Traders** showing who made and lost money on any token
29
+ - **Contract Security** checking mint/freeze authority on Solana
30
+ - **1.5 second** full analysis (not 11 seconds like browser-based scrapers)
31
+ - **Zero config** - no API keys, no wallets, no accounts needed
32
+
33
+ ## Quick Start
34
+
35
+ ```bash
36
+ # Clone and build
37
+ git clone https://github.com/0xprotovox/deficlaw.git
38
+ cd deficlaw
39
+ npm install && npm run build
40
+
41
+ # Add to Claude Code
42
+ claude mcp add defi -- node /path/to/deficlaw/dist/index.js
43
+ ```
44
+
45
+ Then just ask Claude naturally:
46
+
47
+ ```
48
+ > "analyze this token: 3oQw...pump"
49
+ > "what's the price of BONK?"
50
+ > "show me trending tokens on solana"
51
+ > "who made money on JUP token?"
52
+ ```
53
+
54
+ ## Tools
55
+
56
+ ### `analyze_token`
57
+
58
+ Full token analysis with holder intelligence, risk scoring, and human-readable summary.
59
+
60
+ **Input:**
61
+ | Parameter | Type | Default | Description |
62
+ |-----------|------|---------|-------------|
63
+ | `address` | string | required | Token contract address |
64
+ | `chain` | string | `"solana"` | Blockchain (solana, ethereum, bsc, base, arbitrum) |
65
+ | `include_holders` | boolean | `true` | Include GMGN holder analysis |
66
+
67
+ **Output includes:**
68
+ - Token info (name, symbol, age, socials)
69
+ - Price with 5m/1h/6h/24h changes
70
+ - Market data (mcap, fdv, volume, liquidity, vol/liq ratio)
71
+ - Contract security (mint authority, freeze authority, supply)
72
+ - Risk score (0-100) with detailed flags
73
+ - Holder concentration (top 5/10/20)
74
+ - Holder categories (diamond hands, snipers, KOLs, fresh wallets, insiders)
75
+ - Buy/sell pressure ratio
76
+ - Sentiment (profitable vs underwater holders, avg PnL)
77
+ - Dev wallet detection and status
78
+ - Top 20 holders table with PnL and tags
79
+ - KOL list with Twitter handles
80
+ - Human-readable summary with actionable insights
81
+
82
+ ### `get_price`
83
+
84
+ Quick price lookup. Sub-second response.
85
+
86
+ ```
87
+ > "price of So11111112222..."
88
+
89
+ BONK — $0.000024 (+5.2% 24h)
90
+ Volume: $142M | Liquidity: $12M | MCap: $1.8B
91
+ ```
92
+
93
+ ### `get_trending`
94
+
95
+ Trending and boosted tokens on any chain.
96
+
97
+ ```
98
+ > "trending tokens on solana"
99
+
100
+ 1. BONK — $0.000024 (+12%) — $142M volume
101
+ 2. WIF — $0.89 (-2.1%) — $89M volume
102
+ 3. JUP — $0.94 (+3.5%) — $45M volume
103
+ ...
104
+ ```
105
+
106
+ ### `get_top_traders`
107
+
108
+ Who made and lost money on a token. Winners, losers, PnL, tags.
109
+
110
+ ```
111
+ > "who profited on this token?"
112
+
113
+ 🏆 Top Winners:
114
+ 1. CR5N... — +$680 (+124%) 🟢 still holding
115
+ 2. EsRB... — +$166 (+16%) 💎 diamond hands
116
+
117
+ 💀 Top Losers:
118
+ 1. BgeeV... — -$7,548 (-65%) 💎 diamond hands (!)
119
+ 2. 5vqid... — -$5,420 (-50%) gmgn user
120
+ ```
121
+
122
+ ## Data Sources
123
+
124
+ All free, no API keys required:
125
+
126
+ | Source | Data | Speed |
127
+ |--------|------|-------|
128
+ | **DexScreener** | Prices, volume, liquidity, pairs, trending | <0.5s |
129
+ | **GMGN** | Holders, tags, KOLs, PnL, dev wallet, snipers | ~1s |
130
+ | **Solana RPC** | Mint authority, freeze authority, supply | <0.5s |
131
+
132
+ **Total analysis time: ~1.5 seconds**
133
+
134
+ ## Supported Chains
135
+
136
+ Prices and trending work on all DexScreener chains:
137
+
138
+ Solana, Ethereum, Base, BSC, Arbitrum, Polygon, Avalanche, Optimism, Fantom, and more.
139
+
140
+ Holder analysis (GMGN) currently supports **Solana** tokens.
141
+
142
+ ## Risk Scoring
143
+
144
+ The risk scorer analyzes 6 dimensions to produce a 0-100 score:
145
+
146
+ | Dimension | Weight | What it checks |
147
+ |-----------|--------|----------------|
148
+ | Liquidity | 25% | Pool depth in USD |
149
+ | Token Age | 10% | Time since creation |
150
+ | Holder Concentration | 20% | Top 10 holder % |
151
+ | Dev Wallet | 20% | Dev holdings and selling behavior |
152
+ | Fresh Wallets | 15% | New wallet % (possible wash/bundle) |
153
+ | Sniper Activity | 10% | Bot/sniper wallets in top holders |
154
+
155
+ **Levels:** 🟢 LOW (0-19) | 🟡 MEDIUM (20-44) | 🟠 HIGH (45-69) | 🔴 CRITICAL (70-100)
156
+
157
+ ## Architecture
158
+
159
+ ```
160
+ Claude Code ←→ MCP stdio ←→ deficlaw server
161
+
162
+ ┌────────────┼────────────┐
163
+ │ │ │
164
+ DexScreener GMGN API Solana RPC
165
+ (prices) (holders) (security)
166
+ ```
167
+
168
+ - **MCP SDK** for Claude Code integration
169
+ - **curl-based GMGN fetcher** bypasses Cloudflare (Playwright fallback if needed)
170
+ - **In-memory TTL cache** prevents rate limiting
171
+ - **Rate limiter** for DexScreener (150 req/min)
172
+ - **TypeScript** with full type safety
173
+
174
+ ## Configuration
175
+
176
+ ### Environment Variables (all optional)
177
+
178
+ | Variable | Default | Description |
179
+ |----------|---------|-------------|
180
+ | `SOLANA_RPC_URL` | `https://api.mainnet-beta.solana.com` | Custom Solana RPC endpoint |
181
+
182
+ ### Claude Code Config
183
+
184
+ Add to your project's `.mcp.json`:
185
+
186
+ ```json
187
+ {
188
+ "mcpServers": {
189
+ "defi": {
190
+ "command": "node",
191
+ "args": ["/path/to/deficlaw/dist/index.js"],
192
+ "env": {
193
+ "SOLANA_RPC_URL": "https://your-rpc.com"
194
+ }
195
+ }
196
+ }
197
+ }
198
+ ```
199
+
200
+ ## Roadmap
201
+
202
+ - [x] Token analysis with holder intelligence
203
+ - [x] Risk scoring (6 dimensions)
204
+ - [x] Contract security checks
205
+ - [x] KOL detection with Twitter handles
206
+ - [x] Human-readable AI summary
207
+ - [x] Top traders (winners/losers)
208
+ - [ ] Token search by name/symbol
209
+ - [ ] Slippage estimation (Jupiter quotes)
210
+ - [ ] Token comparison (side by side)
211
+ - [ ] Multi-chain holder analysis
212
+ - [ ] npm package (`npm install -g deficlaw`)
213
+ - [ ] Price alerts via MCP resources
214
+
215
+ ## Built With
216
+
217
+ - [Model Context Protocol SDK](https://github.com/modelcontextprotocol/typescript-sdk) - MCP server framework
218
+ - [DexScreener API](https://docs.dexscreener.com) - Price and market data
219
+ - [GMGN](https://gmgn.ai) - Holder intelligence
220
+ - TypeScript, Zod, Node.js 18+
221
+
222
+ ## License
223
+
224
+ MIT
225
+
226
+ ## Author
227
+
228
+ **@0xprotovox** - [Twitter](https://x.com/0xprotovox) | [GitHub](https://github.com/0xprotovox)
229
+
230
+ 20 years building software. Now building AI trading agents and DeFi tools.
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Format analysis output — clean, readable, both summary + detailed numbers
3
+ */
4
+ export declare function formatAnalysis(data: any): string;
@@ -0,0 +1,209 @@
1
+ /**
2
+ * Format analysis output — clean, readable, both summary + detailed numbers
3
+ */
4
+ function fmt(n) {
5
+ if (n === 0)
6
+ return '$0';
7
+ if (Math.abs(n) >= 1_000_000)
8
+ return `$${(n / 1_000_000).toFixed(2)}M`;
9
+ if (Math.abs(n) >= 1_000)
10
+ return `$${(n / 1_000).toFixed(1)}K`;
11
+ if (Math.abs(n) >= 1)
12
+ return `$${n.toFixed(2)}`;
13
+ if (Math.abs(n) >= 0.001)
14
+ return `$${n.toFixed(4)}`;
15
+ return `$${n.toFixed(8)}`;
16
+ }
17
+ function pct(n, digits = 1) {
18
+ return `${(n * 100).toFixed(digits)}%`;
19
+ }
20
+ function arrow(n) {
21
+ if (n > 0)
22
+ return `+${n.toFixed(2)}% 📈`;
23
+ if (n < 0)
24
+ return `${n.toFixed(2)}% 📉`;
25
+ return '0% ➖';
26
+ }
27
+ function shortenAddr(addr) {
28
+ if (addr.length <= 12)
29
+ return addr;
30
+ return `${addr.slice(0, 6)}...${addr.slice(-4)}`;
31
+ }
32
+ export function formatAnalysis(data) {
33
+ const lines = [];
34
+ // ═══════ SUMMARY ═══════
35
+ if (data.summary) {
36
+ lines.push('═══ SUMMARY ═══');
37
+ lines.push(data.summary);
38
+ lines.push('');
39
+ }
40
+ // ═══════ TOKEN INFO ═══════
41
+ lines.push('═══ TOKEN ═══');
42
+ lines.push(`Name: ${data.token.name} (${data.token.symbol})`);
43
+ lines.push(`Chain: ${data.token.chain}`);
44
+ lines.push(`Address: ${data.token.address}`);
45
+ lines.push(`Age: ${data.token.age}`);
46
+ if (data.token.createdAt)
47
+ lines.push(`Created: ${data.token.createdAt}`);
48
+ lines.push('');
49
+ // ═══════ PRICE ═══════
50
+ lines.push('═══ PRICE ═══');
51
+ lines.push(`Price: ${fmt(data.price.usd)}`);
52
+ lines.push(`5min: ${arrow(data.price.change5m)}`);
53
+ lines.push(`1h: ${arrow(data.price.change1h)}`);
54
+ lines.push(`6h: ${arrow(data.price.change6h)}`);
55
+ lines.push(`24h: ${arrow(data.price.change24h)}`);
56
+ lines.push('');
57
+ // ═══════ MARKET ═══════
58
+ lines.push('═══ MARKET ═══');
59
+ lines.push(`Market Cap: ${fmt(data.market.marketCap)}`);
60
+ lines.push(`FDV: ${fmt(data.market.fdv)}`);
61
+ lines.push(`Liquidity: ${fmt(data.market.liquidity)}`);
62
+ lines.push(`Volume 24h: ${fmt(data.market.volume24h)}`);
63
+ lines.push(`Volume 6h: ${fmt(data.market.volume6h)}`);
64
+ lines.push(`Volume 1h: ${fmt(data.market.volume1h)}`);
65
+ lines.push(`Volume 5m: ${fmt(data.market.volume5m)}`);
66
+ lines.push(`Vol/Liq Ratio: ${data.market.volumeLiquidityRatio}x`);
67
+ lines.push(`DEX: ${data.market.dex}`);
68
+ lines.push(`Pair: ${data.market.pairAddress}`);
69
+ lines.push('');
70
+ // ═══════ SECURITY ═══════
71
+ if (data.security) {
72
+ lines.push('═══ SECURITY ═══');
73
+ const mintOk = data.security.mintAuthority === 'revoked';
74
+ const freezeOk = data.security.freezeAuthority === 'revoked';
75
+ lines.push(`Mint Authority: ${mintOk ? '✅ Revoked (safe)' : '⚠️ ACTIVE (can print tokens!)'}`);
76
+ lines.push(`Freeze Authority: ${freezeOk ? '✅ Revoked (safe)' : '⚠️ ACTIVE (can freeze wallets!)'}`);
77
+ lines.push(`Total Supply: ${Math.round(data.security.supply).toLocaleString()}`);
78
+ lines.push(`Decimals: ${data.security.decimals}`);
79
+ lines.push('');
80
+ }
81
+ // ═══════ RISK ═══════
82
+ lines.push('═══ RISK ═══');
83
+ const riskMap = { LOW: '🟢', MEDIUM: '🟡', HIGH: '🟠', CRITICAL: '🔴' };
84
+ const riskEmoji = riskMap[data.risk.level] || '⚪';
85
+ lines.push(`Score: ${data.risk.score}/100 ${riskEmoji} ${data.risk.level}`);
86
+ if (data.risk.flags?.length > 0) {
87
+ data.risk.flags.forEach((f) => {
88
+ const sevMap = { critical: '🔴', high: '🟠', medium: '🟡', low: '🟢' };
89
+ const fEmoji = sevMap[f.severity] || '⚪';
90
+ lines.push(` ${fEmoji} ${f.message}`);
91
+ });
92
+ }
93
+ lines.push('');
94
+ // ═══════ HOLDERS ═══════
95
+ if (data.holders) {
96
+ const h = data.holders;
97
+ lines.push('═══ HOLDERS ═══');
98
+ lines.push(`Total Analyzed: ${h.total}`);
99
+ lines.push('');
100
+ // Concentration
101
+ lines.push('Concentration:');
102
+ lines.push(` Top 5: ${pct(h.concentration.top5Pct)}`);
103
+ lines.push(` Top 10: ${pct(h.concentration.top10Pct)}`);
104
+ lines.push(` Top 20: ${pct(h.concentration.top20Pct)}`);
105
+ lines.push('');
106
+ // Categories
107
+ lines.push('Categories:');
108
+ const cats = h.categories;
109
+ if (cats.diamondHands > 0)
110
+ lines.push(` 💎 Diamond Hands: ${cats.diamondHands}`);
111
+ if (cats.snipers > 0)
112
+ lines.push(` 🎯 Snipers: ${cats.snipers}`);
113
+ if (cats.freshWallets > 0)
114
+ lines.push(` 🆕 Fresh Wallets: ${cats.freshWallets}`);
115
+ if (cats.kols > 0)
116
+ lines.push(` 👑 KOLs: ${cats.kols}`);
117
+ if (cats.smartMoney > 0)
118
+ lines.push(` 🧠 Smart Money: ${cats.smartMoney}`);
119
+ if (cats.insiders > 0)
120
+ lines.push(` 🔑 Insiders: ${cats.insiders}`);
121
+ if (cats.devWallets > 0)
122
+ lines.push(` 🛠️ Dev Wallets: ${cats.devWallets}`);
123
+ if (cats.photonUsers > 0)
124
+ lines.push(` 📸 Photon: ${cats.photonUsers}`);
125
+ if (cats.gmgnUsers > 0)
126
+ lines.push(` 📲 GMGN: ${cats.gmgnUsers}`);
127
+ if (cats.transferIn > 0)
128
+ lines.push(` ↗️ Transfer In: ${cats.transferIn}`);
129
+ lines.push('');
130
+ // Sentiment
131
+ lines.push('Sentiment:');
132
+ lines.push(` Profitable: ${h.sentiment.profitableHolders} (${pct(h.sentiment.profitRatio)})`);
133
+ lines.push(` Losing: ${h.sentiment.losingHolders}`);
134
+ lines.push(` Total PnL: ${fmt(h.sentiment.totalPnlUsd)}`);
135
+ lines.push(` Total Cost: ${fmt(h.sentiment.totalCostUsd)}`);
136
+ lines.push(` Avg PnL/holder: ${fmt(h.sentiment.avgPnlPerHolder)}`);
137
+ lines.push('');
138
+ // Buy/Sell Pressure
139
+ lines.push('Buy/Sell Pressure:');
140
+ lines.push(` Buy TX: ${h.pressure.totalBuyTx}`);
141
+ lines.push(` Sell TX: ${h.pressure.totalSellTx}`);
142
+ lines.push(` Ratio: ${h.pressure.buySellRatio.toFixed(2)}:1 ${h.pressure.buySellRatio > 1.5 ? '🟢' : h.pressure.buySellRatio < 0.7 ? '🔴' : '🟡'}`);
143
+ lines.push('');
144
+ // Dev Wallet
145
+ if (h.devWallet) {
146
+ lines.push('Dev Wallet:');
147
+ lines.push(` Address: ${shortenAddr(h.devWallet.address)}`);
148
+ lines.push(` Holding: ${pct(h.devWallet.holdingPercent)}`);
149
+ lines.push(` PnL: ${fmt(h.devWallet.pnl)}`);
150
+ lines.push(` Status: ${h.devWallet.status}`);
151
+ lines.push('');
152
+ }
153
+ // Top 20 Holders Table
154
+ lines.push('Top 20 Holders:');
155
+ lines.push(' # | Address | Supply | Value | PnL | Tags');
156
+ lines.push(' ---|-------------|---------|-----------|------------|------');
157
+ h.topHolders.slice(0, 20).forEach((holder, i) => {
158
+ const num = String(i + 1).padStart(2);
159
+ const addr = shortenAddr(holder.address).padEnd(12);
160
+ const supply = pct(holder.supplyPercent).padStart(6);
161
+ const value = fmt(holder.valueUsd).padStart(9);
162
+ const pnl = (holder.pnl >= 0 ? '+' : '') + fmt(holder.pnl);
163
+ const tags = holder.tags.filter((t) => !/^TOP\d+$/.test(t)).join(', ') || '-';
164
+ const twitter = holder.twitterHandle ? ` @${holder.twitterHandle}` : '';
165
+ lines.push(` ${num} | ${addr} | ${supply} | ${value} | ${pnl.padStart(10)} | ${tags}${twitter}`);
166
+ });
167
+ lines.push('');
168
+ }
169
+ // ═══════ LP DETECTION ═══════
170
+ if (data.lpDetection) {
171
+ lines.push('═══ LP POOL ═══');
172
+ lines.push(`Top holder is LP pool: ✅`);
173
+ lines.push(`LP Address: ${shortenAddr(data.lpDetection.lpAddress)}`);
174
+ lines.push(`LP holds: ${pct(data.lpDetection.lpPercent)}`);
175
+ if (data.lpDetection.realTopHolder) {
176
+ lines.push(`Real top holder: ${shortenAddr(data.lpDetection.realTopHolder.address)} (${pct(data.lpDetection.realTopHolder.percent)})`);
177
+ }
178
+ lines.push('');
179
+ }
180
+ // ═══════ KOLs ═══════
181
+ if (data.kols && data.kols.length > 0) {
182
+ lines.push('═══ KOLs ═══');
183
+ data.kols.forEach((k, i) => {
184
+ const handle = k.twitterHandle ? `@${k.twitterHandle}` : shortenAddr(k.address);
185
+ const pnlStr = k.pnl !== 0 ? ` | PnL: ${fmt(k.pnl)}` : '';
186
+ const status = k.status === 'selling' ? '🔴 selling' : '🟢 holding';
187
+ const tags = k.tags.filter((t) => !/^TOP\d+$/.test(t) && t !== 'kol').join(', ');
188
+ lines.push(` ${i + 1}. ${handle} | ${status}${pnlStr}${tags ? ` | ${tags}` : ''}`);
189
+ });
190
+ lines.push('');
191
+ }
192
+ // ═══════ SOCIALS ═══════
193
+ if (data.socials) {
194
+ lines.push('═══ SOCIALS ═══');
195
+ if (data.socials.websites?.length > 0)
196
+ lines.push(`Website: ${data.socials.websites.join(', ')}`);
197
+ if (data.socials.twitter)
198
+ lines.push(`Twitter: ${data.socials.twitter}`);
199
+ if (data.socials.telegram)
200
+ lines.push(`Telegram: ${data.socials.telegram}`);
201
+ lines.push('');
202
+ }
203
+ // ═══════ META ═══════
204
+ lines.push('═══ META ═══');
205
+ lines.push(`Sources: ${data.meta.sources.join(' + ')}`);
206
+ lines.push(`Fetch time: ${(data.meta.fetchTimeMs / 1000).toFixed(1)}s`);
207
+ return lines.join('\n');
208
+ }
209
+ //# sourceMappingURL=formatOutput.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formatOutput.js","sourceRoot":"","sources":["../../src/analysis/formatOutput.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Composite Risk Scorer
3
+ * Combines DexScreener + GMGN data into a 0-100 risk score
4
+ */
5
+ import type { DexPair, Holder, RiskAssessment } from '../types/index.js';
6
+ export declare function scoreRisk(pair: DexPair | null, holders?: Holder[]): RiskAssessment;
@@ -0,0 +1,104 @@
1
+ export function scoreRisk(pair, holders) {
2
+ const flags = [];
3
+ let totalScore = 0;
4
+ // 1. Liquidity risk (25% weight)
5
+ const liquidity = pair?.liquidity?.usd || 0;
6
+ if (liquidity < 5000) {
7
+ flags.push({ type: 'liquidity', severity: 'critical', message: `Extremely low liquidity: $${liquidity.toFixed(0)}` });
8
+ totalScore += 25;
9
+ }
10
+ else if (liquidity < 25000) {
11
+ flags.push({ type: 'liquidity', severity: 'high', message: `Low liquidity: $${liquidity.toFixed(0)}` });
12
+ totalScore += 18;
13
+ }
14
+ else if (liquidity < 100000) {
15
+ flags.push({ type: 'liquidity', severity: 'medium', message: `Moderate liquidity: $${liquidity.toFixed(0)}` });
16
+ totalScore += 8;
17
+ }
18
+ // 2. Token age (10% weight)
19
+ if (pair?.pairCreatedAt) {
20
+ const ageMs = Date.now() - pair.pairCreatedAt;
21
+ const ageHours = ageMs / (1000 * 60 * 60);
22
+ if (ageHours < 1) {
23
+ flags.push({ type: 'age', severity: 'critical', message: `Token launched ${Math.round(ageHours * 60)}m ago` });
24
+ totalScore += 10;
25
+ }
26
+ else if (ageHours < 24) {
27
+ flags.push({ type: 'age', severity: 'high', message: `Token is ${Math.round(ageHours)}h old` });
28
+ totalScore += 6;
29
+ }
30
+ }
31
+ // Holder-based risks (only if we have GMGN data)
32
+ if (holders && holders.length > 0) {
33
+ // 3. Top holder concentration (20% weight)
34
+ const sorted = [...holders].sort((a, b) => b.supplyPercent - a.supplyPercent);
35
+ const top10Pct = sorted.slice(0, 10).reduce((s, h) => s + h.supplyPercent, 0);
36
+ if (top10Pct > 60) {
37
+ flags.push({ type: 'concentration', severity: 'critical', message: `Top 10 holders own ${(top10Pct * 100).toFixed(1)}%` });
38
+ totalScore += 20;
39
+ }
40
+ else if (top10Pct > 40) {
41
+ flags.push({ type: 'concentration', severity: 'high', message: `Top 10 holders own ${(top10Pct * 100).toFixed(1)}%` });
42
+ totalScore += 12;
43
+ }
44
+ else if (top10Pct > 25) {
45
+ flags.push({ type: 'concentration', severity: 'medium', message: `Top 10 holders own ${(top10Pct * 100).toFixed(1)}%` });
46
+ totalScore += 5;
47
+ }
48
+ // 4. Dev wallet (20% weight)
49
+ const dev = holders.find(h => h.isDeployer);
50
+ if (dev) {
51
+ if (dev.supplyPercent > 0.10) {
52
+ flags.push({ type: 'dev_wallet', severity: 'high', message: `Dev holds ${(dev.supplyPercent * 100).toFixed(1)}%` });
53
+ totalScore += 15;
54
+ }
55
+ else if (dev.sellAmount > dev.buyAmount * 0.5) {
56
+ flags.push({ type: 'dev_selling', severity: 'medium', message: 'Dev has been selling' });
57
+ totalScore += 8;
58
+ }
59
+ }
60
+ // 5. Fresh wallets (15% weight)
61
+ const freshCount = holders.filter(h => h.isFreshWallet).length;
62
+ const freshPct = freshCount / holders.length;
63
+ if (freshPct > 0.30) {
64
+ flags.push({ type: 'fresh_wallets', severity: 'high', message: `${(freshPct * 100).toFixed(0)}% fresh wallets (possible bundle/wash)` });
65
+ totalScore += 15;
66
+ }
67
+ else if (freshPct > 0.15) {
68
+ flags.push({ type: 'fresh_wallets', severity: 'medium', message: `${(freshPct * 100).toFixed(0)}% fresh wallets` });
69
+ totalScore += 7;
70
+ }
71
+ // 6. Sniper activity (10% weight)
72
+ const sniperCount = holders.filter(h => h.tags.some(t => t.toLowerCase().includes('sniper') || t.toLowerCase().includes('bot'))).length;
73
+ if (sniperCount > 5) {
74
+ flags.push({ type: 'snipers', severity: 'high', message: `${sniperCount} sniper/bot wallets detected` });
75
+ totalScore += 10;
76
+ }
77
+ else if (sniperCount > 2) {
78
+ flags.push({ type: 'snipers', severity: 'medium', message: `${sniperCount} sniper wallets detected` });
79
+ totalScore += 4;
80
+ }
81
+ }
82
+ else {
83
+ // No holder data — add uncertainty
84
+ totalScore += 15;
85
+ flags.push({ type: 'no_holder_data', severity: 'medium', message: 'Holder analysis unavailable (install Playwright for full analysis)' });
86
+ }
87
+ // Clamp to 0-100
88
+ totalScore = Math.min(100, Math.max(0, totalScore));
89
+ const level = totalScore >= 70 ? 'CRITICAL' : totalScore >= 45 ? 'HIGH' : totalScore >= 20 ? 'MEDIUM' : 'LOW';
90
+ const summaryParts = [];
91
+ if (level === 'CRITICAL')
92
+ summaryParts.push('Extreme risk');
93
+ else if (level === 'HIGH')
94
+ summaryParts.push('High risk');
95
+ else if (level === 'MEDIUM')
96
+ summaryParts.push('Moderate risk');
97
+ else
98
+ summaryParts.push('Lower risk');
99
+ if (flags.length > 0) {
100
+ summaryParts.push(flags.slice(0, 3).map(f => f.message).join('; '));
101
+ }
102
+ return { score: totalScore, level, flags, summary: summaryParts.join('. ') + '.' };
103
+ }
104
+ //# sourceMappingURL=riskScorer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"riskScorer.js","sourceRoot":"","sources":["../../src/analysis/riskScorer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * AI-like Summary Generator — code-generated, no API calls
3
+ * Produces human-readable analysis from raw data
4
+ */
5
+ interface SummaryInput {
6
+ token: {
7
+ symbol: string;
8
+ name: string;
9
+ age: string;
10
+ };
11
+ price: {
12
+ usd: number;
13
+ change1h: number;
14
+ change6h: number;
15
+ change24h: number;
16
+ change5m: number;
17
+ };
18
+ market: {
19
+ marketCap: number;
20
+ volume24h: number;
21
+ volume1h: number;
22
+ liquidity: number;
23
+ volumeLiquidityRatio: number;
24
+ dex: string;
25
+ };
26
+ risk: {
27
+ score: number;
28
+ level: string;
29
+ };
30
+ holders?: {
31
+ total: number;
32
+ concentration: {
33
+ top5Pct: number;
34
+ top10Pct: number;
35
+ top20Pct: number;
36
+ };
37
+ categories: Record<string, number>;
38
+ sentiment: {
39
+ profitableHolders: number;
40
+ losingHolders: number;
41
+ profitRatio: number;
42
+ totalPnlUsd: number;
43
+ avgPnlPerHolder: number;
44
+ };
45
+ pressure: {
46
+ buySellRatio: number;
47
+ totalBuyTx: number;
48
+ totalSellTx: number;
49
+ };
50
+ devWallet: {
51
+ status: string;
52
+ holdingPercent: number;
53
+ } | null;
54
+ };
55
+ kols?: {
56
+ twitterHandle: string | null;
57
+ status: string;
58
+ pnl: number;
59
+ }[];
60
+ security?: {
61
+ mintAuthority: string;
62
+ freezeAuthority: string;
63
+ isLpTopHolder: boolean;
64
+ realTopHolderPct: number;
65
+ };
66
+ }
67
+ export declare function generateSummary(data: SummaryInput): string;
68
+ export {};