envio 3.3.2 → 3.5.0-alpha.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.
- package/package.json +6 -6
- package/src/Api.res +1 -8
- package/src/Api.res.mjs +1 -5
- package/src/Bin.res +2 -2
- package/src/ChainState.res +6 -1
- package/src/ChainState.res.mjs +4 -3
- package/src/Config.res +38 -5
- package/src/Config.res.mjs +35 -6
- package/src/Core.res +65 -20
- package/src/Core.res.mjs +36 -6
- package/src/EnvioGlobal.res +0 -2
- package/src/EnvioGlobal.res.mjs +0 -1
- package/src/ExitOnCaughtUp.res +6 -2
- package/src/ExitOnCaughtUp.res.mjs +4 -0
- package/src/FetchState.res +3 -3
- package/src/HandlerRegister.res +357 -434
- package/src/HandlerRegister.res.mjs +202 -242
- package/src/HandlerRegister.resi +7 -15
- package/src/IndexerState.res +10 -0
- package/src/IndexerState.res.mjs +9 -3
- package/src/IndexerState.resi +3 -0
- package/src/Internal.res +10 -1
- package/src/Main.res.mjs +4 -4
- package/src/PgStorage.res +16 -1
- package/src/PgStorage.res.mjs +9 -1
- package/src/SimulateItems.res +61 -40
- package/src/SimulateItems.res.mjs +37 -21
- package/src/TestIndexer.res +453 -454
- package/src/TestIndexer.res.mjs +321 -344
- package/src/bindings/ClickHouse.res +68 -2
- package/src/bindings/ClickHouse.res.mjs +47 -2
- package/src/sources/EvmChain.res +1 -1
- package/src/sources/EvmChain.res.mjs +2 -2
- package/src/sources/FuelHyperSync.res +74 -0
- package/src/sources/FuelHyperSync.res.mjs +80 -0
- package/src/sources/FuelHyperSync.resi +22 -0
- package/src/sources/FuelHyperSyncClient.res +120 -0
- package/src/sources/FuelHyperSyncClient.res.mjs +71 -0
- package/src/sources/FuelHyperSyncSource.res +257 -0
- package/src/sources/FuelHyperSyncSource.res.mjs +252 -0
- package/src/sources/HyperSyncClient.res +2 -2
- package/src/sources/HyperSyncClient.res.mjs +1 -1
- package/src/sources/SvmHyperSyncClient.res +139 -102
- package/src/sources/SvmHyperSyncClient.res.mjs +45 -5
- package/src/sources/SvmHyperSyncSource.res +60 -440
- package/src/sources/SvmHyperSyncSource.res.mjs +42 -363
- package/src/TestIndexerProxyStorage.res +0 -196
- package/src/TestIndexerProxyStorage.res.mjs +0 -121
- package/src/TestIndexerWorker.res +0 -4
- package/src/TestIndexerWorker.res.mjs +0 -7
- package/src/sources/EventRouter.res +0 -165
- package/src/sources/EventRouter.res.mjs +0 -153
- package/src/sources/HyperFuel.res +0 -179
- package/src/sources/HyperFuel.res.mjs +0 -146
- package/src/sources/HyperFuel.resi +0 -36
- package/src/sources/HyperFuelClient.res +0 -127
- package/src/sources/HyperFuelClient.res.mjs +0 -20
- package/src/sources/HyperFuelSource.res +0 -502
- package/src/sources/HyperFuelSource.res.mjs +0 -481
- /package/src/sources/{HyperSyncSource.res → EvmHyperSyncSource.res} +0 -0
- /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,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
|
-
}
|