balanceofsatoshis 11.43.0 → 11.46.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
@@ -1,5 +1,17 @@
1
1
  # Versions
2
2
 
3
+ ## 11.46.0
4
+
5
+ - `telegram`: Add `/stop` command to terminate the running bot
6
+
7
+ ## 11.45.1
8
+
9
+ - `increase-inbound-liquidity`: Add support for formulas in `--amount`
10
+
11
+ ## 11.44.0
12
+
13
+ - `send`: Add support for `--max-fee-rate` to limit fees paid via PPM measure
14
+
3
15
  ## 11.43.0
4
16
 
5
17
  - `limit-forwards`: Add `--min-channel-confirmations` for custom channel ages
@@ -0,0 +1,72 @@
1
+ # Contribution Guidelines
2
+
3
+ - Feel free to open issues or pull requests
4
+ - They may not be addressed or merged
5
+ - You can ignore coding styles if you want
6
+
7
+ ## Coding Style
8
+
9
+ If you want to help with style, here are some rough guidelines on style ideas:
10
+
11
+ ### Formatting
12
+
13
+ - Spaces not tabs, 2 spaces
14
+ - Arguments to methods are snake_case
15
+ - Regular variables are camelCase
16
+ - Returned attributes are snake_case
17
+ - Minimize function nesting, make new files if nesting is required
18
+ - No extraneous whitespace
19
+ - A single newline should appear at the end of a file
20
+ - Don't bother with () in functions when not needed: `const a = b => c`
21
+ - If there are multiple things together, alphabetize them
22
+ - Don't split up long strings over multiple lines
23
+ - Lines should be terminated by explicit semicolons
24
+ - Logic like ternary operators should not extend beyond a single line
25
+ - Don't let any lines linger when they don't do anything
26
+ - Tightly space objects, like `{attribute: value}` not `{ attribute : value }`
27
+ - Use single '' quotes not double "" quotes, except when `` is required
28
+ - If conditions should avoid spanning multiple lines
29
+ - Avoid double specifying an attribute and value, `{type: type}` vs `{type}`
30
+
31
+ ### Control Flow
32
+
33
+ - Async functions should support both cbk and Promise style
34
+ - Use async.js methods for asynchronous control flow
35
+ - Try to exit early from functions when possible, and note this exit in comment
36
+ - Prefer cbk over Promise style, aside from in tests or in Promise libs
37
+ - Use `asyncAuto` for asynchronous control flow dependency management
38
+ - Callbacks should generally be named cbk even when redefinining in inner scope
39
+ - Avoid mixing non-async complex logic and async control flows in the same file
40
+ - Minimize async nesting in returned attributes and in method arguments
41
+ - Methods should always document their arguments and their output
42
+
43
+ ### Variables
44
+
45
+ - Generally use undefined rather than null when defining nil types
46
+ - Prefer variable assignments on new lines rather than on a single line
47
+ - Reduce the usage of . property access, like isArray instead of Array.isArray
48
+ - When there is a newline in an object, always put a comma at the end of a line
49
+ - Short properties always go first in objects: `{short, longer: type}`
50
+ - If a statement relies on a statement above it, it should have a newline above
51
+ - Avoid including scalar values such as strings or numbers in the code itself
52
+
53
+ ### JS Features
54
+
55
+ - Limit usage of `let` and never use `var`, prefer `const`
56
+ - Limit use of npm dependencies when possible, only use good dependencies
57
+ - Target support of the oldest node.js LTS release still being supported
58
+ - Never use class or prototype
59
+ - Do not import more methods from an import than you actually use
60
+ - Try to avoid passing objects in arguments as much as possible
61
+ - Prefer using function iteration like map and forEach over for and while
62
+ - Use arrow functions and not `function` functions whenever possible
63
+
64
+ ### Errors
65
+
66
+ - Never ignore an error case, always deal with it as soon as possible
67
+ - In the case of errors, do include the error string in the code
68
+ - Add simple validations to help target simple calling mistakes
69
+ - When throwing or returning error messages, use PascalCase for the message
70
+ - Use HTTP status codes as a guideline: 4** is a local issue, 5** is remote
71
+ - Return async errors as arrays: `[typeNumber, errorMsgString, extraDetails]`
72
+ - Try to be very specific with error messages and try to not repeat one
package/bos CHANGED
@@ -25,6 +25,7 @@ const {accountingCategories} = commandConstants;
25
25
  const balances = importLazy('./balances');
