balanceofsatoshis 25.2.2 → 25.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -1
- package/balances/get_liquidity.js +1 -13
- package/bos +1 -4
- package/chain/anchor_outcome.js +23 -0
- package/chain/anchor_output.js +86 -0
- package/chain/anchor_output_script.js +43 -0
- package/chain/close_fee_payer.js +48 -0
- package/chain/close_resolutions.js +114 -0
- package/chain/closing_fees.js +125 -18
- package/chain/contract_outputs.js +30 -0
- package/chain/funded_outputs.js +58 -0
- package/chain/funding_keys.js +59 -0
- package/chain/get_block_transactions.js +100 -0
- package/chain/get_channel_closes.js +151 -52
- package/chain/get_close_from_spend.js +125 -0
- package/chain/get_close_transactions.js +116 -0
- package/chain/get_closes_in_blocks.js +81 -0
- package/chain/get_spending_transaction.js +90 -0
- package/chain/input_weight.js +43 -0
- package/chain/is_contract_spend.js +26 -0
- package/chain/link_payment_stages.js +119 -0
- package/chain/payment_outcome.js +28 -0
- package/chain/resolution_fee.js +86 -0
- package/chain/split_fee.js +40 -0
- package/chain/split_utxos.js +167 -54
- package/chain/transaction_fee.js +56 -0
- package/chain/utxo_split_plan.js +142 -0
- package/package.json +2 -3
- package/chain/get_channel_resolution.js +0 -249
package/chain/split_utxos.js
CHANGED
|
@@ -1,20 +1,33 @@
|
|
|
1
1
|
const asyncAuto = require('async/auto');
|
|
2
|
+
const asyncEach = require('async/each');
|
|
2
3
|
const asyncMapSeries = require('async/mapSeries');
|
|
4
|
+
const asyncReflect = require('async/reflect');
|
|
5
|
+
const {broadcastChainTransaction} = require('ln-service');
|
|
3
6
|
const {createChainAddress} = require('ln-service');
|
|
7
|
+
const {fundPsbt} = require('ln-service');
|
|
8
|
+
const {getChainFeeRate} = require('ln-service');
|
|
4
9
|
const {getUtxos} = require('ln-service');
|
|
5
10
|
const {returnResult} = require('asyncjs-util');
|
|
6
|
-
const {
|
|
11
|
+
const {signPsbt} = require('ln-service');
|
|
12
|
+
const {unlockUtxo} = require('ln-service');
|
|
7
13
|
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
const
|
|
14
|
+
const utxoSplitPlan = require('./utxo_split_plan');
|
|
15
|
+
|
|
16
|
+
const asOutpoint = n => `${n.transaction_id}:${n.transaction_vout}`;
|
|
17
|
+
const {ceil} = Math;
|
|
18
|
+
const format = 'p2wpkh';
|
|
11
19
|
const minimumUtxoTokens = 1e5;
|
|
12
20
|
const newArrayOfSize = n => Array.from(Array(n));
|
|
13
21
|
|
|
14
22
|
/** Ensure there are a certain number of utxos greater than or equal to a size
|
|
15
23
|
|
|
16
|
-
|
|
17
|
-
|
|
24
|
+
Spending a utxo that already counts removes it from the count, so the split
|
|
25
|
+
replaces spent counted utxos and counts the change when it is large enough.
|
|
26
|
+
|
|
27
|
+
The inputs to spend are selected so that the split reaches the count, and
|
|
28
|
+
when the funds cannot support the count, the split is rejected.
|
|
29
|
+
|
|
30
|
+
Only confirmed utxos are spent
|
|
18
31
|
|
|
19
32
|
{
|
|
20
33
|
count: <Count of UTXOs Number>
|
|
@@ -24,6 +37,13 @@ const newArrayOfSize = n => Array.from(Array(n));
|
|
|
24
37
|
size: <UTXO Minimum Tokens Number>
|
|
25
38
|
[tokens_per_vbyte]: <Fee Tokens Per Virtual Byte Number>
|
|
26
39
|
}
|
|
40
|
+
|
|
41
|
+
@returns via cbk
|
|
42
|
+
{
|
|
43
|
+
needed_outputs: <Split Outputs Count Number>
|
|
44
|
+
sent_to: [<Split Output Address String>]
|
|
45
|
+
[transaction_id]: <Split Transaction Id Hex String>
|
|
46
|
+
}
|
|
27
47
|
*/
|
|
28
48
|
module.exports = (args, cbk) => {
|
|
29
49
|
return asyncAuto({
|
|
@@ -44,89 +64,182 @@ module.exports = (args, cbk) => {
|
|
|
44
64
|
return cbk();
|
|
45
65
|
},
|
|
46
66
|
|
|
47
|
-
// Get
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
67
|
+
// Get the fee rate to pay for the split
|
|
68
|
+
feeRate: ['validate', ({}, cbk) => {
|
|
69
|
+
// Exit early when the fee rate is specified
|
|
70
|
+
if (!!args.tokens_per_vbyte) {
|
|
71
|
+
return cbk(null, args.tokens_per_vbyte);
|
|
72
|
+
}
|
|
53
73
|
|
|
54
|
-
|
|
55
|
-
if (!!
|
|
56
|
-
return
|
|
74
|
+
return getChainFeeRate({lnd: args.lnd}, (err, res) => {
|
|
75
|
+
if (!!err) {
|
|
76
|
+
return cbk(err);
|
|
57
77
|
}
|
|
58
78
|
|
|
59
|
-
|
|
79
|
+
// Round up the estimated rate since the split pays whole rates
|
|
80
|
+
return cbk(null, ceil(res.tokens_per_vbyte));
|
|
60
81
|
});
|
|
61
|
-
|
|
62
|
-
if (existing.length > args.count) {
|
|
63
|
-
return cbk(null, [].length);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
return cbk(null, args.count - existing.length - consumedUtxoCount);
|
|
67
82
|
}],
|
|
68
83
|
|
|
69
|
-
//
|
|
70
|
-
|
|
71
|
-
// Exit early when there are no needed utxos
|
|
72
|
-
if (!outputCount) {
|
|
73
|
-
return cbk();
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
const utxos = getUtxos.utxos.filter(n => !!n.confirmation_count);
|
|
77
|
-
|
|
78
|
-
const tokens = utxos.reduce((sum, n) => sum + n.tokens, 0);
|
|
84
|
+
// Get all the current UTXOs
|
|
85
|
+
getUtxos: ['validate', ({}, cbk) => getUtxos({lnd: args.lnd}, cbk)],
|
|
79
86
|
|
|
80
|
-
|
|
81
|
-
|
|
87
|
+
// Select the inputs and the count of outputs that reach the count
|
|
88
|
+
plan: ['feeRate', 'getUtxos', ({feeRate, getUtxos}, cbk) => {
|
|
89
|
+
try {
|
|
90
|
+
const plan = utxoSplitPlan({
|
|
91
|
+
count: args.count,
|
|
92
|
+
fee_tokens_per_vbyte: feeRate,
|
|
93
|
+
is_confirmed: args.is_confirmed,
|
|
94
|
+
size: args.size,
|
|
95
|
+
utxos: getUtxos.utxos,
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
return cbk(null, plan);
|
|
99
|
+
} catch (err) {
|
|
100
|
+
return cbk([400, err.message]);
|
|
82
101
|
}
|
|
83
|
-
|
|
84
|
-
return cbk();
|
|
85
102
|
}],
|
|
86
103
|
|
|
87
104
|
// Generate addresses
|
|
88
|
-
getAddresses: ['
|
|
89
|
-
|
|
105
|
+
getAddresses: ['plan', ({plan}, cbk) => {
|
|
106
|
+
// Exit early when not creating any outputs
|
|
107
|
+
if (!!args.is_dry_run || !plan.outputs) {
|
|
90
108
|
return cbk(null, []);
|
|
91
109
|
}
|
|
92
110
|
|
|
93
|
-
return asyncMapSeries(newArrayOfSize(
|
|
94
|
-
|
|
111
|
+
return asyncMapSeries(newArrayOfSize(plan.outputs), (_, cbk) => {
|
|
112
|
+
return createChainAddress({format, lnd: args.lnd}, cbk);
|
|
95
113
|
},
|
|
96
114
|
cbk);
|
|
97
115
|
}],
|
|
98
116
|
|
|
99
|
-
//
|
|
100
|
-
|
|
117
|
+
// Fund the split outputs by spending the selected inputs
|
|
118
|
+
fund: [
|
|
119
|
+
'feeRate',
|
|
101
120
|
'getAddresses',
|
|
102
|
-
'
|
|
103
|
-
({getAddresses,
|
|
121
|
+
'plan',
|
|
122
|
+
({feeRate, getAddresses, plan}, cbk) =>
|
|
104
123
|
{
|
|
105
|
-
|
|
106
|
-
|
|
124
|
+
// Exit early when there are no outputs to fund
|
|
125
|
+
if (!getAddresses.length) {
|
|
126
|
+
return cbk();
|
|
107
127
|
}
|
|
108
128
|
|
|
109
129
|
const tokens = args.size;
|
|
110
130
|
|
|
111
|
-
return
|
|
112
|
-
fee_tokens_per_vbyte:
|
|
131
|
+
return fundPsbt({
|
|
132
|
+
fee_tokens_per_vbyte: feeRate,
|
|
133
|
+
inputs: plan.inputs,
|
|
113
134
|
lnd: args.lnd,
|
|
114
|
-
|
|
135
|
+
outputs: getAddresses.map(({address}) => ({address, tokens})),
|
|
115
136
|
},
|
|
116
137
|
cbk);
|
|
117
138
|
}],
|
|
118
139
|
|
|
140
|
+
// Make sure the funded split reaches the count before signing it
|
|
141
|
+
checkFunding: [
|
|
142
|
+
'fund',
|
|
143
|
+
'getUtxos',
|
|
144
|
+
asyncReflect(({fund, getUtxos}, cbk) =>
|
|
145
|
+
{
|
|
146
|
+
// Exit early when there is no funded split to check
|
|
147
|
+
if (!fund) {
|
|
148
|
+
return cbk();
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const spending = fund.inputs.map(asOutpoint);
|
|
152
|
+
|
|
153
|
+
// Counted utxos that are not spent in the split remain counted
|
|
154
|
+
const remaining = getUtxos.utxos
|
|
155
|
+
.filter(n => !args.is_confirmed || !!n.confirmation_count)
|
|
156
|
+
.filter(n => n.tokens >= args.size)
|
|
157
|
+
.filter(n => !spending.includes(asOutpoint(n)));
|
|
158
|
+
|
|
159
|
+
// Split outputs and change that are large enough are counted
|
|
160
|
+
const created = fund.outputs.filter(n => n.tokens >= args.size);
|
|
161
|
+
|
|
162
|
+
// Exit early with an error when the split would not reach the count
|
|
163
|
+
if (remaining.length + created.length < args.count) {
|
|
164
|
+
return cbk([503, 'ExpectedFundedSplitToReachCountOfUtxos']);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return cbk();
|
|
168
|
+
})],
|
|
169
|
+
|
|
170
|
+
// Sign the funded split
|
|
171
|
+
sign: [
|
|
172
|
+
'checkFunding',
|
|
173
|
+
'fund',
|
|
174
|
+
asyncReflect(({checkFunding, fund}, cbk) =>
|
|
175
|
+
{
|
|
176
|
+
// Exit early when there is no funded split to sign
|
|
177
|
+
if (!fund || !!checkFunding.error) {
|
|
178
|
+
return cbk();
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return signPsbt({lnd: args.lnd, psbt: fund.psbt}, cbk);
|
|
182
|
+
})],
|
|
183
|
+
|
|
184
|
+
// Broadcast the signed split
|
|
185
|
+
broadcast: ['sign', asyncReflect(({sign}, cbk) => {
|
|
186
|
+
// Exit early when there is no signed split to broadcast
|
|
187
|
+
if (!sign.value) {
|
|
188
|
+
return cbk();
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return broadcastChainTransaction({
|
|
192
|
+
lnd: args.lnd,
|
|
193
|
+
transaction: sign.value.transaction,
|
|
194
|
+
},
|
|
195
|
+
cbk);
|
|
196
|
+
})],
|
|
197
|
+
|
|
198
|
+
// Release the locks on the inputs when the split is not broadcast
|
|
199
|
+
unlock: [
|
|
200
|
+
'broadcast',
|
|
201
|
+
'checkFunding',
|
|
202
|
+
'fund',
|
|
203
|
+
'sign',
|
|
204
|
+
({broadcast, checkFunding, fund, sign}, cbk) =>
|
|
205
|
+
{
|
|
206
|
+
const error = checkFunding.error || sign.error || broadcast.error;
|
|
207
|
+
|
|
208
|
+
// Exit early when nothing stopped the split
|
|
209
|
+
if (!error) {
|
|
210
|
+
return cbk();
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
return asyncEach(fund.inputs, (input, cbk) => {
|
|
214
|
+
return unlockUtxo({
|
|
215
|
+
id: input.lock_id,
|
|
216
|
+
lnd: args.lnd,
|
|
217
|
+
transaction_id: input.transaction_id,
|
|
218
|
+
transaction_vout: input.transaction_vout,
|
|
219
|
+
},
|
|
220
|
+
() => {
|
|
221
|
+
// Ignore errors unlocking a UTXO, the lock will expire on its own
|
|
222
|
+
return cbk();
|
|
223
|
+
});
|
|
224
|
+
},
|
|
225
|
+
() => {
|
|
226
|
+
// Return the original error that stopped the split
|
|
227
|
+
return cbk(error);
|
|
228
|
+
});
|
|
229
|
+
}],
|
|
230
|
+
|
|
119
231
|
// Utxos
|
|
120
232
|
utxos: [
|
|
233
|
+
'broadcast',
|
|
121
234
|
'getAddresses',
|
|
122
|
-
'
|
|
123
|
-
'
|
|
124
|
-
({
|
|
235
|
+
'plan',
|
|
236
|
+
'unlock',
|
|
237
|
+
({broadcast, getAddresses, plan}, cbk) =>
|
|
125
238
|
{
|
|
126
239
|
return cbk(null, {
|
|
127
|
-
needed_outputs:
|
|
240
|
+
needed_outputs: plan.outputs,
|
|
128
241
|
sent_to: getAddresses.map(({address}) => address),
|
|
129
|
-
transaction_id:
|
|
242
|
+
transaction_id: !!broadcast.value ? broadcast.value.id : undefined,
|
|
130
243
|
});
|
|
131
244
|
}],
|
|
132
245
|
},
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
const {componentsOfTransaction} = require('@alexbosworth/blockchain');
|
|
2
|
+
|
|
3
|
+
const sumOf = arr => arr.reduce((sum, n) => sum + n, Number());
|
|
4
|
+
|
|
5
|
+
/** Calculate the fee paid by a transaction
|
|
6
|
+
|
|
7
|
+
The fee is known when the wallet reports it, or when every output that the
|
|
8
|
+
transaction spends is known from the raw transaction that created it.
|
|
9
|
+
|
|
10
|
+
{
|
|
11
|
+
[fee]: <Wallet Reported Fee Tokens Number>
|
|
12
|
+
transaction: <Raw Transaction Hex String>
|
|
13
|
+
transactions: [{
|
|
14
|
+
id: <Transaction Id Hex String>
|
|
15
|
+
[transaction]: <Raw Transaction Hex String>
|
|
16
|
+
}]
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
@returns
|
|
20
|
+
{
|
|
21
|
+
[fee]: <Fee Tokens Number>
|
|
22
|
+
}
|
|
23
|
+
*/
|
|
24
|
+
module.exports = args => {
|
|
25
|
+
// Exit early when the wallet knows the fee
|
|
26
|
+
if (!!args.fee) {
|
|
27
|
+
return {fee: args.fee};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const {inputs, outputs} = componentsOfTransaction({
|
|
31
|
+
transaction: args.transaction,
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
const spent = inputs.map(input => {
|
|
35
|
+
const [spending] = args.transactions
|
|
36
|
+
.filter(n => !!n.transaction)
|
|
37
|
+
.filter(n => n.id === input.id)
|
|
38
|
+
.map(({transaction}) => componentsOfTransaction({transaction}));
|
|
39
|
+
|
|
40
|
+
// Exit early when the transaction that created the input is not known
|
|
41
|
+
if (!spending) {
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return spending.outputs[input.vout];
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// Exit early when the value of a spent output is unknown
|
|
49
|
+
if (spent.includes(undefined)) {
|
|
50
|
+
return {};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const spentTokens = sumOf(spent.map(n => n.tokens));
|
|
54
|
+
|
|
55
|
+
return {fee: spentTokens - sumOf(outputs.map(n => n.tokens))};
|
|
56
|
+
};
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
const {sortBy} = require('./../arrays');
|
|
2
|
+
|
|
3
|
+
const fundedOutputs = require('./funded_outputs');
|
|
4
|
+
|
|
5
|
+
const {ceil} = Math;
|
|
6
|
+
const inputVbytes = {np2wpkh: 92, p2tr: 58, p2wpkh: 69};
|
|
7
|
+
const {isArray} = Array;
|
|
8
|
+
const splitOutputVbytes = 31;
|
|
9
|
+
const unknownInputVbytes = 92;
|
|
10
|
+
|
|
11
|
+
/** Plan the inputs and outputs of a transaction that splits utxos
|
|
12
|
+
|
|
13
|
+
Spending a utxo that is already counted removes it from the count, so it has
|
|
14
|
+
to be replaced. Change counts as a new utxo when it is at least the size.
|
|
15
|
+
|
|
16
|
+
Confirmed utxos are spent, starting with the utxos that have the most value
|
|
17
|
+
beyond what they already count for, until the outputs reaching the count can
|
|
18
|
+
be funded.
|
|
19
|
+
|
|
20
|
+
{
|
|
21
|
+
count: <Count of UTXOs Number>
|
|
22
|
+
fee_tokens_per_vbyte: <Fee Tokens Per Virtual Byte Number>
|
|
23
|
+
[is_confirmed]: <Only Count Confirmed UTXOs Bool>
|
|
24
|
+
size: <UTXO Minimum Tokens Number>
|
|
25
|
+
utxos: [{
|
|
26
|
+
address_format: <Address Format String>
|
|
27
|
+
confirmation_count: <Confirmation Count Number>
|
|
28
|
+
tokens: <Unspent Tokens Number>
|
|
29
|
+
transaction_id: <Transaction Id Hex String>
|
|
30
|
+
transaction_vout: <Transaction Output Index Number>
|
|
31
|
+
}]
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
@throws
|
|
35
|
+
<Error>
|
|
36
|
+
|
|
37
|
+
@returns
|
|
38
|
+
{
|
|
39
|
+
inputs: [{
|
|
40
|
+
transaction_id: <Spend Transaction Id Hex String>
|
|
41
|
+
transaction_vout: <Spend Transaction Output Index Number>
|
|
42
|
+
}]
|
|
43
|
+
outputs: <Split Outputs Count Number>
|
|
44
|
+
}
|
|
45
|
+
*/
|
|
46
|
+
module.exports = args => {
|
|
47
|
+
if (!args.count) {
|
|
48
|
+
throw new Error('ExpectedCountOfUtxosToPlanUtxoSplit');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (!args.fee_tokens_per_vbyte) {
|
|
52
|
+
throw new Error('ExpectedFeeRateToPlanUtxoSplit');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (!args.size) {
|
|
56
|
+
throw new Error('ExpectedSizeOfUtxosToPlanUtxoSplit');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (!isArray(args.utxos)) {
|
|
60
|
+
throw new Error('ExpectedArrayOfUtxosToPlanUtxoSplit');
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const fee = vbytes => ceil(vbytes * args.fee_tokens_per_vbyte);
|
|
64
|
+
const isConfirmedEnough = n => !args.is_confirmed || !!n.confirmation_count;
|
|
65
|
+
|
|
66
|
+
const isCounted = n => isConfirmedEnough(n) && n.tokens >= args.size;
|
|
67
|
+
|
|
68
|
+
const counted = args.utxos.filter(isCounted);
|
|
69
|
+
|
|
70
|
+
// Exit early when there are already enough utxos
|
|
71
|
+
if (counted.length >= args.count) {
|
|
72
|
+
return {inputs: [], outputs: [].length};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// A counted utxo that is spent has to be replaced with a split output
|
|
76
|
+
const replacement = args.size + fee(splitOutputVbytes);
|
|
77
|
+
|
|
78
|
+
const candidates = args.utxos.filter(n => !!n.confirmation_count).map(n => {
|
|
79
|
+
const isReplaced = isCounted(n);
|
|
80
|
+
const vbytes = inputVbytes[n.address_format] || unknownInputVbytes;
|
|
81
|
+
|
|
82
|
+
const value = n.tokens - fee(vbytes);
|
|
83
|
+
|
|
84
|
+
return {
|
|
85
|
+
vbytes,
|
|
86
|
+
is_counted: isReplaced,
|
|
87
|
+
surplus: isReplaced ? value - replacement : value,
|
|
88
|
+
tokens: n.tokens,
|
|
89
|
+
transaction_id: n.transaction_id,
|
|
90
|
+
transaction_vout: n.transaction_vout,
|
|
91
|
+
};
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
// Only utxos that add value can help, so spend the most valuable ones first
|
|
95
|
+
const spending = sortBy({
|
|
96
|
+
array: candidates.filter(n => n.surplus > Number()),
|
|
97
|
+
attribute: 'surplus',
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
const spend = spending.sorted.reverse();
|
|
101
|
+
|
|
102
|
+
// Select the fewest inputs that fund enough outputs to reach the count
|
|
103
|
+
const selection = spend.reduce((sum, utxo, i) => {
|
|
104
|
+
// Exit early when enough inputs are already selected
|
|
105
|
+
if (sum.outputs !== undefined) {
|
|
106
|
+
return sum;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const selected = {
|
|
110
|
+
counted: sum.counted + Number(utxo.is_counted),
|
|
111
|
+
inputs: i + 1,
|
|
112
|
+
tokens: sum.tokens + utxo.tokens,
|
|
113
|
+
vbytes: sum.vbytes + utxo.vbytes,
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
const {outputs} = fundedOutputs({
|
|
117
|
+
counted: selected.counted,
|
|
118
|
+
inputs: selected.inputs,
|
|
119
|
+
needed: args.count - counted.length,
|
|
120
|
+
rate: args.fee_tokens_per_vbyte,
|
|
121
|
+
size: args.size,
|
|
122
|
+
tokens: selected.tokens,
|
|
123
|
+
vbytes: selected.vbytes,
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
return {...selected, outputs};
|
|
127
|
+
},
|
|
128
|
+
{counted: 0, inputs: 0, tokens: 0, vbytes: 0});
|
|
129
|
+
|
|
130
|
+
// Exit early with an error when the funds cannot reach the count of utxos
|
|
131
|
+
if (selection.outputs === undefined) {
|
|
132
|
+
throw new Error('InsufficientBalanceToSplitUtxos');
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return {
|
|
136
|
+
inputs: spend.slice(0, selection.inputs).map(utxo => ({
|
|
137
|
+
transaction_id: utxo.transaction_id,
|
|
138
|
+
transaction_vout: utxo.transaction_vout,
|
|
139
|
+
})),
|
|
140
|
+
outputs: selection.outputs,
|
|
141
|
+
};
|
|
142
|
+
};
|
package/package.json
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"url": "https://github.com/alexbosworth/balanceofsatoshis/issues"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@alexbosworth/blockchain": "4.
|
|
18
|
+
"@alexbosworth/blockchain": "4.12.0",
|
|
19
19
|
"@alexbosworth/caporal": "2.0.0",
|
|
20
20
|
"@alexbosworth/fiat": "2.0.0",
|
|
21
21
|
"@alexbosworth/formulas": "1.5.0",
|
|
@@ -25,7 +25,6 @@
|
|
|
25
25
|
"asyncjs-util": "1.2.12",
|
|
26
26
|
"bech32": "2.0.0",
|
|
27
27
|
"bip66": "2.0.0",
|
|
28
|
-
"bolt03": "2.0.0",
|
|
29
28
|
"bolt04": "1.3.0",
|
|
30
29
|
"bolt07": "2.0.0",
|
|
31
30
|
"cbor": "10.0.12",
|
|
@@ -104,5 +103,5 @@
|
|
|
104
103
|
"postpublish": "docker buildx build --platform linux/amd64,linux/arm64 -t alexbosworth/balanceofsatoshis -t alexbosworth/balanceofsatoshis:$npm_package_version --push .",
|
|
105
104
|
"test": "node --experimental-test-coverage --test test/arrays/*.js test/balances/*.js test/chain/*.js test/display/*.js test/encryption/*.js test/lnd/*.js test/network/*.js test/nodes/*.js test/offchain/*.js test/peers/*.js test/responses/*.js test/routing/*.js test/services/*.js test/swaps/*.js test/tags/*.js test/telegram/*.js test/wallets/*.js"
|
|
106
105
|
},
|
|
107
|
-
"version": "25.
|
|
106
|
+
"version": "25.3.0"
|
|
108
107
|
}
|