UNPKG

@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) 2.63 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.validateOutputWithValues = validateOutputWithValues; exports.validateFeeRate = validateFeeRate; exports.validateDust = validateDust; exports.validatedFeeAndVsize = validatedFeeAndVsize; const index_1 = require("./index"); const vsize_1 = require("./vsize"); const dust_1 = require("./dust"); function validateOutputWithValues(outputAndValues) { if (outputAndValues.length === 0) throw new Error('Empty group'); for (const outputAndValue of outputAndValues) { const value = outputAndValue.value; //note an utxo with value === 0 is possible, see https://blockstream.info/testnet/tx/a063dbdc23cf969df020536f75c431167a2bbf29d6215a2067495ac46991c954 if (typeof value !== 'bigint' || value < 0n || value > 100000000000000n /*1 M Btc*/) { throw new Error(`Input value ${value} not supported`); } } } function validateFeeRate(feeRate, minimumFeeRate = index_1.MIN_FEE_RATE) { validateMinimumFeeRate(minimumFeeRate); if (!Number.isFinite(feeRate) || feeRate < minimumFeeRate || feeRate > index_1.MAX_FEE_RATE) { throw new Error(`Fee rate ${feeRate} not supported`); } } function validateMinimumFeeRate(minimumFeeRate) { if (!Number.isFinite(minimumFeeRate) || minimumFeeRate < 0 || minimumFeeRate > index_1.MAX_FEE_RATE) { throw new Error(`Minimum fee rate ${minimumFeeRate} not supported`); } } function validateDust(targets, dustRelayFeeRate = index_1.DUST_RELAY_FEE_RATE) { for (const [index, target] of Object.entries(targets)) if ((0, dust_1.isDust)(target.output, target.value, dustRelayFeeRate)) throw new Error(`Target #${index} is dusty`); } function validatedFeeAndVsize(utxos, targets, feeRate, minimumFeeRate = index_1.MIN_FEE_RATE) { const fee = utxos.reduce((a, u) => a + u.value, 0n) - targets.reduce((a, t) => a + t.value, 0n); const vsizeResult = (0, vsize_1.vsize)(utxos.map(u => u.output), targets.map(t => t.output)); const requiredFee = BigInt(Math.ceil(vsizeResult * feeRate)); const finalFeeRate = Number(fee) / vsizeResult; // Don't compare fee rates because values are picked based on comparing fees (multiplications) // Don't mix * / operators: // F.ex.: 100/27 !== 100*(1/27) // Instead, compare final fee if (fee < requiredFee) throw new Error(`Final fee ${fee} lower than required ${requiredFee}`); validateFeeRate(finalFeeRate, minimumFeeRate); return { fee, vsize: vsizeResult }; }