Completed
Push — master ( 474c17...968c00 )
by Tobias
03:17 queued 55s
created

(CAPITAL) without prefixꞌ)   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8

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 8
rs 9.4285
nop 1
1
/* global window */
2
/* jshint -W101, -W098 */
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
var window = window || {};
0 ignored issues
show
Bug introduced by
The variable window seems to be never initialized.
Loading history...
15
16
/**
17
 *
18
 * @param network
19
 * @param testnet
20
 * @returns {*}
21
 * @private
22
 */
23
function _createApiClient(network, testnet) {
24
    return blocktrail.BlocktrailSDK({
25
        apiKey: process.env.BLOCKTRAIL_SDK_APIKEY || window.BLOCKTRAIL_SDK_APIKEY || "EXAMPLE_BLOCKTRAIL_SDK_NODEJS_APIKEY",
26
        apiSecret: process.env.BLOCKTRAIL_SDK_APISECRET || window.BLOCKTRAIL_SDK_APISECRET || "EXAMPLE_BLOCKTRAIL_SDK_NODEJS_APISECRET",
27
        network: network,
28
        testnet: testnet,
29
        btccom: typeof process.env.BLOCKTRAIL_SDK_BTCCOM !== "undefined" ? JSON.parse(process.env.BLOCKTRAIL_SDK_BTCCOM) : true
30
    });
31
}
32
33
/**
34
 * @type APIClient
35
 */
36
var client = _createApiClient("BTC", true);
37
38
var TRANSACTION_TEST_WALLET_PRIMARY_MNEMONIC = "give pause forget seed dance crawl situate hole keen",
39
    TRANSACTION_TEST_WALLET_BACKUP_MNEMONIC = "give pause forget seed dance crawl situate hole give",
40
    TRANSACTION_TEST_WALLET_PASSWORD = "password";
41
42
var _createTestWallet = function(identifier, passphrase, primaryMnemonic, backupMnemonic, segwit, cb) {
43
    var keyIndex = 9999;
44
    var network = client.testnet ? bitcoin.networks.testnet : bitcoin.networks.bitcoin;
45
46
    var primarySeed = bip39.mnemonicToSeed(primaryMnemonic, passphrase);
47
    var primaryPrivateKey = bitcoin.HDNode.fromSeedBuffer(primarySeed, network);
48
49
    var backupSeed = bip39.mnemonicToSeed(backupMnemonic, "");
50
    var backupPrivateKey = bitcoin.HDNode.fromSeedBuffer(backupSeed, network);
51
    var backupPublicKey = backupPrivateKey.neutered();
52
53
    var checksum = primaryPrivateKey.getAddress();
54
    var primaryPublicKey = primaryPrivateKey.deriveHardened(keyIndex).neutered();
55
56
    client.storeNewWalletV1(
57
        identifier,
58
        [primaryPublicKey.toBase58(), "M/" + keyIndex + "'"],
59
        [backupPublicKey.toBase58(), "M"],
60
        primaryMnemonic,
61
        checksum,
62
        keyIndex,
63
        segwit
64
    ).then(function(result) {
65
        var blocktrailPublicKeys = _.mapValues(result.blocktrail_public_keys, function(blocktrailPublicKey) {
66
            return bitcoin.HDNode.fromBase58(blocktrailPublicKey[0], network);
67
        });
68
69
        var wallet = new blocktrail.Wallet(
70
            client,
71
            identifier,
72
            blocktrail.Wallet.WALLET_VERSION_V1,
73
            primaryMnemonic,
74
            null,
75
            null,
76
            {keyIndex: primaryPublicKey},
77
            backupPublicKey,
78
            blocktrailPublicKeys,
79
            keyIndex,
80
            result.segwit || 0,
81
            client.testnet,
82
            client.regtest,
83
            checksum
84
        );
85
86
        wallet.unlock({
87
            passphrase: passphrase
88
        }, function(err) {
89
            cb(err, wallet);
90
        });
91
92
    }, function(err) {
93
        return cb(err);
94
    });
95
};
96
97
var createUpgradeKeyIndexTestWallet = function(identifier, passphrase, cb) {
98
    var primaryMnemonic = "give pause forget seed dance crawl situate hole kingdom";
99
    var backupMnemonic = "give pause forget seed dance crawl situate hole course";
100
101
    return _createTestWallet(identifier, passphrase, primaryMnemonic, backupMnemonic, false, cb);
102
};
103
104
var createTransactionTestWallet = function(identifier, segwit, cb) {
105
    return _createTestWallet(
106
        identifier,
107
        TRANSACTION_TEST_WALLET_PASSWORD,
108
        TRANSACTION_TEST_WALLET_PRIMARY_MNEMONIC,
109
        TRANSACTION_TEST_WALLET_BACKUP_MNEMONIC,
110
        segwit,
111
        cb
112
    );
113
};
114
115
var createRecoveryTestWallet = function(identifier, passphrase, cb) {
116
    var primaryMnemonic = "give pause forget seed dance crawl situate hole join";
117
    var backupMnemonic = "give pause forget seed dance crawl situate hole crater";
118
119
    return _createTestWallet(identifier, passphrase, primaryMnemonic, backupMnemonic, false, cb);
120
};
121
122
describe('Initialize with check_backup_key', function() {
123
    it('rejects invalid inputs', function(cb) {
124
        try {
125
            client.initWallet({
126
                identifier: "unittest-transaction",
127
                password: "password",
128
                check_backup_key: []
129
            });
130
            assert(false);
131
        } catch (e) {
132
            assert.equal("Invalid input, must provide the backup key as a string (the xpub)", e.message);
133
        }
134
        cb();
135
    });
136
137
    it('checks against the string', function(cb) {
138
        client.initWallet({
139
            identifier: "unittest-transaction",
140
            password: "password",
141
            check_backup_key: 'for demonstration purposes only'
142
        }, 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...
143
            assert.ok(err);
144
            assert.equal("Backup key returned from server didn't match our own copy", err.message);
145
            cb();
146
        });
147
    });
148
149
    it('allows if the backup key matches', function(cb) {
150
        // You wouldn't keep your backup seed in your code,
151
        // dump it from the wallet upon generation
152
153
        var backupSeed = bip39.mnemonicToSeed(TRANSACTION_TEST_WALLET_BACKUP_MNEMONIC, "");
154
        var backupPrivateKey = bitcoin.HDNode.fromSeedBuffer(backupSeed, bitcoin.networks.testnet);
155
        var backupPublicKey = backupPrivateKey.neutered();
156
        var xpub = backupPublicKey.toBase58();
157
158
        // Would be saves as a string in code..
159
        client.initWallet({
160
            identifier: "unittest-transaction",
161
            password: "password",
162
            check_backup_key: xpub
163
        }, function(err, _wallet) {
164
            assert.ifError(err);
165
            assert.ok(_wallet);
166
            cb();
167
        });
168
    });
169
});
170
171
/**
172
 * Test operations on v2 and v3 wallets.
173
 * Also tests the default, encouraging to look at this test if it changes again.
174
 */
175
[
176
  blocktrail.Wallet.WALLET_VERSION_V2,
177
  blocktrail.Wallet.WALLET_VERSION_V3,
178
  null /* test our assumed default version */
179
].map(function(walletVersion) {
180
    var assumedDefault = blocktrail.Wallet.WALLET_VERSION_V3;
181
    describe('test new blank wallet, ' + walletVersion, function() {
182
        var myIdentifier = "nodejs-sdk-" + crypto.randomBytes(24).toString('hex');
183
        var wallet;
184
185
        after(function(cb) {
186
            if (wallet) {
187
                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...
188
                    cb();
189
                });
190
            } else {
191
                cb();
192
            }
193
        });
194
195
        it("shouldn't already exist", function(cb) {
196
            client.initWallet({
197
                identifier: myIdentifier,
198
                readOnly: true
199
            }, function(err, wallet) {
200
                assert.ok(err);
201
                assert.ok(!wallet, "wallet with random ID [" + myIdentifier + "] already exists...");
202
203
                cb();
204
            });
205
        });
206
207
        it("should be created", function(cb) {
208
            var progress = [];
209
            var cnf = {
210
                identifier: myIdentifier,
211
                passphrase: "password",
212
                keyIndex: 9999
213
            };
214
215
            var expectedVersion = assumedDefault;
216
            if (walletVersion !== null) {
217
                cnf.walletVersion = walletVersion;
218
                expectedVersion = walletVersion;
219
            }
220
221
            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...
222
                assert.ifError(err);
223
                assert.ok(_wallet);
224
225
                wallet = _wallet;
226
                assert.equal(wallet.walletVersion, expectedVersion);
227
                assert.equal(wallet.identifier, myIdentifier);
228
                assert.equal(wallet.getBlocktrailPublicKey("M/9999'").toBase58(), "tpubD9q6vq9zdP3gbhpjs7n2TRvT7h4PeBhxg1Kv9jEc1XAss7429VenxvQTsJaZhzTk54gnsHRpgeeNMbm1QTag4Wf1QpQ3gy221GDuUCxgfeZ");
229
230
                assert.deepEqual(progress, [
231
                    blocktrail.CREATE_WALLET_PROGRESS_START,
232
                    blocktrail.CREATE_WALLET_PROGRESS_ENCRYPT_SECRET,
233
                    blocktrail.CREATE_WALLET_PROGRESS_ENCRYPT_PRIMARY,
234
                    blocktrail.CREATE_WALLET_PROGRESS_ENCRYPT_RECOVERY,
235
                    blocktrail.CREATE_WALLET_PROGRESS_PRIMARY,
236
                    blocktrail.CREATE_WALLET_PROGRESS_BACKUP,
237
                    blocktrail.CREATE_WALLET_PROGRESS_SUBMIT,
238
                    blocktrail.CREATE_WALLET_PROGRESS_INIT,
239
                    blocktrail.CREATE_WALLET_PROGRESS_DONE
240
                ]);
241
242
                cb();
243
            })
244
            .progress(function(p) { progress.push(p); });
245
        });
246
247
        it("should lock", function(cb) {
248
            assert(!wallet.locked);
249
            wallet.lock();
250
            assert(wallet.locked);
251
            cb();
252
        });
253
254
        it("should init", function(cb) {
255
            client.initWallet({
256
                identifier: myIdentifier,
257
                readOnly: true
258
            }, function(err, _wallet) {
259
                assert.ifError(err);
260
                assert.ok(_wallet);
261
262
                wallet = _wallet;
263
264
                cb();
265
            });
266
        });
267
268
        it("should have a 0 balance", function(cb) {
269
            wallet.getBalance(function(err, confirmed, unconfirmed) {
270
                assert.ifError(err);
271
                assert.equal(confirmed, 0);
272
                assert.equal(unconfirmed, 0);
273
274
                cb();
275
            });
276
        });
277
278
        it("shouldn't be able to pay when locked", function(cb) {
279
            wallet.pay({
280
                "2N6Fg6T74Fcv1JQ8FkPJMs8mYmbm9kitTxy": blocktrail.toSatoshi(0.001)
281
            }, 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...
282
                assert.ok(!!err && err.message.match(/unlocked/));
283
                assert.ok(err instanceof blocktrail.WalletLockedError);
284
285
                cb();
286
            });
287
        });