26
26
  const chain = importLazy('./chain');
27
27
  const commands = importLazy('./commands');
28
+ const display = importLazy('./display');
28
29
  const encryption = importLazy('./encryption');
29
30
  const lnd = importLazy('./lnd');
30
31
  const network = importLazy('./network');
@@ -54,7 +55,6 @@ const months = [...Array(12).keys()].map(n => ++n);
54
55
  const {REPEATABLE} = prog;
55
56
  const {STRING} = prog;
56
57
  const yearMatch = /^\d{4}$/;
57
-
58
58
  prog
59
59
  .version(version)
60
60
 
@@ -884,10 +884,11 @@ prog
884
884
  .command('increase-inbound-liquidity', 'Increase node inbound liquidity')
885
885
  .help('Spend down a channel to get inbound. Fee is an estimate, may be more')
886
886
  .help('If you want to control chain fee increases, use show-raw-recoveries')
887
+ .help('Formulas supported for --amount like 5*m or 0.05*BTC for 5 million')
887
888
  .option('--address <out_address>', 'Out chain address to send funds out to')
888
889
  .option('--api-key <api_key>', 'Pre-paid API key to use')
890
+ .option('--amount <amount>', 'Amount to increase inbound', STRING, '500*k')
889
891
  .option('--avoid <pubkey/chan/tag>', 'Avoid forwarding through', REPEATABLE)
890
- .option('--amount <amount>', 'Amount to increase liquidity', INT, 5e5)
891
892
  .option('--confs <confs>', 'Confs to consider reorg safe', INT, 1)
892
893
  .option('--dryrun', 'Only show cost estimate for increase')
893
894
  .option('--fast', 'Request swap server avoid batching delay')
@@ -930,11 +931,11 @@ prog
930
931
  spend_address: options.spendAddress || undefined,
931
932
  spend_tokens: options.spendAmount || undefined,
932
933
  timeout: 1000 * 60 * 60 * 10,
933
- tokens: options.amount,
934
+ tokens: display.parseAmount({amount: options.amount}).tokens,
934
935
  },
935
936
  responses.returnObject({exit, logger, reject, resolve}));
936
937
  } catch (err) {
937
- return reject(err);
938
+ return reject(logger.error({err}));
938
939
  }
939
940
  });
940
941
  })
@@ -1464,6 +1465,7 @@ prog
1464
1465
  .option('--dryrun', 'Avoid actually sending funds')
1465
1466
  .option('--in <pubkey_or_alias>', 'Route in through a specific node')
1466
1467
  .option('--max-fee <fee>', 'Maximum fee tokens', INT, 1337)
1468
+ .option('--max-fee-rate <max_fee_rate>', 'Max fee rate in PPM to pay', INT)
1467
1469
  .option('--message <message>', 'Message to include with payment')
1468
1470
  .option('--message-omit-from-key', 'Leave out the from key on messages')
1469
1471
  .option('--no-color', 'Mute all colors')
@@ -1484,6 +1486,7 @@ prog
1484
1486
  is_omitting_message_from: options.messageOmitFromKey,
1485
1487
  lnd: (await lndForNode(logger, options.node)).lnd,
1486
1488
  max_fee: options.maxFee,
1489
+ max_fee_rate: options.maxFeeRate,
1487
1490
  message: options.message,
1488
1491
  quiz_answers: flatten([options.quiz].filter(n => !!n)),
1489
1492
  out_through: options.out,
@@ -16,6 +16,7 @@ const probeDestination = require('./probe_destination');
16
16
 
17
17
  const coins = ['BTC', 'LTC'];
18
18
  const defaultFiatRateProvider = 'coingecko';
