envio 3.3.0-alpha.10 → 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 (57) 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 +13 -10
  8. package/src/ChainFetching.res.mjs +3 -4
  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 +18 -1
  17. package/src/CrossChainState.res.mjs +2 -1
  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 +344 -263
  23. package/src/FetchState.res.mjs +209 -131
  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/SimulateDeadInputTracker.res +1 -1
  31. package/src/SimulateItems.res +38 -6
  32. package/src/SimulateItems.res.mjs +28 -9
  33. package/src/TestIndexer.res +2 -2
  34. package/src/TestIndexer.res.mjs +2 -2
  35. package/src/TopicFilter.res +1 -25
  36. package/src/TopicFilter.res.mjs +0 -74
  37. package/src/bindings/Viem.res +0 -5
  38. package/src/sources/EventRouter.res +0 -21
  39. package/src/sources/EventRouter.res.mjs +0 -12
  40. package/src/sources/EvmChain.res +2 -27
  41. package/src/sources/EvmChain.res.mjs +2 -23
  42. package/src/sources/EvmRpcClient.res +12 -15
  43. package/src/sources/EvmRpcClient.res.mjs +3 -3
  44. package/src/sources/HyperSync.res +9 -38
  45. package/src/sources/HyperSync.res.mjs +16 -28
  46. package/src/sources/HyperSync.resi +2 -2
  47. package/src/sources/HyperSyncClient.res +88 -11
  48. package/src/sources/HyperSyncClient.res.mjs +39 -6
  49. package/src/sources/HyperSyncSource.res +18 -199
  50. package/src/sources/HyperSyncSource.res.mjs +9 -128
  51. package/src/sources/Rpc.res +0 -32
  52. package/src/sources/Rpc.res.mjs +1 -46
  53. package/src/sources/RpcSource.res +29 -175
  54. package/src/sources/RpcSource.res.mjs +32 -110
  55. package/src/sources/SimulateSource.res +37 -19
  56. package/src/sources/SimulateSource.res.mjs +27 -10
  57. package/src/sources/SvmHyperSyncSource.res +3 -3
package/src/Core.res.mjs CHANGED
@@ -180,6 +180,17 @@ function getConfigJson(configPath, directory) {
180
180
  return addon.getConfigJson(Stdlib_Null.fromOption(configPath), Stdlib_Null.fromOption(directory));
181
181
  }
182
182
 
