sendMax option on createTx

This commit is contained in:
Ivan Socolsky 2016-02-25 11:27:30 -03:00
parent 755449e32d
commit bdff2cbc35
3 changed files with 76 additions and 26 deletions

View File

@ -164,7 +164,7 @@ TxProposal.prototype._buildTx = function() {
var totalInputs = _.sum(self.inputs, 'satoshis');
var totalOutputs = _.sum(self.outputs, 'satoshis');
if (totalInputs - totalOutputs - self.fee > 0) {
if (totalInputs - totalOutputs - self.fee > 0 && self.changeAddress) {
t.change(self.changeAddress.address);
}

View File

@ -1152,7 +1152,7 @@ WalletService.prototype.getBalance = function(opts, cb) {
* Return info needed to send all funds in the wallet
* @param {Object} opts
* @param {string} opts.feePerKb - The fee per KB used to compute the TX.
* @param {string} opts.excludeUnconfirmedUtxos - Exclude unconfirmed UTXOs from calculation.
* @param {string} opts.excludeUnconfirmedUtxos[=false] - Optional. Do not use UTXOs of unconfirmed transactions as inputs
* @returns {Object} sendMaxInfo
*/
WalletService.prototype.getSendMaxInfo = function(opts, cb) {
@ -1161,7 +1161,7 @@ WalletService.prototype.getSendMaxInfo = function(opts, cb) {
opts = opts || {};
if (!Utils.checkRequired(opts, ['feePerKb', 'excludeUnconfirmedUtxos']))
if (!Utils.checkRequired(opts, ['feePerKb']))
return cb(new ClientError('Required argument missing'));
self.getWallet({}, function(err, wallet) {
@ -1179,7 +1179,7 @@ WalletService.prototype.getSendMaxInfo = function(opts, cb) {
};
var inputs = _.reject(utxos, 'locked');
if (opts.excludeUnconfirmedUtxos) {
if (!!opts.excludeUnconfirmedUtxos) {
inputs = _.filter(inputs, 'confirmations');
}
inputs = _.sortBy(inputs, 'satoshis');
@ -1628,12 +1628,14 @@ WalletService.prototype._validateOutputs = function(opts, wallet) {
if (toAddress.network != wallet.getNetworkName()) {
return Errors.INCORRECT_ADDRESS_NETWORK;
}
if (!_.isNumber(output.amount) || _.isNaN(output.amount) || output.amount <= 0) {
return new ClientError('Invalid amount');
}
if (output.amount < Bitcore.Transaction.DUST_AMOUNT) {
return Errors.DUST_AMOUNT;
}
output.valid = true;
}
return null;
@ -1785,23 +1787,7 @@ WalletService.prototype.createTxLegacy = 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 {number} opts.feePerKb - The fee per kB to use for this TX.
* @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.
* @param {Array} opts.inputs - Optional. Inputs for this TX
* @param {number} opts.fee - Optional. The fee to use for this TX (used only when opts.inputs is specified).
* @returns {TxProposal} Transaction proposal.
*/
WalletService.prototype.createTx = function(opts, cb) {
WalletService.prototype._doCreateTx = function(opts, cb) {
var self = this;
if (!Utils.checkRequired(opts, ['outputs']))
@ -1869,6 +1855,48 @@ WalletService.prototype.createTx = 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'));
}
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

@ -3113,6 +3113,33 @@ describe('Wallet service', function() {
});
});
});
it.only('should be able to send max funds', function(done) {
helpers.stubUtxos(server, wallet, [1, 2], function() {
var txOpts = {
outputs: [{
toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7',
amount: null,
}],
feePerKb: 10000,
sendMax: true,
};
server.createTx(txOpts, function(err, tx) {
should.not.exist(err);
should.exist(tx);
// should.not.exist(tx.changeAddress);
tx.amount.should.equal(3e8 - tx.fee);
var t = tx.getBitcoreTx();
t.getFee().should.equal(tx.fee);
should.not.exist(t.getChangeOutput());
t.toObject().inputs.length.should.equal(tx.inputs.length);
t.toObject().outputs[0].satoshis.should.equal(tx.amount);
done();
});
});
});
});
describe('Backoff time', function(done) {
@ -3626,7 +3653,6 @@ describe('Wallet service', function() {
it('should be able to get send max info on empty wallet', function(done) {
server.getSendMaxInfo({
feePerKb: 10000,
excludeUnconfirmedUtxos: false,
}, function(err, info) {
should.not.exist(err);
should.exist(info);
@ -3641,7 +3667,6 @@ describe('Wallet service', function() {
helpers.stubUtxos(server, wallet, [0.1, 0.2, 0.3, 0.4], function() {
server.getSendMaxInfo({
feePerKb: 10000,
excludeUnconfirmedUtxos: false,
}, function(err, info) {
should.not.exist(err);
should.exist(info);
@ -3698,7 +3723,6 @@ 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,
excludeUnconfirmedUtxos: false,
}, function(err, info) {
should.not.exist(err);
should.exist(info);
@ -3708,7 +3732,6 @@ describe('Wallet service', function() {
info.amount.should.equal(1e8 - info.fee);
server.getSendMaxInfo({
feePerKb: 0.0001e8,
excludeUnconfirmedUtxos: false,
}, function(err, info) {
should.not.exist(err);
should.exist(info);
@ -3727,7 +3750,6 @@ describe('Wallet service', function() {
helpers.stubUtxos(server, wallet, _.range(1, 10, 0), function() {
server.getSendMaxInfo({
feePerKb: 10000,
excludeUnconfirmedUtxos: false,
}, function(err, info) {
should.not.exist(err);
should.exist(info);