|
|
@ -1267,90 +1267,6 @@ WalletService.prototype._checkTxAndEstimateFee = function(txp) { |
|
|
|
|
|
|
|
WalletService.prototype._selectTxInputs = function(txp, utxosToExclude, cb) { |
|
|
|
var self = this; |
|
|
|
//todo: check inputs are ours and has enough value
|
|
|
|
if (txp.inputs && txp.inputs.length > 0) { |
|
|
|
return cb(self._checkTxAndEstimateFee(txp)); |
|
|
|
} |
|
|
|
|
|
|
|
function sortUtxos(utxos) { |
|
|
|
var list = _.map(utxos, function(utxo) { |
|
|
|
var order; |
|
|
|
if (utxo.confirmations == 0) { |
|
|
|
order = 0; |
|
|
|
} else if (utxo.confirmations < 6) { |
|
|
|
order = -1; |
|
|
|
} else { |
|
|
|
order = -2; |
|
|
|
} |
|
|
|
return { |
|
|
|
order: order, |
|
|
|
utxo: utxo |
|
|
|
}; |
|
|
|
}); |
|
|
|
return _.pluck(_.sortBy(list, 'order'), 'utxo'); |
|
|
|
}; |
|
|
|
|
|
|
|
self._getUtxosForCurrentWallet(null, function(err, utxos) { |
|
|
|
if (err) return cb(err); |
|
|
|
|
|
|
|
var excludeIndex = _.reduce(utxosToExclude, function(res, val) { |
|
|
|
res[val] = val; |
|
|
|
return res; |
|
|
|
}, {}); |
|
|
|
|
|
|
|
utxos = _.reject(utxos, function(utxo) { |
|
|
|
return excludeIndex[utxo.txid + ":" + utxo.vout]; |
|
|
|
}); |
|
|
|
|
|
|
|
var totalAmount; |
|
|
|
var availableAmount; |
|
|
|
|
|
|
|
var balance = self._totalizeUtxos(utxos); |
|
|
|
if (txp.excludeUnconfirmedUtxos) { |
|
|
|
totalAmount = balance.totalConfirmedAmount; |
|
|
|
availableAmount = balance.availableConfirmedAmount; |
|
|
|
} else { |
|
|
|
totalAmount = balance.totalAmount; |
|
|
|
availableAmount = balance.availableAmount; |
|
|
|
} |
|
|
|
|
|
|
|
if (totalAmount < txp.getTotalAmount()) return cb(Errors.INSUFFICIENT_FUNDS); |
|
|
|
if (availableAmount < txp.getTotalAmount()) return cb(Errors.LOCKED_FUNDS); |
|
|
|
|
|
|
|
// Prepare UTXOs list
|
|
|
|
utxos = _.reject(utxos, 'locked'); |
|
|
|
if (txp.excludeUnconfirmedUtxos) { |
|
|
|
utxos = _.filter(utxos, 'confirmations'); |
|
|
|
} |
|
|
|
|
|
|
|
var i = 0; |
|
|
|
var total = 0; |
|
|
|
var selected = []; |
|
|
|
var inputs = sortUtxos(utxos); |
|
|
|
|
|
|
|
var bitcoreTx, bitcoreError; |
|
|
|
|
|
|
|
function select() { |
|
|
|
if (i >= inputs.length) return cb(bitcoreError || new Error('Could not select tx inputs')); |
|
|
|
|
|
|
|
var input = inputs[i++]; |
|
|
|
selected.push(input); |
|
|
|
total += input.satoshis; |
|
|
|
if (total >= txp.getTotalAmount()) { |
|
|
|
txp.setInputs(selected); |
|
|
|
bitcoreError = self._checkTxAndEstimateFee(txp); |
|
|
|
if (!bitcoreError) return cb(); |
|
|
|
} |
|
|
|
setTimeout(select, 0); |
|
|
|
}; |
|
|
|
|
|
|
|
select(); |
|
|
|
}); |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
WalletService.prototype._selectTxInputs2 = function(txp, utxosToExclude, cb) { |
|
|
|
var self = this; |
|
|
|
|
|
|
|
//todo: check inputs are ours and has enough value
|
|
|
|
if (txp.inputs && txp.inputs.length > 0) { |
|
|
@ -1796,22 +1712,6 @@ WalletService.prototype.createTxLegacy = function(opts, cb) { |
|
|
|
WalletService.prototype.createTx = function(opts, cb) { |
|
|
|
var self = this; |
|
|
|
|
|
|
|
function logStatistics(prefix, txp) { |
|
|
|
var totalAmount = txp.getTotalAmount(); |
|
|
|
var inputs = _.sortBy(_.map(txp.inputs, function(input) { |
|
|
|
return _.pick(input, 'satoshis', 'confirmations'); |
|
|
|
}), 'satoshis'); |
|
|
|
var totalLocked = _.sum(inputs, 'satoshis'); |
|
|
|
var overhead = totalLocked - totalAmount; |
|
|
|
|
|
|
|
log.info(prefix, 'TXP ID: ' + txp.id); |
|
|
|
log.info(prefix, 'Total amount: ' + Utils.formatAmountInBtc(totalAmount)); |
|
|
|
log.info(prefix, 'Fee: ' + Utils.formatAmountInBtc(txp.fee) + ' (per KB: ' + Utils.formatAmountInBtc(txp.feePerKb) + ')'); |
|
|
|
log.info(prefix, 'Exclude unconfirmed: ' + txp.excludeUnconfirmedUtxos); |
|
|
|
log.info(prefix, 'Total locked: ' + Utils.formatAmountInBtc(totalLocked) + ', Overhead: ' + Utils.formatAmountInBtc(overhead) + ' (' + Utils.formatRatio(overhead / totalAmount) + ')'); |
|
|
|
log.info(prefix, 'Inputs: ', Utils.formatUtxos(inputs)); |
|
|
|
}; |
|
|
|
|
|
|
|
if (!Utils.checkRequired(opts, ['outputs', 'feePerKb'])) |
|
|
|
return cb(new ClientError('Required argument missing')); |
|
|
|
|
|
|
@ -1853,21 +1753,9 @@ WalletService.prototype.createTx = function(opts, cb) { |
|
|
|
|
|
|
|
var txp = Model.TxProposal.create(txOpts); |
|
|
|
|
|
|
|
self._selectTxInputs2(txp, opts.utxosToExclude, function(err) { |
|
|
|
if (err) { |
|
|
|
log.error('Could not select inputs using new algorithm', err); |
|
|
|
} else { |
|
|
|
logStatistics('NEW_UTXO_SEL', txp); |
|
|
|
} |
|
|
|
|
|
|
|
txp.setInputs([]); |
|
|
|
txp.fee = null; |
|
|
|
|
|
|
|
self._selectTxInputs(txp, opts.utxosToExclude, function(err) { |
|
|
|
if (err) return cb(err); |
|
|
|
|
|
|
|
logStatistics('OLD_UTXO_SEL', txp); |
|
|
|
|
|
|
|
self.storage.storeAddressAndWallet(wallet, txp.changeAddress, function(err) { |
|
|
|
if (err) return cb(err); |
|
|
|
|
|
|
@ -1880,7 +1768,6 @@ WalletService.prototype.createTx = function(opts, cb) { |
|
|
|
}); |
|
|
|
}); |
|
|
|
}); |
|
|
|
}); |
|
|
|
}; |
|
|
|
|
|
|
|
WalletService.prototype._verifyRequestPubKey = function(requestPubKey, signature, xPubKey) { |
|
|
|