288
289
        it("shouldn't be able to upgrade when locked", function(cb) {
290
            wallet.upgradeKeyIndex(10000, function(err) {
291
                assert.ok(!!err && err.message.match(/unlocked/));
292
                assert.ok(err instanceof blocktrail.WalletLockedError);
293
294
                cb();
295
            });
296
        });
297
298
        it("should unlock", function(cb) {
299
            wallet.unlock({password: "password"}, function(err) {
300
                assert.ifError(err);
301
302
                cb();
303
            });
304
        });
305
306
        it("should be able to unlock with secret", function(cb) {
307
            var secret = wallet.secret;
308
309
            wallet.lock();
310
            wallet.unlock({secret: secret}, function(err) {
311
                assert.ifError(err);
312
                cb();
313
            });
314
        });
315
316
        it("shouldn't be able to pay when unlocked (because of no balance)", function(cb) {
317
            wallet.pay({
318
                "2N6Fg6T74Fcv1JQ8FkPJMs8mYmbm9kitTxy": blocktrail.toSatoshi(0.001)
319
            }, 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...
320
                assert.ok(!!err && (err.message.match(/balance/) || err.message.match(/failed/i)));
321
322
                cb();
323
            });
324
        });
325
326
        it("should be able to upgrade when unlocked", function(cb) {
327
            wallet.upgradeKeyIndex(10000, function(err) {
328
                assert.ifError(err);
329
330
                cb();
331
            });
332
        });
333
334
        it("should be able to password change", function(cb) {
335
            wallet.passwordChange("password2", function(err) {
336
                assert.ifError(err);
337
338
                client.initWallet({
339
                    identifier: myIdentifier,
340
                    password: "password2"
341
                }, function(err, _wallet) {
342
                    assert.ifError(err);
343
                    assert.ok(_wallet);
344
345
                    wallet = _wallet;
346
347
                    cb();
348
                });
349
            });
350
        });
351
352
        [
353
            ['', 'string'],
354
            [false, 'string'],
355
            [true, 'boolean']
356
        ].map(function(fixture) {
357
            var invalidInput = fixture[0];
358
            var type = fixture[1];
359
            it('refuses to derive with invalid chain index variable ' + type, function(cb) {
360
                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...
361
                    assert.ok(!!err && err.message.match(/chain index/));
362
                    cb();
363
                });
364
            });
365
        });
366
    });
367
});
368
369
/**
370
 * Test operations on v2 and v3 wallets.
371
 */
372
[
373
    blocktrail.Wallet.WALLET_VERSION_V1,
374
    blocktrail.Wallet.WALLET_VERSION_V2,
375
    blocktrail.Wallet.WALLET_VERSION_V3
376
].map(function(walletVersion) {
377
    var primarySeed = bip39.mnemonicToSeed(TRANSACTION_TEST_WALLET_PRIMARY_MNEMONIC, TRANSACTION_TEST_WALLET_PASSWORD);
378
379
    describe('test input errors, ' + walletVersion, function() {
380
        it("shouldn't allow primaryPrivateKey in creation", function(cb) {
381
            var myIdentifier = "nodejs-sdk-" + crypto.randomBytes(24).toString('hex');
382
            var primaryPrivateKey = bitcoin.HDNode.fromSeedBuffer(primarySeed, bitcoin.networks.testnet);
383
384
            client.createNewWallet({
385
                identifier: myIdentifier,
386
                passphrase: "password",
387
                primaryPrivateKey: primaryPrivateKey,
388
                walletVersion: walletVersion,
389
                keyIndex: 9999
390
            }, 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...
391
                assert.ok(!!err, "should error");
392
393
                cb();
394
            });
395
        });
396
397
        it("shouldn't allow unlocking with primaryPrivateKey", function(cb) {
398
            client.createNewWallet({
399
                identifier: "unittest-transaction-inputerr-" + walletVersion,
400
                primarySeed: primarySeed,
401
                walletVersion: walletVersion,
402
                keyIndex: 9999
403
            }).then(function(r) {
404
                var wallet = r[0];
405
                wallet.lock();
406
                return wallet;
407
            }, function(err) {
408
                assert.ok(err.message.match(/already exists/));
409
410
                return client.initWallet({
411
                    identifier: "unittest-transaction-inputerr-" + walletVersion,
412
                    readOnly: true
413
                });
414
            }).then(function(wallet) {
415
                assert.equal(wallet.getBlocktrailPublicKey("M/9999'").toBase58(), "tpubD9q6vq9zdP3gbhpjs7n2TRvT7h4PeBhxg1Kv9jEc1XAss7429VenxvQTsJaZhzTk54gnsHRpgeeNMbm1QTag4Wf1QpQ3gy221GDuUCxgfeZ");
416
417
                return wallet.unlock({primaryPrivateKey: bitcoin.HDNode.fromSeedBuffer(primarySeed, bitcoin.networks.testnet)})
418
                    .then(function() {
419
                        return;
0 ignored issues
show
Unused Code introduced by
This return has no effect and can be removed.
Loading history...
420
                    }, function(err) {
421
                        return err;
422
                    });
423
            })
424
                .then(function(err) {
425
                    assert.ok(!!err, "should error");
426
                    cb();
427
                })
428
                .done();
429
        });
430
    });
431
});
432
433
/**
434
 * Test upgrade to V3 from V1 and V2
435
 */
436
[
437
    blocktrail.Wallet.WALLET_VERSION_V1,
438
    blocktrail.Wallet.WALLET_VERSION_V2
439
].map(function(walletVersion) {
440
    describe("upgrade to V3 from " + walletVersion, function() {
441
        var myIdentifier = "nodejs-sdk-" + crypto.randomBytes(24).toString('hex');
442
        var passphrase = "password";
443
        var wallet;
444
445
        after(function(cb) {
446
            if (wallet) {
447
                wallet.deleteWallet(true, function(err, result) {
448
                    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...
449
                    cb();
450
                });
451
            } else {
452
                cb();
453
            }
454
        });
455
456
        it("can upgrade", function() {
457
            var addr;
458
            return client.createNewWallet({
459
                identifier: myIdentifier,
460
                passphrase: passphrase,
461
                walletVersion: walletVersion,
462
                keyIndex: 9999
463
            })
464
                .then(function(r) {
465
                    return r[0];
466
                })
467
                .then(function(_wallet) {
468
                    wallet = _wallet;
469
                    addr = wallet.getAddressByPath("M/9999'/0/0");
470
471
                    return wallet;
472
                })
473
                .then(function(wallet) {
474
                    var progress = [];
475
476
                    return wallet.upgradeToV3(passphrase)
477
                        .progress(function(p) {
478
                            progress.push(p);
479
                        })
480
                        .then(function() {
481
                            assert(progress.length);
482
                            return wallet;
483
                        });
484
                })
485
                .then(function(wallet) {
486
                    assert.equal(addr, wallet.getAddressByPath("M/9999'/0/0"));
487
                });
488
        });
489
490
        it("can unlock with secret", function() {
491
            var secret = wallet.secret;
492
            wallet.lock();
493
            return wallet.unlock({secret: secret});
494
        });
495
496
        it("can init after upgrade", function() {
497
            return client.initWallet({
498
                identifier: myIdentifier,
499
                passphrase: passphrase,
500
                keyIndex: 9999
501
            });
502
        });
503
    });
504
});
505
506
describe('test new blank wallet, v1', function() {
507
    var myIdentifier = "nodejs-sdk-" + crypto.randomBytes(24).toString('hex');
508
    var wallet;
509
510
    after(function(cb) {
511
        if (wallet) {
512
            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...
513
                cb();
514
            });
515
        } else {
516
            cb();
517
        }
518
    });
519
520
    it("shouldn't already exist", function(cb) {
521
        client.initWallet({
522
            identifier: myIdentifier,
523
            readOnly: true
524
        }, function(err, wallet) {
525
            assert.ok(err);
526
            assert.ok(!wallet, "wallet with random ID [" + myIdentifier + "] already exists...");
527
528
            cb();
529
        });
530
    });
531
532
    it("should be created", function(cb) {
533
        var progress = [];
534
535
        client.createNewWallet({
536
                identifier: myIdentifier,
537
                passphrase: "password",
538
                keyIndex: 9999,
539
                walletVersion: blocktrail.Wallet.WALLET_VERSION_V1
540
            }, function(err, _wallet) {
541
                assert.ifError(err);
542
                assert.ok(_wallet);
543
544
                wallet = _wallet;
545
546
                assert.equal(wallet.identifier, myIdentifier);
547
                assert.equal(wallet.getBlocktrailPublicKey("M/9999'").toBase58(), "tpubD9q6vq9zdP3gbhpjs7n2TRvT7h4PeBhxg1Kv9jEc1XAss7429VenxvQTsJaZhzTk54gnsHRpgeeNMbm1QTag4Wf1QpQ3gy221GDuUCxgfeZ");
548
549
                assert.deepEqual(progress, [
550
                    blocktrail.CREATE_WALLET_PROGRESS_START,
551
                    blocktrail.CREATE_WALLET_PROGRESS_PRIMARY,
552
                    blocktrail.CREATE_WALLET_PROGRESS_BACKUP,
553
                    blocktrail.CREATE_WALLET_PROGRESS_SUBMIT,
554
                    blocktrail.CREATE_WALLET_PROGRESS_INIT,
555
                    blocktrail.CREATE_WALLET_PROGRESS_DONE
556
                ]);
557
558
                cb();
559
            }
560
        ).progress(function(p) { progress.push(p); });
561
    });
562
563
    it("should lock", function(cb) {
564
        assert(!wallet.locked);
565
        wallet.lock();
566
        assert(wallet.locked);
567
        cb();
568
    });
569
570
    it("should init", function(cb) {
571
        client.initWallet({
572
            identifier: myIdentifier,
573
            readOnly: true
574
        }, function(err, _wallet) {
575
            assert.ifError(err);
576
            assert.ok(_wallet);
577
            assert.equal(wallet.walletVersion, 'v1');
578
579
            wallet = _wallet;
580
581
            cb();
582
        });
583
    });
584
585
    it("should have a 0 balance", function(cb) {
586
        wallet.getBalance(function(err, confirmed, unconfirmed) {
587
            assert.ifError(err);
588
            assert.equal(confirmed, 0);
589
            assert.equal(unconfirmed, 0);
590
591
            cb();
592
        });
593
    });
594
595
    it("should unlock", function(cb) {
596
        wallet.unlock({password: "password"}, function(err) {
597
            assert.ifError(err);
598
599
            cb();
600
        });
601
    });
602
603
    it("shouldn't be able to password change", function(cb) {
604
        wallet.passwordChange("password2", function(err) {
605
            assert.ok(!!err && err.message.match(/version does not support/));
606
607
            cb();
608
        });
609
    });
610
});
611
612
describe('test new blank wallet, old syntax', function() {
613
    var myIdentifier = "nodejs-sdk-" + crypto.randomBytes(24).toString('hex');
614
    var wallet;
615
616
    after(function(cb) {
617
        if (wallet) {
618
            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...
619
                cb();
620
            });
621
        } else {
622
            cb();
623
        }
624
    });
