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.
- package/evm.schema.json +21 -4
- package/fuel.schema.json +21 -4
- package/index.d.ts +1 -1
- package/package.json +6 -6
- package/src/ChainState.res +9 -73
- package/src/ChainState.res.mjs +6 -58
- package/src/Config.res +73 -27
- package/src/Config.res.mjs +71 -21
- package/src/Core.res +0 -15
- package/src/Core.res.mjs +0 -11
- package/src/EventConfigBuilder.res +14 -10
- package/src/EventConfigBuilder.res.mjs +6 -4
- package/src/EventProcessing.res +6 -6
- package/src/EventProcessing.res.mjs +6 -8
- package/src/HandlerLoader.res +8 -20
- package/src/HandlerLoader.res.mjs +2 -11
- package/src/HandlerRegister.res +12 -11
- package/src/HandlerRegister.res.mjs +6 -5
- package/src/Internal.res +20 -4
- package/src/Internal.res.mjs +9 -0
- package/src/Main.res +8 -1
- package/src/Main.res.mjs +3 -3
- package/src/Persistence.res +11 -1
- package/src/Persistence.res.mjs +6 -2
- package/src/PgStorage.res +1 -1
- package/src/PgStorage.res.mjs +1 -1
- package/src/SimulateItems.res +13 -6
- package/src/SimulateItems.res.mjs +7 -6
- package/src/TestIndexer.res +6 -5
- package/src/TestIndexer.res.mjs +5 -4
- package/src/UserContext.res +51 -358
- package/src/UserContext.res.mjs +35 -271
- package/src/db/InternalTable.res +1 -1
- package/src/db/InternalTable.res.mjs +2 -1
- package/src/sources/ChainSources.res +72 -0
- package/src/sources/ChainSources.res.mjs +55 -0
- package/src/sources/EvmHyperSyncSource.res +10 -22
- package/src/sources/EvmHyperSyncSource.res.mjs +9 -41
- package/src/sources/FuelHyperSyncSource.res +10 -18
- package/src/sources/FuelHyperSyncSource.res.mjs +8 -38
- package/src/sources/HyperSync.res +31 -0
- package/src/sources/HyperSync.res.mjs +31 -0
- package/src/sources/HyperSync.resi +16 -0
- package/src/sources/StartBlockResolver.res +173 -0
- package/src/sources/StartBlockResolver.res.mjs +134 -0
- package/src/sources/Svm.res +0 -51
- package/src/sources/Svm.res.mjs +0 -46
- package/src/sources/SvmHyperSyncSource.res +20 -9
- package/src/sources/SvmHyperSyncSource.res.mjs +34 -12
- package/svm.schema.json +78 -63
- package/src/subgraph/blocks.ts +0 -176
- package/src/subgraph/calls.ts +0 -217
- package/src/subgraph/conformance.ts +0 -102
- package/src/subgraph/division.ts +0 -133
- package/src/subgraph/errors.ts +0 -90
- package/src/subgraph/graph-ts-types/VERSION +0 -2
- package/src/subgraph/graph-ts-types/chain/arweave.d.ts +0 -70
- package/src/subgraph/graph-ts-types/chain/cosmos.d.ts +0 -327
- package/src/subgraph/graph-ts-types/chain/ethereum.d.ts +0 -233
- package/src/subgraph/graph-ts-types/chain/near.d.ts +0 -253
- package/src/subgraph/graph-ts-types/chain/starknet.d.ts +0 -32
- package/src/subgraph/graph-ts-types/common/collections.d.ts +0 -136
- package/src/subgraph/graph-ts-types/common/conversion.d.ts +0 -11
- package/src/subgraph/graph-ts-types/common/datasource.d.ts +0 -30
- package/src/subgraph/graph-ts-types/common/eager-offset.d.ts +0 -0
- package/src/subgraph/graph-ts-types/common/json.d.ts +0 -17
- package/src/subgraph/graph-ts-types/common/numbers.d.ts +0 -120
- package/src/subgraph/graph-ts-types/common/value.d.ts +0 -120
- package/src/subgraph/graph-ts-types/common/yaml.d.ts +0 -90
- package/src/subgraph/graph-ts-types/global/global.d.ts +0 -194
- package/src/subgraph/graph-ts-types/helper-functions.d.ts +0 -22
- package/src/subgraph/graph-ts-types/index.d.ts +0 -102
- package/src/subgraph/graph-ts.ts +0 -1948
- package/src/subgraph/hosts.ts +0 -148
- package/src/subgraph/runtime.ts +0 -863
- package/src/subgraph/scope.ts +0 -66
package/src/Config.res.mjs
CHANGED
|
@@ -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(
|
|
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(
|
|
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).
|
|
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
|
-
|
|
649
|
-
|
|
650
|
-
|
|
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<
|
|
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
|
-
~
|
|
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
|
|
730
|
-
|
|
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`
|
|
736
|
+
"The instruction has no named accounts to filter on. Add `accounts` to it in config.yaml, or attach an IDL.",
|
|
733
737
|
)
|
|
734
|
-
|
|
|
738
|
+
| None =>
|
|
735
739
|
invalid(
|
|
736
740
|
`The instruction has no account named "${name}" to filter on. Named accounts: ${Utils.Array.quotedJoin(
|
|
737
|
-
|
|
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
|
-
~
|
|
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,
|
|
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 =
|
|
483
|
-
let position$1 = position !==
|
|
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(
|
|
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)) {
|
package/src/EventProcessing.res
CHANGED
|
@@ -51,7 +51,7 @@ let runEventHandlerOrThrow = async (
|
|
|
51
51
|
isPreload: false,
|
|
52
52
|
chains,
|
|
53
53
|
config,
|
|
54
|
-
|
|
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.
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
91
|
+
isResolved: false
|
|
94
92
|
};
|
|
95
93
|
await item.onBlockRegistration.handler(Ecosystem.makeOnBlockArgs(item.blockNumber, config.ecosystem, UserContext.getHandlerContext(contextParams)));
|
|
96
|
-
|
|
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
|
-
|
|
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
|
-
|
|
154
|
+
isResolved: false
|
|
157
155
|
})))));
|
|
158
156
|
} catch (exn$1) {
|
|
159
157
|
|
package/src/HandlerLoader.res
CHANGED
|
@@ -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
|
-
|
|
90
|
-
|
|
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
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
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
|
-
|
|
65
|
-
|
|
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 */
|
package/src/HandlerRegister.res
CHANGED
|
@@ -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(
|
|
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
|
|
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
|
-
|
|
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 (${
|
|
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
|
|
241
|
+
let match$1 = eventConfig.args;
|
|
242
242
|
let declaresArgs;
|
|
243
|
-
declaresArgs = Array.isArray(
|
|
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
|
|
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
|
-
|
|
496
|
-
|
|
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
|
|
577
|
-
|
|
578
|
-
accounts: array<
|
|
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`
|
|
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
|
package/src/Internal.res.mjs
CHANGED
|
@@ -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,
|