envio 3.3.2 → 3.4.0

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 (60) hide show
  1. package/package.json +6 -6
  2. package/src/Api.res +1 -8
  3. package/src/Api.res.mjs +1 -5
  4. package/src/ChainState.res +6 -1
  5. package/src/ChainState.res.mjs +4 -3
  6. package/src/Config.res +33 -4
  7. package/src/Config.res.mjs +34 -5
  8. package/src/Core.res +30 -19
  9. package/src/Core.res.mjs +5 -5
  10. package/src/EnvioGlobal.res +0 -2
  11. package/src/EnvioGlobal.res.mjs +0 -1
  12. package/src/ExitOnCaughtUp.res +6 -2
  13. package/src/ExitOnCaughtUp.res.mjs +4 -0
  14. package/src/FetchState.res +3 -3
  15. package/src/HandlerRegister.res +357 -434
  16. package/src/HandlerRegister.res.mjs +202 -242
  17. package/src/HandlerRegister.resi +7 -15
  18. package/src/IndexerState.res +10 -0
  19. package/src/IndexerState.res.mjs +9 -3
  20. package/src/IndexerState.resi +3 -0
  21. package/src/Internal.res +10 -1
  22. package/src/Main.res.mjs +4 -4
  23. package/src/PgStorage.res +16 -1
  24. package/src/PgStorage.res.mjs +9 -1
  25. package/src/SimulateItems.res +61 -40
  26. package/src/SimulateItems.res.mjs +37 -21
  27. package/src/TestIndexer.res +446 -453
  28. package/src/TestIndexer.res.mjs +320 -343
  29. package/src/bindings/ClickHouse.res +68 -2
  30. package/src/bindings/ClickHouse.res.mjs +47 -2
  31. package/src/sources/EvmChain.res +1 -1
  32. package/src/sources/EvmChain.res.mjs +2 -2
  33. package/src/sources/FuelHyperSync.res +74 -0
  34. package/src/sources/FuelHyperSync.res.mjs +80 -0
  35. package/src/sources/FuelHyperSync.resi +22 -0
  36. package/src/sources/FuelHyperSyncClient.res +120 -0
  37. package/src/sources/FuelHyperSyncClient.res.mjs +71 -0
  38. package/src/sources/FuelHyperSyncSource.res +257 -0
  39. package/src/sources/FuelHyperSyncSource.res.mjs +252 -0
  40. package/src/sources/HyperSyncClient.res +2 -2
  41. package/src/sources/HyperSyncClient.res.mjs +1 -1
  42. package/src/sources/SvmHyperSyncClient.res +139 -102
  43. package/src/sources/SvmHyperSyncClient.res.mjs +45 -5
  44. package/src/sources/SvmHyperSyncSource.res +60 -440
  45. package/src/sources/SvmHyperSyncSource.res.mjs +42 -363
  46. package/src/TestIndexerProxyStorage.res +0 -196
  47. package/src/TestIndexerProxyStorage.res.mjs +0 -121
  48. package/src/TestIndexerWorker.res +0 -4
  49. package/src/TestIndexerWorker.res.mjs +0 -7
  50. package/src/sources/EventRouter.res +0 -165
  51. package/src/sources/EventRouter.res.mjs +0 -153
  52. package/src/sources/HyperFuel.res +0 -179
  53. package/src/sources/HyperFuel.res.mjs +0 -146
  54. package/src/sources/HyperFuel.resi +0 -36
  55. package/src/sources/HyperFuelClient.res +0 -127
  56. package/src/sources/HyperFuelClient.res.mjs +0 -20
  57. package/src/sources/HyperFuelSource.res +0 -502
  58. package/src/sources/HyperFuelSource.res.mjs +0 -481
  59. /package/src/sources/{HyperSyncSource.res → EvmHyperSyncSource.res} +0 -0
  60. /package/src/sources/{HyperSyncSource.res.mjs → EvmHyperSyncSource.res.mjs} +0 -0
