{"version":3,"file":"market-intel.mjs","names":[],"sources":["../../../src/tools/market-intel.ts"],"sourcesContent":["/**\n * Market Intel Tool — market data, trending analysis, whale watching\n * \n * Inspired by Lemon's MarketIntel. Ingests data from DexScreener,\n * CoinGecko, and on-chain events to surface market movements.\n */\n\nimport { Type } from '@sinclair/typebox';\nimport { stringEnum, jsonResult, errorResult, readStringParam, readNumberParam } from '../lib/tool-helpers.js';\nimport {\n  fetchDexScreener,\n  resolveChain,\n  searchToken,\n  getTrending as dexGetTrending,\n  getNewPairs as dexGetNewPairs,\n} from '../services/dexscreener-service.js';\n\nconst ACTIONS = ['trending', 'new_pairs', 'whale_watch', 'analysis', 'leaderboard'] as const;\n\nconst MarketIntelSchema = Type.Object({\n  action: stringEnum(ACTIONS, {\n    description: 'trending: hot tokens. new_pairs: recently created pools. whale_watch: large trades. analysis: token deep-dive. leaderboard: top Clawnch agents.',\n  }),\n  token: Type.Optional(Type.String({\n    description: 'Token address or symbol (for analysis action)',\n  })),\n  chain: Type.Optional(Type.String({\n    description: 'Chain to query (default: base)',\n  })),\n  limit: Type.Optional(Type.Number({\n    description: 'Number of results to return (default: 10)',\n  })),\n});\n\nexport function createMarketIntelTool() {\n  return {\n    name: 'market_intel',\n    label: 'Market Intel',\n    ownerOnly: false,\n    description:\n      'Real-time market intelligence — trending tokens, new pairs, whale movements, ' +\n      'token analysis, and Clawnch agent leaderboard. ' +\n      'Uses DexScreener, CoinGecko, and Clawnch platform data.',\n    parameters: MarketIntelSchema,\n    execute: async (_toolCallId: string, args: unknown) => {\n      const params = args as Record<string, unknown>;\n      const action = readStringParam(params, 'action', { required: true })!;\n\n      switch (action) {\n        case 'trending':\n          return handleTrending(params);\n        case 'new_pairs':\n          return handleNewPairs(params);\n        case 'whale_watch':\n          return handleWhaleWatch(params);\n        case 'analysis':\n          return handleAnalysis(params);\n        case 'leaderboard':\n          return handleLeaderboard(params);\n        default:\n          return errorResult(`Unknown action: ${action}`);\n      }\n    },\n  };\n}\n\n// ─── Action Handlers ─────────────────────────────────────────────────────\n\nasync function handleTrending(params: Record<string, unknown>) {\n  const chain = readStringParam(params, 'chain') || 'base';\n  const limit = readNumberParam(params, 'limit') ?? 10;\n\n  try {\n    // Get top boosted tokens (proxy for trending)\n    const boosts = await fetchDexScreener('/token-boosts/top/v1');\n    \n    const trending = (boosts ?? [])\n      .filter((t: any) => t.chainId === chain)\n      .slice(0, limit)\n      .map((t: any, i: number) => ({\n        rank: i + 1,\n        address: t.tokenAddress,\n        chain: t.chainId,\n        url: t.url,\n        boostAmount: t.totalAmount,\n      }));\n\n    // Also get token profiles for more detail\n    const addresses = trending.map((t: any) => t.address).filter(Boolean);\n    let profiles: any[] = [];\n    if (addresses.length > 0) {\n      try {\n        const profileData = await fetchDexScreener(\n          `/tokens/v1/${chain}/${addresses.slice(0, 5).join(',')}`,\n        );\n        profiles = Array.isArray(profileData) ? profileData : profileData?.pairs ?? [];\n      } catch {\n        // Non-fatal\n      }\n    }\n\n    return jsonResult({\n      chain,\n      trending,\n      count: trending.length,\n      profiles: profiles.slice(0, 5).map((p: any) => ({\n        symbol: p.baseToken?.symbol,\n        name: p.baseToken?.name,\n        priceUsd: p.priceUsd,\n        change24h: p.priceChange?.h24,\n        volume24h: p.volume?.h24,\n        liquidity: p.liquidity?.usd,\n      })),\n    });\n  } catch (err) {\n    return errorResult(`Trending lookup failed: ${err instanceof Error ? err.message : String(err)}`);\n  }\n}\n\nasync function handleNewPairs(params: Record<string, unknown>) {\n  const chain = readStringParam(params, 'chain') || 'base';\n  const limit = readNumberParam(params, 'limit') ?? 10;\n\n  try {\n    const data = await fetchDexScreener(`/latest/dex/pairs/${chain}`);\n    const pairs = (data?.pairs ?? []).slice(0, limit);\n\n    return jsonResult({\n      chain,\n      newPairs: pairs.map((p: any) => ({\n        pairAddress: p.pairAddress,\n        baseToken: {\n          symbol: p.baseToken?.symbol,\n          name: p.baseToken?.name,\n          address: p.baseToken?.address,\n        },\n        quoteToken: p.quoteToken?.symbol,\n        dexId: p.dexId,\n        priceUsd: p.priceUsd,\n        liquidity: p.liquidity?.usd,\n        volume24h: p.volume?.h24,\n        pairCreatedAt: p.pairCreatedAt,\n        url: p.url,\n      })),\n      count: pairs.length,\n    });\n  } catch (err) {\n    return errorResult(`New pairs lookup failed: ${err instanceof Error ? err.message : String(err)}`);\n  }\n}\n\nasync function handleWhaleWatch(params: Record<string, unknown>) {\n  const token = readStringParam(params, 'token');\n  const chain = readStringParam(params, 'chain') || 'base';\n\n  // DexScreener doesn't expose whale trades directly.\n  // We'll report what we can from available APIs.\n  try {\n    if (token) {\n      // Get token data with volume spikes as a proxy for whale activity\n      const data = await fetchDexScreener(\n        token.startsWith('0x')\n          ? `/tokens/v1/${chain}/${token}`\n          : `/latest/dex/search?q=${encodeURIComponent(token)}`,\n      );\n\n      const pairs = data?.pairs ?? (Array.isArray(data) ? data : []);\n      const topPair = pairs.find((p: any) => p.chainId === chain) ?? pairs[0];\n\n      if (!topPair) {\n        return jsonResult({ found: false, token, chain });\n      }\n\n      return jsonResult({\n        token: topPair.baseToken?.symbol,\n        address: topPair.baseToken?.address,\n        chain,\n        volume: {\n          h1: topPair.volume?.h1,\n          h6: topPair.volume?.h6,\n          h24: topPair.volume?.h24,\n        },\n        txns: {\n          h1: topPair.txns?.h1,\n          h6: topPair.txns?.h6,\n          h24: topPair.txns?.h24,\n        },\n        priceChange: {\n          h1: topPair.priceChange?.h1,\n          h6: topPair.priceChange?.h6,\n          h24: topPair.priceChange?.h24,\n        },\n        note: 'Volume spikes and transaction counts can indicate whale activity. ' +\n          'For detailed on-chain whale tracking, integrate with Herd Intelligence.',\n      });\n    }\n\n    return jsonResult({\n      chain,\n      note: 'Provide a token address or symbol for whale activity analysis. ' +\n        'General whale watching requires on-chain event streaming (future feature).',\n    });\n  } catch (err) {\n    return errorResult(`Whale watch failed: ${err instanceof Error ? err.message : String(err)}`);\n  }\n}\n\nasync function handleAnalysis(params: Record<string, unknown>) {\n  const token = readStringParam(params, 'token', { required: true })!;\n  const chain = readStringParam(params, 'chain') || 'base';\n\n  try {\n    // Get DexScreener data\n    const dexData = await fetchDexScreener(\n      token.startsWith('0x')\n        ? `/tokens/v1/${chain}/${token}`\n        : `/latest/dex/search?q=${encodeURIComponent(token)}`,\n    );\n\n    const pairs = dexData?.pairs ?? (Array.isArray(dexData) ? dexData : []);\n    const mainPair = pairs.find((p: any) => p.chainId === chain) ?? pairs[0];\n\n    if (!mainPair) {\n      return jsonResult({ found: false, token, chain });\n    }\n\n    // Try to get Clawnch analytics if it's a Clawnch token\n    let clawnchData: any = null;\n    try {\n      const { ClawnchClient } = await import('@clawnch/clawncher-sdk');\n      const client = new ClawnchClient({\n        baseUrl: process.env.CLAWNCHER_API_URL || 'https://clawn.ch',\n      });\n      clawnchData = await client.getTokenAnalytics(mainPair.baseToken?.address);\n    } catch {\n      // Not a Clawnch token or API unavailable\n    }\n\n    return jsonResult({\n      token: {\n        symbol: mainPair.baseToken?.symbol,\n        name: mainPair.baseToken?.name,\n        address: mainPair.baseToken?.address,\n      },\n      chain: mainPair.chainId,\n      price: {\n        usd: mainPair.priceUsd,\n        native: mainPair.priceNative,\n      },\n      change: {\n        m5: mainPair.priceChange?.m5,\n        h1: mainPair.priceChange?.h1,\n        h6: mainPair.priceChange?.h6,\n        h24: mainPair.priceChange?.h24,\n      },\n      volume: {\n        h1: mainPair.volume?.h1,\n        h6: mainPair.volume?.h6,\n        h24: mainPair.volume?.h24,\n      },\n      transactions: mainPair.txns?.h24,\n      liquidity: mainPair.liquidity?.usd,\n      marketCap: mainPair.marketCap ?? mainPair.fdv,\n      dex: mainPair.dexId,\n      pairCreated: mainPair.pairCreatedAt,\n      url: mainPair.url,\n      clawnch: clawnchData ?? undefined,\n    });\n  } catch (err) {\n    return errorResult(`Analysis failed: ${err instanceof Error ? err.message : String(err)}`);\n  }\n}\n\nasync function handleLeaderboard(params: Record<string, unknown>) {\n  const limit = readNumberParam(params, 'limit') ?? 20;\n\n  try {\n    const { ClawnchClient } = await import('@clawnch/clawncher-sdk');\n    const client = new ClawnchClient({\n      baseUrl: process.env.CLAWNCHER_API_URL || 'https://clawn.ch',\n    });\n\n    const leaderboard = await client.getLeaderboard('market_cap', limit);\n\n    return jsonResult({\n      leaderboard,\n      note: 'Ranked by total market cap of all tokens launched by each agent.',\n    });\n  } catch (err) {\n    // Fallback: get stats\n    try {\n      const { ClawnchClient } = await import('@clawnch/clawncher-sdk');\n      const client = new ClawnchClient({\n        baseUrl: process.env.CLAWNCHER_API_URL || 'https://clawn.ch',\n      });\n      const stats = await client.getStats();\n      return jsonResult({\n        stats,\n        note: 'Full leaderboard unavailable. Showing platform stats instead.',\n      });\n    } catch (err2) {\n      return errorResult(`Leaderboard failed: ${err instanceof Error ? err.message : String(err)}`);\n    }\n  }\n}\n"],"mappings":";;;;;;;;;AAmBA,MAAM,oBAAoB,KAAK,OAAO;CACpC,QAAQ,WAHM;EAAC;EAAY;EAAa;EAAe;EAAY;EAAc,EAGrD,EAC1B,aAAa,mJACd,CAAC;CACF,OAAO,KAAK,SAAS,KAAK,OAAO,EAC/B,aAAa,iDACd,CAAC,CAAC;CACH,OAAO,KAAK,SAAS,KAAK,OAAO,EAC/B,aAAa,kCACd,CAAC,CAAC;CACH,OAAO,KAAK,SAAS,KAAK,OAAO,EAC/B,aAAa,6CACd,CAAC,CAAC;CACJ,CAAC;AAEF,SAAgB,wBAAwB;AACtC,QAAO;EACL,MAAM;EACN,OAAO;EACP,WAAW;EACX,aACE;EAGF,YAAY;EACZ,SAAS,OAAO,aAAqB,SAAkB;GACrD,MAAM,SAAS;GACf,MAAM,SAAS,gBAAgB,QAAQ,UAAU,EAAE,UAAU,MAAM,CAAC;AAEpE,WAAQ,QAAR;IACE,KAAK,WACH,QAAO,eAAe,OAAO;IAC/B,KAAK,YACH,QAAO,eAAe,OAAO;IAC/B,KAAK,cACH,QAAO,iBAAiB,OAAO;IACjC,KAAK,WACH,QAAO,eAAe,OAAO;IAC/B,KAAK,cACH,QAAO,kBAAkB,OAAO;IAClC,QACE,QAAO,YAAY,mBAAmB,SAAS;;;EAGtD;;AAKH,eAAe,eAAe,QAAiC;CAC7D,MAAM,QAAQ,gBAAgB,QAAQ,QAAQ,IAAI;CAClD,MAAM,QAAQ,gBAAgB,QAAQ,QAAQ,IAAI;AAElD,KAAI;EAIF,MAAM,YAFS,MAAM,iBAAiB,uBAAuB,IAEjC,EAAE,EAC3B,QAAQ,MAAW,EAAE,YAAY,MAAM,CACvC,MAAM,GAAG,MAAM,CACf,KAAK,GAAQ,OAAe;GAC3B,MAAM,IAAI;GACV,SAAS,EAAE;GACX,OAAO,EAAE;GACT,KAAK,EAAE;GACP,aAAa,EAAE;GAChB,EAAE;EAGL,MAAM,YAAY,SAAS,KAAK,MAAW,EAAE,QAAQ,CAAC,OAAO,QAAQ;EACrE,IAAI,WAAkB,EAAE;AACxB,MAAI,UAAU,SAAS,EACrB,KAAI;GACF,MAAM,cAAc,MAAM,iBACxB,cAAc,MAAM,GAAG,UAAU,MAAM,GAAG,EAAE,CAAC,KAAK,IAAI,GACvD;AACD,cAAW,MAAM,QAAQ,YAAY,GAAG,cAAc,aAAa,SAAS,EAAE;UACxE;AAKV,SAAO,WAAW;GAChB;GACA;GACA,OAAO,SAAS;GAChB,UAAU,SAAS,MAAM,GAAG,EAAE,CAAC,KAAK,OAAY;IAC9C,QAAQ,EAAE,WAAW;IACrB,MAAM,EAAE,WAAW;IACnB,UAAU,EAAE;IACZ,WAAW,EAAE,aAAa;IAC1B,WAAW,EAAE,QAAQ;IACrB,WAAW,EAAE,WAAW;IACzB,EAAE;GACJ,CAAC;UACK,KAAK;AACZ,SAAO,YAAY,2BAA2B,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI,GAAG;;;AAIrG,eAAe,eAAe,QAAiC;CAC7D,MAAM,QAAQ,gBAAgB,QAAQ,QAAQ,IAAI;CAClD,MAAM,QAAQ,gBAAgB,QAAQ,QAAQ,IAAI;AAElD,KAAI;EAEF,MAAM,UADO,MAAM,iBAAiB,qBAAqB,QAAQ,GAC5C,SAAS,EAAE,EAAE,MAAM,GAAG,MAAM;AAEjD,SAAO,WAAW;GAChB;GACA,UAAU,MAAM,KAAK,OAAY;IAC/B,aAAa,EAAE;IACf,WAAW;KACT,QAAQ,EAAE,WAAW;KACrB,MAAM,EAAE,WAAW;KACnB,SAAS,EAAE,WAAW;KACvB;IACD,YAAY,EAAE,YAAY;IAC1B,OAAO,EAAE;IACT,UAAU,EAAE;IACZ,WAAW,EAAE,WAAW;IACxB,WAAW,EAAE,QAAQ;IACrB,eAAe,EAAE;IACjB,KAAK,EAAE;IACR,EAAE;GACH,OAAO,MAAM;GACd,CAAC;UACK,KAAK;AACZ,SAAO,YAAY,4BAA4B,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI,GAAG;;;AAItG,eAAe,iBAAiB,QAAiC;CAC/D,MAAM,QAAQ,gBAAgB,QAAQ,QAAQ;CAC9C,MAAM,QAAQ,gBAAgB,QAAQ,QAAQ,IAAI;AAIlD,KAAI;AACF,MAAI,OAAO;GAET,MAAM,OAAO,MAAM,iBACjB,MAAM,WAAW,KAAK,GAClB,cAAc,MAAM,GAAG,UACvB,wBAAwB,mBAAmB,MAAM,GACtD;GAED,MAAM,QAAQ,MAAM,UAAU,MAAM,QAAQ,KAAK,GAAG,OAAO,EAAE;GAC7D,MAAM,UAAU,MAAM,MAAM,MAAW,EAAE,YAAY,MAAM,IAAI,MAAM;AAErE,OAAI,CAAC,QACH,QAAO,WAAW;IAAE,OAAO;IAAO;IAAO;IAAO,CAAC;AAGnD,UAAO,WAAW;IAChB,OAAO,QAAQ,WAAW;IAC1B,SAAS,QAAQ,WAAW;IAC5B;IACA,QAAQ;KACN,IAAI,QAAQ,QAAQ;KACpB,IAAI,QAAQ,QAAQ;KACpB,KAAK,QAAQ,QAAQ;KACtB;IACD,MAAM;KACJ,IAAI,QAAQ,MAAM;KAClB,IAAI,QAAQ,MAAM;KAClB,KAAK,QAAQ,MAAM;KACpB;IACD,aAAa;KACX,IAAI,QAAQ,aAAa;KACzB,IAAI,QAAQ,aAAa;KACzB,KAAK,QAAQ,aAAa;KAC3B;IACD,MAAM;IAEP,CAAC;;AAGJ,SAAO,WAAW;GAChB;GACA,MAAM;GAEP,CAAC;UACK,KAAK;AACZ,SAAO,YAAY,uBAAuB,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI,GAAG;;;AAIjG,eAAe,eAAe,QAAiC;CAC7D,MAAM,QAAQ,gBAAgB,QAAQ,SAAS,EAAE,UAAU,MAAM,CAAC;CAClE,MAAM,QAAQ,gBAAgB,QAAQ,QAAQ,IAAI;AAElD,KAAI;EAEF,MAAM,UAAU,MAAM,iBACpB,MAAM,WAAW,KAAK,GAClB,cAAc,MAAM,GAAG,UACvB,wBAAwB,mBAAmB,MAAM,GACtD;EAED,MAAM,QAAQ,SAAS,UAAU,MAAM,QAAQ,QAAQ,GAAG,UAAU,EAAE;EACtE,MAAM,WAAW,MAAM,MAAM,MAAW,EAAE,YAAY,MAAM,IAAI,MAAM;AAEtE,MAAI,CAAC,SACH,QAAO,WAAW;GAAE,OAAO;GAAO;GAAO;GAAO,CAAC;EAInD,IAAI,cAAmB;AACvB,MAAI;GACF,MAAM,EAAE,kBAAkB,MAAM,OAAO;AAIvC,iBAAc,MAHC,IAAI,cAAc,EAC/B,SAAS,QAAQ,IAAI,qBAAqB,oBAC3C,CAAC,CACyB,kBAAkB,SAAS,WAAW,QAAQ;UACnE;AAIR,SAAO,WAAW;GAChB,OAAO;IACL,QAAQ,SAAS,WAAW;IAC5B,MAAM,SAAS,WAAW;IAC1B,SAAS,SAAS,WAAW;IAC9B;GACD,OAAO,SAAS;GAChB,OAAO;IACL,KAAK,SAAS;IACd,QAAQ,SAAS;IAClB;GACD,QAAQ;IACN,IAAI,SAAS,aAAa;IAC1B,IAAI,SAAS,aAAa;IAC1B,IAAI,SAAS,aAAa;IAC1B,KAAK,SAAS,aAAa;IAC5B;GACD,QAAQ;IACN,IAAI,SAAS,QAAQ;IACrB,IAAI,SAAS,QAAQ;IACrB,KAAK,SAAS,QAAQ;IACvB;GACD,cAAc,SAAS,MAAM;GAC7B,WAAW,SAAS,WAAW;GAC/B,WAAW,SAAS,aAAa,SAAS;GAC1C,KAAK,SAAS;GACd,aAAa,SAAS;GACtB,KAAK,SAAS;GACd,SAAS,eAAe,KAAA;GACzB,CAAC;UACK,KAAK;AACZ,SAAO,YAAY,oBAAoB,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI,GAAG;;;AAI9F,eAAe,kBAAkB,QAAiC;CAChE,MAAM,QAAQ,gBAAgB,QAAQ,QAAQ,IAAI;AAElD,KAAI;EACF,MAAM,EAAE,kBAAkB,MAAM,OAAO;AAOvC,SAAO,WAAW;GAChB,aAHkB,MAJL,IAAI,cAAc,EAC/B,SAAS,QAAQ,IAAI,qBAAqB,oBAC3C,CAAC,CAE+B,eAAe,cAAc,MAAM;GAIlE,MAAM;GACP,CAAC;UACK,KAAK;AAEZ,MAAI;GACF,MAAM,EAAE,kBAAkB,MAAM,OAAO;AAKvC,UAAO,WAAW;IAChB,OAFY,MAHC,IAAI,cAAc,EAC/B,SAAS,QAAQ,IAAI,qBAAqB,oBAC3C,CAAC,CACyB,UAAU;IAGnC,MAAM;IACP,CAAC;WACK,MAAM;AACb,UAAO,YAAY,uBAAuB,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI,GAAG"}