naracli 1.0.17 → 1.0.22

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.
Files changed (41) hide show
  1. package/README.md +101 -114
  2. package/bin/nara-cli.ts +0 -20
  3. package/dist/nara-cli.mjs +49930 -2222
  4. package/index.ts +10 -58
  5. package/package.json +7 -6
  6. package/src/cli/commands/quest.ts +8 -7
  7. package/src/cli/commands/skills.ts +491 -0
  8. package/src/cli/commands/skillsInstall.ts +793 -0
  9. package/src/cli/commands/wallet.ts +13 -114
  10. package/src/cli/commands/zkid.ts +410 -0
  11. package/src/cli/index.ts +215 -9
  12. package/src/cli/prompts/searchMultiselect.ts +297 -0
  13. package/src/cli/types.ts +0 -138
  14. package/src/cli/utils/transaction.ts +1 -1
  15. package/src/cli/utils/validation.ts +0 -40
  16. package/src/cli/utils/wallet.ts +3 -1
  17. package/src/tests/helpers.ts +78 -0
  18. package/src/tests/skills.e2e.test.ts +126 -0
  19. package/src/tests/skills.test.ts +192 -0
  20. package/src/tests/test_skill.md +18 -0
  21. package/src/tests/zkid.e2e.test.ts +128 -0
  22. package/src/tests/zkid.test.ts +153 -0
  23. package/src/types/snarkjs.d.ts +4 -1
  24. package/dist/quest/nara_quest.json +0 -534
  25. package/dist/zk/answer_proof.wasm +0 -0
  26. package/dist/zk/answer_proof_final.zkey +0 -0
  27. package/src/cli/commands/config.ts +0 -125
  28. package/src/cli/commands/migrate.ts +0 -270
  29. package/src/cli/commands/pool.ts +0 -364
  30. package/src/cli/commands/swap.ts +0 -349
  31. package/src/cli/quest/nara_quest.json +0 -534
  32. package/src/cli/quest/nara_quest_types.ts +0 -540
  33. package/src/cli/zk/answer_proof.wasm +0 -0
  34. package/src/cli/zk/answer_proof_final.zkey +0 -0
  35. package/src/client.ts +0 -96
  36. package/src/config.ts +0 -132
  37. package/src/constants.ts +0 -35
  38. package/src/migrate.ts +0 -222
  39. package/src/pool.ts +0 -259
  40. package/src/quest.ts +0 -387
  41. package/src/swap.ts +0 -608
package/src/cli/index.ts CHANGED
@@ -3,23 +3,229 @@
3
3
  */
4
4
 
5
5
  import { Command } from "commander";
6
- import { registerConfigCommands } from "./commands/config";
7
- import { registerPoolCommands } from "./commands/pool";
8
- import { registerSwapCommands } from "./commands/swap";
9
- import { registerMigrateCommands } from "./commands/migrate";
6
+ import {
7
+ Transaction,
8
+ VersionedTransaction,
9
+ } from "@solana/web3.js";
10
10
  import { registerWalletCommands } from "./commands/wallet";
11
11
  import { registerQuestCommands } from "./commands/quest";
12
+ import { registerSkillsCommands } from "./commands/skills";
13
+ import { registerZkIdCommands } from "./commands/zkid";
14
+ import {
15
+ handleWalletAddress,
16
+ handleWalletBalance,
17
+ handleTokenBalance,
18
+ handleTxStatus,
19
+ handleTransferSol,
20
+ handleTransferToken,
21
+ } from "./commands/wallet";
22
+ import { loadWallet, getRpcUrl } from "./utils/wallet";
23
+ import { NaraSDK } from "nara-sdk";
24
+ import { printError, printInfo, printSuccess } from "./utils/output";
25
+ import type {
26
+ GlobalOptions,
27
+ WalletBalanceOptions,
28
+ TokenBalanceOptions,
29
+ TxStatusOptions,
30
+ TransferSolOptions,
31
+ TransferTokenOptions,
32
+ } from "./types";
33
+
34
+ /**
35
+ * Poll for transaction confirmation via HTTP
36
+ */
37
+ async function pollConfirmation(
38
+ connection: any,
39
+ signature: string,
40
+ timeoutMs = 15000,
41
+ intervalMs = 1000
42
+ ): Promise<void> {
43
+ const start = Date.now();
44
+ while (Date.now() - start < timeoutMs) {
45
+ const { value } = await connection.getSignatureStatuses([signature]);
46
+ const status = value?.[0];
47
+ if (status) {
48
+ if (status.err) {
49
+ throw new Error(`Transaction failed: ${JSON.stringify(status.err)}`);
50
+ }
51
+ if (status.confirmationStatus === "confirmed" || status.confirmationStatus === "finalized") {
52
+ return;
53
+ }
54
+ }
55
+ await new Promise((r) => setTimeout(r, intervalMs));
56
+ }
57
+ throw new Error("Transaction confirmation timeout");
58
+ }
12
59
 