@@ -1,121 +0,0 @@
1
- // Generated by ReScript, PLEASE EDIT WITH CARE
2
-
3
- import * as Table from "./db/Table.res.mjs";
4
- import * as Stdlib_Dict from "@rescript/runtime/lib/es6/Stdlib_Dict.js";
5
- import * as EntityFilter from "./db/EntityFilter.res.mjs";
6
- import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
7
- import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
8
-
9
- function make(parentPort, initialState) {
10
- let proxy = {
11
- parentPort: parentPort,
12
- initialState: initialState,
13
- pendingRequests: {},
14
- requestCounter: 0
15
- };
16
- parentPort.on("message", msg => {
17
- let idStr = msg.id.toString();
18
- let pending = proxy.pendingRequests[idStr];
19
- let match = pending !== undefined ? pending : Stdlib_JsError.throwWithMessage(`TestIndexer: No pending request found for id ` + idStr);
20
- Stdlib_Dict.$$delete(proxy.pendingRequests, idStr);
21
- let match$1 = msg.payload;
22
- if (match$1.type === "response") {
23
- return match.resolve(match$1.data);
24
- } else {
25
- return match.reject(new Error(match$1.message));
26
- }
27
- });
28
- return proxy;
29
- }
30
-
31
- function nextRequestId(proxy) {
32
- proxy.requestCounter = proxy.requestCounter + 1 | 0;
33
- return proxy.requestCounter;
34
- }
35
-
36
- function sendRequest(proxy, payload) {
37
- return new Promise((resolve, reject) => {
38
- let id = nextRequestId(proxy);
39
- proxy.pendingRequests[id.toString()] = {
40
- resolve: resolve,
41
- reject: reject
42
- };
43
- proxy.parentPort.postMessage({
44
- id: id,
45
- payload: payload
46
- });
47
- });
48
- }
49
-
50
- function makeStorage(proxy) {
51
- return {
52
- name: "test-proxy",
53
- isInitialized: async () => true,
54
- initialize: async (param, param$1, param$2, param$3) => Stdlib_JsError.throwWithMessage("TestIndexer: initialize should not be called. Use resumeInitialState instead."),
55
- resumeInitialState: async () => proxy.initialState,
56
- loadOrThrow: async (filter, table) => {
57
- let serializeLeafOrThrow = (fieldName, fieldValue, isArray) => {
58
- let queryField = Table.queryFields(table)[fieldName];
59
- let queryField$1 = queryField !== undefined ? queryField : Stdlib_JsError.throwWithMessage(`TestIndexer: The table "` + table.tableName + `" doesn't have the field "` + fieldName + `"`);
60
- return S$RescriptSchema.reverseConvertToJsonOrThrow(fieldValue, isArray ? queryField$1.arrayFieldSchema : queryField$1.fieldSchema);
61
- };
62
- let response = await sendRequest(proxy, {
63
- type: "load",
64
- tableName: table.tableName,
65
- filter: EntityFilter.mapValues(filter, serializeLeafOrThrow)
66
- });
67
- return S$RescriptSchema.parseOrThrow(response, Table.rowsSchema(table));
68
- },
69
- dumpEffectCache: async () => {},
70
- reset: async () => {},
71
- setChainMeta: async param => {},
72
- pruneStaleCheckpoints: async param => {},
73
- pruneStaleEntityHistory: async (param, param$1, param$2) => {},
74
- getRollbackTargetCheckpoint: async (param, param$1) => Stdlib_JsError.throwWithMessage("TestIndexer: Rollback is not supported. Set rollbackOnReorg to false in config."),
75
- getRollbackProgressDiff: async param => Stdlib_JsError.throwWithMessage("TestIndexer: Rollback is not supported. Set rollbackOnReorg to false in config."),
76
- getRollbackData: async (param, param$1) => Stdlib_JsError.throwWithMessage("TestIndexer: Rollback is not supported. Set rollbackOnReorg to false in config."),
77
- writeBatch: async (batch, param, param$1, param$2, param$3, param$4, updatedEntities, param$5, param$6) => {
78
- let serializableEntities = updatedEntities.map(param => {
79
- let entityConfig = param.entityConfig;
80
- let encodeChange = change => {
81
- if (change.type === "SET") {
82
- return {
83
- type: "SET",
84
- entityId: change.entityId,
85
- entity: S$RescriptSchema.reverseConvertToJsonOrThrow(change.entity, entityConfig.schema),
86
- checkpointId: change.checkpointId
87
- };
88
- } else {
89
- return {
90
- type: "DELETE",
91
- entityId: change.entityId,
92
- checkpointId: change.checkpointId
93
- };
94
- }
95
- };
96
- return {
97
- entityName: entityConfig.name,
98
- changes: param.changes.map(encodeChange)
99
- };
100
- });
101
- await sendRequest(proxy, {
102
- type: "writeBatch",
103
- updatedEntities: serializableEntities,
104
- checkpointIds: batch.checkpointIds,
105
- checkpointChainIds: batch.checkpointChainIds,
106
- checkpointBlockNumbers: batch.checkpointBlockNumbers,
107
- checkpointBlockHashes: batch.checkpointBlockHashes,
108
- checkpointEventsProcessed: batch.checkpointEventsProcessed
109
- });
110
- },
111
- close: async () => {}
112
- };
113
- }
114
-
115
- export {
116
- make,
117
- nextRequestId,
118
- sendRequest,
119
- makeStorage,
120
- }
121
- /* Table Not a pure module */
@@ -1,4 +0,0 @@
1
- // Spawned by `TestIndexer.makeCreateTestIndexer` as a sibling of `Api.res.mjs`
2
- // so `import.meta.url` resolves inside the envio package.
3
-
4
- TestIndexer.initTestWorker()
@@ -1,7 +0,0 @@
1
- // Generated by ReScript, PLEASE EDIT WITH CARE
2
-
3
- import * as TestIndexer from "./TestIndexer.res.mjs";
4
-
5
- TestIndexer.initTestWorker();
6
-
7
- /* Not a pure module */
@@ -1,165 +0,0 @@
1
- exception EventDuplicate
2
- exception WildcardCollision
3
-
4
- module Group = {
5
- type t<'a> = {
6
- mutable wildcard: option<'a>,
7
- byContractName: dict<'a>,
8
- }
9
-
10
- let empty = () => {
11
- wildcard: None,
12
- byContractName: Dict.make(),
13
- }
14
-
15
- let addOrThrow = (group: t<'a>, event, ~contractName, ~isWildcard) => {
16
- let {byContractName, wildcard} = group
17
- switch byContractName->Utils.Dict.dangerouslyGetNonOption(contractName) {
18
- | Some(_) => throw(EventDuplicate)
19
- | None =>
20
- if isWildcard && wildcard->Option.isSome {
21
- throw(WildcardCollision)
22
- } else {
23
- if isWildcard {
24
- group.wildcard = Some(event)
25
- }
26
- byContractName->Dict.set(contractName, event)
27
- }
28
- }
29
- }
30
-
31
- // Ownership only: resolve the owning contract from the partition's reverse
32
- // index (the partition that fetched the log), not a chain-wide snapshot. The
33
- // `effectiveStartBlock` temporal gate now lives in `clientAddressFilter`. The
34
- // wildcard partition has an empty index → every log falls back to `wildcard`,
35
- // so it can never claim an address-bound contract's logs.
36
- let get = (group: t<'a>, ~contractAddress, ~contractNameByAddress: dict<string>) =>
37
- switch group {
38
- | {wildcard, byContractName} =>
39
- switch contractNameByAddress->Utils.Dict.dangerouslyGetNonOption(
40
- contractAddress->Address.toString,
41
- ) {
42
- | Some(contractName) =>
43
- switch byContractName->Utils.Dict.dangerouslyGetNonOption(contractName) {
44
- // Fall back to the wildcard handler when the owning contract has no
45
- // matching event for this tag. This covers addresses registered for
46
- // contracts without events (persisted for future config changes) as
47
- // well as addresses whose contract has other events but not this one.
48
- | None => wildcard
49
- | Some(_) as event => event
50
- }
51
- | None => wildcard
52
- }
53
- }
54
- }
55
-
56
- type t<'a> = dict<Group.t<'a>>
57
-
58
- let empty = () => Dict.make()
59
-
60
- let addOrThrow = (
61
- router: t<'a>,
62
- eventId,
63
- event,
64
- ~contractName,
65
- ~isWildcard,
66
- ~eventName,
67
- ~chain,
68
- ) => {
69
- let group = switch router->Utils.Dict.dangerouslyGetNonOption(eventId) {
70
- | None =>
71
- let group = Group.empty()
72
- router->Dict.set(eventId, group)
73
- group
74
- | Some(group) => group
75
- }
76
- try group->Group.addOrThrow(event, ~contractName, ~isWildcard) catch {
77
- | EventDuplicate =>
78
- JsError.throwWithMessage(
79
- `Duplicate event detected: ${eventName} for contract ${contractName} on chain ${chain->ChainMap.Chain.toString}`,
80
- )
81
- | WildcardCollision =>
82
- JsError.throwWithMessage(
83
- `Another event is already registered with the same signature that would interfer with wildcard filtering: ${eventName} for contract ${contractName} on chain ${chain->ChainMap.Chain.toString}`,
84
- )
85
- }
86
- }
87
-
88
- let get = (router: t<'a>, ~tag, ~contractAddress, ~contractNameByAddress) => {
89
- switch router->Utils.Dict.dangerouslyGetNonOption(tag) {
90
- | None => None
91
- | Some(group) => group->Group.get(~contractAddress, ~contractNameByAddress)
92
- }
93
- }
94
-
95
- /** Dispatch key for SVM instructions. `None` matches any instruction in the
96
- program (lowest priority). */
97
- let getSvmEventId = (~programId: SvmTypes.Pubkey.t, ~discriminator: option<string>) =>
98
- switch discriminator {
99
- | None => programId->SvmTypes.Pubkey.toString ++ "_none"
100
- | Some(d) => programId->SvmTypes.Pubkey.toString ++ "_" ++ d
101
- }
102
-
103
- /** Discriminator byte-lengths declared by a program, sorted descending. The
104
- source uses this to probe `(programId, dN)` keys longest-first when routing
105
- a returned instruction to a handler — matching the locked Q1 answer. */
106
- type svmProgramOrdering = {
107
- programId: SvmTypes.Pubkey.t,
108
- /** Byte lengths in descending order, deduplicated. Includes `0` only when
109
- a handler is registered with no discriminator (program-wide match). */
110
- byteLengthsDesc: array<int>,
111
- }
112
-
113
- let fromSvmEventConfigsOrThrow = (events: array<Internal.svmOnEventRegistration>, ~chain): (
114
- t<Internal.svmOnEventRegistration>,
115
- array<svmProgramOrdering>,
116
- ) => {
117
- let router = empty()
118
- events->Array.forEach(config => {
119
- let eventConfig =
120
- config.eventConfig->(Utils.magic: Internal.eventConfig => Internal.svmInstructionEventConfig)
121
- // The router tag must include the programId so two programs declaring the
122
- // same discriminator coexist. The source-side lookup uses the same shape
123
- // via `getSvmEventId(~programId, ~discriminator)`.
124
- let routerTag = getSvmEventId(
125
- ~programId=eventConfig.programId,
126
- ~discriminator=eventConfig.discriminator,
127
- )
128
- router->addOrThrow(
129
- routerTag,
130
- config,
131
- ~contractName=eventConfig.contractName,
132
- ~eventName=eventConfig.name,
133
- ~chain,
134
- ~isWildcard=config.isWildcard,
135
- )
136
- })
137
-
138
- // Per-program list of declared discriminator byte lengths, sorted desc.
139
- let byProgram: dict<Utils.Set.t<int>> = Dict.make()
140
- events->Array.forEach(config => {
141
- let eventConfig =
142
- config.eventConfig->(Utils.magic: Internal.eventConfig => Internal.svmInstructionEventConfig)
143
- let key = eventConfig.programId->SvmTypes.Pubkey.toString
144
- let set = switch byProgram->Utils.Dict.dangerouslyGetNonOption(key) {
145
- | Some(s) => s
146
- | None =>
147
- let s = Utils.Set.make()
148
- byProgram->Dict.set(key, s)
149
- s
150
- }
151
- let _ = set->Utils.Set.add(eventConfig.discriminatorByteLen)
152
- })
153
- let ordering =
154
- byProgram
155
- ->Dict.toArray
156
- ->Array.map(((programIdString, lens)) => {
157
- let sorted = lens->Utils.Set.toArray->Array.toSorted((a, b) => (b - a)->Int.toFloat)
158
- {
159
- programId: programIdString->SvmTypes.Pubkey.fromStringUnsafe,
160
- byteLengthsDesc: sorted,
161
- }
162
- })
163
-
164
- (router, ordering)
165
- }
@@ -1,153 +0,0 @@
1
- // Generated by ReScript, PLEASE EDIT WITH CARE
2
-
3
- import * as ChainMap from "../ChainMap.res.mjs";
4
- import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
5
- import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
6
- import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
7
- import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
8
-
9
- let EventDuplicate = /* @__PURE__ */Primitive_exceptions.create("EventRouter.EventDuplicate");
10
-
11
- let WildcardCollision = /* @__PURE__ */Primitive_exceptions.create("EventRouter.WildcardCollision");
12
-
13
- function empty() {
14
- return {
15
- wildcard: undefined,
16
- byContractName: {}
17
- };
18
- }
19
-
20
- function addOrThrow(group, event, contractName, isWildcard) {
21
- let wildcard = group.wildcard;
22
- let byContractName = group.byContractName;
23
- let match = byContractName[contractName];
24
- if (match !== undefined) {
25
- throw {
26
- RE_EXN_ID: EventDuplicate,
27
- Error: new Error()
28
- };
29
- }
30
- if (isWildcard && Stdlib_Option.isSome(wildcard)) {
31
- throw {
32
- RE_EXN_ID: WildcardCollision,
33
- Error: new Error()
34
- };
35
- }
36
- if (isWildcard) {
37
- group.wildcard = Primitive_option.some(event);
38
- }
39
- byContractName[contractName] = event;
40
- }
41
-
42
- function get(group, contractAddress, contractNameByAddress) {
43
- let wildcard = group.wildcard;
44
- let contractName = contractNameByAddress[contractAddress];
45
- if (contractName === undefined) {
46
- return wildcard;
47
- }
48
- let event = group.byContractName[contractName];
49
- if (event !== undefined) {
50
- return event;
51
- } else {
52
- return wildcard;
53
- }
54
- }
55
-
56
- let Group = {
57
- empty: empty,
58
- addOrThrow: addOrThrow,
59
- get: get
60
- };
61
-
62
- function empty$1() {
63
- return {};
64
- }
65
-
66
- function addOrThrow$1(router, eventId, event, contractName, isWildcard, eventName, chain) {
67
- let group = router[eventId];
68
- let group$1;
69
- if (group !== undefined) {
70
- group$1 = group;
71
- } else {
72
- let group$2 = {
73
- wildcard: undefined,
74
- byContractName: {}
75
- };
76
- router[eventId] = group$2;
77
- group$1 = group$2;
78
- }
79
- try {
80
- return addOrThrow(group$1, event, contractName, isWildcard);
81
- } catch (raw_exn) {
82
- let exn = Primitive_exceptions.internalToException(raw_exn);
83
- if (exn.RE_EXN_ID === EventDuplicate) {
84
- return Stdlib_JsError.throwWithMessage(`Duplicate event detected: ` + eventName + ` for contract ` + contractName + ` on chain ` + ChainMap.Chain.toString(chain));
85
- }
86
- if (exn.RE_EXN_ID === WildcardCollision) {
87
- return Stdlib_JsError.throwWithMessage(`Another event is already registered with the same signature that would interfer with wildcard filtering: ` + eventName + ` for contract ` + contractName + ` on chain ` + ChainMap.Chain.toString(chain));
88
- }
89
- throw exn;
90
- }
91
- }
92
-
93
- function get$1(router, tag, contractAddress, contractNameByAddress) {
94
- let group = router[tag];
95
- if (group !== undefined) {
96
- return get(group, contractAddress, contractNameByAddress);
97
- }
98
- }
99
-
100
- function getSvmEventId(programId, discriminator) {
101
- if (discriminator !== undefined) {
102
- return programId + "_" + discriminator;
103
- } else {
104
- return programId + "_none";
105
- }
106
- }
107
-
108
- function fromSvmEventConfigsOrThrow(events, chain) {
109
- let router = {};
110
- events.forEach(config => {
111
- let eventConfig = config.eventConfig;
112
- let routerTag = getSvmEventId(eventConfig.programId, eventConfig.discriminator);
113
- addOrThrow$1(router, routerTag, config, eventConfig.contractName, config.isWildcard, eventConfig.name, chain);
114
- });
115
- let byProgram = {};
116
- events.forEach(config => {
117
- let eventConfig = config.eventConfig;
118
- let key = eventConfig.programId;
119
- let s = byProgram[key];
120
- let set;
121
- if (s !== undefined) {
122
- set = Primitive_option.valFromOption(s);
123
- } else {
124
- let s$1 = new Set();
125
- byProgram[key] = s$1;
126
- set = s$1;
127
- }
128
- set.add(eventConfig.discriminatorByteLen);
129
- });
130
- let ordering = Object.entries(byProgram).map(param => {
131
- let sorted = Array.from(param[1]).toSorted((a, b) => b - a | 0);
132
- return {
133
- programId: param[0],
134
- byteLengthsDesc: sorted
135
- };
136
- });
137
- return [
138
- router,
139
- ordering
140
- ];
141
- }
142
-
143
- export {
144
- EventDuplicate,
145
- WildcardCollision,
146
- Group,
147
- empty$1 as empty,
148
- addOrThrow$1 as addOrThrow,
149
- get$1 as get,
150
- getSvmEventId,
151
- fromSvmEventConfigsOrThrow,
152
- }
153
- /* ChainMap Not a pure module */
@@ -1,179 +0,0 @@
1
- type hyperSyncPage<'item> = {
2
- items: array<'item>,
3
- nextBlock: int,
4
- archiveHeight: int,
5
- }
6
-
7
- type block = {
8
- id: string,
9
- time: int,
10
- height: int,
11
- }
12
-
13
- type item = {
14
- transactionId: string,
15
- contractId: Address.t,
16
- receipt: FuelSDK.Receipt.t,
17
- receiptIndex: int,
18
- block: block,
19
- }
20
-
21
- type logsQueryPage = hyperSyncPage<item>
22
-
23
- module GetLogs = {
24
- type error =
25
- | UnexpectedMissingParams({missingParams: array<string>})
26
- | WrongInstance
27
-
28
- exception Error(error)
29
-
30
- // Rust encodes structured failures as a JSON payload in the napi error's
31
- // message: `{"kind":"MissingFields","fields":["receipt.txId", ...]}`.
32
- // JSON.parse + shape check is the recovery protocol — no string-grepping
33
- // on anyhow's Debug format.
34
- let extractMissingParams = (exn: exn): option<array<string>> => {
35
- let message = switch exn {
36
- | JsExn(jsExn) => jsExn->JsExn.message
37
- | _ => None
38
- }
39
- switch message {
40
- | None => None
41
- | Some(msg) =>
42
- switch msg->JSON.parseOrThrow->JSON.Decode.object {
43
- | exception _ => None
44
- | None => None
45
- | Some(obj) =>
46
- switch (obj->Dict.get("kind"), obj->Dict.get("fields")) {
47
- | (Some(String("MissingFields")), Some(Array(fields))) =>
48
- Some(fields->Array.filterMap(JSON.Decode.string))
49
- | _ => None
50
- }
51
- }
52
- }
53
- }
54
-
55
- let makeRequestBody = (
56
- ~fromBlock,
57
- ~toBlockInclusive,
58
- ~recieptsSelection,
59
- ): HyperFuelClient.QueryTypes.query => {
60
- {
61
- fromBlock,
62
- toBlockExclusive: ?switch toBlockInclusive {
63
- | Some(toBlockInclusive) => Some(toBlockInclusive + 1)
64
- | None => None
65
- },
66
- receipts: recieptsSelection,
67
- fieldSelection: {
68
- receipt: [
69
- TxId,
70
- BlockHeight,
71
- RootContractId,
72
- Data,
73
- ReceiptIndex,
74
- ReceiptType,
75
- Rb,
76
- // TODO: Include them only when there's a mint/burn/transferOut receipt selection
77
- SubId,
78
- Val,
79
- Amount,
80
- ToAddress,
81
- AssetId,
82
- To,
83
- ],
84
- block: [Id, Height, Time],
85
- },
86
- }
87
- }
88
-
89
- let getParam = (param, name) => {
90
- switch param {
91
- | Some(v) => v
92
- | None =>
93
- throw(
94
- Error(
95
- UnexpectedMissingParams({
96
- missingParams: [name],
97
- }),
98
- ),
99
- )
100
- }
101
- }
102
-
103
- //Note this function can throw an error
104
- let decodeLogQueryPageItems = (response_data: HyperFuelClient.queryResponseDataTyped): array<
105
- item,
106
- > => {
107
- let {receipts, blocks} = response_data
108
-
109
- let blocksDict = Dict.make()
110
- blocks->Array.forEach(block => {
111
- blocksDict->Dict.set(block.height->(Utils.magic: int => string), block)
112
- })
113
-
114
- let items = []
115
-
116
- receipts->Array.forEach(receipt => {
117
- switch receipt.rootContractId {
118
- | None => ()
119
- | Some(contractId) => {
120
- let block =
121
- blocksDict
122
- ->Utils.Dict.dangerouslyGetNonOption(receipt.blockHeight->(Utils.magic: int => string))
123
- ->getParam("Failed to find block associated to receipt")
124
- items
125
- ->Array.push({
126
- transactionId: receipt.txId,
127
- block: {
128
- height: block.height,
129
- id: block.id,
130
- time: block.time,
131
- },
132
- contractId,
133
- receipt: receipt->(Utils.magic: HyperFuelClient.FuelTypes.receipt => FuelSDK.Receipt.t),
134
- receiptIndex: receipt.receiptIndex,
135
- })
136
- ->ignore
137
- }
138
- }
139
- })
140
- items
141
- }
142
-
143
- let convertResponse = (res: HyperFuelClient.queryResponseTyped): logsQueryPage => {
144
- let {nextBlock, ?archiveHeight} = res
145
- let page: logsQueryPage = {
146
- items: res.data->decodeLogQueryPageItems,
147
- nextBlock,
148
- archiveHeight: archiveHeight->Option.getOr(0), // TODO: FIXME: Shouldn't have a default here
149
- }
150
- page
151
- }
152
-
153
- let query = async (
154
- ~client: HyperFuelClient.t,
155
- ~fromBlock,
156
- ~toBlock,
157
- ~recieptsSelection,
158
- ): logsQueryPage => {
159
- let query: HyperFuelClient.QueryTypes.query = makeRequestBody(
160
- ~fromBlock,
161
- ~toBlockInclusive=toBlock,
162
- ~recieptsSelection,
163
- )
164
-
165
- let res = switch await client->HyperFuelClient.getSelectedData(query) {
166
- | res => res
167
- | exception exn =>
168
- switch exn->extractMissingParams {
169
- | Some(missingParams) => throw(Error(UnexpectedMissingParams({missingParams: missingParams})))
170
- | None => throw(exn)
171
- }
172
- }
173
- if res.nextBlock <= fromBlock {
174
- // Might happen when /height response was from another instance of HyperFuel
175
- throw(Error(WrongInstance))
176
- }
177
- res->convertResponse
178
- }
179
- }