{"version":3,"file":"cost-basis.mjs","names":[],"sources":["../../../src/tools/cost-basis.ts"],"sourcesContent":["/**\n * Cost Basis & P&L Tool — Track trade history and calculate profit/loss.\n *\n * Records buy/sell prices per token, computes unrealized and realized P&L\n * using FIFO (first-in, first-out) cost basis. Persists trade records to\n * disk so data survives agent restarts.\n *\n * Actions:\n *   record_trade   — Manually record a trade (buy/sell) with price data\n *   portfolio_pnl  — Show unrealized P&L for all held tokens\n *   token_pnl      — Show detailed P&L for a specific token\n *   history        — List recent trade records\n *   export         — Export full trade history as JSON\n *\n * The after_tool_call hook in index.ts should call recordSwapTrade() when\n * defi_swap completes to auto-record trades.\n */\n\nimport { Type } from '@sinclair/typebox';\nimport { stringEnum, jsonResult, errorResult, readStringParam, readNumberParam } from '../lib/tool-helpers.js';\nimport { getWalletState } from '../services/walletconnect-service.js';\nimport * as fs from 'fs';\nimport * as path from 'path';\n\nconst ACTIONS = ['record_trade', 'portfolio_pnl', 'token_pnl', 'history', 'export'] as const;\n\n// ─── Trade Record Types ──────────────────────────────────────────────────\n\ninterface TradeRecord {\n  id: string;\n  timestamp: number;\n  type: 'buy' | 'sell';\n  token: string;          // token address\n  symbol: string;\n  amount: number;         // token amount\n  priceUsd: number;       // price per token at time of trade\n  totalUsd: number;       // amount * priceUsd\n  txHash?: string;\n  notes?: string;\n}\n\ninterface TaxLot {\n  tradeId: string;\n  timestamp: number;\n  remainingAmount: number;\n  costBasisPerUnit: number;\n}\n\ninterface TradeStore {\n  trades: TradeRecord[];\n  version: number;\n}\n\n// ─── Persistence ─────────────────────────────────────────────────────────\n\nfunction getDataDir(): string {\n  return process.env.OPENCLAWNCH_TX_DIR\n    || path.join(process.env.HOME ?? '', '.openclawnch', 'data');\n}\n\nfunction getStorePath(): string {\n  return path.join(getDataDir(), 'trade-history.json');\n}\n\nfunction loadStore(): TradeStore {\n  try {\n    const raw = fs.readFileSync(getStorePath(), 'utf-8');\n    return JSON.parse(raw) as TradeStore;\n  } catch {\n    return { trades: [], version: 1 };\n  }\n}\n\nfunction saveStore(store: TradeStore): void {\n  const dir = getDataDir();\n  if (!fs.existsSync(dir)) {\n    fs.mkdirSync(dir, { recursive: true });\n  }\n  fs.writeFileSync(getStorePath(), JSON.stringify(store, null, 2));\n}\n\n// ─── Public API for Hook Integration ─────────────────────────────────────\n\n/**\n * Called by after_tool_call hook when a swap completes.\n * Records the trade automatically.\n */\nexport function recordSwapTrade(params: {\n  token: string;\n  symbol: string;\n  amount: number;\n  priceUsd: number;\n  type: 'buy' | 'sell';\n  txHash?: string;\n}): void {\n  const store = loadStore();\n  const trade: TradeRecord = {\n    id: `t_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,\n    timestamp: Date.now(),\n    type: params.type,\n    token: params.token.toLowerCase(),\n    symbol: params.symbol.toUpperCase(),\n    amount: params.amount,\n    priceUsd: params.priceUsd,\n    totalUsd: params.amount * params.priceUsd,\n    txHash: params.txHash,\n  };\n  store.trades.push(trade);\n  saveStore(store);\n}\n\n// ─── Schema ──────────────────────────────────────────────────────────────\n\nconst CostBasisSchema = Type.Object({\n  action: stringEnum(ACTIONS, {\n    description:\n      'record_trade: manually record a buy/sell. ' +\n      'portfolio_pnl: unrealized P&L for all holdings. ' +\n      'token_pnl: detailed P&L for one token. ' +\n      'history: list recent trades. ' +\n      'export: full trade history JSON.',\n  }),\n  token: Type.Optional(Type.String({\n    description: 'Token contract address (0x...). Required for record_trade, token_pnl.',\n  })),\n  symbol: Type.Optional(Type.String({\n    description: 'Token symbol (e.g. \"USDC\"). Required for record_trade.',\n  })),\n  type: Type.Optional(stringEnum(['buy', 'sell'] as const, {\n    description: 'Trade type. Required for record_trade.',\n  })),\n  amount: Type.Optional(Type.Number({\n    description: 'Token amount. Required for record_trade.',\n  })),\n  price_usd: Type.Optional(Type.Number({\n    description: 'Price per token in USD at time of trade. Required for record_trade.',\n  })),\n  current_price: Type.Optional(Type.Number({\n    description: 'Current price per token in USD. Used for P&L calculation. If omitted, uses last known price.',\n  })),\n  tx_hash: Type.Optional(Type.String({\n    description: 'Transaction hash associated with the trade.',\n  })),\n  limit: Type.Optional(Type.Number({\n    description: 'Max records to return for history action. Default: 50.',\n  })),\n});\n\nexport function createCostBasisTool() {\n  return {\n    name: 'cost_basis',\n    label: 'Cost Basis',\n    ownerOnly: true, // Writes to disk (record_trade) and exposes financial data (export)\n    description:\n      'Track trade cost basis and calculate P&L. Records buy/sell prices, computes ' +\n      'unrealized/realized profit using FIFO. Use record_trade to log trades, ' +\n      'portfolio_pnl for overall P&L, token_pnl for per-token detail.',\n    parameters: CostBasisSchema,\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 'record_trade':\n          return handleRecordTrade(params);\n        case 'portfolio_pnl':\n          return handlePortfolioPnl(params);\n        case 'token_pnl':\n          return handleTokenPnl(params);\n        case 'history':\n          return handleHistory(params);\n        case 'export':\n          return handleExport();\n        default:\n          return errorResult(`Unknown action: ${action}. Use: ${ACTIONS.join(', ')}`);\n      }\n    },\n  };\n}\n\n// ─── FIFO Cost Basis Engine ──────────────────────────────────────────────\n\nfunction buildTaxLots(trades: TradeRecord[], tokenAddress: string): {\n  lots: TaxLot[];\n  realizedPnl: number;\n  totalSold: number;\n  totalBought: number;\n} {\n  const filtered = trades\n    .filter((t) => t.token === tokenAddress.toLowerCase())\n    .sort((a, b) => a.timestamp - b.timestamp);\n\n  const lots: TaxLot[] = [];\n  let realizedPnl = 0;\n  let totalSold = 0;\n  let totalBought = 0;\n\n  for (const trade of filtered) {\n    if (trade.type === 'buy') {\n      lots.push({\n        tradeId: trade.id,\n        timestamp: trade.timestamp,\n        remainingAmount: trade.amount,\n        costBasisPerUnit: trade.priceUsd,\n      });\n      totalBought += trade.amount;\n    } else {\n      // FIFO: consume oldest lots first\n      let remaining = trade.amount;\n      totalSold += trade.amount;\n\n      for (const lot of lots) {\n        if (remaining <= 0) break;\n        if (lot.remainingAmount <= 0) continue;\n\n        const consumed = Math.min(lot.remainingAmount, remaining);\n        const costBasis = consumed * lot.costBasisPerUnit;\n        const saleProceeds = consumed * trade.priceUsd;\n        realizedPnl += saleProceeds - costBasis;\n\n        lot.remainingAmount -= consumed;\n        remaining -= consumed;\n      }\n    }\n  }\n\n  return {\n    lots: lots.filter((l) => l.remainingAmount > 0),\n    realizedPnl,\n    totalSold,\n    totalBought,\n  };\n}\n\n// ─── Action Handlers ──────────────────────────────────────────────────────\n\nfunction handleRecordTrade(params: Record<string, unknown>) {\n  const token = readStringParam(params, 'token', { required: true })!;\n  const symbol = readStringParam(params, 'symbol', { required: true })!;\n  const tradeType = readStringParam(params, 'type', { required: true })!;\n  const amount = readNumberParam(params, 'amount', { required: true })!;\n  const priceUsd = readNumberParam(params, 'price_usd') ?? readNumberParam(params, 'priceUsd');\n  const txHash = readStringParam(params, 'tx_hash') ?? readStringParam(params, 'txHash');\n\n  if (tradeType !== 'buy' && tradeType !== 'sell') {\n    return errorResult('type must be \"buy\" or \"sell\".');\n  }\n\n  if (priceUsd === undefined || priceUsd === null) {\n    return errorResult('price_usd is required for record_trade.');\n  }\n\n  const store = loadStore();\n  const trade: TradeRecord = {\n    id: `t_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,\n    timestamp: Date.now(),\n    type: tradeType,\n    token: token.toLowerCase(),\n    symbol: symbol.toUpperCase(),\n    amount,\n    priceUsd,\n    totalUsd: amount * priceUsd,\n    txHash: txHash ?? undefined,\n  };\n  store.trades.push(trade);\n  saveStore(store);\n\n  return jsonResult({\n    status: 'recorded',\n    trade: {\n      id: trade.id,\n      type: trade.type,\n      token: trade.token,\n      symbol: trade.symbol,\n      amount: trade.amount,\n      priceUsd: trade.priceUsd,\n      totalUsd: trade.totalUsd,\n      txHash: trade.txHash,\n    },\n    totalTrades: store.trades.length,\n  });\n}\n\nfunction handlePortfolioPnl(params: Record<string, unknown>) {\n  const currentPriceOverride = readNumberParam(params, 'current_price') ?? readNumberParam(params, 'currentPrice');\n  const store = loadStore();\n\n  if (store.trades.length === 0) {\n    return jsonResult({\n      status: 'empty',\n      message: 'No trades recorded yet. Use record_trade to add trades.',\n      holdings: [],\n    });\n  }\n\n  // Group by token\n  const tokenSet = new Set<string>();\n  for (const t of store.trades) tokenSet.add(t.token);\n\n  const holdings: Array<{\n    token: string;\n    symbol: string;\n    holdingAmount: number;\n    avgCostBasis: number;\n    totalCost: number;\n    currentPrice: number;\n    currentValue: number;\n    unrealizedPnl: number;\n    unrealizedPnlPercent: number;\n    realizedPnl: number;\n  }> = [];\n\n  let totalUnrealizedPnl = 0;\n  let totalRealizedPnl = 0;\n  let totalCurrentValue = 0;\n\n  for (const tokenAddr of tokenSet) {\n    const { lots, realizedPnl } = buildTaxLots(store.trades, tokenAddr);\n    const holdingAmount = lots.reduce((sum, l) => sum + l.remainingAmount, 0);\n\n    if (holdingAmount <= 0 && realizedPnl === 0) continue;\n\n    const totalCost = lots.reduce((sum, l) => sum + l.remainingAmount * l.costBasisPerUnit, 0);\n    const avgCostBasis = holdingAmount > 0 ? totalCost / holdingAmount : 0;\n\n    // Use override price if provided, otherwise use last trade price\n    let currentPrice = currentPriceOverride ?? 0;\n    if (!currentPrice) {\n      const lastTrade = store.trades\n        .filter((t) => t.token === tokenAddr)\n        .sort((a, b) => b.timestamp - a.timestamp)[0];\n      currentPrice = lastTrade?.priceUsd ?? 0;\n    }\n\n    const currentValue = holdingAmount * currentPrice;\n    const unrealizedPnl = currentValue - totalCost;\n    const unrealizedPnlPercent = totalCost > 0 ? (unrealizedPnl / totalCost) * 100 : 0;\n\n    // Get symbol from most recent trade\n    const symbol = store.trades.filter((t) => t.token === tokenAddr).slice(-1)[0]?.symbol ?? 'UNKNOWN';\n\n    holdings.push({\n      token: tokenAddr,\n      symbol,\n      holdingAmount,\n      avgCostBasis,\n      totalCost,\n      currentPrice,\n      currentValue,\n      unrealizedPnl,\n      unrealizedPnlPercent,\n      realizedPnl,\n    });\n\n    totalUnrealizedPnl += unrealizedPnl;\n    totalRealizedPnl += realizedPnl;\n    totalCurrentValue += currentValue;\n  }\n\n  return jsonResult({\n    totalHoldings: holdings.length,\n    totalCurrentValue,\n    totalUnrealizedPnl,\n    totalRealizedPnl,\n    totalPnl: totalUnrealizedPnl + totalRealizedPnl,\n    holdings: holdings.sort((a, b) => b.currentValue - a.currentValue),\n    note: 'Current prices are from last recorded trade unless overridden via current_price parameter.',\n  });\n}\n\nfunction handleTokenPnl(params: Record<string, unknown>) {\n  const token = readStringParam(params, 'token', { required: true })!;\n  const currentPriceOverride = readNumberParam(params, 'current_price') ?? readNumberParam(params, 'currentPrice');\n  const store = loadStore();\n\n  const tokenTrades = store.trades.filter((t) => t.token === token.toLowerCase());\n  if (tokenTrades.length === 0) {\n    return jsonResult({\n      token,\n      status: 'no_trades',\n      message: 'No trades found for this token.',\n    });\n  }\n\n  const { lots, realizedPnl, totalSold, totalBought } = buildTaxLots(store.trades, token);\n  const holdingAmount = lots.reduce((sum, l) => sum + l.remainingAmount, 0);\n  const totalCost = lots.reduce((sum, l) => sum + l.remainingAmount * l.costBasisPerUnit, 0);\n  const avgCostBasis = holdingAmount > 0 ? totalCost / holdingAmount : 0;\n\n  let currentPrice = currentPriceOverride ?? 0;\n  if (!currentPrice) {\n    const lastTrade = tokenTrades.sort((a, b) => b.timestamp - a.timestamp)[0];\n    currentPrice = lastTrade?.priceUsd ?? 0;\n  }\n\n  const currentValue = holdingAmount * currentPrice;\n  const unrealizedPnl = currentValue - totalCost;\n  const unrealizedPnlPercent = totalCost > 0 ? (unrealizedPnl / totalCost) * 100 : 0;\n\n  const symbol = tokenTrades.slice(-1)[0]?.symbol ?? 'UNKNOWN';\n\n  return jsonResult({\n    token,\n    symbol,\n    totalTrades: tokenTrades.length,\n    totalBought,\n    totalSold,\n    holdingAmount,\n    avgCostBasis,\n    totalCost,\n    currentPrice,\n    currentValue,\n    unrealizedPnl,\n    unrealizedPnlPercent: Math.round(unrealizedPnlPercent * 100) / 100,\n    realizedPnl,\n    totalPnl: unrealizedPnl + realizedPnl,\n    openLots: lots.map((l) => ({\n      tradeId: l.tradeId,\n      date: new Date(l.timestamp).toISOString(),\n      remainingAmount: l.remainingAmount,\n      costBasisPerUnit: l.costBasisPerUnit,\n    })),\n    recentTrades: tokenTrades.slice(-10).reverse().map((t) => ({\n      id: t.id,\n      type: t.type,\n      amount: t.amount,\n      priceUsd: t.priceUsd,\n      totalUsd: t.totalUsd,\n      date: new Date(t.timestamp).toISOString(),\n      txHash: t.txHash,\n    })),\n  });\n}\n\nfunction handleHistory(params: Record<string, unknown>) {\n  const limit = readNumberParam(params, 'limit') ?? 50;\n  const store = loadStore();\n\n  const trades = store.trades\n    .sort((a, b) => b.timestamp - a.timestamp)\n    .slice(0, limit)\n    .map((t) => ({\n      id: t.id,\n      type: t.type,\n      token: t.token,\n      symbol: t.symbol,\n      amount: t.amount,\n      priceUsd: t.priceUsd,\n      totalUsd: t.totalUsd,\n      date: new Date(t.timestamp).toISOString(),\n      txHash: t.txHash,\n    }));\n\n  return jsonResult({\n    totalRecords: store.trades.length,\n    showing: trades.length,\n    trades,\n  });\n}\n\nfunction handleExport() {\n  const store = loadStore();\n  return jsonResult({\n    exportDate: new Date().toISOString(),\n    version: store.version,\n    totalTrades: store.trades.length,\n    trades: store.trades.map((t) => ({\n      ...t,\n      date: new Date(t.timestamp).toISOString(),\n    })),\n  });\n}\n"],"mappings":"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"}