envio 3.10.0-subgraph → 3.11.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 (76) hide show
  1. package/evm.schema.json +21 -4
  2. package/fuel.schema.json +21 -4
  3. package/index.d.ts +1 -1
  4. package/package.json +6 -6
  5. package/src/ChainState.res +9 -73
  6. package/src/ChainState.res.mjs +6 -58
  7. package/src/Config.res +73 -27
  8. package/src/Config.res.mjs +71 -21
  9. package/src/Core.res +0 -15
  10. package/src/Core.res.mjs +0 -11
  11. package/src/EventConfigBuilder.res +14 -10
  12. package/src/EventConfigBuilder.res.mjs +6 -4
  13. package/src/EventProcessing.res +6 -6
  14. package/src/EventProcessing.res.mjs +6 -8
  15. package/src/HandlerLoader.res +8 -20
  16. package/src/HandlerLoader.res.mjs +2 -11
  17. package/src/HandlerRegister.res +12 -11
  18. package/src/HandlerRegister.res.mjs +6 -5
  19. package/src/Internal.res +20 -4
  20. package/src/Internal.res.mjs +9 -0
  21. package/src/Main.res +8 -1
  22. package/src/Main.res.mjs +3 -3
  23. package/src/Persistence.res +11 -1
  24. package/src/Persistence.res.mjs +6 -2
  25. package/src/PgStorage.res +1 -1
  26. package/src/PgStorage.res.mjs +1 -1
  27. package/src/SimulateItems.res +13 -6
  28. package/src/SimulateItems.res.mjs +7 -6
  29. package/src/TestIndexer.res +6 -5
  30. package/src/TestIndexer.res.mjs +5 -4
  31. package/src/UserContext.res +51 -358
  32. package/src/UserContext.res.mjs +35 -271
  33. package/src/db/InternalTable.res +1 -1
  34. package/src/db/InternalTable.res.mjs +2 -1
  35. package/src/sources/ChainSources.res +72 -0
  36. package/src/sources/ChainSources.res.mjs +55 -0
  37. package/src/sources/EvmHyperSyncSource.res +10 -22
  38. package/src/sources/EvmHyperSyncSource.res.mjs +9 -41
  39. package/src/sources/FuelHyperSyncSource.res +10 -18
  40. package/src/sources/FuelHyperSyncSource.res.mjs +8 -38
  41. package/src/sources/HyperSync.res +31 -0
  42. package/src/sources/HyperSync.res.mjs +31 -0
  43. package/src/sources/HyperSync.resi +16 -0
  44. package/src/sources/StartBlockResolver.res +173 -0
  45. package/src/sources/StartBlockResolver.res.mjs +134 -0
  46. package/src/sources/Svm.res +0 -51
  47. package/src/sources/Svm.res.mjs +0 -46
  48. package/src/sources/SvmHyperSyncSource.res +20 -9
  49. package/src/sources/SvmHyperSyncSource.res.mjs +34 -12
  50. package/svm.schema.json +78 -63
  51. package/src/subgraph/blocks.ts +0 -176
  52. package/src/subgraph/calls.ts +0 -217
  53. package/src/subgraph/conformance.ts +0 -102
  54. package/src/subgraph/division.ts +0 -133
  55. package/src/subgraph/errors.ts +0 -90
  56. package/src/subgraph/graph-ts-types/VERSION +0 -2
  57. package/src/subgraph/graph-ts-types/chain/arweave.d.ts +0 -70
  58. package/src/subgraph/graph-ts-types/chain/cosmos.d.ts +0 -327
  59. package/src/subgraph/graph-ts-types/chain/ethereum.d.ts +0 -233
  60. package/src/subgraph/graph-ts-types/chain/near.d.ts +0 -253
  61. package/src/subgraph/graph-ts-types/chain/starknet.d.ts +0 -32
  62. package/src/subgraph/graph-ts-types/common/collections.d.ts +0 -136
  63. package/src/subgraph/graph-ts-types/common/conversion.d.ts +0 -11
  64. package/src/subgraph/graph-ts-types/common/datasource.d.ts +0 -30
  65. package/src/subgraph/graph-ts-types/common/eager-offset.d.ts +0 -0
  66. package/src/subgraph/graph-ts-types/common/json.d.ts +0 -17
  67. package/src/subgraph/graph-ts-types/common/numbers.d.ts +0 -120
  68. package/src/subgraph/graph-ts-types/common/value.d.ts +0 -120
  69. package/src/subgraph/graph-ts-types/common/yaml.d.ts +0 -90
  70. package/src/subgraph/graph-ts-types/global/global.d.ts +0 -194
  71. package/src/subgraph/graph-ts-types/helper-functions.d.ts +0 -22
  72. package/src/subgraph/graph-ts-types/index.d.ts +0 -102
  73. package/src/subgraph/graph-ts.ts +0 -1948
  74. package/src/subgraph/hosts.ts +0 -148
  75. package/src/subgraph/runtime.ts +0 -863
  76. package/src/subgraph/scope.ts +0 -66
