{"version":3,"file":"topup-server-R3dNp-p8.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    `Payment wallet: ${wallet.address}`,\n    `USDC on Base: ${balanceUsdc}`,\n    `Gas on Base: ${balanceEth} ETH`,\n    `Payment network: Base`,\n    `Base ETH is used only for one-time payment setup gas.`,\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 payment setup 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 payment setup 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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"}