envio 3.0.0-alpha.2 → 3.0.0-alpha.20

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 (175) hide show
  1. package/README.md +164 -30
  2. package/bin.mjs +49 -0
  3. package/evm.schema.json +79 -169
  4. package/fuel.schema.json +50 -21
  5. package/index.d.ts +497 -1
  6. package/index.js +4 -0
  7. package/package.json +42 -31
  8. package/rescript.json +4 -1
  9. package/src/Batch.res +11 -8
  10. package/src/Batch.res.mjs +11 -9
  11. package/src/ChainFetcher.res +531 -0
  12. package/src/ChainFetcher.res.mjs +339 -0
  13. package/src/ChainManager.res +190 -0
  14. package/src/ChainManager.res.mjs +166 -0
  15. package/src/Change.res +3 -3
  16. package/src/Config.gen.ts +19 -0
  17. package/src/Config.res +737 -22
  18. package/src/Config.res.mjs +703 -26
  19. package/src/{Indexer.res → Ctx.res} +1 -1
  20. package/src/Ecosystem.res +9 -124
  21. package/src/Ecosystem.res.mjs +19 -160
  22. package/src/Env.res +30 -74
  23. package/src/Env.res.mjs +25 -87
  24. package/src/Envio.gen.ts +3 -1
  25. package/src/Envio.res +20 -9
  26. package/src/EventProcessing.res +469 -0
  27. package/src/EventProcessing.res.mjs +337 -0
  28. package/src/EvmTypes.gen.ts +6 -0
  29. package/src/EvmTypes.res +1 -0
  30. package/src/FetchState.res +1256 -639
  31. package/src/FetchState.res.mjs +1135 -612
  32. package/src/GlobalState.res +1190 -0
  33. package/src/GlobalState.res.mjs +1183 -0
  34. package/src/GlobalStateManager.res +68 -0
  35. package/src/GlobalStateManager.res.mjs +75 -0
  36. package/src/GlobalStateManager.resi +7 -0
  37. package/src/HandlerLoader.res +89 -0
  38. package/src/HandlerLoader.res.mjs +79 -0
  39. package/src/HandlerRegister.res +357 -0
  40. package/src/HandlerRegister.res.mjs +299 -0
  41. package/src/{EventRegister.resi → HandlerRegister.resi} +13 -13
  42. package/src/Hasura.res +111 -175
  43. package/src/Hasura.res.mjs +88 -150
  44. package/src/InMemoryStore.res +1 -1
  45. package/src/InMemoryStore.res.mjs +3 -3
  46. package/src/InMemoryTable.res +1 -1
  47. package/src/InMemoryTable.res.mjs +1 -1
  48. package/src/Internal.gen.ts +4 -0
  49. package/src/Internal.res +230 -12
  50. package/src/Internal.res.mjs +115 -1
  51. package/src/LoadLayer.res +444 -0
  52. package/src/LoadLayer.res.mjs +296 -0
  53. package/src/LoadLayer.resi +32 -0
  54. package/src/LogSelection.res +33 -27
  55. package/src/LogSelection.res.mjs +6 -0
  56. package/src/Logging.res +21 -7
  57. package/src/Logging.res.mjs +16 -8
  58. package/src/Main.res +377 -0
  59. package/src/Main.res.mjs +339 -0
  60. package/src/Persistence.res +7 -21
  61. package/src/Persistence.res.mjs +3 -3
  62. package/src/PgStorage.gen.ts +10 -0
  63. package/src/PgStorage.res +116 -69
  64. package/src/PgStorage.res.d.mts +5 -0
  65. package/src/PgStorage.res.mjs +93 -50
  66. package/src/Prometheus.res +294 -224
  67. package/src/Prometheus.res.mjs +353 -340
  68. package/src/ReorgDetection.res +6 -10
  69. package/src/ReorgDetection.res.mjs +6 -6
  70. package/src/SafeCheckpointTracking.res +4 -4
  71. package/src/SafeCheckpointTracking.res.mjs +2 -2
  72. package/src/Sink.res +4 -2
  73. package/src/Sink.res.mjs +2 -1
  74. package/src/TableIndices.res +0 -1
  75. package/src/TestIndexer.res +692 -0
  76. package/src/TestIndexer.res.mjs +527 -0
  77. package/src/TestIndexerProxyStorage.res +205 -0
  78. package/src/TestIndexerProxyStorage.res.mjs +151 -0
  79. package/src/TopicFilter.res +1 -1
  80. package/src/Types.ts +1 -1
  81. package/src/UserContext.res +424 -0
  82. package/src/UserContext.res.mjs +279 -0
  83. package/src/Utils.res +97 -26
  84. package/src/Utils.res.mjs +91 -44
  85. package/src/bindings/BigInt.res +10 -0
  86. package/src/bindings/BigInt.res.mjs +15 -0
  87. package/src/bindings/ClickHouse.res +120 -23
  88. package/src/bindings/ClickHouse.res.mjs +118 -28
  89. package/src/bindings/DateFns.res +74 -0
  90. package/src/bindings/DateFns.res.mjs +22 -0
  91. package/src/bindings/EventSource.res +8 -1
  92. package/src/bindings/EventSource.res.mjs +8 -1
  93. package/src/bindings/Express.res +1 -0
  94. package/src/bindings/Hrtime.res +14 -1
  95. package/src/bindings/Hrtime.res.mjs +22 -2
  96. package/src/bindings/Hrtime.resi +4 -0
  97. package/src/bindings/Lodash.res +0 -1
  98. package/src/bindings/NodeJs.res +49 -3
  99. package/src/bindings/NodeJs.res.mjs +11 -3
  100. package/src/bindings/Pino.res +24 -10
  101. package/src/bindings/Pino.res.mjs +14 -8
  102. package/src/bindings/Postgres.gen.ts +8 -0
  103. package/src/bindings/Postgres.res +5 -1
  104. package/src/bindings/Postgres.res.d.mts +5 -0
  105. package/src/bindings/PromClient.res +0 -10
  106. package/src/bindings/PromClient.res.mjs +0 -3
  107. package/src/bindings/Vitest.res +142 -0
  108. package/src/bindings/Vitest.res.mjs +9 -0
  109. package/src/bindings/WebSocket.res +27 -0
  110. package/src/bindings/WebSocket.res.mjs +2 -0
  111. package/src/bindings/Yargs.res +8 -0
  112. package/src/bindings/Yargs.res.mjs +2 -0
  113. package/src/db/EntityHistory.res +7 -7
  114. package/src/db/EntityHistory.res.mjs +9 -9
  115. package/src/db/InternalTable.res +59 -111
  116. package/src/db/InternalTable.res.mjs +73 -104
  117. package/src/db/Table.res +27 -8
  118. package/src/db/Table.res.mjs +25 -14
  119. package/src/sources/Evm.res +84 -0
  120. package/src/sources/Evm.res.mjs +105 -0
  121. package/src/sources/EvmChain.res +94 -0
  122. package/src/sources/EvmChain.res.mjs +60 -0
  123. package/src/sources/Fuel.res +19 -34
  124. package/src/sources/Fuel.res.mjs +34 -16
  125. package/src/sources/FuelSDK.res +38 -0
  126. package/src/sources/FuelSDK.res.mjs +29 -0
  127. package/src/sources/HyperFuel.res +2 -2
  128. package/src/sources/HyperFuel.resi +1 -1
  129. package/src/sources/HyperFuelClient.res +2 -2
  130. package/src/sources/HyperFuelSource.res +33 -13
  131. package/src/sources/HyperFuelSource.res.mjs +24 -16
  132. package/src/sources/HyperSync.res +36 -6
  133. package/src/sources/HyperSync.res.mjs +9 -7
  134. package/src/sources/HyperSync.resi +4 -0
  135. package/src/sources/HyperSyncClient.res +1 -1
  136. package/src/sources/HyperSyncHeightStream.res +47 -116
  137. package/src/sources/HyperSyncHeightStream.res.mjs +46 -73
  138. package/src/sources/HyperSyncSource.res +118 -139
  139. package/src/sources/HyperSyncSource.res.mjs +104 -121
  140. package/src/sources/Rpc.res +86 -14
  141. package/src/sources/Rpc.res.mjs +101 -9
  142. package/src/sources/RpcSource.res +621 -364
  143. package/src/sources/RpcSource.res.mjs +843 -410
  144. package/src/sources/RpcWebSocketHeightStream.res +181 -0
  145. package/src/sources/RpcWebSocketHeightStream.res.mjs +196 -0
  146. package/src/sources/Source.res +7 -5
  147. package/src/sources/SourceManager.res +325 -225
  148. package/src/sources/SourceManager.res.mjs +314 -171
  149. package/src/sources/SourceManager.resi +17 -6
  150. package/src/sources/Svm.res +81 -0
  151. package/src/sources/Svm.res.mjs +90 -0
  152. package/src/tui/Tui.res +247 -0
  153. package/src/tui/Tui.res.mjs +337 -0
  154. package/src/tui/bindings/Ink.res +371 -0
  155. package/src/tui/bindings/Ink.res.mjs +72 -0
  156. package/src/tui/bindings/Style.res +123 -0
  157. package/src/tui/bindings/Style.res.mjs +2 -0
  158. package/src/tui/components/BufferedProgressBar.res +40 -0
  159. package/src/tui/components/BufferedProgressBar.res.mjs +57 -0
  160. package/src/tui/components/CustomHooks.res +122 -0
  161. package/src/tui/components/CustomHooks.res.mjs +179 -0
  162. package/src/tui/components/Messages.res +41 -0
  163. package/src/tui/components/Messages.res.mjs +75 -0
  164. package/src/tui/components/SyncETA.res +174 -0
  165. package/src/tui/components/SyncETA.res.mjs +263 -0
  166. package/src/tui/components/TuiData.res +47 -0
  167. package/src/tui/components/TuiData.res.mjs +34 -0
  168. package/svm.schema.json +112 -0
  169. package/bin.js +0 -48
  170. package/src/EventRegister.res +0 -241
  171. package/src/EventRegister.res.mjs +0 -240
  172. package/src/bindings/Ethers.gen.ts +0 -14
  173. package/src/bindings/Ethers.res +0 -204
  174. package/src/bindings/Ethers.res.mjs +0 -130
  175. /package/src/{Indexer.res.mjs → Ctx.res.mjs} +0 -0