625
626
    it("shouldn't already exist", function(cb) {
627
        client.initWallet(myIdentifier, "password", function(err, wallet) {
628
            assert.ok(err);
629
            assert.ok(!wallet, "wallet with random ID [" + myIdentifier + "] already exists...");
630
631
            cb();
632
        });
633
    });
634
635
    it("should be created", function(cb) {
636
        client.createNewWallet(myIdentifier, "password", 9999, function(err, _wallet) {
637
            assert.ifError(err);
638
            assert.ok(_wallet);
639
640
            wallet = _wallet;
641
642
            assert.equal(wallet.identifier, myIdentifier);
643
            assert.equal(wallet.getBlocktrailPublicKey("M/9999'").toBase58(), "tpubD9q6vq9zdP3gbhpjs7n2TRvT7h4PeBhxg1Kv9jEc1XAss7429VenxvQTsJaZhzTk54gnsHRpgeeNMbm1QTag4Wf1QpQ3gy221GDuUCxgfeZ");
644
            cb();
645
        });
646
    });
647
648
    it("should have a 0 balance", function(cb) {
649
        wallet.getBalance(function(err, confirmed, unconfirmed) {
650
            assert.ifError(err);
651
            assert.equal(confirmed, 0);
652
            assert.equal(unconfirmed, 0);
653
654
            cb();
655
        });
656
    });
657
658
    it("shouldn't be able to pay", function(cb) {
659
        wallet.pay({
660
            "2N6Fg6T74Fcv1JQ8FkPJMs8mYmbm9kitTxy": blocktrail.toSatoshi(0.001)
661
        }, 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...
662
            assert.ok(!!err);
663
664
            cb();
665
        });
666
    });
667
});
668
669
describe('test new wallet, without mnemonics', function() {
670
    var myIdentifier = "nodejs-sdk-" + crypto.randomBytes(24).toString('hex');
671
    var wallet;
672
673
    var primarySeed = bip39.mnemonicToSeed(bip39.generateMnemonic(512), "password");
674
    var backupPrivateKey = bitcoin.HDNode.fromSeedBuffer(bip39.mnemonicToSeed(bip39.generateMnemonic(512), ""), bitcoin.networks.testnet);
675
    var backupPublicKey = backupPrivateKey.neutered();
676
677
    after(function(cb) {
678
        if (wallet) {
679
            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...
680
                cb();
681
            });
682
        } else {
683
            cb();
684
        }
685
    });
686
687
    it("shouldn't already exist", function(cb) {
688
        client.initWallet({
689
            identifier: myIdentifier
690
        }, function(err, wallet) {
691
            assert.ok(err);
692
            assert.ok(!wallet, "wallet with random ID [" + myIdentifier + "] already exists...");
693
694
            cb();
695
        });
696
    });
697
698
    it("should be created", function(cb) {
699
        client.createNewWallet({
700
                identifier: myIdentifier,
701
                primarySeed: primarySeed,
702
                backupPublicKey: backupPublicKey,
703
                keyIndex: 9999
704
            }, function(err, _wallet) {
705
                assert.ifError(err);
706
                assert.ok(_wallet);
707
                assert.ok(!_wallet.isSegwit());
708
                assert.equal(blocktrail.Wallet.CHAIN_BTC_DEFAULT, _wallet.chain);
709
710
                wallet = _wallet;
711
712
                assert.equal(wallet.identifier, myIdentifier);
713
                assert.equal(wallet.getBlocktrailPublicKey("M/9999'").toBase58(), "tpubD9q6vq9zdP3gbhpjs7n2TRvT7h4PeBhxg1Kv9jEc1XAss7429VenxvQTsJaZhzTk54gnsHRpgeeNMbm1QTag4Wf1QpQ3gy221GDuUCxgfeZ");
714
                cb();
715
            }
716
        );
717
    });
718
719
    it("should be initializable", function(cb) {
720
        client.initWallet({
721
                identifier: myIdentifier,
722
                primarySeed: primarySeed,
723
                keyIndex: 9999
724
            }, function(err, _wallet) {
725
                assert.ifError(err);
726
                assert.ok(_wallet);
727
                assert.ok(!_wallet.isSegwit());
728
                assert.equal(blocktrail.Wallet.CHAIN_BTC_DEFAULT, _wallet.chain);
729
730
                wallet = _wallet;
731
732
                cb();
733
            }
734
        );
735
    });
736
737
    it("should have a 0 balance", function(cb) {
738
        wallet.getBalance(function(err, confirmed, unconfirmed) {
739
            assert.ifError(err);
740
            assert.equal(confirmed, 0);
741
            assert.equal(unconfirmed, 0);
742
743
            cb();
744
        });
745
    });
746
747
    it("shouldn't be able to pay", function(cb) {
748
        wallet.pay({
749
            "2N6Fg6T74Fcv1JQ8FkPJMs8mYmbm9kitTxy": blocktrail.toSatoshi(0.001)
750
        }, 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...
751
            assert.ok(!!err);
752
753
            cb();
754
        });
755
    });
756
});
757
758
describe('test wallet, bitcoin cash mirror', function() {
759
    var tbccClient = _createApiClient("BCC", true);
760
761
    [
762
        {useCashAddress: false, addressType: "base58", description: "false uses base58 address"},
763
        {useCashAddress: true,  addressType: "cashaddr", description: "can opt into cash address"}
764
765
    ].map(function(fixture) {
766
        var useCashAddress = fixture.useCashAddress;
767
        var expectType = fixture.addressType;
768
        var description = fixture.description;
769
770
        var wallet;
771
        var address;
772
773
        it(description, function(cb) {
774
            tbccClient.initWallet({
775
                identifier: "unittest-transaction",
776
                passphrase: TRANSACTION_TEST_WALLET_PASSWORD,
777
                useCashAddress: useCashAddress
778
            }, function(err, _wallet) {
779
                assert.ifError(err);
780
                assert.ok(_wallet);
781
                assert.ok(!_wallet.isSegwit());
782
                assert.equal(_wallet.chain, blocktrail.Wallet.CHAIN_BCC_DEFAULT);
783
                wallet = _wallet;
784
785
                assert.equal(useCashAddress, _wallet.useNewCashAddr);
786
                assert.equal(wallet.primaryMnemonic, "give pause forget seed dance crawl situate hole keen");
787
                assert.equal(wallet.identifier, "unittest-transaction");
788
                assert.equal(wallet.getBlocktrailPublicKey("M/9999'").toBase58(), "tpubD9q6vq9zdP3gbhpjs7n2TRvT7h4PeBhxg1Kv9jEc1XAss7429VenxvQTsJaZhzTk54gnsHRpgeeNMbm1QTag4Wf1QpQ3gy221GDuUCxgfeZ");
789
                cb();
790
            });
791
        });
792
793
        it("derives the right address (" + description + ")", function(cb) {
794
            wallet.getNewAddress(function(err, serverAddress, path) {
795
                assert.ifError(err);
796
                assert.ok(serverAddress);
797
                assert.ok(path);
798
799
                var decoded = wallet.decodeAddress(serverAddress);
800
                assert.ok(decoded);
801
                assert.equal(serverAddress, decoded.address);
802
                assert.equal(expectType, decoded.type);
803
804
                address = serverAddress;
805
                cb();
806
            });
807
        });
808
809
        it("can coin select address (" + expectType + ")", function(cb) {
810
            var pay = {};
811
            pay[address] = 12345;
812
            wallet.coinSelection(pay, function(err, utxos) {
813
                assert.ifError(err);
814
                assert.ok(utxos);
815
                assert.ok(utxos.length > 0);
816
817
                cb();
818
            });
819
        });
820
    });
821
});
822
823
describe('test wallet, do transaction', function() {
824
    var wallet;
825
826
    it("should exists", function(cb) {
827
        client.initWallet({
828
            identifier: "unittest-transaction",
829
            passphrase: TRANSACTION_TEST_WALLET_PASSWORD
830
        }, function(err, _wallet) {
831
            assert.ifError(err);
832
            assert.ok(_wallet);
833
            assert.ok(!_wallet.isSegwit());
834
            assert.equal(blocktrail.Wallet.CHAIN_BTC_DEFAULT, _wallet.chain);
835
            wallet = _wallet;
836
837
            assert.equal(wallet.primaryMnemonic, "give pause forget seed dance crawl situate hole keen");
838
            assert.equal(wallet.identifier, "unittest-transaction");
839
            assert.equal(wallet.getBlocktrailPublicKey("M/9999'").toBase58(), "tpubD9q6vq9zdP3gbhpjs7n2TRvT7h4PeBhxg1Kv9jEc1XAss7429VenxvQTsJaZhzTk54gnsHRpgeeNMbm1QTag4Wf1QpQ3gy221GDuUCxgfeZ");
840
            cb();
841
        });
842
    });
843
844
    it("should have the expected addresses", function(cb) {
845
        assert.equal(wallet.getAddressByPath("M/9999'/0/1"), "2N65RcfKHiKQcPGZAA2QVeqitJvAQ8HroHD");
846
        assert.equal(wallet.getAddressByPath("M/9999'/0/6"), "2MynrezSyqCq1x5dMPtRDupTPA4sfVrNBKq");
847
        assert.equal(wallet.getAddressByPath("M/9999'/0/44"), "2N5eqrZE7LcfRyCWqpeh1T1YpMdgrq8HWzh");
848
849
        cb();
850
    });
851
852
    it("should have a balance", function(cb) {
853
        this.timeout(0);
854
855
        wallet.getBalance(function(err, confirmed, unconfirmed) {
856
            assert.ok(confirmed + unconfirmed > 0);
857
            assert.ok(confirmed > 0);
858
859
            cb();
860
        });
861
    });
862
863
    it("should return errors when expected", function(cb) {
864
        async.parallel([
865
            function(cb) {
866
                wallet.pay({"": blocktrail.toSatoshi(0.001)}, function(err) {
867
                    assert.ok(!!err);
868
                    assert.equal(err.message, "Invalid address [] (Invalid checksum)");
869
                    assert.ok(err instanceof blocktrail.InvalidAddressError);
870
871
                    cb();
872
                });
873
            },
874
            function(cb) {
875
                wallet.pay({"2N65RcfKHiKQcPGZAA2QVeqitJvAQ8HroHA": blocktrail.toSatoshi(0.001)}, function(err) {
876
                    assert.ok(!!err);
877
                    assert.equal(err.message, "Invalid address [2N65RcfKHiKQcPGZAA2QVeqitJvAQ8HroHA] (Invalid checksum)");
878
                    assert.ok(err instanceof blocktrail.InvalidAddressError);
879
880
                    cb();
881
                });
882
            },
883
            function(cb) {
884
                wallet.pay({"2N65RcfKHiKQcPGZAA2QVeqitJvAQ8HroHD": 1}, function(err) {
885
                    assert.ok(!!err);
886
                    assert.equal(err.message, "Values should be more than dust (" + blocktrail.DUST + ")");
887
                    assert.ok(err instanceof blocktrail.WalletSendError);
888
889
                    cb();
890
                });
891
            },
892
            function(cb) {
893
                wallet.pay({"2N65RcfKHiKQcPGZAA2QVeqitJvAQ8HroHD": 0}, function(err) {
894
                    assert.ok(!!err);
895
                    assert.equal(err.message, "Values should be non zero");
896
                    assert.ok(err instanceof blocktrail.WalletSendError);
897
898
                    cb();
899
                });
900
            },
901
            function(cb) {
902
                wallet.pay({"2N65RcfKHiKQcPGZAA2QVeqitJvAQ8HroHD": 1.1}, function(err) {
903
                    assert.ok(!!err);
904
                    assert.equal(err.message, "Values should be in Satoshis");
905
                    assert.ok(err instanceof blocktrail.WalletSendError);
906
907
                    cb();
908
                });
909
            }
910
        ], cb);
911
    });
912
913
    it("should be able to build a transaction paying a bech32 address", function(cb) {
914
        var address = "tb1qn08f8x0eamw66enrt497zu0v3u2danzey6asqs";
915
        var wp = "00149bce9399f9eeddad66635d4be171ec8f14decc59";
916
        var pay = {};
917
        pay[address] = blocktrail.toSatoshi(0.001);
918
919
        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...
920
            assert.ifError(err);
921
            assert.ok(tx);
922
            assert.ok(tx.toHex());
923
            assert.equal(wp, tx.outs[0].script.toString('hex'));
924
            cb();
925
        });
926
    });
