balanceofsatoshis 11.34.0 → 11.36.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 +8 -0
- package/bos +5 -0
- package/network/get_graph_entry.js +56 -2
- package/package.json +4 -3
- package/telegram/connect_to_telegram.js +2 -0
- package/telegram/start_telegram_bot.js +67 -20
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Versions
|
|
2
2
|
|
|
3
|
+
## 11.36.2
|
|
4
|
+
|
|
5
|
+
- `telegram`: Add support for `--use-proxy` to specify a SOCKS proxy server
|
|
6
|
+
|
|
7
|
+
## 11.35.0
|
|
8
|
+
|
|
9
|
+
- `graph`: Add `HOPS` variable to `--filter` for node peer distance from self
|
|
10
|
+
|
|
3
11
|
## 11.34.0
|
|
4
12
|
|
|
5
13
|
- `telegram`: Allow switching the node of a trade-secret
|
package/bos
CHANGED
|
@@ -761,6 +761,8 @@ prog
|
|
|
761
761
|
// Get the edges of a given node
|
|
762
762
|
.command('graph', 'List out the connections a node has with other nodes')
|
|
763
763
|
.argument('<alias_or_public_key>', 'Node in the graph to look up')
|
|
764
|
+
.help('--filter variables: AGE/CAPACITY/HOPS/IN_FEE_RATE/OUT_FEE_RATE')
|
|
765
|
+
.help('Example: --filter "age<7*144" for connections in the last week')
|
|
764
766
|
.option('--filter <formula>', 'Filter formula to apply', REPEATABLE)
|
|
765
767
|
.option('--node <node_name>', 'Node to use for lookup')
|
|
766
768
|
.option('--sort <sort_connections_by', 'Sort peers by field')
|
|
@@ -1605,11 +1607,13 @@ prog
|
|
|
1605
1607
|
.help('Supported updates: forwards, received payments, etc')
|
|
1606
1608
|
.help('Multiple nodes are supported by repeating the `--node` flag')
|
|
1607
1609
|
.help('See README for info on persisting the bot through Docker/nohup')
|
|
1610
|
+
.help('--use-proxy requires path to JSON file for host/password/port/userId')
|
|
1608
1611
|
.option('--budget <amount>', 'Spending amount to allow', INT, Number())
|
|
1609
1612
|
.option('--connect <connect_code>', 'Connection code', INT)
|
|
1610
1613
|
.option('--ignore-forwards-below <amount>', 'Ignore forwards of value', INT)
|
|
1611
1614
|
.option('--node <node_name>', 'Node to connect to Telegram', REPEATABLE)
|
|
1612
1615
|
.option('--reset-api-key', 'Reset the Telegram API key')
|
|
1616
|
+
.option('--use-proxy <path>', 'Proxy agent to connect to Telegram')
|
|
1613
1617
|
.action((args, options, logger) => {
|
|
1614
1618
|
return new Promise(async (resolve, reject) => {
|
|
1615
1619
|
try {
|
|
@@ -1626,6 +1630,7 @@ prog
|
|
|
1626
1630
|
min_forward_tokens: options.ignoreForwardsBelow || undefined,
|
|
1627
1631
|
nodes: flatten([options.node].filter(n => !!n)),
|
|
1628
1632
|
payments: {limit: options.budget},
|
|
1633
|
+
proxy: options.useProxy || undefined,
|
|
1629
1634
|
request: commands.fetchRequest({fetch}),
|
|
1630
1635
|
});
|
|
1631
1636
|
} catch (err) {
|
|
@@ -9,6 +9,7 @@ const {getHeight} = require('ln-service');
|
|
|
9
9
|
const {getNetworkGraph} = require('ln-service');
|
|
10
10
|
const {getNode} = require('ln-service');
|
|
11
11
|
const {getNodeAlias} = require('ln-sync');
|
|
12
|
+
const {getRouteToDestination} = require('ln-service');
|
|
12
13
|
const moment = require('moment');
|
|
13
14
|
const {returnResult} = require('asyncjs-util');
|
|
14
15
|
|
|
@@ -24,7 +25,10 @@ const defaultSort = 'age';
|
|
|
24
25
|
const disableTag = isDisabled => isDisabled ? `${emojiIcons.disabled} ` : '';
|
|
25
26
|
const displayFee = (n, rate) => n.length ? formatFeeRate({rate}).display : ' ';
|
|
26
27
|
const displayTokens = tokens => formatTokens({tokens}).display;
|
|
28
|
+
const distanceTokens = 100;
|
|
29
|
+
const hasDistanceFilter = filters => /hops/gim.test(filters.join(' '));
|
|
27
30
|
const header = [['Alias','Age','In Fee','Capacity','Out Fee','Public Key']];
|
|
31
|
+
const hopsTitle = 'Hops';
|
|
28
32
|
const {isArray} = Array;
|
|
29
33
|
const isClear = sockets => !!sockets.find(n => !!isIP(n.socket.split(':')[0]));
|
|
30
34
|
const isLarge = features => !!features.find(n => n.type === 'large_channels');
|
|
@@ -144,17 +148,49 @@ module.exports = ({filters, fs, lnd, logger, query, sort}, cbk) => {
|
|
|
144
148
|
return cbk();
|
|
145
149
|
}],
|
|
146
150
|
|
|
151
|
+
// Get distances
|
|
152
|
+
getDistances: ['peerKeys', ({peerKeys}, cbk) => {
|
|
153
|
+
// Exit early when there is no distance filter
|
|
154
|
+
if (!hasDistanceFilter(filters)) {
|
|
155
|
+
return cbk(null, peerKeys.map(destination => ({destination})));
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return asyncMap(peerKeys, (destination, cbk) => {
|
|
159
|
+
return getRouteToDestination({
|
|
160
|
+
destination,
|
|
161
|
+
lnd,
|
|
162
|
+
is_ignoring_past_failure: true,
|
|
163
|
+
tokens: distanceTokens,
|
|
164
|
+
},
|
|
165
|
+
(err, res) => {
|
|
166
|
+
if (!!err) {
|
|
167
|
+
return cbk(err);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (!res.route) {
|
|
171
|
+
return cbk(null, {destination, hops: Infinity});
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return cbk(null, {destination, hops: --res.route.hops.length});
|
|
175
|
+
});
|
|
176
|
+
},
|
|
177
|
+
cbk);
|
|
178
|
+
}],
|
|
179
|
+
|
|
147
180
|
// Final set of peers
|
|
148
181
|
peers: [
|
|
182
|
+
'getDistances',
|
|
149
183
|
'getHeight',
|
|
150
184
|
'getIcons',
|
|
151
185
|
'getNode',
|
|
152
186
|
'peerKeys',
|
|
153
|
-
({getHeight, getIcons, getNode, peerKeys}, cbk) =>
|
|
187
|
+
({getDistances, getHeight, getIcons, getNode, peerKeys}, cbk) =>
|
|
154
188
|
{
|
|
155
189
|
const sorting = sort || defaultSort;
|
|
156
190
|
|
|
157
191
|
const peers = peerKeys.map(peerKey => {
|
|
192
|
+
const {hops} = getDistances.find(n => n.destination === peerKey);
|
|
193
|
+
|
|
158
194
|
const capacity = getNode.channels
|
|
159
195
|
.filter(n => !!n.policies.find(n => n.public_key === peerKey))
|
|
160
196
|
.reduce((sum, {capacity}) => sum + capacity, Number());
|
|
@@ -192,6 +228,7 @@ module.exports = ({filters, fs, lnd, logger, query, sort}, cbk) => {
|
|
|
192
228
|
filters,
|
|
193
229
|
variables: {
|
|
194
230
|
capacity,
|
|
231
|
+
hops,
|
|
195
232
|
age: getHeight.current_block_height - connectHeight,
|
|
196
233
|
height: connectHeight,
|
|
197
234
|
in_fee_rate: inboundFeeRate,
|
|
@@ -217,6 +254,10 @@ module.exports = ({filters, fs, lnd, logger, query, sort}, cbk) => {
|
|
|
217
254
|
peerKey,
|
|
218
255
|
];
|
|
219
256
|
|
|
257
|
+
if (!!hasDistanceFilter(filters)) {
|
|
258
|
+
row.unshift(hops);
|
|
259
|
+
}
|
|
260
|
+
|
|
220
261
|
return {sorts, row};
|
|
221
262
|
})
|
|
222
263
|
.filter(n => !!n);
|
|
@@ -258,7 +299,20 @@ module.exports = ({filters, fs, lnd, logger, query, sort}, cbk) => {
|
|
|
258
299
|
|
|
259
300
|
// Final set of rows
|
|
260
301
|
rows: ['getRowsWithAliases', ({getRowsWithAliases}, cbk) => {
|
|
261
|
-
|
|
302
|
+
const [titles] = header;
|
|
303
|
+
|
|
304
|
+
const headers = titles.slice();
|
|
305
|
+
|
|
306
|
+
if (!!hasDistanceFilter(filters)) {
|
|
307
|
+
const first = headers.shift();
|
|
308
|
+
|
|
309
|
+
headers.unshift(hopsTitle);
|
|
310
|
+
headers.unshift(first);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
const rows = [].concat([headers]).concat(getRowsWithAliases);
|
|
314
|
+
|
|
315
|
+
return cbk(null, {rows});
|
|
262
316
|
}],
|
|
263
317
|
},
|
|
264
318
|
returnResult({reject, resolve, of: 'rows'}, cbk));
|
package/package.json
CHANGED
|
@@ -37,13 +37,14 @@
|
|
|
37
37
|
"ln-accounting": "5.0.5",
|
|
38
38
|
"ln-service": "53.5.2",
|
|
39
39
|
"ln-sync": "3.7.0",
|
|
40
|
-
"ln-telegram": "3.
|
|
40
|
+
"ln-telegram": "3.11.0",
|
|
41
41
|
"moment": "2.29.1",
|
|
42
42
|
"paid-services": "3.11.0",
|
|
43
43
|
"probing": "2.0.2",
|
|
44
|
-
"psbt": "1.1.
|
|
44
|
+
"psbt": "1.1.11",
|
|
45
45
|
"qrcode-terminal": "0.12.0",
|
|
46
46
|
"sanitize-filename": "1.6.3",
|
|
47
|
+
"socks-proxy-agent": "6.1.1",
|
|
47
48
|
"table": "6.8.0",
|
|
48
49
|
"update-notifier": "5.1.0",
|
|
49
50
|
"window-size": "1.1.1"
|
|
@@ -80,5 +81,5 @@
|
|
|
80
81
|
"postpublish": "docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t alexbosworth/balanceofsatoshis --push .",
|
|
81
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"
|
|
82
83
|
},
|
|
83
|
-
"version": "11.
|
|
84
|
+
"version": "11.36.2"
|
|
84
85
|
}
|
|
@@ -29,6 +29,7 @@ const restartDelayMs = 1000 * 60 * 3;
|
|
|
29
29
|
payments: {
|
|
30
30
|
[limit]: <Total Spendable Budget Tokens Limit Number>
|
|
31
31
|
}
|
|
32
|
+
[proxy]: <Path to Proxy JSON File String>
|
|
32
33
|
request: <Request Function>
|
|
33
34
|
}
|
|
34
35
|
|
|
@@ -114,6 +115,7 @@ module.exports = (args, cbk) => {
|
|
|
114
115
|
},
|
|
115
116
|
logger: args.logger,
|
|
116
117
|
payments: {limit},
|
|
118
|
+
proxy: args.proxy,
|
|
117
119
|
request: args.request,
|
|
118
120
|
},
|
|
119
121
|
err => {
|
|
@@ -18,6 +18,7 @@ const {handleButtonPush} = require('ln-telegram');
|
|
|
18
18
|
const {handleConnectCommand} = require('ln-telegram');
|
|
19
19
|
const {handleCostsCommand} = require('ln-telegram');
|
|
20
20
|
const {handleEarningsCommand} = require('ln-telegram');
|
|
21
|
+
const {handleEditedMessage} = require('ln-telegram');
|
|
21
22
|
const {handleInvoiceCommand} = require('ln-telegram');
|
|
22
23
|
const {handleLiquidityCommand} = require('ln-telegram');
|
|
23
24
|
const {handleMempoolCommand} = require('ln-telegram');
|
|
@@ -39,6 +40,7 @@ const {postUpdatedBackup} = require('ln-telegram');
|
|
|
39
40
|
const {returnResult} = require('asyncjs-util');
|
|
40
41
|
const {sendMessage} = require('ln-telegram');
|
|
41
42
|
const {serviceAnchoredTrades} = require('paid-services');
|
|
43
|
+
const SocksProxyAgent = require('socks-proxy-agent');
|
|
42
44
|
const {subscribeToBackups} = require('ln-service');
|
|
43
45
|
const {subscribeToBlocks} = require('goldengate');
|
|
44
46
|
const {subscribeToChannels} = require('ln-service');
|
|
@@ -47,7 +49,6 @@ const {subscribeToPastPayments} = require('ln-service');
|
|
|
47
49
|
const {subscribeToTransactions} = require('ln-service');
|
|
48
50
|
|
|
49
51
|
const interaction = require('./interaction');
|
|
50
|
-
const markdown = {parse_mode: 'Markdown'};
|
|
51
52
|
const named = require('./../package').name;
|
|
52
53
|
const {version} = require('./../package');
|
|
53
54
|
|
|
@@ -61,9 +62,11 @@ const home = '.bos';
|
|
|
61
62
|
const {isArray} = Array;
|
|
62
63
|
const isNumber = n => !isNaN(n);
|
|
63
64
|
const limit = 99999;
|
|
65
|
+
const markdown = {parse_mode: 'Markdown'};
|
|
64
66
|
const maxCommandDelayMs = 1000 * 10;
|
|
65
67
|
const msSince = epoch => Date.now() - (epoch * 1e3);
|
|
66
68
|
const network = 'btc';
|
|
69
|
+
const {parse} = JSON;
|
|
67
70
|
const restartSubscriptionTimeMs = 1000 * 30;
|
|
68
71
|
const sanitize = n => (n || '').replace(/_/g, '\\_').replace(/[*~`]/g, '');
|
|
69
72
|
|
|
@@ -85,12 +88,15 @@ const sanitize = n => (n || '').replace(/_/g, '\\_').replace(/[*~`]/g, '');
|
|
|
85
88
|
payments: {
|
|
86
89
|
[limit]: <Total Spendable Budget Tokens Limit Number>
|
|
87
90
|
}
|
|
91
|
+
[proxy]: <Path to Proxy JSON File String>
|
|
88
92
|
request: <Request Function>
|
|
89
93
|
}
|
|
90
94
|
|
|
91
95
|
@returns via cbk or Promise
|
|
92
96
|
*/
|
|
93
|
-
module.exports = (
|
|
97
|
+
module.exports = (args, cbk) => {
|
|
98
|
+
const {fs, id, limits, lnds, logger, payments, request} = args;
|
|
99
|
+
|
|
94
100
|
let connectedId = id;
|
|
95
101
|
let isStopped = false;
|
|
96
102
|
let paymentsLimit = !payments || !payments.limit ? Number() : payments.limit;
|
|
@@ -169,6 +175,45 @@ module.exports = ({fs, id, limits, lnds, logger, payments, request}, cbk) => {
|
|
|
169
175
|
cbk);
|
|
170
176
|
}],
|
|
171
177
|
|
|
178
|
+
// Get proxy agent
|
|
179
|
+
getProxyAgent: ['validate', ({}, cbk) => {
|
|
180
|
+
// Exit early if not using a proxy
|
|
181
|
+
if (!args.proxy) {
|
|
182
|
+
return cbk();
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return args.fs.getFile(args.proxy, (err, res) => {
|
|
186
|
+
if (!!err) {
|
|
187
|
+
return cbk([503, 'FailedToFindFileAtProxySpecifiedPath', {err}]);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (!res) {
|
|
191
|
+
return cbk([503, 'ExpectedFileDataAtProxySpecifiedPath']);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
try {
|
|
195
|
+
parse(res.toString());
|
|
196
|
+
} catch (err) {
|
|
197
|
+
return cbk([503, 'ExpectedValidJsonConfigFileForProxy']);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const {host, password, port, userId} = parse(res);
|
|
201
|
+
|
|
202
|
+
try {
|
|
203
|
+
const socksAgent = new SocksProxyAgent({
|
|
204
|
+
host,
|
|
205
|
+
password,
|
|
206
|
+
port,
|
|
207
|
+
userId,
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
return cbk(null, socksAgent);
|
|
211
|
+
} catch (err) {
|
|
212
|
+
return cbk([503, 'FailedToCreateSocksProxyAgent', {err}]);
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
}],
|
|
216
|
+
|
|
172
217
|
// Save API key
|
|
173
218
|
saveKey: ['apiKey', ({apiKey}, cbk) => {
|
|
174
219
|
// Exit early when API key is already saved
|
|
@@ -192,7 +237,12 @@ module.exports = ({fs, id, limits, lnds, logger, payments, request}, cbk) => {
|
|
|
192
237
|
}],
|
|
193
238
|
|
|
194
239
|
// Setup the bot start action
|
|
195
|
-
initBot: [
|
|
240
|
+
initBot: [
|
|
241
|
+
'apiKey',
|
|
242
|
+
'getNodes',
|
|
243
|
+
'getProxyAgent',
|
|
244
|
+
({apiKey, getNodes, getProxyAgent}, cbk) =>
|
|
245
|
+
{
|
|
196
246
|
allNodes = getNodes;
|
|
197
247
|
|
|
198
248
|
// Exit early when bot is already instantiated
|
|
@@ -200,7 +250,14 @@ module.exports = ({fs, id, limits, lnds, logger, payments, request}, cbk) => {
|
|
|
200
250
|
return cbk();
|
|
201
251
|
}
|
|
202
252
|
|
|
203
|
-
bot
|
|
253
|
+
// Initiate bot using proxy agent when configured
|
|
254
|
+
if (!!getProxyAgent) {
|
|
255
|
+
bot = new Bot(apiKey.key, {
|
|
256
|
+
client: {baseFetchConfig: {agent: getProxyAgent, compress: true}},
|
|
257
|
+
});
|
|
258
|
+
} else {
|
|
259
|
+
bot = new Bot(apiKey.key);
|
|
260
|
+
}
|
|
204
261
|
|
|
205
262
|
bot.api.setMyCommands([
|
|
206
263
|
{command: 'backup', description: 'Get node backup file'},
|
|
@@ -219,18 +276,11 @@ module.exports = ({fs, id, limits, lnds, logger, payments, request}, cbk) => {
|
|
|
219
276
|
|
|
220
277
|
bot.catch(err => logger.error({telegram_error: err}));
|
|
221
278
|
|
|
222
|
-
bot.use((ctx, next) => {
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
// Warn on edit of old message
|
|
229
|
-
if (!!ctx.update && !!ctx.update.edited_message) {
|
|
230
|
-
const {text} = ctx.update.edited_message;
|
|
231
|
-
const warning = interaction.edit_message_warning;
|
|
232
|
-
|
|
233
|
-
return ctx.reply(`${warning}\n${text}`, markdown);
|
|
279
|
+
bot.use(async (ctx, next) => {
|
|
280
|
+
try {
|
|
281
|
+
await handleEditedMessage({ctx});
|
|
282
|
+
} catch (err) {
|
|
283
|
+
logger.error({err});
|
|
234
284
|
}
|
|
235
285
|
|
|
236
286
|
return next();
|
|
@@ -239,7 +289,6 @@ module.exports = ({fs, id, limits, lnds, logger, payments, request}, cbk) => {
|
|
|
239
289
|
bot.command('backup', ctx => {
|
|
240
290
|
handleBackupCommand({
|
|
241
291
|
logger,
|
|
242
|
-
request,
|
|
243
292
|
from: ctx.message.from.id,
|
|
244
293
|
id: connectedId,
|
|
245
294
|
key: apiKey.key,
|
|
@@ -337,12 +386,10 @@ module.exports = ({fs, id, limits, lnds, logger, payments, request}, cbk) => {
|
|
|
337
386
|
},
|
|
338
387
|
}, async () => {
|
|
339
388
|
await handleLiquidityCommand({
|
|
340
|
-
request,
|
|
341
389
|
from: ctx.message.from.id,
|
|
342
390
|
id: connectedId,
|
|
343
|
-
key: apiKey.key,
|
|
344
391
|
nodes: allNodes,
|
|
345
|
-
reply: ctx.reply,
|
|
392
|
+
reply: n => ctx.reply(n, markdown),
|
|
346
393
|
text: ctx.message.text,
|
|
347
394
|
working: () => ctx.replyWithChatAction('typing'),
|
|
348
395
|
});
|