gmsol/store/
token_config.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::{PriceProviderKind, UpdateTokenConfigParams},
11};
12
13use crate::utils::view;
14
15/// Token Config.
16#[derive(Debug)]
17pub struct TokenConfig {
18    name: String,
19    is_enabled: bool,
20    decimals: u8,
21    precision: u8,
22    expected_provider: PriceProviderKind,
23}
24
25impl TokenConfig {
26    /// Get name.
27    pub fn name(&self) -> &str {
28        &self.name
29    }
30
31    /// Get token decimals.
32    pub fn decimals(&self) -> u8 {
33        self.decimals
34    }
35
36    /// Get price precision.
37    pub fn precision(&self) -> u8 {
38        self.precision
39    }
40
41    /// Get expected price provider.
42    pub fn expected_provider(&self) -> PriceProviderKind {
43        self.expected_provider
44    }
45
46    /// Get is enabled.
47    pub fn is_enabled(&self) -> bool {
48        self.is_enabled
49    }
50}
51
52/// Token config management for GMSOL.
53pub trait TokenConfigOps<C> {
54    /// Initialize a  `TokenMap` account.
55    fn initialize_token_map<'a>(
56        &'a self,
57        store: &Pubkey,
58        token_map: &'a dyn Signer,
59    ) -> (TransactionBuilder<'a, C>, Pubkey);
60
61    /// Insert or update config for the given token.
62    #[allow(clippy::too_many_arguments)]
63    fn insert_token_config(
64        &self,
65        store: &Pubkey,
66        token_map: &Pubkey,
67        name: &str,
68        token: &Pubkey,
69        builder: UpdateTokenConfigParams,
70        enable: bool,
71        new: bool,
72    ) -> TransactionBuilder<C>;
73
74    /// Insert or update config the given synthetic token.
75    // FIXME: reduce the number of args.
76    #[allow(clippy::too_many_arguments)]
77    fn insert_synthetic_token_config(
78        &self,
79        store: &Pubkey,
80        token_map: &Pubkey,
81        name: &str,
82        token: &Pubkey,
83        decimals: u8,
84        builder: UpdateTokenConfigParams,
85        enable: bool,
86        new: bool,
87    ) -> TransactionBuilder<C>;
88
89    /// Toggle token config.
90    fn toggle_token_config(
91        &self,
92        store: &Pubkey,
93        token_map: &Pubkey,
94        token: &Pubkey,
95        enable: bool,
96    ) -> TransactionBuilder<C>;
97
98    /// Set expected provider.
99    fn set_expected_provider(
100        &self,
101        store: &Pubkey,
102        token_map: &Pubkey,
103        token: &Pubkey,
104        provider: PriceProviderKind,
105    ) -> TransactionBuilder<C>;
106
107    /// Get the name for the given token.
108    fn token_name(&self, token_map: &Pubkey, token: &Pubkey) -> TransactionBuilder<C>;
109
110    /// Get the token decimals for the given token.
111    fn token_decimals(&self, token_map: &Pubkey, token: &Pubkey) -> TransactionBuilder<C>;
112
113    /// Get the price precision for the given token.
114    fn token_precision(&self, token_map: &Pubkey, token: &Pubkey) -> TransactionBuilder<C>;
115
116    /// Check if the config of the given token is enbaled.
117    fn is_token_config_enabled(&self, token_map: &Pubkey, token: &Pubkey) -> TransactionBuilder<C>;
118
119    /// Get expected provider for the given token.
120    fn token_expected_provider(&self, token_map: &Pubkey, token: &Pubkey) -> TransactionBuilder<C>;
121
122    /// Get feed address of the provider of the given token.
123    fn token_feed(
124        &self,
125        token_map: &Pubkey,
126        token: &Pubkey,
127        provider: PriceProviderKind,
128    ) -> TransactionBuilder<C>;
129
130    /// Get timestamp adjustment of the given token and provider.
131    fn token_timestamp_adjustment(
132        &self,
133        token_map: &Pubkey,
134        token: &Pubkey,
135        provider: PriceProviderKind,
136    ) -> TransactionBuilder<C>;
137
138    /// Get basic token config.
139    fn token_config(
140        &self,
141        token_map: &Pubkey,
142        token: &Pubkey,
143    ) -> impl Future<Output = crate::Result<TokenConfig>>;
144}
145
146impl<C, S> TokenConfigOps<C> for crate::Client<C>
147where
148    C: Deref<Target = S> + Clone,
149    S: Signer,
150{
151    fn initialize_token_map<'a>(
152        &'a self,
153        store: &Pubkey,
154        token_map: &'a dyn Signer,
155    ) -> (TransactionBuilder<'a, C>, Pubkey) {
156        let builder = self
157            .store_transaction()
158            .anchor_accounts(accounts::InitializeTokenMap {
159                payer: self.payer(),
160                store: *store,
161                token_map: token_map.pubkey(),
162                system_program: system_program::ID,
163            })
164            .anchor_args(instruction::InitializeTokenMap {})
165            .signer(token_map);
166        (builder, token_map.pubkey())
167    }
168
169    fn insert_token_config(
170        &self,
171        store: &Pubkey,
172        token_map: &Pubkey,
173        name: &str,
174        token: &Pubkey,
175        builder: UpdateTokenConfigParams,
176        enable: bool,
177        new: bool,
178    ) -> TransactionBuilder<C> {
179        let authority = self.payer();
180        self.store_transaction()
181            .anchor_accounts(accounts::PushToTokenMap {
182                authority,
183                store: *store,
184                token_map: *token_map,
185                token: *token,
186                system_program: system_program::ID,
187            })
188            .anchor_args(instruction::PushToTokenMap {
189                name: name.to_owned(),
190                builder,
191                enable,
192                new,
193            })
194    }
195
196    fn insert_synthetic_token_config(
197        &self,
198        store: &Pubkey,
199        token_map: &Pubkey,
200        name: &str,
201        token: &Pubkey,
202        decimals: u8,
203        builder: UpdateTokenConfigParams,
204        enable: bool,
205        new: bool,
206    ) -> TransactionBuilder<C> {
207        let authority = self.payer();
208        self.store_transaction()
209            .anchor_accounts(accounts::PushToTokenMapSynthetic {
210                authority,
211                store: *store,
212                token_map: *token_map,
213                system_program: system_program::ID,
214            })
215            .anchor_args(instruction::PushToTokenMapSynthetic {
216                name: name.to_owned(),
217                token: *token,
218                token_decimals: decimals,
219                builder,
220                enable,
221                new,
222            })
223    }
224
225    fn toggle_token_config(
226        &self,
227        store: &Pubkey,
228        token_map: &Pubkey,
229        token: &Pubkey,
230        enable: bool,
231    ) -> TransactionBuilder<C> {
232        let authority = self.payer();
233        self.store_transaction()
234            .anchor_accounts(accounts::ToggleTokenConfig {
235                authority,
236                store: *store,
237                token_map: *token_map,
238            })
239            .anchor_args(instruction::ToggleTokenConfig {
240                token: *token,
241                enable,
242            })
243    }
244
245    fn set_expected_provider(
246        &self,
247        store: &Pubkey,
248        token_map: &Pubkey,
249        token: &Pubkey,
250        provider: PriceProviderKind,
251    ) -> TransactionBuilder<C> {
252        let authority = self.payer();
253        self.store_transaction()
254            .anchor_accounts(accounts::SetExpectedProvider {
255                authority,
256                store: *store,
257                token_map: *token_map,
258            })
259            .anchor_args(instruction::SetExpectedProvider {
260                token: *token,
261                provider: provider as u8,
262            })
263    }
264
265    fn token_name(&self, token_map: &Pubkey, token: &Pubkey) -> TransactionBuilder<C> {
266        self.store_transaction()
267            .anchor_args(instruction::TokenName { token: *token })
268            .anchor_accounts(accounts::ReadTokenMap {
269                token_map: *token_map,
270            })
271    }
272
273    fn token_decimals(&self, token_map: &Pubkey, token: &Pubkey) -> TransactionBuilder<C> {
274        self.store_transaction()
275            .anchor_args(instruction::TokenDecimals { token: *token })
276            .anchor_accounts(accounts::ReadTokenMap {
277                token_map: *token_map,
278            })
279    }
280
281    fn token_precision(&self, token_map: &Pubkey, token: &Pubkey) -> TransactionBuilder<C> {
282        self.store_transaction()
283            .anchor_args(instruction::TokenPrecision { token: *token })
284            .anchor_accounts(accounts::ReadTokenMap {
285                token_map: *token_map,
286            })
287    }
288
289    fn is_token_config_enabled(&self, token_map: &Pubkey, token: &Pubkey) -> TransactionBuilder<C> {
290        self.store_transaction()
291            .anchor_args(instruction::IsTokenConfigEnabled { token: *token })
292            .anchor_accounts(accounts::ReadTokenMap {
293                token_map: *token_map,
294            })
295    }
296
297    fn token_expected_provider(&self, token_map: &Pubkey, token: &Pubkey) -> TransactionBuilder<C> {
298        self.store_transaction()
299            .anchor_args(instruction::TokenExpectedProvider { token: *token })
300            .anchor_accounts(accounts::ReadTokenMap {
301                token_map: *token_map,
302            })
303    }
304
305    fn token_feed(
306        &self,
307        token_map: &Pubkey,
308        token: &Pubkey,
309        provider: PriceProviderKind,
310    ) -> TransactionBuilder<C> {
311        self.store_transaction()
312            .anchor_args(instruction::TokenFeed {
313                token: *token,
314                provider: provider as u8,
315            })
316            .anchor_accounts(accounts::ReadTokenMap {
317                token_map: *token_map,
318            })
319    }
320
321    fn token_timestamp_adjustment(
322        &self,
323        token_map: &Pubkey,
324        token: &Pubkey,
325        provider: PriceProviderKind,
326    ) -> TransactionBuilder<C> {
327        self.store_transaction()
328            .anchor_args(instruction::TokenTimestampAdjustment {
329                token: *token,
330                provider: provider as u8,
331            })
332            .anchor_accounts(accounts::ReadTokenMap {
333                token_map: *token_map,
334            })
335    }
336
337    async fn token_config(&self, token_map: &Pubkey, token: &Pubkey) -> crate::Result<TokenConfig> {
338        let client = self.store_program().rpc();
339        let name = self
340            .token_name(token_map, token)
341            .signed_transaction_with_options(true, None)
342            .await?;
343        let token_decimals = self
344            .token_decimals(token_map, token)
345            .signed_transaction_with_options(true, None)
346            .await?;
347        let precision = self
348            .token_precision(token_map, token)
349            .signed_transaction_with_options(true, None)
350            .await?;
351        let expected_provider = self
352            .token_expected_provider(token_map, token)
353            .signed_transaction_with_options(true, None)
354            .await?;
355        let is_enabled = self
356            .is_token_config_enabled(token_map, token)
357            .signed_transaction_with_options(true, None)
358            .await?;
359
360        Ok(TokenConfig {
361            name: view(&client, &name).await?,
362            decimals: view(&client, &token_decimals).await?,
363            precision: view(&client, &precision).await?,
364            expected_provider: view::<u8>(&client, &expected_provider)
365                .await?
366                .try_into()
367                .map_err(crate::Error::unknown)?,
368            is_enabled: view(&client, &is_enabled).await?,
369        })
370    }
371}