{"version":3,"file":"privacy.mjs","names":[],"sources":["../../../src/tools/privacy.ts"],"sourcesContent":["/**\n * Privacy Tool — private transactions via Veil.cash on Base.\n *\n * Actions:\n *   deposit   — Deposit ETH/USDC into privacy pool (public → shielded)\n *   withdraw  — Withdraw from privacy pool (shielded → public)\n *   transfer  — Private-to-private transfer within the pool\n *   balance   — Check shielded balance\n *   info      — Show supported assets and pool info\n *\n * Uses @veil-cash/sdk for ZK proof generation. Privacy pools on Base\n * use zero-knowledge proofs to break the on-chain link between deposits\n * and withdrawals.\n *\n * Requires: @veil-cash/sdk npm package (optional dependency).\n */\n\nimport { Type } from '@sinclair/typebox';\nimport { stringEnum, jsonResult, errorResult, readStringParam } from '../lib/tool-helpers.js';\nimport { getVeilService } from '../services/veil-service.js';\nimport { getWalletState, requirePublicClient } from '../services/walletconnect-service.js';\nimport { resolveAddressOrEns, isEnsName } from '../lib/ens-resolver.js';\n\nconst ACTIONS = ['deposit', 'withdraw', 'transfer', 'balance', 'info'] as const;\n\nconst PrivacySchema = Type.Object({\n  action: stringEnum(ACTIONS, {\n    description:\n      'deposit: send to privacy pool. withdraw: exit privacy pool to an address. ' +\n      'transfer: private-to-private transfer. balance: check shielded balance. ' +\n      'info: supported assets and pool details.',\n  }),\n  asset: Type.Optional(Type.String({\n    description: 'Asset: \"ETH\" or \"USDC\". Required for deposit/withdraw/transfer.',\n  })),\n  amount: Type.Optional(Type.String({\n    description: 'Amount in human-readable units (e.g. \"0.1\" ETH, \"100\" USDC). Required for deposit/withdraw/transfer.',\n  })),\n  recipient: Type.Optional(Type.String({\n    description: 'Recipient address, ENS name, or shielded public key. Required for withdraw/transfer.',\n  })),\n});\n\nexport function createPrivacyTool() {\n  return {\n    name: 'privacy',\n    label: 'Privacy',\n    ownerOnly: true,\n    description:\n      'Private transactions on Base via Veil.cash. Deposit ETH/USDC into ZK privacy pools, ' +\n      'withdraw to any address (breaking on-chain link), or transfer privately within the pool. ' +\n      'Requires @veil-cash/sdk package.',\n    parameters: PrivacySchema,\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      switch (action) {\n        case 'deposit':\n          return handleDeposit(params);\n        case 'withdraw':\n          return handleWithdraw(params);\n        case 'transfer':\n          return handleTransfer(params);\n        case 'balance':\n          return handleBalance(params);\n        case 'info':\n          return handleInfo();\n        default:\n          return errorResult(`Unknown action: ${action}. Use: deposit, withdraw, transfer, balance, info`);\n      }\n    },\n  };\n}\n\n// ── Helpers ──────────────────────────────────────────────────────────────────\n\n/** Validate amount is a non-empty positive number string. */\nfunction validateAmount(amount: string): string {\n  const trimmed = amount.trim();\n  if (!trimmed) throw new Error('Amount cannot be empty.');\n  if (!/^\\d+(\\.\\d+)?$/.test(trimmed)) {\n    throw new Error(`Invalid amount \"${trimmed}\". Must be a positive number (e.g. \"0.1\", \"100\").`);\n  }\n  if (parseFloat(trimmed) === 0) throw new Error('Amount must be greater than zero.');\n  return trimmed;\n}\n\n// ── Action Handlers ─────────────────────────────────────────────────────────\n\nasync function handleDeposit(params: Record<string, unknown>) {\n  const asset = readStringParam(params, 'asset', { required: true });\n  const amountRaw = readStringParam(params, 'amount', { required: true });\n  if (!asset || !amountRaw) {\n    return errorResult('Both asset and amount are required for deposit.');\n  }\n\n  let amount: string;\n  try { amount = validateAmount(amountRaw); } catch (err) {\n    return errorResult(err instanceof Error ? err.message : String(err));\n  }\n\n  const state = getWalletState();\n  if (!state.connected || !state.address) {\n    return errorResult('No wallet connected. Connect a wallet first.');\n  }\n\n  try {\n    const service = getVeilService();\n\n    // Check SDK availability first\n    const available = await service.isAvailable();\n    if (!available) {\n      return errorResult(\n        '@veil-cash/sdk not installed. Install with: pnpm add @veil-cash/sdk',\n      );\n    }\n\n    const result = await service.deposit(asset, amount);\n\n    return jsonResult({\n      status: result.status,\n      action: 'deposit',\n      asset: result.asset,\n      amount: result.amount,\n      txHash: result.txHash,\n      noteHash: result.noteHash,\n      chain: 'base',\n      note: 'Funds are now shielded. Use action=withdraw to exit to any address.',\n      warning: 'SAVE your encrypted note. It is required for withdrawal if you lose access to this wallet.',\n    });\n  } catch (err) {\n    return errorResult(`Deposit failed: ${err instanceof Error ? err.message : String(err)}`);\n  }\n}\n\nasync function handleWithdraw(params: Record<string, unknown>) {\n  const asset = readStringParam(params, 'asset', { required: true });\n  const amountRaw = readStringParam(params, 'amount', { required: true });\n  const recipientInput = readStringParam(params, 'recipient', { required: true });\n  if (!asset || !amountRaw || !recipientInput) {\n    return errorResult('asset, amount, and recipient are required for withdraw.');\n  }\n\n  let amount: string;\n  try { amount = validateAmount(amountRaw); } catch (err) {\n    return errorResult(err instanceof Error ? err.message : String(err));\n  }\n\n  try {\n    const service = getVeilService();\n    const available = await service.isAvailable();\n    if (!available) {\n      return errorResult('@veil-cash/sdk not installed. Install with: pnpm add @veil-cash/sdk');\n    }\n\n    // Resolve ENS if needed\n    let recipient = recipientInput;\n    if (isEnsName(recipientInput)) {\n      const publicClient = requirePublicClient();\n      const resolved = await resolveAddressOrEns(recipientInput, publicClient);\n      recipient = resolved.address;\n    }\n\n    const result = await service.withdraw(asset, amount, recipient);\n\n    return jsonResult({\n      status: result.status,\n      action: 'withdraw',\n      asset: result.asset,\n      amount: result.amount,\n      recipient: result.recipient,\n      ensName: isEnsName(recipientInput) ? recipientInput : undefined,\n      txHash: result.txHash,\n      relayerFee: result.relayerFee,\n      chain: 'base',\n      note: result.status === 'submitted_to_relayer'\n        ? 'Withdrawal submitted to relayer for privacy. Transaction will appear shortly.'\n        : 'Withdrawal confirmed on-chain.',\n    });\n  } catch (err) {\n    return errorResult(`Withdraw failed: ${err instanceof Error ? err.message : String(err)}`);\n  }\n}\n\nasync function handleTransfer(params: Record<string, unknown>) {\n  const asset = readStringParam(params, 'asset', { required: true });\n  const amountRaw = readStringParam(params, 'amount', { required: true });\n  const recipient = readStringParam(params, 'recipient', { required: true });\n  if (!asset || !amountRaw || !recipient) {\n    return errorResult('asset, amount, and recipient (shielded public key) are required for transfer.');\n  }\n\n  let amount: string;\n  try { amount = validateAmount(amountRaw); } catch (err) {\n    return errorResult(err instanceof Error ? err.message : String(err));\n  }\n\n  try {\n    const service = getVeilService();\n    const available = await service.isAvailable();\n    if (!available) {\n      return errorResult('@veil-cash/sdk not installed. Install with: pnpm add @veil-cash/sdk');\n    }\n\n    const result = await service.transfer(asset, amount, recipient);\n\n    return jsonResult({\n      status: result.status,\n      action: 'transfer',\n      asset: result.asset,\n      amount: result.amount,\n      txHash: result.txHash,\n      noteHash: result.noteHash,\n      chain: 'base',\n      note: 'Private transfer completed. Both sender and recipient balances updated within the privacy pool.',\n    });\n  } catch (err) {\n    return errorResult(`Transfer failed: ${err instanceof Error ? err.message : String(err)}`);\n  }\n}\n\nasync function handleBalance(params: Record<string, unknown>) {\n  try {\n    const service = getVeilService();\n    const available = await service.isAvailable();\n    if (!available) {\n      return errorResult('@veil-cash/sdk not installed. Install with: pnpm add @veil-cash/sdk');\n    }\n\n    const state = getWalletState();\n    if (!state.connected) {\n      return errorResult('No wallet connected. Connect a wallet first.');\n    }\n\n    const asset = readStringParam(params, 'asset');\n    const balances = await service.getBalance(asset ?? undefined);\n\n    return jsonResult({\n      chain: 'base',\n      balances: balances.map(b => ({\n        asset: b.asset,\n        shielded: b.shielded,\n        pendingDeposits: b.pendingDeposits !== '0' ? b.pendingDeposits : undefined,\n        pendingWithdrawals: b.pendingWithdrawals !== '0' ? b.pendingWithdrawals : undefined,\n      })),\n      note: 'Shielded balances are private — only visible to the wallet owner.',\n    });\n  } catch (err) {\n    return errorResult(`Balance check failed: ${err instanceof Error ? err.message : String(err)}`);\n  }\n}\n\nasync function handleInfo() {\n  const service = getVeilService();\n  const available = await service.isAvailable();\n  const assets = service.getSupportedAssets();\n\n  return jsonResult({\n    protocol: 'Veil.cash',\n    chain: 'base',\n    sdkInstalled: available,\n    supportedAssets: assets.map(a => ({\n      symbol: a.symbol,\n      poolDenomination: a.poolDenomination,\n      address: a.address === '0x0000000000000000000000000000000000000000' ? 'native ETH' : a.address,\n    })),\n    howItWorks: [\n      '1. Deposit: Send ETH/USDC to the privacy pool (public transaction)',\n      '2. Wait: Let time pass for anonymity set to grow',\n      '3. Withdraw: Exit to any address (ZK proof breaks the on-chain link)',\n    ],\n    privacy: 'ZK proofs ensure no one can link your deposit to your withdrawal.',\n    sdkRequired: !available\n      ? 'Install @veil-cash/sdk: pnpm add @veil-cash/sdk'\n      : undefined,\n  });\n}\n"],"mappings":"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"}