{"version":3,"file":"veil-service.mjs","names":[],"sources":["../../../src/services/veil-service.ts"],"sourcesContent":["/**\n * Veil.cash Service — privacy pool integration for private transfers on Base.\n *\n * Uses @veil-cash/sdk for ZK proof generation and relayer submission.\n * Supports ETH and USDC privacy pools.\n *\n * SDK provides:\n *   - Keypair.fromSigner() — derive privacy keypair from Bankr sign API\n *   - deposit() — deposit into privacy pool (public → private)\n *   - withdraw() — withdraw from privacy pool (private → public)\n *   - transfer() — private-to-private transfer\n *   - balance() — check shielded balance\n *\n * Requires: @veil-cash/sdk npm package (optional dep, ~50KB).\n */\n\nimport { getWalletState, requireWalletClient } from './walletconnect-service.js';\n\n// ── Types ───────────────────────────────────────────────────────────────────\n\nexport interface VeilBalance {\n  asset: string;\n  shielded: string;\n  pendingDeposits: string;\n  pendingWithdrawals: string;\n}\n\nexport interface VeilTxResult {\n  action: string;\n  asset: string;\n  amount: string;\n  txHash: string | null;\n  noteHash: string | null;\n  status: string;\n}\n\nexport interface VeilDepositResult extends VeilTxResult {\n  action: 'deposit';\n  note: string; // encrypted note for withdrawal\n}\n\nexport interface VeilWithdrawResult extends VeilTxResult {\n  action: 'withdraw';\n  recipient: string;\n  relayerFee: string | null;\n}\n\n// ── Supported Assets ────────────────────────────────────────────────────────\n\nconst SUPPORTED_ASSETS: Record<string, { address: string; decimals: number; poolSize: string }> = {\n  ETH: {\n    address: '0x0000000000000000000000000000000000000000',\n    decimals: 18,\n    poolSize: '0.1', // pool denomination in ETH\n  },\n  USDC: {\n    address: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',\n    decimals: 6,\n    poolSize: '100', // pool denomination in USDC\n  },\n};\n\n// ── Service ─────────────────────────────────────────────────────────────────\n\nexport class VeilService {\n  private sdk: any = null;\n  private keypair: any = null;\n  private keypairAddress: string | null = null; // Track which wallet derived the keypair\n\n  /**\n   * Check if the Veil SDK is installed.\n   */\n  async isAvailable(): Promise<boolean> {\n    try {\n      // @ts-expect-error — optional dependency, not always installed\n      await import('@veil-cash/sdk');\n      return true;\n    } catch {\n      return false;\n    }\n  }\n\n  /**\n   * Get the SDK instance, lazily loaded.\n   */\n  private async getSdk(): Promise<any> {\n    if (this.sdk) return this.sdk;\n    try {\n      // @ts-expect-error — optional dependency, not always installed\n      this.sdk = await import('@veil-cash/sdk');\n      return this.sdk;\n    } catch {\n      throw new Error(\n        '@veil-cash/sdk not installed. Install with: pnpm add @veil-cash/sdk\\n' +\n        'This package provides ZK proof generation for private transactions on Base.',\n      );\n    }\n  }\n\n  /**\n   * Derive a privacy keypair from the connected wallet's signer.\n   * Invalidates the cached keypair if the wallet address has changed.\n   */\n  private async getKeypair(): Promise<any> {\n    const state = getWalletState();\n    const currentAddress = state.address ?? null;\n\n    // Invalidate keypair if wallet changed\n    if (this.keypair && this.keypairAddress !== currentAddress) {\n      this.keypair = null;\n      this.keypairAddress = null;\n    }\n\n    if (this.keypair) return this.keypair;\n\n    const sdk = await this.getSdk();\n    const walletClient = requireWalletClient();\n\n    // Keypair.fromSigner works with any EIP-191 signer (including Bankr)\n    this.keypair = await sdk.Keypair.fromSigner(walletClient);\n    this.keypairAddress = currentAddress;\n    return this.keypair;\n  }\n\n  getSupportedAssets() {\n    return Object.entries(SUPPORTED_ASSETS).map(([symbol, info]) => ({\n      symbol,\n      address: info.address,\n      poolDenomination: info.poolSize,\n    }));\n  }\n\n  resolveAsset(input: string): { symbol: string; address: string; decimals: number; poolSize: string } | null {\n    const upper = input.toUpperCase();\n    const asset = SUPPORTED_ASSETS[upper];\n    if (!asset) return null;\n    return { symbol: upper, ...asset };\n  }\n\n  // ── Deposit (Public → Private) ─────────────────────────────────────\n\n  async deposit(\n    asset: string,\n    amount: string,\n  ): Promise<VeilDepositResult> {\n    const sdk = await this.getSdk();\n    const keypair = await this.getKeypair();\n    const assetInfo = this.resolveAsset(asset);\n    if (!assetInfo) throw new Error(`Unsupported asset: ${asset}. Supported: ETH, USDC`);\n\n    const state = getWalletState();\n    if (!state.connected || !state.address) {\n      throw new Error('No wallet connected.');\n    }\n\n    const walletClient = requireWalletClient();\n\n    const result = await sdk.deposit({\n      keypair,\n      asset: assetInfo.address,\n      amount,\n      signer: walletClient,\n      chainId: 8453,\n    });\n\n    return {\n      action: 'deposit',\n      asset: assetInfo.symbol,\n      amount,\n      txHash: result.txHash ?? null,\n      noteHash: result.noteHash ?? null,\n      note: result.note ?? '',\n      status: result.txHash ? 'confirmed' : 'pending',\n    };\n  }\n\n  // ── Withdraw (Private → Public) ────────────────────────────────────\n\n  async withdraw(\n    asset: string,\n    amount: string,\n    recipient: string,\n  ): Promise<VeilWithdrawResult> {\n    const sdk = await this.getSdk();\n    const keypair = await this.getKeypair();\n    const assetInfo = this.resolveAsset(asset);\n    if (!assetInfo) throw new Error(`Unsupported asset: ${asset}. Supported: ETH, USDC`);\n\n    const result = await sdk.withdraw({\n      keypair,\n      asset: assetInfo.address,\n      amount,\n      recipient,\n      chainId: 8453,\n      useRelayer: true, // Use relayer for privacy (hides withdrawal address)\n    });\n\n    return {\n      action: 'withdraw',\n      asset: assetInfo.symbol,\n      amount,\n      recipient,\n      txHash: result.txHash ?? null,\n      noteHash: result.noteHash ?? null,\n      relayerFee: result.relayerFee ?? null,\n      status: result.txHash ? 'confirmed' : 'submitted_to_relayer',\n    };\n  }\n\n  // ── Private Transfer ───────────────────────────────────────────────\n\n  async transfer(\n    asset: string,\n    amount: string,\n    recipientPublicKey: string,\n  ): Promise<VeilTxResult> {\n    const sdk = await this.getSdk();\n    const keypair = await this.getKeypair();\n    const assetInfo = this.resolveAsset(asset);\n    if (!assetInfo) throw new Error(`Unsupported asset: ${asset}. Supported: ETH, USDC`);\n\n    const result = await sdk.transfer({\n      keypair,\n      asset: assetInfo.address,\n      amount,\n      recipientPublicKey,\n      chainId: 8453,\n    });\n\n    return {\n      action: 'transfer',\n      asset: assetInfo.symbol,\n      amount,\n      txHash: result.txHash ?? null,\n      noteHash: result.noteHash ?? null,\n      status: result.txHash ? 'confirmed' : 'pending',\n    };\n  }\n\n  // ── Balance ────────────────────────────────────────────────────────\n\n  async getBalance(asset?: string): Promise<VeilBalance[]> {\n    const sdk = await this.getSdk();\n    const keypair = await this.getKeypair();\n\n    const assets = asset\n      ? [this.resolveAsset(asset)].filter(Boolean)\n      : Object.keys(SUPPORTED_ASSETS).map(s => this.resolveAsset(s)).filter(Boolean);\n\n    const balances: VeilBalance[] = [];\n    for (const a of assets) {\n      if (!a) continue;\n      try {\n        const bal = await sdk.getBalance({\n          keypair,\n          asset: a.address,\n          chainId: 8453,\n        });\n        balances.push({\n          asset: a.symbol,\n          shielded: bal.shielded ?? '0',\n          pendingDeposits: bal.pendingDeposits ?? '0',\n          pendingWithdrawals: bal.pendingWithdrawals ?? '0',\n        });\n      } catch {\n        balances.push({\n          asset: a.symbol,\n          shielded: '0',\n          pendingDeposits: '0',\n          pendingWithdrawals: '0',\n        });\n      }\n    }\n\n    return balances;\n  }\n}\n\n// ── Singleton ───────────────────────────────────────────────────────────────\n\nlet _instance: VeilService | null = null;\n\nexport function getVeilService(): VeilService {\n  if (!_instance) {\n    _instance = new VeilService();\n  }\n  return _instance;\n}\n\nexport function resetVeilService(): void {\n  _instance = null;\n}\n"],"mappings":"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"}