balanceofsatoshis 25.3.1 → 25.5.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 +10 -0
- package/README.md +17 -3
- package/balances/constants.json +14 -1
- package/balances/get_accounting_report.js +95 -10
- package/balances/get_historic_rate.js +75 -0
- package/balances/get_record_rate.js +77 -0
- package/balances/guard_chain_rate.js +50 -0
- package/bos +10 -0
- package/chain/fund_transaction.js +10 -9
- package/chain/get_block_transactions.js +6 -5
- package/chain/recover_p2pk.js +5 -4
- package/chain/split_utxos.js +5 -4
- package/commands/constants.json +1 -1
- package/commands/fetch_request.js +32 -24
- package/commands/simple_request.js +48 -13
- package/display/get_icons.js +33 -22
- package/encryption/cbor_item_head.js +45 -0
- package/encryption/decode_cbor.js +35 -0
- package/encryption/decode_cbor_item.js +169 -0
- package/encryption/decrypt_with_node.js +21 -18
- package/encryption/decrypt_with_secret.js +5 -4
- package/encryption/encode_as_cbor.js +21 -0
- package/encryption/encode_cbor_item.js +90 -0
- package/encryption/encrypt_to_secret.js +6 -4
- package/encryption/index.js +4 -0
- package/lnd/get_credentials.js +2 -2
- package/lnd/get_socket.js +11 -10
- package/lnurl/auth.js +6 -5
- package/network/get_peers.js +9 -4
- package/network/probe.js +2 -0
- package/network/probe_destination.js +97 -68
- package/network/push_payment.js +42 -17
- package/network/send_gift.js +10 -9
- package/network/transfer_funds.js +6 -6
- package/nodes/register_node.js +34 -30
- package/offchain/create_invoice.js +21 -16
- package/offchain/get_invoice_amount.js +5 -4
- package/offchain/sign_payment_request.js +10 -9
- package/package.json +10 -11
- package/peers/detect_open_rule_violation.js +6 -5
- package/routing/get_chain_fees_chart.js +3 -2
- package/routing/get_fees_paid.js +30 -12
- package/services/initiate_balanced_channel.js +13 -7
- package/swaps/append_failing_edge.js +6 -5
- package/swaps/decode_swap_api_key.js +29 -25
- package/swaps/get_paid_service.js +46 -23
- package/swaps/get_routes_for_funding.js +52 -11
- package/swaps/get_swap_service.js +5 -4
- package/swaps/rebalance.js +78 -63
- package/swaps/swap_api_key.js +2 -2
- package/swaps/swap_in.js +36 -26
- package/tags/get_tags.js +26 -15
- package/telegram/connect_to_telegram.js +17 -12
- package/telegram/get_socks_proxy.js +12 -13
- package/telegram/get_telegram_bot.js +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# Versions
|
|
2
2
|
|
|
3
|
+
## 25.5.0
|
|
4
|
+
|
|
5
|
+
- `probe`: Add `--ignore-expiry` to probe expired payment requests
|
|
6
|
+
|
|
7
|
+
## 25.4.0
|
|
8
|
+
|
|
9
|
+
- `accounting`: After 2021-10-19 derive USD prices from chain payments data
|
|
10
|
+
- `accounting`: Add `--rate-provider coinbase`
|
|
11
|
+
- `telegram`: Reduce telegram linkification in messages
|
|
12
|
+
|
|
3
13
|
## 25.3.1
|
|
4
14
|
|
|
5
15
|
- `closed`: Avoid using external chain data lookups to derive resolution info
|
package/README.md
CHANGED
|
@@ -7,12 +7,12 @@ Commands for working with LND balances.
|
|
|
7
7
|
|
|
8
8
|
Supported LND versions:
|
|
9
9
|
|
|
10
|
-
- v0.21.0-beta to v0.21.
|
|
11
|
-
- v0.20.0-beta to v0.20.
|
|
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
|
|
|
15
|
-
- Requires an [installation of Node
|
|
15
|
+
- Requires an [installation of Node.js v22+][nodejs-install-guide]
|
|
16
16
|
|
|
17
17
|
```shell
|
|
18
18
|
npm install -g balanceofsatoshis
|
|
@@ -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.
|
package/balances/constants.json
CHANGED
|
@@ -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
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
@@ -1649,6 +1657,7 @@ prog
|
|
|
1649
1657
|
.option('--avoid <avoid>', 'Avoid forwarding via node/chan/tag', REPEATABLE)
|
|
1650
1658
|
.option('--avoid-high-fee-routes', 'Avoid evaluating too-high fee routes')
|
|
1651
1659
|
.option('--find-max', 'Find the maximum routeable amount on success route')
|
|
1660
|
+
.option('--ignore-expiry', 'Probe even when the request has expired')
|
|
1652
1661
|
.option('--in <public_key>', 'Route through specific peer of destination')
|
|
1653
1662
|
.option('--max-fee <max_fee>', 'Max expected fee for route', INT, 1337)
|
|
1654
1663
|
.option('--max-paths <max>', 'Maximum paths to use for find-max', INT, 1)
|
|
@@ -1671,6 +1680,7 @@ prog
|
|
|
1671
1680
|
find_max: !!options.findMax ? 16777215 : undefined,
|
|
1672
1681
|
fs: {getFile: readFile},
|
|
1673
1682
|
in_through: inThrough.public_key,
|
|
1683
|
+
is_ignoring_expiry: !!options.ignoreExpiry,
|
|
1674
1684
|
is_strict_max_fee: !!options.avoidHighFeeRoutes,
|
|
1675
1685
|
max_fee: options.maxFee,
|
|
1676
1686
|
max_paths: options.maxPaths,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const asyncAuto = require('async/auto');
|
|
2
2
|
const asyncEach = require('async/each');
|
|
3
|
+
const asyncify = require('async/asyncify');
|
|
3
4
|
const {broadcastTransaction} = require('ln-sync');
|
|
4
5
|
const {componentsOfTransaction} = require('@alexbosworth/blockchain');
|
|
5
6
|
const {formatTokens} = require('ln-sync');
|
|
@@ -112,10 +113,10 @@ module.exports = (args, cbk) => {
|
|
|
112
113
|
getNetwork: ['validate', ({}, cbk) => getNetwork({lnd: args.lnd}, cbk)],
|
|
113
114
|
|
|
114
115
|
// Derive a list of outputs to guide input selection
|
|
115
|
-
outputs: ['validate', (
|
|
116
|
+
outputs: ['validate', asyncify(() => {
|
|
116
117
|
// Exit early when the amount is open ended and thus depends on inputs
|
|
117
118
|
if (hasMaxAmount(args.amounts)) {
|
|
118
|
-
return
|
|
119
|
+
return;
|
|
119
120
|
}
|
|
120
121
|
|
|
121
122
|
try {
|
|
@@ -125,11 +126,11 @@ module.exports = (args, cbk) => {
|
|
|
125
126
|
return {address, tokens};
|
|
126
127
|
});
|
|
127
128
|
|
|
128
|
-
return
|
|
129
|
+
return outputs;
|
|
129
130
|
} catch (err) {
|
|
130
|
-
|
|
131
|
+
throw [400, err.message];
|
|
131
132
|
}
|
|
132
|
-
}],
|
|
133
|
+
})],
|
|
133
134
|
|
|
134
135
|
// Get UTXOs to use for input selection and final fee rate calculation
|
|
135
136
|
getUtxos: ['validate', ({}, cbk) => getUtxos({lnd: args.lnd}, cbk)],
|
|
@@ -238,7 +239,7 @@ module.exports = (args, cbk) => {
|
|
|
238
239
|
}],
|
|
239
240
|
|
|
240
241
|
// Parse amounts and put together the final set of outputs
|
|
241
|
-
finalOutputs: ['getMax', ({getMax}
|
|
242
|
+
finalOutputs: ['getMax', asyncify(({getMax}) => {
|
|
242
243
|
try {
|
|
243
244
|
const outputs = args.addresses.map((address, i) => {
|
|
244
245
|
const amount = args.amounts[i];
|
|
@@ -252,11 +253,11 @@ module.exports = (args, cbk) => {
|
|
|
252
253
|
return {address, tokens: parseAmount({amount, variables}).tokens};
|
|
253
254
|
});
|
|
254
255
|
|
|
255
|
-
return
|
|
256
|
+
return outputs;
|
|
256
257
|
} catch (err) {
|
|
257
|
-
|
|
258
|
+
throw [400, err.message];
|
|
258
259
|
}
|
|
259
|
-
}],
|
|
260
|
+
})],
|
|
260
261
|
|
|
261
262
|
// Create a funded PSBT
|
|
262
263
|
fund: [
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const asyncAuto = require('async/auto');
|
|
2
|
+
const asyncify = require('async/asyncify');
|
|
2
3
|
const {getBlock} = require('ln-service');
|
|
3
4
|
const {queryTransactions} = require('@alexbosworth/blockchain');
|
|
4
5
|
const {returnResult} = require('asyncjs-util');
|
|
@@ -77,10 +78,10 @@ module.exports = (args, cbk) => {
|
|
|
77
78
|
}],
|
|
78
79
|
|
|
79
80
|
// Find the transactions in the block
|
|
80
|
-
transactions: ['getBlock', ({getBlock}
|
|
81
|
+
transactions: ['getBlock', asyncify(({getBlock}) => {
|
|
81
82
|
// Exit early when there is no block to look through
|
|
82
83
|
if (!getBlock.block) {
|
|
83
|
-
return
|
|
84
|
+
return {transactions: []};
|
|
84
85
|
}
|
|
85
86
|
|
|
86
87
|
try {
|
|
@@ -89,11 +90,11 @@ module.exports = (args, cbk) => {
|
|
|
89
90
|
ids: args.ids,
|
|
90
91
|
});
|
|
91
92
|
|
|
92
|
-
return
|
|
93
|
+
return {transactions};
|
|
93
94
|
} catch (err) {
|
|
94
|
-
|
|
95
|
+
throw [503, 'UnexpectedErrorParsingBlockTransactions', {err}];
|
|
95
96
|
}
|
|
96
|
-
}],
|
|
97
|
+
})],
|
|
97
98
|
},
|
|
98
99
|
returnResult({reject, resolve, of: 'transactions'}, cbk));
|
|
99
100
|
});
|
package/chain/recover_p2pk.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const {createHash} = require('crypto');
|
|
2
2
|
|
|
3
3
|
const asyncAuto = require('async/auto');
|
|
4
|
+
const asyncify = require('async/asyncify');
|
|
4
5
|
const {broadcastChainTransaction} = require('ln-service');
|
|
5
6
|
const {componentsOfTransaction} = require('@alexbosworth/blockchain');
|
|
6
7
|
const {createChainAddress} = require('ln-service');
|
|
@@ -135,7 +136,7 @@ module.exports = ({id, lnd, request, vout}, cbk) => {
|
|
|
135
136
|
recoveryScript: [
|
|
136
137
|
'createAddress',
|
|
137
138
|
'getNetwork',
|
|
138
|
-
({createAddress, getNetwork}
|
|
139
|
+
asyncify(({createAddress, getNetwork}) =>
|
|
139
140
|
{
|
|
140
141
|
try {
|
|
141
142
|
const {script} = outputScriptForAddress({
|
|
@@ -143,11 +144,11 @@ module.exports = ({id, lnd, request, vout}, cbk) => {
|
|
|
143
144
|
network: getNetwork.network,
|
|
144
145
|
});
|
|
145
146
|
|
|
146
|
-
return
|
|
147
|
+
return {script};
|
|
147
148
|
} catch (err) {
|
|
148
|
-
|
|
149
|
+
throw [503, 'FailedToParseRecoveryAddress', {err}];
|
|
149
150
|
}
|
|
150
|
-
}],
|
|
151
|
+
})],
|
|
151
152
|
|
|
152
153
|
// Derive the sweep output, less the amount needed to pay for chain fees
|
|
153
154
|
sweep: [
|
package/chain/split_utxos.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const asyncAuto = require('async/auto');
|
|
2
2
|
const asyncEach = require('async/each');
|
|
3
|
+
const asyncify = require('async/asyncify');
|
|
3
4
|
const asyncMapSeries = require('async/mapSeries');
|
|
4
5
|
const asyncReflect = require('async/reflect');
|
|
5
6
|
const {broadcastChainTransaction} = require('ln-service');
|
|
@@ -85,7 +86,7 @@ module.exports = (args, cbk) => {
|
|
|
85
86
|
getUtxos: ['validate', ({}, cbk) => getUtxos({lnd: args.lnd}, cbk)],
|
|
86
87
|
|
|
87
88
|
// Select the inputs and the count of outputs that reach the count
|
|
88
|
-
plan: ['feeRate', 'getUtxos', ({feeRate, getUtxos}
|
|
89
|
+
plan: ['feeRate', 'getUtxos', asyncify(({feeRate, getUtxos}) => {
|
|
89
90
|
try {
|
|
90
91
|
const plan = utxoSplitPlan({
|
|
91
92
|
count: args.count,
|
|
@@ -95,11 +96,11 @@ module.exports = (args, cbk) => {
|
|
|
95
96
|
utxos: getUtxos.utxos,
|
|
96
97
|
});
|
|
97
98
|
|
|
98
|
-
return
|
|
99
|
+
return plan;
|
|
99
100
|
} catch (err) {
|
|
100
|
-
|
|
101
|
+
throw [400, err.message];
|
|
101
102
|
}
|
|
102
|
-
}],
|
|
103
|
+
})],
|
|
103
104
|
|
|
104
105
|
// Generate addresses
|
|
105
106
|
getAddresses: ['plan', ({plan}, cbk) => {
|
package/commands/constants.json
CHANGED