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
@@ -0,0 +1,153 @@
1
+ /**
2
+ * Tests for `zkid` CLI commands
3
+ *
4
+ * Run: npm test
5
+ */
6
+
7
+ import { describe, it } from "node:test";
8
+ import assert from "node:assert/strict";
9
+ import { runCli, hasWallet } from "./helpers.js";
10
+
11
+ // ─── Help output ──────────────────────────────────────────────────
12
+
13
+ describe("zkid --help", () => {
14
+ it("shows all subcommands", async () => {
15
+ const { stdout, exitCode } = await runCli(["zkid", "--help"]);
16
+ assert.equal(exitCode, 0);
17
+ for (const cmd of ["create", "info", "deposit", "scan", "withdraw", "id-commitment", "transfer"]) {
18
+ assert.ok(stdout.includes(cmd), `missing subcommand: ${cmd}`);
19
+ }
20
+ });
21
+
22
+ it("zkid deposit --help lists all valid denominations", async () => {
23
+ const { stdout, exitCode } = await runCli(["zkid", "deposit", "--help"]);
24
+ assert.equal(exitCode, 0);
25
+ for (const amt of ["1", "10", "100", "1000", "10000", "100000"]) {
26
+ assert.ok(stdout.includes(amt), `missing denomination: ${amt}`);
27
+ }
28
+ });
29
+
30
+ it("zkid withdraw --help shows --recipient option", async () => {
31
+ const { stdout, exitCode } = await runCli(["zkid", "withdraw", "--help"]);
32
+ assert.equal(exitCode, 0);
33
+ assert.ok(stdout.includes("--recipient"));
34
+ });
35
+
36
+ it("zkid transfer --help shows <new-id-commitment>", async () => {
37
+ const { stdout, exitCode } = await runCli(["zkid", "transfer", "--help"]);
38
+ assert.equal(exitCode, 0);
39
+ assert.ok(stdout.includes("<new-id-commitment>"));
40
+ });
41
+ });
42
+
43
+ // ─── deposit validation (no chain needed) ────────────────────────
44
+
45
+ describe("zkid deposit denomination validation", () => {
46
+ for (const bad of ["0", "2", "5", "50", "500", "9999", "200000"]) {
47
+ it(`rejects invalid amount "${bad}"`, async () => {
48
+ if (!hasWallet) return;
49
+ const { stderr, exitCode } = await runCli(["zkid", "deposit", "alice", bad]);
50
+ assert.equal(exitCode, 1);
51
+ assert.ok(stderr.includes("Valid denominations"), `stderr: ${stderr}`);
52
+ });
53
+ }
54
+
55
+ it("help text contains all valid denominations", async () => {
56
+ const { stdout } = await runCli(["zkid", "deposit", "--help"]);
57
+ for (const amt of ["1", "10", "100", "1000", "10000", "100000"]) {
58
+ assert.ok(stdout.includes(amt));
59
+ }
60
+ });
61
+ });
62
+
63
+ // ─── transfer validation (no chain needed) ───────────────────────
64
+
65
+ describe("zkid transfer commitment validation", () => {
66
+ it("rejects commitment shorter than 64 chars", async () => {
67
+ if (!hasWallet) return;
68
+ const { stderr, exitCode } = await runCli(["zkid", "transfer", "alice", "deadbeef"]);
69
+ assert.equal(exitCode, 1);
70
+ assert.ok(stderr.includes("Invalid id-commitment"), `stderr: ${stderr}`);
71
+ });
72
+
73
+ it("rejects commitment with non-hex characters", async () => {
74
+ if (!hasWallet) return;
75
+ const { stderr, exitCode } = await runCli(["zkid", "transfer", "alice", "z".repeat(64)]);
76
+ assert.equal(exitCode, 1);
77
+ assert.ok(stderr.includes("Invalid id-commitment"), `stderr: ${stderr}`);
78
+ });
79
+
80
+ it("rejects commitment that is 63 chars (one short)", async () => {
81
+ if (!hasWallet) return;
82
+ const { stderr, exitCode } = await runCli(["zkid", "transfer", "alice", "a".repeat(63)]);
83
+ assert.equal(exitCode, 1);
84
+ assert.ok(stderr.includes("Invalid id-commitment"), `stderr: ${stderr}`);
85
+ });
86
+ });
87
+
88
+ // ─── withdraw validation (no chain needed) ───────────────────────
89
+
90
+ describe("zkid withdraw validation", () => {
91
+ it("rejects --recipient that is not a valid public key", async () => {
92
+ if (!hasWallet) return;
93
+ const { stderr, exitCode } = await runCli(["zkid", "withdraw", "alice", "--recipient", "bad-key"]);
94
+ assert.equal(exitCode, 1);
95
+ assert.ok(stderr.includes("Invalid recipient address"), `stderr: ${stderr}`);
96
+ });
97
+ });
98
+
99
+ // ─── Read-only chain queries ──────────────────────────────────────
100
+
101
+ describe("zkid info (read-only)", () => {
102
+ it("--json returns { exists: false } for non-existent ZK ID", async () => {
103
+ const { stdout, exitCode } = await runCli(["zkid", "info", "--json", "definitely-does-not-exist-xyz999"]);
104
+ assert.equal(exitCode, 0);
105
+ const json = JSON.parse(stdout);
106
+ assert.equal(json.exists, false);
107
+ });
108
+
109
+ it("text output mentions 'does not exist' for non-existent ZK ID", async () => {
110
+ const { stdout, exitCode } = await runCli(["zkid", "info", "definitely-does-not-exist-xyz999"]);
111
+ assert.equal(exitCode, 0);
112
+ assert.ok(stdout.includes("does not exist"), `stdout: ${stdout}`);
113
+ });
114
+ });
115
+
116
+ // ─── id-commitment (requires wallet) ─────────────────────────────
117
+
118
+ describe("zkid id-commitment", () => {
119
+ it("outputs a 64-char hex commitment", async () => {
120
+ if (!hasWallet) return;
121
+ const { stdout, exitCode } = await runCli(["zkid", "id-commitment", "test-name"]);
122
+ assert.equal(exitCode, 0);
123
+ const match = stdout.match(/ID commitment:\s+([0-9a-f]{64})/);
124
+ assert.ok(match, `no commitment in output: ${stdout}`);
125
+ });
126
+
127
+ it("--json output contains idCommitment as 64-char hex", async () => {
128
+ if (!hasWallet) return;
129
+ const { stdout, exitCode } = await runCli(["zkid", "id-commitment", "--json", "test-name"]);
130
+ assert.equal(exitCode, 0);
131
+ const json = JSON.parse(stdout);
132
+ assert.ok("idCommitment" in json);
133
+ assert.match(json.idCommitment, /^[0-9a-f]{64}$/);
134
+ });
135
+
136
+ it("same wallet+name yields the same commitment (deterministic)", async () => {
137
+ if (!hasWallet) return;
138
+ const r1 = await runCli(["zkid", "id-commitment", "--json", "my-id"]);
139
+ const r2 = await runCli(["zkid", "id-commitment", "--json", "my-id"]);
140
+ assert.equal(r1.exitCode, 0);
141
+ assert.equal(r2.exitCode, 0);
142
+ assert.equal(JSON.parse(r1.stdout).idCommitment, JSON.parse(r2.stdout).idCommitment);
143
+ });
144
+
145
+ it("different names yield different commitments", async () => {
146
+ if (!hasWallet) return;
147
+ const r1 = await runCli(["zkid", "id-commitment", "--json", "name-aaa"]);
148
+ const r2 = await runCli(["zkid", "id-commitment", "--json", "name-bbb"]);
149
+ assert.equal(r1.exitCode, 0);
150
+ assert.equal(r2.exitCode, 0);
151
+ assert.notEqual(JSON.parse(r1.stdout).idCommitment, JSON.parse(r2.stdout).idCommitment);
152
+ });
153
+ });
@@ -3,7 +3,10 @@ declare module "snarkjs" {
3
3
  fullProve(
4
4
  input: Record<string, string>,
5
5
  wasmPath: string,
6
- zkeyPath: string
6
+ zkeyPath: string,
7
+ logger?: any,
8
+ wtnsCalc?: any,
9
+ options?: any
7
10
  ): Promise<{ proof: any; publicSignals: string[] }>;
8
11
  };
