diff --git a/packages/bitcore-wallet-client/src/lib/bulkclient.ts b/packages/bitcore-wallet-client/src/lib/bulkclient.ts index 2dc9c25b048..e018c966d31 100644 --- a/packages/bitcore-wallet-client/src/lib/bulkclient.ts +++ b/packages/bitcore-wallet-client/src/lib/bulkclient.ts @@ -72,10 +72,10 @@ export class BulkClient extends Request { let wallets = opts.wallets; if (wallets) { Object.keys(wallets).forEach(copayerId => { - if (wallets[copayerId].tokenAddress) { - qs.push( - `${copayerId}[tokenAddress]=` + wallets[copayerId].tokenAddress - ); + if (wallets[copayerId].tokenAddresses) { + wallets[copayerId].tokenAddresses.forEach(address => { + qs.push(`${copayerId}[tokenAddress]=` + address); + }); } if (wallets[copayerId].multisigContractAddress) { diff --git a/packages/bitcore-wallet-client/test/bulkclient.test.js b/packages/bitcore-wallet-client/test/bulkclient.test.js index 59ff275c10c..4e4ee2eeab1 100644 --- a/packages/bitcore-wallet-client/test/bulkclient.test.js +++ b/packages/bitcore-wallet-client/test/bulkclient.test.js @@ -116,7 +116,6 @@ describe('Bulk Client', function () { helpers.createAndJoinWallet(clients, keys, 1, 1, {}, () => { const credentials = Array(3).fill(clients[0].credentials); - clients[0].bulkClient.getStatusAll(credentials,(err, wallets) => { should.not.exist(err); wallets.every(wallet => { @@ -127,7 +126,76 @@ describe('Bulk Client', function () { done(); }); }); + }); + + it('returns eth wallet and token wallet when getStatusAll is called', done => { + helpers.createAndJoinWallet(clients, keys, 1, 1, { coin: 'eth', network: 'livenet' }, () => { + let walletOptions = { + [clients[0].credentials.copayerId]: { + tokenAddresses: [ + '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48' + ] + } + }; + + clients[0].bulkClient.getStatusAll([clients[0].credentials], { includeExtendedInfo: true, twoStep: true, wallets: walletOptions }, (err, wallets) => { + should.not.exist(err); + wallets.length.should.equal(2); + wallets.findIndex(wallet => wallet.tokenAddress === null).should.be.above(-1); + wallets.findIndex(wallet => wallet.tokenAddress === '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48').should.be.above(-1); + + done(); + }); + }); + }); + + it('returns eth wallet and multiple token wallets when getStatusAll is called', done => { + helpers.createAndJoinWallet(clients, keys, 1, 1, { coin: 'eth', network: 'livenet' }, () => { + let walletOptions = { + [clients[0].credentials.copayerId]: { + tokenAddresses: [ + '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', + '0x056fd409e1d7a124bd7017459dfea2f387b6d5cd' + ] + } + }; + + clients[0].bulkClient.getStatusAll([clients[0].credentials], { includeExtendedInfo: true, twoStep: true, wallets: walletOptions }, (err, wallets) => { + should.not.exist(err); + wallets.length.should.equal(3); + wallets.findIndex(wallet => wallet.tokenAddress === null).should.be.above(-1); + wallets.findIndex(wallet => wallet.tokenAddress === '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48').should.be.above(-1); + wallets.findIndex(wallet => wallet.tokenAddress === '0x056fd409e1d7a124bd7017459dfea2f387b6d5cd').should.be.above(-1); + done(); + }); + }); + }); + + it('returns two eth wallets and token wallets associated with one of them', done => { + let key = new Key({ seedType: 'new' }); + helpers.createAndJoinWallet(clients, keys, 1, 1, { coin: 'eth', key: key, network: 'livenet' }, () => { + helpers.createAndJoinWallet(clients.slice(1), keys, 1, 1, { coin: 'eth', key: key, account: 1, network: 'livenet' }, () => { + let walletOptions = { + [clients[0].credentials.copayerId]: { + tokenAddresses: [ + '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', + '0x056fd409e1d7a124bd7017459dfea2f387b6d5cd' + ] + } + }; + + clients[0].bulkClient.getStatusAll([clients[0].credentials, clients[1].credentials], { includeExtendedInfo: true, twoStep: true, wallets: walletOptions }, (err, wallets) => { + should.not.exist(err); + wallets.length.should.equal(4); + wallets.filter(wallet => wallet.tokenAddress === null).length.should.equal(2); + wallets.findIndex(wallet => wallet.tokenAddress === '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48').should.be.above(-1); + wallets.findIndex(wallet => wallet.tokenAddress === '0x056fd409e1d7a124bd7017459dfea2f387b6d5cd').should.be.above(-1); + + done(); + }); + }); + }); }); it('fails gracefully when given bad signature', done => { diff --git a/packages/bitcore-wallet-client/test/helpers.js b/packages/bitcore-wallet-client/test/helpers.js index b791a78e057..050e00e9594 100644 --- a/packages/bitcore-wallet-client/test/helpers.js +++ b/packages/bitcore-wallet-client/test/helpers.js @@ -112,7 +112,7 @@ const helpers = { let cred = keys[0].createCredentials(null, { coin: coin, network: network, - account: 0, + account: opts.account ? opts.account : 0, n: n, addressType: opts.addressType }); diff --git a/packages/bitcore-wallet-service/src/lib/expressapp.ts b/packages/bitcore-wallet-service/src/lib/expressapp.ts index a4964e084f5..ba79937a17d 100644 --- a/packages/bitcore-wallet-service/src/lib/expressapp.ts +++ b/packages/bitcore-wallet-service/src/lib/expressapp.ts @@ -1,3 +1,4 @@ +import * as async from 'async'; import express from 'express'; import _ from 'lodash'; import 'source-map-support/register'; @@ -449,13 +450,16 @@ export class ExpressApp { router.get('/v1/wallets/all/', async (req, res) => { let responses; - const buildOpts = req => { - const copayerId = req.headers['x-identity']; + const buildOpts = (req, copayerId) => { const opts = { includeExtendedInfo: req.query.includeExtendedInfo == '1', twoStep: req.query.twoStep == '1', includeServerMessages: req.query.serverMessageArray == '1', - tokenAddress: req.query[copayerId] ? req.query[copayerId].tokenAddress : null, + tokenAddresses: req.query[copayerId] + ? Array.isArray(req.query[copayerId].tokenAddress) + ? req.query[copayerId].tokenAddress + : [req.query[copayerId].tokenAddress] + : null, multisigContractAddress: req.query[copayerId] ? req.query[copayerId].multisigContractAddress : null, network: req.query[copayerId] ? req.query[copayerId].network : null }; @@ -467,16 +471,46 @@ export class ExpressApp { getServerWithMultiAuth(req, res).map(promise => promise.then( (server: any) => - new Promise(resolve => - server.getStatus(buildOpts(req), (err, status) => - resolve({ - walletId: server.walletId, - success: true, - ...(err ? { success: false, message: err.message } : {}), - status - }) - ) - ), + new Promise(resolve => { + let options: any = buildOpts(req, server.copayerId); + if (options.tokenAddresses) { + // add a null entry to array so we can get the chain balance + options.tokenAddresses.unshift(null); + return async.concat( + options.tokenAddresses, + (tokenAddress, cb) => { + let optsClone = JSON.parse(JSON.stringify(options)); + optsClone.tokenAddresses = null; + optsClone.tokenAddress = tokenAddress; + return server.getStatus(optsClone, (err, status) => { + let result: any = { + walletId: server.walletId, + tokenAddress: optsClone.tokenAddress, + success: true, + ...(err ? { success: false, message: err.message } : {}), + status + }; + cb(err, result); + }); + }, + (err, result) => { + return resolve(result); + } + ); + } else { + return server.getStatus(options, (err, status) => { + return resolve([ + { + walletId: server.walletId, + tokenAddress: null, + success: true, + ...(err ? { success: false, message: err.message } : {}), + status + } + ]); + }); + } + }), ({ message }) => Promise.resolve({ success: false, error: message }) ) ) @@ -485,7 +519,7 @@ export class ExpressApp { return returnError(err, res, req); } - return res.json(responses); + return res.json(_.flatten(responses)); }); router.get('/v1/wallets/:identifier/', (req, res) => {