diff --git a/lib/services/address/index.js b/lib/services/address/index.js index af9ff7df..5783b43d 100644 --- a/lib/services/address/index.js +++ b/lib/services/address/index.js @@ -52,7 +52,8 @@ AddressService.prototype.getAPIMethods = function() { ['getOutputs', this, this.getOutputs, 2], ['getUnspentOutputs', this, this.getUnspentOutputs, 2], ['isSpent', this, this.isSpent, 2], - ['getAddressHistory', this, this.getAddressHistory, 2] + ['getAddressHistory', this, this.getAddressHistory, 2], + ['getAddressSummary', this, this.getAddressSummary, 1] ]; }; @@ -871,4 +872,116 @@ AddressService.prototype.getAddressHistory = function(addresses, options, callba history.get(callback); }; +/** + * This will return an object with: + * balance - confirmed balance + * unconfirmedBalance - unconfirmed balance + * totalReceived - satoshis received + * totalSpent - satoshis spent + * appearances - number of times used in confirmed transactions + * unconfirmedApearances - number of times used in unconfirmed transactions + * txids - list of txids (unless noTxList is set) + * + * @param {String} address + * @param {Function} callback + */ +AddressService.prototype.getAddressSummary = function(address, options, callback) { + var self = this; + + var opt = { + queryMempool: true + }; + + var outputs; + var inputs; + + async.waterfall( + [ + function(next) { + if(options.noTxList) { + next(); + } else { + self.getInputs(address, opt, function(err, ins) { + inputs = ins; + next(err); + }); + } + }, + function(next) { + self.getOutputs(address, opt, function(err, outs) { + outputs = outs; + next(err); + }); + } + ], + function(err) { + if(err) { + return callback(err); + } + + var totalReceived = 0; + var totalSpent = 0; + var balance = 0; + var unconfirmedBalance = 0; + var appearances = 0; + var unconfirmedAppearances = 0; + var txids = []; + + for(var i = 0; i < outputs.length; i++) { + var spent = self.node.services.bitcoind.isSpent(outputs[i].txid, outputs[i].outputIndex); + var spentConfirmed = true; // TODO + + txids.push(outputs[i]); + totalReceived += outputs[i].satoshis; + unconfirmedBalance += outputs[i].satoshis; + if(outputs[i].confirmations) { + balance += outputs[i].satoshis; + appearances++; + } else { + unconfirmedAppearances++; + } + + if(spent) { + totalSpent += outputs[i].satoshis; + unconfirmedBalance -= outputs[i].satoshis; + if(spentConfirmed) { + balance -= outputs[i].satoshis; + appearances++; + } else { + unconfirmedAppearances++; + } + } + } + + var summary = { + totalReceived: totalReceived, + totalSpent: totalSpent, + balance: balance, + unconfirmedBalance: unconfirmedBalance, + appearances: appearances, + unconfirmedAppearances: unconfirmedAppearances + }; + + if(inputs) { + for(var i = 0; i < inputs.length; i++) { + txids.push(inputs[i]); + } + + // sort by height + txids = txids.sort(function(a, b) { + return a.height > b.height ? 1 : -1; + }).map(function(obj) { + return obj.txid; + }).filter(function(value, index, self) { + return self.indexOf(value) === index; + }); + + summary.txids = txids; + } + + callback(null, summary); + } + ); +}; + module.exports = AddressService;