gmsol/store/
gt.rs

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
14/// GT Operations.
15pub trait GtOps<C> {
16    /// Initialize GT Mint.
17    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    /// Configurate GT order fee dicounts.
28    fn gt_set_order_fee_discount_factors(
29        &self,
30        store: &Pubkey,
31        factors: Vec<u128>,
32    ) -> TransactionBuilder<C>;
33
34    /// Configurate GT referral rewards
35    fn gt_set_referral_reward_factors(
36        &self,
37        store: &Pubkey,
38        factors: Vec<u128>,
39    ) -> TransactionBuilder<C>;
40
41    /// Configurate the time window size for GT exchange.
42    fn gt_set_exchange_time_window(&self, store: &Pubkey, window: u32) -> TransactionBuilder<C>;
43
44    /// Initialize GT exchange vault with the given time window index.
45    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    /// Prepare GT exchange vault with the given time window.
53    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    /// Confirm the given GT exchange vault.
66    fn confirm_gt_exchange_vault(&self, store: &Pubkey, vault: &Pubkey) -> TransactionBuilder<C>;
67
68    /// Request GT exchange with the given time window index.
69    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    /// Request GT exchange with the given time window.
78    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    /// Close a confirmed GT exchange.
93    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
247/// Get current time window index.
248pub 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}