envio 3.3.0-alpha.1 → 3.3.0-alpha.11

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 (143) hide show
  1. package/evm.schema.json +10 -0
  2. package/index.d.ts +45 -25
  3. package/licenses/CLA.md +35 -0
  4. package/licenses/EULA.md +67 -0
  5. package/licenses/LICENSE.md +45 -0
  6. package/licenses/README.md +35 -0
  7. package/package.json +10 -9
  8. package/src/Address.res +5 -2
  9. package/src/Address.res.mjs +3 -1
  10. package/src/Api.res +1 -1
  11. package/src/Api.res.mjs +1 -1
  12. package/src/Batch.res +0 -6
  13. package/src/Batch.res.mjs +1 -12
  14. package/src/BatchProcessing.res +7 -12
  15. package/src/BatchProcessing.res.mjs +8 -7
  16. package/src/Bin.res +3 -0
  17. package/src/Bin.res.mjs +4 -0
  18. package/src/ChainFetching.res +53 -16
  19. package/src/ChainFetching.res.mjs +37 -19
  20. package/src/ChainMetadata.res +1 -11
  21. package/src/ChainMetadata.res.mjs +1 -10
  22. package/src/ChainState.res +630 -161
  23. package/src/ChainState.res.mjs +438 -101
  24. package/src/ChainState.resi +77 -4
  25. package/src/Config.res +70 -38
  26. package/src/Config.res.mjs +52 -12
  27. package/src/ContractRegisterContext.res +2 -12
  28. package/src/ContractRegisterContext.res.mjs +3 -5
  29. package/src/Core.res +34 -3
  30. package/src/Core.res.mjs +12 -0
  31. package/src/CrossChainState.res +130 -89
  32. package/src/CrossChainState.res.mjs +66 -61
  33. package/src/CrossChainState.resi +1 -1
  34. package/src/Ecosystem.res +5 -6
  35. package/src/Ecosystem.res.mjs +3 -3
  36. package/src/Envio.res +17 -11
  37. package/src/EnvioGlobal.res +53 -0
  38. package/src/EnvioGlobal.res.mjs +31 -0
  39. package/src/EventConfigBuilder.res +191 -127
  40. package/src/EventConfigBuilder.res.mjs +116 -66
  41. package/src/EventProcessing.res +77 -28
  42. package/src/EventProcessing.res.mjs +56 -29
  43. package/src/ExitOnCaughtUp.res +10 -2
  44. package/src/ExitOnCaughtUp.res.mjs +10 -1
  45. package/src/FetchState.res +684 -415
  46. package/src/FetchState.res.mjs +505 -486
  47. package/src/HandlerLoader.res +8 -104
  48. package/src/HandlerLoader.res.mjs +2 -81
  49. package/src/HandlerRegister.res +520 -144
  50. package/src/HandlerRegister.res.mjs +286 -133
  51. package/src/HandlerRegister.resi +24 -8
  52. package/src/IndexerState.res +10 -3
  53. package/src/IndexerState.res.mjs +11 -4
  54. package/src/IndexerState.resi +2 -1
  55. package/src/IndexingAddresses.res +108 -0
  56. package/src/IndexingAddresses.res.mjs +101 -0
  57. package/src/IndexingAddresses.resi +34 -0
  58. package/src/Internal.res +166 -48
  59. package/src/Internal.res.mjs +30 -2
  60. package/src/LoadLayer.res +5 -5
  61. package/src/LoadLayer.res.mjs +6 -6
  62. package/src/LogSelection.res +92 -217
  63. package/src/LogSelection.res.mjs +95 -184
  64. package/src/Main.res +71 -236
  65. package/src/Main.res.mjs +60 -145
  66. package/src/Metrics.res +74 -0
  67. package/src/Metrics.res.mjs +75 -0
  68. package/src/PgStorage.res +4 -4
  69. package/src/PgStorage.res.mjs +5 -5
  70. package/src/Prometheus.res +10 -63
  71. package/src/Prometheus.res.mjs +124 -171
  72. package/src/PruneStaleHistory.res +2 -2
  73. package/src/PruneStaleHistory.res.mjs +3 -3
  74. package/src/RawEvent.res +7 -2
  75. package/src/RawEvent.res.mjs +4 -4
  76. package/src/Rollback.res +3 -3
  77. package/src/Rollback.res.mjs +4 -4
  78. package/src/RollbackCommit.res +4 -1
  79. package/src/RollbackCommit.res.mjs +3 -2
  80. package/src/SimulateDeadInputTracker.res +85 -0
  81. package/src/SimulateDeadInputTracker.res.mjs +73 -0
  82. package/src/SimulateDeadInputTracker.resi +12 -0
  83. package/src/SimulateItems.res +128 -28
  84. package/src/SimulateItems.res.mjs +82 -40
  85. package/src/TestIndexer.res +55 -41
  86. package/src/TestIndexer.res.mjs +39 -32
  87. package/src/TopicFilter.res +1 -25
  88. package/src/TopicFilter.res.mjs +0 -74
  89. package/src/bindings/Performance.res +7 -0
  90. package/src/bindings/Performance.res.mjs +21 -0
  91. package/src/bindings/Performance.resi +7 -0
  92. package/src/bindings/Viem.res +0 -46
  93. package/src/bindings/Viem.res.mjs +1 -43
  94. package/src/sources/BlockStore.res +46 -0
  95. package/src/sources/BlockStore.res.mjs +24 -0
  96. package/src/sources/EventRouter.res +31 -49
  97. package/src/sources/EventRouter.res.mjs +12 -25
  98. package/src/sources/Evm.res +83 -72
  99. package/src/sources/Evm.res.mjs +53 -69
  100. package/src/sources/EvmChain.res +7 -34
  101. package/src/sources/EvmChain.res.mjs +6 -27
  102. package/src/sources/EvmRpcClient.res +71 -5
  103. package/src/sources/EvmRpcClient.res.mjs +13 -4
  104. package/src/sources/FieldMask.res +39 -0
  105. package/src/sources/FieldMask.res.mjs +42 -0
  106. package/src/sources/Fuel.res +9 -6
  107. package/src/sources/Fuel.res.mjs +5 -10
  108. package/src/sources/HyperFuelSource.res +46 -50
  109. package/src/sources/HyperFuelSource.res.mjs +64 -54
  110. package/src/sources/HyperSync.res +45 -42
  111. package/src/sources/HyperSync.res.mjs +68 -60
  112. package/src/sources/HyperSync.resi +14 -4
  113. package/src/sources/HyperSyncClient.res +107 -119
  114. package/src/sources/HyperSyncClient.res.mjs +36 -31
  115. package/src/sources/HyperSyncHeightStream.res +1 -8
  116. package/src/sources/HyperSyncHeightStream.res.mjs +0 -2
  117. package/src/sources/HyperSyncSource.res +60 -254
  118. package/src/sources/HyperSyncSource.res.mjs +57 -180
  119. package/src/sources/Rpc.res +15 -79
  120. package/src/sources/Rpc.res.mjs +25 -101
  121. package/src/sources/RpcSource.res +221 -514
  122. package/src/sources/RpcSource.res.mjs +216 -411
  123. package/src/sources/RpcWebSocketHeightStream.res +0 -5
  124. package/src/sources/RpcWebSocketHeightStream.res.mjs +0 -2
  125. package/src/sources/SimulateSource.res +44 -20
  126. package/src/sources/SimulateSource.res.mjs +41 -14
  127. package/src/sources/Source.res +34 -6
  128. package/src/sources/SourceManager.res +77 -19
  129. package/src/sources/SourceManager.res.mjs +63 -21
  130. package/src/sources/SourceManager.resi +10 -0
  131. package/src/sources/Svm.res +31 -16
  132. package/src/sources/Svm.res.mjs +36 -13
  133. package/src/sources/SvmHyperSyncClient.res +5 -32
  134. package/src/sources/SvmHyperSyncSource.res +159 -134
  135. package/src/sources/SvmHyperSyncSource.res.mjs +164 -129
  136. package/src/sources/TransactionStore.res +49 -0
  137. package/src/sources/TransactionStore.res.mjs +30 -0
  138. package/src/tui/Tui.res +13 -16
  139. package/src/tui/Tui.res.mjs +12 -14
  140. package/svm.schema.json +49 -37
  141. package/src/bindings/Hrtime.res +0 -58
  142. package/src/bindings/Hrtime.res.mjs +0 -90
  143. package/src/bindings/Hrtime.resi +0 -30
