envio 3.3.0-alpha.4 → 3.3.0-alpha.6

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.
Files changed (55) hide show
  1. package/evm.schema.json +10 -0
  2. package/package.json +7 -7
  3. package/src/Batch.res.mjs +1 -1
  4. package/src/BatchProcessing.res +5 -0
  5. package/src/BatchProcessing.res.mjs +6 -0
  6. package/src/ChainState.res +41 -7
  7. package/src/ChainState.res.mjs +22 -18
  8. package/src/ChainState.resi +3 -1
  9. package/src/Config.res +3 -0
  10. package/src/Config.res.mjs +3 -1
  11. package/src/Core.res +0 -3
  12. package/src/ExitOnCaughtUp.res +10 -2
  13. package/src/ExitOnCaughtUp.res.mjs +10 -1
  14. package/src/FetchState.res +63 -133
  15. package/src/FetchState.res.mjs +107 -166
  16. package/src/IndexerState.res +4 -0
  17. package/src/IndexerState.res.mjs +8 -1
  18. package/src/IndexerState.resi +1 -0
  19. package/src/IndexingAddresses.res +105 -0
  20. package/src/IndexingAddresses.res.mjs +100 -0
  21. package/src/IndexingAddresses.resi +32 -0
  22. package/src/Main.res +4 -15
  23. package/src/Main.res.mjs +6 -14
  24. package/src/Metrics.res +33 -0
  25. package/src/Metrics.res.mjs +39 -0
  26. package/src/Prometheus.res +2 -20
  27. package/src/Prometheus.res.mjs +83 -95
  28. package/src/SimulateDeadInputTracker.res +85 -0
  29. package/src/SimulateDeadInputTracker.res.mjs +73 -0
  30. package/src/SimulateDeadInputTracker.resi +12 -0
  31. package/src/SimulateItems.res +23 -42
  32. package/src/SimulateItems.res.mjs +12 -30
  33. package/src/TestIndexer.res +3 -27
  34. package/src/TestIndexer.res.mjs +2 -9
  35. package/src/bindings/Viem.res +0 -41
  36. package/src/bindings/Viem.res.mjs +1 -43
  37. package/src/sources/Evm.res +7 -36
  38. package/src/sources/Evm.res.mjs +4 -36
  39. package/src/sources/EvmChain.res +4 -2
  40. package/src/sources/EvmChain.res.mjs +3 -2
  41. package/src/sources/EvmRpcClient.res +36 -5
  42. package/src/sources/EvmRpcClient.res.mjs +7 -4
  43. package/src/sources/HyperSyncClient.res +0 -35
  44. package/src/sources/HyperSyncClient.res.mjs +1 -8
  45. package/src/sources/Rpc.res +15 -47
  46. package/src/sources/Rpc.res.mjs +25 -56
  47. package/src/sources/RpcSource.res +289 -204
  48. package/src/sources/RpcSource.res.mjs +293 -303
  49. package/src/sources/SimulateSource.res +1 -0
  50. package/src/sources/SimulateSource.res.mjs +2 -1
  51. package/src/sources/Source.res +4 -0
  52. package/src/sources/Svm.res +7 -15
  53. package/src/sources/Svm.res.mjs +4 -15
  54. package/src/sources/TransactionStore.res +14 -2
  55. package/src/sources/TransactionStore.res.mjs +10 -2
@@ -165,34 +165,6 @@ function deriveSrcAddress(providedSrcAddress, eventConfig, chainConfig) {
165
165
  }
166
166
  }
167
167
 
