@secondlayer/subgraphs 3.22.0 → 3.23.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.
Files changed (36) hide show
  1. package/dist/src/index.d.ts +118 -9
  2. package/dist/src/index.js +159 -14
  3. package/dist/src/index.js.map +7 -6
  4. package/dist/src/runtime/block-processor.d.ts +43 -2
  5. package/dist/src/runtime/block-processor.js +155 -12
  6. package/dist/src/runtime/block-processor.js.map +7 -6
  7. package/dist/src/runtime/catchup.d.ts +43 -2
  8. package/dist/src/runtime/catchup.js +155 -12
  9. package/dist/src/runtime/catchup.js.map +7 -6
  10. package/dist/src/runtime/context.d.ts +77 -3
  11. package/dist/src/runtime/context.js +142 -1
  12. package/dist/src/runtime/context.js.map +6 -5
  13. package/dist/src/runtime/processor.js +159 -16
  14. package/dist/src/runtime/processor.js.map +7 -6
  15. package/dist/src/runtime/reindex.d.ts +43 -2
  16. package/dist/src/runtime/reindex.js +155 -12
  17. package/dist/src/runtime/reindex.js.map +7 -6
  18. package/dist/src/runtime/reorg.d.ts +43 -2
  19. package/dist/src/runtime/reorg.js +155 -12
  20. package/dist/src/runtime/reorg.js.map +7 -6
  21. package/dist/src/runtime/replay.d.ts +3 -3
  22. package/dist/src/runtime/replay.js +2 -1
  23. package/dist/src/runtime/replay.js.map +3 -3
  24. package/dist/src/runtime/runner.d.ts +102 -5
  25. package/dist/src/runtime/source-matcher.d.ts +2 -2
  26. package/dist/src/runtime/stats.d.ts +3 -3
  27. package/dist/src/schema/index.d.ts +46 -5
  28. package/dist/src/service.js +159 -16
  29. package/dist/src/service.js.map +7 -6
  30. package/dist/src/testing/index.d.ts +52 -5
  31. package/dist/src/testing/index.js +172 -6
  32. package/dist/src/testing/index.js.map +6 -5
  33. package/dist/src/triggers/index.d.ts +2 -2
  34. package/dist/src/types.d.ts +43 -2
  35. package/dist/src/validate.d.ts +43 -2
  36. package/package.json +5 -3
