httpcat-cli 0.3.0 → 0.3.1
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.
- package/.github/workflows/ci.yml +3 -0
- package/.github/workflows/rc-publish.yml +6 -0
- package/.github/workflows/release.yml +102 -0
- package/.github/workflows/sync-version.yml +31 -2
- package/README.md +1408 -109
- package/additions.txt +3 -0
- package/bun.lock +260 -25
- package/dist/agent/autonomous-trader.d.ts.map +1 -0
- package/dist/agent/autonomous-trader.js +362 -0
- package/dist/agent/autonomous-trader.js.map +1 -0
- package/dist/agent/ax-agent.d.ts.map +1 -1
- package/dist/agent/ax-agent.js +356 -18
- package/dist/agent/ax-agent.js.map +1 -1
- package/dist/agent/event-client.d.ts.map +1 -0
- package/dist/agent/event-client.js +82 -0
- package/dist/agent/event-client.js.map +1 -0
- package/dist/agent/log-stream.d.ts.map +1 -0
- package/dist/agent/log-stream.js +95 -0
- package/dist/agent/log-stream.js.map +1 -0
- package/dist/agent/memory/conversation-session.d.ts.map +1 -0
- package/dist/agent/memory/conversation-session.js +232 -0
- package/dist/agent/memory/conversation-session.js.map +1 -0
- package/dist/agent/memory/conversation-store.d.ts.map +1 -0
- package/dist/agent/memory/conversation-store.js +214 -0
- package/dist/agent/memory/conversation-store.js.map +1 -0
- package/dist/agent/memory/database-schema.d.ts.map +1 -0
- package/dist/agent/memory/database-schema.js +355 -0
- package/dist/agent/memory/database-schema.js.map +1 -0
- package/dist/agent/memory/decision-tracker.d.ts.map +1 -0
- package/dist/agent/memory/decision-tracker.js +274 -0
- package/dist/agent/memory/decision-tracker.js.map +1 -0
- package/dist/agent/memory/memory-manager.d.ts.map +1 -0
- package/dist/agent/memory/memory-manager.js +187 -0
- package/dist/agent/memory/memory-manager.js.map +1 -0
- package/dist/agent/memory/types.d.ts.map +1 -0
- package/dist/agent/memory/types.js +5 -0
- package/dist/agent/memory/types.js.map +1 -0
- package/dist/agent/message-formatter.d.ts.map +1 -0
- package/dist/agent/message-formatter.js +76 -0
- package/dist/agent/message-formatter.js.map +1 -0
- package/dist/agent/position-db.d.ts.map +1 -0
- package/dist/agent/position-db.js +154 -0
- package/dist/agent/position-db.js.map +1 -0
- package/dist/agent/simple-chat-ui-static.d.ts.map +1 -0
- package/dist/agent/simple-chat-ui-static.js +129 -0
- package/dist/agent/simple-chat-ui-static.js.map +1 -0
- package/dist/agent/simple-chat-ui.d.ts.map +1 -0
- package/dist/agent/simple-chat-ui.js +90 -0
- package/dist/agent/simple-chat-ui.js.map +1 -0
- package/dist/agent/tools.d.ts.map +1 -1
- package/dist/agent/tools.js +297 -4
- package/dist/agent/tools.js.map +1 -1
- package/dist/agent/ui.d.ts.map +1 -0
- package/dist/agent/ui.js +84 -0
- package/dist/agent/ui.js.map +1 -0
- package/dist/agent/unified-runtime.d.ts.map +1 -0
- package/dist/agent/unified-runtime.js +397 -0
- package/dist/agent/unified-runtime.js.map +1 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +272 -21
- package/dist/client.js.map +1 -1
- package/dist/commands/account.d.ts.map +1 -1
- package/dist/commands/account.js +187 -33
- package/dist/commands/account.js.map +1 -1
- package/dist/commands/agent.d.ts.map +1 -0
- package/dist/commands/agent.js +125 -0
- package/dist/commands/agent.js.map +1 -0
- package/dist/commands/approve.d.ts.map +1 -0
- package/dist/commands/approve.js +505 -0
- package/dist/commands/approve.js.map +1 -0
- package/dist/commands/automation.d.ts.map +1 -0
- package/dist/commands/automation.js +346 -0
- package/dist/commands/automation.js.map +1 -0
- package/dist/commands/balances.d.ts.map +1 -1
- package/dist/commands/balances.js +226 -73
- package/dist/commands/balances.js.map +1 -1
- package/dist/commands/buy.d.ts.map +1 -1
- package/dist/commands/buy.js +149 -146
- package/dist/commands/buy.js.map +1 -1
- package/dist/commands/call.d.ts.map +1 -0
- package/dist/commands/call.js +51 -0
- package/dist/commands/call.js.map +1 -0
- package/dist/commands/cex.d.ts.map +1 -0
- package/dist/commands/cex.js +958 -0
- package/dist/commands/cex.js.map +1 -0
- package/dist/commands/chat.d.ts.map +1 -1
- package/dist/commands/chat.js +169 -411
- package/dist/commands/chat.js.map +1 -1
- package/dist/commands/claim.d.ts.map +1 -1
- package/dist/commands/claim.js +313 -29
- package/dist/commands/claim.js.map +1 -1
- package/dist/commands/create.d.ts.map +1 -1
- package/dist/commands/create.js +151 -43
- package/dist/commands/create.js.map +1 -1
- package/dist/commands/gasless-swap.d.ts.map +1 -0
- package/dist/commands/gasless-swap.js +232 -0
- package/dist/commands/gasless-swap.js.map +1 -0
- package/dist/commands/health.d.ts.map +1 -1
- package/dist/commands/health.js +63 -7
- package/dist/commands/health.js.map +1 -1
- package/dist/commands/info.d.ts.map +1 -1
- package/dist/commands/info.js +131 -47
- package/dist/commands/info.js.map +1 -1
- package/dist/commands/launchpad.d.ts.map +1 -0
- package/dist/commands/launchpad.js +708 -0
- package/dist/commands/launchpad.js.map +1 -0
- package/dist/commands/list.d.ts.map +1 -1
- package/dist/commands/list.js +57 -23
- package/dist/commands/list.js.map +1 -1
- package/dist/commands/market.d.ts.map +1 -0
- package/dist/commands/market.js +960 -0
- package/dist/commands/market.js.map +1 -0
- package/dist/commands/mcp-install.d.ts.map +1 -0
- package/dist/commands/mcp-install.js +387 -0
- package/dist/commands/mcp-install.js.map +1 -0
- package/dist/commands/opps.d.ts.map +1 -0
- package/dist/commands/opps.js +409 -0
- package/dist/commands/opps.js.map +1 -0
- package/dist/commands/perps.d.ts.map +1 -0
- package/dist/commands/perps.js +248 -0
- package/dist/commands/perps.js.map +1 -0
- package/dist/commands/portfolio.d.ts.map +1 -0
- package/dist/commands/portfolio.js +679 -0
- package/dist/commands/portfolio.js.map +1 -0
- package/dist/commands/positions.d.ts.map +1 -1
- package/dist/commands/positions.js +76 -47
- package/dist/commands/positions.js.map +1 -1
- package/dist/commands/predict.d.ts.map +1 -0
- package/dist/commands/predict.js +280 -0
- package/dist/commands/predict.js.map +1 -0
- package/dist/commands/predictions.d.ts.map +1 -0
- package/dist/commands/predictions.js +486 -0
- package/dist/commands/predictions.js.map +1 -0
- package/dist/commands/risk.d.ts.map +1 -0
- package/dist/commands/risk.js +225 -0
- package/dist/commands/risk.js.map +1 -0
- package/dist/commands/security.d.ts.map +1 -0
- package/dist/commands/security.js +244 -0
- package/dist/commands/security.js.map +1 -0
- package/dist/commands/sell.d.ts.map +1 -1
- package/dist/commands/sell.js +67 -34
- package/dist/commands/sell.js.map +1 -1
- package/dist/commands/send.d.ts.map +1 -0
- package/dist/commands/send.js +733 -0
- package/dist/commands/send.js.map +1 -0
- package/dist/commands/sign.d.ts.map +1 -0
- package/dist/commands/sign.js +1048 -0
- package/dist/commands/sign.js.map +1 -0
- package/dist/commands/swap.d.ts.map +1 -0
- package/dist/commands/swap.js +744 -0
- package/dist/commands/swap.js.map +1 -0
- package/dist/commands/system.d.ts.map +1 -0
- package/dist/commands/system.js +417 -0
- package/dist/commands/system.js.map +1 -0
- package/dist/commands/tools/index.d.ts.map +1 -0
- package/dist/commands/tools/index.js +2040 -0
- package/dist/commands/tools/index.js.map +1 -0
- package/dist/commands/trade.d.ts.map +1 -0
- package/dist/commands/trade.js +237 -0
- package/dist/commands/trade.js.map +1 -0
- package/dist/commands/transactions.d.ts.map +1 -1
- package/dist/commands/transactions.js +29 -17
- package/dist/commands/transactions.js.map +1 -1
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +429 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +351 -40
- package/dist/config.js.map +1 -1
- package/dist/index.js +4524 -924
- package/dist/index.js.map +1 -1
- package/dist/interactive/art.d.ts.map +1 -1
- package/dist/interactive/art.js +33 -1
- package/dist/interactive/art.js.map +1 -1
- package/dist/interactive/shell.d.ts.map +1 -1
- package/dist/interactive/shell.js +467 -2652
- package/dist/interactive/shell.js.map +1 -1
- package/dist/mcp/context.d.ts.map +1 -0
- package/dist/mcp/context.js +211 -0
- package/dist/mcp/context.js.map +1 -0
- package/dist/mcp/onboarding.d.ts.map +1 -0
- package/dist/mcp/onboarding.js +266 -0
- package/dist/mcp/onboarding.js.map +1 -0
- package/dist/mcp/resources.d.ts.map +1 -0
- package/dist/mcp/resources.js +222 -0
- package/dist/mcp/resources.js.map +1 -0
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +51 -1
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +4119 -169
- package/dist/mcp/tools.js.map +1 -1
- package/dist/mcp/types.d.ts.map +1 -1
- package/dist/types/agent-info.d.ts.map +1 -0
- package/dist/types/agent-info.js +11 -0
- package/dist/types/agent-info.js.map +1 -0
- package/dist/ui/components/ScrollableList.d.ts.map +1 -0
- package/dist/ui/components/ScrollableList.js +72 -0
- package/dist/ui/components/ScrollableList.js.map +1 -0
- package/dist/ui/components/ThemeProvider.d.ts.map +1 -0
- package/dist/ui/components/ThemeProvider.js +87 -0
- package/dist/ui/components/ThemeProvider.js.map +1 -0
- package/dist/ui/components/ThemedBox.d.ts.map +1 -0
- package/dist/ui/components/ThemedBox.js +24 -0
- package/dist/ui/components/ThemedBox.js.map +1 -0
- package/dist/ui/components/agent/ChatHeader.d.ts.map +1 -0
- package/dist/ui/components/agent/ChatHeader.js +39 -0
- package/dist/ui/components/agent/ChatHeader.js.map +1 -0
- package/dist/ui/components/agent/Header.d.ts.map +1 -0
- package/dist/ui/components/agent/Header.js +14 -0
- package/dist/ui/components/agent/Header.js.map +1 -0
- package/dist/ui/components/agent/Input.d.ts.map +1 -0
- package/dist/ui/components/agent/Input.js +23 -0
- package/dist/ui/components/agent/Input.js.map +1 -0
- package/dist/ui/components/agent/Output.d.ts.map +1 -0
- package/dist/ui/components/agent/Output.js +23 -0
- package/dist/ui/components/agent/Output.js.map +1 -0
- package/dist/ui/components/chat/TokenChatUI.d.ts.map +1 -0
- package/dist/ui/components/chat/TokenChatUI.js +133 -0
- package/dist/ui/components/chat/TokenChatUI.js.map +1 -0
- package/dist/ui/components/shell/ShellHeader.d.ts.map +1 -0
- package/dist/ui/components/shell/ShellHeader.js +31 -0
- package/dist/ui/components/shell/ShellHeader.js.map +1 -0
- package/dist/ui/components/shell/ShellInput.d.ts.map +1 -0
- package/dist/ui/components/shell/ShellInput.js +151 -0
- package/dist/ui/components/shell/ShellInput.js.map +1 -0
- package/dist/ui/components/shell/ShellOutput.d.ts.map +1 -0
- package/dist/ui/components/shell/ShellOutput.js +8 -0
- package/dist/ui/components/shell/ShellOutput.js.map +1 -0
- package/dist/ui/hooks/useChatWebSocket.d.ts.map +1 -0
- package/dist/ui/hooks/useChatWebSocket.js +76 -0
- package/dist/ui/hooks/useChatWebSocket.js.map +1 -0
- package/dist/ui/hooks/useCommandHistory.d.ts.map +1 -0
- package/dist/ui/hooks/useCommandHistory.js +70 -0
- package/dist/ui/hooks/useCommandHistory.js.map +1 -0
- package/dist/ui/hooks/useDebounce.d.ts.map +1 -0
- package/dist/ui/hooks/useDebounce.js +17 -0
- package/dist/ui/hooks/useDebounce.js.map +1 -0
- package/dist/ui/hooks/useLogStream.d.ts.map +1 -0
- package/dist/ui/hooks/useLogStream.js +20 -0
- package/dist/ui/hooks/useLogStream.js.map +1 -0
- package/dist/ui/hooks/useVirtualScroll.d.ts.map +1 -0
- package/dist/ui/hooks/useVirtualScroll.js +70 -0
- package/dist/ui/hooks/useVirtualScroll.js.map +1 -0
- package/dist/utils/admin.d.ts.map +1 -0
- package/dist/utils/admin.js +144 -0
- package/dist/utils/admin.js.map +1 -0
- package/dist/utils/autoSetup.d.ts.map +1 -0
- package/dist/utils/autoSetup.js +252 -0
- package/dist/utils/autoSetup.js.map +1 -0
- package/dist/utils/build-constants.d.ts.map +1 -0
- package/dist/utils/build-constants.js +10 -0
- package/dist/utils/build-constants.js.map +1 -0
- package/dist/utils/constants.d.ts.map +1 -1
- package/dist/utils/errors.d.ts.map +1 -1
- package/dist/utils/errors.js +10 -1
- package/dist/utils/errors.js.map +1 -1
- package/dist/utils/formatting.d.ts.map +1 -1
- package/dist/utils/formatting.js +46 -9
- package/dist/utils/formatting.js.map +1 -1
- package/dist/utils/llm-cli-config.d.ts.map +1 -0
- package/dist/utils/llm-cli-config.js +963 -0
- package/dist/utils/llm-cli-config.js.map +1 -0
- package/dist/utils/llm-cli-detector.d.ts.map +1 -0
- package/dist/utils/llm-cli-detector.js +202 -0
- package/dist/utils/llm-cli-detector.js.map +1 -0
- package/dist/utils/loading.d.ts.map +1 -1
- package/dist/utils/loading.js +25 -3
- package/dist/utils/loading.js.map +1 -1
- package/dist/utils/maintenance.d.ts.map +1 -0
- package/dist/utils/maintenance.js +17 -0
- package/dist/utils/maintenance.js.map +1 -0
- package/dist/utils/mcp-config.d.ts.map +1 -0
- package/dist/utils/mcp-config.js +77 -0
- package/dist/utils/mcp-config.js.map +1 -0
- package/dist/utils/privateKeyPrompt.d.ts.map +1 -1
- package/dist/utils/privateKeyPrompt.js +308 -129
- package/dist/utils/privateKeyPrompt.js.map +1 -1
- package/dist/utils/process-cleanup.d.ts.map +1 -0
- package/dist/utils/process-cleanup.js +136 -0
- package/dist/utils/process-cleanup.js.map +1 -0
- package/dist/utils/retry.d.ts.map +1 -0
- package/dist/utils/retry.js +56 -0
- package/dist/utils/retry.js.map +1 -0
- package/dist/utils/rpc-helpers.d.ts.map +1 -0
- package/dist/utils/rpc-helpers.js +70 -0
- package/dist/utils/rpc-helpers.js.map +1 -0
- package/dist/utils/rpc-transport.d.ts.map +1 -0
- package/dist/utils/rpc-transport.js +87 -0
- package/dist/utils/rpc-transport.js.map +1 -0
- package/dist/utils/shell-setup.d.ts.map +1 -0
- package/dist/utils/shell-setup.js +531 -0
- package/dist/utils/shell-setup.js.map +1 -0
- package/dist/utils/status.d.ts.map +1 -1
- package/dist/utils/status.js +34 -5
- package/dist/utils/status.js.map +1 -1
- package/dist/utils/token-resolver.d.ts.map +1 -1
- package/dist/utils/token-resolver.js +51 -8
- package/dist/utils/token-resolver.js.map +1 -1
- package/dist/utils/x402-caller.d.ts.map +1 -0
- package/dist/utils/x402-caller.js +17 -0
- package/dist/utils/x402-caller.js.map +1 -0
- package/docs/README.md +28 -0
- package/docs/agent/README.md +18 -0
- package/docs/api/README.md +41 -0
- package/docs/cli/README.md +42 -0
- package/docs/guides/README.md +26 -0
- package/docs/implementation/README.md +18 -0
- package/docs/planning/README.md +19 -0
- package/docs/testing/README.md +15 -0
- package/docs/ux/README.md +16 -0
- package/issues.txt +2 -0
- package/package.json +24 -9
- package/scripts/cat-spin.sh +417 -0
- package/scripts/deprecate-rc-versions.js +58 -0
- package/scripts/inject-build-constants.js +43 -0
- package/scripts/monitor-foobar.js +117 -0
- package/swap.logs +61 -0
- package/swapping.txt +108 -0
- package/test.txt +12 -0
- package/tests/fixtures/test-data.json +16 -0
- package/Screenshot 2025-12-21 at 8.56.02/342/200/257PM.png +0 -0
|
@@ -0,0 +1,679 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { HttpcatClient } from "../client.js";
|
|
3
|
+
import { config } from "../config.js";
|
|
4
|
+
import { privateKeyToAccount } from "viem/accounts";
|
|
5
|
+
// Import command functions
|
|
6
|
+
import { checkBalance, displayBalance } from "./balances.js";
|
|
7
|
+
import { getPositions, displayPositions } from "./positions.js";
|
|
8
|
+
import { getTransactions, displayTransactions } from "./transactions.js";
|
|
9
|
+
// Import utilities
|
|
10
|
+
import { withLoading } from "../utils/loading.js";
|
|
11
|
+
import { outputJson, outputError } from "../headless/json-output.js";
|
|
12
|
+
import { handleError, getExitCode } from "../utils/errors.js";
|
|
13
|
+
import { promptForPrivateKey } from "../utils/privateKeyPrompt.js";
|
|
14
|
+
// ============================================================================
|
|
15
|
+
// Shared Utilities (duplicated from index.ts to avoid circular dependencies)
|
|
16
|
+
// ============================================================================
|
|
17
|
+
function getPrivateKey(cliPrivateKey, accountIndex) {
|
|
18
|
+
if (cliPrivateKey)
|
|
19
|
+
return cliPrivateKey;
|
|
20
|
+
const envKey = process.env.HTTPCAT_PRIVATE_KEY;
|
|
21
|
+
if (envKey)
|
|
22
|
+
return envKey;
|
|
23
|
+
// Use account system
|
|
24
|
+
try {
|
|
25
|
+
const index = accountIndex !== undefined
|
|
26
|
+
? accountIndex
|
|
27
|
+
: config.getActiveAccountIndex();
|
|
28
|
+
return config.getAccountPrivateKey(index);
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
// Fall back to legacy format if account system not set up
|
|
32
|
+
return config.get("privateKey");
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function isConfigured(cliPrivateKey) {
|
|
36
|
+
if (cliPrivateKey)
|
|
37
|
+
return true;
|
|
38
|
+
return config.isConfigured();
|
|
39
|
+
}
|
|
40
|
+
async function ensureWalletUnlocked() {
|
|
41
|
+
const password = config.getPassword();
|
|
42
|
+
if (!password) {
|
|
43
|
+
// No password required - ensure session is initialized
|
|
44
|
+
config.ensureSessionValid();
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
if (!config.isSessionValid()) {
|
|
48
|
+
// Need to prompt for password
|
|
49
|
+
const inquirer = (await import("inquirer")).default;
|
|
50
|
+
const answers = await inquirer.prompt([
|
|
51
|
+
{
|
|
52
|
+
type: "password",
|
|
53
|
+
name: "password",
|
|
54
|
+
message: "Enter password to unlock wallet:",
|
|
55
|
+
mask: "•",
|
|
56
|
+
},
|
|
57
|
+
]);
|
|
58
|
+
await config.unlockSession(answers.password);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
// ============================================================================
|
|
62
|
+
// Portfolio Command Group
|
|
63
|
+
// ============================================================================
|
|
64
|
+
export function createPortfolioCommand() {
|
|
65
|
+
const portfolioCommand = new Command("portfolio")
|
|
66
|
+
.description("Portfolio & history management")
|
|
67
|
+
.addHelpText("after", `
|
|
68
|
+
Examples:
|
|
69
|
+
httpcat portfolio balances
|
|
70
|
+
httpcat portfolio positions
|
|
71
|
+
httpcat portfolio transactions
|
|
72
|
+
`);
|
|
73
|
+
// Balances subcommand
|
|
74
|
+
portfolioCommand
|
|
75
|
+
.command("balances")
|
|
76
|
+
.alias("bal")
|
|
77
|
+
.description("Check wallet balances (FREE)")
|
|
78
|
+
.addHelpText("after", `
|
|
79
|
+
Examples:
|
|
80
|
+
httpcat portfolio balances
|
|
81
|
+
httpcat portfolio balances --json
|
|
82
|
+
`)
|
|
83
|
+
.action(async (options, command) => {
|
|
84
|
+
try {
|
|
85
|
+
const globalOpts = command.parent?.parent?.opts() || {};
|
|
86
|
+
const accountIndex = globalOpts.account;
|
|
87
|
+
await ensureWalletUnlocked();
|
|
88
|
+
let privateKey = getPrivateKey(globalOpts.privateKey, accountIndex);
|
|
89
|
+
if (!isConfigured(globalOpts.privateKey)) {
|
|
90
|
+
if (globalOpts.json) {
|
|
91
|
+
console.error('❌ Not configured. Run "httpcat config" first or use --private-key flag.');
|
|
92
|
+
process.exit(2);
|
|
93
|
+
}
|
|
94
|
+
privateKey = await promptForPrivateKey();
|
|
95
|
+
}
|
|
96
|
+
const silent = globalOpts.json || globalOpts.quiet;
|
|
97
|
+
const result = await withLoading(() => checkBalance(privateKey, silent), {
|
|
98
|
+
message: "Fetching balances...",
|
|
99
|
+
json: globalOpts.json,
|
|
100
|
+
quiet: globalOpts.quiet,
|
|
101
|
+
spinner: "cat",
|
|
102
|
+
clearOnSuccess: true,
|
|
103
|
+
});
|
|
104
|
+
if (globalOpts.json) {
|
|
105
|
+
outputJson("balances", result);
|
|
106
|
+
}
|
|
107
|
+
else if (!globalOpts.quiet) {
|
|
108
|
+
displayBalance(result);
|
|
109
|
+
}
|
|
110
|
+
process.exit(0);
|
|
111
|
+
}
|
|
112
|
+
catch (error) {
|
|
113
|
+
const globalOpts = command.parent?.parent?.opts() || {};
|
|
114
|
+
if (globalOpts.json) {
|
|
115
|
+
outputError("balances", error, getExitCode(error));
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
handleError(error, globalOpts.verbose);
|
|
119
|
+
}
|
|
120
|
+
process.exit(getExitCode(error));
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
// Positions subcommand
|
|
124
|
+
portfolioCommand
|
|
125
|
+
.command("positions")
|
|
126
|
+
.alias("pos")
|
|
127
|
+
.description("Get all positions across products (FREE)")
|
|
128
|
+
.option("--active", "Show only active (non-graduated) positions")
|
|
129
|
+
.option("--graduated", "Show only graduated positions")
|
|
130
|
+
.addHelpText("after", `
|
|
131
|
+
Examples:
|
|
132
|
+
httpcat portfolio positions
|
|
133
|
+
httpcat portfolio positions --active
|
|
134
|
+
httpcat portfolio positions --graduated
|
|
135
|
+
`)
|
|
136
|
+
.action(async (options, command) => {
|
|
137
|
+
try {
|
|
138
|
+
const globalOpts = command.parent?.parent?.opts() || {};
|
|
139
|
+
const accountIndex = globalOpts.account;
|
|
140
|
+
await ensureWalletUnlocked();
|
|
141
|
+
let privateKey = getPrivateKey(globalOpts.privateKey, accountIndex);
|
|
142
|
+
if (!isConfigured(globalOpts.privateKey)) {
|
|
143
|
+
if (globalOpts.json) {
|
|
144
|
+
console.error('❌ Not configured. Run "httpcat config" first or use --private-key flag.');
|
|
145
|
+
process.exit(2);
|
|
146
|
+
}
|
|
147
|
+
privateKey = await promptForPrivateKey();
|
|
148
|
+
}
|
|
149
|
+
const client = await HttpcatClient.create(privateKey);
|
|
150
|
+
// Derive user address from private key
|
|
151
|
+
const account = privateKeyToAccount(privateKey);
|
|
152
|
+
const userAddress = account.address;
|
|
153
|
+
let result = await withLoading(() => getPositions(client, userAddress), {
|
|
154
|
+
message: "Fetching positions...",
|
|
155
|
+
json: globalOpts.json,
|
|
156
|
+
quiet: globalOpts.quiet,
|
|
157
|
+
spinner: "cat",
|
|
158
|
+
clearOnSuccess: true,
|
|
159
|
+
});
|
|
160
|
+
// Determine filter
|
|
161
|
+
const filter = options.active
|
|
162
|
+
? "active"
|
|
163
|
+
: options.graduated
|
|
164
|
+
? "graduated"
|
|
165
|
+
: "all";
|
|
166
|
+
// Filter results for JSON output
|
|
167
|
+
if (globalOpts.json && filter !== "all") {
|
|
168
|
+
const filteredPositions = result.positions.filter((p) => filter === "active"
|
|
169
|
+
? p.token.status !== "graduated"
|
|
170
|
+
: p.token.status === "graduated");
|
|
171
|
+
result = {
|
|
172
|
+
...result,
|
|
173
|
+
positions: filteredPositions,
|
|
174
|
+
total: filteredPositions.length,
|
|
175
|
+
};
|
|
176
|
+
outputJson("positions", result);
|
|
177
|
+
}
|
|
178
|
+
else if (globalOpts.json) {
|
|
179
|
+
outputJson("positions", result);
|
|
180
|
+
}
|
|
181
|
+
else if (!globalOpts.quiet) {
|
|
182
|
+
displayPositions(result, filter);
|
|
183
|
+
}
|
|
184
|
+
process.exit(0);
|
|
185
|
+
}
|
|
186
|
+
catch (error) {
|
|
187
|
+
const globalOpts = command.parent?.parent?.opts() || {};
|
|
188
|
+
if (globalOpts.json) {
|
|
189
|
+
outputError("positions", error, getExitCode(error));
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
handleError(error, globalOpts.verbose);
|
|
193
|
+
}
|
|
194
|
+
process.exit(getExitCode(error));
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
// Summary subcommand
|
|
198
|
+
portfolioCommand
|
|
199
|
+
.command("summary")
|
|
200
|
+
.description("Get portfolio summary ($0.001)")
|
|
201
|
+
.option("--wallet <address>", "Wallet address (defaults to active account)")
|
|
202
|
+
.addHelpText("after", `
|
|
203
|
+
Examples:
|
|
204
|
+
httpcat portfolio summary
|
|
205
|
+
httpcat portfolio summary --wallet 0x...
|
|
206
|
+
httpcat portfolio summary --json
|
|
207
|
+
`)
|
|
208
|
+
.action(async (options, command) => {
|
|
209
|
+
try {
|
|
210
|
+
const globalOpts = command.parent?.parent?.opts() || {};
|
|
211
|
+
const accountIndex = globalOpts.account;
|
|
212
|
+
await ensureWalletUnlocked();
|
|
213
|
+
let privateKey = getPrivateKey(globalOpts.privateKey, accountIndex);
|
|
214
|
+
if (!isConfigured(globalOpts.privateKey)) {
|
|
215
|
+
if (globalOpts.json) {
|
|
216
|
+
console.error('❌ Not configured. Run "httpcat config" first or use --private-key flag.');
|
|
217
|
+
process.exit(2);
|
|
218
|
+
}
|
|
219
|
+
privateKey = await promptForPrivateKey();
|
|
220
|
+
}
|
|
221
|
+
const client = await HttpcatClient.create(privateKey);
|
|
222
|
+
// Derive wallet address if not provided
|
|
223
|
+
let walletAddress = options.wallet;
|
|
224
|
+
if (!walletAddress) {
|
|
225
|
+
const account = privateKeyToAccount(privateKey);
|
|
226
|
+
walletAddress = account.address;
|
|
227
|
+
}
|
|
228
|
+
const result = await withLoading(async () => {
|
|
229
|
+
try {
|
|
230
|
+
const data = await client.get(`/portfolio/summary?wallet=${walletAddress}`);
|
|
231
|
+
return data.output || data;
|
|
232
|
+
}
|
|
233
|
+
catch {
|
|
234
|
+
const { data } = await client.invoke("portfolio/summary", {
|
|
235
|
+
wallet: walletAddress,
|
|
236
|
+
});
|
|
237
|
+
return data;
|
|
238
|
+
}
|
|
239
|
+
}, {
|
|
240
|
+
message: "Fetching portfolio summary...",
|
|
241
|
+
json: globalOpts.json,
|
|
242
|
+
quiet: globalOpts.quiet,
|
|
243
|
+
spinner: "cat",
|
|
244
|
+
clearOnSuccess: true,
|
|
245
|
+
});
|
|
246
|
+
if (globalOpts.json) {
|
|
247
|
+
outputJson("summary", result);
|
|
248
|
+
}
|
|
249
|
+
else if (!globalOpts.quiet) {
|
|
250
|
+
displayPortfolioSummary(result);
|
|
251
|
+
}
|
|
252
|
+
process.exit(0);
|
|
253
|
+
}
|
|
254
|
+
catch (error) {
|
|
255
|
+
const globalOpts = command.parent?.parent?.opts() || {};
|
|
256
|
+
if (globalOpts.json) {
|
|
257
|
+
outputError("summary", error, getExitCode(error));
|
|
258
|
+
}
|
|
259
|
+
else {
|
|
260
|
+
handleError(error, globalOpts.verbose);
|
|
261
|
+
}
|
|
262
|
+
process.exit(getExitCode(error));
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
// PnL subcommand
|
|
266
|
+
portfolioCommand
|
|
267
|
+
.command("pnl")
|
|
268
|
+
.description("Get portfolio P&L ($0.001)")
|
|
269
|
+
.option("--wallet <address>", "Wallet address (defaults to active account)")
|
|
270
|
+
.option("--timeframe <timeframe>", "Timeframe: 1d, 7d, 30d, all (default: all)")
|
|
271
|
+
.addHelpText("after", `
|
|
272
|
+
Examples:
|
|
273
|
+
httpcat portfolio pnl
|
|
274
|
+
httpcat portfolio pnl --timeframe 7d
|
|
275
|
+
httpcat portfolio pnl --wallet 0x... --json
|
|
276
|
+
`)
|
|
277
|
+
.action(async (options, command) => {
|
|
278
|
+
try {
|
|
279
|
+
const globalOpts = command.parent?.parent?.opts() || {};
|
|
280
|
+
const accountIndex = globalOpts.account;
|
|
281
|
+
await ensureWalletUnlocked();
|
|
282
|
+
let privateKey = getPrivateKey(globalOpts.privateKey, accountIndex);
|
|
283
|
+
if (!isConfigured(globalOpts.privateKey)) {
|
|
284
|
+
if (globalOpts.json) {
|
|
285
|
+
console.error('❌ Not configured. Run "httpcat config" first or use --private-key flag.');
|
|
286
|
+
process.exit(2);
|
|
287
|
+
}
|
|
288
|
+
privateKey = await promptForPrivateKey();
|
|
289
|
+
}
|
|
290
|
+
const client = await HttpcatClient.create(privateKey);
|
|
291
|
+
// Derive wallet address if not provided
|
|
292
|
+
let walletAddress = options.wallet;
|
|
293
|
+
if (!walletAddress) {
|
|
294
|
+
const account = privateKeyToAccount(privateKey);
|
|
295
|
+
walletAddress = account.address;
|
|
296
|
+
}
|
|
297
|
+
const result = await withLoading(async () => {
|
|
298
|
+
const params = new URLSearchParams({
|
|
299
|
+
wallet: walletAddress,
|
|
300
|
+
});
|
|
301
|
+
if (options.timeframe) {
|
|
302
|
+
params.append("timeframe", options.timeframe);
|
|
303
|
+
}
|
|
304
|
+
try {
|
|
305
|
+
const data = await client.get(`/portfolio/pnl?${params.toString()}`);
|
|
306
|
+
return data.output || data;
|
|
307
|
+
}
|
|
308
|
+
catch {
|
|
309
|
+
const { data } = await client.invoke("portfolio/pnl", {
|
|
310
|
+
wallet: walletAddress,
|
|
311
|
+
timeframe: options.timeframe || "all",
|
|
312
|
+
});
|
|
313
|
+
return data;
|
|
314
|
+
}
|
|
315
|
+
}, {
|
|
316
|
+
message: "Fetching portfolio P&L...",
|
|
317
|
+
json: globalOpts.json,
|
|
318
|
+
quiet: globalOpts.quiet,
|
|
319
|
+
spinner: "cat",
|
|
320
|
+
clearOnSuccess: true,
|
|
321
|
+
});
|
|
322
|
+
if (globalOpts.json) {
|
|
323
|
+
outputJson("pnl", result);
|
|
324
|
+
}
|
|
325
|
+
else if (!globalOpts.quiet) {
|
|
326
|
+
displayPortfolioPnl(result);
|
|
327
|
+
}
|
|
328
|
+
process.exit(0);
|
|
329
|
+
}
|
|
330
|
+
catch (error) {
|
|
331
|
+
const globalOpts = command.parent?.parent?.opts() || {};
|
|
332
|
+
if (globalOpts.json) {
|
|
333
|
+
outputError("pnl", error, getExitCode(error));
|
|
334
|
+
}
|
|
335
|
+
else {
|
|
336
|
+
handleError(error, globalOpts.verbose);
|
|
337
|
+
}
|
|
338
|
+
process.exit(getExitCode(error));
|
|
339
|
+
}
|
|
340
|
+
});
|
|
341
|
+
// Trades subcommand
|
|
342
|
+
portfolioCommand
|
|
343
|
+
.command("trades")
|
|
344
|
+
.description("Get trade history ($0.001)")
|
|
345
|
+
.option("--wallet <address>", "Wallet address (defaults to active account)")
|
|
346
|
+
.option("--limit <number>", "Limit results (default: 50)", "50")
|
|
347
|
+
.option("--offset <number>", "Pagination offset (default: 0)", "0")
|
|
348
|
+
.addHelpText("after", `
|
|
349
|
+
Examples:
|
|
350
|
+
httpcat portfolio trades
|
|
351
|
+
httpcat portfolio trades --limit 100
|
|
352
|
+
httpcat portfolio trades --wallet 0x...
|
|
353
|
+
`)
|
|
354
|
+
.action(async (options, command) => {
|
|
355
|
+
try {
|
|
356
|
+
const globalOpts = command.parent?.parent?.opts() || {};
|
|
357
|
+
const accountIndex = globalOpts.account;
|
|
358
|
+
await ensureWalletUnlocked();
|
|
359
|
+
let privateKey = getPrivateKey(globalOpts.privateKey, accountIndex);
|
|
360
|
+
if (!isConfigured(globalOpts.privateKey)) {
|
|
361
|
+
if (globalOpts.json) {
|
|
362
|
+
console.error('❌ Not configured. Run "httpcat config" first or use --private-key flag.');
|
|
363
|
+
process.exit(2);
|
|
364
|
+
}
|
|
365
|
+
privateKey = await promptForPrivateKey();
|
|
366
|
+
}
|
|
367
|
+
const client = await HttpcatClient.create(privateKey);
|
|
368
|
+
// Derive wallet address if not provided
|
|
369
|
+
let walletAddress = options.wallet;
|
|
370
|
+
if (!walletAddress) {
|
|
371
|
+
const account = privateKeyToAccount(privateKey);
|
|
372
|
+
walletAddress = account.address;
|
|
373
|
+
}
|
|
374
|
+
const result = await withLoading(async () => {
|
|
375
|
+
const params = new URLSearchParams({
|
|
376
|
+
wallet: walletAddress,
|
|
377
|
+
limit: options.limit || "50",
|
|
378
|
+
offset: options.offset || "0",
|
|
379
|
+
});
|
|
380
|
+
try {
|
|
381
|
+
const data = await client.get(`/history/trades?${params.toString()}`);
|
|
382
|
+
return data.output || data;
|
|
383
|
+
}
|
|
384
|
+
catch {
|
|
385
|
+
const { data } = await client.invoke("history/trades", {
|
|
386
|
+
wallet: walletAddress,
|
|
387
|
+
limit: parseInt(options.limit || "50"),
|
|
388
|
+
offset: parseInt(options.offset || "0"),
|
|
389
|
+
});
|
|
390
|
+
return data;
|
|
391
|
+
}
|
|
392
|
+
}, {
|
|
393
|
+
message: "Fetching trade history...",
|
|
394
|
+
json: globalOpts.json,
|
|
395
|
+
quiet: globalOpts.quiet,
|
|
396
|
+
spinner: "cat",
|
|
397
|
+
clearOnSuccess: true,
|
|
398
|
+
});
|
|
399
|
+
if (globalOpts.json) {
|
|
400
|
+
outputJson("trades", result);
|
|
401
|
+
}
|
|
402
|
+
else if (!globalOpts.quiet) {
|
|
403
|
+
displayTradeHistory(result);
|
|
404
|
+
}
|
|
405
|
+
process.exit(0);
|
|
406
|
+
}
|
|
407
|
+
catch (error) {
|
|
408
|
+
const globalOpts = command.parent?.parent?.opts() || {};
|
|
409
|
+
if (globalOpts.json) {
|
|
410
|
+
outputError("trades", error, getExitCode(error));
|
|
411
|
+
}
|
|
412
|
+
else {
|
|
413
|
+
handleError(error, globalOpts.verbose);
|
|
414
|
+
}
|
|
415
|
+
process.exit(getExitCode(error));
|
|
416
|
+
}
|
|
417
|
+
});
|
|
418
|
+
// Transactions subcommand
|
|
419
|
+
portfolioCommand
|
|
420
|
+
.command("transactions")
|
|
421
|
+
.alias("txs")
|
|
422
|
+
.description("Get transaction history ($0.001)")
|
|
423
|
+
.option("--wallet <address>", "Wallet address (defaults to active account)")
|
|
424
|
+
.option("--limit <number>", "Limit results (default: 50)", "50")
|
|
425
|
+
.option("--offset <number>", "Pagination offset (default: 0)", "0")
|
|
426
|
+
.addHelpText("after", `
|
|
427
|
+
Examples:
|
|
428
|
+
httpcat portfolio transactions
|
|
429
|
+
httpcat portfolio transactions --limit 100
|
|
430
|
+
httpcat portfolio transactions --wallet 0x...
|
|
431
|
+
`)
|
|
432
|
+
.action(async (options, command) => {
|
|
433
|
+
try {
|
|
434
|
+
const globalOpts = command.parent?.parent?.opts() || {};
|
|
435
|
+
const accountIndex = globalOpts.account;
|
|
436
|
+
await ensureWalletUnlocked();
|
|
437
|
+
let privateKey = getPrivateKey(globalOpts.privateKey, accountIndex);
|
|
438
|
+
if (!isConfigured(globalOpts.privateKey)) {
|
|
439
|
+
if (globalOpts.json) {
|
|
440
|
+
console.error('❌ Not configured. Run "httpcat config" first or use --private-key flag.');
|
|
441
|
+
process.exit(2);
|
|
442
|
+
}
|
|
443
|
+
privateKey = await promptForPrivateKey();
|
|
444
|
+
}
|
|
445
|
+
const client = await HttpcatClient.create(privateKey);
|
|
446
|
+
// Derive wallet address if not provided
|
|
447
|
+
let walletAddress = options.wallet;
|
|
448
|
+
if (!walletAddress) {
|
|
449
|
+
const account = privateKeyToAccount(privateKey);
|
|
450
|
+
walletAddress = account.address;
|
|
451
|
+
}
|
|
452
|
+
const result = await withLoading(async () => {
|
|
453
|
+
// Try new endpoint first, fallback to old endpoint
|
|
454
|
+
const params = new URLSearchParams({
|
|
455
|
+
wallet: walletAddress,
|
|
456
|
+
limit: options.limit || "50",
|
|
457
|
+
offset: options.offset || "0",
|
|
458
|
+
});
|
|
459
|
+
try {
|
|
460
|
+
const data = await client.get(`/history/transactions?${params.toString()}`);
|
|
461
|
+
return data.output || data;
|
|
462
|
+
}
|
|
463
|
+
catch {
|
|
464
|
+
// Fallback to old endpoint for backward compatibility
|
|
465
|
+
try {
|
|
466
|
+
const { data } = await client.invoke("history/transactions", {
|
|
467
|
+
wallet: walletAddress,
|
|
468
|
+
limit: parseInt(options.limit || "50"),
|
|
469
|
+
offset: parseInt(options.offset || "0"),
|
|
470
|
+
});
|
|
471
|
+
return data;
|
|
472
|
+
}
|
|
473
|
+
catch {
|
|
474
|
+
// Final fallback to tokens/transactions
|
|
475
|
+
return await getTransactions(client, {
|
|
476
|
+
userAddress: walletAddress,
|
|
477
|
+
limit: parseInt(options.limit || "50"),
|
|
478
|
+
offset: parseInt(options.offset || "0"),
|
|
479
|
+
});
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
}, {
|
|
483
|
+
message: "Fetching transactions...",
|
|
484
|
+
json: globalOpts.json,
|
|
485
|
+
quiet: globalOpts.quiet,
|
|
486
|
+
spinner: "cat",
|
|
487
|
+
clearOnSuccess: true,
|
|
488
|
+
});
|
|
489
|
+
if (globalOpts.json) {
|
|
490
|
+
outputJson("transactions", result);
|
|
491
|
+
}
|
|
492
|
+
else if (!globalOpts.quiet) {
|
|
493
|
+
// Use appropriate display function based on response structure
|
|
494
|
+
if (result.transactions && Array.isArray(result.transactions)) {
|
|
495
|
+
if (result.transactions[0]?.txHash) {
|
|
496
|
+
// New format from /history/transactions
|
|
497
|
+
displayTransactionHistory(result);
|
|
498
|
+
}
|
|
499
|
+
else {
|
|
500
|
+
// Old format from /tokens/transactions
|
|
501
|
+
displayTransactions(result);
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
else {
|
|
505
|
+
displayTransactionHistory(result);
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
process.exit(0);
|
|
509
|
+
}
|
|
510
|
+
catch (error) {
|
|
511
|
+
const globalOpts = command.parent?.parent?.opts() || {};
|
|
512
|
+
if (globalOpts.json) {
|
|
513
|
+
outputError("transactions", error, getExitCode(error));
|
|
514
|
+
}
|
|
515
|
+
else {
|
|
516
|
+
handleError(error, globalOpts.verbose);
|
|
517
|
+
}
|
|
518
|
+
process.exit(getExitCode(error));
|
|
519
|
+
}
|
|
520
|
+
});
|
|
521
|
+
return portfolioCommand;
|
|
522
|
+
}
|
|
523
|
+
// Display functions for portfolio commands
|
|
524
|
+
function displayPortfolioSummary(summary) {
|
|
525
|
+
const chalk = require("chalk");
|
|
526
|
+
const { printBox, formatCurrency } = require("../utils/formatting.js");
|
|
527
|
+
console.log();
|
|
528
|
+
console.log(chalk.magenta.bold("📊 Portfolio Summary"));
|
|
529
|
+
console.log();
|
|
530
|
+
const boxData = {};
|
|
531
|
+
if (summary.wallet) {
|
|
532
|
+
boxData["Wallet"] = chalk.cyan(summary.wallet);
|
|
533
|
+
}
|
|
534
|
+
if (summary.totalValue !== undefined) {
|
|
535
|
+
boxData["Total Value"] = chalk.green.bold(formatCurrency(summary.totalValue));
|
|
536
|
+
}
|
|
537
|
+
if (summary.totalInvested !== undefined) {
|
|
538
|
+
boxData["Total Invested"] = chalk.cyan(formatCurrency(summary.totalInvested));
|
|
539
|
+
}
|
|
540
|
+
if (summary.totalPnl !== undefined) {
|
|
541
|
+
const pnlColor = parseFloat(summary.totalPnl) >= 0 ? chalk.green : chalk.red;
|
|
542
|
+
boxData["Total P&L"] = pnlColor(formatCurrency(summary.totalPnl));
|
|
543
|
+
}
|
|
544
|
+
if (summary.totalPnlPercentage !== undefined) {
|
|
545
|
+
const pnlPctColor = summary.totalPnlPercentage >= 0 ? chalk.green : chalk.red;
|
|
546
|
+
const sign = summary.totalPnlPercentage >= 0 ? "+" : "";
|
|
547
|
+
boxData["P&L %"] = pnlPctColor(`${sign}${summary.totalPnlPercentage.toFixed(2)}%`);
|
|
548
|
+
}
|
|
549
|
+
if (summary.positions !== undefined) {
|
|
550
|
+
boxData["Positions"] = chalk.cyan(summary.positions.toString());
|
|
551
|
+
}
|
|
552
|
+
if (summary.tokens !== undefined) {
|
|
553
|
+
boxData["Tokens"] = chalk.cyan(summary.tokens.toString());
|
|
554
|
+
}
|
|
555
|
+
printBox("Portfolio Summary", boxData);
|
|
556
|
+
console.log();
|
|
557
|
+
}
|
|
558
|
+
function displayPortfolioPnl(pnl) {
|
|
559
|
+
const chalk = require("chalk");
|
|
560
|
+
const { printBox, formatCurrency, createTable } = require("../utils/formatting.js");
|
|
561
|
+
console.log();
|
|
562
|
+
console.log(chalk.magenta.bold("💰 Portfolio P&L"));
|
|
563
|
+
console.log();
|
|
564
|
+
const boxData = {};
|
|
565
|
+
if (pnl.wallet) {
|
|
566
|
+
boxData["Wallet"] = chalk.cyan(pnl.wallet);
|
|
567
|
+
}
|
|
568
|
+
if (pnl.timeframe) {
|
|
569
|
+
boxData["Timeframe"] = chalk.cyan(pnl.timeframe.toUpperCase());
|
|
570
|
+
}
|
|
571
|
+
if (pnl.pnl !== undefined) {
|
|
572
|
+
const pnlColor = parseFloat(pnl.pnl) >= 0 ? chalk.green : chalk.red;
|
|
573
|
+
boxData["P&L"] = pnlColor(formatCurrency(pnl.pnl));
|
|
574
|
+
}
|
|
575
|
+
if (pnl.pnlPercentage !== undefined) {
|
|
576
|
+
const pnlPctColor = pnl.pnlPercentage >= 0 ? chalk.green : chalk.red;
|
|
577
|
+
const sign = pnl.pnlPercentage >= 0 ? "+" : "";
|
|
578
|
+
boxData["P&L %"] = pnlPctColor(`${sign}${pnl.pnlPercentage.toFixed(2)}%`);
|
|
579
|
+
}
|
|
580
|
+
printBox("Portfolio P&L", boxData);
|
|
581
|
+
if (pnl.breakdown && Array.isArray(pnl.breakdown) && pnl.breakdown.length > 0) {
|
|
582
|
+
console.log();
|
|
583
|
+
console.log(chalk.cyan.bold("Breakdown by Token:"));
|
|
584
|
+
console.log();
|
|
585
|
+
const table = createTable({
|
|
586
|
+
head: ["Token", "P&L", "P&L %"],
|
|
587
|
+
colWidths: [30, 20, 15],
|
|
588
|
+
});
|
|
589
|
+
for (const item of pnl.breakdown) {
|
|
590
|
+
const pnlColor = parseFloat(item.pnl) >= 0 ? chalk.green : chalk.red;
|
|
591
|
+
const pnlPctColor = item.pnlPercentage >= 0 ? chalk.green : chalk.red;
|
|
592
|
+
const sign = item.pnlPercentage >= 0 ? "+" : "";
|
|
593
|
+
table.push([
|
|
594
|
+
item.token || "N/A",
|
|
595
|
+
pnlColor(formatCurrency(item.pnl)),
|
|
596
|
+
pnlPctColor(`${sign}${item.pnlPercentage.toFixed(2)}%`),
|
|
597
|
+
]);
|
|
598
|
+
}
|
|
599
|
+
console.log(table.toString());
|
|
600
|
+
}
|
|
601
|
+
console.log();
|
|
602
|
+
}
|
|
603
|
+
function displayTradeHistory(trades) {
|
|
604
|
+
const chalk = require("chalk");
|
|
605
|
+
const { formatAddress, formatCurrency, formatTokenAmount, createTable } = require("../utils/formatting.js");
|
|
606
|
+
console.log();
|
|
607
|
+
console.log(chalk.magenta.bold(`📈 Trade History (${trades.total || trades.trades?.length || 0} total)`));
|
|
608
|
+
console.log();
|
|
609
|
+
if (!trades.trades || trades.trades.length === 0) {
|
|
610
|
+
console.log(chalk.yellow("No trades found."));
|
|
611
|
+
console.log();
|
|
612
|
+
return;
|
|
613
|
+
}
|
|
614
|
+
const table = createTable({
|
|
615
|
+
head: ["Date", "Type", "Token In", "Token Out", "Amount In", "Amount Out", "TX"],
|
|
616
|
+
colWidths: [20, 10, 15, 15, 20, 20, 15],
|
|
617
|
+
});
|
|
618
|
+
for (const trade of trades.trades) {
|
|
619
|
+
const date = trade.timestamp
|
|
620
|
+
? new Date(trade.timestamp).toLocaleString()
|
|
621
|
+
: "N/A";
|
|
622
|
+
const typeColor = trade.type === "buy"
|
|
623
|
+
? chalk.green
|
|
624
|
+
: trade.type === "sell"
|
|
625
|
+
? chalk.red
|
|
626
|
+
: chalk.cyan;
|
|
627
|
+
table.push([
|
|
628
|
+
chalk.dim(date),
|
|
629
|
+
typeColor(trade.type?.toUpperCase() || "N/A"),
|
|
630
|
+
trade.tokenIn ? formatAddress(trade.tokenIn, 8) : "N/A",
|
|
631
|
+
trade.tokenOut ? formatAddress(trade.tokenOut, 8) : "N/A",
|
|
632
|
+
trade.amountIn
|
|
633
|
+
? formatTokenAmount(trade.amountIn)
|
|
634
|
+
: "N/A",
|
|
635
|
+
trade.amountOut
|
|
636
|
+
? formatTokenAmount(trade.amountOut)
|
|
637
|
+
: "N/A",
|
|
638
|
+
trade.txHash ? formatAddress(trade.txHash, 8) : "N/A",
|
|
639
|
+
]);
|
|
640
|
+
}
|
|
641
|
+
console.log(table.toString());
|
|
642
|
+
console.log();
|
|
643
|
+
}
|
|
644
|
+
function displayTransactionHistory(transactions) {
|
|
645
|
+
const chalk = require("chalk");
|
|
646
|
+
const { formatAddress, createTable } = require("../utils/formatting.js");
|
|
647
|
+
console.log();
|
|
648
|
+
console.log(chalk.magenta.bold(`📜 Transaction History (${transactions.total || transactions.transactions?.length || 0} total)`));
|
|
649
|
+
console.log();
|
|
650
|
+
if (!transactions.transactions || transactions.transactions.length === 0) {
|
|
651
|
+
console.log(chalk.yellow("No transactions found."));
|
|
652
|
+
console.log();
|
|
653
|
+
return;
|
|
654
|
+
}
|
|
655
|
+
const table = createTable({
|
|
656
|
+
head: ["Date", "Type", "Status", "Gas Used", "TX Hash"],
|
|
657
|
+
colWidths: [20, 15, 12, 15, 20],
|
|
658
|
+
});
|
|
659
|
+
for (const tx of transactions.transactions) {
|
|
660
|
+
const date = tx.timestamp
|
|
661
|
+
? new Date(tx.timestamp).toLocaleString()
|
|
662
|
+
: "N/A";
|
|
663
|
+
const statusColor = tx.status === "success" || tx.status === "confirmed"
|
|
664
|
+
? chalk.green
|
|
665
|
+
: tx.status === "pending"
|
|
666
|
+
? chalk.yellow
|
|
667
|
+
: chalk.red;
|
|
668
|
+
table.push([
|
|
669
|
+
chalk.dim(date),
|
|
670
|
+
chalk.cyan(tx.type || "N/A"),
|
|
671
|
+
statusColor(tx.status?.toUpperCase() || "N/A"),
|
|
672
|
+
tx.gasUsed || "N/A",
|
|
673
|
+
tx.txHash ? formatAddress(tx.txHash, 10) : "N/A",
|
|
674
|
+
]);
|
|
675
|
+
}
|
|
676
|
+
console.log(table.toString());
|
|
677
|
+
console.log();
|
|
678
|
+
}
|
|
679
|
+
//# sourceMappingURL=portfolio.js.map
|