Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions migrations/1779742831642_principal-bond-positions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,15 @@ export function up(pgm: MigrationBuilder): void {
notNull: true,
default: 0,
},
// Running sBTC reward sats already claimed against this position, from
// pox-5 `claim-staker-rewards-for-signer` events. Claimable rewards are
// `accrued_rewards - claimed_rewards`. Maintained incrementally on write
// (and via signed deltas on reorg).
claimed_rewards: {
type: 'numeric',
notNull: true,
default: 0,
},
});

pgm.createIndex('principal_bond_positions', ['principal', 'bond_index'], {
Expand Down
102 changes: 102 additions & 0 deletions migrations/1779745340755_principal-bond-reward-claims.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import type { ColumnDefinitions, MigrationBuilder } from 'node-pg-migrate';

export const shorthands: ColumnDefinitions | undefined = undefined;

/**
* Per-staker reward claims, one row per pox-5 `claim-staker-rewards-for-signer`
* event. These are the source rows behind each position's running
* `principal_bond_positions.claimed_rewards` total: claims with a `bond_index`
* are bond (sBTC) reward claims and feed that total; claims with a NULL
* `bond_index` are STX-staking reward claims (no bond position attached).
* Keeping the per-claim rows lets us re-derive or delta-correct the running
* totals under reorgs.
*/
export function up(pgm: MigrationBuilder): void {
pgm.createTable('principal_bond_reward_claims', {
id: {
type: 'bigserial',
primaryKey: true,
},
// The staker whose rewards were claimed.
principal: {
type: 'string',
notNull: true,
},
// The signer manager that performed the claim.
signer_manager: {
type: 'string',
notNull: true,
},
reward_cycle: {
type: 'integer',
notNull: true,
},
// Bond the claimed rewards accrued against; NULL for STX-staking rewards.
bond_index: {
type: 'integer',
},
rewards_claimed: {
type: 'numeric',
notNull: true,
},
tx_id: {
type: 'bytea',
notNull: true,
},
tx_index: {
type: 'smallint',
notNull: true,
},
block_height: {
type: 'integer',
notNull: true,
},
block_hash: {
type: 'bytea',
},
block_time: {
type: 'bigint',
},
index_block_hash: {
type: 'bytea',
notNull: true,
},
parent_block_hash: {
type: 'bytea',
},
parent_index_block_hash: {
type: 'bytea',
notNull: true,
},
burn_block_height: {
type: 'integer',
},
burn_block_time: {
type: 'bigint',
},
microblock_hash: {
type: 'bytea',
notNull: true,
},
microblock_sequence: {
type: 'integer',
notNull: true,
},
microblock_canonical: {
type: 'boolean',
notNull: true,
},
canonical: {
type: 'boolean',
notNull: true,
},
});

pgm.createIndex('principal_bond_reward_claims', 'tx_id');
pgm.createIndex('principal_bond_reward_claims', ['index_block_hash', 'canonical']);
pgm.createIndex('principal_bond_reward_claims', ['principal', 'bond_index']);
}

export function down(pgm: MigrationBuilder): void {
pgm.dropTable('principal_bond_reward_claims');
}
71 changes: 71 additions & 0 deletions migrations/1779800000003_principal-staking-totals.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import type { ColumnDefinitions, MigrationBuilder } from 'node-pg-migrate';

export const shorthands: ColumnDefinitions | undefined = undefined;

/**
* Materialized per-principal staking summary — one row per principal, holding
* every total the staking-summary endpoint needs so it's a single-row lookup
* rather than an on-read aggregate. Maintained incrementally on write (and
* delta-corrected on reorg), like `ft_balances`:
*
* - `stx_*` columns: the principal's pox-5 STX-staking sBTC rewards, fed by
* `principal_stx_reward_distributions` (accruals) and the NULL-`bond_index`
* rows of `principal_bond_reward_claims` (claims).
* - `bond_*` columns: a rollup of the principal's `principal_bond_positions`
* rows (count + summed locked amounts and sBTC rewards) — the per-principal
* analogue of the per-bond totals on the `bonds` table.
*
* The pox-5 STX *locked* amount is not materialized here: it depends on the
* current burn height (expiry) with no event firing at expiry, so it stays
* resolved-on-read from `stx_locked_balances`.
*/
export function up(pgm: MigrationBuilder): void {
pgm.createTable('principal_staking_totals', {
principal: {
type: 'text',
notNull: true,
primaryKey: true,
},
// STX-staking sBTC reward totals.
stx_accrued_rewards: {
type: 'numeric',
notNull: true,
default: 0,
},
stx_claimed_rewards: {
type: 'numeric',
notNull: true,
default: 0,
},
// Rollup of the principal's bond positions.
bond_count: {
type: 'integer',
notNull: true,
default: 0,
},
bond_btc_locked: {
type: 'numeric',
notNull: true,
default: 0,
},
bond_stx_locked: {
type: 'numeric',
notNull: true,
default: 0,
},
bond_accrued_rewards: {
type: 'numeric',
notNull: true,
default: 0,
},
bond_claimed_rewards: {
type: 'numeric',
notNull: true,
default: 0,
},
});
}

export function down(pgm: MigrationBuilder): void {
pgm.dropTable('principal_staking_totals');
}
93 changes: 93 additions & 0 deletions migrations/1779800000004_principal-stx-reward-distributions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import type { ColumnDefinitions, MigrationBuilder } from 'node-pg-migrate';

export const shorthands: ColumnDefinitions | undefined = undefined;

/**
* Per-staker STX-staking reward distribution source rows. Each pox-5
* `calculate-rewards` event allocates `total_stx_staker_rewards` (sBTC sats) to
* STX stackers at a uniform `accrued_rewards_per_ustx` rate; we split that rate
* across the current pox-5 STX lockers by their locked uSTX and write one row
* here per staker per calculation. These rows back the running
* `principal_staking_totals.stx_accrued_rewards` total under reorgs — analogous
* to `principal_bond_reward_distributions` for bond rewards.
*/
export function up(pgm: MigrationBuilder): void {
pgm.createTable('principal_stx_reward_distributions', {
id: {
type: 'bigserial',
primaryKey: true,
},
principal: {
type: 'text',
notNull: true,
},
reward_cycle: {
type: 'integer',
notNull: true,
},
// sBTC reward sats this staker accrued from this calculation.
reward_amount: {
type: 'numeric',
notNull: true,
},
tx_id: {
type: 'bytea',
notNull: true,
},
tx_index: {
type: 'smallint',
notNull: true,
},
block_height: {
type: 'integer',
notNull: true,
},
block_hash: {
type: 'bytea',
},
block_time: {
type: 'bigint',
},
index_block_hash: {
type: 'bytea',
notNull: true,
},
parent_block_hash: {
type: 'bytea',
},
parent_index_block_hash: {
type: 'bytea',
notNull: true,
},
burn_block_height: {
type: 'integer',
},
burn_block_time: {
type: 'bigint',
},
microblock_hash: {
type: 'bytea',
notNull: true,
},
microblock_sequence: {
type: 'integer',
notNull: true,
},
microblock_canonical: {
type: 'boolean',
notNull: true,
},
canonical: {
type: 'boolean',
notNull: true,
},
});

pgm.createIndex('principal_stx_reward_distributions', 'tx_id');
pgm.createIndex('principal_stx_reward_distributions', ['index_block_hash', 'canonical']);
pgm.createIndex('principal_stx_reward_distributions', 'principal');
}

export function down(pgm: MigrationBuilder): void {
pgm.dropTable('principal_stx_reward_distributions');
}
113 changes: 113 additions & 0 deletions migrations/1779800000005_signer-reward-claims.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import type { ColumnDefinitions, MigrationBuilder } from 'node-pg-migrate';

export const shorthands: ColumnDefinitions | undefined = undefined;

/**
* Per-signer reward claim aggregate, one row per pox-5 `claim-rewards` event.
* This is the signer-manager-level claim: the sBTC rewards a signer manager
* claimed for a cycle, broken into the STX-staking portion (`stx_earned`) and
* the per-bond portion (`bond_rewards`), with `total_rewards` the sum. It is
* bookkeeping/audit data with no running totals derived from it — the
* per-staker effects live in `principal_bond_reward_claims` /
* `principal_staking_totals` — so reorgs only flip its canonical flag.
*/
export function up(pgm: MigrationBuilder): void {
pgm.createTable('signer_reward_claims', {
id: {
type: 'bigserial',
primaryKey: true,
},
signer_manager: {
type: 'text',
notNull: true,
},
reward_cycle: {
type: 'integer',
notNull: true,
},
// sBTC reward sats earned by this signer's STX stakers for the cycle.
stx_earned: {
type: 'numeric',
notNull: true,
},
// The cumulative per-uSTX reward rate at claim time (from `stx_rewards`).
stx_rewards_per_token: {
type: 'numeric',
notNull: true,
},
// JSON array of `{ bond_index, earned, rewards_per_token }` per claimed bond.
bond_rewards: {
type: 'jsonb',
notNull: true,
},
// Total sBTC reward sats claimed across all of this signer's bonds.
bond_totals: {
type: 'numeric',
notNull: true,
},
// Total sBTC reward sats claimed (STX-staking + bonds).
total_rewards: {
type: 'numeric',
notNull: true,
},
tx_id: {
type: 'bytea',
notNull: true,
},
tx_index: {
type: 'smallint',
notNull: true,
},
block_height: {
type: 'integer',
notNull: true,
},
block_hash: {
type: 'bytea',
},
block_time: {
type: 'bigint',
},
index_block_hash: {
type: 'bytea',
notNull: true,
},
parent_block_hash: {
type: 'bytea',
},
parent_index_block_hash: {
type: 'bytea',
notNull: true,
},
burn_block_height: {
type: 'integer',
},
burn_block_time: {
type: 'bigint',
},
microblock_hash: {
type: 'bytea',
notNull: true,
},
microblock_sequence: {
type: 'integer',
notNull: true,
},
microblock_canonical: {
type: 'boolean',
notNull: true,
},
canonical: {
type: 'boolean',
notNull: true,
},
});

pgm.createIndex('signer_reward_claims', 'tx_id');
pgm.createIndex('signer_reward_claims', ['index_block_hash', 'canonical']);
pgm.createIndex('signer_reward_claims', ['signer_manager', 'reward_cycle']);
}

export function down(pgm: MigrationBuilder): void {
pgm.dropTable('signer_reward_claims');
}
Loading
Loading