@secondlayer/subgraphs 6.3.6 → 6.4.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.
@@ -366,6 +366,7 @@ interface GeneratedSQL {
366
366
  declare function generateSubgraphSQL(def: SubgraphDefinition, schemaNameOverride?: string): GeneratedSQL;
367
367
  import { Database as Database2 } from "@secondlayer/shared/db";
368
368
  import { Kysely as Kysely2 } from "kysely";
369
+ import { SubgraphVerification } from "@secondlayer/shared/schemas/subgraphs";
369
370
  type AnyDb = Kysely2<Database2>;
370
371
  interface TableDiff {
371
372
  /** Tables added to the schema */
@@ -428,10 +429,16 @@ declare function deploySchema(db: AnyDb, def: SubgraphDefinition, handlerPath: s
428
429
  schemaName?: string
429
430
  handlerCode?: string
430
431
  sourceCode?: string
432
+ /** Derived level to store (see `deriveVerification`). */
433
+ verification?: SubgraphVerification
434
+ /** Network baked into the pin. Defaults to `NETWORK`, then mainnet. */
435
+ network?: string
431
436
  }): Promise<{
432
437
  action: "created" | "unchanged" | "handler_updated" | "updated" | "reindexed"
433
438
  subgraphId: string
434
439
  version: string
440
+ /** Present when the deploy carried a bundled handler. */
441
+ pin?: string
435
442
  diff?: DeployDiff
436
443
  /** Non-fatal caveats the caller should surface (e.g. handler grafts at tip). */
437
444
  warnings?: string[]
@@ -461,6 +461,265 @@ function filterFieldsByType() {
461
461
  return out;
462
462
  }
463
463
 
464
+ // src/verification.ts
465
+ import { createHash as createHash2 } from "node:crypto";
466
+ // package.json
467
+ var package_default = {
468
+ name: "@secondlayer/subgraphs",
469
+ version: "6.4.0",
470
+ description: "Describe the Stacks data you want as one TypeScript file; it fills itself and survives reorgs.",
471
+ license: "MIT",
472
+ repository: {
473
+ type: "git",
474
+ url: "git+https://github.com/ryanwaits/secondlayer.git",
475
+ directory: "packages/subgraphs"
476
+ },
477
+ homepage: "https://github.com/ryanwaits/secondlayer/tree/main/packages/subgraphs#readme",
478
+ type: "module",
479
+ main: "./dist/index.js",
480
+ types: "./dist/index.d.ts",
481
+ exports: {
482
+ ".": {
483
+ types: "./dist/index.d.ts",
484
+ import: "./dist/index.js"
485
+ },
486
+ "./types": {
487
+ types: "./dist/types.d.ts",
488
+ import: "./dist/types.js"
489
+ },
490
+ "./schema": {
491
+ types: "./dist/schema/index.d.ts",
492
+ import: "./dist/schema/index.js"
493
+ },
494
+ "./validate": {
495
+ types: "./dist/validate.d.ts",
496
+ import: "./dist/validate.js"
497
+ },
498
+ "./verification": {
499
+ types: "./dist/verification.d.ts",
500
+ import: "./dist/verification.js"
501
+ },
502
+ "./runtime/replay": {
503
+ types: "./dist/runtime/replay.d.ts",
504
+ import: "./dist/runtime/replay.js"
505
+ },
506
+ "./runtime/emitter": {
507
+ types: "./dist/runtime/emitter.d.ts",
508
+ import: "./dist/runtime/emitter.js"
509
+ },
510
+ "./testing": {
511
+ types: "./dist/testing/index.d.ts",
512
+ import: "./dist/testing/index.js"
513
+ }
514
+ },
515
+ files: ["dist"],
516
+ scripts: {
517
+ build: "bunup",
518
+ dev: "bunup --watch",
519
+ test: "bun test",
520
+ typecheck: "tsc --noEmit",
521
+ prepublishOnly: "bun run build"
522
+ },
523
+ dependencies: {
524
+ "@secondlayer/shared": "^11.22.0",
525
+ "@secondlayer/stacks": "^6.1.0",
526
+ esbuild: "^0.28.2",
527
+ kysely: "0.28.17",
528
+ zod: "^4.3.6"
529
+ },
530
+ devDependencies: {
531
+ "@types/bun": "latest",
532
+ typescript: "^5"
533
+ },
534
+ publishConfig: {
535
+ access: "public"
536
+ }
537
+ };
538
+
539
+ // src/verification.ts
540
+ var SUBGRAPHS_RUNTIME = `@secondlayer/subgraphs@${package_default.version}`;
541
+ var FORBIDDEN_GLOBALS = {
542
+ Date: "wall-clock time differs per run",
543
+ performance: "timers differ per run",
544
+ process: "host environment differs per run",
545
+ fetch: "network reads are not chain inputs",
546
+ crypto: "randomness differs per run",
547
+ setTimeout: "scheduling order differs per run",
548
+ setInterval: "scheduling order differs per run",
549
+ setImmediate: "scheduling order differs per run",
550
+ clearTimeout: "scheduling order differs per run",
551
+ clearInterval: "scheduling order differs per run",
552
+ queueMicrotask: "scheduling order differs per run",
553
+ WeakRef: "garbage collection timing differs per run",
554
+ FinalizationRegistry: "garbage collection timing differs per run",
555
+ Atomics: "shared memory is not single-threaded",
556
+ SharedArrayBuffer: "shared memory is not single-threaded",
557
+ Intl: "locale and time zone data differ per host",
558
+ Temporal: "locale and time zone data differ per host",
559
+ eval: "generated code hides inputs from the scan",
560
+ WebAssembly: "compiled code hides inputs from the scan",
561
+ ShadowRealm: "a nested realm escapes the allow-list",
562
+ require: "imports must be bundled into the handler"
563
+ };
564
+ var ALLOWED_GLOBALS = [
565
+ "undefined",
566
+ "NaN",
567
+ "Infinity",
568
+ "globalThis",
569
+ "isNaN",
570
+ "isFinite",
571
+ "parseInt",
572
+ "parseFloat",
573
+ "decodeURI",
574
+ "decodeURIComponent",
575
+ "encodeURI",
576
+ "encodeURIComponent",
577
+ "escape",
578
+ "unescape",
579
+ "Object",
580
+ "Function",
581
+ "Array",
582
+ "Number",
583
+ "Boolean",
584
+ "String",
585
+ "Symbol",
586
+ "BigInt",
587
+ "Math",
588
+ "JSON",
589
+ "Reflect",
590
+ "Proxy",
591
+ "Promise",
592
+ "Map",
593
+ "Set",
594
+ "WeakMap",
595
+ "WeakSet",
596
+ "RegExp",
597
+ "Iterator",
598
+ "DisposableStack",
599
+ "AsyncDisposableStack",
600
+ "Error",
601
+ "AggregateError",
602
+ "SuppressedError",
603
+ "EvalError",
604
+ "RangeError",
605
+ "ReferenceError",
606
+ "SyntaxError",
607
+ "TypeError",
608
+ "URIError",
609
+ "ArrayBuffer",
610
+ "DataView",
611
+ "Int8Array",
612
+ "Uint8Array",
613
+ "Uint8ClampedArray",
614
+ "Int16Array",
615
+ "Uint16Array",
616
+ "Int32Array",
617
+ "Uint32Array",
618
+ "Float16Array",
619
+ "Float32Array",
620
+ "Float64Array",
621
+ "BigInt64Array",
622
+ "BigUint64Array",
623
+ "TextEncoder",
624
+ "TextDecoder",
625
+ "atob",
626
+ "btoa",
627
+ "console"
628
+ ];
629
+ var ALLOWED_MATH = [
630
+ "abs",
631
+ "min",
632
+ "max",
633
+ "floor",
634
+ "ceil",
635
+ "trunc",
636
+ "sign",
637
+ "round",
638
+ "E",
639
+ "LN10",
640
+ "LN2",
641
+ "LOG10E",
642
+ "LOG2E",
643
+ "PI",
644
+ "SQRT1_2",
645
+ "SQRT2"
646
+ ];
647
+ var LOCALE_METHODS = [
648
+ "toLocaleString",
649
+ "toLocaleDateString",
650
+ "toLocaleTimeString",
651
+ "toLocaleUpperCase",
652
+ "toLocaleLowerCase",
653
+ "localeCompare"
654
+ ];
655
+ function formatFinding(f) {
656
+ return `${f.file}:${f.line}:${f.column} ${f.name}: ${f.reason}`;
657
+ }
658
+ var STATE_SOURCE_TYPES = new Set([
659
+ "var_set",
660
+ "map_set",
661
+ "map_insert",
662
+ "map_delete"
663
+ ]);
664
+ var LEVEL_RANK = { state: 0, events: 1, none: 2 };
665
+ var MAX_LISTED_FINDINGS = 10;
666
+ function deriveVerification(def, findings = []) {
667
+ let level = "state";
668
+ const raise = (to) => {
669
+ if (LEVEL_RANK[to] > LEVEL_RANK[level])
670
+ level = to;
671
+ };
672
+ const reasons = [];
673
+ for (const [name, source] of Object.entries(def.sources ?? {})) {
674
+ const filter = source;
675
+ if (filter.trait) {
676
+ raise("none");
677
+ reasons.push(`source "${name}": trait scope needs a proven contract registry`);
678
+ } else if (!STATE_SOURCE_TYPES.has(filter.type)) {
679
+ raise("events");
680
+ reasons.push(`${filter.type} source "${name}" needs event proofs`);
681
+ }
682
+ }
683
+ if (def.backfillMode === "concurrent") {
684
+ raise("none");
685
+ reasons.push("backfillMode concurrent: tip-first order is not chain order");
686
+ }
687
+ if (findings.some((f) => f.kind === "needs-events"))
688
+ raise("events");
689
+ for (const f of findings.slice(0, MAX_LISTED_FINDINGS)) {
690
+ reasons.push(f.kind === "needs-events" ? `${formatFinding(f)} (needs event proofs)` : formatFinding(f));
691
+ }
692
+ if (findings.length > MAX_LISTED_FINDINGS) {
693
+ reasons.push(`…and ${findings.length - MAX_LISTED_FINDINGS} more handler findings`);
694
+ }
695
+ const writesMapInsert = Object.values(def.sources ?? {}).some((s) => s.type === "map_insert");
696
+ return {
697
+ level,
698
+ reasons,
699
+ unproven: reasons.length === 0 ? [
700
+ "tx attribution of writes: event.tx, _tx_id (needs event proofs)",
701
+ "intermediate writes within a block (needs event proofs)",
702
+ ...writesMapInsert ? ["map_insert vs map_set (needs event proofs)"] : []
703
+ ] : []
704
+ };
705
+ }
706
+ function isDeterminismViolation(v) {
707
+ return v.level === "state" && v.reasons.length > 0;
708
+ }
709
+ function sha256(input) {
710
+ return createHash2("sha256").update(input).digest("hex");
711
+ }
712
+ function computePin(input) {
713
+ const canonical = JSON.stringify({
714
+ handlerHash: sha256(input.handlerCode),
715
+ network: input.network,
716
+ runtime: input.runtime ?? SUBGRAPHS_RUNTIME,
717
+ schemaHash: input.schemaHash,
718
+ startBlock: input.startBlock ?? null
719
+ });
720
+ return sha256(canonical);
721
+ }
722
+
464
723
  // src/schema/deployer.ts
465
724
  function toJsonSafe(obj) {
466
725
  return JSON.parse(JSON.stringify(obj, (_key, value) => typeof value === "bigint" ? value.toString() : value));
@@ -558,6 +817,13 @@ function renderDeployPlan(def, schemaName) {
558
817
  async function deploySchema(db, def, handlerPath, opts) {
559
818
  validateSubgraphDefinition(def);
560
819
  const { statements, hash } = generateSubgraphSQL(def, opts?.schemaName);
820
+ const pin = opts?.handlerCode != null ? computePin({
821
+ schemaHash: hash,
822
+ handlerCode: opts.handlerCode,
823
+ startBlock: def.startBlock,
824
+ network: opts.network ?? process.env.NETWORK ?? "mainnet"
825
+ }) : null;
826
+ const identity = pin ? { pin } : {};
561
827
  const { getSubgraph, registerSubgraph } = await import("@secondlayer/shared/db/queries/subgraphs");
562
828
  const ddlDb = db;
563
829
  const existing = await getSubgraph(db, def.name, opts?.accountId);
@@ -580,7 +846,9 @@ async function deploySchema(db, def, handlerPath, opts) {
580
846
  handlerCode: opts?.handlerCode,
581
847
  sourceCode: opts?.sourceCode,
582
848
  schemaName,
583
- startBlock: def.startBlock
849
+ startBlock: def.startBlock,
850
+ pin,
851
+ verification: opts?.verification ?? null
584
852
  };
585
853
  if (existing) {
586
854
  const schemaExists = await sql`
@@ -594,19 +862,27 @@ async function deploySchema(db, def, handlerPath, opts) {
594
862
  await sql.raw(stmt).execute(ddlDb);
595
863
  }
596
864
  const sg = await registerSubgraph(db, regData);
597
- return { action: "reindexed", subgraphId: sg.id, version: newVersion };
865
+ return {
866
+ action: "reindexed",
867
+ subgraphId: sg.id,
868
+ version: newVersion,
869
+ ...identity
870
+ };
598
871
  }
599
872
  if (existing.schema_hash === hash && !opts?.forceReindex) {
600
873
  const handlerChanged = opts?.handlerCode != null && opts.handlerCode !== existing.handler_code;
601
874
  const { updateSubgraphHandlerPath } = await import("@secondlayer/shared/db/queries/subgraphs");
602
875
  await updateSubgraphHandlerPath(db, def.name, handlerPath, {
603
876
  handlerCode: opts?.handlerCode,
604
- sourceCode: opts?.sourceCode
877
+ sourceCode: opts?.sourceCode,
878
+ pin,
879
+ verification: opts?.verification ?? null
605
880
  });
606
881
  return {
607
882
  action: handlerChanged ? "handler_updated" : "unchanged",
608
883
  subgraphId: existing.id,
609
884
  version: existing.version,
885
+ ...identity,
610
886
  ...handlerChanged ? {
611
887
  warnings: [
612
888
  "handler changed but schema did not: new logic applies from the current tip only. Rows already indexed were computed by the previous handler. To recompute history, redeploy with --reindex (or backfill a range)."
@@ -620,7 +896,12 @@ async function deploySchema(db, def, handlerPath, opts) {
620
896
  await sql.raw(stmt).execute(ddlDb);
621
897
  }
622
898
  const sg = await registerSubgraph(db, regData);
623
- return { action: "reindexed", subgraphId: sg.id, version: newVersion };
899
+ return {
900
+ action: "reindexed",
901
+ subgraphId: sg.id,
902
+ version: newVersion,
903
+ ...identity
904
+ };
624
905
  }
625
906
  if (existing.definition.schema) {
626
907
  const diff = diffSchema(existing.definition.schema, def.schema);
@@ -636,6 +917,7 @@ async function deploySchema(db, def, handlerPath, opts) {
636
917
  action: "reindexed",
637
918
  subgraphId: sg.id,
638
919
  version: newVersion,
920
+ ...identity,
639
921
  diff: deployDiff
640
922
  };
641
923
  }
@@ -755,6 +1037,7 @@ async function deploySchema(db, def, handlerPath, opts) {
755
1037
  action: "updated",
756
1038
  subgraphId: sg.id,
757
1039
  version: newVersion,
1040
+ ...identity,
758
1041
  diff: deployDiff
759
1042
  };
760
1043
  }
@@ -763,7 +1046,12 @@ async function deploySchema(db, def, handlerPath, opts) {
763
1046
  await sql.raw(stmt).execute(ddlDb);
764
1047
  }
765
1048
  const sg = await registerSubgraph(db, regData);
766
- return { action: "created", subgraphId: sg.id, version: newVersion };
1049
+ return {
1050
+ action: "created",
1051
+ subgraphId: sg.id,
1052
+ version: newVersion,
1053
+ ...identity
1054
+ };
767
1055
  }
768
1056
  function getDefault(type) {
769
1057
  switch (type) {
@@ -790,5 +1078,5 @@ export {
790
1078
  generateSubgraphSQL
791
1079
  };
792
1080
 
793
- //# debugId=054E6A0FD91586DA64756E2164756E21
1081
+ //# debugId=437B69A70A1DC76C64756E2164756E21
794
1082
  //# sourceMappingURL=index.js.map