@bitcoinerlab/coinselect
Advanced tools
Comparing version 1.0.0 to 1.1.0
@@ -1,2 +0,1 @@ | ||
/// <reference types="node" /> | ||
import type { OutputInstance } from '@bitcoinerlab/descriptors'; | ||
@@ -6,3 +5,3 @@ import { OutputWithValue } from '../index'; | ||
* 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, while omitting the `targets` parameter. | ||
* To utilize this function, specify the recipient output in the `remainder` argument. | ||
* In this context, the `remainder` serves as the recipient of the funds. | ||
@@ -14,7 +13,9 @@ * | ||
* - 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. | ||
*/ | ||
export declare function maxFunds({ utxos, remainder, feeRate, dustRelayFeeRate }: { | ||
export declare function maxFunds({ utxos, targets, remainder, feeRate, dustRelayFeeRate }: { | ||
utxos: Array<OutputWithValue>; | ||
targets: Array<OutputWithValue>; | ||
/** | ||
@@ -30,65 +31,3 @@ * Recipient to send maxFunds | ||
utxos: OutputWithValue[]; | ||
targets: { | ||
output: { | ||
readonly "__#1@#payment": import("bitcoinjs-lib").Payment; | ||
readonly "__#1@#preimages": import("@bitcoinerlab/descriptors/dist/types").Preimage[]; | ||
readonly "__#1@#signersPubKeys": Buffer[]; | ||
readonly "__#1@#miniscript"?: string; | ||
readonly "__#1@#witnessScript"?: Buffer; | ||
readonly "__#1@#redeemScript"?: Buffer; | ||
readonly "__#1@#isSegwit"?: boolean; | ||
readonly "__#1@#expandedExpression"?: string; | ||
readonly "__#1@#expandedMiniscript"?: string; | ||
readonly "__#1@#expansionMap"?: import("@bitcoinerlab/descriptors/dist/types").ExpansionMap; | ||
readonly "__#1@#network": import("bitcoinjs-lib").Network; | ||
"__#1@#getTimeConstraints"(): import("@bitcoinerlab/descriptors/dist/types").TimeConstraints | undefined; | ||
getPayment(): import("bitcoinjs-lib").Payment; | ||
getAddress(): string; | ||
getScriptPubKey(): Buffer; | ||
getScriptSatisfaction(signatures: import("bip174/src/lib/interfaces").PartialSig[] | "DANGEROUSLY_USE_FAKE_SIGNATURES"): Buffer; | ||
getSequence(): number | undefined; | ||
getLockTime(): number | undefined; | ||
getWitnessScript(): Buffer | undefined; | ||
getRedeemScript(): Buffer | undefined; | ||
getNetwork(): import("bitcoinjs-lib").Network; | ||
isSegwit(): boolean | undefined; | ||
updatePsbt(params: { | ||
psbt: import("bitcoinjs-lib").Psbt; | ||
txHex?: string; | ||
txId?: string; | ||
value?: number; | ||
vout: number; | ||
}): number; | ||
updatePsbtAsInput({ psbt, txHex, txId, value, vout }: { | ||
psbt: import("bitcoinjs-lib").Psbt; | ||
txHex?: string; | ||
txId?: string; | ||
value?: number; | ||
vout: number; | ||
}): ({ psbt, validate }: { | ||
psbt: import("bitcoinjs-lib").Psbt; | ||
validate?: boolean | undefined; | ||
}) => void; | ||
updatePsbtAsOutput({ psbt, value }: { | ||
psbt: import("bitcoinjs-lib").Psbt; | ||
value: number; | ||
}): void; | ||
"__#1@#assertPsbtInput"({ psbt, index }: { | ||
psbt: import("bitcoinjs-lib").Psbt; | ||
index: number; | ||
}): void; | ||
finalizePsbtInput({ index, psbt, validate }: { | ||
index: number; | ||
psbt: import("bitcoinjs-lib").Psbt; | ||
validate?: boolean | undefined; | ||
}): void; | ||
expand(): { | ||
expansionMap?: import("@bitcoinerlab/descriptors/dist/types").ExpansionMap; | ||
expandedMiniscript?: string; | ||
miniscript?: string; | ||
expandedExpression?: string; | ||
}; | ||
}; | ||
value: number; | ||
}[]; | ||
targets: OutputWithValue[]; | ||
} | undefined; |
@@ -10,3 +10,3 @@ "use strict"; | ||
* 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, while omitting the `targets` parameter. | ||
* To utilize this function, specify the recipient output in the `remainder` argument. | ||
* In this context, the `remainder` serves as the recipient of the funds. | ||
@@ -18,14 +18,18 @@ * | ||
* - 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, remainder, feeRate, dustRelayFeeRate = index_1.DUST_RELAY_FEE_RATE }) { | ||
function maxFunds({ utxos, targets, remainder, feeRate, dustRelayFeeRate = index_1.DUST_RELAY_FEE_RATE }) { | ||
(0, validation_1.validateOutputWithValues)(utxos); | ||
targets.length === 0 || (0, validation_1.validateOutputWithValues)(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), [remainder])); | ||
(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), [remainder]); | ||
const txSizeWithoutUtxo = (0, vsize_1.vsize)(utxos.filter(utxo => utxo !== validUtxo).map(utxo => utxo.output), outputs); | ||
const feeContribution = allUtxosFee - Math.ceil(feeRate * txSizeWithoutUtxo); | ||
@@ -37,9 +41,10 @@ if (feeContribution < 0) | ||
const validFee = Math.ceil(feeRate * | ||
(0, vsize_1.vsize)(validUtxos.map(utxo => utxo.output), [remainder])); | ||
(0, vsize_1.vsize)(validUtxos.map(utxo => utxo.output), outputs)); | ||
const validUtxosValue = validUtxos.reduce((a, utxo) => a + utxo.value, 0); | ||
const remainderValue = validUtxosValue - validFee; | ||
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 | ||
const targets = [{ output: remainder, value: remainderValue }]; | ||
//mutate targets: | ||
targets = [...targets, { output: remainder, value: remainderValue }]; | ||
return { | ||
@@ -46,0 +51,0 @@ utxos: utxos.length === validUtxos.length ? utxos : validUtxos, |
@@ -17,6 +17,2 @@ import type { OutputInstance } from '@bitcoinerlab/descriptors'; | ||
* | ||
* To transfer all funds from your UTXOs to a recipient address, specify the | ||
* recipient in the `remainder` argument and omit the `targets`. This way, | ||
* the {@link maxFunds maxFunds} algorithm is used. | ||
* | ||
* UTXOs that do not provide enough value to cover their respective fee | ||
@@ -61,3 +57,3 @@ * contributions are automatically excluded. | ||
*/ | ||
targets?: Array<OutputWithValue>; | ||
targets: Array<OutputWithValue>; | ||
/** | ||
@@ -64,0 +60,0 @@ * `OutputInstance` used as the change address when targets are specified, |
@@ -8,3 +8,2 @@ "use strict"; | ||
const avoidChange_1 = require("./algos/avoidChange"); | ||
const maxFunds_1 = require("./algos/maxFunds"); | ||
const vsize_1 = require("./vsize"); | ||
@@ -31,6 +30,2 @@ const segwit_1 = require("./segwit"); | ||
* | ||
* To transfer all funds from your UTXOs to a recipient address, specify the | ||
* recipient in the `remainder` argument and omit the `targets`. This way, | ||
* the {@link maxFunds maxFunds} algorithm is used. | ||
* | ||
* UTXOs that do not provide enough value to cover their respective fee | ||
@@ -77,28 +72,21 @@ * contributions are automatically excluded. | ||
//(because the coinselect algo may end up choosing only non-segwit utxos). | ||
let coinselected; | ||
if (targets) { | ||
const isPossiblySegwitTx = (0, segwit_1.isSegwitTx)(utxos.map(utxo => utxo.output)); | ||
//Sort in descending utxoTransferredValue | ||
//Using [...utxos] because sort mutates the input | ||
const sortedUtxos = [...utxos].sort((a, b) => utxoTransferredValue(b, feeRate, isPossiblySegwitTx) - | ||
utxoTransferredValue(a, feeRate, isPossiblySegwitTx)); | ||
coinselected = | ||
(0, avoidChange_1.avoidChange)({ | ||
utxos: sortedUtxos, | ||
targets, | ||
remainder, | ||
feeRate, | ||
dustRelayFeeRate | ||
}) || | ||
(0, addUntilReach_1.addUntilReach)({ | ||
utxos: sortedUtxos, | ||
targets, | ||
remainder, | ||
feeRate, | ||
dustRelayFeeRate | ||
}); | ||
} | ||
else { | ||
coinselected = (0, maxFunds_1.maxFunds)({ utxos, remainder, feeRate, dustRelayFeeRate }); | ||
} | ||
const isPossiblySegwitTx = (0, segwit_1.isSegwitTx)(utxos.map(utxo => utxo.output)); | ||
//Sort in descending utxoTransferredValue | ||
//Using [...utxos] because sort mutates the input | ||
const sortedUtxos = [...utxos].sort((a, b) => utxoTransferredValue(b, feeRate, isPossiblySegwitTx) - | ||
utxoTransferredValue(a, feeRate, isPossiblySegwitTx)); | ||
const coinselected = (0, avoidChange_1.avoidChange)({ | ||
utxos: sortedUtxos, | ||
targets, | ||
remainder, | ||
feeRate, | ||
dustRelayFeeRate | ||
}) || | ||
(0, addUntilReach_1.addUntilReach)({ | ||
utxos: sortedUtxos, | ||
targets, | ||
remainder, | ||
feeRate, | ||
dustRelayFeeRate | ||
}); | ||
if (coinselected) { | ||
@@ -105,0 +93,0 @@ //return the same reference if nothing changed to interact nicely with |
{ | ||
"name": "@bitcoinerlab/coinselect", | ||
"version": "1.0.0", | ||
"version": "1.1.0", | ||
"author": "Jose-Luis Landabaso", | ||
@@ -5,0 +5,0 @@ "license": "MIT", |
@@ -157,9 +157,11 @@ # Coinselect | ||
The `maxFunds` algorithm is tailored for situations where the aim is to transfer all funds from available UTXOs to a single recipient address. To utilize this functionality, either directly import and use `maxFunds` or apply `coinselect` by specifying the recipient's address in the `remainder` argument while omitting the `targets`. This approach ensures that all available funds, minus the transaction fees, are sent to the specified recipient address. | ||
The `maxFunds` algorithm is ideal for transferring all available funds from UTXOs to a specified recipient. To use this algorithm, specify the recipient in the `remainder`. It's also possible to set additional fixed-value targets, if needed. | ||
If the `remainder` value would be below the dust threshold, the function returns `undefined`. | ||
Example: | ||
```typescript | ||
import { coinselect } from '@bitcoinerlab/coinselect'; | ||
import { maxFunds } from '@bitcoinerlab/coinselect'; | ||
const { utxos, targets, fee, vsize } = coinselect({ | ||
const { utxos, targets, fee, vsize } = maxFunds({ | ||
utxos: [ | ||
@@ -175,2 +177,5 @@ { | ||
], | ||
targets: [ | ||
// Additional fixed-value targets can be included here | ||
], | ||
remainder: new Output({ descriptor: 'addr(bc1qwfh5mj2kms4rrf8amr66f7d5ckmpdqdzlpr082)' }), | ||
@@ -181,3 +186,3 @@ feeRate: 1.34 | ||
The final recipient value in the transaction will be: `targets[0].value`. | ||
The value for the recipient (remainder) is determined by subtracting the sum of the values in `targets` and the `fee` from the total value of `utxos`. To access the recipient's value, use `targets[targets.length - 1].value`. | ||
@@ -184,0 +189,0 @@ ### Avoid Change |
334
76218
1318