streak-api 0.1.2

API for interacting with the STREAK directional markets protocol on Solana
//! Instruction discriminators + payload types (**Ore**: single `instruction.rs`).

use steel::*;

/// One-time **`Initialize`**: creates **`Treasury`** PDA + treasury USDC ATA. Economics and routing pubkeys are [`crate::consts`] (**`FEE_COLLECTOR`** for team-fee SPL legs). **`payer`** must be [`ADMIN_ADDRESS`](crate::consts::ADMIN_ADDRESS).
///
/// **Accounts:** **`payer`**, **`treasury`**, **`mint`**, **`treasury_ata`**, **`system_program`**, **`token_program`**, **`ata_program`**.
#[repr(C)]
#[derive(Clone, Copy, Debug, Pod, Zeroable)]
pub struct Initialize {}

/// Purchase tickets: user pays **`amount`** USDC (**micro base units**); team cut to fee collector; remainder splits into **`Treasury`** lanes; **`Ledger`** credits **`unstaked_micros`** and **`tickets`**.
///
/// **Accounts:** **`user`**, **`treasury`**, **`ledger`**, **`mint`**, **`user_ata`**, **`treasury_ata`**, **`team_ata`**, **`system_program`**, **`token_program`**, **`ata_program`**, **`previous_market`**, **`previous_position`**.
#[repr(C)]
#[derive(Clone, Copy, Debug, Pod, Zeroable)]
pub struct BuyTickets {
    pub period: [u8; 8],
    pub amount: [u8; 8],
}

/// Spend **`ticket_units`** from **`Ledger`** into **`Position`** / **`Market`** during **`[open_ts, close_ts)`** after **`InitMarket`** has recorded the open oracle snapshot (**create** within the anchor window **or** a follow-up **`InitMarket`** with identical args once the **`market`** PDA exists).
/// **`period`** must equal **`Treasury::next_market_period`** (**only the active line** accepts stakes).
///
/// **Accounts:** **`user`**, **`ledger`**, **`treasury`** (**readonly**), **`market`**, **`position`**, **`previous_market`**, **`previous_position`**, **`system_program`**.
#[repr(C)]
#[derive(Clone, Copy, Debug, Pod, Zeroable)]
pub struct PlaceBet {
    pub period: [u8; 8],
    pub ticket_units: [u8; 8],
    pub side: u8,
    pub _pad: [u8; 7],
}

/// Creates **`Market`** (**executor signer**) **or**, if the **`market`** PDA already exists and the ix matches on-chain **`Market`** fields (**`period`**, **`open_ts`**, **`close_ts`**, **`pyth_price_feed`**, **`rules_hash`**) while **`open_*`** is unfrozen, records the open Pyth snapshot (**executor-signed crank**, **matching** ix args).
///
/// **`Create`**: **`OPEN_TS`** / **`CLOSE_TS`**, **`PYTH_PRICE_FEED`** (non-zero), **`RULES_HASH`**. **`period`** must equal **`Treasury::next_market_period`** (**prior period must have settled** — sequential listings).
/// Immediately after **`create`**, if **`Clock`** is **`∈ [open_ts, min(open_ts + MARKET_OPEN_ANCHOR_GRACE_SECS, close_ts))`**, the snapshot is taken in the **same ix**; earlier **`Clock`** skips anchoring (**send same ix again later** inside the anchor window — still discriminator **`InitMarket`** — with **matching** **`open_ts`**, **`close_ts`**, **`pyth_price_feed`**, **`rules_hash`**).
///
/// **Accounts:** **`authority`** (writable signer — [`EXECUTOR_ADDRESS`](crate::consts::EXECUTOR_ADDRESS) on **create** and **crank open**), **`market`**, **`treasury`** (**readonly**), **`system_program`**, **`pyth_price_feed`** (**readonly**, must equal stored feed on **`market`**).
#[repr(C)]
#[derive(Clone, Copy, Debug, Pod, Zeroable)]
pub struct InitMarket {
    pub period: [u8; 8],
    pub open_ts: [u8; 8],
    pub close_ts: [u8; 8],
    pub pyth_price_feed: [u8; 32],
    pub rules_hash: [u8; 32],
}

/// Executor instant settle after **`close_ts`** vs fresh Pyth (requires anchored open snapshot). **`authority`** must be [`EXECUTOR_ADDRESS`](crate::consts::EXECUTOR_ADDRESS).
///
/// **`Market::reward_pool`** (treasury subsidy) is set on-chain to **`min(Treasury::daily_jackpot, loser_pot)`** when there are winners, else **`0`**.
///
/// **Accounts:** **`authority`** (**writable signer**), **`treasury`**, **`market`**, **`pyth_price_feed`**.
#[repr(C)]
#[derive(Clone, Copy, Debug, Pod, Zeroable)]
pub struct AdminInstantSettlement {
    pub period: [u8; 8],
}

/// Payload for CPI + treasury route (see [`StreakInstruction::ClaimPositionFee`]).
#[repr(C)]
#[derive(Clone, Copy, Debug, Pod, Zeroable)]
pub struct ClaimPositionFee {}

/// **`EXECUTOR_KIND_DISTRIBUTE_MARKET_REWARD`**: **`pool`** and **`amount`** must be **0** (winner payout + ledger streak).
///
/// **`EXECUTOR_KIND_LANE_PAY`**: SPL **`transfer_checked`** from treasury ATA; **`amount`** & **`pool`** (**daily / weekly** jackpot lane).
///
/// **`EXECUTOR_KIND_MARKET_LINE_RELEASE`**: after **`AdminInstantSettlement`** when **`winning_total > 0`**, executor finishes **`DISTRIBUTE_MARKET_REWARD`** for that period, then advances **`Treasury::next_market_period`** so **`InitMarket` create** may open the next listing (**`pool = 0`**, **`amount = period`** LE). **Accounts:** **`executor`**, **`treasury`**, **`market`**.
#[repr(C)]
#[derive(Clone, Copy, Debug, Pod, Zeroable)]
pub struct ExecutorTreasury {
    pub kind: u8,
    pub pool: u8,
    pub _pad: [u8; 6],
    pub amount: [u8; 8],
}

pub const EXECUTOR_KIND_DISTRIBUTE_MARKET_REWARD: u8 = 0;
pub const EXECUTOR_KIND_LANE_PAY: u8 = 1;
/// Bump **`Treasury::next_market_period`** after market **`period`** is settled and **`DISTRIBUTE`** batch is done (executor-trusted).
pub const EXECUTOR_KIND_MARKET_LINE_RELEASE: u8 = 2;

use num_enum::TryFromPrimitive;

#[repr(u8)]
#[derive(Clone, Copy, Debug, Eq, PartialEq, TryFromPrimitive)]
pub enum StreakInstruction {
    Initialize = 0,
    BuyTickets = 1,
    PlaceBet = 2,
    InitMarket = 3,
    AdminInstantSettlement = 4,
    ExecutorTreasury = 5,
    ClaimPositionFee = 6,
}

instruction!(StreakInstruction, Initialize);
instruction!(StreakInstruction, BuyTickets);
instruction!(StreakInstruction, PlaceBet);
instruction!(StreakInstruction, InitMarket);
instruction!(StreakInstruction, AdminInstantSettlement);
instruction!(StreakInstruction, ExecutorTreasury);
instruction!(StreakInstruction, ClaimPositionFee);