envio 3.0.2-svm-alpha.2 → 3.1.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 (89) hide show
  1. package/index.d.ts +1 -167
  2. package/package.json +6 -6
  3. package/rescript.json +1 -1
  4. package/src/ChainFetcher.res +1 -25
  5. package/src/ChainFetcher.res.mjs +1 -19
  6. package/src/ChainManager.res +7 -4
  7. package/src/ChainManager.res.mjs +2 -4
  8. package/src/Config.res +11 -159
  9. package/src/Config.res.mjs +16 -60
  10. package/src/Core.res +4 -25
  11. package/src/Ctx.res +1 -0
  12. package/src/Envio.res +0 -103
  13. package/src/EventConfigBuilder.res +0 -52
  14. package/src/EventConfigBuilder.res.mjs +0 -32
  15. package/src/EventProcessing.res +5 -29
  16. package/src/EventProcessing.res.mjs +11 -20
  17. package/src/EventUtils.res +0 -9
  18. package/src/EventUtils.res.mjs +0 -6
  19. package/src/GlobalState.res +20 -29
  20. package/src/GlobalState.res.mjs +9 -25
  21. package/src/HandlerLoader.res +1 -12
  22. package/src/HandlerLoader.res.mjs +1 -6
  23. package/src/Hasura.res +0 -43
  24. package/src/Hasura.res.mjs +0 -38
  25. package/src/InMemoryStore.res +181 -45
  26. package/src/InMemoryStore.res.mjs +143 -40
  27. package/src/InMemoryTable.res +147 -247
  28. package/src/InMemoryTable.res.mjs +131 -230
  29. package/src/Internal.res +6 -62
  30. package/src/Internal.res.mjs +6 -0
  31. package/src/LoadLayer.res +5 -5
  32. package/src/LoadLayer.res.mjs +5 -5
  33. package/src/Main.res +5 -53
  34. package/src/Main.res.mjs +4 -33
  35. package/src/Persistence.res +7 -132
  36. package/src/Persistence.res.mjs +1 -102
  37. package/src/PgStorage.res +52 -39
  38. package/src/PgStorage.res.mjs +48 -28
  39. package/src/ReorgDetection.res +35 -58
  40. package/src/ReorgDetection.res.mjs +21 -29
  41. package/src/SimulateItems.res +10 -23
  42. package/src/SimulateItems.res.mjs +6 -21
  43. package/src/Sink.res +2 -2
  44. package/src/Sink.res.mjs +1 -1
  45. package/src/TableIndices.res +9 -2
  46. package/src/TableIndices.res.mjs +7 -1
  47. package/src/TestIndexer.res +53 -60
  48. package/src/TestIndexer.res.mjs +54 -59
  49. package/src/TestIndexerProxyStorage.res +4 -14
  50. package/src/TestIndexerProxyStorage.res.mjs +1 -5
  51. package/src/UserContext.res +2 -4
  52. package/src/UserContext.res.mjs +4 -5
  53. package/src/Utils.res +0 -2
  54. package/src/Utils.res.mjs +0 -3
  55. package/src/bindings/ClickHouse.res +45 -38
  56. package/src/bindings/ClickHouse.res.mjs +16 -17
  57. package/src/db/InternalTable.res +59 -18
  58. package/src/db/InternalTable.res.mjs +47 -16
  59. package/src/sources/EventRouter.res +0 -65
  60. package/src/sources/EventRouter.res.mjs +0 -43
  61. package/src/sources/HyperFuelSource.res +14 -57
  62. package/src/sources/HyperFuelSource.res.mjs +18 -38
  63. package/src/sources/HyperSync.res +36 -101
  64. package/src/sources/HyperSync.res.mjs +42 -96
  65. package/src/sources/HyperSync.resi +4 -22
  66. package/src/sources/HyperSyncClient.res +49 -56
  67. package/src/sources/HyperSyncClient.res.mjs +16 -18
  68. package/src/sources/HyperSyncSource.res +70 -137
  69. package/src/sources/HyperSyncSource.res.mjs +61 -110
  70. package/src/sources/RpcSource.res +32 -15
  71. package/src/sources/RpcSource.res.mjs +44 -30
  72. package/src/sources/SimulateSource.res +1 -7
  73. package/src/sources/SimulateSource.res.mjs +1 -7
  74. package/src/sources/Source.res +8 -1
  75. package/src/sources/SourceManager.res +9 -0
  76. package/src/sources/SourceManager.res.mjs +10 -0
  77. package/src/sources/SourceManager.resi +2 -0
  78. package/src/sources/Svm.res +2 -2
  79. package/src/sources/Svm.res.mjs +2 -3
  80. package/src/tui/Tui.res +2 -9
  81. package/src/tui/Tui.res.mjs +4 -19
  82. package/src/tui/components/TuiData.res +0 -3
  83. package/svm.schema.json +0 -424
  84. package/src/SvmTypes.res +0 -9
  85. package/src/SvmTypes.res.mjs +0 -14
  86. package/src/sources/HyperSyncSolanaClient.res +0 -251
  87. package/src/sources/HyperSyncSolanaClient.res.mjs +0 -25
  88. package/src/sources/HyperSyncSolanaSource.res +0 -588
  89. package/src/sources/HyperSyncSolanaSource.res.mjs +0 -502
