mainnet-js 0.4.28 → 0.4.32
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 +33 -10
- package/dist/main/wallet/Wif.js +188 -77
- package/dist/main/wallet/Wif.js.map +1 -1
- package/dist/main/wallet/interface.d.ts +5 -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.28.js → mainnet-0.4.32.js} +2 -2
- package/dist/{mainnet-0.4.28.js.LICENSE.txt → mainnet-0.4.32.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 +33 -10
- package/dist/module/wallet/Wif.js +191 -80
- package/dist/module/wallet/Wif.js.map +1 -1
- package/dist/module/wallet/interface.d.ts +5 -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 +215 -2
- package/src/wallet/Wif.ts +284 -130
- package/src/wallet/createWallet.test.ts +2 -0
- package/src/wallet/interface.ts +6 -1
- package/src/wallet/model.ts +22 -0
package/src/constant.ts
CHANGED
|
@@ -8,3 +8,20 @@ export const MEMPOOL_CHAIN_LIMIT = 50;
|
|
|
8
8
|
|
|
9
9
|
// time in milliseconds to cache the usd exchange rate
|
|
10
10
|
export const EXCHANGE_RATE_TTL = 250000;
|
|
11
|
+
|
|
12
|
+
// list of common derivation paths
|
|
13
|
+
// a la: https://github.com/Electron-Cash/Electron-Cash/blob/1de24c509992cfebc22217a2a77c862c2b02bc54/electroncash_gui/qt/installwizard.py#L624
|
|
14
|
+
export const DERIVATION_PATHS = [
|
|
15
|
+
"m/0",
|
|
16
|
+
"m/0'",
|
|
17
|
+
"m/0'/0",
|
|
18
|
+
"m/0'/0'",
|
|
19
|
+
"m/0'/0'/0'",
|
|
20
|
+
"m/44'/0'/0'",
|
|
21
|
+
"m/44'/0'/0'/0",
|
|
22
|
+
"m/44'/145'/0'",
|
|
23
|
+
"m/44'/145'/0'/0",
|
|
24
|
+
"m/44'/245'/0",
|
|
25
|
+
"m/44'/245'/0'",
|
|
26
|
+
"m/44'/245'/0'/0",
|
|
27
|
+
];
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import {
|
|
2
|
+
derivePublicNodeCashaddr,
|
|
3
|
+
getAddrsByXpubKey,
|
|
4
|
+
getXpubKeyInfo,
|
|
5
|
+
} from "./getAddrsByXpubKey";
|
|
6
|
+
|
|
7
|
+
test("Should decode xpubInfo", async () => {
|
|
8
|
+
let xpub =
|
|
9
|
+
"xpub6BosfCnifzxcFwrSzQiqu2DBVTshkCXacvNsWGYJVVhhawA7d4R5WSWGFNbi8Aw6ZRc1brxMyWMzG3DSSSSoekkudhUd9yLb6qx39T9nMdj";
|
|
10
|
+
let xpubInfo = await getXpubKeyInfo(xpub);
|
|
11
|
+
expect(xpubInfo.version).toBe("mainnet");
|
|
12
|
+
expect(xpubInfo.depth).toBe(3);
|
|
13
|
+
expect(xpubInfo.parentFingerprint).toBe("155bca59");
|
|
14
|
+
expect(xpubInfo.childNumber).toBe(2147483648);
|
|
15
|
+
expect(xpubInfo.chain).toBe(
|
|
16
|
+
"3da4bc190a2680111d31fadfdc905f2a7f6ce77c6f109919116f253d43445219"
|
|
17
|
+
);
|
|
18
|
+
expect(xpubInfo.data).toBe(
|
|
19
|
+
"03774c910fcf07fa96886ea794f0d5caed9afe30b44b83f7e213bb92930e7df4bd"
|
|
20
|
+
);
|
|
21
|
+
expect(xpubInfo.fingerprint).toBe("6cc9f252");
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test("Should derive cashaddr given xpub and path", async () => {
|
|
25
|
+
// abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about
|
|
26
|
+
// m/0
|
|
27
|
+
const xpub =
|
|
28
|
+
"xpub6F2iaK2JUPcgrZ6RTGH6t8VybLPu1XzfrHsDsaKvK6NfULznU6i6aw6ZoefDW2DpNruSLw73RwQg46qvpqB3eryeJJ2tkFCF4Z6gbr8Pjja";
|
|
29
|
+
const vectors = [
|
|
30
|
+
// M/44'/145'/0'/0/0
|
|
31
|
+
"bitcoincash:qqyx49mu0kkn9ftfj6hje6g2wfer34yfnq5tahq3q6",
|
|
32
|
+
// M/44'/145'/0'/0/1
|
|
33
|
+
"bitcoincash:qp8sfdhgjlq68hlzka9lcsxtcnvuvnd0xqxugfzzc5",
|
|
34
|
+
// M/44'/145'/0'/0/2
|
|
35
|
+
"bitcoincash:qqkuy34ntrye9a2h4xpdstcu4aq5wfrwscjtaphenr",
|
|
36
|
+
];
|
|
37
|
+
|
|
38
|
+
for (let i = 0; i < vectors.length; i++) {
|
|
39
|
+
// M/44'/145'/0'/0/
|
|
40
|
+
const publicNode = await derivePublicNodeCashaddr(xpub, 0, `M/${i}`);
|
|
41
|
+
expect(publicNode).toBe(vectors[i]);
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test("Should derive list of cashaddrs from m/44'/0'/0' given xpub path, & limit", async () => {
|
|
46
|
+
// abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about
|
|
47
|
+
// m/44'/0'/0'
|
|
48
|
+
const xpub =
|
|
49
|
+
"xpub6BosfCnifzxcFwrSzQiqu2DBVTshkCXacvNsWGYJVVhhawA7d4R5WSWGFNbi8Aw6ZRc1brxMyWMzG3DSSSSoekkudhUd9yLb6qx39T9nMdj";
|
|
50
|
+
const vectors = [
|
|
51
|
+
// m/44'/0'/0'/0/0
|
|
52
|
+
"bitcoincash:qrvcdmgpk73zyfd8pmdl9wnuld36zh9n4gms8s0u59",
|
|
53
|
+
// m/44'/0'/0'/0/1
|
|
54
|
+
"bitcoincash:qp4wzvqu73x22ft4r5tk8tz0aufdz9fescwtpcmhc7",
|
|
55
|
+
// m/44'/0'/0'/0/2
|
|
56
|
+
"bitcoincash:qr0kwqzf2h3wvjjhn4pg895lrxwp96wqgyhkksq2nh",
|
|
57
|
+
];
|
|
58
|
+
|
|
59
|
+
// M/44'/0'/0'/0/i
|
|
60
|
+
const cashaddrs = await getAddrsByXpubKey(xpub, "0/0", 3);
|
|
61
|
+
expect(cashaddrs).toStrictEqual(vectors);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test("Should derive list of change cashaddrs from m/44'/0'/0' given xpub path, & limit", async () => {
|
|
65
|
+
// abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about
|
|
66
|
+
// m/44'/0'/0'
|
|
67
|
+
const xpub =
|
|
68
|
+
"xpub6BosfCnifzxcFwrSzQiqu2DBVTshkCXacvNsWGYJVVhhawA7d4R5WSWGFNbi8Aw6ZRc1brxMyWMzG3DSSSSoekkudhUd9yLb6qx39T9nMdj";
|
|
69
|
+
const vectors = [
|
|
70
|
+
// m/44'/0'/0'/1/0
|
|
71
|
+
"bitcoincash:qzawj0yw07mgys3dy3uqkxsj54gwlapg7gjw8v3grk",
|
|
72
|
+
// m/44'/0'/0'/1/1
|
|
73
|
+
"bitcoincash:qqsqv86eghvyxcq7q5eg3l3ad7r7xcff65egddy9e9",
|
|
74
|
+
// m/44'/0'/0'/1/2
|
|
75
|
+
"bitcoincash:qrdexhxheryn7n2kf2s7g9kypfe0ynakrqm3j0f69w",
|
|
76
|
+
];
|
|
77
|
+
|
|
78
|
+
// M/44'/0'/0'/0/i
|
|
79
|
+
const cashaddrs = await getAddrsByXpubKey(xpub, "1/0", 3);
|
|
80
|
+
expect(cashaddrs).toStrictEqual(vectors);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
test("Should derive list of cashaddrs from M/44'/145'/0' given xpub, path and limit", async () => {
|
|
84
|
+
// abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about
|
|
85
|
+
// m/0
|
|
86
|
+
const xpub =
|
|
87
|
+
"xpub6ByHsPNSQXTWZ7PLESMY2FufyYWtLXagSUpMQq7Un96SiThZH2iJB1X7pwviH1WtKVeDP6K8d6xxFzzoaFzF3s8BKCZx8oEDdDkNnp4owAZ";
|
|
88
|
+
const vectors = [
|
|
89
|
+
// M/44'/145'/0'/0/0
|
|
90
|
+
"bitcoincash:qqyx49mu0kkn9ftfj6hje6g2wfer34yfnq5tahq3q6",
|
|
91
|
+
// M/44'/145'/0'/0/1
|
|
92
|
+
"bitcoincash:qp8sfdhgjlq68hlzka9lcsxtcnvuvnd0xqxugfzzc5",
|
|
93
|
+
// M/44'/145'/0'/0/2
|
|
94
|
+
"bitcoincash:qqkuy34ntrye9a2h4xpdstcu4aq5wfrwscjtaphenr",
|
|
95
|
+
];
|
|
96
|
+
|
|
97
|
+
const cashaddrs = await getAddrsByXpubKey(xpub, "0/0", 3);
|
|
98
|
+
expect(cashaddrs).toStrictEqual(vectors);
|
|
99
|
+
});
|
|
100
|
+
test("Should derive list of change cashaddrs from M/44'/145'/0' given xpub, path and limit", async () => {
|
|
101
|
+
// abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about
|
|
102
|
+
// m/0
|
|
103
|
+
const xpub =
|
|
104
|
+
"xpub6ByHsPNSQXTWZ7PLESMY2FufyYWtLXagSUpMQq7Un96SiThZH2iJB1X7pwviH1WtKVeDP6K8d6xxFzzoaFzF3s8BKCZx8oEDdDkNnp4owAZ";
|
|
105
|
+
const vectors = [
|
|
106
|
+
// M/44'/145'/0'/1/0
|
|
107
|
+
"bitcoincash:qr8aeharupyrmhfu0d4tdmsnc5y8cfk47y6qrsjsrx",
|
|
108
|
+
// M/44'/145'/0'/1/1
|
|
109
|
+
"bitcoincash:qr88m3rp5nd5aerz5rh9lzly9u5pevykagwscmjk0c",
|
|
110
|
+
// M/44'/145'/0'/1/2
|
|
111
|
+
"bitcoincash:qp57cex47jtyhedphe2c63gpzsx3zs0ryvejxly47d",
|
|
112
|
+
];
|
|
113
|
+
const cashaddrs = await getAddrsByXpubKey(xpub, "1/0", 3);
|
|
114
|
+
expect(cashaddrs).toStrictEqual(vectors);
|
|
115
|
+
});
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import {
|
|
2
|
+
deriveHdPublicNodeChild,
|
|
3
|
+
decodeHdPublicKey,
|
|
4
|
+
encodeHdPublicKey,
|
|
5
|
+
encodeCashAddress,
|
|
6
|
+
instantiateBIP32Crypto,
|
|
7
|
+
deriveHdPath,
|
|
8
|
+
HdPublicNode,
|
|
9
|
+
HdKeyNetwork,
|
|
10
|
+
binToHex,
|
|
11
|
+
} from "@bitauth/libauth";
|
|
12
|
+
import path from "path";
|
|
13
|
+
|
|
14
|
+
import { hash160 } from "./hash160";
|
|
15
|
+
|
|
16
|
+
export async function getAddrsByXpubKey(
|
|
17
|
+
xpub: string,
|
|
18
|
+
path: string,
|
|
19
|
+
count: number
|
|
20
|
+
) {
|
|
21
|
+
let pathComponents = path.split("/");
|
|
22
|
+
let rootStr = pathComponents.shift()!;
|
|
23
|
+
let root: number;
|
|
24
|
+
if (rootStr === "M" || rootStr === "m") {
|
|
25
|
+
rootStr = pathComponents.shift()!;
|
|
26
|
+
}
|
|
27
|
+
root = parseInt(rootStr);
|
|
28
|
+
let result: any = [];
|
|
29
|
+
|
|
30
|
+
const start = parseInt(pathComponents.pop()!);
|
|
31
|
+
const end = start + count;
|
|
32
|
+
for (let curr = start; curr < end; curr++) {
|
|
33
|
+
let childPath = ["M", root, ...pathComponents, curr].join("/");
|
|
34
|
+
result.push(derivePublicNodeCashaddr(xpub, root, childPath));
|
|
35
|
+
}
|
|
36
|
+
return await Promise.all(result).then((result) => {
|
|
37
|
+
return result;
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export async function getAddrsByXpubKeyObject(obj) {
|
|
42
|
+
return await getAddrsByXpubKey(obj.xpubkey, obj.path, obj.count);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export async function derivePublicNodeCashaddr(
|
|
46
|
+
xpub,
|
|
47
|
+
index: number,
|
|
48
|
+
path?: string
|
|
49
|
+
) {
|
|
50
|
+
const crypto = await instantiateBIP32Crypto();
|
|
51
|
+
const publicParent = await decodeHdPublicKey(crypto, xpub);
|
|
52
|
+
|
|
53
|
+
if (typeof publicParent === "string") {
|
|
54
|
+
throw new Error(publicParent);
|
|
55
|
+
}
|
|
56
|
+
let prefix = publicParent.network === "mainnet" ? "bitcoincash" : "bchtest";
|
|
57
|
+
|
|
58
|
+
let node = await deriveHdPublicNodeChild(crypto, publicParent.node, index);
|
|
59
|
+
if (typeof node === "string") {
|
|
60
|
+
throw new Error(node);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
let cashaddr;
|
|
64
|
+
if (typeof path === "string") {
|
|
65
|
+
if (path[0] !== "M") {
|
|
66
|
+
throw Error("use M for public path derivation");
|
|
67
|
+
}
|
|
68
|
+
let childNode = deriveHdPath(crypto, publicParent.node, path);
|
|
69
|
+
if (typeof childNode === "string") {
|
|
70
|
+
throw new Error(childNode);
|
|
71
|
+
} else {
|
|
72
|
+
let childPkh = await hash160(childNode.publicKey);
|
|
73
|
+
cashaddr = encodeCashAddress(prefix, 0, childPkh);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return cashaddr;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export async function getXpubKeyInfo(hdPublicKey) {
|
|
80
|
+
const crypto = await instantiateBIP32Crypto();
|
|
81
|
+
let node = decodeHdPublicKey(crypto, hdPublicKey);
|
|
82
|
+
if (typeof node === "string") {
|
|
83
|
+
throw new Error(node);
|
|
84
|
+
}
|
|
85
|
+
return {
|
|
86
|
+
version: node.network,
|
|
87
|
+
depth: node.node.depth,
|
|
88
|
+
parentFingerprint: binToHex(node.node.parentFingerprint),
|
|
89
|
+
childNumber: node.node.childIndex,
|
|
90
|
+
chain: binToHex(node.node.chainCode),
|
|
91
|
+
data: binToHex(node.node.publicKey),
|
|
92
|
+
fingerprint: binToHex((await hash160(node.node.publicKey)).slice(0, 4)),
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export async function getXpubKeyInfoObject(obj) {
|
|
97
|
+
return await getXpubKeyInfo(obj.xpubkey);
|
|
98
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import {
|
|
2
|
+
deriveHdPrivateNodeFromSeed,
|
|
3
|
+
deriveHdPath,
|
|
4
|
+
deriveHdPublicNode,
|
|
5
|
+
encodeHdPublicKey,
|
|
6
|
+
HdKeyNetwork,
|
|
7
|
+
instantiateBIP32Crypto,
|
|
8
|
+
hexToBin,
|
|
9
|
+
} from "@bitauth/libauth";
|
|
10
|
+
|
|
11
|
+
export async function getXPubKey(
|
|
12
|
+
seed: Uint8Array | string,
|
|
13
|
+
derivationPath: string,
|
|
14
|
+
network: string
|
|
15
|
+
) {
|
|
16
|
+
if (typeof seed === "string") {
|
|
17
|
+
seed = hexToBin(seed);
|
|
18
|
+
}
|
|
19
|
+
const crypto = await instantiateBIP32Crypto();
|
|
20
|
+
let hdNode = deriveHdPrivateNodeFromSeed(crypto, seed);
|
|
21
|
+
if (!hdNode.valid) {
|
|
22
|
+
throw Error("Invalid private key derived from mnemonic seed");
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
let node = deriveHdPath(crypto, hdNode, derivationPath);
|
|
26
|
+
if (typeof node === "string") {
|
|
27
|
+
throw node;
|
|
28
|
+
}
|
|
29
|
+
let parentPublicNode = deriveHdPublicNode(crypto, node);
|
|
30
|
+
|
|
31
|
+
let xPubKey = encodeHdPublicKey(crypto, {
|
|
32
|
+
network: network as HdKeyNetwork,
|
|
33
|
+
node: parentPublicNode,
|
|
34
|
+
});
|
|
35
|
+
return xPubKey;
|
|
36
|
+
}
|
package/src/util/index.ts
CHANGED
|
@@ -1,16 +1,23 @@
|
|
|
1
1
|
export { amountInSatoshi } from "./amountInSatoshi";
|
|
2
2
|
export { asSendRequestObject } from "./asSendRequestObject";
|
|
3
|
-
export {
|
|
3
|
+
export { atob, btoa } from "./base64";
|
|
4
4
|
export { convert, convertObject } from "./convert";
|
|
5
5
|
export { delay } from "./delay";
|
|
6
|
+
export { derivedNetwork } from "./deriveNetwork";
|
|
7
|
+
export { derivePublicKeyHash } from "./derivePublicKeyHash";
|
|
8
|
+
export {
|
|
9
|
+
getAddrsByXpubKey,
|
|
10
|
+
getAddrsByXpubKeyObject,
|
|
11
|
+
getXpubKeyInfo,
|
|
12
|
+
getXpubKeyInfoObject,
|
|
13
|
+
} from "../util/getAddrsByXpubKey";
|
|
6
14
|
export { getRuntimePlatform, RuntimePlatform } from "./getRuntimePlatform";
|
|
7
15
|
export { getUsdRate } from "./getUsdRate";
|
|
8
16
|
export { ExchangeRate } from "../rate/ExchangeRate";
|
|
9
|
-
export { derivedNetwork } from "./deriveNetwork";
|
|
10
|
-
export { derivePublicKeyHash } from "./derivePublicKeyHash";
|
|
11
17
|
export { sanitizeAddress } from "./sanitizeAddress";
|
|
12
18
|
export { sanitizeUnit } from "./sanitizeUnit";
|
|
13
19
|
export { getRandomInt } from "./randomInt";
|
|
20
|
+
export { getXPubKey } from "../util/getXPubKey";
|
|
14
21
|
import * as randomValues from "./randomValues";
|
|
15
22
|
export { randomValues };
|
|
16
23
|
export { sumUtxoValue } from "./sumUtxoValue";
|
package/src/wallet/Base.ts
CHANGED
|
@@ -14,6 +14,8 @@ import { WalletTypeEnum } from "./enum";
|
|
|
14
14
|
export class BaseWallet implements WalletI {
|
|
15
15
|
provider?: any;
|
|
16
16
|
derivationPath: string = "m/44'/0'/0'/0/0";
|
|
17
|
+
parentDerivationPath: string = "m/44'/0'/0'";
|
|
18
|
+
parentXPubKey?: string;
|
|
17
19
|
mnemonic?: string;
|
|
18
20
|
address?: string;
|
|
19
21
|
privateKey?: any;
|
|
@@ -69,6 +71,7 @@ export class BaseWallet implements WalletI {
|
|
|
69
71
|
return {
|
|
70
72
|
seed: this.mnemonic,
|
|
71
73
|
derivationPath: this.derivationPath,
|
|
74
|
+
parentDerivationPath: this.parentDerivationPath,
|
|
72
75
|
};
|
|
73
76
|
}
|
|
74
77
|
//#endregion Accessors
|
|
@@ -182,7 +185,7 @@ export class BaseWallet implements WalletI {
|
|
|
182
185
|
/**
|
|
183
186
|
* replaceNamed - replace (recover) named wallet with a new walletId
|
|
184
187
|
*
|
|
185
|
-
* If wallet with a provided name does not exist yet, it will be
|
|
188
|
+
* If wallet with a provided name does not exist yet, it will be created with a `walletId` supplied
|
|
186
189
|
* If wallet exists it will be overwritten without exception
|
|
187
190
|
*
|
|
188
191
|
* @param name user friendly wallet alias
|
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,
|
|
@@ -311,7 +483,6 @@ describe(`Watch only Wallets`, () => {
|
|
|
311
483
|
let aliceBalance = await alice.send([
|
|
312
484
|
{ cashaddr: alice.cashaddr!, value: 526, unit: "sat" },
|
|
313
485
|
]);
|
|
314
|
-
expect(aliceBalance.explorerUrl!).toContain("explorer.bitcoin.com");
|
|
315
486
|
expect(aliceBalance.balance!.sat!).toBeGreaterThan(5000);
|
|
316
487
|
}
|
|
317
488
|
});
|
|
@@ -329,6 +500,24 @@ describe(`Watch only Wallets`, () => {
|
|
|
329
500
|
expect(aliceBalance.sat).toBeGreaterThan(2000);
|
|
330
501
|
}
|
|
331
502
|
});
|
|
503
|
+
|
|
504
|
+
test("Should get last transaction", async () => {
|
|
505
|
+
const aliceWif = `wif:regtest:${process.env.PRIVATE_WIF!}`;
|
|
506
|
+
const aliceWallet = await RegTestWallet.fromId(aliceWif);
|
|
507
|
+
const bobWallet = await RegTestWallet.newRandom();
|
|
508
|
+
|
|
509
|
+
expect(await bobWallet.getLastTransaction()).toBeNull();
|
|
510
|
+
|
|
511
|
+
await aliceWallet.send([
|
|
512
|
+
{
|
|
513
|
+
cashaddr: bobWallet.cashaddr!,
|
|
514
|
+
value: 2000,
|
|
515
|
+
unit: "satoshis",
|
|
516
|
+
},
|
|
517
|
+
]);
|
|
518
|
+
|
|
519
|
+
expect(await bobWallet.getLastTransaction()).not.toBeNull();
|
|
520
|
+
});
|
|
332
521
|
});
|
|
333
522
|
describe(`Wallet subscriptions`, () => {
|
|
334
523
|
test("Should wait for transaction", async () => {
|
|
@@ -881,4 +1070,28 @@ describe(`Wallet extrema behavior regression testing`, () => {
|
|
|
881
1070
|
0x6a, 0x4c, 0x00,
|
|
882
1071
|
]);
|
|
883
1072
|
});
|
|
1073
|
+
|
|
1074
|
+
test("Test slpSemiAware", async () => {
|
|
1075
|
+
const alice = await RegTestWallet.fromId(process.env.ALICE_ID!);
|
|
1076
|
+
const bob = await RegTestWallet.newRandom();
|
|
1077
|
+
await alice.send([
|
|
1078
|
+
{ cashaddr: bob.getDepositAddress(), unit: UnitEnum.SAT, value: 546 },
|
|
1079
|
+
{ cashaddr: bob.getDepositAddress(), unit: UnitEnum.SAT, value: 1000 },
|
|
1080
|
+
]);
|
|
1081
|
+
expect(await bob.getBalance("sat")).toBe(1546);
|
|
1082
|
+
bob.slpSemiAware();
|
|
1083
|
+
expect(await bob.getBalance("sat")).toBe(1000);
|
|
1084
|
+
|
|
1085
|
+
expect(
|
|
1086
|
+
(await bob.getMaxAmountToSend({ options: { slpSemiAware: true } })).sat
|
|
1087
|
+
).toBe(780);
|
|
1088
|
+
await bob.sendMax(alice.getDepositAddress());
|
|
1089
|
+
expect(await bob.getBalance("sat")).toBe(0);
|
|
1090
|
+
|
|
1091
|
+
bob.slpSemiAware(false);
|
|
1092
|
+
expect(await bob.getBalance("sat")).toBe(546);
|
|
1093
|
+
expect(
|
|
1094
|
+
(await bob.getMaxAmountToSend({ options: { slpSemiAware: false } })).sat
|
|
1095
|
+
).toBeLessThanOrEqual(546);
|
|
1096
|
+
});
|
|
884
1097
|
});
|