envio 3.0.2 → 3.1.0-rc.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.
Files changed (101) hide show
  1. package/README.md +0 -1
  2. package/evm.schema.json +15 -8
  3. package/fuel.schema.json +19 -12
  4. package/index.d.ts +0 -2
  5. package/package.json +6 -7
  6. package/rescript.json +1 -1
  7. package/src/Batch.res +4 -214
  8. package/src/Batch.res.mjs +6 -165
  9. package/src/ChainFetcher.res +12 -28
  10. package/src/ChainFetcher.res.mjs +8 -17
  11. package/src/ChainManager.res +10 -9
  12. package/src/ChainManager.res.mjs +6 -10
  13. package/src/Config.res +9 -25
  14. package/src/Config.res.mjs +17 -27
  15. package/src/Core.res +7 -0
  16. package/src/Ctx.res +1 -0
  17. package/src/Env.res +0 -8
  18. package/src/Env.res.mjs +0 -6
  19. package/src/EventConfigBuilder.res +13 -123
  20. package/src/EventConfigBuilder.res.mjs +6 -73
  21. package/src/EventProcessing.res +5 -29
  22. package/src/EventProcessing.res.mjs +11 -20
  23. package/src/EventUtils.res +0 -27
  24. package/src/EventUtils.res.mjs +0 -24
  25. package/src/FetchState.res +2 -15
  26. package/src/FetchState.res.mjs +3 -18
  27. package/src/GlobalState.res +26 -39
  28. package/src/GlobalState.res.mjs +12 -40
  29. package/src/HandlerLoader.res +6 -5
  30. package/src/HandlerLoader.res.mjs +27 -9
  31. package/src/HandlerRegister.res +1 -12
  32. package/src/HandlerRegister.res.mjs +1 -6
  33. package/src/HandlerRegister.resi +1 -1
  34. package/src/Hasura.res +96 -32
  35. package/src/Hasura.res.mjs +93 -38
  36. package/src/InMemoryStore.res +205 -45
  37. package/src/InMemoryStore.res.mjs +157 -40
  38. package/src/InMemoryTable.res +165 -249
  39. package/src/InMemoryTable.res.mjs +156 -227
  40. package/src/Internal.res +10 -34
  41. package/src/Internal.res.mjs +9 -3
  42. package/src/LoadLayer.res +5 -5
  43. package/src/LoadLayer.res.mjs +5 -5
  44. package/src/LogSelection.res +15 -19
  45. package/src/LogSelection.res.mjs +5 -6
  46. package/src/Main.res +4 -6
  47. package/src/Main.res.mjs +26 -15
  48. package/src/Persistence.res +7 -132
  49. package/src/Persistence.res.mjs +1 -102
  50. package/src/PgStorage.res +57 -40
  51. package/src/PgStorage.res.mjs +60 -34
  52. package/src/ReorgDetection.res +35 -58
  53. package/src/ReorgDetection.res.mjs +21 -29
  54. package/src/SimulateItems.res.mjs +21 -3
  55. package/src/Sink.res +2 -2
  56. package/src/Sink.res.mjs +1 -1
  57. package/src/TableIndices.res +9 -2
  58. package/src/TableIndices.res.mjs +7 -1
  59. package/src/TestIndexer.res +53 -60
  60. package/src/TestIndexer.res.mjs +77 -63
  61. package/src/TestIndexerProxyStorage.res +4 -14
  62. package/src/TestIndexerProxyStorage.res.mjs +1 -5
  63. package/src/UserContext.res +2 -4
  64. package/src/UserContext.res.mjs +4 -5
  65. package/src/Utils.res +0 -2
  66. package/src/Utils.res.mjs +0 -3
  67. package/src/bindings/ClickHouse.res +45 -38
  68. package/src/bindings/ClickHouse.res.mjs +16 -17
  69. package/src/bindings/Vitest.res +3 -0
  70. package/src/db/InternalTable.res +59 -18
  71. package/src/db/InternalTable.res.mjs +82 -51
  72. package/src/db/Table.res +9 -2
  73. package/src/db/Table.res.mjs +10 -7
  74. package/src/sources/EnvioApiClient.res +15 -0
  75. package/src/sources/EnvioApiClient.res.mjs +24 -0
  76. package/src/sources/EvmChain.res +32 -10
  77. package/src/sources/EvmChain.res.mjs +31 -5
  78. package/src/sources/HyperFuelSource.res +15 -58
  79. package/src/sources/HyperFuelSource.res.mjs +20 -39
  80. package/src/sources/HyperSync.res +54 -100
  81. package/src/sources/HyperSync.res.mjs +67 -96
  82. package/src/sources/HyperSync.resi +4 -22
  83. package/src/sources/HyperSyncClient.res +70 -247
  84. package/src/sources/HyperSyncClient.res.mjs +47 -46
  85. package/src/sources/HyperSyncSource.res +94 -166
  86. package/src/sources/HyperSyncSource.res.mjs +100 -127
  87. package/src/sources/RpcSource.res +43 -22
  88. package/src/sources/RpcSource.res.mjs +50 -35
  89. package/src/sources/SimulateSource.res +1 -7
  90. package/src/sources/SimulateSource.res.mjs +1 -7
  91. package/src/sources/Source.res +10 -1
  92. package/src/sources/Source.res.mjs +3 -0
  93. package/src/sources/SourceManager.res +177 -8
  94. package/src/sources/SourceManager.res.mjs +141 -3
  95. package/src/sources/SourceManager.resi +19 -0
  96. package/src/tui/Tui.res +44 -6
  97. package/src/tui/Tui.res.mjs +56 -8
  98. package/src/tui/components/TuiData.res +3 -0
  99. package/svm.schema.json +11 -4
  100. package/src/sources/HyperSyncJsonApi.res +0 -390
  101. package/src/sources/HyperSyncJsonApi.res.mjs +0 -237
