envio 3.3.0-alpha.1 → 3.3.0-alpha.11
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 +10 -0
- package/index.d.ts +45 -25
- package/licenses/CLA.md +35 -0
- package/licenses/EULA.md +67 -0
- package/licenses/LICENSE.md +45 -0
- package/licenses/README.md +35 -0
- package/package.json +10 -9
- package/src/Address.res +5 -2
- package/src/Address.res.mjs +3 -1
- package/src/Api.res +1 -1
- package/src/Api.res.mjs +1 -1
- package/src/Batch.res +0 -6
- package/src/Batch.res.mjs +1 -12
- package/src/BatchProcessing.res +7 -12
- package/src/BatchProcessing.res.mjs +8 -7
- package/src/Bin.res +3 -0
- package/src/Bin.res.mjs +4 -0
- package/src/ChainFetching.res +53 -16
- package/src/ChainFetching.res.mjs +37 -19
- package/src/ChainMetadata.res +1 -11
- package/src/ChainMetadata.res.mjs +1 -10
- package/src/ChainState.res +630 -161
- package/src/ChainState.res.mjs +438 -101
- package/src/ChainState.resi +77 -4
- package/src/Config.res +70 -38
- package/src/Config.res.mjs +52 -12
- package/src/ContractRegisterContext.res +2 -12
- package/src/ContractRegisterContext.res.mjs +3 -5
- package/src/Core.res +34 -3
- package/src/Core.res.mjs +12 -0
- package/src/CrossChainState.res +130 -89
- package/src/CrossChainState.res.mjs +66 -61
- package/src/CrossChainState.resi +1 -1
- package/src/Ecosystem.res +5 -6
- package/src/Ecosystem.res.mjs +3 -3
- package/src/Envio.res +17 -11
- package/src/EnvioGlobal.res +53 -0
- package/src/EnvioGlobal.res.mjs +31 -0
- package/src/EventConfigBuilder.res +191 -127
- package/src/EventConfigBuilder.res.mjs +116 -66
- package/src/EventProcessing.res +77 -28
- package/src/EventProcessing.res.mjs +56 -29
- package/src/ExitOnCaughtUp.res +10 -2
- package/src/ExitOnCaughtUp.res.mjs +10 -1
- package/src/FetchState.res +684 -415
- package/src/FetchState.res.mjs +505 -486
- package/src/HandlerLoader.res +8 -104
- package/src/HandlerLoader.res.mjs +2 -81
- package/src/HandlerRegister.res +520 -144
- package/src/HandlerRegister.res.mjs +286 -133
- package/src/HandlerRegister.resi +24 -8
- package/src/IndexerState.res +10 -3
- package/src/IndexerState.res.mjs +11 -4
- package/src/IndexerState.resi +2 -1
- package/src/IndexingAddresses.res +108 -0
- package/src/IndexingAddresses.res.mjs +101 -0
- package/src/IndexingAddresses.resi +34 -0
- package/src/Internal.res +166 -48
- package/src/Internal.res.mjs +30 -2
- package/src/LoadLayer.res +5 -5
- package/src/LoadLayer.res.mjs +6 -6
- package/src/LogSelection.res +92 -217
- package/src/LogSelection.res.mjs +95 -184
- package/src/Main.res +71 -236
- package/src/Main.res.mjs +60 -145
- package/src/Metrics.res +74 -0
- package/src/Metrics.res.mjs +75 -0
- package/src/PgStorage.res +4 -4
- package/src/PgStorage.res.mjs +5 -5
- package/src/Prometheus.res +10 -63
- package/src/Prometheus.res.mjs +124 -171
- package/src/PruneStaleHistory.res +2 -2
- package/src/PruneStaleHistory.res.mjs +3 -3
- package/src/RawEvent.res +7 -2
- package/src/RawEvent.res.mjs +4 -4
- package/src/Rollback.res +3 -3
- package/src/Rollback.res.mjs +4 -4
- package/src/RollbackCommit.res +4 -1
- package/src/RollbackCommit.res.mjs +3 -2
- package/src/SimulateDeadInputTracker.res +85 -0
- package/src/SimulateDeadInputTracker.res.mjs +73 -0
- package/src/SimulateDeadInputTracker.resi +12 -0
- package/src/SimulateItems.res +128 -28
- package/src/SimulateItems.res.mjs +82 -40
- package/src/TestIndexer.res +55 -41
- package/src/TestIndexer.res.mjs +39 -32
- package/src/TopicFilter.res +1 -25
- package/src/TopicFilter.res.mjs +0 -74
- package/src/bindings/Performance.res +7 -0
- package/src/bindings/Performance.res.mjs +21 -0
- package/src/bindings/Performance.resi +7 -0
- package/src/bindings/Viem.res +0 -46
- package/src/bindings/Viem.res.mjs +1 -43
- package/src/sources/BlockStore.res +46 -0
- package/src/sources/BlockStore.res.mjs +24 -0
- package/src/sources/EventRouter.res +31 -49
- package/src/sources/EventRouter.res.mjs +12 -25
- package/src/sources/Evm.res +83 -72
- package/src/sources/Evm.res.mjs +53 -69
- package/src/sources/EvmChain.res +7 -34
- package/src/sources/EvmChain.res.mjs +6 -27
- package/src/sources/EvmRpcClient.res +71 -5
- package/src/sources/EvmRpcClient.res.mjs +13 -4
- package/src/sources/FieldMask.res +39 -0
- package/src/sources/FieldMask.res.mjs +42 -0
- package/src/sources/Fuel.res +9 -6
- package/src/sources/Fuel.res.mjs +5 -10
- package/src/sources/HyperFuelSource.res +46 -50
- package/src/sources/HyperFuelSource.res.mjs +64 -54
- package/src/sources/HyperSync.res +45 -42
- package/src/sources/HyperSync.res.mjs +68 -60
- package/src/sources/HyperSync.resi +14 -4
- package/src/sources/HyperSyncClient.res +107 -119
- package/src/sources/HyperSyncClient.res.mjs +36 -31
- package/src/sources/HyperSyncHeightStream.res +1 -8
- package/src/sources/HyperSyncHeightStream.res.mjs +0 -2
- package/src/sources/HyperSyncSource.res +60 -254
- package/src/sources/HyperSyncSource.res.mjs +57 -180
- package/src/sources/Rpc.res +15 -79
- package/src/sources/Rpc.res.mjs +25 -101
- package/src/sources/RpcSource.res +221 -514
- package/src/sources/RpcSource.res.mjs +216 -411
- package/src/sources/RpcWebSocketHeightStream.res +0 -5
- package/src/sources/RpcWebSocketHeightStream.res.mjs +0 -2
- package/src/sources/SimulateSource.res +44 -20
- package/src/sources/SimulateSource.res.mjs +41 -14
- package/src/sources/Source.res +34 -6
- package/src/sources/SourceManager.res +77 -19
- package/src/sources/SourceManager.res.mjs +63 -21
- package/src/sources/SourceManager.resi +10 -0
- package/src/sources/Svm.res +31 -16
- package/src/sources/Svm.res.mjs +36 -13
- package/src/sources/SvmHyperSyncClient.res +5 -32
- package/src/sources/SvmHyperSyncSource.res +159 -134
- package/src/sources/SvmHyperSyncSource.res.mjs +164 -129
- package/src/sources/TransactionStore.res +49 -0
- package/src/sources/TransactionStore.res.mjs +30 -0
- package/src/tui/Tui.res +13 -16
- package/src/tui/Tui.res.mjs +12 -14
- package/svm.schema.json +49 -37
- package/src/bindings/Hrtime.res +0 -58
- package/src/bindings/Hrtime.res.mjs +0 -90
- package/src/bindings/Hrtime.resi +0 -30
|
@@ -1,44 +1,2 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
-
|
|
3
|
-
import * as Viem from "viem";
|
|
4
|
-
import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
|
|
5
|
-
import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
|
|
6
|
-
|
|
7
|
-
let ParseError = /* @__PURE__ */Primitive_exceptions.create("Viem.ParseError");
|
|
8
|
-
|
|
9
|
-
let UnknownContractName = /* @__PURE__ */Primitive_exceptions.create("Viem.UnknownContractName");
|
|
10
|
-
|
|
11
|
-
function parseLogOrThrow(contractNameAbiMapping, contractName, topics, data) {
|
|
12
|
-
let abi = contractNameAbiMapping[contractName];
|
|
13
|
-
if (abi !== undefined) {
|
|
14
|
-
let viemLog_abi = Primitive_option.valFromOption(abi);
|
|
15
|
-
let viemLog = {
|
|
16
|
-
abi: viemLog_abi,
|
|
17
|
-
data: data,
|
|
18
|
-
topics: topics
|
|
19
|
-
};
|
|
20
|
-
try {
|
|
21
|
-
return Viem.decodeEventLog(viemLog);
|
|
22
|
-
} catch (raw_exn) {
|
|
23
|
-
let exn = Primitive_exceptions.internalToException(raw_exn);
|
|
24
|
-
throw {
|
|
25
|
-
RE_EXN_ID: ParseError,
|
|
26
|
-
_1: exn,
|
|
27
|
-
Error: new Error()
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
} else {
|
|
31
|
-
throw {
|
|
32
|
-
RE_EXN_ID: UnknownContractName,
|
|
33
|
-
contractName: contractName,
|
|
34
|
-
Error: new Error()
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export {
|
|
40
|
-
ParseError,
|
|
41
|
-
UnknownContractName,
|
|
42
|
-
parseLogOrThrow,
|
|
43
|
-
}
|
|
44
|
-
/* viem Not a pure module */
|
|
2
|
+
/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// Binding to the Rust `BlockStore` napi class. Blocks are kept in Rust as raw
|
|
2
|
+
// structs (their large fields never enter JS until read) keyed by block number.
|
|
3
|
+
// One store lives per chain on `ChainState`; each fetch response contributes a
|
|
4
|
+
// page that is merged in. At batch preparation the selected fields are
|
|
5
|
+
// materialised in bulk, off the JS thread, in columnar form and zipped into
|
|
6
|
+
// plain JS objects on the main thread.
|
|
7
|
+
type t
|
|
8
|
+
|
|
9
|
+
@send external newEvm: (Core.blockStoreCtor, ~shouldChecksum: bool) => t = "newEvm"
|
|
10
|
+
@send external newSvm: Core.blockStoreCtor => t = "newSvm"
|
|
11
|
+
@send external newFuel: Core.blockStoreCtor => t = "newFuel"
|
|
12
|
+
|
|
13
|
+
// The store's ecosystem is fixed here, from the chain's config. EVM carries the
|
|
14
|
+
// chain's address-checksumming setting; SVM/Fuel need no extra data.
|
|
15
|
+
let make = (~ecosystem: Ecosystem.name, ~shouldChecksum: bool): t => {
|
|
16
|
+
let ctor = Core.getAddon().blockStore
|
|
17
|
+
switch ecosystem {
|
|
18
|
+
| Evm => ctor->newEvm(~shouldChecksum)
|
|
19
|
+
| Svm => ctor->newSvm
|
|
20
|
+
| Fuel => ctor->newFuel
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// One event's selected block fields → store selection bitmask, built from the
|
|
25
|
+
// ecosystem's ordered field-name array (the bit index is the field code shared
|
|
26
|
+
// with the Rust store, `EvmBlockField`).
|
|
27
|
+
let makeMaskFn = FieldMask.makeMaskFn
|
|
28
|
+
|
|
29
|
+
// Drain another store (a fetch-response page) into this one.
|
|
30
|
+
@send external merge: (t, t) => unit = "merge"
|
|
31
|
+
|
|
32
|
+
// Bulk-materialise blocks off the JS thread, one row per `blockNumbers[i]` key,
|
|
33
|
+
// decoding only the fields set in that row's own `masks[i]`. Result is aligned
|
|
34
|
+
// with the input.
|
|
35
|
+
@send
|
|
36
|
+
external materialize: (
|
|
37
|
+
t,
|
|
38
|
+
~blockNumbers: array<int>,
|
|
39
|
+
~masks: array<float>,
|
|
40
|
+
) => promise<array<Internal.eventBlock>> = "materialize"
|
|
41
|
+
|
|
42
|
+
// Drop blocks at or below the given block (already processed).
|
|
43
|
+
@send external prune: (t, int) => unit = "prune"
|
|
44
|
+
|
|
45
|
+
// Drop blocks above the given block (rolled back).
|
|
46
|
+
@send external rollback: (t, int) => unit = "rollback"
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as Core from "../Core.res.mjs";
|
|
4
|
+
import * as FieldMask from "./FieldMask.res.mjs";
|
|
5
|
+
|
|
6
|
+
function make(ecosystem, shouldChecksum) {
|
|
7
|
+
let ctor = Core.getAddon().BlockStore;
|
|
8
|
+
switch (ecosystem) {
|
|
9
|
+
case "evm" :
|
|
10
|
+
return ctor.newEvm(shouldChecksum);
|
|
11
|
+
case "fuel" :
|
|
12
|
+
return ctor.newFuel();
|
|
13
|
+
case "svm" :
|
|
14
|
+
return ctor.newSvm();
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
let makeMaskFn = FieldMask.makeMaskFn;
|
|
19
|
+
|
|
20
|
+
export {
|
|
21
|
+
make,
|
|
22
|
+
makeMaskFn,
|
|
23
|
+
}
|
|
24
|
+
/* Core Not a pure module */
|
|
@@ -28,29 +28,25 @@ module Group = {
|
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
) =>
|
|
31
|
+
// Ownership only: resolve the owning contract from the partition's reverse
|
|
32
|
+
// index (the partition that fetched the log), not a chain-wide snapshot. The
|
|
33
|
+
// `effectiveStartBlock` temporal gate now lives in `clientAddressFilter`. The
|
|
34
|
+
// wildcard partition has an empty index → every log falls back to `wildcard`,
|
|
35
|
+
// so it can never claim an address-bound contract's logs.
|
|
36
|
+
let get = (group: t<'a>, ~contractAddress, ~contractNameByAddress: dict<string>) =>
|
|
37
37
|
switch group {
|
|
38
38
|
| {wildcard, byContractName} =>
|
|
39
|
-
switch
|
|
39
|
+
switch contractNameByAddress->Utils.Dict.dangerouslyGetNonOption(
|
|
40
40
|
contractAddress->Address.toString,
|
|
41
41
|
) {
|
|
42
|
-
| Some(
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
| Some(_) as event => event
|
|
51
|
-
}
|
|
52
|
-
} else {
|
|
53
|
-
None
|
|
42
|
+
| Some(contractName) =>
|
|
43
|
+
switch byContractName->Utils.Dict.dangerouslyGetNonOption(contractName) {
|
|
44
|
+
// Fall back to the wildcard handler when the owning contract has no
|
|
45
|
+
// matching event for this tag. This covers addresses registered for
|
|
46
|
+
// contracts without events (persisted for future config changes) as
|
|
47
|
+
// well as addresses whose contract has other events but not this one.
|
|
48
|
+
| None => wildcard
|
|
49
|
+
| Some(_) as event => event
|
|
54
50
|
}
|
|
55
51
|
| None => wildcard
|
|
56
52
|
}
|
|
@@ -89,34 +85,13 @@ let addOrThrow = (
|
|
|
89
85
|
}
|
|
90
86
|
}
|
|
91
87
|
|
|
92
|
-
let get = (router: t<'a>, ~tag, ~contractAddress, ~
|
|
88
|
+
let get = (router: t<'a>, ~tag, ~contractAddress, ~contractNameByAddress) => {
|
|
93
89
|
switch router->Utils.Dict.dangerouslyGetNonOption(tag) {
|
|
94
90
|
| None => None
|
|
95
|
-
| Some(group) => group->Group.get(~contractAddress, ~
|
|
91
|
+
| Some(group) => group->Group.get(~contractAddress, ~contractNameByAddress)
|
|
96
92
|
}
|
|
97
93
|
}
|
|
98
94
|
|
|
99
|
-
let getEvmEventId = (~sighash, ~topicCount) => {
|
|
100
|
-
sighash ++ "_" ++ topicCount->Int.toString
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
let fromEvmEventModsOrThrow = (events: array<Internal.evmEventConfig>, ~chain): t<
|
|
104
|
-
Internal.evmEventConfig,
|
|
105
|
-
> => {
|
|
106
|
-
let router = empty()
|
|
107
|
-
events->Array.forEach(config => {
|
|
108
|
-
router->addOrThrow(
|
|
109
|
-
config.id,
|
|
110
|
-
config,
|
|
111
|
-
~contractName=config.contractName,
|
|
112
|
-
~eventName=config.name,
|
|
113
|
-
~chain,
|
|
114
|
-
~isWildcard=config.isWildcard,
|
|
115
|
-
)
|
|
116
|
-
})
|
|
117
|
-
router
|
|
118
|
-
}
|
|
119
|
-
|
|
120
95
|
/** Dispatch key for SVM instructions. `None` matches any instruction in the
|
|
121
96
|
program (lowest priority). */
|
|
122
97
|
let getSvmEventId = (~programId: SvmTypes.Pubkey.t, ~discriminator: option<string>) =>
|
|
@@ -135,21 +110,26 @@ type svmProgramOrdering = {
|
|
|
135
110
|
byteLengthsDesc: array<int>,
|
|
136
111
|
}
|
|
137
112
|
|
|
138
|
-
let fromSvmEventConfigsOrThrow = (events: array<Internal.
|
|
139
|
-
t<Internal.
|
|
113
|
+
let fromSvmEventConfigsOrThrow = (events: array<Internal.svmOnEventRegistration>, ~chain): (
|
|
114
|
+
t<Internal.svmOnEventRegistration>,
|
|
140
115
|
array<svmProgramOrdering>,
|
|
141
116
|
) => {
|
|
142
117
|
let router = empty()
|
|
143
118
|
events->Array.forEach(config => {
|
|
119
|
+
let eventConfig =
|
|
120
|
+
config.eventConfig->(Utils.magic: Internal.eventConfig => Internal.svmInstructionEventConfig)
|
|
144
121
|
// The router tag must include the programId so two programs declaring the
|
|
145
122
|
// same discriminator coexist. The source-side lookup uses the same shape
|
|
146
123
|
// via `getSvmEventId(~programId, ~discriminator)`.
|
|
147
|
-
let routerTag = getSvmEventId(
|
|
124
|
+
let routerTag = getSvmEventId(
|
|
125
|
+
~programId=eventConfig.programId,
|
|
126
|
+
~discriminator=eventConfig.discriminator,
|
|
127
|
+
)
|
|
148
128
|
router->addOrThrow(
|
|
149
129
|
routerTag,
|
|
150
130
|
config,
|
|
151
|
-
~contractName=
|
|
152
|
-
~eventName=
|
|
131
|
+
~contractName=eventConfig.contractName,
|
|
132
|
+
~eventName=eventConfig.name,
|
|
153
133
|
~chain,
|
|
154
134
|
~isWildcard=config.isWildcard,
|
|
155
135
|
)
|
|
@@ -158,7 +138,9 @@ let fromSvmEventConfigsOrThrow = (events: array<Internal.svmInstructionEventConf
|
|
|
158
138
|
// Per-program list of declared discriminator byte lengths, sorted desc.
|
|
159
139
|
let byProgram: dict<Utils.Set.t<int>> = Dict.make()
|
|
160
140
|
events->Array.forEach(config => {
|
|
161
|
-
let
|
|
141
|
+
let eventConfig =
|
|
142
|
+
config.eventConfig->(Utils.magic: Internal.eventConfig => Internal.svmInstructionEventConfig)
|
|
143
|
+
let key = eventConfig.programId->SvmTypes.Pubkey.toString
|
|
162
144
|
let set = switch byProgram->Utils.Dict.dangerouslyGetNonOption(key) {
|
|
163
145
|
| Some(s) => s
|
|
164
146
|
| None =>
|
|
@@ -166,7 +148,7 @@ let fromSvmEventConfigsOrThrow = (events: array<Internal.svmInstructionEventConf
|
|
|
166
148
|
byProgram->Dict.set(key, s)
|
|
167
149
|
s
|
|
168
150
|
}
|
|
169
|
-
let _ = set->Utils.Set.add(
|
|
151
|
+
let _ = set->Utils.Set.add(eventConfig.discriminatorByteLen)
|
|
170
152
|
})
|
|
171
153
|
let ordering =
|
|
172
154
|
byProgram
|
|
@@ -39,16 +39,13 @@ function addOrThrow(group, event, contractName, isWildcard) {
|
|
|
39
39
|
byContractName[contractName] = event;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
function get(group, contractAddress,
|
|
42
|
+
function get(group, contractAddress, contractNameByAddress) {
|
|
43
43
|
let wildcard = group.wildcard;
|
|
44
|
-
let
|
|
45
|
-
if (
|
|
44
|
+
let contractName = contractNameByAddress[contractAddress];
|
|
45
|
+
if (contractName === undefined) {
|
|
46
46
|
return wildcard;
|
|
47
47
|
}
|
|
48
|
-
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
let event = group.byContractName[indexingContract.contractName];
|
|
48
|
+
let event = group.byContractName[contractName];
|
|
52
49
|
if (event !== undefined) {
|
|
53
50
|
return event;
|
|
54
51
|
} else {
|
|
@@ -93,23 +90,13 @@ function addOrThrow$1(router, eventId, event, contractName, isWildcard, eventNam
|
|
|
93
90
|
}
|
|
94
91
|
}
|
|
95
92
|
|
|
96
|
-
function get$1(router, tag, contractAddress,
|
|
93
|
+
function get$1(router, tag, contractAddress, contractNameByAddress) {
|
|
97
94
|
let group = router[tag];
|
|
98
95
|
if (group !== undefined) {
|
|
99
|
-
return get(group, contractAddress,
|
|
96
|
+
return get(group, contractAddress, contractNameByAddress);
|
|
100
97
|
}
|
|
101
98
|
}
|
|
102
99
|
|
|
103
|
-
function getEvmEventId(sighash, topicCount) {
|
|
104
|
-
return sighash + "_" + topicCount.toString();
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
function fromEvmEventModsOrThrow(events, chain) {
|
|
108
|
-
let router = {};
|
|
109
|
-
events.forEach(config => addOrThrow$1(router, config.id, config, config.contractName, config.isWildcard, config.name, chain));
|
|
110
|
-
return router;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
100
|
function getSvmEventId(programId, discriminator) {
|
|
114
101
|
if (discriminator !== undefined) {
|
|
115
102
|
return programId + "_" + discriminator;
|
|
@@ -121,12 +108,14 @@ function getSvmEventId(programId, discriminator) {
|
|
|
121
108
|
function fromSvmEventConfigsOrThrow(events, chain) {
|
|
122
109
|
let router = {};
|
|
123
110
|
events.forEach(config => {
|
|
124
|
-
let
|
|
125
|
-
|
|
111
|
+
let eventConfig = config.eventConfig;
|
|
112
|
+
let routerTag = getSvmEventId(eventConfig.programId, eventConfig.discriminator);
|
|
113
|
+
addOrThrow$1(router, routerTag, config, eventConfig.contractName, config.isWildcard, eventConfig.name, chain);
|
|
126
114
|
});
|
|
127
115
|
let byProgram = {};
|
|
128
116
|
events.forEach(config => {
|
|
129
|
-
let
|
|
117
|
+
let eventConfig = config.eventConfig;
|
|
118
|
+
let key = eventConfig.programId;
|
|
130
119
|
let s = byProgram[key];
|
|
131
120
|
let set;
|
|
132
121
|
if (s !== undefined) {
|
|
@@ -136,7 +125,7 @@ function fromSvmEventConfigsOrThrow(events, chain) {
|
|
|
136
125
|
byProgram[key] = s$1;
|
|
137
126
|
set = s$1;
|
|
138
127
|
}
|
|
139
|
-
set.add(
|
|
128
|
+
set.add(eventConfig.discriminatorByteLen);
|
|
140
129
|
});
|
|
141
130
|
let ordering = Object.entries(byProgram).map(param => {
|
|
142
131
|
let sorted = Array.from(param[1]).toSorted((a, b) => b - a | 0);
|
|
@@ -158,8 +147,6 @@ export {
|
|
|
158
147
|
empty$1 as empty,
|
|
159
148
|
addOrThrow$1 as addOrThrow,
|
|
160
149
|
get$1 as get,
|
|
161
|
-
getEvmEventId,
|
|
162
|
-
fromEvmEventModsOrThrow,
|
|
163
150
|
getSvmEventId,
|
|
164
151
|
fromSvmEventConfigsOrThrow,
|
|
165
152
|
}
|
package/src/sources/Evm.res
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
// EVM's concrete item payload. Erased to `Internal.eventPayload` on the item
|
|
2
|
-
// and recovered here via `toPayload`.
|
|
2
|
+
// and recovered here via `toPayload`. HyperSync omits `transaction` (it lives
|
|
3
|
+
// raw in the per-chain store and is written onto the payload at batch prep);
|
|
4
|
+
// RPC/simulate build it inline.
|
|
3
5
|
type payload = {
|
|
4
6
|
contractName: string,
|
|
5
7
|
eventName: string,
|
|
@@ -7,12 +9,62 @@ type payload = {
|
|
|
7
9
|
chainId: int,
|
|
8
10
|
srcAddress: Address.t,
|
|
9
11
|
logIndex: int,
|
|
10
|
-
transaction
|
|
11
|
-
block
|
|
12
|
+
transaction?: Internal.eventTransaction,
|
|
13
|
+
// HyperSync omits `block` (it lives raw in the per-chain store and is written
|
|
14
|
+
// onto the payload at batch prep); RPC/simulate build it inline.
|
|
15
|
+
block?: Internal.eventBlock,
|
|
12
16
|
}
|
|
13
17
|
external fromPayload: payload => Internal.eventPayload = "%identity"
|
|
14
18
|
external toPayload: Internal.eventPayload => payload = "%identity"
|
|
15
19
|
|
|
20
|
+
// Ordered transaction field names, the field codes shared with the Rust store
|
|
21
|
+
// (`EvmTxField`). Derived from the typed field list so the two can't drift;
|
|
22
|
+
// `Internal.allEvmTransactionFields` is pinned to the Rust ordinal order by a test.
|
|
23
|
+
let transactionFields =
|
|
24
|
+
Internal.allEvmTransactionFields->(
|
|
25
|
+
Utils.magic: array<Internal.evmTransactionField> => array<string>
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
// One event's selected transaction fields → store selection bitmask. Computed
|
|
29
|
+
// per event at config build and cached on the event config.
|
|
30
|
+
let eventTransactionFieldMask = TransactionStore.makeMaskFn(transactionFields)
|
|
31
|
+
|
|
32
|
+
// Ordered block field names. The index of each is the field code shared with the
|
|
33
|
+
// Rust store (`EvmBlockField`) — keep this order in sync.
|
|
34
|
+
let blockFields = [
|
|
35
|
+
"number",
|
|
36
|
+
"timestamp",
|
|
37
|
+
"hash",
|
|
38
|
+
"parentHash",
|
|
39
|
+
"nonce",
|
|
40
|
+
"sha3Uncles",
|
|
41
|
+
"logsBloom",
|
|
42
|
+
"transactionsRoot",
|
|
43
|
+
"stateRoot",
|
|
44
|
+
"receiptsRoot",
|
|
45
|
+
"miner",
|
|
46
|
+
"difficulty",
|
|
47
|
+
"totalDifficulty",
|
|
48
|
+
"extraData",
|
|
49
|
+
"size",
|
|
50
|
+
"gasLimit",
|
|
51
|
+
"gasUsed",
|
|
52
|
+
"uncles",
|
|
53
|
+
"baseFeePerGas",
|
|
54
|
+
"blobGasUsed",
|
|
55
|
+
"excessBlobGas",
|
|
56
|
+
"parentBeaconBlockRoot",
|
|
57
|
+
"withdrawalsRoot",
|
|
58
|
+
"l1BlockNumber",
|
|
59
|
+
"sendCount",
|
|
60
|
+
"sendRoot",
|
|
61
|
+
"mixHash",
|
|
62
|
+
]
|
|
63
|
+
|
|
64
|
+
// One event's selected block fields → store selection bitmask. Computed per
|
|
65
|
+
// event at config build and cached on the event config.
|
|
66
|
+
let eventBlockFieldMask = BlockStore.makeMaskFn(blockFields)
|
|
67
|
+
|
|
16
68
|
let cleanUpRawEventFieldsInPlace: JSON.t => unit = %raw(`fields => {
|
|
17
69
|
delete fields.hash
|
|
18
70
|
delete fields.number
|
|
@@ -21,70 +73,6 @@ let cleanUpRawEventFieldsInPlace: JSON.t => unit = %raw(`fields => {
|
|
|
21
73
|
|
|
22
74
|
let make = (~logger: Pino.t): Ecosystem.t => {
|
|
23
75
|
name: Evm,
|
|
24
|
-
blockFields: [
|
|
25
|
-
"number",
|
|
26
|
-
"timestamp",
|
|
27
|
-
"hash",
|
|
28
|
-
"parentHash",
|
|
29
|
-
"nonce",
|
|
30
|
-
"sha3Uncles",
|
|
31
|
-
"logsBloom",
|
|
32
|
-
"transactionsRoot",
|
|
33
|
-
"stateRoot",
|
|
34
|
-
"receiptsRoot",
|
|
35
|
-
"miner",
|
|
36
|
-
"difficulty",
|
|
37
|
-
"totalDifficulty",
|
|
38
|
-
"extraData",
|
|
39
|
-
"size",
|
|
40
|
-
"gasLimit",
|
|
41
|
-
"gasUsed",
|
|
42
|
-
"uncles",
|
|
43
|
-
"baseFeePerGas",
|
|
44
|
-
"blobGasUsed",
|
|
45
|
-
"excessBlobGas",
|
|
46
|
-
"parentBeaconBlockRoot",
|
|
47
|
-
"withdrawalsRoot",
|
|
48
|
-
"l1BlockNumber",
|
|
49
|
-
"sendCount",
|
|
50
|
-
"sendRoot",
|
|
51
|
-
"mixHash",
|
|
52
|
-
],
|
|
53
|
-
transactionFields: [
|
|
54
|
-
"transactionIndex",
|
|
55
|
-
"hash",
|
|
56
|
-
"from",
|
|
57
|
-
"to",
|
|
58
|
-
"gas",
|
|
59
|
-
"gasPrice",
|
|
60
|
-
"maxPriorityFeePerGas",
|
|
61
|
-
"maxFeePerGas",
|
|
62
|
-
"cumulativeGasUsed",
|
|
63
|
-
"effectiveGasPrice",
|
|
64
|
-
"gasUsed",
|
|
65
|
-
"input",
|
|
66
|
-
"nonce",
|
|
67
|
-
"value",
|
|
68
|
-
"v",
|
|
69
|
-
"r",
|
|
70
|
-
"s",
|
|
71
|
-
"contractAddress",
|
|
72
|
-
"logsBloom",
|
|
73
|
-
"root",
|
|
74
|
-
"status",
|
|
75
|
-
"yParity",
|
|
76
|
-
"chainId",
|
|
77
|
-
"maxFeePerBlobGas",
|
|
78
|
-
"blobVersionedHashes",
|
|
79
|
-
"type",
|
|
80
|
-
"l1Fee",
|
|
81
|
-
"l1GasPrice",
|
|
82
|
-
"l1GasUsed",
|
|
83
|
-
"l1FeeScalar",
|
|
84
|
-
"gasUsedForL1",
|
|
85
|
-
"accessList",
|
|
86
|
-
"authorizationList",
|
|
87
|
-
],
|
|
88
76
|
blockNumberName: "number",
|
|
89
77
|
blockTimestampName: "timestamp",
|
|
90
78
|
blockHashName: "hash",
|
|
@@ -102,17 +90,22 @@ let make = (~logger: Pino.t): Ecosystem.t => {
|
|
|
102
90
|
// range chunk is validated by `eventBlockRangeSchema` in
|
|
103
91
|
// `LogSelection.res` which rejects `_lte`/`_every` (use `onBlock` for
|
|
104
92
|
// stride- and endBlock-based block handlers).
|
|
93
|
+
// `S.strict` on the inner object rejects unknown `block` fields (e.g. a
|
|
94
|
+
// `numbre` typo or `block: {timestamp: ...}`) instead of silently
|
|
95
|
+
// ignoring them.
|
|
105
96
|
onEventBlockFilterSchema: S.object(s =>
|
|
106
|
-
s.field("block", S.option(S.object(s2 => s2.field("number", S.unknown))))
|
|
97
|
+
s.field("block", S.option(S.object(s2 => s2.field("number", S.unknown))->S.strict))
|
|
107
98
|
),
|
|
108
99
|
logger,
|
|
109
|
-
|
|
100
|
+
// The payload carries `transaction` by batch prep (HyperSync) or inline
|
|
101
|
+
// (RPC/simulate), so the event is the payload as-is.
|
|
102
|
+
toEvent: eventItem => eventItem.payload->(Utils.magic: Internal.eventPayload => Internal.event),
|
|
110
103
|
toEventLogger: eventItem =>
|
|
111
104
|
Logging.createChildFrom(
|
|
112
105
|
~logger,
|
|
113
106
|
~params={
|
|
114
|
-
"contract": eventItem.eventConfig.contractName,
|
|
115
|
-
"event": eventItem.eventConfig.name,
|
|
107
|
+
"contract": eventItem.onEventRegistration.eventConfig.contractName,
|
|
108
|
+
"event": eventItem.onEventRegistration.eventConfig.name,
|
|
116
109
|
"chainId": eventItem.chain->ChainMap.Chain.toChainId,
|
|
117
110
|
"block": eventItem.blockNumber,
|
|
118
111
|
"logIndex": eventItem.logIndex,
|
|
@@ -121,11 +114,29 @@ let make = (~logger: Pino.t): Ecosystem.t => {
|
|
|
121
114
|
),
|
|
122
115
|
toRawEvent: eventItem => {
|
|
123
116
|
let payload = eventItem.payload->toPayload
|
|
117
|
+
let eventConfig =
|
|
118
|
+
eventItem.onEventRegistration.eventConfig->(
|
|
119
|
+
Utils.magic: Internal.eventConfig => Internal.evmEventConfig
|
|
120
|
+
)
|
|
121
|
+
// Store-backed payloads get `block` written at batch prep and inline
|
|
122
|
+
// sources carry it from the start, with hash/timestamp always selected —
|
|
123
|
+
// so both are present by the time a raw event is built.
|
|
124
|
+
let header = switch payload.block {
|
|
125
|
+
| Some(block) => block->(Utils.magic: Internal.eventBlock => {"hash": string, "timestamp": int})
|
|
126
|
+
| None =>
|
|
127
|
+
JsError.throwWithMessage("Unexpected case: The event block is missing for a raw event")
|
|
128
|
+
}
|
|
124
129
|
eventItem->RawEvent.make(
|
|
125
130
|
~block=payload.block,
|
|
126
131
|
~transaction=payload.transaction,
|
|
127
|
-
|
|
132
|
+
// The decoder emits `{}` for zero-parameter events, which the params
|
|
133
|
+
// schema rejects; pass unit so it serializes to the "null" sentinel.
|
|
134
|
+
~params=eventConfig.paramsMetadata->Array.length == 0
|
|
135
|
+
? ()->(Utils.magic: unit => Internal.eventParams)
|
|
136
|
+
: payload.params,
|
|
128
137
|
~srcAddress=payload.srcAddress,
|
|
138
|
+
~blockHash=header["hash"],
|
|
139
|
+
~blockTimestamp=header["timestamp"],
|
|
129
140
|
~cleanUpRawEventFieldsInPlace,
|
|
130
141
|
)
|
|
131
142
|
},
|