gmsol_sdk/client/ops/
gt.rs

1use std::{future::Future, ops::Deref};
2
3use gmsol_programs::gmsol_store::{
4    accounts::GtExchange,
5    client::{accounts, args},
6};
7use gmsol_solana_utils::{transaction_builder::TransactionBuilder, IntoAtomicGroup};
8use gmsol_utils::gt::get_time_window_index;
9use solana_sdk::{pubkey::Pubkey, signer::Signer, system_program};
10
11use crate::{builders::gt::MintGtReward, utils::zero_copy::ZeroCopy};
12
13/// GT Operations.
14pub trait GtOps<C> {
15    /// Initialize GT Mint.
16    fn initialize_gt(
17        &self,
18        store: &Pubkey,
19        decimals: u8,
20        initial_minting_cost: u128,
21        grow_factor: u128,
22        grow_step: u64,
23        ranks: Vec<u64>,
24    ) -> TransactionBuilder<C>;
25
26    /// Configurate GT order fee dicounts.
27    fn gt_set_order_fee_discount_factors(
28        &self,
29        store: &Pubkey,
30        factors: Vec<u128>,
31    ) -> TransactionBuilder<C>;
32
33    /// Configurate GT referral rewards
34    fn gt_set_referral_reward_factors(
35        &self,
36        store: &Pubkey,
37        factors: Vec<u128>,
38    ) -> TransactionBuilder<C>;
39
40    /// Configurate the time window size for GT exchange.
41    fn gt_set_exchange_time_window(&self, store: &Pubkey, window: u32) -> TransactionBuilder<C>;
42
43    /// Initialize GT exchange vault with the given time window index.
44    fn prepare_gt_exchange_vault_with_time_window_index(
45        &self,
46        store: &Pubkey,
47        time_window_index: i64,
48        time_window: u32,
49    ) -> TransactionBuilder<C, Pubkey>;
50
51    /// Prepare GT exchange vault with the given time window.
52    fn prepare_gt_exchange_vault_with_time_window(
53        &self,
54        store: &Pubkey,
55        time_window: u32,
56    ) -> crate::Result<TransactionBuilder<C, Pubkey>> {
57        Ok(self.prepare_gt_exchange_vault_with_time_window_index(
58            store,
59            current_time_window_index(time_window)?,
60            time_window,
61        ))
62    }
63
64    /// Confirm the given GT exchange vault.
65    fn confirm_gt_exchange_vault(
66        &self,
67        store: &Pubkey,
68        vault: &Pubkey,
69        buyback_value: u128,
70        buyback_price: Option<u128>,
71    ) -> TransactionBuilder<C>;
72
73    /// Request GT exchange with the given time window index.
74    fn request_gt_exchange_with_time_window_index(
75        &self,
76        store: &Pubkey,
77        time_window_index: i64,
78        time_window: u32,
79        amount: u64,
80    ) -> TransactionBuilder<C>;
81
82    /// Request GT exchange with the given time window.
83    fn request_gt_exchange_with_time_window(
84        &self,
85        store: &Pubkey,
86        time_window: u32,
87        amount: u64,
88    ) -> crate::Result<TransactionBuilder<C>> {
89        Ok(self.request_gt_exchange_with_time_window_index(
90            store,
91            current_time_window_index(time_window)?,
92            time_window,
93            amount,
94        ))
95    }
96
97    /// Close a confirmed GT exchange.
98    fn close_gt_exchange(
99        &self,
100        store: &Pubkey,
101        exchange: &Pubkey,
102        hint_owner: Option<&Pubkey>,
103        hint_vault: Option<&Pubkey>,
104    ) -> impl Future<Output = crate::Result<TransactionBuilder<C>>>;
105
106    /// Mint GT reward.
107    fn mint_gt_reward(
108        &self,
109        store: &Pubkey,
110        owner: &Pubkey,
111        amount: u64,
112    ) -> crate::Result<TransactionBuilder<C>>;
113}
114
115impl<C: Deref<Target = impl Signer> + Clone> GtOps<C> for crate::Client<C> {
116    fn initialize_gt(
117        &self,
118        store: &Pubkey,
119        decimals: u8,
120        initial_minting_cost: u128,
121        grow_factor: u128,
122        grow_step: u64,
123        ranks: Vec<u64>,
124    ) -> TransactionBuilder<C> {
125        self.store_transaction()
126            .anchor_accounts(accounts::InitializeGt {
127                authority: self.payer(),
128                store: *store,
129                system_program: system_program::ID,
130            })
131            .anchor_args(args::InitializeGt {
132                decimals,
133                initial_minting_cost,
134                grow_factor,
135                grow_step,
136                ranks,
137            })
138    }
139
140    fn gt_set_order_fee_discount_factors(
141        &self,
142        store: &Pubkey,
143        factors: Vec<u128>,
144    ) -> TransactionBuilder<C> {
145        self.store_transaction()
146            .anchor_accounts(accounts::GtSetOrderFeeDiscountFactors {
147                authority: self.payer(),
148                store: *store,
149            })
150            .anchor_args(args::GtSetOrderFeeDiscountFactors { factors })
151    }
152
153    fn gt_set_referral_reward_factors(
154        &self,
155        store: &Pubkey,
156        factors: Vec<u128>,
157    ) -> TransactionBuilder<C> {
158        self.store_transaction()
159            .anchor_accounts(accounts::GtSetReferralRewardFactors {
160                authority: self.payer(),
161                store: *store,
162            })
163            .anchor_args(args::GtSetReferralRewardFactors { factors })
164    }
165
166    fn gt_set_exchange_time_window(&self, store: &Pubkey, window: u32) -> TransactionBuilder<C> {
167        self.store_transaction()
168            .anchor_accounts(accounts::GtSetExchangeTimeWindow {
169                authority: self.payer(),
170                store: *store,
171            })
172            .anchor_args(args::GtSetExchangeTimeWindow { window })
173    }
174
175    fn prepare_gt_exchange_vault_with_time_window_index(
176        &self,
177        store: &Pubkey,
178        time_window_index: i64,
179        time_window: u32,
180    ) -> TransactionBuilder<C, Pubkey> {
181        let vault = self.find_gt_exchange_vault_address(store, time_window_index, time_window);
182        self.store_transaction()
183            .anchor_accounts(accounts::PrepareGtExchangeVault {
184                payer: self.payer(),
185                store: *store,
186                vault,
187                system_program: system_program::ID,
188            })
189            .anchor_args(args::PrepareGtExchangeVault { time_window_index })
190            .output(vault)
191    }
192
193    fn confirm_gt_exchange_vault(
194        &self,
195        store: &Pubkey,
196        vault: &Pubkey,
197        buyback_value: u128,
198        buyback_price: Option<u128>,
199    ) -> TransactionBuilder<C> {
200        self.store_transaction()
201            .anchor_accounts(accounts::ConfirmGtExchangeVaultV2 {
202                authority: self.payer(),
203                store: *store,
204                vault: *vault,
205                event_authority: self.store_event_authority(),
206                program: *self.store_program_id(),
207            })
208            .anchor_args(args::ConfirmGtExchangeVaultV2 {
209                buyback_value,
210                buyback_price,
211            })
212    }
213
214    fn request_gt_exchange_with_time_window_index(
215        &self,
216        store: &Pubkey,
217        time_window_index: i64,
218        time_window: u32,
219        amount: u64,
220    ) -> TransactionBuilder<C> {
221        let owner = self.payer();
222        let vault = self.find_gt_exchange_vault_address(store, time_window_index, time_window);
223        self.store_transaction()
224            .anchor_accounts(accounts::RequestGtExchange {
225                owner,
226                store: *store,
227                user: self.find_user_address(store, &owner),
228                vault,
229                exchange: self.find_gt_exchange_address(&vault, &owner),
230                system_program: system_program::ID,
231                event_authority: self.store_event_authority(),
232                program: *self.store_program_id(),
233            })
234            .anchor_args(args::RequestGtExchange { amount })
235    }
236
237    async fn close_gt_exchange(
238        &self,
239        store: &Pubkey,
240        exchange: &Pubkey,
241        hint_owner: Option<&Pubkey>,
242        hint_vault: Option<&Pubkey>,
243    ) -> crate::Result<TransactionBuilder<C>> {
244        let (owner, vault) = match (hint_owner, hint_vault) {
245            (Some(owner), Some(vault)) => (*owner, *vault),
246            _ => {
247                let exchange = self
248                    .account::<ZeroCopy<GtExchange>>(exchange)
249                    .await?
250                    .ok_or(crate::Error::NotFound)?
251                    .0;
252                (exchange.owner, exchange.vault)
253            }
254        };
255
256        Ok(self
257            .store_transaction()
258            .anchor_accounts(accounts::CloseGtExchange {
259                authority: self.payer(),
260                store: *store,
261                owner,
262                vault,
263                exchange: *exchange,
264            })
265            .anchor_args(args::CloseGtExchange {}))
266    }
267
268    fn mint_gt_reward(
269        &self,
270        store: &Pubkey,
271        owner: &Pubkey,
272        amount: u64,
273    ) -> crate::Result<TransactionBuilder<C>> {
274        Ok(self.store_transaction().pre_atomic_group(
275            MintGtReward::builder()
276                .amount(amount)
277                .payer(self.payer())
278                .owner((*owner).into())
279                .store_program(self.store_program_for_builders(store))
280                .build()
281                .into_atomic_group(&())?,
282            true,
283        ))
284    }
285}
286
287/// Get current time window index.
288pub fn current_time_window_index(time_window: u32) -> crate::Result<i64> {
289    use std::time::SystemTime;
290    let now = SystemTime::now()
291        .duration_since(SystemTime::UNIX_EPOCH)
292        .map_err(crate::Error::custom)?;
293
294    let ts = now.as_secs() as i64;
295    Ok(get_time_window_index(ts, time_window as i64))
296}