envio 2.28.0 → 2.29.0-alpha.1
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/index.d.ts +3 -0
- package/package.json +5 -5
- package/src/Batch.res +4 -14
- package/src/Batch.res.js +3 -14
- package/src/Envio.gen.ts +10 -0
- package/src/Envio.res +21 -0
- package/src/EventRegister.res +150 -31
- package/src/EventRegister.res.js +120 -33
- package/src/EventRegister.resi +11 -0
- package/src/EventUtils.res +52 -58
- package/src/EventUtils.res.js +15 -51
- package/src/FetchState.res +68 -56
- package/src/FetchState.res.js +66 -53
- package/src/Internal.gen.ts +2 -0
- package/src/Internal.res +44 -3
- package/src/InternalConfig.res +18 -0
- package/src/Logging.res +36 -24
- package/src/Logging.res.js +35 -21
- package/src/sources/HyperFuelSource.res +506 -0
- package/src/sources/HyperFuelSource.res.js +451 -0
- package/src/sources/HyperSync.res +1 -1
- package/src/sources/HyperSync.resi +1 -1
- package/src/sources/HyperSyncSource.res +569 -0
- package/src/sources/HyperSyncSource.res.js +413 -0
- package/src/sources/RpcSource.res +18 -20
- package/src/sources/RpcSource.res.js +1 -0
- package/src/sources/Source.res +1 -1
|
@@ -0,0 +1,506 @@
|
|
|
1
|
+
open Source
|
|
2
|
+
open Belt
|
|
3
|
+
|
|
4
|
+
exception EventRoutingFailed
|
|
5
|
+
|
|
6
|
+
let mintEventTag = "mint"
|
|
7
|
+
let burnEventTag = "burn"
|
|
8
|
+
let transferEventTag = "transfer"
|
|
9
|
+
let callEventTag = "call"
|
|
10
|
+
|
|
11
|
+
type selectionConfig = {
|
|
12
|
+
getRecieptsSelection: (
|
|
13
|
+
~addressesByContractName: dict<array<Address.t>>,
|
|
14
|
+
) => array<HyperFuelClient.QueryTypes.receiptSelection>,
|
|
15
|
+
eventRouter: EventRouter.t<Internal.fuelEventConfig>,
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
let logDataReceiptTypeSelection: array<Fuel.receiptType> = [LogData]
|
|
19
|
+
|
|
20
|
+
// only transactions with status 1 (success)
|
|
21
|
+
let txStatusSelection = [1]
|
|
22
|
+
|
|
23
|
+
let makeGetNormalRecieptsSelection = (
|
|
24
|
+
~nonWildcardLogDataRbsByContract,
|
|
25
|
+
~nonLogDataReceiptTypesByContract,
|
|
26
|
+
~contractNames,
|
|
27
|
+
) => {
|
|
28
|
+
(~addressesByContractName) => {
|
|
29
|
+
let selection: array<HyperFuelClient.QueryTypes.receiptSelection> = []
|
|
30
|
+
|
|
31
|
+
//Instantiate each time to add new registered contract addresses
|
|
32
|
+
contractNames->Utils.Set.forEach(contractName => {
|
|
33
|
+
switch addressesByContractName->Utils.Dict.dangerouslyGetNonOption(contractName) {
|
|
34
|
+
| None
|
|
35
|
+
| Some([]) => ()
|
|
36
|
+
| Some(addresses) => {
|
|
37
|
+
switch nonLogDataReceiptTypesByContract->Utils.Dict.dangerouslyGetNonOption(
|
|
38
|
+
contractName,
|
|
39
|
+
) {
|
|
40
|
+
| Some(receiptTypes) =>
|
|
41
|
+
selection
|
|
42
|
+
->Js.Array2.push({
|
|
43
|
+
rootContractId: addresses,
|
|
44
|
+
receiptType: receiptTypes,
|
|
45
|
+
txStatus: txStatusSelection,
|
|
46
|
+
})
|
|
47
|
+
->ignore
|
|
48
|
+
| None => ()
|
|
49
|
+
}
|
|
50
|
+
switch nonWildcardLogDataRbsByContract->Utils.Dict.dangerouslyGetNonOption(contractName) {
|
|
51
|
+
| None
|
|
52
|
+
| Some([]) => ()
|
|
53
|
+
| Some(nonWildcardLogDataRbs) =>
|
|
54
|
+
selection
|
|
55
|
+
->Js.Array2.push({
|
|
56
|
+
rootContractId: addresses,
|
|
57
|
+
receiptType: logDataReceiptTypeSelection,
|
|
58
|
+
txStatus: txStatusSelection,
|
|
59
|
+
rb: nonWildcardLogDataRbs,
|
|
60
|
+
})
|
|
61
|
+
->ignore
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
selection
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
let makeWildcardRecieptsSelection = (~wildcardLogDataRbs, ~nonLogDataWildcardReceiptTypes) => {
|
|
72
|
+
let selection: array<HyperFuelClient.QueryTypes.receiptSelection> = []
|
|
73
|
+
|
|
74
|
+
switch nonLogDataWildcardReceiptTypes {
|
|
75
|
+
| [] => ()
|
|
76
|
+
| nonLogDataWildcardReceiptTypes =>
|
|
77
|
+
selection
|
|
78
|
+
->Js.Array2.push(
|
|
79
|
+
(
|
|
80
|
+
{
|
|
81
|
+
receiptType: nonLogDataWildcardReceiptTypes,
|
|
82
|
+
txStatus: txStatusSelection,
|
|
83
|
+
}: HyperFuelClient.QueryTypes.receiptSelection
|
|
84
|
+
),
|
|
85
|
+
)
|
|
86
|
+
->ignore
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
switch wildcardLogDataRbs {
|
|
90
|
+
| [] => ()
|
|
91
|
+
| wildcardLogDataRbs =>
|
|
92
|
+
selection
|
|
93
|
+
->Js.Array2.push(
|
|
94
|
+
(
|
|
95
|
+
{
|
|
96
|
+
receiptType: logDataReceiptTypeSelection,
|
|
97
|
+
txStatus: txStatusSelection,
|
|
98
|
+
rb: wildcardLogDataRbs,
|
|
99
|
+
}: HyperFuelClient.QueryTypes.receiptSelection
|
|
100
|
+
),
|
|
101
|
+
)
|
|
102
|
+
->ignore
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
selection
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
let getSelectionConfig = (selection: FetchState.selection, ~chain) => {
|
|
109
|
+
let eventRouter = EventRouter.empty()
|
|
110
|
+
let nonWildcardLogDataRbsByContract = Js.Dict.empty()
|
|
111
|
+
let wildcardLogDataRbs = []
|
|
112
|
+
|
|
113
|
+
// This is for non-LogData events, since they don't have rb filter and can be grouped
|
|
114
|
+
let nonLogDataReceiptTypesByContract = Js.Dict.empty()
|
|
115
|
+
let nonLogDataWildcardReceiptTypes = []
|
|
116
|
+
|
|
117
|
+
let addNonLogDataWildcardReceiptTypes = (receiptType: Fuel.receiptType) => {
|
|
118
|
+
nonLogDataWildcardReceiptTypes->Array.push(receiptType)->ignore
|
|
119
|
+
}
|
|
120
|
+
let addNonLogDataReceiptType = (contractName, receiptType: Fuel.receiptType) => {
|
|
121
|
+
switch nonLogDataReceiptTypesByContract->Utils.Dict.dangerouslyGetNonOption(contractName) {
|
|
122
|
+
| None => nonLogDataReceiptTypesByContract->Js.Dict.set(contractName, [receiptType])
|
|
123
|
+
| Some(receiptTypes) => receiptTypes->Array.push(receiptType)->ignore // Duplication prevented by EventRouter
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
let contractNames = Utils.Set.make()
|
|
128
|
+
|
|
129
|
+
selection.eventConfigs
|
|
130
|
+
->(Utils.magic: array<Internal.eventConfig> => array<Internal.fuelEventConfig>)
|
|
131
|
+
->Array.forEach(eventConfig => {
|
|
132
|
+
let contractName = eventConfig.contractName
|
|
133
|
+
if !eventConfig.isWildcard {
|
|
134
|
+
let _ = contractNames->Utils.Set.add(contractName)
|
|
135
|
+
}
|
|
136
|
+
eventRouter->EventRouter.addOrThrow(
|
|
137
|
+
eventConfig.id,
|
|
138
|
+
eventConfig,
|
|
139
|
+
~contractName,
|
|
140
|
+
~eventName=eventConfig.name,
|
|
141
|
+
~chain,
|
|
142
|
+
~isWildcard=eventConfig.isWildcard,
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
switch eventConfig {
|
|
146
|
+
| {kind: Mint, isWildcard: true} => addNonLogDataWildcardReceiptTypes(Mint)
|
|
147
|
+
| {kind: Mint} => addNonLogDataReceiptType(contractName, Mint)
|
|
148
|
+
| {kind: Burn, isWildcard: true} => addNonLogDataWildcardReceiptTypes(Burn)
|
|
149
|
+
| {kind: Burn} => addNonLogDataReceiptType(contractName, Burn)
|
|
150
|
+
| {kind: Transfer, isWildcard: true} => {
|
|
151
|
+
addNonLogDataWildcardReceiptTypes(Transfer)
|
|
152
|
+
addNonLogDataWildcardReceiptTypes(TransferOut)
|
|
153
|
+
}
|
|
154
|
+
| {kind: Transfer} => {
|
|
155
|
+
addNonLogDataReceiptType(contractName, Transfer)
|
|
156
|
+
addNonLogDataReceiptType(contractName, TransferOut)
|
|
157
|
+
}
|
|
158
|
+
| {kind: Call, isWildcard: true} => addNonLogDataWildcardReceiptTypes(Call)
|
|
159
|
+
| {kind: Call} =>
|
|
160
|
+
Js.Exn.raiseError("Call receipt indexing currently supported only in wildcard mode")
|
|
161
|
+
| {kind: LogData({logId}), isWildcard} => {
|
|
162
|
+
let rb = logId->BigInt.fromStringUnsafe
|
|
163
|
+
if isWildcard {
|
|
164
|
+
wildcardLogDataRbs->Array.push(rb)->ignore
|
|
165
|
+
} else {
|
|
166
|
+
switch nonWildcardLogDataRbsByContract->Utils.Dict.dangerouslyGetNonOption(contractName) {
|
|
167
|
+
| Some(arr) => arr->Belt.Array.push(rb)
|
|
168
|
+
| None => nonWildcardLogDataRbsByContract->Js.Dict.set(contractName, [rb])
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
})
|
|
174
|
+
|
|
175
|
+
{
|
|
176
|
+
getRecieptsSelection: switch selection.dependsOnAddresses {
|
|
177
|
+
| false => {
|
|
178
|
+
let recieptsSelection = makeWildcardRecieptsSelection(
|
|
179
|
+
~wildcardLogDataRbs,
|
|
180
|
+
~nonLogDataWildcardReceiptTypes,
|
|
181
|
+
)
|
|
182
|
+
(~addressesByContractName as _) => recieptsSelection
|
|
183
|
+
}
|
|
184
|
+
| true =>
|
|
185
|
+
makeGetNormalRecieptsSelection(
|
|
186
|
+
~nonWildcardLogDataRbsByContract,
|
|
187
|
+
~nonLogDataReceiptTypesByContract,
|
|
188
|
+
~contractNames,
|
|
189
|
+
)
|
|
190
|
+
},
|
|
191
|
+
eventRouter,
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
let memoGetSelectionConfig = (~chain) => {
|
|
196
|
+
let cache = Utils.WeakMap.make()
|
|
197
|
+
selection =>
|
|
198
|
+
switch cache->Utils.WeakMap.get(selection) {
|
|
199
|
+
| Some(c) => c
|
|
200
|
+
| None => {
|
|
201
|
+
let c = selection->getSelectionConfig(~chain)
|
|
202
|
+
let _ = cache->Utils.WeakMap.set(selection, c)
|
|
203
|
+
c
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
type options = {
|
|
209
|
+
chain: ChainMap.Chain.t,
|
|
210
|
+
endpointUrl: string,
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
let make = ({chain, endpointUrl}: options): t => {
|
|
214
|
+
let name = "HyperFuel"
|
|
215
|
+
|
|
216
|
+
let getSelectionConfig = memoGetSelectionConfig(~chain)
|
|
217
|
+
|
|
218
|
+
let getItemsOrThrow = async (
|
|
219
|
+
~fromBlock,
|
|
220
|
+
~toBlock,
|
|
221
|
+
~addressesByContractName,
|
|
222
|
+
~indexingContracts,
|
|
223
|
+
~currentBlockHeight,
|
|
224
|
+
~partitionId as _,
|
|
225
|
+
~selection: FetchState.selection,
|
|
226
|
+
~retry,
|
|
227
|
+
~logger,
|
|
228
|
+
) => {
|
|
229
|
+
let mkLogAndRaise = ErrorHandling.mkLogAndRaise(~logger, ...)
|
|
230
|
+
let totalTimeRef = Hrtime.makeTimer()
|
|
231
|
+
|
|
232
|
+
let selectionConfig = getSelectionConfig(selection)
|
|
233
|
+
let recieptsSelection = selectionConfig.getRecieptsSelection(~addressesByContractName)
|
|
234
|
+
|
|
235
|
+
let startFetchingBatchTimeRef = Hrtime.makeTimer()
|
|
236
|
+
|
|
237
|
+
//fetch batch
|
|
238
|
+
let pageUnsafe = try await HyperFuel.GetLogs.query(
|
|
239
|
+
~serverUrl=endpointUrl,
|
|
240
|
+
~fromBlock,
|
|
241
|
+
~toBlock,
|
|
242
|
+
~recieptsSelection,
|
|
243
|
+
) catch {
|
|
244
|
+
| HyperSync.GetLogs.Error(error) =>
|
|
245
|
+
raise(
|
|
246
|
+
Source.GetItemsError(
|
|
247
|
+
Source.FailedGettingItems({
|
|
248
|
+
exn: %raw(`null`),
|
|
249
|
+
attemptedToBlock: toBlock->Option.getWithDefault(currentBlockHeight),
|
|
250
|
+
retry: switch error {
|
|
251
|
+
| WrongInstance =>
|
|
252
|
+
let backoffMillis = switch retry {
|
|
253
|
+
| 0 => 100
|
|
254
|
+
| _ => 500 * retry
|
|
255
|
+
}
|
|
256
|
+
WithBackoff({
|
|
257
|
+
message: `Block #${fromBlock->Int.toString} not found in HyperFuel. HyperFuel has multiple instances and it's possible that they drift independently slightly from the head. Indexing should continue correctly after retrying the query in ${backoffMillis->Int.toString}ms.`,
|
|
258
|
+
backoffMillis,
|
|
259
|
+
})
|
|
260
|
+
| UnexpectedMissingParams({missingParams}) =>
|
|
261
|
+
WithBackoff({
|
|
262
|
+
message: `Received page response with invalid data. Attempt a retry. Missing params: ${missingParams->Js.Array2.joinWith(
|
|
263
|
+
",",
|
|
264
|
+
)}`,
|
|
265
|
+
backoffMillis: switch retry {
|
|
266
|
+
| 0 => 1000
|
|
267
|
+
| _ => 4000 * retry
|
|
268
|
+
},
|
|
269
|
+
})
|
|
270
|
+
},
|
|
271
|
+
}),
|
|
272
|
+
),
|
|
273
|
+
)
|
|
274
|
+
| exn =>
|
|
275
|
+
raise(
|
|
276
|
+
Source.GetItemsError(
|
|
277
|
+
Source.FailedGettingItems({
|
|
278
|
+
exn,
|
|
279
|
+
attemptedToBlock: toBlock->Option.getWithDefault(currentBlockHeight),
|
|
280
|
+
retry: WithBackoff({
|
|
281
|
+
message: `Unexpected issue while fetching events from HyperFuel client. Attempt a retry.`,
|
|
282
|
+
backoffMillis: switch retry {
|
|
283
|
+
| 0 => 500
|
|
284
|
+
| _ => 1000 * retry
|
|
285
|
+
},
|
|
286
|
+
}),
|
|
287
|
+
}),
|
|
288
|
+
),
|
|
289
|
+
)
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
let pageFetchTime =
|
|
293
|
+
startFetchingBatchTimeRef->Hrtime.timeSince->Hrtime.toMillis->Hrtime.intFromMillis
|
|
294
|
+
|
|
295
|
+
//set height and next from block
|
|
296
|
+
let currentBlockHeight = pageUnsafe.archiveHeight
|
|
297
|
+
|
|
298
|
+
//The heighest (biggest) blocknumber that was accounted for in
|
|
299
|
+
//Our query. Not necessarily the blocknumber of the last log returned
|
|
300
|
+
//In the query
|
|
301
|
+
let heighestBlockQueried = pageUnsafe.nextBlock - 1
|
|
302
|
+
|
|
303
|
+
let lastBlockQueriedPromise = // switch pageUnsafe.rollbackGuard {
|
|
304
|
+
// //In the case a rollbackGuard is returned (this only happens at the head for unconfirmed blocks)
|
|
305
|
+
// //use these values
|
|
306
|
+
// | Some({blockNumber, timestamp, hash}) =>
|
|
307
|
+
// {
|
|
308
|
+
// ReorgDetection.blockNumber,
|
|
309
|
+
// blockTimestamp: timestamp,
|
|
310
|
+
// blockHash: hash,
|
|
311
|
+
// }->Promise.resolve
|
|
312
|
+
// | None =>
|
|
313
|
+
//The optional block and timestamp of the last item returned by the query
|
|
314
|
+
//(Optional in the case that there are no logs returned in the query)
|
|
315
|
+
switch pageUnsafe.items->Belt.Array.get(pageUnsafe.items->Belt.Array.length - 1) {
|
|
316
|
+
| Some({block}) if block.height == heighestBlockQueried =>
|
|
317
|
+
//If the last log item in the current page is equal to the
|
|
318
|
+
//heighest block acounted for in the query. Simply return this
|
|
319
|
+
//value without making an extra query
|
|
320
|
+
|
|
321
|
+
(
|
|
322
|
+
{
|
|
323
|
+
blockNumber: block.height,
|
|
324
|
+
blockTimestamp: block.time,
|
|
325
|
+
blockHash: block.id,
|
|
326
|
+
}: ReorgDetection.blockDataWithTimestamp
|
|
327
|
+
)->Promise.resolve
|
|
328
|
+
//If it does not match it means that there were no matching logs in the last
|
|
329
|
+
//block so we should fetch the block data
|
|
330
|
+
| Some(_)
|
|
331
|
+
| None =>
|
|
332
|
+
//If there were no logs at all in the current page query then fetch the
|
|
333
|
+
//timestamp of the heighest block accounted for
|
|
334
|
+
HyperFuel.queryBlockData(~serverUrl=endpointUrl, ~blockNumber=heighestBlockQueried, ~logger)
|
|
335
|
+
->Promise.thenResolve(res => {
|
|
336
|
+
switch res {
|
|
337
|
+
| Some(blockData) => blockData
|
|
338
|
+
| None =>
|
|
339
|
+
mkLogAndRaise(
|
|
340
|
+
Not_found,
|
|
341
|
+
~msg=`Failure, blockData for block ${heighestBlockQueried->Int.toString} unexpectedly returned None`,
|
|
342
|
+
)
|
|
343
|
+
}
|
|
344
|
+
})
|
|
345
|
+
->Promise.catch(exn => {
|
|
346
|
+
exn->mkLogAndRaise(
|
|
347
|
+
~msg=`Failed to query blockData for block ${heighestBlockQueried->Int.toString}`,
|
|
348
|
+
)
|
|
349
|
+
})
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
let parsingTimeRef = Hrtime.makeTimer()
|
|
353
|
+
|
|
354
|
+
let parsedQueueItems = pageUnsafe.items->Array.map(item => {
|
|
355
|
+
let {contractId: contractAddress, receipt, block, receiptIndex} = item
|
|
356
|
+
|
|
357
|
+
let chainId = chain->ChainMap.Chain.toChainId
|
|
358
|
+
let eventId = switch receipt {
|
|
359
|
+
| LogData({rb}) => BigInt.toString(rb)
|
|
360
|
+
| Mint(_) => mintEventTag
|
|
361
|
+
| Burn(_) => burnEventTag
|
|
362
|
+
| Transfer(_)
|
|
363
|
+
| TransferOut(_) => transferEventTag
|
|
364
|
+
| Call(_) => callEventTag
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
let eventConfig = switch selectionConfig.eventRouter->EventRouter.get(
|
|
368
|
+
~tag=eventId,
|
|
369
|
+
~indexingContracts,
|
|
370
|
+
~contractAddress,
|
|
371
|
+
~blockNumber=block.height,
|
|
372
|
+
) {
|
|
373
|
+
| None => {
|
|
374
|
+
let logger = Logging.createChildFrom(
|
|
375
|
+
~logger,
|
|
376
|
+
~params={
|
|
377
|
+
"chainId": chainId,
|
|
378
|
+
"blockNumber": block.height,
|
|
379
|
+
"logIndex": receiptIndex,
|
|
380
|
+
"contractAddress": contractAddress,
|
|
381
|
+
"eventId": eventId,
|
|
382
|
+
},
|
|
383
|
+
)
|
|
384
|
+
EventRoutingFailed->ErrorHandling.mkLogAndRaise(
|
|
385
|
+
~msg="Failed to route registered event",
|
|
386
|
+
~logger,
|
|
387
|
+
)
|
|
388
|
+
}
|
|
389
|
+
| Some(eventConfig) => eventConfig
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
let params = switch (eventConfig, receipt) {
|
|
393
|
+
| ({kind: LogData({decode})}, LogData({data})) =>
|
|
394
|
+
try decode(data) catch {
|
|
395
|
+
| exn => {
|
|
396
|
+
let params = {
|
|
397
|
+
"chainId": chainId,
|
|
398
|
+
"blockNumber": block.height,
|
|
399
|
+
"logIndex": receiptIndex,
|
|
400
|
+
}
|
|
401
|
+
let logger = Logging.createChildFrom(~logger, ~params)
|
|
402
|
+
exn->ErrorHandling.mkLogAndRaise(
|
|
403
|
+
~msg="Failed to decode Fuel LogData receipt, please double check your ABI.",
|
|
404
|
+
~logger,
|
|
405
|
+
)
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
| (_, Mint({val, subId}))
|
|
409
|
+
| (_, Burn({val, subId})) =>
|
|
410
|
+
(
|
|
411
|
+
{
|
|
412
|
+
subId,
|
|
413
|
+
amount: val,
|
|
414
|
+
}: Internal.fuelSupplyParams
|
|
415
|
+
)->Obj.magic
|
|
416
|
+
| (_, Transfer({amount, assetId, to})) =>
|
|
417
|
+
(
|
|
418
|
+
{
|
|
419
|
+
to: to->Address.unsafeFromString,
|
|
420
|
+
assetId,
|
|
421
|
+
amount,
|
|
422
|
+
}: Internal.fuelTransferParams
|
|
423
|
+
)->Obj.magic
|
|
424
|
+
| (_, TransferOut({amount, assetId, toAddress})) =>
|
|
425
|
+
(
|
|
426
|
+
{
|
|
427
|
+
to: toAddress->Address.unsafeFromString,
|
|
428
|
+
assetId,
|
|
429
|
+
amount,
|
|
430
|
+
}: Internal.fuelTransferParams
|
|
431
|
+
)->Obj.magic
|
|
432
|
+
| (_, Call({amount, assetId, to})) =>
|
|
433
|
+
(
|
|
434
|
+
{
|
|
435
|
+
to: to->Address.unsafeFromString,
|
|
436
|
+
assetId,
|
|
437
|
+
amount,
|
|
438
|
+
}: Internal.fuelTransferParams
|
|
439
|
+
)->Obj.magic
|
|
440
|
+
// This should never happen unless there's a bug in the routing logic
|
|
441
|
+
| _ => Js.Exn.raiseError("Unexpected bug in the event routing logic")
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
Internal.Event({
|
|
445
|
+
eventConfig: (eventConfig :> Internal.eventConfig),
|
|
446
|
+
timestamp: block.time,
|
|
447
|
+
chain,
|
|
448
|
+
blockNumber: block.height,
|
|
449
|
+
logIndex: receiptIndex,
|
|
450
|
+
event: {
|
|
451
|
+
chainId,
|
|
452
|
+
params,
|
|
453
|
+
transaction: {
|
|
454
|
+
"id": item.transactionId,
|
|
455
|
+
}->Obj.magic, // TODO: Obj.magic needed until the field selection types are not configurable for Fuel and Evm separately
|
|
456
|
+
block: block->Obj.magic,
|
|
457
|
+
srcAddress: contractAddress,
|
|
458
|
+
logIndex: receiptIndex,
|
|
459
|
+
},
|
|
460
|
+
})
|
|
461
|
+
})
|
|
462
|
+
|
|
463
|
+
let parsingTimeElapsed = parsingTimeRef->Hrtime.timeSince->Hrtime.toMillis->Hrtime.intFromMillis
|
|
464
|
+
|
|
465
|
+
let rangeLastBlock = await lastBlockQueriedPromise
|
|
466
|
+
|
|
467
|
+
let reorgGuard: ReorgDetection.reorgGuard = {
|
|
468
|
+
rangeLastBlock: rangeLastBlock->ReorgDetection.generalizeBlockDataWithTimestamp,
|
|
469
|
+
prevRangeLastBlock: None,
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
let totalTimeElapsed = totalTimeRef->Hrtime.timeSince->Hrtime.toMillis->Hrtime.intFromMillis
|
|
473
|
+
|
|
474
|
+
let stats = {
|
|
475
|
+
totalTimeElapsed,
|
|
476
|
+
parsingTimeElapsed,
|
|
477
|
+
pageFetchTime,
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
{
|
|
481
|
+
latestFetchedBlockTimestamp: rangeLastBlock.blockTimestamp,
|
|
482
|
+
parsedQueueItems,
|
|
483
|
+
latestFetchedBlockNumber: rangeLastBlock.blockNumber,
|
|
484
|
+
stats,
|
|
485
|
+
currentBlockHeight,
|
|
486
|
+
reorgGuard,
|
|
487
|
+
fromBlockQueried: fromBlock,
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
let getBlockHashes = (~blockNumbers as _, ~logger as _) =>
|
|
492
|
+
Js.Exn.raiseError("HyperFuel does not support getting block hashes")
|
|
493
|
+
|
|
494
|
+
let jsonApiClient = Rest.client(endpointUrl)
|
|
495
|
+
|
|
496
|
+
{
|
|
497
|
+
name,
|
|
498
|
+
sourceFor: Sync,
|
|
499
|
+
chain,
|
|
500
|
+
getBlockHashes,
|
|
501
|
+
pollingInterval: 100,
|
|
502
|
+
poweredByHyperSync: true,
|
|
503
|
+
getHeightOrThrow: () => HyperFuel.heightRoute->Rest.fetch((), ~client=jsonApiClient),
|
|
504
|
+
getItemsOrThrow,
|
|
505
|
+
}
|
|
506
|
+
}
|