@secondlayer/shared 6.9.0 → 6.11.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.
@@ -33,6 +33,35 @@ interface EventsTable {
33
33
  data: unknown;
34
34
  created_at: Generated<Date>;
35
35
  }
36
+ interface TransactionsArchiveTable {
37
+ archive_id: Generated<string>;
38
+ tx_id: string;
39
+ block_height: number;
40
+ tx_index: number;
41
+ type: string;
42
+ sender: string;
43
+ status: string;
44
+ contract_id: string | null;
45
+ function_name: string | null;
46
+ function_args: unknown | null;
47
+ raw_result: string | null;
48
+ raw_tx: string;
49
+ created_at: Date;
50
+ orphaned_block_hash: string | null;
51
+ archived_at: Generated<Date>;
52
+ }
53
+ interface EventsArchiveTable {
54
+ archive_id: Generated<string>;
55
+ id: string;
56
+ tx_id: string;
57
+ block_height: number;
58
+ event_index: number;
59
+ type: string;
60
+ data: unknown;
61
+ created_at: Date;
62
+ orphaned_block_hash: string | null;
63
+ archived_at: Generated<Date>;
64
+ }
36
65
  interface IndexProgressTable {
37
66
  network: string;
38
67
  last_indexed_block: Generated<number>;
@@ -380,6 +409,26 @@ interface Pox4SignersDailyTable {
380
409
  aggregation_calls: Generated<number>;
381
410
  updated_at: Generated<Date>;
382
411
  }
412
+ interface BurnBlockRewardsTable {
413
+ cursor: string;
414
+ burn_block_height: number;
415
+ burn_block_hash: string;
416
+ reward_index: number;
417
+ recipient_btc: string;
418
+ amount_sats: string;
419
+ burn_amount: Generated<string>;
420
+ canonical: Generated<boolean>;
421
+ created_at: Generated<Date>;
422
+ }
423
+ interface BurnBlockRewardSlotsTable {
424
+ cursor: string;
425
+ burn_block_height: number;
426
+ burn_block_hash: string;
427
+ slot_index: number;
428
+ holder_btc: string;
429
+ canonical: Generated<boolean>;
430
+ created_at: Generated<Date>;
431
+ }
383
432
  type SbtcEventTopic = "completed-deposit" | "withdrawal-create" | "withdrawal-accept" | "withdrawal-reject" | "key-rotation" | "update-protocol-contract";
384
433
  interface SbtcEventsTable {
385
434
  cursor: string;
@@ -531,6 +580,8 @@ interface Database {
531
580
  blocks: BlocksTable;
532
581
  transactions: TransactionsTable;
533
582
  events: EventsTable;
583
+ transactions_archive: TransactionsArchiveTable;
584
+ events_archive: EventsArchiveTable;
534
585
  index_progress: IndexProgressTable;
535
586
  contracts: ContractsTable;
536
587
  subgraphs: SubgraphsTable;
@@ -568,6 +619,8 @@ interface Database {
568
619
  pox4_calls: Pox4CallsTable;
569
620
  pox4_cycles_daily: Pox4CyclesDailyTable;
570
621
  pox4_signers_daily: Pox4SignersDailyTable;
622
+ burn_block_rewards: BurnBlockRewardsTable;
623
+ burn_block_reward_slots: BurnBlockRewardSlotsTable;
571
624
  sbtc_events: SbtcEventsTable;
572
625
  sbtc_token_events: SbtcTokenEventsTable;
573
626
  sbtc_supply_snapshots: SbtcSupplySnapshotsTable;
@@ -1,6 +1,7 @@
1
1
  import { type Kysely, sql } from "kysely";
2
2
 
3
- export async function up(db: Kysely<unknown>): Promise<void> {
3
+ // biome-ignore lint/suspicious/noExplicitAny: migration DDL is intentionally schema-dynamic
4
+ export async function up(db: Kysely<any>): Promise<void> {
4
5
  await sql`
5
6
  ALTER TABLE decoded_events
6
7
  ADD COLUMN microblock_hash TEXT,
@@ -41,7 +42,8 @@ export async function up(db: Kysely<unknown>): Promise<void> {
41
42
  `.execute(db);
42
43
  }
43
44
 
44
- export async function down(db: Kysely<unknown>): Promise<void> {
45
+ // biome-ignore lint/suspicious/noExplicitAny: migration DDL is intentionally schema-dynamic
46
+ export async function down(db: Kysely<any>): Promise<void> {
45
47
  await sql`DROP INDEX IF EXISTS decoded_events_recipient_height_event_idx`.execute(
46
48
  db,
47
49
  );
@@ -1,6 +1,7 @@
1
1
  import { type Kysely, sql } from "kysely";
2
2
 
3
- export async function up(db: Kysely<unknown>): Promise<void> {
3
+ // biome-ignore lint/suspicious/noExplicitAny: migration DDL is intentionally schema-dynamic
4
+ export async function up(db: Kysely<any>): Promise<void> {
4
5
  await sql`SET lock_timeout = '30s'`.execute(db);
5
6
  await sql`
6
7
  ALTER TABLE usage_daily
@@ -9,7 +10,8 @@ export async function up(db: Kysely<unknown>): Promise<void> {
9
10
  `.execute(db);
10
11
  }
11
12
 
12
- export async function down(db: Kysely<unknown>): Promise<void> {
13
+ // biome-ignore lint/suspicious/noExplicitAny: migration DDL is intentionally schema-dynamic
14
+ export async function down(db: Kysely<any>): Promise<void> {
13
15
  await sql`
14
16
  ALTER TABLE usage_daily
15
17
  DROP COLUMN IF EXISTS index_decoded_events_returned,
@@ -0,0 +1,63 @@
1
+ import { type Kysely, sql } from "kysely";
2
+
3
+ // Burnchain (Bitcoin) PoX reward data, sourced from the stacks-node
4
+ // /new_burn_block event observer payload (reward_recipients / reward_slot_holders),
5
+ // which the indexer previously discarded. Two views per burn block:
6
+ // - burn_block_rewards: actual BTC payouts (one row per reward slot, ≤2/block).
7
+ // Populated only during a reward cycle's reward phase.
8
+ // - burn_block_reward_slots: reward-set membership (eligible BTC addresses).
9
+ // Both are keyed by (burn_block_height, index) via `cursor`; the handler does
10
+ // delete-by-height-then-insert (replace-per-height), which makes redelivery and
11
+ // shallow burnchain reorgs idempotent. `canonical` is reserved for a future
12
+ // mark-non-canonical reorg path; v1 keeps every row canonical.
13
+ export async function up(db: Kysely<unknown>): Promise<void> {
14
+ await sql`SET lock_timeout = '30s'`.execute(db);
15
+
16
+ await sql`
17
+ CREATE TABLE IF NOT EXISTS burn_block_rewards (
18
+ cursor TEXT PRIMARY KEY,
19
+ burn_block_height BIGINT NOT NULL,
20
+ burn_block_hash TEXT NOT NULL,
21
+ reward_index INTEGER NOT NULL,
22
+ recipient_btc TEXT NOT NULL,
23
+ amount_sats TEXT NOT NULL,
24
+ burn_amount TEXT NOT NULL DEFAULT '0',
25
+ canonical BOOLEAN NOT NULL DEFAULT true,
26
+ created_at TIMESTAMPTZ NOT NULL DEFAULT now()
27
+ )
28
+ `.execute(db);
29
+
30
+ await sql`CREATE INDEX IF NOT EXISTS burn_block_rewards_canonical_height_idx ON burn_block_rewards (canonical, burn_block_height)`.execute(
31
+ db,
32
+ );
33
+ await sql`CREATE INDEX IF NOT EXISTS burn_block_rewards_recipient_height_idx ON burn_block_rewards (recipient_btc, burn_block_height)`.execute(
34
+ db,
35
+ );
36
+ await sql`CREATE INDEX IF NOT EXISTS burn_block_rewards_hash_idx ON burn_block_rewards (burn_block_hash)`.execute(
37
+ db,
38
+ );
39
+
40
+ await sql`
41
+ CREATE TABLE IF NOT EXISTS burn_block_reward_slots (
42
+ cursor TEXT PRIMARY KEY,
43
+ burn_block_height BIGINT NOT NULL,
44
+ burn_block_hash TEXT NOT NULL,
45
+ slot_index INTEGER NOT NULL,
46
+ holder_btc TEXT NOT NULL,
47
+ canonical BOOLEAN NOT NULL DEFAULT true,
48
+ created_at TIMESTAMPTZ NOT NULL DEFAULT now()
49
+ )
50
+ `.execute(db);
51
+
52
+ await sql`CREATE INDEX IF NOT EXISTS burn_block_reward_slots_canonical_height_idx ON burn_block_reward_slots (canonical, burn_block_height)`.execute(
53
+ db,
54
+ );
55
+ await sql`CREATE INDEX IF NOT EXISTS burn_block_reward_slots_holder_height_idx ON burn_block_reward_slots (holder_btc, burn_block_height)`.execute(
56
+ db,
57
+ );
58
+ }
59
+
60
+ export async function down(db: Kysely<unknown>): Promise<void> {
61
+ await sql`DROP TABLE IF EXISTS burn_block_reward_slots`.execute(db);
62
+ await sql`DROP TABLE IF EXISTS burn_block_rewards`.execute(db);
63
+ }
@@ -0,0 +1,59 @@
1
+ import { type Kysely, sql } from "kysely";
2
+
3
+ // Reorg archive: when a reorg reuses a height, the indexer replaces the
4
+ // transactions/events at that height (persistBlock). Previously the orphaned
5
+ // rows were DELETEd outright. Instead, we now copy them here first so the raw
6
+ // log is preserved (queryable + auditable) rather than destroyed — the
7
+ // "immutable log" the availability layer promises. Append-only; a synthetic
8
+ // archive_id lets the same original row be archived across multiple reorgs.
9
+ export async function up(db: Kysely<unknown>): Promise<void> {
10
+ await sql`SET lock_timeout = '30s'`.execute(db);
11
+
12
+ await sql`
13
+ CREATE TABLE IF NOT EXISTS transactions_archive (
14
+ archive_id BIGSERIAL PRIMARY KEY,
15
+ tx_id TEXT NOT NULL,
16
+ block_height BIGINT NOT NULL,
17
+ tx_index INTEGER NOT NULL,
18
+ type TEXT NOT NULL,
19
+ sender TEXT NOT NULL,
20
+ status TEXT NOT NULL,
21
+ contract_id TEXT,
22
+ function_name TEXT,
23
+ function_args JSONB,
24
+ raw_result TEXT,
25
+ raw_tx TEXT NOT NULL,
26
+ created_at TIMESTAMPTZ NOT NULL,
27
+ orphaned_block_hash TEXT,
28
+ archived_at TIMESTAMPTZ NOT NULL DEFAULT now()
29
+ )
30
+ `.execute(db);
31
+
32
+ await sql`CREATE INDEX IF NOT EXISTS transactions_archive_height_idx ON transactions_archive (block_height)`.execute(
33
+ db,
34
+ );
35
+
36
+ await sql`
37
+ CREATE TABLE IF NOT EXISTS events_archive (
38
+ archive_id BIGSERIAL PRIMARY KEY,
39
+ id TEXT NOT NULL,
40
+ tx_id TEXT NOT NULL,
41
+ block_height BIGINT NOT NULL,
42
+ event_index INTEGER NOT NULL,
43
+ type TEXT NOT NULL,
44
+ data JSONB,
45
+ created_at TIMESTAMPTZ NOT NULL,
46
+ orphaned_block_hash TEXT,
47
+ archived_at TIMESTAMPTZ NOT NULL DEFAULT now()
48
+ )
49
+ `.execute(db);
50
+
51
+ await sql`CREATE INDEX IF NOT EXISTS events_archive_height_idx ON events_archive (block_height)`.execute(
52
+ db,
53
+ );
54
+ }
55
+
56
+ export async function down(db: Kysely<unknown>): Promise<void> {
57
+ await sql`DROP TABLE IF EXISTS events_archive`.execute(db);
58
+ await sql`DROP TABLE IF EXISTS transactions_archive`.execute(db);
59
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@secondlayer/shared",
3
- "version": "6.9.0",
3
+ "version": "6.11.0",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",