1use std::{ops::Deref, sync::Arc};
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::{Factor, FactorKey},
11};
12
13pub trait StoreOps<C> {
15 fn initialize_store<S: Signer + 'static>(
17 &self,
18 key: &str,
19 authority: Option<S>,
20 receiver: Option<S>,
21 holding: Option<S>,
22 ) -> TransactionBuilder<C>;
23
24 fn transfer_store_authority(
26 &self,
27 store: &Pubkey,
28 new_authority: &Pubkey,
29 ) -> TransactionBuilder<C>;
30
31 fn accept_store_authority(&self, store: &Pubkey) -> TransactionBuilder<C>;
33
34 fn transfer_receiver(&self, store: &Pubkey, new_receiver: &Pubkey) -> TransactionBuilder<C>;
36
37 fn set_token_map(&self, store: &Pubkey, token_map: &Pubkey) -> TransactionBuilder<C>;
39
40 fn insert_factor(
42 &self,
43 store: &Pubkey,
44 key: FactorKey,
45 factor: Factor,
46 ) -> TransactionBuilder<C>;
47}
48
49impl<C, S> StoreOps<C> for crate::Client<C>
50where
51 C: Deref<Target = S> + Clone,
52 S: Signer,
53{
54 fn initialize_store<S2: Signer + 'static>(
55 &self,
56 key: &str,
57 authority: Option<S2>,
58 receiver: Option<S2>,
59 holding: Option<S2>,
60 ) -> TransactionBuilder<C> {
61 let store = self.find_store_address(key);
62 let authority_address = authority.as_ref().map(|s| s.pubkey());
63 let receiver_address = receiver.as_ref().map(|s| s.pubkey());
64 let holding_address = holding.as_ref().map(|s| s.pubkey());
65 let mut rpc = self
66 .store_transaction()
67 .anchor_accounts(accounts::Initialize {
68 payer: self.payer(),
69 authority: authority_address,
70 receiver: receiver_address,
71 holding: holding_address,
72 store,
73 system_program: system_program::ID,
74 })
75 .anchor_args(instruction::Initialize {
76 key: key.to_string(),
77 });
78
79 for signer in authority.into_iter().chain(receiver).chain(holding) {
80 rpc = rpc.owned_signer(Arc::new(signer));
81 }
82
83 rpc
84 }
85
86 fn transfer_store_authority(
87 &self,
88 store: &Pubkey,
89 next_authority: &Pubkey,
90 ) -> TransactionBuilder<C> {
91 self.store_transaction()
92 .anchor_args(instruction::TransferStoreAuthority {})
93 .anchor_accounts(accounts::TransferStoreAuthority {
94 authority: self.payer(),
95 store: *store,
96 next_authority: *next_authority,
97 })
98 }
99
100 fn accept_store_authority(&self, store: &Pubkey) -> TransactionBuilder<C> {
101 self.store_transaction()
102 .anchor_args(instruction::AcceptStoreAuthority {})
103 .anchor_accounts(accounts::AcceptStoreAuthority {
104 next_authority: self.payer(),
105 store: *store,
106 })
107 }
108
109 fn transfer_receiver(&self, store: &Pubkey, new_receiver: &Pubkey) -> TransactionBuilder<C> {
110 self.store_transaction()
111 .anchor_args(instruction::TransferReceiver {})
112 .anchor_accounts(accounts::TransferReceiver {
113 authority: self.payer(),
114 store: *store,
115 next_receiver: *new_receiver,
116 })
117 }
118
119 fn set_token_map(&self, store: &Pubkey, token_map: &Pubkey) -> TransactionBuilder<C> {
120 self.store_transaction()
121 .anchor_args(instruction::SetTokenMap {})
122 .anchor_accounts(accounts::SetTokenMap {
123 authority: self.payer(),
124 store: *store,
125 token_map: *token_map,
126 })
127 }
128
129 fn insert_factor(
130 &self,
131 store: &Pubkey,
132 key: FactorKey,
133 factor: Factor,
134 ) -> TransactionBuilder<C> {
135 let rpc = self
136 .store_transaction()
137 .anchor_accounts(accounts::InsertConfig {
138 authority: self.payer(),
139 store: *store,
140 });
141 match key {
142 FactorKey::OrderFeeDiscountForReferredUser => {
143 rpc.anchor_args(instruction::InsertOrderFeeDiscountForReferredUser { factor })
144 }
145 _ => rpc.anchor_args(instruction::InsertFactor {
146 key: key.to_string(),
147 factor,
148 }),
149 }
150 }
151}