13
60
  /**
14
61
  * Register all CLI commands
15
62
  * @param program Commander program
16
63
  */
17
64
  export function registerCommands(program: Command): void {
18
- // Register command modules
19
- registerConfigCommands(program);
20
- registerPoolCommands(program);
21
- registerSwapCommands(program);
22
- registerMigrateCommands(program);
65
+ // wallet (create, import only)
23
66
  registerWalletCommands(program);
67
+
68
+ // quest
24
69
  registerQuestCommands(program);
70
+
71
+ // skills
72
+ registerSkillsCommands(program);
73
+
74
+ // zkid
75
+ registerZkIdCommands(program);
76
+
77
+ // Top-level: address
78
+ program
79
+ .command("address")
80
+ .description("Show wallet address")
81
+ .action(async () => {
82
+ const opts = program.opts() as GlobalOptions;
83
+ try {
84
+ await handleWalletAddress(opts);
85
+ } catch (error: any) {
86
+ printError(error.message);
87
+ process.exit(1);
88
+ }
89
+ });
90
+
91
+ // Top-level: balance
92
+ program
93
+ .command("balance")
94
+ .description("Check NARA balance")
95
+ .argument("[address]", "Wallet address (optional, defaults to current wallet)")
96
+ .action(async (address: string | undefined) => {
97
+ const opts = program.opts() as WalletBalanceOptions;
98
+ try {
99
+ await handleWalletBalance(address, opts);
100
+ } catch (error: any) {
101
+ printError(error.message);
102
+ process.exit(1);
103
+ }
104
+ });
105
+
106
+ // Top-level: token-balance
107
+ program
108
+ .command("token-balance <token-address>")
109
+ .description("Check token balance")
110
+ .option("--owner <address>", "Owner address (optional, defaults to current wallet)")
111
+ .action(async (tokenAddress: string, options: { owner?: string }) => {
112
+ const opts = program.opts() as TokenBalanceOptions;
113
+ try {
114
+ await handleTokenBalance(tokenAddress, { ...opts, ...options });
115
+ } catch (error: any) {
116
+ printError(error.message);
117
+ process.exit(1);
118
+ }
119
+ });
120
+
121
+ // Top-level: tx-status
122
+ program
123
+ .command("tx-status <signature>")
124
+ .description("Check transaction status")
125
+ .action(async (signature: string) => {
126
+ const opts = program.opts() as TxStatusOptions;
127
+ try {
128
+ await handleTxStatus(signature, opts);
129
+ } catch (error: any) {
130
+ printError(error.message);
131
+ process.exit(1);
132
+ }
133
+ });
134
+
135
+ // Top-level: transfer
136
+ program
137
+ .command("transfer <to> <amount>")
138
+ .description("Transfer NARA to another wallet")
139
+ .option("-e, --export-tx", "Export unsigned transaction", false)
140
+ .action(async (to: string, amount: string, options: { exportTx?: boolean }) => {
141
+ const opts = program.opts() as TransferSolOptions;
142
+ try {
143
+ await handleTransferSol(to, amount, { ...opts, ...options });
144
+ } catch (error: any) {
145
+ printError(error.message);
146
+ process.exit(1);
147
+ }
148
+ });
149
+
150
+ // Top-level: transfer-token
151
+ program
152
+ .command("transfer-token <token-address> <to> <amount>")
153
+ .description("Transfer tokens to another wallet")
154
+ .option("--decimals <number>", "Token decimals", "6")
155
+ .option("-e, --export-tx", "Export unsigned transaction", false)
156
+ .action(async (tokenAddress: string, to: string, amount: string, options: { decimals?: string; exportTx?: boolean }) => {
157
+ const opts = program.opts() as TransferTokenOptions;
158
+ try {
159
+ await handleTransferToken(tokenAddress, to, amount, { ...opts, decimals: options.decimals ? parseInt(options.decimals) : undefined, exportTx: options.exportTx });
160
+ } catch (error: any) {
161
+ printError(error.message);
162
+ process.exit(1);
163
+ }
164
+ });
165
+
166
+ // Top-level: sign
167
+ program
168
+ .command("sign <base64-tx>")
169
+ .description("Sign a base64-encoded transaction")
170
+ .option("--send", "Send the signed transaction", false)
171
+ .action(async (base64Tx: string, options: { send?: boolean }) => {
172
+ const opts = program.opts() as GlobalOptions;
173
+ try {
174
+ const wallet = await loadWallet(opts.wallet);
175
+ const buf = Buffer.from(base64Tx, "base64");
176
+
177
+ // Try VersionedTransaction first, fall back to legacy
178
+ let tx: Transaction | VersionedTransaction;
179
+ try {
180
+ tx = VersionedTransaction.deserialize(new Uint8Array(buf));
181
+ } catch {
182
+ tx = Transaction.from(buf);
183
+ }
184
+
185
+ // Sign
186
+ if (tx instanceof VersionedTransaction) {
187
+ tx.sign([wallet]);
188
+ } else {
189
+ tx.sign(wallet);
190
+ }
191
+
192
+ if (options.send) {
193
+ const rpcUrl = getRpcUrl(opts.rpcUrl);
194
+ const sdk = new NaraSDK({ rpcUrl, commitment: "confirmed" });
195
+ const connection = sdk.getConnection();
196
+
197
+ printInfo("Sending transaction...");
198
+ let signature: string;
199
+ if (tx instanceof VersionedTransaction) {
200
+ signature = await connection.sendTransaction(tx, { maxRetries: 3 });
201
+ } else {
202
+ signature = await connection.sendRawTransaction(tx.serialize(), { skipPreflight: true });
203
+ }
204
+
205
+ printInfo("Confirming transaction...");
206
+ await pollConfirmation(connection, signature);
207
+
208
+ if (opts.json) {
209
+ console.log(JSON.stringify({ signature }, null, 2));
210
+ } else {
211
+ printSuccess("Transaction sent!");
212
+ console.log(`Signature: ${signature}`);
213
+ }
214
+ } else {
215
+ // Output signed base64
216
+ const serialized = tx instanceof VersionedTransaction
217
+ ? Buffer.from(tx.serialize()).toString("base64")
218
+ : Buffer.from(tx.serialize()).toString("base64");
219
+
220
+ if (opts.json) {
221
+ console.log(JSON.stringify({ transaction: serialized }, null, 2));
222
+ } else {
223
+ console.log(serialized);
224
+ }
225
+ }
226
+ } catch (error: any) {
227
+ printError(error.message);
228
+ process.exit(1);
229
+ }
230
+ });
25
231
  }
