{"version":3,"file":"crypto-workflow.mjs","names":[],"sources":["../../../src/tools/crypto-workflow.ts"],"sourcesContent":["/**\n * Crypto Workflow Tool — orchestrates multi-tool pipelines.\n *\n * Named workflows chain existing tool logic into safe, complete operations.\n * Each workflow runs pre-flight checks, executes the core action, and\n * performs follow-up steps (monitoring, social, order management).\n *\n * This tool exists because LLMs can forget steps in a multi-tool sequence.\n * The workflow guarantees all steps happen, in order, with safety checks.\n */\n\nimport { Type } from '@sinclair/typebox';\nimport { stringEnum, jsonResult, errorResult, readStringParam, readNumberParam } from '../lib/tool-helpers.js';\nimport { getWalletState, getTransactionHistory } from '../services/walletconnect-service.js';\nimport { getPrice, getEthPrice } from '../services/price-service.js';\nimport { validateSwap, validateLaunch } from '../services/safety-service.js';\n\nconst WORKFLOWS = [\n  'safe_swap',\n  'launch_and_promote',\n  'check_orders',\n  'portfolio_snapshot',\n] as const;\n\nconst CryptoWorkflowSchema = Type.Object({\n  workflow: stringEnum(WORKFLOWS, {\n    description:\n      'safe_swap: price check + audit + balance check + swap + set stop-loss. ' +\n      'launch_and_promote: balance check + deploy + generate tweet text. ' +\n      'check_orders: auto-fetch prices and check all order triggers. ' +\n      'portfolio_snapshot: balance + positions + unrealized PnL.',\n  }),\n  // safe_swap params\n  token_in: Type.Optional(Type.String({ description: 'Token to sell (for safe_swap)' })),\n  token_out: Type.Optional(Type.String({ description: 'Token to buy (for safe_swap)' })),\n  amount: Type.Optional(Type.String({ description: 'Amount to sell (for safe_swap)' })),\n  slippage: Type.Optional(Type.Number({ description: 'Slippage % (for safe_swap, default 1.0)' })),\n  stop_loss_pct: Type.Optional(Type.Number({ description: 'Auto stop-loss % below entry (for safe_swap, default: none)' })),\n  // launch_and_promote params\n  name: Type.Optional(Type.String({ description: 'Token name (for launch_and_promote)' })),\n  symbol: Type.Optional(Type.String({ description: 'Token symbol (for launch_and_promote)' })),\n  description: Type.Optional(Type.String({ description: 'Token description (for launch_and_promote)' })),\n  dev_buy_eth: Type.Optional(Type.String({ description: 'Dev buy ETH amount (for launch_and_promote)' })),\n});\n\nexport function createCryptoWorkflowTool() {\n  return {\n    name: 'crypto_workflow',\n    label: 'Crypto Workflow',\n    ownerOnly: true, // safe_swap and launch_and_promote involve spending funds\n    description:\n      'Multi-step crypto workflows that chain tools together with safety checks. ' +\n      'Use \"safe_swap\" for audited token swaps, \"launch_and_promote\" for token launches ' +\n      'with auto-generated tweet text, \"check_orders\" to auto-check all order triggers ' +\n      'with live prices, \"portfolio_snapshot\" for a full portfolio view.',\n    parameters: CryptoWorkflowSchema,\n    execute: async (_toolCallId: string, args: unknown) => {\n      const params = args as Record<string, unknown>;\n      const workflow = readStringParam(params, 'workflow', { required: true })!;\n\n      switch (workflow) {\n        case 'safe_swap':\n          return handleSafeSwap(params);\n        case 'launch_and_promote':\n          return handleLaunchAndPromote(params);\n        case 'check_orders':\n          return handleCheckOrders();\n        case 'portfolio_snapshot':\n          return handlePortfolioSnapshot();\n        default:\n          return errorResult(`Unknown workflow: ${workflow}`);\n      }\n    },\n  };\n}\n\n// ─── safe_swap: price → audit → balance → quote → execute → stop-loss ────\n\nasync function handleSafeSwap(params: Record<string, unknown>) {\n  const tokenIn = readStringParam(params, 'token_in', { required: true })!;\n  const tokenOut = readStringParam(params, 'token_out', { required: true })!;\n  const amount = readStringParam(params, 'amount', { required: true })!;\n  const slippage = readNumberParam(params, 'slippage') ?? 1.0;\n  const stopLossPct = readNumberParam(params, 'stop_loss_pct');\n\n  const steps: Array<{ step: string; status: string; data?: unknown }> = [];\n\n  // Step 1: Wallet check\n  const state = getWalletState();\n  if (!state.connected) {\n    return errorResult('No wallet connected. Use clawnchconnect tool first.');\n  }\n  steps.push({ step: 'wallet_check', status: 'ok', data: { address: state.address } });\n\n  // Step 2: Price lookup for both tokens\n  let priceIn: any = null;\n  let priceOut: any = null;\n  try {\n    [priceIn, priceOut] = await Promise.all([\n      getPrice(tokenIn).catch(() => null),\n      getPrice(tokenOut).catch(() => null),\n    ]);\n    steps.push({\n      step: 'price_lookup',\n      status: 'ok',\n      data: {\n        tokenIn: priceIn ? { symbol: priceIn.symbol, priceUsd: priceIn.priceUsd } : 'unknown',\n        tokenOut: priceOut ? { symbol: priceOut.symbol, priceUsd: priceOut.priceUsd } : 'unknown',\n      },\n    });\n  } catch {\n    steps.push({ step: 'price_lookup', status: 'warning', data: 'Price lookup failed' });\n  }\n\n  // Step 3: Safety validation (balance + token audit)\n  const safety = await validateSwap({\n    tokenIn,\n    tokenOut,\n    amountEth: parseFloat(amount),\n  });\n\n  steps.push({\n    step: 'safety_check',\n    status: safety.safe ? 'ok' : 'blocked',\n    data: {\n      safe: safety.safe,\n      warnings: safety.warnings,\n      blockers: safety.blockers,\n    },\n  });\n\n  if (!safety.safe) {\n    return jsonResult({\n      workflow: 'safe_swap',\n      status: 'blocked',\n      steps,\n      message: 'Swap blocked by safety checks. Review blockers above.',\n    });\n  }\n\n  // Step 4: Return the pipeline result with execution instructions.\n  // The actual swap execution should be done by calling defi_swap tool,\n  // which now also includes safety checks. This workflow's value is the\n  // upfront aggregation of all context.\n  const swapInstruction = {\n    tool: 'defi_swap',\n    action: 'execute',\n    params: {\n      token_in: tokenIn,\n      token_out: tokenOut,\n      amount,\n      slippage,\n    },\n  };\n\n  steps.push({ step: 'swap_ready', status: 'ready', data: swapInstruction });\n\n  // Step 5: Stop-loss recommendation\n  let stopLossInstruction: any = null;\n  if (stopLossPct && priceOut) {\n    const stopPrice = priceOut.priceEth * (1 - stopLossPct / 100);\n    stopLossInstruction = {\n      tool: 'manage_orders',\n      action: 'create',\n      params: {\n        type: 'stop_loss',\n        token: tokenOut,\n        trigger_price: stopPrice.toFixed(8),\n        amount_pct: 100,\n        description: `Auto stop-loss at -${stopLossPct}% from entry`,\n      },\n    };\n    steps.push({ step: 'stop_loss_prepared', status: 'ready', data: stopLossInstruction });\n  }\n\n  return jsonResult({\n    workflow: 'safe_swap',\n    status: 'ready',\n    steps,\n    nextActions: [\n      swapInstruction,\n      ...(stopLossInstruction ? [stopLossInstruction] : []),\n    ],\n    message: safety.warnings.length\n      ? `Swap is ready with ${safety.warnings.length} warning(s). Execute defi_swap to proceed.`\n      : 'All checks passed. Execute defi_swap to proceed.',\n  });\n}\n\n// ─── launch_and_promote: balance → deploy instructions → tweet text ──────\n\nasync function handleLaunchAndPromote(params: Record<string, unknown>) {\n  const name = readStringParam(params, 'name', { required: true })!;\n  const symbol = readStringParam(params, 'symbol', { required: true })!;\n  const description = readStringParam(params, 'description') ?? '';\n  const devBuyEth = readStringParam(params, 'dev_buy_eth');\n\n  const steps: Array<{ step: string; status: string; data?: unknown }> = [];\n\n  // Step 1: Wallet check\n  const state = getWalletState();\n  if (!state.connected) {\n    return errorResult('No wallet connected. Use clawnchconnect tool first.');\n  }\n  steps.push({ step: 'wallet_check', status: 'ok', data: { address: state.address } });\n\n  // Step 2: Balance validation\n  const safety = await validateLaunch({\n    devBuyEth: devBuyEth ? parseFloat(devBuyEth) : undefined,\n  });\n  steps.push({\n    step: 'balance_check',\n    status: safety.safe ? 'ok' : 'blocked',\n    data: safety,\n  });\n\n  if (!safety.safe) {\n    return jsonResult({\n      workflow: 'launch_and_promote',\n      status: 'blocked',\n      steps,\n      message: 'Launch blocked: ' + safety.blockers.join('; '),\n    });\n  }\n\n  // Step 3: Launch instruction\n  const launchInstruction = {\n    tool: 'clawnch_launch',\n    params: { name, symbol, description, dev_buy_eth: devBuyEth },\n  };\n  steps.push({ step: 'launch_ready', status: 'ready', data: launchInstruction });\n\n  // Step 4: Generate tweet text for post-launch promotion\n  const tweetText =\n    `Just launched $${symbol} (${name}) on @clawnch! 🦞\\n\\n` +\n    `${description ? description + '\\n\\n' : ''}` +\n    `Trade it now on Base via Uniswap V4.\\n` +\n    `1% LP fees, MEV protection, fully decentralized.\\n\\n` +\n    `#DeFi #Base #${symbol}`;\n\n  const tweetInstruction = {\n    tool: 'clawnx',\n    action: 'post',\n    params: {\n      content: tweetText,\n      note: 'Post after launch succeeds. Replace with actual token address URL.',\n    },\n  };\n  steps.push({ step: 'tweet_prepared', status: 'ready', data: tweetInstruction });\n\n  // Step 5: Monitoring instruction\n  const monitorInstruction = {\n    tool: 'watch_activity',\n    action: 'token_activity',\n    params: {\n      note: 'Use the token address from the launch result to monitor trading activity.',\n    },\n  };\n  steps.push({ step: 'monitor_prepared', status: 'ready', data: monitorInstruction });\n\n  return jsonResult({\n    workflow: 'launch_and_promote',\n    status: 'ready',\n    steps,\n    nextActions: [launchInstruction, tweetInstruction, monitorInstruction],\n    message: 'All pre-flight checks passed. Execute clawnch_launch to deploy, then follow up with tweet and monitoring.',\n  });\n}\n\n// ─── check_orders: auto-fetch prices → check all triggers ────────────────\n\nasync function handleCheckOrders() {\n  // The manage_orders tool now auto-fetches prices in its check action.\n  // This workflow provides the orchestration hint to the LLM.\n  return jsonResult({\n    workflow: 'check_orders',\n    status: 'ready',\n    nextActions: [\n      {\n        tool: 'manage_orders',\n        action: 'check',\n        note: 'The check action now auto-fetches prices from DexScreener. ' +\n          'Pass a token param if your orders use a token address.',\n      },\n    ],\n    message: 'Call manage_orders with action \"check\" to auto-check triggers with live prices. ' +\n      'Any triggered orders will include execution instructions for defi_swap.',\n  });\n}\n\n// ─── portfolio_snapshot: balance + prices + tx history ────────────────────\n\nasync function handlePortfolioSnapshot() {\n  const state = getWalletState();\n  if (!state.connected || !state.address) {\n    return errorResult('No wallet connected. Use clawnchconnect tool first.');\n  }\n\n  const steps: Array<{ step: string; status: string; data?: unknown }> = [];\n\n  // Step 1: ETH balance\n  let ethBalance = '0';\n  let ethValueUsd = 0;\n  try {\n    const { formatEther } = await import('viem');\n    const { requirePublicClient } = await import('../services/walletconnect-service.js');\n    const publicClient = requirePublicClient();\n    const balance = await publicClient.getBalance({ address: state.address });\n    ethBalance = formatEther(balance);\n\n    const ethPrice = await getEthPrice();\n    ethValueUsd = parseFloat(ethBalance) * ethPrice;\n\n    steps.push({\n      step: 'eth_balance',\n      status: 'ok',\n      data: { balance: ethBalance, priceUsd: ethPrice, valueUsd: ethValueUsd },\n    });\n  } catch (err) {\n    steps.push({ step: 'eth_balance', status: 'error', data: String(err) });\n  }\n\n  // Step 2: Recent transaction history\n  const txHistory = getTransactionHistory();\n  const recentTxs = txHistory.slice(-10).reverse();\n  steps.push({\n    step: 'recent_transactions',\n    status: 'ok',\n    data: {\n      total: txHistory.length,\n      recent: recentTxs.map(tx => ({\n        status: tx.status,\n        summary: tx.summary,\n        hash: tx.hash,\n        policyLabel: tx.policyLabel,\n      })),\n    },\n  });\n\n  // Step 3: Wallet policies\n  steps.push({\n    step: 'policies',\n    status: 'ok',\n    data: {\n      count: state.policies.length,\n      mode: state.mode,\n    },\n  });\n\n  return jsonResult({\n    workflow: 'portfolio_snapshot',\n    status: 'ok',\n    address: state.address,\n    chainId: state.chainId,\n    ethBalance,\n    ethValueUsd,\n    transactionCount: txHistory.length,\n    steps,\n    message: 'For detailed ERC-20 balances, also call defi_balance with action \"tokens\". ' +\n      'For fee revenue, call clawnch_fees with action \"check\".',\n  });\n}\n"],"mappings":"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"}