envio 3.3.0-alpha.0 → 3.3.0-alpha.10
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/package.json +7 -7
- 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 +48 -16
- package/src/ChainFetching.res.mjs +36 -17
- package/src/ChainMetadata.res +1 -11
- package/src/ChainMetadata.res.mjs +1 -10
- package/src/ChainState.res +628 -149
- package/src/ChainState.res.mjs +440 -102
- package/src/ChainState.resi +74 -4
- package/src/Config.res +61 -33
- package/src/Config.res.mjs +50 -10
- package/src/ContractRegisterContext.res +2 -12
- package/src/ContractRegisterContext.res.mjs +3 -5
- package/src/Core.res +14 -3
- package/src/CrossChainState.res +142 -93
- package/src/CrossChainState.res.mjs +88 -60
- package/src/CrossChainState.resi +2 -10
- package/src/Ecosystem.res +5 -6
- package/src/Ecosystem.res.mjs +3 -3
- package/src/Env.res +0 -7
- package/src/Env.res.mjs +0 -6
- package/src/Envio.res +17 -11
- package/src/EnvioGlobal.res +53 -0
- package/src/EnvioGlobal.res.mjs +31 -0
- package/src/EventConfigBuilder.res +177 -88
- package/src/EventConfigBuilder.res.mjs +99 -42
- package/src/EventProcessing.res +74 -28
- package/src/EventProcessing.res.mjs +55 -29
- package/src/ExitOnCaughtUp.res +10 -2
- package/src/ExitOnCaughtUp.res.mjs +10 -1
- package/src/FetchState.res +558 -300
- package/src/FetchState.res.mjs +437 -423
- package/src/HandlerLoader.res +8 -104
- package/src/HandlerLoader.res.mjs +2 -81
- package/src/HandlerRegister.res +518 -144
- package/src/HandlerRegister.res.mjs +285 -133
- package/src/HandlerRegister.resi +24 -8
- package/src/IndexerLoop.res +2 -3
- package/src/IndexerLoop.res.mjs +1 -1
- package/src/IndexerState.res +10 -11
- package/src/IndexerState.res.mjs +14 -11
- package/src/IndexerState.resi +2 -5
- package/src/IndexingAddresses.res +108 -0
- package/src/IndexingAddresses.res.mjs +101 -0
- package/src/IndexingAddresses.resi +34 -0
- package/src/Internal.res +155 -46
- package/src/Internal.res.mjs +30 -2
- package/src/LoadLayer.res +5 -5
- package/src/LoadLayer.res.mjs +6 -6
- package/src/LogSelection.res +102 -165
- package/src/LogSelection.res.mjs +101 -116
- 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 -74
- package/src/Prometheus.res.mjs +124 -186
- 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 +91 -23
- package/src/SimulateItems.res.mjs +55 -32
- package/src/TestIndexer.res +54 -40
- package/src/TestIndexer.res.mjs +37 -30
- 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 -41
- 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 +36 -33
- package/src/sources/EventRouter.res.mjs +13 -14
- package/src/sources/Evm.res +83 -72
- package/src/sources/Evm.res.mjs +53 -69
- package/src/sources/EvmChain.res +18 -20
- package/src/sources/EvmChain.res.mjs +15 -15
- package/src/sources/EvmRpcClient.res +74 -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 +39 -7
- package/src/sources/HyperSync.res.mjs +57 -37
- package/src/sources/HyperSync.resi +12 -2
- package/src/sources/HyperSyncClient.res +22 -111
- package/src/sources/HyperSyncClient.res.mjs +2 -30
- package/src/sources/HyperSyncHeightStream.res +1 -8
- package/src/sources/HyperSyncHeightStream.res.mjs +0 -2
- package/src/sources/HyperSyncSource.res +94 -107
- package/src/sources/HyperSyncSource.res.mjs +82 -86
- package/src/sources/Rpc.res +15 -47
- package/src/sources/Rpc.res.mjs +25 -56
- package/src/sources/RpcSource.res +320 -467
- package/src/sources/RpcSource.res.mjs +268 -385
- package/src/sources/RpcWebSocketHeightStream.res +0 -5
- package/src/sources/RpcWebSocketHeightStream.res.mjs +0 -2
- package/src/sources/SimulateSource.res +10 -4
- package/src/sources/SimulateSource.res.mjs +16 -6
- package/src/sources/Source.res +34 -6
- package/src/sources/SourceManager.res +86 -27
- package/src/sources/SourceManager.res.mjs +84 -47
- package/src/sources/SourceManager.resi +12 -3
- 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
package/src/ChainState.resi
CHANGED
|
@@ -8,6 +8,7 @@ let configAddresses: Config.chain => array<Internal.indexingAddress>
|
|
|
8
8
|
let make: (
|
|
9
9
|
~chainConfig: Config.chain,
|
|
10
10
|
~fetchState: FetchState.t,
|
|
11
|
+
~indexingAddresses: IndexingAddresses.t,
|
|
11
12
|
~sourceManager: SourceManager.t,
|
|
12
13
|
~reorgDetection: ReorgDetection.t,
|
|
13
14
|
~committedProgressBlockNumber: int,
|
|
@@ -15,13 +16,16 @@ let make: (
|
|
|
15
16
|
~numEventsProcessed: float=?,
|
|
16
17
|
~timestampCaughtUpToHeadOrEndblock: option<Date.t>=?,
|
|
17
18
|
~isProgressAtHead: bool=?,
|
|
19
|
+
~transactionStore: TransactionStore.t=?,
|
|
20
|
+
~chainDensity: option<float>=?,
|
|
21
|
+
~blockStore: BlockStore.t=?,
|
|
18
22
|
~logger: Pino.t,
|
|
19
23
|
) => t
|
|
20
24
|
|
|
21
25
|
let makeFromConfig: (
|
|
22
26
|
Config.chain,
|
|
23
27
|
~config: Config.t,
|
|
24
|
-
~
|
|
28
|
+
~registrationsByChainId: HandlerRegister.registrationsByChainId,
|
|
25
29
|
~knownHeight: int,
|
|
26
30
|
) => t
|
|
27
31
|
|
|
@@ -32,13 +36,12 @@ let makeFromDbState: (
|
|
|
32
36
|
~isInReorgThreshold: bool,
|
|
33
37
|
~isRealtime: bool,
|
|
34
38
|
~config: Config.t,
|
|
35
|
-
~
|
|
39
|
+
~registrationsByChainId: HandlerRegister.registrationsByChainId,
|
|
36
40
|
~reducedPollingInterval: int=?,
|
|
37
41
|
) => t
|
|
38
42
|
|
|
39
43
|
// Accessors.
|
|
40
44
|
let logger: t => Pino.t
|
|
41
|
-
let fetchState: t => FetchState.t
|
|
42
45
|
let sourceManager: t => SourceManager.t
|
|
43
46
|
let chainConfig: t => Config.chain
|
|
44
47
|
let reorgDetection: t => ReorgDetection.t
|
|
@@ -46,14 +49,68 @@ let safeCheckpointTracking: t => option<SafeCheckpointTracking.t>
|
|
|
46
49
|
let isProgressAtHead: t => bool
|
|
47
50
|
let committedProgressBlockNumber: t => int
|
|
48
51
|
let numEventsProcessed: t => float
|
|
52
|
+
let pendingBudget: t => float
|
|
53
|
+
let startFetchingQueries: (t, ~queries: array<FetchState.query>) => unit
|
|
49
54
|
let timestampCaughtUpToHeadOrEndblock: t => option<Date.t>
|
|
50
55
|
|
|
56
|
+
// Fetch-frontier reads.
|
|
57
|
+
let knownHeight: t => int
|
|
58
|
+
let contractAddresses: (t, ~contractName: string) => array<Address.t>
|
|
59
|
+
let bufferSize: t => int
|
|
60
|
+
let bufferReadyCount: t => int
|
|
61
|
+
let getProgressPercentage: t => float
|
|
62
|
+
let chainDensity: t => option<float>
|
|
63
|
+
let effectiveDensity: t => option<float>
|
|
64
|
+
let hasReadyItem: t => bool
|
|
65
|
+
let isReadyToEnterReorgThreshold: t => bool
|
|
66
|
+
|
|
67
|
+
// Fetch control.
|
|
68
|
+
let targetBlock: (t, ~chainTargetItems: float) => int
|
|
69
|
+
let progressAtBlock: (t, ~blockNumber: int) => float
|
|
70
|
+
let blockAtProgress: (t, ~progress: float) => int
|
|
71
|
+
let getNextQuery: (
|
|
72
|
+
t,
|
|
73
|
+
~chainTargetItems: float,
|
|
74
|
+
~chunkItemsMultiplier: float=?,
|
|
75
|
+
~maxTargetBlock: int=?,
|
|
76
|
+
) => FetchState.nextQuery
|
|
77
|
+
let dispatch: (
|
|
78
|
+
t,
|
|
79
|
+
~executeQuery: FetchState.query => promise<unit>,
|
|
80
|
+
~waitForNewBlock: (~knownHeight: int) => promise<int>,
|
|
81
|
+
~onNewBlock: (~knownHeight: int) => unit,
|
|
82
|
+
~action: FetchState.nextQuery,
|
|
83
|
+
~stateId: int,
|
|
84
|
+
) => promise<unit>
|
|
85
|
+
|
|
86
|
+
// Views.
|
|
87
|
+
type chainData = {
|
|
88
|
+
chainId: float,
|
|
89
|
+
poweredByHyperSync: bool,
|
|
90
|
+
firstEventBlockNumber: option<int>,
|
|
91
|
+
latestProcessedBlock: option<int>,
|
|
92
|
+
timestampCaughtUpToHeadOrEndblock: option<Date.t>,
|
|
93
|
+
numEventsProcessed: float,
|
|
94
|
+
latestFetchedBlockNumber: int,
|
|
95
|
+
@as("currentBlockHeight")
|
|
96
|
+
knownHeight: int,
|
|
97
|
+
numBatchesFetched: int,
|
|
98
|
+
startBlock: int,
|
|
99
|
+
endBlock: option<int>,
|
|
100
|
+
numAddresses: int,
|
|
101
|
+
}
|
|
102
|
+
let toChainData: t => chainData
|
|
103
|
+
let toChainMetadata: t => InternalTable.Chains.metaFields
|
|
104
|
+
let toChainBeforeBatch: t => Batch.chainBeforeBatch
|
|
105
|
+
let isReadyToEnterReorgThresholdAfterBatch: (t, ~batch: Batch.t) => bool
|
|
106
|
+
|
|
51
107
|
// Derived (pure).
|
|
52
108
|
let hasProcessedToEndblock: t => bool
|
|
53
109
|
let getHighestBlockBelowThreshold: t => int
|
|
54
110
|
let isActivelyIndexing: t => bool
|
|
55
111
|
let isReady: t => bool
|
|
56
112
|
let isFetchingAtHead: t => bool
|
|
113
|
+
let isAtHeadWithoutEndBlock: t => bool
|
|
57
114
|
|
|
58
115
|
// State transitions. The chain state is mutated only through these.
|
|
59
116
|
let handleQueryResult: (
|
|
@@ -63,7 +120,20 @@ let handleQueryResult: (
|
|
|
63
120
|
~newItemsWithDcs: array<Internal.item>,
|
|
64
121
|
~latestFetchedBlock: FetchState.blockNumberAndTimestamp,
|
|
65
122
|
~knownHeight: int,
|
|
123
|
+
~transactionStore: option<TransactionStore.t>,
|
|
124
|
+
~blockStore: option<BlockStore.t>,
|
|
66
125
|
) => unit
|
|
126
|
+
let materializeBatchItems: (
|
|
127
|
+
t,
|
|
128
|
+
~items: array<Internal.item>,
|
|
129
|
+
~ecosystem: Ecosystem.name,
|
|
130
|
+
) => promise<unit>
|
|
131
|
+
let materializePageItems: (
|
|
132
|
+
~items: array<Internal.item>,
|
|
133
|
+
~transactionStore: option<TransactionStore.t>,
|
|
134
|
+
~blockStore: option<BlockStore.t>,
|
|
135
|
+
~ecosystem: Ecosystem.name,
|
|
136
|
+
) => promise<unit>
|
|
67
137
|
let registerReorgGuard: (
|
|
68
138
|
t,
|
|
69
139
|
~blockHashes: array<ReorgDetection.blockData>,
|
|
@@ -74,7 +144,7 @@ let updateKnownHeight: (t, ~knownHeight: int) => unit
|
|
|
74
144
|
let setEndBlockToFirstEvent: (t, ~blockNumber: int) => unit
|
|
75
145
|
let enterReorgThreshold: t => unit
|
|
76
146
|
let advanceAfterBatch: (t, ~batch: Batch.t, ~enteringReorgThreshold: bool) => unit
|
|
77
|
-
let applyBatchProgress: (t, ~batch: Batch.t) => unit
|
|
147
|
+
let applyBatchProgress: (t, ~batch: Batch.t, ~blockTimestampName: string) => unit
|
|
78
148
|
let markReady: t => unit
|
|
79
149
|
let rollback: (
|
|
80
150
|
t,
|
package/src/Config.res
CHANGED
|
@@ -23,6 +23,7 @@ type evmRpcConfig = {
|
|
|
23
23
|
sourceFor: Source.sourceFor,
|
|
24
24
|
syncConfig: option<sourceSyncOptions>,
|
|
25
25
|
ws: option<string>,
|
|
26
|
+
headers: option<dict<string>>,
|
|
26
27
|
}
|
|
27
28
|
|
|
28
29
|
type sourceConfig =
|
|
@@ -156,6 +157,7 @@ let rpcConfigSchema = S.schema(s =>
|
|
|
156
157
|
"url": s.matches(S.string),
|
|
157
158
|
"for": s.matches(rpcSourceForSchema),
|
|
158
159
|
"ws": s.matches(S.option(S.string)),
|
|
160
|
+
"headers": s.matches(S.option(S.dict(S.string))),
|
|
159
161
|
"initialBlockInterval": s.matches(S.option(S.int)),
|
|
160
162
|
"backoffMultiplicative": s.matches(S.option(S.float)),
|
|
161
163
|
"accelerationAdditive": s.matches(S.option(S.int)),
|
|
@@ -195,9 +197,9 @@ let svmEventDescriptorSchema = S.schema(s =>
|
|
|
195
197
|
{
|
|
196
198
|
"discriminator": s.matches(S.option(S.string)),
|
|
197
199
|
"discriminatorByteLen": s.matches(S.int),
|
|
198
|
-
"
|
|
200
|
+
"transactionFields": s.matches(S.array(Internal.svmTransactionFieldSchema)),
|
|
201
|
+
"blockFields": s.matches(S.option(S.array(Internal.svmBlockFieldSchema))),
|
|
199
202
|
"includeLogs": s.matches(S.bool),
|
|
200
|
-
"includeTokenBalances": s.matches(S.bool),
|
|
201
203
|
"accountFilters": s.matches(
|
|
202
204
|
S.option(
|
|
203
205
|
S.array(
|
|
@@ -653,7 +655,6 @@ let fromPublic = (publicConfigJson: JSON.t) => {
|
|
|
653
655
|
~events: option<array<_>>,
|
|
654
656
|
~abi,
|
|
655
657
|
~chainId: int,
|
|
656
|
-
~startBlock: option<int>,
|
|
657
658
|
~addresses: array<string>,
|
|
658
659
|
~svmDefinedTypes: JSON.t=JSON.Null,
|
|
659
660
|
) => {
|
|
@@ -676,10 +677,6 @@ let fromPublic = (publicConfigJson: JSON.t) => {
|
|
|
676
677
|
~kind=fuelKind,
|
|
677
678
|
~sighash,
|
|
678
679
|
~rawAbi=abi->(Utils.magic: EvmTypes.Abi.t => JSON.t),
|
|
679
|
-
~isWildcard=false,
|
|
680
|
-
~handler=None,
|
|
681
|
-
~contractRegister=None,
|
|
682
|
-
~startBlock?,
|
|
683
680
|
) :> Internal.eventConfig)
|
|
684
681
|
| None =>
|
|
685
682
|
JsError.throwWithMessage(
|
|
@@ -704,9 +701,9 @@ let fromPublic = (publicConfigJson: JSON.t) => {
|
|
|
704
701
|
"svm": option<{
|
|
705
702
|
"discriminator": option<string>,
|
|
706
703
|
"discriminatorByteLen": int,
|
|
707
|
-
"
|
|
704
|
+
"transactionFields": array<Internal.svmTransactionField>,
|
|
705
|
+
"blockFields": option<array<Internal.svmBlockField>>,
|
|
708
706
|
"includeLogs": bool,
|
|
709
|
-
"includeTokenBalances": bool,
|
|
710
707
|
"accountFilters": option<
|
|
711
708
|
array<array<{"position": int, "values": array<string>}>>,
|
|
712
709
|
>,
|
|
@@ -740,18 +737,14 @@ let fromPublic = (publicConfigJson: JSON.t) => {
|
|
|
740
737
|
~programId,
|
|
741
738
|
~discriminator=svm["discriminator"],
|
|
742
739
|
~discriminatorByteLen=svm["discriminatorByteLen"],
|
|
743
|
-
~
|
|
740
|
+
~transactionFields=svm["transactionFields"],
|
|
741
|
+
~blockFields=?svm["blockFields"],
|
|
744
742
|
~includeLogs=svm["includeLogs"],
|
|
745
|
-
~includeTokenBalances=svm["includeTokenBalances"],
|
|
746
743
|
~accountFilters,
|
|
747
744
|
~isInner=svm["isInner"],
|
|
748
|
-
~isWildcard=false,
|
|
749
|
-
~handler=None,
|
|
750
|
-
~contractRegister=None,
|
|
751
745
|
~accounts=svm["accounts"]->Option.getOr([]),
|
|
752
746
|
~args=svm["args"]->Option.getOr(JSON.Null),
|
|
753
747
|
~definedTypes=svmDefinedTypes,
|
|
754
|
-
~startBlock?,
|
|
755
748
|
) :> Internal.eventConfig)
|
|
756
749
|
| _ =>
|
|
757
750
|
(EventConfigBuilder.buildEvmEventConfig(
|
|
@@ -759,15 +752,8 @@ let fromPublic = (publicConfigJson: JSON.t) => {
|
|
|
759
752
|
~eventName,
|
|
760
753
|
~sighash,
|
|
761
754
|
~params,
|
|
762
|
-
~isWildcard=false,
|
|
763
|
-
~handler=None,
|
|
764
|
-
~contractRegister=None,
|
|
765
|
-
~eventFilters=None,
|
|
766
|
-
~probeChainId=chainId,
|
|
767
|
-
~onEventBlockFilterSchema=ecosystem.onEventBlockFilterSchema,
|
|
768
755
|
~blockFields=?eventItem["blockFields"],
|
|
769
756
|
~transactionFields=?eventItem["transactionFields"],
|
|
770
|
-
~startBlock?,
|
|
771
757
|
~globalBlockFieldsSet,
|
|
772
758
|
~globalTransactionFieldsSet,
|
|
773
759
|
) :> Internal.eventConfig)
|
|
@@ -819,17 +805,14 @@ let fromPublic = (publicConfigJson: JSON.t) => {
|
|
|
819
805
|
let addresses = rawAddresses->Array.map(parseAddress)
|
|
820
806
|
let startBlock = chainContract->Option.flatMap(cc => cc["startBlock"])
|
|
821
807
|
|
|
822
|
-
// Build event
|
|
823
|
-
//
|
|
824
|
-
//
|
|
825
|
-
// that branch on `chain.id` are taken through the same path
|
|
826
|
-
// they will follow at runtime.
|
|
808
|
+
// Build event definitions from JSON (field selections resolved
|
|
809
|
+
// inline). Handlers and per-chain `where` filters are layered on
|
|
810
|
+
// later as `onEventRegistration`s in `ChainState.makeInternal`.
|
|
827
811
|
let events = buildContractEvents(
|
|
828
812
|
~contractName=capitalizedName,
|
|
829
813
|
~events=contractData["events"],
|
|
830
814
|
~abi=contractData["abi"],
|
|
831
815
|
~chainId,
|
|
832
|
-
~startBlock,
|
|
833
816
|
~addresses=rawAddresses,
|
|
834
817
|
~svmDefinedTypes=contractData["svmAbi"]
|
|
835
818
|
->Option.map(a => a["definedTypes"])
|
|
@@ -910,6 +893,7 @@ let fromPublic = (publicConfigJson: JSON.t) => {
|
|
|
910
893
|
sourceFor: parseRpcSourceFor(rpcConfig["for"]),
|
|
911
894
|
syncConfig,
|
|
912
895
|
ws: rpcConfig["ws"],
|
|
896
|
+
headers: rpcConfig["headers"],
|
|
913
897
|
}
|
|
914
898
|
})
|
|
915
899
|
EvmSourceConfig({hypersync: publicChainConfig["hypersync"], rpcs})
|
|
@@ -1018,6 +1002,50 @@ let fromPublic = (publicConfigJson: JSON.t) => {
|
|
|
1018
1002
|
}
|
|
1019
1003
|
}
|
|
1020
1004
|
|
|
1005
|
+
// Canonicalize a user-provided address to the configured casing so it matches
|
|
1006
|
+
// addresses parsed from config.yaml during routing. HyperSync/RPC data arrives
|
|
1007
|
+
// already canonical; only user-land input (simulate srcAddress, contractRegister
|
|
1008
|
+
// add) can carry arbitrary casing and needs this before comparison.
|
|
1009
|
+
let normalizeUserAddress = (config: t, address: Address.t): Address.t =>
|
|
1010
|
+
switch config.ecosystem.name {
|
|
1011
|
+
| Ecosystem.Evm =>
|
|
1012
|
+
if config.lowercaseAddresses {
|
|
1013
|
+
address->Address.Evm.fromAddressLowercaseOrThrow
|
|
1014
|
+
} else {
|
|
1015
|
+
address->Address.Evm.fromAddressOrThrow
|
|
1016
|
+
}
|
|
1017
|
+
// TODO: Ideally we should do the same for other ecosystems
|
|
1018
|
+
| Ecosystem.Fuel | Ecosystem.Svm => address
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
// Relaxed counterpart to normalizeUserAddress, used only for simulate srcAddress.
|
|
1022
|
+
// Tests commonly use short placeholder strings like "0xfoo" as a stand-in
|
|
1023
|
+
// identity (e.g. for a wildcard event whose srcAddress doesn't need to resolve
|
|
1024
|
+
// to any real contract), so only the "0x" prefix is enforced here. Under
|
|
1025
|
+
// address_format: checksum, a real address is checksummed even if the input
|
|
1026
|
+
// casing doesn't match (getAddress doesn't require the input to already be
|
|
1027
|
+
// checksummed) — a placeholder that isn't valid hex falls back unchanged.
|
|
1028
|
+
let normalizeSimulateAddress = (config: t, address: Address.t): Address.t =>
|
|
1029
|
+
switch config.ecosystem.name {
|
|
1030
|
+
| Ecosystem.Evm =>
|
|
1031
|
+
let str = address->Address.toString
|
|
1032
|
+
if !(str->String.startsWith("0x")) {
|
|
1033
|
+
JsError.throwWithMessage(
|
|
1034
|
+
`simulate: srcAddress "${str}" is invalid. Expected a string starting with "0x".`,
|
|
1035
|
+
)
|
|
1036
|
+
}
|
|
1037
|
+
if config.lowercaseAddresses {
|
|
1038
|
+
address->Address.Evm.fromAddressLowercaseOrThrow
|
|
1039
|
+
} else {
|
|
1040
|
+
try {
|
|
1041
|
+
address->Address.Evm.fromAddressOrThrow
|
|
1042
|
+
} catch {
|
|
1043
|
+
| _ => address
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
| Ecosystem.Fuel | Ecosystem.Svm => address
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1021
1049
|
// Look up an event config by (contract, event) name. When `chainId` is given,
|
|
1022
1050
|
// returns that chain's per-chain event config (matters for where-callback
|
|
1023
1051
|
// probe detection, which runs with the chain's real id). Without `chainId`,
|
|
@@ -1259,11 +1287,11 @@ let throwIfIncompatible = (
|
|
|
1259
1287
|
}
|
|
1260
1288
|
}
|
|
1261
1289
|
|
|
1262
|
-
// The returned value is a pure function of the JSON
|
|
1263
|
-
//
|
|
1264
|
-
// `
|
|
1265
|
-
// memoize without invalidation.
|
|
1266
|
-
let
|
|
1290
|
+
// The returned value is a pure function of the JSON: it holds only event
|
|
1291
|
+
// definitions, never handler/contractRegister/where state (that's layered on
|
|
1292
|
+
// separately as `HandlerRegister.registrationsByChainId`). That purity is
|
|
1293
|
+
// what lets this memoize without invalidation.
|
|
1294
|
+
let load = () =>
|
|
1267
1295
|
switch cached.contents {
|
|
1268
1296
|
| Some(c) => c
|
|
1269
1297
|
| None => {
|
package/src/Config.res.mjs
CHANGED
|
@@ -81,6 +81,7 @@ let rpcConfigSchema = S$RescriptSchema.schema(s => ({
|
|
|
81
81
|
url: s.m(S$RescriptSchema.string),
|
|
82
82
|
for: s.m(rpcSourceForSchema),
|
|
83
83
|
ws: s.m(S$RescriptSchema.option(S$RescriptSchema.string)),
|
|
84
|
+
headers: s.m(S$RescriptSchema.option(S$RescriptSchema.dict(S$RescriptSchema.string))),
|
|
84
85
|
initialBlockInterval: s.m(S$RescriptSchema.option(S$RescriptSchema.int)),
|
|
85
86
|
backoffMultiplicative: s.m(S$RescriptSchema.option(S$RescriptSchema.float)),
|
|
86
87
|
accelerationAdditive: s.m(S$RescriptSchema.option(S$RescriptSchema.int)),
|
|
@@ -111,9 +112,9 @@ let publicConfigChainSchema = S$RescriptSchema.schema(s => ({
|
|
|
111
112
|
let svmEventDescriptorSchema = S$RescriptSchema.schema(s => ({
|
|
112
113
|
discriminator: s.m(S$RescriptSchema.option(S$RescriptSchema.string)),
|
|
113
114
|
discriminatorByteLen: s.m(S$RescriptSchema.int),
|
|
114
|
-
|
|
115
|
+
transactionFields: s.m(S$RescriptSchema.array(Internal.svmTransactionFieldSchema)),
|
|
116
|
+
blockFields: s.m(S$RescriptSchema.option(S$RescriptSchema.array(Internal.svmBlockFieldSchema))),
|
|
115
117
|
includeLogs: s.m(S$RescriptSchema.bool),
|
|
116
|
-
includeTokenBalances: s.m(S$RescriptSchema.bool),
|
|
117
118
|
accountFilters: s.m(S$RescriptSchema.option(S$RescriptSchema.array(S$RescriptSchema.schema(s => ({
|
|
118
119
|
position: s.m(S$RescriptSchema.int),
|
|
119
120
|
values: s.m(S$RescriptSchema.array(S$RescriptSchema.string))
|
|
@@ -490,7 +491,7 @@ function fromPublic(publicConfigJson) {
|
|
|
490
491
|
};
|
|
491
492
|
});
|
|
492
493
|
}
|
|
493
|
-
let buildContractEvents = (contractName, events, abi, chainId,
|
|
494
|
+
let buildContractEvents = (contractName, events, abi, chainId, addresses, svmDefinedTypesOpt) => {
|
|
494
495
|
let svmDefinedTypes = svmDefinedTypesOpt !== undefined ? svmDefinedTypesOpt : null;
|
|
495
496
|
if (events !== undefined) {
|
|
496
497
|
return events.map(eventItem => {
|
|
@@ -500,10 +501,10 @@ function fromPublic(publicConfigJson) {
|
|
|
500
501
|
let kind = eventItem.kind;
|
|
501
502
|
switch (ecosystemName) {
|
|
502
503
|
case "evm" :
|
|
503
|
-
return EventConfigBuilder.buildEvmEventConfig(contractName, eventName, sighash, params,
|
|
504
|
+
return EventConfigBuilder.buildEvmEventConfig(contractName, eventName, sighash, params, eventItem.blockFields, eventItem.transactionFields, Primitive_option.some(globalBlockFieldsSet), Primitive_option.some(globalTransactionFieldsSet));
|
|
504
505
|
case "fuel" :
|
|
505
506
|
if (kind !== undefined) {
|
|
506
|
-
return EventConfigBuilder.buildFuelEventConfig(contractName, eventName, kind, sighash, abi
|
|
507
|
+
return EventConfigBuilder.buildFuelEventConfig(contractName, eventName, kind, sighash, abi);
|
|
507
508
|
} else {
|
|
508
509
|
return Stdlib_JsError.throwWithMessage(`Fuel event ` + contractName + `.` + eventName + ` is missing "kind" in internal config`);
|
|
509
510
|
}
|
|
@@ -518,7 +519,7 @@ function fromPublic(publicConfigJson) {
|
|
|
518
519
|
position: af.position,
|
|
519
520
|
values: af.values
|
|
520
521
|
})));
|
|
521
|
-
return EventConfigBuilder.buildSvmInstructionEventConfig(contractName, eventName, programId, svm.discriminator, svm.discriminatorByteLen, svm.
|
|
522
|
+
return EventConfigBuilder.buildSvmInstructionEventConfig(contractName, eventName, programId, svm.discriminator, svm.discriminatorByteLen, svm.includeLogs, svm.transactionFields, svm.blockFields, accountFilters, svm.isInner, Stdlib_Option.getOr(svm.accounts, []), Stdlib_Option.getOr(svm.args, null), svmDefinedTypes);
|
|
522
523
|
}
|
|
523
524
|
});
|
|
524
525
|
} else {
|
|
@@ -559,7 +560,7 @@ function fromPublic(publicConfigJson) {
|
|
|
559
560
|
let rawAddresses = Stdlib_Option.getOr(Stdlib_Option.flatMap(chainContract, cc => cc.addresses), []);
|
|
560
561
|
let addresses = rawAddresses.map(parseAddress);
|
|
561
562
|
let startBlock = Stdlib_Option.flatMap(chainContract, cc => cc.startBlock);
|
|
562
|
-
let events = buildContractEvents(capitalizedName, contractData.events, contractData.abi, chainId,
|
|
563
|
+
let events = buildContractEvents(capitalizedName, contractData.events, contractData.abi, chainId, rawAddresses, Stdlib_Option.getOr(Stdlib_Option.map(contractData.svmAbi, a => a.definedTypes), null));
|
|
563
564
|
return {
|
|
564
565
|
name: capitalizedName,
|
|
565
566
|
abi: contractData.abi,
|
|
@@ -607,7 +608,8 @@ function fromPublic(publicConfigJson) {
|
|
|
607
608
|
url: rpcConfig.url,
|
|
608
609
|
sourceFor: parseRpcSourceFor(rpcConfig.for),
|
|
609
610
|
syncConfig: syncConfig,
|
|
610
|
-
ws: rpcConfig.ws
|
|
611
|
+
ws: rpcConfig.ws,
|
|
612
|
+
headers: rpcConfig.headers
|
|
611
613
|
};
|
|
612
614
|
});
|
|
613
615
|
sourceConfig = {
|
|
@@ -705,6 +707,42 @@ function fromPublic(publicConfigJson) {
|
|
|
705
707
|
};
|
|
706
708
|
}
|
|
707
709
|
|
|
710
|
+
function normalizeUserAddress(config, address) {
|
|
711
|
+
let match = config.ecosystem.name;
|
|
712
|
+
switch (match) {
|
|
713
|
+
case "evm" :
|
|
714
|
+
if (config.lowercaseAddresses) {
|
|
715
|
+
return Address.Evm.fromAddressLowercaseOrThrow(address);
|
|
716
|
+
} else {
|
|
717
|
+
return Address.Evm.fromAddressOrThrow(address);
|
|
718
|
+
}
|
|
719
|
+
case "fuel" :
|
|
720
|
+
case "svm" :
|
|
721
|
+
return address;
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
function normalizeSimulateAddress(config, address) {
|
|
726
|
+
let match = config.ecosystem.name;
|
|
727
|
+
switch (match) {
|
|
728
|
+
case "evm" :
|
|
729
|
+
if (!address.startsWith("0x")) {
|
|
730
|
+
Stdlib_JsError.throwWithMessage(`simulate: srcAddress "` + address + `" is invalid. Expected a string starting with "0x".`);
|
|
731
|
+
}
|
|
732
|
+
if (config.lowercaseAddresses) {
|
|
733
|
+
return Address.Evm.fromAddressLowercaseOrThrow(address);
|
|
734
|
+
}
|
|
735
|
+
try {
|
|
736
|
+
return Address.Evm.fromAddressOrThrow(address);
|
|
737
|
+
} catch (exn) {
|
|
738
|
+
return address;
|
|
739
|
+
}
|
|
740
|
+
case "fuel" :
|
|
741
|
+
case "svm" :
|
|
742
|
+
return address;
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
|
|
708
746
|
function getEventConfig(config, contractName, eventName, chainId) {
|
|
709
747
|
let chains;
|
|
710
748
|
if (chainId !== undefined) {
|
|
@@ -974,7 +1012,7 @@ function throwIfIncompatible(changedPaths, resetCommand, runCommand, hasClickhou
|
|
|
974
1012
|
Stdlib_JsError.throwWithMessage(`The following config changes are incompatible with the existing indexer data:\n\n` + bullets + `\n\nPick one:\n 1. ` + padTo(option1, col) + `# resume indexing where it left off\n 2. ` + padTo(resetCommand, col) + `# delete all indexed data and start over` + option3);
|
|
975
1013
|
}
|
|
976
1014
|
|
|
977
|
-
function
|
|
1015
|
+
function load() {
|
|
978
1016
|
let c = cached.contents;
|
|
979
1017
|
if (c !== undefined) {
|
|
980
1018
|
return c;
|
|
@@ -1011,6 +1049,8 @@ export {
|
|
|
1011
1049
|
publicConfigStorageSchema,
|
|
1012
1050
|
publicConfigSchema,
|
|
1013
1051
|
fromPublic,
|
|
1052
|
+
normalizeUserAddress,
|
|
1053
|
+
normalizeSimulateAddress,
|
|
1014
1054
|
getEventConfig,
|
|
1015
1055
|
shouldSaveHistory,
|
|
1016
1056
|
shouldPruneHistory,
|
|
@@ -1021,7 +1061,7 @@ export {
|
|
|
1021
1061
|
canonicalJson,
|
|
1022
1062
|
diffPaths,
|
|
1023
1063
|
throwIfIncompatible,
|
|
1024
|
-
|
|
1064
|
+
load,
|
|
1025
1065
|
getPgUserEntities,
|
|
1026
1066
|
}
|
|
1027
1067
|
/* schema Not a pure module */
|
|
@@ -22,18 +22,8 @@ let makeAddFunction = (~params: contractRegisterParams, ~contractName: string):
|
|
|
22
22
|
~logger=Ecosystem.getItemLogger(params.item, ~ecosystem=params.config.ecosystem),
|
|
23
23
|
)
|
|
24
24
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
// so we need to validate and checksum/lowercase the address.
|
|
28
|
-
if params.config.lowercaseAddresses {
|
|
29
|
-
contractAddress->Address.Evm.fromAddressLowercaseOrThrow
|
|
30
|
-
} else {
|
|
31
|
-
contractAddress->Address.Evm.fromAddressOrThrow
|
|
32
|
-
}
|
|
33
|
-
} else {
|
|
34
|
-
// TODO: Ideally we should do the same for other ecosystems
|
|
35
|
-
contractAddress
|
|
36
|
-
}
|
|
25
|
+
// The value is passed from user-land, so validate and checksum/lowercase it.
|
|
26
|
+
let validatedAddress = params.config->Config.normalizeUserAddress(contractAddress)
|
|
37
27
|
|
|
38
28
|
params.onRegister(~item=params.item, ~contractAddress=validatedAddress, ~contractName)
|
|
39
29
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
|
|
3
|
-
import * as
|
|
3
|
+
import * as Config from "./Config.res.mjs";
|
|
4
4
|
import * as ChainMap from "./ChainMap.res.mjs";
|
|
5
5
|
import * as Ecosystem from "./Ecosystem.res.mjs";
|
|
6
6
|
import * as EntityFilter from "./db/EntityFilter.res.mjs";
|
|
@@ -12,9 +12,7 @@ function makeAddFunction(params, contractName) {
|
|
|
12
12
|
if (params.isResolved) {
|
|
13
13
|
ErrorHandling.mkLogAndRaise(Ecosystem.getItemLogger(params.item, params.config.ecosystem), undefined, new Error(`Impossible to access context.chain after the contract register is resolved. Make sure you didn't miss an await in the handler.`));
|
|
14
14
|
}
|
|
15
|
-
let validatedAddress = params.config
|
|
16
|
-
params.config.lowercaseAddresses ? Address.Evm.fromAddressLowercaseOrThrow(contractAddress) : Address.Evm.fromAddressOrThrow(contractAddress)
|
|
17
|
-
) : contractAddress;
|
|
15
|
+
let validatedAddress = Config.normalizeUserAddress(params.config, contractAddress);
|
|
18
16
|
params.onRegister(params.item, validatedAddress, contractName);
|
|
19
17
|
};
|
|
20
18
|
}
|
|
@@ -73,4 +71,4 @@ export {
|
|
|
73
71
|
getContractRegisterContext,
|
|
74
72
|
getContractRegisterArgs,
|
|
75
73
|
}
|
|
76
|
-
/*
|
|
74
|
+
/* Config Not a pure module */
|
package/src/Core.res
CHANGED
|
@@ -6,9 +6,10 @@
|
|
|
6
6
|
// tighter `Null.t` captures the exact boundary shape.
|
|
7
7
|
type evmHypersyncClientCtor
|
|
8
8
|
type evmRpcClientCtor
|
|
9
|
-
type evmDecoderCtor
|
|
10
9
|
type svmHypersyncClientCtor
|
|
11
10
|
type hyperfuelClientCtor
|
|
11
|
+
type transactionStoreCtor
|
|
12
|
+
type blockStoreCtor
|
|
12
13
|
|
|
13
14
|
type addon = {
|
|
14
15
|
getConfigJson: (~configPath: Null.t<string>, ~directory: Null.t<string>) => string,
|
|
@@ -17,12 +18,22 @@ type addon = {
|
|
|
17
18
|
evmHypersyncClient: evmHypersyncClientCtor,
|
|
18
19
|
@as("EvmRpcClient")
|
|
19
20
|
evmRpcClient: evmRpcClientCtor,
|
|
20
|
-
@as("EvmDecoder")
|
|
21
|
-
evmDecoder: evmDecoderCtor,
|
|
22
21
|
@as("SvmHypersyncClient")
|
|
23
22
|
svmHypersyncClient: svmHypersyncClientCtor,
|
|
24
23
|
@as("HyperfuelClient")
|
|
25
24
|
hyperfuelClient: hyperfuelClientCtor,
|
|
25
|
+
@as("TransactionStore")
|
|
26
|
+
transactionStore: transactionStoreCtor,
|
|
27
|
+
@as("BlockStore")
|
|
28
|
+
blockStore: blockStoreCtor,
|
|
29
|
+
// Ordered transaction-field names exposed for the field-code contract test
|
|
30
|
+
// (the ReScript `transactionFields` arrays must match the Rust ordinals).
|
|
31
|
+
evmTransactionFieldNames: unit => array<string>,
|
|
32
|
+
svmTransactionFieldNames: unit => array<string>,
|
|
33
|
+
// Ordered block-field names for the same contract test (`blockFields` arrays
|
|
34
|
+
// must match the Rust ordinals).
|
|
35
|
+
evmBlockFieldNames: unit => array<string>,
|
|
36
|
+
svmBlockFieldNames: unit => array<string>,
|
|
26
37
|
}
|
|
27
38
|
|
|
28
39
|
@module("node:module") external createRequire: string => {..} = "createRequire"
|