allow for external use of getSendMaxInfo + refactor createTx

This commit is contained in:
Ivan Socolsky 2016-02-25 14:23:01 -03:00
parent b2fc191f54
commit d23788100e
2 changed files with 80 additions and 65 deletions

View File

@ -1153,6 +1153,7 @@ WalletService.prototype.getBalance = function(opts, cb) {
* @param {Object} opts
* @param {string} opts.feePerKb - The fee per KB used to compute the TX.
* @param {string} opts.excludeUnconfirmedUtxos[=false] - Optional. Do not use UTXOs of unconfirmed transactions as inputs
* @param {string} opts.returnInputs[=false] - Optional. Return the list of UTXOs that would be included in the tx.
* @returns {Object} sendMaxInfo
*/
WalletService.prototype.getSendMaxInfo = function(opts, cb) {
@ -1209,7 +1210,7 @@ WalletService.prototype.getSendMaxInfo = function(opts, cb) {
info.size = txp.getEstimatedSize();
info.fee = txp.getEstimatedFee();
info.amount = _.sum(txp.inputs, 'satoshis') - info.fee;
info.inputs = txp.inputs;
if (opts.returnInputs) info.inputs = txp.inputs;
return cb(null, info);
});
@ -1785,20 +1786,78 @@ WalletService.prototype.createTxLegacy = function(opts, cb) {
});
};
WalletService.prototype._doCreateTx = function(opts, cb) {
WalletService.prototype._validateAndSanitizeTxOpts = function(wallet, opts, cb) {
var self = this;
if (!Utils.checkRequired(opts, ['outputs']))
return cb(new ClientError('Required argument missing'));
async.series([
// feePerKb is required unless inputs & fee are specified
if (!_.isNumber(opts.feePerKb) && !(opts.inputs && _.isNumber(opts.fee)))
return cb(new ClientError('Required argument missing'));
function(next) {
if (!Utils.checkRequired(opts, ['outputs']))
return next(new ClientError('Required argument missing'));
next();
},
function(next) {
// feePerKb is required unless inputs & fee are specified
if (!_.isNumber(opts.feePerKb) && !(opts.inputs && _.isNumber(opts.fee)))
return next(new ClientError('Required argument missing'));
if (_.isNumber(opts.feePerKb)) {
if (opts.feePerKb < Defaults.MIN_FEE_PER_KB || opts.feePerKb > Defaults.MAX_FEE_PER_KB)
return cb(new ClientError('Invalid fee per KB'));
}
if (_.isNumber(opts.feePerKb)) {
if (opts.feePerKb < Defaults.MIN_FEE_PER_KB || opts.feePerKb > Defaults.MAX_FEE_PER_KB)
return next(new ClientError('Invalid fee per KB'));
}
next();
},
function(next) {
if (!opts.sendMax) return next();
if (!_.isArray(opts.outputs) || opts.outputs.length > 1) {
return next(new ClientError('Only one output allowed when sendMax is specified'));
}
if (_.isNumber(opts.outputs[0].amount))
return next(new ClientError('Amount is not allowed when sendMax is specified'));
if (_.isNumber(opts.fee))
return next(new ClientError('Fee is not allowed when sendMax is specified (use feePerKb instead)'));
self.getSendMaxInfo({
feePerKb: opts.feePerKb || Defaults.DEFAULT_FEE_PER_KB,
excludeUnconfirmedUtxos: !!opts.excludeUnconfirmedUtxos,
returnInputs: true,
}, function(err, info) {
if (err) return next(err);
opts.outputs[0].amount = info.amount;
opts.inputs = info.inputs;
return next();
});
},
function(next) {
if (opts.validateOutputs === false) return next();
var validationError = self._validateOutputs(opts, wallet);
if (validationError) {
return next(validationError);
}
next();
},
], cb);
};
/**
* Creates a new transaction proposal.
* @param {Object} opts
* @param {Array} opts.outputs - List of outputs.
* @param {string} opts.outputs[].toAddress - Destination address.
* @param {number} opts.outputs[].amount - Amount to transfer in satoshi.
* @param {string} opts.outputs[].message - A message to attach to this output.
* @param {string} opts.message - A message to attach to this transaction.
* @param {Array} opts.inputs - Optional. Inputs for this TX
* @param {string} opts.fee - Optional. Use an alternative fee for this TX (mutually exclusive with feePerKb)
* @param {string} opts.feePerKb - Optional. Use an alternative fee per KB for this TX (mutually exclusive with fee)
* @param {string} opts.sendMax - Optional. Send maximum amount of funds that make sense under the specified fee/feePerKb conditions. (defaults to false).
* @param {string} opts.payProUrl - Optional. Paypro URL for peers to verify TX
* @param {string} opts.excludeUnconfirmedUtxos[=false] - Optional. Do not use UTXOs of unconfirmed transactions as inputs
* @param {string} opts.validateOutputs[=true] - Optional. Perform validation on outputs.
* @returns {TxProposal} Transaction proposal.
*/
WalletService.prototype.createTx = function(opts, cb) {
var self = this;
self._runLocked(cb, function(cb) {
@ -1813,17 +1872,13 @@ WalletService.prototype._doCreateTx = function(opts, cb) {
next();
});
},
function(next) {
self._validateAndSanitizeTxOpts(wallet, opts, next);
},
function(next) {
self._canCreateTx(function(err, canCreate) {
if (err) return next(err);
if (!canCreate) return next(Errors.TX_CANNOT_CREATE);
if (opts.validateOutputs !== false) {
var validationError = self._validateOutputs(opts, wallet);
if (validationError) {
return next(validationError);
}
}
next();
});
},
@ -1869,53 +1924,6 @@ WalletService.prototype._doCreateTx = function(opts, cb) {
});
};
/**
* Creates a new transaction proposal.
* @param {Object} opts
* @param {Array} opts.outputs - List of outputs.
* @param {string} opts.outputs[].toAddress - Destination address.
* @param {number} opts.outputs[].amount - Amount to transfer in satoshi.
* @param {string} opts.outputs[].message - A message to attach to this output.
* @param {string} opts.message - A message to attach to this transaction.
* @param {Array} opts.inputs - Optional. Inputs for this TX
* @param {string} opts.fee - Optional. Use an alternative fee for this TX (mutually exclusive with feePerKb)
* @param {string} opts.feePerKb - Optional. Use an alternative fee per KB for this TX (mutually exclusive with fee)
* @param {string} opts.sendMax - Optional. Send maximum amount of funds that make sense under the specified fee/feePerKb conditions. (defaults to false).
* @param {string} opts.payProUrl - Optional. Paypro URL for peers to verify TX
* @param {string} opts.excludeUnconfirmedUtxos[=false] - Optional. Do not use UTXOs of unconfirmed transactions as inputs
* @param {string} opts.validateOutputs[=true] - Optional. Perform validation on outputs.
* @returns {TxProposal} Transaction proposal.
*/
WalletService.prototype.createTx = function(opts, cb) {
var self = this;
opts = opts || [];
async.series([
function(next) {
if (!opts.sendMax) return next();
if (!_.isArray(opts.outputs) || opts.outputs.length > 1) {
return next(new ClientError('Only one output allowed when sendMax is specified'));
}
if (_.isNumber(opts.outputs[0].amount))
return next(new ClientError('Amount is not allowed when sendMax is specified'));
if (_.isNumber(opts.fee))
return next(new ClientError('Fee is not allowed when sendMax is specified (use feePerKb instead)'));
self.getSendMaxInfo(opts, function(err, info) {
if (err) return next(err);
opts.outputs[0].amount = info.amount;
opts.inputs = info.inputs;
return next();
});
},
], function(err) {
if (err) return cb(err);
self._doCreateTx(opts, cb);
});
};
WalletService.prototype._verifyRequestPubKey = function(requestPubKey, signature, xPubKey) {
var pub = (new Bitcore.HDPublicKey(xPubKey)).derive(Constants.PATHS.REQUEST_KEY_AUTH).publicKey;
return Utils.verifyMessage(requestPubKey, signature, pub.toString());

View File

@ -3653,6 +3653,7 @@ describe('Wallet service', function() {
it('should be able to get send max info on empty wallet', function(done) {
server.getSendMaxInfo({
feePerKb: 10000,
returnInputs: true,
}, function(err, info) {
should.not.exist(err);
should.exist(info);
@ -3667,6 +3668,7 @@ describe('Wallet service', function() {
helpers.stubUtxos(server, wallet, [0.1, 0.2, 0.3, 0.4], function() {
server.getSendMaxInfo({
feePerKb: 10000,
returnInputs: true,
}, function(err, info) {
should.not.exist(err);
should.exist(info);
@ -3683,6 +3685,7 @@ describe('Wallet service', function() {
server.getSendMaxInfo({
feePerKb: 10000,
excludeUnconfirmedUtxos: true,
returnInputs: true,
}, function(err, info) {
should.not.exist(err);
should.exist(info);
@ -3707,6 +3710,7 @@ describe('Wallet service', function() {
server.getSendMaxInfo({
feePerKb: 10000,
excludeUnconfirmedUtxos: true,
returnInputs: true,
}, function(err, info) {
should.not.exist(err);
should.exist(info);
@ -3723,6 +3727,7 @@ describe('Wallet service', function() {
helpers.stubUtxos(server, wallet, ['u0.1', 0.2, 0.3, 0.4, 0.000001, 0.0002, 0.0003], function() {
server.getSendMaxInfo({
feePerKb: 0.001e8,
returnInputs: true,
}, function(err, info) {
should.not.exist(err);
should.exist(info);
@ -3732,6 +3737,7 @@ describe('Wallet service', function() {
info.amount.should.equal(1e8 - info.fee);
server.getSendMaxInfo({
feePerKb: 0.0001e8,
returnInputs: true,
}, function(err, info) {
should.not.exist(err);
should.exist(info);
@ -3750,6 +3756,7 @@ describe('Wallet service', function() {
helpers.stubUtxos(server, wallet, _.range(1, 10, 0), function() {
server.getSendMaxInfo({
feePerKb: 10000,
returnInputs: true,
}, function(err, info) {
should.not.exist(err);
should.exist(info);