harb/services/ponder/ponder.schema.ts

158 lines
3.7 KiB
TypeScript
Raw Normal View History

import { onchainTable, index } from 'ponder';
import { TAX_RATE_OPTIONS } from 'kraiken-lib/taxRates';
2025-09-23 14:18:04 +02:00
export const HOURS_IN_RING_BUFFER = 168; // 7 days * 24 hours
const RING_BUFFER_SEGMENTS = 4; // ubi, minted, burned, tax
// Global protocol stats - singleton with id "0x01"
export const stats = onchainTable('stats', t => ({
id: t.text().primaryKey(), // Always "0x01"
kraikenTotalSupply: t
.bigint()
.notNull()
.$default(() => 0n),
stakeTotalSupply: t
.bigint()
.notNull()
.$default(() => 0n),
outstandingStake: t
.bigint()
.notNull()
.$default(() => 0n),
2025-09-23 14:18:04 +02:00
// Totals
totalMinted: t
.bigint()
.notNull()
.$default(() => 0n),
totalBurned: t
.bigint()
.notNull()
.$default(() => 0n),
totalTaxPaid: t
.bigint()
.notNull()
.$default(() => 0n),
totalUbiClaimed: t
.bigint()
.notNull()
.$default(() => 0n),
2025-09-23 14:18:04 +02:00
// Rolling windows - calculated from ring buffer
mintedLastWeek: t
.bigint()
.notNull()
.$default(() => 0n),
mintedLastDay: t
.bigint()
.notNull()
.$default(() => 0n),
mintNextHourProjected: t
.bigint()
.notNull()
.$default(() => 0n),
2025-09-23 14:18:04 +02:00
burnedLastWeek: t
.bigint()
.notNull()
.$default(() => 0n),
burnedLastDay: t
.bigint()
.notNull()
.$default(() => 0n),
burnNextHourProjected: t
.bigint()
.notNull()
.$default(() => 0n),
2025-09-23 14:18:04 +02:00
taxPaidLastWeek: t
.bigint()
.notNull()
.$default(() => 0n),
taxPaidLastDay: t
.bigint()
.notNull()
.$default(() => 0n),
taxPaidNextHourProjected: t
.bigint()
.notNull()
.$default(() => 0n),
2025-09-23 14:18:04 +02:00
ubiClaimedLastWeek: t
.bigint()
.notNull()
.$default(() => 0n),
ubiClaimedLastDay: t
.bigint()
.notNull()
.$default(() => 0n),
ubiClaimedNextHourProjected: t
.bigint()
.notNull()
.$default(() => 0n),
2025-09-23 14:18:04 +02:00
// Ring buffer state (flattened array of length HOURS_IN_RING_BUFFER * 4)
ringBufferPointer: t
.integer()
.notNull()
.$default(() => 0),
lastHourlyUpdateTimestamp: t
.bigint()
.notNull()
.$default(() => 0n),
ringBuffer: t
.jsonb()
.$type<string[]>()
.notNull()
.$default(() => Array(HOURS_IN_RING_BUFFER * RING_BUFFER_SEGMENTS).fill('0')),
}));
2025-09-23 14:18:04 +02:00
// Individual staking positions
export const positions = onchainTable(
'positions',
t => ({
2025-09-23 14:18:04 +02:00
id: t.text().primaryKey(), // Position ID from contract
owner: t.hex().notNull(),
share: t.real().notNull(), // Share as decimal (0-1)
taxRate: t.real().notNull(), // Tax rate as decimal (e.g., 0.01 for 1%) - for display
taxRateIndex: t.integer().notNull(), // Tax rate index from contract - source of truth
2025-09-23 14:18:04 +02:00
kraikenDeposit: t.bigint().notNull(),
stakeDeposit: t.bigint().notNull(),
taxPaid: t
.bigint()
.notNull()
.$default(() => 0n),
snatched: t
.integer()
.notNull()
.$default(() => 0),
2025-09-23 14:18:04 +02:00
creationTime: t.bigint().notNull(),
lastTaxTime: t.bigint().notNull(),
status: t
.text()
.notNull()
.$default(() => 'Active'), // "Active" or "Closed"
2025-09-23 14:18:04 +02:00
createdAt: t.bigint().notNull(),
closedAt: t.bigint(),
totalSupplyInit: t.bigint().notNull(),
totalSupplyEnd: t.bigint(),
payout: t
.bigint()
.notNull()
.$default(() => 0n),
2025-09-23 14:18:04 +02:00
}),
table => ({
2025-09-23 14:18:04 +02:00
ownerIdx: index().on(table.owner),
statusIdx: index().on(table.status),
taxRateIndexIdx: index().on(table.taxRateIndex),
2025-09-23 14:18:04 +02:00
})
);
// Export decimal values for backward compatibility in event handlers
// Maps index → decimal (e.g., TAX_RATES[0] = 0.01 for 1% yearly)
export const TAX_RATES = TAX_RATE_OPTIONS.map(opt => opt.decimal);
2025-09-23 14:18:04 +02:00
// Helper constants
export const STATS_ID = '0x01';
2025-09-23 14:18:04 +02:00
export const SECONDS_IN_HOUR = 3600;