9
12
  }
@@ -1,534 +0,0 @@
1
- {
2
- "address": "EXPLAHaMHLK9p7w5jVqEVY671NkkCKSHTNhhyUrPAboZ",
3
- "metadata": {
4
- "name": "nara_quest",
5
- "version": "0.1.0",
6
- "spec": "0.1.0",
7
- "description": "Created with Anchor"
8
- },
9
- "instructions": [
10
- {
11
- "name": "create_question",
12
- "discriminator": [
13
- 222,
14
- 74,
15
- 49,
16
- 30,
17
- 160,
18
- 220,
19
- 179,
20
- 27
21
- ],
22
- "accounts": [
23
- {
24
- "name": "game_config",
25
- "writable": true,
26
- "pda": {
27
- "seeds": [
28
- {
29
- "kind": "const",
30
- "value": [
31
- 103,
32
- 97,
33
- 109,
34
- 101,
35
- 95,
36
- 99,
37
- 111,
38
- 110,
39
- 102,
40
- 105,
41
- 103
42
- ]
43
- }
44
- ]
45
- }
46
- },
47
- {
48
- "name": "pool",
49
- "writable": true,
50
- "pda": {
51
- "seeds": [
52
- {
53
- "kind": "const",
54
- "value": [
55
- 112,
56
- 111,
57
- 111,
58
- 108
59
- ]
60
- }
61
- ]
62
- }
63
- },
64
- {
65
- "name": "vault",
66
- "writable": true,
67
- "pda": {
68
- "seeds": [
69
- {
70
- "kind": "const",
71
- "value": [
72
- 118,
73
- 97,
74
- 117,
75
- 108,
76
- 116
77
- ]
78
- }
79
- ]
80
- }
81
- },
82
- {
83
- "name": "authority",
84
- "writable": true,
85
- "signer": true
86
- },
87
- {
88
- "name": "system_program",
89
- "address": "11111111111111111111111111111111"
90
- }
91
- ],
92
- "args": [
93
- {
94
- "name": "question",
95
- "type": "string"
96
- },
97
- {
98
- "name": "answer_hash",
99
- "type": {
100
- "array": [
101
- "u8",
102
- 32
103
- ]
104
- }
105
- },
106
- {
107
- "name": "deadline",
108
- "type": "i64"
109
- },
110
- {
111
- "name": "reward_amount",
112
- "type": "u64"
113
- }
114
- ]
115
- },
116
- {
117
- "name": "initialize",
118
- "discriminator": [
119
- 175,
120
- 175,
121
- 109,
122
- 31,
123
- 13,
124
- 152,
125
- 155,
126
- 237
127
- ],
128
- "accounts": [
129
- {
130
- "name": "game_config",
131
- "writable": true,
132
- "pda": {
133
- "seeds": [
134
- {
135
- "kind": "const",
136
- "value": [
137
- 103,
138
- 97,
139
- 109,
140
- 101,
141
- 95,
142
- 99,
143
- 111,
144
- 110,
145
- 102,
146
- 105,
147
- 103
148
- ]
149
- }
150
- ]
151
- }
152
- },
153
- {
154
- "name": "pool",
155
- "writable": true,
156
- "pda": {
157
- "seeds": [
158
- {
159
- "kind": "const",
160
- "value": [
161
- 112,
162
- 111,
163
- 111,
164
- 108
165
- ]
166
- }
167
- ]
168
- }
169
- },
170
- {
171
- "name": "authority",
172
- "writable": true,
173
- "signer": true
174
- },
175
- {
176
- "name": "system_program",
177
- "address": "11111111111111111111111111111111"
178
- }
179
- ],
180
- "args": []
181
- },
182
- {
183
- "name": "submit_answer",
184
- "discriminator": [
185
- 221,
186
- 73,
187
- 184,
188
- 157,
189
- 1,
190
- 150,
191
- 231,
192
- 48
193
- ],
194
- "accounts": [
195
- {
196
- "name": "pool",
197
- "writable": true,
198
- "pda": {
199
- "seeds": [
200
- {
201
- "kind": "const",
202
- "value": [
203
- 112,
204
- 111,
205
- 111,
206
- 108
207
- ]
208
- }
209
- ]
210
- }
211
- },
212
- {
213
- "name": "winner_record",
214
- "writable": true,
215
- "pda": {
216
- "seeds": [
217
- {
218
- "kind": "const",
219
- "value": [
220
- 119,
221
- 105,
222
- 110,
223
- 110,
224
- 101,
225
- 114
226
- ]
227
- },
228
- {
229
- "kind": "account",
230
- "path": "user"
231
- }
232
- ]
233
- }
234
- },
235
- {
236
- "name": "vault",
237
- "writable": true,
238
- "pda": {
239
- "seeds": [
240
- {
241
- "kind": "const",
242
- "value": [
243
- 118,
244
- 97,
245
- 117,
246
- 108,
247
- 116
248
- ]
249
- }
250
- ]
251
- }
252
- },
253
- {
254
- "name": "user",
255
- "writable": true
256
- },
257
- {
258
- "name": "payer",
259
- "writable": true,
260
- "signer": true
261
- },
262
- {
263
- "name": "system_program",
264
- "address": "11111111111111111111111111111111"
265
- }
266
- ],
267
- "args": [
268
- {
269
- "name": "proof_a",
270
- "type": {
271
- "array": [
272
- "u8",
273
- 64
274
- ]
275
- }
276
- },
277
- {
278
- "name": "proof_b",
279
- "type": {
280
- "array": [
281
- "u8",
282
- 128
283
- ]
284
- }
285
- },
286
- {
287
- "name": "proof_c",
288
- "type": {
289
- "array": [
290
- "u8",
291
- 64
292
- ]
293
- }
294
- }
295
- ]
296
- },
297
- {
298
- "name": "transfer_authority",
299
- "discriminator": [
300
- 48,
301
- 169,
302
- 76,
303
- 72,
304
- 229,
305
- 180,
306
- 55,
307
- 161
308
- ],
309
- "accounts": [
310
- {
311
- "name": "game_config",
312
- "writable": true,
313
- "pda": {
314
- "seeds": [
315
- {
316
- "kind": "const",
317
- "value": [
318
- 103,
319
- 97,
320
- 109,
321
- 101,
322
- 95,
323
- 99,
324
- 111,
325
- 110,
326
- 102,
327
- 105,
328
- 103
329
- ]
330
- }
331
- ]
332
- }
333
- },
334
- {
335
- "name": "authority",
336
- "signer": true
337
- }
338
- ],
339
- "args": [
340
- {
341
- "name": "new_authority",
342
- "type": "pubkey"
343
- }
344
- ]
345
- }
346
- ],
347
- "accounts": [
348
- {
349
- "name": "GameConfig",
350
- "discriminator": [
351
- 45,
352
- 146,
353
- 146,
354
- 33,
355
- 170,
356
- 69,
357
- 96,
358
- 133
359
- ]
360
- },
361
- {
362
- "name": "Pool",
363
- "discriminator": [
364
- 241,
365
- 154,
366
- 109,
367
- 4,
368
- 17,
369
- 177,
370
- 109,
371
- 188
372
- ]
373
- },
374
- {
375
- "name": "WinnerRecord",
376
- "discriminator": [
377
- 248,
378
- 27,
379
- 49,
380
- 33,
381
- 45,
382
- 88,
383
- 210,
384
- 100
385
- ]
386
- }
387
- ],
388
- "errors": [
389
- {
390
- "code": 6000,
391
- "name": "Unauthorized",
392
- "msg": "Only the authority can perform this action"
393
- },
394
- {
395
- "code": 6001,
396
- "name": "PoolNotActive",
397
- "msg": "Pool has no active question"
398
- },
399
- {
400
- "code": 6002,
401
- "name": "DeadlineExpired",
402
- "msg": "The deadline for this question has passed"
403
- },
404
- {
405
- "code": 6003,
406
- "name": "InvalidProof",
407
- "msg": "ZK proof verification failed"
408
- },
409
- {
410
- "code": 6004,
411
- "name": "InvalidDeadline",
412
- "msg": "Deadline must be in the future"
413
- },
414
- {
415
- "code": 6005,
416
- "name": "InsufficientReward",
417
- "msg": "Reward amount must be greater than zero"
418
- },
419
- {
420
- "code": 6006,
421
- "name": "InsufficientPoolBalance",
422
- "msg": "Pool balance insufficient for reward transfer"
423
- },
424
- {
425
- "code": 6007,
426
- "name": "QuestionTooLong",
427
- "msg": "Question exceeds maximum length"
428
- },
429
- {
430
- "code": 6008,
431
- "name": "AlreadyAnswered",
432
- "msg": "Already answered this round"
433
- }
434
- ],
435
- "types": [
436
- {
437
- "name": "GameConfig",
438
- "type": {
439
- "kind": "struct",
440
- "fields": [
441
- {
442
- "name": "authority",
443
- "type": "pubkey"
444
- },
445
- {
446
- "name": "next_question_id",
447
- "type": "u64"
448
- },
449
- {
450
- "name": "bump",
451
- "type": "u8"
452
- }
453
- ]
454
- }
455
- },
456
- {
457
- "name": "Pool",
458
- "type": {
459
- "kind": "struct",
460
- "fields": [
461
- {
462
- "name": "round",
463
- "type": "u64"
464
- },
465
- {
466
- "name": "question_id",
467
- "type": "u64"
468
- },
469
- {
470
- "name": "question",
471
- "type": "string"
472
- },
473
- {
474
- "name": "answer_hash",
475
- "type": {
476
- "array": [
477
- "u8",
478
- 32
479
- ]
480
- }
481
- },
482
- {
483
- "name": "deadline",
484
- "type": "i64"
485
- },
486
- {
487
- "name": "reward_amount",
488
- "type": "u64"
489
- },
490
- {
491
- "name": "reward_count",
492
- "type": "u32"
493
- },
494
- {
495
- "name": "reward_per_winner",
496
- "type": "u64"
497
- },
498
- {
499
- "name": "winner_count",
500
- "type": "u32"
501
- },
502
- {
503
- "name": "is_active",
504
- "type": "bool"
505
- },
506
- {
507
- "name": "bump",
508
- "type": "u8"
509
- }
510
- ]
511
- }
512
- },
513
- {
514
- "name": "WinnerRecord",
515
- "type": {
516
- "kind": "struct",
517
- "fields": [
518
- {
519
- "name": "bump",
520
- "type": "u8"
521
- },
522
- {
523
- "name": "round",
524
- "type": "u64"
525
- },
526
- {
527
- "name": "rewarded",
528
- "type": "bool"
529
- }
530
- ]
531
- }
532
- }
533
- ]
534
- }
Binary file
Binary file