168
- function validateSrcAddresses(simulateItems, config, chainConfig, indexingAddresses) {
169
- let known = new Set();
170
- indexingAddresses.forEach(ia => {
171
- known.add(ia.address);
172
- });
173
- simulateItems.forEach(rawJson => {
174
- let match = rawJson.contract;
175
- let match$1 = rawJson.event;
176
- if (match === undefined) {
177
- return;
178
- }
179
- if (match$1 === undefined) {
180
- return;
181
- }
182
- let eventConfig = findEventConfig(config, match, match$1);
183
- if (eventConfig === undefined) {
184
- return;
185
- }
186
- if (eventConfig.isWildcard) {
187
- return;
188
- }
189
- let srcAddress = deriveSrcAddress(rawJson.srcAddress, eventConfig, chainConfig);
190
- if (!known.has(srcAddress)) {
191
- return Stdlib_JsError.throwWithMessage(`simulate: ` + match + `.` + match$1 + ` resolved to address ` + srcAddress + `, which isn't indexed on chain ` + chainConfig.id.toString() + `. ` + (`Provide a "srcAddress" configured or registered for ` + match + ` on this chain, or use a wildcard event.`));
192
- }
193
- });
194
- }
195
-
196
168
  function parse(simulateItems, config, chainConfig) {
197
169
  let chain = ChainMap.Chain.makeUnsafe(chainConfig.id);
198
170
  let chainId = chainConfig.id;
@@ -204,7 +176,8 @@ function parse(simulateItems, config, chainConfig) {
204
176
  contents: 0
205
177
  };
206
178
  let items = [];
207
- simulateItems.forEach(rawJson => {
179
+ let seenCoordinates = {};
180
+ simulateItems.forEach((rawJson, itemIndex) => {
208
181
  let match = rawJson.contract;
209
182
  let match$1 = rawJson.event;
210
183
  if (match === undefined) {
@@ -221,6 +194,9 @@ function parse(simulateItems, config, chainConfig) {
221
194
  let li = rawJson.logIndex;
222
195
  let logIndex;
223
196
  if (li !== undefined) {
197
+ if (li >= currentLogIndex.contents) {
198
+ currentLogIndex.contents = li + 1 | 0;
199
+ }
224
200
  logIndex = li;
225
201
  } else {
226
202
  let li$1 = currentLogIndex.contents;
@@ -272,6 +248,13 @@ function parse(simulateItems, config, chainConfig) {
272
248
  break;
273
249
  }
274
250
  currentBlock.contents = blockNumber;
251
+ let coordinate = blockNumber.toString() + `:` + logIndex.toString();
252
+ let firstIndex = seenCoordinates[coordinate];
253
+ if (firstIndex !== undefined) {
254
+ Stdlib_JsError.throwWithMessage(`simulate: items at index ` + firstIndex.toString() + ` and ` + itemIndex.toString() + ` on chain ` + chainId.toString() + ` both resolve to block ` + blockNumber.toString() + `, logIndex ` + logIndex.toString() + `. Give each item a distinct logIndex (or omit logIndex so they auto-increment).`);
255
+ } else {
256
+ seenCoordinates[coordinate] = itemIndex;
257
+ }
275
258
  items.push({
276
259
  kind: 0,
277
260
  eventConfig: eventConfig,
@@ -360,7 +343,6 @@ export {
360
343
  dummySrcAddress,
361
344
  firstContractAddress,
362
345
  deriveSrcAddress,
363
- validateSrcAddresses,
364
346
  parse,
365
347
  patchConfig,
366
348
  }
@@ -667,11 +667,7 @@ let makeCreateTestIndexer = (~config: Config.t, ~workerPath: string): (
667
667
  Int.compare(aId, bId)
668
668
  })
669
669
 
670
- // Parse and validate the block ranges upfront before starting any
671
- // workers. srcAddress validation can't run here: it depends on which
672
- // events are wildcard, and `config` reflects config.yaml only —
673
- // handler-level `wildcard: true` takes effect only once registrations
674
- // are applied.
670
+ // Parse and validate the block ranges upfront before starting any workers.
675
671
  let chainEntries = sortedChainKeys->Array.map(chainIdStr => {
676
672
  let rawChainConfig = rawChains->Dict.getUnsafe(chainIdStr)
677
673
  let chainId = switch chainIdStr->Int.fromString {
@@ -868,26 +864,6 @@ let initTestWorker = () => {
868
864
  }
869
865
 
870
866
  let patchConfig = (config: Config.t, _registrations) => {
871
- // `config` here has handler registrations applied, so `isWildcard`
872
- // reflects `indexer.onEvent({ wildcard: true })` — which the main thread
873
- // can't see. Validate srcAddresses against it before patching in the
874
- // simulate source.
875
- switch simulate {
876
- | Some(simulateItems) =>
877
- let chainConfig = config.chainMap->ChainMap.get(ChainMap.Chain.makeUnsafe(~chainId))
878
- let indexingAddresses =
879
- initialState.chains
880
- ->Array.find(c => c.id == chainId)
881
- ->Option.mapOr([], c => c.indexingAddresses)
882
- SimulateItems.validateSrcAddresses(
883
- ~simulateItems,
884
- ~config,
885
- ~chainConfig,
886
- ~indexingAddresses,
887
- )
888
- | None => ()
889
- }
890
-
891
867
  let config = SimulateItems.patchConfig(~config, ~processConfig)
892
868
 
893
869
  // In auto-exit mode, set batchSize=1 to process one block checkpoint at a time
@@ -900,8 +876,8 @@ let initTestWorker = () => {
900
876
  Main.start(~persistence, ~isTest=true, ~patchConfig, ~exitAfterFirstEventBlock)
901
877
  ->Promise.catch(exn => {
902
878
  // `Main.start` rejects on any fatal error: a runtime failure arrives wrapped
903
- // in `Main.FatalError` (already logged), a setup throw (e.g. patchConfig's
904
- // srcAddress validation) arrives raw. The parent only learns of failures
879
+ // in `Main.FatalError` (already logged), a setup throw (e.g. an invalid
880
+ // simulate item) arrives raw. The parent only learns of failures
905
881
  // through the worker `error` event, which fires on an *uncaught* exception.
906
882
  // Throwing synchronously in this catch would just reject the catch's own
907
883
  // promise (swallowed by `ignore`); `setImmediate` re-throws outside the
@@ -586,11 +586,9 @@ function initTestWorker() {
586
586
  Process.exit(1);
587
587
  return;
588
588
  }
589
- let initialState = workerData.initialState;
590
589
  let simulate = workerData.simulate;
591
590
  let endBlock = workerData.endBlock;
592
- let chainId = workerData.chainId;
593
- let chainIdStr = chainId.toString();
591
+ let chainIdStr = workerData.chainId.toString();
594
592
  let exitAfterFirstEventBlock = Stdlib_Option.isNone(endBlock);
595
593
  let resolvedChainDict = {};
596
594
  resolvedChainDict["startBlock"] = workerData.startBlock;
@@ -605,7 +603,7 @@ function initTestWorker() {
605
603
  let processConfig = {
606
604
  chains: resolvedChainsDict
607
605
  };
608
- let proxy = TestIndexerProxyStorage.make(parentPort, initialState);
606
+ let proxy = TestIndexerProxyStorage.make(parentPort, workerData.initialState);
609
607
  let storage = TestIndexerProxyStorage.makeStorage(proxy);
610
608
  let config = Config.loadWithoutRegistrations();
611
609
  let persistence = Persistence.make(config.userEntities, config.allEnums, storage);
@@ -615,11 +613,6 @@ function initTestWorker() {
615
613
  Logging.setLogLevel("silent");
616
614
  }
617
615
  let patchConfig = (config, _registrations) => {
618
- if (simulate !== undefined) {
619
- let chainConfig = ChainMap.get(config.chainMap, ChainMap.Chain.makeUnsafe(chainId));
620
- let indexingAddresses = Stdlib_Option.mapOr(initialState.chains.find(c => c.id === chainId), [], c => c.indexingAddresses);
621
- SimulateItems.validateSrcAddresses(simulate, config, chainConfig, indexingAddresses);
622
- }
623
616
  let config$1 = SimulateItems.patchConfig(config, processConfig);
624
617
  if (exitAfterFirstEventBlock) {
625
618
  return {
@@ -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. */
@@ -15,42 +15,13 @@ type payload = {
15
15
  external fromPayload: payload => Internal.eventPayload = "%identity"
16
16
  external toPayload: Internal.eventPayload => payload = "%identity"
17
17
 
18
- // Ordered transaction field names. The index of each is the field code shared
19
- // with the Rust store (`EvmTxField`) keep this order in sync.
20
- let transactionFields = [
21
- "transactionIndex",
22
- "hash",
23
- "from",
24
- "to",
25
- "gas",
26
- "gasPrice",
27
- "maxPriorityFeePerGas",
28
- "maxFeePerGas",
29
- "cumulativeGasUsed",
30
- "effectiveGasPrice",
31
- "gasUsed",
32
- "input",
33
- "nonce",
34
- "value",
35
- "v",
36
- "r",
37
- "s",
38
- "contractAddress",
39
- "logsBloom",
40
- "root",
41
- "status",
42
- "yParity",
43
- "maxFeePerBlobGas",
44
- "blobVersionedHashes",
45
- "type",
46
- "l1Fee",
47
- "l1GasPrice",
48
- "l1GasUsed",
49
- "l1FeeScalar",
50
- "gasUsedForL1",
51
- "accessList",
52
- "authorizationList",
53
- ]
18
+ // Ordered transaction field names, the field codes shared with the Rust store
19
+ // (`EvmTxField`). Derived from the typed field list so the two can't drift;
20
+ // `Internal.allEvmTransactionFields` is pinned to the Rust ordinal order by a test.
21
+ let transactionFields =
22
+ Internal.allEvmTransactionFields->(
23
+ Utils.magic: array<Internal.evmTransactionField> => array<string>
24
+ )
54
25
 
55
26
  // One event's selected transaction fields → store selection bitmask. Computed
56
27
  // per event at config build and cached on the event config.
@@ -1,46 +1,12 @@
1
1
  // Generated by ReScript, PLEASE EDIT WITH CARE
2
2
 
3
3
  import * as Logging from "../Logging.res.mjs";
4
+ import * as Internal from "../Internal.res.mjs";
4
5
  import * as RawEvent from "../RawEvent.res.mjs";
5
6
  import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
6
7
  import * as TransactionStore from "./TransactionStore.res.mjs";
7
8
 
8
- let transactionFields = [
9
- "transactionIndex",
10
- "hash",
11
- "from",
12
- "to",
13
- "gas",
14
- "gasPrice",
15
- "maxPriorityFeePerGas",
16
- "maxFeePerGas",
17
- "cumulativeGasUsed",
18
- "effectiveGasPrice",
19
- "gasUsed",
20
- "input",
21
- "nonce",
22
- "value",
23
- "v",
24
- "r",
25
- "s",
26
- "contractAddress",
27
- "logsBloom",
28
- "root",
29
- "status",
30
- "yParity",
31
- "maxFeePerBlobGas",
32
- "blobVersionedHashes",
33
- "type",
34
- "l1Fee",
35
- "l1GasPrice",
36
- "l1GasUsed",
37
- "l1FeeScalar",
38
- "gasUsedForL1",
39
- "accessList",
40
- "authorizationList"
41
- ];
42
-
43
- let eventTransactionFieldMask = TransactionStore.makeMaskFn(transactionFields);
9
+ let eventTransactionFieldMask = TransactionStore.makeMaskFn(Internal.allEvmTransactionFields);
44
10
 
45
11
  let cleanUpRawEventFieldsInPlace = (fields => {
46
12
  delete fields.hash
@@ -76,6 +42,8 @@ function make(logger) {
76
42
  };
77
43
  }
78
44
 
45
+ let transactionFields = Internal.allEvmTransactionFields;
46
+
79
47
  export {
80
48
  transactionFields,
81
49
  eventTransactionFieldMask,
@@ -3,6 +3,7 @@ type rpc = {
3
3
  sourceFor: Source.sourceFor,
4
4
  syncConfig?: Config.sourceSyncOptions,
5
5
  ws?: string,
6
+ headers?: dict<string>,
6
7
  }
7
8
 
8
9
  let getSyncConfig = (
@@ -31,7 +32,7 @@ let getSyncConfig = (
31
32
  intervalCeiling: Env.Configurable.SyncConfig.intervalCeiling->Option.getOr(
32
33
  intervalCeiling->Option.getOr(10_000),
33
34
  ),
34
- backoffMillis: backoffMillis->Option.getOr(5000),
35
+ backoffMillis: backoffMillis->Option.getOr(2000),
35
36
  queryTimeoutMillis,
36
37
  fallbackStallTimeout: fallbackStallTimeout->Option.getOr(queryTimeoutMillis / 2),
37
38
  pollingInterval: pollingInterval->Option.getOr(1000),
@@ -89,7 +90,7 @@ let makeSources = (
89
90
  ]
90
91
  | _ => []
91
92
  }
92
- rpcs->Array.forEach(({?syncConfig, url, sourceFor, ?ws}) => {
93
+ rpcs->Array.forEach(({?syncConfig, url, sourceFor, ?ws, ?headers}) => {
93
94
  let source = RpcSource.make({
94
95
  chain,
95
96
  sourceFor,
@@ -99,6 +100,7 @@ let makeSources = (
99
100
  allEventParams,
100
101
  lowercaseAddresses,
101
102
  ?ws,
103
+ ?headers,
102
104
  })
103
105
  let _ = sources->Array.push(source)
104
106
  })
@@ -13,7 +13,7 @@ function getSyncConfig(param) {
13
13
  backoffMultiplicative: Stdlib_Option.getOr(Env.Configurable.SyncConfig.backoffMultiplicative, Stdlib_Option.getOr(param.backoffMultiplicative, 0.8)),
14
14
  accelerationAdditive: Stdlib_Option.getOr(Env.Configurable.SyncConfig.accelerationAdditive, Stdlib_Option.getOr(param.accelerationAdditive, 500)),
15
15
  intervalCeiling: Stdlib_Option.getOr(Env.Configurable.SyncConfig.intervalCeiling, Stdlib_Option.getOr(param.intervalCeiling, 10000)),
16
- backoffMillis: Stdlib_Option.getOr(param.backoffMillis, 5000),
16
+ backoffMillis: Stdlib_Option.getOr(param.backoffMillis, 2000),
17
17
  queryTimeoutMillis: queryTimeoutMillis,
18
18
  fallbackStallTimeout: Stdlib_Option.getOr(param.fallbackStallTimeout, queryTimeoutMillis / 2 | 0),
19
19
  pollingInterval: Stdlib_Option.getOr(param.pollingInterval, 1000)
@@ -60,7 +60,8 @@ function makeSources(chain, contracts, hyperSync, rpcs, lowercaseAddresses) {
60
60
  eventRouter: eventRouter,
61
61
  allEventParams: allEventParams,
62
62
  lowercaseAddresses: lowercaseAddresses,
63
- ws: param.ws
63
+ ws: param.ws,
64
+ headers: param.headers
64
65
  });
65
66
  sources.push(source);
66
67
  });
@@ -1,9 +1,34 @@
1
- type cfg = {url: string, httpReqTimeoutMillis?: int}
1
+ type cfg = {url: string, httpReqTimeoutMillis?: int, headers?: dict<string>}
2
2
 
3
- type t = {getHeight: unit => promise<int>}
3
+ // `addresses` omitted matches any address (a wildcard selection). Each `topics`
4
+ // position is `null` (match any) or a list of accepted topic hashes; the
5
+ // single-match case is a one-element list.
6
+ type getLogsParams = {
7
+ fromBlock: int,
8
+ toBlock: int,
9
+ addresses?: array<Address.t>,
10
+ topics: array<Nullable.t<array<string>>>,
11
+ }
12
+
13
+ // Decoded `params` keyed by contract name, matching the HyperSync decoder's
14
+ // shape so the caller routes by address then picks its contract's params.
15
+ type rpcEventItem = {
16
+ log: Rpc.GetLogs.log,
17
+ params: Nullable.t<dict<Internal.eventParams>>,
18
+ }
19
+
20
+ type t = {
21
+ getHeight: unit => promise<int>,
22
+ getLogs: getLogsParams => promise<array<rpcEventItem>>,
23
+ }
4
24
 
5
25
  @send
6
- external classNew: (Core.evmRpcClientCtor, cfg) => t = "new"
26
+ external classNew: (
27
+ Core.evmRpcClientCtor,
28
+ cfg,
29
+ array<HyperSyncClient.Decoder.eventParamsInput>,
30
+ ~checksumAddresses: bool,
31
+ ) => t = "new"
7
32
 
8
33
  // Rust encodes JSON-RPC errors as a JSON payload in the napi error's
9
34
  // message: `{"kind":"JsonRpcError","code":-32005,"message":"..."}`.
@@ -34,9 +59,15 @@ let coerceErrorOrThrow = exn =>
34
59
  | None => exn->throw
35
60
  }
36
61
 
37
- let make = (~url, ~httpReqTimeoutMillis=?) => {
38
- let client = Core.getAddon().evmRpcClient->classNew({url, ?httpReqTimeoutMillis})
62
+ let make = (~url, ~checksumAddresses, ~httpReqTimeoutMillis=?, ~headers=?, ~allEventParams=[]) => {
63
+ let client =
64
+ Core.getAddon().evmRpcClient->classNew(
65
+ {url, ?httpReqTimeoutMillis, ?headers},
66
+ allEventParams,
67
+ ~checksumAddresses,
68
+ )
39
69
  {
40
70
  getHeight: () => client.getHeight()->Promise.catch(coerceErrorOrThrow),
71
+ getLogs: params => client.getLogs(params)->Promise.catch(coerceErrorOrThrow),
41
72
  }
42
73
  }
@@ -46,13 +46,16 @@ function coerceErrorOrThrow(exn) {
46
46
  throw exn;
47
47
  }
48
48
 
49
- function make(url, httpReqTimeoutMillis) {
49
+ function make(url, checksumAddresses, httpReqTimeoutMillis, headers, allEventParamsOpt) {
50
+ let allEventParams = allEventParamsOpt !== undefined ? allEventParamsOpt : [];
50
51
  let client = Core.getAddon().EvmRpcClient.new({
51
52
  url: url,
52
- httpReqTimeoutMillis: httpReqTimeoutMillis
53
- });
53
+ httpReqTimeoutMillis: httpReqTimeoutMillis,
54
+ headers: headers
55
+ }, allEventParams, checksumAddresses);
54
56
  return {
55
- getHeight: () => Stdlib_Promise.$$catch(client.getHeight(), coerceErrorOrThrow)
57
+ getHeight: () => Stdlib_Promise.$$catch(client.getHeight(), coerceErrorOrThrow),
58
+ getLogs: params => Stdlib_Promise.$$catch(client.getLogs(params), coerceErrorOrThrow)
56
59
  };
57
60
  }
58
61
 
@@ -208,22 +208,6 @@ module ResponseTypes = {
208
208
  mixHash?: string,
209
209
  }
210
210
 
211
- type log = {
212
- removed?: bool,
213
- @as("logIndex") index?: int,
214
- transactionIndex?: int,
215
- transactionHash?: string,
216
- blockHash?: string,
217
- blockNumber?: int,
218
- address?: Address.t,
219
- data?: string,
220
- topics?: array<Nullable.t<EvmTypes.Hex.t>>,
221
- }
222
-
223
- // Only the log is needed for decoding; the transaction/block are served from
224
- // the store (event items) or unused (block-hash query).
225
- type event = {log: log}
226
-
227
211
  type rollbackGuard = {
228
212
  blockNumber: int,
229
213
  timestamp: int,
@@ -253,25 +237,6 @@ module Decoder = {
253
237
  contractName: string,
254
238
  params: array<Internal.paramMeta>,
255
239
  }
256
-
257
- // Decoded params keyed by contract name. Contracts that emit the same-signature
258
- // event share one decode but get their own param names, so the caller picks the
259
- // entry for the contract its router resolved the log to.
260
- type tWithParams = {
261
- decodeLogs: array<ResponseTypes.event> => promise<
262
- array<Nullable.t<dict<Internal.eventParams>>>,
263
- >,
264
- }
265
-
266
- @send
267
- external classFromParams: (
268
- Core.evmDecoderCtor,
269
- array<eventParamsInput>,
270
- ~checksumAddresses: bool=?,
271
- ) => tWithParams = "fromParams"
272
-
273
- let fromParams = (eventParams, ~checksumAddresses=?) =>
274
- Core.getAddon().evmDecoder->classFromParams(eventParams, ~checksumAddresses?)
275
240
  }
276
241
 
277
242
  module EventItems = {
@@ -2,7 +2,6 @@
2
2
 
3
3
  import * as Core from "../Core.res.mjs";
4
4
  import * as Utils from "../Utils.res.mjs";
5
- import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
6
5
  import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
7
6
 
8
7
  let serializationFormatSchema = S$RescriptSchema.$$enum([
@@ -37,13 +36,7 @@ let QueryTypes = {
37
36
 
38
37
  let ResponseTypes = {};
39
38
 
40
- function fromParams(eventParams, checksumAddresses) {
41
- return Core.getAddon().EvmDecoder.fromParams(eventParams, checksumAddresses !== undefined ? Primitive_option.valFromOption(checksumAddresses) : undefined);
42
- }
43
-
44
- let Decoder = {
45
- fromParams: fromParams
46
- };
39
+ let Decoder = {};
47
40
 
48
41
  let EventItems = {};
49
42
 
@@ -38,7 +38,21 @@ let jsonRpcFetcher: Rest.ApiFetcher.t = async args => {
38
38
  }
39
39
  }
40
40
 
41
- let makeClient = url => Rest.client(url, ~fetcher=jsonRpcFetcher)
41
+ let makeClient = (url, ~headers=?) => {
42
+ let fetcher: Rest.ApiFetcher.t = switch headers {
43
+ | None => jsonRpcFetcher
44
+ | Some(customHeaders) =>
45
+ async args => {
46
+ let headers = switch args.headers {
47
+ | Some(headers) => headers
48
+ | None => Dict.make()
49
+ }
50
+ customHeaders->Dict.forEachWithKey((value, key) => headers->Dict.set(key, value->Obj.magic))
51
+ await jsonRpcFetcher({...args, headers: Some(headers)})
52
+ }
53
+ }
54
+ Rest.client(url, ~fetcher)
55
+ }
42
56
 
43
57
  type hex = string
44
58
  let makeHexSchema = fromStr =>
@@ -70,13 +84,7 @@ let decimalFloatSchema: S.schema<float> = S.string->S.transform(s => {
70
84
  module GetLogs = {
71
85
  @unboxed
72
86
  type topicFilter = Single(hex) | Multiple(array<hex>) | @as(null) Null
73
- let topicFilterSchema = S.union([
74
- S.literal(Null),
75
- S.schema(s => Multiple(s.matches(S.array(S.string)))),
76
- S.schema(s => Single(s.matches(S.string))),
77
- ])
78
87
  type topicQuery = array<topicFilter>
79
- let topicQuerySchema = S.array(topicFilterSchema)
80
88
 
81
89
  let makeTopicQuery = (~topic0=[], ~topic1=[], ~topic2=[], ~topic3=[]) => {
82
90
  let topics = [topic0, topic1, topic2, topic3]
@@ -106,51 +114,15 @@ module GetLogs = {
106
114
  let mapTopicQuery = ({topic0, topic1, topic2, topic3}: Internal.topicSelection): topicQuery =>
107
115
  makeTopicQuery(~topic0, ~topic1, ~topic2, ~topic3)
108
116
 
109
- type param = {
110
- fromBlock: int,
111
- toBlock: int,
112
- address?: array<Address.t>,
113
- topics: topicQuery,
114
- // blockHash?: string,
115
- }
116
-
117
- let paramsSchema = S.object((s): param => {
118
- fromBlock: s.field("fromBlock", hexIntSchema),
119
- toBlock: s.field("toBlock", hexIntSchema),
120
- address: ?s.field("address", S.option(S.array(Address.schema))),
121
- topics: s.field("topics", topicQuerySchema),
122
- // blockHash: ?s.field("blockHash", S.option(S.string)),
123
- })
124
-
125
- let fullParamsSchema = S.tuple1(paramsSchema)
126
-
127
117
  type log = {
128
118
  address: Address.t,
129
119
  topics: array<hex>,
130
- data: hex,
131
120
  blockNumber: int,
132
121
  transactionHash: hex,
133
122
  transactionIndex: int,
134
123
  blockHash: hex,
135
124
  logIndex: int,
136
- removed: bool,
137
125
  }
138
-
139
- let logSchema = S.object((s): log => {
140
- address: s.field("address", Address.schema),
141
- topics: s.field("topics", S.array(S.string)),
142
- data: s.field("data", S.string),
143
- blockNumber: s.field("blockNumber", hexIntSchema),
144
- transactionHash: s.field("transactionHash", S.string),
145
- transactionIndex: s.field("transactionIndex", hexIntSchema),
146
- blockHash: s.field("blockHash", S.string),
147
- logIndex: s.field("logIndex", hexIntSchema),
148
- removed: s.field("removed", S.bool),
149
- })
150
-
151
- let resultSchema = S.array(logSchema)
152
-
153
- let route = makeRpcRoute("eth_getLogs", fullParamsSchema, resultSchema)
154
126
  }
155
127
 
156
128
  module GetBlockByNumber = {
@@ -230,10 +202,6 @@ module GetTransactionReceipt = {
230
202
  )
231
203
  }
232
204
 
233
- let getLogs = async (~client: Rest.client, ~param: GetLogs.param) => {
234
- await GetLogs.route->Rest.fetch(param, ~client)
235
- }
236
-
237
205
  let getBlock = async (~client: Rest.client, ~blockNumber: int) => {
238
206
  await GetBlockByNumber.route->Rest.fetch(
239
207
  {"blockNumber": blockNumber, "includeTransactions": false},