@0xprotovox/deficlaw 0.1.1 → 0.3.0
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.
- package/README.md +115 -41
- package/dist/analysis/formatOutput.d.ts +113 -2
- package/dist/analysis/formatOutput.js +135 -100
- package/dist/analysis/formatOutput.js.map +1 -1
- package/dist/analysis/riskScorer.d.ts +24 -2
- package/dist/analysis/riskScorer.js +146 -48
- package/dist/analysis/riskScorer.js.map +1 -1
- package/dist/analysis/summaryGenerator.d.ts +3 -2
- package/dist/analysis/summaryGenerator.js +204 -42
- package/dist/analysis/summaryGenerator.js.map +1 -1
- package/dist/cache/memoryCache.d.ts +12 -3
- package/dist/cache/memoryCache.js +43 -2
- package/dist/cache/memoryCache.js.map +1 -1
- package/dist/server.d.ts +3 -2
- package/dist/server.js +66 -16
- package/dist/server.js.map +1 -1
- package/dist/sources/dexscreener.d.ts +8 -17
- package/dist/sources/dexscreener.js +123 -29
- package/dist/sources/dexscreener.js.map +1 -1
- package/dist/sources/gmgn.d.ts +11 -4
- package/dist/sources/gmgn.js +207 -115
- package/dist/sources/gmgn.js.map +1 -1
- package/dist/sources/solanaRpc.d.ts +4 -4
- package/dist/sources/solanaRpc.js +60 -29
- package/dist/sources/solanaRpc.js.map +1 -1
- package/dist/tools/analyzeToken.d.ts +1 -2
- package/dist/tools/analyzeToken.js +114 -100
- package/dist/tools/analyzeToken.js.map +1 -1
- package/dist/tools/getNewLaunches.d.ts +30 -0
- package/dist/tools/getNewLaunches.js +63 -0
- package/dist/tools/getNewLaunches.js.map +1 -0
- package/dist/tools/getPrice.d.ts +2 -12
- package/dist/tools/getPrice.js +23 -4
- package/dist/tools/getPrice.js.map +1 -1
- package/dist/tools/getTopTraders.d.ts +30 -24
- package/dist/tools/getTopTraders.js +36 -21
- package/dist/tools/getTopTraders.js.map +1 -1
- package/dist/tools/getTrending.d.ts +8 -1
- package/dist/tools/getTrending.js +12 -2
- package/dist/tools/getTrending.js.map +1 -1
- package/dist/tools/searchToken.d.ts +24 -0
- package/dist/tools/searchToken.js +43 -0
- package/dist/tools/searchToken.js.map +1 -0
- package/dist/types/index.d.ts +34 -0
- package/dist/utils/debug.d.ts +7 -0
- package/dist/utils/debug.js +27 -0
- package/dist/utils/debug.js.map +1 -0
- package/package.json +18 -2
package/dist/server.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* DeFi MCP Server
|
|
3
|
-
* First open-source DeFi MCP for Claude Code
|
|
2
|
+
* DeFi MCP Server — deficlaw
|
|
3
|
+
* First open-source DeFi MCP for Claude Code.
|
|
4
|
+
* Token analysis, prices, trending, top traders.
|
|
4
5
|
* by @0xprotovox
|
|
5
6
|
*/
|
|
6
7
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
@@ -9,66 +10,115 @@ import { handleAnalyzeToken } from './tools/analyzeToken.js';
|
|
|
9
10
|
import { handleGetPrice } from './tools/getPrice.js';
|
|
10
11
|
import { handleGetTrending } from './tools/getTrending.js';
|
|
11
12
|
import { handleGetTopTraders } from './tools/getTopTraders.js';
|
|
13
|
+
import { handleSearchToken } from './tools/searchToken.js';
|
|
14
|
+
import { handleGetNewLaunches } from './tools/getNewLaunches.js';
|
|
12
15
|
import { formatAnalysis } from './analysis/formatOutput.js';
|
|
13
16
|
export function createServer() {
|
|
14
17
|
const server = new McpServer({
|
|
15
18
|
name: 'deficlaw',
|
|
16
|
-
version: '0.
|
|
19
|
+
version: '0.3.0',
|
|
17
20
|
});
|
|
18
21
|
// ── analyze_token ──
|
|
19
22
|
server.tool('analyze_token', 'Full token analysis: price, volume, liquidity, holder intelligence, risk scoring. Supports Solana tokens with GMGN holder data.', {
|
|
20
|
-
address: z.string().describe('Token contract address (e.g. Solana mint address)'),
|
|
23
|
+
address: z.string().min(1).describe('Token contract address (e.g. Solana mint address)'),
|
|
21
24
|
chain: z.string().default('solana').describe('Blockchain: solana, ethereum, bsc, base, arbitrum'),
|
|
22
|
-
include_holders: z.boolean().default(true).describe('Include GMGN holder analysis (slower, needs Playwright)'),
|
|
25
|
+
include_holders: z.boolean().default(true).describe('Include GMGN holder analysis (slower, needs curl or Playwright)'),
|
|
23
26
|
}, async (args) => {
|
|
24
27
|
try {
|
|
25
28
|
const result = await handleAnalyzeToken(args);
|
|
26
|
-
if ('error' in result)
|
|
29
|
+
if ('error' in result && typeof result.error === 'string') {
|
|
27
30
|
return { content: [{ type: 'text', text: JSON.stringify(result) }], isError: true };
|
|
31
|
+
}
|
|
28
32
|
const formatted = formatAnalysis(result);
|
|
29
33
|
return { content: [{ type: 'text', text: formatted }] };
|
|
30
34
|
}
|
|
31
35
|
catch (err) {
|
|
32
|
-
|
|
36
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
37
|
+
return { content: [{ type: 'text', text: JSON.stringify({ error: `Analysis failed: ${message}` }) }], isError: true };
|
|
33
38
|
}
|
|
34
39
|
});
|
|
35
40
|
// ── get_price ──
|
|
36
41
|
server.tool('get_price', 'Quick token price lookup with 24h change, volume, liquidity, and market cap.', {
|
|
37
|
-
token: z.string().describe('Token address or search query'),
|
|
42
|
+
token: z.string().min(1).describe('Token address or search query (symbol/name)'),
|
|
38
43
|
chain: z.string().default('solana').describe('Blockchain: solana, ethereum, bsc, base, arbitrum'),
|
|
39
44
|
}, async (args) => {
|
|
40
45
|
try {
|
|
41
46
|
const result = await handleGetPrice(args);
|
|
42
|
-
return {
|
|
47
|
+
return {
|
|
48
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
49
|
+
...('error' in result ? { isError: true } : {}),
|
|
50
|
+
};
|
|
43
51
|
}
|
|
44
52
|
catch (err) {
|
|
45
|
-
|
|
53
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
54
|
+
return { content: [{ type: 'text', text: JSON.stringify({ error: `Price lookup failed: ${message}` }) }], isError: true };
|
|
46
55
|
}
|
|
47
56
|
});
|
|
48
57
|
// ── get_trending ──
|
|
49
58
|
server.tool('get_trending', 'Get trending/boosted tokens on a blockchain. Returns top tokens by volume and boost activity.', {
|
|
50
59
|
chain: z.string().default('solana').describe('Blockchain: solana, ethereum, bsc, base, arbitrum'),
|
|
51
|
-
limit: z.number().default(20).describe('Number of tokens to return (
|
|
60
|
+
limit: z.number().min(1).max(50).default(20).describe('Number of tokens to return (1-50)'),
|
|
52
61
|
}, async (args) => {
|
|
53
62
|
try {
|
|
54
63
|
const result = await handleGetTrending(args);
|
|
55
64
|
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
56
65
|
}
|
|
57
66
|
catch (err) {
|
|
58
|
-
|
|
67
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
68
|
+
return { content: [{ type: 'text', text: JSON.stringify({ error: `Trending fetch failed: ${message}` }) }], isError: true };
|
|
59
69
|
}
|
|
60
70
|
});
|
|
61
71
|
// ── get_top_traders ──
|
|
62
72
|
server.tool('get_top_traders', 'Find who made and lost money on a token. Shows top winners and losers with PnL, tags, and Twitter handles.', {
|
|
63
|
-
address: z.string().describe('Token contract address'),
|
|
64
|
-
limit: z.number().default(10).describe('Number of top winners/losers to show'),
|
|
73
|
+
address: z.string().min(1).describe('Token contract address'),
|
|
74
|
+
limit: z.number().min(1).max(50).default(10).describe('Number of top winners/losers to show (1-50)'),
|
|
65
75
|
}, async (args) => {
|
|
66
76
|
try {
|
|
67
77
|
const result = await handleGetTopTraders(args);
|
|
68
|
-
return {
|
|
78
|
+
return {
|
|
79
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
80
|
+
...('error' in result ? { isError: true } : {}),
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
catch (err) {
|
|
84
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
85
|
+
return { content: [{ type: 'text', text: JSON.stringify({ error: `Top traders fetch failed: ${message}` }) }], isError: true };
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
// ── search_token ──
|
|
89
|
+
server.tool('search_token', 'Search for tokens by name or symbol. Returns top matches with address, price, chain, volume, and liquidity.', {
|
|
90
|
+
query: z.string().min(1).describe('Token name or symbol to search for (e.g. "BONK", "Jupiter")'),
|
|
91
|
+
chain: z.string().optional().describe('Filter by blockchain: solana, ethereum, bsc, base, arbitrum. Omit for all chains.'),
|
|
92
|
+
limit: z.number().min(1).max(20).default(10).describe('Number of results to return (1-20)'),
|
|
93
|
+
}, async (args) => {
|
|
94
|
+
try {
|
|
95
|
+
const result = await handleSearchToken(args);
|
|
96
|
+
return {
|
|
97
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
98
|
+
...('error' in result ? { isError: true } : {}),
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
catch (err) {
|
|
102
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
103
|
+
return { content: [{ type: 'text', text: JSON.stringify({ error: `Token search failed: ${message}` }) }], isError: true };
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
// ── get_new_launches ──
|
|
107
|
+
server.tool('get_new_launches', 'Get recently created tokens on a blockchain. Shows name, symbol, address, age, market cap, liquidity, and volume.', {
|
|
108
|
+
chain: z.string().default('solana').describe('Blockchain: solana, ethereum, bsc, base, arbitrum'),
|
|
109
|
+
max_age_minutes: z.number().min(5).max(1440).default(60).describe('Maximum token age in minutes (5-1440)'),
|
|
110
|
+
limit: z.number().min(1).max(50).default(20).describe('Number of tokens to return (1-50)'),
|
|
111
|
+
}, async (args) => {
|
|
112
|
+
try {
|
|
113
|
+
const result = await handleGetNewLaunches(args);
|
|
114
|
+
return {
|
|
115
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
116
|
+
...('error' in result ? { isError: true } : {}),
|
|
117
|
+
};
|
|
69
118
|
}
|
|
70
119
|
catch (err) {
|
|
71
|
-
|
|
120
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
121
|
+
return { content: [{ type: 'text', text: JSON.stringify({ error: `New launches fetch failed: ${message}` }) }], isError: true };
|
|
72
122
|
}
|
|
73
123
|
});
|
|
74
124
|
return server;
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,20 +1,11 @@
|
|
|
1
|
-
import type { DexPair } from '../types/index.js';
|
|
2
|
-
/** Get best pair for a token address (highest liquidity) */
|
|
1
|
+
import type { DexPair, PriceResult, TrendingToken } from '../types/index.js';
|
|
2
|
+
/** Get best pair for a token address (highest liquidity on the target chain) */
|
|
3
3
|
export declare function getTokenPair(address: string, chain?: string): Promise<DexPair | null>;
|
|
4
|
-
/** Quick price lookup */
|
|
5
|
-
export declare function getPrice(address: string, chain?: string): Promise<
|
|
6
|
-
address: string;
|
|
7
|
-
symbol: string;
|
|
8
|
-
name: string;
|
|
9
|
-
priceUsd: number;
|
|
10
|
-
priceChange1h: number;
|
|
11
|
-
priceChange24h: number;
|
|
12
|
-
volume24h: number;
|
|
13
|
-
liquidity: number;
|
|
14
|
-
marketCap: number;
|
|
15
|
-
dex: string;
|
|
16
|
-
} | null>;
|
|
4
|
+
/** Quick price lookup — returns null if token not found */
|
|
5
|
+
export declare function getPrice(address: string, chain?: string): Promise<PriceResult | null>;
|
|
17
6
|
/** Search tokens by name or symbol */
|
|
18
7
|
export declare function searchTokens(query: string): Promise<DexPair[]>;
|
|
19
|
-
/** Get
|
|
20
|
-
export declare function
|
|
8
|
+
/** Get recently created token pairs on a chain, sorted by creation time desc */
|
|
9
|
+
export declare function getNewPairs(chain?: string, maxAgeMinutes?: number, limit?: number): Promise<DexPair[]>;
|
|
10
|
+
/** Get trending/boosted tokens. Enriches with price data in parallel. */
|
|
11
|
+
export declare function getTrending(chain?: string, limit?: number): Promise<(TrendingToken & Partial<PriceResult>)[]>;
|
|
@@ -1,66 +1,115 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* DexScreener API Client
|
|
3
|
-
*
|
|
4
|
-
*
|
|
3
|
+
* Free API, no auth needed. Rate limit: ~300 req/min (we cap at ~150).
|
|
4
|
+
* All fetches have timeouts, retries on transient errors, and proper error handling.
|
|
5
5
|
*/
|
|
6
6
|
import { MemoryCache } from '../cache/memoryCache.js';
|
|
7
|
+
import { debug } from '../utils/debug.js';
|
|
7
8
|
const BASE_URL = 'https://api.dexscreener.com';
|
|
8
9
|
const PAIR_CACHE_TTL = 5 * 60 * 1000; // 5 min
|
|
9
|
-
const PRICE_CACHE_TTL = 30 * 1000;
|
|
10
|
+
const PRICE_CACHE_TTL = parseInt(process.env.DEFICLAW_PRICE_CACHE_TTL ?? '', 10) || 30 * 1000;
|
|
10
11
|
const TRENDING_CACHE_TTL = 30 * 1000; // 30s
|
|
12
|
+
const MAX_RETRIES = 2;
|
|
11
13
|
// Simple rate limiter — sequential queue with min interval
|
|
12
14
|
let lastRequestMs = 0;
|
|
13
15
|
const MIN_INTERVAL = 200; // 200ms between requests
|
|
16
|
+
/**
|
|
17
|
+
* Fetch with rate limiting, timeout, and retry for transient failures.
|
|
18
|
+
* Returns parsed JSON on success; throws on permanent failures.
|
|
19
|
+
*/
|
|
14
20
|
async function throttledFetch(url, timeoutMs = 8000) {
|
|
15
21
|
const now = Date.now();
|
|
16
22
|
const wait = MIN_INTERVAL - (now - lastRequestMs);
|
|
17
23
|
if (wait > 0)
|
|
18
24
|
await new Promise(r => setTimeout(r, wait));
|
|
19
25
|
lastRequestMs = Date.now();
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
26
|
+
let lastError = null;
|
|
27
|
+
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
28
|
+
try {
|
|
29
|
+
const res = await fetch(url, { signal: AbortSignal.timeout(timeoutMs) });
|
|
30
|
+
if (res.status === 429) {
|
|
31
|
+
// Rate limited — wait and retry
|
|
32
|
+
const retryAfter = Math.min(parseInt(res.headers.get('retry-after') || '2', 10) * 1000, 10000);
|
|
33
|
+
await new Promise(r => setTimeout(r, retryAfter));
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
if (res.status >= 500 && attempt < MAX_RETRIES) {
|
|
37
|
+
// Server error — brief pause and retry
|
|
38
|
+
await new Promise(r => setTimeout(r, 1000 * (attempt + 1)));
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
if (!res.ok) {
|
|
42
|
+
throw new Error(`DexScreener HTTP ${res.status}: ${res.statusText} (${url})`);
|
|
43
|
+
}
|
|
44
|
+
return await res.json();
|
|
45
|
+
}
|
|
46
|
+
catch (err) {
|
|
47
|
+
lastError = err instanceof Error ? err : new Error(String(err));
|
|
48
|
+
if (err instanceof TypeError && attempt < MAX_RETRIES) {
|
|
49
|
+
// Network error (DNS, connection refused, etc.) — retry
|
|
50
|
+
await new Promise(r => setTimeout(r, 1000 * (attempt + 1)));
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
if (lastError.name === 'TimeoutError' && attempt < MAX_RETRIES) {
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
throw lastError;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
throw lastError ?? new Error(`DexScreener request failed after ${MAX_RETRIES + 1} attempts`);
|
|
24
60
|
}
|
|
25
61
|
const pairCache = new MemoryCache(PAIR_CACHE_TTL);
|
|
26
62
|
const priceCache = new MemoryCache(PRICE_CACHE_TTL);
|
|
27
63
|
const trendingCache = new MemoryCache(TRENDING_CACHE_TTL);
|
|
28
|
-
/** Get best pair for a token address (highest liquidity) */
|
|
64
|
+
/** Get best pair for a token address (highest liquidity on the target chain) */
|
|
29
65
|
export async function getTokenPair(address, chain = 'solana') {
|
|
66
|
+
if (!address || address.trim().length === 0)
|
|
67
|
+
return null;
|
|
30
68
|
const cacheKey = `${chain}:${address}`;
|
|
31
69
|
const cached = pairCache.get(cacheKey);
|
|
32
|
-
if (cached)
|
|
70
|
+
if (cached) {
|
|
71
|
+
debug(`pair cache HIT: ${cacheKey}`);
|
|
33
72
|
return cached;
|
|
73
|
+
}
|
|
74
|
+
debug(`pair cache MISS: ${cacheKey}`);
|
|
34
75
|
const data = await throttledFetch(`${BASE_URL}/latest/dex/tokens/${address}`);
|
|
35
|
-
const pairs = data.pairs
|
|
76
|
+
const pairs = data.pairs ?? [];
|
|
77
|
+
if (pairs.length === 0)
|
|
78
|
+
return null;
|
|
36
79
|
// Filter by chain and sort by liquidity
|
|
37
80
|
const chainPairs = pairs
|
|
38
81
|
.filter(p => p.chainId === chain)
|
|
39
|
-
.sort((a, b) => (b.liquidity?.usd
|
|
40
|
-
const best = chainPairs[0]
|
|
82
|
+
.sort((a, b) => (b.liquidity?.usd ?? 0) - (a.liquidity?.usd ?? 0));
|
|
83
|
+
const best = chainPairs[0] ?? pairs[0] ?? null;
|
|
41
84
|
if (best)
|
|
42
85
|
pairCache.set(cacheKey, best);
|
|
43
86
|
return best;
|
|
44
87
|
}
|
|
45
|
-
/** Quick price lookup */
|
|
88
|
+
/** Quick price lookup — returns null if token not found */
|
|
46
89
|
export async function getPrice(address, chain = 'solana') {
|
|
90
|
+
if (!address || address.trim().length === 0)
|
|
91
|
+
return null;
|
|
47
92
|
const cacheKey = `price:${chain}:${address}`;
|
|
48
93
|
const cached = priceCache.get(cacheKey);
|
|
49
|
-
if (cached)
|
|
94
|
+
if (cached) {
|
|
95
|
+
debug(`price cache HIT: ${cacheKey}`);
|
|
50
96
|
return cached;
|
|
97
|
+
}
|
|
98
|
+
debug(`price cache MISS: ${cacheKey}`);
|
|
51
99
|
const pair = await getTokenPair(address, chain);
|
|
52
100
|
if (!pair)
|
|
53
101
|
return null;
|
|
102
|
+
const priceUsd = parseFloat(pair.priceUsd);
|
|
54
103
|
const result = {
|
|
55
104
|
address: pair.baseToken.address,
|
|
56
105
|
symbol: pair.baseToken.symbol,
|
|
57
106
|
name: pair.baseToken.name,
|
|
58
|
-
priceUsd:
|
|
59
|
-
priceChange1h: pair.priceChange?.h1
|
|
60
|
-
priceChange24h: pair.priceChange?.h24
|
|
61
|
-
volume24h: pair.volume?.h24
|
|
62
|
-
liquidity: pair.liquidity?.usd
|
|
63
|
-
marketCap: pair.marketCap
|
|
107
|
+
priceUsd: isNaN(priceUsd) ? 0 : priceUsd,
|
|
108
|
+
priceChange1h: pair.priceChange?.h1 ?? 0,
|
|
109
|
+
priceChange24h: pair.priceChange?.h24 ?? 0,
|
|
110
|
+
volume24h: pair.volume?.h24 ?? 0,
|
|
111
|
+
liquidity: pair.liquidity?.usd ?? 0,
|
|
112
|
+
marketCap: pair.marketCap ?? 0,
|
|
64
113
|
dex: pair.dexId,
|
|
65
114
|
};
|
|
66
115
|
priceCache.set(cacheKey, result);
|
|
@@ -68,22 +117,67 @@ export async function getPrice(address, chain = 'solana') {
|
|
|
68
117
|
}
|
|
69
118
|
/** Search tokens by name or symbol */
|
|
70
119
|
export async function searchTokens(query) {
|
|
120
|
+
if (!query || query.trim().length === 0)
|
|
121
|
+
return [];
|
|
71
122
|
const data = await throttledFetch(`${BASE_URL}/latest/dex/search?q=${encodeURIComponent(query)}`);
|
|
72
|
-
return (data.pairs
|
|
123
|
+
return (data.pairs ?? []).slice(0, 20);
|
|
124
|
+
}
|
|
125
|
+
/** Get recently created token pairs on a chain, sorted by creation time desc */
|
|
126
|
+
export async function getNewPairs(chain = 'solana', maxAgeMinutes = 60, limit = 20) {
|
|
127
|
+
const clampedLimit = Math.min(Math.max(1, limit), 50);
|
|
128
|
+
const cacheKey = `newpairs:${chain}:${maxAgeMinutes}`;
|
|
129
|
+
const cached = trendingCache.get(cacheKey);
|
|
130
|
+
if (cached) {
|
|
131
|
+
debug(`newpairs cache HIT: ${cacheKey}`);
|
|
132
|
+
return cached.slice(0, clampedLimit);
|
|
133
|
+
}
|
|
134
|
+
debug(`Fetching new pairs for ${chain} (max age ${maxAgeMinutes}m)`);
|
|
135
|
+
// Use DexScreener token profiles + latest boosts to find new tokens
|
|
136
|
+
// Then filter by creation time
|
|
137
|
+
const data = await throttledFetch(`${BASE_URL}/token-profiles/latest/v1`).catch(() => []);
|
|
138
|
+
const raw = Array.isArray(data) ? data : [];
|
|
139
|
+
const now = Date.now();
|
|
140
|
+
const maxAgeMs = maxAgeMinutes * 60 * 1000;
|
|
141
|
+
const chainTokens = raw
|
|
142
|
+
.filter(t => t.chainId === chain && t.tokenAddress)
|
|
143
|
+
.slice(0, clampedLimit * 2); // fetch extra in case some don't have pairs
|
|
144
|
+
// Fetch pair data in parallel for each token
|
|
145
|
+
const pairsResults = await Promise.all(chainTokens.map(async (t) => {
|
|
146
|
+
try {
|
|
147
|
+
const pair = await getTokenPair(t.tokenAddress, chain);
|
|
148
|
+
if (!pair)
|
|
149
|
+
return null;
|
|
150
|
+
// Filter by age
|
|
151
|
+
if (pair.pairCreatedAt && (now - pair.pairCreatedAt) > maxAgeMs)
|
|
152
|
+
return null;
|
|
153
|
+
return pair;
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
}));
|
|
159
|
+
const validPairs = pairsResults
|
|
160
|
+
.filter((p) => p !== null)
|
|
161
|
+
.sort((a, b) => (b.pairCreatedAt ?? 0) - (a.pairCreatedAt ?? 0))
|
|
162
|
+
.slice(0, clampedLimit);
|
|
163
|
+
debug(`Found ${validPairs.length} new pairs on ${chain}`);
|
|
164
|
+
return validPairs;
|
|
73
165
|
}
|
|
74
|
-
/** Get trending/boosted tokens */
|
|
166
|
+
/** Get trending/boosted tokens. Enriches with price data in parallel. */
|
|
75
167
|
export async function getTrending(chain = 'solana', limit = 20) {
|
|
168
|
+
const clampedLimit = Math.min(Math.max(1, limit), 50);
|
|
76
169
|
const cacheKey = `trending:${chain}`;
|
|
77
170
|
const cached = trendingCache.get(cacheKey);
|
|
78
171
|
if (cached)
|
|
79
|
-
return cached.slice(0,
|
|
172
|
+
return cached.slice(0, clampedLimit);
|
|
173
|
+
// Fetch both boost endpoints in parallel — catch individually so one failure doesn't block the other
|
|
80
174
|
const [topData, latestData] = await Promise.all([
|
|
81
175
|
throttledFetch(`${BASE_URL}/token-boosts/top/v1`).catch(() => []),
|
|
82
176
|
throttledFetch(`${BASE_URL}/token-boosts/latest/v1`).catch(() => []),
|
|
83
177
|
]);
|
|
84
178
|
const top = Array.isArray(topData) ? topData : [];
|
|
85
179
|
const latest = Array.isArray(latestData) ? latestData : [];
|
|
86
|
-
// Merge and deduplicate
|
|
180
|
+
// Merge and deduplicate by address
|
|
87
181
|
const seen = new Set();
|
|
88
182
|
const merged = [];
|
|
89
183
|
for (const token of [...top, ...latest]) {
|
|
@@ -97,21 +191,21 @@ export async function getTrending(chain = 'solana', limit = 20) {
|
|
|
97
191
|
symbol: token.description?.split('/')[0] || token.tokenAddress.slice(0, 6),
|
|
98
192
|
name: token.description || '',
|
|
99
193
|
chainId: token.chainId,
|
|
100
|
-
url: token.url,
|
|
194
|
+
url: token.url || '',
|
|
101
195
|
boostAmount: token.totalAmount || 0,
|
|
102
196
|
});
|
|
103
197
|
}
|
|
104
|
-
// Enrich top items with price data
|
|
105
|
-
const enriched = await Promise.all(merged.slice(0,
|
|
198
|
+
// Enrich top items with price data — all in parallel
|
|
199
|
+
const enriched = await Promise.all(merged.slice(0, clampedLimit).map(async (t) => {
|
|
106
200
|
try {
|
|
107
201
|
const price = await getPrice(t.address, chain);
|
|
108
|
-
return { ...t, ...price };
|
|
202
|
+
return price ? { ...t, ...price } : t;
|
|
109
203
|
}
|
|
110
204
|
catch {
|
|
111
205
|
return t;
|
|
112
206
|
}
|
|
113
207
|
}));
|
|
114
208
|
trendingCache.set(cacheKey, enriched);
|
|
115
|
-
return enriched.slice(0,
|
|
209
|
+
return enriched.slice(0, clampedLimit);
|
|
116
210
|
}
|
|
117
211
|
//# sourceMappingURL=dexscreener.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dexscreener.js","sourceRoot":"","sources":["../../src/sources/dexscreener.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"dexscreener.js","sourceRoot":"","sources":["../../src/sources/dexscreener.ts"],"names":[],"mappings":"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"}
|
package/dist/sources/gmgn.d.ts
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
import type { Holder } from '../types/index.js';
|
|
2
|
-
|
|
3
|
-
/** Get holders — try curl first, then Playwright */
|
|
4
|
-
export declare function getHolders(address: string): Promise<{
|
|
2
|
+
interface HolderResult {
|
|
5
3
|
holders: Holder[];
|
|
6
4
|
kolHolders: Holder[];
|
|
7
|
-
}
|
|
5
|
+
}
|
|
6
|
+
/** Returns true — curl fallback is always available, Playwright is optional */
|
|
7
|
+
export declare function isPlaywrightAvailable(): Promise<boolean>;
|
|
8
|
+
/**
|
|
9
|
+
* Get holders for a Solana token.
|
|
10
|
+
* Strategy: try curl first (fast, ~1s), fall back to Playwright (~11s).
|
|
11
|
+
*/
|
|
12
|
+
export declare function getHolders(address: string): Promise<HolderResult>;
|
|
13
|
+
/** Gracefully shut down the Playwright browser */
|
|
8
14
|
export declare function shutdown(): Promise<void>;
|
|
15
|
+
export {};
|