package/index.d.ts CHANGED
@@ -959,137 +959,6 @@ export type SvmOnSlotOptions<Config extends IndexerConfigTypes = GlobalConfig> =
959
959
  readonly where?: (args: SvmOnSlotWhereArgs<Config>) => SvmOnSlotWhereResult;
960
960
  };
961
961
 
962
- // ============== SVM onInstruction types ==============
963
-
964
- /** Borsh-decoded view of an instruction. Present whenever a `ProgramSchema`
965
- * was attached to the program (bundled, Anchor IDL, or hand-written
966
- * `accounts`/`args` in YAML). Absent when no schema applies or the
967
- * discriminator didn't match any registered instruction. */
968
- export type SvmDecodedInstruction = {
969
- /** Schema-declared instruction name. */
970
- readonly name: string;
971
- /** Borsh-decoded args object. POC types this as `unknown`; narrow with a
972
- * locally-declared type until the typed-args codegen lands. */
973
- readonly args: unknown;
974
- /** Named accounts in schema order. Keys are exactly the schema-declared
975
- * names; values are base58 pubkeys. */
976
- readonly accounts: Readonly<Record<string, string>>;
977
- /** Accounts beyond the schema's named list (Anchor `remaining_accounts`,
978
- * IDL drift). Empty when counts match the schema. */
979
- readonly extraAccounts: readonly string[];
980
- };
981
-
982
- /** A single Solana instruction matched by the indexer.
983
- *
984
- * `data` and discriminator prefixes are `0x`-prefixed hex strings; accounts
985
- * are base58 strings. When a Borsh schema is configured (bundled, Anchor
986
- * IDL, or hand-written YAML), `decoded` carries the named-accounts +
987
- * decoded-args view. */
988
- export type SvmInstruction = {
989
- readonly programId: string;
990
- readonly data: string;
991
- readonly accounts: readonly string[];
992
- readonly instructionAddress: readonly number[];
993
- readonly isInner: boolean;
994
- readonly d1?: string;
995
- readonly d2?: string;
996
- readonly d4?: string;
997
- readonly d8?: string;
998
- readonly decoded?: SvmDecodedInstruction;
999
- };
1000
-
1001
- export type SvmTokenBalance = {
1002
- readonly account?: string;
1003
- readonly mint?: string;
1004
- readonly owner?: string;
1005
- /** u64 decimal string. Cast with BigInt(...) for arithmetic. */
1006
- readonly preAmount?: string;
1007
- readonly postAmount?: string;
1008
- };
1009
-
1010
- /** Parent transaction surfaced when an instruction's
1011
- * `include_transaction` flag is `true`. */
1012
- export type SvmTransaction = {
1013
- readonly signatures: readonly string[];
1014
- readonly feePayer?: string;
1015
- readonly success?: boolean;
1016
- readonly err?: string;
1017
- /** Lamports. */
1018
- readonly fee?: bigint;
1019
- readonly computeUnitsConsumed?: bigint;
1020
- readonly accountKeys: readonly string[];
1021
- readonly recentBlockhash?: string;
1022
- readonly version?: string;
1023
- /** SPL Token / Token-2022 balance snapshots for this transaction.
1024
- * Present when `include_token_balances` is `true`. */
1025
- readonly tokenBalances?: readonly SvmTokenBalance[];
1026
- };
1027
-
1028
- export type SvmLog = {
1029
- readonly kind: string;
1030
- readonly message: string;
1031
- };
1032
-
1033
- /** A single Solana instruction event delivered to a handler. Parameterised
1034
- * over `Decoded` so the per-(program, instruction) overload of
1035
- * `onInstruction` can narrow `event.instruction.decoded` to the
1036
- * codegen-generated `{ args, accounts }` shape. */
1037
- export type SvmInstructionEvent<
1038
- Decoded extends SvmDecodedInstruction = SvmDecodedInstruction,
1039
- > = {
1040
- readonly contractName: string;
1041
- readonly eventName: string;
1042
- readonly instruction: Omit<SvmInstruction, "decoded"> & {
1043
- readonly decoded?: Decoded;
1044
- };
1045
- /** Present when the instruction's `include_transaction` is `true`. */
1046
- readonly transaction?: SvmTransaction;
1047
- /** Present when the instruction's `include_logs` is `true`; only logs
1048
- * scoped to this exact instruction (matching `instruction_address`). */
1049
- readonly logs?: readonly SvmLog[];
1050
- readonly slot: number;
1051
- readonly blockTime?: number;
1052
- };
1053
-
1054
- /** Arguments passed to handlers registered via `indexer.onInstruction`. */
1055
- export type SvmOnInstructionHandlerArgs<
1056
- Config extends IndexerConfigTypes = GlobalConfig,
1057
- Event extends SvmInstructionEvent = SvmInstructionEvent,
1058
- > = {
1059
- readonly event: Event;
1060
- readonly context: SvmOnSlotContext<Config>;
1061
- };
1062
-
1063
- /** Shape extracted from `Global.config.svm.programs[P][I]`. The codegen
1064
- * emits `{ args: ...; accounts: ... }` per (program, instruction); this
1065
- * helper turns that into a `SvmDecodedInstruction`-compatible record. */
1066
- type SvmDecodedFromProgramTable<TInstr> = TInstr extends {
1067
- args: infer A;
1068
- accounts: infer Acc extends Readonly<Record<string, string>>;
1069
- }
1070
- ? {
1071
- readonly name: string;
1072
- readonly args: A;
1073
- readonly accounts: Acc;
1074
- readonly extraAccounts: readonly string[];
1075
- }
1076
- : SvmDecodedInstruction;
1077
-
1078
- /** Options for an SVM `indexer.onInstruction` registration. */
1079
- export type SvmOnInstructionOptions<P extends string = string, I extends string = string> = {
1080
- /** Program name as declared under `chains[].programs[].name` in
1081
- * `config.yaml`. */
1082
- readonly program: P;
1083
- /** Instruction name as declared under
1084
- * `chains[].programs[].instructions[].name` in `config.yaml`. */
1085
- readonly instruction: I;
1086
- };
1087
-
1088
- /** Handler function for an SVM `indexer.onInstruction` registration. */
1089
- export type SvmOnInstructionHandler<
1090
- Config extends IndexerConfigTypes = GlobalConfig,
1091
- > = (args: SvmOnInstructionHandlerArgs<Config>) => Promise<void>;
1092
-
1093
962
  // ============== Indexer Types ==============
