gmsol_store/instructions/
store.rs1use anchor_lang::prelude::*;
2use gmsol_utils::{to_seed, InitSpace};
3
4use crate::{
5 states::{Seed, Store, TokenMapHeader},
6 utils::internal,
7 CoreError,
8};
9
10#[derive(Accounts)]
12#[instruction(key: String)]
13pub struct Initialize<'info> {
14 #[account(mut)]
16 pub payer: Signer<'info>,
17 pub authority: Option<Signer<'info>>,
21 pub receiver: Option<Signer<'info>>,
25 pub holding: Option<Signer<'info>>,
29 #[account(
33 init,
34 payer = payer,
35 space = 8 + Store::INIT_SPACE,
36 seeds = [Store::SEED, &to_seed(&key)],
37 bump,
38 )]
39 pub store: AccountLoader<'info, Store>,
40 pub system_program: Program<'info, System>,
42}
43
44pub(crate) fn initialize(ctx: Context<Initialize>, key: String) -> Result<()> {
45 ctx.accounts.validate_key(&key)?;
46
47 let mut store = ctx.accounts.store.load_init()?;
48 let authority = ctx
49 .accounts
50 .authority
51 .as_ref()
52 .map(|a| a.key())
53 .unwrap_or(ctx.accounts.payer.key());
54 let receiver = ctx
55 .accounts
56 .receiver
57 .as_ref()
58 .map(|a| a.key())
59 .unwrap_or(authority);
60 let holding = ctx
61 .accounts
62 .holding
63 .as_ref()
64 .map(|a| a.key())
65 .unwrap_or(authority);
66 store.init(authority, &key, ctx.bumps.store, receiver, holding)?;
67 Ok(())
68}
69
70impl Initialize<'_> {
71 fn validate_key(&self, key: &str) -> Result<()> {
72 #[cfg(not(feature = "multi-store"))]
73 require!(key.is_empty(), CoreError::NonDefaultStore);
74
75 msg!("initializing a new store with key = {}", key);
76 Ok(())
77 }
78}
79
80#[derive(Accounts)]
83pub struct UpdateLastRestartedSlot<'info> {
84 pub authority: Signer<'info>,
86 #[account(mut)]
88 pub store: AccountLoader<'info, Store>,
89}
90
91pub(crate) fn update_last_restarted_slot(ctx: Context<UpdateLastRestartedSlot>) -> Result<()> {
93 let slot = ctx
94 .accounts
95 .store
96 .load_mut()?
97 .update_last_restarted_slot(true)?;
98 msg!("[Store] the last_restarted_slot is now {}", slot);
99 Ok(())
100}
101
102impl<'info> internal::Authentication<'info> for UpdateLastRestartedSlot<'info> {
103 fn authority(&self) -> &Signer<'info> {
104 &self.authority
105 }
106
107 fn store(&self) -> &AccountLoader<'info, Store> {
108 &self.store
109 }
110}
111
112#[derive(Accounts)]
115pub struct TransferStoreAuthority<'info> {
116 pub authority: Signer<'info>,
118 #[account(mut)]
120 pub store: AccountLoader<'info, Store>,
121 pub next_authority: UncheckedAccount<'info>,
124}
125
126pub(crate) fn unchecked_transfer_store_authority(
131 ctx: Context<TransferStoreAuthority>,
132) -> Result<()> {
133 ctx.accounts
134 .store
135 .load_mut()?
136 .set_next_authority(ctx.accounts.next_authority.key)?;
137 msg!(
138 "[Store] the next_authority is now {}",
139 ctx.accounts.next_authority.key
140 );
141 Ok(())
142}
143
144impl<'info> internal::Authentication<'info> for TransferStoreAuthority<'info> {
145 fn authority(&self) -> &Signer<'info> {
146 &self.authority
147 }
148
149 fn store(&self) -> &AccountLoader<'info, Store> {
150 &self.store
151 }
152}
153
154#[derive(Accounts)]
157pub struct AcceptStoreAuthority<'info> {
158 pub next_authority: Signer<'info>,
160 #[account(mut, has_one = next_authority)]
162 pub store: AccountLoader<'info, Store>,
163}
164
165pub(crate) fn accept_store_authority(ctx: Context<AcceptStoreAuthority>) -> Result<()> {
166 let authority = ctx
167 .accounts
168 .store
169 .load_mut()?
170 .validate_not_restarted_mut()?
171 .update_authority()?;
172 msg!("[Store] the authority is now {}", authority);
173 Ok(())
174}
175
176#[derive(Accounts)]
178pub struct TransferReceiver<'info> {
179 #[account(
181 constraint = authority.key() == store.load()?.receiver() @ CoreError::PermissionDenied,
182 )]
183 pub authority: Signer<'info>,
184 #[account(mut)]
186 pub store: AccountLoader<'info, Store>,
187 pub next_receiver: UncheckedAccount<'info>,
190}
191
192pub(crate) fn transfer_receiver(ctx: Context<TransferReceiver>) -> Result<()> {
193 ctx.accounts
194 .store
195 .load_mut()?
196 .validate_not_restarted_mut()?
197 .set_next_receiver(ctx.accounts.next_receiver.key)?;
198 msg!(
199 "[Treasury] the next_receiver is now {}",
200 ctx.accounts.next_receiver.key
201 );
202 Ok(())
203}
204
205#[derive(Accounts)]
207pub struct AcceptReceiver<'info> {
208 #[account(
210 constraint = next_receiver.key() == store.load()?.next_receiver() @ CoreError::PermissionDenied,
211 )]
212 pub next_receiver: Signer<'info>,
213 #[account(mut)]
215 pub store: AccountLoader<'info, Store>,
216}
217
218pub(crate) fn accept_receiver(ctx: Context<AcceptReceiver>) -> Result<()> {
219 let receiver = ctx
220 .accounts
221 .store
222 .load_mut()?
223 .validate_not_restarted_mut()?
224 .update_receiver()?;
225 msg!("[Treasury] the receiver is now {}", receiver);
226 Ok(())
227}
228
229#[derive(Accounts)]
231pub struct SetTokenMap<'info> {
232 pub authority: Signer<'info>,
234 #[account(mut)]
236 pub store: AccountLoader<'info, Store>,
237 #[account(has_one = store)]
239 pub token_map: AccountLoader<'info, TokenMapHeader>,
240}
241
242pub(crate) fn unchecked_set_token_map(ctx: Context<SetTokenMap>) -> Result<()> {
247 ctx.accounts.store.load_mut()?.token_map = ctx.accounts.token_map.key();
248 Ok(())
249}
250
251impl<'info> internal::Authentication<'info> for SetTokenMap<'info> {
252 fn authority(&self) -> &Signer<'info> {
253 &self.authority
254 }
255
256 fn store(&self) -> &AccountLoader<'info, Store> {
257 &self.store
258 }
259}
260
261#[derive(Accounts)]
262pub struct ReadStore<'info> {
263 pub store: AccountLoader<'info, Store>,
264}
265
266pub(crate) fn _get_token_map(ctx: Context<ReadStore>) -> Result<Option<Pubkey>> {
268 Ok(ctx
269 .accounts
270 .store
271 .load()?
272 .validate_not_restarted()?
273 .token_map()
274 .copied())
275}