Issues (615)

test/wallet.test.js (1 issue)

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
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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;
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);
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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);
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;
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) {
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) {
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) {
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) {
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) {
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) {
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) {
1564
                assert.ifError(err);
1565
1566
                wallet.getNewAddress(function(err, address1) {
1567
                    assert.ifError(err);
1568
1569
                    wallet.deleteWebhook(myWebhookIdentifier, function(err, result) {
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) {
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);
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) {
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) {
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);
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);
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) {
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) {
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