1use std::{future::Future, ops::Deref};
2
3use crate::utils::ZeroCopy;
4use anchor_client::{
5 anchor_lang::system_program,
6 solana_sdk::{pubkey::Pubkey, signer::Signer},
7};
8use gmsol_solana_utils::transaction_builder::TransactionBuilder;
9use gmsol_store::{
10 accounts, instruction,
11 states::gt::{get_time_window_index, GtExchange},
12};
13
14pub trait GtOps<C> {
16 fn initialize_gt(
18 &self,
19 store: &Pubkey,
20 decimals: u8,
21 initial_minting_cost: u128,
22 grow_factor: u128,
23 grow_step: u64,
24 ranks: Vec<u64>,
25 ) -> TransactionBuilder<C>;
26
27 fn gt_set_order_fee_discount_factors(
29 &self,
30 store: &Pubkey,
31 factors: Vec<u128>,
32 ) -> TransactionBuilder<C>;
33
34 fn gt_set_referral_reward_factors(
36 &self,
37 store: &Pubkey,
38 factors: Vec<u128>,
39 ) -> TransactionBuilder<C>;
40
41 fn gt_set_exchange_time_window(&self, store: &Pubkey, window: u32) -> TransactionBuilder<C>;
43
44 fn prepare_gt_exchange_vault_with_time_window_index(
46 &self,
47 store: &Pubkey,
48 time_window_index: i64,
49 time_window: u32,
50 ) -> TransactionBuilder<C, Pubkey>;
51
52 fn prepare_gt_exchange_vault_with_time_window(
54 &self,
55 store: &Pubkey,
56 time_window: u32,
57 ) -> crate::Result<TransactionBuilder<C, Pubkey>> {
58 Ok(self.prepare_gt_exchange_vault_with_time_window_index(
59 store,
60 current_time_window_index(time_window)?,
61 time_window,
62 ))
63 }
64
65 fn confirm_gt_exchange_vault(&self, store: &Pubkey, vault: &Pubkey) -> TransactionBuilder<C>;
67
68 fn request_gt_exchange_with_time_window_index(
70 &self,
71 store: &Pubkey,
72 time_window_index: i64,
73 time_window: u32,
74 amount: u64,
75 ) -> TransactionBuilder<C>;
76
77 fn request_gt_exchange_with_time_window(
79 &self,
80 store: &Pubkey,
81 time_window: u32,
82 amount: u64,
83 ) -> crate::Result<TransactionBuilder<C>> {
84 Ok(self.request_gt_exchange_with_time_window_index(
85 store,
86 current_time_window_index(time_window)?,
87 time_window,
88 amount,
89 ))
90 }
91
92 fn close_gt_exchange(
94 &self,
95 store: &Pubkey,
96 exchange: &Pubkey,
97 hint_owner: Option<&Pubkey>,
98 hint_vault: Option<&Pubkey>,
99 ) -> impl Future<Output = crate::Result<TransactionBuilder<C>>>;
100}
101
102impl<C: Deref<Target = impl Signer> + Clone> GtOps<C> for crate::Client<C> {
103 fn initialize_gt(
104 &self,
105 store: &Pubkey,
106 decimals: u8,
107 initial_minting_cost: u128,
108 grow_factor: u128,
109 grow_step: u64,
110 ranks: Vec<u64>,
111 ) -> TransactionBuilder<C> {
112 self.store_transaction()
113 .anchor_accounts(accounts::InitializeGt {
114 authority: self.payer(),
115 store: *store,
116 system_program: system_program::ID,
117 })
118 .anchor_args(instruction::InitializeGt {
119 decimals,
120 initial_minting_cost,
121 grow_factor,
122 grow_step,
123 ranks,
124 })
125 }
126
127 fn gt_set_order_fee_discount_factors(
128 &self,
129 store: &Pubkey,
130 factors: Vec<u128>,
131 ) -> TransactionBuilder<C> {
132 self.store_transaction()
133 .anchor_accounts(accounts::ConfigurateGt {
134 authority: self.payer(),
135 store: *store,
136 })
137 .anchor_args(instruction::GtSetOrderFeeDiscountFactors { factors })
138 }
139
140 fn gt_set_referral_reward_factors(
141 &self,
142 store: &Pubkey,
143 factors: Vec<u128>,
144 ) -> TransactionBuilder<C> {
145 self.store_transaction()
146 .anchor_accounts(accounts::ConfigurateGt {
147 authority: self.payer(),
148 store: *store,
149 })
150 .anchor_args(instruction::GtSetReferralRewardFactors { factors })
151 }
152
153 fn gt_set_exchange_time_window(&self, store: &Pubkey, window: u32) -> TransactionBuilder<C> {
154 self.store_transaction()
155 .anchor_accounts(accounts::ConfigurateGt {
156 authority: self.payer(),
157 store: *store,
158 })
159 .anchor_args(instruction::GtSetExchangeTimeWindow { window })
160 }
161
162 fn prepare_gt_exchange_vault_with_time_window_index(
163 &self,
164 store: &Pubkey,
165 time_window_index: i64,
166 time_window: u32,
167 ) -> TransactionBuilder<C, Pubkey> {
168 let vault = self.find_gt_exchange_vault_address(store, time_window_index, time_window);
169 self.store_transaction()
170 .anchor_accounts(accounts::PrepareGtExchangeVault {
171 payer: self.payer(),
172 store: *store,
173 vault,
174 system_program: system_program::ID,
175 })
176 .anchor_args(instruction::PrepareGtExchangeVault { time_window_index })
177 .output(vault)
178 }
179
180 fn confirm_gt_exchange_vault(&self, store: &Pubkey, vault: &Pubkey) -> TransactionBuilder<C> {
181 self.store_transaction()
182 .anchor_accounts(accounts::ConfirmGtExchangeVault {
183 authority: self.payer(),
184 store: *store,
185 vault: *vault,
186 event_authority: self.store_event_authority(),
187 program: *self.store_program_id(),
188 })
189 .anchor_args(instruction::ConfirmGtExchangeVault {})
190 }
191
192 fn request_gt_exchange_with_time_window_index(
193 &self,
194 store: &Pubkey,
195 time_window_index: i64,
196 time_window: u32,
197 amount: u64,
198 ) -> TransactionBuilder<C> {
199 let owner = self.payer();
200 let vault = self.find_gt_exchange_vault_address(store, time_window_index, time_window);
201 self.store_transaction()
202 .anchor_accounts(accounts::RequestGtExchange {
203 owner,
204 store: *store,
205 user: self.find_user_address(store, &owner),
206 vault,
207 exchange: self.find_gt_exchange_address(&vault, &owner),
208 system_program: system_program::ID,
209 event_authority: self.store_event_authority(),
210 program: *self.store_program_id(),
211 })
212 .anchor_args(instruction::RequestGtExchange { amount })
213 }
214
215 async fn close_gt_exchange(
216 &self,
217 store: &Pubkey,
218 exchange: &Pubkey,
219 hint_owner: Option<&Pubkey>,
220 hint_vault: Option<&Pubkey>,
221 ) -> crate::Result<TransactionBuilder<C>> {
222 let (owner, vault) = match (hint_owner, hint_vault) {
223 (Some(owner), Some(vault)) => (*owner, *vault),
224 _ => {
225 let exchange = self
226 .account::<ZeroCopy<GtExchange>>(exchange)
227 .await?
228 .ok_or(crate::Error::NotFound)?
229 .0;
230 (*exchange.owner(), *exchange.vault())
231 }
232 };
233
234 Ok(self
235 .store_transaction()
236 .anchor_accounts(accounts::CloseGtExchange {
237 authority: self.payer(),
238 store: *store,
239 owner,
240 vault,
241 exchange: *exchange,
242 })
243 .anchor_args(instruction::CloseGtExchange {}))
244 }
245}
246
247pub fn current_time_window_index(time_window: u32) -> crate::Result<i64> {
249 use std::time::SystemTime;
250 let now = SystemTime::now()
251 .duration_since(SystemTime::UNIX_EPOCH)
252 .map_err(crate::Error::invalid_argument)?;
253
254 let ts = now.as_secs() as i64;
255 Ok(get_time_window_index(ts, time_window as i64))
256}