@clawdvault/cli 0.1.5 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -48
- package/dist/index.js +312 -403
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -160,54 +160,6 @@ Examples:
|
|
|
160
160
|
clawdvault trade quote -m TOKEN_MINT -t buy -a 0.1
|
|
161
161
|
```
|
|
162
162
|
|
|
163
|
-
### `clawdvault stream`
|
|
164
|
-
|
|
165
|
-
Real-time data streaming (live trades, prices, chat).
|
|
166
|
-
|
|
167
|
-
```bash
|
|
168
|
-
# Stream live trades
|
|
169
|
-
clawdvault stream trades [options]
|
|
170
|
-
-m, --mint <address> Token mint address (required)
|
|
171
|
-
--json Output as JSON (one object per line)
|
|
172
|
-
--append Append mode (simple log format)
|
|
173
|
-
|
|
174
|
-
# Stream token price updates
|
|
175
|
-
clawdvault stream token [options]
|
|
176
|
-
-m, --mint <address> Token mint address (required)
|
|
177
|
-
--json Output as JSON
|
|
178
|
-
|
|
179
|
-
# Stream chat messages
|
|
180
|
-
clawdvault stream chat [options]
|
|
181
|
-
-m, --mint <address> Token mint address (required)
|
|
182
|
-
--json Output as JSON
|
|
183
|
-
|
|
184
|
-
Examples:
|
|
185
|
-
# Watch trades in real-time (table mode)
|
|
186
|
-
clawdvault stream trades -m TOKEN_MINT
|
|
187
|
-
|
|
188
|
-
# Watch trades for scripting (JSON output)
|
|
189
|
-
clawdvault stream trades -m TOKEN_MINT --json
|
|
190
|
-
|
|
191
|
-
# Log trades to file
|
|
192
|
-
clawdvault stream trades -m TOKEN_MINT --append >> trades.log
|
|
193
|
-
|
|
194
|
-
# Monitor price changes
|
|
195
|
-
clawdvault stream token -m TOKEN_MINT
|
|
196
|
-
|
|
197
|
-
# Watch chat
|
|
198
|
-
clawdvault stream chat -m TOKEN_MINT
|
|
199
|
-
|
|
200
|
-
# Pipe to jq for filtering
|
|
201
|
-
clawdvault stream trades -m TOKEN_MINT --json | jq 'select(.type == "buy")'
|
|
202
|
-
```
|
|
203
|
-
|
|
204
|
-
**Features:**
|
|
205
|
-
- Auto-reconnect on connection loss
|
|
206
|
-
- Graceful shutdown with Ctrl+C
|
|
207
|
-
- Multiple output modes: table (default), append, JSON
|
|
208
|
-
- Table mode clears and updates in-place
|
|
209
|
-
- JSON mode outputs one object per line (great for piping)
|
|
210
|
-
|
|
211
163
|
### `clawdvault wallet`
|
|
212
164
|
|
|
213
165
|
Wallet management and info.
|
package/dist/index.js
CHANGED
|
@@ -43,6 +43,44 @@ var os = __toESM(require("os"));
|
|
|
43
43
|
function getConfigDir() {
|
|
44
44
|
return path.join(os.homedir(), ".clawdvault");
|
|
45
45
|
}
|
|
46
|
+
function getAuthConfigPath() {
|
|
47
|
+
return path.join(getConfigDir(), "auth.json");
|
|
48
|
+
}
|
|
49
|
+
function loadAuthConfig() {
|
|
50
|
+
const configPath = getAuthConfigPath();
|
|
51
|
+
if (!fs.existsSync(configPath)) {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
try {
|
|
55
|
+
const data = fs.readFileSync(configPath, "utf-8");
|
|
56
|
+
const config = JSON.parse(data);
|
|
57
|
+
if (config.expiresAt) {
|
|
58
|
+
const expiresAt = new Date(config.expiresAt);
|
|
59
|
+
if (expiresAt <= /* @__PURE__ */ new Date()) {
|
|
60
|
+
fs.unlinkSync(configPath);
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return config;
|
|
65
|
+
} catch {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
function saveAuthConfig(config) {
|
|
70
|
+
const configDir = getConfigDir();
|
|
71
|
+
const configPath = getAuthConfigPath();
|
|
72
|
+
if (!fs.existsSync(configDir)) {
|
|
73
|
+
fs.mkdirSync(configDir, { recursive: true });
|
|
74
|
+
}
|
|
75
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
76
|
+
fs.chmodSync(configPath, 384);
|
|
77
|
+
}
|
|
78
|
+
function clearAuthConfig() {
|
|
79
|
+
const configPath = getAuthConfigPath();
|
|
80
|
+
if (fs.existsSync(configPath)) {
|
|
81
|
+
fs.unlinkSync(configPath);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
46
84
|
function getWalletPath() {
|
|
47
85
|
if (process.env.CLAWDVAULT_WALLET) {
|
|
48
86
|
return process.env.CLAWDVAULT_WALLET;
|
|
@@ -81,13 +119,27 @@ function getBaseUrl() {
|
|
|
81
119
|
function createClientWithWallet(walletPath) {
|
|
82
120
|
const signer = loadSigner(walletPath);
|
|
83
121
|
const baseUrl = getBaseUrl();
|
|
84
|
-
const
|
|
122
|
+
const authConfig = loadAuthConfig();
|
|
123
|
+
const sessionToken = authConfig?.sessionToken;
|
|
124
|
+
const client = (0, import_sdk.createClient)({
|
|
125
|
+
signer: signer || void 0,
|
|
126
|
+
baseUrl,
|
|
127
|
+
sessionToken
|
|
128
|
+
});
|
|
85
129
|
return {
|
|
86
130
|
client,
|
|
87
131
|
signer,
|
|
88
132
|
walletAddress: signer?.publicKey.toBase58() ?? null
|
|
89
133
|
};
|
|
90
134
|
}
|
|
135
|
+
function requireAuth() {
|
|
136
|
+
const authConfig = loadAuthConfig();
|
|
137
|
+
if (!authConfig?.sessionToken) {
|
|
138
|
+
error("Not logged in. Run: clawdvault wallet login");
|
|
139
|
+
process.exit(1);
|
|
140
|
+
}
|
|
141
|
+
return authConfig;
|
|
142
|
+
}
|
|
91
143
|
function createReadOnlyClient() {
|
|
92
144
|
const baseUrl = getBaseUrl();
|
|
93
145
|
return (0, import_sdk.createClient)({ baseUrl });
|
|
@@ -178,7 +230,7 @@ tokensCommand.command("list").description("List all tokens").option("-s, --sort
|
|
|
178
230
|
return;
|
|
179
231
|
}
|
|
180
232
|
console.log(import_chalk2.default.bold(`
|
|
181
|
-
\u{1F4CA} Tokens (Page ${result.page}, ${result.tokens
|
|
233
|
+
\u{1F4CA} Tokens (Page ${result.page}, ${result.tokens?.length ?? 0} of ${result.total ?? 0})
|
|
182
234
|
`));
|
|
183
235
|
const table = new import_cli_table3.default({
|
|
184
236
|
head: [
|
|
@@ -192,16 +244,16 @@ tokensCommand.command("list").description("List all tokens").option("-s, --sort
|
|
|
192
244
|
],
|
|
193
245
|
style: { head: [], border: [] }
|
|
194
246
|
});
|
|
195
|
-
for (const token of result.tokens) {
|
|
247
|
+
for (const token of result.tokens ?? []) {
|
|
196
248
|
const status = token.graduated ? import_chalk2.default.green("\u{1F393} Graduated") : import_chalk2.default.yellow("\u{1F4C8} Bonding");
|
|
197
249
|
table.push([
|
|
198
|
-
import_chalk2.default.bold(token.symbol),
|
|
199
|
-
token.name,
|
|
200
|
-
formatSol(token.price_sol),
|
|
201
|
-
formatSol(token.market_cap_sol),
|
|
250
|
+
import_chalk2.default.bold(token.symbol ?? "???"),
|
|
251
|
+
token.name ?? "Unknown",
|
|
252
|
+
formatSol(token.price_sol ?? 0),
|
|
253
|
+
formatSol(token.market_cap_sol ?? 0),
|
|
202
254
|
token.volume_24h ? formatSol(token.volume_24h) : "-",
|
|
203
255
|
status,
|
|
204
|
-
shortenAddress(token.mint)
|
|
256
|
+
shortenAddress(token.mint ?? "")
|
|
205
257
|
]);
|
|
206
258
|
}
|
|
207
259
|
console.log(table.toString());
|
|
@@ -223,7 +275,6 @@ var import_commander2 = require("commander");
|
|
|
223
275
|
var import_chalk3 = __toESM(require("chalk"));
|
|
224
276
|
var import_cli_table32 = __toESM(require("cli-table3"));
|
|
225
277
|
var fs2 = __toESM(require("fs"));
|
|
226
|
-
var import_sdk3 = require("@clawdvault/sdk");
|
|
227
278
|
var tokenCommand = new import_commander2.Command("token").description("Token operations");
|
|
228
279
|
tokenCommand.command("get <mint>").description("Get token details").option("--json", "Output as JSON").action(async (mint, options) => {
|
|
229
280
|
const spin = spinner("Fetching token...").start();
|
|
@@ -235,18 +286,23 @@ tokenCommand.command("get <mint>").description("Get token details").option("--js
|
|
|
235
286
|
console.log(JSON.stringify(result, null, 2));
|
|
236
287
|
return;
|
|
237
288
|
}
|
|
238
|
-
const
|
|
289
|
+
const token = result.token;
|
|
290
|
+
const trades = result.trades ?? [];
|
|
291
|
+
if (!token) {
|
|
292
|
+
console.log(import_chalk3.default.yellow("Token not found"));
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
239
295
|
console.log(import_chalk3.default.bold(`
|
|
240
|
-
\u{1FA99} ${token.name} (${token.symbol})
|
|
296
|
+
\u{1FA99} ${token.name ?? "Unknown"} (${token.symbol ?? "???"})
|
|
241
297
|
`));
|
|
242
298
|
const table = new import_cli_table32.default({
|
|
243
299
|
style: { head: [], border: [] }
|
|
244
300
|
});
|
|
245
301
|
table.push(
|
|
246
|
-
{ [import_chalk3.default.cyan("Mint")]: token.mint },
|
|
247
|
-
{ [import_chalk3.default.cyan("Creator")]: shortenAddress(token.creator) },
|
|
248
|
-
{ [import_chalk3.default.cyan("Price")]: formatSol(token.price_sol) },
|
|
249
|
-
{ [import_chalk3.default.cyan("Market Cap")]: formatSol(token.market_cap_sol) },
|
|
302
|
+
{ [import_chalk3.default.cyan("Mint")]: token.mint ?? "" },
|
|
303
|
+
{ [import_chalk3.default.cyan("Creator")]: shortenAddress(token.creator ?? "") },
|
|
304
|
+
{ [import_chalk3.default.cyan("Price")]: formatSol(token.price_sol ?? 0) },
|
|
305
|
+
{ [import_chalk3.default.cyan("Market Cap")]: formatSol(token.market_cap_sol ?? 0) },
|
|
250
306
|
{ [import_chalk3.default.cyan("Status")]: token.graduated ? "\u{1F393} Graduated" : "\u{1F4C8} Bonding Curve" }
|
|
251
307
|
);
|
|
252
308
|
if (token.description) {
|
|
@@ -280,10 +336,10 @@ tokenCommand.command("get <mint>").description("Get token details").option("--js
|
|
|
280
336
|
const typeStr = trade.type === "buy" ? import_chalk3.default.green("BUY") : import_chalk3.default.red("SELL");
|
|
281
337
|
tradesTable.push([
|
|
282
338
|
typeStr,
|
|
283
|
-
formatSol(trade.sol_amount),
|
|
284
|
-
formatTokens(trade.token_amount),
|
|
285
|
-
shortenAddress(trade.trader),
|
|
286
|
-
new Date(trade.created_at).toLocaleString()
|
|
339
|
+
formatSol(trade.sol_amount ?? 0),
|
|
340
|
+
formatTokens(trade.token_amount ?? 0),
|
|
341
|
+
shortenAddress(trade.trader ?? ""),
|
|
342
|
+
new Date(trade.created_at ?? Date.now()).toLocaleString()
|
|
287
343
|
]);
|
|
288
344
|
}
|
|
289
345
|
console.log(tradesTable.toString());
|
|
@@ -327,13 +383,13 @@ tokenCommand.command("create").description("Create a new token").requiredOption(
|
|
|
327
383
|
createSpin.stop();
|
|
328
384
|
success(`Token created successfully!`);
|
|
329
385
|
console.log();
|
|
330
|
-
info(`Name: ${result.token
|
|
331
|
-
info(`Symbol: ${result.token
|
|
332
|
-
info(`Mint: ${result.mint}`);
|
|
333
|
-
info(`Signature: ${result.signature}`);
|
|
386
|
+
info(`Name: ${result.token?.name ?? "Unknown"}`);
|
|
387
|
+
info(`Symbol: ${result.token?.symbol ?? "???"}`);
|
|
388
|
+
info(`Mint: ${result.mint ?? ""}`);
|
|
389
|
+
info(`Signature: ${result.signature ?? ""}`);
|
|
334
390
|
console.log();
|
|
335
|
-
info(`Explorer: ${link(result.explorer)}`);
|
|
336
|
-
info(`View: ${link(`https://clawdvault.com/${result.mint}`)}`);
|
|
391
|
+
info(`Explorer: ${link(result.explorer ?? "")}`);
|
|
392
|
+
info(`View: ${link(`https://clawdvault.com/${result.mint ?? ""}`)}`);
|
|
337
393
|
console.log();
|
|
338
394
|
} catch (err) {
|
|
339
395
|
createSpin.stop();
|
|
@@ -353,17 +409,21 @@ tokenCommand.command("stats <mint>").description("Get on-chain stats").option("-
|
|
|
353
409
|
console.log(import_chalk3.default.bold(`
|
|
354
410
|
\u{1F4C8} On-Chain Stats
|
|
355
411
|
`));
|
|
356
|
-
const
|
|
412
|
+
const onChain = result.onChain;
|
|
413
|
+
if (!onChain) {
|
|
414
|
+
console.log(import_chalk3.default.yellow("No on-chain data available"));
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
357
417
|
const table = new import_cli_table32.default({
|
|
358
418
|
style: { head: [], border: [] }
|
|
359
419
|
});
|
|
360
420
|
table.push(
|
|
361
|
-
{ [import_chalk3.default.cyan("Price")]: formatSol(onChain.price) },
|
|
362
|
-
{ [import_chalk3.default.cyan("Market Cap")]: formatSol(onChain.marketCap) },
|
|
363
|
-
{ [import_chalk3.default.cyan("Total Supply")]: formatTokens(onChain.totalSupply) },
|
|
364
|
-
{ [import_chalk3.default.cyan("Circulating")]: formatTokens(onChain.circulatingSupply) },
|
|
365
|
-
{ [import_chalk3.default.cyan("Curve Balance")]: formatTokens(onChain.bondingCurveBalance) },
|
|
366
|
-
{ [import_chalk3.default.cyan("Curve SOL")]: formatSol(onChain.bondingCurveSol) },
|
|
421
|
+
{ [import_chalk3.default.cyan("Price")]: formatSol(onChain.price ?? 0) },
|
|
422
|
+
{ [import_chalk3.default.cyan("Market Cap")]: formatSol(onChain.marketCap ?? 0) },
|
|
423
|
+
{ [import_chalk3.default.cyan("Total Supply")]: formatTokens(onChain.totalSupply ?? 0) },
|
|
424
|
+
{ [import_chalk3.default.cyan("Circulating")]: formatTokens(onChain.circulatingSupply ?? 0) },
|
|
425
|
+
{ [import_chalk3.default.cyan("Curve Balance")]: formatTokens(onChain.bondingCurveBalance ?? 0) },
|
|
426
|
+
{ [import_chalk3.default.cyan("Curve SOL")]: formatSol(onChain.bondingCurveSol ?? 0) },
|
|
367
427
|
{ [import_chalk3.default.cyan("Status")]: onChain.graduated ? "\u{1F393} Graduated" : "\u{1F4C8} Bonding" }
|
|
368
428
|
);
|
|
369
429
|
console.log(table.toString());
|
|
@@ -396,12 +456,12 @@ tokenCommand.command("holders <mint>").description("Get top token holders").opti
|
|
|
396
456
|
],
|
|
397
457
|
style: { head: [], border: [] }
|
|
398
458
|
});
|
|
399
|
-
result.holders.forEach((holder, i) => {
|
|
459
|
+
(result.holders ?? []).forEach((holder, i) => {
|
|
400
460
|
table.push([
|
|
401
461
|
i + 1,
|
|
402
|
-
shortenAddress(holder.address),
|
|
403
|
-
formatTokens(holder.balance),
|
|
404
|
-
`${holder.percentage.toFixed(2)}%`,
|
|
462
|
+
shortenAddress(holder.address ?? ""),
|
|
463
|
+
formatTokens(holder.balance ?? 0),
|
|
464
|
+
`${(holder.percentage ?? 0).toFixed(2)}%`,
|
|
405
465
|
holder.label || "-"
|
|
406
466
|
]);
|
|
407
467
|
});
|
|
@@ -412,86 +472,11 @@ tokenCommand.command("holders <mint>").description("Get top token holders").opti
|
|
|
412
472
|
handleError(err);
|
|
413
473
|
}
|
|
414
474
|
});
|
|
415
|
-
tokenCommand.command("watch <mint>").description("Watch token price in real-time").option("--json", "Output as JSON").action(async (mint, options) => {
|
|
416
|
-
const baseUrl = process.env.CLAWDVAULT_API_URL || "https://clawdvault.com/api";
|
|
417
|
-
console.log(import_chalk3.default.bold(`
|
|
418
|
-
\u{1F4C8} Watching ${shortenAddress(mint)}
|
|
419
|
-
`));
|
|
420
|
-
info(`Connecting to ${baseUrl}...`);
|
|
421
|
-
console.log(import_chalk3.default.dim("Press Ctrl+C to stop\n"));
|
|
422
|
-
const streaming = (0, import_sdk3.createStreaming)(baseUrl);
|
|
423
|
-
const conn = streaming.streamToken(mint);
|
|
424
|
-
const client = createReadOnlyClient();
|
|
425
|
-
let solPrice = 0;
|
|
426
|
-
try {
|
|
427
|
-
const { price } = await client.getSolPrice();
|
|
428
|
-
solPrice = price;
|
|
429
|
-
} catch {
|
|
430
|
-
}
|
|
431
|
-
let tokenInfo = {};
|
|
432
|
-
let lastUpdate = null;
|
|
433
|
-
const displayUpdate = (update) => {
|
|
434
|
-
if (options.json) {
|
|
435
|
-
console.log(JSON.stringify({ ...update, ...tokenInfo }));
|
|
436
|
-
return;
|
|
437
|
-
}
|
|
438
|
-
console.clear();
|
|
439
|
-
console.log(import_chalk3.default.bold(`
|
|
440
|
-
\u{1F4C8} ${tokenInfo.name || "Token"} (${tokenInfo.symbol || shortenAddress(mint)})
|
|
441
|
-
`));
|
|
442
|
-
const table = new import_cli_table32.default({
|
|
443
|
-
style: { head: [], border: [] }
|
|
444
|
-
});
|
|
445
|
-
const priceUsd = solPrice > 0 ? formatUsd(update.price_sol * solPrice) : "-";
|
|
446
|
-
const mcapUsd = solPrice > 0 ? formatUsd(update.market_cap_sol * solPrice) : "-";
|
|
447
|
-
table.push(
|
|
448
|
-
{ [import_chalk3.default.cyan("Price (SOL)")]: formatSol(update.price_sol) },
|
|
449
|
-
{ [import_chalk3.default.cyan("Price (USD)")]: priceUsd },
|
|
450
|
-
{ [import_chalk3.default.cyan("Market Cap (SOL)")]: formatSol(update.market_cap_sol) },
|
|
451
|
-
{ [import_chalk3.default.cyan("Market Cap (USD)")]: mcapUsd },
|
|
452
|
-
{ [import_chalk3.default.cyan("Bonding Curve SOL")]: formatSol(update.real_sol_reserves) },
|
|
453
|
-
{ [import_chalk3.default.cyan("Status")]: update.graduated ? import_chalk3.default.green("\u2713 Graduated") : import_chalk3.default.yellow("Bonding Curve") }
|
|
454
|
-
);
|
|
455
|
-
console.log(table.toString());
|
|
456
|
-
if (lastUpdate && lastUpdate.price_sol !== update.price_sol) {
|
|
457
|
-
const change = (update.price_sol - lastUpdate.price_sol) / lastUpdate.price_sol * 100;
|
|
458
|
-
const changeStr = change >= 0 ? import_chalk3.default.green(`+${change.toFixed(2)}%`) : import_chalk3.default.red(`${change.toFixed(2)}%`);
|
|
459
|
-
console.log(`
|
|
460
|
-
${import_chalk3.default.dim("Last change:")} ${changeStr}`);
|
|
461
|
-
}
|
|
462
|
-
console.log(import_chalk3.default.dim("\nLast update: " + new Date(update.timestamp).toLocaleTimeString()));
|
|
463
|
-
console.log(import_chalk3.default.dim("Press Ctrl+C to stop"));
|
|
464
|
-
lastUpdate = update;
|
|
465
|
-
};
|
|
466
|
-
conn.onConnect(() => success("Connected to stream"));
|
|
467
|
-
conn.onDisconnect(() => warn("Disconnected - reconnecting..."));
|
|
468
|
-
conn.on("connected", (data) => {
|
|
469
|
-
tokenInfo = { name: data.name, symbol: data.symbol };
|
|
470
|
-
displayUpdate(data);
|
|
471
|
-
});
|
|
472
|
-
conn.on("update", displayUpdate);
|
|
473
|
-
conn.on("trade", (trade) => {
|
|
474
|
-
if (lastUpdate) {
|
|
475
|
-
lastUpdate.price_sol = trade.price_sol;
|
|
476
|
-
displayUpdate(lastUpdate);
|
|
477
|
-
}
|
|
478
|
-
});
|
|
479
|
-
conn.connect();
|
|
480
|
-
process.on("SIGINT", () => {
|
|
481
|
-
console.log("\n");
|
|
482
|
-
info("Disconnecting...");
|
|
483
|
-
streaming.disconnectAll();
|
|
484
|
-
process.exit(0);
|
|
485
|
-
});
|
|
486
|
-
await new Promise(() => {
|
|
487
|
-
});
|
|
488
|
-
});
|
|
489
475
|
|
|
490
476
|
// src/commands/trade.ts
|
|
491
477
|
var import_commander3 = require("commander");
|
|
492
478
|
var import_chalk4 = __toESM(require("chalk"));
|
|
493
479
|
var import_cli_table33 = __toESM(require("cli-table3"));
|
|
494
|
-
var import_sdk4 = require("@clawdvault/sdk");
|
|
495
480
|
var tradeCommand = new import_commander3.Command("trade").description("Trading operations");
|
|
496
481
|
tradeCommand.command("buy").description("Buy tokens").requiredOption("-m, --mint <address>", "Token mint address").requiredOption("-a, --sol <amount>", "Amount of SOL to spend").option("-s, --slippage <percent>", "Slippage tolerance (default: 1%)", "1").option("-w, --wallet <path>", "Wallet file path").option("--simulate", "Only simulate, don't execute").action(async (options) => {
|
|
497
482
|
const { client, signer, walletAddress } = createClientWithWallet(options.wallet);
|
|
@@ -510,12 +495,13 @@ tradeCommand.command("buy").description("Buy tokens").requiredOption("-m, --mint
|
|
|
510
495
|
const table = new import_cli_table33.default({
|
|
511
496
|
style: { head: [], border: [] }
|
|
512
497
|
});
|
|
498
|
+
const priceImpact = quote.price_impact ?? 0;
|
|
513
499
|
table.push(
|
|
514
500
|
{ [import_chalk4.default.cyan("Input")]: `${solAmount} SOL` },
|
|
515
|
-
{ [import_chalk4.default.cyan("Output")]: `~${formatTokens(quote.output)} tokens` },
|
|
516
|
-
{ [import_chalk4.default.cyan("Price")]: formatSol(quote.current_price) },
|
|
517
|
-
{ [import_chalk4.default.cyan("Fee")]: formatSol(quote.fee) },
|
|
518
|
-
{ [import_chalk4.default.cyan("Price Impact")]: formatPercent(
|
|
501
|
+
{ [import_chalk4.default.cyan("Output")]: `~${formatTokens(quote.output ?? 0)} tokens` },
|
|
502
|
+
{ [import_chalk4.default.cyan("Price")]: formatSol(quote.current_price ?? 0) },
|
|
503
|
+
{ [import_chalk4.default.cyan("Fee")]: formatSol(quote.fee ?? 0) },
|
|
504
|
+
{ [import_chalk4.default.cyan("Price Impact")]: formatPercent(priceImpact) },
|
|
519
505
|
{ [import_chalk4.default.cyan("Slippage")]: `${(slippage * 100).toFixed(1)}%` }
|
|
520
506
|
);
|
|
521
507
|
console.log(table.toString());
|
|
@@ -523,8 +509,8 @@ tradeCommand.command("buy").description("Buy tokens").requiredOption("-m, --mint
|
|
|
523
509
|
info("Simulation only - no transaction executed");
|
|
524
510
|
return;
|
|
525
511
|
}
|
|
526
|
-
if (
|
|
527
|
-
warn(`High price impact: ${(
|
|
512
|
+
if (priceImpact > 0.05) {
|
|
513
|
+
warn(`High price impact: ${(priceImpact * 100).toFixed(2)}%`);
|
|
528
514
|
}
|
|
529
515
|
console.log();
|
|
530
516
|
const tradeSpin = spinner("Executing trade...").start();
|
|
@@ -540,10 +526,10 @@ tradeCommand.command("buy").description("Buy tokens").requiredOption("-m, --mint
|
|
|
540
526
|
success("Trade executed successfully!");
|
|
541
527
|
console.log();
|
|
542
528
|
info(`Signature: ${result.signature}`);
|
|
543
|
-
info(`SOL spent: ${formatSol(result.trade
|
|
544
|
-
info(`Tokens received: ${formatTokens(result.trade
|
|
529
|
+
info(`SOL spent: ${formatSol(result.trade?.solAmount ?? 0)}`);
|
|
530
|
+
info(`Tokens received: ${formatTokens(result.trade?.tokenAmount ?? 0)}`);
|
|
545
531
|
console.log();
|
|
546
|
-
info(`Explorer: ${link(result.explorer)}`);
|
|
532
|
+
info(`Explorer: ${link(result.explorer ?? "")}`);
|
|
547
533
|
console.log();
|
|
548
534
|
} catch (err) {
|
|
549
535
|
quoteSpin.stop();
|
|
@@ -559,7 +545,8 @@ tradeCommand.command("sell").description("Sell tokens").requiredOption("-m, --mi
|
|
|
559
545
|
const slippage = parseFloat(options.slippage) / 100;
|
|
560
546
|
const balanceSpin = spinner("Checking balance...").start();
|
|
561
547
|
try {
|
|
562
|
-
const { balance } = await client.getMyBalance(options.mint);
|
|
548
|
+
const { balance: rawBalance } = await client.getMyBalance(options.mint);
|
|
549
|
+
const balance = rawBalance ?? 0;
|
|
563
550
|
balanceSpin.stop();
|
|
564
551
|
if (balance <= 0) {
|
|
565
552
|
throw new Error("No tokens to sell");
|
|
@@ -586,12 +573,13 @@ tradeCommand.command("sell").description("Sell tokens").requiredOption("-m, --mi
|
|
|
586
573
|
const table = new import_cli_table33.default({
|
|
587
574
|
style: { head: [], border: [] }
|
|
588
575
|
});
|
|
576
|
+
const sellPriceImpact = quote.price_impact ?? 0;
|
|
589
577
|
table.push(
|
|
590
578
|
{ [import_chalk4.default.cyan("Input")]: `${formatTokens(tokenAmount)} tokens` },
|
|
591
|
-
{ [import_chalk4.default.cyan("Output")]: `~${formatSol(quote.output)}` },
|
|
592
|
-
{ [import_chalk4.default.cyan("Price")]: formatSol(quote.current_price) },
|
|
593
|
-
{ [import_chalk4.default.cyan("Fee")]: formatSol(quote.fee) },
|
|
594
|
-
{ [import_chalk4.default.cyan("Price Impact")]: formatPercent(-
|
|
579
|
+
{ [import_chalk4.default.cyan("Output")]: `~${formatSol(quote.output ?? 0)}` },
|
|
580
|
+
{ [import_chalk4.default.cyan("Price")]: formatSol(quote.current_price ?? 0) },
|
|
581
|
+
{ [import_chalk4.default.cyan("Fee")]: formatSol(quote.fee ?? 0) },
|
|
582
|
+
{ [import_chalk4.default.cyan("Price Impact")]: formatPercent(-sellPriceImpact) },
|
|
595
583
|
{ [import_chalk4.default.cyan("Slippage")]: `${(slippage * 100).toFixed(1)}%` }
|
|
596
584
|
);
|
|
597
585
|
console.log(table.toString());
|
|
@@ -599,8 +587,8 @@ tradeCommand.command("sell").description("Sell tokens").requiredOption("-m, --mi
|
|
|
599
587
|
info("Simulation only - no transaction executed");
|
|
600
588
|
return;
|
|
601
589
|
}
|
|
602
|
-
if (
|
|
603
|
-
warn(`High price impact: ${(
|
|
590
|
+
if (sellPriceImpact > 0.05) {
|
|
591
|
+
warn(`High price impact: ${(sellPriceImpact * 100).toFixed(2)}%`);
|
|
604
592
|
}
|
|
605
593
|
console.log();
|
|
606
594
|
const tradeSpin = spinner("Executing trade...").start();
|
|
@@ -616,10 +604,10 @@ tradeCommand.command("sell").description("Sell tokens").requiredOption("-m, --mi
|
|
|
616
604
|
success("Trade executed successfully!");
|
|
617
605
|
console.log();
|
|
618
606
|
info(`Signature: ${result.signature}`);
|
|
619
|
-
info(`Tokens sold: ${formatTokens(result.trade
|
|
620
|
-
info(`SOL received: ${formatSol(result.trade
|
|
607
|
+
info(`Tokens sold: ${formatTokens(result.trade?.tokenAmount ?? 0)}`);
|
|
608
|
+
info(`SOL received: ${formatSol(result.trade?.solAmount ?? 0)}`);
|
|
621
609
|
console.log();
|
|
622
|
-
info(`Explorer: ${link(result.explorer)}`);
|
|
610
|
+
info(`Explorer: ${link(result.explorer ?? "")}`);
|
|
623
611
|
console.log();
|
|
624
612
|
} catch (err) {
|
|
625
613
|
balanceSpin.stop();
|
|
@@ -647,12 +635,13 @@ tradeCommand.command("quote").description("Get a price quote without executing")
|
|
|
647
635
|
const table = new import_cli_table33.default({
|
|
648
636
|
style: { head: [], border: [] }
|
|
649
637
|
});
|
|
638
|
+
const quotePriceImpact = quote.price_impact ?? 0;
|
|
650
639
|
table.push(
|
|
651
640
|
{ [import_chalk4.default.cyan("Input")]: isBuy ? `${options.amount} SOL` : `${formatTokens(parseFloat(options.amount))} tokens` },
|
|
652
|
-
{ [import_chalk4.default.cyan("Output")]: isBuy ? `~${formatTokens(quote.output)} tokens` : `~${formatSol(quote.output)}` },
|
|
653
|
-
{ [import_chalk4.default.cyan("Price")]: formatSol(quote.current_price) },
|
|
654
|
-
{ [import_chalk4.default.cyan("Fee")]: formatSol(quote.fee) },
|
|
655
|
-
{ [import_chalk4.default.cyan("Price Impact")]: formatPercent(isBuy ?
|
|
641
|
+
{ [import_chalk4.default.cyan("Output")]: isBuy ? `~${formatTokens(quote.output ?? 0)} tokens` : `~${formatSol(quote.output ?? 0)}` },
|
|
642
|
+
{ [import_chalk4.default.cyan("Price")]: formatSol(quote.current_price ?? 0) },
|
|
643
|
+
{ [import_chalk4.default.cyan("Fee")]: formatSol(quote.fee ?? 0) },
|
|
644
|
+
{ [import_chalk4.default.cyan("Price Impact")]: formatPercent(isBuy ? quotePriceImpact : -quotePriceImpact) }
|
|
656
645
|
);
|
|
657
646
|
console.log(table.toString());
|
|
658
647
|
console.log();
|
|
@@ -688,15 +677,15 @@ tradeCommand.command("history").description("Get trade history for a token").req
|
|
|
688
677
|
],
|
|
689
678
|
style: { head: [], border: [] }
|
|
690
679
|
});
|
|
691
|
-
for (const trade of result.trades) {
|
|
680
|
+
for (const trade of result.trades ?? []) {
|
|
692
681
|
const typeStr = trade.type === "buy" ? import_chalk4.default.green("BUY") : import_chalk4.default.red("SELL");
|
|
693
682
|
table.push([
|
|
694
683
|
typeStr,
|
|
695
|
-
formatSol(trade.sol_amount),
|
|
696
|
-
formatTokens(trade.token_amount),
|
|
697
|
-
formatSol(trade.
|
|
698
|
-
shortenAddress(trade.trader),
|
|
699
|
-
new Date(trade.created_at).toLocaleString()
|
|
684
|
+
formatSol(trade.sol_amount ?? 0),
|
|
685
|
+
formatTokens(trade.token_amount ?? 0),
|
|
686
|
+
formatSol(trade.price ?? 0),
|
|
687
|
+
shortenAddress(trade.trader ?? ""),
|
|
688
|
+
new Date(trade.created_at ?? Date.now()).toLocaleString()
|
|
700
689
|
]);
|
|
701
690
|
}
|
|
702
691
|
console.log(table.toString());
|
|
@@ -706,78 +695,6 @@ tradeCommand.command("history").description("Get trade history for a token").req
|
|
|
706
695
|
handleError(err);
|
|
707
696
|
}
|
|
708
697
|
});
|
|
709
|
-
tradeCommand.command("stream").description("Stream trades in real-time").requiredOption("-m, --mint <address>", "Token mint address").option("--json", "Output as JSON (one object per line)").option("--append", "Append mode (simple log format)").action(async (options) => {
|
|
710
|
-
const baseUrl = process.env.CLAWDVAULT_API_URL || "https://clawdvault.com/api";
|
|
711
|
-
console.log(import_chalk4.default.bold(`
|
|
712
|
-
\u{1F4E1} Streaming trades for ${shortenAddress(options.mint)}
|
|
713
|
-
`));
|
|
714
|
-
info(`Connecting to ${baseUrl}...`);
|
|
715
|
-
console.log(import_chalk4.default.dim("Press Ctrl+C to stop\n"));
|
|
716
|
-
const streaming = (0, import_sdk4.createStreaming)(baseUrl);
|
|
717
|
-
const conn = streaming.streamTrades(options.mint);
|
|
718
|
-
const trades = [];
|
|
719
|
-
const MAX_DISPLAY = 20;
|
|
720
|
-
conn.onConnect(() => {
|
|
721
|
-
success("Connected to stream");
|
|
722
|
-
console.log();
|
|
723
|
-
});
|
|
724
|
-
conn.onDisconnect(() => warn("Disconnected - reconnecting..."));
|
|
725
|
-
conn.on("trade", (trade) => {
|
|
726
|
-
if (options.json) {
|
|
727
|
-
console.log(JSON.stringify(trade));
|
|
728
|
-
return;
|
|
729
|
-
}
|
|
730
|
-
if (options.append) {
|
|
731
|
-
const typeStr = trade.type === "buy" ? import_chalk4.default.green("BUY ") : import_chalk4.default.red("SELL");
|
|
732
|
-
const time = new Date(trade.created_at).toLocaleTimeString();
|
|
733
|
-
console.log(
|
|
734
|
-
`${import_chalk4.default.dim(time)} ${typeStr} ${formatSol(trade.sol_amount).padEnd(15)} ${formatTokens(trade.token_amount).padEnd(12)} @ ${formatSol(trade.price_sol).padEnd(18)} ${import_chalk4.default.dim(shortenAddress(trade.trader))}`
|
|
735
|
-
);
|
|
736
|
-
return;
|
|
737
|
-
}
|
|
738
|
-
trades.unshift(trade);
|
|
739
|
-
if (trades.length > MAX_DISPLAY) {
|
|
740
|
-
trades.pop();
|
|
741
|
-
}
|
|
742
|
-
console.clear();
|
|
743
|
-
console.log(import_chalk4.default.bold(`
|
|
744
|
-
\u{1F4E1} Live Trades - ${shortenAddress(options.mint)}
|
|
745
|
-
`));
|
|
746
|
-
const table = new import_cli_table33.default({
|
|
747
|
-
head: [
|
|
748
|
-
import_chalk4.default.cyan("Type"),
|
|
749
|
-
import_chalk4.default.cyan("SOL"),
|
|
750
|
-
import_chalk4.default.cyan("Tokens"),
|
|
751
|
-
import_chalk4.default.cyan("Price"),
|
|
752
|
-
import_chalk4.default.cyan("Trader"),
|
|
753
|
-
import_chalk4.default.cyan("Time")
|
|
754
|
-
],
|
|
755
|
-
style: { head: [], border: [] }
|
|
756
|
-
});
|
|
757
|
-
for (const t of trades) {
|
|
758
|
-
const typeStr = t.type === "buy" ? import_chalk4.default.green("BUY") : import_chalk4.default.red("SELL");
|
|
759
|
-
table.push([
|
|
760
|
-
typeStr,
|
|
761
|
-
formatSol(t.sol_amount),
|
|
762
|
-
formatTokens(t.token_amount),
|
|
763
|
-
formatSol(t.price_sol),
|
|
764
|
-
shortenAddress(t.trader),
|
|
765
|
-
new Date(t.created_at).toLocaleTimeString()
|
|
766
|
-
]);
|
|
767
|
-
}
|
|
768
|
-
console.log(table.toString());
|
|
769
|
-
console.log(import_chalk4.default.dim("\nPress Ctrl+C to stop"));
|
|
770
|
-
});
|
|
771
|
-
conn.connect();
|
|
772
|
-
process.on("SIGINT", () => {
|
|
773
|
-
console.log("\n");
|
|
774
|
-
info("Disconnecting...");
|
|
775
|
-
streaming.disconnectAll();
|
|
776
|
-
process.exit(0);
|
|
777
|
-
});
|
|
778
|
-
await new Promise(() => {
|
|
779
|
-
});
|
|
780
|
-
});
|
|
781
698
|
|
|
782
699
|
// src/commands/wallet.ts
|
|
783
700
|
var import_commander4 = require("commander");
|
|
@@ -860,7 +777,7 @@ walletCommand.command("balance").description("Get wallet balance for a token").r
|
|
|
860
777
|
table.push(
|
|
861
778
|
{ [import_chalk5.default.cyan("Wallet")]: result.wallet },
|
|
862
779
|
{ [import_chalk5.default.cyan("Token")]: result.mint },
|
|
863
|
-
{ [import_chalk5.default.cyan("Balance")]: formatTokens(result.balance) }
|
|
780
|
+
{ [import_chalk5.default.cyan("Balance")]: formatTokens(result.balance ?? 0) }
|
|
864
781
|
);
|
|
865
782
|
console.log(table.toString());
|
|
866
783
|
console.log();
|
|
@@ -925,7 +842,7 @@ walletCommand.command("sol-price").description("Get current SOL/USD price").opti
|
|
|
925
842
|
return;
|
|
926
843
|
}
|
|
927
844
|
console.log(import_chalk5.default.bold(`
|
|
928
|
-
\u{1F4B2} SOL Price: $${result.price.toFixed(2)}
|
|
845
|
+
\u{1F4B2} SOL Price: $${(result.price ?? 0).toFixed(2)}
|
|
929
846
|
`));
|
|
930
847
|
if (result.cached) {
|
|
931
848
|
info(`Cached ${result.age}s ago from ${result.source}`);
|
|
@@ -955,7 +872,7 @@ walletCommand.command("sol-balance").description("Get SOL balance with USD value
|
|
|
955
872
|
let usdValue = 0;
|
|
956
873
|
try {
|
|
957
874
|
const priceData = await client.getSolPrice();
|
|
958
|
-
solPrice = priceData.price;
|
|
875
|
+
solPrice = priceData.price ?? 0;
|
|
959
876
|
usdValue = balanceSol * solPrice;
|
|
960
877
|
} catch {
|
|
961
878
|
}
|
|
@@ -1154,214 +1071,206 @@ walletCommand.command("airdrop").description("Request SOL from devnet faucet (de
|
|
|
1154
1071
|
handleError(err);
|
|
1155
1072
|
}
|
|
1156
1073
|
});
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
}
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
\u{1F4E1} Streaming trades for ${shortenAddress(options.mint)}
|
|
1171
|
-
`));
|
|
1172
|
-
info(`Connecting to ${baseUrl}...`);
|
|
1173
|
-
console.log(import_chalk6.default.dim("Press Ctrl+C to stop\n"));
|
|
1174
|
-
const streaming = (0, import_sdk5.createStreaming)(baseUrl, {
|
|
1175
|
-
autoReconnect: true,
|
|
1176
|
-
reconnectDelay: 3e3
|
|
1177
|
-
});
|
|
1178
|
-
const conn = streaming.streamTrades(options.mint);
|
|
1179
|
-
const trades = [];
|
|
1180
|
-
const MAX_DISPLAY = 20;
|
|
1181
|
-
conn.onConnect(() => {
|
|
1182
|
-
success("Connected to stream");
|
|
1183
|
-
console.log();
|
|
1184
|
-
});
|
|
1185
|
-
conn.onDisconnect(() => {
|
|
1186
|
-
warn("Disconnected - reconnecting...");
|
|
1187
|
-
});
|
|
1188
|
-
conn.onError((err) => {
|
|
1189
|
-
if (!err.message.includes("Max reconnect")) {
|
|
1190
|
-
} else {
|
|
1191
|
-
console.error(import_chalk6.default.red(`Error: ${err.message}`));
|
|
1074
|
+
walletCommand.command("login").description("Login to ClawdVault (get session token)").option("-w, --wallet <path>", "Wallet file path").action(async (options) => {
|
|
1075
|
+
const spin = spinner("Authenticating...").start();
|
|
1076
|
+
try {
|
|
1077
|
+
const signer = loadSigner(options.wallet);
|
|
1078
|
+
requireWallet(signer);
|
|
1079
|
+
const walletAddress = signer.publicKey.toBase58();
|
|
1080
|
+
const { createClient: createClient3 } = require("@clawdvault/sdk");
|
|
1081
|
+
const baseUrl = process.env.CLAWDVAULT_API_URL;
|
|
1082
|
+
const client = createClient3({ signer, baseUrl });
|
|
1083
|
+
const session = await client.createSession();
|
|
1084
|
+
if (!session.token) {
|
|
1085
|
+
spin.stop();
|
|
1086
|
+
error("Failed to get session token");
|
|
1192
1087
|
process.exit(1);
|
|
1193
1088
|
}
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1089
|
+
const expiresInMs = (session.expiresIn || 7 * 24 * 60 * 60) * 1e3;
|
|
1090
|
+
const expiresAt = new Date(Date.now() + expiresInMs).toISOString();
|
|
1091
|
+
saveAuthConfig({
|
|
1092
|
+
sessionToken: session.token,
|
|
1093
|
+
wallet: walletAddress,
|
|
1094
|
+
expiresAt
|
|
1095
|
+
});
|
|
1096
|
+
spin.stop();
|
|
1097
|
+
success("Logged in successfully!");
|
|
1098
|
+
console.log();
|
|
1099
|
+
info(`Wallet: ${walletAddress}`);
|
|
1100
|
+
info(`Session expires: ${new Date(expiresAt).toLocaleString()}`);
|
|
1101
|
+
info(`Config saved to: ${getAuthConfigPath()}`);
|
|
1102
|
+
console.log();
|
|
1103
|
+
} catch (err) {
|
|
1104
|
+
spin.stop();
|
|
1105
|
+
handleError(err);
|
|
1106
|
+
}
|
|
1107
|
+
});
|
|
1108
|
+
walletCommand.command("logout").description("Logout from ClawdVault (clear session token)").action(async () => {
|
|
1109
|
+
try {
|
|
1110
|
+
const authConfig = loadAuthConfig();
|
|
1111
|
+
if (!authConfig) {
|
|
1112
|
+
warn("Not logged in");
|
|
1198
1113
|
return;
|
|
1199
1114
|
}
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1115
|
+
clearAuthConfig();
|
|
1116
|
+
success("Logged out successfully");
|
|
1117
|
+
console.log();
|
|
1118
|
+
} catch (err) {
|
|
1119
|
+
handleError(err);
|
|
1120
|
+
}
|
|
1121
|
+
});
|
|
1122
|
+
walletCommand.command("status").description("Show authentication status").action(async () => {
|
|
1123
|
+
try {
|
|
1124
|
+
const authConfig = loadAuthConfig();
|
|
1125
|
+
console.log(import_chalk5.default.bold("\n\u{1F510} Auth Status\n"));
|
|
1126
|
+
if (!authConfig?.sessionToken) {
|
|
1127
|
+
warn("Not logged in");
|
|
1128
|
+
info("Run: clawdvault wallet login");
|
|
1129
|
+
console.log();
|
|
1206
1130
|
return;
|
|
1207
1131
|
}
|
|
1208
|
-
|
|
1209
|
-
if (trades.length > MAX_DISPLAY) {
|
|
1210
|
-
trades.pop();
|
|
1211
|
-
}
|
|
1212
|
-
console.clear();
|
|
1213
|
-
console.log(import_chalk6.default.bold(`
|
|
1214
|
-
\u{1F4E1} Live Trades - ${shortenAddress(options.mint)}
|
|
1215
|
-
`));
|
|
1216
|
-
const table = new import_cli_table35.default({
|
|
1217
|
-
head: [
|
|
1218
|
-
import_chalk6.default.cyan("Type"),
|
|
1219
|
-
import_chalk6.default.cyan("SOL"),
|
|
1220
|
-
import_chalk6.default.cyan("Tokens"),
|
|
1221
|
-
import_chalk6.default.cyan("Price"),
|
|
1222
|
-
import_chalk6.default.cyan("Trader"),
|
|
1223
|
-
import_chalk6.default.cyan("Time")
|
|
1224
|
-
],
|
|
1132
|
+
const table = new import_cli_table34.default({
|
|
1225
1133
|
style: { head: [], border: [] }
|
|
1226
1134
|
});
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
formatTokens(t.token_amount),
|
|
1233
|
-
formatSol(t.price_sol),
|
|
1234
|
-
shortenAddress(t.trader),
|
|
1235
|
-
new Date(t.created_at).toLocaleTimeString()
|
|
1236
|
-
]);
|
|
1237
|
-
}
|
|
1135
|
+
table.push(
|
|
1136
|
+
{ [import_chalk5.default.cyan("Status")]: import_chalk5.default.green("\u2713 Logged in") },
|
|
1137
|
+
{ [import_chalk5.default.cyan("Wallet")]: authConfig.wallet || "Unknown" },
|
|
1138
|
+
{ [import_chalk5.default.cyan("Expires")]: authConfig.expiresAt ? new Date(authConfig.expiresAt).toLocaleString() : "Unknown" }
|
|
1139
|
+
);
|
|
1238
1140
|
console.log(table.toString());
|
|
1239
|
-
console.log(
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1141
|
+
console.log();
|
|
1142
|
+
const { client } = createClientWithWallet();
|
|
1143
|
+
const spin = spinner("Validating session...").start();
|
|
1144
|
+
try {
|
|
1145
|
+
const validation = await client.validateSession();
|
|
1146
|
+
spin.stop();
|
|
1147
|
+
if (validation.valid) {
|
|
1148
|
+
success("Session is valid");
|
|
1149
|
+
} else {
|
|
1150
|
+
warn("Session may be expired or invalid");
|
|
1151
|
+
info("Run: clawdvault wallet login");
|
|
1152
|
+
}
|
|
1153
|
+
} catch {
|
|
1154
|
+
spin.stop();
|
|
1155
|
+
warn("Could not validate session with server");
|
|
1156
|
+
}
|
|
1157
|
+
console.log();
|
|
1158
|
+
} catch (err) {
|
|
1159
|
+
handleError(err);
|
|
1160
|
+
}
|
|
1250
1161
|
});
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
const streaming = (0, import_sdk5.createStreaming)(baseUrl);
|
|
1259
|
-
const conn = streaming.streamToken(options.mint);
|
|
1260
|
-
const client = createReadOnlyClient();
|
|
1261
|
-
let solPrice = 0;
|
|
1162
|
+
|
|
1163
|
+
// src/commands/chat.ts
|
|
1164
|
+
var import_commander5 = require("commander");
|
|
1165
|
+
var import_chalk6 = __toESM(require("chalk"));
|
|
1166
|
+
var chatCommand = new import_commander5.Command("chat").description("Token chat operations");
|
|
1167
|
+
chatCommand.command("send").description("Send a chat message to a token").requiredOption("-m, --mint <address>", "Token mint address").argument("<message>", "Message to send").option("-w, --wallet <path>", "Wallet file path").option("--reply <id>", "Reply to message ID").option("--json", "Output as JSON").action(async (message, options) => {
|
|
1168
|
+
const spin = spinner("Sending message...").start();
|
|
1262
1169
|
try {
|
|
1263
|
-
const
|
|
1264
|
-
|
|
1265
|
-
|
|
1170
|
+
const auth = requireAuth();
|
|
1171
|
+
const { client, signer, walletAddress } = createClientWithWallet(options.wallet);
|
|
1172
|
+
if (!signer) {
|
|
1173
|
+
spin.stop();
|
|
1174
|
+
warn("Wallet recommended for chat (using session wallet)");
|
|
1175
|
+
}
|
|
1176
|
+
const result = await client.sendChat({
|
|
1177
|
+
mint: options.mint,
|
|
1178
|
+
message,
|
|
1179
|
+
replyTo: options.reply
|
|
1180
|
+
});
|
|
1181
|
+
spin.stop();
|
|
1182
|
+
if (options.json) {
|
|
1183
|
+
console.log(JSON.stringify(result, null, 2));
|
|
1184
|
+
return;
|
|
1185
|
+
}
|
|
1186
|
+
if (result.success) {
|
|
1187
|
+
success("Message sent!");
|
|
1188
|
+
console.log();
|
|
1189
|
+
const msg = result.message;
|
|
1190
|
+
if (msg) {
|
|
1191
|
+
info(`ID: ${msg.id}`);
|
|
1192
|
+
if (msg.created_at) {
|
|
1193
|
+
info(`Time: ${new Date(msg.created_at).toLocaleString()}`);
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1196
|
+
} else {
|
|
1197
|
+
error("Failed to send message");
|
|
1198
|
+
}
|
|
1199
|
+
console.log();
|
|
1200
|
+
} catch (err) {
|
|
1201
|
+
spin.stop();
|
|
1202
|
+
handleError(err);
|
|
1266
1203
|
}
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
const
|
|
1204
|
+
});
|
|
1205
|
+
chatCommand.command("history").description("Get chat history for a token").requiredOption("-m, --mint <address>", "Token mint address").option("-l, --limit <number>", "Number of messages to fetch", "20").option("--before <id>", "Get messages before this ID").option("--json", "Output as JSON").action(async (options) => {
|
|
1206
|
+
const spin = spinner("Fetching messages...").start();
|
|
1207
|
+
try {
|
|
1208
|
+
const { client } = createClientWithWallet();
|
|
1209
|
+
const result = await client.getChat({
|
|
1210
|
+
mint: options.mint,
|
|
1211
|
+
limit: parseInt(options.limit, 10),
|
|
1212
|
+
before: options.before
|
|
1213
|
+
});
|
|
1214
|
+
spin.stop();
|
|
1270
1215
|
if (options.json) {
|
|
1271
|
-
console.log(JSON.stringify(
|
|
1216
|
+
console.log(JSON.stringify(result, null, 2));
|
|
1217
|
+
return;
|
|
1218
|
+
}
|
|
1219
|
+
const messages = result.messages || [];
|
|
1220
|
+
if (messages.length === 0) {
|
|
1221
|
+
info("No messages found");
|
|
1272
1222
|
return;
|
|
1273
1223
|
}
|
|
1274
|
-
console.clear();
|
|
1275
1224
|
console.log(import_chalk6.default.bold(`
|
|
1276
|
-
\u{
|
|
1225
|
+
\u{1F4AC} Chat History - ${shortenAddress(options.mint)}
|
|
1277
1226
|
`));
|
|
1278
|
-
const
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
{ [import_chalk6.default.cyan("Market Cap (SOL)")]: formatSol(update.market_cap_sol) },
|
|
1287
|
-
{ [import_chalk6.default.cyan("Market Cap (USD)")]: mcapUsd },
|
|
1288
|
-
{ [import_chalk6.default.cyan("Bonding Curve SOL")]: formatSol(update.real_sol_reserves) },
|
|
1289
|
-
{ [import_chalk6.default.cyan("Status")]: update.graduated ? import_chalk6.default.green("\u2713 Graduated") : import_chalk6.default.yellow("Bonding Curve") }
|
|
1290
|
-
);
|
|
1291
|
-
console.log(table.toString());
|
|
1292
|
-
if (lastUpdate && lastUpdate.price_sol !== update.price_sol) {
|
|
1293
|
-
const change = (update.price_sol - lastUpdate.price_sol) / lastUpdate.price_sol * 100;
|
|
1294
|
-
const changeStr = change >= 0 ? import_chalk6.default.green(`+${change.toFixed(2)}%`) : import_chalk6.default.red(`${change.toFixed(2)}%`);
|
|
1295
|
-
console.log(`
|
|
1296
|
-
${import_chalk6.default.dim("Last change:")} ${changeStr}`);
|
|
1227
|
+
const sorted = [...messages].reverse();
|
|
1228
|
+
for (const msg of sorted) {
|
|
1229
|
+
const time = msg.created_at ? new Date(msg.created_at).toLocaleTimeString() : "??:??";
|
|
1230
|
+
const sender = msg.username || (msg.wallet ? shortenAddress(msg.wallet) : "unknown");
|
|
1231
|
+
const replyPrefix = msg.reply_to ? import_chalk6.default.dim(`\u21A9 ${shortenAddress(msg.reply_to)} `) : "";
|
|
1232
|
+
console.log(
|
|
1233
|
+
`${import_chalk6.default.dim(time)} ${import_chalk6.default.cyan(sender)}: ${replyPrefix}${msg.message || ""}`
|
|
1234
|
+
);
|
|
1297
1235
|
}
|
|
1298
|
-
console.log(
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
conn.onConnect(() => {
|
|
1303
|
-
success("Connected to stream");
|
|
1304
|
-
});
|
|
1305
|
-
conn.onDisconnect(() => {
|
|
1306
|
-
warn("Disconnected - reconnecting...");
|
|
1307
|
-
});
|
|
1308
|
-
conn.on("connected", (data) => {
|
|
1309
|
-
tokenInfo = { name: data.name, symbol: data.symbol };
|
|
1310
|
-
displayUpdate(data);
|
|
1311
|
-
});
|
|
1312
|
-
conn.on("update", displayUpdate);
|
|
1313
|
-
conn.on("trade", (trade) => {
|
|
1314
|
-
if (lastUpdate) {
|
|
1315
|
-
lastUpdate.price_sol = trade.price_sol;
|
|
1316
|
-
displayUpdate(lastUpdate);
|
|
1236
|
+
console.log();
|
|
1237
|
+
info(`Showing ${messages.length} messages`);
|
|
1238
|
+
if (messages.length > 0) {
|
|
1239
|
+
info(`Use --before ${messages[messages.length - 1]?.id} for older messages`);
|
|
1317
1240
|
}
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
streaming.disconnectAll();
|
|
1324
|
-
process.exit(0);
|
|
1325
|
-
});
|
|
1326
|
-
await new Promise(() => {
|
|
1327
|
-
});
|
|
1241
|
+
console.log();
|
|
1242
|
+
} catch (err) {
|
|
1243
|
+
spin.stop();
|
|
1244
|
+
handleError(err);
|
|
1245
|
+
}
|
|
1328
1246
|
});
|
|
1329
|
-
|
|
1330
|
-
const
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
const conn = streaming.streamChat(options.mint);
|
|
1338
|
-
conn.onConnect(() => {
|
|
1339
|
-
success("Connected to stream");
|
|
1247
|
+
chatCommand.command("react").description("Add reaction to a message").requiredOption("-i, --id <messageId>", "Message ID").requiredOption("-e, --emoji <emoji>", "Emoji to react with").option("-w, --wallet <path>", "Wallet file path").action(async (options) => {
|
|
1248
|
+
const spin = spinner("Adding reaction...").start();
|
|
1249
|
+
try {
|
|
1250
|
+
requireAuth();
|
|
1251
|
+
const { client } = createClientWithWallet(options.wallet);
|
|
1252
|
+
await client.addReaction(options.id, options.emoji);
|
|
1253
|
+
spin.stop();
|
|
1254
|
+
success(`Reacted with ${options.emoji}`);
|
|
1340
1255
|
console.log();
|
|
1341
|
-
})
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
}
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
const
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
);
|
|
1355
|
-
})
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
info("Disconnecting...");
|
|
1360
|
-
streaming.disconnectAll();
|
|
1361
|
-
process.exit(0);
|
|
1362
|
-
});
|
|
1363
|
-
await new Promise(() => {
|
|
1364
|
-
});
|
|
1256
|
+
} catch (err) {
|
|
1257
|
+
spin.stop();
|
|
1258
|
+
handleError(err);
|
|
1259
|
+
}
|
|
1260
|
+
});
|
|
1261
|
+
chatCommand.command("unreact").description("Remove reaction from a message").requiredOption("-i, --id <messageId>", "Message ID").requiredOption("-e, --emoji <emoji>", "Emoji to remove").option("-w, --wallet <path>", "Wallet file path").action(async (options) => {
|
|
1262
|
+
const spin = spinner("Removing reaction...").start();
|
|
1263
|
+
try {
|
|
1264
|
+
requireAuth();
|
|
1265
|
+
const { client } = createClientWithWallet(options.wallet);
|
|
1266
|
+
await client.removeReaction(options.id, options.emoji);
|
|
1267
|
+
spin.stop();
|
|
1268
|
+
success(`Removed ${options.emoji} reaction`);
|
|
1269
|
+
console.log();
|
|
1270
|
+
} catch (err) {
|
|
1271
|
+
spin.stop();
|
|
1272
|
+
handleError(err);
|
|
1273
|
+
}
|
|
1365
1274
|
});
|
|
1366
1275
|
|
|
1367
1276
|
// src/index.ts
|
|
@@ -1371,7 +1280,7 @@ program.addCommand(tokensCommand);
|
|
|
1371
1280
|
program.addCommand(tokenCommand);
|
|
1372
1281
|
program.addCommand(tradeCommand);
|
|
1373
1282
|
program.addCommand(walletCommand);
|
|
1374
|
-
program.addCommand(
|
|
1283
|
+
program.addCommand(chatCommand);
|
|
1375
1284
|
program.hook("preAction", () => {
|
|
1376
1285
|
});
|
|
1377
1286
|
program.configureOutput({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@clawdvault/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "CLI for ClawdVault - Solana token launchpad",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -10,12 +10,12 @@
|
|
|
10
10
|
"dist"
|
|
11
11
|
],
|
|
12
12
|
"scripts": {
|
|
13
|
-
"build": "tsup src/index.ts --format cjs --clean --shims",
|
|
13
|
+
"build": "tsc --noEmit && tsup src/index.ts --format cjs --clean --shims",
|
|
14
14
|
"dev": "tsup src/index.ts --format cjs --watch --shims",
|
|
15
15
|
"clean": "rm -rf dist"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@clawdvault/sdk": "^0.
|
|
18
|
+
"@clawdvault/sdk": "^0.2.0",
|
|
19
19
|
"@solana/spl-token": "^0.4.0",
|
|
20
20
|
"@solana/web3.js": "^1.91.0",
|
|
21
21
|
"bs58": "^5.0.0",
|