balanceofsatoshis 25.4.0 → 25.6.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 +8 -0
- package/README.md +4 -1
- package/bos +49 -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/fetch_request.js +32 -24
- package/display/describe_routing_failure.js +6 -2
- 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 +5 -12
- package/encryption/encode_cbor_item.js +90 -0
- package/encryption/index.js +2 -0
- package/lnd/get_socket.js +11 -10
- package/lnurl/auth.js +6 -5
- package/lnurl/get_pay_request.js +8 -3
- package/lnurl/get_pay_terms.js +12 -3
- package/lnurl/parse_url.js +18 -4
- package/network/constants.json +1 -0
- package/network/execute_probe.js +14 -11
- package/network/get_out_channels.js +128 -0
- package/network/get_out_queries.js +102 -0
- package/network/get_peers.js +9 -4
- package/network/get_stream_invoice.js +95 -0
- package/network/get_stream_route.js +153 -0
- package/network/index.js +2 -0
- package/network/line_writer.js +29 -0
- package/network/pay_stream_route.js +103 -0
- 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/stream_payment.js +591 -0
- 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 +5 -6
- 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 +38 -17
- 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_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,13 @@
|
|
|
1
1
|
# Versions
|
|
2
2
|
|
|
3
|
+
## 25.6.0
|
|
4
|
+
|
|
5
|
+
- `stream`: Add command to stream a payment to a lnurl or lightning address
|
|
6
|
+
|
|
7
|
+
## 25.5.0
|
|
8
|
+
|
|
9
|
+
- `probe`: Add `--ignore-expiry` to probe expired payment requests
|
|
10
|
+
|
|
3
11
|
## 25.4.0
|
|
4
12
|
|
|
5
13
|
- `accounting`: After 2021-10-19 derive USD prices from chain payments data
|
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@ Supported LND versions:
|
|
|
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
|
|
@@ -168,6 +168,9 @@ bos send
|
|
|
168
168
|
# Run a server of paid services
|
|
169
169
|
bos server
|
|
170
170
|
|
|
171
|
+
# Stream a payment to a lnurl or lightning address in a series of payments
|
|
172
|
+
bos stream "amount" --lnurl "lnurl/lightning_address"
|
|
173
|
+
|
|
171
174
|
# Connect up to a Telegram bot
|
|
172
175
|
bos telegram
|
|
173
176
|
|
package/bos
CHANGED
|
@@ -1657,6 +1657,7 @@ prog
|
|
|
1657
1657
|
.option('--avoid <avoid>', 'Avoid forwarding via node/chan/tag', REPEATABLE)
|
|
1658
1658
|
.option('--avoid-high-fee-routes', 'Avoid evaluating too-high fee routes')
|
|
1659
1659
|
.option('--find-max', 'Find the maximum routeable amount on success route')
|
|
1660
|
+
.option('--ignore-expiry', 'Probe even when the request has expired')
|
|
1660
1661
|
.option('--in <public_key>', 'Route through specific peer of destination')
|
|
1661
1662
|
.option('--max-fee <max_fee>', 'Max expected fee for route', INT, 1337)
|
|
1662
1663
|
.option('--max-paths <max>', 'Maximum paths to use for find-max', INT, 1)
|
|
@@ -1679,6 +1680,7 @@ prog
|
|
|
1679
1680
|
find_max: !!options.findMax ? 16777215 : undefined,
|
|
1680
1681
|
fs: {getFile: readFile},
|
|
1681
1682
|
in_through: inThrough.public_key,
|
|
1683
|
+
is_ignoring_expiry: !!options.ignoreExpiry,
|
|
1682
1684
|
is_strict_max_fee: !!options.avoidHighFeeRoutes,
|
|
1683
1685
|
max_fee: options.maxFee,
|
|
1684
1686
|
max_paths: options.maxPaths,
|
|
@@ -1952,6 +1954,53 @@ prog
|
|
|
1952
1954
|
});
|
|
1953
1955
|
})
|
|
1954
1956
|
|
|
1957
|
+
// Stream a payment in a series of payments
|
|
1958
|
+
.command('stream', 'Stream a payment in a series of payments')
|
|
1959
|
+
.help('Each payment is sized to the most a single route can carry')
|
|
1960
|
+
.help('--lnurl is required, it can stream above the max the service takes')
|
|
1961
|
+
.help('--min-payment defaults to 100*k, a smaller remainder is not sent')
|
|
1962
|
+
.help('--out can take a tag to make the first hop through any tagged peer')
|
|
1963
|
+
.help('--out-filter is checked before every payment, skipping failing peers')
|
|
1964
|
+
.help('--out-filter vars: CAPACITY/HEIGHTS/INBOUND_LIQUIDITY')
|
|
1965
|
+
.help('--out-filter vars: OUTBOUND_LIQUIDITY/PENDING_PAYMENTS')
|
|
1966
|
+
.help('--out-filter vars: INBOUND_BASE_FEE/INBOUND_FEE_RATE')
|
|
1967
|
+
.help('Amounts can take m/k variables: 5*m for 5 million, 250*k = 0.0025')
|
|
1968
|
+
.argument('<amount>', 'Total amount to stream')
|
|
1969
|
+
.option('--avoid <avoid>', 'Avoid forwarding via node/chan/tag', REPEATABLE)
|
|
1970
|
+
.option('--lnurl <url>', 'Lnurl/lightning address', STRING, undefined, true)
|
|
1971
|
+
.option('--max-fee <max_fee>', 'Maximum total fee to pay', STRING, '1337')
|
|
1972
|
+
.option('--max-fee-rate <ppm>', 'Max fee rate for all payments', INT, 1000)
|
|
1973
|
+
.option('--max-payment <amount>', 'Largest single payment to make', STRING)
|
|
1974
|
+
.option('--min-payment <amount>', 'Smallest single payment to make', STRING)
|
|
1975
|
+
.option('--no-color', 'Mute all colors')
|
|
1976
|
+
.option('--node <node_name>', 'Node to stream from')
|
|
1977
|
+
.option('--out <peer_or_tag>', 'Make first hop through peer/tag', REPEATABLE)
|
|
1978
|
+
.option('--out-filter <out_filter>', 'Filter outbound peer/tag', REPEATABLE)
|
|
1979
|
+
.action((args, options, logger) => {
|
|
1980
|
+
return new Promise(async (resolve, reject) => {
|
|
1981
|
+
try {
|
|
1982
|
+
return network.streamPayment({
|
|
1983
|
+
logger,
|
|
1984
|
+
amount: args.amount,
|
|
1985
|
+
avoid: flatten([options.avoid].filter(n => !!n)),
|
|
1986
|
+
fs: {getFile: readFile},
|
|
1987
|
+
lnd: (await lndForNode(logger, options.node)).lnd,
|
|
1988
|
+
lnurl: options.lnurl,
|
|
1989
|
+
max_fee: options.maxFee,
|
|
1990
|
+
max_fee_rate: options.maxFeeRate,
|
|
1991
|
+
max_payment: options.maxPayment,
|
|
1992
|
+
min_payment: options.minPayment,
|
|
1993
|
+
out: flatten([options.out].filter(n => !!n)),
|
|
1994
|
+
out_filters: flatten([options.outFilter].filter(n => !!n)),
|
|
1995
|
+
request: commands.simpleRequest,
|
|
1996
|
+
},
|
|
1997
|
+
responses.returnObject({logger, reject, resolve}));
|
|
1998
|
+
} catch (err) {
|
|
1999
|
+
return logger.error({err}) && reject();
|
|
2000
|
+
}
|
|
2001
|
+
});
|
|
2002
|
+
})
|
|
2003
|
+
|
|
1955
2004
|
// Get a swap API key or inspect an existing one
|
|
1956
2005
|
.command('swap-api-key', 'Purchase a swap API key or inspect a swap API key')
|
|
1957
2006
|
.visible(false)
|
|
@@ -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) => {
|
|
@@ -10,14 +10,12 @@ const timeoutSignals = new WeakMap();
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
@returns
|
|
13
|
-
{
|
|
14
|
-
request: <Request Function>
|
|
15
|
-
}
|
|
13
|
+
<Request Function> (args, cbk) => {}
|
|
16
14
|
*/
|
|
17
15
|
module.exports = ({fetch}, cbk) => {
|
|
18
16
|
return (options, cbk) => {
|
|
19
17
|
(async () => {
|
|
20
|
-
|
|
18
|
+
const controller = new AbortController();
|
|
21
19
|
|
|
22
20
|
// Setup the timeout controller
|
|
23
21
|
if (!!options.timeout) {
|
|
@@ -28,30 +26,40 @@ module.exports = ({fetch}, cbk) => {
|
|
|
28
26
|
|
|
29
27
|
const url = options.url + encodeQs(options.qs);
|
|
30
28
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
29
|
+
// Only the request is guarded, so the callback is called once
|
|
30
|
+
const fetched = await (async () => {
|
|
31
|
+
try {
|
|
32
|
+
// Make the request
|
|
33
|
+
const response = await fetch(url, {
|
|
34
|
+
body: options.body || undefined,
|
|
35
|
+
method: options.method || undefined,
|
|
36
|
+
signal: controller.signal,
|
|
37
|
+
});
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
const res = {statusCode: response.status};
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
41
|
+
// Exit early when the response is JSON
|
|
42
|
+
if (!!options.json) {
|
|
43
|
+
return {res, body: await response.json()};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return {res, body: await response.text()};
|
|
47
|
+
} catch (err) {
|
|
48
|
+
return {err};
|
|
49
|
+
} finally {
|
|
50
|
+
// Reset the timeout since the request is over
|
|
51
|
+
if (!!options.timeout) {
|
|
52
|
+
clearTimeout(timeoutSignals.get(controller.signal));
|
|
53
|
+
}
|
|
53
54
|
}
|
|
55
|
+
})();
|
|
56
|
+
|
|
57
|
+
// Exit early when the request failed
|
|
58
|
+
if (!!fetched.err) {
|
|
59
|
+
return cbk(fetched.err);
|
|
54
60
|
}
|
|
61
|
+
|
|
62
|
+
return cbk(null, fetched.res, fetched.body);
|
|
55
63
|
})();
|
|
56
64
|
};
|
|
57
65
|
};
|
|
@@ -108,6 +108,7 @@ module.exports = ({index, lnd, reason, route, tagged}, cbk) => {
|
|
|
108
108
|
|
|
109
109
|
const {display} = chartAliasForPeer({
|
|
110
110
|
alias: getTo.alias,
|
|
111
|
+
icons: !!tag ? tag.icons : undefined,
|
|
111
112
|
public_key: getTo.id,
|
|
112
113
|
});
|
|
113
114
|
|
|
@@ -120,11 +121,14 @@ module.exports = ({index, lnd, reason, route, tagged}, cbk) => {
|
|
|
120
121
|
'toName',
|
|
121
122
|
({fromName, toName}, cbk) =>
|
|
122
123
|
{
|
|
123
|
-
const
|
|
124
|
+
const hop = route.hops[index];
|
|
125
|
+
|
|
126
|
+
// A failure at the destination is not on a channel out of it
|
|
127
|
+
const at = !hop ? '' : ` on ${hop.channel}`;
|
|
124
128
|
const from = !fromName ? '' : `from ${fromName}`;
|
|
125
129
|
const to = !toName ? '' : ` forwarding to ${toName}`;
|
|
126
130
|
|
|
127
|
-
return cbk(null, {description: `${reason} ${from}
|
|
131
|
+
return cbk(null, {description: `${reason} ${from}${at}${to}`});
|
|
128
132
|
}],
|
|
129
133
|
},
|
|
130
134
|
returnResult({reject, resolve, of: 'description'}, cbk));
|
package/display/get_icons.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const asyncAuto = require('async/auto');
|
|
2
|
+
const asyncify = require('async/asyncify');
|
|
2
3
|
const {returnResult} = require('asyncjs-util');
|
|
3
4
|
|
|
4
5
|
const {homePath} = require('../storage');
|
|
@@ -38,38 +39,48 @@ module.exports = ({fs}, cbk) => {
|
|
|
38
39
|
return cbk();
|
|
39
40
|
},
|
|
40
41
|
|
|
41
|
-
// Get
|
|
42
|
-
|
|
42
|
+
// Get the tags file
|
|
43
|
+
getFile: ['validate', ({}, cbk) => {
|
|
43
44
|
return fs.getFile(tagFilePath(), (err, res) => {
|
|
44
45
|
// Exit early when there is no tag file
|
|
45
46
|
if (!!err || !res) {
|
|
46
|
-
return cbk(
|
|
47
|
+
return cbk();
|
|
47
48
|
}
|
|
48
49
|
|
|
49
|
-
|
|
50
|
-
|
|
50
|
+
return cbk(null, res.toString());
|
|
51
|
+
});
|
|
52
|
+
}],
|
|
53
|
+
|
|
54
|
+
// Get icons from the tags file
|
|
55
|
+
getIcons: ['getFile', asyncify(({getFile}) => {
|
|
56
|
+
// Exit early when there is no tag file
|
|
57
|
+
if (!getFile) {
|
|
58
|
+
return {nodes: []};
|
|
59
|
+
}
|
|
51
60
|
|
|
52
|
-
|
|
61
|
+
try {
|
|
62
|
+
const file = parse(getFile);
|
|
53
63
|
|
|
54
|
-
|
|
55
|
-
// Only tags this node is included in
|
|
56
|
-
const meta = file.tags.filter(tag => {
|
|
57
|
-
return isArray(tag.nodes) && tag.nodes.includes(key);
|
|
58
|
-
});
|
|
64
|
+
const keys = uniq(flatten(file.tags.map(n => n.nodes)));
|
|
59
65
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
};
|
|
66
|
+
const nodes = keys.map(key => {
|
|
67
|
+
// Only tags this node is included in
|
|
68
|
+
const meta = file.tags.filter(tag => {
|
|
69
|
+
return isArray(tag.nodes) && tag.nodes.includes(key);
|
|
65
70
|
});
|
|
66
71
|
|
|
67
|
-
return
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
72
|
+
return {
|
|
73
|
+
aliases: uniq(meta.map(n => n.alias)),
|
|
74
|
+
icons: uniq(meta.map(n => n.icon)),
|
|
75
|
+
public_key: key,
|
|
76
|
+
};
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
return {nodes};
|
|
80
|
+
} catch (err) {
|
|
81
|
+
return {nodes: []};
|
|
82
|
+
}
|
|
83
|
+
})],
|
|
73
84
|
},
|
|
74
85
|
returnResult({reject, resolve, of: 'getIcons'}, cbk));
|
|
75
86
|
});
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
const additionalInfo = {1: 24, 2: 25, 4: 26, 8: 27};
|
|
2
|
+
const bitsPerByte = 8;
|
|
3
|
+
const largestSize = 8;
|
|
4
|
+
const majorTypeMultiplier = 32;
|
|
5
|
+
const maxInitialNumber = 23;
|
|
6
|
+
const sizes = [1, 2, 4];
|
|
7
|
+
|
|
8
|
+
/** Encode the head of a CBOR data item, its major type and its number
|
|
9
|
+
|
|
10
|
+
{
|
|
11
|
+
major: <Major Type Number>
|
|
12
|
+
number: <Length or Value Number>
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
@returns
|
|
16
|
+
{
|
|
17
|
+
head: <Data Item Head Buffer Object>
|
|
18
|
+
}
|
|
19
|
+
*/
|
|
20
|
+
module.exports = ({major, number}) => {
|
|
21
|
+
const initial = major * majorTypeMultiplier;
|
|
22
|
+
|
|
23
|
+
// Exit early when the number fits into the initial byte
|
|
24
|
+
if (number <= maxInitialNumber) {
|
|
25
|
+
return {head: Buffer.from([initial + number])};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// The number follows the initial byte, in as few bytes as it fits into
|
|
29
|
+
const size = sizes.find(n => number < 2 ** (n * bitsPerByte)) || largestSize;
|
|
30
|
+
|
|
31
|
+
const head = Buffer.alloc(1 + size);
|
|
32
|
+
|
|
33
|
+
head[0] = initial + additionalInfo[size];
|
|
34
|
+
|
|
35
|
+
// Exit early when the number needs all eight bytes
|
|
36
|
+
if (size === largestSize) {
|
|
37
|
+
head.writeBigUInt64BE(BigInt(number), 1);
|
|
38
|
+
|
|
39
|
+
return {head};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
head.writeUIntBE(number, 1, size);
|
|
43
|
+
|
|
44
|
+
return {head};
|
|
45
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
const decodeCborItem = require('./decode_cbor_item');
|
|
2
|
+
|
|
3
|
+
const hexAsBuffer = hex => Buffer.from(hex, 'hex');
|
|
4
|
+
const isString = n => typeof n === 'string';
|
|
5
|
+
|
|
6
|
+
/** Decode CBOR encoded data
|
|
7
|
+
|
|
8
|
+
{
|
|
9
|
+
cbor: <CBOR Encoded Hex String>
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
@throws
|
|
13
|
+
<Error>
|
|
14
|
+
|
|
15
|
+
@returns
|
|
16
|
+
{
|
|
17
|
+
value: <Decoded Value Object>
|
|
18
|
+
}
|
|
19
|
+
*/
|
|
20
|
+
module.exports = ({cbor}) => {
|
|
21
|
+
if (!isString(cbor)) {
|
|
22
|
+
throw new Error('ExpectedHexEncodedCborToDecode');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const data = hexAsBuffer(cbor);
|
|
26
|
+
|
|
27
|
+
const {end, value} = decodeCborItem({data, start: 0});
|
|
28
|
+
|
|
29
|
+
// The data has to be a single item, with nothing left over
|
|
30
|
+
if (end !== data.length) {
|
|
31
|
+
throw new Error('UnexpectedDataAfterCborItem');
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return {value};
|
|
35
|
+
};
|