@earnforge/cli 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"src-kbE_XVj7.mjs","names":[],"sources":["../../src/helpers.ts","../../src/doctor.ts","../../src/index.ts"],"sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\nimport chalk from 'chalk';\nimport Table from 'cli-table3';\nimport type { Vault, Chain, ProtocolDetail, RiskScore, ApyDataPoint, PreflightReport } from '@earnforge/sdk';\nimport { parseTvl } from '@earnforge/sdk';\n\n// ── Formatting helpers ──\n\nexport function fmtPct(n: number): string {\n // API returns APY as percentage (3.84 = 3.84%), NOT as decimal fraction\n return `${n.toFixed(2)}%`;\n}\n\nexport function fmtUsd(n: number): string {\n if (n >= 1_000_000_000) return `$${(n / 1_000_000_000).toFixed(2)}B`;\n if (n >= 1_000_000) return `$${(n / 1_000_000).toFixed(2)}M`;\n if (n >= 1_000) return `$${(n / 1_000).toFixed(2)}K`;\n return `$${n.toFixed(2)}`;\n}\n\nexport function riskLabel(score: number): string {\n if (score >= 7) return chalk.green(`${score}/10 (low)`);\n if (score >= 4) return chalk.yellow(`${score}/10 (medium)`);\n return chalk.red(`${score}/10 (high)`);\n}\n\nexport function riskLabelPlain(score: number): string {\n if (score >= 7) return `${score}/10 (low)`;\n if (score >= 4) return `${score}/10 (medium)`;\n return `${score}/10 (high)`;\n}\n\n// ── Table builders ──\n\nexport function vaultTable(vaults: Vault[]): string {\n const table = new Table({\n head: [\n chalk.bold('Name'),\n chalk.bold('Chain'),\n chalk.bold('Protocol'),\n chalk.bold('APY'),\n chalk.bold('TVL'),\n chalk.bold('Tags'),\n chalk.bold('Slug'),\n ],\n colWidths: [30, 8, 14, 10, 12, 16, 20],\n wordWrap: true,\n });\n\n for (const v of vaults) {\n const tvl = parseTvl(v.analytics.tvl);\n table.push([\n v.name,\n String(v.chainId),\n v.protocol.name,\n chalk.green(fmtPct(v.analytics.apy.total)),\n fmtUsd(tvl.parsed),\n v.tags.join(', '),\n v.slug,\n ]);\n }\n\n return table.toString();\n}\n\nexport function vaultDetail(v: Vault): string {\n const tvl = parseTvl(v.analytics.tvl);\n const lines = [\n chalk.bold.underline(v.name),\n '',\n ` ${chalk.dim('Slug:')} ${v.slug}`,\n ` ${chalk.dim('Chain:')} ${v.chainId} (${v.network})`,\n ` ${chalk.dim('Address:')} ${v.address}`,\n ` ${chalk.dim('Protocol:')} ${v.protocol.name} (${v.protocol.url})`,\n ` ${chalk.dim('Provider:')} ${v.provider}`,\n ` ${chalk.dim('Tags:')} ${v.tags.join(', ') || '(none)'}`,\n '',\n chalk.bold('Analytics'),\n ` ${chalk.dim('APY Total:')} ${chalk.green(fmtPct(v.analytics.apy.total))}`,\n ` ${chalk.dim('APY Base:')} ${fmtPct(v.analytics.apy.base)}`,\n ` ${chalk.dim('APY Reward:')} ${fmtPct(v.analytics.apy.reward)}`,\n ` ${chalk.dim('APY 1d:')} ${v.analytics.apy1d !== null ? fmtPct(v.analytics.apy1d) : 'N/A'}`,\n ` ${chalk.dim('APY 7d:')} ${v.analytics.apy7d !== null ? fmtPct(v.analytics.apy7d) : 'N/A'}`,\n ` ${chalk.dim('APY 30d:')} ${v.analytics.apy30d !== null ? fmtPct(v.analytics.apy30d) : 'N/A'}`,\n ` ${chalk.dim('TVL:')} ${fmtUsd(tvl.parsed)}`,\n ` ${chalk.dim('Updated:')} ${v.analytics.updatedAt}`,\n '',\n chalk.bold('Deposit & Redeem'),\n ` ${chalk.dim('Transactional:')} ${v.isTransactional ? chalk.green('Yes') : chalk.red('No')}`,\n ` ${chalk.dim('Redeemable:')} ${v.isRedeemable ? chalk.green('Yes') : chalk.red('No')}`,\n ` ${chalk.dim('Deposit Packs:')} ${v.depositPacks.map((p) => p.name).join(', ') || '(none)'}`,\n ` ${chalk.dim('Redeem Packs:')} ${v.redeemPacks.map((p) => p.name).join(', ') || '(none)'}`,\n '',\n chalk.bold('Underlying Tokens'),\n ...v.underlyingTokens.map(\n (t) => ` ${t.symbol} (${t.address}) — ${t.decimals} decimals`,\n ),\n ...(v.underlyingTokens.length === 0 ? [' (none)'] : []),\n '',\n ...(v.description ? [chalk.bold('Description'), ` ${v.description}`, ''] : []),\n ];\n\n return lines.join('\\n');\n}\n\nexport function chainTable(chains: Chain[]): string {\n const table = new Table({\n head: [chalk.bold('Chain ID'), chalk.bold('Name'), chalk.bold('CAIP')],\n });\n for (const c of chains) {\n table.push([String(c.chainId), c.name, c.networkCaip]);\n }\n return table.toString();\n}\n\nexport function protocolTable(protocols: ProtocolDetail[]): string {\n const table = new Table({\n head: [chalk.bold('Name'), chalk.bold('URL')],\n });\n for (const p of protocols) {\n table.push([p.name, p.url]);\n }\n return table.toString();\n}\n\nexport function portfolioTable(positions: Array<{ chainId: number; protocolName: string; asset: { symbol: string; name: string }; balanceUsd: string; balanceNative: string }>): string {\n const table = new Table({\n head: [\n chalk.bold('Chain'),\n chalk.bold('Protocol'),\n chalk.bold('Asset'),\n chalk.bold('Balance (Native)'),\n chalk.bold('Balance (USD)'),\n ],\n });\n for (const p of positions) {\n table.push([\n String(p.chainId),\n p.protocolName,\n `${p.asset.symbol} (${p.asset.name})`,\n p.balanceNative,\n `$${Number(p.balanceUsd).toFixed(2)}`,\n ]);\n }\n return table.toString();\n}\n\nexport function riskTable(risk: RiskScore): string {\n const table = new Table({\n head: [chalk.bold('Dimension'), chalk.bold('Score')],\n });\n table.push(['TVL Magnitude', `${risk.breakdown.tvl}/10`]);\n table.push(['APY Stability', `${risk.breakdown.apyStability}/10`]);\n table.push(['Protocol Maturity', `${risk.breakdown.protocol}/10`]);\n table.push(['Redeemability', `${risk.breakdown.redeemability}/10`]);\n table.push(['Asset Type', `${risk.breakdown.assetType}/10`]);\n table.push([chalk.bold('Composite'), chalk.bold(riskLabel(risk.score))]);\n return table.toString();\n}\n\nexport function suggestTable(allocations: Array<{ vault: Vault; risk: RiskScore; percentage: number; amount: number; apy: number }>): string {\n const table = new Table({\n head: [\n chalk.bold('Vault'),\n chalk.bold('Chain'),\n chalk.bold('Protocol'),\n chalk.bold('APY'),\n chalk.bold('Risk'),\n chalk.bold('Allocation'),\n chalk.bold('Amount'),\n ],\n });\n for (const a of allocations) {\n table.push([\n a.vault.name,\n String(a.vault.chainId),\n a.vault.protocol.name,\n chalk.green(fmtPct(a.apy)),\n riskLabel(a.risk.score),\n `${a.percentage.toFixed(1)}%`,\n fmtUsd(a.amount),\n ]);\n }\n return table.toString();\n}\n\nexport function apyHistoryTable(history: ApyDataPoint[]): string {\n const table = new Table({\n head: [chalk.bold('Date'), chalk.bold('APY'), chalk.bold('TVL')],\n });\n for (const d of history) {\n const date = d.timestamp.split('T')[0] ?? d.timestamp;\n table.push([date, fmtPct(d.apy), fmtUsd(d.tvlUsd)]);\n }\n return table.toString();\n}\n\nexport function preflightTable(report: PreflightReport): string {\n const lines: string[] = [];\n const status = report.ok ? chalk.green('PASS') : chalk.red('FAIL');\n lines.push(chalk.bold(`Preflight — ${report.vault.name} ${status}`));\n lines.push('');\n\n if (report.issues.length === 0) {\n lines.push(chalk.green(' All checks passed. Ready to deposit.'));\n } else {\n for (const issue of report.issues) {\n const icon = issue.severity === 'error' ? chalk.red('ERROR') : chalk.yellow('WARN');\n lines.push(` ${icon} [${issue.code}] ${issue.message}`);\n }\n }\n\n return lines.join('\\n');\n}\n\nexport function compareTable(vaults: Vault[], risks: RiskScore[]): string {\n const fields: Array<{ label: string; value: (v: Vault, r: RiskScore) => string }> = [\n { label: 'Slug', value: (v) => v.slug },\n { label: 'Chain', value: (v) => `${v.network} (${v.chainId})` },\n { label: 'Protocol', value: (v) => v.protocol.name },\n { label: 'APY Total', value: (v) => chalk.green(fmtPct(v.analytics.apy.total)) },\n { label: 'APY Base', value: (v) => fmtPct(v.analytics.apy.base) },\n { label: 'APY Reward', value: (v) => fmtPct(v.analytics.apy.reward) },\n { label: 'APY 7d', value: (v) => v.analytics.apy7d !== null ? fmtPct(v.analytics.apy7d) : 'N/A' },\n { label: 'APY 30d', value: (v) => v.analytics.apy30d !== null ? fmtPct(v.analytics.apy30d) : 'N/A' },\n { label: 'TVL', value: (v) => fmtUsd(parseTvl(v.analytics.tvl).parsed) },\n { label: 'Risk', value: (_, r) => riskLabel(r.score) },\n { label: 'Tags', value: (v) => v.tags.join(', ') || '(none)' },\n { label: 'Transactional', value: (v) => v.isTransactional ? chalk.green('Yes') : chalk.red('No') },\n { label: 'Redeemable', value: (v) => v.isRedeemable ? chalk.green('Yes') : chalk.red('No') },\n { label: 'Underlying', value: (v) => v.underlyingTokens.map((t) => t.symbol).join(', ') || '(none)' },\n ];\n\n const table = new Table({\n head: [chalk.bold(''), ...vaults.map((v) => chalk.bold(v.name))],\n wordWrap: true,\n });\n\n for (const field of fields) {\n table.push([\n chalk.dim(field.label),\n ...vaults.map((v, i) => field.value(v, risks[i])),\n ]);\n }\n\n return table.toString();\n}\n\n// ── Output helper ──\n\nexport function outputResult(data: unknown, json: boolean, humanFn: () => string): void {\n if (json) {\n console.log(JSON.stringify(data, null, 2));\n } else {\n console.log(humanFn());\n }\n}\n","// SPDX-License-Identifier: Apache-2.0\n\nimport chalk from 'chalk';\nimport type { Vault } from '@earnforge/sdk';\nimport { parseTvl, riskScore } from '@earnforge/sdk';\nimport { riskLabel } from './helpers.js';\n\nexport interface DoctorCheck {\n id: number;\n pitfall: string;\n description: string;\n passed: boolean;\n detail: string;\n}\n\nexport interface DoctorReport {\n checks: DoctorCheck[];\n passed: number;\n failed: number;\n total: number;\n riskScore?: { score: number; label: string };\n}\n\n/**\n * Run all 18 pitfall checks on a vault.\n * Each check is based on a real pitfall from the LI.FI Earn API.\n */\nexport function runDoctorChecks(vault: Vault, opts: { hasApiKey: boolean }): DoctorReport {\n const checks: DoctorCheck[] = [];\n\n // Pitfall #1: Wrong base URL\n // earn.li.fi for read-only data, li.quest for Composer\n checks.push({\n id: 1,\n pitfall: 'Base URL split',\n description: 'Earn Data uses earn.li.fi, Composer uses li.quest',\n passed: true, // SDK handles this\n detail: 'SDK uses correct base URLs (earn.li.fi / li.quest)',\n });\n\n // Pitfall #2: Sending auth to Earn Data API\n checks.push({\n id: 2,\n pitfall: 'No auth for Earn Data',\n description: 'Earn Data API (earn.li.fi) requires no authentication',\n passed: true, // SDK handles this\n detail: 'SDK sends no auth headers to earn.li.fi',\n });\n\n // Pitfall #3: Missing Composer API key\n checks.push({\n id: 3,\n pitfall: 'Composer API key',\n description: 'Composer (li.quest) requires x-lifi-api-key header',\n passed: opts.hasApiKey,\n detail: opts.hasApiKey\n ? 'LIFI_API_KEY is set'\n : 'LIFI_API_KEY is NOT set — quote/deposit commands will fail',\n });\n\n // Pitfall #4: Using POST for Composer quote\n checks.push({\n id: 4,\n pitfall: 'GET for Composer',\n description: 'Composer quote endpoint uses GET, not POST',\n passed: true,\n detail: 'SDK uses GET for /v1/quote',\n });\n\n // Pitfall #5: Wrong toToken for deposit\n checks.push({\n id: 5,\n pitfall: 'toToken = vault.address',\n description: 'Deposit toToken must be vault.address, not underlying token',\n passed: true,\n detail: `Vault address: ${vault.address}`,\n });\n\n // Pitfall #6: Not handling pagination\n const hasNextCursorLogic = true; // SDK handles via listAllVaults\n checks.push({\n id: 6,\n pitfall: 'Pagination via nextCursor',\n description: 'Vault list is paginated — must follow nextCursor',\n passed: hasNextCursorLogic,\n detail: 'SDK auto-paginates via listAllVaults()',\n });\n\n // Pitfall #7: APY is a fraction, not a percentage\n const apyTotal = vault.analytics.apy.total;\n const apyIsReasonable = apyTotal >= 0 && apyTotal < 500;\n checks.push({\n id: 7,\n pitfall: 'APY value is reasonable',\n description: 'apy.total is already a percentage (3.84 = 3.84%), not a fraction',\n passed: apyIsReasonable,\n detail: `apy.total = ${apyTotal.toFixed(2)}%`,\n });\n\n // Pitfall #8: TVL.usd is a string\n const tvl = parseTvl(vault.analytics.tvl);\n const tvlIsString = typeof vault.analytics.tvl.usd === 'string';\n checks.push({\n id: 8,\n pitfall: 'TVL.usd is a string',\n description: 'tvl.usd comes as a string, must parse to number',\n passed: tvlIsString,\n detail: `tvl.usd type=${typeof vault.analytics.tvl.usd}, parsed=${tvl.parsed}`,\n });\n\n // Pitfall #9: Decimal mismatch\n const hasDecimals = vault.underlyingTokens.length > 0;\n const decimals = vault.underlyingTokens[0]?.decimals;\n checks.push({\n id: 9,\n pitfall: 'Token decimals',\n description: 'Use underlyingTokens[0].decimals for amount conversion (6 for USDC, 18 for ETH)',\n passed: hasDecimals,\n detail: hasDecimals\n ? `Decimals: ${decimals} (${vault.underlyingTokens[0]?.symbol})`\n : 'No underlyingTokens — decimals unknown, must specify fromToken manually',\n });\n\n // Pitfall #10: Chain ID is a number, not name\n const chainIdIsNumber = typeof vault.chainId === 'number';\n checks.push({\n id: 10,\n pitfall: 'chainId is a number',\n description: 'Use numeric chainId (8453), not chain name (\"Base\")',\n passed: chainIdIsNumber,\n detail: `chainId = ${vault.chainId} (type: ${typeof vault.chainId})`,\n });\n\n // Pitfall #11: No gas token on destination chain\n checks.push({\n id: 11,\n pitfall: 'Gas token needed',\n description: 'Wallet must have native gas on the vault chain for tx execution',\n passed: true, // Cannot check from vault data alone; informational\n detail: `Vault is on chain ${vault.chainId} — ensure wallet has native gas`,\n });\n\n // Pitfall #12: Chain mismatch (wallet vs vault)\n checks.push({\n id: 12,\n pitfall: 'Chain mismatch',\n description: 'Wallet chain must match vault chain (or use cross-chain route)',\n passed: true, // Informational in vault-only mode\n detail: `Vault on chain ${vault.chainId} — ensure wallet is on same chain or use bridge`,\n });\n\n // Pitfall #13: Non-transactional vault\n checks.push({\n id: 13,\n pitfall: 'isTransactional',\n description: 'Vault must be isTransactional=true to deposit via Composer',\n passed: vault.isTransactional,\n detail: vault.isTransactional\n ? 'Vault is transactional — deposits supported'\n : 'Vault is NOT transactional — cannot deposit via API',\n });\n\n // Pitfall #14: Not redeemable\n checks.push({\n id: 14,\n pitfall: 'isRedeemable',\n description: 'If isRedeemable=false, you may not be able to withdraw',\n passed: vault.isRedeemable,\n detail: vault.isRedeemable\n ? 'Vault is redeemable'\n : 'Vault is NOT redeemable — funds may be locked',\n });\n\n // Pitfall #15: Empty underlyingTokens\n const hasUnderlyingTokens = vault.underlyingTokens.length > 0;\n checks.push({\n id: 15,\n pitfall: 'underlyingTokens[]',\n description: 'Some vaults have empty underlyingTokens — must specify fromToken manually',\n passed: hasUnderlyingTokens,\n detail: hasUnderlyingTokens\n ? `Underlying: ${vault.underlyingTokens.map((t) => t.symbol).join(', ')}`\n : 'underlyingTokens is EMPTY — you must pass fromToken explicitly',\n });\n\n // Pitfall #16: description is optional\n const hasDescription = vault.description !== undefined && vault.description !== '';\n checks.push({\n id: 16,\n pitfall: 'description optional',\n description: '~14% of vaults lack a description field — do not assume it exists',\n passed: true, // Always passes — it's fine if missing\n detail: hasDescription\n ? `Description present: \"${vault.description!.slice(0, 60)}...\"`\n : 'No description (this is expected for some vaults)',\n });\n\n // Pitfall #17: apy.reward can be null\n checks.push({\n id: 17,\n pitfall: 'apy.reward nullable',\n description: 'apy.reward is null for some protocols (Morpho) — normalize to 0',\n passed: typeof vault.analytics.apy.reward === 'number',\n detail: `apy.reward = ${vault.analytics.apy.reward} (type: ${typeof vault.analytics.apy.reward})`,\n });\n\n // Pitfall #18: apy1d/apy7d/apy30d nullable\n const apyFields = {\n apy1d: vault.analytics.apy1d,\n apy7d: vault.analytics.apy7d,\n apy30d: vault.analytics.apy30d,\n };\n const nullApyFields = Object.entries(apyFields)\n .filter(([, v]) => v === null)\n .map(([k]) => k);\n checks.push({\n id: 18,\n pitfall: 'Historical APY nullable',\n description: 'apy1d, apy7d, apy30d can all be null — use fallback chain',\n passed: true, // Always passes — null is expected; SDK handles fallback\n detail:\n nullApyFields.length > 0\n ? `Null fields: ${nullApyFields.join(', ')} — SDK uses fallback chain`\n : 'All historical APY fields present',\n });\n\n const passed = checks.filter((c) => c.passed).length;\n const failed = checks.filter((c) => !c.passed).length;\n\n const risk = riskScore(vault);\n\n return {\n checks,\n passed,\n failed,\n total: checks.length,\n riskScore: { score: risk.score, label: risk.label },\n };\n}\n\nexport function formatDoctorReport(report: DoctorReport, vaultName?: string): string {\n const lines: string[] = [];\n\n lines.push(chalk.bold.underline(`EarnForge Doctor${vaultName ? ` — ${vaultName}` : ''}`));\n lines.push('');\n\n for (const check of report.checks) {\n const icon = check.passed ? chalk.green('OK') : chalk.red('FAIL');\n const num = `#${String(check.id).padStart(2, '0')}`;\n lines.push(\n ` ${icon} ${chalk.dim(num)} ${chalk.bold(check.pitfall)}`,\n );\n lines.push(` ${chalk.dim(check.description)}`);\n lines.push(` ${check.detail}`);\n lines.push('');\n }\n\n lines.push(chalk.bold('Summary'));\n lines.push(\n ` ${chalk.green(`${report.passed} passed`)} ${report.failed > 0 ? chalk.red(`${report.failed} failed`) : chalk.dim('0 failed')} ${chalk.dim(`${report.total} total`)}`,\n );\n\n if (report.riskScore) {\n lines.push('');\n lines.push(chalk.bold('Risk Score'));\n lines.push(` ${riskLabel(report.riskScore.score)}`);\n }\n\n return lines.join('\\n');\n}\n\n/**\n * Run environment-only doctor checks (no vault needed).\n */\nexport function runEnvChecks(): DoctorReport {\n const checks: DoctorCheck[] = [];\n\n const hasApiKey = !!process.env['LIFI_API_KEY'];\n checks.push({\n id: 1,\n pitfall: 'LIFI_API_KEY',\n description: 'Composer API key for quote/deposit operations',\n passed: hasApiKey,\n detail: hasApiKey ? 'LIFI_API_KEY is set' : 'LIFI_API_KEY is NOT set',\n });\n\n const nodeVersion = process.version;\n const majorVersion = parseInt(nodeVersion.slice(1), 10);\n checks.push({\n id: 2,\n pitfall: 'Node.js version',\n description: 'Node.js 18+ required for native fetch',\n passed: majorVersion >= 18,\n detail: `Node.js ${nodeVersion} (major: ${majorVersion})`,\n });\n\n checks.push({\n id: 3,\n pitfall: 'Earn Data API',\n description: 'earn.li.fi is the read-only API (no auth needed)',\n passed: true,\n detail: 'earn.li.fi — public, no API key required',\n });\n\n checks.push({\n id: 4,\n pitfall: 'Composer API',\n description: 'li.quest is the Composer API (requires API key)',\n passed: hasApiKey,\n detail: hasApiKey\n ? 'li.quest will use LIFI_API_KEY for x-lifi-api-key header'\n : 'li.quest requires LIFI_API_KEY — set it to use quote/deposit',\n });\n\n const passed = checks.filter((c) => c.passed).length;\n const failed = checks.filter((c) => !c.passed).length;\n\n return { checks, passed, failed, total: checks.length };\n}\n\nexport function formatEnvReport(report: DoctorReport): string {\n const lines: string[] = [];\n\n lines.push(chalk.bold.underline('EarnForge Doctor — Environment'));\n lines.push('');\n\n for (const check of report.checks) {\n const icon = check.passed ? chalk.green('OK') : chalk.red('FAIL');\n lines.push(` ${icon} ${chalk.bold(check.pitfall)}`);\n lines.push(` ${chalk.dim(check.description)}`);\n lines.push(` ${check.detail}`);\n lines.push('');\n }\n\n lines.push(chalk.bold('Summary'));\n lines.push(\n ` ${chalk.green(`${report.passed} passed`)} ${report.failed > 0 ? chalk.red(`${report.failed} failed`) : chalk.dim('0 failed')} ${chalk.dim(`${report.total} total`)}`,\n );\n\n return lines.join('\\n');\n}\n","// SPDX-License-Identifier: Apache-2.0\n\nimport { Command } from 'commander';\nimport chalk from 'chalk';\nimport ora from 'ora';\nimport {\n createEarnForge,\n parseTvl,\n checkAllowance,\n buildApprovalTx,\n MAX_UINT256,\n type Vault,\n type EarnForge,\n type StrategyPreset,\n} from '@earnforge/sdk';\nimport {\n vaultTable,\n vaultDetail,\n compareTable,\n chainTable,\n protocolTable,\n portfolioTable,\n riskTable,\n suggestTable,\n apyHistoryTable,\n preflightTable,\n fmtPct,\n fmtUsd,\n riskLabel,\n riskLabelPlain,\n outputResult,\n} from './helpers.js';\nimport {\n runDoctorChecks,\n formatDoctorReport,\n runEnvChecks,\n formatEnvReport,\n type DoctorReport,\n} from './doctor.js';\n\nexport { runDoctorChecks, formatDoctorReport, runEnvChecks, formatEnvReport };\nexport type { DoctorReport };\n\n// ── Forge factory (lazy singleton) ──\n\nlet _forge: EarnForge | undefined;\n\nfunction getForge(): EarnForge {\n if (!_forge) {\n _forge = createEarnForge({\n composerApiKey: process.env['LIFI_API_KEY'],\n });\n }\n return _forge;\n}\n\n/** Override forge instance (for testing) */\nexport function setForge(forge: EarnForge): void {\n _forge = forge;\n}\n\n/** Reset forge instance */\nexport function resetForge(): void {\n _forge = undefined;\n}\n\nconst VALID_STRATEGIES: StrategyPreset[] = ['conservative', 'max-apy', 'diversified', 'risk-adjusted'];\n\nfunction validateStrategy(s: string): StrategyPreset {\n if (!VALID_STRATEGIES.includes(s as StrategyPreset)) {\n throw new Error(`Invalid strategy: ${s}. Valid: ${VALID_STRATEGIES.join(', ')}`);\n }\n return s as StrategyPreset;\n}\n\n// ── Program ──\n\nexport const program = new Command();\n\nprogram\n .name('earnforge')\n .version('0.1.0')\n .description('EarnForge CLI — Developer toolkit for the LI.FI Earn API');\n\n// ── list ──\n\nprogram\n .command('list')\n .description('List vaults with filters')\n .option('--chain <id>', 'Filter by chain ID', parseInt)\n .option('--asset <sym>', 'Filter by asset symbol')\n .option('--min-apy <n>', 'Minimum APY (e.g. 5 = 5%)', parseFloat)\n .option('--min-tvl <n>', 'Minimum TVL in USD', parseFloat)\n .option('--sort <field>', 'Sort by apy or tvl', 'apy')\n .option('--limit <n>', 'Max results', parseInt)\n .option('--strategy <preset>', 'Strategy preset (conservative, max-apy, diversified, risk-adjusted)')\n .option('--json', 'Output as JSON', false)\n .action(async (opts) => {\n const spinner = ora('Fetching vaults...').start();\n try {\n const forge = getForge();\n const limit = opts.limit ?? 20;\n const strategy = opts.strategy ? validateStrategy(opts.strategy) : undefined;\n\n const vaults: Vault[] = [];\n for await (const v of forge.vaults.listAll({\n chainId: opts.chain,\n asset: opts.asset,\n minTvl: opts.minTvl,\n strategy,\n })) {\n // Client-side APY filter\n if (opts.minApy !== undefined && v.analytics.apy.total < opts.minApy) continue;\n // Client-side TVL filter\n if (opts.minTvl !== undefined && parseTvl(v.analytics.tvl).parsed < opts.minTvl) continue;\n\n vaults.push(v);\n if (vaults.length >= limit * 3) break; // Over-fetch for sorting\n }\n\n // Sort\n if (opts.sort === 'tvl') {\n vaults.sort((a, b) => parseTvl(b.analytics.tvl).parsed - parseTvl(a.analytics.tvl).parsed);\n } else {\n vaults.sort((a, b) => b.analytics.apy.total - a.analytics.apy.total);\n }\n\n const result = vaults.slice(0, limit);\n spinner.stop();\n\n outputResult(\n result.map((v) => ({\n slug: v.slug,\n name: v.name,\n chainId: v.chainId,\n protocol: v.protocol.name,\n apy: v.analytics.apy.total,\n tvlUsd: parseTvl(v.analytics.tvl).parsed,\n tags: v.tags,\n isTransactional: v.isTransactional,\n })),\n opts.json,\n () => {\n if (result.length === 0) return chalk.yellow('No vaults found matching your filters.');\n return `${vaultTable(result)}\\n\\n${chalk.dim(`Showing ${result.length} vault${result.length !== 1 ? 's' : ''}`)}`;\n },\n );\n } catch (err) {\n spinner.fail('Failed to fetch vaults');\n console.error(chalk.red(err instanceof Error ? err.message : String(err)));\n process.exitCode = 1;\n }\n });\n\n// ── top ──\n\nprogram\n .command('top')\n .description('Show top vaults by APY for a given asset')\n .requiredOption('--asset <sym>', 'Asset symbol (e.g. USDC, WETH)')\n .option('--chain <id>', 'Filter by chain ID', parseInt)\n .option('--limit <n>', 'Max results', parseInt)\n .option('--json', 'Output as JSON', false)\n .action(async (opts) => {\n const spinner = ora('Fetching top vaults...').start();\n try {\n const forge = getForge();\n const result = await forge.vaults.top({\n asset: opts.asset,\n chainId: opts.chain,\n limit: opts.limit ?? 10,\n });\n spinner.stop();\n\n outputResult(\n result.map((v) => ({\n slug: v.slug,\n name: v.name,\n chainId: v.chainId,\n protocol: v.protocol.name,\n apy: v.analytics.apy.total,\n tvlUsd: parseTvl(v.analytics.tvl).parsed,\n tags: v.tags,\n })),\n opts.json,\n () => {\n if (result.length === 0) return chalk.yellow(`No vaults found for asset: ${opts.asset}`);\n return `${chalk.bold(`Top ${opts.asset} vaults`)}\\n\\n${vaultTable(result)}`;\n },\n );\n } catch (err) {\n spinner.fail('Failed to fetch top vaults');\n console.error(chalk.red(err instanceof Error ? err.message : String(err)));\n process.exitCode = 1;\n }\n });\n\n// ── vault ──\n\nprogram\n .command('vault')\n .description('Get detailed vault info by slug')\n .argument('<slug>', 'Vault slug (e.g. 8453-0xbeef...)')\n .option('--json', 'Output as JSON', false)\n .action(async (slug: string, opts) => {\n const spinner = ora('Fetching vault...').start();\n try {\n const forge = getForge();\n const vault = await forge.vaults.get(slug);\n spinner.stop();\n\n outputResult(vault, opts.json, () => vaultDetail(vault));\n } catch (err) {\n spinner.fail('Failed to fetch vault');\n console.error(chalk.red(err instanceof Error ? err.message : String(err)));\n process.exitCode = 1;\n }\n });\n\n// ── compare ──\n\nprogram\n .command('compare')\n .description('Side-by-side comparison of 2 or more vaults')\n .argument('<slugs...>', 'Vault slugs to compare (space-separated)')\n .option('--json', 'Output as JSON', false)\n .action(async (slugs: string[], opts) => {\n if (slugs.length < 2) {\n console.error(chalk.red('Provide at least 2 vault slugs to compare.'));\n process.exitCode = 1;\n return;\n }\n const spinner = ora(`Fetching ${slugs.length} vaults...`).start();\n try {\n const forge = getForge();\n const vaults = await Promise.all(slugs.map((s) => forge.vaults.get(s)));\n const risks = vaults.map((v) => forge.riskScore(v));\n spinner.stop();\n\n outputResult(\n vaults.map((v, i) => ({\n slug: v.slug,\n name: v.name,\n chainId: v.chainId,\n network: v.network,\n protocol: v.protocol.name,\n apy: v.analytics.apy,\n apy7d: v.analytics.apy7d,\n apy30d: v.analytics.apy30d,\n tvlUsd: parseTvl(v.analytics.tvl).parsed,\n risk: risks[i],\n tags: v.tags,\n isTransactional: v.isTransactional,\n isRedeemable: v.isRedeemable,\n underlyingTokens: v.underlyingTokens.map((t) => t.symbol),\n })),\n opts.json,\n () => {\n return `${chalk.bold(`Vault Comparison (${vaults.length} vaults)`)}\\n\\n${compareTable(vaults, risks)}`;\n },\n );\n } catch (err) {\n spinner.fail('Failed to compare vaults');\n console.error(chalk.red(err instanceof Error ? err.message : String(err)));\n process.exitCode = 1;\n }\n });\n\n// ── portfolio ──\n\nprogram\n .command('portfolio')\n .description('View portfolio positions for a wallet')\n .argument('<wallet>', 'Wallet address')\n .option('--json', 'Output as JSON', false)\n .action(async (wallet: string, opts) => {\n const spinner = ora('Fetching portfolio...').start();\n try {\n const forge = getForge();\n const portfolio = await forge.portfolio.get(wallet);\n spinner.stop();\n\n outputResult(portfolio, opts.json, () => {\n if (portfolio.positions.length === 0) return chalk.yellow('No positions found.');\n const totalUsd = portfolio.positions.reduce(\n (sum, p) => sum + Number(p.balanceUsd),\n 0,\n );\n return `${chalk.bold('Portfolio')}\\n\\n${portfolioTable(portfolio.positions)}\\n\\n${chalk.dim(`Total: ${fmtUsd(totalUsd)}`)}`;\n });\n } catch (err) {\n spinner.fail('Failed to fetch portfolio');\n console.error(chalk.red(err instanceof Error ? err.message : String(err)));\n process.exitCode = 1;\n }\n });\n\n// ── quote ──\n\nprogram\n .command('quote')\n .description('Build a deposit quote')\n .requiredOption('--vault <slug>', 'Vault slug')\n .requiredOption('--amount <human>', 'Human-readable deposit amount')\n .requiredOption('--wallet <addr>', 'Wallet address')\n .option('--from-token <addr>', 'Override from token address')\n .option('--from-chain <id>', 'Override source chain', parseInt)\n .option('--optimize-gas', 'Compare routes from multiple chains', false)\n .option('--json', 'Output as JSON', false)\n .action(async (opts) => {\n const spinner = ora('Building quote...').start();\n try {\n const forge = getForge();\n const vault = await forge.vaults.get(opts.vault);\n\n if (opts.optimizeGas) {\n spinner.text = 'Comparing cross-chain routes...';\n const routes = await forge.optimizeGasRoutes(vault, {\n fromAmount: opts.amount,\n wallet: opts.wallet,\n fromToken: opts.fromToken,\n fromChains: opts.fromChain ? [opts.fromChain, vault.chainId] : undefined,\n });\n spinner.stop();\n\n outputResult(\n routes.map((r) => ({\n fromChain: r.fromChain,\n fromChainName: r.fromChainName,\n totalCostUsd: r.totalCostUsd,\n gasCostUsd: r.gasCostUsd,\n feeCostUsd: r.feeCostUsd,\n executionDuration: r.executionDuration,\n })),\n opts.json,\n () => {\n if (routes.length === 0) return chalk.yellow('No routes found.');\n const lines = [chalk.bold(`Gas-optimized routes for ${vault.name}`), ''];\n for (const r of routes) {\n const best = r === routes[0] ? chalk.green(' << cheapest') : '';\n lines.push(\n ` ${r.fromChainName} (${r.fromChain}): gas=${fmtUsd(r.gasCostUsd)} fee=${fmtUsd(r.feeCostUsd)} total=${fmtUsd(r.totalCostUsd)} time=${r.executionDuration}s${best}`,\n );\n }\n return lines.join('\\n');\n },\n );\n } else {\n const result = await forge.buildDepositQuote(vault, {\n fromAmount: opts.amount,\n wallet: opts.wallet,\n fromToken: opts.fromToken,\n fromChain: opts.fromChain,\n });\n spinner.stop();\n\n const approvalAddress = (result.quote.estimate as Record<string, unknown>).approvalAddress as string | undefined;\n\n outputResult(\n {\n vault: vault.slug,\n humanAmount: result.humanAmount,\n rawAmount: result.rawAmount,\n decimals: result.decimals,\n fromToken: result.quote.action.fromToken.symbol,\n toToken: result.quote.action.toToken.symbol,\n estimatedOutput: result.quote.estimate.toAmount,\n gasCosts: result.quote.estimate.gasCosts,\n feeCosts: result.quote.estimate.feeCosts,\n executionDuration: result.quote.estimate.executionDuration,\n approvalAddress,\n },\n opts.json,\n () => {\n const lines = [\n chalk.bold(`Deposit Quote — ${vault.name}`),\n '',\n ` ${chalk.dim('Amount:')} ${result.humanAmount} (${result.rawAmount} raw, ${result.decimals} decimals)`,\n ` ${chalk.dim('From:')} ${result.quote.action.fromToken.symbol} on chain ${result.quote.action.fromChainId}`,\n ` ${chalk.dim('To:')} ${result.quote.action.toToken.symbol} on chain ${result.quote.action.toChainId}`,\n ` ${chalk.dim('Est. Output:')} ${result.quote.estimate.toAmount}`,\n ` ${chalk.dim('Duration:')} ${result.quote.estimate.executionDuration}s`,\n ];\n const gasCosts = result.quote.estimate.gasCosts ?? [];\n const feeCosts = result.quote.estimate.feeCosts ?? [];\n if (gasCosts.length > 0) {\n const totalGas = gasCosts.reduce((s, g) => s + Number(g.amountUSD), 0);\n lines.push(` ${chalk.dim('Gas Cost:')} ${fmtUsd(totalGas)}`);\n }\n if (feeCosts.length > 0) {\n const totalFee = feeCosts.reduce((s, f) => s + Number(f.amountUSD), 0);\n lines.push(` ${chalk.dim('Fee Cost:')} ${fmtUsd(totalFee)}`);\n }\n if (approvalAddress) {\n lines.push('');\n lines.push(chalk.yellow(` Approval needed: approve ${result.quote.action.fromToken.symbol} for spender ${approvalAddress}`));\n lines.push(chalk.dim(` Run: earnforge allowance --token ${result.quote.action.fromToken.address} --owner ${opts.wallet} --spender ${approvalAddress} --amount ${result.rawAmount} --chain ${result.quote.action.fromChainId}`));\n }\n lines.push('');\n lines.push(chalk.dim('Transaction ready to sign via quote.transactionRequest'));\n return lines.join('\\n');\n },\n );\n }\n } catch (err) {\n spinner.fail('Failed to build quote');\n console.error(chalk.red(err instanceof Error ? err.message : String(err)));\n process.exitCode = 1;\n }\n });\n\n// ── withdraw ──\n\nprogram\n .command('withdraw')\n .description('Build a withdrawal/redeem quote')\n .requiredOption('--vault <slug>', 'Vault slug')\n .requiredOption('--amount <human>', 'Amount of vault shares to redeem')\n .requiredOption('--wallet <addr>', 'Wallet address')\n .option('--to-token <addr>', 'Override destination token address')\n .option('--to-chain <id>', 'Override destination chain', parseInt)\n .option('--slippage <n>', 'Slippage tolerance (0.03 = 3%)', parseFloat)\n .option('--json', 'Output as JSON', false)\n .action(async (opts) => {\n const spinner = ora('Building redeem quote...').start();\n try {\n const forge = getForge();\n const vault = await forge.vaults.get(opts.vault);\n const result = await forge.buildRedeemQuote(vault, {\n fromAmount: opts.amount,\n wallet: opts.wallet,\n toToken: opts.toToken,\n toChain: opts.toChain,\n slippage: opts.slippage,\n });\n spinner.stop();\n\n outputResult(\n {\n vault: vault.slug,\n humanAmount: result.humanAmount,\n rawAmount: result.rawAmount,\n fromToken: result.quote.action.fromToken.symbol,\n toToken: result.quote.action.toToken.symbol,\n estimatedOutput: result.quote.estimate.toAmount,\n gasCosts: result.quote.estimate.gasCosts,\n feeCosts: result.quote.estimate.feeCosts,\n executionDuration: result.quote.estimate.executionDuration,\n },\n opts.json,\n () => {\n const lines = [\n chalk.bold(`Withdraw Quote — ${vault.name}`),\n '',\n ` ${chalk.dim('Amount:')} ${result.humanAmount} vault shares (${result.rawAmount} raw)`,\n ` ${chalk.dim('From:')} ${result.quote.action.fromToken.symbol} (vault token) on chain ${result.quote.action.fromChainId}`,\n ` ${chalk.dim('To:')} ${result.quote.action.toToken.symbol} on chain ${result.quote.action.toChainId}`,\n ` ${chalk.dim('Est. Output:')} ${result.quote.estimate.toAmount}`,\n ` ${chalk.dim('Duration:')} ${result.quote.estimate.executionDuration}s`,\n ];\n const gasCosts = result.quote.estimate.gasCosts ?? [];\n const feeCosts = result.quote.estimate.feeCosts ?? [];\n if (gasCosts.length > 0) {\n const totalGas = gasCosts.reduce((s: number, g: { amountUSD: string }) => s + Number(g.amountUSD), 0);\n lines.push(` ${chalk.dim('Gas Cost:')} ${fmtUsd(totalGas)}`);\n }\n if (feeCosts.length > 0) {\n const totalFee = feeCosts.reduce((s: number, f: { amountUSD: string }) => s + Number(f.amountUSD), 0);\n lines.push(` ${chalk.dim('Fee Cost:')} ${fmtUsd(totalFee)}`);\n }\n lines.push('');\n lines.push(chalk.dim('Transaction ready to sign via quote.transactionRequest'));\n return lines.join('\\n');\n },\n );\n } catch (err) {\n spinner.fail('Failed to build redeem quote');\n console.error(chalk.red(err instanceof Error ? err.message : String(err)));\n process.exitCode = 1;\n }\n });\n\n// ── allowance ──\n\nprogram\n .command('allowance')\n .description('Check ERC-20 token allowance for a spender')\n .requiredOption('--token <addr>', 'ERC-20 token address')\n .requiredOption('--owner <addr>', 'Token owner (wallet) address')\n .requiredOption('--spender <addr>', 'Spender address (from quote.estimate.approvalAddress)')\n .requiredOption('--amount <raw>', 'Required amount in smallest unit')\n .requiredOption('--chain <id>', 'Chain ID', parseInt)\n .option('--rpc <url>', 'Custom RPC URL')\n .option('--json', 'Output as JSON', false)\n .action(async (opts) => {\n const spinner = ora('Checking allowance...').start();\n try {\n const rpcUrl = opts.rpc ?? `https://rpc.li.fi/v1/chain/${opts.chain}`;\n const result = await checkAllowance(\n rpcUrl,\n opts.token,\n opts.owner,\n opts.spender,\n BigInt(opts.amount),\n );\n spinner.stop();\n\n const jsonData = {\n token: opts.token,\n owner: opts.owner,\n spender: opts.spender,\n allowance: result.allowance.toString(),\n requiredAmount: result.requiredAmount.toString(),\n sufficient: result.sufficient,\n };\n\n outputResult(jsonData, opts.json, () => {\n const status = result.sufficient\n ? chalk.green('SUFFICIENT — no approval needed')\n : chalk.red('INSUFFICIENT — approval required');\n return [\n chalk.bold('Allowance Check'),\n '',\n ` ${chalk.dim('Token:')} ${opts.token}`,\n ` ${chalk.dim('Owner:')} ${opts.owner}`,\n ` ${chalk.dim('Spender:')} ${opts.spender}`,\n ` ${chalk.dim('Allowance:')} ${result.allowance.toString()}`,\n ` ${chalk.dim('Required:')} ${result.requiredAmount.toString()}`,\n ` ${chalk.dim('Status:')} ${status}`,\n '',\n ...(result.sufficient\n ? []\n : [\n chalk.dim('To approve, run:'),\n chalk.dim(` earnforge approve --token ${opts.token} --spender ${opts.spender} --chain ${opts.chain}`),\n ]),\n ].join('\\n');\n });\n } catch (err) {\n spinner.fail('Failed to check allowance');\n console.error(chalk.red(err instanceof Error ? err.message : String(err)));\n process.exitCode = 1;\n }\n });\n\n// ── approve ──\n\nprogram\n .command('approve')\n .description('Build an ERC-20 approval transaction')\n .requiredOption('--token <addr>', 'ERC-20 token address')\n .requiredOption('--spender <addr>', 'Spender address (from quote.estimate.approvalAddress)')\n .requiredOption('--chain <id>', 'Chain ID', parseInt)\n .option('--amount <raw>', 'Amount to approve (default: unlimited)')\n .option('--json', 'Output as JSON', false)\n .action(async (opts) => {\n const amount = opts.amount ? BigInt(opts.amount) : MAX_UINT256;\n const tx = buildApprovalTx(opts.token, opts.spender, amount, opts.chain);\n\n outputResult(tx, opts.json, () => {\n return [\n chalk.bold('Approval Transaction'),\n '',\n ` ${chalk.dim('To:')} ${tx.to}`,\n ` ${chalk.dim('Chain:')} ${tx.chainId}`,\n ` ${chalk.dim('Amount:')} ${amount === MAX_UINT256 ? 'Unlimited (MaxUint256)' : amount.toString()}`,\n ` ${chalk.dim('Data:')} ${tx.data.slice(0, 20)}...`,\n '',\n chalk.dim('Sign and send this transaction before the deposit/quote transaction.'),\n ].join('\\n');\n });\n });\n\n// ── apy-history ──\n\nprogram\n .command('apy-history')\n .description('Fetch 30-day APY history from DeFiLlama')\n .argument('<slug>', 'Vault slug')\n .option('--json', 'Output as JSON', false)\n .action(async (slug: string, opts) => {\n const spinner = ora('Fetching APY history...').start();\n try {\n const forge = getForge();\n const vault = await forge.vaults.get(slug);\n const history = await forge.getApyHistory(vault);\n spinner.stop();\n\n outputResult(\n { vault: vault.slug, name: vault.name, dataPoints: history.length, history },\n opts.json,\n () => {\n if (history.length === 0) {\n return chalk.yellow(`No APY history found for ${vault.name}. DeFiLlama may not track this vault.`);\n }\n return `${chalk.bold(`APY History — ${vault.name} (${history.length} days)`)}\\n\\n${apyHistoryTable(history)}`;\n },\n );\n } catch (err) {\n spinner.fail('Failed to fetch APY history');\n console.error(chalk.red(err instanceof Error ? err.message : String(err)));\n process.exitCode = 1;\n }\n });\n\n// ── preflight ──\n\nprogram\n .command('preflight')\n .description('Run pre-deposit checks on a vault + wallet')\n .requiredOption('--vault <slug>', 'Vault slug')\n .requiredOption('--wallet <addr>', 'Wallet address')\n .option('--amount <human>', 'Deposit amount (human-readable)')\n .option('--wallet-chain <id>', 'Wallet current chain ID', parseInt)\n .option('--cross-chain', 'Flag cross-chain deposit intent', false)\n .option('--json', 'Output as JSON', false)\n .action(async (opts) => {\n const spinner = ora('Running preflight checks...').start();\n try {\n const forge = getForge();\n const vault = await forge.vaults.get(opts.vault);\n const report = forge.preflight(vault, opts.wallet, {\n walletChainId: opts.walletChain,\n depositAmount: opts.amount,\n crossChain: opts.crossChain,\n });\n spinner.stop();\n\n outputResult(\n {\n ok: report.ok,\n vault: vault.slug,\n wallet: opts.wallet,\n issues: report.issues,\n },\n opts.json,\n () => preflightTable(report),\n );\n } catch (err) {\n spinner.fail('Preflight failed');\n console.error(chalk.red(err instanceof Error ? err.message : String(err)));\n process.exitCode = 1;\n }\n });\n\n// ── doctor ──\n\nprogram\n .command('doctor')\n .description('Run 18-pitfall diagnostics on a vault or environment')\n .option('--vault <slug>', 'Vault slug to check')\n .option('--env', 'Run environment checks only', false)\n .option('--json', 'Output as JSON', false)\n .action(async (opts) => {\n if (opts.env && !opts.vault) {\n // Env-only mode\n const report = runEnvChecks();\n outputResult(report, opts.json, () => formatEnvReport(report));\n return;\n }\n\n if (!opts.vault) {\n console.error(chalk.red('Provide --vault <slug> or --env'));\n process.exitCode = 1;\n return;\n }\n\n const spinner = ora('Running doctor checks...').start();\n try {\n const forge = getForge();\n const vault = await forge.vaults.get(opts.vault);\n const report = runDoctorChecks(vault, {\n hasApiKey: !!process.env['LIFI_API_KEY'],\n });\n spinner.stop();\n\n outputResult(report, opts.json, () => formatDoctorReport(report, vault.name));\n } catch (err) {\n spinner.fail('Doctor failed');\n console.error(chalk.red(err instanceof Error ? err.message : String(err)));\n process.exitCode = 1;\n }\n });\n\n// ── risk ──\n\nprogram\n .command('risk')\n .description('Calculate risk score for a vault')\n .argument('<slug>', 'Vault slug')\n .option('--json', 'Output as JSON', false)\n .action(async (slug: string, opts) => {\n const spinner = ora('Calculating risk...').start();\n try {\n const forge = getForge();\n const vault = await forge.vaults.get(slug);\n const risk = forge.riskScore(vault);\n spinner.stop();\n\n outputResult(\n { slug: vault.slug, name: vault.name, ...risk },\n opts.json,\n () => `${chalk.bold(`Risk Score — ${vault.name}`)}\\n\\n${riskTable(risk)}`,\n );\n } catch (err) {\n spinner.fail('Failed to calculate risk');\n console.error(chalk.red(err instanceof Error ? err.message : String(err)));\n process.exitCode = 1;\n }\n });\n\n// ── suggest ──\n\nprogram\n .command('suggest')\n .description('Get portfolio allocation suggestions')\n .requiredOption('--amount <human>', 'Total amount to allocate (USD)', parseFloat)\n .requiredOption('--asset <sym>', 'Asset symbol (e.g. USDC)')\n .option('--max-chains <n>', 'Max number of chains', parseInt)\n .option('--strategy <preset>', 'Strategy preset')\n .option('--json', 'Output as JSON', false)\n .action(async (opts) => {\n const spinner = ora('Analyzing vaults and building allocations...').start();\n try {\n const forge = getForge();\n const strategy = opts.strategy ? validateStrategy(opts.strategy) : undefined;\n const result = await forge.suggest({\n amount: opts.amount,\n asset: opts.asset,\n maxChains: opts.maxChains,\n strategy,\n });\n spinner.stop();\n\n outputResult(\n {\n totalAmount: result.totalAmount,\n expectedApy: result.expectedApy,\n allocations: result.allocations.map((a) => ({\n vault: a.vault.slug,\n vaultName: a.vault.name,\n chainId: a.vault.chainId,\n protocol: a.vault.protocol.name,\n apy: a.apy,\n risk: a.risk,\n percentage: a.percentage,\n amount: a.amount,\n })),\n },\n opts.json,\n () => {\n if (result.allocations.length === 0)\n return chalk.yellow('No suitable vaults found for allocation.');\n const lines = [\n chalk.bold(`Allocation Suggestion — ${fmtUsd(result.totalAmount)} in ${opts.asset}`),\n ` ${chalk.dim('Expected APY:')} ${chalk.green(fmtPct(result.expectedApy))}`,\n '',\n suggestTable(result.allocations),\n ];\n return lines.join('\\n');\n },\n );\n } catch (err) {\n spinner.fail('Failed to generate suggestions');\n console.error(chalk.red(err instanceof Error ? err.message : String(err)));\n process.exitCode = 1;\n }\n });\n\n// ── watch ──\n\nprogram\n .command('watch')\n .description('Watch a vault for APY/TVL changes')\n .requiredOption('--vault <slug>', 'Vault slug')\n .option('--apy-drop <pct>', 'APY drop threshold (%)', parseFloat)\n .option('--tvl-drop <pct>', 'TVL drop threshold (%)', parseFloat)\n .option('--interval <ms>', 'Poll interval in milliseconds', parseInt)\n .option('--max-iterations <n>', 'Max iterations (0 = unlimited)', parseInt)\n .option('--json', 'Output events as JSON', false)\n .action(async (opts) => {\n if (!opts.json) {\n console.log(chalk.dim(`Watching ${opts.vault} (Ctrl+C to stop)...`));\n }\n try {\n const forge = getForge();\n const ac = new AbortController();\n\n // Wire SIGINT/SIGTERM to AbortSignal for clean shutdown\n const onSignal = () => { ac.abort(); };\n process.on('SIGINT', onSignal);\n process.on('SIGTERM', onSignal);\n\n const gen = forge.watch(opts.vault, {\n apyDropPercent: opts.apyDrop,\n tvlDropPercent: opts.tvlDrop,\n interval: opts.interval,\n maxIterations: opts.maxIterations,\n signal: ac.signal,\n });\n\n for await (const event of gen) {\n if (opts.json) {\n console.log(JSON.stringify({\n type: event.type,\n vault: event.vault.slug,\n previous: event.previous,\n current: event.current,\n timestamp: event.timestamp.toISOString(),\n }));\n } else {\n const typeColor =\n event.type === 'apy-drop'\n ? chalk.red\n : event.type === 'tvl-drop'\n ? chalk.yellow\n : chalk.dim;\n\n const prevApy = event.previous ? fmtPct(event.previous.apy) : 'N/A';\n const prevTvl = event.previous ? fmtUsd(event.previous.tvlUsd) : 'N/A';\n console.log(\n `[${event.timestamp.toISOString()}] ${typeColor(event.type.toUpperCase())} ` +\n `APY: ${fmtPct(event.current.apy)} (prev: ${prevApy}) ` +\n `TVL: ${fmtUsd(event.current.tvlUsd)} (prev: ${prevTvl})`,\n );\n }\n }\n } catch (err) {\n console.error(chalk.red(err instanceof Error ? err.message : String(err)));\n process.exitCode = 1;\n }\n });\n\n// ── chains ──\n\nprogram\n .command('chains')\n .description('List supported chains')\n .option('--json', 'Output as JSON', false)\n .action(async (opts) => {\n const spinner = ora('Fetching chains...').start();\n try {\n const forge = getForge();\n const chains = await forge.chains.list();\n spinner.stop();\n\n outputResult(chains, opts.json, () =>\n `${chalk.bold('Supported Chains')}\\n\\n${chainTable(chains)}`,\n );\n } catch (err) {\n spinner.fail('Failed to fetch chains');\n console.error(chalk.red(err instanceof Error ? err.message : String(err)));\n process.exitCode = 1;\n }\n });\n\n// ── protocols ──\n\nprogram\n .command('protocols')\n .description('List supported protocols')\n .option('--json', 'Output as JSON', false)\n .action(async (opts) => {\n const spinner = ora('Fetching protocols...').start();\n try {\n const forge = getForge();\n const protocols = await forge.protocols.list();\n spinner.stop();\n\n outputResult(protocols, opts.json, () =>\n `${chalk.bold('Supported Protocols')}\\n\\n${protocolTable(protocols)}`,\n );\n } catch (err) {\n spinner.fail('Failed to fetch protocols');\n console.error(chalk.red(err instanceof Error ? err.message : String(err)));\n process.exitCode = 1;\n }\n });\n\n// ── init ──\n\nprogram\n .command('init')\n .argument('<name>', 'Project name')\n .description('Scaffold a new Next.js + wagmi + @earnforge/react project')\n .action(async (name: string) => {\n const fs = await import('node:fs');\n const path = await import('node:path');\n const dir = path.resolve(process.cwd(), name);\n\n if (fs.existsSync(dir)) {\n console.error(chalk.red(`Directory \"${name}\" already exists.`));\n process.exitCode = 1;\n return;\n }\n\n fs.mkdirSync(dir, { recursive: true });\n fs.mkdirSync(path.join(dir, 'src'), { recursive: true });\n\n fs.writeFileSync(\n path.join(dir, 'package.json'),\n JSON.stringify(\n {\n name,\n version: '0.1.0',\n private: true,\n type: 'module',\n scripts: { dev: 'next dev', build: 'next build', start: 'next start' },\n dependencies: {\n '@earnforge/sdk': '^0.1.0',\n '@earnforge/react': '^0.1.0',\n '@tanstack/react-query': '^5.90.0',\n next: '^15.0.0',\n react: '^19.0.0',\n 'react-dom': '^19.0.0',\n wagmi: '^2.0.0',\n viem: '^2.47.0',\n },\n },\n null,\n 2,\n ),\n );\n\n fs.writeFileSync(\n path.join(dir, '.env.example'),\n 'LIFI_API_KEY=your-api-key-from-portal.li.fi\\n',\n );\n\n fs.writeFileSync(\n path.join(dir, 'src', 'page.tsx'),\n `// SPDX-License-Identifier: Apache-2.0\nimport { createEarnForge } from '@earnforge/sdk';\n\nconst forge = createEarnForge({\n composerApiKey: process.env.LIFI_API_KEY,\n});\n\nexport default async function Home() {\n const top = await forge.vaults.top({ asset: 'USDC', limit: 5 });\n return (\n <main>\n <h1>Top USDC Vaults</h1>\n <ul>\n {top.map((v) => (\n <li key={v.slug}>\n {v.name} — {v.analytics.apy.total.toFixed(2)}% APY\n </li>\n ))}\n </ul>\n </main>\n );\n}\n`,\n );\n\n console.log(chalk.green(`\\n Scaffolded ${chalk.bold(name)}!\\n`));\n console.log(` ${chalk.dim('cd')} ${name}`);\n console.log(` ${chalk.dim('cp')} .env.example .env.local`);\n console.log(` ${chalk.dim('npm install')}`);\n console.log(` ${chalk.dim('npm run dev')}\\n`);\n });\n\n// ── simulate ──\n\nprogram\n .command('simulate')\n .description('Dry-run a deposit quote against an anvil fork (requires anvil)')\n .requiredOption('--vault <slug>', 'Vault slug')\n .requiredOption('--amount <human>', 'Deposit amount (human-readable)')\n .requiredOption('--wallet <addr>', 'Wallet address')\n .option('--rpc <url>', 'Custom RPC URL (default: auto-detect)')\n .option('--json', 'JSON output')\n .action(async (opts: { vault: string; amount: string; wallet: string; rpc?: string; json?: boolean }) => {\n const spinner = ora('Running preflight checks...').start();\n try {\n const forge = getForge();\n const vault = await forge.vaults.get(opts.vault);\n\n // Run preflight checks before building quote\n const pre = forge.preflight(vault, opts.wallet, { depositAmount: opts.amount });\n if (!pre.ok) {\n spinner.fail('Preflight failed');\n const errors = pre.issues.filter((i) => i.severity === 'error');\n for (const e of errors) {\n console.error(chalk.red(` [${e.code}] ${e.message}`));\n }\n process.exitCode = 1;\n return;\n }\n // Show warnings even if ok\n const warnings = pre.issues.filter((i) => i.severity === 'warning');\n for (const w of warnings) {\n console.warn(chalk.yellow(` [${w.code}] ${w.message}`));\n }\n\n spinner.text = 'Building quote for simulation...';\n const result = await forge.buildDepositQuote(vault, {\n fromAmount: opts.amount,\n wallet: opts.wallet,\n });\n\n spinner.text = 'Simulating on anvil fork...';\n\n const txReq = result.quote.transactionRequest;\n const rpcUrl = opts.rpc ?? `https://rpc.li.fi/v1/chain/${vault.chainId}`;\n\n // Use a simple eth_call simulation\n const simResult = await globalThis.fetch(rpcUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n jsonrpc: '2.0',\n method: 'eth_call',\n params: [\n {\n from: opts.wallet,\n to: txReq.to,\n data: txReq.data,\n value: txReq.value,\n gas: txReq.gasLimit,\n },\n 'latest',\n ],\n id: 1,\n }),\n });\n\n const sim = (await simResult.json()) as { result?: string; error?: { message: string } };\n spinner.stop();\n\n const simData = {\n vault: vault.slug,\n amount: opts.amount,\n decimals: result.decimals,\n rawAmount: result.rawAmount,\n gasLimit: txReq.gasLimit,\n to: txReq.to,\n chainId: txReq.chainId,\n simulation: sim.error ? 'FAILED' : 'SUCCESS',\n error: sim.error?.message,\n };\n\n outputResult(simData, opts.json, () => {\n const status = sim.error\n ? chalk.red('FAILED: ' + sim.error.message)\n : chalk.green('SUCCESS — transaction would execute');\n return [\n chalk.bold('Simulation Result'),\n '',\n ` Vault: ${vault.name} (${vault.slug})`,\n ` Amount: ${opts.amount} (${result.rawAmount} raw)`,\n ` Gas Limit: ${txReq.gasLimit}`,\n ` Target: ${txReq.to}`,\n ` Chain: ${txReq.chainId}`,\n '',\n ` Status: ${status}`,\n ].join('\\n');\n });\n } catch (err) {\n spinner.fail('Simulation failed');\n console.error(chalk.red(err instanceof Error ? err.message : String(err)));\n process.exitCode = 1;\n }\n });\n"],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "@earnforge/cli",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "license": "Apache-2.0",
6
+ "description": "CLI for the LI.FI Earn API — vault discovery, risk scoring, deposit quoting, and the 18-pitfall doctor",
7
+ "bin": {
8
+ "earnforge": "./dist/esm/bin.js"
9
+ },
10
+ "exports": {
11
+ ".": {
12
+ "import": "./dist/esm/index.js",
13
+ "types": "./dist/esm/index.d.ts"
14
+ }
15
+ },
16
+ "files": ["dist", "README.md", "LICENSE"],
17
+ "scripts": {
18
+ "build": "tsdown src/bin.ts src/index.ts --format esm --dts --out-dir dist/esm",
19
+ "typecheck": "tsc --noEmit",
20
+ "test": "vitest run",
21
+ "test:unit": "vitest run",
22
+ "clean": "rm -rf dist .turbo"
23
+ },
24
+ "dependencies": {
25
+ "@earnforge/sdk": "workspace:*",
26
+ "commander": "^14.0.0",
27
+ "chalk": "^5.4.1",
28
+ "cli-table3": "^0.6.5",
29
+ "ora": "^8.2.0"
30
+ },
31
+ "devDependencies": {
32
+ "tsdown": "^0.21.7",
33
+ "typescript": "^5.9.3",
34
+ "vitest": "^4.1.4"
35
+ }
36
+ }