@witnet/sdk 1.2.2 → 1.2.4
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/.env_witnet +2 -1
- package/dist/package.json +4 -4
- package/dist/src/bin/helpers.js +1 -1
- package/dist/src/index.js +1 -1
- package/dist/src/lib/crypto/account.js +1 -1
- package/dist/src/lib/crypto/coinbase.js +1 -1
- package/dist/src/lib/crypto/index.js +1 -1
- package/dist/src/lib/crypto/interfaces.js +1 -1
- package/dist/src/lib/crypto/payloads/DataRequestPayload.js +1 -1
- package/dist/src/lib/crypto/payloads/StakePayload.js +1 -1
- package/dist/src/lib/crypto/payloads/UnstakePayload.js +1 -1
- package/dist/src/lib/crypto/payloads/ValueTransferPayload.js +1 -1
- package/dist/src/lib/crypto/payloads.js +1 -1
- package/dist/src/lib/crypto/signer.js +1 -1
- package/dist/src/lib/crypto/transmitters/DataRequests.js +1 -1
- package/dist/src/lib/crypto/transmitters/StakeDeposits.js +1 -1
- package/dist/src/lib/crypto/transmitters/StakeWithdrawals.js +1 -1
- package/dist/src/lib/crypto/transmitters/ValueTransfers.js +1 -1
- package/dist/src/lib/crypto/transmitters.js +1 -1
- package/dist/src/lib/crypto/types.js +1 -1
- package/dist/src/lib/crypto/utils.js +1 -1
- package/dist/src/lib/crypto/wallet.js +1 -1
- package/dist/src/lib/index.js +1 -1
- package/dist/src/lib/radon/ccdr/eth.js +1 -1
- package/dist/src/lib/radon/ccdr/index.js +1 -1
- package/dist/src/lib/radon/ccdr/wit.js +1 -1
- package/dist/src/lib/radon/filters.js +1 -1
- package/dist/src/lib/radon/index.js +1 -1
- package/dist/src/lib/radon/reducers.js +1 -1
- package/dist/src/lib/radon/types.js +1 -1
- package/dist/src/lib/radon/utils.d.ts.map +1 -1
- package/dist/src/lib/radon/utils.js +1 -1
- package/dist/src/lib/rest/kermit.d.ts.map +1 -1
- package/dist/src/lib/rest/kermit.js +2 -4
- package/dist/src/lib/rest/types.js +1 -1
- package/dist/src/lib/rpc/index.js +1 -1
- package/dist/src/lib/rpc/nodes.js +1 -1
- package/dist/src/lib/rpc/provider.js +1 -1
- package/dist/src/lib/rpc/types.js +1 -1
- package/dist/src/lib/types.js +1 -1
- package/dist/src/lib/utils.js +1 -1
- package/package.json +4 -4
- package/scripts/clean.cjs +21 -21
- package/scripts/postinstall.cjs +9 -9
- package/src/bin/bots/watcher.cjs +365 -354
- package/src/bin/cli/history.cjs +31 -31
- package/src/bin/cli/inspect.js +581 -581
- package/src/bin/cli/network.js +695 -695
- package/src/bin/cli/nodes.js +424 -424
- package/src/bin/cli/radon.js +1124 -1122
- package/src/bin/cli/wallet.js +1362 -1362
- package/src/bin/helpers.js +974 -974
- package/src/bin/index.js +328 -328
- package/witnet/assets/_index.cjs +0 -5
- package/witnet/assets/_requests.cjs +0 -25
- package/witnet/assets/_sources.cjs +0 -36
- package/witnet/assets/_templates.cjs +0 -36
- package/witnet/assets/index.cjs +0 -4
- package/witnet/assets/modals/index.cjs +0 -7
- package/witnet/assets/modals/web3/btc.cjs +0 -0
- package/witnet/assets/modals/web3/eth.cjs +0 -27
- package/witnet/assets/modals/web3/ipfs.cjs +0 -22
- package/witnet/assets/modals/web3/sol.cjs +0 -0
- package/witnet/assets/modals/web3/wit.cjs +0 -28
- package/witnet/assets/requests.cjs +0 -49
- package/witnet/witnet copy.proto +0 -457
- package/witnet/witnet.proto +0 -456
- package/witnet/witnet.proto.json +0 -1322
- package/witnet/witnet_toolkit-1.6.7-x86_64-pc-windows-msvc.exe +0 -0
- package/witnet/witnet_toolkit-1.7.1-x86_64-pc-windows-msvc.exe +0 -0
- package/witnet/witnet_toolkit-2.0.0-rc.7-x86_64-pc-windows-msvc.exe +0 -0
- package/witnet/witnet_toolkit-2.0.2-x86_64-pc-windows-msvc.exe +0 -0
- package/witnet/witnet_toolkit-2.0.21-x86_64-pc-windows-msvc.exe +0 -0
- package/witnet/witnet_toolkit-2.0.7-x86_64-pc-windows-msvc.exe +0 -0
- package/witnet/witnet_toolkit-2.0.8-x86_64-pc-windows-msvc.exe +0 -0
package/src/bin/bots/watcher.cjs
CHANGED
|
@@ -1,354 +1,365 @@
|
|
|
1
|
-
const cron = require("node-cron");
|
|
2
|
-
require("dotenv").config({
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
"--
|
|
37
|
-
"
|
|
38
|
-
process.env.
|
|
39
|
-
)
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
"--
|
|
47
|
-
"
|
|
48
|
-
process.env.
|
|
49
|
-
)
|
|
50
|
-
|
|
51
|
-
"--
|
|
52
|
-
"
|
|
53
|
-
process.env.
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
)
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
);
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
)
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
)
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
}
|
|
1
|
+
const cron = require("node-cron");
|
|
2
|
+
require("dotenv").config({
|
|
3
|
+
quiet: true,
|
|
4
|
+
path: _spliceFromArgs(process.argv, `--config-path`),
|
|
5
|
+
});
|
|
6
|
+
const { Command } = require("commander");
|
|
7
|
+
const moment = require("moment");
|
|
8
|
+
const program = new Command();
|
|
9
|
+
|
|
10
|
+
const { utils, Witnet } = require("../../../dist/src/index.js");
|
|
11
|
+
const { colors, traceHeader } = require("../helpers.js");
|
|
12
|
+
const { version } = require("../../../package.json");
|
|
13
|
+
|
|
14
|
+
const CHECK_BALANCE_SCHEDULE =
|
|
15
|
+
process.env.WITNET_SDK_WATCHER_BALANCE_SCHEDULE || "*/15 * * * *"; // every 15 minutes
|
|
16
|
+
const DRY_RUN_SCHEDULE =
|
|
17
|
+
process.env.WITNET_SDK_WATCHER_DRY_RUN_SCHEDULE || "* * * * *"; // every minute
|
|
18
|
+
const WIT_WALLET_MASTER_KEY = process.env.WITNET_SDK_WALLET_MASTER_KEY;
|
|
19
|
+
|
|
20
|
+
const lastUpdate = {};
|
|
21
|
+
|
|
22
|
+
traceHeader(`@WITNET/SDK WATCHER BOT v${version}`, colors.white);
|
|
23
|
+
|
|
24
|
+
main();
|
|
25
|
+
|
|
26
|
+
async function main() {
|
|
27
|
+
program
|
|
28
|
+
.name("npx --package @witnet/sdk watcher")
|
|
29
|
+
.description(
|
|
30
|
+
"Watcher bot for detecting and notarizing real-world data updates in Witnet.",
|
|
31
|
+
)
|
|
32
|
+
.version(version);
|
|
33
|
+
|
|
34
|
+
program
|
|
35
|
+
.option(
|
|
36
|
+
"--cooldown <secs>",
|
|
37
|
+
"Min. amount of seconds that must elapse before notarizing the next data update in Witnet.",
|
|
38
|
+
process.env.WITNET_SDK_WATCHER_WIT_COOLDOWN_SECS || 900,
|
|
39
|
+
)
|
|
40
|
+
.option(
|
|
41
|
+
"--deviation <percentage>",
|
|
42
|
+
"Deviation percentage threshold that will force notarizing a data update in Witnet (numeric data feeds only).",
|
|
43
|
+
process.env.WITNET_SDK_WATCHER_WIT_DEVIATION_PERCENTAGE,
|
|
44
|
+
)
|
|
45
|
+
.option(
|
|
46
|
+
"--heartbeat <secs>",
|
|
47
|
+
"If set, max. amount of seconds between data feed updates in Witnet.",
|
|
48
|
+
process.env.WITNET_SDK_WATCHER_WIT_HEARTBEAT_SECS,
|
|
49
|
+
)
|
|
50
|
+
.option(
|
|
51
|
+
"--min-balance <wits>",
|
|
52
|
+
"Min. balance threshold",
|
|
53
|
+
process.env.WITNET_SDK_WATCHER_WIT_MIN_BALANCE || 1000.0,
|
|
54
|
+
)
|
|
55
|
+
.option(
|
|
56
|
+
"--priority <priority>",
|
|
57
|
+
"Network priority when notarizing data updates in Witnet.",
|
|
58
|
+
process.env.WITNET_SDK_WATCHER_WIT_NETWORK_PRIORITY ||
|
|
59
|
+
Witnet.TransactionPriority.Medium,
|
|
60
|
+
)
|
|
61
|
+
.option(
|
|
62
|
+
"--notarize-errors",
|
|
63
|
+
"If set, eventual data retrieving errors will also get notarized.",
|
|
64
|
+
)
|
|
65
|
+
.option(
|
|
66
|
+
"--signer <wit_pkh>",
|
|
67
|
+
"Witnet public key hash in charge of notarizing data updates.",
|
|
68
|
+
process.env.WITNET_SDK_WATCHER_WIT_SIGNER,
|
|
69
|
+
)
|
|
70
|
+
.option(
|
|
71
|
+
"--target <hex>",
|
|
72
|
+
"Either an existing Radon hash in Witnet, or the Radon Request bytecode to use for detecting data updates.",
|
|
73
|
+
process.env.WITNET_SDK_WATCHER_WIT_RADON_REQUEST,
|
|
74
|
+
)
|
|
75
|
+
.option(
|
|
76
|
+
"--witnesses <number>",
|
|
77
|
+
"Size of the witnessing committee when notarizing data updates in Witnet.",
|
|
78
|
+
process.env.WITNET_SDK_WATCHER_WIT_WITNESSES || undefined,
|
|
79
|
+
)
|
|
80
|
+
.option(
|
|
81
|
+
'--witnet <"mainnet" | "testnet" | url>',
|
|
82
|
+
"The name of the Witnet network, or the URL of the WIT/RPC provider to connect to.",
|
|
83
|
+
process.env.WITNET_SDK_WATCHER_WIT_NETWORK ||
|
|
84
|
+
process.env.WITNET_SDK_PROVIDER_URL ||
|
|
85
|
+
"mainnet",
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
program.parse();
|
|
89
|
+
|
|
90
|
+
let { deviation, minBalance } = program.opts();
|
|
91
|
+
const {
|
|
92
|
+
debug,
|
|
93
|
+
target,
|
|
94
|
+
cooldown,
|
|
95
|
+
heartbeat,
|
|
96
|
+
notarizeErrors,
|
|
97
|
+
priority,
|
|
98
|
+
signer,
|
|
99
|
+
witnesses,
|
|
100
|
+
witnet,
|
|
101
|
+
} = program.opts();
|
|
102
|
+
|
|
103
|
+
if (!debug) console.debug = () => {};
|
|
104
|
+
|
|
105
|
+
if (!WIT_WALLET_MASTER_KEY) {
|
|
106
|
+
console.error(
|
|
107
|
+
`❌ Fatal: a Witnet wallet's master key is not settled on this environment.`,
|
|
108
|
+
);
|
|
109
|
+
process.exit(0);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const provider =
|
|
113
|
+
witnet === "mainnet"
|
|
114
|
+
? "https://rpc-01.witnet.io"
|
|
115
|
+
: witnet === "testnet"
|
|
116
|
+
? "https://rpc-testnet.witnet.io"
|
|
117
|
+
: witnet;
|
|
118
|
+
const wallet = await Witnet.Wallet.fromXprv(WIT_WALLET_MASTER_KEY, {
|
|
119
|
+
limit: 1,
|
|
120
|
+
provider: await Witnet.JsonRpcProvider.fromURL(provider),
|
|
121
|
+
});
|
|
122
|
+
const ledger = wallet.getSigner(signer || wallet.coinbase.pkh);
|
|
123
|
+
if (!ledger) {
|
|
124
|
+
console.error(
|
|
125
|
+
`❌ Fatal: hot wallet address ${signer} not found in wallet!`,
|
|
126
|
+
);
|
|
127
|
+
process.exit(0);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
console.info(`Wit/RPC provider: ${provider}`);
|
|
131
|
+
console.info(
|
|
132
|
+
`Witnet network: WITNET:${wallet.provider.network.toUpperCase()} (${wallet.provider.networkId.toString(16)})`,
|
|
133
|
+
);
|
|
134
|
+
console.info(`Witnet hot wallet: ${ledger.pkh}`);
|
|
135
|
+
console.info(`Network priority: ${priority.toUpperCase()}`);
|
|
136
|
+
console.info(
|
|
137
|
+
`Balance threshold: ${Witnet.Coins.fromWits(minBalance).toString(2)}`,
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
if (!target || !utils.isHexString(target)) {
|
|
141
|
+
console.error(`❌ Fatal: a valid hex string must be provided as --target.`);
|
|
142
|
+
process.exit(0);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
let request;
|
|
146
|
+
try {
|
|
147
|
+
request = Witnet.Radon.RadonRequest.fromBytecode(target);
|
|
148
|
+
} catch {
|
|
149
|
+
const txs = await wallet.provider.searchDataRequests(target, {
|
|
150
|
+
limit: 1,
|
|
151
|
+
mode: "ethereal",
|
|
152
|
+
});
|
|
153
|
+
if (txs.length > 0 && txs[0]?.query) {
|
|
154
|
+
const bytecode = txs[0].query.rad_bytecode;
|
|
155
|
+
request = Witnet.Radon.RadonRequest.fromBytecode(bytecode);
|
|
156
|
+
} else {
|
|
157
|
+
console.error(
|
|
158
|
+
`❌ Fatal: provided --target is not a valid Radon Request bytecode nor a known Radon Request hash.`,
|
|
159
|
+
);
|
|
160
|
+
process.exit(0);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const dataType = request.dataType;
|
|
165
|
+
const authorities = request.sources.map((source) =>
|
|
166
|
+
source.authority.split(".").slice(-2)[0].toUpperCase(),
|
|
167
|
+
);
|
|
168
|
+
console.info(`Radon bytecode: ${request.toBytecode()}`);
|
|
169
|
+
console.info(`Radon RAD hash: ${request.radHash}`);
|
|
170
|
+
console.info(`Radon data type: ${dataType}`);
|
|
171
|
+
console.info(`Data authorities: ${authorities}`);
|
|
172
|
+
if (heartbeat) console.info(`Update heartbeat: ${_commas(heartbeat)} "`);
|
|
173
|
+
if (cooldown) console.info(`Update cool-down: ${_commas(cooldown)} "`);
|
|
174
|
+
|
|
175
|
+
// validate deviation parameter, only on integer or float data feeds
|
|
176
|
+
if (["RadonInteger", "RadonFloat"].includes(request.dataType)) {
|
|
177
|
+
deviation = parseFloat(deviation || 0.0);
|
|
178
|
+
console.info(`Update deviation: ${deviation.toFixed(2)} %`);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// create DR transaction factory
|
|
182
|
+
const DRs = Witnet.DataRequests.from(ledger, request);
|
|
183
|
+
|
|
184
|
+
// schedule signer's balance check
|
|
185
|
+
let balance = Witnet.Coins.fromPedros((await ledger.getBalance()).unlocked);
|
|
186
|
+
minBalance = Witnet.Coins.fromWits(minBalance);
|
|
187
|
+
console.info(`Initial balance: ${balance.toString(2)}`);
|
|
188
|
+
if (balance.pedros < minBalance.pedros) {
|
|
189
|
+
console.error(
|
|
190
|
+
`❌ Fatal: hot wallet must be funded with at least ${minBalance.toString(2)}.`,
|
|
191
|
+
);
|
|
192
|
+
process.exit(0);
|
|
193
|
+
} else {
|
|
194
|
+
if (!cron.validate(CHECK_BALANCE_SCHEDULE)) {
|
|
195
|
+
console.error(
|
|
196
|
+
`❌ Fatal: invalid check balance schedule: ${CHECK_BALANCE_SCHEDULE}`,
|
|
197
|
+
);
|
|
198
|
+
process.exit(0);
|
|
199
|
+
}
|
|
200
|
+
console.info(`Checking balance schedule: ${CHECK_BALANCE_SCHEDULE}`);
|
|
201
|
+
cron.schedule(CHECK_BALANCE_SCHEDULE, async () => checkWitnetBalance());
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// schedule data feeding dry runs
|
|
205
|
+
if (!cron.validate(DRY_RUN_SCHEDULE)) {
|
|
206
|
+
console.error(`❌ Fatal: invalid dry-run schedule: ${DRY_RUN_SCHEDULE}`);
|
|
207
|
+
process.exit(0);
|
|
208
|
+
}
|
|
209
|
+
console.info(`Dry running schedule: ${DRY_RUN_SCHEDULE}`);
|
|
210
|
+
cron.schedule(DRY_RUN_SCHEDULE, async () => dryRunRadonRequest(), {
|
|
211
|
+
noOverlap: true,
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
// ----------------------------------------------------------------------------------------------------------------
|
|
215
|
+
async function dryRunRadonRequest() {
|
|
216
|
+
const tag = `[@witnet/sdk/watcher][witnet:${wallet.provider.network}]`;
|
|
217
|
+
try {
|
|
218
|
+
let notarize = false;
|
|
219
|
+
const dryrun = JSON.parse(await request.execDryRun());
|
|
220
|
+
let result;
|
|
221
|
+
if (Object.keys(dryrun).includes("RadonError")) {
|
|
222
|
+
if (notarizeErrors) {
|
|
223
|
+
notarize = true;
|
|
224
|
+
result = dryrun.RadonError;
|
|
225
|
+
} else {
|
|
226
|
+
throw `Unexpected dry run error: ${JSON.stringify(result)}`;
|
|
227
|
+
}
|
|
228
|
+
} else if (
|
|
229
|
+
["RadonInteger", "RadonFloat"].includes(dataType) &&
|
|
230
|
+
Object.keys(dryrun).includes(`${dataType}`)
|
|
231
|
+
) {
|
|
232
|
+
result = parseFloat(dryrun[`${dataType}`]);
|
|
233
|
+
if (deviation && lastUpdate?.value) {
|
|
234
|
+
notarize =
|
|
235
|
+
Math.abs(result - lastUpdate.value) / lastUpdate.value >= deviation;
|
|
236
|
+
} else {
|
|
237
|
+
notarize = true;
|
|
238
|
+
}
|
|
239
|
+
} else if (!lastUpdate?.value || lastUpdate.value !== result) {
|
|
240
|
+
notarize = true;
|
|
241
|
+
}
|
|
242
|
+
console.info(`${tag} Dry run result => ${JSON.stringify(dryrun)}`);
|
|
243
|
+
const clock = Math.floor(Date.now() / 1000);
|
|
244
|
+
const elapsed = clock - (lastUpdate?.timestamp || clock - cooldown - 1);
|
|
245
|
+
if (!notarize && heartbeat && elapsed >= heartbeat) {
|
|
246
|
+
console.info(
|
|
247
|
+
`${tag} Notarizing data due to heartbeat after ${elapsed} secs ...`,
|
|
248
|
+
);
|
|
249
|
+
notarize = true;
|
|
250
|
+
} else if (notarize) {
|
|
251
|
+
if (!cooldown || elapsed >= cooldown) {
|
|
252
|
+
console.info(
|
|
253
|
+
`${tag} Notarizing possible data update as provided by ${authorities} ...`,
|
|
254
|
+
);
|
|
255
|
+
} else {
|
|
256
|
+
throw `Postponing possible data update as only ${elapsed} out of ${cooldown} secs elapsed since the last notarized update.`;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
if (notarize) {
|
|
260
|
+
lastUpdate.timestamp = clock;
|
|
261
|
+
lastUpdate.value = result;
|
|
262
|
+
return notarizeRadonRequest(tag);
|
|
263
|
+
}
|
|
264
|
+
} catch (err) {
|
|
265
|
+
console.warn(`${tag} ${err}`);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// ----------------------------------------------------------------------------------------------------------------
|
|
270
|
+
async function notarizeRadonRequest(tag) {
|
|
271
|
+
try {
|
|
272
|
+
// create, sign and send new data request transaction
|
|
273
|
+
let tx = await DRs.sendTransaction({ witnesses, fees: priority });
|
|
274
|
+
console.info(`${tag} RAD hash =>`, tx.radHash);
|
|
275
|
+
console.info(`${tag} DRT hash =>`, tx.hash);
|
|
276
|
+
console.info(`${tag} DRT weight =>`, _commas(tx.weight));
|
|
277
|
+
console.info(`${tag} DRT wtnsss =>`, tx.witnesses);
|
|
278
|
+
console.debug(
|
|
279
|
+
`${tag} DRT inputs =>`,
|
|
280
|
+
tx.tx?.DataRequest?.signatures.length,
|
|
281
|
+
);
|
|
282
|
+
console.info(
|
|
283
|
+
`${tag} DRT cost =>`,
|
|
284
|
+
Witnet.Coins.fromNanowits(
|
|
285
|
+
tx.fees.nanowits + tx.value?.nanowits,
|
|
286
|
+
).toString(2),
|
|
287
|
+
);
|
|
288
|
+
|
|
289
|
+
// await inclusion in Witnet
|
|
290
|
+
tx = await DRs.confirmTransaction(tx.hash, {
|
|
291
|
+
onStatusChange: () => console.info(`${tag} DRT status =>`, tx.status),
|
|
292
|
+
}).catch((err) => {
|
|
293
|
+
throw err;
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
console.debug(
|
|
297
|
+
`${tag} Cache info after confirmation =>`,
|
|
298
|
+
ledger.cacheInfo,
|
|
299
|
+
);
|
|
300
|
+
|
|
301
|
+
// await resolution in Witnet
|
|
302
|
+
let status = tx.status;
|
|
303
|
+
do {
|
|
304
|
+
const report = await ledger.provider.getDataRequest(
|
|
305
|
+
tx.hash,
|
|
306
|
+
"ethereal",
|
|
307
|
+
);
|
|
308
|
+
if (report.status !== status) {
|
|
309
|
+
status = report.status;
|
|
310
|
+
console.info(`${tag} DRT status =>`, report.status);
|
|
311
|
+
}
|
|
312
|
+
if (report.status === "solved" && report?.result) {
|
|
313
|
+
lastUpdate.cborBytes = report.result.cbor_bytes;
|
|
314
|
+
const result = utils.cbor.decode(
|
|
315
|
+
utils.fromHexString(report.result.cbor_bytes),
|
|
316
|
+
);
|
|
317
|
+
console.info(`${tag} DRT result =>`, result);
|
|
318
|
+
console.info(
|
|
319
|
+
`${tag} DRT tmstmp =>`,
|
|
320
|
+
moment.unix(report.result.timestamp),
|
|
321
|
+
);
|
|
322
|
+
lastUpdate.value = result;
|
|
323
|
+
break;
|
|
324
|
+
}
|
|
325
|
+
const delay = (ms) =>
|
|
326
|
+
new Promise((_resolve) => setTimeout(_resolve, ms));
|
|
327
|
+
await delay(5000);
|
|
328
|
+
} while (status !== "solved");
|
|
329
|
+
} catch (err) {
|
|
330
|
+
console.warn(`${tag} ${err}`);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// ----------------------------------------------------------------------------------------------------------------
|
|
335
|
+
async function checkWitnetBalance() {
|
|
336
|
+
const tag = `[@witnet/sdk/watcher][witnet:${wallet.provider.network}:${ledger.pkh}]`;
|
|
337
|
+
try {
|
|
338
|
+
balance = Witnet.Coins.fromPedros((await ledger.getBalance()).unlocked);
|
|
339
|
+
} catch (err) {
|
|
340
|
+
console.error(`${tag} Cannot check balance: ${err}`);
|
|
341
|
+
}
|
|
342
|
+
console.info(`${tag} Balance: ${balance.toString(2)}`);
|
|
343
|
+
if (balance.pedros < minBalance.pedros)
|
|
344
|
+
console.warn(`${tag} Low funds !!!`);
|
|
345
|
+
return balance;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
const _commas = (number) => {
|
|
350
|
+
const parts = number.toString().split(".");
|
|
351
|
+
const result =
|
|
352
|
+
parts.length <= 1
|
|
353
|
+
? `${parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",")}`
|
|
354
|
+
: `${parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",")}.${parts[1]}`;
|
|
355
|
+
return result;
|
|
356
|
+
};
|
|
357
|
+
|
|
358
|
+
function _spliceFromArgs(args, flag) {
|
|
359
|
+
const argIndex = args.indexOf(flag);
|
|
360
|
+
if (argIndex >= 0 && args.length > argIndex + 1) {
|
|
361
|
+
const value = args[argIndex + 1];
|
|
362
|
+
args.splice(argIndex, 2);
|
|
363
|
+
return value;
|
|
364
|
+
}
|
|
365
|
+
}
|