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 || {}; |
||
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
|
|||
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) { |
||
0 ignored issues
–
show
|
|||
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) { |
||
0 ignored issues
–
show
|
|||
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); |
||
0 ignored issues
–
show
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. ![]() |
|||
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
|
|||
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); |
||
0 ignored issues
–
show
|
|||
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
|
|||
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
|
|||
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
|
|||
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
|
|||
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
|
|||
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
|
|||
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 |
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.