{"version":3,"file":"transfer.mjs","names":[],"sources":["../../../src/tools/transfer.ts"],"sourcesContent":["/**\n * Transfer Tool — Send ETH or ERC-20 tokens to a recipient address.\n *\n * The most fundamental wallet operation. Uses viem directly for ETH transfers,\n * and the erc20Abi for ERC-20 transfers. Reads token metadata (decimals, symbol)\n * via ClawnchSwapper. All transactions go through ClawnchConnect for approval.\n *\n * Safety: pre-flight balance check via safety-service.\n */\n\nimport { Type } from '@sinclair/typebox';\nimport { stringEnum, jsonResult, errorResult, readStringParam, readNumberParam } from '../lib/tool-helpers.js';\nimport {\n  getWalletState,\n  requireWalletClient,\n  requirePublicClient,\n  getMevWalletClient,\n} from '../services/walletconnect-service.js';\nimport { checkBalance } from '../services/safety-service.js';\nimport { resolveAddressOrEns, isEnsName } from '../lib/ens-resolver.js';\n\nconst ACTIONS = ['send', 'estimate'] as const;\n\nconst TransferSchema = Type.Object({\n  action: stringEnum(ACTIONS, {\n    description: 'send: execute the transfer. estimate: check balance and estimate gas without sending.',\n  }),\n  to: Type.String({\n    description: 'Recipient address (0x...) or ENS name (e.g. vitalik.eth)',\n  }),\n  amount: Type.String({\n    description: 'Amount to send in human-readable units (e.g. \"0.1\" for 0.1 ETH, \"100\" for 100 USDC)',\n  }),\n  token: Type.Optional(Type.String({\n    description: 'ERC-20 token contract address (0x...). Omit for native ETH transfer.',\n  })),\n});\n\nexport function createTransferTool() {\n  return {\n    name: 'transfer',\n    label: 'Transfer',\n    ownerOnly: true,\n    description:\n      'Send ETH or ERC-20 tokens to a recipient address. ' +\n      'Use action \"estimate\" to preview gas costs and check balance, ' +\n      'or \"send\" to execute. All transactions go through ClawnchConnect for approval.',\n    parameters: TransferSchema,\n    execute: async (_toolCallId: string, args: unknown) => {\n      const params = args as Record<string, unknown>;\n      const action = readStringParam(params, 'action', { required: true })!;\n\n      const state = getWalletState();\n      if (!state.connected) {\n        return errorResult('No wallet connected. Use clawnchconnect tool to connect first.');\n      }\n\n      switch (action) {\n        case 'send':\n          return handleSend(params);\n        case 'estimate':\n          return handleEstimate(params);\n        default:\n          return errorResult(`Unknown action: ${action}. Use: send, estimate`);\n      }\n    },\n  };\n}\n\n// H4: Address validation helper\nfunction isValidAddress(addr: string): boolean {\n  return /^0x[a-fA-F0-9]{40}$/.test(addr);\n}\n\n// ─── Well-known tokens on Base ────────────────────────────────────────────\n\nconst BASE_TOKENS: Record<string, { address: string; decimals: number; symbol: string }> = {\n  USDC: { address: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', decimals: 6, symbol: 'USDC' },\n  USDT: { address: '0xfde4C96c8593536E31F229EA8f37b2ADa2699bb2', decimals: 6, symbol: 'USDT' },\n  DAI: { address: '0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb', decimals: 18, symbol: 'DAI' },\n  WETH: { address: '0x4200000000000000000000000000000000000006', decimals: 18, symbol: 'WETH' },\n  CLAWNCH: { address: '0xa1F72459dfA10BAD200Ac160eCd78C6b77a747be', decimals: 18, symbol: 'CLAWNCH' },\n};\n\n// ─── Helpers ──────────────────────────────────────────────────────────────\n\nasync function getTokenInfo(tokenAddress: string): Promise<{ decimals: number; symbol: string }> {\n  // Check well-known tokens first\n  for (const info of Object.values(BASE_TOKENS)) {\n    if (info.address.toLowerCase() === tokenAddress.toLowerCase()) {\n      return { decimals: info.decimals, symbol: info.symbol };\n    }\n  }\n\n  // Read from chain via ClawnchSwapper\n  try {\n    const { ClawnchSwapper } = await import('@clawnch/clawncher-sdk');\n    const wallet = requireWalletClient();\n    const publicClient = requirePublicClient();\n\n    const swapper = new ClawnchSwapper({\n      wallet,\n      publicClient,\n      network: 'mainnet',\n    });\n\n    const [decimals, symbol] = await Promise.all([\n      swapper.getDecimals(tokenAddress as `0x${string}`),\n      swapper.getSymbol(tokenAddress as `0x${string}`),\n    ]);\n\n    return { decimals, symbol };\n  } catch {\n    // Fallback: assume 18 decimals\n    return { decimals: 18, symbol: 'UNKNOWN' };\n  }\n}\n\nfunction parseTokenAmount(amount: string, decimals: number): bigint {\n  const trimmed = amount.trim();\n  // Validate numeric format before BigInt conversion\n  if (!trimmed || !/^\\d+(\\.\\d+)?$/.test(trimmed)) {\n    throw new Error(`Invalid amount: \"${amount}\". Must be a positive number (e.g. \"1.5\" or \"100\").`);\n  }\n\n  // Handle decimal amounts properly\n  const parts = trimmed.split('.');\n  const whole = parts[0] ?? '0';\n  let fraction = parts[1] ?? '';\n\n  // Pad or truncate fraction to match decimals\n  if (fraction.length > decimals) {\n    fraction = fraction.slice(0, decimals);\n  } else {\n    fraction = fraction.padEnd(decimals, '0');\n  }\n\n  return BigInt(whole + fraction);\n}\n\n// ─── Action Handlers ──────────────────────────────────────────────────────\n\nasync function handleEstimate(params: Record<string, unknown>) {\n  const toInput = readStringParam(params, 'to', { required: true })!;\n  const amount = readStringParam(params, 'amount', { required: true })!;\n  // Validate amount format early — prevents opaque errors in parseTokenAmount/parseEther\n  if (!/^\\d+(\\.\\d+)?$/.test(amount.trim())) {\n    return errorResult(`Invalid amount: \"${amount}\". Must be a positive number (e.g. \"1.5\" or \"100\").`);\n  }\n  const tokenAddr = readStringParam(params, 'token');\n  if (tokenAddr && !isValidAddress(tokenAddr)) {\n    return errorResult(`Invalid token address: \"${tokenAddr}\". Must be a valid 0x... address.`);\n  }\n\n  // Resolve recipient: supports both 0x addresses and ENS names\n  // Validate format first (before requiring publicClient for ENS lookups)\n  if (!isValidAddress(toInput) && !isEnsName(toInput)) {\n    return errorResult(`Invalid recipient address: \"${toInput}\". Must be a valid 0x... Ethereum address (40 hex chars) or ENS name (e.g. vitalik.eth).`);\n  }\n  let to: string;\n  let ensName: string | undefined;\n  try {\n    const publicClient = requirePublicClient();\n    const resolved = await resolveAddressOrEns(toInput, publicClient);\n    to = resolved.address;\n    ensName = resolved.ensName;\n  } catch (err) {\n    return errorResult(err instanceof Error ? err.message : String(err));\n  }\n  const isErc20 = !!tokenAddr;\n\n  try {\n    const publicClient = requirePublicClient();\n    const state = getWalletState();\n    const { formatEther, formatUnits, erc20Abi } = await import('viem');\n\n    // Get ETH balance\n    const ethBalance = await publicClient.getBalance({ address: state.address! });\n    const ethBalanceFormatted = formatEther(ethBalance);\n\n    const result: Record<string, unknown> = {\n      to,\n      amount,\n      type: isErc20 ? 'ERC-20' : 'ETH',\n      ethBalance: ethBalanceFormatted,\n    };\n\n    if (isErc20) {\n      const info = await getTokenInfo(tokenAddr!);\n      result.token = { address: tokenAddr, symbol: info.symbol, decimals: info.decimals };\n\n      // Check ERC-20 balance\n      try {\n        const tokenBalance = await publicClient.readContract({\n          address: tokenAddr as `0x${string}`,\n          abi: erc20Abi,\n          functionName: 'balanceOf',\n          args: [state.address!],\n        }) as bigint;\n\n        const tokenBalanceFormatted = formatUnits(tokenBalance, info.decimals);\n        result.tokenBalance = tokenBalanceFormatted;\n\n        const amountWei = parseTokenAmount(amount, info.decimals);\n        if (amountWei > tokenBalance) {\n          result.sufficientTokenBalance = false;\n          result.shortfall = formatUnits(amountWei - tokenBalance, info.decimals);\n        } else {\n          result.sufficientTokenBalance = true;\n        }\n      } catch (err) {\n        result.tokenBalanceError = err instanceof Error ? err.message : String(err);\n      }\n\n      // Check ETH for gas\n      const safety = await checkBalance({ requiredEth: 0 });\n      result.sufficientGas = safety.safe;\n      if (!safety.safe) result.gasWarning = safety.blockers.join('; ');\n    } else {\n      // Native ETH transfer\n      const amountEth = parseFloat(amount);\n      const safety = await checkBalance({ requiredEth: amountEth });\n      result.sufficientBalance = safety.safe;\n      if (!safety.safe) result.balanceWarning = safety.blockers.join('; ');\n      if (safety.warnings.length > 0) result.warnings = safety.warnings;\n    }\n\n    // Estimate gas\n    try {\n      if (isErc20) {\n        const amountWei = parseTokenAmount(amount, (result.token as any).decimals);\n        const gas = await publicClient.estimateGas({\n          account: state.address!,\n          to: tokenAddr as `0x${string}`,\n          data: encodeFunctionData_transfer(to as `0x${string}`, amountWei),\n        });\n        result.estimatedGas = gas.toString();\n      } else {\n        const { parseEther } = await import('viem');\n        const gas = await publicClient.estimateGas({\n          account: state.address!,\n          to: to as `0x${string}`,\n          value: parseEther(amount),\n        });\n        result.estimatedGas = gas.toString();\n      }\n    } catch (err) {\n      result.gasEstimateError = err instanceof Error ? err.message : String(err);\n    }\n\n    return jsonResult(result);\n  } catch (err) {\n    return errorResult(`Estimate failed: ${err instanceof Error ? err.message : String(err)}`);\n  }\n}\n\nasync function handleSend(params: Record<string, unknown>) {\n  const toInput = readStringParam(params, 'to', { required: true })!;\n  const amount = readStringParam(params, 'amount', { required: true })!;\n  // Validate amount format early — prevents opaque errors in parseTokenAmount/parseEther\n  if (!/^\\d+(\\.\\d+)?$/.test(amount.trim())) {\n    return errorResult(`Invalid amount: \"${amount}\". Must be a positive number (e.g. \"1.5\" or \"100\").`);\n  }\n  const tokenAddr = readStringParam(params, 'token');\n  if (tokenAddr && !isValidAddress(tokenAddr)) {\n    return errorResult(`Invalid token address: \"${tokenAddr}\". Must be a valid 0x... address.`);\n  }\n\n  // Resolve recipient: supports both 0x addresses and ENS names\n  // Validate format first (before requiring publicClient for ENS lookups)\n  if (!isValidAddress(toInput) && !isEnsName(toInput)) {\n    return errorResult(`Invalid recipient address: \"${toInput}\". Must be a valid 0x... Ethereum address (40 hex chars) or ENS name (e.g. vitalik.eth).`);\n  }\n  let to: string;\n  let ensName: string | undefined;\n  try {\n    const publicClient = requirePublicClient();\n    const resolved = await resolveAddressOrEns(toInput, publicClient);\n    to = resolved.address;\n    ensName = resolved.ensName;\n  } catch (err) {\n    return errorResult(err instanceof Error ? err.message : String(err));\n  }\n  const isErc20 = !!tokenAddr;\n\n  try {\n    const wallet = await getMevWalletClient();\n    const publicClient = requirePublicClient();\n\n    if (isErc20) {\n      // ─── ERC-20 Transfer ─────────────────────────────────────────\n      const info = await getTokenInfo(tokenAddr!);\n      const amountWei = parseTokenAmount(amount, info.decimals);\n\n      // Pre-flight: check token balance\n      const { erc20Abi, formatUnits } = await import('viem');\n      const state = getWalletState();\n      const tokenBalance = await publicClient.readContract({\n        address: tokenAddr as `0x${string}`,\n        abi: erc20Abi,\n        functionName: 'balanceOf',\n        args: [state.address!],\n      }) as bigint;\n\n      if (amountWei > tokenBalance) {\n        return errorResult(\n          `Insufficient ${info.symbol} balance. ` +\n          `Have: ${formatUnits(tokenBalance, info.decimals)}, need: ${amount}`\n        );\n      }\n\n      // Pre-flight: check ETH for gas\n      const safety = await checkBalance({ requiredEth: 0 });\n      if (!safety.safe) {\n        return errorResult(`Insufficient gas: ${safety.blockers.join('; ')}`);\n      }\n\n      // Execute\n      const txHash = await wallet.writeContract({\n        address: tokenAddr as `0x${string}`,\n        abi: erc20Abi,\n        functionName: 'transfer',\n        args: [to as `0x${string}`, amountWei],\n      });\n\n      // Wait for receipt\n      const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });\n\n      if (receipt.status === 'reverted') {\n        return errorResult(`Transfer reverted. TX: ${txHash}`);\n      }\n\n      return jsonResult({\n        status: 'success',\n        type: 'ERC-20',\n        token: { address: tokenAddr, symbol: info.symbol, decimals: info.decimals },\n        to,\n        ...(ensName ? { ensName } : {}),\n        amount,\n        amountWei: amountWei.toString(),\n        txHash,\n        blockNumber: receipt.blockNumber.toString(),\n        gasUsed: receipt.gasUsed.toString(),\n      });\n    } else {\n      // ─── Native ETH Transfer ─────────────────────────────────────\n      const amountEth = parseFloat(amount);\n      const safety = await checkBalance({ requiredEth: amountEth });\n      if (!safety.safe) {\n        return errorResult(`Insufficient balance: ${safety.blockers.join('; ')}`);\n      }\n\n      const { parseEther } = await import('viem');\n      const value = parseEther(amount);\n\n      const txHash = await wallet.sendTransaction({\n        to: to as `0x${string}`,\n        value,\n      });\n\n      // Wait for receipt\n      const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });\n\n      if (receipt.status === 'reverted') {\n        return errorResult(`Transfer reverted. TX: ${txHash}`);\n      }\n\n      return jsonResult({\n        status: 'success',\n        type: 'ETH',\n        to,\n        ...(ensName ? { ensName } : {}),\n        amount,\n        amountWei: value.toString(),\n        txHash,\n        blockNumber: receipt.blockNumber.toString(),\n        gasUsed: receipt.gasUsed.toString(),\n      });\n    }\n  } catch (err) {\n    return errorResult(`Transfer failed: ${err instanceof Error ? err.message : String(err)}`);\n  }\n}\n\n// ─── ABI Encoding Helper ──────────────────────────────────────────────────\n\n/**\n * Minimal ERC-20 transfer calldata encoder (avoids importing encodeFunctionData).\n * transfer(address,uint256) = 0xa9059cbb\n */\nfunction encodeFunctionData_transfer(to: `0x${string}`, amount: bigint): `0x${string}` {\n  const selector = '0xa9059cbb';\n  const toParam = to.slice(2).toLowerCase().padStart(64, '0');\n  const amountParam = amount.toString(16).padStart(64, '0');\n  return `${selector}${toParam}${amountParam}` as `0x${string}`;\n}\n"],"mappings":"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"}