balanceofsatoshis 25.3.1 → 25.4.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,11 @@
1
1
  # Versions
2
2
 
3
+ ## 25.4.0
4
+
5
+ - `accounting`: After 2021-10-19 derive USD prices from chain payments data
6
+ - `accounting`: Add `--rate-provider coinbase`
7
+ - `telegram`: Reduce telegram linkification in messages
8
+
3
9
  ## 25.3.1
4
10
 
5
11
  - `closed`: Avoid using external chain data lookups to derive resolution info
package/README.md CHANGED
@@ -7,8 +7,8 @@ Commands for working with LND balances.
7
7
 
8
8
  Supported LND versions:
9
9
 
10
- - v0.21.0-beta to v0.21.4-beta
11
- - v0.20.0-beta to v0.20.5-beta
10
+ - v0.21.0-beta to v0.21.5-beta
11
+ - v0.20.0-beta to v0.20.6-beta
12
12
 
13
13
  ## Install
14
14
 
@@ -298,6 +298,20 @@ If that is set, it will use that node if no node is specified.
298
298
  You can also add a JSON file to your .bos directory: config.json, add
299
299
  `{"default_saved_node": "nodename"}` to set the default via a file instead
300
300
 
301
+ ## Files in `~/.bos`
302
+
303
+ `bos` keeps its files in `~/.bos`, or in `BOS_DATA_PATH` when that is set:
304
+
305
+ - `chain_prices.json`: USD prices of BTC that `bos accounting` derived from
306
+ chain data, kept so that a day is only derived once. Prices are derived
307
+ this way when no `--rate-provider` is given, and the prices of the days
308
+ up to the release of `bos` come with it rather than being written here.
309
+ The file can be deleted, prices are then derived again when needed
310
+ - `config.json`: settings you add, like a default saved node
311
+ - `tags.json`: the tags made with `bos tags`
312
+ - `telegram_bot_api_key`: the bot API key that `bos telegram` asked for
313
+ - `YOUR_NODE_NAME/credentials.json`: the credentials of a saved node
314
+
301
315
  ## Linux Fu
302
316
 
303
317
  Some commands are designed to return outputs that can be piped or used in other CLI programs.
@@ -1,6 +1,11 @@
1
1
  {
2
+ "chainPricesFile": "chain_prices.json",
3
+ "coinbaseProvider": "coinbase",
2
4
  "defaultCurrency": "BTC",
3
5
  "defaultFiat": "USD",
6
+ "failedRequestErrors": ["UnexpectedErrorGettingCoinbaseCandles"],
7
+ "fsMethods": ["getFile", "makeDirectory", "renameFile", "writeFile"],
8
+ "mainnet": "btc",
4
9
  "notFoundIndex": -1,
5
10
  "monthNumbers": [
6
11
  "01",
@@ -25,5 +30,13 @@
25
30
  "11",
26
31
  "12"
27
32
  ],
28
- "monthOffset": 1
33
+ "monthOffset": 1,
34
+ "pricesFileErrors": [
35
+ "ExpectedPricesObjectInPricesFile",
36
+ "FailedToParsePricesFile",
37
+ "FailedToReadPricesFile",
38
+ "FailedToReplacePricesFile",
39
+ "FailedToWritePricesFile",
40
+ "UnsupportedPricesFileVersion"
41
+ ]
29
42
  }
@@ -1,11 +1,19 @@
1
1
  const asyncAuto = require('async/auto');
2
+ const {chainRates} = require('@alexbosworth/fiat');
2
3
  const {getAccountingReport} = require('ln-accounting');
3
4
  const {getNetwork} = require('ln-sync');
4
5
  const {returnResult} = require('asyncjs-util');
5
6
 
6
7
  const categories = require('./accounting_categories');
8
+ const {chainPricesFile} = require('./constants');
9
+ const {coinbaseProvider} = require('./constants');
7
10
  const {defaultCurrency} = require('./constants');
8
11
  const {defaultFiat} = require('./constants');
