use anchor_client::{solana_sdk::commitment_config::CommitmentConfig, Client, Cluster};
use anchor_lang::{prelude::Pubkey, AccountDeserialize};
use anyhow::Ok;
use pyth_solana_receiver_sdk::price_update::PriceUpdateV2;
use std::sync::Arc;
use crate::{
math::{casting::Cast, safe_math::SafeMath},
oracle::{OraclePriceLiquidate, ORACLE_PROGRAM_ID},
programs::oracle,
ReadKeypair,
};
pub const RATE_OUTPUT_DECIMALS: u32 = 15;
pub async fn get_oracle_price_liquidate(
oracle: Pubkey,
cluster: Cluster,
) -> anyhow::Result<OraclePriceLiquidate> {
let payer = ReadKeypair::new();
let provider = Client::new_with_options(
cluster.clone(),
Arc::new(payer.clone()),
CommitmentConfig::confirmed(),
);
let program = provider.program(ORACLE_PROGRAM_ID)?;
let oracle_data: oracle::accounts::Oracle = program.account(oracle).await?;
if oracle_data.sources.len() == 0 {
return Err(anyhow::anyhow!("No sources found"));
}
let source = oracle_data.sources[0];
let price = match source.source_type {
oracle::types::SourceType::Pyth => {
let rpc = program.rpc();
let account = rpc.get_account(&source.source).await?;
let mut price_update_data: &[u8] = account.data.iter().as_slice();
let price_update = PriceUpdateV2::try_deserialize(&mut price_update_data).unwrap();
if price_update.price_message.price <= 0 || price_update.price_message.exponent > 0 {
return Err(anyhow::anyhow!("Price is not valid"));
}
let multiplier: u32 = price_update.price_message.exponent.abs().cast()?;
let delta = 10u128.pow(RATE_OUTPUT_DECIMALS.safe_sub(multiplier)?);
price_update
.price_message
.price
.cast::<u128>()?
.safe_mul(delta)?
.saturating_div(source.divisor)
}
oracle::types::SourceType::StakePool => {
return Err(anyhow::anyhow!("Unsupported source type"));
}
};
Ok(OraclePriceLiquidate {
price,
sources: oracle_data.sources,
})
}