envio 3.3.0-alpha.10 → 3.3.0-alpha.12

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 (60) hide show
  1. package/licenses/CLA.md +35 -0
  2. package/licenses/EULA.md +67 -0
  3. package/licenses/LICENSE.md +45 -0
  4. package/licenses/README.md +35 -0
  5. package/package.json +9 -8
  6. package/src/Batch.res.mjs +1 -1
  7. package/src/ChainFetching.res +30 -18
  8. package/src/ChainFetching.res.mjs +23 -13
  9. package/src/ChainState.res +45 -30
  10. package/src/ChainState.res.mjs +22 -8
  11. package/src/ChainState.resi +5 -0
  12. package/src/Config.res +9 -5
  13. package/src/Config.res.mjs +2 -2
  14. package/src/Core.res +20 -0
  15. package/src/Core.res.mjs +12 -0
  16. package/src/CrossChainState.res +64 -29
  17. package/src/CrossChainState.res.mjs +17 -8
  18. package/src/EventConfigBuilder.res +21 -46
  19. package/src/EventConfigBuilder.res.mjs +18 -25
  20. package/src/EventProcessing.res +8 -5
  21. package/src/EventProcessing.res.mjs +2 -1
  22. package/src/FetchState.res +428 -322
  23. package/src/FetchState.res.mjs +316 -233
  24. package/src/HandlerRegister.res +3 -1
  25. package/src/HandlerRegister.res.mjs +3 -2
  26. package/src/Internal.res +11 -2
  27. package/src/LogSelection.res +0 -62
  28. package/src/LogSelection.res.mjs +0 -74
  29. package/src/RawEvent.res +2 -2
  30. package/src/Rollback.res +32 -13
  31. package/src/Rollback.res.mjs +24 -11
  32. package/src/SimulateDeadInputTracker.res +1 -1
  33. package/src/SimulateItems.res +38 -6
  34. package/src/SimulateItems.res.mjs +28 -9
  35. package/src/TestIndexer.res +2 -2
  36. package/src/TestIndexer.res.mjs +2 -2
  37. package/src/TopicFilter.res +1 -25
  38. package/src/TopicFilter.res.mjs +0 -74
  39. package/src/bindings/Viem.res +0 -5
  40. package/src/sources/EventRouter.res +0 -21
  41. package/src/sources/EventRouter.res.mjs +0 -12
  42. package/src/sources/EvmChain.res +2 -27
  43. package/src/sources/EvmChain.res.mjs +2 -23
  44. package/src/sources/EvmRpcClient.res +12 -15
  45. package/src/sources/EvmRpcClient.res.mjs +3 -3
  46. package/src/sources/HyperSync.res +9 -38
  47. package/src/sources/HyperSync.res.mjs +16 -28
  48. package/src/sources/HyperSync.resi +2 -2
  49. package/src/sources/HyperSyncClient.res +88 -11
  50. package/src/sources/HyperSyncClient.res.mjs +39 -6
  51. package/src/sources/HyperSyncSource.res +18 -199
  52. package/src/sources/HyperSyncSource.res.mjs +9 -128
  53. package/src/sources/Rpc.res +0 -32
  54. package/src/sources/Rpc.res.mjs +1 -46
  55. package/src/sources/RpcSource.res +29 -175
  56. package/src/sources/RpcSource.res.mjs +32 -110
  57. package/src/sources/SimulateSource.res +37 -19
  58. package/src/sources/SimulateSource.res.mjs +27 -10
  59. package/src/sources/SvmHyperSyncSource.res +13 -3
  60. package/src/sources/SvmHyperSyncSource.res.mjs +1 -1
@@ -1,11 +1,6 @@
1
1
  type hex = EvmTypes.Hex.t
2
2
  @module("viem") external toHex: 'a => hex = "toHex"
3
- @module("viem") external keccak256: hex => hex = "keccak256"
4
3
  @module("viem") external pad: hex => hex = "pad"
5
4
 
6
5
  type sizeOptions = {size: int}
7
6
  @module("viem") external bigintToHex: (bigint, ~options: sizeOptions=?) => hex = "numberToHex"
8
- @module("viem") external stringToHex: (string, ~options: sizeOptions=?) => hex = "stringToHex"
9
- @module("viem") external boolToHex: (bool, ~options: sizeOptions=?) => hex = "boolToHex"
10
- @module("viem") external bytesToHex: (Uint8Array.t, ~options: sizeOptions=?) => hex = "bytesToHex"
11
- @module("viem") external concat: array<hex> => hex = "concat"
@@ -92,27 +92,6 @@ let get = (router: t<'a>, ~tag, ~contractAddress, ~contractNameByAddress) => {
92
92
  }
93
93
  }
94
94
 
