envio 3.0.0-alpha.0 → 3.0.0-alpha.10

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 (136) hide show
  1. package/README.md +2 -2
  2. package/evm.schema.json +53 -57
  3. package/fuel.schema.json +35 -31
  4. package/index.d.ts +446 -1
  5. package/index.js +4 -0
  6. package/package.json +23 -11
  7. package/rescript.json +4 -1
  8. package/src/Batch.res.mjs +1 -1
  9. package/src/Benchmark.res +394 -0
  10. package/src/Benchmark.res.mjs +398 -0
  11. package/src/ChainFetcher.res +526 -0
  12. package/src/ChainFetcher.res.mjs +343 -0
  13. package/src/ChainManager.res +182 -0
  14. package/src/ChainManager.res.mjs +150 -0
  15. package/src/Config.res +367 -27
  16. package/src/Config.res.mjs +338 -28
  17. package/src/{Indexer.res → Ctx.res} +1 -1
  18. package/src/Ecosystem.res +25 -0
  19. package/src/Ecosystem.res.mjs +29 -0
  20. package/src/Env.res +252 -0
  21. package/src/Env.res.mjs +271 -0
  22. package/src/Envio.gen.ts +9 -1
  23. package/src/Envio.res +12 -9
  24. package/src/EventProcessing.res +476 -0
  25. package/src/EventProcessing.res.mjs +341 -0
  26. package/src/EventRegister.res +4 -15
  27. package/src/EventRegister.res.mjs +3 -9
  28. package/src/EventRegister.resi +2 -8
  29. package/src/FetchState.res +54 -29
  30. package/src/FetchState.res.mjs +62 -35
  31. package/src/GlobalState.res +1163 -0
  32. package/src/GlobalState.res.mjs +1196 -0
  33. package/src/GlobalStateManager.res +68 -0
  34. package/src/GlobalStateManager.res.mjs +75 -0
  35. package/src/GlobalStateManager.resi +7 -0
  36. package/src/HandlerLoader.res +89 -0
  37. package/src/HandlerLoader.res.mjs +79 -0
  38. package/src/Internal.gen.ts +3 -14
  39. package/src/Internal.res +45 -13
  40. package/src/LoadLayer.res +444 -0
  41. package/src/LoadLayer.res.mjs +296 -0
  42. package/src/LoadLayer.resi +32 -0
  43. package/src/LogSelection.res +33 -27
  44. package/src/LogSelection.res.mjs +6 -0
  45. package/src/Logging.res +11 -4
  46. package/src/Logging.res.mjs +14 -6
  47. package/src/Main.res +351 -0
  48. package/src/Main.res.mjs +312 -0
  49. package/src/Persistence.res +1 -2
  50. package/src/PgStorage.gen.ts +10 -0
  51. package/src/PgStorage.res +28 -34
  52. package/src/PgStorage.res.d.mts +5 -0
  53. package/src/PgStorage.res.mjs +27 -27
  54. package/src/Prometheus.res +8 -8
  55. package/src/Prometheus.res.mjs +10 -10
  56. package/src/ReorgDetection.res +6 -10
  57. package/src/ReorgDetection.res.mjs +6 -6
  58. package/src/TestIndexer.res +536 -0
  59. package/src/TestIndexer.res.mjs +412 -0
  60. package/src/TestIndexerProxyStorage.res +210 -0
  61. package/src/TestIndexerProxyStorage.res.mjs +157 -0
  62. package/src/Types.ts +1 -1
  63. package/src/UserContext.res +355 -0
  64. package/src/UserContext.res.mjs +236 -0
  65. package/src/Utils.res +28 -0
  66. package/src/Utils.res.mjs +18 -0
  67. package/src/bindings/ClickHouse.res +31 -1
  68. package/src/bindings/ClickHouse.res.mjs +27 -1
  69. package/src/bindings/DateFns.res +71 -0
  70. package/src/bindings/DateFns.res.mjs +22 -0
  71. package/src/bindings/Ethers.res +27 -67
  72. package/src/bindings/Ethers.res.mjs +18 -70
  73. package/src/bindings/EventSource.res +13 -0
  74. package/src/bindings/EventSource.res.mjs +2 -0
  75. package/src/bindings/NodeJs.res +44 -3
  76. package/src/bindings/NodeJs.res.mjs +11 -3
  77. package/src/bindings/Pino.res +21 -7
  78. package/src/bindings/Pino.res.mjs +11 -5
  79. package/src/bindings/Postgres.gen.ts +8 -0
  80. package/src/bindings/Postgres.res +3 -0
  81. package/src/bindings/Postgres.res.d.mts +5 -0
  82. package/src/bindings/RescriptMocha.res +123 -0
  83. package/src/bindings/RescriptMocha.res.mjs +18 -0
  84. package/src/bindings/Vitest.res +134 -0
  85. package/src/bindings/Vitest.res.mjs +9 -0
  86. package/src/bindings/Yargs.res +8 -0
  87. package/src/bindings/Yargs.res.mjs +2 -0
  88. package/src/db/InternalTable.res +2 -0
  89. package/src/db/InternalTable.res.mjs +1 -1
  90. package/src/sources/Evm.res +87 -0
  91. package/src/sources/Evm.res.mjs +105 -0
  92. package/src/sources/EvmChain.res +90 -0
  93. package/src/sources/EvmChain.res.mjs +57 -0
  94. package/src/sources/Fuel.res +19 -34
  95. package/src/sources/Fuel.res.mjs +34 -16
  96. package/src/sources/FuelSDK.res +38 -0
  97. package/src/sources/FuelSDK.res.mjs +29 -0
  98. package/src/sources/HyperFuel.res +2 -2
  99. package/src/sources/HyperFuel.resi +1 -1
  100. package/src/sources/HyperFuelClient.res +2 -2
  101. package/src/sources/HyperFuelSource.res +8 -8
  102. package/src/sources/HyperFuelSource.res.mjs +5 -5
  103. package/src/sources/HyperSyncHeightStream.res +97 -0
  104. package/src/sources/HyperSyncHeightStream.res.mjs +94 -0
  105. package/src/sources/HyperSyncSource.res +64 -172
  106. package/src/sources/HyperSyncSource.res.mjs +73 -155
  107. package/src/sources/Rpc.res +43 -0
  108. package/src/sources/Rpc.res.mjs +31 -0
  109. package/src/sources/RpcSource.res +32 -130
  110. package/src/sources/RpcSource.res.mjs +47 -121
  111. package/src/sources/Source.res +3 -2
  112. package/src/sources/SourceManager.res +183 -108
  113. package/src/sources/SourceManager.res.mjs +162 -99
  114. package/src/sources/SourceManager.resi +4 -5
  115. package/src/sources/Svm.res +59 -0
  116. package/src/sources/Svm.res.mjs +79 -0
  117. package/src/tui/Tui.res +266 -0
  118. package/src/tui/Tui.res.mjs +342 -0
  119. package/src/tui/bindings/Ink.res +376 -0
  120. package/src/tui/bindings/Ink.res.mjs +75 -0
  121. package/src/tui/bindings/Style.res +123 -0
  122. package/src/tui/bindings/Style.res.mjs +2 -0
  123. package/src/tui/components/BufferedProgressBar.res +40 -0
  124. package/src/tui/components/BufferedProgressBar.res.mjs +57 -0
  125. package/src/tui/components/CustomHooks.res +122 -0
  126. package/src/tui/components/CustomHooks.res.mjs +179 -0
  127. package/src/tui/components/Messages.res +41 -0
  128. package/src/tui/components/Messages.res.mjs +75 -0
  129. package/src/tui/components/SyncETA.res +193 -0
  130. package/src/tui/components/SyncETA.res.mjs +269 -0
  131. package/src/tui/components/TuiData.res +46 -0
  132. package/src/tui/components/TuiData.res.mjs +29 -0
  133. package/src/Platform.res +0 -140
  134. package/src/Platform.res.mjs +0 -170
  135. package/src/bindings/Ethers.gen.ts +0 -14
  136. /package/src/{Indexer.res.mjs → Ctx.res.mjs} +0 -0