927
928
    it("change should be randomized when building a transaction", function(cb) {
929
        wallet.getNewAddress(function(err, address, path) {
930
            assert.ifError(err);
931
            assert.ok(path.indexOf("M/9999'/0/") === 0);
932
            assert.ok(bitcoin.address.fromBase58Check(address));
933
934
            var pay = {};
935
            pay[address] = blocktrail.toSatoshi(0.001);
936
937
            var changeIdxs = [];
938
            var tryX = 10;
939
940
            async.whilst(
941
                function() { return tryX-- > 0 && _.uniq(changeIdxs).length < 2; },
942
                function(cb) {
943
                    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...
944
                        assert.ifError(err);
945
946
                        tx.outs.forEach(function(output, idx) {
947
                            var addr = bitcoin.address.fromOutputScript(output.script, client.testnet ? bitcoin.networks.testnet : bitcoin.networks.bitcoin);
948
949
                            if (addr !== address) {
950
                                changeIdxs.push(idx);
951
                            }
952
                        });
953
954
                        cb();
955
                    });
956
                },
957
                function() {
958
                    assert(_.uniq(changeIdxs).length > 1);
959
960
                    cb();
961
                }
962
            );
963
        });
964
965
        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...
966
            wallet.getNewAddress(function(err, address, path) {
967
                assert.ifError(err);
968
                assert.ok(path.indexOf("M/9999'/0/") === 0);
969
                assert.ok(bitcoin.address.fromBase58Check(address));
970
971
                var pay = {};
972
                pay[address] = blocktrail.toSatoshi(0.001);
973
974
                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...
975
                    assert.ifError(err);
976
                    assert.ok(tx);
977
                    assert.ok(tx.toHex());
978
                });
979
            });
980
        });
981
    });
982
983
    it("should be able to do a payment", function(cb) {
984
        wallet.getNewAddress(function(err, address, path) {
985
            assert.ifError(err);
986
            assert.ok(path.indexOf("M/9999'/", wallet.chain, "/") === 0);
987
            assert.ok(bitcoin.address.fromBase58Check(address));
988
989
            var pay = {};
990
            pay[address] = blocktrail.toSatoshi(0.001);
991
992
            var progress = [];
993
994
            wallet.pay(pay, function(err, txHash) {
995
                assert.ifError(err);
996
                assert.ok(txHash);
997
998
                // change address doesn't always happen ...
999
                if (progress.indexOf(blocktrail.Wallet.PAY_PROGRESS_CHANGE_ADDRESS) === -1) {
1000
                    progress.splice(2, 0, blocktrail.Wallet.PAY_PROGRESS_CHANGE_ADDRESS);
1001
                }
1002
1003
                assert.deepEqual(progress, [
1004
                    blocktrail.Wallet.PAY_PROGRESS_START,
1005
                    blocktrail.Wallet.PAY_PROGRESS_COIN_SELECTION,
1006
                    blocktrail.Wallet.PAY_PROGRESS_CHANGE_ADDRESS,
1007
                    blocktrail.Wallet.PAY_PROGRESS_SIGN,
1008
                    blocktrail.Wallet.PAY_PROGRESS_SEND,
1009
                    blocktrail.Wallet.PAY_PROGRESS_DONE
1010
                ]);
1011
1012
                // 200ms timeout, for w/e this is neccesary now ... @TODO: figure out why ...
1013
                setTimeout(function() {
1014
                    client.transaction(txHash, function(err, tx) {
1015
                        assert.ifError(err);
1016
                        assert.ok(tx);
1017
1018
                        cb();
1019
                    });
1020
                }, WAIT_FOR_TX_PROCESSED);
1021
            }).progress(function(_progress) {
1022
                progress.push(_progress);
1023
            });
1024
        });
1025
    });
1026
});
1027
1028
describe('test wallet with segwit chain', function() {
1029
    var wallet;
1030
1031
    it("should exist and be setup", function(cb) {
1032
        client.initWallet({
1033
            identifier: "unittest-transaction-sw",
1034
            passphrase: TRANSACTION_TEST_WALLET_PASSWORD
1035
        }, function(err, _wallet) {
1036
            assert.ifError(err);
1037
            assert.ok(_wallet);
1038
            assert.equal(_wallet.primaryMnemonic, "give pause forget seed dance crawl situate hole keen");
1039
            assert.equal(_wallet.identifier, "unittest-transaction-sw");
1040
            assert.equal(_wallet.getBlocktrailPublicKey("M/9999'").toBase58(), "tpubD9q6vq9zdP3gbhpjs7n2TRvT7h4PeBhxg1Kv9jEc1XAss7429VenxvQTsJaZhzTk54gnsHRpgeeNMbm1QTag4Wf1QpQ3gy221GDuUCxgfeZ");
1041
            assert.ok(_wallet.isSegwit());
1042
            assert.equal(blocktrail.Wallet.CHAIN_BTC_DEFAULT, _wallet.chain);
1043
            assert.equal(blocktrail.Wallet.CHAIN_BTC_SEGWIT, _wallet.changeChain);
1044
1045
            wallet = _wallet;
1046
            cb();
1047
        });
1048
    });
1049
1050
    it("getNewAddress produces plain P2SH addresses", function(cb) {
1051
        wallet.getNewAddress(function(err, address, path) {
1052
            assert.ifError(err);
1053
            assert.ok(path.indexOf("M/9999'/0/") === 0);
1054
1055
            assert.ok(bitcoin.address.fromBase58Check(address));
1056
1057
            cb();
1058
        });
1059
    });
1060
1061
    it("getNewAddress produces segwit P2SH addresses for change chain", function(cb) {
1062
        wallet.getNewAddress(wallet.changeChain, function(err, address, path) {
1063
            assert.ifError(err);
1064
            assert.ok(path.indexOf("M/9999'/2/") === 0);
1065
1066
            assert.ok(bitcoin.address.fromBase58Check(address));
1067
1068
            cb();
1069
        });
1070
    });
1071
1072
    it("getWalletScriptByPath produces P2SH addresses, and returns witnessScript", function(cb) {
1073
        var eAddress = "2N3j4Vx3D9LPumjtRbRe2RJpwVocvCCkHKh";
1074
1075
        assert.equal(wallet.getAddressByPath("M/9999'/2/0"), eAddress);
1076
1077
        var walletScript = wallet.getWalletScriptByPath("M/9999'/2/0");
1078
        assert.equal(walletScript.address, eAddress);
1079
        assert.ok(walletScript.witnessScript);
1080
        assert.ok(walletScript.redeemScript);
1081
        cb();
1082
    });
1083
});
1084
1085
describe('test wallet, do transaction, segwit spend', function() {
1086
    var wallets = [];
1087
    after(function(cb) {
1088
        if (wallets.length > 0) {
1089
            wallets.map(function(wallet) {
1090
                wallet.deleteWallet(true);
1091
            });
1092
        }
1093
        cb();
1094
    });
1095
1096
    var unitTestWallet;
1097
    var identifier = crypto.randomBytes(12).toString('hex');
1098
    var segwitWallet;
1099
    var receiveAddr;
1100
    var receiveBackAddr;
1101
    it("should setup the funding wallet", function(cb) {
1102
        client.initWallet({
1103
            identifier: "unittest-transaction",
1104
            passphrase: TRANSACTION_TEST_WALLET_PASSWORD
1105
        }, function(err, _wallet) {
1106
            assert.ifError(err);
1107
            assert.ok(_wallet);
1108
1109
            _wallet.getNewAddress(function(err, address, path) {
1110
                assert.ifError(err);
1111
                assert.ok(address);
1112
                assert.ok(path);
1113
1114
                unitTestWallet = _wallet;
1115
                receiveBackAddr = address;
1116
                cb();
1117
            });
1118
        });
1119
    });
1120
1121
    it("should make the receiving segwit wallet", function(cb) {
1122
        createTransactionTestWallet(identifier, true, function(err, newWallet) {
1123
            wallets.push(newWallet);
1124
            assert.ifError(err);
1125
            newWallet.getNewAddress(newWallet.changeChain, function(err, address, path) {
1126
                assert.ifError(err);
1127
                assert.ok(bitcoin.address.fromBase58Check(address));
1128
                assert.ok(newWallet.isSegwit());
1129
                assert.ok(path.indexOf("M/9999'/2/") === 0);
1130
1131
                var checkScript = newWallet.getWalletScriptByPath(path);
1132
                assert.ok(checkScript.address = address);
1133
                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...
1134
                assert.ok(checkScript.witnessScript instanceof Buffer);
1135
1136
                segwitWallet = newWallet;
1137
                receiveAddr = address;
1138
                cb();
1139
            });
1140
        });
1141
    });
1142
1143
    var paymentHash;
1144
    it("should receive funds from unitTestWallet", function(cb) {
1145
        var pay = {};
1146
        pay[receiveAddr] = 30000;
1147
        unitTestWallet.pay(pay, null, true, function(err, txid) {
1148
            assert.ifError(err);
1149
            assert.ok(txid);
1150
            paymentHash = txid;
0 ignored issues
show
Unused Code introduced by
The variable paymentHash seems to be never used. Consider removing it.
Loading history...
1151
            cb();
1152
        });
1153
    });
1154
1155
    it("should return to unitTestWallet", function(cb) {
1156
        var pay = {};
1157
        pay[receiveBackAddr] = 20000;
1158
        segwitWallet.pay(pay, null, true, function(err, txid) {
1159
            assert.ifError(err);
1160
            assert.ok(txid);
1161
1162
            setTimeout(function() {
1163
                client.transaction(txid, function(err, tx) {
1164
                    assert.ifError(err);
1165
                    assert.ok(tx);
1166
                    cb();
1167
                });
1168
            }, WAIT_FOR_TX_PROCESSED);
1169
        });
1170
    });
1171
});
1172
1173
describe('test wallet, do transaction, without mnemonics', function() {
1174
    var wallet;
1175
1176
    var primarySeed = bip39.mnemonicToSeed(TRANSACTION_TEST_WALLET_PRIMARY_MNEMONIC, TRANSACTION_TEST_WALLET_PASSWORD);
1177
1178
    it("should exists", function(cb) {
1179
        client.initWallet({
1180
                identifier: "unittest-transaction",
1181
                primarySeed: primarySeed,
1182
                primaryMnemonic: false // explicitly set false because we're reusing unittest-transaction which has a mnemonic stored
1183
            }, function(err, _wallet) {
1184
                assert.ifError(err);
1185
                assert.ok(_wallet);
1186
1187
                wallet = _wallet;
1188
1189
                assert.equal(wallet.identifier, "unittest-transaction");
1190
                assert.equal(wallet.getBlocktrailPublicKey("M/9999'").toBase58(), "tpubD9q6vq9zdP3gbhpjs7n2TRvT7h4PeBhxg1Kv9jEc1XAss7429VenxvQTsJaZhzTk54gnsHRpgeeNMbm1QTag4Wf1QpQ3gy221GDuUCxgfeZ");
1191
                cb();
1192
            }
1193
        );
1194
    });
1195
1196
    it("should have the expected addresses", function(cb) {
1197
        assert.equal(wallet.getAddressByPath("M/9999'/0/1"), "2N65RcfKHiKQcPGZAA2QVeqitJvAQ8HroHD");
1198
        assert.equal(wallet.getAddressByPath("M/9999'/0/6"), "2MynrezSyqCq1x5dMPtRDupTPA4sfVrNBKq");
1199
        assert.equal(wallet.getAddressByPath("M/9999'/0/44"), "2N5eqrZE7LcfRyCWqpeh1T1YpMdgrq8HWzh");
1200
1201
        cb();
1202
    });
1203
1204
    it("should have a balance", function(cb) {
1205
        this.timeout(0);
1206
1207
        wallet.getBalance(function(err, confirmed, unconfirmed) {
1208
            assert.ok(confirmed + unconfirmed > 0);
1209
            assert.ok(confirmed > 0);
1210
1211
            cb();
1212
        });
1213
    });
1214
1215
    it("should be able to do a payment", function(cb) {
1216
        wallet.getNewAddress(function(err, address, path) {
1217
            assert.ifError(err);
1218
            assert.ok(path.indexOf("M/9999'/0/") === 0);
1219
            assert.ok(bitcoin.address.fromBase58Check(address));
1220
1221
            var pay = {};
1222
            pay[address] = blocktrail.toSatoshi(0.001);
1223
1224
            wallet.pay(pay, function(err, txHash) {
1225
                assert.ifError(err);
1226
                assert.ok(txHash);
1227
1228
                // 200ms timeout, for w/e this is neccesary now ... @TODO: figure out why ...
1229
                setTimeout(function() {
1230
                    client.transaction(txHash, function(err, tx) {
1231
                        assert.ifError(err);
1232
                        assert.ok(tx);
1233
1234
                        cb();
1235
                    });
1236
                }, WAIT_FOR_TX_PROCESSED);
1237
            });
1238
        });
1239
    });
1240
});
1241
1242
describe('test wallet, do opreturn transaction', function() {
1243
    var wallet;
1244
1245
    it("should exists", function(cb) {
1246
        client.initWallet({
1247
            identifier: "unittest-transaction",
1248
            passphrase: TRANSACTION_TEST_WALLET_PASSWORD
1249
        }, function(err, _wallet) {
1250
            assert.ifError(err);
1251
            assert.ok(_wallet);
1252
1253
            wallet = _wallet;
1254
1255
            assert.equal(wallet.primaryMnemonic, "give pause forget seed dance crawl situate hole keen");
1256
            assert.equal(wallet.identifier, "unittest-transaction");
1257
            assert.equal(wallet.getBlocktrailPublicKey("M/9999'").toBase58(), "tpubD9q6vq9zdP3gbhpjs7n2TRvT7h4PeBhxg1Kv9jEc1XAss7429VenxvQTsJaZhzTk54gnsHRpgeeNMbm1QTag4Wf1QpQ3gy221GDuUCxgfeZ");
1258
            cb();
1259
        });
1260
    });
1261
1262
    it("should be able to do a payment with opreturn output", function(cb) {
1263
        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...
1264
            assert.ifError(err);
1265
1266
            var pay = {};
1267
            pay[address] = blocktrail.toSatoshi(0.001);
1268
            pay[blocktrail.Wallet.OP_RETURN] = "BLOCKTRAILTESTDATA";
1269
1270
            wallet.pay(pay, function(err, txHash) {
1271
                assert.ifError(err);
1272
                assert.ok(txHash);
1273
1274
1275
                // 200ms timeout, for w/e this is neccesary now ... @TODO: figure out why ...
1276
                setTimeout(function() {
1277
                    client.transaction(txHash, function(err, tx) {
1278
                        assert.ifError(err);
1279
                        assert.ok(tx);
1280
1281
                        var hasOpreturn;
1282
                        tx.outputs.forEach(function(output) {
1283
                            if (output.type === 'op_return') {
1284
                                hasOpreturn = true;
1285
1286
                                assert.equal(output.script_hex, "6a12424c4f434b545241494c5445535444415441");
1287
                            }
1288
                        });
1289
                        assert.ok(hasOpreturn);
1290
1291
                        cb();
1292
                    });
1293
                }, WAIT_FOR_TX_PROCESSED);
1294
            });
1295
        });
1296
    });
