gmsol_store/states/oracle/
chainlink.rs1use anchor_lang::prelude::*;
2
3use gmsol_utils::price::{Decimal, Price};
4
5use crate::{states::TokenConfig, CoreError};
6
7pub struct Chainlink;
9
10impl Id for Chainlink {
11 fn id() -> Pubkey {
12 chainlink_solana::ID
13 }
14}
15
16impl Chainlink {
17 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 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}