gmsol_sdk/client/ops/
oracle.rs

1use std::{future::Future, ops::Deref};
2
3use gmsol_programs::gmsol_store::{
4    accounts::Oracle,
5    client::{accounts, args},
6};
7use gmsol_solana_utils::transaction_builder::TransactionBuilder;
8use gmsol_utils::oracle::PriceProviderKind;
9use solana_sdk::{
10    pubkey::Pubkey, signer::Signer, system_instruction::create_account, system_program,
11};
12
13/// Operations for oracle management.
14pub trait OracleOps<C> {
15    /// Initialize [`Oracle`] account.
16    fn initialize_oracle<'a>(
17        &'a self,
18        store: &Pubkey,
19        oracle: &'a dyn Signer,
20        authority: Option<&Pubkey>,
21    ) -> impl Future<Output = crate::Result<(TransactionBuilder<'a, C>, Pubkey)>>;
22
23    /// Initialize Price Feed.
24    fn initialize_price_feed(
25        &self,
26        store: &Pubkey,
27        index: u16,
28        provider: PriceProviderKind,
29        token: &Pubkey,
30        feed_id: &Pubkey,
31    ) -> (TransactionBuilder<C>, Pubkey);
32
33    /// Update price feed with chainlink.
34    #[cfg(feature = "gmsol-chainlink-datastreams")]
35    fn update_price_feed_with_chainlink(
36        &self,
37        store: &Pubkey,
38        price_feed: &Pubkey,
39        chainlink: &Pubkey,
40        access_controller: &Pubkey,
41        signed_report: &[u8],
42    ) -> crate::Result<TransactionBuilder<C>>;
43}
44
45impl<C: Deref<Target = impl Signer> + Clone> OracleOps<C> for crate::Client<C> {
46    async fn initialize_oracle<'a>(
47        &'a self,
48        store: &Pubkey,
49        oracle: &'a dyn Signer,
50        authority: Option<&Pubkey>,
51    ) -> crate::Result<(TransactionBuilder<'a, C>, Pubkey)> {
52        let payer = self.payer();
53        let oracle_address = oracle.pubkey();
54
55        let size = 8 + std::mem::size_of::<Oracle>();
56        let lamports = self
57            .store_program()
58            .rpc()
59            .get_minimum_balance_for_rent_exemption(size)
60            .await
61            .map_err(crate::Error::custom)?;
62        let create = create_account(
63            &payer,
64            &oracle_address,
65            lamports,
66            size as u64,
67            self.store_program_id(),
68        );
69
70        let builder = self
71            .store_transaction()
72            .pre_instruction(create, false)
73            .anchor_accounts(accounts::InitializeOracle {
74                payer,
75                authority: authority.copied().unwrap_or(payer),
76                store: *store,
77                oracle: oracle_address,
78                system_program: system_program::ID,
79            })
80            .anchor_args(args::InitializeOracle {})
81            .signer(oracle);
82        Ok((builder, oracle_address))
83    }
84
85    fn initialize_price_feed(
86        &self,
87        store: &Pubkey,
88        index: u16,
89        provider: PriceProviderKind,
90        token: &Pubkey,
91        feed_id: &Pubkey,
92    ) -> (TransactionBuilder<C>, Pubkey) {
93        let authority = self.payer();
94        let price_feed = self.find_price_feed_address(store, &authority, index, provider, token);
95        let rpc = self
96            .store_transaction()
97            .anchor_accounts(accounts::InitializePriceFeed {
98                authority,
99                store: *store,
100                price_feed,
101                system_program: system_program::ID,
102            })
103            .anchor_args(args::InitializePriceFeed {
104                index,
105                provider: provider.into(),
106                token: *token,
107                feed_id: *feed_id,
108            });
109        (rpc, price_feed)
110    }
111
112    #[cfg(feature = "gmsol-chainlink-datastreams")]
113    fn update_price_feed_with_chainlink(
114        &self,
115        store: &Pubkey,
116        price_feed: &Pubkey,
117        chainlink: &Pubkey,
118        access_controller: &Pubkey,
119        signed_report: &[u8],
120    ) -> crate::Result<TransactionBuilder<C>> {
121        use gmsol_chainlink_datastreams::utils::{
122            find_config_account_pda, find_verifier_account_pda, Compressor,
123        };
124
125        let authority = self.payer();
126        let verifier_account = find_verifier_account_pda(chainlink);
127        let config_account = find_config_account_pda(signed_report, chainlink);
128        Ok(self
129            .store_transaction()
130            .anchor_accounts(accounts::UpdatePriceFeedWithChainlink {
131                authority,
132                store: *store,
133                verifier_account,
134                access_controller: *access_controller,
135                config_account,
136                price_feed: *price_feed,
137                chainlink: *chainlink,
138            })
139            .anchor_args(args::UpdatePriceFeedWithChainlink {
140                compressed_report: Compressor::compress(signed_report)
141                    .map_err(crate::Error::custom)?,
142            }))
143    }
144}