envio 3.3.0-alpha.10 → 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/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 +9 -8
- package/src/Batch.res.mjs +1 -1
- package/src/ChainFetching.res +13 -10
- package/src/ChainFetching.res.mjs +3 -4
- package/src/ChainState.res +45 -30
- package/src/ChainState.res.mjs +22 -8
- package/src/ChainState.resi +5 -0
- package/src/Config.res +9 -5
- package/src/Config.res.mjs +2 -2
- package/src/Core.res +20 -0
- package/src/Core.res.mjs +12 -0
- package/src/CrossChainState.res +18 -1
- package/src/CrossChainState.res.mjs +2 -1
- package/src/EventConfigBuilder.res +21 -46
- package/src/EventConfigBuilder.res.mjs +18 -25
- package/src/EventProcessing.res +8 -5
- package/src/EventProcessing.res.mjs +2 -1
- package/src/FetchState.res +344 -263
- package/src/FetchState.res.mjs +209 -131
- package/src/HandlerRegister.res +3 -1
- package/src/HandlerRegister.res.mjs +3 -2
- package/src/Internal.res +11 -2
- package/src/LogSelection.res +0 -62
- package/src/LogSelection.res.mjs +0 -74
- package/src/RawEvent.res +2 -2
- package/src/SimulateDeadInputTracker.res +1 -1
- package/src/SimulateItems.res +38 -6
- package/src/SimulateItems.res.mjs +28 -9
- package/src/TestIndexer.res +2 -2
- package/src/TestIndexer.res.mjs +2 -2
- package/src/TopicFilter.res +1 -25
- package/src/TopicFilter.res.mjs +0 -74
- package/src/bindings/Viem.res +0 -5
- package/src/sources/EventRouter.res +0 -21
- package/src/sources/EventRouter.res.mjs +0 -12
- package/src/sources/EvmChain.res +2 -27
- package/src/sources/EvmChain.res.mjs +2 -23
- package/src/sources/EvmRpcClient.res +12 -15
- package/src/sources/EvmRpcClient.res.mjs +3 -3
- package/src/sources/HyperSync.res +9 -38
- package/src/sources/HyperSync.res.mjs +16 -28
- package/src/sources/HyperSync.resi +2 -2
- package/src/sources/HyperSyncClient.res +88 -11
- package/src/sources/HyperSyncClient.res.mjs +39 -6
- package/src/sources/HyperSyncSource.res +18 -199
- package/src/sources/HyperSyncSource.res.mjs +9 -128
- package/src/sources/Rpc.res +0 -32
- package/src/sources/Rpc.res.mjs +1 -46
- package/src/sources/RpcSource.res +29 -175
- package/src/sources/RpcSource.res.mjs +32 -110
- package/src/sources/SimulateSource.res +37 -19
- package/src/sources/SimulateSource.res.mjs +27 -10
- package/src/sources/SvmHyperSyncSource.res +3 -3
package/src/Core.res.mjs
CHANGED
|
@@ -180,6 +180,17 @@ function getConfigJson(configPath, directory) {
|
|
|
180
180
|
return addon.getConfigJson(Stdlib_Null.fromOption(configPath), Stdlib_Null.fromOption(directory));
|
|
181
181
|
}
|
|
182
182
|
|
|
183
|
+
function parseConfigYaml(schema, env, files, isRescriptOpt, yaml) {
|
|
184
|
+
let isRescript = isRescriptOpt !== undefined ? isRescriptOpt : false;
|
|
185
|
+
let addon = getAddon();
|
|
186
|
+
return addon.parseConfigYaml(yaml, {
|
|
187
|
+
schema: schema,
|
|
188
|
+
env: env,
|
|
189
|
+
files: files,
|
|
190
|
+
isRescript: isRescript
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
|
|
183
194
|
function runCli(args) {
|
|
184
195
|
let addon = getAddon();
|
|
185
196
|
return addon.runCli(args, envioPackageDir);
|
|
@@ -196,6 +207,7 @@ export {
|
|
|
196
207
|
addonRef,
|
|
197
208
|
getAddon,
|
|
198
209
|
getConfigJson,
|
|
210
|
+
parseConfigYaml,
|
|
199
211
|
runCli,
|
|
200
212
|
}
|
|
201
213
|
/* envioPackageDir Not a pure module */
|
package/src/CrossChainState.res
CHANGED
|
@@ -267,7 +267,24 @@ let checkAndFetch = async (
|
|
|
267
267
|
~chunkItemsMultiplier,
|
|
268
268
|
~maxTargetBlock?,
|
|
269
269
|
) {
|
|
270
|
-
|
|
|
270
|
+
| WaitingForNewBlock as action => actionByChain->Utils.Dict.setByInt(chainId, action)
|
|
271
|
+
| NothingToQuery =>
|
|
272
|
+
// A chain below its head that emitted no query this tick — its budget
|
|
273
|
+
// went to more-behind chains, or the cross-chain alignment clamped its
|
|
274
|
+
// range to nothing — and has nothing else to wake it must keep polling
|
|
275
|
+
// for new blocks instead of going silent. NothingToQuery isn't
|
|
276
|
+
// dispatched, so such a chain would never be re-scheduled and its head
|
|
277
|
+
// tracking would freeze (the knownHeight == 0 branch above forces a poll
|
|
278
|
+
// for the same reason). A chain is genuinely idle — and correctly left
|
|
279
|
+
// undispatched — when it is caught up to its head/endblock, still
|
|
280
|
+
// draining in-flight queries, or holding ready items that batch
|
|
281
|
+
// processing will drain and re-schedule from.
|
|
282
|
+
let action =
|
|
283
|
+
cs->ChainState.isFetchingAtHead ||
|
|
284
|
+
cs->ChainState.pendingBudget > 0. ||
|
|
285
|
+
cs->ChainState.bufferReadyCount > 0
|
|
286
|
+
? FetchState.NothingToQuery
|
|
287
|
+
: FetchState.WaitingForNewBlock
|
|
271
288
|
actionByChain->Utils.Dict.setByInt(chainId, action)
|
|
272
289
|
| Ready(queries) => {
|
|
273
290
|
let consumed =
|
|
@@ -163,7 +163,8 @@ async function checkAndFetch(crossChainState, dispatchChain) {
|
|
|
163
163
|
actionByChain[chainId] = action;
|
|
164
164
|
return;
|
|
165
165
|
}
|
|
166
|
-
|
|
166
|
+
let action$1 = ChainState.isFetchingAtHead(cs) || ChainState.pendingBudget(cs) > 0 || ChainState.bufferReadyCount(cs) > 0 ? "NothingToQuery" : "WaitingForNewBlock";
|
|
167
|
+
actionByChain[chainId] = action$1;
|
|
167
168
|
return;
|
|
168
169
|
} else {
|
|
169
170
|
let queries = action._0;
|
|
@@ -236,58 +236,30 @@ let buildSimulateParamsSchema = (params: array<paramMeta>): S.t<Internal.eventPa
|
|
|
236
236
|
|
|
237
237
|
// ============== Build topic filter getters ==============
|
|
238
238
|
|
|
239
|
-
let getTopicEncoder = (abiType: string): (unknown => EvmTypes.Hex.t) =>
|
|
240
|
-
|
|
241
|
-
if abiType->String.endsWith("]") || abiType->String.startsWith("(") {
|
|
242
|
-
TopicFilter.castToHexUnsafe->(Utils.magic: ('a => EvmTypes.Hex.t) => unknown => EvmTypes.Hex.t)
|
|
243
|
-
} else {
|
|
244
|
-
switch abiType {
|
|
245
|
-
| "address" =>
|
|
246
|
-
// Lowercase before encoding so mixed-case (checksummed) user input
|
|
247
|
-
// still matches the lowercase hex topics returned by sources.
|
|
248
|
-
|
|
249
|
-
(
|
|
250
|
-
(value: string) =>
|
|
251
|
-
value->String.toLowerCase->Address.unsafeFromString->TopicFilter.fromAddress
|
|
252
|
-
)->(Utils.magic: (string => EvmTypes.Hex.t) => unknown => EvmTypes.Hex.t)
|
|
253
|
-
|
|
254
|
-
| "bool" =>
|
|
255
|
-
TopicFilter.fromBool->(Utils.magic: (bool => EvmTypes.Hex.t) => unknown => EvmTypes.Hex.t)
|
|
256
|
-
| "string" =>
|
|
257
|
-
TopicFilter.fromDynamicString->(
|
|
258
|
-
Utils.magic: (string => EvmTypes.Hex.t) => unknown => EvmTypes.Hex.t
|
|
259
|
-
)
|
|
260
|
-
|
|
261
|
-
| "bytes" =>
|
|
262
|
-
TopicFilter.fromDynamicBytes->(
|
|
263
|
-
Utils.magic: (string => EvmTypes.Hex.t) => unknown => EvmTypes.Hex.t
|
|
264
|
-
)
|
|
265
|
-
|
|
266
|
-
| t if t->String.startsWith("uint") =>
|
|
267
|
-
TopicFilter.fromBigInt->(Utils.magic: (bigint => EvmTypes.Hex.t) => unknown => EvmTypes.Hex.t)
|
|
268
|
-
| t if t->String.startsWith("int") =>
|
|
269
|
-
TopicFilter.fromSignedBigInt->(
|
|
270
|
-
Utils.magic: (bigint => EvmTypes.Hex.t) => unknown => EvmTypes.Hex.t
|
|
271
|
-
)
|
|
272
|
-
|
|
273
|
-
| t if t->String.startsWith("bytes") =>
|
|
274
|
-
TopicFilter.castToHexUnsafe->(
|
|
275
|
-
Utils.magic: ('a => EvmTypes.Hex.t) => unknown => EvmTypes.Hex.t
|
|
276
|
-
)
|
|
277
|
-
|
|
278
|
-
| other => JsError.throwWithMessage(`Unsupported topic filter ABI type: ${other}`)
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
}
|
|
239
|
+
let getTopicEncoder = (abiType: string): (unknown => EvmTypes.Hex.t) => value =>
|
|
240
|
+
Core.getAddon().encodeIndexedTopic(~abiType, ~value)
|
|
282
241
|
|
|
283
242
|
let buildTopicGetter = (p: paramMeta) => {
|
|
284
243
|
let encoder = getTopicEncoder(p.abiType)
|
|
244
|
+
let isTuple = p.abiType->String.startsWith("(")
|
|
285
245
|
(eventFilter: dict<JSON.t>) =>
|
|
286
246
|
eventFilter
|
|
287
247
|
->Utils.Dict.dangerouslyGetNonOption(p.name)
|
|
288
|
-
->Option.mapOr([], topicFilters =>
|
|
289
|
-
topicFilters->(Utils.magic: JSON.t => unknown)
|
|
290
|
-
|
|
248
|
+
->Option.mapOr([], topicFilters => {
|
|
249
|
+
let raw = topicFilters->(Utils.magic: JSON.t => unknown)
|
|
250
|
+
// A tuple filter value is itself an array, so a directly-passed tuple is
|
|
251
|
+
// indistinguishable from an OR-list by shape alone. A single tuple is
|
|
252
|
+
// the common case, so try it first; when the value doesn't ABI-encode as
|
|
253
|
+
// one tuple it must be an OR-list of tuples.
|
|
254
|
+
if isTuple {
|
|
255
|
+
switch encoder(raw) {
|
|
256
|
+
| encoded => [encoded]
|
|
257
|
+
| exception _ => raw->normalizeOrThrow->Array.map(encoder)
|
|
258
|
+
}
|
|
259
|
+
} else {
|
|
260
|
+
raw->normalizeOrThrow->Array.map(encoder)
|
|
261
|
+
}
|
|
262
|
+
})
|
|
291
263
|
}
|
|
292
264
|
|
|
293
265
|
// ============== Field selection ==============
|
|
@@ -452,6 +424,7 @@ let buildEvmOnEventRegistration = (
|
|
|
452
424
|
}
|
|
453
425
|
|
|
454
426
|
{
|
|
427
|
+
index: -1,
|
|
455
428
|
eventConfig: (eventConfig :> Internal.eventConfig),
|
|
456
429
|
isWildcard,
|
|
457
430
|
handler,
|
|
@@ -536,6 +509,7 @@ let buildSvmOnEventRegistration = (
|
|
|
536
509
|
~contractRegister: option<Internal.contractRegister>,
|
|
537
510
|
~startBlock: option<int>=?,
|
|
538
511
|
): Internal.svmOnEventRegistration => {
|
|
512
|
+
index: -1,
|
|
539
513
|
eventConfig: (eventConfig :> Internal.eventConfig),
|
|
540
514
|
handler,
|
|
541
515
|
contractRegister,
|
|
@@ -613,6 +587,7 @@ let buildFuelOnEventRegistration = (
|
|
|
613
587
|
~contractRegister: option<Internal.contractRegister>,
|
|
614
588
|
~startBlock: option<int>=?,
|
|
615
589
|
): Internal.fuelOnEventRegistration => {
|
|
590
|
+
index: -1,
|
|
616
591
|
eventConfig: (eventConfig :> Internal.eventConfig),
|
|
617
592
|
handler,
|
|
618
593
|
contractRegister,
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
import * as Evm from "./sources/Evm.res.mjs";
|
|
4
4
|
import * as Svm from "./sources/Svm.res.mjs";
|
|
5
|
+
import * as Core from "./Core.res.mjs";
|
|
5
6
|
import * as Utils from "./Utils.res.mjs";
|
|
6
7
|
import * as Address from "./Address.res.mjs";
|
|
7
8
|
import * as FuelSDK from "./sources/FuelSDK.res.mjs";
|
|
8
9
|
import * as Internal from "./Internal.res.mjs";
|
|
9
|
-
import * as TopicFilter from "./TopicFilter.res.mjs";
|
|
10
10
|
import * as LogSelection from "./LogSelection.res.mjs";
|
|
11
11
|
import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
|
|
12
12
|
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
@@ -208,34 +208,24 @@ function buildSimulateParamsSchema(params) {
|
|
|
208
208
|
}
|
|
209
209
|
|
|
210
210
|
function getTopicEncoder(abiType) {
|
|
211
|
-
|
|
212
|
-
return TopicFilter.castToHexUnsafe;
|
|
213
|
-
}
|
|
214
|
-
switch (abiType) {
|
|
215
|
-
case "address" :
|
|
216
|
-
return value => TopicFilter.fromAddress(value.toLowerCase());
|
|
217
|
-
case "bool" :
|
|
218
|
-
return TopicFilter.fromBool;
|
|
219
|
-
case "bytes" :
|
|
220
|
-
return TopicFilter.fromDynamicBytes;
|
|
221
|
-
case "string" :
|
|
222
|
-
return TopicFilter.fromDynamicString;
|
|
223
|
-
default:
|
|
224
|
-
if (abiType.startsWith("uint")) {
|
|
225
|
-
return TopicFilter.fromBigInt;
|
|
226
|
-
} else if (abiType.startsWith("int")) {
|
|
227
|
-
return TopicFilter.fromSignedBigInt;
|
|
228
|
-
} else if (abiType.startsWith("bytes")) {
|
|
229
|
-
return TopicFilter.castToHexUnsafe;
|
|
230
|
-
} else {
|
|
231
|
-
return Stdlib_JsError.throwWithMessage(`Unsupported topic filter ABI type: ` + abiType);
|
|
232
|
-
}
|
|
233
|
-
}
|
|
211
|
+
return value => Core.getAddon().encodeIndexedTopic(abiType, value);
|
|
234
212
|
}
|
|
235
213
|
|
|
236
214
|
function buildTopicGetter(p) {
|
|
237
215
|
let encoder = getTopicEncoder(p.abiType);
|
|
238
|
-
|
|
216
|
+
let isTuple = p.abiType.startsWith("(");
|
|
217
|
+
return eventFilter => Stdlib_Option.mapOr(eventFilter[p.name], [], topicFilters => {
|
|
218
|
+
if (!isTuple) {
|
|
219
|
+
return normalizeOrThrow(topicFilters).map(encoder);
|
|
220
|
+
}
|
|
221
|
+
let encoded;
|
|
222
|
+
try {
|
|
223
|
+
encoded = encoder(topicFilters);
|
|
224
|
+
} catch (exn) {
|
|
225
|
+
return normalizeOrThrow(topicFilters).map(encoder);
|
|
226
|
+
}
|
|
227
|
+
return [encoded];
|
|
228
|
+
});
|
|
239
229
|
}
|
|
240
230
|
|
|
241
231
|
let alwaysIncludedBlockFields = [
|
|
@@ -317,6 +307,7 @@ function buildEvmOnEventRegistration(eventConfig, isWildcard, handler, contractR
|
|
|
317
307
|
let sb = resolvedWhere.startBlock;
|
|
318
308
|
let resolvedStartBlock = sb !== undefined ? sb : startBlock;
|
|
319
309
|
return {
|
|
310
|
+
index: -1,
|
|
320
311
|
eventConfig: eventConfig,
|
|
321
312
|
handler: handler,
|
|
322
313
|
contractRegister: contractRegister,
|
|
@@ -369,6 +360,7 @@ function buildSvmInstructionEventConfig(contractName, instructionName, programId
|
|
|
369
360
|
|
|
370
361
|
function buildSvmOnEventRegistration(eventConfig, isWildcard, handler, contractRegister, startBlock) {
|
|
371
362
|
return {
|
|
363
|
+
index: -1,
|
|
372
364
|
eventConfig: eventConfig,
|
|
373
365
|
handler: handler,
|
|
374
366
|
contractRegister: contractRegister,
|
|
@@ -438,6 +430,7 @@ function buildFuelEventConfig(contractName, eventName, kind, sighash, rawAbi) {
|
|
|
438
430
|
|
|
439
431
|
function buildFuelOnEventRegistration(eventConfig, isWildcard, handler, contractRegister, startBlock) {
|
|
440
432
|
return {
|
|
433
|
+
index: -1,
|
|
441
434
|
eventConfig: eventConfig,
|
|
442
435
|
handler: handler,
|
|
443
436
|
contractRegister: contractRegister,
|
package/src/EventProcessing.res
CHANGED
|
@@ -73,9 +73,10 @@ let runEventHandlerOrThrow = async (
|
|
|
73
73
|
)
|
|
74
74
|
}
|
|
75
75
|
let handlerDuration = timeBeforeHandler->Performance.secondsSince
|
|
76
|
+
let eventConfig = eventItem.onEventRegistration.eventConfig
|
|
76
77
|
Prometheus.ProcessingHandler.increment(
|
|
77
|
-
~contract=
|
|
78
|
-
~event=
|
|
78
|
+
~contract=eventConfig.contractName,
|
|
79
|
+
~event=eventConfig.name,
|
|
79
80
|
~duration=handlerDuration,
|
|
80
81
|
)
|
|
81
82
|
}
|
|
@@ -121,8 +122,8 @@ let runHandlerOrThrow = async (
|
|
|
121
122
|
}),
|
|
122
123
|
)
|
|
123
124
|
}
|
|
124
|
-
| Event(
|
|
125
|
-
switch onEventRegistration.handler {
|
|
125
|
+
| Event(_) =>
|
|
126
|
+
switch (item->Internal.castUnsafeEventItem).onEventRegistration.handler {
|
|
126
127
|
| Some(handler) =>
|
|
127
128
|
await item->runEventHandlerOrThrow(
|
|
128
129
|
~handler,
|
|
@@ -161,7 +162,9 @@ let preloadBatchOrThrow = async (
|
|
|
161
162
|
for idx in 0 to checkpointEventsProcessed - 1 {
|
|
162
163
|
let item = batch.items->Array.getUnsafe(itemIdx.contents + idx)
|
|
163
164
|
switch item {
|
|
164
|
-
| Event(
|
|
165
|
+
| Event(_) =>
|
|
166
|
+
let {handler, eventConfig: {contractName, name: eventName}} =
|
|
167
|
+
(item->Internal.castUnsafeEventItem).onEventRegistration
|
|
165
168
|
switch handler {
|
|
166
169
|
| None => ()
|
|
167
170
|
| Some(handler) =>
|
|
@@ -65,7 +65,8 @@ async function runEventHandlerOrThrow(item, checkpointId, handler, indexerState,
|
|
|
65
65
|
};
|
|
66
66
|
}
|
|
67
67
|
let handlerDuration = Performance.secondsSince(timeBeforeHandler);
|
|
68
|
-
|
|
68
|
+
let eventConfig = item.onEventRegistration.eventConfig;
|
|
69
|
+
return Prometheus.ProcessingHandler.increment(eventConfig.contractName, eventConfig.name, handlerDuration);
|
|
69
70
|
}
|
|
70
71
|
|
|
71
72
|
async function runHandlerOrThrow(item, checkpointId, indexerState, loadManager, persistence, config, chains) {
|