@bankr/cli 0.3.1 → 0.3.11
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 -7
- package/dist/cli.js +146 -83
- package/dist/commands/club.d.ts +1 -0
- package/dist/commands/club.js +47 -5
- package/dist/commands/fees.js +10 -2
- package/dist/commands/launch.js +16 -23
- package/dist/commands/llm.d.ts +3 -1
- package/dist/commands/llm.js +240 -63
- package/dist/commands/login.d.ts +0 -1
- package/dist/commands/login.js +28 -23
- package/dist/commands/profile.d.ts +5 -1
- package/dist/commands/profile.js +54 -10
- package/dist/commands/prompt.js +6 -0
- package/dist/commands/swap.d.ts +8 -0
- package/dist/commands/swap.js +107 -0
- package/dist/commands/transfer.js +38 -25
- package/dist/commands/webhooks.js +2 -7
- package/dist/commands/x402.js +57 -41
- package/dist/lib/api.d.ts +50 -3
- package/dist/lib/api.js +41 -16
- package/dist/lib/config.d.ts +0 -1
- package/dist/lib/output.d.ts +1 -0
- package/dist/lib/output.js +3 -0
- package/dist/lib/tokens.d.ts +21 -0
- package/dist/lib/tokens.js +40 -0
- package/package.json +6 -6
package/dist/commands/x402.js
CHANGED
|
@@ -20,7 +20,7 @@ import { join } from "node:path";
|
|
|
20
20
|
import chalk from "chalk";
|
|
21
21
|
import { input, select, confirm } from "@inquirer/prompts";
|
|
22
22
|
import * as output from "../lib/output.js";
|
|
23
|
-
import { getApiUrl, requireApiKey,
|
|
23
|
+
import { getApiUrl, requireApiKey, CLI_USER_AGENT } from "../lib/config.js";
|
|
24
24
|
// ── Config file helpers ─────────────────────────────────────────────────
|
|
25
25
|
const CONFIG_FILENAME = "bankr.x402.json";
|
|
26
26
|
function findProjectRoot() {
|
|
@@ -50,16 +50,11 @@ function saveConfigFile(projectRoot, config) {
|
|
|
50
50
|
}
|
|
51
51
|
// ── API helpers ─────────────────────────────────────────────────────────
|
|
52
52
|
function authHeaders() {
|
|
53
|
-
|
|
53
|
+
return {
|
|
54
54
|
"X-API-Key": requireApiKey(),
|
|
55
55
|
"Content-Type": "application/json",
|
|
56
56
|
"User-Agent": CLI_USER_AGENT,
|
|
57
57
|
};
|
|
58
|
-
const config = readConfig();
|
|
59
|
-
if (config.partnerKey) {
|
|
60
|
-
headers["X-Partner-Key"] = config.partnerKey;
|
|
61
|
-
}
|
|
62
|
-
return headers;
|
|
63
58
|
}
|
|
64
59
|
async function handleResponse(res) {
|
|
65
60
|
if (!res.ok) {
|
|
@@ -279,10 +274,7 @@ export async function x402ConfigureCommand(name) {
|
|
|
279
274
|
const currency = "USDC";
|
|
280
275
|
const network = await select({
|
|
281
276
|
message: "Network:",
|
|
282
|
-
choices: [
|
|
283
|
-
{ name: "Base", value: "base" },
|
|
284
|
-
{ name: "Base Sepolia (testnet)", value: "base-sepolia" },
|
|
285
|
-
],
|
|
277
|
+
choices: [{ name: "Base", value: "base" }],
|
|
286
278
|
default: existing.network ?? "base",
|
|
287
279
|
theme: output.bankrTheme,
|
|
288
280
|
});
|
|
@@ -697,62 +689,78 @@ function resolveSchemas(schema) {
|
|
|
697
689
|
const outputSchema = schema.output;
|
|
698
690
|
return { input: inputSchema, output: outputSchema };
|
|
699
691
|
}
|
|
700
|
-
|
|
692
|
+
/**
|
|
693
|
+
* Builds the verbose multi-line card for a service. Returns the rendered
|
|
694
|
+
* string. Pass `rank` and `total` to render a `#N of M` badge in the header
|
|
695
|
+
* (used by the search command so reading top-to-bottom shows ascending rank
|
|
696
|
+
* with the top match at the bottom).
|
|
697
|
+
*/
|
|
698
|
+
function formatServiceCard(svc, rank, total) {
|
|
701
699
|
const route = svc.routes[0];
|
|
702
700
|
const methods = route?.methods?.filter((m) => m !== "*").join(", ") || "ANY";
|
|
703
701
|
const url = svc.url ?? `https://x402.bankr.bot/${svc.slug}`;
|
|
704
702
|
const isGet = methods === "GET";
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
703
|
+
const lines = [];
|
|
704
|
+
// ── Header (with rank badge) ──
|
|
705
|
+
const rankBadge = rank !== undefined
|
|
706
|
+
? `${chalk.bold(`#${rank}${total ? ` of ${total}` : ""}`)} `
|
|
707
|
+
: "";
|
|
708
|
+
const scoreBadge = svc.score !== undefined
|
|
709
|
+
? ` ${chalk.dim(`(score ${svc.score.toFixed(2)})`)}`
|
|
710
|
+
: "";
|
|
711
|
+
lines.push(` ${rankBadge}${output.fmt.brandBold(svc.name)}${scoreBadge}`);
|
|
712
|
+
if (svc.description)
|
|
713
|
+
lines.push(` ${chalk.dim(svc.description)}`);
|
|
714
|
+
lines.push("");
|
|
711
715
|
// ── Metadata ──
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
+
lines.push(` ${chalk.dim("URL")} ${url}`);
|
|
717
|
+
lines.push(` ${chalk.dim("Method")} ${chalk.bold(methods)}`);
|
|
718
|
+
lines.push(` ${chalk.dim("Price")} ${chalk.green(`$${route?.price ?? "?"} ${route?.currency ?? "USDC"}`)}`);
|
|
719
|
+
lines.push(` ${chalk.dim("Network")} ${route?.network ?? "base"}`);
|
|
716
720
|
// ── Schema ──
|
|
717
721
|
const { input: inputSchema, output: outputSchema } = resolveSchemas(route?.schema);
|
|
718
722
|
if (inputSchema || outputSchema) {
|
|
719
|
-
|
|
723
|
+
lines.push("");
|
|
720
724
|
if (inputSchema) {
|
|
721
725
|
const label = isGet ? "Input (query params)" : "Input (JSON body)";
|
|
722
|
-
|
|
726
|
+
lines.push(` ${chalk.bold(label)}`);
|
|
723
727
|
if (isJsonSchema(inputSchema)) {
|
|
724
728
|
for (const line of renderJsonSchemaProps(inputSchema)) {
|
|
725
|
-
|
|
729
|
+
lines.push(line);
|
|
726
730
|
}
|
|
727
731
|
}
|
|
728
732
|
else if (typeof inputSchema === "object" && inputSchema !== null) {
|
|
729
733
|
for (const line of renderLegacySchema(inputSchema)) {
|
|
730
|
-
|
|
734
|
+
lines.push(line);
|
|
731
735
|
}
|
|
732
736
|
}
|
|
733
737
|
}
|
|
734
738
|
if (outputSchema) {
|
|
735
|
-
|
|
736
|
-
|
|
739
|
+
lines.push("");
|
|
740
|
+
lines.push(` ${chalk.bold("Output")}`);
|
|
737
741
|
if (isJsonSchema(outputSchema)) {
|
|
738
742
|
for (const line of renderJsonSchemaProps(outputSchema)) {
|
|
739
|
-
|
|
743
|
+
lines.push(line);
|
|
740
744
|
}
|
|
741
745
|
}
|
|
742
746
|
else if (typeof outputSchema === "object" && outputSchema !== null) {
|
|
743
747
|
for (const line of renderLegacySchema(outputSchema)) {
|
|
744
|
-
|
|
748
|
+
lines.push(line);
|
|
745
749
|
}
|
|
746
750
|
}
|
|
747
751
|
}
|
|
748
752
|
}
|
|
749
753
|
// ── Tags ──
|
|
750
754
|
if (svc.tags?.length) {
|
|
751
|
-
|
|
752
|
-
|
|
755
|
+
lines.push("");
|
|
756
|
+
lines.push(` ${svc.tags.map((t) => chalk.dim(`#${t}`)).join(" ")}`);
|
|
753
757
|
}
|
|
754
|
-
|
|
755
|
-
|
|
758
|
+
lines.push(` ${chalk.dim("─".repeat(60))}`);
|
|
759
|
+
lines.push("");
|
|
760
|
+
return lines.join("\n");
|
|
761
|
+
}
|
|
762
|
+
function printServiceFormatted(svc, rank, total) {
|
|
763
|
+
console.log(formatServiceCard(svc, rank, total));
|
|
756
764
|
}
|
|
757
765
|
// ── Schema ────────────────────────────────────────────────────────────
|
|
758
766
|
export async function x402SchemaCommand(url, opts = {}) {
|
|
@@ -1144,8 +1152,7 @@ export async function x402CallCommand(url, opts = {}) {
|
|
|
1144
1152
|
resolvedPrice = parseFloat(schema.price);
|
|
1145
1153
|
}
|
|
1146
1154
|
}
|
|
1147
|
-
|
|
1148
|
-
if (!opts.yes && !opts.interactive) {
|
|
1155
|
+
if (!opts.yes && !opts.interactive && !output.isNonInteractive()) {
|
|
1149
1156
|
const priceDisplay = resolvedPrice !== null
|
|
1150
1157
|
? chalk.green(`$${resolvedPrice} USDC`)
|
|
1151
1158
|
: chalk.green(`up to $${maxPaymentUsd} USDC`);
|
|
@@ -1235,7 +1242,7 @@ export async function x402SearchCommand(queryParts, opts = {}) {
|
|
|
1235
1242
|
}
|
|
1236
1243
|
const spin = output.spinner("Searching services...");
|
|
1237
1244
|
try {
|
|
1238
|
-
const params = new URLSearchParams({ q: query, limit: "
|
|
1245
|
+
const params = new URLSearchParams({ q: query, limit: "50" });
|
|
1239
1246
|
const res = await fetch(`${getApiUrl()}/x402/endpoints/discover?${params}`);
|
|
1240
1247
|
const result = await handleResponse(res);
|
|
1241
1248
|
spin.stop();
|
|
@@ -1246,16 +1253,25 @@ export async function x402SearchCommand(queryParts, opts = {}) {
|
|
|
1246
1253
|
output.info(`No services found for "${query}"`);
|
|
1247
1254
|
return;
|
|
1248
1255
|
}
|
|
1249
|
-
// Raw mode: dump JSON and exit
|
|
1256
|
+
// Raw mode: dump JSON and exit (preserves natural rank order for AI
|
|
1257
|
+
// agents and pipelines — most relevant first).
|
|
1250
1258
|
if (opts.raw) {
|
|
1251
1259
|
console.log(JSON.stringify(services, null, 2));
|
|
1252
1260
|
return;
|
|
1253
1261
|
}
|
|
1262
|
+
// Print results in REVERSE rank order so the cursor parks on the most
|
|
1263
|
+
// relevant result (rank #1) at the bottom of the buffer. Each card has
|
|
1264
|
+
// a `#N of M` badge so the rank is always visible regardless of which
|
|
1265
|
+
// direction you read.
|
|
1254
1266
|
console.log();
|
|
1255
|
-
console.log(` ${chalk.dim(`Found ${services.length} service(s) for`)} "${query}"`);
|
|
1267
|
+
console.log(` ${chalk.dim(`Found ${services.length} service(s) for`)} "${query}" ${chalk.dim("(scrolling order: lowest rank first, top match at the bottom)")}`);
|
|
1256
1268
|
console.log(` ${chalk.dim("─".repeat(60))}`);
|
|
1257
|
-
|
|
1258
|
-
|
|
1269
|
+
console.log();
|
|
1270
|
+
const total = services.length;
|
|
1271
|
+
// Iterate in reverse: start with the lowest-ranked result, end on rank #1.
|
|
1272
|
+
for (let i = total - 1; i >= 0; i--) {
|
|
1273
|
+
const svc = services[i];
|
|
1274
|
+
printServiceFormatted(svc, i + 1, total);
|
|
1259
1275
|
}
|
|
1260
1276
|
}
|
|
1261
1277
|
catch (err) {
|
package/dist/lib/api.d.ts
CHANGED
|
@@ -384,16 +384,20 @@ export interface AgentProfileResponse {
|
|
|
384
384
|
content: string;
|
|
385
385
|
createdAt: string;
|
|
386
386
|
}>;
|
|
387
|
+
tags?: string[];
|
|
387
388
|
approved: boolean;
|
|
389
|
+
isPublished?: boolean;
|
|
388
390
|
createdAt: string;
|
|
389
391
|
}
|
|
392
|
+
export declare function getOwnProfiles(): Promise<AgentProfileResponse[]>;
|
|
393
|
+
/** @deprecated Use getOwnProfiles() — returns first profile for backward compat */
|
|
390
394
|
export declare function getOwnProfile(): Promise<AgentProfileResponse>;
|
|
391
395
|
export declare function createProfile(data: Record<string, unknown>): Promise<AgentProfileResponse>;
|
|
392
|
-
export declare function updateProfile(data: Record<string, unknown>): Promise<AgentProfileResponse>;
|
|
393
|
-
export declare function deleteProfile(): Promise<{
|
|
396
|
+
export declare function updateProfile(slug: string, data: Record<string, unknown>): Promise<AgentProfileResponse>;
|
|
397
|
+
export declare function deleteProfile(slug: string): Promise<{
|
|
394
398
|
success: boolean;
|
|
395
399
|
}>;
|
|
396
|
-
export declare function addProjectUpdate(data: {
|
|
400
|
+
export declare function addProjectUpdate(slug: string, data: {
|
|
397
401
|
title: string;
|
|
398
402
|
content: string;
|
|
399
403
|
}): Promise<AgentProfileResponse>;
|
|
@@ -422,6 +426,49 @@ export interface TransferResponse {
|
|
|
422
426
|
error?: string;
|
|
423
427
|
}
|
|
424
428
|
export declare function transfer(request: TransferRequest): Promise<TransferResponse>;
|
|
429
|
+
export interface SwapQuoteRequest {
|
|
430
|
+
fromChain: string;
|
|
431
|
+
fromToken: string;
|
|
432
|
+
toChain: string;
|
|
433
|
+
toToken: string;
|
|
434
|
+
amount: string;
|
|
435
|
+
}
|
|
436
|
+
export interface SwapQuoteSide {
|
|
437
|
+
chain: string;
|
|
438
|
+
token: string;
|
|
439
|
+
amount: string;
|
|
440
|
+
formattedAmount: string;
|
|
441
|
+
symbol: string;
|
|
442
|
+
decimals: number;
|
|
443
|
+
usdValue: string;
|
|
444
|
+
}
|
|
445
|
+
export interface SwapQuoteResponse {
|
|
446
|
+
from: SwapQuoteSide;
|
|
447
|
+
to: SwapQuoteSide;
|
|
448
|
+
minBuyAmount: string;
|
|
449
|
+
}
|
|
450
|
+
export interface SwapExecuteRequest extends SwapQuoteRequest {
|
|
451
|
+
minBuyAmount: string;
|
|
452
|
+
}
|
|
453
|
+
export interface SwapExecuteResponse {
|
|
454
|
+
success: boolean;
|
|
455
|
+
hash?: string;
|
|
456
|
+
error?: string;
|
|
457
|
+
amountReceived?: number;
|
|
458
|
+
amountReceivedRaw?: string;
|
|
459
|
+
amountSold?: number;
|
|
460
|
+
amountSoldRaw?: string;
|
|
461
|
+
}
|
|
462
|
+
export declare function getSwapQuote(request: SwapQuoteRequest): Promise<SwapQuoteResponse>;
|
|
463
|
+
export declare function executeSwap(request: SwapExecuteRequest): Promise<SwapExecuteResponse>;
|
|
464
|
+
export type RecipientType = "address" | "ens" | "twitter" | "farcaster";
|
|
465
|
+
export interface ResolveRecipientResponse {
|
|
466
|
+
resolved: boolean;
|
|
467
|
+
address?: string;
|
|
468
|
+
displayName?: string;
|
|
469
|
+
error?: string;
|
|
470
|
+
}
|
|
471
|
+
export declare function resolveRecipient(value: string, type: RecipientType): Promise<ResolveRecipientResponse>;
|
|
425
472
|
export interface X402PayRequest {
|
|
426
473
|
url: string;
|
|
427
474
|
method?: string;
|
package/dist/lib/api.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CLI_USER_AGENT, getApiUrl,
|
|
1
|
+
import { CLI_USER_AGENT, getApiUrl, requireApiKey } from "./config.js";
|
|
2
2
|
const TERMINAL_STATUSES = [
|
|
3
3
|
"completed",
|
|
4
4
|
"failed",
|
|
@@ -8,16 +8,11 @@ function isTerminalStatus(status) {
|
|
|
8
8
|
return TERMINAL_STATUSES.includes(status);
|
|
9
9
|
}
|
|
10
10
|
function authHeaders() {
|
|
11
|
-
|
|
11
|
+
return {
|
|
12
12
|
"X-API-Key": requireApiKey(),
|
|
13
13
|
"Content-Type": "application/json",
|
|
14
14
|
"User-Agent": CLI_USER_AGENT,
|
|
15
15
|
};
|
|
16
|
-
const config = readConfig();
|
|
17
|
-
if (config.partnerKey) {
|
|
18
|
-
headers["X-Partner-Key"] = config.partnerKey;
|
|
19
|
-
}
|
|
20
|
-
return headers;
|
|
21
16
|
}
|
|
22
17
|
async function handleResponse(res) {
|
|
23
18
|
if (!res.ok) {
|
|
@@ -265,37 +260,42 @@ export async function claimTokenLaunchFees(tokenAddress) {
|
|
|
265
260
|
});
|
|
266
261
|
return handleResponse(res);
|
|
267
262
|
}
|
|
268
|
-
export async function
|
|
269
|
-
const res = await fetch(`${getApiUrl()}/agent/profile`, {
|
|
263
|
+
export async function getOwnProfiles() {
|
|
264
|
+
const res = await fetch(`${getApiUrl()}/agent/profile?multi=true`, {
|
|
270
265
|
headers: authHeaders(),
|
|
271
266
|
});
|
|
272
267
|
return handleResponse(res);
|
|
273
268
|
}
|
|
269
|
+
/** @deprecated Use getOwnProfiles() — returns first profile for backward compat */
|
|
270
|
+
export async function getOwnProfile() {
|
|
271
|
+
const profiles = await getOwnProfiles();
|
|
272
|
+
return profiles[0];
|
|
273
|
+
}
|
|
274
274
|
export async function createProfile(data) {
|
|
275
|
-
const res = await fetch(`${getApiUrl()}/agent/profile`, {
|
|
275
|
+
const res = await fetch(`${getApiUrl()}/agent/profile?multi=true`, {
|
|
276
276
|
method: "POST",
|
|
277
277
|
headers: authHeaders(),
|
|
278
278
|
body: JSON.stringify(data),
|
|
279
279
|
});
|
|
280
280
|
return handleResponse(res);
|
|
281
281
|
}
|
|
282
|
-
export async function updateProfile(data) {
|
|
283
|
-
const res = await fetch(`${getApiUrl()}/agent/profile`, {
|
|
282
|
+
export async function updateProfile(slug, data) {
|
|
283
|
+
const res = await fetch(`${getApiUrl()}/agent/profile/${encodeURIComponent(slug)}`, {
|
|
284
284
|
method: "PUT",
|
|
285
285
|
headers: authHeaders(),
|
|
286
286
|
body: JSON.stringify(data),
|
|
287
287
|
});
|
|
288
288
|
return handleResponse(res);
|
|
289
289
|
}
|
|
290
|
-
export async function deleteProfile() {
|
|
291
|
-
const res = await fetch(`${getApiUrl()}/agent/profile`, {
|
|
290
|
+
export async function deleteProfile(slug) {
|
|
291
|
+
const res = await fetch(`${getApiUrl()}/agent/profile/${encodeURIComponent(slug)}`, {
|
|
292
292
|
method: "DELETE",
|
|
293
293
|
headers: authHeaders(),
|
|
294
294
|
});
|
|
295
295
|
return handleResponse(res);
|
|
296
296
|
}
|
|
297
|
-
export async function addProjectUpdate(data) {
|
|
298
|
-
const res = await fetch(`${getApiUrl()}/agent/profile/update`, {
|
|
297
|
+
export async function addProjectUpdate(slug, data) {
|
|
298
|
+
const res = await fetch(`${getApiUrl()}/agent/profile/${encodeURIComponent(slug)}/update`, {
|
|
299
299
|
method: "POST",
|
|
300
300
|
headers: authHeaders(),
|
|
301
301
|
body: JSON.stringify(data),
|
|
@@ -321,6 +321,31 @@ export async function transfer(request) {
|
|
|
321
321
|
});
|
|
322
322
|
return handleResponse(res);
|
|
323
323
|
}
|
|
324
|
+
export async function getSwapQuote(request) {
|
|
325
|
+
const res = await fetch(`${getApiUrl()}/wallet/swap-quote`, {
|
|
326
|
+
method: "POST",
|
|
327
|
+
headers: authHeaders(),
|
|
328
|
+
body: JSON.stringify(request),
|
|
329
|
+
});
|
|
330
|
+
return handleResponse(res);
|
|
331
|
+
}
|
|
332
|
+
export async function executeSwap(request) {
|
|
333
|
+
const res = await fetch(`${getApiUrl()}/wallet/swap`, {
|
|
334
|
+
method: "POST",
|
|
335
|
+
headers: authHeaders(),
|
|
336
|
+
body: JSON.stringify(request),
|
|
337
|
+
});
|
|
338
|
+
return handleResponse(res);
|
|
339
|
+
}
|
|
340
|
+
export async function resolveRecipient(value, type) {
|
|
341
|
+
const params = new URLSearchParams({ value, type });
|
|
342
|
+
const res = await fetch(`${getApiUrl()}/addresses/resolve?${params}`, {
|
|
343
|
+
headers: {
|
|
344
|
+
"User-Agent": CLI_USER_AGENT,
|
|
345
|
+
},
|
|
346
|
+
});
|
|
347
|
+
return handleResponse(res);
|
|
348
|
+
}
|
|
324
349
|
export async function x402Pay(request) {
|
|
325
350
|
const res = await fetch(`${getApiUrl()}/wallet/x402-pay`, {
|
|
326
351
|
method: "POST",
|
package/dist/lib/config.d.ts
CHANGED
package/dist/lib/output.d.ts
CHANGED
|
@@ -44,5 +44,6 @@ export interface RemediationStep {
|
|
|
44
44
|
* Used when the API returns a `remediation` array in error responses.
|
|
45
45
|
*/
|
|
46
46
|
export declare function remediation(steps: RemediationStep[]): void;
|
|
47
|
+
export declare function isNonInteractive(): boolean;
|
|
47
48
|
export declare function formatStatus(status: string): string;
|
|
48
49
|
//# sourceMappingURL=output.d.ts.map
|
package/dist/lib/output.js
CHANGED
|
@@ -105,6 +105,9 @@ export function remediation(steps) {
|
|
|
105
105
|
}
|
|
106
106
|
console.log();
|
|
107
107
|
}
|
|
108
|
+
export function isNonInteractive() {
|
|
109
|
+
return process.env.BANKR_NOT_INTERACTIVE === "1";
|
|
110
|
+
}
|
|
108
111
|
export function formatStatus(status) {
|
|
109
112
|
switch (status) {
|
|
110
113
|
case "completed":
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Native-token sentinel (zero address). The API detects + sanitizes native
|
|
3
|
+
* tokens from this, so callers send it instead of a real contract address.
|
|
4
|
+
*/
|
|
5
|
+
export declare const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
|
|
6
|
+
/** Shorten an address for display, e.g. `0x8335…2913`. */
|
|
7
|
+
export declare function shortenAddress(address: string): string;
|
|
8
|
+
/**
|
|
9
|
+
* Resolve a token symbol or 0x address to `{ address, symbol }` on a chain:
|
|
10
|
+
* - a valid 0x address is used as-is (symbol shown shortened for display),
|
|
11
|
+
* - otherwise an exact, case-insensitive symbol match is looked up via
|
|
12
|
+
* `/tokens/search`, throwing a "Did you mean" suggestion list on no match.
|
|
13
|
+
*
|
|
14
|
+
* Native-token handling is caller-specific (a `--native` flag for transfer, a
|
|
15
|
+
* native-ticker/zero-address short-circuit for swap), so it lives in the command.
|
|
16
|
+
*/
|
|
17
|
+
export declare function resolveTokenSymbol(tokenInput: string, chain: string): Promise<{
|
|
18
|
+
address: string;
|
|
19
|
+
symbol: string;
|
|
20
|
+
}>;
|
|
21
|
+
//# sourceMappingURL=tokens.d.ts.map
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { isAddress } from "viem";
|
|
2
|
+
import { searchTokens } from "./api.js";
|
|
3
|
+
import { CHAIN_IDS } from "./chains.js";
|
|
4
|
+
/**
|
|
5
|
+
* Native-token sentinel (zero address). The API detects + sanitizes native
|
|
6
|
+
* tokens from this, so callers send it instead of a real contract address.
|
|
7
|
+
*/
|
|
8
|
+
export const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
|
|
9
|
+
/** Shorten an address for display, e.g. `0x8335…2913`. */
|
|
10
|
+
export function shortenAddress(address) {
|
|
11
|
+
return `${address.slice(0, 6)}…${address.slice(-4)}`;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Resolve a token symbol or 0x address to `{ address, symbol }` on a chain:
|
|
15
|
+
* - a valid 0x address is used as-is (symbol shown shortened for display),
|
|
16
|
+
* - otherwise an exact, case-insensitive symbol match is looked up via
|
|
17
|
+
* `/tokens/search`, throwing a "Did you mean" suggestion list on no match.
|
|
18
|
+
*
|
|
19
|
+
* Native-token handling is caller-specific (a `--native` flag for transfer, a
|
|
20
|
+
* native-ticker/zero-address short-circuit for swap), so it lives in the command.
|
|
21
|
+
*/
|
|
22
|
+
export async function resolveTokenSymbol(tokenInput, chain) {
|
|
23
|
+
const input = tokenInput.trim();
|
|
24
|
+
if (isAddress(input)) {
|
|
25
|
+
return { address: input, symbol: shortenAddress(input) };
|
|
26
|
+
}
|
|
27
|
+
const chainId = CHAIN_IDS[chain];
|
|
28
|
+
const res = await searchTokens(input, chainId);
|
|
29
|
+
const inputUpper = input.toUpperCase();
|
|
30
|
+
const exactMatch = res.tokens.find((t) => t.symbol.toUpperCase() === inputUpper);
|
|
31
|
+
if (!exactMatch) {
|
|
32
|
+
const available = res.tokens
|
|
33
|
+
.slice(0, 5)
|
|
34
|
+
.map((t) => `${t.symbol} (${t.address})`)
|
|
35
|
+
.join(", ");
|
|
36
|
+
throw new Error(`No exact match for "${input}" on ${chain}. Did you mean: ${available || "no results"}`);
|
|
37
|
+
}
|
|
38
|
+
return { address: exactMatch.address, symbol: exactMatch.symbol };
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=tokens.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bankr/cli",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.11",
|
|
4
4
|
"description": "Official CLI for the Bankr AI agent platform",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -40,11 +40,11 @@
|
|
|
40
40
|
"url": "https://discord.gg/bankr"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@inquirer/prompts": "^8.2
|
|
44
|
-
"chalk": "^5.
|
|
45
|
-
"commander": "^
|
|
46
|
-
"open": "^
|
|
47
|
-
"ora": "^
|
|
43
|
+
"@inquirer/prompts": "^8.4.2",
|
|
44
|
+
"chalk": "^5.6.2",
|
|
45
|
+
"commander": "^14.0.3",
|
|
46
|
+
"open": "^11.0.0",
|
|
47
|
+
"ora": "^9.4.0",
|
|
48
48
|
"viem": "^2.37.2"
|
|
49
49
|
}
|
|
50
50
|
}
|