envio 3.1.0-rc.2 → 3.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.d.ts CHANGED
@@ -1201,6 +1201,18 @@ export type IndexerFromConfig<Config extends IndexerConfigTypes = GlobalConfig>
1201
1201
  readonly name: string;
1202
1202
  /** The indexer description from config.yaml. */
1203
1203
  readonly description: string | undefined;
1204
+ /**
1205
+ * Internal, unstable API that will be removed without notice. Registers a
1206
+ * callback fired once per chain affected by a reorg rollback, after the
1207
+ * rollback is durably written to the database. A throwing callback crashes
1208
+ * the indexer through the same path as a failed write.
1209
+ */
1210
+ readonly "~internalAndWillBeRemovedSoon_onRollbackCommit": (
1211
+ callback: (args: {
1212
+ readonly chainId: number;
1213
+ readonly rollbackToBlock: number;
1214
+ }) => Promise<void>,
1215
+ ) => void;
1204
1216
  } & SingleEcosystemChains<Config>
1205
1217
  >;
1206
1218
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "envio",
3
- "version": "3.1.0-rc.2",
3
+ "version": "3.1.1",
4
4
  "type": "module",
5
5
  "description": "A latency and sync speed optimized, developer friendly blockchain data indexer.",
6
6
  "bin": "./bin.mjs",
@@ -70,10 +70,10 @@
70
70
  "tsx": "4.21.0"
71
71
  },
72
72
  "optionalDependencies": {
73
- "envio-linux-x64": "3.1.0-rc.2",
74
- "envio-linux-x64-musl": "3.1.0-rc.2",
75
- "envio-linux-arm64": "3.1.0-rc.2",
76
- "envio-darwin-x64": "3.1.0-rc.2",
77
- "envio-darwin-arm64": "3.1.0-rc.2"
73
+ "envio-linux-x64": "3.1.1",
74
+ "envio-linux-x64-musl": "3.1.1",
75
+ "envio-linux-arm64": "3.1.1",
76
+ "envio-darwin-x64": "3.1.1",
77
+ "envio-darwin-arm64": "3.1.1"
78
78
  }
79
79
  }
@@ -1159,6 +1159,7 @@ let injectedTaskReducer = (
1159
1159
  ~persistence=state.ctx.persistence,
1160
1160
  ~rollbackTargetCheckpointId,
1161
1161
  ~rollbackDiffCheckpointId=state.ctx.inMemoryStore.committedCheckpointId->BigInt.add(1n),
1162
+ ~progressBlockNumberByChainId=newProgressBlockNumberPerChain,
1162
1163
  )
1163
1164
 
1164
1165
  let chainManager = {
@@ -1151,7 +1151,7 @@ function injectedTaskReducer(waitForNewBlock, executeQuery, getLastKnownValidBlo
1151
1151
  };
1152
1152
  });
1153
1153
  await InMemoryStore.flush(state.ctx.inMemoryStore);
1154
- let diff$1 = await InMemoryStore.prepareRollbackDiff(state.ctx.inMemoryStore, state.ctx.persistence, rollbackTargetCheckpointId, state.ctx.inMemoryStore.committedCheckpointId + 1n);
1154
+ let diff$1 = await InMemoryStore.prepareRollbackDiff(state.ctx.inMemoryStore, state.ctx.persistence, rollbackTargetCheckpointId, state.ctx.inMemoryStore.committedCheckpointId + 1n, newProgressBlockNumberPerChain);
1155
1155
  let init = state.chainManager;
1156
1156
  let chainManager_isInReorgThreshold = init.isInReorgThreshold;
1157
1157
  let chainManager_isRealtime = init.isRealtime;
@@ -124,10 +124,19 @@ let getEffectInMemTable = (inMemoryStore: t, ~effect: Internal.effect) => {
124
124
  }
125
125
  }
126
126
 
