@witnet/sdk 1.2.1 → 1.2.3

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.
Files changed (53) hide show
  1. package/.env_witnet +2 -1
  2. package/dist/package.json +5 -3
  3. package/dist/src/bin/helpers.js +1 -1
  4. package/dist/src/index.js +1 -1
  5. package/dist/src/lib/crypto/account.js +1 -1
  6. package/dist/src/lib/crypto/coinbase.js +1 -1
  7. package/dist/src/lib/crypto/index.js +1 -1
  8. package/dist/src/lib/crypto/interfaces.js +1 -1
  9. package/dist/src/lib/crypto/payloads/DataRequestPayload.js +1 -1
  10. package/dist/src/lib/crypto/payloads/StakePayload.js +1 -1
  11. package/dist/src/lib/crypto/payloads/UnstakePayload.js +1 -1
  12. package/dist/src/lib/crypto/payloads/ValueTransferPayload.js +1 -1
  13. package/dist/src/lib/crypto/payloads.js +1 -1
  14. package/dist/src/lib/crypto/signer.js +1 -1
  15. package/dist/src/lib/crypto/transmitters/DataRequests.js +1 -1
  16. package/dist/src/lib/crypto/transmitters/StakeDeposits.js +1 -1
  17. package/dist/src/lib/crypto/transmitters/StakeWithdrawals.js +1 -1
  18. package/dist/src/lib/crypto/transmitters/ValueTransfers.js +1 -1
  19. package/dist/src/lib/crypto/transmitters.js +1 -1
  20. package/dist/src/lib/crypto/types.js +1 -1
  21. package/dist/src/lib/crypto/utils.js +1 -1
  22. package/dist/src/lib/crypto/wallet.js +1 -1
  23. package/dist/src/lib/index.js +1 -1
  24. package/dist/src/lib/radon/ccdr/eth.js +1 -1
  25. package/dist/src/lib/radon/ccdr/index.js +1 -1
  26. package/dist/src/lib/radon/ccdr/wit.js +1 -1
  27. package/dist/src/lib/radon/filters.js +1 -1
  28. package/dist/src/lib/radon/index.js +1 -1
  29. package/dist/src/lib/radon/reducers.js +1 -1
  30. package/dist/src/lib/radon/types.js +1 -1
  31. package/dist/src/lib/radon/utils.d.ts.map +1 -1
  32. package/dist/src/lib/radon/utils.js +1 -1
  33. package/dist/src/lib/rest/kermit.d.ts.map +1 -1
  34. package/dist/src/lib/rest/kermit.js +2 -4
  35. package/dist/src/lib/rest/types.js +1 -1
  36. package/dist/src/lib/rpc/index.js +1 -1
  37. package/dist/src/lib/rpc/nodes.js +1 -1
  38. package/dist/src/lib/rpc/provider.js +1 -1
  39. package/dist/src/lib/rpc/types.js +1 -1
  40. package/dist/src/lib/types.js +1 -1
  41. package/dist/src/lib/utils.js +1 -1
  42. package/package.json +5 -3
  43. package/scripts/clean.cjs +21 -0
  44. package/scripts/postinstall.cjs +9 -0
  45. package/src/bin/bots/watcher.cjs +365 -354
  46. package/src/bin/cli/history.cjs +31 -31
  47. package/src/bin/cli/inspect.js +581 -581
  48. package/src/bin/cli/network.js +695 -695
  49. package/src/bin/cli/nodes.js +424 -424
  50. package/src/bin/cli/radon.js +1124 -1122
  51. package/src/bin/cli/wallet.js +1362 -1362
  52. package/src/bin/helpers.js +974 -974
  53. package/src/bin/index.js +328 -328
