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 +2 -0
- package/README.md +17 -0
- package/examples/package-lock.json +8 -6
- package/examples/package.json +2 -2
- package/examples/wallet-offline.js +9 -0
- package/package.json +3 -3
- package/src/wallet/wallet.d.ts +16 -0
- package/src/wallet/wallet.js +38 -0
- package/test/e2e/signing-context-and-fee.e2e.test.js +5 -5
- package/test/e2e/signing-context-and-fee.e2e.test.ts +5 -5
- package/test/unit/address-wallet.test.js +128 -0
- package/test/unit/address-wallet.test.ts +128 -0
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.
|
|
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.
|
|
9
|
+
"version": "1.0.1",
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"quantum-coin-js-sdk": "1.0.
|
|
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.
|
|
21
|
+
"version": "7.0.10",
|
|
22
22
|
"license": "MIT",
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"quantum-coin-js-sdk": "1.0.
|
|
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.
|
|
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"
|
package/examples/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "quantumcoinjs-sdk-examples",
|
|
3
|
-
"version": "1.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.
|
|
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.
|
|
4
|
-
"description": "QuantumCoin
|
|
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.
|
|
93
|
+
"quantum-coin-js-sdk": "1.0.33"
|
|
94
94
|
}
|
|
95
95
|
}
|
package/src/wallet/wallet.d.ts
CHANGED
|
@@ -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
|
package/src/wallet/wallet.js
CHANGED
|
@@ -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:
|
|
96
|
-
{ wallet: wallet36, signingContext:
|
|
97
|
-
{ wallet: wallet32, signingContext:
|
|
98
|
-
{ wallet: wallet32, signingContext:
|
|
99
|
-
{ wallet: wallet32, signingContext:
|
|
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:
|
|
87
|
-
{ wallet: wallet36, signingContext:
|
|
88
|
-
{ wallet: wallet32, signingContext:
|
|
89
|
-
{ wallet: wallet32, signingContext:
|
|
90
|
-
{ wallet: wallet32, signingContext:
|
|
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
|
});
|