envio 3.1.2 → 3.2.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 (134) hide show
  1. package/evm.schema.json +83 -11
  2. package/fuel.schema.json +83 -11
  3. package/index.d.ts +184 -3
  4. package/package.json +6 -6
  5. package/src/Batch.res +2 -2
  6. package/src/ChainFetcher.res +27 -3
  7. package/src/ChainFetcher.res.mjs +17 -3
  8. package/src/ChainManager.res +163 -0
  9. package/src/ChainManager.res.mjs +136 -0
  10. package/src/Config.res +213 -30
  11. package/src/Config.res.mjs +102 -41
  12. package/src/Core.res +16 -10
  13. package/src/Ecosystem.res +0 -3
  14. package/src/Env.res +2 -2
  15. package/src/Env.res.mjs +2 -2
  16. package/src/Envio.res +101 -2
  17. package/src/Envio.res.mjs +2 -3
  18. package/src/EventConfigBuilder.res +52 -0
  19. package/src/EventConfigBuilder.res.mjs +32 -0
  20. package/src/EventUtils.res +2 -2
  21. package/src/FetchState.res +23 -14
  22. package/src/FetchState.res.mjs +21 -15
  23. package/src/GlobalState.res +219 -363
  24. package/src/GlobalState.res.mjs +314 -491
  25. package/src/GlobalStateManager.res +49 -59
  26. package/src/GlobalStateManager.res.mjs +5 -4
  27. package/src/GlobalStateManager.resi +1 -1
  28. package/src/HandlerLoader.res +12 -1
  29. package/src/HandlerLoader.res.mjs +6 -1
  30. package/src/HandlerRegister.res +9 -9
  31. package/src/HandlerRegister.res.mjs +9 -9
  32. package/src/Hasura.res +102 -32
  33. package/src/Hasura.res.mjs +88 -34
  34. package/src/InMemoryStore.res +10 -1
  35. package/src/InMemoryStore.res.mjs +4 -1
  36. package/src/InMemoryTable.res +83 -136
  37. package/src/InMemoryTable.res.mjs +57 -86
  38. package/src/Internal.res +54 -5
  39. package/src/Internal.res.mjs +2 -8
  40. package/src/LazyLoader.res +2 -2
  41. package/src/LazyLoader.res.mjs +3 -3
  42. package/src/LoadLayer.res +47 -60
  43. package/src/LoadLayer.res.mjs +28 -50
  44. package/src/LoadLayer.resi +2 -5
  45. package/src/LogSelection.res +4 -4
  46. package/src/LogSelection.res.mjs +5 -7
  47. package/src/Logging.res +1 -1
  48. package/src/Main.res +61 -2
  49. package/src/Main.res.mjs +37 -1
  50. package/src/Persistence.res +3 -16
  51. package/src/PgStorage.res +125 -114
  52. package/src/PgStorage.res.mjs +112 -95
  53. package/src/Ports.res +5 -0
  54. package/src/Ports.res.mjs +9 -0
  55. package/src/Prometheus.res +3 -3
  56. package/src/Prometheus.res.mjs +4 -4
  57. package/src/ReorgDetection.res +4 -4
  58. package/src/ReorgDetection.res.mjs +4 -5
  59. package/src/SafeCheckpointTracking.res +16 -16
  60. package/src/SafeCheckpointTracking.res.mjs +2 -2
  61. package/src/SimulateItems.res +10 -14
  62. package/src/SimulateItems.res.mjs +5 -2
  63. package/src/Sink.res +1 -1
  64. package/src/Sink.res.mjs +1 -2
  65. package/src/SvmTypes.res +9 -0
  66. package/src/SvmTypes.res.mjs +14 -0
  67. package/src/TestIndexer.res +17 -57
  68. package/src/TestIndexer.res.mjs +14 -48
  69. package/src/TestIndexerProxyStorage.res +23 -23
  70. package/src/TestIndexerProxyStorage.res.mjs +12 -15
  71. package/src/Throttler.res +2 -2
  72. package/src/Time.res +2 -2
  73. package/src/Time.res.mjs +2 -2
  74. package/src/UserContext.res +19 -118
  75. package/src/UserContext.res.mjs +10 -66
  76. package/src/Utils.res +15 -15
  77. package/src/Utils.res.mjs +7 -8
  78. package/src/adapters/MarkBatchProcessedAdapter.res +5 -0
  79. package/src/adapters/MarkBatchProcessedAdapter.res.mjs +14 -0
  80. package/src/bindings/BigDecimal.res +1 -1
  81. package/src/bindings/BigDecimal.res.mjs +2 -2
  82. package/src/bindings/ClickHouse.res +8 -6
  83. package/src/bindings/ClickHouse.res.mjs +5 -5
  84. package/src/bindings/Hrtime.res +1 -1
  85. package/src/bindings/Pino.res +2 -2
  86. package/src/bindings/Pino.res.mjs +3 -4
  87. package/src/db/EntityFilter.res +410 -0
  88. package/src/db/EntityFilter.res.mjs +424 -0
  89. package/src/db/EntityHistory.res +1 -1
  90. package/src/db/EntityHistory.res.mjs +1 -1
  91. package/src/db/InternalTable.res +10 -10
  92. package/src/db/InternalTable.res.mjs +41 -45
  93. package/src/db/Schema.res +2 -2
  94. package/src/db/Schema.res.mjs +3 -3
  95. package/src/db/Table.res +106 -22
  96. package/src/db/Table.res.mjs +84 -35
  97. package/src/sources/EventRouter.res +67 -2
  98. package/src/sources/EventRouter.res.mjs +45 -3
  99. package/src/sources/Evm.res +0 -7
  100. package/src/sources/Evm.res.mjs +0 -15
  101. package/src/sources/EvmChain.res +1 -1
  102. package/src/sources/EvmChain.res.mjs +1 -2
  103. package/src/sources/EvmRpcClient.res +42 -0
  104. package/src/sources/EvmRpcClient.res.mjs +64 -0
  105. package/src/sources/Fuel.res +0 -7
  106. package/src/sources/Fuel.res.mjs +0 -15
  107. package/src/sources/HyperFuelSource.res +5 -4
  108. package/src/sources/HyperFuelSource.res.mjs +2 -2
  109. package/src/sources/HyperSyncClient.res +9 -5
  110. package/src/sources/HyperSyncClient.res.mjs +2 -2
  111. package/src/sources/HyperSyncHeightStream.res +2 -2
  112. package/src/sources/HyperSyncHeightStream.res.mjs +2 -2
  113. package/src/sources/HyperSyncSource.res +10 -9
  114. package/src/sources/HyperSyncSource.res.mjs +4 -4
  115. package/src/sources/Rpc.res +1 -5
  116. package/src/sources/Rpc.res.mjs +1 -9
  117. package/src/sources/RpcSource.res +57 -21
  118. package/src/sources/RpcSource.res.mjs +47 -20
  119. package/src/sources/RpcWebSocketHeightStream.res +1 -1
  120. package/src/sources/SourceManager.res +3 -2
  121. package/src/sources/SourceManager.res.mjs +1 -1
  122. package/src/sources/Svm.res +3 -10
  123. package/src/sources/Svm.res.mjs +4 -18
  124. package/src/sources/SvmHyperSyncClient.res +265 -0
  125. package/src/sources/SvmHyperSyncClient.res.mjs +28 -0
  126. package/src/sources/SvmHyperSyncSource.res +638 -0
  127. package/src/sources/SvmHyperSyncSource.res.mjs +557 -0
  128. package/src/tui/Tui.res +9 -2
  129. package/src/tui/Tui.res.mjs +18 -3
  130. package/src/tui/components/BufferedProgressBar.res +2 -2
  131. package/src/tui/components/TuiData.res +3 -0
  132. package/svm.schema.json +523 -14
  133. package/src/TableIndices.res +0 -115
  134. package/src/TableIndices.res.mjs +0 -144
