balanceofsatoshis 11.47.2 → 11.48.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
CHANGED
package/CONTRIBUTING.md
CHANGED
|
@@ -17,6 +17,8 @@ If you want to help with style, here are some rough guidelines on style ideas:
|
|
|
17
17
|
- Minimize function nesting, make new files if nesting is required
|
|
18
18
|
- No extraneous whitespace
|
|
19
19
|
- A single newline should appear at the end of a file
|
|
20
|
+
- A single line should contain max 80 characters including the newline
|
|
21
|
+
- If a top level scalar would go over 80 characters in a line, that's ok
|
|
20
22
|
- Don't bother with () in functions when not needed: `const a = b => c`
|
|
21
23
|
- If there are multiple things together, alphabetize them
|
|
22
24
|
- Don't split up long strings over multiple lines
|
|
@@ -27,11 +29,14 @@ If you want to help with style, here are some rough guidelines on style ideas:
|
|
|
27
29
|
- Use single '' quotes not double "" quotes, except when `` is required
|
|
28
30
|
- If conditions should avoid spanning multiple lines
|
|
29
31
|
- Avoid double specifying an attribute and value, `{type: type}` vs `{type}`
|
|
32
|
+
- Always use {} with if, else, etc statements
|
|
33
|
+
- Document the top of methods with what the arguments are and what is returned
|
|
30
34
|
|
|
31
35
|
### Control Flow
|
|
32
36
|
|
|
33
37
|
- Async functions should support both cbk and Promise style
|
|
34
38
|
- Use async.js methods for asynchronous control flow
|
|
39
|
+
- Use async auto and returnResult for all non-event async functions
|
|
35
40
|
- Try to exit early from functions when possible, and note this exit in comment
|
|
36
41
|
- Prefer cbk over Promise style, aside from in tests or in Promise libs
|
|
37
42
|
- Use `asyncAuto` for asynchronous control flow dependency management
|
|
@@ -49,6 +54,8 @@ If you want to help with style, here are some rough guidelines on style ideas:
|
|
|
49
54
|
- Short properties always go first in objects: `{short, longer: type}`
|
|
50
55
|
- If a statement relies on a statement above it, it should have a newline above
|
|
51
56
|
- Avoid including scalar values such as strings or numbers in the code itself
|
|
57
|
+
- Prefer hex serialization over base64 or Buffers in arguments or output
|
|
58
|
+
- Avoid any function arguments that are multiple data types
|
|
52
59
|
|
|
53
60
|
### JS Features
|
|
54
61
|
|
|
@@ -60,6 +67,7 @@ If you want to help with style, here are some rough guidelines on style ideas:
|
|
|
60
67
|
- Try to avoid passing objects in arguments as much as possible
|
|
61
68
|
- Prefer using function iteration like map and forEach over for and while
|
|
62
69
|
- Use arrow functions and not `function` functions whenever possible
|
|
70
|
+
- Functions should only take and return a single object as argument, result
|
|
63
71
|
|
|
64
72
|
### Errors
|
|
65
73
|
|
|
@@ -70,3 +78,5 @@ If you want to help with style, here are some rough guidelines on style ideas:
|
|
|
70
78
|
- Use HTTP status codes as a guideline: 4** is a local issue, 5** is remote
|
|
71
79
|
- Return async errors as arrays: `[typeNumber, errorMsgString, extraDetails]`
|
|
72
80
|
- Try to be very specific with error messages and try to not repeat one
|
|
81
|
+
- Callbacks should always be called as (err, result)
|
|
82
|
+
- Try and catch should not be used unless an error is expected
|
|
@@ -1,10 +1,15 @@
|
|
|
1
|
+
const {address} = require('bitcoinjs-lib');
|
|
1
2
|
const asyncAuto = require('async/auto');
|
|
2
3
|
const asyncEach = require('async/each');
|
|
4
|
+
const {createPsbt} = require('psbt');
|
|
3
5
|
const {formatTokens} = require('ln-sync');
|
|
6
|
+
const {fromBech32} = address;
|
|
4
7
|
const {fundPsbt} = require('ln-service');
|
|
5
8
|
const {getChainFeeRate} = require('ln-service');
|
|
6
9
|
const {getMaxFundAmount} = require('ln-sync');
|
|
10
|
+
const {getNetwork} = require('ln-sync');
|
|
7
11
|
const {getUtxos} = require('ln-service');
|
|
12
|
+
const {networks} = require('bitcoinjs-lib');
|
|
8
13
|
const {returnResult} = require('asyncjs-util');
|
|
9
14
|
const {signPsbt} = require('ln-service');
|
|
10
15
|
const {Transaction} = require('bitcoinjs-lib');
|
|
@@ -16,6 +21,7 @@ const asBigUnit = n => (n / 1e8).toFixed(8);
|
|
|
16
21
|
const asOutpoint = utxo => `${utxo.transaction_id}:${utxo.transaction_vout}`;
|
|
17
22
|
const asInput = n => ({transaction_id: n.id, transaction_vout: n.vout});
|
|
18
23
|
const asUtxo = n => ({id: n.slice(0, 64), vout: Number(n.slice(65))});
|
|
24
|
+
const bufferAsHex = buffer => buffer.toString('hex');
|
|
19
25
|
const dustValue = 293;
|
|
20
26
|
const formattedFeeRate = n => n.toFixed(2);
|
|
21
27
|
const {fromHex} = Transaction;
|
|
@@ -25,6 +31,8 @@ const isOutpoint = n => !!n && /^[0-9A-F]{64}:[0-9]{1,6}$/i.test(n);
|
|
|
25
31
|
const isPublicKey = n => !!n && /^0[2-3][0-9A-F]{64}$/i.test(n);
|
|
26
32
|
const minConfs = 1;
|
|
27
33
|
const sumOf = arr => arr.reduce((sum, n) => sum + n, Number());
|
|
34
|
+
const taprootAddressVersion = 1;
|
|
35
|
+
const {toOutputScript} = address;
|
|
28
36
|
const txHashAsTxId = hash => hash.reverse().toString('hex');
|
|
29
37
|
|
|
30
38
|
/** Fund and sign a transaction
|
|
@@ -98,6 +106,9 @@ module.exports = (args, cbk) => {
|
|
|
98
106
|
// Get the current fee rate
|
|
99
107
|
getFee: ['validate', ({}, cbk) => getChainFeeRate({lnd: args.lnd}, cbk)],
|
|
100
108
|
|
|
109
|
+
// Get the network name
|
|
110
|
+
getNetwork: ['validate', ({}, cbk) => getNetwork({lnd: args.lnd}, cbk)],
|
|
111
|
+
|
|
101
112
|
// Derive a list of outputs to guide input selection
|
|
102
113
|
outputs: ['validate', ({}, cbk) => {
|
|
103
114
|
// Exit early when the amount is open ended and thus depends on inputs
|
|
@@ -241,8 +252,9 @@ module.exports = (args, cbk) => {
|
|
|
241
252
|
fund: [
|
|
242
253
|
'finalOutputs',
|
|
243
254
|
'getFee',
|
|
255
|
+
'getNetwork',
|
|
244
256
|
'utxos',
|
|
245
|
-
({finalOutputs, getFee, utxos}, cbk) =>
|
|
257
|
+
({finalOutputs, getFee, getNetwork, utxos}, cbk) =>
|
|
246
258
|
{
|
|
247
259
|
const inputs = utxos.map(asUtxo).map(asInput);
|
|
248
260
|
const feeRate = args.fee_tokens_per_vbyte || getFee.tokens_per_vbyte;
|
|
@@ -258,11 +270,50 @@ module.exports = (args, cbk) => {
|
|
|
258
270
|
requested_fee_rate: feeRate,
|
|
259
271
|
});
|
|
260
272
|
|
|
273
|
+
const hasTaprootOutput = !!finalOutputs.find(n => {
|
|
274
|
+
try {
|
|
275
|
+
return fromBech32(n.address).version === taprootAddressVersion;
|
|
276
|
+
} catch (err) {
|
|
277
|
+
return false;
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
// Exit early when there is no taproot output
|
|
282
|
+
if (!hasTaprootOutput) {
|
|
283
|
+
return fundPsbt({
|
|
284
|
+
fee_tokens_per_vbyte: feeRate,
|
|
285
|
+
inputs: !!inputs.length ? inputs : undefined,
|
|
286
|
+
lnd: args.lnd,
|
|
287
|
+
outputs: finalOutputs,
|
|
288
|
+
},
|
|
289
|
+
cbk);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
const network = networks[getNetwork.bitcoinjs];
|
|
293
|
+
|
|
294
|
+
if (!network) {
|
|
295
|
+
return cbk([400, 'UnsupportedNetworkForFundingOutputs']);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
const warn = console.warn;
|
|
299
|
+
|
|
300
|
+
console.warn = () => {};
|
|
301
|
+
|
|
302
|
+
const {psbt} = createPsbt({
|
|
303
|
+
outputs: finalOutputs.map(({address, tokens}) => ({
|
|
304
|
+
tokens,
|
|
305
|
+
script: bufferAsHex(toOutputScript(address, network)),
|
|
306
|
+
})),
|
|
307
|
+
utxos: inputs.map(input => ({
|
|
308
|
+
id: input.transaction_id,
|
|
309
|
+
vout: input.transaction_vout,
|
|
310
|
+
})),
|
|
311
|
+
});
|
|
312
|
+
|
|
261
313
|
return fundPsbt({
|
|
314
|
+
psbt,
|
|
262
315
|
fee_tokens_per_vbyte: feeRate,
|
|
263
|
-
inputs: !!inputs.length ? inputs : undefined,
|
|
264
316
|
lnd: args.lnd,
|
|
265
|
-
outputs: finalOutputs,
|
|
266
317
|
},
|
|
267
318
|
cbk);
|
|
268
319
|
}],
|
package/package.json
CHANGED
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"colorette": "2.0.16",
|
|
28
28
|
"crypto-js": "4.1.1",
|
|
29
29
|
"csv-parse": "5.0.4",
|
|
30
|
-
"goldengate": "11.0.
|
|
30
|
+
"goldengate": "11.0.1",
|
|
31
31
|
"grammy": "1.7.0",
|
|
32
32
|
"hot-formula-parser": "4.0.0",
|
|
33
33
|
"import-lazy": "4.0.0",
|
|
@@ -35,13 +35,13 @@
|
|
|
35
35
|
"inquirer": "8.2.0",
|
|
36
36
|
"invoices": "2.0.3",
|
|
37
37
|
"ln-accounting": "5.0.5",
|
|
38
|
-
"ln-service": "53.7.
|
|
39
|
-
"ln-sync": "3.9.
|
|
38
|
+
"ln-service": "53.7.2",
|
|
39
|
+
"ln-sync": "3.9.2",
|
|
40
40
|
"ln-telegram": "3.14.1",
|
|
41
41
|
"moment": "2.29.1",
|
|
42
42
|
"paid-services": "3.11.0",
|
|
43
43
|
"probing": "2.0.2",
|
|
44
|
-
"psbt": "
|
|
44
|
+
"psbt": "2.0.0",
|
|
45
45
|
"qrcode-terminal": "0.12.0",
|
|
46
46
|
"sanitize-filename": "1.6.3",
|
|
47
47
|
"socks-proxy-agent": "6.1.1",
|
|
@@ -52,9 +52,9 @@
|
|
|
52
52
|
"description": "Lightning balance CLI",
|
|
53
53
|
"devDependencies": {
|
|
54
54
|
"@alexbosworth/tap": "15.0.10",
|
|
55
|
-
"ln-docker-daemons": "2.2.
|
|
55
|
+
"ln-docker-daemons": "2.2.4",
|
|
56
56
|
"mock-lnd": "1.4.1",
|
|
57
|
-
"secp256k1": "
|
|
57
|
+
"tiny-secp256k1": "2.2.0"
|
|
58
58
|
},
|
|
59
59
|
"engines": {
|
|
60
60
|
"node": ">=12.20"
|
|
@@ -81,5 +81,5 @@
|
|
|
81
81
|
"postpublish": "docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t alexbosworth/balanceofsatoshis --push .",
|
|
82
82
|
"test": "tap --branches=1 --functions=1 --lines=1 --statements=1 -t 60 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/peers/*.js test/responses/*.js test/routing/*.js test/services/*.js test/swaps/*.js test/tags/*.js test/wallets/*.js"
|
|
83
83
|
},
|
|
84
|
-
"version": "11.
|
|
84
|
+
"version": "11.48.0"
|
|
85
85
|
}
|
package/peers/open_channels.js
CHANGED
|
@@ -11,7 +11,6 @@ const asyncMap = require('async/map');
|
|
|
11
11
|
const asyncReflect = require('async/reflect');
|
|
12
12
|
const asyncRetry = require('async/retry');
|
|
13
13
|
const {cancelPendingChannel} = require('ln-service');
|
|
14
|
-
const {decodePsbt} = require('psbt');
|
|
15
14
|
const {fundPendingChannels} = require('ln-service');
|
|
16
15
|
const {getFundedTransaction} = require('ln-sync');
|
|
17
16
|
const {getNetwork} = require('ln-sync');
|
|
@@ -24,7 +23,6 @@ const {maintainUtxoLocks} = require('ln-sync');
|
|
|
24
23
|
const moment = require('moment');
|
|
25
24
|
const {returnResult} = require('asyncjs-util');
|
|
26
25
|
const {Transaction} = require('bitcoinjs-lib');
|
|
27
|
-
const {transactionAsPsbt} = require('psbt');
|
|
28
26
|
const {unlockUtxo} = require('ln-service');
|
|
29
27
|
|
|
30
28
|
const adjustFees = require('./../routing/adjust_fees');
|
|
@@ -657,19 +655,7 @@ module.exports = (args, cbk) => {
|
|
|
657
655
|
'setFeeRates',
|
|
658
656
|
({getFunding, fundingPsbt}, cbk) =>
|
|
659
657
|
{
|
|
660
|
-
|
|
661
|
-
const tx = getFunding.value.transaction;
|
|
662
|
-
|
|
663
|
-
const decoded = decodePsbt({psbt: fundingPsbt.value.psbt});
|
|
664
|
-
|
|
665
|
-
const transaction = tx || decoded.unsigned_transaction;
|
|
666
|
-
|
|
667
|
-
return cbk(null, {
|
|
668
|
-
transaction_id: Transaction.fromHex(transaction).getId(),
|
|
669
|
-
});
|
|
670
|
-
} catch (err) {
|
|
671
|
-
return cbk([503, 'UnexpectedErrorGettingTransactionId', {err}]);
|
|
672
|
-
}
|
|
658
|
+
return cbk(null, {transaction_id: getFunding.value.id});
|
|
673
659
|
}],
|
|
674
660
|
},
|
|
675
661
|
returnResult({reject, resolve, of: 'completed'}, cbk));
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
const {address} = require('bitcoinjs-lib');
|
|
2
|
+
const {crypto} = require('bitcoinjs-lib');
|
|
3
|
+
const {networks} = require('bitcoinjs-lib');
|
|
4
|
+
const {script} = require('bitcoinjs-lib');
|
|
5
|
+
const {spawnLightningCluster} = require('ln-docker-daemons');
|
|
6
|
+
const {test} = require('@alexbosworth/tap');
|
|
7
|
+
const tinysecp = require('tiny-secp256k1');
|
|
8
|
+
|
|
9
|
+
const {fundTransaction} = require('./../../chain');
|
|
10
|
+
|
|
11
|
+
const {compile} = script;
|
|
12
|
+
const count = 100;
|
|
13
|
+
const {fromOutputScript} = address;
|
|
14
|
+
const makeTaprootKey = (k, h) => tinysecp.xOnlyPointAddTweak(k, h).xOnlyPubkey;
|
|
15
|
+
const OP_1 = 81;
|
|
16
|
+
const shortKey = keyPair => keyPair.publicKey.slice(1, 33);
|
|
17
|
+
const tapHash = k => crypto.taggedHash('TapTweak', k.publicKey.slice(1, 33));
|
|
18
|
+
const tokens = 1e6;
|
|
19
|
+
|
|
20
|
+
// Funding a transaction should result in a funded tx
|
|
21
|
+
test(`Fund transaction`, async ({end, equal, strictSame}) => {
|
|
22
|
+
const ecp = (await import('ecpair')).ECPairFactory(tinysecp);
|
|
23
|
+
const {kill, nodes} = await spawnLightningCluster({});
|
|
24
|
+
|
|
25
|
+
const [{generate, lnd}] = nodes;
|
|
26
|
+
|
|
27
|
+
await generate({count});
|
|
28
|
+
|
|
29
|
+
const keyPair = ecp.makeRandom({network: networks.regtest});
|
|
30
|
+
|
|
31
|
+
const outputKey = makeTaprootKey(shortKey(keyPair), tapHash(keyPair));
|
|
32
|
+
const tweakHash = tapHash(keyPair);
|
|
33
|
+
|
|
34
|
+
const outputScript = compile([OP_1, Buffer.from(outputKey)]);
|
|
35
|
+
|
|
36
|
+
// Suppress fromOutputScript warning on Taproot address
|
|
37
|
+
const warn = console.warn;
|
|
38
|
+
console.warn = () => {};
|
|
39
|
+
|
|
40
|
+
const address = fromOutputScript(outputScript, networks.regtest);
|
|
41
|
+
|
|
42
|
+
// Restore warnings
|
|
43
|
+
console.warn = warn;
|
|
44
|
+
|
|
45
|
+
try {
|
|
46
|
+
await fundTransaction({
|
|
47
|
+
lnd,
|
|
48
|
+
addresses: [address],
|
|
49
|
+
amounts: [tokens.toString()],
|
|
50
|
+
ask: () => {},
|
|
51
|
+
spend: [],
|
|
52
|
+
is_dry_run: false,
|
|
53
|
+
logger: {error: () => {}, info: () => {}},
|
|
54
|
+
utxos: [],
|
|
55
|
+
});
|
|
56
|
+
} catch (err) {
|
|
57
|
+
equal(err, null, 'Expected no error');
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
await kill({});
|
|
61
|
+
});
|
|
@@ -2,11 +2,13 @@ const EventEmitter = require('events');
|
|
|
2
2
|
|
|
3
3
|
const {createSignedRequest} = require('invoices');
|
|
4
4
|
const {createUnsignedRequest} = require('invoices');
|
|
5
|
-
const
|
|
5
|
+
const secp256k1 = require('tiny-secp256k1');
|
|
6
6
|
const {test} = require('@alexbosworth/tap');
|
|
7
7
|
|
|
8
8
|
const getBalancedOpens = require('./../../services/get_balanced_opens');
|
|
9
9
|
|
|
10
|
+
const sign = (h, k) => Buffer.from(secp256k1.sign(h, k));
|
|
11
|
+
|
|
10
12
|
const createRequest = () => {
|
|
11
13
|
const {hash, hrp, tags} = createUnsignedRequest({
|
|
12
14
|
created_at: '2017-06-01T10:57:38.000Z',
|
|
@@ -32,7 +34,7 @@ const createRequest = () => {
|
|
|
32
34
|
const bufFromHex = hex => Buffer.from(hex, 'hex');
|
|
33
35
|
const privateKey = 'e126f68f7eafcc8b74f54d269fe206be715000f94dac067d1c04a8ca3b2db734';
|
|
34
36
|
|
|
35
|
-
const
|
|
37
|
+
const signature = sign(bufFromHex(hash), bufFromHex(privateKey));
|
|
36
38
|
|
|
37
39
|
const {request} = createSignedRequest({
|
|
38
40
|
hrp,
|