envio 3.3.0-alpha.8 → 3.3.0-rc.0

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 (107) hide show
  1. package/index.d.ts +19 -0
  2. package/licenses/CLA.md +35 -0
  3. package/licenses/EULA.md +67 -0
  4. package/licenses/LICENSE.md +45 -0
  5. package/licenses/README.md +35 -0
  6. package/package.json +9 -8
  7. package/src/Batch.res.mjs +1 -1
  8. package/src/BatchProcessing.res +0 -7
  9. package/src/BatchProcessing.res.mjs +1 -8
  10. package/src/ChainFetching.res +30 -18
  11. package/src/ChainFetching.res.mjs +23 -13
  12. package/src/ChainState.res +205 -59
  13. package/src/ChainState.res.mjs +130 -27
  14. package/src/ChainState.resi +16 -1
  15. package/src/Config.res +9 -5
  16. package/src/Config.res.mjs +2 -2
  17. package/src/Core.res +20 -0
  18. package/src/Core.res.mjs +12 -0
  19. package/src/CrossChainState.res +147 -39
  20. package/src/CrossChainState.res.mjs +42 -10
  21. package/src/EffectState.res +100 -0
  22. package/src/EffectState.res.mjs +74 -0
  23. package/src/EffectState.resi +32 -0
  24. package/src/Envio.res +25 -7
  25. package/src/Envio.res.mjs +15 -19
  26. package/src/EnvioGlobal.res +53 -0
  27. package/src/EnvioGlobal.res.mjs +31 -0
  28. package/src/EventConfigBuilder.res +30 -56
  29. package/src/EventConfigBuilder.res.mjs +24 -30
  30. package/src/EventProcessing.res +8 -5
  31. package/src/EventProcessing.res.mjs +2 -1
  32. package/src/FetchState.res +842 -474
  33. package/src/FetchState.res.mjs +545 -356
  34. package/src/HandlerLoader.res +1 -1
  35. package/src/HandlerLoader.res.mjs +1 -1
  36. package/src/HandlerRegister.res +478 -305
  37. package/src/HandlerRegister.res.mjs +277 -209
  38. package/src/HandlerRegister.resi +11 -6
  39. package/src/InMemoryStore.res +14 -26
  40. package/src/InMemoryStore.res.mjs +6 -19
  41. package/src/IndexerState.res +15 -39
  42. package/src/IndexerState.res.mjs +18 -29
  43. package/src/IndexerState.resi +2 -10
  44. package/src/Internal.res +121 -18
  45. package/src/Internal.res.mjs +96 -2
  46. package/src/LoadLayer.res +44 -24
  47. package/src/LoadLayer.res.mjs +43 -20
  48. package/src/LoadLayer.resi +1 -0
  49. package/src/LogSelection.res +92 -217
  50. package/src/LogSelection.res.mjs +95 -184
  51. package/src/Main.res +29 -143
  52. package/src/Main.res.mjs +25 -88
  53. package/src/Metrics.res +1 -1
  54. package/src/Metrics.res.mjs +1 -1
  55. package/src/Persistence.res +12 -3
  56. package/src/PgStorage.res +155 -82
  57. package/src/PgStorage.res.mjs +130 -77
  58. package/src/Prometheus.res +20 -10
  59. package/src/Prometheus.res.mjs +22 -10
  60. package/src/PruneStaleHistory.res +146 -35
  61. package/src/PruneStaleHistory.res.mjs +114 -20
  62. package/src/RawEvent.res +2 -2
  63. package/src/Rollback.res +32 -13
  64. package/src/Rollback.res.mjs +24 -11
  65. package/src/RollbackCommit.res +4 -1
  66. package/src/RollbackCommit.res.mjs +3 -2
  67. package/src/SimulateDeadInputTracker.res +1 -1
  68. package/src/SimulateItems.res +39 -7
  69. package/src/SimulateItems.res.mjs +28 -9
  70. package/src/TestIndexer.res +2 -2
  71. package/src/TestIndexer.res.mjs +2 -2
  72. package/src/TopicFilter.res +1 -25
  73. package/src/TopicFilter.res.mjs +0 -74
  74. package/src/UserContext.res +62 -23
  75. package/src/UserContext.res.mjs +26 -6
  76. package/src/Writing.res +60 -21
  77. package/src/Writing.res.mjs +27 -9
  78. package/src/bindings/NodeJs.res +5 -0
  79. package/src/bindings/Viem.res +0 -5
  80. package/src/sources/EventRouter.res +0 -21
  81. package/src/sources/EventRouter.res.mjs +0 -12
  82. package/src/sources/Evm.res +4 -1
  83. package/src/sources/Evm.res.mjs +1 -1
  84. package/src/sources/EvmChain.res +2 -27
  85. package/src/sources/EvmChain.res.mjs +2 -23
  86. package/src/sources/EvmRpcClient.res +58 -23
  87. package/src/sources/EvmRpcClient.res.mjs +11 -5
  88. package/src/sources/Fuel.res +3 -1
  89. package/src/sources/Fuel.res.mjs +1 -1
  90. package/src/sources/HyperSync.res +9 -38
  91. package/src/sources/HyperSync.res.mjs +16 -28
  92. package/src/sources/HyperSync.resi +2 -2
  93. package/src/sources/HyperSyncClient.res +88 -11
  94. package/src/sources/HyperSyncClient.res.mjs +39 -6
  95. package/src/sources/HyperSyncSource.res +18 -210
  96. package/src/sources/HyperSyncSource.res.mjs +9 -137
  97. package/src/sources/Rpc.res +0 -32
  98. package/src/sources/Rpc.res.mjs +1 -46
  99. package/src/sources/RpcSource.res +129 -533
  100. package/src/sources/RpcSource.res.mjs +161 -379
  101. package/src/sources/SimulateSource.res +37 -19
  102. package/src/sources/SimulateSource.res.mjs +27 -10
  103. package/src/sources/SourceManager.res +4 -14
  104. package/src/sources/SourceManager.res.mjs +3 -9
  105. package/src/sources/SourceManager.resi +0 -2
  106. package/src/sources/SvmHyperSyncSource.res +13 -3
  107. package/src/sources/SvmHyperSyncSource.res.mjs +1 -1