@@ -1,27 +1,23 @@
1
1
  // Generated by ReScript, PLEASE EDIT WITH CARE
2
2
 
3
- import * as Rest from "../vendored/Rest.res.mjs";
4
3
  import * as Utils from "../Utils.res.mjs";
5
4
  import * as Hrtime from "../bindings/Hrtime.res.mjs";
6
5
  import * as Source from "./Source.res.mjs";
7
6
  import * as Logging from "../Logging.res.mjs";
8
- import * as Internal from "../Internal.res.mjs";
9
7
  import * as HyperSync from "./HyperSync.res.mjs";
10
8
  import * as Belt_Array from "@rescript/runtime/lib/es6/Belt_Array.js";
11
9
  import * as Prometheus from "../Prometheus.res.mjs";
12
10
  import * as EventRouter from "./EventRouter.res.mjs";
13
11
  import * as LogSelection from "../LogSelection.res.mjs";
12
+ import * as Stdlib_JsExn from "@rescript/runtime/lib/es6/Stdlib_JsExn.js";
14
13
  import * as ErrorHandling from "../ErrorHandling.res.mjs";
15
14
  import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
16
15
  import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
17
16
  import * as HyperSyncClient from "./HyperSyncClient.res.mjs";
18
- import * as HyperSyncJsonApi from "./HyperSyncJsonApi.res.mjs";
19
17
  import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
20
18
  import * as HyperSyncHeightStream from "./HyperSyncHeightStream.res.mjs";
21
19
 
