use crate::errors::ErrorCode;
use crate::state::*;
use anchor_lang::prelude::*;
use anchor_spl::token::Mint;
use anchor_spl::token::Token;
use anchor_spl::token::TokenAccount;
use anchor_spl::token::{self};
#[derive(Accounts)]
pub struct StakeCtx<'info> {
#[account(mut, seeds = [STAKE_ENTRY_PREFIX.as_bytes(), stake_entry.pool.as_ref(), stake_entry.original_mint.as_ref(), get_stake_seed(original_mint.supply, user.key()).as_ref()], bump=stake_entry.bump)]
stake_entry: Box<Account<'info, StakeEntry>>,
#[account(mut, constraint = stake_entry.pool == stake_pool.key() @ ErrorCode::InvalidStakePool)]
stake_pool: Box<Account<'info, StakePool>>,
#[account(mut, constraint =
stake_entry_original_mint_token_account.mint == stake_entry.original_mint
&& stake_entry_original_mint_token_account.owner == stake_entry.key()
@ ErrorCode::InvalidStakeEntryOriginalMintTokenAccount
)]
stake_entry_original_mint_token_account: Box<Account<'info, TokenAccount>>,
original_mint: Box<Account<'info, Mint>>,
#[account(mut)]
user: Signer<'info>,
#[account(mut, constraint =
user_original_mint_token_account.amount > 0
&& user_original_mint_token_account.mint == stake_entry.original_mint
&& user_original_mint_token_account.owner == user.key()
@ ErrorCode::InvalidUserOriginalMintTokenAccount
)]
user_original_mint_token_account: Box<Account<'info, TokenAccount>>,
token_program: Program<'info, Token>,
}
pub fn handler(ctx: Context<StakeCtx>, amount: u64) -> Result<()> {
let stake_pool = &mut ctx.accounts.stake_pool;
let stake_entry = &mut ctx.accounts.stake_entry;
if stake_pool.end_date.is_some() && Clock::get().unwrap().unix_timestamp > stake_pool.end_date.unwrap() {
return Err(error!(ErrorCode::StakePoolHasEnded));
}
if stake_entry.amount != 0 {
stake_entry.total_stake_seconds = stake_entry.total_stake_seconds.saturating_add(
(u128::try_from(stake_entry.cooldown_start_seconds.unwrap_or(Clock::get().unwrap().unix_timestamp))
.unwrap()
.saturating_sub(u128::try_from(stake_entry.last_updated_at.unwrap_or(stake_entry.last_staked_at)).unwrap()))
.checked_mul(u128::try_from(stake_entry.amount).unwrap())
.unwrap(),
);
stake_entry.cooldown_start_seconds = None;
}
let cpi_accounts = token::Transfer {
from: ctx.accounts.user_original_mint_token_account.to_account_info(),
to: ctx.accounts.stake_entry_original_mint_token_account.to_account_info(),
authority: ctx.accounts.user.to_account_info(),
};
let cpi_program = ctx.accounts.token_program.to_account_info();
let cpi_context = CpiContext::new(cpi_program, cpi_accounts);
token::transfer(cpi_context, amount)?;
if stake_pool.reset_on_stake && stake_entry.amount == 0 {
stake_entry.total_stake_seconds = 0;
}
stake_entry.last_staked_at = Clock::get().unwrap().unix_timestamp;
stake_entry.last_updated_at = Some(Clock::get().unwrap().unix_timestamp);
stake_entry.last_staker = ctx.accounts.user.key();
stake_entry.amount = stake_entry.amount.checked_add(amount).unwrap();
stake_pool.total_staked = stake_pool.total_staked.checked_add(1).expect("Add error");
Ok(())
}