@@ -10,9 +10,7 @@ import * as Utils from "./Utils.res.mjs";
10
10
  import * as Address from "./Address.res.mjs";
11
11
  import * as ChainMap from "./ChainMap.res.mjs";
12
12
  import * as Internal from "./Internal.res.mjs";
13
- import * as Belt_Array from "@rescript/runtime/lib/es6/Belt_Array.js";
14
13
  import * as BigDecimal from "./bindings/BigDecimal.res.mjs";
15
- import * as Belt_Option from "@rescript/runtime/lib/es6/Belt_Option.js";
16
14
  import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
17
15
  import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
18
16
  import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
@@ -25,7 +23,7 @@ import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_excep
25
23
  let name = "envio_addresses";
26
24
 
27
25
  function makeId(chainId, address) {
28
- return String(chainId) + "-" + address;
26
+ return chainId.toString() + "-" + address;
29
27
  }
30
28
 
31
29
  function getAddress(entity) {
@@ -41,14 +39,12 @@ let schema = S$RescriptSchema.schema(s => ({
41
39
  contract_name: s.m(S$RescriptSchema.string)
42
40
  }));
43
41
 
44
- let rowsSchema = S$RescriptSchema.array(schema);
45
-
46
42
  let table = Table.mkTable(name, undefined, [
47
- Table.mkField("id", "String", S$RescriptSchema.string, undefined, undefined, undefined, true, undefined, undefined, undefined),
48
- Table.mkField("chain_id", "Int32", S$RescriptSchema.int, undefined, undefined, undefined, undefined, undefined, undefined, undefined),
49
- Table.mkField("registration_block", "Int32", S$RescriptSchema.int, undefined, undefined, undefined, undefined, undefined, undefined, undefined),
50
- Table.mkField("registration_log_index", "Int32", S$RescriptSchema.int, undefined, undefined, undefined, undefined, undefined, undefined, undefined),
51
- Table.mkField("contract_name", "String", S$RescriptSchema.string, undefined, undefined, undefined, undefined, undefined, undefined, undefined)
43
+ Table.mkField("id", "String", S$RescriptSchema.string, undefined, undefined, undefined, true, undefined, undefined, undefined, undefined, undefined),
44
+ Table.mkField("chain_id", "Int32", S$RescriptSchema.int, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined),
45
+ Table.mkField("registration_block", "Int32", S$RescriptSchema.int, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined),
46
+ Table.mkField("registration_log_index", "Int32", S$RescriptSchema.int, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined),
47
+ Table.mkField("contract_name", "String", S$RescriptSchema.string, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined)
52
48
  ], undefined);
53
49
 
54
50
  let entityConfig_storage = {
@@ -60,7 +56,6 @@ let entityConfig = {
60
56
  name: name,
61
57
  index: -1,
62
58
  schema: schema,
63
- rowsSchema: rowsSchema,
64
59
  table: table,
65
60
  storage: entityConfig_storage
66
61
  };
@@ -71,7 +66,6 @@ let EnvioAddresses = {
71
66
  makeId: makeId,
72
67
  getAddress: getAddress,
73
68
  schema: schema,
74
- rowsSchema: rowsSchema,
75
69
  table: table,
76
70
  entityConfig: entityConfig
77
71
  };
@@ -113,24 +107,48 @@ let publicConfigChainSchema = S$RescriptSchema.schema(s => ({
113
107
  contracts: s.m(S$RescriptSchema.option(S$RescriptSchema.dict(chainContractSchema)))
114
108
  }));
115
109
 
110
+ let svmEventDescriptorSchema = S$RescriptSchema.schema(s => ({
111
+ discriminator: s.m(S$RescriptSchema.option(S$RescriptSchema.string)),
112
+ discriminatorByteLen: s.m(S$RescriptSchema.int),
113
+ includeTransaction: s.m(S$RescriptSchema.bool),
114
+ includeLogs: s.m(S$RescriptSchema.bool),
115
+ includeTokenBalances: s.m(S$RescriptSchema.bool),
116
+ accountFilters: s.m(S$RescriptSchema.option(S$RescriptSchema.array(S$RescriptSchema.schema(s => ({
117
+ position: s.m(S$RescriptSchema.int),
118
+ values: s.m(S$RescriptSchema.array(S$RescriptSchema.string))
119
+ }))))),
120
+ isInner: s.m(S$RescriptSchema.option(S$RescriptSchema.bool)),
121
+ accounts: s.m(S$RescriptSchema.option(S$RescriptSchema.array(S$RescriptSchema.string))),
122
+ args: s.m(S$RescriptSchema.option(S$RescriptSchema.json(false)))
123
+ }));
124
+
125
+ let svmAbiSchema = S$RescriptSchema.schema(s => ({
126
+ programId: s.m(S$RescriptSchema.string),
127
+ definedTypes: s.m(S$RescriptSchema.json(false)),
128
+ source: s.m(S$RescriptSchema.string)
129
+ }));
130
+
116
131
  let contractEventItemSchema = S$RescriptSchema.schema(s => ({
117
132
  name: s.m(S$RescriptSchema.string),
118
133
  sighash: s.m(S$RescriptSchema.string),
119
134
  params: s.m(S$RescriptSchema.option(S$RescriptSchema.array(EventConfigBuilder.paramMetaSchema))),
120
135
  kind: s.m(S$RescriptSchema.option(S$RescriptSchema.string)),
121
136
  blockFields: s.m(S$RescriptSchema.option(S$RescriptSchema.array(Internal.evmBlockFieldSchema))),
122
- transactionFields: s.m(S$RescriptSchema.option(S$RescriptSchema.array(Internal.evmTransactionFieldSchema)))
137
+ transactionFields: s.m(S$RescriptSchema.option(S$RescriptSchema.array(Internal.evmTransactionFieldSchema))),
138
+ svm: s.m(S$RescriptSchema.option(svmEventDescriptorSchema))
123
139
  }));
124
140
 
125
141
  let contractConfigSchema = S$RescriptSchema.schema(s => ({
126
142
  abi: s.m(S$RescriptSchema.json(false)),
127
143
  handler: s.m(S$RescriptSchema.option(S$RescriptSchema.string)),
128
- events: s.m(S$RescriptSchema.option(S$RescriptSchema.array(contractEventItemSchema)))
144
+ events: s.m(S$RescriptSchema.option(S$RescriptSchema.array(contractEventItemSchema))),
145
+ svmAbi: s.m(S$RescriptSchema.option(svmAbiSchema))
129
146
  }));
130
147
 
131
148
  let publicConfigEcosystemSchema = S$RescriptSchema.schema(s => ({
132
149
  chains: s.m(S$RescriptSchema.dict(publicConfigChainSchema)),
133
- contracts: s.m(S$RescriptSchema.option(S$RescriptSchema.dict(contractConfigSchema)))
150
+ contracts: s.m(S$RescriptSchema.option(S$RescriptSchema.dict(contractConfigSchema))),
151
+ programs: s.m(S$RescriptSchema.option(S$RescriptSchema.dict(contractConfigSchema)))
134
152
  }));
135
153
 
136
154
  let publicConfigEvmSchema = S$RescriptSchema.schema(s => ({
@@ -158,6 +176,8 @@ let derivedFieldSchema = S$RescriptSchema.schema(s => ({
158
176
 
159
177
  let propertySchema = S$RescriptSchema.schema(s => ({
160
178
  name: s.m(S$RescriptSchema.string),
179
+ postgresDbName: s.m(S$RescriptSchema.option(S$RescriptSchema.string)),
180
+ clickhouseDbName: s.m(S$RescriptSchema.option(S$RescriptSchema.string)),
161
181
  type: s.m(S$RescriptSchema.string),
162
182
  isNullable: s.m(S$RescriptSchema.option(S$RescriptSchema.bool)),
163
183
  isArray: s.m(S$RescriptSchema.option(S$RescriptSchema.bool)),
@@ -299,7 +319,7 @@ function parseEntitiesFromJson(entitiesJson, enumConfigsByName, globalStorage) {
299
319
  let entityName = entityJson.name;
300
320
  let fields = entityJson.properties.map(prop => {
301
321
  let match = getFieldTypeAndSchema(prop, enumConfigsByName);
302
- return Table.mkField(prop.name, match[0], match[1], undefined, match[3], match[2], prop.name === "id", match[4], prop.linkedEntity, prop.description);
322
+ return Table.mkField(prop.name, match[0], match[1], undefined, match[3], match[2], prop.name === "id", match[4], prop.linkedEntity, prop.description, prop.postgresDbName, prop.clickhouseDbName);
303
323
  });
304
324
  let derivedFields = Stdlib_Option.getOr(entityJson.derivedFields, []).map(df => Table.mkDerivedFromField(df.fieldName, df.derivedFromEntity, df.derivedFromField, df.description));
305
325
  let compositeIndices = Stdlib_Option.getOr(entityJson.compositeIndices, []).map(ci => ci.map(f => ({
@@ -307,13 +327,19 @@ function parseEntitiesFromJson(entitiesJson, enumConfigsByName, globalStorage) {
307
327
  direction: f.direction === "Asc" ? "Asc" : "Desc"
308
328
  })));
309
329
  let table = Table.mkTable(entityName, compositeIndices, fields.concat(derivedFields), entityJson.description);
330
+ let getApiFieldName = prop => {
331
+ let match = prop.linkedEntity;
332
+ if (match !== undefined) {
333
+ return prop.name + "_id";
334
+ } else {
335
+ return prop.name;
336
+ }
337
+ };
310
338
  let schema = S$RescriptSchema.schema(s => {
311
339
  let dict = {};
312
340
  entityJson.properties.forEach(prop => {
313
341
  let match = getFieldTypeAndSchema(prop, enumConfigsByName);
314
- let match$1 = prop.linkedEntity;
315
- let dbFieldName = match$1 !== undefined ? prop.name + "_id" : prop.name;
316
- dict[dbFieldName] = s.m(match[1]);
342
+ dict[getApiFieldName(prop)] = s.m(match[1]);
317
343
  });
318
344
  return dict;
319
345
  });
@@ -335,7 +361,6 @@ function parseEntitiesFromJson(entitiesJson, enumConfigsByName, globalStorage) {
335
361
  name: entityName,
336
362
  index: index,
337
363
  schema: schema,
338
- rowsSchema: S$RescriptSchema.array(schema),
339
364
  table: table,
340
365
  storage: storage
341
366
  };
@@ -415,6 +440,7 @@ function fromPublic(publicConfigJson) {
415
440
  let lowercaseAddresses = evm !== undefined ? Stdlib_Option.getOr(Primitive_option.valFromOption(evm).addressFormat, "checksum") === "lowercase" : false;
416
441
  let match$4 = publicConfig.evm;
417
442
  let match$5 = publicConfig.fuel;
443
+ let match$6 = publicConfig.svm;
418
444
  let publicContractsConfig;
419
445
  switch (ecosystemName) {
420
446
  case "evm" :
@@ -424,38 +450,43 @@ function fromPublic(publicConfigJson) {
424
450
  publicContractsConfig = match$5 !== undefined ? Primitive_option.valFromOption(match$5).contracts : undefined;
425
451
  break;
426
452
  case "svm" :
427
- publicContractsConfig = undefined;
453
+ publicContractsConfig = match$6 !== undefined ? Primitive_option.valFromOption(match$6).programs : undefined;
428
454
  break;
429
455
  }
430
456
  let evm$1 = publicConfig.evm;
431
- let match$6;
457
+ let match$7;
432
458
  if (evm$1 !== undefined) {
433
459
  let evm$2 = Primitive_option.valFromOption(evm$1);
434
- match$6 = [
460
+ match$7 = [
435
461
  new Set(EventConfigBuilder.alwaysIncludedBlockFields.concat(Stdlib_Option.getOr(evm$2.globalBlockFields, []))),
436
462
  new Set(Stdlib_Option.getOr(evm$2.globalTransactionFields, []))
437
463
  ];
438
464
  } else {
439
- match$6 = [
465
+ match$7 = [
440
466
  new Set(EventConfigBuilder.alwaysIncludedBlockFields),
441
467
  new Set()
442
468
  ];
443
469
  }
444
- let globalTransactionFieldsSet = match$6[1];
445
- let globalBlockFieldsSet = match$6[0];
470
+ let globalTransactionFieldsSet = match$7[1];
471
+ let globalBlockFieldsSet = match$7[0];
446
472
  let contractDataByName = {};
447
473
  if (publicContractsConfig !== undefined) {
448
474
  Object.entries(publicContractsConfig).forEach(param => {
449
475
  let contractConfig = param[1];
450
476
  let capitalizedName = Utils.$$String.capitalize(param[0]);
451
477
  let abi = contractConfig.abi;
478
+ let events = contractConfig.events;
479
+ let eventSignatures = events !== undefined ? events.map(eventItem => eventItem.sighash) : [];
452
480
  contractDataByName[capitalizedName] = {
453
481
  abi: abi,
454
- events: contractConfig.events
482
+ eventSignatures: eventSignatures,
483
+ events: contractConfig.events,
484
+ svmAbi: contractConfig.svmAbi
455
485
  };
456
486
  });
457
487
  }
458
- let buildContractEvents = (contractName, events, abi, chainId, startBlock) => {
488
+ let buildContractEvents = (contractName, events, abi, chainId, startBlock, addresses, svmDefinedTypesOpt) => {
489
+ let svmDefinedTypes = svmDefinedTypesOpt !== undefined ? svmDefinedTypesOpt : null;
459
490
  if (events !== undefined) {
460
491
  return events.map(eventItem => {
461
492
  let eventName = eventItem.name;
@@ -463,17 +494,27 @@ function fromPublic(publicConfigJson) {
463
494
  let params = Stdlib_Option.getOr(eventItem.params, []);
464
495
  let kind = eventItem.kind;
465
496
  switch (ecosystemName) {
497
+ case "evm" :
498
+ return EventConfigBuilder.buildEvmEventConfig(contractName, eventName, sighash, params, false, undefined, undefined, undefined, chainId, ecosystem.onEventBlockFilterSchema, eventItem.blockFields, eventItem.transactionFields, startBlock, Primitive_option.some(globalBlockFieldsSet), Primitive_option.some(globalTransactionFieldsSet));
466
499
  case "fuel" :
467
500
  if (kind !== undefined) {
468
501
  return EventConfigBuilder.buildFuelEventConfig(contractName, eventName, kind, sighash, abi, false, undefined, undefined, startBlock);
469
502
  } else {
470
503
  return Stdlib_JsError.throwWithMessage(`Fuel event ` + contractName + `.` + eventName + ` is missing "kind" in internal config`);
471
504
  }
472
- case "evm" :
473
505
  case "svm" :
474
- break;
506
+ let len = addresses.length;
507
+ let programId = len !== 1 ? (
508
+ len !== 0 ? Stdlib_JsError.throwWithMessage(`SVM program ` + contractName + ` on chain ` + chainId.toString() + ` has multiple addresses; a program is uniquely identified by a single program_id`) : Stdlib_JsError.throwWithMessage(`SVM program ` + contractName + ` on chain ` + chainId.toString() + ` is missing a program_id`)
509
+ ) : addresses[0];
510
+ let s = eventItem.svm;
511
+ let svm = s !== undefined ? Primitive_option.valFromOption(s) : Stdlib_JsError.throwWithMessage(`SVM instruction ` + contractName + `.` + eventName + ` is missing the "svm" descriptor in internal config`);
512
+ let accountFilters = Stdlib_Option.getOr(svm.accountFilters, []).map(group => group.map(af => ({
513
+ position: af.position,
514
+ values: af.values
515
+ })));
516
+ return EventConfigBuilder.buildSvmInstructionEventConfig(contractName, eventName, programId, svm.discriminator, svm.discriminatorByteLen, svm.includeTransaction, svm.includeLogs, svm.includeTokenBalances, accountFilters, svm.isInner, false, undefined, undefined, Stdlib_Option.getOr(svm.accounts, []), Stdlib_Option.getOr(svm.args, null), svmDefinedTypes, startBlock);
475
517
  }
476
- return EventConfigBuilder.buildEvmEventConfig(contractName, eventName, sighash, params, false, undefined, undefined, undefined, chainId, ecosystem.onEventBlockFilterSchema, eventItem.blockFields, eventItem.transactionFields, startBlock, Primitive_option.some(globalBlockFieldsSet), Primitive_option.some(globalTransactionFieldsSet));
477
518
  });
478
519
  } else {
479
520
  return [];
@@ -510,9 +551,10 @@ function fromPublic(publicConfigJson) {
510
551
  let contractData = param[1];
511
552
  let capitalizedName = param[0];
512
553
  let chainContract = chainContracts[capitalizedName];
513
- let addresses = Stdlib_Option.getOr(Stdlib_Option.flatMap(chainContract, cc => cc.addresses), []).map(parseAddress);
554
+ let rawAddresses = Stdlib_Option.getOr(Stdlib_Option.flatMap(chainContract, cc => cc.addresses), []);
555
+ let addresses = rawAddresses.map(parseAddress);
514
556
  let startBlock = Stdlib_Option.flatMap(chainContract, cc => cc.startBlock);
515
- let events = buildContractEvents(capitalizedName, contractData.events, contractData.abi, chainId, startBlock);
557
+ let events = buildContractEvents(capitalizedName, contractData.events, contractData.abi, chainId, startBlock, rawAddresses, Stdlib_Option.getOr(Stdlib_Option.map(contractData.svmAbi, a => a.definedTypes), null));
516
558
  return {
517
559
  name: capitalizedName,
518
560
  abi: contractData.abi,
@@ -521,6 +563,18 @@ function fromPublic(publicConfigJson) {
521
563
  startBlock: startBlock
522
564
  };
523
565
  });
566
+ let contractNameByAddress = {};
567
+ contracts.forEach(contract => {
568
+ contract.addresses.forEach(address => {
569
+ let existingContractName = contractNameByAddress[address];
570
+ if (existingContractName !== undefined) {
571
+ return Stdlib_JsError.throwWithMessage(existingContractName === contract.name ? `Address ` + address + ` is listed multiple times for the contract ` + contract.name + ` on chain ` + chainId.toString() + `. Please remove the duplicate from your config.` : `Address ` + address + ` on chain ` + chainId.toString() + ` is configured for multiple contracts: ` + existingContractName + ` and ` + contract.name + `. Indexing the same address with multiple contract definitions is not supported. Please define the events on a single contract definition instead.`);
572
+ } else {
573
+ contractNameByAddress[address] = contract.name;
574
+ return;
575
+ }
576
+ });
577
+ });
524
578
  let sourceConfig;
525
579
  switch (ecosystemName) {
526
580
  case "evm" :
@@ -565,11 +619,16 @@ function fromPublic(publicConfigJson) {
565
619
  }) : Stdlib_JsError.throwWithMessage(`Chain ` + chainName + ` is missing hypersync endpoint in config`);
566
620
  break;
567
621
  case "svm" :
622
+ let hypersync$1 = publicChainConfig.hypersync;
568
623
  let rpc = publicChainConfig.rpc;
569
- sourceConfig = rpc !== undefined ? ({
570
- TAG: "SvmSourceConfig",
571
- rpc: rpc
572
- }) : Stdlib_JsError.throwWithMessage(`Chain ` + chainName + ` is missing rpc endpoint in config`);
624
+ if (Stdlib_Option.isNone(hypersync$1) && Stdlib_Option.isNone(rpc)) {
625
+ Stdlib_JsError.throwWithMessage(`Chain ` + chainName + ` is missing a data source: provide either an rpc endpoint or an experimental hypersync config`);
626
+ }
627
+ sourceConfig = {
628
+ TAG: "SvmSourceConfig",
629
+ hypersync: hypersync$1,
630
+ rpc: rpc
631
+ };
573
632
  break;
574
633
  }
575
634
  let tmp;
@@ -663,7 +722,7 @@ function getEventConfig(config, contractName, eventName, chainId) {
663
722
  if (acc !== undefined) {
664
723
  return acc;
665
724
  } else {
666
- return Belt_Option.flatMap(chain.contracts.find(c => c.name === contractName), contract => contract.events.find(e => e.name === eventName));
725
+ return Stdlib_Option.flatMap(chain.contracts.find(c => c.name === contractName), contract => contract.events.find(e => e.name === eventName));
667
726
  }
668
727
  });
669
728
  }
@@ -782,8 +841,8 @@ function diffPaths(stored, current) {
782
841
  let maxLen = Math.max(s.length, c.length);
783
842
  for (let i = 0; i < maxLen; ++i) {
784
843
  let p = prefix + `[` + i.toString() + `]`;
785
- let match = Belt_Array.get(s, i);
786
- let match$1 = Belt_Array.get(c, i);
844
+ let match = s[i];
845
+ let match$1 = c[i];
787
846
  if (match !== undefined && match$1 !== undefined) {
788
847
  go(match, match$1, p);
789
848
  } else {
@@ -883,7 +942,7 @@ function diffPaths(stored, current) {
883
942
  if (firstHit !== undefined) {
884
943
  runTier(firstHit);
885
944
  } else {
886
- let knownSet = new Set(Belt_Array.concatMany(tiers));
945
+ let knownSet = new Set(tiers.flat());
887
946
  runTier(Array.from(new Set(Object.keys(stored).concat(Object.keys(current)))).filter(k => !knownSet.has(k)).toSorted(Primitive_string.compare).filter(topKeyDiffers));
888
947
  }
889
948
  } else {
@@ -930,6 +989,8 @@ export {
930
989
  rpcConfigSchema,
931
990
  chainContractSchema,
932
991
  publicConfigChainSchema,
992
+ svmEventDescriptorSchema,
993
+ svmAbiSchema,
933
994
  contractEventItemSchema,
934
995
  contractConfigSchema,
935
996
  publicConfigEcosystemSchema,
package/src/Core.res CHANGED
@@ -1,19 +1,25 @@
1
1
  // Resolution order:
2
- // 1. Production: require("envio-{os}-{arch}") platform-specific npm package
3
- // 2. Dev build: find repo cargo build --lib load from target/debug/
2
+ // 1. Production: require("envio-{os}-{arch}") - platform-specific npm package
3
+ // 2. Dev build: find repo -> cargo build --lib -> load from target/debug/
4
4
 
5
5
  // NAPI encodes Rust `Option<T>` as `null | T` (never `undefined`), so the
6
6
  // tighter `Null.t` captures the exact boundary shape.
7
- type hypersyncClientCtor
8
- type decoderCtor
7
+ type evmHypersyncClientCtor
8
+ type evmRpcClientCtor
9
+ type evmDecoderCtor
10
+ type svmHypersyncClientCtor
9
11
 
10
12
  type addon = {
11
13
  getConfigJson: (~configPath: Null.t<string>, ~directory: Null.t<string>) => string,
12
14
  runCli: (~args: array<string>, ~envioPackageDir: Null.t<string>) => promise<Null.t<string>>,
13
- @as("HypersyncClient")
14
- hypersyncClient: hypersyncClientCtor,
15
- @as("Decoder")
16
- decoder: decoderCtor,
15
+ @as("EvmHypersyncClient")
16
+ evmHypersyncClient: evmHypersyncClientCtor,
17
+ @as("EvmRpcClient")
18
+ evmRpcClient: evmRpcClientCtor,
19
+ @as("EvmDecoder")
20
+ evmDecoder: evmDecoderCtor,
21
+ @as("SvmHypersyncClient")
22
+ svmHypersyncClient: svmHypersyncClientCtor,
17
23
  }
18
24
 
19
25
  @module("node:module") external createRequire: string => {..} = "createRequire"
@@ -122,8 +128,8 @@ let loadAddon = () => {
122
128
  }
123
129
 
124
130
  // Only swallow MODULE_NOT_FOUND (the optional package isn't installed on
125
- // this host). Any other failure corrupt .node, ABI mismatch, dlopen
126
- // error is a real load failure and must surface.
131
+ // this host). Any other failure - corrupt .node, ABI mismatch, dlopen
132
+ // error - is a real load failure and must surface.
127
133
  let rec tryRequire = i =>
128
134
  switch candidates[i] {
129
135
  | None => None
package/src/Ecosystem.res CHANGED
@@ -7,9 +7,6 @@ type t = {
7
7
  blockNumberName: string,
8
8
  blockTimestampName: string,
9
9
  blockHashName: string,
10
- getNumber: Internal.eventBlock => int,
11
- getTimestamp: Internal.eventBlock => int,
12
- getId: Internal.eventBlock => string,
13
10
  cleanUpRawEventFieldsInPlace: JSON.t => unit,
14
11
  /** Method name that the block handler is exposed under on the public
15
12
  `indexer` object — `"onBlock"` for chain-based ecosystems, `"onSlot"`
package/src/Env.res CHANGED
@@ -15,7 +15,7 @@ let maxPartitionConcurrency =
15
15
  // unwritten batch items) the store holds before processing waits for the write
16
16
  // cycle to catch up.
17
17
  let inMemoryObjectsTarget =
18
- envSafe->EnvSafe.get("ENVIO_IN_MEMORY_OBJECTS_TARGET", S.int, ~fallback=100_000)->Belt.Int.toFloat
18
+ envSafe->EnvSafe.get("ENVIO_IN_MEMORY_OBJECTS_TARGET", S.int, ~fallback=100_000)->Int.toFloat
19
19
 
20
20
  // FIXME: This broke HS grafana dashboard. Should investigate it later. Maybe we should use :: as a default value?
21
21
  // We want to be able to set it to 0.0.0.0
@@ -86,7 +86,7 @@ Logging.setLogger(
86
86
  ~logStrategy,
87
87
  ~logFilePath,
88
88
  ~defaultFileLogLevel,
89
- ~userLogLevel=userLogLevel->Belt.Option.getWithDefault(#info),
89
+ ~userLogLevel=userLogLevel->Option.getOr(#info),
90
90
  ),
91
91
  )
92
92
 
package/src/Env.res.mjs CHANGED
@@ -3,7 +3,7 @@
3
3
  import * as EnvSafe from "./EnvSafe.res.mjs";
4
4
  import * as Logging from "./Logging.res.mjs";
5
5
  import * as Postgres from "./bindings/Postgres.res.mjs";
6
- import * as Belt_Option from "@rescript/runtime/lib/es6/Belt_Option.js";
6
+ import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
7
7
  import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
8
8
  import * as HyperSyncClient from "./sources/HyperSyncClient.res.mjs";
9
9
  import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
@@ -71,7 +71,7 @@ let logStrategy = EnvSafe.get(envSafe, "LOG_STRATEGY", S$RescriptSchema.$$enum([
71
71
  "both-prettyconsole"
72
72
  ]), undefined, "console-pretty", undefined, undefined);
73
73
 
74
- Logging.setLogger(Logging.makeLogger(logStrategy, logFilePath, defaultFileLogLevel, Belt_Option.getWithDefault(userLogLevel, "info")));
74
+ Logging.setLogger(Logging.makeLogger(logStrategy, logFilePath, defaultFileLogLevel, Stdlib_Option.getOr(userLogLevel, "info")));
75
75
 
76
76
  let host = EnvSafe.get(envSafe, "ENVIO_PG_HOST", S$RescriptSchema.string, undefined, undefined, "localhost", undefined);
77
77
 
package/src/Envio.res CHANGED
@@ -20,6 +20,105 @@ type svmOnSlotArgs<'context> = {
20
20
  context: 'context,
21
21
  }
22
22
 
23
+ /** Borsh-decoded instruction view. Present whenever a `ProgramSchema` was
24
+ attached to the program (bundled schema, Anchor IDL, or hand-written YAML
25
+ `accounts`/`args`). Absent (`None`) when no schema applied or the
26
+ discriminator didn't match any registered instruction. */
27
+ type svmInstructionParams = {
28
+ /** Schema-declared instruction name (matches the codegen module suffix). */
29
+ name: string,
30
+ /** Borsh-decoded args. `JSON.Object({})` for no-arg instructions
31
+ (e.g. `VerifyCollection`). POC types this as raw `JSON.t`; cast at the
32
+ handler with `(json :> MyArgsType)` until typed codegen lands. */
33
+ args: JSON.t,
34
+ /** Named accounts in schema order. Keys are exactly the schema-declared
35
+ names; values are base58 pubkey strings. */
36
+ accounts: dict<string>,
37
+ /** Accounts beyond the schema's named list (Anchor `remaining_accounts`,
38
+ IDL drift). `[]` when counts match. */
39
+ extraAccounts: array<string>,
40
+ }
41
+
42
+ type svmTokenBalance = {
43
+ account?: SvmTypes.Pubkey.t,
44
+ mint?: SvmTypes.Pubkey.t,
45
+ owner?: SvmTypes.Pubkey.t,
46
+ preAmount?: string,
47
+ postAmount?: string,
48
+ }
49
+
50
+ type svmTransaction = {
51
+ signatures: array<string>,
52
+ feePayer?: SvmTypes.Pubkey.t,
53
+ success?: bool,
54
+ err?: string,
55
+ fee?: bigint,
56
+ computeUnitsConsumed?: bigint,
57
+ accountKeys: array<SvmTypes.Pubkey.t>,
58
+ recentBlockhash?: string,
59
+ version?: string,
60
+ tokenBalances?: array<svmTokenBalance>,
61
+ }
62
+
63
+ type svmLog = {
64
+ kind: string,
65
+ message: string,
66
+ }
67
+
68
+ /** Block context for a matched instruction. `time`/`hash` follow the
69
+ EVM/Fuel field names so the shared `Ecosystem.t` getters in `Svm.res` read
70
+ them uniformly. */
71
+ type svmInstructionBlock = {
72
+ /** Slot this instruction's block was matched in. */
73
+ slot: int,
74
+ /** Unix block time (seconds). `0` when HyperSync didn't return a block
75
+ for this instruction's slot. */
76
+ time: int,
77
+ /** Block hash. Currently always empty — populated by the future
78
+ reorg-guard `queryBlockHash(slot)` route. */
79
+ hash: string,
80
+ }
81
+
82
+ /** The per-instruction payload handlers receive as their `instruction`
83
+ argument. Carries the matched instruction's own fields plus the
84
+ program/instruction names, parent transaction, scoped logs, and block. */
85
+ type svmInstruction = {
86
+ /** Program name as declared under `programs[].name` in `config.yaml`. */
87
+ programName: string,
88
+ /** Instruction name as declared under `instructions[].name` in
89
+ `config.yaml`. */
90
+ instructionName: string,
91
+ programId: SvmTypes.Pubkey.t,
92
+ /** Raw instruction bytes as `0x`-prefixed hex. */
93
+ data: string,
94
+ accounts: array<SvmTypes.Pubkey.t>,
95
+ /** Path through the call tree: `[outerIndex]` for top-level instructions,
96
+ appended child indices for inner CPI calls. */
97
+ instructionAddress: array<int>,
98
+ isInner: bool,
99
+ /** Discriminator prefixes pre-extracted by HyperSync. Each is `Some` only
100
+ when the underlying instruction is at least that long. */
101
+ d1?: string,
102
+ d2?: string,
103
+ d4?: string,
104
+ d8?: string,
105
+ /** Borsh-decoded params view. See [[svmInstructionParams]]. */
106
+ params?: svmInstructionParams,
107
+ /** Parent transaction. Absent when the per-instruction
108
+ `include_transaction` flag is `false`. */
109
+ transaction?: svmTransaction,
110
+ /** Program log entries scoped to this instruction. Absent when the
111
+ per-instruction `include_logs` flag is `false`. */
112
+ logs?: array<svmLog>,
113
+ block: svmInstructionBlock,
114
+ }
115
+
116
+ /** Arguments passed to handlers registered via `indexer.onInstruction`. */
117
+ type svmOnInstructionArgs<'context> = {
118
+ instruction: svmInstruction,
119
+ context: 'context,
120
+ }
121
+
23
122
  // Internal-only type for the `indexer.onBlock` (and SVM `onSlot`) `where`
24
123
  // callback argument. The canonical TypeScript shape lives in
25
124
  // `packages/envio/index.d.ts`; the ReScript declaration here is free to
@@ -216,7 +315,7 @@ module TestHelpers = {
216
315
  "0xbDA5747bFD65F08deb54cb465eB87D40e51B197E",
217
316
  "0xdD2FD4581271e230360230F9337D5c0430Bf44C0",
218
317
  "0x8626f6940E2eb28930eFb4CeF49B2d1F2C9C1199",
219
- ]->Belt.Array.map(Address.Evm.fromStringOrThrow)
220
- let defaultAddress = mockAddresses->Belt.Array.getUnsafe(0)
318
+ ]->Array.map(Address.Evm.fromStringOrThrow)
319
+ let defaultAddress = mockAddresses->Array.getUnsafe(0)
221
320
  }
222
321
  }
package/src/Envio.res.mjs CHANGED
@@ -3,7 +3,6 @@
3
3
  import * as Address from "./Address.res.mjs";
4
4
  import * as Process from "process";
5
5
  import * as Internal from "./Internal.res.mjs";
6
- import * as Belt_Array from "@rescript/runtime/lib/es6/Belt_Array.js";
7
6
  import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
8
7
  import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
9
8
 
@@ -67,7 +66,7 @@ function isNonInteractive() {
67
66
  }
68
67
  }
69
68
 
70
- let mockAddresses = Belt_Array.map([
69
+ let mockAddresses = [
71
70
  "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
72
71
  "0x70997970C51812dc3A010C7d01b50e0d17dc79C8",
73
72
  "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC",
@@ -88,7 +87,7 @@ let mockAddresses = Belt_Array.map([
88
87
  "0xbDA5747bFD65F08deb54cb465eB87D40e51B197E",
89
88
  "0xdD2FD4581271e230360230F9337D5c0430Bf44C0",
90
89
  "0x8626f6940E2eb28930eFb4CeF49B2d1F2C9C1199"
91
- ], Address.Evm.fromStringOrThrow);
90
+ ].map(Address.Evm.fromStringOrThrow);
92
91
 
93
92
  let defaultAddress = mockAddresses[0];
94
93
 
@@ -386,6 +386,58 @@ let buildEvmEventConfig = (
386
386
 
387
387
  // ============== Build Fuel event config ==============
388
388
 
389
+ let buildSvmInstructionEventConfig = (
390
+ ~contractName: string,
391
+ ~instructionName: string,
392
+ ~programId: SvmTypes.Pubkey.t,
393
+ ~discriminator: option<string>,
394
+ ~discriminatorByteLen: int,
395
+ ~includeTransaction: bool,
396
+ ~includeLogs: bool,
397
+ ~includeTokenBalances: bool,
398
+ ~accountFilters: array<Internal.svmAccountFilterGroup>,
399
+ ~isInner: option<bool>,
400
+ ~isWildcard: bool,
401
+ ~handler: option<Internal.handler>,
402
+ ~contractRegister: option<Internal.contractRegister>,
403
+ ~accounts: array<string>=[],
404
+ ~args: JSON.t=JSON.Null,
405
+ ~definedTypes: JSON.t=JSON.Null,
406
+ ~startBlock: option<int>=?,
407
+ ): Internal.svmInstructionEventConfig => {
408
+ let paramsSchema =
409
+ S.json(~validate=false)
410
+ ->Utils.Schema.coerceToJsonPgType
411
+ ->(Utils.magic: S.t<JSON.t> => S.t<Internal.eventParams>)
412
+ {
413
+ id: switch discriminator {
414
+ | Some(d) => d
415
+ | None => "none"
416
+ },
417
+ name: instructionName,
418
+ contractName,
419
+ isWildcard,
420
+ handler,
421
+ contractRegister,
422
+ paramsRawEventSchema: paramsSchema,
423
+ simulateParamsSchema: paramsSchema,
424
+ filterByAddresses: false,
425
+ dependsOnAddresses: !isWildcard,
426
+ startBlock,
427
+ programId,
428
+ discriminator,
429
+ discriminatorByteLen,
430
+ includeTransaction,
431
+ includeLogs,
432
+ includeTokenBalances,
433
+ accountFilters,
434
+ isInner,
435
+ accounts,
436
+ args,
437
+ definedTypes,
438
+ }
439
+ }
440
+
389
441
  let buildFuelEventConfig = (
390
442
  ~contractName: string,
391
443
  ~eventName: string,