gmsol_store/states/oracle/
pyth.rs

1use anchor_lang::prelude::*;
2use gmsol_utils::{oracle::OracleError, price::Price};
3use pyth_solana_receiver_sdk::price_update::PriceUpdateV2;
4
5use crate::{states::TokenConfig, CoreError};
6
7pub use gmsol_utils::oracle::pyth_price_with_confidence_to_price;
8
9/// The Pyth receiver program.
10pub struct Pyth;
11
12impl Id for Pyth {
13    fn id() -> Pubkey {
14        pyth_solana_receiver_sdk::ID
15    }
16}
17
18impl Pyth {
19    /// Push Oracle ID.
20    pub const PUSH_ORACLE_ID: Pubkey = pyth_solana_receiver_sdk::PYTH_PUSH_ORACLE_ID;
21
22    #[allow(clippy::manual_inspect)]
23    pub(super) fn check_and_get_price<'info>(
24        clock: &Clock,
25        token_config: &TokenConfig,
26        feed: &'info AccountInfo<'info>,
27        feed_id: &Pubkey,
28    ) -> Result<(u64, i64, Price)> {
29        let feed = Account::<PriceUpdateV2>::try_from(feed)?;
30        let feed_id = feed_id.to_bytes();
31        let max_age = token_config.heartbeat_duration().into();
32        let price = feed
33            .get_price_no_older_than(clock, max_age, &feed_id)
34            .map_err(|err| {
35                let price_ts = feed.price_message.publish_time;
36                msg!(
37                    "[Pyth] get price error, clock={} price_ts={} max_age={}",
38                    clock.unix_timestamp,
39                    price_ts,
40                    max_age,
41                );
42                err
43            })?;
44        let parsed_price = pyth_price_with_confidence_to_price(
45            price.price,
46            price.conf,
47            price.exponent,
48            token_config,
49        )
50        .map_err(CoreError::from)
51        .map_err(|err| error!(err))?;
52        Ok((feed.posted_slot, price.publish_time, parsed_price))
53    }
54}
55
56impl From<OracleError> for CoreError {
57    fn from(err: OracleError) -> Self {
58        msg!("Oracle error: {}", err);
59        match err {
60            OracleError::InvalidPriceFeedPrice(_) => CoreError::InvalidPriceFeedPrice,
61        }
62    }
63}