chain-insights 0.2.21 → 0.2.24

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 (38) hide show
  1. package/README.md +2 -1
  2. package/dist/{capabilities-Bm0JDbV7.cjs → capabilities-B4hvro_I.cjs} +1 -1
  3. package/dist/{capabilities-BShqspb-.mjs → capabilities-mXm_rCe8.mjs} +2 -2
  4. package/dist/{capabilities-BShqspb-.mjs.map → capabilities-mXm_rCe8.mjs.map} +1 -1
  5. package/dist/cli.cjs +32 -16
  6. package/dist/cli.mjs +32 -16
  7. package/dist/cli.mjs.map +1 -1
  8. package/dist/{client-DPc2eyVN.cjs → client-BYnFGA0y.cjs} +45 -10
  9. package/dist/{client-D4_hd4AP.mjs → client-Dl-uHrh1.mjs} +46 -11
  10. package/dist/client-Dl-uHrh1.mjs.map +1 -0
  11. package/dist/index.cjs +2 -2
  12. package/dist/index.d.cts.map +1 -1
  13. package/dist/index.d.mts.map +1 -1
  14. package/dist/index.mjs +2 -2
  15. package/dist/{init-4tn7jfhN.mjs → init-CB_ga4_8.mjs} +2 -2
  16. package/dist/init-CB_ga4_8.mjs.map +1 -0
  17. package/dist/{init-TCQY5RDJ.cjs → init-jhOZ_RvC.cjs} +1 -1
  18. package/dist/mcp-proxy.cjs +8 -8
  19. package/dist/mcp-proxy.mjs +8 -8
  20. package/dist/mcp-proxy.mjs.map +1 -1
  21. package/dist/{public-tools-BC1fi0DV.cjs → public-tools-q4NMdmDX.cjs} +227 -10
  22. package/dist/{public-tools-B13J0MJZ.mjs → public-tools-w7En2m3q.mjs} +228 -11
  23. package/dist/public-tools-w7En2m3q.mjs.map +1 -0
  24. package/dist/{runner-DIs04IhN.mjs → runner-BBH5Ks6q.mjs} +2 -2
  25. package/dist/{runner-DIs04IhN.mjs.map → runner-BBH5Ks6q.mjs.map} +1 -1
  26. package/dist/{runner-ZYowxCVl.cjs → runner-e9slg6R2.cjs} +1 -1
  27. package/dist/tools-D6RBAhSX.mjs +298 -0
  28. package/dist/tools-D6RBAhSX.mjs.map +1 -0
  29. package/dist/tools-UH5hRXYG.cjs +343 -0
  30. package/dist/topup-server-BJgVw6Jt.mjs.map +1 -1
  31. package/docs/mcp-proxy.md +4 -2
  32. package/package.json +1 -1
  33. package/dist/client-D4_hd4AP.mjs.map +0 -1
  34. package/dist/init-4tn7jfhN.mjs.map +0 -1
  35. package/dist/public-tools-B13J0MJZ.mjs.map +0 -1
  36. package/dist/tools-DY8h0WbE.cjs +0 -139
  37. package/dist/tools-Py6SXg6J.mjs +0 -100
  38. package/dist/tools-Py6SXg6J.mjs.map +0 -1
@@ -1,6 +1,6 @@
1
1
  import { n as PACKAGE_VERSION } from "./version-BA3J8hu4.mjs";
2
2
  import { n as loadConfig } from "./config-Drgc2HuF.mjs";
3
- import { r as createConfiguredMcpFetch } from "./client-D4_hd4AP.mjs";
3
+ import { r as createConfiguredMcpFetch } from "./client-Dl-uHrh1.mjs";
4
4
  import { t as generateVisualization } from "./viz-DkJyqlUu.mjs";
5
5
  import { CaseStore } from "./store-BT2SCcQr.mjs";
6
6
  import { t as EvidenceStore } from "./evidence-D96PTzOQ.mjs";
