{"version":3,"file":"wayfinder.mjs","names":[],"sources":["../../../src/tools/wayfinder.ts"],"sourcesContent":["/**\n * Wayfinder Tool — Cross-chain DeFi via Wayfinder Paths.\n *\n * Breaks the single-chain (Base-only) limitation by providing:\n *   - Cross-chain swap quotes and execution\n *   - Multi-chain balance aggregation\n *   - DeFi pool/yield discovery\n *   - Token resolution across chains\n *   - Strategy execution (basis trading, yield farming, etc.)\n *\n * Two tiers:\n *   REST (always available): pools, balances, quote, resolve_token, gas_token\n *   CLI (requires Python + wayfinder-paths): execute_swap, strategy\n *\n * Requires WAYFINDER_API_KEY env var.\n * Uses WayfinderClient from @clawnch/clawncher-sdk.\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 { getCredentialVault } from '../services/credential-vault.js';\n\nconst ACTIONS = [\n  'pools', 'balances', 'quote', 'resolve_token',\n  'gas_token', 'execute_swap', 'strategy',\n  'lending', 'yield_vaults', 'perps', 'pnl',\n] as const;\n\nconst WayfinderSchema = Type.Object({\n  action: stringEnum(ACTIONS, {\n    description:\n      'pools: search DeFi yields. balances: multi-chain portfolio. quote: cross-chain swap quote. ' +\n      'resolve_token: token lookup. gas_token: get gas token for chain. ' +\n      'execute_swap: execute via CLI (needs Python). strategy: run DeFi strategy (needs Python). ' +\n      'lending: Moonwell/Hyperlend positions and markets. yield_vaults: Pendle/Boros fixed-rate vaults. ' +\n      'perps: Hyperliquid perpetual positions. pnl: cross-protocol P&L summary.',\n  }),\n  // Pool filters\n  protocol: Type.Optional(Type.String({\n    description: 'For pools: filter by protocol (e.g. \"moonwell\", \"aave\", \"morpho\").',\n  })),\n  min_apy: Type.Optional(Type.Number({\n    description: 'For pools: minimum supply APY filter (e.g. 2.0 for 2%).',\n  })),\n  token_symbol: Type.Optional(Type.String({\n    description: 'For pools: filter by underlying token symbol (e.g. \"WETH\", \"USDC\").',\n  })),\n  // Chain\n  chain_id: Type.Optional(Type.Number({\n    description: 'Chain ID. Default: 8453 (Base). Common: 1 (Ethereum), 42161 (Arbitrum), 10 (Optimism).',\n  })),\n  // Swap params\n  from_token: Type.Optional(Type.String({\n    description: 'Source token address or identifier (for quote/execute_swap).',\n  })),\n  to_token: Type.Optional(Type.String({\n    description: 'Destination token address or identifier (for quote/execute_swap).',\n  })),\n  amount: Type.Optional(Type.String({\n    description: 'Amount: raw units (wei) for quote, human-readable for execute_swap.',\n  })),\n  from_chain: Type.Optional(Type.Number({\n    description: 'Source chain ID for cross-chain quote. Default: 8453.',\n  })),\n  to_chain: Type.Optional(Type.Number({\n    description: 'Destination chain ID for cross-chain quote. Default: 8453.',\n  })),\n  slippage: Type.Optional(Type.Number({\n    description: 'Slippage tolerance (e.g. 0.005 for 0.5%). Default: 0.005.',\n  })),\n  // Token resolution\n  query: Type.Optional(Type.String({\n    description: 'Token query for resolve_token (name, symbol, address, or CoinGecko ID).',\n  })),\n  // Strategy\n  strategy_name: Type.Optional(Type.String({\n    description: 'Strategy name (e.g. \"basis_trading_strategy\").',\n  })),\n  strategy_action: Type.Optional(Type.String({\n    description: 'Strategy sub-action: status, deposit, update, exit, withdraw, analyze, quote.',\n  })),\n  main_token_amount: Type.Optional(Type.Number({\n    description: 'Main token amount for strategy deposit.',\n  })),\n  wallet_label: Type.Optional(Type.String({\n    description: 'Wallet label for CLI operations (must match wayfinder config). Default: \"main\".',\n  })),\n  // Address override\n  address: Type.Optional(Type.String({\n    description: 'Wallet address for balances/lending/pnl. Defaults to connected wallet.',\n  })),\n  // Lending params\n  lending_protocol: Type.Optional(Type.String({\n    description: 'For lending: \"moonwell\", \"hyperlend\", or \"aave\". Shows all if omitted.',\n  })),\n  // Yield vault params\n  vault_protocol: Type.Optional(Type.String({\n    description: 'For yield_vaults: \"pendle\" or \"boros\". Shows all if omitted.',\n  })),\n  maturity: Type.Optional(Type.String({\n    description: 'For yield_vaults: filter by maturity date (e.g. \"2025-06\").',\n  })),\n  // Perps params\n  market: Type.Optional(Type.String({\n    description: 'For perps: market symbol (e.g. \"ETH-USD\", \"BTC-USD\").',\n  })),\n  side: Type.Optional(Type.String({\n    description: 'For perps: \"long\" or \"short\".',\n  })),\n});\n\nexport function createWayfinderTool() {\n  return {\n    name: 'wayfinder',\n    label: 'Wayfinder',\n    ownerOnly: true, // execute_swap and strategy are write operations\n    description:\n      'Cross-chain DeFi via Wayfinder Paths. ' +\n      'Get multi-chain balances, search DeFi yields, quote cross-chain swaps, ' +\n      'resolve tokens across chains, and execute swaps/strategies. ' +\n      'Requires WAYFINDER_API_KEY. CLI actions (execute_swap, strategy) also need Python + wayfinder-paths.',\n    parameters: WayfinderSchema,\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      // Check API key\n      const apiKey = getCredentialVault().getSecret('bot.wayfinder.apiKey', 'wayfinder');\n      if (!apiKey) {\n        return errorResult(\n          'Wayfinder not configured. Set WAYFINDER_API_KEY environment variable. ' +\n          'Get an API key at https://wayfinder.dev'\n        );\n      }\n\n      try {\n        const { WayfinderClient } = await import('@clawnch/clawncher-sdk');\n        const client = new WayfinderClient({ apiKey });\n\n        switch (action) {\n          case 'pools':\n            return handlePools(client, params);\n          case 'balances':\n            return handleBalances(client, params);\n          case 'quote':\n            return handleQuote(client, params);\n          case 'resolve_token':\n            return handleResolveToken(client, params);\n          case 'gas_token':\n            return handleGasToken(client, params);\n          case 'execute_swap':\n            return handleExecuteSwap(client, params);\n          case 'strategy':\n            return handleStrategy(client, params);\n          case 'lending':\n            return handleLending(client, params);\n          case 'yield_vaults':\n            return handleYieldVaults(client, params);\n          case 'perps':\n            return handlePerps(client, params);\n          case 'pnl':\n            return handlePnl(client, params);\n          default:\n            return errorResult(`Unknown action: ${action}`);\n        }\n      } catch (err) {\n        return errorResult(`Wayfinder operation failed: ${err instanceof Error ? err.message : String(err)}`);\n      }\n    },\n  };\n}\n\n// ─── Chain Names ──────────────────────────────────────────────────────────\n\nconst CHAIN_NAMES: Record<number, string> = {\n  1: 'Ethereum',\n  8453: 'Base',\n  42161: 'Arbitrum',\n  10: 'Optimism',\n  137: 'Polygon',\n  43114: 'Avalanche',\n  56: 'BNB Chain',\n  250: 'Fantom',\n  324: 'zkSync Era',\n  59144: 'Linea',\n  534352: 'Scroll',\n  5000: 'Mantle',\n  81457: 'Blast',\n};\n\nfunction chainName(chainId: number): string {\n  return CHAIN_NAMES[chainId] ?? `Chain ${chainId}`;\n}\n\n// ─── REST Actions ─────────────────────────────────────────────────────────\n\nasync function handlePools(client: any, params: Record<string, unknown>) {\n  const chainId = readNumberParam(params, 'chain_id') ?? 8453;\n  const protocol = readStringParam(params, 'protocol');\n  const minApy = readNumberParam(params, 'min_apy');\n  const tokenSymbol = readStringParam(params, 'token_symbol')?.toUpperCase();\n\n  let pools = await client.getPools(chainId, protocol);\n\n  if (minApy !== undefined) {\n    pools = pools.filter((p: any) => p.supplyApy >= minApy);\n  }\n  if (tokenSymbol) {\n    pools = pools.filter((p: any) => p.tokenSymbol.toUpperCase() === tokenSymbol);\n  }\n\n  // Sort by APY descending\n  pools.sort((a: any, b: any) => b.supplyApy - a.supplyApy);\n  const topPools = pools.slice(0, 20);\n\n  if (topPools.length === 0) {\n    return jsonResult({\n      count: 0,\n      chain: chainName(chainId),\n      filters: { protocol, minApy, tokenSymbol },\n      message: 'No pools found matching filters. Try broadening your search.',\n    });\n  }\n\n  const formatted = topPools.map((p: any) => ({\n    protocol: p.protocol,\n    token: p.tokenSymbol,\n    apy: `${p.supplyApy.toFixed(2)}%`,\n    tvl: p.totalSupplyUsd > 1_000_000\n      ? `$${(p.totalSupplyUsd / 1_000_000).toFixed(1)}M`\n      : `$${(p.totalSupplyUsd / 1_000).toFixed(0)}K`,\n    address: p.address,\n  }));\n\n  return jsonResult({\n    count: pools.length,\n    showing: topPools.length,\n    chain: chainName(chainId),\n    pools: formatted,\n  });\n}\n\nasync function handleBalances(client: any, params: Record<string, unknown>) {\n  const state = getWalletState();\n  const address = readStringParam(params, 'address') ?? state.address;\n\n  if (!address) {\n    return errorResult('No address provided and no wallet connected.');\n  }\n\n  const balances = await client.getBalances(address);\n  const tokens = balances.tokens\n    .filter((t: any) => t.balanceUsd > 0.01)\n    .sort((a: any, b: any) => b.balanceUsd - a.balanceUsd);\n\n  if (tokens.length === 0) {\n    return jsonResult({\n      address,\n      totalValueUsd: 0,\n      tokens: [],\n      message: 'No token balances found.',\n    });\n  }\n\n  const formatted = tokens.map((t: any) => ({\n    chain: t.chainName,\n    symbol: t.symbol,\n    balance: t.balanceFormatted,\n    valueUsd: `$${t.balanceUsd.toFixed(2)}`,\n  }));\n\n  return jsonResult({\n    address,\n    totalValueUsd: `$${balances.totalValueUsd.toFixed(2)}`,\n    tokenCount: tokens.length,\n    tokens: formatted,\n  });\n}\n\nasync function handleQuote(client: any, params: Record<string, unknown>) {\n  const fromToken = readStringParam(params, 'from_token', { required: true })!;\n  const toToken = readStringParam(params, 'to_token', { required: true })!;\n  const amount = readStringParam(params, 'amount', { required: true })!;\n  const fromChain = readNumberParam(params, 'from_chain') ?? 8453;\n  const toChain = readNumberParam(params, 'to_chain') ?? 8453;\n  const slippage = readNumberParam(params, 'slippage');\n\n  const state = getWalletState();\n  const fromWallet = readStringParam(params, 'address') ?? state.address;\n  if (!fromWallet) {\n    return errorResult('No wallet connected and no address provided.');\n  }\n\n  const quote = await client.quoteSwap({\n    fromToken,\n    toToken,\n    fromChain,\n    toChain,\n    fromWallet,\n    amount,\n    slippage,\n  });\n\n  if (!quote.bestQuote) {\n    return jsonResult({\n      found: false,\n      fromToken,\n      toToken,\n      route: `${chainName(fromChain)} → ${chainName(toChain)}`,\n      message: 'No routes found. Try different tokens, amounts, or chains.',\n    });\n  }\n\n  const best = quote.bestQuote;\n  const result: Record<string, unknown> = {\n    found: true,\n    route: `${chainName(fromChain)} → ${chainName(toChain)}`,\n    provider: best.provider,\n    input: {\n      amount: best.inputAmount,\n      valueUsd: `$${best.inputAmountUsd.toFixed(2)}`,\n      native: best.nativeInput,\n    },\n    output: {\n      amount: best.outputAmount,\n      valueUsd: `$${best.outputAmountUsd.toFixed(2)}`,\n      native: best.nativeOutput,\n    },\n    fees: `$${best.feeEstimate.feeTotalUsd.toFixed(2)}`,\n  };\n\n  if (best.gasEstimate) {\n    result.gasEstimate = best.gasEstimate;\n  }\n\n  // Include alternative routes\n  if (quote.quotes.length > 1) {\n    result.alternatives = quote.quotes\n      .filter((q: any) => q.provider !== best.provider)\n      .slice(0, 4)\n      .map((q: any) => ({\n        provider: q.provider,\n        output: q.error ? `failed: ${q.error}` : `${q.outputAmount} ($${q.outputAmountUsd.toFixed(2)})`,\n      }));\n    result.totalRoutesCompared = quote.quoteCount;\n  }\n\n  return jsonResult(result);\n}\n\nasync function handleResolveToken(client: any, params: Record<string, unknown>) {\n  const query = readStringParam(params, 'query', { required: true })!;\n  const chainId = readNumberParam(params, 'chain_id');\n\n  const token = await client.resolveToken(query, chainId);\n\n  const result: Record<string, unknown> = {\n    name: token.name,\n    symbol: token.symbol,\n    address: token.address,\n    chain: chainName(token.chainId),\n    chainId: token.chainId,\n    decimals: token.decimals,\n  };\n\n  if (token.priceUsd !== undefined) result.priceUsd = `$${token.priceUsd.toFixed(6)}`;\n  if (token.priceChange24h !== undefined) result.change24h = `${token.priceChange24h >= 0 ? '+' : ''}${token.priceChange24h.toFixed(2)}%`;\n  if (token.marketCapUsd !== undefined) {\n    result.marketCap = token.marketCapUsd > 1_000_000\n      ? `$${(token.marketCapUsd / 1_000_000).toFixed(1)}M`\n      : `$${(token.marketCapUsd / 1_000).toFixed(0)}K`;\n  }\n  if (token.coingeckoId) result.coingeckoId = token.coingeckoId;\n\n  return jsonResult(result);\n}\n\nasync function handleGasToken(client: any, params: Record<string, unknown>) {\n  const chainId = readNumberParam(params, 'chain_id') ?? 8453;\n\n  // Gas tokens per chain (Wayfinder uses these internally)\n  const GAS_TOKENS: Record<number, { symbol: string; name: string }> = {\n    1: { symbol: 'ETH', name: 'Ether' },\n    8453: { symbol: 'ETH', name: 'Ether' },\n    42161: { symbol: 'ETH', name: 'Ether' },\n    10: { symbol: 'ETH', name: 'Ether' },\n    137: { symbol: 'MATIC', name: 'Polygon' },\n    43114: { symbol: 'AVAX', name: 'Avalanche' },\n    56: { symbol: 'BNB', name: 'BNB' },\n    250: { symbol: 'FTM', name: 'Fantom' },\n    324: { symbol: 'ETH', name: 'Ether' },\n    59144: { symbol: 'ETH', name: 'Ether' },\n    534352: { symbol: 'ETH', name: 'Ether' },\n    5000: { symbol: 'MNT', name: 'Mantle' },\n    81457: { symbol: 'ETH', name: 'Ether' },\n  };\n\n  const gasToken = GAS_TOKENS[chainId] ?? { symbol: 'UNKNOWN', name: 'Unknown' };\n\n  return jsonResult({\n    chainId,\n    chain: chainName(chainId),\n    gasToken: gasToken.symbol,\n    gasTokenName: gasToken.name,\n  });\n}\n\n// ─── CLI Actions (require Python + wayfinder-paths) ───────────────────────\n\nasync function handleExecuteSwap(client: any, params: Record<string, unknown>) {\n  // Check Python availability\n  const pyStatus = await client.checkPython();\n  if (!pyStatus.wayfinderInstalled) {\n    return errorResult(\n      pyStatus.available\n        ? 'wayfinder-paths not installed. Install with: pip3 install wayfinder-paths'\n        : 'Python 3 not found. Install Python 3.12+ first, then: pip3 install wayfinder-paths'\n    );\n  }\n\n  const fromToken = readStringParam(params, 'from_token', { required: true })!;\n  const toToken = readStringParam(params, 'to_token', { required: true })!;\n  const amount = readStringParam(params, 'amount', { required: true })!;\n  const walletLabel = readStringParam(params, 'wallet_label') ?? 'main';\n  const chainId = readNumberParam(params, 'chain_id');\n\n  const slippageBps = readNumberParam(params, 'slippage')\n    ? Math.round(readNumberParam(params, 'slippage')! * 10000)\n    : undefined;\n\n  const result = await client.executeSwap({\n    kind: 'swap',\n    walletLabel,\n    amount,\n    fromToken,\n    toToken,\n    slippageBps,\n    chainId,\n  });\n\n  if (!result.ok) {\n    return errorResult(`Swap failed: ${result.error}`);\n  }\n\n  const r = result.result!;\n  const effects = Object.values(r.effects) as any[];\n  const txHashes = effects.map((e: any) => e.txnHash).filter(Boolean);\n\n  return jsonResult({\n    status: r.status,\n    preview: r.preview,\n    sender: r.sender,\n    recipient: r.recipient,\n    transactions: effects.map((e: any) => ({\n      txHash: e.txnHash,\n      chainId: e.chainId,\n      chain: chainName(e.chainId),\n      explorerUrl: e.explorerUrl,\n    })),\n    txHashes,\n  });\n}\n\nasync function handleStrategy(client: any, params: Record<string, unknown>) {\n  // Check Python availability\n  const pyStatus = await client.checkPython();\n  if (!pyStatus.wayfinderInstalled) {\n    return errorResult(\n      pyStatus.available\n        ? 'wayfinder-paths not installed. Install with: pip3 install wayfinder-paths'\n        : 'Python 3 not found. Install Python 3.12+ first, then: pip3 install wayfinder-paths'\n    );\n  }\n\n  const strategyName = readStringParam(params, 'strategy_name');\n  const strategyAction = readStringParam(params, 'strategy_action') ?? 'status';\n  const walletLabel = readStringParam(params, 'wallet_label') ?? 'main';\n  const mainTokenAmount = readNumberParam(params, 'main_token_amount');\n\n  // If no strategy name, list available strategies\n  if (!strategyName) {\n    const strategies = await client.listStrategies();\n    if (strategies.length === 0) {\n      return jsonResult({\n        count: 0,\n        message: 'No strategies available. Check wayfinder-paths installation.',\n      });\n    }\n\n    return jsonResult({\n      count: strategies.length,\n      strategies: strategies.map((s: any) => ({\n        name: s.name,\n        description: s.description,\n        riskLevel: s.riskLevel,\n        chains: s.chains.map((c: number) => chainName(c)),\n      })),\n    });\n  }\n\n  // Run strategy action\n  const result = await client.runStrategy({\n    strategy: strategyName,\n    action: strategyAction as any,\n    mainTokenAmount,\n    walletLabel,\n  });\n\n  if (!result.success) {\n    return errorResult(`Strategy ${strategyAction} failed: ${result.error}`);\n  }\n\n  return jsonResult({\n    strategy: strategyName,\n    action: strategyAction,\n    output: result.output,\n  });\n}\n\n// ─── Extended Actions (Strategies Upgrade) ────────────────────────────────\n\n/**\n * Lending: Moonwell, Hyperlend, and Aave positions and market rates\n * via Wayfinder's lending aggregation endpoints.\n */\nasync function handleLending(client: any, params: Record<string, unknown>) {\n  const state = getWalletState();\n  const address = readStringParam(params, 'address') ?? state.address;\n  const lendingProtocol = readStringParam(params, 'lending_protocol');\n  const chainId = readNumberParam(params, 'chain_id') ?? 8453;\n\n  // Fetch lending markets via the pools endpoint filtered for lending protocols\n  const lendingProtocols = lendingProtocol\n    ? [lendingProtocol]\n    : ['moonwell', 'hyperlend', 'aave-v3'];\n\n  const allMarkets: any[] = [];\n  for (const proto of lendingProtocols) {\n    try {\n      const pools = await client.getPools(chainId, proto);\n      allMarkets.push(...pools.map((p: any) => ({\n        protocol: proto,\n        token: p.tokenSymbol,\n        supplyApy: `${p.supplyApy?.toFixed(2) ?? '?'}%`,\n        borrowApy: p.borrowApy !== undefined ? `${p.borrowApy.toFixed(2)}%` : 'N/A',\n        tvl: p.totalSupplyUsd > 1_000_000\n          ? `$${(p.totalSupplyUsd / 1_000_000).toFixed(1)}M`\n          : `$${(p.totalSupplyUsd / 1_000).toFixed(0)}K`,\n        address: p.address,\n        chain: chainName(chainId),\n      })));\n    } catch {\n      // Protocol may not be available on this chain\n    }\n  }\n\n  // Sort by supply APY descending\n  allMarkets.sort((a, b) => {\n    const aApy = parseFloat(a.supplyApy) || 0;\n    const bApy = parseFloat(b.supplyApy) || 0;\n    return bApy - aApy;\n  });\n\n  // If address provided, try to get positions\n  let positions: any[] | undefined;\n  if (address) {\n    try {\n      const balances = await client.getBalances(address);\n      // Filter for lending receipt tokens (aTokens, mTokens, etc.)\n      positions = balances.tokens\n        ?.filter((t: any) =>\n          t.balanceUsd > 0.01 && (\n            t.symbol?.startsWith('a') || // Aave aTokens\n            t.symbol?.startsWith('m') || // Moonwell mTokens\n            t.symbol?.includes('Debt')   // Debt tokens\n          ),\n        )\n        .map((t: any) => ({\n          token: t.symbol,\n          balance: t.balanceFormatted,\n          valueUsd: `$${t.balanceUsd.toFixed(2)}`,\n          chain: t.chainName,\n          type: t.symbol?.includes('Debt') ? 'borrow' : 'supply',\n        }));\n    } catch {\n      // Balance fetch failed — continue without positions\n    }\n  }\n\n  return jsonResult({\n    chain: chainName(chainId),\n    markets: allMarkets.slice(0, 30),\n    marketCount: allMarkets.length,\n    positions: positions?.length ? positions : undefined,\n    tip: 'Use defi_lend tool for direct supply/borrow execution on Aave V3.',\n  });\n}\n\n/**\n * Yield vaults: Pendle and Boros fixed-rate strategies\n * via Wayfinder's yield discovery endpoints.\n */\nasync function handleYieldVaults(client: any, params: Record<string, unknown>) {\n  const chainId = readNumberParam(params, 'chain_id') ?? 8453;\n  const vaultProtocol = readStringParam(params, 'vault_protocol');\n  const maturity = readStringParam(params, 'maturity');\n\n  const protocols = vaultProtocol\n    ? [vaultProtocol]\n    : ['pendle', 'boros'];\n\n  const allVaults: any[] = [];\n  for (const proto of protocols) {\n    try {\n      const pools = await client.getPools(chainId, proto);\n      let filtered = pools;\n\n      if (maturity) {\n        filtered = pools.filter((p: any) =>\n          p.maturity?.includes(maturity) || p.expiry?.includes(maturity),\n        );\n      }\n\n      allVaults.push(...filtered.map((p: any) => ({\n        protocol: proto,\n        token: p.tokenSymbol,\n        fixedApy: p.fixedApy !== undefined ? `${p.fixedApy.toFixed(2)}%` : undefined,\n        impliedApy: p.impliedApy !== undefined ? `${p.impliedApy.toFixed(2)}%` : undefined,\n        supplyApy: `${p.supplyApy?.toFixed(2) ?? '?'}%`,\n        maturity: p.maturity ?? p.expiry ?? 'N/A',\n        tvl: p.totalSupplyUsd > 1_000_000\n          ? `$${(p.totalSupplyUsd / 1_000_000).toFixed(1)}M`\n          : `$${(p.totalSupplyUsd / 1_000).toFixed(0)}K`,\n        chain: chainName(chainId),\n      })));\n    } catch {\n      // Protocol may not be available\n    }\n  }\n\n  // Sort by APY descending\n  allVaults.sort((a, b) => {\n    const aApy = parseFloat(a.fixedApy ?? a.supplyApy) || 0;\n    const bApy = parseFloat(b.fixedApy ?? b.supplyApy) || 0;\n    return bApy - aApy;\n  });\n\n  return jsonResult({\n    chain: chainName(chainId),\n    vaultCount: allVaults.length,\n    vaults: allVaults.slice(0, 20),\n    note: 'Fixed-rate vaults lock funds until maturity. Check maturity dates before depositing.',\n    tip: 'Use action=strategy strategy_name=<name> for managed vault execution.',\n  });\n}\n\n/**\n * Perps: Hyperliquid perpetual futures positions and markets.\n */\nasync function handlePerps(client: any, params: Record<string, unknown>) {\n  const state = getWalletState();\n  const address = readStringParam(params, 'address') ?? state.address;\n  const market = readStringParam(params, 'market');\n\n  if (!address) {\n    return errorResult('No wallet connected and no address provided.');\n  }\n\n  try {\n    // Fetch Hyperliquid positions via Wayfinder\n    // The SDK exposes perps data through the balances/positions aggregation\n    const balances = await client.getBalances(address);\n\n    // Filter for perp positions (Hyperliquid tokens)\n    const perpPositions = balances.tokens\n      ?.filter((t: any) =>\n        t.balanceUsd > 0.01 && (\n          t.protocol === 'hyperliquid' ||\n          t.chainName?.toLowerCase().includes('hyperliquid')\n        ),\n      )\n      .map((t: any) => ({\n        market: t.symbol,\n        size: t.balanceFormatted,\n        valueUsd: `$${t.balanceUsd.toFixed(2)}`,\n        chain: t.chainName,\n      }));\n\n    // Also fetch available perp markets via pools\n    let markets: any[] = [];\n    try {\n      const pools = await client.getPools(42161, 'hyperliquid'); // Hyperliquid settles on Arbitrum\n      markets = pools\n        .filter((p: any) => !market || p.tokenSymbol?.includes(market.replace('-USD', '')))\n        .slice(0, 20)\n        .map((p: any) => ({\n          market: p.tokenSymbol,\n          fundingRate: p.fundingRate !== undefined ? `${(p.fundingRate * 100).toFixed(4)}%` : undefined,\n          openInterest: p.totalSupplyUsd > 1_000_000\n            ? `$${(p.totalSupplyUsd / 1_000_000).toFixed(1)}M`\n            : `$${(p.totalSupplyUsd / 1_000).toFixed(0)}K`,\n          volume24h: p.volume24h ? `$${(p.volume24h / 1_000_000).toFixed(1)}M` : undefined,\n        }));\n    } catch {\n      // Perp markets fetch may not be supported\n    }\n\n    return jsonResult({\n      address,\n      positions: perpPositions?.length ? perpPositions : [],\n      availableMarkets: markets.length > 0 ? markets : undefined,\n      tip: 'Use action=strategy for managed perp strategies via Wayfinder CLI.',\n    });\n  } catch (err) {\n    return errorResult(`Perps fetch failed: ${err instanceof Error ? err.message : String(err)}`);\n  }\n}\n\n/**\n * PnL: Cross-protocol profit and loss summary.\n */\nasync function handlePnl(client: any, params: Record<string, unknown>) {\n  const state = getWalletState();\n  const address = readStringParam(params, 'address') ?? state.address;\n\n  if (!address) {\n    return errorResult('No wallet connected and no address provided.');\n  }\n\n  try {\n    // Fetch multi-chain balances as the basis for PnL\n    const balances = await client.getBalances(address);\n    const tokens = balances.tokens\n      .filter((t: any) => t.balanceUsd > 0.01)\n      .sort((a: any, b: any) => b.balanceUsd - a.balanceUsd);\n\n    // Group by chain\n    const byChain: Record<string, { tokens: any[]; total: number }> = {};\n    for (const t of tokens) {\n      const chain = t.chainName ?? 'Unknown';\n      if (!byChain[chain]) byChain[chain] = { tokens: [], total: 0 };\n      byChain[chain].tokens.push({\n        symbol: t.symbol,\n        balance: t.balanceFormatted,\n        valueUsd: t.balanceUsd,\n        change24h: t.priceChange24h !== undefined\n          ? `${t.priceChange24h >= 0 ? '+' : ''}${t.priceChange24h.toFixed(2)}%`\n          : undefined,\n      });\n      byChain[chain].total += t.balanceUsd;\n    }\n\n    // Calculate portfolio-level metrics\n    const totalValueUsd = tokens.reduce((sum: number, t: any) => sum + t.balanceUsd, 0);\n\n    // Weighted average 24h change\n    let weightedChange = 0;\n    let weightTotal = 0;\n    for (const t of tokens) {\n      if (t.priceChange24h !== undefined && t.balanceUsd > 0) {\n        weightedChange += t.priceChange24h * t.balanceUsd;\n        weightTotal += t.balanceUsd;\n      }\n    }\n    const portfolioChange24h = weightTotal > 0 ? weightedChange / weightTotal : 0;\n    const pnl24h = totalValueUsd * (portfolioChange24h / 100);\n\n    return jsonResult({\n      address,\n      totalValueUsd: `$${totalValueUsd.toFixed(2)}`,\n      change24h: `${portfolioChange24h >= 0 ? '+' : ''}${portfolioChange24h.toFixed(2)}%`,\n      pnl24hUsd: `${pnl24h >= 0 ? '+' : ''}$${Math.abs(pnl24h).toFixed(2)}`,\n      chainBreakdown: Object.entries(byChain).map(([chain, data]) => ({\n        chain,\n        totalUsd: `$${data.total.toFixed(2)}`,\n        tokenCount: data.tokens.length,\n        topHoldings: data.tokens.slice(0, 5).map(t => ({\n          symbol: t.symbol,\n          valueUsd: `$${t.valueUsd.toFixed(2)}`,\n          change24h: t.change24h,\n        })),\n      })),\n      note: '24h P&L is estimated from price changes. For accurate cost-basis tracking, use the cost-basis skill.',\n    });\n  } catch (err) {\n    return errorResult(`PnL fetch failed: ${err instanceof Error ? err.message : String(err)}`);\n  }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AA6BA,MAAM,kBAAkB,KAAK,OAAO;CAClC,QAAQ,WAPM;EACd;EAAS;EAAY;EAAS;EAC9B;EAAa;EAAgB;EAC7B;EAAW;EAAgB;EAAS;EACrC,EAG6B,EAC1B,aACE,maAKH,CAAC;CAEF,UAAU,KAAK,SAAS,KAAK,OAAO,EAClC,aAAa,4EACd,CAAC,CAAC;CACH,SAAS,KAAK,SAAS,KAAK,OAAO,EACjC,aAAa,2DACd,CAAC,CAAC;CACH,cAAc,KAAK,SAAS,KAAK,OAAO,EACtC,aAAa,2EACd,CAAC,CAAC;CAEH,UAAU,KAAK,SAAS,KAAK,OAAO,EAClC,aAAa,0FACd,CAAC,CAAC;CAEH,YAAY,KAAK,SAAS,KAAK,OAAO,EACpC,aAAa,gEACd,CAAC,CAAC;CACH,UAAU,KAAK,SAAS,KAAK,OAAO,EAClC,aAAa,qEACd,CAAC,CAAC;CACH,QAAQ,KAAK,SAAS,KAAK,OAAO,EAChC,aAAa,uEACd,CAAC,CAAC;CACH,YAAY,KAAK,SAAS,KAAK,OAAO,EACpC,aAAa,yDACd,CAAC,CAAC;CACH,UAAU,KAAK,SAAS,KAAK,OAAO,EAClC,aAAa,8DACd,CAAC,CAAC;CACH,UAAU,KAAK,SAAS,KAAK,OAAO,EAClC,aAAa,6DACd,CAAC,CAAC;CAEH,OAAO,KAAK,SAAS,KAAK,OAAO,EAC/B,aAAa,2EACd,CAAC,CAAC;CAEH,eAAe,KAAK,SAAS,KAAK,OAAO,EACvC,aAAa,oDACd,CAAC,CAAC;CACH,iBAAiB,KAAK,SAAS,KAAK,OAAO,EACzC,aAAa,iFACd,CAAC,CAAC;CACH,mBAAmB,KAAK,SAAS,KAAK,OAAO,EAC3C,aAAa,2CACd,CAAC,CAAC;CACH,cAAc,KAAK,SAAS,KAAK,OAAO,EACtC,aAAa,qFACd,CAAC,CAAC;CAEH,SAAS,KAAK,SAAS,KAAK,OAAO,EACjC,aAAa,0EACd,CAAC,CAAC;CAEH,kBAAkB,KAAK,SAAS,KAAK,OAAO,EAC1C,aAAa,gFACd,CAAC,CAAC;CAEH,gBAAgB,KAAK,SAAS,KAAK,OAAO,EACxC,aAAa,oEACd,CAAC,CAAC;CACH,UAAU,KAAK,SAAS,KAAK,OAAO,EAClC,aAAa,iEACd,CAAC,CAAC;CAEH,QAAQ,KAAK,SAAS,KAAK,OAAO,EAChC,aAAa,6DACd,CAAC,CAAC;CACH,MAAM,KAAK,SAAS,KAAK,OAAO,EAC9B,aAAa,qCACd,CAAC,CAAC;CACJ,CAAC;AAEF,SAAgB,sBAAsB;AACpC,QAAO;EACL,MAAM;EACN,OAAO;EACP,WAAW;EACX,aACE;EAIF,YAAY;EACZ,SAAS,OAAO,aAAqB,SAAkB;GACrD,MAAM,SAAS;GACf,MAAM,SAAS,gBAAgB,QAAQ,UAAU,EAAE,UAAU,MAAM,CAAC;GAGpE,MAAM,SAAS,oBAAoB,CAAC,UAAU,wBAAwB,YAAY;AAClF,OAAI,CAAC,OACH,QAAO,YACL,gHAED;AAGH,OAAI;IACF,MAAM,EAAE,oBAAoB,MAAM,OAAO;IACzC,MAAM,SAAS,IAAI,gBAAgB,EAAE,QAAQ,CAAC;AAE9C,YAAQ,QAAR;KACE,KAAK,QACH,QAAO,YAAY,QAAQ,OAAO;KACpC,KAAK,WACH,QAAO,eAAe,QAAQ,OAAO;KACvC,KAAK,QACH,QAAO,YAAY,QAAQ,OAAO;KACpC,KAAK,gBACH,QAAO,mBAAmB,QAAQ,OAAO;KAC3C,KAAK,YACH,QAAO,eAAe,QAAQ,OAAO;KACvC,KAAK,eACH,QAAO,kBAAkB,QAAQ,OAAO;KAC1C,KAAK,WACH,QAAO,eAAe,QAAQ,OAAO;KACvC,KAAK,UACH,QAAO,cAAc,QAAQ,OAAO;KACtC,KAAK,eACH,QAAO,kBAAkB,QAAQ,OAAO;KAC1C,KAAK,QACH,QAAO,YAAY,QAAQ,OAAO;KACpC,KAAK,MACH,QAAO,UAAU,QAAQ,OAAO;KAClC,QACE,QAAO,YAAY,mBAAmB,SAAS;;YAE5C,KAAK;AACZ,WAAO,YAAY,+BAA+B,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI,GAAG;;;EAG1G;;AAKH,MAAM,cAAsC;CAC1C,GAAG;CACH,MAAM;CACN,OAAO;CACP,IAAI;CACJ,KAAK;CACL,OAAO;CACP,IAAI;CACJ,KAAK;CACL,KAAK;CACL,OAAO;CACP,QAAQ;CACR,KAAM;CACN,OAAO;CACR;AAED,SAAS,UAAU,SAAyB;AAC1C,QAAO,YAAY,YAAY,SAAS;;AAK1C,eAAe,YAAY,QAAa,QAAiC;CACvE,MAAM,UAAU,gBAAgB,QAAQ,WAAW,IAAI;CACvD,MAAM,WAAW,gBAAgB,QAAQ,WAAW;CACpD,MAAM,SAAS,gBAAgB,QAAQ,UAAU;CACjD,MAAM,cAAc,gBAAgB,QAAQ,eAAe,EAAE,aAAa;CAE1E,IAAI,QAAQ,MAAM,OAAO,SAAS,SAAS,SAAS;AAEpD,KAAI,WAAW,KAAA,EACb,SAAQ,MAAM,QAAQ,MAAW,EAAE,aAAa,OAAO;AAEzD,KAAI,YACF,SAAQ,MAAM,QAAQ,MAAW,EAAE,YAAY,aAAa,KAAK,YAAY;AAI/E,OAAM,MAAM,GAAQ,MAAW,EAAE,YAAY,EAAE,UAAU;CACzD,MAAM,WAAW,MAAM,MAAM,GAAG,GAAG;AAEnC,KAAI,SAAS,WAAW,EACtB,QAAO,WAAW;EAChB,OAAO;EACP,OAAO,UAAU,QAAQ;EACzB,SAAS;GAAE;GAAU;GAAQ;GAAa;EAC1C,SAAS;EACV,CAAC;CAGJ,MAAM,YAAY,SAAS,KAAK,OAAY;EAC1C,UAAU,EAAE;EACZ,OAAO,EAAE;EACT,KAAK,GAAG,EAAE,UAAU,QAAQ,EAAE,CAAC;EAC/B,KAAK,EAAE,iBAAiB,MACpB,KAAK,EAAE,iBAAiB,KAAW,QAAQ,EAAE,CAAC,KAC9C,KAAK,EAAE,iBAAiB,KAAO,QAAQ,EAAE,CAAC;EAC9C,SAAS,EAAE;EACZ,EAAE;AAEH,QAAO,WAAW;EAChB,OAAO,MAAM;EACb,SAAS,SAAS;EAClB,OAAO,UAAU,QAAQ;EACzB,OAAO;EACR,CAAC;;AAGJ,eAAe,eAAe,QAAa,QAAiC;CAC1E,MAAM,QAAQ,gBAAgB;CAC9B,MAAM,UAAU,gBAAgB,QAAQ,UAAU,IAAI,MAAM;AAE5D,KAAI,CAAC,QACH,QAAO,YAAY,+CAA+C;CAGpE,MAAM,WAAW,MAAM,OAAO,YAAY,QAAQ;CAClD,MAAM,SAAS,SAAS,OACrB,QAAQ,MAAW,EAAE,aAAa,IAAK,CACvC,MAAM,GAAQ,MAAW,EAAE,aAAa,EAAE,WAAW;AAExD,KAAI,OAAO,WAAW,EACpB,QAAO,WAAW;EAChB;EACA,eAAe;EACf,QAAQ,EAAE;EACV,SAAS;EACV,CAAC;CAGJ,MAAM,YAAY,OAAO,KAAK,OAAY;EACxC,OAAO,EAAE;EACT,QAAQ,EAAE;EACV,SAAS,EAAE;EACX,UAAU,IAAI,EAAE,WAAW,QAAQ,EAAE;EACtC,EAAE;AAEH,QAAO,WAAW;EAChB;EACA,eAAe,IAAI,SAAS,cAAc,QAAQ,EAAE;EACpD,YAAY,OAAO;EACnB,QAAQ;EACT,CAAC;;AAGJ,eAAe,YAAY,QAAa,QAAiC;CACvE,MAAM,YAAY,gBAAgB,QAAQ,cAAc,EAAE,UAAU,MAAM,CAAC;CAC3E,MAAM,UAAU,gBAAgB,QAAQ,YAAY,EAAE,UAAU,MAAM,CAAC;CACvE,MAAM,SAAS,gBAAgB,QAAQ,UAAU,EAAE,UAAU,MAAM,CAAC;CACpE,MAAM,YAAY,gBAAgB,QAAQ,aAAa,IAAI;CAC3D,MAAM,UAAU,gBAAgB,QAAQ,WAAW,IAAI;CACvD,MAAM,WAAW,gBAAgB,QAAQ,WAAW;CAEpD,MAAM,QAAQ,gBAAgB;CAC9B,MAAM,aAAa,gBAAgB,QAAQ,UAAU,IAAI,MAAM;AAC/D,KAAI,CAAC,WACH,QAAO,YAAY,+CAA+C;CAGpE,MAAM,QAAQ,MAAM,OAAO,UAAU;EACnC;EACA;EACA;EACA;EACA;EACA;EACA;EACD,CAAC;AAEF,KAAI,CAAC,MAAM,UACT,QAAO,WAAW;EAChB,OAAO;EACP;EACA;EACA,OAAO,GAAG,UAAU,UAAU,CAAC,KAAK,UAAU,QAAQ;EACtD,SAAS;EACV,CAAC;CAGJ,MAAM,OAAO,MAAM;CACnB,MAAM,SAAkC;EACtC,OAAO;EACP,OAAO,GAAG,UAAU,UAAU,CAAC,KAAK,UAAU,QAAQ;EACtD,UAAU,KAAK;EACf,OAAO;GACL,QAAQ,KAAK;GACb,UAAU,IAAI,KAAK,eAAe,QAAQ,EAAE;GAC5C,QAAQ,KAAK;GACd;EACD,QAAQ;GACN,QAAQ,KAAK;GACb,UAAU,IAAI,KAAK,gBAAgB,QAAQ,EAAE;GAC7C,QAAQ,KAAK;GACd;EACD,MAAM,IAAI,KAAK,YAAY,YAAY,QAAQ,EAAE;EAClD;AAED,KAAI,KAAK,YACP,QAAO,cAAc,KAAK;AAI5B,KAAI,MAAM,OAAO,SAAS,GAAG;AAC3B,SAAO,eAAe,MAAM,OACzB,QAAQ,MAAW,EAAE,aAAa,KAAK,SAAS,CAChD,MAAM,GAAG,EAAE,CACX,KAAK,OAAY;GAChB,UAAU,EAAE;GACZ,QAAQ,EAAE,QAAQ,WAAW,EAAE,UAAU,GAAG,EAAE,aAAa,KAAK,EAAE,gBAAgB,QAAQ,EAAE,CAAC;GAC9F,EAAE;AACL,SAAO,sBAAsB,MAAM;;AAGrC,QAAO,WAAW,OAAO;;AAG3B,eAAe,mBAAmB,QAAa,QAAiC;CAC9E,MAAM,QAAQ,gBAAgB,QAAQ,SAAS,EAAE,UAAU,MAAM,CAAC;CAClE,MAAM,UAAU,gBAAgB,QAAQ,WAAW;CAEnD,MAAM,QAAQ,MAAM,OAAO,aAAa,OAAO,QAAQ;CAEvD,MAAM,SAAkC;EACtC,MAAM,MAAM;EACZ,QAAQ,MAAM;EACd,SAAS,MAAM;EACf,OAAO,UAAU,MAAM,QAAQ;EAC/B,SAAS,MAAM;EACf,UAAU,MAAM;EACjB;AAED,KAAI,MAAM,aAAa,KAAA,EAAW,QAAO,WAAW,IAAI,MAAM,SAAS,QAAQ,EAAE;AACjF,KAAI,MAAM,mBAAmB,KAAA,EAAW,QAAO,YAAY,GAAG,MAAM,kBAAkB,IAAI,MAAM,KAAK,MAAM,eAAe,QAAQ,EAAE,CAAC;AACrI,KAAI,MAAM,iBAAiB,KAAA,EACzB,QAAO,YAAY,MAAM,eAAe,MACpC,KAAK,MAAM,eAAe,KAAW,QAAQ,EAAE,CAAC,KAChD,KAAK,MAAM,eAAe,KAAO,QAAQ,EAAE,CAAC;AAElD,KAAI,MAAM,YAAa,QAAO,cAAc,MAAM;AAElD,QAAO,WAAW,OAAO;;AAG3B,eAAe,eAAe,QAAa,QAAiC;CAC1E,MAAM,UAAU,gBAAgB,QAAQ,WAAW,IAAI;CAmBvD,MAAM,WAhB+D;EACnE,GAAG;GAAE,QAAQ;GAAO,MAAM;GAAS;EACnC,MAAM;GAAE,QAAQ;GAAO,MAAM;GAAS;EACtC,OAAO;GAAE,QAAQ;GAAO,MAAM;GAAS;EACvC,IAAI;GAAE,QAAQ;GAAO,MAAM;GAAS;EACpC,KAAK;GAAE,QAAQ;GAAS,MAAM;GAAW;EACzC,OAAO;GAAE,QAAQ;GAAQ,MAAM;GAAa;EAC5C,IAAI;GAAE,QAAQ;GAAO,MAAM;GAAO;EAClC,KAAK;GAAE,QAAQ;GAAO,MAAM;GAAU;EACtC,KAAK;GAAE,QAAQ;GAAO,MAAM;GAAS;EACrC,OAAO;GAAE,QAAQ;GAAO,MAAM;GAAS;EACvC,QAAQ;GAAE,QAAQ;GAAO,MAAM;GAAS;EACxC,KAAM;GAAE,QAAQ;GAAO,MAAM;GAAU;EACvC,OAAO;GAAE,QAAQ;GAAO,MAAM;GAAS;EACxC,CAE2B,YAAY;EAAE,QAAQ;EAAW,MAAM;EAAW;AAE9E,QAAO,WAAW;EAChB;EACA,OAAO,UAAU,QAAQ;EACzB,UAAU,SAAS;EACnB,cAAc,SAAS;EACxB,CAAC;;AAKJ,eAAe,kBAAkB,QAAa,QAAiC;CAE7E,MAAM,WAAW,MAAM,OAAO,aAAa;AAC3C,KAAI,CAAC,SAAS,mBACZ,QAAO,YACL,SAAS,YACL,8EACA,qFACL;CAGH,MAAM,YAAY,gBAAgB,QAAQ,cAAc,EAAE,UAAU,MAAM,CAAC;CAC3E,MAAM,UAAU,gBAAgB,QAAQ,YAAY,EAAE,UAAU,MAAM,CAAC;CACvE,MAAM,SAAS,gBAAgB,QAAQ,UAAU,EAAE,UAAU,MAAM,CAAC;CACpE,MAAM,cAAc,gBAAgB,QAAQ,eAAe,IAAI;CAC/D,MAAM,UAAU,gBAAgB,QAAQ,WAAW;CAEnD,MAAM,cAAc,gBAAgB,QAAQ,WAAW,GACnD,KAAK,MAAM,gBAAgB,QAAQ,WAAW,GAAI,IAAM,GACxD,KAAA;CAEJ,MAAM,SAAS,MAAM,OAAO,YAAY;EACtC,MAAM;EACN;EACA;EACA;EACA;EACA;EACA;EACD,CAAC;AAEF,KAAI,CAAC,OAAO,GACV,QAAO,YAAY,gBAAgB,OAAO,QAAQ;CAGpD,MAAM,IAAI,OAAO;CACjB,MAAM,UAAU,OAAO,OAAO,EAAE,QAAQ;CACxC,MAAM,WAAW,QAAQ,KAAK,MAAW,EAAE,QAAQ,CAAC,OAAO,QAAQ;AAEnE,QAAO,WAAW;EAChB,QAAQ,EAAE;EACV,SAAS,EAAE;EACX,QAAQ,EAAE;EACV,WAAW,EAAE;EACb,cAAc,QAAQ,KAAK,OAAY;GACrC,QAAQ,EAAE;GACV,SAAS,EAAE;GACX,OAAO,UAAU,EAAE,QAAQ;GAC3B,aAAa,EAAE;GAChB,EAAE;EACH;EACD,CAAC;;AAGJ,eAAe,eAAe,QAAa,QAAiC;CAE1E,MAAM,WAAW,MAAM,OAAO,aAAa;AAC3C,KAAI,CAAC,SAAS,mBACZ,QAAO,YACL,SAAS,YACL,8EACA,qFACL;CAGH,MAAM,eAAe,gBAAgB,QAAQ,gBAAgB;CAC7D,MAAM,iBAAiB,gBAAgB,QAAQ,kBAAkB,IAAI;CACrE,MAAM,cAAc,gBAAgB,QAAQ,eAAe,IAAI;CAC/D,MAAM,kBAAkB,gBAAgB,QAAQ,oBAAoB;AAGpE,KAAI,CAAC,cAAc;EACjB,MAAM,aAAa,MAAM,OAAO,gBAAgB;AAChD,MAAI,WAAW,WAAW,EACxB,QAAO,WAAW;GAChB,OAAO;GACP,SAAS;GACV,CAAC;AAGJ,SAAO,WAAW;GAChB,OAAO,WAAW;GAClB,YAAY,WAAW,KAAK,OAAY;IACtC,MAAM,EAAE;IACR,aAAa,EAAE;IACf,WAAW,EAAE;IACb,QAAQ,EAAE,OAAO,KAAK,MAAc,UAAU,EAAE,CAAC;IAClD,EAAE;GACJ,CAAC;;CAIJ,MAAM,SAAS,MAAM,OAAO,YAAY;EACtC,UAAU;EACV,QAAQ;EACR;EACA;EACD,CAAC;AAEF,KAAI,CAAC,OAAO,QACV,QAAO,YAAY,YAAY,eAAe,WAAW,OAAO,QAAQ;AAG1E,QAAO,WAAW;EAChB,UAAU;EACV,QAAQ;EACR,QAAQ,OAAO;EAChB,CAAC;;;;;;AASJ,eAAe,cAAc,QAAa,QAAiC;CACzE,MAAM,QAAQ,gBAAgB;CAC9B,MAAM,UAAU,gBAAgB,QAAQ,UAAU,IAAI,MAAM;CAC5D,MAAM,kBAAkB,gBAAgB,QAAQ,mBAAmB;CACnE,MAAM,UAAU,gBAAgB,QAAQ,WAAW,IAAI;CAGvD,MAAM,mBAAmB,kBACrB,CAAC,gBAAgB,GACjB;EAAC;EAAY;EAAa;EAAU;CAExC,MAAM,aAAoB,EAAE;AAC5B,MAAK,MAAM,SAAS,iBAClB,KAAI;EACF,MAAM,QAAQ,MAAM,OAAO,SAAS,SAAS,MAAM;AACnD,aAAW,KAAK,GAAG,MAAM,KAAK,OAAY;GACxC,UAAU;GACV,OAAO,EAAE;GACT,WAAW,GAAG,EAAE,WAAW,QAAQ,EAAE,IAAI,IAAI;GAC7C,WAAW,EAAE,cAAc,KAAA,IAAY,GAAG,EAAE,UAAU,QAAQ,EAAE,CAAC,KAAK;GACtE,KAAK,EAAE,iBAAiB,MACpB,KAAK,EAAE,iBAAiB,KAAW,QAAQ,EAAE,CAAC,KAC9C,KAAK,EAAE,iBAAiB,KAAO,QAAQ,EAAE,CAAC;GAC9C,SAAS,EAAE;GACX,OAAO,UAAU,QAAQ;GAC1B,EAAE,CAAC;SACE;AAMV,YAAW,MAAM,GAAG,MAAM;EACxB,MAAM,OAAO,WAAW,EAAE,UAAU,IAAI;AAExC,UADa,WAAW,EAAE,UAAU,IAAI,KAC1B;GACd;CAGF,IAAI;AACJ,KAAI,QACF,KAAI;AAGF,eAFiB,MAAM,OAAO,YAAY,QAAQ,EAE7B,QACjB,QAAQ,MACR,EAAE,aAAa,QACb,EAAE,QAAQ,WAAW,IAAI,IACzB,EAAE,QAAQ,WAAW,IAAI,IACzB,EAAE,QAAQ,SAAS,OAAO,EAE7B,CACA,KAAK,OAAY;GAChB,OAAO,EAAE;GACT,SAAS,EAAE;GACX,UAAU,IAAI,EAAE,WAAW,QAAQ,EAAE;GACrC,OAAO,EAAE;GACT,MAAM,EAAE,QAAQ,SAAS,OAAO,GAAG,WAAW;GAC/C,EAAE;SACC;AAKV,QAAO,WAAW;EAChB,OAAO,UAAU,QAAQ;EACzB,SAAS,WAAW,MAAM,GAAG,GAAG;EAChC,aAAa,WAAW;EACxB,WAAW,WAAW,SAAS,YAAY,KAAA;EAC3C,KAAK;EACN,CAAC;;;;;;AAOJ,eAAe,kBAAkB,QAAa,QAAiC;CAC7E,MAAM,UAAU,gBAAgB,QAAQ,WAAW,IAAI;CACvD,MAAM,gBAAgB,gBAAgB,QAAQ,iBAAiB;CAC/D,MAAM,WAAW,gBAAgB,QAAQ,WAAW;CAEpD,MAAM,YAAY,gBACd,CAAC,cAAc,GACf,CAAC,UAAU,QAAQ;CAEvB,MAAM,YAAmB,EAAE;AAC3B,MAAK,MAAM,SAAS,UAClB,KAAI;EACF,MAAM,QAAQ,MAAM,OAAO,SAAS,SAAS,MAAM;EACnD,IAAI,WAAW;AAEf,MAAI,SACF,YAAW,MAAM,QAAQ,MACvB,EAAE,UAAU,SAAS,SAAS,IAAI,EAAE,QAAQ,SAAS,SAAS,CAC/D;AAGH,YAAU,KAAK,GAAG,SAAS,KAAK,OAAY;GAC1C,UAAU;GACV,OAAO,EAAE;GACT,UAAU,EAAE,aAAa,KAAA,IAAY,GAAG,EAAE,SAAS,QAAQ,EAAE,CAAC,KAAK,KAAA;GACnE,YAAY,EAAE,eAAe,KAAA,IAAY,GAAG,EAAE,WAAW,QAAQ,EAAE,CAAC,KAAK,KAAA;GACzE,WAAW,GAAG,EAAE,WAAW,QAAQ,EAAE,IAAI,IAAI;GAC7C,UAAU,EAAE,YAAY,EAAE,UAAU;GACpC,KAAK,EAAE,iBAAiB,MACpB,KAAK,EAAE,iBAAiB,KAAW,QAAQ,EAAE,CAAC,KAC9C,KAAK,EAAE,iBAAiB,KAAO,QAAQ,EAAE,CAAC;GAC9C,OAAO,UAAU,QAAQ;GAC1B,EAAE,CAAC;SACE;AAMV,WAAU,MAAM,GAAG,MAAM;EACvB,MAAM,OAAO,WAAW,EAAE,YAAY,EAAE,UAAU,IAAI;AAEtD,UADa,WAAW,EAAE,YAAY,EAAE,UAAU,IAAI,KACxC;GACd;AAEF,QAAO,WAAW;EAChB,OAAO,UAAU,QAAQ;EACzB,YAAY,UAAU;EACtB,QAAQ,UAAU,MAAM,GAAG,GAAG;EAC9B,MAAM;EACN,KAAK;EACN,CAAC;;;;;AAMJ,eAAe,YAAY,QAAa,QAAiC;CACvE,MAAM,QAAQ,gBAAgB;CAC9B,MAAM,UAAU,gBAAgB,QAAQ,UAAU,IAAI,MAAM;CAC5D,MAAM,SAAS,gBAAgB,QAAQ,SAAS;AAEhD,KAAI,CAAC,QACH,QAAO,YAAY,+CAA+C;AAGpE,KAAI;EAMF,MAAM,iBAHW,MAAM,OAAO,YAAY,QAAQ,EAGnB,QAC3B,QAAQ,MACR,EAAE,aAAa,QACb,EAAE,aAAa,iBACf,EAAE,WAAW,aAAa,CAAC,SAAS,cAAc,EAErD,CACA,KAAK,OAAY;GAChB,QAAQ,EAAE;GACV,MAAM,EAAE;GACR,UAAU,IAAI,EAAE,WAAW,QAAQ,EAAE;GACrC,OAAO,EAAE;GACV,EAAE;EAGL,IAAI,UAAiB,EAAE;AACvB,MAAI;AAEF,cADc,MAAM,OAAO,SAAS,OAAO,cAAc,EAEtD,QAAQ,MAAW,CAAC,UAAU,EAAE,aAAa,SAAS,OAAO,QAAQ,QAAQ,GAAG,CAAC,CAAC,CAClF,MAAM,GAAG,GAAG,CACZ,KAAK,OAAY;IAChB,QAAQ,EAAE;IACV,aAAa,EAAE,gBAAgB,KAAA,IAAY,IAAI,EAAE,cAAc,KAAK,QAAQ,EAAE,CAAC,KAAK,KAAA;IACpF,cAAc,EAAE,iBAAiB,MAC7B,KAAK,EAAE,iBAAiB,KAAW,QAAQ,EAAE,CAAC,KAC9C,KAAK,EAAE,iBAAiB,KAAO,QAAQ,EAAE,CAAC;IAC9C,WAAW,EAAE,YAAY,KAAK,EAAE,YAAY,KAAW,QAAQ,EAAE,CAAC,KAAK,KAAA;IACxE,EAAE;UACC;AAIR,SAAO,WAAW;GAChB;GACA,WAAW,eAAe,SAAS,gBAAgB,EAAE;GACrD,kBAAkB,QAAQ,SAAS,IAAI,UAAU,KAAA;GACjD,KAAK;GACN,CAAC;UACK,KAAK;AACZ,SAAO,YAAY,uBAAuB,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI,GAAG;;;;;;AAOjG,eAAe,UAAU,QAAa,QAAiC;CACrE,MAAM,QAAQ,gBAAgB;CAC9B,MAAM,UAAU,gBAAgB,QAAQ,UAAU,IAAI,MAAM;AAE5D,KAAI,CAAC,QACH,QAAO,YAAY,+CAA+C;AAGpE,KAAI;EAGF,MAAM,UADW,MAAM,OAAO,YAAY,QAAQ,EAC1B,OACrB,QAAQ,MAAW,EAAE,aAAa,IAAK,CACvC,MAAM,GAAQ,MAAW,EAAE,aAAa,EAAE,WAAW;EAGxD,MAAM,UAA4D,EAAE;AACpE,OAAK,MAAM,KAAK,QAAQ;GACtB,MAAM,QAAQ,EAAE,aAAa;AAC7B,OAAI,CAAC,QAAQ,OAAQ,SAAQ,SAAS;IAAE,QAAQ,EAAE;IAAE,OAAO;IAAG;AAC9D,WAAQ,OAAO,OAAO,KAAK;IACzB,QAAQ,EAAE;IACV,SAAS,EAAE;IACX,UAAU,EAAE;IACZ,WAAW,EAAE,mBAAmB,KAAA,IAC5B,GAAG,EAAE,kBAAkB,IAAI,MAAM,KAAK,EAAE,eAAe,QAAQ,EAAE,CAAC,KAClE,KAAA;IACL,CAAC;AACF,WAAQ,OAAO,SAAS,EAAE;;EAI5B,MAAM,gBAAgB,OAAO,QAAQ,KAAa,MAAW,MAAM,EAAE,YAAY,EAAE;EAGnF,IAAI,iBAAiB;EACrB,IAAI,cAAc;AAClB,OAAK,MAAM,KAAK,OACd,KAAI,EAAE,mBAAmB,KAAA,KAAa,EAAE,aAAa,GAAG;AACtD,qBAAkB,EAAE,iBAAiB,EAAE;AACvC,kBAAe,EAAE;;EAGrB,MAAM,qBAAqB,cAAc,IAAI,iBAAiB,cAAc;EAC5E,MAAM,SAAS,iBAAiB,qBAAqB;AAErD,SAAO,WAAW;GAChB;GACA,eAAe,IAAI,cAAc,QAAQ,EAAE;GAC3C,WAAW,GAAG,sBAAsB,IAAI,MAAM,KAAK,mBAAmB,QAAQ,EAAE,CAAC;GACjF,WAAW,GAAG,UAAU,IAAI,MAAM,GAAG,GAAG,KAAK,IAAI,OAAO,CAAC,QAAQ,EAAE;GACnE,gBAAgB,OAAO,QAAQ,QAAQ,CAAC,KAAK,CAAC,OAAO,WAAW;IAC9D;IACA,UAAU,IAAI,KAAK,MAAM,QAAQ,EAAE;IACnC,YAAY,KAAK,OAAO;IACxB,aAAa,KAAK,OAAO,MAAM,GAAG,EAAE,CAAC,KAAI,OAAM;KAC7C,QAAQ,EAAE;KACV,UAAU,IAAI,EAAE,SAAS,QAAQ,EAAE;KACnC,WAAW,EAAE;KACd,EAAE;IACJ,EAAE;GACH,MAAM;GACP,CAAC;UACK,KAAK;AACZ,SAAO,YAAY,qBAAqB,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI,GAAG"}