@@ -1,32 +1,51 @@
1
- type cfg = {url: string, httpReqTimeoutMillis?: int, headers?: dict<string>}
2
-
3
- // `addresses` omitted matches any address (a wildcard selection). Each `topics`
4
- // position is `null` (match any) or a list of accepted topic hashes; the
5
- // single-match case is a one-element list.
6
- type getLogsParams = {
7
- fromBlock: int,
8
- toBlock: int,
9
- addresses?: array<Address.t>,
10
- topics: array<Nullable.t<array<string>>>,
1
+ type cfg = {
2
+ url: string,
3
+ httpReqTimeoutMillis?: int,
4
+ headers?: dict<string>,
5
+ initialBlockInterval: int,
6
+ backoffMultiplicative: float,
7
+ accelerationAdditive: int,
8
+ intervalCeiling: int,
9
+ backoffMillis: int,
10
+ queryTimeoutMillis: int,
11
11
  }
12
12
 
13
- // Decoded `params` keyed by contract name, matching the HyperSync decoder's
14
- // shape so the caller routes by address then picks its contract's params.
13
+ // Only logs that resolved to a registration cross the boundary, each carrying
14
+ // its registration's chain-scoped index.
15
15
  type rpcEventItem = {
16
16
  log: Rpc.GetLogs.log,
17
- params: Nullable.t<dict<Internal.eventParams>>,
17
+ onEventRegistrationIndex: int,
18
+ params: Internal.eventParams,
19
+ }
20
+
21
+ type nextPageParams = {
22
+ fromBlock: int,
23
+ toBlockCeiling: int,
24
+ partitionId: string,
25
+ // The partition's registration selection, by chain-scoped index. Log
26
+ // selections and the routing index are derived on the Rust side from the
27
+ // registrations passed at construction.
28
+ registrationIndexes: array<int>,
29
+ addressesByContractName: dict<array<Address.t>>,
30
+ }
31
+
32
+ type nextPageResponse = {
33
+ items: array<rpcEventItem>,
34
+ toBlock: int,
35
+ requestStats: array<Source.requestStat>,
18
36
  }
19
37
 
38
+ // The caller provides a range; Rust decides the actual `toBlock` and returns it.
20
39
  type t = {
21
40
  getHeight: unit => promise<int>,
22
- getLogs: getLogsParams => promise<array<rpcEventItem>>,
41
+ getNextPage: nextPageParams => promise<nextPageResponse>,
23
42
  }
24
43
 
25
44
  @send
26
45
  external classNew: (
27
46
  Core.evmRpcClientCtor,
28
47
  cfg,
29
- array<HyperSyncClient.Decoder.eventParamsInput>,
48
+ array<HyperSyncClient.Registration.input>,
30
49
  ~checksumAddresses: bool,
31
50
  ) => t = "new"
32
51
 
@@ -59,15 +78,31 @@ let coerceErrorOrThrow = exn =>
59
78
  | None => exn->throw
60
79
  }
