1use std::ops::Deref;
2
3use gmsol_programs::gmsol_store::client::{accounts, args};
4use gmsol_solana_utils::transaction_builder::TransactionBuilder;
5use gmsol_utils::{oracle::PriceProviderKind, token_config::UpdateTokenConfigParams};
6use solana_sdk::{pubkey::Pubkey, signer::Signer, system_program};
7
8use crate::{serde::StringPubkey, utils::Value};
9
10pub trait TokenConfigOps<C> {
12 fn initialize_token_map<'a>(
14 &'a self,
15 store: &Pubkey,
16 token_map: &'a dyn Signer,
17 ) -> (TransactionBuilder<'a, C>, Pubkey);
18
19 #[allow(clippy::too_many_arguments)]
21 fn insert_token_config(
22 &self,
23 store: &Pubkey,
24 token_map: &Pubkey,
25 name: &str,
26 token: &Pubkey,
27 builder: UpdateTokenConfigParams,
28 enable: bool,
29 new: bool,
30 ) -> TransactionBuilder<C>;
31
32 #[allow(clippy::too_many_arguments)]
34 fn insert_synthetic_token_config(
35 &self,
36 store: &Pubkey,
37 token_map: &Pubkey,
38 name: &str,
39 token: &Pubkey,
40 decimals: u8,
41 builder: UpdateTokenConfigParams,
42 enable: bool,
43 new: bool,
44 ) -> TransactionBuilder<C>;
45
46 fn toggle_token_config(
48 &self,
49 store: &Pubkey,
50 token_map: &Pubkey,
51 token: &Pubkey,
52 enable: bool,
53 ) -> TransactionBuilder<C>;
54
55 fn toggle_token_price_adjustment(
57 &self,
58 store: &Pubkey,
59 token_map: &Pubkey,
60 token: &Pubkey,
61 enable: bool,
62 ) -> TransactionBuilder<C>;
63
64 fn set_expected_provider(
66 &self,
67 store: &Pubkey,
68 token_map: &Pubkey,
69 token: &Pubkey,
70 provider: PriceProviderKind,
71 ) -> TransactionBuilder<C>;
72
73 fn update_feed_config(
75 &self,
76 store: &Pubkey,
77 token_map: &Pubkey,
78 token: &Pubkey,
79 provider: PriceProviderKind,
80 update: UpdateFeedConfig,
81 ) -> crate::Result<TransactionBuilder<C>>;
82}
83
84impl<C: Deref<Target = impl Signer> + Clone> TokenConfigOps<C> for crate::Client<C> {
85 fn initialize_token_map<'a>(
86 &'a self,
87 store: &Pubkey,
88 token_map: &'a dyn Signer,
89 ) -> (TransactionBuilder<'a, C>, Pubkey) {
90 let builder = self
91 .store_transaction()
92 .anchor_accounts(accounts::InitializeTokenMap {
93 payer: self.payer(),
94 store: *store,
95 token_map: token_map.pubkey(),
96 system_program: system_program::ID,
97 })
98 .anchor_args(args::InitializeTokenMap {})
99 .signer(token_map);
100 (builder, token_map.pubkey())
101 }
102
103 fn insert_token_config(
104 &self,
105 store: &Pubkey,
106 token_map: &Pubkey,
107 name: &str,
108 token: &Pubkey,
109 builder: UpdateTokenConfigParams,
110 enable: bool,
111 new: bool,
112 ) -> TransactionBuilder<C> {
113 let authority = self.payer();
114 self.store_transaction()
115 .anchor_accounts(accounts::PushToTokenMap {
116 authority,
117 store: *store,
118 token_map: *token_map,
119 token: *token,
120 system_program: system_program::ID,
121 })
122 .anchor_args(args::PushToTokenMap {
123 name: name.to_owned(),
124 builder: builder.into(),
125 enable,
126 new,
127 })
128 }
129
130 fn insert_synthetic_token_config(
131 &self,
132 store: &Pubkey,
133 token_map: &Pubkey,
134 name: &str,
135 token: &Pubkey,
136 decimals: u8,
137 builder: UpdateTokenConfigParams,
138 enable: bool,
139 new: bool,
140 ) -> TransactionBuilder<C> {
141 let authority = self.payer();
142 self.store_transaction()
143 .anchor_accounts(accounts::PushToTokenMapSynthetic {
144 authority,
145 store: *store,
146 token_map: *token_map,
147 system_program: system_program::ID,
148 })
149 .anchor_args(args::PushToTokenMapSynthetic {
150 name: name.to_owned(),
151 token: *token,
152 token_decimals: decimals,
153 builder: builder.into(),
154 enable,
155 new,
156 })
157 }
158
159 fn toggle_token_config(
160 &self,
161 store: &Pubkey,
162 token_map: &Pubkey,
163 token: &Pubkey,
164 enable: bool,
165 ) -> TransactionBuilder<C> {
166 let authority = self.payer();
167 self.store_transaction()
168 .anchor_accounts(accounts::ToggleTokenConfig {
169 authority,
170 store: *store,
171 token_map: *token_map,
172 })
173 .anchor_args(args::ToggleTokenConfig {
174 token: *token,
175 enable,
176 })
177 }
178
179 fn toggle_token_price_adjustment(
180 &self,
181 store: &Pubkey,
182 token_map: &Pubkey,
183 token: &Pubkey,
184 enable: bool,
185 ) -> TransactionBuilder<C> {
186 let authority = self.payer();
187 self.store_transaction()
188 .anchor_accounts(accounts::ToggleTokenPriceAdjustment {
189 authority,
190 store: *store,
191 token_map: *token_map,
192 })
193 .anchor_args(args::ToggleTokenPriceAdjustment {
194 token: *token,
195 enable,
196 })
197 }
198
199 fn set_expected_provider(
200 &self,
201 store: &Pubkey,
202 token_map: &Pubkey,
203 token: &Pubkey,
204 provider: PriceProviderKind,
205 ) -> TransactionBuilder<C> {
206 let authority = self.payer();
207 self.store_transaction()
208 .anchor_accounts(accounts::SetExpectedProvider {
209 authority,
210 store: *store,
211 token_map: *token_map,
212 })
213 .anchor_args(args::SetExpectedProvider {
214 token: *token,
215 provider: provider as u8,
216 })
217 }
218
219 fn update_feed_config(
220 &self,
221 store: &Pubkey,
222 token_map: &Pubkey,
223 token: &Pubkey,
224 provider: PriceProviderKind,
225 update: UpdateFeedConfig,
226 ) -> crate::Result<TransactionBuilder<C>> {
227 let authority = self.payer();
228 let txn = self
229 .store_transaction()
230 .anchor_accounts(accounts::SetFeedConfigV2 {
231 authority,
232 store: *store,
233 token_map: *token_map,
234 })
235 .anchor_args(args::SetFeedConfigV2 {
236 token: *token,
237 provider: provider.into(),
238 feed: update.feed_id.map(|k| k.0),
239 timestamp_adjustment: update.timestamp_adjustment,
240 max_deviation_factor: update
241 .max_deviation_factor
242 .map(|f| f.to_u128())
243 .transpose()?,
244 });
245 Ok(txn)
246 }
247}
248
249#[derive(typed_builder::TypedBuilder)]
251#[cfg_attr(serde, derive(serde::Serialize, serde::Deserialize))]
252pub struct UpdateFeedConfig {
253 #[builder(default)]
255 #[cfg_attr(serde, serde(default))]
256 pub feed_id: Option<StringPubkey>,
257 #[builder(default)]
259 #[cfg_attr(serde, serde(default))]
260 pub timestamp_adjustment: Option<u32>,
261 #[builder(default)]
263 #[cfg_attr(serde, serde(default))]
264 pub max_deviation_factor: Option<Value>,
265}