@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.
Files changed (48) hide show
  1. package/README.md +115 -41
  2. package/dist/analysis/formatOutput.d.ts +113 -2
  3. package/dist/analysis/formatOutput.js +135 -100
  4. package/dist/analysis/formatOutput.js.map +1 -1
  5. package/dist/analysis/riskScorer.d.ts +24 -2
  6. package/dist/analysis/riskScorer.js +146 -48
  7. package/dist/analysis/riskScorer.js.map +1 -1
  8. package/dist/analysis/summaryGenerator.d.ts +3 -2
  9. package/dist/analysis/summaryGenerator.js +204 -42
  10. package/dist/analysis/summaryGenerator.js.map +1 -1
  11. package/dist/cache/memoryCache.d.ts +12 -3
  12. package/dist/cache/memoryCache.js +43 -2
  13. package/dist/cache/memoryCache.js.map +1 -1
  14. package/dist/server.d.ts +3 -2
  15. package/dist/server.js +66 -16
  16. package/dist/server.js.map +1 -1
  17. package/dist/sources/dexscreener.d.ts +8 -17
  18. package/dist/sources/dexscreener.js +123 -29
  19. package/dist/sources/dexscreener.js.map +1 -1
  20. package/dist/sources/gmgn.d.ts +11 -4
  21. package/dist/sources/gmgn.js +207 -115
  22. package/dist/sources/gmgn.js.map +1 -1
  23. package/dist/sources/solanaRpc.d.ts +4 -4
  24. package/dist/sources/solanaRpc.js +60 -29
  25. package/dist/sources/solanaRpc.js.map +1 -1
  26. package/dist/tools/analyzeToken.d.ts +1 -2
  27. package/dist/tools/analyzeToken.js +114 -100
  28. package/dist/tools/analyzeToken.js.map +1 -1
  29. package/dist/tools/getNewLaunches.d.ts +30 -0
  30. package/dist/tools/getNewLaunches.js +63 -0
  31. package/dist/tools/getNewLaunches.js.map +1 -0
  32. package/dist/tools/getPrice.d.ts +2 -12
  33. package/dist/tools/getPrice.js +23 -4
  34. package/dist/tools/getPrice.js.map +1 -1
  35. package/dist/tools/getTopTraders.d.ts +30 -24
  36. package/dist/tools/getTopTraders.js +36 -21
  37. package/dist/tools/getTopTraders.js.map +1 -1
  38. package/dist/tools/getTrending.d.ts +8 -1
  39. package/dist/tools/getTrending.js +12 -2
  40. package/dist/tools/getTrending.js.map +1 -1
  41. package/dist/tools/searchToken.d.ts +24 -0
  42. package/dist/tools/searchToken.js +43 -0
  43. package/dist/tools/searchToken.js.map +1 -0
  44. package/dist/types/index.d.ts +34 -0
  45. package/dist/utils/debug.d.ts +7 -0
  46. package/dist/utils/debug.js +27 -0
  47. package/dist/utils/debug.js.map +1 -0
  48. package/package.json +18 -2
@@ -1,22 +1,10 @@
1
1
  /**
2
- * get_top_traders tool — Who made/lost money on a token
3
- * Uses GMGN holder data already collected by analyze_token
2
+ * get_top_traders tool — Who made/lost money on a token.
3
+ * Uses GMGN holder data to rank traders by PnL.
4
4
  */
5
5
  import * as gmgn from '../sources/gmgn.js';