61
80
 
62
- let make = (~url, ~checksumAddresses, ~httpReqTimeoutMillis=?, ~headers=?, ~allEventParams=[]) => {
63
- let client =
64
- Core.getAddon().evmRpcClient->classNew(
65
- {url, ?httpReqTimeoutMillis, ?headers},
66
- allEventParams,
67
- ~checksumAddresses,
68
- )
81
+ let make = (
82
+ ~url,
83
+ ~checksumAddresses,
84
+ ~syncConfig: Config.sourceSync,
85
+ ~httpReqTimeoutMillis=?,
86
+ ~headers=?,
87
+ ~eventRegistrations=[],
88
+ ) => {
89
+ let client = Core.getAddon().evmRpcClient->classNew(
90
+ {
91
+ url,
92
+ ?httpReqTimeoutMillis,
93
+ ?headers,
94
+ initialBlockInterval: syncConfig.initialBlockInterval,
95
+ backoffMultiplicative: syncConfig.backoffMultiplicative,
96
+ accelerationAdditive: syncConfig.accelerationAdditive,
97
+ intervalCeiling: syncConfig.intervalCeiling,
98
+ backoffMillis: syncConfig.backoffMillis,
99
+ queryTimeoutMillis: syncConfig.queryTimeoutMillis,
100
+ },
101
+ eventRegistrations,
102
+ ~checksumAddresses,
103
+ )
69
104
  {
70
105
  getHeight: () => client.getHeight()->Promise.catch(coerceErrorOrThrow),
71
- getLogs: params => client.getLogs(params)->Promise.catch(coerceErrorOrThrow),
106
+ getNextPage: params => client.getNextPage(params)->Promise.catch(coerceErrorOrThrow),
72
107
  }
73
108
  }
@@ -46,16 +46,22 @@ function coerceErrorOrThrow(exn) {
46
46
  throw exn;
47
47
  }
48
48
 
49
- function make(url, checksumAddresses, httpReqTimeoutMillis, headers, allEventParamsOpt) {
50
- let allEventParams = allEventParamsOpt !== undefined ? allEventParamsOpt : [];
49
+ function make(url, checksumAddresses, syncConfig, httpReqTimeoutMillis, headers, eventRegistrationsOpt) {
50
+ let eventRegistrations = eventRegistrationsOpt !== undefined ? eventRegistrationsOpt : [];
51
51
  let client = Core.getAddon().EvmRpcClient.new({
52
52
  url: url,
53
53
  httpReqTimeoutMillis: httpReqTimeoutMillis,
54
- headers: headers
55
- }, allEventParams, checksumAddresses);
54
+ headers: headers,
55
+ initialBlockInterval: syncConfig.initialBlockInterval,
56
+ backoffMultiplicative: syncConfig.backoffMultiplicative,
57
+ accelerationAdditive: syncConfig.accelerationAdditive,
58
+ intervalCeiling: syncConfig.intervalCeiling,
59
+ backoffMillis: syncConfig.backoffMillis,
60
+ queryTimeoutMillis: syncConfig.queryTimeoutMillis
61
+ }, eventRegistrations, checksumAddresses);
56
62
  return {
57
63
  getHeight: () => Stdlib_Promise.$$catch(client.getHeight(), coerceErrorOrThrow),
58
- getLogs: params => Stdlib_Promise.$$catch(client.getLogs(params), coerceErrorOrThrow)
64
+ getNextPage: params => Stdlib_Promise.$$catch(client.getNextPage(params), coerceErrorOrThrow)
59
65
  };
60
66
  }
61
67
 
