streak_api/state/treasury.rs
1//! Protocol USDC bookkeeping (`treasury` PDA). **`BuyTickets`**, **`AdminInstantSettlement`**, and **`ClaimPositionFee`** update these counters; SPL USDC sits in the treasury ATA (**owner = this PDA**).
2//!
3//! Daily / weekly **winner lists and tier splits are computed off-chain**; **`ExecutorTreasury`** (**`JACKPOT_PAY`**) debits **`daily_jackpot`** / **`weekly_jackpot`** when the executor pays.
4
5use steel::*;
6
7use crate::consts::MAX_MARKET_SERIES;
8use crate::error::StreakError;
9
10use super::{treasury_pda, StreakAccount};
11
12#[repr(C)]
13#[derive(Clone, Copy, Debug, PartialEq, Pod, Zeroable)]
14pub struct Treasury {
15 /// **Daily jackpot** accruals (tickets + settlement subsidy); debited via **`ExecutorTreasury`** (**`JACKPOT_PAY`**, daily pool).
16 pub daily_jackpot: u64,
17 /// **Weekly jackpot** accruals (tickets + hook split); debited via **`ExecutorTreasury`** (**`JACKPOT_PAY`**, weekly pool).
18 pub weekly_jackpot: u64,
19 pub buyback: u64,
20 /// Monotonic bookkeeping floor (`max` of **`period + 1`** pushed by **`MARKET_LINE_RELEASE`** and by settlement when **`winning_total == 0`**).
21 ///
22 /// **`InitMarket`** / **`PlaceBet`** do **not** require **`period == next_period[..]`**: many rounds may be deployed and traded like a listing grid; this cursor is ops / indexing only.
23 pub next_period: [u64; MAX_MARKET_SERIES],
24 /// Monotonically increasing week counter. Incremented by [`AdminNewWeek`](crate::instruction::AdminNewWeek)
25 /// at the start of each scoring week (admin-gated, not time-derived on-chain).
26 ///
27 /// Each `Ledger` stores [`Ledger::week_number`](super::Ledger::week_number) and compares it
28 /// against this value on every instruction that touches weekly stats; stale weekly counters
29 /// are zeroed lazily (no all-ledger sweep needed).
30 pub current_week: u64,
31}
32
33impl Treasury {
34 pub fn pda() -> (Pubkey, u8) {
35 treasury_pda()
36 }
37
38 #[inline(always)]
39 pub fn series_index(series_id: u16) -> Result<usize, StreakError> {
40 let i = series_id as usize;
41 if i >= MAX_MARKET_SERIES {
42 return Err(StreakError::InvalidMarketSeries);
43 }
44 Ok(i)
45 }
46
47 /// Advance **`next_period[slot]`** to at least **`settled_period + 1`** (no-op if already higher).
48 #[inline(always)]
49 pub fn bump_next_period_floor(
50 &mut self,
51 series_id: u16,
52 settled_period: u64,
53 ) -> Result<(), StreakError> {
54 let i = Self::series_index(series_id)?;
55 let n = settled_period.checked_add(1).ok_or(StreakError::Overflow)?;
56 if n > self.next_period[i] {
57 self.next_period[i] = n;
58 }
59 Ok(())
60 }
61}
62
63account!(StreakAccount, Treasury);