envio 3.3.0-alpha.1 → 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.
Files changed (143) hide show
  1. package/evm.schema.json +10 -0
  2. package/index.d.ts +45 -25
  3. package/licenses/CLA.md +35 -0
  4. package/licenses/EULA.md +67 -0
  5. package/licenses/LICENSE.md +45 -0
  6. package/licenses/README.md +35 -0
  7. package/package.json +10 -9
  8. package/src/Address.res +5 -2
  9. package/src/Address.res.mjs +3 -1
  10. package/src/Api.res +1 -1
  11. package/src/Api.res.mjs +1 -1
  12. package/src/Batch.res +0 -6
  13. package/src/Batch.res.mjs +1 -12
  14. package/src/BatchProcessing.res +7 -12
  15. package/src/BatchProcessing.res.mjs +8 -7
  16. package/src/Bin.res +3 -0
  17. package/src/Bin.res.mjs +4 -0
  18. package/src/ChainFetching.res +53 -16
  19. package/src/ChainFetching.res.mjs +37 -19
  20. package/src/ChainMetadata.res +1 -11
  21. package/src/ChainMetadata.res.mjs +1 -10
  22. package/src/ChainState.res +630 -161
  23. package/src/ChainState.res.mjs +438 -101
  24. package/src/ChainState.resi +77 -4
  25. package/src/Config.res +70 -38
  26. package/src/Config.res.mjs +52 -12
  27. package/src/ContractRegisterContext.res +2 -12
  28. package/src/ContractRegisterContext.res.mjs +3 -5
  29. package/src/Core.res +34 -3
  30. package/src/Core.res.mjs +12 -0
  31. package/src/CrossChainState.res +130 -89
  32. package/src/CrossChainState.res.mjs +66 -61
  33. package/src/CrossChainState.resi +1 -1
  34. package/src/Ecosystem.res +5 -6
  35. package/src/Ecosystem.res.mjs +3 -3
  36. package/src/Envio.res +17 -11
  37. package/src/EnvioGlobal.res +53 -0
  38. package/src/EnvioGlobal.res.mjs +31 -0
  39. package/src/EventConfigBuilder.res +191 -127
  40. package/src/EventConfigBuilder.res.mjs +116 -66
  41. package/src/EventProcessing.res +77 -28
  42. package/src/EventProcessing.res.mjs +56 -29
  43. package/src/ExitOnCaughtUp.res +10 -2
  44. package/src/ExitOnCaughtUp.res.mjs +10 -1
  45. package/src/FetchState.res +684 -415
  46. package/src/FetchState.res.mjs +505 -486
  47. package/src/HandlerLoader.res +8 -104
  48. package/src/HandlerLoader.res.mjs +2 -81
  49. package/src/HandlerRegister.res +520 -144
  50. package/src/HandlerRegister.res.mjs +286 -133
  51. package/src/HandlerRegister.resi +24 -8
  52. package/src/IndexerState.res +10 -3
  53. package/src/IndexerState.res.mjs +11 -4
  54. package/src/IndexerState.resi +2 -1
  55. package/src/IndexingAddresses.res +108 -0
  56. package/src/IndexingAddresses.res.mjs +101 -0
  57. package/src/IndexingAddresses.resi +34 -0
  58. package/src/Internal.res +166 -48
  59. package/src/Internal.res.mjs +30 -2
  60. package/src/LoadLayer.res +5 -5
  61. package/src/LoadLayer.res.mjs +6 -6
  62. package/src/LogSelection.res +92 -217
  63. package/src/LogSelection.res.mjs +95 -184
  64. package/src/Main.res +71 -236
  65. package/src/Main.res.mjs +60 -145
  66. package/src/Metrics.res +74 -0
  67. package/src/Metrics.res.mjs +75 -0
  68. package/src/PgStorage.res +4 -4
  69. package/src/PgStorage.res.mjs +5 -5
  70. package/src/Prometheus.res +10 -63
  71. package/src/Prometheus.res.mjs +124 -171
  72. package/src/PruneStaleHistory.res +2 -2
  73. package/src/PruneStaleHistory.res.mjs +3 -3
  74. package/src/RawEvent.res +7 -2
  75. package/src/RawEvent.res.mjs +4 -4
  76. package/src/Rollback.res +3 -3
  77. package/src/Rollback.res.mjs +4 -4
  78. package/src/RollbackCommit.res +4 -1
  79. package/src/RollbackCommit.res.mjs +3 -2
  80. package/src/SimulateDeadInputTracker.res +85 -0
  81. package/src/SimulateDeadInputTracker.res.mjs +73 -0
  82. package/src/SimulateDeadInputTracker.resi +12 -0
  83. package/src/SimulateItems.res +128 -28
  84. package/src/SimulateItems.res.mjs +82 -40
  85. package/src/TestIndexer.res +55 -41
  86. package/src/TestIndexer.res.mjs +39 -32
  87. package/src/TopicFilter.res +1 -25
  88. package/src/TopicFilter.res.mjs +0 -74
  89. package/src/bindings/Performance.res +7 -0
  90. package/src/bindings/Performance.res.mjs +21 -0
  91. package/src/bindings/Performance.resi +7 -0
  92. package/src/bindings/Viem.res +0 -46
  93. package/src/bindings/Viem.res.mjs +1 -43
  94. package/src/sources/BlockStore.res +46 -0
  95. package/src/sources/BlockStore.res.mjs +24 -0
  96. package/src/sources/EventRouter.res +31 -49
  97. package/src/sources/EventRouter.res.mjs +12 -25
  98. package/src/sources/Evm.res +83 -72
  99. package/src/sources/Evm.res.mjs +53 -69
  100. package/src/sources/EvmChain.res +7 -34
  101. package/src/sources/EvmChain.res.mjs +6 -27
  102. package/src/sources/EvmRpcClient.res +71 -5
  103. package/src/sources/EvmRpcClient.res.mjs +13 -4
  104. package/src/sources/FieldMask.res +39 -0
  105. package/src/sources/FieldMask.res.mjs +42 -0
  106. package/src/sources/Fuel.res +9 -6
  107. package/src/sources/Fuel.res.mjs +5 -10
  108. package/src/sources/HyperFuelSource.res +46 -50
  109. package/src/sources/HyperFuelSource.res.mjs +64 -54
  110. package/src/sources/HyperSync.res +45 -42
  111. package/src/sources/HyperSync.res.mjs +68 -60
  112. package/src/sources/HyperSync.resi +14 -4
  113. package/src/sources/HyperSyncClient.res +107 -119
  114. package/src/sources/HyperSyncClient.res.mjs +36 -31
  115. package/src/sources/HyperSyncHeightStream.res +1 -8
  116. package/src/sources/HyperSyncHeightStream.res.mjs +0 -2
  117. package/src/sources/HyperSyncSource.res +60 -254
  118. package/src/sources/HyperSyncSource.res.mjs +57 -180
  119. package/src/sources/Rpc.res +15 -79
  120. package/src/sources/Rpc.res.mjs +25 -101
  121. package/src/sources/RpcSource.res +221 -514
  122. package/src/sources/RpcSource.res.mjs +216 -411
  123. package/src/sources/RpcWebSocketHeightStream.res +0 -5
  124. package/src/sources/RpcWebSocketHeightStream.res.mjs +0 -2
  125. package/src/sources/SimulateSource.res +44 -20
  126. package/src/sources/SimulateSource.res.mjs +41 -14
  127. package/src/sources/Source.res +34 -6
  128. package/src/sources/SourceManager.res +77 -19
  129. package/src/sources/SourceManager.res.mjs +63 -21
  130. package/src/sources/SourceManager.resi +10 -0
  131. package/src/sources/Svm.res +31 -16
  132. package/src/sources/Svm.res.mjs +36 -13
  133. package/src/sources/SvmHyperSyncClient.res +5 -32
  134. package/src/sources/SvmHyperSyncSource.res +159 -134
  135. package/src/sources/SvmHyperSyncSource.res.mjs +164 -129
  136. package/src/sources/TransactionStore.res +49 -0
  137. package/src/sources/TransactionStore.res.mjs +30 -0
  138. package/src/tui/Tui.res +13 -16
  139. package/src/tui/Tui.res.mjs +12 -14
  140. package/svm.schema.json +49 -37
  141. package/src/bindings/Hrtime.res +0 -58
  142. package/src/bindings/Hrtime.res.mjs +0 -90
  143. package/src/bindings/Hrtime.resi +0 -30