1094
963
 
1095
964
  // Helper: Check if an ecosystem is configured. Single-ecosystem indexers only
@@ -1267,7 +1136,7 @@ type FuelEcosystem<Config extends IndexerConfigTypes = GlobalConfig> =
1267
1136
  : never
1268
1137
  : never;
1269
1138
 
1270
- // SVM ecosystem type — chains plus instruction + slot handler methods.
1139
+ // SVM ecosystem type — chains plus onSlot handler method. SVM has no onEvent yet.
1271
1140
  type SvmEcosystem<Config extends IndexerConfigTypes = GlobalConfig> =
1272
1141
  "svm" extends keyof Config
1273
1142
  ? Config["svm"] extends { chains: infer Chains }
@@ -1291,41 +1160,7 @@ type SvmEcosystem<Config extends IndexerConfigTypes = GlobalConfig> =
1291
1160
  options: SvmOnSlotOptions<Config>,
1292
1161
  handler: SvmOnSlotHandler<Config>,
1293
1162
  ) => void;
1294
- } & (Config["svm"] extends {
1295
- programs: infer Programs extends Record<string, Record<string, any>>;
1296
1163
  }
1297
- ? {
1298
- /**
1299
- * Register an instruction handler. Dispatch matches on
1300
- * `(programId, discriminator)` from the YAML config.
1301
- * `event.instruction.decoded.args` and
1302
- * `event.instruction.decoded.accounts` are typed from the
1303
- * program's Borsh schema (Anchor IDL, bundled, or
1304
- * hand-written `accounts`/`args` in YAML). `decoded` stays
1305
- * optional at runtime because schema-matching can fail on
1306
- * IDL drift or unknown discriminators.
1307
- */
1308
- readonly onInstruction: <
1309
- P extends keyof Programs & string,
1310
- I extends keyof Programs[P] & string,
1311
- >(
1312
- options: SvmOnInstructionOptions<P, I>,
1313
- handler: (
1314
- args: SvmOnInstructionHandlerArgs<
1315
- Config,
1316
- SvmInstructionEvent<SvmDecodedFromProgramTable<Programs[P][I]>>
1317
- >,
1318
- ) => Promise<void>,
1319
- ) => void;
1320
- }
1321
- : {
1322
- /** Untyped fallback for indexers with no `programs` in
1323
- * config. `decoded` stays the generic shape. */
1324
- readonly onInstruction: (
1325
- options: SvmOnInstructionOptions,
1326
- handler: SvmOnInstructionHandler<Config>,
1327
- ) => void;
1328
- })
1329
1164
  : never
