@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.
58 lines (57 loc) • 3.01 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.maxFunds = maxFunds;
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, minimumFeeRate = index_1.MIN_FEE_RATE, 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, minimumFeeRate);
(0, validation_1.validateFeeRate)(dustRelayFeeRate);
const outputs = [...targets.map(target => target.output), remainder];
const targetsValue = targets.reduce((a, target) => a + target.value, 0n);
const allUtxosFee = BigInt(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 - BigInt(Math.ceil(feeRate * txSizeWithoutUtxo));
if (feeContribution < 0n)
throw new Error(`feeContribution < 0`);
return validUtxo.value > feeContribution;
});
const validFee = BigInt(Math.ceil(feeRate *
(0, vsize_1.vsize)(validUtxos.map(utxo => utxo.output), outputs)));
const validUtxosValue = validUtxos.reduce((a, utxo) => a + utxo.value, 0n);
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, minimumFeeRate)
};
}
else
return;
}