127
- let getEffectOutput = (inMemTable: effectCacheInMemTable, key) =>
127
+ let hasEffectOutput = (inMemTable: effectCacheInMemTable, key) =>
128
128
  switch inMemTable.dict->Utils.Dict.dangerouslyGetNonOption(key) {
129
- | Some(Set({entity: output})) => Some(output)
130
- | Some(Delete(_)) | None => None
129
+ | Some(Set(_)) => true
130
+ | Some(Delete(_)) | None => false
131
+ }
132
+
133
+ // Returns the raw output. The output is itself an option for effects with an
134
+ // optional output, so it must never be wrapped in another option here: Some(None)
135
+ // is encoded as the nested-option sentinel and would leak to the handler.
136
+ let getEffectOutputUnsafe = (inMemTable: effectCacheInMemTable, key): Internal.effectOutput =>
137
+ switch inMemTable.dict->Utils.Dict.dangerouslyGetNonOption(key) {
138
+ | Some(Set({entity: output})) => output
139
+ | Some(Delete(_)) | None => %raw(`undefined`)
131
140
  }
132
141
 
133
142
  // Records a handler output. Persisted on the next write only when shouldCache;
@@ -359,6 +368,12 @@ let runOneWrite = async (inMemoryStore: t, ~persistence: Persistence.t, ~config)
359
368
  )
360
369
 
361
370
  inMemoryStore.committedCheckpointId = upToCheckpointId
371
+
372
+ switch rollback {
373
+ | Some({progressBlockNumberByChainId}) if RollbackCommit.callbacks->Utils.Array.notEmpty =>
374
+ await RollbackCommit.fire(~progressBlockNumberByChainId)
375
+ | _ => ()
376
+ }
362
377
  }
363
378
  }
364
379
 