1330
1165
  : never
1331
1166
  : never;
@@ -1341,7 +1176,6 @@ type CodegenRequiredHint =
1341
1176
  "Run 'envio codegen' to generate handler types from config.yaml. Without codegen, the indexer has no contracts, chains, or events to register handlers for.";
1342
1177
  type CodegenRequiredFallback = {
1343
1178
  readonly onEvent: (...hint: CodegenRequiredHint[]) => void;
1344
- readonly onInstruction: (...hint: CodegenRequiredHint[]) => void;
1345
1179
  readonly onBlock: (...hint: CodegenRequiredHint[]) => void;
1346
1180
  readonly onSlot: (...hint: CodegenRequiredHint[]) => void;
1347
1181
  readonly contractRegister: (...hint: CodegenRequiredHint[]) => void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "envio",
3
- "version": "3.0.2-svm-alpha.2",
3
+ "version": "3.1.0-rc.0",
4
4
  "type": "module",
5
5
  "description": "A latency and sync speed optimized, developer friendly blockchain data indexer.",
6
6
  "bin": "./bin.mjs",
@@ -70,10 +70,10 @@
70
70
  "tsx": "4.21.0"
71
71
  },
72
72
  "optionalDependencies": {
73
- "envio-linux-x64": "3.0.2-svm-alpha.2",
74
- "envio-linux-x64-musl": "3.0.2-svm-alpha.2",
75
- "envio-linux-arm64": "3.0.2-svm-alpha.2",
76
- "envio-darwin-x64": "3.0.2-svm-alpha.2",
77
- "envio-darwin-arm64": "3.0.2-svm-alpha.2"
73
+ "envio-linux-x64": "3.1.0-rc.0",
74
+ "envio-linux-x64-musl": "3.1.0-rc.0",
75
+ "envio-linux-arm64": "3.1.0-rc.0",
76
+ "envio-darwin-x64": "3.1.0-rc.0",
77
+ "envio-darwin-arm64": "3.1.0-rc.0"
78
78
  }
79
79
  }
package/rescript.json CHANGED
@@ -18,6 +18,6 @@
18
18
  "dependencies": ["rescript-schema", "@rescript/react"],
19
19
  "compiler-flags": ["-open RescriptSchema"],
20
20
  "warnings": {
21
- "error": "+3"
21
+ "error": "+a"
22
22
  }
23
23
  }
@@ -229,31 +229,7 @@ let make = (
229
229
  ~lowercaseAddresses,
230
230
  )
231
231
  | Config.FuelSourceConfig({hypersync}) => [HyperFuelSource.make({chain, endpointUrl: hypersync})]
232
- | Config.SvmSourceConfig({hypersync, rpc}) =>
233
- switch hypersync {
234
- | None => [Svm.makeRPCSource(~chain, ~rpc)]
235
- | Some(hypersyncUrl) =>
236
- // HyperSync drives instruction sync; RPC remains the height oracle
237
- // (Svm.makeRPCSource's `getFinalizedSlot` route) and the fallback.
238
- let svmEventConfigs =
239
- chainConfig.contracts
240
- ->Array.flatMap(contract => contract.events)
241
- ->(
242
- Utils.magic: array<Internal.eventConfig> => array<Internal.svmInstructionEventConfig>
243
- )
244
- let apiToken = Env.envioApiToken
245
- [
246
- HyperSyncSolanaSource.make({
247
- chain,
248
- endpointUrl: hypersyncUrl,
249
- apiToken,
250
- eventConfigs: svmEventConfigs,
251
- clientMaxRetries: Env.hyperSyncClientMaxRetries,
252
- clientTimeoutMillis: Env.hyperSyncClientTimeoutMillis,
253
- }),
254
- Svm.makeRPCSource(~chain, ~rpc, ~sourceFor=Fallback),
255
- ]
256
- }
232
+ | Config.SvmSourceConfig({rpc}) => [Svm.makeRPCSource(~chain, ~rpc)]
257
233
  // For tests: use ready-to-use sources directly
