@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
JavaScript
;
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 };
}