@@ -494,12 +509,14 @@ let prepareRollbackDiff = async (
494
509
  ~persistence: Persistence.t,
495
510
  ~rollbackTargetCheckpointId,
496
511
  ~rollbackDiffCheckpointId,
512
+ ~progressBlockNumberByChainId,
497
513
  ) => {
498
514
  inMemoryStore.entities = EntityTables.make(inMemoryStore.allEntities)
499
515
  inMemoryStore.effects = Dict.make()
500
516
  inMemoryStore.rollback = Some({
501
517
  targetCheckpointId: rollbackTargetCheckpointId,
502
518
  diffCheckpointId: rollbackDiffCheckpointId,
519
+ progressBlockNumberByChainId,
503
520
  })
504
521
 
505
522
  let deletedEntities = Dict.make()
@@ -11,6 +11,7 @@ import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
11
11
  import * as ErrorHandling from "./ErrorHandling.res.mjs";
12
12
  import * as InMemoryTable from "./InMemoryTable.res.mjs";
13
13
  import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
14
+ import * as RollbackCommit from "./RollbackCommit.res.mjs";
14
15
  import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
15
16
  import * as Primitive_object from "@rescript/runtime/lib/es6/Primitive_object.js";
16
17
  import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
@@ -89,11 +90,21 @@ function getEffectInMemTable(inMemoryStore, effect) {
89
90
  return table$1;
90
91
  }
91
92
 
92
- function getEffectOutput(inMemTable, key) {
93
+ function hasEffectOutput(inMemTable, key) {
94
+ let match = inMemTable.dict[key];
95
+ if (match !== undefined) {
96
+ return match.type === "SET";
97
+ } else {
98
+ return false;
99
+ }
100
+ }
101
+
102
+ function getEffectOutputUnsafe(inMemTable, key) {
93
103
  let match = inMemTable.dict[key];
94
104
  if (match !== undefined && match.type === "SET") {
95
- return Primitive_option.some(match.entity);
105
+ return match.entity;
96
106
  }
107
+ return undefined;
97
108
  }
98
109
 
99
110
  function setEffectOutput(inMemTable, checkpointId, cacheKey, output, shouldCache) {
@@ -300,6 +311,9 @@ async function runOneWrite(inMemoryStore, persistence, config) {
300
311
  let updatedEffectsCache = snapshotEffects(inMemoryStore, cache);
301
312
  await persistence.storage.writeBatch(batch, rollback, batch.isInReorgThreshold, config, persistence.allEntities, updatedEffectsCache, updatedEntities, chainMetaData);
302
313
  inMemoryStore.committedCheckpointId = upToCheckpointId;
314
+ if (rollback !== undefined && Utils.$$Array.notEmpty(RollbackCommit.callbacks)) {
315
+ return await RollbackCommit.fire(rollback.progressBlockNumberByChainId);
316
+ }
303
317
  }
304
318
 
305
319
  function hasPendingWrite(inMemoryStore) {
@@ -401,12 +415,13 @@ async function flush(inMemoryStore) {
401
415
  }
402
416
  }
403
417
 
404
- async function prepareRollbackDiff(inMemoryStore, persistence, rollbackTargetCheckpointId, rollbackDiffCheckpointId) {
418
+ async function prepareRollbackDiff(inMemoryStore, persistence, rollbackTargetCheckpointId, rollbackDiffCheckpointId, progressBlockNumberByChainId) {
405
419
  inMemoryStore.entities = make(inMemoryStore.allEntities);
406
420
  inMemoryStore.effects = {};
407
421
  inMemoryStore.rollback = {
408
422
  targetCheckpointId: rollbackTargetCheckpointId,
409
- diffCheckpointId: rollbackDiffCheckpointId
423
+ diffCheckpointId: rollbackDiffCheckpointId,
424
+ progressBlockNumberByChainId: progressBlockNumberByChainId
410
425
  };
411
426
  let deletedEntities = {};
412
427
  let setEntities = {};
@@ -482,7 +497,8 @@ export {
482
497
  make$1 as make,
483
498
  keepLatestChangesLimit,
484
499
  getEffectInMemTable,
485
- getEffectOutput,
500
+ hasEffectOutput,
501
+ getEffectOutputUnsafe,
486
502
  setEffectOutput,
487
503
  initEffectOutputFromDb,
488
504
  dropCommittedEffects,
package/src/LoadLayer.res CHANGED
@@ -336,8 +336,8 @@ let loadEffect = (
336
336
  ~load,
337
337
  ~shouldGroup,
338
338
  ~hasher=args => args.cacheKey,
339
- ~getUnsafeInMemory=hash => inMemTable->InMemoryStore.getEffectOutput(hash)->Option.getUnsafe,
340
- ~hasInMemory=hash => inMemTable->InMemoryStore.getEffectOutput(hash)->Option.isSome,
339
+ ~getUnsafeInMemory=hash => inMemTable->InMemoryStore.getEffectOutputUnsafe(hash),
340
+ ~hasInMemory=hash => inMemTable->InMemoryStore.hasEffectOutput(hash),
341
341
  ~input=effectArgs,
342
342
  )
343
343
  }
@@ -12,7 +12,6 @@ import * as TableIndices from "./TableIndices.res.mjs";
12
12
  import * as ErrorHandling from "./ErrorHandling.res.mjs";
13
13
  import * as InMemoryStore from "./InMemoryStore.res.mjs";
14
14
  import * as InMemoryTable from "./InMemoryTable.res.mjs";
15
- import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
16
15
  import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
17
16
  import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
18
17
 
@@ -187,7 +186,7 @@ function loadEffect(loadManager, persistence, effect, effectArgs, inMemoryStore,
187
186
  return await executeWithRateLimit(effect, argsToCall, inMemTable, onError, false);
188
187
  }
189
188
  };
190
- return LoadManager.call(loadManager, effectArgs, key, load, args => args.cacheKey, shouldGroup, hash => Stdlib_Option.isSome(InMemoryStore.getEffectOutput(inMemTable, hash)), hash => InMemoryStore.getEffectOutput(inMemTable, hash));
189
+ return LoadManager.call(loadManager, effectArgs, key, load, args => args.cacheKey, shouldGroup, hash => InMemoryStore.hasEffectOutput(inMemTable, hash), hash => InMemoryStore.getEffectOutputUnsafe(inMemTable, hash));
191
190
  }
192
191
 
193
192
  function loadByField(loadManager, persistence, operator, entityConfig, inMemoryStore, fieldName, fieldValueSchema, shouldGroup, item, fieldValue) {
package/src/Main.res CHANGED
@@ -312,6 +312,13 @@ let getGlobalIndexer = (): 'indexer => {
312
312
  )
313
313
  }
314
314
 
315
+ let onRollbackCommitFn = (callback: 'a) => {
316
+ HandlerRegister.throwIfFinishedRegistration(
317
+ ~methodName="~internalAndWillBeRemovedSoon_onRollbackCommit",
318
+ )
319
+ let _ = RollbackCommit.register(callback->(Utils.magic: 'a => RollbackCommit.callback))
320
+ }
321
+
315
322
  // Two-stage parse: first the ecosystem-specific outer schema unwraps the
316
323
  // wrapper (`block.number` / `block.height` / `slot`) and surfaces the
317
324
  // inner chunk as raw `unknown`; then the shared `blockRangeSchema`
@@ -453,8 +460,16 @@ let getGlobalIndexer = (): 'indexer => {
453
460
  "onEvent",
454
461
  "contractRegister",
455
462
  "onBlock",
463
+ "~internalAndWillBeRemovedSoon_onRollbackCommit",
464
+ ]
465
+ | Svm => [
466
+ "name",
467
+ "description",
468
+ "chainIds",
469
+ "chains",
470
+ "onSlot",
471
+ "~internalAndWillBeRemovedSoon_onRollbackCommit",
456
472
  ]
457
- | Svm => ["name", "description", "chainIds", "chains", "onSlot"]
458
473
  }
459
474
  keysMemo := Some(keys)
460
475
  keys
@@ -477,6 +492,7 @@ let getGlobalIndexer = (): 'indexer => {
477
492
  | "onEvent" => onEventFn->Utils.magic
478
493
  | "contractRegister" => contractRegisterFn->Utils.magic
479
494
  | "onBlock" | "onSlot" => onBlockFn->Utils.magic
495
+ | "~internalAndWillBeRemovedSoon_onRollbackCommit" => onRollbackCommitFn->Utils.magic
480
496
  | _ =>
481
497
  JsError.throwWithMessage(
482
498
  `Field \`${prop}\` does not exist on \`indexer\`. Available fields: ${getKeys()->Array.join(
package/src/Main.res.mjs CHANGED
@@ -25,6 +25,7 @@ import * as Primitive_int from "@rescript/runtime/lib/es6/Primitive_int.js";
25
25
  import * as SourceManager from "./sources/SourceManager.res.mjs";
26
26
  import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
27
27
  import * as Helpers from "yargs/helpers";
28
+ import * as RollbackCommit from "./RollbackCommit.res.mjs";
28
29
  import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
29
30
  import * as HandlerRegister from "./HandlerRegister.res.mjs";
30
31
  import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
@@ -255,6 +256,10 @@ function getGlobalIndexer() {
255
256
  let match = parseIdentityConfig(identityConfig);
256
257
  HandlerRegister.setContractRegister(match[0], match[1], handler, match[2], undefined);
257
258
  };
259
+ let onRollbackCommitFn = callback => {
260
+ HandlerRegister.throwIfFinishedRegistration("~internalAndWillBeRemovedSoon_onRollbackCommit");
261
+ RollbackCommit.register(callback);
262
+ };
258
263
  let extractRange = (filter, name, ecosystem) => {
259
264
  try {
260
265
  let inner = S$RescriptSchema.parseOrThrow(filter, ecosystem.onBlockFilterSchema);
@@ -341,7 +346,8 @@ function getGlobalIndexer() {
341
346
  "description",
342
347
  "chainIds",
343
348
  "chains",
344
- "onSlot"
349
+ "onSlot",
350
+ "~internalAndWillBeRemovedSoon_onRollbackCommit"
345
351
  ];
346
352
  break;
347
353
  }
@@ -353,7 +359,8 @@ function getGlobalIndexer() {
353
359
  "chains",
354
360
  "onEvent",
355
361
  "contractRegister",
356
- "onBlock"
362
+ "onBlock",
363
+ "~internalAndWillBeRemovedSoon_onRollbackCommit"
357
364
  ];
358
365
  }
359
366
  keysMemo.contents = keys;
@@ -376,6 +383,8 @@ function getGlobalIndexer() {
376
383
  case "onBlock" :
377
384
  case "onSlot" :
378
385
  return onBlockFn;
386
+ case "~internalAndWillBeRemovedSoon_onRollbackCommit" :
387
+ return onRollbackCommitFn;
379
388
  default:
380
389
  return Stdlib_JsError.throwWithMessage(`Field \`` + prop + `\` does not exist on \`indexer\`. Available fields: ` + getKeys().join(", ") + `.`);
381
390
  }
@@ -51,6 +51,9 @@ type updatedEffectCache = {
51
51
  type rollback = {
52
52
  targetCheckpointId: Internal.checkpointId,
53
53
  diffCheckpointId: Internal.checkpointId,
54
+ // Last valid block per chain affected by the rollback. Read by
55
+ // `RollbackCommit.fire` once the diff is durably written.
56
+ progressBlockNumberByChainId: dict<int>,
54
57
  }
55
58
 
56
59
  type updatedEntity = {
@@ -0,0 +1,32 @@
1
+ // Temporary, internal-only support for the unstable
2
+ // `indexer.~internalAndWillBeRemovedSoon_onRollbackCommit` API. The whole
3
+ // feature lives here plus two call sites: registration in `Main.res` and the
4
+ // fire on a successful rollback write in `InMemoryStore.res`. Delete those
5
+ // together with this module.
6
+ type args = {chainId: int, rollbackToBlock: int}
7
+ type callback = args => promise<unit>
8
+
9
+ let callbacks: array<callback> = []
10
+
11
+ let register = (callback: callback) => {
12
+ callbacks->Array.push(callback)
13
+ () =>
14
+ switch callbacks->Array.indexOf(callback) {
15
+ | -1 => ()
16
+ | index => callbacks->Array.splice(~start=index, ~remove=1, ~insert=[])
17
+ }
18
+ }
19
+
20
+ // Fired after a rollback diff is durably written, once per affected chain.
21
+ // `progressBlockNumberByChainId` is the last valid block per chain, taken from
22
+ // the in-memory store's rollback object. A throwing callback bubbles to the
23
+ // write loop's onError, crashing the indexer like a failed write.
24
+ let fire = async (~progressBlockNumberByChainId: dict<int>) => {
25
+ let _ = await progressBlockNumberByChainId
26
+ ->Dict.toArray
27
+ ->Array.flatMap(((chainIdKey, rollbackToBlock)) => {
28
+ let args = {chainId: chainIdKey->Int.fromString->Option.getUnsafe, rollbackToBlock}
29
+ callbacks->Array.map(callback => callback(args))
30
+ })
31
+ ->Promise.all
32
+ }
@@ -0,0 +1,35 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Stdlib_Int from "@rescript/runtime/lib/es6/Stdlib_Int.js";
4
+
5
+ let callbacks = [];
6
+
7
+ function register(callback) {
8
+ callbacks.push(callback);
9
+ return () => {
10
+ let index = callbacks.indexOf(callback);
11
+ if (index !== -1) {
12
+ callbacks.splice(index, 1);
13
+ return;
14
+ }
15
+ };
16
+ }
17
+
18
+ async function fire(progressBlockNumberByChainId) {
19
+ await Promise.all(Object.entries(progressBlockNumberByChainId).flatMap(param => {
20
+ let args_chainId = Stdlib_Int.fromString(param[0], undefined);
21
+ let args_rollbackToBlock = param[1];
22
+ let args = {
23
+ chainId: args_chainId,
24
+ rollbackToBlock: args_rollbackToBlock
25
+ };
26
+ return callbacks.map(callback => callback(args));
27
+ }));
28
+ }
29
+
30
+ export {
31
+ callbacks,
32
+ register,
33
+ fire,
34
+ }
35
+ /* No side effect */
@@ -41,25 +41,18 @@ let getSyncConfig = (
41
41
  let collectEventParams = (contracts: array<Internal.evmContractConfig>): array<
42
42
  HyperSyncClient.Decoder.eventParamsInput,
43
43
  > => {
44
- let seen = Dict.make()
45
44
  let result = []
46
45
  contracts->Array.forEach(contract => {
47
46
  contract.events->Array.forEach(event => {
48
- let key = event.sighash ++ "_" ++ event.topicCount->Int.toString
49
- switch seen->Dict.get(key) {
50
- | Some(_) => ()
51
- | None => {
52
- seen->Dict.set(key, true)
53
- result
54
- ->Array.push({
55
- HyperSyncClient.Decoder.sighash: event.sighash,
56
- topicCount: event.topicCount,
57
- eventName: event.name,
58
- params: event.paramsMetadata,
59
- })
60
- ->ignore
61
- }
62
- }
47
+ result
48
+ ->Array.push({
49
+ HyperSyncClient.Decoder.sighash: event.sighash,
50
+ topicCount: event.topicCount,
51
+ eventName: event.name,
52
+ contractName: contract.name,
53
+ params: event.paramsMetadata,
54
+ })
55
+ ->ignore
63
56
  })
64
57
  })
65
58
  result
@@ -22,24 +22,16 @@ function getSyncConfig(param) {
22
22
  }
23
23
 
24
24
  function collectEventParams(contracts) {
25
- let seen = {};
26
25
  let result = [];
27
26
  contracts.forEach(contract => {
28
27
  contract.events.forEach(event => {
29
- let key = event.sighash + "_" + event.topicCount.toString();
30
- let match = seen[key];
31
- if (match !== undefined) {
32
- return;
33
- } else {
34
- seen[key] = true;
35
- result.push({
36
- sighash: event.sighash,
37
- topicCount: event.topicCount,
38
- eventName: event.name,
39
- params: event.paramsMetadata
40
- });
41
- return;
42
- }
28
+ result.push({
29
+ sighash: event.sighash,
30
+ topicCount: event.topicCount,
31
+ eventName: event.name,
32
+ contractName: contract.name,
33
+ params: event.paramsMetadata
34
+ });
43
35
  });
44
36
  });
45
37
  return result;
@@ -322,11 +322,17 @@ module Decoder = {
322
322
  sighash: string,
323
323
  topicCount: int,
324
324
  eventName: string,
325
+ contractName: string,
325
326
  params: array<Internal.paramMeta>,
326
327
  }
327
328
 
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.
328
332
  type tWithParams = {
329
- decodeLogs: array<ResponseTypes.event> => promise<array<Nullable.t<Internal.eventParams>>>,
333
+ decodeLogs: array<ResponseTypes.event> => promise<
334
+ array<Nullable.t<dict<Internal.eventParams>>>,
335
+ >,
330
336
  }
331
337
 
332
338
  @send
@@ -348,7 +354,7 @@ module EventItems = {
348
354
  topicCount: int,
349
355
  block: ResponseTypes.block,
350
356
  transaction: ResponseTypes.transaction,
351
- params: Nullable.t<Internal.eventParams>,
357
+ params: Nullable.t<dict<Internal.eventParams>>,
352
358
  }
353
359
 
354
360
  type response = {
@@ -351,20 +351,23 @@ Learn more or get a free API token at: https://envio.dev/app/api-tokens`)
351
351
  ~blockNumber=item.block.number->Belt.Option.getUnsafe,
352
352
  )
353
353
 
354
- switch (maybeEventConfig, item.params) {
355
- | (Some(eventConfig), Value(decoded)) =>
356
- parsedQueueItems
357
- ->Array.push(makeEventBatchQueueItem(item, ~params=decoded, ~eventConfig))
358
- ->ignore
359
- | (Some(eventConfig), Null | Undefined) =>
360
- handleDecodeFailure(
361
- ~eventConfig,
362
- ~logIndex=item.logIndex,
363
- ~blockNumber=item.block.number->Belt.Option.getUnsafe,
364
- ~chainId,
365
- ~exn=UndefinedValue,
366
- )
367
- | (None, _) => () //ignore events that aren't registered
354
+ switch maybeEventConfig {
355
+ | None => () //ignore events that aren't registered
356
+ | Some(eventConfig) =>
357
+ switch item.params
358
+ ->Nullable.toOption
359
+ ->Option.flatMap(Dict.get(_, eventConfig.contractName)) {
360
+ | Some(params) =>
361
+ parsedQueueItems->Array.push(makeEventBatchQueueItem(item, ~params, ~eventConfig))->ignore
362
+ | None =>
363
+ handleDecodeFailure(
364
+ ~eventConfig,
365
+ ~logIndex=item.logIndex,
366
+ ~blockNumber=item.block.number->Belt.Option.getUnsafe,
367
+ ~chainId,
368
+ ~exn=UndefinedValue,
369
+ )
370
+ }
368
371
  }
369
372
  })
370
373
 
@@ -14,6 +14,7 @@ import * as ErrorHandling from "../ErrorHandling.res.mjs";
14
14
  import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
15
15
  import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
16
16
  import * as HyperSyncClient from "./HyperSyncClient.res.mjs";
17
+ import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
17
18
  import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
18
19
  import * as HyperSyncHeightStream from "./HyperSyncHeightStream.res.mjs";
19
20
 
@@ -215,32 +216,31 @@ Learn more or get a free API token at: https://envio.dev/app/api-tokens`);
215
216
  let parsedQueueItems = [];
216
217
  Belt_Array.forEach(pageUnsafe.items, item => {
217
218
  let maybeEventConfig = EventRouter.get(eventRouter, EventRouter.getEvmEventId(item.topic0, item.topicCount), item.srcAddress, item.block.number, indexingAddresses);
218
- let match = item.params;
219
219
  if (maybeEventConfig === undefined) {
220
220
  return;
221
221
  }
222
- if (match == null) {
223
- match === null;
224
- } else {
225
- parsedQueueItems.push(makeEventBatchQueueItem(item, match, maybeEventConfig));
226
- return;
227
- }
228
- let logIndex = item.logIndex;
229
- let blockNumber = item.block.number;
230
- let exn = {
231
- RE_EXN_ID: UndefinedValue
232
- };
233
- if (maybeEventConfig.isWildcard) {
222
+ let params = Stdlib_Option.flatMap(Primitive_option.fromNullable(item.params), __x => __x[maybeEventConfig.contractName]);
223
+ if (params !== undefined) {
224
+ parsedQueueItems.push(makeEventBatchQueueItem(item, Primitive_option.valFromOption(params), maybeEventConfig));
234
225
  return;
226
+ } else {
227
+ let logIndex = item.logIndex;
228
+ let blockNumber = item.block.number;
229
+ let exn = {
230
+ RE_EXN_ID: UndefinedValue
231
+ };
232
+ if (maybeEventConfig.isWildcard) {
233
+ return;
234
+ }
235
+ let msg = `Event ` + maybeEventConfig.name + ` was unexpectedly parsed as undefined`;
236
+ let logger$1 = Logging.createChildFrom(logger, {
237
+ chainId: chain,
238
+ blockNumber: blockNumber,
239
+ logIndex: logIndex,
240
+ decoder: "hypersync-client"
241
+ });
242
+ return ErrorHandling.mkLogAndRaise(logger$1, msg, exn);
235
243
  }
236
- let msg = `Event ` + maybeEventConfig.name + ` was unexpectedly parsed as undefined`;
237
- let logger$1 = Logging.createChildFrom(logger, {
238
- chainId: chain,
239
- blockNumber: blockNumber,
240
- logIndex: logIndex,
241
- decoder: "hypersync-client"
242
- });
243
- ErrorHandling.mkLogAndRaise(logger$1, msg, exn);
244
244
  });
245
245
  let parsingTimeElapsed = Hrtime.toSecondsFloat(Hrtime.timeSince(parsingTimeRef));
246
246
  let blockHashes = [];
@@ -1115,7 +1115,7 @@ let make = (
1115
1115
  ->Array.zip(parsedEvents)
1116
1116
  ->Array.filterMap(((
1117
1117
  log: Rpc.GetLogs.log,
1118
- maybeDecodedEvent: Nullable.t<Internal.eventParams>,
1118
+ maybeDecodedEvent: Nullable.t<dict<Internal.eventParams>>,
1119
1119
  )) => {
1120
1120
  let topic0 = log.topics[0]->Option.getOr("0x0")
1121
1121
  let routedAddress = if lowercaseAddresses {
@@ -1132,8 +1132,10 @@ let make = (
1132
1132
  ) {
1133
1133
  | None => None
1134
1134
  | Some(eventConfig) =>
1135
- switch maybeDecodedEvent {
1136
- | Value(decoded) =>
1135
+ switch maybeDecodedEvent
1136
+ ->Nullable.toOption
1137
+ ->Option.flatMap(Dict.get(_, eventConfig.contractName)) {
1138
+ | Some(decoded) =>
1137
1139
  Some(
1138
1140
  (
1139
1141
  async () => {
@@ -1176,7 +1178,7 @@ let make = (
1176
1178
  }
1177
1179
  )(),
1178
1180
  )
1179
- | Null | Undefined => None
1181
+ | None => None
1180
1182
  }
1181
1183
  }
1182
1184
  })
@@ -1064,54 +1064,59 @@ function make(param) {
1064
1064
  };
1065
1065
  }
1066
1066
  let parsedQueueItems = await Promise.all(Stdlib_Array.filterMap(Stdlib_Array.zip(logs, parsedEvents), param => {
1067
- let maybeDecodedEvent = param[1];
1068
1067
  let log = param[0];
1069
1068
  let topic0 = Stdlib_Option.getOr(log.topics[0], "0x0");
1070
1069
  let routedAddress = lowercaseAddresses ? Address.Evm.fromAddressLowercaseOrThrow(log.address) : Address.Evm.fromAddressOrThrow(log.address);
1071
1070
  let eventConfig = EventRouter.get(eventRouter, EventRouter.getEvmEventId(topic0, log.topics.length), routedAddress, log.blockNumber, indexingAddresses);
1072
- if (eventConfig !== undefined && maybeDecodedEvent !== null && maybeDecodedEvent !== undefined) {
1073
- return (async () => {
1074
- let match;
1075
- try {
1076
- match = await Promise.all([
1077
- getEventBlockOrThrow(log, eventConfig.selectedBlockFields),
1078
- getEventTransactionOrThrow(log, eventConfig.selectedTransactionFields)
1079
- ]);
1080
- } catch (raw_exn) {
1081
- let exn = Primitive_exceptions.internalToException(raw_exn);
1082
- throw {
1083
- RE_EXN_ID: Source.GetItemsError,
1084
- _1: {
1085
- TAG: "FailedGettingFieldSelection",
1086
- exn: exn,
1087
- blockNumber: log.blockNumber,
1088
- logIndex: log.logIndex,
1089
- message: "Failed getting selected fields. Please double-check your RPC provider returns correct data."
1090
- },
1091
- Error: new Error()
1092
- };
1093
- }
1094
- let block = match[0];
1095
- return {
1096
- kind: 0,
1097
- eventConfig: eventConfig,
1098
- timestamp: block.timestamp,
1099
- chain: chain,
1100
- blockNumber: block.number,
1101
- logIndex: log.logIndex,
1102
- event: {
1103
- contractName: eventConfig.contractName,
1104
- eventName: eventConfig.name,
1105
- params: maybeDecodedEvent,
1106
- chainId: chain,
1107
- srcAddress: routedAddress,
1071
+ if (eventConfig === undefined) {
1072
+ return;
1073
+ }
1074
+ let decoded = Stdlib_Option.flatMap(Primitive_option.fromNullable(param[1]), __x => __x[eventConfig.contractName]);
1075
+ if (decoded === undefined) {
1076
+ return;
1077
+ }
1078
+ let decoded$1 = Primitive_option.valFromOption(decoded);
1079
+ return (async () => {
1080
+ let match;
1081
+ try {
1082
+ match = await Promise.all([
1083
+ getEventBlockOrThrow(log, eventConfig.selectedBlockFields),
1084
+ getEventTransactionOrThrow(log, eventConfig.selectedTransactionFields)
1085
+ ]);
1086
+ } catch (raw_exn) {
1087
+ let exn = Primitive_exceptions.internalToException(raw_exn);
1088
+ throw {
1089
+ RE_EXN_ID: Source.GetItemsError,
1090
+ _1: {
1091
+ TAG: "FailedGettingFieldSelection",
1092
+ exn: exn,
1093
+ blockNumber: log.blockNumber,
1108
1094
  logIndex: log.logIndex,
1109
- transaction: match[1],
1110
- block: block
1111
- }
1095
+ message: "Failed getting selected fields. Please double-check your RPC provider returns correct data."
1096
+ },
1097
+ Error: new Error()
1112
1098
  };
1113
- })();
1114
- }
1099
+ }
1100
+ let block = match[0];
1101
+ return {
1102
+ kind: 0,
1103
+ eventConfig: eventConfig,
1104
+ timestamp: block.timestamp,
1105
+ chain: chain,
1106
+ blockNumber: block.number,
1107
+ logIndex: log.logIndex,
1108
+ event: {
1109
+ contractName: eventConfig.contractName,
1110
+ eventName: eventConfig.name,
1111
+ params: decoded$1,
1112
+ chainId: chain,
1113
+ srcAddress: routedAddress,
1114
+ logIndex: log.logIndex,
1115
+ transaction: match[1],
1116
+ block: block
1117
+ }
1118
+ };
1119
+ })();
1115
1120
  }));
1116
1121
  let optFirstBlockParent = await firstBlockParentPromise;
1117
1122
  let totalTimeElapsed = Hrtime.toSecondsFloat(Hrtime.timeSince(startFetchingBatchTimeRef));