package/src/Config.res CHANGED
@@ -16,15 +16,45 @@ type contract = {
16
16
  addresses: array<Address.t>,
17
17
  events: array<Internal.eventConfig>,
18
18
  startBlock: option<int>,
19
+ // EVM-specific: event sighashes for HyperSync queries
20
+ eventSignatures: array<string>,
19
21
  }
20
22
 
23
+ type codegenContract = {
24
+ name: string,
25
+ addresses: array<string>,
26
+ events: array<Internal.eventConfig>,
27
+ startBlock: option<int>,
28
+ }
29
+
30
+ // Source config is now parsed from internal.config.json and sources are created lazily
31
+ type codegenChain = {
32
+ id: int,
33
+ contracts: array<codegenContract>,
34
+ }
35
+
36
+ // Source config parsed from internal.config.json - sources are created lazily in ChainFetcher
37
+ type evmRpcConfig = {
38
+ url: string,
39
+ sourceFor: Source.sourceFor,
40
+ syncConfig: option<sourceSyncOptions>,
41
+ }
42
+
43
+ type sourceConfig =
44
+ | EvmSourceConfig({hypersync: option<string>, rpcs: array<evmRpcConfig>})
45
+ | FuelSourceConfig({hypersync: string})
46
+ | SvmSourceConfig({rpc: string})
47
+ // For tests: pass custom sources directly
48
+ | CustomSources(array<Source.t>)
49
+
21
50
  type chain = {
51
+ name: string,
22
52
  id: int,
23
53
  startBlock: int,
24
54
  endBlock?: int,
25
55
  maxReorgDepth: int,
26
56
  contracts: array<contract>,
27
- sources: array<Source.t>,
57
+ sourceConfig: sourceConfig,
28
58
  }