@@ -1,4 +1,91 @@
1
- import { AbiContract } from "@secondlayer/stacks/clarity";
1
+ import { AbiContract as AbiContract2 } from "@secondlayer/stacks/clarity";
2
+ import { UnwrapResponse } from "@secondlayer/stacks/actions";
3
+ import { AbiContract, ExtractFunctionArgs, ExtractFunctionOutput, ExtractReadOnlyFunctions, ToCamelCase } from "@secondlayer/stacks/clarity";
4
+ /**
5
+ * How long a read stays valid.
6
+ *
7
+ * - `per-block` (default): pinned to the block being processed, cached under
8
+ * its `index_block_hash`. Sound for any read-only function — reindexing the
9
+ * same block always returns the same value, and a reorg-replaced block has a
10
+ * different id so it can't inherit the orphaned answer.
11
+ * - `contract-constant`: the caller asserts the value cannot change for this
12
+ * contract and these args (SIP-010 `get-decimals`/`get-symbol`), so it is
13
+ * resolved ONCE instead of once per block. This is the mode that makes a
14
+ * backfill affordable — under `per-block` every block is a distinct key and
15
+ * therefore a distinct RPC. Declaring it on a value that does change pins the
16
+ * first answer forever, so it is opt-in and never inferred.
17
+ */
18
+ type ChainReadCacheMode = "per-block" | "contract-constant";
19
+ type ChainReadOptions = {
20
+ cache?: ChainReadCacheMode
21
+ };
22
+ /**
23
+ * The chain-read surface, fully typed by an ABI.
24
+ *
25
+ * Shaped like `getContract` from `@secondlayer/stacks` — the same ABI in, the
26
+ * same camelCased read methods out — minus `call`/`buildCall`: a handler
27
+ * indexes the chain, it never writes to it.
28
+ *
29
+ * Reached through {@link readContractAt} rather than off `ctx.client`
30
+ * directly: an ABI-generic method living on the context interface makes every
31
+ * structural comparison of a subgraph definition instantiate it, which exceeds
32
+ * TS's depth budget. At a call site the ABI is already concrete and it costs
33
+ * nothing.
34
+ */
35
+ interface ChainReadClient {
36
+ /**
37
+ * Read-only methods of a contract, evaluated against the exact block being
38
+ * processed.
39
+ *
40
+ * Every call is pinned to the block's `index_block_hash`, so a handler is a
41
+ * pure function of its block: reindexing a range produces byte-identical
42
+ * rows. Reading at the node's tip instead would make the same reindex
43
+ * return different values — that is the corruption this refuses to allow,
44
+ * so a block whose id was never persisted throws rather than falling back.
45
+ *
46
+ * Results are memoized in Postgres, so a value is fetched once per block
47
+ * rather than once per event (or once per contract with
48
+ * `cache: "contract-constant"`).
49
+ */
50
+ contract<const C extends AbiContract>(contractId: string, abi: C, options?: ChainReadOptions): {
51
+ read: ChainReadMethods<C>
52
+ };
53
+ }
54
+ /**
55
+ * The camelCased read methods of an ABI. Spelled out rather than reused from
56
+ * `ContractInstance<C>["read"]`: that type is a conditional over the codegen
57
+ * brand, and evaluating it wherever a subgraph definition is structurally
58
+ * compared pushes TS past its instantiation depth.
59
+ */
60
+ type ChainReadMethods<C extends AbiContract> = { [N in ExtractReadOnlyFunctions<C> as ToCamelCase<N>] : (args: ExtractFunctionArgs<C, N>) => Promise<UnwrapResponse<ExtractFunctionOutput<C, N>>> };
61
+ /**
62
+ * `ChainReadClient` with the ABI generic erased. Structurally cheap, so the
63
+ * base `SubgraphContext` can carry it; `TypedSubgraphContext` uses the real
64
+ * one and handlers get full inference.
65
+ */
66
+ interface ErasedChainReadClient {
67
+ contract(contractId: string, abi: unknown, options?: ChainReadOptions): {
68
+ read: Record<string, (args?: Record<string, unknown>) => Promise<unknown>>
69
+ };
70
+ }
71
+ /**
72
+ * Typed read methods for one contract, from a handler.
73
+ *
74
+ * ```ts
75
+ * const token = readContractAt(ctx, contractId, SIP010_ABI, {
76
+ * cache: "contract-constant",
77
+ * });
78
+ * const decimals = await token.read.getDecimals({}); // bigint
79
+ * ```
80
+ */
81
+ declare function readContractAt<const C extends AbiContract>(ctx: {
82
+ client: ErasedChainReadClient
83
+ }, contractId: string, abi: C, options?: ChainReadOptions): {
84
+ read: ChainReadMethods<C>
85
+ };
86
+ declare class ChainReadError extends Error {
87
+ name: string;
88
+ }
2
89
  /** Supported column types for subgraph schemas */
3
90
  type ColumnType = "text" | "uint" | "int" | "principal" | "boolean" | "timestamp" | "jsonb";
4
91
  /** Column definition in a subgraph table */
@@ -216,7 +303,7 @@ interface ContractCallFilter extends TraitScope, FactoryScope {
216
303
  * definition and used at runtime to decode args by name. Omit to keep
217
304
  * `event.args` as a positional `unknown[]`.
218
305
  */
219
- abi?: AbiContract;
306
+ abi?: AbiContract2;
220
307
  }