@@ -1,8 +1,47 @@
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";
6
+ import * as BlockStore from "./BlockStore.res.mjs";
7
+ import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
8
+ import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
5
9
  import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
10
+ import * as TransactionStore from "./TransactionStore.res.mjs";
11
+
12
+ let eventTransactionFieldMask = TransactionStore.makeMaskFn(Internal.allEvmTransactionFields);
13
+
14
+ let blockFields = [
15
+ "number",
16
+ "timestamp",
17
+ "hash",
18
+ "parentHash",
19
+ "nonce",
20
+ "sha3Uncles",
21
+ "logsBloom",
22
+ "transactionsRoot",
23
+ "stateRoot",
24
+ "receiptsRoot",
25
+ "miner",
26
+ "difficulty",
27
+ "totalDifficulty",
28
+ "extraData",
29
+ "size",
30
+ "gasLimit",
31
+ "gasUsed",
32
+ "uncles",
33
+ "baseFeePerGas",
34
+ "blobGasUsed",
35
+ "excessBlobGas",
36
+ "parentBeaconBlockRoot",
37
+ "withdrawalsRoot",
38
+ "l1BlockNumber",
39
+ "sendCount",
40
+ "sendRoot",
41
+ "mixHash"
42
+ ];
43
+
44
+ let eventBlockFieldMask = BlockStore.makeMaskFn(blockFields);
6
45
 
