envio 3.0.2-svm-alpha.0 → 3.0.2
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/evm.schema.json +8 -8
- package/fuel.schema.json +12 -12
- package/index.d.ts +1 -155
- package/package.json +7 -6
- package/src/ChainFetcher.res +1 -25
- package/src/ChainFetcher.res.mjs +1 -19
- package/src/Config.res +94 -156
- package/src/Config.res.mjs +97 -60
- package/src/Core.res +0 -32
- package/src/Env.res.mjs +2 -1
- package/src/Envio.res +0 -94
- package/src/EventConfigBuilder.res +25 -63
- package/src/EventConfigBuilder.res.mjs +8 -37
- package/src/HandlerLoader.res +1 -12
- package/src/HandlerLoader.res.mjs +1 -6
- package/src/Internal.res +0 -38
- package/src/Main.res +3 -53
- package/src/Main.res.mjs +2 -34
- package/src/Persistence.res +17 -2
- package/src/Persistence.res.mjs +14 -2
- package/src/SimulateItems.res +10 -23
- package/src/SimulateItems.res.mjs +6 -21
- package/src/bindings/ClickHouse.res +6 -2
- package/src/bindings/ClickHouse.res.mjs +3 -2
- package/src/sources/EventRouter.res +0 -65
- package/src/sources/EventRouter.res.mjs +0 -43
- package/src/sources/HyperSyncClient.res +157 -30
- package/src/sources/HyperSyncClient.res.mjs +6 -20
- package/src/sources/HyperSyncSource.res +8 -5
- package/src/sources/HyperSyncSource.res.mjs +8 -1
- package/src/sources/RpcSource.res.mjs +1 -1
- package/src/sources/Svm.res +2 -2
- package/src/sources/Svm.res.mjs +2 -3
- package/src/tui/Tui.res +2 -9
- package/src/tui/Tui.res.mjs +4 -19
- package/src/tui/components/TuiData.res +0 -3
- package/svm.schema.json +4 -345
- package/src/SvmTypes.res +0 -9
- package/src/SvmTypes.res.mjs +0 -14
- package/src/sources/HyperSyncSolanaClient.res +0 -227
- package/src/sources/HyperSyncSolanaClient.res.mjs +0 -25
- package/src/sources/HyperSyncSolanaSource.res +0 -515
- package/src/sources/HyperSyncSolanaSource.res.mjs +0 -441
package/src/Persistence.res.mjs
CHANGED
|
@@ -27,7 +27,7 @@ function make(userEntities, allEnums, storage) {
|
|
|
27
27
|
};
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
async function init(persistence, chainConfigs, envioInfo, resetCommand, resetOpt) {
|
|
30
|
+
async function init(persistence, chainConfigs, envioInfo, resetCommand, runCommand, resetOpt) {
|
|
31
31
|
let reset = resetOpt !== undefined ? resetOpt : false;
|
|
32
32
|
try {
|
|
33
33
|
let promise = persistence.storageStatus;
|
|
@@ -70,7 +70,19 @@ async function init(persistence, chainConfigs, envioInfo, resetCommand, resetOpt
|
|
|
70
70
|
let initialState$1 = await persistence.storage.resumeInitialState();
|
|
71
71
|
let stored = initialState$1.envioInfo;
|
|
72
72
|
let changedPaths = stored !== undefined ? Config.diffPaths(stored, envioInfo) : ["envio info is missing — storage initialized by an older envio"];
|
|
73
|
-
|
|
73
|
+
let hasClickhouse;
|
|
74
|
+
if (typeof envioInfo === "object" && envioInfo !== null && !Array.isArray(envioInfo)) {
|
|
75
|
+
let match$1 = envioInfo["storage"];
|
|
76
|
+
if (typeof match$1 === "object" && match$1 !== null && !Array.isArray(match$1)) {
|
|
77
|
+
let match$2 = match$1["clickhouse"];
|
|
78
|
+
hasClickhouse = match$2 === true;
|
|
79
|
+
} else {
|
|
80
|
+
hasClickhouse = false;
|
|
81
|
+
}
|
|
82
|
+
} else {
|
|
83
|
+
hasClickhouse = false;
|
|
84
|
+
}
|
|
85
|
+
Config.throwIfIncompatible(changedPaths, resetCommand, runCommand, hasClickhouse);
|
|
74
86
|
persistence.storageStatus = {
|
|
75
87
|
TAG: "Ready",
|
|
76
88
|
_0: initialState$1
|
package/src/SimulateItems.res
CHANGED
|
@@ -320,34 +320,21 @@ let patchConfig = (~config: Config.t, ~processConfig: JSON.t): Config.t => {
|
|
|
320
320
|
let chainIdStr = chain->ChainMap.Chain.toChainId->Int.toString
|
|
321
321
|
switch chainsDict->Dict.get(chainIdStr) {
|
|
322
322
|
| Some(processChainJson) =>
|
|
323
|
-
let
|
|
324
|
-
|
|
323
|
+
let simulateRaw: option<array<JSON.t>> =
|
|
324
|
+
(processChainJson->(Utils.magic: JSON.t => {..}))["simulate"]->Nullable.toOption
|
|
325
325
|
switch simulateRaw {
|
|
326
326
|
| Some(simulateItems) =>
|
|
327
327
|
let items = parse(~simulateItems, ~config, ~chainConfig)
|
|
328
|
-
|
|
329
|
-
let
|
|
328
|
+
// Use endBlock from processConfig (the user-specified range)
|
|
329
|
+
let startBlock: int =
|
|
330
|
+
(processChainJson->(Utils.magic: JSON.t => {..}))["startBlock"]->(
|
|
331
|
+
Utils.magic: 'a => int
|
|
332
|
+
)
|
|
333
|
+
let endBlock: int =
|
|
334
|
+
(processChainJson->(Utils.magic: JSON.t => {..}))["endBlock"]->(Utils.magic: 'a => int)
|
|
330
335
|
let source = SimulateSource.make(~items, ~endBlock, ~chain)
|
|
331
336
|
{...chainConfig, startBlock, endBlock, sourceConfig: Config.CustomSources([source])}
|
|
332
|
-
| None =>
|
|
333
|
-
// No simulate items: still honor `startBlock` / `endBlock` overrides
|
|
334
|
-
// so non-EVM/Fuel ecosystems (notably SVM `indexer.onInstruction`,
|
|
335
|
-
// which doesn't support simulate items) can bound the run window
|
|
336
|
-
// via `testIndexer.process({chains: { id: {startBlock, endBlock} }})`.
|
|
337
|
-
let startBlockOpt: option<int> =
|
|
338
|
-
raw["startBlock"]
|
|
339
|
-
->(Utils.magic: 'a => Nullable.t<int>)
|
|
340
|
-
->Nullable.toOption
|
|
341
|
-
let endBlockOpt: option<int> =
|
|
342
|
-
raw["endBlock"]->(Utils.magic: 'a => Nullable.t<int>)->Nullable.toOption
|
|
343
|
-
let withStart = switch startBlockOpt {
|
|
344
|
-
| Some(sb) => {...chainConfig, startBlock: sb}
|
|
345
|
-
| None => chainConfig
|
|
346
|
-
}
|
|
347
|
-
switch endBlockOpt {
|
|
348
|
-
| Some(eb) => {...withStart, endBlock: eb}
|
|
349
|
-
| None => withStart
|
|
350
|
-
}
|
|
337
|
+
| None => chainConfig
|
|
351
338
|
}
|
|
352
339
|
| None => chainConfig
|
|
353
340
|
}
|
|
@@ -266,35 +266,20 @@ function patchConfig(config, processConfig) {
|
|
|
266
266
|
}
|
|
267
267
|
let simulateRaw = processChainJson.simulate;
|
|
268
268
|
if (simulateRaw == null) {
|
|
269
|
-
|
|
270
|
-
let endBlockOpt = processChainJson.endBlock;
|
|
271
|
-
let withStart;
|
|
272
|
-
if (startBlockOpt == null) {
|
|
273
|
-
withStart = chainConfig;
|
|
274
|
-
} else {
|
|
275
|
-
let newrecord = {...chainConfig};
|
|
276
|
-
newrecord.startBlock = startBlockOpt;
|
|
277
|
-
withStart = newrecord;
|
|
278
|
-
}
|
|
279
|
-
if (endBlockOpt == null) {
|
|
280
|
-
return withStart;
|
|
281
|
-
}
|
|
282
|
-
let newrecord$1 = {...withStart};
|
|
283
|
-
newrecord$1.endBlock = endBlockOpt;
|
|
284
|
-
return newrecord$1;
|
|
269
|
+
return chainConfig;
|
|
285
270
|
}
|
|
286
271
|
let items = parse(simulateRaw, config, chainConfig);
|
|
287
272
|
let startBlock = processChainJson.startBlock;
|
|
288
273
|
let endBlock = processChainJson.endBlock;
|
|
289
274
|
let source = SimulateSource.make(items, endBlock, chain);
|
|
290
|
-
let newrecord
|
|
291
|
-
newrecord
|
|
275
|
+
let newrecord = {...chainConfig};
|
|
276
|
+
newrecord.sourceConfig = {
|
|
292
277
|
TAG: "CustomSources",
|
|
293
278
|
_0: [source]
|
|
294
279
|
};
|
|
295
|
-
newrecord
|
|
296
|
-
newrecord
|
|
297
|
-
return newrecord
|
|
280
|
+
newrecord.endBlock = endBlock;
|
|
281
|
+
newrecord.startBlock = startBlock;
|
|
282
|
+
return newrecord;
|
|
298
283
|
});
|
|
299
284
|
let newrecord = {...config};
|
|
300
285
|
newrecord.chainMap = newChainMap;
|
|
@@ -426,6 +426,10 @@ let initialize = async (
|
|
|
426
426
|
| Some(engine) => ` ENGINE = ${engine}`
|
|
427
427
|
| None => ""
|
|
428
428
|
}
|
|
429
|
+
// Replicated database engine requires CREATE DATABASE to run on every
|
|
430
|
+
// replica; ON CLUSTER fans the DDL out via Keeper. The '{cluster}' macro
|
|
431
|
+
// resolves to each node's configured cluster name.
|
|
432
|
+
let onClusterClause = replicated ? ` ON CLUSTER '{cluster}'` : ""
|
|
429
433
|
|
|
430
434
|
switch databaseEngine {
|
|
431
435
|
| Some(engineSpec) => {
|
|
@@ -445,9 +449,9 @@ let initialize = async (
|
|
|
445
449
|
| None => ()
|
|
446
450
|
}
|
|
447
451
|
|
|
448
|
-
await client->exec({query: `TRUNCATE DATABASE IF EXISTS ${database}`})
|
|
452
|
+
await client->exec({query: `TRUNCATE DATABASE IF EXISTS ${database}${onClusterClause}`})
|
|
449
453
|
await client->exec({
|
|
450
|
-
query: `CREATE DATABASE IF NOT EXISTS ${database}${databaseEngineClause}`,
|
|
454
|
+
query: `CREATE DATABASE IF NOT EXISTS ${database}${onClusterClause}${databaseEngineClause}`,
|
|
451
455
|
})
|
|
452
456
|
await client->exec({query: `USE ${database}`})
|
|
453
457
|
|
|
@@ -301,6 +301,7 @@ async function initialize(client, database, entities, param) {
|
|
|
301
301
|
let replicated = Env.ClickHouse.replicated();
|
|
302
302
|
let databaseEngine = Env.ClickHouse.databaseEngine();
|
|
303
303
|
let databaseEngineClause = databaseEngine !== undefined ? ` ENGINE = ` + databaseEngine : "";
|
|
304
|
+
let onClusterClause = replicated ? ` ON CLUSTER '{cluster}'` : "";
|
|
304
305
|
if (databaseEngine !== undefined) {
|
|
305
306
|
let expectedEngineName = databaseEngine.split("(")[0].trim();
|
|
306
307
|
let existingResult = await client.query({
|
|
@@ -316,10 +317,10 @@ async function initialize(client, database, entities, param) {
|
|
|
316
317
|
}
|
|
317
318
|
}
|
|
318
319
|
await client.exec({
|
|
319
|
-
query: `TRUNCATE DATABASE IF EXISTS ` + database
|
|
320
|
+
query: `TRUNCATE DATABASE IF EXISTS ` + database + onClusterClause
|
|
320
321
|
});
|
|
321
322
|
await client.exec({
|
|
322
|
-
query: `CREATE DATABASE IF NOT EXISTS ` + database + databaseEngineClause
|
|
323
|
+
query: `CREATE DATABASE IF NOT EXISTS ` + database + onClusterClause + databaseEngineClause
|
|
323
324
|
});
|
|
324
325
|
await client.exec({
|
|
325
326
|
query: `USE ` + database
|
|
@@ -116,68 +116,3 @@ let fromEvmEventModsOrThrow = (events: array<Internal.evmEventConfig>, ~chain):
|
|
|
116
116
|
})
|
|
117
117
|
router
|
|
118
118
|
}
|
|
119
|
-
|
|
120
|
-
/** Dispatch key for SVM instructions. `None` matches any instruction in the
|
|
121
|
-
program (lowest priority). */
|
|
122
|
-
let getSvmEventId = (~programId: SvmTypes.Pubkey.t, ~discriminator: option<string>) =>
|
|
123
|
-
switch discriminator {
|
|
124
|
-
| None => (programId->SvmTypes.Pubkey.toString) ++ "_none"
|
|
125
|
-
| Some(d) => (programId->SvmTypes.Pubkey.toString) ++ "_" ++ d
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
/** Discriminator byte-lengths declared by a program, sorted descending. The
|
|
129
|
-
source uses this to probe `(programId, dN)` keys longest-first when routing
|
|
130
|
-
a returned instruction to a handler — matching the locked Q1 answer. */
|
|
131
|
-
type svmProgramOrdering = {
|
|
132
|
-
programId: SvmTypes.Pubkey.t,
|
|
133
|
-
/** Byte lengths in descending order, deduplicated. Includes `0` only when
|
|
134
|
-
a handler is registered with no discriminator (program-wide match). */
|
|
135
|
-
byteLengthsDesc: array<int>,
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
let fromSvmEventConfigsOrThrow = (
|
|
139
|
-
events: array<Internal.svmInstructionEventConfig>,
|
|
140
|
-
~chain,
|
|
141
|
-
): (t<Internal.svmInstructionEventConfig>, array<svmProgramOrdering>) => {
|
|
142
|
-
let router = empty()
|
|
143
|
-
events->Belt.Array.forEach(config => {
|
|
144
|
-
// The router tag must include the programId so two programs declaring the
|
|
145
|
-
// same discriminator coexist. The source-side lookup uses the same shape
|
|
146
|
-
// via `getSvmEventId(~programId, ~discriminator)`.
|
|
147
|
-
let routerTag = getSvmEventId(~programId=config.programId, ~discriminator=config.discriminator)
|
|
148
|
-
router->addOrThrow(
|
|
149
|
-
routerTag,
|
|
150
|
-
config,
|
|
151
|
-
~contractName=config.contractName,
|
|
152
|
-
~eventName=config.name,
|
|
153
|
-
~chain,
|
|
154
|
-
~isWildcard=config.isWildcard,
|
|
155
|
-
)
|
|
156
|
-
})
|
|
157
|
-
|
|
158
|
-
// Per-program list of declared discriminator byte lengths, sorted desc.
|
|
159
|
-
let byProgram: dict<Utils.Set.t<int>> = Dict.make()
|
|
160
|
-
events->Belt.Array.forEach(config => {
|
|
161
|
-
let key = config.programId->SvmTypes.Pubkey.toString
|
|
162
|
-
let set = switch byProgram->Utils.Dict.dangerouslyGetNonOption(key) {
|
|
163
|
-
| Some(s) => s
|
|
164
|
-
| None =>
|
|
165
|
-
let s = Utils.Set.make()
|
|
166
|
-
byProgram->Dict.set(key, s)
|
|
167
|
-
s
|
|
168
|
-
}
|
|
169
|
-
let _ = set->Utils.Set.add(config.discriminatorByteLen)
|
|
170
|
-
})
|
|
171
|
-
let ordering =
|
|
172
|
-
byProgram
|
|
173
|
-
->Dict.toArray
|
|
174
|
-
->Array.map(((programIdString, lens)) => {
|
|
175
|
-
let sorted = lens->Utils.Set.toArray->Array.toSorted((a, b) => (b - a)->Int.toFloat)
|
|
176
|
-
{
|
|
177
|
-
programId: programIdString->SvmTypes.Pubkey.fromStringUnsafe,
|
|
178
|
-
byteLengthsDesc: sorted,
|
|
179
|
-
}
|
|
180
|
-
})
|
|
181
|
-
|
|
182
|
-
(router, ordering)
|
|
183
|
-
}
|
|
@@ -111,47 +111,6 @@ function fromEvmEventModsOrThrow(events, chain) {
|
|
|
111
111
|
return router;
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
-
function getSvmEventId(programId, discriminator) {
|
|
115
|
-
if (discriminator !== undefined) {
|
|
116
|
-
return programId + "_" + discriminator;
|
|
117
|
-
} else {
|
|
118
|
-
return programId + "_none";
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
function fromSvmEventConfigsOrThrow(events, chain) {
|
|
123
|
-
let router = {};
|
|
124
|
-
Belt_Array.forEach(events, config => {
|
|
125
|
-
let routerTag = getSvmEventId(config.programId, config.discriminator);
|
|
126
|
-
addOrThrow$1(router, routerTag, config, config.contractName, config.isWildcard, config.name, chain);
|
|
127
|
-
});
|
|
128
|
-
let byProgram = {};
|
|
129
|
-
Belt_Array.forEach(events, config => {
|
|
130
|
-
let key = config.programId;
|
|
131
|
-
let s = byProgram[key];
|
|
132
|
-
let set;
|
|
133
|
-
if (s !== undefined) {
|
|
134
|
-
set = Primitive_option.valFromOption(s);
|
|
135
|
-
} else {
|
|
136
|
-
let s$1 = new Set();
|
|
137
|
-
byProgram[key] = s$1;
|
|
138
|
-
set = s$1;
|
|
139
|
-
}
|
|
140
|
-
set.add(config.discriminatorByteLen);
|
|
141
|
-
});
|
|
142
|
-
let ordering = Object.entries(byProgram).map(param => {
|
|
143
|
-
let sorted = Array.from(param[1]).toSorted((a, b) => b - a | 0);
|
|
144
|
-
return {
|
|
145
|
-
programId: param[0],
|
|
146
|
-
byteLengthsDesc: sorted
|
|
147
|
-
};
|
|
148
|
-
});
|
|
149
|
-
return [
|
|
150
|
-
router,
|
|
151
|
-
ordering
|
|
152
|
-
];
|
|
153
|
-
}
|
|
154
|
-
|
|
155
114
|
export {
|
|
156
115
|
EventDuplicate,
|
|
157
116
|
WildcardCollision,
|
|
@@ -161,7 +120,5 @@ export {
|
|
|
161
120
|
get$1 as get,
|
|
162
121
|
getEvmEventId,
|
|
163
122
|
fromEvmEventModsOrThrow,
|
|
164
|
-
getSvmEventId,
|
|
165
|
-
fromSvmEventConfigsOrThrow,
|
|
166
123
|
}
|
|
167
124
|
/* ChainMap Not a pure module */
|
|
@@ -155,18 +155,41 @@ module QueryTypes = {
|
|
|
155
155
|
)
|
|
156
156
|
|
|
157
157
|
type logFilter = {
|
|
158
|
+
/**
|
|
159
|
+
* Address of the contract, any logs that has any of these addresses will be returned.
|
|
160
|
+
* Empty means match all.
|
|
161
|
+
*/
|
|
158
162
|
address?: array<Address.t>,
|
|
163
|
+
/**
|
|
164
|
+
* Topics to match, each member of the top level array is another array, if the nth topic matches any
|
|
165
|
+
* topic specified in topics[n] the log will be returned. Empty means match all.
|
|
166
|
+
*/
|
|
159
167
|
topics: topicSelection,
|
|
160
168
|
}
|
|
161
169
|
|
|
162
170
|
let makeLogSelection = (~address, ~topics) => {address, topics}
|
|
163
171
|
|
|
164
172
|
type transactionFilter = {
|
|
173
|
+
/**
|
|
174
|
+
* Address the transaction should originate from. If transaction.from matches any of these, the transaction
|
|
175
|
+
* will be returned. Keep in mind that this has an and relationship with to filter, so each transaction should
|
|
176
|
+
* match both of them. Empty means match all.
|
|
177
|
+
*/
|
|
165
178
|
from?: array<Address.t>,
|
|
166
|
-
|
|
179
|
+
/**
|
|
180
|
+
* Address the transaction should go to. If transaction.to matches any of these, the transaction will
|
|
181
|
+
* be returned. Keep in mind that this has an and relationship with from filter, so each transaction should
|
|
182
|
+
* match both of them. Empty means match all.
|
|
183
|
+
*/
|
|
184
|
+
@as("to")
|
|
185
|
+
to_?: array<Address.t>,
|
|
186
|
+
/** If first 4 bytes of transaction input matches any of these, transaction will be returned. Empty means match all. */
|
|
167
187
|
sighash?: array<string>,
|
|
188
|
+
/** If tx.status matches this it will be returned. */
|
|
168
189
|
status?: int,
|
|
169
|
-
|
|
190
|
+
/** If transaction.type matches any of these values, the transaction will be returned */
|
|
191
|
+
@as("type")
|
|
192
|
+
type_?: array<int>,
|
|
170
193
|
contractAddress?: array<Address.t>,
|
|
171
194
|
}
|
|
172
195
|
|
|
@@ -176,30 +199,94 @@ module QueryTypes = {
|
|
|
176
199
|
address?: array<Address.t>,
|
|
177
200
|
callType?: array<string>,
|
|
178
201
|
rewardType?: array<string>,
|
|
179
|
-
@as("type")
|
|
202
|
+
@as("type")
|
|
203
|
+
type_?: array<string>,
|
|
180
204
|
sighash?: array<string>,
|
|
181
205
|
}
|
|
182
206
|
|
|
183
207
|
type blockSelection = {
|
|
208
|
+
/**
|
|
209
|
+
* Hash of a block, any blocks that have one of these hashes will be returned.
|
|
210
|
+
* Empty means match all.
|
|
211
|
+
*/
|
|
184
212
|
hash?: array<string>,
|
|
213
|
+
/**
|
|
214
|
+
* Miner address of a block, any blocks that have one of these miners will be returned.
|
|
215
|
+
* Empty means match all.
|
|
216
|
+
*/
|
|
185
217
|
miner?: array<Address.t>,
|
|
186
218
|
}
|
|
187
219
|
|
|
188
220
|
type joinMode = | @as(0) Default | @as(1) JoinAll | @as(2) JoinNothing
|
|
189
221
|
|
|
190
222
|
type query = {
|
|
223
|
+
/** The block to start the query from */
|
|
191
224
|
fromBlock: int,
|
|
192
|
-
|
|
225
|
+
/**
|
|
226
|
+
* The block to end the query at. If not specified, the query will go until the
|
|
227
|
+
* end of data. Exclusive, the returned range will be [from_block..to_block).
|
|
228
|
+
*
|
|
229
|
+
* The query will return before it reaches this target block if it hits the time limit
|
|
230
|
+
* configured on the server. The user should continue their query by putting the
|
|
231
|
+
* next_block field in the response into from_block field of their next query. This implements
|
|
232
|
+
* pagination.
|
|
233
|
+
*/
|
|
234
|
+
@as("toBlock")
|
|
235
|
+
toBlockExclusive?: int,
|
|
236
|
+
/**
|
|
237
|
+
* List of log selections, these have an or relationship between them, so the query will return logs
|
|
238
|
+
* that match any of these selections.
|
|
239
|
+
*/
|
|
193
240
|
logs?: array<logFilter>,
|
|
241
|
+
/**
|
|
242
|
+
* List of transaction selections, the query will return transactions that match any of these selections and
|
|
243
|
+
* it will return transactions that are related to the returned logs.
|
|
244
|
+
*/
|
|
194
245
|
transactions?: array<transactionFilter>,
|
|
246
|
+
/**
|
|
247
|
+
* List of trace selections, the query will return traces that match any of these selections and
|
|
248
|
+
* it will re turn traces that are related to the returned logs.
|
|
249
|
+
*/
|
|
195
250
|
traces?: array<traceSelection>,
|
|
251
|
+
/** List of block selections, the query will return blocks that match any of these selections */
|
|
196
252
|
blocks?: array<blockSelection>,
|
|
253
|
+
/**
|
|
254
|
+
* Field selection. The user can select which fields they are interested in, requesting less fields will improve
|
|
255
|
+
* query execution time and reduce the payload size so the user should always use a minimal number of fields.
|
|
256
|
+
*/
|
|
197
257
|
fieldSelection: fieldSelection,
|
|
258
|
+
/**
|
|
259
|
+
* Maximum number of blocks that should be returned, the server might return more blocks than this number but
|
|
260
|
+
* it won't overshoot by too much.
|
|
261
|
+
*/
|
|
198
262
|
maxNumBlocks?: int,
|
|
263
|
+
/**
|
|
264
|
+
* Maximum number of transactions that should be returned, the server might return more transactions than this number but
|
|
265
|
+
* it won't overshoot by too much.
|
|
266
|
+
*/
|
|
199
267
|
maxNumTransactions?: int,
|
|
268
|
+
/**
|
|
269
|
+
* Maximum number of logs that should be returned, the server might return more logs than this number but
|
|
270
|
+
* it won't overshoot by too much.
|
|
271
|
+
*/
|
|
200
272
|
maxNumLogs?: int,
|
|
273
|
+
/**
|
|
274
|
+
* Maximum number of traces that should be returned, the server might return more traces than this number but
|
|
275
|
+
* it won't overshoot by too much.
|
|
276
|
+
*/
|
|
201
277
|
maxNumTraces?: int,
|
|
278
|
+
/**
|
|
279
|
+
* Selects join mode for the query,
|
|
280
|
+
* Default: join in this order logs -> transactions -> traces -> blocks
|
|
281
|
+
* JoinAll: join everything to everything. For example if logSelection matches log0, we get the
|
|
282
|
+
* associated transaction of log0 and then we get associated logs of that transaction as well. Applites similarly
|
|
283
|
+
* to blocks, traces.
|
|
284
|
+
* JoinNothing: join nothing.
|
|
285
|
+
*/
|
|
202
286
|
joinMode?: joinMode,
|
|
287
|
+
/**
|
|
288
|
+
* If set to true, the server will return data for all blocks in the requested range [from_block, to_block).
|
|
289
|
+
*/
|
|
203
290
|
includeAllBlocks?: bool,
|
|
204
291
|
}
|
|
205
292
|
}
|
|
@@ -298,7 +385,8 @@ module ResponseTypes = {
|
|
|
298
385
|
gasUsed?: bigint,
|
|
299
386
|
contractAddress?: string,
|
|
300
387
|
logsBloom?: string,
|
|
301
|
-
@as("type")
|
|
388
|
+
@as("type")
|
|
389
|
+
type_?: int,
|
|
302
390
|
root?: string,
|
|
303
391
|
status?: int,
|
|
304
392
|
l1Fee?: bigint,
|
|
@@ -328,18 +416,40 @@ module ResponseTypes = {
|
|
|
328
416
|
}
|
|
329
417
|
|
|
330
418
|
type rollbackGuard = {
|
|
419
|
+
/** Block number of the last scanned block */
|
|
331
420
|
blockNumber: int,
|
|
421
|
+
/** Block timestamp of the last scanned block */
|
|
332
422
|
timestamp: int,
|
|
423
|
+
/** Block hash of the last scanned block */
|
|
333
424
|
hash: string,
|
|
425
|
+
/**
|
|
426
|
+
* Block number of the first scanned block in memory.
|
|
427
|
+
*
|
|
428
|
+
* This might not be the first scanned block. It only includes blocks that are in memory (possible to be rolled back).
|
|
429
|
+
*/
|
|
334
430
|
firstBlockNumber: int,
|
|
431
|
+
/**
|
|
432
|
+
* Parent hash of the first scanned block in memory.
|
|
433
|
+
*
|
|
434
|
+
* This might not be the first scanned block. It only includes blocks that are in memory (possible to be rolled back).
|
|
435
|
+
*/
|
|
335
436
|
firstParentHash: string,
|
|
336
437
|
}
|
|
337
438
|
|
|
338
439
|
type eventResponse = {
|
|
440
|
+
/** Current height of the source hypersync instance */
|
|
339
441
|
archiveHeight: option<int>,
|
|
442
|
+
/**
|
|
443
|
+
* Next block to query for, the responses are paginated so,
|
|
444
|
+
* the caller should continue the query from this block if they
|
|
445
|
+
* didn't get responses up to the to_block they specified in the Query.
|
|
446
|
+
*/
|
|
340
447
|
nextBlock: int,
|
|
448
|
+
/** Total time it took the hypersync instance to execute the query. */
|
|
341
449
|
totalExecutionTime: int,
|
|
450
|
+
/** Response data */
|
|
342
451
|
data: array<event>,
|
|
452
|
+
/** Rollback guard, supposed to be used to detect rollbacks */
|
|
343
453
|
rollbackGuard: option<rollbackGuard>,
|
|
344
454
|
}
|
|
345
455
|
}
|
|
@@ -361,16 +471,40 @@ type queryResponse = {
|
|
|
361
471
|
rollbackGuard: option<ResponseTypes.rollbackGuard>,
|
|
362
472
|
}
|
|
363
473
|
|
|
474
|
+
//Todo, add bindings for these types
|
|
475
|
+
type streamConfig
|
|
476
|
+
type queryResponseStream
|
|
477
|
+
type eventStream
|
|
478
|
+
|
|
479
|
+
@tag("type")
|
|
480
|
+
type heightStreamEvent =
|
|
481
|
+
| Height({height: int})
|
|
482
|
+
| Connected
|
|
483
|
+
| Reconnecting({delayMillis: int, errorMsg: string})
|
|
484
|
+
|
|
485
|
+
module HeightStream = {
|
|
486
|
+
type t = {
|
|
487
|
+
/** Close the height stream */
|
|
488
|
+
close: unit => promise<unit>,
|
|
489
|
+
/** Receive the next height stream event from the stream */
|
|
490
|
+
recv: unit => promise<heightStreamEvent>,
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
|
|
364
494
|
type t = {
|
|
495
|
+
getHeight: unit => promise<int>,
|
|
496
|
+
collect: (~query: query, ~config: streamConfig) => promise<queryResponse>,
|
|
497
|
+
collectEvents: (~query: query, ~config: streamConfig) => promise<eventResponse>,
|
|
498
|
+
collectParquet: (~path: string, ~query: query, ~config: streamConfig) => promise<unit>,
|
|
365
499
|
get: (~query: query) => promise<queryResponse>,
|
|
366
500
|
getEvents: (~query: query) => promise<eventResponse>,
|
|
501
|
+
stream: (~query: query, ~config: streamConfig) => promise<queryResponseStream>,
|
|
502
|
+
streamEvents: (~query: query, ~config: streamConfig) => promise<eventStream>,
|
|
503
|
+
streamHeight: unit => promise<HeightStream.t>,
|
|
367
504
|
}
|
|
368
505
|
|
|
369
|
-
@
|
|
370
|
-
external
|
|
371
|
-
|
|
372
|
-
let makeWithAgent = (cfg, ~userAgent) =>
|
|
373
|
-
Core.getAddon().hypersyncClient->classNewWithAgent(cfg, userAgent)
|
|
506
|
+
@module("@envio-dev/hypersync-client") @scope("HypersyncClient")
|
|
507
|
+
external makeWithAgent: (cfg, ~userAgent: string) => t = "newWithAgent"
|
|
374
508
|
|
|
375
509
|
let make = (
|
|
376
510
|
~url,
|
|
@@ -406,19 +540,11 @@ type logLevel = [#trace | #debug | #info | #warn | #error]
|
|
|
406
540
|
let logLevelSchema: S.t<logLevel> = S.enum([#trace, #debug, #info, #warn, #error])
|
|
407
541
|
|
|
408
542
|
/**
|
|
409
|
-
* Set the log level for the underlying Rust logger.
|
|
543
|
+
* Set the log level for the underlying Rust logger in hypersync-client.
|
|
410
544
|
* Must be called before creating any HypersyncClient.
|
|
411
545
|
*/
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
| #trace => "trace"
|
|
415
|
-
| #debug => "debug"
|
|
416
|
-
| #info => "info"
|
|
417
|
-
| #warn => "warn"
|
|
418
|
-
| #error => "error"
|
|
419
|
-
}
|
|
420
|
-
Core.getAddon().setLogLevel(s)
|
|
421
|
-
}
|
|
546
|
+
@module("@envio-dev/hypersync-client")
|
|
547
|
+
external setLogLevel: logLevel => unit = "setLogLevel"
|
|
422
548
|
|
|
423
549
|
module Decoder = {
|
|
424
550
|
type rec decodedSolType<'a> = {val: 'a}
|
|
@@ -453,17 +579,18 @@ module Decoder = {
|
|
|
453
579
|
body: array<decodedRaw>,
|
|
454
580
|
}
|
|
455
581
|
|
|
582
|
+
type log
|
|
456
583
|
type t = {
|
|
584
|
+
enableChecksummedAddresses: unit => unit,
|
|
585
|
+
disableChecksummedAddresses: unit => unit,
|
|
586
|
+
decodeLogs: array<log> => promise<array<Nullable.t<decodedEvent>>>,
|
|
587
|
+
decodeLogsSync: array<log> => array<Nullable.t<decodedEvent>>,
|
|
457
588
|
decodeEvents: array<ResponseTypes.event> => promise<array<Nullable.t<decodedEvent>>>,
|
|
589
|
+
decodeEventsSync: array<ResponseTypes.event> => array<Nullable.t<decodedEvent>>,
|
|
458
590
|
}
|
|
459
591
|
|
|
460
|
-
@
|
|
461
|
-
external
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
~checksumAddresses: bool=?,
|
|
465
|
-
) => t = "fromSignatures"
|
|
466
|
-
|
|
467
|
-
let fromSignatures = (signatures, ~checksumAddresses=?) =>
|
|
468
|
-
Core.getAddon().decoder->classFromSignatures(signatures, ~checksumAddresses?)
|
|
592
|
+
@module("@envio-dev/hypersync-client") @scope("Decoder")
|
|
593
|
+
external fromSignatures: array<string> => t = "fromSignatures"
|
|
594
|
+
// Keep the @envio-dev/hypersync-client import inside of the package
|
|
595
|
+
let fromSignatures = fromSignatures
|
|
469
596
|
}
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
|
|
3
|
-
import * as Core from "../Core.res.mjs";
|
|
4
3
|
import * as Utils from "../Utils.res.mjs";
|
|
5
4
|
import * as Address from "../Address.res.mjs";
|
|
6
5
|
import * as Belt_Array from "@rescript/runtime/lib/es6/Belt_Array.js";
|
|
7
|
-
import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
|
|
8
6
|
import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
|
|
7
|
+
import * as HypersyncClient from "@envio-dev/hypersync-client";
|
|
9
8
|
|
|
10
9
|
let serializationFormatSchema = S$RescriptSchema.$$enum([
|
|
11
10
|
"Json",
|
|
@@ -59,14 +58,12 @@ let ResponseTypes = {
|
|
|
59
58
|
authorizationListSchema: authorizationListSchema
|
|
60
59
|
};
|
|
61
60
|
|
|
62
|
-
|
|
63
|
-
return Core.getAddon().HypersyncClient.newWithAgent(cfg, userAgent);
|
|
64
|
-
}
|
|
61
|
+
let HeightStream = {};
|
|
65
62
|
|
|
66
63
|
function make(url, apiToken, httpReqTimeoutMillis, maxNumRetries, enableChecksumAddressesOpt, serializationFormat, enableQueryCaching, retryBaseMs, retryBackoffMs, retryCeilingMs) {
|
|
67
64
|
let enableChecksumAddresses = enableChecksumAddressesOpt !== undefined ? enableChecksumAddressesOpt : true;
|
|
68
65
|
let envioVersion = Utils.EnvioPackage.value.version;
|
|
69
|
-
return
|
|
66
|
+
return HypersyncClient.HypersyncClient.newWithAgent({
|
|
70
67
|
url: url,
|
|
71
68
|
apiToken: apiToken,
|
|
72
69
|
httpReqTimeoutMillis: httpReqTimeoutMillis,
|
|
@@ -88,16 +85,6 @@ let logLevelSchema = S$RescriptSchema.$$enum([
|
|
|
88
85
|
"error"
|
|
89
86
|
]);
|
|
90
87
|
|
|
91
|
-
function setLogLevel(level) {
|
|
92
|
-
Core.getAddon().setLogLevel(level === "warn" ? "warn" : (
|
|
93
|
-
level === "debug" ? "debug" : (
|
|
94
|
-
level === "error" ? "error" : (
|
|
95
|
-
level === "trace" ? "trace" : "info"
|
|
96
|
-
)
|
|
97
|
-
)
|
|
98
|
-
));
|
|
99
|
-
}
|
|
100
|
-
|
|
101
88
|
function toUnderlying(_d) {
|
|
102
89
|
while (true) {
|
|
103
90
|
let d = _d;
|
|
@@ -118,8 +105,8 @@ function toUnderlying(_d) {
|
|
|
118
105
|
};
|
|
119
106
|
}
|
|
120
107
|
|
|
121
|
-
function fromSignatures(
|
|
122
|
-
return
|
|
108
|
+
function fromSignatures(prim) {
|
|
109
|
+
return HypersyncClient.Decoder.fromSignatures(prim);
|
|
123
110
|
}
|
|
124
111
|
|
|
125
112
|
let Decoder = {
|
|
@@ -131,10 +118,9 @@ export {
|
|
|
131
118
|
serializationFormatSchema,
|
|
132
119
|
QueryTypes,
|
|
133
120
|
ResponseTypes,
|
|
134
|
-
|
|
121
|
+
HeightStream,
|
|
135
122
|
make,
|
|
136
123
|
logLevelSchema,
|
|
137
|
-
setLogLevel,
|
|
138
124
|
Decoder,
|
|
139
125
|
}
|
|
140
126
|
/* serializationFormatSchema Not a pure module */
|
|
@@ -192,15 +192,18 @@ Learn more or get a free API token at: https://envio.dev/app/api-tokens`)
|
|
|
192
192
|
switch hscDecoder.contents {
|
|
193
193
|
| Some(decoder) => decoder
|
|
194
194
|
| None =>
|
|
195
|
-
switch HyperSyncClient.Decoder.fromSignatures(
|
|
196
|
-
allEventSignatures,
|
|
197
|
-
~checksumAddresses=!lowercaseAddresses,
|
|
198
|
-
) {
|
|
195
|
+
switch HyperSyncClient.Decoder.fromSignatures(allEventSignatures) {
|
|
199
196
|
| exception exn =>
|
|
200
197
|
exn->ErrorHandling.mkLogAndRaise(
|
|
201
198
|
~msg="Failed to instantiate a decoder from hypersync client, please double check your ABI",
|
|
202
199
|
)
|
|
203
|
-
| decoder =>
|
|
200
|
+
| decoder =>
|
|
201
|
+
if lowercaseAddresses {
|
|
202
|
+
decoder.disableChecksummedAddresses()
|
|
203
|
+
} else {
|
|
204
|
+
decoder.enableChecksummedAddresses()
|
|
205
|
+
}
|
|
206
|
+
decoder
|
|
204
207
|
}
|
|
205
208
|
}
|
|
206
209
|
}
|