gmsol_store/instructions/
store.rs

1use 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/// The accounts definition for [`initialize`](crate::gmsol_store::initialize).
11#[derive(Accounts)]
12#[instruction(key: String)]
13pub struct Initialize<'info> {
14    /// The payer for the rent-exempt fee of the [`Store`] Account.
15    #[account(mut)]
16    pub payer: Signer<'info>,
17    /// The authority of the the [`Store`] account.
18    ///
19    /// If it is not specified, the `payer` will be set as the authority of this [`Store`] Account.
20    pub authority: Option<Signer<'info>>,
21    /// The receiver address of the the [`Store`] account.
22    ///
23    /// Defaults to the authority address.
24    pub receiver: Option<Signer<'info>>,
25    /// The holding address.
26    ///
27    /// Defaults to the authority address.
28    pub holding: Option<Signer<'info>>,
29    /// The account to be used for creating the [`Store`] Account.
30    /// Its address is a PDA derived from a constant [`SEED`](Store::SEED)
31    /// and a hashed key as the seeds.
32    #[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    /// The [`System`] program.
41    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/// The accounts definition for
81/// [`update_last_restarted_slot`](crate::gmsol_store::update_last_restarted_slot).
82#[derive(Accounts)]
83pub struct UpdateLastRestartedSlot<'info> {
84    /// The caller of this instruction.
85    pub authority: Signer<'info>,
86    /// The store account whose authority is to be transferred.
87    #[account(mut)]
88    pub store: AccountLoader<'info, Store>,
89}
90
91/// Update last restarted slot.
92pub(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/// The accounts definition for
113/// [`transfer_store_authority`](crate::gmsol_store::transfer_store_authority).
114#[derive(Accounts)]
115pub struct TransferStoreAuthority<'info> {
116    /// The caller of this instruction.
117    pub authority: Signer<'info>,
118    /// The store account whose authority is to be transferred.
119    #[account(mut)]
120    pub store: AccountLoader<'info, Store>,
121    /// Next authority address.
122    /// CHECK: only the address is used.
123    pub next_authority: UncheckedAccount<'info>,
124}
125
126/// Transfer the authority of the store to a new one.
127///
128/// ## CHECK
129/// - Only ADMIN can execute this instruction.
130pub(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/// The accounts definition for
155/// [`accept_store_authority`](crate::gmsol_store::accept_store_authority).
156#[derive(Accounts)]
157pub struct AcceptStoreAuthority<'info> {
158    /// The next authority.
159    pub next_authority: Signer<'info>,
160    /// The store account whose authority is being transferred.
161    #[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/// The accounts definition for [`transfer_receiver`](crate::gmsol_store::transfer_receiver).
177#[derive(Accounts)]
178pub struct TransferReceiver<'info> {
179    /// The caller of this instruction.
180    #[account(
181        constraint = authority.key() == store.load()?.receiver() @ CoreError::PermissionDenied,
182    )]
183    pub authority: Signer<'info>,
184    /// The store account whose receiver is to be transferred.
185    #[account(mut)]
186    pub store: AccountLoader<'info, Store>,
187    /// The new receiver.
188    /// CHECK: only the address is used.
189    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/// The accounts definition for [`accept_receiver`](crate::gmsol_store::accept_receiver).
206#[derive(Accounts)]
207pub struct AcceptReceiver<'info> {
208    /// The next receiver.
209    #[account(
210        constraint = next_receiver.key() == store.load()?.next_receiver() @ CoreError::PermissionDenied,
211    )]
212    pub next_receiver: Signer<'info>,
213    /// The store account whose receiver is being transferred.
214    #[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/// The accounts definition for [`set_token_map`](crate::gmsol_store::set_token_map).
230#[derive(Accounts)]
231pub struct SetTokenMap<'info> {
232    /// The caller of this instruction.
233    pub authority: Signer<'info>,
234    /// Store.
235    #[account(mut)]
236    pub store: AccountLoader<'info, Store>,
237    /// Token map to use.
238    #[account(has_one = store)]
239    pub token_map: AccountLoader<'info, TokenMapHeader>,
240}
241
242/// Set token map.
243///
244/// ## Check
245/// - Only MARKET_KEEPER can perform this action.
246pub(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
266/// Get the token map address of the store.
267pub(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}