7
46
  let cleanUpRawEventFieldsInPlace = (fields => {
8
47
  delete fields.hash
@@ -13,82 +52,18 @@ let cleanUpRawEventFieldsInPlace = (fields => {
13
52
  function make(logger) {
14
53
  return {
15
54
  name: "evm",
16
- blockFields: [
17
- "number",
18
- "timestamp",
19
- "hash",
20
- "parentHash",
21
- "nonce",
22
- "sha3Uncles",
23
- "logsBloom",
24
- "transactionsRoot",
25
- "stateRoot",
26
- "receiptsRoot",
27
- "miner",
28
- "difficulty",
29
- "totalDifficulty",
30
- "extraData",
31
- "size",
32
- "gasLimit",
33
- "gasUsed",
34
- "uncles",
35
- "baseFeePerGas",
36
- "blobGasUsed",
37
- "excessBlobGas",
38
- "parentBeaconBlockRoot",
39
- "withdrawalsRoot",
40
- "l1BlockNumber",
41
- "sendCount",
42
- "sendRoot",
43
- "mixHash"
44
- ],
45
- transactionFields: [
46
- "transactionIndex",
47
- "hash",
48
- "from",
49
- "to",
50
- "gas",
51
- "gasPrice",
52
- "maxPriorityFeePerGas",
53
- "maxFeePerGas",
54
- "cumulativeGasUsed",
55
- "effectiveGasPrice",
56
- "gasUsed",
57
- "input",
58
- "nonce",
59
- "value",
60
- "v",
61
- "r",
62
- "s",
63
- "contractAddress",
64
- "logsBloom",
65
- "root",
66
- "status",
67
- "yParity",
68
- "chainId",
69
- "maxFeePerBlobGas",
70
- "blobVersionedHashes",
71
- "type",
72
- "l1Fee",
73
- "l1GasPrice",
74
- "l1GasUsed",
75
- "l1FeeScalar",
76
- "gasUsedForL1",
77
- "accessList",
78
- "authorizationList"
79
- ],
80
55
  blockNumberName: "number",
81
56
  blockTimestampName: "timestamp",
82
57
  blockHashName: "hash",
83
58
  cleanUpRawEventFieldsInPlace: cleanUpRawEventFieldsInPlace,
84
59
  onBlockMethodName: "onBlock",
85
60
  onBlockFilterSchema: S$RescriptSchema.object(s => s.f("block", S$RescriptSchema.option(S$RescriptSchema.object(s2 => s2.f("number", S$RescriptSchema.unknown))))),
86
- onEventBlockFilterSchema: S$RescriptSchema.object(s => s.f("block", S$RescriptSchema.option(S$RescriptSchema.object(s2 => s2.f("number", S$RescriptSchema.unknown))))),
61
+ onEventBlockFilterSchema: S$RescriptSchema.object(s => s.f("block", S$RescriptSchema.option(S$RescriptSchema.strict(S$RescriptSchema.object(s2 => s2.f("number", S$RescriptSchema.unknown)))))),
87
62
  logger: logger,
88
63
  toEvent: eventItem => eventItem.payload,
89
64
  toEventLogger: eventItem => Logging.createChildFrom(logger, {
90
- contract: eventItem.eventConfig.contractName,
91
- event: eventItem.eventConfig.name,
65
+ contract: eventItem.onEventRegistration.eventConfig.contractName,
66
+ event: eventItem.onEventRegistration.eventConfig.name,
92
67
  chainId: eventItem.chain,
93
68
  block: eventItem.blockNumber,
94
69
  logIndex: eventItem.logIndex,
@@ -96,13 +71,22 @@ function make(logger) {
96
71
  }),
97
72
  toRawEvent: eventItem => {
98
73
  let payload = eventItem.payload;
99
- return RawEvent.make(eventItem, payload.block, payload.transaction, payload.params, payload.srcAddress, cleanUpRawEventFieldsInPlace);
74
+ let eventConfig = eventItem.onEventRegistration.eventConfig;
75
+ let block = payload.block;
76
+ let header = block !== undefined ? Primitive_option.valFromOption(block) : Stdlib_JsError.throwWithMessage("Unexpected case: The event block is missing for a raw event");
77
+ return RawEvent.make(eventItem, payload.block, payload.transaction, eventConfig.paramsMetadata.length === 0 ? undefined : payload.params, payload.srcAddress, header.hash, header.timestamp, cleanUpRawEventFieldsInPlace);
100
78
  }
101
79
  };
102
80
  }
103
81
 
82
+ let transactionFields = Internal.allEvmTransactionFields;
83
+
104
84
  export {
85
+ transactionFields,
86
+ eventTransactionFieldMask,
87
+ blockFields,
88
+ eventBlockFieldMask,
105
89
  cleanUpRawEventFieldsInPlace,
106
90
  make,
107
91
  }
108
- /* Logging Not a pure module */
92
+ /* eventTransactionFieldMask Not a pure module */
@@ -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,54 +32,26 @@ 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),
38
39
  }
39
40
  }
40
41
 
41
- let collectEventParams = (contracts: array<Internal.evmContractConfig>): array<
42
- HyperSyncClient.Decoder.eventParamsInput,
43
- > => {
44
- let result = []
45
- contracts->Array.forEach(contract => {
46
- contract.events->Array.forEach(event => {
47
- result
48
- ->Array.push({
49
- HyperSyncClient.Decoder.sighash: event.sighash,
50
- topicCount: event.topicCount,
51
- eventName: event.name,
52
- contractName: contract.name,
53
- params: event.paramsMetadata,
54
- })
55
- ->ignore
56
- })
57
- })
58
- result
59
- }
60
-
61
42
  let makeSources = (
62
43
  ~chain,
63
- ~contracts: array<Internal.evmContractConfig>,
44
+ ~onEventRegistrations: array<Internal.evmOnEventRegistration>,
64
45
  ~hyperSync,
65
46
  ~rpcs: array<rpc>,
66
47
  ~lowercaseAddresses,
67
48
  ) => {
68
- let eventRouter =
69
- contracts
70
- ->Array.flatMap(contract => contract.events)
71
- ->EventRouter.fromEvmEventModsOrThrow(~chain)
72
-
73
- let allEventParams = collectEventParams(contracts)
74
-
75
49
  let sources = switch hyperSync {
76
50
  | Some(endpointUrl) => [
77
51
  HyperSyncSource.make({
78
52
  chain,
79
53
  endpointUrl,
80
- allEventParams,
81
- eventRouter,
54
+ onEventRegistrations,
82
55
  apiToken: Env.envioApiToken,
83
56
  clientTimeoutMillis: Env.hyperSyncClientTimeoutMillis,
84
57
  lowercaseAddresses,
@@ -89,16 +62,16 @@ let makeSources = (
89
62
  ]
90
63
  | _ => []
91
64
  }
92
- rpcs->Array.forEach(({?syncConfig, url, sourceFor, ?ws}) => {
65
+ rpcs->Array.forEach(({?syncConfig, url, sourceFor, ?ws, ?headers}) => {
93
66
  let source = RpcSource.make({
94
67
  chain,
95
68
  sourceFor,
96
69
  syncConfig: getSyncConfig(syncConfig->Option.getOr({})),
97
70
  url,
98
- eventRouter,
99
- allEventParams,
71
+ onEventRegistrations,
100
72
  lowercaseAddresses,
101
73
  ?ws,
74
+ ?headers,
102
75
  })
103
76
  let _ = sources->Array.push(source)
104
77
  })
@@ -2,7 +2,6 @@
2
2
 
3
3
  import * as Env from "../Env.res.mjs";
4
4
  import * as RpcSource from "./RpcSource.res.mjs";
5
- import * as EventRouter from "./EventRouter.res.mjs";
6
5
  import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
7
6
  import * as HyperSyncSource from "./HyperSyncSource.res.mjs";
8
7
 
@@ -13,37 +12,18 @@ function getSyncConfig(param) {
13
12
  backoffMultiplicative: Stdlib_Option.getOr(Env.Configurable.SyncConfig.backoffMultiplicative, Stdlib_Option.getOr(param.backoffMultiplicative, 0.8)),
14
13
  accelerationAdditive: Stdlib_Option.getOr(Env.Configurable.SyncConfig.accelerationAdditive, Stdlib_Option.getOr(param.accelerationAdditive, 500)),
15
14
  intervalCeiling: Stdlib_Option.getOr(Env.Configurable.SyncConfig.intervalCeiling, Stdlib_Option.getOr(param.intervalCeiling, 10000)),
16
- backoffMillis: Stdlib_Option.getOr(param.backoffMillis, 5000),
15
+ backoffMillis: Stdlib_Option.getOr(param.backoffMillis, 2000),
17
16
  queryTimeoutMillis: queryTimeoutMillis,
18
17
  fallbackStallTimeout: Stdlib_Option.getOr(param.fallbackStallTimeout, queryTimeoutMillis / 2 | 0),
19
18
  pollingInterval: Stdlib_Option.getOr(param.pollingInterval, 1000)
20
19
  };
21
20
  }
22
21
 
23
- function collectEventParams(contracts) {
24
- let result = [];
25
- contracts.forEach(contract => {
26
- contract.events.forEach(event => {
27
- result.push({
28
- sighash: event.sighash,
29
- topicCount: event.topicCount,
30
- eventName: event.name,
31
- contractName: contract.name,
32
- params: event.paramsMetadata
33
- });
34
- });
35
- });
36
- return result;
37
- }
38
-
39
- function makeSources(chain, contracts, hyperSync, rpcs, lowercaseAddresses) {
40
- let eventRouter = EventRouter.fromEvmEventModsOrThrow(contracts.flatMap(contract => contract.events), chain);
41
- let allEventParams = collectEventParams(contracts);
22
+ function makeSources(chain, onEventRegistrations, hyperSync, rpcs, lowercaseAddresses) {
42
23
  let sources = hyperSync !== undefined ? [HyperSyncSource.make({
43
24
  chain: chain,
44
25
  endpointUrl: hyperSync,
45
- allEventParams: allEventParams,
46
- eventRouter: eventRouter,
26
+ onEventRegistrations: onEventRegistrations,
47
27
  apiToken: Env.envioApiToken,
48
28
  clientTimeoutMillis: Env.hyperSyncClientTimeoutMillis,
49
29
  lowercaseAddresses: lowercaseAddresses,
@@ -57,10 +37,10 @@ function makeSources(chain, contracts, hyperSync, rpcs, lowercaseAddresses) {
57
37
  syncConfig: getSyncConfig(Stdlib_Option.getOr(param.syncConfig, {})),
58
38
  url: param.url,
59
39
  chain: chain,
60
- eventRouter: eventRouter,
61
- allEventParams: allEventParams,
40
+ onEventRegistrations: onEventRegistrations,
62
41
  lowercaseAddresses: lowercaseAddresses,
63
- ws: param.ws
42
+ ws: param.ws,
43
+ headers: param.headers
64
44
  });
65
45
  sources.push(source);
66
46
  });
@@ -69,7 +49,6 @@ function makeSources(chain, contracts, hyperSync, rpcs, lowercaseAddresses) {
69
49
 
70
50
  export {
71
51
  getSyncConfig,
72
- collectEventParams,
73
52
  makeSources,
74
53
  }
75
54
  /* Env Not a pure module */
@@ -1,9 +1,53 @@
1
- type cfg = {url: string, httpReqTimeoutMillis?: int}
1
+ type cfg = {
2
+ url: string,
3
+ httpReqTimeoutMillis?: int,
4
+ headers?: dict<string>,
5
+ initialBlockInterval: int,
6
+ backoffMultiplicative: float,
7
+ accelerationAdditive: int,
8
+ intervalCeiling: int,
9
+ backoffMillis: int,
10
+ queryTimeoutMillis: int,
11
+ }
12
+
13
+ // Only logs that resolved to a registration cross the boundary, each carrying
14
+ // its registration's chain-scoped index.
15
+ type rpcEventItem = {
16
+ log: Rpc.GetLogs.log,
17
+ onEventRegistrationIndex: int,
18
+ params: Internal.eventParams,
19
+ }
20
+
21
+ type nextPageParams = {
22
+ fromBlock: int,
23
+ toBlockCeiling: int,
24
+ partitionId: string,
25
+ // The partition's registration selection, by chain-scoped index. Log
26
+ // selections and the routing index are derived on the Rust side from the
27
+ // registrations passed at construction.
28
+ registrationIndexes: array<int>,
29
+ addressesByContractName: dict<array<Address.t>>,
30
+ }
31
+
32
+ type nextPageResponse = {
33
+ items: array<rpcEventItem>,
34
+ toBlock: int,
35
+ requestStats: array<Source.requestStat>,
36
+ }
2
37
 
3
- type t = {getHeight: unit => promise<int>}
38
+ // The caller provides a range; Rust decides the actual `toBlock` and returns it.
39
+ type t = {
40
+ getHeight: unit => promise<int>,
41
+ getNextPage: nextPageParams => promise<nextPageResponse>,
42
+ }
4
43
 
5
44
  @send
6
- external classNew: (Core.evmRpcClientCtor, cfg) => t = "new"
45
+ external classNew: (
46
+ Core.evmRpcClientCtor,
47
+ cfg,
48
+ array<HyperSyncClient.Registration.input>,
49
+ ~checksumAddresses: bool,
50
+ ) => t = "new"
7
51
 
8
52
  // Rust encodes JSON-RPC errors as a JSON payload in the napi error's
9
53
  // message: `{"kind":"JsonRpcError","code":-32005,"message":"..."}`.
@@ -34,9 +78,31 @@ let coerceErrorOrThrow = exn =>
34
78
  | None => exn->throw
35
79
  }
36
80
 
37
- let make = (~url, ~httpReqTimeoutMillis=?) => {
38
- let client = Core.getAddon().evmRpcClient->classNew({url, ?httpReqTimeoutMillis})
81
+ let make = (
82
+ ~url,
83
+ ~checksumAddresses,
84
+ ~syncConfig: Config.sourceSync,
85
+ ~httpReqTimeoutMillis=?,
86
+ ~headers=?,
87
+ ~eventRegistrations=[],
88
+ ) => {
89
+ let client = Core.getAddon().evmRpcClient->classNew(
90
+ {
91
+ url,
92
+ ?httpReqTimeoutMillis,
93
+ ?headers,
94
+ initialBlockInterval: syncConfig.initialBlockInterval,
95
+ backoffMultiplicative: syncConfig.backoffMultiplicative,
96
+ accelerationAdditive: syncConfig.accelerationAdditive,
97
+ intervalCeiling: syncConfig.intervalCeiling,
98
+ backoffMillis: syncConfig.backoffMillis,
99
+ queryTimeoutMillis: syncConfig.queryTimeoutMillis,
100
+ },
101
+ eventRegistrations,
102
+ ~checksumAddresses,
103
+ )
39
104
  {
40
105
  getHeight: () => client.getHeight()->Promise.catch(coerceErrorOrThrow),
106
+ getNextPage: params => client.getNextPage(params)->Promise.catch(coerceErrorOrThrow),
41
107
  }
42
108
  }
@@ -46,13 +46,22 @@ function coerceErrorOrThrow(exn) {
46
46
  throw exn;
47
47
  }
48
48
 
49
- function make(url, httpReqTimeoutMillis) {
49
+ function make(url, checksumAddresses, syncConfig, httpReqTimeoutMillis, headers, eventRegistrationsOpt) {
50
+ let eventRegistrations = eventRegistrationsOpt !== undefined ? eventRegistrationsOpt : [];
50
51
  let client = Core.getAddon().EvmRpcClient.new({
51
52
  url: url,
52
- httpReqTimeoutMillis: httpReqTimeoutMillis
53
- });
53
+ httpReqTimeoutMillis: httpReqTimeoutMillis,
54
+ headers: headers,
55
+ initialBlockInterval: syncConfig.initialBlockInterval,
56
+ backoffMultiplicative: syncConfig.backoffMultiplicative,
57
+ accelerationAdditive: syncConfig.accelerationAdditive,
58
+ intervalCeiling: syncConfig.intervalCeiling,
59
+ backoffMillis: syncConfig.backoffMillis,
60
+ queryTimeoutMillis: syncConfig.queryTimeoutMillis
61
+ }, eventRegistrations, checksumAddresses);
54
62
  return {
55
- getHeight: () => Stdlib_Promise.$$catch(client.getHeight(), coerceErrorOrThrow)
63
+ getHeight: () => Stdlib_Promise.$$catch(client.getHeight(), coerceErrorOrThrow),
64
+ getNextPage: params => Stdlib_Promise.$$catch(client.getNextPage(params), coerceErrorOrThrow)
56
65
  };
57
66
  }
58
67
 
@@ -0,0 +1,39 @@
1
+ // Selection-bitmask helpers shared by the per-chain field stores
2
+ // (`TransactionStore`, `BlockStore`). A field's bit index is its position in the
3
+ // ecosystem's ordered field-name array — the same code the Rust store uses.
4
+
5
+ // Field-name → bit-index map from an ordered field-name array.
6
+ let fieldCodes = (fields: array<string>): dict<int> => {
7
+ let codes = Dict.make()
8
+ fields->Array.forEachWithIndex((name, i) => codes->Dict.set(name, i))
9
+ codes
10
+ }
11
+
12
+ let pow2: int => float = %raw(`c => Math.pow(2, c)`)
13
+
14
+ // One event's selected fields as a bitmask float (bit `code` set ⇔ selected).
15
+ // Each field appears once, so summing `pow2(code)` sets distinct bits with no
16
+ // overlap; the result stays exact in f64 (codes span 0..31, so a mask is at most
17
+ // 2^32-1).
18
+ let maskFromFields = (selectedFields: Utils.Set.t<string>, ~codes: dict<int>): float => {
19
+ let mask = ref(0.)
20
+ selectedFields->Utils.Set.forEach(name =>
21
+ switch codes->Utils.Dict.dangerouslyGetNonOption(name) {
22
+ | Some(code) => mask := mask.contents +. pow2(code)
23
+ | None => ()
24
+ }
25
+ )
26
+ mask.contents
27
+ }
28
+
29
+ // Build an ecosystem's per-event mask function from its ordered field-name
30
+ // array. The field codes are derived once and closed over.
31
+ let makeMaskFn = (fields: array<string>): (Utils.Set.t<string> => float) => {
32
+ let codes = fieldCodes(fields)
33
+ selectedFields => selectedFields->maskFromFields(~codes)
34
+ }
35
+
36
+ // Bitwise OR of two per-event masks. Masks fit in 32 bits (≤32 fields), so
37
+ // `>>> 0` recovers the unsigned value that a plain `|` renders negative once bit
38
+ // 31 is set.
39
+ let orMask: (float, float) => float = %raw(`(a, b) => (a | b) >>> 0`)
@@ -0,0 +1,42 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+
4
+ function fieldCodes(fields) {
5
+ let codes = {};
6
+ fields.forEach((name, i) => {
7
+ codes[name] = i;
8
+ });
9
+ return codes;
10
+ }
11
+
12
+ let pow2 = (c => Math.pow(2, c));
13
+
14
+ function maskFromFields(selectedFields, codes) {
15
+ let mask = {
16
+ contents: 0
17
+ };
18
+ selectedFields.forEach(name => {
19
+ let code = codes[name];
20
+ if (code !== undefined) {
21
+ mask.contents = mask.contents + pow2(code);
22
+ return;
23
+ }
24
+ });
25
+ return mask.contents;
26
+ }
27
+
28
+ function makeMaskFn(fields) {
29
+ let codes = fieldCodes(fields);
30
+ return selectedFields => maskFromFields(selectedFields, codes);
31
+ }
32
+
33
+ let orMask = ((a, b) => (a | b) >>> 0);
34
+
35
+ export {
36
+ fieldCodes,
37
+ pow2,
38
+ maskFromFields,
39
+ makeMaskFn,
40
+ orMask,
41
+ }
42
+ /* No side effect */
@@ -21,8 +21,6 @@ let cleanUpRawEventFieldsInPlace: JSON.t => unit = %raw(`fields => {
21
21
 
22
22
  let make = (~logger: Pino.t): Ecosystem.t => {
23
23
  name: Fuel,
24
- blockFields: ["id", "height", "time"],
25
- transactionFields: ["id"],
26
24
  blockNumberName: "height",
27
25
  blockTimestampName: "time",
28
26
  blockHashName: "id",
@@ -37,17 +35,19 @@ let make = (~logger: Pino.t): Ecosystem.t => {
37
35
  // Analogous to EVM, but keyed by `block.height` instead of
38
36
  // `block.number`. See `Evm.res` for the rationale on the two-stage
39
37
  // parse and the `_lte`/`_every` rejection.
38
+ // `S.strict` on the inner object rejects unknown `block` fields — including
39
+ // `block.number`, which is EVM-only; Fuel filters by `block.height`.
40
40
  onEventBlockFilterSchema: S.object(s =>
41
- s.field("block", S.option(S.object(s2 => s2.field("height", S.unknown))))
41
+ s.field("block", S.option(S.object(s2 => s2.field("height", S.unknown))->S.strict))
42
42
  ),
43
43
  logger,
44
- toEvent: eventItem => eventItem.payload->Internal.payloadToEvent,
44
+ toEvent: eventItem => eventItem.payload->(Utils.magic: Internal.eventPayload => Internal.event),
45
45
  toEventLogger: eventItem =>
46
46
  Logging.createChildFrom(
47
47
  ~logger,
48
48
  ~params={
49
- "contract": eventItem.eventConfig.contractName,
50
- "event": eventItem.eventConfig.name,
49
+ "contract": eventItem.onEventRegistration.eventConfig.contractName,
50
+ "event": eventItem.onEventRegistration.eventConfig.name,
51
51
  "chainId": eventItem.chain->ChainMap.Chain.toChainId,
52
52
  "block": eventItem.blockNumber,
53
53
  "logIndex": eventItem.logIndex,
@@ -56,11 +56,14 @@ let make = (~logger: Pino.t): Ecosystem.t => {
56
56
  ),
57
57
  toRawEvent: eventItem => {
58
58
  let payload = eventItem.payload->toPayload
59
+ let header = payload.block->(Utils.magic: Internal.eventBlock => {"id": string, "time": int})
59
60
  eventItem->RawEvent.make(
60
61
  ~block=payload.block,
61
62
  ~transaction=payload.transaction,
62
63
  ~params=payload.params,
63
64
  ~srcAddress=payload.srcAddress,
65
+ ~blockHash=header["id"],
66
+ ~blockTimestamp=header["time"],
64
67
  ~cleanUpRawEventFieldsInPlace,
65
68
  )
66
69
  },
@@ -13,24 +13,18 @@ let cleanUpRawEventFieldsInPlace = (fields => {
13
13
  function make(logger) {
14
14
  return {
15
15
  name: "fuel",
16
- blockFields: [
17
- "id",
18
- "height",
19
- "time"
20
- ],
21
- transactionFields: ["id"],
22
16
  blockNumberName: "height",
23
17
  blockTimestampName: "time",
24
18
  blockHashName: "id",
25
19
  cleanUpRawEventFieldsInPlace: cleanUpRawEventFieldsInPlace,
26
20
  onBlockMethodName: "onBlock",
27
21
  onBlockFilterSchema: S$RescriptSchema.object(s => s.f("block", S$RescriptSchema.option(S$RescriptSchema.object(s2 => s2.f("height", S$RescriptSchema.unknown))))),
28
- onEventBlockFilterSchema: S$RescriptSchema.object(s => s.f("block", S$RescriptSchema.option(S$RescriptSchema.object(s2 => s2.f("height", S$RescriptSchema.unknown))))),
22
+ onEventBlockFilterSchema: S$RescriptSchema.object(s => s.f("block", S$RescriptSchema.option(S$RescriptSchema.strict(S$RescriptSchema.object(s2 => s2.f("height", S$RescriptSchema.unknown)))))),
29
23
  logger: logger,
30
24
  toEvent: eventItem => eventItem.payload,
31
25
  toEventLogger: eventItem => Logging.createChildFrom(logger, {
32
- contract: eventItem.eventConfig.contractName,
33
- event: eventItem.eventConfig.name,
26
+ contract: eventItem.onEventRegistration.eventConfig.contractName,
27
+ event: eventItem.onEventRegistration.eventConfig.name,
34
28
  chainId: eventItem.chain,
35
29
  block: eventItem.blockNumber,
36
30
  logIndex: eventItem.logIndex,
@@ -38,7 +32,8 @@ function make(logger) {
38
32
  }),
39
33
  toRawEvent: eventItem => {
40
34
  let payload = eventItem.payload;
41
- return RawEvent.make(eventItem, payload.block, payload.transaction, payload.params, payload.srcAddress, cleanUpRawEventFieldsInPlace);
35
+ let header = payload.block;
36
+ return RawEvent.make(eventItem, payload.block, payload.transaction, payload.params, payload.srcAddress, header.id, header.time, cleanUpRawEventFieldsInPlace);
42
37
  }
43
38
  };
44
39
  }