quantumcoin 7.0.8 → 7.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README-SDK.md CHANGED
@@ -392,6 +392,7 @@ User-facing wallet class.
392
392
  - `Wallet.fromEncryptedJsonSync(json: string, password: string, provider?: AbstractProvider): Wallet`
393
393
  - `Wallet.fromPhrase(phrase: string | string[], provider?: AbstractProvider): Wallet`
394
394
  - `Wallet.fromKeys(privateKey: Uint8Array | string, publicKey: Uint8Array | string, provider?: AbstractProvider): Wallet`
395
+ - `Wallet.encryptSeedSync(seed: number[] | Uint8Array, password: string | Uint8Array): string` — encrypts raw seed bytes (64/72/96) into a wallet JSON string (version 5 pre-expansion format). The resulting JSON can be opened with `fromEncryptedJsonSync()` or Desktop/Mobile/Web/CLI wallet applications. Password must be at least 12 characters.
395
396
 
396
397
  **Instance methods**
397
398
  - `getAddress(): string`
@@ -399,6 +400,7 @@ User-facing wallet class.
399
400
  - `getTransactionCount(blockTag?: string): Promise<number>`
400
401
  - `encryptSync(password: string | Uint8Array): string`
401
402
  - `connect(provider: AbstractProvider): Wallet`
403
+ - `getSigningContext(fullSign?: boolean | null): number` — returns the recommended signing context for this wallet (based on public key type). Setting `fullSign` to `true` may incur additional gas cost.
402
404
 
403
405
  **Example(s):**
404
406
  - `examples/wallet-offline.js`
package/README.md CHANGED
@@ -58,6 +58,23 @@ const restored = Wallet.fromEncryptedJsonSync(encrypted, "mySecurePassword123");
58
58
  console.log(restored.address);
59
59
  ```
60
60
 
61
+ ### Encrypt a raw seed
62
+
63
+ You can encrypt raw seed bytes (pre-expansion) into a portable wallet JSON (version 5 format) without first opening the wallet:
64
+
65
+ ```js
66
+ const { Wallet } = require("quantumcoin");
67
+ const { Initialize } = require("quantumcoin/config");
68
+
69
+ await Initialize(null);
70
+
71
+ // 64-byte seed (keyType 3), 72-byte (keyType 5), or 96-byte (legacy)
72
+ const seed = [51,214,149,165, /* ...remaining bytes... */];
73
+ const json = Wallet.encryptSeedSync(seed, "mySecurePassword123");
74
+ const restored = Wallet.fromEncryptedJsonSync(json, "mySecurePassword123");
75
+ console.log(restored.address);
76
+ ```
77
+
61
78
  ## Contracts (read-only)
62
79
 
63
80
  ```js
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "name": "quantumcoinjs-sdk-examples",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "quantumcoinjs-sdk-examples",
9
- "version": "1.0.0",
9
+ "version": "1.0.1",
10
10
  "license": "MIT",
11
11
  "dependencies": {
12
- "quantum-coin-js-sdk": "1.0.32",
12
+ "quantum-coin-js-sdk": "1.0.33",
13
13
  "quantumcoin": "file:.."
14
14
  },
15
15
  "devDependencies": {
@@ -18,10 +18,10 @@
18
18
  },
19
19
  "..": {
20
20
  "name": "quantumcoin",
21
- "version": "7.0.8",
21
+ "version": "7.0.10",
22
22
  "license": "MIT",
23
23
  "dependencies": {
24
- "quantum-coin-js-sdk": "1.0.32",
24
+ "quantum-coin-js-sdk": "1.0.33",
25
25
  "seed-words": "^1.0.2"
26
26
  },
27
27
  "bin": {
@@ -201,7 +201,9 @@
201
201
  }
202
202
  },
