Skip to main content

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);