19
+ const feeTokensForFeeRate = (tokens, rate) => Math.floor(rate * tokens / 1e6);
19
20
  const fiats = ['EUR', 'USD'];
20
21
  const hasFiat = n => /(eur|usd)/gim.test(n);
21
22
  const {isArray} = Array;
@@ -23,6 +24,7 @@ const isPublicKey = n => /^[0-9A-F]{66}$/i.test(n);
23
24
  const maxQuizLength = 10;
24
25
  const rateAsTokens = rate => 1e8 / rate;
25
26
  const sumOf = arr => arr.reduce((sum, n) => sum + n, Number());
27
+ const {min} = Math;
26
28
  const minQuiz = 2;
27
29
  const minTokens = 1;
28
30
  const networks = {btc: 'BTC', btctestnet: 'BTC', ltc: 'LTC'};
@@ -45,6 +47,7 @@ const utf8AsHex = n => Buffer.from(n, 'utf8').toString('hex');
45
47
  lnd: <Authenticated LND API Object>
46
48
  logger: <Winston Logger Object>
47
49
  max_fee: <Maximum Fee Tokens Number>
50
+ [max_fee_rate]: <Max Fee Rate Tokens Per Million Number>
48
51
  [message]: <Message to Include With Payment String>
49
52
  [out_through]: <Pay Out Through Peer String>
50
53
  quiz_answers: [<Quiz Answer String>]
@@ -346,7 +349,18 @@ module.exports = (args, cbk) => {
346
349
  };
347
350
 
348
351
  try {
349
- return cbk(null, parseAmount({variables, amount: args.amount}));
352
+ const {tokens} = parseAmount({variables, amount: args.amount});
353
+
354
+ // Exit early when there is no max fee rate to compute max fee for
355
+ if (!!args.max_fee_rate === undefined) {
356
+ return cbk(null, {tokens, max_fee: args.mage_fee});
357
+ }
358
+
359
+ // Compute the max potential fee given the max fee rate constraint
360
+ const maxFeeByRate = feeTokensForFeeRate(tokens, args.max_fee_rate);
361
+
362
+ // The maximum fee to pay is the lower of the fee limit, fee by rate
363
+ return cbk(null, {tokens, max_fee: min(args.max_fee, maxFeeByRate)});
350
364
  } catch (err) {
351
365
  return cbk([400, 'FailedToParsePushAmount', err]);
352
366
  }
@@ -384,7 +398,7 @@ module.exports = (args, cbk) => {
384
398
  is_omitting_message_from: args.is_omitting_message_from,
385
399
  is_push: payment.is_push,
386
400
  is_real_payment: true,
387
- max_fee: args.max_fee,
401
+ max_fee: parseAmount.max_fee,
388
402
  message: args.message,
389
403
  messages: args.quiz_answers.map((answer, i) => ({
390
404
  type: (quizStart + i).toString(),
package/package.json CHANGED
@@ -28,7 +28,7 @@
28
28
  "crypto-js": "4.1.1",
29
29
  "csv-parse": "5.0.4",
30
30
  "goldengate": "11.0.0",
31
- "grammy": "1.6.2",
31
+ "grammy": "1.7.0",
32
32
  "hot-formula-parser": "4.0.0",
33
33
  "import-lazy": "4.0.0",
34
34
  "ini": "2.0.0",
@@ -37,7 +37,7 @@
37
37
  "ln-accounting": "5.0.5",
38
38
  "ln-service": "53.6.0",
39
39
  "ln-sync": "3.9.0",
40
- "ln-telegram": "3.12.0",
40
+ "ln-telegram": "3.13.0",
41
41
  "moment": "2.29.1",
42
42
  "paid-services": "3.11.0",
43
43
  "probing": "2.0.2",
@@ -52,7 +52,7 @@
52
52
  "description": "Lightning balance CLI",
53
53
  "devDependencies": {
54
54
  "@alexbosworth/tap": "15.0.10",
55
- "ln-docker-daemons": "2.2.2",
55
+ "ln-docker-daemons": "2.2.3",
56
56
  "mock-lnd": "1.4.1",
57
57
  "secp256k1": "4.0.3"
58
58
  },
@@ -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.43.0"
84
+ "version": "11.46.0"
85
85
  }
@@ -25,6 +25,7 @@ const {handleMempoolCommand} = require('ln-telegram');
25
25
  const {handlePayCommand} = require('ln-telegram');
26
26
  const {handlePendingCommand} = require('ln-telegram');
27
27
  const {handleStartCommand} = require('ln-telegram');
28
+ const {handleStopCommand} = require('ln-telegram');
28
29
  const {handleVersionCommand} = require('ln-telegram');
29
30
  const {InputFile} = require('grammy');
30
31
  const inquirer = require('inquirer');
@@ -272,6 +273,7 @@ module.exports = (args, cbk) => {
272
273
  {command: 'mempool', description: 'Get info about the mempool'},
273
274
  {command: 'pay', description: 'Pay a payment request'},
274
275
  {command: 'pending', description: 'Get pending forwards, channels'},
276
+ {command: 'stop', description: 'Stop the bot'},
275
277
  {command: 'version', description: 'View current bot version'},
276
278
  ]);
277
279
 
@@ -457,6 +459,22 @@ module.exports = (args, cbk) => {
457
459
  });
458
460
  });