package/src/Main.res ADDED
@@ -0,0 +1,377 @@
1
+ open Belt
2
+
3
+ type chainData = {
4
+ chainId: float,
5
+ poweredByHyperSync: bool,
6
+ firstEventBlockNumber: option<int>,
7
+ latestProcessedBlock: option<int>,
8
+ timestampCaughtUpToHeadOrEndblock: option<Js.Date.t>,
9
+ numEventsProcessed: float,
10
+ latestFetchedBlockNumber: int,
11
+ // Need this for API backwards compatibility
12
+ @as("currentBlockHeight")
13
+ knownHeight: int,
14
+ numBatchesFetched: int,
15
+ startBlock: int,
16
+ endBlock: option<int>,
17
+ numAddresses: int,
18
+ }
19
+ @tag("status")
20
+ type state =
21
+ | @as("disabled") Disabled({})
22
+ | @as("initializing") Initializing({})
23
+ | @as("active")
24
+ Active({
25
+ envioVersion: string,
26
+ chains: array<chainData>,
27
+ indexerStartTime: Js.Date.t,
28
+ isPreRegisteringDynamicContracts: bool,
29
+ isUnorderedMultichainMode: bool,
30
+ rollbackOnReorg: bool,
31
+ })
32
+
33
+ let chainDataSchema = S.schema((s): chainData => {
34
+ chainId: s.matches(S.float),
35
+ poweredByHyperSync: s.matches(S.bool),
36
+ firstEventBlockNumber: s.matches(S.option(S.int)),
37
+ latestProcessedBlock: s.matches(S.option(S.int)),
38
+ timestampCaughtUpToHeadOrEndblock: s.matches(S.option(S.datetime(S.string))),
39
+ numEventsProcessed: s.matches(S.float),
40
+ latestFetchedBlockNumber: s.matches(S.int),
41
+ knownHeight: s.matches(S.int),
42
+ numBatchesFetched: s.matches(S.int),
43
+ startBlock: s.matches(S.int),
44
+ endBlock: s.matches(S.option(S.int)),
45
+ numAddresses: s.matches(S.int),
46
+ })
47
+ let stateSchema = S.union([
48
+ S.literal(Disabled({})),
49
+ S.literal(Initializing({})),
50
+ S.schema(s => Active({
51
+ envioVersion: s.matches(S.string),
52
+ chains: s.matches(S.array(chainDataSchema)),
53
+ indexerStartTime: s.matches(S.datetime(S.string)),
54
+ // Keep the field, since Dev Console expects it to be present
55
+ isPreRegisteringDynamicContracts: false,
56
+ isUnorderedMultichainMode: s.matches(S.bool),
57
+ rollbackOnReorg: s.matches(S.bool),
58
+ })),
59
+ ])
60
+
61
+ let globalGsManagerRef: ref<option<GlobalStateManager.t>> = ref(None)
62
+
63
+ let getGlobalIndexer = (~config: Config.t): 'indexer => {
64
+ let indexer = Utils.Object.createNullObject()
65
+
66
+ indexer
67
+ ->Utils.Object.definePropertyWithValue("name", {enumerable: true, value: config.name})
68
+ ->Utils.Object.definePropertyWithValue(
69
+ "description",
70
+ {enumerable: true, value: config.description},
71
+ )
72
+ ->ignore
73
+
74
+ let chainIds = []
75
+
76
+ // Build chains object with chain ID as string key
77
+ let chains = Utils.Object.createNullObject()
78
+ config.chainMap
79
+ ->ChainMap.values
80
+ ->Array.forEach(chainConfig => {
81
+ let chainIdStr = chainConfig.id->Int.toString
82
+
83
+ chainIds->Js.Array2.push(chainConfig.id)->ignore
84
+
85
+ let chainObj = Utils.Object.createNullObject()
86
+ chainObj
87
+ ->Utils.Object.definePropertyWithValue("id", {enumerable: true, value: chainConfig.id})
88
+ ->Utils.Object.definePropertyWithValue(
89
+ "startBlock",
90
+ {enumerable: true, value: chainConfig.startBlock},
91
+ )
92
+ ->Utils.Object.definePropertyWithValue(
93
+ "endBlock",
94
+ {enumerable: true, value: chainConfig.endBlock},
95
+ )
96
+ ->Utils.Object.definePropertyWithValue("name", {enumerable: true, value: chainConfig.name})
97
+ ->Utils.Object.defineProperty(
98
+ "isLive",
99
+ {
100
+ enumerable: true,
101
+ get: () => {
102
+ switch globalGsManagerRef.contents {
103
+ | None => false
104
+ | Some(gsManager) =>
105
+ let state = gsManager->GlobalStateManager.getState
106
+ let chain = ChainMap.Chain.makeUnsafe(~chainId=chainConfig.id)
107
+ let chainFetcher = state.chainManager.chainFetchers->ChainMap.get(chain)
108
+ chainFetcher->ChainFetcher.isReady
109
+ }
110
+ },
111
+ },
112
+ )
113
+ ->ignore
114
+
115
+ // Add contracts to chain object
116
+ chainConfig.contracts->Array.forEach(contract => {
117
+ let contractObj = Utils.Object.createNullObject()
118
+ contractObj
119
+ ->Utils.Object.definePropertyWithValue("name", {enumerable: true, value: contract.name})
120
+ ->Utils.Object.definePropertyWithValue("abi", {enumerable: true, value: contract.abi})
121
+ ->Utils.Object.defineProperty(
122
+ "addresses",
123
+ {
124
+ enumerable: true,
125
+ get: () => {
126
+ switch globalGsManagerRef.contents {
127
+ | None => contract.addresses
128
+ | Some(gsManager) => {
129
+ let state = gsManager->GlobalStateManager.getState
130
+ let chain = ChainMap.Chain.makeUnsafe(~chainId=chainConfig.id)
131
+ let chainFetcher = state.chainManager.chainFetchers->ChainMap.get(chain)
132
+ let indexingContracts = chainFetcher.fetchState.indexingContracts
133
+
134
+ // Collect all addresses for this contract name from indexingContracts
135
+ let addresses = []
136
+ let values = indexingContracts->Js.Dict.values
137
+ for idx in 0 to values->Array.length - 1 {
138
+ let indexingContract = values->Js.Array2.unsafe_get(idx)
139
+ if indexingContract.contractName === contract.name {
140
+ addresses->Array.push(indexingContract.address)->ignore
141
+ }
142
+ }
143
+ addresses
144
+ }
145
+ }
146
+ },
147
+ },
148
+ )
149
+ ->ignore
150
+
151
+ chainObj
152
+ ->Utils.Object.definePropertyWithValue(contract.name, {enumerable: true, value: contractObj})
153
+ ->ignore
154
+ })
155
+
156
+ // Primary key is chain ID as string
157
+ chains
158
+ ->Utils.Object.definePropertyWithValue(chainIdStr, {enumerable: true, value: chainObj})
159
+ ->ignore
160
+
161
+ // If chain has a name different from ID, add non-enumerable alias
162
+ if chainConfig.name !== chainIdStr {
163
+ chains
164
+ ->Utils.Object.definePropertyWithValue(chainConfig.name, {enumerable: false, value: chainObj})
165
+ ->ignore
166
+ }
167
+ })
168
+ indexer
169
+ ->Utils.Object.definePropertyWithValue("chainIds", {enumerable: true, value: chainIds})
170
+ ->ignore
171
+ indexer->Utils.Object.definePropertyWithValue("chains", {enumerable: true, value: chains})->ignore
172
+
173
+ indexer->(Utils.magic: 'a => 'indexer)
174
+ }
175
+
176
+ let startServer = (~getState, ~ctx: Ctx.t, ~isDevelopmentMode: bool) => {
177
+ open Express
178
+
179
+ let app = make()
180
+
181
+ let consoleCorsMiddleware = (req, res, next) => {
182
+ switch req.headers->Js.Dict.get("origin") {
183
+ | Some(origin) if origin === Env.prodEnvioAppUrl || origin === Env.envioAppUrl =>
184
+ res->setHeader("Access-Control-Allow-Origin", origin)
185
+ | _ => ()
186
+ }
187
+
188
+ res->setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
189
+ res->setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept")
190
+
191
+ if req.method === Rest.Options {
192
+ res->sendStatus(200)
193
+ } else {
194
+ next()
195
+ }
196
+ }
197
+ app->useFor("/console", consoleCorsMiddleware)
198
+ app->useFor("/metrics", consoleCorsMiddleware)
199
+ app->useFor("/metrics/runtime", consoleCorsMiddleware)
200
+
201
+ app->get("/healthz", (_req, res) => {
202
+ // this is the machine readable port used in kubernetes to check the health of this service.
203
+ // aditional health information could be added in the future (info about errors, back-offs, etc).
204
+ res->sendStatus(200)
205
+ })
206
+
207
+ app->get("/console/state", (_req, res) => {
208
+ let state = if isDevelopmentMode {
209
+ getState()
210
+ } else {
211
+ Disabled({})
212
+ }
213
+
214
+ res->json(state->S.reverseConvertToJsonOrThrow(stateSchema))
215
+ })
216
+
217
+ app->post("/console/syncCache", (_req, res) => {
218
+ if isDevelopmentMode {
219
+ (ctx.persistence->Persistence.getInitializedStorageOrThrow).dumpEffectCache()
220
+ ->Promise.thenResolve(_ => res->json(Boolean(true)))
221
+ ->Promise.done
222
+ } else {
223
+ res->json(Boolean(false))
224
+ }
225
+ })
226
+
227
+ let runtimeRegistry = PromClient.makeRegistry()
228
+ PromClient.collectDefaultMetrics({"register": runtimeRegistry})
229
+
230
+ app->get("/metrics", (_req, res) => {
231
+ res->set("Content-Type", PromClient.defaultRegister->PromClient.getContentType)
232
+ let _ =
233
+ PromClient.defaultRegister
234
+ ->PromClient.metrics
235
+ ->Promise.thenResolve(metrics => res->endWithData(metrics))
236
+ })
237
+
238
+ app->get("/metrics/runtime", (_req, res) => {
239
+ res->set("Content-Type", runtimeRegistry->PromClient.getContentType)
240
+ let _ =
241
+ runtimeRegistry
242
+ ->PromClient.metrics
243
+ ->Promise.thenResolve(metrics => res->endWithData(metrics))
244
+ })
245
+
246
+ let server = app->listen(Env.serverPort)
247
+ server->Express.onError(err => {
248
+ let code = (err->(Utils.magic: Js.Exn.t => {..}))["code"]
249
+ if code === "EADDRINUSE" {
250
+ Logging.error(
251
+ `Port ${Env.serverPort->Int.toString} is already in use. To fix this either:` ++
252
+ `\n 1. Kill the process using the port: lsof -ti :${Env.serverPort->Int.toString} | xargs kill -9` ++ `\n 2. Use a different port by setting the ENVIO_INDEXER_PORT environment variable: ENVIO_INDEXER_PORT=9899 envio start`,
253
+ )
254
+ } else {
255
+ Logging.errorWithExn(err, "Failed to start indexer server")
256
+ }
257
+ NodeJs.process->NodeJs.exitWithCode(Failure)
258
+ })
259
+ }
260
+
261
+ type args = {@as("tui-off") tuiOff?: bool}
262
+
263
+ type process
264
+ @val external process: process = "process"
265
+ @get external argv: process => 'a = "argv"
266
+
267
+ type mainArgs = Yargs.parsedArgs<args>
268
+
269
+ let start = async (
270
+ ~makeGeneratedConfig: unit => Config.t,
271
+ ~persistence: Persistence.t,
272
+ ~isTest=false,
273
+ ) => {
274
+ let mainArgs: mainArgs = process->argv->Yargs.hideBin->Yargs.yargs->Yargs.argv
275
+ let shouldUseTui = !isTest && !(mainArgs.tuiOff->Belt.Option.getWithDefault(Env.tuiOffEnvVar))
276
+ // The most simple check to verify whether we are running in development mode
277
+ // and prevent exposing the console to public, when creating a real deployment.
278
+ // Note: isTest overrides isDevelopmentMode to ensure proper process exit in test mode.
279
+ let isDevelopmentMode = !isTest && Env.Db.password === "testing"
280
+
281
+ // Register all handlers first, then get the config with registrations
282
+ let configWithoutRegistrations = makeGeneratedConfig()
283
+ let registrations = await HandlerLoader.registerAllHandlers(~config=configWithoutRegistrations)
284
+ let config = makeGeneratedConfig()
285
+ let config = if isTest {
286
+ {...config, shouldRollbackOnReorg: false}
287
+ } else {
288
+ config
289
+ }
290
+ let ctx = {
291
+ Ctx.registrations,
292
+ config,
293
+ persistence,
294
+ }
295
+
296
+ let envioVersion = Utils.EnvioPackage.value.version
297
+ Prometheus.Info.set(~version=envioVersion)
298
+ Prometheus.ProcessStartTimeSeconds.set()
299
+ Prometheus.RollbackEnabled.set(~enabled=ctx.config.shouldRollbackOnReorg)
300
+
301
+ if !isTest {
302
+ startServer(~ctx, ~isDevelopmentMode, ~getState=() =>
303
+ switch globalGsManagerRef.contents {
304
+ | None => Initializing({})
305
+ | Some(gsManager) => {
306
+ let state = gsManager->GlobalStateManager.getState
307
+ let chains =
308
+ state.chainManager.chainFetchers
309
+ ->ChainMap.values
310
+ ->Array.map(cf => {
311
+ let {fetchState} = cf
312
+ let latestFetchedBlockNumber = Pervasives.max(
313
+ FetchState.bufferBlockNumber(fetchState),
314
+ 0,
315
+ )
316
+ let knownHeight =
317
+ cf->ChainFetcher.hasProcessedToEndblock
318
+ ? cf.fetchState.endBlock->Option.getWithDefault(cf.fetchState.knownHeight)
319
+ : cf.fetchState.knownHeight
320
+
321
+ {
322
+ chainId: cf.chainConfig.id->Js.Int.toFloat,
323
+ poweredByHyperSync: (
324
+ cf.sourceManager->SourceManager.getActiveSource
325
+ ).poweredByHyperSync,
326
+ latestFetchedBlockNumber,
327
+ knownHeight,
328
+ numBatchesFetched: 0,
329
+ startBlock: cf.fetchState.startBlock,
330
+ endBlock: cf.fetchState.endBlock,
331
+ firstEventBlockNumber: cf.fetchState.firstEventBlock,
332
+ latestProcessedBlock: cf.committedProgressBlockNumber === -1
333
+ ? None
334
+ : Some(cf.committedProgressBlockNumber),
335
+ timestampCaughtUpToHeadOrEndblock: cf.timestampCaughtUpToHeadOrEndblock,
336
+ numEventsProcessed: cf.numEventsProcessed,
337
+ numAddresses: cf.fetchState->FetchState.numAddresses,
338
+ }
339
+ })
340
+ Active({
341
+ envioVersion,
342
+ chains,
343
+ indexerStartTime: state.indexerStartTime,
344
+ isPreRegisteringDynamicContracts: false,
345
+ rollbackOnReorg: ctx.config.shouldRollbackOnReorg,
346
+ isUnorderedMultichainMode: switch ctx.config.multichain {
347
+ | Unordered => true
348
+ | Ordered => false
349
+ },
350
+ })
351
+ }
352
+ }
353
+ )
354
+ }
355
+
356
+ await ctx.persistence->Persistence.init(~chainConfigs=ctx.config.chainMap->ChainMap.values)
357
+
358
+ let chainManager = await ChainManager.makeFromDbState(
359
+ ~initialState=ctx.persistence->Persistence.getInitializedState,
360
+ ~config=ctx.config,
361
+ ~registrations=ctx.registrations,
362
+ )
363
+ let globalState = GlobalState.make(~ctx, ~chainManager, ~isDevelopmentMode, ~shouldUseTui)
364
+ let gsManager = globalState->GlobalStateManager.make
365
+ if shouldUseTui {
366
+ let _rerender = Tui.start(~getState=() => gsManager->GlobalStateManager.getState)
367
+ }
368
+ globalGsManagerRef := Some(gsManager)
369
+ gsManager->GlobalStateManager.dispatchTask(NextQuery(CheckAllChains))
370
+ /*
371
+ NOTE:
372
+ This `ProcessEventBatch` dispatch shouldn't be necessary but we are adding for safety, it should immediately return doing
373
+ nothing since there is no events on the queues.
374
+ */
375
+
376
+ gsManager->GlobalStateManager.dispatchTask(ProcessEventBatch)
377
+ }