95
- let getEvmEventId = (~sighash, ~topicCount) => {
96
- sighash ++ "_" ++ topicCount->Int.toString
97
- }
98
-
99
- let fromEvmEventModsOrThrow = (events: array<Internal.evmOnEventRegistration>, ~chain): t<
100
- Internal.evmOnEventRegistration,
101
- > => {
102
- let router = empty()
103
- events->Array.forEach(config => {
104
- router->addOrThrow(
105
- config.eventConfig.id,
106
- config,
107
- ~contractName=config.eventConfig.contractName,
108
- ~eventName=config.eventConfig.name,
109
- ~chain,
110
- ~isWildcard=config.isWildcard,
111
- )
112
- })
113
- router
114
- }
115
-
116
95
  /** Dispatch key for SVM instructions. `None` matches any instruction in the
117
96
  program (lowest priority). */
118
97
  let getSvmEventId = (~programId: SvmTypes.Pubkey.t, ~discriminator: option<string>) =>
@@ -97,16 +97,6 @@ function get$1(router, tag, contractAddress, contractNameByAddress) {
97
97
  }
98
98
  }
99
99
 
100
- function getEvmEventId(sighash, topicCount) {
101
- return sighash + "_" + topicCount.toString();
102
- }
103
-
104
- function fromEvmEventModsOrThrow(events, chain) {
105
- let router = {};
106
- events.forEach(config => addOrThrow$1(router, config.eventConfig.id, config, config.eventConfig.contractName, config.isWildcard, config.eventConfig.name, chain));
107
- return router;
108
- }
109
-
110
100
  function getSvmEventId(programId, discriminator) {
111
101
  if (discriminator !== undefined) {
112
102
  return programId + "_" + discriminator;
@@ -157,8 +147,6 @@ export {
157
147
  empty$1 as empty,
158
148
  addOrThrow$1 as addOrThrow,
159
149
  get$1 as get,
160
- getEvmEventId,
161
- fromEvmEventModsOrThrow,
162
150
  getSvmEventId,
163
151
  fromSvmEventConfigsOrThrow,
164
152
  }
@@ -39,25 +39,6 @@ let getSyncConfig = (
39
39
  }
40
40
  }
41
41
 
42
- let collectEventParams = (onEventRegistrations: array<Internal.evmOnEventRegistration>): array<
43
- HyperSyncClient.Decoder.eventParamsInput,
44
- > => {
45
- let result = []
46
- onEventRegistrations->Array.forEach(reg => {
47
- let event = reg.eventConfig->(Utils.magic: Internal.eventConfig => Internal.evmEventConfig)
48
- result
49
- ->Array.push({
50
- HyperSyncClient.Decoder.sighash: event.sighash,
51
- topicCount: event.topicCount,
52
- eventName: event.name,
53
- contractName: event.contractName,
54
- params: event.paramsMetadata,
55
- })
56
- ->ignore
57
- })
58
- result
59
- }
60
-
61
42
  let makeSources = (
62
43
  ~chain,
63
44
  ~onEventRegistrations: array<Internal.evmOnEventRegistration>,
@@ -65,17 +46,12 @@ let makeSources = (
65
46
  ~rpcs: array<rpc>,
66
47
  ~lowercaseAddresses,
67
48
  ) => {
68
- let eventRouter = onEventRegistrations->EventRouter.fromEvmEventModsOrThrow(~chain)
69
-
70
- let allEventParams = collectEventParams(onEventRegistrations)
71
-
72
49
  let sources = switch hyperSync {
73
50
  | Some(endpointUrl) => [
74
51
  HyperSyncSource.make({
75
52
  chain,
76
53
  endpointUrl,
77
- allEventParams,
78
- eventRouter,
54
+ onEventRegistrations,
79
55
  apiToken: Env.envioApiToken,
80
56
  clientTimeoutMillis: Env.hyperSyncClientTimeoutMillis,
81
57
  lowercaseAddresses,
@@ -92,8 +68,7 @@ let makeSources = (
92
68
  sourceFor,
93
69
  syncConfig: getSyncConfig(syncConfig->Option.getOr({})),
94
70
  url,
95
- eventRouter,
96
- allEventParams,
71
+ onEventRegistrations,
97
72
  lowercaseAddresses,
98
73
  ?ws,
99
74
  ?headers,
@@ -2,7 +2,6 @@
2
2
 
3
3
  import * as Env from "../Env.res.mjs";
4
4
  import * as RpcSource from "./RpcSource.res.mjs";
5
- import * as EventRouter from "./EventRouter.res.mjs";
6
5
  import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
7
6
  import * as HyperSyncSource from "./HyperSyncSource.res.mjs";
8
7
 
@@ -20,29 +19,11 @@ function getSyncConfig(param) {
20
19
  };
21
20
  }
22
21
 
23
- function collectEventParams(onEventRegistrations) {
24
- let result = [];
25
- onEventRegistrations.forEach(reg => {
26
- let event = reg.eventConfig;
27
- result.push({
28
- sighash: event.sighash,
29
- topicCount: event.topicCount,
30
- eventName: event.name,
31
- contractName: event.contractName,
32
- params: event.paramsMetadata
33
- });
34
- });
35
- return result;
36
- }
37
-
38
22
  function makeSources(chain, onEventRegistrations, hyperSync, rpcs, lowercaseAddresses) {
39
- let eventRouter = EventRouter.fromEvmEventModsOrThrow(onEventRegistrations, chain);
40
- let allEventParams = collectEventParams(onEventRegistrations);
41
23
  let sources = hyperSync !== undefined ? [HyperSyncSource.make({
42
24
  chain: chain,
43
25
  endpointUrl: hyperSync,
44
- allEventParams: allEventParams,
45
- eventRouter: eventRouter,
26
+ onEventRegistrations: onEventRegistrations,
46
27
  apiToken: Env.envioApiToken,
47
28
  clientTimeoutMillis: Env.hyperSyncClientTimeoutMillis,
48
29
  lowercaseAddresses: lowercaseAddresses,
@@ -56,8 +37,7 @@ function makeSources(chain, onEventRegistrations, hyperSync, rpcs, lowercaseAddr
56
37
  syncConfig: getSyncConfig(Stdlib_Option.getOr(param.syncConfig, {})),
57
38
  url: param.url,
58
39
  chain: chain,
59
- eventRouter: eventRouter,
60
- allEventParams: allEventParams,
40
+ onEventRegistrations: onEventRegistrations,
61
41
  lowercaseAddresses: lowercaseAddresses,
62
42
  ws: param.ws,
63
43
  headers: param.headers
@@ -69,7 +49,6 @@ function makeSources(chain, onEventRegistrations, hyperSync, rpcs, lowercaseAddr
69
49
 
70
50
  export {
71
51
  getSyncConfig,
72
- collectEventParams,
73
52
  makeSources,
74
53
  }
75
54
  /* Env Not a pure module */
@@ -10,26 +10,23 @@ type cfg = {
10
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>>,
18
- }
19
-
20
- // `addresses` omitted matches any address (a wildcard selection). Each `topics`
21
- // position is `null` (match any) or a list of accepted topic hashes; the
22
- // single-match case is a one-element list.
23
- type logSelectionInput = {
24
- addresses?: array<Address.t>,
25
- topics: array<Nullable.t<array<string>>>,
17
+ onEventRegistrationIndex: int,
18
+ params: Internal.eventParams,
26
19
  }
27
20
 
28
21
  type nextPageParams = {
29
22
  fromBlock: int,
30
23
  toBlockCeiling: int,
31
- logSelections: array<logSelectionInput>,
32
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>>,
33
30
  }
34
31
 
35
32
  type nextPageResponse = {
@@ -48,7 +45,7 @@ type t = {
48
45
  external classNew: (
49
46
  Core.evmRpcClientCtor,
50
47
  cfg,
51
- array<HyperSyncClient.Decoder.eventParamsInput>,
48
+ array<HyperSyncClient.Registration.input>,
52
49
  ~checksumAddresses: bool,
53
50
  ) => t = "new"
54
51
 
@@ -87,7 +84,7 @@ let make = (
87
84
  ~syncConfig: Config.sourceSync,
88
85
  ~httpReqTimeoutMillis=?,
89
86
  ~headers=?,
90
- ~allEventParams=[],
87
+ ~eventRegistrations=[],
91
88
  ) => {
92
89
  let client = Core.getAddon().evmRpcClient->classNew(
93
90
  {
@@ -101,7 +98,7 @@ let make = (
101
98
  backoffMillis: syncConfig.backoffMillis,
102
99
  queryTimeoutMillis: syncConfig.queryTimeoutMillis,
103
100
  },
104
- allEventParams,
101
+ eventRegistrations,
105
102
  ~checksumAddresses,
106
103
  )
107
104
  {
@@ -46,8 +46,8 @@ function coerceErrorOrThrow(exn) {
46
46
  throw exn;
47
47
  }
48
48
 
49
- function make(url, checksumAddresses, syncConfig, 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,
@@ -58,7 +58,7 @@ function make(url, checksumAddresses, syncConfig, httpReqTimeoutMillis, headers,
58
58
  intervalCeiling: syncConfig.intervalCeiling,
59
59
  backoffMillis: syncConfig.backoffMillis,
60
60
  queryTimeoutMillis: syncConfig.queryTimeoutMillis
61
- }, allEventParams, checksumAddresses);
61
+ }, eventRegistrations, checksumAddresses);
62
62
  return {
63
63
  getHeight: () => Stdlib_Promise.$$catch(client.getHeight(), coerceErrorOrThrow),
64
64
  getNextPage: params => Stdlib_Promise.$$catch(client.getNextPage(params), coerceErrorOrThrow)
@@ -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,