streak_api/instruction.rs
1//! Instruction discriminators + payload types.
2
3use steel::*;
4
5/// One-time setup: creates `Treasury` PDA + treasury USDC ATA. `payer` must be `ADMIN_ADDRESS`.
6///
7/// **Accounts:** `payer`, `treasury`, `mint`, `treasury_ata`, `system_program`, `token_program`,
8/// `ata_program`.
9#[repr(C)]
10#[derive(Clone, Copy, Debug, Pod, Zeroable)]
11pub struct Initialize {}
12
13/// Purchase tickets (gaming credits) with USDC.
14///
15/// Buying tickets is separate from placing a bet. The user first buys credits here
16/// (on-chain, USDC split immediately), then places bets off-chain via the server
17/// using those credits.
18///
19/// 1. Transfers `amount` µUSDC from the user's ATA into the treasury ATA.
20/// 2. Updates `Treasury` PDA counters: `daily_jackpot += 70%`, `weekly_jackpot += 15%`,
21/// `buyback += 10%`.
22/// 3. Forwards the team share (5%) from the treasury ATA to `FEE_COLLECTOR` (CPI).
23/// 4. Creates or increments the user's `UserCredits` PDA (`total_purchased += amount`).
24/// 5. Emits `TicketPurchased { user, amount }`.
25///
26/// The indexer reads `TicketPurchased` events to credit the user's off-chain spendable
27/// balance. Bets are placed and debited server-side against that balance.
28///
29/// **Accounts:** `user` (signer/payer), `user_ata`, `treasury`, `treasury_ata`, `credits`,
30/// `fee_collector_ata`, `mint`, `token_program`, `system_program`.
31#[repr(C)]
32#[derive(Clone, Copy, Debug, Pod, Zeroable)]
33pub struct BuyTicket {
34 /// Amount in µUSDC (6 decimals).
35 pub amount: [u8; 8],
36}
37
38/// Route claimed DBC / DAMM v2 trading fees into the treasury and split them on-chain.
39///
40/// The executor bot claims pool creator/LP fees off-chain via the Meteora SDK, receiving USDC
41/// into its own ATA. This instruction then:
42/// 1. Transfers `amount` µUSDC from the executor's ATA into the treasury ATA (CPI).
43/// 2. Splits the amount according to `TICKET_*_BPS` and updates `Treasury` counters.
44/// 3. Forwards the team share (5%) from the treasury ATA to `FEE_COLLECTOR` (CPI).
45/// 4. Emits `FeesRouted`.
46///
47/// **Accounts:** `executor` (signer), `executor_ata`, `treasury`, `treasury_ata`,
48/// `fee_collector_ata`, `mint`, `token_program`.
49#[repr(C)]
50#[derive(Clone, Copy, Debug, Pod, Zeroable)]
51pub struct AdminRouteFees {
52 pub amount: [u8; 8],
53}
54
55/// Pay `amount` µUSDC from the treasury ATA to `recipient_ata`. Used for winner payouts and
56/// jackpot distributions. Only `EXECUTOR_ADDRESS` may sign.
57///
58/// **Accounts:** `executor` (signer), `treasury`, `treasury_ata`, `recipient_ata`, `mint`,
59/// `token_program`.
60#[repr(C)]
61#[derive(Clone, Copy, Debug, Pod, Zeroable)]
62pub struct AdminPayout {
63 pub amount: [u8; 8],
64 pub series_id: [u8; 2],
65 /// Which treasury counter to debit (`PAYOUT_POOL_*`). Zero = bet payout only.
66 pub pool: u8,
67 pub _pad_ix: [u8; 5],
68 pub period: [u8; 8],
69}
70
71/// Executor-only: overwrite treasury pool counters (one-shot reconcile).
72///
73/// Enforces `daily_jackpot + weekly_jackpot + buyback <= treasury_ata.amount`.
74///
75/// **Accounts:** `executor` (signer), `treasury`, `treasury_ata`, `mint`, `token_program`.
76#[repr(C)]
77#[derive(Clone, Copy, Debug, Pod, Zeroable)]
78pub struct AdminSetTreasuryPools {
79 pub daily_jackpot: [u8; 8],
80 pub weekly_jackpot: [u8; 8],
81 pub buyback: [u8; 8],
82 pub stability_reserve: [u8; 8],
83}
84
85/// Place one bet for the current round.
86///
87/// Rules enforced on-chain:
88/// 1. `User.balance >= TICKET_PRICE_MICROS` (must have at least 1 ticket).
89/// 2. `User.last_bet_period != period` (one bet per round, no double-betting).
90/// 3. Debits exactly `TICKET_PRICE_MICROS` from `User.balance`.
91/// 4. Sets `User.last_bet_period = period`.
92/// 5. Emits `BetPlaced { user, period, side }`.
93///
94/// The indexer reads `BetPlaced` to insert the bet into the DB and update market pools.
95/// The server builds and returns an unsigned `PlaceBet` tx; the user signs in their wallet.
96///
97/// **Accounts:** `user` (signer), `user_pda`.
98#[repr(C)]
99#[derive(Clone, Copy, Debug, Pod, Zeroable)]
100pub struct PlaceBet {
101 /// 0 = UP, 1 = DOWN.
102 pub side: u8,
103 pub _pad: [u8; 1],
104 /// Market series (always 0 for BTC/USD).
105 pub series_id: [u8; 2],
106 pub _pad2: [u8; 4],
107 /// 5-min period number: `floor(unix_ts / 300)`.
108 pub period: [u8; 8],
109}
110
111use num_enum::TryFromPrimitive;
112
113#[repr(u8)]
114#[derive(Clone, Copy, Debug, Eq, PartialEq, TryFromPrimitive)]
115pub enum StreakInstruction {
116 Initialize = 0,
117 BuyTicket = 1,
118 AdminRouteFees = 2,
119 AdminPayout = 3,
120 PlaceBet = 4,
121 AdminSetTreasuryPools = 5,
122}
123
124instruction!(StreakInstruction, Initialize);
125instruction!(StreakInstruction, BuyTicket);
126instruction!(StreakInstruction, AdminRouteFees);
127instruction!(StreakInstruction, AdminPayout);
128instruction!(StreakInstruction, PlaceBet);
129instruction!(StreakInstruction, AdminSetTreasuryPools);