naracli 1.0.69 → 1.0.71

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "naracli",
3
- "version": "1.0.69",
3
+ "version": "1.0.71",
4
4
  "description": "CLI for the Nara chain (Solana-compatible)",
5
5
  "homepage": "https://nara.build",
6
6
  "repository": {
@@ -63,7 +63,7 @@
63
63
  "bs58": "^6.0.0",
64
64
  "commander": "^12.1.0",
65
65
  "ed25519-hd-key": "^1.3.0",
66
- "nara-sdk": "^1.0.65",
66
+ "nara-sdk": "^1.0.67",
67
67
  "picocolors": "^1.1.1"
68
68
  },
69
69
  "packageManager": "pnpm@10.27.0+sha512.72d699da16b1179c14ba9e64dc71c9a40988cbdc65c264cb0e489db7de917f20dcf4d64d8723625f2969ba52d4b7e2a1170682d9ac2a5dcaeaab732b7e16f04a"
@@ -58,7 +58,7 @@ async function resolveAgentId(options: GlobalOptions & { agentId?: string }): Pr
58
58
  const pubkey = await tryGetWalletPubkey(options.wallet);
59
59
  const networkConfig = loadNetworkConfig(rpcUrl, pubkey);
60
60
  if (!networkConfig.agent_id) {
61
- printError('No agent ID specified. Use --agent-id or run "agent register <id>" first.');
61
+ printError('No agent ID registered for this wallet. Run "agent register <id>" to create one, or use --agent-id to query another agent.');
62
62
  process.exit(1);
63
63
  }
64
64
  return networkConfig.agent_id;
@@ -37,7 +37,7 @@ import type {
37
37
  WalletBalanceOptions,
38
38
  TokenBalanceOptions,
39
39
  TxStatusOptions,
40
- TransferSolOptions,
40
+ TransferNaraOptions,
41
41
  TransferTokenOptions,
42
42
  } from "../types";
43
43
 
@@ -124,19 +124,19 @@ export async function handleWalletBalance(
124
124
 
125
125
  // Get balance
126
126
  const balance = await connection.getBalance(pubkey);
127
- const balanceSOL = balance / LAMPORTS_PER_SOL;
127
+ const balanceNara = balance / LAMPORTS_PER_SOL;
128
128
 
129
129
  // Output result
130
130
  if (options.json) {
131
131
  const output = {
132
132
  address: pubkey.toBase58(),
133
- balance: balanceSOL,
133
+ balance: balanceNara,
134
134
  lamports: balance,
135
135
  };
136
136
  console.log(JSON.stringify(output, null, 2));
137
137
  } else {
138
138
  console.log(`\nWallet: ${pubkey.toBase58()}`);
139
- console.log(`Balance: ${balanceSOL.toFixed(4)} NARA (${balance.toLocaleString()} lamports)`);
139
+ console.log(`Balance: ${balanceNara.toFixed(4)} NARA (${balance.toLocaleString()} lamports)`);
140
140
  }
141
141
  }
142
142
 
@@ -320,15 +320,15 @@ export async function handleTxStatus(
320
320
  }
321
321
 
322
322
  /**
323
- * Handle transfer SOL command
323
+ * Handle transfer NARA command
324
324
  * @param to Recipient address
325
- * @param amount Amount in SOL
325
+ * @param amount Amount in NARA
326
326
  * @param options Command options
327
327
  */