1297
});
1298
1299
describe('test wallet, do forcefee transaction', function() {
1300
    var wallet;
1301
1302
    it("should exists", function(cb) {
1303
        client.initWallet({
1304
            identifier: "unittest-transaction",
1305
            passphrase: TRANSACTION_TEST_WALLET_PASSWORD
1306
        }, function(err, _wallet) {
1307
            assert.ifError(err);
1308
            assert.ok(_wallet);
1309
1310
            wallet = _wallet;
1311
1312
            assert.equal(wallet.primaryMnemonic, "give pause forget seed dance crawl situate hole keen");
1313
            assert.equal(wallet.identifier, "unittest-transaction");
1314
            assert.equal(wallet.getBlocktrailPublicKey("M/9999'").toBase58(), "tpubD9q6vq9zdP3gbhpjs7n2TRvT7h4PeBhxg1Kv9jEc1XAss7429VenxvQTsJaZhzTk54gnsHRpgeeNMbm1QTag4Wf1QpQ3gy221GDuUCxgfeZ");
1315
            cb();
1316
        });
1317
    });
1318
1319
    it("should be able to do a payment with forced fee", function(cb) {
1320
        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...
1321
            assert.ifError(err);
1322
1323
            var pay = {};
1324
            pay[address] = blocktrail.toSatoshi(0.01);
1325
            var forceFee = blocktrail.toSatoshi(0.00054321);
1326
1327
            wallet.pay(pay, null, false, true, blocktrail.Wallet.FEE_STRATEGY_FORCE_FEE, null, {
1328
                forcefee: forceFee,
1329
                checkFee: false
1330
            }, function(err, txHash) {
1331
                assert.ifError(err);
1332
                assert.ok(txHash);
1333
1334
                // 200ms timeout, for w/e this is neccesary now ... @TODO: figure out why ...
1335
                setTimeout(function() {
1336
                    client.transaction(txHash, function(err, tx) {
1337
                        assert.ifError(err);
1338
                        // this could very occasionally fail if change < DUST because then it's added to fee, so adjusted check for that
1339
                        assert.ok(tx['total_fee'] >= forceFee && tx['total_fee'] <= forceFee + blocktrail.DUST,
1340
                            "fee [" + tx['total_fee'] + "] should be equal to forced fee [" +  forceFee + "] for tx [" + txHash + "]");
1341
1342
                        cb();
1343
                    });
1344
                }, WAIT_FOR_TX_PROCESSED);
1345
            });
1346
        });
1347
    });
1348
});
1349
1350
describe('test wallet upgrade key index', function() {
1351
    var myIdentifier = "nodejs-sdk-" + crypto.randomBytes(24).toString('hex');
1352
    var wallet;
1353
1354
    after(function(cb) {
1355
        if (wallet) {
1356
            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...
1357
                cb();
1358
            });
1359
        } else {
1360
            cb();
1361
        }
1362
    });
1363
1364
    it("should be created", function(cb) {
1365
        createUpgradeKeyIndexTestWallet(myIdentifier, "password", function(err, _wallet) {
1366
            assert.ifError(err);
1367
            assert.ok(_wallet);
1368
            _wallet.chain = blocktrail.Wallet.CHAIN_BTC_DEFAULT;
1369
            wallet = _wallet;
1370
1371
            assert.equal(wallet.primaryMnemonic, "give pause forget seed dance crawl situate hole kingdom");
1372
            assert.equal(wallet.identifier, myIdentifier);
1373
            assert.equal(wallet.getBlocktrailPublicKey("M/9999'").toBase58(), "tpubD9q6vq9zdP3gbhpjs7n2TRvT7h4PeBhxg1Kv9jEc1XAss7429VenxvQTsJaZhzTk54gnsHRpgeeNMbm1QTag4Wf1QpQ3gy221GDuUCxgfeZ");
1374
1375
            cb();
1376
        });
1377
    });
1378
1379
    it("should have the expected addresses", function(cb) {
1380
        async.series([
1381
            function(cb) {
1382
                wallet.getNewAddress(function(err, address, path) {
1383
                    assert.ifError(err);
1384
                    assert.equal(path, "M/9999'/0/0");
1385
                    assert.equal(address, "2Mtfn5S9tVWnnHsBQixCLTsCAPFHvfhu6bM");
1386
1387
                    cb();
1388
                });
1389
            },
1390
            function(cb) {
1391
                wallet.getNewAddress(function(err, address, path) {
1392
                    assert.ifError(err);
1393
                    assert.equal(path, "M/9999'/0/1");
1394
                    assert.equal(address, "2NG49GDkm5qCYvDFi4cxAnkSho8qLbEz6C4");
1395
1396
                    cb();
1397
                });
1398
            },
1399
            function(cb) {
1400
                assert.equal(wallet.getAddressByPath("M/9999'/0/1"), "2NG49GDkm5qCYvDFi4cxAnkSho8qLbEz6C4");
1401
                assert.equal(wallet.getAddressByPath("M/9999'/0/6"), "2N1kM5xeDaCN9Weog3mbyxjpryNZcirnkB7");
1402
1403
                cb();
1404
            }
1405
        ], cb);
1406
    });
1407
1408
    it("should be upgraded and have expected addresses", function(cb) {
1409
        // set upgrade
1410
        wallet.upgradeToKeyIndex = 10000;
1411
        // lock
1412
        wallet.lock();
1413
        // unlock should upgrade
1414
        wallet.unlock({
1415
            passphrase: "password"
1416
        }).then(function() {
1417
            assert.equal(wallet.getBlocktrailPublicKey("M/10000'").toBase58(), "tpubD9m9hziKhYQExWgzMUNXdYMNUtourv96sjTUS9jJKdo3EDJAnCBJooMPm6vGSmkNTNAmVt988dzNfNY12YYzk9E6PkA7JbxYeZBFy4XAaCp");
1418
1419
            assert.equal(wallet.getAddressByPath("M/10000'/0/0"), "2N9ZLKXgs12JQKXvLkngn7u9tsYaQ5kXJmk");
1420
1421
            wallet.getNewAddress(function(err, address, path) {
1422
                assert.ifError(err);
1423
                assert.equal(path, "M/10000'/0/0");
1424
                assert.equal(address, "2N9ZLKXgs12JQKXvLkngn7u9tsYaQ5kXJmk");
1425
1426
                cb();
1427
            });
1428
        });
1429
    });