@@ -1,974 +1,974 @@
1
- import { exec } from "node:child_process";
2
- import { createRequire } from "node:module";
3
- import * as net from "node:net";
4
- import * as os from "node:os";
5
- import * as readline from "node:readline";
6
- import moment from "moment";
7
-
8
- const require = createRequire(import.meta.url);
9
-
10
- export const colorstrip = (str) =>
11
- str.replace(
12
- /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g,
13
- "",
14
- );
15
-
16
- export const commas = (number) => {
17
- const parts = number.toString().split(".");
18
- const result =
19
- parts.length <= 1
20
- ? `${parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",")}`
21
- : `${parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",")}.${parts[1]}`;
22
- return result;
23
- };
24
-
25
- export function toFixedTrunc(x, n) {
26
- const v = (typeof x === "string" ? x : x.toString()).split(".");
27
- if (n <= 0) return v[0];
28
- let f = v[1] || "";
29
- if (f.length > n) return `${v[0]}.${f.substr(0, n)}`;
30
- while (f.length < n) f += "0";
31
- return `${v[0]}.${f}`;
32
- }
33
-
34
- export const whole_wits = (number, digits) => {
35
- const lookup = [
36
- { value: 1n, symbol: "pedros" },
37
- { value: 10n ** 6n, symbol: "mWits" },
38
- { value: 10n ** 9n, symbol: " Wits" },
39
- { value: 10n ** 12n, symbol: "KWits" },
40
- { value: 10n ** 15n, symbol: "MWits" },
41
- ];
42
- // const regexp = /\.0+$|(?<=\.[0-9])0+$/
43
- const item = lookup.findLast((item) => number >= item.value);
44
- const quotient = item
45
- ? Number(BigInt(number) / item.value)
46
- : number.toString();
47
- const decimals = item
48
- ? (item.value + BigInt(number) - BigInt(quotient) * item.value)
49
- .toString()
50
- .slice(1)
51
- : "";
52
- return item
53
- ? `${commas(quotient)}${decimals !== "" ? `.${decimals.slice(0, digits)}` : ""} ${item.symbol}`
54
- : "(no coins)";
55
- };
56
-
57
- const bblue = (str) => `\x1b[1;98;44m${str}\x1b[0;0;0m`;
58
- const bcyan = (str) => `\x1b[38;46m${str}\x1b[0;0m`;
59
- const bgreen = (str) => `\x1b[30;42m${str}\x1b[0;0m`;
60
- const bred = (str) => `\x1b[30;41m${str}\x1b[0;0m`;
61
- const bviolet = (str) => `\x1b[30;45m${str}\x1b[0;0m`;
62
-
63
- const lcyan = (str) => `\x1b[1;96m${str}\x1b[0m`;
64
- const lgray = (str) => `\x1b[1;90m${str}\x1b[0m`;
65
- const lgreen = (str) => `\x1b[1;92m${str}\x1b[0m`;
66
- const lmagenta = (str) => `\x1b[1;95m${str}\x1b[0m`;
67
- const lyellow = (str) => `\x1b[1;93m${str}\x1b[0m`;
68
- const mblue = (str) => `\x1b[94m${str}\x1b[0m`;
69
- const mcyan = (str) => `\x1b[96m${str}\x1b[0m`;
70
- const mgreen = (str) => `\x1b[92m${str}\x1b[0m`;
71
- const mmagenta = (str) => `\x1b[0;95m${str}\x1b[0m`;
72
- const mred = (str) => `\x1b[91m${str}\x1b[0m`;
73
- const myellow = (str) => `\x1b[93m${str}\x1b[0m`;
74
-
75
- const blue = (str) => `\x1b[34m${str}\x1b[0m`;
76
- const cyan = (str) => `\x1b[36m${str}\x1b[0m`;
77
- const gray = (str) => `\x1b[90m${str}\x1b[0m`;
78
- const green = (str) => `\x1b[32m${str}\x1b[0m`;
79
- const magenta = (str) => `\x1b[0;35m${str}\x1b[0m`;
80
- const normal = (str) => `\x1b[98m${str}\x1b[0m`;
81
- const red = (str) => `\x1b[31m${str}\x1b[0m`;
82
- const white = (str) => `\x1b[1;98m${str}\x1b[0m`;
83
- const yellow = (str) => `\x1b[33m${str}\x1b[0m`;
84
-
85
- export const colors = {
86
- bblue,
87
- bcyan,
88
- bgreen,
89
- bred,
90
- bviolet,
91
- lcyan,
92
- lgray,
93
- lgreen,
94
- lmagenta,
95
- lyellow,
96
- mblue,
97
- mcyan,
98
- mgreen,
99
- mmagenta,
100
- mred,
101
- myellow,
102
- blue,
103
- cyan,
104
- gray,
105
- green,
106
- magenta,
107
- normal,
108
- red,
109
- white,
110
- yellow,
111
- };
112
-
113
- export function countLeaves(t, obj) {
114
- if (!obj || typeof obj === "string") return 0;
115
- if (obj instanceof t) return 1;
116
- if (Array.isArray(obj))
117
- return obj.reduce((sum, item) => sum + countLeaves(t, item), 0);
118
- else
119
- return Object.values(obj).reduce(
120
- (sum, item) => sum + countLeaves(t, item),
121
- 0,
122
- );
123
- }
124
-
125
- export function deleteExtraFlags(args) {
126
- return args.filter((arg) => !arg.startsWith("--"));
127
- }
128
-
129
- export function cmd(...command) {
130
- return new Promise((resolve, reject) => {
131
- exec(
132
- command.join(" "),
133
- { maxBuffer: 1024 * 1024 * 10 },
134
- (error, stdout, stderr) => {
135
- if (error) {
136
- reject(error);
137
- }
138
- if (stderr) {
139
- reject(stderr);
140
- }
141
- resolve(stdout);
142
- },
143
- );
144
- });
145
- }
146
-
147
- export async function execRadonBytecode(bytecode, ...flags) {
148
- if (!isHexString(bytecode)) {
149
- throw EvalError("invalid hex string");
150
- } else {
151
- const npx = os.type() === "Windows_NT" ? "npx.cmd" : "npx";
152
- return cmd(npx, "witsdk", "radon", "dry-run", bytecode, ...flags);
153
- // .catch((err) => {
154
- // let errorMessage = err.message.split('\n').slice(1).join('\n').trim()
155
- // const errorRegex = /.*^error: (?<message>.*)$.*/gm
156
- // const matched = errorRegex.exec(err.message)
157
- // if (matched) {
158
- // errorMessage = matched.groups.message
159
- // }
160
- // console.log(errorMessage || err)
161
- // console.error(errorMessage || err)
162
- // })
163
- }
164
- }
165
-
166
- export function extractFromArgs(args, flags) {
167
- const curated = {};
168
- if (args && flags) {
169
- Object.keys(flags).forEach((flag) => {
170
- const flagIndex = args.indexOf(`--${flag}`);
171
- if (flagIndex >= 0) {
172
- if (flags[flag].param) {
173
- curated[flag] = args[flagIndex];
174
- if (!args[flagIndex + 1] || args[flagIndex + 1].startsWith("--")) {
175
- throw Error(`Missing required parameter for --${flag}`);
176
- } else {
177
- curated[flag] = args[flagIndex + 1];
178
- args.splice(flagIndex, 2);
179
- }
180
- } else {
181
- curated[flag] = true;
182
- args.splice(flagIndex, 1);
183
- }
184
- }
185
- });
186
- }
187
- return [args, curated];
188
- }
189
-
190
- export function fromHexString(hexString) {
191
- if (hexString.startsWith("0x")) hexString = hexString.slice(2);
192
- return Uint8Array.from(
193
- hexString.match(/.{1,2}/g).map((byte) => parseInt(byte, 16)),
194
- );
195
- }
196
-
197
- export function ipIsPrivateOrLocalhost(ip) {
198
- if (ip.substring(0, 7) === "::ffff:") {
199
- ip = ip.substring(7);
200
- }
201
-
202
- if (net.isIPv4(ip)) {
203
- // check localhost
204
- if (ip === "127.0.0.1") {
205
- return true;
206
- }
207
-
208
- // 10.0.0.0 - 10.255.255.255 || 172.16.0.0 - 172.31.255.255 || 192.168.0.0 - 192.168.255.255
209
- return (
210
- /^(10)\.(.*)\.(.*)\.(.*)$/.test(ip) ||
211
- /^(172)\.(1[6-9]|2[0-9]|3[0-1])\.(.*)\.(.*)$/.test(ip) ||
212
- /^(192)\.(168)\.(.*)\.(.*)$/.test(ip)
213
- );
214
- }
215
-
216
- // else: ip is IPv6
217
- const firstWord = ip.split(":").find((el) => !!el); // get first not empty word
218
-
219
- // equivalent of 127.0.0.1 in IPv6
220
- if (ip === "::1") return true;
221
- // The original IPv6 Site Local addresses (fec0::/10) are deprecated. Range: fec0 - feff
222
- else if (/^fe[c-f][0-f]$/.test(firstWord)) return true;
223
- // These days Unique Local Addresses (ULA) are used in place of Site Local.
224
- // Range: fc00 - fcff
225
- else if (/^fc[0-f]{2}$/.test(firstWord)) return true;
226
- // Range: fd00 - fcff
227
- else if (/^fd[0-f]{2}$/.test(firstWord)) return true;
228
- // Link local addresses (prefixed with fe80) are not routable
229
- else if (firstWord === "fe80") return true;
230
- // Discard Prefix
231
- else if (firstWord === "100") return true;
232
-
233
- // Any other IP address is not Unique Local Address (ULA)
234
- return false;
235
- }
236
-
237
- export function isHexStringOfLength(str, length) {
238
- return (
239
- (isHexString(str) &&
240
- ((str.startsWith("0x") && str.slice(2).length === length * 2) ||
241
- str.length === length * 2)) ||
242
- isWildcard(str)
243
- );
244
- }
245
-
246
- export function isHexString(str) {
247
- return (
248
- (typeof str === "string" &&
249
- ((str.startsWith("0x") && /^[a-fA-F0-9]+$/i.test(str.slice(2))) ||
250
- /^[a-fA-F0-9]+$/i.test(str))) ||
251
- isWildcard(str)
252
- );
253
- }
254
-
255
- export function toHexString(buffer, prefix0x = false) {
256
- if (buffer instanceof Uint8Array) buffer = Buffer.from(buffer);
257
- return (
258
- (prefix0x ? "0x" : "") +
259
- Array.prototype.map
260
- .call(buffer, (x) => `00${x.toString(16)}`.slice(-2))
261
- .join("")
262
- .match(/[a-fA-F0-9]{2}/g)
263
- .join("")
264
- );
265
- }
266
-
267
- export function parseURL(url) {
268
- try {
269
- const parsedUrl = new URL(url);
270
- return [
271
- `${parsedUrl.protocol}//`,
272
- parsedUrl.host,
273
- parsedUrl.pathname.slice(1),
274
- parsedUrl.search.slice(1),
275
- ];
276
- } catch {
277
- throw new TypeError(`Invalid URL was provided: ${url}`);
278
- }
279
- }
280
-
281
- export function showUsage(cmd, module) {
282
- showUsageHeadline(cmd);
283
- showUsageOptions({ ...module?.flags });
284
- showUsageFlags({ ...module?.flags });
285
- showUsageRouter({ ...module?.router });
286
- showUsageEnvars({ ...module?.envars });
287
- }
288
-
289
- export function showUsageRouter(router) {
290
- const cmds = Object.entries(router);
291
- if (cmds.length > 0) {
292
- console.info("\nSUBCOMMANDS:");
293
- const maxLength = Math.max(...cmds.map(([cmd]) => cmd.length));
294
- cmds.forEach((cmd) => {
295
- console.info(
296
- " ",
297
- `${cmd[0]}${" ".repeat(maxLength - cmd[0].length)}`,
298
- " ",
299
- cmd[1].hint,
300
- );
301
- });
302
- }
303
- }
304
-
305
- export function showUsageError(cmd, subcmd, module, error, flags) {
306
- showUsageSubcommand(cmd, subcmd, module, error);
307
- if (error) {
308
- console.info("\nERROR:");
309
- if (flags?.debug) {
310
- console.error(error);
311
- } else {
312
- console.error(colors.red(error?.stack?.split("\n")[0] || error));
313
- }
314
- }
315
- }
316
-
317
- export function showUsageEnvars(envars) {
318
- if (envars) {
319
- envars = Object.entries(envars);
320
- if (envars.length > 0) {
321
- console.info("\nENVARS:");
322
- const maxWidth = Math.max(...envars.map(([envar]) => envar.length));
323
- envars.forEach(([envar, hint]) => {
324
- if (envar.toUpperCase().indexOf("KEY") < 0 && process.env[envar]) {
325
- console.info(
326
- " ",
327
- `${yellow(envar.toUpperCase())}${" ".repeat(maxWidth - envar.length)}`,
328
- ` => Settled to "${myellow(process.env[envar])}"`,
329
- );
330
- } else {
331
- console.info(
332
- " ",
333
- `${yellow(envar.toUpperCase())}${" ".repeat(maxWidth - envar.length)}`,
334
- ` ${hint}`,
335
- );
336
- }
337
- });
338
- }
339
- }
340
- }
341
-
342
- export function showUsageFlags(flags) {
343
- if (flags) {
344
- flags = Object.entries(flags)
345
- .filter(([, flag]) => !flag?.param)
346
- .sort(([a], [b]) => {
347
- if (a < b) return -1;
348
- else if (a > b) return 1;
349
- else return 0;
350
- });
351
- if (flags.length > 0) {
352
- console.info("\nFLAGS:");
353
- const maxLength = Math.max(
354
- ...flags
355
- .filter(([, { hint }]) => hint)
356
- .map(([key, { param }]) =>
357
- param ? key.length + param.length + 3 : key.length,
358
- ),
359
- );
360
- flags.forEach((flag) => {
361
- const str = `${flag[0]}${flag[1].param ? gray(` <${flag[1].param}>`) : ""}`;
362
- if (flag[1].hint) {
363
- console.info(
364
- " ",
365
- `--${str}${" ".repeat(maxLength - colorstrip(str).length)}`,
366
- " ",
367
- flag[1].hint,
368
- );
369
- }
370
- });
371
- }
372
- }
373
- }
374
-
375
- export function showUsageHeadline(cmd, subcmd, module) {
376
- console.info("USAGE:");
377
- if (subcmd) {
378
- let params = module.router[subcmd]?.params;
379
- // const options = module.router[subcmd]?.options
380
- if (params) {
381
- const optionalize = (str) =>
382
- str.endsWith(" ...]")
383
- ? `[<${str.slice(1, -5)}> ...]`
384
- : str[0] === "["
385
- ? `[<${str.slice(1, -1)}>]`
386
- : `<${str}>`;
387
- if (Array.isArray(params)) {
388
- params = `${params.map((param) => optionalize(param)).join(" ")} `;
389
- } else {
390
- params = optionalize(params);
391
- }
392
- }
393
- console.info(
394
- ` ${colors.white(`npx witsdk ${cmd}`)} ${colors.white(subcmd)} ${params ? `${colors.green(params)} ` : ""}[OPTIONS] [FLAGS]`,
395
- );
396
- if (module?.router[subcmd]?.hint) {
397
- console.info("\nDESCRIPTION:");
398
- console.info(` ${module.router[subcmd].hint}`);
399
- }
400
- } else {
401
- console.info(
402
- ` ${colors.white(`npx witsdk ${cmd}`)} <SUBCOMMAND> ... [OPTIONS] [FLAGS]`,
403
- );
404
- }
405
- }
406
-
407
- export function showUsageOptions(options) {
408
- options = Object.entries(options)
409
- .filter(([, option]) => option?.param)
410
- .sort(([a], [b]) => {
411
- if (a < b) return -1;
412
- else if (a > b) return 1;
413
- else return 0;
414
- });
415
- if (options.length > 0) {
416
- console.info("\nOPTIONS:");
417
- const maxLength = options
418
- .map((option) =>
419
- option[1].param
420
- ? option[1].param.length + option[0].length + 3
421
- : option[0].length,
422
- )
423
- .reduce((prev, curr) => (curr > prev ? curr : prev));
424
- options.forEach((option) => {
425
- if (option[1].hint) {
426
- const str = `${option[0]}${option[1].param ? gray(` <${option[1].param}>`) : ""}`;
427
- console.info(
428
- " ",
429
- `--${str}${" ".repeat(maxLength - colorstrip(str).length)}`,
430
- " ",
431
- option[1].hint,
432
- );
433
- }
434
- });
435
- }
436
- }
437
-
438
- export function showUsageSubcommand(cmd, subcmd, module) {
439
- showUsageHeadline(cmd, subcmd, module);
440
- showUsageOptions({ ...module?.flags, ...module.router[subcmd]?.options });
441
- showUsageFlags({ ...module?.flags, ...module.router[subcmd]?.options });
442
- showUsageEnvars(module.router[subcmd]?.envars || module?.envars);
443
- }
444
-
445
- export function showVersion() {
446
- console.info(
447
- `${colors.mcyan(`Witnet SDK v${require("../../package.json").version}`)}`,
448
- );
449
- }
450
-
451
- export function getWildcardsCountFromString(str) {
452
- let maxArgsIndex = 0;
453
- if (str && typeof str === "string") {
454
- let match;
455
- const regexp = /\\\d\\/g;
456
- while ((match = regexp.exec(str)) !== null) {
457
- const argsIndex = parseInt(match[0][1], 10) + 1;
458
- if (argsIndex > maxArgsIndex) maxArgsIndex = argsIndex;
459
- }
460
- }
461
- return maxArgsIndex;
462
- }
463
-
464
- export function checkRpcWildcards(wildcards) {
465
- if (typeof wildcards === "object") {
466
- Object.values(wildcards).forEach((wildcard) => {
467
- if (Array.isArray(wildcard))
468
- wildcard.forEach((item) => checkRpcWildcards(item));
469
- else checkRpcWildcards(wildcard);
470
- });
471
- } else if (Array.isArray(wildcards)) {
472
- wildcards.forEach((wildcard) => checkRpcWildcards(wildcard));
473
- } else if (typeof wildcards === "string") {
474
- if (isWildcard(wildcards)) {
475
- const char = wildcards.charAt(1);
476
- if (char < "0" || char > "9") {
477
- throw Error("RPC: wildcards not in range [0 .. 9]");
478
- }
479
- }
480
- }
481
- }
482
-
483
- export function isWildcard(str) {
484
- return str.length === 3 && /\\\d\\/g.test(str);
485
- }
486
-
487
- export function replaceWildcards(obj, args) {
488
- if (args.length > 10) args = args.slice(0, 10);
489
- if (obj && typeof obj === "string") {
490
- for (let argIndex = 0; argIndex < args.length; argIndex++) {
491
- const wildcard = `\\${argIndex}\\`;
492
- obj = obj.replaceAll(wildcard, args[argIndex]);
493
- }
494
- } else if (obj && Array.isArray(obj)) {
495
- obj = obj.map((value) =>
496
- typeof value === "string" || Array.isArray(value)
497
- ? replaceWildcards(value, args)
498
- : value,
499
- );
500
- } else if (obj && typeof obj === "object") {
501
- obj = replaceObjectWildcards(obj, args);
502
- }
503
- return obj;
504
- }
505
-
506
- export function replaceObjectWildcards(obj, args) {
507
- return Object.fromEntries(
508
- Object.entries(obj).map(([key, value]) => {
509
- for (let argIndex = 0; argIndex < args.length; argIndex++) {
510
- const wildcard = `\\${argIndex}\\`;
511
- key = key.replaceAll(wildcard, args[argIndex]);
512
- value = replaceWildcards(value, args);
513
- }
514
- return [key, value];
515
- }),
516
- );
517
- }
518
-
519
- export function spliceWildcard(obj, argIndex, argValue, argsCount) {
520
- if (obj && typeof obj === "string") {
521
- const wildcard = `\\${argIndex}\\`;
522
- obj = obj.replaceAll(wildcard, argValue);
523
- for (let j = argIndex + 1; j < argsCount; j++) {
524
- obj = obj.replaceAll(`\\${j}\\`, `\\${j - 1}\\`);
525
- }
526
- } else if (obj && Array.isArray(obj)) {
527
- obj = obj.map((value) =>
528
- typeof value === "string" || Array.isArray(value)
529
- ? spliceWildcard(value, argIndex, argValue, argsCount)
530
- : value,
531
- );
532
- }
533
- return obj;
534
- }
535
-
536
- export async function toolkitRun(settings, args) {
537
- const cmd = `${settings.paths.toolkitBinPath} ${args.join(" ")}`;
538
- return new Promise((resolve, reject) => {
539
- exec(cmd, { maxBuffer: 1024 * 1024 * 10 }, (error, stdout, stderr) => {
540
- if (error) {
541
- reject(error);
542
- }
543
- if (stderr) {
544
- reject(stderr);
545
- }
546
- resolve(stdout);
547
- });
548
- });
549
- }
550
-
551
- export function toUpperCamelCase(str) {
552
- return str
553
- .replace(/\b(\w)/g, (_match, capture) => capture.toUpperCase())
554
- .replace(/\s+/g, "");
555
- }
556
-
557
- export function toUtf16Bytes(str) {
558
- const bytes = new Uint8Array(str.length * 2);
559
- for (let i = 0; i < str.length; i++) {
560
- const code = str.charCodeAt(i);
561
- bytes[i * 2] = code >> 8;
562
- bytes[i * 2 + 1] = code & 0xff;
563
- }
564
- return bytes;
565
- }
566
-
567
- export function toUtf8Array(str) {
568
- const utf8 = [];
569
- for (let i = 0; i < str.length; i++) {
570
- let charcode = str.charCodeAt(i);
571
- if (charcode < 0x80) utf8.push(charcode);
572
- else if (charcode < 0x800) {
573
- utf8.push(0xc0 | (charcode >> 6), 0x80 | (charcode & 0x3f));
574
- } else if (charcode < 0xd800 || charcode >= 0xe000) {
575
- utf8.push(
576
- 0xe0 | (charcode >> 12),
577
- 0x80 | ((charcode >> 6) & 0x3f),
578
- 0x80 | (charcode & 0x3f),
579
- );
580
- } else {
581
- // surrogate pair
582
- i++;
583
- // UTF-16 encodes 0x10000-0x10FFFF by
584
- // subtracting 0x10000 and splitting the
585
- // 20 bits of 0x0-0xFFFFF into two halves
586
- charcode =
587
- 0x10000 + (((charcode & 0x3ff) << 10) | (str.charCodeAt(i) & 0x3ff));
588
- utf8.push(
589
- 0xf0 | (charcode >> 18),
590
- 0x80 | ((charcode >> 12) & 0x3f),
591
- 0x80 | ((charcode >> 6) & 0x3f),
592
- 0x80 | (charcode & 0x3f),
593
- );
594
- }
595
- }
596
- return utf8;
597
- }
598
-
599
- export function utf8ArrayToStr(array) {
600
- const len = array.length;
601
- let out = "";
602
- let i = 0;
603
- let c;
604
- let char2, char3;
605
- while (i < len) {
606
- c = array[i++];
607
- switch (c >> 4) {
608
- case 0:
609
- case 1:
610
- case 2:
611
- case 3:
612
- case 4:
613
- case 5:
614
- case 6:
615
- case 7:
616
- // 0xxxxxxx
617
- out += String.fromCharCode(c);
618
- break;
619
- case 12:
620
- case 13:
621
- // 110x xxxx 10xx xxxx
622
- char2 = array[i++];
623
- out += String.fromCharCode(((c & 0x1f) << 6) | (char2 & 0x3f));
624
- break;
625
- case 14:
626
- // 1110 xxxx 10xx xxxx 10xx xxxx
627
- char2 = array[i++];
628
- char3 = array[i++];
629
- out += String.fromCharCode(
630
- ((c & 0x0f) << 12) | ((char2 & 0x3f) << 6) | ((char3 & 0x3f) << 0),
631
- );
632
- break;
633
- }
634
- }
635
- return out;
636
- }
637
-
638
- export async function prompt(question) {
639
- const readlineInterface = readline.createInterface({
640
- input: process.stdin,
641
- output: process.stdout,
642
- });
643
- return new Promise((resolve, _reject) => {
644
- readlineInterface.question(`${question} `, (response) => {
645
- readlineInterface.close();
646
- resolve(response.trim());
647
- });
648
- });
649
- }
650
-
651
- export function prompter(promise) {
652
- const loading = (() => {
653
- const h = ["|", "/", "-", "\\"];
654
- let i = 0;
655
- return setInterval(() => {
656
- i = i > 3 ? 0 : i;
657
- process.stdout.write(`\b\b${h[i]} `);
658
- i++;
659
- }, 50);
660
- })();
661
- return promise.then((result) => {
662
- clearInterval(loading);
663
- process.stdout.write("\b\b");
664
- return result;
665
- });
666
- }
667
-
668
- export function traceChecklists(checklists) {
669
- if (checklists && Object.keys(checklists).length > 0) {
670
- const headlines = [
671
- "NODES",
672
- ...Object.keys(checklists).map((key) => `:${key}`),
673
- ];
674
- checklists = Object.values(checklists);
675
- const urls = Object.keys(checklists[0]);
676
- const records = urls.map((url) => {
677
- const errors = checklists.filter(
678
- (checklist) => checklist[url] instanceof Error,
679
- ).length;
680
- return [
681
- errors === checklists.length
682
- ? colors.red(url)
683
- : errors > 0
684
- ? colors.myellow(url)
685
- : colors.mcyan(url),
686
- ...checklists.map((checklist) =>
687
- checklist[url] instanceof Error
688
- ? colors.red(checklist[url])
689
- : checklist[url] === true
690
- ? colors.lcyan("Aye")
691
- : colors.cyan("Nay"),
692
- ),
693
- ];
694
- });
695
- traceTable(records, {
696
- headlines,
697
- maxColumnWidth: 31,
698
- });
699
- }
700
- }
701
-
702
- export function traceHeader(headline, color = normal, indent = "") {
703
- console.info(`${indent}┌─${"─".repeat(headline.length)}─┐`);
704
- console.info(`${indent}│ ${color(headline)} │`);
705
- console.info(`${indent}└─${"─".repeat(headline.length)}─┘`);
706
- }
707
-
708
- export function traceTable(records, options) {
709
- const stringify = (data, humanizers, index) =>
710
- humanizers?.[index]
711
- ? humanizers[index](data).toString()
712
- : (data?.toString() ?? "");
713
- const max = (a, b) => (a > b ? a : b);
714
- const reduceMax = (numbers) =>
715
- numbers.reduce((curr, prev) => (prev > curr ? prev : curr), 0);
716
- if (!options) options = {};
717
- const indent = options?.indent || "";
718
- const numColumns = reduceMax(records.map((record) => record?.length || 1));
719
- const maxColumnWidth = options?.maxColumnWidth || 80;
720
- const table = transpose(records, numColumns);
721
- options.widths =
722
- options?.widths ||
723
- table.map((column, index) => {
724
- let maxWidth = reduceMax(
725
- column.map(
726
- (field) =>
727
- colorstrip(stringify(field, options?.humanizers, index)).length,
728
- ),
729
- );
730
- if (options?.headlines?.[index]) {
731
- maxWidth = max(
732
- maxWidth,
733
- colorstrip(options.headlines[index].replaceAll(":", "")).length,
734
- );
735
- }
736
- return Math.min(maxWidth, maxColumnWidth);
737
- });
738
- let headline = options.widths.map((maxWidth) => "─".repeat(maxWidth));
739
- console.info(`${indent}┌─${headline.join("─┬─")}─┐`);
740
- if (options?.headlines) {
741
- headline = options.widths.map((maxWidth, index) => {
742
- const caption = options.headlines[index].replaceAll(":", "");
743
- const captionLength = colorstrip(caption).length;
744
- return `${white(caption)}${" ".repeat(maxWidth - captionLength)}`;
745
- });
746
- console.info(`${indent}│ ${headline.join(" │ ")} │`);
747
- headline = options.widths.map((maxWidth) => "─".repeat(maxWidth));
748
- console.info(`${indent}├─${headline.join("─┼─")}─┤`);
749
- }
750
- for (let i = 0; i < records.length; i++) {
751
- let line = "";
752
- for (let j = 0; j < numColumns; j++) {
753
- let data = table[j][i];
754
- let color;
755
- if (options?.colors?.[j]) {
756
- color = options.colors[j];
757
- } else {
758
- color =
759
- typeof data === "string"
760
- ? green
761
- : Number(data) === data && data % 1 !== 0 // is float number?
762
- ? yellow
763
- : (x) => x;
764
- }
765
- data = stringify(data, options?.humanizers, j);
766
- if (colorstrip(data).length > maxColumnWidth) {
767
- while (colorstrip(data).length > maxColumnWidth - 3) {
768
- data = data.slice(0, -1);
769
- }
770
- data += "...";
771
- }
772
- const dataLength = colorstrip(data).length;
773
- if (options?.headlines && options.headlines[j][0] === ":") {
774
- data = `${color(data)}${" ".repeat(options.widths[j] - dataLength)}`;
775
- } else {
776
- data = `${" ".repeat(options.widths[j] - dataLength)}${color(data)}`;
777
- }
778
- line += `│ ${data} `;
779
- }
780
- console.info(`${indent}${line}│`);
781
- }
782
- headline = options.widths.map((maxWidth) => "─".repeat(maxWidth));
783
- console.info(`${indent}└─${headline.join("─┴─")}─┘`);
784
- }
785
-
786
- function transpose(records, numColumns) {
787
- const columns = [];
788
- for (let index = 0; index < numColumns; index++) {
789
- columns.push(records.map((row) => row[index]));
790
- }
791
- return columns;
792
- }
793
-
794
- export function txJsonReplacer(key, value) {
795
- switch (key) {
796
- case "bytes":
797
- case "der":
798
- return toHexString(value, true);
799
- case "tx":
800
- return JSON.stringify(value, txJsonReplacer);
801
- case "change":
802
- case "fees":
803
- case "value":
804
- return parseInt(value, 10) / 10 ** 9;
805
- default:
806
- return value;
807
- }
808
- }
809
-
810
- export function txReceiptJsonReplacer(key, value) {
811
- switch (key) {
812
- case "bytes":
813
- case "der":
814
- return toHexString(value, true);
815
- case "tx":
816
- return JSON.stringify(value, txJsonReplacer);
817
- case "change":
818
- case "fees":
819
- case "value":
820
- return parseInt(value?.pedros, 10) / 10 ** 9;
821
- case "timestamp":
822
- return moment.unix(value).format("MMMM Do YYYY, h:mm:ss a");
823
- default:
824
- return value;
825
- }
826
- }
827
-
828
- export function traceTransactionOnCheckpoint(receipt) {
829
- if (receipt?.confirmations) {
830
- console.info(` > Checkpoint #${commas(receipt.confirmations)}...`);
831
- }
832
- }
833
-
834
- export function traceTransactionOnStatusChange(receipt) {
835
- const captions = {
836
- pending: "Awaiting relay...",
837
- // confirmed: "Transaction confirmed:",
838
- // finalized: "Transaction finalized:",
839
- relayed: "Awaiting inclusion...",
840
- mined: "Awaiting confirmations...",
841
- };
842
- const caption = captions[receipt.status];
843
- if (caption) console.info(` > ${captions[receipt.status]}`);
844
- if (["finalized", "confirmed"].includes(receipt.status)) {
845
- console.info(` > Block hash: ${colors.gray(receipt?.blockHash)}`);
846
- console.info(` > Block miner: ${colors.cyan(receipt?.blockMiner)}`);
847
- console.info(
848
- ` > Block epoch: ${colors.white(commas(receipt?.blockEpoch))}`,
849
- );
850
- console.info(
851
- ` > Included at: ${colors.green(moment.unix(receipt?.blockTimestamp).format("MMMM Do YYYY, h:mm:ss a"))}`,
852
- );
853
- console.info(
854
- ` > ${receipt.status[0].toUpperCase() + receipt.status.slice(1)} at: ${colors.mgreen(moment.unix(receipt.timestamp).format("MMMM Do YYYY, h:mm:ss a"))}`,
855
- );
856
- }
857
- }
858
-
859
- export function traceTransactionReceipt(receipt) {
860
- const captions = {
861
- DataRequest: " > DRT hash: ",
862
- ValueTransfer: " > VTT hash: ",
863
- };
864
- console.info(
865
- `${captions[receipt.type] || " > TX hash: "}${colors.white(receipt.hash)}`,
866
- );
867
- if (receipt?.droHash)
868
- console.info(` > DRO hash: ${colors.green(receipt.droHash)}`);
869
- if (receipt?.radHash)
870
- console.info(` > RAD hash: ${colors.mgreen(receipt.radHash)}`);
871
- if (receipt?.droSLA)
872
- console.info(` > SLA params: ${JSON.stringify(receipt.droSLA)}`);
873
- if (receipt?.withdrawer) {
874
- if (receipt?.validator) {
875
- console.info(` > Validator: ${colors.mcyan(receipt.validator)}`);
876
- }
877
- console.info(` > Withdrawer: ${colors.mmagenta(receipt.withdrawer)}`);
878
- } else {
879
- const signers = Array.isArray(receipt.from) ? receipt.from : [receipt.from];
880
- console.info(` > Signer/s: ${colors.mmagenta(signers[0])}`);
881
- signers.slice(1).forEach((signer) => {
882
- console.info(` ${colors.mmagenta(signer)}`);
883
- });
884
- }
885
- if (receipt?.recipients) {
886
- console.info(
887
- ` > Recipient/s: ${colors.mblue(
888
- receipt.recipients.filter(
889
- (pkh, index, array) => index === array.indexOf(pkh),
890
- ),
891
- )}`,
892
- );
893
- }
894
- if (receipt?.fees)
895
- console.info(` > Network fee: ${colors.yellow(receipt.fees.toString(2))}`);
896
- if (receipt?.value)
897
- console.info(
898
- ` > Value: ${colors.myellow(receipt.value.toString(2))}`,
899
- );
900
- if (receipt?.weight)
901
- console.info(` > Weight: ${colors.mgreen(commas(receipt.weight))}`);
902
- if (receipt?.witnesses) {
903
- console.info(` > Witnesses: ${receipt.witnesses}`);
904
- }
905
- }
906
-
907
- export async function traceTransaction(transmitter, options) {
908
- const color = options?.color || ((x) => `\x1b[30;45m${x}\x1b[0m`);
909
- let receipt = await transmitter.signTransaction(options, options?.reload);
910
- if (options?.verbose) {
911
- console.info(`\n${gray(JSON.stringify(receipt.tx, txJsonReplacer))}`);
912
- }
913
- if (options?.headline) {
914
- console.info(`\n ${color(` ${options.headline} `)}\n`);
915
- }
916
- traceTransactionReceipt(receipt);
917
- if (!options?.force) {
918
- // prompt user confirmation
919
- console.info();
920
- const answer = await require("inquirer").createPromptModule()([
921
- {
922
- message: "Send transaction?",
923
- type: "confirm",
924
- name: "continue",
925
- default: false,
926
- },
927
- ]);
928
- if (!answer.continue) {
929
- return receipt;
930
- }
931
- }
932
- try {
933
- console.info();
934
- receipt = await transmitter.sendTransaction();
935
- if (options?.await || options?.confirmations !== undefined) {
936
- receipt = await transmitter.confirmTransaction(receipt.hash, {
937
- confirmations: options?.confirmations || 0,
938
- onCheckpoint: traceTransactionOnCheckpoint,
939
- onStatusChange: traceTransactionOnStatusChange,
940
- });
941
- } else {
942
- const data = {
943
- status: receipt?.status,
944
- timestamp: receipt?.timestamp || Math.floor(Date.now() / 1000),
945
- };
946
- console.info(data);
947
- }
948
- } catch (err) {
949
- if (err?.inFlight && err.inFlight) {
950
- console.info(
951
- `\n${colors.gray(JSON.stringify(err.inFligt?.message, txReceiptJsonReplacer))}`,
952
- );
953
- }
954
- throw err;
955
- }
956
- return receipt;
957
- }
958
-
959
- export function unescapeSlashes(str) {
960
- // add another escaped slash if the string ends with an odd
961
- // number of escaped slashes which will crash JSON.parse
962
- let parsedStr = str.replace(/(^|[^\\])(\\\\)*\\$/, "$&\\");
963
-
964
- // escape unescaped double quotes to prevent error with
965
- // added double quotes in json string
966
- parsedStr = parsedStr.replace(/(^|[^\\])((\\\\)*")/g, "$1\\$2");
967
-
968
- try {
969
- parsedStr = JSON.parse(`"${parsedStr}"`);
970
- } catch (_e) {
971
- return str;
972
- }
973
- return parsedStr;
974
- }
1
+ import { exec } from "node:child_process";
2
+ import { createRequire } from "node:module";
3
+ import * as net from "node:net";
4
+ import * as os from "node:os";
5
+ import * as readline from "node:readline";
6
+ import moment from "moment";
7
+
8
+ const require = createRequire(import.meta.url);
9
+
10
+ export const colorstrip = (str) =>
11
+ str.replace(
12
+ /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g,
13
+ "",
14
+ );
15
+
16
+ export const commas = (number) => {
17
+ const parts = number.toString().split(".");
18
+ const result =
19
+ parts.length <= 1
20
+ ? `${parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",")}`
21
+ : `${parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",")}.${parts[1]}`;
22
+ return result;
23
+ };
24
+
25
+ export function toFixedTrunc(x, n) {
26
+ const v = (typeof x === "string" ? x : x.toString()).split(".");
27
+ if (n <= 0) return v[0];
28
+ let f = v[1] || "";
29
+ if (f.length > n) return `${v[0]}.${f.substr(0, n)}`;
30
+ while (f.length < n) f += "0";
31
+ return `${v[0]}.${f}`;
32
+ }
33
+
34
+ export const whole_wits = (number, digits) => {
35
+ const lookup = [
36
+ { value: 1n, symbol: "pedros" },
37
+ { value: 10n ** 6n, symbol: "mWits" },
38
+ { value: 10n ** 9n, symbol: " Wits" },
39
+ { value: 10n ** 12n, symbol: "KWits" },
40
+ { value: 10n ** 15n, symbol: "MWits" },
41
+ ];
42
+ // const regexp = /\.0+$|(?<=\.[0-9])0+$/
43
+ const item = lookup.findLast((item) => number >= item.value);
44
+ const quotient = item
45
+ ? Number(BigInt(number) / item.value)
46
+ : number.toString();
47
+ const decimals = item
48
+ ? (item.value + BigInt(number) - BigInt(quotient) * item.value)
49
+ .toString()
50
+ .slice(1)
51
+ : "";
52
+ return item
53
+ ? `${commas(quotient)}${decimals !== "" ? `.${decimals.slice(0, digits)}` : ""} ${item.symbol}`
54
+ : "(no coins)";
55
+ };
56
+
57
+ const bblue = (str) => `\x1b[1;98;44m${str}\x1b[0;0;0m`;
58
+ const bcyan = (str) => `\x1b[38;46m${str}\x1b[0;0m`;
59
+ const bgreen = (str) => `\x1b[30;42m${str}\x1b[0;0m`;
60
+ const bred = (str) => `\x1b[30;41m${str}\x1b[0;0m`;
61
+ const bviolet = (str) => `\x1b[30;45m${str}\x1b[0;0m`;
62
+
63
+ const lcyan = (str) => `\x1b[1;96m${str}\x1b[0m`;
64
+ const lgray = (str) => `\x1b[1;90m${str}\x1b[0m`;
65
+ const lgreen = (str) => `\x1b[1;92m${str}\x1b[0m`;
66
+ const lmagenta = (str) => `\x1b[1;95m${str}\x1b[0m`;
67
+ const lyellow = (str) => `\x1b[1;93m${str}\x1b[0m`;
68
+ const mblue = (str) => `\x1b[94m${str}\x1b[0m`;
69
+ const mcyan = (str) => `\x1b[96m${str}\x1b[0m`;
70
+ const mgreen = (str) => `\x1b[92m${str}\x1b[0m`;
71
+ const mmagenta = (str) => `\x1b[0;95m${str}\x1b[0m`;
72
+ const mred = (str) => `\x1b[91m${str}\x1b[0m`;
73
+ const myellow = (str) => `\x1b[93m${str}\x1b[0m`;
74
+
75
+ const blue = (str) => `\x1b[34m${str}\x1b[0m`;
76
+ const cyan = (str) => `\x1b[36m${str}\x1b[0m`;
77
+ const gray = (str) => `\x1b[90m${str}\x1b[0m`;
78
+ const green = (str) => `\x1b[32m${str}\x1b[0m`;
79
+ const magenta = (str) => `\x1b[0;35m${str}\x1b[0m`;
80
+ const normal = (str) => `\x1b[98m${str}\x1b[0m`;
81
+ const red = (str) => `\x1b[31m${str}\x1b[0m`;
82
+ const white = (str) => `\x1b[1;98m${str}\x1b[0m`;
83
+ const yellow = (str) => `\x1b[33m${str}\x1b[0m`;
84
+
85
+ export const colors = {
86
+ bblue,
87
+ bcyan,
88
+ bgreen,
89
+ bred,
90
+ bviolet,
91
+ lcyan,
92
+ lgray,
93
+ lgreen,
94
+ lmagenta,
95
+ lyellow,
96
+ mblue,
97
+ mcyan,
98
+ mgreen,
99
+ mmagenta,
100
+ mred,
101
+ myellow,
102
+ blue,
103
+ cyan,
104
+ gray,
105
+ green,
106
+ magenta,
107
+ normal,
108
+ red,
109
+ white,
110
+ yellow,
111
+ };
112
+
113
+ export function countLeaves(t, obj) {
114
+ if (!obj || typeof obj === "string") return 0;
115
+ if (obj instanceof t) return 1;
116
+ if (Array.isArray(obj))
117
+ return obj.reduce((sum, item) => sum + countLeaves(t, item), 0);
118
+ else
119
+ return Object.values(obj).reduce(
120
+ (sum, item) => sum + countLeaves(t, item),
121
+ 0,
122
+ );
123
+ }
124
+
125
+ export function deleteExtraFlags(args) {
126
+ return args.filter((arg) => !arg.startsWith("--"));
127
+ }
128
+
129
+ export function cmd(...command) {
130
+ return new Promise((resolve, reject) => {
131
+ exec(
132
+ command.join(" "),
133
+ { maxBuffer: 1024 * 1024 * 10 },
134
+ (error, stdout, stderr) => {
135
+ if (error) {
136
+ reject(error);
137
+ }
138
+ if (stderr) {
139
+ reject(stderr);
140
+ }
141
+ resolve(stdout);
142
+ },
143
+ );
144
+ });
145
+ }
146
+
147
+ export async function execRadonBytecode(bytecode, ...flags) {
148
+ if (!isHexString(bytecode)) {
149
+ throw EvalError("invalid hex string");
150
+ } else {
151
+ const npx = os.type() === "Windows_NT" ? "npx.cmd" : "npx";
152
+ return cmd(npx, "witsdk", "radon", "dry-run", bytecode, ...flags);
153
+ // .catch((err) => {
154
+ // let errorMessage = err.message.split('\n').slice(1).join('\n').trim()
155
+ // const errorRegex = /.*^error: (?<message>.*)$.*/gm
156
+ // const matched = errorRegex.exec(err.message)
157
+ // if (matched) {
158
+ // errorMessage = matched.groups.message
159
+ // }
160
+ // console.log(errorMessage || err)
161
+ // console.error(errorMessage || err)
162
+ // })
163
+ }
164
+ }
165
+
166
+ export function extractFromArgs(args, flags) {
167
+ const curated = {};
168
+ if (args && flags) {
169
+ Object.keys(flags).forEach((flag) => {
170
+ const flagIndex = args.indexOf(`--${flag}`);
171
+ if (flagIndex >= 0) {
172
+ if (flags[flag].param) {
173
+ curated[flag] = args[flagIndex];
174
+ if (!args[flagIndex + 1] || args[flagIndex + 1].startsWith("--")) {
175
+ throw Error(`Missing required parameter for --${flag}`);
176
+ } else {
177
+ curated[flag] = args[flagIndex + 1];
178
+ args.splice(flagIndex, 2);
179
+ }
180
+ } else {
181
+ curated[flag] = true;
182
+ args.splice(flagIndex, 1);
183
+ }
184
+ }
185
+ });
186
+ }
187
+ return [args, curated];
188
+ }
189
+
190
+ export function fromHexString(hexString) {
191
+ if (hexString.startsWith("0x")) hexString = hexString.slice(2);
192
+ return Uint8Array.from(
193
+ hexString.match(/.{1,2}/g).map((byte) => parseInt(byte, 16)),
194
+ );
195
+ }
196
+
197
+ export function ipIsPrivateOrLocalhost(ip) {
198
+ if (ip.substring(0, 7) === "::ffff:") {
199
+ ip = ip.substring(7);
200
+ }
201
+
202
+ if (net.isIPv4(ip)) {
203
+ // check localhost
204
+ if (ip === "127.0.0.1") {
205
+ return true;
206
+ }
207
+
208
+ // 10.0.0.0 - 10.255.255.255 || 172.16.0.0 - 172.31.255.255 || 192.168.0.0 - 192.168.255.255
209
+ return (
210
+ /^(10)\.(.*)\.(.*)\.(.*)$/.test(ip) ||
211
+ /^(172)\.(1[6-9]|2[0-9]|3[0-1])\.(.*)\.(.*)$/.test(ip) ||
212
+ /^(192)\.(168)\.(.*)\.(.*)$/.test(ip)
213
+ );
214
+ }
215
+
216
+ // else: ip is IPv6
217
+ const firstWord = ip.split(":").find((el) => !!el); // get first not empty word
218
+
219
+ // equivalent of 127.0.0.1 in IPv6
220
+ if (ip === "::1") return true;
221
+ // The original IPv6 Site Local addresses (fec0::/10) are deprecated. Range: fec0 - feff
222
+ else if (/^fe[c-f][0-f]$/.test(firstWord)) return true;
223
+ // These days Unique Local Addresses (ULA) are used in place of Site Local.
224
+ // Range: fc00 - fcff
225
+ else if (/^fc[0-f]{2}$/.test(firstWord)) return true;
226
+ // Range: fd00 - fcff
227
+ else if (/^fd[0-f]{2}$/.test(firstWord)) return true;
228
+ // Link local addresses (prefixed with fe80) are not routable
229
+ else if (firstWord === "fe80") return true;
230
+ // Discard Prefix
231
+ else if (firstWord === "100") return true;
232
+
233
+ // Any other IP address is not Unique Local Address (ULA)
234
+ return false;
235
+ }
236
+
237
+ export function isHexStringOfLength(str, length) {
238
+ return (
239
+ (isHexString(str) &&
240
+ ((str.startsWith("0x") && str.slice(2).length === length * 2) ||
241
+ str.length === length * 2)) ||
242
+ isWildcard(str)
243
+ );
244
+ }
245
+
246
+ export function isHexString(str) {
247
+ return (
248
+ (typeof str === "string" &&
249
+ ((str.startsWith("0x") && /^[a-fA-F0-9]+$/i.test(str.slice(2))) ||
250
+ /^[a-fA-F0-9]+$/i.test(str))) ||
251
+ isWildcard(str)
252
+ );
253
+ }
254
+
255
+ export function toHexString(buffer, prefix0x = false) {
256
+ if (buffer instanceof Uint8Array) buffer = Buffer.from(buffer);
257
+ return (
258
+ (prefix0x ? "0x" : "") +
259
+ Array.prototype.map
260
+ .call(buffer, (x) => `00${x.toString(16)}`.slice(-2))
261
+ .join("")
262
+ .match(/[a-fA-F0-9]{2}/g)
263
+ .join("")
264
+ );
265
+ }
266
+
267
+ export function parseURL(url) {
268
+ try {
269
+ const parsedUrl = new URL(url);
270
+ return [
271
+ `${parsedUrl.protocol}//`,
272
+ parsedUrl.host,
273
+ parsedUrl.pathname.slice(1),
274
+ parsedUrl.search.slice(1),
275
+ ];
276
+ } catch {
277
+ throw new TypeError(`Invalid URL was provided: ${url}`);
278
+ }
279
+ }
280
+
281
+ export function showUsage(cmd, module) {
282
+ showUsageHeadline(cmd);
283
+ showUsageOptions({ ...module?.flags });
284
+ showUsageFlags({ ...module?.flags });
285
+ showUsageRouter({ ...module?.router });
286
+ showUsageEnvars({ ...module?.envars });
287
+ }
288
+
289
+ export function showUsageRouter(router) {
290
+ const cmds = Object.entries(router);
291
+ if (cmds.length > 0) {
292
+ console.info("\nSUBCOMMANDS:");
293
+ const maxLength = Math.max(...cmds.map(([cmd]) => cmd.length));
294
+ cmds.forEach((cmd) => {
295
+ console.info(
296
+ " ",
297
+ `${cmd[0]}${" ".repeat(maxLength - cmd[0].length)}`,
298
+ " ",
299
+ cmd[1].hint,
300
+ );
301
+ });
302
+ }
303
+ }
304
+
305
+ export function showUsageError(cmd, subcmd, module, error, flags) {
306
+ showUsageSubcommand(cmd, subcmd, module, error);
307
+ if (error) {
308
+ console.info("\nERROR:");
309
+ if (flags?.debug) {
310
+ console.error(error);
311
+ } else {
312
+ console.error(colors.red(error?.stack?.split("\n")[0] || error));
313
+ }
314
+ }
315
+ }
316
+
317
+ export function showUsageEnvars(envars) {
318
+ if (envars) {
319
+ envars = Object.entries(envars);
320
+ if (envars.length > 0) {
321
+ console.info("\nENVARS:");
322
+ const maxWidth = Math.max(...envars.map(([envar]) => envar.length));
323
+ envars.forEach(([envar, hint]) => {
324
+ if (envar.toUpperCase().indexOf("KEY") < 0 && process.env[envar]) {
325
+ console.info(
326
+ " ",
327
+ `${yellow(envar.toUpperCase())}${" ".repeat(maxWidth - envar.length)}`,
328
+ ` => Settled to "${myellow(process.env[envar])}"`,
329
+ );
330
+ } else {
331
+ console.info(
332
+ " ",
333
+ `${yellow(envar.toUpperCase())}${" ".repeat(maxWidth - envar.length)}`,
334
+ ` ${hint}`,
335
+ );
336
+ }
337
+ });
338
+ }
339
+ }
340
+ }
341
+
342
+ export function showUsageFlags(flags) {
343
+ if (flags) {
344
+ flags = Object.entries(flags)
345
+ .filter(([, flag]) => !flag?.param)
346
+ .sort(([a], [b]) => {
347
+ if (a < b) return -1;
348
+ else if (a > b) return 1;
349
+ else return 0;
350
+ });
351
+ if (flags.length > 0) {
352
+ console.info("\nFLAGS:");
353
+ const maxLength = Math.max(
354
+ ...flags
355
+ .filter(([, { hint }]) => hint)
356
+ .map(([key, { param }]) =>
357
+ param ? key.length + param.length + 3 : key.length,
358
+ ),
359
+ );
360
+ flags.forEach((flag) => {
361
+ const str = `${flag[0]}${flag[1].param ? gray(` <${flag[1].param}>`) : ""}`;
362
+ if (flag[1].hint) {
363
+ console.info(
364
+ " ",
365
+ `--${str}${" ".repeat(maxLength - colorstrip(str).length)}`,
366
+ " ",
367
+ flag[1].hint,
368
+ );
369
+ }
370
+ });
371
+ }
372
+ }
373
+ }
374
+
375
+ export function showUsageHeadline(cmd, subcmd, module) {
376
+ console.info("USAGE:");
377
+ if (subcmd) {
378
+ let params = module.router[subcmd]?.params;
379
+ // const options = module.router[subcmd]?.options
380
+ if (params) {
381
+ const optionalize = (str) =>
382
+ str.endsWith(" ...]")
383
+ ? `[<${str.slice(1, -5)}> ...]`
384
+ : str[0] === "["
385
+ ? `[<${str.slice(1, -1)}>]`
386
+ : `<${str}>`;
387
+ if (Array.isArray(params)) {
388
+ params = `${params.map((param) => optionalize(param)).join(" ")} `;
389
+ } else {
390
+ params = optionalize(params);
391
+ }
392
+ }
393
+ console.info(
394
+ ` ${colors.white(`npx witsdk ${cmd}`)} ${colors.white(subcmd)} ${params ? `${colors.green(params)} ` : ""}[OPTIONS] [FLAGS]`,
395
+ );
396
+ if (module?.router[subcmd]?.hint) {
397
+ console.info("\nDESCRIPTION:");
398
+ console.info(` ${module.router[subcmd].hint}`);
399
+ }
400
+ } else {
401
+ console.info(
402
+ ` ${colors.white(`npx witsdk ${cmd}`)} <SUBCOMMAND> ... [OPTIONS] [FLAGS]`,
403
+ );
404
+ }
405
+ }
406
+
407
+ export function showUsageOptions(options) {
408
+ options = Object.entries(options)
409
+ .filter(([, option]) => option?.param)
410
+ .sort(([a], [b]) => {
411
+ if (a < b) return -1;
412
+ else if (a > b) return 1;
413
+ else return 0;
414
+ });
415
+ if (options.length > 0) {
416
+ console.info("\nOPTIONS:");
417
+ const maxLength = options
418
+ .map((option) =>
419
+ option[1].param
420
+ ? option[1].param.length + option[0].length + 3
421
+ : option[0].length,
422
+ )
423
+ .reduce((prev, curr) => (curr > prev ? curr : prev));
424
+ options.forEach((option) => {
425
+ if (option[1].hint) {
426
+ const str = `${option[0]}${option[1].param ? gray(` <${option[1].param}>`) : ""}`;
427
+ console.info(
428
+ " ",
429
+ `--${str}${" ".repeat(maxLength - colorstrip(str).length)}`,
430
+ " ",
431
+ option[1].hint,
432
+ );
433
+ }
434
+ });
435
+ }
436
+ }
437
+
438
+ export function showUsageSubcommand(cmd, subcmd, module) {
439
+ showUsageHeadline(cmd, subcmd, module);
440
+ showUsageOptions({ ...module?.flags, ...module.router[subcmd]?.options });
441
+ showUsageFlags({ ...module?.flags, ...module.router[subcmd]?.options });
442
+ showUsageEnvars(module.router[subcmd]?.envars || module?.envars);
443
+ }
444
+
445
+ export function showVersion() {
446
+ console.info(
447
+ `${colors.mcyan(`Witnet SDK v${require("../../package.json").version}`)}`,
448
+ );
449
+ }
450
+
451
+ export function getWildcardsCountFromString(str) {
452
+ let maxArgsIndex = 0;
453
+ if (str && typeof str === "string") {
454
+ let match;
455
+ const regexp = /\\\d\\/g;
456
+ while ((match = regexp.exec(str)) !== null) {
457
+ const argsIndex = parseInt(match[0][1], 10) + 1;
458
+ if (argsIndex > maxArgsIndex) maxArgsIndex = argsIndex;
459
+ }
460
+ }
461
+ return maxArgsIndex;
462
+ }
463
+
464
+ export function checkRpcWildcards(wildcards) {
465
+ if (typeof wildcards === "object") {
466
+ Object.values(wildcards).forEach((wildcard) => {
467
+ if (Array.isArray(wildcard))
468
+ wildcard.forEach((item) => checkRpcWildcards(item));
469
+ else checkRpcWildcards(wildcard);
470
+ });
471
+ } else if (Array.isArray(wildcards)) {
472
+ wildcards.forEach((wildcard) => checkRpcWildcards(wildcard));
473
+ } else if (typeof wildcards === "string") {
474
+ if (isWildcard(wildcards)) {
475
+ const char = wildcards.charAt(1);
476
+ if (char < "0" || char > "9") {
477
+ throw Error("RPC: wildcards not in range [0 .. 9]");
478
+ }
479
+ }
480
+ }
481
+ }
482
+
483
+ export function isWildcard(str) {
484
+ return str.length === 3 && /\\\d\\/g.test(str);
485
+ }
486
+
487
+ export function replaceWildcards(obj, args) {
488
+ if (args.length > 10) args = args.slice(0, 10);
489
+ if (obj && typeof obj === "string") {
490
+ for (let argIndex = 0; argIndex < args.length; argIndex++) {
491
+ const wildcard = `\\${argIndex}\\`;
492
+ obj = obj.replaceAll(wildcard, args[argIndex]);
493
+ }
494
+ } else if (obj && Array.isArray(obj)) {
495
+ obj = obj.map((value) =>
496
+ typeof value === "string" || Array.isArray(value)
497
+ ? replaceWildcards(value, args)
498
+ : value,
499
+ );
500
+ } else if (obj && typeof obj === "object") {
501
+ obj = replaceObjectWildcards(obj, args);
502
+ }
503
+ return obj;
504
+ }
505
+
506
+ export function replaceObjectWildcards(obj, args) {
507
+ return Object.fromEntries(
508
+ Object.entries(obj).map(([key, value]) => {
509
+ for (let argIndex = 0; argIndex < args.length; argIndex++) {
510
+ const wildcard = `\\${argIndex}\\`;
511
+ key = key.replaceAll(wildcard, args[argIndex]);
512
+ value = replaceWildcards(value, args);
513
+ }
514
+ return [key, value];
515
+ }),
516
+ );
517
+ }
518
+
519
+ export function spliceWildcard(obj, argIndex, argValue, argsCount) {
520
+ if (obj && typeof obj === "string") {
521
+ const wildcard = `\\${argIndex}\\`;
522
+ obj = obj.replaceAll(wildcard, argValue);
523
+ for (let j = argIndex + 1; j < argsCount; j++) {
524
+ obj = obj.replaceAll(`\\${j}\\`, `\\${j - 1}\\`);
525
+ }
526
+ } else if (obj && Array.isArray(obj)) {
527
+ obj = obj.map((value) =>
528
+ typeof value === "string" || Array.isArray(value)
529
+ ? spliceWildcard(value, argIndex, argValue, argsCount)
530
+ : value,
531
+ );
532
+ }
533
+ return obj;
534
+ }
535
+
536
+ export async function toolkitRun(settings, args) {
537
+ const cmd = `${settings.paths.toolkitBinPath} ${args.join(" ")}`;
538
+ return new Promise((resolve, reject) => {
539
+ exec(cmd, { maxBuffer: 1024 * 1024 * 10 }, (error, stdout, stderr) => {
540
+ if (error) {
541
+ reject(error);
542
+ }
543
+ if (stderr) {
544
+ reject(stderr);
545
+ }
546
+ resolve(stdout);
547
+ });
548
+ });
549
+ }
550
+
551
+ export function toUpperCamelCase(str) {
552
+ return str
553
+ .replace(/\b(\w)/g, (_match, capture) => capture.toUpperCase())
554
+ .replace(/\s+/g, "");
555
+ }
556
+
557
+ export function toUtf16Bytes(str) {
558
+ const bytes = new Uint8Array(str.length * 2);
559
+ for (let i = 0; i < str.length; i++) {
560
+ const code = str.charCodeAt(i);
561
+ bytes[i * 2] = code >> 8;
562
+ bytes[i * 2 + 1] = code & 0xff;
563
+ }
564
+ return bytes;
565
+ }
566
+
567
+ export function toUtf8Array(str) {
568
+ const utf8 = [];
569
+ for (let i = 0; i < str.length; i++) {
570
+ let charcode = str.charCodeAt(i);
571
+ if (charcode < 0x80) utf8.push(charcode);
572
+ else if (charcode < 0x800) {
573
+ utf8.push(0xc0 | (charcode >> 6), 0x80 | (charcode & 0x3f));
574
+ } else if (charcode < 0xd800 || charcode >= 0xe000) {
575
+ utf8.push(
576
+ 0xe0 | (charcode >> 12),
577
+ 0x80 | ((charcode >> 6) & 0x3f),
578
+ 0x80 | (charcode & 0x3f),
579
+ );
580
+ } else {
581
+ // surrogate pair
582
+ i++;
583
+ // UTF-16 encodes 0x10000-0x10FFFF by
584
+ // subtracting 0x10000 and splitting the
585
+ // 20 bits of 0x0-0xFFFFF into two halves
586
+ charcode =
587
+ 0x10000 + (((charcode & 0x3ff) << 10) | (str.charCodeAt(i) & 0x3ff));
588
+ utf8.push(
589
+ 0xf0 | (charcode >> 18),
590
+ 0x80 | ((charcode >> 12) & 0x3f),
591
+ 0x80 | ((charcode >> 6) & 0x3f),
592
+ 0x80 | (charcode & 0x3f),
593
+ );
594
+ }
595
+ }
596
+ return utf8;
597
+ }
598
+
599
+ export function utf8ArrayToStr(array) {
600
+ const len = array.length;
601
+ let out = "";
602
+ let i = 0;
603
+ let c;
604
+ let char2, char3;
605
+ while (i < len) {
606
+ c = array[i++];
607
+ switch (c >> 4) {
608
+ case 0:
609
+ case 1:
610
+ case 2:
611
+ case 3:
612
+ case 4:
613
+ case 5:
614
+ case 6:
615
+ case 7:
616
+ // 0xxxxxxx
617
+ out += String.fromCharCode(c);
618
+ break;
619
+ case 12:
620
+ case 13:
621
+ // 110x xxxx 10xx xxxx
622
+ char2 = array[i++];
623
+ out += String.fromCharCode(((c & 0x1f) << 6) | (char2 & 0x3f));
624
+ break;
625
+ case 14:
626
+ // 1110 xxxx 10xx xxxx 10xx xxxx
627
+ char2 = array[i++];
628
+ char3 = array[i++];
629
+ out += String.fromCharCode(
630
+ ((c & 0x0f) << 12) | ((char2 & 0x3f) << 6) | ((char3 & 0x3f) << 0),
631
+ );
632
+ break;
633
+ }
634
+ }
635
+ return out;
636
+ }
637
+
638
+ export async function prompt(question) {
639
+ const readlineInterface = readline.createInterface({
640
+ input: process.stdin,
641
+ output: process.stdout,
642
+ });
643
+ return new Promise((resolve, _reject) => {
644
+ readlineInterface.question(`${question} `, (response) => {
645
+ readlineInterface.close();
646
+ resolve(response.trim());
647
+ });
648
+ });
649
+ }
650
+
651
+ export function prompter(promise) {
652
+ const loading = (() => {
653
+ const h = ["|", "/", "-", "\\"];
654
+ let i = 0;
655
+ return setInterval(() => {
656
+ i = i > 3 ? 0 : i;
657
+ process.stdout.write(`\b\b${h[i]} `);
658
+ i++;
659
+ }, 50);
660
+ })();
661
+ return promise.then((result) => {
662
+ clearInterval(loading);
663
+ process.stdout.write("\b\b");
664
+ return result;
665
+ });
666
+ }
667
+
668
+ export function traceChecklists(checklists) {
669
+ if (checklists && Object.keys(checklists).length > 0) {
670
+ const headlines = [
671
+ "NODES",
672
+ ...Object.keys(checklists).map((key) => `:${key}`),
673
+ ];
674
+ checklists = Object.values(checklists);
675
+ const urls = Object.keys(checklists[0]);
676
+ const records = urls.map((url) => {
677
+ const errors = checklists.filter(
678
+ (checklist) => checklist[url] instanceof Error,
679
+ ).length;
680
+ return [
681
+ errors === checklists.length
682
+ ? colors.red(url)
683
+ : errors > 0
684
+ ? colors.myellow(url)
685
+ : colors.mcyan(url),
686
+ ...checklists.map((checklist) =>
687
+ checklist[url] instanceof Error
688
+ ? colors.red(checklist[url])
689
+ : checklist[url] === true
690
+ ? colors.lcyan("Aye")
691
+ : colors.cyan("Nay"),
692
+ ),
693
+ ];
694
+ });
695
+ traceTable(records, {
696
+ headlines,
697
+ maxColumnWidth: 31,
698
+ });
699
+ }
700
+ }
701
+
702
+ export function traceHeader(headline, color = normal, indent = "") {
703
+ console.info(`${indent}┌─${"─".repeat(headline.length)}─┐`);
704
+ console.info(`${indent}│ ${color(headline)} │`);
705
+ console.info(`${indent}└─${"─".repeat(headline.length)}─┘`);
706
+ }
707
+
708
+ export function traceTable(records, options) {
709
+ const stringify = (data, humanizers, index) =>
710
+ humanizers?.[index]
711
+ ? humanizers[index](data).toString()
712
+ : (data?.toString() ?? "");
713
+ const max = (a, b) => (a > b ? a : b);
714
+ const reduceMax = (numbers) =>
715
+ numbers.reduce((curr, prev) => (prev > curr ? prev : curr), 0);
716
+ if (!options) options = {};
717
+ const indent = options?.indent || "";
718
+ const numColumns = reduceMax(records.map((record) => record?.length || 1));
719
+ const maxColumnWidth = options?.maxColumnWidth || 80;
720
+ const table = transpose(records, numColumns);
721
+ options.widths =
722
+ options?.widths ||
723
+ table.map((column, index) => {
724
+ let maxWidth = reduceMax(
725
+ column.map(
726
+ (field) =>
727
+ colorstrip(stringify(field, options?.humanizers, index)).length,
728
+ ),
729
+ );
730
+ if (options?.headlines?.[index]) {
731
+ maxWidth = max(
732
+ maxWidth,
733
+ colorstrip(options.headlines[index].replaceAll(":", "")).length,
734
+ );
735
+ }
736
+ return Math.min(maxWidth, maxColumnWidth);
737
+ });
738
+ let headline = options.widths.map((maxWidth) => "─".repeat(maxWidth));
739
+ console.info(`${indent}┌─${headline.join("─┬─")}─┐`);
740
+ if (options?.headlines) {
741
+ headline = options.widths.map((maxWidth, index) => {
742
+ const caption = options.headlines[index].replaceAll(":", "");
743
+ const captionLength = colorstrip(caption).length;
744
+ return `${white(caption)}${" ".repeat(maxWidth - captionLength)}`;
745
+ });
746
+ console.info(`${indent}│ ${headline.join(" │ ")} │`);
747
+ headline = options.widths.map((maxWidth) => "─".repeat(maxWidth));
748
+ console.info(`${indent}├─${headline.join("─┼─")}─┤`);
749
+ }
750
+ for (let i = 0; i < records.length; i++) {
751
+ let line = "";
752
+ for (let j = 0; j < numColumns; j++) {
753
+ let data = table[j][i];
754
+ let color;
755
+ if (options?.colors?.[j]) {
756
+ color = options.colors[j];
757
+ } else {
758
+ color =
759
+ typeof data === "string"
760
+ ? green
761
+ : Number(data) === data && data % 1 !== 0 // is float number?
762
+ ? yellow
763
+ : (x) => x;
764
+ }
765
+ data = stringify(data, options?.humanizers, j);
766
+ if (colorstrip(data).length > maxColumnWidth) {
767
+ while (colorstrip(data).length > maxColumnWidth - 3) {
768
+ data = data.slice(0, -1);
769
+ }
770
+ data += "...";
771
+ }
772
+ const dataLength = colorstrip(data).length;
773
+ if (options?.headlines && options.headlines[j][0] === ":") {
774
+ data = `${color(data)}${" ".repeat(options.widths[j] - dataLength)}`;
775
+ } else {
776
+ data = `${" ".repeat(options.widths[j] - dataLength)}${color(data)}`;
777
+ }
778
+ line += `│ ${data} `;
779
+ }
780
+ console.info(`${indent}${line}│`);
781
+ }
782
+ headline = options.widths.map((maxWidth) => "─".repeat(maxWidth));
783
+ console.info(`${indent}└─${headline.join("─┴─")}─┘`);
784
+ }
785
+
786
+ function transpose(records, numColumns) {
787
+ const columns = [];
788
+ for (let index = 0; index < numColumns; index++) {
789
+ columns.push(records.map((row) => row[index]));
790
+ }
791
+ return columns;
792
+ }
793
+
794
+ export function txJsonReplacer(key, value) {
795
+ switch (key) {
796
+ case "bytes":
797
+ case "der":
798
+ return toHexString(value, true);
799
+ case "tx":
800
+ return JSON.stringify(value, txJsonReplacer);
801
+ case "change":
802
+ case "fees":
803
+ case "value":
804
+ return parseInt(value, 10) / 10 ** 9;
805
+ default:
806
+ return value;
807
+ }
808
+ }
809
+
810
+ export function txReceiptJsonReplacer(key, value) {
811
+ switch (key) {
812
+ case "bytes":
813
+ case "der":
814
+ return toHexString(value, true);
815
+ case "tx":
816
+ return JSON.stringify(value, txJsonReplacer);
817
+ case "change":
818
+ case "fees":
819
+ case "value":
820
+ return parseInt(value?.pedros, 10) / 10 ** 9;
821
+ case "timestamp":
822
+ return moment.unix(value).format("MMMM Do YYYY, h:mm:ss a");
823
+ default:
824
+ return value;
825
+ }
826
+ }
827
+
828
+ export function traceTransactionOnCheckpoint(receipt) {
829
+ if (receipt?.confirmations) {
830
+ console.info(` > Checkpoint #${commas(receipt.confirmations)}...`);
831
+ }
832
+ }
833
+
834
+ export function traceTransactionOnStatusChange(receipt) {
835
+ const captions = {
836
+ pending: "Awaiting relay...",
837
+ // confirmed: "Transaction confirmed:",
838
+ // finalized: "Transaction finalized:",
839
+ relayed: "Awaiting inclusion...",
840
+ mined: "Awaiting confirmations...",
841
+ };
842
+ const caption = captions[receipt.status];
843
+ if (caption) console.info(` > ${captions[receipt.status]}`);
844
+ if (["finalized", "confirmed"].includes(receipt.status)) {
845
+ console.info(` > Block hash: ${colors.gray(receipt?.blockHash)}`);
846
+ console.info(` > Block miner: ${colors.cyan(receipt?.blockMiner)}`);
847
+ console.info(
848
+ ` > Block epoch: ${colors.white(commas(receipt?.blockEpoch))}`,
849
+ );
850
+ console.info(
851
+ ` > Included at: ${colors.green(moment.unix(receipt?.blockTimestamp).format("MMMM Do YYYY, h:mm:ss a"))}`,
852
+ );
853
+ console.info(
854
+ ` > ${receipt.status[0].toUpperCase() + receipt.status.slice(1)} at: ${colors.mgreen(moment.unix(receipt.timestamp).format("MMMM Do YYYY, h:mm:ss a"))}`,
855
+ );
856
+ }
857
+ }
858
+
859
+ export function traceTransactionReceipt(receipt) {
860
+ const captions = {
861
+ DataRequest: " > DRT hash: ",
862
+ ValueTransfer: " > VTT hash: ",
863
+ };
864
+ console.info(
865
+ `${captions[receipt.type] || " > TX hash: "}${colors.white(receipt.hash)}`,
866
+ );
867
+ if (receipt?.droHash)
868
+ console.info(` > DRO hash: ${colors.green(receipt.droHash)}`);
869
+ if (receipt?.radHash)
870
+ console.info(` > RAD hash: ${colors.mgreen(receipt.radHash)}`);
871
+ if (receipt?.droSLA)
872
+ console.info(` > SLA params: ${JSON.stringify(receipt.droSLA)}`);
873
+ if (receipt?.withdrawer) {
874
+ if (receipt?.validator) {
875
+ console.info(` > Validator: ${colors.mcyan(receipt.validator)}`);
876
+ }
877
+ console.info(` > Withdrawer: ${colors.mmagenta(receipt.withdrawer)}`);
878
+ } else {
879
+ const signers = Array.isArray(receipt.from) ? receipt.from : [receipt.from];
880
+ console.info(` > Signer/s: ${colors.mmagenta(signers[0])}`);
881
+ signers.slice(1).forEach((signer) => {
882
+ console.info(` ${colors.mmagenta(signer)}`);
883
+ });
884
+ }
885
+ if (receipt?.recipients) {
886
+ console.info(
887
+ ` > Recipient/s: ${colors.mblue(
888
+ receipt.recipients.filter(
889
+ (pkh, index, array) => index === array.indexOf(pkh),
890
+ ),
891
+ )}`,
892
+ );
893
+ }
894
+ if (receipt?.fees)
895
+ console.info(` > Network fee: ${colors.yellow(receipt.fees.toString(2))}`);
896
+ if (receipt?.value)
897
+ console.info(
898
+ ` > Value: ${colors.myellow(receipt.value.toString(2))}`,
899
+ );
900
+ if (receipt?.weight)
901
+ console.info(` > Weight: ${colors.mgreen(commas(receipt.weight))}`);
902
+ if (receipt?.witnesses) {
903
+ console.info(` > Witnesses: ${receipt.witnesses}`);
904
+ }
905
+ }
906
+
907
+ export async function traceTransaction(transmitter, options) {
908
+ const color = options?.color || ((x) => `\x1b[30;45m${x}\x1b[0m`);
909
+ let receipt = await transmitter.signTransaction(options, options?.reload);
910
+ if (options?.verbose) {
911
+ console.info(`\n${gray(JSON.stringify(receipt.tx, txJsonReplacer))}`);
912
+ }
913
+ if (options?.headline) {
914
+ console.info(`\n ${color(` ${options.headline} `)}\n`);
915
+ }
916
+ traceTransactionReceipt(receipt);
917
+ if (!options?.force) {
918
+ // prompt user confirmation
919
+ console.info();
920
+ const answer = await require("inquirer").createPromptModule()([
921
+ {
922
+ message: "Send transaction?",
923
+ type: "confirm",
924
+ name: "continue",
925
+ default: false,
926
+ },
927
+ ]);
928
+ if (!answer.continue) {
929
+ return receipt;
930
+ }
931
+ }
932
+ try {
933
+ console.info();
934
+ receipt = await transmitter.sendTransaction();
935
+ if (options?.await || options?.confirmations !== undefined) {
936
+ receipt = await transmitter.confirmTransaction(receipt.hash, {
937
+ confirmations: options?.confirmations || 0,
938
+ onCheckpoint: traceTransactionOnCheckpoint,
939
+ onStatusChange: traceTransactionOnStatusChange,
940
+ });
941
+ } else {
942
+ const data = {
943
+ status: receipt?.status,
944
+ timestamp: receipt?.timestamp || Math.floor(Date.now() / 1000),
945
+ };
946
+ console.info(data);
947
+ }
948
+ } catch (err) {
949
+ if (err?.inFlight && err.inFlight) {
950
+ console.info(
951
+ `\n${colors.gray(JSON.stringify(err.inFligt?.message, txReceiptJsonReplacer))}`,
952
+ );
953
+ }
954
+ throw err;
955
+ }
956
+ return receipt;
957
+ }
958
+
959
+ export function unescapeSlashes(str) {
960
+ // add another escaped slash if the string ends with an odd
961
+ // number of escaped slashes which will crash JSON.parse
962
+ let parsedStr = str.replace(/(^|[^\\])(\\\\)*\\$/, "$&\\");
963
+
964
+ // escape unescaped double quotes to prevent error with
965
+ // added double quotes in json string
966
+ parsedStr = parsedStr.replace(/(^|[^\\])((\\\\)*")/g, "$1\\$2");
967
+
968
+ try {
969
+ parsedStr = JSON.parse(`"${parsedStr}"`);
970
+ } catch (_e) {
971
+ return str;
972
+ }
973
+ return parsedStr;
974
+ }