bsv-coinselect
An unspent transaction output (UTXO) selection module for Bitcoin SV.
https://matterpool.io
Originally forked from https://github.com/bitcoinjs/coinselect
Problem and Overview
Working with Unspent transaction outputs (UTXO) the developer must choose which "coins" to use for creating transactions.
For instance, the developer may want to use the minimal number of UTXOs to pay all outputs at a given fee rate.
This library makes it easy to select UTXO's according different policies.
This is a client-side library only and can be used in any Javascript project. If you need to fetch UTXO's or broadcast BSV transactions then use the Filepay library at http://github.com/mattercloud/filepay which makes use of bsv-coinselect
NOTE: Force a UTXO to be selected by specifying required: true
const utxos = [
{
"address": "1CgPDEav5fdzry3V7tGADY4rHqG8oi4kfv",
"txid": "a939afcb78a06239f02eefbfaabc6e0a78dfe3cd64f9676932cc1195796fa42f",
"vout": 1,
"value": 1000,
"height": 617496,
"confirmations": 18639,
"scriptPubKey": "76a914801c259a527abd83a977fd90a06b22d215fcad4988ac",
"script": "76a914801c259a527abd83a977fd90a06b22d215fcad4988ac",
"outputIndex": 1,
"required": true
},
{
"address": "1CgPDEav5fdzry3V7tGADY4rHqG8oi4kfv",
"txid": "716e6b12d111984818d8c5e6d68446a52746d480d397d077cad598d55f059a65",
"vout": 1,
"value": 5000,
"height": 616468,
"confirmations": 19667,
"scriptPubKey": "76a914801c259a527abd83a977fd90a06b22d215fcad4988ac",
"script": "76a914801c259a527abd83a977fd90a06b22d215fcad4988ac",
"outputIndex": 1
},
{
"address": "1CgPDEav5fdzry3V7tGADY4rHqG8oi4kfv",
"txid": "98e0987b5b5783ae083814f448f1dda52c18c881beda649c36576d0c81ee31f9",
"vout": 1,
"value": 10004,
"height": 610466,
"confirmations": 25669,
"scriptPubKey": "76a914801c259a527abd83a977fd90a06b22d215fcad4988ac",
"script": "76a914801c259a527abd83a977fd90a06b22d215fcad4988ac",
"outputIndex": 1
}
];
const outputs = [
{
script: '76a914801c259a527abd83a977fd90a06b22d215fcad4988ac',
value: 1000,
},
{
script: '76a914801c259a527abd83a977fd90a06b22d215fcad4988ac',
value: 546,
},
{
script: '76a914801c259a527abd83a977fd90a06b22d215fcad4988ac',
value: 1000,
},
{
script: '76a914801c259a527abd83a977fd90a06b22d215fcad4988ac',
value: 10000,
},
];
const changeScript = null;
const { inputs, outputs, fee } = coinSelect(utxos, outputs, 0.5, null);
Sample response:
{
fee: 232,
inputs: [
{
"address": "1CgPDEav5fdzry3V7tGADY4rHqG8oi4kfv",
"txid": "98e0987b5b5783ae083814f448f1dda52c18c881beda649c36576d0c81ee31f9",
"vout": 1,
"value": 10004,
"height": 610466,
"confirmations": 25669,
"scriptPubKey": "76a914801c259a527abd83a977fd90a06b22d215fcad4988ac",
"script": "76a914801c259a527abd83a977fd90a06b22d215fcad4988ac",
"outputIndex": 1
},
{
"address": "1CgPDEav5fdzry3V7tGADY4rHqG8oi4kfv",
"txid": "716e6b12d111984818d8c5e6d68446a52746d480d397d077cad598d55f059a65",
"vout": 1,
"value": 5000,
"height": 616468,
"confirmations": 19667,
"scriptPubKey": "76a914801c259a527abd83a977fd90a06b22d215fcad4988ac",
"script": "76a914801c259a527abd83a977fd90a06b22d215fcad4988ac",
"outputIndex": 1
},
],
"outputs": [
{
script: '76a914801c259a527abd83a977fd90a06b22d215fcad4988ac',
value: 1000,
},
{
script: '76a914801c259a527abd83a977fd90a06b22d215fcad4988ac',
value: 546,
},
{
script: '76a914801c259a527abd83a977fd90a06b22d215fcad4988ac',
value: 1000,
},
{
script: '76a914801c259a527abd83a977fd90a06b22d215fcad4988ac',
value: 10000,
},
{
script: null,
"value": 2226
}
]
};
Algorithms
Module | Algorithm | Re-orders UTXOs? |
---|
require('coinselect') | Accumulative - accumulates inputs until the target value (+fees) is reached, skipping | |
require('coinselect/accumulative') | Accumulative - accumulates inputs until the target value (+fees) is reached, skipping detrimental inputs | - |
Note: Each algorithm will add a change output if the input - output - fee
value difference is over a dust threshold.
This is calculated independently by utils.finalize
, irrespective of the algorithm chosen, for the purposes of safety.
Example
let coinSelect = require('coinselect')
let feeRate = 55
let utxos = [
...,
{
txid: '...',
vout: 0,
...,
value: 10000,
}
]
let targets = [
...,
{
address: '1EHNa6Q4Jz2uvNExL497mE43ikXhwF6kZm',
value: 5000
},
{
script: '....',
value: 5000
}
]
let changeScript = null;
let { inputs, outputs, fee } = coinSelect(utxos, targets, feeRate, changeScript, options)
console.log(fee)
if (!inputs || !outputs) return
let tx = new bitcoin.Transaction().from(inputs);
outputs.forEach(output => {
const script = (new bitcoin.Script(output.script)).toString();
tx.addOutput(new bitcoin.Transaction.Output({ script: script, satoshis: output.value }));
})
tx.change('address here');
License MIT