use pyth_sdk_solana::state::SolanaPriceAccount;
use solana_program::{
account_info::AccountInfo,
entrypoint::ProgramResult,
program_error::ProgramError,
};
use steel::AccountInfoValidation;
pub use pyth_sdk_solana::Price;
use crate::consts::{PYTH_MAX_PRICE_AGE_SECS, PYTH_ORACLE_PROGRAM};
use crate::error::StreakError;
use crate::state::Market;
pub fn assert_legacy_pyth_owner(info: &AccountInfo) -> ProgramResult {
if *info.key == solana_program::pubkey::Pubkey::default() {
return Err(StreakError::PythInvalidAccount.into());
}
if info.owner != &PYTH_ORACLE_PROGRAM {
return Err(StreakError::PythBadOwner.into());
}
Ok(())
}
pub fn load_fresh_price(
info: &AccountInfo,
unix_timestamp: i64,
) -> Result<Price, ProgramError> {
assert_legacy_pyth_owner(info)?;
let feed = SolanaPriceAccount::account_info_to_feed(info)
.map_err(|_| StreakError::PythInvalidAccount)?;
feed.get_price_no_older_than(unix_timestamp, PYTH_MAX_PRICE_AGE_SECS)
.ok_or(StreakError::OraclePriceStale.into())
}
pub fn anchor_open_snapshot(
market: &mut Market,
pyth_price_feed_info: &AccountInfo,
unix_timestamp: i64,
) -> Result<(), ProgramError> {
pyth_price_feed_info.has_address(&market.pyth_price_feed)?;
let px = load_fresh_price(pyth_price_feed_info, unix_timestamp)?;
market.open_ref_price = px.price;
market.open_ref_expo = px.expo;
market.open_ref_publish_time = px.publish_time;
Ok(())
}
pub fn outcome_from_open_close(open: Price, close: Price) -> Result<u8, ProgramError> {
const EXP: i32 = -8;
let o = open
.scale_to_exponent(EXP)
.ok_or(StreakError::OracleNormalize)?;
let c = close
.scale_to_exponent(EXP)
.ok_or(StreakError::OracleNormalize)?;
if c.price > o.price {
Ok(Market::SIDE_UP)
} else {
Ok(Market::SIDE_DOWN)
}
}