streak-api 0.1.7

API for interacting with the STREAK directional markets protocol on Solana
Documentation
//! Off-chain instruction builders. Fixed account order mirrors on-chain `process_*` comments.

use solana_program::pubkey::Pubkey;
use spl_associated_token_account::{
    get_associated_token_address, get_associated_token_address_with_program_id,
};
use steel::*;

use crate::{
    consts::{
        EXECUTOR_ADDRESS, FEE_COLLECTOR, PYTH_BTC_USD_PRICE_FEED_ACCOUNT, USDC_MAINNET_MINT,
    },
    instruction::{AdminInstantSettlement, AdminPayout, Deposit, Initialize},
    state::Treasury,
};

#[inline(always)]
pub fn program_id() -> Pubkey {
    crate::ID
}

// ── ATA helpers ──────────────────────────────────────────────────────────────

pub fn treasury_usdc_ata() -> Pubkey {
    get_associated_token_address(&Treasury::pda().0, &USDC_MAINNET_MINT)
}

pub fn treasury_usdc_ata_with_token_program(token_program: &Pubkey) -> Pubkey {
    get_associated_token_address_with_program_id(
        &Treasury::pda().0,
        &USDC_MAINNET_MINT,
        token_program,
    )
}

pub fn associated_usdc_ata(owner: Pubkey, token_program: &Pubkey) -> Pubkey {
    get_associated_token_address_with_program_id(&owner, &USDC_MAINNET_MINT, token_program)
}

pub fn usdc_ata(owner: Pubkey) -> Pubkey {
    get_associated_token_address(&owner, &USDC_MAINNET_MINT)
}

pub fn fee_collector_usdc_ata_with_token_program(token_program: &Pubkey) -> Pubkey {
    get_associated_token_address_with_program_id(&FEE_COLLECTOR, &USDC_MAINNET_MINT, token_program)
}

// ── Instruction builders ─────────────────────────────────────────────────────

/// One-time treasury initialization. Seeds genesis BTC price from Pyth push feed.
/// `payer` must be `ADMIN_ADDRESS`.
pub fn initialize(payer: Pubkey, token_program: Pubkey) -> Instruction {
    let treasury_address = Treasury::pda().0;
    let treasury_ata = treasury_usdc_ata_with_token_program(&token_program);
    Instruction {
        program_id: crate::ID,
        accounts: vec![
            AccountMeta::new(payer, true),
            AccountMeta::new(treasury_address, false),
            AccountMeta::new_readonly(USDC_MAINNET_MINT, false),
            AccountMeta::new(treasury_ata, false),
            AccountMeta::new_readonly(system_program::ID, false),
            AccountMeta::new_readonly(token_program, false),
            AccountMeta::new_readonly(spl_associated_token_account::ID, false),
            AccountMeta::new_readonly(PYTH_BTC_USD_PRICE_FEED_ACCOUNT, false),
        ],
        data: Initialize {}.to_bytes(),
    }
}

/// User deposits `amount` µUSDC into the treasury.
/// Server listens for the `Deposited` event to credit the user's off-chain balance.
pub fn deposit(user: Pubkey, amount: u64, token_program: Pubkey) -> Instruction {
    let user_ata = associated_usdc_ata(user, &token_program);
    let treasury_ata = treasury_usdc_ata_with_token_program(&token_program);
    Instruction {
        program_id: crate::ID,
        accounts: vec![
            AccountMeta::new(user, true),
            AccountMeta::new(user_ata, false),
            AccountMeta::new(treasury_ata, false),
            AccountMeta::new_readonly(USDC_MAINNET_MINT, false),
            AccountMeta::new_readonly(token_program, false),
        ],
        data: Deposit {
            amount: amount.to_le_bytes(),
        }
        .to_bytes(),
    }
}

/// Advance the price chain and emit `PeriodSettled`. Reads close price from the Pyth push feed.
pub fn settle_period(authority: Pubkey, series_id: u16, period: u64) -> Instruction {
    Instruction {
        program_id: crate::ID,
        accounts: vec![
            AccountMeta::new(authority, true),
            AccountMeta::new(Treasury::pda().0, false),
            AccountMeta::new_readonly(PYTH_BTC_USD_PRICE_FEED_ACCOUNT, false),
        ],
        data: AdminInstantSettlement {
            series_id: series_id.to_le_bytes(),
            _pad_ix: [0; 6],
            period: period.to_le_bytes(),
        }
        .to_bytes(),
    }
}

/// Pay `amount` µUSDC from the treasury to `recipient_ata`.
/// Used for winner payouts, jackpot distributions, and withdrawals.
pub fn payout(
    executor: Pubkey,
    recipient_ata: Pubkey,
    amount: u64,
    series_id: u16,
    period: u64,
    token_program: Pubkey,
) -> Instruction {
    let treasury_address = Treasury::pda().0;
    let treasury_ata = treasury_usdc_ata_with_token_program(&token_program);
    Instruction {
        program_id: crate::ID,
        accounts: vec![
            AccountMeta::new(executor, true),
            AccountMeta::new(treasury_address, false),
            AccountMeta::new(treasury_ata, false),
            AccountMeta::new(recipient_ata, false),
            AccountMeta::new_readonly(USDC_MAINNET_MINT, false),
            AccountMeta::new_readonly(token_program, false),
        ],
        data: AdminPayout {
            amount: amount.to_le_bytes(),
            series_id: series_id.to_le_bytes(),
            _pad_ix: [0; 6],
            period: period.to_le_bytes(),
        }
        .to_bytes(),
    }
}

/// Convenience: `settle_period` signed by the canonical `EXECUTOR_ADDRESS`.
pub fn settle_period_default_executor(series_id: u16, period: u64) -> Instruction {
    settle_period(EXECUTOR_ADDRESS, series_id, period)
}