chain-insights 0.2.26 → 0.2.28

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 (34) hide show
  1. package/README.md +3 -0
  2. package/dist/{capabilities-B4hvro_I.cjs → capabilities-BAZ16MFI.cjs} +1 -1
  3. package/dist/{capabilities-mXm_rCe8.mjs → capabilities-CYv7k4wI.mjs} +2 -2
  4. package/dist/{capabilities-mXm_rCe8.mjs.map → capabilities-CYv7k4wI.mjs.map} +1 -1
  5. package/dist/cli.cjs +25 -15
  6. package/dist/cli.mjs +26 -16
  7. package/dist/cli.mjs.map +1 -1
  8. package/dist/{client-Dl-uHrh1.mjs → client-7vkBVEIj.mjs} +5 -5
  9. package/dist/client-7vkBVEIj.mjs.map +1 -0
  10. package/dist/{client-BYnFGA0y.cjs → client-ByXzwNum.cjs} +4 -4
  11. package/dist/index.cjs +4 -4
  12. package/dist/index.mjs +4 -4
  13. package/dist/{init-jhOZ_RvC.cjs → init-CFaUWgjK.cjs} +1 -1
  14. package/dist/{init-CB_ga4_8.mjs → init-DBC9Ml33.mjs} +2 -2
  15. package/dist/{init-CB_ga4_8.mjs.map → init-DBC9Ml33.mjs.map} +1 -1
  16. package/dist/mcp-proxy.cjs +3 -3
  17. package/dist/mcp-proxy.mjs +3 -3
  18. package/dist/{runner-BBH5Ks6q.mjs → runner-B-9g4X1q.mjs} +3 -3
  19. package/dist/{runner-BBH5Ks6q.mjs.map → runner-B-9g4X1q.mjs.map} +1 -1
  20. package/dist/{runner-e9slg6R2.cjs → runner-BKHImisp.cjs} +2 -2
  21. package/dist/{tools-UH5hRXYG.cjs → tools-BhTI3Lmg.cjs} +6 -6
  22. package/dist/{tools-D6RBAhSX.mjs → tools-v6kcdojg.mjs} +7 -7
  23. package/dist/tools-v6kcdojg.mjs.map +1 -0
  24. package/dist/{topup-server-yAaXYkJP.cjs → topup-server-DhYlOOBM.cjs} +2 -2
  25. package/dist/{topup-server-BJgVw6Jt.mjs → topup-server-R3dNp-p8.mjs} +3 -3
  26. package/dist/topup-server-R3dNp-p8.mjs.map +1 -0
  27. package/dist/{wallet-D8IqFRKY.mjs → wallet-BL0fJC29.mjs} +3 -3
  28. package/dist/{wallet-D8IqFRKY.mjs.map → wallet-BL0fJC29.mjs.map} +1 -1
  29. package/dist/{wallet-TAlNMvIM.cjs → wallet-gC2jxh7j.cjs} +2 -2
  30. package/docs/mcp-proxy.md +6 -3
  31. package/package.json +1 -1
  32. package/dist/client-Dl-uHrh1.mjs.map +0 -1
  33. package/dist/tools-D6RBAhSX.mjs.map +0 -1
  34. package/dist/topup-server-BJgVw6Jt.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"wallet-D8IqFRKY.mjs","names":["nodeErr"],"sources":["../src/wallet/index.ts"],"sourcesContent":["import crypto from 'node:crypto'\nimport os from 'node:os'\nimport path from 'node:path'\nimport { readFile, writeFile, mkdir, stat } from 'node:fs/promises'\nimport type { Address, Hex } from 'viem'\nimport { privateKeyToAccount } from 'viem/accounts'\n\n// Path derived at call time so tests can override HOME.\nexport function walletPath(): string {\n return path.join(os.homedir(), '.chain-insights', 'wallet.json')\n}\n\n// Derive a 32-byte key from the machine identity (hostname + username) and a\n// random per-wallet salt. The salt prevents precomputation attacks across wallets.\nfunction deriveKey(salt: Buffer): Buffer {\n return crypto.scryptSync(\n `${os.hostname()}:${os.userInfo().username}`,\n salt,\n 32,\n )\n}\n\ninterface WalletData {\n salt: string\n iv: string\n tag: string\n data: string\n}\n\nexport function normalizeWalletPrivateKey(value: string): Hex {\n if (!/^0x[0-9a-fA-F]{64}$/.test(value)) {\n throw new Error('Stored wallet private key is not a valid 0x-prefixed EVM private key')\n }\n return value as Hex\n}\n\nexport function walletAddressFromPrivateKey(privateKey: string): Address {\n return privateKeyToAccount(normalizeWalletPrivateKey(privateKey)).address\n}\n\n/**\n * Encrypts a private key and writes it to ~/.chain-insights/wallet.json.\n * Uses AES-256-GCM with a machine-identity-derived key and a random per-wallet salt.\n * File is written with 0o600 permissions (owner read/write only).\n *\n * @param privateKey - The EVM private key to encrypt (0x-prefixed)\n */\nexport async function encryptKey(privateKey: string): Promise<void> {\n const normalizedPrivateKey = normalizeWalletPrivateKey(privateKey)\n const salt = crypto.randomBytes(16)\n const key = deriveKey(salt)\n const iv = crypto.randomBytes(12)\n const cipher = crypto.createCipheriv('aes-256-gcm', key, iv)\n\n const encrypted = Buffer.concat([\n cipher.update(normalizedPrivateKey, 'utf8'),\n cipher.final(),\n ])\n\n // getAuthTag() MUST be called after final()\n const tag = cipher.getAuthTag()\n\n const walletData: WalletData = {\n salt: salt.toString('hex'),\n iv: iv.toString('hex'),\n tag: tag.toString('hex'),\n data: encrypted.toString('hex'),\n }\n\n const p = walletPath()\n await mkdir(path.dirname(p), { recursive: true })\n await writeFile(p, JSON.stringify(walletData, null, 2) + '\\n', { mode: 0o600 })\n}\n\nexport async function setWalletPrivateKey(privateKey: string): Promise<Address> {\n const normalizedPrivateKey = normalizeWalletPrivateKey(privateKey)\n const address = walletAddressFromPrivateKey(normalizedPrivateKey)\n await encryptKey(normalizedPrivateKey)\n return address\n}\n\n/**\n * Reads and decrypts the private key from ~/.chain-insights/wallet.json.\n * Throws a human-readable error if wallet is absent or decryption fails.\n *\n * @returns The decrypted EVM private key string\n */\nexport async function decryptKey(): Promise<string> {\n let raw: string\n try {\n raw = await readFile(walletPath(), 'utf8')\n } catch (err: unknown) {\n const nodeErr = err as NodeJS.ErrnoException\n if (nodeErr.code === 'ENOENT') {\n throw new Error(\n 'Wallet not configured. Run `chain-insights config set walletPrivateKey <key>` to enable paid MCP calls',\n )\n }\n throw err\n }\n\n try {\n const stored = JSON.parse(raw) as WalletData\n const salt = Buffer.from(stored.salt, 'hex')\n const key = deriveKey(salt)\n const iv = Buffer.from(stored.iv, 'hex')\n const tag = Buffer.from(stored.tag, 'hex')\n const encrypted = Buffer.from(stored.data, 'hex')\n\n const decipher = crypto.createDecipheriv('aes-256-gcm', key, iv)\n // setAuthTag() MUST be called before update()\n decipher.setAuthTag(tag)\n\n const decrypted = Buffer.concat([\n decipher.update(encrypted),\n decipher.final(),\n ])\n\n return decrypted.toString('utf8')\n } catch {\n throw new Error(\n 'Wallet decryption failed. If you changed your hostname or username, re-configure with `chain-insights config set walletPrivateKey <key>`.',\n )\n }\n}\n\n/**\n * Returns true if wallet.json exists, false if absent.\n * Does not validate the wallet contents.\n */\nexport async function isWalletConfigured(): Promise<boolean> {\n try {\n await stat(walletPath())\n return true\n } catch (err: unknown) {\n const nodeErr = err as NodeJS.ErrnoException\n if (nodeErr.code === 'ENOENT') return false\n throw err\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAQA,SAAgB,aAAqB;CACnC,OAAO,KAAK,KAAK,GAAG,QAAQ,GAAG,mBAAmB,aAAa;AACjE;AAIA,SAAS,UAAU,MAAsB;CACvC,OAAO,OAAO,WACZ,GAAG,GAAG,SAAS,EAAE,GAAG,GAAG,SAAS,EAAE,YAClC,MACA,EACF;AACF;AASA,SAAgB,0BAA0B,OAAoB;CAC5D,IAAI,CAAC,sBAAsB,KAAK,KAAK,GACnC,MAAM,IAAI,MAAM,sEAAsE;CAExF,OAAO;AACT;AAEA,SAAgB,4BAA4B,YAA6B;CACvE,OAAO,oBAAoB,0BAA0B,UAAU,CAAC,EAAE;AACpE;;;;;;;;AASA,eAAsB,WAAW,YAAmC;CAClE,MAAM,uBAAuB,0BAA0B,UAAU;CACjE,MAAM,OAAO,OAAO,YAAY,EAAE;CAClC,MAAM,MAAM,UAAU,IAAI;CAC1B,MAAM,KAAK,OAAO,YAAY,EAAE;CAChC,MAAM,SAAS,OAAO,eAAe,eAAe,KAAK,EAAE;CAE3D,MAAM,YAAY,OAAO,OAAO,CAC9B,OAAO,OAAO,sBAAsB,MAAM,GAC1C,OAAO,MAAM,CACf,CAAC;CAGD,MAAM,MAAM,OAAO,WAAW;CAE9B,MAAM,aAAyB;EAC7B,MAAM,KAAK,SAAS,KAAK;EACzB,IAAI,GAAG,SAAS,KAAK;EACrB,KAAK,IAAI,SAAS,KAAK;EACvB,MAAM,UAAU,SAAS,KAAK;CAChC;CAEA,MAAM,IAAI,WAAW;CACrB,MAAM,MAAM,KAAK,QAAQ,CAAC,GAAG,EAAE,WAAW,KAAK,CAAC;CAChD,MAAM,UAAU,GAAG,KAAK,UAAU,YAAY,MAAM,CAAC,IAAI,MAAM,EAAE,MAAM,IAAM,CAAC;AAChF;AAEA,eAAsB,oBAAoB,YAAsC;CAC9E,MAAM,uBAAuB,0BAA0B,UAAU;CACjE,MAAM,UAAU,4BAA4B,oBAAoB;CAChE,MAAM,WAAW,oBAAoB;CACrC,OAAO;AACT;;;;;;;AAQA,eAAsB,aAA8B;CAClD,IAAI;CACJ,IAAI;EACF,MAAM,MAAM,SAAS,WAAW,GAAG,MAAM;CAC3C,SAAS,KAAc;EAErB,IAAIA,IAAQ,SAAS,UACnB,MAAM,IAAI,MACR,wGACF;EAEF,MAAM;CACR;CAEA,IAAI;EACF,MAAM,SAAS,KAAK,MAAM,GAAG;EAE7B,MAAM,MAAM,UADC,OAAO,KAAK,OAAO,MAAM,KACb,CAAC;EAC1B,MAAM,KAAK,OAAO,KAAK,OAAO,IAAI,KAAK;EACvC,MAAM,MAAM,OAAO,KAAK,OAAO,KAAK,KAAK;EACzC,MAAM,YAAY,OAAO,KAAK,OAAO,MAAM,KAAK;EAEhD,MAAM,WAAW,OAAO,iBAAiB,eAAe,KAAK,EAAE;EAE/D,SAAS,WAAW,GAAG;EAOvB,OALkB,OAAO,OAAO,CAC9B,SAAS,OAAO,SAAS,GACzB,SAAS,MAAM,CACjB,CAEe,EAAE,SAAS,MAAM;CAClC,QAAQ;EACN,MAAM,IAAI,MACR,2IACF;CACF;AACF;;;;;AAMA,eAAsB,qBAAuC;CAC3D,IAAI;EACF,MAAM,KAAK,WAAW,CAAC;EACvB,OAAO;CACT,SAAS,KAAc;EAErB,IAAIA,IAAQ,SAAS,UAAU,OAAO;EACtC,MAAM;CACR;AACF"}
