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.

92 lines (91 loc) 3.94 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.dustThreshold = dustThreshold; exports.isDust = isDust; const index_1 = require("./index"); /** * Coin selection algorithms in this library throw errors for targets below the * dustThreshold to prevent creation of transactions that Bitcoin nodes may not * relay. Ensure your targets are equal or above dust with this function. * * The default `DUST_RELAY_FEE_RATE` matches Bitcoin Core's. Changing it isn't * recommended. * * "Dust" is defined in terms of `dustRelayFee`, measured in satoshis-per-byte * (it differs from Bitcoin Core's measurement in satoshis-per-kilobyte). * If you'd pay more in fees than the value of the output to spend something, * then we consider it dust. * * Examples: A typical spendable non-segwit output is 34 bytes big, and will * need an input of at least 148 bytes to spend: * `TX_INPUT_BASE + TX_INPUT_PUBKEYHASH = (32 + 4 + 1 + 4) + 107 = 148` * so dust is a spendable output less than * `(34 + 148) * dustRelayFeeRate = 182 * dustRelayFee` (in satoshis). * 546 satoshis at the default `DUST_RELAY_FEE_RATE` of 3 sat/vB. * * A typical spendable segwit P2WPKH output is 31 bytes big, and will * need an input of at least 67.75 bytes to spend, 68, rounded up: * so dust is a spendable output less than * `98 * dustRelayFee` (in satoshis). * 297 satoshis at the default `DUST_RELAY_FEE_RATE` of 3 sat/vB. * * Note: Bitcoin Core contains a rounding error (rounds down instead of up) that * generates an incorrect dust threshold for Segwit (294). See: * https://github.com/lightningnetwork/lnd/issues/3946#issuecomment-890222512. * * We rather return the correct value (rounding up) which, in fact, is safer * should Bitcoin Core fix the problem in the future. * * See Bitcoin Core implementation here: * https://github.com/bitcoin/bitcoin/blob/d752349029ec7a76f1fd440db2ec2e458d0f3c99/src/policy/policy.cpp#L26 */ function dustThreshold( /** * The `Output` instance for which the dust threshold is computed */ output, /** * Fee rate (in sats/byte) used to define dust, the value of an output such * that it will cost more than its value in fees at this fee rate to * spend it. * @defaultValue `DUST_RELAY_FEE_RATE `= `3` */ dustRelayFeeRate = index_1.DUST_RELAY_FEE_RATE) { const isSegwitOutput = output.isSegwit(); if (isSegwitOutput === undefined) throw new Error(`Unknown output type`); // When sending to scripts (such as TR, SH, or WSH) using an addr() descriptor, // the actual input weight may be unknown because the unlocking script isn’t provided. // In such cases, we fall back to a conservative estimate based on a typical P2WPKH input. // Bitcoin Core Wallet does similar stuff... // // The fallback is derived as follows: // - Non-witness part: // • txid: 32 bytes // • vout: 4 bytes // • sequence: 4 bytes // • script length: 1 byte // Total non-witness bytes = 41 bytes → 41 * 4 = 164 weight units. // - Witness part (for P2WPKH): // • push count: 1 byte // • signature: 73 bytes // • public key: 34 bytes // Total witness bytes = 108 weight units. // Combined total input weight = 164 + 108 = 272 weight units. let inputWeight; try { //this may throw. F.ex. if the output is a wsh and the miniscript was //not provided. inputWeight = output.inputWeight(isSegwitOutput, 'DANGEROUSLY_USE_FAKE_SIGNATURES'); } catch (err) { void err; inputWeight = 272; } return BigInt(Math.ceil(dustRelayFeeRate * Math.ceil((output.outputWeight() + inputWeight) / 4))); } function isDust(output, value, dustRelayFeeRate = index_1.DUST_RELAY_FEE_RATE) { if (typeof value !== 'bigint') throw new Error(`Invalid value ${value}`); return value < dustThreshold(output, dustRelayFeeRate); }