balanceofsatoshis 11.18.1 → 11.20.2

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
@@ -1,5 +1,22 @@
1
1
  # Versions
2
2
 
3
+ ## 11.20.2
4
+
5
+ - `change-channel-capacity`: Increase RBF fee buffer when increasing capacity
6
+ - `telegram`: Redesign /invoice user interface to be button based
7
+
8
+ ## 11.20.1
9
+
10
+ - `fees`: Correct issue where fee rate could not be set to zero
11
+
12
+ ## 11.20.0
13
+
14
+ - `send`: Add support for paying to zero-amount BOLT 11 payment requests
15
+
16
+ ## 11.19.0
17
+
18
+ - `change-channel-capacity`: Allow changing private/public status of channel
19
+
3
20
  ## 11.18.1
4
21
 
5
22
  This release fixes an important issue with the experimental
package/README.md CHANGED
@@ -89,6 +89,9 @@ bos chart-fees-paid
89
89
  # Show a chart of payments received
90
90
  bos chart-payments-received
91
91
 
92
+ # Remove old failed payment data for probes and other failed payments
93
+ bos clean-failed-payments
94
+
92
95
  # See details on how closed channels resolved on-chain
93
96
  bos closed
94
97
 
package/bos CHANGED
@@ -1390,11 +1390,11 @@ prog
1390
1390
  })
1391
1391
 
1392
1392
  // Send funds to a destination
1393
- .command('send', 'Send funds to a node')
1393
+ .command('send', 'Send funds to a node off-chain')
1394
1394
  .help('Formulas supported in amount, and N*USD or N*EUR')
1395
1395
  .help('Also supported in formulas: LIQUIDITY, INBOUND, OUTBOUND (with peer)')
1396
1396
  .help('OUT_INBOUND, OUT_OUTBOUND (when specifying outbound peer)')
1397
- .argument('<to>', 'Send to node with public key')
1397
+ .argument('<to>', 'Send to node with public key, or zero amount pay request')
1398
1398
  .option('--amount <amount>', 'Amount to send to destination', STRING, '1')
1399
1399
  .option('--avoid <avoid>', 'Avoid forwarding via node/chan/tag', REPEATABLE)
1400
1400
  .option('--dryrun', 'Avoid actually sending funds')