@@ -0,0 +1,297 @@
1
+ import * as readline from 'readline';
2
+ import { Writable } from 'stream';
3
+ import pc from 'picocolors';
4
+
5
+ // Silent writable stream to prevent readline from echoing input
6
+ const silentOutput = new Writable({
7
+ write(_chunk, _encoding, callback) {
8
+ callback();
9
+ },
10
+ });
11
+
12
+ export interface SearchItem<T> {
13
+ value: T;
14
+ label: string;
15
+ hint?: string;
16
+ }
17
+
18
+ export interface LockedSection<T> {
19
+ title: string;
20
+ items: SearchItem<T>[];
21
+ }
22
+
23
+ export interface SearchMultiselectOptions<T> {
24
+ message: string;
25
+ items: SearchItem<T>[];
26
+ maxVisible?: number;
27
+ initialSelected?: T[];
28
+ /** If true, require at least one item to be selected before submitting */
29
+ required?: boolean;
30
+ /** Locked section shown above the searchable list - items are always selected and can't be toggled */
31
+ lockedSection?: LockedSection<T>;
32
+ }
33
+
34
+ const S_STEP_ACTIVE = pc.green('◆');
35
+ const S_STEP_CANCEL = pc.red('■');
36
+ const S_STEP_SUBMIT = pc.green('◇');
37
+ const S_RADIO_ACTIVE = pc.green('●');
38
+ const S_RADIO_INACTIVE = pc.dim('○');
39
+ const S_CHECKBOX_LOCKED = pc.green('✓');
40
+ const S_BULLET = pc.green('•');
41
+ const S_BAR = pc.dim('│');
42
+ const S_BAR_H = pc.dim('─');
43
+
44
+ export const cancelSymbol = Symbol('cancel');
45
+
46
+ /**
47
+ * Interactive search multiselect prompt.
48
+ * Allows users to filter a long list by typing and select multiple items.
49
+ * Optionally supports a "locked" section that displays always-selected items.
50
+ */
51
+ export async function searchMultiselect<T>(
52
+ options: SearchMultiselectOptions<T>
53
+ ): Promise<T[] | symbol> {
54
+ const {
55
+ message,
56
+ items,
57
+ maxVisible = 8,
58
+ initialSelected = [],
59
+ required = false,
60
+ lockedSection,
61
+ } = options;
62
+
63
+ return new Promise((resolve) => {
64
+ const rl = readline.createInterface({
65
+ input: process.stdin,
66
+ output: silentOutput,
67
+ terminal: false,
68
+ });
69
+
70
+ // Enable raw mode for keypress detection
71
+ if (process.stdin.isTTY) {
72
+ process.stdin.setRawMode(true);
73
+ }
74
+ readline.emitKeypressEvents(process.stdin, rl);
75
+
76
+ let query = '';
77
+ let cursor = 0;
78
+ const selected = new Set<T>(initialSelected);
79
+ let lastRenderHeight = 0;
80
+
81
+ // Locked items are always included in the result
82
+ const lockedValues = lockedSection ? lockedSection.items.map((i) => i.value) : [];
83
+
84
+ const filter = (item: SearchItem<T>, q: string): boolean => {
85
+ if (!q) return true;
86
+ const lowerQ = q.toLowerCase();
87
+ return (
88
+ item.label.toLowerCase().includes(lowerQ) ||
89
+ String(item.value).toLowerCase().includes(lowerQ)
90
+ );
91
+ };
92
+
93
+ const getFiltered = (): SearchItem<T>[] => {
94
+ return items.filter((item) => filter(item, query));
95
+ };
96
+
97
+ const clearRender = (): void => {
98
+ if (lastRenderHeight > 0) {
99
+ // Move up and clear each line
100
+ process.stdout.write(`\x1b[${lastRenderHeight}A`);
101
+ for (let i = 0; i < lastRenderHeight; i++) {
102
+ process.stdout.write('\x1b[2K\x1b[1B');
103
+ }
104
+ process.stdout.write(`\x1b[${lastRenderHeight}A`);
105
+ }
106
+ };
107
+
108
+ const render = (state: 'active' | 'submit' | 'cancel' = 'active'): void => {
109
+ clearRender();
110
+
111
+ const lines: string[] = [];
112
+ const filtered = getFiltered();
113
+
114
+ // Header
115
+ const icon =
116
+ state === 'active' ? S_STEP_ACTIVE : state === 'cancel' ? S_STEP_CANCEL : S_STEP_SUBMIT;
117
+ lines.push(`${icon} ${pc.bold(message)}`);
118
+
119
+ if (state === 'active') {
120
+ // Locked section (universal agents)
121
+ if (lockedSection && lockedSection.items.length > 0) {
122
+ lines.push(`${S_BAR}`);
123
+ const lockedTitle = `${pc.bold(lockedSection.title)} ${pc.dim('── always included')}`;
124
+ lines.push(`${S_BAR} ${S_BAR_H}${S_BAR_H} ${lockedTitle} ${S_BAR_H.repeat(12)}`);
125
+ for (const item of lockedSection.items) {
126
+ lines.push(`${S_BAR} ${S_BULLET} ${pc.bold(item.label)}`);
127
+ }
128
+ lines.push(`${S_BAR}`);
129
+ lines.push(
130
+ `${S_BAR} ${S_BAR_H}${S_BAR_H} ${pc.bold('Additional agents')} ${S_BAR_H.repeat(29)}`
131
+ );
132
+ }
133
+
134
+ // Search input
135
+ const searchLine = `${S_BAR} ${pc.dim('Search:')} ${query}${pc.inverse(' ')}`;
136
+ lines.push(searchLine);
137
+
138
+ // Hint
139
+ lines.push(`${S_BAR} ${pc.dim('↑↓ move, space select, enter confirm')}`);
140
+ lines.push(`${S_BAR}`);
141
+
142
+ // Items
143
+ const visibleStart = Math.max(
144
+ 0,
145
+ Math.min(cursor - Math.floor(maxVisible / 2), filtered.length - maxVisible)
146
+ );
147
+ const visibleEnd = Math.min(filtered.length, visibleStart + maxVisible);
148
+ const visibleItems = filtered.slice(visibleStart, visibleEnd);
149
+
150
+ if (filtered.length === 0) {
151
+ lines.push(`${S_BAR} ${pc.dim('No matches found')}`);
152
+ } else {
153
+ for (let i = 0; i < visibleItems.length; i++) {
154
+ const item = visibleItems[i]!;
155
+ const actualIndex = visibleStart + i;
156
+ const isSelected = selected.has(item.value);
157
+ const isCursor = actualIndex === cursor;
158
+
159
+ const radio = isSelected ? S_RADIO_ACTIVE : S_RADIO_INACTIVE;
160
+ const label = isCursor ? pc.underline(item.label) : item.label;
161
+ const hint = item.hint ? pc.dim(` (${item.hint})`) : '';
162
+
163
+ const prefix = isCursor ? pc.cyan('❯') : ' ';
164
+ lines.push(`${S_BAR} ${prefix} ${radio} ${label}${hint}`);
165
+ }
166
+
167
+ // Show count if more items
168
+ const hiddenBefore = visibleStart;
169
+ const hiddenAfter = filtered.length - visibleEnd;
170
+ if (hiddenBefore > 0 || hiddenAfter > 0) {
171
+ const parts: string[] = [];
172
+ if (hiddenBefore > 0) parts.push(`↑ ${hiddenBefore} more`);
173
+ if (hiddenAfter > 0) parts.push(`↓ ${hiddenAfter} more`);
174
+ lines.push(`${S_BAR} ${pc.dim(parts.join(' '))}`);
175
+ }
176
+ }
177
+
178
+ // Selected summary (include locked items)
179
+ lines.push(`${S_BAR}`);
180
+ const allSelectedLabels = [
181
+ ...(lockedSection ? lockedSection.items.map((i) => i.label) : []),
182
+ ...items.filter((item) => selected.has(item.value)).map((item) => item.label),
183
+ ];
184
+ if (allSelectedLabels.length === 0) {
185
+ lines.push(`${S_BAR} ${pc.dim('Selected: (none)')}`);
186
+ } else {
187
+ const summary =
188
+ allSelectedLabels.length <= 3
189
+ ? allSelectedLabels.join(', ')
190
+ : `${allSelectedLabels.slice(0, 3).join(', ')} +${allSelectedLabels.length - 3} more`;
191
+ lines.push(`${S_BAR} ${pc.green('Selected:')} ${summary}`);
192
+ }
193
+
194
+ lines.push(`${pc.dim('└')}`);
195
+ } else if (state === 'submit') {
196
+ // Final state - show what was selected (including locked)
197
+ const allSelectedLabels = [
198
+ ...(lockedSection ? lockedSection.items.map((i) => i.label) : []),
199
+ ...items.filter((item) => selected.has(item.value)).map((item) => item.label),
200
+ ];
201
+ lines.push(`${S_BAR} ${pc.dim(allSelectedLabels.join(', '))}`);
202
+ } else if (state === 'cancel') {
203
+ lines.push(`${S_BAR} ${pc.strikethrough(pc.dim('Cancelled'))}`);
204
+ }
205
+
206
+ process.stdout.write(lines.join('\n') + '\n');
207
+ lastRenderHeight = lines.length;
208
+ };
209
+
210
+ const cleanup = (): void => {
211
+ process.stdin.removeListener('keypress', keypressHandler);
212
+ if (process.stdin.isTTY) {
213
+ process.stdin.setRawMode(false);
214
+ }
215
+ rl.close();
216
+ };
217
+
218
+ const submit = (): void => {
219
+ // If required and no locked items, don't allow submitting with no selection
220
+ if (required && selected.size === 0 && lockedValues.length === 0) {
221
+ return;
222
+ }
223
+ render('submit');
224
+ cleanup();
225
+ // Include locked values in the result
226
+ resolve([...lockedValues, ...Array.from(selected)]);
227
+ };
228
+
229
+ const cancel = (): void => {
230
+ render('cancel');
231
+ cleanup();
232
+ resolve(cancelSymbol);
233
+ };
234
+
235
+ // Handle keypresses
236
+ const keypressHandler = (_str: string, key: readline.Key): void => {
237
+ if (!key) return;
238
+
239
+ const filtered = getFiltered();
240
+
241
+ if (key.name === 'return') {
242
+ submit();
243
+ return;
244
+ }
245
+
246
+ if (key.name === 'escape' || (key.ctrl && key.name === 'c')) {
247
+ cancel();
248
+ return;
249
+ }
250
+
251
+ if (key.name === 'up') {
252
+ cursor = Math.max(0, cursor - 1);
253
+ render();
254
+ return;
255
+ }
256
+
257
+ if (key.name === 'down') {
258
+ cursor = Math.min(filtered.length - 1, cursor + 1);
259
+ render();
260
+ return;
261
+ }
262
+
263
+ if (key.name === 'space') {
264
+ const item = filtered[cursor];
265
+ if (item) {
266
+ if (selected.has(item.value)) {
267
+ selected.delete(item.value);
268
+ } else {
269
+ selected.add(item.value);
270
+ }
271
+ }
272
+ render();
273
+ return;
274
+ }
275
+
276
+ if (key.name === 'backspace') {
277
+ query = query.slice(0, -1);
278
+ cursor = 0;
279
+ render();
280
+ return;
281
+ }
282
+
283
+ // Regular character input
284
+ if (key.sequence && !key.ctrl && !key.meta && key.sequence.length === 1) {
285
+ query += key.sequence;
286
+ cursor = 0;
287
+ render();
288
+ return;
289
+ }
290
+ };
291
+
292
+ process.stdin.on('keypress', keypressHandler);
293
+
294
+ // Initial render
295
+ render();
296
+ });
297
+ }
package/src/cli/types.ts CHANGED
@@ -2,8 +2,6 @@
2
2
  * CLI-specific types and interfaces