@@ -60,26 +60,72 @@ let chainContractSchema = S$RescriptSchema.schema(s => ({
60
60
  startBlock: s.m(S$RescriptSchema.option(S$RescriptSchema.int))
61
61
  }));
62
62
 
63
+ function startBlockOrThrow(chain) {
64
+ let startBlock = chain.startBlock;
65
+ if (startBlock === "latest") {
66
+ return Stdlib_JsError.throwWithMessage(`Chain ` + ChainId.toString(chain.id) + `: the "latest" start block was read before it was resolved. This is a bug in envio - please report it.`);
67
+ } else {
68
+ return startBlock;
69
+ }
70
+ }
71
+
72
+ function startBlockOrZero(chain) {
73
+ let startBlock = chain.startBlock;
74
+ if (startBlock === "latest") {
75
+ return 0;
76
+ } else {
77
+ return startBlock;
78
+ }
79
+ }
80
+
81
+ let startBlockSchema = S$RescriptSchema.union([
82
+ S$RescriptSchema.shape(S$RescriptSchema.int, n => (n)),
83
+ S$RescriptSchema.shape(S$RescriptSchema.literal("latest"), param => "latest")
84
+ ]);
85
+
63
86
  let publicConfigChainSchema = S$RescriptSchema.schema(s => ({
64
87
  id: s.m(ChainId.schema),
65
- startBlock: s.m(S$RescriptSchema.int),
88
+ startBlock: s.m(startBlockSchema),
66
89
  endBlock: s.m(S$RescriptSchema.option(S$RescriptSchema.int)),
67
90
  maxReorgDepth: s.m(S$RescriptSchema.option(S$RescriptSchema.int)),
68
91
  blockLag: s.m(S$RescriptSchema.option(S$RescriptSchema.int)),
69
92
  hypersync: s.m(S$RescriptSchema.option(S$RescriptSchema.string)),
70
93
  rpcs: s.m(S$RescriptSchema.option(S$RescriptSchema.array(rpcConfigSchema))),
71
- rpc: s.m(S$RescriptSchema.option(S$RescriptSchema.string)),
72
94
  contracts: s.m(S$RescriptSchema.option(S$RescriptSchema.dict(chainContractSchema)))
73
95
  }));
74
96
 
97
+ let svmAccountSlotSchema = S$RescriptSchema.schema(s => ({
98
+ name: s.m(S$RescriptSchema.option(S$RescriptSchema.string)),
99
+ optional: s.m(S$RescriptSchema.option(S$RescriptSchema.bool))
100
+ }));
101
+
102
+ function svmAccountSlotFromItem(slot) {
103
+ let match = slot.name;
104
+ let match$1 = slot.optional;
105
+ if (match !== undefined) {
106
+ if (match$1 !== undefined && match$1) {
107
+ return {
108
+ TAG: "Optional",
109
+ _0: match
110
+ };
111
+ } else {
112
+ return {
113
+ TAG: "Required",
114
+ _0: match
115
+ };
116
+ }
117
+ } else {
118
+ return "Unnamed";
119
+ }
120
+ }
121
+
75
122
  let svmEventDescriptorSchema = S$RescriptSchema.schema(s => ({
76
123
  discriminator: s.m(S$RescriptSchema.option(S$RescriptSchema.string)),
77
- accounts: s.m(S$RescriptSchema.option(S$RescriptSchema.array(S$RescriptSchema.string))),
124
+ accounts: s.m(S$RescriptSchema.option(S$RescriptSchema.array(svmAccountSlotSchema))),
78
125
  args: s.m(S$RescriptSchema.option(S$RescriptSchema.json(false)))
79
126
  }));
80
127
 
81
128
  let svmAbiSchema = S$RescriptSchema.schema(s => ({
82
- programId: s.m(S$RescriptSchema.string),
83
129
  definedTypes: s.m(S$RescriptSchema.json(false)),
84
130
  source: s.m(S$RescriptSchema.string)
85
131
  }));
@@ -401,8 +447,7 @@ let publicConfigSchema = S$RescriptSchema.schema(s => ({
401
447
  fuel: s.m(S$RescriptSchema.option(publicConfigEcosystemSchema)),
402
448
  svm: s.m(S$RescriptSchema.option(publicConfigEcosystemSchema)),
403
449
  enums: s.m(S$RescriptSchema.option(S$RescriptSchema.dict(S$RescriptSchema.array(S$RescriptSchema.string)))),
404
- entities: s.m(S$RescriptSchema.option(S$RescriptSchema.array(entityJsonSchema))),
405
- subgraph: s.m(S$RescriptSchema.option(S$RescriptSchema.json(false)))
450
+ entities: s.m(S$RescriptSchema.option(S$RescriptSchema.array(entityJsonSchema)))
406
451
  }));
407
452
 
