harb/services/ponder/ponder.schema.ts

275 lines
6.4 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
export const stackMeta = onchainTable('stackMeta', t => ({
id: t.text().primaryKey(),
contractVersion: t
.integer()
.notNull()
.$default(() => 0),
ponderVersion: t
.text()
.notNull()
.$default(() => 'unknown'),
kraikenLibVersion: t
.integer()
.notNull()
.$default(() => 0),
updatedAt: t
.bigint()
.notNull()
.$default(() => 0n),
}));
2025-09-23 14:18:04 +02:00
// 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-10-11 12:33:35 +00:00
positionsUpdatedAt: t
.bigint()
.notNull()
.$default(() => 0n),
minStake: 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')),
2026-02-18 00:19:05 +01:00
// LiquidityManager stats
holderCount: t
.integer()
.notNull()
.$default(() => 0),
lastRecenterTimestamp: t
.bigint()
.notNull()
.$default(() => 0n),
lastRecenterTick: t
.integer()
.notNull()
.$default(() => 0),
recentersLastDay: t
.integer()
.notNull()
.$default(() => 0),
recentersLastWeek: t
.integer()
.notNull()
.$default(() => 0),
lastEthReserve: t
.bigint()
.notNull()
.$default(() => 0n),
lastVwapTick: t
.integer()
.notNull()
.$default(() => 0),
// 7-day ETH reserve growth metrics
ethReserve7dAgo: t.bigint(),
ethReserveGrowthBps: t.integer(),
// 7-day trading fees earned
feesEarned7dEth: t
.bigint()
.notNull()
.$default(() => 0n),
feesEarned7dKrk: t
.bigint()
.notNull()
.$default(() => 0n),
feesLastUpdated: t.bigint(),
// Floor price metrics
floorTick: t.integer(),
floorPriceWei: t.bigint(),
currentPriceWei: t.bigint(),
floorDistanceBps: t.integer(),
}));
// ETH reserve history - tracks ethBalance over time for 7d growth calculation
export const ethReserveHistory = onchainTable('ethReserveHistory', t => ({
id: t.text().primaryKey(), // block_logIndex format
timestamp: t.bigint().notNull(),
ethBalance: t.bigint().notNull(),
}));
// Fee history - tracks fees earned over time for 7d totals
export const feeHistory = onchainTable('feeHistory', t => ({
id: t.text().primaryKey(), // block_logIndex format
timestamp: t.bigint().notNull(),
ethFees: t.bigint().notNull(),
krkFees: t.bigint().notNull(),
}));
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
2026-02-18 00:19:05 +01:00
// Recenters - track LiquidityManager recenter events
export const recenters = onchainTable('recenters', t => ({
id: t.text().primaryKey(), // block_logIndex format
timestamp: t.bigint().notNull(),
currentTick: t.integer().notNull(),
isUp: t.boolean().notNull(),
ethBalance: t.bigint(), // nullable - only from Scarcity/Abundance events
outstandingSupply: t.bigint(), // nullable
vwapTick: t.integer(), // nullable
}));
// Holders - track Kraiken token holders
export const holders = onchainTable(
'holders',
t => ({
address: t.hex().primaryKey(),
balance: t.bigint().notNull(),
}),
table => ({
addressIdx: index().on(table.address),
})
);
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;