Browse Source

allow absolute fee when specifying inputs

activeAddress
Ivan Socolsky 9 years ago
parent
commit
ee7d3bad7f
  1. 6
      lib/model/txproposal.js
  2. 27
      lib/server.js
  3. 1
      test/integration/helpers.js
  4. 24
      test/integration/server.js

6
lib/model/txproposal.js

@ -33,7 +33,6 @@ TxProposal.create = function(opts) {
x.message = opts.message;
x.payProUrl = opts.payProUrl;
x.changeAddress = opts.changeAddress;
x.setInputs(opts.inputs);
x.outputs = _.map(opts.outputs, function(output) {
return _.pick(output, ['amount', 'toAddress', 'message']);
});
@ -44,7 +43,6 @@ TxProposal.create = function(opts) {
x.requiredRejections = Math.min(x.walletM, x.walletN - x.walletM + 1),
x.status = 'temporary';
x.actions = [];
x.fee = null;
x.feePerKb = opts.feePerKb;
x.excludeUnconfirmedUtxos = opts.excludeUnconfirmedUtxos;
@ -59,6 +57,9 @@ TxProposal.create = function(opts) {
} catch (ex) {}
$.checkState(_.contains(_.values(Constants.NETWORKS), x.network));
x.setInputs(opts.inputs);
x.fee = opts.fee;
return x;
};
@ -137,6 +138,7 @@ TxProposal.prototype._buildTx = function() {
switch (self.addressType) {
case Constants.SCRIPT_TYPES.P2SH:
_.each(self.inputs, function(i) {
$.checkState(i.publicKeys, 'Inputs should include public keys');
t.from(i, i.publicKeys, self.requiredSignatures);
});
break;

27
lib/server.js

@ -1270,9 +1270,10 @@ WalletService.prototype._checkTx = 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) {
self._estimateFee(txp);
//todo: check inputs are ours and have enough value
if (txp.inputs && !_.isEmpty(txp.inputs)) {
if (!_.isNumber(txp.fee))
self._estimateFee(txp);
return cb(self._checkTx(txp));
}
@ -1725,21 +1726,28 @@ WalletService.prototype.createTxLegacy = function(opts, cb) {
* @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.feePerKb - The fee per kB to use for this TX.
* @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) {
var self = this;
if (!Utils.checkRequired(opts, ['outputs', 'feePerKb']))
if (!Utils.checkRequired(opts, ['outputs']))
return cb(new ClientError('Required argument missing'));
if (opts.feePerKb < Defaults.MIN_FEE_PER_KB || opts.feePerKb > Defaults.MAX_FEE_PER_KB)
return cb(new ClientError('Invalid fee per KB'));
// feePerKb is required unless inputs & fee are specified
if (!_.isNumber(opts.feePerKb) && !(opts.inputs && _.isNumber(opts.fee)))
return cb(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'));
}
self._runLocked(cb, function(cb) {
self.getWallet({}, function(err, wallet) {
@ -1760,7 +1768,6 @@ WalletService.prototype.createTx = function(opts, cb) {
var txOpts = {
walletId: self.walletId,
creatorId: self.copayerId,
inputs: opts.inputs,
outputs: opts.outputs,
message: opts.message,
changeAddress: wallet.createAddress(true),
@ -1772,6 +1779,8 @@ WalletService.prototype.createTx = function(opts, cb) {
validateOutputs: !opts.validateOutputs,
addressType: wallet.addressType,
customData: opts.customData,
inputs: opts.inputs,
fee: opts.inputs && !_.isNumber(opts.feePerKb) ? opts.fee : null,
};
var txp = Model.TxProposal.create(txOpts);

1
test/integration/helpers.js

@ -291,6 +291,7 @@ helpers.stubUtxos = function(server, wallet, amounts, opts, cb) {
scriptPubKey: scriptPubKey.toBuffer().toString('hex'),
address: address.address,
confirmations: parsed.confirmations,
publicKeys: address.publicKeys,
};
}));

24
test/integration/server.js

@ -3089,6 +3089,30 @@ describe('Wallet service', function() {
});
});
});
it('should be able to specify inputs & absolute fee', function(done) {
helpers.stubUtxos(server, wallet, [1, 2], function(utxos) {
var txOpts = {
outputs: [{
toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7',
amount: 0.8e8,
}],
inputs: utxos,
fee: 1000e2,
};
server.createTx(txOpts, function(err, tx) {
should.not.exist(err);
should.exist(tx);
tx.amount.should.equal(helpers.toSatoshi(0.8));
should.not.exist(tx.feePerKb);
tx.fee.should.equal(1000e2);
var t = tx.getBitcoreTx();
t.getFee().should.equal(1000e2);
t.getChangeOutput().satoshis.should.equal(3e8 - 0.8e8 - 1000e2);
done();
});
});
});
});
describe('Backoff time', function(done) {

Loading…
Cancel
Save