chain-insights 0.3.4 → 0.3.6

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 (54) hide show
  1. package/README.md +28 -11
  2. package/dist/canvas-Cn-maEIh.mjs +203 -0
  3. package/dist/canvas-Cn-maEIh.mjs.map +1 -0
  4. package/dist/canvas-p-oKCMjc.cjs +251 -0
  5. package/dist/cases-Bz_9XKEw.cjs +19 -0
  6. package/dist/cases-TVcAifxu.mjs +16 -0
  7. package/dist/cases-TVcAifxu.mjs.map +1 -0
  8. package/dist/cli.cjs +74 -28
  9. package/dist/cli.mjs +74 -28
  10. package/dist/cli.mjs.map +1 -1
  11. package/dist/{data-extractor-DZUJu1Bz.mjs → data-extractor-B4nHw1wZ.mjs} +2 -2
  12. package/dist/{data-extractor-DZUJu1Bz.mjs.map → data-extractor-B4nHw1wZ.mjs.map} +1 -1
  13. package/dist/{data-extractor-Cavd7wHk.cjs → data-extractor-DS4rzy3M.cjs} +1 -1
  14. package/dist/{export-BqTCO9lP.mjs → export-CBhcJuZ6.mjs} +8 -205
  15. package/dist/export-CBhcJuZ6.mjs.map +1 -0
  16. package/dist/{export-DsXgtCwO.cjs → export-D4v4-6F4.cjs} +16 -214
  17. package/dist/index.cjs +1 -1
  18. package/dist/index.mjs +1 -1
  19. package/dist/{init-DLBL_nVG.mjs → init-CKQ6F07J.mjs} +22 -5
  20. package/dist/init-CKQ6F07J.mjs.map +1 -0
  21. package/dist/{init-zqbd7i-_.cjs → init-Dhw8F23z.cjs} +21 -4
  22. package/dist/mcp-proxy.cjs +20 -20
  23. package/dist/mcp-proxy.mjs +20 -20
  24. package/dist/mcp-proxy.mjs.map +1 -1
  25. package/dist/{public-tools-wJoAFDFa.mjs → public-tools-CyUZEz9B.mjs} +3 -3
  26. package/dist/{public-tools-wJoAFDFa.mjs.map → public-tools-CyUZEz9B.mjs.map} +1 -1
  27. package/dist/{public-tools-BvMb3H2P.cjs → public-tools-xfVNz9NE.cjs} +2 -2
  28. package/dist/{runner-BhZ4lnF1.cjs → runner-CVo41fjz.cjs} +2 -2
  29. package/dist/{runner-DIJSbkjc.mjs → runner-DWuSy1Se.mjs} +3 -3
  30. package/dist/{runner-DIJSbkjc.mjs.map → runner-DWuSy1Se.mjs.map} +1 -1
  31. package/dist/{selector-CF2o5gxN.mjs → selector-BvXM9jbe.mjs} +2 -2
  32. package/dist/{selector-CF2o5gxN.mjs.map → selector-BvXM9jbe.mjs.map} +1 -1
  33. package/dist/{selector-DfAMZEC9.cjs → selector-Dps_ZFxq.cjs} +1 -1
  34. package/dist/{store-CTtqQtaE.mjs → store-C2B_AssI.mjs} +2 -2
  35. package/dist/{store-CTtqQtaE.mjs.map → store-C2B_AssI.mjs.map} +1 -1
  36. package/dist/{store-CqPfs47P.cjs → store-CQhU8dz8.cjs} +0 -18
  37. package/dist/vault-B2y78Ypu.cjs +560 -0
  38. package/dist/vault-z35Dohdq.mjs +560 -0
  39. package/dist/vault-z35Dohdq.mjs.map +1 -0
  40. package/dist/{viz-Dqp3C5kb.cjs → viz-D1620cBX.cjs} +3 -3
  41. package/dist/{viz-5y24S5X1.mjs → viz-DB5XFG1z.mjs} +4 -4
  42. package/dist/{viz-5y24S5X1.mjs.map → viz-DB5XFG1z.mjs.map} +1 -1
  43. package/docs/graph-tools.md +24 -8
  44. package/docs/investigation-workspaces.md +36 -10
  45. package/docs/knowledge-exports.md +6 -2
  46. package/docs/mcp-proxy.md +29 -7
  47. package/docs/obsidian-vault.md +130 -0
  48. package/package.json +1 -1
  49. package/skills/chain-insights-developer-experience/SKILL.md +2 -2
  50. package/skills/chain-insights-investigation/SKILL.md +1 -1
  51. package/dist/cases-Cp9DUbEV.mjs +0 -6
  52. package/dist/cases-sTY5aXav.cjs +0 -9
  53. package/dist/export-BqTCO9lP.mjs.map +0 -1
  54. package/dist/init-DLBL_nVG.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"public-tools-wJoAFDFa.mjs","names":["GRAPH_QUERY_BATCH_TIMEOUT_SECONDS","GRAPH_QUERY_BATCH_REQUEST_TIMEOUT_MS","clampInt","escapeCypherString","textFromToolResult","parseGraphBatchResult","topologyGraphQuery","callGraphBatch","flowEdgeMap","pathNodeMap","edgeKey","numberValue","isExchangeFlag","stringArrayValue","uniqueStrings","hasExactExchangeLabel","htmlEscape","escapeCypherString","textFromToolResult","parseGraphBatchResult","numberValue","clampInt","callGraphBatch"],"sources":["../src/investigation/trace-funds.ts","../src/investigation/stake-insights.ts","../src/investigation/public-tools.ts"],"sourcesContent":["import { mkdir, readFile, writeFile } from 'node:fs/promises'\nimport path from 'node:path'\nimport type { Client } from '@modelcontextprotocol/sdk/client/index.js'\nimport type { ContentBlock } from '@modelcontextprotocol/sdk/types.js'\nimport type { InvestigatorConfig } from '../config/schema.js'\nimport { normalizeGraphPayload } from '../viz/graph-normalizer.js'\nimport { workspaceOutputPaths, type WorkspaceOutputPaths } from '../workspace/output-root.js'\n\ntype RemoteToolResult = {\n content?: ContentBlock[]\n isError?: boolean\n}\n\nexport interface TraceFundsOptions {\n seedAddress: string\n network: string\n caseId?: string\n maxHops?: number\n perAddressLimit?: number\n minAmountSum?: number\n includeDepositTraceback?: boolean\n evidenceSource?: string\n}\n\nexport interface TraceFlow {\n hop: number\n src: string\n dst: string\n amount_sum: number\n amount_usd_sum?: number\n tx_count?: number\n first_tx_id?: string\n last_tx_id?: string\n src_labels?: string[]\n dst_labels?: string[]\n src_node?: GraphNodeMetadata\n dst_node?: GraphNodeMetadata\n dst_degree_in?: number\n dst_degree_out?: number\n terminal_exchange: boolean\n}\n\nexport interface TraceFundsResult {\n summaryText: string\n compactEvidence: Record<string, unknown>\n graphData: Record<string, unknown>\n files: {\n schema: string\n compactEvidence: string\n graph: string\n graphHtml: string\n table: string\n tableHtml: string\n report: string\n }\n continuation: {\n nextHopAddresses: string[]\n depositAddresses: string[]\n exchangeAddresses: string[]\n hint: string\n }\n addressMap: Record<string, string>\n}\n\ninterface TraceDeposit {\n address: string\n exchangeAddress: string\n exchangeLabels?: string[]\n exchangeNode?: GraphNodeMetadata\n amount_sum?: number\n amount_usd_sum?: number\n hops: number\n path: string[]\n pathNodes?: GraphNodeMetadata[]\n}\n\ninterface SourceMatch {\n deposit_address: string\n source_exchange: string\n source_labels?: string[]\n sourceNode?: GraphNodeMetadata\n hops: number\n path: string[]\n pathNodes?: GraphNodeMetadata[]\n}\n\ninterface ReverseLead {\n address: string\n labels?: string[]\n node?: GraphNodeMetadata\n deposit_address: string\n amount_usd?: number\n degree_in?: number\n degree_out?: number\n total_volume_usd?: number\n reason: string\n}\n\ninterface GraphNodeMetadata {\n address: string\n labels?: string[]\n system_labels?: string[]\n address_type?: string\n address_subtypes?: string[]\n is_exchange?: boolean\n}\n\nclass AliasTracker {\n private readonly byAddress = new Map<string, string>()\n private readonly byAlias = new Map<string, string>()\n private readonly counters = new Map<string, number>()\n\n assign(address: string, prefix: string): string {\n const existing = this.byAddress.get(address)\n if (existing) return existing\n const next = (this.counters.get(prefix) ?? 0) + 1\n this.counters.set(prefix, next)\n const alias = `${prefix}${next}`\n this.byAddress.set(address, alias)\n this.byAlias.set(alias, address)\n return alias\n }\n\n alias(address: string): string | undefined {\n return this.byAddress.get(address)\n }\n\n addressMap(): Record<string, string> {\n return Object.fromEntries([...this.byAlias.entries()].sort(([a], [b]) => a.localeCompare(b, undefined, { numeric: true })))\n }\n\n compactAddressMap(maxIntermediaries = 20, maxSourceExchanges = 20, maxLeads = 20): Record<string, string> {\n const counts = new Map<string, number>()\n const entries = [...this.byAlias.entries()].filter(([alias]) => {\n const prefix = alias.slice(0, 1)\n if (['V', 'D', 'E'].includes(prefix)) return true\n const next = (counts.get(prefix) ?? 0) + 1\n counts.set(prefix, next)\n if (prefix === 'I') return next <= maxIntermediaries\n if (prefix === 'X') return next <= maxSourceExchanges\n if (prefix === 'L') return next <= maxLeads\n return true\n })\n return Object.fromEntries(entries.sort(([a], [b]) => a.localeCompare(b, undefined, { numeric: true })))\n }\n}\n\ninterface ParsedGraphBatch {\n facts?: {\n queries?: Array<{\n id?: string\n ok?: boolean\n results?: Array<Record<string, unknown>>\n error?: string\n }>\n }\n}\n\nconst GRAPH_QUERY_BATCH_TIMEOUT_SECONDS = 120\nconst GRAPH_QUERY_BATCH_REQUEST_TIMEOUT_MS = 5 * 60 * 1000\n\nconst SCHEMA_QUERY_SET = [\n {\n id: 'node_labels',\n query: 'MATCH (n:Address) RETURN \"Address\" AS node_label, count(n) AS sample_count LIMIT 1',\n },\n {\n id: 'relationship_types',\n query: 'MATCH (:Address)-[r:FLOWS_TO]->(:Address) RETURN \"FLOWS_TO\" AS rel_name, count(r) AS sample_count LIMIT 1',\n },\n {\n id: 'address_property_keys',\n query: 'MATCH (n:Address) RETURN \"address\" AS property_key, count(n) AS sample_count LIMIT 1',\n },\n {\n id: 'flows_to_property_keys',\n query: 'MATCH (:Address)-[r:FLOWS_TO]->(:Address) RETURN \"amount_sum\" AS property_key, count(r) AS sample_count LIMIT 1',\n },\n]\n\nfunction clampInt(value: number | undefined, fallback: number, min: number, max: number): number {\n if (!Number.isFinite(value)) return fallback\n return Math.max(min, Math.min(max, Math.trunc(value as number)))\n}\n\nfunction escapeCypherString(value: string): string {\n return value.replaceAll('\\\\', '\\\\\\\\').replaceAll('\"', '\\\\\"')\n}\n\nfunction sanitizeSegment(value: string): string {\n const sanitized = value.toLowerCase().replace(/[^a-z0-9_-]+/g, '-').replace(/(^-|-$)/g, '').slice(0, 80)\n return sanitized || 'trace'\n}\n\nasync function ensureDirs(paths: WorkspaceOutputPaths): Promise<void> {\n await mkdir(paths.schemaDir, { recursive: true, mode: 0o700 })\n await mkdir(paths.reportsRoot, { recursive: true, mode: 0o700 })\n await mkdir(paths.reportGraphsRoot, { recursive: true, mode: 0o700 })\n await mkdir(paths.reportTablesRoot, { recursive: true, mode: 0o700 })\n await mkdir(paths.logsRoot, { recursive: true, mode: 0o700 })\n}\n\nfunction textFromToolResult(result: RemoteToolResult): string {\n return (result.content ?? [])\n .filter((item): item is Extract<ContentBlock, { type: 'text' }> => item.type === 'text')\n .map((item) => item.text)\n .join('\\n')\n}\n\nfunction parseGraphBatchResult(result: RemoteToolResult): ParsedGraphBatch {\n const text = textFromToolResult(result).trim()\n if (!text) throw new Error('graph_query_batch returned no text content')\n const parsed = JSON.parse(text) as ParsedGraphBatch\n if (!parsed.facts?.queries) throw new Error('graph_query_batch response did not include facts.queries')\n return parsed\n}\n\nfunction topologyGraphQuery(query: string): string {\n const trimmed = query.trim()\n if (/^USE\\s+/i.test(trimmed)) return trimmed\n return `USE live_topology ${trimmed}`\n}\n\nasync function callGraphBatch(\n remoteClient: Client,\n network: string,\n queries: Array<{ id: string; query: string }>,\n): Promise<ParsedGraphBatch> {\n const result = await remoteClient.callTool(\n {\n name: 'graph_query_batch',\n arguments: {\n network,\n queries: queries.map((query) => ({\n ...query,\n query: topologyGraphQuery(query.query),\n })),\n per_query_timeout_seconds: GRAPH_QUERY_BATCH_TIMEOUT_SECONDS,\n },\n },\n undefined,\n {\n timeout: GRAPH_QUERY_BATCH_REQUEST_TIMEOUT_MS,\n maxTotalTimeout: GRAPH_QUERY_BATCH_REQUEST_TIMEOUT_MS,\n },\n ) as RemoteToolResult\n if (result.isError) throw new Error(textFromToolResult(result) || 'graph_query_batch failed')\n return parseGraphBatchResult(result)\n}\n\nfunction resultsFor(batch: ParsedGraphBatch, id: string): Array<Record<string, unknown>> {\n const query = batch.facts?.queries?.find((entry) => entry.id === id)\n if (!query) return []\n if (query.ok === false) throw new Error(query.error || `Query failed: ${id}`)\n return query.results ?? []\n}\n\nfunction schemaFromGraphBatch(network: string, batch: ParsedGraphBatch): Record<string, unknown> {\n return {\n schema: 'chain-insights.runtime_graph_schema.v1',\n network,\n source: 'graph_query_batch',\n node_labels: resultsFor(batch, 'node_labels'),\n relationship_types: resultsFor(batch, 'relationship_types'),\n address_property_keys: resultsFor(batch, 'address_property_keys').map((row) => row['property_key']),\n flows_to_property_keys: resultsFor(batch, 'flows_to_property_keys').map((row) => row['property_key']),\n recommended_flow_projection: [\n 'src.address AS src',\n 'dst.address AS dst',\n 'r.amount_sum AS amount_sum',\n 'r.amount_usd_sum AS amount_usd_sum',\n 'r.tx_count AS tx_count',\n 'r.first_tx_id AS first_tx_id',\n 'r.last_tx_id AS last_tx_id',\n 'dst.labels AS dst_labels',\n 'dst.lifetime_degree_in AS dst_degree_in',\n 'dst.lifetime_degree_out AS dst_degree_out',\n ],\n }\n}\n\nasync function loadOrCaptureTopologySchema(\n remoteClient: Client,\n paths: WorkspaceOutputPaths,\n network: string,\n): Promise<{ schema: Record<string, unknown>; filePath: string }> {\n const filePath = path.join(paths.schemaDir, `${sanitizeSegment(network)}.graph-schema.json`)\n try {\n return { schema: JSON.parse(await readFile(filePath, 'utf8')) as Record<string, unknown>, filePath }\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') throw err\n }\n\n const batch = await callGraphBatch(\n remoteClient,\n network,\n SCHEMA_QUERY_SET,\n )\n const schema = schemaFromGraphBatch(network, batch)\n await writeFile(filePath, JSON.stringify(schema, null, 2) + '\\n', { mode: 0o600 })\n return { schema, filePath }\n}\n\nfunction flowEdgeMap(variableName: string): string {\n return `{amount_sum: ${variableName}.amount_sum, amount_usd_sum: ${variableName}.amount_usd_sum, tx_count: ${variableName}.tx_count, first_tx_id: ${variableName}.first_tx_id, last_tx_id: ${variableName}.last_tx_id}`\n}\n\nfunction pathNodeMap(variableName: string): string {\n return `{address: ${variableName}.address, labels: ${variableName}.labels, system_labels: ${variableName}.labels, address_type: ${variableName}.address_type, address_subtypes: ${variableName}.address_subtypes, is_exchange: ${variableName}.is_exchange}`\n}\n\nfunction forwardExchangeQueries(address: string, limit: number, minAmountSum: number, maxHops: number): Array<{ id: string; query: string }> {\n return Array.from({ length: maxHops }, (_, index) => forwardExchangeQueryAtDepth(address, limit, minAmountSum, index + 1))\n}\n\nfunction forwardExchangeQueryAtDepth(address: string, limit: number, minAmountSum: number, depth: number): { id: string; query: string } {\n const intermediateVariables = Array.from({ length: Math.max(depth - 1, 0) }, (_, index) => `n${index + 1}`)\n const nodeVariables = ['s', ...intermediateVariables, 't']\n const edgeVariables = Array.from({ length: depth }, (_, index) => `r${index + 1}`)\n const relationshipChain = edgeVariables.map((edgeVariable, index) => {\n const targetVariable = index === edgeVariables.length - 1 ? 't' : intermediateVariables[index]!\n return `-[${edgeVariable}:FLOWS_TO]->(${targetVariable}:Address)`\n }).join('')\n const amountPredicates = edgeVariables.map((edgeVariable) => `${edgeVariable}.amount_sum IS NOT NULL${minAmountSum > 0 ? ` AND ${edgeVariable}.amount_sum >= ${minAmountSum}` : ''}`)\n const nonTerminalPredicates = ['s', ...intermediateVariables].map((nodeVariable) => `${nodeVariable}.is_exchange IS NULL`)\n const predicates = ['s <> t', ...nonTerminalPredicates, 't.is_exchange IS NOT NULL', ...amountPredicates]\n const depositVariable = nodeVariables[nodeVariables.length - 2]!\n return {\n id: `forward_exchange_paths_${depth}`,\n query: [\n `MATCH (s:Address {address: \"${escapeCypherString(address)}\"})${relationshipChain}`,\n `WHERE ${predicates.join(' AND ')}`,\n `RETURN [${nodeVariables.map((nodeVariable) => `${nodeVariable}.address`).join(', ')}] AS addresses, [${nodeVariables.map((nodeVariable) => `${nodeVariable}.labels`).join(', ')}] AS node_labels, [${nodeVariables.map(pathNodeMap).join(', ')}] AS path_nodes, [${edgeVariables.map(flowEdgeMap).join(', ')}] AS edge_props, t.address AS exchange_address, t.labels AS exchange_display_labels, t.labels AS exchange_labels, t.address_type AS exchange_address_type, t.address_subtypes AS exchange_address_subtypes, t.is_exchange AS exchange_is_exchange, ${depositVariable}.address AS deposit_address, ${depositVariable}.is_exchange AS deposit_is_exchange, ${depth} AS hops`,\n 'ORDER BY hops ASC',\n `LIMIT ${limit}`,\n ].join(' '),\n }\n}\n\nfunction backwardSourceQueries(idPrefix: string, depositAddress: string, maxHops: number): Array<{ id: string; query: string }> {\n return Array.from({ length: maxHops }, (_, index) => backwardSourceQueryAtDepth(`${idPrefix}_${index + 1}`, depositAddress, index + 1))\n}\n\nfunction backwardSourceQueryAtDepth(id: string, depositAddress: string, depth: number): { id: string; query: string } {\n const intermediateVariables = Array.from({ length: Math.max(depth - 1, 0) }, (_, index) => `n${index + 1}`)\n const nodeVariables = ['dep', ...intermediateVariables, 'source']\n const edgeVariables = Array.from({ length: depth }, (_, index) => `r${index + 1}`)\n const relationshipChain = edgeVariables.map((edgeVariable, index) => {\n const targetVariable = index === edgeVariables.length - 1 ? 'source' : intermediateVariables[index]!\n return `<-[${edgeVariable}:FLOWS_TO]-(${targetVariable}:Address)`\n }).join('')\n const intermediatePredicates = intermediateVariables.map((nodeVariable) => `${nodeVariable}.is_exchange IS NULL`)\n return {\n id,\n query: [\n `MATCH (dep:Address {address: \"${escapeCypherString(depositAddress)}\"})`,\n `MATCH (dep)${relationshipChain}`,\n `WHERE source <> dep AND source.is_exchange IS NOT NULL${intermediatePredicates.length > 0 ? ` AND ${intermediatePredicates.join(' AND ')}` : ''}`,\n `RETURN dep.address AS deposit_address, source.address AS source_exchange, source.labels AS source_display_labels, source.labels AS source_labels, source.address_type AS source_address_type, source.address_subtypes AS source_address_subtypes, ${depth} AS hops, [${nodeVariables.map((nodeVariable) => `${nodeVariable}.address`).join(', ')}] AS addresses, [${nodeVariables.map((nodeVariable) => `${nodeVariable}.labels`).join(', ')}] AS node_labels, [${nodeVariables.map(pathNodeMap).join(', ')}] AS path_nodes`,\n 'LIMIT 20',\n ].join(' '),\n }\n}\n\nfunction reverseLeadsQuery(depositAddresses: string[]): { id: string; query: string } {\n const depositPredicates = depositAddresses.map((address) => `deposit.address = \"${escapeCypherString(address)}\"`)\n return {\n id: 'reverse_1hop',\n query: [\n 'MATCH (sender:Address)-[r:FLOWS_TO]->(deposit:Address)',\n `WHERE (${depositPredicates.join(' OR ')}) AND sender.is_exchange IS NULL AND sender.address <> deposit.address`,\n 'RETURN DISTINCT sender.address AS address, sender.labels AS display_labels, sender.labels AS system_labels, sender.address_type AS address_type, sender.address_subtypes AS address_subtypes, coalesce(sender.lifetime_degree_in, 0) AS degree_in, coalesce(sender.lifetime_degree_out, 0) AS degree_out, coalesce(sender.total_volume_usd, 0) AS total_volume_usd, deposit.address AS deposit_address, r.amount_usd_sum AS amount_usd',\n 'ORDER BY r.amount_usd_sum DESC',\n `LIMIT ${Math.max(50, depositAddresses.length * 50)}`,\n ].join(' '),\n }\n}\n\nfunction edgeKey(src: string, dst: string): string {\n return `${src}\\u0000${dst}`\n}\n\nfunction directEdgePropsQuery(flows: TraceFlow[]): { id: string; query: string } | null {\n const pairs = [...new Map(flows.map((flow) => [edgeKey(flow.src, flow.dst), { src: flow.src, dst: flow.dst }])).values()]\n if (pairs.length === 0) return null\n const predicates = pairs.map((pair) =>\n `(a.address = \"${escapeCypherString(pair.src)}\" AND b.address = \"${escapeCypherString(pair.dst)}\")`\n )\n return {\n id: 'direct_edge_props',\n query: [\n 'MATCH (a:Address)-[r:FLOWS_TO]->(b:Address)',\n `WHERE (${predicates.join(' OR ')})`,\n 'RETURN a.address AS src, b.address AS dst, r.amount_sum AS amount_sum, r.amount_usd_sum AS amount_usd_sum, r.tx_count AS tx_count, r.first_tx_id AS first_tx_id, r.last_tx_id AS last_tx_id',\n `LIMIT ${pairs.length}`,\n ].join(' '),\n }\n}\n\nfunction numberValue(value: unknown): number | undefined {\n if (typeof value === 'number' && Number.isFinite(value)) return value\n if (typeof value === 'string' && value.trim()) {\n const parsed = Number(value)\n return Number.isFinite(parsed) ? parsed : undefined\n }\n return undefined\n}\n\nfunction isExchangeFlag(value: unknown): boolean {\n if (value === true) return true\n if (value === false || value === null || value === undefined) return false\n if (typeof value === 'string') {\n const normalized = value.trim().toLowerCase()\n return normalized === 'true' || normalized === '1'\n }\n if (typeof value === 'number') return value === 1\n return false\n}\n\nfunction rowTerminalAmount(row: Record<string, unknown>): number | undefined {\n const edgeProps = Array.isArray(row['edge_props']) ? row['edge_props'] as Array<Record<string, unknown>> : []\n const terminalEdge = edgeProps[edgeProps.length - 1]\n if (!terminalEdge) return undefined\n return numberValue(terminalEdge['amount_sum']) ?? numberValue(terminalEdge['amount_usd_sum'])\n}\n\nfunction rowsMatchingMinimumAmount(rows: Array<Record<string, unknown>>, minAmountSum: number): Array<Record<string, unknown>> {\n if (minAmountSum <= 0) return rows\n return rows.filter((row) => (rowTerminalAmount(row) ?? 0) >= minAmountSum)\n}\n\nfunction stringArrayValue(value: unknown): string[] | undefined {\n if (Array.isArray(value)) return value.map(String)\n if (typeof value === 'string' && value.trim()) return [value]\n return undefined\n}\n\nfunction uniqueStrings(values: string[] | undefined): string[] {\n return [...new Set(values ?? [])]\n}\n\nfunction hasExactExchangeLabel(labels: string[] | undefined): boolean {\n return (labels ?? []).some((label) => label.trim().toLowerCase() === 'exchange')\n}\n\nfunction nodeMetadataFromValue(value: unknown, fallbackAddress?: string): GraphNodeMetadata | undefined {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n return fallbackAddress ? { address: fallbackAddress } : undefined\n }\n const record = value as Record<string, unknown>\n const address = typeof record['address'] === 'string' ? record['address'] : fallbackAddress\n if (!address) return undefined\n return {\n address,\n labels: stringArrayValue(record['labels']),\n system_labels: stringArrayValue(record['system_labels']),\n address_type: typeof record['address_type'] === 'string' ? record['address_type'] : undefined,\n address_subtypes: stringArrayValue(record['address_subtypes']),\n is_exchange: isExchangeFlag(record['is_exchange']),\n }\n}\n\nfunction isExchangeFlow(flow: TraceFlow): boolean {\n return flow.terminal_exchange ||\n isExchangeFlag(flow.dst_node?.is_exchange) ||\n hasExactExchangeLabel(flow.dst_labels) ||\n hasExactExchangeLabel(flow.dst_node?.system_labels) ||\n hasExactExchangeLabel(flow.dst_node?.labels)\n}\n\nfunction isExchangeNode(metadata: GraphNodeMetadata | undefined, labels: string[] | undefined): boolean {\n return isExchangeFlag(metadata?.is_exchange) ||\n hasExactExchangeLabel(labels) ||\n hasExactExchangeLabel(metadata?.system_labels) ||\n hasExactExchangeLabel(metadata?.labels)\n}\n\nfunction rowTouchesExchangeBeforeTerminal(pathNodes: Array<GraphNodeMetadata | undefined>, nodeLabels: string[][], pathLength: number): boolean {\n for (let index = 0; index < Math.max(pathLength - 1, 0); index += 1) {\n if (isExchangeNode(pathNodes[index], nodeLabels[index])) return true\n }\n return false\n}\n\nfunction depositFromRow(row: Record<string, unknown>): TraceDeposit | null {\n const pathAddresses = stringArrayValue(row['addresses']) ?? []\n if (pathAddresses.length < 2) return null\n const nodeLabels = Array.isArray(row['node_labels']) ? row['node_labels'].map((labels) => stringArrayValue(labels) ?? []) : []\n const exchangeAddress = typeof row['exchange_address'] === 'string' ? row['exchange_address'] : pathAddresses[pathAddresses.length - 1]\n const edgeProps = Array.isArray(row['edge_props']) ? row['edge_props'] as Array<Record<string, unknown>> : []\n const terminalEdge = edgeProps[edgeProps.length - 1] ?? {}\n const pathNodes = Array.isArray(row['path_nodes'])\n ? row['path_nodes'].map((node, index) => nodeMetadataFromValue(node, pathAddresses[index])).filter((node): node is GraphNodeMetadata => Boolean(node))\n : undefined\n const depositIndex = pathAddresses.length - 2\n const depositNode = pathNodes?.find((node) => node.address === pathAddresses[depositIndex]) ?? pathNodes?.[depositIndex]\n if (isExchangeFlag(row['deposit_is_exchange']) || isExchangeNode(depositNode, nodeLabels[depositIndex])) return null\n const exchangeNode = {\n address: exchangeAddress,\n labels: stringArrayValue(row['exchange_display_labels']),\n system_labels: stringArrayValue(row['exchange_system_labels']) ?? stringArrayValue(row['exchange_labels']),\n address_type: typeof row['exchange_address_type'] === 'string' ? row['exchange_address_type'] : undefined,\n address_subtypes: stringArrayValue(row['exchange_address_subtypes']),\n is_exchange: true,\n }\n return {\n address: pathAddresses[pathAddresses.length - 2]!,\n exchangeAddress,\n exchangeLabels: stringArrayValue(row['exchange_labels']),\n exchangeNode,\n amount_sum: numberValue(terminalEdge['amount_sum']),\n amount_usd_sum: numberValue(terminalEdge['amount_usd_sum']),\n hops: numberValue(row['hops']) ?? pathAddresses.length - 1,\n path: pathAddresses,\n pathNodes,\n }\n}\n\nfunction flowsFromForwardRows(rows: Array<Record<string, unknown>>): { flows: TraceFlow[]; deposits: TraceDeposit[] } {\n const flows: TraceFlow[] = []\n const deposits: TraceDeposit[] = []\n const seenEdges = new Set<string>()\n for (const row of rows) {\n const pathAddresses = stringArrayValue(row['addresses']) ?? []\n const nodeLabels = Array.isArray(row['node_labels']) ? row['node_labels'].map((labels) => stringArrayValue(labels) ?? []) : []\n const pathNodes = Array.isArray(row['path_nodes'])\n ? row['path_nodes'].map((node, index) => nodeMetadataFromValue(node, pathAddresses[index]))\n : []\n const edgeProps = Array.isArray(row['edge_props']) ? row['edge_props'] as Array<Record<string, unknown>> : []\n if (rowTouchesExchangeBeforeTerminal(pathNodes, nodeLabels, pathAddresses.length)) continue\n const deposit = depositFromRow(row)\n if (deposit) deposits.push(deposit)\n for (let index = 0; index < pathAddresses.length - 1; index += 1) {\n const src = pathAddresses[index]!\n const dst = pathAddresses[index + 1]!\n const edge = edgeProps[index] ?? {}\n const amount = numberValue(edge['amount_sum']) ?? numberValue(edge['amount_usd_sum']) ?? 0\n const terminal = index === pathAddresses.length - 2\n const key = `${src}->${dst}`\n if (seenEdges.has(key)) continue\n seenEdges.add(key)\n flows.push({\n hop: index + 1,\n src,\n dst,\n amount_sum: amount,\n amount_usd_sum: numberValue(edge['amount_usd_sum']),\n tx_count: numberValue(edge['tx_count']),\n first_tx_id: typeof edge['first_tx_id'] === 'string' ? edge['first_tx_id'] : undefined,\n last_tx_id: typeof edge['last_tx_id'] === 'string' ? edge['last_tx_id'] : undefined,\n src_labels: nodeLabels[index],\n dst_labels: nodeLabels[index + 1],\n src_node: pathNodes[index],\n dst_node: pathNodes[index + 1],\n terminal_exchange: terminal,\n })\n }\n }\n return { flows, deposits }\n}\n\nasync function hydrateDirectEdgeProps(remoteClient: Client, network: string, flows: TraceFlow[], deposits: TraceDeposit[]): Promise<void> {\n const query = directEdgePropsQuery(flows)\n if (!query) return\n\n const batch = await callGraphBatch(remoteClient, network, [query])\n const edgeProps = new Map<string, Record<string, unknown>>()\n for (const row of resultsFor(batch, 'direct_edge_props')) {\n const src = typeof row['src'] === 'string' ? row['src'] : ''\n const dst = typeof row['dst'] === 'string' ? row['dst'] : ''\n if (!src || !dst) continue\n edgeProps.set(edgeKey(src, dst), row)\n }\n\n for (const flow of flows) {\n const props = edgeProps.get(edgeKey(flow.src, flow.dst))\n if (!props) continue\n flow.amount_sum = numberValue(props['amount_sum']) ?? flow.amount_sum\n flow.amount_usd_sum = numberValue(props['amount_usd_sum'])\n flow.tx_count = numberValue(props['tx_count'])\n flow.first_tx_id = typeof props['first_tx_id'] === 'string' ? props['first_tx_id'] : undefined\n flow.last_tx_id = typeof props['last_tx_id'] === 'string' ? props['last_tx_id'] : undefined\n }\n\n for (const deposit of deposits) {\n const props = edgeProps.get(edgeKey(deposit.address, deposit.exchangeAddress))\n if (!props) continue\n deposit.amount_sum = numberValue(props['amount_sum'])\n deposit.amount_usd_sum = numberValue(props['amount_usd_sum'])\n }\n}\n\nasync function collectProbeTrace(\n remoteClient: Client,\n options: Required<Pick<TraceFundsOptions, 'seedAddress' | 'network' | 'maxHops' | 'perAddressLimit' | 'minAmountSum'>> & Pick<TraceFundsOptions, 'includeDepositTraceback'>,\n): Promise<{ flows: TraceFlow[]; deposits: TraceDeposit[]; sourceMatches: SourceMatch[]; reverseLeads: ReverseLead[] }> {\n const forwardBatch = await callGraphBatch(remoteClient, options.network, [\n ...forwardExchangeQueries(options.seedAddress, Math.max(options.perAddressLimit * 20, 200), options.minAmountSum, options.maxHops),\n ])\n const forwardRows = rowsMatchingMinimumAmount((forwardBatch.facts?.queries ?? [])\n .filter((query) => query.id?.startsWith('forward_exchange_paths_'))\n .flatMap((query) => {\n if (query.ok === false) throw new Error(query.error || `Query failed: ${query.id}`)\n return query.results ?? []\n }), options.minAmountSum)\n const { flows, deposits } = flowsFromForwardRows(forwardRows)\n await hydrateDirectEdgeProps(remoteClient, options.network, flows, deposits)\n const uniqueDepositAddresses = [...new Set(deposits.map((deposit) => deposit.address))]\n\n const sourceMatches: SourceMatch[] = []\n if (options.includeDepositTraceback !== false && uniqueDepositAddresses.length > 0) {\n const backwardBatch = await callGraphBatch(\n remoteClient,\n options.network,\n uniqueDepositAddresses.slice(0, Math.max(1, Math.floor(20 / options.maxHops))).flatMap((address, index) => backwardSourceQueries(`backward_from_deposit_${index + 1}`, address, options.maxHops)),\n )\n for (const query of backwardBatch.facts?.queries ?? []) {\n for (const row of query.results ?? []) {\n const pathAddresses = stringArrayValue(row['addresses']) ?? []\n const pathNodes = Array.isArray(row['path_nodes'])\n ? row['path_nodes'].map((node, index) => nodeMetadataFromValue(node, pathAddresses[index])).filter((node): node is GraphNodeMetadata => Boolean(node))\n : undefined\n const depositAddress = typeof row['deposit_address'] === 'string' ? row['deposit_address'] : pathAddresses[0]\n const sourceExchange = typeof row['source_exchange'] === 'string' ? row['source_exchange'] : pathAddresses[pathAddresses.length - 1]\n if (!depositAddress || !sourceExchange) continue\n const sourceNode = {\n address: sourceExchange,\n labels: stringArrayValue(row['source_display_labels']),\n system_labels: stringArrayValue(row['source_system_labels']) ?? stringArrayValue(row['source_labels']),\n address_type: typeof row['source_address_type'] === 'string' ? row['source_address_type'] : undefined,\n address_subtypes: stringArrayValue(row['source_address_subtypes']),\n }\n sourceMatches.push({\n deposit_address: depositAddress,\n source_exchange: sourceExchange,\n source_labels: stringArrayValue(row['source_labels']),\n sourceNode,\n hops: numberValue(row['hops']) ?? Math.max(pathAddresses.length - 1, 0),\n path: pathAddresses,\n pathNodes,\n })\n }\n }\n }\n\n const reverseLeads: ReverseLead[] = []\n if (options.includeDepositTraceback !== false && uniqueDepositAddresses.length > 0) {\n const reverseBatch = await callGraphBatch(remoteClient, options.network, [reverseLeadsQuery(uniqueDepositAddresses)])\n for (const row of resultsFor(reverseBatch, 'reverse_1hop')) {\n const address = typeof row['address'] === 'string' ? row['address'] : ''\n const depositAddress = typeof row['deposit_address'] === 'string' ? row['deposit_address'] : ''\n if (!address || !depositAddress) continue\n const labels = stringArrayValue(row['display_labels']) ?? stringArrayValue(row['labels']) ?? []\n const degreeIn = numberValue(row['degree_in']) ?? 0\n const degreeOut = numberValue(row['degree_out']) ?? 0\n const totalVolume = numberValue(row['total_volume_usd']) ?? 0\n const reason = labels.length > 0 ? 'labeled_entity' : degreeIn > 50 ? 'fan_in_hub' : degreeOut > 50 ? 'fan_out_hub' : totalVolume > 100000 ? 'high_volume_sender' : ''\n if (!reason) continue\n reverseLeads.push({\n address,\n labels,\n node: {\n address,\n labels,\n system_labels: stringArrayValue(row['system_labels']),\n address_type: typeof row['address_type'] === 'string' ? row['address_type'] : undefined,\n address_subtypes: stringArrayValue(row['address_subtypes']),\n },\n degree_in: degreeIn,\n degree_out: degreeOut,\n total_volume_usd: totalVolume,\n deposit_address: depositAddress,\n amount_usd: numberValue(row['amount_usd']),\n reason,\n })\n }\n }\n\n return { flows, deposits, sourceMatches, reverseLeads }\n}\n\nfunction buildAliases(seedAddress: string, deposits: TraceDeposit[], sourceMatches: SourceMatch[], reverseLeads: ReverseLead[]): AliasTracker {\n const aliases = new AliasTracker()\n aliases.assign(seedAddress, 'V')\n for (const deposit of deposits) {\n for (const address of deposit.path.slice(1, -2)) aliases.assign(address, 'I')\n aliases.assign(deposit.address, 'D')\n aliases.assign(deposit.exchangeAddress, 'E')\n }\n for (const source of sourceMatches) {\n aliases.assign(source.source_exchange, 'X')\n for (const address of source.path.slice(1, -1)) aliases.assign(address, 'I')\n }\n for (const lead of reverseLeads) aliases.assign(lead.address, 'L')\n return aliases\n}\n\nfunction buildGraph(seedAddress: string, network: string, flows: TraceFlow[], deposits: TraceDeposit[], sourceMatches: SourceMatch[], reverseLeads: ReverseLead[]): Record<string, unknown> {\n type NodeAccumulator = {\n in: number\n out: number\n labels: string[]\n systemLabels: string[]\n addressType?: string\n addressSubtypes: string[]\n roles: Set<string>\n }\n\n const totals = new Map<string, NodeAccumulator>()\n const ensure = (address: string) => {\n if (!totals.has(address)) {\n totals.set(address, {\n in: 0,\n out: 0,\n labels: [],\n systemLabels: [],\n addressSubtypes: [],\n roles: new Set(address === seedAddress ? ['seed'] : []),\n })\n }\n return totals.get(address)!\n }\n const mergeNode = (address: string, metadata?: GraphNodeMetadata, role?: string, systemLabelsFallback?: string[]) => {\n const node = ensure(address)\n node.labels = uniqueStrings([...node.labels, ...(metadata?.labels ?? [])])\n node.systemLabels = uniqueStrings([...node.systemLabels, ...(metadata?.system_labels ?? []), ...(systemLabelsFallback ?? [])])\n if (metadata?.address_type) node.addressType = metadata.address_type\n node.addressSubtypes = uniqueStrings([...node.addressSubtypes, ...(metadata?.address_subtypes ?? [])])\n if (role) node.roles.add(role)\n return node\n }\n\n for (const flow of flows) {\n const src = mergeNode(flow.src, flow.src_node, undefined, flow.src_labels)\n src.out += flow.amount_usd_sum ?? flow.amount_sum\n const dst = mergeNode(flow.dst, flow.dst_node, undefined, flow.dst_labels)\n dst.in += flow.amount_usd_sum ?? flow.amount_sum\n if (isExchangeFlow(flow)) dst.roles.add('exchange')\n }\n for (const deposit of deposits) {\n for (const node of deposit.pathNodes ?? []) mergeNode(node.address, node)\n mergeNode(deposit.address, deposit.pathNodes?.find((node) => node.address === deposit.address), 'deposit_candidate')\n mergeNode(deposit.exchangeAddress, deposit.exchangeNode, 'exchange', deposit.exchangeLabels)\n }\n for (const source of sourceMatches) {\n for (const node of source.pathNodes ?? []) mergeNode(node.address, node)\n mergeNode(source.source_exchange, source.sourceNode, 'exchange', source.source_labels)\n }\n for (const lead of reverseLeads) {\n mergeNode(lead.address, lead.node ?? { address: lead.address, labels: lead.labels }, 'lead')\n const deposit = ensure(lead.deposit_address)\n deposit.in += lead.amount_usd ?? 0\n }\n const sourceMatchEdges = sourceMatches.flatMap((source) => {\n const path = source.path.length >= 2 ? source.path : [source.deposit_address, source.source_exchange]\n const edges: Array<Record<string, unknown>> = []\n for (let index = path.length - 1; index > 0; index -= 1) {\n edges.push({\n source: path[index],\n target: path[index - 1],\n edge_type: 'flows_to',\n usd_amount: 0,\n amount_sum: 0,\n tx_count: 0,\n direction: 'traceback',\n })\n }\n return edges\n })\n\n return normalizeGraphPayload({\n schema: 'chain-insights.graph.v1',\n nodes: [...totals.entries()].map(([address, data]) => ({\n id: address,\n address,\n node_type: 'address',\n labels: uniqueStrings(data.labels),\n ...(data.systemLabels.length > 0 ? { system_labels: uniqueStrings(data.systemLabels) } : {}),\n ...(data.addressType ? { address_type: data.addressType } : {}),\n ...(data.addressSubtypes.length > 0 ? { address_subtypes: uniqueStrings(data.addressSubtypes) } : {}),\n ...(data.roles.size > 0 ? { roles: [...data.roles] } : {}),\n flow_in_usd: data.in,\n flow_out_usd: data.out,\n })),\n edges: [\n ...flows.map((flow) => ({\n source: flow.src,\n target: flow.dst,\n edge_type: 'flows_to',\n usd_amount: flow.amount_usd_sum ?? flow.amount_sum,\n amount_sum: flow.amount_sum,\n tx_count: flow.tx_count ?? 0,\n first_tx_id: flow.first_tx_id,\n last_tx_id: flow.last_tx_id,\n terminal_exchange: flow.terminal_exchange,\n })),\n ...sourceMatchEdges,\n ...reverseLeads.map((lead) => ({\n source: lead.address,\n target: lead.deposit_address,\n edge_type: 'flows_to',\n usd_amount: lead.amount_usd ?? 0,\n amount_sum: lead.amount_usd ?? 0,\n tx_count: 0,\n direction: 'reverse_1hop_lead',\n })),\n ],\n flows,\n deposits,\n source_matches: sourceMatches,\n reverse_leads: reverseLeads,\n edge_anchors: [],\n metadata: {\n seed_address: seedAddress,\n network,\n generated_at: new Date().toISOString(),\n },\n })\n}\n\nfunction buildMarkdownReport(seedAddress: string, network: string, flows: TraceFlow[], deposits: TraceDeposit[], sourceMatches: SourceMatch[], reverseLeads: ReverseLead[], aliases: AliasTracker, graphPath: string, schemaPath: string): string {\n const lines = [\n `# Trace Funds: ${seedAddress}`,\n '',\n `Network: \\`${network}\\``,\n `Schema: \\`${schemaPath}\\``,\n `Graph: \\`${graphPath}\\``,\n '',\n '## Probe Summary',\n '',\n `- Exchange endpoint(s): ${[...new Set(deposits.map((deposit) => aliases.alias(deposit.exchangeAddress) ?? deposit.exchangeAddress))].join(', ') || 'none'}`,\n `- Deposit candidate(s): ${[...new Set(deposits.map((deposit) => aliases.alias(deposit.address) ?? deposit.address))].join(', ') || 'none'}`,\n `- Traceback source exchange path(s): ${sourceMatches.length}`,\n `- Reverse 1-hop lead(s): ${reverseLeads.length}`,\n '',\n '## Flow Table',\n '',\n '| Hop | Source | Destination | amount_sum | amount_usd_sum | tx_count | first_tx_id | terminal_exchange |',\n '|---:|---|---|---:|---:|---:|---|---|',\n ...flows.map((flow) => [\n `| ${flow.hop}`,\n `\\`${flow.src}\\``,\n `\\`${flow.dst}\\``,\n flow.amount_sum,\n flow.amount_usd_sum ?? '',\n flow.tx_count ?? '',\n flow.first_tx_id ? `\\`${flow.first_tx_id}\\`` : '',\n flow.terminal_exchange ? 'yes' : 'no',\n ].join(' | ') + ' |'),\n '',\n '## Mermaid',\n '',\n '```mermaid',\n 'flowchart LR',\n ...flows.map((flow, index) =>\n ` n${index}[\"${flow.src.slice(0, 8)}...\"] -->|\"amount_sum ${flow.amount_sum}${flow.terminal_exchange ? '; exchange endpoint' : ''}\"| m${index}[\"${flow.dst.slice(0, 8)}...\"]`\n ),\n '```',\n ]\n return lines.join('\\n') + '\\n'\n}\n\nfunction probeEvidence(seedAddress: string, network: string, schemaPath: string, aliases: AliasTracker, flows: TraceFlow[], deposits: TraceDeposit[], sourceMatches: SourceMatch[], reverseLeads: ReverseLead[], evidenceSource = 'track_funds'): Record<string, unknown> {\n return {\n schema: 'chain-insights.probe_evidence.v1',\n source: evidenceSource,\n network,\n seed_address: seedAddress,\n schema_ref: schemaPath,\n address_map: aliases.addressMap(),\n fund_flows: [\n ...deposits.map((deposit, index) => ({\n id: `F${index + 1}`,\n type: 'deposit',\n path: deposit.path.map((address) => aliases.alias(address) ?? address),\n deposit: aliases.alias(deposit.address),\n exchange: aliases.alias(deposit.exchangeAddress),\n amount_sum: deposit.amount_sum,\n amount_usd_sum: deposit.amount_usd_sum,\n hops: deposit.hops,\n })),\n ...sourceMatches.map((source, index) => ({\n id: `S${index + 1}`,\n type: 'source',\n path: [...source.path].reverse().map((address) => aliases.alias(address) ?? address),\n source_exchange: aliases.alias(source.source_exchange),\n deposit: aliases.alias(source.deposit_address),\n hops: source.hops,\n })),\n ],\n reverse_leads: reverseLeads.map((lead) => ({\n alias: aliases.alias(lead.address),\n address: lead.address,\n reason: lead.reason,\n labels: lead.labels,\n deposit: aliases.alias(lead.deposit_address),\n amount_usd: lead.amount_usd,\n })),\n outgoing_flows: flows.map((flow) => ({\n hop: flow.hop,\n src: aliases.alias(flow.src) ?? flow.src,\n dst: aliases.alias(flow.dst) ?? flow.dst,\n amount_sum: flow.amount_sum,\n amount_usd_sum: flow.amount_usd_sum,\n tx_count: flow.tx_count,\n first_tx_id: flow.first_tx_id,\n last_tx_id: flow.last_tx_id,\n terminal_exchange: flow.terminal_exchange,\n })),\n }\n}\n\nfunction tableCsv(flows: TraceFlow[]): string {\n const rows = ['hop,src,dst,amount_sum,amount_usd_sum,tx_count,first_tx_id,last_tx_id,terminal_exchange']\n for (const flow of flows) {\n rows.push([\n flow.hop,\n flow.src,\n flow.dst,\n flow.amount_sum,\n flow.amount_usd_sum ?? '',\n flow.tx_count ?? '',\n flow.first_tx_id ?? '',\n flow.last_tx_id ?? '',\n flow.terminal_exchange ? 'true' : 'false',\n ].map((value) => JSON.stringify(String(value))).join(','))\n }\n return rows.join('\\n') + '\\n'\n}\n\nfunction htmlEscape(value: unknown): string {\n return String(value ?? '')\n .replaceAll('&', '&amp;')\n .replaceAll('<', '&lt;')\n .replaceAll('>', '&gt;')\n .replaceAll('\"', '&quot;')\n .replaceAll(\"'\", '&#39;')\n}\n\nfunction buildTableHtml(seedAddress: string, network: string, flows: TraceFlow[], deposits: TraceDeposit[], sourceMatches: SourceMatch[], reverseLeads: ReverseLead[]): string {\n const headers = [\n 'hop',\n 'src',\n 'dst',\n 'amount_sum',\n 'amount_usd_sum',\n 'tx_count',\n 'first_tx_id',\n 'last_tx_id',\n 'terminal_exchange_display',\n ] as const\n const headerLabels: Record<typeof headers[number], string> = {\n hop: 'Hop',\n src: 'Source',\n dst: 'Destination',\n amount_sum: 'amount_sum',\n amount_usd_sum: 'amount_usd_sum',\n tx_count: 'tx_count',\n first_tx_id: 'first_tx_id',\n last_tx_id: 'last_tx_id',\n terminal_exchange_display: 'terminal_exchange',\n }\n const rows = flows.map((flow) => {\n const values: Record<string, unknown> = {\n ...flow,\n terminal_exchange_display: flow.terminal_exchange ? 'yes' : 'no',\n }\n return `<tr>${headers.map((header) => `<td>${htmlEscape(values[header])}</td>`).join('')}</tr>`\n }).join('\\n')\n\n return `<!doctype html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<title>Trace Funds Table - ${htmlEscape(seedAddress)}</title>\n<style>\n :root { color-scheme: dark; font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif; background: #0b0d12; color: #f4f2ea; }\n body { margin: 0; background: #0b0d12; color: #f4f2ea; }\n main { padding: 24px; }\n h1 { font-size: 20px; margin: 0 0 8px; font-weight: 650; }\n .meta { display: grid; gap: 6px; margin: 0 0 20px; color: rgba(244,242,234,.72); font-size: 13px; }\n .summary { display: flex; flex-wrap: wrap; gap: 8px; margin: 0 0 20px; }\n .pill { border: 1px solid rgba(242,221,166,.25); background: rgba(242,221,166,.08); border-radius: 999px; padding: 6px 10px; font-size: 12px; color: #f2dda6; }\n .table-wrap { overflow: auto; border: 1px solid rgba(255,255,255,.1); border-radius: 8px; background: #10131b; }\n table { border-collapse: collapse; width: 100%; min-width: 1180px; font-size: 12px; }\n th, td { border-bottom: 1px solid rgba(255,255,255,.08); padding: 8px 10px; text-align: left; vertical-align: top; }\n th { position: sticky; top: 0; background: #161a24; color: #f2dda6; font-weight: 600; z-index: 1; }\n td { color: rgba(244,242,234,.86); font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }\n tr:hover td { background: rgba(242,221,166,.045); }\n</style>\n</head>\n<body>\n<main>\n <h1>Trace Funds Table</h1>\n <div class=\"meta\">\n <div>Network: <strong>${htmlEscape(network)}</strong></div>\n <div>Seed: <strong>${htmlEscape(seedAddress)}</strong></div>\n <div>Generated: <strong>${htmlEscape(new Date().toISOString())}</strong></div>\n </div>\n <div class=\"summary\">\n <span class=\"pill\">${flows.length} FLOWS_TO edges</span>\n <span class=\"pill\">${deposits.length} deposit candidates</span>\n <span class=\"pill\">${sourceMatches.length} traceback source paths</span>\n <span class=\"pill\">${reverseLeads.length} reverse 1-hop leads</span>\n </div>\n <div class=\"table-wrap\">\n <table>\n <thead><tr>${headers.map((header) => `<th>${htmlEscape(headerLabels[header])}</th>`).join('')}</tr></thead>\n <tbody>\n${rows}\n </tbody>\n </table>\n </div>\n</main>\n</body>\n</html>\n`\n}\n\nfunction summarize(seedAddress: string, network: string, flows: TraceFlow[], sourceMatches: SourceMatch[], reverseLeads: ReverseLead[], aliases: AliasTracker, files: TraceFundsResult['files'], continuation: TraceFundsResult['continuation']): string {\n const totalAmount = flows.reduce((sum, flow) => sum + flow.amount_sum, 0)\n const byHop = new Map<number, number>()\n for (const flow of flows) byHop.set(flow.hop, (byHop.get(flow.hop) ?? 0) + 1)\n const depositCount = continuation.depositAddresses.length\n const exchangeCount = continuation.exchangeAddresses.length\n return [\n `Trace complete for ${network}:${seedAddress}`,\n '',\n `Facts: ${flows.length} FLOWS_TO edge(s), sum of traced edge amount_sum values ${Number(totalAmount.toFixed(8))}.`,\n `By hop: ${[...byHop.entries()].map(([hop, count]) => `hop ${hop}: ${count}`).join(', ') || 'none'}.`,\n `Exchange endpoints reached: ${exchangeCount}. Deposit candidate address(es): ${depositCount}.`,\n `Traceback source path(s): ${sourceMatches.length}. Reverse 1-hop lead(s): ${reverseLeads.length}.`,\n '',\n 'Files written:',\n `- schema: ${files.schema}`,\n `- compact evidence JSON: ${files.compactEvidence}`,\n `- graph JSON: ${files.graph}`,\n `- graph HTML: ${files.graphHtml}`,\n `- table CSV: ${files.table}`,\n `- table HTML: ${files.tableHtml}`,\n `- report: ${files.report}`,\n '',\n `Continuation hint: ${continuation.hint}`,\n continuation.depositAddresses.length > 0\n ? `Deposit candidates: ${continuation.depositAddresses.map((address) => aliases.alias(address) ?? address).join(', ')}`\n : 'Deposit candidates: none reached in this bounded trace.',\n continuation.nextHopAddresses.length > 0\n ? `Next addresses: ${continuation.nextHopAddresses.join(', ')}`\n : 'Next addresses: none found in this trace.',\n ].join('\\n')\n}\n\nexport async function runFundFlowProbe(\n remoteClient: Client,\n _config: Pick<InvestigatorConfig, 'dataDir' | 'serverPort'>,\n options: TraceFundsOptions,\n): Promise<TraceFundsResult> {\n const seedAddress = options.seedAddress.trim()\n const network = options.network.trim()\n if (!seedAddress) throw new Error('seed_address is required')\n if (!network) throw new Error('network is required')\n\n const maxHops = clampInt(options.maxHops, 3, 1, 5)\n const perAddressLimit = clampInt(options.perAddressLimit, 5, 1, 10)\n const minAmountSum = Math.max(0, options.minAmountSum ?? 0)\n const evidenceSource = options.evidenceSource ?? 'track_funds'\n const paths = workspaceOutputPaths()\n await ensureDirs(paths)\n\n const schemaResult = await loadOrCaptureTopologySchema(remoteClient, paths, network)\n const { flows, deposits, sourceMatches, reverseLeads } = await collectProbeTrace(remoteClient, { seedAddress, network, maxHops, perAddressLimit, minAmountSum, includeDepositTraceback: options.includeDepositTraceback })\n const aliases = buildAliases(seedAddress, deposits, sourceMatches, reverseLeads)\n const slug = `${new Date().toISOString().replace(/[-:]/g, '').replace(/\\.\\d{3}Z$/, 'Z')}_${sanitizeSegment(seedAddress.slice(0, 16))}`\n const compact = probeEvidence(seedAddress, network, schemaResult.filePath, aliases, flows, deposits, sourceMatches, reverseLeads, evidenceSource)\n const graph = buildGraph(seedAddress, network, flows, deposits, sourceMatches, reverseLeads)\n\n const compactPath = path.join(paths.reportTablesRoot, `${slug}.compact-evidence.json`)\n const graphPath = path.join(paths.reportGraphsRoot, `${slug}.graph.json`)\n const graphHtmlPath = path.join(paths.reportsRoot, `${slug}.graph.html`)\n const tablePath = path.join(paths.reportTablesRoot, `${slug}.flows.csv`)\n const tableHtmlPath = path.join(paths.reportsRoot, `${slug}.table.html`)\n const reportPath = path.join(paths.reportsRoot, `${slug}.trace-report.md`)\n const { generateInlineGraphHtml } = await import('../viz/html-generator.js')\n\n await writeFile(compactPath, JSON.stringify(compact, null, 2) + '\\n', { mode: 0o600 })\n await writeFile(graphPath, JSON.stringify(graph, null, 2) + '\\n', { mode: 0o600 })\n await writeFile(graphHtmlPath, generateInlineGraphHtml(graph), { mode: 0o600 })\n await writeFile(tablePath, tableCsv(flows), { mode: 0o600 })\n await writeFile(tableHtmlPath, buildTableHtml(seedAddress, network, flows, deposits, sourceMatches, reverseLeads), { mode: 0o600 })\n await writeFile(reportPath, buildMarkdownReport(seedAddress, network, flows, deposits, sourceMatches, reverseLeads, aliases, graphPath, schemaResult.filePath), { mode: 0o600 })\n\n if (options.caseId) {\n const { EvidenceStore } = await import('../cases/index.js')\n await EvidenceStore.append(options.caseId, {\n source: evidenceSource,\n queryParams: `network=${network} seed_address=${seedAddress} max_hops=${maxHops} per_address_limit=${perAddressLimit} min_amount_sum=${minAmountSum}`,\n content: JSON.stringify({\n schema: 'chain-insights.evidence_pointer.v1',\n source: evidenceSource,\n network,\n seed_address: seedAddress,\n address_map: aliases.compactAddressMap(),\n files: {\n compactEvidence: compactPath,\n graph: graphPath,\n graphHtml: graphHtmlPath,\n table: tablePath,\n tableHtml: tableHtmlPath,\n report: reportPath,\n },\n facts: {\n flow_count: flows.length,\n deposit_candidates: [...new Set(deposits.map((deposit) => aliases.alias(deposit.address) ?? deposit.address))],\n exchange_endpoints: [...new Set(deposits.map((deposit) => aliases.alias(deposit.exchangeAddress) ?? deposit.exchangeAddress))],\n traceback_source_paths: sourceMatches.length,\n reverse_leads: reverseLeads.length,\n },\n }, null, 2),\n })\n }\n\n const depositAddresses = [...new Set(deposits.map((deposit) => deposit.address))]\n const exchangeAddresses = [...new Set(deposits.map((deposit) => deposit.exchangeAddress))]\n const leaves: string[] = []\n const continuation = {\n nextHopAddresses: leaves.slice(0, 20),\n depositAddresses,\n exchangeAddresses,\n hint: depositAddresses.length > 0\n ? `Found ${depositAddresses.length} deposit candidate(s), defined as the address one hop before an exchange endpoint. Do not continue through exchange nodes.`\n : leaves.length > 0\n ? `No exchange endpoint reached yet. Continue from ${leaves.length} non-exchange leaf destination(s) with the same tool, or raise the result budget if the current trace stopped early.`\n : 'No exchange endpoint or non-exchange leaf destinations found; inspect graph/report files or lower min_amount_sum.',\n }\n const files = {\n schema: schemaResult.filePath,\n compactEvidence: compactPath,\n graph: graphPath,\n graphHtml: graphHtmlPath,\n table: tablePath,\n tableHtml: tableHtmlPath,\n report: reportPath,\n }\n\n return {\n summaryText: summarize(seedAddress, network, flows, sourceMatches, reverseLeads, aliases, files, continuation),\n compactEvidence: compact,\n graphData: graph,\n files,\n continuation,\n addressMap: aliases.compactAddressMap(),\n }\n}\n","import type { Client } from '@modelcontextprotocol/sdk/client/index.js'\nimport type { ContentBlock } from '@modelcontextprotocol/sdk/types.js'\nimport { normalizeGraphPayload } from '../viz/graph-normalizer.js'\n\ntype RemoteToolResult = {\n content?: ContentBlock[]\n isError?: boolean\n}\n\ntype ParsedGraphBatch = {\n facts?: {\n queries?: Array<{\n id?: string\n ok?: boolean\n results?: Array<Record<string, unknown>>\n error?: string\n }>\n }\n}\n\ntype StakeSubjectRole = 'address' | 'coldkey' | 'hotkey'\ntype StakeTopologyGraph = 'live_topology' | 'archive_topology'\n\nexport interface StakeInsightsOptions {\n network: string\n address?: string\n coldkey?: string\n hotkey?: string\n netuid?: number\n startTimestampMs?: number\n endTimestampMs?: number\n startBlock?: number\n endBlock?: number\n depth?: number\n maxHops?: number\n}\n\nexport interface StakeInsightsResult {\n summaryText: string\n structuredContent: {\n schema: 'chain-insights.result.v1'\n tool: 'stake_insights'\n facts: Record<string, unknown>\n hint: string\n }\n graphData: Record<string, unknown>\n}\n\ntype QueryFailure = {\n id: string\n error: string\n}\n\ntype StakeRelationship = {\n coldkey: string\n hotkey: string\n netuid?: number\n amount?: number\n source_role?: string\n destination_role?: string\n stake_added_amount?: number\n stake_removed_amount?: number\n stake_moved_in_amount?: number\n stake_moved_out_amount?: number\n net_stake_change?: number\n stake_event_count?: number\n first_seen_timestamp?: number\n last_seen_timestamp?: number\n first_activity_timestamp?: number\n last_activity_timestamp?: number\n first_tx_id?: string\n last_tx_id?: string\n active_days?: number\n granularity?: string\n source_stake_rows?: number\n source_backend?: string\n topology_graph: StakeTopologyGraph\n}\n\nconst STAKE_INSIGHTS_QUERY_TIMEOUT_SECONDS = 120\nconst STAKE_INSIGHTS_REQUEST_TIMEOUT_MS = 5 * 60 * 1000\n\nfunction escapeCypherString(value: string): string {\n return value.replaceAll('\\\\', '\\\\\\\\').replaceAll('\"', '\\\\\"')\n}\n\nfunction textFromToolResult(result: RemoteToolResult): string {\n return (result.content ?? [])\n .filter((item): item is Extract<ContentBlock, { type: 'text' }> => item.type === 'text')\n .map((item) => item.text)\n .join('\\n')\n}\n\nfunction parseGraphBatchResult(result: RemoteToolResult): ParsedGraphBatch {\n const text = textFromToolResult(result).trim()\n if (!text) throw new Error('graph_query_batch returned no text content')\n const parsed = JSON.parse(text) as ParsedGraphBatch\n if (!parsed.facts?.queries) throw new Error('graph_query_batch response did not include facts.queries')\n return parsed\n}\n\nfunction stringValue(value: unknown): string | undefined {\n return typeof value === 'string' && value.trim() ? value.trim() : undefined\n}\n\nfunction numberValue(value: unknown): number | undefined {\n if (typeof value === 'number' && Number.isFinite(value)) return value\n if (typeof value === 'string' && value.trim()) {\n const parsed = Number(value)\n if (Number.isFinite(parsed)) return parsed\n }\n return undefined\n}\n\nfunction nonZeroNumber(value: unknown): number | undefined {\n const parsed = numberValue(value)\n return parsed !== undefined && parsed !== 0 ? parsed : undefined\n}\n\nfunction clampInt(value: number | undefined, fallback: number, min: number, max: number): number {\n if (!Number.isFinite(value)) return fallback\n return Math.max(min, Math.min(max, Math.trunc(value as number)))\n}\n\nfunction resolveSubject(options: StakeInsightsOptions): { role: StakeSubjectRole; address: string } {\n const candidates = [\n ['address', options.address] as const,\n ['coldkey', options.coldkey] as const,\n ['hotkey', options.hotkey] as const,\n ].filter((entry): entry is readonly [StakeSubjectRole, string] => !!entry[1]?.trim())\n\n if (candidates.length !== 1) {\n throw new Error('Provide exactly one of address, coldkey, or hotkey')\n }\n\n return { role: candidates[0][0], address: candidates[0][1].trim() }\n}\n\nfunction validateOptions(options: StakeInsightsOptions): {\n network: string\n subject: { role: StakeSubjectRole; address: string }\n depth: number\n} {\n const network = options.network.trim()\n if (!network) throw new Error('network is required')\n if (options.startBlock !== undefined || options.endBlock !== undefined) {\n throw new Error('Block windows are not available on the current stake graph surface; use start_timestamp_ms/end_timestamp_ms')\n }\n\n return {\n network,\n subject: resolveSubject(options),\n depth: clampInt(options.depth ?? options.maxHops, 1, 1, 3),\n }\n}\n\nfunction subjectPredicate(subject: { role: StakeSubjectRole; address: string }): string {\n const address = escapeCypherString(subject.address)\n if (subject.role === 'coldkey') return `coldkey.address = \"${address}\"`\n if (subject.role === 'hotkey') return `hotkey.address = \"${address}\"`\n return `(coldkey.address = \"${address}\" OR hotkey.address = \"${address}\")`\n}\n\nfunction stakeRelationshipQuery(\n topologyGraph: StakeTopologyGraph,\n subject: { role: StakeSubjectRole; address: string },\n options: StakeInsightsOptions,\n depth: number,\n): { id: string; query: string } {\n const predicates = [subjectPredicate(subject)]\n if (options.netuid !== undefined) predicates.push(`stake.netuid = ${Math.trunc(options.netuid)}`)\n if (options.startTimestampMs !== undefined) predicates.push(`stake.last_activity_timestamp >= ${Math.trunc(options.startTimestampMs)}`)\n if (options.endTimestampMs !== undefined) predicates.push(`stake.first_activity_timestamp <= ${Math.trunc(options.endTimestampMs)}`)\n const limit = Math.min(500, Math.max(50, depth * 100))\n\n return {\n id: topologyGraph === 'live_topology' ? 'live_stake_relationships' : 'archive_stake_relationships',\n query: [\n `USE ${topologyGraph}`,\n 'MATCH (coldkey:Address)-[stake:STAKES_IN]->(hotkey:Address)',\n `WHERE ${predicates.join(' AND ')}`,\n [\n 'RETURN coldkey.address AS coldkey',\n 'hotkey.address AS hotkey',\n 'stake.netuid AS netuid',\n 'stake.amount AS amount',\n 'stake.source_role AS source_role',\n 'stake.destination_role AS destination_role',\n 'stake.stake_added_amount AS stake_added_amount',\n 'stake.stake_removed_amount AS stake_removed_amount',\n 'stake.stake_moved_in_amount AS stake_moved_in_amount',\n 'stake.stake_moved_out_amount AS stake_moved_out_amount',\n 'stake.net_stake_change AS net_stake_change',\n 'stake.stake_event_count AS stake_event_count',\n 'stake.first_seen_timestamp AS first_seen_timestamp',\n 'stake.last_seen_timestamp AS last_seen_timestamp',\n 'stake.first_activity_timestamp AS first_activity_timestamp',\n 'stake.last_activity_timestamp AS last_activity_timestamp',\n 'stake.first_tx_id AS first_tx_id',\n 'stake.last_tx_id AS last_tx_id',\n 'stake.active_days AS active_days',\n 'stake.granularity AS granularity',\n 'stake.source_stake_rows AS source_stake_rows',\n 'stake.source_backend AS source_backend',\n `\"${topologyGraph}\" AS topology_graph`,\n ].join(', '),\n 'ORDER BY stake.amount DESC',\n `LIMIT ${limit}`,\n ].join(' '),\n }\n}\n\nasync function callGraphBatch(\n remoteClient: Client,\n network: string,\n queries: Array<{ id: string; query: string }>,\n): Promise<ParsedGraphBatch> {\n const result = await remoteClient.callTool(\n {\n name: 'graph_query_batch',\n arguments: {\n network,\n queries,\n per_query_timeout_seconds: STAKE_INSIGHTS_QUERY_TIMEOUT_SECONDS,\n },\n },\n undefined,\n {\n timeout: STAKE_INSIGHTS_REQUEST_TIMEOUT_MS,\n maxTotalTimeout: STAKE_INSIGHTS_REQUEST_TIMEOUT_MS,\n },\n ) as RemoteToolResult\n if (result.isError) throw new Error(textFromToolResult(result) || 'graph_query_batch failed')\n return parseGraphBatchResult(result)\n}\n\nfunction topologyGraphForQueryId(id: string): StakeTopologyGraph {\n return id.startsWith('archive_') ? 'archive_topology' : 'live_topology'\n}\n\nfunction collectRelationships(batch: ParsedGraphBatch): {\n live: StakeRelationship[]\n archive: StakeRelationship[]\n failures: QueryFailure[]\n evidence: Array<Record<string, unknown>>\n} {\n const failures: QueryFailure[] = []\n const evidence: Array<Record<string, unknown>> = []\n const live: StakeRelationship[] = []\n const archive: StakeRelationship[] = []\n\n for (const query of batch.facts?.queries ?? []) {\n const id = query.id ?? 'unknown'\n const topologyGraph = topologyGraphForQueryId(id)\n if (query.ok === false) {\n failures.push({ id, error: query.error || 'unknown error' })\n evidence.push({ id, topology_graph: topologyGraph, ok: false, row_count: 0, error: query.error || 'unknown error' })\n continue\n }\n\n const rows = (query.results ?? []).map((row) => normalizeRelationship(row, topologyGraph))\n if (topologyGraph === 'live_topology') live.push(...rows)\n else archive.push(...rows)\n evidence.push({\n id,\n topology_graph: topologyGraph,\n ok: true,\n row_count: rows.length,\n source_backends: [...new Set(rows.map((row) => row.source_backend).filter(Boolean))],\n })\n }\n\n return { live, archive, failures, evidence }\n}\n\nfunction normalizeRelationship(row: Record<string, unknown>, topologyGraph: StakeTopologyGraph): StakeRelationship {\n return {\n coldkey: String(row['coldkey'] ?? ''),\n hotkey: String(row['hotkey'] ?? ''),\n netuid: numberValue(row['netuid']),\n amount: numberValue(row['amount']),\n source_role: stringValue(row['source_role']),\n destination_role: stringValue(row['destination_role']),\n stake_added_amount: numberValue(row['stake_added_amount']),\n stake_removed_amount: numberValue(row['stake_removed_amount']),\n stake_moved_in_amount: numberValue(row['stake_moved_in_amount']),\n stake_moved_out_amount: numberValue(row['stake_moved_out_amount']),\n net_stake_change: numberValue(row['net_stake_change']),\n stake_event_count: numberValue(row['stake_event_count']),\n first_seen_timestamp: numberValue(row['first_seen_timestamp']),\n last_seen_timestamp: numberValue(row['last_seen_timestamp']),\n first_activity_timestamp: numberValue(row['first_activity_timestamp']),\n last_activity_timestamp: numberValue(row['last_activity_timestamp']),\n first_tx_id: stringValue(row['first_tx_id']),\n last_tx_id: stringValue(row['last_tx_id']),\n active_days: numberValue(row['active_days']),\n granularity: stringValue(row['granularity']),\n source_stake_rows: numberValue(row['source_stake_rows']),\n source_backend: stringValue(row['source_backend']) ?? (topologyGraph === 'live_topology' ? 'memgraph_live' : 'starrocks_archive'),\n topology_graph: topologyGraph,\n }\n}\n\nfunction firstTimestamp(rows: StakeRelationship[]): number | undefined {\n const timestamps = rows.map((row) => row.first_activity_timestamp).filter((value): value is number => value !== undefined)\n return timestamps.length > 0 ? Math.min(...timestamps) : undefined\n}\n\nfunction lastTimestamp(rows: StakeRelationship[]): number | undefined {\n const timestamps = rows.map((row) => row.last_activity_timestamp).filter((value): value is number => value !== undefined)\n return timestamps.length > 0 ? Math.max(...timestamps) : undefined\n}\n\nfunction sum(rows: StakeRelationship[], selector: (row: StakeRelationship) => number | undefined): number {\n return rows.reduce((total, row) => total + (selector(row) ?? 0), 0)\n}\n\nfunction stakeTotals(rows: StakeRelationship[]): Record<string, unknown> {\n const totalStaked = sum(rows, (row) => row.stake_added_amount)\n const totalUnstaked = sum(rows, (row) => row.stake_removed_amount)\n const totalMovedIn = sum(rows, (row) => row.stake_moved_in_amount)\n const totalMovedOut = sum(rows, (row) => row.stake_moved_out_amount)\n const netStaked = rows.some((row) => row.net_stake_change !== undefined)\n ? sum(rows, (row) => row.net_stake_change)\n : sum(rows, (row) => row.amount)\n\n return {\n amount_unit: 'tao',\n total_staked: totalStaked,\n total_unstaked: totalUnstaked,\n total_moved_in: totalMovedIn,\n total_moved_out: totalMovedOut,\n net_staked: netStaked,\n relationship_count: rows.length,\n first_activity_timestamp: firstTimestamp(rows),\n last_activity_timestamp: lastTimestamp(rows),\n }\n}\n\nfunction movementRows(rows: StakeRelationship[]): Array<Record<string, unknown>> {\n const movements: Array<Record<string, unknown>> = []\n for (const row of rows) {\n const base = {\n coldkey: row.coldkey,\n hotkey: row.hotkey,\n netuid: row.netuid,\n source_backend: row.source_backend,\n first_activity_timestamp: row.first_activity_timestamp,\n last_activity_timestamp: row.last_activity_timestamp,\n }\n const added = nonZeroNumber(row.stake_added_amount)\n if (added !== undefined) movements.push({ ...base, movement_type: 'stake_added', direction: 'coldkey_to_hotkey', amount: added })\n const removed = nonZeroNumber(row.stake_removed_amount)\n if (removed !== undefined) movements.push({ ...base, movement_type: 'stake_removed', direction: 'hotkey_to_coldkey', amount: removed })\n const movedIn = nonZeroNumber(row.stake_moved_in_amount)\n if (movedIn !== undefined) movements.push({ ...base, movement_type: 'stake_moved_in', direction: 'counterparty_to_relationship', amount: movedIn })\n const movedOut = nonZeroNumber(row.stake_moved_out_amount)\n if (movedOut !== undefined) movements.push({ ...base, movement_type: 'stake_moved_out', direction: 'relationship_to_counterparty', amount: movedOut })\n }\n return movements\n}\n\nfunction topCounterparties(\n subject: { role: StakeSubjectRole; address: string },\n rows: StakeRelationship[],\n): Array<Record<string, unknown>> {\n const byAddress = new Map<string, { address: string; role: 'coldkey' | 'hotkey'; amount: number; relationship_count: number; stake_event_count: number }>()\n for (const row of rows) {\n const counterparties: Array<{ address: string; role: 'coldkey' | 'hotkey' }> = []\n if (subject.role === 'coldkey') counterparties.push({ address: row.hotkey, role: 'hotkey' })\n else if (subject.role === 'hotkey') counterparties.push({ address: row.coldkey, role: 'coldkey' })\n else {\n if (row.coldkey === subject.address) counterparties.push({ address: row.hotkey, role: 'hotkey' })\n if (row.hotkey === subject.address) counterparties.push({ address: row.coldkey, role: 'coldkey' })\n }\n\n for (const counterparty of counterparties.filter((entry) => entry.address)) {\n const current = byAddress.get(counterparty.address) ?? {\n address: counterparty.address,\n role: counterparty.role,\n amount: 0,\n relationship_count: 0,\n stake_event_count: 0,\n }\n current.amount += row.amount ?? row.net_stake_change ?? 0\n current.relationship_count += 1\n current.stake_event_count += row.stake_event_count ?? 0\n byAddress.set(counterparty.address, current)\n }\n }\n\n return [...byAddress.values()]\n .sort((left, right) => Math.abs(right.amount) - Math.abs(left.amount))\n .slice(0, 10)\n}\n\nfunction graphData(rows: StakeRelationship[], subject: { address: string; role: StakeSubjectRole }, network: string): Record<string, unknown> {\n const nodes = new Map<string, Record<string, unknown>>()\n const ensureNode = (address: string, role: string) => {\n const existing = nodes.get(address) ?? { id: address, address, node_type: 'address', labels: [], roles: [] }\n const roles = Array.isArray(existing['roles']) ? existing['roles'].map(String) : []\n nodes.set(address, { ...existing, roles: [...new Set([...roles, role])] })\n }\n\n ensureNode(subject.address, 'subject')\n const edges = rows.map((row) => {\n ensureNode(row.coldkey, 'coldkey')\n ensureNode(row.hotkey, 'hotkey')\n return {\n source: row.coldkey,\n target: row.hotkey,\n edge_type: 'stakes_in',\n amount: row.amount ?? row.net_stake_change ?? 0,\n netuid: row.netuid,\n source_backend: row.source_backend,\n topology_graph: row.topology_graph,\n first_activity_timestamp: row.first_activity_timestamp,\n last_activity_timestamp: row.last_activity_timestamp,\n }\n })\n\n return normalizeGraphPayload({\n schema: 'chain-insights.graph.v1',\n nodes: [...nodes.values()],\n edges,\n flows: [],\n edge_anchors: [],\n metadata: {\n network,\n subject_address: subject.address,\n subject_role: subject.role,\n generated_at: new Date().toISOString(),\n },\n })\n}\n\nfunction summaryLines(\n network: string,\n subject: { role: StakeSubjectRole; address: string },\n rows: StakeRelationship[],\n totals: Record<string, unknown>,\n failures: QueryFailure[],\n): string {\n const lines = [\n `Stake insights for ${network}:${subject.address}`,\n '',\n `Subject role: ${subject.role}`,\n `Relationships: ${rows.length}`,\n `Net staked: ${totals['net_staked'] ?? 0} TAO`,\n `Total staked: ${totals['total_staked'] ?? 0} TAO`,\n `Total unstaked: ${totals['total_unstaked'] ?? 0} TAO`,\n `First activity: ${totals['first_activity_timestamp'] ?? 'unknown'}`,\n `Last activity: ${totals['last_activity_timestamp'] ?? 'unknown'}`,\n ]\n\n if (rows.length > 0) {\n lines.push('', 'Top staking relationships')\n for (const row of rows.slice(0, 10)) {\n lines.push(`- ${row.coldkey} -> ${row.hotkey} netuid ${row.netuid ?? 'unknown'} amount ${row.amount ?? row.net_stake_change ?? 'unknown'} (${row.source_backend})`)\n }\n } else {\n lines.push('', 'No stake relationships matched the requested filters.')\n }\n\n if (failures.length > 0) {\n lines.push('', 'Partial query failures', failures.map((failure) => `- ${failure.id}: ${failure.error}`).join('\\n'))\n }\n\n return lines.join('\\n')\n}\n\nexport async function stakeInsights(\n remoteClient: Client,\n options: StakeInsightsOptions,\n): Promise<StakeInsightsResult> {\n const { network, subject, depth } = validateOptions(options)\n const batch = await callGraphBatch(remoteClient, network, [\n stakeRelationshipQuery('live_topology', subject, options, depth),\n stakeRelationshipQuery('archive_topology', subject, options, depth),\n ])\n const { live, archive, failures, evidence } = collectRelationships(batch)\n\n if (live.length === 0 && archive.length === 0 && failures.length > 0) {\n throw new Error(`Stake insights unavailable: ${failures.map((failure) => `${failure.id}: ${failure.error}`).join('; ')}`)\n }\n\n const rows = live.length > 0 ? live : archive\n const totals = stakeTotals(rows)\n const facts = {\n subject: {\n network,\n address: subject.address,\n role: subject.role,\n netuid: options.netuid,\n start_timestamp_ms: options.startTimestampMs,\n end_timestamp_ms: options.endTimestampMs,\n depth,\n },\n backend_used: [...new Set(rows.map((row) => row.source_backend).filter(Boolean))],\n primary_topology_graph: live.length > 0 ? 'live_topology' : 'archive_topology',\n stake_totals: totals,\n active_relationships: rows,\n stake_movements: movementRows(rows),\n top_counterparties: topCounterparties(subject, rows),\n query_evidence: evidence,\n partial_query_errors: failures.length > 0 ? failures : undefined,\n }\n\n return {\n summaryText: summaryLines(network, subject, rows, totals, failures),\n structuredContent: {\n schema: 'chain-insights.result.v1',\n tool: 'stake_insights',\n facts,\n hint: rows.length > 0\n ? 'Review active_relationships and stake_movements before treating stake behavior as generic money flow.'\n : 'No matching stake relationships were found; confirm the address role, netuid, and time window.',\n },\n graphData: graphData(rows, subject, network),\n }\n}\n","import { createHash } from 'node:crypto'\nimport { mkdir, writeFile } from 'node:fs/promises'\nimport path from 'node:path'\nimport type { Client } from '@modelcontextprotocol/sdk/client/index.js'\nimport type { ContentBlock } from '@modelcontextprotocol/sdk/types.js'\nimport type { InvestigatorConfig } from '../config/schema.js'\nimport { runFundFlowProbe, type TraceFundsResult } from './trace-funds.js'\nimport { normalizeGraphPayload } from '../viz/graph-normalizer.js'\nimport { workspaceOutputPaths } from '../workspace/output-root.js'\n\nexport { scamTopology, type ScamTopologyOptions, type ScamTopologyResult } from './scam-topology.js'\nexport { stakeInsights, type StakeInsightsOptions, type StakeInsightsResult } from './stake-insights.js'\n\ntype RemoteToolResult = {\n content?: ContentBlock[]\n isError?: boolean\n}\n\ninterface ParsedGraphBatch {\n facts?: {\n queries?: Array<{\n id?: string\n ok?: boolean\n results?: Array<Record<string, unknown>>\n error?: string\n }>\n }\n}\n\ntype QueryFailure = {\n id: string\n error: string\n}\n\nconst GRAPH_QUERY_BATCH_TIMEOUT_SECONDS = 120\nconst GRAPH_QUERY_BATCH_REQUEST_TIMEOUT_MS = 5 * 60 * 1000\n\nexport interface AddressRiskOptions {\n address: string\n network: string\n compareAddress?: string\n}\n\nexport interface TrackFundsOptions {\n trustedAddresses: string | string[]\n untrustedAddresses?: string | string[]\n network: string\n caseId?: string\n maxHops?: number\n perAddressLimit?: number\n minAmountSum?: number\n}\n\nfunction escapeCypherString(value: string): string {\n return value.replaceAll('\\\\', '\\\\\\\\').replaceAll('\"', '\\\\\"')\n}\n\nfunction textFromToolResult(result: RemoteToolResult): string {\n return (result.content ?? [])\n .filter((item): item is Extract<ContentBlock, { type: 'text' }> => item.type === 'text')\n .map((item) => item.text)\n .join('\\n')\n}\n\nfunction parseGraphBatchResult(result: RemoteToolResult): ParsedGraphBatch {\n const text = textFromToolResult(result).trim()\n if (!text) throw new Error('graph_query_batch returned no text content')\n const parsed = JSON.parse(text) as ParsedGraphBatch\n if (!parsed.facts?.queries) throw new Error('graph_query_batch response did not include facts.queries')\n return parsed\n}\n\nfunction topologyGraphQuery(query: string): string {\n const trimmed = query.trim()\n if (/^USE\\s+/i.test(trimmed)) return trimmed\n return `USE live_topology ${trimmed}`\n}\n\nfunction collectQueryFailure(failures: QueryFailure[], id: string, error: string | undefined): void {\n failures.push({ id, error: error || 'unknown error' })\n}\n\nfunction optionalResultsFor(batch: ParsedGraphBatch, id: string, failures: QueryFailure[]): Array<Record<string, unknown>> {\n const query = batch.facts?.queries?.find((entry) => entry.id === id)\n if (!query) return []\n if (query.ok === false) {\n collectQueryFailure(failures, id, query.error)\n return []\n }\n return query.results ?? []\n}\n\nfunction optionalResultsWithPrefix(batch: ParsedGraphBatch, prefix: string, failures: QueryFailure[]): Array<Record<string, unknown>> {\n return (batch.facts?.queries ?? [])\n .filter((entry) => entry.id?.startsWith(prefix))\n .flatMap((entry) => {\n if (entry.ok === false) {\n collectQueryFailure(failures, entry.id ?? prefix, entry.error)\n return []\n }\n return entry.results ?? []\n })\n}\n\nasync function callGraphBatch(\n remoteClient: Client,\n network: string,\n queries: Array<{ id: string; query: string }>,\n): Promise<ParsedGraphBatch> {\n const result = await remoteClient.callTool(\n {\n name: 'graph_query_batch',\n arguments: {\n network,\n queries: queries.map((query) => ({\n ...query,\n query: topologyGraphQuery(query.query),\n })),\n per_query_timeout_seconds: GRAPH_QUERY_BATCH_TIMEOUT_SECONDS,\n },\n },\n undefined,\n {\n timeout: GRAPH_QUERY_BATCH_REQUEST_TIMEOUT_MS,\n maxTotalTimeout: GRAPH_QUERY_BATCH_REQUEST_TIMEOUT_MS,\n },\n ) as RemoteToolResult\n if (result.isError) throw new Error(textFromToolResult(result) || 'graph_query_batch failed')\n return parseGraphBatchResult(result)\n}\n\nfunction parseAddressList(value: string | string[] | undefined): string[] {\n const raw = Array.isArray(value) ? value.join(',') : value ?? ''\n return raw\n .split(',')\n .map((entry) => entry.trim())\n .filter(Boolean)\n}\n\nfunction graphArray(graphData: Record<string, unknown>, key: string): Array<Record<string, unknown>> {\n const value = graphData[key]\n return Array.isArray(value) ? value.filter((item): item is Record<string, unknown> => typeof item === 'object' && item !== null && !Array.isArray(item)) : []\n}\n\nfunction addressProfileQuery(address: string): { id: string; query: string } {\n return {\n id: 'address_profile',\n query: [\n `MATCH (a:Address {address: \"${escapeCypherString(address)}\"})`,\n 'RETURN a.address AS address, a.labels AS display_labels, a.labels AS system_labels, a.address_type AS address_type, a.address_subtypes AS address_subtypes, a.is_exchange AS is_exchange, a.confluence_score AS confluence_score, a.ml_risk_score AS ml_risk_score, a.ml_risk_level AS ml_risk_level, a.ml_top_drivers AS ml_top_drivers, a.ml_pattern_summary AS ml_pattern_summary, a.risk_score AS risk_score, a.risk_level AS risk_level, a.pattern_flags AS pattern_flags, a.ml_pagerank AS ml_pagerank, a.ml_betweenness AS ml_betweenness, a.ml_community_id AS ml_community_id',\n 'LIMIT 1',\n ].join(' '),\n }\n}\n\nfunction addressFeatureQuery(address: string): { id: string; query: string } {\n return {\n id: 'address_feature',\n query: [\n 'USE facts',\n `MATCH (a:Address {address: \"${escapeCypherString(address)}\"})-[:HAS_FEATURE]->(feature:AddressFeature)`,\n 'RETURN feature.degree_in AS degree_in, feature.degree_out AS degree_out, feature.degree_total AS degree_total, feature.tx_in_count AS tx_in_count, feature.tx_out_count AS tx_out_count, feature.tx_total_count AS tx_total_count, feature.total_volume_usd AS total_volume_usd, feature.total_in_usd AS total_in_usd, feature.total_out_usd AS total_out_usd, feature.net_flow_usd AS net_flow_usd, feature.first_activity_timestamp AS first_activity_timestamp, feature.last_activity_timestamp AS last_activity_timestamp, feature.activity_span_days AS activity_span_days, feature.active_days AS active_days',\n 'LIMIT 1',\n ].join(' '),\n }\n}\n\nfunction addressRiskScoreQuery(address: string): { id: string; query: string } {\n return {\n id: 'address_risk_score',\n query: [\n 'USE facts',\n `MATCH (a:Address {address: \"${escapeCypherString(address)}\"})-[:HAS_RISK_SCORE]->(risk:RiskScore)`,\n 'RETURN risk.risk_score AS risk_score, risk.window_days AS risk_window_days, risk.processing_date AS risk_processing_date, risk.shap_top_features AS shap_top_features',\n 'LIMIT 1',\n ].join(' '),\n }\n}\n\nfunction flowEdgeMap(variableName: string): string {\n return `{amount_sum: ${variableName}.amount_sum, amount_usd_sum: ${variableName}.amount_usd_sum, tx_count: ${variableName}.tx_count, first_tx_id: ${variableName}.first_tx_id, last_tx_id: ${variableName}.last_tx_id}`\n}\n\nfunction pathNodeMap(variableName: string): string {\n return `{address: ${variableName}.address, labels: ${variableName}.labels, system_labels: ${variableName}.labels, address_type: ${variableName}.address_type, address_subtypes: ${variableName}.address_subtypes, is_exchange: ${variableName}.is_exchange}`\n}\n\nfunction exchangeOutflowQueries(address: string): Array<{ id: string; query: string }> {\n return Array.from({ length: 3 }, (_, index) => exchangeOutflowQueryAtDepth(address, index + 1))\n}\n\nfunction exchangeOutflowQueryAtDepth(address: string, depth: number): { id: string; query: string } {\n const intermediateVariables = Array.from({ length: Math.max(depth - 1, 0) }, (_, index) => `n${index + 1}`)\n const nodeVariables = ['a', ...intermediateVariables, 'exchange']\n const edgeVariables = Array.from({ length: depth }, (_, index) => `r${index + 1}`)\n const relationshipChain = edgeVariables.map((edgeVariable, index) => {\n const targetVariable = index === edgeVariables.length - 1 ? 'exchange' : intermediateVariables[index]!\n return `-[${edgeVariable}:FLOWS_TO]->(${targetVariable}:Address)`\n }).join('')\n const intermediatePredicates = intermediateVariables.map((nodeVariable) => `${nodeVariable}.is_exchange IS NULL`)\n const depositVariable = nodeVariables[nodeVariables.length - 2]!\n const terminalEdgeVariable = edgeVariables[edgeVariables.length - 1]!\n return {\n id: `exchange_outflows_${depth}`,\n query: [\n `MATCH (a:Address {address: \"${escapeCypherString(address)}\"})${relationshipChain}`,\n `WHERE a <> exchange AND exchange.is_exchange IS NOT NULL${intermediatePredicates.length > 0 ? ` AND ${intermediatePredicates.join(' AND ')}` : ''}`,\n `RETURN \"outflow\" AS direction, exchange.address AS exchange_address, exchange.labels AS exchange_display_labels, exchange.labels AS exchange_system_labels, exchange.address_type AS exchange_address_type, exchange.address_subtypes AS exchange_address_subtypes, ${depositVariable}.address AS deposit_address, ${depth} AS hops, ${terminalEdgeVariable}.amount_sum AS amount_sum, ${terminalEdgeVariable}.amount_usd_sum AS amount_usd_sum, ${terminalEdgeVariable}.tx_count AS tx_count, [${nodeVariables.map((nodeVariable) => `${nodeVariable}.address`).join(', ')}] AS addresses, [${nodeVariables.map(pathNodeMap).join(', ')}] AS path_nodes, [${edgeVariables.map(flowEdgeMap).join(', ')}] AS edge_props`,\n 'ORDER BY hops ASC',\n 'LIMIT 200',\n ].join(' '),\n }\n}\n\nfunction exchangeInflowQueries(address: string): Array<{ id: string; query: string }> {\n return Array.from({ length: 3 }, (_, index) => exchangeInflowQueryAtDepth(address, index + 1))\n}\n\nfunction exchangeInflowQueryAtDepth(address: string, depth: number): { id: string; query: string } {\n const intermediateVariables = Array.from({ length: Math.max(depth - 1, 0) }, (_, index) => `n${index + 1}`)\n const nodeVariables = ['exchange', ...intermediateVariables, 'a']\n const edgeVariables = Array.from({ length: depth }, (_, index) => `r${index + 1}`)\n const relationshipChain = edgeVariables.map((edgeVariable, index) => {\n const targetVariable = index === edgeVariables.length - 1 ? 'a' : intermediateVariables[index]!\n return `-[${edgeVariable}:FLOWS_TO]->(${targetVariable}:Address)`\n }).join('')\n const intermediatePredicates = intermediateVariables.map((nodeVariable) => `${nodeVariable}.is_exchange IS NULL`)\n const withdrawalVariable = nodeVariables[1]!\n const terminalEdgeVariable = edgeVariables[edgeVariables.length - 1]!\n return {\n id: `exchange_inflows_${depth}`,\n query: [\n `MATCH (exchange:Address)${relationshipChain}`,\n `WHERE a.address = \"${escapeCypherString(address)}\" AND a <> exchange AND exchange.is_exchange IS NOT NULL${intermediatePredicates.length > 0 ? ` AND ${intermediatePredicates.join(' AND ')}` : ''}`,\n `RETURN \"inflow\" AS direction, exchange.address AS exchange_address, exchange.labels AS exchange_display_labels, exchange.labels AS exchange_system_labels, exchange.address_type AS exchange_address_type, exchange.address_subtypes AS exchange_address_subtypes, ${withdrawalVariable}.address AS withdrawal_address, ${depth} AS hops, ${terminalEdgeVariable}.amount_sum AS amount_sum, ${terminalEdgeVariable}.amount_usd_sum AS amount_usd_sum, ${terminalEdgeVariable}.tx_count AS tx_count, [${nodeVariables.map((nodeVariable) => `${nodeVariable}.address`).join(', ')}] AS addresses, [${nodeVariables.map(pathNodeMap).join(', ')}] AS path_nodes, [${edgeVariables.map(flowEdgeMap).join(', ')}] AS edge_props`,\n 'ORDER BY hops ASC',\n 'LIMIT 200',\n ].join(' '),\n }\n}\n\nfunction connectionProbeQuery(address: string, compareAddress: string): { id: string; query: string } {\n return {\n id: 'connection_probe',\n query: [\n `MATCH (a:Address {address: \"${escapeCypherString(address)}\"})-[r:FLOWS_TO]-(b:Address {address: \"${escapeCypherString(compareAddress)}\"})`,\n 'RETURN [a.address, b.address] AS addresses, 1 AS hops',\n 'LIMIT 5',\n ].join(' '),\n }\n}\n\nfunction formatExchangeRows(rows: Array<Record<string, unknown>>): string[] {\n return rows.map((row) => {\n const direction = String(row['direction'] ?? 'flow')\n const exchange = String(row['exchange_address'] ?? '')\n const amount = row['amount_sum'] ?? row['amount_usd_sum'] ?? ''\n const hops = row['hops'] ?? ''\n return `- ${direction}: ${exchange} (${hops} hop(s), amount ${amount})`\n })\n}\n\nfunction numberValue(value: unknown): number | undefined {\n if (typeof value === 'number' && Number.isFinite(value)) return value\n if (typeof value === 'string' && value.trim()) {\n const parsed = Number(value)\n return Number.isFinite(parsed) ? parsed : undefined\n }\n return undefined\n}\n\nfunction isExchangeFlag(value: unknown): boolean {\n if (value === true) return true\n if (value === false || value === null || value === undefined) return false\n if (typeof value === 'string') {\n const normalized = value.trim().toLowerCase()\n return normalized === 'true' || normalized === '1'\n }\n if (typeof value === 'number') return value === 1\n return false\n}\n\nfunction hasExactExchangeLabel(labels: string[] | undefined): boolean {\n return (labels ?? []).some((label) => label.trim().toLowerCase() === 'exchange')\n}\n\nfunction firstNumber(...values: unknown[]): number | undefined {\n for (const value of values) {\n const parsed = numberValue(value)\n if (parsed !== undefined) return parsed\n }\n return undefined\n}\n\nfunction firstString(...values: unknown[]): string | undefined {\n for (const value of values) {\n if (typeof value === 'string' && value.trim()) return value.trim()\n }\n return undefined\n}\n\nfunction riskLevelFromScore(score: number): string {\n if (score >= 0.85) return 'critical'\n if (score >= 0.7) return 'high'\n if (score >= 0.4) return 'medium'\n return 'low'\n}\n\nfunction riskRecommendation(level: string): string {\n if (level === 'critical' || level === 'high') return 'Escalate for manual review.'\n if (level === 'medium') return 'Review exchange exposure and counterparties before clearing.'\n return 'No stored risk signal found; continue with normal monitoring.'\n}\n\nfunction riskDrivers(profile: Record<string, unknown>, exchangeRows: Array<Record<string, unknown>>): string[] {\n const drivers: string[] = []\n const storedDrivers = stringArrayValue(profile['ml_top_drivers'])\n if (storedDrivers?.length) drivers.push(...storedDrivers)\n\n const patternFlags = stringArrayValue(profile['pattern_flags'])\n if (patternFlags?.length) drivers.push(`Pattern flags: ${patternFlags.join(', ')}`)\n\n const outflowCount = exchangeRows.filter((row) => row['direction'] === 'outflow').length\n const inflowCount = exchangeRows.filter((row) => row['direction'] === 'inflow').length\n if (outflowCount > 0) drivers.push(`Forward bounded search reached ${outflowCount} exchange path(s).`)\n if (inflowCount > 0) drivers.push(`Backward bounded search found ${inflowCount} source exchange path(s).`)\n\n return [...new Set(drivers)]\n}\n\nfunction terminalEdgeProperties(row: Record<string, unknown>): Record<string, unknown> | undefined {\n const edgeProps = Array.isArray(row['edge_props']) ? row['edge_props'] as Array<Record<string, unknown>> : []\n return edgeProps[edgeProps.length - 1]\n}\n\nfunction enrichExchangeRows(rows: Array<Record<string, unknown>>): Array<Record<string, unknown>> {\n return rows.map((row) => {\n const terminal = terminalEdgeProperties(row)\n if (!terminal) return row\n return {\n ...row,\n amount_sum: row['amount_sum'] ?? terminal['amount_sum'],\n amount_usd_sum: row['amount_usd_sum'] ?? terminal['amount_usd_sum'],\n tx_count: row['tx_count'] ?? terminal['tx_count'],\n first_tx_id: row['first_tx_id'] ?? terminal['first_tx_id'],\n last_tx_id: row['last_tx_id'] ?? terminal['last_tx_id'],\n }\n })\n}\n\nfunction riskAssessment(profile: Record<string, unknown>, exchangeRows: Array<Record<string, unknown>>): Record<string, unknown> {\n const storedScore = firstNumber(profile['confluence_score'], profile['ml_risk_score'], profile['risk_score'])\n const score = storedScore ?? (exchangeRows.length > 0 ? 0.4 : 0)\n const level = firstString(profile['ml_risk_level'], profile['risk_level']) ?? riskLevelFromScore(score)\n const drivers = riskDrivers(profile, exchangeRows)\n return {\n level,\n score,\n confidence: storedScore !== undefined || firstString(profile['ml_risk_level'], profile['risk_level']) ? 'high' : exchangeRows.length > 0 ? 'medium' : 'low',\n recommendation: riskRecommendation(level),\n drivers,\n }\n}\n\nfunction formatRiskScore(score: unknown): string {\n const parsed = numberValue(score)\n if (parsed === undefined) return String(score ?? 'unknown')\n return Number.isInteger(parsed) ? parsed.toString() : parsed.toFixed(2)\n}\n\nfunction stringArrayValue(value: unknown): string[] | undefined {\n if (Array.isArray(value)) return value.map(String)\n if (typeof value === 'string' && value.trim()) return [value]\n return undefined\n}\n\nfunction restoreSystemLabels(graph: Record<string, unknown>, rawNodes: Array<Record<string, unknown>>): Record<string, unknown> {\n if (!Array.isArray(graph['nodes'])) return graph\n const labelsByAddress = new Map(rawNodes\n .map((node) => [typeof node['address'] === 'string' ? node['address'] : typeof node['id'] === 'string' ? node['id'] : '', stringArrayValue(node['system_labels'])] as const)\n .filter((entry): entry is readonly [string, string[]] => Boolean(entry[0]) && Array.isArray(entry[1]) && entry[1].length > 0))\n return {\n ...graph,\n nodes: graph['nodes'].map((node) => {\n if (typeof node !== 'object' || node === null || Array.isArray(node)) return node\n const record = node as Record<string, unknown>\n const address = typeof record['address'] === 'string' ? record['address'] : typeof record['id'] === 'string' ? record['id'] : ''\n const systemLabels = labelsByAddress.get(address)\n return systemLabels ? { ...record, system_labels: systemLabels } : record\n }),\n }\n}\n\nfunction buildRiskGraph(address: string, profile: Record<string, unknown>, rows: Array<Record<string, unknown>>, network: string): Record<string, unknown> {\n const nodes = new Map<string, Record<string, unknown>>()\n nodes.set(address, {\n id: address,\n address,\n node_type: 'address',\n labels: stringArrayValue(profile['display_labels']) ?? [],\n ...(stringArrayValue(profile['system_labels']) ? { system_labels: stringArrayValue(profile['system_labels']) } : {}),\n ...(typeof profile['address_type'] === 'string' ? { address_type: profile['address_type'] } : {}),\n ...(stringArrayValue(profile['address_subtypes']) ? { address_subtypes: stringArrayValue(profile['address_subtypes']) } : {}),\n roles: ['subject'],\n })\n const edges: Array<Record<string, unknown>> = []\n const mergeNode = (entry: string, metadata?: Record<string, unknown>) => {\n const existing = nodes.get(entry) ?? { id: entry, address: entry, node_type: 'address', labels: [] }\n const labels = stringArrayValue(metadata?.['labels']) ?? existing['labels']\n const systemLabels = stringArrayValue(metadata?.['system_labels']) ?? existing['system_labels']\n const addressType = typeof metadata?.['address_type'] === 'string' ? metadata['address_type'] : existing['address_type']\n const addressSubtypes = stringArrayValue(metadata?.['address_subtypes']) ?? existing['address_subtypes']\n nodes.set(entry, {\n ...existing,\n labels,\n ...(systemLabels ? { system_labels: systemLabels } : {}),\n ...(addressType ? { address_type: addressType } : {}),\n ...(addressSubtypes ? { address_subtypes: addressSubtypes } : {}),\n })\n }\n for (const row of rows) {\n const rawPath = Array.isArray(row['path']) ? row['path'] : row['addresses']\n const path = Array.isArray(rawPath) ? rawPath.map(String) : []\n const pathNodes = Array.isArray(row['path_nodes']) ? row['path_nodes'] as Array<Record<string, unknown>> : []\n for (let index = 0; index < path.length; index += 1) {\n const entry = path[index]!\n mergeNode(entry, pathNodes[index])\n }\n const exchange = typeof row['exchange_address'] === 'string' ? row['exchange_address'] : ''\n if (exchange) {\n const displayLabels = stringArrayValue(row['exchange_display_labels']) ?? []\n const systemLabels = stringArrayValue(row['exchange_system_labels']) ?? stringArrayValue(row['exchange_labels']) ?? []\n nodes.set(exchange, {\n id: exchange,\n address: exchange,\n node_type: 'address',\n labels: displayLabels,\n ...(systemLabels.length > 0 ? { system_labels: systemLabels } : {}),\n ...(typeof row['exchange_address_type'] === 'string' ? { address_type: row['exchange_address_type'] } : {}),\n ...(stringArrayValue(row['exchange_address_subtypes']) ? { address_subtypes: stringArrayValue(row['exchange_address_subtypes']) } : {}),\n roles: ['exchange'],\n })\n }\n for (let index = 0; index < path.length - 1; index += 1) {\n const edgeProps = Array.isArray(row['edge_props']) ? row['edge_props'] as Array<Record<string, unknown>> : []\n const edge = edgeProps[index] ?? row\n edges.push({\n source: path[index],\n target: path[index + 1],\n edge_type: 'flows_to',\n usd_amount: edge['amount_usd_sum'] ?? edge['amount_sum'] ?? 0,\n amount_sum: edge['amount_sum'] ?? 0,\n tx_count: edge['tx_count'] ?? 0,\n first_tx_id: edge['first_tx_id'],\n last_tx_id: edge['last_tx_id'],\n direction: row['direction'],\n })\n }\n }\n const rawNodes = [...nodes.values()]\n return restoreSystemLabels(normalizeGraphPayload({\n schema: 'chain-insights.graph.v1',\n nodes: rawNodes,\n edges,\n flows: [],\n edge_anchors: [],\n metadata: { address, network, generated_at: new Date().toISOString() },\n }), rawNodes)\n}\n\nexport async function addressRisk(remoteClient: Client, options: AddressRiskOptions): Promise<{\n summaryText: string\n structuredContent: Record<string, unknown>\n graphData: Record<string, unknown>\n}> {\n const address = options.address.trim()\n const network = options.network.trim()\n const compareAddress = options.compareAddress?.trim() ?? ''\n if (!address) throw new Error('address is required')\n if (!network) throw new Error('network is required')\n\n const queries = [\n addressProfileQuery(address),\n addressFeatureQuery(address),\n addressRiskScoreQuery(address),\n ...exchangeOutflowQueries(address),\n ...exchangeInflowQueries(address),\n ...(compareAddress ? [connectionProbeQuery(address, compareAddress)] : [{ id: 'connection_probe', query: 'MATCH (n:Address {address: \"__chain_insights_noop__\"}) RETURN n.address AS noop LIMIT 0' }]),\n ]\n const batch = await callGraphBatch(remoteClient, network, queries)\n const partialQueryFailures: QueryFailure[] = []\n const profile: Record<string, unknown> = {\n address,\n ...(optionalResultsFor(batch, 'address_profile', partialQueryFailures)[0] ?? {}),\n ...(optionalResultsFor(batch, 'address_feature', partialQueryFailures)[0] ?? {}),\n ...(optionalResultsFor(batch, 'address_risk_score', partialQueryFailures)[0] ?? {}),\n }\n const outflows = enrichExchangeRows(optionalResultsWithPrefix(batch, 'exchange_outflows_', partialQueryFailures))\n const inflows = enrichExchangeRows(optionalResultsWithPrefix(batch, 'exchange_inflows_', partialQueryFailures))\n const connections = compareAddress ? optionalResultsFor(batch, 'connection_probe', partialQueryFailures) : []\n const exchangeRows = [...outflows, ...inflows]\n const graphData = buildRiskGraph(address, profile, exchangeRows, network)\n const risk = riskAssessment(profile, exchangeRows)\n\n const lines = [\n `Address risk for ${network}:${address}`,\n '',\n `Risk: ${risk['level']} (${formatRiskScore(risk['score'])})`,\n `Confidence: ${risk['confidence']}`,\n `Recommendation: ${risk['recommendation']}`,\n `Graph degree: in ${profile['degree_in'] ?? 'unknown'}, out ${profile['degree_out'] ?? 'unknown'}.`,\n '',\n 'Exchange behavior',\n exchangeRows.length > 0 ? formatExchangeRows(exchangeRows).join('\\n') : '- No exchange inflow/outflow paths found in bounded search.',\n ]\n if (Array.isArray(risk['drivers']) && risk['drivers'].length > 0) {\n lines.push('', 'Risk drivers', risk['drivers'].map((driver) => `- ${driver}`).join('\\n'))\n }\n if (compareAddress) {\n lines.push('', `Connection compare target: ${compareAddress}`, connections.length > 0 ? `Connection paths found: ${connections.length}` : 'Connection paths found: 0')\n }\n if (partialQueryFailures.length > 0) {\n lines.push('', 'Partial query failures', partialQueryFailures.map((failure) => `- ${failure.id}: ${failure.error}`).join('\\n'))\n }\n\n return {\n summaryText: lines.join('\\n'),\n structuredContent: {\n schema: 'chain-insights.result.v1',\n tool: 'address_risk',\n facts: {\n subject: { network, addresses: compareAddress ? [address, compareAddress] : [address] },\n risk,\n exchange_behavior: {\n outflows,\n inflows,\n },\n connection: compareAddress ? { compare_address: compareAddress, paths: connections } : undefined,\n partial_query_errors: partialQueryFailures.length > 0 ? partialQueryFailures : undefined,\n },\n },\n graphData,\n }\n}\n\ntype TraceSeedRole = 'victim' | 'suspect' | 'deposit'\ntype TraceToolName = 'trace_victim_funds' | 'trace_suspect_funds' | 'trace_deposit_sources'\ntype TraceRole =\n | 'seed_victim'\n | 'seed_suspect'\n | 'seed_deposit'\n | 'candidate_victim'\n | 'candidate_suspect'\n | 'candidate_intermediate'\n | 'candidate_deposit'\n | 'exchange'\n | 'unknown'\n\nexport interface TraceVictimFundsOptions {\n victimAddresses: string | string[]\n knownSuspectAddresses?: string | string[]\n network: string\n caseId?: string\n incidentTimestampMs?: number\n timeRange?: { from_ms?: number; to_ms?: number }\n maxHops?: number\n perAddressLimit?: number\n minAmountSum?: number\n}\n\nexport interface TraceSuspectFundsOptions {\n suspectAddresses: string | string[]\n network: string\n caseId?: string\n incidentTimestampMs?: number\n timeRange?: { from_ms?: number; to_ms?: number }\n maxHops?: number\n perAddressLimit?: number\n minAmountSum?: number\n}\n\nexport interface TraceDepositSourcesOptions {\n depositAddresses: string | string[]\n network: string\n caseId?: string\n timeRange?: { from_ms?: number; to_ms?: number }\n maxHops?: number\n}\n\ntype TraceToolResult = {\n summaryText: string\n structuredContent: Record<string, unknown>\n graphData: Record<string, unknown>\n}\n\ntype TraceRunRole = 'victim' | 'suspect'\ntype TraceRun = { role: TraceRunRole; address: string; result: TraceFundsResult }\ntype TraceAddressAccumulator = {\n address: string\n roles: Set<TraceRole>\n labels: string[]\n is_exchange?: boolean\n confidence: 'low' | 'medium' | 'high'\n rationale: string[]\n}\n\nfunction uniqueStrings(values: Array<string | undefined>): string[] {\n return [...new Set(values.filter((value): value is string => typeof value === 'string' && value.length > 0))]\n}\n\nfunction clampInt(value: number | undefined, fallback: number, min: number, max: number): number {\n if (!Number.isFinite(value)) return fallback\n return Math.max(min, Math.min(max, Math.trunc(value as number)))\n}\n\nfunction graphRecords(graphData: Record<string, unknown>, key: string): Array<Record<string, unknown>> {\n const value = graphData[key]\n return Array.isArray(value)\n ? value.filter((item): item is Record<string, unknown> => typeof item === 'object' && item !== null && !Array.isArray(item))\n : []\n}\n\nfunction normalizeTraceGraphData(runs: TraceRun[], network: string): Record<string, unknown> {\n return normalizeGraphPayload({\n schema: 'chain-insights.graph.v1',\n nodes: runs.flatMap((run) => graphRecords(run.result.graphData, 'nodes')),\n edges: runs.flatMap((run) => graphRecords(run.result.graphData, 'edges')),\n flows: runs.flatMap((run) => graphRecords(run.result.graphData, 'flows')),\n deposits: runs.flatMap((run) => graphRecords(run.result.graphData, 'deposits').map((item) => ({ ...item, run_role: run.role, run_address: run.address }))),\n source_matches: runs.flatMap((run) => graphRecords(run.result.graphData, 'source_matches').map((item) => ({ ...item, run_role: run.role, run_address: run.address }))),\n reverse_leads: runs.flatMap((run) => graphRecords(run.result.graphData, 'reverse_leads').map((item) => ({ ...item, run_role: run.role, run_address: run.address }))),\n edge_anchors: [],\n metadata: {\n network,\n generated_at: new Date().toISOString(),\n trace_tools: true,\n },\n })\n}\n\nfunction traceArtifactPointersFromRun(run: TraceFundsResult | undefined): Record<string, unknown> {\n if (!run) return {}\n return {\n graph_json: run.files.graph,\n graph_html: run.files.graphHtml,\n table_json: run.files.compactEvidence,\n flows_csv: run.files.table,\n table_html: run.files.tableHtml,\n report_md: run.files.report,\n }\n}\n\nfunction artifactEvidence(artifacts: Record<string, unknown>): Array<Record<string, unknown>> {\n return Object.entries(artifacts)\n .filter((entry): entry is [string, string] => typeof entry[1] === 'string' && entry[1].length > 0)\n .map(([kind, filePath]) => ({\n evidence_type: 'artifact_pointer',\n path: filePath,\n summary: `${kind} artifact`,\n }))\n}\n\nfunction traceAddressRoleForSeed(seedRole: TraceSeedRole): TraceRole {\n if (seedRole === 'victim') return 'seed_victim'\n if (seedRole === 'suspect') return 'seed_suspect'\n return 'seed_deposit'\n}\n\nfunction addTraceAddress(\n addresses: Map<string, TraceAddressAccumulator>,\n address: string,\n role: TraceRole,\n rationale: string,\n labels: string[] = [],\n): void {\n if (!address) return\n const existing = addresses.get(address)\n if (existing) {\n existing.roles.add(role)\n existing.labels = uniqueStrings([...existing.labels, ...labels])\n if (role === 'exchange') existing.is_exchange = true\n if (!existing.rationale.includes(rationale)) existing.rationale.push(rationale)\n return\n }\n addresses.set(address, {\n address,\n roles: new Set([role]),\n labels,\n is_exchange: role === 'exchange' ? true : undefined,\n confidence: role.startsWith('seed_') || role === 'exchange' ? 'high' : 'medium',\n rationale: [rationale],\n })\n}\n\nfunction edgeKey(from: string, to: string): string {\n return `${from}\\u0000${to}`\n}\n\nfunction traceResultFromFundRuns(\n tool: Extract<TraceToolName, 'trace_victim_funds' | 'trace_suspect_funds'>,\n seedRole: Extract<TraceSeedRole, 'victim' | 'suspect'>,\n network: string,\n runs: TraceRun[],\n options: {\n incidentTimestampMs?: number\n timeRange?: { from_ms?: number; to_ms?: number }\n maxHops?: number\n caseId?: string\n } = {},\n): { summaryText: string; structuredContent: Record<string, unknown>; graphData: Record<string, unknown> } {\n const graphData = normalizeTraceGraphData(runs, network)\n const flows = graphRecords(graphData, 'flows')\n const deposits = graphRecords(graphData, 'deposits')\n const addresses = new Map<string, TraceAddressAccumulator>()\n for (const run of runs) {\n addTraceAddress(addresses, run.address, traceAddressRoleForSeed(seedRole), `${seedRole} seed provided by caller`)\n }\n\n const edgeIdsByPair = new Map<string, string>()\n const edges = flows.map((flow, index) => {\n const src = typeof flow['src'] === 'string' ? flow['src'] : ''\n const dst = typeof flow['dst'] === 'string' ? flow['dst'] : ''\n const edgeId = `e${index + 1}`\n edgeIdsByPair.set(edgeKey(src, dst), edgeId)\n const terminalExchange = flow['terminal_exchange'] === true\n addTraceAddress(addresses, src, runs.some((run) => run.address === src) ? traceAddressRoleForSeed(seedRole) : 'candidate_intermediate', 'Address appears in traced FLOWS_TO path')\n addTraceAddress(addresses, dst, terminalExchange ? 'exchange' : 'candidate_intermediate', terminalExchange ? 'Terminal exchange endpoint reached' : 'Address appears in traced FLOWS_TO path')\n return {\n edge_id: edgeId,\n from_address: src,\n to_address: dst,\n edge_type: 'FLOWS_TO',\n amount_sum: numberValue(flow['amount_sum']),\n amount_usd_sum: numberValue(flow['amount_usd_sum']),\n tx_count: numberValue(flow['tx_count']),\n first_tx_id: typeof flow['first_tx_id'] === 'string' ? flow['first_tx_id'] : undefined,\n last_tx_id: typeof flow['last_tx_id'] === 'string' ? flow['last_tx_id'] : undefined,\n }\n }).filter((edge) => edge.from_address && edge.to_address)\n\n const paths = deposits.map((deposit, index) => {\n const depositAddress = typeof deposit['address'] === 'string'\n ? deposit['address']\n : typeof deposit['deposit_address'] === 'string' ? deposit['deposit_address'] : ''\n const exchangeAddress = typeof deposit['exchangeAddress'] === 'string'\n ? deposit['exchangeAddress']\n : typeof deposit['exchange_address'] === 'string' ? deposit['exchange_address'] : ''\n const pathAddresses = stringArrayValue(deposit['path']) ?? [\n typeof deposit['run_address'] === 'string' ? deposit['run_address'] : runs[0]?.address ?? '',\n depositAddress,\n exchangeAddress,\n ].filter(Boolean)\n addTraceAddress(addresses, depositAddress, 'candidate_deposit', 'Penultimate address before an exchange endpoint')\n if (exchangeAddress) addTraceAddress(addresses, exchangeAddress, 'exchange', 'Exchange endpoint reached')\n const edgeIds: string[] = []\n for (let offset = 0; offset < pathAddresses.length - 1; offset += 1) {\n const id = edgeIdsByPair.get(edgeKey(pathAddresses[offset]!, pathAddresses[offset + 1]!))\n if (id) edgeIds.push(id)\n }\n return {\n path_id: `p${index + 1}`,\n direction: 'forward',\n source: pathAddresses[0] ?? '',\n target: exchangeAddress || depositAddress,\n addresses: pathAddresses,\n edge_ids: edgeIds,\n hops: numberValue(deposit['hops']) ?? Math.max(pathAddresses.length - 1, 0),\n terminal_role: exchangeAddress ? 'exchange' : 'deposit',\n amount_sum: numberValue(deposit['amount_sum']),\n amount_usd_sum: numberValue(deposit['amount_usd_sum']),\n }\n })\n\n const depositAddresses = uniqueStrings(deposits.map((deposit) => (\n typeof deposit['address'] === 'string' ? deposit['address'] : typeof deposit['deposit_address'] === 'string' ? deposit['deposit_address'] : undefined\n )))\n const exchangeAddresses = uniqueStrings(deposits.map((deposit) => (\n typeof deposit['exchangeAddress'] === 'string' ? deposit['exchangeAddress'] : typeof deposit['exchange_address'] === 'string' ? deposit['exchange_address'] : undefined\n )))\n const convergence = [...new Map(depositAddresses.map((address) => {\n const pathIds = paths.filter((path) => path.addresses.includes(address)).map((path) => path.path_id)\n return [address, {\n address,\n role: 'candidate_deposit',\n path_ids: pathIds,\n reason: pathIds.length > 1 ? 'Multiple traced paths converge into this deposit candidate.' : 'Single traced path reached this deposit candidate.',\n }]\n })).values()].filter((entry) => entry.path_ids.length > 1)\n const candidateLabels = depositAddresses.map((address) => ({\n address,\n candidate_label: 'candidate_deposit',\n confidence: 'medium',\n evidence_path_ids: paths.filter((path) => path.addresses.includes(address)).map((path) => path.path_id),\n reason: 'Penultimate address before an exchange endpoint in bounded FLOWS_TO trace.',\n promote_to_core_label: false,\n }))\n const runArtifacts = runs.map((run, index) => ({\n run_id: `run_${index + 1}`,\n role: run.role,\n address: run.address,\n ...traceArtifactPointersFromRun(run.result),\n }))\n const artifacts = {\n ...traceArtifactPointersFromRun(runs[0]?.result),\n runs: runArtifacts,\n }\n const artifactEvidenceEntries = runs.flatMap((run) => artifactEvidence(traceArtifactPointersFromRun(run.result))\n .map((entry) => ({ ...entry, run_role: run.role, address: run.address })))\n const recommendedNextTools = depositAddresses.length > 0\n ? ['trace_deposit_sources', 'address_risk']\n : ['address_risk', 'graph_query_batch']\n\n const structuredContent = {\n schema: 'chain-insights.trace.v1',\n tool,\n network,\n input: {\n addresses: runs.map((run) => run.address),\n seed_role: seedRole,\n ...(options.incidentTimestampMs !== undefined ? { incident_timestamp_ms: options.incidentTimestampMs } : {}),\n ...(options.timeRange ? { time_range: options.timeRange } : {}),\n max_hops: options.maxHops ?? 3,\n },\n summary: {\n seed_count: runs.length,\n path_count: paths.length,\n edge_count: edges.length,\n candidate_suspect_count: seedRole === 'suspect' ? runs.length : 0,\n candidate_intermediate_count: [...addresses.values()].filter((entry) => entry.roles.has('candidate_intermediate')).length,\n candidate_deposit_count: depositAddresses.length,\n exchange_count: exchangeAddresses.length,\n },\n addresses: [...addresses.values()].map((entry) => ({\n address: entry.address,\n roles: [...entry.roles],\n ...(entry.labels.length > 0 ? { labels: entry.labels } : {}),\n ...(entry.is_exchange !== undefined ? { is_exchange: entry.is_exchange } : {}),\n confidence: entry.confidence,\n rationale: entry.rationale,\n })),\n edges,\n paths,\n convergence,\n exchange_exposure: deposits.map((deposit) => ({\n deposit_address: typeof deposit['address'] === 'string' ? deposit['address'] : deposit['deposit_address'],\n exchange_address: typeof deposit['exchangeAddress'] === 'string' ? deposit['exchangeAddress'] : deposit['exchange_address'],\n path_ids: paths.filter((path) => path.addresses.includes(String(deposit['address'] ?? deposit['deposit_address'] ?? ''))).map((path) => path.path_id),\n })),\n candidate_labels: candidateLabels,\n artifacts,\n evidence: [\n ...artifactEvidenceEntries,\n ...(options.caseId ? [{ evidence_type: 'case_pointer', summary: `case_id=${options.caseId}` }] : []),\n ],\n continuation: {\n candidate_deposit_addresses: depositAddresses,\n candidate_suspect_addresses: seedRole === 'suspect' ? runs.map((run) => run.address) : [],\n candidate_victim_addresses: [],\n recommended_next_tools: recommendedNextTools,\n },\n warnings: depositAddresses.length === 0 ? ['No exchange deposit candidates were connected in the queried topology.'] : [],\n }\n\n return {\n summaryText: [\n `${seedRole === 'victim' ? 'Trace victim funds' : 'Trace suspect funds'} complete for ${network}`,\n '',\n ...runs.map((run) => `## ${run.role}: ${run.address}\\n${run.result.summaryText}`),\n ].join('\\n'),\n structuredContent,\n graphData,\n }\n}\n\nexport async function traceVictimFunds(\n remoteClient: Client,\n config: Pick<InvestigatorConfig, 'dataDir' | 'serverPort'>,\n options: TraceVictimFundsOptions,\n): Promise<TraceToolResult> {\n const network = options.network.trim()\n const victims = parseAddressList(options.victimAddresses)\n const knownSuspects = parseAddressList(options.knownSuspectAddresses)\n if (!network) throw new Error('network is required')\n if (victims.length < 1) throw new Error('victim_addresses must contain at least 1 address')\n if (victims.length > 5) throw new Error('victim_addresses cannot exceed 5 addresses')\n if (knownSuspects.length > 5) throw new Error('known_suspect_addresses cannot exceed 5 addresses')\n\n const runs: TraceRun[] = []\n for (const address of victims) {\n runs.push({\n role: 'victim',\n address,\n result: await runFundFlowProbe(remoteClient, config, {\n seedAddress: address,\n network,\n caseId: options.caseId,\n maxHops: options.maxHops,\n perAddressLimit: options.perAddressLimit,\n minAmountSum: options.minAmountSum,\n includeDepositTraceback: false,\n evidenceSource: 'trace_victim_funds',\n }),\n })\n }\n return traceResultFromFundRuns('trace_victim_funds', 'victim', network, runs, {\n incidentTimestampMs: options.incidentTimestampMs,\n timeRange: options.timeRange,\n maxHops: options.maxHops,\n caseId: options.caseId,\n })\n}\n\nexport async function traceSuspectFunds(\n remoteClient: Client,\n config: Pick<InvestigatorConfig, 'dataDir' | 'serverPort'>,\n options: TraceSuspectFundsOptions,\n): Promise<TraceToolResult> {\n const network = options.network.trim()\n const suspects = parseAddressList(options.suspectAddresses)\n if (!network) throw new Error('network is required')\n if (suspects.length < 1) throw new Error('suspect_addresses must contain at least 1 address')\n if (suspects.length > 5) throw new Error('suspect_addresses cannot exceed 5 addresses')\n\n const runs: TraceRun[] = []\n for (const address of suspects) {\n runs.push({\n role: 'suspect',\n address,\n result: await runFundFlowProbe(remoteClient, config, {\n seedAddress: address,\n network,\n caseId: options.caseId,\n maxHops: options.maxHops,\n perAddressLimit: options.perAddressLimit,\n minAmountSum: options.minAmountSum,\n includeDepositTraceback: false,\n evidenceSource: 'trace_suspect_funds',\n }),\n })\n }\n return traceResultFromFundRuns('trace_suspect_funds', 'suspect', network, runs, {\n incidentTimestampMs: options.incidentTimestampMs,\n timeRange: options.timeRange,\n maxHops: options.maxHops,\n caseId: options.caseId,\n })\n}\n\nfunction reverseDepositSourceQueryAtDepth(depositAddresses: string[], depth: number): { id: string; query: string } {\n const intermediateVariables = Array.from({ length: Math.max(depth - 1, 0) }, (_, index) => `n${index + 1}`)\n const nodeVariables = ['source', ...intermediateVariables, 'deposit']\n const edgeVariables = Array.from({ length: depth }, (_, index) => `r${index + 1}`)\n const relationshipChain = edgeVariables.map((edgeVariable, index) => {\n const targetVariable = index === edgeVariables.length - 1 ? 'deposit' : intermediateVariables[index]!\n return `-[${edgeVariable}:FLOWS_TO]->(${targetVariable}:Address)`\n }).join('')\n const depositPredicates = depositAddresses.map((address) => `deposit.address = \"${escapeCypherString(address)}\"`)\n const nonExchangePredicates = ['source', ...intermediateVariables, 'deposit'].map((nodeVariable) => `${nodeVariable}.is_exchange IS NULL`)\n return {\n id: `reverse_deposit_sources_${depth}`,\n query: [\n `MATCH (source:Address)${relationshipChain}`,\n `WHERE (${depositPredicates.join(' OR ')}) AND source.address <> deposit.address AND ${nonExchangePredicates.join(' AND ')}`,\n `RETURN DISTINCT source.address AS source_address, source.is_exchange AS source_is_exchange, deposit.address AS deposit_address, deposit.is_exchange AS deposit_is_exchange, ${depth} AS hop, [${nodeVariables.map((nodeVariable) => `${nodeVariable}.address`).join(', ')}] AS addresses, [${nodeVariables.map(pathNodeMap).join(', ')}] AS path_nodes, [${edgeVariables.map(flowEdgeMap).join(', ')}] AS edge_props`,\n 'LIMIT 500',\n ].join(' '),\n }\n}\n\nfunction rowNodeIsExchange(value: unknown): boolean {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return false\n const record = value as Record<string, unknown>\n return isExchangeFlag(record['is_exchange']) ||\n hasExactExchangeLabel(stringArrayValue(record['labels'])) ||\n hasExactExchangeLabel(stringArrayValue(record['system_labels']))\n}\n\nfunction reverseDepositSourceRowUsesExchange(row: Record<string, unknown>): boolean {\n if (isExchangeFlag(row['source_is_exchange']) || isExchangeFlag(row['deposit_is_exchange'])) return true\n if (!Array.isArray(row['path_nodes'])) return false\n return row['path_nodes'].some(rowNodeIsExchange)\n}\n\nfunction htmlEscape(value: unknown): string {\n return String(value ?? '')\n .replaceAll('&', '&amp;')\n .replaceAll('<', '&lt;')\n .replaceAll('>', '&gt;')\n .replaceAll('\"', '&quot;')\n .replaceAll(\"'\", '&#39;')\n}\n\nfunction buildTraceSourceTableHtml(tool: TraceToolName, network: string, rows: Array<Record<string, unknown>>): string {\n const headers = ['path_id', 'source_address', 'deposit_address', 'hop', 'amount_sum', 'first_tx_id'] as const\n const body = rows.map((row) => `<tr>${headers.map((header) => `<td>${htmlEscape(row[header])}</td>`).join('')}</tr>`).join('\\n')\n return `<!doctype html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<title>${htmlEscape(tool)} Table</title>\n<style>\n :root { color-scheme: dark; font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif; background: #0b0d12; color: #f4f2ea; }\n body { margin: 0; background: #0b0d12; color: #f4f2ea; }\n main { padding: 24px; }\n h1 { font-size: 20px; margin: 0 0 8px; font-weight: 650; }\n .meta { display: grid; gap: 6px; margin: 0 0 20px; color: rgba(244,242,234,.72); font-size: 13px; }\n .table-wrap { overflow: auto; border: 1px solid rgba(255,255,255,.1); border-radius: 8px; background: #10131b; }\n table { border-collapse: collapse; width: 100%; min-width: 980px; font-size: 12px; }\n th, td { border-bottom: 1px solid rgba(255,255,255,.08); padding: 8px 10px; text-align: left; vertical-align: top; }\n th { position: sticky; top: 0; background: #161a24; color: #f2dda6; font-weight: 600; z-index: 1; }\n td { color: rgba(244,242,234,.86); font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }\n tr:hover td { background: rgba(242,221,166,.045); }\n</style>\n</head>\n<body>\n<main>\n <h1>${htmlEscape(tool)} Table</h1>\n <div class=\"meta\">\n <div>Network: <strong>${htmlEscape(network)}</strong></div>\n <div>Generated: <strong>${htmlEscape(new Date().toISOString())}</strong></div>\n <div>Rows: <strong>${rows.length}</strong></div>\n </div>\n <div class=\"table-wrap\">\n <table>\n <thead><tr>${headers.map((header) => `<th>${htmlEscape(header)}</th>`).join('')}</tr></thead>\n <tbody>\n${body}\n </tbody>\n </table>\n </div>\n</main>\n</body>\n</html>\n`\n}\n\nasync function writeTraceSourceArtifacts(tool: TraceToolName, network: string, graphData: Record<string, unknown>, rows: Array<Record<string, unknown>>, summaryText: string): Promise<Record<string, unknown>> {\n const paths = workspaceOutputPaths()\n await Promise.all([\n mkdir(paths.reportsRoot, { recursive: true }),\n mkdir(paths.reportGraphsRoot, { recursive: true }),\n mkdir(paths.reportTablesRoot, { recursive: true }),\n ])\n const slug = `${new Date().toISOString().replace(/[-:]/g, '').replace(/\\.\\d{3}Z$/, 'Z')}_${tool}`\n const graphPath = path.join(paths.reportGraphsRoot, `${slug}.graph.json`)\n const tableJsonPath = path.join(paths.reportTablesRoot, `${slug}.compact-evidence.json`)\n const csvPath = path.join(paths.reportTablesRoot, `${slug}.flows.csv`)\n const tableHtmlPath = path.join(paths.reportsRoot, `${slug}.table.html`)\n const reportPath = path.join(paths.reportsRoot, `${slug}.trace-report.md`)\n const graphHtmlPath = path.join(paths.reportsRoot, `${slug}.graph.html`)\n const { generateInlineGraphHtml } = await import('../viz/html-generator.js')\n const csv = [\n 'path_id,source_address,deposit_address,hop,amount_sum,first_tx_id',\n ...rows.map((row) => [\n row['path_id'] ?? '',\n row['source_address'] ?? '',\n row['deposit_address'] ?? '',\n row['hop'] ?? '',\n row['amount_sum'] ?? '',\n row['first_tx_id'] ?? '',\n ].map((value) => JSON.stringify(String(value))).join(',')),\n ].join('\\n') + '\\n'\n await writeFile(graphPath, JSON.stringify(graphData, null, 2) + '\\n', { mode: 0o600 })\n await writeFile(tableJsonPath, JSON.stringify(rows, null, 2) + '\\n', { mode: 0o600 })\n await writeFile(csvPath, csv, { mode: 0o600 })\n await writeFile(tableHtmlPath, buildTraceSourceTableHtml(tool, network, rows), { mode: 0o600 })\n await writeFile(reportPath, summaryText + '\\n', { mode: 0o600 })\n await writeFile(graphHtmlPath, generateInlineGraphHtml(graphData), { mode: 0o600 })\n return {\n graph_json: graphPath,\n graph_html: graphHtmlPath,\n table_json: tableJsonPath,\n flows_csv: csvPath,\n table_html: tableHtmlPath,\n report_md: reportPath,\n }\n}\n\nexport async function traceDepositSources(\n remoteClient: Client,\n _config: Pick<InvestigatorConfig, 'dataDir' | 'serverPort'>,\n options: TraceDepositSourcesOptions,\n): Promise<TraceToolResult> {\n const network = options.network.trim()\n const deposits = parseAddressList(options.depositAddresses)\n if (!network) throw new Error('network is required')\n if (deposits.length < 1) throw new Error('deposit_addresses must contain at least 1 address')\n if (deposits.length > 5) throw new Error('deposit_addresses cannot exceed 5 addresses')\n const maxHops = clampInt(options.maxHops, 2, 1, 5)\n\n const batch = await callGraphBatch(\n remoteClient,\n network,\n Array.from({ length: maxHops }, (_, index) => reverseDepositSourceQueryAtDepth(deposits, index + 1)),\n )\n const failures: QueryFailure[] = []\n const rows: Array<Record<string, unknown>> = optionalResultsWithPrefix(batch, 'reverse_deposit_sources_', failures)\n .filter((row) => !reverseDepositSourceRowUsesExchange(row))\n .map((row, index) => ({\n ...row,\n path_id: `p${index + 1}`,\n }))\n const addresses = new Map<string, {\n address: string\n roles: Set<TraceRole>\n labels: string[]\n is_exchange?: boolean\n confidence: 'low' | 'medium' | 'high'\n rationale: string[]\n }>()\n for (const deposit of deposits) addTraceAddress(addresses, deposit, 'seed_deposit', 'Deposit/cashout seed provided by caller')\n\n const edges: Array<Record<string, unknown>> = []\n const paths: Array<Record<string, unknown>> = []\n for (const row of rows) {\n const sourceAddress = typeof row['source_address'] === 'string' ? row['source_address'] : ''\n const depositAddress = typeof row['deposit_address'] === 'string' ? row['deposit_address'] : ''\n const pathAddresses = stringArrayValue(row['addresses']) ?? [sourceAddress, depositAddress].filter(Boolean)\n addTraceAddress(addresses, sourceAddress, 'candidate_suspect', 'Upstream address funds a suspected deposit/cashout seed')\n addTraceAddress(addresses, depositAddress, 'seed_deposit', 'Deposit/cashout seed provided by caller')\n const edgeProps = Array.isArray(row['edge_props']) ? row['edge_props'] as Array<Record<string, unknown>> : []\n const edgeIds: string[] = []\n for (let index = 0; index < pathAddresses.length - 1; index += 1) {\n const props = edgeProps[index] ?? {}\n const edgeId = `e${edges.length + 1}`\n edgeIds.push(edgeId)\n edges.push({\n edge_id: edgeId,\n from_address: pathAddresses[index],\n to_address: pathAddresses[index + 1],\n edge_type: 'FLOWS_TO',\n amount_sum: numberValue(props['amount_sum']) ?? numberValue(row['amount_sum']),\n amount_usd_sum: numberValue(props['amount_usd_sum']) ?? numberValue(row['amount_usd_sum']),\n tx_count: numberValue(props['tx_count']) ?? numberValue(row['tx_count']),\n first_seen_timestamp: numberValue(props['first_seen_timestamp']) ?? numberValue(row['first_seen_timestamp']),\n last_seen_timestamp: numberValue(props['last_seen_timestamp']) ?? numberValue(row['last_seen_timestamp']),\n first_tx_id: typeof props['first_tx_id'] === 'string' ? props['first_tx_id'] : typeof row['first_tx_id'] === 'string' ? row['first_tx_id'] : undefined,\n last_tx_id: typeof props['last_tx_id'] === 'string' ? props['last_tx_id'] : typeof row['last_tx_id'] === 'string' ? row['last_tx_id'] : undefined,\n })\n }\n paths.push({\n path_id: row['path_id'],\n direction: 'reverse',\n source: depositAddress,\n target: sourceAddress,\n addresses: [...pathAddresses].reverse(),\n edge_ids: [...edgeIds].reverse(),\n hops: numberValue(row['hop']) ?? Math.max(pathAddresses.length - 1, 0),\n terminal_role: 'source',\n amount_sum: numberValue(row['amount_sum']),\n amount_usd_sum: numberValue(row['amount_usd_sum']),\n first_seen_ms: numberValue(row['first_seen_timestamp']),\n last_seen_ms: numberValue(row['last_seen_timestamp']),\n })\n }\n\n const sourceToPathIds = new Map<string, string[]>()\n const sourceToDeposits = new Map<string, Set<string>>()\n for (const row of rows) {\n const source = typeof row['source_address'] === 'string' ? row['source_address'] : ''\n const deposit = typeof row['deposit_address'] === 'string' ? row['deposit_address'] : ''\n if (!source) continue\n sourceToPathIds.set(source, [...(sourceToPathIds.get(source) ?? []), String(row['path_id'])])\n if (!sourceToDeposits.has(source)) sourceToDeposits.set(source, new Set())\n if (deposit) sourceToDeposits.get(source)!.add(deposit)\n }\n const convergence = [...sourceToPathIds.entries()]\n .filter(([address]) => (sourceToDeposits.get(address)?.size ?? 0) > 1)\n .map(([address, pathIds]) => ({\n address,\n role: 'candidate_suspect',\n path_ids: pathIds,\n reason: 'Same upstream source funds multiple provided deposit/cashout seeds.',\n }))\n const candidateSuspects = convergence.map((entry) => entry.address)\n const candidateLabels = [...sourceToPathIds.keys()].map((address) => ({\n address,\n candidate_label: 'candidate_suspect',\n confidence: candidateSuspects.includes(address) ? 'high' : 'medium',\n evidence_path_ids: sourceToPathIds.get(address) ?? [],\n reason: candidateSuspects.includes(address)\n ? 'Upstream source converges into multiple provided deposit/cashout seeds.'\n : 'Upstream source funds a provided deposit/cashout seed.',\n promote_to_core_label: false,\n }))\n const graphData = normalizeGraphPayload({\n schema: 'chain-insights.graph.v1',\n nodes: [...addresses.values()].map((entry) => ({\n id: entry.address,\n address: entry.address,\n node_type: 'address',\n roles: [...entry.roles],\n labels: entry.labels,\n })),\n edges: edges.map((edge) => ({\n source: edge['from_address'],\n target: edge['to_address'],\n edge_type: 'flows_to',\n amount_sum: edge['amount_sum'],\n tx_count: edge['tx_count'],\n first_tx_id: edge['first_tx_id'],\n last_tx_id: edge['last_tx_id'],\n direction: 'traceback',\n })),\n flows: edges.map((edge, index) => ({\n hop: index + 1,\n src: edge['from_address'],\n dst: edge['to_address'],\n amount_sum: edge['amount_sum'] ?? 0,\n terminal_exchange: false,\n })),\n edge_anchors: [],\n metadata: {\n network,\n deposit_addresses: deposits,\n generated_at: new Date().toISOString(),\n },\n })\n const summaryText = [\n `Trace deposit sources complete for ${network}`,\n '',\n `Deposit seeds: ${deposits.join(', ')}`,\n `Reverse path(s): ${paths.length}`,\n `Shared upstream convergence: ${convergence.length}`,\n ].join('\\n')\n const artifacts = await writeTraceSourceArtifacts('trace_deposit_sources', network, graphData, rows, summaryText)\n const evidence = artifactEvidence(artifacts)\n if (options.caseId) {\n const { EvidenceStore } = await import('../cases/index.js')\n await EvidenceStore.append(options.caseId, {\n source: 'trace_deposit_sources',\n queryParams: `network=${network} deposit_addresses=${deposits.join(',')} max_hops=${maxHops}`,\n content: JSON.stringify({\n schema: 'chain-insights.evidence_pointer.v1',\n source: 'trace_deposit_sources',\n network,\n deposit_addresses: deposits,\n files: artifacts,\n compact_sha256: createHash('sha256').update(JSON.stringify({ rows, convergence })).digest('hex'),\n }, null, 2),\n })\n evidence.push({ evidence_type: 'case_pointer', summary: `case_id=${options.caseId}` })\n }\n\n return {\n summaryText,\n structuredContent: {\n schema: 'chain-insights.trace.v1',\n tool: 'trace_deposit_sources',\n network,\n input: {\n addresses: deposits,\n seed_role: 'deposit',\n ...(options.timeRange ? { time_range: options.timeRange } : {}),\n max_hops: maxHops,\n },\n summary: {\n seed_count: deposits.length,\n path_count: paths.length,\n edge_count: edges.length,\n candidate_suspect_count: sourceToPathIds.size,\n candidate_intermediate_count: 0,\n candidate_deposit_count: deposits.length,\n exchange_count: 0,\n },\n addresses: [...addresses.values()].map((entry) => ({\n address: entry.address,\n roles: [...entry.roles],\n confidence: entry.confidence,\n rationale: entry.rationale,\n })),\n edges,\n paths,\n convergence,\n exchange_exposure: [],\n candidate_labels: candidateLabels,\n artifacts,\n evidence: [\n ...evidence,\n ...(failures.length > 0 ? [{ evidence_type: 'query_summary', summary: `partial query failures: ${failures.length}` }] : []),\n ],\n continuation: {\n candidate_deposit_addresses: deposits,\n candidate_suspect_addresses: candidateSuspects,\n candidate_victim_addresses: [],\n recommended_next_tools: candidateSuspects.length > 0\n ? ['trace_suspect_funds', 'address_risk']\n : ['address_risk', 'graph_query_batch'],\n },\n warnings: paths.length === 0 ? ['No upstream sources were connected in the queried topology.'] : [],\n },\n graphData,\n }\n}\n\nexport async function trackFunds(\n remoteClient: Client,\n config: Pick<InvestigatorConfig, 'dataDir' | 'serverPort'>,\n options: TrackFundsOptions,\n): Promise<{\n summaryText: string\n structuredContent: Record<string, unknown>\n graphData: Record<string, unknown>\n}> {\n const network = options.network.trim()\n const trusted = parseAddressList(options.trustedAddresses)\n const untrusted = parseAddressList(options.untrustedAddresses)\n if (!network) throw new Error('network is required')\n if (trusted.length < 1) throw new Error('trusted_addresses must contain at least 1 address')\n if (trusted.length > 5) throw new Error('trusted_addresses cannot exceed 5 addresses')\n if (untrusted.length > 5) throw new Error('untrusted_addresses cannot exceed 5 addresses')\n const overlap = trusted.filter((address) => untrusted.includes(address))\n if (overlap.length > 0) throw new Error(`Address(es) appear in both trusted and untrusted lists: ${overlap.join(', ')}`)\n\n const runs: Array<{ role: 'trusted' | 'untrusted'; address: string; result: TraceFundsResult }> = []\n for (const address of trusted) {\n runs.push({\n role: 'trusted',\n address,\n result: await runFundFlowProbe(remoteClient, config, {\n seedAddress: address,\n network,\n caseId: options.caseId,\n maxHops: options.maxHops,\n perAddressLimit: options.perAddressLimit,\n minAmountSum: options.minAmountSum,\n }),\n })\n }\n for (const address of untrusted) {\n runs.push({\n role: 'untrusted',\n address,\n result: await runFundFlowProbe(remoteClient, config, {\n seedAddress: address,\n network,\n caseId: options.caseId,\n maxHops: options.maxHops,\n perAddressLimit: options.perAddressLimit,\n minAmountSum: options.minAmountSum,\n }),\n })\n }\n\n const graphData = normalizeGraphPayload({\n schema: 'chain-insights.graph.v1',\n nodes: runs.flatMap((run) => Array.isArray(run.result.graphData.nodes) ? run.result.graphData.nodes : []),\n edges: runs.flatMap((run) => Array.isArray(run.result.graphData.edges) ? run.result.graphData.edges : []),\n flows: runs.flatMap((run) => Array.isArray(run.result.graphData.flows) ? run.result.graphData.flows : []),\n deposits: runs.flatMap((run) => graphArray(run.result.graphData, 'deposits').map((item) => ({ ...item, run_role: run.role, run_address: run.address }))),\n source_matches: runs.flatMap((run) => graphArray(run.result.graphData, 'source_matches').map((item) => ({ ...item, run_role: run.role, run_address: run.address }))),\n reverse_leads: runs.flatMap((run) => graphArray(run.result.graphData, 'reverse_leads').map((item) => ({ ...item, run_role: run.role, run_address: run.address }))),\n edge_anchors: [],\n metadata: { network, trusted_addresses: trusted, untrusted_addresses: untrusted, generated_at: new Date().toISOString() },\n })\n\n return {\n summaryText: [\n `Track funds complete for ${network}`,\n '',\n `Trusted addresses: ${trusted.join(', ')}`,\n `Untrusted addresses: ${untrusted.join(', ') || 'none'}`,\n '',\n ...runs.map((run) => `## ${run.role}: ${run.address}\\n${run.result.summaryText}`),\n ].join('\\n'),\n structuredContent: {\n schema: 'chain-insights.result.v1',\n tool: 'track_funds',\n facts: {\n network,\n trusted_addresses: trusted,\n untrusted_addresses: untrusted,\n runs: runs.map((run) => ({\n role: run.role,\n address: run.address,\n files: run.result.files,\n continuation: run.result.continuation,\n address_map: run.result.addressMap,\n })),\n },\n },\n graphData,\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"public-tools-CyUZEz9B.mjs","names":["GRAPH_QUERY_BATCH_TIMEOUT_SECONDS","GRAPH_QUERY_BATCH_REQUEST_TIMEOUT_MS","clampInt","escapeCypherString","textFromToolResult","parseGraphBatchResult","topologyGraphQuery","callGraphBatch","flowEdgeMap","pathNodeMap","edgeKey","numberValue","isExchangeFlag","stringArrayValue","uniqueStrings","hasExactExchangeLabel","htmlEscape","escapeCypherString","textFromToolResult","parseGraphBatchResult","numberValue","clampInt","callGraphBatch"],"sources":["../src/investigation/trace-funds.ts","../src/investigation/stake-insights.ts","../src/investigation/public-tools.ts"],"sourcesContent":["import { mkdir, readFile, writeFile } from 'node:fs/promises'\nimport path from 'node:path'\nimport type { Client } from '@modelcontextprotocol/sdk/client/index.js'\nimport type { ContentBlock } from '@modelcontextprotocol/sdk/types.js'\nimport type { InvestigatorConfig } from '../config/schema.js'\nimport { normalizeGraphPayload } from '../viz/graph-normalizer.js'\nimport { workspaceOutputPaths, type WorkspaceOutputPaths } from '../workspace/output-root.js'\n\ntype RemoteToolResult = {\n content?: ContentBlock[]\n isError?: boolean\n}\n\nexport interface TraceFundsOptions {\n seedAddress: string\n network: string\n caseId?: string\n maxHops?: number\n perAddressLimit?: number\n minAmountSum?: number\n includeDepositTraceback?: boolean\n evidenceSource?: string\n}\n\nexport interface TraceFlow {\n hop: number\n src: string\n dst: string\n amount_sum: number\n amount_usd_sum?: number\n tx_count?: number\n first_tx_id?: string\n last_tx_id?: string\n src_labels?: string[]\n dst_labels?: string[]\n src_node?: GraphNodeMetadata\n dst_node?: GraphNodeMetadata\n dst_degree_in?: number\n dst_degree_out?: number\n terminal_exchange: boolean\n}\n\nexport interface TraceFundsResult {\n summaryText: string\n compactEvidence: Record<string, unknown>\n graphData: Record<string, unknown>\n files: {\n schema: string\n compactEvidence: string\n graph: string\n graphHtml: string\n table: string\n tableHtml: string\n report: string\n }\n continuation: {\n nextHopAddresses: string[]\n depositAddresses: string[]\n exchangeAddresses: string[]\n hint: string\n }\n addressMap: Record<string, string>\n}\n\ninterface TraceDeposit {\n address: string\n exchangeAddress: string\n exchangeLabels?: string[]\n exchangeNode?: GraphNodeMetadata\n amount_sum?: number\n amount_usd_sum?: number\n hops: number\n path: string[]\n pathNodes?: GraphNodeMetadata[]\n}\n\ninterface SourceMatch {\n deposit_address: string\n source_exchange: string\n source_labels?: string[]\n sourceNode?: GraphNodeMetadata\n hops: number\n path: string[]\n pathNodes?: GraphNodeMetadata[]\n}\n\ninterface ReverseLead {\n address: string\n labels?: string[]\n node?: GraphNodeMetadata\n deposit_address: string\n amount_usd?: number\n degree_in?: number\n degree_out?: number\n total_volume_usd?: number\n reason: string\n}\n\ninterface GraphNodeMetadata {\n address: string\n labels?: string[]\n system_labels?: string[]\n address_type?: string\n address_subtypes?: string[]\n is_exchange?: boolean\n}\n\nclass AliasTracker {\n private readonly byAddress = new Map<string, string>()\n private readonly byAlias = new Map<string, string>()\n private readonly counters = new Map<string, number>()\n\n assign(address: string, prefix: string): string {\n const existing = this.byAddress.get(address)\n if (existing) return existing\n const next = (this.counters.get(prefix) ?? 0) + 1\n this.counters.set(prefix, next)\n const alias = `${prefix}${next}`\n this.byAddress.set(address, alias)\n this.byAlias.set(alias, address)\n return alias\n }\n\n alias(address: string): string | undefined {\n return this.byAddress.get(address)\n }\n\n addressMap(): Record<string, string> {\n return Object.fromEntries([...this.byAlias.entries()].sort(([a], [b]) => a.localeCompare(b, undefined, { numeric: true })))\n }\n\n compactAddressMap(maxIntermediaries = 20, maxSourceExchanges = 20, maxLeads = 20): Record<string, string> {\n const counts = new Map<string, number>()\n const entries = [...this.byAlias.entries()].filter(([alias]) => {\n const prefix = alias.slice(0, 1)\n if (['V', 'D', 'E'].includes(prefix)) return true\n const next = (counts.get(prefix) ?? 0) + 1\n counts.set(prefix, next)\n if (prefix === 'I') return next <= maxIntermediaries\n if (prefix === 'X') return next <= maxSourceExchanges\n if (prefix === 'L') return next <= maxLeads\n return true\n })\n return Object.fromEntries(entries.sort(([a], [b]) => a.localeCompare(b, undefined, { numeric: true })))\n }\n}\n\ninterface ParsedGraphBatch {\n facts?: {\n queries?: Array<{\n id?: string\n ok?: boolean\n results?: Array<Record<string, unknown>>\n error?: string\n }>\n }\n}\n\nconst GRAPH_QUERY_BATCH_TIMEOUT_SECONDS = 120\nconst GRAPH_QUERY_BATCH_REQUEST_TIMEOUT_MS = 5 * 60 * 1000\n\nconst SCHEMA_QUERY_SET = [\n {\n id: 'node_labels',\n query: 'MATCH (n:Address) RETURN \"Address\" AS node_label, count(n) AS sample_count LIMIT 1',\n },\n {\n id: 'relationship_types',\n query: 'MATCH (:Address)-[r:FLOWS_TO]->(:Address) RETURN \"FLOWS_TO\" AS rel_name, count(r) AS sample_count LIMIT 1',\n },\n {\n id: 'address_property_keys',\n query: 'MATCH (n:Address) RETURN \"address\" AS property_key, count(n) AS sample_count LIMIT 1',\n },\n {\n id: 'flows_to_property_keys',\n query: 'MATCH (:Address)-[r:FLOWS_TO]->(:Address) RETURN \"amount_sum\" AS property_key, count(r) AS sample_count LIMIT 1',\n },\n]\n\nfunction clampInt(value: number | undefined, fallback: number, min: number, max: number): number {\n if (!Number.isFinite(value)) return fallback\n return Math.max(min, Math.min(max, Math.trunc(value as number)))\n}\n\nfunction escapeCypherString(value: string): string {\n return value.replaceAll('\\\\', '\\\\\\\\').replaceAll('\"', '\\\\\"')\n}\n\nfunction sanitizeSegment(value: string): string {\n const sanitized = value.toLowerCase().replace(/[^a-z0-9_-]+/g, '-').replace(/(^-|-$)/g, '').slice(0, 80)\n return sanitized || 'trace'\n}\n\nasync function ensureDirs(paths: WorkspaceOutputPaths): Promise<void> {\n await mkdir(paths.schemaDir, { recursive: true, mode: 0o700 })\n await mkdir(paths.reportsRoot, { recursive: true, mode: 0o700 })\n await mkdir(paths.reportGraphsRoot, { recursive: true, mode: 0o700 })\n await mkdir(paths.reportTablesRoot, { recursive: true, mode: 0o700 })\n await mkdir(paths.logsRoot, { recursive: true, mode: 0o700 })\n}\n\nfunction textFromToolResult(result: RemoteToolResult): string {\n return (result.content ?? [])\n .filter((item): item is Extract<ContentBlock, { type: 'text' }> => item.type === 'text')\n .map((item) => item.text)\n .join('\\n')\n}\n\nfunction parseGraphBatchResult(result: RemoteToolResult): ParsedGraphBatch {\n const text = textFromToolResult(result).trim()\n if (!text) throw new Error('graph_query_batch returned no text content')\n const parsed = JSON.parse(text) as ParsedGraphBatch\n if (!parsed.facts?.queries) throw new Error('graph_query_batch response did not include facts.queries')\n return parsed\n}\n\nfunction topologyGraphQuery(query: string): string {\n const trimmed = query.trim()\n if (/^USE\\s+/i.test(trimmed)) return trimmed\n return `USE live_topology ${trimmed}`\n}\n\nasync function callGraphBatch(\n remoteClient: Client,\n network: string,\n queries: Array<{ id: string; query: string }>,\n): Promise<ParsedGraphBatch> {\n const result = await remoteClient.callTool(\n {\n name: 'graph_query_batch',\n arguments: {\n network,\n queries: queries.map((query) => ({\n ...query,\n query: topologyGraphQuery(query.query),\n })),\n per_query_timeout_seconds: GRAPH_QUERY_BATCH_TIMEOUT_SECONDS,\n },\n },\n undefined,\n {\n timeout: GRAPH_QUERY_BATCH_REQUEST_TIMEOUT_MS,\n maxTotalTimeout: GRAPH_QUERY_BATCH_REQUEST_TIMEOUT_MS,\n },\n ) as RemoteToolResult\n if (result.isError) throw new Error(textFromToolResult(result) || 'graph_query_batch failed')\n return parseGraphBatchResult(result)\n}\n\nfunction resultsFor(batch: ParsedGraphBatch, id: string): Array<Record<string, unknown>> {\n const query = batch.facts?.queries?.find((entry) => entry.id === id)\n if (!query) return []\n if (query.ok === false) throw new Error(query.error || `Query failed: ${id}`)\n return query.results ?? []\n}\n\nfunction schemaFromGraphBatch(network: string, batch: ParsedGraphBatch): Record<string, unknown> {\n return {\n schema: 'chain-insights.runtime_graph_schema.v1',\n network,\n source: 'graph_query_batch',\n node_labels: resultsFor(batch, 'node_labels'),\n relationship_types: resultsFor(batch, 'relationship_types'),\n address_property_keys: resultsFor(batch, 'address_property_keys').map((row) => row['property_key']),\n flows_to_property_keys: resultsFor(batch, 'flows_to_property_keys').map((row) => row['property_key']),\n recommended_flow_projection: [\n 'src.address AS src',\n 'dst.address AS dst',\n 'r.amount_sum AS amount_sum',\n 'r.amount_usd_sum AS amount_usd_sum',\n 'r.tx_count AS tx_count',\n 'r.first_tx_id AS first_tx_id',\n 'r.last_tx_id AS last_tx_id',\n 'dst.labels AS dst_labels',\n 'dst.lifetime_degree_in AS dst_degree_in',\n 'dst.lifetime_degree_out AS dst_degree_out',\n ],\n }\n}\n\nasync function loadOrCaptureTopologySchema(\n remoteClient: Client,\n paths: WorkspaceOutputPaths,\n network: string,\n): Promise<{ schema: Record<string, unknown>; filePath: string }> {\n const filePath = path.join(paths.schemaDir, `${sanitizeSegment(network)}.graph-schema.json`)\n try {\n return { schema: JSON.parse(await readFile(filePath, 'utf8')) as Record<string, unknown>, filePath }\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') throw err\n }\n\n const batch = await callGraphBatch(\n remoteClient,\n network,\n SCHEMA_QUERY_SET,\n )\n const schema = schemaFromGraphBatch(network, batch)\n await writeFile(filePath, JSON.stringify(schema, null, 2) + '\\n', { mode: 0o600 })\n return { schema, filePath }\n}\n\nfunction flowEdgeMap(variableName: string): string {\n return `{amount_sum: ${variableName}.amount_sum, amount_usd_sum: ${variableName}.amount_usd_sum, tx_count: ${variableName}.tx_count, first_tx_id: ${variableName}.first_tx_id, last_tx_id: ${variableName}.last_tx_id}`\n}\n\nfunction pathNodeMap(variableName: string): string {\n return `{address: ${variableName}.address, labels: ${variableName}.labels, system_labels: ${variableName}.labels, address_type: ${variableName}.address_type, address_subtypes: ${variableName}.address_subtypes, is_exchange: ${variableName}.is_exchange}`\n}\n\nfunction forwardExchangeQueries(address: string, limit: number, minAmountSum: number, maxHops: number): Array<{ id: string; query: string }> {\n return Array.from({ length: maxHops }, (_, index) => forwardExchangeQueryAtDepth(address, limit, minAmountSum, index + 1))\n}\n\nfunction forwardExchangeQueryAtDepth(address: string, limit: number, minAmountSum: number, depth: number): { id: string; query: string } {\n const intermediateVariables = Array.from({ length: Math.max(depth - 1, 0) }, (_, index) => `n${index + 1}`)\n const nodeVariables = ['s', ...intermediateVariables, 't']\n const edgeVariables = Array.from({ length: depth }, (_, index) => `r${index + 1}`)\n const relationshipChain = edgeVariables.map((edgeVariable, index) => {\n const targetVariable = index === edgeVariables.length - 1 ? 't' : intermediateVariables[index]!\n return `-[${edgeVariable}:FLOWS_TO]->(${targetVariable}:Address)`\n }).join('')\n const amountPredicates = edgeVariables.map((edgeVariable) => `${edgeVariable}.amount_sum IS NOT NULL${minAmountSum > 0 ? ` AND ${edgeVariable}.amount_sum >= ${minAmountSum}` : ''}`)\n const nonTerminalPredicates = ['s', ...intermediateVariables].map((nodeVariable) => `${nodeVariable}.is_exchange IS NULL`)\n const predicates = ['s <> t', ...nonTerminalPredicates, 't.is_exchange IS NOT NULL', ...amountPredicates]\n const depositVariable = nodeVariables[nodeVariables.length - 2]!\n return {\n id: `forward_exchange_paths_${depth}`,\n query: [\n `MATCH (s:Address {address: \"${escapeCypherString(address)}\"})${relationshipChain}`,\n `WHERE ${predicates.join(' AND ')}`,\n `RETURN [${nodeVariables.map((nodeVariable) => `${nodeVariable}.address`).join(', ')}] AS addresses, [${nodeVariables.map((nodeVariable) => `${nodeVariable}.labels`).join(', ')}] AS node_labels, [${nodeVariables.map(pathNodeMap).join(', ')}] AS path_nodes, [${edgeVariables.map(flowEdgeMap).join(', ')}] AS edge_props, t.address AS exchange_address, t.labels AS exchange_display_labels, t.labels AS exchange_labels, t.address_type AS exchange_address_type, t.address_subtypes AS exchange_address_subtypes, t.is_exchange AS exchange_is_exchange, ${depositVariable}.address AS deposit_address, ${depositVariable}.is_exchange AS deposit_is_exchange, ${depth} AS hops`,\n 'ORDER BY hops ASC',\n `LIMIT ${limit}`,\n ].join(' '),\n }\n}\n\nfunction backwardSourceQueries(idPrefix: string, depositAddress: string, maxHops: number): Array<{ id: string; query: string }> {\n return Array.from({ length: maxHops }, (_, index) => backwardSourceQueryAtDepth(`${idPrefix}_${index + 1}`, depositAddress, index + 1))\n}\n\nfunction backwardSourceQueryAtDepth(id: string, depositAddress: string, depth: number): { id: string; query: string } {\n const intermediateVariables = Array.from({ length: Math.max(depth - 1, 0) }, (_, index) => `n${index + 1}`)\n const nodeVariables = ['dep', ...intermediateVariables, 'source']\n const edgeVariables = Array.from({ length: depth }, (_, index) => `r${index + 1}`)\n const relationshipChain = edgeVariables.map((edgeVariable, index) => {\n const targetVariable = index === edgeVariables.length - 1 ? 'source' : intermediateVariables[index]!\n return `<-[${edgeVariable}:FLOWS_TO]-(${targetVariable}:Address)`\n }).join('')\n const intermediatePredicates = intermediateVariables.map((nodeVariable) => `${nodeVariable}.is_exchange IS NULL`)\n return {\n id,\n query: [\n `MATCH (dep:Address {address: \"${escapeCypherString(depositAddress)}\"})`,\n `MATCH (dep)${relationshipChain}`,\n `WHERE source <> dep AND source.is_exchange IS NOT NULL${intermediatePredicates.length > 0 ? ` AND ${intermediatePredicates.join(' AND ')}` : ''}`,\n `RETURN dep.address AS deposit_address, source.address AS source_exchange, source.labels AS source_display_labels, source.labels AS source_labels, source.address_type AS source_address_type, source.address_subtypes AS source_address_subtypes, ${depth} AS hops, [${nodeVariables.map((nodeVariable) => `${nodeVariable}.address`).join(', ')}] AS addresses, [${nodeVariables.map((nodeVariable) => `${nodeVariable}.labels`).join(', ')}] AS node_labels, [${nodeVariables.map(pathNodeMap).join(', ')}] AS path_nodes`,\n 'LIMIT 20',\n ].join(' '),\n }\n}\n\nfunction reverseLeadsQuery(depositAddresses: string[]): { id: string; query: string } {\n const depositPredicates = depositAddresses.map((address) => `deposit.address = \"${escapeCypherString(address)}\"`)\n return {\n id: 'reverse_1hop',\n query: [\n 'MATCH (sender:Address)-[r:FLOWS_TO]->(deposit:Address)',\n `WHERE (${depositPredicates.join(' OR ')}) AND sender.is_exchange IS NULL AND sender.address <> deposit.address`,\n 'RETURN DISTINCT sender.address AS address, sender.labels AS display_labels, sender.labels AS system_labels, sender.address_type AS address_type, sender.address_subtypes AS address_subtypes, coalesce(sender.lifetime_degree_in, 0) AS degree_in, coalesce(sender.lifetime_degree_out, 0) AS degree_out, coalesce(sender.total_volume_usd, 0) AS total_volume_usd, deposit.address AS deposit_address, r.amount_usd_sum AS amount_usd',\n 'ORDER BY r.amount_usd_sum DESC',\n `LIMIT ${Math.max(50, depositAddresses.length * 50)}`,\n ].join(' '),\n }\n}\n\nfunction edgeKey(src: string, dst: string): string {\n return `${src}\\u0000${dst}`\n}\n\nfunction directEdgePropsQuery(flows: TraceFlow[]): { id: string; query: string } | null {\n const pairs = [...new Map(flows.map((flow) => [edgeKey(flow.src, flow.dst), { src: flow.src, dst: flow.dst }])).values()]\n if (pairs.length === 0) return null\n const predicates = pairs.map((pair) =>\n `(a.address = \"${escapeCypherString(pair.src)}\" AND b.address = \"${escapeCypherString(pair.dst)}\")`\n )\n return {\n id: 'direct_edge_props',\n query: [\n 'MATCH (a:Address)-[r:FLOWS_TO]->(b:Address)',\n `WHERE (${predicates.join(' OR ')})`,\n 'RETURN a.address AS src, b.address AS dst, r.amount_sum AS amount_sum, r.amount_usd_sum AS amount_usd_sum, r.tx_count AS tx_count, r.first_tx_id AS first_tx_id, r.last_tx_id AS last_tx_id',\n `LIMIT ${pairs.length}`,\n ].join(' '),\n }\n}\n\nfunction numberValue(value: unknown): number | undefined {\n if (typeof value === 'number' && Number.isFinite(value)) return value\n if (typeof value === 'string' && value.trim()) {\n const parsed = Number(value)\n return Number.isFinite(parsed) ? parsed : undefined\n }\n return undefined\n}\n\nfunction isExchangeFlag(value: unknown): boolean {\n if (value === true) return true\n if (value === false || value === null || value === undefined) return false\n if (typeof value === 'string') {\n const normalized = value.trim().toLowerCase()\n return normalized === 'true' || normalized === '1'\n }\n if (typeof value === 'number') return value === 1\n return false\n}\n\nfunction rowTerminalAmount(row: Record<string, unknown>): number | undefined {\n const edgeProps = Array.isArray(row['edge_props']) ? row['edge_props'] as Array<Record<string, unknown>> : []\n const terminalEdge = edgeProps[edgeProps.length - 1]\n if (!terminalEdge) return undefined\n return numberValue(terminalEdge['amount_sum']) ?? numberValue(terminalEdge['amount_usd_sum'])\n}\n\nfunction rowsMatchingMinimumAmount(rows: Array<Record<string, unknown>>, minAmountSum: number): Array<Record<string, unknown>> {\n if (minAmountSum <= 0) return rows\n return rows.filter((row) => (rowTerminalAmount(row) ?? 0) >= minAmountSum)\n}\n\nfunction stringArrayValue(value: unknown): string[] | undefined {\n if (Array.isArray(value)) return value.map(String)\n if (typeof value === 'string' && value.trim()) return [value]\n return undefined\n}\n\nfunction uniqueStrings(values: string[] | undefined): string[] {\n return [...new Set(values ?? [])]\n}\n\nfunction hasExactExchangeLabel(labels: string[] | undefined): boolean {\n return (labels ?? []).some((label) => label.trim().toLowerCase() === 'exchange')\n}\n\nfunction nodeMetadataFromValue(value: unknown, fallbackAddress?: string): GraphNodeMetadata | undefined {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n return fallbackAddress ? { address: fallbackAddress } : undefined\n }\n const record = value as Record<string, unknown>\n const address = typeof record['address'] === 'string' ? record['address'] : fallbackAddress\n if (!address) return undefined\n return {\n address,\n labels: stringArrayValue(record['labels']),\n system_labels: stringArrayValue(record['system_labels']),\n address_type: typeof record['address_type'] === 'string' ? record['address_type'] : undefined,\n address_subtypes: stringArrayValue(record['address_subtypes']),\n is_exchange: isExchangeFlag(record['is_exchange']),\n }\n}\n\nfunction isExchangeFlow(flow: TraceFlow): boolean {\n return flow.terminal_exchange ||\n isExchangeFlag(flow.dst_node?.is_exchange) ||\n hasExactExchangeLabel(flow.dst_labels) ||\n hasExactExchangeLabel(flow.dst_node?.system_labels) ||\n hasExactExchangeLabel(flow.dst_node?.labels)\n}\n\nfunction isExchangeNode(metadata: GraphNodeMetadata | undefined, labels: string[] | undefined): boolean {\n return isExchangeFlag(metadata?.is_exchange) ||\n hasExactExchangeLabel(labels) ||\n hasExactExchangeLabel(metadata?.system_labels) ||\n hasExactExchangeLabel(metadata?.labels)\n}\n\nfunction rowTouchesExchangeBeforeTerminal(pathNodes: Array<GraphNodeMetadata | undefined>, nodeLabels: string[][], pathLength: number): boolean {\n for (let index = 0; index < Math.max(pathLength - 1, 0); index += 1) {\n if (isExchangeNode(pathNodes[index], nodeLabels[index])) return true\n }\n return false\n}\n\nfunction depositFromRow(row: Record<string, unknown>): TraceDeposit | null {\n const pathAddresses = stringArrayValue(row['addresses']) ?? []\n if (pathAddresses.length < 2) return null\n const nodeLabels = Array.isArray(row['node_labels']) ? row['node_labels'].map((labels) => stringArrayValue(labels) ?? []) : []\n const exchangeAddress = typeof row['exchange_address'] === 'string' ? row['exchange_address'] : pathAddresses[pathAddresses.length - 1]\n const edgeProps = Array.isArray(row['edge_props']) ? row['edge_props'] as Array<Record<string, unknown>> : []\n const terminalEdge = edgeProps[edgeProps.length - 1] ?? {}\n const pathNodes = Array.isArray(row['path_nodes'])\n ? row['path_nodes'].map((node, index) => nodeMetadataFromValue(node, pathAddresses[index])).filter((node): node is GraphNodeMetadata => Boolean(node))\n : undefined\n const depositIndex = pathAddresses.length - 2\n const depositNode = pathNodes?.find((node) => node.address === pathAddresses[depositIndex]) ?? pathNodes?.[depositIndex]\n if (isExchangeFlag(row['deposit_is_exchange']) || isExchangeNode(depositNode, nodeLabels[depositIndex])) return null\n const exchangeNode = {\n address: exchangeAddress,\n labels: stringArrayValue(row['exchange_display_labels']),\n system_labels: stringArrayValue(row['exchange_system_labels']) ?? stringArrayValue(row['exchange_labels']),\n address_type: typeof row['exchange_address_type'] === 'string' ? row['exchange_address_type'] : undefined,\n address_subtypes: stringArrayValue(row['exchange_address_subtypes']),\n is_exchange: true,\n }\n return {\n address: pathAddresses[pathAddresses.length - 2]!,\n exchangeAddress,\n exchangeLabels: stringArrayValue(row['exchange_labels']),\n exchangeNode,\n amount_sum: numberValue(terminalEdge['amount_sum']),\n amount_usd_sum: numberValue(terminalEdge['amount_usd_sum']),\n hops: numberValue(row['hops']) ?? pathAddresses.length - 1,\n path: pathAddresses,\n pathNodes,\n }\n}\n\nfunction flowsFromForwardRows(rows: Array<Record<string, unknown>>): { flows: TraceFlow[]; deposits: TraceDeposit[] } {\n const flows: TraceFlow[] = []\n const deposits: TraceDeposit[] = []\n const seenEdges = new Set<string>()\n for (const row of rows) {\n const pathAddresses = stringArrayValue(row['addresses']) ?? []\n const nodeLabels = Array.isArray(row['node_labels']) ? row['node_labels'].map((labels) => stringArrayValue(labels) ?? []) : []\n const pathNodes = Array.isArray(row['path_nodes'])\n ? row['path_nodes'].map((node, index) => nodeMetadataFromValue(node, pathAddresses[index]))\n : []\n const edgeProps = Array.isArray(row['edge_props']) ? row['edge_props'] as Array<Record<string, unknown>> : []\n if (rowTouchesExchangeBeforeTerminal(pathNodes, nodeLabels, pathAddresses.length)) continue\n const deposit = depositFromRow(row)\n if (deposit) deposits.push(deposit)\n for (let index = 0; index < pathAddresses.length - 1; index += 1) {\n const src = pathAddresses[index]!\n const dst = pathAddresses[index + 1]!\n const edge = edgeProps[index] ?? {}\n const amount = numberValue(edge['amount_sum']) ?? numberValue(edge['amount_usd_sum']) ?? 0\n const terminal = index === pathAddresses.length - 2\n const key = `${src}->${dst}`\n if (seenEdges.has(key)) continue\n seenEdges.add(key)\n flows.push({\n hop: index + 1,\n src,\n dst,\n amount_sum: amount,\n amount_usd_sum: numberValue(edge['amount_usd_sum']),\n tx_count: numberValue(edge['tx_count']),\n first_tx_id: typeof edge['first_tx_id'] === 'string' ? edge['first_tx_id'] : undefined,\n last_tx_id: typeof edge['last_tx_id'] === 'string' ? edge['last_tx_id'] : undefined,\n src_labels: nodeLabels[index],\n dst_labels: nodeLabels[index + 1],\n src_node: pathNodes[index],\n dst_node: pathNodes[index + 1],\n terminal_exchange: terminal,\n })\n }\n }\n return { flows, deposits }\n}\n\nasync function hydrateDirectEdgeProps(remoteClient: Client, network: string, flows: TraceFlow[], deposits: TraceDeposit[]): Promise<void> {\n const query = directEdgePropsQuery(flows)\n if (!query) return\n\n const batch = await callGraphBatch(remoteClient, network, [query])\n const edgeProps = new Map<string, Record<string, unknown>>()\n for (const row of resultsFor(batch, 'direct_edge_props')) {\n const src = typeof row['src'] === 'string' ? row['src'] : ''\n const dst = typeof row['dst'] === 'string' ? row['dst'] : ''\n if (!src || !dst) continue\n edgeProps.set(edgeKey(src, dst), row)\n }\n\n for (const flow of flows) {\n const props = edgeProps.get(edgeKey(flow.src, flow.dst))\n if (!props) continue\n flow.amount_sum = numberValue(props['amount_sum']) ?? flow.amount_sum\n flow.amount_usd_sum = numberValue(props['amount_usd_sum'])\n flow.tx_count = numberValue(props['tx_count'])\n flow.first_tx_id = typeof props['first_tx_id'] === 'string' ? props['first_tx_id'] : undefined\n flow.last_tx_id = typeof props['last_tx_id'] === 'string' ? props['last_tx_id'] : undefined\n }\n\n for (const deposit of deposits) {\n const props = edgeProps.get(edgeKey(deposit.address, deposit.exchangeAddress))\n if (!props) continue\n deposit.amount_sum = numberValue(props['amount_sum'])\n deposit.amount_usd_sum = numberValue(props['amount_usd_sum'])\n }\n}\n\nasync function collectProbeTrace(\n remoteClient: Client,\n options: Required<Pick<TraceFundsOptions, 'seedAddress' | 'network' | 'maxHops' | 'perAddressLimit' | 'minAmountSum'>> & Pick<TraceFundsOptions, 'includeDepositTraceback'>,\n): Promise<{ flows: TraceFlow[]; deposits: TraceDeposit[]; sourceMatches: SourceMatch[]; reverseLeads: ReverseLead[] }> {\n const forwardBatch = await callGraphBatch(remoteClient, options.network, [\n ...forwardExchangeQueries(options.seedAddress, Math.max(options.perAddressLimit * 20, 200), options.minAmountSum, options.maxHops),\n ])\n const forwardRows = rowsMatchingMinimumAmount((forwardBatch.facts?.queries ?? [])\n .filter((query) => query.id?.startsWith('forward_exchange_paths_'))\n .flatMap((query) => {\n if (query.ok === false) throw new Error(query.error || `Query failed: ${query.id}`)\n return query.results ?? []\n }), options.minAmountSum)\n const { flows, deposits } = flowsFromForwardRows(forwardRows)\n await hydrateDirectEdgeProps(remoteClient, options.network, flows, deposits)\n const uniqueDepositAddresses = [...new Set(deposits.map((deposit) => deposit.address))]\n\n const sourceMatches: SourceMatch[] = []\n if (options.includeDepositTraceback !== false && uniqueDepositAddresses.length > 0) {\n const backwardBatch = await callGraphBatch(\n remoteClient,\n options.network,\n uniqueDepositAddresses.slice(0, Math.max(1, Math.floor(20 / options.maxHops))).flatMap((address, index) => backwardSourceQueries(`backward_from_deposit_${index + 1}`, address, options.maxHops)),\n )\n for (const query of backwardBatch.facts?.queries ?? []) {\n for (const row of query.results ?? []) {\n const pathAddresses = stringArrayValue(row['addresses']) ?? []\n const pathNodes = Array.isArray(row['path_nodes'])\n ? row['path_nodes'].map((node, index) => nodeMetadataFromValue(node, pathAddresses[index])).filter((node): node is GraphNodeMetadata => Boolean(node))\n : undefined\n const depositAddress = typeof row['deposit_address'] === 'string' ? row['deposit_address'] : pathAddresses[0]\n const sourceExchange = typeof row['source_exchange'] === 'string' ? row['source_exchange'] : pathAddresses[pathAddresses.length - 1]\n if (!depositAddress || !sourceExchange) continue\n const sourceNode = {\n address: sourceExchange,\n labels: stringArrayValue(row['source_display_labels']),\n system_labels: stringArrayValue(row['source_system_labels']) ?? stringArrayValue(row['source_labels']),\n address_type: typeof row['source_address_type'] === 'string' ? row['source_address_type'] : undefined,\n address_subtypes: stringArrayValue(row['source_address_subtypes']),\n }\n sourceMatches.push({\n deposit_address: depositAddress,\n source_exchange: sourceExchange,\n source_labels: stringArrayValue(row['source_labels']),\n sourceNode,\n hops: numberValue(row['hops']) ?? Math.max(pathAddresses.length - 1, 0),\n path: pathAddresses,\n pathNodes,\n })\n }\n }\n }\n\n const reverseLeads: ReverseLead[] = []\n if (options.includeDepositTraceback !== false && uniqueDepositAddresses.length > 0) {\n const reverseBatch = await callGraphBatch(remoteClient, options.network, [reverseLeadsQuery(uniqueDepositAddresses)])\n for (const row of resultsFor(reverseBatch, 'reverse_1hop')) {\n const address = typeof row['address'] === 'string' ? row['address'] : ''\n const depositAddress = typeof row['deposit_address'] === 'string' ? row['deposit_address'] : ''\n if (!address || !depositAddress) continue\n const labels = stringArrayValue(row['display_labels']) ?? stringArrayValue(row['labels']) ?? []\n const degreeIn = numberValue(row['degree_in']) ?? 0\n const degreeOut = numberValue(row['degree_out']) ?? 0\n const totalVolume = numberValue(row['total_volume_usd']) ?? 0\n const reason = labels.length > 0 ? 'labeled_entity' : degreeIn > 50 ? 'fan_in_hub' : degreeOut > 50 ? 'fan_out_hub' : totalVolume > 100000 ? 'high_volume_sender' : ''\n if (!reason) continue\n reverseLeads.push({\n address,\n labels,\n node: {\n address,\n labels,\n system_labels: stringArrayValue(row['system_labels']),\n address_type: typeof row['address_type'] === 'string' ? row['address_type'] : undefined,\n address_subtypes: stringArrayValue(row['address_subtypes']),\n },\n degree_in: degreeIn,\n degree_out: degreeOut,\n total_volume_usd: totalVolume,\n deposit_address: depositAddress,\n amount_usd: numberValue(row['amount_usd']),\n reason,\n })\n }\n }\n\n return { flows, deposits, sourceMatches, reverseLeads }\n}\n\nfunction buildAliases(seedAddress: string, deposits: TraceDeposit[], sourceMatches: SourceMatch[], reverseLeads: ReverseLead[]): AliasTracker {\n const aliases = new AliasTracker()\n aliases.assign(seedAddress, 'V')\n for (const deposit of deposits) {\n for (const address of deposit.path.slice(1, -2)) aliases.assign(address, 'I')\n aliases.assign(deposit.address, 'D')\n aliases.assign(deposit.exchangeAddress, 'E')\n }\n for (const source of sourceMatches) {\n aliases.assign(source.source_exchange, 'X')\n for (const address of source.path.slice(1, -1)) aliases.assign(address, 'I')\n }\n for (const lead of reverseLeads) aliases.assign(lead.address, 'L')\n return aliases\n}\n\nfunction buildGraph(seedAddress: string, network: string, flows: TraceFlow[], deposits: TraceDeposit[], sourceMatches: SourceMatch[], reverseLeads: ReverseLead[]): Record<string, unknown> {\n type NodeAccumulator = {\n in: number\n out: number\n labels: string[]\n systemLabels: string[]\n addressType?: string\n addressSubtypes: string[]\n roles: Set<string>\n }\n\n const totals = new Map<string, NodeAccumulator>()\n const ensure = (address: string) => {\n if (!totals.has(address)) {\n totals.set(address, {\n in: 0,\n out: 0,\n labels: [],\n systemLabels: [],\n addressSubtypes: [],\n roles: new Set(address === seedAddress ? ['seed'] : []),\n })\n }\n return totals.get(address)!\n }\n const mergeNode = (address: string, metadata?: GraphNodeMetadata, role?: string, systemLabelsFallback?: string[]) => {\n const node = ensure(address)\n node.labels = uniqueStrings([...node.labels, ...(metadata?.labels ?? [])])\n node.systemLabels = uniqueStrings([...node.systemLabels, ...(metadata?.system_labels ?? []), ...(systemLabelsFallback ?? [])])\n if (metadata?.address_type) node.addressType = metadata.address_type\n node.addressSubtypes = uniqueStrings([...node.addressSubtypes, ...(metadata?.address_subtypes ?? [])])\n if (role) node.roles.add(role)\n return node\n }\n\n for (const flow of flows) {\n const src = mergeNode(flow.src, flow.src_node, undefined, flow.src_labels)\n src.out += flow.amount_usd_sum ?? flow.amount_sum\n const dst = mergeNode(flow.dst, flow.dst_node, undefined, flow.dst_labels)\n dst.in += flow.amount_usd_sum ?? flow.amount_sum\n if (isExchangeFlow(flow)) dst.roles.add('exchange')\n }\n for (const deposit of deposits) {\n for (const node of deposit.pathNodes ?? []) mergeNode(node.address, node)\n mergeNode(deposit.address, deposit.pathNodes?.find((node) => node.address === deposit.address), 'deposit_candidate')\n mergeNode(deposit.exchangeAddress, deposit.exchangeNode, 'exchange', deposit.exchangeLabels)\n }\n for (const source of sourceMatches) {\n for (const node of source.pathNodes ?? []) mergeNode(node.address, node)\n mergeNode(source.source_exchange, source.sourceNode, 'exchange', source.source_labels)\n }\n for (const lead of reverseLeads) {\n mergeNode(lead.address, lead.node ?? { address: lead.address, labels: lead.labels }, 'lead')\n const deposit = ensure(lead.deposit_address)\n deposit.in += lead.amount_usd ?? 0\n }\n const sourceMatchEdges = sourceMatches.flatMap((source) => {\n const path = source.path.length >= 2 ? source.path : [source.deposit_address, source.source_exchange]\n const edges: Array<Record<string, unknown>> = []\n for (let index = path.length - 1; index > 0; index -= 1) {\n edges.push({\n source: path[index],\n target: path[index - 1],\n edge_type: 'flows_to',\n usd_amount: 0,\n amount_sum: 0,\n tx_count: 0,\n direction: 'traceback',\n })\n }\n return edges\n })\n\n return normalizeGraphPayload({\n schema: 'chain-insights.graph.v1',\n nodes: [...totals.entries()].map(([address, data]) => ({\n id: address,\n address,\n node_type: 'address',\n labels: uniqueStrings(data.labels),\n ...(data.systemLabels.length > 0 ? { system_labels: uniqueStrings(data.systemLabels) } : {}),\n ...(data.addressType ? { address_type: data.addressType } : {}),\n ...(data.addressSubtypes.length > 0 ? { address_subtypes: uniqueStrings(data.addressSubtypes) } : {}),\n ...(data.roles.size > 0 ? { roles: [...data.roles] } : {}),\n flow_in_usd: data.in,\n flow_out_usd: data.out,\n })),\n edges: [\n ...flows.map((flow) => ({\n source: flow.src,\n target: flow.dst,\n edge_type: 'flows_to',\n usd_amount: flow.amount_usd_sum ?? flow.amount_sum,\n amount_sum: flow.amount_sum,\n tx_count: flow.tx_count ?? 0,\n first_tx_id: flow.first_tx_id,\n last_tx_id: flow.last_tx_id,\n terminal_exchange: flow.terminal_exchange,\n })),\n ...sourceMatchEdges,\n ...reverseLeads.map((lead) => ({\n source: lead.address,\n target: lead.deposit_address,\n edge_type: 'flows_to',\n usd_amount: lead.amount_usd ?? 0,\n amount_sum: lead.amount_usd ?? 0,\n tx_count: 0,\n direction: 'reverse_1hop_lead',\n })),\n ],\n flows,\n deposits,\n source_matches: sourceMatches,\n reverse_leads: reverseLeads,\n edge_anchors: [],\n metadata: {\n seed_address: seedAddress,\n network,\n generated_at: new Date().toISOString(),\n },\n })\n}\n\nfunction buildMarkdownReport(seedAddress: string, network: string, flows: TraceFlow[], deposits: TraceDeposit[], sourceMatches: SourceMatch[], reverseLeads: ReverseLead[], aliases: AliasTracker, graphPath: string, schemaPath: string): string {\n const lines = [\n `# Trace Funds: ${seedAddress}`,\n '',\n `Network: \\`${network}\\``,\n `Schema: \\`${schemaPath}\\``,\n `Graph: \\`${graphPath}\\``,\n '',\n '## Probe Summary',\n '',\n `- Exchange endpoint(s): ${[...new Set(deposits.map((deposit) => aliases.alias(deposit.exchangeAddress) ?? deposit.exchangeAddress))].join(', ') || 'none'}`,\n `- Deposit candidate(s): ${[...new Set(deposits.map((deposit) => aliases.alias(deposit.address) ?? deposit.address))].join(', ') || 'none'}`,\n `- Traceback source exchange path(s): ${sourceMatches.length}`,\n `- Reverse 1-hop lead(s): ${reverseLeads.length}`,\n '',\n '## Flow Table',\n '',\n '| Hop | Source | Destination | amount_sum | amount_usd_sum | tx_count | first_tx_id | terminal_exchange |',\n '|---:|---|---|---:|---:|---:|---|---|',\n ...flows.map((flow) => [\n `| ${flow.hop}`,\n `\\`${flow.src}\\``,\n `\\`${flow.dst}\\``,\n flow.amount_sum,\n flow.amount_usd_sum ?? '',\n flow.tx_count ?? '',\n flow.first_tx_id ? `\\`${flow.first_tx_id}\\`` : '',\n flow.terminal_exchange ? 'yes' : 'no',\n ].join(' | ') + ' |'),\n '',\n '## Mermaid',\n '',\n '```mermaid',\n 'flowchart LR',\n ...flows.map((flow, index) =>\n ` n${index}[\"${flow.src.slice(0, 8)}...\"] -->|\"amount_sum ${flow.amount_sum}${flow.terminal_exchange ? '; exchange endpoint' : ''}\"| m${index}[\"${flow.dst.slice(0, 8)}...\"]`\n ),\n '```',\n ]\n return lines.join('\\n') + '\\n'\n}\n\nfunction probeEvidence(seedAddress: string, network: string, schemaPath: string, aliases: AliasTracker, flows: TraceFlow[], deposits: TraceDeposit[], sourceMatches: SourceMatch[], reverseLeads: ReverseLead[], evidenceSource = 'track_funds'): Record<string, unknown> {\n return {\n schema: 'chain-insights.probe_evidence.v1',\n source: evidenceSource,\n network,\n seed_address: seedAddress,\n schema_ref: schemaPath,\n address_map: aliases.addressMap(),\n fund_flows: [\n ...deposits.map((deposit, index) => ({\n id: `F${index + 1}`,\n type: 'deposit',\n path: deposit.path.map((address) => aliases.alias(address) ?? address),\n deposit: aliases.alias(deposit.address),\n exchange: aliases.alias(deposit.exchangeAddress),\n amount_sum: deposit.amount_sum,\n amount_usd_sum: deposit.amount_usd_sum,\n hops: deposit.hops,\n })),\n ...sourceMatches.map((source, index) => ({\n id: `S${index + 1}`,\n type: 'source',\n path: [...source.path].reverse().map((address) => aliases.alias(address) ?? address),\n source_exchange: aliases.alias(source.source_exchange),\n deposit: aliases.alias(source.deposit_address),\n hops: source.hops,\n })),\n ],\n reverse_leads: reverseLeads.map((lead) => ({\n alias: aliases.alias(lead.address),\n address: lead.address,\n reason: lead.reason,\n labels: lead.labels,\n deposit: aliases.alias(lead.deposit_address),\n amount_usd: lead.amount_usd,\n })),\n outgoing_flows: flows.map((flow) => ({\n hop: flow.hop,\n src: aliases.alias(flow.src) ?? flow.src,\n dst: aliases.alias(flow.dst) ?? flow.dst,\n amount_sum: flow.amount_sum,\n amount_usd_sum: flow.amount_usd_sum,\n tx_count: flow.tx_count,\n first_tx_id: flow.first_tx_id,\n last_tx_id: flow.last_tx_id,\n terminal_exchange: flow.terminal_exchange,\n })),\n }\n}\n\nfunction tableCsv(flows: TraceFlow[]): string {\n const rows = ['hop,src,dst,amount_sum,amount_usd_sum,tx_count,first_tx_id,last_tx_id,terminal_exchange']\n for (const flow of flows) {\n rows.push([\n flow.hop,\n flow.src,\n flow.dst,\n flow.amount_sum,\n flow.amount_usd_sum ?? '',\n flow.tx_count ?? '',\n flow.first_tx_id ?? '',\n flow.last_tx_id ?? '',\n flow.terminal_exchange ? 'true' : 'false',\n ].map((value) => JSON.stringify(String(value))).join(','))\n }\n return rows.join('\\n') + '\\n'\n}\n\nfunction htmlEscape(value: unknown): string {\n return String(value ?? '')\n .replaceAll('&', '&amp;')\n .replaceAll('<', '&lt;')\n .replaceAll('>', '&gt;')\n .replaceAll('\"', '&quot;')\n .replaceAll(\"'\", '&#39;')\n}\n\nfunction buildTableHtml(seedAddress: string, network: string, flows: TraceFlow[], deposits: TraceDeposit[], sourceMatches: SourceMatch[], reverseLeads: ReverseLead[]): string {\n const headers = [\n 'hop',\n 'src',\n 'dst',\n 'amount_sum',\n 'amount_usd_sum',\n 'tx_count',\n 'first_tx_id',\n 'last_tx_id',\n 'terminal_exchange_display',\n ] as const\n const headerLabels: Record<typeof headers[number], string> = {\n hop: 'Hop',\n src: 'Source',\n dst: 'Destination',\n amount_sum: 'amount_sum',\n amount_usd_sum: 'amount_usd_sum',\n tx_count: 'tx_count',\n first_tx_id: 'first_tx_id',\n last_tx_id: 'last_tx_id',\n terminal_exchange_display: 'terminal_exchange',\n }\n const rows = flows.map((flow) => {\n const values: Record<string, unknown> = {\n ...flow,\n terminal_exchange_display: flow.terminal_exchange ? 'yes' : 'no',\n }\n return `<tr>${headers.map((header) => `<td>${htmlEscape(values[header])}</td>`).join('')}</tr>`\n }).join('\\n')\n\n return `<!doctype html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<title>Trace Funds Table - ${htmlEscape(seedAddress)}</title>\n<style>\n :root { color-scheme: dark; font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif; background: #0b0d12; color: #f4f2ea; }\n body { margin: 0; background: #0b0d12; color: #f4f2ea; }\n main { padding: 24px; }\n h1 { font-size: 20px; margin: 0 0 8px; font-weight: 650; }\n .meta { display: grid; gap: 6px; margin: 0 0 20px; color: rgba(244,242,234,.72); font-size: 13px; }\n .summary { display: flex; flex-wrap: wrap; gap: 8px; margin: 0 0 20px; }\n .pill { border: 1px solid rgba(242,221,166,.25); background: rgba(242,221,166,.08); border-radius: 999px; padding: 6px 10px; font-size: 12px; color: #f2dda6; }\n .table-wrap { overflow: auto; border: 1px solid rgba(255,255,255,.1); border-radius: 8px; background: #10131b; }\n table { border-collapse: collapse; width: 100%; min-width: 1180px; font-size: 12px; }\n th, td { border-bottom: 1px solid rgba(255,255,255,.08); padding: 8px 10px; text-align: left; vertical-align: top; }\n th { position: sticky; top: 0; background: #161a24; color: #f2dda6; font-weight: 600; z-index: 1; }\n td { color: rgba(244,242,234,.86); font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }\n tr:hover td { background: rgba(242,221,166,.045); }\n</style>\n</head>\n<body>\n<main>\n <h1>Trace Funds Table</h1>\n <div class=\"meta\">\n <div>Network: <strong>${htmlEscape(network)}</strong></div>\n <div>Seed: <strong>${htmlEscape(seedAddress)}</strong></div>\n <div>Generated: <strong>${htmlEscape(new Date().toISOString())}</strong></div>\n </div>\n <div class=\"summary\">\n <span class=\"pill\">${flows.length} FLOWS_TO edges</span>\n <span class=\"pill\">${deposits.length} deposit candidates</span>\n <span class=\"pill\">${sourceMatches.length} traceback source paths</span>\n <span class=\"pill\">${reverseLeads.length} reverse 1-hop leads</span>\n </div>\n <div class=\"table-wrap\">\n <table>\n <thead><tr>${headers.map((header) => `<th>${htmlEscape(headerLabels[header])}</th>`).join('')}</tr></thead>\n <tbody>\n${rows}\n </tbody>\n </table>\n </div>\n</main>\n</body>\n</html>\n`\n}\n\nfunction summarize(seedAddress: string, network: string, flows: TraceFlow[], sourceMatches: SourceMatch[], reverseLeads: ReverseLead[], aliases: AliasTracker, files: TraceFundsResult['files'], continuation: TraceFundsResult['continuation']): string {\n const totalAmount = flows.reduce((sum, flow) => sum + flow.amount_sum, 0)\n const byHop = new Map<number, number>()\n for (const flow of flows) byHop.set(flow.hop, (byHop.get(flow.hop) ?? 0) + 1)\n const depositCount = continuation.depositAddresses.length\n const exchangeCount = continuation.exchangeAddresses.length\n return [\n `Trace complete for ${network}:${seedAddress}`,\n '',\n `Facts: ${flows.length} FLOWS_TO edge(s), sum of traced edge amount_sum values ${Number(totalAmount.toFixed(8))}.`,\n `By hop: ${[...byHop.entries()].map(([hop, count]) => `hop ${hop}: ${count}`).join(', ') || 'none'}.`,\n `Exchange endpoints reached: ${exchangeCount}. Deposit candidate address(es): ${depositCount}.`,\n `Traceback source path(s): ${sourceMatches.length}. Reverse 1-hop lead(s): ${reverseLeads.length}.`,\n '',\n 'Files written:',\n `- schema: ${files.schema}`,\n `- compact evidence JSON: ${files.compactEvidence}`,\n `- graph JSON: ${files.graph}`,\n `- graph HTML: ${files.graphHtml}`,\n `- table CSV: ${files.table}`,\n `- table HTML: ${files.tableHtml}`,\n `- report: ${files.report}`,\n '',\n `Continuation hint: ${continuation.hint}`,\n continuation.depositAddresses.length > 0\n ? `Deposit candidates: ${continuation.depositAddresses.map((address) => aliases.alias(address) ?? address).join(', ')}`\n : 'Deposit candidates: none reached in this bounded trace.',\n continuation.nextHopAddresses.length > 0\n ? `Next addresses: ${continuation.nextHopAddresses.join(', ')}`\n : 'Next addresses: none found in this trace.',\n ].join('\\n')\n}\n\nexport async function runFundFlowProbe(\n remoteClient: Client,\n _config: Pick<InvestigatorConfig, 'dataDir' | 'serverPort'>,\n options: TraceFundsOptions,\n): Promise<TraceFundsResult> {\n const seedAddress = options.seedAddress.trim()\n const network = options.network.trim()\n if (!seedAddress) throw new Error('seed_address is required')\n if (!network) throw new Error('network is required')\n\n const maxHops = clampInt(options.maxHops, 3, 1, 5)\n const perAddressLimit = clampInt(options.perAddressLimit, 5, 1, 10)\n const minAmountSum = Math.max(0, options.minAmountSum ?? 0)\n const evidenceSource = options.evidenceSource ?? 'track_funds'\n const paths = workspaceOutputPaths()\n await ensureDirs(paths)\n\n const schemaResult = await loadOrCaptureTopologySchema(remoteClient, paths, network)\n const { flows, deposits, sourceMatches, reverseLeads } = await collectProbeTrace(remoteClient, { seedAddress, network, maxHops, perAddressLimit, minAmountSum, includeDepositTraceback: options.includeDepositTraceback })\n const aliases = buildAliases(seedAddress, deposits, sourceMatches, reverseLeads)\n const slug = `${new Date().toISOString().replace(/[-:]/g, '').replace(/\\.\\d{3}Z$/, 'Z')}_${sanitizeSegment(seedAddress.slice(0, 16))}`\n const compact = probeEvidence(seedAddress, network, schemaResult.filePath, aliases, flows, deposits, sourceMatches, reverseLeads, evidenceSource)\n const graph = buildGraph(seedAddress, network, flows, deposits, sourceMatches, reverseLeads)\n\n const compactPath = path.join(paths.reportTablesRoot, `${slug}.compact-evidence.json`)\n const graphPath = path.join(paths.reportGraphsRoot, `${slug}.graph.json`)\n const graphHtmlPath = path.join(paths.reportsRoot, `${slug}.graph.html`)\n const tablePath = path.join(paths.reportTablesRoot, `${slug}.flows.csv`)\n const tableHtmlPath = path.join(paths.reportsRoot, `${slug}.table.html`)\n const reportPath = path.join(paths.reportsRoot, `${slug}.trace-report.md`)\n const { generateInlineGraphHtml } = await import('../viz/html-generator.js')\n\n await writeFile(compactPath, JSON.stringify(compact, null, 2) + '\\n', { mode: 0o600 })\n await writeFile(graphPath, JSON.stringify(graph, null, 2) + '\\n', { mode: 0o600 })\n await writeFile(graphHtmlPath, generateInlineGraphHtml(graph), { mode: 0o600 })\n await writeFile(tablePath, tableCsv(flows), { mode: 0o600 })\n await writeFile(tableHtmlPath, buildTableHtml(seedAddress, network, flows, deposits, sourceMatches, reverseLeads), { mode: 0o600 })\n await writeFile(reportPath, buildMarkdownReport(seedAddress, network, flows, deposits, sourceMatches, reverseLeads, aliases, graphPath, schemaResult.filePath), { mode: 0o600 })\n\n if (options.caseId) {\n const { EvidenceStore } = await import('../cases/index.js')\n await EvidenceStore.append(options.caseId, {\n source: evidenceSource,\n queryParams: `network=${network} seed_address=${seedAddress} max_hops=${maxHops} per_address_limit=${perAddressLimit} min_amount_sum=${minAmountSum}`,\n content: JSON.stringify({\n schema: 'chain-insights.evidence_pointer.v1',\n source: evidenceSource,\n network,\n seed_address: seedAddress,\n address_map: aliases.compactAddressMap(),\n files: {\n compactEvidence: compactPath,\n graph: graphPath,\n graphHtml: graphHtmlPath,\n table: tablePath,\n tableHtml: tableHtmlPath,\n report: reportPath,\n },\n facts: {\n flow_count: flows.length,\n deposit_candidates: [...new Set(deposits.map((deposit) => aliases.alias(deposit.address) ?? deposit.address))],\n exchange_endpoints: [...new Set(deposits.map((deposit) => aliases.alias(deposit.exchangeAddress) ?? deposit.exchangeAddress))],\n traceback_source_paths: sourceMatches.length,\n reverse_leads: reverseLeads.length,\n },\n }, null, 2),\n })\n }\n\n const depositAddresses = [...new Set(deposits.map((deposit) => deposit.address))]\n const exchangeAddresses = [...new Set(deposits.map((deposit) => deposit.exchangeAddress))]\n const leaves: string[] = []\n const continuation = {\n nextHopAddresses: leaves.slice(0, 20),\n depositAddresses,\n exchangeAddresses,\n hint: depositAddresses.length > 0\n ? `Found ${depositAddresses.length} deposit candidate(s), defined as the address one hop before an exchange endpoint. Do not continue through exchange nodes.`\n : leaves.length > 0\n ? `No exchange endpoint reached yet. Continue from ${leaves.length} non-exchange leaf destination(s) with the same tool, or raise the result budget if the current trace stopped early.`\n : 'No exchange endpoint or non-exchange leaf destinations found; inspect graph/report files or lower min_amount_sum.',\n }\n const files = {\n schema: schemaResult.filePath,\n compactEvidence: compactPath,\n graph: graphPath,\n graphHtml: graphHtmlPath,\n table: tablePath,\n tableHtml: tableHtmlPath,\n report: reportPath,\n }\n\n return {\n summaryText: summarize(seedAddress, network, flows, sourceMatches, reverseLeads, aliases, files, continuation),\n compactEvidence: compact,\n graphData: graph,\n files,\n continuation,\n addressMap: aliases.compactAddressMap(),\n }\n}\n","import type { Client } from '@modelcontextprotocol/sdk/client/index.js'\nimport type { ContentBlock } from '@modelcontextprotocol/sdk/types.js'\nimport { normalizeGraphPayload } from '../viz/graph-normalizer.js'\n\ntype RemoteToolResult = {\n content?: ContentBlock[]\n isError?: boolean\n}\n\ntype ParsedGraphBatch = {\n facts?: {\n queries?: Array<{\n id?: string\n ok?: boolean\n results?: Array<Record<string, unknown>>\n error?: string\n }>\n }\n}\n\ntype StakeSubjectRole = 'address' | 'coldkey' | 'hotkey'\ntype StakeTopologyGraph = 'live_topology' | 'archive_topology'\n\nexport interface StakeInsightsOptions {\n network: string\n address?: string\n coldkey?: string\n hotkey?: string\n netuid?: number\n startTimestampMs?: number\n endTimestampMs?: number\n startBlock?: number\n endBlock?: number\n depth?: number\n maxHops?: number\n}\n\nexport interface StakeInsightsResult {\n summaryText: string\n structuredContent: {\n schema: 'chain-insights.result.v1'\n tool: 'stake_insights'\n facts: Record<string, unknown>\n hint: string\n }\n graphData: Record<string, unknown>\n}\n\ntype QueryFailure = {\n id: string\n error: string\n}\n\ntype StakeRelationship = {\n coldkey: string\n hotkey: string\n netuid?: number\n amount?: number\n source_role?: string\n destination_role?: string\n stake_added_amount?: number\n stake_removed_amount?: number\n stake_moved_in_amount?: number\n stake_moved_out_amount?: number\n net_stake_change?: number\n stake_event_count?: number\n first_seen_timestamp?: number\n last_seen_timestamp?: number\n first_activity_timestamp?: number\n last_activity_timestamp?: number\n first_tx_id?: string\n last_tx_id?: string\n active_days?: number\n granularity?: string\n source_stake_rows?: number\n source_backend?: string\n topology_graph: StakeTopologyGraph\n}\n\nconst STAKE_INSIGHTS_QUERY_TIMEOUT_SECONDS = 120\nconst STAKE_INSIGHTS_REQUEST_TIMEOUT_MS = 5 * 60 * 1000\n\nfunction escapeCypherString(value: string): string {\n return value.replaceAll('\\\\', '\\\\\\\\').replaceAll('\"', '\\\\\"')\n}\n\nfunction textFromToolResult(result: RemoteToolResult): string {\n return (result.content ?? [])\n .filter((item): item is Extract<ContentBlock, { type: 'text' }> => item.type === 'text')\n .map((item) => item.text)\n .join('\\n')\n}\n\nfunction parseGraphBatchResult(result: RemoteToolResult): ParsedGraphBatch {\n const text = textFromToolResult(result).trim()\n if (!text) throw new Error('graph_query_batch returned no text content')\n const parsed = JSON.parse(text) as ParsedGraphBatch\n if (!parsed.facts?.queries) throw new Error('graph_query_batch response did not include facts.queries')\n return parsed\n}\n\nfunction stringValue(value: unknown): string | undefined {\n return typeof value === 'string' && value.trim() ? value.trim() : undefined\n}\n\nfunction numberValue(value: unknown): number | undefined {\n if (typeof value === 'number' && Number.isFinite(value)) return value\n if (typeof value === 'string' && value.trim()) {\n const parsed = Number(value)\n if (Number.isFinite(parsed)) return parsed\n }\n return undefined\n}\n\nfunction nonZeroNumber(value: unknown): number | undefined {\n const parsed = numberValue(value)\n return parsed !== undefined && parsed !== 0 ? parsed : undefined\n}\n\nfunction clampInt(value: number | undefined, fallback: number, min: number, max: number): number {\n if (!Number.isFinite(value)) return fallback\n return Math.max(min, Math.min(max, Math.trunc(value as number)))\n}\n\nfunction resolveSubject(options: StakeInsightsOptions): { role: StakeSubjectRole; address: string } {\n const candidates = [\n ['address', options.address] as const,\n ['coldkey', options.coldkey] as const,\n ['hotkey', options.hotkey] as const,\n ].filter((entry): entry is readonly [StakeSubjectRole, string] => !!entry[1]?.trim())\n\n if (candidates.length !== 1) {\n throw new Error('Provide exactly one of address, coldkey, or hotkey')\n }\n\n return { role: candidates[0][0], address: candidates[0][1].trim() }\n}\n\nfunction validateOptions(options: StakeInsightsOptions): {\n network: string\n subject: { role: StakeSubjectRole; address: string }\n depth: number\n} {\n const network = options.network.trim()\n if (!network) throw new Error('network is required')\n if (options.startBlock !== undefined || options.endBlock !== undefined) {\n throw new Error('Block windows are not available on the current stake graph surface; use start_timestamp_ms/end_timestamp_ms')\n }\n\n return {\n network,\n subject: resolveSubject(options),\n depth: clampInt(options.depth ?? options.maxHops, 1, 1, 3),\n }\n}\n\nfunction subjectPredicate(subject: { role: StakeSubjectRole; address: string }): string {\n const address = escapeCypherString(subject.address)\n if (subject.role === 'coldkey') return `coldkey.address = \"${address}\"`\n if (subject.role === 'hotkey') return `hotkey.address = \"${address}\"`\n return `(coldkey.address = \"${address}\" OR hotkey.address = \"${address}\")`\n}\n\nfunction stakeRelationshipQuery(\n topologyGraph: StakeTopologyGraph,\n subject: { role: StakeSubjectRole; address: string },\n options: StakeInsightsOptions,\n depth: number,\n): { id: string; query: string } {\n const predicates = [subjectPredicate(subject)]\n if (options.netuid !== undefined) predicates.push(`stake.netuid = ${Math.trunc(options.netuid)}`)\n if (options.startTimestampMs !== undefined) predicates.push(`stake.last_activity_timestamp >= ${Math.trunc(options.startTimestampMs)}`)\n if (options.endTimestampMs !== undefined) predicates.push(`stake.first_activity_timestamp <= ${Math.trunc(options.endTimestampMs)}`)\n const limit = Math.min(500, Math.max(50, depth * 100))\n\n return {\n id: topologyGraph === 'live_topology' ? 'live_stake_relationships' : 'archive_stake_relationships',\n query: [\n `USE ${topologyGraph}`,\n 'MATCH (coldkey:Address)-[stake:STAKES_IN]->(hotkey:Address)',\n `WHERE ${predicates.join(' AND ')}`,\n [\n 'RETURN coldkey.address AS coldkey',\n 'hotkey.address AS hotkey',\n 'stake.netuid AS netuid',\n 'stake.amount AS amount',\n 'stake.source_role AS source_role',\n 'stake.destination_role AS destination_role',\n 'stake.stake_added_amount AS stake_added_amount',\n 'stake.stake_removed_amount AS stake_removed_amount',\n 'stake.stake_moved_in_amount AS stake_moved_in_amount',\n 'stake.stake_moved_out_amount AS stake_moved_out_amount',\n 'stake.net_stake_change AS net_stake_change',\n 'stake.stake_event_count AS stake_event_count',\n 'stake.first_seen_timestamp AS first_seen_timestamp',\n 'stake.last_seen_timestamp AS last_seen_timestamp',\n 'stake.first_activity_timestamp AS first_activity_timestamp',\n 'stake.last_activity_timestamp AS last_activity_timestamp',\n 'stake.first_tx_id AS first_tx_id',\n 'stake.last_tx_id AS last_tx_id',\n 'stake.active_days AS active_days',\n 'stake.granularity AS granularity',\n 'stake.source_stake_rows AS source_stake_rows',\n 'stake.source_backend AS source_backend',\n `\"${topologyGraph}\" AS topology_graph`,\n ].join(', '),\n 'ORDER BY stake.amount DESC',\n `LIMIT ${limit}`,\n ].join(' '),\n }\n}\n\nasync function callGraphBatch(\n remoteClient: Client,\n network: string,\n queries: Array<{ id: string; query: string }>,\n): Promise<ParsedGraphBatch> {\n const result = await remoteClient.callTool(\n {\n name: 'graph_query_batch',\n arguments: {\n network,\n queries,\n per_query_timeout_seconds: STAKE_INSIGHTS_QUERY_TIMEOUT_SECONDS,\n },\n },\n undefined,\n {\n timeout: STAKE_INSIGHTS_REQUEST_TIMEOUT_MS,\n maxTotalTimeout: STAKE_INSIGHTS_REQUEST_TIMEOUT_MS,\n },\n ) as RemoteToolResult\n if (result.isError) throw new Error(textFromToolResult(result) || 'graph_query_batch failed')\n return parseGraphBatchResult(result)\n}\n\nfunction topologyGraphForQueryId(id: string): StakeTopologyGraph {\n return id.startsWith('archive_') ? 'archive_topology' : 'live_topology'\n}\n\nfunction collectRelationships(batch: ParsedGraphBatch): {\n live: StakeRelationship[]\n archive: StakeRelationship[]\n failures: QueryFailure[]\n evidence: Array<Record<string, unknown>>\n} {\n const failures: QueryFailure[] = []\n const evidence: Array<Record<string, unknown>> = []\n const live: StakeRelationship[] = []\n const archive: StakeRelationship[] = []\n\n for (const query of batch.facts?.queries ?? []) {\n const id = query.id ?? 'unknown'\n const topologyGraph = topologyGraphForQueryId(id)\n if (query.ok === false) {\n failures.push({ id, error: query.error || 'unknown error' })\n evidence.push({ id, topology_graph: topologyGraph, ok: false, row_count: 0, error: query.error || 'unknown error' })\n continue\n }\n\n const rows = (query.results ?? []).map((row) => normalizeRelationship(row, topologyGraph))\n if (topologyGraph === 'live_topology') live.push(...rows)\n else archive.push(...rows)\n evidence.push({\n id,\n topology_graph: topologyGraph,\n ok: true,\n row_count: rows.length,\n source_backends: [...new Set(rows.map((row) => row.source_backend).filter(Boolean))],\n })\n }\n\n return { live, archive, failures, evidence }\n}\n\nfunction normalizeRelationship(row: Record<string, unknown>, topologyGraph: StakeTopologyGraph): StakeRelationship {\n return {\n coldkey: String(row['coldkey'] ?? ''),\n hotkey: String(row['hotkey'] ?? ''),\n netuid: numberValue(row['netuid']),\n amount: numberValue(row['amount']),\n source_role: stringValue(row['source_role']),\n destination_role: stringValue(row['destination_role']),\n stake_added_amount: numberValue(row['stake_added_amount']),\n stake_removed_amount: numberValue(row['stake_removed_amount']),\n stake_moved_in_amount: numberValue(row['stake_moved_in_amount']),\n stake_moved_out_amount: numberValue(row['stake_moved_out_amount']),\n net_stake_change: numberValue(row['net_stake_change']),\n stake_event_count: numberValue(row['stake_event_count']),\n first_seen_timestamp: numberValue(row['first_seen_timestamp']),\n last_seen_timestamp: numberValue(row['last_seen_timestamp']),\n first_activity_timestamp: numberValue(row['first_activity_timestamp']),\n last_activity_timestamp: numberValue(row['last_activity_timestamp']),\n first_tx_id: stringValue(row['first_tx_id']),\n last_tx_id: stringValue(row['last_tx_id']),\n active_days: numberValue(row['active_days']),\n granularity: stringValue(row['granularity']),\n source_stake_rows: numberValue(row['source_stake_rows']),\n source_backend: stringValue(row['source_backend']) ?? (topologyGraph === 'live_topology' ? 'memgraph_live' : 'starrocks_archive'),\n topology_graph: topologyGraph,\n }\n}\n\nfunction firstTimestamp(rows: StakeRelationship[]): number | undefined {\n const timestamps = rows.map((row) => row.first_activity_timestamp).filter((value): value is number => value !== undefined)\n return timestamps.length > 0 ? Math.min(...timestamps) : undefined\n}\n\nfunction lastTimestamp(rows: StakeRelationship[]): number | undefined {\n const timestamps = rows.map((row) => row.last_activity_timestamp).filter((value): value is number => value !== undefined)\n return timestamps.length > 0 ? Math.max(...timestamps) : undefined\n}\n\nfunction sum(rows: StakeRelationship[], selector: (row: StakeRelationship) => number | undefined): number {\n return rows.reduce((total, row) => total + (selector(row) ?? 0), 0)\n}\n\nfunction stakeTotals(rows: StakeRelationship[]): Record<string, unknown> {\n const totalStaked = sum(rows, (row) => row.stake_added_amount)\n const totalUnstaked = sum(rows, (row) => row.stake_removed_amount)\n const totalMovedIn = sum(rows, (row) => row.stake_moved_in_amount)\n const totalMovedOut = sum(rows, (row) => row.stake_moved_out_amount)\n const netStaked = rows.some((row) => row.net_stake_change !== undefined)\n ? sum(rows, (row) => row.net_stake_change)\n : sum(rows, (row) => row.amount)\n\n return {\n amount_unit: 'tao',\n total_staked: totalStaked,\n total_unstaked: totalUnstaked,\n total_moved_in: totalMovedIn,\n total_moved_out: totalMovedOut,\n net_staked: netStaked,\n relationship_count: rows.length,\n first_activity_timestamp: firstTimestamp(rows),\n last_activity_timestamp: lastTimestamp(rows),\n }\n}\n\nfunction movementRows(rows: StakeRelationship[]): Array<Record<string, unknown>> {\n const movements: Array<Record<string, unknown>> = []\n for (const row of rows) {\n const base = {\n coldkey: row.coldkey,\n hotkey: row.hotkey,\n netuid: row.netuid,\n source_backend: row.source_backend,\n first_activity_timestamp: row.first_activity_timestamp,\n last_activity_timestamp: row.last_activity_timestamp,\n }\n const added = nonZeroNumber(row.stake_added_amount)\n if (added !== undefined) movements.push({ ...base, movement_type: 'stake_added', direction: 'coldkey_to_hotkey', amount: added })\n const removed = nonZeroNumber(row.stake_removed_amount)\n if (removed !== undefined) movements.push({ ...base, movement_type: 'stake_removed', direction: 'hotkey_to_coldkey', amount: removed })\n const movedIn = nonZeroNumber(row.stake_moved_in_amount)\n if (movedIn !== undefined) movements.push({ ...base, movement_type: 'stake_moved_in', direction: 'counterparty_to_relationship', amount: movedIn })\n const movedOut = nonZeroNumber(row.stake_moved_out_amount)\n if (movedOut !== undefined) movements.push({ ...base, movement_type: 'stake_moved_out', direction: 'relationship_to_counterparty', amount: movedOut })\n }\n return movements\n}\n\nfunction topCounterparties(\n subject: { role: StakeSubjectRole; address: string },\n rows: StakeRelationship[],\n): Array<Record<string, unknown>> {\n const byAddress = new Map<string, { address: string; role: 'coldkey' | 'hotkey'; amount: number; relationship_count: number; stake_event_count: number }>()\n for (const row of rows) {\n const counterparties: Array<{ address: string; role: 'coldkey' | 'hotkey' }> = []\n if (subject.role === 'coldkey') counterparties.push({ address: row.hotkey, role: 'hotkey' })\n else if (subject.role === 'hotkey') counterparties.push({ address: row.coldkey, role: 'coldkey' })\n else {\n if (row.coldkey === subject.address) counterparties.push({ address: row.hotkey, role: 'hotkey' })\n if (row.hotkey === subject.address) counterparties.push({ address: row.coldkey, role: 'coldkey' })\n }\n\n for (const counterparty of counterparties.filter((entry) => entry.address)) {\n const current = byAddress.get(counterparty.address) ?? {\n address: counterparty.address,\n role: counterparty.role,\n amount: 0,\n relationship_count: 0,\n stake_event_count: 0,\n }\n current.amount += row.amount ?? row.net_stake_change ?? 0\n current.relationship_count += 1\n current.stake_event_count += row.stake_event_count ?? 0\n byAddress.set(counterparty.address, current)\n }\n }\n\n return [...byAddress.values()]\n .sort((left, right) => Math.abs(right.amount) - Math.abs(left.amount))\n .slice(0, 10)\n}\n\nfunction graphData(rows: StakeRelationship[], subject: { address: string; role: StakeSubjectRole }, network: string): Record<string, unknown> {\n const nodes = new Map<string, Record<string, unknown>>()\n const ensureNode = (address: string, role: string) => {\n const existing = nodes.get(address) ?? { id: address, address, node_type: 'address', labels: [], roles: [] }\n const roles = Array.isArray(existing['roles']) ? existing['roles'].map(String) : []\n nodes.set(address, { ...existing, roles: [...new Set([...roles, role])] })\n }\n\n ensureNode(subject.address, 'subject')\n const edges = rows.map((row) => {\n ensureNode(row.coldkey, 'coldkey')\n ensureNode(row.hotkey, 'hotkey')\n return {\n source: row.coldkey,\n target: row.hotkey,\n edge_type: 'stakes_in',\n amount: row.amount ?? row.net_stake_change ?? 0,\n netuid: row.netuid,\n source_backend: row.source_backend,\n topology_graph: row.topology_graph,\n first_activity_timestamp: row.first_activity_timestamp,\n last_activity_timestamp: row.last_activity_timestamp,\n }\n })\n\n return normalizeGraphPayload({\n schema: 'chain-insights.graph.v1',\n nodes: [...nodes.values()],\n edges,\n flows: [],\n edge_anchors: [],\n metadata: {\n network,\n subject_address: subject.address,\n subject_role: subject.role,\n generated_at: new Date().toISOString(),\n },\n })\n}\n\nfunction summaryLines(\n network: string,\n subject: { role: StakeSubjectRole; address: string },\n rows: StakeRelationship[],\n totals: Record<string, unknown>,\n failures: QueryFailure[],\n): string {\n const lines = [\n `Stake insights for ${network}:${subject.address}`,\n '',\n `Subject role: ${subject.role}`,\n `Relationships: ${rows.length}`,\n `Net staked: ${totals['net_staked'] ?? 0} TAO`,\n `Total staked: ${totals['total_staked'] ?? 0} TAO`,\n `Total unstaked: ${totals['total_unstaked'] ?? 0} TAO`,\n `First activity: ${totals['first_activity_timestamp'] ?? 'unknown'}`,\n `Last activity: ${totals['last_activity_timestamp'] ?? 'unknown'}`,\n ]\n\n if (rows.length > 0) {\n lines.push('', 'Top staking relationships')\n for (const row of rows.slice(0, 10)) {\n lines.push(`- ${row.coldkey} -> ${row.hotkey} netuid ${row.netuid ?? 'unknown'} amount ${row.amount ?? row.net_stake_change ?? 'unknown'} (${row.source_backend})`)\n }\n } else {\n lines.push('', 'No stake relationships matched the requested filters.')\n }\n\n if (failures.length > 0) {\n lines.push('', 'Partial query failures', failures.map((failure) => `- ${failure.id}: ${failure.error}`).join('\\n'))\n }\n\n return lines.join('\\n')\n}\n\nexport async function stakeInsights(\n remoteClient: Client,\n options: StakeInsightsOptions,\n): Promise<StakeInsightsResult> {\n const { network, subject, depth } = validateOptions(options)\n const batch = await callGraphBatch(remoteClient, network, [\n stakeRelationshipQuery('live_topology', subject, options, depth),\n stakeRelationshipQuery('archive_topology', subject, options, depth),\n ])\n const { live, archive, failures, evidence } = collectRelationships(batch)\n\n if (live.length === 0 && archive.length === 0 && failures.length > 0) {\n throw new Error(`Stake insights unavailable: ${failures.map((failure) => `${failure.id}: ${failure.error}`).join('; ')}`)\n }\n\n const rows = live.length > 0 ? live : archive\n const totals = stakeTotals(rows)\n const facts = {\n subject: {\n network,\n address: subject.address,\n role: subject.role,\n netuid: options.netuid,\n start_timestamp_ms: options.startTimestampMs,\n end_timestamp_ms: options.endTimestampMs,\n depth,\n },\n backend_used: [...new Set(rows.map((row) => row.source_backend).filter(Boolean))],\n primary_topology_graph: live.length > 0 ? 'live_topology' : 'archive_topology',\n stake_totals: totals,\n active_relationships: rows,\n stake_movements: movementRows(rows),\n top_counterparties: topCounterparties(subject, rows),\n query_evidence: evidence,\n partial_query_errors: failures.length > 0 ? failures : undefined,\n }\n\n return {\n summaryText: summaryLines(network, subject, rows, totals, failures),\n structuredContent: {\n schema: 'chain-insights.result.v1',\n tool: 'stake_insights',\n facts,\n hint: rows.length > 0\n ? 'Review active_relationships and stake_movements before treating stake behavior as generic money flow.'\n : 'No matching stake relationships were found; confirm the address role, netuid, and time window.',\n },\n graphData: graphData(rows, subject, network),\n }\n}\n","import { createHash } from 'node:crypto'\nimport { mkdir, writeFile } from 'node:fs/promises'\nimport path from 'node:path'\nimport type { Client } from '@modelcontextprotocol/sdk/client/index.js'\nimport type { ContentBlock } from '@modelcontextprotocol/sdk/types.js'\nimport type { InvestigatorConfig } from '../config/schema.js'\nimport { runFundFlowProbe, type TraceFundsResult } from './trace-funds.js'\nimport { normalizeGraphPayload } from '../viz/graph-normalizer.js'\nimport { workspaceOutputPaths } from '../workspace/output-root.js'\n\nexport { scamTopology, type ScamTopologyOptions, type ScamTopologyResult } from './scam-topology.js'\nexport { stakeInsights, type StakeInsightsOptions, type StakeInsightsResult } from './stake-insights.js'\n\ntype RemoteToolResult = {\n content?: ContentBlock[]\n isError?: boolean\n}\n\ninterface ParsedGraphBatch {\n facts?: {\n queries?: Array<{\n id?: string\n ok?: boolean\n results?: Array<Record<string, unknown>>\n error?: string\n }>\n }\n}\n\ntype QueryFailure = {\n id: string\n error: string\n}\n\nconst GRAPH_QUERY_BATCH_TIMEOUT_SECONDS = 120\nconst GRAPH_QUERY_BATCH_REQUEST_TIMEOUT_MS = 5 * 60 * 1000\n\nexport interface AddressRiskOptions {\n address: string\n network: string\n compareAddress?: string\n}\n\nexport interface TrackFundsOptions {\n trustedAddresses: string | string[]\n untrustedAddresses?: string | string[]\n network: string\n caseId?: string\n maxHops?: number\n perAddressLimit?: number\n minAmountSum?: number\n}\n\nfunction escapeCypherString(value: string): string {\n return value.replaceAll('\\\\', '\\\\\\\\').replaceAll('\"', '\\\\\"')\n}\n\nfunction textFromToolResult(result: RemoteToolResult): string {\n return (result.content ?? [])\n .filter((item): item is Extract<ContentBlock, { type: 'text' }> => item.type === 'text')\n .map((item) => item.text)\n .join('\\n')\n}\n\nfunction parseGraphBatchResult(result: RemoteToolResult): ParsedGraphBatch {\n const text = textFromToolResult(result).trim()\n if (!text) throw new Error('graph_query_batch returned no text content')\n const parsed = JSON.parse(text) as ParsedGraphBatch\n if (!parsed.facts?.queries) throw new Error('graph_query_batch response did not include facts.queries')\n return parsed\n}\n\nfunction topologyGraphQuery(query: string): string {\n const trimmed = query.trim()\n if (/^USE\\s+/i.test(trimmed)) return trimmed\n return `USE live_topology ${trimmed}`\n}\n\nfunction collectQueryFailure(failures: QueryFailure[], id: string, error: string | undefined): void {\n failures.push({ id, error: error || 'unknown error' })\n}\n\nfunction optionalResultsFor(batch: ParsedGraphBatch, id: string, failures: QueryFailure[]): Array<Record<string, unknown>> {\n const query = batch.facts?.queries?.find((entry) => entry.id === id)\n if (!query) return []\n if (query.ok === false) {\n collectQueryFailure(failures, id, query.error)\n return []\n }\n return query.results ?? []\n}\n\nfunction optionalResultsWithPrefix(batch: ParsedGraphBatch, prefix: string, failures: QueryFailure[]): Array<Record<string, unknown>> {\n return (batch.facts?.queries ?? [])\n .filter((entry) => entry.id?.startsWith(prefix))\n .flatMap((entry) => {\n if (entry.ok === false) {\n collectQueryFailure(failures, entry.id ?? prefix, entry.error)\n return []\n }\n return entry.results ?? []\n })\n}\n\nasync function callGraphBatch(\n remoteClient: Client,\n network: string,\n queries: Array<{ id: string; query: string }>,\n): Promise<ParsedGraphBatch> {\n const result = await remoteClient.callTool(\n {\n name: 'graph_query_batch',\n arguments: {\n network,\n queries: queries.map((query) => ({\n ...query,\n query: topologyGraphQuery(query.query),\n })),\n per_query_timeout_seconds: GRAPH_QUERY_BATCH_TIMEOUT_SECONDS,\n },\n },\n undefined,\n {\n timeout: GRAPH_QUERY_BATCH_REQUEST_TIMEOUT_MS,\n maxTotalTimeout: GRAPH_QUERY_BATCH_REQUEST_TIMEOUT_MS,\n },\n ) as RemoteToolResult\n if (result.isError) throw new Error(textFromToolResult(result) || 'graph_query_batch failed')\n return parseGraphBatchResult(result)\n}\n\nfunction parseAddressList(value: string | string[] | undefined): string[] {\n const raw = Array.isArray(value) ? value.join(',') : value ?? ''\n return raw\n .split(',')\n .map((entry) => entry.trim())\n .filter(Boolean)\n}\n\nfunction graphArray(graphData: Record<string, unknown>, key: string): Array<Record<string, unknown>> {\n const value = graphData[key]\n return Array.isArray(value) ? value.filter((item): item is Record<string, unknown> => typeof item === 'object' && item !== null && !Array.isArray(item)) : []\n}\n\nfunction addressProfileQuery(address: string): { id: string; query: string } {\n return {\n id: 'address_profile',\n query: [\n `MATCH (a:Address {address: \"${escapeCypherString(address)}\"})`,\n 'RETURN a.address AS address, a.labels AS display_labels, a.labels AS system_labels, a.address_type AS address_type, a.address_subtypes AS address_subtypes, a.is_exchange AS is_exchange, a.confluence_score AS confluence_score, a.ml_risk_score AS ml_risk_score, a.ml_risk_level AS ml_risk_level, a.ml_top_drivers AS ml_top_drivers, a.ml_pattern_summary AS ml_pattern_summary, a.risk_score AS risk_score, a.risk_level AS risk_level, a.pattern_flags AS pattern_flags, a.ml_pagerank AS ml_pagerank, a.ml_betweenness AS ml_betweenness, a.ml_community_id AS ml_community_id',\n 'LIMIT 1',\n ].join(' '),\n }\n}\n\nfunction addressFeatureQuery(address: string): { id: string; query: string } {\n return {\n id: 'address_feature',\n query: [\n 'USE facts',\n `MATCH (a:Address {address: \"${escapeCypherString(address)}\"})-[:HAS_FEATURE]->(feature:AddressFeature)`,\n 'RETURN feature.degree_in AS degree_in, feature.degree_out AS degree_out, feature.degree_total AS degree_total, feature.tx_in_count AS tx_in_count, feature.tx_out_count AS tx_out_count, feature.tx_total_count AS tx_total_count, feature.total_volume_usd AS total_volume_usd, feature.total_in_usd AS total_in_usd, feature.total_out_usd AS total_out_usd, feature.net_flow_usd AS net_flow_usd, feature.first_activity_timestamp AS first_activity_timestamp, feature.last_activity_timestamp AS last_activity_timestamp, feature.activity_span_days AS activity_span_days, feature.active_days AS active_days',\n 'LIMIT 1',\n ].join(' '),\n }\n}\n\nfunction addressRiskScoreQuery(address: string): { id: string; query: string } {\n return {\n id: 'address_risk_score',\n query: [\n 'USE facts',\n `MATCH (a:Address {address: \"${escapeCypherString(address)}\"})-[:HAS_RISK_SCORE]->(risk:RiskScore)`,\n 'RETURN risk.risk_score AS risk_score, risk.window_days AS risk_window_days, risk.processing_date AS risk_processing_date, risk.shap_top_features AS shap_top_features',\n 'LIMIT 1',\n ].join(' '),\n }\n}\n\nfunction flowEdgeMap(variableName: string): string {\n return `{amount_sum: ${variableName}.amount_sum, amount_usd_sum: ${variableName}.amount_usd_sum, tx_count: ${variableName}.tx_count, first_tx_id: ${variableName}.first_tx_id, last_tx_id: ${variableName}.last_tx_id}`\n}\n\nfunction pathNodeMap(variableName: string): string {\n return `{address: ${variableName}.address, labels: ${variableName}.labels, system_labels: ${variableName}.labels, address_type: ${variableName}.address_type, address_subtypes: ${variableName}.address_subtypes, is_exchange: ${variableName}.is_exchange}`\n}\n\nfunction exchangeOutflowQueries(address: string): Array<{ id: string; query: string }> {\n return Array.from({ length: 3 }, (_, index) => exchangeOutflowQueryAtDepth(address, index + 1))\n}\n\nfunction exchangeOutflowQueryAtDepth(address: string, depth: number): { id: string; query: string } {\n const intermediateVariables = Array.from({ length: Math.max(depth - 1, 0) }, (_, index) => `n${index + 1}`)\n const nodeVariables = ['a', ...intermediateVariables, 'exchange']\n const edgeVariables = Array.from({ length: depth }, (_, index) => `r${index + 1}`)\n const relationshipChain = edgeVariables.map((edgeVariable, index) => {\n const targetVariable = index === edgeVariables.length - 1 ? 'exchange' : intermediateVariables[index]!\n return `-[${edgeVariable}:FLOWS_TO]->(${targetVariable}:Address)`\n }).join('')\n const intermediatePredicates = intermediateVariables.map((nodeVariable) => `${nodeVariable}.is_exchange IS NULL`)\n const depositVariable = nodeVariables[nodeVariables.length - 2]!\n const terminalEdgeVariable = edgeVariables[edgeVariables.length - 1]!\n return {\n id: `exchange_outflows_${depth}`,\n query: [\n `MATCH (a:Address {address: \"${escapeCypherString(address)}\"})${relationshipChain}`,\n `WHERE a <> exchange AND exchange.is_exchange IS NOT NULL${intermediatePredicates.length > 0 ? ` AND ${intermediatePredicates.join(' AND ')}` : ''}`,\n `RETURN \"outflow\" AS direction, exchange.address AS exchange_address, exchange.labels AS exchange_display_labels, exchange.labels AS exchange_system_labels, exchange.address_type AS exchange_address_type, exchange.address_subtypes AS exchange_address_subtypes, ${depositVariable}.address AS deposit_address, ${depth} AS hops, ${terminalEdgeVariable}.amount_sum AS amount_sum, ${terminalEdgeVariable}.amount_usd_sum AS amount_usd_sum, ${terminalEdgeVariable}.tx_count AS tx_count, [${nodeVariables.map((nodeVariable) => `${nodeVariable}.address`).join(', ')}] AS addresses, [${nodeVariables.map(pathNodeMap).join(', ')}] AS path_nodes, [${edgeVariables.map(flowEdgeMap).join(', ')}] AS edge_props`,\n 'ORDER BY hops ASC',\n 'LIMIT 200',\n ].join(' '),\n }\n}\n\nfunction exchangeInflowQueries(address: string): Array<{ id: string; query: string }> {\n return Array.from({ length: 3 }, (_, index) => exchangeInflowQueryAtDepth(address, index + 1))\n}\n\nfunction exchangeInflowQueryAtDepth(address: string, depth: number): { id: string; query: string } {\n const intermediateVariables = Array.from({ length: Math.max(depth - 1, 0) }, (_, index) => `n${index + 1}`)\n const nodeVariables = ['exchange', ...intermediateVariables, 'a']\n const edgeVariables = Array.from({ length: depth }, (_, index) => `r${index + 1}`)\n const relationshipChain = edgeVariables.map((edgeVariable, index) => {\n const targetVariable = index === edgeVariables.length - 1 ? 'a' : intermediateVariables[index]!\n return `-[${edgeVariable}:FLOWS_TO]->(${targetVariable}:Address)`\n }).join('')\n const intermediatePredicates = intermediateVariables.map((nodeVariable) => `${nodeVariable}.is_exchange IS NULL`)\n const withdrawalVariable = nodeVariables[1]!\n const terminalEdgeVariable = edgeVariables[edgeVariables.length - 1]!\n return {\n id: `exchange_inflows_${depth}`,\n query: [\n `MATCH (exchange:Address)${relationshipChain}`,\n `WHERE a.address = \"${escapeCypherString(address)}\" AND a <> exchange AND exchange.is_exchange IS NOT NULL${intermediatePredicates.length > 0 ? ` AND ${intermediatePredicates.join(' AND ')}` : ''}`,\n `RETURN \"inflow\" AS direction, exchange.address AS exchange_address, exchange.labels AS exchange_display_labels, exchange.labels AS exchange_system_labels, exchange.address_type AS exchange_address_type, exchange.address_subtypes AS exchange_address_subtypes, ${withdrawalVariable}.address AS withdrawal_address, ${depth} AS hops, ${terminalEdgeVariable}.amount_sum AS amount_sum, ${terminalEdgeVariable}.amount_usd_sum AS amount_usd_sum, ${terminalEdgeVariable}.tx_count AS tx_count, [${nodeVariables.map((nodeVariable) => `${nodeVariable}.address`).join(', ')}] AS addresses, [${nodeVariables.map(pathNodeMap).join(', ')}] AS path_nodes, [${edgeVariables.map(flowEdgeMap).join(', ')}] AS edge_props`,\n 'ORDER BY hops ASC',\n 'LIMIT 200',\n ].join(' '),\n }\n}\n\nfunction connectionProbeQuery(address: string, compareAddress: string): { id: string; query: string } {\n return {\n id: 'connection_probe',\n query: [\n `MATCH (a:Address {address: \"${escapeCypherString(address)}\"})-[r:FLOWS_TO]-(b:Address {address: \"${escapeCypherString(compareAddress)}\"})`,\n 'RETURN [a.address, b.address] AS addresses, 1 AS hops',\n 'LIMIT 5',\n ].join(' '),\n }\n}\n\nfunction formatExchangeRows(rows: Array<Record<string, unknown>>): string[] {\n return rows.map((row) => {\n const direction = String(row['direction'] ?? 'flow')\n const exchange = String(row['exchange_address'] ?? '')\n const amount = row['amount_sum'] ?? row['amount_usd_sum'] ?? ''\n const hops = row['hops'] ?? ''\n return `- ${direction}: ${exchange} (${hops} hop(s), amount ${amount})`\n })\n}\n\nfunction numberValue(value: unknown): number | undefined {\n if (typeof value === 'number' && Number.isFinite(value)) return value\n if (typeof value === 'string' && value.trim()) {\n const parsed = Number(value)\n return Number.isFinite(parsed) ? parsed : undefined\n }\n return undefined\n}\n\nfunction isExchangeFlag(value: unknown): boolean {\n if (value === true) return true\n if (value === false || value === null || value === undefined) return false\n if (typeof value === 'string') {\n const normalized = value.trim().toLowerCase()\n return normalized === 'true' || normalized === '1'\n }\n if (typeof value === 'number') return value === 1\n return false\n}\n\nfunction hasExactExchangeLabel(labels: string[] | undefined): boolean {\n return (labels ?? []).some((label) => label.trim().toLowerCase() === 'exchange')\n}\n\nfunction firstNumber(...values: unknown[]): number | undefined {\n for (const value of values) {\n const parsed = numberValue(value)\n if (parsed !== undefined) return parsed\n }\n return undefined\n}\n\nfunction firstString(...values: unknown[]): string | undefined {\n for (const value of values) {\n if (typeof value === 'string' && value.trim()) return value.trim()\n }\n return undefined\n}\n\nfunction riskLevelFromScore(score: number): string {\n if (score >= 0.85) return 'critical'\n if (score >= 0.7) return 'high'\n if (score >= 0.4) return 'medium'\n return 'low'\n}\n\nfunction riskRecommendation(level: string): string {\n if (level === 'critical' || level === 'high') return 'Escalate for manual review.'\n if (level === 'medium') return 'Review exchange exposure and counterparties before clearing.'\n return 'No stored risk signal found; continue with normal monitoring.'\n}\n\nfunction riskDrivers(profile: Record<string, unknown>, exchangeRows: Array<Record<string, unknown>>): string[] {\n const drivers: string[] = []\n const storedDrivers = stringArrayValue(profile['ml_top_drivers'])\n if (storedDrivers?.length) drivers.push(...storedDrivers)\n\n const patternFlags = stringArrayValue(profile['pattern_flags'])\n if (patternFlags?.length) drivers.push(`Pattern flags: ${patternFlags.join(', ')}`)\n\n const outflowCount = exchangeRows.filter((row) => row['direction'] === 'outflow').length\n const inflowCount = exchangeRows.filter((row) => row['direction'] === 'inflow').length\n if (outflowCount > 0) drivers.push(`Forward bounded search reached ${outflowCount} exchange path(s).`)\n if (inflowCount > 0) drivers.push(`Backward bounded search found ${inflowCount} source exchange path(s).`)\n\n return [...new Set(drivers)]\n}\n\nfunction terminalEdgeProperties(row: Record<string, unknown>): Record<string, unknown> | undefined {\n const edgeProps = Array.isArray(row['edge_props']) ? row['edge_props'] as Array<Record<string, unknown>> : []\n return edgeProps[edgeProps.length - 1]\n}\n\nfunction enrichExchangeRows(rows: Array<Record<string, unknown>>): Array<Record<string, unknown>> {\n return rows.map((row) => {\n const terminal = terminalEdgeProperties(row)\n if (!terminal) return row\n return {\n ...row,\n amount_sum: row['amount_sum'] ?? terminal['amount_sum'],\n amount_usd_sum: row['amount_usd_sum'] ?? terminal['amount_usd_sum'],\n tx_count: row['tx_count'] ?? terminal['tx_count'],\n first_tx_id: row['first_tx_id'] ?? terminal['first_tx_id'],\n last_tx_id: row['last_tx_id'] ?? terminal['last_tx_id'],\n }\n })\n}\n\nfunction riskAssessment(profile: Record<string, unknown>, exchangeRows: Array<Record<string, unknown>>): Record<string, unknown> {\n const storedScore = firstNumber(profile['confluence_score'], profile['ml_risk_score'], profile['risk_score'])\n const score = storedScore ?? (exchangeRows.length > 0 ? 0.4 : 0)\n const level = firstString(profile['ml_risk_level'], profile['risk_level']) ?? riskLevelFromScore(score)\n const drivers = riskDrivers(profile, exchangeRows)\n return {\n level,\n score,\n confidence: storedScore !== undefined || firstString(profile['ml_risk_level'], profile['risk_level']) ? 'high' : exchangeRows.length > 0 ? 'medium' : 'low',\n recommendation: riskRecommendation(level),\n drivers,\n }\n}\n\nfunction formatRiskScore(score: unknown): string {\n const parsed = numberValue(score)\n if (parsed === undefined) return String(score ?? 'unknown')\n return Number.isInteger(parsed) ? parsed.toString() : parsed.toFixed(2)\n}\n\nfunction stringArrayValue(value: unknown): string[] | undefined {\n if (Array.isArray(value)) return value.map(String)\n if (typeof value === 'string' && value.trim()) return [value]\n return undefined\n}\n\nfunction restoreSystemLabels(graph: Record<string, unknown>, rawNodes: Array<Record<string, unknown>>): Record<string, unknown> {\n if (!Array.isArray(graph['nodes'])) return graph\n const labelsByAddress = new Map(rawNodes\n .map((node) => [typeof node['address'] === 'string' ? node['address'] : typeof node['id'] === 'string' ? node['id'] : '', stringArrayValue(node['system_labels'])] as const)\n .filter((entry): entry is readonly [string, string[]] => Boolean(entry[0]) && Array.isArray(entry[1]) && entry[1].length > 0))\n return {\n ...graph,\n nodes: graph['nodes'].map((node) => {\n if (typeof node !== 'object' || node === null || Array.isArray(node)) return node\n const record = node as Record<string, unknown>\n const address = typeof record['address'] === 'string' ? record['address'] : typeof record['id'] === 'string' ? record['id'] : ''\n const systemLabels = labelsByAddress.get(address)\n return systemLabels ? { ...record, system_labels: systemLabels } : record\n }),\n }\n}\n\nfunction buildRiskGraph(address: string, profile: Record<string, unknown>, rows: Array<Record<string, unknown>>, network: string): Record<string, unknown> {\n const nodes = new Map<string, Record<string, unknown>>()\n nodes.set(address, {\n id: address,\n address,\n node_type: 'address',\n labels: stringArrayValue(profile['display_labels']) ?? [],\n ...(stringArrayValue(profile['system_labels']) ? { system_labels: stringArrayValue(profile['system_labels']) } : {}),\n ...(typeof profile['address_type'] === 'string' ? { address_type: profile['address_type'] } : {}),\n ...(stringArrayValue(profile['address_subtypes']) ? { address_subtypes: stringArrayValue(profile['address_subtypes']) } : {}),\n roles: ['subject'],\n })\n const edges: Array<Record<string, unknown>> = []\n const mergeNode = (entry: string, metadata?: Record<string, unknown>) => {\n const existing = nodes.get(entry) ?? { id: entry, address: entry, node_type: 'address', labels: [] }\n const labels = stringArrayValue(metadata?.['labels']) ?? existing['labels']\n const systemLabels = stringArrayValue(metadata?.['system_labels']) ?? existing['system_labels']\n const addressType = typeof metadata?.['address_type'] === 'string' ? metadata['address_type'] : existing['address_type']\n const addressSubtypes = stringArrayValue(metadata?.['address_subtypes']) ?? existing['address_subtypes']\n nodes.set(entry, {\n ...existing,\n labels,\n ...(systemLabels ? { system_labels: systemLabels } : {}),\n ...(addressType ? { address_type: addressType } : {}),\n ...(addressSubtypes ? { address_subtypes: addressSubtypes } : {}),\n })\n }\n for (const row of rows) {\n const rawPath = Array.isArray(row['path']) ? row['path'] : row['addresses']\n const path = Array.isArray(rawPath) ? rawPath.map(String) : []\n const pathNodes = Array.isArray(row['path_nodes']) ? row['path_nodes'] as Array<Record<string, unknown>> : []\n for (let index = 0; index < path.length; index += 1) {\n const entry = path[index]!\n mergeNode(entry, pathNodes[index])\n }\n const exchange = typeof row['exchange_address'] === 'string' ? row['exchange_address'] : ''\n if (exchange) {\n const displayLabels = stringArrayValue(row['exchange_display_labels']) ?? []\n const systemLabels = stringArrayValue(row['exchange_system_labels']) ?? stringArrayValue(row['exchange_labels']) ?? []\n nodes.set(exchange, {\n id: exchange,\n address: exchange,\n node_type: 'address',\n labels: displayLabels,\n ...(systemLabels.length > 0 ? { system_labels: systemLabels } : {}),\n ...(typeof row['exchange_address_type'] === 'string' ? { address_type: row['exchange_address_type'] } : {}),\n ...(stringArrayValue(row['exchange_address_subtypes']) ? { address_subtypes: stringArrayValue(row['exchange_address_subtypes']) } : {}),\n roles: ['exchange'],\n })\n }\n for (let index = 0; index < path.length - 1; index += 1) {\n const edgeProps = Array.isArray(row['edge_props']) ? row['edge_props'] as Array<Record<string, unknown>> : []\n const edge = edgeProps[index] ?? row\n edges.push({\n source: path[index],\n target: path[index + 1],\n edge_type: 'flows_to',\n usd_amount: edge['amount_usd_sum'] ?? edge['amount_sum'] ?? 0,\n amount_sum: edge['amount_sum'] ?? 0,\n tx_count: edge['tx_count'] ?? 0,\n first_tx_id: edge['first_tx_id'],\n last_tx_id: edge['last_tx_id'],\n direction: row['direction'],\n })\n }\n }\n const rawNodes = [...nodes.values()]\n return restoreSystemLabels(normalizeGraphPayload({\n schema: 'chain-insights.graph.v1',\n nodes: rawNodes,\n edges,\n flows: [],\n edge_anchors: [],\n metadata: { address, network, generated_at: new Date().toISOString() },\n }), rawNodes)\n}\n\nexport async function addressRisk(remoteClient: Client, options: AddressRiskOptions): Promise<{\n summaryText: string\n structuredContent: Record<string, unknown>\n graphData: Record<string, unknown>\n}> {\n const address = options.address.trim()\n const network = options.network.trim()\n const compareAddress = options.compareAddress?.trim() ?? ''\n if (!address) throw new Error('address is required')\n if (!network) throw new Error('network is required')\n\n const queries = [\n addressProfileQuery(address),\n addressFeatureQuery(address),\n addressRiskScoreQuery(address),\n ...exchangeOutflowQueries(address),\n ...exchangeInflowQueries(address),\n ...(compareAddress ? [connectionProbeQuery(address, compareAddress)] : [{ id: 'connection_probe', query: 'MATCH (n:Address {address: \"__chain_insights_noop__\"}) RETURN n.address AS noop LIMIT 0' }]),\n ]\n const batch = await callGraphBatch(remoteClient, network, queries)\n const partialQueryFailures: QueryFailure[] = []\n const profile: Record<string, unknown> = {\n address,\n ...(optionalResultsFor(batch, 'address_profile', partialQueryFailures)[0] ?? {}),\n ...(optionalResultsFor(batch, 'address_feature', partialQueryFailures)[0] ?? {}),\n ...(optionalResultsFor(batch, 'address_risk_score', partialQueryFailures)[0] ?? {}),\n }\n const outflows = enrichExchangeRows(optionalResultsWithPrefix(batch, 'exchange_outflows_', partialQueryFailures))\n const inflows = enrichExchangeRows(optionalResultsWithPrefix(batch, 'exchange_inflows_', partialQueryFailures))\n const connections = compareAddress ? optionalResultsFor(batch, 'connection_probe', partialQueryFailures) : []\n const exchangeRows = [...outflows, ...inflows]\n const graphData = buildRiskGraph(address, profile, exchangeRows, network)\n const risk = riskAssessment(profile, exchangeRows)\n\n const lines = [\n `Address risk for ${network}:${address}`,\n '',\n `Risk: ${risk['level']} (${formatRiskScore(risk['score'])})`,\n `Confidence: ${risk['confidence']}`,\n `Recommendation: ${risk['recommendation']}`,\n `Graph degree: in ${profile['degree_in'] ?? 'unknown'}, out ${profile['degree_out'] ?? 'unknown'}.`,\n '',\n 'Exchange behavior',\n exchangeRows.length > 0 ? formatExchangeRows(exchangeRows).join('\\n') : '- No exchange inflow/outflow paths found in bounded search.',\n ]\n if (Array.isArray(risk['drivers']) && risk['drivers'].length > 0) {\n lines.push('', 'Risk drivers', risk['drivers'].map((driver) => `- ${driver}`).join('\\n'))\n }\n if (compareAddress) {\n lines.push('', `Connection compare target: ${compareAddress}`, connections.length > 0 ? `Connection paths found: ${connections.length}` : 'Connection paths found: 0')\n }\n if (partialQueryFailures.length > 0) {\n lines.push('', 'Partial query failures', partialQueryFailures.map((failure) => `- ${failure.id}: ${failure.error}`).join('\\n'))\n }\n\n return {\n summaryText: lines.join('\\n'),\n structuredContent: {\n schema: 'chain-insights.result.v1',\n tool: 'address_risk',\n facts: {\n subject: { network, addresses: compareAddress ? [address, compareAddress] : [address] },\n risk,\n exchange_behavior: {\n outflows,\n inflows,\n },\n connection: compareAddress ? { compare_address: compareAddress, paths: connections } : undefined,\n partial_query_errors: partialQueryFailures.length > 0 ? partialQueryFailures : undefined,\n },\n },\n graphData,\n }\n}\n\ntype TraceSeedRole = 'victim' | 'suspect' | 'deposit'\ntype TraceToolName = 'trace_victim_funds' | 'trace_suspect_funds' | 'trace_deposit_sources'\ntype TraceRole =\n | 'seed_victim'\n | 'seed_suspect'\n | 'seed_deposit'\n | 'candidate_victim'\n | 'candidate_suspect'\n | 'candidate_intermediate'\n | 'candidate_deposit'\n | 'exchange'\n | 'unknown'\n\nexport interface TraceVictimFundsOptions {\n victimAddresses: string | string[]\n knownSuspectAddresses?: string | string[]\n network: string\n caseId?: string\n incidentTimestampMs?: number\n timeRange?: { from_ms?: number; to_ms?: number }\n maxHops?: number\n perAddressLimit?: number\n minAmountSum?: number\n}\n\nexport interface TraceSuspectFundsOptions {\n suspectAddresses: string | string[]\n network: string\n caseId?: string\n incidentTimestampMs?: number\n timeRange?: { from_ms?: number; to_ms?: number }\n maxHops?: number\n perAddressLimit?: number\n minAmountSum?: number\n}\n\nexport interface TraceDepositSourcesOptions {\n depositAddresses: string | string[]\n network: string\n caseId?: string\n timeRange?: { from_ms?: number; to_ms?: number }\n maxHops?: number\n}\n\ntype TraceToolResult = {\n summaryText: string\n structuredContent: Record<string, unknown>\n graphData: Record<string, unknown>\n}\n\ntype TraceRunRole = 'victim' | 'suspect'\ntype TraceRun = { role: TraceRunRole; address: string; result: TraceFundsResult }\ntype TraceAddressAccumulator = {\n address: string\n roles: Set<TraceRole>\n labels: string[]\n is_exchange?: boolean\n confidence: 'low' | 'medium' | 'high'\n rationale: string[]\n}\n\nfunction uniqueStrings(values: Array<string | undefined>): string[] {\n return [...new Set(values.filter((value): value is string => typeof value === 'string' && value.length > 0))]\n}\n\nfunction clampInt(value: number | undefined, fallback: number, min: number, max: number): number {\n if (!Number.isFinite(value)) return fallback\n return Math.max(min, Math.min(max, Math.trunc(value as number)))\n}\n\nfunction graphRecords(graphData: Record<string, unknown>, key: string): Array<Record<string, unknown>> {\n const value = graphData[key]\n return Array.isArray(value)\n ? value.filter((item): item is Record<string, unknown> => typeof item === 'object' && item !== null && !Array.isArray(item))\n : []\n}\n\nfunction normalizeTraceGraphData(runs: TraceRun[], network: string): Record<string, unknown> {\n return normalizeGraphPayload({\n schema: 'chain-insights.graph.v1',\n nodes: runs.flatMap((run) => graphRecords(run.result.graphData, 'nodes')),\n edges: runs.flatMap((run) => graphRecords(run.result.graphData, 'edges')),\n flows: runs.flatMap((run) => graphRecords(run.result.graphData, 'flows')),\n deposits: runs.flatMap((run) => graphRecords(run.result.graphData, 'deposits').map((item) => ({ ...item, run_role: run.role, run_address: run.address }))),\n source_matches: runs.flatMap((run) => graphRecords(run.result.graphData, 'source_matches').map((item) => ({ ...item, run_role: run.role, run_address: run.address }))),\n reverse_leads: runs.flatMap((run) => graphRecords(run.result.graphData, 'reverse_leads').map((item) => ({ ...item, run_role: run.role, run_address: run.address }))),\n edge_anchors: [],\n metadata: {\n network,\n generated_at: new Date().toISOString(),\n trace_tools: true,\n },\n })\n}\n\nfunction traceArtifactPointersFromRun(run: TraceFundsResult | undefined): Record<string, unknown> {\n if (!run) return {}\n return {\n graph_json: run.files.graph,\n graph_html: run.files.graphHtml,\n table_json: run.files.compactEvidence,\n flows_csv: run.files.table,\n table_html: run.files.tableHtml,\n report_md: run.files.report,\n }\n}\n\nfunction artifactEvidence(artifacts: Record<string, unknown>): Array<Record<string, unknown>> {\n return Object.entries(artifacts)\n .filter((entry): entry is [string, string] => typeof entry[1] === 'string' && entry[1].length > 0)\n .map(([kind, filePath]) => ({\n evidence_type: 'artifact_pointer',\n path: filePath,\n summary: `${kind} artifact`,\n }))\n}\n\nfunction traceAddressRoleForSeed(seedRole: TraceSeedRole): TraceRole {\n if (seedRole === 'victim') return 'seed_victim'\n if (seedRole === 'suspect') return 'seed_suspect'\n return 'seed_deposit'\n}\n\nfunction addTraceAddress(\n addresses: Map<string, TraceAddressAccumulator>,\n address: string,\n role: TraceRole,\n rationale: string,\n labels: string[] = [],\n): void {\n if (!address) return\n const existing = addresses.get(address)\n if (existing) {\n existing.roles.add(role)\n existing.labels = uniqueStrings([...existing.labels, ...labels])\n if (role === 'exchange') existing.is_exchange = true\n if (!existing.rationale.includes(rationale)) existing.rationale.push(rationale)\n return\n }\n addresses.set(address, {\n address,\n roles: new Set([role]),\n labels,\n is_exchange: role === 'exchange' ? true : undefined,\n confidence: role.startsWith('seed_') || role === 'exchange' ? 'high' : 'medium',\n rationale: [rationale],\n })\n}\n\nfunction edgeKey(from: string, to: string): string {\n return `${from}\\u0000${to}`\n}\n\nfunction traceResultFromFundRuns(\n tool: Extract<TraceToolName, 'trace_victim_funds' | 'trace_suspect_funds'>,\n seedRole: Extract<TraceSeedRole, 'victim' | 'suspect'>,\n network: string,\n runs: TraceRun[],\n options: {\n incidentTimestampMs?: number\n timeRange?: { from_ms?: number; to_ms?: number }\n maxHops?: number\n caseId?: string\n } = {},\n): { summaryText: string; structuredContent: Record<string, unknown>; graphData: Record<string, unknown> } {\n const graphData = normalizeTraceGraphData(runs, network)\n const flows = graphRecords(graphData, 'flows')\n const deposits = graphRecords(graphData, 'deposits')\n const addresses = new Map<string, TraceAddressAccumulator>()\n for (const run of runs) {\n addTraceAddress(addresses, run.address, traceAddressRoleForSeed(seedRole), `${seedRole} seed provided by caller`)\n }\n\n const edgeIdsByPair = new Map<string, string>()\n const edges = flows.map((flow, index) => {\n const src = typeof flow['src'] === 'string' ? flow['src'] : ''\n const dst = typeof flow['dst'] === 'string' ? flow['dst'] : ''\n const edgeId = `e${index + 1}`\n edgeIdsByPair.set(edgeKey(src, dst), edgeId)\n const terminalExchange = flow['terminal_exchange'] === true\n addTraceAddress(addresses, src, runs.some((run) => run.address === src) ? traceAddressRoleForSeed(seedRole) : 'candidate_intermediate', 'Address appears in traced FLOWS_TO path')\n addTraceAddress(addresses, dst, terminalExchange ? 'exchange' : 'candidate_intermediate', terminalExchange ? 'Terminal exchange endpoint reached' : 'Address appears in traced FLOWS_TO path')\n return {\n edge_id: edgeId,\n from_address: src,\n to_address: dst,\n edge_type: 'FLOWS_TO',\n amount_sum: numberValue(flow['amount_sum']),\n amount_usd_sum: numberValue(flow['amount_usd_sum']),\n tx_count: numberValue(flow['tx_count']),\n first_tx_id: typeof flow['first_tx_id'] === 'string' ? flow['first_tx_id'] : undefined,\n last_tx_id: typeof flow['last_tx_id'] === 'string' ? flow['last_tx_id'] : undefined,\n }\n }).filter((edge) => edge.from_address && edge.to_address)\n\n const paths = deposits.map((deposit, index) => {\n const depositAddress = typeof deposit['address'] === 'string'\n ? deposit['address']\n : typeof deposit['deposit_address'] === 'string' ? deposit['deposit_address'] : ''\n const exchangeAddress = typeof deposit['exchangeAddress'] === 'string'\n ? deposit['exchangeAddress']\n : typeof deposit['exchange_address'] === 'string' ? deposit['exchange_address'] : ''\n const pathAddresses = stringArrayValue(deposit['path']) ?? [\n typeof deposit['run_address'] === 'string' ? deposit['run_address'] : runs[0]?.address ?? '',\n depositAddress,\n exchangeAddress,\n ].filter(Boolean)\n addTraceAddress(addresses, depositAddress, 'candidate_deposit', 'Penultimate address before an exchange endpoint')\n if (exchangeAddress) addTraceAddress(addresses, exchangeAddress, 'exchange', 'Exchange endpoint reached')\n const edgeIds: string[] = []\n for (let offset = 0; offset < pathAddresses.length - 1; offset += 1) {\n const id = edgeIdsByPair.get(edgeKey(pathAddresses[offset]!, pathAddresses[offset + 1]!))\n if (id) edgeIds.push(id)\n }\n return {\n path_id: `p${index + 1}`,\n direction: 'forward',\n source: pathAddresses[0] ?? '',\n target: exchangeAddress || depositAddress,\n addresses: pathAddresses,\n edge_ids: edgeIds,\n hops: numberValue(deposit['hops']) ?? Math.max(pathAddresses.length - 1, 0),\n terminal_role: exchangeAddress ? 'exchange' : 'deposit',\n amount_sum: numberValue(deposit['amount_sum']),\n amount_usd_sum: numberValue(deposit['amount_usd_sum']),\n }\n })\n\n const depositAddresses = uniqueStrings(deposits.map((deposit) => (\n typeof deposit['address'] === 'string' ? deposit['address'] : typeof deposit['deposit_address'] === 'string' ? deposit['deposit_address'] : undefined\n )))\n const exchangeAddresses = uniqueStrings(deposits.map((deposit) => (\n typeof deposit['exchangeAddress'] === 'string' ? deposit['exchangeAddress'] : typeof deposit['exchange_address'] === 'string' ? deposit['exchange_address'] : undefined\n )))\n const convergence = [...new Map(depositAddresses.map((address) => {\n const pathIds = paths.filter((path) => path.addresses.includes(address)).map((path) => path.path_id)\n return [address, {\n address,\n role: 'candidate_deposit',\n path_ids: pathIds,\n reason: pathIds.length > 1 ? 'Multiple traced paths converge into this deposit candidate.' : 'Single traced path reached this deposit candidate.',\n }]\n })).values()].filter((entry) => entry.path_ids.length > 1)\n const candidateLabels = depositAddresses.map((address) => ({\n address,\n candidate_label: 'candidate_deposit',\n confidence: 'medium',\n evidence_path_ids: paths.filter((path) => path.addresses.includes(address)).map((path) => path.path_id),\n reason: 'Penultimate address before an exchange endpoint in bounded FLOWS_TO trace.',\n promote_to_core_label: false,\n }))\n const runArtifacts = runs.map((run, index) => ({\n run_id: `run_${index + 1}`,\n role: run.role,\n address: run.address,\n ...traceArtifactPointersFromRun(run.result),\n }))\n const artifacts = {\n ...traceArtifactPointersFromRun(runs[0]?.result),\n runs: runArtifacts,\n }\n const artifactEvidenceEntries = runs.flatMap((run) => artifactEvidence(traceArtifactPointersFromRun(run.result))\n .map((entry) => ({ ...entry, run_role: run.role, address: run.address })))\n const recommendedNextTools = depositAddresses.length > 0\n ? ['trace_deposit_sources', 'address_risk']\n : ['address_risk', 'graph_query_batch']\n\n const structuredContent = {\n schema: 'chain-insights.trace.v1',\n tool,\n network,\n input: {\n addresses: runs.map((run) => run.address),\n seed_role: seedRole,\n ...(options.incidentTimestampMs !== undefined ? { incident_timestamp_ms: options.incidentTimestampMs } : {}),\n ...(options.timeRange ? { time_range: options.timeRange } : {}),\n max_hops: options.maxHops ?? 3,\n },\n summary: {\n seed_count: runs.length,\n path_count: paths.length,\n edge_count: edges.length,\n candidate_suspect_count: seedRole === 'suspect' ? runs.length : 0,\n candidate_intermediate_count: [...addresses.values()].filter((entry) => entry.roles.has('candidate_intermediate')).length,\n candidate_deposit_count: depositAddresses.length,\n exchange_count: exchangeAddresses.length,\n },\n addresses: [...addresses.values()].map((entry) => ({\n address: entry.address,\n roles: [...entry.roles],\n ...(entry.labels.length > 0 ? { labels: entry.labels } : {}),\n ...(entry.is_exchange !== undefined ? { is_exchange: entry.is_exchange } : {}),\n confidence: entry.confidence,\n rationale: entry.rationale,\n })),\n edges,\n paths,\n convergence,\n exchange_exposure: deposits.map((deposit) => ({\n deposit_address: typeof deposit['address'] === 'string' ? deposit['address'] : deposit['deposit_address'],\n exchange_address: typeof deposit['exchangeAddress'] === 'string' ? deposit['exchangeAddress'] : deposit['exchange_address'],\n path_ids: paths.filter((path) => path.addresses.includes(String(deposit['address'] ?? deposit['deposit_address'] ?? ''))).map((path) => path.path_id),\n })),\n candidate_labels: candidateLabels,\n artifacts,\n evidence: [\n ...artifactEvidenceEntries,\n ...(options.caseId ? [{ evidence_type: 'case_pointer', summary: `case_id=${options.caseId}` }] : []),\n ],\n continuation: {\n candidate_deposit_addresses: depositAddresses,\n candidate_suspect_addresses: seedRole === 'suspect' ? runs.map((run) => run.address) : [],\n candidate_victim_addresses: [],\n recommended_next_tools: recommendedNextTools,\n },\n warnings: depositAddresses.length === 0 ? ['No exchange deposit candidates were connected in the queried topology.'] : [],\n }\n\n return {\n summaryText: [\n `${seedRole === 'victim' ? 'Trace victim funds' : 'Trace suspect funds'} complete for ${network}`,\n '',\n ...runs.map((run) => `## ${run.role}: ${run.address}\\n${run.result.summaryText}`),\n ].join('\\n'),\n structuredContent,\n graphData,\n }\n}\n\nexport async function traceVictimFunds(\n remoteClient: Client,\n config: Pick<InvestigatorConfig, 'dataDir' | 'serverPort'>,\n options: TraceVictimFundsOptions,\n): Promise<TraceToolResult> {\n const network = options.network.trim()\n const victims = parseAddressList(options.victimAddresses)\n const knownSuspects = parseAddressList(options.knownSuspectAddresses)\n if (!network) throw new Error('network is required')\n if (victims.length < 1) throw new Error('victim_addresses must contain at least 1 address')\n if (victims.length > 5) throw new Error('victim_addresses cannot exceed 5 addresses')\n if (knownSuspects.length > 5) throw new Error('known_suspect_addresses cannot exceed 5 addresses')\n\n const runs: TraceRun[] = []\n for (const address of victims) {\n runs.push({\n role: 'victim',\n address,\n result: await runFundFlowProbe(remoteClient, config, {\n seedAddress: address,\n network,\n caseId: options.caseId,\n maxHops: options.maxHops,\n perAddressLimit: options.perAddressLimit,\n minAmountSum: options.minAmountSum,\n includeDepositTraceback: false,\n evidenceSource: 'trace_victim_funds',\n }),\n })\n }\n return traceResultFromFundRuns('trace_victim_funds', 'victim', network, runs, {\n incidentTimestampMs: options.incidentTimestampMs,\n timeRange: options.timeRange,\n maxHops: options.maxHops,\n caseId: options.caseId,\n })\n}\n\nexport async function traceSuspectFunds(\n remoteClient: Client,\n config: Pick<InvestigatorConfig, 'dataDir' | 'serverPort'>,\n options: TraceSuspectFundsOptions,\n): Promise<TraceToolResult> {\n const network = options.network.trim()\n const suspects = parseAddressList(options.suspectAddresses)\n if (!network) throw new Error('network is required')\n if (suspects.length < 1) throw new Error('suspect_addresses must contain at least 1 address')\n if (suspects.length > 5) throw new Error('suspect_addresses cannot exceed 5 addresses')\n\n const runs: TraceRun[] = []\n for (const address of suspects) {\n runs.push({\n role: 'suspect',\n address,\n result: await runFundFlowProbe(remoteClient, config, {\n seedAddress: address,\n network,\n caseId: options.caseId,\n maxHops: options.maxHops,\n perAddressLimit: options.perAddressLimit,\n minAmountSum: options.minAmountSum,\n includeDepositTraceback: false,\n evidenceSource: 'trace_suspect_funds',\n }),\n })\n }\n return traceResultFromFundRuns('trace_suspect_funds', 'suspect', network, runs, {\n incidentTimestampMs: options.incidentTimestampMs,\n timeRange: options.timeRange,\n maxHops: options.maxHops,\n caseId: options.caseId,\n })\n}\n\nfunction reverseDepositSourceQueryAtDepth(depositAddresses: string[], depth: number): { id: string; query: string } {\n const intermediateVariables = Array.from({ length: Math.max(depth - 1, 0) }, (_, index) => `n${index + 1}`)\n const nodeVariables = ['source', ...intermediateVariables, 'deposit']\n const edgeVariables = Array.from({ length: depth }, (_, index) => `r${index + 1}`)\n const relationshipChain = edgeVariables.map((edgeVariable, index) => {\n const targetVariable = index === edgeVariables.length - 1 ? 'deposit' : intermediateVariables[index]!\n return `-[${edgeVariable}:FLOWS_TO]->(${targetVariable}:Address)`\n }).join('')\n const depositPredicates = depositAddresses.map((address) => `deposit.address = \"${escapeCypherString(address)}\"`)\n const nonExchangePredicates = ['source', ...intermediateVariables, 'deposit'].map((nodeVariable) => `${nodeVariable}.is_exchange IS NULL`)\n return {\n id: `reverse_deposit_sources_${depth}`,\n query: [\n `MATCH (source:Address)${relationshipChain}`,\n `WHERE (${depositPredicates.join(' OR ')}) AND source.address <> deposit.address AND ${nonExchangePredicates.join(' AND ')}`,\n `RETURN DISTINCT source.address AS source_address, source.is_exchange AS source_is_exchange, deposit.address AS deposit_address, deposit.is_exchange AS deposit_is_exchange, ${depth} AS hop, [${nodeVariables.map((nodeVariable) => `${nodeVariable}.address`).join(', ')}] AS addresses, [${nodeVariables.map(pathNodeMap).join(', ')}] AS path_nodes, [${edgeVariables.map(flowEdgeMap).join(', ')}] AS edge_props`,\n 'LIMIT 500',\n ].join(' '),\n }\n}\n\nfunction rowNodeIsExchange(value: unknown): boolean {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return false\n const record = value as Record<string, unknown>\n return isExchangeFlag(record['is_exchange']) ||\n hasExactExchangeLabel(stringArrayValue(record['labels'])) ||\n hasExactExchangeLabel(stringArrayValue(record['system_labels']))\n}\n\nfunction reverseDepositSourceRowUsesExchange(row: Record<string, unknown>): boolean {\n if (isExchangeFlag(row['source_is_exchange']) || isExchangeFlag(row['deposit_is_exchange'])) return true\n if (!Array.isArray(row['path_nodes'])) return false\n return row['path_nodes'].some(rowNodeIsExchange)\n}\n\nfunction htmlEscape(value: unknown): string {\n return String(value ?? '')\n .replaceAll('&', '&amp;')\n .replaceAll('<', '&lt;')\n .replaceAll('>', '&gt;')\n .replaceAll('\"', '&quot;')\n .replaceAll(\"'\", '&#39;')\n}\n\nfunction buildTraceSourceTableHtml(tool: TraceToolName, network: string, rows: Array<Record<string, unknown>>): string {\n const headers = ['path_id', 'source_address', 'deposit_address', 'hop', 'amount_sum', 'first_tx_id'] as const\n const body = rows.map((row) => `<tr>${headers.map((header) => `<td>${htmlEscape(row[header])}</td>`).join('')}</tr>`).join('\\n')\n return `<!doctype html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<title>${htmlEscape(tool)} Table</title>\n<style>\n :root { color-scheme: dark; font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif; background: #0b0d12; color: #f4f2ea; }\n body { margin: 0; background: #0b0d12; color: #f4f2ea; }\n main { padding: 24px; }\n h1 { font-size: 20px; margin: 0 0 8px; font-weight: 650; }\n .meta { display: grid; gap: 6px; margin: 0 0 20px; color: rgba(244,242,234,.72); font-size: 13px; }\n .table-wrap { overflow: auto; border: 1px solid rgba(255,255,255,.1); border-radius: 8px; background: #10131b; }\n table { border-collapse: collapse; width: 100%; min-width: 980px; font-size: 12px; }\n th, td { border-bottom: 1px solid rgba(255,255,255,.08); padding: 8px 10px; text-align: left; vertical-align: top; }\n th { position: sticky; top: 0; background: #161a24; color: #f2dda6; font-weight: 600; z-index: 1; }\n td { color: rgba(244,242,234,.86); font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }\n tr:hover td { background: rgba(242,221,166,.045); }\n</style>\n</head>\n<body>\n<main>\n <h1>${htmlEscape(tool)} Table</h1>\n <div class=\"meta\">\n <div>Network: <strong>${htmlEscape(network)}</strong></div>\n <div>Generated: <strong>${htmlEscape(new Date().toISOString())}</strong></div>\n <div>Rows: <strong>${rows.length}</strong></div>\n </div>\n <div class=\"table-wrap\">\n <table>\n <thead><tr>${headers.map((header) => `<th>${htmlEscape(header)}</th>`).join('')}</tr></thead>\n <tbody>\n${body}\n </tbody>\n </table>\n </div>\n</main>\n</body>\n</html>\n`\n}\n\nasync function writeTraceSourceArtifacts(tool: TraceToolName, network: string, graphData: Record<string, unknown>, rows: Array<Record<string, unknown>>, summaryText: string): Promise<Record<string, unknown>> {\n const paths = workspaceOutputPaths()\n await Promise.all([\n mkdir(paths.reportsRoot, { recursive: true }),\n mkdir(paths.reportGraphsRoot, { recursive: true }),\n mkdir(paths.reportTablesRoot, { recursive: true }),\n ])\n const slug = `${new Date().toISOString().replace(/[-:]/g, '').replace(/\\.\\d{3}Z$/, 'Z')}_${tool}`\n const graphPath = path.join(paths.reportGraphsRoot, `${slug}.graph.json`)\n const tableJsonPath = path.join(paths.reportTablesRoot, `${slug}.compact-evidence.json`)\n const csvPath = path.join(paths.reportTablesRoot, `${slug}.flows.csv`)\n const tableHtmlPath = path.join(paths.reportsRoot, `${slug}.table.html`)\n const reportPath = path.join(paths.reportsRoot, `${slug}.trace-report.md`)\n const graphHtmlPath = path.join(paths.reportsRoot, `${slug}.graph.html`)\n const { generateInlineGraphHtml } = await import('../viz/html-generator.js')\n const csv = [\n 'path_id,source_address,deposit_address,hop,amount_sum,first_tx_id',\n ...rows.map((row) => [\n row['path_id'] ?? '',\n row['source_address'] ?? '',\n row['deposit_address'] ?? '',\n row['hop'] ?? '',\n row['amount_sum'] ?? '',\n row['first_tx_id'] ?? '',\n ].map((value) => JSON.stringify(String(value))).join(',')),\n ].join('\\n') + '\\n'\n await writeFile(graphPath, JSON.stringify(graphData, null, 2) + '\\n', { mode: 0o600 })\n await writeFile(tableJsonPath, JSON.stringify(rows, null, 2) + '\\n', { mode: 0o600 })\n await writeFile(csvPath, csv, { mode: 0o600 })\n await writeFile(tableHtmlPath, buildTraceSourceTableHtml(tool, network, rows), { mode: 0o600 })\n await writeFile(reportPath, summaryText + '\\n', { mode: 0o600 })\n await writeFile(graphHtmlPath, generateInlineGraphHtml(graphData), { mode: 0o600 })\n return {\n graph_json: graphPath,\n graph_html: graphHtmlPath,\n table_json: tableJsonPath,\n flows_csv: csvPath,\n table_html: tableHtmlPath,\n report_md: reportPath,\n }\n}\n\nexport async function traceDepositSources(\n remoteClient: Client,\n _config: Pick<InvestigatorConfig, 'dataDir' | 'serverPort'>,\n options: TraceDepositSourcesOptions,\n): Promise<TraceToolResult> {\n const network = options.network.trim()\n const deposits = parseAddressList(options.depositAddresses)\n if (!network) throw new Error('network is required')\n if (deposits.length < 1) throw new Error('deposit_addresses must contain at least 1 address')\n if (deposits.length > 5) throw new Error('deposit_addresses cannot exceed 5 addresses')\n const maxHops = clampInt(options.maxHops, 2, 1, 5)\n\n const batch = await callGraphBatch(\n remoteClient,\n network,\n Array.from({ length: maxHops }, (_, index) => reverseDepositSourceQueryAtDepth(deposits, index + 1)),\n )\n const failures: QueryFailure[] = []\n const rows: Array<Record<string, unknown>> = optionalResultsWithPrefix(batch, 'reverse_deposit_sources_', failures)\n .filter((row) => !reverseDepositSourceRowUsesExchange(row))\n .map((row, index) => ({\n ...row,\n path_id: `p${index + 1}`,\n }))\n const addresses = new Map<string, {\n address: string\n roles: Set<TraceRole>\n labels: string[]\n is_exchange?: boolean\n confidence: 'low' | 'medium' | 'high'\n rationale: string[]\n }>()\n for (const deposit of deposits) addTraceAddress(addresses, deposit, 'seed_deposit', 'Deposit/cashout seed provided by caller')\n\n const edges: Array<Record<string, unknown>> = []\n const paths: Array<Record<string, unknown>> = []\n for (const row of rows) {\n const sourceAddress = typeof row['source_address'] === 'string' ? row['source_address'] : ''\n const depositAddress = typeof row['deposit_address'] === 'string' ? row['deposit_address'] : ''\n const pathAddresses = stringArrayValue(row['addresses']) ?? [sourceAddress, depositAddress].filter(Boolean)\n addTraceAddress(addresses, sourceAddress, 'candidate_suspect', 'Upstream address funds a suspected deposit/cashout seed')\n addTraceAddress(addresses, depositAddress, 'seed_deposit', 'Deposit/cashout seed provided by caller')\n const edgeProps = Array.isArray(row['edge_props']) ? row['edge_props'] as Array<Record<string, unknown>> : []\n const edgeIds: string[] = []\n for (let index = 0; index < pathAddresses.length - 1; index += 1) {\n const props = edgeProps[index] ?? {}\n const edgeId = `e${edges.length + 1}`\n edgeIds.push(edgeId)\n edges.push({\n edge_id: edgeId,\n from_address: pathAddresses[index],\n to_address: pathAddresses[index + 1],\n edge_type: 'FLOWS_TO',\n amount_sum: numberValue(props['amount_sum']) ?? numberValue(row['amount_sum']),\n amount_usd_sum: numberValue(props['amount_usd_sum']) ?? numberValue(row['amount_usd_sum']),\n tx_count: numberValue(props['tx_count']) ?? numberValue(row['tx_count']),\n first_seen_timestamp: numberValue(props['first_seen_timestamp']) ?? numberValue(row['first_seen_timestamp']),\n last_seen_timestamp: numberValue(props['last_seen_timestamp']) ?? numberValue(row['last_seen_timestamp']),\n first_tx_id: typeof props['first_tx_id'] === 'string' ? props['first_tx_id'] : typeof row['first_tx_id'] === 'string' ? row['first_tx_id'] : undefined,\n last_tx_id: typeof props['last_tx_id'] === 'string' ? props['last_tx_id'] : typeof row['last_tx_id'] === 'string' ? row['last_tx_id'] : undefined,\n })\n }\n paths.push({\n path_id: row['path_id'],\n direction: 'reverse',\n source: depositAddress,\n target: sourceAddress,\n addresses: [...pathAddresses].reverse(),\n edge_ids: [...edgeIds].reverse(),\n hops: numberValue(row['hop']) ?? Math.max(pathAddresses.length - 1, 0),\n terminal_role: 'source',\n amount_sum: numberValue(row['amount_sum']),\n amount_usd_sum: numberValue(row['amount_usd_sum']),\n first_seen_ms: numberValue(row['first_seen_timestamp']),\n last_seen_ms: numberValue(row['last_seen_timestamp']),\n })\n }\n\n const sourceToPathIds = new Map<string, string[]>()\n const sourceToDeposits = new Map<string, Set<string>>()\n for (const row of rows) {\n const source = typeof row['source_address'] === 'string' ? row['source_address'] : ''\n const deposit = typeof row['deposit_address'] === 'string' ? row['deposit_address'] : ''\n if (!source) continue\n sourceToPathIds.set(source, [...(sourceToPathIds.get(source) ?? []), String(row['path_id'])])\n if (!sourceToDeposits.has(source)) sourceToDeposits.set(source, new Set())\n if (deposit) sourceToDeposits.get(source)!.add(deposit)\n }\n const convergence = [...sourceToPathIds.entries()]\n .filter(([address]) => (sourceToDeposits.get(address)?.size ?? 0) > 1)\n .map(([address, pathIds]) => ({\n address,\n role: 'candidate_suspect',\n path_ids: pathIds,\n reason: 'Same upstream source funds multiple provided deposit/cashout seeds.',\n }))\n const candidateSuspects = convergence.map((entry) => entry.address)\n const candidateLabels = [...sourceToPathIds.keys()].map((address) => ({\n address,\n candidate_label: 'candidate_suspect',\n confidence: candidateSuspects.includes(address) ? 'high' : 'medium',\n evidence_path_ids: sourceToPathIds.get(address) ?? [],\n reason: candidateSuspects.includes(address)\n ? 'Upstream source converges into multiple provided deposit/cashout seeds.'\n : 'Upstream source funds a provided deposit/cashout seed.',\n promote_to_core_label: false,\n }))\n const graphData = normalizeGraphPayload({\n schema: 'chain-insights.graph.v1',\n nodes: [...addresses.values()].map((entry) => ({\n id: entry.address,\n address: entry.address,\n node_type: 'address',\n roles: [...entry.roles],\n labels: entry.labels,\n })),\n edges: edges.map((edge) => ({\n source: edge['from_address'],\n target: edge['to_address'],\n edge_type: 'flows_to',\n amount_sum: edge['amount_sum'],\n tx_count: edge['tx_count'],\n first_tx_id: edge['first_tx_id'],\n last_tx_id: edge['last_tx_id'],\n direction: 'traceback',\n })),\n flows: edges.map((edge, index) => ({\n hop: index + 1,\n src: edge['from_address'],\n dst: edge['to_address'],\n amount_sum: edge['amount_sum'] ?? 0,\n terminal_exchange: false,\n })),\n edge_anchors: [],\n metadata: {\n network,\n deposit_addresses: deposits,\n generated_at: new Date().toISOString(),\n },\n })\n const summaryText = [\n `Trace deposit sources complete for ${network}`,\n '',\n `Deposit seeds: ${deposits.join(', ')}`,\n `Reverse path(s): ${paths.length}`,\n `Shared upstream convergence: ${convergence.length}`,\n ].join('\\n')\n const artifacts = await writeTraceSourceArtifacts('trace_deposit_sources', network, graphData, rows, summaryText)\n const evidence = artifactEvidence(artifacts)\n if (options.caseId) {\n const { EvidenceStore } = await import('../cases/index.js')\n await EvidenceStore.append(options.caseId, {\n source: 'trace_deposit_sources',\n queryParams: `network=${network} deposit_addresses=${deposits.join(',')} max_hops=${maxHops}`,\n content: JSON.stringify({\n schema: 'chain-insights.evidence_pointer.v1',\n source: 'trace_deposit_sources',\n network,\n deposit_addresses: deposits,\n files: artifacts,\n compact_sha256: createHash('sha256').update(JSON.stringify({ rows, convergence })).digest('hex'),\n }, null, 2),\n })\n evidence.push({ evidence_type: 'case_pointer', summary: `case_id=${options.caseId}` })\n }\n\n return {\n summaryText,\n structuredContent: {\n schema: 'chain-insights.trace.v1',\n tool: 'trace_deposit_sources',\n network,\n input: {\n addresses: deposits,\n seed_role: 'deposit',\n ...(options.timeRange ? { time_range: options.timeRange } : {}),\n max_hops: maxHops,\n },\n summary: {\n seed_count: deposits.length,\n path_count: paths.length,\n edge_count: edges.length,\n candidate_suspect_count: sourceToPathIds.size,\n candidate_intermediate_count: 0,\n candidate_deposit_count: deposits.length,\n exchange_count: 0,\n },\n addresses: [...addresses.values()].map((entry) => ({\n address: entry.address,\n roles: [...entry.roles],\n confidence: entry.confidence,\n rationale: entry.rationale,\n })),\n edges,\n paths,\n convergence,\n exchange_exposure: [],\n candidate_labels: candidateLabels,\n artifacts,\n evidence: [\n ...evidence,\n ...(failures.length > 0 ? [{ evidence_type: 'query_summary', summary: `partial query failures: ${failures.length}` }] : []),\n ],\n continuation: {\n candidate_deposit_addresses: deposits,\n candidate_suspect_addresses: candidateSuspects,\n candidate_victim_addresses: [],\n recommended_next_tools: candidateSuspects.length > 0\n ? ['trace_suspect_funds', 'address_risk']\n : ['address_risk', 'graph_query_batch'],\n },\n warnings: paths.length === 0 ? ['No upstream sources were connected in the queried topology.'] : [],\n },\n graphData,\n }\n}\n\nexport async function trackFunds(\n remoteClient: Client,\n config: Pick<InvestigatorConfig, 'dataDir' | 'serverPort'>,\n options: TrackFundsOptions,\n): Promise<{\n summaryText: string\n structuredContent: Record<string, unknown>\n graphData: Record<string, unknown>\n}> {\n const network = options.network.trim()\n const trusted = parseAddressList(options.trustedAddresses)\n const untrusted = parseAddressList(options.untrustedAddresses)\n if (!network) throw new Error('network is required')\n if (trusted.length < 1) throw new Error('trusted_addresses must contain at least 1 address')\n if (trusted.length > 5) throw new Error('trusted_addresses cannot exceed 5 addresses')\n if (untrusted.length > 5) throw new Error('untrusted_addresses cannot exceed 5 addresses')\n const overlap = trusted.filter((address) => untrusted.includes(address))\n if (overlap.length > 0) throw new Error(`Address(es) appear in both trusted and untrusted lists: ${overlap.join(', ')}`)\n\n const runs: Array<{ role: 'trusted' | 'untrusted'; address: string; result: TraceFundsResult }> = []\n for (const address of trusted) {\n runs.push({\n role: 'trusted',\n address,\n result: await runFundFlowProbe(remoteClient, config, {\n seedAddress: address,\n network,\n caseId: options.caseId,\n maxHops: options.maxHops,\n perAddressLimit: options.perAddressLimit,\n minAmountSum: options.minAmountSum,\n }),\n })\n }\n for (const address of untrusted) {\n runs.push({\n role: 'untrusted',\n address,\n result: await runFundFlowProbe(remoteClient, config, {\n seedAddress: address,\n network,\n caseId: options.caseId,\n maxHops: options.maxHops,\n perAddressLimit: options.perAddressLimit,\n minAmountSum: options.minAmountSum,\n }),\n })\n }\n\n const graphData = normalizeGraphPayload({\n schema: 'chain-insights.graph.v1',\n nodes: runs.flatMap((run) => Array.isArray(run.result.graphData.nodes) ? run.result.graphData.nodes : []),\n edges: runs.flatMap((run) => Array.isArray(run.result.graphData.edges) ? run.result.graphData.edges : []),\n flows: runs.flatMap((run) => Array.isArray(run.result.graphData.flows) ? run.result.graphData.flows : []),\n deposits: runs.flatMap((run) => graphArray(run.result.graphData, 'deposits').map((item) => ({ ...item, run_role: run.role, run_address: run.address }))),\n source_matches: runs.flatMap((run) => graphArray(run.result.graphData, 'source_matches').map((item) => ({ ...item, run_role: run.role, run_address: run.address }))),\n reverse_leads: runs.flatMap((run) => graphArray(run.result.graphData, 'reverse_leads').map((item) => ({ ...item, run_role: run.role, run_address: run.address }))),\n edge_anchors: [],\n metadata: { network, trusted_addresses: trusted, untrusted_addresses: untrusted, generated_at: new Date().toISOString() },\n })\n\n return {\n summaryText: [\n `Track funds complete for ${network}`,\n '',\n `Trusted addresses: ${trusted.join(', ')}`,\n `Untrusted addresses: ${untrusted.join(', ') || 'none'}`,\n '',\n ...runs.map((run) => `## ${run.role}: ${run.address}\\n${run.result.summaryText}`),\n ].join('\\n'),\n structuredContent: {\n schema: 'chain-insights.result.v1',\n tool: 'track_funds',\n facts: {\n network,\n trusted_addresses: trusted,\n untrusted_addresses: untrusted,\n runs: runs.map((run) => ({\n role: run.role,\n address: run.address,\n files: run.result.files,\n continuation: run.result.continuation,\n address_map: run.result.addressMap,\n })),\n },\n },\n graphData,\n }\n}\n"],"mappings":"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"}