@secondlayer/subgraphs 0.8.1 → 0.9.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/dist/src/index.d.ts +113 -32
- package/dist/src/index.js +453 -99
- package/dist/src/index.js.map +9 -10
- package/dist/src/runtime/block-processor.d.ts +110 -20
- package/dist/src/runtime/block-processor.js +419 -90
- package/dist/src/runtime/block-processor.js.map +7 -8
- package/dist/src/runtime/catchup.d.ts +110 -20
- package/dist/src/runtime/catchup.js +424 -94
- package/dist/src/runtime/catchup.js.map +8 -9
- package/dist/src/runtime/clarity.js +3 -3
- package/dist/src/runtime/clarity.js.map +3 -3
- package/dist/src/runtime/context.d.ts +23 -5
- package/dist/src/runtime/context.js +57 -1
- package/dist/src/runtime/context.js.map +3 -3
- package/dist/src/runtime/processor.js +424 -94
- package/dist/src/runtime/processor.js.map +8 -9
- package/dist/src/runtime/reindex.d.ts +110 -20
- package/dist/src/runtime/reindex.js +419 -90
- package/dist/src/runtime/reindex.js.map +7 -8
- package/dist/src/runtime/reorg.d.ts +110 -20
- package/dist/src/runtime/reorg.js +419 -90
- package/dist/src/runtime/reorg.js.map +7 -8
- package/dist/src/runtime/runner.d.ts +150 -42
- package/dist/src/runtime/runner.js +193 -30
- package/dist/src/runtime/runner.js.map +4 -4
- package/dist/src/runtime/source-matcher.d.ts +86 -31
- package/dist/src/runtime/source-matcher.js +171 -61
- package/dist/src/runtime/source-matcher.js.map +4 -5
- package/dist/src/schema/index.d.ts +110 -20
- package/dist/src/schema/index.js +34 -9
- package/dist/src/schema/index.js.map +3 -3
- package/dist/src/service.js +424 -94
- package/dist/src/service.js.map +8 -9
- package/dist/src/templates.js +52 -51
- package/dist/src/templates.js.map +3 -3
- package/dist/src/types.d.ts +111 -29
- package/dist/src/types.js +1 -20
- package/dist/src/types.js.map +3 -4
- package/dist/src/validate.d.ts +112 -22
- package/dist/src/validate.js +35 -10
- package/dist/src/validate.js.map +3 -3
- package/package.json +2 -2
package/dist/src/index.js
CHANGED
|
@@ -1,20 +1,6 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
2
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
3
3
|
|
|
4
|
-
// src/types.ts
|
|
5
|
-
function sourceKey(source) {
|
|
6
|
-
if (source.contract) {
|
|
7
|
-
if (source.function)
|
|
8
|
-
return `${source.contract}::${source.function}`;
|
|
9
|
-
if (source.event)
|
|
10
|
-
return `${source.contract}::${source.event}`;
|
|
11
|
-
return source.contract;
|
|
12
|
-
}
|
|
13
|
-
if (source.type)
|
|
14
|
-
return source.type;
|
|
15
|
-
return "*";
|
|
16
|
-
}
|
|
17
|
-
|
|
18
4
|
// src/validate.ts
|
|
19
5
|
import { z } from "zod/v4";
|
|
20
6
|
var SubgraphNameSchema = z.string().min(1).max(63).regex(/^[a-z][a-z0-9-]*$/, "Must start with lowercase letter, contain only lowercase alphanumeric and hyphens");
|
|
@@ -40,18 +26,43 @@ var SubgraphTableSchema = z.object({
|
|
|
40
26
|
uniqueKeys: z.array(z.array(z.string())).optional()
|
|
41
27
|
});
|
|
42
28
|
var SubgraphSchemaSchema = z.record(z.string(), SubgraphTableSchema).refine((s) => Object.keys(s).length > 0, "Schema must have at least one table");
|
|
43
|
-
var
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
29
|
+
var VALID_FILTER_TYPES = [
|
|
30
|
+
"stx_transfer",
|
|
31
|
+
"stx_mint",
|
|
32
|
+
"stx_burn",
|
|
33
|
+
"stx_lock",
|
|
34
|
+
"ft_transfer",
|
|
35
|
+
"ft_mint",
|
|
36
|
+
"ft_burn",
|
|
37
|
+
"nft_transfer",
|
|
38
|
+
"nft_mint",
|
|
39
|
+
"nft_burn",
|
|
40
|
+
"contract_call",
|
|
41
|
+
"contract_deploy",
|
|
42
|
+
"print_event"
|
|
43
|
+
];
|
|
44
|
+
var SubgraphFilterSchema = z.object({
|
|
45
|
+
type: z.enum(VALID_FILTER_TYPES),
|
|
46
|
+
sender: z.string().optional(),
|
|
47
|
+
recipient: z.string().optional(),
|
|
48
|
+
minAmount: z.bigint().optional(),
|
|
49
|
+
maxAmount: z.bigint().optional(),
|
|
50
|
+
assetIdentifier: z.string().optional(),
|
|
51
|
+
contractId: z.string().optional(),
|
|
52
|
+
functionName: z.string().optional(),
|
|
53
|
+
caller: z.string().optional(),
|
|
54
|
+
deployer: z.string().optional(),
|
|
55
|
+
contractName: z.string().optional(),
|
|
56
|
+
topic: z.string().optional(),
|
|
57
|
+
lockedAddress: z.string().optional(),
|
|
58
|
+
abi: z.record(z.string(), z.any()).optional()
|
|
59
|
+
}).passthrough();
|
|
50
60
|
var SubgraphDefinitionSchema = z.object({
|
|
51
61
|
name: SubgraphNameSchema,
|
|
52
62
|
version: z.string().optional(),
|
|
53
63
|
description: z.string().optional(),
|
|
54
|
-
|
|
64
|
+
startBlock: z.number().int().nonnegative().optional(),
|
|
65
|
+
sources: z.record(z.string(), SubgraphFilterSchema).refine((s) => Object.keys(s).length > 0, "Must have at least one source"),
|
|
55
66
|
schema: SubgraphSchemaSchema,
|
|
56
67
|
handlers: z.record(z.string(), z.any())
|
|
57
68
|
});
|
|
@@ -61,6 +72,7 @@ function validateSubgraphDefinition(def) {
|
|
|
61
72
|
|
|
62
73
|
// src/runtime/context.ts
|
|
63
74
|
import { logger } from "@secondlayer/shared/logger";
|
|
75
|
+
import { formatUnits } from "@secondlayer/stacks/utils";
|
|
64
76
|
import { sql } from "kysely";
|
|
65
77
|
function validateColumnName(name) {
|
|
66
78
|
if (!/^[a-z_][a-z0-9_]*$/i.test(name)) {
|
|
@@ -128,6 +140,20 @@ class SubgraphContext {
|
|
|
128
140
|
this.validateTable(table);
|
|
129
141
|
this.ops.push({ kind: "delete", table, data: where });
|
|
130
142
|
}
|
|
143
|
+
patch(table, where, set) {
|
|
144
|
+
this.update(table, where, set);
|
|
145
|
+
}
|
|
146
|
+
async patchOrInsert(table, key, row) {
|
|
147
|
+
const existing = await this.findOne(table, key);
|
|
148
|
+
const resolved = {};
|
|
149
|
+
for (const [k, v] of Object.entries(row)) {
|
|
150
|
+
resolved[k] = typeof v === "function" ? v(existing) : v;
|
|
151
|
+
}
|
|
152
|
+
this.upsert(table, key, resolved);
|
|
153
|
+
}
|
|
154
|
+
formatUnits(value, decimals) {
|
|
155
|
+
return formatUnits(value, decimals);
|
|
156
|
+
}
|
|
131
157
|
async findOne(table, where) {
|
|
132
158
|
this.validateTable(table);
|
|
133
159
|
const qualifiedTable = `"${this.pgSchemaName}"."${table}"`;
|
|
@@ -145,6 +171,47 @@ class SubgraphContext {
|
|
|
145
171
|
const { rows } = await sql.raw(query).execute(this.db);
|
|
146
172
|
return rows.map((r) => this.coerceRow(table, r));
|
|
147
173
|
}
|
|
174
|
+
async count(table, where) {
|
|
175
|
+
this.validateTable(table);
|
|
176
|
+
const qualifiedTable = `"${this.pgSchemaName}"."${table}"`;
|
|
177
|
+
const whereClause = where ? `WHERE ${buildWhereClause(where).clause}` : "";
|
|
178
|
+
const { rows } = await sql.raw(`SELECT COUNT(*)::int AS count FROM ${qualifiedTable} ${whereClause}`).execute(this.db);
|
|
179
|
+
return Number(rows[0]?.count ?? 0);
|
|
180
|
+
}
|
|
181
|
+
async sum(table, column, where) {
|
|
182
|
+
this.validateTable(table);
|
|
183
|
+
validateColumnName(column);
|
|
184
|
+
const qualifiedTable = `"${this.pgSchemaName}"."${table}"`;
|
|
185
|
+
const whereClause = where ? `WHERE ${buildWhereClause(where).clause}` : "";
|
|
186
|
+
const { rows } = await sql.raw(`SELECT COALESCE(SUM("${column}"), 0) AS total FROM ${qualifiedTable} ${whereClause}`).execute(this.db);
|
|
187
|
+
return BigInt(rows[0]?.total?.toString() ?? "0");
|
|
188
|
+
}
|
|
189
|
+
async min(table, column, where) {
|
|
190
|
+
this.validateTable(table);
|
|
191
|
+
validateColumnName(column);
|
|
192
|
+
const qualifiedTable = `"${this.pgSchemaName}"."${table}"`;
|
|
193
|
+
const whereClause = where ? `WHERE ${buildWhereClause(where).clause}` : "";
|
|
194
|
+
const { rows } = await sql.raw(`SELECT MIN("${column}") AS val FROM ${qualifiedTable} ${whereClause}`).execute(this.db);
|
|
195
|
+
const val = rows[0]?.val;
|
|
196
|
+
return val != null ? BigInt(val.toString()) : null;
|
|
197
|
+
}
|
|
198
|
+
async max(table, column, where) {
|
|
199
|
+
this.validateTable(table);
|
|
200
|
+
validateColumnName(column);
|
|
201
|
+
const qualifiedTable = `"${this.pgSchemaName}"."${table}"`;
|
|
202
|
+
const whereClause = where ? `WHERE ${buildWhereClause(where).clause}` : "";
|
|
203
|
+
const { rows } = await sql.raw(`SELECT MAX("${column}") AS val FROM ${qualifiedTable} ${whereClause}`).execute(this.db);
|
|
204
|
+
const val = rows[0]?.val;
|
|
205
|
+
return val != null ? BigInt(val.toString()) : null;
|
|
206
|
+
}
|
|
207
|
+
async countDistinct(table, column, where) {
|
|
208
|
+
this.validateTable(table);
|
|
209
|
+
validateColumnName(column);
|
|
210
|
+
const qualifiedTable = `"${this.pgSchemaName}"."${table}"`;
|
|
211
|
+
const whereClause = where ? `WHERE ${buildWhereClause(where).clause}` : "";
|
|
212
|
+
const { rows } = await sql.raw(`SELECT COUNT(DISTINCT "${column}")::int AS count FROM ${qualifiedTable} ${whereClause}`).execute(this.db);
|
|
213
|
+
return Number(rows[0]?.count ?? 0);
|
|
214
|
+
}
|
|
148
215
|
coerceRow(table, row) {
|
|
149
216
|
const tableDef = this.subgraphSchema[table];
|
|
150
217
|
if (!tableDef)
|
|
@@ -285,12 +352,12 @@ function buildWhereClause(where) {
|
|
|
285
352
|
}
|
|
286
353
|
|
|
287
354
|
// src/runtime/clarity.ts
|
|
288
|
-
import {
|
|
355
|
+
import { cvToValue, deserializeCV } from "@secondlayer/stacks/clarity";
|
|
289
356
|
function decodeClarityValue(hex) {
|
|
290
357
|
try {
|
|
291
358
|
const cleanHex = hex.startsWith("0x") ? hex.slice(2) : hex;
|
|
292
359
|
const cv = deserializeCV(cleanHex);
|
|
293
|
-
return
|
|
360
|
+
return cvToValue(cv);
|
|
294
361
|
} catch {
|
|
295
362
|
return hex;
|
|
296
363
|
}
|
|
@@ -319,19 +386,177 @@ function decodeFunctionArgs(args) {
|
|
|
319
386
|
import { getErrorMessage } from "@secondlayer/shared";
|
|
320
387
|
import { logger as logger2 } from "@secondlayer/shared/logger";
|
|
321
388
|
var DEFAULT_ERROR_THRESHOLD = 50;
|
|
322
|
-
function
|
|
323
|
-
return
|
|
389
|
+
function camelCase(str) {
|
|
390
|
+
return str.replace(/-([a-z0-9])/g, (_, c) => c.toUpperCase());
|
|
391
|
+
}
|
|
392
|
+
function camelizeKeys(obj) {
|
|
393
|
+
if (obj === null || obj === undefined)
|
|
394
|
+
return obj;
|
|
395
|
+
if (typeof obj !== "object")
|
|
396
|
+
return obj;
|
|
397
|
+
if (Array.isArray(obj))
|
|
398
|
+
return obj.map(camelizeKeys);
|
|
399
|
+
const result = {};
|
|
400
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
401
|
+
result[camelCase(k)] = camelizeKeys(v);
|
|
402
|
+
}
|
|
403
|
+
return result;
|
|
404
|
+
}
|
|
405
|
+
function buildEventPayload(filter, tx, event) {
|
|
406
|
+
const txMeta = {
|
|
407
|
+
txId: tx.tx_id,
|
|
408
|
+
sender: tx.sender,
|
|
409
|
+
type: tx.type,
|
|
410
|
+
status: tx.status,
|
|
411
|
+
contractId: tx.contract_id ?? null,
|
|
412
|
+
functionName: tx.function_name ?? null
|
|
413
|
+
};
|
|
414
|
+
if (!event) {
|
|
415
|
+
switch (filter.type) {
|
|
416
|
+
case "contract_call":
|
|
417
|
+
return {
|
|
418
|
+
contractId: tx.contract_id ?? "",
|
|
419
|
+
functionName: tx.function_name ?? "",
|
|
420
|
+
caller: tx.sender,
|
|
421
|
+
args: {},
|
|
422
|
+
result: null,
|
|
423
|
+
tx: txMeta
|
|
424
|
+
};
|
|
425
|
+
case "contract_deploy":
|
|
426
|
+
return {
|
|
427
|
+
contractId: tx.contract_id ?? "",
|
|
428
|
+
deployer: tx.sender,
|
|
429
|
+
tx: txMeta
|
|
430
|
+
};
|
|
431
|
+
default:
|
|
432
|
+
return { tx: txMeta };
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
const decoded = decodeEventData(event.data);
|
|
436
|
+
switch (filter.type) {
|
|
437
|
+
case "ft_transfer":
|
|
438
|
+
return {
|
|
439
|
+
sender: decoded.sender,
|
|
440
|
+
recipient: decoded.recipient,
|
|
441
|
+
amount: decoded.amount,
|
|
442
|
+
assetIdentifier: decoded.asset_identifier,
|
|
443
|
+
tx: txMeta
|
|
444
|
+
};
|
|
445
|
+
case "ft_mint":
|
|
446
|
+
return {
|
|
447
|
+
recipient: decoded.recipient,
|
|
448
|
+
amount: decoded.amount,
|
|
449
|
+
assetIdentifier: decoded.asset_identifier,
|
|
450
|
+
tx: txMeta
|
|
451
|
+
};
|
|
452
|
+
case "ft_burn":
|
|
453
|
+
return {
|
|
454
|
+
sender: decoded.sender,
|
|
455
|
+
amount: decoded.amount,
|
|
456
|
+
assetIdentifier: decoded.asset_identifier,
|
|
457
|
+
tx: txMeta
|
|
458
|
+
};
|
|
459
|
+
case "nft_transfer":
|
|
460
|
+
return {
|
|
461
|
+
sender: decoded.sender,
|
|
462
|
+
recipient: decoded.recipient,
|
|
463
|
+
tokenId: decoded.value,
|
|
464
|
+
assetIdentifier: decoded.asset_identifier,
|
|
465
|
+
tx: txMeta
|
|
466
|
+
};
|
|
467
|
+
case "nft_mint":
|
|
468
|
+
return {
|
|
469
|
+
recipient: decoded.recipient,
|
|
470
|
+
tokenId: decoded.value,
|
|
471
|
+
assetIdentifier: decoded.asset_identifier,
|
|
472
|
+
tx: txMeta
|
|
473
|
+
};
|
|
474
|
+
case "nft_burn":
|
|
475
|
+
return {
|
|
476
|
+
sender: decoded.sender,
|
|
477
|
+
tokenId: decoded.value,
|
|
478
|
+
assetIdentifier: decoded.asset_identifier,
|
|
479
|
+
tx: txMeta
|
|
480
|
+
};
|
|
481
|
+
case "stx_transfer":
|
|
482
|
+
return {
|
|
483
|
+
sender: decoded.sender,
|
|
484
|
+
recipient: decoded.recipient,
|
|
485
|
+
amount: decoded.amount,
|
|
486
|
+
memo: decoded.memo ?? "",
|
|
487
|
+
tx: txMeta
|
|
488
|
+
};
|
|
489
|
+
case "stx_mint":
|
|
490
|
+
return {
|
|
491
|
+
recipient: decoded.recipient,
|
|
492
|
+
amount: decoded.amount,
|
|
493
|
+
tx: txMeta
|
|
494
|
+
};
|
|
495
|
+
case "stx_burn":
|
|
496
|
+
return {
|
|
497
|
+
sender: decoded.sender,
|
|
498
|
+
amount: decoded.amount,
|
|
499
|
+
tx: txMeta
|
|
500
|
+
};
|
|
501
|
+
case "stx_lock":
|
|
502
|
+
return {
|
|
503
|
+
lockedAddress: decoded.locked_address,
|
|
504
|
+
lockedAmount: decoded.locked_amount,
|
|
505
|
+
unlockHeight: decoded.unlock_height,
|
|
506
|
+
tx: txMeta
|
|
507
|
+
};
|
|
508
|
+
case "print_event": {
|
|
509
|
+
const topic = decoded.topic ?? "";
|
|
510
|
+
const rawValue = decoded.value;
|
|
511
|
+
const data = rawValue && typeof rawValue === "object" ? camelizeKeys(rawValue) : rawValue;
|
|
512
|
+
return {
|
|
513
|
+
contractId: decoded.contract_identifier ?? tx.contract_id ?? "",
|
|
514
|
+
topic,
|
|
515
|
+
data: data ?? {},
|
|
516
|
+
tx: txMeta
|
|
517
|
+
};
|
|
518
|
+
}
|
|
519
|
+
case "contract_call":
|
|
520
|
+
return {
|
|
521
|
+
...decoded,
|
|
522
|
+
_eventType: event.type,
|
|
523
|
+
contractId: tx.contract_id ?? "",
|
|
524
|
+
functionName: tx.function_name ?? "",
|
|
525
|
+
caller: tx.sender,
|
|
526
|
+
args: {},
|
|
527
|
+
result: null,
|
|
528
|
+
tx: txMeta
|
|
529
|
+
};
|
|
530
|
+
case "contract_deploy":
|
|
531
|
+
return {
|
|
532
|
+
contractId: tx.contract_id ?? "",
|
|
533
|
+
deployer: tx.sender,
|
|
534
|
+
tx: txMeta
|
|
535
|
+
};
|
|
536
|
+
default:
|
|
537
|
+
return {
|
|
538
|
+
...decoded,
|
|
539
|
+
_eventType: event.type,
|
|
540
|
+
tx: txMeta
|
|
541
|
+
};
|
|
542
|
+
}
|
|
324
543
|
}
|
|
325
544
|
async function runHandlers(subgraph, matched, ctx, opts) {
|
|
326
545
|
let processed = 0;
|
|
327
546
|
let errors = 0;
|
|
328
547
|
const threshold = opts?.errorThreshold ?? DEFAULT_ERROR_THRESHOLD;
|
|
329
|
-
|
|
330
|
-
|
|
548
|
+
const filterLookup = new Map;
|
|
549
|
+
if (!Array.isArray(subgraph.sources)) {
|
|
550
|
+
for (const [name, filter] of Object.entries(subgraph.sources)) {
|
|
551
|
+
filterLookup.set(name, filter);
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
for (const { tx, events, sourceName } of matched) {
|
|
555
|
+
const handler = subgraph.handlers[sourceName] ?? subgraph.handlers["*"] ?? null;
|
|
331
556
|
if (!handler) {
|
|
332
|
-
logger2.warn("No handler found for source
|
|
557
|
+
logger2.warn("No handler found for source", {
|
|
333
558
|
subgraph: subgraph.name,
|
|
334
|
-
|
|
559
|
+
sourceName,
|
|
335
560
|
txId: tx.tx_id
|
|
336
561
|
});
|
|
337
562
|
continue;
|
|
@@ -340,11 +565,14 @@ async function runHandlers(subgraph, matched, ctx, opts) {
|
|
|
340
565
|
txId: tx.tx_id,
|
|
341
566
|
sender: tx.sender,
|
|
342
567
|
type: tx.type,
|
|
343
|
-
status: tx.status
|
|
568
|
+
status: tx.status,
|
|
569
|
+
contractId: tx.contract_id ?? null,
|
|
570
|
+
functionName: tx.function_name ?? null
|
|
344
571
|
});
|
|
572
|
+
const filter = filterLookup.get(sourceName);
|
|
345
573
|
if (events.length === 0) {
|
|
346
574
|
try {
|
|
347
|
-
const
|
|
575
|
+
const payload = filter ? buildEventPayload(filter, tx, null) : {
|
|
348
576
|
tx: {
|
|
349
577
|
txId: tx.tx_id,
|
|
350
578
|
sender: tx.sender,
|
|
@@ -354,13 +582,13 @@ async function runHandlers(subgraph, matched, ctx, opts) {
|
|
|
354
582
|
functionName: tx.function_name
|
|
355
583
|
}
|
|
356
584
|
};
|
|
357
|
-
await handler(
|
|
585
|
+
await handler(payload, ctx);
|
|
358
586
|
processed++;
|
|
359
587
|
} catch (err) {
|
|
360
588
|
errors++;
|
|
361
589
|
logger2.error("Subgraph handler error", {
|
|
362
590
|
subgraph: subgraph.name,
|
|
363
|
-
|
|
591
|
+
sourceName,
|
|
364
592
|
txId: tx.tx_id,
|
|
365
593
|
error: getErrorMessage(err)
|
|
366
594
|
});
|
|
@@ -377,28 +605,30 @@ async function runHandlers(subgraph, matched, ctx, opts) {
|
|
|
377
605
|
return { processed, errors };
|
|
378
606
|
}
|
|
379
607
|
try {
|
|
380
|
-
const
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
608
|
+
const payload = filter ? buildEventPayload(filter, tx, event) : (() => {
|
|
609
|
+
const decoded = decodeEventData(event.data);
|
|
610
|
+
return {
|
|
611
|
+
...decoded,
|
|
612
|
+
_eventId: event.id,
|
|
613
|
+
_eventType: event.type,
|
|
614
|
+
_eventIndex: event.event_index,
|
|
615
|
+
tx: {
|
|
616
|
+
txId: tx.tx_id,
|
|
617
|
+
sender: tx.sender,
|
|
618
|
+
type: tx.type,
|
|
619
|
+
status: tx.status,
|
|
620
|
+
contractId: tx.contract_id,
|
|
621
|
+
functionName: tx.function_name
|
|
622
|
+
}
|
|
623
|
+
};
|
|
624
|
+
})();
|
|
625
|
+
await handler(payload, ctx);
|
|
396
626
|
processed++;
|
|
397
627
|
} catch (err) {
|
|
398
628
|
errors++;
|
|
399
629
|
logger2.error("Subgraph handler error", {
|
|
400
630
|
subgraph: subgraph.name,
|
|
401
|
-
|
|
631
|
+
sourceName,
|
|
402
632
|
txId: tx.tx_id,
|
|
403
633
|
eventId: event.id,
|
|
404
634
|
eventType: event.type,
|
|
@@ -423,62 +653,186 @@ function matchPattern(value, pattern) {
|
|
|
423
653
|
}
|
|
424
654
|
return re.test(value);
|
|
425
655
|
}
|
|
426
|
-
function
|
|
656
|
+
function matchFilter(filter, transactions, eventsByTx) {
|
|
427
657
|
const results = [];
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
const
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
const
|
|
658
|
+
switch (filter.type) {
|
|
659
|
+
case "stx_transfer":
|
|
660
|
+
case "stx_mint":
|
|
661
|
+
case "stx_burn":
|
|
662
|
+
case "stx_lock": {
|
|
663
|
+
const eventType = `${filter.type}_event`;
|
|
664
|
+
for (const tx of transactions) {
|
|
665
|
+
const txEvents = eventsByTx.get(tx.tx_id) ?? [];
|
|
666
|
+
const matched = txEvents.filter((e) => e.type === eventType);
|
|
667
|
+
if (matched.length === 0)
|
|
668
|
+
continue;
|
|
669
|
+
const filtered = matched.filter((e) => {
|
|
437
670
|
const data = e.data;
|
|
438
|
-
|
|
439
|
-
if (rawAmount === undefined)
|
|
671
|
+
if (!data)
|
|
440
672
|
return false;
|
|
441
|
-
|
|
442
|
-
|
|
673
|
+
if ("sender" in filter && filter.sender) {
|
|
674
|
+
if (!matchPattern(data.sender, filter.sender))
|
|
675
|
+
return false;
|
|
676
|
+
}
|
|
677
|
+
if ("recipient" in filter && filter.recipient) {
|
|
678
|
+
if (!matchPattern(data.recipient, filter.recipient))
|
|
679
|
+
return false;
|
|
680
|
+
}
|
|
681
|
+
if ("lockedAddress" in filter && filter.lockedAddress) {
|
|
682
|
+
if (!matchPattern(data.locked_address, filter.lockedAddress))
|
|
683
|
+
return false;
|
|
684
|
+
}
|
|
685
|
+
if ("minAmount" in filter && filter.minAmount !== undefined) {
|
|
686
|
+
const amount = BigInt(data.amount ?? data.locked_amount ?? "0");
|
|
687
|
+
if (amount < filter.minAmount)
|
|
688
|
+
return false;
|
|
689
|
+
}
|
|
690
|
+
if ("maxAmount" in filter && filter.maxAmount !== undefined) {
|
|
691
|
+
const amount = BigInt(data.amount ?? "0");
|
|
692
|
+
if (amount > filter.maxAmount)
|
|
693
|
+
return false;
|
|
694
|
+
}
|
|
695
|
+
return true;
|
|
443
696
|
});
|
|
444
|
-
if (
|
|
445
|
-
|
|
446
|
-
|
|
697
|
+
if (filtered.length > 0) {
|
|
698
|
+
results.push({ tx, events: filtered });
|
|
699
|
+
}
|
|
447
700
|
}
|
|
448
|
-
|
|
449
|
-
continue;
|
|
701
|
+
break;
|
|
450
702
|
}
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
703
|
+
case "ft_transfer":
|
|
704
|
+
case "ft_mint":
|
|
705
|
+
case "ft_burn": {
|
|
706
|
+
const eventType = `${filter.type}_event`;
|
|
707
|
+
for (const tx of transactions) {
|
|
708
|
+
const txEvents = eventsByTx.get(tx.tx_id) ?? [];
|
|
709
|
+
const matched = txEvents.filter((e) => {
|
|
710
|
+
if (e.type !== eventType)
|
|
711
|
+
return false;
|
|
712
|
+
const data = e.data;
|
|
713
|
+
if (!data)
|
|
714
|
+
return false;
|
|
715
|
+
if (filter.assetIdentifier) {
|
|
716
|
+
const assetId = data.asset_identifier;
|
|
717
|
+
if (!assetId || !matchPattern(assetId, filter.assetIdentifier))
|
|
718
|
+
return false;
|
|
719
|
+
}
|
|
720
|
+
if ("sender" in filter && filter.sender) {
|
|
721
|
+
if (!matchPattern(data.sender, filter.sender))
|
|
722
|
+
return false;
|
|
723
|
+
}
|
|
724
|
+
if ("recipient" in filter && filter.recipient) {
|
|
725
|
+
if (!matchPattern(data.recipient, filter.recipient))
|
|
726
|
+
return false;
|
|
727
|
+
}
|
|
728
|
+
if (filter.minAmount !== undefined) {
|
|
729
|
+
const amount = BigInt(data.amount ?? "0");
|
|
730
|
+
if (amount < filter.minAmount)
|
|
731
|
+
return false;
|
|
732
|
+
}
|
|
733
|
+
return true;
|
|
734
|
+
});
|
|
735
|
+
if (matched.length > 0) {
|
|
736
|
+
results.push({ tx, events: matched });
|
|
737
|
+
}
|
|
458
738
|
}
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
739
|
+
break;
|
|
740
|
+
}
|
|
741
|
+
case "nft_transfer":
|
|
742
|
+
case "nft_mint":
|
|
743
|
+
case "nft_burn": {
|
|
744
|
+
const eventType = `${filter.type}_event`;
|
|
745
|
+
for (const tx of transactions) {
|
|
746
|
+
const txEvents = eventsByTx.get(tx.tx_id) ?? [];
|
|
747
|
+
const matched = txEvents.filter((e) => {
|
|
748
|
+
if (e.type !== eventType)
|
|
749
|
+
return false;
|
|
463
750
|
const data = e.data;
|
|
464
|
-
|
|
465
|
-
|
|
751
|
+
if (!data)
|
|
752
|
+
return false;
|
|
753
|
+
if (filter.assetIdentifier) {
|
|
754
|
+
const assetId = data.asset_identifier;
|
|
755
|
+
if (!assetId || !matchPattern(assetId, filter.assetIdentifier))
|
|
756
|
+
return false;
|
|
757
|
+
}
|
|
758
|
+
if ("sender" in filter && filter.sender) {
|
|
759
|
+
if (!matchPattern(data.sender, filter.sender))
|
|
760
|
+
return false;
|
|
761
|
+
}
|
|
762
|
+
if ("recipient" in filter && filter.recipient) {
|
|
763
|
+
if (!matchPattern(data.recipient, filter.recipient))
|
|
764
|
+
return false;
|
|
765
|
+
}
|
|
766
|
+
return true;
|
|
466
767
|
});
|
|
467
|
-
if (
|
|
768
|
+
if (matched.length > 0) {
|
|
769
|
+
results.push({ tx, events: matched });
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
break;
|
|
773
|
+
}
|
|
774
|
+
case "contract_call": {
|
|
775
|
+
for (const tx of transactions) {
|
|
776
|
+
if (tx.type !== "contract_call")
|
|
777
|
+
continue;
|
|
778
|
+
if (filter.contractId) {
|
|
779
|
+
if (!tx.contract_id || !matchPattern(tx.contract_id, filter.contractId))
|
|
780
|
+
continue;
|
|
781
|
+
}
|
|
782
|
+
if (filter.functionName) {
|
|
783
|
+
if (!tx.function_name || !matchPattern(tx.function_name, filter.functionName))
|
|
784
|
+
continue;
|
|
785
|
+
}
|
|
786
|
+
if (filter.caller) {
|
|
787
|
+
if (!matchPattern(tx.sender, filter.caller))
|
|
788
|
+
continue;
|
|
789
|
+
}
|
|
790
|
+
const txEvents = eventsByTx.get(tx.tx_id) ?? [];
|
|
791
|
+
results.push({ tx, events: txEvents });
|
|
792
|
+
}
|
|
793
|
+
break;
|
|
794
|
+
}
|
|
795
|
+
case "contract_deploy": {
|
|
796
|
+
for (const tx of transactions) {
|
|
797
|
+
if (tx.type !== "smart_contract")
|
|
468
798
|
continue;
|
|
799
|
+
if (filter.deployer) {
|
|
800
|
+
if (!matchPattern(tx.sender, filter.deployer))
|
|
801
|
+
continue;
|
|
802
|
+
}
|
|
803
|
+
if (filter.contractName) {
|
|
804
|
+
const name = tx.contract_id?.split(".")[1] ?? "";
|
|
805
|
+
if (!matchPattern(name, filter.contractName))
|
|
806
|
+
continue;
|
|
807
|
+
}
|
|
808
|
+
const txEvents = eventsByTx.get(tx.tx_id) ?? [];
|
|
809
|
+
results.push({ tx, events: txEvents });
|
|
469
810
|
}
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
811
|
+
break;
|
|
812
|
+
}
|
|
813
|
+
case "print_event": {
|
|
814
|
+
for (const tx of transactions) {
|
|
815
|
+
const txEvents = eventsByTx.get(tx.tx_id) ?? [];
|
|
816
|
+
const matched = txEvents.filter((e) => {
|
|
817
|
+
if (e.type !== "smart_contract_event")
|
|
818
|
+
return false;
|
|
474
819
|
const data = e.data;
|
|
475
|
-
|
|
476
|
-
|
|
820
|
+
if (!data)
|
|
821
|
+
return false;
|
|
822
|
+
if (data.topic !== "print")
|
|
823
|
+
return false;
|
|
824
|
+
if (filter.contractId) {
|
|
825
|
+
const contractId = data.contract_identifier;
|
|
826
|
+
if (!contractId || !matchPattern(contractId, filter.contractId))
|
|
827
|
+
return false;
|
|
828
|
+
}
|
|
829
|
+
return true;
|
|
477
830
|
});
|
|
831
|
+
if (matched.length > 0) {
|
|
832
|
+
results.push({ tx, events: matched });
|
|
833
|
+
}
|
|
478
834
|
}
|
|
479
|
-
|
|
480
|
-
results.push({ tx, events: matchedEvents, sourceKey: key });
|
|
481
|
-
}
|
|
835
|
+
break;
|
|
482
836
|
}
|
|
483
837
|
}
|
|
484
838
|
return results;
|
|
@@ -492,13 +846,13 @@ function matchSources(sources, transactions, events) {
|
|
|
492
846
|
}
|
|
493
847
|
const seen = new Set;
|
|
494
848
|
const results = [];
|
|
495
|
-
for (const
|
|
496
|
-
const matches =
|
|
849
|
+
for (const [sourceName, filter] of Object.entries(sources)) {
|
|
850
|
+
const matches = matchFilter(filter, transactions, eventsByTx);
|
|
497
851
|
for (const match of matches) {
|
|
498
|
-
const dedupeKey = `${match.tx.tx_id}:${
|
|
852
|
+
const dedupeKey = `${match.tx.tx_id}:${sourceName}`;
|
|
499
853
|
if (!seen.has(dedupeKey)) {
|
|
500
854
|
seen.add(dedupeKey);
|
|
501
|
-
results.push(match);
|
|
855
|
+
results.push({ ...match, sourceName });
|
|
502
856
|
}
|
|
503
857
|
}
|
|
504
858
|
}
|
|
@@ -1175,6 +1529,7 @@ async function backfillSubgraph(def, opts) {
|
|
|
1175
1529
|
throw err;
|
|
1176
1530
|
}
|
|
1177
1531
|
}
|
|
1532
|
+
|
|
1178
1533
|
// src/define.ts
|
|
1179
1534
|
function defineSubgraph(def) {
|
|
1180
1535
|
return def;
|
|
@@ -1351,7 +1706,6 @@ function getDefault(type) {
|
|
|
1351
1706
|
}
|
|
1352
1707
|
export {
|
|
1353
1708
|
validateSubgraphDefinition,
|
|
1354
|
-
sourceKey,
|
|
1355
1709
|
resumeReindex,
|
|
1356
1710
|
reindexSubgraph,
|
|
1357
1711
|
pgSchemaName,
|
|
@@ -1362,5 +1716,5 @@ export {
|
|
|
1362
1716
|
backfillSubgraph
|
|
1363
1717
|
};
|
|
1364
1718
|
|
|
1365
|
-
//# debugId=
|
|
1719
|
+
//# debugId=9F5F23B13281C9C864756E2164756E21
|
|
1366
1720
|
//# sourceMappingURL=index.js.map
|