1430
});
1431
1432
describe('test wallet with bad password', function() {
1433
    var myIdentifier = "nodejs-sdk-" + crypto.randomBytes(24).toString('hex');
1434
    var wallet;
1435
1436
    after(function(cb) {
1437
        if (wallet) {
1438
            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...
1439
                cb();
1440
            });
1441
        } else {
1442
            cb();
1443
        }
1444
    });
1445
1446
    it("should be created", function(cb) {
1447
        createUpgradeKeyIndexTestWallet(myIdentifier, "badpassword", function(err, _wallet) {
1448
            assert.ifError(err);
1449
            assert.ok(_wallet);
1450
1451
            _wallet.chain = blocktrail.Wallet.CHAIN_BTC_DEFAULT;
1452
            wallet = _wallet;
1453
1454
            assert.equal(wallet.primaryMnemonic, "give pause forget seed dance crawl situate hole kingdom");
1455
            assert.equal(wallet.identifier, myIdentifier);
1456
            assert.equal(wallet.getBlocktrailPublicKey("M/9999'").toBase58(), "tpubD9q6vq9zdP3gbhpjs7n2TRvT7h4PeBhxg1Kv9jEc1XAss7429VenxvQTsJaZhzTk54gnsHRpgeeNMbm1QTag4Wf1QpQ3gy221GDuUCxgfeZ");
1457
1458
            cb();
1459
        });
1460
    });
1461
1462
    it("should have the expected addresses (different from with the correct password)", function(cb) {
1463
        async.series([
1464
            function(cb) {
1465
                wallet.getNewAddress(function(err, address, path) {
1466
                    assert.ifError(err);
1467
                    assert.equal(path, "M/9999'/0/0");
1468
                    assert.equal(address, "2N9SGrV4NKRjdACYvHLPpy2oiPrxTPd44rg");
1469
1470
                    cb();
1471
                });
1472
            },
1473
            function(cb) {
1474
                wallet.getNewAddress(function(err, address, path) {
1475
                    assert.ifError(err);
1476
                    assert.equal(path, "M/9999'/0/1");
1477
                    assert.equal(address, "2NDq3DRy9E3YgHDA3haPJj3FtUS6V93avkf");
1478
1479
                    cb();
1480
                });
1481
            }
1482
        ], cb);
1483
    });
1484
});
1485
1486
describe('test wallet webhook', function() {
1487
    // this.timeout(0); // disable, can take long
1488
1489
    var myIdentifier = "nodejs-sdk-" + crypto.randomBytes(24).toString('hex');
1490
    var wallet;
1491
1492
    after(function(cb) {
1493
        if (wallet) {
1494
            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...
1495
                cb();
1496
            });
1497
        } else {
1498
            cb();
1499
        }
1500
    });
1501
1502
    it("shouldn't already exist", function(cb) {
1503
        client.initWallet({
1504
            identifier: myIdentifier,
1505
            passphrase: "password"
1506
        }, function(err, wallet) {
1507
            assert.ok(err);
1508
            assert.ok(!wallet, "wallet with random ID [" + myIdentifier + "] already exists...");
1509
1510
            cb();
1511
        });
1512
    });
1513
1514
    it("should be created", function(cb) {
1515
        client.createNewWallet({
1516
            identifier: myIdentifier,
1517
            passphrase: "password",
1518
            keyIndex: 9999
1519
        }, function(err, _wallet) {
1520
            assert.ifError(err);
1521
            assert.ok(_wallet);
1522
1523
            wallet = _wallet;
1524
1525
            assert.equal(wallet.identifier, myIdentifier);
1526
            assert.equal(wallet.getBlocktrailPublicKey("M/9999'").toBase58(), "tpubD9q6vq9zdP3gbhpjs7n2TRvT7h4PeBhxg1Kv9jEc1XAss7429VenxvQTsJaZhzTk54gnsHRpgeeNMbm1QTag4Wf1QpQ3gy221GDuUCxgfeZ");
1527
            cb();
1528
        });
1529
    });
1530
1531
    it("should have a 0 balance", function(cb) {
1532
        wallet.getBalance(function(err, confirmed, unconfirmed) {
1533
            assert.ifError(err);
1534
            assert.equal(confirmed, 0);
1535
            assert.equal(unconfirmed, 0);
1536
1537
            cb();
1538
        });
1539
    });
1540
1541
    it("should be able to create a webhook", function(cb) {
1542
        wallet.setupWebhook("https://www.blocktrail.com/webhook-test", function(err, webhook) {
1543
            assert.ifError(err);
1544
            assert.equal(webhook['url'], "https://www.blocktrail.com/webhook-test");
1545
            assert.equal(webhook['identifier'], "WALLET-" + myIdentifier);
1546
1547
            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...
1548
                assert.ifError(err);
1549
1550
                cb();
1551
            });
1552
        });
1553
    });
1554
1555
    it("should be able to create a webhook with custom identifier", function(cb) {
1556
        var myWebhookIdentifier = "nodejs-sdk-" + crypto.randomBytes(24).toString('hex');
1557
1558
        wallet.setupWebhook("https://www.blocktrail.com/webhook-test", myWebhookIdentifier, function(err, webhook) {
1559
            assert.ifError(err);
1560
            assert.equal(webhook['url'], "https://www.blocktrail.com/webhook-test");
1561
            assert.equal(webhook['identifier'], myWebhookIdentifier);
1562
1563
            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...
1564
                assert.ifError(err);
1565
1566
                wallet.getNewAddress(function(err, address1) {
1567
                    assert.ifError(err);
1568
1569
                    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...
1570
                        assert.ifError(err);
1571
1572
                        var myWebhookIdentifier = "nodejs-sdk-" + crypto.randomBytes(24).toString('hex');
1573
1574
                        wallet.setupWebhook("https://www.blocktrail.com/webhook-test", myWebhookIdentifier, function(err, webhook) {
1575
                            assert.ifError(err);
1576
                            assert.equal(webhook['url'], "https://www.blocktrail.com/webhook-test");
1577
                            assert.equal(webhook['identifier'], myWebhookIdentifier);
1578
1579
                            client.getWebhookEvents(myWebhookIdentifier, function(err, result) {
1580
                                assert.ifError(err);
1581
                                assert.ok(_.includes(_.map(result['data'], 'address'), address1));
1582
1583
                                wallet.getNewAddress(function(err, address2) {
1584
                                    assert.ifError(err);
1585
1586
                                    client.getWebhookEvents(myWebhookIdentifier, function(err, result) {
1587
                                        assert.ifError(err);
1588
                                        assert.ok(_.includes(_.map(result['data'], 'address'), address2));
1589
1590
                                        wallet.deleteWallet(function(err, result) {
1591
                                            assert.ifError(err);
1592
                                            assert.ok(result);
1593
1594
                                            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...
1595
                                                assert.ok(err);
1596
1597
                                                cb();
1598
                                            });
1599
                                        });
1600
                                    });
1601
                                });
1602
                            });
1603
                        });
1604
                    });
1605
1606
                });
1607
            });
1608
        });
1609
    });