258
234
  | Config.CustomSources(sources) => sources
259
235
  }
@@ -21,7 +21,6 @@ import * as Stdlib_Promise from "@rescript/runtime/lib/es6/Stdlib_Promise.js";
21
21
  import * as HyperFuelSource from "./sources/HyperFuelSource.res.mjs";
22
22
  import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
23
23
  import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
24
- import * as HyperSyncSolanaSource from "./sources/HyperSyncSolanaSource.res.mjs";
25
24
  import * as SafeCheckpointTracking from "./SafeCheckpointTracking.res.mjs";
26
25
 
27
26
  function configAddresses(chainConfig) {
@@ -133,24 +132,7 @@ function make(chainConfig, indexingAddresses, startBlock, endBlock, firstEventBl
133
132
  })];
134
133
  break;
135
134
  case "SvmSourceConfig" :
136
- let rpc = sources.rpc;
137
- let hypersync = sources.hypersync;
138
- if (hypersync !== undefined) {
139
- let svmEventConfigs = chainConfig.contracts.flatMap(contract => contract.events);
140
- sources$1 = [
141
- HyperSyncSolanaSource.make({
142
- chain: chain,
143
- endpointUrl: hypersync,
144
- apiToken: Env.envioApiToken,
145
- eventConfigs: svmEventConfigs,
146
- clientMaxRetries: Env.hyperSyncClientMaxRetries,
147
- clientTimeoutMillis: Env.hyperSyncClientTimeoutMillis
148
- }),
149
- Svm.makeRPCSource(chain, rpc, "Fallback")
150
- ];
151
- } else {
152
- sources$1 = [Svm.makeRPCSource(chain, rpc, undefined)];
153
- }
135
+ sources$1 = [Svm.makeRPCSource(chain, sources.rpc)];
154
136
  break;
155
137
  case "CustomSources" :
156
138
  sources$1 = sources._0;
