envio 3.5.0-alpha.2 → 3.5.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 (129) hide show
  1. package/package.json +6 -6
  2. package/src/Batch.res +8 -8
  3. package/src/Batch.res.mjs +4 -3
  4. package/src/BatchProcessing.res +24 -0
  5. package/src/BatchProcessing.res.mjs +12 -0
  6. package/src/ChainFetching.res +20 -19
  7. package/src/ChainFetching.res.mjs +14 -14
  8. package/src/ChainId.res +58 -0
  9. package/src/ChainId.res.mjs +49 -0
  10. package/src/ChainId.resi +27 -0
  11. package/src/ChainMap.res +12 -26
  12. package/src/ChainMap.res.mjs +5 -41
  13. package/src/ChainMap.resi +5 -20
  14. package/src/ChainMetadata.res +1 -1
  15. package/src/ChainMetadata.res.mjs +3 -2
  16. package/src/ChainState.res +45 -24
  17. package/src/ChainState.res.mjs +40 -16
  18. package/src/ChainState.resi +3 -1
  19. package/src/Config.res +43 -26
  20. package/src/Config.res.mjs +19 -16
  21. package/src/ContractRegisterContext.res +1 -1
  22. package/src/ContractRegisterContext.res.mjs +1 -1
  23. package/src/Core.res +1 -0
  24. package/src/CrossChainState.res +90 -22
  25. package/src/CrossChainState.res.mjs +55 -16
  26. package/src/CrossChainState.resi +5 -1
  27. package/src/Env.res +0 -3
  28. package/src/Env.res.mjs +0 -3
  29. package/src/EventConfigBuilder.res +1 -1
  30. package/src/EventProcessing.res +4 -4
  31. package/src/EventProcessing.res.mjs +5 -5
  32. package/src/FetchState.res +489 -153
  33. package/src/FetchState.res.mjs +399 -129
  34. package/src/FinalizeBackfill.res +61 -0
  35. package/src/FinalizeBackfill.res.mjs +44 -0
  36. package/src/HandlerRegister.res +8 -8
  37. package/src/HandlerRegister.res.mjs +5 -4
  38. package/src/HandlerRegister.resi +1 -1
  39. package/src/InMemoryStore.res +4 -0
  40. package/src/InMemoryStore.res.mjs +1 -1
  41. package/src/InMemoryTable.res +15 -15
  42. package/src/InMemoryTable.res.mjs +14 -14
  43. package/src/IndexerLoop.res +9 -2
  44. package/src/IndexerLoop.res.mjs +8 -1
  45. package/src/IndexerState.res +52 -23
  46. package/src/IndexerState.res.mjs +52 -14
  47. package/src/IndexerState.resi +11 -6
  48. package/src/Internal.res +19 -17
  49. package/src/Internal.res.mjs +18 -9
  50. package/src/LoadLayer.res +10 -2
  51. package/src/LoadLayer.res.mjs +3 -1
  52. package/src/LogSelection.res +2 -2
  53. package/src/Main.res +7 -11
  54. package/src/Main.res.mjs +4 -6
  55. package/src/Metrics.res +6 -6
  56. package/src/Metrics.res.mjs +4 -3
  57. package/src/Persistence.res +23 -4
  58. package/src/PgStorage.res +447 -100
  59. package/src/PgStorage.res.mjs +285 -99
  60. package/src/RawEvent.res +1 -2
  61. package/src/RawEvent.res.mjs +1 -1
  62. package/src/Rollback.res +18 -20
  63. package/src/Rollback.res.mjs +9 -9
  64. package/src/RollbackCommit.res +2 -2
  65. package/src/RollbackCommit.res.mjs +3 -3
  66. package/src/SafeCheckpointTracking.res +2 -2
  67. package/src/SimulateDeadInputTracker.res +17 -21
  68. package/src/SimulateDeadInputTracker.res.mjs +9 -8
  69. package/src/SimulateItems.res +8 -10
  70. package/src/SimulateItems.res.mjs +9 -10
  71. package/src/Sink.res +2 -2
  72. package/src/Sink.res.mjs +3 -2
  73. package/src/TestIndexer.res +14 -14
  74. package/src/TestIndexer.res.mjs +16 -10
  75. package/src/UserContext.res +2 -2
  76. package/src/UserContext.res.mjs +2 -1
  77. package/src/Utils.res +0 -4
  78. package/src/Utils.res.mjs +1 -6
  79. package/src/bindings/ClickHouse.res +20 -2
  80. package/src/bindings/ClickHouse.res.mjs +25 -14
  81. package/src/db/EntityFilter.res +0 -4
  82. package/src/db/EntityFilter.res.mjs +1 -8
  83. package/src/db/EntityHistory.res +1 -1
  84. package/src/db/IndexCatalog.res +248 -0
  85. package/src/db/IndexCatalog.res.mjs +222 -0
  86. package/src/db/IndexDefinition.res +131 -0
  87. package/src/db/IndexDefinition.res.mjs +138 -0
  88. package/src/db/IndexManager.res +145 -0
  89. package/src/db/IndexManager.res.mjs +130 -0
  90. package/src/db/InternalTable.res +54 -23
  91. package/src/db/InternalTable.res.mjs +38 -23
  92. package/src/db/Table.res +24 -14
  93. package/src/db/Table.res.mjs +21 -16
  94. package/src/sources/AddressSet.res +5 -4
  95. package/src/sources/AddressStore.res +25 -14
  96. package/src/sources/AddressStore.res.mjs +10 -12
  97. package/src/sources/Evm.res +2 -2
  98. package/src/sources/Evm.res.mjs +1 -1
  99. package/src/sources/EvmChain.res +3 -3
  100. package/src/sources/EvmChain.res.mjs +3 -3
  101. package/src/sources/EvmHyperSyncSource.res +7 -7
  102. package/src/sources/EvmHyperSyncSource.res.mjs +6 -6
  103. package/src/sources/Fuel.res +2 -2
  104. package/src/sources/Fuel.res.mjs +1 -1
  105. package/src/sources/FuelHyperSyncClient.res +3 -0
  106. package/src/sources/FuelHyperSyncClient.res.mjs +1 -0
  107. package/src/sources/FuelHyperSyncSource.res +5 -7
  108. package/src/sources/FuelHyperSyncSource.res.mjs +5 -5
  109. package/src/sources/HyperSync.resi +2 -2
  110. package/src/sources/HyperSyncClient.res +5 -0
  111. package/src/sources/HyperSyncClient.res.mjs +1 -0
  112. package/src/sources/RpcSource.res +13 -14
  113. package/src/sources/RpcSource.res.mjs +13 -12
  114. package/src/sources/SimulateSource.res +42 -15
  115. package/src/sources/SimulateSource.res.mjs +27 -9
  116. package/src/sources/Source.res +1 -5
  117. package/src/sources/SourceManager.res +12 -12
  118. package/src/sources/SourceManager.res.mjs +11 -10
  119. package/src/sources/SourceManager.resi +2 -2
  120. package/src/sources/Svm.res +4 -5
  121. package/src/sources/Svm.res.mjs +5 -4
  122. package/src/sources/SvmHyperSyncClient.res +3 -0
  123. package/src/sources/SvmHyperSyncClient.res.mjs +1 -0
  124. package/src/sources/SvmHyperSyncSource.res +4 -4
  125. package/src/sources/SvmHyperSyncSource.res.mjs +3 -3
  126. package/src/tui/Tui.res +1 -1
  127. package/src/tui/Tui.res.mjs +2 -1
  128. package/src/tui/components/CustomHooks.res +5 -4
  129. package/src/tui/components/CustomHooks.res.mjs +4 -2
