chain-insights 0.2.26 → 0.2.27
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.
- package/README.md +3 -0
- package/dist/{capabilities-mXm_rCe8.mjs → capabilities-BCm-2oBt.mjs} +2 -2
- package/dist/{capabilities-mXm_rCe8.mjs.map → capabilities-BCm-2oBt.mjs.map} +1 -1
- package/dist/{capabilities-B4hvro_I.cjs → capabilities-C1-Y-VZx.cjs} +1 -1
- package/dist/cli.cjs +13 -13
- package/dist/cli.mjs +14 -14
- package/dist/cli.mjs.map +1 -1
- package/dist/{client-Dl-uHrh1.mjs → client-Bfw9P9uA.mjs} +3 -3
- package/dist/client-Bfw9P9uA.mjs.map +1 -0
- package/dist/{client-BYnFGA0y.cjs → client-DRJq31u_.cjs} +2 -2
- package/dist/index.cjs +3 -3
- package/dist/index.mjs +3 -3
- package/dist/{init-jhOZ_RvC.cjs → init-CFaUWgjK.cjs} +1 -1
- package/dist/{init-CB_ga4_8.mjs → init-DBC9Ml33.mjs} +2 -2
- package/dist/{init-CB_ga4_8.mjs.map → init-DBC9Ml33.mjs.map} +1 -1
- package/dist/mcp-proxy.cjs +3 -3
- package/dist/mcp-proxy.mjs +3 -3
- package/dist/{runner-BBH5Ks6q.mjs → runner-C-QgZu-S.mjs} +2 -2
- package/dist/{runner-BBH5Ks6q.mjs.map → runner-C-QgZu-S.mjs.map} +1 -1
- package/dist/{runner-e9slg6R2.cjs → runner-Ckl96RcN.cjs} +1 -1
- package/dist/{tools-D6RBAhSX.mjs → tools-6emZlUwg.mjs} +6 -6
- package/dist/tools-6emZlUwg.mjs.map +1 -0
- package/dist/{tools-UH5hRXYG.cjs → tools-kqWI7jPU.cjs} +5 -5
- package/dist/{topup-server-yAaXYkJP.cjs → topup-server-DhYlOOBM.cjs} +2 -2
- package/dist/{topup-server-BJgVw6Jt.mjs → topup-server-R3dNp-p8.mjs} +3 -3
- package/dist/topup-server-R3dNp-p8.mjs.map +1 -0
- package/docs/mcp-proxy.md +5 -2
- package/package.json +1 -1
- package/dist/client-Dl-uHrh1.mjs.map +0 -1
- package/dist/tools-D6RBAhSX.mjs.map +0 -1
- package/dist/topup-server-BJgVw6Jt.mjs.map +0 -1
|
@@ -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(\"&\", \"&\")\n .replaceAll(\"<\", \"<\")\n .replaceAll(\">\", \">\")\n .replaceAll('\"', \""\")\n .replaceAll(\"'\", \"'\");\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,iVBORw0KGgoAAAANSUhEUgAAAMEAAAAeCAYAAACVKnpmAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAA2JSURBVHgB7VxNUhtJFn6ZWSCYNkKsJqI3I43t7phVwwksTmCI2djgDsQJLE6AOAFwAuToBnozgTiB5ROgWU1M27TkTUf0Cln0BH9V+ea9rCqpVD+SQMaWHfoiJJVKVZkvf97/KwkYEGf1vYwF02tC47wGyIPADCBkzI8CmkJDgz4bQkLlBsSbudzzBowxxhcA0e+C87eHeVCwiYh5uAUEiqpQWH6QW3kFY4wxwkhkgrP6YdZC2Eva/Agk9Unym2OELDWUje1AQM0WYnmsGcYYVcQyQevdfgGk2G6bOz4QqvReds6vjucW1pvBn85O9jLwzeSSssQaXZfvbhGbCLg1+/DFDowxxoghwgQfTvdLAsRm8BxJ/aa2nfW573+swAA4+3W/IJXYDGsH1MQIj1dLMMYYI4QuJvhwelCkE9vBc2z26Ourxbl/rDfgFjj7z15WTqZeRxgB9MZYI4wxSmgzAfsASmM9fIHj4MLcd6s1uAPO6vvzSouTj9EmO+go8alhKhQZ9kdQipoNeBznb3jXv+bjielUdvrbf76He4QZ642c5+P0d8/LcA9ovTtYAi0oKofN9PcrA2nljwWzP25cM9f532UlbA7fFp96fXpB+gcKXYKCIDu+dFcGYMzlVmtCilL4PPkNR8aHGAA8Wa3fDurehBVJMy2hwLwGLKDWO8y4rdPDvUHbuy9YWj6lSdwzr3sCzeVL077Vra0/BSybhI83PiuT+gE+M85/O3xN614/r//yEoaEYQLjCGPYbGEz6Hro8KYNl7ucR4DuxrNWeqov8eyfmM3v0ca+CX1UzEsYJ91vsKBmUyefmxHG+HSgqGWW3rOgceg1t8y7JEcYu38QgNWgHxBMlgWvI4ncdKTYTQqBzuXWm63TgzIdFoPnyTfg71uQgNa7n5bAc9CZIaWEQjq38iZ4DfsdajLFUnEpwFiJbd4n7Nbl7tRfJ8rwlWLm8fPqxe8/Z/n48o+bD/AVwTK2meGqbpDqLQe/Kz21TRu3oBHIxOlIds4RKK0LJIVzSXaio51jJVUx1EPm7O1P+bnHP1bj7gGpOETbdsxnYxxzj0mXyVxibZFnxiI6dpPoYEaeuJnMopAZgbr5oI+pF7zetqDRK9fh9dnXTr4tDXdBsA/+zhu41/UXZO/btqtte9E0/e2L94P2e5ex3cfcDNKmxc5m3M0zIalL2zFPbzuzj1Y2ujpxpXF9YibF7cSbT5ZdA60ip4kx+J5q+LxxANFfFCj1i0yRk1wiRi6YL1MmtxHZjCb0i+IlkZEx3g7pOmKehmPjctjv4YmTerIYvF5pskPfHdRsJZbJDyGNI5aY9vTD5+ttmoXYJnobM4+eL7rtcLABPOdvMn99cbkhtGkTumi4cTYGDT/HgW1j/nQcvUyh6TzRsOnTbX6nPhD1bjgq50YDxcsbTULQ8w59muig4rSutnyBEhwL9xOcs7j5ao/NcdYta+IHCo8Xg3Nzl/UJ0mBMIX4XWKTxF/hYSVH8Jvfs2L12f5429zb1m++a79MDOhZlR8KWL9QsIcQ8baAuguhrLAfKwHk2V4RQaxyp4eZRQvH83WEBKWrjtC43gtLYM4kaEA6XRpJqHgQ88Q85MQd94DHsm/hfsUmbb93kPjD8E2kxBa+DWsxMtBskyPrXsy9CUakMjY2iXfpEgNxBXoSgH8W2qQKSOJH+swEaon4Q02CpI8qtLNw9COFuCEvJpxzMiBsn0bxNmrfma143HwSb7uag8Ql3bU323x1XUc2k2PRdjPQzIWb9M8ZMxsnXtMHmY+dXqteonTItaszcmIv6r0/9cKGjhUNWi0noun4BOu6nF+k8QW9s9MY1bU3UwFHFeeND0t6j6xa5XdrX3TY+Q/RR69wJCHWk2YwiB5UGQBMvKih0w3QwkzqKuS2ywERQrFPDjOkNsDpsKI5QofbWaDJ2JqZ1Nv1wRTjXVzlwHWzuLWOlJ9f8i0nSbHYccSyRNJybfbgyx/eQ1izx9WR2ZeF2aNNAi5EP0NCWzEqJNRgGnM0XuGT68vsg2l2avT6kajMh0+PTxuNL/31lkV90nHO0drW9oI1CJmuvbkkDkBZ21ys8x52+JUSCIx30Xx+tPWvlsslj4xd9aXgDL/vnbjyBadYQPFO6dZUj62XBjI0+TdvCMEbW1ejsGGPMRhSiAT2gbjQX1TX1+fXibGiTntcPG6SCCtG7RBMirB5fb/RRIQSbVmVa3LYZx+YVSbB1hak8jx/Bje8b5vZoZwaYfbi6FbyHPrZap/tZr83bEFEgEUs0rG6E2tsglV/w1iALw4A2rNZYm320utzuw12bLeojb0pZutfarwDO/Pnr/nzQVp57/GKHnGAjyJw/7EQnmLUAm3fut9jxbdF+4EoBXztFGcHMJVbC98atD1sU4Gl816xh8mVjJvf8TfyUYMZ6MMX3VrvaJs1PQYxZ38G34BZAIbL8mf5utUwfZXcivCSblkvpx8+O8Ua/B9W3OLV3P5QMMp8Aw4c8aRIpORfxVXhCz9lWBmhrQuWQVvRI163r3bjmSEq+IolagFsiHGgI0FcFN7o19FhJI+8k9MEbPB88RXb9lpKSgw9kM4sTYpQmbega2dg1isTVLq/6l8Nb9tQ8SXuvPYidLw6RK5EqJo7PrE/03rj1GRSO1LsKmblIa1OInRlG8BxwwaeUVU6wTn/bGZvsoaa6wRlako7npwdHf1Jyyn/5STbHvvg33BqY1HfDdEn228eI/U89mDqL/0V099+JOTcSzTDLasAdYN/gh4FoGAJC+SZC6HxMHyztSTiwU1/x7OYMJyHpe1FrKLNg+/B2vwQ9QM52tt1egj9jpDf23mMDr8+A4CStc3W1wNoJvb3E/pxJtMYkWKWA6MSRJI5wHzXKE8YOYZN9AQ16iV58cZXtsQEiONloP/FmF4dU/eNBkmomq0wREn6d/ZfzC0Mjm8R8ln03syV5oT8faOOWyQZfNj6PxAWSkkvBjUPaa/PP+kGyryI7m7SnsBIfQaPfErwf0w9X142PQ36A8RvId8WOL1FQ6ZTxHSzaiMTB3ZteiGjewLdh+bj1K2WYFcw7Um5FVKaST3xzJohYB5xUL8QNgCIYpJ6rbuwfSxQ5Oe4ZOVHszHo0azv5uj5wJmSVpIT75S9WHtrOWQcUBRvOgR0BsC2vbqaMsHAmKPhAa8jSE9zgxbH5HVN11g5aizwkhL4ddUXzlTLHXnAhYtZ4eahPygR+jZVD1ssc5Ui8vcsv9h3Yr9szfhqbobSnpaPtmAGKzMXv//pbUifOxHWFRTubQhQWDbwOTpjDuksaPIczzibUqpLYh8AN31SjyMkJq2bTTgA8wVxD0nnwB8u3rXYNwjC0R7uaUNvh/jisaMZH/cAXDGOiWLjNdUC0AY7C4/TgCbJEk9Vtx5svEh0srLoEHbeLppaK5mtQs3tACK89jAsoCBJU1K+iV/zY3KQIemaaZRJZqJrhTWpfXBcgoQSBB09JsgVrcmqtuxhbcEKCogTPuiSCciiaJLqdZVZLs4+fJeYAWDJReG5ZKXXEtLFqJim9SSZPw+0KM0bCdGL5XOs0dMkEm30qlToxITTEOjF31VSskjnnMxtHJPB24aGRg+8YcziabWR/nPwbmbttR52fGe/ZDs2XWzIvOKZ/0jVfOvBUIsYnMe8MISpgzHYskONb8GjNc86ITLstcozznTU8qNE4vTwIzretEoFmbJbxwuuHO/RjKdgHOUnccOKm8kNgMAhiapMGkaZsFjGzteuD3Puy7kegJfJVdCC7OQxMCI369J+FYGcRA/3RBBYBxK0jFqMGdozP3v5MboB82TVOBvrFilhK51bf9GzHna/FHvNVkiR5P7bQ4KiThFQh7rFeI0Dr+4sSxZFLEwQ2vk8X7PghcCuxQeIidoqGfVB+2ApVvz7IfUhn+qkwiSrMGGmM2Ih71JNhW5c1CyjODFzzEl+rbtt6g7Of9uXl+5g+c636L09Bkxaj/hBUTbcuXnFfrPbpvjKF2toRH8e5rloTqXzwnJvc6U0DSeTdcFtJaNMbutZLHoHdvIqN0NnXl6+sqVQ1fJ9hhJO9sspMP+HCSDcJKNgqqOnIvHbGEu4nab6k1DVmovPTw80ITUOsj+nTzRnkzusHT9rXB+jyfBz3d/Jr/ARnh65OWVDnoRrKDHKKu7srrhCVC3d9SL5dghBiAvpeSD8a/wvF1wAyRbYpzp4BidUkgUnXcOKNTawqrfsijBjaD9Ww6RFMsbsQmR6OU0+4EYYoA7B6HDPAVwQyNfgBJ8pW78SFSbmQDXxTVsCdI3f3iUhq90N9f5Myh6XQVQ1HiMVBNYIJi3FUIIYBgqUIY3z56LIg+M/XUJTRAWO+SAVPNHRKaDheP0z07r4QW99ADlPRpNSjF1fQhlfO5FXVs8k693A1IaXRk/6oix1KYoDY1PoYXzZiBWcApkpV6mI692IkLYDEIh/jiE6kjtzS05gbTT2KmzFEkw2OJtgMyA50NG7M3cPDI2OMDrznSl6yecQly3zOhEpBVv2AAowo+la68X8Ixf+hVh/Q5hcKStGHc8YY7QwcLknczqoyTxlb5/ygxd0Z1Z4VZ5uTJkfPMEqh6Amp+1Kv0fxxhhjVPB/tEQMOhIpwbgAAAAASUVORK5CYII=\";\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 · 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\">⎘</button>\n </div>\n\n <div class=\"network-badge\">\n <span class=\"dot\"></span>\n Base Network · 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 = '✓';\n setTimeout(function() { btn.classList.remove('copied'); btn.innerHTML = '⎘'; }, 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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"}
|