@bagsfm/bags-cli 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,1371 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/index.ts
4
+ import { Command } from "commander";
5
+
6
+ // src/commands/setup.ts
7
+ import chalk2 from "chalk";
8
+
9
+ // src/lib/auth.ts
10
+ import bs582 from "bs58";
11
+ import nacl from "tweetnacl";
12
+ import { Keypair as Keypair2 } from "@solana/web3.js";
13
+
14
+ // src/lib/wallet.ts
15
+ import { readFile, rm } from "fs/promises";
16
+ import { Keypair } from "@solana/web3.js";
17
+ import bs58 from "bs58";
18
+
19
+ // src/lib/paths.ts
20
+ import { homedir } from "os";
21
+ import { join } from "path";
22
+ var BAGS_CONFIG_DIR = join(homedir(), ".config", "bags");
23
+ var BAGS_KEYPAIR_PATH = join(BAGS_CONFIG_DIR, "keypair.json");
24
+ var BAGS_CREDENTIALS_PATH = join(BAGS_CONFIG_DIR, "credentials.json");
25
+ var BAGS_SETTINGS_PATH = join(BAGS_CONFIG_DIR, "config.json");
26
+
27
+ // src/lib/fs.ts
28
+ import { mkdir, writeFile } from "fs/promises";
29
+ import { dirname } from "path";
30
+ async function writeJsonSecure(path, value) {
31
+ await mkdir(dirname(path), { recursive: true, mode: 448 });
32
+ await writeFile(path, `${JSON.stringify(value, null, 2)}
33
+ `, { mode: 384 });
34
+ }
35
+
36
+ // src/lib/wallet.ts
37
+ function keypairFromSecret(secret) {
38
+ return Keypair.fromSecretKey(secret);
39
+ }
40
+ async function loadKeypair(path = BAGS_KEYPAIR_PATH) {
41
+ try {
42
+ const raw = await readFile(path, "utf8");
43
+ const parsed = JSON.parse(raw);
44
+ return keypairFromSecret(Uint8Array.from(parsed));
45
+ } catch {
46
+ return null;
47
+ }
48
+ }
49
+ async function saveKeypair(keypair, path = BAGS_KEYPAIR_PATH) {
50
+ await writeJsonSecure(path, Array.from(keypair.secretKey));
51
+ }
52
+ async function generateKeypair(force = false, path = BAGS_KEYPAIR_PATH) {
53
+ const existing = await loadKeypair(path);
54
+ if (existing && !force) {
55
+ throw new Error(`Keypair already exists at ${path}. Use --force to overwrite.`);
56
+ }
57
+ const kp = Keypair.generate();
58
+ await saveKeypair(kp, path);
59
+ return kp;
60
+ }
61
+ async function importKeypairFromBase58(base58PrivateKey, path = BAGS_KEYPAIR_PATH) {
62
+ const secret = bs58.decode(base58PrivateKey);
63
+ const kp = keypairFromSecret(secret);
64
+ await saveKeypair(kp, path);
65
+ return kp;
66
+ }
67
+ async function importKeypairFromJsonFile(filePath, path = BAGS_KEYPAIR_PATH) {
68
+ const raw = await readFile(filePath, "utf8");
69
+ const parsed = JSON.parse(raw);
70
+ const kp = keypairFromSecret(Uint8Array.from(parsed));
71
+ await saveKeypair(kp, path);
72
+ return kp;
73
+ }
74
+ function detectKeyFormat(raw) {
75
+ const trimmed = raw.trim();
76
+ if (trimmed.startsWith("[") || /^\d+\s*,/.test(trimmed)) {
77
+ return "intArray";
78
+ }
79
+ return "base58";
80
+ }
81
+ async function importKeypairFromIntArray(intArrayStr, path = BAGS_KEYPAIR_PATH) {
82
+ let input3 = intArrayStr.trim();
83
+ if (!input3.startsWith("[")) {
84
+ input3 = `[${input3}]`;
85
+ }
86
+ const parsed = JSON.parse(input3);
87
+ if (!Array.isArray(parsed) || !parsed.every((n) => Number.isInteger(n))) {
88
+ throw new Error("Invalid int array format.");
89
+ }
90
+ const kp = keypairFromSecret(Uint8Array.from(parsed));
91
+ await saveKeypair(kp, path);
92
+ return kp;
93
+ }
94
+ async function deleteKeypair(path = BAGS_KEYPAIR_PATH) {
95
+ try {
96
+ await rm(path, { force: true });
97
+ } catch {
98
+ }
99
+ }
100
+
101
+ // src/lib/credentials.ts
102
+ import { readFile as readFile2, rm as rm2 } from "fs/promises";
103
+ async function loadCredentials() {
104
+ try {
105
+ const raw = await readFile2(BAGS_CREDENTIALS_PATH, "utf8");
106
+ const parsed = JSON.parse(raw);
107
+ if (!parsed.apiKey || !parsed.walletAddress) {
108
+ return null;
109
+ }
110
+ return {
111
+ apiKey: parsed.apiKey,
112
+ keyId: parsed.keyId,
113
+ walletAddress: parsed.walletAddress,
114
+ authenticatedAt: parsed.authenticatedAt ?? (/* @__PURE__ */ new Date()).toISOString()
115
+ };
116
+ } catch {
117
+ return null;
118
+ }
119
+ }
120
+ async function saveCredentials(credentials) {
121
+ await writeJsonSecure(BAGS_CREDENTIALS_PATH, credentials);
122
+ }
123
+ async function clearCredentials() {
124
+ try {
125
+ await rm2(BAGS_CREDENTIALS_PATH, { force: true });
126
+ } catch {
127
+ }
128
+ }
129
+
130
+ // src/lib/auth.ts
131
+ var BAGS_BASE_URL = "https://public-api-v2.bags.fm/api/v1";
132
+ async function post(path, body) {
133
+ const response = await fetch(`${BAGS_BASE_URL}${path}`, {
134
+ method: "POST",
135
+ headers: { "Content-Type": "application/json" },
136
+ body: JSON.stringify(body)
137
+ });
138
+ const json = await response.json();
139
+ if (!response.ok || !json.success || !json.response) {
140
+ throw new Error(json.error ?? `Request failed: ${response.status}`);
141
+ }
142
+ return json.response;
143
+ }
144
+ async function getOrCreateAuthKeypair(path = BAGS_KEYPAIR_PATH) {
145
+ const existing = await loadKeypair(path);
146
+ if (existing) {
147
+ return existing;
148
+ }
149
+ const kp = Keypair2.generate();
150
+ await saveKeypair(kp, path);
151
+ return kp;
152
+ }
153
+ async function authInit(address) {
154
+ return await post("/agent/v2/auth/init", { address });
155
+ }
156
+ function signChallengeMessage(challengeMessageBase58, keypair) {
157
+ const messageBytes = bs582.decode(challengeMessageBase58);
158
+ const signatureBytes = nacl.sign.detached(messageBytes, keypair.secretKey);
159
+ return bs582.encode(signatureBytes);
160
+ }
161
+ async function authSignatureCallback(args) {
162
+ return await post("/agent/v2/auth/callback", args);
163
+ }
164
+ async function authMfaCallback(args) {
165
+ return await post("/agent/v2/auth/callback", args);
166
+ }
167
+ async function runAgentAuthFlow(args) {
168
+ const keypair = await getOrCreateAuthKeypair(args.keypairPath);
169
+ const address = keypair.publicKey.toBase58();
170
+ const init = await authInit(address);
171
+ const signature = signChallengeMessage(init.message, keypair);
172
+ const first = await authSignatureCallback({
173
+ signature,
174
+ address,
175
+ nonce: init.nonce,
176
+ keyName: args.keyName
177
+ });
178
+ let apiKey = first.apiKey;
179
+ let keyId = first.keyId;
180
+ if (!apiKey && first.mfaRequired) {
181
+ if (!first.authCode) {
182
+ throw new Error("MFA required, but no authCode returned by API.");
183
+ }
184
+ if (!args.mfaCodeProvider) {
185
+ throw new Error("MFA required. Please provide an MFA code.");
186
+ }
187
+ const mfaCode = await args.mfaCodeProvider();
188
+ const second = await authMfaCallback({
189
+ authCode: first.authCode,
190
+ mfaCode,
191
+ keyName: args.keyName
192
+ });
193
+ apiKey = second.apiKey;
194
+ keyId = second.keyId;
195
+ }
196
+ if (!apiKey) {
197
+ throw new Error("Authentication succeeded but API key was not returned.");
198
+ }
199
+ const credentials = {
200
+ apiKey,
201
+ keyId,
202
+ walletAddress: address,
203
+ authenticatedAt: (/* @__PURE__ */ new Date()).toISOString()
204
+ };
205
+ await saveCredentials(credentials);
206
+ return credentials;
207
+ }
208
+
209
+ // src/utils/errors.ts
210
+ import chalk from "chalk";
211
+ function isUserAbort(error) {
212
+ if (!(error instanceof Error)) return false;
213
+ return error.message.includes("force closed") || error.message.includes("SIGINT") || error.name === "ExitPromptError";
214
+ }
215
+ function handleCliError(error) {
216
+ if (isUserAbort(error)) {
217
+ console.log(chalk.dim("Goodbye."));
218
+ process.exit(0);
219
+ }
220
+ if (error instanceof Error) {
221
+ console.error(chalk.red(`Error: ${error.message}`));
222
+ } else {
223
+ console.error(chalk.red("Unexpected error"), error);
224
+ }
225
+ process.exit(1);
226
+ }
227
+
228
+ // src/lib/command.ts
229
+ function wrapAction(fn) {
230
+ return async (...args) => {
231
+ const command = args[args.length - 1];
232
+ const rest = args.slice(0, -1);
233
+ try {
234
+ await fn(command, ...rest);
235
+ } catch (error) {
236
+ handleCliError(error);
237
+ }
238
+ };
239
+ }
240
+
241
+ // src/lib/config.ts
242
+ import { readFile as readFile3 } from "fs/promises";
243
+ var DEFAULT_CLI_CONFIG = {
244
+ rpcUrl: "https://api.mainnet-beta.solana.com",
245
+ commitment: "processed",
246
+ output: "pretty"
247
+ };
248
+ async function loadCliConfig() {
249
+ try {
250
+ const raw = await readFile3(BAGS_SETTINGS_PATH, "utf8");
251
+ const parsed = JSON.parse(raw);
252
+ return {
253
+ rpcUrl: parsed.rpcUrl ?? DEFAULT_CLI_CONFIG.rpcUrl,
254
+ commitment: parsed.commitment ?? DEFAULT_CLI_CONFIG.commitment,
255
+ output: parsed.output ?? DEFAULT_CLI_CONFIG.output
256
+ };
257
+ } catch {
258
+ return DEFAULT_CLI_CONFIG;
259
+ }
260
+ }
261
+ async function saveCliConfig(value) {
262
+ await writeJsonSecure(BAGS_SETTINGS_PATH, value);
263
+ }
264
+
265
+ // src/lib/prompt.ts
266
+ import { confirm, input, password, select } from "@inquirer/prompts";
267
+ async function flagOrPrompt(value, message, validate) {
268
+ if (value !== void 0 && value !== "") {
269
+ return value;
270
+ }
271
+ return await input({ message, validate });
272
+ }
273
+ async function optionalFlagOrPrompt(value, message) {
274
+ if (value !== void 0) {
275
+ return value;
276
+ }
277
+ const next = await input({ message });
278
+ return next.trim() === "" ? void 0 : next;
279
+ }
280
+ async function flagOrPromptNumber(value, message, defaultValue) {
281
+ if (value !== void 0) {
282
+ return value;
283
+ }
284
+ const raw = await input({ message, default: defaultValue?.toString() });
285
+ const n = Number(raw);
286
+ if (!Number.isFinite(n)) {
287
+ throw new Error(`Invalid number: ${raw}`);
288
+ }
289
+ return n;
290
+ }
291
+ async function promptConfirm(message, defaultValue = true) {
292
+ return await confirm({ message, default: defaultValue });
293
+ }
294
+ async function promptSecret(message) {
295
+ return await password({ message, mask: "*" });
296
+ }
297
+ async function promptOneOf(flags, labels, promptMessages) {
298
+ const keys = Object.keys(flags);
299
+ const provided = keys.filter((k) => flags[k] !== void 0 && flags[k] !== "");
300
+ if (provided.length > 1) {
301
+ throw new Error(`Only one of ${keys.map((k) => `--${String(k)}`).join(", ")} can be provided.`);
302
+ }
303
+ if (provided.length === 1) {
304
+ return { key: provided[0], value: flags[provided[0]] };
305
+ }
306
+ const key = await select({
307
+ message: "Choose one:",
308
+ choices: keys.map((k) => ({ name: labels[k], value: k }))
309
+ });
310
+ const value = await input({ message: promptMessages[key] });
311
+ if (!value.trim()) {
312
+ throw new Error(`A value is required.`);
313
+ }
314
+ return { key, value };
315
+ }
316
+
317
+ // src/utils/spinner.ts
318
+ import ora from "ora";
319
+ async function withSpinner(message, fn) {
320
+ const spinner = ora(message).start();
321
+ try {
322
+ const result = await fn();
323
+ spinner.succeed(message);
324
+ return result;
325
+ } catch (error) {
326
+ spinner.fail(`${message} failed`);
327
+ throw error;
328
+ }
329
+ }
330
+
331
+ // src/commands/setup.ts
332
+ function registerSetupCommand(program2) {
333
+ program2.command("setup").description("First-run wizard: configure RPC, import wallet, and authenticate").option("--rpc-url <url>", "Solana RPC URL").option("--private-key <key>", "Private key (base58 or int array)").option("--key-name <name>", "Label for API key", "Bags CLI Key").action(
334
+ wrapAction(async (command, options) => {
335
+ console.log(chalk2.bold("\nBags CLI Setup\n"));
336
+ const rpcUrl = await flagOrPrompt(
337
+ options.rpcUrl,
338
+ "Solana RPC URL (default: https://api.mainnet-beta.solana.com):"
339
+ );
340
+ const resolvedRpc = rpcUrl.trim() === "" ? "https://api.mainnet-beta.solana.com" : rpcUrl.trim();
341
+ const config = await loadCliConfig();
342
+ await saveCliConfig({ ...config, rpcUrl: resolvedRpc });
343
+ console.log(chalk2.green(` RPC URL saved: ${resolvedRpc}`));
344
+ let privateKeyRaw;
345
+ if (options.privateKey) {
346
+ privateKeyRaw = options.privateKey;
347
+ } else {
348
+ privateKeyRaw = await promptSecret("Private key (base58 or int array):");
349
+ }
350
+ const format = detectKeyFormat(privateKeyRaw);
351
+ const keypair = await withSpinner("Importing wallet", async () => {
352
+ if (format === "intArray") {
353
+ return await importKeypairFromIntArray(privateKeyRaw);
354
+ }
355
+ return await importKeypairFromBase58(privateKeyRaw);
356
+ });
357
+ console.log(chalk2.green(` Wallet imported: ${keypair.publicKey.toBase58()}`));
358
+ const credentials = await withSpinner("Authenticating with Bags", async () => {
359
+ return await runAgentAuthFlow({
360
+ keyName: options.keyName ?? "Bags CLI Key",
361
+ keypairPath: BAGS_KEYPAIR_PATH,
362
+ mfaCodeProvider: async () => await promptSecret("Enter MFA code:")
363
+ });
364
+ });
365
+ const masked = `${credentials.apiKey.slice(0, 6)}...${credentials.apiKey.slice(-4)}`;
366
+ console.log(
367
+ chalk2.bold.green("\nSetup complete!\n") + ` Wallet: ${credentials.walletAddress}
368
+ API Key: ${masked}
369
+ RPC: ${resolvedRpc}
370
+ `
371
+ );
372
+ })
373
+ );
374
+ }
375
+
376
+ // src/commands/auth.ts
377
+ import chalk4 from "chalk";
378
+
379
+ // src/lib/output.ts
380
+ import chalk3 from "chalk";
381
+ import Table from "cli-table3";
382
+ async function shouldUseJson(command) {
383
+ const globalOpts = command.optsWithGlobals();
384
+ if (globalOpts.json) {
385
+ return true;
386
+ }
387
+ const config = await loadCliConfig();
388
+ return config.output === "json";
389
+ }
390
+ function formatValue(value) {
391
+ if (value === null || value === void 0) {
392
+ return chalk3.dim("\u2014");
393
+ }
394
+ if (typeof value === "boolean") {
395
+ return value ? chalk3.green("yes") : chalk3.red("no");
396
+ }
397
+ if (typeof value === "number") {
398
+ return chalk3.cyan(String(value));
399
+ }
400
+ return String(value);
401
+ }
402
+ function printKeyValue(data) {
403
+ const keys = Object.keys(data);
404
+ const maxLen = Math.max(...keys.map((k) => k.length));
405
+ for (const key of keys) {
406
+ const val = data[key];
407
+ if (val !== null && typeof val === "object" && !Array.isArray(val)) {
408
+ console.log(` ${chalk3.bold(key.padEnd(maxLen))}:`);
409
+ printKeyValue(val);
410
+ continue;
411
+ }
412
+ if (Array.isArray(val)) {
413
+ console.log(` ${chalk3.bold(key.padEnd(maxLen))} ${chalk3.dim(`[${val.length} items]`)}`);
414
+ for (const item of val) {
415
+ if (item !== null && typeof item === "object") {
416
+ const summary = Object.entries(item).map(([k, v]) => `${k}=${formatValue(v)}`).join(" ");
417
+ console.log(` ${chalk3.dim("\u2022")} ${summary}`);
418
+ } else {
419
+ console.log(` ${chalk3.dim("\u2022")} ${formatValue(item)}`);
420
+ }
421
+ }
422
+ continue;
423
+ }
424
+ console.log(` ${chalk3.bold(key.padEnd(maxLen))} ${formatValue(val)}`);
425
+ }
426
+ }
427
+ async function printData(command, data) {
428
+ if (await shouldUseJson(command)) {
429
+ console.log(JSON.stringify(data, null, 2));
430
+ return;
431
+ }
432
+ if (data !== null && typeof data === "object" && !Array.isArray(data)) {
433
+ printKeyValue(data);
434
+ return;
435
+ }
436
+ if (Array.isArray(data)) {
437
+ for (const item of data) {
438
+ if (item !== null && typeof item === "object") {
439
+ printKeyValue(item);
440
+ console.log();
441
+ } else {
442
+ console.log(formatValue(item));
443
+ }
444
+ }
445
+ return;
446
+ }
447
+ console.log(formatValue(data));
448
+ }
449
+ async function printTable(command, headers, rows) {
450
+ if (await shouldUseJson(command)) {
451
+ const keys = headers.map((h) => h.toLowerCase().replace(/\s+/g, "_"));
452
+ const mapped = rows.map((row) => {
453
+ const item = {};
454
+ keys.forEach((key, i) => {
455
+ item[key] = row[i] ?? "";
456
+ });
457
+ return item;
458
+ });
459
+ console.log(JSON.stringify(mapped, null, 2));
460
+ return;
461
+ }
462
+ const table = new Table({ head: headers });
463
+ for (const row of rows) {
464
+ table.push(row);
465
+ }
466
+ console.log(table.toString());
467
+ }
468
+
469
+ // src/commands/auth.ts
470
+ function registerAuthCommands(program2) {
471
+ const auth = program2.command("auth").description("Agent authentication commands");
472
+ auth.command("login").description("Authenticate via wallet signature flow and store API key").option("--keypair <path>", "Custom keypair path").option("--key-name <name>", "Label for API key", "Bags CLI Key").action(
473
+ wrapAction(async (command, options) => {
474
+ const credentials = await withSpinner("Authenticating with Bags", async () => {
475
+ return await runAgentAuthFlow({
476
+ keyName: options.keyName ?? "Bags CLI Key",
477
+ keypairPath: options.keypair ?? BAGS_KEYPAIR_PATH,
478
+ mfaCodeProvider: async () => await promptSecret("Enter MFA code")
479
+ });
480
+ });
481
+ console.log(chalk4.green("Authentication successful."));
482
+ await printData(command, {
483
+ walletAddress: credentials.walletAddress,
484
+ keyId: credentials.keyId ?? null,
485
+ authenticatedAt: credentials.authenticatedAt
486
+ });
487
+ })
488
+ );
489
+ auth.command("status").description("Show current authentication state").action(
490
+ wrapAction(async (command) => {
491
+ const credentials = await loadCredentials();
492
+ if (!credentials) {
493
+ console.log(chalk4.yellow("Not authenticated. Run `bags auth login`."));
494
+ return;
495
+ }
496
+ const masked = `${credentials.apiKey.slice(0, 6)}...${credentials.apiKey.slice(-4)}`;
497
+ await printData(command, {
498
+ authenticated: true,
499
+ walletAddress: credentials.walletAddress,
500
+ apiKey: masked,
501
+ keyId: credentials.keyId ?? null,
502
+ authenticatedAt: credentials.authenticatedAt
503
+ });
504
+ })
505
+ );
506
+ auth.command("logout").description("Remove credentials. Optionally remove keypair too").option("--all", "Also remove wallet keypair").action(
507
+ wrapAction(async (_command, options) => {
508
+ await clearCredentials();
509
+ if (options.all) {
510
+ await deleteKeypair();
511
+ }
512
+ console.log(chalk4.green(`Logged out${options.all ? " and deleted keypair" : ""}.`));
513
+ })
514
+ );
515
+ }
516
+
517
+ // src/commands/config.ts
518
+ import { PublicKey } from "@solana/web3.js";
519
+
520
+ // src/lib/sdk.ts
521
+ import { Connection } from "@solana/web3.js";
522
+ import { BagsSDK } from "@bagsfm/bags-sdk";
523
+ var cached = null;
524
+ async function getSdkContext(forceRefresh = false) {
525
+ if (cached && !forceRefresh) {
526
+ return cached;
527
+ }
528
+ const credentials = await loadCredentials();
529
+ if (!credentials) {
530
+ throw new Error("Not authenticated. Run `bags auth login` first.");
531
+ }
532
+ const config = await loadCliConfig();
533
+ const connection = new Connection(config.rpcUrl, config.commitment);
534
+ const sdk = new BagsSDK(credentials.apiKey, connection, config.commitment);
535
+ cached = { sdk, connection };
536
+ return cached;
537
+ }
538
+
539
+ // src/lib/signer.ts
540
+ async function getLocalSigner() {
541
+ const keypair = await loadKeypair();
542
+ if (!keypair) {
543
+ throw new Error("No local keypair found. Run `bags wallet generate` or `bags wallet import`.");
544
+ }
545
+ const config = await loadCliConfig();
546
+ return { keypair, commitment: config.commitment };
547
+ }
548
+
549
+ // src/lib/tx.ts
550
+ import { signAndSendTransaction } from "@bagsfm/bags-sdk";
551
+ async function signAndSend(connection, commitment, transaction, keypair) {
552
+ const signature = await signAndSendTransaction(connection, commitment, transaction, keypair);
553
+ return signature;
554
+ }
555
+
556
+ // src/commands/config.ts
557
+ function parseClaimers(raw) {
558
+ if (!raw) {
559
+ throw new Error(`--fee-claimers is required. Example: '[{"user":"...","userBps":10000}]'`);
560
+ }
561
+ const parsed = JSON.parse(raw);
562
+ return parsed.map((x) => ({ user: new PublicKey(x.user), userBps: x.userBps }));
563
+ }
564
+ function registerConfigCommands(program2) {
565
+ const config = program2.command("config").description("Fee share configuration");
566
+ config.command("create").description("Create a fee share config for a token").option("--mint <address>", "Base mint").option("--fee-claimers <json>", "JSON array [{user,userBps}]").option("--partner <pubkey>", "Partner wallet").option("--skip-confirm", "Skip confirmation").action(
567
+ wrapAction(async (command, options) => {
568
+ const mint = new PublicKey(await flagOrPrompt(options.mint, "Base mint:"));
569
+ const feeClaimers = parseClaimers(options.feeClaimers);
570
+ const { sdk, connection } = await getSdkContext();
571
+ const { keypair, commitment } = await getLocalSigner();
572
+ if (!options.skipConfirm) {
573
+ const ok = await promptConfirm(`Create fee config for ${mint.toBase58()}?`);
574
+ if (!ok) return;
575
+ }
576
+ const result = await sdk.config.createBagsFeeShareConfig({
577
+ payer: keypair.publicKey,
578
+ baseMint: mint,
579
+ feeClaimers,
580
+ partner: options.partner ? new PublicKey(options.partner) : void 0
581
+ });
582
+ const signatures = [];
583
+ if (Array.isArray(result.transactions)) {
584
+ for (const tx of result.transactions) {
585
+ signatures.push(await signAndSend(connection, commitment, tx, keypair));
586
+ }
587
+ }
588
+ await printData(command, {
589
+ meteoraConfigKey: result.meteoraConfigKey?.toString?.() ?? result.meteoraConfigKey,
590
+ signatures
591
+ });
592
+ })
593
+ );
594
+ config.command("update").description("Update fee share config as admin").option("--mint <address>", "Base mint").option("--fee-claimers <json>", "JSON array [{user,userBps}]").option("--skip-confirm", "Skip confirmation").action(
595
+ wrapAction(async (command, options) => {
596
+ const mint = new PublicKey(await flagOrPrompt(options.mint, "Base mint:"));
597
+ const feeClaimers = parseClaimers(options.feeClaimers);
598
+ const { sdk, connection } = await getSdkContext();
599
+ const { keypair, commitment } = await getLocalSigner();
600
+ if (!options.skipConfirm) {
601
+ const ok = await promptConfirm(`Update admin config for ${mint.toBase58()}?`);
602
+ if (!ok) return;
603
+ }
604
+ const result = await sdk.feeShareAdmin.createUpdateConfigTransactions({
605
+ payer: keypair.publicKey,
606
+ baseMint: mint,
607
+ feeClaimers
608
+ });
609
+ const signatures = [];
610
+ if (Array.isArray(result.transactions)) {
611
+ for (const tx of result.transactions) {
612
+ signatures.push(await signAndSend(connection, commitment, tx, keypair));
613
+ }
614
+ }
615
+ await printData(command, { signatures });
616
+ })
617
+ );
618
+ config.command("transfer-admin").description("Transfer fee share admin authority").option("--mint <address>", "Base mint").option("--new-admin <pubkey>", "New admin wallet").option("--skip-confirm", "Skip confirmation").action(
619
+ wrapAction(async (command, options) => {
620
+ const mint = new PublicKey(await flagOrPrompt(options.mint, "Base mint:"));
621
+ const newAdmin = new PublicKey(await flagOrPrompt(options.newAdmin, "New admin:"));
622
+ const { sdk, connection } = await getSdkContext();
623
+ const { keypair, commitment } = await getLocalSigner();
624
+ if (!options.skipConfirm) {
625
+ const ok = await promptConfirm(`Transfer admin for ${mint.toBase58()} to ${newAdmin.toBase58()}?`);
626
+ if (!ok) return;
627
+ }
628
+ const tx = await sdk.feeShareAdmin.createTransferAdminTransaction({
629
+ payer: keypair.publicKey,
630
+ baseMint: mint,
631
+ newAdmin
632
+ });
633
+ const signature = await signAndSend(connection, commitment, tx, keypair);
634
+ await printData(command, { signature });
635
+ })
636
+ );
637
+ config.command("admin-list").description("List mints where wallet is fee share admin").action(
638
+ wrapAction(async (command) => {
639
+ const { sdk } = await getSdkContext();
640
+ const { keypair } = await getLocalSigner();
641
+ const list = await sdk.feeShareAdmin.getAdminTokenMints(keypair.publicKey);
642
+ await printData(command, list);
643
+ })
644
+ );
645
+ }
646
+
647
+ // src/commands/dexscreener.ts
648
+ import { PublicKey as PublicKey2 } from "@solana/web3.js";
649
+ function registerDexscreenerCommands(program2) {
650
+ const dexscreener = program2.command("dexscreener").description("Dexscreener order flows");
651
+ dexscreener.command("check").description("Check Dexscreener order availability").option("--mint <address>", "Token mint").action(
652
+ wrapAction(async (command, options) => {
653
+ const mint = new PublicKey2(await flagOrPrompt(options.mint, "Token mint:"));
654
+ const { sdk } = await getSdkContext();
655
+ const result = await sdk.dexscreener.checkOrderAvailability(mint);
656
+ await printData(command, result);
657
+ })
658
+ );
659
+ dexscreener.command("order").description("Create Dexscreener order").option("--mint <address>", "Token mint").option("--payload <json>", "Raw JSON payload override").action(
660
+ wrapAction(async (command, options) => {
661
+ const mint = await flagOrPrompt(options.mint, "Token mint:");
662
+ const payload = options.payload !== void 0 ? JSON.parse(options.payload) : {
663
+ tokenMint: mint
664
+ };
665
+ const { sdk } = await getSdkContext();
666
+ const result = await sdk.dexscreener.createOrder(payload);
667
+ await printData(command, result);
668
+ })
669
+ );
670
+ dexscreener.command("pay").description("Submit Dexscreener payment").option("--order-id <id>", "Order ID").option("--transaction <tx>", "Signed serialized transaction").action(
671
+ wrapAction(async (command, options) => {
672
+ const orderId = await flagOrPrompt(options.orderId, "Order ID:");
673
+ const transaction = await flagOrPrompt(options.transaction, "Signed transaction:");
674
+ const { sdk } = await getSdkContext();
675
+ const result = await sdk.dexscreener.submitPayment({ orderId, transaction });
676
+ await printData(command, result);
677
+ })
678
+ );
679
+ }
680
+
681
+ // src/commands/fees.ts
682
+ import { PublicKey as PublicKey3 } from "@solana/web3.js";
683
+
684
+ // src/utils/format.ts
685
+ function lamportsToSol(lamports) {
686
+ return (lamports / 1e9).toFixed(9);
687
+ }
688
+ function shortAddress(value) {
689
+ if (value.length < 10) {
690
+ return value;
691
+ }
692
+ return `${value.slice(0, 4)}...${value.slice(-4)}`;
693
+ }
694
+
695
+ // src/commands/fees.ts
696
+ async function resolveMint(value) {
697
+ const mint = await flagOrPrompt(value, "Token mint:");
698
+ return new PublicKey3(mint);
699
+ }
700
+ async function getClaimTransactionsForMint(sdk, wallet, mint) {
701
+ const fee = sdk.fee;
702
+ if (typeof fee.getClaimTransactions === "function") {
703
+ return await fee.getClaimTransactions(wallet, mint);
704
+ }
705
+ if (typeof fee.getClaimTransaction === "function") {
706
+ const tx = await fee.getClaimTransaction(wallet, mint);
707
+ return tx ? [tx] : [];
708
+ }
709
+ throw new Error("This SDK version does not expose claim transaction methods.");
710
+ }
711
+ function registerFeesCommands(program2) {
712
+ const fees = program2.command("fees").description("Fee claiming and fee analytics");
713
+ fees.command("list").description("List claimable fee positions for local wallet").action(
714
+ wrapAction(async (command) => {
715
+ const { sdk } = await getSdkContext();
716
+ const { keypair } = await getLocalSigner();
717
+ const positions = await sdk.fee.getAllClaimablePositions(keypair.publicKey);
718
+ const rows = positions.map((p) => [
719
+ String(p.baseMint ?? ""),
720
+ Number(p.totalClaimableLamportsUserShare ?? 0),
721
+ p.isCustomFeeVault ? "yes" : "no"
722
+ ]);
723
+ await printTable(command, ["Mint", "Claimable Lamports", "Custom Vault"], rows);
724
+ })
725
+ );
726
+ fees.command("claim").description("Claim fees for a single token mint").argument("[mint]", "Token mint address").option("--mint <address>", "Token mint").option("--skip-confirm", "Skip transaction confirmation").action(
727
+ wrapAction(async (command, mintArg, options) => {
728
+ const mint = await resolveMint(mintArg ?? options.mint);
729
+ const { sdk, connection } = await getSdkContext();
730
+ const { keypair, commitment } = await getLocalSigner();
731
+ if (!options.skipConfirm) {
732
+ const ok = await promptConfirm(`Claim fees for ${mint.toBase58()}?`);
733
+ if (!ok) {
734
+ return;
735
+ }
736
+ }
737
+ const transactions = await getClaimTransactionsForMint(sdk, keypair.publicKey, mint);
738
+ const signatures = [];
739
+ for (const tx of transactions) {
740
+ signatures.push(await signAndSend(connection, commitment, tx, keypair));
741
+ }
742
+ await printData(command, { mint: mint.toBase58(), signatures });
743
+ })
744
+ );
745
+ fees.command("claim-all").description("Claim all claimable fees for the local wallet").option("--skip-confirm", "Skip transaction confirmation").action(
746
+ wrapAction(async (command, options) => {
747
+ const { sdk, connection } = await getSdkContext();
748
+ const { keypair, commitment } = await getLocalSigner();
749
+ const feeService = sdk.fee;
750
+ const positions = await feeService.getAllClaimablePositions(keypair.publicKey);
751
+ const mints = [...new Set(positions.map((p) => String(p.baseMint)))];
752
+ if (!options.skipConfirm) {
753
+ const ok = await promptConfirm(`Claim fees across ${mints.length} token(s)?`);
754
+ if (!ok) {
755
+ return;
756
+ }
757
+ }
758
+ const sent = [];
759
+ for (const mint of mints) {
760
+ const txs = await getClaimTransactionsForMint(sdk, keypair.publicKey, new PublicKey3(mint));
761
+ const signatures = [];
762
+ for (const tx of txs) {
763
+ signatures.push(await signAndSend(connection, commitment, tx, keypair));
764
+ }
765
+ sent.push({ mint, signatures });
766
+ }
767
+ await printData(command, { count: sent.length, claims: sent });
768
+ })
769
+ );
770
+ fees.command("lifetime").description("Get token lifetime fees").argument("[mint]", "Token mint address").option("--mint <address>", "Token mint").option("--raw", "Show raw lamports instead of SOL").action(
771
+ wrapAction(async (command, mintArg, options) => {
772
+ const mint = await resolveMint(mintArg ?? options.mint);
773
+ const { sdk } = await getSdkContext();
774
+ const result = await sdk.state.getTokenLifetimeFees(mint);
775
+ if (typeof result === "number") {
776
+ await printData(command, {
777
+ mint: mint.toBase58(),
778
+ lifetimeFees: options.raw ? `${result} lamports` : `${lamportsToSol(result)} SOL`
779
+ });
780
+ } else {
781
+ await printData(command, result);
782
+ }
783
+ })
784
+ );
785
+ fees.command("events").description("Get token claim events").argument("[mint]", "Token mint address").option("--mint <address>", "Token mint").option("--offset <n>", "Offset", Number).option("--limit <n>", "Limit", Number).option("--start-time <iso>", "Start timestamp (ISO)").option("--end-time <iso>", "End timestamp (ISO)").action(
786
+ wrapAction(async (command, mintArg, options) => {
787
+ const mint = await resolveMint(mintArg ?? options.mint);
788
+ const { sdk } = await getSdkContext();
789
+ const payload = { mint: mint.toBase58() };
790
+ if (options.offset !== void 0) payload.offset = options.offset;
791
+ if (options.limit !== void 0) payload.limit = options.limit;
792
+ if (options.startTime) payload.startTime = options.startTime;
793
+ if (options.endTime) payload.endTime = options.endTime;
794
+ const result = await sdk.state.getTokenClaimEvents(payload);
795
+ await printData(command, result);
796
+ })
797
+ );
798
+ fees.command("stats").description("Get token claim stats").argument("[mint]", "Token mint address").option("--mint <address>", "Token mint").action(
799
+ wrapAction(async (command, mintArg, options) => {
800
+ const mint = await resolveMint(mintArg ?? options.mint);
801
+ const { sdk } = await getSdkContext();
802
+ const result = await sdk.state.getTokenClaimStats(mint);
803
+ await printData(command, result);
804
+ })
805
+ );
806
+ }
807
+
808
+ // src/commands/incorporation.ts
809
+ import { PublicKey as PublicKey4 } from "@solana/web3.js";
810
+ function registerIncorporationCommands(program2) {
811
+ const inc = program2.command("incorporation").description("Incorporation project flows");
812
+ inc.command("pay").description("Start incorporation payment").option("--mint <address>", "Token mint").option("--payload <json>", "Raw JSON payload override").action(
813
+ wrapAction(async (command, options) => {
814
+ const mint = await flagOrPrompt(options.mint, "Token mint:");
815
+ const { sdk } = await getSdkContext();
816
+ const payload = options.payload !== void 0 ? JSON.parse(options.payload) : { tokenMint: mint };
817
+ const result = await sdk.incorporation.startPayment(payload);
818
+ await printData(command, result);
819
+ })
820
+ );
821
+ inc.command("submit").description("Submit incorporation details").option("--mint <address>", "Token mint").option("--company-name <name>", "Company name").option("--founders <json>", "JSON founders array").option("--category <value>", "Project category").action(
822
+ wrapAction(async (command, options) => {
823
+ const mint = await flagOrPrompt(options.mint, "Token mint:");
824
+ const companyName = await flagOrPrompt(options.companyName, "Company name:");
825
+ const foundersRaw = await flagOrPrompt(options.founders, "Founders JSON:");
826
+ const category = await flagOrPrompt(options.category, "Category:");
827
+ const founders = JSON.parse(foundersRaw);
828
+ const { sdk } = await getSdkContext();
829
+ const result = await sdk.incorporation.incorporate({
830
+ tokenMint: mint,
831
+ companyName,
832
+ founders,
833
+ category
834
+ });
835
+ await printData(command, result);
836
+ })
837
+ );
838
+ inc.command("start").description("Start incorporation process").option("--mint <address>", "Token mint").action(
839
+ wrapAction(async (command, options) => {
840
+ const mint = await flagOrPrompt(options.mint, "Token mint:");
841
+ const { sdk } = await getSdkContext();
842
+ const result = await sdk.incorporation.startIncorporation({ tokenMint: mint });
843
+ await printData(command, result);
844
+ })
845
+ );
846
+ inc.command("list").description("List incorporation projects for API key").action(
847
+ wrapAction(async (command) => {
848
+ const { sdk } = await getSdkContext();
849
+ const result = await sdk.incorporation.list();
850
+ await printData(command, result);
851
+ })
852
+ );
853
+ inc.command("details").description("Get incorporation details by token mint").option("--mint <address>", "Token mint").action(
854
+ wrapAction(async (command, options) => {
855
+ const mint = new PublicKey4(await flagOrPrompt(options.mint, "Token mint:"));
856
+ const { sdk } = await getSdkContext();
857
+ const result = await sdk.incorporation.getDetails(mint);
858
+ await printData(command, result);
859
+ })
860
+ );
861
+ }
862
+
863
+ // src/commands/launch.ts
864
+ import {
865
+ BAGS_FEE_SHARE_V2_MAX_CLAIMERS_NON_LUT,
866
+ createTipTransaction,
867
+ sendBundleAndConfirm,
868
+ waitForSlotsToPass
869
+ } from "@bagsfm/bags-sdk";
870
+ import { LAMPORTS_PER_SOL, PublicKey as PublicKey5 } from "@solana/web3.js";
871
+ import chalk5 from "chalk";
872
+ import { confirm as confirm2, input as input2, select as select2 } from "@inquirer/prompts";
873
+ var SOCIAL_PROVIDERS = ["twitter", "github", "kick", "tiktok"];
874
+ var MAX_CLAIMERS = 100;
875
+ var TOTAL_BPS = 1e4;
876
+ async function sendBundleWithTip(sdk, connection, keypair, unsignedTransactions) {
877
+ const bundleBlockhash = unsignedTransactions[0]?.message.recentBlockhash;
878
+ if (!bundleBlockhash) {
879
+ throw new Error("Missing blockhash in bundle transaction.");
880
+ }
881
+ let tipLamports = Math.floor(0.015 * LAMPORTS_PER_SOL);
882
+ try {
883
+ const fees = await sdk.solana.getJitoRecentFees();
884
+ if (fees?.landed_tips_95th_percentile) {
885
+ tipLamports = Math.floor(Number(fees.landed_tips_95th_percentile) * LAMPORTS_PER_SOL);
886
+ }
887
+ } catch {
888
+ }
889
+ const tipTx = await createTipTransaction(connection, sdk.state.getCommitment(), keypair.publicKey, tipLamports, {
890
+ blockhash: bundleBlockhash
891
+ });
892
+ const signed = [tipTx, ...unsignedTransactions].map((tx) => {
893
+ tx.sign([keypair]);
894
+ return tx;
895
+ });
896
+ return await sendBundleAndConfirm(signed, sdk);
897
+ }
898
+ function parseFeeClaimers(raw) {
899
+ if (!raw) {
900
+ return [];
901
+ }
902
+ const parsed = JSON.parse(raw);
903
+ if (!Array.isArray(parsed)) {
904
+ throw new Error("--fee-claimers must be a JSON array.");
905
+ }
906
+ return parsed;
907
+ }
908
+ function printClaimerSummary(claimers) {
909
+ const usedBps = claimers.reduce((s, c) => s + c.bps, 0);
910
+ console.log(chalk5.dim("\n Fee claimers:"));
911
+ claimers.forEach((c, i) => {
912
+ const label = c.wallet ? `wallet:${shortAddress(c.wallet)}` : `${c.provider}:${c.username}`;
913
+ console.log(` ${i + 1}. ${label.padEnd(28)} ${(c.bps / 100).toFixed(2)}%`);
914
+ });
915
+ console.log(chalk5.dim(` Creator keeps: ${((TOTAL_BPS - usedBps) / 100).toFixed(2)}%
916
+ `));
917
+ }
918
+ async function buildFeeClaimersInteractive() {
919
+ const shareFees = await confirm2({ message: "Share fees with others?", default: false });
920
+ if (!shareFees) {
921
+ return [];
922
+ }
923
+ const claimers = [];
924
+ let usedBps = 0;
925
+ while (claimers.length < MAX_CLAIMERS && usedBps < TOTAL_BPS) {
926
+ const remaining = TOTAL_BPS - usedBps;
927
+ console.log(chalk5.dim(`
928
+ Adding fee claimer ${claimers.length + 1}/${MAX_CLAIMERS} (${remaining} BPS remaining)`));
929
+ const type = await select2({
930
+ message: "Claimer type:",
931
+ choices: [
932
+ { name: "Social media account", value: "social" },
933
+ { name: "Direct wallet address", value: "wallet" }
934
+ ]
935
+ });
936
+ let claimer;
937
+ if (type === "social") {
938
+ const provider = await select2({
939
+ message: "Platform:",
940
+ choices: SOCIAL_PROVIDERS.map((p) => ({ name: p, value: p }))
941
+ });
942
+ const username = await input2({ message: "Username:" });
943
+ if (!username.trim()) {
944
+ throw new Error("Username is required.");
945
+ }
946
+ const bps = await inputBps(remaining);
947
+ claimer = { provider, username: username.trim(), bps };
948
+ } else {
949
+ const wallet = await input2({ message: "Wallet address:" });
950
+ if (!wallet.trim()) {
951
+ throw new Error("Wallet address is required.");
952
+ }
953
+ new PublicKey5(wallet.trim());
954
+ const bps = await inputBps(remaining);
955
+ claimer = { wallet: wallet.trim(), bps };
956
+ }
957
+ claimers.push(claimer);
958
+ usedBps += claimer.bps;
959
+ printClaimerSummary(claimers);
960
+ if (claimers.length >= MAX_CLAIMERS || usedBps >= TOTAL_BPS) {
961
+ break;
962
+ }
963
+ const more = await confirm2({ message: "Add another fee claimer?", default: true });
964
+ if (!more) {
965
+ break;
966
+ }
967
+ }
968
+ return claimers;
969
+ }
970
+ async function inputBps(remaining) {
971
+ const raw = await input2({
972
+ message: `Basis points (1-${remaining}, e.g. 3000 = 30%):`,
973
+ validate: (val) => {
974
+ const n = Number(val);
975
+ if (!Number.isInteger(n) || n < 1 || n > remaining) {
976
+ return `Enter a whole number between 1 and ${remaining}.`;
977
+ }
978
+ return true;
979
+ }
980
+ });
981
+ return Number(raw);
982
+ }
983
+ function registerLaunchCommands(program2) {
984
+ const launch = program2.command("launch").description("Token launch flows");
985
+ launch.command("create").description("Create and launch a token").option("--name <name>", "Token name").option("--symbol <symbol>", "Token symbol").option("--description <description>", "Token description").option("--image-url <url>", "Image URL").option("--image <path>", "Image file path").option("--twitter <url>", "Twitter URL").option("--website <url>", "Website URL").option("--telegram <url>", "Telegram URL").option("--initial-buy <lamports>", "Initial buy amount in lamports", Number).option("--fee-claimers <json>", "JSON array of fee claimers").option("--partner <pubkey>", "Partner wallet").option("--partner-config <pubkey>", "Partner config PDA").option("--skip-confirm", "Skip final confirmation").action(
986
+ wrapAction(async (command, options) => {
987
+ const { sdk, connection } = await getSdkContext();
988
+ const { keypair, commitment } = await getLocalSigner();
989
+ const name = await flagOrPrompt(options.name, "Token name:");
990
+ const symbol = await flagOrPrompt(options.symbol, "Token symbol:");
991
+ const description = await flagOrPrompt(options.description, "Token description:");
992
+ const imageChoice = await promptOneOf(
993
+ { imageUrl: options.imageUrl, image: options.image },
994
+ { imageUrl: "Image URL", image: "Image file path" },
995
+ { imageUrl: "Image URL:", image: "Image file path:" }
996
+ );
997
+ const imageUrl = imageChoice.key === "imageUrl" ? imageChoice.value : void 0;
998
+ const image = imageChoice.key === "image" ? imageChoice.value : void 0;
999
+ const initialBuy = await flagOrPromptNumber(options.initialBuy, "Initial buy (lamports):", 1e7);
1000
+ const twitter = await optionalFlagOrPrompt(options.twitter, "Twitter URL (optional):");
1001
+ const website = await optionalFlagOrPrompt(options.website, "Website URL (optional):");
1002
+ const telegram = await optionalFlagOrPrompt(options.telegram, "Telegram URL (optional):");
1003
+ const feeClaimersInput = options.feeClaimers ? parseFeeClaimers(options.feeClaimers) : await buildFeeClaimersInteractive();
1004
+ if (!options.skipConfirm) {
1005
+ let summary = `Launch ${name} (${symbol}) with initial buy ${initialBuy} lamports from ${keypair.publicKey.toBase58()}`;
1006
+ if (feeClaimersInput.length > 0) {
1007
+ const allocBps = feeClaimersInput.reduce((s, c) => s + c.bps, 0);
1008
+ const lines = feeClaimersInput.map((c) => {
1009
+ const label = c.wallet ? `wallet:${shortAddress(c.wallet)}` : `${c.provider}:${c.username}`;
1010
+ return ` ${label} ${(c.bps / 100).toFixed(2)}%`;
1011
+ });
1012
+ lines.push(` creator: ${((TOTAL_BPS - allocBps) / 100).toFixed(2)}%`);
1013
+ summary += `
1014
+
1015
+ Fee split:
1016
+ ${lines.join("\n")}`;
1017
+ } else {
1018
+ summary += "\n\nFee split: 100% to creator";
1019
+ }
1020
+ const ok = await promptConfirm(`${summary}
1021
+
1022
+ Proceed?`);
1023
+ if (!ok) {
1024
+ return;
1025
+ }
1026
+ }
1027
+ const metadata = await sdk.tokenLaunch.createTokenInfoAndMetadata({
1028
+ imageUrl,
1029
+ imagePath: image,
1030
+ name,
1031
+ symbol: symbol.toUpperCase().replace("$", ""),
1032
+ description,
1033
+ twitter,
1034
+ website,
1035
+ telegram
1036
+ });
1037
+ const tokenMint = new PublicKey5(metadata.tokenMint);
1038
+ const feeClaimers = [];
1039
+ if (feeClaimersInput.length > 0) {
1040
+ const allocatedBps = feeClaimersInput.reduce((sum, c) => sum + c.bps, 0);
1041
+ const creatorBps = TOTAL_BPS - allocatedBps;
1042
+ if (creatorBps < 0) {
1043
+ throw new Error("Total fee claimer BPS exceeds 10000.");
1044
+ }
1045
+ if (creatorBps > 0) {
1046
+ feeClaimers.push({ user: keypair.publicKey, userBps: creatorBps });
1047
+ }
1048
+ for (const claimer of feeClaimersInput) {
1049
+ if (claimer.wallet) {
1050
+ feeClaimers.push({ user: new PublicKey5(claimer.wallet), userBps: claimer.bps });
1051
+ } else if (claimer.username && claimer.provider) {
1052
+ const user = await sdk.state.getLaunchWalletV2(claimer.username, claimer.provider);
1053
+ feeClaimers.push({ user: user.wallet, userBps: claimer.bps });
1054
+ } else {
1055
+ throw new Error("Each fee claimer must have either wallet or provider+username.");
1056
+ }
1057
+ }
1058
+ } else {
1059
+ feeClaimers.push({ user: keypair.publicKey, userBps: TOTAL_BPS });
1060
+ }
1061
+ let additionalLookupTables;
1062
+ if (feeClaimers.length > BAGS_FEE_SHARE_V2_MAX_CLAIMERS_NON_LUT) {
1063
+ const lutResult = await sdk.config.getConfigCreationLookupTableTransactions({
1064
+ payer: keypair.publicKey,
1065
+ baseMint: tokenMint,
1066
+ feeClaimers
1067
+ });
1068
+ await signAndSend(connection, commitment, lutResult.creationTransaction, keypair);
1069
+ await waitForSlotsToPass(connection, commitment, 1);
1070
+ for (const tx of lutResult.extendTransactions) {
1071
+ await signAndSend(connection, commitment, tx, keypair);
1072
+ }
1073
+ additionalLookupTables = lutResult.lutAddresses;
1074
+ }
1075
+ const configResult = await sdk.config.createBagsFeeShareConfig({
1076
+ payer: keypair.publicKey,
1077
+ baseMint: tokenMint,
1078
+ feeClaimers,
1079
+ partner: options.partner ? new PublicKey5(options.partner) : void 0,
1080
+ partnerConfig: options.partnerConfig ? new PublicKey5(options.partnerConfig) : void 0,
1081
+ additionalLookupTables
1082
+ });
1083
+ if (Array.isArray(configResult.bundles)) {
1084
+ for (const bundle of configResult.bundles) {
1085
+ await sendBundleWithTip(sdk, connection, keypair, bundle);
1086
+ }
1087
+ }
1088
+ if (Array.isArray(configResult.transactions)) {
1089
+ for (const tx of configResult.transactions) {
1090
+ await signAndSend(connection, commitment, tx, keypair);
1091
+ }
1092
+ }
1093
+ const launchTx = await sdk.tokenLaunch.createLaunchTransaction({
1094
+ metadataUrl: metadata.tokenMetadata,
1095
+ tokenMint,
1096
+ launchWallet: keypair.publicKey,
1097
+ initialBuyLamports: initialBuy,
1098
+ configKey: configResult.meteoraConfigKey
1099
+ });
1100
+ const signature = await signAndSend(connection, commitment, launchTx, keypair);
1101
+ await printData(command, {
1102
+ tokenMint: metadata.tokenMint,
1103
+ metadataUrl: metadata.tokenMetadata,
1104
+ configKey: configResult.meteoraConfigKey?.toString?.() ?? configResult.meteoraConfigKey,
1105
+ signature
1106
+ });
1107
+ })
1108
+ );
1109
+ launch.command("feed").description("Get token launch feed").option("--limit <n>", "Number of items", Number).action(
1110
+ wrapAction(async (command, options) => {
1111
+ const { sdk } = await getSdkContext();
1112
+ const result = await sdk.state.getTokenLaunchFeed({ limit: options.limit ?? 20 });
1113
+ await printData(command, result);
1114
+ })
1115
+ );
1116
+ launch.command("creators").description("Get creators for a token mint").option("--mint <address>", "Token mint").action(
1117
+ wrapAction(async (command, options) => {
1118
+ const mint = new PublicKey5(await flagOrPrompt(options.mint, "Token mint:"));
1119
+ const { sdk } = await getSdkContext();
1120
+ const result = await sdk.state.getTokenCreators(mint);
1121
+ await printData(command, result);
1122
+ })
1123
+ );
1124
+ }
1125
+
1126
+ // src/commands/partner.ts
1127
+ import { PublicKey as PublicKey6 } from "@solana/web3.js";
1128
+ function registerPartnerCommands(program2) {
1129
+ const partner = program2.command("partner").description("Partner configuration and claim");
1130
+ partner.command("create").description("Create partner config for local wallet").option("--skip-confirm", "Skip confirmation").action(
1131
+ wrapAction(async (command, options) => {
1132
+ const { sdk, connection } = await getSdkContext();
1133
+ const { keypair, commitment } = await getLocalSigner();
1134
+ if (!options.skipConfirm) {
1135
+ const ok = await promptConfirm(`Create partner config for ${keypair.publicKey.toBase58()}?`);
1136
+ if (!ok) return;
1137
+ }
1138
+ const tx = await sdk.partner.createPartnerConfigTransaction(keypair.publicKey);
1139
+ const signature = await signAndSend(connection, commitment, tx, keypair);
1140
+ await printData(command, { signature });
1141
+ })
1142
+ );
1143
+ partner.command("stats").description("Get partner stats").option("--partner <pubkey>", "Partner wallet pubkey").action(
1144
+ wrapAction(async (command, options) => {
1145
+ const { sdk } = await getSdkContext();
1146
+ const { keypair } = await getLocalSigner();
1147
+ const partnerWallet = new PublicKey6(await flagOrPrompt(options.partner, "Partner wallet (default local):"));
1148
+ const stats = await sdk.partner.getPartnerStats(partnerWallet ?? keypair.publicKey);
1149
+ await printData(command, stats);
1150
+ })
1151
+ );
1152
+ partner.command("claim").description("Claim partner fees").option("--skip-confirm", "Skip confirmation").action(
1153
+ wrapAction(async (command, options) => {
1154
+ const { sdk, connection } = await getSdkContext();
1155
+ const { keypair, commitment } = await getLocalSigner();
1156
+ if (!options.skipConfirm) {
1157
+ const ok = await promptConfirm(`Claim partner fees for ${keypair.publicKey.toBase58()}?`);
1158
+ if (!ok) return;
1159
+ }
1160
+ const txs = await sdk.partner.getPartnerClaimTransactions(keypair.publicKey);
1161
+ const signatures = [];
1162
+ for (const tx of txs) {
1163
+ signatures.push(await signAndSend(connection, commitment, tx, keypair));
1164
+ }
1165
+ await printData(command, { signatures });
1166
+ })
1167
+ );
1168
+ }
1169
+
1170
+ // src/commands/pool.ts
1171
+ import { PublicKey as PublicKey7 } from "@solana/web3.js";
1172
+ function registerPoolCommands(program2) {
1173
+ const pool = program2.command("pool").description("Pool lookup commands");
1174
+ pool.command("list").description("List Bags pools").option("--limit <n>", "Limit", Number).option("--offset <n>", "Offset", Number).action(
1175
+ wrapAction(async (command, options) => {
1176
+ const { sdk } = await getSdkContext();
1177
+ const result = await sdk.state.getBagsPools({
1178
+ limit: options.limit ?? 50,
1179
+ offset: options.offset ?? 0
1180
+ });
1181
+ await printData(command, result);
1182
+ })
1183
+ );
1184
+ pool.command("get").description("Get Bags pool by token mint").option("--mint <address>", "Token mint").action(
1185
+ wrapAction(async (command, options) => {
1186
+ const mint = new PublicKey7(await flagOrPrompt(options.mint, "Token mint:"));
1187
+ const { sdk } = await getSdkContext();
1188
+ const result = await sdk.state.getBagsPoolByTokenMint(mint);
1189
+ await printData(command, result);
1190
+ })
1191
+ );
1192
+ }
1193
+
1194
+ // src/commands/settings.ts
1195
+ function registerSettingsCommands(program2) {
1196
+ const settings = program2.command("settings").description("CLI settings");
1197
+ settings.command("show").description("Show current settings").action(
1198
+ wrapAction(async (command) => {
1199
+ const config = await loadCliConfig();
1200
+ await printData(command, config);
1201
+ })
1202
+ );
1203
+ settings.command("set").description("Set one or more settings").option("--rpc-url <url>", "Default RPC URL").option("--commitment <level>", "processed|confirmed|finalized").option("--output <mode>", "pretty|table|json").action(
1204
+ wrapAction(async (command, options) => {
1205
+ const current = await loadCliConfig();
1206
+ const next = {
1207
+ rpcUrl: options.rpcUrl ?? current.rpcUrl,
1208
+ commitment: options.commitment ?? current.commitment,
1209
+ output: options.output ?? current.output
1210
+ };
1211
+ await saveCliConfig(next);
1212
+ await printData(command, next);
1213
+ })
1214
+ );
1215
+ }
1216
+
1217
+ // src/commands/trade.ts
1218
+ import { PublicKey as PublicKey8 } from "@solana/web3.js";
1219
+ async function resolveQuoteOptions(options) {
1220
+ const inputMint = new PublicKey8(await flagOrPrompt(options.inputMint, "Input mint:"));
1221
+ const outputMint = new PublicKey8(await flagOrPrompt(options.outputMint, "Output mint:"));
1222
+ const amount = await flagOrPromptNumber(options.amount, "Amount (base units):");
1223
+ const slippageMode = await flagOrPrompt(options.slippageMode, "Slippage mode (auto/manual):");
1224
+ const slippageBps = slippageMode === "manual" ? await flagOrPromptNumber(options.slippageBps, "Slippage BPS (e.g. 100):") : void 0;
1225
+ return { inputMint, outputMint, amount, slippageMode, slippageBps };
1226
+ }
1227
+ function registerTradeCommands(program2) {
1228
+ const trade = program2.command("trade").description("Quote and execute swaps");
1229
+ trade.command("quote").description("Get a swap quote").option("--input-mint <address>", "Input token mint").option("--output-mint <address>", "Output token mint").option("--amount <amount>", "Amount in base units", Number).option("--slippage-mode <mode>", "auto or manual", "auto").option("--slippage-bps <bps>", "Required for manual mode", Number).action(
1230
+ wrapAction(async (command, options) => {
1231
+ const { sdk } = await getSdkContext();
1232
+ const quoteArgs = await resolveQuoteOptions(options);
1233
+ const quote = await sdk.trade.getQuote(quoteArgs);
1234
+ await printData(command, quote);
1235
+ })
1236
+ );
1237
+ trade.command("swap").description("Execute a swap (quote + transaction send)").option("--input-mint <address>", "Input token mint").option("--output-mint <address>", "Output token mint").option("--amount <amount>", "Amount in base units", Number).option("--slippage-mode <mode>", "auto or manual", "auto").option("--slippage-bps <bps>", "Required for manual mode", Number).option("--skip-confirm", "Skip transaction confirmation").action(
1238
+ wrapAction(async (command, options) => {
1239
+ const quoteArgs = await resolveQuoteOptions(options);
1240
+ const { sdk, connection } = await getSdkContext();
1241
+ const { keypair, commitment } = await getLocalSigner();
1242
+ const quote = await sdk.trade.getQuote(quoteArgs);
1243
+ if (!options.skipConfirm) {
1244
+ const ok = await promptConfirm(
1245
+ `Swap ${quoteArgs.amount} from ${quoteArgs.inputMint.toBase58()} to ${quoteArgs.outputMint.toBase58()}?`
1246
+ );
1247
+ if (!ok) {
1248
+ return;
1249
+ }
1250
+ }
1251
+ const swap = await sdk.trade.createSwapTransaction({
1252
+ quoteResponse: quote,
1253
+ userPublicKey: keypair.publicKey
1254
+ });
1255
+ const signature = await signAndSend(connection, commitment, swap.transaction, keypair);
1256
+ await printData(command, { signature, quote, computeUnitLimit: swap.computeUnitLimit });
1257
+ })
1258
+ );
1259
+ }
1260
+
1261
+ // src/commands/wallet.ts
1262
+ import { Connection as Connection2, PublicKey as PublicKey9 } from "@solana/web3.js";
1263
+ function registerWalletCommands(program2) {
1264
+ const wallet = program2.command("wallet").description("Wallet management commands");
1265
+ wallet.command("generate").description("Generate and save a new local Solana keypair").option("--force", "Overwrite existing keypair").action(
1266
+ wrapAction(async (command, options) => {
1267
+ const kp = await generateKeypair(Boolean(options.force));
1268
+ await printData(command, { publicKey: kp.publicKey.toBase58(), path: BAGS_KEYPAIR_PATH });
1269
+ })
1270
+ );
1271
+ wallet.command("import").description("Import keypair from base58 key or JSON secret file").option("--key <base58>", "Base58 private key").option("--file <path>", "JSON file containing secret key bytes").action(
1272
+ wrapAction(async (command, options) => {
1273
+ let kp;
1274
+ if (options.key) {
1275
+ kp = await importKeypairFromBase58(options.key);
1276
+ } else if (options.file) {
1277
+ kp = await importKeypairFromJsonFile(options.file);
1278
+ } else {
1279
+ const method = await flagOrPrompt(void 0, "Import method (key/file):");
1280
+ if (method === "file") {
1281
+ const file = await flagOrPrompt(void 0, "Path to keypair JSON file:");
1282
+ kp = await importKeypairFromJsonFile(file);
1283
+ } else {
1284
+ const key = await flagOrPrompt(void 0, "Base58 private key:");
1285
+ kp = await importKeypairFromBase58(key);
1286
+ }
1287
+ }
1288
+ await printData(command, { publicKey: kp.publicKey.toBase58(), path: BAGS_KEYPAIR_PATH });
1289
+ })
1290
+ );
1291
+ wallet.command("show").description("Show wallet address and SOL balance").option("--rpc <url>", "Override RPC URL").action(
1292
+ wrapAction(async (command, options) => {
1293
+ const kp = await loadKeypair();
1294
+ if (!kp) {
1295
+ throw new Error("No local keypair found. Run `bags wallet generate` or `bags wallet import`.");
1296
+ }
1297
+ const config = await loadCliConfig();
1298
+ const connection = new Connection2(options.rpc ?? config.rpcUrl, config.commitment);
1299
+ let sol = "unknown";
1300
+ try {
1301
+ const lamports = await connection.getBalance(kp.publicKey, config.commitment);
1302
+ sol = `${lamportsToSol(lamports)} SOL`;
1303
+ } catch {
1304
+ }
1305
+ await printData(command, {
1306
+ publicKey: kp.publicKey.toBase58(),
1307
+ balance: sol,
1308
+ keypairPath: BAGS_KEYPAIR_PATH
1309
+ });
1310
+ })
1311
+ );
1312
+ wallet.command("balance").description("Show SOL or SPL token balance").option("--rpc <url>", "Override RPC URL").option("--token <mint>", "SPL token mint address").action(
1313
+ wrapAction(async (command, options) => {
1314
+ const kp = await loadKeypair();
1315
+ if (!kp) {
1316
+ throw new Error("No local keypair found.");
1317
+ }
1318
+ const config = await loadCliConfig();
1319
+ const connection = new Connection2(options.rpc ?? config.rpcUrl, config.commitment);
1320
+ if (options.token) {
1321
+ const mint = new PublicKey9(options.token);
1322
+ const accounts = await connection.getParsedTokenAccountsByOwner(kp.publicKey, { mint });
1323
+ if (accounts.value.length === 0) {
1324
+ await printData(command, {
1325
+ publicKey: kp.publicKey.toBase58(),
1326
+ token: mint.toBase58(),
1327
+ balance: "0"
1328
+ });
1329
+ return;
1330
+ }
1331
+ const info = accounts.value[0].account.data.parsed.info.tokenAmount;
1332
+ await printData(command, {
1333
+ publicKey: kp.publicKey.toBase58(),
1334
+ token: mint.toBase58(),
1335
+ balance: `${info.uiAmountString} (raw: ${info.amount})`
1336
+ });
1337
+ return;
1338
+ }
1339
+ const lamports = await connection.getBalance(kp.publicKey, config.commitment);
1340
+ await printData(command, {
1341
+ publicKey: kp.publicKey.toBase58(),
1342
+ balance: `${lamportsToSol(lamports)} SOL`
1343
+ });
1344
+ })
1345
+ );
1346
+ }
1347
+
1348
+ // src/index.ts
1349
+ var program = new Command();
1350
+ program.name("bags").description("Bags CLI - auth, trading, launches, fees, and config").version("0.1.0").option("--json", "Output machine-readable JSON where supported");
1351
+ registerSetupCommand(program);
1352
+ registerAuthCommands(program);
1353
+ registerWalletCommands(program);
1354
+ registerFeesCommands(program);
1355
+ registerTradeCommands(program);
1356
+ registerLaunchCommands(program);
1357
+ registerConfigCommands(program);
1358
+ registerPartnerCommands(program);
1359
+ registerPoolCommands(program);
1360
+ registerDexscreenerCommands(program);
1361
+ registerIncorporationCommands(program);
1362
+ registerSettingsCommands(program);
1363
+ async function main() {
1364
+ try {
1365
+ await program.parseAsync(process.argv);
1366
+ } catch (error) {
1367
+ handleCliError(error);
1368
+ }
1369
+ }
1370
+ void main();
1371
+ //# sourceMappingURL=index.js.map