6
- export async function handleGetTopTraders(args) {
7
- const limit = args.limit || 10;
8
- if (!(await gmgn.isPlaywrightAvailable())) {
9
- return { error: 'Playwright not installed. Run: npm install playwright && npx playwright install chromium' };
10
- }
11
- const { holders } = await gmgn.getHolders(args.address);
12
- if (holders.length === 0)
13
- return { error: 'No holder data found' };
14
- const withPnl = holders.filter(h => h.totalPnl !== 0);
15
- const winners = [...withPnl].sort((a, b) => b.totalPnl - a.totalPnl).slice(0, limit);
16
- const losers = [...withPnl].sort((a, b) => a.totalPnl - b.totalPnl).slice(0, limit);
17
- const totalProfit = withPnl.filter(h => h.totalPnl > 0).reduce((s, h) => s + h.totalPnl, 0);
18
- const totalLoss = withPnl.filter(h => h.totalPnl < 0).reduce((s, h) => s + h.totalPnl, 0);
19
- const format = (h) => ({
6
+ function formatTrader(h) {
7
+ return {
20
8
  address: h.address,
21
9
  pnl: Math.round(h.totalPnl * 100) / 100,
22
10
  profitMultiple: Math.round(h.profitMultiple * 100) / 100,
@@ -27,18 +15,45 @@ export async function handleGetTopTraders(args) {
27
15
  stillHolding: h.balance > 0,
28
16
  isDeployer: h.isDeployer,
29
17
  isDiamondHands: h.tags.some(t => /diamond/i.test(t)),
30
- });
18
+ };
19
+ }
20
+ export async function handleGetTopTraders(args) {
21
+ if (!args.address || args.address.trim().length === 0) {
22
+ return { error: 'Token address is required' };
23
+ }
24
+ const limit = Math.min(Math.max(1, args.limit || 10), 50);
25
+ const { holders } = await gmgn.getHolders(args.address);
26
+ if (holders.length === 0) {
27
+ return { error: `No holder data found for ${args.address}. The token may not be indexed by GMGN.` };
28
+ }
29
+ const withPnl = holders.filter(h => h.totalPnl !== 0);
30
+ if (withPnl.length === 0) {
31
+ return {
32
+ token: args.address,
33
+ totalHoldersAnalyzed: holders.length,
34
+ note: 'No PnL data available for any holders. All holders may have entered at the same price.',
35
+ profitSummary: { totalProfit: 0, totalLoss: 0, profitableCount: 0, losingCount: 0 },
36
+ topWinners: [],
37
+ topLosers: [],
38
+ };
39
+ }
40
+ const winners = [...withPnl].sort((a, b) => b.totalPnl - a.totalPnl).slice(0, limit);
41
+ const losers = [...withPnl].sort((a, b) => a.totalPnl - b.totalPnl).slice(0, limit);
42
+ const profitable = withPnl.filter(h => h.totalPnl > 0);
43
+ const losing = withPnl.filter(h => h.totalPnl < 0);
44
+ const totalProfit = profitable.reduce((s, h) => s + h.totalPnl, 0);
45
+ const totalLoss = losing.reduce((s, h) => s + h.totalPnl, 0);
31
46
  return {
32
47
  token: args.address,
33
48
  totalHoldersAnalyzed: holders.length,
34
49
  profitSummary: {
35
50
  totalProfit: Math.round(totalProfit),
36
51
  totalLoss: Math.round(totalLoss),
37
- profitableCount: withPnl.filter(h => h.totalPnl > 0).length,
38
- losingCount: withPnl.filter(h => h.totalPnl < 0).length,
52
+ profitableCount: profitable.length,
53
+ losingCount: losing.length,
39
54
  },
40
- topWinners: winners.map(format),
41
- topLosers: losers.map(format),
55
+ topWinners: winners.map(formatTrader),
56
+ topLosers: losers.map(formatTrader),
42
57
  };
43
58
  }
44
59
  //# sourceMappingURL=getTopTraders.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"getTopTraders.js","sourceRoot":"","sources":["../../src/tools/getTopTraders.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,IAAI,MAAM,oBAAoB,CAAC;AAE3C,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,IAAyC;IACjF,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;IAE/B,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,qBAAqB,EAAE,CAAC,EAAE,CAAC;QAC1C,OAAO,EAAE,KAAK,EAAE,0FAA0F,EAAE,CAAC;IAC/G,CAAC;IAED,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACxD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,KAAK,EAAE,sBAAsB,EAAE,CAAC;IAEnE,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,CAAC;IACtD,MAAM,OAAO,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IACrF,MAAM,MAAM,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IAEpF,MAAM,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;IAC5F,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;IAE1F,MAAM,MAAM,GAAG,CAAC,CAAoB,EAAE,EAAE,CAAC,CAAC;QACxC,OAAO,EAAE,CAAC,CAAC,OAAO;QAClB,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,GAAG,GAAG,CAAC,GAAG,GAAG;QACvC,cAAc,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,cAAc,GAAG,GAAG,CAAC,GAAG,GAAG;QACxD,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,aAAa,EAAE,CAAC,CAAC,aAAa;QAC9B,KAAK,EAAE,CAAC,CAAC,UAAU;QACnB,MAAM,EAAE,CAAC,CAAC,WAAW;QACrB,YAAY,EAAE,CAAC,CAAC,OAAO,GAAG,CAAC;QAC3B,UAAU,EAAE,CAAC,CAAC,UAAU;QACxB,cAAc,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;KACrD,CAAC,CAAC;IAEH,OAAO;QACL,KAAK,EAAE,IAAI,CAAC,OAAO;QACnB,oBAAoB,EAAE,OAAO,CAAC,MAAM;QACpC,aAAa,EAAE;YACb,WAAW,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC;YACpC,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC;YAChC,eAAe,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,MAAM;YAC3D,WAAW,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,MAAM;SACxD;QACD,UAAU,EAAE,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC;QAC/B,SAAS,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC;KAC9B,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"getTopTraders.js","sourceRoot":"","sources":["../../src/tools/getTopTraders.ts"],"names":[],"mappings":"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"}
@@ -4,6 +4,13 @@ export declare function handleGetTrending(args: {
4
4
  }): Promise<{
5
5
  chain: string;
6
6
  count: number;
7
- tokens: any[];
7
+ tokens: never[];
8
+ note: string;
8
9
  fetchedAt: string;
10
+ } | {
11
+ chain: string;
12
+ count: number;
13
+ tokens: (import("../types/index.js").TrendingToken & Partial<import("../types/index.js").PriceResult>)[];
14
+ fetchedAt: string;
15
+ note?: undefined;
9
16
  }>;
@@ -1,11 +1,21 @@
1
1
  /**
2
- * get_trending tool — Trending/boosted tokens
2
+ * get_trending tool — Trending/boosted tokens from DexScreener.
3
+ * Returns tokens sorted by boost activity with price enrichment.
3
4
  */
4
5
  import { getTrending } from '../sources/dexscreener.js';
5
6
  export async function handleGetTrending(args) {
6
7
  const chain = args.chain || 'solana';
7
- const limit = args.limit || 20;
8
+ const limit = Math.min(Math.max(1, args.limit || 20), 50);
8
9
  const tokens = await getTrending(chain, limit);
10
+ if (tokens.length === 0) {
11
+ return {
12
+ chain,
13
+ count: 0,
14
+ tokens: [],
15
+ note: `No trending tokens found on ${chain}. DexScreener boost data may be temporarily unavailable.`,
16
+ fetchedAt: new Date().toISOString(),
17
+ };
18
+ }
9
19
  return {
10
20
  chain,
11
21
  count: tokens.length,
@@ -1 +1 @@
1
- {"version":3,"file":"getTrending.js","sourceRoot":"","sources":["../../src/tools/getTrending.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAExD,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,IAAwC;IAC9E,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,QAAQ,CAAC;IACrC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;IAC/B,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IAE/C,OAAO;QACL,KAAK;QACL,KAAK,EAAE,MAAM,CAAC,MAAM;QACpB,MAAM;QACN,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACpC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"getTrending.js","sourceRoot":"","sources":["../../src/tools/getTrending.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAExD,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,IAAwC;IAC9E,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,QAAQ,CAAC;IACrC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;IAC1D,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IAE/C,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO;YACL,KAAK;YACL,KAAK,EAAE,CAAC;YACR,MAAM,EAAE,EAAE;YACV,IAAI,EAAE,+BAA+B,KAAK,0DAA0D;YACpG,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACpC,CAAC;IACJ,CAAC;IAED,OAAO;QACL,KAAK;QACL,KAAK,EAAE,MAAM,CAAC,MAAM;QACpB,MAAM;QACN,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACpC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,24 @@
1
+ interface SearchResult {
2
+ address: string;
3
+ name: string;
4
+ symbol: string;
5
+ chain: string;
6
+ priceUsd: number;
7
+ volume24h: number;
8
+ liquidity: number;
9
+ marketCap: number;
10
+ dex: string;
11
+ pairCreatedAt: string | null;
12
+ }
13
+ export declare function handleSearchToken(args: {
14
+ query: string;
15
+ chain?: string;
16
+ limit?: number;
17
+ }): Promise<{
18
+ results: SearchResult[];
19
+ count: number;
20
+ query: string;
21
+ } | {
22
+ error: string;
23
+ }>;
24
+ export {};
@@ -0,0 +1,43 @@
1
+ /**
2
+ * search_token tool — Search tokens by name or symbol via DexScreener.
3
+ * Returns top matches with address, price, chain.
4
+ */
5
+ import { searchTokens } from '../sources/dexscreener.js';
6
+ import { debug } from '../utils/debug.js';
7
+ export async function handleSearchToken(args) {
8
+ if (!args.query || args.query.trim().length === 0) {
9
+ return { error: 'Search query is required (token name or symbol)' };
10
+ }
11
+ const query = args.query.trim();
12
+ const chain = args.chain || undefined;
13
+ const limit = Math.min(Math.max(1, args.limit || 10), 20);
14
+ debug(`Searching tokens: "${query}" chain=${chain ?? 'any'} limit=${limit}`);
15
+ const pairs = await searchTokens(query);
16
+ if (pairs.length === 0) {
17
+ return { error: `No tokens found matching "${query}". Try a different name or symbol.` };
18
+ }
19
+ // Filter by chain if specified
20
+ const filtered = chain ? pairs.filter(p => p.chainId === chain) : pairs;
21
+ if (filtered.length === 0) {
22
+ return { error: `No tokens found matching "${query}" on ${chain}. Found results on other chains.` };
23
+ }
24
+ const results = filtered.slice(0, limit).map(p => ({
25
+ address: p.baseToken.address,
26
+ name: p.baseToken.name,
27
+ symbol: p.baseToken.symbol,
28
+ chain: p.chainId,
29
+ priceUsd: parseFloat(p.priceUsd) || 0,
30
+ volume24h: p.volume?.h24 ?? 0,
31
+ liquidity: p.liquidity?.usd ?? 0,
32
+ marketCap: p.marketCap ?? 0,
33
+ dex: p.dexId,
34
+ pairCreatedAt: p.pairCreatedAt ? new Date(p.pairCreatedAt).toISOString() : null,
35
+ }));
36
+ debug(`Search "${query}": ${results.length} results`);
37
+ return {
38
+ query,
39
+ count: results.length,
40
+ results,
41
+ };
42
+ }
43
+ //# sourceMappingURL=searchToken.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"searchToken.js","sourceRoot":"","sources":["../../src/tools/searchToken.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAe1C,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,IAAuD;IAG7F,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAClD,OAAO,EAAE,KAAK,EAAE,iDAAiD,EAAE,CAAC;IACtE,CAAC;IAED,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;IAChC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,SAAS,CAAC;IACtC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;IAE1D,KAAK,CAAC,sBAAsB,KAAK,WAAW,KAAK,IAAI,KAAK,UAAU,KAAK,EAAE,CAAC,CAAC;IAE7E,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC,KAAK,CAAC,CAAC;IAExC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,EAAE,KAAK,EAAE,6BAA6B,KAAK,oCAAoC,EAAE,CAAC;IAC3F,CAAC;IAED,+BAA+B;IAC/B,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IAExE,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,EAAE,KAAK,EAAE,6BAA6B,KAAK,QAAQ,KAAK,kCAAkC,EAAE,CAAC;IACtG,CAAC;IAED,MAAM,OAAO,GAAmB,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QACjE,OAAO,EAAE,CAAC,CAAC,SAAS,CAAC,OAAO;QAC5B,IAAI,EAAE,CAAC,CAAC,SAAS,CAAC,IAAI;QACtB,MAAM,EAAE,CAAC,CAAC,SAAS,CAAC,MAAM;QAC1B,KAAK,EAAE,CAAC,CAAC,OAAO;QAChB,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC;QACrC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC;QAC7B,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,GAAG,IAAI,CAAC;QAChC,SAAS,EAAE,CAAC,CAAC,SAAS,IAAI,CAAC;QAC3B,GAAG,EAAE,CAAC,CAAC,KAAK;QACZ,aAAa,EAAE,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,IAAI;KAChF,CAAC,CAAC,CAAC;IAEJ,KAAK,CAAC,WAAW,KAAK,MAAM,OAAO,CAAC,MAAM,UAAU,CAAC,CAAC;IAEtD,OAAO;QACL,KAAK;QACL,KAAK,EAAE,OAAO,CAAC,MAAM;QACrB,OAAO;KACR,CAAC;AACJ,CAAC"}
@@ -1,3 +1,4 @@
1
+ /** DexScreener pair data from /latest/dex/tokens endpoint */
1
2
  export interface DexPair {
2
3
  chainId: string;
3
4
  dexId: string;
@@ -45,6 +46,37 @@ export interface DexPair {
45
46
  };
46
47
  pairCreatedAt?: number;
47
48
  }
49
+ /** Normalized price result from DexScreener */
50
+ export interface PriceResult {
51
+ address: string;
52
+ symbol: string;
53
+ name: string;
54
+ priceUsd: number;
55
+ priceChange1h: number;
56
+ priceChange24h: number;
57
+ volume24h: number;
58
+ liquidity: number;
59
+ marketCap: number;
60
+ dex: string;
61
+ }
62
+ /** Boosted/trending token from DexScreener */
63
+ export interface TrendingToken {
64
+ address: string;
65
+ symbol: string;
66
+ name: string;
67
+ chainId: string;
68
+ url: string;
69
+ boostAmount: number;
70
+ }
71
+ /** Raw GMGN boost entry from /token-boosts endpoints */
72
+ export interface DexBoostEntry {
73
+ tokenAddress?: string;
74
+ chainId?: string;
75
+ description?: string;
76
+ url?: string;
77
+ totalAmount?: number;
78
+ }
79
+ /** Normalized holder from GMGN API */
48
80
  export interface Holder {
49
81
  address: string;
50
82
  tags: string[];
@@ -68,6 +100,7 @@ export interface Holder {
68
100
  isFreshWallet: boolean;
69
101
  lastActiveAt: string | null;
70
102
  }
103
+ /** Individual risk flag from analysis */
71
104
  export interface RiskFlag {
72
105
  type: string;
73
106
  severity: 'low' | 'medium' | 'high' | 'critical';
@@ -79,6 +112,7 @@ export interface RiskAssessment {
79
112
  flags: RiskFlag[];
80
113
  summary: string;
81
114
  }
115
+ /** Complete token analysis result */
82
116
  export interface TokenAnalysis {
83
117
  token: {
84
118
  address: string;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Debug logging utility.
3
+ * Only logs when DEBUG=deficlaw is set. Silent otherwise (clean MCP output).
4
+ */
5
+ export declare function debug(message: string, ...args: unknown[]): void;
6
+ /** Time a function and log duration */
7
+ export declare function debugTime<T>(label: string, fn: () => Promise<T>): Promise<T>;
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Debug logging utility.
3
+ * Only logs when DEBUG=deficlaw is set. Silent otherwise (clean MCP output).
4
+ */
5
+ const DEBUG_ENABLED = (process.env.DEBUG ?? '').split(',').some(s => s.trim() === 'deficlaw' || s.trim() === '*');
6
+ export function debug(message, ...args) {
7
+ if (!DEBUG_ENABLED)
8
+ return;
9
+ const ts = new Date().toISOString().slice(11, 23);
10
+ process.stderr.write(`[deficlaw ${ts}] ${message}${args.length > 0 ? ' ' + args.map(a => typeof a === 'object' ? JSON.stringify(a) : String(a)).join(' ') : ''}\n`);
11
+ }
12
+ /** Time a function and log duration */
13
+ export async function debugTime(label, fn) {
14
+ if (!DEBUG_ENABLED)
15
+ return fn();
16
+ const start = Date.now();
17
+ try {
18
+ const result = await fn();
19
+ debug(`${label} completed in ${Date.now() - start}ms`);
20
+ return result;
21
+ }
22
+ catch (err) {
23
+ debug(`${label} failed in ${Date.now() - start}ms:`, err instanceof Error ? err.message : String(err));
24
+ throw err;
25
+ }
26
+ }
27
+ //# sourceMappingURL=debug.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"debug.js","sourceRoot":"","sources":["../../src/utils/debug.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,aAAa,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAC7D,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,UAAU,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,GAAG,CACjD,CAAC;AAEF,MAAM,UAAU,KAAK,CAAC,OAAe,EAAE,GAAG,IAAe;IACvD,IAAI,CAAC,aAAa;QAAE,OAAO;IAC3B,MAAM,EAAE,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;IAClD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,aAAa,EAAE,KAAK,OAAO,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;AACtK,CAAC;AAED,uCAAuC;AACvC,MAAM,CAAC,KAAK,UAAU,SAAS,CAAI,KAAa,EAAE,EAAoB;IACpE,IAAI,CAAC,aAAa;QAAE,OAAO,EAAE,EAAE,CAAC;IAChC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACzB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,EAAE,EAAE,CAAC;QAC1B,KAAK,CAAC,GAAG,KAAK,iBAAiB,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,CAAC,CAAC;QACvD,OAAO,MAAM,CAAC;IAChB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,KAAK,CAAC,GAAG,KAAK,cAAc,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QACvG,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@0xprotovox/deficlaw",
3
- "version": "0.1.1",
3
+ "version": "0.3.0",
4
4
  "description": "DeFi MCP Server for Claude Code — token analysis, prices, trending, holder intelligence",
5
5
  "author": "0xprotovox",
6
6
  "license": "MIT",
@@ -9,6 +9,19 @@
9
9
  "deficlaw": "dist/index.js"
10
10
  },
11
11
  "main": "dist/server.js",
12
+ "types": "dist/server.d.ts",
13
+ "files": [
14
+ "dist",
15
+ "README.md"
16
+ ],
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "https://github.com/0xprotovox/deficlaw.git"
20
+ },
21
+ "bugs": {
22
+ "url": "https://github.com/0xprotovox/deficlaw/issues"
23
+ },
24
+ "homepage": "https://github.com/0xprotovox/deficlaw#readme",
12
25
  "scripts": {
13
26
  "build": "tsc",
14
27
  "start": "node dist/index.js",
@@ -41,6 +54,9 @@
41
54
  "crypto",
42
55
  "token-analysis",
43
56
  "claude-code",
44
- "ai-tools"
57
+ "ai-tools",
58
+ "dexscreener",
59
+ "gmgn",
60
+ "risk-scoring"
45
61
  ]
46
62
  }