{"version":3,"file":"block-explorer.mjs","names":[],"sources":["../../../src/tools/block-explorer.ts"],"sourcesContent":["/**\n * Block Explorer Tool — Etherscan/Basescan API integrations.\n *\n * Provides on-chain data lookup via Etherscan-compatible APIs:\n * Etherscan (Ethereum mainnet) and Basescan (Base). Requires\n * ETHERSCAN_API_KEY and/or BASESCAN_API_KEY environment variables.\n *\n * Actions:\n *   tx_lookup       — Get transaction details by hash\n *   contract_source — Fetch verified contract source code and ABI\n *   gas_tracker     — Current gas prices (fast/standard/slow)\n *   token_holders   — Top token holders and holder count\n *   internal_txs    — Internal transactions for an address or tx\n *\n * Supports both Ethereum and Base chains.\n */\n\nimport { Type } from '@sinclair/typebox';\nimport { stringEnum, jsonResult, errorResult, readStringParam, readNumberParam } from '../lib/tool-helpers.js';\nimport { checkToolConfig } from '../services/tool-config-service.js';\nimport { guardedFetch } from '../services/endpoint-allowlist.js';\nimport { getCredentialVault } from '../services/credential-vault.js';\n\nconst ACTIONS = ['tx_lookup', 'contract_source', 'gas_tracker', 'token_holders', 'internal_txs'] as const;\nconst CHAINS = ['base', 'ethereum'] as const;\n\ninterface ExplorerConfig {\n  apiUrl: string;\n  apiKey: string;\n  name: string;\n  chainId: number;\n}\n\nfunction getExplorerConfig(chain: string): ExplorerConfig {\n  switch (chain.toLowerCase()) {\n    case 'ethereum':\n    case 'eth':\n    case 'mainnet': {\n      const apiKey = getCredentialVault().getSecret('explorer.etherscan.apiKey', 'block-explorer');\n      if (!apiKey) throw new Error('ETHERSCAN_API_KEY environment variable is required for Ethereum lookups.');\n      return { apiUrl: 'https://api.etherscan.io/api', apiKey, name: 'Etherscan', chainId: 1 };\n    }\n    case 'base':\n    default: {\n      const apiKey = getCredentialVault().getSecret('explorer.basescan.apiKey', 'block-explorer');\n      if (!apiKey) throw new Error('BASESCAN_API_KEY environment variable is required for Base lookups.');\n      return { apiUrl: 'https://api.basescan.org/api', apiKey, name: 'Basescan', chainId: 8453 };\n    }\n  }\n}\n\nasync function explorerFetch(config: ExplorerConfig, params: Record<string, string>): Promise<any> {\n  const url = new URL(config.apiUrl);\n  url.searchParams.set('apikey', config.apiKey);\n  for (const [key, value] of Object.entries(params)) {\n    url.searchParams.set(key, value);\n  }\n\n  // H10: Add request timeout to prevent hanging\n  const response = await guardedFetch(url.toString(), {\n    headers: { Accept: 'application/json' },\n    signal: AbortSignal.timeout(15_000),\n  });\n\n  if (!response.ok) {\n    throw new Error(`${config.name} API error: ${response.status} ${response.statusText}`);\n  }\n\n  const data: any = await response.json();\n\n  // Etherscan returns status \"0\" for errors\n  if (data.status === '0' && data.message !== 'No transactions found' && data.message !== 'No records found') {\n    throw new Error(`${config.name}: ${data.result || data.message}`);\n  }\n\n  return data;\n}\n\nconst BlockExplorerSchema = Type.Object({\n  action: stringEnum(ACTIONS, {\n    description:\n      'tx_lookup: transaction details by hash. ' +\n      'contract_source: verified contract source/ABI. ' +\n      'gas_tracker: current gas prices. ' +\n      'token_holders: top holders of a token. ' +\n      'internal_txs: internal (trace) transactions.',\n  }),\n  chain: Type.Optional(stringEnum(CHAINS, {\n    description: 'Chain: \"base\" (default) or \"ethereum\".',\n  })),\n  tx_hash: Type.Optional(Type.String({\n    description: 'Transaction hash (0x...). Required for tx_lookup.',\n  })),\n  address: Type.Optional(Type.String({\n    description: 'Contract or wallet address (0x...). Required for contract_source, token_holders, internal_txs.',\n  })),\n  token: Type.Optional(Type.String({\n    description: 'Token contract address (0x...). Required for token_holders.',\n  })),\n  page: Type.Optional(Type.Number({\n    description: 'Page number for paginated results. Default: 1.',\n  })),\n  limit: Type.Optional(Type.Number({\n    description: 'Results per page. Default: 25, max: 100.',\n  })),\n});\n\nexport function createBlockExplorerTool() {\n  return {\n    name: 'block_explorer',\n    label: 'Block Explorer',\n    ownerOnly: false,\n    description:\n      'Query Etherscan/Basescan APIs for on-chain data. Look up transactions, ' +\n      'contract source code, gas prices, token holders, and internal transactions.',\n    parameters: BlockExplorerSchema,\n    execute: async (_toolCallId: string, args: unknown) => {\n      // Early check: is the tool configured?\n      const notReady = checkToolConfig('block_explorer');\n      if (notReady) return notReady;\n\n      const params = args as Record<string, unknown>;\n      const action = readStringParam(params, 'action', { required: true })!;\n\n      switch (action) {\n        case 'tx_lookup':\n          return handleTxLookup(params);\n        case 'contract_source':\n          return handleContractSource(params);\n        case 'gas_tracker':\n          return handleGasTracker(params);\n        case 'token_holders':\n          return handleTokenHolders(params);\n        case 'internal_txs':\n          return handleInternalTxs(params);\n        default:\n          return errorResult(`Unknown action: ${action}. Use: ${ACTIONS.join(', ')}`);\n      }\n    },\n  };\n}\n\n// ─── Action Handlers ──────────────────────────────────────────────────────\n\nasync function handleTxLookup(params: Record<string, unknown>) {\n  const txHash = readStringParam(params, 'tx_hash') ?? readStringParam(params, 'txHash');\n  if (!txHash) return errorResult('tx_hash is required for tx_lookup.');\n\n  const chain = readStringParam(params, 'chain') ?? 'base';\n\n  try {\n    const config = getExplorerConfig(chain);\n\n    // Get transaction details\n    const txData = await explorerFetch(config, {\n      module: 'proxy',\n      action: 'eth_getTransactionByHash',\n      txhash: txHash,\n    });\n\n    const tx = txData.result;\n    if (!tx) return errorResult(`Transaction not found: ${txHash}`);\n\n    // Get receipt for status and gas used\n    const receiptData = await explorerFetch(config, {\n      module: 'proxy',\n      action: 'eth_getTransactionReceipt',\n      txhash: txHash,\n    });\n\n    const receipt = receiptData.result;\n\n    const gasPrice = tx.gasPrice ? parseInt(tx.gasPrice, 16) : 0;\n    const gasUsed = receipt?.gasUsed ? parseInt(receipt.gasUsed, 16) : 0;\n    const gasCostWei = BigInt(gasPrice) * BigInt(gasUsed);\n\n    return jsonResult({\n      chain,\n      explorer: config.name,\n      txHash,\n      status: receipt?.status === '0x1' ? 'success' : receipt?.status === '0x0' ? 'reverted' : 'pending',\n      blockNumber: tx.blockNumber ? parseInt(tx.blockNumber, 16) : null,\n      from: tx.from,\n      to: tx.to,\n      value: tx.value ? (parseInt(tx.value, 16) / 1e18).toString() + ' ETH' : '0',\n      gasPrice: gasPrice > 0 ? (gasPrice / 1e9).toFixed(2) + ' gwei' : null,\n      gasUsed: gasUsed > 0 ? gasUsed : null,\n      gasCostEth: gasCostWei > 0n ? (Number(gasCostWei) / 1e18).toFixed(6) : null,\n      nonce: tx.nonce ? parseInt(tx.nonce, 16) : null,\n      input: tx.input?.length > 10 ? `${tx.input.slice(0, 10)}... (${(tx.input.length - 2) / 2} bytes)` : tx.input,\n      logs: receipt?.logs?.length ?? 0,\n    });\n  } catch (err) {\n    return errorResult(`TX lookup failed: ${err instanceof Error ? err.message : String(err)}`);\n  }\n}\n\nasync function handleContractSource(params: Record<string, unknown>) {\n  const address = readStringParam(params, 'address', { required: true })!;\n  const chain = readStringParam(params, 'chain') ?? 'base';\n\n  try {\n    const config = getExplorerConfig(chain);\n\n    const data = await explorerFetch(config, {\n      module: 'contract',\n      action: 'getsourcecode',\n      address,\n    });\n\n    const result = data.result?.[0];\n    if (!result) return errorResult(`No contract found at ${address}`);\n\n    const isVerified = result.SourceCode && result.SourceCode !== '';\n\n    return jsonResult({\n      chain,\n      explorer: config.name,\n      address,\n      isVerified,\n      contractName: result.ContractName || null,\n      compilerVersion: result.CompilerVersion || null,\n      optimizationUsed: result.OptimizationUsed === '1',\n      runs: result.Runs ? parseInt(result.Runs) : null,\n      evmVersion: result.EVMVersion || null,\n      licenseType: result.LicenseType || null,\n      proxy: result.Proxy === '1',\n      implementation: result.Implementation || null,\n      // Truncate source if very long\n      sourceCode: result.SourceCode\n        ? result.SourceCode.length > 5000\n          ? result.SourceCode.slice(0, 5000) + `\\n... (${result.SourceCode.length} chars total, truncated)`\n          : result.SourceCode\n        : null,\n      abi: result.ABI && result.ABI !== 'Contract source code not verified'\n        ? JSON.parse(result.ABI)\n        : null,\n    });\n  } catch (err) {\n    return errorResult(`Contract source failed: ${err instanceof Error ? err.message : String(err)}`);\n  }\n}\n\nasync function handleGasTracker(params: Record<string, unknown>) {\n  const chain = readStringParam(params, 'chain') ?? 'base';\n\n  try {\n    const config = getExplorerConfig(chain);\n\n    const data = await explorerFetch(config, {\n      module: 'gastracker',\n      action: 'gasoracle',\n    });\n\n    const result = data.result;\n    if (!result) return errorResult('Gas tracker data unavailable.');\n\n    return jsonResult({\n      chain,\n      explorer: config.name,\n      gasPrice: {\n        fast: result.FastGasPrice ? parseFloat(result.FastGasPrice) : null,\n        standard: result.ProposeGasPrice ? parseFloat(result.ProposeGasPrice) : null,\n        slow: result.SafeGasPrice ? parseFloat(result.SafeGasPrice) : null,\n        unit: 'gwei',\n      },\n      baseFee: result.suggestBaseFee ? parseFloat(result.suggestBaseFee) : null,\n      gasUsedRatio: result.gasUsedRatio || null,\n      lastBlock: result.LastBlock || null,\n      // Estimate costs for common operations\n      estimates: {\n        ethTransfer: {\n          fast: result.FastGasPrice ? (parseFloat(result.FastGasPrice) * 21000 / 1e9).toFixed(6) + ' ETH' : null,\n          standard: result.ProposeGasPrice ? (parseFloat(result.ProposeGasPrice) * 21000 / 1e9).toFixed(6) + ' ETH' : null,\n        },\n        erc20Transfer: {\n          fast: result.FastGasPrice ? (parseFloat(result.FastGasPrice) * 65000 / 1e9).toFixed(6) + ' ETH' : null,\n          standard: result.ProposeGasPrice ? (parseFloat(result.ProposeGasPrice) * 65000 / 1e9).toFixed(6) + ' ETH' : null,\n        },\n        swap: {\n          fast: result.FastGasPrice ? (parseFloat(result.FastGasPrice) * 200000 / 1e9).toFixed(6) + ' ETH' : null,\n          standard: result.ProposeGasPrice ? (parseFloat(result.ProposeGasPrice) * 200000 / 1e9).toFixed(6) + ' ETH' : null,\n        },\n      },\n    });\n  } catch (err) {\n    return errorResult(`Gas tracker failed: ${err instanceof Error ? err.message : String(err)}`);\n  }\n}\n\nasync function handleTokenHolders(params: Record<string, unknown>) {\n  const token = readStringParam(params, 'token') ?? readStringParam(params, 'address');\n  if (!token) return errorResult('token (or address) is required for token_holders.');\n\n  const chain = readStringParam(params, 'chain') ?? 'base';\n  const page = readNumberParam(params, 'page') ?? 1;\n  const limit = Math.min(readNumberParam(params, 'limit') ?? 25, 100);\n\n  try {\n    const config = getExplorerConfig(chain);\n\n    // Get token info\n    const tokenInfo = await explorerFetch(config, {\n      module: 'token',\n      action: 'tokeninfo',\n      contractaddress: token,\n    });\n\n    // Get top holders via token holder list\n    const holdersData = await explorerFetch(config, {\n      module: 'token',\n      action: 'tokenholderlist',\n      contractaddress: token,\n      page: String(page),\n      offset: String(limit),\n    });\n\n    const info = tokenInfo.result?.[0] ?? {};\n    const holders = holdersData.result ?? [];\n\n    // Calculate percentages if we have total supply\n    const totalSupply = info.totalSupply ? BigInt(info.totalSupply) : null;\n    const decimals = info.divisor ? parseInt(info.divisor) : 18;\n\n    return jsonResult({\n      chain,\n      explorer: config.name,\n      token,\n      tokenName: info.tokenName || null,\n      tokenSymbol: info.symbol || null,\n      totalSupply: totalSupply !== null\n        ? (Number(totalSupply) / Math.pow(10, decimals)).toString()\n        : null,\n      holdersCount: info.holdersCount || holders.length,\n      page,\n      limit,\n      holders: holders.map((h: any) => {\n        const balance = BigInt(h.TokenHolderQuantity || '0');\n        const balanceFormatted = (Number(balance) / Math.pow(10, decimals)).toFixed(4);\n        const percentage = totalSupply && totalSupply > 0n\n          ? (Number(balance * 10000n / totalSupply) / 100).toFixed(2) + '%'\n          : null;\n\n        return {\n          address: h.TokenHolderAddress,\n          balance: balanceFormatted,\n          percentage,\n        };\n      }),\n    });\n  } catch (err) {\n    return errorResult(`Token holders failed: ${err instanceof Error ? err.message : String(err)}`);\n  }\n}\n\nasync function handleInternalTxs(params: Record<string, unknown>) {\n  const address = readStringParam(params, 'address');\n  const txHash = readStringParam(params, 'tx_hash') ?? readStringParam(params, 'txHash');\n  const chain = readStringParam(params, 'chain') ?? 'base';\n  const page = readNumberParam(params, 'page') ?? 1;\n  const limit = Math.min(readNumberParam(params, 'limit') ?? 25, 100);\n\n  if (!address && !txHash) {\n    return errorResult('Either address or tx_hash is required for internal_txs.');\n  }\n\n  try {\n    const config = getExplorerConfig(chain);\n\n    let data: any;\n    if (txHash) {\n      // Internal txs for a specific transaction\n      data = await explorerFetch(config, {\n        module: 'account',\n        action: 'txlistinternal',\n        txhash: txHash,\n      });\n    } else {\n      // Internal txs for an address\n      data = await explorerFetch(config, {\n        module: 'account',\n        action: 'txlistinternal',\n        address: address!,\n        startblock: '0',\n        endblock: '99999999',\n        page: String(page),\n        offset: String(limit),\n        sort: 'desc',\n      });\n    }\n\n    const txs = data.result ?? [];\n\n    return jsonResult({\n      chain,\n      explorer: config.name,\n      query: txHash ? { txHash } : { address },\n      count: txs.length,\n      page: txHash ? undefined : page,\n      transactions: txs.map((tx: any) => ({\n        blockNumber: tx.blockNumber,\n        timestamp: tx.timeStamp ? new Date(parseInt(tx.timeStamp) * 1000).toISOString() : null,\n        from: tx.from,\n        to: tx.to,\n        value: tx.value ? (parseInt(tx.value) / 1e18).toFixed(6) + ' ETH' : '0',\n        type: tx.type || 'call',\n        gas: tx.gas,\n        gasUsed: tx.gasUsed,\n        isError: tx.isError === '1',\n        errCode: tx.errCode || null,\n        traceId: tx.traceId || null,\n      })),\n    });\n  } catch (err) {\n    return errorResult(`Internal txs failed: ${err instanceof Error ? err.message : String(err)}`);\n  }\n}\n"],"mappings":"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"}