203
203
  "node_modules/quantum-coin-js-sdk": {
204
- "version": "1.0.32",
204
+ "version": "1.0.33",
205
+ "resolved": "https://registry.npmjs.org/quantum-coin-js-sdk/-/quantum-coin-js-sdk-1.0.33.tgz",
206
+ "integrity": "sha512-n4Q/PBj6yQ2mj3MpvNdLlBSoSxM9+q+yTDz/l/zuWxeob/unj1ZQgzir1Qh4U/Vu7eAbZmAhRORFP9ttfw3ToA==",
205
207
  "license": "MIT",
206
208
  "dependencies": {
207
209
  "seed-words": "1.0.2"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "quantumcoinjs-sdk-examples",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "QuantumCoin.js SDK Examples",
5
5
  "main": "example.js",
6
6
  "scripts": {
@@ -26,7 +26,7 @@
26
26
  "tsx": "^4.19.0"
27
27
  },
28
28
  "dependencies": {
29
- "quantum-coin-js-sdk": "1.0.32",
29
+ "quantum-coin-js-sdk": "1.0.33",
30
30
  "quantumcoin": "file:.."
31
31
  }
32
32
  }
@@ -26,6 +26,15 @@ async function walletOffline() {
26
26
  const json = wallet.encryptSync("mySecurePassword123");
27
27
  console.log("Encrypted wallet JSON length:", json.length);
28
28
  logExample("wallet-offline.js", "encryptSync", { jsonLength: json.length });
29
+
30
+ // Encrypt a raw seed (pre-expansion format) and restore it
31
+ const seed = [51,214,149,165,206,96,227,5,173,247,83,219,210,2,221,2,4,48,117,55,88,109,241,204,31,62,23,128,47,21,168,247,28,118,30,185,229,255,17,27,34,107,225,138,254,156,55,9,253,255,142,148,234,189,232,43,173,84,159,108,8,35,58,77];
32
+ const seedJson = Wallet.encryptSeedSync(seed, "mySecurePassword123");
33
+ console.log("Seed-encrypted wallet JSON length:", seedJson.length);
34
+ const restored = Wallet.fromEncryptedJsonSync(seedJson, "mySecurePassword123");
35
+ console.log("Restored from seed address:", restored.address);
36
+ logExample("wallet-offline.js", "encryptSeedSync", { jsonLength: seedJson.length });
37
+ logAddress("restored", restored.address);
29
38
  }
30
39
 
31
40
  walletOffline().catch((e) => {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "quantumcoin",
3
- "version": "7.0.8",
4
- "description": "QuantumCoin SDK - a complete SDK for dapps",
3
+ "version": "7.0.10",
4
+ "description": "QuantumCoin.js - a post quantum cryptography SDK for QuantumCoin",
5
5
  "main": "index.js",
6
6
  "types": "src/index.d.ts",
7
7
  "typesVersions": {
@@ -90,6 +90,6 @@
90
90
  },
91
91
  "dependencies": {
92
92
  "seed-words": "^1.0.2",
93
- "quantum-coin-js-sdk": "1.0.32"
93
+ "quantum-coin-js-sdk": "1.0.33"
94
94
  }
95
95
  }
@@ -63,6 +63,13 @@ export class BaseWallet extends AbstractSigner {
63
63
  * Wallet - convenience methods around BaseWallet.
64
64
  */
65
65
  export class Wallet extends BaseWallet {
66
+ /**
67
+ * Returns the recommended signing context for this wallet.
68
+ * Setting fullSign to true may incur additional gas cost.
69
+ * @param {boolean|null=} fullSign Defaults to false when null or omitted.
70
+ * @returns {number}
71
+ */
72
+ getSigningContext(fullSign?: boolean | null): number;
66
73
  /**
67
74
  * Creates a new random wallet.
68
75
  * @param {import("../providers/provider").AbstractProvider=} provider
@@ -141,6 +148,15 @@ export class Wallet extends BaseWallet {
141
148
  * @returns {string}
142
149
  */
143
150
  encryptSync(password: string | Uint8Array): string;
151
+ /**
152
+ * Encrypts raw seed bytes into a wallet JSON string (version 5 pre-expansion format).
153
+ * The resulting JSON can be opened with `Wallet.fromEncryptedJsonSync()` or
154
+ * Desktop/Mobile/Web/CLI wallet applications.
155
+ * @param {number[]|Uint8Array} seed Raw seed bytes: 64 (keyType 3), 72 (keyType 5), or 96 (legacy)
156
+ * @param {string|Uint8Array} password Passphrase (at least 12 characters)
157
+ * @returns {string}
158
+ */
159
+ static encryptSeedSync(seed: number[] | Uint8Array, password: string | Uint8Array): string;
144
160
  /**
145
161
  * Returns a new wallet connected to a provider.
146
162
  * @param {import("../providers/provider").AbstractProvider} provider
@@ -311,6 +311,44 @@ class Wallet extends BaseWallet {
311
311
  return json;
312
312
  }
313
313
 
314
+ /**
315
+ * Encrypts raw seed bytes into a wallet JSON string (version 5 pre-expansion format).
316
+ * The resulting JSON can be opened with `Wallet.fromEncryptedJsonSync()` or
317
+ * Desktop/Mobile/Web/CLI wallet applications.
318
+ * @param {number[]|Uint8Array} seed Raw seed bytes: 64 (keyType 3), 72 (keyType 5), or 96 (legacy)
319
+ * @param {string|Uint8Array} password Passphrase (at least 12 characters)
320
+ * @returns {string}
321
+ */
322
+ static encryptSeedSync(seed, password) {
323
+ _requireInitialized();
324
+ const seedArr = seed instanceof Uint8Array ? Array.from(seed) : seed;
325
+ assertArgument(Array.isArray(seedArr), "seed must be an array of numbers or Uint8Array", "seed", seed);
326
+ const allowedLengths = [64, 72, 96];
327
+ assertArgument(allowedLengths.includes(seedArr.length), "seed must be 64, 72, or 96 bytes", "seed", seedArr.length);
328
+ const pw = typeof password === "string" ? password : Buffer.from(arrayify(password)).toString("utf8");
329
+ const json = qcsdk.serializeSeedAsEncryptedWallet(seedArr, pw);
330
+ if (typeof json !== "string") throw makeError("serializeSeedAsEncryptedWallet failed", "UNKNOWN_ERROR", {});
331
+ return json;
332
+ }
333
+
334
+ /**
335
+ * Returns the recommended signing context for this wallet.
336
+ * Setting fullSign to true may incur additional gas cost.
337
+ * @param {boolean|null=} fullSign Defaults to false when null or omitted.
338
+ * @returns {number}
339
+ */
340
+ getSigningContext(fullSign) {
341
+ const fs = fullSign ?? false;
342
+ const pubLen = this.signingKey.publicKeyBytes.length;
343
+ if (pubLen === 1408) {
344
+ return fs ? 2 : 0;
345
+ }
346
+ if (pubLen === 2688) {
347
+ return 1;
348
+ }
349
+ throw makeError("unsupported public key size", "UNSUPPORTED_OPERATION", { publicKeyLength: pubLen });
350
+ }
351
+
314
352
  /**
315
353
  * Returns a new wallet connected to a provider.
316
354
  * @param {import("../providers/provider").AbstractProvider} provider
@@ -92,11 +92,11 @@ describe("SigningContext and fee E2E", () => {
92
92
 
93
93
  // --- Phase 2: Send back with signingContext (36: null, 1; 32: null, 0, 2) ---
94
94
  const cases = [
95
- { wallet: wallet36, signingContext: null, label: "36_null" },
96
- { wallet: wallet36, signingContext: 1, label: "36_1" },
97
- { wallet: wallet32, signingContext: null, label: "32_null" },
98
- { wallet: wallet32, signingContext: 0, label: "32_0" },
99
- { wallet: wallet32, signingContext: 2, label: "32_2" },
95
+ { wallet: wallet36, signingContext: wallet36.getSigningContext(), label: "36_null" },
96
+ { wallet: wallet36, signingContext: wallet36.getSigningContext(true), label: "36_1" },
97
+ { wallet: wallet32, signingContext: wallet32.getSigningContext(), label: "32_null" },
98
+ { wallet: wallet32, signingContext: wallet32.getSigningContext(), label: "32_0" },
99
+ { wallet: wallet32, signingContext: wallet32.getSigningContext(true), label: "32_2" },
100
100
  ];
101
101
 
102
102
  const expectedFees = {
@@ -83,11 +83,11 @@ describe("SigningContext and fee E2E", () => {
83
83
  const sendBackValue = SEND_AMOUNT - qc.parseEther("10000");
84
84
 
85
85
  const cases = [
86
- { wallet: wallet36, signingContext: null as number | null, label: "36_null" },
87
- { wallet: wallet36, signingContext: 1, label: "36_1" },
88
- { wallet: wallet32, signingContext: null as number | null, label: "32_null" },
89
- { wallet: wallet32, signingContext: 0, label: "32_0" },
90
- { wallet: wallet32, signingContext: 2, label: "32_2" },
86
+ { wallet: wallet36, signingContext: wallet36.getSigningContext(), label: "36_null" },
87
+ { wallet: wallet36, signingContext: wallet36.getSigningContext(true), label: "36_1" },
88
+ { wallet: wallet32, signingContext: wallet32.getSigningContext(), label: "32_null" },
89
+ { wallet: wallet32, signingContext: wallet32.getSigningContext(), label: "32_0" },
90
+ { wallet: wallet32, signingContext: wallet32.getSigningContext(true), label: "32_2" },
91
91
  ];
92
92
 
93
93
  const expectedFees: Record<string, bigint> = {
@@ -560,5 +560,133 @@ describe("Address + Wallet (offline)", () => {
560
560
  assert.equal(w.address, addr5);
561
561
  assert.equal(qc.isAddress(w.address), true);
562
562
  });
563
+
564
+ // ---------------------------------------------------------------------------
565
+ // encryptSeedSync
566
+ // ---------------------------------------------------------------------------
567
+
568
+ it("encryptSeedSync: 32-word seed (64 bytes) roundtrip preserves address, privateKey, publicKey", async () => {
569
+ await Initialize(null);
570
+ const seedwords = require("seed-words");
571
+ const seedArr = seedwords.getSeedArrayFromWordList(TEST_SEED_WORDS_32);
572
+ assert.equal(seedArr.length, 64);
573
+ const ref = qc.Wallet.fromPhrase(TEST_SEED_WORDS_32);
574
+
575
+ const json = qc.Wallet.encryptSeedSync(Array.from(seedArr), PASSPHRASE_PHRASE);
576
+ assert.equal(typeof json, "string");
577
+ assert.ok(json.includes("address"));
578
+
579
+ const restored = qc.Wallet.fromEncryptedJsonSync(json, PASSPHRASE_PHRASE);
580
+ assert.equal(restored.address, ref.address);
581
+ assert.equal(restored.address, TEST_SEED_ADDRESS_32);
582
+ assert.equal(restored.privateKey, ref.privateKey);
583
+ assert.deepEqual(restored.signingKey.publicKeyBytes, ref.signingKey.publicKeyBytes);
584
+ });
585
+
586
+ it("encryptSeedSync: 36-word seed (72 bytes) roundtrip preserves address, privateKey, publicKey", async () => {
587
+ await Initialize(null);
588
+ const seedwords = require("seed-words");
589
+ const seedArr = seedwords.getSeedArrayFromWordList(TEST_SEED_WORDS_36);
590
+ assert.equal(seedArr.length, 72);
591
+ const ref = qc.Wallet.fromPhrase(TEST_SEED_WORDS_36);
592
+
593
+ const json = qc.Wallet.encryptSeedSync(Array.from(seedArr), PASSPHRASE_PHRASE);
594
+ assert.equal(typeof json, "string");
595
+ assert.ok(json.includes("address"));
596
+
597
+ const restored = qc.Wallet.fromEncryptedJsonSync(json, PASSPHRASE_PHRASE);
598
+ assert.equal(restored.address, ref.address);
599
+ assert.equal(restored.address, TEST_SEED_ADDRESS_36);
600
+ assert.equal(restored.privateKey, ref.privateKey);
601
+ assert.deepEqual(restored.signingKey.publicKeyBytes, ref.signingKey.publicKeyBytes);
602
+ });
603
+
604
+ it("encryptSeedSync: 48-word seed (96 bytes) roundtrip preserves address, privateKey, publicKey", async () => {
605
+ await Initialize(null);
606
+ const seedwords = require("seed-words");
607
+ const seedArr = seedwords.getSeedArrayFromWordList(TEST_SEED_WORDS);
608
+ assert.equal(seedArr.length, 96);
609
+ const ref = qc.Wallet.fromPhrase(TEST_SEED_WORDS);
610
+
611
+ const json = qc.Wallet.encryptSeedSync(Array.from(seedArr), PASSPHRASE_PHRASE);
612
+ assert.equal(typeof json, "string");
613
+ assert.ok(json.includes("address"));
614
+
615
+ const restored = qc.Wallet.fromEncryptedJsonSync(json, PASSPHRASE_PHRASE);
616
+ assert.equal(restored.address, ref.address);
617
+ assert.equal(restored.address, TEST_SEED_ADDRESS);
618
+ assert.equal(restored.privateKey, ref.privateKey);
619
+ assert.deepEqual(restored.signingKey.publicKeyBytes, ref.signingKey.publicKeyBytes);
620
+ });
621
+
622
+ it("encryptSeedSync accepts Uint8Array seed", async () => {
623
+ await Initialize(null);
624
+ const seedwords = require("seed-words");
625
+ const seedArr = seedwords.getSeedArrayFromWordList(TEST_SEED_WORDS_32);
626
+ const ref = qc.Wallet.fromPhrase(TEST_SEED_WORDS_32);
627
+
628
+ const json = qc.Wallet.encryptSeedSync(new Uint8Array(seedArr), PASSPHRASE_PHRASE);
629
+ const restored = qc.Wallet.fromEncryptedJsonSync(json, PASSPHRASE_PHRASE);
630
+ assert.equal(restored.address, ref.address);
631
+ });
632
+
633
+ it("encryptSeedSync rejects non-array seed input", async () => {
634
+ await Initialize(null);
635
+ assert.throws(() => qc.Wallet.encryptSeedSync("not an array", PASSPHRASE_PHRASE), /seed must be an array/);
636
+ assert.throws(() => qc.Wallet.encryptSeedSync(12345, PASSPHRASE_PHRASE), /seed must be an array/);
637
+ assert.throws(() => qc.Wallet.encryptSeedSync(null, PASSPHRASE_PHRASE), /seed must be an array/);
638
+ });
639
+
640
+ it("encryptSeedSync rejects wrong-length seed arrays", async () => {
641
+ await Initialize(null);
642
+ assert.throws(() => qc.Wallet.encryptSeedSync(new Array(32).fill(0), PASSPHRASE_PHRASE), /seed must be 64, 72, or 96 bytes/);
643
+ assert.throws(() => qc.Wallet.encryptSeedSync(new Array(48).fill(0), PASSPHRASE_PHRASE), /seed must be 64, 72, or 96 bytes/);
644
+ assert.throws(() => qc.Wallet.encryptSeedSync(new Array(100).fill(0), PASSPHRASE_PHRASE), /seed must be 64, 72, or 96 bytes/);
645
+ assert.throws(() => qc.Wallet.encryptSeedSync([], PASSPHRASE_PHRASE), /seed must be 64, 72, or 96 bytes/);
646
+ });
647
+
648
+ it("encryptSeedSync rejects password shorter than 12 characters", async () => {
649
+ await Initialize(null);
650
+ const seed = new Array(64).fill(1);
651
+ assert.throws(() => qc.Wallet.encryptSeedSync(seed, "short"), /serializeSeedAsEncryptedWallet failed/);
652
+ });
653
+
654
+ // ---------------------------------------------------------------------------
655
+ // getSigningContext
656
+ // ---------------------------------------------------------------------------
657
+
658
+ it("getSigningContext: 32-word wallet (pubKey 1408) returns 0 by default, 2 with fullSign", async () => {
659
+ await Initialize(null);
660
+ const w = qc.Wallet.fromPhrase(TEST_SEED_WORDS_32);
661
+ assert.strictEqual(w.getSigningContext(), 0);
662
+ assert.strictEqual(w.getSigningContext(null), 0);
663
+ assert.strictEqual(w.getSigningContext(false), 0);
664
+ assert.strictEqual(w.getSigningContext(true), 2);
665
+ });
666
+
667
+ it("getSigningContext: 48-word wallet (pubKey 1408) returns 0 by default, 2 with fullSign", async () => {
668
+ await Initialize(null);
669
+ const w = qc.Wallet.fromPhrase(TEST_SEED_WORDS);
670
+ assert.strictEqual(w.getSigningContext(), 0);
671
+ assert.strictEqual(w.getSigningContext(null), 0);
672
+ assert.strictEqual(w.getSigningContext(false), 0);
673
+ assert.strictEqual(w.getSigningContext(true), 2);
674
+ });
675
+
676
+ it("getSigningContext: 36-word wallet (pubKey 2688) returns 1 for all fullSign values", async () => {
677
+ await Initialize(null);
678
+ const w = qc.Wallet.fromPhrase(TEST_SEED_WORDS_36);
679
+ assert.strictEqual(w.getSigningContext(), 1);
680
+ assert.strictEqual(w.getSigningContext(null), 1);
681
+ assert.strictEqual(w.getSigningContext(false), 1);
682
+ assert.strictEqual(w.getSigningContext(true), 1);
683
+ });
684
+
685
+ it("getSigningContext: throws for unsupported public key size", async () => {
686
+ await Initialize(null);
687
+ const w = qc.Wallet.fromPhrase(TEST_SEED_WORDS_32);
688
+ w.signingKey.publicKeyBytes = new Uint8Array(100);
689
+ assert.throws(() => w.getSigningContext(), /unsupported public key size/);
690
+ });
563
691
  });
564
692
 
@@ -546,4 +546,132 @@ describe("Address + Wallet (offline)", () => {
546
546
  assert.equal(w.address, addr5);
547
547
  assert.equal(qc.isAddress(w.address), true);
548
548
  });
549
+
550
+ // ---------------------------------------------------------------------------
551
+ // encryptSeedSync
552
+ // ---------------------------------------------------------------------------
553
+
554
+ it("encryptSeedSync: 32-word seed (64 bytes) roundtrip preserves address, privateKey, publicKey", async () => {
555
+ await Initialize(null);
556
+ const seedwords = require("seed-words");
557
+ const seedArr = seedwords.getSeedArrayFromWordList(TEST_SEED_WORDS_32);
558
+ assert.equal(seedArr.length, 64);
559
+ const ref = qc.Wallet.fromPhrase(TEST_SEED_WORDS_32);
560
+
561
+ const json = qc.Wallet.encryptSeedSync(Array.from(seedArr), PASSPHRASE_PHRASE);
562
+ assert.equal(typeof json, "string");
563
+ assert.ok(json.includes("address"));
564
+
565
+ const restored = qc.Wallet.fromEncryptedJsonSync(json, PASSPHRASE_PHRASE);
566
+ assert.equal(restored.address, ref.address);
567
+ assert.equal(restored.address, TEST_SEED_ADDRESS_32);
568
+ assert.equal(restored.privateKey, ref.privateKey);
569
+ assert.deepEqual(restored.signingKey.publicKeyBytes, ref.signingKey.publicKeyBytes);
570
+ });
571
+
572
+ it("encryptSeedSync: 36-word seed (72 bytes) roundtrip preserves address, privateKey, publicKey", async () => {
573
+ await Initialize(null);
574
+ const seedwords = require("seed-words");
575
+ const seedArr = seedwords.getSeedArrayFromWordList(TEST_SEED_WORDS_36);
576
+ assert.equal(seedArr.length, 72);
577
+ const ref = qc.Wallet.fromPhrase(TEST_SEED_WORDS_36);
578
+
579
+ const json = qc.Wallet.encryptSeedSync(Array.from(seedArr), PASSPHRASE_PHRASE);
580
+ assert.equal(typeof json, "string");
581
+ assert.ok(json.includes("address"));
582
+
583
+ const restored = qc.Wallet.fromEncryptedJsonSync(json, PASSPHRASE_PHRASE);
584
+ assert.equal(restored.address, ref.address);
585
+ assert.equal(restored.address, TEST_SEED_ADDRESS_36);
586
+ assert.equal(restored.privateKey, ref.privateKey);
587
+ assert.deepEqual(restored.signingKey.publicKeyBytes, ref.signingKey.publicKeyBytes);
588
+ });
589
+
590
+ it("encryptSeedSync: 48-word seed (96 bytes) roundtrip preserves address, privateKey, publicKey", async () => {
591
+ await Initialize(null);
592
+ const seedwords = require("seed-words");
593
+ const seedArr = seedwords.getSeedArrayFromWordList(TEST_SEED_WORDS);
594
+ assert.equal(seedArr.length, 96);
595
+ const ref = qc.Wallet.fromPhrase(TEST_SEED_WORDS);
596
+
597
+ const json = qc.Wallet.encryptSeedSync(Array.from(seedArr), PASSPHRASE_PHRASE);
598
+ assert.equal(typeof json, "string");
599
+ assert.ok(json.includes("address"));
600
+
601
+ const restored = qc.Wallet.fromEncryptedJsonSync(json, PASSPHRASE_PHRASE);
602
+ assert.equal(restored.address, ref.address);
603
+ assert.equal(restored.address, TEST_SEED_ADDRESS);
604
+ assert.equal(restored.privateKey, ref.privateKey);
605
+ assert.deepEqual(restored.signingKey.publicKeyBytes, ref.signingKey.publicKeyBytes);
606
+ });
607
+
608
+ it("encryptSeedSync accepts Uint8Array seed", async () => {
609
+ await Initialize(null);
610
+ const seedwords = require("seed-words");
611
+ const seedArr = seedwords.getSeedArrayFromWordList(TEST_SEED_WORDS_32);
612
+ const ref = qc.Wallet.fromPhrase(TEST_SEED_WORDS_32);
613
+
614
+ const json = qc.Wallet.encryptSeedSync(new Uint8Array(seedArr), PASSPHRASE_PHRASE);
615
+ const restored = qc.Wallet.fromEncryptedJsonSync(json, PASSPHRASE_PHRASE);
616
+ assert.equal(restored.address, ref.address);
617
+ });
618
+
619
+ it("encryptSeedSync rejects non-array seed input", async () => {
620
+ await Initialize(null);
621
+ assert.throws(() => qc.Wallet.encryptSeedSync("not an array" as any, PASSPHRASE_PHRASE), /seed must be an array/);
622
+ assert.throws(() => qc.Wallet.encryptSeedSync(12345 as any, PASSPHRASE_PHRASE), /seed must be an array/);
623
+ assert.throws(() => qc.Wallet.encryptSeedSync(null as any, PASSPHRASE_PHRASE), /seed must be an array/);
624
+ });
625
+
626
+ it("encryptSeedSync rejects wrong-length seed arrays", async () => {
627
+ await Initialize(null);
628
+ assert.throws(() => qc.Wallet.encryptSeedSync(new Array(32).fill(0), PASSPHRASE_PHRASE), /seed must be 64, 72, or 96 bytes/);
629
+ assert.throws(() => qc.Wallet.encryptSeedSync(new Array(48).fill(0), PASSPHRASE_PHRASE), /seed must be 64, 72, or 96 bytes/);
630
+ assert.throws(() => qc.Wallet.encryptSeedSync(new Array(100).fill(0), PASSPHRASE_PHRASE), /seed must be 64, 72, or 96 bytes/);
631
+ assert.throws(() => qc.Wallet.encryptSeedSync([], PASSPHRASE_PHRASE), /seed must be 64, 72, or 96 bytes/);
632
+ });
633
+
634
+ it("encryptSeedSync rejects password shorter than 12 characters", async () => {
635
+ await Initialize(null);
636
+ const seed = new Array(64).fill(1);
637
+ assert.throws(() => qc.Wallet.encryptSeedSync(seed, "short"), /serializeSeedAsEncryptedWallet failed/);
638
+ });
639
+
640
+ // ---------------------------------------------------------------------------
641
+ // getSigningContext
642
+ // ---------------------------------------------------------------------------
643
+
644
+ it("getSigningContext: 32-word wallet (pubKey 1408) returns 0 by default, 2 with fullSign", async () => {
645
+ await Initialize(null);
646
+ const w = qc.Wallet.fromPhrase(TEST_SEED_WORDS_32);
647
+ assert.strictEqual(w.getSigningContext(), 0);
648
+ assert.strictEqual(w.getSigningContext(null), 0);
649
+ assert.strictEqual(w.getSigningContext(false), 0);
650
+ assert.strictEqual(w.getSigningContext(true), 2);
651
+ });
652
+
653
+ it("getSigningContext: 48-word wallet (pubKey 1408) returns 0 by default, 2 with fullSign", async () => {
654
+ await Initialize(null);
655
+ const w = qc.Wallet.fromPhrase(TEST_SEED_WORDS);
656
+ assert.strictEqual(w.getSigningContext(), 0);
657
+ assert.strictEqual(w.getSigningContext(null), 0);
658
+ assert.strictEqual(w.getSigningContext(false), 0);
659
+ assert.strictEqual(w.getSigningContext(true), 2);
660
+ });
661
+
662
+ it("getSigningContext: 36-word wallet (pubKey 2688) returns 1 for all fullSign values", async () => {
663
+ await Initialize(null);
664
+ const w = qc.Wallet.fromPhrase(TEST_SEED_WORDS_36);
665
+ assert.strictEqual(w.getSigningContext(), 1);
666
+ assert.strictEqual(w.getSigningContext(null), 1);
667
+ assert.strictEqual(w.getSigningContext(false), 1);
668
+ assert.strictEqual(w.getSigningContext(true), 1);
669
+ });
670
+
671
+ it("getSigningContext: throws for unsupported public key size", async () => {
672
+ await Initialize(null);
673
+ const w = qc.Wallet.fromPhrase(TEST_SEED_WORDS_32);
674
+ (w.signingKey as any).publicKeyBytes = new Uint8Array(100);
675
+ assert.throws(() => w.getSigningContext(), /unsupported public key size/);
676
+ });
549
677
  });