3
3
  */
4
4
 
5
- import { PublicKey } from "@solana/web3.js";
6
-
7
5
  /**
8
6
  * Global options available on all commands
9
7
  */
@@ -16,142 +14,6 @@ export interface GlobalOptions {
16
14
  json?: boolean;
17
15
  }
18
16
 
19
- /**
20
- * Config create command options
21
- */
22
- export interface ConfigCreateOptions extends GlobalOptions {
23
- /** Fee claimer wallet address */
24
- feeClaimer?: string;
25
- /** Leftover token receiver wallet address */
26
- leftoverReceiver?: string;
27
- /** Total token supply */
28
- totalSupply?: number;
29
- /** Initial market cap */
30
- initialMcap?: number;
31
- /** Migration market cap */
32
- migrationMcap?: number;
33
- /** Export unsigned transaction */
34
- exportTx?: boolean;
35
- }
36
-
37
- /**
38
- * Pool create command options
39
- */
40
- export interface PoolCreateOptions extends GlobalOptions {
41
- /** Token name */
42
- name: string;
43
- /** Token symbol */
44
- symbol: string;
45
- /** Metadata URI */
46
- uri: string;
47
- /** DBC config address */
48
- dbcConfig: string;
49
- /** Pool creator address */
50
- creator?: string;
51
- /** Export unsigned transaction */
52
- exportTx?: boolean;
53
- }
54
-
55
- /**
56
- * Pool create with buy command options
57
- */
58
- export interface PoolCreateWithBuyOptions extends PoolCreateOptions {
59
- /** Initial buy amount in SOL */
60
- amount: number;
61
- /** Buyer address */
62
- buyer?: string;
63
- /** Token receiver address */
64
- receiver?: string;
65
- /** Slippage in basis points */
66
- slippage?: number;
67
- }
68
-
69
- /**
70
- * Pool info command options
71
- */
72
- export interface PoolInfoOptions extends GlobalOptions {
73
- /** Token address */
74
- tokenAddress: string;
75
- }
76
-
77
- /**
78
- * Swap buy command options
79
- */
80
- export interface SwapBuyOptions extends GlobalOptions {
81
- /** Token address */
82
- tokenAddress: string;
83
- /** Amount in SOL */
84
- amount: number;
85
- /** Slippage in basis points */
86
- slippage?: number;
87
- /** Swap mode */
88
- mode?: string;
89
- /** Export unsigned transaction */
90
- exportTx?: boolean;
91
- }
92
-
93
- /**
94
- * Swap sell command options
95
- */
96
- export interface SwapSellOptions extends GlobalOptions {
97
- /** Token address */
98
- tokenAddress: string;
99
- /** Amount in tokens */
100
- amount: number;
101
- /** Token decimals */
102
- decimals?: number;
103
- /** Slippage in basis points */
104
- slippage?: number;
105
- /** Swap mode */
106
- mode?: string;
107
- /** Export unsigned transaction */
108
- exportTx?: boolean;
109
- }
110
-
111
- /**
112
- * Swap quote command options
113
- */
114
- export interface SwapQuoteOptions extends GlobalOptions {
115
- /** Token address */
116
- tokenAddress: string;
117
- /** Amount */
118
- amount: number;
119
- /** Direction: buy or sell */
120
- direction: string;
121
- /** Token decimals (for sell only) */
122
- decimals?: number;
123
- /** Slippage in basis points */
124
- slippage?: number;
125
- }
126
-
127
- /**
128
- * Migrate launch command options
129
- */
130
- export interface MigrateLaunchOptions extends GlobalOptions {
131
- /** Token address */
132
- tokenAddress: string;
133
- /** Export unsigned transaction */
134
- exportTx?: boolean;
135
- }
136
-
137
- /**
138
- * Migrate create locker command options
139
- */
140
- export interface MigrateCreateLockerOptions extends GlobalOptions {
141
- /** Token address */
142
- tokenAddress: string;
143
- /** Export unsigned transaction */
144
- exportTx?: boolean;
145
- }
146
-
147
- /**
148
- * Migrate check command options
149
- */
150
- export interface MigrateCheckOptions extends GlobalOptions {
151
- /** Token address */
152
- tokenAddress: string;
153
- }
154
-
155
17
  /**
156
18
  * Wallet balance command options
157
19
  */
@@ -8,7 +8,7 @@ import {
8
8
  Keypair,
9
9
  Connection,
10
10
  } from "@solana/web3.js";
11
- import { NaraSDK } from "../../client";
11
+ import { NaraSDK } from "nara-sdk";
12
12
  import { printInfo, printSuccess } from "./output";
13
13
 
14
14
  /**