balanceofsatoshis 11.2.1 → 11.5.1
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 +18 -0
- package/README.md +16 -0
- package/bos +5 -1
- package/commands/call_raw_api.js +32 -3
- package/lnd/credential_restrictions.js +41 -0
- package/lnd/find_record.js +1 -1
- package/lnd/get_credentials.js +2 -0
- package/lnd/lnd_credentials.js +15 -4
- package/package.json +5 -5
- package/routing/get_ignores.js +4 -1
- package/telegram/start_telegram_bot.js +6 -4
- package/test/lnd/test_credential_restrictions.js +74 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# Versions
|
|
2
2
|
|
|
3
|
+
## Version 11.5.1
|
|
4
|
+
|
|
5
|
+
- `--avoid`: Correct naming`OUT_FEE_RATE`/`IN_FEE_RATE` to `OPPOSITE_FEE_RATE`
|
|
6
|
+
|
|
7
|
+
## Version 11.5.0
|
|
8
|
+
|
|
9
|
+
- `--avoid` Add `IN_FEE_RATE` and `OUT_FEE_RATE` to formulas
|
|
10
|
+
- `find`: Correct socket output for peer node lookups
|
|
11
|
+
- `telegram`: Correct week summary chain fee costs in `/costs`
|
|
12
|
+
|
|
13
|
+
## Version 11.4.0
|
|
14
|
+
|
|
15
|
+
- `call`: Add `--param` flag to pass arguments directly instead of interactively
|
|
16
|
+
|
|
17
|
+
## Version 11.3.0
|
|
18
|
+
|
|
19
|
+
- `credentials`: Allow specifying specific methods to allow in a credential
|
|
20
|
+
|
|
3
21
|
## Version 11.2.1
|
|
4
22
|
|
|
5
23
|
- Improve support for LND v0.13.3
|
package/README.md
CHANGED
|
@@ -533,6 +533,22 @@ functions and reference variables.
|
|
|
533
533
|
There is a dynamic playground here where you can play with expressions:
|
|
534
534
|
https://formulajs.info/functions/
|
|
535
535
|
|
|
536
|
+
### `--avoid`
|
|
537
|
+
|
|
538
|
+
In `--avoid` flag commands like rebalance, a formula can be applied directionally:
|
|
539
|
+
|
|
540
|
+
`--avoid "fee_rate < 100/<PUBKEY>"` to avoid channels forwarding to the public key that
|
|
541
|
+
charge a fee rate under 100 PPM.
|
|
542
|
+
|
|
543
|
+
Available variables:
|
|
544
|
+
|
|
545
|
+
- `age`: Age of the channel vs the current height
|
|
546
|
+
- `base_fee`: Base fee to be charged to route
|
|
547
|
+
- `capacity`: Capacity of the channel
|
|
548
|
+
- `fee_rate`: PPM fee to be charged to route
|
|
549
|
+
- `height`: Absolute height of the channel
|
|
550
|
+
- `opposite_fee_rate`: PPM fee that is charged in the non-routing direction
|
|
551
|
+
|
|
536
552
|
### `amount`
|
|
537
553
|
|
|
538
554
|
Formula amounts are supported in the following commands:
|
package/bos
CHANGED
|
@@ -212,6 +212,7 @@ prog
|
|
|
212
212
|
.help('If you do not specify a method it will list the supported methods')
|
|
213
213
|
.argument('[method]', 'Method to call')
|
|
214
214
|
.option('--node <node_name>', 'Saved node to use for call')
|
|
215
|
+
.option('--param <param>', 'query encoded name=value', REPEATABLE)
|
|
215
216
|
.action((args, options, logger) => {
|
|
216
217
|
return new Promise(async (resolve, reject) => {
|
|
217
218
|
try {
|
|
@@ -220,6 +221,7 @@ prog
|
|
|
220
221
|
ask: (n, cbk) => inquirer.prompt([n]).then(n => cbk(null, n)),
|
|
221
222
|
lnd: (await lndForNode(logger, options.node)).lnd,
|
|
222
223
|
method: args.method,
|
|
224
|
+
params: flatten([options.param].filter(n => !!n)),
|
|
223
225
|
},
|
|
224
226
|
responses.returnObject({logger, reject, resolve}));
|
|
225
227
|
} catch (err) {
|
|
@@ -420,6 +422,7 @@ prog
|
|
|
420
422
|
.help('Output encrypted remote access credentials. Use with "nodes --add"')
|
|
421
423
|
.option('--cleartext', 'Output remote access credentials without encryption')
|
|
422
424
|
.option('--days <days>', 'Expiration days for credentials', INT, 365)
|
|
425
|
+
.option('--method <method_name>', 'White-list specific method', REPEATABLE)
|
|
423
426
|
.option('--node <node_name>', 'Get credentials for a saved node')
|
|
424
427
|
.option('--nospend', 'Credentials do not include spending privileges')
|
|
425
428
|
.option('--readonly', 'Credentials only include read permissions')
|
|
@@ -432,6 +435,7 @@ prog
|
|
|
432
435
|
is_cleartext: options.cleartext,
|
|
433
436
|
is_nospend: options.nospend,
|
|
434
437
|
is_readonly: options.readonly,
|
|
438
|
+
methods: flatten([options.method].filter(n => !!n)),
|
|
435
439
|
node: options.node,
|
|
436
440
|
},
|
|
437
441
|
responses.returnObject({logger, reject, resolve}));
|
|
@@ -1189,7 +1193,7 @@ prog
|
|
|
1189
1193
|
.option('--max-fee-rate <max_fee_rate>', 'Max fee rate to pay')
|
|
1190
1194
|
.option('--minutes <minutes>', 'Time-out route search after N minutes', INT)
|
|
1191
1195
|
.option('--no-color', 'Mute all colors')
|
|
1192
|
-
.option('--node <node_name>', '
|
|
1196
|
+
.option('--node <node_name>', 'Saved node to use for rebalance')
|
|
1193
1197
|
.option('--out <pubkey_or_alias>', 'Route out through a specific peer')
|
|
1194
1198
|
.option('--out-filter <out_filter>', 'Filter outbound tag nodes', REPEATABLE)
|
|
1195
1199
|
.option('--out-target-inbound <amount>', 'Balance up to inbound amount')
|
package/commands/call_raw_api.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
const {parse} = require('querystring');
|
|
2
|
+
|
|
1
3
|
const asyncAuto = require('async/auto');
|
|
2
4
|
const asyncMapSeries = require('async/mapSeries');
|
|
3
5
|
const lnService = require('ln-service');
|
|
@@ -5,6 +7,7 @@ const {returnResult} = require('asyncjs-util');
|
|
|
5
7
|
|
|
6
8
|
const {calls} = require('./api');
|
|
7
9
|
|
|
10
|
+
const {assign} = Object;
|
|
8
11
|
const isChannel = n => !!n && /^\d*x\d*x\d*$/.test(n);
|
|
9
12
|
const isHash = n => !!n && /^[0-9A-F]{64}$/i.test(n);
|
|
10
13
|
const isPublicKey = n => !!n && /^0[2-3][0-9A-F]{64}$/i.test(n);
|
|
@@ -19,12 +22,13 @@ const methodDetails = (calls, method) => calls.find(n => n.method === method);
|
|
|
19
22
|
lnd: <Authenticated LND API Object>
|
|
20
23
|
logger: <Winston Logger Object>
|
|
21
24
|
[method]: <Method to Call String>
|
|
25
|
+
[params]: [<Querystring Encoded Parameter String>]
|
|
22
26
|
}
|
|
23
27
|
|
|
24
28
|
@returns via cbk or Promise
|
|
25
29
|
<Result Object>
|
|
26
30
|
*/
|
|
27
|
-
module.exports = ({ask, lnd, logger, method}, cbk) => {
|
|
31
|
+
module.exports = ({ask, lnd, logger, method, params}, cbk) => {
|
|
28
32
|
return new Promise((resolve, reject) => {
|
|
29
33
|
return asyncAuto({
|
|
30
34
|
// Check arguments
|
|
@@ -76,12 +80,36 @@ module.exports = ({ask, lnd, logger, method}, cbk) => {
|
|
|
76
80
|
return cbk(null, []);
|
|
77
81
|
}
|
|
78
82
|
|
|
83
|
+
const parameters = (params || [])
|
|
84
|
+
.map(encoded => parse(encoded))
|
|
85
|
+
.reduce((sum, n) => assign(sum, n), {});
|
|
86
|
+
|
|
87
|
+
// Parameters must all match method parameters
|
|
88
|
+
const unknown = keys(parameters).find(param => {
|
|
89
|
+
return !arguments.find(({named}) => named === param);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
if (!!unknown) {
|
|
93
|
+
return cbk([400, 'UnknownParameterProvided', {unknown}]);
|
|
94
|
+
}
|
|
95
|
+
|
|
79
96
|
return asyncMapSeries(arguments, (argument, cbk) => {
|
|
97
|
+
const {named} = argument;
|
|
98
|
+
|
|
99
|
+
if (!!parameters[named] && argument.type === 'boolean') {
|
|
100
|
+
return cbk(null, {[named]: parameters[named] === 'true'});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (parameters[named] !== undefined) {
|
|
104
|
+
return cbk(null, {[named]: parameters[named]});
|
|
105
|
+
}
|
|
106
|
+
|
|
80
107
|
if (argument.type === 'boolean') {
|
|
81
108
|
return ask({
|
|
82
109
|
default: false,
|
|
83
|
-
name:
|
|
110
|
+
name: named,
|
|
84
111
|
message: argument.description,
|
|
112
|
+
prefix: `[${named}]`,
|
|
85
113
|
type: 'confirm',
|
|
86
114
|
},
|
|
87
115
|
cbk);
|
|
@@ -90,7 +118,8 @@ module.exports = ({ask, lnd, logger, method}, cbk) => {
|
|
|
90
118
|
return ask({
|
|
91
119
|
default: () => !!argument.optional ? String() : undefined,
|
|
92
120
|
message: argument.description,
|
|
93
|
-
name:
|
|
121
|
+
name: named,
|
|
122
|
+
prefix: `[${named}]`,
|
|
94
123
|
suffix: !!argument.optional ? ' (Optional)' : String(),
|
|
95
124
|
type: argument.type || 'input',
|
|
96
125
|
validate: input => {
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
const {noSpendPerms} = require('./constants');
|
|
2
|
+
const {permissionEntities} = require('./constants');
|
|
3
|
+
|
|
4
|
+
const readPerms = permissionEntities.map(entity => `${entity}:read`);
|
|
5
|
+
|
|
6
|
+
/** Derive restrictions for macaroon
|
|
7
|
+
|
|
8
|
+
{
|
|
9
|
+
[is_nospend]: <Restrict Credentials To Non-Spending Permissions Bool>
|
|
10
|
+
[is_readonly]: <Restrict Credentials To Read-Only Permissions Bool>
|
|
11
|
+
[methods]: [<Allow Specific Method String>]
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
@returns
|
|
15
|
+
{
|
|
16
|
+
[allow]: {
|
|
17
|
+
methods: [<Allow Specific Method String>]
|
|
18
|
+
permissions: [<Entity:Action String>]
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
*/
|
|
22
|
+
module.exports = args => {
|
|
23
|
+
const methods = args.methods || [];
|
|
24
|
+
|
|
25
|
+
// Exit early when specific credentials are not requested
|
|
26
|
+
if (!args.is_readonly && !args.is_nospend && !methods.length) {
|
|
27
|
+
return {};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const permissions = [];
|
|
31
|
+
|
|
32
|
+
if (!!args.is_readonly) {
|
|
33
|
+
readPerms.forEach(n => permissions.push(n));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (!!args.is_nospend) {
|
|
37
|
+
noSpendPerms.forEach(n => permissions.push(n));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return {allow: {methods, permissions}};
|
|
41
|
+
};
|
package/lnd/find_record.js
CHANGED
|
@@ -114,7 +114,7 @@ module.exports = ({lnd, query}, cbk) => {
|
|
|
114
114
|
color: res.color,
|
|
115
115
|
features: res.features,
|
|
116
116
|
public_key: getKey.value.public_key,
|
|
117
|
-
sockets: res.sockets,
|
|
117
|
+
sockets: res.sockets.map(n => n.socket),
|
|
118
118
|
updated_at: res.last_updated,
|
|
119
119
|
}],
|
|
120
120
|
});
|
package/lnd/get_credentials.js
CHANGED
|
@@ -16,6 +16,7 @@ const {pemAsDer} = require('./../encryption');
|
|
|
16
16
|
is_nospend: <Restrict Credentials To Non-Spending Permissions Bool>
|
|
17
17
|
is_readonly: <Restrict Credentials To Read-Only Permissions Bool>
|
|
18
18
|
logger: <Winston Logger Object> ({info}) => ()
|
|
19
|
+
[methods]: [<Allow Specific Method String>]
|
|
19
20
|
[node]: <Node Name String>
|
|
20
21
|
}
|
|
21
22
|
|
|
@@ -81,6 +82,7 @@ module.exports = (args, cbk) => {
|
|
|
81
82
|
is_nospend: args.is_nospend,
|
|
82
83
|
is_readonly: args.is_readonly,
|
|
83
84
|
logger: args.logger,
|
|
85
|
+
methods: args.methods,
|
|
84
86
|
node: args.node,
|
|
85
87
|
},
|
|
86
88
|
cbk);
|
package/lnd/lnd_credentials.js
CHANGED
|
@@ -12,6 +12,7 @@ const {grantAccess} = require('ln-service');
|
|
|
12
12
|
const {restrictMacaroon} = require('ln-service');
|
|
13
13
|
const {returnResult} = require('asyncjs-util');
|
|
14
14
|
|
|
15
|
+
const credentialRestrictions = require('./credential_restrictions');
|
|
15
16
|
const {decryptCiphertext} = require('./../encryption');
|
|
16
17
|
const {derAsPem} = require('./../encryption');
|
|
17
18
|
const getCert = require('./get_cert');
|
|
@@ -38,6 +39,7 @@ const socket = 'localhost:10009';
|
|
|
38
39
|
[is_readonly]: <Restrict Credentials To Read-Only Permissions Bool>
|
|
39
40
|
[key]: <Encrypt to Public Key DER Hex String>
|
|
40
41
|
[logger]: <Winston Logger Object>
|
|
42
|
+
[methods]: [<Allow Specific Method String>]
|
|
41
43
|
[node]: <Node Name String> // Defaults to default local mainnet node creds
|
|
42
44
|
}
|
|
43
45
|
|
|
@@ -199,8 +201,14 @@ module.exports = (args, cbk) => {
|
|
|
199
201
|
'macaroon',
|
|
200
202
|
({credentials, macaroon}, cbk) =>
|
|
201
203
|
{
|
|
204
|
+
const {allow} = credentialRestrictions({
|
|
205
|
+
is_nospend: args.is_nospend,
|
|
206
|
+
is_readonly: args.is_readonly,
|
|
207
|
+
methods: args.methods,
|
|
208
|
+
});
|
|
209
|
+
|
|
202
210
|
// Exit early when readonly credentials are not requested
|
|
203
|
-
if (!
|
|
211
|
+
if (!allow) {
|
|
204
212
|
return cbk(null, {macaroon});
|
|
205
213
|
}
|
|
206
214
|
|
|
@@ -210,9 +218,12 @@ module.exports = (args, cbk) => {
|
|
|
210
218
|
socket: credentials.socket,
|
|
211
219
|
});
|
|
212
220
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
221
|
+
return grantAccess({
|
|
222
|
+
lnd,
|
|
223
|
+
methods: allow.methods,
|
|
224
|
+
permissions: allow.permissions,
|
|
225
|
+
},
|
|
226
|
+
cbk);
|
|
216
227
|
}],
|
|
217
228
|
|
|
218
229
|
// Final credentials with encryption applied
|
package/package.json
CHANGED
|
@@ -25,19 +25,19 @@
|
|
|
25
25
|
"caporal": "1.4.0",
|
|
26
26
|
"cbor": "8.0.2",
|
|
27
27
|
"cert-info": "1.5.1",
|
|
28
|
-
"colorette": "2.0.
|
|
28
|
+
"colorette": "2.0.16",
|
|
29
29
|
"crypto-js": "4.1.1",
|
|
30
30
|
"csv-parse": "4.16.3",
|
|
31
31
|
"goldengate": "10.4.0",
|
|
32
32
|
"hot-formula-parser": "4.0.0",
|
|
33
33
|
"import-lazy": "4.0.0",
|
|
34
34
|
"ini": "2.0.0",
|
|
35
|
-
"inquirer": "8.
|
|
35
|
+
"inquirer": "8.2.0",
|
|
36
36
|
"invoices": "2.0.0",
|
|
37
37
|
"ln-accounting": "5.0.3",
|
|
38
|
-
"ln-service": "52.
|
|
38
|
+
"ln-service": "52.11.1",
|
|
39
39
|
"ln-sync": "2.0.2",
|
|
40
|
-
"ln-telegram": "3.3.
|
|
40
|
+
"ln-telegram": "3.3.1",
|
|
41
41
|
"moment": "2.29.1",
|
|
42
42
|
"paid-services": "3.0.0",
|
|
43
43
|
"probing": "1.3.6",
|
|
@@ -80,5 +80,5 @@
|
|
|
80
80
|
"postpublish": "docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t alexbosworth/balanceofsatoshis --push .",
|
|
81
81
|
"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/fiat/*.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
82
|
},
|
|
83
|
-
"version": "11.
|
|
83
|
+
"version": "11.5.1"
|
|
84
84
|
}
|
package/routing/get_ignores.js
CHANGED
|
@@ -223,6 +223,7 @@ module.exports = (args, cbk) => {
|
|
|
223
223
|
age: getHeight.current_block_height - height,
|
|
224
224
|
base_fee: Number(outPolicy.base_fee_mtokens) || Number(),
|
|
225
225
|
fee_rate: outPolicy.fee_rate || Number(),
|
|
226
|
+
opposite_fee_rate: peerPolicy.fee_rate || Number(),
|
|
226
227
|
});
|
|
227
228
|
|
|
228
229
|
keys(variables).forEach(key => {
|
|
@@ -283,8 +284,9 @@ module.exports = (args, cbk) => {
|
|
|
283
284
|
.map(({capacity, id, policies}) => {
|
|
284
285
|
const height = heightFromId(id);
|
|
285
286
|
const inPolicy = policies.find(n => n.public_key !== key);
|
|
287
|
+
const outPolicy = policies.find(n => n.public_key === key);
|
|
286
288
|
|
|
287
|
-
if (!inPolicy) {
|
|
289
|
+
if (!inPolicy || !outPolicy) {
|
|
288
290
|
return;
|
|
289
291
|
}
|
|
290
292
|
|
|
@@ -299,6 +301,7 @@ module.exports = (args, cbk) => {
|
|
|
299
301
|
age: getHeight.current_block_height - height,
|
|
300
302
|
base_fee: Number(inPolicy.base_fee_mtokens) || Number(),
|
|
301
303
|
fee_rate: inPolicy.fee_rate || Number(),
|
|
304
|
+
opposite_fee_rate: outPolicy.fee_rate || Number(),
|
|
302
305
|
});
|
|
303
306
|
|
|
304
307
|
keys(variables).forEach(key => {
|
|
@@ -323,7 +323,7 @@ module.exports = ({fs, id, limits, lnds, logger, payments, request}, cbk) => {
|
|
|
323
323
|
});
|
|
324
324
|
});
|
|
325
325
|
|
|
326
|
-
bot.command('liquidity', async
|
|
326
|
+
bot.command('liquidity', async ctx => {
|
|
327
327
|
try {
|
|
328
328
|
await asyncRetry({
|
|
329
329
|
errorFilter: err => {
|
|
@@ -335,13 +335,14 @@ module.exports = ({fs, id, limits, lnds, logger, payments, request}, cbk) => {
|
|
|
335
335
|
},
|
|
336
336
|
}, async () => {
|
|
337
337
|
await handleLiquidityCommand({
|
|
338
|
-
reply,
|
|
339
338
|
request,
|
|
340
|
-
from: message.from.id,
|
|
339
|
+
from: ctx.message.from.id,
|
|
341
340
|
id: connectedId,
|
|
342
341
|
key: apiKey.key,
|
|
343
342
|
nodes: allNodes,
|
|
344
|
-
|
|
343
|
+
reply: ctx.reply,
|
|
344
|
+
text: ctx.message.text,
|
|
345
|
+
working: () => ctx.replyWithChatAction('typing'),
|
|
345
346
|
});
|
|
346
347
|
});
|
|
347
348
|
} catch (err) {
|
|
@@ -392,6 +393,7 @@ module.exports = ({fs, id, limits, lnds, logger, payments, request}, cbk) => {
|
|
|
392
393
|
id: connectedId,
|
|
393
394
|
nodes: allNodes,
|
|
394
395
|
reply: n => ctx.reply(n),
|
|
396
|
+
working: () => ctx.replyWithChatAction('typing'),
|
|
395
397
|
});
|
|
396
398
|
} catch (err) {
|
|
397
399
|
logger.error({err});
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
const {test} = require('@alexbosworth/tap');
|
|
2
|
+
|
|
3
|
+
const method = require('./../../lnd/credential_restrictions');
|
|
4
|
+
|
|
5
|
+
const tests = [
|
|
6
|
+
{
|
|
7
|
+
args: {},
|
|
8
|
+
description: 'No restrictions results in no allow elements',
|
|
9
|
+
expected: {},
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
args: {is_nospend: true},
|
|
13
|
+
description: 'No spend results in nospend permissions',
|
|
14
|
+
expected: {
|
|
15
|
+
allow: {
|
|
16
|
+
methods: [],
|
|
17
|
+
permissions: [
|
|
18
|
+
'address:read',
|
|
19
|
+
'address:write',
|
|
20
|
+
'info:read',
|
|
21
|
+
'info:write',
|
|
22
|
+
'invoices:read',
|
|
23
|
+
'invoices:write',
|
|
24
|
+
'macaroon:read',
|
|
25
|
+
'message:read',
|
|
26
|
+
'offchain:read',
|
|
27
|
+
'onchain:read',
|
|
28
|
+
'peers:read',
|
|
29
|
+
'peers:write',
|
|
30
|
+
'signer:read',
|
|
31
|
+
],
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
args: {is_readonly: true},
|
|
37
|
+
description: 'Readonly results in read permissions',
|
|
38
|
+
expected: {
|
|
39
|
+
allow: {
|
|
40
|
+
methods: [],
|
|
41
|
+
permissions: [
|
|
42
|
+
'address:read',
|
|
43
|
+
'info:read',
|
|
44
|
+
'invoices:read',
|
|
45
|
+
'macaroon:read',
|
|
46
|
+
'message:read',
|
|
47
|
+
'offchain:read',
|
|
48
|
+
'onchain:read',
|
|
49
|
+
'peers:read',
|
|
50
|
+
'signer:read',
|
|
51
|
+
],
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
args: {methods: ['getWalletInfo']},
|
|
57
|
+
description: 'Readonly results in read permissions',
|
|
58
|
+
expected: {allow: {methods: ['getWalletInfo'], permissions: []}},
|
|
59
|
+
},
|
|
60
|
+
];
|
|
61
|
+
|
|
62
|
+
tests.forEach(({args, description, error, expected}) => {
|
|
63
|
+
return test(description, async ({end, strictSame, throws}) => {
|
|
64
|
+
if (!!error) {
|
|
65
|
+
throws(() => method(args), new Error(error), 'Got expected error');
|
|
66
|
+
} else {
|
|
67
|
+
const res = method(args);
|
|
68
|
+
|
|
69
|
+
strictSame(res, expected, 'Got expected result');
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return end();
|
|
73
|
+
});
|
|
74
|
+
});
|