Merge pull request #324 from isocolsky/ref/get_utxos
Refactor get UTXOs to accept specific addresses
This commit is contained in:
commit
386fb4c08c
|
@ -277,8 +277,11 @@ ExpressApp.prototype.start = function(opts, cb) {
|
|||
});
|
||||
|
||||
router.get('/v1/utxos/', function(req, res) {
|
||||
var opts = {};
|
||||
var addresses = req.query.addresses;
|
||||
if (addresses && _.isString(addresses)) opts.addresses = req.query.addresses.split(',');
|
||||
getServerWithAuth(req, res, function(server) {
|
||||
server.getUtxos(function(err, utxos) {
|
||||
server.getUtxos(opts, function(err, utxos) {
|
||||
if (err) return returnError(err, res, req);
|
||||
res.json(utxos);
|
||||
});
|
||||
|
|
|
@ -154,7 +154,6 @@ WalletService.getInstance = function(opts) {
|
|||
* @param {string} opts.clientVersion - A string that identifies the client issuing the request
|
||||
*/
|
||||
WalletService.getInstanceWithAuth = function(opts, cb) {
|
||||
|
||||
if (!Utils.checkRequired(opts, ['copayerId', 'message', 'signature']))
|
||||
return cb(new ClientError('Required argument missing'));
|
||||
|
||||
|
@ -618,10 +617,30 @@ WalletService.prototype._getBlockchainExplorer = function(network) {
|
|||
return this.blockchainExplorer;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns list of UTXOs
|
||||
*/
|
||||
WalletService.prototype.getUtxos = function(cb) {
|
||||
WalletService.prototype._getUtxosForAddresses = function(addresses, cb) {
|
||||
var self = this;
|
||||
|
||||
if (addresses.length == 0) return cb(null, []);
|
||||
var networkName = Bitcore.Address(addresses[0]).toObject().network;
|
||||
|
||||
var bc = self._getBlockchainExplorer(networkName);
|
||||
bc.getUnspentUtxos(addresses, function(err, utxos) {
|
||||
if (err) return cb(err);
|
||||
|
||||
var utxos = _.map(utxos, function(utxo) {
|
||||
var u = _.pick(utxo, ['txid', 'vout', 'address', 'scriptPubKey', 'amount', 'satoshis', 'confirmations']);
|
||||
u.confirmations = u.confirmations || 0;
|
||||
u.locked = false;
|
||||
u.satoshis = u.satoshis ? +u.satoshis : Utils.strip(u.amount * 1e8);
|
||||
delete u.amount;
|
||||
return u;
|
||||
});
|
||||
|
||||
return cb(null, utxos);
|
||||
});
|
||||
};
|
||||
|
||||
WalletService.prototype._getUtxosForCurrentWallet = function(cb) {
|
||||
var self = this;
|
||||
|
||||
function utxoKey(utxo) {
|
||||
|
@ -631,29 +650,17 @@ WalletService.prototype.getUtxos = function(cb) {
|
|||
// Get addresses for this wallet
|
||||
self.storage.fetchAddresses(self.walletId, function(err, addresses) {
|
||||
if (err) return cb(err);
|
||||
if (addresses.length == 0) return cb(null, []);
|
||||
|
||||
var addressStrs = _.pluck(addresses, 'address');
|
||||
var addressToPath = _.indexBy(addresses, 'address'); // TODO : check performance
|
||||
var networkName = Bitcore.Address(addressStrs[0]).toObject().network;
|
||||
|
||||
var bc = self._getBlockchainExplorer(networkName);
|
||||
bc.getUnspentUtxos(addressStrs, function(err, inutxos) {
|
||||
self._getUtxosForAddresses(addressStrs, function(err, utxos) {
|
||||
if (err) return cb(err);
|
||||
if (utxos.length == 0) return cb(null, []);
|
||||
|
||||
var utxos = _.map(inutxos, function(utxo) {
|
||||
var u = _.pick(utxo, ['txid', 'vout', 'address', 'scriptPubKey', 'amount', 'satoshis', 'confirmations']);
|
||||
u.confirmations = u.confirmations || 0;
|
||||
u.locked = false;
|
||||
return u;
|
||||
});
|
||||
self.getPendingTxs({}, function(err, txps) {
|
||||
if (err) return cb(err);
|
||||
|
||||
var lockedInputs = _.map(_.flatten(_.pluck(txps, 'inputs')), utxoKey);
|
||||
|
||||
var utxoIndex = _.indexBy(utxos, utxoKey);
|
||||
|
||||
_.each(lockedInputs, function(input) {
|
||||
if (utxoIndex[input]) {
|
||||
utxoIndex[input].locked = true;
|
||||
|
@ -661,9 +668,8 @@ WalletService.prototype.getUtxos = function(cb) {
|
|||
});
|
||||
|
||||
// Needed for the clients to sign UTXOs
|
||||
var addressToPath = _.indexBy(addresses, 'address');
|
||||
_.each(utxos, function(utxo) {
|
||||
utxo.satoshis = utxo.satoshis ? +utxo.satoshis : Utils.strip(utxo.amount * 1e8);
|
||||
delete utxo.amount;
|
||||
utxo.path = addressToPath[utxo.address].path;
|
||||
utxo.publicKeys = addressToPath[utxo.address].publicKeys;
|
||||
});
|
||||
|
@ -674,6 +680,24 @@ WalletService.prototype.getUtxos = function(cb) {
|
|||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns list of UTXOs
|
||||
* @param {Object} opts
|
||||
* @param {Array} opts.addresses (optional) - List of addresses from where to fetch UTXOs.
|
||||
* @returns {Array} utxos - List of UTXOs.
|
||||
*/
|
||||
WalletService.prototype.getUtxos = function(opts, cb) {
|
||||
var self = this;
|
||||
|
||||
opts = opts || {};
|
||||
|
||||
if (_.isUndefined(opts.addresses)) {
|
||||
self._getUtxosForCurrentWallet(cb);
|
||||
} else {
|
||||
self._getUtxosForAddresses(opts.addresses, cb);
|
||||
}
|
||||
};
|
||||
|
||||
WalletService.prototype._totalizeUtxos = function(utxos) {
|
||||
var balance = {
|
||||
totalAmount: _.sum(utxos, 'satoshis'),
|
||||
|
@ -718,7 +742,7 @@ WalletService.prototype._computeBytesToSendMax = function(utxos, cb) {
|
|||
WalletService.prototype.getBalance = function(opts, cb) {
|
||||
var self = this;
|
||||
|
||||
self.getUtxos(function(err, utxos) {
|
||||
self.getUtxos({}, function(err, utxos) {
|
||||
if (err) return cb(err);
|
||||
|
||||
var balance = self._totalizeUtxos(utxos);
|
||||
|
@ -828,7 +852,7 @@ WalletService.prototype._selectTxInputs = function(txp, cb) {
|
|||
return _.pluck(_.sortBy(list, 'order'), 'utxo');
|
||||
};
|
||||
|
||||
self.getUtxos(function(err, utxos) {
|
||||
self.getUtxos({}, function(err, utxos) {
|
||||
if (err) return cb(err);
|
||||
|
||||
var totalAmount;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"name": "bitcore-wallet-service",
|
||||
"description": "A service for Mutisig HD Bitcoin Wallets",
|
||||
"author": "BitPay Inc",
|
||||
"version": "0.1.3",
|
||||
"version": "0.1.4",
|
||||
"keywords": [
|
||||
"bitcoin",
|
||||
"copay",
|
||||
|
|
|
@ -159,7 +159,12 @@ helpers.stubUtxos = function(server, wallet, amounts, cb) {
|
|||
confirmations: confirmations,
|
||||
};
|
||||
});
|
||||
blockchainExplorer.getUnspentUtxos = sinon.stub().callsArgWith(1, null, utxos);
|
||||
blockchainExplorer.getUnspentUtxos = function(addresses, cb) {
|
||||
var selected = _.filter(utxos, function(utxo) {
|
||||
return _.contains(addresses, utxo.address);
|
||||
});
|
||||
return cb(null, selected);
|
||||
};
|
||||
|
||||
return cb(utxos);
|
||||
});
|
||||
|
@ -1350,6 +1355,55 @@ describe('Wallet service', function() {
|
|||
});
|
||||
});
|
||||
|
||||
describe('#getUtxos', function() {
|
||||
var server, wallet;
|
||||
beforeEach(function(done) {
|
||||
helpers.createAndJoinWallet(1, 1, function(s, w) {
|
||||
server = s;
|
||||
wallet = w;
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should get UTXOs for wallet addresses', function(done) {
|
||||
helpers.stubUtxos(server, wallet, [1, 2], function() {
|
||||
server.getUtxos({}, function(err, utxos) {
|
||||
should.not.exist(err);
|
||||
should.exist(utxos);
|
||||
utxos.length.should.equal(2);
|
||||
_.sum(utxos, 'satoshis').should.equal(3 * 1e8);
|
||||
server.getMainAddresses({}, function(err, addresses) {
|
||||
var utxo = utxos[0];
|
||||
var address = _.find(addresses, {
|
||||
address: utxo.address
|
||||
});
|
||||
should.exist(address);
|
||||
utxo.path.should.equal(address.path);
|
||||
utxo.publicKeys.should.deep.equal(address.publicKeys);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
it('should get UTXOs for specific addresses', function(done) {
|
||||
helpers.stubUtxos(server, wallet, [1, 2, 3], function(utxos) {
|
||||
_.uniq(utxos, 'address').length.should.be.above(1);
|
||||
var address = utxos[0].address;
|
||||
var amount = _.sum(_.filter(utxos, {
|
||||
address: address
|
||||
}), 'satoshis');
|
||||
server.getUtxos({
|
||||
addresses: [address]
|
||||
}, function(err, utxos) {
|
||||
should.not.exist(err);
|
||||
should.exist(utxos);
|
||||
_.sum(utxos, 'satoshis').should.equal(amount);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getBalance', function() {
|
||||
var server, wallet;
|
||||
beforeEach(function(done) {
|
||||
|
|
Loading…
Reference in New Issue