beignet 0.0.47 → 0.0.49
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/types/wallet/index.d.ts +1 -0
- package/dist/wallet/index.js +40 -12
- package/dist/wallet/index.js.map +1 -1
- package/package.json +4 -3
- package/src/wallet/index.ts +59 -12
- package/tests/boost.test.ts +68 -98
- package/tests/derivation.test.ts +13 -27
- package/tests/electrum.test.ts +33 -34
- package/tests/receive.test.ts +216 -0
- package/tests/storage.test.ts +54 -41
- package/tests/transaction.test.ts +33 -43
- package/tests/utils.ts +60 -2
- package/tests/wallet.test.ts +35 -44
package/src/wallet/index.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
import * as bip39 from 'bip39';
|
|
1
2
|
import * as bitcoin from 'bitcoinjs-lib';
|
|
2
3
|
import { Network, networks } from 'bitcoinjs-lib';
|
|
3
4
|
import BIP32Factory, { BIP32Interface } from 'bip32';
|
|
4
5
|
import * as ecc from '@bitcoinerlab/secp256k1';
|
|
6
|
+
import cloneDeep from 'lodash.clonedeep';
|
|
7
|
+
|
|
5
8
|
import {
|
|
6
9
|
EAddressType,
|
|
7
10
|
EAvailableNetworks,
|
|
@@ -107,9 +110,7 @@ import {
|
|
|
107
110
|
import { Electrum } from '../electrum';
|
|
108
111
|
import { Transaction } from '../transaction';
|
|
109
112
|
import { GAP_LIMIT, GAP_LIMIT_CHANGE, TRANSACTION_DEFAULTS } from './constants';
|
|
110
|
-
import cloneDeep from 'lodash.clonedeep';
|
|
111
113
|
import { btcToSats } from '../utils/conversion';
|
|
112
|
-
import * as bip39 from 'bip39';
|
|
113
114
|
|
|
114
115
|
const bip32 = BIP32Factory(ecc);
|
|
115
116
|
|
|
@@ -274,13 +275,34 @@ export class Wallet {
|
|
|
274
275
|
if (res.isErr()) return err(res.error.message);
|
|
275
276
|
wallet.updateFeeEstimates(true);
|
|
276
277
|
wallet.refreshWallet({});
|
|
277
|
-
if (wallet._disableMessagesOnCreate) wallet.disableMessages = false;
|
|
278
278
|
return ok(wallet);
|
|
279
279
|
} catch (e) {
|
|
280
280
|
return err(e);
|
|
281
281
|
}
|
|
282
282
|
}
|
|
283
283
|
|
|
284
|
+
/**
|
|
285
|
+
* Stops the wallet. Use this method to prepare the wallet to be de
|
|
286
|
+
* @returns {Promise<Result<string>>}
|
|
287
|
+
*/
|
|
288
|
+
public async stop(): Promise<Result<string>> {
|
|
289
|
+
try {
|
|
290
|
+
// if we are refreshing, we need to wait for it to finish
|
|
291
|
+
if (this.isRefreshing) {
|
|
292
|
+
await this.refreshWallet();
|
|
293
|
+
}
|
|
294
|
+
// disable onMessage callback
|
|
295
|
+
this.disableMessages = true;
|
|
296
|
+
// disable saving to storage
|
|
297
|
+
this._setData = undefined;
|
|
298
|
+
// disconnect from Electrum
|
|
299
|
+
await this.electrum.disconnect();
|
|
300
|
+
return ok('Wallet stopped.');
|
|
301
|
+
} catch (e) {
|
|
302
|
+
return err(e);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
284
306
|
public async switchNetwork(
|
|
285
307
|
network: EAvailableNetworks,
|
|
286
308
|
servers?: TServer | TServer[]
|
|
@@ -351,6 +373,7 @@ export class Wallet {
|
|
|
351
373
|
});
|
|
352
374
|
}
|
|
353
375
|
this.isRefreshing = true;
|
|
376
|
+
this.updateFeeEstimates();
|
|
354
377
|
try {
|
|
355
378
|
await this.setZeroIndexAddresses();
|
|
356
379
|
const r1 = await this.updateAddressIndexes();
|
|
@@ -379,6 +402,8 @@ export class Wallet {
|
|
|
379
402
|
} else {
|
|
380
403
|
return this._handleRefreshError(e);
|
|
381
404
|
}
|
|
405
|
+
} finally {
|
|
406
|
+
if (this._disableMessagesOnCreate) this.disableMessages = false;
|
|
382
407
|
}
|
|
383
408
|
}
|
|
384
409
|
|
|
@@ -1972,7 +1997,6 @@ export class Wallet {
|
|
|
1972
1997
|
[key: string]: number[];
|
|
1973
1998
|
} = {};
|
|
1974
1999
|
for (const tx of receivedTxs) {
|
|
1975
|
-
this.sendMessage('transactionReceived', tx);
|
|
1976
2000
|
// No need to scan an address with a saved UTXO.
|
|
1977
2001
|
if (utxoScriptHashes.has(tx.transaction.scriptHash)) continue;
|
|
1978
2002
|
for (const addressType in addresses) {
|
|
@@ -2009,6 +2033,10 @@ export class Wallet {
|
|
|
2009
2033
|
}
|
|
2010
2034
|
}
|
|
2011
2035
|
|
|
2036
|
+
for (const tx of receivedTxs) {
|
|
2037
|
+
this.sendMessage('transactionReceived', tx);
|
|
2038
|
+
}
|
|
2039
|
+
|
|
2012
2040
|
return ok(notificationTxid);
|
|
2013
2041
|
}
|
|
2014
2042
|
|
|
@@ -2759,13 +2787,25 @@ export class Wallet {
|
|
|
2759
2787
|
public async getFeeEstimates(network = this._network): Promise<IOnchainFees> {
|
|
2760
2788
|
try {
|
|
2761
2789
|
if (network === EAvailableNetworks.bitcoinRegtest) {
|
|
2762
|
-
return defaultFeesShape;
|
|
2790
|
+
return { ...defaultFeesShape, timestamp: Date.now() };
|
|
2763
2791
|
}
|
|
2764
2792
|
const urlModifier = network === 'bitcoin' ? '' : 'testnet/';
|
|
2765
2793
|
const response = await fetch(
|
|
2766
2794
|
`https://mempool.space/${urlModifier}api/v1/fees/recommended`
|
|
2767
2795
|
);
|
|
2768
2796
|
const res: IGetFeeEstimatesResponse = await response.json();
|
|
2797
|
+
// check the response for the expected properties
|
|
2798
|
+
if (
|
|
2799
|
+
!(
|
|
2800
|
+
res.fastestFee > 0 &&
|
|
2801
|
+
res.halfHourFee > 0 &&
|
|
2802
|
+
res.hourFee > 0 &&
|
|
2803
|
+
res.minimumFee > 0
|
|
2804
|
+
)
|
|
2805
|
+
) {
|
|
2806
|
+
throw new Error('Unexpected response from mempool.space');
|
|
2807
|
+
}
|
|
2808
|
+
|
|
2769
2809
|
return {
|
|
2770
2810
|
fast: res.fastestFee,
|
|
2771
2811
|
normal: res.halfHourFee,
|
|
@@ -2791,9 +2831,19 @@ export class Wallet {
|
|
|
2791
2831
|
if (network !== EAvailableNetworks.bitcoinMainnet) {
|
|
2792
2832
|
return defaultFeesShape;
|
|
2793
2833
|
}
|
|
2794
|
-
const url = 'https://blocktank.
|
|
2834
|
+
const url = 'https://api1.blocktank.to/api/info';
|
|
2795
2835
|
const response = await fetch(url);
|
|
2796
2836
|
const res: IBtInfo = await response.json();
|
|
2837
|
+
// check the response for the expected properties
|
|
2838
|
+
if (
|
|
2839
|
+
!(
|
|
2840
|
+
res?.onchain?.feeRates?.fast > 0 &&
|
|
2841
|
+
res?.onchain?.feeRates?.mid > 0 &&
|
|
2842
|
+
res?.onchain?.feeRates?.slow > 0
|
|
2843
|
+
)
|
|
2844
|
+
) {
|
|
2845
|
+
throw new Error('Unexpected response from blocktank');
|
|
2846
|
+
}
|
|
2797
2847
|
const { fast, mid, slow } = res.onchain.feeRates;
|
|
2798
2848
|
return {
|
|
2799
2849
|
fast,
|
|
@@ -2804,7 +2854,7 @@ export class Wallet {
|
|
|
2804
2854
|
};
|
|
2805
2855
|
} catch (e) {
|
|
2806
2856
|
console.log('Unable to fetch fee estimates.', e);
|
|
2807
|
-
return
|
|
2857
|
+
return this.feeEstimates;
|
|
2808
2858
|
}
|
|
2809
2859
|
}
|
|
2810
2860
|
|
|
@@ -3698,7 +3748,7 @@ export class Wallet {
|
|
|
3698
3748
|
* Updates the fee estimates for the current network.
|
|
3699
3749
|
* @public
|
|
3700
3750
|
* @async
|
|
3701
|
-
* @param {
|
|
3751
|
+
* @param {boolean} [forceUpdate] Ignores the timestamp if set true and forces the update
|
|
3702
3752
|
* @returns {Promise<Result<IOnchainFees>>}
|
|
3703
3753
|
*/
|
|
3704
3754
|
public async updateFeeEstimates(
|
|
@@ -3706,13 +3756,10 @@ export class Wallet {
|
|
|
3706
3756
|
): Promise<Result<IOnchainFees>> {
|
|
3707
3757
|
const timestamp = this.feeEstimates.timestamp;
|
|
3708
3758
|
const difference = Math.floor((Date.now() - timestamp) / 1000);
|
|
3709
|
-
if (!forceUpdate && difference <
|
|
3759
|
+
if (!forceUpdate && difference < 60) {
|
|
3710
3760
|
return ok(this.feeEstimates);
|
|
3711
3761
|
}
|
|
3712
3762
|
const feeEstimates = await this.getFeeEstimates();
|
|
3713
|
-
if (!feeEstimates) {
|
|
3714
|
-
return err('Unable to retrieve fee estimates.');
|
|
3715
|
-
}
|
|
3716
3763
|
this.feeEstimates = feeEstimates;
|
|
3717
3764
|
await this.saveWalletData('feeEstimates', feeEstimates);
|
|
3718
3765
|
return ok(feeEstimates);
|
package/tests/boost.test.ts
CHANGED
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
EProtocol,
|
|
11
11
|
generateMnemonic,
|
|
12
12
|
Wallet
|
|
13
|
-
} from '../
|
|
13
|
+
} from '../';
|
|
14
14
|
import {
|
|
15
15
|
bitcoinURL,
|
|
16
16
|
electrumHost,
|
|
@@ -25,62 +25,66 @@ let waitForElectrum: TWaitForElectrum;
|
|
|
25
25
|
const rpc = new BitcoinJsonRpc(bitcoinURL);
|
|
26
26
|
const failure = { canBoost: false, rbf: false, cpfp: false };
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
describe('Boost', async function () {
|
|
29
29
|
this.timeout(testTimeout);
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
beforeEach(async function () {
|
|
32
|
+
this.timeout(testTimeout);
|
|
33
|
+
|
|
34
|
+
let balance = await rpc.getBalance();
|
|
35
|
+
const address = await rpc.getNewAddress();
|
|
36
|
+
await rpc.generateToAddress(1, address);
|
|
34
37
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
38
|
+
while (balance < 10) {
|
|
39
|
+
await rpc.generateToAddress(10, address);
|
|
40
|
+
balance = await rpc.getBalance();
|
|
41
|
+
}
|
|
39
42
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
43
|
+
waitForElectrum = await initWaitForElectrumToSync(
|
|
44
|
+
{ host: electrumHost, port: electrumPort },
|
|
45
|
+
bitcoinURL
|
|
46
|
+
);
|
|
44
47
|
|
|
45
|
-
|
|
48
|
+
await waitForElectrum();
|
|
46
49
|
|
|
47
|
-
|
|
50
|
+
const mnemonic = generateMnemonic();
|
|
48
51
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
52
|
+
const res = await Wallet.create({
|
|
53
|
+
rbf: true,
|
|
54
|
+
mnemonic,
|
|
55
|
+
// mnemonic: 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about',
|
|
56
|
+
network: EAvailableNetworks.regtest,
|
|
57
|
+
addressType: EAddressType.p2wpkh,
|
|
58
|
+
electrumOptions: {
|
|
59
|
+
servers: [
|
|
60
|
+
{
|
|
61
|
+
host: '127.0.0.1',
|
|
62
|
+
ssl: 60002,
|
|
63
|
+
tcp: 60001,
|
|
64
|
+
protocol: EProtocol.tcp
|
|
65
|
+
}
|
|
66
|
+
],
|
|
67
|
+
net,
|
|
68
|
+
tls
|
|
69
|
+
},
|
|
70
|
+
// reduce gap limit to speed up tests
|
|
71
|
+
gapLimitOptions: {
|
|
72
|
+
lookAhead: 2,
|
|
73
|
+
lookBehind: 2,
|
|
74
|
+
lookAheadChange: 2,
|
|
75
|
+
lookBehindChange: 2
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
if (res.isErr()) {
|
|
79
|
+
throw res.error;
|
|
73
80
|
}
|
|
81
|
+
wallet = res.value;
|
|
82
|
+
await wallet.refreshWallet({});
|
|
74
83
|
});
|
|
75
|
-
if (res.isErr()) {
|
|
76
|
-
throw res.error;
|
|
77
|
-
}
|
|
78
|
-
wallet = res.value;
|
|
79
|
-
await wallet.refreshWallet({});
|
|
80
|
-
});
|
|
81
84
|
|
|
82
|
-
|
|
83
|
-
|
|
85
|
+
afterEach(async function () {
|
|
86
|
+
await wallet?.electrum?.disconnect();
|
|
87
|
+
});
|
|
84
88
|
|
|
85
89
|
it('Should fail in some cases.', async () => {
|
|
86
90
|
// tx not found
|
|
@@ -89,9 +93,7 @@ describe('Boost', async function () {
|
|
|
89
93
|
|
|
90
94
|
// balance is 0
|
|
91
95
|
const r = await wallet.getNextAvailableAddress();
|
|
92
|
-
if (r.isErr())
|
|
93
|
-
throw r.error;
|
|
94
|
-
}
|
|
96
|
+
if (r.isErr()) throw r.error;
|
|
95
97
|
const a1 = r.value.addressIndex.address;
|
|
96
98
|
await rpc.sendToAddress(a1, '1');
|
|
97
99
|
await rpc.generateToAddress(1, await rpc.getNewAddress());
|
|
@@ -103,9 +105,7 @@ describe('Boost', async function () {
|
|
|
103
105
|
amount: 99999743,
|
|
104
106
|
satsPerByte: 1
|
|
105
107
|
});
|
|
106
|
-
if (s1.isErr())
|
|
107
|
-
throw s1.error;
|
|
108
|
-
}
|
|
108
|
+
if (s1.isErr()) throw s1.error;
|
|
109
109
|
await wallet.refreshWallet({});
|
|
110
110
|
expect(wallet.data.balance).to.be.below(256);
|
|
111
111
|
const b2 = wallet.canBoost(s1.value);
|
|
@@ -120,9 +120,7 @@ describe('Boost', async function () {
|
|
|
120
120
|
address: 'bcrt1q6rz28mcfaxtmd6v789l9rrlrusdprr9pz3cppk',
|
|
121
121
|
amount: 10000000
|
|
122
122
|
});
|
|
123
|
-
if (s2.isErr())
|
|
124
|
-
throw s2.error;
|
|
125
|
-
}
|
|
123
|
+
if (s2.isErr()) throw s2.error;
|
|
126
124
|
await rpc.generateToAddress(1, await rpc.getNewAddress()); // confirm tx
|
|
127
125
|
await wallet.refreshWallet({});
|
|
128
126
|
const b3 = wallet.canBoost(s2.value);
|
|
@@ -131,9 +129,7 @@ describe('Boost', async function () {
|
|
|
131
129
|
|
|
132
130
|
it('Should generate CPFP for send transaction', async () => {
|
|
133
131
|
const r = await wallet.getNextAvailableAddress();
|
|
134
|
-
if (r.isErr())
|
|
135
|
-
throw r.error;
|
|
136
|
-
}
|
|
132
|
+
if (r.isErr()) throw r.error;
|
|
137
133
|
const a1 = r.value.addressIndex.address;
|
|
138
134
|
await rpc.sendToAddress(a1, '1');
|
|
139
135
|
await rpc.generateToAddress(1, await rpc.getNewAddress());
|
|
@@ -148,18 +144,14 @@ describe('Boost', async function () {
|
|
|
148
144
|
satsPerByte: 1,
|
|
149
145
|
rbf: false
|
|
150
146
|
});
|
|
151
|
-
if (s1.isErr())
|
|
152
|
-
throw s1.error;
|
|
153
|
-
}
|
|
147
|
+
if (s1.isErr()) throw s1.error;
|
|
154
148
|
const oldTxId = s1.value;
|
|
155
149
|
await wallet.refreshWallet({});
|
|
156
150
|
const b1 = wallet.canBoost(oldTxId);
|
|
157
151
|
expect(b1).to.deep.equal({ canBoost: true, rbf: false, cpfp: true });
|
|
158
152
|
|
|
159
153
|
const setup = await wallet.transaction.setupCpfp({ txid: oldTxId });
|
|
160
|
-
if (setup.isErr())
|
|
161
|
-
throw setup.error;
|
|
162
|
-
}
|
|
154
|
+
if (setup.isErr()) throw setup.error;
|
|
163
155
|
expect(setup.value.inputs.length).to.equal(1);
|
|
164
156
|
expect(setup.value.outputs.length).to.equal(1);
|
|
165
157
|
expect(setup.value.boostType).to.equal(EBoostType.cpfp);
|
|
@@ -169,9 +161,7 @@ describe('Boost', async function () {
|
|
|
169
161
|
expect(setup.value.satsPerByte).to.be.above(6);
|
|
170
162
|
|
|
171
163
|
const createRes = await wallet.transaction.createTransaction();
|
|
172
|
-
if (createRes.isErr())
|
|
173
|
-
throw createRes.error;
|
|
174
|
-
}
|
|
164
|
+
if (createRes.isErr()) throw createRes.error;
|
|
175
165
|
const newTxId = createRes.value.id;
|
|
176
166
|
wallet.electrum.broadcastTransaction({ rawTx: createRes.value.hex });
|
|
177
167
|
|
|
@@ -181,9 +171,7 @@ describe('Boost', async function () {
|
|
|
181
171
|
type: EBoostType.cpfp,
|
|
182
172
|
fee: setup.value.fee
|
|
183
173
|
});
|
|
184
|
-
if (addBoost.isErr())
|
|
185
|
-
throw addBoost.error;
|
|
186
|
-
}
|
|
174
|
+
if (addBoost.isErr()) throw addBoost.error;
|
|
187
175
|
const boosted = wallet.getBoostedTransactions();
|
|
188
176
|
expect(boosted).to.deep.equal({
|
|
189
177
|
[oldTxId]: {
|
|
@@ -205,18 +193,14 @@ describe('Boost', async function () {
|
|
|
205
193
|
|
|
206
194
|
it('Should generate RBF for send transaction', async () => {
|
|
207
195
|
const r = await wallet.getNextAvailableAddress();
|
|
208
|
-
if (r.isErr())
|
|
209
|
-
throw r.error;
|
|
210
|
-
}
|
|
196
|
+
if (r.isErr()) throw r.error;
|
|
211
197
|
const a1 = r.value.addressIndex.address;
|
|
212
198
|
await rpc.sendToAddress(a1, '0.0001'); // 10000 sats
|
|
213
199
|
await rpc.generateToAddress(1, await rpc.getNewAddress());
|
|
214
200
|
|
|
215
201
|
await waitForElectrum();
|
|
216
202
|
const r1 = await wallet.refreshWallet({});
|
|
217
|
-
if (r1.isErr())
|
|
218
|
-
throw r1.error;
|
|
219
|
-
}
|
|
203
|
+
if (r1.isErr()) throw r1.error;
|
|
220
204
|
expect(wallet.data.balance).to.equal(10000);
|
|
221
205
|
|
|
222
206
|
// create and send original transaction
|
|
@@ -226,35 +210,25 @@ describe('Boost', async function () {
|
|
|
226
210
|
satsPerByte: 1,
|
|
227
211
|
rbf: true
|
|
228
212
|
});
|
|
229
|
-
if (s1.isErr())
|
|
230
|
-
throw s1.error;
|
|
231
|
-
}
|
|
213
|
+
if (s1.isErr()) throw s1.error;
|
|
232
214
|
const oldTxId = s1.value;
|
|
233
215
|
const r2 = await wallet.refreshWallet({});
|
|
234
|
-
if (r2.isErr())
|
|
235
|
-
throw r2.error;
|
|
236
|
-
}
|
|
216
|
+
if (r2.isErr()) throw r2.error;
|
|
237
217
|
const b1 = wallet.canBoost(oldTxId);
|
|
238
218
|
expect(b1).to.deep.equal({ canBoost: true, rbf: true, cpfp: true });
|
|
239
219
|
|
|
240
220
|
// replace original transaction using RBF
|
|
241
221
|
const setup = await wallet.transaction.setupRbf({ txid: oldTxId });
|
|
242
|
-
if (setup.isErr())
|
|
243
|
-
throw setup.error;
|
|
244
|
-
}
|
|
222
|
+
if (setup.isErr()) throw setup.error;
|
|
245
223
|
expect(setup.value.boostType).to.equal(EBoostType.rbf);
|
|
246
224
|
expect(setup.value.minFee).to.be.above(1);
|
|
247
225
|
const createRes = await wallet.transaction.createTransaction();
|
|
248
|
-
if (createRes.isErr())
|
|
249
|
-
throw createRes.error;
|
|
250
|
-
}
|
|
226
|
+
if (createRes.isErr()) throw createRes.error;
|
|
251
227
|
const newTxId = createRes.value.id;
|
|
252
228
|
const broadcastResp = await wallet.electrum.broadcastTransaction({
|
|
253
229
|
rawTx: createRes.value.hex
|
|
254
230
|
});
|
|
255
|
-
if (broadcastResp.isErr())
|
|
256
|
-
throw broadcastResp.error;
|
|
257
|
-
}
|
|
231
|
+
if (broadcastResp.isErr()) throw broadcastResp.error;
|
|
258
232
|
|
|
259
233
|
const addBoost = await wallet.addBoostedTransaction({
|
|
260
234
|
oldTxId,
|
|
@@ -262,9 +236,7 @@ describe('Boost', async function () {
|
|
|
262
236
|
type: EBoostType.rbf,
|
|
263
237
|
fee: setup.value.fee
|
|
264
238
|
});
|
|
265
|
-
if (addBoost.isErr())
|
|
266
|
-
throw addBoost.error;
|
|
267
|
-
}
|
|
239
|
+
if (addBoost.isErr()) throw addBoost.error;
|
|
268
240
|
const boosted = wallet.getBoostedTransactions();
|
|
269
241
|
expect(boosted).to.deep.equal({
|
|
270
242
|
[oldTxId]: {
|
|
@@ -276,9 +248,7 @@ describe('Boost', async function () {
|
|
|
276
248
|
});
|
|
277
249
|
|
|
278
250
|
const r3 = await wallet.refreshWallet({});
|
|
279
|
-
if (r3.isErr())
|
|
280
|
-
throw r3.error;
|
|
281
|
-
}
|
|
251
|
+
if (r3.isErr()) throw r3.error;
|
|
282
252
|
|
|
283
253
|
expect(Object.keys(wallet.transactions).length).to.equal(2);
|
|
284
254
|
expect(wallet.transactions).not.to.have.property(oldTxId);
|
package/tests/derivation.test.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { expect } from 'chai';
|
|
2
2
|
import {
|
|
3
3
|
EAddressType,
|
|
4
4
|
EAvailableNetworks,
|
|
@@ -8,16 +8,13 @@ import {
|
|
|
8
8
|
getKeyDerivationPathString
|
|
9
9
|
} from '../src';
|
|
10
10
|
|
|
11
|
-
const expect = chai.expect;
|
|
12
|
-
|
|
13
11
|
describe('Derivation Methods', () => {
|
|
14
12
|
it('Should return default derivation path object for p2wpkh', () => {
|
|
15
13
|
const pathRes = getKeyDerivationPath({
|
|
16
14
|
addressType: EAddressType.p2wpkh,
|
|
17
15
|
network: EAvailableNetworks.mainnet
|
|
18
16
|
});
|
|
19
|
-
|
|
20
|
-
if (pathRes.isErr()) return;
|
|
17
|
+
if (pathRes.isErr()) throw pathRes.error;
|
|
21
18
|
expect(pathRes.value.purpose).to.equal('84');
|
|
22
19
|
expect(pathRes.value.coinType).to.equal('0');
|
|
23
20
|
expect(pathRes.value.account).to.equal('0');
|
|
@@ -29,8 +26,7 @@ describe('Derivation Methods', () => {
|
|
|
29
26
|
addressType: EAddressType.p2sh,
|
|
30
27
|
network: EAvailableNetworks.mainnet
|
|
31
28
|
});
|
|
32
|
-
|
|
33
|
-
if (pathRes.isErr()) return;
|
|
29
|
+
if (pathRes.isErr()) throw pathRes.error;
|
|
34
30
|
expect(pathRes.value.purpose).to.equal('49');
|
|
35
31
|
expect(pathRes.value.coinType).to.equal('0');
|
|
36
32
|
expect(pathRes.value.account).to.equal('0');
|
|
@@ -42,8 +38,7 @@ describe('Derivation Methods', () => {
|
|
|
42
38
|
addressType: EAddressType.p2pkh,
|
|
43
39
|
network: EAvailableNetworks.mainnet
|
|
44
40
|
});
|
|
45
|
-
|
|
46
|
-
if (pathRes.isErr()) return;
|
|
41
|
+
if (pathRes.isErr()) throw pathRes.error;
|
|
47
42
|
expect(pathRes.value.purpose).to.equal('44');
|
|
48
43
|
expect(pathRes.value.coinType).to.equal('0');
|
|
49
44
|
expect(pathRes.value.account).to.equal('0');
|
|
@@ -58,8 +53,7 @@ describe('Derivation Methods', () => {
|
|
|
58
53
|
index: 0,
|
|
59
54
|
network: EAvailableNetworks.mainnet
|
|
60
55
|
});
|
|
61
|
-
|
|
62
|
-
if (pathRes.isErr()) return;
|
|
56
|
+
if (pathRes.isErr()) throw pathRes.error;
|
|
63
57
|
expect(pathRes.value).to.equal("m/84'/0'/0'/1/0");
|
|
64
58
|
});
|
|
65
59
|
it('Should return a valid testnet p2sh derivation string at index 40', () => {
|
|
@@ -69,8 +63,7 @@ describe('Derivation Methods', () => {
|
|
|
69
63
|
index: '40',
|
|
70
64
|
network: EAvailableNetworks.testnet
|
|
71
65
|
});
|
|
72
|
-
|
|
73
|
-
if (pathRes.isErr()) return;
|
|
66
|
+
if (pathRes.isErr()) throw pathRes.error;
|
|
74
67
|
expect(pathRes.value).to.equal("m/49'/1'/0'/0/40");
|
|
75
68
|
});
|
|
76
69
|
it('Should return a valid mainnet p2pkh derivation string at index 8', () => {
|
|
@@ -80,8 +73,7 @@ describe('Derivation Methods', () => {
|
|
|
80
73
|
index: 8,
|
|
81
74
|
network: EAvailableNetworks.mainnet
|
|
82
75
|
});
|
|
83
|
-
|
|
84
|
-
if (pathRes.isErr()) return;
|
|
76
|
+
if (pathRes.isErr()) throw pathRes.error;
|
|
85
77
|
expect(pathRes.value).to.equal("m/44'/0'/0'/0/8");
|
|
86
78
|
});
|
|
87
79
|
|
|
@@ -90,8 +82,7 @@ describe('Derivation Methods', () => {
|
|
|
90
82
|
path: "m/84'/0'/0'/1/0",
|
|
91
83
|
network: EAvailableNetworks.mainnet
|
|
92
84
|
});
|
|
93
|
-
|
|
94
|
-
if (pathRes.isErr()) return;
|
|
85
|
+
if (pathRes.isErr()) throw pathRes.error;
|
|
95
86
|
expect(pathRes.value.purpose).to.equal('84');
|
|
96
87
|
expect(pathRes.value.coinType).to.equal('0');
|
|
97
88
|
expect(pathRes.value.account).to.equal('0');
|
|
@@ -103,8 +94,7 @@ describe('Derivation Methods', () => {
|
|
|
103
94
|
path: "m/49'/1'/0'/0/40",
|
|
104
95
|
network: EAvailableNetworks.testnet
|
|
105
96
|
});
|
|
106
|
-
|
|
107
|
-
if (pathRes.isErr()) return;
|
|
97
|
+
if (pathRes.isErr()) throw pathRes.error;
|
|
108
98
|
expect(pathRes.value.purpose).to.equal('49');
|
|
109
99
|
expect(pathRes.value.coinType).to.equal('1');
|
|
110
100
|
expect(pathRes.value.account).to.equal('0');
|
|
@@ -116,8 +106,7 @@ describe('Derivation Methods', () => {
|
|
|
116
106
|
path: "m/44'/0'/0'/0/8",
|
|
117
107
|
network: EAvailableNetworks.mainnet
|
|
118
108
|
});
|
|
119
|
-
|
|
120
|
-
if (pathRes.isErr()) return;
|
|
109
|
+
if (pathRes.isErr()) throw pathRes.error;
|
|
121
110
|
expect(pathRes.value.purpose).to.equal('44');
|
|
122
111
|
expect(pathRes.value.coinType).to.equal('0');
|
|
123
112
|
expect(pathRes.value.account).to.equal('0');
|
|
@@ -127,20 +116,17 @@ describe('Derivation Methods', () => {
|
|
|
127
116
|
|
|
128
117
|
it('Should return a valid address type from p2wpkh path', () => {
|
|
129
118
|
const pathRes = getAddressTypeFromPath("m/84'/0'/0'/0/0");
|
|
130
|
-
|
|
131
|
-
if (pathRes.isErr()) return;
|
|
119
|
+
if (pathRes.isErr()) throw pathRes.error;
|
|
132
120
|
expect(pathRes.value).to.equal(EAddressType.p2wpkh);
|
|
133
121
|
});
|
|
134
122
|
it('Should return a valid address type from p2sh path', () => {
|
|
135
123
|
const pathRes = getAddressTypeFromPath("m/49'/0'/0'/0/0");
|
|
136
|
-
|
|
137
|
-
if (pathRes.isErr()) return;
|
|
124
|
+
if (pathRes.isErr()) throw pathRes.error;
|
|
138
125
|
expect(pathRes.value).to.equal(EAddressType.p2sh);
|
|
139
126
|
});
|
|
140
127
|
it('Should return a valid address type from p2pkh path', () => {
|
|
141
128
|
const pathRes = getAddressTypeFromPath("m/44'/0'/0'/0/0");
|
|
142
|
-
|
|
143
|
-
if (pathRes.isErr()) return;
|
|
129
|
+
if (pathRes.isErr()) throw pathRes.error;
|
|
144
130
|
expect(pathRes.value).to.equal(EAddressType.p2pkh);
|
|
145
131
|
});
|
|
146
132
|
});
|
package/tests/electrum.test.ts
CHANGED
|
@@ -1,47 +1,49 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { expect } from 'chai';
|
|
2
2
|
import net from 'net';
|
|
3
3
|
import tls from 'tls';
|
|
4
4
|
|
|
5
5
|
import { Wallet } from '../';
|
|
6
|
-
import { EAvailableNetworks, EAddressType, IGetUtxosResponse } from '../src';
|
|
7
|
-
import { TEST_MNEMONIC } from './constants';
|
|
8
|
-
import { Result } from '../src';
|
|
9
6
|
import { servers } from '../example/helpers';
|
|
7
|
+
import {
|
|
8
|
+
EAddressType,
|
|
9
|
+
EAvailableNetworks,
|
|
10
|
+
IGetUtxosResponse,
|
|
11
|
+
Result
|
|
12
|
+
} from '../src';
|
|
13
|
+
import { TEST_MNEMONIC } from './constants';
|
|
10
14
|
import { EXPECTED_SHARED_RESULTS } from './expected-results';
|
|
11
15
|
|
|
12
|
-
const expect = chai.expect;
|
|
13
|
-
|
|
14
16
|
const testTimeout = 60000;
|
|
15
17
|
|
|
16
18
|
let wallet: Wallet;
|
|
17
19
|
|
|
18
|
-
|
|
20
|
+
describe('Electrum Methods', async function (): Promise<void> {
|
|
19
21
|
this.timeout(testTimeout);
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
22
|
+
|
|
23
|
+
before(async function () {
|
|
24
|
+
this.timeout(testTimeout);
|
|
25
|
+
const res = await Wallet.create({
|
|
26
|
+
mnemonic: TEST_MNEMONIC,
|
|
27
|
+
network: EAvailableNetworks.testnet,
|
|
28
|
+
addressType: EAddressType.p2wpkh,
|
|
29
|
+
electrumOptions: {
|
|
30
|
+
servers: servers[EAvailableNetworks.testnet],
|
|
31
|
+
net,
|
|
32
|
+
tls
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
if (res.isErr()) throw res.error;
|
|
36
|
+
wallet = res.value;
|
|
37
|
+
await wallet.refreshWallet({});
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
after(async function () {
|
|
41
|
+
await wallet?.electrum?.disconnect();
|
|
29
42
|
});
|
|
30
|
-
if (res.isErr()) {
|
|
31
|
-
console.log('error: ', res.error.message);
|
|
32
|
-
//throw new Error(res.error.message);
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
wallet = res.value;
|
|
36
|
-
await wallet.refreshWallet({});
|
|
37
|
-
});
|
|
38
43
|
|
|
39
|
-
describe('Electrum Methods', async function (): Promise<void> {
|
|
40
|
-
this.timeout(testTimeout);
|
|
41
44
|
it('connectToElectrum: Should connect to a random Electrum server', async () => {
|
|
42
45
|
const connectResponse = await wallet.connectToElectrum();
|
|
43
|
-
|
|
44
|
-
if (connectResponse.isErr()) return;
|
|
46
|
+
if (connectResponse.isErr()) throw connectResponse.error;
|
|
45
47
|
expect(connectResponse.value).to.equal('Connected to Electrum server.');
|
|
46
48
|
});
|
|
47
49
|
|
|
@@ -54,15 +56,13 @@ describe('Electrum Methods', async function (): Promise<void> {
|
|
|
54
56
|
const addressBalance = await wallet.getAddressBalance(
|
|
55
57
|
'tb1qyvc8r7338383xjshqsz38mfn2eql879nhrf8y0'
|
|
56
58
|
);
|
|
57
|
-
|
|
58
|
-
if (addressBalance.isErr()) return;
|
|
59
|
+
if (addressBalance.isErr()) throw addressBalance.error;
|
|
59
60
|
expect(addressBalance.value.confirmed).to.equal(20000);
|
|
60
61
|
});
|
|
61
62
|
|
|
62
63
|
it('getNextAvailableAddress: Should return the next available address/change index and the last used address/change index', async () => {
|
|
63
64
|
const r = await wallet.getNextAvailableAddress();
|
|
64
|
-
|
|
65
|
-
if (r.isErr()) return;
|
|
65
|
+
if (r.isErr()) throw r.error;
|
|
66
66
|
expect(r.value).to.deep.equal(
|
|
67
67
|
EXPECTED_SHARED_RESULTS.getNextAvailableAddress
|
|
68
68
|
);
|
|
@@ -70,8 +70,7 @@ describe('Electrum Methods', async function (): Promise<void> {
|
|
|
70
70
|
|
|
71
71
|
it("Should return available UTXO's", async () => {
|
|
72
72
|
const getUtxosRes: Result<IGetUtxosResponse> = await wallet.getUtxos({});
|
|
73
|
-
|
|
74
|
-
if (getUtxosRes.isErr()) return;
|
|
73
|
+
if (getUtxosRes.isErr()) throw getUtxosRes.error;
|
|
75
74
|
expect(Array.isArray(getUtxosRes.value.utxos)).to.equal(true);
|
|
76
75
|
expect(getUtxosRes.value.utxos.length).to.equal(3);
|
|
77
76
|
expect(getUtxosRes.value.balance).to.equal(5855);
|