diff --git a/lib/common/defaults.js b/lib/common/defaults.js index d21c079..362363b 100644 --- a/lib/common/defaults.js +++ b/lib/common/defaults.js @@ -2,7 +2,6 @@ var Defaults = {}; -Defaults.DEFAULT_FEE_PER_KB = 10000; Defaults.MIN_FEE_PER_KB = 0; Defaults.MAX_FEE_PER_KB = 1000000; Defaults.MIN_TX_FEE = 0; @@ -39,6 +38,8 @@ Defaults.FEE_LEVELS = [{ defaultValue: 25000 }]; +Defaults.DEFAULT_FEE_PER_KB = Defaults.FEE_LEVELS[1].defaultValue; + // Minimum nb of addresses a wallet must have to start using 2-step balance optimization Defaults.TWO_STEP_BALANCE_THRESHOLD = 100; diff --git a/lib/model/txproposal_legacy.js b/lib/model/txproposal_legacy.js index 09952ec..a2af008 100644 --- a/lib/model/txproposal_legacy.js +++ b/lib/model/txproposal_legacy.js @@ -133,8 +133,8 @@ TxProposal.fromObj = function(obj) { return TxProposalAction.fromObj(action); }); x.outputOrder = obj.outputOrder; - x.fee = obj.fee; x.network = obj.network; + x.fee = obj.fee; x.feePerKb = obj.feePerKb; x.excludeUnconfirmedUtxos = obj.excludeUnconfirmedUtxos; x.proposalSignaturePubKey = obj.proposalSignaturePubKey; diff --git a/lib/server.js b/lib/server.js index b72998e..d91f8d1 100644 --- a/lib/server.js +++ b/lib/server.js @@ -1542,7 +1542,7 @@ WalletService.prototype.createTxLegacy = function(opts, cb) { * @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 - Optional. Use an alternative fee per KB for this TX (mutually exclusive with fee) + * @param {string} opts.feePerKb - The fee per kB to use for this TX. * @param {string} opts.feeLevel - Optional. Specify the fee level used to compute feePerKb for this txp. * @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 @@ -1552,10 +1552,9 @@ WalletService.prototype.createTxLegacy = function(opts, cb) { WalletService.prototype.createTx = function(opts, cb) { var self = this; - if (!Utils.checkRequired(opts, ['outputs'])) + if (!Utils.checkRequired(opts, ['outputs', 'feePerKb'])) return cb(new ClientError('Required argument missing')); - opts.feePerKb = opts.feePerKb || Defaults.DEFAULT_FEE_PER_KB; if (opts.feePerKb < Defaults.MIN_FEE_PER_KB || opts.feePerKb > Defaults.MAX_FEE_PER_KB) return cb(new ClientError('Invalid fee per KB')); diff --git a/test/integration/server.js b/test/integration/server.js index 5bca205..15d2f57 100644 --- a/test/integration/server.js +++ b/test/integration/server.js @@ -2038,10 +2038,26 @@ describe('Wallet service', function() { }); }); + it('should assume default feePerKb for "normal" level when none is specified', function(done) { + helpers.stubUtxos(server, wallet, [100, 200], function() { + var txOpts = helpers.createProposalOptsLegacy('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 80, 'some message', TestData.copayers[0].privKey_1H_0); + server.createTxLegacy(txOpts, function(err, tx) { + should.not.exist(err); + should.exist(tx); + tx.feePerKb.should.equal(_.find(Defaults.FEE_LEVELS, { + name: 'normal' + }).defaultValue); + done(); + }); + }); + }); + it('should support creating a tx with no change address', function(done) { helpers.stubUtxos(server, wallet, [1, 2], function() { var max = 3 - (7200 / 1e8); // Fees for this tx at 100bits/kB = 7200 sat - var txOpts = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', max, TestData.copayers[0].privKey_1H_0); + var txOpts = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', max, TestData.copayers[0].privKey_1H_0, { + feePerKb: 100e2 + }); server.createTxLegacy(txOpts, function(err, txp) { should.not.exist(err); should.exist(txp); @@ -2360,7 +2376,9 @@ describe('Wallet service', function() { var fee = 4100 / 1e8; // The exact fee of the resulting tx var amount = 1 - fee; - var txOpts = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', amount, TestData.copayers[0].privKey_1H_0); + var txOpts = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', amount, TestData.copayers[0].privKey_1H_0, { + feePerKb: 100e2 + }); server.createTxLegacy(txOpts, function(err, tx) { should.not.exist(err); should.exist(tx); @@ -2507,7 +2525,8 @@ describe('Wallet service', function() { message: 'message #2' }]; var txOpts = helpers.createProposalOpts(Model.TxProposalLegacy.Types.MULTIPLEOUTPUTS, outputs, TestData.copayers[0].privKey_1H_0, { - message: 'some message' + message: 'some message', + feePerKb: 100e2, }); server.createTxLegacy(txOpts, function(err, txp) { should.not.exist(err); @@ -2587,7 +2606,9 @@ describe('Wallet service', function() { balance.totalBytesToSendConfirmedMax.should.equal(2896); var fee = parseInt((balance.totalBytesToSendMax * 10000 / 1000).toFixed(0)); var max = balance.availableAmount - fee; - var txOpts = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', max / 1e8, TestData.copayers[0].privKey_1H_0); + var txOpts = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', max / 1e8, TestData.copayers[0].privKey_1H_0, { + feePerKb: 100e2, + }); server.createTxLegacy(txOpts, function(err, tx) { should.not.exist(err); should.exist(tx); @@ -2652,7 +2673,9 @@ describe('Wallet service', function() { balance.totalBytesToSendConfirmedMax.should.equal(720); var fee = parseInt((balance.totalBytesToSendConfirmedMax * 10000 / 1000).toFixed(0)); var max = balance.availableConfirmedAmount - fee; - var txOpts = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', max / 1e8, TestData.copayers[0].privKey_1H_0); + var txOpts = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', max / 1e8, TestData.copayers[0].privKey_1H_0, { + feePerKb: 100e2, + }); server.createTxLegacy(txOpts, function(err, tx) { should.not.exist(err); should.exist(tx); @@ -2718,6 +2741,7 @@ describe('Wallet service', function() { }], message: 'some message', customData: 'some custom data', + feePerKb: 123e2, feeLevel: 'priority', }; server.createTx(txOpts, function(err, tx) { @@ -2732,7 +2756,7 @@ describe('Wallet service', function() { tx.isPending().should.equal.true; tx.isTemporary().should.equal.true; tx.amount.should.equal(helpers.toSatoshi(0.8)); - tx.feeLevel.should.equal('priority'); + tx.feePerKb.should.equal(123e2); server.getPendingTxs({}, function(err, txs) { should.not.exist(err); txs.should.be.empty; @@ -2749,6 +2773,7 @@ describe('Wallet service', function() { toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', amount: 0.8 * 1e8, }], + feePerKb: 100e2, message: 'some message', customData: 'some custom data', }; @@ -2776,6 +2801,7 @@ describe('Wallet service', function() { toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', amount: 0.8 * 1e8, }], + feePerKb: 100e2, message: 'some message', }; server.createTx(txOpts, function(err, txp) { @@ -2819,6 +2845,7 @@ describe('Wallet service', function() { toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', amount: 0.8 * 1e8, }], + feePerKb: 100e2, message: 'some message', }; server.createTx(txOpts, function(err, txp) { @@ -2843,6 +2870,7 @@ describe('Wallet service', function() { toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', amount: 0.8 * 1e8, }], + feePerKb: 100e2, message: 'some message', }; server.createTx(txOpts, function(err, txp) { @@ -2885,6 +2913,7 @@ describe('Wallet service', function() { amount: 0.8 * 1e8, }], message: 'some message', + feePerKb: 100e2, }; server.createTx(txOpts, function(err, txp) { should.not.exist(err); @@ -2920,6 +2949,7 @@ describe('Wallet service', function() { amount: 0.8 * 1e8, }], message: 'some message', + feePerKb: 100e2, }; async.waterfall([ @@ -2989,6 +3019,7 @@ describe('Wallet service', function() { }], message: 'some message', customData: 'some custom data', + feePerKb: 100e2, }; server.createTx(txOpts, function(err, txp) { should.not.exist(err); @@ -3655,6 +3686,7 @@ describe('Wallet service', function() { amount: 9e8, }], message: 'some message', + feePerKb: 100e2, }; helpers.createAndPublishTx(server, txOpts, TestData.copayers[0].privKey_1H_0, function(txp) { should.exist(txp);