From c5f40b3bd695d79a7799b2962f59138bf2bd384d Mon Sep 17 00:00:00 2001 From: Bernard Snowden Date: Thu, 21 Jan 2021 13:14:29 -0500 Subject: [PATCH] add /v2/balance/ endpoint; fix tests --- packages/bitcore-wallet-client/src/lib/api.ts | 16 +++-- .../bitcore-wallet-client/test/api.test.js | 71 ++++++++++++++++++- .../src/lib/expressapp.ts | 41 ++++++++++- 3 files changed, 116 insertions(+), 12 deletions(-) diff --git a/packages/bitcore-wallet-client/src/lib/api.ts b/packages/bitcore-wallet-client/src/lib/api.ts index 27b02883521..548133c164e 100644 --- a/packages/bitcore-wallet-client/src/lib/api.ts +++ b/packages/bitcore-wallet-client/src/lib/api.ts @@ -1563,27 +1563,27 @@ export class API extends EventEmitter { } private convertBalance(inB) { - let ret: any = {}; + let ret: any = {}; const fields = [ 'totalAmount', 'lockedAmount', 'totalConfirmedAmount', 'lockedConfirmedAmount', 'availableAmount', - 'availableConfirmedAmount', + 'availableConfirmedAmount' ]; - fields.forEach(x=> { + fields.forEach(x => { ret[x] = BigInt(inB[x] || 0); }); ret.byAddress = inB.byAddress; - ret.byAddress.forEach(x=> { + ret.byAddress.forEach(x => { x = BigInt(x.amount || 0); }); return ret; - }; + } // /** // * Update wallet balance @@ -1593,7 +1593,7 @@ export class API extends EventEmitter { // * @param {String} opts.multisigContractAddress optional: MULTISIG ETH Contract Address // * @param {Callback} cb // */ - getBalance(opts, cb) { + getBalance(opts, cb, baseUrl) { if (!cb) { cb = opts; opts = {}; @@ -1601,6 +1601,7 @@ export class API extends EventEmitter { } opts = opts || {}; + baseUrl = baseUrl || '/v2/balance/'; $.checkState( this.credentials && this.credentials.isComplete(), @@ -1624,9 +1625,10 @@ export class API extends EventEmitter { qs = '?' + args.join('&'); } - var url = '/v1/balance/' + qs; + var url = baseUrl + qs; this.request.get(url, (err, inB) => { if (err) return cb(err); + if (opts.doNotConvertResponse) return cb(null, inB); return cb(null, this.convertBalance(inB)); }); } diff --git a/packages/bitcore-wallet-client/test/api.test.js b/packages/bitcore-wallet-client/test/api.test.js index 7b52fef50f8..015d3aef3d9 100644 --- a/packages/bitcore-wallet-client/test/api.test.js +++ b/packages/bitcore-wallet-client/test/api.test.js @@ -6,6 +6,7 @@ var chai = require('chai'); chai.config.includeStack = true; var sinon = require('sinon'); var should = chai.should(); +var expect = chai.expect(); var async = require('async'); var request = require('supertest'); var Uuid = require('uuid'); @@ -41,6 +42,7 @@ var ExpressApp = BWS.ExpressApp; var Storage = BWS.Storage; var TestData = require('./testdata'); var Errors = require('../ts_build/lib/errors'); +const { assert } = require('console'); var helpers = {}; helpers.toSatoshi = btc => { @@ -6998,7 +7000,70 @@ describe('client API', function() { }); }); - it('should be able to recover funds from recreated wallet', function(done) { + it('should be able to recover funds from recreated wallet /v1/balance/', function(done) { + this.timeout(10000); + helpers.createAndJoinWallet(clients, keys, 2, 2, {}, () => { + clients[0].createAddress((err, addr) => { + should.not.exist(err,err); + should.exist(addr); + blockchainExplorerMock.setUtxo(addr, 1, 2); + + var storage = new Storage({ + db: db2 + }); + var newApp; + var expressApp = new ExpressApp(); + expressApp.start( + { + storage: storage, + blockchainExplorer: blockchainExplorerMock, + disableLogs: true + }, + () => { + newApp = expressApp.app; + + var recoveryClient = helpers.newClient(newApp); + recoveryClient.fromString(clients[0].toString()); + + recoveryClient.getStatus({}, (err, status) => { + should.exist(err); + err.should.be.an.instanceOf(Errors.NOT_AUTHORIZED); + recoveryClient.recreateWallet(err => { + should.not.exist(err,err); + recoveryClient.getStatus({}, (err, status) => { + should.not.exist(err,err); + recoveryClient.startScan({}, err => { + should.not.exist(err,err); + var balance = 0; + async.whilst( + () => { + return balance == 0; + }, + next => { + setTimeout(() => { + recoveryClient.getBalance({doNotConvertResponse: true}, (err, b) => { + balance = b.totalAmount; + next(err); + }, '/v1/balance/'); + }, 200); + }, + err => { + should.not.exist(err,err); + (typeof(balance) === "string").should.equal(true); + done(); + } + ); + }); + }); + }); + }); + } + ); + }); + }); + }); + + it('should be able to recover funds from recreated wallet /v2/balance/', function(done) { this.timeout(10000); helpers.createAndJoinWallet(clients, keys, 2, 2, {}, () => { clients[0].createAddress((err, addr) => { @@ -7042,12 +7107,12 @@ describe('client API', function() { recoveryClient.getBalance({}, (err, b) => { balance = b.totalAmount; next(err); - }); + }, '/v2/balance/'); }, 200); }, err => { should.not.exist(err,err); - balance.should.equal(1e8); + (typeof(balance) === "bigint").should.equal(true); done(); } ); diff --git a/packages/bitcore-wallet-service/src/lib/expressapp.ts b/packages/bitcore-wallet-service/src/lib/expressapp.ts index 40b49891f4e..3519f0adc8c 100644 --- a/packages/bitcore-wallet-service/src/lib/expressapp.ts +++ b/packages/bitcore-wallet-service/src/lib/expressapp.ts @@ -18,13 +18,14 @@ const Defaults = Common.Defaults; // / Patch bigint for JSON serealization // @ts-ignore-start -BigInt.prototype.toJSON = function() { return this.toString(); } +BigInt.prototype.toJSON = function() { + return this.toString(); +}; // @ts-ignore-end/ export class ExpressApp { app: express.Express; - constructor() { this.app = express(); } @@ -738,6 +739,42 @@ export class ExpressApp { }); }); + router.get('/v2/balance/', (req, res) => { + getServerWithAuth(req, res, server => { + const opts: { + coin?: string; + twoStep?: boolean; + tokenAddress?: string; + multisigContractAddress?: string; + } = {}; + if (req.query.coin) opts.coin = req.query.coin; + if (req.query.twoStep == '1') opts.twoStep = true; + if (req.query.tokenAddress) opts.tokenAddress = req.query.tokenAddress; + if (req.query.multisigContractAddress) opts.multisigContractAddress = req.query.multisigContractAddress; + + server.getBalance(opts, (err, balance) => { + let balanceResponse = {}; + + if (err) return returnError(err, res, req); + _.forEach(balance, (value, key) => { + if (key == 'totalAmount') { + balanceResponse[key] = balance[key].toString(); + } + + if (key == 'byAddress') { + balanceResponse[key] = balance[key]; + if (balanceResponse[key].amount) { + balanceResponse[key].amount = balanceResponse[key].amount.toString(); + } + } else { + balanceResponse[key] = balance[key]; + } + }); + res.json(balanceResponse); + }); + }); + }); + let estimateFeeLimiter; if (Defaults.RateLimit.estimateFee && !opts.ignoreRateLimiter) {