1
+ {"version":3,"file":"wallet-BL0fJC29.mjs","names":["nodeErr"],"sources":["../src/wallet/index.ts"],"sourcesContent":["import crypto from 'node:crypto'\nimport os from 'node:os'\nimport path from 'node:path'\nimport { readFile, writeFile, mkdir, stat } from 'node:fs/promises'\nimport type { Address, Hex } from 'viem'\nimport { privateKeyToAccount } from 'viem/accounts'\n\n// Path derived at call time so tests can override HOME.\nexport function walletPath(): string {\n return path.join(os.homedir(), '.chain-insights', 'wallet.json')\n}\n\n// Derive a 32-byte key from the machine identity (hostname + username) and a\n// random per-wallet salt. The salt prevents precomputation attacks across wallets.\nfunction deriveKey(salt: Buffer): Buffer {\n return crypto.scryptSync(\n `${os.hostname()}:${os.userInfo().username}`,\n salt,\n 32,\n )\n}\n\ninterface WalletData {\n salt: string\n iv: string\n tag: string\n data: string\n}\n\nexport function normalizeWalletPrivateKey(value: string): Hex {\n if (!/^0x[0-9a-fA-F]{64}$/.test(value)) {\n throw new Error('Stored wallet private key is not a valid 0x-prefixed EVM private key')\n }\n return value as Hex\n}\n\nexport function walletAddressFromPrivateKey(privateKey: string): Address {\n return privateKeyToAccount(normalizeWalletPrivateKey(privateKey)).address\n}\n\n/**\n * Encrypts a private key and writes it to ~/.chain-insights/wallet.json.\n * Uses AES-256-GCM with a machine-identity-derived key and a random per-wallet salt.\n * File is written with 0o600 permissions (owner read/write only).\n *\n * @param privateKey - The EVM private key to encrypt (0x-prefixed)\n */\nexport async function encryptKey(privateKey: string): Promise<void> {\n const normalizedPrivateKey = normalizeWalletPrivateKey(privateKey)\n const salt = crypto.randomBytes(16)\n const key = deriveKey(salt)\n const iv = crypto.randomBytes(12)\n const cipher = crypto.createCipheriv('aes-256-gcm', key, iv)\n\n const encrypted = Buffer.concat([\n cipher.update(normalizedPrivateKey, 'utf8'),\n cipher.final(),\n ])\n\n // getAuthTag() MUST be called after final()\n const tag = cipher.getAuthTag()\n\n const walletData: WalletData = {\n salt: salt.toString('hex'),\n iv: iv.toString('hex'),\n tag: tag.toString('hex'),\n data: encrypted.toString('hex'),\n }\n\n const p = walletPath()\n await mkdir(path.dirname(p), { recursive: true })\n await writeFile(p, JSON.stringify(walletData, null, 2) + '\\n', { mode: 0o600 })\n}\n\nexport async function setWalletPrivateKey(privateKey: string): Promise<Address> {\n const normalizedPrivateKey = normalizeWalletPrivateKey(privateKey)\n const address = walletAddressFromPrivateKey(normalizedPrivateKey)\n await encryptKey(normalizedPrivateKey)\n return address\n}\n\n/**\n * Reads and decrypts the private key from ~/.chain-insights/wallet.json.\n * Throws a human-readable error if wallet is absent or decryption fails.\n *\n * @returns The decrypted EVM private key string\n */\nexport async function decryptKey(): Promise<string> {\n let raw: string\n try {\n raw = await readFile(walletPath(), 'utf8')\n } catch (err: unknown) {\n const nodeErr = err as NodeJS.ErrnoException\n if (nodeErr.code === 'ENOENT') {\n throw new Error(\n 'Wallet not configured. Run `chain-insights wallet import <private-key>`, then `chain-insights wallet ready`.',\n )\n }\n throw err\n }\n\n try {\n const stored = JSON.parse(raw) as WalletData\n const salt = Buffer.from(stored.salt, 'hex')\n const key = deriveKey(salt)\n const iv = Buffer.from(stored.iv, 'hex')\n const tag = Buffer.from(stored.tag, 'hex')\n const encrypted = Buffer.from(stored.data, 'hex')\n\n const decipher = crypto.createDecipheriv('aes-256-gcm', key, iv)\n // setAuthTag() MUST be called before update()\n decipher.setAuthTag(tag)\n\n const decrypted = Buffer.concat([\n decipher.update(encrypted),\n decipher.final(),\n ])\n\n return decrypted.toString('utf8')\n } catch {\n throw new Error(\n 'Wallet decryption failed. If you changed your hostname or username, re-import it with `chain-insights wallet import <private-key>`.',\n )\n }\n}\n\n/**\n * Returns true if wallet.json exists, false if absent.\n * Does not validate the wallet contents.\n */\nexport async function isWalletConfigured(): Promise<boolean> {\n try {\n await stat(walletPath())\n return true\n } catch (err: unknown) {\n const nodeErr = err as NodeJS.ErrnoException\n if (nodeErr.code === 'ENOENT') return false\n throw err\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAQA,SAAgB,aAAqB;CACnC,OAAO,KAAK,KAAK,GAAG,QAAQ,GAAG,mBAAmB,aAAa;AACjE;AAIA,SAAS,UAAU,MAAsB;CACvC,OAAO,OAAO,WACZ,GAAG,GAAG,SAAS,EAAE,GAAG,GAAG,SAAS,EAAE,YAClC,MACA,EACF;AACF;AASA,SAAgB,0BAA0B,OAAoB;CAC5D,IAAI,CAAC,sBAAsB,KAAK,KAAK,GACnC,MAAM,IAAI,MAAM,sEAAsE;CAExF,OAAO;AACT;AAEA,SAAgB,4BAA4B,YAA6B;CACvE,OAAO,oBAAoB,0BAA0B,UAAU,CAAC,EAAE;AACpE;;;;;;;;AASA,eAAsB,WAAW,YAAmC;CAClE,MAAM,uBAAuB,0BAA0B,UAAU;CACjE,MAAM,OAAO,OAAO,YAAY,EAAE;CAClC,MAAM,MAAM,UAAU,IAAI;CAC1B,MAAM,KAAK,OAAO,YAAY,EAAE;CAChC,MAAM,SAAS,OAAO,eAAe,eAAe,KAAK,EAAE;CAE3D,MAAM,YAAY,OAAO,OAAO,CAC9B,OAAO,OAAO,sBAAsB,MAAM,GAC1C,OAAO,MAAM,CACf,CAAC;CAGD,MAAM,MAAM,OAAO,WAAW;CAE9B,MAAM,aAAyB;EAC7B,MAAM,KAAK,SAAS,KAAK;EACzB,IAAI,GAAG,SAAS,KAAK;EACrB,KAAK,IAAI,SAAS,KAAK;EACvB,MAAM,UAAU,SAAS,KAAK;CAChC;CAEA,MAAM,IAAI,WAAW;CACrB,MAAM,MAAM,KAAK,QAAQ,CAAC,GAAG,EAAE,WAAW,KAAK,CAAC;CAChD,MAAM,UAAU,GAAG,KAAK,UAAU,YAAY,MAAM,CAAC,IAAI,MAAM,EAAE,MAAM,IAAM,CAAC;AAChF;AAEA,eAAsB,oBAAoB,YAAsC;CAC9E,MAAM,uBAAuB,0BAA0B,UAAU;CACjE,MAAM,UAAU,4BAA4B,oBAAoB;CAChE,MAAM,WAAW,oBAAoB;CACrC,OAAO;AACT;;;;;;;AAQA,eAAsB,aAA8B;CAClD,IAAI;CACJ,IAAI;EACF,MAAM,MAAM,SAAS,WAAW,GAAG,MAAM;CAC3C,SAAS,KAAc;EAErB,IAAIA,IAAQ,SAAS,UACnB,MAAM,IAAI,MACR,8GACF;EAEF,MAAM;CACR;CAEA,IAAI;EACF,MAAM,SAAS,KAAK,MAAM,GAAG;EAE7B,MAAM,MAAM,UADC,OAAO,KAAK,OAAO,MAAM,KACb,CAAC;EAC1B,MAAM,KAAK,OAAO,KAAK,OAAO,IAAI,KAAK;EACvC,MAAM,MAAM,OAAO,KAAK,OAAO,KAAK,KAAK;EACzC,MAAM,YAAY,OAAO,KAAK,OAAO,MAAM,KAAK;EAEhD,MAAM,WAAW,OAAO,iBAAiB,eAAe,KAAK,EAAE;EAE/D,SAAS,WAAW,GAAG;EAOvB,OALkB,OAAO,OAAO,CAC9B,SAAS,OAAO,SAAS,GACzB,SAAS,MAAM,CACjB,CAEe,EAAE,SAAS,MAAM;CAClC,QAAQ;EACN,MAAM,IAAI,MACR,qIACF;CACF;AACF;;;;;AAMA,eAAsB,qBAAuC;CAC3D,IAAI;EACF,MAAM,KAAK,WAAW,CAAC;EACvB,OAAO;CACT,SAAS,KAAc;EAErB,IAAIA,IAAQ,SAAS,UAAU,OAAO;EACtC,MAAM;CACR;AACF"}
@@ -72,7 +72,7 @@ async function decryptKey() {
72
72
  try {
73
73
  raw = await (0, node_fs_promises.readFile)(walletPath(), "utf8");
74
74
  } catch (err) {
75
- if (err.code === "ENOENT") throw new Error("Wallet not configured. Run `chain-insights config set walletPrivateKey <key>` to enable paid MCP calls");
75
+ if (err.code === "ENOENT") throw new Error("Wallet not configured. Run `chain-insights wallet import <private-key>`, then `chain-insights wallet ready`.");
76
76
  throw err;
77
77
  }
78
78
  try {
@@ -85,7 +85,7 @@ async function decryptKey() {
85
85
  decipher.setAuthTag(tag);
86
86
  return Buffer.concat([decipher.update(encrypted), decipher.final()]).toString("utf8");
87
87
  } catch {
88
- throw new Error("Wallet decryption failed. If you changed your hostname or username, re-configure with `chain-insights config set walletPrivateKey <key>`.");
88
+ throw new Error("Wallet decryption failed. If you changed your hostname or username, re-import it with `chain-insights wallet import <private-key>`.");
89
89
  }
90
90
  }
91
91
  /**
package/docs/mcp-proxy.md CHANGED
@@ -38,6 +38,8 @@ Set hosted staging for approved testers:
38
38
  chain-insights config set graphMcpEndpoint https://staging-mcp.chain-insights.ai/mcp
39
39
  ```
40
40
 
41
+ For now, use staging only for tester activation. Production is not live yet.
42
+
41
43
  Use a one-shot environment override:
42
44
 
43
45
  ```bash
@@ -117,7 +119,7 @@ Paid x402 mode:
117
119
  ```bash
118
120
  chain-insights config set graphMcpEndpoint https://staging-mcp.chain-insights.ai/mcp
119
121
  chain-insights debug off
120
- chain-insights config set walletPrivateKey 0xYOUR_EVM_PRIVATE_KEY
122
+ chain-insights wallet import 0xYOUR_EVM_PRIVATE_KEY
121
123
  chain-insights wallet ready
122
124
  ```
123
125
 
@@ -125,8 +127,9 @@ If `graphMcpAuthToken` is set, Chain Insights sends both
125
127
  `X-MCP-Debug-Token` and `Authorization: Bearer <token>`. If it is empty,
126
128
  Chain Insights uses the encrypted wallet private key with x402 payment
127
129
  handling. `wallet ready` is the user-facing preflight: it checks Base USDC,
128
- Base ETH gas, and payment approval, and it submits only the one-time approval
129
- transaction when needed.
130
+ Base ETH gas, and one-time payment setup. A normal user does not need payment
131
+ protocol details; run `chain-insights wallet ready` and retry the paid tool
132
+ after it reports ready.
130
133
 
131
134
  ## Agent Installers
132
135
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chain-insights",
3
- "version": "0.2.26",
3
+ "version": "0.2.28",
4
4
  "description": "AML investigation CLI and MCP proxy for blockchain risk, fund-flow tracing, case reports, and GraphRAG MCP access",
5
5
  "homepage": "https://chain-insights.ai",
6
6
  "repository": {
@@ -1 +0,0 @@
1
- {"version":3,"file":"client-Dl-uHrh1.mjs","names":[],"sources":["../src/mcp/client.ts"],"sourcesContent":["import { wrapFetchWithPaymentFromConfig } from '@x402/fetch'\nimport { ExactEvmScheme } from '@x402/evm'\nimport { UptoEvmScheme } from '@x402/evm/upto/client'\nimport { privateKeyToAccount } from 'viem/accounts'\nimport type { InvestigatorConfig } from '../config/schema.js'\nimport { prepareWalletForPaidCalls } from '../wallet/tools.js'\n\ntype FetchLike = typeof fetch\ntype FetchInput = Parameters<FetchLike>[0]\ntype FetchInit = Parameters<FetchLike>[1]\n\nexport class PaymentRequiredError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'PaymentRequiredError'\n }\n}\n\nfunction createHeaderFetch(authToken: string, baseFetch: FetchLike): FetchLike {\n return (async (input: FetchInput, init?: FetchInit) => {\n const requestHeaders = input instanceof Request ? input.headers : undefined\n const headers = new Headers(init?.headers ?? requestHeaders)\n headers.set('X-MCP-Debug-Token', authToken)\n headers.set('Authorization', `Bearer ${authToken}`)\n\n return baseFetch(input, {\n ...init,\n headers,\n })\n }) as FetchLike\n}\n\nexport const PAYMENT_NEXT_STEPS =\n 'Next steps: run `chain-insights wallet ready` to check funding and finish one-time payment setup, ' +\n 'run `chain-insights wallet topup` if it says the wallet needs USDC, ' +\n 'or `chain-insights access-key set <key>` if you have been given test access.'\n\ninterface PaymentRequirementDetails {\n reason: string\n scheme?: string\n network?: string\n amount?: string\n amountUnits?: bigint\n payTo?: string\n}\n\nfunction paymentRequirementFromResponse(response: Response): PaymentRequirementDetails | null {\n const encoded = response.headers.get('payment-required')\n if (!encoded) return null\n\n try {\n const decoded = Buffer.from(encoded, 'base64').toString('utf8')\n const parsed = JSON.parse(decoded) as {\n error?: unknown\n accepts?: Array<{ scheme?: unknown; network?: unknown; amount?: unknown; payTo?: unknown }>\n }\n const reason = typeof parsed.error === 'string' && parsed.error.trim() ? parsed.error.trim() : 'payment_required'\n const firstRequirement = Array.isArray(parsed.accepts) ? parsed.accepts[0] : undefined\n const amount = typeof firstRequirement?.amount === 'string' ? firstRequirement.amount.trim() : undefined\n return {\n reason,\n scheme: typeof firstRequirement?.scheme === 'string' ? firstRequirement.scheme : undefined,\n network: typeof firstRequirement?.network === 'string' ? firstRequirement.network : undefined,\n amount,\n amountUnits: amount && /^\\d+$/.test(amount) ? BigInt(amount) : undefined,\n payTo: typeof firstRequirement?.payTo === 'string' ? firstRequirement.payTo.trim() : undefined,\n }\n } catch {\n return null\n }\n}\n\nfunction describePaymentRequiredResponse(response: Response, payerAddress?: string): string {\n const requirement = paymentRequirementFromResponse(response)\n if (!requirement) return `Payment required — this tool costs USDC on Base via x402 micropayments. ${PAYMENT_NEXT_STEPS}`\n\n try {\n const { reason, payTo } = requirement\n if (payerAddress && payTo && payerAddress.toLowerCase() === payTo.toLowerCase()) {\n return 'Local payment wallet matches the MCP payTo address. Configure a separate payer wallet with USDC on Base; do not use the service recipient wallet as the client payment wallet.'\n }\n const details = [\n requirement.scheme ? `scheme=${requirement.scheme}` : undefined,\n requirement.network ? `network=${requirement.network}` : undefined,\n requirement.amount ? `amount=${requirement.amount}` : undefined,\n ].filter(Boolean).join(' ')\n const message = details ? `x402 payment failed: ${reason} (${details})` : `x402 payment failed: ${reason}`\n if (reason.includes('allowance_required')) {\n return `${message}. The payment wallet needs one-time setup before paid MCP calls can settle. Run \\`chain-insights wallet ready\\`; Base ETH is required for the approval gas.`\n }\n if (reason === 'payment_required') {\n return `${message}. ${PAYMENT_NEXT_STEPS}`\n }\n return `${message}. ${PAYMENT_NEXT_STEPS}`\n } catch {\n return `Payment required — this tool costs USDC on Base via x402 micropayments. ${PAYMENT_NEXT_STEPS}`\n }\n}\n\nfunction createPaymentFailureReportingFetch(\n baseFetch: FetchLike,\n payerAddress?: string,\n paymentWallet?: { address: `0x${string}`; privateKey: `0x${string}` },\n): FetchLike {\n const reportingFetch = (async (input: FetchInput, init?: FetchInit) => {\n const response = await baseFetch(input, init)\n if (response.status !== 402) return response\n const requirement = paymentRequirementFromResponse(response)\n if (paymentWallet && requirement?.reason.includes('allowance_required')) {\n try {\n await prepareWalletForPaidCalls({\n account: paymentWallet,\n ...(requirement.amountUnits === undefined ? {} : { minimumApprovalUnits: requirement.amountUnits }),\n })\n } catch (err) {\n throw new PaymentRequiredError(\n 'Payment setup is not ready yet. Run `chain-insights wallet ready` and try again. ' +\n `${(err as Error).message}`,\n )\n }\n const retryResponse = await baseFetch(input, init)\n if (retryResponse.status !== 402) return retryResponse\n throw new PaymentRequiredError(describePaymentRequiredResponse(retryResponse, payerAddress))\n }\n throw new PaymentRequiredError(describePaymentRequiredResponse(response, payerAddress))\n }) as FetchLike\n return Object.assign(reportingFetch, baseFetch)\n}\n\n/**\n * Creates an x402-payment-wrapped fetch function for the Chain Insights MCP.\n * Payments are made in USDC on Base Mainnet (eip155:8453).\n *\n * The factory is pure — no side effects, no state, no caching.\n * If called with an invalid private key format, viem throws — the error propagates.\n *\n * @param privateKey - 0x-prefixed EVM private key (decrypted from wallet.json)\n * @returns A fetch-compatible function that auto-handles HTTP 402 payment challenges\n */\nexport function createMcpFetchClient(privateKey: `0x${string}`, authToken?: string) {\n const account = privateKeyToAccount(privateKey)\n const paymentFetch = wrapFetchWithPaymentFromConfig(fetch, {\n schemes: [\n {\n network: 'eip155:8453', // Base Mainnet — dynamic MCP pricing uses the x402 upto scheme\n client: new UptoEvmScheme(account),\n },\n {\n network: 'eip155:8453', // Base Mainnet — only supported chain in v1\n client: new ExactEvmScheme(account),\n },\n ],\n })\n const reportingFetch = createPaymentFailureReportingFetch(\n paymentFetch,\n account.address,\n { address: account.address, privateKey },\n )\n return authToken ? createHeaderFetch(authToken, reportingFetch) : reportingFetch\n}\n\n/**\n * Creates a bearer/debug-token fetch for local Graph MCP testing.\n *\n * The public x402 debug bypass expects X-MCP-Debug-Token.\n * Private endpoints commonly expect Authorization: Bearer <token>.\n * Sending both lets one config value work for public debug and private M2M endpoints.\n *\n * Wraps with 402 interception so that if the server still requires payment\n * (e.g. token not accepted for paid tools), the user sees actionable guidance\n * instead of a generic transport error.\n */\nexport function createMcpAuthFetchClient(authToken: string, baseFetch: FetchLike = fetch): FetchLike {\n const headerFetch = createHeaderFetch(authToken, baseFetch)\n return createPaymentFailureReportingFetch(headerFetch)\n}\n\nexport function resolveGraphMcpEndpoint(config: Pick<InvestigatorConfig, 'graphMcpEndpoint' | 'mcpEndpoint'>): string {\n const graphEndpoint = config.graphMcpEndpoint?.trim()\n return graphEndpoint || config.mcpEndpoint\n}\n\nasync function createConfiguredFetchWithToken(\n authToken: string | undefined,\n missingTokenName: string,\n): Promise<FetchLike> {\n const normalizedAuthToken = authToken?.trim()\n if (normalizedAuthToken) return createMcpAuthFetchClient(normalizedAuthToken)\n\n const { isWalletConfigured, decryptKey } = await import('../wallet/index.js')\n if (!(await isWalletConfigured())) {\n throw new Error(\n `Wallet not configured and ${missingTokenName} is empty. ` +\n `Run \\`chain-insights access-key set <key>\\` for invited test access or \\`chain-insights config set ${missingTokenName} <token>\\` for local MCP debug bypass, ` +\n 'or `chain-insights config set walletPrivateKey <key>` to enable paid x402 MCP calls.',\n )\n }\n\n const privateKey = await decryptKey()\n return createMcpFetchClient(privateKey as `0x${string}`)\n}\n\nexport async function createConfiguredMcpFetch(config: Pick<InvestigatorConfig, 'mcpAuthToken'>): Promise<FetchLike> {\n return createConfiguredFetchWithToken(config.mcpAuthToken, 'mcpAuthToken')\n}\n\nexport async function createConfiguredGraphMcpFetch(\n config: Pick<InvestigatorConfig, 'mcpAuthToken' | 'graphMcpAuthToken' | 'graphMcpMode'>,\n): Promise<FetchLike> {\n if (config.graphMcpMode === 'debug') {\n const authToken = config.graphMcpAuthToken?.trim() || config.mcpAuthToken?.trim()\n if (!authToken) {\n throw new Error('Graph MCP debug mode requires graphMcpAuthToken. Run `cia access-key set <key>` or `cia debug on --token <token>`.')\n }\n return createMcpAuthFetchClient(authToken)\n }\n\n return createConfiguredFetchWithToken(undefined, 'walletPrivateKey')\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
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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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"topup-server-BJgVw6Jt.mjs","names":["USDC_ADDRESS","getTopupUrl","startTopupServer","getCopiedTopupUrl","startCopiedTopupServer"],"sources":["../src/wallet/mcp-proxy/qr.ts","../src/wallet/mcp-proxy/tools.ts","../src/wallet/mcp-proxy/topup-server.ts","../src/wallet/topup-server.ts"],"sourcesContent":["/**\n * Minimal QR code generator — produces SVG string server-side.\n * Supports alphanumeric mode (sufficient for Ethereum addresses).\n * No external dependencies.\n */\n\n// Error correction level M (15% recovery)\nconst EC_LEVEL = 0; // L=0, M=1 — using L for simplicity with short data\n\n// QR code version 2 (25x25) is sufficient for 42-char ETH addresses\nconst VERSION = 2;\nconst SIZE = 25; // modules per side for version 2\n\n// Generator polynomial for version 2-L: 10 EC codewords\nconst EC_CODEWORDS = 10;\nconst DATA_CODEWORDS = 34;\n\n// Format info for version 2, mask 0, EC level L\nconst FORMAT_BITS = 0b111011111000100;\n\n// Byte mode indicator\nconst MODE_BYTE = 0b0100;\n\nfunction createMatrix(): number[][] {\n const m: number[][] = [];\n for (let i = 0; i < SIZE; i++) {\n m[i] = new Array(SIZE).fill(-1);\n }\n return m;\n}\n\nfunction addFinderPattern(matrix: number[][], row: number, col: number): void {\n for (let r = -1; r <= 7; r++) {\n for (let c = -1; c <= 7; c++) {\n const mr = row + r;\n const mc = col + c;\n if (mr < 0 || mr >= SIZE || mc < 0 || mc >= SIZE) continue;\n if (r >= 0 && r <= 6 && c >= 0 && c <= 6) {\n if (r === 0 || r === 6 || c === 0 || c === 6 || (r >= 2 && r <= 4 && c >= 2 && c <= 4)) {\n matrix[mr][mc] = 1;\n } else {\n matrix[mr][mc] = 0;\n }\n } else {\n matrix[mr][mc] = 0;\n }\n }\n }\n}\n\nfunction addAlignmentPattern(matrix: number[][], row: number, col: number): void {\n for (let r = -2; r <= 2; r++) {\n for (let c = -2; c <= 2; c++) {\n if (Math.abs(r) === 2 || Math.abs(c) === 2 || (r === 0 && c === 0)) {\n matrix[row + r][col + c] = 1;\n } else {\n matrix[row + r][col + c] = 0;\n }\n }\n }\n}\n\nfunction addTimingPatterns(matrix: number[][]): void {\n for (let i = 8; i < SIZE - 8; i++) {\n if (matrix[6][i] === -1) matrix[6][i] = i % 2 === 0 ? 1 : 0;\n if (matrix[i][6] === -1) matrix[i][6] = i % 2 === 0 ? 1 : 0;\n }\n}\n\nfunction addFormatInfo(matrix: number[][]): void {\n const bits = FORMAT_BITS;\n for (let i = 0; i <= 5; i++) matrix[8][i] = (bits >> (14 - i)) & 1;\n matrix[8][7] = (bits >> 8) & 1;\n matrix[8][8] = (bits >> 7) & 1;\n matrix[7][8] = (bits >> 6) & 1;\n for (let i = 0; i <= 5; i++) matrix[5 - i][8] = (bits >> (i)) & 1;\n\n for (let i = 0; i <= 7; i++) matrix[SIZE - 1 - i][8] = (bits >> (14 - i)) & 1;\n for (let i = 0; i <= 7; i++) matrix[8][SIZE - 8 + i] = (bits >> (7 - i)) & 1;\n\n // Dark module\n matrix[SIZE - 8][8] = 1;\n}\n\nfunction encodeData(text: string): number[] {\n const bytes = new TextEncoder().encode(text);\n const bits: number[] = [];\n\n // Mode indicator (4 bits): byte mode\n for (let i = 3; i >= 0; i--) bits.push((MODE_BYTE >> i) & 1);\n\n // Character count (8 bits for version 1-9 byte mode)\n for (let i = 7; i >= 0; i--) bits.push((bytes.length >> i) & 1);\n\n // Data\n for (const b of bytes) {\n for (let i = 7; i >= 0; i--) bits.push((b >> i) & 1);\n }\n\n // Terminator\n while (bits.length < DATA_CODEWORDS * 8 && bits.length < DATA_CODEWORDS * 8) {\n bits.push(0);\n if (bits.length >= DATA_CODEWORDS * 8) break;\n }\n\n // Pad to byte boundary\n while (bits.length % 8 !== 0) bits.push(0);\n\n // Pad codewords\n const padBytes = [0xec, 0x11];\n let padIdx = 0;\n while (bits.length < DATA_CODEWORDS * 8) {\n const pb = padBytes[padIdx % 2];\n for (let i = 7; i >= 0; i--) bits.push((pb >> i) & 1);\n padIdx++;\n }\n\n // Convert to bytes\n const codewords: number[] = [];\n for (let i = 0; i < bits.length; i += 8) {\n let val = 0;\n for (let j = 0; j < 8; j++) val = (val << 1) | (bits[i + j] || 0);\n codewords.push(val);\n }\n\n return codewords;\n}\n\n// GF(256) arithmetic for Reed-Solomon\nconst GF_EXP = new Array(512).fill(0);\nconst GF_LOG = new Array(256).fill(0);\n\n(function initGF() {\n let x = 1;\n for (let i = 0; i < 255; i++) {\n GF_EXP[i] = x;\n GF_LOG[x] = i;\n x <<= 1;\n if (x & 0x100) x ^= 0x11d;\n }\n for (let i = 255; i < 512; i++) GF_EXP[i] = GF_EXP[i - 255];\n})();\n\nfunction gfMul(a: number, b: number): number {\n if (a === 0 || b === 0) return 0;\n return GF_EXP[GF_LOG[a] + GF_LOG[b]];\n}\n\nfunction rsEncode(data: number[], ecCount: number): number[] {\n // Generate generator polynomial\n let gen = [1];\n for (let i = 0; i < ecCount; i++) {\n const next = new Array(gen.length + 1).fill(0);\n for (let j = 0; j < gen.length; j++) {\n next[j] ^= gen[j];\n next[j + 1] ^= gfMul(gen[j], GF_EXP[i]);\n }\n gen = next;\n }\n\n const msg = [...data, ...new Array(ecCount).fill(0)];\n for (let i = 0; i < data.length; i++) {\n const coef = msg[i];\n if (coef !== 0) {\n for (let j = 0; j < gen.length; j++) {\n msg[i + j] ^= gfMul(gen[j], coef);\n }\n }\n }\n\n return msg.slice(data.length);\n}\n\nfunction placeData(matrix: number[][], dataBits: number[]): void {\n let bitIdx = 0;\n let upward = true;\n\n for (let right = SIZE - 1; right >= 1; right -= 2) {\n if (right === 6) right = 5; // skip timing column\n\n const rows = upward\n ? Array.from({ length: SIZE }, (_, i) => SIZE - 1 - i)\n : Array.from({ length: SIZE }, (_, i) => i);\n\n for (const row of rows) {\n for (let c = 0; c < 2; c++) {\n const col = right - c;\n if (matrix[row][col] !== -1) continue;\n matrix[row][col] = bitIdx < dataBits.length ? dataBits[bitIdx++] : 0;\n }\n }\n upward = !upward;\n }\n}\n\nfunction applyMask0(matrix: number[][], reserved: number[][]): void {\n for (let r = 0; r < SIZE; r++) {\n for (let c = 0; c < SIZE; c++) {\n if (reserved[r][c] !== -1) continue;\n if ((r + c) % 2 === 0) {\n matrix[r][c] ^= 1;\n }\n }\n }\n}\n\nexport interface QrOptions {\n cellSize?: number;\n fgColor?: string;\n bgColor?: string;\n finderColor?: string;\n logoBase64?: string; // data URI for center logo\n logoWidth?: number; // logo width in modules (default: 7)\n logoHeight?: number; // logo height in modules (default: 5)\n}\n\nexport function generateQrSvg(text: string, opts: QrOptions | number = 4): string {\n // Backward compat: accept bare cellSize number\n const options: QrOptions = typeof opts === \"number\" ? { cellSize: opts } : opts;\n const cellSize = options.cellSize ?? 4;\n const fgColor = options.fgColor ?? \"#000\";\n const bgColor = options.bgColor ?? \"#fff\";\n const finderColor = options.finderColor ?? fgColor;\n\n const matrix = createMatrix();\n\n // Finder patterns\n addFinderPattern(matrix, 0, 0);\n addFinderPattern(matrix, 0, SIZE - 7);\n addFinderPattern(matrix, SIZE - 7, 0);\n\n // Alignment pattern (version 2: at position 18)\n addAlignmentPattern(matrix, 18, 18);\n\n // Timing\n addTimingPatterns(matrix);\n\n // Format info placeholder\n addFormatInfo(matrix);\n\n // Save reserved areas\n const reserved = matrix.map(row => [...row]);\n\n // Encode data + EC\n const dataCodewords = encodeData(text);\n const ecCodewords = rsEncode(dataCodewords, EC_CODEWORDS);\n const allCodewords = [...dataCodewords, ...ecCodewords];\n\n // Convert to bits\n const dataBits: number[] = [];\n for (const cw of allCodewords) {\n for (let i = 7; i >= 0; i--) dataBits.push((cw >> i) & 1);\n }\n\n // Place data\n placeData(matrix, dataBits);\n\n // Apply mask 0\n applyMask0(matrix, reserved);\n\n // Re-apply format info (mask may have flipped it)\n addFormatInfo(matrix);\n\n // Logo exclusion zone (center of QR)\n const logoW = options.logoWidth ?? 7;\n const logoH = options.logoHeight ?? 5;\n const logoStartC = Math.floor((SIZE - logoW) / 2);\n const logoStartR = Math.floor((SIZE - logoH) / 2);\n const hasLogo = !!options.logoBase64;\n\n // Generate SVG\n const svgSize = SIZE * cellSize;\n let svg = `<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" width=\"${svgSize}\" height=\"${svgSize}\" viewBox=\"0 0 ${svgSize} ${svgSize}\">`;\n svg += `<rect width=\"${svgSize}\" height=\"${svgSize}\" fill=\"${bgColor}\" rx=\"4\"/>`;\n\n // Finder pattern regions for coloring\n const isFinderModule = (r: number, c: number): boolean =>\n (r < 7 && c < 7) || (r < 7 && c >= SIZE - 7) || (r >= SIZE - 7 && c < 7);\n\n for (let r = 0; r < SIZE; r++) {\n for (let c = 0; c < SIZE; c++) {\n // Skip logo area\n if (hasLogo && r >= logoStartR && r < logoStartR + logoH && c >= logoStartC && c < logoStartC + logoW) {\n continue;\n }\n if (matrix[r][c] === 1) {\n const color = isFinderModule(r, c) ? finderColor : fgColor;\n svg += `<rect x=\"${c * cellSize}\" y=\"${r * cellSize}\" width=\"${cellSize}\" height=\"${cellSize}\" fill=\"${color}\" rx=\"0.5\"/>`;\n }\n }\n }\n\n // Embed logo in center\n if (hasLogo && options.logoBase64) {\n const lx = logoStartC * cellSize;\n const ly = logoStartR * cellSize;\n const lw = logoW * cellSize;\n const lh = logoH * cellSize;\n // White background behind logo\n svg += `<rect x=\"${lx - 1}\" y=\"${ly - 1}\" width=\"${lw + 2}\" height=\"${lh + 2}\" fill=\"${bgColor}\" rx=\"3\"/>`;\n svg += `<image x=\"${lx + 2}\" y=\"${ly + 2}\" width=\"${lw - 4}\" height=\"${lh - 4}\" href=\"${options.logoBase64}\" xlink:href=\"${options.logoBase64}\" preserveAspectRatio=\"xMidYMid meet\"/>`;\n }\n\n svg += '</svg>';\n return svg;\n}\n","import type { WalletData } from \"./types.js\";\nimport { createPublicClient, http, formatEther, formatUnits } from \"viem\";\nimport { base } from \"viem/chains\";\n\nconst USDC_ADDRESS = \"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913\" as const;\nconst DEFAULT_BASE_RPC_URL = \"https://mainnet.base.org\";\nconst 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;\nconst USDC_ABI = [\n {\n name: \"balanceOf\",\n type: \"function\",\n stateMutability: \"view\",\n inputs: [{ name: \"account\", type: \"address\" }],\n outputs: [{ name: \"\", type: \"uint256\" }],\n },\n] as const;\n\nfunction walletAddress(wallet: WalletData | string): `0x${string}` {\n return (typeof wallet === \"string\" ? wallet : wallet.address) as `0x${string}`;\n}\n\nexport async function getBalanceUsdc(wallet: WalletData | string): Promise<string> {\n const envRpcUrl = process.env.BASE_RPC_URL;\n const rpcUrls = [\n ...(envRpcUrl ? [envRpcUrl] : []),\n ...PUBLIC_BASE_RPC_URLS.filter((url) => url !== envRpcUrl),\n ];\n\n for (const rpcUrl of rpcUrls) {\n try {\n const client = createPublicClient({ chain: base, transport: http(rpcUrl) });\n const balance = await client.readContract({\n address: USDC_ADDRESS,\n abi: USDC_ABI,\n functionName: \"balanceOf\",\n args: [walletAddress(wallet)],\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(wallet: WalletData | string): Promise<string> {\n const envRpcUrl = process.env.BASE_RPC_URL;\n const rpcUrls = [\n ...(envRpcUrl ? [envRpcUrl] : []),\n ...PUBLIC_BASE_RPC_URLS.filter((url) => url !== envRpcUrl),\n ];\n\n for (const rpcUrl of rpcUrls) {\n try {\n const client = createPublicClient({ chain: base, transport: http(rpcUrl) });\n const balance = await client.getBalance({ address: walletAddress(wallet) });\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 getBalance(wallet: WalletData): Promise<string> {\n const [balanceUsdc, balanceEth] = await Promise.all([\n getBalanceUsdc(wallet),\n getBalanceEth(wallet),\n ]);\n return [\n `Balance: ${balanceUsdc} USDC`,\n `Gas: ${balanceEth} ETH on Base`,\n `Network: Base`,\n `Base ETH is required only for one-time payment approval gas.`,\n `Address: ${wallet.address}`,\n ].filter(Boolean).join(\"\\n\");\n}\n\nexport function getTopupInfo(wallet: WalletData): string {\n return JSON.stringify({\n wallet_address: wallet.address,\n network: \"Base (Chain ID 8453)\",\n token: \"USDC\",\n contract: USDC_ADDRESS,\n instructions: [\n `Send USDC on Base network to: ${wallet.address}`,\n ],\n });\n}\n","import { createServer, type Server } from \"node:http\";\nimport { readFileSync } from \"node:fs\";\nimport { join, dirname } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { isAddress } from \"viem\";\nimport type { WalletData } from \"./types.js\";\nimport { generateQrSvg } from \"./qr.js\";\nimport { getBalanceEth, getBalanceUsdc } from \"./tools.js\";\n\nconst USDC_ADDRESS = \"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913\";\nconst BASE_CHAIN_ID = \"0x2105\"; // 8453\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\n// Pre-load assets — try dist/assets first (installed), then src/assets (dev)\nfunction loadAsset(name: string): Buffer {\n const paths = [\n join(__dirname, \"assets\", name), // dist/assets/ (global install)\n join(__dirname, \"..\", \"src\", \"assets\", name), // src/assets/ (dev)\n ];\n for (const p of paths) {\n try { return readFileSync(p); } catch { /* try next */ }\n }\n console.error(`[chain-insights] Warning: asset ${name} not found`);\n return Buffer.alloc(0);\n}\n\nconst logoPng = loadAsset(\"logo.png\");\nconst bgPatternPng = loadAsset(\"bg-pattern.png\");\n\nlet server: Server | null = null;\nlet serverPort: number | null = null;\n\nfunction assertWalletAddress(wallet: WalletData | string): string {\n const walletAddress = typeof wallet === \"string\" ? wallet : wallet.address;\n if (!isAddress(walletAddress)) {\n throw new Error(\"Wallet address must be a valid 0x-prefixed 20-byte EVM address\");\n }\n return walletAddress;\n}\n\nfunction escapeHtml(value: string): string {\n return value\n .replaceAll(\"&\", \"&amp;\")\n .replaceAll(\"<\", \"&lt;\")\n .replaceAll(\">\", \"&gt;\")\n .replaceAll('\"', \"&quot;\")\n .replaceAll(\"'\", \"&#39;\");\n}\n\nfunction jsonForScript(value: string): string {\n return JSON.stringify(value)\n .replaceAll(\"<\", \"\\\\u003c\")\n .replaceAll(\">\", \"\\\\u003e\")\n .replaceAll(\"&\", \"\\\\u0026\");\n}\n\nexport function getTopupUrl(): string | null {\n return serverPort ? `http://localhost:${serverPort}` : null;\n}\n\nexport async function startTopupServer(wallet: WalletData | string): Promise<string> {\n const walletAddress = assertWalletAddress(wallet);\n\n if (server && serverPort) {\n return `http://localhost:${serverPort}`;\n }\n\n return new Promise((resolve, reject) => {\n server = createServer((req, res) => {\n if (req.url === \"/api/wallet\") {\n res.writeHead(200, { \"Content-Type\": \"application/json\", \"Access-Control-Allow-Origin\": \"*\" });\n res.end(JSON.stringify({ address: walletAddress }));\n return;\n }\n\n if (req.url === \"/api/balance\") {\n Promise.all([getBalanceUsdc(walletAddress), getBalanceEth(walletAddress)]).then(([balanceUsdc, balanceEth]) => {\n res.writeHead(200, { \"Content-Type\": \"application/json\", \"Access-Control-Allow-Origin\": \"*\" });\n res.end(JSON.stringify({ balance_usdc: balanceUsdc, balance_eth: balanceEth }));\n }).catch(() => {\n res.writeHead(200, { \"Content-Type\": \"application/json\", \"Access-Control-Allow-Origin\": \"*\" });\n res.end(JSON.stringify({ balance_usdc: \"unknown\", balance_eth: \"unknown\" }));\n });\n return;\n }\n\n if (req.url === \"/assets/logo.png\") {\n res.writeHead(200, { \"Content-Type\": \"image/png\", \"Cache-Control\": \"public, max-age=86400\", \"Access-Control-Allow-Origin\": \"*\" });\n res.end(logoPng);\n return;\n }\n\n if (req.url === \"/assets/bg-pattern.png\") {\n res.writeHead(200, { \"Content-Type\": \"image/png\", \"Cache-Control\": \"public, max-age=86400\", \"Access-Control-Allow-Origin\": \"*\" });\n res.end(bgPatternPng);\n return;\n }\n\n res.writeHead(200, { \"Content-Type\": \"text/html\" });\n res.end(generatePage(walletAddress));\n });\n\n server.listen(0, \"127.0.0.1\", () => {\n const addr = server!.address();\n if (addr && typeof addr === \"object\") {\n serverPort = addr.port;\n const url = `http://localhost:${serverPort}`;\n console.error(`[chain-insights] Topup server running at ${url}`);\n resolve(url);\n } else {\n reject(new Error(\"Failed to start topup server\"));\n }\n });\n\n server.on(\"error\", reject);\n });\n}\n\nexport function generateArtifactHtml(walletAddressInput: string, topupUrl: string): string {\n const walletAddress = assertWalletAddress(walletAddressInput);\n const safeWalletAddress = escapeHtml(walletAddress);\n const safeTopupUrl = escapeHtml(topupUrl);\n const topupUrlJson = jsonForScript(topupUrl);\n\n const LOGO_B64 = \"data:image/png;base64,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\";\n\n // Generate QR code SVG server-side — standard B&W, 2x size\n const qrSvg = generateQrSvg(walletAddress, { cellSize: 8 });\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<style>\n * { margin: 0; padding: 0; box-sizing: border-box; }\n body {\n font-family: Inter, -apple-system, BlinkMacSystemFont, sans-serif;\n background: rgba(10, 12, 17, 1) url('${safeTopupUrl}/assets/bg-pattern.png') top left / contain no-repeat;\n color: rgba(255, 255, 255, 0.9);\n display: flex;\n justify-content: center;\n padding: 24px;\n line-height: 1.3;\n }\n .card {\n max-width: 400px;\n width: 100%;\n background: rgba(19, 19, 24, 1);\n border: 1px solid rgba(255, 255, 255, 0.06);\n border-radius: 12px;\n padding: 28px 24px;\n text-align: center;\n }\n .logo { margin-bottom: 8px; }\n .logo img { height: 24px; }\n .subtitle { color: rgba(255, 255, 255, 0.5); font-size: 13px; margin-bottom: 20px; }\n .qr { margin-bottom: 16px; }\n .qr svg { border-radius: 12px; background: #fff; padding: 10px; }\n .address-wrap {\n position: relative;\n margin-bottom: 16px;\n }\n .address {\n width: 100%;\n background: rgba(10, 12, 17, 1);\n border: 1px solid rgba(255, 255, 255, 0.06);\n border-radius: 8px;\n padding: 10px 14px;\n font-family: 'SF Mono', 'Fira Code', monospace;\n font-size: 11px; color: #f2dda6; word-break: break-all;\n cursor: pointer; text-align: center;\n transition: border-color 0.3s linear;\n -webkit-user-select: all; user-select: all;\n outline: none;\n }\n .address:focus { border-color: #ae9d71; }\n .address-hint {\n font-size: 10px; color: rgba(255,255,255,0.3);\n text-align: center; margin-top: 4px;\n }\n .badge {\n display: inline-flex; align-items: center; gap: 6px;\n background: rgba(255, 255, 255, 0.04);\n border: 1px solid rgba(255, 255, 255, 0.06);\n border-radius: 20px; padding: 5px 12px;\n font-size: 11px; color: rgba(255, 255, 255, 0.5); margin-bottom: 20px;\n }\n .badge .dot { width: 7px; height: 7px; border-radius: 50%; background: #f2dda6; }\n .balance-line {\n font-size: 13px;\n color: rgba(255, 255, 255, 0.5);\n margin-bottom: 20px;\n line-height: 1.4;\n }\n .balance-line .amount {\n color: #4feb69;\n font-weight: 600;\n }\n .balance-line .gas {\n color: #f2dda6;\n font-weight: 600;\n }\n @keyframes flash { 0%{opacity:0.4} 100%{opacity:1} }\n .balance-line.flash .amount { animation: flash 1s ease-out; }\n .hint {\n margin-top: 14px; font-size: 12px;\n color: rgba(255, 255, 255, 0.3);\n line-height: 1.5;\n }\n</style>\n</head>\n<body>\n<div class=\"card\">\n <div class=\"logo\"><img src=\"${safeTopupUrl}/assets/logo.png\" alt=\"Chain Insights\"></div>\n <p class=\"subtitle\">Fund your wallet with USDC on Base</p>\n <div class=\"qr\">${qrSvg}</div>\n <div class=\"address-wrap\">\n <div class=\"address\" id=\"addr\" onclick=\"selectAndCopy()\">${safeWalletAddress}</div>\n <div class=\"address-hint\" id=\"addrHint\">Click to copy address</div>\n </div>\n <div class=\"badge\"><span class=\"dot\"></span>Base Network &middot; USDC</div>\n <p class=\"balance-line\" id=\"balLine\">Current balance: <span class=\"amount\" id=\"bal\">--</span> USDC<br>Gas balance: <span class=\"gas\" id=\"gas\">--</span> ETH<br>Base ETH is used for one-time approval gas.</p>\n</div>\n<script>\n// MCP Apps protocol handshake (matches @modelcontextprotocol/ext-apps App.connect())\n(function() {\n var initId = 1;\n\n // Listen for host messages\n window.addEventListener('message', function(event) {\n var data = event.data;\n if (!data || data.jsonrpc !== '2.0') return;\n\n // Initialize response\n if (data.id === initId && data.result) {\n // Send initialized notification\n window.parent.postMessage({\n jsonrpc: '2.0',\n method: 'ui/notifications/initialized',\n params: {}\n }, '*');\n\n // Send initial size\n var rect = document.documentElement.getBoundingClientRect();\n window.parent.postMessage({\n jsonrpc: '2.0',\n method: 'ui/notifications/size-changed',\n params: { width: Math.ceil(rect.width), height: Math.ceil(rect.height) }\n }, '*');\n }\n\n // Respond to pings\n if (data.method === 'ping' && data.id != null) {\n window.parent.postMessage({\n jsonrpc: '2.0',\n id: data.id,\n result: {}\n }, '*');\n }\n });\n\n // Send initialize request (must match App class protocol)\n window.parent.postMessage({\n jsonrpc: '2.0',\n id: initId,\n method: 'ui/initialize',\n params: {\n appInfo: { name: 'Chain Insights Topup', version: '1.0.0' },\n appCapabilities: {},\n protocolVersion: '2026-01-26'\n }\n }, '*');\n})();\n\n// Live balance polling\nvar lastBal = null;\nvar TOPUP_URL = ${topupUrlJson};\nfunction fetchBal() {\n fetch(TOPUP_URL + '/api/balance')\n .then(function(r) { return r.json(); })\n .then(function(d) {\n var el = document.getElementById('bal');\n var gas = document.getElementById('gas');\n var line = document.getElementById('balLine');\n var val = parseFloat(d.balance_usdc || '0').toFixed(2);\n var gasVal = d.balance_eth === 'unknown' ? '--' : parseFloat(d.balance_eth || '0').toFixed(6);\n if (d.balance_usdc === 'unknown') { el.textContent = '--'; gas.textContent = gasVal; return; }\n el.textContent = val;\n gas.textContent = gasVal;\n if (lastBal !== null && val !== lastBal) {\n line.classList.remove('flash');\n void line.offsetWidth;\n line.classList.add('flash');\n }\n lastBal = val;\n })\n .catch(function() {});\n}\nfetchBal();\nsetInterval(fetchBal, 10000);\n\nfunction selectAndCopy() {\n var addr = document.getElementById('addr');\n var hint = document.getElementById('addrHint');\n // Select the text\n var r = document.createRange();\n r.selectNodeContents(addr);\n var s = window.getSelection();\n s.removeAllRanges();\n s.addRange(r);\n // Try every clipboard method available\n var copied = false;\n try { copied = document.execCommand('copy'); } catch(e) {}\n if (!copied && navigator.clipboard && navigator.clipboard.writeText) {\n navigator.clipboard.writeText(addr.textContent).then(function() {\n hint.textContent = 'Copied!'; hint.style.color = '#4feb69';\n setTimeout(function() { hint.textContent = 'Click to copy address'; hint.style.color = ''; }, 2000);\n }).catch(function() {});\n }\n if (copied) {\n hint.textContent = 'Copied!'; hint.style.color = '#4feb69';\n setTimeout(function() { hint.textContent = 'Click to copy address'; hint.style.color = ''; }, 2000);\n } else {\n hint.textContent = 'Selected — press Ctrl+C'; hint.style.color = '#f2dda6';\n setTimeout(function() { hint.textContent = 'Click to copy address'; hint.style.color = ''; }, 3000);\n }\n}\n<\\/script>\n</body>\n</html>`;\n}\n\nfunction generatePage(walletAddressInput: string): string {\n const walletAddress = assertWalletAddress(walletAddressInput);\n const safeWalletAddress = escapeHtml(walletAddress);\n const walletAddressJson = jsonForScript(walletAddress);\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>Chain Insights — Fund Wallet</title>\n<script src=\"https://cdn.jsdelivr.net/npm/qrcode-generator@1.4.4/qrcode.min.js\"></script>\n<style>\n * { margin: 0; padding: 0; box-sizing: border-box; }\n\n body {\n font-family: Inter, -apple-system, BlinkMacSystemFont, sans-serif;\n background: rgba(10, 12, 17, 1);\n color: rgba(255, 255, 255, 0.9);\n min-height: 100vh;\n display: flex;\n justify-content: center;\n align-items: center;\n line-height: 1.3;\n }\n\n .container {\n max-width: 480px;\n width: 100%;\n padding: 24px;\n }\n\n .logo {\n text-align: center;\n margin-bottom: 32px;\n }\n\n .logo h1 {\n font-size: 24px;\n font-weight: 600;\n color: #f2dda6;\n letter-spacing: -0.5px;\n }\n\n .logo p {\n color: rgba(255, 255, 255, 0.5);\n font-size: 14px;\n margin-top: 4px;\n }\n\n .card {\n background: rgba(19, 19, 24, 1);\n border: 1px solid rgba(255, 255, 255, 0.06);\n border-radius: 12px;\n padding: 32px 24px;\n }\n\n .qr-container {\n display: flex;\n justify-content: center;\n margin-bottom: 24px;\n }\n\n .qr-container canvas, .qr-container img {\n border-radius: 12px;\n background: #fff;\n padding: 12px;\n }\n\n .address-box {\n background: rgba(10, 12, 17, 1);\n border: 1px solid rgba(255, 255, 255, 0.06);\n border-radius: 8px;\n padding: 12px 16px;\n display: flex;\n align-items: center;\n gap: 8px;\n margin-bottom: 24px;\n }\n\n .address-box code {\n font-family: 'SF Mono', 'Fira Code', monospace;\n font-size: 12px;\n color: #f2dda6;\n word-break: break-all;\n flex: 1;\n }\n\n .copy-btn {\n background: none;\n border: none;\n color: rgba(255, 255, 255, 0.4);\n cursor: pointer;\n padding: 4px;\n font-size: 18px;\n transition: color 0.3s linear;\n }\n\n .copy-btn:hover { color: #f2dda6; }\n .copy-btn.copied { color: #4feb69; }\n\n .network-badge {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n background: rgba(255, 255, 255, 0.04);\n border: 1px solid rgba(255, 255, 255, 0.06);\n border-radius: 20px;\n padding: 6px 12px;\n font-size: 12px;\n color: rgba(255, 255, 255, 0.5);\n margin-bottom: 24px;\n }\n\n .network-badge .dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background: #f2dda6;\n }\n\n .balance-row {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 12px 0;\n border-top: 1px solid rgba(255, 255, 255, 0.06);\n margin-bottom: 16px;\n }\n\n .balance-label { color: rgba(255, 255, 255, 0.5); font-size: 14px; }\n\n .balance-value {\n font-size: 20px;\n font-weight: 600;\n color: rgba(255, 255, 255, 0.9);\n }\n\n .balance-value .currency {\n font-size: 14px;\n color: rgba(255, 255, 255, 0.5);\n font-weight: 400;\n margin-left: 4px;\n }\n\n .gas-note {\n margin-top: -8px;\n margin-bottom: 16px;\n color: rgba(255,255,255,0.45);\n font-size: 12px;\n line-height: 1.4;\n text-align: left;\n }\n\n .metamask-btn {\n width: 100%;\n padding: 14px;\n border: none;\n border-radius: 10px;\n font-size: 15px;\n font-weight: 600;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 10px;\n transition: all 0.2s;\n background: #f6851b;\n color: #fff;\n }\n\n .metamask-btn:hover { background: #e2761b; transform: translateY(-1px); }\n .metamask-btn:disabled { opacity: 0.5; cursor: not-allowed; transform: none; }\n\n .metamask-btn svg { width: 22px; height: 22px; }\n\n .amount-input {\n width: 100%;\n padding: 12px 16px;\n background: #0a0c11;\n border: 1px solid rgba(255, 255, 255, 0.06);\n border-radius: 8px;\n color: rgba(255, 255, 255, 0.9);\n font-size: 16px;\n margin-bottom: 16px;\n outline: none;\n transition: border-color 0.2s;\n }\n\n .amount-input:focus { border-color: #f2dda6; }\n\n .amount-label {\n font-size: 13px;\n color: rgba(255, 255, 255, 0.5);\n margin-bottom: 6px;\n display: block;\n }\n\n .status {\n text-align: center;\n padding: 12px;\n border-radius: 8px;\n font-size: 14px;\n margin-top: 16px;\n display: none;\n }\n\n .status.success { display: block; background: #0a2e1a; color: #4feb69; border: 1px solid #1a4a2e; }\n .status.error { display: block; background: #2e0a0a; color: #eb4f4f; border: 1px solid #4a1a1a; }\n .status.pending { display: block; background: #1a1a0a; color: #f2dda6; border: 1px solid #4a4a1a; }\n\n .info {\n text-align: center;\n margin-top: 24px;\n font-size: 12px;\n color: rgba(255, 255, 255, 0.3);\n line-height: 1.6;\n }\n</style>\n</head>\n<body>\n<div class=\"container\">\n <div class=\"logo\">\n <h1>Chain Insights</h1>\n <p>Fund your wallet to use blockchain intelligence tools</p>\n </div>\n\n <div class=\"card\">\n <div class=\"qr-container\" id=\"qr\"></div>\n\n <div class=\"address-box\">\n <code id=\"address\">${safeWalletAddress}</code>\n <button class=\"copy-btn\" onclick=\"copyAddress()\" id=\"copyBtn\" title=\"Copy address\">&#x2398;</button>\n </div>\n\n <div class=\"network-badge\">\n <span class=\"dot\"></span>\n Base Network &middot; USDC\n </div>\n\n <div class=\"balance-row\">\n <span class=\"balance-label\">Current balance</span>\n <span class=\"balance-value\" id=\"balance\">—<span class=\"currency\">USDC</span></span>\n </div>\n <div class=\"balance-row\">\n <span class=\"balance-label\">Gas balance</span>\n <span class=\"balance-value\" id=\"gasBalance\">—<span class=\"currency\">ETH</span></span>\n </div>\n <p class=\"gas-note\">Base ETH is used for one-time approval gas.</p>\n\n <div class=\"status\" id=\"status\"></div>\n </div>\n\n <p class=\"info\">Send Base USDC to the wallet address above.</p>\n</div>\n\n<script>\nconst WALLET = ${walletAddressJson};\nconst USDC = '${USDC_ADDRESS}';\nconst CHAIN_ID = '${BASE_CHAIN_ID}';\n\n// QR code\n(function() {\n var qr = qrcode(0, 'M');\n qr.addData(WALLET);\n qr.make();\n document.getElementById('qr').innerHTML = qr.createSvgTag(5, 0);\n var svg = document.querySelector('#qr svg');\n if (svg) { svg.style.borderRadius = '12px'; svg.style.background = '#fff'; svg.style.padding = '12px'; }\n})();\n\n// Copy address — fallback for sandboxed iframes where navigator.clipboard is blocked\nfunction copyAddress() {\n var ok = false;\n // Try modern clipboard API first\n if (navigator.clipboard && navigator.clipboard.writeText) {\n navigator.clipboard.writeText(WALLET).then(function() { ok = true; }).catch(function() {});\n }\n // Fallback: hidden textarea + execCommand\n if (!ok) {\n var ta = document.createElement('textarea');\n ta.value = WALLET;\n ta.style.position = 'fixed';\n ta.style.left = '-9999px';\n document.body.appendChild(ta);\n ta.select();\n try { document.execCommand('copy'); } catch(e) {}\n document.body.removeChild(ta);\n }\n var btn = document.getElementById('copyBtn');\n btn.classList.add('copied');\n btn.innerHTML = '&#x2713;';\n setTimeout(function() { btn.classList.remove('copied'); btn.innerHTML = '&#x2398;'; }, 2000);\n}\n\n// Fetch balance\nasync function fetchBalance() {\n try {\n var resp = await fetch('/api/balance');\n var json = await resp.json();\n if (json.balance_usdc === 'unknown') throw new Error('balance unavailable');\n var balance = Number(json.balance_usdc || 0).toFixed(2);\n document.getElementById('balance').innerHTML = balance + '<span class=\"currency\">USDC</span>';\n var gasBalance = json.balance_eth === 'unknown' ? '—' : Number(json.balance_eth || 0).toFixed(6);\n document.getElementById('gasBalance').innerHTML = gasBalance + '<span class=\"currency\">ETH</span>';\n } catch(e) {\n document.getElementById('balance').innerHTML = '—<span class=\"currency\">USDC</span>';\n document.getElementById('gasBalance').innerHTML = '—<span class=\"currency\">ETH</span>';\n }\n}\nfetchBalance();\nsetInterval(fetchBalance, 15000);\n\n</script>\n</body>\n</html>`;\n}\n","import {\n generateArtifactHtml,\n getTopupUrl as getCopiedTopupUrl,\n startTopupServer as startCopiedTopupServer,\n} from './mcp-proxy/topup-server.js'\nimport { createServer, type Server, type ServerResponse } from 'node:http'\nimport { isAddress } from 'viem'\nimport type { PaymentWalletAccount } from './tools.js'\n\ninterface ArtifactServerState {\n address: string\n assetServerUrl: string\n server: Server\n url: string\n}\n\nlet artifactServerState: ArtifactServerState | null = null\nconst REQUEST_TARGET_BASE = 'http://localhost'\n\nclass ProxyRequestError extends Error {\n status: number\n\n constructor(status: number, message: string) {\n super(message)\n this.name = 'ProxyRequestError'\n this.status = status\n }\n}\n\ninterface NormalizedProxyTarget {\n pathAndSearch: string\n pathname: string\n}\n\nfunction toWalletAddress(account: PaymentWalletAccount | string): string {\n const address = typeof account === 'string' ? account : account.address\n if (!isAddress(address)) {\n throw new Error('Wallet address must be a valid 0x-prefixed 20-byte EVM address')\n }\n return address\n}\n\nfunction send(res: ServerResponse, status: number, body: string | Buffer, contentType: string): void {\n res.writeHead(status, {\n 'content-type': contentType,\n 'cache-control': 'no-store',\n 'access-control-allow-origin': '*',\n })\n res.end(body)\n}\n\nfunction normalizeProxyTarget(reqUrl: string): NormalizedProxyTarget {\n if (!reqUrl.startsWith('/') || reqUrl.startsWith('//')) {\n throw new ProxyRequestError(400, 'Proxy request target must be an origin-form path')\n }\n\n const parsed = new URL(reqUrl, REQUEST_TARGET_BASE)\n if (parsed.origin !== REQUEST_TARGET_BASE) {\n throw new ProxyRequestError(400, 'Absolute and protocol-relative proxy targets are not allowed')\n }\n\n let decodedPathname: string\n try {\n decodedPathname = decodeURIComponent(parsed.pathname)\n } catch {\n throw new ProxyRequestError(400, 'Proxy request target contains invalid encoding')\n }\n\n if (decodedPathname.startsWith('//') || /^\\/[a-z][a-z0-9+.-]*:\\/\\//i.test(decodedPathname)) {\n throw new ProxyRequestError(400, 'Encoded host override targets are not allowed')\n }\n\n return {\n pathAndSearch: `${parsed.pathname}${parsed.search}`,\n pathname: parsed.pathname,\n }\n}\n\nasync function proxyToCopiedServer(\n proxyTarget: NormalizedProxyTarget,\n res: ServerResponse,\n assetServerUrl: string,\n): Promise<void> {\n const allowedOrigin = new URL(assetServerUrl).origin\n const upstreamUrl = new URL(proxyTarget.pathAndSearch, assetServerUrl)\n if (upstreamUrl.origin !== allowedOrigin) {\n throw new ProxyRequestError(403, 'Upstream origin is not allowed')\n }\n\n const upstream = await fetch(upstreamUrl)\n const contentType = upstream.headers.get('content-type') ?? 'application/octet-stream'\n const body = Buffer.from(await upstream.arrayBuffer())\n send(res, upstream.status, body, contentType)\n}\n\nexport { generateArtifactHtml }\n\nexport function getTopupArtifactUrl(): string | null {\n return artifactServerState?.url ?? null\n}\n\nexport function getTopupUrl(): string | null {\n return getTopupArtifactUrl() ?? getCopiedTopupUrl()\n}\n\nexport async function stopTopupServer(): Promise<void> {\n if (!artifactServerState) {\n return\n }\n\n const { server } = artifactServerState\n artifactServerState = null\n await new Promise<void>((resolve) => server.close(() => resolve()))\n}\n\nexport async function startTopupServer(account: PaymentWalletAccount | string): Promise<string> {\n const walletAddress = toWalletAddress(account)\n\n if (artifactServerState && artifactServerState.address.toLowerCase() === walletAddress.toLowerCase()) {\n return artifactServerState.url\n }\n\n const assetServerUrl = await startCopiedTopupServer(walletAddress)\n\n if (artifactServerState) {\n await stopTopupServer()\n }\n\n const server = createServer((req, res) => {\n const reqUrl = req.url ?? '/'\n let proxyTarget: NormalizedProxyTarget\n try {\n proxyTarget = normalizeProxyTarget(reqUrl)\n } catch (err) {\n if (err instanceof ProxyRequestError) {\n send(res, err.status, JSON.stringify({ error: err.message }) + '\\n', 'application/json; charset=utf-8')\n return\n }\n send(res, 400, JSON.stringify({ error: 'Invalid request target' }) + '\\n', 'application/json; charset=utf-8')\n return\n }\n const { pathname } = proxyTarget\n\n if (pathname === '/' || pathname === '/index.html') {\n const artifactUrl = artifactServerState?.url ?? assetServerUrl\n send(res, 200, generateArtifactHtml(walletAddress, artifactUrl), 'text/html; charset=utf-8')\n return\n }\n\n if (pathname.startsWith('/assets/') || pathname.startsWith('/api/')) {\n void proxyToCopiedServer(proxyTarget, res, assetServerUrl).catch((err) => {\n if (err instanceof ProxyRequestError) {\n send(res, err.status, JSON.stringify({ error: err.message }) + '\\n', 'application/json; charset=utf-8')\n return\n }\n send(res, 502, JSON.stringify({ error: (err as Error).message }) + '\\n', 'application/json; charset=utf-8')\n })\n return\n }\n\n send(res, 404, JSON.stringify({ error: 'Not found' }) + '\\n', 'application/json; charset=utf-8')\n })\n\n const url = await new Promise<string>((resolve, reject) => {\n server.once('error', reject)\n server.listen(0, '127.0.0.1', () => {\n const addressInfo = server.address()\n if (!addressInfo || typeof addressInfo === 'string') {\n reject(new Error('Failed to start topup artifact server'))\n return\n }\n resolve(`http://localhost:${addressInfo.port}`)\n })\n })\n\n artifactServerState = {\n address: walletAddress,\n assetServerUrl,\n server,\n url,\n }\n\n return url\n}\n"],"mappings":"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"}