mainnet-js 2.4.3 → 2.6.0
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/{mainnet-2.4.3.js → mainnet-2.6.0.js} +533 -553
- package/dist/module/cli.js.map +1 -1
- package/dist/module/config.js +9 -9
- package/dist/module/config.js.map +1 -1
- package/dist/module/db/ExchangeRateProvider.js.map +1 -1
- package/dist/module/enum.d.ts +1 -1
- package/dist/module/enum.d.ts.map +1 -1
- package/dist/module/history/electrumTransformer.d.ts +5 -5
- package/dist/module/history/electrumTransformer.d.ts.map +1 -1
- package/dist/module/history/electrumTransformer.js +9 -3
- package/dist/module/history/electrumTransformer.js.map +1 -1
- package/dist/module/interface.d.ts +2 -2
- package/dist/module/interface.d.ts.map +1 -1
- package/dist/module/message/signed.d.ts.map +1 -1
- package/dist/module/message/signed.js +5 -1
- package/dist/module/message/signed.js.map +1 -1
- package/dist/module/mine/mine.js.map +1 -1
- package/dist/module/network/Connection.js.map +1 -1
- package/dist/module/network/ElectrumNetworkProvider.d.ts.map +1 -1
- package/dist/module/network/ElectrumNetworkProvider.js +2 -2
- package/dist/module/network/ElectrumNetworkProvider.js.map +1 -1
- package/dist/module/network/configuration.js +5 -5
- package/dist/module/network/configuration.js.map +1 -1
- package/dist/module/network/default.js.map +1 -1
- package/dist/module/network/getRelayFeeCache.js.map +1 -1
- package/dist/module/network/util.js.map +1 -1
- package/dist/module/rate/ExchangeRate.js.map +1 -1
- package/dist/module/test/expect.d.ts.map +1 -1
- package/dist/module/test/expect.js.map +1 -1
- package/dist/module/test/fetch.d.ts.map +1 -1
- package/dist/module/test/fetch.js +3 -0
- package/dist/module/test/fetch.js.map +1 -1
- package/dist/module/transaction/Wif.d.ts +1 -1
- package/dist/module/transaction/Wif.d.ts.map +1 -1
- package/dist/module/transaction/Wif.js +1 -1
- package/dist/module/transaction/Wif.js.map +1 -1
- package/dist/module/transaction/allocateFee.js.map +1 -1
- package/dist/module/util/amountInSatoshi.js.map +1 -1
- package/dist/module/util/asSendRequestObject.js +4 -4
- package/dist/module/util/asSendRequestObject.js.map +1 -1
- package/dist/module/util/balanceObjectFromSatoshi.js.map +1 -1
- package/dist/module/util/base64.js.map +1 -1
- package/dist/module/util/browserNotSupported.js.map +1 -1
- package/dist/module/util/checkUtxos.js.map +1 -1
- package/dist/module/util/checkWifNetwork.js.map +1 -1
- package/dist/module/util/deriveCashaddr.d.ts.map +1 -1
- package/dist/module/util/deriveCashaddr.js +20 -4
- package/dist/module/util/deriveCashaddr.js.map +1 -1
- package/dist/module/util/deriveNetwork.d.ts +1 -1
- package/dist/module/util/deriveNetwork.d.ts.map +1 -1
- package/dist/module/util/deriveNetwork.js.map +1 -1
- package/dist/module/util/derivePublicKeyHash.js.map +1 -1
- package/dist/module/util/eventsource.js.map +1 -1
- package/dist/module/util/getAddrsByXpubKey.d.ts +9 -1
- package/dist/module/util/getAddrsByXpubKey.d.ts.map +1 -1
- package/dist/module/util/getAddrsByXpubKey.js +23 -24
- package/dist/module/util/getAddrsByXpubKey.js.map +1 -1
- package/dist/module/util/getRuntimePlatform.js.map +1 -1
- package/dist/module/util/getXPubKey.d.ts.map +1 -1
- package/dist/module/util/getXPubKey.js +7 -5
- package/dist/module/util/getXPubKey.js.map +1 -1
- package/dist/module/util/header.d.ts.map +1 -1
- package/dist/module/util/header.js +8 -7
- package/dist/module/util/header.js.map +1 -1
- package/dist/module/util/randomBytes.d.ts +0 -1
- package/dist/module/util/randomBytes.d.ts.map +1 -1
- package/dist/module/util/randomBytes.js.map +1 -1
- package/dist/module/util/sanitizeAddress.js.map +1 -1
- package/dist/module/util/sanitizeUnit.js.map +1 -1
- package/dist/module/util/satoshiToAmount.js.map +1 -1
- package/dist/module/util/sumSendRequestAmounts.js.map +1 -1
- package/dist/module/util/sumUtxoValue.js.map +1 -1
- package/dist/module/wallet/Base.js +18 -18
- package/dist/module/wallet/Base.js.map +1 -1
- package/dist/module/wallet/Bcmr.d.ts +1 -1
- package/dist/module/wallet/Bcmr.d.ts.map +1 -1
- package/dist/module/wallet/Bcmr.js +2 -2
- package/dist/module/wallet/Bcmr.js.map +1 -1
- package/dist/module/wallet/Util.d.ts.map +1 -1
- package/dist/module/wallet/Util.js +13 -5
- package/dist/module/wallet/Util.js.map +1 -1
- package/dist/module/wallet/Wif.d.ts.map +1 -1
- package/dist/module/wallet/Wif.js +80 -73
- package/dist/module/wallet/Wif.js.map +1 -1
- package/dist/module/wallet/bcmr-v2.schema.d.ts +14 -14
- package/dist/module/wallet/bcmr-v2.schema.d.ts.map +1 -1
- package/dist/module/wallet/createWallet.js.map +1 -1
- package/dist/module/wallet/interface.d.ts +1 -1
- package/dist/module/wallet/interface.d.ts.map +1 -1
- package/dist/module/wallet/model.d.ts +8 -18
- package/dist/module/wallet/model.d.ts.map +1 -1
- package/dist/module/wallet/model.js +6 -24
- package/dist/module/wallet/model.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/polyfill/support/types.js +0 -4
- package/src/history/electrumTransformer.test.ts +1 -1
- package/src/history/electrumTransformer.ts +13 -8
- package/src/message/signed.ts +5 -4
- package/src/rate/ExchangeRate.test.ts +15 -17
- package/src/test/fetch.ts +4 -0
- package/src/util/asSendRequestObject.ts +6 -6
- package/src/util/deriveCashaddr.ts +21 -16
- package/src/util/getAddrsByXpubKey.test.ts +4 -4
- package/src/util/getAddrsByXpubKey.ts +23 -30
- package/src/util/getXPubKey.ts +13 -8
- package/src/util/header.ts +8 -7
- package/src/wallet/Util.ts +17 -4
- package/src/wallet/Wif.bip39.test.ts +1 -1
- package/src/wallet/Wif.test.ts +9 -6
- package/src/wallet/Wif.ts +51 -46
- package/src/wallet/model.ts +12 -30
- package/webpack.config.cjs +0 -3
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
decodeCashAddress,
|
|
10
10
|
cashAddressTypeBitsToType,
|
|
11
11
|
decodeCashAddressVersionByte,
|
|
12
|
+
assertSuccess,
|
|
12
13
|
} from "@bitauth/libauth";
|
|
13
14
|
|
|
14
15
|
import { hash160 } from "./hash160.js";
|
|
@@ -31,7 +32,11 @@ export function deriveCashaddr(
|
|
|
31
32
|
throw new Error(publicKey);
|
|
32
33
|
}
|
|
33
34
|
let pkh = hash160(publicKey);
|
|
34
|
-
return encodeCashAddress(
|
|
35
|
+
return encodeCashAddress({
|
|
36
|
+
prefix: networkPrefix,
|
|
37
|
+
type: CashAddressType.p2pkh,
|
|
38
|
+
payload: pkh,
|
|
39
|
+
}).address;
|
|
35
40
|
}
|
|
36
41
|
|
|
37
42
|
export function deriveTokenaddr(
|
|
@@ -63,11 +68,11 @@ export function deriveTokenaddr(
|
|
|
63
68
|
throw new Error("Unsupported type of key");
|
|
64
69
|
}
|
|
65
70
|
|
|
66
|
-
return encodeCashAddress(
|
|
67
|
-
networkPrefix,
|
|
68
|
-
CashAddressType.p2pkhWithTokens,
|
|
69
|
-
publicKeyHash
|
|
70
|
-
);
|
|
71
|
+
return encodeCashAddress({
|
|
72
|
+
prefix: networkPrefix,
|
|
73
|
+
type: CashAddressType.p2pkhWithTokens,
|
|
74
|
+
payload: publicKeyHash,
|
|
75
|
+
}).address;
|
|
71
76
|
}
|
|
72
77
|
|
|
73
78
|
export function toCashaddr(tokenaddr: string): string {
|
|
@@ -87,11 +92,11 @@ export function toCashaddr(tokenaddr: string): string {
|
|
|
87
92
|
|
|
88
93
|
if (typeof result === "string") throw new Error(result);
|
|
89
94
|
|
|
90
|
-
return encodeCashAddress(
|
|
91
|
-
result.prefix as CashAddressNetworkPrefix,
|
|
92
|
-
CashAddressType.p2pkh,
|
|
93
|
-
result.payload
|
|
94
|
-
);
|
|
95
|
+
return encodeCashAddress({
|
|
96
|
+
prefix: result.prefix as CashAddressNetworkPrefix,
|
|
97
|
+
type: CashAddressType.p2pkh,
|
|
98
|
+
payload: result.payload,
|
|
99
|
+
}).address;
|
|
95
100
|
}
|
|
96
101
|
|
|
97
102
|
export function toTokenaddr(cashaddr: string): string {
|
|
@@ -111,11 +116,11 @@ export function toTokenaddr(cashaddr: string): string {
|
|
|
111
116
|
|
|
112
117
|
if (typeof result === "string") throw new Error(result);
|
|
113
118
|
|
|
114
|
-
return encodeCashAddress(
|
|
115
|
-
result.prefix as CashAddressNetworkPrefix,
|
|
116
|
-
CashAddressType.p2pkhWithTokens,
|
|
117
|
-
result.payload
|
|
118
|
-
);
|
|
119
|
+
return encodeCashAddress({
|
|
120
|
+
prefix: result.prefix as CashAddressNetworkPrefix,
|
|
121
|
+
type: CashAddressType.p2pkhWithTokens,
|
|
122
|
+
payload: result.payload,
|
|
123
|
+
}).address;
|
|
119
124
|
}
|
|
120
125
|
|
|
121
126
|
export function isTokenaddr(address: string): boolean {
|
|
@@ -23,7 +23,7 @@ test("Should decode xpubInfo", async () => {
|
|
|
23
23
|
|
|
24
24
|
test("Should derive cashaddr given xpub and path", async () => {
|
|
25
25
|
// abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about
|
|
26
|
-
// m/0
|
|
26
|
+
// m/44'/145'/0'/0/
|
|
27
27
|
const xpub =
|
|
28
28
|
"xpub6F2iaK2JUPcgrZ6RTGH6t8VybLPu1XzfrHsDsaKvK6NfULznU6i6aw6ZoefDW2DpNruSLw73RwQg46qvpqB3eryeJJ2tkFCF4Z6gbr8Pjja";
|
|
29
29
|
const vectors = [
|
|
@@ -37,7 +37,7 @@ test("Should derive cashaddr given xpub and path", async () => {
|
|
|
37
37
|
|
|
38
38
|
for (let i = 0; i < vectors.length; i++) {
|
|
39
39
|
// M/44'/145'/0'/0/
|
|
40
|
-
const publicNode =
|
|
40
|
+
const publicNode = derivePublicNodeCashaddr(xpub, `${i}`);
|
|
41
41
|
expect(publicNode).toBe(vectors[i]);
|
|
42
42
|
}
|
|
43
43
|
});
|
|
@@ -82,7 +82,7 @@ test("Should derive list of change cashaddrs from m/44'/0'/0' given xpub path, &
|
|
|
82
82
|
|
|
83
83
|
test("Should derive list of cashaddrs from M/44'/145'/0' given xpub, path and limit", async () => {
|
|
84
84
|
// abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about
|
|
85
|
-
// m/0
|
|
85
|
+
// m/44'/145'/0'
|
|
86
86
|
const xpub =
|
|
87
87
|
"xpub6ByHsPNSQXTWZ7PLESMY2FufyYWtLXagSUpMQq7Un96SiThZH2iJB1X7pwviH1WtKVeDP6K8d6xxFzzoaFzF3s8BKCZx8oEDdDkNnp4owAZ";
|
|
88
88
|
const vectors = [
|
|
@@ -99,7 +99,7 @@ test("Should derive list of cashaddrs from M/44'/145'/0' given xpub, path and li
|
|
|
99
99
|
});
|
|
100
100
|
test("Should derive list of change cashaddrs from M/44'/145'/0' given xpub, path and limit", async () => {
|
|
101
101
|
// abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about
|
|
102
|
-
// m/0
|
|
102
|
+
// m/44'/145'/0'
|
|
103
103
|
const xpub =
|
|
104
104
|
"xpub6ByHsPNSQXTWZ7PLESMY2FufyYWtLXagSUpMQq7Un96SiThZH2iJB1X7pwviH1WtKVeDP6K8d6xxFzzoaFzF3s8BKCZx8oEDdDkNnp4owAZ";
|
|
105
105
|
const vectors = [
|
|
@@ -1,34 +1,35 @@
|
|
|
1
1
|
import {
|
|
2
|
-
deriveHdPublicNodeChild,
|
|
3
2
|
decodeHdPublicKey,
|
|
4
3
|
encodeCashAddress,
|
|
5
|
-
deriveHdPath,
|
|
6
4
|
binToHex,
|
|
7
5
|
CashAddressNetworkPrefix,
|
|
8
6
|
CashAddressType,
|
|
7
|
+
deriveHdPathRelative,
|
|
9
8
|
} from "@bitauth/libauth";
|
|
10
9
|
|
|
11
10
|
import { hash160 } from "./hash160.js";
|
|
12
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Derive cashsaddresses given the `xpub`, relative `path` and count of addresses to derive.
|
|
14
|
+
*
|
|
15
|
+
* @param xpub the parent xpubkey from which to derive child public keys, for example `xpub6ByHsPNSQXTWZ7PLESMY2FufyYWtLXagSUpMQq7Un96SiThZH2iJB1X7pwviH1WtKVeDP6K8d6xxFzzoaFzF3s8BKCZx8oEDdDkNnp4owAZ` at `m/44'/145'/0'`
|
|
16
|
+
* @param path relative path from the parent xpubkey to derive the child public keys, for example "0/0" for receiving addresses or "1/0" for change addresses
|
|
17
|
+
* @param count amount of child public keys to derive
|
|
18
|
+
* @returns array of cashaddresses derived from the xpubkey
|
|
19
|
+
*/
|
|
13
20
|
export function getAddrsByXpubKey(
|
|
14
21
|
xpub: string,
|
|
15
22
|
path: string,
|
|
16
23
|
count: number
|
|
17
24
|
): Array<string> {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
let root: number;
|
|
21
|
-
if (rootStr === "M" || rootStr === "m") {
|
|
22
|
-
rootStr = pathComponents.shift()!;
|
|
23
|
-
}
|
|
24
|
-
root = parseInt(rootStr);
|
|
25
|
-
let result: Array<string> = [];
|
|
25
|
+
const pathComponents = path.split("/");
|
|
26
|
+
const result: Array<string> = [];
|
|
26
27
|
|
|
27
28
|
const start = parseInt(pathComponents.pop()!);
|
|
28
29
|
const end = start + count;
|
|
29
30
|
for (let curr = start; curr < end; curr++) {
|
|
30
|
-
|
|
31
|
-
result.push(derivePublicNodeCashaddr(xpub,
|
|
31
|
+
const childPath = [...pathComponents, curr].join("/");
|
|
32
|
+
result.push(derivePublicNodeCashaddr(xpub, childPath));
|
|
32
33
|
}
|
|
33
34
|
return result;
|
|
34
35
|
}
|
|
@@ -37,43 +38,35 @@ export function getAddrsByXpubKeyObject(obj): Array<string> {
|
|
|
37
38
|
return getAddrsByXpubKey(obj.xpubkey, obj.path, obj.count);
|
|
38
39
|
}
|
|
39
40
|
|
|
40
|
-
export function derivePublicNodeCashaddr(
|
|
41
|
-
xpub,
|
|
42
|
-
index: number,
|
|
43
|
-
path?: string
|
|
44
|
-
): string {
|
|
41
|
+
export function derivePublicNodeCashaddr(xpub: string, path?: string): string {
|
|
45
42
|
const publicParent = decodeHdPublicKey(xpub);
|
|
46
43
|
|
|
47
44
|
if (typeof publicParent === "string") {
|
|
48
45
|
throw new Error(publicParent);
|
|
49
46
|
}
|
|
50
|
-
|
|
47
|
+
const prefix = (
|
|
51
48
|
publicParent.network === "mainnet" ? "bitcoincash" : "bchtest"
|
|
52
49
|
) as CashAddressNetworkPrefix;
|
|
53
50
|
|
|
54
|
-
let node = deriveHdPublicNodeChild(publicParent.node, index);
|
|
55
|
-
if (typeof node === "string") {
|
|
56
|
-
throw new Error(node);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
51
|
let cashaddr;
|
|
60
52
|
if (typeof path === "string") {
|
|
61
|
-
|
|
62
|
-
throw Error("use M for public path derivation");
|
|
63
|
-
}
|
|
64
|
-
let childNode = deriveHdPath(publicParent.node, path);
|
|
53
|
+
const childNode = deriveHdPathRelative(publicParent.node, path);
|
|
65
54
|
if (typeof childNode === "string") {
|
|
66
55
|
throw new Error(childNode);
|
|
67
56
|
} else {
|
|
68
|
-
|
|
69
|
-
cashaddr = encodeCashAddress(
|
|
57
|
+
const childPkh = hash160(childNode.publicKey);
|
|
58
|
+
cashaddr = encodeCashAddress({
|
|
59
|
+
prefix,
|
|
60
|
+
type: CashAddressType.p2pkh,
|
|
61
|
+
payload: childPkh,
|
|
62
|
+
}).address;
|
|
70
63
|
}
|
|
71
64
|
}
|
|
72
65
|
return cashaddr;
|
|
73
66
|
}
|
|
74
67
|
|
|
75
68
|
export function getXpubKeyInfo(hdPublicKey: string) {
|
|
76
|
-
|
|
69
|
+
const node = decodeHdPublicKey(hdPublicKey);
|
|
77
70
|
if (typeof node === "string") {
|
|
78
71
|
throw new Error(node);
|
|
79
72
|
}
|
package/src/util/getXPubKey.ts
CHANGED
|
@@ -15,10 +15,10 @@ export function getXPubKey(
|
|
|
15
15
|
if (typeof seed === "string") {
|
|
16
16
|
seed = hexToBin(seed);
|
|
17
17
|
}
|
|
18
|
-
let hdNode = deriveHdPrivateNodeFromSeed(seed
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}
|
|
18
|
+
let hdNode = deriveHdPrivateNodeFromSeed(seed, {
|
|
19
|
+
assumeValidity: true, // TODO: we should switch to libauth's BIP39 implementation and set this to false
|
|
20
|
+
throwErrors: true,
|
|
21
|
+
});
|
|
22
22
|
|
|
23
23
|
let node = deriveHdPath(hdNode, derivationPath);
|
|
24
24
|
if (typeof node === "string") {
|
|
@@ -26,9 +26,14 @@ export function getXPubKey(
|
|
|
26
26
|
}
|
|
27
27
|
let parentPublicNode = deriveHdPublicNode(node);
|
|
28
28
|
|
|
29
|
-
let xPubKey = encodeHdPublicKey(
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
29
|
+
let xPubKey = encodeHdPublicKey(
|
|
30
|
+
{
|
|
31
|
+
network: network as HdKeyNetwork,
|
|
32
|
+
node: parentPublicNode,
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
throwErrors: true,
|
|
36
|
+
}
|
|
37
|
+
).hdPublicKey;
|
|
33
38
|
return xPubKey;
|
|
34
39
|
}
|
package/src/util/header.ts
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
|
+
import { assertSuccess, binToHex, hexToBin, readUint32LE } from "@bitauth/libauth";
|
|
1
2
|
import { HeaderI, HexHeaderI } from "../interface";
|
|
2
3
|
|
|
3
4
|
export const decodeHeader = (hexHeader: HexHeaderI): HeaderI => {
|
|
4
5
|
const result = {} as HeaderI;
|
|
5
6
|
|
|
6
|
-
const header =
|
|
7
|
-
result.version = header
|
|
8
|
-
result.previousBlockHash = header.
|
|
9
|
-
result.merkleRoot = header.
|
|
10
|
-
result.timestamp = header
|
|
11
|
-
result.bits = header
|
|
12
|
-
result.nonce = header
|
|
7
|
+
const header = hexToBin(hexHeader.hex);
|
|
8
|
+
result.version = assertSuccess(readUint32LE({bin: header, index: 0})).result;
|
|
9
|
+
result.previousBlockHash = binToHex(header.slice(4, 36).reverse());
|
|
10
|
+
result.merkleRoot = binToHex(header.slice(36, 68).reverse());
|
|
11
|
+
result.timestamp = assertSuccess(readUint32LE({bin: header, index: 68})).result;
|
|
12
|
+
result.bits = assertSuccess(readUint32LE({bin: header, index: 72})).result;
|
|
13
|
+
result.nonce = assertSuccess(readUint32LE({bin: header, index: 76})).result;
|
|
13
14
|
result.height = hexHeader.height;
|
|
14
15
|
|
|
15
16
|
return result;
|
package/src/wallet/Util.ts
CHANGED
|
@@ -15,6 +15,10 @@ import {
|
|
|
15
15
|
hexToBin,
|
|
16
16
|
lockingBytecodeToCashAddress,
|
|
17
17
|
Transaction as LibAuthTransaction,
|
|
18
|
+
assertSuccess,
|
|
19
|
+
isPayToPublicKey,
|
|
20
|
+
publicKeyToP2pkhCashAddress,
|
|
21
|
+
lockingBytecodeToAddressContents,
|
|
18
22
|
} from "@bitauth/libauth";
|
|
19
23
|
import {
|
|
20
24
|
ElectrumRawTransaction,
|
|
@@ -131,10 +135,19 @@ export class Util {
|
|
|
131
135
|
n: index,
|
|
132
136
|
scriptPubKey: {
|
|
133
137
|
addresses: [
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
+
isPayToPublicKey(output.lockingBytecode)
|
|
139
|
+
? publicKeyToP2pkhCashAddress({
|
|
140
|
+
publicKey: lockingBytecodeToAddressContents(
|
|
141
|
+
output.lockingBytecode
|
|
142
|
+
).payload,
|
|
143
|
+
prefix: this.wallet.networkPrefix,
|
|
144
|
+
})
|
|
145
|
+
: assertSuccess(
|
|
146
|
+
lockingBytecodeToCashAddress({
|
|
147
|
+
bytecode: output.lockingBytecode,
|
|
148
|
+
prefix: this.wallet.networkPrefix,
|
|
149
|
+
})
|
|
150
|
+
).address,
|
|
138
151
|
],
|
|
139
152
|
hex: binToHex(output.lockingBytecode),
|
|
140
153
|
} as ElectrumRawTransactionVoutScriptPubKey,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { mnemonicToSeedSync } from "@scure/bip39";
|
|
2
2
|
import { hexToBin } from "@bitauth/libauth";
|
|
3
|
-
import { RegTestWallet } from "./Wif";
|
|
3
|
+
import { RegTestWallet, Wallet } from "./Wif";
|
|
4
4
|
|
|
5
5
|
describe(`Test bip39 edge cases`, () => {
|
|
6
6
|
test("Should match match the abandon seed", async () => {
|
package/src/wallet/Wif.test.ts
CHANGED
|
@@ -1025,7 +1025,7 @@ describe(`Wallet extrema behavior regression testing`, () => {
|
|
|
1025
1025
|
|
|
1026
1026
|
result = await wallet.send([
|
|
1027
1027
|
[wallet.cashaddr!, 546, "sats"],
|
|
1028
|
-
["OP_RETURN",
|
|
1028
|
+
["OP_RETURN", Uint8Array.from([0x00, 0x01, 0x02])],
|
|
1029
1029
|
]);
|
|
1030
1030
|
transaction = (await wallet.provider!.getRawTransactionObject(
|
|
1031
1031
|
result.txId!
|
|
@@ -1037,7 +1037,7 @@ describe(`Wallet extrema behavior regression testing`, () => {
|
|
|
1037
1037
|
|
|
1038
1038
|
result = await wallet.send([
|
|
1039
1039
|
OpReturnData.from(""),
|
|
1040
|
-
OpReturnData.from(
|
|
1040
|
+
OpReturnData.from(Uint8Array.from([])),
|
|
1041
1041
|
]);
|
|
1042
1042
|
transaction = (await wallet.provider!.getRawTransactionObject(
|
|
1043
1043
|
result.txId!
|
|
@@ -1113,11 +1113,14 @@ describe(`Wallet extrema behavior regression testing`, () => {
|
|
|
1113
1113
|
binsAreEqual(decoded.inputs[0].unlockingBytecode, Uint8Array.from([]))
|
|
1114
1114
|
).toBe(true);
|
|
1115
1115
|
const toCashAddress = (bytecode) => {
|
|
1116
|
-
const cashaddr = lockingBytecodeToCashAddress(
|
|
1117
|
-
|
|
1118
|
-
|
|
1116
|
+
const cashaddr = lockingBytecodeToCashAddress({
|
|
1117
|
+
bytecode: bytecode,
|
|
1118
|
+
prefix: "bchreg",
|
|
1119
|
+
});
|
|
1120
|
+
if (typeof cashaddr === "string") {
|
|
1121
|
+
throw Error(cashaddr);
|
|
1119
1122
|
}
|
|
1120
|
-
return cashaddr;
|
|
1123
|
+
return cashaddr.address;
|
|
1121
1124
|
};
|
|
1122
1125
|
expect(toCashAddress(decoded.outputs[0].lockingBytecode)).toBe(
|
|
1123
1126
|
bobWallet.cashaddr
|
package/src/wallet/Wif.ts
CHANGED
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
decodeCashAddress,
|
|
5
5
|
encodeHdPublicKey,
|
|
6
6
|
HdKeyNetwork,
|
|
7
|
+
hexToBin,
|
|
7
8
|
secp256k1,
|
|
8
9
|
} from "@bitauth/libauth";
|
|
9
10
|
|
|
@@ -114,6 +115,9 @@ import { TransactionHistoryItem } from "../history/interface.js";
|
|
|
114
115
|
|
|
115
116
|
//#endregion Imports
|
|
116
117
|
|
|
118
|
+
const placeholderPrivateKey =
|
|
119
|
+
"0000000000000000000000000000000000000000000000000000000000000001";
|
|
120
|
+
|
|
117
121
|
/**
|
|
118
122
|
* Class to manage a bitcoin cash wallet.
|
|
119
123
|
*/
|
|
@@ -348,21 +352,17 @@ export class Wallet extends BaseWallet {
|
|
|
348
352
|
this.mnemonic = generateMnemonic(Config.getWordlist());
|
|
349
353
|
if (this.mnemonic.length == 0)
|
|
350
354
|
throw Error("refusing to create wallet from empty mnemonic");
|
|
351
|
-
|
|
355
|
+
const seed = mnemonicToSeedSync(this.mnemonic!);
|
|
352
356
|
checkForEmptySeed(seed);
|
|
353
|
-
|
|
354
|
-
this.parentXPubKey =
|
|
355
|
-
seed,
|
|
356
|
-
this.parentDerivationPath,
|
|
357
|
-
network
|
|
358
|
-
);
|
|
357
|
+
const network = this.isTestnet ? "testnet" : "mainnet";
|
|
358
|
+
this.parentXPubKey = getXPubKey(seed, this.parentDerivationPath, network);
|
|
359
359
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
}
|
|
360
|
+
const hdNode = deriveHdPrivateNodeFromSeed(seed, {
|
|
361
|
+
assumeValidity: true, // TODO: we should switch to libauth's BIP39 implementation and set this to false
|
|
362
|
+
throwErrors: true,
|
|
363
|
+
});
|
|
364
364
|
|
|
365
|
-
|
|
365
|
+
const zerothChild = deriveHdPath(hdNode, this.derivationPath);
|
|
366
366
|
if (typeof zerothChild === "string") {
|
|
367
367
|
throw Error(zerothChild);
|
|
368
368
|
}
|
|
@@ -373,7 +373,7 @@ export class Wallet extends BaseWallet {
|
|
|
373
373
|
}
|
|
374
374
|
|
|
375
375
|
protected fromId = async (walletId: string): Promise<this> => {
|
|
376
|
-
|
|
376
|
+
const [walletType, networkGiven, arg1]: string[] = walletId.split(":");
|
|
377
377
|
|
|
378
378
|
if (this.network != networkGiven) {
|
|
379
379
|
throw Error(`Network prefix ${networkGiven} to a ${this.network} wallet`);
|
|
@@ -408,29 +408,29 @@ export class Wallet extends BaseWallet {
|
|
|
408
408
|
|
|
409
409
|
if (this.mnemonic.length == 0)
|
|
410
410
|
throw Error("refusing to create wallet from empty mnemonic");
|
|
411
|
-
|
|
411
|
+
const seed = mnemonicToSeedSync(this.mnemonic);
|
|
412
412
|
checkForEmptySeed(seed);
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
}
|
|
413
|
+
const hdNode = deriveHdPrivateNodeFromSeed(seed, {
|
|
414
|
+
assumeValidity: true, // TODO: we should switch to libauth's BIP39 implementation and set this to false
|
|
415
|
+
throwErrors: true,
|
|
416
|
+
});
|
|
417
417
|
if (derivationPath) {
|
|
418
418
|
this.derivationPath = derivationPath;
|
|
419
419
|
|
|
420
420
|
// If the derivation path is for the first account child, set the parent derivation path
|
|
421
|
-
|
|
421
|
+
const path = derivationPath.split("/");
|
|
422
422
|
if (path.slice(-2).join("/") == "0/0") {
|
|
423
423
|
this.parentDerivationPath = path.slice(0, -2).join("/");
|
|
424
424
|
}
|
|
425
425
|
}
|
|
426
426
|
|
|
427
|
-
|
|
427
|
+
const zerothChild = deriveHdPath(hdNode, this.derivationPath);
|
|
428
428
|
if (typeof zerothChild === "string") {
|
|
429
429
|
throw Error(zerothChild);
|
|
430
430
|
}
|
|
431
431
|
this.privateKey = zerothChild.privateKey;
|
|
432
432
|
|
|
433
|
-
|
|
433
|
+
const network = this.isTestnet ? "testnet" : "mainnet";
|
|
434
434
|
this.parentXPubKey = await getXPubKey(
|
|
435
435
|
seed,
|
|
436
436
|
this.parentDerivationPath,
|
|
@@ -446,14 +446,14 @@ export class Wallet extends BaseWallet {
|
|
|
446
446
|
public async deriveHdPaths(hdPaths: string[]): Promise<any[]> {
|
|
447
447
|
if (!this.mnemonic)
|
|
448
448
|
throw Error("refusing to create wallet from empty mnemonic");
|
|
449
|
-
|
|
449
|
+
const seed = mnemonicToSeedSync(this.mnemonic!);
|
|
450
450
|
checkForEmptySeed(seed);
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
}
|
|
451
|
+
const hdNode = deriveHdPrivateNodeFromSeed(seed, {
|
|
452
|
+
assumeValidity: true, // TODO: we should switch to libauth's BIP39 implementation and set this to false
|
|
453
|
+
throwErrors: true,
|
|
454
|
+
});
|
|
455
455
|
|
|
456
|
-
|
|
456
|
+
const result: any[] = [];
|
|
457
457
|
|
|
458
458
|
for (const path of hdPaths) {
|
|
459
459
|
if (path === "m") {
|
|
@@ -461,19 +461,24 @@ export class Wallet extends BaseWallet {
|
|
|
461
461
|
"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"
|
|
462
462
|
);
|
|
463
463
|
}
|
|
464
|
-
|
|
464
|
+
const childNode = deriveHdPath(hdNode, path);
|
|
465
465
|
if (typeof childNode === "string") {
|
|
466
466
|
throw Error(childNode);
|
|
467
467
|
}
|
|
468
|
-
|
|
468
|
+
const node = deriveHdPublicNode(childNode);
|
|
469
469
|
if (typeof node === "string") {
|
|
470
470
|
throw Error(node);
|
|
471
471
|
}
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
472
|
+
const xPubKey = encodeHdPublicKey(
|
|
473
|
+
{
|
|
474
|
+
network: this.network as HdKeyNetwork,
|
|
475
|
+
node: node,
|
|
476
|
+
},
|
|
477
|
+
{
|
|
478
|
+
throwErrors: true,
|
|
479
|
+
}
|
|
480
|
+
).hdPublicKey;
|
|
481
|
+
const key = new XPubKey({
|
|
477
482
|
path: path,
|
|
478
483
|
xPubKey: xPubKey,
|
|
479
484
|
});
|
|
@@ -488,7 +493,7 @@ export class Wallet extends BaseWallet {
|
|
|
488
493
|
// Initialize a watch only wallet from a cash addr
|
|
489
494
|
protected async watchOnly(address: string): Promise<this> {
|
|
490
495
|
this.walletType = WalletTypeEnum.Watch;
|
|
491
|
-
|
|
496
|
+
const addressComponents = address.split(":");
|
|
492
497
|
let addressPrefix, addressBase;
|
|
493
498
|
if (addressComponents.length === 1) {
|
|
494
499
|
addressBase = addressComponents.shift() as string;
|
|
@@ -499,7 +504,7 @@ export class Wallet extends BaseWallet {
|
|
|
499
504
|
if (addressPrefix in networkPrefixMap) {
|
|
500
505
|
if (networkPrefixMap[addressPrefix] != this.network) {
|
|
501
506
|
throw Error(
|
|
502
|
-
`a ${addressPrefix} address cannot be watched from a ${this.network}
|
|
507
|
+
`a ${addressPrefix} address cannot be watched from a ${this.network} Walconst`
|
|
503
508
|
);
|
|
504
509
|
}
|
|
505
510
|
}
|
|
@@ -508,7 +513,7 @@ export class Wallet extends BaseWallet {
|
|
|
508
513
|
const prefixedAddress = `${addressPrefix}:${addressBase}`;
|
|
509
514
|
|
|
510
515
|
// check if a token aware address was provided
|
|
511
|
-
|
|
516
|
+
const addressData = decodeCashAddress(prefixedAddress);
|
|
512
517
|
if (typeof addressData === "string") throw addressData;
|
|
513
518
|
|
|
514
519
|
this.publicKeyHash = addressData.payload;
|
|
@@ -521,11 +526,11 @@ export class Wallet extends BaseWallet {
|
|
|
521
526
|
if (nonTokenAwareType == CashAddressType.p2pkh)
|
|
522
527
|
this.publicKeyHash = addressData.payload;
|
|
523
528
|
|
|
524
|
-
this.cashaddr = encodeCashAddress(
|
|
525
|
-
addressData.prefix as CashAddressNetworkPrefix,
|
|
526
|
-
nonTokenAwareType,
|
|
527
|
-
addressData.payload
|
|
528
|
-
);
|
|
529
|
+
this.cashaddr = encodeCashAddress({
|
|
530
|
+
prefix: addressData.prefix as CashAddressNetworkPrefix,
|
|
531
|
+
type: nonTokenAwareType,
|
|
532
|
+
payload: addressData.payload,
|
|
533
|
+
}).address;
|
|
529
534
|
this.address = this.cashaddr;
|
|
530
535
|
this.tokenaddr = deriveTokenaddr(addressData.payload, this.networkPrefix);
|
|
531
536
|
|
|
@@ -880,7 +885,7 @@ export class Wallet extends BaseWallet {
|
|
|
880
885
|
const fee = await getFeeAmountSimple({
|
|
881
886
|
utxos: fundingUtxos,
|
|
882
887
|
sendRequests: sendRequests,
|
|
883
|
-
privateKey: this.privateKey ??
|
|
888
|
+
privateKey: this.privateKey ?? hexToBin(placeholderPrivateKey),
|
|
884
889
|
sourceAddress: this.cashaddr!,
|
|
885
890
|
relayFeePerByteInSatoshi: relayFeePerByteInSatoshi,
|
|
886
891
|
feePaidBy: feePaidBy,
|
|
@@ -1196,7 +1201,7 @@ export class Wallet extends BaseWallet {
|
|
|
1196
1201
|
const feeEstimate = await getFeeAmountSimple({
|
|
1197
1202
|
utxos: utxos,
|
|
1198
1203
|
sendRequests: sendRequests,
|
|
1199
|
-
privateKey: this.privateKey ??
|
|
1204
|
+
privateKey: this.privateKey ?? hexToBin(placeholderPrivateKey),
|
|
1200
1205
|
sourceAddress: this.cashaddr!,
|
|
1201
1206
|
relayFeePerByteInSatoshi: relayFeePerByteInSatoshi,
|
|
1202
1207
|
feePaidBy: feePaidBy,
|
|
@@ -1219,7 +1224,7 @@ export class Wallet extends BaseWallet {
|
|
|
1219
1224
|
const fee = await getFeeAmount({
|
|
1220
1225
|
utxos: fundingUtxos,
|
|
1221
1226
|
sendRequests: sendRequests,
|
|
1222
|
-
privateKey: this.privateKey ??
|
|
1227
|
+
privateKey: this.privateKey ?? hexToBin(placeholderPrivateKey),
|
|
1223
1228
|
sourceAddress: this.cashaddr!,
|
|
1224
1229
|
relayFeePerByteInSatoshi: relayFeePerByteInSatoshi,
|
|
1225
1230
|
feePaidBy: feePaidBy,
|
|
@@ -1228,7 +1233,7 @@ export class Wallet extends BaseWallet {
|
|
|
1228
1233
|
{
|
|
1229
1234
|
inputs: fundingUtxos,
|
|
1230
1235
|
outputs: sendRequests,
|
|
1231
|
-
signingKey: this.privateKey ??
|
|
1236
|
+
signingKey: this.privateKey ?? hexToBin(placeholderPrivateKey),
|
|
1232
1237
|
sourceAddress: this.cashaddr!,
|
|
1233
1238
|
fee,
|
|
1234
1239
|
discardChange,
|
package/src/wallet/model.ts
CHANGED
|
@@ -161,10 +161,10 @@ export class TokenMintRequest {
|
|
|
161
161
|
}
|
|
162
162
|
|
|
163
163
|
export class OpReturnData {
|
|
164
|
-
buffer:
|
|
164
|
+
buffer: Uint8Array;
|
|
165
165
|
|
|
166
|
-
public constructor(buffer:
|
|
167
|
-
this.buffer =
|
|
166
|
+
public constructor(buffer: Uint8Array) {
|
|
167
|
+
this.buffer = Uint8Array.from(buffer);
|
|
168
168
|
}
|
|
169
169
|
|
|
170
170
|
/**
|
|
@@ -174,7 +174,7 @@ export class OpReturnData {
|
|
|
174
174
|
*
|
|
175
175
|
* @returns class instance
|
|
176
176
|
*/
|
|
177
|
-
public static from(data: string |
|
|
177
|
+
public static from(data: string | Uint8Array) {
|
|
178
178
|
return this.fromArray([data]);
|
|
179
179
|
}
|
|
180
180
|
|
|
@@ -189,21 +189,6 @@ export class OpReturnData {
|
|
|
189
189
|
return this.fromArray([string]);
|
|
190
190
|
}
|
|
191
191
|
|
|
192
|
-
/**
|
|
193
|
-
* buffer - Accept OP_RETURN data as a binary buffer.
|
|
194
|
-
* If buffer lacks the OP_RETURN and OP_PUSHDATA opcodes, they will be prepended.
|
|
195
|
-
*
|
|
196
|
-
* @param buffer Data buffer to be assigned to the OP_RETURN outpit
|
|
197
|
-
*
|
|
198
|
-
* @returns class instance
|
|
199
|
-
*/
|
|
200
|
-
public static fromBuffer(buffer: Buffer) {
|
|
201
|
-
if (buffer[0] !== 0x6a) {
|
|
202
|
-
return this.fromArray([buffer]);
|
|
203
|
-
}
|
|
204
|
-
return new this(buffer);
|
|
205
|
-
}
|
|
206
|
-
|
|
207
192
|
/**
|
|
208
193
|
* buffer - Accept OP_RETURN data as a binary buffer.
|
|
209
194
|
* If buffer lacks the OP_RETURN and OP_PUSHDATA opcodes, they will be prepended.
|
|
@@ -216,30 +201,27 @@ export class OpReturnData {
|
|
|
216
201
|
if (uint8Array[0] !== 0x6a) {
|
|
217
202
|
return this.fromArray([uint8Array]);
|
|
218
203
|
}
|
|
219
|
-
return new this(
|
|
204
|
+
return new this(Uint8Array.from(uint8Array));
|
|
220
205
|
}
|
|
221
206
|
|
|
222
207
|
/**
|
|
223
208
|
* fromArray - Accept array of data
|
|
224
209
|
*
|
|
225
|
-
* @param array Array of
|
|
210
|
+
* @param array Array of Uint8Array or UTF-8 encoded string messages to be converted to OP_RETURN data
|
|
226
211
|
*
|
|
227
212
|
* @returns class instance
|
|
228
213
|
*/
|
|
229
|
-
public static fromArray(array: Array<string |
|
|
230
|
-
let data:
|
|
214
|
+
public static fromArray(array: Array<string | Uint8Array>) {
|
|
215
|
+
let data: Uint8Array = Uint8Array.from([0x6a]); // OP_RETURN
|
|
231
216
|
for (const element of array) {
|
|
232
217
|
let length: number;
|
|
233
|
-
let elementData: Uint8Array
|
|
218
|
+
let elementData: Uint8Array;
|
|
234
219
|
let lengthData: any;
|
|
235
220
|
if (typeof element === "string") {
|
|
236
221
|
elementData = utf8ToBin(element);
|
|
237
222
|
length = elementData.length;
|
|
238
|
-
} else if (element instanceof Buffer) {
|
|
239
|
-
elementData = element;
|
|
240
|
-
length = elementData.length;
|
|
241
223
|
} else if (element instanceof Uint8Array) {
|
|
242
|
-
elementData =
|
|
224
|
+
elementData = element;
|
|
243
225
|
length = elementData.length;
|
|
244
226
|
} else {
|
|
245
227
|
throw new Error("Wrong data array element");
|
|
@@ -255,7 +237,7 @@ export class OpReturnData {
|
|
|
255
237
|
throw new Error("OP_RETURN data can not exceed 220 bytes in size");
|
|
256
238
|
}
|
|
257
239
|
|
|
258
|
-
data =
|
|
240
|
+
data = Uint8Array.from([...data, ...lengthData, ...elementData]);
|
|
259
241
|
}
|
|
260
242
|
|
|
261
243
|
if (data.length > 220) {
|
|
@@ -312,7 +294,7 @@ export class OpReturnData {
|
|
|
312
294
|
}
|
|
313
295
|
}
|
|
314
296
|
|
|
315
|
-
export type SendRequestArray = Array<string | number | UnitEnum |
|
|
297
|
+
export type SendRequestArray = Array<string | number | UnitEnum | Uint8Array>;
|
|
316
298
|
|
|
317
299
|
export type SourceOutput = Input & Output;
|
|
318
300
|
|