mainnet-js 0.4.30 → 0.4.31
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/dist/index.html +1 -1
- package/dist/main/constant.d.ts +1 -0
- package/dist/main/constant.js +17 -1
- package/dist/main/constant.js.map +1 -1
- package/dist/main/util/getAddrsByXpubKey.d.ts +22 -0
- package/dist/main/util/getAddrsByXpubKey.js +79 -0
- package/dist/main/util/getAddrsByXpubKey.js.map +1 -0
- package/dist/main/util/getXPubKey.d.ts +1 -0
- package/dist/main/util/getXPubKey.js +26 -0
- package/dist/main/util/getXPubKey.js.map +1 -0
- package/dist/main/util/index.d.ts +5 -3
- package/dist/main/util/index.js +13 -6
- package/dist/main/util/index.js.map +1 -1
- package/dist/main/wallet/Base.d.ts +3 -1
- package/dist/main/wallet/Base.js +3 -1
- package/dist/main/wallet/Base.js.map +1 -1
- package/dist/main/wallet/Wif.d.ts +4 -0
- package/dist/main/wallet/Wif.js +72 -3
- package/dist/main/wallet/Wif.js.map +1 -1
- package/dist/main/wallet/interface.d.ts +4 -0
- package/dist/main/wallet/model.d.ts +16 -0
- package/dist/main/wallet/model.js +18 -1
- package/dist/main/wallet/model.js.map +1 -1
- package/dist/mainnet-0.4.31.js +2 -0
- package/dist/{mainnet-0.4.30.js.LICENSE.txt → mainnet-0.4.31.js.LICENSE.txt} +0 -0
- package/dist/module/constant.d.ts +1 -0
- package/dist/module/constant.js +16 -0
- package/dist/module/constant.js.map +1 -1
- package/dist/module/util/getAddrsByXpubKey.d.ts +22 -0
- package/dist/module/util/getAddrsByXpubKey.js +71 -0
- package/dist/module/util/getAddrsByXpubKey.js.map +1 -0
- package/dist/module/util/getXPubKey.d.ts +1 -0
- package/dist/module/util/getXPubKey.js +22 -0
- package/dist/module/util/getXPubKey.js.map +1 -0
- package/dist/module/util/index.d.ts +5 -3
- package/dist/module/util/index.js +5 -3
- package/dist/module/util/index.js.map +1 -1
- package/dist/module/wallet/Base.d.ts +3 -1
- package/dist/module/wallet/Base.js +3 -1
- package/dist/module/wallet/Base.js.map +1 -1
- package/dist/module/wallet/Wif.d.ts +4 -0
- package/dist/module/wallet/Wif.js +76 -7
- package/dist/module/wallet/Wif.js.map +1 -1
- package/dist/module/wallet/interface.d.ts +4 -0
- package/dist/module/wallet/model.d.ts +16 -0
- package/dist/module/wallet/model.js +16 -0
- package/dist/module/wallet/model.js.map +1 -1
- package/dist/tsconfig.browser.tsbuildinfo +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/constant.ts +17 -0
- package/src/util/getAddrsByXpubKey.test.ts +115 -0
- package/src/util/getAddrsByXpubKey.ts +98 -0
- package/src/util/getXPubKey.ts +36 -0
- package/src/util/index.ts +10 -3
- package/src/wallet/Base.ts +4 -1
- package/src/wallet/Wif.test.ts +173 -1
- package/src/wallet/Wif.ts +100 -15
- package/src/wallet/createWallet.test.ts +2 -0
- package/src/wallet/interface.ts +4 -0
- package/src/wallet/model.ts +22 -0
- package/dist/mainnet-0.4.30.js +0 -2
package/src/wallet/Wif.test.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { bchParam } from "../chain";
|
|
|
3
3
|
import { BalanceResponse } from "../util/balanceObjectFromSatoshi";
|
|
4
4
|
import { UnitEnum } from "../enum";
|
|
5
5
|
import { initProviders, disconnectProviders } from "../network/Connection";
|
|
6
|
-
import { DUST_UTXO_THRESHOLD as DUST } from "../constant";
|
|
6
|
+
import { DERIVATION_PATHS, DUST_UTXO_THRESHOLD as DUST } from "../constant";
|
|
7
7
|
import { delay } from "../util/delay";
|
|
8
8
|
import { OpReturnData, SendResponse } from "./model";
|
|
9
9
|
import { ElectrumRawTransaction } from "../network/interface";
|
|
@@ -183,6 +183,9 @@ describe(`Mnemonic wallet creation`, () => {
|
|
|
183
183
|
"04aaeb52dd7494c361049de67cc680e83ebcbbbdbeb13637d92cd845f70308af5e9370164133294e5fd1679672fe7866c307daf97281a28f66dca7cbb52919824f",
|
|
184
184
|
publicKeyHash: "d986ed01b7a22225a70edbf2ba7cfb63a15cb3aa",
|
|
185
185
|
|
|
186
|
+
parentXPubKey:
|
|
187
|
+
"xpub6BosfCnifzxcFwrSzQiqu2DBVTshkCXacvNsWGYJVVhhawA7d4R5WSWGFNbi8Aw6ZRc1brxMyWMzG3DSSSSoekkudhUd9yLb6qx39T9nMdj",
|
|
188
|
+
parentDerivationPath: "m/44'/0'/0'",
|
|
186
189
|
derivationPath: "m/44'/0'/0'/0/0",
|
|
187
190
|
seed: "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about",
|
|
188
191
|
|
|
@@ -208,6 +211,7 @@ describe(`Mnemonic wallet creation`, () => {
|
|
|
208
211
|
"abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"
|
|
209
212
|
);
|
|
210
213
|
expect(w.getSeed().derivationPath).toBe("m/44'/145'/0'/0/0");
|
|
214
|
+
expect(w.getSeed().parentDerivationPath).toBe("m/44'/145'/0'");
|
|
211
215
|
});
|
|
212
216
|
test("Expect '11x abandon about' to have the correct key, seed and path from regtest wallet", async () => {
|
|
213
217
|
let w = await RegTestWallet.fromId(
|
|
@@ -226,6 +230,172 @@ describe(`Mnemonic wallet creation`, () => {
|
|
|
226
230
|
});
|
|
227
231
|
});
|
|
228
232
|
|
|
233
|
+
describe(`XPubKey path derivation`, () => {
|
|
234
|
+
test("Expect '11x abandon about' to have the correct xpubs for common derivation paths, seed and path", async () => {
|
|
235
|
+
let w = await Wallet.fromId(
|
|
236
|
+
"seed:mainnet:abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"
|
|
237
|
+
);
|
|
238
|
+
let commonPaths = await w.deriveHdPaths(DERIVATION_PATHS);
|
|
239
|
+
expect(commonPaths).toStrictEqual([
|
|
240
|
+
{
|
|
241
|
+
path: "m/0",
|
|
242
|
+
xPubKey:
|
|
243
|
+
"xpub68jrRzQfUmwSaf5Y37Yd5uwfnMRxiR14M3HBonDr91GB7GKEh7R9Mvu2UeCtbASfXZ9FdNo9FwFx6a37HNXUDiXVQFXuadXmevRBa3y7rL8",
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
path: "m/0'",
|
|
247
|
+
xPubKey:
|
|
248
|
+
"xpub68jrRzQopSUQm76hJ6TNtiJMJfhj38u1X12xCzExrw388hcN443UVnYpswdUkV7vPJ3KayiCdp3Q5E23s4wvkucohVTh7eSstJdBFyn2DMx",
|
|
249
|
+
},
|
|
250
|
+
{
|
|
251
|
+
path: "m/0'/0",
|
|
252
|
+
xPubKey:
|
|
253
|
+
"xpub6A7PsGUCo9qsn1jhZVB68WKWU9bTt1Wu7fzRqhczRbJ3u3xsF1bJmWBL1MvygTtrfmvNw1adLzmRjQHtDCJDXAHFa4K3wELpGGqEXL4e6d4",
|
|
254
|
+
},
|
|
255
|
+
{
|
|
256
|
+
path: "m/0'/0'",
|
|
257
|
+
xPubKey:
|
|
258
|
+
"xpub6A7PsGUM8pNqwy9AceVuFK6KxY88FhvFMRGP9fjEDKA3P4WpR1zyHH3Lmczj7eorx4RbDC4Qttd8C7HhLA2W9LsxxZzXo1DMCwJFb3zZKZ8",
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
path: "m/0'/0'/0'",
|
|
262
|
+
xPubKey:
|
|
263
|
+
"xpub6BiChRN7aqq51RA7RnAmKhqKdGckPncrHWLrj1xoj6ZMfdMJ1dX4Ysh9V3yEhpFCpC3BapjR83xPKY693XXTEU6qgWU3qZs78WBHA15uhYf",
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
path: "m/44'/0'/0'",
|
|
267
|
+
xPubKey:
|
|
268
|
+
"xpub6BosfCnifzxcFwrSzQiqu2DBVTshkCXacvNsWGYJVVhhawA7d4R5WSWGFNbi8Aw6ZRc1brxMyWMzG3DSSSSoekkudhUd9yLb6qx39T9nMdj",
|
|
269
|
+
},
|
|
270
|
+
{
|
|
271
|
+
path: "m/44'/0'/0'/0",
|
|
272
|
+
xPubKey:
|
|
273
|
+
"xpub6ELHKXNimKbxMCytPh7EdC2QXx46T9qLDJWGnTraz1H9kMMFdcduoU69wh9cxP12wDxqAAfbaESWGYt5rREsX1J8iR2TEunvzvddduAPYcY",
|
|
274
|
+
},
|
|
275
|
+
{
|
|
276
|
+
path: "m/44'/145'/0'",
|
|
277
|
+
xPubKey:
|
|
278
|
+
"xpub6ByHsPNSQXTWZ7PLESMY2FufyYWtLXagSUpMQq7Un96SiThZH2iJB1X7pwviH1WtKVeDP6K8d6xxFzzoaFzF3s8BKCZx8oEDdDkNnp4owAZ",
|
|
279
|
+
},
|
|
280
|
+
{
|
|
281
|
+
path: "m/44'/145'/0'/0",
|
|
282
|
+
xPubKey:
|
|
283
|
+
"xpub6F2iaK2JUPcgrZ6RTGH6t8VybLPu1XzfrHsDsaKvK6NfULznU6i6aw6ZoefDW2DpNruSLw73RwQg46qvpqB3eryeJJ2tkFCF4Z6gbr8Pjja",
|
|
284
|
+
},
|
|
285
|
+
{
|
|
286
|
+
path: "m/44'/245'/0",
|
|
287
|
+
xPubKey:
|
|
288
|
+
"xpub6Ch34ms5osevEtkEZX81n8EG4c6vgHWGH1gQXBG2uf2Tihb1eed4H1wozLfZB31mV9JD7mymYTQxcLKFFjZHdM5NGdH2Ud1ksSkfwSFjjCg",
|
|
289
|
+
},
|
|
290
|
+
{
|
|
291
|
+
path: "m/44'/245'/0'",
|
|
292
|
+
xPubKey:
|
|
293
|
+
"xpub6Ch34msE9YBtQV7pZrLyRXHwocrpJtNN4KDG8bbyxyhGmEM5MirtqkiH4h9dvnVJ3MekET3w2Fkvej3fyo8WLz9bRPyDynDf6NXNfuydhv1",
|
|
294
|
+
},
|
|
295
|
+
{
|
|
296
|
+
path: "m/44'/245'/0'/0",
|
|
297
|
+
xPubKey:
|
|
298
|
+
"xpub6FFeETss5Zwkw78NDAibKEaGxigU3bgYzLihcqbQqqTyb6jorR9mgR9AexYydxmiPU8koAf5ndaQPjPWK3sDz1wjBjf2TkLbD982S9PWd9Z",
|
|
299
|
+
},
|
|
300
|
+
]);
|
|
301
|
+
});
|
|
302
|
+
test("Expect '11x abandon about' to return 'protected' for root path", async () => {
|
|
303
|
+
expect.assertions(1);
|
|
304
|
+
try {
|
|
305
|
+
let w = await Wallet.fromId(
|
|
306
|
+
"seed:mainnet:abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"
|
|
307
|
+
);
|
|
308
|
+
let commonPaths = await w.deriveHdPaths(["m"]);
|
|
309
|
+
} catch (e: any) {
|
|
310
|
+
expect(e.message).toBe(
|
|
311
|
+
"Storing or sharing of parent public key may lead to loss of funds. Storing or sharing *root* parent public keys is strongly discouraged, although all parent keys have risk. See: https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#implications"
|
|
312
|
+
);
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
test("Expect '11x abandon about' to have the correct xpubs for common derivation paths, seed and path", async () => {
|
|
317
|
+
let w = await Wallet.fromId(
|
|
318
|
+
"seed:mainnet:abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"
|
|
319
|
+
);
|
|
320
|
+
let commonPaths = await w.getXPubKeys();
|
|
321
|
+
expect(commonPaths).toStrictEqual([
|
|
322
|
+
{
|
|
323
|
+
path: "m/0",
|
|
324
|
+
xPubKey:
|
|
325
|
+
"xpub68jrRzQfUmwSaf5Y37Yd5uwfnMRxiR14M3HBonDr91GB7GKEh7R9Mvu2UeCtbASfXZ9FdNo9FwFx6a37HNXUDiXVQFXuadXmevRBa3y7rL8",
|
|
326
|
+
},
|
|
327
|
+
{
|
|
328
|
+
path: "m/0'",
|
|
329
|
+
xPubKey:
|
|
330
|
+
"xpub68jrRzQopSUQm76hJ6TNtiJMJfhj38u1X12xCzExrw388hcN443UVnYpswdUkV7vPJ3KayiCdp3Q5E23s4wvkucohVTh7eSstJdBFyn2DMx",
|
|
331
|
+
},
|
|
332
|
+
{
|
|
333
|
+
path: "m/0'/0",
|
|
334
|
+
xPubKey:
|
|
335
|
+
"xpub6A7PsGUCo9qsn1jhZVB68WKWU9bTt1Wu7fzRqhczRbJ3u3xsF1bJmWBL1MvygTtrfmvNw1adLzmRjQHtDCJDXAHFa4K3wELpGGqEXL4e6d4",
|
|
336
|
+
},
|
|
337
|
+
{
|
|
338
|
+
path: "m/0'/0'",
|
|
339
|
+
xPubKey:
|
|
340
|
+
"xpub6A7PsGUM8pNqwy9AceVuFK6KxY88FhvFMRGP9fjEDKA3P4WpR1zyHH3Lmczj7eorx4RbDC4Qttd8C7HhLA2W9LsxxZzXo1DMCwJFb3zZKZ8",
|
|
341
|
+
},
|
|
342
|
+
{
|
|
343
|
+
path: "m/0'/0'/0'",
|
|
344
|
+
xPubKey:
|
|
345
|
+
"xpub6BiChRN7aqq51RA7RnAmKhqKdGckPncrHWLrj1xoj6ZMfdMJ1dX4Ysh9V3yEhpFCpC3BapjR83xPKY693XXTEU6qgWU3qZs78WBHA15uhYf",
|
|
346
|
+
},
|
|
347
|
+
{
|
|
348
|
+
path: "m/44'/0'/0'",
|
|
349
|
+
xPubKey:
|
|
350
|
+
"xpub6BosfCnifzxcFwrSzQiqu2DBVTshkCXacvNsWGYJVVhhawA7d4R5WSWGFNbi8Aw6ZRc1brxMyWMzG3DSSSSoekkudhUd9yLb6qx39T9nMdj",
|
|
351
|
+
},
|
|
352
|
+
{
|
|
353
|
+
path: "m/44'/0'/0'/0",
|
|
354
|
+
xPubKey:
|
|
355
|
+
"xpub6ELHKXNimKbxMCytPh7EdC2QXx46T9qLDJWGnTraz1H9kMMFdcduoU69wh9cxP12wDxqAAfbaESWGYt5rREsX1J8iR2TEunvzvddduAPYcY",
|
|
356
|
+
},
|
|
357
|
+
{
|
|
358
|
+
path: "m/44'/145'/0'",
|
|
359
|
+
xPubKey:
|
|
360
|
+
"xpub6ByHsPNSQXTWZ7PLESMY2FufyYWtLXagSUpMQq7Un96SiThZH2iJB1X7pwviH1WtKVeDP6K8d6xxFzzoaFzF3s8BKCZx8oEDdDkNnp4owAZ",
|
|
361
|
+
},
|
|
362
|
+
{
|
|
363
|
+
path: "m/44'/145'/0'/0",
|
|
364
|
+
xPubKey:
|
|
365
|
+
"xpub6F2iaK2JUPcgrZ6RTGH6t8VybLPu1XzfrHsDsaKvK6NfULznU6i6aw6ZoefDW2DpNruSLw73RwQg46qvpqB3eryeJJ2tkFCF4Z6gbr8Pjja",
|
|
366
|
+
},
|
|
367
|
+
{
|
|
368
|
+
path: "m/44'/245'/0",
|
|
369
|
+
xPubKey:
|
|
370
|
+
"xpub6Ch34ms5osevEtkEZX81n8EG4c6vgHWGH1gQXBG2uf2Tihb1eed4H1wozLfZB31mV9JD7mymYTQxcLKFFjZHdM5NGdH2Ud1ksSkfwSFjjCg",
|
|
371
|
+
},
|
|
372
|
+
{
|
|
373
|
+
path: "m/44'/245'/0'",
|
|
374
|
+
xPubKey:
|
|
375
|
+
"xpub6Ch34msE9YBtQV7pZrLyRXHwocrpJtNN4KDG8bbyxyhGmEM5MirtqkiH4h9dvnVJ3MekET3w2Fkvej3fyo8WLz9bRPyDynDf6NXNfuydhv1",
|
|
376
|
+
},
|
|
377
|
+
{
|
|
378
|
+
path: "m/44'/245'/0'/0",
|
|
379
|
+
xPubKey:
|
|
380
|
+
"xpub6FFeETss5Zwkw78NDAibKEaGxigU3bgYzLihcqbQqqTyb6jorR9mgR9AexYydxmiPU8koAf5ndaQPjPWK3sDz1wjBjf2TkLbD982S9PWd9Z",
|
|
381
|
+
},
|
|
382
|
+
]);
|
|
383
|
+
});
|
|
384
|
+
test("Expect '11x abandon about' to return 'protected' for root path", async () => {
|
|
385
|
+
expect.assertions(1);
|
|
386
|
+
try {
|
|
387
|
+
let w = await Wallet.fromId(
|
|
388
|
+
"seed:mainnet:abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"
|
|
389
|
+
);
|
|
390
|
+
let commonPaths = await w.getXPubKeys(["m"]);
|
|
391
|
+
} catch (e: any) {
|
|
392
|
+
expect(e.message).toBe(
|
|
393
|
+
"Storing or sharing of parent public key may lead to loss of funds. Storing or sharing *root* parent public keys is strongly discouraged, although all parent keys have risk. See: https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#implications"
|
|
394
|
+
);
|
|
395
|
+
}
|
|
396
|
+
});
|
|
397
|
+
});
|
|
398
|
+
|
|
229
399
|
describe(`Watch only Wallets`, () => {
|
|
230
400
|
test("Create a watch only testnet wallet from string id", async () => {
|
|
231
401
|
let w = await TestNetWallet.fromId(
|
|
@@ -242,6 +412,8 @@ describe(`Watch only Wallets`, () => {
|
|
|
242
412
|
isTestnet: true,
|
|
243
413
|
name: "",
|
|
244
414
|
network: "testnet",
|
|
415
|
+
parentDerivationPath: undefined,
|
|
416
|
+
parentXPubKey: undefined,
|
|
245
417
|
privateKey: undefined,
|
|
246
418
|
privateKeyWif: undefined,
|
|
247
419
|
publicKey: undefined,
|
package/src/wallet/Wif.ts
CHANGED
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
//#region Imports
|
|
2
2
|
// Stable
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
deriveHdPublicNodeIdentifier,
|
|
5
|
+
encodeHdPublicKey,
|
|
6
|
+
HdKeyNetwork,
|
|
7
|
+
instantiateSecp256k1,
|
|
8
|
+
instantiateSha256,
|
|
9
|
+
} from "@bitauth/libauth";
|
|
4
10
|
|
|
5
11
|
// Unstable?
|
|
6
12
|
import {
|
|
7
13
|
binToHex,
|
|
8
14
|
CashAddressNetworkPrefix,
|
|
15
|
+
deriveHdPublicNode,
|
|
9
16
|
decodePrivateKeyWif,
|
|
10
17
|
encodePrivateKeyWif,
|
|
11
18
|
deriveHdPrivateNodeFromSeed,
|
|
@@ -40,6 +47,7 @@ import {
|
|
|
40
47
|
SendResponse,
|
|
41
48
|
UtxoItem,
|
|
42
49
|
UtxoResponse,
|
|
50
|
+
XPubKey,
|
|
43
51
|
} from "./model";
|
|
44
52
|
|
|
45
53
|
import {
|
|
@@ -92,7 +100,8 @@ import { generateRandomBytes } from "../util/randomBytes";
|
|
|
92
100
|
import { SignedMessageI, SignedMessage } from "../message";
|
|
93
101
|
import ElectrumNetworkProvider from "../network/ElectrumNetworkProvider";
|
|
94
102
|
import { amountInSatoshi } from "../util/amountInSatoshi";
|
|
95
|
-
import {
|
|
103
|
+
import { getXPubKey } from "../util/getXPubKey";
|
|
104
|
+
import { DERIVATION_PATHS, DUST_UTXO_THRESHOLD } from "../constant";
|
|
96
105
|
|
|
97
106
|
//#endregion Imports
|
|
98
107
|
|
|
@@ -105,6 +114,8 @@ const sha256Promise = instantiateSha256();
|
|
|
105
114
|
export class Wallet extends BaseWallet {
|
|
106
115
|
cashaddr?: string;
|
|
107
116
|
derivationPath: string = "m/44'/0'/0'/0/0";
|
|
117
|
+
parentDerivationPath: string = "m/44'/0'/0'";
|
|
118
|
+
parentXPubKey?: string;
|
|
108
119
|
privateKey?: Uint8Array;
|
|
109
120
|
publicKeyCompressed?: Uint8Array;
|
|
110
121
|
privateKeyWif?: string;
|
|
@@ -186,6 +197,10 @@ export class Wallet extends BaseWallet {
|
|
|
186
197
|
network: this.network as any,
|
|
187
198
|
seed: this.mnemonic ? this.getSeed().seed : undefined,
|
|
188
199
|
derivationPath: this.mnemonic ? this.getSeed().derivationPath : undefined,
|
|
200
|
+
parentDerivationPath: this.mnemonic
|
|
201
|
+
? this.getSeed().parentDerivationPath
|
|
202
|
+
: undefined,
|
|
203
|
+
parentXPubKey: this.parentXPubKey ? this.parentXPubKey : undefined,
|
|
189
204
|
publicKey: this.publicKey ? binToHex(this.publicKey!) : undefined,
|
|
190
205
|
publicKeyHash: binToHex(this.publicKeyHash!),
|
|
191
206
|
privateKey: this.privateKey ? binToHex(this.privateKey!) : undefined,
|
|
@@ -319,19 +334,25 @@ export class Wallet extends BaseWallet {
|
|
|
319
334
|
}
|
|
320
335
|
|
|
321
336
|
private async _generateMnemonic() {
|
|
322
|
-
const crypto = await instantiateBIP32Crypto();
|
|
323
337
|
this.mnemonic = generateMnemonic();
|
|
324
338
|
let seed = mnemonicToSeedSync(this.mnemonic!);
|
|
339
|
+
let network = this.isTestnet ? "testnet" : "mainnet";
|
|
340
|
+
this.parentXPubKey = await getXPubKey(
|
|
341
|
+
seed,
|
|
342
|
+
this.parentDerivationPath,
|
|
343
|
+
network
|
|
344
|
+
);
|
|
345
|
+
|
|
346
|
+
const crypto = await instantiateBIP32Crypto();
|
|
325
347
|
let hdNode = deriveHdPrivateNodeFromSeed(crypto, seed);
|
|
326
348
|
if (!hdNode.valid) {
|
|
327
349
|
throw Error("Invalid private key derived from mnemonic seed");
|
|
328
350
|
}
|
|
329
351
|
|
|
330
|
-
let zerothChild = deriveHdPath(
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
) as HdPrivateNodeValid;
|
|
352
|
+
let zerothChild = deriveHdPath(crypto, hdNode, this.derivationPath);
|
|
353
|
+
if (typeof zerothChild === "string") {
|
|
354
|
+
throw Error(zerothChild);
|
|
355
|
+
}
|
|
335
356
|
this.privateKey = zerothChild.privateKey;
|
|
336
357
|
|
|
337
358
|
this.walletType = WalletTypeEnum.Seed;
|
|
@@ -353,6 +374,18 @@ export class Wallet extends BaseWallet {
|
|
|
353
374
|
return super.fromId(walletId);
|
|
354
375
|
};
|
|
355
376
|
|
|
377
|
+
public async getXPubKeys(paths?) {
|
|
378
|
+
if (this.mnemonic) {
|
|
379
|
+
if (paths) {
|
|
380
|
+
let xPubKeys = await this.deriveHdPaths(paths);
|
|
381
|
+
return [xPubKeys];
|
|
382
|
+
} else {
|
|
383
|
+
return await this.deriveHdPaths(DERIVATION_PATHS);
|
|
384
|
+
}
|
|
385
|
+
} else {
|
|
386
|
+
throw Error("xpubkeys can only be derived from seed type wallets.");
|
|
387
|
+
}
|
|
388
|
+
}
|
|
356
389
|
// Initialize wallet from a mnemonic phrase
|
|
357
390
|
protected async fromSeed(
|
|
358
391
|
mnemonic: string,
|
|
@@ -369,20 +402,73 @@ export class Wallet extends BaseWallet {
|
|
|
369
402
|
}
|
|
370
403
|
if (derivationPath) {
|
|
371
404
|
this.derivationPath = derivationPath;
|
|
405
|
+
|
|
406
|
+
// If the derivation path is for the first account child, set the parent derivation path
|
|
407
|
+
let path = derivationPath.split("/");
|
|
408
|
+
if (path.slice(-2).join("/") == "0/0") {
|
|
409
|
+
this.parentDerivationPath = path.slice(0, -2).join("/");
|
|
410
|
+
}
|
|
372
411
|
}
|
|
373
412
|
|
|
374
|
-
let zerothChild = deriveHdPath(
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
) as HdPrivateNodeValid;
|
|
413
|
+
let zerothChild = deriveHdPath(crypto, hdNode, this.derivationPath);
|
|
414
|
+
if (typeof zerothChild === "string") {
|
|
415
|
+
throw Error(zerothChild);
|
|
416
|
+
}
|
|
379
417
|
this.privateKey = zerothChild.privateKey;
|
|
380
418
|
|
|
419
|
+
let network = this.isTestnet ? "testnet" : "mainnet";
|
|
420
|
+
this.parentXPubKey = await getXPubKey(
|
|
421
|
+
seed,
|
|
422
|
+
this.parentDerivationPath,
|
|
423
|
+
network
|
|
424
|
+
);
|
|
425
|
+
|
|
381
426
|
this.walletType = WalletTypeEnum.Seed;
|
|
382
427
|
await this.deriveInfo();
|
|
383
428
|
return this;
|
|
384
429
|
}
|
|
385
430
|
|
|
431
|
+
// Get common xpub paths from zerothChild privateKey
|
|
432
|
+
public async deriveHdPaths(hdPaths: string[]): Promise<any[]> {
|
|
433
|
+
const crypto = await instantiateBIP32Crypto();
|
|
434
|
+
let seed = mnemonicToSeedSync(this.mnemonic!);
|
|
435
|
+
let hdNode = deriveHdPrivateNodeFromSeed(crypto, seed);
|
|
436
|
+
if (!hdNode.valid) {
|
|
437
|
+
throw Error("Invalid private key derived from mnemonic seed");
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
let result: any[] = [];
|
|
441
|
+
|
|
442
|
+
for (const path of hdPaths) {
|
|
443
|
+
if (path === "m") {
|
|
444
|
+
throw Error(
|
|
445
|
+
"Storing or sharing of parent public key may lead to loss of funds. Storing or sharing *root* parent public keys is strongly discouraged, although all parent keys have risk. See: https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#implications"
|
|
446
|
+
);
|
|
447
|
+
}
|
|
448
|
+
let childNode = deriveHdPath(crypto, hdNode, path);
|
|
449
|
+
if (typeof childNode === "string") {
|
|
450
|
+
throw Error(childNode);
|
|
451
|
+
}
|
|
452
|
+
let node = deriveHdPublicNode(crypto, childNode);
|
|
453
|
+
if (typeof node === "string") {
|
|
454
|
+
throw Error(node);
|
|
455
|
+
}
|
|
456
|
+
let xPubKey = encodeHdPublicKey(crypto, {
|
|
457
|
+
network: this.network as HdKeyNetwork,
|
|
458
|
+
node: node,
|
|
459
|
+
});
|
|
460
|
+
let key = new XPubKey({
|
|
461
|
+
path: path,
|
|
462
|
+
xPubKey: xPubKey,
|
|
463
|
+
});
|
|
464
|
+
|
|
465
|
+
result.push(await key.ready());
|
|
466
|
+
}
|
|
467
|
+
return await Promise.all(result).then((result) => {
|
|
468
|
+
return result;
|
|
469
|
+
});
|
|
470
|
+
}
|
|
471
|
+
|
|
386
472
|
// Initialize a watch only wallet from a cash addr
|
|
387
473
|
protected async watchOnly(address: string): Promise<this> {
|
|
388
474
|
this.walletType = WalletTypeEnum.Watch;
|
|
@@ -417,8 +503,7 @@ export class Wallet extends BaseWallet {
|
|
|
417
503
|
const sha256 = await sha256Promise;
|
|
418
504
|
let wifResult = decodePrivateKeyWif(sha256, secret);
|
|
419
505
|
|
|
420
|
-
|
|
421
|
-
if (hasError) {
|
|
506
|
+
if (typeof wifResult === "string") {
|
|
422
507
|
throw Error(wifResult as string);
|
|
423
508
|
}
|
|
424
509
|
let resultData: PrivateKeyI = wifResult as PrivateKeyI;
|
package/src/wallet/interface.ts
CHANGED
|
@@ -23,6 +23,7 @@ export interface WalletResponseI {
|
|
|
23
23
|
privkey?: string;
|
|
24
24
|
seed?: string;
|
|
25
25
|
derivationPath?: string;
|
|
26
|
+
parentDerivationPath?: string;
|
|
26
27
|
}
|
|
27
28
|
|
|
28
29
|
export interface WalletInfoI {
|
|
@@ -32,6 +33,8 @@ export interface WalletInfoI {
|
|
|
32
33
|
network: NetworkEnum;
|
|
33
34
|
seed?: string;
|
|
34
35
|
derivationPath?: string;
|
|
36
|
+
parentDerivationPath?: string;
|
|
37
|
+
parentXPubKey?: string;
|
|
35
38
|
publicKey?: string;
|
|
36
39
|
publicKeyHash?: string;
|
|
37
40
|
privateKey?: string;
|
|
@@ -52,6 +55,7 @@ export interface SendRequestOptionsI {
|
|
|
52
55
|
export interface MnemonicI {
|
|
53
56
|
seed: string;
|
|
54
57
|
derivationPath: string;
|
|
58
|
+
parentDerivationPath: string;
|
|
55
59
|
}
|
|
56
60
|
|
|
57
61
|
export interface WalletI {
|
package/src/wallet/model.ts
CHANGED
|
@@ -159,3 +159,25 @@ export class SendResponse {
|
|
|
159
159
|
this.explorerUrl = explorerUrl;
|
|
160
160
|
}
|
|
161
161
|
}
|
|
162
|
+
|
|
163
|
+
export class XPubKey {
|
|
164
|
+
path: string;
|
|
165
|
+
xPubKey: string;
|
|
166
|
+
|
|
167
|
+
constructor({ path, xPubKey }: { path: string; xPubKey: string }) {
|
|
168
|
+
this.path = path;
|
|
169
|
+
this.xPubKey = xPubKey;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
public async ready() {
|
|
173
|
+
await this.xPubKey;
|
|
174
|
+
return this.asObject();
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
public asObject() {
|
|
178
|
+
return {
|
|
179
|
+
path: this.path,
|
|
180
|
+
xPubKey: this.xPubKey,
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
}
|