Completed
Push — master ( 4c84df...04fe6f )
by thomas
51s
created

wallet.test.js ➔ ... ➔ wallet.getNewAddress   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
c 1
b 0
f 0
nc 1
dl 0
loc 6
rs 9.4285
nop 2
1
/* jshint -W101, -W098 */
2
/* global window */
3
var _ = require('lodash');
4
var blocktrail = require('../');
5
var Wallet = blocktrail.Wallet;
6
var assert = require('assert');
7
var crypto = require('crypto');
8
var async = require('async');
9
var bitcoin = require('bitcoinjs-lib');
10
var bip39 = require("bip39");
11
12
var WAIT_FOR_TX_PROCESSED = process.env.BLOCKTRAIL_WAIT_FOR_TX || 300;
13
14
/**
15
 *
16
 * @param network
17
 * @param testnet
18
 * @returns {*}
19
 * @private
20
 */
21
function _createApiClient(network, testnet) {
22
    return blocktrail.BlocktrailSDK({
23
        apiKey : process.env.BLOCKTRAIL_SDK_APIKEY || window.BLOCKTRAIL_SDK_APIKEY || "EXAMPLE_BLOCKTRAIL_SDK_NODEJS_APIKEY",
24
        apiSecret : process.env.BLOCKTRAIL_SDK_APISECRET || window.BLOCKTRAIL_SDK_APISECRET || "EXAMPLE_BLOCKTRAIL_SDK_NODEJS_APISECRET",
25
        network: network,
26
        testnet : testnet
27 View Code Duplication
    });
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
28
}
29
30
/**
31
 * @type APIClient
32
 */
33
var client = _createApiClient("BTC", true);
34
35
var TRANSACTION_TEST_WALLET_PRIMARY_MNEMONIC = "give pause forget seed dance crawl situate hole keen",
36
    TRANSACTION_TEST_WALLET_BACKUP_MNEMONIC = "give pause forget seed dance crawl situate hole give",
37
    TRANSACTION_TEST_WALLET_PASSWORD = "password";
38
39
var _createTestWallet = function(identifier, passphrase, primaryMnemonic, backupMnemonic, segwit, cb) {
40
    var keyIndex = 9999;
41
    var network = client.testnet ? bitcoin.networks.testnet : bitcoin.networks.bitcoin;
42
43
    var primarySeed = bip39.mnemonicToSeed(primaryMnemonic, passphrase);
44
    var primaryPrivateKey = bitcoin.HDNode.fromSeedBuffer(primarySeed, network);
45
46
    var backupSeed = bip39.mnemonicToSeed(backupMnemonic, "");
47
    var backupPrivateKey = bitcoin.HDNode.fromSeedBuffer(backupSeed, network);
48
    var backupPublicKey = backupPrivateKey.neutered();
49
50
    var checksum = primaryPrivateKey.getAddress();
51
    var primaryPublicKey = primaryPrivateKey.deriveHardened(keyIndex).neutered();
52
53
    client.storeNewWalletV1(
54
        identifier,
55
        [primaryPublicKey.toBase58(), "M/" + keyIndex + "'"],
56
        [backupPublicKey.toBase58(), "M"],
57
        primaryMnemonic,
58
        checksum,
59
        keyIndex,
60
        segwit
61
    ).then(function(result) {
62
        var blocktrailPublicKeys = _.mapValues(result.blocktrail_public_keys, function(blocktrailPublicKey) {
63
            return bitcoin.HDNode.fromBase58(blocktrailPublicKey[0], network);
64
        });
65
66
        var wallet = new blocktrail.Wallet(
67
            client,
68
            identifier,
69
            blocktrail.Wallet.WALLET_VERSION_V1,
70
            primaryMnemonic,
71
            null,
72
            null,
73
            {keyIndex: primaryPublicKey},
74
            backupPublicKey,
75
            blocktrailPublicKeys,
76
            keyIndex,
77
            result.segwit || 0,
78
            client.testnet,
79
            checksum
80
        );
81
82
        wallet.unlock({
83
            passphrase: passphrase
84
        }, function(err) {
85
            cb(err, wallet);
86
        });
87
88
    }, function(err) {
89
        return cb(err);
90
    });
91
};
92
93
var createDiscoveryTestWallet = function(identifier, passphrase, cb) {
94
    var primaryMnemonic = "give pause forget seed dance crawl situate hole kingdom";
95
    var backupMnemonic = "give pause forget seed dance crawl situate hole course";
96
97
    return _createTestWallet(identifier, passphrase, primaryMnemonic, backupMnemonic, false, cb);
98
};
99
100
var createTransactionTestWallet = function(identifier, segwit, cb) {
101
    return _createTestWallet(
102
        identifier,
103
        TRANSACTION_TEST_WALLET_PASSWORD,
104
        TRANSACTION_TEST_WALLET_PRIMARY_MNEMONIC,
105
        TRANSACTION_TEST_WALLET_BACKUP_MNEMONIC,
106
        segwit,
107
        cb
108
    );
109
};
110
111
var createRecoveryTestWallet = function(identifier, passphrase, cb) {
112
    var primaryMnemonic = "give pause forget seed dance crawl situate hole join";
113
    var backupMnemonic = "give pause forget seed dance crawl situate hole crater";
114
115
    return _createTestWallet(identifier, passphrase, primaryMnemonic, backupMnemonic, false, cb);
116
};
117
118
describe('Initialize with check_backup_key', function() {
119
    it('rejects invalid inputs', function(cb) {
120
        try {
121
            client.initWallet({
122
                identifier: "unittest-transaction",
123
                password: "password",
124
                check_backup_key: []
125
            });
126
            assert(false);
127
        } catch (e) {
128
            assert.equal("Invalid input, must provide the backup key as a string (the xpub)", e.message);
129
        }
130
        cb();
131
    });
132
133
    it('checks against the string', function(cb) {
134
        client.initWallet({
135
            identifier: "unittest-transaction",
136
            password: "password",
137
            check_backup_key: 'for demonstration purposes only'
138
        }, function(err, _wallet) {
0 ignored issues
show
Unused Code introduced by
The parameter _wallet is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
139
            assert.ok(err);
140
            assert.equal("Backup key returned from server didn't match our own copy", err.message);
141
            cb();
142
        });
143
    });
144
145
    it('allows if the backup key matches', function(cb) {
146
        // You wouldn't keep your backup seed in your code,
147
        // dump it from the wallet upon generation
148
149
        var backupSeed = bip39.mnemonicToSeed(TRANSACTION_TEST_WALLET_BACKUP_MNEMONIC, "");
150
        var backupPrivateKey = bitcoin.HDNode.fromSeedBuffer(backupSeed, bitcoin.networks.testnet);
151
        var backupPublicKey = backupPrivateKey.neutered();
152
        var xpub = backupPublicKey.toBase58();
153
154
        // Would be saves as a string in code..
155
        client.initWallet({
156
            identifier: "unittest-transaction",
157
            password: "password",
158
            check_backup_key: xpub
159
        }, function(err, _wallet) {
160
            assert.ifError(err);
161
            assert.ok(_wallet);
162
            cb();
163
        });
164
    });
165
});
166
167
/**
168
 * Test operations on v2 and v3 wallets.
169
 * Also tests the default, encouraging to look at this test if it changes again.
170
 */
171
[
172
  blocktrail.Wallet.WALLET_VERSION_V2,
173
  blocktrail.Wallet.WALLET_VERSION_V3,
174
  null /* test our assumed default version */
175
].map(function(walletVersion) {
176
    var assumedDefault = blocktrail.Wallet.WALLET_VERSION_V3;
177
    describe('test new blank wallet, ' + walletVersion, function() {
178
        var myIdentifier = "nodejs-sdk-" + crypto.randomBytes(24).toString('hex');
179
        var wallet;
180
181
        after(function(cb) {
182
            if (wallet) {
183
                wallet.deleteWallet(true, function(err, result) {
0 ignored issues
show
Unused Code introduced by
The parameter result is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
Unused Code introduced by
The parameter err is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
184
                    cb();
185
                });
186
            } else {
187
                cb();
188
            }
189
        });
190
191
        it("shouldn't already exist", function(cb) {
192
            client.initWallet({
193
                identifier: myIdentifier,
194
                readOnly: true
195
            }, function(err, wallet) {
196
                assert.ok(err);
197
                assert.ok(!wallet, "wallet with random ID [" + myIdentifier + "] already exists...");
198
199
                cb();
200
            });
201
        });
202
203
        it("should be created", function(cb) {
204
            var progress = [];
205
            var cnf = {
206
                identifier: myIdentifier,
207
                passphrase: "password",
208
                keyIndex: 9999
209
            };
210
211
            var expectedVersion = assumedDefault;
212
            if (walletVersion !== null) {
213
                cnf.walletVersion = walletVersion;
214
                expectedVersion = walletVersion;
215
            }
216
217
            client.createNewWallet(cnf, function(err, _wallet, backupInfo) {
0 ignored issues
show
Unused Code introduced by
The parameter backupInfo is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
218
                assert.ifError(err);
219
                assert.ok(_wallet);
220
221
                wallet = _wallet;
222
                assert.equal(wallet.walletVersion, expectedVersion);
223
                assert.equal(wallet.identifier, myIdentifier);
224
                assert.equal(wallet.getBlocktrailPublicKey("M/9999'").toBase58(), "tpubD9q6vq9zdP3gbhpjs7n2TRvT7h4PeBhxg1Kv9jEc1XAss7429VenxvQTsJaZhzTk54gnsHRpgeeNMbm1QTag4Wf1QpQ3gy221GDuUCxgfeZ");
225
226
                assert.deepEqual(progress, [
227
                    blocktrail.CREATE_WALLET_PROGRESS_START,
228
                    blocktrail.CREATE_WALLET_PROGRESS_ENCRYPT_SECRET,
229
                    blocktrail.CREATE_WALLET_PROGRESS_ENCRYPT_PRIMARY,
230
                    blocktrail.CREATE_WALLET_PROGRESS_ENCRYPT_RECOVERY,
231
                    blocktrail.CREATE_WALLET_PROGRESS_PRIMARY,
232
                    blocktrail.CREATE_WALLET_PROGRESS_BACKUP,
233
                    blocktrail.CREATE_WALLET_PROGRESS_SUBMIT,
234
                    blocktrail.CREATE_WALLET_PROGRESS_INIT,
235
                    blocktrail.CREATE_WALLET_PROGRESS_DONE
236
                ]);
237
238
                cb();
239
            })
240
            .progress(function(p) { progress.push(p); });
241
        });
242
243
        it("should lock", function(cb) {
244
            assert(!wallet.locked);
245
            wallet.lock();
246
            assert(wallet.locked);
247
            cb();
248
        });
249
250
        it("should init", function(cb) {
251
            client.initWallet({
252
                identifier: myIdentifier,
253
                readOnly: true
254
            }, function(err, _wallet) {
255
                assert.ifError(err);
256
                assert.ok(_wallet);
257
258
                wallet = _wallet;
259
260
                cb();
261
            });
262
        });
263
264
        it("should have a 0 balance", function(cb) {
265
            wallet.getBalance(function(err, confirmed, unconfirmed) {
266
                assert.ifError(err);
267
                assert.equal(confirmed, 0);
268
                assert.equal(unconfirmed, 0);
269
270
                cb();
271
            });
272
        });
273
274
        it("shouldn't be able to pay when locked", function(cb) {
275
            wallet.pay({
276
                "2N6Fg6T74Fcv1JQ8FkPJMs8mYmbm9kitTxy": blocktrail.toSatoshi(0.001)
277
            }, function(err, txHash) {
0 ignored issues
show
Unused Code introduced by
The parameter txHash is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
278
                assert.ok(!!err && err.message.match(/unlocked/));
279
                assert.ok(err instanceof blocktrail.WalletLockedError);
280
281
                cb();
282
            });
283
        });
284
285
        it("shouldn't be able to upgrade when locked", function(cb) {
286
            wallet.upgradeKeyIndex(10000, function(err) {
287
                assert.ok(!!err && err.message.match(/unlocked/));
288
                assert.ok(err instanceof blocktrail.WalletLockedError);
289
290
                cb();
291
            });
292
        });
293
294
        it("should unlock", function(cb) {
295
            wallet.unlock({password: "password"}, function(err) {
296
                assert.ifError(err);
297
298
                cb();
299
            });
300
        });
301
302
        it("should be able to unlock with secret", function(cb) {
303
            var secret = wallet.secret;
304
305
            wallet.lock();
306
            wallet.unlock({secret: secret}, function(err) {
307
                assert.ifError(err);
308
                cb();
309
            });
310
        });
311
312
        it("shouldn't be able to pay when unlocked (because of no balance)", function(cb) {
313
            wallet.pay({
314
                "2N6Fg6T74Fcv1JQ8FkPJMs8mYmbm9kitTxy": blocktrail.toSatoshi(0.001)
315
            }, function(err, txHash) {
0 ignored issues
show
Unused Code introduced by
The parameter txHash is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
316
                assert.ok(!!err && err.message.match(/balance/));
317
318
                cb();
319
            });
320
        });
321
322
        it("should be able to upgrade when unlocked", function(cb) {
323
            wallet.upgradeKeyIndex(10000, function(err) {
324
                assert.ifError(err);
325
326
                cb();
327
            });
328
        });
329
330
        it("should be able to password change", function(cb) {
331
            wallet.passwordChange("password2", function(err) {
332
                assert.ifError(err);
333
334
                client.initWallet({
335
                    identifier: myIdentifier,
336
                    password: "password2"
337
                }, function(err, _wallet) {
338
                    assert.ifError(err);
339
                    assert.ok(_wallet);
340
341
                    wallet = _wallet;
342
343
                    cb();
344
                });
345
            });
346
        });
347
348
        [
349
            ['', 'string'],
350
            [false, 'string'],
351
            [true, 'boolean']
352
        ].map(function(fixture) {
353
            var invalidInput = fixture[0];
354
            var type = fixture[1];
355
            it('refuses to derive with invalid chain index variable ' + type, function(cb) {
356
                wallet.getNewAddress(invalidInput, function(err, res) {
0 ignored issues
show
Unused Code introduced by
The parameter res is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
357
                    assert.ok(!!err && err.message.match(/chain index/));
358
                    cb();
359
                });
360
            });
361
        });
362
    });
363
});
364
365
/**
366
 * Test operations on v2 and v3 wallets.
367
 */
