gmsol_store/states/oracle/
chainlink.rs

1use anchor_lang::prelude::*;
2
3use gmsol_utils::price::{Decimal, Price};
4
5use crate::{states::TokenConfig, CoreError};
6
7/// The Chainlink Program.
8pub struct Chainlink;
9
10impl Id for Chainlink {
11    fn id() -> Pubkey {
12        chainlink_solana::ID
13    }
14}
15
16impl Chainlink {
17    /// Check and get latest chainlink price from data feed.
18    pub(crate) fn check_and_get_chainlink_price<'info>(
19        clock: &Clock,
20        chainlink_program: &impl ToAccountInfo<'info>,
21        token_config: &TokenConfig,
22        feed: &AccountInfo<'info>,
23    ) -> Result<(u64, i64, Price)> {
24        let chainlink_program = chainlink_program.to_account_info();
25        let round = chainlink_solana::latest_round_data(chainlink_program.clone(), feed.clone())?;
26        let decimals = chainlink_solana::decimals(chainlink_program, feed.clone())?;
27        Self::check_and_get_price_from_round(clock, &round, decimals, token_config)
28    }
29
30    /// Check and get price from the round data.
31    fn check_and_get_price_from_round(
32        clock: &Clock,
33        round: &chainlink_solana::Round,
34        decimals: u8,
35        token_config: &TokenConfig,
36    ) -> Result<(u64, i64, Price)> {
37        let chainlink_solana::Round {
38            answer, timestamp, ..
39        } = round;
40        require_gt!(*answer, 0, CoreError::InvalidPriceFeedPrice);
41        let timestamp = *timestamp as i64;
42        let current = clock.unix_timestamp;
43        if current > timestamp && current - timestamp > token_config.heartbeat_duration().into() {
44            return err!(CoreError::PriceFeedNotUpdated);
45        }
46        let price = Decimal::try_from_price(
47            *answer as u128,
48            decimals,
49            token_config.token_decimals(),
50            token_config.precision(),
51        )
52        .map_err(|_| error!(CoreError::InvalidPriceFeedPrice))?;
53        Ok((
54            round.slot,
55            timestamp,
56            Price {
57                min: price,
58                max: price,
59            },
60        ))
61    }
62}