use solana_program::{account_info::AccountInfo, program_error::ProgramError};
use crate::error::StreakError;
use crate::pyth::{load_fresh_price, outcome_from_open_close, Price};
use crate::state::{Market, Treasury};
use steel::AccountInfoValidation;
pub fn oracle_outcome_market_vs_pyth(
market: &Market,
pyth_price_feed_info: &AccountInfo<'_>,
unix_timestamp: i64,
) -> Result<u8, ProgramError> {
if !market.has_open_oracle_snapshot() {
return Err(StreakError::MarketNotOracleAnchored.into());
}
pyth_price_feed_info.has_address(&market.pyth_price_feed)?;
let open_px = Price {
price: market.open_ref_price,
conf: 0,
expo: market.open_ref_expo,
publish_time: market.open_ref_publish_time,
};
let close_px = load_fresh_price(pyth_price_feed_info, unix_timestamp)?;
outcome_from_open_close(open_px, close_px)
}
pub fn apply_settlement_outcome(
market: &mut Market,
treasury: &mut Treasury,
period: u64,
outcome: u8,
) -> Result<(), ProgramError> {
if market.period != period {
return Err(StreakError::BadMarketState.into());
}
if market.status != Market::STATUS_OPEN {
return Err(StreakError::BadMarketState.into());
}
if market.committed_up != 0 || market.committed_down != 0 {
return Err(StreakError::UnresolvedCommittedStakes.into());
}
let winner_total = if outcome == Market::SIDE_UP {
market.total_up
} else {
market.total_down
};
let loser_pot = if outcome == Market::SIDE_UP {
market.total_down
} else {
market.total_up
};
let reward_pool = if winner_total == 0 {
0u64
} else {
treasury.daily_jackpot.min(loser_pot)
};
if reward_pool > 0 {
treasury.daily_jackpot = treasury
.daily_jackpot
.checked_sub(reward_pool)
.ok_or(StreakError::InsufficientTreasury)?;
}
market.loser_pot = loser_pot;
market.reward_pool = reward_pool;
market.winning_total = winner_total;
market.outcome = outcome;
market.status = Market::STATUS_SETTLED;
if winner_total == 0 {
treasury.bump_next_period_floor(market.series_id, period)?;
}
Ok(())
}