@@ -1,5 +1,4 @@
1
1
  type t = {
2
- committedCheckpointId: bigint,
3
2
  chainFetchers: ChainMap.t<ChainFetcher.t>,
4
3
  isInReorgThreshold: bool,
5
4
  // True once every chain has caught up to head/endBlock. Monotonic during a run.
@@ -106,7 +105,6 @@ let makeFromDbState = (
106
105
  }
107
106
 
108
107
  {
109
- committedCheckpointId: initialState.checkpointId,
110
108
  chainFetchers,
111
109
  isInReorgThreshold,
112
110
  isRealtime,
@@ -135,9 +133,14 @@ let nextItemIsNone = (chainManager: t): bool => {
135
133
  )
136
134
  }
137
135
 
138
- let createBatch = (chainManager: t, ~batchSizeTarget: int, ~isRollback: bool): Batch.t => {
136
+ let createBatch = (
137
+ chainManager: t,
138
+ ~committedCheckpointId,
139
+ ~batchSizeTarget: int,
140
+ ~isRollback: bool,
141
+ ): Batch.t => {
139
142
  Batch.make(
140
- ~checkpointIdBeforeBatch=chainManager.committedCheckpointId->BigInt.add(
143
+ ~checkpointIdBeforeBatch=committedCheckpointId->BigInt.add(
141
144
  // Since for rollback we have a diff checkpoint id.
142
145
  // This is needed to currectly overwrite old state
143
146
  // in an append-only ClickHouse insert.
@@ -77,7 +77,6 @@ function makeFromDbState(initialState, config, registrations, reducedPollingInte
77
77
  Prometheus.ProgressReady.setAllReady();
78
78
  }
79
79
  return {
80
- committedCheckpointId: initialState.checkpointId,
81
80
  chainFetchers: chainFetchers,
82
81
  isInReorgThreshold: isInReorgThreshold,
83
82
  isRealtime: isRealtime
@@ -90,7 +89,6 @@ function getChainFetcher(chainManager, chain) {
90
89
 
91
90
  function setChainFetcher(chainManager, chainFetcher) {
92
91
  return {
93
- committedCheckpointId: chainManager.committedCheckpointId,
94
92
  chainFetchers: ChainMap.set(chainManager.chainFetchers, ChainMap.Chain.makeUnsafe(chainFetcher.chainConfig.id), chainFetcher),
95
93
  isInReorgThreshold: chainManager.isInReorgThreshold,
96
94
  isRealtime: chainManager.isRealtime
@@ -101,8 +99,8 @@ function nextItemIsNone(chainManager) {
101
99
  return !Batch.hasReadyItem(ChainMap.map(chainManager.chainFetchers, cf => cf.fetchState));
102
100
  }
103
101
 
104
- function createBatch(chainManager, batchSizeTarget, isRollback) {
105
- return Batch.make(chainManager.committedCheckpointId + (
102
+ function createBatch(chainManager, committedCheckpointId, batchSizeTarget, isRollback) {
103
+ return Batch.make(committedCheckpointId + (
106
104
  isRollback ? 1n : 0n
107
105
  ), ChainMap.map(chainManager.chainFetchers, cf => ({
108
106
  fetchState: cf.fetchState,
package/src/Config.res CHANGED
@@ -28,7 +28,7 @@ type evmRpcConfig = {
28
28
  type sourceConfig =
29
29
  | EvmSourceConfig({hypersync: option<string>, rpcs: array<evmRpcConfig>})
30
30
  | FuelSourceConfig({hypersync: string})
31
- | SvmSourceConfig({hypersync: option<string>, rpc: string})
31
+ | SvmSourceConfig({rpc: string})
32
32
  // For tests: pass custom sources directly
33
33
  | CustomSources(array<Source.t>)
34
34
 
@@ -194,39 +194,6 @@ let publicConfigChainSchema = S.schema(s =>
194
194
  }
195
195
  )
196
196
 
197
- let svmEventDescriptorSchema = S.schema(s =>
198
- {
199
- "discriminator": s.matches(S.option(S.string)),
200
- "discriminatorByteLen": s.matches(S.int),
201
- "includeTransaction": s.matches(S.bool),
202
- "includeLogs": s.matches(S.bool),
203
- "includeTokenBalances": s.matches(S.bool),
204
- "accountFilters": s.matches(
205
- S.option(
206
- S.array(
207
- S.schema(
208
- s => {
209
- "position": s.matches(S.int),
210
- "values": s.matches(S.array(S.string)),
211
- },
212
- ),
213
- ),
214
- ),
215
- ),
216
- "isInner": s.matches(S.option(S.bool)),
217
- "accounts": s.matches(S.option(S.array(S.string))),
218
- "args": s.matches(S.option(S.json(~validate=false))),
219
- }
220
- )
221
-
222
- let svmAbiSchema = S.schema(s =>
223
- {
224
- "programId": s.matches(S.string),
225
- "definedTypes": s.matches(S.json(~validate=false)),
226
- "source": s.matches(S.string),
227
- }
228
- )
229
-
230
197
  let contractEventItemSchema = S.schema(s =>
231
198
  {
232
199
  "name": s.matches(S.string),
@@ -235,7 +202,6 @@ let contractEventItemSchema = S.schema(s =>
235
202
  "kind": s.matches(S.option(S.string)),
236
203
  "blockFields": s.matches(S.option(S.array(Internal.evmBlockFieldSchema))),
237
204
  "transactionFields": s.matches(S.option(S.array(Internal.evmTransactionFieldSchema))),
238
- "svm": s.matches(S.option(svmEventDescriptorSchema)),
239
205
  }
240
206
  )
241
207
 
@@ -245,8 +211,6 @@ let contractConfigSchema = S.schema(s =>
245
211
  "handler": s.matches(S.option(S.string)),
246
212
  // EVM-specific: event signatures for HyperSync queries
247
213
  "events": s.matches(S.option(S.array(contractEventItemSchema))),
248
- // SVM-only: program-level Borsh schema (defined-types registry, source).
249
- "svmAbi": s.matches(S.option(svmAbiSchema)),
250
214
  }
251
215
  )
252
216
 
@@ -254,10 +218,6 @@ let publicConfigEcosystemSchema = S.schema(s =>
254
218
  {
255
219
  "chains": s.matches(S.dict(publicConfigChainSchema)),
256
220
  "contracts": s.matches(S.option(S.dict(contractConfigSchema))),
257
- // SVM-only alias: programs are the SVM analog of EVM/Fuel contracts.
258
- // Parsed via the same `contractConfigSchema` and read in `fromPublic`'s
259
- // `publicContractsConfig` switch.
260
- "programs": s.matches(S.option(S.dict(contractConfigSchema))),
261
221
  }
262
222
  )
263
223
 
@@ -558,19 +518,10 @@ let fromPublic = (publicConfigJson: JSON.t) => {
558
518
  | None => false
559
519
  }
560
520
 
561
- // Parse contract configs (ABIs, events, handlers).
562
- // SVM stores them under `svm.programs` in the public JSON — the per-program
563
- // events drive `indexer.onInstruction` registration the same way EVM/Fuel
564
- // contracts drive `onEvent`.
565
- let publicContractsConfig = switch (
566
- ecosystemName,
567
- publicConfig["evm"],
568
- publicConfig["fuel"],
569
- publicConfig["svm"],
570
- ) {
571
- | (Ecosystem.Evm, Some(evm), _, _) => evm["contracts"]
572
- | (Ecosystem.Fuel, _, Some(fuel), _) => fuel["contracts"]
573
- | (Ecosystem.Svm, _, _, Some(svm)) => svm["programs"]
521
+ // Parse contract configs (ABIs, events, handlers)
522
+ let publicContractsConfig = switch (ecosystemName, publicConfig["evm"], publicConfig["fuel"]) {
523
+ | (Ecosystem.Evm, Some(evm), _) => evm["contracts"]
524
+ | (Ecosystem.Fuel, _, Some(fuel)) => fuel["contracts"]
574
525
  | _ => None
575
526
  }
576
527
 
@@ -588,12 +539,7 @@ let fromPublic = (publicConfigJson: JSON.t) => {
588
539
  | None => (Utils.Set.fromArray(EventConfigBuilder.alwaysIncludedBlockFields), Utils.Set.make())
589
540
  }
590
541
 
591
- let contractDataByName: dict<{
592
- "abi": EvmTypes.Abi.t,
593
- "eventSignatures": array<string>,
594
- "events": option<array<_>>,
595
- "svmAbi": option<{"programId": string, "definedTypes": JSON.t, "source": string}>,
596
- }> = Dict.make()
542
+ let contractDataByName: dict<{"abi": EvmTypes.Abi.t, "events": option<array<_>>}> = Dict.make()
597
543
  switch publicContractsConfig {
598
544
  | Some(contractsDict) =>
599
545
  contractsDict
@@ -601,44 +547,21 @@ let fromPublic = (publicConfigJson: JSON.t) => {
601
547
  ->Array.forEach(((contractName, contractConfig)) => {
602
548
  let capitalizedName = contractName->Utils.String.capitalize
603
549
  let abi = contractConfig["abi"]->(Utils.magic: JSON.t => EvmTypes.Abi.t)
604
- let eventSignatures = switch contractConfig["events"] {
605
- | Some(events) => events->Array.map(eventItem => eventItem["sighash"])
606
- | None => []
607
- }
608
- let widened =
609
- contractConfig->(
610
- Utils.magic: _ => {
611
- "svmAbi": option<{"programId": string, "definedTypes": JSON.t, "source": string}>,
612
- }
613
- )
614
550
  contractDataByName->Dict.set(
615
551
  capitalizedName,
616
- {
617
- "abi": abi,
618
- "eventSignatures": eventSignatures,
619
- "events": contractConfig["events"],
620
- "svmAbi": widened["svmAbi"],
621
- },
552
+ {"abi": abi, "events": contractConfig["events"]},
622
553
  )
623
554
  })
624
555
  | None => ()
625
556
  }
626
557
 
627
- // Build event configs for a contract from JSON event items.
628
- //
629
- // `~addresses` is the chain-side address list. For SVM programs it's the
630
- // single base58 program_id — wired onto each instruction's event config so
631
- // the source can build `(programId, discriminator)`-keyed InstructionSelections.
632
- // EVM and Fuel ignore it (the address lives in `ChainContract.addresses` and
633
- // is looked up at dispatch time, not stamped on the event).
558
+ // Build event configs for a contract from JSON event items
634
559
  let buildContractEvents = (
635
560
  ~contractName,
636
561
  ~events: option<array<_>>,
637
562
  ~abi,
638
563
  ~chainId: int,
639
564
  ~startBlock: option<int>,
640
- ~addresses: array<string>,
641
- ~svmDefinedTypes: JSON.t=JSON.Null,
642
565
  ) => {
643
566
  switch events {
644
567
  | None => []
@@ -669,69 +592,6 @@ let fromPublic = (publicConfigJson: JSON.t) => {
669
592
  `Fuel event ${contractName}.${eventName} is missing "kind" in internal config`,
670
593
  )
671
594
  }
672
- | Ecosystem.Svm =>
673
- let programId = switch addresses {
674
- | [pid] => pid->SvmTypes.Pubkey.fromStringUnsafe
675
- | [] =>
676
- JsError.throwWithMessage(
677
- `SVM program ${contractName} on chain ${chainId->Int.toString} is missing a program_id`,
678
- )
679
- | _ =>
680
- JsError.throwWithMessage(
681
- `SVM program ${contractName} on chain ${chainId->Int.toString} has multiple addresses; a program is uniquely identified by a single program_id`,
682
- )
683
- }
684
- let widenedEventItem =
685
- eventItem->(
686
- Utils.magic: _ => {
687
- "svm": option<{
688
- "discriminator": option<string>,
689
- "discriminatorByteLen": int,
690
- "includeTransaction": bool,
691
- "includeLogs": bool,
692
- "includeTokenBalances": bool,
693
- "accountFilters": option<
694
- array<array<{"position": int, "values": array<string>}>>,
695
- >,
696
- "isInner": option<bool>,
697
- "accounts": option<array<string>>,
698
- "args": option<JSON.t>,
699
- }>,
700
- }
701
- )
702
- let svm = switch widenedEventItem["svm"] {
703
- | Some(s) => s
704
- | None =>
705
- JsError.throwWithMessage(
706
- `SVM instruction ${contractName}.${eventName} is missing the "svm" descriptor in internal config`,
707
- )
708
- }
709
- let accountFilters =
710
- (svm["accountFilters"]->Option.getOr([]))->Array.map(group =>
711
- group->Array.map(af => {
712
- Internal.position: af["position"],
713
- values: af["values"]->SvmTypes.Pubkey.fromStringsUnsafe,
714
- })
715
- )
716
- (EventConfigBuilder.buildSvmInstructionEventConfig(
717
- ~contractName,
718
- ~instructionName=eventName,
719
- ~programId,
720
- ~discriminator=svm["discriminator"],
721
- ~discriminatorByteLen=svm["discriminatorByteLen"],
722
- ~includeTransaction=svm["includeTransaction"],
723
- ~includeLogs=svm["includeLogs"],
724
- ~includeTokenBalances=svm["includeTokenBalances"],
725
- ~accountFilters,
726
- ~isInner=svm["isInner"],
727
- ~isWildcard=false,
728
- ~handler=None,
729
- ~contractRegister=None,
730
- ~accounts=svm["accounts"]->Option.getOr([]),
731
- ~args=svm["args"]->Option.getOr(JSON.Null),
732
- ~definedTypes=svmDefinedTypes,
733
- ~startBlock?,
734
- ) :> Internal.eventConfig)
735
595
  | _ =>
736
596
  (EventConfigBuilder.buildEvmEventConfig(
737
597
  ~contractName,
@@ -791,11 +651,11 @@ let fromPublic = (publicConfigJson: JSON.t) => {
791
651
  ->Dict.toArray
792
652
  ->Array.map(((capitalizedName, contractData)) => {
793
653
  let chainContract = chainContracts->Dict.get(capitalizedName)
794
- let rawAddresses =
654
+ let addresses =
795
655
  chainContract
796
656
  ->Option.flatMap(cc => cc["addresses"])
797
657
  ->Option.getOr([])
798
- let addresses = rawAddresses->Array.map(parseAddress)
658
+ ->Array.map(parseAddress)
799
659
  let startBlock = chainContract->Option.flatMap(cc => cc["startBlock"])
800
660
 
801
661
  // Build event configs from JSON (field selections resolved inline)
@@ -809,10 +669,6 @@ let fromPublic = (publicConfigJson: JSON.t) => {
809
669
  ~abi=contractData["abi"],
810
670
  ~chainId,
811
671
  ~startBlock,
812
- ~addresses=rawAddresses,
813
- ~svmDefinedTypes=contractData["svmAbi"]
814
- ->Option.map(a => a["definedTypes"])
815
- ->Option.getOr(JSON.Null),
816
672
  )
817
673
 
818
674
  {
@@ -877,11 +733,7 @@ let fromPublic = (publicConfigJson: JSON.t) => {
877
733
  }
878
734
  | Ecosystem.Svm =>
879
735
  switch publicChainConfig["rpc"] {
880
- | Some(rpc) =>
881
- SvmSourceConfig({
882
- hypersync: publicChainConfig["hypersync"],
883
- rpc,
884
- })
736
+ | Some(rpc) => SvmSourceConfig({rpc: rpc})
885
737
  | None => JsError.throwWithMessage(`Chain ${chainName} is missing rpc endpoint in config`)
886
738
  }
887
739
  }