envio 3.0.0-alpha.21 → 3.0.0-alpha.22
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/bin.mjs +2 -48
- package/evm.schema.json +67 -0
- package/fuel.schema.json +67 -0
- package/index.d.ts +822 -38
- package/index.js +5 -3
- package/package.json +10 -8
- package/rescript.json +5 -9
- package/src/Address.res +4 -5
- package/src/Address.res.mjs +9 -12
- package/src/Api.res +15 -0
- package/src/Api.res.mjs +20 -0
- package/src/Batch.res +32 -34
- package/src/Batch.res.mjs +172 -187
- package/src/Bin.res +89 -0
- package/src/Bin.res.mjs +97 -0
- package/src/ChainFetcher.res +33 -57
- package/src/ChainFetcher.res.mjs +197 -227
- package/src/ChainManager.res +6 -14
- package/src/ChainManager.res.mjs +74 -85
- package/src/ChainMap.res +14 -16
- package/src/ChainMap.res.mjs +38 -38
- package/src/Config.res +193 -135
- package/src/Config.res.mjs +566 -592
- package/src/Core.res +182 -0
- package/src/Core.res.mjs +207 -0
- package/src/Ecosystem.res +25 -4
- package/src/Ecosystem.res.mjs +12 -13
- package/src/Env.res +20 -13
- package/src/Env.res.mjs +124 -113
- package/src/EnvSafe.res +269 -0
- package/src/EnvSafe.res.mjs +296 -0
- package/src/EnvSafe.resi +18 -0
- package/src/Envio.res +37 -26
- package/src/Envio.res.mjs +59 -60
- package/src/ErrorHandling.res +2 -2
- package/src/ErrorHandling.res.mjs +15 -15
- package/src/EventConfigBuilder.res +219 -81
- package/src/EventConfigBuilder.res.mjs +259 -202
- package/src/EventProcessing.res +27 -38
- package/src/EventProcessing.res.mjs +165 -183
- package/src/EventUtils.res +11 -11
- package/src/EventUtils.res.mjs +21 -22
- package/src/EvmTypes.res +0 -1
- package/src/EvmTypes.res.mjs +5 -5
- package/src/FetchState.res +360 -256
- package/src/FetchState.res.mjs +958 -914
- package/src/GlobalState.res +365 -351
- package/src/GlobalState.res.mjs +958 -992
- package/src/GlobalStateManager.res +1 -2
- package/src/GlobalStateManager.res.mjs +36 -44
- package/src/HandlerLoader.res +107 -23
- package/src/HandlerLoader.res.mjs +128 -38
- package/src/HandlerRegister.res +127 -103
- package/src/HandlerRegister.res.mjs +164 -164
- package/src/HandlerRegister.resi +12 -4
- package/src/Hasura.res +35 -22
- package/src/Hasura.res.mjs +158 -167
- package/src/InMemoryStore.res +20 -27
- package/src/InMemoryStore.res.mjs +64 -80
- package/src/InMemoryTable.res +34 -39
- package/src/InMemoryTable.res.mjs +165 -170
- package/src/Internal.res +52 -33
- package/src/Internal.res.mjs +84 -81
- package/src/LazyLoader.res.mjs +55 -61
- package/src/LoadLayer.res +77 -78
- package/src/LoadLayer.res.mjs +160 -189
- package/src/LoadManager.res +16 -21
- package/src/LoadManager.res.mjs +79 -84
- package/src/LogSelection.res +236 -68
- package/src/LogSelection.res.mjs +211 -141
- package/src/Logging.res +13 -9
- package/src/Logging.res.mjs +130 -143
- package/src/Main.res +428 -51
- package/src/Main.res.mjs +528 -271
- package/src/Persistence.res +77 -84
- package/src/Persistence.res.mjs +131 -132
- package/src/PgStorage.res +291 -167
- package/src/PgStorage.res.mjs +797 -817
- package/src/Prometheus.res +50 -58
- package/src/Prometheus.res.mjs +345 -373
- package/src/ReorgDetection.res +22 -24
- package/src/ReorgDetection.res.mjs +100 -106
- package/src/SafeCheckpointTracking.res +7 -7
- package/src/SafeCheckpointTracking.res.mjs +40 -43
- package/src/SimulateItems.res +41 -49
- package/src/SimulateItems.res.mjs +257 -272
- package/src/Sink.res +2 -2
- package/src/Sink.res.mjs +22 -26
- package/src/TableIndices.res +1 -2
- package/src/TableIndices.res.mjs +42 -48
- package/src/TestIndexer.res +196 -189
- package/src/TestIndexer.res.mjs +536 -536
- package/src/TestIndexerProxyStorage.res +15 -16
- package/src/TestIndexerProxyStorage.res.mjs +98 -122
- package/src/TestIndexerWorker.res +4 -0
- package/src/TestIndexerWorker.res.mjs +7 -0
- package/src/Throttler.res +3 -3
- package/src/Throttler.res.mjs +23 -24
- package/src/Time.res +1 -1
- package/src/Time.res.mjs +18 -21
- package/src/TopicFilter.res +3 -3
- package/src/TopicFilter.res.mjs +29 -30
- package/src/UserContext.res +93 -54
- package/src/UserContext.res.mjs +197 -182
- package/src/Utils.res +141 -86
- package/src/Utils.res.mjs +334 -295
- package/src/bindings/BigDecimal.res +0 -2
- package/src/bindings/BigDecimal.res.mjs +19 -23
- package/src/bindings/ClickHouse.res +28 -27
- package/src/bindings/ClickHouse.res.mjs +243 -240
- package/src/bindings/DateFns.res +11 -11
- package/src/bindings/DateFns.res.mjs +7 -7
- package/src/bindings/EventSource.res.mjs +2 -2
- package/src/bindings/Express.res +2 -5
- package/src/bindings/Hrtime.res +2 -2
- package/src/bindings/Hrtime.res.mjs +30 -32
- package/src/bindings/Lodash.res.mjs +1 -1
- package/src/bindings/NodeJs.res +14 -9
- package/src/bindings/NodeJs.res.mjs +20 -20
- package/src/bindings/Pino.res +8 -10
- package/src/bindings/Pino.res.mjs +40 -43
- package/src/bindings/Postgres.res +2 -5
- package/src/bindings/Postgres.res.mjs +9 -9
- package/src/bindings/PromClient.res +17 -2
- package/src/bindings/PromClient.res.mjs +30 -7
- package/src/bindings/SDSL.res.mjs +2 -2
- package/src/bindings/Viem.res +4 -4
- package/src/bindings/Viem.res.mjs +20 -22
- package/src/bindings/Vitest.res +1 -1
- package/src/bindings/Vitest.res.mjs +2 -2
- package/src/bindings/WebSocket.res +1 -1
- package/src/db/EntityHistory.res +9 -3
- package/src/db/EntityHistory.res.mjs +84 -59
- package/src/db/InternalTable.res +62 -60
- package/src/db/InternalTable.res.mjs +271 -203
- package/src/db/Schema.res +1 -2
- package/src/db/Schema.res.mjs +28 -32
- package/src/db/Table.res +28 -27
- package/src/db/Table.res.mjs +276 -292
- package/src/sources/EventRouter.res +21 -16
- package/src/sources/EventRouter.res.mjs +55 -57
- package/src/sources/Evm.res +17 -1
- package/src/sources/Evm.res.mjs +16 -8
- package/src/sources/EvmChain.res +15 -17
- package/src/sources/EvmChain.res.mjs +40 -42
- package/src/sources/Fuel.res +14 -1
- package/src/sources/Fuel.res.mjs +16 -8
- package/src/sources/FuelSDK.res +1 -1
- package/src/sources/FuelSDK.res.mjs +6 -8
- package/src/sources/HyperFuel.res +8 -10
- package/src/sources/HyperFuel.res.mjs +113 -123
- package/src/sources/HyperFuelClient.res.mjs +6 -7
- package/src/sources/HyperFuelSource.res +19 -20
- package/src/sources/HyperFuelSource.res.mjs +339 -356
- package/src/sources/HyperSync.res +11 -13
- package/src/sources/HyperSync.res.mjs +206 -220
- package/src/sources/HyperSyncClient.res +5 -7
- package/src/sources/HyperSyncClient.res.mjs +70 -75
- package/src/sources/HyperSyncHeightStream.res +8 -9
- package/src/sources/HyperSyncHeightStream.res.mjs +78 -86
- package/src/sources/HyperSyncJsonApi.res +18 -15
- package/src/sources/HyperSyncJsonApi.res.mjs +201 -231
- package/src/sources/HyperSyncSource.res +17 -21
- package/src/sources/HyperSyncSource.res.mjs +268 -290
- package/src/sources/Rpc.res +5 -5
- package/src/sources/Rpc.res.mjs +168 -192
- package/src/sources/RpcSource.res +166 -167
- package/src/sources/RpcSource.res.mjs +972 -1046
- package/src/sources/RpcWebSocketHeightStream.res +10 -11
- package/src/sources/RpcWebSocketHeightStream.res.mjs +131 -145
- package/src/sources/SimulateSource.res +1 -1
- package/src/sources/SimulateSource.res.mjs +35 -38
- package/src/sources/Source.res +1 -1
- package/src/sources/Source.res.mjs +3 -3
- package/src/sources/SourceManager.res +39 -20
- package/src/sources/SourceManager.res.mjs +340 -371
- package/src/sources/SourceManager.resi +2 -1
- package/src/sources/Svm.res +12 -5
- package/src/sources/Svm.res.mjs +44 -41
- package/src/tui/Tui.res +23 -12
- package/src/tui/Tui.res.mjs +292 -290
- package/src/tui/bindings/Ink.res +2 -4
- package/src/tui/bindings/Ink.res.mjs +35 -41
- package/src/tui/components/BufferedProgressBar.res +7 -7
- package/src/tui/components/BufferedProgressBar.res.mjs +46 -46
- package/src/tui/components/CustomHooks.res +1 -2
- package/src/tui/components/CustomHooks.res.mjs +102 -122
- package/src/tui/components/Messages.res +1 -2
- package/src/tui/components/Messages.res.mjs +38 -42
- package/src/tui/components/SyncETA.res +10 -11
- package/src/tui/components/SyncETA.res.mjs +178 -196
- package/src/tui/components/TuiData.res +1 -1
- package/src/tui/components/TuiData.res.mjs +7 -6
- package/src/vendored/Rest.res +52 -66
- package/src/vendored/Rest.res.mjs +324 -364
- package/svm.schema.json +67 -0
- package/src/Address.gen.ts +0 -8
- package/src/Config.gen.ts +0 -19
- package/src/Envio.gen.ts +0 -55
- package/src/EvmTypes.gen.ts +0 -6
- package/src/InMemoryStore.gen.ts +0 -6
- package/src/Internal.gen.ts +0 -64
- package/src/PgStorage.gen.ts +0 -10
- package/src/PgStorage.res.d.mts +0 -5
- package/src/Types.ts +0 -56
- package/src/bindings/BigDecimal.gen.ts +0 -14
- package/src/bindings/BigDecimal.res.d.mts +0 -5
- package/src/bindings/BigInt.gen.ts +0 -10
- package/src/bindings/BigInt.res +0 -70
- package/src/bindings/BigInt.res.d.mts +0 -5
- package/src/bindings/BigInt.res.mjs +0 -154
- package/src/bindings/Ethers.res.d.mts +0 -5
- package/src/bindings/Pino.gen.ts +0 -17
- package/src/bindings/Postgres.gen.ts +0 -8
- package/src/bindings/Postgres.res.d.mts +0 -5
- package/src/bindings/Promise.res +0 -67
- package/src/bindings/Promise.res.mjs +0 -26
- package/src/db/InternalTable.gen.ts +0 -36
- package/src/sources/HyperSyncClient.gen.ts +0 -19
|
@@ -1,20 +1,27 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
// Types moved to `Internal` so `Internal.evmEventConfig` can retain
|
|
2
|
+
// `indexedParams: array<eventParam>` for post-registration filter rebuild.
|
|
3
|
+
// Re-exported here as aliases for existing call sites.
|
|
4
|
+
type eventParamComponent = Internal.eventParamComponent
|
|
5
|
+
type eventParam = Internal.eventParam
|
|
6
|
+
|
|
7
|
+
let eventParamComponentSchema = S.recursive(self =>
|
|
8
|
+
S.object((s): eventParamComponent => {
|
|
9
|
+
name: s.field("name", S.string),
|
|
10
|
+
abiType: s.field("abiType", S.string),
|
|
11
|
+
components: ?s.field("components", S.option(S.array(self))),
|
|
12
|
+
})
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
let eventParamSchema = S.object((s): eventParam => {
|
|
10
16
|
name: s.field("name", S.string),
|
|
11
17
|
abiType: s.field("abiType", S.string),
|
|
12
18
|
indexed: s.fieldOr("indexed", S.bool, false),
|
|
19
|
+
components: ?s.field("components", S.option(S.array(eventParamComponentSchema))),
|
|
13
20
|
})
|
|
14
21
|
|
|
15
22
|
// Normalize a value that could be a single item or an array into an array
|
|
16
23
|
let normalizeOrThrow: 'a => array<'a> = value => {
|
|
17
|
-
if
|
|
24
|
+
if Array.isArray(value->Obj.magic) {
|
|
18
25
|
value->Obj.magic
|
|
19
26
|
} else {
|
|
20
27
|
[value]
|
|
@@ -29,22 +36,22 @@ let splitTupleComponents = (inner: string): array<string> => {
|
|
|
29
36
|
let components = []
|
|
30
37
|
let depth = ref(0)
|
|
31
38
|
let start = ref(0)
|
|
32
|
-
for i in 0 to inner->
|
|
33
|
-
let ch = inner->
|
|
39
|
+
for i in 0 to inner->String.length - 1 {
|
|
40
|
+
let ch = inner->String.charAt(i)
|
|
34
41
|
if ch == "(" {
|
|
35
42
|
depth := depth.contents + 1
|
|
36
43
|
} else if ch == ")" {
|
|
37
44
|
depth := depth.contents - 1
|
|
38
45
|
} else if ch == "," && depth.contents == 0 {
|
|
39
|
-
components->
|
|
46
|
+
components->Array.push(inner->String.slice(~start=start.contents, ~end=i))->ignore
|
|
40
47
|
start := i + 1
|
|
41
48
|
}
|
|
42
49
|
}
|
|
43
50
|
|
|
44
51
|
// Last component
|
|
45
|
-
if start.contents < inner->
|
|
52
|
+
if start.contents < inner->String.length {
|
|
46
53
|
components
|
|
47
|
-
->
|
|
54
|
+
->Array.push(inner->String.slice(~start=start.contents))
|
|
48
55
|
->ignore
|
|
49
56
|
}
|
|
50
57
|
components
|
|
@@ -54,53 +61,53 @@ let splitTupleComponents = (inner: string): array<string> => {
|
|
|
54
61
|
|
|
55
62
|
let rec abiTypeToSchema = (abiType: string): S.t<unknown> => {
|
|
56
63
|
// Handle array types: "type[]" or "type[N]"
|
|
57
|
-
if abiType->
|
|
58
|
-
let bracketIdx = abiType->
|
|
59
|
-
let baseType = abiType->
|
|
64
|
+
if abiType->String.endsWith("]") {
|
|
65
|
+
let bracketIdx = abiType->String.lastIndexOf("[")
|
|
66
|
+
let baseType = abiType->String.slice(~start=0, ~end=bracketIdx)
|
|
60
67
|
S.array(abiTypeToSchema(baseType))->S.toUnknown
|
|
61
|
-
} else if abiType->
|
|
68
|
+
} else if abiType->String.startsWith("(") && abiType->String.endsWith(")") {
|
|
62
69
|
// Tuple type: "(type1,type2,...)"
|
|
63
|
-
let inner = abiType->
|
|
70
|
+
let inner = abiType->String.slice(~start=1, ~end=abiType->String.length - 1)
|
|
64
71
|
let components = splitTupleComponents(inner)
|
|
65
|
-
let schemas = components->Array.map(c => abiTypeToSchema(c->
|
|
72
|
+
let schemas = components->Array.map(c => abiTypeToSchema(c->String.trim))
|
|
66
73
|
S.tuple(s => {
|
|
67
|
-
schemas->Array.mapWithIndex((
|
|
74
|
+
schemas->Array.mapWithIndex((schema, i) => s.item(i, schema))
|
|
68
75
|
})->S.toUnknown
|
|
69
76
|
} else {
|
|
70
77
|
switch abiType {
|
|
71
78
|
| "address" => Address.schema->S.toUnknown
|
|
72
79
|
| "bool" => S.bool->S.toUnknown
|
|
73
80
|
| "string" | "bytes" => S.string->S.toUnknown
|
|
74
|
-
| t if t->
|
|
75
|
-
| t if t->
|
|
76
|
-
| t if t->
|
|
77
|
-
| other =>
|
|
81
|
+
| t if t->String.startsWith("uint") => Utils.BigInt.schema->S.toUnknown
|
|
82
|
+
| t if t->String.startsWith("int") => Utils.BigInt.schema->S.toUnknown
|
|
83
|
+
| t if t->String.startsWith("bytes") => S.string->S.toUnknown
|
|
84
|
+
| other => JsError.throwWithMessage(`Unsupported ABI type: ${other}`)
|
|
78
85
|
}
|
|
79
86
|
}
|
|
80
87
|
}
|
|
81
88
|
|
|
82
89
|
// ABI type → schema for simulate items (accepts native JS values, not string-encoded)
|
|
83
90
|
let rec abiTypeToSimulateSchema = (abiType: string): S.t<unknown> => {
|
|
84
|
-
if abiType->
|
|
85
|
-
let bracketIdx = abiType->
|
|
86
|
-
let baseType = abiType->
|
|
91
|
+
if abiType->String.endsWith("]") {
|
|
92
|
+
let bracketIdx = abiType->String.lastIndexOf("[")
|
|
93
|
+
let baseType = abiType->String.slice(~start=0, ~end=bracketIdx)
|
|
87
94
|
S.array(abiTypeToSimulateSchema(baseType))->S.toUnknown
|
|
88
|
-
} else if abiType->
|
|
89
|
-
let inner = abiType->
|
|
95
|
+
} else if abiType->String.startsWith("(") && abiType->String.endsWith(")") {
|
|
96
|
+
let inner = abiType->String.slice(~start=1, ~end=abiType->String.length - 1)
|
|
90
97
|
let components = splitTupleComponents(inner)
|
|
91
|
-
let schemas = components->Array.map(c => abiTypeToSimulateSchema(c->
|
|
98
|
+
let schemas = components->Array.map(c => abiTypeToSimulateSchema(c->String.trim))
|
|
92
99
|
S.tuple(s => {
|
|
93
|
-
schemas->Array.mapWithIndex((
|
|
100
|
+
schemas->Array.mapWithIndex((schema, i) => s.item(i, schema))
|
|
94
101
|
})->S.toUnknown
|
|
95
102
|
} else {
|
|
96
103
|
switch abiType {
|
|
97
104
|
| "address" => S.string->S.toUnknown
|
|
98
105
|
| "bool" => S.bool->S.toUnknown
|
|
99
106
|
| "string" | "bytes" => S.string->S.toUnknown
|
|
100
|
-
| t if t->
|
|
101
|
-
| t if t->
|
|
102
|
-
| t if t->
|
|
103
|
-
| other =>
|
|
107
|
+
| t if t->String.startsWith("uint") => S.bigint->S.toUnknown
|
|
108
|
+
| t if t->String.startsWith("int") => S.bigint->S.toUnknown
|
|
109
|
+
| t if t->String.startsWith("bytes") => S.string->S.toUnknown
|
|
110
|
+
| other => JsError.throwWithMessage(`Unsupported ABI type: ${other}`)
|
|
104
111
|
}
|
|
105
112
|
}
|
|
106
113
|
}
|
|
@@ -108,13 +115,13 @@ let rec abiTypeToSimulateSchema = (abiType: string): S.t<unknown> => {
|
|
|
108
115
|
// ============== ABI type → default value for simulate ==============
|
|
109
116
|
|
|
110
117
|
let rec abiTypeToDefaultValue = (abiType: string): unknown => {
|
|
111
|
-
if abiType->
|
|
118
|
+
if abiType->String.endsWith("]") {
|
|
112
119
|
[]->(Utils.magic: array<unknown> => unknown)
|
|
113
|
-
} else if abiType->
|
|
114
|
-
let inner = abiType->
|
|
120
|
+
} else if abiType->String.startsWith("(") && abiType->String.endsWith(")") {
|
|
121
|
+
let inner = abiType->String.slice(~start=1, ~end=abiType->String.length - 1)
|
|
115
122
|
let components = splitTupleComponents(inner)
|
|
116
123
|
components
|
|
117
|
-
->Array.map(c => abiTypeToDefaultValue(c->
|
|
124
|
+
->Array.map(c => abiTypeToDefaultValue(c->String.trim))
|
|
118
125
|
->(Utils.magic: array<unknown> => unknown)
|
|
119
126
|
} else {
|
|
120
127
|
switch abiType {
|
|
@@ -125,14 +132,96 @@ let rec abiTypeToDefaultValue = (abiType: string): unknown => {
|
|
|
125
132
|
|
|
126
133
|
| "bool" => false->(Utils.magic: bool => unknown)
|
|
127
134
|
| "string" | "bytes" => ""->(Utils.magic: string => unknown)
|
|
128
|
-
| t if t->
|
|
129
|
-
| t if t->
|
|
130
|
-
| t if t->
|
|
135
|
+
| t if t->String.startsWith("uint") => 0n->(Utils.magic: bigint => unknown)
|
|
136
|
+
| t if t->String.startsWith("int") => 0n->(Utils.magic: bigint => unknown)
|
|
137
|
+
| t if t->String.startsWith("bytes") => ""->(Utils.magic: string => unknown)
|
|
131
138
|
| _ => %raw(`undefined`)->(Utils.magic: 'a => unknown)
|
|
132
139
|
}
|
|
133
140
|
}
|
|
134
141
|
}
|
|
135
142
|
|
|
143
|
+
// ============== Named-tuple (struct) schema helpers ==============
|
|
144
|
+
|
|
145
|
+
// Build a simulate schema that honours component names: whenever an event param
|
|
146
|
+
// (or nested field) has components, we decode it as an object with named fields
|
|
147
|
+
// rather than a positional tuple. Walks through array wrappers so `struct[]`
|
|
148
|
+
// still produces `array<{...}>`.
|
|
149
|
+
let rec componentsToSimulateSchema = (abiType: string, components: array<eventParamComponent>): S.t<
|
|
150
|
+
unknown,
|
|
151
|
+
> => {
|
|
152
|
+
if abiType->String.endsWith("]") {
|
|
153
|
+
let bracketIdx = abiType->String.lastIndexOf("[")
|
|
154
|
+
let baseType = abiType->String.slice(~start=0, ~end=bracketIdx)
|
|
155
|
+
S.array(componentsToSimulateSchema(baseType, components))->S.toUnknown
|
|
156
|
+
} else {
|
|
157
|
+
// Must be a tuple at this level: build a record keyed by component names.
|
|
158
|
+
S.object(s => {
|
|
159
|
+
let dict = Dict.make()
|
|
160
|
+
components->Array.forEach(c => {
|
|
161
|
+
let childSchema = switch c.components {
|
|
162
|
+
| Some(sub) => componentsToSimulateSchema(c.abiType, sub)
|
|
163
|
+
| None => abiTypeToSimulateSchema(c.abiType)
|
|
164
|
+
}
|
|
165
|
+
dict->Dict.set(c.name, s.field(c.name, childSchema))
|
|
166
|
+
})
|
|
167
|
+
dict
|
|
168
|
+
})->S.toUnknown
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Default simulate value for a component tree — mirrors `abiTypeToDefaultValue`
|
|
173
|
+
// but emits objects with named fields for tuples.
|
|
174
|
+
let rec componentsToDefaultValue = (
|
|
175
|
+
abiType: string,
|
|
176
|
+
components: array<eventParamComponent>,
|
|
177
|
+
): unknown => {
|
|
178
|
+
if abiType->String.endsWith("]") {
|
|
179
|
+
[]->(Utils.magic: array<unknown> => unknown)
|
|
180
|
+
} else {
|
|
181
|
+
let dict = Dict.make()
|
|
182
|
+
components->Array.forEach(c => {
|
|
183
|
+
let v = switch c.components {
|
|
184
|
+
| Some(sub) => componentsToDefaultValue(c.abiType, sub)
|
|
185
|
+
| None => abiTypeToDefaultValue(c.abiType)
|
|
186
|
+
}
|
|
187
|
+
dict->Dict.set(c.name, v)
|
|
188
|
+
})
|
|
189
|
+
dict->(Utils.magic: dict<unknown> => unknown)
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Build a post-processor that converts the raw positional tuple values
|
|
194
|
+
// produced by the HyperSync decoder into objects with named fields. Walks
|
|
195
|
+
// through array wrappers so `struct[]` becomes `array<{...}>`. Returns `None`
|
|
196
|
+
// for leaf params where no remapping is needed.
|
|
197
|
+
let rec componentsToRemapper = (
|
|
198
|
+
abiType: string,
|
|
199
|
+
components: array<eventParamComponent>,
|
|
200
|
+
value: unknown,
|
|
201
|
+
): unknown => {
|
|
202
|
+
if abiType->String.endsWith("]") {
|
|
203
|
+
let bracketIdx = abiType->String.lastIndexOf("[")
|
|
204
|
+
let baseType = abiType->String.slice(~start=0, ~end=bracketIdx)
|
|
205
|
+
let arr = value->(Utils.magic: unknown => array<unknown>)
|
|
206
|
+
arr
|
|
207
|
+
->Array.map(item => componentsToRemapper(baseType, components, item))
|
|
208
|
+
->(Utils.magic: array<unknown> => unknown)
|
|
209
|
+
} else {
|
|
210
|
+
// Must be a tuple at this level: build an object keyed by component names.
|
|
211
|
+
let arr = value->(Utils.magic: unknown => array<unknown>)
|
|
212
|
+
let dict = Dict.make()
|
|
213
|
+
components->Array.forEachWithIndex((c, i) => {
|
|
214
|
+
let raw = arr->Array.getUnsafe(i)
|
|
215
|
+
let mapped = switch c.components {
|
|
216
|
+
| Some(sub) => componentsToRemapper(c.abiType, sub, raw)
|
|
217
|
+
| None => raw
|
|
218
|
+
}
|
|
219
|
+
dict->Dict.set(c.name, mapped)
|
|
220
|
+
})
|
|
221
|
+
dict->(Utils.magic: dict<unknown> => unknown)
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
136
225
|
// ============== Build paramsRawEventSchema ==============
|
|
137
226
|
|
|
138
227
|
let buildParamsSchema = (params: array<eventParam>): S.t<Internal.eventParams> => {
|
|
@@ -142,9 +231,9 @@ let buildParamsSchema = (params: array<eventParam>): S.t<Internal.eventParams> =
|
|
|
142
231
|
->(Utils.magic: S.t<unit> => S.t<Internal.eventParams>)
|
|
143
232
|
} else {
|
|
144
233
|
S.object(s => {
|
|
145
|
-
let dict =
|
|
234
|
+
let dict = Dict.make()
|
|
146
235
|
params->Array.forEach(p => {
|
|
147
|
-
dict->
|
|
236
|
+
dict->Dict.set(p.name, s.field(p.name, abiTypeToSchema(p.abiType)))
|
|
148
237
|
})
|
|
149
238
|
dict
|
|
150
239
|
})->(Utils.magic: S.t<dict<unknown>> => S.t<Internal.eventParams>)
|
|
@@ -153,6 +242,8 @@ let buildParamsSchema = (params: array<eventParam>): S.t<Internal.eventParams> =
|
|
|
153
242
|
|
|
154
243
|
// Build a lenient params schema for simulate items.
|
|
155
244
|
// Uses S.schema + s.matches with S.null->S.Option.getOr to fill missing fields with defaults.
|
|
245
|
+
// When a param carries component metadata (Solidity struct), we accept and emit a
|
|
246
|
+
// record with named fields rather than a positional tuple.
|
|
156
247
|
let buildSimulateParamsSchema = (params: array<eventParam>): S.t<Internal.eventParams> => {
|
|
157
248
|
if params->Array.length == 0 {
|
|
158
249
|
S.unknown
|
|
@@ -160,16 +251,16 @@ let buildSimulateParamsSchema = (params: array<eventParam>): S.t<Internal.eventP
|
|
|
160
251
|
->(Utils.magic: S.t<unit> => S.t<Internal.eventParams>)
|
|
161
252
|
} else {
|
|
162
253
|
S.schema(s => {
|
|
163
|
-
let dict =
|
|
254
|
+
let dict = Dict.make()
|
|
164
255
|
params->Array.forEach(p => {
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
)
|
|
256
|
+
let (paramSchema, paramDefault) = switch p.components {
|
|
257
|
+
| Some(components) => (
|
|
258
|
+
componentsToSimulateSchema(p.abiType, components),
|
|
259
|
+
componentsToDefaultValue(p.abiType, components),
|
|
260
|
+
)
|
|
261
|
+
| None => (abiTypeToSimulateSchema(p.abiType), abiTypeToDefaultValue(p.abiType))
|
|
262
|
+
}
|
|
263
|
+
dict->Dict.set(p.name, s.matches(S.null(paramSchema)->S.Option.getOr(paramDefault)))
|
|
173
264
|
})
|
|
174
265
|
dict
|
|
175
266
|
})->(Utils.magic: S.t<dict<unknown>> => S.t<Internal.eventParams>)
|
|
@@ -189,18 +280,18 @@ let buildHyperSyncDecoder = (params: array<eventParam>): (
|
|
|
189
280
|
if params->Array.length == 0 {
|
|
190
281
|
_ => ()->(Utils.magic: unit => Internal.eventParams)
|
|
191
282
|
} else {
|
|
192
|
-
let indexedParams = params->
|
|
193
|
-
let bodyParams = params->
|
|
283
|
+
let indexedParams = params->Array.filter(p => p.indexed)
|
|
284
|
+
let bodyParams = params->Array.filter(p => !p.indexed)
|
|
194
285
|
|
|
195
286
|
let fields = []
|
|
196
|
-
indexedParams->Array.forEachWithIndex((
|
|
197
|
-
fields->
|
|
287
|
+
indexedParams->Array.forEachWithIndex((p, i) => {
|
|
288
|
+
fields->Array.push(`"${p.name}": t(d.indexed[${i->Int.toString}])`)->ignore
|
|
198
289
|
})
|
|
199
|
-
bodyParams->Array.forEachWithIndex((
|
|
200
|
-
fields->
|
|
290
|
+
bodyParams->Array.forEachWithIndex((p, i) => {
|
|
291
|
+
fields->Array.push(`"${p.name}": t(d.body[${i->Int.toString}])`)->ignore
|
|
201
292
|
})
|
|
202
293
|
// Generate: function(t) { return function(d) { return { ... } } }
|
|
203
|
-
let body = `return function(d) { return {${fields->
|
|
294
|
+
let body = `return function(d) { return {${fields->Array.joinUnsafe(", ")}} }`
|
|
204
295
|
|
|
205
296
|
let factory: (
|
|
206
297
|
HyperSyncClient.Decoder.decodedRaw => HyperSyncClient.Decoder.decodedUnderlying
|
|
@@ -211,7 +302,33 @@ let buildHyperSyncDecoder = (params: array<eventParam>): (
|
|
|
211
302
|
) => HyperSyncClient.Decoder.decodedEvent => Internal.eventParams
|
|
212
303
|
)
|
|
213
304
|
|
|
214
|
-
factory(HyperSyncClient.Decoder.toUnderlying)
|
|
305
|
+
let baseDecode = factory(HyperSyncClient.Decoder.toUnderlying)
|
|
306
|
+
|
|
307
|
+
// For any param that has tuple component metadata, rewrite its value from a
|
|
308
|
+
// positional array into a named record post-decode. We pre-collect the
|
|
309
|
+
// params that need remapping so the hot path only walks those. Indexed
|
|
310
|
+
// struct/tuple params arrive as keccak256 topic hashes (single hex strings)
|
|
311
|
+
// rather than positional arrays, so they must be skipped here — running
|
|
312
|
+
// componentsToRemapper on a hash would treat the hex string as an array
|
|
313
|
+
// and read garbage.
|
|
314
|
+
let paramsToRemap = params->Array.filter(p => !p.indexed && p.components->Option.isSome)
|
|
315
|
+
|
|
316
|
+
if paramsToRemap->Array.length == 0 {
|
|
317
|
+
baseDecode
|
|
318
|
+
} else {
|
|
319
|
+
decoded => {
|
|
320
|
+
let result = baseDecode(decoded)
|
|
321
|
+
let dict = result->(Utils.magic: Internal.eventParams => dict<unknown>)
|
|
322
|
+
paramsToRemap->Array.forEach(p => {
|
|
323
|
+
switch (p.components, dict->Dict.get(p.name)) {
|
|
324
|
+
| (Some(components), Some(raw)) =>
|
|
325
|
+
dict->Dict.set(p.name, componentsToRemapper(p.abiType, components, raw))
|
|
326
|
+
| _ => ()
|
|
327
|
+
}
|
|
328
|
+
})
|
|
329
|
+
dict->(Utils.magic: dict<unknown> => Internal.eventParams)
|
|
330
|
+
}
|
|
331
|
+
}
|
|
215
332
|
}
|
|
216
333
|
}
|
|
217
334
|
|
|
@@ -219,7 +336,7 @@ let buildHyperSyncDecoder = (params: array<eventParam>): (
|
|
|
219
336
|
|
|
220
337
|
let getTopicEncoder = (abiType: string): (unknown => EvmTypes.Hex.t) => {
|
|
221
338
|
// Handle array/tuple types - these get keccak256'd
|
|
222
|
-
if abiType->
|
|
339
|
+
if abiType->String.endsWith("]") || abiType->String.startsWith("(") {
|
|
223
340
|
TopicFilter.castToHexUnsafe->(Utils.magic: ('a => EvmTypes.Hex.t) => unknown => EvmTypes.Hex.t)
|
|
224
341
|
} else {
|
|
225
342
|
switch abiType {
|
|
@@ -240,33 +357,30 @@ let getTopicEncoder = (abiType: string): (unknown => EvmTypes.Hex.t) => {
|
|
|
240
357
|
Utils.magic: (string => EvmTypes.Hex.t) => unknown => EvmTypes.Hex.t
|
|
241
358
|
)
|
|
242
359
|
|
|
243
|
-
| t if t->
|
|
360
|
+
| t if t->String.startsWith("uint") =>
|
|
244
361
|
TopicFilter.fromBigInt->(Utils.magic: (bigint => EvmTypes.Hex.t) => unknown => EvmTypes.Hex.t)
|
|
245
|
-
| t if t->
|
|
362
|
+
| t if t->String.startsWith("int") =>
|
|
246
363
|
TopicFilter.fromSignedBigInt->(
|
|
247
364
|
Utils.magic: (bigint => EvmTypes.Hex.t) => unknown => EvmTypes.Hex.t
|
|
248
365
|
)
|
|
249
366
|
|
|
250
|
-
| t if t->
|
|
367
|
+
| t if t->String.startsWith("bytes") =>
|
|
251
368
|
TopicFilter.castToHexUnsafe->(
|
|
252
369
|
Utils.magic: ('a => EvmTypes.Hex.t) => unknown => EvmTypes.Hex.t
|
|
253
370
|
)
|
|
254
371
|
|
|
255
|
-
| other =>
|
|
372
|
+
| other => JsError.throwWithMessage(`Unsupported topic filter ABI type: ${other}`)
|
|
256
373
|
}
|
|
257
374
|
}
|
|
258
375
|
}
|
|
259
376
|
|
|
260
377
|
let buildTopicGetter = (p: eventParam) => {
|
|
261
378
|
let encoder = getTopicEncoder(p.abiType)
|
|
262
|
-
(eventFilter:
|
|
379
|
+
(eventFilter: dict<JSON.t>) =>
|
|
263
380
|
eventFilter
|
|
264
381
|
->Utils.Dict.dangerouslyGetNonOption(p.name)
|
|
265
|
-
->Option.
|
|
266
|
-
topicFilters
|
|
267
|
-
->(Utils.magic: Js.Json.t => unknown)
|
|
268
|
-
->normalizeOrThrow
|
|
269
|
-
->Js.Array2.map(encoder)
|
|
382
|
+
->Option.mapOr([], topicFilters =>
|
|
383
|
+
topicFilters->(Utils.magic: JSON.t => unknown)->normalizeOrThrow->Array.map(encoder)
|
|
270
384
|
)
|
|
271
385
|
}
|
|
272
386
|
|
|
@@ -303,24 +417,43 @@ let buildEvmEventConfig = (
|
|
|
303
417
|
~isWildcard: bool,
|
|
304
418
|
~handler: option<Internal.handler>,
|
|
305
419
|
~contractRegister: option<Internal.contractRegister>,
|
|
306
|
-
~eventFilters: option<
|
|
420
|
+
~eventFilters: option<JSON.t>,
|
|
421
|
+
~probeChainId: int,
|
|
422
|
+
~onEventBlockFilterSchema: S.t<option<unknown>>,
|
|
307
423
|
~blockFields: option<array<Internal.evmBlockField>>=?,
|
|
308
424
|
~transactionFields: option<array<Internal.evmTransactionField>>=?,
|
|
425
|
+
~startBlock: option<int>=?,
|
|
309
426
|
~globalBlockFieldsSet: Utils.Set.t<Internal.evmBlockField>=Utils.Set.make(),
|
|
310
427
|
~globalTransactionFieldsSet: Utils.Set.t<Internal.evmTransactionField>=Utils.Set.make(),
|
|
311
428
|
): Internal.evmEventConfig => {
|
|
312
429
|
let topicCount = params->Array.reduce(1, (acc, p) => p.indexed ? acc + 1 : acc)
|
|
313
|
-
let indexedParams = params->
|
|
430
|
+
let indexedParams = params->Array.filter(p => p.indexed)
|
|
314
431
|
|
|
315
|
-
let {
|
|
432
|
+
let {
|
|
433
|
+
getEventFiltersOrThrow,
|
|
434
|
+
filterByAddresses,
|
|
435
|
+
startBlock: whereStartBlock,
|
|
436
|
+
} = LogSelection.parseEventFiltersOrThrow(
|
|
316
437
|
~eventFilters,
|
|
317
438
|
~sighash,
|
|
318
439
|
~params=indexedParams->Array.map(p => p.name),
|
|
440
|
+
~contractName,
|
|
441
|
+
~probeChainId,
|
|
442
|
+
~onEventBlockFilterSchema,
|
|
319
443
|
~topic1=?indexedParams->Array.get(0)->Option.map(buildTopicGetter),
|
|
320
444
|
~topic2=?indexedParams->Array.get(1)->Option.map(buildTopicGetter),
|
|
321
445
|
~topic3=?indexedParams->Array.get(2)->Option.map(buildTopicGetter),
|
|
322
446
|
)
|
|
323
447
|
|
|
448
|
+
// `where.block.number._gte` overrides the contract-level startBlock
|
|
449
|
+
// when present. The user opts into this explicitly in handler code so
|
|
450
|
+
// it should win over the `config.yaml` contract `start_block`; absent
|
|
451
|
+
// `where.block`, the caller's contract-level value passes through.
|
|
452
|
+
let resolvedStartBlock = switch whereStartBlock {
|
|
453
|
+
| Some(_) as sb => sb
|
|
454
|
+
| None => startBlock
|
|
455
|
+
}
|
|
456
|
+
|
|
324
457
|
let (selectedBlockFields, selectedTransactionFields) = resolveFieldSelection(
|
|
325
458
|
~blockFields,
|
|
326
459
|
~transactionFields,
|
|
@@ -340,9 +473,12 @@ let buildEvmEventConfig = (
|
|
|
340
473
|
getEventFiltersOrThrow,
|
|
341
474
|
filterByAddresses,
|
|
342
475
|
dependsOnAddresses: !isWildcard || filterByAddresses,
|
|
476
|
+
startBlock: resolvedStartBlock,
|
|
343
477
|
convertHyperSyncEventArgs: buildHyperSyncDecoder(params),
|
|
344
478
|
selectedBlockFields,
|
|
345
479
|
selectedTransactionFields,
|
|
480
|
+
sighash,
|
|
481
|
+
indexedParams,
|
|
346
482
|
}
|
|
347
483
|
}
|
|
348
484
|
|
|
@@ -353,10 +489,11 @@ let buildFuelEventConfig = (
|
|
|
353
489
|
~eventName: string,
|
|
354
490
|
~kind: string,
|
|
355
491
|
~sighash: string,
|
|
356
|
-
~rawAbi:
|
|
492
|
+
~rawAbi: JSON.t,
|
|
357
493
|
~isWildcard: bool,
|
|
358
494
|
~handler: option<Internal.handler>,
|
|
359
495
|
~contractRegister: option<Internal.contractRegister>,
|
|
496
|
+
~startBlock: option<int>=?,
|
|
360
497
|
): Internal.fuelEventConfig => {
|
|
361
498
|
let fuelKind = switch kind {
|
|
362
499
|
| "logData" =>
|
|
@@ -370,7 +507,7 @@ let buildFuelEventConfig = (
|
|
|
370
507
|
| "burn" => Burn
|
|
371
508
|
| "transfer" => Transfer
|
|
372
509
|
| "call" => Call
|
|
373
|
-
| other =>
|
|
510
|
+
| other => JsError.throwWithMessage(`Unsupported Fuel event kind: ${other}`)
|
|
374
511
|
}
|
|
375
512
|
let paramsSchema = switch kind {
|
|
376
513
|
| "mint" | "burn" =>
|
|
@@ -386,8 +523,8 @@ let buildFuelEventConfig = (
|
|
|
386
523
|
| "logData" =>
|
|
387
524
|
S.json(~validate=false)
|
|
388
525
|
->Utils.Schema.coerceToJsonPgType
|
|
389
|
-
->(Utils.magic: S.t<
|
|
390
|
-
| other =>
|
|
526
|
+
->(Utils.magic: S.t<JSON.t> => S.t<Internal.eventParams>)
|
|
527
|
+
| other => JsError.throwWithMessage(`Unsupported Fuel event kind: ${other}`)
|
|
391
528
|
}
|
|
392
529
|
{
|
|
393
530
|
id: switch kind {
|
|
@@ -403,6 +540,7 @@ let buildFuelEventConfig = (
|
|
|
403
540
|
simulateParamsSchema: paramsSchema,
|
|
404
541
|
filterByAddresses: false,
|
|
405
542
|
dependsOnAddresses: !isWildcard,
|
|
543
|
+
startBlock,
|
|
406
544
|
kind: fuelKind,
|
|
407
545
|
}
|
|
408
546
|
}
|