@@ -146,4 +146,4 @@ async run(playbook, opts) {
146
146
  //#endregion
147
147
  export { PlaybookRunner };
148
148
 
149
- //# sourceMappingURL=runner-DIs04IhN.mjs.map
149
+ //# sourceMappingURL=runner-BBH5Ks6q.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"runner-DIs04IhN.mjs","names":[],"sources":["../src/playbooks/runner.ts"],"sourcesContent":["import { Client } from '@modelcontextprotocol/sdk/client/index.js'\nimport { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js'\nimport { CaseStore } from '../cases/store.js'\nimport { EvidenceStore } from '../cases/evidence.js'\nimport { loadConfig } from '../config/index.js'\nimport { createConfiguredMcpFetch } from '../mcp/client.js'\nimport { generateVisualization } from '../viz/index.js'\nimport { PACKAGE_VERSION } from '../version.js'\nimport type { PlaybookDefinition } from './schema.js'\n\nexport interface RunnerOptions {\n caseId?: string // attach to existing case; omit for quick-case auto-creation\n from?: number // 1-based step to resume from (default: 1)\n dryRun?: boolean // print steps, no MCP calls\n params?: Record<string, string>\n}\n\n/** Sleep for ms milliseconds. */\nfunction sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms))\n}\n\n/** Check if an error is a timeout/abort error. */\nfunction isTimeoutError(err: unknown): boolean {\n if (!(err instanceof Error)) return false\n return err.name === 'AbortError' || (err as NodeJS.ErrnoException).code === 'ECONNRESET'\n}\n\n/** Check if an error is a payment failure. */\nfunction isPaymentError(err: unknown): boolean {\n if (!(err instanceof Error)) return false\n const msg = err.message.toLowerCase()\n // Match HTTP 402 status more precisely, or x402-specific error signals\n return msg.includes('http 402') ||\n msg.includes('status 402') ||\n msg.includes('payment required') ||\n msg.includes('x402')\n}\n\n/**\n * Call an MCP tool with retry logic on timeout (up to 3 total attempts).\n * Returns the text result or throws on non-retryable error.\n */\nasync function callWithRetry(\n client: Client,\n toolName: string,\n params: Record<string, string>\n): Promise<string> {\n const MAX_ATTEMPTS = 3\n let lastErr: unknown\n\n for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {\n try {\n const result = await client.callTool({ name: toolName, arguments: params })\n const content = result.content as Array<{ type: string; text?: string }>\n return content.filter(c => c.type === 'text').map(c => c.text ?? '').join('\\n')\n } catch (err) {\n if (isTimeoutError(err) && attempt < MAX_ATTEMPTS) {\n lastErr = err\n await sleep(1000)\n continue\n }\n throw err\n }\n }\n\n throw lastErr\n}\n\nasync function validateStepTools(client: Client, steps: PlaybookDefinition['steps']): Promise<void> {\n const result = await client.listTools()\n const available = new Set(result.tools.map(tool => tool.name))\n const missing = [...new Set(steps.map(step => step.tool).filter(tool => !available.has(tool)))]\n if (missing.length === 0) return\n\n const availableList = [...available].sort().join(', ') || 'none'\n throw new Error(\n `Unknown MCP tool(s) in playbook: ${missing.join(', ')}. ` +\n `Available tools: ${availableList}. Run \\`chain-insights mcp tools --refresh\\` to inspect the live MCP schema.`\n )\n}\n\nexport const PlaybookRunner = {\n /**\n * Execute a playbook definition step-by-step against the live MCP.\n *\n * @param playbook - Parsed and validated PlaybookDefinition\n * @param opts - Runner options (caseId, from, dryRun, params)\n */\n async run(playbook: PlaybookDefinition, opts: RunnerOptions): Promise<void> {\n const startIndex = (opts.from ?? 1) - 1 // convert 1-based to 0-based\n const stepsToRun = playbook.steps.slice(startIndex)\n const totalSteps = playbook.steps.length\n\n // --- DRY RUN ---\n if (opts.dryRun) {\n console.log(`Playbook: ${playbook.name} (dry run — no MCP calls)`)\n console.log(`Steps: ${totalSteps} total, starting from ${startIndex + 1}`)\n console.log('')\n for (const step of stepsToRun) {\n console.log(`Step ${step.index}/${totalSteps}: ${step.tool} (params: ${JSON.stringify(step.params)})`)\n }\n console.log('')\n console.log('Cost: unknown (MCP pricing not available without live connection)')\n return\n }\n\n // --- MCP AUTH CHECK (before case creation to avoid orphan cases) ---\n const config = await loadConfig()\n const mcpFetch = await createConfiguredMcpFetch(config)\n\n // --- CASE RESOLUTION ---\n let caseId: string\n if (opts.caseId) {\n const existingCase = await CaseStore.get(opts.caseId)\n caseId = existingCase.id\n } else {\n const newCase = await CaseStore.create({\n name: `quick-${playbook.name}-${Date.now()}`,\n tags: ['quick', 'playbook', playbook.name],\n description: `Auto-created for one-off playbook run: ${playbook.name}`,\n })\n caseId = newCase.id\n console.log(`Created quick case: ${caseId}`)\n }\n\n // --- MCP CONNECTION ---\n const client = new Client({ name: 'chain-insights-playbook', version: PACKAGE_VERSION })\n await client.connect(\n new StreamableHTTPClientTransport(new URL(config.mcpEndpoint), { fetch: mcpFetch })\n )\n\n let evidenceCount = 0\n\n try {\n await validateStepTools(client, stepsToRun)\n\n // --- STEP LOOP ---\n for (const step of stepsToRun) {\n console.log(`Step ${step.index}/${totalSteps}: ${step.label}...`)\n\n let result: string\n try {\n result = await callWithRetry(client, step.tool, step.params)\n } catch (err) {\n if (isPaymentError(err)) {\n if (process.stdin.isTTY) {\n // Interactive: prompt user\n const { createInterface } = await import('node:readline')\n const rl = createInterface({ input: process.stdin, output: process.stdout })\n const answer = await new Promise<string>(resolve => {\n rl.question(`Payment required for step ${step.index}. (retry/skip/abort): `, resolve)\n })\n rl.close()\n\n if (answer.trim().toLowerCase() === 'retry') {\n result = await callWithRetry(client, step.tool, step.params)\n } else if (answer.trim().toLowerCase() === 'skip') {\n console.log(`Step ${step.index} skipped.`)\n continue\n } else {\n throw new Error(`Aborted at step ${step.index} due to payment failure.`)\n }\n } else {\n // Non-TTY: abort\n throw new Error(\n `Payment required for step ${step.index} but no interactive terminal available. ` +\n `Configure wallet with \\`chain-insights config set walletPrivateKey <key>\\`. Aborting.`\n )\n }\n } else {\n // Non-payment, non-timeout MCP error — stop and report\n const completedSteps = step.index - 1 - startIndex\n const completedMsg = completedSteps > 0\n ? `Completed: steps ${startIndex + 1}..${step.index - 1}.`\n : 'No steps completed before failure.'\n console.error(\n `Step ${step.index} failed: ${(err as Error).message}. ` +\n `${completedMsg} Run with --from ${step.index} to resume.`\n )\n throw err\n }\n }\n\n // --- STORE EVIDENCE ---\n await EvidenceStore.append(caseId, {\n source: step.tool,\n content: result,\n queryParams: JSON.stringify(step.params),\n })\n evidenceCount++\n console.log(` (${result.length} chars stored)`)\n }\n\n // --- AUTO-VIZ for trace-funds ---\n if (playbook.name === 'trace-funds') {\n try {\n const viz = await generateVisualization({ caseId })\n console.log(`Visualization generated: ${viz.htmlPath}`)\n } catch {\n console.log('No transaction data to visualize.')\n }\n }\n\n // --- FINAL SUMMARY ---\n console.log(`Playbook complete. Case: ${caseId}. Evidence: ${evidenceCount} entries.`)\n } finally {\n await client.close()\n }\n },\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"runner-BBH5Ks6q.mjs","names":[],"sources":["../src/playbooks/runner.ts"],"sourcesContent":["import { Client } from '@modelcontextprotocol/sdk/client/index.js'\nimport { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js'\nimport { CaseStore } from '../cases/store.js'\nimport { EvidenceStore } from '../cases/evidence.js'\nimport { loadConfig } from '../config/index.js'\nimport { createConfiguredMcpFetch } from '../mcp/client.js'\nimport { generateVisualization } from '../viz/index.js'\nimport { PACKAGE_VERSION } from '../version.js'\nimport type { PlaybookDefinition } from './schema.js'\n\nexport interface RunnerOptions {\n caseId?: string // attach to existing case; omit for quick-case auto-creation\n from?: number // 1-based step to resume from (default: 1)\n dryRun?: boolean // print steps, no MCP calls\n params?: Record<string, string>\n}\n\n/** Sleep for ms milliseconds. */\nfunction sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms))\n}\n\n/** Check if an error is a timeout/abort error. */\nfunction isTimeoutError(err: unknown): boolean {\n if (!(err instanceof Error)) return false\n return err.name === 'AbortError' || (err as NodeJS.ErrnoException).code === 'ECONNRESET'\n}\n\n/** Check if an error is a payment failure. */\nfunction isPaymentError(err: unknown): boolean {\n if (!(err instanceof Error)) return false\n const msg = err.message.toLowerCase()\n // Match HTTP 402 status more precisely, or x402-specific error signals\n return msg.includes('http 402') ||\n msg.includes('status 402') ||\n msg.includes('payment required') ||\n msg.includes('x402')\n}\n\n/**\n * Call an MCP tool with retry logic on timeout (up to 3 total attempts).\n * Returns the text result or throws on non-retryable error.\n */\nasync function callWithRetry(\n client: Client,\n toolName: string,\n params: Record<string, string>\n): Promise<string> {\n const MAX_ATTEMPTS = 3\n let lastErr: unknown\n\n for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {\n try {\n const result = await client.callTool({ name: toolName, arguments: params })\n const content = result.content as Array<{ type: string; text?: string }>\n return content.filter(c => c.type === 'text').map(c => c.text ?? '').join('\\n')\n } catch (err) {\n if (isTimeoutError(err) && attempt < MAX_ATTEMPTS) {\n lastErr = err\n await sleep(1000)\n continue\n }\n throw err\n }\n }\n\n throw lastErr\n}\n\nasync function validateStepTools(client: Client, steps: PlaybookDefinition['steps']): Promise<void> {\n const result = await client.listTools()\n const available = new Set(result.tools.map(tool => tool.name))\n const missing = [...new Set(steps.map(step => step.tool).filter(tool => !available.has(tool)))]\n if (missing.length === 0) return\n\n const availableList = [...available].sort().join(', ') || 'none'\n throw new Error(\n `Unknown MCP tool(s) in playbook: ${missing.join(', ')}. ` +\n `Available tools: ${availableList}. Run \\`chain-insights mcp tools --refresh\\` to inspect the live MCP schema.`\n )\n}\n\nexport const PlaybookRunner = {\n /**\n * Execute a playbook definition step-by-step against the live MCP.\n *\n * @param playbook - Parsed and validated PlaybookDefinition\n * @param opts - Runner options (caseId, from, dryRun, params)\n */\n async run(playbook: PlaybookDefinition, opts: RunnerOptions): Promise<void> {\n const startIndex = (opts.from ?? 1) - 1 // convert 1-based to 0-based\n const stepsToRun = playbook.steps.slice(startIndex)\n const totalSteps = playbook.steps.length\n\n // --- DRY RUN ---\n if (opts.dryRun) {\n console.log(`Playbook: ${playbook.name} (dry run — no MCP calls)`)\n console.log(`Steps: ${totalSteps} total, starting from ${startIndex + 1}`)\n console.log('')\n for (const step of stepsToRun) {\n console.log(`Step ${step.index}/${totalSteps}: ${step.tool} (params: ${JSON.stringify(step.params)})`)\n }\n console.log('')\n console.log('Cost: unknown (MCP pricing not available without live connection)')\n return\n }\n\n // --- MCP AUTH CHECK (before case creation to avoid orphan cases) ---\n const config = await loadConfig()\n const mcpFetch = await createConfiguredMcpFetch(config)\n\n // --- CASE RESOLUTION ---\n let caseId: string\n if (opts.caseId) {\n const existingCase = await CaseStore.get(opts.caseId)\n caseId = existingCase.id\n } else {\n const newCase = await CaseStore.create({\n name: `quick-${playbook.name}-${Date.now()}`,\n tags: ['quick', 'playbook', playbook.name],\n description: `Auto-created for one-off playbook run: ${playbook.name}`,\n })\n caseId = newCase.id\n console.log(`Created quick case: ${caseId}`)\n }\n\n // --- MCP CONNECTION ---\n const client = new Client({ name: 'chain-insights-playbook', version: PACKAGE_VERSION })\n await client.connect(\n new StreamableHTTPClientTransport(new URL(config.mcpEndpoint), { fetch: mcpFetch })\n )\n\n let evidenceCount = 0\n\n try {\n await validateStepTools(client, stepsToRun)\n\n // --- STEP LOOP ---\n for (const step of stepsToRun) {\n console.log(`Step ${step.index}/${totalSteps}: ${step.label}...`)\n\n let result: string\n try {\n result = await callWithRetry(client, step.tool, step.params)\n } catch (err) {\n if (isPaymentError(err)) {\n if (process.stdin.isTTY) {\n // Interactive: prompt user\n const { createInterface } = await import('node:readline')\n const rl = createInterface({ input: process.stdin, output: process.stdout })\n const answer = await new Promise<string>(resolve => {\n rl.question(`Payment required for step ${step.index}. (retry/skip/abort): `, resolve)\n })\n rl.close()\n\n if (answer.trim().toLowerCase() === 'retry') {\n result = await callWithRetry(client, step.tool, step.params)\n } else if (answer.trim().toLowerCase() === 'skip') {\n console.log(`Step ${step.index} skipped.`)\n continue\n } else {\n throw new Error(`Aborted at step ${step.index} due to payment failure.`)\n }\n } else {\n // Non-TTY: abort\n throw new Error(\n `Payment required for step ${step.index} but no interactive terminal available. ` +\n `Configure wallet with \\`chain-insights config set walletPrivateKey <key>\\`. Aborting.`\n )\n }\n } else {\n // Non-payment, non-timeout MCP error — stop and report\n const completedSteps = step.index - 1 - startIndex\n const completedMsg = completedSteps > 0\n ? `Completed: steps ${startIndex + 1}..${step.index - 1}.`\n : 'No steps completed before failure.'\n console.error(\n `Step ${step.index} failed: ${(err as Error).message}. ` +\n `${completedMsg} Run with --from ${step.index} to resume.`\n )\n throw err\n }\n }\n\n // --- STORE EVIDENCE ---\n await EvidenceStore.append(caseId, {\n source: step.tool,\n content: result,\n queryParams: JSON.stringify(step.params),\n })\n evidenceCount++\n console.log(` (${result.length} chars stored)`)\n }\n\n // --- AUTO-VIZ for trace-funds ---\n if (playbook.name === 'trace-funds') {\n try {\n const viz = await generateVisualization({ caseId })\n console.log(`Visualization generated: ${viz.htmlPath}`)\n } catch {\n console.log('No transaction data to visualize.')\n }\n }\n\n // --- FINAL SUMMARY ---\n console.log(`Playbook complete. Case: ${caseId}. Evidence: ${evidenceCount} entries.`)\n } finally {\n await client.close()\n }\n },\n}\n"],"mappings":";;;;;;;;;;AAkBA,SAAS,MAAM,IAA2B;CACxC,OAAO,IAAI,SAAQ,YAAW,WAAW,SAAS,EAAE,CAAC;AACvD;;AAGA,SAAS,eAAe,KAAuB;CAC7C,IAAI,EAAE,eAAe,QAAQ,OAAO;CACpC,OAAO,IAAI,SAAS,gBAAiB,IAA8B,SAAS;AAC9E;;AAGA,SAAS,eAAe,KAAuB;CAC7C,IAAI,EAAE,eAAe,QAAQ,OAAO;CACpC,MAAM,MAAM,IAAI,QAAQ,YAAY;CAEpC,OAAO,IAAI,SAAS,UAAU,KACvB,IAAI,SAAS,YAAY,KACzB,IAAI,SAAS,kBAAkB,KAC/B,IAAI,SAAS,MAAM;AAC5B;;;;;AAMA,eAAe,cACb,QACA,UACA,QACiB;CACjB,MAAM,eAAe;CACrB,IAAI;CAEJ,KAAK,IAAI,UAAU,GAAG,WAAW,cAAc,WAC7C,IAAI;EAGF,QADgB,MADK,OAAO,SAAS;GAAE,MAAM;GAAU,WAAW;EAAO,CAAC,GACnD,QACR,QAAO,MAAK,EAAE,SAAS,MAAM,EAAE,KAAI,MAAK,EAAE,QAAQ,EAAE,EAAE,KAAK,IAAI;CAChF,SAAS,KAAK;EACZ,IAAI,eAAe,GAAG,KAAK,UAAU,cAAc;GACjD,UAAU;GACV,MAAM,MAAM,GAAI;GAChB;EACF;EACA,MAAM;CACR;CAGF,MAAM;AACR;AAEA,eAAe,kBAAkB,QAAgB,OAAmD;CAClG,MAAM,SAAS,MAAM,OAAO,UAAU;CACtC,MAAM,YAAY,IAAI,IAAI,OAAO,MAAM,KAAI,SAAQ,KAAK,IAAI,CAAC;CAC7D,MAAM,UAAU,CAAC,GAAG,IAAI,IAAI,MAAM,KAAI,SAAQ,KAAK,IAAI,EAAE,QAAO,SAAQ,CAAC,UAAU,IAAI,IAAI,CAAC,CAAC,CAAC;CAC9F,IAAI,QAAQ,WAAW,GAAG;CAE1B,MAAM,gBAAgB,CAAC,GAAG,SAAS,EAAE,KAAK,EAAE,KAAK,IAAI,KAAK;CAC1D,MAAM,IAAI,MACR,oCAAoC,QAAQ,KAAK,IAAI,EAAE,qBACnC,cAAc,6EACpC;AACF;AAEA,MAAa,iBAAiB;;;;;;;AAO5B,MAAM,IAAI,UAA8B,MAAoC;CAC1E,MAAM,cAAc,KAAK,QAAQ,KAAK;CACtC,MAAM,aAAa,SAAS,MAAM,MAAM,UAAU;CAClD,MAAM,aAAa,SAAS,MAAM;CAGlC,IAAI,KAAK,QAAQ;EACf,QAAQ,IAAI,aAAa,SAAS,KAAK,0BAA0B;EACjE,QAAQ,IAAI,UAAU,WAAW,wBAAwB,aAAa,GAAG;EACzE,QAAQ,IAAI,EAAE;EACd,KAAK,MAAM,QAAQ,YACjB,QAAQ,IAAI,QAAQ,KAAK,MAAM,GAAG,WAAW,IAAI,KAAK,KAAK,YAAY,KAAK,UAAU,KAAK,MAAM,EAAE,EAAE;EAEvG,QAAQ,IAAI,EAAE;EACd,QAAQ,IAAI,mEAAmE;EAC/E;CACF;CAGA,MAAM,SAAS,MAAM,WAAW;CAChC,MAAM,WAAW,MAAM,yBAAyB,MAAM;CAGtD,IAAI;CACJ,IAAI,KAAK,QAEP,UAAS,MADkB,UAAU,IAAI,KAAK,MAAM,GAC9B;MACjB;EAML,UAAS,MALa,UAAU,OAAO;GACrC,MAAM,SAAS,SAAS,KAAK,GAAG,KAAK,IAAI;GACzC,MAAM;IAAC;IAAS;IAAY,SAAS;GAAI;GACzC,aAAa,0CAA0C,SAAS;EAClE,CAAC,GACgB;EACjB,QAAQ,IAAI,uBAAuB,QAAQ;CAC7C;CAGA,MAAM,SAAS,IAAI,OAAO;EAAE,MAAM;EAA2B,SAAS;CAAgB,CAAC;CACvF,MAAM,OAAO,QACX,IAAI,8BAA8B,IAAI,IAAI,OAAO,WAAW,GAAG,EAAE,OAAO,SAAS,CAAC,CACpF;CAEA,IAAI,gBAAgB;CAEpB,IAAI;EACF,MAAM,kBAAkB,QAAQ,UAAU;EAG1C,KAAK,MAAM,QAAQ,YAAY;GAC7B,QAAQ,IAAI,QAAQ,KAAK,MAAM,GAAG,WAAW,IAAI,KAAK,MAAM,IAAI;GAEhE,IAAI;GACJ,IAAI;IACF,SAAS,MAAM,cAAc,QAAQ,KAAK,MAAM,KAAK,MAAM;GAC7D,SAAS,KAAK;IACZ,IAAI,eAAe,GAAG,GACpB,IAAI,QAAQ,MAAM,OAAO;KAEvB,MAAM,EAAE,oBAAoB,MAAM,OAAO;KACzC,MAAM,KAAK,gBAAgB;MAAE,OAAO,QAAQ;MAAO,QAAQ,QAAQ;KAAO,CAAC;KAC3E,MAAM,SAAS,MAAM,IAAI,SAAgB,YAAW;MAClD,GAAG,SAAS,6BAA6B,KAAK,MAAM,yBAAyB,OAAO;KACtF,CAAC;KACD,GAAG,MAAM;KAET,IAAI,OAAO,KAAK,EAAE,YAAY,MAAM,SAClC,SAAS,MAAM,cAAc,QAAQ,KAAK,MAAM,KAAK,MAAM;UACtD,IAAI,OAAO,KAAK,EAAE,YAAY,MAAM,QAAQ;MACjD,QAAQ,IAAI,QAAQ,KAAK,MAAM,UAAU;MACzC;KACF,OACE,MAAM,IAAI,MAAM,mBAAmB,KAAK,MAAM,yBAAyB;IAE3E,OAEE,MAAM,IAAI,MACR,6BAA6B,KAAK,MAAM,8HAE1C;SAEG;KAGL,MAAM,eADiB,KAAK,QAAQ,IAAI,aACF,IAClC,oBAAoB,aAAa,EAAE,IAAI,KAAK,QAAQ,EAAE,KACtD;KACJ,QAAQ,MACN,QAAQ,KAAK,MAAM,WAAY,IAAc,QAAQ,IAClD,aAAa,mBAAmB,KAAK,MAAM,YAChD;KACA,MAAM;IACR;GACF;GAGA,MAAM,cAAc,OAAO,QAAQ;IACjC,QAAQ,KAAK;IACb,SAAS;IACT,aAAa,KAAK,UAAU,KAAK,MAAM;GACzC,CAAC;GACD;GACA,QAAQ,IAAI,MAAM,OAAO,OAAO,eAAe;EACjD;EAGA,IAAI,SAAS,SAAS,eACpB,IAAI;GACF,MAAM,MAAM,MAAM,sBAAsB,EAAE,OAAO,CAAC;GAClD,QAAQ,IAAI,4BAA4B,IAAI,UAAU;EACxD,QAAQ;GACN,QAAQ,IAAI,mCAAmC;EACjD;EAIF,QAAQ,IAAI,4BAA4B,OAAO,cAAc,cAAc,UAAU;CACvF,UAAU;EACR,MAAM,OAAO,MAAM;CACrB;AACF,EACF"}
@@ -1,6 +1,6 @@
1
1
  const require_version = require("./version-CO9Or_YV.cjs");
2
2
  const require_config = require("./config-BwVx19Og.cjs");
3
- const require_client = require("./client-DPc2eyVN.cjs");
3
+ const require_client = require("./client-BYnFGA0y.cjs");
4
4
  const require_viz = require("./viz-Da9YWN_I.cjs");
5
5
  const require_store = require("./store-DogLawSj.cjs");
6
6
  const require_evidence = require("./evidence-CvEesemA.cjs");
@@ -0,0 +1,298 @@
1
+ import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
2
+ import { i as normalizeWalletPrivateKey, t as decryptKey } from "./wallet-D8IqFRKY.mjs";
3
+ import { privateKeyToAccount } from "viem/accounts";
4
+ import { createPublicClient, createWalletClient, formatEther, formatUnits, http, parseUnits } from "viem";
5
+ import { base } from "viem/chains";
6
+ //#region src/wallet/tools.ts
7
+ var tools_exports = /* @__PURE__ */ __exportAll({
8
+ BASE_CHAIN_ID: () => BASE_CHAIN_ID,
9
+ DEFAULT_BASE_RPC_URL: () => DEFAULT_BASE_RPC_URL,
10
+ DEFAULT_PAYMENT_APPROVAL_UNITS: () => DEFAULT_PAYMENT_APPROVAL_UNITS,
11
+ PERMIT2_ADDRESS: () => PERMIT2_ADDRESS,
12
+ PUBLIC_BASE_RPC_URLS: () => PUBLIC_BASE_RPC_URLS,
13
+ USDC_ADDRESS: () => USDC_ADDRESS,
14
+ approvePaymentAllowance: () => approvePaymentAllowance,
15
+ buildTopupInfo: () => buildTopupInfo,
16
+ formatWalletBalance: () => formatWalletBalance,
17
+ formatWalletReadiness: () => formatWalletReadiness,
18
+ getBalanceEth: () => getBalanceEth,
19
+ getBalanceUsdc: () => getBalanceUsdc,
20
+ getPaymentApprovalUnits: () => getPaymentApprovalUnits,
21
+ getWalletAccount: () => getWalletAccount,
22
+ getWalletBalanceText: () => getWalletBalanceText,
23
+ getWalletReadiness: () => getWalletReadiness,
24
+ parsePaymentApprovalUnits: () => parsePaymentApprovalUnits,
25
+ prepareWalletForPaidCalls: () => prepareWalletForPaidCalls
26
+ });
27
+ const BASE_CHAIN_ID = 8453;
28
+ const USDC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
29
+ const PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
30
+ const DEFAULT_BASE_RPC_URL = "https://mainnet.base.org";
31
+ const DEFAULT_PAYMENT_APPROVAL_UNITS = 1000000n;
32
+ const PUBLIC_BASE_RPC_URLS = [
33
+ DEFAULT_BASE_RPC_URL,
34
+ "https://base-rpc.publicnode.com",
35
+ "https://base.drpc.org",
36
+ "https://1rpc.io/base"
37
+ ];
38
+ const USDC_ABI = [
39
+ {
40
+ type: "function",
41
+ name: "balanceOf",
42
+ stateMutability: "view",
43
+ inputs: [{
44
+ name: "account",
45
+ type: "address"
46
+ }],
47
+ outputs: [{
48
+ name: "",
49
+ type: "uint256"
50
+ }]
51
+ },
52
+ {
53
+ type: "function",
54
+ name: "allowance",
55
+ stateMutability: "view",
56
+ inputs: [{
57
+ name: "owner",
58
+ type: "address"
59
+ }, {
60
+ name: "spender",
61
+ type: "address"
62
+ }],
63
+ outputs: [{
64
+ name: "",
65
+ type: "uint256"
66
+ }]
67
+ },
68
+ {
69
+ type: "function",
70
+ name: "approve",
71
+ stateMutability: "nonpayable",
72
+ inputs: [{
73
+ name: "spender",
74
+ type: "address"
75
+ }, {
76
+ name: "amount",
77
+ type: "uint256"
78
+ }],
79
+ outputs: [{
80
+ name: "",
81
+ type: "bool"
82
+ }]
83
+ }
84
+ ];
85
+ async function getWalletAccount() {
86
+ const privateKey = normalizeWalletPrivateKey(await decryptKey());
87
+ return {
88
+ address: privateKeyToAccount(privateKey).address,
89
+ privateKey
90
+ };
91
+ }
92
+ function baseRpcUrls(rpcUrl = process.env["BASE_RPC_URL"]) {
93
+ return [...rpcUrl ? [rpcUrl] : [], ...PUBLIC_BASE_RPC_URLS.filter((fallbackUrl) => fallbackUrl !== rpcUrl)];
94
+ }
95
+ async function getBalanceUsdc(address, rpcUrl = process.env["BASE_RPC_URL"]) {
96
+ for (const url of baseRpcUrls(rpcUrl)) try {
97
+ return formatUnits(await createPublicClient({
98
+ chain: base,
99
+ transport: http(url)
100
+ }).readContract({
101
+ address: USDC_ADDRESS,
102
+ abi: USDC_ABI,
103
+ functionName: "balanceOf",
104
+ args: [address]
105
+ }), 6);
106
+ } catch {}
107
+ return "unknown";
108
+ }
109
+ async function getBalanceEth(address, rpcUrl = process.env["BASE_RPC_URL"]) {
110
+ for (const url of baseRpcUrls(rpcUrl)) try {
111
+ return formatEther(await createPublicClient({
112
+ chain: base,
113
+ transport: http(url)
114
+ }).getBalance({ address }));
115
+ } catch {}
116
+ return "unknown";
117
+ }
118
+ async function getPaymentApprovalUnits(address, rpcUrl = process.env["BASE_RPC_URL"]) {
119
+ for (const url of baseRpcUrls(rpcUrl)) try {
120
+ return await createPublicClient({
121
+ chain: base,
122
+ transport: http(url)
123
+ }).readContract({
124
+ address: USDC_ADDRESS,
125
+ abi: USDC_ABI,
126
+ functionName: "allowance",
127
+ args: [address, PERMIT2_ADDRESS]
128
+ });
129
+ } catch {}
130
+ return null;
131
+ }
132
+ function parsePaymentApprovalUnits(amountUsdc) {
133
+ const trimmed = amountUsdc.trim();
134
+ if (!/^\d+(\.\d{1,6})?$/.test(trimmed) || !isPositiveDecimal(trimmed)) throw new Error("Approval amount must be a positive USDC value with up to 6 decimals.");
135
+ return parseUnits(trimmed, 6);
136
+ }
137
+ function isPositiveDecimal(value) {
138
+ if (value === "unknown") return false;
139
+ const parsed = Number.parseFloat(value);
140
+ return Number.isFinite(parsed) && parsed > 0;
141
+ }
142
+ function decimalStatus(value) {
143
+ return value === "unknown" ? null : isPositiveDecimal(value);
144
+ }
145
+ function readinessNextSteps(readiness) {
146
+ const nextSteps = [];
147
+ if (readiness.hasUsdc === false) nextSteps.push("Run `chain-insights wallet topup` and send USDC on Base to this wallet.");
148
+ if (readiness.hasUsdc === null) nextSteps.push("Base USDC balance could not be confirmed; retry or set BASE_RPC_URL to a working Base RPC endpoint.");
149
+ if (readiness.needsPaymentApproval && readiness.hasGas === false) nextSteps.push("Add a small amount of ETH on Base for the one-time payment setup gas.");
150
+ if (readiness.needsPaymentApproval && readiness.hasGas !== false) nextSteps.push("Run `chain-insights wallet ready` to finish the one-time payment setup.");
151
+ if (readiness.hasGas === null) nextSteps.push("Base ETH gas balance could not be confirmed; retry or set BASE_RPC_URL to a working Base RPC endpoint.");
152
+ return nextSteps;
153
+ }
154
+ function buildWalletReadiness(params) {
155
+ const paymentApprovalUnits = params.paymentApprovalUnits ?? 0n;
156
+ const hasUsdc = decimalStatus(params.balanceUsdc);
157
+ const hasGas = decimalStatus(params.balanceEth);
158
+ const hasPaymentApproval = paymentApprovalUnits >= params.minimumApprovalUnits;
159
+ const needsPaymentApproval = !hasPaymentApproval;
160
+ const ready = hasUsdc !== false && hasPaymentApproval;
161
+ const readiness = {
162
+ address: params.address,
163
+ balanceUsdc: params.balanceUsdc,
164
+ balanceEth: params.balanceEth,
165
+ paymentApprovalUsdc: params.paymentApprovalUnits === null ? "unknown" : formatUnits(paymentApprovalUnits, 6),
166
+ paymentApprovalUnits,
167
+ minimumApprovalUnits: params.minimumApprovalUnits,
168
+ hasUsdc,
169
+ hasGas,
170
+ hasPaymentApproval,
171
+ needsPaymentApproval,
172
+ ready,
173
+ nextSteps: []
174
+ };
175
+ return {
176
+ ...readiness,
177
+ nextSteps: readinessNextSteps(readiness)
178
+ };
179
+ }
180
+ async function getWalletReadiness(account, minimumApprovalUnits = DEFAULT_PAYMENT_APPROVAL_UNITS) {
181
+ const wallet = account ?? await getWalletAccount();
182
+ const [balanceUsdc, balanceEth, paymentApprovalUnits] = await Promise.all([
183
+ getBalanceUsdc(wallet.address),
184
+ getBalanceEth(wallet.address),
185
+ getPaymentApprovalUnits(wallet.address)
186
+ ]);
187
+ return buildWalletReadiness({
188
+ address: wallet.address,
189
+ balanceUsdc,
190
+ balanceEth,
191
+ paymentApprovalUnits,
192
+ minimumApprovalUnits
193
+ });
194
+ }
195
+ function formatWalletReadiness(readiness, approval) {
196
+ const status = readiness.ready ? "Ready for paid GraphRAG MCP calls" : "Action needed before paid GraphRAG MCP calls";
197
+ const setup = readiness.needsPaymentApproval ? `Payment setup: needs one-time approval (${readiness.paymentApprovalUsdc} / ${formatUnits(readiness.minimumApprovalUnits, 6)} USDC cap)` : `Payment setup: ready (${readiness.paymentApprovalUsdc} USDC cap)`;
198
+ const approvalLine = approval?.status === "approved" ? `Approval transaction: ${approval.txHash}` : void 0;
199
+ return [
200
+ status,
201
+ `Balance: ${readiness.balanceUsdc} USDC`,
202
+ `Gas: ${readiness.balanceEth} ETH on Base`,
203
+ setup,
204
+ approvalLine,
205
+ "Network: Base",
206
+ `Address: ${readiness.address}`,
207
+ ...readiness.nextSteps.map((step) => `Next: ${step}`)
208
+ ].filter(Boolean).join("\n");
209
+ }
210
+ async function approvePaymentAllowance(account, minimumApprovalUnits = DEFAULT_PAYMENT_APPROVAL_UNITS, rpcUrl = process.env["BASE_RPC_URL"]) {
211
+ const wallet = account ?? await getWalletAccount();
212
+ const initialApprovalUnits = await getPaymentApprovalUnits(wallet.address, rpcUrl);
213
+ if (initialApprovalUnits !== null && initialApprovalUnits >= minimumApprovalUnits) return {
214
+ status: "already_ready",
215
+ paymentApprovalUnits: initialApprovalUnits,
216
+ minimumApprovalUnits
217
+ };
218
+ const clientAccount = privateKeyToAccount(wallet.privateKey);
219
+ for (const url of baseRpcUrls(rpcUrl)) try {
220
+ const publicClient = createPublicClient({
221
+ chain: base,
222
+ transport: http(url)
223
+ });
224
+ const txHash = await createWalletClient({
225
+ account: clientAccount,
226
+ chain: base,
227
+ transport: http(url)
228
+ }).writeContract({
229
+ address: USDC_ADDRESS,
230
+ abi: USDC_ABI,
231
+ functionName: "approve",
232
+ args: [PERMIT2_ADDRESS, minimumApprovalUnits]
233
+ });
234
+ if ((await publicClient.waitForTransactionReceipt({ hash: txHash })).status === "reverted") throw new Error(`Payment setup transaction reverted: ${txHash}`);
235
+ return {
236
+ status: "approved",
237
+ txHash,
238
+ paymentApprovalUnits: await getPaymentApprovalUnits(wallet.address, url) ?? minimumApprovalUnits,
239
+ minimumApprovalUnits
240
+ };
241
+ } catch (err) {
242
+ if (url === baseRpcUrls(rpcUrl).at(-1)) throw err;
243
+ }
244
+ throw new Error("Unable to submit payment setup transaction on Base.");
245
+ }
246
+ async function prepareWalletForPaidCalls(options = {}) {
247
+ const minimumApprovalUnits = options.minimumApprovalUnits ?? 1000000n;
248
+ const wallet = options.account ?? await getWalletAccount();
249
+ const readiness = await getWalletReadiness(wallet, minimumApprovalUnits);
250
+ if (!readiness.needsPaymentApproval) return {
251
+ readiness,
252
+ approval: {
253
+ status: "already_ready",
254
+ paymentApprovalUnits: readiness.paymentApprovalUnits,
255
+ minimumApprovalUnits
256
+ }
257
+ };
258
+ if (options.approve === false || readiness.hasGas === false) return { readiness };
259
+ const approval = await approvePaymentAllowance(wallet, minimumApprovalUnits, options.rpcUrl);
260
+ return {
261
+ readiness: buildWalletReadiness({
262
+ address: wallet.address,
263
+ balanceUsdc: readiness.balanceUsdc,
264
+ balanceEth: readiness.balanceEth,
265
+ paymentApprovalUnits: approval.paymentApprovalUnits,
266
+ minimumApprovalUnits
267
+ }),
268
+ approval
269
+ };
270
+ }
271
+ function formatWalletBalance(address, balanceUsdc, balanceEth) {
272
+ return [
273
+ `Balance: ${balanceUsdc} USDC`,
274
+ balanceEth === void 0 ? void 0 : `Gas: ${balanceEth} ETH on Base`,
275
+ "Network: Base",
276
+ "Base ETH is required only for one-time payment approval gas.",
277
+ `Address: ${address}`
278
+ ].filter(Boolean).join("\n");
279
+ }
280
+ async function getWalletBalanceText(account) {
281
+ const wallet = account ?? await getWalletAccount();
282
+ const [balanceUsdc, balanceEth] = await Promise.all([getBalanceUsdc(wallet.address), getBalanceEth(wallet.address)]);
283
+ return formatWalletBalance(wallet.address, balanceUsdc, balanceEth);
284
+ }
285
+ function buildTopupInfo(address, topupUrl) {
286
+ return {
287
+ wallet_address: address,
288
+ network: "Base",
289
+ chain_id: BASE_CHAIN_ID,
290
+ token: "USDC",
291
+ token_contract: USDC_ADDRESS,
292
+ ...topupUrl ? { topup_url: topupUrl } : {}
293
+ };
294
+ }
295
+ //#endregion
296
+ export { getWalletAccount as a, tools_exports as c, getBalanceUsdc as i, formatWalletBalance as n, getWalletBalanceText as o, getBalanceEth as r, prepareWalletForPaidCalls as s, buildTopupInfo as t };
297
+
298
+ //# sourceMappingURL=tools-D6RBAhSX.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools-D6RBAhSX.mjs","names":[],"sources":["../src/wallet/tools.ts"],"sourcesContent":["import { createPublicClient, createWalletClient, formatEther, formatUnits, http, parseUnits, type Address, type Hex } from 'viem'\nimport { base } from 'viem/chains'\nimport { privateKeyToAccount } from 'viem/accounts'\nimport { decryptKey, normalizeWalletPrivateKey } from './index.js'\n\nexport const BASE_CHAIN_ID = 8453\nexport const USDC_ADDRESS = '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913' as const\nexport const PERMIT2_ADDRESS = '0x000000000022D473030F116dDEE9F6B43aC78BA3' as const\nexport const DEFAULT_BASE_RPC_URL = 'https://mainnet.base.org'\nexport const DEFAULT_PAYMENT_APPROVAL_UNITS = 1_000_000n\nexport const PUBLIC_BASE_RPC_URLS = [\n DEFAULT_BASE_RPC_URL,\n 'https://base-rpc.publicnode.com',\n 'https://base.drpc.org',\n 'https://1rpc.io/base',\n] as const\n\nconst USDC_ABI = [\n {\n type: 'function',\n name: 'balanceOf',\n stateMutability: 'view',\n inputs: [{ name: 'account', type: 'address' }],\n outputs: [{ name: '', type: 'uint256' }],\n },\n {\n type: 'function',\n name: 'allowance',\n stateMutability: 'view',\n inputs: [\n { name: 'owner', type: 'address' },\n { name: 'spender', type: 'address' },\n ],\n outputs: [{ name: '', type: 'uint256' }],\n },\n {\n type: 'function',\n name: 'approve',\n stateMutability: 'nonpayable',\n inputs: [\n { name: 'spender', type: 'address' },\n { name: 'amount', type: 'uint256' },\n ],\n outputs: [{ name: '', type: 'bool' }],\n },\n] as const\n\nexport interface PaymentWalletAccount {\n address: Address\n privateKey: Hex\n}\n\nexport interface TopupInfo {\n wallet_address: string\n network: 'Base'\n chain_id: typeof BASE_CHAIN_ID\n token: 'USDC'\n token_contract: typeof USDC_ADDRESS\n topup_url?: string\n}\n\nexport interface WalletReadiness {\n address: Address\n balanceUsdc: string\n balanceEth: string\n paymentApprovalUsdc: string\n paymentApprovalUnits: bigint\n minimumApprovalUnits: bigint\n hasUsdc: boolean | null\n hasGas: boolean | null\n hasPaymentApproval: boolean\n needsPaymentApproval: boolean\n ready: boolean\n nextSteps: string[]\n}\n\nexport interface PaymentApprovalResult {\n status: 'already_ready' | 'approved'\n txHash?: Hex\n paymentApprovalUnits: bigint\n minimumApprovalUnits: bigint\n}\n\nexport interface PrepareWalletResult {\n readiness: WalletReadiness\n approval?: PaymentApprovalResult\n}\n\nexport interface PrepareWalletOptions {\n account?: PaymentWalletAccount\n minimumApprovalUnits?: bigint\n approve?: boolean\n rpcUrl?: string\n}\n\nexport async function getWalletAccount(): Promise<PaymentWalletAccount> {\n const privateKey = normalizeWalletPrivateKey(await decryptKey()) as Hex\n const account = privateKeyToAccount(privateKey)\n return { address: account.address, privateKey }\n}\n\nfunction baseRpcUrls(rpcUrl = process.env['BASE_RPC_URL']): string[] {\n return [\n ...(rpcUrl ? [rpcUrl] : []),\n ...PUBLIC_BASE_RPC_URLS.filter((fallbackUrl) => fallbackUrl !== rpcUrl),\n ]\n}\n\nexport async function getBalanceUsdc(\n address: Address | string,\n rpcUrl = process.env['BASE_RPC_URL'],\n): Promise<string> {\n for (const url of baseRpcUrls(rpcUrl)) {\n try {\n const client = createPublicClient({\n chain: base,\n transport: http(url),\n })\n const balance = await client.readContract({\n address: USDC_ADDRESS,\n abi: USDC_ABI,\n functionName: 'balanceOf',\n args: [address as Address],\n })\n return formatUnits(balance, 6)\n } catch {\n // Try the next public Base RPC endpoint.\n }\n }\n\n return 'unknown'\n}\n\nexport async function getBalanceEth(\n address: Address | string,\n rpcUrl = process.env['BASE_RPC_URL'],\n): Promise<string> {\n for (const url of baseRpcUrls(rpcUrl)) {\n try {\n const client = createPublicClient({\n chain: base,\n transport: http(url),\n })\n const balance = await client.getBalance({ address: address as Address })\n return formatEther(balance)\n } catch {\n // Try the next public Base RPC endpoint.\n }\n }\n\n return 'unknown'\n}\n\nexport async function getPaymentApprovalUnits(\n address: Address | string,\n rpcUrl = process.env['BASE_RPC_URL'],\n): Promise<bigint | null> {\n for (const url of baseRpcUrls(rpcUrl)) {\n try {\n const client = createPublicClient({\n chain: base,\n transport: http(url),\n })\n return await client.readContract({\n address: USDC_ADDRESS,\n abi: USDC_ABI,\n functionName: 'allowance',\n args: [address as Address, PERMIT2_ADDRESS],\n })\n } catch {\n // Try the next public Base RPC endpoint.\n }\n }\n\n return null\n}\n\nexport async function getPaymentApprovalUsdc(\n address: Address | string,\n rpcUrl = process.env['BASE_RPC_URL'],\n): Promise<string> {\n const allowance = await getPaymentApprovalUnits(address, rpcUrl)\n return allowance === null ? 'unknown' : formatUnits(allowance, 6)\n}\n\nexport function parsePaymentApprovalUnits(amountUsdc: string): bigint {\n const trimmed = amountUsdc.trim()\n if (!/^\\d+(\\.\\d{1,6})?$/.test(trimmed) || !isPositiveDecimal(trimmed)) {\n throw new Error('Approval amount must be a positive USDC value with up to 6 decimals.')\n }\n return parseUnits(trimmed, 6)\n}\n\nfunction isPositiveDecimal(value: string): boolean {\n if (value === 'unknown') return false\n const parsed = Number.parseFloat(value)\n return Number.isFinite(parsed) && parsed > 0\n}\n\nfunction decimalStatus(value: string): boolean | null {\n return value === 'unknown' ? null : isPositiveDecimal(value)\n}\n\nfunction readinessNextSteps(readiness: Pick<WalletReadiness, 'hasUsdc' | 'hasGas' | 'needsPaymentApproval'>): string[] {\n const nextSteps: string[] = []\n if (readiness.hasUsdc === false) {\n nextSteps.push('Run `chain-insights wallet topup` and send USDC on Base to this wallet.')\n }\n if (readiness.hasUsdc === null) {\n nextSteps.push('Base USDC balance could not be confirmed; retry or set BASE_RPC_URL to a working Base RPC endpoint.')\n }\n if (readiness.needsPaymentApproval && readiness.hasGas === false) {\n nextSteps.push('Add a small amount of ETH on Base for the one-time payment setup gas.')\n }\n if (readiness.needsPaymentApproval && readiness.hasGas !== false) {\n nextSteps.push('Run `chain-insights wallet ready` to finish the one-time payment setup.')\n }\n if (readiness.hasGas === null) {\n nextSteps.push('Base ETH gas balance could not be confirmed; retry or set BASE_RPC_URL to a working Base RPC endpoint.')\n }\n return nextSteps\n}\n\nfunction buildWalletReadiness(params: {\n address: Address\n balanceUsdc: string\n balanceEth: string\n paymentApprovalUnits: bigint | null\n minimumApprovalUnits: bigint\n}): WalletReadiness {\n const paymentApprovalUnits = params.paymentApprovalUnits ?? 0n\n const hasUsdc = decimalStatus(params.balanceUsdc)\n const hasGas = decimalStatus(params.balanceEth)\n const hasPaymentApproval = paymentApprovalUnits >= params.minimumApprovalUnits\n const needsPaymentApproval = !hasPaymentApproval\n const ready = hasUsdc !== false && hasPaymentApproval\n const readiness = {\n address: params.address,\n balanceUsdc: params.balanceUsdc,\n balanceEth: params.balanceEth,\n paymentApprovalUsdc: params.paymentApprovalUnits === null ? 'unknown' : formatUnits(paymentApprovalUnits, 6),\n paymentApprovalUnits,\n minimumApprovalUnits: params.minimumApprovalUnits,\n hasUsdc,\n hasGas,\n hasPaymentApproval,\n needsPaymentApproval,\n ready,\n nextSteps: [],\n }\n return {\n ...readiness,\n nextSteps: readinessNextSteps(readiness),\n }\n}\n\nexport async function getWalletReadiness(\n account?: PaymentWalletAccount,\n minimumApprovalUnits = DEFAULT_PAYMENT_APPROVAL_UNITS,\n): Promise<WalletReadiness> {\n const wallet = account ?? await getWalletAccount()\n const [balanceUsdc, balanceEth, paymentApprovalUnits] = await Promise.all([\n getBalanceUsdc(wallet.address),\n getBalanceEth(wallet.address),\n getPaymentApprovalUnits(wallet.address),\n ])\n return buildWalletReadiness({\n address: wallet.address,\n balanceUsdc,\n balanceEth,\n paymentApprovalUnits,\n minimumApprovalUnits,\n })\n}\n\nexport function formatWalletReadiness(readiness: WalletReadiness, approval?: PaymentApprovalResult): string {\n const status = readiness.ready ? 'Ready for paid GraphRAG MCP calls' : 'Action needed before paid GraphRAG MCP calls'\n const setup = readiness.needsPaymentApproval\n ? `Payment setup: needs one-time approval (${readiness.paymentApprovalUsdc} / ${formatUnits(readiness.minimumApprovalUnits, 6)} USDC cap)`\n : `Payment setup: ready (${readiness.paymentApprovalUsdc} USDC cap)`\n const approvalLine = approval?.status === 'approved'\n ? `Approval transaction: ${approval.txHash}`\n : undefined\n return [\n status,\n `Balance: ${readiness.balanceUsdc} USDC`,\n `Gas: ${readiness.balanceEth} ETH on Base`,\n setup,\n approvalLine,\n 'Network: Base',\n `Address: ${readiness.address}`,\n ...readiness.nextSteps.map((step) => `Next: ${step}`),\n ].filter(Boolean).join('\\n')\n}\n\nexport async function approvePaymentAllowance(\n account?: PaymentWalletAccount,\n minimumApprovalUnits = DEFAULT_PAYMENT_APPROVAL_UNITS,\n rpcUrl = process.env['BASE_RPC_URL'],\n): Promise<PaymentApprovalResult> {\n const wallet = account ?? await getWalletAccount()\n const initialApprovalUnits = await getPaymentApprovalUnits(wallet.address, rpcUrl)\n if (initialApprovalUnits !== null && initialApprovalUnits >= minimumApprovalUnits) {\n return {\n status: 'already_ready',\n paymentApprovalUnits: initialApprovalUnits,\n minimumApprovalUnits,\n }\n }\n\n const clientAccount = privateKeyToAccount(wallet.privateKey)\n for (const url of baseRpcUrls(rpcUrl)) {\n try {\n const publicClient = createPublicClient({ chain: base, transport: http(url) })\n const walletClient = createWalletClient({\n account: clientAccount,\n chain: base,\n transport: http(url),\n })\n const txHash = await walletClient.writeContract({\n address: USDC_ADDRESS,\n abi: USDC_ABI,\n functionName: 'approve',\n args: [PERMIT2_ADDRESS, minimumApprovalUnits],\n })\n const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash })\n if (receipt.status === 'reverted') {\n throw new Error(`Payment setup transaction reverted: ${txHash}`)\n }\n const paymentApprovalUnits = await getPaymentApprovalUnits(wallet.address, url)\n return {\n status: 'approved',\n txHash,\n paymentApprovalUnits: paymentApprovalUnits ?? minimumApprovalUnits,\n minimumApprovalUnits,\n }\n } catch (err) {\n if (url === baseRpcUrls(rpcUrl).at(-1)) throw err\n }\n }\n\n throw new Error('Unable to submit payment setup transaction on Base.')\n}\n\nexport async function prepareWalletForPaidCalls(options: PrepareWalletOptions = {}): Promise<PrepareWalletResult> {\n const minimumApprovalUnits = options.minimumApprovalUnits ?? DEFAULT_PAYMENT_APPROVAL_UNITS\n const wallet = options.account ?? await getWalletAccount()\n const readiness = await getWalletReadiness(wallet, minimumApprovalUnits)\n\n if (!readiness.needsPaymentApproval) {\n return {\n readiness,\n approval: {\n status: 'already_ready',\n paymentApprovalUnits: readiness.paymentApprovalUnits,\n minimumApprovalUnits,\n },\n }\n }\n if (options.approve === false || readiness.hasGas === false) {\n return { readiness }\n }\n\n const approval = await approvePaymentAllowance(wallet, minimumApprovalUnits, options.rpcUrl)\n const updatedReadiness = buildWalletReadiness({\n address: wallet.address,\n balanceUsdc: readiness.balanceUsdc,\n balanceEth: readiness.balanceEth,\n paymentApprovalUnits: approval.paymentApprovalUnits,\n minimumApprovalUnits,\n })\n return { readiness: updatedReadiness, approval }\n}\n\nexport function formatWalletBalance(address: string, balanceUsdc: string, balanceEth?: string): string {\n return [\n `Balance: ${balanceUsdc} USDC`,\n balanceEth === undefined ? undefined : `Gas: ${balanceEth} ETH on Base`,\n 'Network: Base',\n 'Base ETH is required only for one-time payment approval gas.',\n `Address: ${address}`,\n ].filter(Boolean).join('\\n')\n}\n\nexport async function getWalletBalanceText(account?: PaymentWalletAccount): Promise<string> {\n const wallet = account ?? await getWalletAccount()\n const [balanceUsdc, balanceEth] = await Promise.all([\n getBalanceUsdc(wallet.address),\n getBalanceEth(wallet.address),\n ])\n return formatWalletBalance(wallet.address, balanceUsdc, balanceEth)\n}\n\nexport function buildTopupInfo(address: string, topupUrl?: string): TopupInfo {\n return {\n wallet_address: address,\n network: 'Base',\n chain_id: BASE_CHAIN_ID,\n token: 'USDC',\n token_contract: USDC_ADDRESS,\n ...(topupUrl ? { topup_url: topupUrl } : {}),\n }\n}\n"],"mappings":"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"}