183
+ function parseConfigYaml(schema, env, files, isRescriptOpt, yaml) {
184
+ let isRescript = isRescriptOpt !== undefined ? isRescriptOpt : false;
185
+ let addon = getAddon();
186
+ return addon.parseConfigYaml(yaml, {
187
+ schema: schema,
188
+ env: env,
189
+ files: files,
190
+ isRescript: isRescript
191
+ });
192
+ }
193
+
183
194
  function runCli(args) {
184
195
  let addon = getAddon();
185
196
  return addon.runCli(args, envioPackageDir);
@@ -196,6 +207,7 @@ export {
196
207
  addonRef,
197
208
  getAddon,
198
209
  getConfigJson,
210
+ parseConfigYaml,
199
211
  runCli,
200
212
  }
201
213
  /* envioPackageDir Not a pure module */
@@ -267,7 +267,24 @@ let checkAndFetch = async (
267
267
  ~chunkItemsMultiplier,
268
268
  ~maxTargetBlock?,
269
269
  ) {
270
- | (WaitingForNewBlock | NothingToQuery) as action =>
270
+ | WaitingForNewBlock as action => actionByChain->Utils.Dict.setByInt(chainId, action)
271
+ | NothingToQuery =>
272
+ // A chain below its head that emitted no query this tick — its budget
273
+ // went to more-behind chains, or the cross-chain alignment clamped its
274
+ // range to nothing — and has nothing else to wake it must keep polling
275
+ // for new blocks instead of going silent. NothingToQuery isn't
276
+ // dispatched, so such a chain would never be re-scheduled and its head
277
+ // tracking would freeze (the knownHeight == 0 branch above forces a poll
278
+ // for the same reason). A chain is genuinely idle — and correctly left
279
+ // undispatched — when it is caught up to its head/endblock, still
280
+ // draining in-flight queries, or holding ready items that batch
281
+ // processing will drain and re-schedule from.
282
+ let action =
283
+ cs->ChainState.isFetchingAtHead ||
284
+ cs->ChainState.pendingBudget > 0. ||
285
+ cs->ChainState.bufferReadyCount > 0
286
+ ? FetchState.NothingToQuery
287
+ : FetchState.WaitingForNewBlock
271
288
  actionByChain->Utils.Dict.setByInt(chainId, action)
272
289
  | Ready(queries) => {
273
290
  let consumed =
@@ -163,7 +163,8 @@ async function checkAndFetch(crossChainState, dispatchChain) {
163
163
  actionByChain[chainId] = action;
164
164
  return;
165
165
  }
166
- actionByChain[chainId] = action;
166
+ let action$1 = ChainState.isFetchingAtHead(cs) || ChainState.pendingBudget(cs) > 0 || ChainState.bufferReadyCount(cs) > 0 ? "NothingToQuery" : "WaitingForNewBlock";
167
+ actionByChain[chainId] = action$1;
167
168
  return;
168
169
  } else {
169
170
  let queries = action._0;
@@ -236,58 +236,30 @@ let buildSimulateParamsSchema = (params: array<paramMeta>): S.t<Internal.eventPa
236
236
 
237
237
  // ============== Build topic filter getters ==============
238
238
 
239
- let getTopicEncoder = (abiType: string): (unknown => EvmTypes.Hex.t) => {
240
- // Handle array/tuple types - these get keccak256'd
241
- if abiType->String.endsWith("]") || abiType->String.startsWith("(") {
242
- TopicFilter.castToHexUnsafe->(Utils.magic: ('a => EvmTypes.Hex.t) => unknown => EvmTypes.Hex.t)
243
- } else {
244
- switch abiType {
245
- | "address" =>
246
- // Lowercase before encoding so mixed-case (checksummed) user input
247
- // still matches the lowercase hex topics returned by sources.
248
-
249
- (
250
- (value: string) =>
251
- value->String.toLowerCase->Address.unsafeFromString->TopicFilter.fromAddress
252
- )->(Utils.magic: (string => EvmTypes.Hex.t) => unknown => EvmTypes.Hex.t)
253
-
254
- | "bool" =>
255
- TopicFilter.fromBool->(Utils.magic: (bool => EvmTypes.Hex.t) => unknown => EvmTypes.Hex.t)
256
- | "string" =>
257
- TopicFilter.fromDynamicString->(
258
- Utils.magic: (string => EvmTypes.Hex.t) => unknown => EvmTypes.Hex.t
259
- )
260
-
261
- | "bytes" =>
262
- TopicFilter.fromDynamicBytes->(
263
- Utils.magic: (string => EvmTypes.Hex.t) => unknown => EvmTypes.Hex.t
264
- )
265
-
266
- | t if t->String.startsWith("uint") =>
267
- TopicFilter.fromBigInt->(Utils.magic: (bigint => EvmTypes.Hex.t) => unknown => EvmTypes.Hex.t)
268
- | t if t->String.startsWith("int") =>
269
- TopicFilter.fromSignedBigInt->(
270
- Utils.magic: (bigint => EvmTypes.Hex.t) => unknown => EvmTypes.Hex.t
271
- )
272
-
273
- | t if t->String.startsWith("bytes") =>
274
- TopicFilter.castToHexUnsafe->(
275
- Utils.magic: ('a => EvmTypes.Hex.t) => unknown => EvmTypes.Hex.t
276
- )
277
-
278
- | other => JsError.throwWithMessage(`Unsupported topic filter ABI type: ${other}`)
279
- }
280
- }
281
- }
239
+ let getTopicEncoder = (abiType: string): (unknown => EvmTypes.Hex.t) => value =>
240
+ Core.getAddon().encodeIndexedTopic(~abiType, ~value)
282
241
 
283
242
  let buildTopicGetter = (p: paramMeta) => {
284
243
  let encoder = getTopicEncoder(p.abiType)
244
+ let isTuple = p.abiType->String.startsWith("(")
285
245
  (eventFilter: dict<JSON.t>) =>
286
246
  eventFilter
287
247
  ->Utils.Dict.dangerouslyGetNonOption(p.name)
288
- ->Option.mapOr([], topicFilters =>
289
- topicFilters->(Utils.magic: JSON.t => unknown)->normalizeOrThrow->Array.map(encoder)
290
- )
248
+ ->Option.mapOr([], topicFilters => {
249
+ let raw = topicFilters->(Utils.magic: JSON.t => unknown)
250
+ // A tuple filter value is itself an array, so a directly-passed tuple is
251
+ // indistinguishable from an OR-list by shape alone. A single tuple is
252
+ // the common case, so try it first; when the value doesn't ABI-encode as
253
+ // one tuple it must be an OR-list of tuples.
254
+ if isTuple {
255
+ switch encoder(raw) {
256
+ | encoded => [encoded]
257
+ | exception _ => raw->normalizeOrThrow->Array.map(encoder)
258
+ }
259
+ } else {
260
+ raw->normalizeOrThrow->Array.map(encoder)
261
+ }
262
+ })
291
263
  }
292
264
 
293
265
  // ============== Field selection ==============
@@ -452,6 +424,7 @@ let buildEvmOnEventRegistration = (
452
424
  }
453
425
 
454
426
  {
427
+ index: -1,
455
428
  eventConfig: (eventConfig :> Internal.eventConfig),
456
429
  isWildcard,
457
430
  handler,
@@ -536,6 +509,7 @@ let buildSvmOnEventRegistration = (
536
509
  ~contractRegister: option<Internal.contractRegister>,
537
510
  ~startBlock: option<int>=?,
538
511
  ): Internal.svmOnEventRegistration => {
512
+ index: -1,
539
513
  eventConfig: (eventConfig :> Internal.eventConfig),
540
514
  handler,
541
515
  contractRegister,
@@ -613,6 +587,7 @@ let buildFuelOnEventRegistration = (
613
587
  ~contractRegister: option<Internal.contractRegister>,
614
588
  ~startBlock: option<int>=?,
615
589
  ): Internal.fuelOnEventRegistration => {
590
+ index: -1,
616
591
  eventConfig: (eventConfig :> Internal.eventConfig),
617
592
  handler,
618
593
  contractRegister,
@@ -2,11 +2,11 @@
2
2
 
3
3
  import * as Evm from "./sources/Evm.res.mjs";
4
4
  import * as Svm from "./sources/Svm.res.mjs";
5
+ import * as Core from "./Core.res.mjs";
5
6
  import * as Utils from "./Utils.res.mjs";
6
7
  import * as Address from "./Address.res.mjs";
7
8
  import * as FuelSDK from "./sources/FuelSDK.res.mjs";
8
9
  import * as Internal from "./Internal.res.mjs";
9
- import * as TopicFilter from "./TopicFilter.res.mjs";
10
10
  import * as LogSelection from "./LogSelection.res.mjs";
11
11
  import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
12
12
  import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
@@ -208,34 +208,24 @@ function buildSimulateParamsSchema(params) {
208
208
  }
209
209
 
210
210
  function getTopicEncoder(abiType) {
211
- if (abiType.endsWith("]") || abiType.startsWith("(")) {
212
- return TopicFilter.castToHexUnsafe;
213
- }
214
- switch (abiType) {
215
- case "address" :
216
- return value => TopicFilter.fromAddress(value.toLowerCase());
217
- case "bool" :
218
- return TopicFilter.fromBool;
219
- case "bytes" :
220
- return TopicFilter.fromDynamicBytes;
221
- case "string" :
222
- return TopicFilter.fromDynamicString;
223
- default:
224
- if (abiType.startsWith("uint")) {
225
- return TopicFilter.fromBigInt;
226
- } else if (abiType.startsWith("int")) {
227
- return TopicFilter.fromSignedBigInt;
228
- } else if (abiType.startsWith("bytes")) {
229
- return TopicFilter.castToHexUnsafe;
230
- } else {
231
- return Stdlib_JsError.throwWithMessage(`Unsupported topic filter ABI type: ` + abiType);
232
- }
233
- }
211
+ return value => Core.getAddon().encodeIndexedTopic(abiType, value);
234
212
  }
235
213
 
236
214
  function buildTopicGetter(p) {
237
215
  let encoder = getTopicEncoder(p.abiType);
238
- return eventFilter => Stdlib_Option.mapOr(eventFilter[p.name], [], topicFilters => normalizeOrThrow(topicFilters).map(encoder));
216
+ let isTuple = p.abiType.startsWith("(");
217
+ return eventFilter => Stdlib_Option.mapOr(eventFilter[p.name], [], topicFilters => {
218
+ if (!isTuple) {
219
+ return normalizeOrThrow(topicFilters).map(encoder);
220
+ }
221
+ let encoded;
222
+ try {
223
+ encoded = encoder(topicFilters);
224
+ } catch (exn) {
225
+ return normalizeOrThrow(topicFilters).map(encoder);
226
+ }
227
+ return [encoded];
228
+ });
239
229
  }
240
230
 
241
231
  let alwaysIncludedBlockFields = [
@@ -317,6 +307,7 @@ function buildEvmOnEventRegistration(eventConfig, isWildcard, handler, contractR
317
307
  let sb = resolvedWhere.startBlock;
318
308
  let resolvedStartBlock = sb !== undefined ? sb : startBlock;
319
309
  return {
310
+ index: -1,
320
311
  eventConfig: eventConfig,
321
312
  handler: handler,
322
313
  contractRegister: contractRegister,
@@ -369,6 +360,7 @@ function buildSvmInstructionEventConfig(contractName, instructionName, programId
369
360
 
370
361
  function buildSvmOnEventRegistration(eventConfig, isWildcard, handler, contractRegister, startBlock) {
371
362
  return {
363
+ index: -1,
372
364
  eventConfig: eventConfig,
373
365
  handler: handler,
374
366
  contractRegister: contractRegister,
@@ -438,6 +430,7 @@ function buildFuelEventConfig(contractName, eventName, kind, sighash, rawAbi) {
438
430
 
439
431
  function buildFuelOnEventRegistration(eventConfig, isWildcard, handler, contractRegister, startBlock) {
440
432
  return {
433
+ index: -1,
441
434
  eventConfig: eventConfig,
442
435
  handler: handler,
443
436
  contractRegister: contractRegister,
@@ -73,9 +73,10 @@ let runEventHandlerOrThrow = async (
73
73
  )
74
74
  }
75
75
  let handlerDuration = timeBeforeHandler->Performance.secondsSince
76
+ let eventConfig = eventItem.onEventRegistration.eventConfig
76
77
  Prometheus.ProcessingHandler.increment(
77
- ~contract=eventItem.onEventRegistration.eventConfig.contractName,
78
- ~event=eventItem.onEventRegistration.eventConfig.name,
78
+ ~contract=eventConfig.contractName,
79
+ ~event=eventConfig.name,
79
80
  ~duration=handlerDuration,
80
81
  )
81
82
  }
@@ -121,8 +122,8 @@ let runHandlerOrThrow = async (
121
122
  }),
122
123
  )
123
124
  }
124
- | Event({onEventRegistration}) =>
125
- switch onEventRegistration.handler {
125
+ | Event(_) =>
126
+ switch (item->Internal.castUnsafeEventItem).onEventRegistration.handler {
126
127
  | Some(handler) =>
127
128
  await item->runEventHandlerOrThrow(
128
129
  ~handler,
@@ -161,7 +162,9 @@ let preloadBatchOrThrow = async (
161
162
  for idx in 0 to checkpointEventsProcessed - 1 {
162
163
  let item = batch.items->Array.getUnsafe(itemIdx.contents + idx)
163
164
  switch item {
164
- | Event({onEventRegistration: {handler, eventConfig: {contractName, name: eventName}}}) =>
165
+ | Event(_) =>
166
+ let {handler, eventConfig: {contractName, name: eventName}} =
167
+ (item->Internal.castUnsafeEventItem).onEventRegistration
165
168
  switch handler {
166
169
  | None => ()
167
170
  | Some(handler) =>
@@ -65,7 +65,8 @@ async function runEventHandlerOrThrow(item, checkpointId, handler, indexerState,
65
65
  };
66
66
  }
67
67
  let handlerDuration = Performance.secondsSince(timeBeforeHandler);
68
- return Prometheus.ProcessingHandler.increment(item.onEventRegistration.eventConfig.contractName, item.onEventRegistration.eventConfig.name, handlerDuration);
68
+ let eventConfig = item.onEventRegistration.eventConfig;
69
+ return Prometheus.ProcessingHandler.increment(eventConfig.contractName, eventConfig.name, handlerDuration);
69
70
  }
70
71
 
71
72
  async function runHandlerOrThrow(item, checkpointId, indexerState, loadManager, persistence, config, chains) {