envio 3.3.0-alpha.1 → 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 +43 -9
- package/src/ChainFetching.res.mjs +34 -15
- package/src/ChainMetadata.res +1 -11
- package/src/ChainMetadata.res.mjs +1 -10
- package/src/ChainState.res +605 -151
- package/src/ChainState.res.mjs +427 -104
- package/src/ChainState.resi +72 -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 +113 -89
- package/src/CrossChainState.res.mjs +64 -60
- 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 +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 +544 -356
- package/src/FetchState.res.mjs +412 -471
- 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/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 +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 -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 +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 +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
package/src/TestIndexer.res
CHANGED
|
@@ -43,6 +43,33 @@ let toIndexingAddress = (dc: InternalTable.EnvioAddresses.t): Internal.indexingA
|
|
|
43
43
|
registrationBlock: dc.registrationBlock,
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
// All indexing addresses (config-seeded + dynamically registered) grouped by
|
|
47
|
+
// chain id string, derived from the envio_addresses entities.
|
|
48
|
+
let getIndexingAddressesByChain = (state: testIndexerState): dict<
|
|
49
|
+
array<Internal.indexingAddress>,
|
|
50
|
+
> => {
|
|
51
|
+
let byChain = Dict.make()
|
|
52
|
+
switch state.entities->Dict.get(InternalTable.EnvioAddresses.name) {
|
|
53
|
+
| Some(dcDict) =>
|
|
54
|
+
dcDict
|
|
55
|
+
->Dict.valuesToArray
|
|
56
|
+
->Array.forEach(entity => {
|
|
57
|
+
let dc = entity->castToEnvioAddresses
|
|
58
|
+
let chainIdStr = dc.chainId->Int.toString
|
|
59
|
+
let contracts = switch byChain->Dict.get(chainIdStr) {
|
|
60
|
+
| Some(arr) => arr
|
|
61
|
+
| None =>
|
|
62
|
+
let arr = []
|
|
63
|
+
byChain->Dict.set(chainIdStr, arr)
|
|
64
|
+
arr
|
|
65
|
+
}
|
|
66
|
+
contracts->Array.push(dc->toIndexingAddress)->ignore
|
|
67
|
+
})
|
|
68
|
+
| None => ()
|
|
69
|
+
}
|
|
70
|
+
byChain
|
|
71
|
+
}
|
|
72
|
+
|
|
46
73
|
let handleLoad = (state: testIndexerState, ~tableName: string, ~filter: EntityFilter.t): JSON.t => {
|
|
47
74
|
// Loads for non-entity tables (e.g. effect caches `envio_effect_<name>`) reach
|
|
48
75
|
// here too. TestIndexer never persists those, so there's nothing to return —
|
|
@@ -566,22 +593,10 @@ let makeCreateTestIndexer = (~config: Config.t, ~workerPath: string): (
|
|
|
566
593
|
`Cannot access ${contract.name}.addresses while indexer.process() is running. ` ++ "Wait for process() to complete before reading contract addresses.",
|
|
567
594
|
)
|
|
568
595
|
}
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
->Dict.valuesToArray
|
|
574
|
-
->Array.forEach(
|
|
575
|
-
entity => {
|
|
576
|
-
let dc = entity->castToEnvioAddresses
|
|
577
|
-
if dc.contractName === contract.name && dc.chainId === chainConfig.id {
|
|
578
|
-
addresses->Array.push(dc->Config.EnvioAddresses.getAddress)->ignore
|
|
579
|
-
}
|
|
580
|
-
},
|
|
581
|
-
)
|
|
582
|
-
| None => ()
|
|
583
|
-
}
|
|
584
|
-
addresses
|
|
596
|
+
getIndexingAddressesByChain(state)
|
|
597
|
+
->Dict.get(chainConfig.id->Int.toString)
|
|
598
|
+
->Option.getOr([])
|
|
599
|
+
->Array.filterMap(ia => ia.contractName === contract.name ? Some(ia.address) : None)
|
|
585
600
|
},
|
|
586
601
|
},
|
|
587
602
|
)
|
|
@@ -652,7 +667,7 @@ let makeCreateTestIndexer = (~config: Config.t, ~workerPath: string): (
|
|
|
652
667
|
Int.compare(aId, bId)
|
|
653
668
|
})
|
|
654
669
|
|
|
655
|
-
// Parse and validate
|
|
670
|
+
// Parse and validate the block ranges upfront before starting any workers.
|
|
656
671
|
let chainEntries = sortedChainKeys->Array.map(chainIdStr => {
|
|
657
672
|
let rawChainConfig = rawChains->Dict.getUnsafe(chainIdStr)
|
|
658
673
|
let chainId = switch chainIdStr->Int.fromString {
|
|
@@ -684,26 +699,9 @@ let makeCreateTestIndexer = (~config: Config.t, ~workerPath: string): (
|
|
|
684
699
|
let chains: dict<chainConfig> = Dict.make()
|
|
685
700
|
chains->Dict.set(chainIdStr, processChainConfig)
|
|
686
701
|
|
|
687
|
-
//
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
| Some(dcDict) =>
|
|
691
|
-
dcDict
|
|
692
|
-
->Dict.valuesToArray
|
|
693
|
-
->Array.forEach(entity => {
|
|
694
|
-
let dc = entity->castToEnvioAddresses
|
|
695
|
-
let dcChainIdStr = dc.chainId->Int.toString
|
|
696
|
-
let contracts = switch indexingAddressesByChain->Dict.get(dcChainIdStr) {
|
|
697
|
-
| Some(arr) => arr
|
|
698
|
-
| None =>
|
|
699
|
-
let arr = []
|
|
700
|
-
indexingAddressesByChain->Dict.set(dcChainIdStr, arr)
|
|
701
|
-
arr
|
|
702
|
-
}
|
|
703
|
-
contracts->Array.push(dc->toIndexingAddress)->ignore
|
|
704
|
-
})
|
|
705
|
-
| None => ()
|
|
706
|
-
}
|
|
702
|
+
// Rebuilt per chain so workers see contracts registered by earlier
|
|
703
|
+
// chains in the same process() call.
|
|
704
|
+
let indexingAddressesByChain = getIndexingAddressesByChain(state)
|
|
707
705
|
|
|
708
706
|
let initialState = makeInitialState(
|
|
709
707
|
~config,
|
|
@@ -852,7 +850,7 @@ let initTestWorker = () => {
|
|
|
852
850
|
// Create proxy storage that communicates with main thread
|
|
853
851
|
let proxy = TestIndexerProxyStorage.make(~parentPort, ~initialState)
|
|
854
852
|
let storage = TestIndexerProxyStorage.makeStorage(proxy)
|
|
855
|
-
let config = Config.
|
|
853
|
+
let config = Config.load()
|
|
856
854
|
let persistence = Persistence.make(
|
|
857
855
|
~userEntities=config.userEntities,
|
|
858
856
|
~allEnums=config.allEnums,
|
|
@@ -865,7 +863,7 @@ let initTestWorker = () => {
|
|
|
865
863
|
| Some(_) => ()
|
|
866
864
|
}
|
|
867
865
|
|
|
868
|
-
let patchConfig = (config, _registrations) => {
|
|
866
|
+
let patchConfig = (config: Config.t, _registrations) => {
|
|
869
867
|
let config = SimulateItems.patchConfig(~config, ~processConfig)
|
|
870
868
|
|
|
871
869
|
// In auto-exit mode, set batchSize=1 to process one block checkpoint at a time
|
|
@@ -875,7 +873,23 @@ let initTestWorker = () => {
|
|
|
875
873
|
config
|
|
876
874
|
}
|
|
877
875
|
}
|
|
878
|
-
Main.start(~persistence, ~isTest=true, ~patchConfig, ~exitAfterFirstEventBlock)
|
|
876
|
+
Main.start(~persistence, ~isTest=true, ~patchConfig, ~exitAfterFirstEventBlock)
|
|
877
|
+
->Promise.catch(exn => {
|
|
878
|
+
// `Main.start` rejects on any fatal error: a runtime failure arrives wrapped
|
|
879
|
+
// in `Main.FatalError` (already logged), a setup throw (e.g. an invalid
|
|
880
|
+
// simulate item) arrives raw. The parent only learns of failures
|
|
881
|
+
// through the worker `error` event, which fires on an *uncaught* exception.
|
|
882
|
+
// Throwing synchronously in this catch would just reject the catch's own
|
|
883
|
+
// promise (swallowed by `ignore`); `setImmediate` re-throws outside the
|
|
884
|
+
// promise chain so it becomes uncaught and reaches the parent.
|
|
885
|
+
let toThrow = switch exn {
|
|
886
|
+
| Main.FatalError(inner) => inner
|
|
887
|
+
| _ => exn->Utils.prettifyExn
|
|
888
|
+
}
|
|
889
|
+
NodeJs.setImmediate(() => throw(toThrow))
|
|
890
|
+
Promise.resolve()
|
|
891
|
+
})
|
|
892
|
+
->ignore
|
|
879
893
|
| None =>
|
|
880
894
|
Logging.error("TestIndexerWorker: No worker data provided")
|
|
881
895
|
NodeJs.process->NodeJs.exitWithCode(Failure)
|
package/src/TestIndexer.res.mjs
CHANGED
|
@@ -12,6 +12,7 @@ import * as Stdlib_Int from "@rescript/runtime/lib/es6/Stdlib_Int.js";
|
|
|
12
12
|
import * as Persistence from "./Persistence.res.mjs";
|
|
13
13
|
import * as Stdlib_Dict from "@rescript/runtime/lib/es6/Stdlib_Dict.js";
|
|
14
14
|
import * as EntityFilter from "./db/EntityFilter.res.mjs";
|
|
15
|
+
import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
|
|
15
16
|
import * as InternalTable from "./db/InternalTable.res.mjs";
|
|
16
17
|
import * as Primitive_int from "@rescript/runtime/lib/es6/Primitive_int.js";
|
|
17
18
|
import * as SimulateItems from "./SimulateItems.res.mjs";
|
|
@@ -32,6 +33,27 @@ function toIndexingAddress(dc) {
|
|
|
32
33
|
};
|
|
33
34
|
}
|
|
34
35
|
|
|
36
|
+
function getIndexingAddressesByChain(state) {
|
|
37
|
+
let byChain = {};
|
|
38
|
+
let dcDict = state.entities[Config.EnvioAddresses.name];
|
|
39
|
+
if (dcDict !== undefined) {
|
|
40
|
+
Object.values(dcDict).forEach(entity => {
|
|
41
|
+
let chainIdStr = entity.chain_id.toString();
|
|
42
|
+
let arr = byChain[chainIdStr];
|
|
43
|
+
let contracts;
|
|
44
|
+
if (arr !== undefined) {
|
|
45
|
+
contracts = arr;
|
|
46
|
+
} else {
|
|
47
|
+
let arr$1 = [];
|
|
48
|
+
byChain[chainIdStr] = arr$1;
|
|
49
|
+
contracts = arr$1;
|
|
50
|
+
}
|
|
51
|
+
contracts.push(toIndexingAddress(entity));
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
return byChain;
|
|
55
|
+
}
|
|
56
|
+
|
|
35
57
|
function handleLoad(state, tableName, filter) {
|
|
36
58
|
let entityConfig = state.entityConfigs[tableName];
|
|
37
59
|
if (entityConfig === undefined) {
|
|
@@ -403,17 +425,11 @@ function makeCreateTestIndexer(config, workerPath) {
|
|
|
403
425
|
if (state.processInProgress) {
|
|
404
426
|
Stdlib_JsError.throwWithMessage(`Cannot access ` + contract.name + `.addresses while indexer.process() is running. ` + "Wait for process() to complete before reading contract addresses.");
|
|
405
427
|
}
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
addresses.push(Config.EnvioAddresses.getAddress(entity));
|
|
412
|
-
return;
|
|
413
|
-
}
|
|
414
|
-
});
|
|
415
|
-
}
|
|
416
|
-
return addresses;
|
|
428
|
+
return Stdlib_Array.filterMap(Stdlib_Option.getOr(getIndexingAddressesByChain(state)[chainConfig.id.toString()], []), ia => {
|
|
429
|
+
if (ia.contractName === contract.name) {
|
|
430
|
+
return Primitive_option.some(ia.address);
|
|
431
|
+
}
|
|
432
|
+
});
|
|
417
433
|
}
|
|
418
434
|
});
|
|
419
435
|
Object.defineProperty(chainObj, contract.name, {
|
|
@@ -484,23 +500,7 @@ function makeCreateTestIndexer(config, workerPath) {
|
|
|
484
500
|
let chainId = param[1];
|
|
485
501
|
let chains = {};
|
|
486
502
|
chains[param[0]] = processChainConfig;
|
|
487
|
-
let indexingAddressesByChain =
|
|
488
|
-
let dcDict = state.entities[Config.EnvioAddresses.name];
|
|
489
|
-
if (dcDict !== undefined) {
|
|
490
|
-
Object.values(dcDict).forEach(entity => {
|
|
491
|
-
let dcChainIdStr = entity.chain_id.toString();
|
|
492
|
-
let arr = indexingAddressesByChain[dcChainIdStr];
|
|
493
|
-
let contracts;
|
|
494
|
-
if (arr !== undefined) {
|
|
495
|
-
contracts = arr;
|
|
496
|
-
} else {
|
|
497
|
-
let arr$1 = [];
|
|
498
|
-
indexingAddressesByChain[dcChainIdStr] = arr$1;
|
|
499
|
-
contracts = arr$1;
|
|
500
|
-
}
|
|
501
|
-
contracts.push(toIndexingAddress(entity));
|
|
502
|
-
});
|
|
503
|
-
}
|
|
503
|
+
let indexingAddressesByChain = getIndexingAddressesByChain(state);
|
|
504
504
|
let initialState = makeInitialState(config, chains, indexingAddressesByChain);
|
|
505
505
|
return new Promise((resolve, reject) => {
|
|
506
506
|
let workerData_startBlock = processChainConfig.startBlock;
|
|
@@ -605,7 +605,7 @@ function initTestWorker() {
|
|
|
605
605
|
};
|
|
606
606
|
let proxy = TestIndexerProxyStorage.make(parentPort, workerData.initialState);
|
|
607
607
|
let storage = TestIndexerProxyStorage.makeStorage(proxy);
|
|
608
|
-
let config = Config.
|
|
608
|
+
let config = Config.load();
|
|
609
609
|
let persistence = Persistence.make(config.userEntities, config.allEnums, storage);
|
|
610
610
|
if (Env.userLogLevel !== undefined) {
|
|
611
611
|
|
|
@@ -640,11 +640,18 @@ function initTestWorker() {
|
|
|
640
640
|
return config$1;
|
|
641
641
|
}
|
|
642
642
|
};
|
|
643
|
-
Main.start(persistence, undefined, true, exitAfterFirstEventBlock, patchConfig)
|
|
643
|
+
Stdlib_Promise.$$catch(Main.start(persistence, undefined, true, exitAfterFirstEventBlock, patchConfig), exn => {
|
|
644
|
+
let toThrow = exn.RE_EXN_ID === Main.FatalError ? exn._1 : Utils.prettifyExn(exn);
|
|
645
|
+
setImmediate(() => {
|
|
646
|
+
throw toThrow;
|
|
647
|
+
});
|
|
648
|
+
return Promise.resolve();
|
|
649
|
+
});
|
|
644
650
|
}
|
|
645
651
|
|
|
646
652
|
export {
|
|
647
653
|
toIndexingAddress,
|
|
654
|
+
getIndexingAddressesByChain,
|
|
648
655
|
handleLoad,
|
|
649
656
|
handleWriteBatch,
|
|
650
657
|
makeInitialState,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
function secondsSince(from) {
|
|
5
|
+
return (performance.now() - from) / 1000;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
function secondsBetween(from, to) {
|
|
9
|
+
return (to - from) / 1000;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function now(prim) {
|
|
13
|
+
return performance.now();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export {
|
|
17
|
+
now,
|
|
18
|
+
secondsSince,
|
|
19
|
+
secondsBetween,
|
|
20
|
+
}
|
|
21
|
+
/* No side effect */
|
package/src/bindings/Viem.res
CHANGED
|
@@ -1,52 +1,11 @@
|
|
|
1
|
-
type eventLog = {
|
|
2
|
-
abi: EvmTypes.Abi.t,
|
|
3
|
-
data: string,
|
|
4
|
-
topics: array<EvmTypes.Hex.t>,
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
type decodedEvent<'a> = {
|
|
8
|
-
eventName: string,
|
|
9
|
-
args: 'a,
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
@module("viem") external decodeEventLogOrThrow: eventLog => decodedEvent<'a> = "decodeEventLog"
|
|
13
|
-
|
|
14
1
|
type hex = EvmTypes.Hex.t
|
|
15
2
|
@module("viem") external toHex: 'a => hex = "toHex"
|
|
16
3
|
@module("viem") external keccak256: hex => hex = "keccak256"
|
|
17
|
-
@module("viem") external keccak256Bytes: Uint8Array.t => hex = "keccak256"
|
|
18
4
|
@module("viem") external pad: hex => hex = "pad"
|
|
19
|
-
@module("viem")
|
|
20
|
-
external encodePacked: (~types: array<string>, ~values: array<'a>) => hex = "encodePacked"
|
|
21
5
|
|
|
22
6
|
type sizeOptions = {size: int}
|
|
23
|
-
@module("viem") external intToHex: (int, ~options: sizeOptions=?) => hex = "numberToHex"
|
|
24
7
|
@module("viem") external bigintToHex: (bigint, ~options: sizeOptions=?) => hex = "numberToHex"
|
|
25
8
|
@module("viem") external stringToHex: (string, ~options: sizeOptions=?) => hex = "stringToHex"
|
|
26
9
|
@module("viem") external boolToHex: (bool, ~options: sizeOptions=?) => hex = "boolToHex"
|
|
27
10
|
@module("viem") external bytesToHex: (Uint8Array.t, ~options: sizeOptions=?) => hex = "bytesToHex"
|
|
28
11
|
@module("viem") external concat: array<hex> => hex = "concat"
|
|
29
|
-
|
|
30
|
-
exception ParseError(exn)
|
|
31
|
-
exception UnknownContractName({contractName: string})
|
|
32
|
-
|
|
33
|
-
let parseLogOrThrow = (
|
|
34
|
-
contractNameAbiMapping: dict<EvmTypes.Abi.t>,
|
|
35
|
-
~contractName,
|
|
36
|
-
~topics,
|
|
37
|
-
~data,
|
|
38
|
-
) => {
|
|
39
|
-
switch contractNameAbiMapping->Utils.Dict.dangerouslyGetNonOption(contractName) {
|
|
40
|
-
| None => throw(UnknownContractName({contractName: contractName}))
|
|
41
|
-
| Some(abi) =>
|
|
42
|
-
let viemLog: eventLog = {
|
|
43
|
-
abi,
|
|
44
|
-
data,
|
|
45
|
-
topics,
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
try viemLog->decodeEventLogOrThrow catch {
|
|
49
|
-
| exn => throw(ParseError(exn))
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}
|
|
@@ -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,10 +85,10 @@ 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
|
|
|
@@ -100,16 +96,16 @@ let getEvmEventId = (~sighash, ~topicCount) => {
|
|
|
100
96
|
sighash ++ "_" ++ topicCount->Int.toString
|
|
101
97
|
}
|
|
102
98
|
|
|
103
|
-
let fromEvmEventModsOrThrow = (events: array<Internal.
|
|
104
|
-
Internal.
|
|
99
|
+
let fromEvmEventModsOrThrow = (events: array<Internal.evmOnEventRegistration>, ~chain): t<
|
|
100
|
+
Internal.evmOnEventRegistration,
|
|
105
101
|
> => {
|
|
106
102
|
let router = empty()
|
|
107
103
|
events->Array.forEach(config => {
|
|
108
104
|
router->addOrThrow(
|
|
109
|
-
config.id,
|
|
105
|
+
config.eventConfig.id,
|
|
110
106
|
config,
|
|
111
|
-
~contractName=config.contractName,
|
|
112
|
-
~eventName=config.name,
|
|
107
|
+
~contractName=config.eventConfig.contractName,
|
|
108
|
+
~eventName=config.eventConfig.name,
|
|
113
109
|
~chain,
|
|
114
110
|
~isWildcard=config.isWildcard,
|
|
115
111
|
)
|
|
@@ -135,21 +131,26 @@ type svmProgramOrdering = {
|
|
|
135
131
|
byteLengthsDesc: array<int>,
|
|
136
132
|
}
|
|
137
133
|
|
|
138
|
-
let fromSvmEventConfigsOrThrow = (events: array<Internal.
|
|
139
|
-
t<Internal.
|
|
134
|
+
let fromSvmEventConfigsOrThrow = (events: array<Internal.svmOnEventRegistration>, ~chain): (
|
|
135
|
+
t<Internal.svmOnEventRegistration>,
|
|
140
136
|
array<svmProgramOrdering>,
|
|
141
137
|
) => {
|
|
142
138
|
let router = empty()
|
|
143
139
|
events->Array.forEach(config => {
|
|
140
|
+
let eventConfig =
|
|
141
|
+
config.eventConfig->(Utils.magic: Internal.eventConfig => Internal.svmInstructionEventConfig)
|
|
144
142
|
// The router tag must include the programId so two programs declaring the
|
|
145
143
|
// same discriminator coexist. The source-side lookup uses the same shape
|
|
146
144
|
// via `getSvmEventId(~programId, ~discriminator)`.
|
|
147
|
-
let routerTag = getSvmEventId(
|
|
145
|
+
let routerTag = getSvmEventId(
|
|
146
|
+
~programId=eventConfig.programId,
|
|
147
|
+
~discriminator=eventConfig.discriminator,
|
|
148
|
+
)
|
|
148
149
|
router->addOrThrow(
|
|
149
150
|
routerTag,
|
|
150
151
|
config,
|
|
151
|
-
~contractName=
|
|
152
|
-
~eventName=
|
|
152
|
+
~contractName=eventConfig.contractName,
|
|
153
|
+
~eventName=eventConfig.name,
|
|
153
154
|
~chain,
|
|
154
155
|
~isWildcard=config.isWildcard,
|
|
155
156
|
)
|
|
@@ -158,7 +159,9 @@ let fromSvmEventConfigsOrThrow = (events: array<Internal.svmInstructionEventConf
|
|
|
158
159
|
// Per-program list of declared discriminator byte lengths, sorted desc.
|
|
159
160
|
let byProgram: dict<Utils.Set.t<int>> = Dict.make()
|
|
160
161
|
events->Array.forEach(config => {
|
|
161
|
-
let
|
|
162
|
+
let eventConfig =
|
|
163
|
+
config.eventConfig->(Utils.magic: Internal.eventConfig => Internal.svmInstructionEventConfig)
|
|
164
|
+
let key = eventConfig.programId->SvmTypes.Pubkey.toString
|
|
162
165
|
let set = switch byProgram->Utils.Dict.dangerouslyGetNonOption(key) {
|
|
163
166
|
| Some(s) => s
|
|
164
167
|
| None =>
|
|
@@ -166,7 +169,7 @@ let fromSvmEventConfigsOrThrow = (events: array<Internal.svmInstructionEventConf
|
|
|
166
169
|
byProgram->Dict.set(key, s)
|
|
167
170
|
s
|
|
168
171
|
}
|
|
169
|
-
let _ = set->Utils.Set.add(
|
|
172
|
+
let _ = set->Utils.Set.add(eventConfig.discriminatorByteLen)
|
|
170
173
|
})
|
|
171
174
|
let ordering =
|
|
172
175
|
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,10 +90,10 @@ 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
|
|
|
@@ -106,7 +103,7 @@ function getEvmEventId(sighash, topicCount) {
|
|
|
106
103
|
|
|
107
104
|
function fromEvmEventModsOrThrow(events, chain) {
|
|
108
105
|
let router = {};
|
|
109
|
-
events.forEach(config => addOrThrow$1(router, config.id, config, config.contractName, config.isWildcard, config.name, chain));
|
|
106
|
+
events.forEach(config => addOrThrow$1(router, config.eventConfig.id, config, config.eventConfig.contractName, config.isWildcard, config.eventConfig.name, chain));
|
|
110
107
|
return router;
|
|
111
108
|
}
|
|
112
109
|
|
|
@@ -121,12 +118,14 @@ function getSvmEventId(programId, discriminator) {
|
|
|
121
118
|
function fromSvmEventConfigsOrThrow(events, chain) {
|
|
122
119
|
let router = {};
|
|
123
120
|
events.forEach(config => {
|
|
124
|
-
let
|
|
125
|
-
|
|
121
|
+
let eventConfig = config.eventConfig;
|
|
122
|
+
let routerTag = getSvmEventId(eventConfig.programId, eventConfig.discriminator);
|
|
123
|
+
addOrThrow$1(router, routerTag, config, eventConfig.contractName, config.isWildcard, eventConfig.name, chain);
|
|
126
124
|
});
|
|
127
125
|
let byProgram = {};
|
|
128
126
|
events.forEach(config => {
|
|
129
|
-
let
|
|
127
|
+
let eventConfig = config.eventConfig;
|
|
128
|
+
let key = eventConfig.programId;
|
|
130
129
|
let s = byProgram[key];
|
|
131
130
|
let set;
|
|
132
131
|
if (s !== undefined) {
|
|
@@ -136,7 +135,7 @@ function fromSvmEventConfigsOrThrow(events, chain) {
|
|
|
136
135
|
byProgram[key] = s$1;
|
|
137
136
|
set = s$1;
|
|
138
137
|
}
|
|
139
|
-
set.add(
|
|
138
|
+
set.add(eventConfig.discriminatorByteLen);
|
|
140
139
|
});
|
|
141
140
|
let ordering = Object.entries(byProgram).map(param => {
|
|
142
141
|
let sorted = Array.from(param[1]).toSorted((a, b) => b - a | 0);
|