diff --git a/lib/primitives/mtx.js b/lib/primitives/mtx.js index 6dfe8a464..fccc29aef 100644 --- a/lib/primitives/mtx.js +++ b/lib/primitives/mtx.js @@ -1222,42 +1222,28 @@ MTX.prototype.selectCoins = function selectCoins(coins, options) { return selector.select(coins); }; -/** - * Attempt to subtract a fee from a single output. - * @param {Number} index - * @param {Amount} fee - */ - -MTX.prototype.subtractIndex = function subtractIndex(index, fee) { - assert(typeof index === 'number'); - assert(typeof fee === 'number'); - - const output = this.outputs[index]; - - if (!output) - throw new Error('Subtraction index does not exist.'); - - if (output.value < fee + output.getDustThreshold()) - throw new Error('Could not subtract fee.'); - - output.value -= fee; -}; - /** * Attempt to subtract a fee from all outputs evenly. * @param {Amount} fee + * @param {Set|null} set */ -MTX.prototype.subtractFee = function subtractFee(fee) { +MTX.prototype.subtractFee = function subtractFee(fee, set) { assert(typeof fee === 'number'); let outputs = 0; - for (const output of this.outputs) { + for (let i = 0; i < this.outputs.length; i++) { + const output = this.outputs[i]; + + if (set && !set.has(i)) + continue; + // Ignore nulldatas and // other OP_RETURN scripts. if (output.script.isUnspendable()) continue; + outputs += 1; } @@ -1268,7 +1254,12 @@ MTX.prototype.subtractFee = function subtractFee(fee) { const share = (fee - left) / outputs; // First pass, remove even shares. - for (const output of this.outputs) { + for (let i = 0; i < this.outputs.length; i++) { + const output = this.outputs[i]; + + if (set && !set.has(i)) + continue; + if (output.script.isUnspendable()) continue; @@ -1280,7 +1271,12 @@ MTX.prototype.subtractFee = function subtractFee(fee) { // Second pass, remove the remainder // for the one unlucky output. - for (const output of this.outputs) { + for (let i = 0; i < this.outputs.length; i++) { + const output = this.outputs[i]; + + if (set && !set.has(i)) + continue; + if (output.script.isUnspendable()) continue; @@ -1313,13 +1309,8 @@ MTX.prototype.fund = async function fund(coins, options) { this.addCoin(coin); // Attempt to subtract fee. - if (select.subtractFee) { - const index = select.subtractIndex; - if (index !== -1) - this.subtractIndex(index, select.fee); - else - this.subtractFee(select.fee); - } + if (select.subtractFee) + this.subtractFee(select.fee, select.subtractIndex); // Add a change output. const output = new Output(); @@ -1554,7 +1545,7 @@ function CoinSelector(tx, options) { this.selection = 'value'; this.subtractFee = false; - this.subtractIndex = -1; + this.subtractIndex = null; this.height = -1; this.depth = -1; this.hardFee = -1; @@ -1610,22 +1601,32 @@ CoinSelector.prototype.fromOptions = function fromOptions(options) { } if (options.subtractFee != null) { - if (typeof options.subtractFee === 'number') { - assert(util.isInt(options.subtractFee)); - assert(options.subtractFee >= -1); - this.subtractIndex = options.subtractFee; - this.subtractFee = this.subtractIndex !== -1; - } else { - assert(typeof options.subtractFee === 'boolean'); - this.subtractFee = options.subtractFee; - } + assert(typeof options.subtractFee === 'boolean'); + this.subtractFee = options.subtractFee; } if (options.subtractIndex != null) { - assert(util.isInt(options.subtractIndex)); - assert(options.subtractIndex >= -1); - this.subtractIndex = options.subtractIndex; - this.subtractFee = this.subtractIndex !== -1; + let indicies = null; + + if (typeof options.subtractIndex === 'number') { + indicies = [options.subtractIndex]; + } else { + assert(Array.isArray(options.subtractIndex)); + indicies = options.subtractIndex; + } + + if (indicies.length > 0) { + const set = new Set(); + + for (const index of indicies) { + assert(util.isU32(index)); + assert(index < this.tx.outputs.length); + set.add(index); + } + + this.subtractIndex = set; + this.subtractFee = true; + } } if (options.height != null) { diff --git a/lib/wallet/http.js b/lib/wallet/http.js index b70d2ee7d..5aedb8578 100644 --- a/lib/wallet/http.js +++ b/lib/wallet/http.js @@ -391,7 +391,7 @@ HTTPServer.prototype.initRouter = function initRouter() { selection: valid.str('selection'), smart: valid.bool('smart'), subtractFee: valid.bool('subtractFee'), - subtractIndex: valid.i32('subtractIndex'), + subtractIndex: valid.get('subtractIndex'), depth: valid.u32(['confirmations', 'depth']), outputs: [] }; @@ -431,7 +431,7 @@ HTTPServer.prototype.initRouter = function initRouter() { selection: valid.str('selection'), smart: valid.bool('smart'), subtractFee: valid.bool('subtractFee'), - subtractIndex: valid.i32('subtractIndex'), + subtractIndex: valid.get('subtractIndex'), depth: valid.u32(['confirmations', 'depth']), outputs: [] };