408
453
  function contractMappingOf(chainConfigs) {
@@ -539,7 +584,7 @@ function fromPublic(publicConfigJson) {
539
584
  ) : addresses[0];
540
585
  let s = eventItem.svm;
541
586
  let svm = s !== undefined ? Primitive_option.valFromOption(s) : Stdlib_JsError.throwWithMessage(`SVM instruction ` + contractName + `.` + eventName + ` is missing the "svm" descriptor in internal config`);
542
- return EventConfigBuilder.buildSvmInstructionEventConfig(contractName, eventName, programId, svm.discriminator, Stdlib_Option.getOr(svm.accounts, []), Stdlib_Option.getOr(svm.args, null), svmDefinedTypes);
587
+ return EventConfigBuilder.buildSvmInstructionEventConfig(contractName, eventName, programId, svm.discriminator, Stdlib_Option.getOr(svm.accounts, []).map(svmAccountSlotFromItem), Stdlib_Option.getOr(svm.args, null), svmDefinedTypes);
543
588
  }
544
589
  });
545
590
  } else {
@@ -573,7 +618,15 @@ function fromPublic(publicConfigJson) {
573
618
  let publicChainConfig = publicChainsConfig[chainName];
574
619
  let chainId = publicChainConfig.id;
575
620
  let chainContracts = Stdlib_Option.getOr(publicChainConfig.contracts, {});
576
- let contracts = Object.entries(contractDataByName).map(param => {
621
+ let contracts = Object.entries(contractDataByName).filter(param => {
622
+ switch (ecosystemName) {
623
+ case "evm" :
624
+ case "fuel" :
625
+ return true;
626
+ case "svm" :
627
+ return Stdlib_Option.isSome(chainContracts[param[0]]);
628
+ }
629
+ }).map(param => {
577
630
  let contractData = param[1];
578
631
  let capitalizedName = param[0];
579
632
  let chainContract = chainContracts[capitalizedName];
@@ -645,15 +698,10 @@ function fromPublic(publicConfigJson) {
645
698
  break;
646
699
  case "svm" :
647
700
  let hypersync$1 = publicChainConfig.hypersync;
648
- let rpc = publicChainConfig.rpc;
649
- if (Stdlib_Option.isNone(hypersync$1) && Stdlib_Option.isNone(rpc)) {
650
- Stdlib_JsError.throwWithMessage(`Chain ` + chainName + ` is missing a data source: provide either an rpc endpoint or an experimental hypersync config`);
651
- }
652
- sourceConfig = {
653
- TAG: "SvmSourceConfig",
654
- hypersync: hypersync$1,
655
- rpc: rpc
656
- };
701
+ sourceConfig = hypersync$1 !== undefined ? ({
702
+ TAG: "SvmSourceConfig",
703
+ hypersync: hypersync$1
704
+ }) : Stdlib_JsError.throwWithMessage(`Chain ` + chainName + ` is missing hypersync endpoint in config`);
657
705
  break;
658
706
  }
659
707
  let tmp;
@@ -730,8 +778,7 @@ function fromPublic(publicConfigJson) {
730
778
  isDev: Stdlib_Option.getOr(publicConfig.isDev, false),
731
779
  userEntitiesByName: userEntitiesByName,
732
780
  userEntities: userEntities,
733
- allEnums: allEnums,
734
- subgraph: publicConfig.subgraph
781
+ allEnums: allEnums
735
782
  };
736
783
  }
737
784
 
@@ -879,7 +926,6 @@ function stripSensitiveData(json) {
879
926
  return;
880
927
  }
881
928
  Utils.Dict.deleteInPlace(chainJson, "rpcs");
882
- Utils.Dict.deleteInPlace(chainJson, "rpc");
883
929
  Utils.Dict.deleteInPlace(chainJson, "hypersync");
884
930
  });
885
931
  };
@@ -888,7 +934,6 @@ function stripSensitiveData(json) {
888
934
  stripChains(cloned["evm"]);
889
935
  stripChains(cloned["fuel"]);
890
936
  stripChains(cloned["svm"]);
891
- Utils.Dict.deleteInPlace(cloned, "subgraph");
892
937
  }
893
938
  return cloned;
894
939
  }
@@ -1086,7 +1131,12 @@ export {
1086
1131
  rpcSourceForSchema,
1087
1132
  rpcConfigSchema,
1088
1133
  chainContractSchema,
1134
+ startBlockOrThrow,
1135
+ startBlockOrZero,
1136
+ startBlockSchema,
1089
1137
  publicConfigChainSchema,
1138
+ svmAccountSlotSchema,
1139
+ svmAccountSlotFromItem,
1090
1140
  svmEventDescriptorSchema,
1091
1141
  svmAbiSchema,
1092
1142
  contractEventItemSchema,
package/src/Core.res CHANGED
@@ -27,16 +27,8 @@ type fromUserApiResult = {
27
27
  indexerCode: Null.t<string>,
28
28
  }
29
29
 
30
- type fromSubgraphOptions = {
31
- name?: string,
32
- env?: dict<string>,
33
- files?: dict<string>,
34
- root?: string,
35
- }
36
-
37
30
  type addon = {
38
31
  getConfigJson: (~configPath: Null.t<string>, ~directory: Null.t<string>) => string,
39
- fromSubgraph: (string, string, fromSubgraphOptions) => fromUserApiResult,
40
32
  encodeIndexedTopic: (~abiType: string, ~value: unknown) => EvmTypes.Hex.t,
41
33
  isSvmPubkey: (~value: string) => bool,
42
34
  fromUserApi: (string, fromUserApiOptions) => fromUserApiResult,
@@ -269,13 +261,6 @@ let fromUserApi = (~schema=?, ~env=?, ~files=?, ~withIndexerTypes=false, yaml) =
269
261
  )
270
262
  }
271
263
 
272
- /// Parses a subgraph project without touching the filesystem: subgraph.yaml and
273
- /// its schema inline, ABI bodies through `files`.
274
- let fromSubgraph = (~name=?, ~env=?, ~files=?, ~root=?, ~manifest, ~schema) => {
275
- let addon = getAddon()
276
- addon.fromSubgraph(manifest, schema, {?name, ?env, ?files, ?root})
277
- }
278
-
279
264
  let runCli = args => {
280
265
  let addon = getAddon()
281
266
  addon.runCli(~args, ~envioPackageDir=Null.make(envioPackageDir))
package/src/Core.res.mjs CHANGED
@@ -195,16 +195,6 @@ function fromUserApi(schema, env, files, withIndexerTypesOpt, yaml) {
195
195
  });
196
196
  }
