{"version":3,"file":"yield.mjs","names":[],"sources":["../../../src/tools/yield.ts"],"sourcesContent":["/**\n * Yield Aggregation Tool — find and execute yield opportunities across DeFi.\n *\n * Actions:\n *   search         — Search DeFiLlama for yield opportunities (filter by chain, asset, APY)\n *   top_yields     — Top yields for a specific asset on a chain\n *   deposit        — Deposit into a Yearn V3 vault (ERC-4626) on Base\n *   withdraw       — Withdraw from a Yearn V3 vault\n *   positions      — View vault positions and earned yield\n *   vaults         — List available vaults for direct deposit\n *\n * Data from DeFiLlama yields API. Execution via Yearn V3 vaults on Base.\n */\n\nimport { Type } from '@sinclair/typebox';\nimport { formatUnits } from 'viem';\nimport { stringEnum, jsonResult, errorResult, readStringParam, readNumberParam } from '../lib/tool-helpers.js';\nimport {\n  getWalletState,\n  requireWalletClient,\n  requirePublicClient,\n} from '../services/walletconnect-service.js';\nimport { getYieldService } from '../services/yield-service.js';\n\nconst ACTIONS = ['search', 'top_yields', 'deposit', 'withdraw', 'positions', 'vaults'] as const;\n\nconst YieldSchema = Type.Object({\n  action: stringEnum(ACTIONS, {\n    description:\n      'search: find yield pools across DeFi. top_yields: best yields for an asset. ' +\n      'deposit: deposit into Yearn V3 vault. withdraw: exit vault position. ' +\n      'positions: view vault positions. vaults: list available vaults.',\n  }),\n  asset: Type.Optional(Type.String({\n    description: 'Asset symbol (USDC, WETH, ETH, DAI). Used for search/top_yields/deposit/withdraw.',\n  })),\n  chain: Type.Optional(Type.String({\n    description: 'Chain name: \"base\" (default), \"ethereum\", \"arbitrum\", \"optimism\", \"polygon\".',\n  })),\n  amount: Type.Optional(Type.String({\n    description: 'Amount in human-readable units (e.g. \"100\" USDC, \"0.5\" ETH). Use \"max\" for withdraw. Required for deposit/withdraw.',\n  })),\n  vault: Type.Optional(Type.String({\n    description: 'Vault name (yvUSDC, yvWETH, yvDAI) or address. Required for deposit/withdraw.',\n  })),\n  min_tvl: Type.Optional(Type.Number({\n    description: 'Minimum TVL in USD for search results. Default: 100000.',\n  })),\n  min_apy: Type.Optional(Type.Number({\n    description: 'Minimum APY % for search results.',\n  })),\n  stable_only: Type.Optional(Type.Boolean({\n    description: 'Only show stablecoin pools. Default: false.',\n  })),\n  project: Type.Optional(Type.String({\n    description: 'Filter by protocol name (e.g. \"aave\", \"yearn\", \"moonwell\", \"morpho\").',\n  })),\n  limit: Type.Optional(Type.Number({\n    description: 'Max results for search. Default: 20.',\n  })),\n});\n\nexport function createYieldTool() {\n  return {\n    name: 'yield',\n    label: 'Yield',\n    ownerOnly: true,\n    description:\n      'Find and execute yield opportunities across DeFi. Search DeFiLlama for best APYs, ' +\n      'deposit into Yearn V3 vaults on Base (ERC-4626), or view your vault positions. ' +\n      'Covers 400+ protocols across all EVM chains.',\n    parameters: YieldSchema,\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 'search':\n          return handleSearch(params);\n        case 'top_yields':\n          return handleTopYields(params);\n        case 'deposit':\n          return handleDeposit(params);\n        case 'withdraw':\n          return handleWithdraw(params);\n        case 'positions':\n          return handlePositions();\n        case 'vaults':\n          return handleVaults();\n        default:\n          return errorResult(`Unknown action: ${action}. Use: search, top_yields, deposit, withdraw, positions, vaults`);\n      }\n    },\n  };\n}\n\n// ── Action Handlers ─────────────────────────────────────────────────────\n\nasync function handleSearch(params: Record<string, unknown>) {\n  try {\n    const service = getYieldService();\n    const pools = await service.searchPools({\n      chain: readStringParam(params, 'chain') ?? undefined,\n      asset: readStringParam(params, 'asset') ?? undefined,\n      project: readStringParam(params, 'project') ?? undefined,\n      minTvl: readNumberParam(params, 'min_tvl') ?? undefined,\n      minApy: readNumberParam(params, 'min_apy') ?? undefined,\n      stableOnly: params.stable_only === true,\n      singleExposure: params.single_exposure === true,\n      limit: readNumberParam(params, 'limit') ?? 20,\n    });\n\n    if (pools.length === 0) {\n      return jsonResult({\n        results: [],\n        message: 'No pools found matching your criteria. Try broadening your search filters.',\n      });\n    }\n\n    return jsonResult({\n      count: pools.length,\n      pools: pools.map(p => ({\n        protocol: p.project,\n        chain: p.chain,\n        symbol: p.symbol,\n        apy: `${p.apy.toFixed(2)}%`,\n        apyBase: p.apyBase !== null ? `${p.apyBase.toFixed(2)}%` : null,\n        apyReward: p.apyReward !== null ? `${p.apyReward.toFixed(2)}%` : null,\n        tvl: formatTvl(p.tvlUsd),\n        stablecoin: p.stablecoin,\n        ilRisk: p.ilRisk,\n        exposure: p.exposure,\n      })),\n      tip: 'Use action=deposit with a vault name to deposit directly, or action=top_yields for asset-specific results.',\n    });\n  } catch (err) {\n    return errorResult(`Yield search failed: ${err instanceof Error ? err.message : String(err)}`);\n  }\n}\n\nasync function handleTopYields(params: Record<string, unknown>) {\n  const asset = readStringParam(params, 'asset');\n  if (!asset) {\n    return errorResult('asset is required for top_yields (e.g. \"USDC\", \"WETH\", \"ETH\").');\n  }\n\n  const chain = readStringParam(params, 'chain') ?? 'base';\n  const limit = readNumberParam(params, 'limit') ?? 10;\n\n  try {\n    const service = getYieldService();\n    const pools = await service.topYieldsForAsset(asset, chain, limit);\n\n    if (pools.length === 0) {\n      return jsonResult({\n        asset,\n        chain,\n        results: [],\n        message: `No yield pools found for ${asset} on ${chain}.`,\n      });\n    }\n\n    return jsonResult({\n      asset,\n      chain,\n      count: pools.length,\n      pools: pools.map(p => ({\n        protocol: p.project,\n        symbol: p.symbol,\n        apy: `${p.apy.toFixed(2)}%`,\n        tvl: formatTvl(p.tvlUsd),\n        stablecoin: p.stablecoin,\n        meta: p.poolMeta,\n      })),\n    });\n  } catch (err) {\n    return errorResult(`Top yields failed: ${err instanceof Error ? err.message : String(err)}`);\n  }\n}\n\nasync function handleDeposit(params: Record<string, unknown>) {\n  const vaultInput = readStringParam(params, 'vault') ?? readStringParam(params, 'asset');\n  const amountInput = readStringParam(params, 'amount');\n  if (!vaultInput || !amountInput) {\n    return errorResult('Both vault (or asset) and amount are required for deposit.');\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  const service = getYieldService();\n  const vault = service.resolveVault(vaultInput);\n  if (!vault) {\n    const available = service.getAvailableVaults().map(v => `${v.name} (${v.asset})`).join(', ');\n    return errorResult(`Unknown vault: \"${vaultInput}\". Available: ${available}`);\n  }\n\n  try {\n    const amount = parseAmount(amountInput, vault.decimals);\n    const tokenAddress = service.getTokenAddress(vault.asset);\n    if (!tokenAddress) {\n      return errorResult(`Cannot resolve token address for ${vault.asset}.`);\n    }\n\n    const wallet = requireWalletClient();\n    const publicClient = requirePublicClient();\n\n    const result = await service.deposit(\n      vault.address,\n      tokenAddress,\n      amount,\n      state.address as `0x${string}`,\n      wallet,\n      publicClient,\n    );\n\n    return jsonResult({\n      status: 'success',\n      action: 'deposit',\n      vault: vault.name,\n      vaultAddress: vault.address,\n      asset: vault.asset,\n      amount: formatUnits(amount, vault.decimals),\n      txHash: result.hash,\n      chain: 'base',\n      note: `Deposited into ${vault.name} vault. Yield accrues automatically.`,\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 vaultInput = readStringParam(params, 'vault') ?? readStringParam(params, 'asset');\n  const amountInput = readStringParam(params, 'amount');\n  if (!vaultInput || !amountInput) {\n    return errorResult('Both vault (or asset) and amount are required for withdraw. Use \"max\" for full withdrawal.');\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  const service = getYieldService();\n  const vault = service.resolveVault(vaultInput);\n  if (!vault) {\n    const available = service.getAvailableVaults().map(v => `${v.name} (${v.asset})`).join(', ');\n    return errorResult(`Unknown vault: \"${vaultInput}\". Available: ${available}`);\n  }\n\n  try {\n    const isMax = amountInput.toLowerCase() === 'max';\n    const amount = isMax ? 0n : parseAmount(amountInput, vault.decimals);\n\n    const wallet = requireWalletClient();\n    const publicClient = requirePublicClient();\n\n    const result = await service.withdraw(\n      vault.address,\n      amount,\n      state.address as `0x${string}`,\n      wallet,\n      publicClient,\n      isMax,\n      vault.decimals,\n    );\n\n    return jsonResult({\n      status: 'success',\n      action: 'withdraw',\n      vault: vault.name,\n      vaultAddress: vault.address,\n      asset: vault.asset,\n      amount: result.assetsReturned,\n      txHash: result.hash,\n      chain: 'base',\n    });\n  } catch (err) {\n    return errorResult(`Withdraw failed: ${err instanceof Error ? err.message : String(err)}`);\n  }\n}\n\nasync function handlePositions() {\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 publicClient = requirePublicClient();\n    const service = getYieldService();\n    const positions = await service.getPositions(\n      state.address as `0x${string}`,\n      publicClient,\n    );\n\n    if (positions.length === 0) {\n      return jsonResult({\n        positions: [],\n        message: 'No vault positions found. Use action=vaults to see available vaults, or action=search to find yield opportunities.',\n      });\n    }\n\n    return jsonResult({\n      chain: 'base',\n      address: state.address,\n      positions: positions.map(p => ({\n        vault: p.vault,\n        asset: p.asset,\n        shares: p.shares,\n        value: `${p.assetsValue} ${p.asset}`,\n        apy: p.apy !== undefined ? `${p.apy.toFixed(2)}%` : 'unknown',\n      })),\n    });\n  } catch (err) {\n    return errorResult(`Positions check failed: ${err instanceof Error ? err.message : String(err)}`);\n  }\n}\n\nasync function handleVaults() {\n  const service = getYieldService();\n  const vaults = service.getAvailableVaults();\n\n  return jsonResult({\n    chain: 'base',\n    protocol: 'Yearn V3',\n    standard: 'ERC-4626',\n    vaults: vaults.map(v => ({\n      name: v.name,\n      asset: v.asset,\n      address: v.address,\n    })),\n    note: 'Use action=deposit with vault name and amount to deposit. Use action=search to discover more yield options across all protocols.',\n  });\n}\n\n// ── Helpers ──────────────────────────────────────────────────────────────\n\nfunction parseAmount(amount: string, decimals: number): bigint {\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.`);\n  }\n\n  const parts = trimmed.split('.');\n  const whole = parts[0] ?? '0';\n  let fraction = parts[1] ?? '';\n  if (fraction.length > decimals) {\n    fraction = fraction.slice(0, decimals);\n  } else {\n    fraction = fraction.padEnd(decimals, '0');\n  }\n  const result = BigInt(whole + fraction);\n  if (result === 0n) throw new Error('Amount must be greater than zero.');\n  return result;\n}\n\nfunction formatTvl(tvl: number): string {\n  if (tvl >= 1_000_000_000) return `$${(tvl / 1_000_000_000).toFixed(2)}B`;\n  if (tvl >= 1_000_000) return `$${(tvl / 1_000_000).toFixed(2)}M`;\n  if (tvl >= 1_000) return `$${(tvl / 1_000).toFixed(1)}K`;\n  return `$${tvl.toFixed(0)}`;\n}\n"],"mappings":"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"}