12
+ const {fsMethods} = require('./constants');
13
+ const getRecordRate = require('./get_record_rate');
14
+ const guardChainRate = require('./guard_chain_rate');
15
+ const {homePath} = require('./../storage');
16
+ const {mainnet} = require('./constants');
9
17
  const {monthNumbers} = require('./constants');
10
18
  const {monthOffset} = require('./constants');
11
19
  const {notFoundIndex} = require('./constants');
@@ -26,9 +34,16 @@ const summaryHeadings = ['Total', 'Asset', 'Report Date', 'Total Fiat'];
26
34
  [currency]: <Currency Label String>
27
35
  [date]: <Day of Month String>
28
36
  [fiat]: <Fiat Type String>
37
+ [fs]: {
38
+ getFile: <Read File Contents Function> (path, cbk) => {}
39
+ makeDirectory: <Make Directory Function> (path, cbk) => {}
40
+ renameFile: <Rename File Function> (from, to, cbk) => {}
41
+ writeFile: <Write File Contents Function> (path, contents, cbk) => {}
42
+ }
29
43
  [is_csv]: <Return CSV Output Bool>
30
44
  [is_fiat_disabled]: <Omit Fiat Conversion Bool>
31
45
  lnd: <Authenticated LND API Object>
46
+ [logger]: <Winston Logger Object>
32
47
  [month]: <Month for Report String>
33
48
  [node]: <Node Name String>
34
49
  [rate_provider]: <Rate Provider String>