@@ -4,15 +4,14 @@ import * as Time from "../Time.res.mjs";
4
4
  import * as Utils from "../Utils.res.mjs";
5
5
  import * as Source from "./Source.res.mjs";
6
6
  import * as Logging from "../Logging.res.mjs";
7
- import * as Prometheus from "../Prometheus.res.mjs";
8
7
  import * as Stdlib_Int from "@rescript/runtime/lib/es6/Stdlib_Int.js";
8
+ import * as Performance from "../bindings/Performance.res.mjs";
9
9
  import * as Stdlib_JSON from "@rescript/runtime/lib/es6/Stdlib_JSON.js";
10
10
  import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
11
11
  import * as Stdlib_JsExn from "@rescript/runtime/lib/es6/Stdlib_JsExn.js";
12
12
  import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
13
13
  import * as Stdlib_Result from "@rescript/runtime/lib/es6/Stdlib_Result.js";
14
14
  import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
15
- import * as HyperSyncClient from "./HyperSyncClient.res.mjs";
16
15
  import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
17
16
 
18
17
  function reraisIfRateLimited(exn) {
@@ -62,15 +61,6 @@ function mapExn(queryResponse) {
62
61
 
63
62
  let $$Error = /* @__PURE__ */Primitive_exceptions.create("HyperSync.GetLogs.Error");
64
63
 
65
- function makeRequestBody(fromBlock, toBlockInclusive, addressesWithTopics, fieldSelection) {
66
- return {
67
- fromBlock: fromBlock,
68
- toBlock: toBlockInclusive !== undefined ? toBlockInclusive + 1 | 0 : undefined,
69
- logs: addressesWithTopics,
70
- fieldSelection: fieldSelection
71
- };
72
- }
73
-
74
64
  function extractMissingParams(exn) {
75
65
  let message = exn.RE_EXN_ID === "JsExn" ? Stdlib_JsExn.message(exn._1) : undefined;
76
66
  if (message === undefined) {
@@ -92,18 +82,17 @@ function extractMissingParams(exn) {
92
82
  }
93
83
  }
94
84
 
95
- async function query(client, fromBlock, toBlock, logSelections, fieldSelection) {
96
- let addressesWithTopics = logSelections.flatMap(param => {
97
- let addresses = param.addresses;
98
- return param.topicSelections.map(param => {
99
- let topics = HyperSyncClient.QueryTypes.makeTopicSelection(param.topic0, param.topic1, param.topic2, param.topic3);
100
- return HyperSyncClient.QueryTypes.makeLogSelection(addresses, topics);
101
- });
102
- });
103
- let query$1 = makeRequestBody(fromBlock, toBlock, addressesWithTopics, fieldSelection);
104
- let res;
85
+ async function query(client, fromBlock, toBlock, maxNumLogs, registrationIndexes, addressesByContractName) {
86
+ let query$1 = {
87
+ fromBlock: fromBlock,
88
+ toBlock: toBlock,
89
+ maxNumLogs: maxNumLogs,
90
+ registrationIndexes: registrationIndexes,
91
+ addressesByContractName: addressesByContractName
92
+ };
93
+ let match;
105
94
  try {
106
- res = await client.getEventItems(query$1);
95
+ match = await client.getEventItems(query$1);
107
96
  } catch (raw_exn) {
108
97
  let exn = Primitive_exceptions.internalToException(raw_exn);
109
98
  reraisIfRateLimited(exn);
@@ -120,6 +109,7 @@ async function query(client, fromBlock, toBlock, logSelections, fieldSelection)
120
109
  }
121
110
  throw exn;
122
111
  }
112
+ let res = match[0];
123
113
  if (res.nextBlock <= fromBlock) {
124
114
  throw {
125
115
  RE_EXN_ID: $$Error,
@@ -129,13 +119,22 @@ async function query(client, fromBlock, toBlock, logSelections, fieldSelection)
129
119
  }
130
120
  return {
131
121
  items: res.items,
122
+ blocks: res.blocks,
132
123
  nextBlock: res.nextBlock,
133
124
  archiveHeight: Stdlib_Option.getOr(res.archiveHeight, 0),
134
- rollbackGuard: res.rollbackGuard
125
+ rollbackGuard: res.rollbackGuard,
126
+ transactionStore: match[1],
127
+ blockStore: match[2]
135
128
  };
136
129
  }
137
130
 
138
- function makeRequestBody$1(fromBlock, toBlock) {
131
+ let GetLogs = {
132
+ $$Error: $$Error,
133
+ extractMissingParams: extractMissingParams,
134
+ query: query
135
+ };
136
+
137
+ function makeRequestBody(fromBlock, toBlock) {
139
138
  return {
140
139
  fromBlock: fromBlock,
141
140
  toBlock: toBlock + 1 | 0,
@@ -187,14 +186,14 @@ function convertResponse(res) {
187
186
  }));
188
187
  }
189
188
 
190
- async function queryBlockData(client, fromBlock, toBlock, sourceName, chainId, logger) {
191
- let body = makeRequestBody$1(fromBlock, toBlock);
189
+ async function queryBlockData(client, fromBlock, toBlock, sourceName, chainId, logger, requestStats) {
190
+ let body = makeRequestBody(fromBlock, toBlock);
192
191
  let logger$1 = Logging.createChildFrom(logger, {
193
192
  logType: "HyperSync get block hash query",
194
193
  fromBlock: fromBlock,
195
194
  toBlock: toBlock
196
195
  });
197
- Prometheus.SourceRequestCount.increment(sourceName, chainId, "getBlockHashes");
196
+ let timerRef = Performance.now();
198
197
  let maybeSuccessfulRes;
199
198
  let exit = 0;
200
199
  let res;
@@ -209,6 +208,10 @@ async function queryBlockData(client, fromBlock, toBlock, sourceName, chainId, l
209
208
  if (exit === 1) {
210
209
  maybeSuccessfulRes = res.nextBlock <= fromBlock ? undefined : res;
211
210
  }
211
+ requestStats.push({
212
+ method: "getBlockHashes",
213
+ seconds: Performance.secondsSince(timerRef)
214
+ });
212
215
  if (maybeSuccessfulRes !== undefined) {
213
216
  let err = convertResponse(maybeSuccessfulRes);
214
217
  if (err.TAG !== "Ok") {
@@ -218,56 +221,61 @@ async function queryBlockData(client, fromBlock, toBlock, sourceName, chainId, l
218
221
  return err;
219
222
  }
220
223
  let datas = err._0;
221
- let restRes = await queryBlockData(client, maybeSuccessfulRes.nextBlock, toBlock, sourceName, chainId, logger$1);
224
+ let restRes = await queryBlockData(client, maybeSuccessfulRes.nextBlock, toBlock, sourceName, chainId, logger$1, requestStats);
222
225
  return Stdlib_Result.map(restRes, rest => datas.concat(rest));
223
226
  }
224
227
  Logging.childInfo(logger$1, `Block #` + fromBlock.toString() + ` not found in HyperSync. HyperSync has multiple instances and it's possible that they drift independently slightly from the head. Indexing should continue correctly after retrying the query in ` + (100).toString() + `ms.`);
225
228
  await Time.resolvePromiseAfterDelay(100);
226
- return await queryBlockData(client, fromBlock, toBlock, sourceName, chainId, logger$1);
229
+ return await queryBlockData(client, fromBlock, toBlock, sourceName, chainId, logger$1, requestStats);
227
230
  }
228
231
 
229
232
  async function queryBlockDataMulti(client, blockNumbers, sourceName, chainId, logger) {
233
+ let requestStats = [];
230
234
  let firstBlock = blockNumbers[0];
231
- if (firstBlock === undefined) {
232
- return {
235
+ let result;
236
+ if (firstBlock !== undefined) {
237
+ let fromBlock = firstBlock;
238
+ let toBlock = firstBlock;
239
+ let set = new Set();
240
+ for (let idx = 0, idx_finish = blockNumbers.length; idx < idx_finish; ++idx) {
241
+ let blockNumber = blockNumbers[idx];
242
+ if (blockNumber < fromBlock) {
243
+ fromBlock = blockNumber;
244
+ }
245
+ if (blockNumber > toBlock) {
246
+ toBlock = blockNumber;
247
+ }
248
+ set.add(blockNumber);
249
+ }
250
+ if ((toBlock - fromBlock | 0) > 1000) {
251
+ Stdlib_JsError.throwWithMessage(`Invalid block data request. Range of block numbers is too large. Max range is 1000. Requested range: ` + fromBlock.toString() + `-` + toBlock.toString());
252
+ }
253
+ let res = await queryBlockData(client, fromBlock, toBlock, sourceName, chainId, logger, requestStats);
254
+ let filtered = Stdlib_Result.map(res, datas => datas.filter(data => set.delete(data.blockNumber)));
255
+ if (set.size > 0) {
256
+ Stdlib_JsError.throwWithMessage(`Invalid response. Failed to get block data for block numbers: ` + Array.from(set).join(", "));
257
+ }
258
+ result = filtered;
259
+ } else {
260
+ result = {
233
261
  TAG: "Ok",
234
262
  _0: []
235
263
  };
236
264
  }
237
- let fromBlock = firstBlock;
238
- let toBlock = firstBlock;
239
- let set = new Set();
240
- for (let idx = 0, idx_finish = blockNumbers.length; idx < idx_finish; ++idx) {
241
- let blockNumber = blockNumbers[idx];
242
- if (blockNumber < fromBlock) {
243
- fromBlock = blockNumber;
244
- }
245
- if (blockNumber > toBlock) {
246
- toBlock = blockNumber;
247
- }
248
- set.add(blockNumber);
249
- }
250
- if ((toBlock - fromBlock | 0) > 1000) {
251
- Stdlib_JsError.throwWithMessage(`Invalid block data request. Range of block numbers is too large. Max range is 1000. Requested range: ` + fromBlock.toString() + `-` + toBlock.toString());
252
- }
253
- let res = await queryBlockData(client, fromBlock, toBlock, sourceName, chainId, logger);
254
- let filtered = Stdlib_Result.map(res, datas => datas.filter(data => set.delete(data.blockNumber)));
255
- if (set.size > 0) {
256
- Stdlib_JsError.throwWithMessage(`Invalid response. Failed to get block data for block numbers: ` + Array.from(set).join(", "));
257
- }
258
- return filtered;
265
+ return [
266
+ result,
267
+ requestStats
268
+ ];
259
269
  }
260
270
 
261
271
  function queryBlockData$1(client, blockNumber, sourceName, chainId, logger) {
262
- return queryBlockData(client, blockNumber, blockNumber, sourceName, chainId, logger).then(res => Stdlib_Result.map(res, res => res[0]));
272
+ let requestStats = [];
273
+ return queryBlockData(client, blockNumber, blockNumber, sourceName, chainId, logger, requestStats).then(res => [
274
+ Stdlib_Result.map(res, res => res[0]),
275
+ requestStats
276
+ ]);
263
277
  }
264
278
 
265
- let GetLogs = {
266
- $$Error: $$Error,
267
- extractMissingParams: extractMissingParams,
268
- query: query
269
- };
270
-
271
279
  export {
272
280
  queryErrorToMsq,
273
281
  GetLogs,
@@ -1,8 +1,11 @@
1
1
  type logsQueryPage = {
2
2
  items: array<HyperSyncClient.EventItems.item>,
3
+ blocks: array<HyperSyncClient.EventItems.blockHeader>,
3
4
  nextBlock: int,
4
5
  archiveHeight: int,
5
6
  rollbackGuard: option<HyperSyncClient.ResponseTypes.rollbackGuard>,
7
+ transactionStore: TransactionStore.t,
8
+ blockStore: BlockStore.t,
6
9
  }
7
10
 
8
11
  type missingParams = {
@@ -29,8 +32,9 @@ module GetLogs: {
29
32
  ~client: HyperSyncClient.t,
30
33
  ~fromBlock: int,
31
34
  ~toBlock: option<int>,
32
- ~logSelections: array<LogSelection.t>,
33
- ~fieldSelection: HyperSyncClient.QueryTypes.fieldSelection,
35
+ ~maxNumLogs: int,
36
+ ~registrationIndexes: array<int>,
37
+ ~addressesByContractName: dict<array<Address.t>>,
34
38
  ) => promise<logsQueryPage>
35
39
  }
36
40
 
@@ -40,7 +44,10 @@ let queryBlockData: (
40
44
  ~sourceName: string,
41
45
  ~chainId: int,
42
46
  ~logger: Pino.t,
43
- ) => promise<queryResponse<option<ReorgDetection.blockDataWithTimestamp>>>
47
+ ) => promise<(
48
+ queryResponse<option<ReorgDetection.blockDataWithTimestamp>>,
49
+ array<Source.requestStat>,
50
+ )>
44
51
 
45
52
  let queryBlockDataMulti: (
46
53
  ~client: HyperSyncClient.t,
@@ -48,6 +55,9 @@ let queryBlockDataMulti: (
48
55
  ~sourceName: string,
49
56
  ~chainId: int,
50
57
  ~logger: Pino.t,
51
- ) => promise<queryResponse<array<ReorgDetection.blockDataWithTimestamp>>>
58
+ ) => promise<(
59
+ queryResponse<array<ReorgDetection.blockDataWithTimestamp>>,
60
+ array<Source.requestStat>,
61
+ )>
52
62
 
53
63
  let mapExn: queryResponse<'a> => result<'a, exn>
@@ -208,90 +208,6 @@ module ResponseTypes = {
208
208
  mixHash?: string,
209
209
  }
210
210
 
211
- type accessList = {
212
- address?: Address.t,
213
- storageKeys?: array<string>,
214
- }
215
-
216
- let accessListSchema = S.object(s => {
217
- address: ?s.field("address", S.option(Address.schema)),
218
- storageKeys: ?s.field("storageKeys", S.option(S.array(S.string))),
219
- })
220
-
221
- type authorizationList = {
222
- chainId: bigint,
223
- address: Address.t,
224
- nonce: int,
225
- yParity: [#0 | #1],
226
- r: string,
227
- s: string,
228
- }
229
-
230
- let authorizationListSchema = S.object(s => {
231
- chainId: s.field("chainId", S.bigint),
232
- address: s.field("address", Address.schema),
233
- nonce: s.field("nonce", S.int),
234
- yParity: s.field("yParity", S.enum([#0, #1])),
235
- r: s.field("r", S.string),
236
- s: s.field("s", S.string),
237
- })
238
-
239
- type transaction = {
240
- blockHash?: string,
241
- blockNumber?: int,
242
- from?: string,
243
- gas?: bigint,
244
- gasPrice?: bigint,
245
- hash?: string,
246
- input?: string,
247
- nonce?: bigint,
248
- to?: string,
249
- transactionIndex?: int,
250
- value?: bigint,
251
- v?: string,
252
- r?: string,
253
- s?: string,
254
- yParity?: string,
255
- maxPriorityFeePerGas?: bigint,
256
- maxFeePerGas?: bigint,
257
- chainId?: int,
258
- accessList?: array<accessList>,
259
- maxFeePerBlobGas?: bigint,
260
- blobVersionedHashes?: array<string>,
261
- cumulativeGasUsed?: bigint,
262
- effectiveGasPrice?: bigint,
263
- gasUsed?: bigint,
264
- contractAddress?: string,
265
- logsBloom?: string,
266
- @as("type") type_?: int,
267
- root?: string,
268
- status?: int,
269
- l1Fee?: bigint,
270
- l1GasPrice?: bigint,
271
- l1GasUsed?: bigint,
272
- l1FeeScalar?: float,
273
- gasUsedForL1?: bigint,
274
- authorizationList?: array<authorizationList>,
275
- }
276
-
277
- type log = {
278
- removed?: bool,
279
- @as("logIndex") index?: int,
280
- transactionIndex?: int,
281
- transactionHash?: string,
282
- blockHash?: string,
283
- blockNumber?: int,
284
- address?: Address.t,
285
- data?: string,
286
- topics?: array<Nullable.t<EvmTypes.Hex.t>>,
287
- }
288
-
289
- type event = {
290
- transaction?: transaction,
291
- block?: block,
292
- log: log,
293
- }
294
-
295
211
  type rollbackGuard = {
296
212
  blockNumber: int,
297
213
  timestamp: int,
@@ -303,11 +219,7 @@ module ResponseTypes = {
303
219
 
304
220
  type query = QueryTypes.query
305
221
 
306
- type queryResponseData = {
307
- blocks: array<ResponseTypes.block>,
308
- transactions: array<ResponseTypes.transaction>,
309
- logs: array<ResponseTypes.log>,
310
- }
222
+ type queryResponseData = {blocks: array<ResponseTypes.block>}
311
223
 
312
224
  type queryResponse = {
313
225
  archiveHeight: option<int>,
@@ -317,49 +229,121 @@ type queryResponse = {
317
229
  rollbackGuard: option<ResponseTypes.rollbackGuard>,
318
230
  }
319
231
 
320
- module Decoder = {
321
- type eventParamsInput = {
232
+ module Registration = {
233
+ // One topic position of the resolved `where`: static topic values, or
234
+ // `None` — the "currently registered addresses of this contract" marker,
235
+ // expanded to padded address topics when Rust builds a query.
236
+ type topicFilterInput = option<array<string>>
237
+
238
+ type topicSelectionInput = {
239
+ topic0: array<string>,
240
+ topic1: topicFilterInput,
241
+ topic2: topicFilterInput,
242
+ topic3: topicFilterInput,
243
+ }
244
+
245
+ // The full per-(event, chain) registration passed to the Rust clients at
246
+ // construction: decode metadata, routing identity, and the fetch state
247
+ // queries are built from.
248
+ type input = {
249
+ // Chain-scoped sequential registration index, echoed back on routed items.
250
+ index: int,
322
251
  sighash: string,
323
252
  topicCount: int,
324
253
  eventName: string,
325
254
  contractName: string,
255
+ isWildcard: bool,
256
+ dependsOnAddresses: bool,
326
257
  params: array<Internal.paramMeta>,
258
+ topicSelections: array<topicSelectionInput>,
259
+ // Capitalized field names matching the Rust BlockField/TransactionField
260
+ // string enums.
261
+ blockFields: array<string>,
262
+ transactionFields: array<string>,
327
263
  }
328
264
 
329
- // Decoded params keyed by contract name. Contracts that emit the same-signature
330
- // event share one decode but get their own param names, so the caller picks the
331
- // entry for the contract its router resolved the log to.
332
- type tWithParams = {
333
- decodeLogs: array<ResponseTypes.event> => promise<
334
- array<Nullable.t<dict<Internal.eventParams>>>,
335
- >,
265
+ let toTopicFilterInput = (filter: Internal.topicFilter): topicFilterInput =>
266
+ switch filter {
267
+ | Values(values) => Some(values->EvmTypes.Hex.toStrings)
268
+ | ContractAddresses(_) => None
269
+ }
270
+
271
+ let fromOnEventRegistrations = (
272
+ onEventRegistrations: array<Internal.evmOnEventRegistration>,
273
+ ): array<input> => {
274
+ onEventRegistrations->Array.map(reg => {
275
+ let event = reg.eventConfig->(Utils.magic: Internal.eventConfig => Internal.evmEventConfig)
276
+ {
277
+ index: reg.index,
278
+ sighash: event.sighash,
279
+ topicCount: event.topicCount,
280
+ eventName: event.name,
281
+ contractName: event.contractName,
282
+ isWildcard: reg.isWildcard,
283
+ dependsOnAddresses: reg.dependsOnAddresses,
284
+ params: event.paramsMetadata,
285
+ topicSelections: reg.resolvedWhere.topicSelections->Array.map((
286
+ ts
287
+ ): topicSelectionInput => {
288
+ topic0: ts.topic0->EvmTypes.Hex.toStrings,
289
+ topic1: ts.topic1->toTopicFilterInput,
290
+ topic2: ts.topic2->toTopicFilterInput,
291
+ topic3: ts.topic3->toTopicFilterInput,
292
+ }),
293
+ // Capitalized to match the Rust BlockField/TransactionField string
294
+ // enums.
295
+ blockFields: event.selectedBlockFields
296
+ ->Utils.Set.toArray
297
+ ->Array.map(name => (name :> string)->Utils.String.capitalize),
298
+ transactionFields: event.selectedTransactionFields
299
+ ->Utils.Set.toArray
300
+ ->Array.map(name => (name :> string)->Utils.String.capitalize),
301
+ }
302
+ })
336
303
  }
337
-
338
- @send
339
- external classFromParams: (
340
- Core.evmDecoderCtor,
341
- array<eventParamsInput>,
342
- ~checksumAddresses: bool=?,
343
- ) => tWithParams = "fromParams"
344
-
345
- let fromParams = (eventParams, ~checksumAddresses=?) =>
346
- Core.getAddon().evmDecoder->classFromParams(eventParams, ~checksumAddresses?)
347
304
  }
348
305
 
349
306
  module EventItems = {
307
+ // The whole per-query input: block range, the partition's registration
308
+ // selection (by id), and its current addresses. Log selections, field
309
+ // selection, and the routing index are derived on the Rust side.
310
+ type query = {
311
+ fromBlock: int,
312
+ // Inclusive; None queries to the end of available data.
313
+ toBlock: option<int>,
314
+ maxNumLogs: int,
315
+ registrationIndexes: array<int>,
316
+ addressesByContractName: dict<array<Address.t>>,
317
+ }
318
+
350
319
  type item = {
351
320
  logIndex: int,
352
321
  srcAddress: Address.t,
353
- topic0: EvmTypes.Hex.t,
354
- topicCount: int,
355
- block: ResponseTypes.block,
356
- transaction: ResponseTypes.transaction,
357
- params: Nullable.t<dict<Internal.eventParams>>,
322
+ // Number of the block this log belongs to; the block itself is resolved from
323
+ // `response.blocks`, deduplicated across items sharing a block.
324
+ blockNumber: int,
325
+ // Key (with the block number) into the transaction store; the transaction
326
+ // is resolved from the store on demand.
327
+ transactionIndex: int,
328
+ // The registration this log routed to, by chain-scoped index. Logs that
329
+ // route to no registration never cross the boundary.
330
+ onEventRegistrationIndex: int,
331
+ params: Internal.eventParams,
332
+ }
333
+
334
+ // The always-needed block fields, one per block number. The block's remaining
335
+ // fields live raw in the block store and are materialised on demand.
336
+ type blockHeader = {
337
+ number: int,
338
+ timestamp: int,
339
+ hash: string,
358
340
  }
359
341
 
360
342
  type response = {
361
343
  archiveHeight: option<int>,
362
344
  nextBlock: int,
345
+ // One header per block number referenced by `items`.
346
+ blocks: array<blockHeader>,
363
347
  items: array<item>,
364
348
  rollbackGuard: option<ResponseTypes.rollbackGuard>,
365
349
  }
@@ -367,7 +351,11 @@ module EventItems = {
367
351
 
368
352
  type t = {
369
353
  get: (~query: query) => promise<queryResponse>,
370
- getEventItems: (~query: query) => promise<EventItems.response>,
354
+ // Returns the response plus page stores owning this page's raw transactions
355
+ // and blocks.
356
+ getEventItems: (
357
+ ~query: EventItems.query,
358
+ ) => promise<(EventItems.response, TransactionStore.t, BlockStore.t)>,
371
359
  getHeight: unit => promise<int>,
372
360
  }
373
361
 
@@ -376,11 +364,11 @@ external classNew: (
376
364
  Core.evmHypersyncClientCtor,
377
365
  cfg,
378
366
  string,
379
- array<Decoder.eventParamsInput>,
367
+ array<Registration.input>,
380
368
  ) => t = "new"
381
369
 
382
- let makeWithAgent = (cfg, ~userAgent, ~eventParams) =>
383
- Core.getAddon().evmHypersyncClient->classNew(cfg, userAgent, eventParams)
370
+ let makeWithAgent = (cfg, ~userAgent, ~eventRegistrations) =>
371
+ Core.getAddon().evmHypersyncClient->classNew(cfg, userAgent, eventRegistrations)
384
372
 
385
373
  type logLevel = [#trace | #debug | #info | #warn | #error]
386
374
  let logLevelSchema: S.t<logLevel> = S.enum([#trace, #debug, #info, #warn, #error])
@@ -398,7 +386,7 @@ let make = (
398
386
  ~url,
399
387
  ~apiToken,
400
388
  ~httpReqTimeoutMillis,
401
- ~eventParams,
389
+ ~eventRegistrations,
402
390
  ~enableChecksumAddresses=true,
403
391
  ~serializationFormat=?,
404
392
  ~enableQueryCaching=?,
@@ -424,6 +412,6 @@ let make = (
424
412
  logLevel: logLevelToString(logLevel),
425
413
  },
426
414
  ~userAgent=`hyperindex/${envioVersion}`,
427
- ~eventParams,
415
+ ~eventRegistrations,
428
416
  )
429
417
  }
@@ -2,8 +2,6 @@
2
2
 
3
3
  import * as Core from "../Core.res.mjs";
4
4
  import * as Utils from "../Utils.res.mjs";
5
- import * as Address from "../Address.res.mjs";
6
- import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
7
5
  import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
8
6
 
9
7
  let serializationFormatSchema = S$RescriptSchema.$$enum([
@@ -36,40 +34,47 @@ let QueryTypes = {
36
34
  makeLogSelection: makeLogSelection
37
35
  };
38
36
 
39
- let accessListSchema = S$RescriptSchema.object(s => ({
40
- address: s.f("address", S$RescriptSchema.option(Address.schema)),
41
- storageKeys: s.f("storageKeys", S$RescriptSchema.option(S$RescriptSchema.array(S$RescriptSchema.string)))
42
- }));
37
+ let ResponseTypes = {};
43
38
 
44
- let authorizationListSchema = S$RescriptSchema.object(s => ({
45
- chainId: s.f("chainId", S$RescriptSchema.bigint),
46
- address: s.f("address", Address.schema),
47
- nonce: s.f("nonce", S$RescriptSchema.int),
48
- yParity: s.f("yParity", S$RescriptSchema.$$enum([
49
- 0,
50
- 1
51
- ])),
52
- r: s.f("r", S$RescriptSchema.string),
53
- s: s.f("s", S$RescriptSchema.string)
54
- }));
55
-
56
- let ResponseTypes = {
57
- accessListSchema: accessListSchema,
58
- authorizationListSchema: authorizationListSchema
59
- };
39
+ function toTopicFilterInput(filter) {
40
+ if (filter.TAG === "Values") {
41
+ return filter._0;
42
+ }
43
+ }
60
44
 
61
- function fromParams(eventParams, checksumAddresses) {
62
- return Core.getAddon().EvmDecoder.fromParams(eventParams, checksumAddresses !== undefined ? Primitive_option.valFromOption(checksumAddresses) : undefined);
45
+ function fromOnEventRegistrations(onEventRegistrations) {
46
+ return onEventRegistrations.map(reg => {
47
+ let event = reg.eventConfig;
48
+ return {
49
+ index: reg.index,
50
+ sighash: event.sighash,
51
+ topicCount: event.topicCount,
52
+ eventName: event.name,
53
+ contractName: event.contractName,
54
+ isWildcard: reg.isWildcard,
55
+ dependsOnAddresses: reg.dependsOnAddresses,
56
+ params: event.paramsMetadata,
57
+ topicSelections: reg.resolvedWhere.topicSelections.map(ts => ({
58
+ topic0: ts.topic0,
59
+ topic1: toTopicFilterInput(ts.topic1),
60
+ topic2: toTopicFilterInput(ts.topic2),
61
+ topic3: toTopicFilterInput(ts.topic3)
62
+ })),
63
+ blockFields: Array.from(event.selectedBlockFields).map(name => Utils.$$String.capitalize(name)),
64
+ transactionFields: Array.from(event.selectedTransactionFields).map(name => Utils.$$String.capitalize(name))
65
+ };
66
+ });
63
67
  }
64
68
 
65
- let Decoder = {
66
- fromParams: fromParams
69
+ let Registration = {
70
+ toTopicFilterInput: toTopicFilterInput,
71
+ fromOnEventRegistrations: fromOnEventRegistrations
67
72
  };
68
73
 
69
74
  let EventItems = {};
70
75
 
71
- function makeWithAgent(cfg, userAgent, eventParams) {
72
- return Core.getAddon().EvmHypersyncClient.new(cfg, userAgent, eventParams);
76
+ function makeWithAgent(cfg, userAgent, eventRegistrations) {
77
+ return Core.getAddon().EvmHypersyncClient.new(cfg, userAgent, eventRegistrations);
73
78
  }
74
79
 
75
80
  let logLevelSchema = S$RescriptSchema.$$enum([
@@ -94,7 +99,7 @@ function logLevelToString(level) {
94
99
  }
95
100
  }
96
101
 
97
- function make(url, apiToken, httpReqTimeoutMillis, eventParams, enableChecksumAddressesOpt, serializationFormat, enableQueryCaching, retryBaseMs, retryBackoffMs, retryCeilingMs, logLevelOpt) {
102
+ function make(url, apiToken, httpReqTimeoutMillis, eventRegistrations, enableChecksumAddressesOpt, serializationFormat, enableQueryCaching, retryBaseMs, retryBackoffMs, retryCeilingMs, logLevelOpt) {
98
103
  let enableChecksumAddresses = enableChecksumAddressesOpt !== undefined ? enableChecksumAddressesOpt : true;
99
104
  let logLevel = logLevelOpt !== undefined ? logLevelOpt : "info";
100
105
  let envioVersion = Utils.EnvioPackage.value.version;
@@ -110,14 +115,14 @@ function make(url, apiToken, httpReqTimeoutMillis, eventParams, enableChecksumAd
110
115
  serializationFormat: serializationFormat,
111
116
  enableQueryCaching: enableQueryCaching,
112
117
  logLevel: logLevelToString(logLevel)
113
- }, `hyperindex/` + envioVersion, eventParams);
118
+ }, `hyperindex/` + envioVersion, eventRegistrations);
114
119
  }
115
120
 
116
121
  export {
117
122
  serializationFormatSchema,
118
123
  QueryTypes,
119
124
  ResponseTypes,
120
- Decoder,
125
+ Registration,
121
126
  EventItems,
122
127
  makeWithAgent,
123
128
  logLevelSchema,
@@ -35,8 +35,7 @@ let subscribe = (~hyperSyncUrl, ~apiToken, ~chainId, ~onHeight: int => unit): (u
35
35
  and scheduleReconnect = () => {
36
36
  // Clear any pending stale/reconnect timeout to avoid double reconnect
37
37
  timeoutIdRef.contents->clearTimeout
38
- let delay =
39
- baseDuration * Math.pow(2.0, ~exp=errorCount.contents->Int.toFloat)->Float.toInt
38
+ let delay = baseDuration * Math.pow(2.0, ~exp=errorCount.contents->Int.toFloat)->Float.toInt
40
39
  timeoutIdRef := setTimeout(() => refreshEventSource(), Pervasives.min(delay, 60_000))
41
40
  }
42
41
  and refreshEventSource = () => {
@@ -102,12 +101,6 @@ let subscribe = (~hyperSyncUrl, ~apiToken, ~chainId, ~onHeight: int => unit): (u
102
101
  es->EventSource.addEventListener("height", event => {
103
102
  switch event.data->Int.fromString {
104
103
  | Some(height) =>
105
- // Track the SSE height event
106
- Prometheus.SourceRequestCount.increment(
107
- ~sourceName="HyperSync",
108
- ~chainId,
109
- ~method="heightStream",
110
- )
111
104
  // On a successful height event, update the timeout
112
105
  updateTimeoutId()
113
106
  // Call the callback with the new height