@paysponge/sdk 0.1.21 → 0.1.25
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 +4 -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 +6 -1
- package/dist/api/transactions.d.ts.map +1 -1
- package/dist/api/transactions.js +24 -1
- package/dist/api/transactions.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +579 -93
- 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");
|
|
@@ -48,6 +50,7 @@ export function buildCliProgram(metadata = {}) {
|
|
|
48
50
|
.command("advanced")
|
|
49
51
|
.description("Low-level commands mirroring the raw tool surface");
|
|
50
52
|
registerToolCommands(advancedCmd, shared);
|
|
53
|
+
applyHelpTheme(program, metadata);
|
|
51
54
|
return program;
|
|
52
55
|
}
|
|
53
56
|
export async function runCli(args, metadata = {}) {
|
|
@@ -221,6 +224,39 @@ async function continueClaimFlow(creds, opts) {
|
|
|
221
224
|
p.log.info("After the browser claim completes, the cached API key will keep working for this agent.");
|
|
222
225
|
p.outro("Claim flow ready");
|
|
223
226
|
}
|
|
227
|
+
function requiredInput(opts, positional, optionKey, flagName) {
|
|
228
|
+
const fromOption = opts[optionKey];
|
|
229
|
+
const value = positional
|
|
230
|
+
?? (typeof fromOption === "string" ? fromOption : undefined);
|
|
231
|
+
if (!value) {
|
|
232
|
+
throw new Error(`missing required argument or option: ${flagName}`);
|
|
233
|
+
}
|
|
234
|
+
return value;
|
|
235
|
+
}
|
|
236
|
+
function isTempoChain(chain) {
|
|
237
|
+
return chain === "tempo" || chain === "tempo-testnet";
|
|
238
|
+
}
|
|
239
|
+
function normalizeTempoTokenSymbol(token, chain) {
|
|
240
|
+
const trimmed = token.trim();
|
|
241
|
+
if (trimmed.startsWith("0x") && trimmed.length === 42) {
|
|
242
|
+
return trimmed;
|
|
243
|
+
}
|
|
244
|
+
const normalized = trimmed.toLowerCase().replace(/[\s_-]/g, "");
|
|
245
|
+
const aliasMap = {
|
|
246
|
+
path: "pathUSD",
|
|
247
|
+
pathusd: "pathUSD",
|
|
248
|
+
alpha: "AlphaUSD",
|
|
249
|
+
alphausd: "AlphaUSD",
|
|
250
|
+
beta: "BetaUSD",
|
|
251
|
+
betausd: "BetaUSD",
|
|
252
|
+
theta: "ThetaUSD",
|
|
253
|
+
thetausd: "ThetaUSD",
|
|
254
|
+
usdc: chain === "tempo" ? "USDC.e" : "pathUSD",
|
|
255
|
+
"usdc.e": chain === "tempo" ? "USDC.e" : "pathUSD",
|
|
256
|
+
usdce: chain === "tempo" ? "USDC.e" : "pathUSD",
|
|
257
|
+
};
|
|
258
|
+
return aliasMap[normalized] ?? trimmed;
|
|
259
|
+
}
|
|
224
260
|
// ---------------------------------------------------------------------------
|
|
225
261
|
// Helpers
|
|
226
262
|
// ---------------------------------------------------------------------------
|
|
@@ -231,6 +267,89 @@ function defaultAgentName(email) {
|
|
|
231
267
|
.replace(/^-+|-+$/g, "");
|
|
232
268
|
return slug ? `agent-${slug}` : "sponge-agent";
|
|
233
269
|
}
|
|
270
|
+
const ANSI_PATTERN = /\u001B\[[0-9;]*m/g;
|
|
271
|
+
const HELP_COLOR_ENABLED = Boolean(!process.env.NO_COLOR
|
|
272
|
+
&& (process.stdout.isTTY || process.env.FORCE_COLOR));
|
|
273
|
+
function ansi(text, open, close = "\u001B[0m") {
|
|
274
|
+
if (!HELP_COLOR_ENABLED)
|
|
275
|
+
return text;
|
|
276
|
+
return `${open}${text}${close}`;
|
|
277
|
+
}
|
|
278
|
+
function stripAnsi(text) {
|
|
279
|
+
return text.replace(ANSI_PATTERN, "");
|
|
280
|
+
}
|
|
281
|
+
function bold(text) {
|
|
282
|
+
return ansi(text, "\u001B[1m");
|
|
283
|
+
}
|
|
284
|
+
function cyan(text) {
|
|
285
|
+
return ansi(text, "\u001B[36m");
|
|
286
|
+
}
|
|
287
|
+
function green(text) {
|
|
288
|
+
return ansi(text, "\u001B[32m");
|
|
289
|
+
}
|
|
290
|
+
function dim(text) {
|
|
291
|
+
return ansi(text, "\u001B[2m");
|
|
292
|
+
}
|
|
293
|
+
function toTitleCase(value) {
|
|
294
|
+
return value
|
|
295
|
+
.split(/[\s-]+/)
|
|
296
|
+
.filter(Boolean)
|
|
297
|
+
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
|
|
298
|
+
.join(" ");
|
|
299
|
+
}
|
|
300
|
+
function commandPath(command) {
|
|
301
|
+
const parts = [];
|
|
302
|
+
let current = command;
|
|
303
|
+
while (current) {
|
|
304
|
+
parts.unshift(current.name());
|
|
305
|
+
current = current.parent ?? null;
|
|
306
|
+
}
|
|
307
|
+
return parts;
|
|
308
|
+
}
|
|
309
|
+
function buildHelpBanner(command, metadata) {
|
|
310
|
+
const path = commandPath(command);
|
|
311
|
+
const rootName = metadata.commandName ?? "spongewallet";
|
|
312
|
+
const title = path.length === 1
|
|
313
|
+
? "Sponge Wallet CLI"
|
|
314
|
+
: `Sponge Wallet ${path.slice(1).map(toTitleCase).join(" ")}`;
|
|
315
|
+
const subtitle = path.length === 1
|
|
316
|
+
? "Manage agent wallets, swaps, payments, and MCP setup."
|
|
317
|
+
: command.description() || `${rootName} command help`;
|
|
318
|
+
const lines = [bold(green(title)), "", dim(subtitle)];
|
|
319
|
+
const width = Math.max(...lines.map((line) => stripAnsi(line).length));
|
|
320
|
+
const top = cyan(`╭${"─".repeat(width + 2)}╮`);
|
|
321
|
+
const bottom = cyan(`╰${"─".repeat(width + 2)}╯`);
|
|
322
|
+
const body = lines.map((line) => {
|
|
323
|
+
const padding = " ".repeat(width - stripAnsi(line).length);
|
|
324
|
+
return `${cyan("│")} ${line}${padding} ${cyan("│")}`;
|
|
325
|
+
});
|
|
326
|
+
return [top, ...body, bottom].join("\n");
|
|
327
|
+
}
|
|
328
|
+
function applyHelpTheme(command, metadata) {
|
|
329
|
+
command.configureHelp({
|
|
330
|
+
commandDescription: () => "",
|
|
331
|
+
styleTitle: (text) => bold(cyan(text)),
|
|
332
|
+
styleCommandText: (text) => bold(green(text)),
|
|
333
|
+
styleSubcommandText: (text) => green(text),
|
|
334
|
+
styleOptionText: (text) => cyan(text),
|
|
335
|
+
styleArgumentText: (text) => bold(text),
|
|
336
|
+
styleDescriptionText: (text) => text,
|
|
337
|
+
formatHelp(cmd, helper) {
|
|
338
|
+
const description = cmd.description();
|
|
339
|
+
const lines = Help.prototype.formatHelp.call(helper, cmd, helper)
|
|
340
|
+
.trimEnd()
|
|
341
|
+
.split("\n");
|
|
342
|
+
if (description && lines[2] === description && lines[3] === "") {
|
|
343
|
+
lines.splice(2, 2);
|
|
344
|
+
}
|
|
345
|
+
const body = lines.join("\n");
|
|
346
|
+
return `${buildHelpBanner(cmd, metadata)}\n\n${body}\n`;
|
|
347
|
+
},
|
|
348
|
+
});
|
|
349
|
+
for (const subcommand of command.commands) {
|
|
350
|
+
applyHelpTheme(subcommand, metadata);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
234
353
|
// ---------------------------------------------------------------------------
|
|
235
354
|
// Curated command tree
|
|
236
355
|
// ---------------------------------------------------------------------------
|
|
@@ -246,12 +365,12 @@ const CHAIN_VALUES = [
|
|
|
246
365
|
];
|
|
247
366
|
const EVM_CHAIN_VALUES = ["ethereum", "base", "sepolia", "base-sepolia"];
|
|
248
367
|
const SOLANA_CHAIN_VALUES = ["solana", "solana-devnet"];
|
|
368
|
+
const TEMPO_CHAIN_VALUES = ["tempo", "tempo-testnet"];
|
|
249
369
|
const ONRAMP_CHAIN_VALUES = ["base", "solana", "polygon"];
|
|
250
370
|
const PAY_CHAIN_VALUES = ["base", "solana", "tempo", "ethereum"];
|
|
251
371
|
const PREFERRED_X402_CHAINS = ["base", "solana", "ethereum"];
|
|
252
372
|
function registerCuratedCommands(program, shared) {
|
|
253
|
-
|
|
254
|
-
shared(walletCmd.command("balance").description("Show wallet balances"))
|
|
373
|
+
shared(program.command("balance").description("Show wallet balances"))
|
|
255
374
|
.addOption(new Option("--chain <chain>", "specific chain").choices([...CHAIN_VALUES, "all"]))
|
|
256
375
|
.option("--allowed-chains <chains>", "comma-separated chain allowlist")
|
|
257
376
|
.option("--only-usdc", "only show USDC balances")
|
|
@@ -264,58 +383,97 @@ function registerCuratedCommands(program, shared) {
|
|
|
264
383
|
});
|
|
265
384
|
displayToolResult(getToolDefinition("get_balance"), data);
|
|
266
385
|
});
|
|
267
|
-
shared(
|
|
268
|
-
.
|
|
269
|
-
.
|
|
270
|
-
.
|
|
271
|
-
.
|
|
272
|
-
.
|
|
386
|
+
shared(program.command("send").description("Send assets on EVM, Solana, or Tempo"))
|
|
387
|
+
.usage("<chain> <to> <asset> <amount> [options]")
|
|
388
|
+
.argument("<chain>", "destination chain")
|
|
389
|
+
.argument("<to>", "recipient address")
|
|
390
|
+
.argument("<asset>", "currency symbol or token symbol/address")
|
|
391
|
+
.argument("<amount>", "amount to send")
|
|
392
|
+
.option("--chain <chain>", "destination chain")
|
|
393
|
+
.option("--to <address>", "recipient address")
|
|
394
|
+
.option("--amount <amount>", "amount to send")
|
|
395
|
+
.option("--asset <asset>", "currency symbol or token symbol/address")
|
|
396
|
+
.addHelpText("after", "\nExamples:\n spongewallet send base 0xabc... USDC 10\n spongewallet send tempo 0xabc... usdce 1\n")
|
|
397
|
+
.action(async (chainArg, toArg, assetArg, amountArg, opts) => {
|
|
273
398
|
const wallet = await connectWallet(opts);
|
|
274
|
-
const chain =
|
|
275
|
-
const asset =
|
|
399
|
+
const chain = requiredInput(opts, chainArg, "chain", "--chain");
|
|
400
|
+
const asset = isTempoChain(chain)
|
|
401
|
+
? normalizeTempoTokenSymbol(requiredInput(opts, assetArg, "asset", "--asset"), chain)
|
|
402
|
+
: requiredInput(opts, assetArg, "asset", "--asset");
|
|
276
403
|
const input = chain === "tempo" || chain === "tempo-testnet"
|
|
277
|
-
? {
|
|
278
|
-
|
|
404
|
+
? {
|
|
405
|
+
chain,
|
|
406
|
+
to: requiredInput(opts, toArg, "to", "--to"),
|
|
407
|
+
amount: requiredInput(opts, amountArg, "amount", "--amount"),
|
|
408
|
+
token: asset,
|
|
409
|
+
}
|
|
410
|
+
: {
|
|
411
|
+
chain,
|
|
412
|
+
to: requiredInput(opts, toArg, "to", "--to"),
|
|
413
|
+
amount: requiredInput(opts, amountArg, "amount", "--amount"),
|
|
414
|
+
currency: asset,
|
|
415
|
+
};
|
|
279
416
|
const data = await wallet.transfer(input);
|
|
280
417
|
displayToolResult(getToolDefinition(chain.startsWith("solana") ? "solana_transfer" : "evm_transfer"), data);
|
|
281
418
|
});
|
|
282
|
-
shared(
|
|
419
|
+
shared(program.command("history").description("Show recent transaction history"))
|
|
420
|
+
.usage("[limit] [options]")
|
|
421
|
+
.argument("[limit]", "maximum number of transactions")
|
|
283
422
|
.option("--limit <n>", "maximum number of transactions", parseInt)
|
|
284
423
|
.addOption(new Option("--chain <chain>", "filter by chain").choices(CHAIN_VALUES))
|
|
285
|
-
.
|
|
424
|
+
.addHelpText("after", "\nExamples:\n spongewallet history\n spongewallet history 20 --chain base\n")
|
|
425
|
+
.action(async (limitArg, opts) => {
|
|
286
426
|
const wallet = await connectWallet(opts);
|
|
427
|
+
const limit = limitArg !== undefined
|
|
428
|
+
? parseInt(limitArg, 10)
|
|
429
|
+
: opts.limit;
|
|
287
430
|
const data = await wallet.getTransactionHistoryDetailed({
|
|
288
|
-
limit:
|
|
431
|
+
limit: Number.isFinite(limit) ? limit : undefined,
|
|
289
432
|
chain: opts.chain,
|
|
290
433
|
});
|
|
291
434
|
displayToolResult(getToolDefinition("get_transaction_history"), data);
|
|
292
435
|
});
|
|
293
|
-
shared(
|
|
294
|
-
.
|
|
295
|
-
.
|
|
436
|
+
shared(program.command("tokens").description("List Solana wallet tokens"))
|
|
437
|
+
.usage("[chain] [options]")
|
|
438
|
+
.argument("[chain]", "Solana network")
|
|
439
|
+
.option("--chain <chain>", "Solana network")
|
|
440
|
+
.addHelpText("after", "\nExamples:\n spongewallet tokens\n spongewallet tokens solana-devnet\n")
|
|
441
|
+
.action(async (chainArg, opts) => {
|
|
296
442
|
const wallet = await connectWallet(opts);
|
|
297
|
-
const
|
|
443
|
+
const chain = (chainArg ?? opts.chain ?? "solana");
|
|
444
|
+
const data = await wallet.getSolanaTokens(chain);
|
|
298
445
|
displayToolResult(getToolDefinition("get_solana_tokens"), data);
|
|
299
446
|
});
|
|
300
|
-
shared(
|
|
301
|
-
.
|
|
447
|
+
shared(program.command("search-tokens").description("Search the Solana token list"))
|
|
448
|
+
.usage("<query> [limit] [options]")
|
|
449
|
+
.argument("<query>", "token symbol or name")
|
|
450
|
+
.argument("[limit]", "maximum results")
|
|
451
|
+
.option("--query <query>", "token symbol or name")
|
|
302
452
|
.option("--limit <n>", "maximum results", parseInt)
|
|
303
|
-
.
|
|
453
|
+
.addHelpText("after", "\nExamples:\n spongewallet search-tokens BONK\n spongewallet search-tokens BONK 5\n")
|
|
454
|
+
.action(async (queryArg, limitArg, opts) => {
|
|
304
455
|
const wallet = await connectWallet(opts);
|
|
305
|
-
const
|
|
456
|
+
const limit = limitArg !== undefined
|
|
457
|
+
? parseInt(limitArg, 10)
|
|
458
|
+
: opts.limit;
|
|
459
|
+
const data = await wallet.searchSolanaTokens(requiredInput(opts, queryArg, "query", "--query"), Number.isFinite(limit) ? limit : undefined);
|
|
306
460
|
displayToolResult(getToolDefinition("search_solana_tokens"), data);
|
|
307
461
|
});
|
|
308
|
-
shared(
|
|
309
|
-
.
|
|
462
|
+
shared(program.command("onramp").description("Create a fiat-to-crypto onramp link"))
|
|
463
|
+
.usage("[chain] [fiatAmount] [options]")
|
|
464
|
+
.argument("[chain]", "destination chain")
|
|
465
|
+
.argument("[fiatAmount]", "prefill fiat amount")
|
|
466
|
+
.option("--chain <chain>", "destination chain")
|
|
310
467
|
.option("--wallet-address <address>", "destination wallet address (defaults to agent wallet)")
|
|
311
468
|
.addOption(new Option("--provider <provider>", "onramp provider").choices(["auto", "stripe", "coinbase"]).default("auto"))
|
|
312
469
|
.option("--fiat-amount <amount>", "prefill fiat amount")
|
|
313
470
|
.option("--fiat-currency <code>", "fiat currency code")
|
|
314
471
|
.option("--lock-wallet-address", "lock destination wallet address")
|
|
315
472
|
.option("--redirect-url <url>", "redirect URL after checkout")
|
|
316
|
-
.
|
|
473
|
+
.addHelpText("after", "\nExamples:\n spongewallet onramp\n spongewallet onramp base 100\n spongewallet onramp solana 250 --fiat-currency usd\n")
|
|
474
|
+
.action(async (chainArg, fiatAmountArg, opts) => {
|
|
317
475
|
const wallet = await connectWallet(opts);
|
|
318
|
-
const chain = String(opts.chain ?? "base");
|
|
476
|
+
const chain = String(chainArg ?? opts.chain ?? "base");
|
|
319
477
|
const walletAddress = opts.walletAddress
|
|
320
478
|
?? (await wallet.getAddress(chain))
|
|
321
479
|
?? "";
|
|
@@ -323,7 +481,7 @@ function registerCuratedCommands(program, shared) {
|
|
|
323
481
|
wallet_address: walletAddress,
|
|
324
482
|
chain: chain,
|
|
325
483
|
provider: opts.provider,
|
|
326
|
-
fiat_amount: opts.fiatAmount,
|
|
484
|
+
fiat_amount: (fiatAmountArg ?? opts.fiatAmount),
|
|
327
485
|
fiat_currency: opts.fiatCurrency,
|
|
328
486
|
lock_wallet_address: Boolean(opts.lockWalletAddress),
|
|
329
487
|
redirect_url: opts.redirectUrl,
|
|
@@ -332,11 +490,15 @@ function registerCuratedCommands(program, shared) {
|
|
|
332
490
|
});
|
|
333
491
|
const txCmd = program.command("tx").description("Transaction status and signing");
|
|
334
492
|
shared(txCmd.command("status").description("Check transaction status"))
|
|
335
|
-
.
|
|
336
|
-
.
|
|
337
|
-
.
|
|
493
|
+
.usage("<chain> <txHash> [options]")
|
|
494
|
+
.argument("<chain>", "transaction chain")
|
|
495
|
+
.argument("<txHash>", "transaction hash or signature")
|
|
496
|
+
.option("--tx-hash <hash>", "transaction hash or signature")
|
|
497
|
+
.option("--chain <chain>", "transaction chain")
|
|
498
|
+
.addHelpText("after", "\nExamples:\n spongewallet tx status base 0x123...\n spongewallet tx status solana 5K2...\n")
|
|
499
|
+
.action(async (chainArg, txHashArg, opts) => {
|
|
338
500
|
const wallet = await connectWallet(opts);
|
|
339
|
-
const data = await wallet.getTransactionStatus(
|
|
501
|
+
const data = await wallet.getTransactionStatus(requiredInput(opts, txHashArg, "txHash", "--tx-hash"), requiredInput(opts, chainArg, "chain", "--chain"));
|
|
340
502
|
displayToolResult(getToolDefinition("get_transaction_status"), data);
|
|
341
503
|
});
|
|
342
504
|
shared(txCmd.command("sign").description("Sign a Solana transaction without submitting"))
|
|
@@ -355,70 +517,115 @@ function registerCuratedCommands(program, shared) {
|
|
|
355
517
|
});
|
|
356
518
|
const swapCmd = program.command("swap").description("Quotes and swaps");
|
|
357
519
|
shared(swapCmd.command("solana").description("Swap on Solana"))
|
|
520
|
+
.usage("[from] [to] [amount] [options]")
|
|
521
|
+
.argument("[from]", "input token")
|
|
522
|
+
.argument("[to]", "output token")
|
|
523
|
+
.argument("[amount]", "amount to swap")
|
|
358
524
|
.addOption(new Option("--chain <chain>", "Solana network").choices(SOLANA_CHAIN_VALUES).default("solana"))
|
|
359
|
-
.
|
|
360
|
-
.
|
|
361
|
-
.
|
|
525
|
+
.option("--from <token>", "input token")
|
|
526
|
+
.option("--to <token>", "output token")
|
|
527
|
+
.option("--amount <amount>", "amount to swap")
|
|
362
528
|
.option("--slippage-bps <bps>", "slippage in basis points", parseInt)
|
|
363
|
-
.
|
|
529
|
+
.addHelpText("after", "\nExamples:\n spongewallet swap solana SOL USDC 1\n spongewallet swap solana --chain solana --from SOL --to USDC --amount 1\n")
|
|
530
|
+
.action(async (fromArg, toArg, amountArg, opts) => {
|
|
364
531
|
const wallet = await connectWallet(opts);
|
|
365
532
|
const data = await wallet.swap({
|
|
366
533
|
chain: opts.chain,
|
|
367
|
-
from:
|
|
368
|
-
to:
|
|
369
|
-
amount:
|
|
534
|
+
from: requiredInput(opts, fromArg, "from", "--from"),
|
|
535
|
+
to: requiredInput(opts, toArg, "to", "--to"),
|
|
536
|
+
amount: requiredInput(opts, amountArg, "amount", "--amount"),
|
|
370
537
|
slippageBps: opts.slippageBps,
|
|
371
538
|
});
|
|
372
539
|
displayToolResult(getToolDefinition("solana_swap"), data);
|
|
373
540
|
});
|
|
374
541
|
shared(swapCmd.command("quote").description("Get a Jupiter quote without executing"))
|
|
542
|
+
.usage("[from] [to] [amount] [options]")
|
|
543
|
+
.argument("[from]", "input token")
|
|
544
|
+
.argument("[to]", "output token")
|
|
545
|
+
.argument("[amount]", "amount to quote")
|
|
375
546
|
.addOption(new Option("--chain <chain>", "Solana network").choices(SOLANA_CHAIN_VALUES).default("solana"))
|
|
376
|
-
.
|
|
377
|
-
.
|
|
378
|
-
.
|
|
547
|
+
.option("--from <token>", "input token")
|
|
548
|
+
.option("--to <token>", "output token")
|
|
549
|
+
.option("--amount <amount>", "amount to quote")
|
|
379
550
|
.option("--slippage-bps <bps>", "slippage in basis points", parseInt)
|
|
380
|
-
.
|
|
551
|
+
.addHelpText("after", "\nExamples:\n spongewallet swap quote SOL USDC 1\n spongewallet swap quote --chain solana --from SOL --to USDC --amount 1\n")
|
|
552
|
+
.action(async (fromArg, toArg, amountArg, opts) => {
|
|
381
553
|
await executeToolCommand(opts, "jupiter_swap_quote", {
|
|
382
554
|
chain: opts.chain,
|
|
383
|
-
input_token: opts
|
|
384
|
-
output_token: opts
|
|
385
|
-
amount: opts
|
|
555
|
+
input_token: requiredInput(opts, fromArg, "from", "--from"),
|
|
556
|
+
output_token: requiredInput(opts, toArg, "to", "--to"),
|
|
557
|
+
amount: requiredInput(opts, amountArg, "amount", "--amount"),
|
|
386
558
|
slippage_bps: opts.slippageBps,
|
|
387
559
|
});
|
|
388
560
|
});
|
|
389
561
|
shared(swapCmd.command("execute").description("Execute a previously quoted Jupiter swap"))
|
|
390
|
-
.
|
|
391
|
-
.
|
|
562
|
+
.usage("<quoteId> [options]")
|
|
563
|
+
.argument("<quoteId>", "quote ID to execute")
|
|
564
|
+
.option("--quote-id <id>", "quote ID to execute")
|
|
565
|
+
.addHelpText("after", "\nExamples:\n spongewallet swap execute quote_123\n")
|
|
566
|
+
.action(async (quoteIdArg, opts) => {
|
|
392
567
|
await executeToolCommand(opts, "jupiter_swap_execute", {
|
|
393
|
-
quote_id:
|
|
568
|
+
quote_id: requiredInput(opts, quoteIdArg, "quoteId", "--quote-id"),
|
|
394
569
|
});
|
|
395
570
|
});
|
|
396
571
|
shared(swapCmd.command("base").description("Swap on Base via 0x"))
|
|
397
|
-
.
|
|
398
|
-
.
|
|
399
|
-
.
|
|
572
|
+
.usage("[from] [to] [amount] [options]")
|
|
573
|
+
.argument("[from]", "input token")
|
|
574
|
+
.argument("[to]", "output token")
|
|
575
|
+
.argument("[amount]", "amount to swap")
|
|
576
|
+
.option("--from <token>", "input token")
|
|
577
|
+
.option("--to <token>", "output token")
|
|
578
|
+
.option("--amount <amount>", "amount to swap")
|
|
400
579
|
.option("--slippage-bps <bps>", "slippage in basis points", parseInt)
|
|
401
|
-
.
|
|
580
|
+
.addHelpText("after", "\nExamples:\n spongewallet swap base ETH USDC 0.1\n spongewallet swap base --from ETH --to USDC --amount 0.1\n")
|
|
581
|
+
.action(async (fromArg, toArg, amountArg, opts) => {
|
|
402
582
|
await executeToolCommand(opts, "base_swap", {
|
|
403
|
-
input_token: opts
|
|
404
|
-
output_token: opts
|
|
405
|
-
amount: opts
|
|
583
|
+
input_token: requiredInput(opts, fromArg, "from", "--from"),
|
|
584
|
+
output_token: requiredInput(opts, toArg, "to", "--to"),
|
|
585
|
+
amount: requiredInput(opts, amountArg, "amount", "--amount"),
|
|
586
|
+
slippage_bps: opts.slippageBps,
|
|
587
|
+
});
|
|
588
|
+
});
|
|
589
|
+
shared(swapCmd.command("tempo").description("Swap stablecoins on Tempo via native DEX"))
|
|
590
|
+
.usage("[from] [to] [amount] [options]")
|
|
591
|
+
.argument("[from]", "input token")
|
|
592
|
+
.argument("[to]", "output token")
|
|
593
|
+
.argument("[amount]", "amount to swap")
|
|
594
|
+
.addOption(new Option("--chain <chain>", "Tempo network").choices(TEMPO_CHAIN_VALUES).default("tempo"))
|
|
595
|
+
.option("--from <token>", "input token")
|
|
596
|
+
.option("--to <token>", "output token")
|
|
597
|
+
.option("--amount <amount>", "amount to swap")
|
|
598
|
+
.option("--slippage-bps <bps>", "slippage in basis points", parseInt)
|
|
599
|
+
.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")
|
|
600
|
+
.action(async (fromArg, toArg, amountArg, opts) => {
|
|
601
|
+
const chain = String(opts.chain ?? "tempo");
|
|
602
|
+
await executeToolCommand(opts, "tempo_swap", {
|
|
603
|
+
chain,
|
|
604
|
+
input_token: normalizeTempoTokenSymbol(requiredInput(opts, fromArg, "from", "--from"), chain),
|
|
605
|
+
output_token: normalizeTempoTokenSymbol(requiredInput(opts, toArg, "to", "--to"), chain),
|
|
606
|
+
amount: requiredInput(opts, amountArg, "amount", "--amount"),
|
|
406
607
|
slippage_bps: opts.slippageBps,
|
|
407
608
|
});
|
|
408
609
|
});
|
|
409
610
|
shared(program.command("bridge").description("Bridge assets between chains"))
|
|
410
|
-
.
|
|
411
|
-
.
|
|
412
|
-
.
|
|
413
|
-
.
|
|
611
|
+
.usage("[sourceChain] [destinationChain] [token] [amount] [options]")
|
|
612
|
+
.argument("[sourceChain]", "source chain")
|
|
613
|
+
.argument("[destinationChain]", "destination chain")
|
|
614
|
+
.argument("[token]", "token to bridge")
|
|
615
|
+
.argument("[amount]", "amount to bridge")
|
|
616
|
+
.option("--source-chain <chain>", "source chain")
|
|
617
|
+
.option("--destination-chain <chain>", "destination chain")
|
|
618
|
+
.option("--token <token>", "token to bridge")
|
|
619
|
+
.option("--amount <amount>", "amount to bridge")
|
|
414
620
|
.option("--destination-token <token>", "token to receive on destination")
|
|
415
621
|
.option("--recipient-address <address>", "recipient address on destination")
|
|
416
|
-
.
|
|
622
|
+
.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")
|
|
623
|
+
.action(async (sourceChainArg, destinationChainArg, tokenArg, amountArg, opts) => {
|
|
417
624
|
await executeToolCommand(opts, "bridge", {
|
|
418
|
-
source_chain: opts
|
|
419
|
-
destination_chain: opts
|
|
420
|
-
token: opts
|
|
421
|
-
amount: opts
|
|
625
|
+
source_chain: requiredInput(opts, sourceChainArg, "sourceChain", "--source-chain"),
|
|
626
|
+
destination_chain: requiredInput(opts, destinationChainArg, "destinationChain", "--destination-chain"),
|
|
627
|
+
token: requiredInput(opts, tokenArg, "token", "--token"),
|
|
628
|
+
amount: requiredInput(opts, amountArg, "amount", "--amount"),
|
|
422
629
|
destination_token: opts.destinationToken,
|
|
423
630
|
recipient_address: opts.recipientAddress,
|
|
424
631
|
});
|
|
@@ -479,21 +686,28 @@ function registerCuratedCommands(program, shared) {
|
|
|
479
686
|
await executeToolCommand(opts, "get_key_list", {});
|
|
480
687
|
});
|
|
481
688
|
shared(keysCmd.command("get").description("Get a stored key value"))
|
|
482
|
-
.
|
|
483
|
-
.
|
|
689
|
+
.usage("<service> [options]")
|
|
690
|
+
.argument("<service>", "service name")
|
|
691
|
+
.option("--service <service>", "service name")
|
|
692
|
+
.addHelpText("after", "\nExamples:\n spongewallet keys get openai\n")
|
|
693
|
+
.action(async (serviceArg, opts) => {
|
|
484
694
|
await executeToolCommand(opts, "get_key_value", {
|
|
485
|
-
service:
|
|
695
|
+
service: requiredInput(opts, serviceArg, "service", "--service"),
|
|
486
696
|
});
|
|
487
697
|
});
|
|
488
698
|
shared(keysCmd.command("set").description("Store a service key"))
|
|
489
|
-
.
|
|
490
|
-
.
|
|
699
|
+
.usage("<service> <key> [options]")
|
|
700
|
+
.argument("<service>", "service name")
|
|
701
|
+
.argument("<key>", "key or secret to store")
|
|
702
|
+
.option("--service <service>", "service name")
|
|
703
|
+
.option("--key <secret>", "key or secret to store")
|
|
491
704
|
.option("--label <label>", "friendly label")
|
|
492
705
|
.option("--metadata <json>", "metadata as JSON", parseJsonObject)
|
|
493
|
-
.
|
|
706
|
+
.addHelpText("after", "\nExamples:\n spongewallet keys set openai sk-... --label primary\n")
|
|
707
|
+
.action(async (serviceArg, keyArg, opts) => {
|
|
494
708
|
await executeToolCommand(opts, "store_key", {
|
|
495
|
-
service: opts
|
|
496
|
-
key: opts
|
|
709
|
+
service: requiredInput(opts, serviceArg, "service", "--service"),
|
|
710
|
+
key: requiredInput(opts, keyArg, "key", "--key"),
|
|
497
711
|
label: opts.label,
|
|
498
712
|
metadata: opts.metadata,
|
|
499
713
|
});
|
|
@@ -560,41 +774,53 @@ function registerCuratedCommands(program, shared) {
|
|
|
560
774
|
displayToolResult(getToolDefinition("submit_plan"), data);
|
|
561
775
|
});
|
|
562
776
|
shared(planCmd.command("approve").description("Approve and execute a submitted plan"))
|
|
563
|
-
.
|
|
564
|
-
.
|
|
777
|
+
.usage("<planId> [options]")
|
|
778
|
+
.argument("<planId>", "plan ID")
|
|
779
|
+
.option("--plan-id <id>", "plan ID")
|
|
780
|
+
.addHelpText("after", "\nExamples:\n spongewallet plan approve plan_123\n")
|
|
781
|
+
.action(async (planIdArg, opts) => {
|
|
565
782
|
const wallet = await connectWallet(opts);
|
|
566
|
-
const data = await wallet.approvePlan(
|
|
783
|
+
const data = await wallet.approvePlan(requiredInput(opts, planIdArg, "planId", "--plan-id"));
|
|
567
784
|
displayToolResult(getToolDefinition("approve_plan"), data);
|
|
568
785
|
});
|
|
569
786
|
const tradeCmd = program.command("trade").description("Single trade proposal flow");
|
|
570
787
|
shared(tradeCmd.command("propose").description("Propose a trade for approval"))
|
|
571
|
-
.
|
|
572
|
-
.
|
|
573
|
-
.
|
|
788
|
+
.usage("<from> <to> <amount> --reason <text> [options]")
|
|
789
|
+
.argument("<from>", "input token")
|
|
790
|
+
.argument("<to>", "output token")
|
|
791
|
+
.argument("<amount>", "amount to trade")
|
|
792
|
+
.option("--from <token>", "input token")
|
|
793
|
+
.option("--to <token>", "output token")
|
|
794
|
+
.option("--amount <amount>", "amount to trade")
|
|
574
795
|
.requiredOption("--reason <text>", "reason shown to the user")
|
|
575
|
-
.
|
|
796
|
+
.addHelpText("after", "\nExamples:\n spongewallet trade propose ETH USDC 0.5 --reason \"Reduce exposure\"\n")
|
|
797
|
+
.action(async (fromArg, toArg, amountArg, opts) => {
|
|
576
798
|
const wallet = await connectWallet(opts);
|
|
577
799
|
const data = await wallet.proposeTrade({
|
|
578
|
-
input_token:
|
|
579
|
-
output_token:
|
|
580
|
-
amount:
|
|
800
|
+
input_token: requiredInput(opts, fromArg, "from", "--from"),
|
|
801
|
+
output_token: requiredInput(opts, toArg, "to", "--to"),
|
|
802
|
+
amount: requiredInput(opts, amountArg, "amount", "--amount"),
|
|
581
803
|
reason: String(opts.reason),
|
|
582
804
|
});
|
|
583
805
|
displayToolResult(getToolDefinition("propose_trade"), data);
|
|
584
806
|
});
|
|
585
807
|
const authCmd = program.command("auth").description("Authentication helpers");
|
|
586
808
|
shared(authCmd.command("siwe").description("Generate a SIWE signature"))
|
|
587
|
-
.
|
|
588
|
-
.
|
|
809
|
+
.usage("<domain> <uri> [options]")
|
|
810
|
+
.argument("<domain>", "requesting domain")
|
|
811
|
+
.argument("<uri>", "resource URI")
|
|
812
|
+
.option("--domain <domain>", "requesting domain")
|
|
813
|
+
.option("--uri <uri>", "resource URI")
|
|
589
814
|
.option("--statement <text>", "human-readable statement")
|
|
590
815
|
.option("--chain-id <id>", "chain ID", parseInt)
|
|
591
816
|
.option("--expiration-time <iso>", "expiration time")
|
|
592
817
|
.option("--not-before <iso>", "not before time")
|
|
593
818
|
.option("--resources <json>", "resources array as JSON", parseJsonValue)
|
|
594
|
-
.
|
|
819
|
+
.addHelpText("after", "\nExamples:\n spongewallet auth siwe app.example.com https://app.example.com\n")
|
|
820
|
+
.action(async (domainArg, uriArg, opts) => {
|
|
595
821
|
await executeToolCommand(opts, "generate_siwe", {
|
|
596
|
-
domain: opts
|
|
597
|
-
uri: opts
|
|
822
|
+
domain: requiredInput(opts, domainArg, "domain", "--domain"),
|
|
823
|
+
uri: requiredInput(opts, uriArg, "uri", "--uri"),
|
|
598
824
|
statement: opts.statement,
|
|
599
825
|
chain_id: opts.chainId,
|
|
600
826
|
expiration_time: opts.expirationTime,
|
|
@@ -603,7 +829,105 @@ function registerCuratedCommands(program, shared) {
|
|
|
603
829
|
});
|
|
604
830
|
});
|
|
605
831
|
const marketCmd = program.command("market").description("Trading venue integrations");
|
|
606
|
-
|
|
832
|
+
const hyperliquidCmd = marketCmd.command("hyperliquid").description("Trade or inspect Hyperliquid");
|
|
833
|
+
shared(hyperliquidCmd.command("status").description("Show Hyperliquid account status"))
|
|
834
|
+
.action(async (opts) => {
|
|
835
|
+
await executeHyperliquidAction(opts, { action: "status" });
|
|
836
|
+
});
|
|
837
|
+
shared(hyperliquidCmd.command("markets").description("List Hyperliquid markets"))
|
|
838
|
+
.usage("[limit] [offset] [options]")
|
|
839
|
+
.argument("[limit]", "result limit")
|
|
840
|
+
.argument("[offset]", "result offset")
|
|
841
|
+
.option("--limit <n>", "result limit", parseInt)
|
|
842
|
+
.option("--offset <n>", "result offset", parseInt)
|
|
843
|
+
.addHelpText("after", "\nExamples:\n spongewallet market hyperliquid markets\n spongewallet market hyperliquid markets 10\n")
|
|
844
|
+
.action(async (limitArg, offsetArg, opts) => {
|
|
845
|
+
await executeHyperliquidAction(opts, {
|
|
846
|
+
action: "markets",
|
|
847
|
+
limit: limitArg !== undefined ? parseInt(limitArg, 10) : opts.limit,
|
|
848
|
+
offset: offsetArg !== undefined ? parseInt(offsetArg, 10) : opts.offset,
|
|
849
|
+
});
|
|
850
|
+
});
|
|
851
|
+
shared(hyperliquidCmd.command("positions").description("List open Hyperliquid positions"))
|
|
852
|
+
.action(async (opts) => {
|
|
853
|
+
await executeHyperliquidAction(opts, { action: "positions" });
|
|
854
|
+
});
|
|
855
|
+
shared(hyperliquidCmd.command("orders").description("List open Hyperliquid orders"))
|
|
856
|
+
.usage("[limit] [offset] [options]")
|
|
857
|
+
.argument("[limit]", "result limit")
|
|
858
|
+
.argument("[offset]", "result offset")
|
|
859
|
+
.option("--limit <n>", "result limit", parseInt)
|
|
860
|
+
.option("--offset <n>", "result offset", parseInt)
|
|
861
|
+
.addHelpText("after", "\nExamples:\n spongewallet market hyperliquid orders\n spongewallet market hyperliquid orders 20\n")
|
|
862
|
+
.action(async (limitArg, offsetArg, opts) => {
|
|
863
|
+
await executeHyperliquidAction(opts, {
|
|
864
|
+
action: "orders",
|
|
865
|
+
limit: limitArg !== undefined ? parseInt(limitArg, 10) : opts.limit,
|
|
866
|
+
offset: offsetArg !== undefined ? parseInt(offsetArg, 10) : opts.offset,
|
|
867
|
+
});
|
|
868
|
+
});
|
|
869
|
+
shared(hyperliquidCmd.command("fills").description("List recent Hyperliquid fills"))
|
|
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 fills\n spongewallet market hyperliquid fills 20\n")
|
|
876
|
+
.action(async (limitArg, offsetArg, opts) => {
|
|
877
|
+
await executeHyperliquidAction(opts, {
|
|
878
|
+
action: "fills",
|
|
879
|
+
limit: limitArg !== undefined ? parseInt(limitArg, 10) : opts.limit,
|
|
880
|
+
offset: offsetArg !== undefined ? parseInt(offsetArg, 10) : opts.offset,
|
|
881
|
+
});
|
|
882
|
+
});
|
|
883
|
+
shared(hyperliquidCmd.command("order").description("Place a Hyperliquid order"))
|
|
884
|
+
.argument("<symbol>", "market symbol")
|
|
885
|
+
.argument("<side>", "buy or sell")
|
|
886
|
+
.argument("<type>", "order type")
|
|
887
|
+
.argument("<amount>", "order amount")
|
|
888
|
+
.argument("[price]", "limit price")
|
|
889
|
+
.option("--symbol <symbol>", "market symbol")
|
|
890
|
+
.option("--side <side>", "buy or sell")
|
|
891
|
+
.option("--type <type>", "order type")
|
|
892
|
+
.option("--amount <amount>", "order amount")
|
|
893
|
+
.option("--price <price>", "limit price")
|
|
894
|
+
.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")
|
|
895
|
+
.action(async (symbolArg, sideArg, typeArg, amountArg, priceArg, opts) => {
|
|
896
|
+
await executeHyperliquidAction(opts, {
|
|
897
|
+
action: "order",
|
|
898
|
+
symbol: requiredInput(opts, symbolArg, "symbol", "--symbol"),
|
|
899
|
+
side: requiredInput(opts, sideArg, "side", "--side"),
|
|
900
|
+
type: requiredInput(opts, typeArg, "type", "--type"),
|
|
901
|
+
amount: requiredInput(opts, amountArg, "amount", "--amount"),
|
|
902
|
+
price: priceArg ?? opts.price,
|
|
903
|
+
});
|
|
904
|
+
});
|
|
905
|
+
shared(hyperliquidCmd.command("cancel").description("Cancel a Hyperliquid order"))
|
|
906
|
+
.argument("<orderId>", "order ID")
|
|
907
|
+
.option("--order-id <id>", "order ID")
|
|
908
|
+
.action(async (orderIdArg, opts) => {
|
|
909
|
+
await executeHyperliquidAction(opts, {
|
|
910
|
+
action: "cancel",
|
|
911
|
+
order_id: requiredInput(opts, orderIdArg, "orderId", "--order-id"),
|
|
912
|
+
});
|
|
913
|
+
});
|
|
914
|
+
shared(hyperliquidCmd.command("cancel-all").description("Cancel all Hyperliquid orders"))
|
|
915
|
+
.action(async (opts) => {
|
|
916
|
+
await executeHyperliquidAction(opts, { action: "cancel_all" });
|
|
917
|
+
});
|
|
918
|
+
shared(hyperliquidCmd.command("leverage").description("Set Hyperliquid leverage"))
|
|
919
|
+
.argument("<symbol>", "market symbol")
|
|
920
|
+
.argument("<leverage>", "leverage")
|
|
921
|
+
.option("--symbol <symbol>", "market symbol")
|
|
922
|
+
.option("--leverage <n>", "leverage", parseFloat)
|
|
923
|
+
.action(async (symbolArg, leverageArg, opts) => {
|
|
924
|
+
await executeHyperliquidAction(opts, {
|
|
925
|
+
action: "set_leverage",
|
|
926
|
+
symbol: requiredInput(opts, symbolArg, "symbol", "--symbol"),
|
|
927
|
+
leverage: leverageArg !== undefined ? parseFloat(leverageArg) : opts.leverage,
|
|
928
|
+
});
|
|
929
|
+
});
|
|
930
|
+
shared(hyperliquidCmd.command("raw").description("Call a raw Hyperliquid action"))
|
|
607
931
|
.requiredOption("--action <action>", "hyperliquid action")
|
|
608
932
|
.option("--symbol <symbol>", "market symbol")
|
|
609
933
|
.option("--side <side>", "buy or sell")
|
|
@@ -616,8 +940,7 @@ function registerCuratedCommands(program, shared) {
|
|
|
616
940
|
.option("--offset <n>", "result offset", parseInt)
|
|
617
941
|
.option("--json <json>", "additional args as JSON", parseJsonObject)
|
|
618
942
|
.action(async (opts) => {
|
|
619
|
-
|
|
620
|
-
const data = await wallet.hyperliquid({
|
|
943
|
+
await executeHyperliquidAction(opts, {
|
|
621
944
|
...opts.json,
|
|
622
945
|
action: String(opts.action),
|
|
623
946
|
symbol: opts.symbol,
|
|
@@ -630,7 +953,6 @@ function registerCuratedCommands(program, shared) {
|
|
|
630
953
|
limit: opts.limit,
|
|
631
954
|
offset: opts.offset,
|
|
632
955
|
});
|
|
633
|
-
displayToolResult(getToolDefinition("hyperliquid"), data);
|
|
634
956
|
});
|
|
635
957
|
}
|
|
636
958
|
async function connectWallet(opts) {
|
|
@@ -639,6 +961,11 @@ async function connectWallet(opts) {
|
|
|
639
961
|
credentialsPath: opts.credentialsPath,
|
|
640
962
|
});
|
|
641
963
|
}
|
|
964
|
+
async function executeHyperliquidAction(opts, input) {
|
|
965
|
+
const wallet = await connectWallet(opts);
|
|
966
|
+
const data = await wallet.hyperliquid(input);
|
|
967
|
+
displayToolResult(getToolDefinition("hyperliquid"), data);
|
|
968
|
+
}
|
|
642
969
|
async function executeToolCommand(opts, toolName, input) {
|
|
643
970
|
const wallet = await connectWallet(opts);
|
|
644
971
|
const tools = await wallet.tools();
|
|
@@ -792,6 +1119,7 @@ const toolFormatters = {
|
|
|
792
1119
|
const chains = data;
|
|
793
1120
|
const rows = [];
|
|
794
1121
|
let emptyCount = 0;
|
|
1122
|
+
let totalUsd = 0;
|
|
795
1123
|
for (const [chain, info] of Object.entries(chains)) {
|
|
796
1124
|
if (TESTNET_CHAINS.has(chain))
|
|
797
1125
|
continue;
|
|
@@ -806,6 +1134,11 @@ const toolFormatters = {
|
|
|
806
1134
|
amount: b.amount,
|
|
807
1135
|
usd: b.usdValue ? `$${b.usdValue}` : "-",
|
|
808
1136
|
});
|
|
1137
|
+
if (b.usdValue) {
|
|
1138
|
+
const parsed = Number(b.usdValue);
|
|
1139
|
+
if (Number.isFinite(parsed))
|
|
1140
|
+
totalUsd += parsed;
|
|
1141
|
+
}
|
|
809
1142
|
}
|
|
810
1143
|
}
|
|
811
1144
|
if (rows.length === 0) {
|
|
@@ -826,10 +1159,147 @@ const toolFormatters = {
|
|
|
826
1159
|
console.log(row(r.chain, r.token, r.amount, r.usd));
|
|
827
1160
|
}
|
|
828
1161
|
console.log();
|
|
1162
|
+
console.log(` Total: $${totalUsd.toFixed(2)}`);
|
|
1163
|
+
console.log();
|
|
829
1164
|
if (emptyCount > 0) {
|
|
830
1165
|
p.log.step(`${emptyCount} chain${emptyCount !== 1 ? "s" : ""} with no balance`);
|
|
831
1166
|
}
|
|
832
1167
|
},
|
|
1168
|
+
hyperliquid(data) {
|
|
1169
|
+
if (!isRecord(data)) {
|
|
1170
|
+
p.log.success("Hyperliquid");
|
|
1171
|
+
console.log(JSON.stringify(data, null, 2));
|
|
1172
|
+
return;
|
|
1173
|
+
}
|
|
1174
|
+
const action = getValueByKey(data, "tool_call.arguments.action");
|
|
1175
|
+
const title = action
|
|
1176
|
+
? `Hyperliquid ${toTitleCase(String(action).replace(/_/g, " "))}`
|
|
1177
|
+
: "Hyperliquid";
|
|
1178
|
+
if (getValueByKey(data, "address") && isRecord(getValueByKey(data, "balances"))) {
|
|
1179
|
+
const perps = getValueByKey(data, "balances.perps");
|
|
1180
|
+
const spot = getValueByKey(data, "balances.spot");
|
|
1181
|
+
const openOrders = getValueByKey(data, "openOrders");
|
|
1182
|
+
const spotRows = Object.entries(spot ?? {}).map(([symbol, value]) => ({
|
|
1183
|
+
symbol,
|
|
1184
|
+
amount: getValueByKey(value, "amount"),
|
|
1185
|
+
usdValue: getValueByKey(value, "usdValue"),
|
|
1186
|
+
}));
|
|
1187
|
+
p.log.success(title);
|
|
1188
|
+
p.log.info([
|
|
1189
|
+
`Wallet: ${formatInlineValue(getValueByKey(data, "address"))}`,
|
|
1190
|
+
`Perps total: ${formatInlineValue(getValueByKey(perps, "total.USDC"))} USDC`,
|
|
1191
|
+
`Perps free: ${formatInlineValue(getValueByKey(perps, "free.USDC"))} USDC`,
|
|
1192
|
+
`Perps used: ${formatInlineValue(getValueByKey(perps, "used.USDC"))} USDC`,
|
|
1193
|
+
`Spot assets: ${spotRows.length}`,
|
|
1194
|
+
`Open orders: ${formatInlineValue(getValueByKey(data, "openOrderCount"))}`,
|
|
1195
|
+
].join("\n"));
|
|
1196
|
+
if (spotRows.length > 0) {
|
|
1197
|
+
renderTable("Spot balances", [
|
|
1198
|
+
{ key: "symbol", label: "Symbol" },
|
|
1199
|
+
{ key: "amount", label: "Amount" },
|
|
1200
|
+
{ key: "usdValue", label: "USD Value" },
|
|
1201
|
+
], spotRows);
|
|
1202
|
+
}
|
|
1203
|
+
if (Array.isArray(openOrders) && openOrders.length > 0) {
|
|
1204
|
+
renderTable("Open orders", [
|
|
1205
|
+
{ key: "symbol", label: "Symbol" },
|
|
1206
|
+
{ key: "side", label: "Side" },
|
|
1207
|
+
{ key: "price", label: "Price" },
|
|
1208
|
+
{ key: "remaining", label: "Remaining" },
|
|
1209
|
+
{ key: "status", label: "Status" },
|
|
1210
|
+
], openOrders);
|
|
1211
|
+
}
|
|
1212
|
+
return;
|
|
1213
|
+
}
|
|
1214
|
+
const positions = getValueByKey(data, "positions");
|
|
1215
|
+
if (Array.isArray(positions)) {
|
|
1216
|
+
if (positions.length === 0) {
|
|
1217
|
+
p.log.info("No open Hyperliquid positions.");
|
|
1218
|
+
return;
|
|
1219
|
+
}
|
|
1220
|
+
renderTable(title, [
|
|
1221
|
+
{ key: "symbol", label: "Symbol" },
|
|
1222
|
+
{ key: "side", label: "Side" },
|
|
1223
|
+
{ key: "contracts", label: "Size" },
|
|
1224
|
+
{ key: "entryPrice", label: "Entry" },
|
|
1225
|
+
{ key: "markPrice", label: "Mark" },
|
|
1226
|
+
{ key: "leverage", label: "Lev" },
|
|
1227
|
+
{ key: "unrealizedPnl", label: "PnL" },
|
|
1228
|
+
], positions);
|
|
1229
|
+
return;
|
|
1230
|
+
}
|
|
1231
|
+
const orders = getValueByKey(data, "orders");
|
|
1232
|
+
if (Array.isArray(orders)) {
|
|
1233
|
+
if (orders.length === 0) {
|
|
1234
|
+
p.log.info("No open Hyperliquid orders.");
|
|
1235
|
+
return;
|
|
1236
|
+
}
|
|
1237
|
+
renderTable(title, [
|
|
1238
|
+
{ key: "symbol", label: "Symbol" },
|
|
1239
|
+
{ key: "side", label: "Side" },
|
|
1240
|
+
{ key: "price", label: "Price" },
|
|
1241
|
+
{ key: "remaining", label: "Remaining" },
|
|
1242
|
+
{ key: "reduceOnly", label: "Reduce" },
|
|
1243
|
+
{ key: "status", label: "Status" },
|
|
1244
|
+
], orders);
|
|
1245
|
+
return;
|
|
1246
|
+
}
|
|
1247
|
+
const fills = getValueByKey(data, "fills");
|
|
1248
|
+
if (Array.isArray(fills)) {
|
|
1249
|
+
if (fills.length === 0) {
|
|
1250
|
+
p.log.info("No recent Hyperliquid fills.");
|
|
1251
|
+
return;
|
|
1252
|
+
}
|
|
1253
|
+
renderTable(title, [
|
|
1254
|
+
{ key: "symbol", label: "Symbol" },
|
|
1255
|
+
{ key: "side", label: "Side" },
|
|
1256
|
+
{ key: "price", label: "Price" },
|
|
1257
|
+
{ key: "amount", label: "Amount" },
|
|
1258
|
+
{ key: "closedPnl", label: "PnL" },
|
|
1259
|
+
{ key: "datetime", label: "Time" },
|
|
1260
|
+
], fills);
|
|
1261
|
+
return;
|
|
1262
|
+
}
|
|
1263
|
+
const markets = getValueByKey(data, "markets");
|
|
1264
|
+
if (Array.isArray(markets)) {
|
|
1265
|
+
if (markets.length === 0) {
|
|
1266
|
+
p.log.info("No Hyperliquid markets found.");
|
|
1267
|
+
return;
|
|
1268
|
+
}
|
|
1269
|
+
renderTable(title, [
|
|
1270
|
+
{ key: "symbol", label: "Symbol" },
|
|
1271
|
+
{ key: "type", label: "Type" },
|
|
1272
|
+
{ key: "base", label: "Base" },
|
|
1273
|
+
{ key: "quote", label: "Quote" },
|
|
1274
|
+
{ key: "maxLeverage", label: "Max Lev" },
|
|
1275
|
+
], markets);
|
|
1276
|
+
const total = getValueByKey(data, "total");
|
|
1277
|
+
const nextOffset = getValueByKey(data, "nextOffset");
|
|
1278
|
+
if (total !== undefined) {
|
|
1279
|
+
p.log.info(`Showing ${markets.length} of ${formatInlineValue(total)} markets.`);
|
|
1280
|
+
}
|
|
1281
|
+
if (nextOffset !== null && nextOffset !== undefined) {
|
|
1282
|
+
p.log.info(`Next offset: ${formatInlineValue(nextOffset)}`);
|
|
1283
|
+
}
|
|
1284
|
+
return;
|
|
1285
|
+
}
|
|
1286
|
+
const cleanData = Object.fromEntries(Object.entries(data).filter(([key]) => key !== "tool_call"));
|
|
1287
|
+
if (renderFields(title, [
|
|
1288
|
+
{ key: "message", label: "Message" },
|
|
1289
|
+
{ key: "status", label: "Status" },
|
|
1290
|
+
{ key: "orderId", label: "Order ID" },
|
|
1291
|
+
{ key: "clientOrderId", label: "Client Order ID" },
|
|
1292
|
+
{ key: "symbol", label: "Symbol" },
|
|
1293
|
+
{ key: "leverage", label: "Leverage" },
|
|
1294
|
+
{ key: "cancelled", label: "Cancelled" },
|
|
1295
|
+
{ key: "address", label: "Address" },
|
|
1296
|
+
{ key: "webChartUrl", label: "Chart" },
|
|
1297
|
+
], cleanData)) {
|
|
1298
|
+
return;
|
|
1299
|
+
}
|
|
1300
|
+
p.log.success(title);
|
|
1301
|
+
console.log(JSON.stringify(cleanData, null, 2));
|
|
1302
|
+
},
|
|
833
1303
|
};
|
|
834
1304
|
function isRecord(value) {
|
|
835
1305
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -926,9 +1396,25 @@ function renderTxOutput(title, data) {
|
|
|
926
1396
|
if (!isRecord(data))
|
|
927
1397
|
return false;
|
|
928
1398
|
const hash = getValueByKey(data, ["transactionHash", "txHash", "signature"]);
|
|
1399
|
+
const inputAmount = getValueByKey(data, ["inputToken.amount", "input_token.amount"]);
|
|
1400
|
+
const inputSymbol = getValueByKey(data, ["inputToken.symbol", "input_token.symbol"]);
|
|
1401
|
+
const outputAmount = getValueByKey(data, ["outputToken.amount", "output_token.amount"]);
|
|
1402
|
+
const outputSymbol = getValueByKey(data, ["outputToken.symbol", "output_token.symbol"]);
|
|
1403
|
+
const flow = inputAmount && inputSymbol && outputAmount && outputSymbol
|
|
1404
|
+
? `${formatInlineValue(inputAmount)} ${formatInlineValue(inputSymbol)} -> ${formatInlineValue(outputAmount)} ${formatInlineValue(outputSymbol)}`
|
|
1405
|
+
: undefined;
|
|
1406
|
+
const sourceChain = getValueByKey(data, ["sourceChain", "source_chain"]);
|
|
1407
|
+
const destinationChain = getValueByKey(data, ["destinationChain", "destination_chain"]);
|
|
1408
|
+
const route = sourceChain && destinationChain
|
|
1409
|
+
? `${formatInlineValue(sourceChain)} -> ${formatInlineValue(destinationChain)}`
|
|
1410
|
+
: undefined;
|
|
929
1411
|
const lines = [
|
|
1412
|
+
route ? `Route: ${route}` : undefined,
|
|
1413
|
+
flow ? `Flow: ${flow}` : undefined,
|
|
930
1414
|
hash ? `Transaction: ${formatInlineValue(hash)}` : undefined,
|
|
931
1415
|
getValueByKey(data, "status") ? `Status: ${formatInlineValue(getValueByKey(data, "status"))}` : undefined,
|
|
1416
|
+
getValueByKey(data, "priceImpactPct") ? `Price impact: ${formatInlineValue(getValueByKey(data, "priceImpactPct"))}%` : undefined,
|
|
1417
|
+
getValueByKey(data, "gasUsed") ? `Gas used: ${formatInlineValue(getValueByKey(data, "gasUsed"))}` : undefined,
|
|
932
1418
|
getValueByKey(data, "explorerUrl") ? `Explorer: ${formatInlineValue(getValueByKey(data, "explorerUrl"))}` : undefined,
|
|
933
1419
|
getValueByKey(data, "chain") ? `Chain: ${formatInlineValue(getValueByKey(data, "chain"))}` : undefined,
|
|
934
1420
|
getValueByKey(data, "from") ? `Signer: ${formatInlineValue(getValueByKey(data, "from"))}` : undefined,
|