@@ -96,7 +96,8 @@ function getPgFieldName(fieldOrDerived) {
96
96
 
97
97
  let idFieldName = "id";
98
98
 
99
- function getPgFieldType(fieldType, pgSchema, isArray, isNumericArrayAsText, isNullable) {
99
+ function getPgFieldType(fieldType, pgSchema, isArray, isNumericArrayAsText, isNullable, chainIdModeOpt) {
100
+ let chainIdMode = chainIdModeOpt !== undefined ? chainIdModeOpt : "int32";
100
101
  let columnType;
101
102
  if (typeof fieldType !== "object") {
102
103
  switch (fieldType) {
@@ -109,6 +110,9 @@ function getPgFieldType(fieldType, pgSchema, isArray, isNumericArrayAsText, isNu
109
110
  case "Int32" :
110
111
  columnType = "INTEGER";
111
112
  break;
113
+ case "ChainId" :
114
+ columnType = chainIdMode === "int32" ? "INTEGER" : "BIGINT";
115
+ break;
112
116
  case "Number" :
113
117
  columnType = "DOUBLE PRECISION";
114
118
  break;
@@ -153,12 +157,12 @@ function getPgFieldType(fieldType, pgSchema, isArray, isNumericArrayAsText, isNu
153
157
  );
154
158
  }
155
159
 
156
- function mkTable(tableName, compositeIndicesOpt, fields, description) {
157
- let compositeIndices = compositeIndicesOpt !== undefined ? compositeIndicesOpt : [];
160
+ function mkTable(tableName, compositeIndexesOpt, fields, description) {
161
+ let compositeIndexes = compositeIndexesOpt !== undefined ? compositeIndexesOpt : [];
158
162
  return {
159
163
  tableName: tableName,
160
164
  fields: fields,
161
- compositeIndices: compositeIndices,
165
+ compositeIndexes: compositeIndexes,
162
166
  description: description
163
167
  };
164
168
  }
@@ -247,7 +251,7 @@ function getIdFieldOrThrow(table) {
247
251
  }
248
252
 
249
253
  function getIdPgFieldType(table, pgSchema) {
250
- return getPgFieldType(getIdFieldOrThrow(table).fieldType, pgSchema, false, false, false);
254
+ return getPgFieldType(getIdFieldOrThrow(table).fieldType, pgSchema, false, false, false, undefined);
251
255
  }
252
256
 
253
257
  function getIdSchema(table) {
@@ -304,8 +308,8 @@ let pgRowsSchema = Utils.$$WeakMap.memoize(table => makeRowsSchema(table, getPgD
304
308
 
305
309
  let NonExistingTableField = /* @__PURE__ */Primitive_exceptions.create("Table.NonExistingTableField");
306
310
 
307
- function getUnfilteredCompositeIndicesUnsafe(table) {
308
- return table.compositeIndices.map(compositeIndex => compositeIndex.map(indexField => {
311
+ function getUnfilteredCompositeIndexesUnsafe(table) {
312
+ return table.compositeIndexes.map(compositeIndex => compositeIndex.map(indexField => {
309
313
  let field = getFieldByName(table, indexField.fieldName);
310
314
  let dbFieldName;
311
315
  if (field !== undefined) {
@@ -324,7 +328,8 @@ function getUnfilteredCompositeIndicesUnsafe(table) {
324
328
  }));
325
329
  }
326
330
 
327
- function toSqlParams(table, schema, pgSchema) {
331
+ function toSqlParams(table, schema, pgSchema, chainIdModeOpt) {
332
+ let chainIdMode = chainIdModeOpt !== undefined ? chainIdModeOpt : "int32";
328
333
  let quotedFieldNames = [];
329
334
  let quotedNonPrimaryFieldNames = [];
330
335
  let arrayFieldTypes = [];
@@ -395,7 +400,7 @@ function toSqlParams(table, schema, pgSchema) {
395
400
  let tmp;
396
401
  if (field$1.TAG === "Field") {
397
402
  let f = field$1._0;
398
- let pgFieldType = getPgFieldType(f.fieldType, pgSchema, true, false, f.isNullable);
403
+ let pgFieldType = getPgFieldType(f.fieldType, pgSchema, true, false, f.isNullable, chainIdMode);
399
404
  let match = f.fieldType;
400
405
  tmp = typeof match !== "object" ? (
401
406
  match === "Boolean" ? "INTEGER" + `[]::` + pgFieldType : pgFieldType
@@ -419,7 +424,7 @@ function toSqlParams(table, schema, pgSchema) {
419
424
  };
420
425
  }
421
426
 
422
- function getSingleIndices(table) {
427
+ function getSingleIndexes(table) {
423
428
  let indexFields = Stdlib_Array.filterMap(table.fields, field => {
424
429
  if (field.TAG !== "Field") {
425
430
  return;
@@ -429,7 +434,7 @@ function getSingleIndices(table) {
429
434
  return getPgDbFieldName(field$1);
430
435
  }
431
436
  });
432
- return Array.from(new Set(Stdlib_Array.filterMap(getUnfilteredCompositeIndicesUnsafe(table), cidx => {
437
+ return Array.from(new Set(Stdlib_Array.filterMap(getUnfilteredCompositeIndexesUnsafe(table), cidx => {
433
438
  if (cidx.length !== 1) {
434
439
  return;
435
440
  }
@@ -438,8 +443,8 @@ function getSingleIndices(table) {
438
443
  }).concat([indexFields]).flat())).toSorted(Primitive_string.compare);
439
444
  }
440
445
 
441
- function getCompositeIndices(table) {
442
- return getUnfilteredCompositeIndicesUnsafe(table).filter(ind => ind.length > 1);
446
+ function getCompositeIndexes(table) {
447
+ return getUnfilteredCompositeIndexesUnsafe(table).filter(ind => ind.length > 1);
443
448
  }
444
449
 
445
450
  export {
@@ -473,9 +478,9 @@ export {
473
478
  rowsSchema,
474
479
  pgRowsSchema,
475
480
  NonExistingTableField,
476
- getUnfilteredCompositeIndicesUnsafe,
481
+ getUnfilteredCompositeIndexesUnsafe,
477
482
  toSqlParams,
478
- getSingleIndices,
479
- getCompositeIndices,
483
+ getSingleIndexes,
484
+ getCompositeIndexes,
480
485
  }
481
486
  /* idsArraySchema Not a pure module */
@@ -15,10 +15,11 @@ type startBlockGroup = {startBlock: int, count: int}
15
15
  // fetch state can size and split partitions without ever walking the addresses.
16
16
  @send external countFor: (t, string) => int = "countFor"
17
17
 
18
- // The chain-wide address gate, reachable through any set of the store. Not set
19
- // membership: the simulate source has no native query boundary, so it applies
20
- // the same gate every real source applies while routing.
21
- @send external has: (t, Address.t, string, int) => bool = "has"
18
+ // This set holds the address under the contract and it has already started at
19
+ // the block — the gate a real source's router applies to a server-side
20
+ // address-filtered query. The temporal half still comes from the store: a
21
+ // merged partition's addresses don't all start at the same block.
22
+ @send external containsAt: (t, Address.t, string, int) => bool = "containsAt"
22
23
 
23
24
  @send external contractNames: t => array<string> = "contractNames"
24
25
 
@@ -67,28 +67,39 @@ let make = (~ecosystem: Ecosystem.name, ~shouldChecksum: bool, ~contracts: array
67
67
  }
68
68
 
69
69
  // The contracts of a chain that have events, with the earliest block any of
70
- // their events may fire at.
70
+ // their events may fire at. `None` means unrestricted, so it wins over any
71
+ // `Some`: one registration without a start block makes the whole contract's
72
+ // address gate open from the chain's start, and the per-registration start
73
+ // block still holds back the registrations that declared one.
71
74
  let contractsOf = (~onEventRegistrations: array<Internal.onEventRegistration>): array<contract> => {
72
- let startBlocks = Dict.make()
75
+ // Only ever holds a declared start block, so a missing key is unambiguous —
76
+ // storing `None` in a dict would be indistinguishable from "not seen yet".
77
+ let startBlocks: dict<int> = Dict.make()
78
+ let unrestricted = Utils.Set.make()
73
79
  let names = []
74
80
  onEventRegistrations->Array.forEach(reg => {
75
81
  let name = reg.eventConfig.contractName
76
- switch startBlocks->Utils.Dict.dangerouslyGetNonOption(name) {
77
- | None =>
82
+ if !(names->Array.includes(name)) {
78
83
  names->Array.push(name)->ignore
79
- startBlocks->Dict.set(name, reg.startBlock)
80
- | Some(existing) =>
84
+ }
85
+ switch reg.startBlock {
86
+ | None => unrestricted->Utils.Set.add(name)->ignore
87
+ | Some(startBlock) =>
81
88
  startBlocks->Dict.set(
82
89
  name,
83
- switch (existing, reg.startBlock) {
84
- | (Some(a), Some(b)) => Some(Pervasives.min(a, b))
85
- | (Some(_) as s, None) | (None, Some(_) as s) => s
86
- | (None, None) => None
90
+ switch startBlocks->Utils.Dict.dangerouslyGetNonOption(name) {
91
+ | Some(existing) => Pervasives.min(existing, startBlock)
92
+ | None => startBlock
87
93
  },
88
94
  )
89
95
  }
90
96
  })
91
- names->Array.map(name => {name, startBlock: startBlocks->Dict.getUnsafe(name)})
97
+ names->Array.map(name => {
98
+ name,
99
+ startBlock: unrestricted->Utils.Set.has(name)
100
+ ? None
101
+ : startBlocks->Utils.Dict.dangerouslyGetNonOption(name),
102
+ })
92
103
  }
93
104
 
94
105
  @send external nextId: t => int = "nextId"
@@ -108,9 +119,9 @@ external startBlockGroups: (t, string) => array<AddressSet.startBlockGroup> = "s
108
119
  @send external contractCount: (t, string) => int = "contractCount"
109
120
  @send external size: t => int = "size"
110
121
 
111
- // The gate routing applies, exposed for the simulate source — it has no real
112
- // query boundary to gate at.
113
- @send external has: (t, Address.t, string, int) => bool = "has"
122
+ // The chain-wide gate routing applies, exposed for the simulate source — it has
123
+ // no real query boundary to gate at.
124
+ @send external isIndexedAt: (t, Address.t, string, int) => bool = "isIndexedAt"
114
125
 
115
126
  // Drops every address registered after the target block, returning how many
116
127
  // were dropped. Ids are tombstoned rather than reused, so sets built before the
@@ -19,26 +19,24 @@ function make(ecosystem, shouldChecksum, contracts) {
19
19
 
20
20
  function contractsOf(onEventRegistrations) {
21
21
  let startBlocks = {};
22
+ let unrestricted = new Set();
22
23
  let names = [];
23
24
  onEventRegistrations.forEach(reg => {
24
25
  let name = reg.eventConfig.contractName;
25
- let existing = startBlocks[name];
26
- if (existing !== undefined) {
27
- let existing$1 = Primitive_option.valFromOption(existing);
28
- let match = reg.startBlock;
29
- startBlocks[name] = existing$1 !== undefined ? (
30
- match !== undefined ? Primitive_int.min(existing$1, match) : existing$1
31
- ) : (
32
- match !== undefined ? match : undefined
33
- );
26
+ if (!names.includes(name)) {
27
+ names.push(name);
28
+ }
29
+ let startBlock = reg.startBlock;
30
+ if (startBlock !== undefined) {
31
+ let existing = startBlocks[name];
32
+ startBlocks[name] = existing !== undefined ? Primitive_int.min(existing, startBlock) : startBlock;
34
33
  return;
35
34
  }
36
- names.push(name);
37
- startBlocks[name] = reg.startBlock;
35
+ unrestricted.add(name);
38
36
  });
39
37
  return names.map(name => ({
40
38
  name: name,
41
- startBlock: startBlocks[name]
39
+ startBlock: unrestricted.has(name) ? undefined : startBlocks[name]
42
40
  }));
43
41
  }
44
42
 
@@ -6,7 +6,7 @@ type payload = {
6
6
  contractName: string,
7
7
  eventName: string,
8
8
  params: Internal.eventParams,
9
- chainId: int,
9
+ chainId: ChainId.t,
10
10
  srcAddress: Address.t,
11
11
  logIndex: int,
12
12
  transaction?: Internal.eventTransaction,
@@ -106,7 +106,7 @@ let make = (~logger: Pino.t): Ecosystem.t => {
106
106
  ~params={
107
107
  "contract": eventItem.onEventRegistration.eventConfig.contractName,
108
108
  "event": eventItem.onEventRegistration.eventConfig.name,
109
- "chainId": eventItem.chain->ChainMap.Chain.toChainId,
109
+ "chainId": eventItem.chainId,
110
110
  "block": eventItem.blockNumber,
111
111
  "logIndex": eventItem.logIndex,
112
112
  "address": (eventItem.payload->toPayload).srcAddress,
@@ -64,7 +64,7 @@ function make(logger) {
64
64
  toEventLogger: eventItem => Logging.createChildFrom(logger, {
65
65
  contract: eventItem.onEventRegistration.eventConfig.contractName,
66
66
  event: eventItem.onEventRegistration.eventConfig.name,
67
- chainId: eventItem.chain,
67
+ chainId: eventItem.chainId,
68
68
  block: eventItem.blockNumber,
69
69
  logIndex: eventItem.logIndex,
70
70
  address: eventItem.payload.srcAddress
@@ -40,7 +40,7 @@ let getSyncConfig = (
40
40
  }
41
41
 
42
42
  let makeSources = (
43
- ~chain,
43
+ ~chainId,
44
44
  ~onEventRegistrations: array<Internal.evmOnEventRegistration>,
45
45
  ~hyperSync,
46
46
  ~rpcs: array<rpc>,
@@ -50,7 +50,7 @@ let makeSources = (
50
50
  let sources = switch hyperSync {
51
51
  | Some(endpointUrl) => [
52
52
  EvmHyperSyncSource.make({
53
- chain,
53
+ chainId,
54
54
  endpointUrl,
55
55
  onEventRegistrations,
56
56
  apiToken: Env.envioApiToken,
@@ -66,7 +66,7 @@ let makeSources = (
66
66
  }
67
67
  rpcs->Array.forEach(({?syncConfig, url, sourceFor, ?ws, ?headers}) => {
68
68
  let source = RpcSource.make({
69
- chain,
69
+ chainId,
70
70
  sourceFor,
71
71
  syncConfig: getSyncConfig(syncConfig->Option.getOr({})),
72
72
  url,
@@ -19,9 +19,9 @@ function getSyncConfig(param) {
19
19
  };
20
20
  }
21
21
 
22
- function makeSources(chain, onEventRegistrations, hyperSync, rpcs, lowercaseAddresses, addressStore) {
22
+ function makeSources(chainId, onEventRegistrations, hyperSync, rpcs, lowercaseAddresses, addressStore) {
23
23
  let sources = hyperSync !== undefined ? [EvmHyperSyncSource.make({
24
- chain: chain,
24
+ chainId: chainId,
25
25
  endpointUrl: hyperSync,
26
26
  onEventRegistrations: onEventRegistrations,
27
27
  apiToken: Env.envioApiToken,
@@ -37,7 +37,7 @@ function makeSources(chain, onEventRegistrations, hyperSync, rpcs, lowercaseAddr
37
37
  sourceFor: param.sourceFor,
38
38
  syncConfig: getSyncConfig(Stdlib_Option.getOr(param.syncConfig, {})),
39
39
  url: param.url,
40
- chain: chain,
40
+ chainId: chainId,
41
41
  onEventRegistrations: onEventRegistrations,
42
42
  lowercaseAddresses: lowercaseAddresses,
43
43
  addressStore: addressStore,
@@ -6,7 +6,7 @@ open Source
6
6
  let isUnauthorizedError = (message: string) => message->String.includes("401 Unauthorized")
7
7
 
8
8
  type options = {
9
- chain: ChainMap.Chain.t,
9
+ chainId: ChainId.t,
10
10
  endpointUrl: string,
11
11
  // The chain's registrations, indexed by their sequential `index`.
12
12
  onEventRegistrations: array<Internal.evmOnEventRegistration>,
@@ -22,7 +22,7 @@ type options = {
22
22
 
23
23
  let make = (
24
24
  {
25
- chain,
25
+ chainId,
26
26
  endpointUrl,
27
27
  onEventRegistrations,
28
28
  apiToken,
@@ -70,7 +70,7 @@ Learn more or get a free Envio API token at: https://envio.dev/app/api-tokens`)
70
70
 
71
71
  Internal.Event({
72
72
  onEventRegistration: (onEventRegistration :> Internal.onEventRegistration),
73
- chain,
73
+ chainId,
74
74
  blockNumber: item.blockNumber,
75
75
  logIndex,
76
76
  transactionIndex,
@@ -79,7 +79,7 @@ Learn more or get a free Envio API token at: https://envio.dev/app/api-tokens`)
79
79
  payload: {
80
80
  contractName: onEventRegistration.eventConfig.contractName,
81
81
  eventName: onEventRegistration.eventConfig.name,
82
- chainId: chain->ChainMap.Chain.toChainId,
82
+ chainId: chainId,
83
83
  params: item.params,
84
84
  srcAddress,
85
85
  logIndex,
@@ -253,7 +253,7 @@ Learn more or get a free Envio API token at: https://envio.dev/app/api-tokens`)
253
253
  ~client,
254
254
  ~blockNumbers,
255
255
  ~sourceName=name,
256
- ~chainId=chain->ChainMap.Chain.toChainId,
256
+ ~chainId=chainId,
257
257
  ~logger,
258
258
  )->Promise.thenResolve(((queryRes, requestStats)) => {
259
259
  Source.result: queryRes->HyperSync.mapExn,
@@ -263,7 +263,7 @@ Learn more or get a free Envio API token at: https://envio.dev/app/api-tokens`)
263
263
  {
264
264
  name,
265
265
  sourceFor: Sync,
266
- chain,
266
+ chainId,
267
267
  pollingInterval: 100,
268
268
  poweredByHyperSync: true,
269
269
  getBlockHashes,
@@ -290,7 +290,7 @@ Learn more or get a free Envio API token at: https://envio.dev/app/api-tokens`)
290
290
  HyperSyncHeightStream.subscribe(
291
291
  ~hyperSyncUrl=endpointUrl,
292
292
  ~apiToken,
293
- ~chainId=chain->ChainMap.Chain.toChainId,
293
+ ~chainId=chainId,
294
294
  ~onHeight,
295
295
  ),
296
296
  }
@@ -21,7 +21,7 @@ function make(param) {
21
21
  let apiToken = param.apiToken;
22
22
  let onEventRegistrations = param.onEventRegistrations;
23
23
  let endpointUrl = param.endpointUrl;
24
- let chain = param.chain;
24
+ let chainId = param.chainId;
25
25
  let name = "HyperSync";
26
26
  let apiToken$1 = apiToken !== undefined ? apiToken : Stdlib_JsError.throwWithMessage(`An Envio API token is required for using HyperSync as a data-source.
27
27
  Set the ENVIO_API_TOKEN environment variable in your .env file.
@@ -38,7 +38,7 @@ Learn more or get a free Envio API token at: https://envio.dev/app/api-tokens`);
38
38
  return {
39
39
  kind: 0,
40
40
  onEventRegistration: onEventRegistration,
41
- chain: chain,
41
+ chainId: chainId,
42
42
  blockNumber: item.blockNumber,
43
43
  logIndex: logIndex,
44
44
  transactionIndex: item.transactionIndex,
@@ -46,7 +46,7 @@ Learn more or get a free Envio API token at: https://envio.dev/app/api-tokens`);
46
46
  contractName: onEventRegistration.eventConfig.contractName,
47
47
  eventName: onEventRegistration.eventConfig.name,
48
48
  params: item.params,
49
- chainId: chain,
49
+ chainId: chainId,
50
50
  srcAddress: item.srcAddress,
51
51
  logIndex: logIndex
52
52
  }
@@ -170,14 +170,14 @@ Learn more or get a free Envio API token at: https://envio.dev/app/api-tokens`);
170
170
  requestStats: requestStats
171
171
  };
172
172
  };
173
- let getBlockHashes = (blockNumbers, logger) => HyperSync.queryBlockDataMulti(client, blockNumbers, name, chain, logger).then(param => ({
173
+ let getBlockHashes = (blockNumbers, logger) => HyperSync.queryBlockDataMulti(client, blockNumbers, name, chainId, logger).then(param => ({
174
174
  result: HyperSync.mapExn(param[0]),
175
175
  requestStats: param[1]
176
176
  }));
177
177
  return {
178
178
  name: name,
179
179
  sourceFor: "Sync",
180
- chain: chain,
180
+ chainId: chainId,
181
181
  poweredByHyperSync: true,
182
182
  pollingInterval: 100,
183
183
  getBlockHashes: getBlockHashes,
@@ -224,7 +224,7 @@ Learn more or get a free Envio API token at: https://envio.dev/app/api-tokens`);
224
224
  };
225
225
  },
226
226
  getItemsOrThrow: getItemsOrThrow,
227
- createHeightSubscription: onHeight => HyperSyncHeightStream.subscribe(endpointUrl, apiToken$1, chain, onHeight)
227
+ createHeightSubscription: onHeight => HyperSyncHeightStream.subscribe(endpointUrl, apiToken$1, chainId, onHeight)
228
228
  };
229
229
  }
230
230
 
@@ -4,7 +4,7 @@ type payload = {
4
4
  contractName: string,
5
5
  eventName: string,
6
6
  params: Internal.eventParams,
7
- chainId: int,
7
+ chainId: ChainId.t,
8
8
  srcAddress: Address.t,
9
9
  logIndex: int,
10
10
  transaction: Internal.eventTransaction,
@@ -48,7 +48,7 @@ let make = (~logger: Pino.t): Ecosystem.t => {
48
48
  ~params={
49
49
  "contract": eventItem.onEventRegistration.eventConfig.contractName,
50
50
  "event": eventItem.onEventRegistration.eventConfig.name,
51
- "chainId": eventItem.chain->ChainMap.Chain.toChainId,
51
+ "chainId": eventItem.chainId,
52
52
  "block": eventItem.blockNumber,
53
53
  "logIndex": eventItem.logIndex,
54
54
  "address": (eventItem.payload->toPayload).srcAddress,
@@ -25,7 +25,7 @@ function make(logger) {
25
25
  toEventLogger: eventItem => Logging.createChildFrom(logger, {
26
26
  contract: eventItem.onEventRegistration.eventConfig.contractName,
27
27
  event: eventItem.onEventRegistration.eventConfig.name,
28
- chainId: eventItem.chain,
28
+ chainId: eventItem.chainId,
29
29
  block: eventItem.blockNumber,
30
30
  logIndex: eventItem.logIndex,
31
31
  address: eventItem.payload.srcAddress
@@ -22,6 +22,8 @@ module Registration = {
22
22
  eventName: string,
23
23
  contractName: string,
24
24
  isWildcard: bool,
25
+ // Earliest block height this registration accepts; `None` is unrestricted.
26
+ startBlock: option<int>,
25
27
  kind: kind,
26
28
  // The LogData `rb` value as a decimal string; absent for other kinds.
27
29
  logId?: string,
@@ -45,6 +47,7 @@ module Registration = {
45
47
  eventName: eventConfig.name,
46
48
  contractName: eventConfig.contractName,
47
49
  isWildcard: reg.isWildcard,
50
+ startBlock: reg.startBlock,
48
51
  kind,
49
52
  ?logId,
50
53
  }
@@ -46,6 +46,7 @@ function fromOnEventRegistrations(onEventRegistrations) {
46
46
  eventName: eventConfig.name,
47
47
  contractName: eventConfig.contractName,
48
48
  isWildcard: reg.isWildcard,
49
+ startBlock: reg.startBlock,
49
50
  kind: match$1[0],
50
51
  logId: match$1[1]
51
52
  };
@@ -3,7 +3,7 @@ open Source
3
3
  let isUnauthorizedError = (message: string) => message->String.includes("401 Unauthorized")
4
4
 
5
5
  type options = {
6
- chain: ChainMap.Chain.t,
6
+ chainId: ChainId.t,
7
7
  endpointUrl: string,
8
8
  apiToken: option<string>,
9
9
  // The chain's registrations, indexed by their sequential `index`.
@@ -12,7 +12,7 @@ type options = {
12
12
  addressStore: AddressStore.t,
13
13
  }
14
14
 
15
- let make = ({chain, endpointUrl, apiToken, onEventRegistrations, addressStore}: options): t => {
15
+ let make = ({chainId, endpointUrl, apiToken, onEventRegistrations, addressStore}: options): t => {
16
16
  let name = "HyperFuel"
17
17
 
18
18
  let apiToken = switch apiToken {
@@ -120,8 +120,6 @@ Learn more or get a free Envio API token at: https://envio.dev/app/api-tokens`)
120
120
  blocksByHeight->Utils.Map.set(block.height, block)->ignore
121
121
  })
122
122
 
123
- let chainId = chain->ChainMap.Chain.toChainId
124
-
125
123
  let parsedQueueItems = pageUnsafe.items->Array.map(item => {
126
124
  // Routing happened in Rust; the item references its registration by
127
125
  // chain-scoped index.
@@ -171,7 +169,7 @@ Learn more or get a free Envio API token at: https://envio.dev/app/api-tokens`)
171
169
 
172
170
  Internal.Event({
173
171
  onEventRegistration,
174
- chain,
172
+ chainId,
175
173
  blockNumber: item.blockHeight,
176
174
  logIndex: item.receiptIndex,
177
175
  // Fuel carries the transaction inline on the payload; the store key is
@@ -180,7 +178,7 @@ Learn more or get a free Envio API token at: https://envio.dev/app/api-tokens`)
180
178
  payload: {
181
179
  contractName: eventConfig.contractName,
182
180
  eventName: eventConfig.name,
183
- chainId,
181
+ chainId: chainId,
184
182
  params,
185
183
  transaction: {
186
184
  "id": item.txId,
@@ -235,7 +233,7 @@ Learn more or get a free Envio API token at: https://envio.dev/app/api-tokens`)
235
233
  {
236
234
  name,
237
235
  sourceFor: Sync,
238
- chain,
236
+ chainId,
239
237
  getBlockHashes,
240
238
  pollingInterval: 100,
241
239
  poweredByHyperSync: true,
@@ -18,7 +18,7 @@ function isUnauthorizedError(message) {
18
18
  function make(param) {
19
19
  let onEventRegistrations = param.onEventRegistrations;
20
20
  let apiToken = param.apiToken;
21
- let chain = param.chain;
21
+ let chainId = param.chainId;
22
22
  let apiToken$1 = apiToken !== undefined ? apiToken : Stdlib_JsError.throwWithMessage(`An Envio API token is required for using HyperFuel as a data-source.
23
23
  Set the ENVIO_API_TOKEN environment variable in your .env file.
24
24
  Learn more or get a free Envio API token at: https://envio.dev/app/api-tokens`);
@@ -119,7 +119,7 @@ Learn more or get a free Envio API token at: https://envio.dev/app/api-tokens`);
119
119
  } catch (raw_exn) {
120
120
  let exn = Primitive_exceptions.internalToException(raw_exn);
121
121
  let params$1 = {
122
- chainId: chain,
122
+ chainId: chainId,
123
123
  blockNumber: item.blockHeight,
124
124
  logIndex: item.receiptIndex
125
125
  };
@@ -145,7 +145,7 @@ Learn more or get a free Envio API token at: https://envio.dev/app/api-tokens`);
145
145
  return {
146
146
  kind: 0,
147
147
  onEventRegistration: onEventRegistration,
148
- chain: chain,
148
+ chainId: chainId,
149
149
  blockNumber: item.blockHeight,
150
150
  logIndex: item.receiptIndex,
151
151
  transactionIndex: 0,
@@ -153,7 +153,7 @@ Learn more or get a free Envio API token at: https://envio.dev/app/api-tokens`);
153
153
  contractName: eventConfig.contractName,
154
154
  eventName: eventConfig.name,
155
155
  params: params,
156
- chainId: chain,
156
+ chainId: chainId,
157
157
  srcAddress: item.srcAddress,
158
158
  logIndex: item.receiptIndex,
159
159
  transaction: {
@@ -195,7 +195,7 @@ Learn more or get a free Envio API token at: https://envio.dev/app/api-tokens`);
195
195
  return {
196
196
  name: "HyperFuel",
197
197
  sourceFor: "Sync",
198
- chain: chain,
198
+ chainId: chainId,
199
199
  poweredByHyperSync: true,
200
200
  pollingInterval: 100,
201
201
  getBlockHashes: getBlockHashes,
@@ -43,7 +43,7 @@ let queryBlockData: (
43
43
  ~client: HyperSyncClient.t,
44
44
  ~blockNumber: int,
45
45
  ~sourceName: string,
46
- ~chainId: int,
46
+ ~chainId: ChainId.t,
47
47
  ~logger: Pino.t,
48
48
  ) => promise<(
49
49
  queryResponse<option<ReorgDetection.blockDataWithTimestamp>>,
@@ -54,7 +54,7 @@ let queryBlockDataMulti: (
54
54
  ~client: HyperSyncClient.t,
55
55
  ~blockNumbers: array<int>,
56
56
  ~sourceName: string,
57
- ~chainId: int,
57
+ ~chainId: ChainId.t,
58
58
  ~logger: Pino.t,
59
59
  ) => promise<(
60
60
  queryResponse<array<ReorgDetection.blockDataWithTimestamp>>,
@@ -254,6 +254,10 @@ module Registration = {
254
254
  contractName: string,
255
255
  isWildcard: bool,
256
256
  dependsOnAddresses: bool,
257
+ // Earliest block this registration accepts; `None` is unrestricted. The
258
+ // address store's start block is contract-wide, so it can't hold one
259
+ // registration back when a sibling declares no start block.
260
+ startBlock: option<int>,
257
261
  params: array<Internal.paramMeta>,
258
262
  topicSelections: array<topicSelectionInput>,
259
263
  // Capitalized field names matching the Rust BlockField/TransactionField
@@ -281,6 +285,7 @@ module Registration = {
281
285
  contractName: event.contractName,
282
286
  isWildcard: reg.isWildcard,
283
287
  dependsOnAddresses: reg.dependsOnAddresses,
288
+ startBlock: reg.startBlock,
284
289
  params: event.paramsMetadata,
285
290
  topicSelections: reg.resolvedWhere.topicSelections->Array.map((ts): topicSelectionInput => {
286
291
  topic0: ts.topic0->EvmTypes.Hex.toStrings,
@@ -53,6 +53,7 @@ function fromOnEventRegistrations(onEventRegistrations) {
53
53
  contractName: event.contractName,
54
54
  isWildcard: reg.isWildcard,
55
55
  dependsOnAddresses: reg.dependsOnAddresses,
56
+ startBlock: reg.startBlock,
56
57
  params: event.paramsMetadata,
57
58
  topicSelections: reg.resolvedWhere.topicSelections.map(ts => ({
58
59
  topic0: ts.topic0,