envio 3.0.0-alpha.20 → 3.0.0-alpha.21
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/index.d.ts +114 -33
- package/package.json +11 -6
- package/src/Config.res +142 -157
- package/src/Config.res.mjs +107 -118
- package/src/Env.res +4 -0
- package/src/Env.res.mjs +6 -0
- package/src/Envio.res +57 -0
- package/src/Envio.res.mjs +39 -1
- package/src/EventConfigBuilder.res +408 -0
- package/src/EventConfigBuilder.res.mjs +376 -0
- package/src/GlobalState.res +43 -9
- package/src/GlobalState.res.mjs +118 -10
- package/src/HandlerRegister.res +1 -1
- package/src/HandlerRegister.resi +1 -1
- package/src/Internal.gen.ts +2 -0
- package/src/Internal.res +38 -3
- package/src/Main.res +14 -1
- package/src/Main.res.mjs +10 -8
- package/src/SimulateItems.res +353 -0
- package/src/SimulateItems.res.mjs +335 -0
- package/src/TestIndexer.res +392 -171
- package/src/TestIndexer.res.mjs +285 -114
- package/src/bindings/EventSource.res +3 -1
- package/src/bindings/Vitest.res +3 -1
- package/src/sources/HyperFuelSource.res +2 -0
- package/src/sources/HyperFuelSource.res.mjs +2 -0
- package/src/sources/HyperSync.res +37 -66
- package/src/sources/HyperSync.res.mjs +51 -67
- package/src/sources/HyperSync.resi +2 -4
- package/src/sources/HyperSyncClient.res +28 -1
- package/src/sources/HyperSyncClient.res.mjs +9 -0
- package/src/sources/HyperSyncHeightStream.res +31 -4
- package/src/sources/HyperSyncHeightStream.res.mjs +22 -2
- package/src/sources/HyperSyncSource.res +4 -4
- package/src/sources/HyperSyncSource.res.mjs +4 -2
- package/src/sources/RpcSource.res +132 -22
- package/src/sources/RpcSource.res.mjs +2 -0
- package/src/sources/SimulateSource.res +59 -0
- package/src/sources/SimulateSource.res.mjs +50 -0
- package/src/sources/SourceManager.res +42 -5
- package/src/sources/SourceManager.res.mjs +44 -12
package/index.d.ts
CHANGED
|
@@ -15,6 +15,18 @@ export type {
|
|
|
15
15
|
import type { Address } from "./src/Types.ts";
|
|
16
16
|
export type { EffectCaller, Address } from "./src/Types.ts";
|
|
17
17
|
|
|
18
|
+
export const TestHelpers: {
|
|
19
|
+
Addresses: {
|
|
20
|
+
readonly mockAddresses: readonly [
|
|
21
|
+
Address, Address, Address, Address, Address,
|
|
22
|
+
Address, Address, Address, Address, Address,
|
|
23
|
+
Address, Address, Address, Address, Address,
|
|
24
|
+
Address, Address, Address, Address, Address,
|
|
25
|
+
];
|
|
26
|
+
readonly defaultAddress: Address;
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
|
|
18
30
|
/** Utility type to expand/flatten complex types for better IDE display. */
|
|
19
31
|
export type Prettify<T> = { [K in keyof T]: T[K] } & {};
|
|
20
32
|
|
|
@@ -378,11 +390,11 @@ type SvmChain<Id extends number = number> = {
|
|
|
378
390
|
type IndexerConfigTypes = {
|
|
379
391
|
evm?: {
|
|
380
392
|
chains: Record<string, { id: number }>;
|
|
381
|
-
contracts?: Record<string, {}
|
|
393
|
+
contracts?: Record<string, Record<string, { eventName: string }>>;
|
|
382
394
|
};
|
|
383
395
|
fuel?: {
|
|
384
396
|
chains: Record<string, { id: number }>;
|
|
385
|
-
contracts?: Record<string, {}
|
|
397
|
+
contracts?: Record<string, Record<string, { eventName: string }>>;
|
|
386
398
|
};
|
|
387
399
|
svm?: { chains: Record<string, { id: number }> };
|
|
388
400
|
entities?: Record<string, object>;
|
|
@@ -526,12 +538,74 @@ export type IndexerFromConfig<Config extends IndexerConfigTypes> = Prettify<
|
|
|
526
538
|
|
|
527
539
|
// ============== Test Indexer Types ==============
|
|
528
540
|
|
|
529
|
-
/**
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
541
|
+
/** Simulate item type for EVM ecosystem. */
|
|
542
|
+
type EvmSimulateItem<Config extends IndexerConfigTypes> =
|
|
543
|
+
Config["evm"] extends { contracts: infer Contracts extends Record<string, Record<string, any>> }
|
|
544
|
+
? {
|
|
545
|
+
[C in keyof Contracts]: {
|
|
546
|
+
[E in keyof Contracts[C]]: {
|
|
547
|
+
/** The contract name as defined in config.yaml. */
|
|
548
|
+
contract: C;
|
|
549
|
+
/** The event name as defined in the contract ABI. */
|
|
550
|
+
event: E;
|
|
551
|
+
/** Override the source address. Defaults to the first contract address. */
|
|
552
|
+
srcAddress?: Address;
|
|
553
|
+
/** Override the log index. Auto-increments by default. */
|
|
554
|
+
logIndex?: number;
|
|
555
|
+
/** Override block fields. */
|
|
556
|
+
block?: Partial<Contracts[C][E]["block"]>;
|
|
557
|
+
/** Override transaction fields. */
|
|
558
|
+
transaction?: Partial<Contracts[C][E]["transaction"]>;
|
|
559
|
+
/** Event parameters. Keys match the event's parameter names. */
|
|
560
|
+
params?: Partial<Contracts[C][E]["params"]>;
|
|
561
|
+
};
|
|
562
|
+
}[keyof Contracts[C]];
|
|
563
|
+
}[keyof Contracts]
|
|
564
|
+
: never;
|
|
565
|
+
|
|
566
|
+
/** Simulate item type for Fuel ecosystem. */
|
|
567
|
+
type FuelSimulateItem<Config extends IndexerConfigTypes> =
|
|
568
|
+
Config["fuel"] extends { contracts: infer Contracts extends Record<string, Record<string, any>> }
|
|
569
|
+
? {
|
|
570
|
+
[C in keyof Contracts]: {
|
|
571
|
+
[E in keyof Contracts[C]]: {
|
|
572
|
+
/** The contract name as defined in config.yaml. */
|
|
573
|
+
contract: C;
|
|
574
|
+
/** The event name as defined in the contract ABI. */
|
|
575
|
+
event: E;
|
|
576
|
+
/** Override the source address. Defaults to the first contract address. */
|
|
577
|
+
srcAddress?: Address;
|
|
578
|
+
/** Override the log index. Auto-increments by default. */
|
|
579
|
+
logIndex?: number;
|
|
580
|
+
/** Override block fields. */
|
|
581
|
+
block?: Partial<Contracts[C][E]["block"]>;
|
|
582
|
+
/** Override transaction fields. */
|
|
583
|
+
transaction?: Partial<Contracts[C][E]["transaction"]>;
|
|
584
|
+
/** Event parameters. Keys match the event's parameter names. */
|
|
585
|
+
params: Contracts[C][E]["params"];
|
|
586
|
+
};
|
|
587
|
+
}[keyof Contracts[C]];
|
|
588
|
+
}[keyof Contracts]
|
|
589
|
+
: never;
|
|
590
|
+
|
|
591
|
+
/** Configuration for a single EVM chain in the test indexer. */
|
|
592
|
+
type EvmTestIndexerChainConfig<Config extends IndexerConfigTypes> = {
|
|
593
|
+
/** The block number to start processing from. Defaults to config startBlock or progressBlock+1. */
|
|
594
|
+
startBlock?: number;
|
|
595
|
+
/** The block number to stop processing at. Defaults to max simulate block number when simulate is provided. */
|
|
596
|
+
endBlock?: number;
|
|
597
|
+
/** Simulate items to process instead of fetching from real sources. */
|
|
598
|
+
simulate?: EvmSimulateItem<Config>[];
|
|
599
|
+
};
|
|
600
|
+
|
|
601
|
+
/** Configuration for a single Fuel chain in the test indexer. */
|
|
602
|
+
type FuelTestIndexerChainConfig<Config extends IndexerConfigTypes> = {
|
|
603
|
+
/** The block number to start processing from. Defaults to config startBlock or progressBlock+1. */
|
|
604
|
+
startBlock?: number;
|
|
605
|
+
/** The block number to stop processing at. Defaults to max simulate block height when simulate is provided. */
|
|
606
|
+
endBlock?: number;
|
|
607
|
+
/** Simulate items to process instead of fetching from real sources. */
|
|
608
|
+
simulate?: FuelSimulateItem<Config>[];
|
|
535
609
|
};
|
|
536
610
|
|
|
537
611
|
/** Entity change value containing sets and/or deleted IDs. */
|
|
@@ -555,9 +629,13 @@ type ConfigEntities<Config extends IndexerConfigTypes> =
|
|
|
555
629
|
Config["entities"] extends Record<string, object> ? Config["entities"] : {};
|
|
556
630
|
|
|
557
631
|
/** Entity operations available on test indexer for direct entity manipulation. */
|
|
558
|
-
type
|
|
632
|
+
type TestIndexerEntityOperations<Entity> = {
|
|
559
633
|
/** Get an entity by ID. Returns undefined if not found. */
|
|
560
634
|
readonly get: (id: string) => Promise<Entity | undefined>;
|
|
635
|
+
/** Get an entity by ID or throw if not found. */
|
|
636
|
+
readonly getOrThrow: (id: string, message?: string) => Promise<Entity>;
|
|
637
|
+
/** Get all entities. */
|
|
638
|
+
readonly getAll: () => Promise<Entity[]>;
|
|
561
639
|
/** Set (create or update) an entity. */
|
|
562
640
|
readonly set: (entity: Entity) => void;
|
|
563
641
|
};
|
|
@@ -566,8 +644,6 @@ type EntityOps<Entity> = {
|
|
|
566
644
|
type EntityChange<Config extends IndexerConfigTypes> = {
|
|
567
645
|
/** The block where the changes occurred. */
|
|
568
646
|
readonly block: number;
|
|
569
|
-
/** The block hash (if available). */
|
|
570
|
-
readonly blockHash?: string;
|
|
571
647
|
/** The chain ID. */
|
|
572
648
|
readonly chainId: number;
|
|
573
649
|
/** Number of events processed in this block. */
|
|
@@ -583,34 +659,39 @@ type EntityChange<Config extends IndexerConfigTypes> = {
|
|
|
583
659
|
};
|
|
584
660
|
|
|
585
661
|
|
|
586
|
-
// Helper to extract chain IDs
|
|
587
|
-
type
|
|
588
|
-
|
|
589
|
-
?
|
|
590
|
-
? Chains
|
|
591
|
-
? Chains[keyof Chains]["id"]
|
|
592
|
-
: never
|
|
662
|
+
// Helper to extract chain IDs per ecosystem
|
|
663
|
+
type EvmChainIds<Config extends IndexerConfigTypes> =
|
|
664
|
+
Config["evm"] extends { chains: infer Chains }
|
|
665
|
+
? Chains extends Record<string, { id: number }>
|
|
666
|
+
? Chains[keyof Chains]["id"]
|
|
593
667
|
: never
|
|
594
|
-
:
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
: HasSvm<Config> extends true
|
|
601
|
-
? Config["svm"] extends { chains: infer Chains }
|
|
602
|
-
? Chains extends Record<string, { id: number }>
|
|
603
|
-
? Chains[keyof Chains]["id"]
|
|
604
|
-
: never
|
|
668
|
+
: never;
|
|
669
|
+
|
|
670
|
+
type FuelChainIds<Config extends IndexerConfigTypes> =
|
|
671
|
+
Config["fuel"] extends { chains: infer Chains }
|
|
672
|
+
? Chains extends Record<string, { id: number }>
|
|
673
|
+
? Chains[keyof Chains]["id"]
|
|
605
674
|
: never
|
|
606
675
|
: never;
|
|
607
676
|
|
|
677
|
+
// Per-ecosystem chain config mappings
|
|
678
|
+
type EvmTestChains<Config extends IndexerConfigTypes> =
|
|
679
|
+
HasEvm<Config> extends true
|
|
680
|
+
? { [K in EvmChainIds<Config>]?: EvmTestIndexerChainConfig<Config> }
|
|
681
|
+
: {};
|
|
682
|
+
|
|
683
|
+
type FuelTestChains<Config extends IndexerConfigTypes> =
|
|
684
|
+
HasFuel<Config> extends true
|
|
685
|
+
? { [K in FuelChainIds<Config>]?: FuelTestIndexerChainConfig<Config> }
|
|
686
|
+
: {};
|
|
687
|
+
|
|
608
688
|
/** Process configuration for the test indexer, with chains keyed by chain ID. */
|
|
609
689
|
export type TestIndexerProcessConfig<Config extends IndexerConfigTypes> = {
|
|
610
690
|
/** Chain configurations keyed by chain ID. Each chain specifies start and end blocks. */
|
|
611
|
-
chains:
|
|
612
|
-
|
|
613
|
-
|
|
691
|
+
chains: Prettify<
|
|
692
|
+
EvmTestChains<Config> &
|
|
693
|
+
FuelTestChains<Config>
|
|
694
|
+
>;
|
|
614
695
|
};
|
|
615
696
|
|
|
616
697
|
/**
|
|
@@ -629,7 +710,7 @@ export type TestIndexerFromConfig<Config extends IndexerConfigTypes> = {
|
|
|
629
710
|
? SingleEcosystemChains<Config>
|
|
630
711
|
: MultiEcosystemChains<Config>) & {
|
|
631
712
|
/** Entity operations for direct manipulation outside of handlers. */
|
|
632
|
-
readonly [K in keyof ConfigEntities<Config>]:
|
|
713
|
+
readonly [K in keyof ConfigEntities<Config>]: TestIndexerEntityOperations<
|
|
633
714
|
ConfigEntities<Config>[K]
|
|
634
715
|
>;
|
|
635
716
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "envio",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.21",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "A latency and sync speed optimized, developer friendly blockchain data indexer.",
|
|
6
6
|
"bin": "./bin.mjs",
|
|
@@ -43,7 +43,12 @@
|
|
|
43
43
|
"@clickhouse/client": "1.17.0",
|
|
44
44
|
"@elastic/ecs-pino-format": "1.4.0",
|
|
45
45
|
"@envio-dev/hyperfuel-client": "1.2.2",
|
|
46
|
-
"@envio-dev/hypersync-client": "1.
|
|
46
|
+
"@envio-dev/hypersync-client": "1.3.0",
|
|
47
|
+
"@fuel-ts/crypto": "0.96.1",
|
|
48
|
+
"@fuel-ts/errors": "0.96.1",
|
|
49
|
+
"@fuel-ts/hasher": "0.96.1",
|
|
50
|
+
"@fuel-ts/math": "0.96.1",
|
|
51
|
+
"@fuel-ts/utils": "0.96.1",
|
|
47
52
|
"bignumber.js": "9.3.1",
|
|
48
53
|
"eventsource": "4.1.0",
|
|
49
54
|
"express": "4.19.2",
|
|
@@ -65,9 +70,9 @@
|
|
|
65
70
|
"tsx": "4.21.0"
|
|
66
71
|
},
|
|
67
72
|
"optionalDependencies": {
|
|
68
|
-
"envio-linux-x64": "3.0.0-alpha.
|
|
69
|
-
"envio-linux-arm64": "3.0.0-alpha.
|
|
70
|
-
"envio-darwin-x64": "3.0.0-alpha.
|
|
71
|
-
"envio-darwin-arm64": "3.0.0-alpha.
|
|
73
|
+
"envio-linux-x64": "3.0.0-alpha.21",
|
|
74
|
+
"envio-linux-arm64": "3.0.0-alpha.21",
|
|
75
|
+
"envio-darwin-x64": "3.0.0-alpha.21",
|
|
76
|
+
"envio-darwin-arm64": "3.0.0-alpha.21"
|
|
72
77
|
}
|
|
73
78
|
}
|
package/src/Config.res
CHANGED
|
@@ -21,19 +21,6 @@ type contract = {
|
|
|
21
21
|
eventSignatures: array<string>,
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
type codegenContract = {
|
|
25
|
-
name: string,
|
|
26
|
-
addresses: array<string>,
|
|
27
|
-
events: array<Internal.eventConfig>,
|
|
28
|
-
startBlock: option<int>,
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// Source config is now parsed from internal.config.json and sources are created lazily
|
|
32
|
-
type codegenChain = {
|
|
33
|
-
id: int,
|
|
34
|
-
contracts: array<codegenContract>,
|
|
35
|
-
}
|
|
36
|
-
|
|
37
24
|
// Source config parsed from internal.config.json - sources are created lazily in ChainFetcher
|
|
38
25
|
type evmRpcConfig = {
|
|
39
26
|
url: string,
|
|
@@ -71,7 +58,9 @@ type sourceSync = {
|
|
|
71
58
|
pollingInterval: int,
|
|
72
59
|
}
|
|
73
60
|
|
|
74
|
-
type multichain =
|
|
61
|
+
type multichain = Internal.multichain =
|
|
62
|
+
| @as("ordered") Ordered
|
|
63
|
+
| @as("unordered") Unordered
|
|
75
64
|
|
|
76
65
|
type contractHandler = {
|
|
77
66
|
name: string,
|
|
@@ -185,6 +174,13 @@ let rpcConfigSchema = S.schema(s =>
|
|
|
185
174
|
}
|
|
186
175
|
)
|
|
187
176
|
|
|
177
|
+
let chainContractSchema = S.schema(s =>
|
|
178
|
+
{
|
|
179
|
+
"addresses": s.matches(S.option(S.array(S.string))),
|
|
180
|
+
"startBlock": s.matches(S.option(S.int)),
|
|
181
|
+
}
|
|
182
|
+
)
|
|
183
|
+
|
|
188
184
|
let publicConfigChainSchema = S.schema(s =>
|
|
189
185
|
{
|
|
190
186
|
"id": s.matches(S.int),
|
|
@@ -197,6 +193,8 @@ let publicConfigChainSchema = S.schema(s =>
|
|
|
197
193
|
"rpcs": s.matches(S.option(S.array(rpcConfigSchema))),
|
|
198
194
|
// SVM source config
|
|
199
195
|
"rpc": s.matches(S.option(S.string)),
|
|
196
|
+
// Per-chain contract data (addresses and optional start block)
|
|
197
|
+
"contracts": s.matches(S.option(S.dict(chainContractSchema))),
|
|
200
198
|
}
|
|
201
199
|
)
|
|
202
200
|
|
|
@@ -204,8 +202,11 @@ let contractEventItemSchema = S.schema(s =>
|
|
|
204
202
|
{
|
|
205
203
|
"event": s.matches(S.string),
|
|
206
204
|
"name": s.matches(S.string),
|
|
207
|
-
"
|
|
208
|
-
"
|
|
205
|
+
"sighash": s.matches(S.string),
|
|
206
|
+
"params": s.matches(S.option(S.array(EventConfigBuilder.eventParamSchema))),
|
|
207
|
+
"kind": s.matches(S.option(S.string)),
|
|
208
|
+
"blockFields": s.matches(S.option(S.array(Internal.evmBlockFieldSchema))),
|
|
209
|
+
"transactionFields": s.matches(S.option(S.array(Internal.evmTransactionFieldSchema))),
|
|
209
210
|
}
|
|
210
211
|
)
|
|
211
212
|
|
|
@@ -437,71 +438,7 @@ let publicConfigSchema = S.schema(s =>
|
|
|
437
438
|
}
|
|
438
439
|
)
|
|
439
440
|
|
|
440
|
-
|
|
441
|
-
// they're prepended at runtime so they're always present.
|
|
442
|
-
let alwaysIncludedBlockFields: array<Internal.evmBlockField> = [Number, Timestamp, Hash]
|
|
443
|
-
|
|
444
|
-
// Enrich EVM event configs with field selections from the JSON config.
|
|
445
|
-
// Mutates the event configs in-place to set selectedBlockFields/selectedTransactionFields.
|
|
446
|
-
let enrichEvmFieldSelections = (
|
|
447
|
-
events: array<Internal.eventConfig>,
|
|
448
|
-
~jsonEvents: option<array<_>>,
|
|
449
|
-
~globalBlockFieldsSet: Utils.Set.t<Internal.evmBlockField>,
|
|
450
|
-
~globalTransactionFieldsSet: Utils.Set.t<Internal.evmTransactionField>,
|
|
451
|
-
) => {
|
|
452
|
-
// Build a lookup by event name for events with per-event field overrides
|
|
453
|
-
let fieldsByName: Js.Dict.t<_> = Js.Dict.empty()
|
|
454
|
-
switch jsonEvents {
|
|
455
|
-
| Some(jes) =>
|
|
456
|
-
jes->Array.forEach(je => {
|
|
457
|
-
let name = je["name"]
|
|
458
|
-
if je["blockFields"] != None || je["transactionFields"] != None {
|
|
459
|
-
fieldsByName->Js.Dict.set(name, je)
|
|
460
|
-
}
|
|
461
|
-
})
|
|
462
|
-
| None => ()
|
|
463
|
-
}
|
|
464
|
-
events->Js.Array2.forEachi((event, i) => {
|
|
465
|
-
let evmEvent = event->(Utils.magic: Internal.eventConfig => Internal.evmEventConfig)
|
|
466
|
-
let (selectedBlockFields, selectedTransactionFields) = switch fieldsByName->Js.Dict.get(
|
|
467
|
-
evmEvent.name,
|
|
468
|
-
) {
|
|
469
|
-
| Some(je) => (
|
|
470
|
-
switch je["blockFields"] {
|
|
471
|
-
| Some(fields) =>
|
|
472
|
-
// Prepend always-included block fields for per-event overrides too
|
|
473
|
-
Utils.Set.fromArray(
|
|
474
|
-
Array.concat(
|
|
475
|
-
alwaysIncludedBlockFields,
|
|
476
|
-
fields->(Utils.magic: array<string> => array<Internal.evmBlockField>),
|
|
477
|
-
),
|
|
478
|
-
)
|
|
479
|
-
| None => globalBlockFieldsSet
|
|
480
|
-
},
|
|
481
|
-
switch je["transactionFields"] {
|
|
482
|
-
| Some(fields) =>
|
|
483
|
-
Utils.Set.fromArray(
|
|
484
|
-
fields->(Utils.magic: array<string> => array<Internal.evmTransactionField>),
|
|
485
|
-
)
|
|
486
|
-
| None => globalTransactionFieldsSet
|
|
487
|
-
},
|
|
488
|
-
)
|
|
489
|
-
| None => (globalBlockFieldsSet, globalTransactionFieldsSet)
|
|
490
|
-
}
|
|
491
|
-
events->Js.Array2.unsafe_set(
|
|
492
|
-
i,
|
|
493
|
-
{...evmEvent, selectedBlockFields, selectedTransactionFields}->(
|
|
494
|
-
Utils.magic: Internal.evmEventConfig => Internal.eventConfig
|
|
495
|
-
),
|
|
496
|
-
)
|
|
497
|
-
})
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
let fromPublic = (
|
|
501
|
-
publicConfigJson: Js.Json.t,
|
|
502
|
-
~codegenChains: array<codegenChain>=[],
|
|
503
|
-
~maxAddrInPartition=5000,
|
|
504
|
-
) => {
|
|
441
|
+
let fromPublic = (publicConfigJson: Js.Json.t, ~maxAddrInPartition=5000) => {
|
|
505
442
|
// Parse public config
|
|
506
443
|
let publicConfig = try publicConfigJson->S.parseOrThrow(publicConfigSchema) catch {
|
|
507
444
|
| S.Raised(exn) =>
|
|
@@ -533,7 +470,7 @@ let fromPublic = (
|
|
|
533
470
|
| None => false
|
|
534
471
|
}
|
|
535
472
|
|
|
536
|
-
// Parse ABIs
|
|
473
|
+
// Parse contract configs (ABIs, events, handlers)
|
|
537
474
|
let publicContractsConfig = switch (ecosystemName, publicConfig["evm"], publicConfig["fuel"]) {
|
|
538
475
|
| (Ecosystem.Evm, Some(evm), _) => evm["contracts"]
|
|
539
476
|
| (Ecosystem.Fuel, _, Some(fuel)) => fuel["contracts"]
|
|
@@ -545,19 +482,21 @@ let fromPublic = (
|
|
|
545
482
|
| Some(evm) => (
|
|
546
483
|
Utils.Set.fromArray(
|
|
547
484
|
Array.concat(
|
|
548
|
-
alwaysIncludedBlockFields,
|
|
485
|
+
EventConfigBuilder.alwaysIncludedBlockFields,
|
|
549
486
|
evm["globalBlockFields"]->Option.getWithDefault([]),
|
|
550
487
|
),
|
|
551
488
|
),
|
|
552
489
|
Utils.Set.fromArray(evm["globalTransactionFields"]->Option.getWithDefault([])),
|
|
553
490
|
)
|
|
554
|
-
| None => (Utils.Set.fromArray(alwaysIncludedBlockFields), Utils.Set.make())
|
|
491
|
+
| None => (Utils.Set.fromArray(EventConfigBuilder.alwaysIncludedBlockFields), Utils.Set.make())
|
|
555
492
|
}
|
|
556
493
|
|
|
557
|
-
//
|
|
558
|
-
let
|
|
559
|
-
|
|
560
|
-
|
|
494
|
+
// Build contract data lookup: ABI, event signatures, event configs (keyed by capitalized name)
|
|
495
|
+
let contractDataByName: Js.Dict.t<{
|
|
496
|
+
"abi": EvmTypes.Abi.t,
|
|
497
|
+
"eventSignatures": array<string>,
|
|
498
|
+
"events": option<array<_>>,
|
|
499
|
+
}> = Js.Dict.empty()
|
|
561
500
|
switch publicContractsConfig {
|
|
562
501
|
| Some(contractsDict) =>
|
|
563
502
|
contractsDict
|
|
@@ -569,68 +508,80 @@ let fromPublic = (
|
|
|
569
508
|
| Some(events) => events->Array.map(eventItem => eventItem["event"])
|
|
570
509
|
| None => []
|
|
571
510
|
}
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
}
|
|
511
|
+
contractDataByName->Js.Dict.set(
|
|
512
|
+
capitalizedName,
|
|
513
|
+
{"abi": abi, "eventSignatures": eventSignatures, "events": contractConfig["events"]},
|
|
514
|
+
)
|
|
577
515
|
})
|
|
578
516
|
| None => ()
|
|
579
517
|
}
|
|
580
518
|
|
|
581
|
-
//
|
|
582
|
-
let
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
let
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
519
|
+
// Build event configs for a contract from JSON event items
|
|
520
|
+
let buildContractEvents = (~contractName, ~events: option<array<_>>, ~abi) => {
|
|
521
|
+
switch events {
|
|
522
|
+
| None => []
|
|
523
|
+
| Some(eventItems) =>
|
|
524
|
+
eventItems->Array.map(eventItem => {
|
|
525
|
+
let eventName = eventItem["name"]
|
|
526
|
+
let sighash = eventItem["sighash"]
|
|
527
|
+
let params = eventItem["params"]->Option.getWithDefault([])
|
|
528
|
+
let kind = eventItem["kind"]
|
|
529
|
+
// Get handler registration data
|
|
530
|
+
let isWildcard = HandlerRegister.isWildcard(~contractName, ~eventName)
|
|
531
|
+
let handler = HandlerRegister.getHandler(~contractName, ~eventName)
|
|
532
|
+
let contractRegister = HandlerRegister.getContractRegister(~contractName, ~eventName)
|
|
533
|
+
|
|
534
|
+
switch ecosystemName {
|
|
535
|
+
| Ecosystem.Fuel =>
|
|
536
|
+
switch kind {
|
|
537
|
+
| Some(fuelKind) =>
|
|
538
|
+
(EventConfigBuilder.buildFuelEventConfig(
|
|
539
|
+
~contractName,
|
|
540
|
+
~eventName,
|
|
541
|
+
~kind=fuelKind,
|
|
542
|
+
~sighash,
|
|
543
|
+
~rawAbi=abi->(Utils.magic: EvmTypes.Abi.t => Js.Json.t),
|
|
544
|
+
~isWildcard,
|
|
545
|
+
~handler,
|
|
546
|
+
~contractRegister,
|
|
547
|
+
) :> Internal.eventConfig)
|
|
548
|
+
| None =>
|
|
549
|
+
Js.Exn.raiseError(
|
|
550
|
+
`Fuel event ${contractName}.${eventName} is missing "kind" in internal config`,
|
|
551
|
+
)
|
|
552
|
+
}
|
|
553
|
+
| _ =>
|
|
554
|
+
(EventConfigBuilder.buildEvmEventConfig(
|
|
555
|
+
~contractName,
|
|
556
|
+
~eventName,
|
|
557
|
+
~sighash,
|
|
558
|
+
~params,
|
|
559
|
+
~isWildcard,
|
|
560
|
+
~handler,
|
|
561
|
+
~contractRegister,
|
|
562
|
+
~eventFilters=HandlerRegister.getEventFilters(~contractName, ~eventName),
|
|
563
|
+
~blockFields=?eventItem["blockFields"],
|
|
564
|
+
~transactionFields=?eventItem["transactionFields"],
|
|
613
565
|
~globalBlockFieldsSet,
|
|
614
566
|
~globalTransactionFieldsSet,
|
|
615
|
-
)
|
|
567
|
+
) :> Internal.eventConfig)
|
|
616
568
|
}
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
)
|
|
569
|
+
})
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
// Parse address based on ecosystem and address format
|
|
574
|
+
let parseAddress = addressString => {
|
|
575
|
+
switch ecosystemName {
|
|
576
|
+
| Ecosystem.Evm =>
|
|
577
|
+
if lowercaseAddresses {
|
|
578
|
+
addressString->Address.Evm.fromStringLowercaseOrThrow
|
|
579
|
+
} else {
|
|
580
|
+
addressString->Address.Evm.fromStringOrThrow
|
|
630
581
|
}
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
}
|
|
582
|
+
| Ecosystem.Fuel | Ecosystem.Svm => addressString->Address.unsafeFromString
|
|
583
|
+
}
|
|
584
|
+
}
|
|
634
585
|
|
|
635
586
|
// Helper to convert parsed RPC config to evmRpcConfig
|
|
636
587
|
let parseRpcSourceFor = (sourceFor: rpcSourceFor): Source.sourceFor => {
|
|
@@ -641,25 +592,45 @@ let fromPublic = (
|
|
|
641
592
|
}
|
|
642
593
|
}
|
|
643
594
|
|
|
644
|
-
//
|
|
595
|
+
// Build chains from JSON config (no more codegenChains)
|
|
645
596
|
let chains =
|
|
646
597
|
publicChainsConfig
|
|
647
598
|
->Js.Dict.keys
|
|
648
599
|
->Js.Array2.map(chainName => {
|
|
649
600
|
let publicChainConfig = publicChainsConfig->Js.Dict.unsafeGet(chainName)
|
|
650
601
|
let chainId = publicChainConfig["id"]
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
602
|
+
|
|
603
|
+
// Build contracts for this chain from per-chain contract data + contract configs
|
|
604
|
+
let chainContracts = publicChainConfig["contracts"]->Option.getWithDefault(Js.Dict.empty())
|
|
605
|
+
let contracts =
|
|
606
|
+
contractDataByName
|
|
607
|
+
->Js.Dict.entries
|
|
608
|
+
->Array.map(((capitalizedName, contractData)) => {
|
|
609
|
+
// Get per-chain contract data (addresses, startBlock)
|
|
610
|
+
let chainContract = chainContracts->Js.Dict.get(capitalizedName)
|
|
611
|
+
let addresses =
|
|
612
|
+
chainContract
|
|
613
|
+
->Option.flatMap(cc => cc["addresses"])
|
|
614
|
+
->Option.getWithDefault([])
|
|
615
|
+
->Array.map(parseAddress)
|
|
616
|
+
let startBlock = chainContract->Option.flatMap(cc => cc["startBlock"])
|
|
617
|
+
|
|
618
|
+
// Build event configs from JSON (field selections resolved inline)
|
|
619
|
+
let events = buildContractEvents(
|
|
620
|
+
~contractName=capitalizedName,
|
|
621
|
+
~events=contractData["events"],
|
|
622
|
+
~abi=contractData["abi"],
|
|
623
|
+
)
|
|
624
|
+
|
|
625
|
+
{
|
|
626
|
+
name: capitalizedName,
|
|
627
|
+
abi: contractData["abi"],
|
|
628
|
+
addresses,
|
|
629
|
+
events,
|
|
630
|
+
startBlock,
|
|
631
|
+
eventSignatures: contractData["eventSignatures"],
|
|
632
|
+
}
|
|
633
|
+
})
|
|
663
634
|
|
|
664
635
|
// Build sourceConfig from the parsed chain config
|
|
665
636
|
let sourceConfig = switch ecosystemName {
|
|
@@ -722,7 +693,7 @@ let fromPublic = (
|
|
|
722
693
|
|
|
723
694
|
{
|
|
724
695
|
name: chainName,
|
|
725
|
-
id:
|
|
696
|
+
id: chainId,
|
|
726
697
|
startBlock: publicChainConfig["startBlock"],
|
|
727
698
|
endBlock: ?publicChainConfig["endBlock"],
|
|
728
699
|
maxReorgDepth: switch ecosystemName {
|
|
@@ -731,7 +702,7 @@ let fromPublic = (
|
|
|
731
702
|
| Ecosystem.Fuel | Ecosystem.Svm => 0
|
|
732
703
|
},
|
|
733
704
|
blockLag: publicChainConfig["blockLag"]->Option.getWithDefault(0),
|
|
734
|
-
contracts
|
|
705
|
+
contracts,
|
|
735
706
|
sourceConfig,
|
|
736
707
|
}
|
|
737
708
|
})
|
|
@@ -820,6 +791,20 @@ let fromPublic = (
|
|
|
820
791
|
}
|
|
821
792
|
}
|
|
822
793
|
|
|
794
|
+
let getEventConfig = (config: t, ~contractName, ~eventName) => {
|
|
795
|
+
config.chainMap
|
|
796
|
+
->ChainMap.values
|
|
797
|
+
->Js.Array2.reduce((acc, chain) => {
|
|
798
|
+
switch acc {
|
|
799
|
+
| Some(_) => acc
|
|
800
|
+
| None =>
|
|
801
|
+
chain.contracts
|
|
802
|
+
->Js.Array2.find(c => c.name == contractName)
|
|
803
|
+
->Belt.Option.flatMap(contract => contract.events->Js.Array2.find(e => e.name == eventName))
|
|
804
|
+
}
|
|
805
|
+
}, None)
|
|
806
|
+
}
|
|
807
|
+
|
|
823
808
|
let shouldSaveHistory = (config, ~isInReorgThreshold) =>
|
|
824
809
|
config.shouldSaveFullHistory || (config.shouldRollbackOnReorg && isInReorgThreshold)
|
|
825
810
|
|