gmsol/store/
oracle.rs

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