1610
});
1611
1612
describe("Wallet.getAddressAndType", function() {
1613
    var fixtures = [
1614
        {
1615
            address: "tb1qn08f8x0eamw66enrt497zu0v3u2danzey6asqs",
1616
            network: bitcoin.networks.testnet,
1617
            type: "bech32",
1618
            valid: true
1619
        },
1620
        {
1621
            address: "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7",
1622
            network: bitcoin.networks.testnet,
1623
            type: "bech32",
1624
            valid: true
1625
        },
1626
        {
1627
            address: "muinVykhtZyonxQxk8zBptX6Lmri91bdNG",
1628
            network: bitcoin.networks.testnet,
1629
            type: "base58",
1630
            valid: true
1631
        },
1632
        {
1633
            address: "2N7T4CD6CEuNHJoGKpoJH3YexqektXjyy6L",
1634
            network: bitcoin.networks.testnet,
1635
            type: "base58",
1636
            valid: true
1637
        },
1638
        {
1639
            address: "16uf9UUBbUHdVAnETGZQnvXZcf9NPU1QR6",
1640
            network: bitcoin.networks.bitcoin,
1641
            type: "base58",
1642
            valid: true
1643
        },
1644
        {
1645
            address: "3CgSFohdEqd7pSxbDAJeJo6X5Qm2tBbby9",
1646
            network: bitcoin.networks.bitcoin,
1647
            type: "base58",
1648
            valid: true
1649
        },
1650
        {
1651
            address: "bc1qqy36hngpyw4u6qfr40xszgate5qj827dqy36hngpyw4u6qfr40xsp3an42",
1652
            network: bitcoin.networks.bitcoin,
1653
            type: "bech32",
1654
            valid: true
1655
        },
1656
        {
1657
            address: "bc1qn08f8x0eamw66enrt497zu0v3u2danzewuxrmr",
1658
            network: bitcoin.networks.bitcoin,
1659
            type: "bech32",
1660
            valid: true
1661
        },
1662
        {
1663
            address: "16uf9UUBbUHdVAnETGZQnvXZcf9NPU1QR6",
1664
            network: bitcoin.networks.testnet,
1665
            type: "base58",
1666
            error: "Address invalid on this network",
1667
            valid: false
1668
        },
1669
        {
1670
            address: "3CgSFohdEqd7pSxbDAJeJo6X5Qm2tBbby9",
1671
            network: bitcoin.networks.testnet,
1672
            type: "base58",
1673
            error: "Address invalid on this network",
1674
            valid: false
1675
        },
1676
        {
1677
            address: "bc1qqy36hngpyw4u6qfr40xszgate5qj827dqy36hngpyw4u6qfr40xsp3an42",
1678
            network: bitcoin.networks.testnet,
1679
            type: "bech32",
1680
            error: "Address invalid on this network",
1681
            valid: false
1682
        },
1683
        {
1684
            address: "bc1qn08f8x0eamw66enrt497zu0v3u2danzewuxrmr",
1685
            network: bitcoin.networks.testnet,
1686
            type: "bech32",
1687
            error: "Address invalid on this network",
1688
            valid: false
1689
        },
1690
        {
1691
            address: "bc1qqy36hngpyw4u6qfr40xszgate5qj827dqy36hngpyw4u6qfr40xsp3an42",
1692
            network: bitcoin.networks.bitcoincash,
1693
            error: "Non-base58 character",
1694
            type: "bech32",
1695
            valid: false
1696
        },
1697
        {
1698
            address: "bc1qn08f8x0eamw66enrt497zu0v3u2danzewuxrmr",
1699
            network: bitcoin.networks.bitcoincash,
1700
            error: "Non-base58 character",
1701
            type: "bech32",
1702
            valid: false
1703
        },
1704
        {
1705
            address: "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7",
1706
            network: bitcoin.networks.bitcoincashtestnet,
1707
            error: "Non-base58 character",
1708
            type: "bech32",
1709
            valid: false
1710
        },
1711
        {
1712
            address: "tb1qn08f8x0eamw66enrt497zu0v3u2danzey6asqs",
1713
            network: bitcoin.networks.bitcoincashtestnet,
1714
            error: "Non-base58 character",
1715
            type: "bech32",
1716
            valid: false
1717
        },
1718
        {
1719
            address: "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7",
1720
            network: bitcoin.networks.bitcoin,
1721
            error: "Address invalid on this network",
1722
            type: "bech32",
1723
            valid: false
1724
        },
1725
        {
1726
            address: "tb1qn08f8x0eamw66enrt497zu0v3u2danzey6asqs",
1727
            network: bitcoin.networks.bitcoin,
1728
            error: "Address invalid on this network",
1729
            type: "bech32",
1730
            valid: false
1731
        },
1732
        {
1733
            address: "bc1qqy36hngpyw4u6qfr40xszgate5qj827dqy36hngpyw4u6qfr40xsp3an42",
1734
            network: bitcoin.networks.testnet,
1735
            error: "Address invalid on this network",
1736
            type: "bech32",
1737
            valid: false
1738
        },
1739
        {
1740
            address: "bc1qn08f8x0eamw66enrt497zu0v3u2danzewuxrmr",
1741
            network: bitcoin.networks.testnet,
1742
            error: "Address invalid on this network",
1743
            type: "bech32",
1744
            valid: false
1745
        }
1746
    ];
1747
1748
    fixtures.map(function(fixture) {
1749
        var description =
1750
            (fixture.valid ? "parses" : "fails to parse") +
1751
            " a " + fixture.type + " address: " + fixture.address;
1752
1753
        it(description, function(cb) {
1754
            var addrAndType;
1755
            var err;
1756
            try {
1757
                addrAndType = Wallet.getAddressAndType(fixture.address, fixture.network);
1758
            } catch (e) {
1759
                err = e;
1760
            }
1761
1762
            if (fixture.valid) {
1763
                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...
1764
                assert.ok(Object.keys(addrAndType).indexOf("address") !== -1);
1765
                assert.ok(Object.keys(addrAndType).indexOf("decoded") !== -1);
1766
                assert.ok(Object.keys(addrAndType).indexOf("type") !== -1);
1767
                assert.equal(addrAndType.type, fixture.type);
1768
                assert.equal(addrAndType.address, fixture.address);
1769
            } else {
1770
                assert.ok(typeof err === "object");
1771
                assert.ok(typeof addrAndType === "undefined");
1772
                if (Object.keys(fixture).indexOf("error") !== -1) {
1773
                    assert.equal(err.message, fixture.error);
1774
                }
1775
            }
1776
            cb();
1777
        });
1778
    });
1779
});
1780
1781
describe("Wallet.convertPayToOutputs", function() {
1782
    var fixtures = [
1783
        {
1784
            description: "p2wpkh",
1785
            network: bitcoin.networks.testnet,
1786
            cashaddr: false,
1787
            value: 12345,
1788
            address: "tb1qn08f8x0eamw66enrt497zu0v3u2danzey6asqs",
1789
            script: "00149bce9399f9eeddad66635d4be171ec8f14decc59"
1790
        },
1791
        {
1792
            description: "p2wsh",
1793
            network: bitcoin.networks.testnet,
1794
            value: 12345,
1795
            cashaddr: false,
1796
            address: "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7",
1797
            script: "00201863143c14c5166804bd19203356da136c985678cd4d27a1b8c6329604903262"
1798
        },
1799
        {
1800
            description: "p2pkh",
1801
            network: bitcoin.networks.testnet,
1802
            value: 12345,
1803
            cashaddr: false,
1804
            address: "muinVykhtZyonxQxk8zBptX6Lmri91bdNG",
1805
            script: "76a9149bce9399f9eeddad66635d4be171ec8f14decc5988ac"
1806
        },
1807
        {
1808
            description: "p2sh",
1809
            network: bitcoin.networks.testnet,
1810
            value: 12345,
1811
            cashaddr: false,
1812
            address: "2N7T4CD6CEuNHJoGKpoJH3YexqektXjyy6L",
1813
            script: "a9149bce9399f9eeddad66635d4be171ec8f14decc5987"
1814
        },
1815
        {
1816
            description: "p2sh cashaddr",
1817
            network: bitcoin.networks.bitcoincash,
1818
            value: 12345,
1819
            cashaddr: true,
1820
            address: "bitcoincash:ppm2qsznhks23z7629mms6s4cwef74vcwvn0h829pq",
1821
            script: "a91476a04053bda0a88bda5177b86a15c3b29f55987387"
1822
        }
1823
    ];
1824
1825
    fixtures.map(function(fixture) {
1826
        var network = fixture.network;
1827
        var payScriptOutputs = [{
1828
            scriptPubKey: fixture.script,
1829
            value: fixture.value
1830
        }];
1831
        var payAddressOutputs = [{
1832
            address: fixture.address,
1833
            value: fixture.value
1834
        }];
1835
        var payKeyedObject = {};
1836
        payKeyedObject[fixture.address] = fixture.value;
1837
        var payFlatArray = [
1838
            [fixture.address, fixture.value]
1839
        ];
1840
        [
1841
            {
1842
                desc: "deals with script outputs",
1843
                pay: payScriptOutputs
1844
            },
1845
            {
1846
                desc: "deals with address outputs",
1847
                pay: payAddressOutputs
1848
            },
1849
            {
1850
                desc: "deals with object keyed by address",
1851
                pay: payKeyedObject
1852
            },
1853
            {
1854
                desc: "deals with a flat output array",
1855
                pay: payFlatArray
1856
            }
1857
        ].map(function(f) {
1858
            it(fixture.description + " converted to script, " + f.desc, function(cb) {
1859
                var test = function(outputs) {
1860
                    assert.ok(Array.isArray(outputs));
1861
                    assert.equal(outputs[0].value, fixture.value);
1862
                    assert.equal(outputs[0].scriptPubKey, fixture.script);
1863
                    assert.equal(outputs[0].address, null);
1864
                };
1865
1866
                // should accept some input of ours
1867
                var outputs = Wallet.convertPayToOutputs(f.pay, network, fixture.cashaddr);
1868
                test(outputs);
1869
1870
                // repeating the procedure should pass the same test
1871
                var outputs2 = Wallet.convertPayToOutputs(outputs, network, fixture.cashaddr);
1872
                test(outputs2);
1873
1874
                outputs.map(function(output, i) {
1875
                    assert.equal(outputs[i].scriptPubKey, outputs2[i].scriptPubKey);
1876
                    assert.equal(outputs[i].value, outputs2[i].value);
1877
                });
1878
1879
                cb();
1880
            });
1881
        });
1882
    });
1883
});
1884
1885
describe('test wallet coin selection forms', function() {
1886
    var wallet;
1887
1888
    it("BTC testnet wallet should exist", function(cb) {
1889
        client.initWallet({
1890
            identifier: "unittest-transaction",
1891
            passphrase: "password"
1892
        }, function(err, _wallet) {
1893
            assert.ifError(err);
1894
            assert.ok(_wallet);
1895
1896
            wallet = _wallet;
1897
1898
            client.allWallets({page: 1}, function(err, wallets) {
1899
                assert.ifError(err);
1900
1901
                assert.ok(wallets['data'].length > 0);
1902
1903
                assert.equal(wallet.primaryMnemonic, "give pause forget seed dance crawl situate hole keen");
1904
                assert.equal(wallet.identifier, "unittest-transaction");
1905
                assert.equal(wallet.getBlocktrailPublicKey("M/9999'").toBase58(), "tpubD9q6vq9zdP3gbhpjs7n2TRvT7h4PeBhxg1Kv9jEc1XAss7429VenxvQTsJaZhzTk54gnsHRpgeeNMbm1QTag4Wf1QpQ3gy221GDuUCxgfeZ");
1906
1907
                cb();
1908
            });
1909
        });
1910
    });
1911
1912
    it("shouldnt coin select for wrong network", function(cb) {
1913
        var pay = {};
1914
        pay["bc1qqy36hngpyw4u6qfr40xszgate5qj827dqy36hngpyw4u6qfr40xsp3an42"] = 10000;
1915
        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...
1916
            assert.ok(err);
1917
            cb();
1918
        });
1919
    });
1920
1921
    var fixtures = [
1922
        {"tb1qn08f8x0eamw66enrt497zu0v3u2danzey6asqs": 10000},
1923
        {"tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7": 10000},
1924
        [
1925
            {
1926
                "address": "tb1qn08f8x0eamw66enrt497zu0v3u2danzey6asqs",
1927
                "value": 10000
1928
            },
1929
            {
1930
                "address": "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7",
1931
                "value": 10000
1932
            }
1933
        ],
1934
        [
1935
            {
1936
                "scriptPubKey": "00149bce9399f9eeddad66635d4be171ec8f14decc59",
1937
                "value": 10000
1938
            },
1939
            {
1940
                "address": "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7",
1941
                "value": 10000
1942
            }
1943
        ]
1944
    ];
1945
1946
    fixtures.map(function(fixture) {
1947
        var type = "object";
1948
        if (Array.isArray(fixture)) {
1949
            type = "outputs array";
1950
        }
1951
        it("should coin select for " + type, function(cb) {
1952
            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...
1953
                assert.ifError(err);
1954
                cb();
1955
            });
1956
        });
1957
    });
