envio 3.13.0 → 3.14.0-subgraph
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/bin.mjs +10 -1
- package/index.d.ts +11 -0
- package/package.json +8 -20
- package/rescript.json +1 -4
- package/src/Config.res +78 -100
- package/src/Config.res.mjs +55 -64
- package/src/Core.res +67 -6
- package/src/Core.res.mjs +58 -4
- package/src/EventConfigBuilder.res +4 -10
- package/src/EventConfigBuilder.res.mjs +1 -3
- package/src/EventProcessing.res +6 -6
- package/src/EventProcessing.res.mjs +8 -6
- package/src/ExitOnCaughtUp.res +5 -1
- package/src/ExitOnCaughtUp.res.mjs +8 -3
- package/src/HandlerLoader.res +98 -36
- package/src/HandlerLoader.res.mjs +89 -24
- package/src/HandlerTypeCheck.mjs +14 -0
- package/src/HandlerTypeCheckWorker.mjs +68 -0
- package/src/Internal.res +1 -1
- package/src/LoadLayer.res +39 -7
- package/src/LoadLayer.res.mjs +65 -38
- package/src/LoadLayer.resi +28 -0
- package/src/Main.res +17 -12
- package/src/Main.res.mjs +9 -3
- package/src/NodeVersion.mjs +13 -0
- package/src/Persistence.res +79 -38
- package/src/Persistence.res.mjs +41 -10
- package/src/PgStorage.res +86 -39
- package/src/PgStorage.res.mjs +83 -32
- package/src/ResumePlan.res +172 -0
- package/src/ResumePlan.res.mjs +122 -0
- package/src/Supervisor.res +8 -8
- package/src/Supervisor.res.mjs +6 -1
- package/src/SyncWrites.res +86 -0
- package/src/SyncWrites.res.mjs +85 -0
- package/src/TestIndexer.res +14 -4
- package/src/TestIndexer.res.mjs +3 -2
- package/src/TsModuleHooks.mjs +121 -0
- package/src/UserContext.res +377 -62
- package/src/UserContext.res.mjs +297 -39
- package/src/Utils.res +0 -8
- package/src/Worker.res +8 -0
- package/src/Worker.res.mjs +11 -0
- package/src/bindings/NodeJs.res +8 -7
- package/src/bindings/NodeJs.res.mjs +0 -3
- package/src/bindings/Pino.res +2 -2
- package/src/db/InternalTable.res +52 -2
- package/src/db/InternalTable.res.mjs +32 -3
- package/src/db/Table.res +10 -0
- package/src/db/Table.res.mjs +22 -11
- package/src/sources/FuelHyperSync.res +2 -0
- package/src/sources/FuelHyperSync.res.mjs +1 -0
- package/src/sources/FuelHyperSync.resi +1 -0
- package/src/sources/FuelHyperSyncClient.res +25 -8
- package/src/sources/FuelHyperSyncClient.res.mjs +8 -2
- package/src/sources/FuelHyperSyncSource.res +24 -22
- package/src/sources/FuelHyperSyncSource.res.mjs +18 -13
- package/src/subgraph/abi-types.ts +63 -0
- package/src/subgraph/assemblyscript.ts +85 -0
- package/src/subgraph/blocks.ts +183 -0
- package/src/subgraph/calls.ts +149 -0
- package/src/subgraph/conformance.ts +83 -0
- package/src/subgraph/errors.ts +96 -0
- package/src/subgraph/graph-cli-worker.mjs +26 -0
- package/src/subgraph/graph-cli.ts +190 -0
- package/src/subgraph/graph-ts-enums.ts +28 -0
- package/src/subgraph/graph-ts-types/VERSION +2 -0
- package/src/subgraph/graph-ts-types/chain/arweave.d.ts +70 -0
- package/src/subgraph/graph-ts-types/chain/cosmos.d.ts +327 -0
- package/src/subgraph/graph-ts-types/chain/ethereum.d.ts +233 -0
- package/src/subgraph/graph-ts-types/chain/near.d.ts +253 -0
- package/src/subgraph/graph-ts-types/chain/starknet.d.ts +32 -0
- package/src/subgraph/graph-ts-types/common/collections.d.ts +136 -0
- package/src/subgraph/graph-ts-types/common/conversion.d.ts +11 -0
- package/src/subgraph/graph-ts-types/common/datasource.d.ts +30 -0
- package/src/subgraph/graph-ts-types/common/eager-offset.d.ts +0 -0
- package/src/subgraph/graph-ts-types/common/json.d.ts +17 -0
- package/src/subgraph/graph-ts-types/common/numbers.d.ts +120 -0
- package/src/subgraph/graph-ts-types/common/value.d.ts +120 -0
- package/src/subgraph/graph-ts-types/common/yaml.d.ts +90 -0
- package/src/subgraph/graph-ts-types/global/global.d.ts +194 -0
- package/src/subgraph/graph-ts-types/helper-functions.d.ts +22 -0
- package/src/subgraph/graph-ts-types/index.d.ts +102 -0
- package/src/subgraph/graph-ts.ts +2285 -0
- package/src/subgraph/hosts.ts +158 -0
- package/src/subgraph/rpc.ts +65 -0
- package/src/subgraph/runtime.ts +595 -0
- package/src/subgraph/scope.ts +68 -0
- package/src/tui/InitApi.res +85 -0
- package/src/tui/{components/CustomHooks.res.mjs → InitApi.res.mjs} +11 -64
- package/src/tui/Tui.res +142 -249
- package/src/tui/Tui.res.mjs +123 -332
- package/src/Js.shim.ts +0 -11
- package/src/bindings/DateFns.res +0 -74
- package/src/bindings/DateFns.res.mjs +0 -22
- package/src/sources/FuelSDK.res +0 -38
- package/src/sources/FuelSDK.res.mjs +0 -27
- package/src/sources/vendored-fuel-abi-coder.js +0 -1792
- package/src/tui/bindings/Ink.res +0 -369
- package/src/tui/bindings/Ink.res.mjs +0 -66
- package/src/tui/bindings/Style.res +0 -123
- package/src/tui/bindings/Style.res.mjs +0 -2
- package/src/tui/components/BufferedProgressBar.res +0 -40
- package/src/tui/components/BufferedProgressBar.res.mjs +0 -57
- package/src/tui/components/CustomHooks.res +0 -122
- package/src/tui/components/Messages.res +0 -40
- package/src/tui/components/Messages.res.mjs +0 -71
- package/src/tui/components/SyncETA.res +0 -179
- package/src/tui/components/SyncETA.res.mjs +0 -249
- package/src/tui/components/TuiData.res +0 -98
- package/src/tui/components/TuiData.res.mjs +0 -73
|
@@ -133,12 +133,15 @@ function $$delete(sql, pgSchema, keys, chainIdModeOpt) {
|
|
|
133
133
|
], {prepare: true});
|
|
134
134
|
}
|
|
135
135
|
|
|
136
|
-
function makeGetRowsQuery(pgSchema) {
|
|
136
|
+
function makeGetRowsQuery(pgSchema, onlyConfigOpt) {
|
|
137
|
+
let onlyConfig = onlyConfigOpt !== undefined ? onlyConfigOpt : false;
|
|
137
138
|
return `SELECT "chain_id" as "chainId",
|
|
138
139
|
"address" as "address",
|
|
139
140
|
"contract_id" as "contractId",
|
|
140
141
|
"registration_block" as "registrationBlock"
|
|
141
|
-
FROM "` + pgSchema + `"."` + table$1.tableName + `"
|
|
142
|
+
FROM "` + pgSchema + `"."` + table$1.tableName + `"` + (
|
|
143
|
+
onlyConfig ? ` WHERE "registration_block" = ` + AddressRows.configRegistrationBlock.toString() : ""
|
|
144
|
+
) + `;`;
|
|
142
145
|
}
|
|
143
146
|
|
|
144
147
|
let EnvioAddresses = {
|
|
@@ -264,6 +267,31 @@ WHERE "` + "id" + `" = $2
|
|
|
264
267
|
AND "` + "ready_at" + `" IS NULL;`;
|
|
265
268
|
}
|
|
266
269
|
|
|
270
|
+
async function readStoredChains(sql, pgSchema) {
|
|
271
|
+
let match = await Promise.all([
|
|
272
|
+
sql.unsafe(`SELECT "` + "id" + `" as "id",
|
|
273
|
+
"` + "ecosystem" + `" as "ecosystem",
|
|
274
|
+
"` + "start_block" + `" as "startBlock",
|
|
275
|
+
"` + "end_block" + `" as "endBlock",
|
|
276
|
+
"` + "max_reorg_depth" + `" as "maxReorgDepth"
|
|
277
|
+
FROM "` + pgSchema + `"."` + table$2.tableName + `";`),
|
|
278
|
+
sql.unsafe(makeGetRowsQuery(pgSchema, true))
|
|
279
|
+
]);
|
|
280
|
+
let configAddressesByChain = {};
|
|
281
|
+
match[1].forEach(addressRow => Utils.Dict.push(configAddressesByChain, ChainId.toString(ChainId.normalizeOrThrow(addressRow.chainId)), addressRow));
|
|
282
|
+
return match[0].map(row => {
|
|
283
|
+
let id = ChainId.normalizeOrThrow(row.id);
|
|
284
|
+
return {
|
|
285
|
+
id: id,
|
|
286
|
+
ecosystem: row.ecosystem,
|
|
287
|
+
startBlock: row.startBlock,
|
|
288
|
+
endBlock: Primitive_option.fromNull(row.endBlock),
|
|
289
|
+
maxReorgDepth: row.maxReorgDepth,
|
|
290
|
+
configAddresses: Stdlib_Option.getOr(configAddressesByChain[ChainId.toString(id)], [])
|
|
291
|
+
};
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
|
|
267
295
|
function makeGetInitialStateQuery(pgSchema) {
|
|
268
296
|
return `SELECT "` + "id" + `" as "id",
|
|
269
297
|
"` + "start_block" + `" as "startBlock",
|
|
@@ -282,7 +310,7 @@ FROM "` + pgSchema + `"."` + table$2.tableName + `";`;
|
|
|
282
310
|
async function getInitialState(sql, pgSchema) {
|
|
283
311
|
let match = await Promise.all([
|
|
284
312
|
sql.unsafe(makeGetInitialStateQuery(pgSchema)),
|
|
285
|
-
sql.unsafe(makeGetRowsQuery(pgSchema))
|
|
313
|
+
sql.unsafe(makeGetRowsQuery(pgSchema, undefined))
|
|
286
314
|
]);
|
|
287
315
|
let addressRowsByChainId = AddressRows.group(match[1]);
|
|
288
316
|
return match[0].map(rawInitialState => {
|
|
@@ -384,6 +412,7 @@ let Chains = {
|
|
|
384
412
|
metaFields: metaFields,
|
|
385
413
|
makeMetaFieldsUpdateQuery: makeMetaFieldsUpdateQuery,
|
|
386
414
|
makeSetReadyAtQuery: makeSetReadyAtQuery,
|
|
415
|
+
readStoredChains: readStoredChains,
|
|
387
416
|
makeGetInitialStateQuery: makeGetInitialStateQuery,
|
|
388
417
|
getInitialState: getInitialState,
|
|
389
418
|
blockTimeToDb: blockTimeToDb,
|
package/src/db/Table.res
CHANGED
|
@@ -454,6 +454,7 @@ type sqlParams<'entity> = {
|
|
|
454
454
|
quotedNonPrimaryFieldNames: array<string>,
|
|
455
455
|
arrayFieldTypes: array<string>,
|
|
456
456
|
byteaColumnIndexes: array<int>,
|
|
457
|
+
booleanArrayColumnIndexes: array<int>,
|
|
457
458
|
hasArrayField: bool,
|
|
458
459
|
}
|
|
459
460
|
|
|
@@ -464,6 +465,10 @@ let toSqlParams = (table: table, ~schema, ~pgSchema, ~chainIdMode: ChainId.mode=
|
|
|
464
465
|
// Positions of the bytea columns among the unnest parameters, which the
|
|
465
466
|
// caller binds as array literals (see `Utils.Bytes.toPgArrayLiteral`).
|
|
466
467
|
let byteaColumnIndexes = []
|
|
468
|
+
// postgres binds a JS array of booleans as a single `boolean`, whatever the
|
|
469
|
+
// column (https://github.com/porsager/postgres/issues/471), so the VALUES
|
|
470
|
+
// insert binds these columns as integer arrays and casts them back.
|
|
471
|
+
let booleanArrayColumnIndexes = []
|
|
467
472
|
let hasArrayField = ref(false)
|
|
468
473
|
|
|
469
474
|
let dbSchema: S.t<dict<unknown>> = S.schema(s =>
|
|
@@ -499,6 +504,10 @@ let toSqlParams = (table: table, ~schema, ~pgSchema, ~chainIdMode: ChainId.mode=
|
|
|
499
504
|
| None => throw(NonExistingTableField(location))
|
|
500
505
|
}
|
|
501
506
|
switch field {
|
|
507
|
+
| Field({isArray: true, fieldType: Boolean}) => {
|
|
508
|
+
hasArrayField := true
|
|
509
|
+
booleanArrayColumnIndexes->Array.push(arrayFieldTypes->Array.length)->ignore
|
|
510
|
+
}
|
|
502
511
|
| Field({isArray: true}) => hasArrayField := true
|
|
503
512
|
| Field({fieldType: Bytea}) =>
|
|
504
513
|
byteaColumnIndexes->Array.push(arrayFieldTypes->Array.length)->ignore
|
|
@@ -554,6 +563,7 @@ let toSqlParams = (table: table, ~schema, ~pgSchema, ~chainIdMode: ChainId.mode=
|
|
|
554
563
|
quotedNonPrimaryFieldNames,
|
|
555
564
|
arrayFieldTypes,
|
|
556
565
|
byteaColumnIndexes,
|
|
566
|
+
booleanArrayColumnIndexes,
|
|
557
567
|
hasArrayField: hasArrayField.contents,
|
|
558
568
|
}
|
|
559
569
|
}
|
package/src/db/Table.res.mjs
CHANGED
|
@@ -384,6 +384,7 @@ function toSqlParams(table, schema, pgSchema, chainIdModeOpt) {
|
|
|
384
384
|
let quotedNonPrimaryFieldNames = [];
|
|
385
385
|
let arrayFieldTypes = [];
|
|
386
386
|
let byteaColumnIndexes = [];
|
|
387
|
+
let booleanArrayColumnIndexes = [];
|
|
387
388
|
let hasArrayField = {
|
|
388
389
|
contents: false
|
|
389
390
|
};
|
|
@@ -441,11 +442,20 @@ function toSqlParams(table, schema, pgSchema, chainIdModeOpt) {
|
|
|
441
442
|
}
|
|
442
443
|
if (field$1.TAG === "Field") {
|
|
443
444
|
let match = field$1._0;
|
|
444
|
-
|
|
445
|
-
|
|
445
|
+
let match$1 = match.fieldType;
|
|
446
|
+
let exit = 0;
|
|
447
|
+
if (typeof match$1 !== "object" && match$1 === "Boolean") {
|
|
448
|
+
if (match.isArray) {
|
|
449
|
+
hasArrayField.contents = true;
|
|
450
|
+
booleanArrayColumnIndexes.push(arrayFieldTypes.length);
|
|
451
|
+
}
|
|
446
452
|
} else {
|
|
447
|
-
|
|
448
|
-
|
|
453
|
+
exit = 1;
|
|
454
|
+
}
|
|
455
|
+
if (exit === 1) {
|
|
456
|
+
if (match.isArray) {
|
|
457
|
+
hasArrayField.contents = true;
|
|
458
|
+
} else if (typeof match$1 !== "object" && match$1 === "Bytea") {
|
|
449
459
|
byteaColumnIndexes.push(arrayFieldTypes.length);
|
|
450
460
|
}
|
|
451
461
|
}
|
|
@@ -459,20 +469,20 @@ function toSqlParams(table, schema, pgSchema, chainIdModeOpt) {
|
|
|
459
469
|
quotedNonPrimaryFieldNames.push(quotedDbName);
|
|
460
470
|
}
|
|
461
471
|
}
|
|
462
|
-
let tmp
|
|
472
|
+
let tmp;
|
|
463
473
|
if (field$1.TAG === "Field") {
|
|
464
474
|
let f = field$1._0;
|
|
465
475
|
let pgFieldType = getPgFieldType(f.fieldType, pgSchema, true, false, f.isNullable, chainIdMode);
|
|
466
|
-
let match$
|
|
467
|
-
tmp
|
|
468
|
-
match$
|
|
476
|
+
let match$2 = f.fieldType;
|
|
477
|
+
tmp = typeof match$2 !== "object" ? (
|
|
478
|
+
match$2 === "Boolean" ? "INTEGER" + `[]::` + pgFieldType : pgFieldType
|
|
469
479
|
) : (
|
|
470
|
-
match$
|
|
480
|
+
match$2.type === "Enum" ? "TEXT" + `[]::` + pgFieldType : pgFieldType
|
|
471
481
|
);
|
|
472
482
|
} else {
|
|
473
|
-
tmp
|
|
483
|
+
tmp = "TEXT[]";
|
|
474
484
|
}
|
|
475
|
-
arrayFieldTypes.push(tmp
|
|
485
|
+
arrayFieldTypes.push(tmp);
|
|
476
486
|
dict[location] = s.m(coerceSchema(param.schema));
|
|
477
487
|
});
|
|
478
488
|
return dict;
|
|
@@ -483,6 +493,7 @@ function toSqlParams(table, schema, pgSchema, chainIdModeOpt) {
|
|
|
483
493
|
quotedNonPrimaryFieldNames: quotedNonPrimaryFieldNames,
|
|
484
494
|
arrayFieldTypes: arrayFieldTypes,
|
|
485
495
|
byteaColumnIndexes: byteaColumnIndexes,
|
|
496
|
+
booleanArrayColumnIndexes: booleanArrayColumnIndexes,
|
|
486
497
|
hasArrayField: hasArrayField.contents
|
|
487
498
|
};
|
|
488
499
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
type logsQueryPage = {
|
|
2
2
|
items: array<FuelHyperSyncClient.EventItems.item>,
|
|
3
|
+
rejectedLogData: array<FuelHyperSyncClient.EventItems.rejectedLogData>,
|
|
3
4
|
// Blocks referenced by `items`, one per height.
|
|
4
5
|
nextBlock: int,
|
|
5
6
|
archiveHeight: int,
|
|
@@ -72,6 +73,7 @@ module GetLogs = {
|
|
|
72
73
|
}
|
|
73
74
|
{
|
|
74
75
|
items: res.items,
|
|
76
|
+
rejectedLogData: res.rejectedLogData,
|
|
75
77
|
nextBlock: res.nextBlock,
|
|
76
78
|
archiveHeight: res.archiveHeight->Option.getOr(0), // TODO: FIXME: Shouldn't have a default here
|
|
77
79
|
blockStore,
|
|
@@ -64,6 +64,7 @@ async function query(client, fromBlock, toBlock, registrationIndexes, addressSet
|
|
|
64
64
|
}
|
|
65
65
|
return {
|
|
66
66
|
items: res.items,
|
|
67
|
+
rejectedLogData: res.rejectedLogData,
|
|
67
68
|
nextBlock: res.nextBlock,
|
|
68
69
|
archiveHeight: Stdlib_Option.getOr(res.archiveHeight, 0),
|
|
69
70
|
blockStore: match[1]
|
|
@@ -27,6 +27,9 @@ module Registration = {
|
|
|
27
27
|
kind: kind,
|
|
28
28
|
// The LogData `rb` value as a decimal string; absent for other kinds.
|
|
29
29
|
logId?: string,
|
|
30
|
+
// The contract's Fuel ABI, which LogData receipts are decoded against in
|
|
31
|
+
// Rust; absent for other kinds.
|
|
32
|
+
abi?: JSON.t,
|
|
30
33
|
}
|
|
31
34
|
|
|
32
35
|
let fromOnEventRegistrations = (
|
|
@@ -35,12 +38,12 @@ module Registration = {
|
|
|
35
38
|
onEventRegistrations->Array.map(reg => {
|
|
36
39
|
let eventConfig =
|
|
37
40
|
reg.eventConfig->(Utils.magic: Internal.eventConfig => Internal.fuelEventConfig)
|
|
38
|
-
let (kind, logId) = switch eventConfig.kind {
|
|
39
|
-
| LogData({logId}) => (LogData, Some(logId))
|
|
40
|
-
| Mint => (Mint, None)
|
|
41
|
-
| Burn => (Burn, None)
|
|
42
|
-
| Transfer => (Transfer, None)
|
|
43
|
-
| Call => (Call, None)
|
|
41
|
+
let (kind, logId, abi) = switch eventConfig.kind {
|
|
42
|
+
| LogData({logId, abi}) => (LogData, Some(logId), Some(abi))
|
|
43
|
+
| Mint => (Mint, None, None)
|
|
44
|
+
| Burn => (Burn, None, None)
|
|
45
|
+
| Transfer => (Transfer, None, None)
|
|
46
|
+
| Call => (Call, None, None)
|
|
44
47
|
}
|
|
45
48
|
{
|
|
46
49
|
index: reg.index,
|
|
@@ -50,6 +53,7 @@ module Registration = {
|
|
|
50
53
|
startBlock: reg.startBlock,
|
|
51
54
|
kind,
|
|
52
55
|
?logId,
|
|
56
|
+
?abi,
|
|
53
57
|
}
|
|
54
58
|
})
|
|
55
59
|
}
|
|
@@ -70,7 +74,8 @@ module EventItems = {
|
|
|
70
74
|
}
|
|
71
75
|
|
|
72
76
|
// One routed receipt with its kind-specific columns flattened: LogData
|
|
73
|
-
// carries `
|
|
77
|
+
// carries `params` decoded against the ABI (a receipt its logged type
|
|
78
|
+
// rejects is dropped in Rust), Mint/Burn carry `val`/`subId`,
|
|
74
79
|
// Transfer/TransferOut/Call carry `amount`/`assetId`/`to` (TransferOut's
|
|
75
80
|
// wallet recipient normalised into `to`).
|
|
76
81
|
type item = {
|
|
@@ -79,7 +84,7 @@ module EventItems = {
|
|
|
79
84
|
txId: string,
|
|
80
85
|
blockHeight: int,
|
|
81
86
|
srcAddress: Address.t,
|
|
82
|
-
|
|
87
|
+
params?: Internal.eventParams,
|
|
83
88
|
subId?: string,
|
|
84
89
|
val?: bigint,
|
|
85
90
|
amount?: bigint,
|
|
@@ -87,10 +92,22 @@ module EventItems = {
|
|
|
87
92
|
to?: string,
|
|
88
93
|
}
|
|
89
94
|
|
|
95
|
+
// The page's first LogData receipt a contract-bound registration's ABI
|
|
96
|
+
// rejected, with how many it rejected. The receipts themselves are dropped.
|
|
97
|
+
type rejectedLogData = {
|
|
98
|
+
onEventRegistrationIndex: int,
|
|
99
|
+
blockHeight: int,
|
|
100
|
+
receiptIndex: int,
|
|
101
|
+
txId: string,
|
|
102
|
+
dataLength: int,
|
|
103
|
+
count: int,
|
|
104
|
+
}
|
|
105
|
+
|
|
90
106
|
type response = {
|
|
91
107
|
archiveHeight: option<int>,
|
|
92
108
|
nextBlock: int,
|
|
93
109
|
items: array<item>,
|
|
110
|
+
rejectedLogData: array<rejectedLogData>,
|
|
94
111
|
}
|
|
95
112
|
}
|
|
96
113
|
|
|
@@ -13,24 +13,28 @@ function fromOnEventRegistrations(onEventRegistrations) {
|
|
|
13
13
|
case "Mint" :
|
|
14
14
|
match$1 = [
|
|
15
15
|
"Mint",
|
|
16
|
+
undefined,
|
|
16
17
|
undefined
|
|
17
18
|
];
|
|
18
19
|
break;
|
|
19
20
|
case "Burn" :
|
|
20
21
|
match$1 = [
|
|
21
22
|
"Burn",
|
|
23
|
+
undefined,
|
|
22
24
|
undefined
|
|
23
25
|
];
|
|
24
26
|
break;
|
|
25
27
|
case "Transfer" :
|
|
26
28
|
match$1 = [
|
|
27
29
|
"Transfer",
|
|
30
|
+
undefined,
|
|
28
31
|
undefined
|
|
29
32
|
];
|
|
30
33
|
break;
|
|
31
34
|
case "Call" :
|
|
32
35
|
match$1 = [
|
|
33
36
|
"Call",
|
|
37
|
+
undefined,
|
|
34
38
|
undefined
|
|
35
39
|
];
|
|
36
40
|
break;
|
|
@@ -38,7 +42,8 @@ function fromOnEventRegistrations(onEventRegistrations) {
|
|
|
38
42
|
} else {
|
|
39
43
|
match$1 = [
|
|
40
44
|
"LogData",
|
|
41
|
-
match.logId
|
|
45
|
+
match.logId,
|
|
46
|
+
match.abi
|
|
42
47
|
];
|
|
43
48
|
}
|
|
44
49
|
return {
|
|
@@ -48,7 +53,8 @@ function fromOnEventRegistrations(onEventRegistrations) {
|
|
|
48
53
|
isWildcard: reg.isWildcard,
|
|
49
54
|
startBlock: reg.startBlock,
|
|
50
55
|
kind: match$1[0],
|
|
51
|
-
logId: match$1[1]
|
|
56
|
+
logId: match$1[1],
|
|
57
|
+
abi: match$1[2]
|
|
52
58
|
};
|
|
53
59
|
});
|
|
54
60
|
}
|
|
@@ -16,6 +16,9 @@ let make = ({chainId, endpointUrl, apiToken, onEventRegistrations, addressStore}
|
|
|
16
16
|
// Per source, so one rejected token is reported once rather than on every
|
|
17
17
|
// height retry for the life of the process.
|
|
18
18
|
let unauthorizedWarned = ref(false)
|
|
19
|
+
// Registration indexes already warned about undecodable LogData — a stale
|
|
20
|
+
// ABI rejects every receipt, so one line per event is enough.
|
|
21
|
+
let rejectedLogDataWarned = Utils.Set.make()
|
|
19
22
|
|
|
20
23
|
let apiToken = apiToken->HyperSync.requireApiToken
|
|
21
24
|
|
|
@@ -106,6 +109,24 @@ let make = ({chainId, endpointUrl, apiToken, onEventRegistrations, addressStore}
|
|
|
106
109
|
|
|
107
110
|
let parsingTimeRef = Performance.now()
|
|
108
111
|
|
|
112
|
+
pageUnsafe.rejectedLogData->Array.forEach(rejected => {
|
|
113
|
+
if !(rejectedLogDataWarned->Utils.Set.has(rejected.onEventRegistrationIndex)) {
|
|
114
|
+
rejectedLogDataWarned->Utils.Set.add(rejected.onEventRegistrationIndex)->ignore
|
|
115
|
+
let eventConfig = (
|
|
116
|
+
onEventRegistrations->Array.getUnsafe(rejected.onEventRegistrationIndex)
|
|
117
|
+
).eventConfig
|
|
118
|
+
logger->Logging.childWarn({
|
|
119
|
+
"msg": `Skipped ${eventConfig.contractName}.${eventConfig.name} LogData receipts whose data doesn't decode against the contract ABI. Check that the ABI matches the deployed contract.`,
|
|
120
|
+
"chainId": chainId,
|
|
121
|
+
"blockNumber": rejected.blockHeight,
|
|
122
|
+
"logIndex": rejected.receiptIndex,
|
|
123
|
+
"txId": rejected.txId,
|
|
124
|
+
"dataLength": rejected.dataLength,
|
|
125
|
+
"skippedInPage": rejected.count,
|
|
126
|
+
})
|
|
127
|
+
}
|
|
128
|
+
})
|
|
129
|
+
|
|
109
130
|
let parsedQueueItems = pageUnsafe.items->Array.map(item => {
|
|
110
131
|
// Routing happened in Rust; the item references its registration by
|
|
111
132
|
// chain-scoped index.
|
|
@@ -116,24 +137,8 @@ let make = ({chainId, endpointUrl, apiToken, onEventRegistrations, addressStore}
|
|
|
116
137
|
)
|
|
117
138
|
|
|
118
139
|
let params = switch eventConfig.kind {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
// crosses the boundary.
|
|
122
|
-
let data = item.data->Option.getOr("")
|
|
123
|
-
try decode(data) catch {
|
|
124
|
-
| exn => {
|
|
125
|
-
let params = {
|
|
126
|
-
"chainId": chainId,
|
|
127
|
-
"blockNumber": item.blockHeight,
|
|
128
|
-
"logIndex": item.receiptIndex,
|
|
129
|
-
}
|
|
130
|
-
let logger = Logging.createChildFrom(~logger, ~params)
|
|
131
|
-
exn->ErrorHandling.mkLogAndRaise(
|
|
132
|
-
~msg="Failed to decode Fuel LogData receipt, please double check your ABI.",
|
|
133
|
-
~logger,
|
|
134
|
-
)
|
|
135
|
-
}
|
|
136
|
-
}
|
|
140
|
+
// Rust only routes a LogData receipt once its data decoded.
|
|
141
|
+
| LogData(_) => item.params->Option.getUnsafe
|
|
137
142
|
| Mint | Burn =>
|
|
138
143
|
(
|
|
139
144
|
{
|
|
@@ -213,10 +218,7 @@ let make = ({chainId, endpointUrl, apiToken, onEventRegistrations, addressStore}
|
|
|
213
218
|
let timerRef = Performance.now()
|
|
214
219
|
let height = try await client->FuelHyperSyncClient.getHeight catch {
|
|
215
220
|
| exn =>
|
|
216
|
-
exn->HyperSync.rethrowLoggingUnauthorized(
|
|
217
|
-
~warned=unauthorizedWarned,
|
|
218
|
-
~product="HyperFuel",
|
|
219
|
-
)
|
|
221
|
+
exn->HyperSync.rethrowLoggingUnauthorized(~warned=unauthorizedWarned, ~product="HyperFuel")
|
|
220
222
|
}
|
|
221
223
|
let seconds = timerRef->Performance.secondsSince
|
|
222
224
|
{height, requestStats: [{method: "getHeight", seconds}]}
|
|
@@ -18,6 +18,7 @@ function make(param) {
|
|
|
18
18
|
let unauthorizedWarned = {
|
|
19
19
|
contents: false
|
|
20
20
|
};
|
|
21
|
+
let rejectedLogDataWarned = new Set();
|
|
21
22
|
let apiToken = HyperSync.requireApiToken(param.apiToken);
|
|
22
23
|
let client;
|
|
23
24
|
try {
|
|
@@ -82,6 +83,22 @@ function make(param) {
|
|
|
82
83
|
let knownHeight$1 = pageUnsafe.archiveHeight;
|
|
83
84
|
let heighestBlockQueried = pageUnsafe.nextBlock - 1 | 0;
|
|
84
85
|
let parsingTimeRef = Performance.now();
|
|
86
|
+
pageUnsafe.rejectedLogData.forEach(rejected => {
|
|
87
|
+
if (rejectedLogDataWarned.has(rejected.onEventRegistrationIndex)) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
rejectedLogDataWarned.add(rejected.onEventRegistrationIndex);
|
|
91
|
+
let eventConfig = onEventRegistrations[rejected.onEventRegistrationIndex].eventConfig;
|
|
92
|
+
Logging.childWarn(logger, {
|
|
93
|
+
msg: `Skipped ` + eventConfig.contractName + `.` + eventConfig.name + ` LogData receipts whose data doesn't decode against the contract ABI. Check that the ABI matches the deployed contract.`,
|
|
94
|
+
chainId: chainId,
|
|
95
|
+
blockNumber: rejected.blockHeight,
|
|
96
|
+
logIndex: rejected.receiptIndex,
|
|
97
|
+
txId: rejected.txId,
|
|
98
|
+
dataLength: rejected.dataLength,
|
|
99
|
+
skippedInPage: rejected.count
|
|
100
|
+
});
|
|
101
|
+
});
|
|
85
102
|
let parsedQueueItems = pageUnsafe.items.map(item => {
|
|
86
103
|
let onEventRegistration = onEventRegistrations[item.onEventRegistrationIndex];
|
|
87
104
|
let eventConfig = onEventRegistration.eventConfig;
|
|
@@ -100,19 +117,7 @@ function make(param) {
|
|
|
100
117
|
break;
|
|
101
118
|
}
|
|
102
119
|
} else {
|
|
103
|
-
|
|
104
|
-
try {
|
|
105
|
-
params = match.decode(data);
|
|
106
|
-
} catch (raw_exn) {
|
|
107
|
-
let exn = Primitive_exceptions.internalToException(raw_exn);
|
|
108
|
-
let params$1 = {
|
|
109
|
-
chainId: chainId,
|
|
110
|
-
blockNumber: item.blockHeight,
|
|
111
|
-
logIndex: item.receiptIndex
|
|
112
|
-
};
|
|
113
|
-
let logger$1 = Logging.createChildFrom(logger, params$1);
|
|
114
|
-
params = ErrorHandling.mkLogAndRaise(logger$1, "Failed to decode Fuel LogData receipt, please double check your ABI.", exn);
|
|
115
|
-
}
|
|
120
|
+
params = item.params;
|
|
116
121
|
}
|
|
117
122
|
switch (exit) {
|
|
118
123
|
case 1 :
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Contract-call signatures and ABI type lists as graph codegen writes them.
|
|
3
|
+
* Free of envio imports: the graph-ts shim reads them too.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export type ParsedSignature = {
|
|
7
|
+
name: string;
|
|
8
|
+
inputs: string;
|
|
9
|
+
outputs: string;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* graph codegen emits `"balanceOf(address):(uint256)"`. Types only, no names —
|
|
14
|
+
* which is all `parseAbiParameters` needs.
|
|
15
|
+
*/
|
|
16
|
+
export function parseSignature(signature: string): ParsedSignature {
|
|
17
|
+
const open = signature.indexOf("(");
|
|
18
|
+
if (open === -1) {
|
|
19
|
+
throw new Error(`Unreadable contract call signature "${signature}"`);
|
|
20
|
+
}
|
|
21
|
+
const name = signature.slice(0, open);
|
|
22
|
+
|
|
23
|
+
let depth = 0;
|
|
24
|
+
let close = -1;
|
|
25
|
+
for (let index = open; index < signature.length; index++) {
|
|
26
|
+
const char = signature[index];
|
|
27
|
+
if (char === "(") depth++;
|
|
28
|
+
if (char === ")") {
|
|
29
|
+
depth--;
|
|
30
|
+
if (depth === 0) {
|
|
31
|
+
close = index;
|
|
32
|
+
break;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
if (close === -1) {
|
|
37
|
+
throw new Error(`Unreadable contract call signature "${signature}"`);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const inputs = signature.slice(open + 1, close);
|
|
41
|
+
const rest = signature.slice(close + 1).replace(/^:/, "");
|
|
42
|
+
const outputs = rest.startsWith("(") ? rest.slice(1, -1) : rest;
|
|
43
|
+
|
|
44
|
+
return { name, inputs, outputs };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** `address,(uint256,bytes)` → `["address", "(uint256,bytes)"]`. */
|
|
48
|
+
export function splitTypes(list: string): string[] {
|
|
49
|
+
const types: string[] = [];
|
|
50
|
+
let depth = 0;
|
|
51
|
+
let start = 0;
|
|
52
|
+
for (let index = 0; index < list.length; index++) {
|
|
53
|
+
const char = list[index];
|
|
54
|
+
if (char === "(") depth++;
|
|
55
|
+
else if (char === ")") depth--;
|
|
56
|
+
else if (char === "," && depth === 0) {
|
|
57
|
+
types.push(list.slice(start, index));
|
|
58
|
+
start = index + 1;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (list.length > 0) types.push(list.slice(start));
|
|
62
|
+
return types;
|
|
63
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The runtime half of `packages/cli/src/subgraph/assemblyscript.rs`, which
|
|
3
|
+
* rewrites every arithmetic and comparison operator in a mapping into a call
|
|
4
|
+
* on `OPERATORS_HELPER`, every `changetype<Foo>(x)` into one to `RETAG_HELPER`,
|
|
5
|
+
* and exports each handler's event class as `EVENT_CLASSES_EXPORT`. The names
|
|
6
|
+
* are shared with that file.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export const OPERATORS_HELPER = "__envio_op";
|
|
10
|
+
export const RETAG_HELPER = "__envio_retag";
|
|
11
|
+
export const EVENT_CLASSES_EXPORT = "__envio_event_classes";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* AssemblyScript divides two integers as integers; this truncates only when
|
|
15
|
+
* both operands really are integers and otherwise divides as before — an `f64`
|
|
16
|
+
* divides as a float in AssemblyScript too.
|
|
17
|
+
*/
|
|
18
|
+
export function integerDivision(a: unknown, b: unknown): unknown {
|
|
19
|
+
const left = typeof a === "object" && a !== null ? (a as any).valueOf() : a;
|
|
20
|
+
const right = typeof b === "object" && b !== null ? (b as any).valueOf() : b;
|
|
21
|
+
|
|
22
|
+
const integral = (v: unknown) =>
|
|
23
|
+
typeof v === "bigint" || (typeof v === "number" && Number.isInteger(v));
|
|
24
|
+
if (integral(left) && integral(right)) {
|
|
25
|
+
// Only i64 / i64 stays 64-bit; anything narrower is an i32 in AssemblyScript
|
|
26
|
+
// and must come back as a number, or the bigint spreads through every
|
|
27
|
+
// arithmetic that follows.
|
|
28
|
+
if (typeof left === "bigint" && typeof right === "bigint") {
|
|
29
|
+
return left / right;
|
|
30
|
+
}
|
|
31
|
+
return Math.trunc(Number(left) / Number(right));
|
|
32
|
+
}
|
|
33
|
+
return (left as number) / (right as number);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** The graph-ts operator overload `value` declares under `method`, if any. */
|
|
37
|
+
function overload(value: unknown, method: string): Function | undefined {
|
|
38
|
+
if (!isObject(value)) return undefined;
|
|
39
|
+
const fn = (value as Record<string, unknown>)[method];
|
|
40
|
+
return typeof fn === "function" ? fn : undefined;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function isObject(value: unknown): boolean {
|
|
44
|
+
return value !== null && typeof value === "object";
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Both operands are objects wherever AssemblyScript picks the overload — it
|
|
48
|
+
// doesn't compile `BigInt < i32` — so a primitive on either side is left to
|
|
49
|
+
// JavaScript, which reads the object through `valueOf`.
|
|
50
|
+
const binary =
|
|
51
|
+
(method: string, fallback: (a: any, b: any) => unknown) =>
|
|
52
|
+
(a: unknown, b: unknown): unknown => {
|
|
53
|
+
const declared = isObject(b) ? overload(a, method) : undefined;
|
|
54
|
+
return declared ? declared.call(a, b) : fallback(a, b);
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
// Against null AssemblyScript compares the reference, overload or not.
|
|
58
|
+
const equals = (a: unknown, b: unknown): boolean => {
|
|
59
|
+
const declared = isObject(b) ? overload(a, "equals") : undefined;
|
|
60
|
+
return declared ? (declared.call(a, b) as boolean) : a == b;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* graph-ts overloads the arithmetic and comparison operators on `BigInt`,
|
|
65
|
+
* `BigDecimal` and `ByteArray`, and AssemblyScript calls the overload: a
|
|
66
|
+
* JavaScript operator would coerce them, or compare their identity — so
|
|
67
|
+
* `address == ZERO_ADDRESS` would always be false.
|
|
68
|
+
*/
|
|
69
|
+
export const operators = {
|
|
70
|
+
add: binary("plus", (a, b) => a + b),
|
|
71
|
+
sub: binary("minus", (a, b) => a - b),
|
|
72
|
+
mul: binary("times", (a, b) => a * b),
|
|
73
|
+
div: binary("div", integerDivision),
|
|
74
|
+
rem: binary("mod", (a, b) => a % b),
|
|
75
|
+
eq: equals,
|
|
76
|
+
ne: (a: unknown, b: unknown) => !equals(a, b),
|
|
77
|
+
lt: binary("lt", (a, b) => a < b),
|
|
78
|
+
le: binary("le", (a, b) => a <= b),
|
|
79
|
+
gt: binary("gt", (a, b) => a > b),
|
|
80
|
+
ge: binary("ge", (a, b) => a >= b),
|
|
81
|
+
neg: (a: unknown) => {
|
|
82
|
+
const declared = overload(a, "neg");
|
|
83
|
+
return declared ? declared.call(a) : -(a as number);
|
|
84
|
+
},
|
|
85
|
+
};
|