envio 3.0.2-svm-alpha.0 → 3.0.2
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 +8 -8
- package/fuel.schema.json +12 -12
- package/index.d.ts +1 -155
- package/package.json +7 -6
- package/src/ChainFetcher.res +1 -25
- package/src/ChainFetcher.res.mjs +1 -19
- package/src/Config.res +94 -156
- package/src/Config.res.mjs +97 -60
- package/src/Core.res +0 -32
- package/src/Env.res.mjs +2 -1
- package/src/Envio.res +0 -94
- package/src/EventConfigBuilder.res +25 -63
- package/src/EventConfigBuilder.res.mjs +8 -37
- package/src/HandlerLoader.res +1 -12
- package/src/HandlerLoader.res.mjs +1 -6
- package/src/Internal.res +0 -38
- package/src/Main.res +3 -53
- package/src/Main.res.mjs +2 -34
- package/src/Persistence.res +17 -2
- package/src/Persistence.res.mjs +14 -2
- package/src/SimulateItems.res +10 -23
- package/src/SimulateItems.res.mjs +6 -21
- package/src/bindings/ClickHouse.res +6 -2
- package/src/bindings/ClickHouse.res.mjs +3 -2
- package/src/sources/EventRouter.res +0 -65
- package/src/sources/EventRouter.res.mjs +0 -43
- package/src/sources/HyperSyncClient.res +157 -30
- package/src/sources/HyperSyncClient.res.mjs +6 -20
- package/src/sources/HyperSyncSource.res +8 -5
- package/src/sources/HyperSyncSource.res.mjs +8 -1
- package/src/sources/RpcSource.res.mjs +1 -1
- package/src/sources/Svm.res +2 -2
- package/src/sources/Svm.res.mjs +2 -3
- package/src/tui/Tui.res +2 -9
- package/src/tui/Tui.res.mjs +4 -19
- package/src/tui/components/TuiData.res +0 -3
- package/svm.schema.json +4 -345
- package/src/SvmTypes.res +0 -9
- package/src/SvmTypes.res.mjs +0 -14
- package/src/sources/HyperSyncSolanaClient.res +0 -227
- package/src/sources/HyperSyncSolanaClient.res.mjs +0 -25
- package/src/sources/HyperSyncSolanaSource.res +0 -515
- package/src/sources/HyperSyncSolanaSource.res.mjs +0 -441
package/src/Core.res
CHANGED
|
@@ -4,41 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
// NAPI encodes Rust `Option<T>` as `null | T` (never `undefined`), so the
|
|
6
6
|
// tighter `Null.t` captures the exact boundary shape.
|
|
7
|
-
//
|
|
8
|
-
// Opaque carriers for the NAPI class constructors. Static factories
|
|
9
|
-
// (`newWithAgent`, `fromConfig`, `fromSignatures`) hang off these via `@send`
|
|
10
|
-
// in `HyperSyncClient.res` / `HyperSyncSolanaClient.res`.
|
|
11
|
-
type hypersyncClientCtor
|
|
12
|
-
type hypersyncSolanaClientCtor
|
|
13
|
-
type decoderCtor
|
|
14
|
-
|
|
15
|
-
/// JS shape of one decoded instruction. Mirrors `DecodedInstructionJson` in
|
|
16
|
-
/// `packages/cli/src/hypersync_source_svm/decoder.rs`. The `argsJson` /
|
|
17
|
-
/// `accountsJson` fields are stringified to side-step napi-rs's lack of
|
|
18
|
-
/// native `serde_json::Value` passthrough; callers `JSON.parse` once.
|
|
19
|
-
type svmDecodedInstruction = {
|
|
20
|
-
name: string,
|
|
21
|
-
argsJson: string,
|
|
22
|
-
accountsJson: string,
|
|
23
|
-
extraAccounts: array<string>,
|
|
24
|
-
}
|
|
25
|
-
|
|
26
7
|
type addon = {
|
|
27
8
|
getConfigJson: (~configPath: Null.t<string>, ~directory: Null.t<string>) => string,
|
|
28
9
|
runCli: (~args: array<string>, ~envioPackageDir: Null.t<string>) => promise<Null.t<string>>,
|
|
29
|
-
@as("HypersyncClient")
|
|
30
|
-
hypersyncClient: hypersyncClientCtor,
|
|
31
|
-
@as("HypersyncSolanaClient")
|
|
32
|
-
hypersyncSolanaClient: hypersyncSolanaClientCtor,
|
|
33
|
-
@as("Decoder")
|
|
34
|
-
decoder: decoderCtor,
|
|
35
|
-
setLogLevel: string => unit,
|
|
36
|
-
registerProgramSchema: (~descriptorJson: string) => int,
|
|
37
|
-
decodeInstruction: (
|
|
38
|
-
~schemaHandle: int,
|
|
39
|
-
~dataHex: string,
|
|
40
|
-
~accounts: array<string>,
|
|
41
|
-
) => Null.t<svmDecodedInstruction>,
|
|
42
10
|
}
|
|
43
11
|
|
|
44
12
|
@module("node:module") external createRequire: string => {..} = "createRequire"
|
package/src/Env.res.mjs
CHANGED
|
@@ -7,6 +7,7 @@ import * as Belt_Option from "@rescript/runtime/lib/es6/Belt_Option.js";
|
|
|
7
7
|
import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
|
|
8
8
|
import * as HyperSyncClient from "./sources/HyperSyncClient.res.mjs";
|
|
9
9
|
import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
|
|
10
|
+
import * as HypersyncClient from "@envio-dev/hypersync-client";
|
|
10
11
|
|
|
11
12
|
import 'dotenv/config'
|
|
12
13
|
;
|
|
@@ -61,7 +62,7 @@ let hypersyncClientEnableQueryCaching = EnvSafe.get(envSafe, "ENVIO_HYPERSYNC_CL
|
|
|
61
62
|
|
|
62
63
|
let hypersyncLogLevel = EnvSafe.get(envSafe, "ENVIO_HYPERSYNC_LOG_LEVEL", HyperSyncClient.logLevelSchema, undefined, "info", undefined, undefined);
|
|
63
64
|
|
|
64
|
-
|
|
65
|
+
HypersyncClient.setLogLevel(hypersyncLogLevel);
|
|
65
66
|
|
|
66
67
|
let logStrategy = EnvSafe.get(envSafe, "LOG_STRATEGY", S$RescriptSchema.$$enum([
|
|
67
68
|
"ecs-file",
|
package/src/Envio.res
CHANGED
|
@@ -20,100 +20,6 @@ type svmOnSlotArgs<'context> = {
|
|
|
20
20
|
context: 'context,
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
/** Borsh-decoded instruction view. Present whenever a `ProgramSchema` was
|
|
24
|
-
attached to the program (bundled schema, Anchor IDL, or hand-written YAML
|
|
25
|
-
`accounts`/`args`). Absent (`None`) when no schema applied or the
|
|
26
|
-
discriminator didn't match any registered instruction. */
|
|
27
|
-
type svmDecodedInstruction = {
|
|
28
|
-
/** Schema-declared instruction name (matches the codegen module suffix). */
|
|
29
|
-
name: string,
|
|
30
|
-
/** Borsh-decoded args. `JSON.Object({})` for no-arg instructions
|
|
31
|
-
(e.g. `VerifyCollection`). POC types this as raw `JSON.t`; cast at the
|
|
32
|
-
handler with `(json :> MyArgsType)` until typed codegen lands. */
|
|
33
|
-
args: JSON.t,
|
|
34
|
-
/** Named accounts in schema order. Keys are exactly the schema-declared
|
|
35
|
-
names; values are base58 pubkey strings. */
|
|
36
|
-
accounts: dict<string>,
|
|
37
|
-
/** Accounts beyond the schema's named list (Anchor `remaining_accounts`,
|
|
38
|
-
IDL drift). `[]` when counts match. */
|
|
39
|
-
extraAccounts: array<string>,
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
type svmInstruction = {
|
|
43
|
-
programId: SvmTypes.Pubkey.t,
|
|
44
|
-
/** Raw instruction bytes as `0x`-prefixed hex. */
|
|
45
|
-
data: string,
|
|
46
|
-
accounts: array<SvmTypes.Pubkey.t>,
|
|
47
|
-
/** Path through the call tree: `[outerIndex]` for top-level instructions,
|
|
48
|
-
appended child indices for inner CPI calls. */
|
|
49
|
-
instructionAddress: array<int>,
|
|
50
|
-
isInner: bool,
|
|
51
|
-
/** Discriminator prefixes pre-extracted by HyperSync. Each is `Some` only
|
|
52
|
-
when the underlying instruction is at least that long. */
|
|
53
|
-
d1?: string,
|
|
54
|
-
d2?: string,
|
|
55
|
-
d4?: string,
|
|
56
|
-
d8?: string,
|
|
57
|
-
/** Borsh-decoded view. See [[svmDecodedInstruction]]. */
|
|
58
|
-
decoded?: svmDecodedInstruction,
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
type svmTransaction = {
|
|
62
|
-
signatures: array<string>,
|
|
63
|
-
feePayer?: SvmTypes.Pubkey.t,
|
|
64
|
-
success?: bool,
|
|
65
|
-
err?: string,
|
|
66
|
-
fee?: bigint,
|
|
67
|
-
computeUnitsConsumed?: bigint,
|
|
68
|
-
accountKeys: array<SvmTypes.Pubkey.t>,
|
|
69
|
-
recentBlockhash?: string,
|
|
70
|
-
version?: string,
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
type svmLog = {
|
|
74
|
-
kind: string,
|
|
75
|
-
message: string,
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/** Inner block record on `svmInstructionEvent`. Field names follow EVM/Fuel
|
|
79
|
-
(`height`, `time`, `hash`) so the shared `Ecosystem.t` getters in
|
|
80
|
-
`Svm.res` work uniformly across ecosystems — `height` carries the slot. */
|
|
81
|
-
type svmInstructionEventBlock = {
|
|
82
|
-
/** Slot number. Named `height` so the shared ecosystem getter reads it. */
|
|
83
|
-
height: int,
|
|
84
|
-
/** Unix block time (seconds). `0` when HyperSync didn't return a block
|
|
85
|
-
for this instruction's slot. */
|
|
86
|
-
time: int,
|
|
87
|
-
/** Block hash. Currently always empty — populated by the future
|
|
88
|
-
reorg-guard `queryBlockHash(slot)` route. */
|
|
89
|
-
hash: string,
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/** The per-instruction payload handlers receive on `.event`. Mirrors the
|
|
93
|
-
EVM `type event` shape inside generated per-event modules. */
|
|
94
|
-
type svmInstructionEvent = {
|
|
95
|
-
contractName: string,
|
|
96
|
-
eventName: string,
|
|
97
|
-
instruction: svmInstruction,
|
|
98
|
-
/** Parent transaction. `None` when the per-instruction
|
|
99
|
-
`include_transaction` flag is `false`. */
|
|
100
|
-
transaction: option<svmTransaction>,
|
|
101
|
-
/** Program log entries scoped to this instruction. `None` when the
|
|
102
|
-
per-instruction `include_logs` flag is `false`. */
|
|
103
|
-
logs: option<array<svmLog>>,
|
|
104
|
-
/** Convenience alias for `block.height`. */
|
|
105
|
-
slot: int,
|
|
106
|
-
/** Convenience alias for `block.time`. */
|
|
107
|
-
blockTime: option<int>,
|
|
108
|
-
block: svmInstructionEventBlock,
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/** Arguments passed to handlers registered via `indexer.onInstruction`. */
|
|
112
|
-
type svmOnInstructionArgs<'context> = {
|
|
113
|
-
event: svmInstructionEvent,
|
|
114
|
-
context: 'context,
|
|
115
|
-
}
|
|
116
|
-
|
|
117
23
|
// Internal-only type for the `indexer.onBlock` (and SVM `onSlot`) `where`
|
|
118
24
|
// callback argument. The canonical TypeScript shape lives in
|
|
119
25
|
// `packages/envio/index.d.ts`; the ReScript declaration here is free to
|
|
@@ -142,25 +142,28 @@ let rec abiTypeToDefaultValue = (abiType: string): unknown => {
|
|
|
142
142
|
|
|
143
143
|
// ============== Named-tuple (struct) schema helpers ==============
|
|
144
144
|
|
|
145
|
-
// Build
|
|
146
|
-
// (or nested field) has components,
|
|
147
|
-
// rather than a positional tuple. Walks through array wrappers so
|
|
148
|
-
// still produces `array<{...}>`.
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
145
|
+
// Build an object schema that honours component names: whenever an event param
|
|
146
|
+
// (or nested field) has components, decode/serialize it as an object with
|
|
147
|
+
// named fields rather than a positional tuple. Walks through array wrappers so
|
|
148
|
+
// `struct[]` still produces `array<{...}>`. `~leafSchema` picks the per-ABI
|
|
149
|
+
// schema for non-tuple leaves (raw-event vs simulate variants differ in how
|
|
150
|
+
// they accept primitives — string-encoded numbers vs native bigints).
|
|
151
|
+
let rec componentsToObjectSchema = (
|
|
152
|
+
~leafSchema: string => S.t<unknown>,
|
|
153
|
+
abiType: string,
|
|
154
|
+
components: array<eventParamComponent>,
|
|
155
|
+
): S.t<unknown> => {
|
|
152
156
|
if abiType->String.endsWith("]") {
|
|
153
157
|
let bracketIdx = abiType->String.lastIndexOf("[")
|
|
154
158
|
let baseType = abiType->String.slice(~start=0, ~end=bracketIdx)
|
|
155
|
-
S.array(
|
|
159
|
+
S.array(componentsToObjectSchema(~leafSchema, baseType, components))->S.toUnknown
|
|
156
160
|
} else {
|
|
157
|
-
// Must be a tuple at this level: build a record keyed by component names.
|
|
158
161
|
S.object(s => {
|
|
159
162
|
let dict = Dict.make()
|
|
160
163
|
components->Array.forEach(c => {
|
|
161
164
|
let childSchema = switch c.components {
|
|
162
|
-
| Some(sub) =>
|
|
163
|
-
| None =>
|
|
165
|
+
| Some(sub) => componentsToObjectSchema(~leafSchema, c.abiType, sub)
|
|
166
|
+
| None => leafSchema(c.abiType)
|
|
164
167
|
}
|
|
165
168
|
dict->Dict.set(c.name, s.field(c.name, childSchema))
|
|
166
169
|
})
|
|
@@ -233,7 +236,16 @@ let buildParamsSchema = (params: array<eventParam>): S.t<Internal.eventParams> =
|
|
|
233
236
|
S.object(s => {
|
|
234
237
|
let dict = Dict.make()
|
|
235
238
|
params->Array.forEach(p => {
|
|
236
|
-
|
|
239
|
+
// Indexed structs arrive as keccak256 topic hashes (single hex
|
|
240
|
+
// strings), so they keep the positional/leaf path; only non-indexed
|
|
241
|
+
// tuple params get the named-object shape that the HyperSync decoder
|
|
242
|
+
// (componentsToRemapper) produces.
|
|
243
|
+
let paramSchema = switch p.components {
|
|
244
|
+
| Some(components) if !p.indexed =>
|
|
245
|
+
componentsToObjectSchema(~leafSchema=abiTypeToSchema, p.abiType, components)
|
|
246
|
+
| _ => abiTypeToSchema(p.abiType)
|
|
247
|
+
}
|
|
248
|
+
dict->Dict.set(p.name, s.field(p.name, paramSchema))
|
|
237
249
|
})
|
|
238
250
|
dict
|
|
239
251
|
})->(Utils.magic: S.t<dict<unknown>> => S.t<Internal.eventParams>)
|
|
@@ -255,7 +267,7 @@ let buildSimulateParamsSchema = (params: array<eventParam>): S.t<Internal.eventP
|
|
|
255
267
|
params->Array.forEach(p => {
|
|
256
268
|
let (paramSchema, paramDefault) = switch p.components {
|
|
257
269
|
| Some(components) => (
|
|
258
|
-
|
|
270
|
+
componentsToObjectSchema(~leafSchema=abiTypeToSimulateSchema, p.abiType, components),
|
|
259
271
|
componentsToDefaultValue(p.abiType, components),
|
|
260
272
|
)
|
|
261
273
|
| None => (abiTypeToSimulateSchema(p.abiType), abiTypeToDefaultValue(p.abiType))
|
|
@@ -484,56 +496,6 @@ let buildEvmEventConfig = (
|
|
|
484
496
|
|
|
485
497
|
// ============== Build Fuel event config ==============
|
|
486
498
|
|
|
487
|
-
let buildSvmInstructionEventConfig = (
|
|
488
|
-
~contractName: string,
|
|
489
|
-
~instructionName: string,
|
|
490
|
-
~programId: SvmTypes.Pubkey.t,
|
|
491
|
-
~discriminator: option<string>,
|
|
492
|
-
~discriminatorByteLen: int,
|
|
493
|
-
~includeTransaction: bool,
|
|
494
|
-
~includeLogs: bool,
|
|
495
|
-
~accountFilters: array<Internal.svmAccountFilter>,
|
|
496
|
-
~isInner: option<bool>,
|
|
497
|
-
~isWildcard: bool,
|
|
498
|
-
~handler: option<Internal.handler>,
|
|
499
|
-
~contractRegister: option<Internal.contractRegister>,
|
|
500
|
-
~accounts: array<string>=[],
|
|
501
|
-
~args: JSON.t=JSON.Null,
|
|
502
|
-
~definedTypes: JSON.t=JSON.Null,
|
|
503
|
-
~startBlock: option<int>=?,
|
|
504
|
-
): Internal.svmInstructionEventConfig => {
|
|
505
|
-
let paramsSchema =
|
|
506
|
-
S.json(~validate=false)
|
|
507
|
-
->Utils.Schema.coerceToJsonPgType
|
|
508
|
-
->(Utils.magic: S.t<JSON.t> => S.t<Internal.eventParams>)
|
|
509
|
-
{
|
|
510
|
-
id: switch discriminator {
|
|
511
|
-
| Some(d) => d
|
|
512
|
-
| None => "none"
|
|
513
|
-
},
|
|
514
|
-
name: instructionName,
|
|
515
|
-
contractName,
|
|
516
|
-
isWildcard,
|
|
517
|
-
handler,
|
|
518
|
-
contractRegister,
|
|
519
|
-
paramsRawEventSchema: paramsSchema,
|
|
520
|
-
simulateParamsSchema: paramsSchema,
|
|
521
|
-
filterByAddresses: false,
|
|
522
|
-
dependsOnAddresses: !isWildcard,
|
|
523
|
-
startBlock,
|
|
524
|
-
programId,
|
|
525
|
-
discriminator,
|
|
526
|
-
discriminatorByteLen,
|
|
527
|
-
includeTransaction,
|
|
528
|
-
includeLogs,
|
|
529
|
-
accountFilters,
|
|
530
|
-
isInner,
|
|
531
|
-
accounts,
|
|
532
|
-
args,
|
|
533
|
-
definedTypes,
|
|
534
|
-
}
|
|
535
|
-
}
|
|
536
|
-
|
|
537
499
|
let buildFuelEventConfig = (
|
|
538
500
|
~contractName: string,
|
|
539
501
|
~eventName: string,
|
|
@@ -144,13 +144,13 @@ function abiTypeToDefaultValue(abiType) {
|
|
|
144
144
|
}
|
|
145
145
|
}
|
|
146
146
|
|
|
147
|
-
function
|
|
147
|
+
function componentsToObjectSchema(leafSchema, abiType, components) {
|
|
148
148
|
if (!abiType.endsWith("]")) {
|
|
149
149
|
return S$RescriptSchema.object(s => {
|
|
150
150
|
let dict = {};
|
|
151
151
|
components.forEach(c => {
|
|
152
152
|
let sub = c.components;
|
|
153
|
-
let childSchema = sub !== undefined ?
|
|
153
|
+
let childSchema = sub !== undefined ? componentsToObjectSchema(leafSchema, c.abiType, sub) : leafSchema(c.abiType);
|
|
154
154
|
dict[c.name] = s.f(c.name, childSchema);
|
|
155
155
|
});
|
|
156
156
|
return dict;
|
|
@@ -158,7 +158,7 @@ function componentsToSimulateSchema(abiType, components) {
|
|
|
158
158
|
}
|
|
159
159
|
let bracketIdx = abiType.lastIndexOf("[");
|
|
160
160
|
let baseType = abiType.slice(0, bracketIdx);
|
|
161
|
-
return S$RescriptSchema.array(
|
|
161
|
+
return S$RescriptSchema.array(componentsToObjectSchema(leafSchema, baseType, components));
|
|
162
162
|
}
|
|
163
163
|
|
|
164
164
|
function componentsToDefaultValue(abiType, components) {
|
|
@@ -197,7 +197,9 @@ function buildParamsSchema(params) {
|
|
|
197
197
|
return S$RescriptSchema.object(s => {
|
|
198
198
|
let dict = {};
|
|
199
199
|
params.forEach(p => {
|
|
200
|
-
|
|
200
|
+
let components = p.components;
|
|
201
|
+
let paramSchema = components !== undefined && !p.indexed ? componentsToObjectSchema(abiTypeToSchema, p.abiType, components) : abiTypeToSchema(p.abiType);
|
|
202
|
+
dict[p.name] = s.f(p.name, paramSchema);
|
|
201
203
|
});
|
|
202
204
|
return dict;
|
|
203
205
|
});
|
|
@@ -213,7 +215,7 @@ function buildSimulateParamsSchema(params) {
|
|
|
213
215
|
params.forEach(p => {
|
|
214
216
|
let components = p.components;
|
|
215
217
|
let match = components !== undefined ? [
|
|
216
|
-
|
|
218
|
+
componentsToObjectSchema(abiTypeToSimulateSchema, p.abiType, components),
|
|
217
219
|
componentsToDefaultValue(p.abiType, components)
|
|
218
220
|
] : [
|
|
219
221
|
abiTypeToSimulateSchema(p.abiType),
|
|
@@ -350,36 +352,6 @@ function buildEvmEventConfig(contractName, eventName, sighash, params, isWildcar
|
|
|
350
352
|
};
|
|
351
353
|
}
|
|
352
354
|
|
|
353
|
-
function buildSvmInstructionEventConfig(contractName, instructionName, programId, discriminator, discriminatorByteLen, includeTransaction, includeLogs, accountFilters, isInner, isWildcard, handler, contractRegister, accountsOpt, argsOpt, definedTypesOpt, startBlock) {
|
|
354
|
-
let accounts = accountsOpt !== undefined ? accountsOpt : [];
|
|
355
|
-
let args = argsOpt !== undefined ? argsOpt : null;
|
|
356
|
-
let definedTypes = definedTypesOpt !== undefined ? definedTypesOpt : null;
|
|
357
|
-
let paramsSchema = Utils.Schema.coerceToJsonPgType(S$RescriptSchema.json(false));
|
|
358
|
-
return {
|
|
359
|
-
id: discriminator !== undefined ? discriminator : "none",
|
|
360
|
-
name: instructionName,
|
|
361
|
-
contractName: contractName,
|
|
362
|
-
isWildcard: isWildcard,
|
|
363
|
-
filterByAddresses: false,
|
|
364
|
-
dependsOnAddresses: !isWildcard,
|
|
365
|
-
handler: handler,
|
|
366
|
-
contractRegister: contractRegister,
|
|
367
|
-
paramsRawEventSchema: paramsSchema,
|
|
368
|
-
simulateParamsSchema: paramsSchema,
|
|
369
|
-
startBlock: startBlock,
|
|
370
|
-
programId: programId,
|
|
371
|
-
discriminator: discriminator,
|
|
372
|
-
discriminatorByteLen: discriminatorByteLen,
|
|
373
|
-
includeTransaction: includeTransaction,
|
|
374
|
-
includeLogs: includeLogs,
|
|
375
|
-
accountFilters: accountFilters,
|
|
376
|
-
isInner: isInner,
|
|
377
|
-
accounts: accounts,
|
|
378
|
-
args: args,
|
|
379
|
-
definedTypes: definedTypes
|
|
380
|
-
};
|
|
381
|
-
}
|
|
382
|
-
|
|
383
355
|
function buildFuelEventConfig(contractName, eventName, kind, sighash, rawAbi, isWildcard, handler, contractRegister, startBlock) {
|
|
384
356
|
let fuelKind;
|
|
385
357
|
switch (kind) {
|
|
@@ -447,7 +419,7 @@ export {
|
|
|
447
419
|
abiTypeToSchema,
|
|
448
420
|
abiTypeToSimulateSchema,
|
|
449
421
|
abiTypeToDefaultValue,
|
|
450
|
-
|
|
422
|
+
componentsToObjectSchema,
|
|
451
423
|
componentsToDefaultValue,
|
|
452
424
|
componentsToRemapper,
|
|
453
425
|
buildParamsSchema,
|
|
@@ -458,7 +430,6 @@ export {
|
|
|
458
430
|
alwaysIncludedBlockFields,
|
|
459
431
|
resolveFieldSelection,
|
|
460
432
|
buildEvmEventConfig,
|
|
461
|
-
buildSvmInstructionEventConfig,
|
|
462
433
|
buildFuelEventConfig,
|
|
463
434
|
}
|
|
464
435
|
/* eventParamComponentSchema Not a pure module */
|
package/src/HandlerLoader.res
CHANGED
|
@@ -142,18 +142,7 @@ let applyRegistrations = (~config: Config.t): Config.t => {
|
|
|
142
142
|
dependsOnAddresses: Internal.dependsOnAddresses(~isWildcard, ~filterByAddresses),
|
|
143
143
|
} :> Internal.eventConfig)
|
|
144
144
|
| Svm =>
|
|
145
|
-
|
|
146
|
-
ev->(Utils.magic: Internal.eventConfig => Internal.svmInstructionEventConfig)
|
|
147
|
-
({
|
|
148
|
-
...svmEv,
|
|
149
|
-
isWildcard,
|
|
150
|
-
handler,
|
|
151
|
-
contractRegister,
|
|
152
|
-
dependsOnAddresses: Internal.dependsOnAddresses(
|
|
153
|
-
~isWildcard,
|
|
154
|
-
~filterByAddresses=false,
|
|
155
|
-
),
|
|
156
|
-
} :> Internal.eventConfig)
|
|
145
|
+
JsError.throwWithMessage(`SVM does not support indexer.onEvent or indexer.contractRegister. Use indexer.onSlot for per-slot handlers.`)
|
|
157
146
|
}
|
|
158
147
|
},
|
|
159
148
|
)
|
|
@@ -109,12 +109,7 @@ function applyRegistrations(config) {
|
|
|
109
109
|
kind: ev.kind
|
|
110
110
|
};
|
|
111
111
|
case "svm" :
|
|
112
|
-
|
|
113
|
-
newrecord.contractRegister = contractRegister;
|
|
114
|
-
newrecord.handler = handler;
|
|
115
|
-
newrecord.dependsOnAddresses = Internal.dependsOnAddresses(isWildcard, false);
|
|
116
|
-
newrecord.isWildcard = isWildcard;
|
|
117
|
-
return newrecord;
|
|
112
|
+
return Stdlib_JsError.throwWithMessage(`SVM does not support indexer.onEvent or indexer.contractRegister. Use indexer.onSlot for per-slot handlers.`);
|
|
118
113
|
}
|
|
119
114
|
});
|
|
120
115
|
return {
|
package/src/Internal.res
CHANGED
|
@@ -422,44 +422,6 @@ type evmContractConfig = {
|
|
|
422
422
|
events: array<evmEventConfig>,
|
|
423
423
|
}
|
|
424
424
|
|
|
425
|
-
type svmAccountFilter = {
|
|
426
|
-
position: int,
|
|
427
|
-
values: array<SvmTypes.Pubkey.t>,
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
type svmInstructionEventConfig = {
|
|
431
|
-
...eventConfig,
|
|
432
|
-
/** Base58 Solana program id this instruction belongs to. */
|
|
433
|
-
programId: SvmTypes.Pubkey.t,
|
|
434
|
-
/** Hex-encoded discriminator. `None` matches every instruction in the program. */
|
|
435
|
-
discriminator: option<string>,
|
|
436
|
-
/** Length of the discriminator in bytes (0 / 1 / 2 / 4 / 8). Drives the
|
|
437
|
-
`dN` selector at query time and the dispatch-key precomputation in the
|
|
438
|
-
router. */
|
|
439
|
-
discriminatorByteLen: int,
|
|
440
|
-
includeTransaction: bool,
|
|
441
|
-
includeLogs: bool,
|
|
442
|
-
accountFilters: array<svmAccountFilter>,
|
|
443
|
-
/** `None` matches both outer and inner (CPI-invoked) instructions. */
|
|
444
|
-
isInner: option<bool>,
|
|
445
|
-
/** Positional account names from the Borsh schema, in declared order.
|
|
446
|
-
`[]` means no schema is attached for this instruction. */
|
|
447
|
-
accounts: array<string>,
|
|
448
|
-
/** Borsh args layout as `Vec<ArgDef>` JSON (see `human_config::svm::ArgDef`
|
|
449
|
-
on the Rust side). `JSON.Null` means no schema is attached. */
|
|
450
|
-
args: JSON.t,
|
|
451
|
-
/** Program-level nominal-type registry (`BTreeMap<String, ArgType>` JSON).
|
|
452
|
-
Duplicated on every event of the same program — the runtime dedups by
|
|
453
|
-
`programId` when registering. `JSON.Null` when empty. */
|
|
454
|
-
definedTypes: JSON.t,
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
type svmProgramConfig = {
|
|
458
|
-
name: string,
|
|
459
|
-
programId: SvmTypes.Pubkey.t,
|
|
460
|
-
instructions: array<svmInstructionEventConfig>,
|
|
461
|
-
}
|
|
462
|
-
|
|
463
425
|
type indexingAddress = {
|
|
464
426
|
address: Address.t,
|
|
465
427
|
contractName: string,
|
package/src/Main.res
CHANGED
|
@@ -298,57 +298,6 @@ let getGlobalIndexer = (): 'indexer => {
|
|
|
298
298
|
)
|
|
299
299
|
}
|
|
300
300
|
|
|
301
|
-
// SVM identity: `{program, instruction}` from TS or
|
|
302
|
-
// `{instruction: GADT{contract, _0}}` from ReScript. Same two-format dance
|
|
303
|
-
// as the EVM `parseIdentityConfig`, but reading the SVM-native field names.
|
|
304
|
-
let parseSvmIdentityConfig = (identityConfig: 'a) => {
|
|
305
|
-
let raw =
|
|
306
|
-
identityConfig->(
|
|
307
|
-
Utils.magic: 'a => {
|
|
308
|
-
"program": unknown,
|
|
309
|
-
"instruction": unknown,
|
|
310
|
-
"where": option<JSON.t>,
|
|
311
|
-
}
|
|
312
|
-
)
|
|
313
|
-
let (programName, instructionName) = if typeof(raw["program"]) === #string {
|
|
314
|
-
(
|
|
315
|
-
raw["program"]->(Utils.magic: unknown => string),
|
|
316
|
-
raw["instruction"]->(Utils.magic: unknown => string),
|
|
317
|
-
)
|
|
318
|
-
} else {
|
|
319
|
-
let inst =
|
|
320
|
-
raw["instruction"]->(Utils.magic: unknown => {"contract": string, "_0": string})
|
|
321
|
-
(inst["contract"], inst["_0"])
|
|
322
|
-
}
|
|
323
|
-
let where = raw["where"]
|
|
324
|
-
let eventOptions: option<Internal.eventOptions<_>> = switch where {
|
|
325
|
-
| None => None
|
|
326
|
-
| Some(_) =>
|
|
327
|
-
Some({
|
|
328
|
-
where: ?(where->(Utils.magic: option<JSON.t> => option<_>)),
|
|
329
|
-
})
|
|
330
|
-
}
|
|
331
|
-
(programName, instructionName, eventOptions)
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
// onInstruction: delegates to HandlerRegister.setHandler. The SVM analog of
|
|
335
|
-
// onEvent; the registration store keys on `(contractName, eventName)` which
|
|
336
|
-
// for SVM is `(programName, instructionName)`.
|
|
337
|
-
let onInstructionFn = (identityConfig: 'a, handler: 'b) => {
|
|
338
|
-
HandlerRegister.throwIfFinishedRegistration(~methodName="onInstruction")
|
|
339
|
-
let (programName, instructionName, eventOptions) = parseSvmIdentityConfig(identityConfig)
|
|
340
|
-
HandlerRegister.setHandler(
|
|
341
|
-
~contractName=programName,
|
|
342
|
-
~eventName=instructionName,
|
|
343
|
-
handler->(
|
|
344
|
-
Utils.magic: 'b => Internal.genericHandler<
|
|
345
|
-
Internal.genericHandlerArgs<Internal.event, Internal.handlerContext>,
|
|
346
|
-
>
|
|
347
|
-
),
|
|
348
|
-
~eventOptions,
|
|
349
|
-
)
|
|
350
|
-
}
|
|
351
|
-
|
|
352
301
|
// contractRegister: delegates to HandlerRegister.setContractRegister
|
|
353
302
|
let contractRegisterFn = (identityConfig: 'a, handler: 'b) => {
|
|
354
303
|
HandlerRegister.throwIfFinishedRegistration(~methodName="contractRegister")
|
|
@@ -507,7 +456,7 @@ let getGlobalIndexer = (): 'indexer => {
|
|
|
507
456
|
"contractRegister",
|
|
508
457
|
"onBlock",
|
|
509
458
|
]
|
|
510
|
-
| Svm => ["name", "description", "chainIds", "chains", "
|
|
459
|
+
| Svm => ["name", "description", "chainIds", "chains", "onSlot"]
|
|
511
460
|
}
|
|
512
461
|
keysMemo := Some(keys)
|
|
513
462
|
keys
|
|
@@ -528,7 +477,6 @@ let getGlobalIndexer = (): 'indexer => {
|
|
|
528
477
|
chains->(Utils.magic: {..} => unknown)
|
|
529
478
|
}
|
|
530
479
|
| "onEvent" => onEventFn->Utils.magic
|
|
531
|
-
| "onInstruction" => onInstructionFn->Utils.magic
|
|
532
480
|
| "contractRegister" => contractRegisterFn->Utils.magic
|
|
533
481
|
| "onBlock" | "onSlot" => onBlockFn->Utils.magic
|
|
534
482
|
| _ =>
|
|
@@ -674,6 +622,7 @@ let migrate = async (~reset) => {
|
|
|
674
622
|
~chainConfigs=config.chainMap->ChainMap.values,
|
|
675
623
|
~envioInfo=getEnvioInfo(),
|
|
676
624
|
~resetCommand="envio local db-migrate setup",
|
|
625
|
+
~runCommand=None,
|
|
677
626
|
)
|
|
678
627
|
await persistence.storage.close()
|
|
679
628
|
}
|
|
@@ -720,6 +669,7 @@ let start = async (
|
|
|
720
669
|
~chainConfigs=configWithoutRegistrations.chainMap->ChainMap.values,
|
|
721
670
|
~envioInfo=getEnvioInfo(),
|
|
722
671
|
~resetCommand=isDevelopmentMode ? "envio dev -r" : "envio start -r",
|
|
672
|
+
~runCommand=Some(isDevelopmentMode ? "envio dev" : "envio start"),
|
|
723
673
|
)
|
|
724
674
|
|
|
725
675
|
// `Config.loadWithoutRegistrations` never sees registration state; handler,
|
package/src/Main.res.mjs
CHANGED
|
@@ -249,35 +249,6 @@ function getGlobalIndexer() {
|
|
|
249
249
|
let match = parseIdentityConfig(identityConfig);
|
|
250
250
|
HandlerRegister.setHandler(match[0], match[1], handler, match[2], undefined);
|
|
251
251
|
};
|
|
252
|
-
let parseSvmIdentityConfig = identityConfig => {
|
|
253
|
-
let match;
|
|
254
|
-
if (typeof identityConfig.program === "string") {
|
|
255
|
-
match = [
|
|
256
|
-
identityConfig.program,
|
|
257
|
-
identityConfig.instruction
|
|
258
|
-
];
|
|
259
|
-
} else {
|
|
260
|
-
let inst = identityConfig.instruction;
|
|
261
|
-
match = [
|
|
262
|
-
inst.contract,
|
|
263
|
-
inst._0
|
|
264
|
-
];
|
|
265
|
-
}
|
|
266
|
-
let where = identityConfig.where;
|
|
267
|
-
let eventOptions = where !== undefined ? ({
|
|
268
|
-
where: where
|
|
269
|
-
}) : undefined;
|
|
270
|
-
return [
|
|
271
|
-
match[0],
|
|
272
|
-
match[1],
|
|
273
|
-
eventOptions
|
|
274
|
-
];
|
|
275
|
-
};
|
|
276
|
-
let onInstructionFn = (identityConfig, handler) => {
|
|
277
|
-
HandlerRegister.throwIfFinishedRegistration("onInstruction");
|
|
278
|
-
let match = parseSvmIdentityConfig(identityConfig);
|
|
279
|
-
HandlerRegister.setHandler(match[0], match[1], handler, match[2], undefined);
|
|
280
|
-
};
|
|
281
252
|
let contractRegisterFn = (identityConfig, handler) => {
|
|
282
253
|
HandlerRegister.throwIfFinishedRegistration("contractRegister");
|
|
283
254
|
let match = parseIdentityConfig(identityConfig);
|
|
@@ -369,7 +340,6 @@ function getGlobalIndexer() {
|
|
|
369
340
|
"description",
|
|
370
341
|
"chainIds",
|
|
371
342
|
"chains",
|
|
372
|
-
"onInstruction",
|
|
373
343
|
"onSlot"
|
|
374
344
|
];
|
|
375
345
|
break;
|
|
@@ -402,8 +372,6 @@ function getGlobalIndexer() {
|
|
|
402
372
|
return Config.loadWithoutRegistrations().name;
|
|
403
373
|
case "onEvent" :
|
|
404
374
|
return onEventFn;
|
|
405
|
-
case "onInstruction" :
|
|
406
|
-
return onInstructionFn;
|
|
407
375
|
case "onBlock" :
|
|
408
376
|
case "onSlot" :
|
|
409
377
|
return onBlockFn;
|
|
@@ -504,7 +472,7 @@ function getEnvioInfo() {
|
|
|
504
472
|
async function migrate(reset) {
|
|
505
473
|
let config = Config.loadWithoutRegistrations();
|
|
506
474
|
let persistence = PgStorage.makePersistenceFromConfig(config, undefined);
|
|
507
|
-
await Persistence.init(persistence, ChainMap.values(config.chainMap), Config.stripSensitiveData(Config.getPublicConfigJson()), "envio local db-migrate setup", reset);
|
|
475
|
+
await Persistence.init(persistence, ChainMap.values(config.chainMap), Config.stripSensitiveData(Config.getPublicConfigJson()), "envio local db-migrate setup", undefined, reset);
|
|
508
476
|
return await persistence.storage.close();
|
|
509
477
|
}
|
|
510
478
|
|
|
@@ -529,7 +497,7 @@ async function start(persistence, resetOpt, isTestOpt, exitAfterFirstEventBlockO
|
|
|
529
497
|
let isDevelopmentMode = !isTest && configWithoutRegistrations.isDev;
|
|
530
498
|
let persistence$1 = persistence !== undefined ? persistence : PgStorage.makePersistenceFromConfig(configWithoutRegistrations, undefined);
|
|
531
499
|
globalPersistenceRef.contents = persistence$1;
|
|
532
|
-
await Persistence.init(persistence$1, ChainMap.values(configWithoutRegistrations.chainMap), Config.stripSensitiveData(Config.getPublicConfigJson()), isDevelopmentMode ? "envio dev -r" : "envio start -r", reset);
|
|
500
|
+
await Persistence.init(persistence$1, ChainMap.values(configWithoutRegistrations.chainMap), Config.stripSensitiveData(Config.getPublicConfigJson()), isDevelopmentMode ? "envio dev -r" : "envio start -r", isDevelopmentMode ? "envio dev" : "envio start", reset);
|
|
533
501
|
let match = await HandlerLoader.registerAllHandlers(configWithoutRegistrations);
|
|
534
502
|
let registrations = match[1];
|
|
535
503
|
let config = match[0];
|
package/src/Persistence.res
CHANGED
|
@@ -168,7 +168,7 @@ let make = (
|
|
|
168
168
|
}
|
|
169
169
|
|
|
170
170
|
let init = {
|
|
171
|
-
async (persistence, ~chainConfigs, ~envioInfo, ~resetCommand, ~reset=false) => {
|
|
171
|
+
async (persistence, ~chainConfigs, ~envioInfo, ~resetCommand, ~runCommand, ~reset=false) => {
|
|
172
172
|
try {
|
|
173
173
|
let shouldRun = switch persistence.storageStatus {
|
|
174
174
|
| Unknown => true
|
|
@@ -212,7 +212,22 @@ let init = {
|
|
|
212
212
|
| None => ["envio info is missing — storage initialized by an older envio"]
|
|
213
213
|
| Some(stored) => Config.diffPaths(~stored, ~current=envioInfo)
|
|
214
214
|
}
|
|
215
|
-
|
|
215
|
+
// `storage.clickhouse` is serialized as a plain bool by the
|
|
216
|
+
// public config (see Rust `StorageConfig`), so probe for
|
|
217
|
+
// `Boolean(true)`, not an object.
|
|
218
|
+
let hasClickhouse = switch envioInfo {
|
|
219
|
+
| Object(d) =>
|
|
220
|
+
switch d->Dict.get("storage") {
|
|
221
|
+
| Some(Object(s)) =>
|
|
222
|
+
switch s->Dict.get("clickhouse") {
|
|
223
|
+
| Some(Boolean(true)) => true
|
|
224
|
+
| _ => false
|
|
225
|
+
}
|
|
226
|
+
| _ => false
|
|
227
|
+
}
|
|
228
|
+
| _ => false
|
|
229
|
+
}
|
|
230
|
+
Config.throwIfIncompatible(changedPaths, ~resetCommand, ~runCommand, ~hasClickhouse)
|
|
216
231
|
persistence.storageStatus = Ready(initialState)
|
|
217
232
|
let progress = Dict.make()
|
|
218
233
|
initialState.chains->Array.forEach(c => {
|