@@ -1409,20 +1409,16 @@ prog
1409
1409
  .action((args, options, logger) => {
1410
1410
  return new Promise(async (resolve, reject) => {
1411
1411
  try {
1412
- const {lnd} = await lndForNode(logger, options.node);
1413
-
1414
- const destination = await lnSync.findKey({lnd, query: args.to});
1415
-
1416
1412
  return network.pushPayment({
1417
- lnd,
1418
1413
  logger,
1419
1414
  amount: options.amount,
1420
1415
  avoid: flatten([options.avoid].filter(n => !!n)),
1421
- destination: destination.public_key,
1416
+ destination: args.to,
1422
1417
  fs: {getFile: readFile},
1423
1418
  in_through: options.in,
1424
1419
  is_dry_run: options.dryrun,
1425
1420
  is_omitting_message_from: options.messageOmitFromKey,
1421
+ lnd: (await lndForNode(logger, options.node)).lnd,
1426
1422
  max_fee: options.maxFee,
1427
1423
  message: options.message,
1428
1424
  quiz_answers: flatten([options.quiz].filter(n => !!n)),
@@ -1587,6 +1583,7 @@ prog
1587
1583
  .help('Connect to a Telegram bot. Create bot: tg://resolve?domain=botfather')
1588
1584
  .help('After creating the bot start chatting with the bot for connect code')
1589
1585
  .help('Supported updates: forwards, received payments, etc')
1586
+ .help('Multiple nodes are supported by repeating the `--node` flag')
1590
1587
  .help('See README for info on persisting the bot through Docker/nohup')
1591
1588
  .option('--budget <amount>', 'Spending amount to allow', INT, Number())
1592
1589
  .option('--connect <connect_code>', 'Connection code', INT)
@@ -1639,7 +1636,7 @@ prog
1639
1636
  })
1640
1637
 
1641
1638
  // Transfer funds between own nodes
1642
- .command('transfer', 'Send funds to a saved node')
1639
+ .command('transfer', 'Send funds off-chain to a saved node')
1643
1640
  .argument('<to>', 'Saved node name')
1644
1641
  .argument('[amount]', 'Amount to transfer', STRING, '1')
1645
1642
  .help('Formulas are supported in amount')
package/network/pay.js CHANGED
@@ -82,6 +82,10 @@ module.exports = (args, cbk) => {
82
82
  return cbk([400, 'PaymentRequestExpired']);
83
83
  }
84
84
 
85
+ if (!BigInt(parsePaymentRequest({request: args.request}).mtokens)) {
86
+ return cbk([400, 'UseSendToPayZeroAmountPaymentRequests']);
87
+ }
88
+
85
89
  return cbk();
86
90
  },
87
91
 
@@ -157,6 +157,20 @@ module.exports = (args, cbk) => {
157
157
  return cbk([400, 'InvoiceIsExpired']);
158
158
  }
159
159
 
160
+ // Exit early when tokens are specified for a request
161
+ if (!!args.tokens) {
162
+ return cbk(null, {
163
+ cltv_delta: details.cltv_delta,
164
+ destination: details.destination,
165
+ features: details.features,
166
+ id: details.id,
167
+ mtokens: tokAsMtok(args.tokens),
168
+ payment: details.payment,
169
+ routes: details.routes,
170
+ tokens: args.tokens,
171
+ });
172
+ }
173
+
160
174
  args.logger.info({
161
175
  description: details.description || undefined,
162
176
  destination: details.destination,
@@ -175,8 +189,6 @@ module.exports = (args, cbk) => {
175
189
  routes: details.routes,
176
190
  tokens: details.tokens,
177
191
  });
178
-
179
- return cbk(null, parsePaymentRequest({request: args.request}));
180
192
  } catch (err) {
181
193
  return cbk([400, 'FailedToDecodePaymentRequest', {err}]);
182
194
  }
@@ -6,6 +6,7 @@ const {getIdentity} = require('ln-service');
6
6
  const {getNetwork} = require('ln-sync');
7
7
  const {getPeerLiquidity} = require('ln-sync');
8
8
  const {getPrices} = require('@alexbosworth/fiat');
9
+ const {parsePaymentRequest} = require('ln-service');
9
10
  const {returnResult} = require('asyncjs-util');
10
11
 
11
12
  const {getIgnores} = require('./../routing');
@@ -64,10 +65,6 @@ module.exports = (args, cbk) => {
64
65
  return cbk([400, 'ExpectedArrayOfAvoidDirectivesToSendPushPayment']);
65
66
  }
66
67
 
67
- if (!isPublicKey(args.destination)) {
68
- return cbk([400, 'ExpectedDestinationToPushPaymentTo']);
69
- }
70
-
71
68
  if (!args.fs) {
72
69
  return cbk([400, 'ExpectedFileSystemMethodsToPushPayment']);
73
70
  }
@@ -150,6 +147,33 @@ module.exports = (args, cbk) => {
150
147
  // Get tags for figuring out avoid flags
151
148
  getTags: ['validate', ({}, cbk) => getTags({fs: args.fs}, cbk)],
152
149
 
150
+ // Payment details
151
+ payment: ['validate', ({}, cbk) => {
152
+ try {
153
+ const {destination, mtokens} = parsePaymentRequest({
154
+ request: args.destination,
155
+ });
156
+
157
+ if (!!BigInt(mtokens)) {
158
+ return cbk([400, 'ExpectedZeroAmountPayRequestToSendFunds']);
159
+ }
160
+
161
+ return cbk(null, {destination, request: args.destination});
162
+ } catch (_) {
163
+ return findKey({
164
+ lnd: args.lnd,
165
+ query: args.destination,
166
+ },
167
+ (err, res) => {
168
+ if (!!err) {
169
+ return cbk(err);
170
+ }
171
+
172
+ return cbk(null, {destination: res.public_key, is_push: true});
173
+ });
174
+ }
175
+ }],
176
+
153
177
  // Get ignores
154
178
  getIgnores: [
155
179
  'getChannels',
@@ -241,11 +265,12 @@ module.exports = (args, cbk) => {
241
265
  'getChannels',
242
266
  'getNetwork',
243
267
  'getOutKey',
244
- ({fiatRates, getChannels, getNetwork, getOutKey}, cbk) =>
268
+ 'payment',
269
+ ({fiatRates, getChannels, getNetwork, getOutKey, payment}, cbk) =>
245
270
  {
246
271
  // Total remote balance including pending if pending fails
247
272
  const inbound = getChannels.channels
248
- .filter(n => n.partner_public_key === args.destination)
273
+ .filter(n => n.partner_public_key === payment.destination)
249
274
  .reduce((sum, chan) => {
250
275
  // Treat incoming payment as if they were still remote balance
251
276
  const inbound = chan.pending_payments.filter(n => !n.is_outgoing);
@@ -285,7 +310,7 @@ module.exports = (args, cbk) => {
285
310
 
286
311
  // Total local balance including pending if pending fails
287
312
  const outbound = getChannels.channels
288
- .filter(n => n.partner_public_key === args.destination)
313
+ .filter(n => n.partner_public_key === payment.destination)
289
314
  .reduce((sum, chan) => {
290
315
  // Treat outgoing payment as if they were still local balance
291
316
  const outbound = chan.pending_payments
@@ -307,7 +332,7 @@ module.exports = (args, cbk) => {
307
332
  eur: !!eur ? eur.unit : undefined,
308
333
  liquidity: sumOf(
309
334
  getChannels.channels
310
- .filter(n => n.partner_public_key === args.destination)
335
+ .filter(n => n.partner_public_key === payment.destination)
311
336
  .map(n => n.capacity)
312
337
  ),
313
338
  out_inbound: outInbound,
@@ -333,7 +358,8 @@ module.exports = (args, cbk) => {
333
358
  'getInKey',
334
359
  'getOutKey',
335
360
  'parseAmount',
336
- ({getIgnores, getInKey, getOutKey, parseAmount}, cbk) =>
361
+ 'payment',
362
+ ({getIgnores, getInKey, getOutKey, parseAmount, payment}, cbk) =>
337
363
  {
338
364
  if (parseAmount.tokens < minTokens) {
339
365
  return cbk([400, 'ExpectedNonZeroAmountToPushPayment']);
@@ -341,7 +367,7 @@ module.exports = (args, cbk) => {
341
367
 
342
368
  args.logger.info({
343
369
  paying: formatTokens({tokens: parseAmount.tokens}).display,
344
- to: args.destination,
370
+ to: payment.destination,
345
371
  });
346
372
 
347
373
  if (!!args.is_dry_run) {
@@ -349,14 +375,14 @@ module.exports = (args, cbk) => {
349
375
  }
350
376
 
351
377
  return probeDestination({
352
- destination: args.destination,
378
+ destination: payment.destination,
353
379
  fs: args.fs,
354
380
  ignore: getIgnores.ignore,
355
381
  lnd: args.lnd,
356
382
  logger: args.logger,
357
383
  in_through: getInKey,
358
384
  is_omitting_message_from: args.is_omitting_message_from,
359
- is_push: true,
385
+ is_push: payment.is_push,
360
386
  is_real_payment: true,
361
387
  max_fee: args.max_fee,
362
388
  message: args.message,
@@ -365,6 +391,7 @@ module.exports = (args, cbk) => {
365
391
  value: utf8AsHex(answer),
366
392
  })),
367
393
  out_through: getOutKey,
394
+ request: payment.request,
368
395
  timeout_minutes: args.timeout_minutes,
369
396
  tokens: parseAmount.tokens,
370
397
  },
package/package.json CHANGED
@@ -36,15 +36,15 @@
36
36
  "invoices": "2.0.2",
37
37
  "ln-accounting": "5.0.5",
38
38
  "ln-service": "53.2.0",
39
- "ln-sync": "3.6.0",
40
- "ln-telegram": "3.4.3",
39
+ "ln-sync": "3.6.1",
40
+ "ln-telegram": "3.5.0",
41
41
  "moment": "2.29.1",
42
- "paid-services": "3.4.0",
42
+ "paid-services": "3.5.1",
43
43
  "probing": "2.0.1",
44
44
  "psbt": "1.1.10",
45
45
  "qrcode-terminal": "0.12.0",
46
46
  "sanitize-filename": "1.6.3",
47
- "table": "6.7.5",
47
+ "table": "6.8.0",
48
48
  "update-notifier": "5.1.0",
49
49
  "window-size": "1.1.1"
50
50
  },
@@ -80,5 +80,5 @@
80
80
  "postpublish": "docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t alexbosworth/balanceofsatoshis --push .",
81
81
  "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"
82
82
  },
83
- "version": "11.18.1"
83
+ "version": "11.20.2"
84
84
  }
@@ -12,6 +12,7 @@ const {getTransactionRecord} = require('ln-sync');
12
12
  const {getWalletInfo} = require('ln-service');
13
13
  const {handleBackupCommand} = require('ln-telegram');
14
14
  const {handleBlocknotifyCommand} = require('ln-telegram');
15
+ const {handleButtonPush} = require('ln-telegram');
15
16
  const {handleConnectCommand} = require('ln-telegram');
16
17
  const {handleCostsCommand} = require('ln-telegram');
17
18
  const {handleEarningsCommand} = require('ln-telegram');
@@ -23,6 +24,7 @@ const {handlePendingCommand} = require('ln-telegram');
23
24
  const {handleVersionCommand} = require('ln-telegram');
24
25
  const {InputFile} = require('grammy');
25
26
  const inquirer = require('inquirer');
27
+ const {isMessageReplyToInvoice} = require('ln-telegram');
26
28
  const {notifyOfForwards} = require('ln-telegram');
27
29
  const {postChainTransaction} = require('ln-telegram');
28
30
  const {postClosedMessage} = require('ln-telegram');
@@ -38,6 +40,7 @@ const {subscribeToChannels} = require('ln-service');
38
40
  const {subscribeToInvoices} = require('ln-service');
39
41
  const {subscribeToPastPayments} = require('ln-service');
40
42
  const {subscribeToTransactions} = require('ln-service');
43
+ const {updateInvoiceFromReply} = require('ln-telegram');
41
44
 
42
45
  const interaction = require('./interaction');
43
46
  const markdown = {parse_mode: 'Markdown'};
@@ -298,19 +301,17 @@ module.exports = ({fs, id, limits, lnds, logger, payments, request}, cbk) => {
298
301
  return;
299
302
  });
300
303
 
301
- bot.command('invoice', ({message, reply}) => {
302
- handleInvoiceCommand({
303
- reply,
304
- request,
305
- from: message.from.id,
306
- id: connectedId,
307
- key: apiKey.key,
308
- nodes: allNodes,
309
- text: message.text,
310
- },
311
- err => !!err && !!err[0] >= 500 ? logger.error({err}) : null);
312
-
313
- return;
304
+ // Handle creation of an invoice
305
+ bot.command('invoice', async ctx => {
306
+ try {
307
+ await handleInvoiceCommand({
308
+ ctx,
309
+ id: connectedId,
310
+ nodes: getNodes,
311
+ });
312
+ } catch (err) {
313
+ logger.error({err});
314
+ }
314
315
  });
315
316
 
316
317
  bot.command('mempool', async ctx => {
@@ -425,7 +426,7 @@ module.exports = ({fs, id, limits, lnds, logger, payments, request}, cbk) => {
425
426
  '/connect - Connect bot',
426
427
  '/costs - View costs over the past week',
427
428
  '/earnings - View earnings over the past week',
428
- '/invoice - Make an invoice',
429
+ '/invoice [amount] [memo] - Make an invoice',
429
430
  '/liquidity [with] - View node liquidity',
430
431
  '/mempool - BTC mempool report',
431
432
  '/pay - Pay an invoice',
@@ -441,6 +442,32 @@ module.exports = ({fs, id, limits, lnds, logger, payments, request}, cbk) => {
441
442
  }
442
443
  });
443
444
 
445
+ // Handle button push type commands
446
+ bot.on('callback_query:data', async ctx => {
447
+ try {
448
+ await handleButtonPush({ctx, id: connectedId, nodes: getNodes});
449
+ } catch (err) {
450
+ logger.error({err});
451
+ }
452
+ });
453
+
454
+ // Listen for replies to created invoice messages
455
+ bot.on('message').filter(
456
+ ctx => isMessageReplyToInvoice({ctx, nodes: getNodes}),
457
+ async ctx => {
458
+ try {
459
+ return await updateInvoiceFromReply({
460
+ ctx,
461
+ api: bot.api,
462
+ id: connectedId,
463
+ nodes: getNodes,
464
+ });
465
+ } catch (err) {
466
+ logger.error({err});
467
+ }
468
+ },
469
+ );
470
+
444
471
  bot.start();
445
472
 
446
473
  return cbk();