197
197
 
198
- function fromSubgraph(name, env, files, root, manifest, schema) {
199
- let addon = getAddon();
200
- return addon.fromSubgraph(manifest, schema, {
201
- name: name,
202
- env: env,
203
- files: files,
204
- root: root
205
- });
206
- }
207
-
208
198
  function runCli(args) {
209
199
  let addon = getAddon();
210
200
  return addon.runCli(args, envioPackageDir);
@@ -222,7 +212,6 @@ export {
222
212
  getAddon,
223
213
  getConfigJson,
224
214
  fromUserApi,
225
- fromSubgraph,
226
215
  runCli,
227
216
  }
228
217
  /* envioPackageDir Not a pure module */
@@ -635,7 +635,7 @@ let buildSvmInstructionEventConfig = (
635
635
  ~instructionName: string,
636
636
  ~programId: SvmTypes.Pubkey.t,
637
637
  ~discriminator: option<string>,
638
- ~accounts: array<string>=[],
638
+ ~accounts: array<Internal.svmAccountSlot>=[],
639
639
  ~args: JSON.t=JSON.Null,
640
640
  ~definedTypes: JSON.t=JSON.Null,
641
641
  ): Internal.svmInstructionEventConfig => {
@@ -699,7 +699,7 @@ let resolveSvmWhereOrThrow = (
699
699
  where: JSON.t,
700
700
  ~contractName: string,
701
701
  ~eventName: string,
702
- ~accountNames: array<string>,
702
+ ~accounts: array<Internal.svmAccountSlot>,
703
703
  ): parsedSvmWhere => {
704
704
  let invalid = message =>
705
705
  JsError.throwWithMessage(
@@ -722,26 +722,30 @@ let resolveSvmWhereOrThrow = (
722
722
  | Some(_) => invalid(`The "isInner" filter must be a boolean.`)
723
723
  }
724
724
 
725
+ let namedAccounts = accounts->Array.filterMap(Internal.svmAccountSlotName)
726
+
725
727
  let parseGroup = (group: dict<JSON.t>): Internal.svmAccountFilterGroup =>
726
728
  group
727
729
  ->Dict.toArray
728
730
  ->Array.map(((name, value)) => {
729
- let position = switch accountNames->Array.indexOf(name) {
730
- | -1 if accountNames->Utils.Array.isEmpty =>
731
+ let position = switch accounts->Array.findIndexOpt(slot =>
732
+ slot->Internal.svmAccountSlotName == Some(name)
733
+ ) {
734
+ | None if namedAccounts->Utils.Array.isEmpty =>
731
735
  invalid(
732
- "The instruction has no named accounts to filter on. Add `accounts` and `args` to it in config.yaml, or attach an IDL.",
736
+ "The instruction has no named accounts to filter on. Add `accounts` to it in config.yaml, or attach an IDL.",
733
737
  )
734
- | -1 =>
738
+ | None =>
735
739
  invalid(
736
740
  `The instruction has no account named "${name}" to filter on. Named accounts: ${Utils.Array.quotedJoin(
737
- accountNames,
741
+ namedAccounts,
738
742
  )}.`,
739
743
  )
740
- | position if position >= filterableAccountCount =>
744
+ | Some(position) if position >= filterableAccountCount =>
741
745
  invalid(
742
746
  `Account "${name}" is at position ${position->Int.toString}, and only the first ${filterableAccountCount->Int.toString} accounts of an instruction can be filtered.`,
743
747
  )
744
- | position => position
748
+ | Some(position) => position
745
749
  }
746
750
  let values = value->normalizeOrThrow
747
751
  if values->Utils.Array.isEmpty {
@@ -817,7 +821,7 @@ let buildSvmOnEventRegistration = (
817
821
  where->resolveSvmWhereOrThrow(
818
822
  ~contractName=eventConfig.contractName,
819
823
  ~eventName=eventConfig.name,
820
- ~accountNames=eventConfig.accounts,
824
+ ~accounts=eventConfig.accounts,
821
825
  )
822
826
  }
823
827
 
@@ -12,6 +12,7 @@ import * as LogSelection from "./LogSelection.res.mjs";
12
12
  import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
13
13
  import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
14
14
  import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
15
+ import * as Primitive_object from "@rescript/runtime/lib/es6/Primitive_object.js";
15
16
  import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
16
17
  import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
17
18
  import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
@@ -464,7 +465,7 @@ let svmBlockFilterSchema = S$RescriptSchema.strict(S$RescriptSchema.object(s =>
464
465
  slot: s.f("slot", S$RescriptSchema.option(LogSelection.eventBlockRangeSchema))
465
466
  })));
466
467
 
467
- function resolveSvmWhereOrThrow(where, contractName, eventName, accountNames) {
468
+ function resolveSvmWhereOrThrow(where, contractName, eventName, accounts) {
468
469
  let invalid = message => Stdlib_JsError.throwWithMessage(`Invalid where configuration for the "` + eventName + `" instruction on program "` + contractName + `". ` + message);
469
470
  let obj;
470
471
  obj = typeof where === "object" && where !== null && !Array.isArray(where) ? where : invalid("Expected an object.");
@@ -477,13 +478,14 @@ function resolveSvmWhereOrThrow(where, contractName, eventName, accountNames) {
477
478
  let isInner = match !== undefined ? (
478
479
  typeof match === "boolean" ? match : invalid(`The "isInner" filter must be a boolean.`)
479
480
  ) : undefined;
481
+ let namedAccounts = Stdlib_Array.filterMap(accounts, Internal.svmAccountSlotName);
480
482
  let parseGroup = group => Object.entries(group).map(param => {
481
483
  let name = param[0];
482
- let position = accountNames.indexOf(name);
483
- let position$1 = position !== -1 ? (
484
+ let position = Stdlib_Array.findIndexOpt(accounts, slot => Primitive_object.equal(Internal.svmAccountSlotName(slot), name));
485
+ let position$1 = position !== undefined ? (
484
486
  position >= 10 ? invalid(`Account "` + name + `" is at position ` + position.toString() + `, and only the first ` + (10).toString() + ` accounts of an instruction can be filtered.`) : position
485
487
  ) : (
486
- Utils.$$Array.isEmpty(accountNames) ? invalid("The instruction has no named accounts to filter on. Add `accounts` and `args` to it in config.yaml, or attach an IDL.") : invalid(`The instruction has no account named "` + name + `" to filter on. Named accounts: ` + Utils.$$Array.quotedJoin(accountNames) + `.`)
488
+ Utils.$$Array.isEmpty(namedAccounts) ? invalid("The instruction has no named accounts to filter on. Add `accounts` to it in config.yaml, or attach an IDL.") : invalid(`The instruction has no account named "` + name + `" to filter on. Named accounts: ` + Utils.$$Array.quotedJoin(namedAccounts) + `.`)
487
489
  );
488
490
  let values = normalizeOrThrow(param[1]);
489
491
  if (Utils.$$Array.isEmpty(values)) {
@@ -51,7 +51,7 @@ let runEventHandlerOrThrow = async (
51
51
  isPreload: false,
52
52
  chains,
53
53
  config,
54
- sync: UserContext.makeSyncState(),
54
+ isResolved: false,
55
55
  }
56
56
  await handler(
57
57
  (
@@ -61,7 +61,7 @@ let runEventHandlerOrThrow = async (
61
61
  }: Internal.handlerArgs
62
62
  ),
63
63
  )
64
- contextParams.sync.status = Resolved
64
+ contextParams.isResolved = true
65
65
  } catch {
66
66
  | exn =>
67
67
  throw(
@@ -102,7 +102,7 @@ let runHandlerOrThrow = async (
102
102
  isPreload: false,
103
103
  chains,
104
104
  config,
105
- sync: UserContext.makeSyncState(),
105
+ isResolved: false,
106
106
  }
107
107
  await handler(
108
108
  Ecosystem.makeOnBlockArgs(
@@ -111,7 +111,7 @@ let runHandlerOrThrow = async (
111
111
  ~context=UserContext.getHandlerContext(contextParams),
112
112
  ),
113
113
  )
114
- contextParams.sync.status = Resolved
114
+ contextParams.isResolved = true
115
115
  } catch {
116
116
  | exn =>
117
117
  throw(
@@ -186,7 +186,7 @@ let preloadBatchOrThrow = async (
186
186
  checkpointId,
187
187
  isPreload: true,
188
188
  chains,
189
- sync: UserContext.makeSyncState(),
189
+ isResolved: false,
190
190
  config,
191
191
  }),
192
192
  })
@@ -221,7 +221,7 @@ let preloadBatchOrThrow = async (
221
221
  checkpointId,
222
222
  isPreload: true,
223
223
  chains,
224
- sync: UserContext.makeSyncState(),
224
+ isResolved: false,
225
225
  config,
226
226
  }),
227
227
  )
@@ -38,7 +38,6 @@ let ProcessingError = /* @__PURE__ */Primitive_exceptions.create("EventProcessin
38
38
  async function runEventHandlerOrThrow(item, checkpointId, handler, indexerState, loadManager, persistence, chains, config) {
39
39
  let timeBeforeHandler = Performance.now();
40
40
  try {
41
- let contextParams_sync = UserContext.makeSyncState();
42
41
  let contextParams = {
43
42
  item: item,
44
43
  checkpointId: checkpointId,
@@ -48,13 +47,13 @@ async function runEventHandlerOrThrow(item, checkpointId, handler, indexerState,
48
47
  isPreload: false,
49
48
  chains: chains,
50
49
  config: config,
51
- sync: contextParams_sync
50
+ isResolved: false
52
51
  };
53
52
  await handler({
54
53
  event: Ecosystem.getItemEvent(item, config.ecosystem),
55
54
  context: UserContext.getHandlerContext(contextParams)
56
55
  });
57
- contextParams_sync.status = "Resolved";
56
+ contextParams.isResolved = true;
58
57
  } catch (raw_exn) {
59
58
  let exn = Primitive_exceptions.internalToException(raw_exn);
60
59
  throw {
@@ -80,7 +79,6 @@ async function runHandlerOrThrow(item, checkpointId, indexerState, loadManager,
80
79
  }
81
80
  }
82
81
  try {
83
- let contextParams_sync = UserContext.makeSyncState();
84
82
  let contextParams = {
85
83
  item: item,
86
84
  checkpointId: checkpointId,
@@ -90,10 +88,10 @@ async function runHandlerOrThrow(item, checkpointId, indexerState, loadManager,
90
88
  isPreload: false,
91
89
  chains: chains,
92
90
  config: config,
93
- sync: contextParams_sync
91
+ isResolved: false
94
92
  };
95
93
  await item.onBlockRegistration.handler(Ecosystem.makeOnBlockArgs(item.blockNumber, config.ecosystem, UserContext.getHandlerContext(contextParams)));
96
- contextParams_sync.status = "Resolved";
94
+ contextParams.isResolved = true;
97
95
  return;
98
96
  } catch (raw_exn) {
99
97
  let exn = Primitive_exceptions.internalToException(raw_exn);
@@ -135,7 +133,7 @@ async function preloadBatchOrThrow(batch, loadManager, persistence, config, inde
135
133
  isPreload: true,
136
134
  chains: chains,
137
135
  config: config,
138
- sync: UserContext.makeSyncState()
136
+ isResolved: false
139
137
  })
140
138
  }).then(() => IndexerState.endPreloadHandler(indexerState, timerRef, contractName, eventName))));
141
139
  } catch (exn) {
@@ -153,7 +151,7 @@ async function preloadBatchOrThrow(batch, loadManager, persistence, config, inde
153
151
  isPreload: true,
154
152
  chains: chains,
155
153
  config: config,
156
- sync: UserContext.makeSyncState()
154
+ isResolved: false
157
155
  })))));
158
156
  } catch (exn$1) {
159
157
 
@@ -77,30 +77,18 @@ let autoLoadFromSrcHandlers = async (~handlers: string) => {
77
77
  // `HandlerRegister.finishRegistration`. This loads the user handler files
78
78
  // (populating the global `HandlerRegister` registry as a side effect) and
79
79
  // returns the resulting per-chain registrations.
80
- // The subgraph runtime lives in this package but is never exported: it's
81
- // reached only from here, when the resolved config carries a translated
82
- // manifest.
83
- let registerSubgraph: (JSON.t, ~isDev: bool) => promise<unit> = %raw(`(subgraph, isDev) =>
84
- import("./subgraph/runtime.ts").then((m) => m.registerSubgraph({ ...subgraph, isDev }))`)
85
-
86
80
  let registerAllHandlers = async (~config: Config.t): HandlerRegister.registrationsByChainId => {
87
81
  HandlerRegister.startRegistration(~config)
88
82
 
89
- switch config.subgraph {
90
- // A subgraph project's `src/` holds AssemblyScript mappings, not envio
91
- // handlers, so the usual auto-load would import them without a scope.
92
- | Some(subgraph) => await registerSubgraph(subgraph, ~isDev=config.isDev)
93
- | None =>
94
- // Auto-load all .js files from src/handlers directory
95
- await autoLoadFromSrcHandlers(~handlers=config.handlers)
83
+ // Auto-load all .js files from src/handlers directory
84
+ await autoLoadFromSrcHandlers(~handlers=config.handlers)
96
85
 
97
- // Load contract-specific handlers
98
- let _ = await config.contractHandlers
99
- ->Array.map(({name, handler}) => {
100
- registerContractHandlers(~contractName=name, ~handler)
101
- })
102
- ->Promise.all
103
- }
86
+ // Load contract-specific handlers
87
+ let _ = await config.contractHandlers
88
+ ->Array.map(({name, handler}) => {
89
+ registerContractHandlers(~contractName=name, ~handler)
90
+ })
91
+ ->Promise.all
104
92
 
105
93
  HandlerRegister.finishRegistration(~config)
106
94
  }
@@ -56,18 +56,10 @@ async function autoLoadFromSrcHandlers(handlers) {
56
56
  })));
57
57
  }
58
58
 
59
- let registerSubgraph = ((subgraph, isDev) =>
60
- import("./subgraph/runtime.ts").then((m) => m.registerSubgraph({ ...subgraph, isDev })));
61
-
62
59
  async function registerAllHandlers(config) {
63
60
  HandlerRegister.startRegistration(config);
64
- let subgraph = config.subgraph;
65
- if (subgraph !== undefined) {
66
- await registerSubgraph(subgraph, config.isDev);
67
- } else {
68
- await autoLoadFromSrcHandlers(config.handlers);
69
- await Promise.all(config.contractHandlers.map(param => registerContractHandlers(param.name, param.handler)));
70
- }
61
+ await autoLoadFromSrcHandlers(config.handlers);
62
+ await Promise.all(config.contractHandlers.map(param => registerContractHandlers(param.name, param.handler)));
71
63
  return HandlerRegister.finishRegistration(config);
72
64
  }
73
65
 
@@ -75,7 +67,6 @@ export {
75
67
  toImportUrl,
76
68
  registerContractHandlers,
77
69
  autoLoadFromSrcHandlers,
78
- registerSubgraph,
79
70
  registerAllHandlers,
80
71
  }
81
72
  /* Not a pure module */
@@ -312,13 +312,7 @@ let addOnEventRegistration = (
312
312
  ),
313
313
  )
314
314
  | Svm =>
315
- Some(
316
- EventConfigBuilder.resolveSvmInlineFieldSelection(
317
- fields,
318
- ~contractName,
319
- ~eventName,
320
- ),
321
- )
315
+ Some(EventConfigBuilder.resolveSvmInlineFieldSelection(fields, ~contractName, ~eventName))
322
316
  | Fuel =>
323
317
  JsError.throwWithMessage(
324
318
  `The fields option of the "${eventName}" event registration on contract "${contractName}" is not supported on Fuel. Select the fields in your config instead.`,
@@ -340,13 +334,16 @@ let addOnEventRegistration = (
340
334
  | (Svm, Some(fieldSelection)) if fieldSelection.instructionFields->Utils.Set.has("args") =>
341
335
  let svmEventConfig =
342
336
  eventConfig->(Utils.magic: Internal.eventConfig => Internal.svmInstructionEventConfig)
337
+ // An empty layout is still a layout: it decodes to `{}` and filters
338
+ // out the calls that carry a payload. Only an absent one has nothing
339
+ // to decode.
343
340
  let declaresArgs = switch svmEventConfig.args {
344
- | JSON.Array(args) => args->Array.length > 0
341
+ | JSON.Array(_) => true
345
342
  | _ => false
346
343
  }
347
344
  if !declaresArgs {
348
345
  JsError.throwWithMessage(
349
- `Invalid "args" field in the fields.instruction option of the "${eventName}" instruction on program "${contractName}". The instruction declares no args in config.yaml, so there is nothing to decode. Remove "args" from the selection, or declare the instruction's args.`,
346
+ `Invalid "args" field in the fields.instruction option of the "${eventName}" instruction on program "${contractName}". The instruction attaches no args layout in config.yaml, so there is nothing to decode. Remove "args" from the selection, or give the instruction an \`args\` layout — \`args: []\` if it takes none.`,
350
347
  )
351
348
  }
352
349
  | _ => ()
@@ -800,9 +797,13 @@ let registerOnBlock = (
800
797
 
801
798
  if shouldRegister {
802
799
  matchedAny := true
803
- if range._gte->Option.getOr(chainConfig.startBlock) < chainConfig.startBlock {
800
+ // Off the same object the predicate above was handed, not off
801
+ // `chainConfig`: that one still says whatever config.yaml said, and for
802
+ // `start_block: latest` the resolved head only lives in persisted state.
803
+ let chainStartBlock = (chainObj->(Utils.magic: unknown => {"startBlock": int}))["startBlock"]
804
+ if range._gte->Option.getOr(chainStartBlock) < chainStartBlock {
804
805
  JsError.throwWithMessage(
805
- `The start block for onBlock handler "${name}" is less than the chain start block (${chainConfig.startBlock->Int.toString}). This is not supported yet.`,
806
+ `The start block for onBlock handler "${name}" is less than the chain start block (${chainStartBlock->Int.toString}). This is not supported yet.`,
806
807
  )
807
808
  }
808
809
  switch chainConfig.endBlock {
@@ -238,11 +238,11 @@ function addOnEventRegistration(registration, contractName, eventName, handler,
238
238
  break;
239
239
  case "svm" :
240
240
  if (fieldSelection !== undefined && fieldSelection.instructionFields.has("args")) {
241
- let args = eventConfig.args;
241
+ let match$1 = eventConfig.args;
242
242
  let declaresArgs;
243
- declaresArgs = Array.isArray(args) ? args.length !== 0 : false;
243
+ declaresArgs = Array.isArray(match$1);
244
244
  if (!declaresArgs) {
245
- Stdlib_JsError.throwWithMessage(`Invalid "args" field in the fields.instruction option of the "` + eventName + `" instruction on program "` + contractName + `". The instruction declares no args in config.yaml, so there is nothing to decode. Remove "args" from the selection, or declare the instruction's args.`);
245
+ Stdlib_JsError.throwWithMessage(`Invalid "args" field in the fields.instruction option of the "` + eventName + `" instruction on program "` + contractName + `". The instruction attaches no args layout in config.yaml, so there is nothing to decode. Remove "args" from the selection, or give the instruction an \`args\` layout — \`args: []\` if it takes none.`);
246
246
  }
247
247
  }
248
248
  break;
@@ -492,8 +492,9 @@ function registerOnBlock(name, where, handler, getChainsObject) {
492
492
  }
493
493
  let range = match[1];
494
494
  matchedAny.contents = true;
495
- if (Stdlib_Option.getOr(range._gte, chainConfig.startBlock) < chainConfig.startBlock) {
496
- Stdlib_JsError.throwWithMessage(`The start block for onBlock handler "` + name + `" is less than the chain start block (` + chainConfig.startBlock.toString() + `). This is not supported yet.`);
495
+ let chainStartBlock = chainObj.startBlock;
496
+ if (Stdlib_Option.getOr(range._gte, chainStartBlock) < chainStartBlock) {
497
+ Stdlib_JsError.throwWithMessage(`The start block for onBlock handler "` + name + `" is less than the chain start block (` + chainStartBlock.toString() + `). This is not supported yet.`);
497
498
  }
498
499
  let chainEndBlock = chainConfig.endBlock;
499
500
  if (chainEndBlock !== undefined && Stdlib_Option.getOr(range._lte, chainEndBlock) > chainEndBlock) {
package/src/Internal.res CHANGED
@@ -567,17 +567,33 @@ type svmAccountFilter = {
567
567
  /** AND-group: every entry must match the same instruction. */
568
568
  type svmAccountFilterGroup = array<svmAccountFilter>
569
569
 
570
+ /** One positional account slot of an instruction. An `Optional` slot is absent
571
+ from the payload when the call carries no such slot, or fills it with the id of
572
+ the program being invoked. `Unnamed` holds a position and surfaces nothing. */
573
+ type svmAccountSlot =
574
+ | Unnamed
575
+ | Required(string)
576
+ | Optional(string)
577
+
578
+ let svmAccountSlotName = slot =>
579
+ switch slot {
580
+ | Unnamed => None
581
+ | Required(name) | Optional(name) => Some(name)
582
+ }
583
+
570
584
  type svmInstructionEventConfig = {
571
585
  ...eventConfig,
572
586
  /** Base58 Solana program id this instruction belongs to. */
573
587
  programId: SvmTypes.Pubkey.t,
574
588
  /** Hex-encoded discriminator. `None` matches every instruction in the program. */
575
589
  discriminator: option<string>,
576
- /** Positional account names from the Borsh schema, in declared order.
577
- `[]` means no schema is attached for this instruction. */
578
- accounts: array<string>,
590
+ /** Positional account slots in declared order. `[]` means no schema is
591
+ attached for this instruction. */
592
+ accounts: array<svmAccountSlot>,
579
593
  /** Borsh args layout as `Vec<ArgDef>` JSON (see `human_config::svm::ArgDef`
580
- on the Rust side). `JSON.Null` means no schema is attached. */
594
+ on the Rust side). `JSON.Null` attaches no decoder, so every matched call is
595
+ delivered with its payload raw. An array attaches one, `[]` included: a call
596
+ whose data the layout rejects is skipped. */
581
597
  args: JSON.t,
582
598
  /** Program-level nominal-type registry (`BTreeMap<String, ArgType>` JSON).
583
599
  Duplicated on every event of the same program — the runtime dedups by
@@ -174,6 +174,14 @@ function dependsOnAddresses(isWildcard, filterByAddresses) {
174
174
  }
175
175
  }
176
176
 
177
+ function svmAccountSlotName(slot) {
178
+ if (typeof slot !== "object") {
179
+ return;
180
+ } else {
181
+ return slot._0;
182
+ }
183
+ }
184
+
177
185
  function getItemChainId(item) {
178
186
  if (item.kind === 0) {
179
187
  return item.chainId;
@@ -334,6 +342,7 @@ export {
334
342
  unionFields,
335
343
  unionFieldSelection,
336
344
  dependsOnAddresses,
345
+ svmAccountSlotName,
337
346
  getItemChainId,
338
347
  fuelSupplyParamsSchema,
339
348
  fuelTransferParamsSchema,