use anchor_lang::prelude::*;
use gmsol_utils::{to_seed, InitSpace};
use crate::{
states::{Seed, Store, TokenMapHeader},
utils::internal,
CoreError,
};
#[derive(Accounts)]
#[instruction(key: String)]
pub struct Initialize<'info> {
#[account(mut)]
pub payer: Signer<'info>,
pub authority: Option<Signer<'info>>,
pub receiver: Option<Signer<'info>>,
pub holding: Option<Signer<'info>>,
#[account(
init,
payer = payer,
space = 8 + Store::INIT_SPACE,
seeds = [Store::SEED, &to_seed(&key)],
bump,
)]
pub store: AccountLoader<'info, Store>,
pub system_program: Program<'info, System>,
}
pub(crate) fn initialize(ctx: Context<Initialize>, key: String) -> Result<()> {
ctx.accounts.validate_key(&key)?;
let mut store = ctx.accounts.store.load_init()?;
let authority = ctx
.accounts
.authority
.as_ref()
.map(|a| a.key())
.unwrap_or(ctx.accounts.payer.key());
let receiver = ctx
.accounts
.receiver
.as_ref()
.map(|a| a.key())
.unwrap_or(authority);
let holding = ctx
.accounts
.holding
.as_ref()
.map(|a| a.key())
.unwrap_or(authority);
store.init(authority, &key, ctx.bumps.store, receiver, holding)?;
Ok(())
}
impl Initialize<'_> {
fn validate_key(&self, key: &str) -> Result<()> {
#[cfg(not(feature = "multi-store"))]
require!(key.is_empty(), CoreError::NonDefaultStore);
msg!("initializing a new store with key = {}", key);
Ok(())
}
}
#[derive(Accounts)]
pub struct UpdateLastRestartedSlot<'info> {
pub authority: Signer<'info>,
#[account(mut)]
pub store: AccountLoader<'info, Store>,
}
pub(crate) fn update_last_restarted_slot(ctx: Context<UpdateLastRestartedSlot>) -> Result<()> {
let slot = ctx
.accounts
.store
.load_mut()?
.update_last_restarted_slot(true)?;
msg!("[Store] the last_restarted_slot is now {}", slot);
Ok(())
}
impl<'info> internal::Authentication<'info> for UpdateLastRestartedSlot<'info> {
fn authority(&self) -> &Signer<'info> {
&self.authority
}
fn store(&self) -> &AccountLoader<'info, Store> {
&self.store
}
}
#[derive(Accounts)]
pub struct TransferStoreAuthority<'info> {
pub authority: Signer<'info>,
#[account(mut)]
pub store: AccountLoader<'info, Store>,
pub next_authority: UncheckedAccount<'info>,
}
pub(crate) fn unchecked_transfer_store_authority(
ctx: Context<TransferStoreAuthority>,
) -> Result<()> {
ctx.accounts
.store
.load_mut()?
.set_next_authority(ctx.accounts.next_authority.key)?;
msg!(
"[Store] the next_authority is now {}",
ctx.accounts.next_authority.key
);
Ok(())
}
impl<'info> internal::Authentication<'info> for TransferStoreAuthority<'info> {
fn authority(&self) -> &Signer<'info> {
&self.authority
}
fn store(&self) -> &AccountLoader<'info, Store> {
&self.store
}
}
#[derive(Accounts)]
pub struct AcceptStoreAuthority<'info> {
pub next_authority: Signer<'info>,
#[account(mut, has_one = next_authority)]
pub store: AccountLoader<'info, Store>,
}
pub(crate) fn accept_store_authority(ctx: Context<AcceptStoreAuthority>) -> Result<()> {
let authority = ctx
.accounts
.store
.load_mut()?
.validate_not_restarted_mut()?
.update_authority()?;
msg!("[Store] the authority is now {}", authority);
Ok(())
}
#[derive(Accounts)]
pub struct TransferReceiver<'info> {
#[account(
constraint = authority.key() == store.load()?.receiver() @ CoreError::PermissionDenied,
)]
pub authority: Signer<'info>,
#[account(mut)]
pub store: AccountLoader<'info, Store>,
pub next_receiver: UncheckedAccount<'info>,
}
pub(crate) fn transfer_receiver(ctx: Context<TransferReceiver>) -> Result<()> {
ctx.accounts
.store
.load_mut()?
.validate_not_restarted_mut()?
.set_next_receiver(ctx.accounts.next_receiver.key)?;
msg!(
"[Treasury] the next_receiver is now {}",
ctx.accounts.next_receiver.key
);
Ok(())
}
#[derive(Accounts)]
pub struct AcceptReceiver<'info> {
#[account(
constraint = next_receiver.key() == store.load()?.next_receiver() @ CoreError::PermissionDenied,
)]
pub next_receiver: Signer<'info>,
#[account(mut)]
pub store: AccountLoader<'info, Store>,
}
pub(crate) fn accept_receiver(ctx: Context<AcceptReceiver>) -> Result<()> {
let receiver = ctx
.accounts
.store
.load_mut()?
.validate_not_restarted_mut()?
.update_receiver()?;
msg!("[Treasury] the receiver is now {}", receiver);
Ok(())
}
#[derive(Accounts)]
pub struct SetTokenMap<'info> {
pub authority: Signer<'info>,
#[account(mut)]
pub store: AccountLoader<'info, Store>,
#[account(has_one = store)]
pub token_map: AccountLoader<'info, TokenMapHeader>,
}
pub(crate) fn unchecked_set_token_map(ctx: Context<SetTokenMap>) -> Result<()> {
ctx.accounts.store.load_mut()?.token_map = ctx.accounts.token_map.key();
Ok(())
}
impl<'info> internal::Authentication<'info> for SetTokenMap<'info> {
fn authority(&self) -> &Signer<'info> {
&self.authority
}
fn store(&self) -> &AccountLoader<'info, Store> {
&self.store
}
}
#[derive(Accounts)]
pub struct ReadStore<'info> {
pub store: AccountLoader<'info, Store>,
}
pub(crate) fn _get_token_map(ctx: Context<ReadStore>) -> Result<Option<Pubkey>> {
Ok(ctx
.accounts
.store
.load()?
.validate_not_restarted()?
.token_map()
.copied())
}