221
308
  interface ContractDeployFilter {
222
309
  type: "contract_deploy";
@@ -287,8 +374,21 @@ interface SubgraphContext {
287
374
  hash: string
288
375
  timestamp: number
289
376
  burnBlockHeight: number
377
+ /** Nakamoto StacksBlockId, when the block row carries one. */
378
+ indexBlockHash?: string | null
290
379
  };
291
380
  tx: TxMeta;
381
+ /**
382
+ * Read-only contract calls pinned to this block. Cached, so the same
383
+ * (contract, function, args) is fetched once per block rather than once
384
+ * per event.
385
+ *
386
+ * Erased here on purpose: this interface is compared structurally wherever
387
+ * a subgraph definition is passed around, and carrying an ABI-generic
388
+ * method pushes those comparisons past TS's instantiation depth. Handlers
389
+ * receive `TypedSubgraphContext`, which exposes the fully typed version.
390
+ */
391
+ client: ErasedChainReadClient;
292
392
  insert(table: string, row: Record<string, unknown>): void;
293
393
  update(table: string, where: Record<string, unknown>, set: Record<string, unknown>): void;
294
394
  upsert(table: string, key: Record<string, unknown>, row: Record<string, unknown>): void;
@@ -397,7 +497,7 @@ declare function backfillSubgraph(def: SubgraphDefinition, opts: {
397
497
  }): Promise<{
398
498
  processed: number
399
499
  }>;
400
- import { AbiContract as AbiContract2, ExtractFunctionArgs, ExtractFunctionNames } from "@secondlayer/stacks/clarity";
500
+ import { AbiContract as AbiContract3, ExtractFunctionArgs as ExtractFunctionArgs2, ExtractFunctionNames } from "@secondlayer/stacks/clarity";
401
501
  /** Maps a ColumnType string literal to its TypeScript equivalent */
402
502
  type ColumnToTS<T extends string> = T extends "uint" | "int" ? bigint : T extends "text" | "principal" | "timestamp" ? string : T extends "boolean" ? boolean : T extends "jsonb" ? Record<string, unknown> : unknown;
403
503
  /** Infer TS type for a single column definition, respecting nullable */
@@ -574,8 +674,17 @@ interface TypedSubgraphContext<S extends SubgraphSchema> {
574
674
  hash: string
575
675
  timestamp: number
576
676
  burnBlockHeight: number
677
+ /** Nakamoto StacksBlockId, when the block row carries one. */
678
+ indexBlockHash?: string | null
577
679
  };
578
680
  tx: TxMeta;
681
+ /**
682
+ * Read-only contract calls pinned to this block. Erased here for the same
683
+ * reason as on `SubgraphContext`: an ABI-generic method on a structurally
684
+ * compared interface exceeds TS's instantiation budget. Wrap it with
685
+ * `readContractAt(ctx, id, abi)` for full ABI typing at the call site.
686
+ */
687
+ client: ErasedChainReadClient;
579
688
  insert<T extends TableName<S>>(table: T, row: WriteRow<S[T]>): void;
580
689
  update<T extends TableName<S>>(table: T, where: RowWhere<S, T>, set: Partial<WriteRow<S[T]>>): void;
581
690
  upsert<
@@ -690,10 +799,10 @@ interface ContractDeployPayload {
690
799
  * present for back-compat. Without an `abi`, the payload is {@link ContractCallEvent}.
691
800
  */
692
801
  type ContractCallPayload<F> = F extends {
693
- abi: infer A extends AbiContract2
802
+ abi: infer A extends AbiContract3
694
803
  functionName: infer N extends string
695
804
  } ? N extends ExtractFunctionNames<A> ? ContractCallEvent & {
696
- input: ExtractFunctionArgs<A, N>
805
+ input: ExtractFunctionArgs2<A, N>
697
806
  } : ContractCallEvent : ContractCallEvent;
698
807
  /**
699
808
  * Print event typed per topic. When a `print_event` source declares a `prints`
@@ -963,10 +1072,10 @@ declare function generateIndexSchema(target: IndexCodegenTarget, opts?: IndexCod
963
1072
  /** Index tables available to codegen, for help text and validation. */
964
1073
  declare const INDEX_CODEGEN_TABLES: readonly string[];
965
1074
  import { pgSchemaName } from "@secondlayer/shared/db/queries/subgraphs";
966
- import { Database } from "@secondlayer/shared/db";
1075
+ import { Database as Database2 } from "@secondlayer/shared/db";
967
1076
  import { ByoBreakingChangeDetails } from "@secondlayer/shared/errors";
968
- import { Kysely } from "kysely";
969
- type AnyDb = Kysely<Database>;
1077
+ import { Kysely as Kysely2 } from "kysely";
1078
+ type AnyDb = Kysely2<Database2>;
970
1079
  interface TableDiff {
971
1080
  /** Tables added to the schema */
972
1081
  addedTables: string[];
@@ -1100,4 +1209,4 @@ type SparseProbeTarget = {
1100
1209
  declare function canSparseScan(subgraph: SubgraphDefinition): boolean;
1101
1210
  /** Probe targets for a subgraph's filters: decoded type + contract scope when\\n* the filter pins one (assetIdentifier "SP….contract::asset" or contractId). */
1102
1211
  declare function sparseProbeTargets(subgraph: SubgraphDefinition): SparseProbeTarget[];
1103
- export { validateSubgraphDefinition, validatePrintPayload, sparseProbeTargets, resumeReindex, renderDeployPlan, reindexSubgraph, pgSchemaName, inferPrintTopics, hasBreakingChanges, generateSubgraphSQL, generatePrismaSchema, generateKyselySchema, generateIndexSchema, generateDrizzleSchema, filterFieldsByType, diffSchema, deploySchema, defineSubgraph, defineSchema, canSparseScan, camelizeDataKey, backfillSubgraph, WriteRow, WhereInput, TypedSubgraphDefinition, TypedSubgraphContext, TypedHandlers, TxMeta, TableDiff, SystemRow, SubscribeOptions, SubgraphTableClient, SubgraphTable, SubgraphSchema, SubgraphHandler, SubgraphFilter, SubgraphDefinition, SubgraphContext, SubgraphColumn, StxTransferPayload, StxTransferFilter, StxMintPayload, StxMintFilter, StxLockPayload, StxLockFilter, StxBurnPayload, StxBurnFilter, SparseProbeTarget, RowValue, ReindexOptions, PrismaGenOptions, PrintValidationResult, PrintSample, PrintFieldToTS, PrintField, PrintEventPayload, PrintEventFor, PrintEventFilter, PrintDataOf, NftTransferPayload, NftTransferFilter, NftMintPayload, NftMintFilter, NftBurnPayload, NftBurnFilter, KyselyGenOptions, InferredTopicSchema, InferredPrintField, InferTableRow, InferSubgraphClient, InferContext, InferColumnType, IndexCodegenTarget, IndexCodegenOptions, INDEX_CODEGEN_TABLES, GeneratedSQL, FtTransferPayload, FtTransferFilter, FtMintPayload, FtMintFilter, FtBurnPayload, FtBurnFilter, FindManyOptions, FactoryScope, EventForFilter, DrizzleGenOptions, DeployPlan, DeployDiff, ContractDeployPayload, ContractDeployFilter, ContractCallPayload, ContractCallFilter, ContractCallEvent, ComputedValue, ComparisonFilter, ColumnType, ColumnToTS, ColumnDiff, ByoMigrationPlan, ByoBreakingChangeError, AnyEvent, AggregateSpec, AggregateResult };
1212
+ export { validateSubgraphDefinition, validatePrintPayload, sparseProbeTargets, resumeReindex, renderDeployPlan, reindexSubgraph, readContractAt, pgSchemaName, inferPrintTopics, hasBreakingChanges, generateSubgraphSQL, generatePrismaSchema, generateKyselySchema, generateIndexSchema, generateDrizzleSchema, filterFieldsByType, diffSchema, deploySchema, defineSubgraph, defineSchema, canSparseScan, camelizeDataKey, backfillSubgraph, WriteRow, WhereInput, TypedSubgraphDefinition, TypedSubgraphContext, TypedHandlers, TxMeta, TableDiff, SystemRow, SubscribeOptions, SubgraphTableClient, SubgraphTable, SubgraphSchema, SubgraphHandler, SubgraphFilter, SubgraphDefinition, SubgraphContext, SubgraphColumn, StxTransferPayload, StxTransferFilter, StxMintPayload, StxMintFilter, StxLockPayload, StxLockFilter, StxBurnPayload, StxBurnFilter, SparseProbeTarget, RowValue, ReindexOptions, PrismaGenOptions, PrintValidationResult, PrintSample, PrintFieldToTS, PrintField, PrintEventPayload, PrintEventFor, PrintEventFilter, PrintDataOf, NftTransferPayload, NftTransferFilter, NftMintPayload, NftMintFilter, NftBurnPayload, NftBurnFilter, KyselyGenOptions, InferredTopicSchema, InferredPrintField, InferTableRow, InferSubgraphClient, InferContext, InferColumnType, IndexCodegenTarget, IndexCodegenOptions, INDEX_CODEGEN_TABLES, GeneratedSQL, FtTransferPayload, FtTransferFilter, FtMintPayload, FtMintFilter, FtBurnPayload, FtBurnFilter, FindManyOptions, FactoryScope, EventForFilter, ErasedChainReadClient, DrizzleGenOptions, DeployPlan, DeployDiff, ContractDeployPayload, ContractDeployFilter, ContractCallPayload, ContractCallFilter, ContractCallEvent, ComputedValue, ComparisonFilter, ColumnType, ColumnToTS, ColumnDiff, ChainReadOptions, ChainReadMethods, ChainReadError, ChainReadClient, ChainReadCacheMode, ByoMigrationPlan, ByoBreakingChangeError, AnyEvent, AggregateSpec, AggregateResult };
package/dist/src/index.js CHANGED
@@ -360,6 +360,139 @@ function generateSubgraphSQL(def, schemaNameOverride) {
360
360
  return { statements, hash };
361
361
  }
362
362
 
363
+ // src/runtime/chain-read.ts
364
+ import { getSourceDb } from "@secondlayer/shared/db";
365
+ import { http, createPublicClient } from "@secondlayer/stacks";
366
+ import {
367
+ ContractResponseError,
368
+ buildFunctionArgs,
369
+ isResponseOutput,
370
+ readContract
371
+ } from "@secondlayer/stacks/actions";
372
+ import {
373
+ clarityValueToJSUntyped,
374
+ deserializeCV,
375
+ normalizeAbi,
376
+ serializeCV,
377
+ toCamelCase
378
+ } from "@secondlayer/stacks/clarity";
379
+ function readContractAt(ctx, contractId, abi, options) {
380
+ return ctx.client.contract(contractId, abi, options);
381
+ }
382
+
383
+ class ChainReadError extends Error {
384
+ name = "ChainReadError";
385
+ }
386
+ function nodeClient(rpcUrl) {
387
+ return createPublicClient({
388
+ transport: http(rpcUrl, { retryCount: 0, timeout: 1e4 })
389
+ });
390
+ }
391
+
392
+ class ConcurrencyGate {
393
+ limit;
394
+ active = 0;
395
+ queue = [];
396
+ constructor(limit) {
397
+ this.limit = limit;
398
+ }
399
+ async run(fn) {
400
+ if (this.active >= this.limit) {
401
+ await new Promise((resolve) => this.queue.push(resolve));
402
+ }
403
+ this.active++;
404
+ try {
405
+ return await fn();
406
+ } finally {
407
+ this.active--;
408
+ this.queue.shift()?.();
409
+ }
410
+ }
411
+ }
412
+ var DEFAULT_MAX_CONCURRENT_READS = 4;
413
+ function maxConcurrentReads() {
414
+ const raw = process.env.SUBGRAPH_CHAIN_READ_CONCURRENCY;
415
+ const parsed = raw ? Number.parseInt(raw, 10) : Number.NaN;
416
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_MAX_CONCURRENT_READS;
417
+ }
418
+ var gate = new ConcurrencyGate(maxConcurrentReads());
419
+ function hashArgs(args) {
420
+ const serialized = args.map((arg) => serializeCV(arg)).join(",");
421
+ return Bun.hash(serialized).toString(16);
422
+ }
423
+ function findFunction(abi, name) {
424
+ const fn = abi.functions.find((f) => f.name === name);
425
+ if (!fn) {
426
+ throw new ChainReadError(`No function "${name}" in the supplied ABI.`);
427
+ }
428
+ if (fn.access !== "read-only") {
429
+ throw new ChainReadError(`"${name}" is ${fn.access}, not read-only — a handler cannot call it.`);
430
+ }
431
+ return fn;
432
+ }
433
+ function createChainReadClient(ctx) {
434
+ const readValue = async (contractId, abi, functionName, args, options) => {
435
+ const rpcUrl = ctx.rpcUrl ?? process.env.STACKS_NODE_RPC_URL;
436
+ if (!rpcUrl) {
437
+ throw new ChainReadError("ctx.client needs a Stacks node: set STACKS_NODE_RPC_URL on the subgraph processor.");
438
+ }
439
+ const constant = options.cache === "contract-constant";
440
+ if (!constant && !ctx.indexBlockHash) {
441
+ throw new ChainReadError(`Block ${ctx.blockHeight} has no index_block_hash, so a read cannot be pinned to it. Reading at the node's tip would make this handler non-deterministic (the same reindex would produce different rows). Re-ingest the block, or pass cache: "contract-constant" if the value genuinely cannot change.`);
442
+ }
443
+ const fn = findFunction(abi, functionName);
444
+ const clarityArgs = buildFunctionArgs(fn, args);
445
+ const db = ctx.db ?? getSourceDb();
446
+ const argsHash = hashArgs(clarityArgs);
447
+ const pinnedTo = constant ? null : ctx.indexBlockHash;
448
+ const cached = await db.selectFrom("chain_read_cache").select("result_hex").where("contract_id", "=", contractId).where("function_name", "=", fn.name).where("args_hash", "=", argsHash).where((eb) => pinnedTo === null ? eb("index_block_hash", "is", null) : eb("index_block_hash", "=", pinnedTo)).executeTakeFirst();
449
+ const resultHex = cached?.result_hex ?? await gate.run(async () => {
450
+ const value2 = await readContract(nodeClient(rpcUrl), {
451
+ contract: contractId,
452
+ functionName: fn.name,
453
+ args: clarityArgs,
454
+ tip: ctx.indexBlockHash ?? undefined
455
+ });
456
+ return serializeCV(value2);
457
+ });
458
+ if (!cached) {
459
+ await db.insertInto("chain_read_cache").values({
460
+ contract_id: contractId,
461
+ function_name: fn.name,
462
+ args_hash: argsHash,
463
+ index_block_hash: pinnedTo,
464
+ block_height: constant ? null : ctx.blockHeight,
465
+ result_hex: resultHex
466
+ }).onConflict((oc) => oc.doNothing()).execute();
467
+ }
468
+ const value = deserializeCV(resultHex);
469
+ const js = clarityValueToJSUntyped(fn.outputs, value);
470
+ if (isResponseOutput(fn.outputs)) {
471
+ const response = js;
472
+ if ("ok" in response)
473
+ return response.ok;
474
+ throw new ContractResponseError(`${contractId}::${fn.name} returned an err response.`, response.err);
475
+ }
476
+ return js;
477
+ };
478
+ return {
479
+ contract(contractId, rawAbi, options = {}) {
480
+ const abi = normalizeAbi(rawAbi);
481
+ const camelToKebab = new Map;
482
+ for (const fn of abi.functions) {
483
+ camelToKebab.set(toCamelCase(fn.name), fn.name);
484
+ }
485
+ const read = new Proxy({}, {
486
+ get(_target, prop) {
487
+ const fnName = camelToKebab.get(prop) ?? prop;
488
+ return (args = {}) => readValue(contractId, abi, fnName, args, options);
489
+ }
490
+ });
491
+ return { read };
492
+ }
493
+ };
494
+ }
495
+
363
496
  // src/runtime/context.ts
364
497
  var JOURNAL_RETENTION_BLOCKS = 300;
365
498
  var journalEnsured = new Set;
@@ -378,6 +511,7 @@ class SubgraphContext {
378
511
  ops = [];
379
512
  byo;
380
513
  journal;
514
+ _client;
381
515
  constructor(db, pgSchemaName2, subgraphSchema, block, tx, byo = false, journal = false) {
382
516
  this.db = db;
383
517
  this.pgSchemaName = pgSchemaName2;
@@ -387,6 +521,13 @@ class SubgraphContext {
387
521
  this.byo = byo;
388
522
  this.journal = journal;
389
523
  }
524
+ get client() {
525
+ this._client ??= createChainReadClient({
526
+ blockHeight: this.block.height,
527
+ indexBlockHash: this.block.indexBlockHash
528
+ });
529
+ return this._client;
530
+ }
390
531
  get tx() {
391
532
  return this._tx;
392
533
  }
@@ -948,11 +1089,11 @@ function buildWhereClause(where) {
948
1089
  }
949
1090
 
950
1091
  // src/runtime/clarity.ts
951
- import { cvToValue, deserializeCV } from "@secondlayer/stacks/clarity";
1092
+ import { cvToValue, deserializeCV as deserializeCV2 } from "@secondlayer/stacks/clarity";
952
1093
  function decodeClarityValue(hex) {
953
1094
  try {
954
1095
  const cleanHex = hex.startsWith("0x") ? hex.slice(2) : hex;
955
- const cv = deserializeCV(cleanHex);
1096
+ const cv = deserializeCV2(cleanHex);
956
1097
  return cvToValue(cv);
957
1098
  } catch {
958
1099
  return hex;
@@ -983,8 +1124,8 @@ import { getErrorMessage } from "@secondlayer/shared";
983
1124
  import { logger as logger2 } from "@secondlayer/shared/logger";
984
1125
  import {
985
1126
  clarityValueToJS,
986
- deserializeCV as deserializeCV2,
987
- toCamelCase
1127
+ deserializeCV as deserializeCV3,
1128
+ toCamelCase as toCamelCase2
988
1129
  } from "@secondlayer/stacks/clarity";
989
1130
 
990
1131
  // src/runtime/print-validate.ts
@@ -1147,7 +1288,7 @@ function buildContractCallInput(filter, tx) {
1147
1288
  return;
1148
1289
  try {
1149
1290
  const clean = hex.startsWith("0x") ? hex.slice(2) : hex;
1150
- input[toCamelCase(arg.name)] = decodeArg(arg.type, deserializeCV2(clean));
1291
+ input[toCamelCase2(arg.name)] = decodeArg(arg.type, deserializeCV3(clean));
1151
1292
  } catch {}
1152
1293
  });
1153
1294
  return input;
@@ -1701,7 +1842,7 @@ import { logger as logger5 } from "@secondlayer/shared/logger";
1701
1842
  import { sql as sql3 } from "kysely";
1702
1843
 
1703
1844
  // src/runtime/block-source.ts
1704
- import { getSourceDb } from "@secondlayer/shared/db";
1845
+ import { getSourceDb as getSourceDb2 } from "@secondlayer/shared/db";
1705
1846
  import {
1706
1847
  IndexHttpClient
1707
1848
  } from "@secondlayer/shared/index-http";
@@ -1762,6 +1903,7 @@ function reconstructBlock(b) {
1762
1903
  parent_hash: b.parent_hash,
1763
1904
  burn_block_height: b.burn_block_height,
1764
1905
  burn_block_hash: b.burn_block_hash,
1906
+ index_block_hash: b.index_block_hash ?? null,
1765
1907
  timestamp: isoToUnixSeconds(b.block_time),
1766
1908
  canonical: true,
1767
1909
  created_at: new Date(0)
@@ -1896,11 +2038,11 @@ function sparseProbeTargets(subgraph) {
1896
2038
 
1897
2039
  class PostgresBlockSource {
1898
2040
  async getTip() {
1899
- const progress = await getSourceDb().selectFrom("index_progress").selectAll().where("network", "=", process.env.NETWORK ?? "mainnet").executeTakeFirst();
2041
+ const progress = await getSourceDb2().selectFrom("index_progress").selectAll().where("network", "=", process.env.NETWORK ?? "mainnet").executeTakeFirst();
1900
2042
  return progress ? Number(progress.highest_seen_block) : 0;
1901
2043
  }
1902
2044
  loadBlockRange(fromHeight, toHeight) {
1903
- return loadBlockRange(getSourceDb(), fromHeight, toHeight);
2045
+ return loadBlockRange(getSourceDb2(), fromHeight, toHeight);
1904
2046
  }
1905
2047
  }
1906
2048
  var EVENT_FILTER_TO_INDEX_TYPE = {
@@ -1969,8 +2111,8 @@ class PublicApiBlockSource {
1969
2111
  eventTypes;
1970
2112
  probeTargets;
1971
2113
  needsTransactions;
1972
- constructor(http, eventTypes, probeTargets, needsTransactions = true) {
1973
- this.http = http;
2114
+ constructor(http2, eventTypes, probeTargets, needsTransactions = true) {
2115
+ this.http = http2;
1974
2116
  this.eventTypes = eventTypes;
1975
2117
  this.probeTargets = probeTargets;
1976
2118
  this.needsTransactions = needsTransactions;
@@ -2482,7 +2624,8 @@ async function processBlock(subgraph, subgraphName, blockHeight, opts) {
2482
2624
  height: block.height,
2483
2625
  hash: block.hash,
2484
2626
  timestamp: block.timestamp,
2485
- burnBlockHeight: block.burn_block_height
2627
+ burnBlockHeight: block.burn_block_height,
2628
+ indexBlockHash: block.index_block_hash
2486
2629
  };
2487
2630
  const initialTx = {
2488
2631
  txId: "",
@@ -3260,7 +3403,7 @@ function defineSchema(schema) {
3260
3403
  }
3261
3404
  // src/print-schema.ts
3262
3405
  import {
3263
- deserializeCV as deserializeCV3
3406
+ deserializeCV as deserializeCV4
3264
3407
  } from "@secondlayer/stacks/clarity";
3265
3408
  function camelizeDataKey(str) {
3266
3409
  return str.replace(/-([a-z0-9])/g, (_, c) => c.toUpperCase());
@@ -3528,7 +3671,7 @@ function inferPrintTopics(samples) {
3528
3671
  let decoded = 0;
3529
3672
  for (const p of picked) {
3530
3673
  try {
3531
- const cv = deserializeCV3(p.rawHex);
3674
+ const cv = deserializeCV4(p.rawHex);
3532
3675
  decoded++;
3533
3676
  if (cv.type === "tuple")
3534
3677
  tuples.push(cv);
@@ -4527,6 +4670,7 @@ export {
4527
4670
  resumeReindex,
4528
4671
  renderDeployPlan,
4529
4672
  reindexSubgraph,
4673
+ readContractAt,
4530
4674
  pgSchemaName,
4531
4675
  inferPrintTopics,
4532
4676
  hasBreakingChanges,
@@ -4544,8 +4688,9 @@ export {
4544
4688
  camelizeDataKey,
4545
4689
  backfillSubgraph,
4546
4690
  INDEX_CODEGEN_TABLES,
4691
+ ChainReadError,
4547
4692
  ByoBreakingChangeError
4548
4693
  };
4549
4694
 
4550
- //# debugId=8BECEC189376FB2B64756E2164756E21
4695
+ //# debugId=A7D0F6BE4A80734464756E2164756E21
4551
4696
  //# sourceMappingURL=index.js.map