beignet 0.0.48 → 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 +19 -3
- package/dist/wallet/index.js.map +1 -1
- package/package.json +4 -3
- package/src/wallet/index.ts +29 -3
- 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
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import BitcoinJsonRpc from 'bitcoin-json-rpc';
|
|
2
|
+
import { expect } from 'chai';
|
|
3
|
+
import net from 'net';
|
|
4
|
+
import tls from 'tls';
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
EAddressType,
|
|
8
|
+
EAvailableNetworks,
|
|
9
|
+
EProtocol,
|
|
10
|
+
generateMnemonic,
|
|
11
|
+
sleep,
|
|
12
|
+
Wallet
|
|
13
|
+
} from '../';
|
|
14
|
+
import {
|
|
15
|
+
bitcoinURL,
|
|
16
|
+
electrumHost,
|
|
17
|
+
electrumPort,
|
|
18
|
+
initWaitForElectrumToSync,
|
|
19
|
+
MessageListener,
|
|
20
|
+
TWaitForElectrum
|
|
21
|
+
} from './utils';
|
|
22
|
+
|
|
23
|
+
const testTimeout = 60000;
|
|
24
|
+
let wallet: Wallet;
|
|
25
|
+
let waitForElectrum: TWaitForElectrum;
|
|
26
|
+
const rpc = new BitcoinJsonRpc(bitcoinURL);
|
|
27
|
+
const ml = new MessageListener();
|
|
28
|
+
|
|
29
|
+
describe('Receive', async function () {
|
|
30
|
+
this.timeout(testTimeout);
|
|
31
|
+
|
|
32
|
+
beforeEach(async function () {
|
|
33
|
+
this.timeout(testTimeout);
|
|
34
|
+
ml.clear();
|
|
35
|
+
|
|
36
|
+
// Ensure sufficient balance in regtest
|
|
37
|
+
let balance = await rpc.getBalance();
|
|
38
|
+
const address = await rpc.getNewAddress();
|
|
39
|
+
await rpc.generateToAddress(1, address);
|
|
40
|
+
|
|
41
|
+
while (balance < 10) {
|
|
42
|
+
await rpc.generateToAddress(10, address);
|
|
43
|
+
balance = await rpc.getBalance();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
waitForElectrum = await initWaitForElectrumToSync(
|
|
47
|
+
{ host: electrumHost, port: electrumPort },
|
|
48
|
+
bitcoinURL
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
await waitForElectrum();
|
|
52
|
+
|
|
53
|
+
const mnemonic = generateMnemonic();
|
|
54
|
+
|
|
55
|
+
const res = await Wallet.create({
|
|
56
|
+
mnemonic,
|
|
57
|
+
network: EAvailableNetworks.regtest,
|
|
58
|
+
addressType: EAddressType.p2wpkh,
|
|
59
|
+
electrumOptions: {
|
|
60
|
+
servers: [
|
|
61
|
+
{
|
|
62
|
+
host: '127.0.0.1',
|
|
63
|
+
ssl: 60002,
|
|
64
|
+
tcp: 60001,
|
|
65
|
+
protocol: EProtocol.tcp
|
|
66
|
+
}
|
|
67
|
+
],
|
|
68
|
+
net,
|
|
69
|
+
tls
|
|
70
|
+
},
|
|
71
|
+
// reduce gap limit to speed up tests
|
|
72
|
+
gapLimitOptions: {
|
|
73
|
+
lookAhead: 2,
|
|
74
|
+
lookBehind: 2,
|
|
75
|
+
lookAheadChange: 2,
|
|
76
|
+
lookBehindChange: 2
|
|
77
|
+
},
|
|
78
|
+
addressTypesToMonitor: [EAddressType.p2wpkh],
|
|
79
|
+
onMessage: ml.onMessage
|
|
80
|
+
});
|
|
81
|
+
if (res.isErr()) throw res.error;
|
|
82
|
+
wallet = res.value;
|
|
83
|
+
await wallet.refreshWallet({});
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
afterEach(async function () {
|
|
87
|
+
await wallet?.electrum?.disconnect();
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('Should generate new receiving address', async () => {
|
|
91
|
+
const r = await wallet.getNextAvailableAddress();
|
|
92
|
+
if (r.isErr()) throw r.error;
|
|
93
|
+
const address = r.value.addressIndex.address;
|
|
94
|
+
expect(address).to.be.a('string');
|
|
95
|
+
expect(address).to.match(/^bcrt1/); // Regtest bech32 prefix
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('Should receive funds and update balance', async () => {
|
|
99
|
+
expect(wallet.data.balance).to.equal(0);
|
|
100
|
+
|
|
101
|
+
const r = await wallet.getNextAvailableAddress();
|
|
102
|
+
if (r.isErr()) throw r.error;
|
|
103
|
+
const address = r.value.addressIndex.address;
|
|
104
|
+
expect(address).to.be.a('string');
|
|
105
|
+
expect(address).to.match(/^bcrt1/); // Regtest bech32 prefix
|
|
106
|
+
|
|
107
|
+
const amount = 0.1;
|
|
108
|
+
const amountSats = amount * 10e7;
|
|
109
|
+
await rpc.sendToAddress(address, amount.toString());
|
|
110
|
+
|
|
111
|
+
await rpc.generateToAddress(1, await rpc.getNewAddress());
|
|
112
|
+
await waitForElectrum();
|
|
113
|
+
|
|
114
|
+
await wallet.refreshWallet({});
|
|
115
|
+
expect(wallet.getBalance()).to.equal(amountSats);
|
|
116
|
+
expect(wallet.balance).to.equal(amountSats);
|
|
117
|
+
expect(wallet.utxos.length).to.equal(1);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('Should track multiple receiving addresses', async () => {
|
|
121
|
+
const r1 = await wallet.getNextAvailableAddress();
|
|
122
|
+
if (r1.isErr()) throw r1.error;
|
|
123
|
+
const address1 = r1.value.addressIndex.address;
|
|
124
|
+
const r2 = await wallet.getNextAvailableAddress();
|
|
125
|
+
if (r2.isErr()) throw r2.error;
|
|
126
|
+
const address2 = r2.value.addressIndex.address;
|
|
127
|
+
|
|
128
|
+
// Without any transactions addresses should match
|
|
129
|
+
expect(address1).to.equal(address2);
|
|
130
|
+
|
|
131
|
+
// Send funds, get new address
|
|
132
|
+
await rpc.sendToAddress(address1, '0.1');
|
|
133
|
+
await rpc.generateToAddress(1, await rpc.getNewAddress());
|
|
134
|
+
await waitForElectrum();
|
|
135
|
+
const r3 = await wallet.getNextAvailableAddress();
|
|
136
|
+
if (r3.isErr()) throw r3.error;
|
|
137
|
+
const address3 = r3.value.addressIndex.address;
|
|
138
|
+
|
|
139
|
+
// After a transaction, addresses should differ
|
|
140
|
+
expect(address1).to.not.equal(address3);
|
|
141
|
+
|
|
142
|
+
// Second transaction
|
|
143
|
+
const receivePromise = ml.waitFor('transactionReceived');
|
|
144
|
+
await rpc.sendToAddress(address3, '0.2');
|
|
145
|
+
await receivePromise;
|
|
146
|
+
|
|
147
|
+
// unfortinately it is possible that Electrum server still does not
|
|
148
|
+
// have second transaction parsed so we need to wait a bit
|
|
149
|
+
while (wallet.data.utxos.length === 1) {
|
|
150
|
+
await sleep(100);
|
|
151
|
+
await wallet.refreshWallet();
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Check balances
|
|
155
|
+
expect(wallet.balance).to.equal(0.3 * 10e7); // 0.3 BTC in sats
|
|
156
|
+
|
|
157
|
+
// Test getAddressBalance
|
|
158
|
+
const balance1 = await wallet.getAddressBalance(address1);
|
|
159
|
+
if (balance1.isErr()) throw balance1.error;
|
|
160
|
+
expect(balance1.value.confirmed).to.equal(0.1 * 10e7);
|
|
161
|
+
const balance3 = await wallet.getAddressBalance(address3);
|
|
162
|
+
if (balance3.isErr()) throw balance3.error;
|
|
163
|
+
expect(balance3.value.unconfirmed).to.equal(0.2 * 10e7);
|
|
164
|
+
|
|
165
|
+
// Test getAddressesBalance
|
|
166
|
+
const combinedBalance = await wallet.getAddressesBalance([
|
|
167
|
+
address1,
|
|
168
|
+
address3
|
|
169
|
+
]);
|
|
170
|
+
if (combinedBalance.isErr()) throw combinedBalance.error;
|
|
171
|
+
expect(combinedBalance.value).to.equal(0.3 * 10e7);
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
it('Should handle unconfirmed transactions', async () => {
|
|
175
|
+
const r = await wallet.getNextAvailableAddress();
|
|
176
|
+
if (r.isErr()) throw r.error;
|
|
177
|
+
const address = r.value.addressIndex.address;
|
|
178
|
+
|
|
179
|
+
await rpc.sendToAddress(address, '0.1');
|
|
180
|
+
await waitForElectrum();
|
|
181
|
+
|
|
182
|
+
// Refresh wallet and check unconfirmed transactions
|
|
183
|
+
await wallet.refreshWallet({});
|
|
184
|
+
expect(Object.keys(wallet.data.unconfirmedTransactions)).to.have.length(1);
|
|
185
|
+
expect(Object.keys(wallet.data.transactions)).to.have.length(1);
|
|
186
|
+
|
|
187
|
+
// Generate blocks to confirm transaction
|
|
188
|
+
await rpc.generateToAddress(10, await rpc.getNewAddress());
|
|
189
|
+
await waitForElectrum();
|
|
190
|
+
|
|
191
|
+
// Refresh and check confirmed status
|
|
192
|
+
await wallet.refreshWallet({});
|
|
193
|
+
expect(Object.keys(wallet.data.unconfirmedTransactions)).to.have.length(0);
|
|
194
|
+
expect(Object.keys(wallet.data.transactions)).to.have.length(1);
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it('Should receive transaction and emit correct messages', async () => {
|
|
198
|
+
const r = await wallet.getNextAvailableAddress();
|
|
199
|
+
if (r.isErr()) throw r.error;
|
|
200
|
+
const address = r.value.addressIndex.address;
|
|
201
|
+
|
|
202
|
+
// test transactionReceived message
|
|
203
|
+
const receivePromise = ml.waitFor('transactionReceived');
|
|
204
|
+
const amount = 0.1;
|
|
205
|
+
await rpc.sendToAddress(address, amount.toString());
|
|
206
|
+
const txReceivedMessage = await receivePromise;
|
|
207
|
+
expect(txReceivedMessage.transaction.value).to.equal(0.1);
|
|
208
|
+
|
|
209
|
+
// test transactionConfirmed message
|
|
210
|
+
const confirmedPromise = ml.waitFor('transactionConfirmed');
|
|
211
|
+
await rpc.generateToAddress(1, await rpc.getNewAddress());
|
|
212
|
+
await waitForElectrum();
|
|
213
|
+
const txConfirmedMessage = await confirmedPromise;
|
|
214
|
+
expect(txConfirmedMessage.transaction.height).to.be.greaterThan(0);
|
|
215
|
+
});
|
|
216
|
+
});
|
package/tests/storage.test.ts
CHANGED
|
@@ -1,55 +1,58 @@
|
|
|
1
|
-
import * as chai from 'chai';
|
|
2
1
|
import { validateMnemonic } from 'bip39';
|
|
2
|
+
import { expect } from 'chai';
|
|
3
3
|
import net from 'net';
|
|
4
4
|
import tls from 'tls';
|
|
5
|
+
import sinon from 'sinon';
|
|
5
6
|
|
|
6
7
|
import { Wallet } from '../';
|
|
8
|
+
import { deleteDirectory, getData, servers, setData } from '../example/helpers';
|
|
7
9
|
import {
|
|
8
10
|
EAddressType,
|
|
9
11
|
EAvailableNetworks,
|
|
12
|
+
generateMnemonic,
|
|
10
13
|
IGetUtxosResponse,
|
|
11
|
-
Result
|
|
12
|
-
generateMnemonic
|
|
14
|
+
Result
|
|
13
15
|
} from '../src';
|
|
14
16
|
import { TEST_MNEMONIC } from './constants';
|
|
15
|
-
import { deleteDirectory, getData, servers, setData } from '../example/helpers';
|
|
16
17
|
import { EXPECTED_SHARED_RESULTS } from './expected-results';
|
|
17
18
|
|
|
18
|
-
const expect = chai.expect;
|
|
19
|
-
|
|
20
19
|
const testTimeout = 60000;
|
|
21
20
|
|
|
22
21
|
let wallet: Wallet;
|
|
23
22
|
const WALLET_NAME = 'storagetestwallet0';
|
|
24
23
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
const res = await Wallet.create({
|
|
29
|
-
mnemonic: TEST_MNEMONIC,
|
|
30
|
-
network: EAvailableNetworks.testnet,
|
|
31
|
-
name: WALLET_NAME,
|
|
32
|
-
addressType: EAddressType.p2wpkh,
|
|
33
|
-
storage: {
|
|
34
|
-
getData,
|
|
35
|
-
setData
|
|
36
|
-
},
|
|
37
|
-
electrumOptions: {
|
|
38
|
-
servers: servers[EAvailableNetworks.testnet],
|
|
39
|
-
net,
|
|
40
|
-
tls
|
|
41
|
-
}
|
|
42
|
-
});
|
|
43
|
-
if (res.isErr()) {
|
|
44
|
-
console.log('error: ', res.error.message);
|
|
45
|
-
//throw new Error(res.error.message);
|
|
46
|
-
return;
|
|
47
|
-
}
|
|
48
|
-
wallet = res.value;
|
|
49
|
-
});
|
|
24
|
+
const storage = { getData, setData };
|
|
25
|
+
const storageSpy = sinon.spy(storage, 'setData');
|
|
26
|
+
const messageSpy = sinon.spy();
|
|
50
27
|
|
|
51
28
|
describe('Storage Test', async function (): Promise<void> {
|
|
52
29
|
this.timeout(testTimeout);
|
|
30
|
+
|
|
31
|
+
before(async function () {
|
|
32
|
+
this.timeout(testTimeout);
|
|
33
|
+
await deleteDirectory('example/walletData'); // Start test with clean slate.
|
|
34
|
+
const res = await Wallet.create({
|
|
35
|
+
mnemonic: TEST_MNEMONIC,
|
|
36
|
+
network: EAvailableNetworks.testnet,
|
|
37
|
+
name: WALLET_NAME,
|
|
38
|
+
addressType: EAddressType.p2wpkh,
|
|
39
|
+
storage,
|
|
40
|
+
onMessage: messageSpy,
|
|
41
|
+
electrumOptions: {
|
|
42
|
+
servers: servers[EAvailableNetworks.testnet],
|
|
43
|
+
net,
|
|
44
|
+
tls
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
if (res.isErr()) throw res.error;
|
|
48
|
+
wallet = res.value;
|
|
49
|
+
await wallet.refreshWallet({});
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
after(async function () {
|
|
53
|
+
await wallet?.electrum?.disconnect();
|
|
54
|
+
});
|
|
55
|
+
|
|
53
56
|
it('Should successfully create a wallet.', () => {
|
|
54
57
|
expect(wallet).not.to.be.null;
|
|
55
58
|
});
|
|
@@ -100,8 +103,7 @@ describe('Storage Test', async function (): Promise<void> {
|
|
|
100
103
|
|
|
101
104
|
it('Should generate a bech32 receiving address at index 0 via its path', async () => {
|
|
102
105
|
const address = await wallet.getAddressByPath({ path: "m/84'/1'/0'/0/0" });
|
|
103
|
-
|
|
104
|
-
if (address.isErr()) return;
|
|
106
|
+
if (address.isErr()) throw address.error;
|
|
105
107
|
expect(address.value.address).to.equal(
|
|
106
108
|
'tb1qmja98kkd540qtesjqdanfg0ywags845vehfg66'
|
|
107
109
|
);
|
|
@@ -109,8 +111,7 @@ describe('Storage Test', async function (): Promise<void> {
|
|
|
109
111
|
|
|
110
112
|
it('Should generate a segwit change address at index 1 via its path', async () => {
|
|
111
113
|
const address = await wallet.getAddressByPath({ path: "m/49'/1'/0'/1/1" });
|
|
112
|
-
|
|
113
|
-
if (address.isErr()) return;
|
|
114
|
+
if (address.isErr()) throw address.error;
|
|
114
115
|
expect(address.value.address).to.equal(
|
|
115
116
|
'2NDRG1ZGhWMGGNW7Mp58BKcyBs4Hyat8Law'
|
|
116
117
|
);
|
|
@@ -118,8 +119,7 @@ describe('Storage Test', async function (): Promise<void> {
|
|
|
118
119
|
|
|
119
120
|
it('Should generate a testnet legacy receiving address at index 5 via its path', async () => {
|
|
120
121
|
const address = await wallet.getAddressByPath({ path: "m/44'/1'/0'/0/5" });
|
|
121
|
-
|
|
122
|
-
if (address.isErr()) return;
|
|
122
|
+
if (address.isErr()) throw address.error;
|
|
123
123
|
expect(address.value.address).to.equal(
|
|
124
124
|
'mohdq3fadTtT4uSH4oNr4F1Dp3YM4pR3VF'
|
|
125
125
|
);
|
|
@@ -127,8 +127,7 @@ describe('Storage Test', async function (): Promise<void> {
|
|
|
127
127
|
|
|
128
128
|
it('getNextAvailableAddress: Should return the next available address/change index and the last used address/change index', async () => {
|
|
129
129
|
const r = await wallet.getNextAvailableAddress();
|
|
130
|
-
|
|
131
|
-
if (r.isErr()) return;
|
|
130
|
+
if (r.isErr()) throw r.error;
|
|
132
131
|
expect(r.value).to.deep.equal(
|
|
133
132
|
EXPECTED_SHARED_RESULTS.getNextAvailableAddress
|
|
134
133
|
);
|
|
@@ -136,8 +135,7 @@ describe('Storage Test', async function (): Promise<void> {
|
|
|
136
135
|
|
|
137
136
|
it("Should return available UTXO's", async () => {
|
|
138
137
|
const getUtxosRes: Result<IGetUtxosResponse> = await wallet.getUtxos({});
|
|
139
|
-
|
|
140
|
-
if (getUtxosRes.isErr()) return;
|
|
138
|
+
if (getUtxosRes.isErr()) throw getUtxosRes.error;
|
|
141
139
|
expect(Array.isArray(getUtxosRes.value.utxos)).to.equal(true);
|
|
142
140
|
expect(getUtxosRes.value.utxos.length).to.equal(3);
|
|
143
141
|
expect(getUtxosRes.value.balance).to.equal(5855);
|
|
@@ -152,6 +150,21 @@ describe('Storage Test', async function (): Promise<void> {
|
|
|
152
150
|
);
|
|
153
151
|
});
|
|
154
152
|
|
|
153
|
+
it('Should successfully stop the wallet', async () => {
|
|
154
|
+
wallet.refreshWallet(); // start wallet refresh in the background
|
|
155
|
+
const r = await wallet.stop();
|
|
156
|
+
if (r.isErr()) throw r.error;
|
|
157
|
+
storageSpy.resetHistory();
|
|
158
|
+
messageSpy.resetHistory();
|
|
159
|
+
// try to force the wallet to update it's data
|
|
160
|
+
wallet.feeEstimates.timestamp = 0;
|
|
161
|
+
await wallet.updateFeeEstimates(true);
|
|
162
|
+
await wallet.refreshWallet();
|
|
163
|
+
// make sure that the wallet did not call setData or onMessage
|
|
164
|
+
expect(storageSpy.called).to.equal(false);
|
|
165
|
+
expect(messageSpy.called).to.equal(false);
|
|
166
|
+
});
|
|
167
|
+
|
|
155
168
|
// it('Attempts to create a new wallet using the same name of an existing wallet in storage.', async () => {
|
|
156
169
|
// const createRes = await Wallet.create({
|
|
157
170
|
// mnemonic: generateMnemonic(),
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { expect } from 'chai';
|
|
2
2
|
import net from 'net';
|
|
3
3
|
import tls from 'tls';
|
|
4
4
|
|
|
@@ -8,38 +8,37 @@ import {
|
|
|
8
8
|
ISweepPrivateKeyRes,
|
|
9
9
|
Wallet
|
|
10
10
|
} from '../';
|
|
11
|
+
import { servers } from '../example/helpers';
|
|
11
12
|
import { EAvailableNetworks, Result } from '../src';
|
|
12
13
|
import { TRANSACTION_TEST_MNEMONIC } from './constants';
|
|
13
|
-
import { servers } from '../example/helpers';
|
|
14
14
|
import { EXPECTED_TRANSACTION_RESULTS } from './expected-results';
|
|
15
15
|
|
|
16
|
-
const expect = chai.expect;
|
|
17
|
-
|
|
18
16
|
const testTimeout = 60000;
|
|
19
17
|
|
|
20
18
|
let wallet: Wallet;
|
|
21
19
|
|
|
22
|
-
|
|
20
|
+
describe('Transaction Test', async function (): Promise<void> {
|
|
23
21
|
this.timeout(testTimeout);
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
22
|
+
|
|
23
|
+
before(async function () {
|
|
24
|
+
this.timeout(testTimeout);
|
|
25
|
+
const res = await Wallet.create({
|
|
26
|
+
mnemonic: TRANSACTION_TEST_MNEMONIC,
|
|
27
|
+
network: EAvailableNetworks.testnet,
|
|
28
|
+
electrumOptions: {
|
|
29
|
+
servers: servers[EAvailableNetworks.testnet],
|
|
30
|
+
net,
|
|
31
|
+
tls
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
if (res.isErr()) throw res.error;
|
|
35
|
+
wallet = res.value;
|
|
36
|
+
await wallet.refreshWallet({});
|
|
32
37
|
});
|
|
33
|
-
if (res.isErr()) {
|
|
34
|
-
console.log('error: ', res.error.message);
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
wallet = res.value;
|
|
38
|
-
await wallet.refreshWallet({});
|
|
39
|
-
});
|
|
40
38
|
|
|
41
|
-
|
|
42
|
-
|
|
39
|
+
after(async function () {
|
|
40
|
+
await wallet?.electrum?.disconnect();
|
|
41
|
+
});
|
|
43
42
|
|
|
44
43
|
it('Should successfully create a wallet.', (): void => {
|
|
45
44
|
expect(wallet).not.to.be.null;
|
|
@@ -53,9 +52,7 @@ describe('Transaction Test', async function (): Promise<void> {
|
|
|
53
52
|
|
|
54
53
|
it('Should successfully return fee information.', (): void => {
|
|
55
54
|
const feeInfo = wallet.getFeeInfo({ satsPerByte: 5 });
|
|
56
|
-
|
|
57
|
-
if (feeInfo.isErr()) return;
|
|
58
|
-
expect(feeInfo).not.to.be.null;
|
|
55
|
+
if (feeInfo.isErr()) throw feeInfo.error;
|
|
59
56
|
expect(feeInfo.value.satsPerByte).to.equal(5);
|
|
60
57
|
expect(feeInfo.value.totalFee).to.equal(830);
|
|
61
58
|
expect(feeInfo.value.transactionByteCount).to.equal(166);
|
|
@@ -72,15 +69,13 @@ describe('Transaction Test', async function (): Promise<void> {
|
|
|
72
69
|
shuffleOutputs: false,
|
|
73
70
|
rbf: true
|
|
74
71
|
});
|
|
75
|
-
|
|
76
|
-
if (sendRes.isErr()) return;
|
|
72
|
+
if (sendRes.isErr()) throw sendRes.error;
|
|
77
73
|
expect(sendRes.value).to.equal(
|
|
78
74
|
'020000000001014b44d379e48a8100d1c26f7220b8bbf7a4894ff015d5bc4064a28d08d25d808d0000000000000000000288130000000000001600143f1a7a1802e377d01602acf1cad403368ed3bb89ba21010000000000160014a6bd95db4dd6979189cad389daad006e236f4ba802483045022100dd709b656c271c7e2ab4c83e0245b9b8d9096a1c7a33eddc9a32113f436851d9022033f8e5cb016ae4c440badfa34e438ada7bea2cdd36e782c136e516350b502bca012102e86b90924963237c59e5389aab1cc5350c114549d1c5e7186a56ef33aea24ff900000000'
|
|
79
75
|
);
|
|
80
76
|
|
|
81
77
|
const decodeRes = decodeRawTransaction(sendRes.value, wallet.network);
|
|
82
|
-
|
|
83
|
-
if (decodeRes.isErr()) return;
|
|
78
|
+
if (decodeRes.isErr()) throw decodeRes.error;
|
|
84
79
|
expect(decodeRes.value).to.deep.equal(
|
|
85
80
|
EXPECTED_TRANSACTION_RESULTS.decodeRawTransaction
|
|
86
81
|
);
|
|
@@ -104,15 +99,13 @@ describe('Transaction Test', async function (): Promise<void> {
|
|
|
104
99
|
satsPerByte: 5,
|
|
105
100
|
rbf: true
|
|
106
101
|
});
|
|
107
|
-
|
|
108
|
-
if (sendManyRes.isErr()) return;
|
|
102
|
+
if (sendManyRes.isErr()) throw sendManyRes.error;
|
|
109
103
|
expect(sendManyRes.value).to.equal(
|
|
110
104
|
'020000000001014b44d379e48a8100d1c26f7220b8bbf7a4894ff015d5bc4064a28d08d25d808d000000000000000000038813000000000000160014a6b760eaa96a9ba91bae9465dfc4eabe711e1d6770170000000000001600146bcf920595e09b5d8f7b8d03b3694ad3057572892c0a010000000000160014a6bd95db4dd6979189cad389daad006e236f4ba80247304402207e7b5de41cb9bf33e434c2136390bf40d6b6552b69234a62f6bf48b89f0d44ac022056121c9a9d79d9d84896c9896a6fddb358b48667021ff2832b5c5871d90b701a012102e86b90924963237c59e5389aab1cc5350c114549d1c5e7186a56ef33aea24ff900000000'
|
|
111
105
|
);
|
|
112
106
|
|
|
113
107
|
const decodeRes = decodeRawTransaction(sendManyRes.value, wallet.network);
|
|
114
|
-
|
|
115
|
-
if (decodeRes.isErr()) return;
|
|
108
|
+
if (decodeRes.isErr()) throw decodeRes.error;
|
|
116
109
|
expect(decodeRes.value).to.deep.equal(
|
|
117
110
|
EXPECTED_TRANSACTION_RESULTS.decodeRawSendManyTransaction
|
|
118
111
|
);
|
|
@@ -126,7 +119,7 @@ describe('Transaction Test', async function (): Promise<void> {
|
|
|
126
119
|
satsPerByte: 5,
|
|
127
120
|
broadcast: false
|
|
128
121
|
});
|
|
129
|
-
if (sweepPrivateKey.isErr())
|
|
122
|
+
if (sweepPrivateKey.isErr()) throw sweepPrivateKey.error;
|
|
130
123
|
expect(sweepPrivateKey.value.id).to.equal(
|
|
131
124
|
'7fbef762e16676715bc94693a495923273259aa1190a5bf97bf18ab676393af5'
|
|
132
125
|
);
|
|
@@ -145,7 +138,7 @@ describe('Transaction Test', async function (): Promise<void> {
|
|
|
145
138
|
broadcast: false,
|
|
146
139
|
combineWithWalletUtxos: true
|
|
147
140
|
});
|
|
148
|
-
if (sweepPrivateKey.isErr())
|
|
141
|
+
if (sweepPrivateKey.isErr()) throw sweepPrivateKey.error;
|
|
149
142
|
expect(sweepPrivateKey.value.id).to.equal(
|
|
150
143
|
'ea6677d40bbf44dbc2d19d3765fd440aa2344f928d724dc021884fc5984e91ff'
|
|
151
144
|
);
|
|
@@ -166,14 +159,13 @@ describe('Transaction Test', async function (): Promise<void> {
|
|
|
166
159
|
}
|
|
167
160
|
]
|
|
168
161
|
});
|
|
169
|
-
|
|
170
|
-
|
|
162
|
+
if (setupResponse.isErr()) throw setupResponse.error;
|
|
163
|
+
|
|
171
164
|
const privateKeyInfo: Result<IPrivateKeyInfo> =
|
|
172
165
|
await wallet.getPrivateKeyInfo(
|
|
173
166
|
'cUVwTLfHYrF7KGdTVU4AcP4yjtRTH3Y2BbTKHJbp2tsHDfpE8Zq5'
|
|
174
167
|
);
|
|
175
|
-
|
|
176
|
-
if (privateKeyInfo.isErr()) return;
|
|
168
|
+
if (privateKeyInfo.isErr()) throw privateKeyInfo.error;
|
|
177
169
|
const utxos = privateKeyInfo.value.utxos;
|
|
178
170
|
const keyPair = privateKeyInfo.value.keyPair;
|
|
179
171
|
expect(Array.isArray(utxos)).to.equal(true);
|
|
@@ -185,13 +177,11 @@ describe('Transaction Test', async function (): Promise<void> {
|
|
|
185
177
|
inputs: utxos,
|
|
186
178
|
keyPair
|
|
187
179
|
});
|
|
188
|
-
|
|
189
|
-
if (addExternRes.isErr()) return;
|
|
180
|
+
if (addExternRes.isErr()) throw addExternRes.error;
|
|
190
181
|
const createTransaction = await wallet.transaction.createTransaction({
|
|
191
182
|
shuffleOutputs: false
|
|
192
183
|
});
|
|
193
|
-
|
|
194
|
-
if (createTransaction.isErr()) return;
|
|
184
|
+
if (createTransaction.isErr()) throw createTransaction.error;
|
|
195
185
|
expect(createTransaction.value.id).to.equal(
|
|
196
186
|
'c0b4a54d9b4f88a32c7d7349f03c71c84a16b99b5c82159474768e734afecd81'
|
|
197
187
|
);
|
package/tests/utils.ts
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import net from 'net';
|
|
2
2
|
import BitcoinJsonRpc from 'bitcoin-json-rpc';
|
|
3
3
|
import ElectrumClient from 'bw-electrum-client';
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
EProtocol,
|
|
6
|
+
sleep,
|
|
7
|
+
TMessageDataMap,
|
|
8
|
+
TMessageKeys,
|
|
9
|
+
TOnMessage
|
|
10
|
+
} from '../src';
|
|
5
11
|
|
|
6
12
|
export const bitcoinURL = 'http://polaruser:polarpass@127.0.0.1:43782';
|
|
7
13
|
export const electrumHost = '127.0.0.1';
|
|
@@ -44,7 +50,7 @@ export const initWaitForElectrumToSync = async (
|
|
|
44
50
|
|
|
45
51
|
const waitForElectrum = (): Promise<void> => {
|
|
46
52
|
return new Promise(async (resolve, reject) => {
|
|
47
|
-
let count;
|
|
53
|
+
let count: number;
|
|
48
54
|
let running = true;
|
|
49
55
|
|
|
50
56
|
const timer = setTimeout(async () => {
|
|
@@ -82,3 +88,55 @@ export const initWaitForElectrumToSync = async (
|
|
|
82
88
|
|
|
83
89
|
return waitForElectrum;
|
|
84
90
|
};
|
|
91
|
+
|
|
92
|
+
type TMessage = {
|
|
93
|
+
key: TMessageKeys;
|
|
94
|
+
data: TMessageDataMap[keyof TMessageDataMap];
|
|
95
|
+
timestamp: number;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
export class MessageListener {
|
|
99
|
+
public messages: TMessage[] = [];
|
|
100
|
+
private resolvers: ((message: TMessage) => void)[] = [];
|
|
101
|
+
|
|
102
|
+
onMessage: TOnMessage = (key, data) => {
|
|
103
|
+
const message: TMessage = {
|
|
104
|
+
key,
|
|
105
|
+
data,
|
|
106
|
+
timestamp: Date.now()
|
|
107
|
+
};
|
|
108
|
+
this.messages.push(message);
|
|
109
|
+
this.resolvers.forEach((resolve) => resolve(message));
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
waitFor<K extends TMessageKeys>(
|
|
113
|
+
messageKey: K,
|
|
114
|
+
timeout = 20000
|
|
115
|
+
): Promise<TMessageDataMap[K]> {
|
|
116
|
+
// Check if message already received
|
|
117
|
+
const existingMessage = this.messages.find((msg) => msg.key === messageKey);
|
|
118
|
+
if (existingMessage) {
|
|
119
|
+
return Promise.resolve(existingMessage.data as TMessageDataMap[K]);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Wait for new message
|
|
123
|
+
return new Promise((resolve, reject) => {
|
|
124
|
+
const timer = setTimeout(() => {
|
|
125
|
+
reject(new Error('Timeout waiting for message'));
|
|
126
|
+
}, timeout);
|
|
127
|
+
|
|
128
|
+
const resolver = (msg: TMessage): void => {
|
|
129
|
+
if (msg.key === messageKey) {
|
|
130
|
+
clearTimeout(timer);
|
|
131
|
+
resolve(msg.data as TMessageDataMap[K]);
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
this.resolvers.push(resolver);
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
clear(): void {
|
|
139
|
+
this.messages = [];
|
|
140
|
+
this.resolvers = [];
|
|
141
|
+
}
|
|
142
|
+
}
|