459
461
 
462
+ // Terminate the running bot
463
+ bot.command('stop', async ctx => {
464
+ try {
465
+ await handleStopCommand({
466
+ from: ctx.message.from.id,
467
+ id: connectedId,
468
+ quit: () => bot.stop(),
469
+ reply: (msg, mode) => ctx.reply(msg, mode),
470
+ });
471
+
472
+ process.exit();
473
+ } catch (err) {
474
+ logger.error({err});
475
+ }
476
+ });
477
+
460
478
  bot.command('version', async ctx => {
461
479
  try {
462
480
  await handleVersionCommand({
@@ -481,6 +499,7 @@ module.exports = (args, cbk) => {
481
499
  '/mempool - BTC mempool report',
482
500
  '/pay - Pay an invoice',
483
501
  '/pending - View pending channels, probes, and forwards',
502
+ '/stop - Stop bot',
484
503
  '/version - View the current bot version',
485
504
  ];
486
505
 
@@ -599,15 +618,14 @@ module.exports = (args, cbk) => {
599
618
  return postClosedMessage({
600
619
  from,
601
620
  lnd,
602
- request,
603
621
  capacity: update.capacity,
604
622
  id: connectedId,
605
623
  is_breach_close: update.is_breach_close,
606
624
  is_cooperative_close: update.is_cooperative_close,
607
625
  is_local_force_close: update.is_local_force_close,
608
626
  is_remote_force_close: update.is_remote_force_close,
609
- key: apiKey.key,
610
627
  partner_public_key: update.partner_public_key,
628
+ send: (id, message) => bot.api.sendMessage(id, message, markdown),
611
629
  },
612
630
  err => !!err ? logger.error({node: from, closed_err: err}) : null);
613
631
  });
@@ -616,13 +634,12 @@ module.exports = (args, cbk) => {
616
634
  return postOpenMessage({
617
635
  from,
618
636
  lnd,
619
- request,
620
637
  capacity: update.capacity,
621
638
  id: connectedId,
622
639
  is_partner_initiated: update.is_partner_initiated,
623
640
  is_private: update.is_private,
624
- key: apiKey.key,
625
641
  partner_public_key: update.partner_public_key,
642
+ send: (id, message) => bot.api.sendMessage(id, message, markdown),
626
643
  },
627
644
  err => !!err ? logger.error({open_err: err}) : null);
628
645
  });
@@ -899,10 +916,9 @@ module.exports = (args, cbk) => {
899
916
 
900
917
  return await postChainTransaction({
901
918
  from,
902
- request,
903
919
  confirmed: transaction.is_confirmed,
904
920
  id: connectedId,
905
- key: apiKey.key,
921
+ send: (id, message) => bot.api.sendMessage(id, message, markdown),
906
922
  transaction: record,
907
923
  });
908
924
  } catch (err) {