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#[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 pub fn name(&self) -> &str {
28 &self.name
29 }
30
31 pub fn decimals(&self) -> u8 {
33 self.decimals
34 }
35
36 pub fn precision(&self) -> u8 {
38 self.precision
39 }
40
41 pub fn expected_provider(&self) -> PriceProviderKind {
43 self.expected_provider
44 }
45
46 pub fn is_enabled(&self) -> bool {
48 self.is_enabled
49 }
50}
51
52pub trait TokenConfigOps<C> {
54 fn initialize_token_map<'a>(
56 &'a self,
57 store: &Pubkey,
58 token_map: &'a dyn Signer,
59 ) -> (TransactionBuilder<'a, C>, Pubkey);
60
61 #[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 #[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 fn toggle_token_config(
91 &self,
92 store: &Pubkey,
93 token_map: &Pubkey,
94 token: &Pubkey,
95 enable: bool,
96 ) -> TransactionBuilder<C>;
97
98 fn set_expected_provider(
100 &self,
101 store: &Pubkey,
102 token_map: &Pubkey,
103 token: &Pubkey,
104 provider: PriceProviderKind,
105 ) -> TransactionBuilder<C>;
106
107 fn token_name(&self, token_map: &Pubkey, token: &Pubkey) -> TransactionBuilder<C>;
109
110 fn token_decimals(&self, token_map: &Pubkey, token: &Pubkey) -> TransactionBuilder<C>;
112
113 fn token_precision(&self, token_map: &Pubkey, token: &Pubkey) -> TransactionBuilder<C>;
115
116 fn is_token_config_enabled(&self, token_map: &Pubkey, token: &Pubkey) -> TransactionBuilder<C>;
118
119 fn token_expected_provider(&self, token_map: &Pubkey, token: &Pubkey) -> TransactionBuilder<C>;
121
122 fn token_feed(
124 &self,
125 token_map: &Pubkey,
126 token: &Pubkey,
127 provider: PriceProviderKind,
128 ) -> TransactionBuilder<C>;
129
130 fn token_timestamp_adjustment(
132 &self,
133 token_map: &Pubkey,
134 token: &Pubkey,
135 provider: PriceProviderKind,
136 ) -> TransactionBuilder<C>;
137
138 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}