@bitcoinerlab/coinselect
Version:
A TypeScript library for Bitcoin transaction management, based on Bitcoin Descriptors for defining inputs and outputs. It facilitates optimal UTXO selection and transaction size calculation.
59 lines (58 loc) • 2.94 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.maxFunds = void 0;
const index_1 = require("../index");
const validation_1 = require("../validation");
const vsize_1 = require("../vsize");
const dust_1 = require("../dust");
/**
* The `maxFunds` algorithm is tailored for scenarios where the goal is to transfer all funds from specified UTXOs to a single recipient output.
* To utilize this function, specify the recipient output in the `remainder` argument.
* In this context, the `remainder` serves as the recipient of the funds.
*
* Notes:
*
* - This function does not reorder UTXOs prior to selection.
* - UTXOs that do not provide enough value to cover their respective fee contributions are automatically excluded.
* - Recipient of all funds is set to last position of the returned `targets` array.
*
* Refer to {@link coinselect coinselect} for additional details on input parameters and expected returned values.
*/
function maxFunds({ utxos, targets, remainder, feeRate, dustRelayFeeRate = index_1.DUST_RELAY_FEE_RATE }) {
(0, validation_1.validateOutputWithValues)(utxos);
if (targets.length)
(0, validation_1.validateOutputWithValues)(targets);
(0, validation_1.validateDust)(targets);
(0, validation_1.validateFeeRate)(feeRate);
(0, validation_1.validateFeeRate)(dustRelayFeeRate);
const outputs = [...targets.map(target => target.output), remainder];
const targetsValue = targets.reduce((a, target) => a + target.value, 0);
const allUtxosFee = Math.ceil(feeRate *
(0, vsize_1.vsize)(utxos.map(utxo => utxo.output), outputs));
// Only consider inputs with more value than the fee they require
const validUtxos = utxos.filter(validUtxo => {
const txSizeWithoutUtxo = (0, vsize_1.vsize)(utxos.filter(utxo => utxo !== validUtxo).map(utxo => utxo.output), outputs);
const feeContribution = allUtxosFee - Math.ceil(feeRate * txSizeWithoutUtxo);
if (feeContribution < 0)
throw new Error(`feeContribution < 0`);
return validUtxo.value > feeContribution;
});
const validFee = Math.ceil(feeRate *
(0, vsize_1.vsize)(validUtxos.map(utxo => utxo.output), outputs));
const validUtxosValue = validUtxos.reduce((a, utxo) => a + utxo.value, 0);
const remainderValue = validUtxosValue - targetsValue - validFee;
if (!(0, dust_1.isDust)(remainder, remainderValue, dustRelayFeeRate)) {
//return the same reference if nothing changed to interact nicely with
//reactive components
//mutate targets:
targets = [...targets, { output: remainder, value: remainderValue }];
return {
utxos: utxos.length === validUtxos.length ? utxos : validUtxos,
targets,
...(0, validation_1.validatedFeeAndVsize)(validUtxos, targets, feeRate)
};
}
else
return;
}
exports.maxFunds = maxFunds;