29
59
 
30
60
  type sourceSync = {
@@ -39,45 +69,325 @@ type sourceSync = {
39
69
 
40
70
  type multichain = | @as("ordered") Ordered | @as("unordered") Unordered
41
71
 
72
+ type contractHandler = {
73
+ name: string,
74
+ handler: option<string>,
75
+ }
76
+
42
77
  type t = {
78
+ name: string,
79
+ description: option<string>,
80
+ handlers: string,
81
+ contractHandlers: array<contractHandler>,
43
82
  shouldRollbackOnReorg: bool,
44
83
  shouldSaveFullHistory: bool,
45
84
  multichain: multichain,
46
85
  chainMap: ChainMap.t<chain>,
47
86
  defaultChain: option<chain>,
48
- platform: Platform.t,
87
+ ecosystem: Ecosystem.t,
49
88
  enableRawEvents: bool,
50
- preloadHandlers: bool,
51
89
  maxAddrInPartition: int,
52
90
  batchSize: int,
53
91
  lowercaseAddresses: bool,
54
92
  addContractNameToContractNameMapping: dict<string>,
93
+ userEntitiesByName: dict<Internal.entityConfig>,
55
94
  }
56
95
 
57
- let make = (
58
- ~shouldRollbackOnReorg=true,
59
- ~shouldSaveFullHistory=false,
60
- ~chains: array<chain>=[],
61
- ~enableRawEvents=false,
62
- ~preloadHandlers=false,
63
- ~ecosystem: Platform.name=Platform.Evm,
64
- ~batchSize=5000,
65
- ~lowercaseAddresses=false,
66
- ~multichain=Unordered,
67
- ~shouldUseHypersyncClientDecoder=true,
96
+ // Types for parsing source config from internal.config.json
97
+ type rpcSourceFor = | @as("sync") Sync | @as("fallback") Fallback | @as("live") Live
98
+
99
+ let rpcSourceForSchema = S.enum([Sync, Fallback, Live])
100
+
101
+ let rpcConfigSchema = S.schema(s =>
102
+ {
103
+ "url": s.matches(S.string),
104
+ "for": s.matches(rpcSourceForSchema),
105
+ "initialBlockInterval": s.matches(S.option(S.int)),
106
+ "backoffMultiplicative": s.matches(S.option(S.float)),
107
+ "accelerationAdditive": s.matches(S.option(S.int)),
108
+ "intervalCeiling": s.matches(S.option(S.int)),
109
+ "backoffMillis": s.matches(S.option(S.int)),
110
+ "fallbackStallTimeout": s.matches(S.option(S.int)),
111
+ "queryTimeoutMillis": s.matches(S.option(S.int)),
112
+ }
113
+ )
114
+
115
+ let publicConfigChainSchema = S.schema(s =>
116
+ {
117
+ "id": s.matches(S.int),
118
+ "startBlock": s.matches(S.int),
119
+ "endBlock": s.matches(S.option(S.int)),
120
+ "maxReorgDepth": s.matches(S.option(S.int)),
121
+ // EVM/Fuel source config (hypersync for EVM, hyperfuel for Fuel)
122
+ "hypersync": s.matches(S.option(S.string)),
123
+ "rpcs": s.matches(S.option(S.array(rpcConfigSchema))),
124
+ // SVM source config
125
+ "rpc": s.matches(S.option(S.string)),
126
+ }
127
+ )
128
+
129
+ let contractEventItemSchema = S.schema(s =>
130
+ {
131
+ "event": s.matches(S.string),
132
+ }
133
+ )
134
+
135
+ let contractConfigSchema = S.schema(s =>
136
+ {
137
+ "abi": s.matches(S.json(~validate=false)),
138
+ "handler": s.matches(S.option(S.string)),
139
+ // EVM-specific: event signatures for HyperSync queries
140
+ "events": s.matches(S.option(S.array(contractEventItemSchema))),
141
+ }
142
+ )
143
+
144
+ let publicConfigEcosystemSchema = S.schema(s =>
145
+ {
146
+ "chains": s.matches(S.dict(publicConfigChainSchema)),
147
+ "contracts": s.matches(S.option(S.dict(contractConfigSchema))),
148
+ }
149
+ )
150
+
151
+ type addressFormat = | @as("lowercase") Lowercase | @as("checksum") Checksum
152
+
153
+ let publicConfigEvmSchema = S.schema(s =>
154
+ {
155
+ "chains": s.matches(S.dict(publicConfigChainSchema)),
156
+ "contracts": s.matches(S.option(S.dict(contractConfigSchema))),
157
+ "addressFormat": s.matches(S.option(S.enum([Lowercase, Checksum]))),
158
+ }
159
+ )
160
+
161
+ let multichainSchema = S.enum([Ordered, Unordered])
162
+
163
+ let publicConfigSchema = S.schema(s =>
164
+ {
165
+ "name": s.matches(S.string),
166
+ "description": s.matches(S.option(S.string)),
167
+ "handlers": s.matches(S.option(S.string)),
168
+ "multichain": s.matches(S.option(multichainSchema)),
169
+ "fullBatchSize": s.matches(S.option(S.int)),
170
+ "rollbackOnReorg": s.matches(S.option(S.bool)),
171
+ "saveFullHistory": s.matches(S.option(S.bool)),
172
+ "rawEvents": s.matches(S.option(S.bool)),
173
+ "evm": s.matches(S.option(publicConfigEvmSchema)),
174
+ "fuel": s.matches(S.option(publicConfigEcosystemSchema)),
175
+ "svm": s.matches(S.option(publicConfigEcosystemSchema)),
176
+ }
177
+ )
178
+
179
+ let fromPublic = (
180
+ publicConfigJson: Js.Json.t,
181
+ ~codegenChains: array<codegenChain>=[],
68
182
  ~maxAddrInPartition=5000,
183
+ ~userEntities: array<Internal.entityConfig>=[],
69
184
  ) => {
70
- // Validate that lowercase addresses is not used with viem decoder
71
- if lowercaseAddresses && !shouldUseHypersyncClientDecoder {
185
+ // Parse public config
186
+ let publicConfig = try publicConfigJson->S.parseOrThrow(publicConfigSchema) catch {
187
+ | S.Raised(exn) =>
188
+ Js.Exn.raiseError(`Invalid internal.config.ts: ${exn->Utils.prettifyExn->Utils.magic}`)
189
+ }
190
+
191
+ // Determine ecosystem from publicConfig (extract just chains for unified handling)
192
+ let (publicChainsConfig, ecosystemName) = switch (
193
+ publicConfig["evm"],
194
+ publicConfig["fuel"],
195
+ publicConfig["svm"],
196
+ ) {
197
+ | (Some(ecosystemConfig), None, None) => (ecosystemConfig["chains"], Ecosystem.Evm)
198
+ | (None, Some(ecosystemConfig), None) => (ecosystemConfig["chains"], Ecosystem.Fuel)
199
+ | (None, None, Some(ecosystemConfig)) => (ecosystemConfig["chains"], Ecosystem.Svm)
200
+ | (None, None, None) =>
201
+ Js.Exn.raiseError("Invalid indexer config: No ecosystem configured (evm, fuel, or svm)")
202
+ | _ =>
72
203
  Js.Exn.raiseError(
73
- "lowercase addresses is not supported when event_decoder is 'viem'. Please set event_decoder to 'hypersync-client' or change address_format to 'checksum'.",
204
+ "Invalid indexer config: Multiple ecosystems are not supported for a single indexer",
74
205
  )
75
206
  }
76
207
 
208
+ // Extract EVM-specific options with defaults
209
+ let lowercaseAddresses = switch publicConfig["evm"] {
210
+ | Some(evm) => evm["addressFormat"]->Option.getWithDefault(Checksum) == Lowercase
211
+ | None => false
212
+ }
213
+
214
+ // Parse ABIs from public config
215
+ let publicContractsConfig = switch (ecosystemName, publicConfig["evm"], publicConfig["fuel"]) {
216
+ | (Ecosystem.Evm, Some(evm), _) => evm["contracts"]
217
+ | (Ecosystem.Fuel, _, Some(fuel)) => fuel["contracts"]
218
+ | _ => None
219
+ }
220
+
221
+ // Store both ABI and event signatures for each contract (using inline tuple)
222
+ let contractsWithAbis: Js.Dict.t<(EvmTypes.Abi.t, array<string>)> = switch publicContractsConfig {
223
+ | Some(contractsDict) =>
224
+ contractsDict
225
+ ->Js.Dict.entries
226
+ ->Js.Array2.map(((contractName, contractConfig)) => {
227
+ let abi = contractConfig["abi"]->(Utils.magic: Js.Json.t => EvmTypes.Abi.t)
228
+ let eventSignatures = switch contractConfig["events"] {
229
+ | Some(events) => events->Array.map(eventItem => eventItem["event"])
230
+ | None => []
231
+ }
232
+ (contractName, (abi, eventSignatures))
233
+ })
234
+ ->Js.Dict.fromArray
235
+ | None => Js.Dict.empty()
236
+ }
237
+
238
+ // Index codegenChains by id for efficient lookup
239
+ let codegenChainById = Js.Dict.empty()
240
+ codegenChains->Array.forEach(codegenChain => {
241
+ codegenChainById->Js.Dict.set(codegenChain.id->Int.toString, codegenChain)
242
+ })
243
+
244
+ // Create a dictionary to store merged contracts with ABIs by chain id
245
+ let contractsByChainId: Js.Dict.t<array<contract>> = Js.Dict.empty()
246
+ codegenChains->Array.forEach(codegenChain => {
247
+ let mergedContracts = codegenChain.contracts->Array.map(codegenContract => {
248
+ switch contractsWithAbis->Js.Dict.get(codegenContract.name) {
249
+ | Some((abi, eventSignatures)) =>
250
+ // Parse addresses based on ecosystem and address format
251
+ let parsedAddresses = codegenContract.addresses->Array.map(
252
+ addressString => {
253
+ switch ecosystemName {
254
+ | Ecosystem.Evm =>
255
+ if lowercaseAddresses {
256
+ addressString->Address.Evm.fromStringLowercaseOrThrow
257
+ } else {
258
+ addressString->Address.Evm.fromStringOrThrow
259
+ }
260
+ | Ecosystem.Fuel | Ecosystem.Svm => addressString->Address.unsafeFromString
261
+ }
262
+ },
263
+ )
264
+ // Convert codegenContract to contract by adding abi and eventSignatures
265
+ {
266
+ name: codegenContract.name,
267
+ abi,
268
+ addresses: parsedAddresses,
269
+ events: codegenContract.events,
270
+ startBlock: codegenContract.startBlock,
271
+ eventSignatures,
272
+ }
273
+ | None =>
274
+ Js.Exn.raiseError(
275
+ `Contract "${codegenContract.name}" is missing ABI in public config (internal.config.ts)`,
276
+ )
277
+ }
278
+ })
279
+ contractsByChainId->Js.Dict.set(codegenChain.id->Int.toString, mergedContracts)
280
+ })
281
+
282
+ // Helper to convert parsed RPC config to evmRpcConfig
283
+ let parseRpcSourceFor = (sourceFor: rpcSourceFor): Source.sourceFor => {
284
+ switch sourceFor {
285
+ | Sync => Source.Sync
286
+ | Fallback => Source.Fallback
287
+ | Live => Source.Live
288
+ }
289
+ }
290
+
291
+ // Merge codegenChains with names from publicConfig
292
+ let chains =
293
+ publicChainsConfig
294
+ ->Js.Dict.keys
295
+ ->Js.Array2.map(chainName => {
296
+ let publicChainConfig = publicChainsConfig->Js.Dict.unsafeGet(chainName)
297
+ let chainId = publicChainConfig["id"]
298
+ let codegenChain = switch codegenChainById->Js.Dict.get(chainId->Int.toString) {
299
+ | Some(c) => c
300
+ | None =>
301
+ Js.Exn.raiseError(`Chain with id ${chainId->Int.toString} not found in codegen chains`)
302
+ }
303
+ let mergedContracts = switch contractsByChainId->Js.Dict.get(chainId->Int.toString) {
304
+ | Some(contracts) => contracts
305
+ | None =>
306
+ Js.Exn.raiseError(
307
+ `Contracts for chain with id ${chainId->Int.toString} not found in merged contracts`,
308
+ )
309
+ }
310
+
311
+ // Build sourceConfig from the parsed chain config
312
+ let sourceConfig = switch ecosystemName {
313
+ | Ecosystem.Evm =>
314
+ let rpcs =
315
+ publicChainConfig["rpcs"]
316
+ ->Option.getWithDefault([])
317
+ ->Array.map((rpcConfig): evmRpcConfig => {
318
+ // Build syncConfig from flattened fields
319
+ let initialBlockInterval = rpcConfig["initialBlockInterval"]
320
+ let backoffMultiplicative = rpcConfig["backoffMultiplicative"]
321
+ let accelerationAdditive = rpcConfig["accelerationAdditive"]
322
+ let intervalCeiling = rpcConfig["intervalCeiling"]
323
+ let backoffMillis = rpcConfig["backoffMillis"]
324
+ let queryTimeoutMillis = rpcConfig["queryTimeoutMillis"]
325
+ let fallbackStallTimeout = rpcConfig["fallbackStallTimeout"]
326
+ let hasSyncConfig =
327
+ initialBlockInterval->Option.isSome ||
328
+ backoffMultiplicative->Option.isSome ||
329
+ accelerationAdditive->Option.isSome ||
330
+ intervalCeiling->Option.isSome ||
331
+ backoffMillis->Option.isSome ||
332
+ queryTimeoutMillis->Option.isSome ||
333
+ fallbackStallTimeout->Option.isSome
334
+ let syncConfig: option<sourceSyncOptions> = if hasSyncConfig {
335
+ Some({
336
+ ?initialBlockInterval,
337
+ ?backoffMultiplicative,
338
+ ?accelerationAdditive,
339
+ ?intervalCeiling,
340
+ ?backoffMillis,
341
+ ?queryTimeoutMillis,
342
+ ?fallbackStallTimeout,
343
+ })
344
+ } else {
345
+ None
346
+ }
347
+ {
348
+ url: rpcConfig["url"],
349
+ sourceFor: parseRpcSourceFor(rpcConfig["for"]),
350
+ syncConfig,
351
+ }
352
+ })
353
+ EvmSourceConfig({hypersync: publicChainConfig["hypersync"], rpcs})
354
+ | Ecosystem.Fuel =>
355
+ switch publicChainConfig["hypersync"] {
356
+ | Some(hypersync) => FuelSourceConfig({hypersync: hypersync})
357
+ | None =>
358
+ Js.Exn.raiseError(
359
+ `Chain ${chainName} is missing hypersync endpoint in config`,
360
+ )
361
+ }
362
+ | Ecosystem.Svm =>
363
+ switch publicChainConfig["rpc"] {
364
+ | Some(rpc) => SvmSourceConfig({rpc: rpc})
365
+ | None =>
366
+ Js.Exn.raiseError(
367
+ `Chain ${chainName} is missing rpc endpoint in config`,
368
+ )
369
+ }
370
+ }
371
+
372
+ {
373
+ name: chainName,
374
+ id: codegenChain.id,
375
+ startBlock: publicChainConfig["startBlock"],
376
+ endBlock: ?publicChainConfig["endBlock"],
377
+ maxReorgDepth: switch ecosystemName {
378
+ | Ecosystem.Evm => publicChainConfig["maxReorgDepth"]->Option.getWithDefault(200)
379
+ // Fuel doesn't have reorgs, SVM reorg handling is not supported
380
+ | Ecosystem.Fuel | Ecosystem.Svm => 0
381
+ },
382
+ contracts: mergedContracts,
383
+ sourceConfig,
384
+ }
385
+ })
386
+
77
387
  let chainMap =
78
388
  chains
79
- ->Js.Array2.map(n => {
80
- (ChainMap.Chain.makeUnsafe(~chainId=n.id), n)
389
+ ->Js.Array2.map(chain => {
390
+ (ChainMap.Chain.makeUnsafe(~chainId=chain.id), chain)
81
391
  })
82
392
  ->ChainMap.fromArrayUnsafe
83
393
 
@@ -90,21 +400,50 @@ let make = (
90
400
  })
91
401
  })
92
402
 
93
- let platform = Platform.fromName(ecosystem)
403
+ let ecosystem = switch ecosystemName {
404
+ | Ecosystem.Evm => Evm.ecosystem
405
+ | Ecosystem.Fuel => Fuel.ecosystem
406
+ | Ecosystem.Svm => Svm.ecosystem
407
+ }
408
+
409
+ let userEntitiesByName =
410
+ userEntities
411
+ ->Js.Array2.map(entityConfig => {
412
+ (entityConfig.name, entityConfig)
413
+ })
414
+ ->Js.Dict.fromArray
415
+
416
+ // Extract contract handlers from the public config
417
+ let contractHandlers = switch publicContractsConfig {
418
+ | Some(contractsDict) =>
419
+ contractsDict
420
+ ->Js.Dict.entries
421
+ ->Js.Array2.map(((contractName, contractConfig)) => {
422
+ {
423
+ name: contractName,
424
+ handler: contractConfig["handler"],
425
+ }
426
+ })
427
+ | None => []
428
+ }
94
429
 
95
430
  {
96
- shouldRollbackOnReorg,
97
- shouldSaveFullHistory,
98
- multichain,
431
+ name: publicConfig["name"],
432
+ description: publicConfig["description"],
433
+ handlers: publicConfig["handlers"]->Option.getWithDefault("src/handlers"),
434
+ contractHandlers,
435
+ shouldRollbackOnReorg: publicConfig["rollbackOnReorg"]->Option.getWithDefault(true),
436
+ shouldSaveFullHistory: publicConfig["saveFullHistory"]->Option.getWithDefault(false),
437
+ multichain: publicConfig["multichain"]->Option.getWithDefault(Unordered),
99
438
  chainMap,
100
439
  defaultChain: chains->Array.get(0),
101
- enableRawEvents,
102
- platform,
440
+ enableRawEvents: publicConfig["rawEvents"]->Option.getWithDefault(false),
441
+ ecosystem,
103
442
  maxAddrInPartition,
104
- preloadHandlers,
105
- batchSize,
443
+ batchSize: publicConfig["fullBatchSize"]->Option.getWithDefault(5000),
106
444
  lowercaseAddresses,
107
445
  addContractNameToContractNameMapping,
446
+ userEntitiesByName,
108
447
  }
109
448
  }
110
449
 
@@ -122,3 +461,4 @@ let getChain = (config, ~chainId) => {
122
461
  "No chain with id " ++ chain->ChainMap.Chain.toString ++ " found in config.yaml",
123
462
  )
124
463
  }
464
+