@@ -35,8 +35,10 @@ let make = (~logger: Pino.t): Ecosystem.t => {
35
35
  // Analogous to EVM, but keyed by `block.height` instead of
36
36
  // `block.number`. See `Evm.res` for the rationale on the two-stage
37
37
  // parse and the `_lte`/`_every` rejection.
38
+ // `S.strict` on the inner object rejects unknown `block` fields — including
39
+ // `block.number`, which is EVM-only; Fuel filters by `block.height`.
38
40
  onEventBlockFilterSchema: S.object(s =>
39
- s.field("block", S.option(S.object(s2 => s2.field("height", S.unknown))))
41
+ s.field("block", S.option(S.object(s2 => s2.field("height", S.unknown))->S.strict))
40
42
  ),
41
43
  logger,
42
44
  toEvent: eventItem => eventItem.payload->(Utils.magic: Internal.eventPayload => Internal.event),
@@ -19,7 +19,7 @@ function make(logger) {
19
19
  cleanUpRawEventFieldsInPlace: cleanUpRawEventFieldsInPlace,
20
20
  onBlockMethodName: "onBlock",
21
21
  onBlockFilterSchema: S$RescriptSchema.object(s => s.f("block", S$RescriptSchema.option(S$RescriptSchema.object(s2 => s2.f("height", S$RescriptSchema.unknown))))),
22
- onEventBlockFilterSchema: S$RescriptSchema.object(s => s.f("block", S$RescriptSchema.option(S$RescriptSchema.object(s2 => s2.f("height", S$RescriptSchema.unknown))))),
22
+ onEventBlockFilterSchema: S$RescriptSchema.object(s => s.f("block", S$RescriptSchema.option(S$RescriptSchema.strict(S$RescriptSchema.object(s2 => s2.f("height", S$RescriptSchema.unknown)))))),
23
23
  logger: logger,
24
24
  toEvent: eventItem => eventItem.payload,
25
25
  toEventLogger: eventItem => Logging.createChildFrom(logger, {
@@ -61,23 +61,6 @@ module GetLogs = {
61
61
 
62
62
  exception Error(error)
63
63
 
64
- let makeRequestBody = (
65
- ~fromBlock,
66
- ~toBlockInclusive,
67
- ~addressesWithTopics,
68
- ~fieldSelection,
69
- ~maxNumLogs,
70
- ): HyperSyncClient.QueryTypes.query => {
71
- fromBlock,
72
- toBlockExclusive: ?switch toBlockInclusive {
73
- | Some(toBlockInclusive) => Some(toBlockInclusive + 1)
74
- | None => None
75
- },
76
- logs: addressesWithTopics,
77
- fieldSelection,
78
- maxNumLogs,
79
- }
80
-
81
64
  // Rust encodes structured failures as a JSON payload in the napi error's
82
65
  // message: `{"kind":"MissingFields","fields":["block.timestamp", ...]}`.
83
66
  // JSON.parse + shape check is the recovery protocol — no string-grepping
@@ -107,29 +90,17 @@ module GetLogs = {
107
90
  ~client: HyperSyncClient.t,
108
91
  ~fromBlock,
109
92
  ~toBlock,
110
- ~logSelections: array<LogSelection.t>,
111
- ~fieldSelection,
112
93
  ~maxNumLogs,
94
+ ~registrationIndexes,
95
+ ~addressesByContractName,
113
96
  ): logsQueryPage => {
114
- let addressesWithTopics = logSelections->Array.flatMap(({addresses, topicSelections}) =>
115
- topicSelections->Array.map(({topic0, topic1, topic2, topic3}) => {
116
- let topics = HyperSyncClient.QueryTypes.makeTopicSelection(
117
- ~topic0,
118
- ~topic1,
119
- ~topic2,
120
- ~topic3,
121
- )
122
- HyperSyncClient.QueryTypes.makeLogSelection(~address=addresses, ~topics)
123
- })
124
- )
125
-
126
- let query = makeRequestBody(
127
- ~fromBlock,
128
- ~toBlockInclusive=toBlock,
129
- ~addressesWithTopics,
130
- ~fieldSelection,
131
- ~maxNumLogs,
132
- )
97
+ let query: HyperSyncClient.EventItems.query = {
98
+ fromBlock,
99
+ toBlock,
100
+ maxNumLogs,
101
+ registrationIndexes,
102
+ addressesByContractName,
103
+ }
133
104
 
134
105
  let (res, transactionStore, blockStore) = switch await client.getEventItems(~query) {
135
106
  | res => res
@@ -12,7 +12,6 @@ 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,16 +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, maxNumLogs) {
66
- return {
67
- fromBlock: fromBlock,
68
- toBlock: toBlockInclusive !== undefined ? toBlockInclusive + 1 | 0 : undefined,
69
- logs: addressesWithTopics,
70
- fieldSelection: fieldSelection,
71
- maxNumLogs: maxNumLogs
72
- };
73
- }
74
-
75
64
  function extractMissingParams(exn) {
76
65
  let message = exn.RE_EXN_ID === "JsExn" ? Stdlib_JsExn.message(exn._1) : undefined;
77
66
  if (message === undefined) {
@@ -93,15 +82,14 @@ function extractMissingParams(exn) {
93
82
  }
94
83
  }
95
84
 
96
- async function query(client, fromBlock, toBlock, logSelections, fieldSelection, maxNumLogs) {
97
- let addressesWithTopics = logSelections.flatMap(param => {
98
- let addresses = param.addresses;
99
- return param.topicSelections.map(param => {
100
- let topics = HyperSyncClient.QueryTypes.makeTopicSelection(param.topic0, param.topic1, param.topic2, param.topic3);
101
- return HyperSyncClient.QueryTypes.makeLogSelection(addresses, topics);
102
- });
103
- });
104
- let query$1 = makeRequestBody(fromBlock, toBlock, addressesWithTopics, fieldSelection, maxNumLogs);
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
+ };
105
93
  let match;
106
94
  try {
107
95
  match = await client.getEventItems(query$1);
@@ -140,7 +128,13 @@ async function query(client, fromBlock, toBlock, logSelections, fieldSelection,
140
128
  };
141
129
  }
142
130
 
143
- function makeRequestBody$1(fromBlock, toBlock) {
131
+ let GetLogs = {
132
+ $$Error: $$Error,
133
+ extractMissingParams: extractMissingParams,
134
+ query: query
135
+ };
136
+
137
+ function makeRequestBody(fromBlock, toBlock) {
144
138
  return {
145
139
  fromBlock: fromBlock,
146
140
  toBlock: toBlock + 1 | 0,
@@ -193,7 +187,7 @@ function convertResponse(res) {
193
187
  }
194
188
 
195
189
  async function queryBlockData(client, fromBlock, toBlock, sourceName, chainId, logger, requestStats) {
196
- let body = makeRequestBody$1(fromBlock, toBlock);
190
+ let body = makeRequestBody(fromBlock, toBlock);
197
191
  let logger$1 = Logging.createChildFrom(logger, {
198
192
  logType: "HyperSync get block hash query",
199
193
  fromBlock: fromBlock,
@@ -282,12 +276,6 @@ function queryBlockData$1(client, blockNumber, sourceName, chainId, logger) {
282
276
  ]);
283
277
  }
284
278
 
285
- let GetLogs = {
286
- $$Error: $$Error,
287
- extractMissingParams: extractMissingParams,
288
- query: query
289
- };
290
-
291
279
  export {
292
280
  queryErrorToMsq,
293
281
  GetLogs,
@@ -32,9 +32,9 @@ module GetLogs: {
32
32
  ~client: HyperSyncClient.t,
33
33
  ~fromBlock: int,
34
34
  ~toBlock: option<int>,
35
- ~logSelections: array<LogSelection.t>,
36
- ~fieldSelection: HyperSyncClient.QueryTypes.fieldSelection,
37
35
  ~maxNumLogs: int,
36
+ ~registrationIndexes: array<int>,
37
+ ~addressesByContractName: dict<array<Address.t>>,
38
38
  ) => promise<logsQueryPage>
39
39
  }
40
40
 
@@ -229,29 +229,106 @@ type queryResponse = {
229
229
  rollbackGuard: option<ResponseTypes.rollbackGuard>,
230
230
  }
231
231
 
232
- module Decoder = {
233
- 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,
234
251
  sighash: string,
235
252
  topicCount: int,
236
253
  eventName: string,
237
254
  contractName: string,
255
+ isWildcard: bool,
256
+ dependsOnAddresses: bool,
238
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>,
263
+ }
264
+
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
+ })
239
303
  }
240
304
  }
241
305
 
242
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
+
243
319
  type item = {
244
320
  logIndex: int,
245
321
  srcAddress: Address.t,
246
- topic0: EvmTypes.Hex.t,
247
- topicCount: int,
248
322
  // Number of the block this log belongs to; the block itself is resolved from
249
323
  // `response.blocks`, deduplicated across items sharing a block.
250
324
  blockNumber: int,
251
325
  // Key (with the block number) into the transaction store; the transaction
252
326
  // is resolved from the store on demand.
253
327
  transactionIndex: int,
254
- params: Nullable.t<dict<Internal.eventParams>>,
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,
255
332
  }
256
333
 
257
334
  // The always-needed block fields, one per block number. The block's remaining
@@ -277,7 +354,7 @@ type t = {
277
354
  // Returns the response plus page stores owning this page's raw transactions
278
355
  // and blocks.
279
356
  getEventItems: (
280
- ~query: query,
357
+ ~query: EventItems.query,
281
358
  ) => promise<(EventItems.response, TransactionStore.t, BlockStore.t)>,
282
359
  getHeight: unit => promise<int>,
283
360
  }
@@ -287,11 +364,11 @@ external classNew: (
287
364
  Core.evmHypersyncClientCtor,
288
365
  cfg,
289
366
  string,
290
- array<Decoder.eventParamsInput>,
367
+ array<Registration.input>,
291
368
  ) => t = "new"
292
369
 
293
- let makeWithAgent = (cfg, ~userAgent, ~eventParams) =>
294
- Core.getAddon().evmHypersyncClient->classNew(cfg, userAgent, eventParams)
370
+ let makeWithAgent = (cfg, ~userAgent, ~eventRegistrations) =>
371
+ Core.getAddon().evmHypersyncClient->classNew(cfg, userAgent, eventRegistrations)
295
372
 
296
373
  type logLevel = [#trace | #debug | #info | #warn | #error]
297
374
  let logLevelSchema: S.t<logLevel> = S.enum([#trace, #debug, #info, #warn, #error])
@@ -309,7 +386,7 @@ let make = (
309
386
  ~url,
310
387
  ~apiToken,
311
388
  ~httpReqTimeoutMillis,
312
- ~eventParams,
389
+ ~eventRegistrations,
313
390
  ~enableChecksumAddresses=true,
314
391
  ~serializationFormat=?,
315
392
  ~enableQueryCaching=?,
@@ -335,6 +412,6 @@ let make = (
335
412
  logLevel: logLevelToString(logLevel),
336
413
  },
337
414
  ~userAgent=`hyperindex/${envioVersion}`,
338
- ~eventParams,
415
+ ~eventRegistrations,
339
416
  )
340
417
  }
@@ -36,12 +36,45 @@ let QueryTypes = {
36
36
 
37
37
  let ResponseTypes = {};
38
38
 
39
- let Decoder = {};
39
+ function toTopicFilterInput(filter) {
40
+ if (filter.TAG === "Values") {
41
+ return filter._0;
42
+ }
43
+ }
44
+
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
+ });
67
+ }
68
+
69
+ let Registration = {
70
+ toTopicFilterInput: toTopicFilterInput,
71
+ fromOnEventRegistrations: fromOnEventRegistrations
72
+ };
40
73
 
41
74
  let EventItems = {};
42
75
 
43
- function makeWithAgent(cfg, userAgent, eventParams) {
44
- return Core.getAddon().EvmHypersyncClient.new(cfg, userAgent, eventParams);
76
+ function makeWithAgent(cfg, userAgent, eventRegistrations) {
77
+ return Core.getAddon().EvmHypersyncClient.new(cfg, userAgent, eventRegistrations);
45
78
  }
46
79
 
47
80
  let logLevelSchema = S$RescriptSchema.$$enum([
@@ -66,7 +99,7 @@ function logLevelToString(level) {
66
99
  }
67
100
  }
68
101
 
69
- 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) {
70
103
  let enableChecksumAddresses = enableChecksumAddressesOpt !== undefined ? enableChecksumAddressesOpt : true;
71
104
  let logLevel = logLevelOpt !== undefined ? logLevelOpt : "info";
72
105
  let envioVersion = Utils.EnvioPackage.value.version;
@@ -82,14 +115,14 @@ function make(url, apiToken, httpReqTimeoutMillis, eventParams, enableChecksumAd
82
115
  serializationFormat: serializationFormat,
83
116
  enableQueryCaching: enableQueryCaching,
84
117
  logLevel: logLevelToString(logLevel)
85
- }, `hyperindex/` + envioVersion, eventParams);
118
+ }, `hyperindex/` + envioVersion, eventRegistrations);
86
119
  }
87
120
 
88
121
  export {
89
122
  serializationFormatSchema,
90
123
  QueryTypes,
91
124
  ResponseTypes,
92
- Decoder,
125
+ Registration,
93
126
  EventItems,
94
127
  makeWithAgent,
95
128
  logLevelSchema,