368
[
369
    blocktrail.Wallet.WALLET_VERSION_V1,
370
    blocktrail.Wallet.WALLET_VERSION_V2,
371
    blocktrail.Wallet.WALLET_VERSION_V3
372
].map(function(walletVersion) {
373
    var primarySeed = bip39.mnemonicToSeed(TRANSACTION_TEST_WALLET_PRIMARY_MNEMONIC, TRANSACTION_TEST_WALLET_PASSWORD);
374
375
    describe('test input errors, ' + walletVersion, function() {
376
        it("shouldn't allow primaryPrivateKey in creation", function(cb) {
377
            var myIdentifier = "nodejs-sdk-" + crypto.randomBytes(24).toString('hex');
378
            var primaryPrivateKey = bitcoin.HDNode.fromSeedBuffer(primarySeed, bitcoin.networks.testnet);
379
380
            client.createNewWallet({
381
                identifier: myIdentifier,
382
                passphrase: "password",
383
                primaryPrivateKey: primaryPrivateKey,
384
                walletVersion: walletVersion,
385
                keyIndex: 9999
386
            }, function(err, wallet) {
0 ignored issues
show
Unused Code introduced by
The parameter wallet is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
387
                assert.ok(!!err, "should error");
388
389
                cb();
390
            });
391
        });
392
393
        it("shouldn't allow unlocking with primaryPrivateKey", function(cb) {
394
            client.createNewWallet({
395
                identifier: "unittest-transaction-inputerr-" + walletVersion,
396
                primarySeed: primarySeed,
397
                walletVersion: walletVersion,
398
                keyIndex: 9999
399
            }).then(function(r) {
400
                var wallet = r[0];
401
                wallet.lock();
402
                return wallet;
403
            }, function(err) {
404
                assert.ok(err.message.match(/already exists/));
405
406
                return client.initWallet({
407
                    identifier: "unittest-transaction-inputerr-" + walletVersion,
408
                    readOnly: true
409
                });
410
            }).then(function(wallet) {
411
                assert.equal(wallet.getBlocktrailPublicKey("M/9999'").toBase58(), "tpubD9q6vq9zdP3gbhpjs7n2TRvT7h4PeBhxg1Kv9jEc1XAss7429VenxvQTsJaZhzTk54gnsHRpgeeNMbm1QTag4Wf1QpQ3gy221GDuUCxgfeZ");
412
413
                return wallet.unlock({primaryPrivateKey: bitcoin.HDNode.fromSeedBuffer(primarySeed, bitcoin.networks.testnet)})
414
                    .then(function() {
415
                        return;
0 ignored issues
show
Unused Code introduced by
This return has no effect and can be removed.
Loading history...
416
                    }, function(err) {
417
                        return err;
418
                    });
419
            })
420
                .then(function(err) {
421
                    assert.ok(!!err, "should error");
422
                    cb();
423
                })
424
                .done();
425
        });
426
    });
427
});
428
429
/**
430
 * Test upgrade to V3 from V1 and V2
431
 */
