1use solana_program::{
2 account_info::AccountInfo,
3 clock::Clock,
4 msg,
5 program_error::ProgramError,
6 pubkey::{Pubkey},
7 pubkey,
8 sysvar::Sysvar,
9};
10use pyth_solana_receiver_sdk::{
11 self,
12 price_update::Price,
13};
14use std::convert::TryInto;
15
16use crate::{check::{check_account_key}, price_update::OriginSolanaPriceUpdateV2};
17
18pub const PYTH_SOL_USD_FEED: Pubkey = pubkey!("7UVimffxr9ow1uXYxsr4LHAcV58mLzhmwaeKvJ1pjLiE");
19
20pub const PRICE_FEED_DISCRIMATOR: [u8; 8] = [34, 241, 35, 99, 157, 126, 244, 205];
21
22pub fn parse_price(data: &[u8]) -> Result<OriginSolanaPriceUpdateV2, ProgramError> {
28 let suffix = &data[..8];
30 if suffix != PRICE_FEED_DISCRIMATOR {
31 msg!("discrimator err");
32 return Err(ProgramError::InvalidArgument);
33 }
34 msg!("discrimator OK");
35 let update = OriginSolanaPriceUpdateV2::new(data)?;
36
37 Ok(update)
38}
39
40pub fn get_oracle_price_fp32(
41 account: &AccountInfo,
42 clock: &Clock,
43 maximum_age: u64,
44) -> Result<u64, ProgramError> {
45 check_account_key(account, &PYTH_SOL_USD_FEED)?;
46 msg!("pyth account ok");
47
48 let data = &account.data.borrow();
49 let update = parse_price(data)?;
50 msg!("get the update ok");
51
52 msg!("max age: {:?}", maximum_age);
53
54 let actual_feed_id = update.0.price_message.feed_id;
55
56 let Price { price, exponent, .. } = update.0
57 .get_price_no_older_than(clock, maximum_age, &actual_feed_id)
58 .map_err(|e| {
59 msg!("pyth error: {:?}", e);
60 ProgramError::InvalidArgument
61 })?;
62 msg!("get the price ok");
63
64 let price = if exponent > 0 {
65 ((price as u128) << 32) * 10u128.pow(exponent as u32)
66 } else {
67 ((price as u128) << 32) / 10u128.pow((-exponent) as u32)
68 };
69
70 let corrected_price = (price * 10u128.pow(6)) / 10u128.pow(9);
71
72 let final_price: u64 = corrected_price
73 .try_into()
74 .map_err(|_| ProgramError::InvalidArgument)?;
75 msg!("get the correct price ok");
76
77 msg!("Pyth SOL/USD FP32 price: {:?}", final_price);
78
79 Ok(final_price)
80}
81
82
83pub fn get_domain_price_sol(
84 domain_price_usd: u64,
85 sol_pyth_feed_account: &AccountInfo,
86) -> Result<u64, ProgramError> {
87
88 let clock = Clock::get()
89 .map_err(|_| ProgramError::InvalidArgument)?;
90 msg!("get clock ok");
91
92 #[cfg(feature="devnet")]
93 let query_deviation = 60000;
94 #[cfg(not(feature="devnet"))]
95 let query_deviation = 60;
96
97 msg!("now the deviation: {:?}", query_deviation);
98
99 let sol_price = get_oracle_price_fp32(
100 &sol_pyth_feed_account, &clock, query_deviation)
101 .map_err(|_| ProgramError::InvalidArgument)?;
102
103 Ok(domain_price_usd * sol_price)
104}