1958
});
1959
1960
describe('test wallet list transactions and addresses', function() {
1961
    var wallet;
1962
1963
    it("should exists", function(cb) {
1964
        client.initWallet({
1965
            identifier: "unittest-transaction",
1966
            passphrase: "password"
1967
        }, function(err, _wallet) {
1968
            assert.ifError(err);
1969
            assert.ok(_wallet);
1970
1971
            wallet = _wallet;
1972
1973
            client.allWallets({page: 1}, function(err, wallets) {
1974
                assert.ifError(err);
1975
1976
                assert.ok(wallets['data'].length > 0);
1977
1978
                assert.equal(wallet.primaryMnemonic, "give pause forget seed dance crawl situate hole keen");
1979
                assert.equal(wallet.identifier, "unittest-transaction");
1980
                assert.equal(wallet.getBlocktrailPublicKey("M/9999'").toBase58(), "tpubD9q6vq9zdP3gbhpjs7n2TRvT7h4PeBhxg1Kv9jEc1XAss7429VenxvQTsJaZhzTk54gnsHRpgeeNMbm1QTag4Wf1QpQ3gy221GDuUCxgfeZ");
1981
1982
                cb();
1983
            });
1984
        });
1985
    });
1986
1987
    it("should list expected transactions", function(cb) {
1988
        wallet.transactions({page: 1, limit: 23}, function(err, transactions) {
1989
            assert.ifError(err);
1990
            assert.ok(transactions['data']);
1991
            assert.ok(transactions['total']);
1992
            assert.ok(transactions['data'].length === 23);
1993
            assert.ok(transactions['data'][0]['hash'], "2cb21783635a5f22e9934b8c3262146b42d251dfb14ee961d120936a6c40fe89");
1994
1995
            cb();
1996
        });
1997
    });
1998
1999
    it("should list expected addresses", function(cb) {
2000
        wallet.addresses({page: 1, limit: 23}, function(err, addresses) {
2001
            assert.ifError(err);
2002
            assert.ok(addresses['data']);
2003
            assert.ok(addresses['total']);
2004
            assert.ok(addresses['data'].length === 23);
2005
            assert.ok(addresses['data'][0]['address'], "2MzyKviSL6pnWxkbHV7ecFRE3hWKfzmT8WS");
2006
2007
            cb();
2008
        });
2009
    });
2010
2011
    it("should list UTXOs", function(cb) {
2012
        wallet.utxos({page: 0, limit: 23}, function(err, addresses) {
2013
            assert.ifError(err);
2014
            assert.ok(addresses['data']);
2015
            assert.ok(addresses['total']);
2016
            assert.ok(addresses['data'].length === 23);
2017
2018
            cb();
2019
        });
2020
    });
2021
});
2022
2023
describe("size estimation", function() {
2024
2025
    it("should estimate proper size for 1 input 1 output TX", function() {
2026
        var txb = new bitcoin.TransactionBuilder(bitcoin.networks.testnet);
2027
        txb.addInput('4200000000000000000000000000000000000000000000000000000000000000', 0);
2028
        txb.addOutput('2MzyKviSL6pnWxkbHV7ecFRE3hWKfzmT8WS', 1);
2029
2030
        assert.equal(347, blocktrail.Wallet.estimateIncompleteTxSize(txb.buildIncomplete()));
2031
    });
2032
2033
    it("should estimate proper size for 99 inputs 1 output TX", function() {
2034
        var txb = new bitcoin.TransactionBuilder(bitcoin.networks.testnet);
2035
        for (var i = 0; i < 99; i++) {
2036
            txb.addInput('4200000000000000000000000000000000000000000000000000000000000000', i);
2037
        }
2038
        txb.addOutput('2MzyKviSL6pnWxkbHV7ecFRE3hWKfzmT8WS', 1);
2039
2040
        assert.equal(29453, blocktrail.Wallet.estimateIncompleteTxSize(txb.buildIncomplete()));
2041
    });
2042
2043
    it("should estimate proper size for 1 input 99 outputs TX", function() {
2044
        var txb = new bitcoin.TransactionBuilder(bitcoin.networks.testnet);
2045
        txb.addInput('4200000000000000000000000000000000000000000000000000000000000000', 0);
2046
        for (var i = 0; i < 99; i++) {
2047
            txb.addOutput('2MzyKviSL6pnWxkbHV7ecFRE3hWKfzmT8WS', 1);
2048
        }
2049
2050
        assert.equal(3679, blocktrail.Wallet.estimateIncompleteTxSize(txb.buildIncomplete()));
2051
    });
2052
});
2053
2054
describe("APIClient", function() {
2055
    it("resolvePrimaryPrivateKeyFromOptions", function(cb) {
2056
        client.resolvePrimaryPrivateKeyFromOptions({
2057
            passphrase: "password",
2058
            primaryMnemonic: "give pause forget seed dance crawl situate hole keen"
2059
        }, function(err, options) {
2060
            assert.ifError(err);
2061
            assert.ok(options.primaryPrivateKey);
2062
            assert.ok(options.primaryPrivateKey instanceof bitcoin.HDNode);
2063
            assert.equal("tprv8ZgxMBicQKsPeR93md5eVTbLDgQ8kfV4CDNtrVXv5p29KXtx7VHKFQThGkFgC61sYeeeaVH1yFv4thcvxS9cYdFrYwTNmkGhkQEJycSzAhE", options.primaryPrivateKey.toBase58());
2064
2065
            cb();
2066
2067
        });
2068
    });
2069
});
2070
2071
describe("bitcoin cash address switching", function() {
2072
    describe("APIClient.getLegacyBitcoinCashAddress", function() {
2073
        describe("doesnt work with BTC", function() {
2074
            it("fails", function(cb) {
2075
                var tbtcNetwork = _createApiClient("BTC", true);
2076
                var err;
2077
                try {
2078
                    tbtcNetwork.getLegacyBitcoinCashAddress("1BpEi6DfDAUFd7GtittLSdBeYJvcoaVggu");
2079
                } catch (e) {
2080
                    err = e;
2081
                }
2082
2083
                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...
2084
                assert.ok("Cash addresses only work on bitcoin cash" === err.message);
2085
                cb();
2086
            });
2087
        });
2088
2089
        function testLegacyFromCashAddress(network, testnet, legacy, cash) {
2090
            var bccNetwork = _createApiClient(network, testnet);
2091
2092
            it("returns base58 address if that was given", function(cb) {
2093
                assert.ok(legacy === bccNetwork.getLegacyBitcoinCashAddress(legacy));
2094
                cb();
2095
            });
2096
            it("returns legacy address for cashaddress", function(cb) {
2097
                assert.ok(legacy === bccNetwork.getLegacyBitcoinCashAddress(cash));
2098
                cb();
2099
            });
2100
        }
2101
2102
        describe ("works with BCC testnet (P2SH)", function() {
2103
            testLegacyFromCashAddress("BCC", true, "2N44ThNe8NXHyv4bsX8AoVCXquBRW94Ls7W", "bchtest:ppm2qsznhks23z7629mms6s4cwef74vcwvhanqgjxu");
2104
        });
2105
        describe ("works with BCC (P2SH)", function() {
2106
            testLegacyFromCashAddress("BCC", false, "3LDsS579y7sruadqu11beEJoTjdFiFCdX4", "bitcoincash:pr95sy3j9xwd2ap32xkykttr4cvcu7as4yc93ky28e");
2107
        });
2108
        describe ("works with BCC (P2PKH)", function() {
2109
            testLegacyFromCashAddress("BCC", false, "1BpEi6DfDAUFd7GtittLSdBeYJvcoaVggu", "bitcoincash:qpm2qsznhks23z7629mms6s4cwef74vcwvy22gdx6a");
2110
        });
2111
    });
2112
2113
2114
    describe("APIClient.getCashAddressFromLegacyAddress", function() {
2115
        describe("doesnt work with BTC", function() {
2116
            it("fails", function(cb) {
2117
                var tbtcNetwork = _createApiClient("BTC", true);
2118
                var err;
2119
                try {
2120
                    tbtcNetwork.getCashAddressFromLegacyAddress("1BpEi6DfDAUFd7GtittLSdBeYJvcoaVggu");
2121
                } catch (e) {
2122
                    err = e;
2123
                }
2124
2125
                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...
2126
                assert.ok("Cash addresses only work on bitcoin cash" === err.message);
2127
                cb();
2128
            });
2129
        });
2130
2131
        function testCashFromLegacyAddress(network, testnet, cash, legacy) {
2132
            var bccNetwork = _createApiClient(network, testnet);
2133
2134
            it("returns cash address if that was given", function(cb) {
2135
                assert.ok(cash === bccNetwork.getCashAddressFromLegacyAddress(cash));
2136
                cb();
2137
            });
2138
2139
            it("returns cash address for base58 address", function(cb) {
2140
                assert.ok(cash === bccNetwork.getCashAddressFromLegacyAddress(legacy));
2141
                cb();
2142
            });
2143
        }
2144
2145
        describe ("works with BCC testnet (P2SH)", function() {
2146
            testCashFromLegacyAddress("BCC", true, "bchtest:ppm2qsznhks23z7629mms6s4cwef74vcwvhanqgjxu", "2N44ThNe8NXHyv4bsX8AoVCXquBRW94Ls7W");
2147
        });
2148
2149
        describe ("works with BCC (P2SH)", function() {
2150
            testCashFromLegacyAddress("BCC", false, "bitcoincash:pr95sy3j9xwd2ap32xkykttr4cvcu7as4yc93ky28e", "3LDsS579y7sruadqu11beEJoTjdFiFCdX4");
2151
        });
2152
2153
        describe ("works with BCC (P2PKH)", function() {
2154
            testCashFromLegacyAddress("BCC", false, "bitcoincash:qpm2qsznhks23z7629mms6s4cwef74vcwvy22gdx6a", "1BpEi6DfDAUFd7GtittLSdBeYJvcoaVggu");
2155
        });
2156
    });
2157
2158
    var wallet;
2159
2160
    describe("wallet send", function() {
2161
        /**
2162
         * @type APIClient
2163
         */
2164
        var tbccClient = _createApiClient("BCC", true);
2165
        var legacyAddress;
2166
        var cashAddress;
2167
        it("should exists", function(cb) {
2168
            tbccClient.initWallet({
2169
                identifier: "unittest-transaction",
2170
                passphrase: "password",
2171
                useCashAddress: true
2172
            }, function(err, _wallet) {
2173
                assert.ifError(err);
2174
                assert.ok(_wallet);
2175
2176
                wallet = _wallet;
2177
                cb();
2178
            });
2179
        });
2180
2181
        it("generates an address", function(cb) {
2182
            wallet.getNewAddress(function(err, result) {
2183
                assert.ifError(err);
2184
                legacyAddress = tbccClient.getLegacyBitcoinCashAddress(result);
2185
                cashAddress = result;
2186
                cb();
2187
            });
2188
        });
2189
2190
        it("sends to legacy address", function(cb) {
2191
            var pay = {};
2192
            pay[legacyAddress] = 100000;
2193
            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...
2194
                assert.ifError(err);
2195
                cb();
2196
            });
2197
        });
2198
2199
        it("sends to cash address", function(cb) {
2200
            var pay = {};
2201
            pay[cashAddress] = 100000;
2202
            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...
2203
                assert.ifError(err);
2204
                cb();
2205
            });
2206
        });
2207
2208
        it("parse cash address without prefix", function(cb) {
2209
            var net = bitcoin.networks.bitcoincash;
2210
            var decoded = Wallet.getAddressAndType("qpm2qsznhks23z7629mms6s4cwef74vcwvy22gdx6a", net, true);
2211
            assert.ok(decoded);
2212
            assert.equal('cashaddr', decoded.type);
2213
            assert.equal('bitcoincash', decoded.decoded.prefix);
2214
            cb();
2215
        });
2216
2217
        it("parse cash address (CAPITAL) without prefix", function(cb) {
2218
            var net = bitcoin.networks.bitcoincash;
2219
            var decoded = Wallet.getAddressAndType("qpm2qsznhks23z7629mms6s4cwef74vcwvy22gdx6a".toUpperCase(), net, true);
2220
            assert.ok(decoded);
2221
            assert.equal('cashaddr', decoded.type);
2222
            assert.equal('bitcoincash', decoded.decoded.prefix);
2223
            cb();
2224
        });
2225
2226
        it("parse cash address (CAPITAL) with prefix", function(cb) {
2227
            var net = bitcoin.networks.bitcoincash;
2228
            var decoded = Wallet.getAddressAndType("bitcoincash:qpm2qsznhks23z7629mms6s4cwef74vcwvy22gdx6a".toUpperCase(), net, true);
2229
            assert.ok(decoded);
2230
            assert.equal('cashaddr', decoded.type);
2231
            assert.equal('bitcoincash', decoded.decoded.prefix);
2232
            cb();
2233
        });
2234
    });
2235
});
2236