432
[
433
    blocktrail.Wallet.WALLET_VERSION_V1,
434
    blocktrail.Wallet.WALLET_VERSION_V2
435
].map(function(walletVersion) {
436
    describe("upgrade to V3 from " + walletVersion, function() {
437
        var myIdentifier = "nodejs-sdk-" + crypto.randomBytes(24).toString('hex');
438
        var passphrase = "password";
439
        var wallet;
440
441
        after(function(cb) {
442
            if (wallet) {
443
                wallet.deleteWallet(true, function(err, result) {
444
                    console.log(err, result);
0 ignored issues
show
Debugging Code introduced by
console.log looks like debug code. Are you sure you do not want to remove it?
Loading history...
445
                    cb();
446
                });
447
            } else {
448
                cb();
449
            }
450
        });
451
452
        it("can upgrade", function() {
453
            var addr;
454
            return client.createNewWallet({
455
                identifier: myIdentifier,
456
                passphrase: passphrase,
457
                walletVersion: walletVersion,
458
                keyIndex: 9999
459
            })
460
                .then(function(r) {
461
                    return r[0];
462
                })
463
                .then(function(_wallet) {
464
                    wallet = _wallet;
465
                    addr = wallet.getAddressByPath("M/9999'/0/0");
466
467
                    return wallet;
468
                })
469
                .then(function(wallet) {
470
                    var progress = [];
471
472
                    return wallet.upgradeToV3(passphrase)
473
                        .progress(function(p) {
474
                            progress.push(p);
475
                        })
476
                        .then(function() {
477
                            assert(progress.length);
478
                            return wallet;
479
                        });
480
                })
481
                .then(function(wallet) {
482
                    assert.equal(addr, wallet.getAddressByPath("M/9999'/0/0"));
483
                });
484
        });
485
486
        it("can unlock with secret", function() {
487
            var secret = wallet.secret;
488
            wallet.lock();
489
            return wallet.unlock({secret: secret});
490
        });
491
492
        it("can init after upgrade", function() {
493
            return client.initWallet({
494
                identifier: myIdentifier,
495
                passphrase: passphrase,
496
                keyIndex: 9999
497
            });
498
        });
499
    });
500
});
501
502
describe('test new blank wallet, v1', function() {
503
    var myIdentifier = "nodejs-sdk-" + crypto.randomBytes(24).toString('hex');
504
    var wallet;
505
506
    after(function(cb) {
507
        if (wallet) {
508
            wallet.deleteWallet(true, function(err, result) {
0 ignored issues
show
Unused Code introduced by
The parameter err is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
Unused Code introduced by
The parameter result is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
509
                cb();
510
            });
511
        } else {
512
            cb();
513
        }
514
    });
515
516
    it("shouldn't already exist", function(cb) {
517
        client.initWallet({
518
            identifier: myIdentifier,
519
            readOnly: true
520
        }, function(err, wallet) {
521
            assert.ok(err);
522
            assert.ok(!wallet, "wallet with random ID [" + myIdentifier + "] already exists...");
523
524
            cb();
525
        });
526
    });
527
528
    it("should be created", function(cb) {
529
        var progress = [];
530
531
        client.createNewWallet({
532
                identifier: myIdentifier,
533
                passphrase: "password",
534
                keyIndex: 9999,
535
                walletVersion: blocktrail.Wallet.WALLET_VERSION_V1
536
            }, function(err, _wallet) {
537
                assert.ifError(err);
538
                assert.ok(_wallet);
539
540
                wallet = _wallet;
541
542
                assert.equal(wallet.identifier, myIdentifier);
543
                assert.equal(wallet.getBlocktrailPublicKey("M/9999'").toBase58(), "tpubD9q6vq9zdP3gbhpjs7n2TRvT7h4PeBhxg1Kv9jEc1XAss7429VenxvQTsJaZhzTk54gnsHRpgeeNMbm1QTag4Wf1QpQ3gy221GDuUCxgfeZ");
544
545
                assert.deepEqual(progress, [
546
                    blocktrail.CREATE_WALLET_PROGRESS_START,
547
                    blocktrail.CREATE_WALLET_PROGRESS_PRIMARY,
548
                    blocktrail.CREATE_WALLET_PROGRESS_BACKUP,
549
                    blocktrail.CREATE_WALLET_PROGRESS_SUBMIT,
550
                    blocktrail.CREATE_WALLET_PROGRESS_INIT,
551
                    blocktrail.CREATE_WALLET_PROGRESS_DONE
552
                ]);
553
554
                cb();
555
            }
556
        ).progress(function(p) { progress.push(p); });
557
    });
558
559
    it("should lock", function(cb) {
560
        assert(!wallet.locked);
561
        wallet.lock();
562
        assert(wallet.locked);
563
        cb();
564
    });
565
566
    it("should init", function(cb) {
567
        client.initWallet({
568
            identifier: myIdentifier,
569
            readOnly: true
570
        }, function(err, _wallet) {
571
            assert.ifError(err);
572
            assert.ok(_wallet);
573
            assert.equal(wallet.walletVersion, 'v1');
574
575
            wallet = _wallet;
576
577
            cb();
578
        });
579
    });
580
581
    it("should have a 0 balance", function(cb) {
582
        wallet.getBalance(function(err, confirmed, unconfirmed) {
583
            assert.ifError(err);
584
            assert.equal(confirmed, 0);
585
            assert.equal(unconfirmed, 0);
586
587
            cb();
588
        });
589
    });
590
591
    it("should unlock", function(cb) {
592
        wallet.unlock({password: "password"}, function(err) {
593
            assert.ifError(err);
594
595
            cb();
596
        });
597
    });
598
599
    it("shouldn't be able to password change", function(cb) {
600
        wallet.passwordChange("password2", function(err) {
601
            assert.ok(!!err && err.message.match(/version does not support/));
602
603
            cb();
604
        });
605
    });
606
});
607
608
describe('test new blank wallet, old syntax', function() {
609
    var myIdentifier = "nodejs-sdk-" + crypto.randomBytes(24).toString('hex');
610
    var wallet;
611
612
    after(function(cb) {
613
        if (wallet) {
614
            wallet.deleteWallet(true, function(err, result) {
0 ignored issues
show
Unused Code introduced by
The parameter err is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
Unused Code introduced by
The parameter result is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
615
                cb();
616
            });
617
        } else {
618
            cb();
619
        }
620
    });
621
622
    it("shouldn't already exist", function(cb) {
623
        client.initWallet(myIdentifier, "password", function(err, wallet) {
624
            assert.ok(err);
625
            assert.ok(!wallet, "wallet with random ID [" + myIdentifier + "] already exists...");
626
627
            cb();
628
        });
629
    });
630
631
    it("should be created", function(cb) {
632
        client.createNewWallet(myIdentifier, "password", 9999, function(err, _wallet) {
633
            assert.ifError(err);
634
            assert.ok(_wallet);
635
636
            wallet = _wallet;
637
638
            assert.equal(wallet.identifier, myIdentifier);
639
            assert.equal(wallet.getBlocktrailPublicKey("M/9999'").toBase58(), "tpubD9q6vq9zdP3gbhpjs7n2TRvT7h4PeBhxg1Kv9jEc1XAss7429VenxvQTsJaZhzTk54gnsHRpgeeNMbm1QTag4Wf1QpQ3gy221GDuUCxgfeZ");
640
            cb();
641
        });
642
    });
643
644
    it("should have a 0 balance", function(cb) {
645
        wallet.getBalance(function(err, confirmed, unconfirmed) {
646
            assert.ifError(err);
647
            assert.equal(confirmed, 0);
648
            assert.equal(unconfirmed, 0);
649
650
            cb();
651
        });
652
    });
653
654
    it("shouldn't be able to pay", function(cb) {
655
        wallet.pay({
656
            "2N6Fg6T74Fcv1JQ8FkPJMs8mYmbm9kitTxy": blocktrail.toSatoshi(0.001)
657
        }, function(err, txHash) {
0 ignored issues
show
Unused Code introduced by
The parameter txHash is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
658
            assert.ok(!!err);
659
660
            cb();
661
        });
662
    });
663
});
664
665
describe('test new wallet, without mnemonics', function() {
666
    var myIdentifier = "nodejs-sdk-" + crypto.randomBytes(24).toString('hex');
667
    var wallet;
668
669
    var primarySeed = bip39.mnemonicToSeed(bip39.generateMnemonic(512), "password");
670
    var backupPrivateKey = bitcoin.HDNode.fromSeedBuffer(bip39.mnemonicToSeed(bip39.generateMnemonic(512), ""), bitcoin.networks.testnet);
671
    var backupPublicKey = backupPrivateKey.neutered();
672
673
    after(function(cb) {
674
        if (wallet) {
675
            wallet.deleteWallet(true, function(err, result) {
0 ignored issues
show
Unused Code introduced by
The parameter result is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
Unused Code introduced by
The parameter err is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
676
                cb();
677
            });
678
        } else {
679
            cb();
680
        }
681
    });
682
683
    it("shouldn't already exist", function(cb) {
684
        client.initWallet({
685
            identifier: myIdentifier
686
        }, function(err, wallet) {
687
            assert.ok(err);
688
            assert.ok(!wallet, "wallet with random ID [" + myIdentifier + "] already exists...");
689
690
            cb();
691
        });
692
    });
693
694
    it("should be created", function(cb) {
695
        client.createNewWallet({
696
                identifier: myIdentifier,
697
                primarySeed: primarySeed,
698
                backupPublicKey: backupPublicKey,
699
                keyIndex: 9999
700
            }, function(err, _wallet) {
701
                assert.ifError(err);
702
                assert.ok(_wallet);
703
                assert.ok(!_wallet.isSegwit());
704
                assert.equal(blocktrail.Wallet.CHAIN_BTC_DEFAULT, _wallet.chain);
705
706
                wallet = _wallet;
707
708
                assert.equal(wallet.identifier, myIdentifier);
709
                assert.equal(wallet.getBlocktrailPublicKey("M/9999'").toBase58(), "tpubD9q6vq9zdP3gbhpjs7n2TRvT7h4PeBhxg1Kv9jEc1XAss7429VenxvQTsJaZhzTk54gnsHRpgeeNMbm1QTag4Wf1QpQ3gy221GDuUCxgfeZ");
710
                cb();
711
            }
712
        );
713
    });
714
715
    it("should be initializable", function(cb) {
716
        client.initWallet({
717
                identifier: myIdentifier,
718
                primarySeed: primarySeed,
719
                keyIndex: 9999
720
            }, function(err, _wallet) {
721
                assert.ifError(err);
722
                assert.ok(_wallet);
723
                assert.ok(!_wallet.isSegwit());
724
                assert.equal(blocktrail.Wallet.CHAIN_BTC_DEFAULT, _wallet.chain);
725
726
                wallet = _wallet;
727
728
                cb();
729
            }
730
        );
731
    });
732
733
    it("should have a 0 balance", function(cb) {
734
        wallet.getBalance(function(err, confirmed, unconfirmed) {
735
            assert.ifError(err);
736
            assert.equal(confirmed, 0);
737
            assert.equal(unconfirmed, 0);
738
739
            cb();
740
        });
741
    });
742
743
    it("shouldn't be able to pay", function(cb) {
744
        wallet.pay({
745
            "2N6Fg6T74Fcv1JQ8FkPJMs8mYmbm9kitTxy": blocktrail.toSatoshi(0.001)
746
        }, function(err, txHash) {
0 ignored issues
show
Unused Code introduced by
The parameter txHash is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
747
            assert.ok(!!err);
748
749
            cb();
750
        });
751
    });
752
});
753
754
describe('test wallet, bitcoin cash mirror', function() {
755
    var tbccClient = _createApiClient("BCC", true);
756
757
    [
758
        {useCashAddress: false, addressType: "base58", description: "false uses base58 address"},
759
        {useCashAddress: true,  addressType: "cashaddr", description: "can opt into cash address"}
760
761
    ].map(function(fixture) {
762
        var useCashAddress = fixture.useCashAddress;
763
        var expectType = fixture.addressType;
764
        var description = fixture.description;
765
766
        var wallet;
767
        var address;
768
769
        it(description, function(cb) {
770
            tbccClient.initWallet({
771
                identifier: "unittest-transaction",
772
                passphrase: TRANSACTION_TEST_WALLET_PASSWORD,
773
                useCashAddress: useCashAddress
774
            }, function(err, _wallet) {
775
                assert.ifError(err);
776
                assert.ok(_wallet);
777
                assert.ok(!_wallet.isSegwit());
778
                assert.equal(_wallet.chain, blocktrail.Wallet.CHAIN_BCC_DEFAULT);
779
                wallet = _wallet;
780
781
                assert.equal(useCashAddress, _wallet.useNewCashAddr);
782
                assert.equal(wallet.primaryMnemonic, "give pause forget seed dance crawl situate hole keen");
783
                assert.equal(wallet.identifier, "unittest-transaction");
784
                assert.equal(wallet.getBlocktrailPublicKey("M/9999'").toBase58(), "tpubD9q6vq9zdP3gbhpjs7n2TRvT7h4PeBhxg1Kv9jEc1XAss7429VenxvQTsJaZhzTk54gnsHRpgeeNMbm1QTag4Wf1QpQ3gy221GDuUCxgfeZ");
785
                cb();
786
            });
787
        });
788
789
        it("derives the right address (" + description + ")", function(cb) {
790
            wallet.getNewAddress(function(err, serverAddress, path) {
791
                assert.ifError(err);
792
                assert.ok(serverAddress);
793
                assert.ok(path);
794
795
                var decoded = wallet.decodeAddress(serverAddress);
796
                assert.ok(decoded);
797
                assert.equal(serverAddress, decoded.address);
798
                assert.equal(expectType, decoded.type);
799
800
                address = serverAddress;
801
                cb();
802
            });
803
        });
804
805
        it("can coin select address (" + expectType + ")", function(cb) {
806
            var pay = {};
807
            pay[address] = 12345;
808
            wallet.coinSelection(pay, function(err, utxos) {
809
                assert.ifError(err);
810
                assert.ok(utxos);
811
                assert.ok(utxos.length > 0);
812
813
                cb();
814
            });
815
        });
816
    });
817
});
818
819
describe('test wallet, do transaction', function() {
820
    var wallet;
821
822
    it("should exists", function(cb) {
823
        client.initWallet({
824
            identifier: "unittest-transaction",
825
            passphrase: TRANSACTION_TEST_WALLET_PASSWORD
826
        }, function(err, _wallet) {
827
            assert.ifError(err);
828
            assert.ok(_wallet);
829
            assert.ok(!_wallet.isSegwit());
830
            assert.equal(blocktrail.Wallet.CHAIN_BTC_DEFAULT, _wallet.chain);
831
            wallet = _wallet;
832
833
            assert.equal(wallet.primaryMnemonic, "give pause forget seed dance crawl situate hole keen");
834
            assert.equal(wallet.identifier, "unittest-transaction");
835
            assert.equal(wallet.getBlocktrailPublicKey("M/9999'").toBase58(), "tpubD9q6vq9zdP3gbhpjs7n2TRvT7h4PeBhxg1Kv9jEc1XAss7429VenxvQTsJaZhzTk54gnsHRpgeeNMbm1QTag4Wf1QpQ3gy221GDuUCxgfeZ");
836
            cb();
837
        });
838
    });
839
840
    it("should have the expected addresses", function(cb) {
841
        assert.equal(wallet.getAddressByPath("M/9999'/0/1"), "2N65RcfKHiKQcPGZAA2QVeqitJvAQ8HroHD");
842
        assert.equal(wallet.getAddressByPath("M/9999'/0/6"), "2MynrezSyqCq1x5dMPtRDupTPA4sfVrNBKq");
843
        assert.equal(wallet.getAddressByPath("M/9999'/0/44"), "2N5eqrZE7LcfRyCWqpeh1T1YpMdgrq8HWzh");
844
845
        cb();
846
    });
847
848
    it("should have a balance", function(cb) {
849
        this.timeout(0);
850
851
        wallet.getBalance(function(err, confirmed, unconfirmed) {
852
            assert.ok(confirmed + unconfirmed > 0);
853
            assert.ok(confirmed > 0);
854
855
            cb();
856
        });
857
    });
858
859
    it("should return errors when expected", function(cb) {
860
        async.parallel([
861
            function(cb) {
862
                wallet.pay({"": blocktrail.toSatoshi(0.001)}, function(err) {
863
                    assert.ok(!!err);
864
                    assert.equal(err.message, "Invalid address [] (Invalid checksum)");
865
                    assert.ok(err instanceof blocktrail.InvalidAddressError);
866
867
                    cb();
868
                });
869
            },
870
            function(cb) {
871
                wallet.pay({"2N65RcfKHiKQcPGZAA2QVeqitJvAQ8HroHA": blocktrail.toSatoshi(0.001)}, function(err) {
872
                    assert.ok(!!err);
873
                    assert.equal(err.message, "Invalid address [2N65RcfKHiKQcPGZAA2QVeqitJvAQ8HroHA] (Invalid checksum)");
874
                    assert.ok(err instanceof blocktrail.InvalidAddressError);
875
876
                    cb();
877
                });
878
            },
879
            function(cb) {
880
                wallet.pay({"2N65RcfKHiKQcPGZAA2QVeqitJvAQ8HroHD": 1}, function(err) {
881
                    assert.ok(!!err);
882
                    assert.equal(err.message, "Values should be more than dust (" + blocktrail.DUST + ")");
883
                    assert.ok(err instanceof blocktrail.WalletSendError);
884
885
                    cb();
886
                });
887
            },
888
            function(cb) {
889
                wallet.pay({"2N65RcfKHiKQcPGZAA2QVeqitJvAQ8HroHD": 0}, function(err) {
890
                    assert.ok(!!err);
891
                    assert.equal(err.message, "Values should be non zero");
892
                    assert.ok(err instanceof blocktrail.WalletSendError);
893
894
                    cb();
895
                });
896
            },
897
            function(cb) {
898
                wallet.pay({"2N65RcfKHiKQcPGZAA2QVeqitJvAQ8HroHD": 1.1}, function(err) {
899
                    assert.ok(!!err);
900
                    assert.equal(err.message, "Values should be in Satoshis");
901
                    assert.ok(err instanceof blocktrail.WalletSendError);
902
903
                    cb();
904
                });
905
            }
906
        ], cb);
907
    });
908
909
    it("should be able to build a transaction paying a bech32 address", function(cb) {
910
        var address = "tb1qn08f8x0eamw66enrt497zu0v3u2danzey6asqs";
911
        var wp = "00149bce9399f9eeddad66635d4be171ec8f14decc59";
912
        var pay = {};
913
        pay[address] = blocktrail.toSatoshi(0.001);
914
915
        wallet.buildTransaction(pay, null, false, false, function(err, tx, utxos) {
0 ignored issues
show
Unused Code introduced by
The parameter utxos is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
916
            assert.ifError(err);
917
            assert.ok(tx);
918
            assert.ok(tx.toHex());
919
            assert.equal(wp, tx.outs[0].script.toString('hex'));
920
            cb();
921
        });
922
    });
923
924
    it("change should be randomized when building a transaction", function(cb) {
925
        wallet.getNewAddress(function(err, address, path) {
926
            assert.ifError(err);
927
            assert.ok(path.indexOf("M/9999'/0/") === 0);
928
            assert.ok(bitcoin.address.fromBase58Check(address));
929
930
            var pay = {};
931
            pay[address] = blocktrail.toSatoshi(0.001);
932
933
            var changeIdxs = [];
934
            var tryX = 10;
935
936
            async.whilst(
937
                function() { return tryX-- > 0 && _.uniq(changeIdxs).length < 2; },
938
                function(cb) {
939
                    wallet.buildTransaction(pay, function(err, tx, utxos) {
0 ignored issues
show
Unused Code introduced by
The parameter utxos is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
940
                        assert.ifError(err);
941
942
                        tx.outs.forEach(function(output, idx) {
943
                            var addr = bitcoin.address.fromOutputScript(output.script, client.testnet ? bitcoin.networks.testnet : bitcoin.networks.bitcoin);
944
945
                            if (addr !== address) {
946
                                changeIdxs.push(idx);
947
                            }
948
                        });
949
950
                        cb();
951
                    });
952
                },
953
                function() {
954
                    assert(_.uniq(changeIdxs).length > 1);
955
956
                    cb();
957
                }
958
            );
959
        });
960
961
        it("should be able to build a transaction", function(cb) {
0 ignored issues
show
Unused Code introduced by
The parameter cb is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
962
            wallet.getNewAddress(function(err, address, path) {
963
                assert.ifError(err);
964
                assert.ok(path.indexOf("M/9999'/0/") === 0);
965
                assert.ok(bitcoin.address.fromBase58Check(address));
966
967
                var pay = {};
968
                pay[address] = blocktrail.toSatoshi(0.001);
969
970
                wallet.buildTransaction(pay, function(err, tx, utxos) {
0 ignored issues
show
Unused Code introduced by
The parameter utxos is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
971
                    assert.ifError(err);
972
                    assert.ok(tx);
973
                    assert.ok(tx.toHex());
974
                });
975
            });
976
        });
977
    });
978
979
    it("should be able to do a payment", function(cb) {
980
        wallet.getNewAddress(function(err, address, path) {
981
            assert.ifError(err);
982
            assert.ok(path.indexOf("M/9999'/", wallet.chain, "/") === 0);
983
            assert.ok(bitcoin.address.fromBase58Check(address));
984
985
            var pay = {};
986
            pay[address] = blocktrail.toSatoshi(0.001);
987
988
            var progress = [];
989
990
            wallet.pay(pay, function(err, txHash) {
991
                assert.ifError(err);
992
                assert.ok(txHash);
993
994
                // change address doesn't always happen ...
995
                if (progress.indexOf(blocktrail.Wallet.PAY_PROGRESS_CHANGE_ADDRESS) === -1) {
996
                    progress.splice(2, 0, blocktrail.Wallet.PAY_PROGRESS_CHANGE_ADDRESS);
997
                }
998
999
                assert.deepEqual(progress, [
1000
                    blocktrail.Wallet.PAY_PROGRESS_START,
1001
                    blocktrail.Wallet.PAY_PROGRESS_COIN_SELECTION,
1002
                    blocktrail.Wallet.PAY_PROGRESS_CHANGE_ADDRESS,
1003
                    blocktrail.Wallet.PAY_PROGRESS_SIGN,
1004
                    blocktrail.Wallet.PAY_PROGRESS_SEND,
1005
                    blocktrail.Wallet.PAY_PROGRESS_DONE
1006
                ]);
1007
1008
                // 200ms timeout, for w/e this is neccesary now ... @TODO: figure out why ...
1009
                setTimeout(function() {
1010
                    client.transaction(txHash, function(err, tx) {
1011
                        assert.ifError(err);
1012
                        assert.ok(tx);
1013
1014
                        cb();
1015
                    });
1016
                }, WAIT_FOR_TX_PROCESSED);
1017
            }).progress(function(_progress) {
1018
                progress.push(_progress);
1019
            });
1020
        });
1021
    });
1022
});
1023
1024
describe('test wallet with segwit chain', function() {
1025
    var wallet;
1026
1027
    it("should exist and be setup", function(cb) {
1028
        client.initWallet({
1029
            identifier: "unittest-transaction-sw",
1030
            passphrase: TRANSACTION_TEST_WALLET_PASSWORD
1031
        }, function(err, _wallet) {
1032
            assert.ifError(err);
1033
            assert.ok(_wallet);
1034
            assert.equal(_wallet.primaryMnemonic, "give pause forget seed dance crawl situate hole keen");
1035
            assert.equal(_wallet.identifier, "unittest-transaction-sw");
1036
            assert.equal(_wallet.getBlocktrailPublicKey("M/9999'").toBase58(), "tpubD9q6vq9zdP3gbhpjs7n2TRvT7h4PeBhxg1Kv9jEc1XAss7429VenxvQTsJaZhzTk54gnsHRpgeeNMbm1QTag4Wf1QpQ3gy221GDuUCxgfeZ");
1037
            assert.ok(_wallet.isSegwit());
1038
            assert.equal(blocktrail.Wallet.CHAIN_BTC_DEFAULT, _wallet.chain);
1039
            assert.equal(blocktrail.Wallet.CHAIN_BTC_SEGWIT, _wallet.changeChain);
1040
1041
            wallet = _wallet;
1042
            cb();
1043
        });
1044
    });
1045
1046
    it("getNewAddress produces plain P2SH addresses", function(cb) {
1047
        wallet.getNewAddress(function(err, address, path) {
1048
            assert.ifError(err);
1049
            assert.ok(path.indexOf("M/9999'/0/") === 0);
1050
1051
            assert.ok(bitcoin.address.fromBase58Check(address));
1052
1053
            cb();
1054
        });
1055
    });
1056
1057
    it("getNewAddress produces segwit P2SH addresses for change chain", function(cb) {
1058
        wallet.getNewAddress(wallet.changeChain, function(err, address, path) {
1059
            assert.ifError(err);
1060
            assert.ok(path.indexOf("M/9999'/2/") === 0);
1061
1062
            assert.ok(bitcoin.address.fromBase58Check(address));
1063
1064
            cb();
1065
        });
1066
    });
1067
1068
    it("getWalletScriptByPath produces P2SH addresses, and returns witnessScript", function(cb) {
1069
        var eAddress = "2N3j4Vx3D9LPumjtRbRe2RJpwVocvCCkHKh";
1070
1071
        assert.equal(wallet.getAddressByPath("M/9999'/2/0"), eAddress);
1072
1073
        var walletScript = wallet.getWalletScriptByPath("M/9999'/2/0");
1074
        assert.equal(walletScript.address, eAddress);
1075
        assert.ok(walletScript.witnessScript);
1076
        assert.ok(walletScript.redeemScript);
1077
        cb();
1078
    });
1079
});
1080
1081
describe('test wallet, do transaction, segwit spend', function() {
1082
    var wallets = [];
1083
    after(function(cb) {
1084
        if (wallets.length > 0) {
1085
            wallets.map(function(wallet) {
1086
                wallet.deleteWallet(true);
1087
            });
1088
        }
1089
        cb();
1090
    });
1091
1092
    var unitTestWallet;
1093
    var identifier = crypto.randomBytes(12).toString('hex');
1094
    var segwitWallet;
1095
    var receiveAddr;
1096
    var receiveBackAddr;
1097
    it("should setup the funding wallet", function(cb) {
1098
        client.initWallet({
1099
            identifier: "unittest-transaction",
1100
            passphrase: TRANSACTION_TEST_WALLET_PASSWORD
1101
        }, function(err, _wallet) {
1102
            assert.ifError(err);
1103
            assert.ok(_wallet);
1104
1105
            _wallet.getNewAddress(function(err, address, path) {
1106
                assert.ifError(err);
1107
                assert.ok(address);
1108
                assert.ok(path);
1109
1110
                unitTestWallet = _wallet;
1111
                receiveBackAddr = address;
1112
                cb();
1113
            });
1114
        });
1115
    });
1116
1117
    it("should make the receiving segwit wallet", function(cb) {
1118
        createTransactionTestWallet(identifier, true, function(err, newWallet) {
1119
            wallets.push(newWallet);
1120
            assert.ifError(err);
1121
            newWallet.getNewAddress(newWallet.changeChain, function(err, address, path) {
1122
                assert.ifError(err);
1123
                assert.ok(bitcoin.address.fromBase58Check(address));
1124
                assert.ok(newWallet.isSegwit());
1125
                assert.ok(path.indexOf("M/9999'/2/") === 0);
1126
1127
                var checkScript = newWallet.getWalletScriptByPath(path);
1128
                assert.ok(checkScript.address = address);
1129
                assert.ok(checkScript.redeemScript instanceof Buffer);
0 ignored issues
show
Bug introduced by
The variable Buffer seems to be never declared. If this is a global, consider adding a /** global: Buffer */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
1130
                assert.ok(checkScript.witnessScript instanceof Buffer);
1131
1132
                segwitWallet = newWallet;
1133
                receiveAddr = address;
1134
                cb();
1135
            });
1136
        });
1137
    });
1138
1139
    var paymentHash;
1140
    it("should receive funds from unitTestWallet", function(cb) {
1141
        var pay = {};
1142
        pay[receiveAddr] = 30000;
1143
        unitTestWallet.pay(pay, null, true, function(err, txid) {
1144
            assert.ifError(err);
1145
            assert.ok(txid);
1146
            paymentHash = txid;
0 ignored issues
show
Unused Code introduced by
The variable paymentHash seems to be never used. Consider removing it.
Loading history...
1147
            cb();
1148
        });
1149
    });
1150
1151
    it("should return to unitTestWallet", function(cb) {
1152
        var pay = {};
1153
        pay[receiveBackAddr] = 20000;
1154
        segwitWallet.pay(pay, null, true, function(err, txid) {
1155
            assert.ifError(err);
1156
            assert.ok(txid);
1157
1158
            setTimeout(function() {
1159
                client.transaction(txid, function(err, tx) {
1160
                    assert.ifError(err);
1161
                    assert.ok(tx);
1162
                    cb();
1163
                });
1164
            }, WAIT_FOR_TX_PROCESSED);
1165
        });
1166
    });
1167
});
1168
describe('test wallet, do transaction, without mnemonics', function() {
1169
    var wallet;
1170
1171
    var primarySeed = bip39.mnemonicToSeed(TRANSACTION_TEST_WALLET_PRIMARY_MNEMONIC, TRANSACTION_TEST_WALLET_PASSWORD);
1172
1173
    it("should exists", function(cb) {
1174
        client.initWallet({
1175
                identifier: "unittest-transaction",
1176
                primarySeed: primarySeed,
1177
                primaryMnemonic: false // explicitly set false because we're reusing unittest-transaction which has a mnemonic stored
1178
            }, function(err, _wallet) {
1179
                assert.ifError(err);
1180
                assert.ok(_wallet);
1181
1182
                wallet = _wallet;
1183
1184
                assert.equal(wallet.identifier, "unittest-transaction");
1185
                assert.equal(wallet.getBlocktrailPublicKey("M/9999'").toBase58(), "tpubD9q6vq9zdP3gbhpjs7n2TRvT7h4PeBhxg1Kv9jEc1XAss7429VenxvQTsJaZhzTk54gnsHRpgeeNMbm1QTag4Wf1QpQ3gy221GDuUCxgfeZ");
1186
                cb();
1187
            }
1188
        );
1189
    });
1190
1191
    it("should have the expected addresses", function(cb) {
1192
        assert.equal(wallet.getAddressByPath("M/9999'/0/1"), "2N65RcfKHiKQcPGZAA2QVeqitJvAQ8HroHD");
1193
        assert.equal(wallet.getAddressByPath("M/9999'/0/6"), "2MynrezSyqCq1x5dMPtRDupTPA4sfVrNBKq");
1194
        assert.equal(wallet.getAddressByPath("M/9999'/0/44"), "2N5eqrZE7LcfRyCWqpeh1T1YpMdgrq8HWzh");
1195
1196
        cb();
1197
    });
1198
1199
    it("should have a balance", function(cb) {
1200
        this.timeout(0);
1201
1202
        wallet.getBalance(function(err, confirmed, unconfirmed) {
1203
            assert.ok(confirmed + unconfirmed > 0);
1204
            assert.ok(confirmed > 0);
1205
1206
            cb();
1207
        });
1208
    });
1209
1210
    it("should be able to do a payment", function(cb) {
1211
        wallet.getNewAddress(function(err, address, path) {
1212
            assert.ifError(err);
1213
            assert.ok(path.indexOf("M/9999'/0/") === 0);
1214
            assert.ok(bitcoin.address.fromBase58Check(address));
1215
1216
            var pay = {};
1217
            pay[address] = blocktrail.toSatoshi(0.001);
1218
1219
            wallet.pay(pay, function(err, txHash) {
1220
                assert.ifError(err);
1221
                assert.ok(txHash);
1222
1223
                // 200ms timeout, for w/e this is neccesary now ... @TODO: figure out why ...
1224
                setTimeout(function() {
1225
                    client.transaction(txHash, function(err, tx) {
1226
                        assert.ifError(err);
1227
                        assert.ok(tx);
1228
1229
                        cb();
1230
                    });
1231
                }, WAIT_FOR_TX_PROCESSED);
1232
            });
1233
        });
1234
    });
1235
});
1236
1237
describe('test wallet, do opreturn transaction', function() {
1238
    var wallet;
1239
1240
    it("should exists", function(cb) {
1241
        client.initWallet({
1242
            identifier: "unittest-transaction",
1243
            passphrase: TRANSACTION_TEST_WALLET_PASSWORD
1244
        }, function(err, _wallet) {
1245
            assert.ifError(err);
1246
            assert.ok(_wallet);
1247
1248
            wallet = _wallet;
1249
1250
            assert.equal(wallet.primaryMnemonic, "give pause forget seed dance crawl situate hole keen");
1251
            assert.equal(wallet.identifier, "unittest-transaction");
1252
            assert.equal(wallet.getBlocktrailPublicKey("M/9999'").toBase58(), "tpubD9q6vq9zdP3gbhpjs7n2TRvT7h4PeBhxg1Kv9jEc1XAss7429VenxvQTsJaZhzTk54gnsHRpgeeNMbm1QTag4Wf1QpQ3gy221GDuUCxgfeZ");
1253
            cb();
1254
        });
1255
    });
1256
1257
    it("should be able to do a payment with opreturn output", function(cb) {
1258
        wallet.getNewAddress(function(err, address, path) {
0 ignored issues
show
Unused Code introduced by
The parameter path is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
1259
            assert.ifError(err);
1260
1261
            var pay = {};
1262
            pay[address] = blocktrail.toSatoshi(0.001);
1263
            pay[blocktrail.Wallet.OP_RETURN] = "BLOCKTRAILTESTDATA";
1264
1265
            wallet.pay(pay, function(err, txHash) {
1266
                assert.ifError(err);
1267
                assert.ok(txHash);
1268
1269
1270
                // 200ms timeout, for w/e this is neccesary now ... @TODO: figure out why ...
1271
                setTimeout(function() {
1272
                    client.transaction(txHash, function(err, tx) {
1273
                        assert.ifError(err);
1274
                        assert.ok(tx);
1275
1276
                        var hasOpreturn;
1277
                        tx.outputs.forEach(function(output) {
1278
                            if (output.type === 'op_return') {
1279
                                hasOpreturn = true;
1280
1281
                                assert.equal(output.script_hex, "6a12424c4f434b545241494c5445535444415441");
1282
                            }
1283
                        });
1284
                        assert.ok(hasOpreturn);
1285
1286
                        cb();
1287
                    });
1288
                }, WAIT_FOR_TX_PROCESSED);
1289
            });
1290
        });
1291
    });
1292
});
1293
1294
describe('test wallet, do forcefee transaction', function() {
1295
    var wallet;
1296
1297
    it("should exists", function(cb) {
1298
        client.initWallet({
1299
            identifier: "unittest-transaction",
1300
            passphrase: TRANSACTION_TEST_WALLET_PASSWORD
1301
        }, function(err, _wallet) {
1302
            assert.ifError(err);
1303
            assert.ok(_wallet);
1304
1305
            wallet = _wallet;
1306
1307
            assert.equal(wallet.primaryMnemonic, "give pause forget seed dance crawl situate hole keen");
1308
            assert.equal(wallet.identifier, "unittest-transaction");
1309
            assert.equal(wallet.getBlocktrailPublicKey("M/9999'").toBase58(), "tpubD9q6vq9zdP3gbhpjs7n2TRvT7h4PeBhxg1Kv9jEc1XAss7429VenxvQTsJaZhzTk54gnsHRpgeeNMbm1QTag4Wf1QpQ3gy221GDuUCxgfeZ");
1310
            cb();
1311
        });
1312
    });
1313
1314
    it("should be able to do a payment with forced fee", function(cb) {
1315
        wallet.getNewAddress(function(err, address, path) {
0 ignored issues
show
Unused Code introduced by
The parameter path is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
1316
            assert.ifError(err);
1317
1318
            var pay = {};
1319
            pay[address] = blocktrail.toSatoshi(0.01);
1320
            var forceFee = blocktrail.toSatoshi(0.00054321);
1321
1322
            wallet.pay(pay, null, false, true, blocktrail.Wallet.FEE_STRATEGY_FORCE_FEE, null, {
1323
                forcefee: forceFee,
1324
                checkFee: false
1325
            }, function(err, txHash) {
1326
                assert.ifError(err);
1327
                assert.ok(txHash);
1328
1329
                // 200ms timeout, for w/e this is neccesary now ... @TODO: figure out why ...
1330
                setTimeout(function() {
1331
                    client.transaction(txHash, function(err, tx) {
1332
                        assert.ifError(err);
1333
                        // this could very occasionally fail if change < DUST because then it's added to fee, so adjusted check for that
1334
                        assert.ok(tx['total_fee'] >= forceFee && tx['total_fee'] <= forceFee + blocktrail.DUST,
1335
                            "fee [" + tx['total_fee'] + "] should be equal to forced fee [" +  forceFee + "] for tx [" + txHash + "]");
1336
1337
                        cb();
1338
                    });
1339
                }, WAIT_FOR_TX_PROCESSED);
1340
            });
1341
        });
1342
    });
1343
});
1344
1345
describe('test wallet discovery and upgrade key index', function() {
1346
    var myIdentifier = "nodejs-sdk-" + crypto.randomBytes(24).toString('hex');
1347
    var wallet;
1348
1349
    after(function(cb) {
1350
        if (wallet) {
1351
            wallet.deleteWallet(true, function(err, result) {
0 ignored issues
show
Unused Code introduced by
The parameter result is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
Unused Code introduced by
The parameter err is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
1352
                cb();
1353
            });
1354
        } else {
1355
            cb();
1356
        }
1357
    });
1358
1359
    it("should be created", function(cb) {
1360
        createDiscoveryTestWallet(myIdentifier, "password", function(err, _wallet) {
1361
            assert.ifError(err);
1362
            assert.ok(_wallet);
1363
            _wallet.chain = blocktrail.Wallet.CHAIN_BTC_DEFAULT;
1364
            wallet = _wallet;
1365
1366
            assert.equal(wallet.primaryMnemonic, "give pause forget seed dance crawl situate hole kingdom");
1367
            assert.equal(wallet.identifier, myIdentifier);
1368
            assert.equal(wallet.getBlocktrailPublicKey("M/9999'").toBase58(), "tpubD9q6vq9zdP3gbhpjs7n2TRvT7h4PeBhxg1Kv9jEc1XAss7429VenxvQTsJaZhzTk54gnsHRpgeeNMbm1QTag4Wf1QpQ3gy221GDuUCxgfeZ");
1369
1370
            cb();
1371
        });
1372
    });
1373
1374
    it("should have the expected addresses", function(cb) {
1375
        async.series([
1376
            function(cb) {
1377
                wallet.getNewAddress(function(err, address, path) {
1378
                    assert.ifError(err);
1379
                    assert.equal(path, "M/9999'/0/0");
1380
                    assert.equal(address, "2Mtfn5S9tVWnnHsBQixCLTsCAPFHvfhu6bM");
1381
1382
                    cb();
1383
                });
1384
            },
1385
            function(cb) {
1386
                wallet.getNewAddress(function(err, address, path) {
1387
                    assert.ifError(err);
1388
                    assert.equal(path, "M/9999'/0/1");
1389
                    assert.equal(address, "2NG49GDkm5qCYvDFi4cxAnkSho8qLbEz6C4");
1390
1391
                    cb();
1392
                });
1393
            },
1394
            function(cb) {
1395
                assert.equal(wallet.getAddressByPath("M/9999'/0/1"), "2NG49GDkm5qCYvDFi4cxAnkSho8qLbEz6C4");
1396
                assert.equal(wallet.getAddressByPath("M/9999'/0/6"), "2N1kM5xeDaCN9Weog3mbyxjpryNZcirnkB7");
1397
1398
                cb();
1399
            }
1400
        ], cb);
1401
    });
1402
1403
    it("should have a balance after discovery", function(cb) {
1404
        this.timeout(0);
1405
1406
        wallet.doDiscovery(50, function(err, confirmed, unconfirmed) {
1407
            assert.ok(confirmed + unconfirmed > 0);
1408
1409
            cb();
1410
        });
1411
    });
1412
1413
    it("should be upgraded and have expected addresses", function(cb) {
1414
        // set upgrade
1415
        wallet.upgradeToKeyIndex = 10000;
1416
        // lock
1417
        wallet.lock();
1418
        // unlock should upgrade
1419
        wallet.unlock({
1420
            passphrase: "password"
1421
        }).then(function() {
1422
            assert.equal(wallet.getBlocktrailPublicKey("M/10000'").toBase58(), "tpubD9m9hziKhYQExWgzMUNXdYMNUtourv96sjTUS9jJKdo3EDJAnCBJooMPm6vGSmkNTNAmVt988dzNfNY12YYzk9E6PkA7JbxYeZBFy4XAaCp");
1423
1424
            assert.equal(wallet.getAddressByPath("M/10000'/0/0"), "2N9ZLKXgs12JQKXvLkngn7u9tsYaQ5kXJmk");
1425
1426
            wallet.getNewAddress(function(err, address, path) {
1427
                assert.ifError(err);
1428
                assert.equal(path, "M/10000'/0/0");
1429
                assert.equal(address, "2N9ZLKXgs12JQKXvLkngn7u9tsYaQ5kXJmk");
1430
1431
                cb();
1432
            });
1433
        });
1434
    });
1435
});
1436
1437
describe('test wallet with bad password', function() {
1438
    var myIdentifier = "nodejs-sdk-" + crypto.randomBytes(24).toString('hex');
1439
    var wallet;
1440
1441
    after(function(cb) {
1442
        if (wallet) {
1443
            wallet.deleteWallet(true, function(err, result) {
0 ignored issues
show
Unused Code introduced by
The parameter result is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
Unused Code introduced by
The parameter err is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
1444
                cb();
1445
            });
1446
        } else {
1447
            cb();
1448
        }
1449
    });
1450
1451
    it("should be created", function(cb) {
1452
        createDiscoveryTestWallet(myIdentifier, "badpassword", function(err, _wallet) {
1453
            assert.ifError(err);
1454
            assert.ok(_wallet);
1455
1456
            _wallet.chain = blocktrail.Wallet.CHAIN_BTC_DEFAULT;
1457
            wallet = _wallet;
1458
1459
            assert.equal(wallet.primaryMnemonic, "give pause forget seed dance crawl situate hole kingdom");
1460
            assert.equal(wallet.identifier, myIdentifier);
1461
            assert.equal(wallet.getBlocktrailPublicKey("M/9999'").toBase58(), "tpubD9q6vq9zdP3gbhpjs7n2TRvT7h4PeBhxg1Kv9jEc1XAss7429VenxvQTsJaZhzTk54gnsHRpgeeNMbm1QTag4Wf1QpQ3gy221GDuUCxgfeZ");
1462
1463
            cb();
1464
        });
1465
    });
1466
1467
    it("should have the expected addresses (different from with the correct password)", function(cb) {
1468
        async.series([
1469
            function(cb) {
1470
                wallet.getNewAddress(function(err, address, path) {
1471
                    assert.ifError(err);
1472
                    assert.equal(path, "M/9999'/0/0");
1473
                    assert.equal(address, "2N9SGrV4NKRjdACYvHLPpy2oiPrxTPd44rg");
1474
1475
                    cb();
1476
                });
1477
            },
1478
            function(cb) {
1479
                wallet.getNewAddress(function(err, address, path) {
1480
                    assert.ifError(err);
1481
                    assert.equal(path, "M/9999'/0/1");
1482
                    assert.equal(address, "2NDq3DRy9E3YgHDA3haPJj3FtUS6V93avkf");
1483
1484
                    cb();
1485
                });
1486
            }
1487
        ], cb);
1488
    });
1489
1490
    it("shouldn't have a balance after discovery", function(cb) {
1491
        this.timeout(0);
1492
1493
        wallet.doDiscovery(50, function(err, confirmed, unconfirmed) {
1494
            assert.ok(confirmed + unconfirmed === 0);
1495
1496
            cb();
1497
        });
1498
    });
1499
});
1500
1501
describe('test wallet webhook', function() {
1502
    // this.timeout(0); // disable, can take long
1503
1504
    var myIdentifier = "nodejs-sdk-" + crypto.randomBytes(24).toString('hex');
1505
    var wallet;
1506
1507
    after(function(cb) {
1508
        if (wallet) {
1509
            wallet.deleteWallet(true, function(err, result) {
0 ignored issues
show
Unused Code introduced by
The parameter result is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
Unused Code introduced by
The parameter err is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
1510
                cb();
1511
            });
1512
        } else {
1513
            cb();
1514
        }
1515
    });
1516
1517
    it("shouldn't already exist", function(cb) {
1518
        client.initWallet({
1519
            identifier: myIdentifier,
1520
            passphrase: "password"
1521
        }, function(err, wallet) {
1522
            assert.ok(err);
1523
            assert.ok(!wallet, "wallet with random ID [" + myIdentifier + "] already exists...");
1524
1525
            cb();
1526
        });
1527
    });
1528
1529
    it("should be created", function(cb) {
1530
        client.createNewWallet({
1531
            identifier: myIdentifier,
1532
            passphrase: "password",
1533
            keyIndex: 9999
1534
        }, function(err, _wallet) {
1535
            assert.ifError(err);
1536
            assert.ok(_wallet);
1537
1538
            wallet = _wallet;
1539
1540
            assert.equal(wallet.identifier, myIdentifier);
1541
            assert.equal(wallet.getBlocktrailPublicKey("M/9999'").toBase58(), "tpubD9q6vq9zdP3gbhpjs7n2TRvT7h4PeBhxg1Kv9jEc1XAss7429VenxvQTsJaZhzTk54gnsHRpgeeNMbm1QTag4Wf1QpQ3gy221GDuUCxgfeZ");
1542
            cb();
1543
        });
1544
    });
1545
1546
    it("should have a 0 balance", function(cb) {
1547
        wallet.getBalance(function(err, confirmed, unconfirmed) {
1548
            assert.ifError(err);
1549
            assert.equal(confirmed, 0);
1550
            assert.equal(unconfirmed, 0);
1551
1552
            cb();
1553
        });
1554
    });
1555
1556
    it("should be able to create a webhook", function(cb) {
1557
        wallet.setupWebhook("https://www.blocktrail.com/webhook-test", function(err, webhook) {
1558
            assert.ifError(err);
1559
            assert.equal(webhook['url'], "https://www.blocktrail.com/webhook-test");
1560
            assert.equal(webhook['identifier'], "WALLET-" + myIdentifier);
1561
1562
            wallet.deleteWebhook(function(err, result) {
0 ignored issues
show
Unused Code introduced by
The parameter result is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
1563
                assert.ifError(err);
1564
1565
                cb();
1566
            });
1567
        });
1568
    });
1569
1570
    it("should be able to create a webhook with custom identifier", function(cb) {
1571
        var myWebhookIdentifier = "nodejs-sdk-" + crypto.randomBytes(24).toString('hex');
1572
1573
        wallet.setupWebhook("https://www.blocktrail.com/webhook-test", myWebhookIdentifier, function(err, webhook) {
1574
            assert.ifError(err);
1575
            assert.equal(webhook['url'], "https://www.blocktrail.com/webhook-test");
1576
            assert.equal(webhook['identifier'], myWebhookIdentifier);
1577
1578
            client.getWebhookEvents(myWebhookIdentifier, function(err, result) {
0 ignored issues
show
Unused Code introduced by
The parameter result is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
1579
                assert.ifError(err);
1580
1581
                wallet.getNewAddress(function(err, address1) {
1582
                    assert.ifError(err);
1583
1584
                    wallet.deleteWebhook(myWebhookIdentifier, function(err, result) {
0 ignored issues
show
Unused Code introduced by
The parameter result is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
1585
                        assert.ifError(err);
1586
1587
                        var myWebhookIdentifier = "nodejs-sdk-" + crypto.randomBytes(24).toString('hex');
1588
1589
                        wallet.setupWebhook("https://www.blocktrail.com/webhook-test", myWebhookIdentifier, function(err, webhook) {
1590
                            assert.ifError(err);
1591
                            assert.equal(webhook['url'], "https://www.blocktrail.com/webhook-test");
1592
                            assert.equal(webhook['identifier'], myWebhookIdentifier);
1593
1594
                            client.getWebhookEvents(myWebhookIdentifier, function(err, result) {
1595
                                assert.ifError(err);
1596
                                assert.ok(_.includes(_.map(result['data'], 'address'), address1));
1597
1598
                                wallet.getNewAddress(function(err, address2) {
1599
                                    assert.ifError(err);
1600
1601
                                    client.getWebhookEvents(myWebhookIdentifier, function(err, result) {
1602
                                        assert.ifError(err);
1603
                                        assert.ok(_.includes(_.map(result['data'], 'address'), address2));
1604
1605
                                        wallet.deleteWallet(function(err, result) {
1606
                                            assert.ifError(err);
1607
                                            assert.ok(result);
1608
1609
                                            client.deleteWebhook(myWebhookIdentifier, function(err, result) {
0 ignored issues
show
Unused Code introduced by
The parameter result is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
1610
                                                assert.ok(err);
1611
1612
                                                cb();
1613
                                            });
1614
                                        });
1615
                                    });
1616
                                });
1617
                            });
1618
                        });
1619
                    });
1620
1621
                });
1622
            });
1623
        });
1624
    });
1625
});
1626
1627
describe("Wallet.getAddressAndType", function() {
1628
    var fixtures = [
1629
        {
1630
            address: "tb1qn08f8x0eamw66enrt497zu0v3u2danzey6asqs",
1631
            network: bitcoin.networks.testnet,
1632
            type: "bech32",
1633
            valid: true
1634
        },
1635
        {
1636
            address: "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7",
1637
            network: bitcoin.networks.testnet,
1638
            type: "bech32",
1639
            valid: true
1640
        },
1641
        {
1642
            address: "muinVykhtZyonxQxk8zBptX6Lmri91bdNG",
1643
            network: bitcoin.networks.testnet,
1644
            type: "base58",
1645
            valid: true
1646
        },
1647
        {
1648
            address: "2N7T4CD6CEuNHJoGKpoJH3YexqektXjyy6L",
1649
            network: bitcoin.networks.testnet,
1650
            type: "base58",
1651
            valid: true
1652
        },
1653
        {
1654
            address: "16uf9UUBbUHdVAnETGZQnvXZcf9NPU1QR6",
1655
            network: bitcoin.networks.bitcoin,
1656
            type: "base58",
1657
            valid: true
1658
        },
1659
        {
1660
            address: "3CgSFohdEqd7pSxbDAJeJo6X5Qm2tBbby9",
1661
            network: bitcoin.networks.bitcoin,
1662
            type: "base58",
1663
            valid: true
1664
        },
1665
        {
1666
            address: "bc1qqy36hngpyw4u6qfr40xszgate5qj827dqy36hngpyw4u6qfr40xsp3an42",
1667
            network: bitcoin.networks.bitcoin,
1668
            type: "bech32",
1669
            valid: true
1670
        },
1671
        {
1672
            address: "bc1qn08f8x0eamw66enrt497zu0v3u2danzewuxrmr",
1673
            network: bitcoin.networks.bitcoin,
1674
            type: "bech32",
1675
            valid: true
1676
        },
1677
        {
1678
            address: "16uf9UUBbUHdVAnETGZQnvXZcf9NPU1QR6",
1679
            network: bitcoin.networks.testnet,
1680
            type: "base58",
1681
            error: "Address invalid on this network",
1682
            valid: false
1683
        },
1684
        {
1685
            address: "3CgSFohdEqd7pSxbDAJeJo6X5Qm2tBbby9",
1686
            network: bitcoin.networks.testnet,
1687
            type: "base58",
1688
            error: "Address invalid on this network",
1689
            valid: false
1690
        },
1691
        {
1692
            address: "bc1qqy36hngpyw4u6qfr40xszgate5qj827dqy36hngpyw4u6qfr40xsp3an42",
1693
            network: bitcoin.networks.testnet,
1694
            type: "bech32",
1695
            error: "Address invalid on this network",
1696
            valid: false
1697
        },
1698
        {
1699
            address: "bc1qn08f8x0eamw66enrt497zu0v3u2danzewuxrmr",
1700
            network: bitcoin.networks.testnet,
1701
            type: "bech32",
1702
            error: "Address invalid on this network",
1703
            valid: false
1704
        },
1705
        {
1706
            address: "bc1qqy36hngpyw4u6qfr40xszgate5qj827dqy36hngpyw4u6qfr40xsp3an42",
1707
            network: bitcoin.networks.bitcoincash,
1708
            error: "Non-base58 character",
1709
            type: "bech32",
1710
            valid: false
1711
        },
1712
        {
1713
            address: "bc1qn08f8x0eamw66enrt497zu0v3u2danzewuxrmr",
1714
            network: bitcoin.networks.bitcoincash,
1715
            error: "Non-base58 character",
1716
            type: "bech32",
1717
            valid: false
1718
        },
1719
        {
1720
            address: "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7",
1721
            network: bitcoin.networks.bitcoincashtestnet,
1722
            error: "Non-base58 character",
1723
            type: "bech32",
1724
            valid: false
1725
        },
1726
        {
1727
            address: "tb1qn08f8x0eamw66enrt497zu0v3u2danzey6asqs",
1728
            network: bitcoin.networks.bitcoincashtestnet,
1729
            error: "Non-base58 character",
1730
            type: "bech32",
1731
            valid: false
1732
        },
1733
        {
1734
            address: "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7",
1735
            network: bitcoin.networks.bitcoin,
1736
            error: "Address invalid on this network",
1737
            type: "bech32",
1738
            valid: false
1739
        },
1740
        {
1741
            address: "tb1qn08f8x0eamw66enrt497zu0v3u2danzey6asqs",
1742
            network: bitcoin.networks.bitcoin,
1743
            error: "Address invalid on this network",
1744
            type: "bech32",
1745
            valid: false
1746
        },
1747
        {
1748
            address: "bc1qqy36hngpyw4u6qfr40xszgate5qj827dqy36hngpyw4u6qfr40xsp3an42",
1749
            network: bitcoin.networks.testnet,
1750
            error: "Address invalid on this network",
1751
            type: "bech32",
1752
            valid: false
1753
        },
1754
        {
1755
            address: "bc1qn08f8x0eamw66enrt497zu0v3u2danzewuxrmr",
1756
            network: bitcoin.networks.testnet,
1757
            error: "Address invalid on this network",
1758
            type: "bech32",
1759
            valid: false
1760
        }
1761
    ];
1762
1763
    fixtures.map(function(fixture) {
1764
        var description =
1765
            (fixture.valid ? "parses" : "fails to parse") +
1766
            " a " + fixture.type + " address: " + fixture.address;
1767
1768
        it(description, function(cb) {
1769
            var addrAndType;
1770
            var err;
1771
            try {
1772
                addrAndType = Wallet.getAddressAndType(fixture.address, fixture.network);
1773
            } catch (e) {
1774
                err = e;
1775
            }
1776
1777
            if (fixture.valid) {
1778
                assert.ifError(err);
0 ignored issues
show
Bug introduced by
The variable err seems to not be initialized for all possible execution paths. Are you sure ifError handles undefined variables?
Loading history...
1779
                assert.ok(Object.keys(addrAndType).indexOf("address") !== -1);
1780
                assert.ok(Object.keys(addrAndType).indexOf("decoded") !== -1);
1781
                assert.ok(Object.keys(addrAndType).indexOf("type") !== -1);
1782
                assert.equal(addrAndType.type, fixture.type);
1783
                assert.equal(addrAndType.address, fixture.address);
1784
            } else {
1785
                assert.ok(typeof err === "object");
1786
                assert.ok(typeof addrAndType === "undefined");
1787
                if (Object.keys(fixture).indexOf("error") !== -1) {
1788
                    assert.equal(err.message, fixture.error);
1789
                }
1790
            }
1791
            cb();
1792
        });
1793
    });
1794
});
1795
1796
describe("Wallet.convertPayToOutputs", function() {
1797
    var fixtures = [
1798
        {
1799
            description: "p2wpkh",
1800
            network: bitcoin.networks.testnet,
1801
            cashaddr: false,
1802
            value: 12345,
1803
            address: "tb1qn08f8x0eamw66enrt497zu0v3u2danzey6asqs",
1804
            script: "00149bce9399f9eeddad66635d4be171ec8f14decc59"
1805
        },
1806
        {
1807
            description: "p2wsh",
1808
            network: bitcoin.networks.testnet,
1809
            value: 12345,
1810
            cashaddr: false,
1811
            address: "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7",
1812
            script: "00201863143c14c5166804bd19203356da136c985678cd4d27a1b8c6329604903262"
1813
        },
1814
        {
1815
            description: "p2pkh",
1816
            network: bitcoin.networks.testnet,
1817
            value: 12345,
1818
            cashaddr: false,
1819
            address: "muinVykhtZyonxQxk8zBptX6Lmri91bdNG",
1820
            script: "76a9149bce9399f9eeddad66635d4be171ec8f14decc5988ac"
1821
        },
1822
        {
1823
            description: "p2sh",
1824
            network: bitcoin.networks.testnet,
1825
            value: 12345,
1826
            cashaddr: false,
1827
            address: "2N7T4CD6CEuNHJoGKpoJH3YexqektXjyy6L",
1828
            script: "a9149bce9399f9eeddad66635d4be171ec8f14decc5987"
1829
        },
1830
        {
1831
            description: "p2sh cashaddr",
1832
            network: bitcoin.networks.bitcoincash,
1833
            value: 12345,
1834
            cashaddr: true,
1835
            address: "bitcoincash:ppm2qsznhks23z7629mms6s4cwef74vcwvn0h829pq",
1836
            script: "a91476a04053bda0a88bda5177b86a15c3b29f55987387"
1837
        }
1838
    ];
1839
1840
    fixtures.map(function(fixture) {
1841
        var network = fixture.network;
1842
        var payScriptOutputs = [{
1843
            scriptPubKey: fixture.script,
1844
            value: fixture.value
1845
        }];
1846
        var payAddressOutputs = [{
1847
            address: fixture.address,
1848
            value: fixture.value
1849
        }];
1850
        var payKeyedObject = {};
1851
        payKeyedObject[fixture.address] = fixture.value;
1852
        var payFlatArray = [
1853
            [fixture.address, fixture.value]
1854
        ];
1855
        [
1856
            {
1857
                desc: "deals with script outputs",
1858
                pay: payScriptOutputs
1859
            },
1860
            {
1861
                desc: "deals with address outputs",
1862
                pay: payAddressOutputs
1863
            },
1864
            {
1865
                desc: "deals with object keyed by address",
1866
                pay: payKeyedObject
1867
            },
1868
            {
1869
                desc: "deals with a flat output array",
1870
                pay: payFlatArray
1871
            }
1872
        ].map(function(f) {
1873
            it(fixture.description + " converted to script, " + f.desc, function(cb) {
1874
                var test = function(outputs) {
1875
                    assert.ok(Array.isArray(outputs));
1876
                    assert.equal(outputs[0].value, fixture.value);
1877
                    assert.equal(outputs[0].scriptPubKey, fixture.script);
1878
                    assert.equal(outputs[0].address, null);
1879
                };
1880
1881
                // should accept some input of ours
1882
                var outputs = Wallet.convertPayToOutputs(f.pay, network, fixture.cashaddr);
1883
                test(outputs);
1884
1885
                // repeating the procedure should pass the same test
1886
                var outputs2 = Wallet.convertPayToOutputs(outputs, network, fixture.cashaddr);
1887
                test(outputs2);
1888
1889
                outputs.map(function(output, i) {
1890
                    assert.equal(outputs[i].scriptPubKey, outputs2[i].scriptPubKey);
1891
                    assert.equal(outputs[i].value, outputs2[i].value);
1892
                });
1893
1894
                cb();
1895
            });
1896
        });
1897
    });
1898
});
1899
1900
describe('test wallet coin selection forms', function() {
1901
    var wallet;
1902
1903
    it("BTC testnet wallet should exist", function(cb) {
1904
        client.initWallet({
1905
            identifier: "unittest-transaction",
1906
            passphrase: "password"
1907
        }, function(err, _wallet) {
1908
            assert.ifError(err);
1909
            assert.ok(_wallet);
1910
1911
            wallet = _wallet;
1912
1913
            client.allWallets({page: 1}, function(err, wallets) {
1914
                assert.ifError(err);
1915
1916
                assert.ok(wallets['data'].length > 0);
1917
1918
                assert.equal(wallet.primaryMnemonic, "give pause forget seed dance crawl situate hole keen");
1919
                assert.equal(wallet.identifier, "unittest-transaction");
1920
                assert.equal(wallet.getBlocktrailPublicKey("M/9999'").toBase58(), "tpubD9q6vq9zdP3gbhpjs7n2TRvT7h4PeBhxg1Kv9jEc1XAss7429VenxvQTsJaZhzTk54gnsHRpgeeNMbm1QTag4Wf1QpQ3gy221GDuUCxgfeZ");
1921
1922
                cb();
1923
            });
1924
        });
1925
    });
1926
1927
    it("shouldnt coin select for wrong network", function(cb) {
1928
        var pay = {};
1929
        pay["bc1qqy36hngpyw4u6qfr40xszgate5qj827dqy36hngpyw4u6qfr40xsp3an42"] = 10000;
1930
        wallet.coinSelection(pay, function(err, res) {
0 ignored issues
show
Unused Code introduced by
The parameter res is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
1931
            assert.ok(err);
1932
            cb();
1933
        });
1934
    });
1935
1936
    var fixtures = [
1937
        {"tb1qn08f8x0eamw66enrt497zu0v3u2danzey6asqs": 10000},
1938
        {"tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7": 10000},
1939
        [
1940
            {
1941
                "address": "tb1qn08f8x0eamw66enrt497zu0v3u2danzey6asqs",
1942
                "value": 10000
1943
            },
1944
            {
1945
                "address": "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7",
1946
                "value": 10000
1947
            }
1948
        ],
1949
        [
1950
            {
1951
                "scriptPubKey": "00149bce9399f9eeddad66635d4be171ec8f14decc59",
1952
                "value": 10000
1953
            },
1954
            {
1955
                "address": "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7",
1956
                "value": 10000
1957
            }
1958
        ]
1959
    ];
1960
1961
    fixtures.map(function(fixture) {
1962
        var type = "object";
1963
        if (Array.isArray(fixture)) {
1964
            type = "outputs array";
1965
        }
1966
        it("should coin select for " + type, function(cb) {
1967
            wallet.coinSelection(fixture, false, function(err, res) {
0 ignored issues
show
Unused Code introduced by
The parameter res is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
1968
                assert.ifError(err);
1969
                cb();
1970
            });
1971
        });
1972
    });
1973
});
1974
1975
describe('test wallet list transactions and addresses', function() {
1976
    var wallet;
1977
1978
    it("should exists", function(cb) {
1979
        client.initWallet({
1980
            identifier: "unittest-transaction",
1981
            passphrase: "password"
1982
        }, function(err, _wallet) {
1983
            assert.ifError(err);
1984
            assert.ok(_wallet);
1985
1986
            wallet = _wallet;
1987
1988
            client.allWallets({page: 1}, function(err, wallets) {
1989
                assert.ifError(err);
1990
1991
                assert.ok(wallets['data'].length > 0);
1992
1993
                assert.equal(wallet.primaryMnemonic, "give pause forget seed dance crawl situate hole keen");
1994
                assert.equal(wallet.identifier, "unittest-transaction");
1995
                assert.equal(wallet.getBlocktrailPublicKey("M/9999'").toBase58(), "tpubD9q6vq9zdP3gbhpjs7n2TRvT7h4PeBhxg1Kv9jEc1XAss7429VenxvQTsJaZhzTk54gnsHRpgeeNMbm1QTag4Wf1QpQ3gy221GDuUCxgfeZ");
1996
1997
                cb();
1998
            });
1999
        });
2000
    });
2001
2002
    it("should list expected transactions", function(cb) {
2003
        wallet.transactions({page: 1, limit: 23}, function(err, transactions) {
2004
            assert.ifError(err);
2005
            assert.ok(transactions['data']);
2006
            assert.ok(transactions['total']);
2007
            assert.ok(transactions['data'].length === 23);
2008
            assert.ok(transactions['data'][0]['hash'], "2cb21783635a5f22e9934b8c3262146b42d251dfb14ee961d120936a6c40fe89");
2009
2010
            cb();
2011
        });
2012
    });
2013
2014
    it("should list expected addresses", function(cb) {
2015
        wallet.addresses({page: 1, limit: 23}, function(err, addresses) {
2016
            assert.ifError(err);
2017
            assert.ok(addresses['data']);
2018
            assert.ok(addresses['total']);
2019
            assert.ok(addresses['data'].length === 23);
2020
            assert.ok(addresses['data'][0]['address'], "2MzyKviSL6pnWxkbHV7ecFRE3hWKfzmT8WS");
2021
2022
            cb();
2023
        });
2024
    });
2025
2026
    it("should list UTXOs", function(cb) {
2027
        wallet.utxos({page: 0, limit: 23}, function(err, addresses) {
2028
            assert.ifError(err);
2029
            assert.ok(addresses['data']);
2030
            assert.ok(addresses['total']);
2031
            assert.ok(addresses['data'].length === 23);
2032
2033
            cb();
2034
        });
2035
    });
2036
});
2037
2038
describe("size estimation", function() {
2039
2040
    it("should estimate proper size for 1 input 1 output TX", function() {
2041
        var txb = new bitcoin.TransactionBuilder(bitcoin.networks.testnet);
2042
        txb.addInput('4200000000000000000000000000000000000000000000000000000000000000', 0);
2043
        txb.addOutput('2MzyKviSL6pnWxkbHV7ecFRE3hWKfzmT8WS', 1);
2044
2045
        assert.equal(347, blocktrail.Wallet.estimateIncompleteTxSize(txb.buildIncomplete()));
2046
    });
2047
2048
    it("should estimate proper size for 99 inputs 1 output TX", function() {
2049
        var txb = new bitcoin.TransactionBuilder(bitcoin.networks.testnet);
2050
        for (var i = 0; i < 99; i++) {
2051
            txb.addInput('4200000000000000000000000000000000000000000000000000000000000000', i);
2052
        }
2053
        txb.addOutput('2MzyKviSL6pnWxkbHV7ecFRE3hWKfzmT8WS', 1);
2054
2055
        assert.equal(29453, blocktrail.Wallet.estimateIncompleteTxSize(txb.buildIncomplete()));
2056
    });
2057
2058
    it("should estimate proper size for 1 input 99 outputs TX", function() {
2059
        var txb = new bitcoin.TransactionBuilder(bitcoin.networks.testnet);
2060
        txb.addInput('4200000000000000000000000000000000000000000000000000000000000000', 0);
2061
        for (var i = 0; i < 99; i++) {
2062
            txb.addOutput('2MzyKviSL6pnWxkbHV7ecFRE3hWKfzmT8WS', 1);
2063
        }
2064
2065
        assert.equal(3679, blocktrail.Wallet.estimateIncompleteTxSize(txb.buildIncomplete()));
2066
    });
2067
});
2068
2069
describe("APIClient", function() {
2070
    it("resolvePrimaryPrivateKeyFromOptions", function(cb) {
2071
        client.resolvePrimaryPrivateKeyFromOptions({
2072
            passphrase: "password",
2073
            primaryMnemonic: "give pause forget seed dance crawl situate hole keen"
2074
        }, function(err, options) {
2075
            assert.ifError(err);
2076
            assert.ok(options.primaryPrivateKey);
2077
            assert.ok(options.primaryPrivateKey instanceof bitcoin.HDNode);
2078
            assert.equal("tprv8ZgxMBicQKsPeR93md5eVTbLDgQ8kfV4CDNtrVXv5p29KXtx7VHKFQThGkFgC61sYeeeaVH1yFv4thcvxS9cYdFrYwTNmkGhkQEJycSzAhE", options.primaryPrivateKey.toBase58());
2079
2080
            cb();
2081
2082
        });
2083
    });
2084
});
2085
2086
describe("bitcoin cash address switching", function() {
2087
    describe("APIClient.getLegacyBitcoinCashAddress", function() {
2088
        describe("doesnt work with BTC", function() {
2089
            it("fails", function(cb) {
2090
                var tbtcNetwork = _createApiClient("BTC", true);
2091
                var err;
2092
                try {
2093
                    tbtcNetwork.getLegacyBitcoinCashAddress("1BpEi6DfDAUFd7GtittLSdBeYJvcoaVggu");
2094
                } catch (e) {
2095
                    err = e;
2096
                }
2097
2098
                assert.ok(err);
0 ignored issues
show
Bug introduced by
The variable err seems to not be initialized for all possible execution paths. Are you sure ok handles undefined variables?
Loading history...
2099
                assert.ok("Cash addresses only work on bitcoin cash" === err.message);
2100
                cb();
2101
            });
2102
        });
2103
2104
        function testLegacyFromCashAddress(network, testnet, legacy, cash) {
2105
            var bccNetwork = _createApiClient(network, testnet);
2106
2107
            it("returns base58 address if that was given", function(cb) {
2108
                assert.ok(legacy === bccNetwork.getLegacyBitcoinCashAddress(legacy));
2109
                cb();
2110
            });
2111
            it("returns legacy address for cashaddress", function(cb) {
2112
                assert.ok(legacy === bccNetwork.getLegacyBitcoinCashAddress(cash));
2113
                cb();
2114
            });
2115
        }
2116
2117
        describe ("works with BCC testnet (P2SH)", function() {
2118
            testLegacyFromCashAddress("BCC", true, "2N44ThNe8NXHyv4bsX8AoVCXquBRW94Ls7W", "bchtest:ppm2qsznhks23z7629mms6s4cwef74vcwvhanqgjxu");
2119
        });
2120
        describe ("works with BCC (P2SH)", function() {
2121
            testLegacyFromCashAddress("BCC", false, "3LDsS579y7sruadqu11beEJoTjdFiFCdX4", "bitcoincash:pr95sy3j9xwd2ap32xkykttr4cvcu7as4yc93ky28e");
2122
        });
2123
        describe ("works with BCC (P2PKH)", function() {
2124
            testLegacyFromCashAddress("BCC", false, "1BpEi6DfDAUFd7GtittLSdBeYJvcoaVggu", "bitcoincash:qpm2qsznhks23z7629mms6s4cwef74vcwvy22gdx6a");
2125
        });
2126
    });
2127
2128
2129
    describe("APIClient.getCashAddressFromLegacyAddress", function() {
2130
        describe("doesnt work with BTC", function() {
2131
            it("fails", function(cb) {
2132
                var tbtcNetwork = _createApiClient("BTC", true);
2133
                var err;
2134
                try {
2135
                    tbtcNetwork.getCashAddressFromLegacyAddress("1BpEi6DfDAUFd7GtittLSdBeYJvcoaVggu");
2136
                } catch (e) {
2137
                    err = e;
2138
                }
2139
2140
                assert.ok(err);
0 ignored issues
show
Bug introduced by
The variable err seems to not be initialized for all possible execution paths. Are you sure ok handles undefined variables?
Loading history...
2141
                assert.ok("Cash addresses only work on bitcoin cash" === err.message);
2142
                cb();
2143
            });
2144
        });
2145
2146
        function testCashFromLegacyAddress(network, testnet, cash, legacy) {
2147
            var bccNetwork = _createApiClient(network, testnet);
2148
2149
            it("returns cash address if that was given", function(cb) {
2150
                assert.ok(cash === bccNetwork.getCashAddressFromLegacyAddress(cash));
2151
                cb();
2152
            });
2153
2154
            it("returns cash address for base58 address", function(cb) {
2155
                assert.ok(cash === bccNetwork.getCashAddressFromLegacyAddress(legacy));
2156
                cb();
2157
            });
2158
        }
2159
2160
        describe ("works with BCC testnet (P2SH)", function() {
2161
            testCashFromLegacyAddress("BCC", true, "bchtest:ppm2qsznhks23z7629mms6s4cwef74vcwvhanqgjxu", "2N44ThNe8NXHyv4bsX8AoVCXquBRW94Ls7W");
2162
        });
2163
2164
        describe ("works with BCC (P2SH)", function() {
2165
            testCashFromLegacyAddress("BCC", false, "bitcoincash:pr95sy3j9xwd2ap32xkykttr4cvcu7as4yc93ky28e", "3LDsS579y7sruadqu11beEJoTjdFiFCdX4");
2166
        });
2167
2168
        describe ("works with BCC (P2PKH)", function() {
2169
            testCashFromLegacyAddress("BCC", false, "bitcoincash:qpm2qsznhks23z7629mms6s4cwef74vcwvy22gdx6a", "1BpEi6DfDAUFd7GtittLSdBeYJvcoaVggu");
2170
        });
2171
    });
2172
2173
    var wallet;
2174
2175
    describe("wallet send", function() {
2176
        /**
2177
         * @type APIClient
2178
         */
2179
        var tbccClient = _createApiClient("BCC", true);
2180
        var legacyAddress;
2181
        var cashAddress;
2182
        it("should exists", function(cb) {
2183
            tbccClient.initWallet({
2184
                identifier: "unittest-transaction",
2185
                passphrase: "password",
2186
                useCashAddress: true
2187
            }, function(err, _wallet) {
2188
                assert.ifError(err);
2189
                assert.ok(_wallet);
2190
2191
                wallet = _wallet;
2192
                cb();
2193
            });
2194
        });
2195
2196
        it("generates an address", function(cb) {
2197
            wallet.getNewAddress(function(err, result) {
2198
                assert.ifError(err);
2199
                legacyAddress = tbccClient.getLegacyBitcoinCashAddress(result);
2200
                cashAddress = result;
2201
                cb();
2202
            });
2203
        });
2204
2205
        it("sends to legacy address", function(cb) {
2206
            var pay = {};
2207
            pay[legacyAddress] = 100000;
2208
            wallet.pay(pay, null, false, false, function(err, result) {
0 ignored issues
show
Unused Code introduced by
The parameter result is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
2209
                assert.ifError(err);
2210
                cb();
2211
            });
2212
        });
2213
2214
        it("sends to casah address", function(cb) {
2215
            var pay = {};
2216
            pay[cashAddress] = 100000;
2217
            wallet.pay(pay, null, false, false, function(err, result) {
0 ignored issues
show
Unused Code introduced by
The parameter result is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
2218
                assert.ifError(err);
2219
                cb();
2220
            });
2221
        });
2222
    });
2223
});
2224