@@ -47,6 +62,8 @@ module.exports = (args, cbk) => {
47
62
  return asyncAuto({
48
63
  // Validate
49
64
  validate: cbk => {
65
+ const {fs} = args;
66
+
50
67
  if (!args.category || !categories[args.category]) {
51
68
  return cbk([400, 'ExpectedKnownAccountingRecordsCategory']);
52
69
  }
@@ -55,6 +72,10 @@ module.exports = (args, cbk) => {
55
72
  return cbk([400, 'ExpectedMonthForDateToGetAccountingReport']);
56
73
  }
57
74
 
75
+ if (!!fs && !fsMethods.every(n => typeof fs[n] === 'function')) {
76
+ return cbk([400, 'ExpectedFileSystemMethodsToGetAccountingReport']);
77
+ }
78
+
58
79
  if (!args.lnd) {
59
80
  return cbk([400, 'ExpectedAuthenticatedLndToGetAccountingReport']);
60
81
  }
@@ -68,25 +89,88 @@ module.exports = (args, cbk) => {
68
89
 
69
90
  // Get date range
70
91
  dateRange: ['validate', ({}, cbk) => {
71
- try {
72
- return cbk(null, rangeForDate({
73
- date: args.date,
74
- month: args.month,
75
- year: args.year,
76
- }));
77
- } catch (err) {
78
- return cbk([400, err.message]);
92
+ const range = (() => {
93
+ try {
94
+ return {
95
+ value: rangeForDate({
96
+ date: args.date,
97
+ month: args.month,
98
+ year: args.year,
99
+ }),
100
+ };
101
+ } catch (err) {
102
+ return {err};
103
+ }
104
+ })();
105
+
106
+ // Exit early when the date range cannot be determined
107
+ if (!!range.err) {
108
+ return cbk([400, range.err.message]);
79
109
  }
110
+
111
+ return cbk(null, range.value);
80
112
  }],
81
113
 
82
114
  // Get the network name
83
115
  getNetwork: ['validate', ({}, cbk) => getNetwork({lnd: args.lnd}, cbk)],
84
116
 
117
+ // Make the method that gets chain prices, used without a rate provider
118
+ chain: ['getNetwork', ({getNetwork}, cbk) => {
119
+ // Exit early when fiat is disabled or a rate provider is specified
120
+ if (!!args.is_fiat_disabled || !!args.rate_provider) {
121
+ return cbk();
122
+ }
123
+
124
+ // Exit early when there are no chain prices for the network or no
125
+ // file system to keep them in
126
+ if (!args.fs || getNetwork.network !== mainnet) {
127
+ return cbk();
128
+ }
129
+
130
+ // Progress is only logged when it cannot end up in CSV output
131
+ const logger = !args.is_csv ? args.logger : undefined;
132
+
133
+ const {getChainRate} = chainRates({
134
+ logger,
135
+ fs: args.fs,
136
+ lnd: args.lnd,
137
+ path: homePath({file: chainPricesFile}).path,
138
+ });
139
+
140
+ return cbk(null, guardChainRate({getChainRate}));
141
+ }],
142
+
143
+ // Without a rate provider, records are valued with chain prices, and
144
+ // at their hour on Coinbase Exchange when chain prices cannot value them
145
+ rate: ['chain', ({chain}, cbk) => {
146
+ // Exit early when fiat is disabled
147
+ if (!!args.is_fiat_disabled) {
148
+ return cbk();
149
+ }
150
+
151
+ // Exit early when a rate provider other than Coinbase is specified
152
+ if (!!args.rate_provider && args.rate_provider !== coinbaseProvider) {
153
+ return cbk();
154
+ }
155
+
156
+ return cbk(null, {
157
+ rate: (record, cbk) => getRecordRate({
158
+ currency: record.currency,
159
+ date: record.date,
160
+ fiat: record.fiat,
161
+ get_chain_rate: !!chain ? chain.getChainRate : undefined,
162
+ request: args.request,
163
+ },
164
+ cbk),
165
+ });
166
+ }],
167
+
85
168
  // Get accounting info
86
169
  getAccounting: [
87
170
  'dateRange',
88
171
  'getNetwork',
89
- ({dateRange, getNetwork}, cbk) =>
172
+ 'rate',
173
+ ({dateRange, getNetwork, rate}, cbk) =>
90
174
  {
91
175
  return getAccountingReport({
92
176
  after: dateRange.after,
@@ -96,7 +180,8 @@ module.exports = (args, cbk) => {
96
180
  fiat: !args.is_fiat_disabled ? (args.fiat || defaultFiat) : null,
97
181
  lnd: args.lnd,
98
182
  network: getNetwork.network,
99
- rate_provider: args.rate_provider || undefined,
183
+ rate: !!rate ? rate.rate : undefined,
184
+ rate_provider: !rate ? args.rate_provider : undefined,
100
185
  request: args.request,
101
186
  },
102
187
  cbk);
@@ -0,0 +1,75 @@
1
+ const asyncAuto = require('async/auto');
2
+ const asyncRetry = require('async/retry');
3
+ const {getPrices} = require('@alexbosworth/fiat');
4
+ const {returnResult} = require('asyncjs-util');
5
+
6
+ const {failedRequestErrors} = require('./constants');
7
+
8
+ const isFailedRequest = err => !!err && failedRequestErrors.includes(err[1]);
9
+ const retryDelaysMs = [1000, 2000];
10
+ const supportedCurrency = 'BTC';
11
+
12
+ /** Get the fiat rate of BTC at the hour of a date from a rate provider
13
+
14
+ {
15
+ currency: <Currency Type String>
16
+ date: <ISO 8601 Date String>
17
+ fiat: <Fiat Type String>
18
+ from: <Rate Provider String>
19
+ request: <Request Function>
20
+ }
21
+
22
+ @returns via cbk or Promise
23
+ {
24
+ cents: <Cents Per BTC Number>
25
+ }
26
+ */
27
+ module.exports = ({currency, date, fiat, from, request}, cbk) => {
28
+ return new Promise((resolve, reject) => {
29
+ return asyncAuto({
30
+ // Check arguments
31
+ validate: cbk => {
32
+ if (currency !== supportedCurrency) {
33
+ return cbk([400, 'UnsupportedCurrencyToGetHistoricRate']);
34
+ }
35
+
36
+ if (!date) {
37
+ return cbk([400, 'ExpectedDateToGetHistoricRate']);
38
+ }
39
+
40
+ if (!fiat) {
41
+ return cbk([400, 'ExpectedFiatToGetHistoricRate']);
42
+ }
43
+
44
+ if (!from) {
45
+ return cbk([400, 'ExpectedRateProviderToGetHistoricRate']);
46
+ }
47
+
48
+ if (!request) {
49
+ return cbk([400, 'ExpectedRequestFunctionToGetHistoricRate']);
50
+ }
51
+
52
+ return cbk();
53
+ },
54
+
55
+ // Get the price at the hour of the date, trying a failed request again
56
+ getPrice: ['validate', ({}, cbk) => {
57
+ return asyncRetry({
58
+ errorFilter: isFailedRequest,
59
+ interval: count => retryDelaysMs[count - 1],
60
+ times: retryDelaysMs.length + 1,
61
+ },
62
+ cbk => getPrices({date, from, request, symbols: [fiat]}, cbk),
63
+ cbk);
64
+ }],
65
+
66
+ // The rate of the fiat
67
+ rate: ['getPrice', ({getPrice}, cbk) => {
68
+ const [ticker] = getPrice.tickers;
69
+
70
+ return cbk(null, {cents: ticker.rate});
71
+ }],
72
+ },
73
+ returnResult({reject, resolve, of: 'rate'}, cbk));
74
+ });
75
+ };
@@ -0,0 +1,77 @@
1
+ const asyncAuto = require('async/auto');
2
+ const {returnResult} = require('asyncjs-util');
3
+
4
+ const {coinbaseProvider} = require('./constants');
5
+ const getHistoricRate = require('./get_historic_rate');
6
+
7
+ /** Get the fiat rate of BTC for an accounting record
8
+
9
+ {
10
+ currency: <Currency Type String>
11
+ date: <Record ISO 8601 Date String>
12
+ fiat: <Fiat Type String>
13
+ [get_chain_rate]: <Get Chain Rate Function>
14
+ request: <Request Function>
15
+ }
16
+
17
+ @returns via cbk or Promise
18
+ {
19
+ cents: <Cents Per BTC Number>
20
+ }
21
+ */
22
+ module.exports = (args, cbk) => {
23
+ return new Promise((resolve, reject) => {
24
+ return asyncAuto({
25
+ // Check arguments
26
+ validate: cbk => {
27
+ if (!args.request) {
28
+ return cbk([400, 'ExpectedRequestFunctionToGetRecordRate']);
29
+ }
30
+
31
+ return cbk();
32
+ },
33
+
34
+ // Get the price derived from chain data
35
+ getChainRate: ['validate', ({}, cbk) => {
36
+ // Exit early when there are no chain prices
37
+ if (!args.get_chain_rate) {
38
+ return cbk();
39
+ }
40
+
41
+ return args.get_chain_rate({
42
+ currency: args.currency,
43
+ date: args.date,
44
+ fiat: args.fiat,
45
+ },
46
+ cbk);
47
+ }],
48
+
49
+ // Get the price at the hour of the record on Coinbase Exchange
50
+ getCoinbaseRate: ['getChainRate', ({getChainRate}, cbk) => {
51
+ // Exit early when the record has a chain price
52
+ if (!!getChainRate) {
53
+ return cbk();
54
+ }
55
+
56
+ return getHistoricRate({
57
+ currency: args.currency,
58
+ date: args.date,
59
+ fiat: args.fiat,
60
+ from: coinbaseProvider,
61
+ request: args.request,
62
+ },
63
+ cbk);
64
+ }],
65
+
66
+ // The rate of the record
67
+ rate: [
68
+ 'getChainRate',
69
+ 'getCoinbaseRate',
70
+ ({getChainRate, getCoinbaseRate}, cbk) =>
71
+ {
72
+ return cbk(null, {cents: (getChainRate || getCoinbaseRate).cents});
73
+ }],
74
+ },
75
+ returnResult({reject, resolve, of: 'rate'}, cbk));
76
+ });
77
+ };
@@ -0,0 +1,50 @@
1
+ const {pricesFileErrors} = require('./constants');
2
+
3
+ const isFileError = err => !!err && pricesFileErrors.includes(err[1]);
4
+
5
+ /** Make a chain rate lookup that only fails on prices file errors
6
+
7
+ {
8
+ getChainRate: <Get Chain Rate Function>
9
+ }
10
+
11
+ @returns
12
+ {
13
+ getChainRate: <Get Chain Rate Method> ({
14
+ currency: <Currency To Price String>
15
+ date: <Date To Price ISO 8601 Date String>
16
+ fiat: <Fiat Currency To Price In String>
17
+ }, cbk) => (err, [{
18
+ cents: <US Cents Per BTC Number>
19
+ }])
20
+ }
21
+ */
22
+ module.exports = ({getChainRate}) => {
23
+ const failure = {};
24
+
25
+ return {
26
+ getChainRate: (args, cbk) => {
27
+ // Exit early when the prices file failed, since it would fail again
28
+ if (!!failure.err) {
29
+ return cbk(failure.err);
30
+ }
31
+
32
+ return getChainRate(args, (err, res) => {
33
+ // Exit early when there is a chain price
34
+ if (!err) {
35
+ return cbk(null, res);
36
+ }
37
+
38
+ // Exit early without a price when chain prices cannot value the date
39
+ if (!isFileError(err)) {
40
+ return cbk();
41
+ }
42
+
43
+ // A prices file error is kept, as trying again cannot fix the file
44
+ failure.err = err;
45
+
46
+ return cbk(err);
47
+ });
48
+ },
49
+ };
50
+ };
package/bos CHANGED
@@ -70,6 +70,7 @@ prog
70
70
  .argument('<category>', 'Report category', keys(accountingCategories))
71
71
  .help(`Categories: ${keys(accountingCategories).join(', ')}`)
72
72
  .help(`Rate providers: ${rateProviders.join(', ')}`)
73
+ .help('By default fiat rates after 2021-10-19 use chain data derived rates')
73
74
  .help('Privacy note: this requests tx related data from third parties')
74
75
  .option('--csv', 'Output a CSV')
75
76
  .option('--date <day>', 'Show only records for specific date')
@@ -84,8 +85,15 @@ prog
84
85
  return new Promise(async (resolve, reject) => {
85
86
  try {
86
87
  return balances.getAccountingReport({
88
+ logger,
87
89
  category: args.category,
88
90
  date: options.date,
91
+ fs: {
92
+ writeFile,
93
+ getFile: readFile,
94
+ makeDirectory: mkdir,
95
+ renameFile: rename,
96
+ },
89
97
  is_csv: !!options.csv,
90
98
  is_fiat_disabled: options.disableFiat,
91
99
  lnd: (await lnd.authenticatedLnd({logger, node: options.node})).lnd,
@@ -25,6 +25,6 @@
25
25
  ],
26
26
  "priceProviders": ["coinbase", "coindesk", "coingecko"],
27
27
  "process": "bos",
28
- "rateProviders": ["coindesk", "coingecko"],
28
+ "rateProviders": ["coinbase", "coindesk", "coingecko"],
29
29
  "swapTypes": ["inbound", "outbound"]
30
30
  }
@@ -8,8 +8,10 @@ const {parse} = JSON;
8
8
  /** Simplified version of request method
9
9
 
10
10
  {
11
+ [headers]: <Request Headers Object>
11
12
  [json]: <Interpret Result as JSON Bool>
12
13
  [method]: <HTTPS Method String>
14
+ [qs]: <Query String Arguments Object>
13
15
  [timeout]: <Timeout MS Number>
14
16
  url: <HTTPS URL String>
15
17
  }
@@ -29,15 +31,28 @@ module.exports = (args, cbk) => {
29
31
  return cbk([400, 'ExpectedHttpsProtocolToExecuteSimpleRequest']);
30
32
  }
31
33
 
32
- let error;
34
+ let isFinished = false;
33
35
  const qs = url.searchParams;
34
36
 
37
+ // Call back once, since a request that times out also errors
38
+ const finish = (err, res, body) => {
39
+ // Exit early when the request has already called back
40
+ if (isFinished) {
41
+ return;
42
+ }
43
+
44
+ isFinished = true;
45
+
46
+ return cbk(err, res, body);
47
+ };
48
+
35
49
  // Include passed query string arguments
36
50
  if (!!args.qs) {
37
51
  keys(args.qs).forEach(key => qs.set(key, args.qs[key]));
38
52
  }
39
53
 
40
54
  const req = https.request({
55
+ headers: args.headers,
41
56
  hostname: url.hostname,
42
57
  method: args.method,
43
58
  path: url.pathname + asQueryString(qs.toString()),
@@ -50,31 +65,51 @@ module.exports = (args, cbk) => {
50
65
  // Collect response chunks
51
66
  res.on('data', data => body.push(data));
52
67
 
68
+ // A response that is cut off is an error
69
+ res.on('error', err => {
70
+ return finish([503, 'UnexpectedErrorReceivingSimpleRequest', {err}]);
71
+ });
72
+
53
73
  // Response is finished
54
74
  res.on('end', () => {
55
- if (!!error) {
56
- return cbk(err);
57
- }
58
-
59
75
  const combined = Buffer.concat(body).toString();
60
76
 
77
+ // Exit early when the response is not meant to be JSON
61
78
  if (!args.json) {
62
- return cbk(null, res, combined);
79
+ return finish(null, res, combined);
63
80
  }
64
81
 
65
- try {
66
- return cbk(null, res, parse(combined));
67
- } catch (err) {
68
- return cbk(err);
82
+ // Only the parsing is guarded, so the callback is called once
83
+ const parsed = (() => {
84
+ try {
85
+ return {json: parse(combined)};
86
+ } catch (err) {
87
+ return {err};
88
+ }
89
+ })();
90
+
91
+ // Exit early when the response is not JSON
92
+ if (!!parsed.err) {
93
+ return finish([503, 'ExpectedJsonResponseToSimpleRequest', {
94
+ err: parsed.err,
95
+ }]);
69
96
  }
97
+
98
+ return finish(null, res, parsed.json);
70
99
  });
71
100
  });
72
101
 
73
- req.on('error', err => error = err);
102
+ // A request that fails before it is answered is an error
103
+ req.on('error', err => {
104
+ return finish([503, 'UnexpectedErrorExecutingSimpleRequest', {err}]);
105
+ });
106
+
107
+ // A request that is not answered in time is an error
74
108
  req.on('timeout', () => {
75
- req.abort();
109
+ finish([503, 'RequestTimedOut']);
76
110
 
77
- return cbk([503, 'RequestTimedOut']);
111
+ // The request is stopped, and the error that comes of it is not passed on
112
+ return req.destroy();
78
113
  });
79
114
 
80
115
  req.end();
@@ -0,0 +1,28 @@
1
+ const {Encoder} = require('cbor');
2
+
3
+ const bufferAsHex = buffer => buffer.toString('hex');
4
+
5
+ /** Encode a value as CBOR
6
+
7
+ {
8
+ value: <Value to Encode Object>
9
+ }
10
+
11
+ @returns
12
+ {
13
+ cbor: <CBOR Encoded Hex String>
14
+ }
15
+ */
16
+ module.exports = ({value}) => {
17
+ const chunks = [];
18
+ const encoder = new Encoder();
19
+
20
+ // Gather the encoding as it is emitted, reading it later can cut it short
21
+ encoder.on('data', chunk => chunks.push(chunk));
22
+
23
+ encoder.pushAny(value);
24
+
25
+ encoder.end();
26
+
27
+ return {cbor: bufferAsHex(Buffer.concat(chunks))};
28
+ };
@@ -3,11 +3,11 @@ const {randomBytes} = require('crypto');
3
3
  const {scrypt} = require('crypto');
4
4
 
5
5
  const asyncAuto = require('async/auto');
6
- const {encode} = require('cbor');
7
6
  const {returnResult} = require('asyncjs-util');
8
7
 
8
+ const encodeAsCbor = require('./encode_as_cbor');
9
+
9
10
  const algorithm = 'aes-256-gcm';
10
- const cbor = n => encode(n).toString('hex');
11
11
  const derivation = 'scrypt';
12
12
  const digest = 'sha512';
13
13
  const fromHex = n => Buffer.from(n, 'hex');
@@ -37,7 +37,7 @@ module.exports = ({encoding, from, plain, secret, to}, cbk) => {
37
37
  // Check arguments
38
38
  validate: cbk => {
39
39
  if (!plain) {
40
- return cbk([400, 'ExectedDataToEncryptToSecret']);
40
+ return cbk([400, 'ExpectedDataToEncryptToSecret']);
41
41
  }
42
42
 
43
43
  if (!secret) {
@@ -90,7 +90,9 @@ module.exports = ({encoding, from, plain, secret, to}, cbk) => {
90
90
  const encrypted = Buffer.concat(updated);
91
91
  const tag = cipher.getAuthTag();
92
92
 
93
- return cbk(null, {cipher: cbor({encrypted, iv, salt, settings, tag})});
93
+ const value = {encrypted, iv, salt, settings, tag};
94
+
95
+ return cbk(null, {cipher: encodeAsCbor({value}).cbor});
94
96
  }],
95
97
  },
96
98
  returnResult({reject, resolve, of: 'encrypt'}, cbk));
@@ -2,6 +2,7 @@ const certExpiration = require('./cert_expiration');
2
2
  const decryptCiphertext = require('./decrypt_ciphertext');
3
3
  const decryptWithNode = require('./decrypt_with_node');
4
4
  const derAsPem = require('./der_as_pem');
5
+ const encodeAsCbor = require('./encode_as_cbor');
5
6
  const encryptToNode = require('./encrypt_to_node');
6
7
  const encryptToPublicKeys = require('./encrypt_to_public_keys');
7
8
  const pemAsDer = require('./pem_as_der');
@@ -11,6 +12,7 @@ module.exports = {
11
12
  decryptCiphertext,
12
13
  decryptWithNode,
13
14
  derAsPem,
15
+ encodeAsCbor,
14
16
  encryptToNode,
15
17
  encryptToPublicKeys,
16
18
  pemAsDer,
@@ -1,9 +1,9 @@
1
1
  const asyncAuto = require('async/auto');
2
- const {encode} = require('cbor');
3
2
  const {grantAccess} = require('ln-service');
4
3
  const moment = require('moment');
5
4
  const {returnResult} = require('asyncjs-util');
6
5
 
6
+ const {encodeAsCbor} = require('./../encryption');
7
7
  const lndCredentials = require('./lnd_credentials');
8
8
  const {pemAsDer} = require('./../encryption');
9
9
 
@@ -112,7 +112,7 @@ module.exports = (args, cbk) => {
112
112
  };
113
113
 
114
114
  return cbk(null, {
115
- exported_credentials: encode(credentials).toString('hex'),
115
+ exported_credentials: encodeAsCbor({value: credentials}).cbor,
116
116
  });
117
117
  }],
118
118
  },
package/package.json CHANGED
@@ -17,7 +17,7 @@
17
17
  "dependencies": {
18
18
  "@alexbosworth/blockchain": "4.12.0",
19
19
  "@alexbosworth/caporal": "2.0.0",
20
- "@alexbosworth/fiat": "2.0.0",
20
+ "@alexbosworth/fiat": "3.0.0",
21
21
  "@alexbosworth/formulas": "1.5.0",
22
22
  "@alexbosworth/html2unicode": "1.1.5",
23
23
  "asciichart": "1.5.25",
@@ -34,24 +34,24 @@
34
34
  "grammy": "1.46.0",
35
35
  "import-lazy": "4.0.0",
36
36
  "ini": "7.0.0",
37
- "inquirer": "14.2.3",
37
+ "inquirer": "14.2.5",
38
38
  "ln-accounting": "10.0.9",
39
- "ln-service": "60.1.6",
39
+ "ln-service": "60.1.8",
40
40
  "ln-sync": "8.0.9",
41
- "ln-telegram": "8.1.2",
41
+ "ln-telegram": "8.2.0",
42
42
  "moment": "2.31.0",
43
43
  "paid-services": "10.3.3",
44
- "probing": "7.0.1",
44
+ "probing": "7.0.2",
45
45
  "qrcode-terminal": "0.12.0",
46
46
  "sanitize-filename": "1.6.4",
47
47
  "socks-proxy-agent": "10.1.0",
48
48
  "table": "6.9.0",
49
- "tiny-secp256k1": "2.2.4",
49
+ "tiny-secp256k1": "2.2.5",
50
50
  "window-size": "1.1.1"
51
51
  },
52
52
  "description": "Lightning balance CLI",
53
53
  "devDependencies": {
54
- "invoices": "6.3.0",
54
+ "invoices": "6.3.3",
55
55
  "ln-docker-daemons": "8.1.3"
56
56
  },
57
57
  "engines": {
@@ -101,7 +101,7 @@
101
101
  "integration-tests": "node test/integration",
102
102
  "postpack": "PACKAGE_VERSION=$(cat package.json | grep \\\"version\\\" | head -1 | awk -F: '{ print $2 }' | sed 's/[\",]//g' | tr -d '[[:space:]]') && git tag -s v$PACKAGE_VERSION -m v$PACKAGE_VERSION && git push github --tags",
103
103
  "postpublish": "docker buildx build --platform linux/amd64,linux/arm64 -t alexbosworth/balanceofsatoshis -t alexbosworth/balanceofsatoshis:$npm_package_version --push .",
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"
104
+ "test": "node --experimental-test-coverage --test test/arrays/*.js test/balances/*.js test/chain/*.js test/commands/*.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"
105
105
  },
106
- "version": "25.3.1"
106
+ "version": "25.4.0"
107
107
  }
@@ -1,5 +1,4 @@
1
1
  const asyncAuto = require('async/auto');
2
- const {encode} = require('cbor');
3
2
  const {genericSwapAuth} = require('goldengate');
4
3
  const {genericSwapService} = require('goldengate');
5
4
  const {getNetwork} = require('ln-sync');
@@ -14,13 +13,13 @@ const {returnResult} = require('asyncjs-util');
14
13
  const {swapUserId} = require('goldengate');
15
14
 
16
15
  const decodeSwapApiKey = require('./decode_swap_api_key');
16
+ const {encodeAsCbor} = require('./../encryption');
17
17
 
18
18
  const bitcoinNetwork = 'btc';
19
19
  const bitcoinTestnetNetwork = 'btctestnet';
20
20
  const bufferFromBase64 = base64 => Buffer.from(base64, 'base64');
21
21
  const bufferFromHex = hex => Buffer.from(hex, 'hex');
22
22
  const connectError = 'FailedToConnectToService';
23
- const encodeCbor = json => encode(json).toString('hex');
24
23
  const httpMatch = /^https?:\/\//;
25
24
  const {isArray} = Array;
26
25
  const mainnetSocket = 'https://balanceofsatoshis.com:11011';
@@ -222,10 +221,13 @@ module.exports = ({fetch, lnd, socket, token}, cbk) => {
222
221
  const paid = payForMacaroon.tokens;
223
222
  const {service} = remote;
224
223
 
225
- const token = encodeCbor({
226
- macaroon: bufferFromBase64(getUnpaidMacaroon.macaroon),
227
- preimage: bufferFromHex(payForMacaroon.secret),
228
- });
224
+ const token = encodeAsCbor({
225
+ value: {
226
+ macaroon: bufferFromBase64(getUnpaidMacaroon.macaroon),
227
+ preimage: bufferFromHex(payForMacaroon.secret),
228
+ },
229
+ })
230
+ .cbor;
229
231
 
230
232
  return cbk(null, {id, metadata, paid, service, token});
231
233
  }],
@@ -1,9 +1,9 @@
1
1
  const asyncAuto = require('async/auto');
2
- const {encode} = require('cbor');
3
2
  const {returnResult} = require('asyncjs-util');
4
3
  const {swapUserId} = require('goldengate');
5
4
 
6
5
  const decodeSwapApiKey = require('./decode_swap_api_key');
6
+ const {encodeAsCbor} = require('./../encryption');
7
7
  const getPaidService = require('./get_paid_service');
8
8
 
9
9
  /** Purchase or inspect a swap API key
@@ -75,7 +75,7 @@ module.exports = (args, cbk) => {
75
75
  const preimage = Buffer.from(args.preimage, 'hex');
76
76
 
77
77
  return cbk(null, {
78
- api_key: encode({macaroon, preimage}).toString('hex'),
78
+ api_key: encodeAsCbor({value: {macaroon, preimage}}).cbor,
79
79
  id: swapUserId({macaroon: macaroon.toString('base64')}),
80
80
  });
81
81
  }],