328
- export async function handleTransferSol(
328
+ export async function handleTransferNara(
329
329
  to: string,
330
330
  amount: string,
331
- options: Omit<TransferSolOptions, "to" | "amount">
331
+ options: Omit<TransferNaraOptions, "to" | "amount">
332
332
  ): Promise<void> {
333
333
  // Load wallet
334
334
  const wallet = await loadWallet(options.wallet);
@@ -339,11 +339,11 @@ export async function handleTransferSol(
339
339
 
340
340
  // Validate inputs
341
341
  const recipient = validatePublicKey(to);
342
- const amountSOL = validatePositiveNumber(amount, "amount");
343
- const lamports = Math.floor(amountSOL * LAMPORTS_PER_SOL);
342
+ const amountNara = validatePositiveNumber(amount, "amount");
343
+ const lamports = Math.floor(amountNara * LAMPORTS_PER_SOL);
344
344
 
345
345
  printInfo(`To: ${recipient.toBase58()}`);
346
- printInfo(`Amount: ${amountSOL} NARA`);
346
+ printInfo(`Amount: ${amountNara} NARA`);
347
347
 
348
348
  // Initialize SDK
349
349
  const sdk = new NaraSDK({
@@ -381,7 +381,7 @@ export async function handleTransferSol(
381
381
  const output = {
382
382
  from: wallet.publicKey.toBase58(),
383
383
  to: recipient.toBase58(),
384
- amount: amountSOL,
384
+ amount: amountNara,
385
385
  lamports,
386
386
  ...(txResult.signature && { signature: txResult.signature }),
387
387
  ...(txResult.base64 && { transaction: txResult.base64 }),
@@ -391,7 +391,7 @@ export async function handleTransferSol(
391
391
  console.log(`\nTransfer Details:`);
392
392
  console.log(` From: ${wallet.publicKey.toBase58()}`);
393
393
  console.log(` To: ${recipient.toBase58()}`);
394
- console.log(` Amount: ${amountSOL} NARA`);
394
+ console.log(` Amount: ${amountNara} NARA`);
395
395
  printTransactionResult(txResult, false);
396
396
  }
397
397
  }
package/src/cli/index.ts CHANGED
@@ -18,7 +18,7 @@ import {
18
18
  handleWalletBalance,
19
19
  handleTokenBalance,
20
20
  handleTxStatus,
21
- handleTransferSol,
21
+ handleTransferNara,
22
22
  handleTransferToken,
23
23
  } from "./commands/wallet";
24
24
  import { loadWallet, getRpcUrl } from "./utils/wallet";
@@ -29,7 +29,7 @@ import type {
29
29
  WalletBalanceOptions,
30
30
  TokenBalanceOptions,
31
31
  TxStatusOptions,
32
- TransferSolOptions,
32
+ TransferNaraOptions,
33
33
  TransferTokenOptions,
34
34
  } from "./types";
35
35
 
@@ -114,18 +114,72 @@ export function registerCommands(program: Command): void {
114
114
  // Top-level: airdrop
115
115
  program
116
116
  .command("airdrop")
117
- .description("Claim a free NARA airdrop (0.1 NARA, once per 24 hours per address/IP)")
118
- .action(async () => {
117
+ .description("Claim a free NARA airdrop by answering the current quest (once per 24h per address/IP)")
118
+ .argument("[answer]", "Answer to the current quest question")
119
+ .action(async (answer: string | undefined) => {
119
120
  const opts = program.opts() as GlobalOptions;
120
121
  try {
121
122
  const wallet = await loadWallet(opts.wallet);
122
- const address = wallet.publicKey.toBase58();
123
- if (!opts.json) printInfo(`Requesting airdrop for ${address}...`);
123
+ const rpcUrl = getRpcUrl(opts.rpcUrl);
124
+ const connection = new (await import("@solana/web3.js")).Connection(rpcUrl, "confirmed");
125
+ const { getQuestInfo, generateProof } = await import("nara-sdk");
126
+
127
+ // Fetch quest info
128
+ let quest;
129
+ try {
130
+ quest = await getQuestInfo(connection, wallet);
131
+ } catch (err: any) {
132
+ printError(`Failed to fetch quest info: ${err.message}`);
133
+ process.exit(1);
134
+ }
135
+
136
+ if (!quest.active) {
137
+ printError("No active quest at the moment. Try again later.");
138
+ process.exit(1);
139
+ }
140
+
141
+ // No answer provided — show question and prompt
142
+ if (!answer) {
143
+ console.log("");
144
+ console.log(` Question: ${quest.question}`);
145
+ console.log(` Time remaining: ${quest.timeRemaining}s`);
146
+ console.log("");
147
+ console.log(` Answer the question correctly to claim your free NARA airdrop:`);
148
+ console.log(` npx naracli airdrop "<your-answer>"`);
149
+ console.log("");
150
+ return;
151
+ }
152
+
153
+ if (quest.expired) {
154
+ printError("Quest has expired. Wait for the next round and try again.");
155
+ process.exit(1);
156
+ }
157
+
158
+ // Generate ZK proof
159
+ printInfo("Generating ZK proof...");
160
+ let proof;
161
+ try {
162
+ proof = await generateProof(answer, quest.answerHash, wallet.publicKey, quest.round);
163
+ } catch (err: any) {
164
+ if (err.message?.includes("Assert Failed")) {
165
+ printError("Wrong answer. Try again with the correct answer.");
166
+ } else {
167
+ printError(`ZK proof generation failed: ${err.message}`);
168
+ }
169
+ process.exit(1);
170
+ }
124
171
 
172
+ // Submit to relay airdrop endpoint
173
+ printInfo("Submitting airdrop claim...");
125
174
  const res = await fetch("https://quest-api.nara.build/airdrop", {
126
175
  method: "POST",
127
176
  headers: { "Content-Type": "application/json" },
128
- body: JSON.stringify({ wallet: address }),
177
+ body: JSON.stringify({
178
+ wallet: wallet.publicKey.toBase58(),
179
+ proofA: proof.hex.proofA,
180
+ proofB: proof.hex.proofB,
181
+ proofC: proof.hex.proofC,
182
+ }),
129
183
  });
130
184
  const data = await res.json() as any;
131
185
 
@@ -142,7 +196,7 @@ export function registerCommands(program: Command): void {
142
196
  if (opts.json) {
143
197
  console.log(JSON.stringify(data, null, 2));
144
198
  } else {
145
- printSuccess(`Airdrop received: ${data.amount} NARA`);
199
+ printSuccess(`Airdrop claimed!`);
146
200
  console.log(` Transaction: ${data.txHash}`);
147
201
  }
148
202
  } catch (error: any) {
@@ -186,9 +240,9 @@ export function registerCommands(program: Command): void {
186
240
  .description("Transfer NARA to another wallet")
187
241
  .option("-e, --export-tx", "Export unsigned transaction", false)
188
242
  .action(async (to: string, amount: string, options: { exportTx?: boolean }) => {
189
- const opts = program.opts() as TransferSolOptions;
243
+ const opts = program.opts() as TransferNaraOptions;
190
244
  try {
191
- await handleTransferSol(to, amount, { ...opts, ...options });
245
+ await handleTransferNara(to, amount, { ...opts, ...options });
192
246
  } catch (error: any) {
193
247
  printError(error.message);
194
248
  process.exit(1);
package/src/cli/types.ts CHANGED
@@ -41,12 +41,12 @@ export interface TxStatusOptions extends GlobalOptions {
41
41
  }
42
42
 
43
43
  /**
44
- * Transfer SOL command options
44
+ * Transfer NARA command options
45
45
  */
46
- export interface TransferSolOptions extends GlobalOptions {
46
+ export interface TransferNaraOptions extends GlobalOptions {
47
47
  /** Recipient address */
48
48
  to: string;
49
- /** Amount in SOL */
49
+ /** Amount in NARA */
50
50
  amount: number;
51
51
  /** Export unsigned transaction */
52
52
  exportTx?: boolean;