envio 3.3.0-alpha.6 → 3.3.0-alpha.8

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 (93) hide show
  1. package/index.d.ts +23 -5
  2. package/package.json +6 -6
  3. package/src/Address.res +5 -2
  4. package/src/Address.res.mjs +3 -1
  5. package/src/Api.res +1 -1
  6. package/src/Api.res.mjs +1 -1
  7. package/src/ChainFetching.res +34 -34
  8. package/src/ChainFetching.res.mjs +29 -29
  9. package/src/ChainState.res +328 -165
  10. package/src/ChainState.res.mjs +205 -100
  11. package/src/ChainState.resi +16 -7
  12. package/src/Config.res +55 -27
  13. package/src/Config.res.mjs +46 -7
  14. package/src/ContractRegisterContext.res +2 -12
  15. package/src/ContractRegisterContext.res.mjs +3 -5
  16. package/src/Core.res +7 -0
  17. package/src/CrossChainState.res +54 -79
  18. package/src/CrossChainState.res.mjs +45 -60
  19. package/src/CrossChainState.resi +1 -1
  20. package/src/Ecosystem.res +3 -3
  21. package/src/Ecosystem.res.mjs +3 -3
  22. package/src/Envio.res +14 -9
  23. package/src/EventConfigBuilder.res +105 -56
  24. package/src/EventConfigBuilder.res.mjs +69 -33
  25. package/src/EventProcessing.res +19 -15
  26. package/src/EventProcessing.res.mjs +13 -12
  27. package/src/FetchState.res +383 -182
  28. package/src/FetchState.res.mjs +260 -264
  29. package/src/HandlerLoader.res +7 -112
  30. package/src/HandlerLoader.res.mjs +1 -87
  31. package/src/HandlerRegister.res +209 -6
  32. package/src/HandlerRegister.res.mjs +90 -5
  33. package/src/HandlerRegister.resi +13 -2
  34. package/src/IndexerState.res +6 -3
  35. package/src/IndexerState.res.mjs +3 -3
  36. package/src/IndexerState.resi +1 -1
  37. package/src/IndexingAddresses.res +10 -7
  38. package/src/IndexingAddresses.res.mjs +8 -7
  39. package/src/IndexingAddresses.resi +3 -1
  40. package/src/Internal.res +82 -36
  41. package/src/Internal.res.mjs +11 -1
  42. package/src/Main.res +22 -23
  43. package/src/Main.res.mjs +15 -17
  44. package/src/Metrics.res +43 -2
  45. package/src/Metrics.res.mjs +39 -3
  46. package/src/Prometheus.res +0 -35
  47. package/src/Prometheus.res.mjs +33 -68
  48. package/src/RawEvent.res +7 -2
  49. package/src/RawEvent.res.mjs +4 -4
  50. package/src/SimulateItems.res +26 -8
  51. package/src/SimulateItems.res.mjs +11 -14
  52. package/src/TestIndexer.res +1 -1
  53. package/src/TestIndexer.res.mjs +1 -1
  54. package/src/sources/BlockStore.res +46 -0
  55. package/src/sources/BlockStore.res.mjs +24 -0
  56. package/src/sources/EventRouter.res +19 -12
  57. package/src/sources/EventRouter.res.mjs +7 -5
  58. package/src/sources/Evm.res +54 -4
  59. package/src/sources/Evm.res.mjs +43 -4
  60. package/src/sources/EvmChain.res +14 -18
  61. package/src/sources/EvmChain.res.mjs +12 -13
  62. package/src/sources/FieldMask.res +39 -0
  63. package/src/sources/FieldMask.res.mjs +42 -0
  64. package/src/sources/Fuel.res +5 -2
  65. package/src/sources/Fuel.res.mjs +4 -3
  66. package/src/sources/HyperFuelSource.res +32 -40
  67. package/src/sources/HyperFuelSource.res.mjs +53 -45
  68. package/src/sources/HyperSync.res +35 -9
  69. package/src/sources/HyperSync.res.mjs +52 -35
  70. package/src/sources/HyperSync.resi +11 -3
  71. package/src/sources/HyperSyncClient.res +15 -4
  72. package/src/sources/HyperSyncHeightStream.res +1 -8
  73. package/src/sources/HyperSyncHeightStream.res.mjs +0 -2
  74. package/src/sources/HyperSyncSource.res +39 -58
  75. package/src/sources/HyperSyncSource.res.mjs +44 -44
  76. package/src/sources/RpcSource.res +114 -92
  77. package/src/sources/RpcSource.res.mjs +77 -46
  78. package/src/sources/RpcWebSocketHeightStream.res +0 -5
  79. package/src/sources/RpcWebSocketHeightStream.res.mjs +0 -2
  80. package/src/sources/SimulateSource.res +6 -3
  81. package/src/sources/SimulateSource.res.mjs +13 -5
  82. package/src/sources/Source.res +25 -5
  83. package/src/sources/SourceManager.res +66 -3
  84. package/src/sources/SourceManager.res.mjs +55 -7
  85. package/src/sources/SourceManager.resi +10 -0
  86. package/src/sources/Svm.res +15 -10
  87. package/src/sources/Svm.res.mjs +24 -7
  88. package/src/sources/SvmHyperSyncClient.res +5 -6
  89. package/src/sources/SvmHyperSyncSource.res +84 -41
  90. package/src/sources/SvmHyperSyncSource.res.mjs +90 -43
  91. package/src/sources/TransactionStore.res +6 -107
  92. package/src/sources/TransactionStore.res.mjs +5 -86
  93. package/svm.schema.json +19 -0
