use anchor_lang::prelude::*;
use anchor_spl::{
associated_token::AssociatedToken,
token::{Mint, Token, TokenAccount},
token_interface,
};
use crate::{
constants,
states::Store,
utils::{internal, token::must_be_uninitialized},
};
#[derive(Accounts)]
pub struct InitializeMarketVault<'info> {
#[account(mut)]
pub authority: Signer<'info>,
pub store: AccountLoader<'info, Store>,
pub mint: Account<'info, Mint>,
#[account(
init_if_needed,
payer = authority,
token::mint = mint,
// We use the store as the authority of the token account.
token::authority = store,
seeds = [
constants::MARKET_VAULT_SEED,
store.key().as_ref(),
mint.key().as_ref(),
],
bump,
)]
pub vault: Account<'info, TokenAccount>,
pub system_program: Program<'info, System>,
pub token_program: Program<'info, Token>,
}
#[allow(unused_variables)]
pub(crate) fn unchecked_initialize_market_vault(ctx: Context<InitializeMarketVault>) -> Result<()> {
Ok(())
}
impl<'info> internal::Authentication<'info> for InitializeMarketVault<'info> {
fn authority(&self) -> &Signer<'info> {
&self.authority
}
fn store(&self) -> &AccountLoader<'info, Store> {
&self.store
}
}
#[derive(Accounts)]
#[instruction(timestamp: i64)]
pub struct UseClaimableAccount<'info> {
#[account(mut)]
pub authority: Signer<'info>,
pub store: AccountLoader<'info, Store>,
pub mint: Account<'info, Mint>,
pub owner: UncheckedAccount<'info>,
#[account(
init_if_needed,
payer = authority,
token::mint = mint,
// We use the store as the authority of the token account.
token::authority = store,
seeds = [
constants::CLAIMABLE_ACCOUNT_SEED,
store.key().as_ref(),
mint.key().as_ref(),
owner.key().as_ref(),
&store.load()?.claimable_time_key(timestamp)?,
],
bump,
)]
pub account: Account<'info, TokenAccount>,
pub system_program: Program<'info, System>,
pub token_program: Program<'info, Token>,
}
pub(crate) fn unchecked_use_claimable_account(
ctx: Context<UseClaimableAccount>,
_timestamp: i64,
amount: u64,
) -> Result<()> {
if ctx.accounts.account.delegate.is_none() || ctx.accounts.account.delegated_amount != amount {
anchor_spl::token::approve(
CpiContext::new_with_signer(
ctx.accounts.token_program.to_account_info(),
anchor_spl::token::Approve {
to: ctx.accounts.account.to_account_info(),
delegate: ctx.accounts.owner.to_account_info(),
authority: ctx.accounts.store.to_account_info(),
},
&[&ctx.accounts.store.load()?.signer_seeds()],
),
amount,
)?;
}
Ok(())
}
impl<'info> internal::Authentication<'info> for UseClaimableAccount<'info> {
fn authority(&self) -> &Signer<'info> {
&self.authority
}
fn store(&self) -> &AccountLoader<'info, Store> {
&self.store
}
}
#[derive(Accounts)]
#[instruction(timestamp: i64)]
pub struct CloseEmptyClaimableAccount<'info> {
#[account(mut)]
pub authority: Signer<'info>,
pub store: AccountLoader<'info, Store>,
pub mint: Account<'info, Mint>,
pub owner: UncheckedAccount<'info>,
#[account(
mut,
seeds = [
constants::CLAIMABLE_ACCOUNT_SEED,
store.key().as_ref(),
mint.key().as_ref(),
owner.key().as_ref(),
&store.load()?.claimable_time_key(timestamp)?,
],
bump,
)]
pub account: UncheckedAccount<'info>,
pub system_program: Program<'info, System>,
pub token_program: Program<'info, Token>,
}
pub(crate) fn unchecked_close_empty_claimable_account(
ctx: Context<CloseEmptyClaimableAccount>,
_timestamp: i64,
) -> Result<()> {
if must_be_uninitialized(&ctx.accounts.account) {
return Ok(());
}
let account = ctx.accounts.account.to_account_info();
let amount = anchor_spl::token::accessor::amount(&account)?;
if amount == 0 {
anchor_spl::token::close_account(CpiContext::new_with_signer(
ctx.accounts.token_program.to_account_info(),
anchor_spl::token::CloseAccount {
account: ctx.accounts.account.to_account_info(),
destination: ctx.accounts.authority.to_account_info(),
authority: ctx.accounts.store.to_account_info(),
},
&[&ctx.accounts.store.load()?.signer_seeds()],
))?;
}
Ok(())
}
impl<'info> internal::Authentication<'info> for CloseEmptyClaimableAccount<'info> {
fn authority(&self) -> &Signer<'info> {
&self.authority
}
fn store(&self) -> &AccountLoader<'info, Store> {
&self.store
}
}
#[derive(Accounts)]
pub struct PrepareAssociatedTokenAccount<'info> {
#[account(mut)]
pub payer: Signer<'info>,
pub owner: UncheckedAccount<'info>,
pub mint: InterfaceAccount<'info, token_interface::Mint>,
#[account(
init_if_needed,
payer = payer,
associated_token::mint = mint,
associated_token::authority = owner,
)]
pub account: InterfaceAccount<'info, token_interface::TokenAccount>,
pub system_program: Program<'info, System>,
pub token_program: Interface<'info, token_interface::TokenInterface>,
pub associated_token_program: Program<'info, AssociatedToken>,
}
pub(crate) fn prepare_associated_token_account(
_ctx: Context<PrepareAssociatedTokenAccount>,
) -> Result<()> {
Ok(())
}