{"version":3,"file":"clawnchconnect.mjs","names":[],"sources":["../../../src/tools/clawnchconnect.ts"],"sourcesContent":["/**\n * ClawnchConnect Tool — wallet connection and transaction signing\n * \n * The core security model. The agent never holds private keys.\n * Every transaction goes to the user's phone wallet for approval,\n * unless spending policies auto-approve it.\n */\n\nimport { Type } from '@sinclair/typebox';\nimport { stringEnum, jsonResult, textResult, errorResult, readStringParam } from '../lib/tool-helpers.js';\nimport {\n  initWalletService,\n  waitForWalletSession,\n  disconnectWallet,\n  getWalletState,\n  getWCSigner,\n  getTransactionHistory,\n  addPolicy,\n  clearPolicies,\n  isBankrMode,\n} from '../services/walletconnect-service.js';\nimport { getCredentialVault } from '../services/credential-vault.js';\n\nconst ACTIONS = [\n  'connect',\n  'status',\n  'disconnect',\n  'send_tx',\n  'set_policy',\n  'sign_message',\n] as const;\n\nconst WALLETS = [\n  'metamask',\n  'rainbow',\n  'coinbase',\n  'trust',\n  'zerion',\n  'uniswap',\n  'rabby',\n  'bankr',\n  'other',\n] as const;\n\n// Mobile wallet deep links — tappable on phone\nconst WALLET_DEEPLINKS: Record<string, string> = {\n  metamask: 'https://metamask.app.link/wc?uri=',\n  rainbow: 'https://rnbwapp.com/wc?uri=',\n  coinbase: 'https://go.cb-w.com/wc?uri=',\n  trust: 'https://link.trustwallet.com/wc?uri=',\n  zerion: 'https://wallet.zerion.io/wc?uri=',\n  uniswap: 'https://uniswap.org/app/wc?uri=',\n};\n\n// Desktop/browser extension wallets — need raw URI to paste\nconst DESKTOP_WALLETS = new Set(['rabby', 'other']);\n\nconst ClawnchConnectSchema = Type.Object({\n  action: stringEnum(ACTIONS, {\n    description: 'The action to perform',\n  }),\n  // connect\n  wallet: Type.Optional(stringEnum(WALLETS, {\n    description: 'Which wallet app the user wants to connect. ASK THE USER which wallet they use before calling connect. Mobile: metamask, rainbow, coinbase, trust, zerion, uniswap. Desktop: rabby, other.',\n  })),\n  project_id: Type.Optional(Type.String({\n    description: 'WalletConnect project ID (if not set via env)',\n  })),\n  // send_tx\n  to: Type.Optional(Type.String({\n    description: 'Target contract or wallet address (0x...)',\n  })),\n  value: Type.Optional(Type.String({\n    description: 'ETH value to send (in ETH, e.g. \"0.01\")',\n  })),\n  data: Type.Optional(Type.String({\n    description: 'Transaction calldata (hex)',\n  })),\n  summary: Type.Optional(Type.String({\n    description: 'Human-readable description of the transaction',\n  })),\n  // set_policy\n  policy: Type.Optional(Type.String({\n    description: 'Spending policy in natural language, e.g. \"approve under 0.05 ETH, max 10/hour\"',\n  })),\n  // sign_message\n  message: Type.Optional(Type.String({\n    description: 'Message to sign',\n  })),\n});\n\n/**\n * @param api - OpenClawPluginApi instance (optional). When provided, the connect\n *   action sends the WalletConnect link directly to the user via the channel,\n *   bypassing LLM summarization which tends to drop URLs.\n */\nexport function createClawnchConnectTool(api?: any) {\n  return {\n    name: 'clawnchconnect',\n    label: 'ClawnchConnect',\n    ownerOnly: true,\n    description:\n      'Connect a wallet for human-approved blockchain transactions. ' +\n      'IMPORTANT: For the connect action, you MUST ask the user which wallet app they use BEFORE calling this tool, then pass it as the wallet parameter. ' +\n      'Actions: connect (pair wallet — requires wallet param), status (check connection), ' +\n      'disconnect, send_tx (submit transaction for approval), ' +\n      'set_policy (configure auto-approval rules in natural language), ' +\n      'sign_message (request signature).',\n    parameters: ClawnchConnectSchema,\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 'connect':\n          return handleConnect(params, api);\n        case 'status':\n          return handleStatus();\n        case 'disconnect':\n          return handleDisconnect();\n        case 'send_tx':\n          return handleSendTx(params);\n        case 'set_policy':\n          return handleSetPolicy(params);\n        case 'sign_message':\n          return handleSignMessage(params);\n        default:\n          return errorResult(`Unknown action: ${action}`);\n      }\n    },\n  };\n}\n\n// ─── Action Handlers ─────────────────────────────────────────────────────\n\nasync function handleConnect(params: Record<string, unknown>, api?: any) {\n  const state = getWalletState();\n  console.log(`[clawnchconnect:connect] state: connected=${state.connected} mode=${state.mode} address=${state.address}`);\n\n  if (state.connected && state.address) {\n    return jsonResult({\n      status: 'already_connected',\n      address: state.address,\n      chainId: state.chainId,\n      mode: state.mode,\n      bankrEvmAddress: state.bankrEvmAddress,\n      bankrSolAddress: state.bankrSolAddress,\n    });\n  }\n\n  // Bankr wallet — simplified connect (no pairing URI)\n  const wallet = readStringParam(params, 'wallet') || 'other';\n  if (wallet === 'bankr') {\n    const bankrApiKey = getCredentialVault().getSecret('bankr.apiKey', 'clawnchconnect');\n    if (!bankrApiKey) {\n      return errorResult(\n        'BANKR_API_KEY not set. Get a key at bankr.bot/api with Agent API enabled, ' +\n        'then set: fly secrets set BANKR_API_KEY=\"bk_your_key\" -a <your-app>'\n      );\n    }\n    try {\n      const result = await initWalletService({ bankrApiKey });\n      if (result.mode === 'bankr') {\n        return jsonResult({\n          status: 'connected',\n          mode: 'bankr',\n          address: result.address,\n          solAddress: result.solAddress,\n          note: 'Connected via Bankr custodial wallet. Transactions execute server-side.',\n        });\n      }\n      return errorResult('Bankr wallet initialization failed.');\n    } catch (err) {\n      return errorResult(`Bankr connect failed: ${err instanceof Error ? err.message : String(err)}`);\n    }\n  }\n\n  const projectId = readStringParam(params, 'project_id')\n    || (getCredentialVault().getSecret('walletconnect.projectId', 'clawnchconnect') ?? undefined);\n  const privateKey = getCredentialVault().getSecret('wallet.privateKey', 'clawnchconnect') ?? undefined;\n\n  if (!projectId && !privateKey) {\n    return errorResult(\n      'No wallet configuration found. Set WALLETCONNECT_PROJECT_ID env var ' +\n      'or pass project_id parameter to connect via WalletConnect. ' +\n      'For testing, set CLAWNCHER_PRIVATE_KEY.'\n    );\n  }\n\n  try {\n    console.log(`[clawnchconnect:connect] Calling initWalletService (fresh)`);\n    const result = await initWalletService({\n      privateKey,\n      walletConnectProjectId: projectId,\n      rpcUrl: process.env.CLAWNCHER_RPC_URL,\n      network: (process.env.CLAWNCHER_NETWORK as 'mainnet' | 'sepolia') || 'mainnet',\n      sessionPath: process.env.WALLETCONNECT_SESSION\n        || `${process.env.HOME ?? ''}/.openclawnch/wc-session.json`,\n    });\n\n    console.log(`[clawnchconnect:connect] initWalletService result: mode=${result.mode} hasUri=${!!result.pairingUri} hasAddress=${!!result.address}`);\n\n    if (result.mode === 'private_key') {\n      return jsonResult({\n        status: 'connected',\n        mode: 'private_key',\n        address: result.address,\n        note: 'Using private key (headless mode). Transactions are auto-signed.',\n      });\n    }\n\n    if (result.pairingUri) {\n      const wallet = readStringParam(params, 'wallet') || 'other';\n\n      // Start background session wait. When the user approves in their wallet,\n      // this resolves and sets _walletClient so subsequent tools can use it.\n      // We don't await it here — the tool returns the link immediately,\n      // and the session establishes in the background.\n      waitForWalletSession(300_000)\n        .then((session) => {\n          console.log(`[clawnchconnect] Session established: ${session.address} (chain ${session.chainId})`);\n          // Proactively confirm wallet pairing to the user\n          if (api) {\n            const sendFn = api.runtime?.channel?.telegram?.sendMessageTelegram;\n            // Use the chat ID from the execution context (injected by the gateway,\n            // not from LLM-controlled params). Only accept numeric Telegram chat IDs.\n            const chatId = params._chatId ?? params._senderId;\n            const chatIdStr = chatId != null ? String(chatId) : '';\n            if (sendFn && chatIdStr && /^\\d+$/.test(chatIdStr)) {\n              sendFn(chatIdStr,\n                `Wallet connected!\\n\\nAddress: ${session.address.slice(0, 6)}...${session.address.slice(-4)}\\nChain: ${session.chainId}\\n\\nYou're ready to trade. Try: \"What's the price of ETH?\" or \"Show my balance\"`,\n                { accountId: 'default' }\n              ).catch((err: any) => console.log(`[clawnchconnect] Failed to send confirmation: ${err}`));\n            } else {\n              api.logger?.info?.(`[clawnchconnect] Wallet connected: ${session.address} — no chatId available to send confirmation`);\n            }\n          }\n        })\n        .catch((err) => {\n          console.log(`[clawnchconnect] Session wait failed: ${err instanceof Error ? err.message : String(err)}`);\n        });\n\n      return returnConnectLink(result.pairingUri, wallet);\n    }\n\n    if (result.address) {\n      return jsonResult({\n        status: 'connected',\n        mode: 'walletconnect',\n        address: result.address,\n        note: 'Session restored from previous connection.',\n      });\n    }\n\n    return errorResult('WalletConnect failed to generate a pairing link. The relay server may be down. Try again in a minute.');\n  } catch (err) {\n    const msg = err instanceof Error ? err.message : String(err);\n    console.log(`[clawnchconnect:connect] Error: ${msg}`);\n    return errorResult(`Connection failed: ${msg}`);\n  }\n}\n\n/**\n * Build a wallet-specific connect link and return it.\n * Mobile wallets get a tappable deep link. Desktop/extension wallets get the raw wc: URI to paste.\n */\nfunction returnConnectLink(pairingUri: string, wallet: string) {\n  const encodedUri = encodeURIComponent(pairingUri);\n\n  if (DESKTOP_WALLETS.has(wallet)) {\n    // Desktop/extension wallets — user copies the raw URI and pastes into wallet\n    console.log(`[clawnchconnect] Desktop wallet \"${wallet}\" — returning raw URI`);\n    return textResult(\n      `Copy this connection code and paste it in your wallet's WalletConnect input:\\n\\n` +\n      `${pairingUri}\\n\\n` +\n      `Expires in 5 minutes.`\n    );\n  }\n\n  // Mobile wallet — return tappable deep link\n  const deepLinkBase = WALLET_DEEPLINKS[wallet];\n  if (deepLinkBase) {\n    const deepLink = `${deepLinkBase}${encodedUri}`;\n    console.log(`[clawnchconnect] Deep link for \"${wallet}\" (${deepLink.length} chars)`);\n    return textResult(deepLink);\n  }\n\n  // Unknown wallet — return raw URI with instructions\n  console.log(`[clawnchconnect] Unknown wallet \"${wallet}\" — returning raw URI`);\n  return textResult(\n    `Copy this connection code and paste it in your wallet's WalletConnect scanner:\\n\\n` +\n    `${pairingUri}\\n\\n` +\n    `Expires in 5 minutes.`\n  );\n}\n\nasync function handleStatus() {\n  const state = getWalletState();\n\n  if (!state.connected) {\n    return jsonResult({\n      status: 'disconnected',\n      message: 'No wallet connected. Use action \"connect\" to pair a wallet.',\n    });\n  }\n\n  // Bankr mode: show both EVM and Solana addresses, Club status\n  if (state.mode === 'bankr') {\n    return jsonResult({\n      status: 'connected',\n      mode: 'bankr',\n      evmAddress: state.bankrEvmAddress,\n      solanaAddress: state.bankrSolAddress,\n      bankrClub: state.bankrClub,\n      chains: ['base', 'ethereum', 'polygon', 'unichain', 'solana'],\n      security: 'Bankr Sentinel (server-side transaction screening)',\n      note: 'Custodial wallet — transactions execute server-side. No phone approval needed.',\n    });\n  }\n\n  // Try to get ETH balance\n  let ethBalance: string | undefined;\n  try {\n    const { requirePublicClient } = await import('../services/walletconnect-service.js');\n    const publicClient = requirePublicClient();\n    const balance = await publicClient.getBalance({ address: state.address! });\n    const { formatEther } = await import('viem');\n    ethBalance = formatEther(balance);\n  } catch {\n    // Non-fatal\n  }\n\n  // Include recent transaction history\n  const txHistory = getTransactionHistory();\n  const recentTxs = txHistory.slice(-5).reverse().map(tx => ({\n    status: tx.status,\n    summary: tx.summary,\n    hash: tx.hash,\n    policyLabel: tx.policyLabel,\n  }));\n\n  return jsonResult({\n    status: 'connected',\n    address: state.address,\n    chainId: state.chainId,\n    mode: state.mode,\n    ethBalance,\n    policies: state.policies.map(p => ({\n      label: p.label,\n      maxValueEth: p.maxValueWei ? Number(p.maxValueWei) / 1e18 : 'unlimited',\n      allowedContracts: p.allowedContracts?.length ?? 'any',\n      maxPerHour: p.maxPerHour ?? 'unlimited',\n      enabled: p.enabled !== false,\n    })),\n    recentTransactions: recentTxs.length > 0 ? recentTxs : undefined,\n    transactionCount: txHistory.length || undefined,\n  });\n}\n\nasync function handleDisconnect() {\n  const state = getWalletState();\n  if (!state.connected) {\n    return textResult('No wallet is currently connected.');\n  }\n\n  await disconnectWallet();\n  return textResult(`Disconnected wallet ${state.address}. Session cleared.`);\n}\n\n// H4: Address validation helper\nfunction isValidAddress(addr: string): boolean {\n  return /^0x[a-fA-F0-9]{40}$/.test(addr);\n}\n\nasync function handleSendTx(params: Record<string, unknown>) {\n  const state = getWalletState();\n  if (!state.connected) {\n    return errorResult('No wallet connected. Use action \"connect\" first.');\n  }\n\n  // Bankr mode: submit via Bankr prompt API\n  if (isBankrMode()) {\n    const to = readStringParam(params, 'to', { required: true })!;\n    // H4: Validate address\n    if (!isValidAddress(to)) {\n      return errorResult(`Invalid target address: \"${to}\". Must be a valid 0x... Ethereum address.`);\n    }\n    const valueStr = readStringParam(params, 'value');\n    const summary = readStringParam(params, 'summary') || 'Transaction submitted by agent';\n\n    try {\n      const { bankrPromptAndPoll } = await import('../services/bankr-api.js');\n      const prompt = valueStr\n        ? `send ${valueStr} ETH to ${to}`\n        : `send transaction to ${to}`;\n      const result = await bankrPromptAndPoll(prompt, { timeoutMs: 60_000 });\n\n      if (result.status === 'failed') {\n        return errorResult(`Transaction failed: ${result.error ?? 'Unknown error'}`);\n      }\n\n      const txData = result.transactions?.[0];\n      return jsonResult({\n        status: 'sent',\n        mode: 'bankr',\n        hash: txData?.hash,\n        summary,\n        response: result.response,\n      });\n    } catch (err) {\n      return errorResult(`Transaction failed: ${err instanceof Error ? err.message : String(err)}`);\n    }\n  }\n\n  const signer = getWCSigner();\n\n  const to = readStringParam(params, 'to', { required: true })!;\n  // H4: Validate address\n  if (!isValidAddress(to)) {\n    return errorResult(`Invalid target address: \"${to}\". Must be a valid 0x... Ethereum address.`);\n  }\n  const valueStr = readStringParam(params, 'value');\n  const data = readStringParam(params, 'data');\n  const summary = readStringParam(params, 'summary') || 'Transaction submitted by agent';\n\n  // Validate value before parseEther to prevent opaque viem errors\n  if (valueStr && !/^\\d+(\\.\\d+)?$/.test(valueStr.trim())) {\n    return errorResult(`Invalid value: \"${valueStr}\". Must be a positive number (in ETH).`);\n  }\n\n  try {\n    const { parseEther } = await import('viem');\n    const value = valueStr ? parseEther(valueStr) : undefined;\n\n    if (signer) {\n      // WalletConnect path — goes through policies + user approval\n      const result = await signer.sendTransaction(\n        {\n          to: to as `0x${string}`,\n          value,\n          data: data as `0x${string}` | undefined,\n        },\n        {\n          summary,\n          estimatedGasCostEth: 'estimating...',\n        },\n      );\n\n      // Wait for on-chain confirmation\n      const { requirePublicClient } = await import('../services/walletconnect-service.js');\n      const publicClient = requirePublicClient();\n      const receipt = await publicClient.waitForTransactionReceipt({ hash: result.hash });\n\n      return jsonResult({\n        status: receipt.status === 'reverted' ? 'reverted' : (result.autoApproved ? 'auto_approved' : 'approved'),\n        hash: result.hash,\n        policyLabel: result.policyLabel,\n        summary,\n        blockNumber: receipt.blockNumber.toString(),\n        gasUsed: receipt.gasUsed.toString(),\n      });\n    } else {\n      // Private key path — direct send\n      const { requireWalletClient, requirePublicClient } = await import('../services/walletconnect-service.js');\n      const wallet = requireWalletClient();\n      const publicClient = requirePublicClient();\n      const hash = await wallet.sendTransaction({\n        to: to as `0x${string}`,\n        value,\n        data: data as `0x${string}` | undefined,\n      });\n\n      // Wait for on-chain confirmation\n      const receipt = await publicClient.waitForTransactionReceipt({ hash });\n\n      return jsonResult({\n        status: receipt.status === 'reverted' ? 'reverted' : 'sent',\n        hash,\n        summary,\n        blockNumber: receipt.blockNumber.toString(),\n        gasUsed: receipt.gasUsed.toString(),\n        note: 'Sent directly (private key mode, no approval required)',\n      });\n    }\n  } catch (err) {\n    return errorResult(`Transaction failed: ${err instanceof Error ? err.message : String(err)}`);\n  }\n}\n\nasync function handleSetPolicy(params: Record<string, unknown>) {\n  const policyInput = readStringParam(params, 'policy', { required: true })!;\n\n  try {\n    const { parsePolicies, formatPolicy } = await import('@clawnch/sdk');\n    const result = parsePolicies(policyInput);\n\n    if (result.clearAll) {\n      clearPolicies();\n      return textResult('All spending policies cleared. Every transaction will require manual approval.');\n    }\n\n    if (result.unrecognized.length > 0 && result.policies.length === 0) {\n      return errorResult(\n        `Could not parse policy: \"${policyInput}\"\\n\\n` +\n        'Examples:\\n' +\n        '  \"approve under 0.05 ETH\"\\n' +\n        '  \"auto-approve below 0.01 ETH, max 10/hour\"\\n' +\n        '  \"allow only 0xABC...DEF\"\\n' +\n        '  \"no auto-approve\" (clear all)'\n      );\n    }\n\n    // Add each parsed policy\n    for (const policy of result.policies) {\n      addPolicy(policy);\n    }\n\n    const formatted = result.policies.map(p => formatPolicy(p));\n\n    return jsonResult({\n      status: 'policies_updated',\n      added: formatted,\n      unrecognized: result.unrecognized.length > 0 ? result.unrecognized : undefined,\n      allPolicies: getWalletState().policies.map(p => formatPolicy(p)),\n    });\n  } catch (err) {\n    return errorResult(`Failed to set policy: ${err instanceof Error ? err.message : String(err)}`);\n  }\n}\n\nasync function handleSignMessage(params: Record<string, unknown>) {\n  const message = readStringParam(params, 'message', { required: true })!;\n\n  // Bankr mode: use Bankr sign endpoint\n  if (isBankrMode()) {\n    try {\n      const { bankrSign } = await import('../services/bankr-api.js');\n      const result = await bankrSign({\n        signatureType: 'personal_sign',\n        message,\n      });\n      return jsonResult({\n        status: 'signed',\n        signature: result.signature,\n        signer: result.signer,\n        mode: 'bankr',\n        message,\n      });\n    } catch (err) {\n      return errorResult(`Bankr signing failed: ${err instanceof Error ? err.message : String(err)}`);\n    }\n  }\n\n  const signer = getWCSigner();\n  if (!signer) {\n    return errorResult('Message signing requires WalletConnect or Bankr. Not available in private key mode.');\n  }\n\n  try {\n    const result = await signer.signMessage(message);\n    return jsonResult({\n      status: 'signed',\n      signature: result.signature,\n      message,\n    });\n  } catch (err) {\n    return errorResult(`Signing failed: ${err instanceof Error ? err.message : String(err)}`);\n  }\n}\n"],"mappings":"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"}