@@ -7,9 +7,7 @@ import * as Logging from "./Logging.res.mjs";
7
7
  import * as ChainMap from "./ChainMap.res.mjs";
8
8
  import * as ChainState from "./ChainState.res.mjs";
9
9
  import * as Prometheus from "./Prometheus.res.mjs";
10
- import * as Stdlib_Int from "@rescript/runtime/lib/es6/Stdlib_Int.js";
11
- import * as Stdlib_Dict from "@rescript/runtime/lib/es6/Stdlib_Dict.js";
12
- import * as Primitive_int from "@rescript/runtime/lib/es6/Primitive_int.js";
10
+ import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
13
11
  import * as Primitive_float from "@rescript/runtime/lib/es6/Primitive_float.js";
14
12
  import * as SafeCheckpointTracking from "./SafeCheckpointTracking.res.mjs";
15
13
 
@@ -17,13 +15,13 @@ function calculateTargetBufferSize() {
17
15
  if (Env.targetBufferSize !== undefined) {
18
16
  return Env.targetBufferSize;
19
17
  } else {
20
- return 100000;
18
+ return 50000;
21
19
  }
22
20
  }
23
21
 
24
22
  function make(chainStates, isInReorgThreshold, isRealtime, targetBufferSizeOpt) {
25
23
  let targetBufferSize = targetBufferSizeOpt !== undefined ? targetBufferSizeOpt : (
26
- Env.targetBufferSize !== undefined ? Env.targetBufferSize : 100000
24
+ Env.targetBufferSize !== undefined ? Env.targetBufferSize : 50000
27
25
  );
28
26
  let crossChainState = {
29
27
  chainStates: chainStates,
@@ -95,12 +93,12 @@ function enterReorgThreshold(crossChainState) {
95
93
  crossChainState.isInReorgThreshold = true;
96
94
  }
97
95
 
98
- function applyBatchProgress(crossChainState, batch) {
96
+ function applyBatchProgress(crossChainState, batch, blockTimestampName) {
99
97
  let chainIds = crossChainState.chainIds;
100
98
  let everyChainCaughtUp = true;
101
99
  for (let i = 0, i_finish = chainIds.length; i < i_finish; ++i) {
102
100
  let cs = crossChainState.chainStates[chainIds[i]];
103
- ChainState.applyBatchProgress(cs, batch);
101
+ ChainState.applyBatchProgress(cs, batch, blockTimestampName);
104
102
  if (!(ChainState.hasProcessedToEndblock(cs) || ChainState.isProgressAtHead(cs))) {
105
103
  everyChainCaughtUp = false;
106
104
  }
@@ -135,72 +133,59 @@ function totalReservedSize(crossChainState) {
135
133
  return total;
136
134
  }
137
135
 
138
- function compareByProgress(a, b) {
139
- return Primitive_float.compare(a.progress, b.progress);
140
- }
141
-
142
136
  async function checkAndFetch(crossChainState, dispatchChain) {
143
- let remaining = Primitive_int.max(0, (crossChainState.targetBufferSize - totalReadyCount(crossChainState) | 0) - (totalReservedSize(crossChainState) | 0) | 0);
144
- let chainIds = crossChainState.chainIds;
137
+ let remaining = {
138
+ contents: Primitive_float.max(0, crossChainState.targetBufferSize - totalReadyCount(crossChainState) - totalReservedSize(crossChainState))
139
+ };
145
140
  let actionByChain = {};
146
- let candidates = [];
147
- for (let i = 0, i_finish = chainIds.length; i < i_finish; ++i) {
148
- let chainId = chainIds[i];
149
- let cs = crossChainState.chainStates[chainId];
150
- let action = ChainState.getNextQuery(cs, remaining);
141
+ priorityOrder(crossChainState).forEach(cs => {
142
+ let chainId = ChainState.chainConfig(cs).id;
143
+ let chainTargetItems = remaining.contents + ChainState.pendingBudget(cs);
144
+ let action = ChainState.getNextQuery(cs, chainTargetItems);
151
145
  if (typeof action !== "object") {
146
+ if (action === "WaitingForNewBlock") {
147
+ actionByChain[chainId] = action;
148
+ return;
149
+ }
152
150
  actionByChain[chainId] = action;
151
+ return;
153
152
  } else {
154
- actionByChain[chainId] = "NothingToQuery";
155
- action._0.forEach(query => {
156
- query.chainId = chainId;
157
- query.progress = ChainState.getProgressPercentageAt(cs, query.fromBlock);
158
- candidates.push(query);
153
+ let queries = action._0;
154
+ let consumed = Stdlib_Array.reduce(queries, 0, (acc, query) => acc + query.itemsTarget);
155
+ let partitions = {};
156
+ queries.forEach(query => {
157
+ partitions[query.partitionId] = {
158
+ fromBlock: query.fromBlock,
159
+ targetBlock: query.toBlock,
160
+ targetEvents: Math.round(query.itemsTarget) | 0
161
+ };
159
162
  });
160
- }
161
- }
162
- candidates.sort(compareByProgress);
163
- let admittedByChain = {};
164
- let running = 0;
165
- let idx = 0;
166
- while (running < remaining && idx < candidates.length) {
167
- let query = candidates[idx];
168
- Utils.Dict.push(admittedByChain, query.chainId.toString(), query);
169
- running = running + query.estResponseSize;
170
- idx = idx + 1 | 0;
171
- };
172
- Stdlib_Dict.forEachWithKey(admittedByChain, (queries, chainId) => {
173
- let partitions = {};
174
- queries.forEach(query => {
175
- partitions[query.partitionId] = {
176
- fromBlock: query.fromBlock,
177
- targetBlock: query.toBlock
163
+ Logging.trace({
164
+ msg: "Started querying",
165
+ chainId: chainId,
166
+ partitions: partitions
167
+ });
168
+ actionByChain[chainId] = {
169
+ TAG: "Ready",
170
+ _0: queries
178
171
  };
179
- });
180
- Logging.trace({
181
- msg: "Started querying",
182
- chainId: Stdlib_Int.fromString(chainId, undefined),
183
- partitions: partitions
184
- });
185
- actionByChain[chainId] = {
186
- TAG: "Ready",
187
- _0: queries
188
- };
189
- let chainId$1 = Stdlib_Int.fromString(chainId, undefined);
190
- ChainState.startFetchingQueries(crossChainState.chainStates[chainId$1], queries);
172
+ ChainState.startFetchingQueries(cs, queries);
173
+ remaining.contents = Primitive_float.max(0, remaining.contents - consumed);
174
+ return;
175
+ }
191
176
  });
192
177
  let promises = [];
193
- for (let i$1 = 0, i_finish$1 = chainIds.length; i$1 < i_finish$1; ++i$1) {
194
- let chainId$1 = chainIds[i$1];
195
- let action$1 = actionByChain[chainId$1];
196
- if (action$1 !== undefined) {
178
+ for (let i = 0, i_finish = crossChainState.chainIds.length; i < i_finish; ++i) {
179
+ let chainId = crossChainState.chainIds[i];
180
+ let action = actionByChain[chainId];
181
+ if (action !== undefined) {
197
182
  let exit = 0;
198
- if (typeof action$1 === "object" || action$1 === "WaitingForNewBlock") {
183
+ if (typeof action === "object" || action === "WaitingForNewBlock") {
199
184
  exit = 1;
200
185
  }
201
186
  if (exit === 1) {
202
- let chain = ChainMap.Chain.makeUnsafe(chainId$1);
203
- promises.push(dispatchChain(chain, action$1));
187
+ let chain = ChainMap.Chain.makeUnsafe(chainId);
188
+ promises.push(dispatchChain(chain, action));
204
189
  }
205
190
  }
206
191
  }
@@ -29,7 +29,7 @@ let createBatch: (
29
29
  ~isRollback: bool,
30
30
  ) => Batch.t
31
31
  let enterReorgThreshold: t => unit
32
- let applyBatchProgress: (t, ~batch: Batch.t) => unit
32
+ let applyBatchProgress: (t, ~batch: Batch.t, ~blockTimestampName: string) => unit
33
33
 
34
34
  // Fetch control.
35
35
  let priorityOrder: t => array<ChainState.t>
package/src/Ecosystem.res CHANGED
@@ -69,12 +69,12 @@ let getItemLogger = {
69
69
  | None =>
70
70
  let logger = switch item {
71
71
  | Internal.Event(_) => ecosystem.toEventLogger(item->Internal.castUnsafeEventItem)
72
- | Block({blockNumber, onBlockConfig}) =>
72
+ | Block({blockNumber, onBlockRegistration}) =>
73
73
  Logging.createChildFrom(
74
74
  ~logger=ecosystem.logger,
75
75
  ~params={
76
- "onBlock": onBlockConfig.name,
77
- "chainId": onBlockConfig.chainId,
76
+ "onBlock": onBlockRegistration.name,
77
+ "chainId": onBlockRegistration.chainId,
78
78
  "block": blockNumber,
79
79
  },
80
80
  )
@@ -26,10 +26,10 @@ function getItemLogger(item, ecosystem) {
26
26
  if (item.kind === 0) {
27
27
  logger$1 = ecosystem.toEventLogger(item);
28
28
  } else {
29
- let onBlockConfig = item.onBlockConfig;
29
+ let onBlockRegistration = item.onBlockRegistration;
30
30
  logger$1 = Logging.createChildFrom(ecosystem.logger, {
31
- onBlock: onBlockConfig.name,
32
- chainId: onBlockConfig.chainId,
31
+ onBlock: onBlockRegistration.name,
32
+ chainId: onBlockRegistration.chainId,
33
33
  block: item.blockNumber
34
34
  });
35
35
  }
package/src/Envio.res CHANGED
@@ -66,18 +66,21 @@ type svmLog = {
66
66
  message: string,
67
67
  }
68
68
 
69
- /** Block context for a matched instruction. `time`/`hash` follow the
70
- EVM/Fuel field names so the shared `Ecosystem.t` getters in `Svm.res` read
71
- them uniformly. */
69
+ /** Block context for a matched instruction. `slot`/`hash` are always present;
70
+ `time` can still be absent HyperSync/Solana may not report a block time for
71
+ every slot. Every other field is opt-in via `field_selection.block_fields`,
72
+ materialised from the per-chain block store at batch prep. */
72
73
  type svmInstructionBlock = {
73
74
  /** Slot this instruction's block was matched in. */
74
75
  slot: int,
75
- /** Unix block time (seconds). `0` when HyperSync didn't return a block
76
- for this instruction's slot. */
77
- time: int,
78
- /** Block hash. Currently always empty — populated by the future
79
- reorg-guard `queryBlockHash(slot)` route. */
76
+ /** Unix block time (seconds). */
77
+ time?: int,
80
78
  hash: string,
79
+ /** Block height (distinct from slot). Absent when not selected via
80
+ `field_selection.block_fields`. */
81
+ height?: int,
82
+ parentSlot?: int,
83
+ parentHash?: string,
81
84
  }
82
85
 
83
86
  /** The per-instruction payload handlers receive as their `instruction`
@@ -111,7 +114,9 @@ type svmInstruction = {
111
114
  /** Program log entries scoped to this instruction. Absent when the
112
115
  per-instruction `include_logs` flag is `false`. */
113
116
  logs?: array<svmLog>,
114
- block: svmInstructionBlock,
117
+ // Omitted on construction; materialised onto the payload at batch prep,
118
+ // before a handler ever reads it.
119
+ block?: svmInstructionBlock,
115
120
  }
116
121
 
117
122
  /** Arguments passed to handlers registered via `indexer.onInstruction`. */
@@ -378,20 +378,54 @@ let buildEvmEventConfig = (
378
378
  ~eventName: string,
379
379
  ~sighash: string,
380
380
  ~params: array<paramMeta>,
381
+ ~blockFields: option<array<Internal.evmBlockField>>=?,
382
+ ~transactionFields: option<array<Internal.evmTransactionField>>=?,
383
+ ~globalBlockFieldsSet: Utils.Set.t<Internal.evmBlockField>=Utils.Set.make(),
384
+ ~globalTransactionFieldsSet: Utils.Set.t<Internal.evmTransactionField>=Utils.Set.make(),
385
+ ): Internal.evmEventConfig => {
386
+ let topicCount = params->Array.reduce(1, (acc, p) => p.indexed ? acc + 1 : acc)
387
+
388
+ let (selectedBlockFields, selectedTransactionFields) = resolveFieldSelection(
389
+ ~blockFields,
390
+ ~transactionFields,
391
+ ~globalBlockFieldsSet,
392
+ ~globalTransactionFieldsSet,
393
+ )
394
+
395
+ {
396
+ id: sighash ++ "_" ++ topicCount->Int.toString,
397
+ name: eventName,
398
+ contractName,
399
+ paramsRawEventSchema: buildParamsSchema(params),
400
+ simulateParamsSchema: buildSimulateParamsSchema(params),
401
+ selectedBlockFields,
402
+ selectedTransactionFields,
403
+ transactionFieldMask: Evm.eventTransactionFieldMask(selectedTransactionFields),
404
+ blockFieldMask: Evm.eventBlockFieldMask(
405
+ selectedBlockFields->(
406
+ Utils.magic: Utils.Set.t<Internal.evmBlockField> => Utils.Set.t<string>
407
+ ),
408
+ ),
409
+ sighash,
410
+ topicCount,
411
+ paramsMetadata: params,
412
+ }
413
+ }
414
+
415
+ // Enrich an EVM definition into a per-(event,chain) registration: resolve the
416
+ // registered `where` (with `probeChainId`) into the lazy `getEventFiltersOrThrow`
417
+ // closure + address filters, and override `startBlock` with `where.block._gte`.
418
+ let buildEvmOnEventRegistration = (
419
+ ~eventConfig: Internal.evmEventConfig,
381
420
  ~isWildcard: bool,
382
421
  ~handler: option<Internal.handler>,
383
422
  ~contractRegister: option<Internal.contractRegister>,
384
423
  ~eventFilters: option<JSON.t>,
385
424
  ~probeChainId: int,
386
425
  ~onEventBlockFilterSchema: S.t<option<unknown>>,
387
- ~blockFields: option<array<Internal.evmBlockField>>=?,
388
- ~transactionFields: option<array<Internal.evmTransactionField>>=?,
389
426
  ~startBlock: option<int>=?,
390
- ~globalBlockFieldsSet: Utils.Set.t<Internal.evmBlockField>=Utils.Set.make(),
391
- ~globalTransactionFieldsSet: Utils.Set.t<Internal.evmTransactionField>=Utils.Set.make(),
392
- ): Internal.evmEventConfig => {
393
- let topicCount = params->Array.reduce(1, (acc, p) => p.indexed ? acc + 1 : acc)
394
- let indexedParams = params->Array.filter(p => p.indexed)
427
+ ): Internal.evmOnEventRegistration => {
428
+ let indexedParams = eventConfig.paramsMetadata->Array.filter(p => p.indexed)
395
429
 
396
430
  let {
397
431
  getEventFiltersOrThrow,
@@ -400,9 +434,9 @@ let buildEvmEventConfig = (
400
434
  startBlock: whereStartBlock,
401
435
  } = LogSelection.parseEventFiltersOrThrow(
402
436
  ~eventFilters,
403
- ~sighash,
437
+ ~sighash=eventConfig.sighash,
404
438
  ~params=indexedParams->Array.map(p => p.name),
405
- ~contractName,
439
+ ~contractName=eventConfig.contractName,
406
440
  ~probeChainId,
407
441
  ~onEventBlockFilterSchema,
408
442
  ~topic1=?indexedParams->Array.get(0)->Option.map(buildTopicGetter),
@@ -410,46 +444,32 @@ let buildEvmEventConfig = (
410
444
  ~topic3=?indexedParams->Array.get(2)->Option.map(buildTopicGetter),
411
445
  )
412
446
 
413
- // `where.block.number._gte` overrides the contract-level startBlock
414
- // when present. The user opts into this explicitly in handler code so
415
- // it should win over the `config.yaml` contract `start_block`; absent
416
- // `where.block`, the caller's contract-level value passes through.
447
+ // `where.block.number._gte` overrides the contract-level startBlock when
448
+ // present (an explicit per-event opt-in that wins over `config.yaml`);
449
+ // otherwise the contract/chain value passes through.
417
450
  let resolvedStartBlock = switch whereStartBlock {
418
451
  | Some(_) as sb => sb
419
452
  | None => startBlock
420
453
  }
421
454
 
422
- let (selectedBlockFields, selectedTransactionFields) = resolveFieldSelection(
423
- ~blockFields,
424
- ~transactionFields,
425
- ~globalBlockFieldsSet,
426
- ~globalTransactionFieldsSet,
427
- )
428
-
429
455
  {
430
- id: sighash ++ "_" ++ topicCount->Int.toString,
431
- name: eventName,
432
- contractName,
456
+ eventConfig: (eventConfig :> Internal.eventConfig),
433
457
  isWildcard,
434
458
  handler,
435
459
  contractRegister,
436
- paramsRawEventSchema: buildParamsSchema(params),
437
- simulateParamsSchema: buildSimulateParamsSchema(params),
438
460
  getEventFiltersOrThrow,
439
461
  filterByAddresses,
440
462
  clientAddressFilter: ?buildAddressFilter(addressFilterParamGroups, ~isWildcard),
441
- dependsOnAddresses: !isWildcard || filterByAddresses,
463
+ dependsOnAddresses: Internal.dependsOnAddresses(~isWildcard, ~filterByAddresses),
442
464
  startBlock: resolvedStartBlock,
443
- selectedBlockFields,
444
- selectedTransactionFields,
445
- transactionFieldMask: Evm.eventTransactionFieldMask(selectedTransactionFields),
446
- sighash,
447
- topicCount,
448
- paramsMetadata: params,
449
465
  }
450
466
  }
451
467
 
452
- // ============== Build Fuel event config ==============
468
+ // ============== Build SVM instruction event config ==============
469
+
470
+ // Always-included block fields (slot, time, hash) are prepended at runtime so
471
+ // they're always present regardless of config.
472
+ let alwaysIncludedSvmBlockFields: array<Internal.svmBlockField> = [Slot, Time, Hash]
453
473
 
454
474
  let buildSvmInstructionEventConfig = (
455
475
  ~contractName: string,
@@ -459,15 +479,12 @@ let buildSvmInstructionEventConfig = (
459
479
  ~discriminatorByteLen: int,
460
480
  ~includeLogs: bool,
461
481
  ~transactionFields: array<Internal.svmTransactionField>=[],
482
+ ~blockFields: array<Internal.svmBlockField>=[],
462
483
  ~accountFilters: array<Internal.svmAccountFilterGroup>,
463
484
  ~isInner: option<bool>,
464
- ~isWildcard: bool,
465
- ~handler: option<Internal.handler>,
466
- ~contractRegister: option<Internal.contractRegister>,
467
485
  ~accounts: array<string>=[],
468
486
  ~args: JSON.t=JSON.Null,
469
487
  ~definedTypes: JSON.t=JSON.Null,
470
- ~startBlock: option<int>=?,
471
488
  ): Internal.svmInstructionEventConfig => {
472
489
  let paramsSchema =
473
490
  S.json(~validate=false)
@@ -480,6 +497,12 @@ let buildSvmInstructionEventConfig = (
480
497
  Utils.Set.fromArray(transactionFields)->(
481
498
  Utils.magic: Utils.Set.t<Internal.svmTransactionField> => Utils.Set.t<string>
482
499
  )
500
+ let selectedBlockFields = Utils.Set.fromArray(
501
+ Array.concat(alwaysIncludedSvmBlockFields, blockFields),
502
+ )
503
+ let blockFieldMask = Svm.eventBlockFieldMask(
504
+ selectedBlockFields->(Utils.magic: Utils.Set.t<Internal.svmBlockField> => Utils.Set.t<string>),
505
+ )
483
506
  {
484
507
  id: switch discriminator {
485
508
  | Some(d) => d
@@ -487,21 +510,16 @@ let buildSvmInstructionEventConfig = (
487
510
  },
488
511
  name: instructionName,
489
512
  contractName,
490
- isWildcard,
491
- handler,
492
- contractRegister,
493
513
  paramsRawEventSchema: paramsSchema,
494
514
  simulateParamsSchema: paramsSchema,
495
- filterByAddresses: false,
496
- dependsOnAddresses: !isWildcard,
497
- clientAddressFilter: ?buildAddressFilter([], ~isWildcard, ~srcAddressExpr="event.programId"),
498
- startBlock,
499
515
  programId,
500
516
  discriminator,
501
517
  discriminatorByteLen,
502
518
  includeLogs,
503
519
  selectedTransactionFields,
504
520
  transactionFieldMask: Svm.eventTransactionFieldMask(selectedTransactionFields),
521
+ selectedBlockFields,
522
+ blockFieldMask,
505
523
  accountFilters,
506
524
  isInner,
507
525
  accounts,
@@ -510,16 +528,33 @@ let buildSvmInstructionEventConfig = (
510
528
  }
511
529
  }
512
530
 
531
+ // Enrich an SVM definition into a registration. SVM has no `where`; only the
532
+ // handler binding + wildcard-derived address gate are registration state.
533
+ let buildSvmOnEventRegistration = (
534
+ ~eventConfig: Internal.svmInstructionEventConfig,
535
+ ~isWildcard: bool,
536
+ ~handler: option<Internal.handler>,
537
+ ~contractRegister: option<Internal.contractRegister>,
538
+ ~startBlock: option<int>=?,
539
+ ): Internal.svmOnEventRegistration => {
540
+ eventConfig: (eventConfig :> Internal.eventConfig),
541
+ handler,
542
+ contractRegister,
543
+ isWildcard,
544
+ filterByAddresses: false,
545
+ dependsOnAddresses: Internal.dependsOnAddresses(~isWildcard, ~filterByAddresses=false),
546
+ clientAddressFilter: ?buildAddressFilter([], ~isWildcard, ~srcAddressExpr="event.programId"),
547
+ startBlock,
548
+ }
549
+
550
+ // ============== Build Fuel event config ==============
551
+
513
552
  let buildFuelEventConfig = (
514
553
  ~contractName: string,
515
554
  ~eventName: string,
516
555
  ~kind: string,
517
556
  ~sighash: string,
518
557
  ~rawAbi: JSON.t,
519
- ~isWildcard: bool,
520
- ~handler: option<Internal.handler>,
521
- ~contractRegister: option<Internal.contractRegister>,
522
- ~startBlock: option<int>=?,
523
558
  ): Internal.fuelEventConfig => {
524
559
  let fuelKind = switch kind {
525
560
  | "logData" =>
@@ -559,18 +594,32 @@ let buildFuelEventConfig = (
559
594
  },
560
595
  name: eventName,
561
596
  contractName,
562
- isWildcard,
563
- handler,
564
- contractRegister,
565
597
  paramsRawEventSchema: paramsSchema,
566
598
  simulateParamsSchema: paramsSchema,
567
- filterByAddresses: false,
568
- dependsOnAddresses: !isWildcard,
569
- clientAddressFilter: ?buildAddressFilter([], ~isWildcard),
570
- startBlock,
571
- // Fuel keeps the transaction inline on the payload; nothing to materialise.
599
+ // Fuel keeps the transaction and block inline on the payload; nothing to
600
+ // materialise.
572
601
  selectedTransactionFields: Utils.Set.make(),
573
602
  transactionFieldMask: 0.,
603
+ blockFieldMask: 0.,
574
604
  kind: fuelKind,
575
605
  }
576
606
  }
607
+
608
+ // Enrich a Fuel definition into a registration (handler binding +
609
+ // wildcard-derived address gate; Fuel never filters by addresses).
610
+ let buildFuelOnEventRegistration = (
611
+ ~eventConfig: Internal.fuelEventConfig,
612
+ ~isWildcard: bool,
613
+ ~handler: option<Internal.handler>,
614
+ ~contractRegister: option<Internal.contractRegister>,
615
+ ~startBlock: option<int>=?,
616
+ ): Internal.fuelOnEventRegistration => {
617
+ eventConfig: (eventConfig :> Internal.eventConfig),
618
+ handler,
619
+ contractRegister,
620
+ isWildcard,
621
+ filterByAddresses: false,
622
+ dependsOnAddresses: Internal.dependsOnAddresses(~isWildcard, ~filterByAddresses=false),
623
+ clientAddressFilter: ?buildAddressFilter([], ~isWildcard),
624
+ startBlock,
625
+ }
@@ -280,7 +280,7 @@ function buildAddressFilter(groups, isWildcard, srcAddressExprOpt) {
280
280
  return Stdlib_Option.map(buildAddressFilterBody(groups, isWildcard, srcAddressExpr), compileAddressFilter);
281
281
  }
282
282
 
283
- function buildEvmEventConfig(contractName, eventName, sighash, params, isWildcard, handler, contractRegister, eventFilters, probeChainId, onEventBlockFilterSchema, blockFields, transactionFields, startBlock, globalBlockFieldsSetOpt, globalTransactionFieldsSetOpt) {
283
+ function buildEvmEventConfig(contractName, eventName, sighash, params, blockFields, transactionFields, globalBlockFieldsSetOpt, globalTransactionFieldsSetOpt) {
284
284
  let globalBlockFieldsSet = globalBlockFieldsSetOpt !== undefined ? Primitive_option.valFromOption(globalBlockFieldsSetOpt) : new Set();
285
285
  let globalTransactionFieldsSet = globalTransactionFieldsSetOpt !== undefined ? Primitive_option.valFromOption(globalTransactionFieldsSetOpt) : new Set();
286
286
  let topicCount = Stdlib_Array.reduce(params, 1, (acc, p) => {
@@ -290,58 +290,70 @@ function buildEvmEventConfig(contractName, eventName, sighash, params, isWildcar
290
290
  return acc;
291
291
  }
292
292
  });
293
- let indexedParams = params.filter(p => p.indexed);
294
- let match = LogSelection.parseEventFiltersOrThrow(eventFilters, sighash, indexedParams.map(p => p.name), contractName, probeChainId, onEventBlockFilterSchema, Stdlib_Option.map(indexedParams[0], buildTopicGetter), Stdlib_Option.map(indexedParams[1], buildTopicGetter), Stdlib_Option.map(indexedParams[2], buildTopicGetter));
295
- let whereStartBlock = match.startBlock;
296
- let filterByAddresses = match.filterByAddresses;
297
- let resolvedStartBlock = whereStartBlock !== undefined ? whereStartBlock : startBlock;
298
- let match$1 = resolveFieldSelection(blockFields, transactionFields, globalBlockFieldsSet, globalTransactionFieldsSet);
299
- let selectedTransactionFields = match$1[1];
293
+ let match = resolveFieldSelection(blockFields, transactionFields, globalBlockFieldsSet, globalTransactionFieldsSet);
294
+ let selectedTransactionFields = match[1];
295
+ let selectedBlockFields = match[0];
300
296
  return {
301
297
  id: sighash + "_" + topicCount.toString(),
302
298
  name: eventName,
303
299
  contractName: contractName,
304
- isWildcard: isWildcard,
305
- filterByAddresses: filterByAddresses,
306
- dependsOnAddresses: !isWildcard || filterByAddresses,
307
- clientAddressFilter: buildAddressFilter(match.addressFilterParamGroups, isWildcard, undefined),
308
- handler: handler,
309
- contractRegister: contractRegister,
310
300
  paramsRawEventSchema: buildParamsSchema(params),
311
301
  simulateParamsSchema: buildSimulateParamsSchema(params),
312
- startBlock: resolvedStartBlock,
313
302
  selectedTransactionFields: selectedTransactionFields,
314
303
  transactionFieldMask: Evm.eventTransactionFieldMask(selectedTransactionFields),
315
- getEventFiltersOrThrow: match.getEventFiltersOrThrow,
316
- selectedBlockFields: match$1[0],
304
+ blockFieldMask: Evm.eventBlockFieldMask(selectedBlockFields),
305
+ selectedBlockFields: selectedBlockFields,
317
306
  sighash: sighash,
318
307
  topicCount: topicCount,
319
308
  paramsMetadata: params
320
309
  };
321
310
  }
322
311
 
323
- function buildSvmInstructionEventConfig(contractName, instructionName, programId, discriminator, discriminatorByteLen, includeLogs, transactionFieldsOpt, accountFilters, isInner, isWildcard, handler, contractRegister, accountsOpt, argsOpt, definedTypesOpt, startBlock) {
312
+ function buildEvmOnEventRegistration(eventConfig, isWildcard, handler, contractRegister, eventFilters, probeChainId, onEventBlockFilterSchema, startBlock) {
313
+ let indexedParams = eventConfig.paramsMetadata.filter(p => p.indexed);
314
+ let match = LogSelection.parseEventFiltersOrThrow(eventFilters, eventConfig.sighash, indexedParams.map(p => p.name), eventConfig.contractName, probeChainId, onEventBlockFilterSchema, Stdlib_Option.map(indexedParams[0], buildTopicGetter), Stdlib_Option.map(indexedParams[1], buildTopicGetter), Stdlib_Option.map(indexedParams[2], buildTopicGetter));
315
+ let whereStartBlock = match.startBlock;
316
+ let filterByAddresses = match.filterByAddresses;
317
+ let resolvedStartBlock = whereStartBlock !== undefined ? whereStartBlock : startBlock;
318
+ return {
319
+ eventConfig: eventConfig,
320
+ handler: handler,
321
+ contractRegister: contractRegister,
322
+ isWildcard: isWildcard,
323
+ filterByAddresses: filterByAddresses,
324
+ dependsOnAddresses: Internal.dependsOnAddresses(isWildcard, filterByAddresses),
325
+ clientAddressFilter: buildAddressFilter(match.addressFilterParamGroups, isWildcard, undefined),
326
+ startBlock: resolvedStartBlock,
327
+ getEventFiltersOrThrow: match.getEventFiltersOrThrow
328
+ };
329
+ }
330
+
331
+ let alwaysIncludedSvmBlockFields = [
332
+ "slot",
333
+ "time",
334
+ "hash"
335
+ ];
336
+
337
+ function buildSvmInstructionEventConfig(contractName, instructionName, programId, discriminator, discriminatorByteLen, includeLogs, transactionFieldsOpt, blockFieldsOpt, accountFilters, isInner, accountsOpt, argsOpt, definedTypesOpt) {
324
338
  let transactionFields = transactionFieldsOpt !== undefined ? transactionFieldsOpt : [];
339
+ let blockFields = blockFieldsOpt !== undefined ? blockFieldsOpt : [];
325
340
  let accounts = accountsOpt !== undefined ? accountsOpt : [];
326
341
  let args = argsOpt !== undefined ? argsOpt : null;
327
342
  let definedTypes = definedTypesOpt !== undefined ? definedTypesOpt : null;
328
343
  let paramsSchema = Utils.Schema.coerceToJsonPgType(S$RescriptSchema.json(false));
329
344
  let selectedTransactionFields = new Set(transactionFields);
345
+ let selectedBlockFields = new Set(alwaysIncludedSvmBlockFields.concat(blockFields));
346
+ let blockFieldMask = Svm.eventBlockFieldMask(selectedBlockFields);
330
347
  return {
331
348
  id: discriminator !== undefined ? discriminator : "none",
332
349
  name: instructionName,
333
350
  contractName: contractName,
334
- isWildcard: isWildcard,
335
- filterByAddresses: false,
336
- dependsOnAddresses: !isWildcard,
337
- clientAddressFilter: buildAddressFilter([], isWildcard, "event.programId"),
338
- handler: handler,
339
- contractRegister: contractRegister,
340
351
  paramsRawEventSchema: paramsSchema,
341
352
  simulateParamsSchema: paramsSchema,
342
- startBlock: startBlock,
343
353
  selectedTransactionFields: selectedTransactionFields,
344
354
  transactionFieldMask: Svm.eventTransactionFieldMask(selectedTransactionFields),
355
+ blockFieldMask: blockFieldMask,
356
+ selectedBlockFields: selectedBlockFields,
345
357
  programId: programId,
346
358
  discriminator: discriminator,
347
359
  discriminatorByteLen: discriminatorByteLen,
@@ -354,7 +366,20 @@ function buildSvmInstructionEventConfig(contractName, instructionName, programId
354
366
  };
355
367
  }
356
368
 
357
- function buildFuelEventConfig(contractName, eventName, kind, sighash, rawAbi, isWildcard, handler, contractRegister, startBlock) {
369
+ function buildSvmOnEventRegistration(eventConfig, isWildcard, handler, contractRegister, startBlock) {
370
+ return {
371
+ eventConfig: eventConfig,
372
+ handler: handler,
373
+ contractRegister: contractRegister,
374
+ isWildcard: isWildcard,
375
+ filterByAddresses: false,
376
+ dependsOnAddresses: Internal.dependsOnAddresses(isWildcard, false),
377
+ clientAddressFilter: buildAddressFilter([], isWildcard, "event.programId"),
378
+ startBlock: startBlock
379
+ };
380
+ }
381
+
382
+ function buildFuelEventConfig(contractName, eventName, kind, sighash, rawAbi) {
358
383
  let fuelKind;
359
384
  switch (kind) {
360
385
  case "burn" :
@@ -401,21 +426,28 @@ function buildFuelEventConfig(contractName, eventName, kind, sighash, rawAbi, is
401
426
  id: tmp,
402
427
  name: eventName,
403
428
  contractName: contractName,
404
- isWildcard: isWildcard,
405
- filterByAddresses: false,
406
- dependsOnAddresses: !isWildcard,
407
- clientAddressFilter: buildAddressFilter([], isWildcard, undefined),
408
- handler: handler,
409
- contractRegister: contractRegister,
410
429
  paramsRawEventSchema: paramsSchema,
411
430
  simulateParamsSchema: paramsSchema,
412
- startBlock: startBlock,
413
431
  selectedTransactionFields: new Set(),
414
432
  transactionFieldMask: 0,
433
+ blockFieldMask: 0,
415
434
  kind: fuelKind
416
435
  };
417
436
  }
418
437
 
438
+ function buildFuelOnEventRegistration(eventConfig, isWildcard, handler, contractRegister, startBlock) {
439
+ return {
440
+ eventConfig: eventConfig,
441
+ handler: handler,
442
+ contractRegister: contractRegister,
443
+ isWildcard: isWildcard,
444
+ filterByAddresses: false,
445
+ dependsOnAddresses: Internal.dependsOnAddresses(isWildcard, false),
446
+ clientAddressFilter: buildAddressFilter([], isWildcard, undefined),
447
+ startBlock: startBlock
448
+ };
449
+ }
450
+
419
451
  export {
420
452
  paramMetaSchema,
421
453
  normalizeOrThrow,
@@ -435,7 +467,11 @@ export {
435
467
  buildAddressFilterBody,
436
468
  buildAddressFilter,
437
469
  buildEvmEventConfig,
470
+ buildEvmOnEventRegistration,
471
+ alwaysIncludedSvmBlockFields,
438
472
  buildSvmInstructionEventConfig,
473
+ buildSvmOnEventRegistration,
439
474
  buildFuelEventConfig,
475
+ buildFuelOnEventRegistration,
440
476
  }
441
477
  /* paramMetaSchema Not a pure module */