@paysponge/sdk 0.1.21 → 0.1.26
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 +7 -3
- package/dist/api/generated/openapi/apis/default-api.d.ts +65 -0
- package/dist/api/generated/openapi/apis/default-api.d.ts.map +1 -1
- package/dist/api/generated/openapi/apis/default-api.js +64 -0
- package/dist/api/generated/openapi/apis/default-api.js.map +1 -1
- package/dist/api/transactions.d.ts +7 -1
- package/dist/api/transactions.d.ts.map +1 -1
- package/dist/api/transactions.js +33 -5
- package/dist/api/transactions.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +614 -96
- package/dist/cli.js.map +1 -1
- package/dist/client.d.ts +7 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +6 -0
- package/dist/client.js.map +1 -1
- package/dist/tools/definitions.d.ts.map +1 -1
- package/dist/tools/definitions.js +37 -1
- package/dist/tools/definitions.js.map +1 -1
- package/dist/tools/executor.d.ts.map +1 -1
- package/dist/tools/executor.js +18 -0
- package/dist/tools/executor.js.map +1 -1
- package/dist/types/schemas.d.ts +23 -3
- package/dist/types/schemas.d.ts.map +1 -1
- package/dist/types/schemas.js +8 -1
- package/dist/types/schemas.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +3 -2
package/dist/cli.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Command, Option } from "commander";
|
|
1
|
+
import { Command, Help, Option } from "commander";
|
|
2
2
|
import * as p from "@clack/prompts";
|
|
3
3
|
import { SpongeWallet } from "./client.js";
|
|
4
4
|
import { deviceFlowAuth } from "./auth/device-flow.js";
|
|
@@ -17,6 +17,8 @@ export function buildCliProgram(metadata = {}) {
|
|
|
17
17
|
.name(cmdName)
|
|
18
18
|
.description(`${pkgName} – CLI for managing agent wallets`)
|
|
19
19
|
.version(`${pkgName} v${version}`, "-v, --version");
|
|
20
|
+
program.showSuggestionAfterError();
|
|
21
|
+
program.showHelpAfterError();
|
|
20
22
|
const shared = (cmd) => cmd
|
|
21
23
|
.option("--base-url <url>", "custom API URL")
|
|
22
24
|
.option("--credentials-path <path>", "custom credentials file path");
|
|
@@ -32,7 +34,10 @@ export function buildCliProgram(metadata = {}) {
|
|
|
32
34
|
.action((opts) => handleInit(opts, metadata));
|
|
33
35
|
withAuth(program
|
|
34
36
|
.command("login")
|
|
35
|
-
.description("Claim a pending agent or authenticate and cache credentials"))
|
|
37
|
+
.description("Claim a pending agent or authenticate and cache credentials"))
|
|
38
|
+
.option("--continue-claim", "open the cached claim URL for the current agent")
|
|
39
|
+
.option("--switch", "replace cached credentials with a new agent login")
|
|
40
|
+
.action((opts) => handleLogin(opts));
|
|
36
41
|
shared(program.command("logout").description("Remove stored credentials")).action((opts) => handleLogout(opts));
|
|
37
42
|
shared(program
|
|
38
43
|
.command("whoami")
|
|
@@ -48,6 +53,7 @@ export function buildCliProgram(metadata = {}) {
|
|
|
48
53
|
.command("advanced")
|
|
49
54
|
.description("Low-level commands mirroring the raw tool surface");
|
|
50
55
|
registerToolCommands(advancedCmd, shared);
|
|
56
|
+
applyHelpTheme(program, metadata);
|
|
51
57
|
return program;
|
|
52
58
|
}
|
|
53
59
|
export async function runCli(args, metadata = {}) {
|
|
@@ -59,7 +65,17 @@ export async function runCli(args, metadata = {}) {
|
|
|
59
65
|
// ---------------------------------------------------------------------------
|
|
60
66
|
async function handleLogin(opts) {
|
|
61
67
|
const creds = loadCredentials(opts.credentialsPath);
|
|
62
|
-
if (
|
|
68
|
+
if (opts.switch) {
|
|
69
|
+
deleteCredentials(opts.credentialsPath);
|
|
70
|
+
}
|
|
71
|
+
if (opts.continueClaim) {
|
|
72
|
+
if (!creds?.claimUrl) {
|
|
73
|
+
throw new Error("No pending claim URL found in cached credentials. Run `spongewallet login --switch` to authenticate a different agent.");
|
|
74
|
+
}
|
|
75
|
+
await continueClaimFlow(creds, opts);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
if (!opts.switch && !process.env.SPONGE_API_KEY && creds?.claimUrl) {
|
|
63
79
|
await continueClaimFlow(creds, opts);
|
|
64
80
|
return;
|
|
65
81
|
}
|
|
@@ -174,6 +190,11 @@ async function handleWhoami(opts, meta) {
|
|
|
174
190
|
lines.push(`Claim Code: ${creds.claimCode}`);
|
|
175
191
|
lines.push(`Credentials: ${getCredentialsPath(opts.credentialsPath)}`);
|
|
176
192
|
p.log.info(lines.join("\n"));
|
|
193
|
+
if (creds.claimUrl) {
|
|
194
|
+
const cmd = meta.commandName ?? "spongewallet";
|
|
195
|
+
p.log.step(`Run \`${cmd} login --continue-claim\` to reopen this claim flow.`);
|
|
196
|
+
p.log.step(`Run \`${cmd} login --switch\` to replace this cached agent with a different one.`);
|
|
197
|
+
}
|
|
177
198
|
}
|
|
178
199
|
async function handleMcpPrint(opts) {
|
|
179
200
|
const wallet = await SpongeWallet.connect({
|
|
@@ -219,8 +240,45 @@ async function continueClaimFlow(creds, opts) {
|
|
|
219
240
|
p.log.step("Could not open browser automatically. Open the claim URL manually.");
|
|
220
241
|
}
|
|
221
242
|
p.log.info("After the browser claim completes, the cached API key will keep working for this agent.");
|
|
243
|
+
p.log.step("To authenticate a different agent, run `spongewallet login --switch`.");
|
|
222
244
|
p.outro("Claim flow ready");
|
|
223
245
|
}
|
|
246
|
+
function requiredInput(command, opts, positional, optionKey, flagName) {
|
|
247
|
+
const fromOption = opts[optionKey];
|
|
248
|
+
const value = positional
|
|
249
|
+
?? (typeof fromOption === "string" ? fromOption : undefined);
|
|
250
|
+
if (!value) {
|
|
251
|
+
command.error(`missing required argument or option: ${flagName}`, {
|
|
252
|
+
exitCode: 1,
|
|
253
|
+
code: "sponge.missing_required_input",
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
return value;
|
|
257
|
+
}
|
|
258
|
+
function isTempoChain(chain) {
|
|
259
|
+
return chain === "tempo" || chain === "tempo-testnet";
|
|
260
|
+
}
|
|
261
|
+
function normalizeTempoTokenSymbol(token, chain) {
|
|
262
|
+
const trimmed = token.trim();
|
|
263
|
+
if (trimmed.startsWith("0x") && trimmed.length === 42) {
|
|
264
|
+
return trimmed;
|
|
265
|
+
}
|
|
266
|
+
const normalized = trimmed.toLowerCase().replace(/[\s_-]/g, "");
|
|
267
|
+
const aliasMap = {
|
|
268
|
+
path: "pathUSD",
|
|
269
|
+
pathusd: "pathUSD",
|
|
270
|
+
alpha: "AlphaUSD",
|
|
271
|
+
alphausd: "AlphaUSD",
|
|
272
|
+
beta: "BetaUSD",
|
|
273
|
+
betausd: "BetaUSD",
|
|
274
|
+
theta: "ThetaUSD",
|
|
275
|
+
thetausd: "ThetaUSD",
|
|
276
|
+
usdc: chain === "tempo" ? "USDC.e" : "pathUSD",
|
|
277
|
+
"usdc.e": chain === "tempo" ? "USDC.e" : "pathUSD",
|
|
278
|
+
usdce: chain === "tempo" ? "USDC.e" : "pathUSD",
|
|
279
|
+
};
|
|
280
|
+
return aliasMap[normalized] ?? trimmed;
|
|
281
|
+
}
|
|
224
282
|
// ---------------------------------------------------------------------------
|
|
225
283
|
// Helpers
|
|
226
284
|
// ---------------------------------------------------------------------------
|
|
@@ -231,6 +289,89 @@ function defaultAgentName(email) {
|
|
|
231
289
|
.replace(/^-+|-+$/g, "");
|
|
232
290
|
return slug ? `agent-${slug}` : "sponge-agent";
|
|
233
291
|
}
|
|
292
|
+
const ANSI_PATTERN = /\u001B\[[0-9;]*m/g;
|
|
293
|
+
const HELP_COLOR_ENABLED = Boolean(!process.env.NO_COLOR
|
|
294
|
+
&& (process.stdout.isTTY || process.env.FORCE_COLOR));
|
|
295
|
+
function ansi(text, open, close = "\u001B[0m") {
|
|
296
|
+
if (!HELP_COLOR_ENABLED)
|
|
297
|
+
return text;
|
|
298
|
+
return `${open}${text}${close}`;
|
|
299
|
+
}
|
|
300
|
+
function stripAnsi(text) {
|
|
301
|
+
return text.replace(ANSI_PATTERN, "");
|
|
302
|
+
}
|
|
303
|
+
function bold(text) {
|
|
304
|
+
return ansi(text, "\u001B[1m");
|
|
305
|
+
}
|
|
306
|
+
function cyan(text) {
|
|
307
|
+
return ansi(text, "\u001B[36m");
|
|
308
|
+
}
|
|
309
|
+
function green(text) {
|
|
310
|
+
return ansi(text, "\u001B[32m");
|
|
311
|
+
}
|
|
312
|
+
function dim(text) {
|
|
313
|
+
return ansi(text, "\u001B[2m");
|
|
314
|
+
}
|
|
315
|
+
function toTitleCase(value) {
|
|
316
|
+
return value
|
|
317
|
+
.split(/[\s-]+/)
|
|
318
|
+
.filter(Boolean)
|
|
319
|
+
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
|
|
320
|
+
.join(" ");
|
|
321
|
+
}
|
|
322
|
+
function commandPath(command) {
|
|
323
|
+
const parts = [];
|
|
324
|
+
let current = command;
|
|
325
|
+
while (current) {
|
|
326
|
+
parts.unshift(current.name());
|
|
327
|
+
current = current.parent ?? null;
|
|
328
|
+
}
|
|
329
|
+
return parts;
|
|
330
|
+
}
|
|
331
|
+
function buildHelpBanner(command, metadata) {
|
|
332
|
+
const path = commandPath(command);
|
|
333
|
+
const rootName = metadata.commandName ?? "spongewallet";
|
|
334
|
+
const title = path.length === 1
|
|
335
|
+
? "Sponge Wallet CLI"
|
|
336
|
+
: `Sponge Wallet ${path.slice(1).map(toTitleCase).join(" ")}`;
|
|
337
|
+
const subtitle = path.length === 1
|
|
338
|
+
? "Manage agent wallets, swaps, payments, and MCP setup."
|
|
339
|
+
: command.description() || `${rootName} command help`;
|
|
340
|
+
const lines = [bold(green(title)), "", dim(subtitle)];
|
|
341
|
+
const width = Math.max(...lines.map((line) => stripAnsi(line).length));
|
|
342
|
+
const top = cyan(`╭${"─".repeat(width + 2)}╮`);
|
|
343
|
+
const bottom = cyan(`╰${"─".repeat(width + 2)}╯`);
|
|
344
|
+
const body = lines.map((line) => {
|
|
345
|
+
const padding = " ".repeat(width - stripAnsi(line).length);
|
|
346
|
+
return `${cyan("│")} ${line}${padding} ${cyan("│")}`;
|
|
347
|
+
});
|
|
348
|
+
return [top, ...body, bottom].join("\n");
|
|
349
|
+
}
|
|
350
|
+
function applyHelpTheme(command, metadata) {
|
|
351
|
+
command.configureHelp({
|
|
352
|
+
commandDescription: () => "",
|
|
353
|
+
styleTitle: (text) => bold(cyan(text)),
|
|
354
|
+
styleCommandText: (text) => bold(green(text)),
|
|
355
|
+
styleSubcommandText: (text) => green(text),
|
|
356
|
+
styleOptionText: (text) => cyan(text),
|
|
357
|
+
styleArgumentText: (text) => bold(text),
|
|
358
|
+
styleDescriptionText: (text) => text,
|
|
359
|
+
formatHelp(cmd, helper) {
|
|
360
|
+
const description = cmd.description();
|
|
361
|
+
const lines = Help.prototype.formatHelp.call(helper, cmd, helper)
|
|
362
|
+
.trimEnd()
|
|
363
|
+
.split("\n");
|
|
364
|
+
if (description && lines[2] === description && lines[3] === "") {
|
|
365
|
+
lines.splice(2, 2);
|
|
366
|
+
}
|
|
367
|
+
const body = lines.join("\n");
|
|
368
|
+
return `${buildHelpBanner(cmd, metadata)}\n\n${body}\n`;
|
|
369
|
+
},
|
|
370
|
+
});
|
|
371
|
+
for (const subcommand of command.commands) {
|
|
372
|
+
applyHelpTheme(subcommand, metadata);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
234
375
|
// ---------------------------------------------------------------------------
|
|
235
376
|
// Curated command tree
|
|
236
377
|
// ---------------------------------------------------------------------------
|
|
@@ -246,12 +387,12 @@ const CHAIN_VALUES = [
|
|
|
246
387
|
];
|
|
247
388
|
const EVM_CHAIN_VALUES = ["ethereum", "base", "sepolia", "base-sepolia"];
|
|
248
389
|
const SOLANA_CHAIN_VALUES = ["solana", "solana-devnet"];
|
|
390
|
+
const TEMPO_CHAIN_VALUES = ["tempo", "tempo-testnet"];
|
|
249
391
|
const ONRAMP_CHAIN_VALUES = ["base", "solana", "polygon"];
|
|
250
392
|
const PAY_CHAIN_VALUES = ["base", "solana", "tempo", "ethereum"];
|
|
251
393
|
const PREFERRED_X402_CHAINS = ["base", "solana", "ethereum"];
|
|
252
394
|
function registerCuratedCommands(program, shared) {
|
|
253
|
-
|
|
254
|
-
shared(walletCmd.command("balance").description("Show wallet balances"))
|
|
395
|
+
shared(program.command("balance").description("Show wallet balances"))
|
|
255
396
|
.addOption(new Option("--chain <chain>", "specific chain").choices([...CHAIN_VALUES, "all"]))
|
|
256
397
|
.option("--allowed-chains <chains>", "comma-separated chain allowlist")
|
|
257
398
|
.option("--only-usdc", "only show USDC balances")
|
|
@@ -264,58 +405,98 @@ function registerCuratedCommands(program, shared) {
|
|
|
264
405
|
});
|
|
265
406
|
displayToolResult(getToolDefinition("get_balance"), data);
|
|
266
407
|
});
|
|
267
|
-
shared(
|
|
268
|
-
.
|
|
269
|
-
.
|
|
270
|
-
.
|
|
271
|
-
.
|
|
272
|
-
.
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
408
|
+
shared(program.command("send").description("Send assets on EVM, Solana, or Tempo"))
|
|
409
|
+
.usage("[chain] [to] [asset] [amount] [options]")
|
|
410
|
+
.argument("[chain]", "destination chain")
|
|
411
|
+
.argument("[to]", "recipient address")
|
|
412
|
+
.argument("[asset]", "currency symbol or token symbol/address")
|
|
413
|
+
.argument("[amount]", "amount to send")
|
|
414
|
+
.option("--chain <chain>", "destination chain")
|
|
415
|
+
.option("--to <address>", "recipient address")
|
|
416
|
+
.option("--amount <amount>", "amount to send")
|
|
417
|
+
.option("--asset <asset>", "currency symbol or token symbol/address")
|
|
418
|
+
.addHelpText("after", "\nExamples:\n spongewallet send base 0xabc... USDC 10\n spongewallet send tempo 0xabc... usdce 1\n")
|
|
419
|
+
.action(async (chainArg, toArg, assetArg, amountArg, opts, command) => {
|
|
420
|
+
const chain = requiredInput(command, opts, chainArg, "chain", "--chain");
|
|
421
|
+
const asset = isTempoChain(chain)
|
|
422
|
+
? normalizeTempoTokenSymbol(requiredInput(command, opts, assetArg, "asset", "--asset"), chain)
|
|
423
|
+
: requiredInput(command, opts, assetArg, "asset", "--asset");
|
|
276
424
|
const input = chain === "tempo" || chain === "tempo-testnet"
|
|
277
|
-
? {
|
|
278
|
-
|
|
425
|
+
? {
|
|
426
|
+
chain,
|
|
427
|
+
to: requiredInput(command, opts, toArg, "to", "--to"),
|
|
428
|
+
amount: requiredInput(command, opts, amountArg, "amount", "--amount"),
|
|
429
|
+
token: asset,
|
|
430
|
+
}
|
|
431
|
+
: {
|
|
432
|
+
chain,
|
|
433
|
+
to: requiredInput(command, opts, toArg, "to", "--to"),
|
|
434
|
+
amount: requiredInput(command, opts, amountArg, "amount", "--amount"),
|
|
435
|
+
currency: asset,
|
|
436
|
+
};
|
|
437
|
+
const wallet = await connectWallet(opts);
|
|
279
438
|
const data = await wallet.transfer(input);
|
|
280
439
|
displayToolResult(getToolDefinition(chain.startsWith("solana") ? "solana_transfer" : "evm_transfer"), data);
|
|
281
440
|
});
|
|
282
|
-
shared(
|
|
441
|
+
shared(program.command("history").description("Show recent transaction history"))
|
|
442
|
+
.usage("[limit] [options]")
|
|
443
|
+
.argument("[limit]", "maximum number of transactions")
|
|
283
444
|
.option("--limit <n>", "maximum number of transactions", parseInt)
|
|
284
445
|
.addOption(new Option("--chain <chain>", "filter by chain").choices(CHAIN_VALUES))
|
|
285
|
-
.
|
|
446
|
+
.addHelpText("after", "\nExamples:\n spongewallet history\n spongewallet history 20 --chain base\n")
|
|
447
|
+
.action(async (limitArg, opts) => {
|
|
286
448
|
const wallet = await connectWallet(opts);
|
|
449
|
+
const limit = limitArg !== undefined
|
|
450
|
+
? parseInt(limitArg, 10)
|
|
451
|
+
: opts.limit;
|
|
287
452
|
const data = await wallet.getTransactionHistoryDetailed({
|
|
288
|
-
limit:
|
|
453
|
+
limit: Number.isFinite(limit) ? limit : undefined,
|
|
289
454
|
chain: opts.chain,
|
|
290
455
|
});
|
|
291
456
|
displayToolResult(getToolDefinition("get_transaction_history"), data);
|
|
292
457
|
});
|
|
293
|
-
shared(
|
|
294
|
-
.
|
|
295
|
-
.
|
|
458
|
+
shared(program.command("tokens").description("List Solana wallet tokens"))
|
|
459
|
+
.usage("[chain] [options]")
|
|
460
|
+
.argument("[chain]", "Solana network")
|
|
461
|
+
.option("--chain <chain>", "Solana network")
|
|
462
|
+
.addHelpText("after", "\nExamples:\n spongewallet tokens\n spongewallet tokens solana-devnet\n")
|
|
463
|
+
.action(async (chainArg, opts) => {
|
|
296
464
|
const wallet = await connectWallet(opts);
|
|
297
|
-
const
|
|
465
|
+
const chain = (chainArg ?? opts.chain ?? "solana");
|
|
466
|
+
const data = await wallet.getSolanaTokens(chain);
|
|
298
467
|
displayToolResult(getToolDefinition("get_solana_tokens"), data);
|
|
299
468
|
});
|
|
300
|
-
shared(
|
|
301
|
-
.
|
|
469
|
+
shared(program.command("search-tokens").description("Search the Solana token list"))
|
|
470
|
+
.usage("[query] [limit] [options]")
|
|
471
|
+
.argument("[query]", "token symbol or name")
|
|
472
|
+
.argument("[limit]", "maximum results")
|
|
473
|
+
.option("--query <query>", "token symbol or name")
|
|
302
474
|
.option("--limit <n>", "maximum results", parseInt)
|
|
303
|
-
.
|
|
475
|
+
.addHelpText("after", "\nExamples:\n spongewallet search-tokens BONK\n spongewallet search-tokens BONK 5\n")
|
|
476
|
+
.action(async (queryArg, limitArg, opts, command) => {
|
|
477
|
+
const limit = limitArg !== undefined
|
|
478
|
+
? parseInt(limitArg, 10)
|
|
479
|
+
: opts.limit;
|
|
480
|
+
const query = requiredInput(command, opts, queryArg, "query", "--query");
|
|
304
481
|
const wallet = await connectWallet(opts);
|
|
305
|
-
const data = await wallet.searchSolanaTokens(
|
|
482
|
+
const data = await wallet.searchSolanaTokens(query, Number.isFinite(limit) ? limit : undefined);
|
|
306
483
|
displayToolResult(getToolDefinition("search_solana_tokens"), data);
|
|
307
484
|
});
|
|
308
|
-
shared(
|
|
309
|
-
.
|
|
485
|
+
shared(program.command("onramp").description("Create a fiat-to-crypto onramp link"))
|
|
486
|
+
.usage("[chain] [fiatAmount] [options]")
|
|
487
|
+
.argument("[chain]", "destination chain")
|
|
488
|
+
.argument("[fiatAmount]", "prefill fiat amount")
|
|
489
|
+
.option("--chain <chain>", "destination chain")
|
|
310
490
|
.option("--wallet-address <address>", "destination wallet address (defaults to agent wallet)")
|
|
311
491
|
.addOption(new Option("--provider <provider>", "onramp provider").choices(["auto", "stripe", "coinbase"]).default("auto"))
|
|
312
492
|
.option("--fiat-amount <amount>", "prefill fiat amount")
|
|
313
493
|
.option("--fiat-currency <code>", "fiat currency code")
|
|
314
494
|
.option("--lock-wallet-address", "lock destination wallet address")
|
|
315
495
|
.option("--redirect-url <url>", "redirect URL after checkout")
|
|
316
|
-
.
|
|
496
|
+
.addHelpText("after", "\nExamples:\n spongewallet onramp\n spongewallet onramp base 100\n spongewallet onramp solana 250 --fiat-currency usd\n")
|
|
497
|
+
.action(async (chainArg, fiatAmountArg, opts) => {
|
|
317
498
|
const wallet = await connectWallet(opts);
|
|
318
|
-
const chain = String(opts.chain ?? "base");
|
|
499
|
+
const chain = String(chainArg ?? opts.chain ?? "base");
|
|
319
500
|
const walletAddress = opts.walletAddress
|
|
320
501
|
?? (await wallet.getAddress(chain))
|
|
321
502
|
?? "";
|
|
@@ -323,7 +504,7 @@ function registerCuratedCommands(program, shared) {
|
|
|
323
504
|
wallet_address: walletAddress,
|
|
324
505
|
chain: chain,
|
|
325
506
|
provider: opts.provider,
|
|
326
|
-
fiat_amount: opts.fiatAmount,
|
|
507
|
+
fiat_amount: (fiatAmountArg ?? opts.fiatAmount),
|
|
327
508
|
fiat_currency: opts.fiatCurrency,
|
|
328
509
|
lock_wallet_address: Boolean(opts.lockWalletAddress),
|
|
329
510
|
redirect_url: opts.redirectUrl,
|
|
@@ -332,11 +513,17 @@ function registerCuratedCommands(program, shared) {
|
|
|
332
513
|
});
|
|
333
514
|
const txCmd = program.command("tx").description("Transaction status and signing");
|
|
334
515
|
shared(txCmd.command("status").description("Check transaction status"))
|
|
335
|
-
.
|
|
336
|
-
.
|
|
337
|
-
.
|
|
516
|
+
.usage("[chain] [txHash] [options]")
|
|
517
|
+
.argument("[chain]", "transaction chain")
|
|
518
|
+
.argument("[txHash]", "transaction hash or signature")
|
|
519
|
+
.option("--tx-hash <hash>", "transaction hash or signature")
|
|
520
|
+
.option("--chain <chain>", "transaction chain")
|
|
521
|
+
.addHelpText("after", "\nExamples:\n spongewallet tx status base 0x123...\n spongewallet tx status solana 5K2...\n")
|
|
522
|
+
.action(async (chainArg, txHashArg, opts, command) => {
|
|
523
|
+
const txHash = requiredInput(command, opts, txHashArg, "txHash", "--tx-hash");
|
|
524
|
+
const chain = requiredInput(command, opts, chainArg, "chain", "--chain");
|
|
338
525
|
const wallet = await connectWallet(opts);
|
|
339
|
-
const data = await wallet.getTransactionStatus(
|
|
526
|
+
const data = await wallet.getTransactionStatus(txHash, chain);
|
|
340
527
|
displayToolResult(getToolDefinition("get_transaction_status"), data);
|
|
341
528
|
});
|
|
342
529
|
shared(txCmd.command("sign").description("Sign a Solana transaction without submitting"))
|
|
@@ -355,70 +542,118 @@ function registerCuratedCommands(program, shared) {
|
|
|
355
542
|
});
|
|
356
543
|
const swapCmd = program.command("swap").description("Quotes and swaps");
|
|
357
544
|
shared(swapCmd.command("solana").description("Swap on Solana"))
|
|
545
|
+
.usage("[from] [to] [amount] [options]")
|
|
546
|
+
.argument("[from]", "input token")
|
|
547
|
+
.argument("[to]", "output token")
|
|
548
|
+
.argument("[amount]", "amount to swap")
|
|
358
549
|
.addOption(new Option("--chain <chain>", "Solana network").choices(SOLANA_CHAIN_VALUES).default("solana"))
|
|
359
|
-
.
|
|
360
|
-
.
|
|
361
|
-
.
|
|
550
|
+
.option("--from <token>", "input token")
|
|
551
|
+
.option("--to <token>", "output token")
|
|
552
|
+
.option("--amount <amount>", "amount to swap")
|
|
362
553
|
.option("--slippage-bps <bps>", "slippage in basis points", parseInt)
|
|
363
|
-
.
|
|
554
|
+
.addHelpText("after", "\nExamples:\n spongewallet swap solana SOL USDC 1\n spongewallet swap solana --chain solana --from SOL --to USDC --amount 1\n")
|
|
555
|
+
.action(async (fromArg, toArg, amountArg, opts, command) => {
|
|
556
|
+
const from = requiredInput(command, opts, fromArg, "from", "--from");
|
|
557
|
+
const to = requiredInput(command, opts, toArg, "to", "--to");
|
|
558
|
+
const amount = requiredInput(command, opts, amountArg, "amount", "--amount");
|
|
364
559
|
const wallet = await connectWallet(opts);
|
|
365
560
|
const data = await wallet.swap({
|
|
366
561
|
chain: opts.chain,
|
|
367
|
-
from
|
|
368
|
-
to
|
|
369
|
-
amount
|
|
562
|
+
from,
|
|
563
|
+
to,
|
|
564
|
+
amount,
|
|
370
565
|
slippageBps: opts.slippageBps,
|
|
371
566
|
});
|
|
372
567
|
displayToolResult(getToolDefinition("solana_swap"), data);
|
|
373
568
|
});
|
|
374
569
|
shared(swapCmd.command("quote").description("Get a Jupiter quote without executing"))
|
|
570
|
+
.usage("[from] [to] [amount] [options]")
|
|
571
|
+
.argument("[from]", "input token")
|
|
572
|
+
.argument("[to]", "output token")
|
|
573
|
+
.argument("[amount]", "amount to quote")
|
|
375
574
|
.addOption(new Option("--chain <chain>", "Solana network").choices(SOLANA_CHAIN_VALUES).default("solana"))
|
|
376
|
-
.
|
|
377
|
-
.
|
|
378
|
-
.
|
|
575
|
+
.option("--from <token>", "input token")
|
|
576
|
+
.option("--to <token>", "output token")
|
|
577
|
+
.option("--amount <amount>", "amount to quote")
|
|
379
578
|
.option("--slippage-bps <bps>", "slippage in basis points", parseInt)
|
|
380
|
-
.
|
|
579
|
+
.addHelpText("after", "\nExamples:\n spongewallet swap quote SOL USDC 1\n spongewallet swap quote --chain solana --from SOL --to USDC --amount 1\n")
|
|
580
|
+
.action(async (fromArg, toArg, amountArg, opts, command) => {
|
|
381
581
|
await executeToolCommand(opts, "jupiter_swap_quote", {
|
|
382
582
|
chain: opts.chain,
|
|
383
|
-
input_token: opts
|
|
384
|
-
output_token: opts
|
|
385
|
-
amount: opts
|
|
583
|
+
input_token: requiredInput(command, opts, fromArg, "from", "--from"),
|
|
584
|
+
output_token: requiredInput(command, opts, toArg, "to", "--to"),
|
|
585
|
+
amount: requiredInput(command, opts, amountArg, "amount", "--amount"),
|
|
386
586
|
slippage_bps: opts.slippageBps,
|
|
387
587
|
});
|
|
388
588
|
});
|
|
389
589
|
shared(swapCmd.command("execute").description("Execute a previously quoted Jupiter swap"))
|
|
390
|
-
.
|
|
391
|
-
.
|
|
590
|
+
.usage("[quoteId] [options]")
|
|
591
|
+
.argument("[quoteId]", "quote ID to execute")
|
|
592
|
+
.option("--quote-id <id>", "quote ID to execute")
|
|
593
|
+
.addHelpText("after", "\nExamples:\n spongewallet swap execute quote_123\n")
|
|
594
|
+
.action(async (quoteIdArg, opts, command) => {
|
|
392
595
|
await executeToolCommand(opts, "jupiter_swap_execute", {
|
|
393
|
-
quote_id:
|
|
596
|
+
quote_id: requiredInput(command, opts, quoteIdArg, "quoteId", "--quote-id"),
|
|
394
597
|
});
|
|
395
598
|
});
|
|
396
599
|
shared(swapCmd.command("base").description("Swap on Base via 0x"))
|
|
397
|
-
.
|
|
398
|
-
.
|
|
399
|
-
.
|
|
600
|
+
.usage("[from] [to] [amount] [options]")
|
|
601
|
+
.argument("[from]", "input token")
|
|
602
|
+
.argument("[to]", "output token")
|
|
603
|
+
.argument("[amount]", "amount to swap")
|
|
604
|
+
.option("--from <token>", "input token")
|
|
605
|
+
.option("--to <token>", "output token")
|
|
606
|
+
.option("--amount <amount>", "amount to swap")
|
|
400
607
|
.option("--slippage-bps <bps>", "slippage in basis points", parseInt)
|
|
401
|
-
.
|
|
608
|
+
.addHelpText("after", "\nExamples:\n spongewallet swap base ETH USDC 0.1\n spongewallet swap base --from ETH --to USDC --amount 0.1\n")
|
|
609
|
+
.action(async (fromArg, toArg, amountArg, opts, command) => {
|
|
402
610
|
await executeToolCommand(opts, "base_swap", {
|
|
403
|
-
input_token: opts
|
|
404
|
-
output_token: opts
|
|
405
|
-
amount: opts
|
|
611
|
+
input_token: requiredInput(command, opts, fromArg, "from", "--from"),
|
|
612
|
+
output_token: requiredInput(command, opts, toArg, "to", "--to"),
|
|
613
|
+
amount: requiredInput(command, opts, amountArg, "amount", "--amount"),
|
|
614
|
+
slippage_bps: opts.slippageBps,
|
|
615
|
+
});
|
|
616
|
+
});
|
|
617
|
+
shared(swapCmd.command("tempo").description("Swap stablecoins on Tempo via native DEX"))
|
|
618
|
+
.usage("[from] [to] [amount] [options]")
|
|
619
|
+
.argument("[from]", "input token")
|
|
620
|
+
.argument("[to]", "output token")
|
|
621
|
+
.argument("[amount]", "amount to swap")
|
|
622
|
+
.addOption(new Option("--chain <chain>", "Tempo network").choices(TEMPO_CHAIN_VALUES).default("tempo"))
|
|
623
|
+
.option("--from <token>", "input token")
|
|
624
|
+
.option("--to <token>", "output token")
|
|
625
|
+
.option("--amount <amount>", "amount to swap")
|
|
626
|
+
.option("--slippage-bps <bps>", "slippage in basis points", parseInt)
|
|
627
|
+
.addHelpText("after", "\nExamples:\n spongewallet swap tempo pathUSD USDC.e 1\n spongewallet swap tempo --chain tempo --from pathUSD --to USDC.e --amount 1\n")
|
|
628
|
+
.action(async (fromArg, toArg, amountArg, opts, command) => {
|
|
629
|
+
const chain = String(opts.chain ?? "tempo");
|
|
630
|
+
await executeToolCommand(opts, "tempo_swap", {
|
|
631
|
+
chain,
|
|
632
|
+
input_token: normalizeTempoTokenSymbol(requiredInput(command, opts, fromArg, "from", "--from"), chain),
|
|
633
|
+
output_token: normalizeTempoTokenSymbol(requiredInput(command, opts, toArg, "to", "--to"), chain),
|
|
634
|
+
amount: requiredInput(command, opts, amountArg, "amount", "--amount"),
|
|
406
635
|
slippage_bps: opts.slippageBps,
|
|
407
636
|
});
|
|
408
637
|
});
|
|
409
638
|
shared(program.command("bridge").description("Bridge assets between chains"))
|
|
410
|
-
.
|
|
411
|
-
.
|
|
412
|
-
.
|
|
413
|
-
.
|
|
639
|
+
.usage("[sourceChain] [destinationChain] [token] [amount] [options]")
|
|
640
|
+
.argument("[sourceChain]", "source chain")
|
|
641
|
+
.argument("[destinationChain]", "destination chain")
|
|
642
|
+
.argument("[token]", "token to bridge")
|
|
643
|
+
.argument("[amount]", "amount to bridge")
|
|
644
|
+
.option("--source-chain <chain>", "source chain")
|
|
645
|
+
.option("--destination-chain <chain>", "destination chain")
|
|
646
|
+
.option("--token <token>", "token to bridge")
|
|
647
|
+
.option("--amount <amount>", "amount to bridge")
|
|
414
648
|
.option("--destination-token <token>", "token to receive on destination")
|
|
415
649
|
.option("--recipient-address <address>", "recipient address on destination")
|
|
416
|
-
.
|
|
650
|
+
.addHelpText("after", "\nExamples:\n spongewallet bridge base solana USDC 25\n spongewallet bridge base hyperliquid USDC 50\n spongewallet bridge --source-chain base --destination-chain polymarket --token USDC --amount 50\n")
|
|
651
|
+
.action(async (sourceChainArg, destinationChainArg, tokenArg, amountArg, opts, command) => {
|
|
417
652
|
await executeToolCommand(opts, "bridge", {
|
|
418
|
-
source_chain: opts
|
|
419
|
-
destination_chain: opts
|
|
420
|
-
token: opts
|
|
421
|
-
amount: opts
|
|
653
|
+
source_chain: requiredInput(command, opts, sourceChainArg, "sourceChain", "--source-chain"),
|
|
654
|
+
destination_chain: requiredInput(command, opts, destinationChainArg, "destinationChain", "--destination-chain"),
|
|
655
|
+
token: requiredInput(command, opts, tokenArg, "token", "--token"),
|
|
656
|
+
amount: requiredInput(command, opts, amountArg, "amount", "--amount"),
|
|
422
657
|
destination_token: opts.destinationToken,
|
|
423
658
|
recipient_address: opts.recipientAddress,
|
|
424
659
|
});
|
|
@@ -479,21 +714,28 @@ function registerCuratedCommands(program, shared) {
|
|
|
479
714
|
await executeToolCommand(opts, "get_key_list", {});
|
|
480
715
|
});
|
|
481
716
|
shared(keysCmd.command("get").description("Get a stored key value"))
|
|
482
|
-
.
|
|
483
|
-
.
|
|
717
|
+
.usage("[service] [options]")
|
|
718
|
+
.argument("[service]", "service name")
|
|
719
|
+
.option("--service <service>", "service name")
|
|
720
|
+
.addHelpText("after", "\nExamples:\n spongewallet keys get openai\n")
|
|
721
|
+
.action(async (serviceArg, opts, command) => {
|
|
484
722
|
await executeToolCommand(opts, "get_key_value", {
|
|
485
|
-
service:
|
|
723
|
+
service: requiredInput(command, opts, serviceArg, "service", "--service"),
|
|
486
724
|
});
|
|
487
725
|
});
|
|
488
726
|
shared(keysCmd.command("set").description("Store a service key"))
|
|
489
|
-
.
|
|
490
|
-
.
|
|
727
|
+
.usage("[service] [key] [options]")
|
|
728
|
+
.argument("[service]", "service name")
|
|
729
|
+
.argument("[key]", "key or secret to store")
|
|
730
|
+
.option("--service <service>", "service name")
|
|
731
|
+
.option("--key <secret>", "key or secret to store")
|
|
491
732
|
.option("--label <label>", "friendly label")
|
|
492
733
|
.option("--metadata <json>", "metadata as JSON", parseJsonObject)
|
|
493
|
-
.
|
|
734
|
+
.addHelpText("after", "\nExamples:\n spongewallet keys set openai sk-... --label primary\n")
|
|
735
|
+
.action(async (serviceArg, keyArg, opts, command) => {
|
|
494
736
|
await executeToolCommand(opts, "store_key", {
|
|
495
|
-
service: opts
|
|
496
|
-
key: opts
|
|
737
|
+
service: requiredInput(command, opts, serviceArg, "service", "--service"),
|
|
738
|
+
key: requiredInput(command, opts, keyArg, "key", "--key"),
|
|
497
739
|
label: opts.label,
|
|
498
740
|
metadata: opts.metadata,
|
|
499
741
|
});
|
|
@@ -560,41 +802,57 @@ function registerCuratedCommands(program, shared) {
|
|
|
560
802
|
displayToolResult(getToolDefinition("submit_plan"), data);
|
|
561
803
|
});
|
|
562
804
|
shared(planCmd.command("approve").description("Approve and execute a submitted plan"))
|
|
563
|
-
.
|
|
564
|
-
.
|
|
805
|
+
.usage("[planId] [options]")
|
|
806
|
+
.argument("[planId]", "plan ID")
|
|
807
|
+
.option("--plan-id <id>", "plan ID")
|
|
808
|
+
.addHelpText("after", "\nExamples:\n spongewallet plan approve plan_123\n")
|
|
809
|
+
.action(async (planIdArg, opts, command) => {
|
|
810
|
+
const planId = requiredInput(command, opts, planIdArg, "planId", "--plan-id");
|
|
565
811
|
const wallet = await connectWallet(opts);
|
|
566
|
-
const data = await wallet.approvePlan(
|
|
812
|
+
const data = await wallet.approvePlan(planId);
|
|
567
813
|
displayToolResult(getToolDefinition("approve_plan"), data);
|
|
568
814
|
});
|
|
569
815
|
const tradeCmd = program.command("trade").description("Single trade proposal flow");
|
|
570
816
|
shared(tradeCmd.command("propose").description("Propose a trade for approval"))
|
|
571
|
-
.
|
|
572
|
-
.
|
|
573
|
-
.
|
|
817
|
+
.usage("[from] [to] [amount] --reason <text> [options]")
|
|
818
|
+
.argument("[from]", "input token")
|
|
819
|
+
.argument("[to]", "output token")
|
|
820
|
+
.argument("[amount]", "amount to trade")
|
|
821
|
+
.option("--from <token>", "input token")
|
|
822
|
+
.option("--to <token>", "output token")
|
|
823
|
+
.option("--amount <amount>", "amount to trade")
|
|
574
824
|
.requiredOption("--reason <text>", "reason shown to the user")
|
|
575
|
-
.
|
|
825
|
+
.addHelpText("after", "\nExamples:\n spongewallet trade propose ETH USDC 0.5 --reason \"Reduce exposure\"\n")
|
|
826
|
+
.action(async (fromArg, toArg, amountArg, opts, command) => {
|
|
827
|
+
const inputToken = requiredInput(command, opts, fromArg, "from", "--from");
|
|
828
|
+
const outputToken = requiredInput(command, opts, toArg, "to", "--to");
|
|
829
|
+
const amount = requiredInput(command, opts, amountArg, "amount", "--amount");
|
|
576
830
|
const wallet = await connectWallet(opts);
|
|
577
831
|
const data = await wallet.proposeTrade({
|
|
578
|
-
input_token:
|
|
579
|
-
output_token:
|
|
580
|
-
amount
|
|
832
|
+
input_token: inputToken,
|
|
833
|
+
output_token: outputToken,
|
|
834
|
+
amount,
|
|
581
835
|
reason: String(opts.reason),
|
|
582
836
|
});
|
|
583
837
|
displayToolResult(getToolDefinition("propose_trade"), data);
|
|
584
838
|
});
|
|
585
839
|
const authCmd = program.command("auth").description("Authentication helpers");
|
|
586
840
|
shared(authCmd.command("siwe").description("Generate a SIWE signature"))
|
|
587
|
-
.
|
|
588
|
-
.
|
|
841
|
+
.usage("[domain] [uri] [options]")
|
|
842
|
+
.argument("[domain]", "requesting domain")
|
|
843
|
+
.argument("[uri]", "resource URI")
|
|
844
|
+
.option("--domain <domain>", "requesting domain")
|
|
845
|
+
.option("--uri <uri>", "resource URI")
|
|
589
846
|
.option("--statement <text>", "human-readable statement")
|
|
590
847
|
.option("--chain-id <id>", "chain ID", parseInt)
|
|
591
848
|
.option("--expiration-time <iso>", "expiration time")
|
|
592
849
|
.option("--not-before <iso>", "not before time")
|
|
593
850
|
.option("--resources <json>", "resources array as JSON", parseJsonValue)
|
|
594
|
-
.
|
|
851
|
+
.addHelpText("after", "\nExamples:\n spongewallet auth siwe app.example.com https://app.example.com\n")
|
|
852
|
+
.action(async (domainArg, uriArg, opts, command) => {
|
|
595
853
|
await executeToolCommand(opts, "generate_siwe", {
|
|
596
|
-
domain: opts
|
|
597
|
-
uri: opts
|
|
854
|
+
domain: requiredInput(command, opts, domainArg, "domain", "--domain"),
|
|
855
|
+
uri: requiredInput(command, opts, uriArg, "uri", "--uri"),
|
|
598
856
|
statement: opts.statement,
|
|
599
857
|
chain_id: opts.chainId,
|
|
600
858
|
expiration_time: opts.expirationTime,
|
|
@@ -603,7 +861,105 @@ function registerCuratedCommands(program, shared) {
|
|
|
603
861
|
});
|
|
604
862
|
});
|
|
605
863
|
const marketCmd = program.command("market").description("Trading venue integrations");
|
|
606
|
-
|
|
864
|
+
const hyperliquidCmd = marketCmd.command("hyperliquid").description("Trade or inspect Hyperliquid");
|
|
865
|
+
shared(hyperliquidCmd.command("status").description("Show Hyperliquid account status"))
|
|
866
|
+
.action(async (opts) => {
|
|
867
|
+
await executeHyperliquidAction(opts, { action: "status" });
|
|
868
|
+
});
|
|
869
|
+
shared(hyperliquidCmd.command("markets").description("List Hyperliquid markets"))
|
|
870
|
+
.usage("[limit] [offset] [options]")
|
|
871
|
+
.argument("[limit]", "result limit")
|
|
872
|
+
.argument("[offset]", "result offset")
|
|
873
|
+
.option("--limit <n>", "result limit", parseInt)
|
|
874
|
+
.option("--offset <n>", "result offset", parseInt)
|
|
875
|
+
.addHelpText("after", "\nExamples:\n spongewallet market hyperliquid markets\n spongewallet market hyperliquid markets 10\n")
|
|
876
|
+
.action(async (limitArg, offsetArg, opts) => {
|
|
877
|
+
await executeHyperliquidAction(opts, {
|
|
878
|
+
action: "markets",
|
|
879
|
+
limit: limitArg !== undefined ? parseInt(limitArg, 10) : opts.limit,
|
|
880
|
+
offset: offsetArg !== undefined ? parseInt(offsetArg, 10) : opts.offset,
|
|
881
|
+
});
|
|
882
|
+
});
|
|
883
|
+
shared(hyperliquidCmd.command("positions").description("List open Hyperliquid positions"))
|
|
884
|
+
.action(async (opts) => {
|
|
885
|
+
await executeHyperliquidAction(opts, { action: "positions" });
|
|
886
|
+
});
|
|
887
|
+
shared(hyperliquidCmd.command("orders").description("List open Hyperliquid orders"))
|
|
888
|
+
.usage("[limit] [offset] [options]")
|
|
889
|
+
.argument("[limit]", "result limit")
|
|
890
|
+
.argument("[offset]", "result offset")
|
|
891
|
+
.option("--limit <n>", "result limit", parseInt)
|
|
892
|
+
.option("--offset <n>", "result offset", parseInt)
|
|
893
|
+
.addHelpText("after", "\nExamples:\n spongewallet market hyperliquid orders\n spongewallet market hyperliquid orders 20\n")
|
|
894
|
+
.action(async (limitArg, offsetArg, opts) => {
|
|
895
|
+
await executeHyperliquidAction(opts, {
|
|
896
|
+
action: "orders",
|
|
897
|
+
limit: limitArg !== undefined ? parseInt(limitArg, 10) : opts.limit,
|
|
898
|
+
offset: offsetArg !== undefined ? parseInt(offsetArg, 10) : opts.offset,
|
|
899
|
+
});
|
|
900
|
+
});
|
|
901
|
+
shared(hyperliquidCmd.command("fills").description("List recent Hyperliquid fills"))
|
|
902
|
+
.usage("[limit] [offset] [options]")
|
|
903
|
+
.argument("[limit]", "result limit")
|
|
904
|
+
.argument("[offset]", "result offset")
|
|
905
|
+
.option("--limit <n>", "result limit", parseInt)
|
|
906
|
+
.option("--offset <n>", "result offset", parseInt)
|
|
907
|
+
.addHelpText("after", "\nExamples:\n spongewallet market hyperliquid fills\n spongewallet market hyperliquid fills 20\n")
|
|
908
|
+
.action(async (limitArg, offsetArg, opts) => {
|
|
909
|
+
await executeHyperliquidAction(opts, {
|
|
910
|
+
action: "fills",
|
|
911
|
+
limit: limitArg !== undefined ? parseInt(limitArg, 10) : opts.limit,
|
|
912
|
+
offset: offsetArg !== undefined ? parseInt(offsetArg, 10) : opts.offset,
|
|
913
|
+
});
|
|
914
|
+
});
|
|
915
|
+
shared(hyperliquidCmd.command("order").description("Place a Hyperliquid order"))
|
|
916
|
+
.argument("[symbol]", "market symbol")
|
|
917
|
+
.argument("[side]", "buy or sell")
|
|
918
|
+
.argument("[type]", "order type")
|
|
919
|
+
.argument("[amount]", "order amount")
|
|
920
|
+
.argument("[price]", "limit price")
|
|
921
|
+
.option("--symbol <symbol>", "market symbol")
|
|
922
|
+
.option("--side <side>", "buy or sell")
|
|
923
|
+
.option("--type <type>", "order type")
|
|
924
|
+
.option("--amount <amount>", "order amount")
|
|
925
|
+
.option("--price <price>", "limit price")
|
|
926
|
+
.addHelpText("after", "\nExamples:\n spongewallet market hyperliquid order ETH buy market 0.1\n spongewallet market hyperliquid order ETH buy limit 0.1 3000\n")
|
|
927
|
+
.action(async (symbolArg, sideArg, typeArg, amountArg, priceArg, opts, command) => {
|
|
928
|
+
await executeHyperliquidAction(opts, {
|
|
929
|
+
action: "order",
|
|
930
|
+
symbol: requiredInput(command, opts, symbolArg, "symbol", "--symbol"),
|
|
931
|
+
side: requiredInput(command, opts, sideArg, "side", "--side"),
|
|
932
|
+
type: requiredInput(command, opts, typeArg, "type", "--type"),
|
|
933
|
+
amount: requiredInput(command, opts, amountArg, "amount", "--amount"),
|
|
934
|
+
price: priceArg ?? opts.price,
|
|
935
|
+
});
|
|
936
|
+
});
|
|
937
|
+
shared(hyperliquidCmd.command("cancel").description("Cancel a Hyperliquid order"))
|
|
938
|
+
.argument("[orderId]", "order ID")
|
|
939
|
+
.option("--order-id <id>", "order ID")
|
|
940
|
+
.action(async (orderIdArg, opts, command) => {
|
|
941
|
+
await executeHyperliquidAction(opts, {
|
|
942
|
+
action: "cancel",
|
|
943
|
+
order_id: requiredInput(command, opts, orderIdArg, "orderId", "--order-id"),
|
|
944
|
+
});
|
|
945
|
+
});
|
|
946
|
+
shared(hyperliquidCmd.command("cancel-all").description("Cancel all Hyperliquid orders"))
|
|
947
|
+
.action(async (opts) => {
|
|
948
|
+
await executeHyperliquidAction(opts, { action: "cancel_all" });
|
|
949
|
+
});
|
|
950
|
+
shared(hyperliquidCmd.command("leverage").description("Set Hyperliquid leverage"))
|
|
951
|
+
.argument("[symbol]", "market symbol")
|
|
952
|
+
.argument("[leverage]", "leverage")
|
|
953
|
+
.option("--symbol <symbol>", "market symbol")
|
|
954
|
+
.option("--leverage <n>", "leverage", parseFloat)
|
|
955
|
+
.action(async (symbolArg, leverageArg, opts, command) => {
|
|
956
|
+
await executeHyperliquidAction(opts, {
|
|
957
|
+
action: "set_leverage",
|
|
958
|
+
symbol: requiredInput(command, opts, symbolArg, "symbol", "--symbol"),
|
|
959
|
+
leverage: leverageArg !== undefined ? parseFloat(leverageArg) : opts.leverage,
|
|
960
|
+
});
|
|
961
|
+
});
|
|
962
|
+
shared(hyperliquidCmd.command("raw").description("Call a raw Hyperliquid action"))
|
|
607
963
|
.requiredOption("--action <action>", "hyperliquid action")
|
|
608
964
|
.option("--symbol <symbol>", "market symbol")
|
|
609
965
|
.option("--side <side>", "buy or sell")
|
|
@@ -616,8 +972,7 @@ function registerCuratedCommands(program, shared) {
|
|
|
616
972
|
.option("--offset <n>", "result offset", parseInt)
|
|
617
973
|
.option("--json <json>", "additional args as JSON", parseJsonObject)
|
|
618
974
|
.action(async (opts) => {
|
|
619
|
-
|
|
620
|
-
const data = await wallet.hyperliquid({
|
|
975
|
+
await executeHyperliquidAction(opts, {
|
|
621
976
|
...opts.json,
|
|
622
977
|
action: String(opts.action),
|
|
623
978
|
symbol: opts.symbol,
|
|
@@ -630,7 +985,6 @@ function registerCuratedCommands(program, shared) {
|
|
|
630
985
|
limit: opts.limit,
|
|
631
986
|
offset: opts.offset,
|
|
632
987
|
});
|
|
633
|
-
displayToolResult(getToolDefinition("hyperliquid"), data);
|
|
634
988
|
});
|
|
635
989
|
}
|
|
636
990
|
async function connectWallet(opts) {
|
|
@@ -639,6 +993,11 @@ async function connectWallet(opts) {
|
|
|
639
993
|
credentialsPath: opts.credentialsPath,
|
|
640
994
|
});
|
|
641
995
|
}
|
|
996
|
+
async function executeHyperliquidAction(opts, input) {
|
|
997
|
+
const wallet = await connectWallet(opts);
|
|
998
|
+
const data = await wallet.hyperliquid(input);
|
|
999
|
+
displayToolResult(getToolDefinition("hyperliquid"), data);
|
|
1000
|
+
}
|
|
642
1001
|
async function executeToolCommand(opts, toolName, input) {
|
|
643
1002
|
const wallet = await connectWallet(opts);
|
|
644
1003
|
const tools = await wallet.tools();
|
|
@@ -792,6 +1151,7 @@ const toolFormatters = {
|
|
|
792
1151
|
const chains = data;
|
|
793
1152
|
const rows = [];
|
|
794
1153
|
let emptyCount = 0;
|
|
1154
|
+
let totalUsd = 0;
|
|
795
1155
|
for (const [chain, info] of Object.entries(chains)) {
|
|
796
1156
|
if (TESTNET_CHAINS.has(chain))
|
|
797
1157
|
continue;
|
|
@@ -806,6 +1166,11 @@ const toolFormatters = {
|
|
|
806
1166
|
amount: b.amount,
|
|
807
1167
|
usd: b.usdValue ? `$${b.usdValue}` : "-",
|
|
808
1168
|
});
|
|
1169
|
+
if (b.usdValue) {
|
|
1170
|
+
const parsed = Number(b.usdValue);
|
|
1171
|
+
if (Number.isFinite(parsed))
|
|
1172
|
+
totalUsd += parsed;
|
|
1173
|
+
}
|
|
809
1174
|
}
|
|
810
1175
|
}
|
|
811
1176
|
if (rows.length === 0) {
|
|
@@ -826,10 +1191,147 @@ const toolFormatters = {
|
|
|
826
1191
|
console.log(row(r.chain, r.token, r.amount, r.usd));
|
|
827
1192
|
}
|
|
828
1193
|
console.log();
|
|
1194
|
+
console.log(` Total: $${totalUsd.toFixed(2)}`);
|
|
1195
|
+
console.log();
|
|
829
1196
|
if (emptyCount > 0) {
|
|
830
1197
|
p.log.step(`${emptyCount} chain${emptyCount !== 1 ? "s" : ""} with no balance`);
|
|
831
1198
|
}
|
|
832
1199
|
},
|
|
1200
|
+
hyperliquid(data) {
|
|
1201
|
+
if (!isRecord(data)) {
|
|
1202
|
+
p.log.success("Hyperliquid");
|
|
1203
|
+
console.log(JSON.stringify(data, null, 2));
|
|
1204
|
+
return;
|
|
1205
|
+
}
|
|
1206
|
+
const action = getValueByKey(data, "tool_call.arguments.action");
|
|
1207
|
+
const title = action
|
|
1208
|
+
? `Hyperliquid ${toTitleCase(String(action).replace(/_/g, " "))}`
|
|
1209
|
+
: "Hyperliquid";
|
|
1210
|
+
if (getValueByKey(data, "address") && isRecord(getValueByKey(data, "balances"))) {
|
|
1211
|
+
const perps = getValueByKey(data, "balances.perps");
|
|
1212
|
+
const spot = getValueByKey(data, "balances.spot");
|
|
1213
|
+
const openOrders = getValueByKey(data, "openOrders");
|
|
1214
|
+
const spotRows = Object.entries(spot ?? {}).map(([symbol, value]) => ({
|
|
1215
|
+
symbol,
|
|
1216
|
+
amount: getValueByKey(value, "amount"),
|
|
1217
|
+
usdValue: getValueByKey(value, "usdValue"),
|
|
1218
|
+
}));
|
|
1219
|
+
p.log.success(title);
|
|
1220
|
+
p.log.info([
|
|
1221
|
+
`Wallet: ${formatInlineValue(getValueByKey(data, "address"))}`,
|
|
1222
|
+
`Perps total: ${formatInlineValue(getValueByKey(perps, "total.USDC"))} USDC`,
|
|
1223
|
+
`Perps free: ${formatInlineValue(getValueByKey(perps, "free.USDC"))} USDC`,
|
|
1224
|
+
`Perps used: ${formatInlineValue(getValueByKey(perps, "used.USDC"))} USDC`,
|
|
1225
|
+
`Spot assets: ${spotRows.length}`,
|
|
1226
|
+
`Open orders: ${formatInlineValue(getValueByKey(data, "openOrderCount"))}`,
|
|
1227
|
+
].join("\n"));
|
|
1228
|
+
if (spotRows.length > 0) {
|
|
1229
|
+
renderTable("Spot balances", [
|
|
1230
|
+
{ key: "symbol", label: "Symbol" },
|
|
1231
|
+
{ key: "amount", label: "Amount" },
|
|
1232
|
+
{ key: "usdValue", label: "USD Value" },
|
|
1233
|
+
], spotRows);
|
|
1234
|
+
}
|
|
1235
|
+
if (Array.isArray(openOrders) && openOrders.length > 0) {
|
|
1236
|
+
renderTable("Open orders", [
|
|
1237
|
+
{ key: "symbol", label: "Symbol" },
|
|
1238
|
+
{ key: "side", label: "Side" },
|
|
1239
|
+
{ key: "price", label: "Price" },
|
|
1240
|
+
{ key: "remaining", label: "Remaining" },
|
|
1241
|
+
{ key: "status", label: "Status" },
|
|
1242
|
+
], openOrders);
|
|
1243
|
+
}
|
|
1244
|
+
return;
|
|
1245
|
+
}
|
|
1246
|
+
const positions = getValueByKey(data, "positions");
|
|
1247
|
+
if (Array.isArray(positions)) {
|
|
1248
|
+
if (positions.length === 0) {
|
|
1249
|
+
p.log.info("No open Hyperliquid positions.");
|
|
1250
|
+
return;
|
|
1251
|
+
}
|
|
1252
|
+
renderTable(title, [
|
|
1253
|
+
{ key: "symbol", label: "Symbol" },
|
|
1254
|
+
{ key: "side", label: "Side" },
|
|
1255
|
+
{ key: "contracts", label: "Size" },
|
|
1256
|
+
{ key: "entryPrice", label: "Entry" },
|
|
1257
|
+
{ key: "markPrice", label: "Mark" },
|
|
1258
|
+
{ key: "leverage", label: "Lev" },
|
|
1259
|
+
{ key: "unrealizedPnl", label: "PnL" },
|
|
1260
|
+
], positions);
|
|
1261
|
+
return;
|
|
1262
|
+
}
|
|
1263
|
+
const orders = getValueByKey(data, "orders");
|
|
1264
|
+
if (Array.isArray(orders)) {
|
|
1265
|
+
if (orders.length === 0) {
|
|
1266
|
+
p.log.info("No open Hyperliquid orders.");
|
|
1267
|
+
return;
|
|
1268
|
+
}
|
|
1269
|
+
renderTable(title, [
|
|
1270
|
+
{ key: "symbol", label: "Symbol" },
|
|
1271
|
+
{ key: "side", label: "Side" },
|
|
1272
|
+
{ key: "price", label: "Price" },
|
|
1273
|
+
{ key: "remaining", label: "Remaining" },
|
|
1274
|
+
{ key: "reduceOnly", label: "Reduce" },
|
|
1275
|
+
{ key: "status", label: "Status" },
|
|
1276
|
+
], orders);
|
|
1277
|
+
return;
|
|
1278
|
+
}
|
|
1279
|
+
const fills = getValueByKey(data, "fills");
|
|
1280
|
+
if (Array.isArray(fills)) {
|
|
1281
|
+
if (fills.length === 0) {
|
|
1282
|
+
p.log.info("No recent Hyperliquid fills.");
|
|
1283
|
+
return;
|
|
1284
|
+
}
|
|
1285
|
+
renderTable(title, [
|
|
1286
|
+
{ key: "symbol", label: "Symbol" },
|
|
1287
|
+
{ key: "side", label: "Side" },
|
|
1288
|
+
{ key: "price", label: "Price" },
|
|
1289
|
+
{ key: "amount", label: "Amount" },
|
|
1290
|
+
{ key: "closedPnl", label: "PnL" },
|
|
1291
|
+
{ key: "datetime", label: "Time" },
|
|
1292
|
+
], fills);
|
|
1293
|
+
return;
|
|
1294
|
+
}
|
|
1295
|
+
const markets = getValueByKey(data, "markets");
|
|
1296
|
+
if (Array.isArray(markets)) {
|
|
1297
|
+
if (markets.length === 0) {
|
|
1298
|
+
p.log.info("No Hyperliquid markets found.");
|
|
1299
|
+
return;
|
|
1300
|
+
}
|
|
1301
|
+
renderTable(title, [
|
|
1302
|
+
{ key: "symbol", label: "Symbol" },
|
|
1303
|
+
{ key: "type", label: "Type" },
|
|
1304
|
+
{ key: "base", label: "Base" },
|
|
1305
|
+
{ key: "quote", label: "Quote" },
|
|
1306
|
+
{ key: "maxLeverage", label: "Max Lev" },
|
|
1307
|
+
], markets);
|
|
1308
|
+
const total = getValueByKey(data, "total");
|
|
1309
|
+
const nextOffset = getValueByKey(data, "nextOffset");
|
|
1310
|
+
if (total !== undefined) {
|
|
1311
|
+
p.log.info(`Showing ${markets.length} of ${formatInlineValue(total)} markets.`);
|
|
1312
|
+
}
|
|
1313
|
+
if (nextOffset !== null && nextOffset !== undefined) {
|
|
1314
|
+
p.log.info(`Next offset: ${formatInlineValue(nextOffset)}`);
|
|
1315
|
+
}
|
|
1316
|
+
return;
|
|
1317
|
+
}
|
|
1318
|
+
const cleanData = Object.fromEntries(Object.entries(data).filter(([key]) => key !== "tool_call"));
|
|
1319
|
+
if (renderFields(title, [
|
|
1320
|
+
{ key: "message", label: "Message" },
|
|
1321
|
+
{ key: "status", label: "Status" },
|
|
1322
|
+
{ key: "orderId", label: "Order ID" },
|
|
1323
|
+
{ key: "clientOrderId", label: "Client Order ID" },
|
|
1324
|
+
{ key: "symbol", label: "Symbol" },
|
|
1325
|
+
{ key: "leverage", label: "Leverage" },
|
|
1326
|
+
{ key: "cancelled", label: "Cancelled" },
|
|
1327
|
+
{ key: "address", label: "Address" },
|
|
1328
|
+
{ key: "webChartUrl", label: "Chart" },
|
|
1329
|
+
], cleanData)) {
|
|
1330
|
+
return;
|
|
1331
|
+
}
|
|
1332
|
+
p.log.success(title);
|
|
1333
|
+
console.log(JSON.stringify(cleanData, null, 2));
|
|
1334
|
+
},
|
|
833
1335
|
};
|
|
834
1336
|
function isRecord(value) {
|
|
835
1337
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -926,9 +1428,25 @@ function renderTxOutput(title, data) {
|
|
|
926
1428
|
if (!isRecord(data))
|
|
927
1429
|
return false;
|
|
928
1430
|
const hash = getValueByKey(data, ["transactionHash", "txHash", "signature"]);
|
|
1431
|
+
const inputAmount = getValueByKey(data, ["inputToken.amount", "input_token.amount"]);
|
|
1432
|
+
const inputSymbol = getValueByKey(data, ["inputToken.symbol", "input_token.symbol"]);
|
|
1433
|
+
const outputAmount = getValueByKey(data, ["outputToken.amount", "output_token.amount"]);
|
|
1434
|
+
const outputSymbol = getValueByKey(data, ["outputToken.symbol", "output_token.symbol"]);
|
|
1435
|
+
const flow = inputAmount && inputSymbol && outputAmount && outputSymbol
|
|
1436
|
+
? `${formatInlineValue(inputAmount)} ${formatInlineValue(inputSymbol)} -> ${formatInlineValue(outputAmount)} ${formatInlineValue(outputSymbol)}`
|
|
1437
|
+
: undefined;
|
|
1438
|
+
const sourceChain = getValueByKey(data, ["sourceChain", "source_chain"]);
|
|
1439
|
+
const destinationChain = getValueByKey(data, ["destinationChain", "destination_chain"]);
|
|
1440
|
+
const route = sourceChain && destinationChain
|
|
1441
|
+
? `${formatInlineValue(sourceChain)} -> ${formatInlineValue(destinationChain)}`
|
|
1442
|
+
: undefined;
|
|
929
1443
|
const lines = [
|
|
1444
|
+
route ? `Route: ${route}` : undefined,
|
|
1445
|
+
flow ? `Flow: ${flow}` : undefined,
|
|
930
1446
|
hash ? `Transaction: ${formatInlineValue(hash)}` : undefined,
|
|
931
1447
|
getValueByKey(data, "status") ? `Status: ${formatInlineValue(getValueByKey(data, "status"))}` : undefined,
|
|
1448
|
+
getValueByKey(data, "priceImpactPct") ? `Price impact: ${formatInlineValue(getValueByKey(data, "priceImpactPct"))}%` : undefined,
|
|
1449
|
+
getValueByKey(data, "gasUsed") ? `Gas used: ${formatInlineValue(getValueByKey(data, "gasUsed"))}` : undefined,
|
|
932
1450
|
getValueByKey(data, "explorerUrl") ? `Explorer: ${formatInlineValue(getValueByKey(data, "explorerUrl"))}` : undefined,
|
|
933
1451
|
getValueByKey(data, "chain") ? `Chain: ${formatInlineValue(getValueByKey(data, "chain"))}` : undefined,
|
|
934
1452
|
getValueByKey(data, "from") ? `Signer: ${formatInlineValue(getValueByKey(data, "from"))}` : undefined,
|