diff --git a/lib/server.js b/lib/server.js index 00347cf..a920eaf 100644 --- a/lib/server.js +++ b/lib/server.js @@ -926,6 +926,10 @@ WalletService.prototype.getTxHistory = function(opts, cb) { var self = this; function decorate(txs, addresses, proposals) { + + var indexedAddresses = _.indexBy(addresses, 'address'); + var indexedProposals = _.indexBy(proposals, 'txid'); + function sum(items, isMine, isChange) { var filter = {}; if (_.isBoolean(isMine)) filter.isMine = isMine; @@ -936,48 +940,64 @@ WalletService.prototype.getTxHistory = function(opts, cb) { }, 0); }; - var indexedAddresses = _.indexBy(addresses, 'address'); - var indexedProposals = _.indexBy(proposals, 'txid'); - - _.each(txs, function(tx) { - _.each(tx.inputs.concat(tx.outputs), function(item) { + function classify(items) { + return _.map(items, function(item) { var address = indexedAddresses[item.address]; - item.isMine = !!address; - item.isChange = address ? address.isChange : false; + return { + address: item.address, + amount: item.amount, + isMine: !!address, + isChange: address ? address.isChange : false, + } }); + }; - var amountIn = sum(tx.inputs, true); - var amountOut = sum(tx.outputs, true, false); - var amountOutChange = sum(tx.outputs, true, true); - var amount; + + return _.map(txs, function(tx) { + var inputs = classify(tx.inputs); + var outputs = classify(tx.outputs); + + var amountIn = sum(inputs, true); + var amountOut = sum(outputs, true, false); + var amountOutChange = sum(outputs, true, true); + var amount, action, addressTo; if (amountIn == (amountOut + amountOutChange + (amountIn > 0 ? tx.fees : 0))) { - tx.action = 'moved'; amount = amountOut; + action = 'moved'; } else { amount = amountIn - amountOut - amountOutChange - (amountIn > 0 ? tx.fees : 0); - tx.action = amount > 0 ? 'sent' : 'received'; + action = amount > 0 ? 'sent' : 'received'; } - tx.amount = Math.abs(amount); - if (tx.action == 'sent' || tx.action == 'moved') { - tx.addressTo = tx.outputs[0].address; + amount = Math.abs(amount); + if (action == 'sent' || action == 'moved') { + addressTo = outputs[0].address; }; - delete tx.inputs; - delete tx.outputs; + var newTx = { + txid: tx.txid, + action: action, + amount: amount, + fees: tx.fees, + time: tx.time, + addressTo: addressTo, + confirmations: tx.confirmations, + }; var proposal = indexedProposals[tx.txid]; if (proposal) { - tx.proposalId = proposal.id; - tx.creatorName = proposal.creatorName; - tx.message = proposal.message; - tx.actions = _.map(proposal.actions, function(action) { + newTx.proposalId = proposal.id; + newTx.creatorName = proposal.creatorName; + newTx.message = proposal.message; + newTx.actions = _.map(proposal.actions, function(action) { return _.pick(action, ['createdOn', 'type', 'copayerId', 'copayerName', 'comment']); }); - // tx.sentTs = proposal.sentTs; - // tx.merchant = proposal.merchant; - //tx.paymentAckMemo = proposal.paymentAckMemo; + // newTx.sentTs = proposal.sentTs; + // newTx.merchant = proposal.merchant; + //newTx.paymentAckMemo = proposal.paymentAckMemo; } + + return newTx; }); }; @@ -1024,8 +1044,7 @@ WalletService.prototype.getTxHistory = function(opts, cb) { var proposals = res[0]; var txs = res[1]; - decorate(txs, addresses, proposals); - txs = paginate(txs); + txs = paginate(decorate(txs, addresses, proposals)); return cb(null, txs); }); diff --git a/test/integration/server.js b/test/integration/server.js index f53299c..8f81a6a 100644 --- a/test/integration/server.js +++ b/test/integration/server.js @@ -2345,54 +2345,66 @@ describe('Copay server', function() { }); }); }); - describe('Pagination', function() { - beforeEach(function() { - server._normalizeTxHistory = sinon.stub().returnsArg(0); - var timestamps = [10, 50, 30, 40, 20]; - var txs = _.map(timestamps, function(ts, idx) { - return { - txid: (idx + 1).toString(), - confirmations: ts / 10, - fees: 100, - time: ts, - inputs: [{ - address: 'external', - amount: 500, - }], - outputs: [{ - address: mainAddresses[0].address, - amount: 200, - }], - }; - }); - - helpers.stubHistory(txs); - }); - it('should get paginated tx history', function(done) { - server.getTxHistory({ + it('should get various paginated tx history', function(done) { + var testCases = [{ + opts: { minTs: 15, maxTs: 45, - }, function(err, txs) { - should.not.exist(err); - should.exist(txs); - txs.length.should.equal(3); - _.pluck(txs, 'time').should.deep.equal([20, 30, 40]); - done(); - }); - }); - it('should get paginated tx history with limit', function(done) { - server.getTxHistory({ + }, + expected: [20, 30, 40], + }, { + opts: { minTs: 15, maxTs: 45, limit: 2, - }, function(err, txs) { + }, + expected: [20, 30], + }, { + opts: { + maxTs: 35, + }, + expected: [10, 20, 30], + }, { + opts: { + minTs: 15, + }, + expected: [20, 30, 40, 50], + }, { + opts: { + minTs: 15, + limit: 3, + }, + expected: [20, 30, 40], + }]; + + server._normalizeTxHistory = sinon.stub().returnsArg(0); + var timestamps = [10, 50, 30, 40, 20]; + var txs = _.map(timestamps, function(ts, idx) { + return { + txid: (idx + 1).toString(), + confirmations: ts / 10, + fees: 100, + time: ts, + inputs: [{ + address: 'external', + amount: 500, + }], + outputs: [{ + address: mainAddresses[0].address, + amount: 200, + }], + }; + }); + helpers.stubHistory(txs); + + async.each(testCases, function(testCase, next) { + server.getTxHistory(testCase.opts, function(err, txs) { should.not.exist(err); should.exist(txs); - txs.length.should.equal(2); - _.pluck(txs, 'time').should.deep.equal([20, 30]); - done(); + _.pluck(txs, 'time').should.deep.equal(testCase.expected); + next(); }); - }); + }, done); }); }); });