UNPKG

bitcore-wallet-service

Version:
346 lines (293 loc) 11.6 kB
'use strict'; var _ = require('lodash'); var chai = require('chai'); var sinon = require('sinon'); var should = chai.should(); var { V8 } = require('../ts_build/lib/blockchainexplorers/v8'); var B = require('bitcore-lib-cash'); const { Readable } = require('stream'); var { Common } = require('../ts_build/lib/common'); var Defaults = Common.Defaults; const V8UTXOS = [ {"_id":"5c1d4bc47adced963b3cddb9","chain":"BCH","network":"testnet","coinbase":false,"mintIndex":0,"spentTxid":"","mintTxid":"6e34d9b83631cd55ee09d907061332ba3c17246e3c1255543fb7a35e58c52e42","mintHeight":12,"spentHeight":-2,"address":"qrua7vsdmks4522wwv8rtamfph7g8s8vpq6a0g3veh","script":"76a914f9df320ddda15a294e730e35f7690dfc83c0ec0888ac","value":1000000,"confirmations":-1}, {"_id":"5c1e33e17adced963b776bcf","chain":"BCH","network":"testnet","coinbase":false,"mintIndex":0,"spentTxid":"","mintTxid":"fb1340bae2431f71c5f14d0c5893cbfb09042dcb9602b858ccec43e0e1e2f1a1","mintHeight":15,"spentHeight":-2,"address":"qrua7vsdmks4522wwv8rtamfph7g8s8vpq6a0g3veh","script":"76a914f9df320ddda15a294e730e35f7690dfc83c0ec0888ac","value":2000000,"confirmations":-1}, {"_id":"5c21088f7adced963b33eea2","chain":"BCH","network":"testnet","coinbase":false,"mintIndex":0,"spentTxid":"","mintTxid":"42eeb1d139521fa5206685ffec5df3b302cf85561201178680a0efe6bd23d449","mintHeight":-1,"spentHeight":-2,"address":"qrua7vsdmks4522wwv8rtamfph7g8s8vpq6a0g3veh","script":"76a914f9df320ddda15a294e730e35f7690dfc83c0ec0888ac","value":2000000,"confirmations":-1}]; const V8UTXOS2 = [ { _id: '5cb4f9d612025b0a3931b13c', chain: 'BTC', network: 'mainnet', coinbase: false, mintIndex: 0, spentTxid: '', mintTxid: '623f72b089da60a179d7b85b50ed655e8580747ee06f2f77369cacfb99de11a0', mintHeight: 571792, spentHeight: -2, address: '38o49rd64PFDmvUV7928K1a5SRnoVgJSFW', script: 'a9144ded3cc47fcf6883a78c29134f90b0c1b0c368c887', value: 109810934, confirmations: 126 }, { _id: '5cb503e612025b0a393d2ea9', chain: 'BTC', network: 'mainnet', coinbase: false, mintIndex: 0, spentTxid: '', mintTxid: '06ab9db9100409132a4c1367b87f16983938007dbae7b96a0746a64a7755e3e6', mintHeight: 571797, spentHeight: -2, address: '36pUaXzGouNdCqUDRWRXX9NJYungJEWJC2', script: 'a9143841ca886a1c4276966a77a15d0d1c4fe1e841bd87', value: 350000000, confirmations: 121 }]; var t = (new Date).toISOString(); var external = '11234'; var txsStr = '{"id":"63863c730c84018998d248f1","txid":"e7d7362ff5e917c751ca54edc5022930ecc28f521b74851028a723c02ce2ad37","fee":225000,"size":225,"category":"receive","satoshis":1025000000,"height":-1,"address":"mi4rc4nKmWHHeNY4693cHofQY6gRLZW48P","outputIndex":1,"blockTime":"2022-11-29T15:59:11.000Z"}\n{"id":"63863c740c84018998d24f51","txid":"17966f1c514679eb55ccdacaa66a8186e433a06372b06c689e5514ff9b4442cb","fee":372000,"size":372,"category":"receive","satoshis":1055000000,"height":5589,"address":"mgAFBzA2M1yqFuXHvkUBUFMGM7CTzoEZgN","outputIndex":1,"blockTime":"2022-11-29T16:00:24.000Z"}\n{"id":"63863c750c84018998d255b7","txid":"52e6aa1d231a9c79f08f69d48fc91c28e36f2100f4bcb2aae270d3656d80bd96","fee":1232128,"size":1219,"category":"receive","satoshis":10000000000,"height":5689,"address":"n2bmPmt2z5MJ8SA1QR2uViKofBJE9wg2Wf","outputIndex":0,"blockTime":"2022-11-29T16:57:01.000Z"}\n'; describe('V8', () => { var wallet={}; wallet.beAuthPrivateKey2= new B.PrivateKey(); describe('#listTransactions', () => { it('should handle partial json results', (done) => { class PartialJson { listTransactions(opts) { class MyReadable extends Readable { constructor(options) { super(options); this.push(txsStr.substr(0,10)); this.push(txsStr.substr(10)); this.push(null); } }; return new MyReadable; }; }; var be = new V8({ chain: 'btc', network: 'livenet', url: 'http://dummy/', apiPrefix: 'dummyPath', userAgent: 'testAgent', addressFormat: null, client: PartialJson, }); be.getTransactions(wallet, 0, (err, txs) => { should.not.exist(err); should.exist(txs); txs.length.should.equal(3); return done(); }); }); it('should handle partial jsonline results', (done) => { class PartialJsonL { listTransactions(opts) { class MyReadable extends Readable { constructor(options) { super(options); var txStr = '{ "id": 1, "txid": "txid1", "confirmations": 1, "blockTime": "'+ t + '", "size": 226, "category": "send", "height": 123, "toAddress": "'+ external +'", "satoshis": 0.5e8 } \n { "id": 2, "txid": "txid2", "confirmations": 1, "category": "send", "blockTime": "'+ t + '", "satoshis": 0.3e8, "height": 123, "toAddress": "'+external + '"}'; this.push(txStr.substr(0,10)); this.push(txStr.substr(10)); this.push(null); } }; return new MyReadable; }; }; var be2 = new V8({ chain: 'btc', network: 'livenet', url: 'http://dummy/', apiPrefix: 'dummyPath', userAgent: 'testAgent', addressFormat: null, client: PartialJsonL, }); be2.getTransactions(wallet, 0, (err, txs) => { should.not.exist(err); should.exist(txs); txs.length.should.equal(2); return done(); }); }); }); describe.skip('#deregistedwallet', () => { }); describe('#getAddressUtxos', () => { it('should get uxtos', (done) => { class PartialJson { getAddressTxos(opts) { return new Promise(function (resolve) { resolve(V8UTXOS); }) }; }; var be = new V8({ chain: 'bch', network: 'livenet', url: 'http://dummy/', apiPrefix: 'dummyPath', userAgent: 'testAgent', client: PartialJson, }); be.getAddressUtxos('1EU9VhWRN7aW38pGk7qj3c2EDcUGDZKESt', 15, (err, utxos) => { should.not.exist(err); should.exist(utxos); let x = utxos[2]; x.confirmations.should.equal(0); x.address.should.equal('qrua7vsdmks4522wwv8rtamfph7g8s8vpq6a0g3veh'); x.satoshis.should.equal(2000000); x.amount.should.equal(x.satoshis/1e8); x.scriptPubKey.should.equal('76a914f9df320ddda15a294e730e35f7690dfc83c0ec0888ac'); x.txid.should.equal('42eeb1d139521fa5206685ffec5df3b302cf85561201178680a0efe6bd23d449'); x.vout.should.equal(0); utxos[1].confirmations.should.equal(1); utxos[0].confirmations.should.equal(4); return done(); }); }); it('should get uxtos 2', (done) => { class PartialJson { getAddressTxos(opts) { return new Promise(function (resolve) { resolve(V8UTXOS2); }) }; }; var be = new V8({ chain: 'bch', network: 'livenet', url: 'http://dummy/', apiPrefix: 'dummyPath', userAgent: 'testAgent', client: PartialJson, }); be.getAddressUtxos('36pUaXzGouNdCqUDRWRXX9NJYungJEWJC2', 571920, (err, utxos) => { should.not.exist(err); should.exist(utxos); let x = utxos[1]; x.confirmations.should.equal(124); x.satoshis.should.equal(350000000); x.amount.should.equal(3.5); return done(); }); }); }); describe('#estimateFee', () => { it('should estimate fee', (done) => { let fakeRequest = { get: sinon.stub().resolves('{"feerate":0.00017349,"blocks":5}'), }; var be = new V8({ chain: 'bch', network: 'livenet', url: 'http://dummy/', apiPrefix: 'dummyPath', userAgent: 'testAgent', request: fakeRequest, }); be.estimateFee([5], (err, levels) => { should.not.exist(err); should.exist(levels); // should ignore non-matching results levels.should.deep.equal({ '5': 0.00017349 }); return done(); }); }); it('should ignore non-matching results from estimate fee', (done) => { let fakeRequest = { get: sinon.stub().resolves('{"feerate":0.00017349,"blocks":4}'), }; var be = new V8({ chain: 'bch', network: 'livenet', url: 'http://dummy/', apiPrefix: 'dummyPath', userAgent: 'testAgent', request: fakeRequest, }); be.estimateFee([1,2,3,4,5], (err, levels) => { should.not.exist(err); should.exist(levels); // should ignore non-matching results levels.should.deep.equal({ '4': 0.00017349 }); return done(); }); }); it('should use results from estimate fee is blocks is not present', (done) => { let fakeRequest = { get: sinon.stub().resolves('{"feerate":0.00017349}'), }; var be = new V8({ chain: 'bch', network: 'livenet', url: 'http://dummy/', apiPrefix: 'dummyPath', userAgent: 'testAgent', request: fakeRequest, }); be.estimateFee([1,2,3,4,5], (err, levels) => { should.not.exist(err); should.exist(levels); levels.should.deep.equal({ '1': 0.00017349, '2': 0.00017349, '3': 0.00017349, '4': 0.00017349, '5': 0.00017349 }); return done(); }); }); }); describe('#broadcast', () => { it('should broadcast a TX', (done) => { class BroadcastOk { broadcast(payload) { return new Promise(function (resolve) { resolve({'txid':'txid'}); }) }; }; var be = new V8({ chain: 'bch', network: 'livenet', url: 'http://dummy/', apiPrefix: 'dummyPath', userAgent: 'testAgent', client: BroadcastOk, }); be.broadcast('xxx', (err, txid) => { should.not.exist(err); txid.should.equal('txid'); done(); }); }); it('should fail to broadcast an invalid TX', (done) => { class BroadcastInvalid { broadcast(payload) { return new Promise(function (resolve) { resolve('invalid'); }) }; }; var be = new V8({ chain: 'bch', network: 'livenet', url: 'http://dummy/', apiPrefix: 'dummyPath', userAgent: 'testAgent', client: BroadcastInvalid, }); be.broadcast('xxx', (err, txid) => { should.not.exist(txid); err.toString().should.contain('Error'); done(); }); }); it('should retry to broadcast is socket hang up', (done) => { var oldd = Defaults.BROADCAST_RETRY_TIME; Defaults.BROADCAST_RETRY_TIME = 5; var x=0; class BroadcastInvalid { broadcast(payload) { return new Promise(function (resolve,reject) { if (x++<2) { reject('socket err or'); } else { resolve({'txid':'txid'}); } }) }; }; var be = new V8({ chain: 'bch', network: 'livenet', url: 'http://dummy/', apiPrefix: 'dummyPath', userAgent: 'testAgent', client: BroadcastInvalid, }); be.broadcast('xxx', (err, txid) => { should.not.exist(err); txid.should.equal('txid'); Defaults.BROADCAST_RETRY_TIME = oldd; done(); }); }); }); });