22
20
  function getSelectionConfig(selection, chain) {
23
- let nonOptionalBlockFieldNames = new Set();
24
- let nonOptionalTransactionFieldNames = new Set();
25
21
  let capitalizedBlockFields = new Set();
26
22
  let capitalizedTransactionFields = new Set();
27
23
  let staticTopicSelectionsByContract = {};
@@ -32,15 +28,9 @@ function getSelectionConfig(selection, chain) {
32
28
  selection.eventConfigs.forEach(param => {
33
29
  let contractName = param.contractName;
34
30
  Array.from(param.selectedBlockFields).forEach(name => {
35
- if (!Internal.evmNullableBlockFields.has(name)) {
36
- nonOptionalBlockFieldNames.add(name);
37
- }
38
31
  capitalizedBlockFields.add(Utils.$$String.capitalize(name));
39
32
  });
40
33
  Array.from(param.selectedTransactionFields).forEach(name => {
41
- if (!Internal.evmNullableTransactionFields.has(name)) {
42
- nonOptionalTransactionFieldNames.add(name);
43
- }
44
34
  capitalizedTransactionFields.add(Utils.$$String.capitalize(name));
45
35
  });
46
36
  let eventFilters = param.getEventFiltersOrThrow(chain);
@@ -104,9 +94,7 @@ function getSelectionConfig(selection, chain) {
104
94
  };
105
95
  return {
106
96
  getLogSelectionOrThrow: getLogSelectionOrThrow,
107
- fieldSelection: fieldSelection,
108
- nonOptionalBlockFieldNames: Array.from(nonOptionalBlockFieldNames),
109
- nonOptionalTransactionFieldNames: Array.from(nonOptionalTransactionFieldNames)
97
+ fieldSelection: fieldSelection
110
98
  };
111
99
  }
112
100
 
@@ -114,11 +102,13 @@ function memoGetSelectionConfig(chain) {
114
102
  return Utils.$$WeakMap.memoize(selection => getSelectionConfig(selection, chain));
115
103
  }
116
104
 
105
+ function isUnauthorizedError(message) {
106
+ return message.includes("401 Unauthorized");
107
+ }
108
+
117
109
  function make(param) {
118
- let lowercaseAddresses = param.lowercaseAddresses;
119
110
  let apiToken = param.apiToken;
120
111
  let eventRouter = param.eventRouter;
121
- let allEventSignatures = param.allEventSignatures;
122
112
  let endpointUrl = param.endpointUrl;
123
113
  let chain = param.chain;
124
114
  let name = "HyperSync";
@@ -126,54 +116,37 @@ function make(param) {
126
116
  let apiToken$1 = apiToken !== undefined ? apiToken : Stdlib_JsError.throwWithMessage(`An API token is required for using HyperSync as a data-source.
127
117
  Set the ENVIO_API_TOKEN environment variable in your .env file.
128
118
  Learn more or get a free API token at: https://envio.dev/app/api-tokens`);
129
- let client = HyperSyncClient.make(endpointUrl, apiToken$1, param.clientTimeoutMillis, param.clientMaxRetries, !lowercaseAddresses, param.serializationFormat, param.enableQueryCaching, undefined, undefined, undefined);
130
- let hscDecoder = {
131
- contents: undefined
132
- };
133
- let getHscDecoder = () => {
134
- let decoder = hscDecoder.contents;
135
- if (decoder !== undefined) {
136
- return decoder;
137
- }
138
- let decoder$1;
139
- try {
140
- decoder$1 = HyperSyncClient.Decoder.fromSignatures(allEventSignatures);
141
- } catch (raw_exn) {
142
- let exn = Primitive_exceptions.internalToException(raw_exn);
143
- return ErrorHandling.mkLogAndRaise(undefined, "Failed to instantiate a decoder from hypersync client, please double check your ABI", exn);
144
- }
145
- if (lowercaseAddresses) {
146
- decoder$1.disableChecksummedAddresses();
147
- } else {
148
- decoder$1.enableChecksummedAddresses();
149
- }
150
- return decoder$1;
151
- };
119
+ let client;
120
+ try {
121
+ client = HyperSyncClient.make(endpointUrl, apiToken$1, param.clientTimeoutMillis, param.allEventParams, !param.lowercaseAddresses, param.serializationFormat, param.enableQueryCaching, undefined, undefined, undefined, param.logLevel);
122
+ } catch (raw_exn) {
123
+ let exn = Primitive_exceptions.internalToException(raw_exn);
124
+ client = ErrorHandling.mkLogAndRaise(undefined, "Failed to instantiate the hypersync client, please double check your ABI", exn);
125
+ }
152
126
  let UndefinedValue = /* @__PURE__ */Primitive_exceptions.create("UndefinedValue");
153
127
  let makeEventBatchQueueItem = (item, params, eventConfig) => {
154
128
  let block = item.block;
155
- let log = item.log;
129
+ let logIndex = item.logIndex;
156
130
  return {
157
131
  kind: 0,
158
132
  eventConfig: eventConfig,
159
133
  timestamp: block.timestamp,
160
134
  chain: chain,
161
135
  blockNumber: block.number,
162
- logIndex: log.logIndex,
136
+ logIndex: logIndex,
163
137
  event: {
164
138
  contractName: eventConfig.contractName,
165
139
  eventName: eventConfig.name,
166
140
  params: params,
167
141
  chainId: chain,
168
- srcAddress: log.address,
169
- logIndex: log.logIndex,
142
+ srcAddress: item.srcAddress,
143
+ logIndex: logIndex,
170
144
  transaction: item.transaction,
171
145
  block: block
172
146
  }
173
147
  };
174
148
  };
175
149
  let getItemsOrThrow = async (fromBlock, toBlock, addressesByContractName, indexingAddresses, knownHeight, param, selection, retry, logger) => {
176
- let mkLogAndRaise = (extra, extra$1) => ErrorHandling.mkLogAndRaise(logger, extra, extra$1);
177
150
  let totalTimeRef = Hrtime.makeTimer();
178
151
  let selectionConfig = getSelectionConfig(selection);
179
152
  let logSelections;
@@ -187,7 +160,7 @@ Learn more or get a free API token at: https://envio.dev/app/api-tokens`);
187
160
  Prometheus.SourceRequestCount.increment(name, chain, "getLogs");
188
161
  let pageUnsafe;
189
162
  try {
190
- pageUnsafe = await HyperSync.GetLogs.query(client, fromBlock, toBlock, logSelections, selectionConfig.fieldSelection, selectionConfig.nonOptionalBlockFieldNames, selectionConfig.nonOptionalTransactionFieldNames);
163
+ pageUnsafe = await HyperSync.GetLogs.query(client, fromBlock, toBlock, logSelections, selectionConfig.fieldSelection);
191
164
  } catch (raw_error) {
192
165
  let error = Primitive_exceptions.internalToException(raw_error);
193
166
  if (error.RE_EXN_ID === HyperSync.GetLogs.$$Error) {
@@ -217,6 +190,9 @@ Learn more or get a free API token at: https://envio.dev/app/api-tokens`);
217
190
  Error: new Error()
218
191
  };
219
192
  }
193
+ if (error.RE_EXN_ID === Source.RateLimited) {
194
+ throw error;
195
+ }
220
196
  throw {
221
197
  RE_EXN_ID: Source.GetItemsError,
222
198
  _1: {
@@ -235,73 +211,22 @@ Learn more or get a free API token at: https://envio.dev/app/api-tokens`);
235
211
  let pageFetchTime = Hrtime.toSecondsFloat(Hrtime.timeSince(startFetchingBatchTimeRef));
236
212
  let knownHeight$1 = pageUnsafe.archiveHeight;
237
213
  let heighestBlockQueried = pageUnsafe.nextBlock - 1 | 0;
238
- let match = pageUnsafe.rollbackGuard;
239
- let lastBlockQueriedPromise;
240
- if (match !== undefined) {
241
- lastBlockQueriedPromise = Promise.resolve({
242
- blockHash: match.hash,
243
- blockNumber: match.blockNumber,
244
- blockTimestamp: match.timestamp
245
- });
246
- } else {
247
- let match$1 = Belt_Array.get(pageUnsafe.items, pageUnsafe.items.length - 1 | 0);
248
- let exit = 0;
249
- if (match$1 !== undefined) {
250
- let block = match$1.block;
251
- if (block.number === heighestBlockQueried) {
252
- lastBlockQueriedPromise = Promise.resolve({
253
- blockHash: block.hash,
254
- blockNumber: block.number,
255
- blockTimestamp: block.timestamp
256
- });
257
- } else {
258
- exit = 1;
259
- }
260
- } else {
261
- exit = 1;
262
- }
263
- if (exit === 1) {
264
- lastBlockQueriedPromise = HyperSync.queryBlockData(client, heighestBlockQueried, name, chain, logger).then(res => {
265
- if (res.TAG !== "Ok") {
266
- return mkLogAndRaise(`Failed to query blockData for block ` + heighestBlockQueried.toString(), HyperSync.queryErrorToMsq(res._0));
267
- }
268
- let blockData = res._0;
269
- if (blockData !== undefined) {
270
- return blockData;
271
- } else {
272
- return mkLogAndRaise(`Failure, blockData for block ` + heighestBlockQueried.toString() + ` unexpectedly returned None`, {
273
- RE_EXN_ID: "Not_found"
274
- });
275
- }
276
- });
277
- }
278
- }
279
214
  let parsingTimeRef = Hrtime.makeTimer();
280
215
  let parsedQueueItems = [];
281
- let parsedEvents;
282
- try {
283
- parsedEvents = await getHscDecoder().decodeEvents(pageUnsafe.events);
284
- } catch (raw_exn$1) {
285
- let exn$1 = Primitive_exceptions.internalToException(raw_exn$1);
286
- parsedEvents = mkLogAndRaise("Failed to parse events using hypersync client, please double check your ABI.", exn$1);
287
- }
288
- Belt_Array.forEachWithIndex(pageUnsafe.items, (index, item) => {
289
- let block = item.block;
290
- let log = item.log;
291
- let topic0 = Utils.$$Array.firstUnsafe(log.topics);
292
- let maybeEventConfig = EventRouter.get(eventRouter, EventRouter.getEvmEventId(topic0, log.topics.length), log.address, block.number, indexingAddresses);
293
- let maybeDecodedEvent = parsedEvents[index];
216
+ Belt_Array.forEach(pageUnsafe.items, item => {
217
+ let maybeEventConfig = EventRouter.get(eventRouter, EventRouter.getEvmEventId(item.topic0, item.topicCount), item.srcAddress, item.block.number, indexingAddresses);
218
+ let match = item.params;
294
219
  if (maybeEventConfig === undefined) {
295
220
  return;
296
221
  }
297
- if (maybeDecodedEvent == null) {
298
- maybeDecodedEvent === null;
222
+ if (match == null) {
223
+ match === null;
299
224
  } else {
300
- parsedQueueItems.push(makeEventBatchQueueItem(item, maybeEventConfig.convertHyperSyncEventArgs(maybeDecodedEvent), maybeEventConfig));
225
+ parsedQueueItems.push(makeEventBatchQueueItem(item, match, maybeEventConfig));
301
226
  return;
302
227
  }
303
- let logIndex = log.logIndex;
304
- let blockNumber = block.number;
228
+ let logIndex = item.logIndex;
229
+ let blockNumber = item.block.number;
305
230
  let exn = {
306
231
  RE_EXN_ID: UndefinedValue
307
232
  };
@@ -318,15 +243,43 @@ Learn more or get a free API token at: https://envio.dev/app/api-tokens`);
318
243
  ErrorHandling.mkLogAndRaise(logger$1, msg, exn);
319
244
  });
320
245
  let parsingTimeElapsed = Hrtime.toSecondsFloat(Hrtime.timeSince(parsingTimeRef));
321
- let rangeLastBlock = await lastBlockQueriedPromise;
322
- let reorgGuard_prevRangeLastBlock = Stdlib_Option.map(pageUnsafe.rollbackGuard, v => ({
323
- blockHash: v.firstParentHash,
324
- blockNumber: v.firstBlockNumber - 1 | 0
325
- }));
326
- let reorgGuard = {
327
- rangeLastBlock: rangeLastBlock,
328
- prevRangeLastBlock: reorgGuard_prevRangeLastBlock
329
- };
246
+ let blockHashes = [];
247
+ Belt_Array.forEach(pageUnsafe.items, param => {
248
+ let block = param.block;
249
+ let match = block.number;
250
+ let match$1 = block.hash;
251
+ if (match !== undefined && match$1 !== undefined) {
252
+ blockHashes.push({
253
+ blockHash: match$1,
254
+ blockNumber: match
255
+ });
256
+ return;
257
+ }
258
+ });
259
+ let match = pageUnsafe.rollbackGuard;
260
+ if (match !== undefined) {
261
+ blockHashes.push({
262
+ blockHash: match.hash,
263
+ blockNumber: match.blockNumber
264
+ });
265
+ blockHashes.push({
266
+ blockHash: match.firstParentHash,
267
+ blockNumber: match.firstBlockNumber - 1 | 0
268
+ });
269
+ }
270
+ let match$1 = pageUnsafe.rollbackGuard;
271
+ let latestFetchedBlockTimestamp;
272
+ if (match$1 !== undefined) {
273
+ latestFetchedBlockTimestamp = match$1.timestamp;
274
+ } else {
275
+ let match$2 = Belt_Array.get(pageUnsafe.items, pageUnsafe.items.length - 1 | 0);
276
+ if (match$2 !== undefined) {
277
+ let block = match$2.block;
278
+ latestFetchedBlockTimestamp = block.number === heighestBlockQueried ? block.timestamp : 0;
279
+ } else {
280
+ latestFetchedBlockTimestamp = 0;
281
+ }
282
+ }
330
283
  let totalTimeElapsed = Hrtime.toSecondsFloat(Hrtime.timeSince(totalTimeRef));
331
284
  let stats_parsing$unknowntime$unknown$lpars$rpar = parsingTimeElapsed;
332
285
  let stats_page$unknownfetch$unknowntime$unknown$lpars$rpar = pageFetchTime;
@@ -337,16 +290,15 @@ Learn more or get a free API token at: https://envio.dev/app/api-tokens`);
337
290
  };
338
291
  return {
339
292
  knownHeight: knownHeight$1,
340
- reorgGuard: reorgGuard,
293
+ blockHashes: blockHashes,
341
294
  parsedQueueItems: parsedQueueItems,
342
295
  fromBlockQueried: fromBlock,
343
- latestFetchedBlockNumber: rangeLastBlock.blockNumber,
344
- latestFetchedBlockTimestamp: rangeLastBlock.blockTimestamp,
296
+ latestFetchedBlockNumber: heighestBlockQueried,
297
+ latestFetchedBlockTimestamp: latestFetchedBlockTimestamp,
345
298
  stats: stats
346
299
  };
347
300
  };
348
301
  let getBlockHashes = (blockNumbers, logger) => HyperSync.queryBlockDataMulti(client, blockNumbers, name, chain, logger).then(HyperSync.mapExn);
349
- let jsonApiClient = Rest.client(endpointUrl, undefined);
350
302
  return {
351
303
  name: name,
352
304
  sourceFor: "Sync",
@@ -356,16 +308,36 @@ Learn more or get a free API token at: https://envio.dev/app/api-tokens`);
356
308
  getBlockHashes: getBlockHashes,
357
309
  getHeightOrThrow: async () => {
358
310
  let timerRef = Hrtime.makeTimer();
359
- let height = await Rest.fetch(HyperSyncJsonApi.heightRoute, apiToken$1, jsonApiClient);
360
311
  let result;
361
- if (typeof height === "number") {
362
- result = height;
363
- } else if (height === `Your token is malformed. For more info: https://docs.envio.dev/docs/HyperSync/api-tokens.`) {
364
- Logging.error(`Your ENVIO_API_TOKEN is malformed. The indexer will not be able to fetch events. Update the token and restart the indexer using 'pnpm envio start'. For more info: https://docs.envio.dev/docs/HyperSync/api-tokens`);
365
- await new Promise((param, param$1) => {});
366
- result = 0;
367
- } else {
368
- result = Stdlib_JsError.throwWithMessage(height);
312
+ try {
313
+ result = await client.getHeight();
314
+ } catch (raw_e) {
315
+ let e = Primitive_exceptions.internalToException(raw_e);
316
+ if (e.RE_EXN_ID === "JsExn") {
317
+ let e$1 = e._1;
318
+ let message = Stdlib_JsExn.message(e$1);
319
+ if (message !== undefined) {
320
+ if (message.includes("401 Unauthorized")) {
321
+ Logging.error(`Your ENVIO_API_TOKEN was rejected by HyperSync (401 Unauthorized). The indexer will not be able to fetch events. Update the token and try again using 'envio start' or 'envio dev'. For more info: https://docs.envio.dev/docs/HyperSync/api-tokens`);
322
+ await new Promise((param, param$1) => {});
323
+ result = 0;
324
+ } else {
325
+ throw {
326
+ RE_EXN_ID: "JsExn",
327
+ _1: e$1,
328
+ Error: new Error()
329
+ };
330
+ }
331
+ } else {
332
+ throw {
333
+ RE_EXN_ID: "JsExn",
334
+ _1: e$1,
335
+ Error: new Error()
336
+ };
337
+ }
338
+ } else {
339
+ throw e;
340
+ }
369
341
  }
370
342
  let seconds = Hrtime.toSecondsFloat(Hrtime.timeSince(timerRef));
371
343
  Prometheus.SourceRequestCount.increment(name, chain, "getHeight");
@@ -380,6 +352,7 @@ Learn more or get a free API token at: https://envio.dev/app/api-tokens`);
380
352
  export {
381
353
  getSelectionConfig,
382
354
  memoGetSelectionConfig,
355
+ isUnauthorizedError,
383
356
  make,
384
357
  }
385
- /* Rest Not a pure module */
358
+ /* Utils Not a pure module */
@@ -7,6 +7,7 @@ type blockInfo = {
7
7
  number: int,
8
8
  timestamp: int,
9
9
  hash: string,
10
+ parentHash: string,
10
11
  }
11
12
 
12
13
  let getKnownRawBlock = async (~client, ~blockNumber) =>
@@ -29,6 +30,9 @@ let parseBlockInfo = (json: JSON.t): blockInfo => {
29
30
  hash: jsonDict
30
31
  ->Dict.getUnsafe("hash")
31
32
  ->S.parseOrThrow(S.string),
33
+ parentHash: jsonDict
34
+ ->Dict.getUnsafe("parentHash")
35
+ ->S.parseOrThrow(S.string),
32
36
  }
33
37
  }
34
38
 
@@ -838,7 +842,7 @@ type options = {
838
842
  url: string,
839
843
  chain: ChainMap.Chain.t,
840
844
  eventRouter: EventRouter.t<Internal.evmEventConfig>,
841
- allEventSignatures: array<string>,
845
+ allEventParams: array<HyperSyncClient.Decoder.eventParamsInput>,
842
846
  lowercaseAddresses: bool,
843
847
  ws?: string,
844
848
  }
@@ -850,7 +854,7 @@ let make = (
850
854
  url,
851
855
  chain,
852
856
  eventRouter,
853
- allEventSignatures,
857
+ allEventParams,
854
858
  lowercaseAddresses,
855
859
  ?ws,
856
860
  }: options,
@@ -993,12 +997,16 @@ let make = (
993
997
  {log: hyperSyncLog}
994
998
  }
995
999
 
996
- let hscDecoder: ref<option<HyperSyncClient.Decoder.t>> = ref(None)
1000
+ let hscDecoder: ref<option<HyperSyncClient.Decoder.tWithParams>> = ref(None)
997
1001
  let getHscDecoder = () => {
998
1002
  switch hscDecoder.contents {
999
1003
  | Some(decoder) => decoder
1000
1004
  | None => {
1001
- let decoder = HyperSyncClient.Decoder.fromSignatures(allEventSignatures)
1005
+ let decoder = HyperSyncClient.Decoder.fromParams(
1006
+ allEventParams,
1007
+ ~checksumAddresses=!lowercaseAddresses,
1008
+ )
1009
+ hscDecoder := Some(decoder)
1002
1010
  decoder
1003
1011
  }
1004
1012
  }
@@ -1071,7 +1079,7 @@ let make = (
1071
1079
  // We also don't care about it when we have a hard max block interval
1072
1080
  if (
1073
1081
  executedBlockInterval >= suggestedBlockInterval &&
1074
- !(mutSuggestedBlockIntervals->Utils.Dict.has(maxSuggestedBlockIntervalKey))
1082
+ !(mutSuggestedBlockIntervals->Dict.has(maxSuggestedBlockIntervalKey))
1075
1083
  ) {
1076
1084
  // Increase batch size going forward, but do not increase past a configured maximum
1077
1085
  // See: https://en.wikipedia.org/wiki/Additive_increase/multiplicative_decrease
@@ -1088,7 +1096,7 @@ let make = (
1088
1096
  let hyperSyncEvents = logs->Belt.Array.map(convertLogToHyperSyncEvent)
1089
1097
 
1090
1098
  // Decode using HyperSyncClient decoder
1091
- let parsedEvents = try await getHscDecoder().decodeEvents(hyperSyncEvents) catch {
1099
+ let parsedEvents = try await getHscDecoder().decodeLogs(hyperSyncEvents) catch {
1092
1100
  | exn =>
1093
1101
  throw(
1094
1102
  Source.GetItemsError(
@@ -1107,7 +1115,7 @@ let make = (
1107
1115
  ->Array.zip(parsedEvents)
1108
1116
  ->Array.filterMap(((
1109
1117
  log: Rpc.GetLogs.log,
1110
- maybeDecodedEvent: Nullable.t<HyperSyncClient.Decoder.decodedEvent>,
1118
+ maybeDecodedEvent: Nullable.t<Internal.eventParams>,
1111
1119
  )) => {
1112
1120
  let topic0 = log.topics[0]->Option.getOr("0x0")
1113
1121
  let routedAddress = if lowercaseAddresses {
@@ -1158,7 +1166,7 @@ let make = (
1158
1166
  contractName: eventConfig.contractName,
1159
1167
  eventName: eventConfig.name,
1160
1168
  chainId: chain->ChainMap.Chain.toChainId,
1161
- params: decoded->eventConfig.convertHyperSyncEventArgs,
1169
+ params: decoded,
1162
1170
  transaction,
1163
1171
  block,
1164
1172
  srcAddress: routedAddress,
@@ -1178,16 +1186,27 @@ let make = (
1178
1186
 
1179
1187
  let totalTimeElapsed = startFetchingBatchTimeRef->Hrtime.timeSince->Hrtime.toSecondsFloat
1180
1188
 
1181
- let reorgGuard: ReorgDetection.reorgGuard = {
1182
- prevRangeLastBlock: optFirstBlockParent->Option.map(b => {
1183
- ReorgDetection.blockNumber: b.number,
1184
- blockHash: b.hash,
1185
- }),
1186
- rangeLastBlock: {
1187
- blockNumber: latestFetchedBlockInfo.number,
1188
- blockHash: latestFetchedBlockInfo.hash,
1189
- },
1189
+ // Every fetched block carries `hash` and `parentHash`, so each one yields
1190
+ // two confirmed (number, hash) pairs for reorg detection at no extra cost.
1191
+ let blockHashes = []
1192
+ let pushBlockInfo = (b: blockInfo) => {
1193
+ blockHashes->Array.push({ReorgDetection.blockNumber: b.number, blockHash: b.hash})->ignore
1194
+ if b.number > 0 {
1195
+ blockHashes
1196
+ ->Array.push({ReorgDetection.blockNumber: b.number - 1, blockHash: b.parentHash})
1197
+ ->ignore
1198
+ }
1199
+ }
1200
+ pushBlockInfo(latestFetchedBlockInfo)
1201
+ switch optFirstBlockParent {
1202
+ | Some(b) => pushBlockInfo(b)
1203
+ | None => ()
1190
1204
  }
1205
+ logs->Belt.Array.forEach(log =>
1206
+ blockHashes
1207
+ ->Array.push({ReorgDetection.blockNumber: log.blockNumber, blockHash: log.blockHash})
1208
+ ->ignore
1209
+ )
1191
1210
 
1192
1211
  {
1193
1212
  latestFetchedBlockTimestamp: latestFetchedBlockInfo.timestamp,
@@ -1197,19 +1216,20 @@ let make = (
1197
1216
  totalTimeElapsed: totalTimeElapsed,
1198
1217
  },
1199
1218
  knownHeight,
1200
- reorgGuard,
1219
+ blockHashes,
1201
1220
  fromBlockQueried: fromBlock,
1202
1221
  }
1203
1222
  }
1204
1223
 
1205
- let getBlockHashes = (~blockNumbers, ~logger as _currentlyUnusedLogger) => {
1206
- // Clear cache by creating a fresh LazyLoader
1207
- // This is important, since we call this
1208
- // function when a reorg is detected
1224
+ let onReorg = (~rollbackTargetBlock as _) => {
1225
+ // Drop cached block/transaction/receipt data — after a reorg the cached
1226
+ // entries may refer to orphaned-chain values.
1209
1227
  blockLoader := makeBlockLoader()
1210
1228
  transactionLoader := makeTransactionLoader()
1211
1229
  receiptLoader := makeReceiptLoader()
1230
+ }
1212
1231
 
1232
+ let getBlockHashes = (~blockNumbers, ~logger as _currentlyUnusedLogger) => {
1213
1233
  blockNumbers
1214
1234
  ->Array.map(blockNum => blockLoader.contents->LazyLoader.get(blockNum))
1215
1235
  ->Promise.all
@@ -1243,6 +1263,7 @@ let make = (
1243
1263
  poweredByHyperSync: false,
1244
1264
  pollingInterval: syncConfig.pollingInterval,
1245
1265
  getBlockHashes,
1266
+ onReorg,
1246
1267
  getHeightOrThrow: async () => {
1247
1268
  let timerRef = Hrtime.makeTimer()
1248
1269
  let height = try {
@@ -43,7 +43,8 @@ function parseBlockInfo(json) {
43
43
  return {
44
44
  number: S$RescriptSchema.parseOrThrow(json["number"], Rpc.hexIntSchema),
45
45
  timestamp: S$RescriptSchema.parseOrThrow(json["timestamp"], Rpc.hexIntSchema),
46
- hash: S$RescriptSchema.parseOrThrow(json["hash"], S$RescriptSchema.string)
46
+ hash: S$RescriptSchema.parseOrThrow(json["hash"], S$RescriptSchema.string),
47
+ parentHash: S$RescriptSchema.parseOrThrow(json["parentHash"], S$RescriptSchema.string)
47
48
  };
48
49
  }
49
50
 
@@ -917,7 +918,7 @@ function makeThrowingGetEventTransaction(getTransactionJson, getReceiptJson, low
917
918
 
918
919
  function make(param) {
919
920
  let lowercaseAddresses = param.lowercaseAddresses;
920
- let allEventSignatures = param.allEventSignatures;
921
+ let allEventParams = param.allEventParams;
921
922
  let eventRouter = param.eventRouter;
922
923
  let chain = param.chain;
923
924
  let url = param.url;
@@ -1021,9 +1022,10 @@ function make(param) {
1021
1022
  let decoder = hscDecoder.contents;
1022
1023
  if (decoder !== undefined) {
1023
1024
  return decoder;
1024
- } else {
1025
- return HyperSyncClient.Decoder.fromSignatures(allEventSignatures);
1026
1025
  }
1026
+ let decoder$1 = HyperSyncClient.Decoder.fromParams(allEventParams, !lowercaseAddresses);
1027
+ hscDecoder.contents = decoder$1;
1028
+ return decoder$1;
1027
1029
  };
1028
1030
  let getItemsOrThrow = async (fromBlock, toBlock, addressesByContractName, indexingAddresses, knownHeight, partitionId, selection, param, param$1) => {
1029
1031
  let startFetchingBatchTimeRef = Hrtime.makeTimer();
@@ -1038,13 +1040,13 @@ function make(param) {
1038
1040
  let latestFetchedBlockInfo = match$2.latestFetchedBlockInfo;
1039
1041
  let logs = match$2.logs;
1040
1042
  let executedBlockInterval = (suggestedToBlock - fromBlock | 0) + 1 | 0;
1041
- if (executedBlockInterval >= suggestedBlockInterval && !Utils.Dict.has(mutSuggestedBlockIntervals, maxSuggestedBlockIntervalKey)) {
1043
+ if (executedBlockInterval >= suggestedBlockInterval && !(maxSuggestedBlockIntervalKey in mutSuggestedBlockIntervals)) {
1042
1044
  mutSuggestedBlockIntervals[partitionId] = Primitive_int.min(executedBlockInterval + syncConfig.accelerationAdditive | 0, syncConfig.intervalCeiling);
1043
1045
  }
1044
1046
  let hyperSyncEvents = Belt_Array.map(logs, convertLogToHyperSyncEvent);
1045
1047
  let parsedEvents;
1046
1048
  try {
1047
- parsedEvents = await getHscDecoder().decodeEvents(hyperSyncEvents);
1049
+ parsedEvents = await getHscDecoder().decodeLogs(hyperSyncEvents);
1048
1050
  } catch (raw_exn) {
1049
1051
  let exn = Primitive_exceptions.internalToException(raw_exn);
1050
1052
  throw {
@@ -1100,7 +1102,7 @@ function make(param) {
1100
1102
  event: {
1101
1103
  contractName: eventConfig.contractName,
1102
1104
  eventName: eventConfig.name,
1103
- params: eventConfig.convertHyperSyncEventArgs(maybeDecodedEvent),
1105
+ params: maybeDecodedEvent,
1104
1106
  chainId: chain,
1105
1107
  srcAddress: routedAddress,
1106
1108
  logIndex: log.logIndex,
@@ -1113,21 +1115,33 @@ function make(param) {
1113
1115
  }));
1114
1116
  let optFirstBlockParent = await firstBlockParentPromise;
1115
1117
  let totalTimeElapsed = Hrtime.toSecondsFloat(Hrtime.timeSince(startFetchingBatchTimeRef));
1116
- let reorgGuard_rangeLastBlock = {
1117
- blockHash: latestFetchedBlockInfo.hash,
1118
- blockNumber: latestFetchedBlockInfo.number
1119
- };
1120
- let reorgGuard_prevRangeLastBlock = Stdlib_Option.map(optFirstBlockParent, b => ({
1121
- blockHash: b.hash,
1122
- blockNumber: b.number
1123
- }));
1124
- let reorgGuard = {
1125
- rangeLastBlock: reorgGuard_rangeLastBlock,
1126
- prevRangeLastBlock: reorgGuard_prevRangeLastBlock
1118
+ let blockHashes = [];
1119
+ let pushBlockInfo = b => {
1120
+ blockHashes.push({
1121
+ blockHash: b.hash,
1122
+ blockNumber: b.number
1123
+ });
1124
+ if (b.number > 0) {
1125
+ blockHashes.push({
1126
+ blockHash: b.parentHash,
1127
+ blockNumber: b.number - 1 | 0
1128
+ });
1129
+ return;
1130
+ }
1127
1131
  };
1132
+ pushBlockInfo(latestFetchedBlockInfo);
1133
+ if (optFirstBlockParent !== undefined) {
1134
+ pushBlockInfo(optFirstBlockParent);
1135
+ }
1136
+ Belt_Array.forEach(logs, log => {
1137
+ blockHashes.push({
1138
+ blockHash: log.blockHash,
1139
+ blockNumber: log.blockNumber
1140
+ });
1141
+ });
1128
1142
  return {
1129
1143
  knownHeight: knownHeight,
1130
- reorgGuard: reorgGuard,
1144
+ blockHashes: blockHashes,
1131
1145
  parsedQueueItems: parsedQueueItems,
1132
1146
  fromBlockQueried: fromBlock,
1133
1147
  latestFetchedBlockNumber: latestFetchedBlockInfo.number,
@@ -1137,25 +1151,25 @@ function make(param) {
1137
1151
  }
1138
1152
  };
1139
1153
  };
1140
- let getBlockHashes = (blockNumbers, _currentlyUnusedLogger) => {
1154
+ let onReorg = param => {
1141
1155
  blockLoader.contents = makeBlockLoader();
1142
1156
  transactionLoader.contents = makeTransactionLoader();
1143
1157
  receiptLoader.contents = makeReceiptLoader();
1144
- return Stdlib_Promise.$$catch(Promise.all(blockNumbers.map(blockNum => LazyLoader.get(blockLoader.contents, blockNum))).then(rawBlocks => ({
1145
- TAG: "Ok",
1146
- _0: rawBlocks.map(json => {
1147
- let b = parseBlockInfo(json);
1148
- return {
1149
- blockHash: b.hash,
1150
- blockNumber: b.number,
1151
- blockTimestamp: b.timestamp
1152
- };
1153
- })
1154
- })), exn => Promise.resolve({
1155
- TAG: "Error",
1156
- _0: exn
1157
- }));
1158
1158
  };
1159
+ let getBlockHashes = (blockNumbers, _currentlyUnusedLogger) => Stdlib_Promise.$$catch(Promise.all(blockNumbers.map(blockNum => LazyLoader.get(blockLoader.contents, blockNum))).then(rawBlocks => ({
1160
+ TAG: "Ok",
1161
+ _0: rawBlocks.map(json => {
1162
+ let b = parseBlockInfo(json);
1163
+ return {
1164
+ blockHash: b.hash,
1165
+ blockNumber: b.number,
1166
+ blockTimestamp: b.timestamp
1167
+ };
1168
+ })
1169
+ })), exn => Promise.resolve({
1170
+ TAG: "Error",
1171
+ _0: exn
1172
+ }));
1159
1173
  let createHeightSubscription = Belt_Option.map(param.ws, wsUrl => (onHeight => RpcWebSocketHeightStream.subscribe(wsUrl, chain, onHeight)));
1160
1174
  return {
1161
1175
  name: name,
@@ -1181,7 +1195,8 @@ function make(param) {
1181
1195
  return height;
1182
1196
  },
1183
1197
  getItemsOrThrow: getItemsOrThrow,
1184
- createHeightSubscription: createHeightSubscription
1198
+ createHeightSubscription: createHeightSubscription,
1199
+ onReorg: onReorg
1185
1200
  };
1186
1201
  }
1187
1202