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,960 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { HttpcatClient } from "../client.js";
|
|
3
|
+
import { config } from "../config.js";
|
|
4
|
+
import chalk from "chalk";
|
|
5
|
+
import { printBox, formatAddress, formatCurrency, formatTokenAmount, createTable } from "../utils/formatting.js";
|
|
6
|
+
import { withLoading } from "../utils/loading.js";
|
|
7
|
+
import { outputJson, outputError } from "../headless/json-output.js";
|
|
8
|
+
import { handleError, getExitCode } from "../utils/errors.js";
|
|
9
|
+
import { promptForPrivateKey } from "../utils/privateKeyPrompt.js";
|
|
10
|
+
// ============================================================================
|
|
11
|
+
// Shared Utilities
|
|
12
|
+
// ============================================================================
|
|
13
|
+
function getPrivateKey(cliPrivateKey, accountIndex) {
|
|
14
|
+
if (cliPrivateKey)
|
|
15
|
+
return cliPrivateKey;
|
|
16
|
+
const envKey = process.env.HTTPCAT_PRIVATE_KEY;
|
|
17
|
+
if (envKey)
|
|
18
|
+
return envKey;
|
|
19
|
+
try {
|
|
20
|
+
const index = accountIndex !== undefined
|
|
21
|
+
? accountIndex
|
|
22
|
+
: config.getActiveAccountIndex();
|
|
23
|
+
return config.getAccountPrivateKey(index);
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
return config.get("privateKey");
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function isConfigured(cliPrivateKey) {
|
|
30
|
+
if (cliPrivateKey)
|
|
31
|
+
return true;
|
|
32
|
+
return config.isConfigured();
|
|
33
|
+
}
|
|
34
|
+
async function ensureWalletUnlocked() {
|
|
35
|
+
const password = config.getPassword();
|
|
36
|
+
if (!password) {
|
|
37
|
+
config.ensureSessionValid();
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
if (!config.isSessionValid()) {
|
|
41
|
+
const inquirer = (await import("inquirer")).default;
|
|
42
|
+
const answers = await inquirer.prompt([
|
|
43
|
+
{
|
|
44
|
+
type: "password",
|
|
45
|
+
name: "password",
|
|
46
|
+
message: "Enter password to unlock wallet:",
|
|
47
|
+
mask: "•",
|
|
48
|
+
},
|
|
49
|
+
]);
|
|
50
|
+
await config.unlockSession(answers.password);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
// ============================================================================
|
|
54
|
+
// Market Intelligence Command Group
|
|
55
|
+
// ============================================================================
|
|
56
|
+
export function createMarketCommand() {
|
|
57
|
+
const marketCommand = new Command("market")
|
|
58
|
+
.description("Market intelligence & token analysis")
|
|
59
|
+
.addHelpText("after", `
|
|
60
|
+
Examples:
|
|
61
|
+
httpcat market price <token>
|
|
62
|
+
httpcat market ohlc <token> --interval 1h
|
|
63
|
+
httpcat market liquidity <token>
|
|
64
|
+
httpcat market price-impact <token> <amount> <side>
|
|
65
|
+
httpcat market search bitcoin
|
|
66
|
+
httpcat market coin-data bitcoin --sparkline
|
|
67
|
+
httpcat market chart bitcoin 7
|
|
68
|
+
`);
|
|
69
|
+
marketCommand
|
|
70
|
+
.command("price")
|
|
71
|
+
.description("Get token price data ($0.001)")
|
|
72
|
+
.argument("<tokenIdentifier>", "Token identifier (address, symbol, or name)")
|
|
73
|
+
.option("--timeframe <timeframe>", "Timeframe: 1h, 24h, 7d, 30d")
|
|
74
|
+
.action(async (tokenIdentifier, options, command) => {
|
|
75
|
+
try {
|
|
76
|
+
const globalOpts = command.parent?.parent?.opts() || {};
|
|
77
|
+
const accountIndex = globalOpts.account;
|
|
78
|
+
await ensureWalletUnlocked();
|
|
79
|
+
let privateKey = getPrivateKey(globalOpts.privateKey, accountIndex);
|
|
80
|
+
if (!isConfigured(globalOpts.privateKey)) {
|
|
81
|
+
if (globalOpts.json) {
|
|
82
|
+
console.error('❌ Not configured. Run "httpcat config" first or use --private-key flag.');
|
|
83
|
+
process.exit(2);
|
|
84
|
+
}
|
|
85
|
+
privateKey = await promptForPrivateKey();
|
|
86
|
+
}
|
|
87
|
+
const client = await HttpcatClient.create(privateKey);
|
|
88
|
+
const params = new URLSearchParams({ tokenIdentifier });
|
|
89
|
+
if (options.timeframe)
|
|
90
|
+
params.append("timeframe", options.timeframe);
|
|
91
|
+
const result = await withLoading(async () => {
|
|
92
|
+
try {
|
|
93
|
+
const data = await client.get(`/market/price?${params.toString()}`);
|
|
94
|
+
return data.output || data;
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
const { data } = await client.invoke("market/price", {
|
|
98
|
+
tokenIdentifier,
|
|
99
|
+
timeframe: options.timeframe,
|
|
100
|
+
});
|
|
101
|
+
return data;
|
|
102
|
+
}
|
|
103
|
+
}, {
|
|
104
|
+
message: "Fetching price data...",
|
|
105
|
+
json: globalOpts.json,
|
|
106
|
+
quiet: globalOpts.quiet,
|
|
107
|
+
spinner: "cat",
|
|
108
|
+
clearOnSuccess: true,
|
|
109
|
+
});
|
|
110
|
+
if (globalOpts.json) {
|
|
111
|
+
outputJson("market_price", result);
|
|
112
|
+
}
|
|
113
|
+
else if (!globalOpts.quiet) {
|
|
114
|
+
console.log();
|
|
115
|
+
console.log(chalk.magenta.bold("💰 Token Price"));
|
|
116
|
+
console.log();
|
|
117
|
+
const boxData = {
|
|
118
|
+
Token: chalk.cyan(tokenIdentifier),
|
|
119
|
+
Price: chalk.green.bold(formatCurrency(result.price || "0")),
|
|
120
|
+
};
|
|
121
|
+
if (result.priceChange24h !== undefined) {
|
|
122
|
+
const change24h = parseFloat(result.priceChange24h.toString());
|
|
123
|
+
const changeColor = change24h >= 0 ? chalk.green : chalk.red;
|
|
124
|
+
boxData["24h Change"] = changeColor(`${change24h >= 0 ? "+" : ""}${change24h.toFixed(2)}%`);
|
|
125
|
+
}
|
|
126
|
+
if (result.priceChange7d !== undefined) {
|
|
127
|
+
const change7d = parseFloat(result.priceChange7d.toString());
|
|
128
|
+
const changeColor = change7d >= 0 ? chalk.green : chalk.red;
|
|
129
|
+
boxData["7d Change"] = changeColor(`${change7d >= 0 ? "+" : ""}${change7d.toFixed(2)}%`);
|
|
130
|
+
}
|
|
131
|
+
printBox("Price Data", boxData);
|
|
132
|
+
console.log();
|
|
133
|
+
}
|
|
134
|
+
process.exit(0);
|
|
135
|
+
}
|
|
136
|
+
catch (error) {
|
|
137
|
+
const globalOpts = command.parent?.parent?.opts() || {};
|
|
138
|
+
if (globalOpts.json) {
|
|
139
|
+
outputError("market_price", error, getExitCode(error));
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
handleError(error, globalOpts.verbose);
|
|
143
|
+
}
|
|
144
|
+
process.exit(getExitCode(error));
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
marketCommand
|
|
148
|
+
.command("ohlc")
|
|
149
|
+
.description("Get OHLC (Open, High, Low, Close) candle data ($0.01)")
|
|
150
|
+
.argument("<tokenIdentifier>", "Token identifier")
|
|
151
|
+
.option("--interval <interval>", "Interval: 1m, 5m, 15m, 1h, 4h, 1d", "1h")
|
|
152
|
+
.option("--limit <limit>", "Limit results", "100")
|
|
153
|
+
.action(async (tokenIdentifier, options, command) => {
|
|
154
|
+
try {
|
|
155
|
+
const globalOpts = command.parent?.parent?.opts() || {};
|
|
156
|
+
const accountIndex = globalOpts.account;
|
|
157
|
+
await ensureWalletUnlocked();
|
|
158
|
+
let privateKey = getPrivateKey(globalOpts.privateKey, accountIndex);
|
|
159
|
+
if (!isConfigured(globalOpts.privateKey)) {
|
|
160
|
+
if (globalOpts.json) {
|
|
161
|
+
console.error('❌ Not configured. Run "httpcat config" first or use --private-key flag.');
|
|
162
|
+
process.exit(2);
|
|
163
|
+
}
|
|
164
|
+
privateKey = await promptForPrivateKey();
|
|
165
|
+
}
|
|
166
|
+
const client = await HttpcatClient.create(privateKey);
|
|
167
|
+
const params = new URLSearchParams({
|
|
168
|
+
tokenIdentifier,
|
|
169
|
+
interval: options.interval || "1h",
|
|
170
|
+
limit: options.limit || "100",
|
|
171
|
+
});
|
|
172
|
+
const result = await withLoading(async () => {
|
|
173
|
+
try {
|
|
174
|
+
const data = await client.get(`/market/ohlc?${params.toString()}`);
|
|
175
|
+
return data.output || data;
|
|
176
|
+
}
|
|
177
|
+
catch {
|
|
178
|
+
const { data } = await client.invoke("market/ohlc", {
|
|
179
|
+
tokenIdentifier,
|
|
180
|
+
interval: options.interval || "1h",
|
|
181
|
+
limit: parseInt(options.limit || "100"),
|
|
182
|
+
});
|
|
183
|
+
return data;
|
|
184
|
+
}
|
|
185
|
+
}, {
|
|
186
|
+
message: "Fetching OHLC data...",
|
|
187
|
+
json: globalOpts.json,
|
|
188
|
+
quiet: globalOpts.quiet,
|
|
189
|
+
spinner: "cat",
|
|
190
|
+
clearOnSuccess: true,
|
|
191
|
+
});
|
|
192
|
+
if (globalOpts.json) {
|
|
193
|
+
outputJson("market_ohlc", result);
|
|
194
|
+
}
|
|
195
|
+
else if (!globalOpts.quiet) {
|
|
196
|
+
console.log();
|
|
197
|
+
console.log(chalk.magenta.bold(`📊 OHLC Data (${result.candles?.length || 0} candles)`));
|
|
198
|
+
console.log();
|
|
199
|
+
if (result.candles && result.candles.length > 0) {
|
|
200
|
+
const table = createTable({
|
|
201
|
+
head: ["Time", "Open", "High", "Low", "Close", "Volume"],
|
|
202
|
+
colWidths: [20, 15, 15, 15, 15, 20],
|
|
203
|
+
});
|
|
204
|
+
for (const candle of result.candles.slice(0, 20)) {
|
|
205
|
+
table.push([
|
|
206
|
+
new Date(candle.timestamp).toLocaleString(),
|
|
207
|
+
formatCurrency(candle.open),
|
|
208
|
+
chalk.green(formatCurrency(candle.high)),
|
|
209
|
+
chalk.red(formatCurrency(candle.low)),
|
|
210
|
+
formatCurrency(candle.close),
|
|
211
|
+
formatTokenAmount(candle.volume),
|
|
212
|
+
]);
|
|
213
|
+
}
|
|
214
|
+
console.log(table.toString());
|
|
215
|
+
if (result.candles.length > 20) {
|
|
216
|
+
console.log(chalk.dim(`... and ${result.candles.length - 20} more candles`));
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
console.log();
|
|
220
|
+
}
|
|
221
|
+
process.exit(0);
|
|
222
|
+
}
|
|
223
|
+
catch (error) {
|
|
224
|
+
const globalOpts = command.parent?.parent?.opts() || {};
|
|
225
|
+
if (globalOpts.json) {
|
|
226
|
+
outputError("market_ohlc", error, getExitCode(error));
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
handleError(error, globalOpts.verbose);
|
|
230
|
+
}
|
|
231
|
+
process.exit(getExitCode(error));
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
marketCommand
|
|
235
|
+
.command("liquidity")
|
|
236
|
+
.description("Get liquidity depth ($0.01)")
|
|
237
|
+
.argument("<tokenIdentifier>", "Token identifier")
|
|
238
|
+
.option("--depth <depth>", "Depth level", "10")
|
|
239
|
+
.action(async (tokenIdentifier, options, command) => {
|
|
240
|
+
try {
|
|
241
|
+
const globalOpts = command.parent?.parent?.opts() || {};
|
|
242
|
+
const accountIndex = globalOpts.account;
|
|
243
|
+
await ensureWalletUnlocked();
|
|
244
|
+
let privateKey = getPrivateKey(globalOpts.privateKey, accountIndex);
|
|
245
|
+
if (!isConfigured(globalOpts.privateKey)) {
|
|
246
|
+
if (globalOpts.json) {
|
|
247
|
+
console.error('❌ Not configured. Run "httpcat config" first or use --private-key flag.');
|
|
248
|
+
process.exit(2);
|
|
249
|
+
}
|
|
250
|
+
privateKey = await promptForPrivateKey();
|
|
251
|
+
}
|
|
252
|
+
const client = await HttpcatClient.create(privateKey);
|
|
253
|
+
const params = new URLSearchParams({
|
|
254
|
+
tokenIdentifier,
|
|
255
|
+
depth: options.depth || "10",
|
|
256
|
+
});
|
|
257
|
+
const result = await withLoading(async () => {
|
|
258
|
+
try {
|
|
259
|
+
const data = await client.get(`/market/liquidity?${params.toString()}`);
|
|
260
|
+
return data.output || data;
|
|
261
|
+
}
|
|
262
|
+
catch {
|
|
263
|
+
const { data } = await client.invoke("market/liquidity", {
|
|
264
|
+
tokenIdentifier,
|
|
265
|
+
depth: parseInt(options.depth || "10"),
|
|
266
|
+
});
|
|
267
|
+
return data;
|
|
268
|
+
}
|
|
269
|
+
}, {
|
|
270
|
+
message: "Fetching liquidity data...",
|
|
271
|
+
json: globalOpts.json,
|
|
272
|
+
quiet: globalOpts.quiet,
|
|
273
|
+
spinner: "cat",
|
|
274
|
+
clearOnSuccess: true,
|
|
275
|
+
});
|
|
276
|
+
if (globalOpts.json) {
|
|
277
|
+
outputJson("market_liquidity", result);
|
|
278
|
+
}
|
|
279
|
+
else if (!globalOpts.quiet) {
|
|
280
|
+
console.log();
|
|
281
|
+
console.log(chalk.magenta.bold("💧 Liquidity Depth"));
|
|
282
|
+
console.log();
|
|
283
|
+
if (result.bids && result.bids.length > 0) {
|
|
284
|
+
console.log(chalk.green.bold("Bids:"));
|
|
285
|
+
const bidsTable = createTable({
|
|
286
|
+
head: ["Price", "Amount"],
|
|
287
|
+
colWidths: [20, 20],
|
|
288
|
+
});
|
|
289
|
+
for (const bid of result.bids.slice(0, 10)) {
|
|
290
|
+
bidsTable.push([formatCurrency(bid.price), formatTokenAmount(bid.amount)]);
|
|
291
|
+
}
|
|
292
|
+
console.log(bidsTable.toString());
|
|
293
|
+
}
|
|
294
|
+
if (result.asks && result.asks.length > 0) {
|
|
295
|
+
console.log();
|
|
296
|
+
console.log(chalk.red.bold("Asks:"));
|
|
297
|
+
const asksTable = createTable({
|
|
298
|
+
head: ["Price", "Amount"],
|
|
299
|
+
colWidths: [20, 20],
|
|
300
|
+
});
|
|
301
|
+
for (const ask of result.asks.slice(0, 10)) {
|
|
302
|
+
asksTable.push([formatCurrency(ask.price), formatTokenAmount(ask.amount)]);
|
|
303
|
+
}
|
|
304
|
+
console.log(asksTable.toString());
|
|
305
|
+
}
|
|
306
|
+
console.log();
|
|
307
|
+
}
|
|
308
|
+
process.exit(0);
|
|
309
|
+
}
|
|
310
|
+
catch (error) {
|
|
311
|
+
const globalOpts = command.parent?.parent?.opts() || {};
|
|
312
|
+
if (globalOpts.json) {
|
|
313
|
+
outputError("market_liquidity", error, getExitCode(error));
|
|
314
|
+
}
|
|
315
|
+
else {
|
|
316
|
+
handleError(error, globalOpts.verbose);
|
|
317
|
+
}
|
|
318
|
+
process.exit(getExitCode(error));
|
|
319
|
+
}
|
|
320
|
+
});
|
|
321
|
+
marketCommand
|
|
322
|
+
.command("price-impact")
|
|
323
|
+
.description("Calculate price impact for trade ($0.01)")
|
|
324
|
+
.argument("<tokenIdentifier>", "Token identifier")
|
|
325
|
+
.argument("<amount>", "Trade amount")
|
|
326
|
+
.argument("<side>", "Trade side: buy or sell")
|
|
327
|
+
.action(async (tokenIdentifier, amount, side, options, command) => {
|
|
328
|
+
try {
|
|
329
|
+
const globalOpts = command.parent?.parent?.opts() || {};
|
|
330
|
+
const accountIndex = globalOpts.account;
|
|
331
|
+
await ensureWalletUnlocked();
|
|
332
|
+
let privateKey = getPrivateKey(globalOpts.privateKey, accountIndex);
|
|
333
|
+
if (!isConfigured(globalOpts.privateKey)) {
|
|
334
|
+
if (globalOpts.json) {
|
|
335
|
+
console.error('❌ Not configured. Run "httpcat config" first or use --private-key flag.');
|
|
336
|
+
process.exit(2);
|
|
337
|
+
}
|
|
338
|
+
privateKey = await promptForPrivateKey();
|
|
339
|
+
}
|
|
340
|
+
const client = await HttpcatClient.create(privateKey);
|
|
341
|
+
const params = new URLSearchParams({
|
|
342
|
+
tokenIdentifier,
|
|
343
|
+
amount,
|
|
344
|
+
side,
|
|
345
|
+
});
|
|
346
|
+
const result = await withLoading(async () => {
|
|
347
|
+
try {
|
|
348
|
+
const data = await client.get(`/market/price-impact?${params.toString()}`);
|
|
349
|
+
return data.output || data;
|
|
350
|
+
}
|
|
351
|
+
catch {
|
|
352
|
+
const { data } = await client.invoke("market/price-impact", {
|
|
353
|
+
tokenIdentifier,
|
|
354
|
+
amount,
|
|
355
|
+
side,
|
|
356
|
+
});
|
|
357
|
+
return data;
|
|
358
|
+
}
|
|
359
|
+
}, {
|
|
360
|
+
message: "Calculating price impact...",
|
|
361
|
+
json: globalOpts.json,
|
|
362
|
+
quiet: globalOpts.quiet,
|
|
363
|
+
spinner: "cat",
|
|
364
|
+
clearOnSuccess: true,
|
|
365
|
+
});
|
|
366
|
+
if (globalOpts.json) {
|
|
367
|
+
outputJson("market_price_impact", result);
|
|
368
|
+
}
|
|
369
|
+
else if (!globalOpts.quiet) {
|
|
370
|
+
console.log();
|
|
371
|
+
console.log(chalk.magenta.bold("📉 Price Impact"));
|
|
372
|
+
console.log();
|
|
373
|
+
const impact = parseFloat(result.priceImpact?.toString() || "0");
|
|
374
|
+
const impactColor = impact < 0.5
|
|
375
|
+
? chalk.green
|
|
376
|
+
: impact < 1
|
|
377
|
+
? chalk.yellow
|
|
378
|
+
: impact < 3
|
|
379
|
+
? chalk.red
|
|
380
|
+
: chalk.red.bold;
|
|
381
|
+
printBox("Price Impact", {
|
|
382
|
+
"Price Impact": impactColor(`${impact.toFixed(2)}%`),
|
|
383
|
+
Amount: chalk.cyan(amount),
|
|
384
|
+
Side: chalk.cyan(side),
|
|
385
|
+
});
|
|
386
|
+
console.log();
|
|
387
|
+
}
|
|
388
|
+
process.exit(0);
|
|
389
|
+
}
|
|
390
|
+
catch (error) {
|
|
391
|
+
const globalOpts = command.parent?.parent?.opts() || {};
|
|
392
|
+
if (globalOpts.json) {
|
|
393
|
+
outputError("market_price_impact", error, getExitCode(error));
|
|
394
|
+
}
|
|
395
|
+
else {
|
|
396
|
+
handleError(error, globalOpts.verbose);
|
|
397
|
+
}
|
|
398
|
+
process.exit(getExitCode(error));
|
|
399
|
+
}
|
|
400
|
+
});
|
|
401
|
+
marketCommand
|
|
402
|
+
.command("holders-top")
|
|
403
|
+
.description("Get top token holders ($0.01)")
|
|
404
|
+
.argument("<tokenIdentifier>", "Token identifier")
|
|
405
|
+
.option("--limit <limit>", "Limit results", "10")
|
|
406
|
+
.action(async (tokenIdentifier, options, command) => {
|
|
407
|
+
try {
|
|
408
|
+
const globalOpts = command.parent?.parent?.opts() || {};
|
|
409
|
+
const accountIndex = globalOpts.account;
|
|
410
|
+
await ensureWalletUnlocked();
|
|
411
|
+
let privateKey = getPrivateKey(globalOpts.privateKey, accountIndex);
|
|
412
|
+
if (!isConfigured(globalOpts.privateKey)) {
|
|
413
|
+
if (globalOpts.json) {
|
|
414
|
+
console.error('❌ Not configured. Run "httpcat config" first or use --private-key flag.');
|
|
415
|
+
process.exit(2);
|
|
416
|
+
}
|
|
417
|
+
privateKey = await promptForPrivateKey();
|
|
418
|
+
}
|
|
419
|
+
const client = await HttpcatClient.create(privateKey);
|
|
420
|
+
const params = new URLSearchParams({
|
|
421
|
+
tokenIdentifier,
|
|
422
|
+
limit: options.limit || "10",
|
|
423
|
+
});
|
|
424
|
+
const result = await withLoading(async () => {
|
|
425
|
+
try {
|
|
426
|
+
const data = await client.get(`/token/holders/top?${params.toString()}`);
|
|
427
|
+
return data.output || data;
|
|
428
|
+
}
|
|
429
|
+
catch {
|
|
430
|
+
const { data } = await client.invoke("token/holders/top", {
|
|
431
|
+
tokenIdentifier,
|
|
432
|
+
limit: parseInt(options.limit || "10"),
|
|
433
|
+
});
|
|
434
|
+
return data;
|
|
435
|
+
}
|
|
436
|
+
}, {
|
|
437
|
+
message: "Fetching top holders...",
|
|
438
|
+
json: globalOpts.json,
|
|
439
|
+
quiet: globalOpts.quiet,
|
|
440
|
+
spinner: "cat",
|
|
441
|
+
clearOnSuccess: true,
|
|
442
|
+
});
|
|
443
|
+
if (globalOpts.json) {
|
|
444
|
+
outputJson("market_holders_top", result);
|
|
445
|
+
}
|
|
446
|
+
else if (!globalOpts.quiet) {
|
|
447
|
+
console.log();
|
|
448
|
+
console.log(chalk.magenta.bold(`👥 Top Holders (${result.holders?.length || 0})`));
|
|
449
|
+
console.log();
|
|
450
|
+
if (result.holders && result.holders.length > 0) {
|
|
451
|
+
const table = createTable({
|
|
452
|
+
head: ["Rank", "Address", "Balance", "Percentage"],
|
|
453
|
+
colWidths: [8, 20, 20, 15],
|
|
454
|
+
});
|
|
455
|
+
for (const holder of result.holders) {
|
|
456
|
+
table.push([
|
|
457
|
+
holder.rank?.toString() || "N/A",
|
|
458
|
+
formatAddress(holder.address, 12),
|
|
459
|
+
formatTokenAmount(holder.balance),
|
|
460
|
+
`${parseFloat(holder.percentage?.toString() || "0").toFixed(2)}%`,
|
|
461
|
+
]);
|
|
462
|
+
}
|
|
463
|
+
console.log(table.toString());
|
|
464
|
+
}
|
|
465
|
+
console.log();
|
|
466
|
+
}
|
|
467
|
+
process.exit(0);
|
|
468
|
+
}
|
|
469
|
+
catch (error) {
|
|
470
|
+
const globalOpts = command.parent?.parent?.opts() || {};
|
|
471
|
+
if (globalOpts.json) {
|
|
472
|
+
outputError("market_holders_top", error, getExitCode(error));
|
|
473
|
+
}
|
|
474
|
+
else {
|
|
475
|
+
handleError(error, globalOpts.verbose);
|
|
476
|
+
}
|
|
477
|
+
process.exit(getExitCode(error));
|
|
478
|
+
}
|
|
479
|
+
});
|
|
480
|
+
marketCommand
|
|
481
|
+
.command("distribution")
|
|
482
|
+
.description("Get token distribution ($0.01)")
|
|
483
|
+
.argument("<tokenIdentifier>", "Token identifier")
|
|
484
|
+
.action(async (tokenIdentifier, options, command) => {
|
|
485
|
+
try {
|
|
486
|
+
const globalOpts = command.parent?.parent?.opts() || {};
|
|
487
|
+
const accountIndex = globalOpts.account;
|
|
488
|
+
await ensureWalletUnlocked();
|
|
489
|
+
let privateKey = getPrivateKey(globalOpts.privateKey, accountIndex);
|
|
490
|
+
if (!isConfigured(globalOpts.privateKey)) {
|
|
491
|
+
if (globalOpts.json) {
|
|
492
|
+
console.error('❌ Not configured. Run "httpcat config" first or use --private-key flag.');
|
|
493
|
+
process.exit(2);
|
|
494
|
+
}
|
|
495
|
+
privateKey = await promptForPrivateKey();
|
|
496
|
+
}
|
|
497
|
+
const client = await HttpcatClient.create(privateKey);
|
|
498
|
+
const params = new URLSearchParams({ tokenIdentifier });
|
|
499
|
+
const result = await withLoading(async () => {
|
|
500
|
+
try {
|
|
501
|
+
const data = await client.get(`/token/distribution?${params.toString()}`);
|
|
502
|
+
return data.output || data;
|
|
503
|
+
}
|
|
504
|
+
catch {
|
|
505
|
+
const { data } = await client.invoke("token/distribution", {
|
|
506
|
+
tokenIdentifier,
|
|
507
|
+
});
|
|
508
|
+
return data;
|
|
509
|
+
}
|
|
510
|
+
}, {
|
|
511
|
+
message: "Fetching distribution...",
|
|
512
|
+
json: globalOpts.json,
|
|
513
|
+
quiet: globalOpts.quiet,
|
|
514
|
+
spinner: "cat",
|
|
515
|
+
clearOnSuccess: true,
|
|
516
|
+
});
|
|
517
|
+
if (globalOpts.json) {
|
|
518
|
+
outputJson("market_distribution", result);
|
|
519
|
+
}
|
|
520
|
+
else if (!globalOpts.quiet) {
|
|
521
|
+
console.log();
|
|
522
|
+
console.log(chalk.magenta.bold("📊 Token Distribution"));
|
|
523
|
+
console.log();
|
|
524
|
+
console.log(JSON.stringify(result, null, 2));
|
|
525
|
+
console.log();
|
|
526
|
+
}
|
|
527
|
+
process.exit(0);
|
|
528
|
+
}
|
|
529
|
+
catch (error) {
|
|
530
|
+
const globalOpts = command.parent?.parent?.opts() || {};
|
|
531
|
+
if (globalOpts.json) {
|
|
532
|
+
outputError("market_distribution", error, getExitCode(error));
|
|
533
|
+
}
|
|
534
|
+
else {
|
|
535
|
+
handleError(error, globalOpts.verbose);
|
|
536
|
+
}
|
|
537
|
+
process.exit(getExitCode(error));
|
|
538
|
+
}
|
|
539
|
+
});
|
|
540
|
+
marketCommand
|
|
541
|
+
.command("supply")
|
|
542
|
+
.description("Get token supply information ($0.001)")
|
|
543
|
+
.argument("<tokenIdentifier>", "Token identifier")
|
|
544
|
+
.action(async (tokenIdentifier, options, command) => {
|
|
545
|
+
try {
|
|
546
|
+
const globalOpts = command.parent?.parent?.opts() || {};
|
|
547
|
+
const accountIndex = globalOpts.account;
|
|
548
|
+
await ensureWalletUnlocked();
|
|
549
|
+
let privateKey = getPrivateKey(globalOpts.privateKey, accountIndex);
|
|
550
|
+
if (!isConfigured(globalOpts.privateKey)) {
|
|
551
|
+
if (globalOpts.json) {
|
|
552
|
+
console.error('❌ Not configured. Run "httpcat config" first or use --private-key flag.');
|
|
553
|
+
process.exit(2);
|
|
554
|
+
}
|
|
555
|
+
privateKey = await promptForPrivateKey();
|
|
556
|
+
}
|
|
557
|
+
const client = await HttpcatClient.create(privateKey);
|
|
558
|
+
const params = new URLSearchParams({ tokenIdentifier });
|
|
559
|
+
const result = await withLoading(async () => {
|
|
560
|
+
try {
|
|
561
|
+
const data = await client.get(`/token/supply?${params.toString()}`);
|
|
562
|
+
return data.output || data;
|
|
563
|
+
}
|
|
564
|
+
catch {
|
|
565
|
+
const { data } = await client.invoke("token/supply", {
|
|
566
|
+
tokenIdentifier,
|
|
567
|
+
});
|
|
568
|
+
return data;
|
|
569
|
+
}
|
|
570
|
+
}, {
|
|
571
|
+
message: "Fetching supply info...",
|
|
572
|
+
json: globalOpts.json,
|
|
573
|
+
quiet: globalOpts.quiet,
|
|
574
|
+
spinner: "cat",
|
|
575
|
+
clearOnSuccess: true,
|
|
576
|
+
});
|
|
577
|
+
if (globalOpts.json) {
|
|
578
|
+
outputJson("market_supply", result);
|
|
579
|
+
}
|
|
580
|
+
else if (!globalOpts.quiet) {
|
|
581
|
+
console.log();
|
|
582
|
+
console.log(chalk.magenta.bold("📈 Token Supply"));
|
|
583
|
+
console.log();
|
|
584
|
+
printBox("Supply Information", {
|
|
585
|
+
"Total Supply": chalk.green(formatTokenAmount(result.totalSupply || "0")),
|
|
586
|
+
"Circulating Supply": chalk.cyan(formatTokenAmount(result.circulatingSupply || "0")),
|
|
587
|
+
"Max Supply": result.maxSupply
|
|
588
|
+
? chalk.yellow(formatTokenAmount(result.maxSupply))
|
|
589
|
+
: chalk.dim("Unlimited"),
|
|
590
|
+
});
|
|
591
|
+
console.log();
|
|
592
|
+
}
|
|
593
|
+
process.exit(0);
|
|
594
|
+
}
|
|
595
|
+
catch (error) {
|
|
596
|
+
const globalOpts = command.parent?.parent?.opts() || {};
|
|
597
|
+
if (globalOpts.json) {
|
|
598
|
+
outputError("market_supply", error, getExitCode(error));
|
|
599
|
+
}
|
|
600
|
+
else {
|
|
601
|
+
handleError(error, globalOpts.verbose);
|
|
602
|
+
}
|
|
603
|
+
process.exit(getExitCode(error));
|
|
604
|
+
}
|
|
605
|
+
});
|
|
606
|
+
marketCommand
|
|
607
|
+
.command("unlocks")
|
|
608
|
+
.description("Get token unlock schedule ($0.01)")
|
|
609
|
+
.argument("<tokenIdentifier>", "Token identifier")
|
|
610
|
+
.action(async (tokenIdentifier, options, command) => {
|
|
611
|
+
try {
|
|
612
|
+
const globalOpts = command.parent?.parent?.opts() || {};
|
|
613
|
+
const accountIndex = globalOpts.account;
|
|
614
|
+
await ensureWalletUnlocked();
|
|
615
|
+
let privateKey = getPrivateKey(globalOpts.privateKey, accountIndex);
|
|
616
|
+
if (!isConfigured(globalOpts.privateKey)) {
|
|
617
|
+
if (globalOpts.json) {
|
|
618
|
+
console.error('❌ Not configured. Run "httpcat config" first or use --private-key flag.');
|
|
619
|
+
process.exit(2);
|
|
620
|
+
}
|
|
621
|
+
privateKey = await promptForPrivateKey();
|
|
622
|
+
}
|
|
623
|
+
const client = await HttpcatClient.create(privateKey);
|
|
624
|
+
const params = new URLSearchParams({ tokenIdentifier });
|
|
625
|
+
const result = await withLoading(async () => {
|
|
626
|
+
try {
|
|
627
|
+
const data = await client.get(`/token/unlocks?${params.toString()}`);
|
|
628
|
+
return data.output || data;
|
|
629
|
+
}
|
|
630
|
+
catch {
|
|
631
|
+
const { data } = await client.invoke("token/unlocks", {
|
|
632
|
+
tokenIdentifier,
|
|
633
|
+
});
|
|
634
|
+
return data;
|
|
635
|
+
}
|
|
636
|
+
}, {
|
|
637
|
+
message: "Fetching unlock schedule...",
|
|
638
|
+
json: globalOpts.json,
|
|
639
|
+
quiet: globalOpts.quiet,
|
|
640
|
+
spinner: "cat",
|
|
641
|
+
clearOnSuccess: true,
|
|
642
|
+
});
|
|
643
|
+
if (globalOpts.json) {
|
|
644
|
+
outputJson("market_unlocks", result);
|
|
645
|
+
}
|
|
646
|
+
else if (!globalOpts.quiet) {
|
|
647
|
+
console.log();
|
|
648
|
+
console.log(chalk.magenta.bold(`🔓 Token Unlocks (${result.unlocks?.length || 0})`));
|
|
649
|
+
console.log();
|
|
650
|
+
if (result.unlocks && result.unlocks.length > 0) {
|
|
651
|
+
const table = createTable({
|
|
652
|
+
head: ["Date", "Amount", "Percentage"],
|
|
653
|
+
colWidths: [25, 20, 15],
|
|
654
|
+
});
|
|
655
|
+
for (const unlock of result.unlocks) {
|
|
656
|
+
table.push([
|
|
657
|
+
new Date(unlock.date).toLocaleString(),
|
|
658
|
+
formatTokenAmount(unlock.amount),
|
|
659
|
+
`${parseFloat(unlock.percentage?.toString() || "0").toFixed(2)}%`,
|
|
660
|
+
]);
|
|
661
|
+
}
|
|
662
|
+
console.log(table.toString());
|
|
663
|
+
}
|
|
664
|
+
console.log();
|
|
665
|
+
}
|
|
666
|
+
process.exit(0);
|
|
667
|
+
}
|
|
668
|
+
catch (error) {
|
|
669
|
+
const globalOpts = command.parent?.parent?.opts() || {};
|
|
670
|
+
if (globalOpts.json) {
|
|
671
|
+
outputError("market_unlocks", error, getExitCode(error));
|
|
672
|
+
}
|
|
673
|
+
else {
|
|
674
|
+
handleError(error, globalOpts.verbose);
|
|
675
|
+
}
|
|
676
|
+
process.exit(getExitCode(error));
|
|
677
|
+
}
|
|
678
|
+
});
|
|
679
|
+
// ============================================================================
|
|
680
|
+
// CoinGecko Commands
|
|
681
|
+
// ============================================================================
|
|
682
|
+
marketCommand
|
|
683
|
+
.command("search")
|
|
684
|
+
.description("Search cryptocurrencies (FREE)")
|
|
685
|
+
.argument("<query>", "Search term (name or symbol)")
|
|
686
|
+
.option("--limit <limit>", "Maximum results", "20")
|
|
687
|
+
.action(async (query, options, command) => {
|
|
688
|
+
try {
|
|
689
|
+
const globalOpts = command.parent?.parent?.opts() || {};
|
|
690
|
+
const accountIndex = globalOpts.account;
|
|
691
|
+
await ensureWalletUnlocked();
|
|
692
|
+
let privateKey = getPrivateKey(globalOpts.privateKey, accountIndex);
|
|
693
|
+
if (!isConfigured(globalOpts.privateKey)) {
|
|
694
|
+
if (globalOpts.json) {
|
|
695
|
+
console.error('❌ Not configured. Run "httpcat config" first or use --private-key flag.');
|
|
696
|
+
process.exit(2);
|
|
697
|
+
}
|
|
698
|
+
privateKey = await promptForPrivateKey();
|
|
699
|
+
}
|
|
700
|
+
const client = await HttpcatClient.create(privateKey);
|
|
701
|
+
const limit = Math.min(parseInt(options.limit || "20"), 100);
|
|
702
|
+
const result = await withLoading(async () => {
|
|
703
|
+
const { data } = await client.invoke("market/search", {
|
|
704
|
+
query,
|
|
705
|
+
limit,
|
|
706
|
+
});
|
|
707
|
+
return data;
|
|
708
|
+
}, {
|
|
709
|
+
message: "Searching cryptocurrencies...",
|
|
710
|
+
json: globalOpts.json,
|
|
711
|
+
quiet: globalOpts.quiet,
|
|
712
|
+
spinner: "cat",
|
|
713
|
+
clearOnSuccess: true,
|
|
714
|
+
});
|
|
715
|
+
if (globalOpts.json) {
|
|
716
|
+
outputJson("market_search", {
|
|
717
|
+
command: "market_search",
|
|
718
|
+
data: result,
|
|
719
|
+
});
|
|
720
|
+
}
|
|
721
|
+
else if (!globalOpts.quiet) {
|
|
722
|
+
console.log();
|
|
723
|
+
console.log(chalk.magenta.bold(`🔍 Market Search Results (${result.coins?.length || 0} found)`));
|
|
724
|
+
console.log();
|
|
725
|
+
if (result.coins && result.coins.length > 0) {
|
|
726
|
+
const table = createTable({
|
|
727
|
+
head: ["Coin ID", "Symbol", "Name"],
|
|
728
|
+
colWidths: [20, 12, 30],
|
|
729
|
+
});
|
|
730
|
+
for (const coin of result.coins) {
|
|
731
|
+
table.push([
|
|
732
|
+
chalk.cyan(coin.id || ""),
|
|
733
|
+
chalk.yellow(coin.symbol?.toUpperCase() || ""),
|
|
734
|
+
coin.name || "",
|
|
735
|
+
]);
|
|
736
|
+
}
|
|
737
|
+
console.log(table.toString());
|
|
738
|
+
console.log();
|
|
739
|
+
console.log(chalk.dim(`Total: ${result.total || result.coins.length} results`));
|
|
740
|
+
}
|
|
741
|
+
else {
|
|
742
|
+
console.log(chalk.dim("No results found."));
|
|
743
|
+
}
|
|
744
|
+
console.log();
|
|
745
|
+
}
|
|
746
|
+
process.exit(0);
|
|
747
|
+
}
|
|
748
|
+
catch (error) {
|
|
749
|
+
const globalOpts = command.parent?.parent?.opts() || {};
|
|
750
|
+
if (globalOpts.json) {
|
|
751
|
+
outputError("market_search", error, getExitCode(error));
|
|
752
|
+
}
|
|
753
|
+
else {
|
|
754
|
+
handleError(error, globalOpts.verbose);
|
|
755
|
+
}
|
|
756
|
+
process.exit(getExitCode(error));
|
|
757
|
+
}
|
|
758
|
+
});
|
|
759
|
+
marketCommand
|
|
760
|
+
.command("coin-data")
|
|
761
|
+
.description("Get comprehensive coin market data ($0.001)")
|
|
762
|
+
.argument("<coinId>", "CoinGecko coin ID (e.g., 'bitcoin')")
|
|
763
|
+
.option("--currency <currency>", "Currency (usd, eur, btc)", "usd")
|
|
764
|
+
.option("--sparkline", "Include 7-day sparkline")
|
|
765
|
+
.action(async (coinId, options, command) => {
|
|
766
|
+
try {
|
|
767
|
+
const globalOpts = command.parent?.parent?.opts() || {};
|
|
768
|
+
const accountIndex = globalOpts.account;
|
|
769
|
+
await ensureWalletUnlocked();
|
|
770
|
+
let privateKey = getPrivateKey(globalOpts.privateKey, accountIndex);
|
|
771
|
+
if (!isConfigured(globalOpts.privateKey)) {
|
|
772
|
+
if (globalOpts.json) {
|
|
773
|
+
console.error('❌ Not configured. Run "httpcat config" first or use --private-key flag.');
|
|
774
|
+
process.exit(2);
|
|
775
|
+
}
|
|
776
|
+
privateKey = await promptForPrivateKey();
|
|
777
|
+
}
|
|
778
|
+
const client = await HttpcatClient.create(privateKey);
|
|
779
|
+
const result = await withLoading(async () => {
|
|
780
|
+
const { data } = await client.invoke("market/coin-data", {
|
|
781
|
+
coinId,
|
|
782
|
+
currency: options.currency || "usd",
|
|
783
|
+
sparkline: options.sparkline || false,
|
|
784
|
+
});
|
|
785
|
+
return data;
|
|
786
|
+
}, {
|
|
787
|
+
message: "Fetching coin data ($0.001)...",
|
|
788
|
+
json: globalOpts.json,
|
|
789
|
+
quiet: globalOpts.quiet,
|
|
790
|
+
spinner: "cat",
|
|
791
|
+
clearOnSuccess: true,
|
|
792
|
+
});
|
|
793
|
+
if (globalOpts.json) {
|
|
794
|
+
outputJson("market_coin_data", {
|
|
795
|
+
command: "market_coin_data",
|
|
796
|
+
data: result,
|
|
797
|
+
});
|
|
798
|
+
}
|
|
799
|
+
else if (!globalOpts.quiet) {
|
|
800
|
+
console.log();
|
|
801
|
+
const symbol = result.symbol?.toUpperCase() || "";
|
|
802
|
+
const name = result.name || coinId;
|
|
803
|
+
console.log(chalk.magenta.bold(`💰 Coin Data: ${name} (${symbol})`));
|
|
804
|
+
console.log();
|
|
805
|
+
const currency = (options.currency || "usd").toUpperCase();
|
|
806
|
+
const priceKey = `currentPrice`; // API returns currentPrice
|
|
807
|
+
const price = result[priceKey] || result.price || 0;
|
|
808
|
+
const priceChange24h = result.priceChange24h || result.priceChangePercentage24h || 0;
|
|
809
|
+
const changeColor = priceChange24h >= 0 ? chalk.green : chalk.red;
|
|
810
|
+
const changeEmoji = priceChange24h >= 0 ? "🟢" : "🔴";
|
|
811
|
+
const boxData = {
|
|
812
|
+
Price: chalk.green.bold(formatCurrency(price)),
|
|
813
|
+
"24h Change": changeColor(`${priceChange24h >= 0 ? "+" : ""}${priceChange24h.toFixed(2)}% ${changeEmoji}`),
|
|
814
|
+
};
|
|
815
|
+
if (result.marketCap) {
|
|
816
|
+
boxData["Market Cap"] = formatCurrency(result.marketCap);
|
|
817
|
+
}
|
|
818
|
+
if (result.marketCapRank) {
|
|
819
|
+
boxData["Market Cap Rank"] = `#${result.marketCapRank}`;
|
|
820
|
+
}
|
|
821
|
+
if (result.totalVolume) {
|
|
822
|
+
boxData["Volume 24h"] = formatCurrency(result.totalVolume);
|
|
823
|
+
}
|
|
824
|
+
if (result.high24h) {
|
|
825
|
+
boxData["High 24h"] = formatCurrency(result.high24h);
|
|
826
|
+
}
|
|
827
|
+
if (result.low24h) {
|
|
828
|
+
boxData["Low 24h"] = formatCurrency(result.low24h);
|
|
829
|
+
}
|
|
830
|
+
if (result.circulatingSupply) {
|
|
831
|
+
boxData["Circulating Supply"] = formatTokenAmount(result.circulatingSupply.toString());
|
|
832
|
+
}
|
|
833
|
+
if (result.totalSupply) {
|
|
834
|
+
boxData["Total Supply"] = formatTokenAmount(result.totalSupply.toString());
|
|
835
|
+
}
|
|
836
|
+
if (result.ath) {
|
|
837
|
+
const athChange = result.athChangePercentage || 0;
|
|
838
|
+
boxData["ATH"] = `${formatCurrency(result.ath)} (${athChange.toFixed(1)}%)`;
|
|
839
|
+
}
|
|
840
|
+
if (result.atl) {
|
|
841
|
+
const atlChange = result.atlChangePercentage || 0;
|
|
842
|
+
boxData["ATL"] = `${formatCurrency(result.atl)} (+${atlChange.toFixed(1)}%)`;
|
|
843
|
+
}
|
|
844
|
+
printBox("Coin Data", boxData);
|
|
845
|
+
console.log();
|
|
846
|
+
}
|
|
847
|
+
process.exit(0);
|
|
848
|
+
}
|
|
849
|
+
catch (error) {
|
|
850
|
+
const globalOpts = command.parent?.parent?.opts() || {};
|
|
851
|
+
if (globalOpts.json) {
|
|
852
|
+
outputError("market_coin_data", error, getExitCode(error));
|
|
853
|
+
}
|
|
854
|
+
else {
|
|
855
|
+
handleError(error, globalOpts.verbose);
|
|
856
|
+
}
|
|
857
|
+
process.exit(getExitCode(error));
|
|
858
|
+
}
|
|
859
|
+
});
|
|
860
|
+
marketCommand
|
|
861
|
+
.command("chart")
|
|
862
|
+
.description("Get historical price chart data ($0.01)")
|
|
863
|
+
.argument("<coinId>", "CoinGecko coin ID")
|
|
864
|
+
.argument("<days>", "Timeframe: 1, 7, 14, 30, 90, 180, 365, or max")
|
|
865
|
+
.option("--currency <currency>", "Currency", "usd")
|
|
866
|
+
.option("--interval <interval>", "Interval: daily or hourly")
|
|
867
|
+
.action(async (coinId, days, options, command) => {
|
|
868
|
+
try {
|
|
869
|
+
const globalOpts = command.parent?.parent?.opts() || {};
|
|
870
|
+
const accountIndex = globalOpts.account;
|
|
871
|
+
await ensureWalletUnlocked();
|
|
872
|
+
let privateKey = getPrivateKey(globalOpts.privateKey, accountIndex);
|
|
873
|
+
if (!isConfigured(globalOpts.privateKey)) {
|
|
874
|
+
if (globalOpts.json) {
|
|
875
|
+
console.error('❌ Not configured. Run "httpcat config" first or use --private-key flag.');
|
|
876
|
+
process.exit(2);
|
|
877
|
+
}
|
|
878
|
+
privateKey = await promptForPrivateKey();
|
|
879
|
+
}
|
|
880
|
+
const client = await HttpcatClient.create(privateKey);
|
|
881
|
+
const result = await withLoading(async () => {
|
|
882
|
+
const { data } = await client.invoke("market/chart", {
|
|
883
|
+
coinId,
|
|
884
|
+
days,
|
|
885
|
+
currency: options.currency || "usd",
|
|
886
|
+
interval: options.interval,
|
|
887
|
+
});
|
|
888
|
+
return data;
|
|
889
|
+
}, {
|
|
890
|
+
message: "Fetching chart data ($0.01)...",
|
|
891
|
+
json: globalOpts.json,
|
|
892
|
+
quiet: globalOpts.quiet,
|
|
893
|
+
spinner: "cat",
|
|
894
|
+
clearOnSuccess: true,
|
|
895
|
+
});
|
|
896
|
+
if (globalOpts.json) {
|
|
897
|
+
outputJson("market_chart", {
|
|
898
|
+
command: "market_chart",
|
|
899
|
+
data: result,
|
|
900
|
+
});
|
|
901
|
+
}
|
|
902
|
+
else if (!globalOpts.quiet) {
|
|
903
|
+
console.log();
|
|
904
|
+
const currency = (options.currency || "usd").toUpperCase();
|
|
905
|
+
console.log(chalk.magenta.bold(`📊 Price Chart: ${coinId} (${days} days)`));
|
|
906
|
+
console.log();
|
|
907
|
+
const dataPoints = result.prices?.length || 0;
|
|
908
|
+
console.log(chalk.dim(`Data Points: ${dataPoints}`));
|
|
909
|
+
console.log(chalk.dim(`Currency: ${currency}`));
|
|
910
|
+
console.log();
|
|
911
|
+
if (result.prices && result.prices.length > 0) {
|
|
912
|
+
console.log(chalk.dim("Sample Data:"));
|
|
913
|
+
const table = createTable({
|
|
914
|
+
head: ["Timestamp", "Price", "Market Cap", "Volume"],
|
|
915
|
+
colWidths: [20, 15, 15, 15],
|
|
916
|
+
});
|
|
917
|
+
// Show first 5 and last 5 data points
|
|
918
|
+
const sampleSize = Math.min(10, result.prices.length);
|
|
919
|
+
const prices = result.prices.slice(0, sampleSize);
|
|
920
|
+
const marketCaps = result.marketCaps?.slice(0, sampleSize) || [];
|
|
921
|
+
const totalVolumes = result.totalVolumes?.slice(0, sampleSize) || [];
|
|
922
|
+
for (let i = 0; i < prices.length; i++) {
|
|
923
|
+
const [timestamp, price] = prices[i];
|
|
924
|
+
const marketCap = marketCaps[i]?.[1] || 0;
|
|
925
|
+
const volume = totalVolumes[i]?.[1] || 0;
|
|
926
|
+
table.push([
|
|
927
|
+
new Date(timestamp).toLocaleString(),
|
|
928
|
+
formatCurrency(price),
|
|
929
|
+
marketCap > 0 ? formatCurrency(marketCap) : "-",
|
|
930
|
+
volume > 0 ? formatCurrency(volume) : "-",
|
|
931
|
+
]);
|
|
932
|
+
}
|
|
933
|
+
console.log(table.toString());
|
|
934
|
+
if (result.prices.length > sampleSize) {
|
|
935
|
+
console.log(chalk.dim(`... and ${result.prices.length - sampleSize} more data points`));
|
|
936
|
+
}
|
|
937
|
+
console.log();
|
|
938
|
+
console.log(chalk.dim("Use --json to get full data for charting"));
|
|
939
|
+
}
|
|
940
|
+
else {
|
|
941
|
+
console.log(chalk.dim("No chart data available."));
|
|
942
|
+
}
|
|
943
|
+
console.log();
|
|
944
|
+
}
|
|
945
|
+
process.exit(0);
|
|
946
|
+
}
|
|
947
|
+
catch (error) {
|
|
948
|
+
const globalOpts = command.parent?.parent?.opts() || {};
|
|
949
|
+
if (globalOpts.json) {
|
|
950
|
+
outputError("market_chart", error, getExitCode(error));
|
|
951
|
+
}
|
|
952
|
+
else {
|
|
953
|
+
handleError(error, globalOpts.verbose);
|
|
954
|
+
}
|
|
955
|
+
process.exit(getExitCode(error));
|
|
956
|
+
}
|
|
957
|
+
});
|
|
958
|
+
return marketCommand;
|
|
959
|
+
}
|
|
960
|
+
//# sourceMappingURL=market.js.map
|