Skip to main content

percli_program/instructions/
deposit_fee_credits.rs

1use anchor_lang::prelude::*;
2use anchor_spl::token::{transfer_checked, Mint, Token, TokenAccount, TransferChecked};
3
4use crate::error::{from_risk_error, PercolatorError};
5use crate::instructions::events;
6use crate::state::{engine_from_account_data, header_from_account_data, MARKET_ACCOUNT_SIZE};
7
8#[derive(Accounts)]
9pub struct DepositFeeCredits<'info> {
10    #[account(mut)]
11    pub user: Signer<'info>,
12
13    /// CHECK: Validated via owner, discriminator, and size.
14    #[account(
15        mut,
16        owner = crate::ID @ PercolatorError::AccountNotFound,
17        constraint = market.data_len() >= MARKET_ACCOUNT_SIZE @ PercolatorError::AccountNotFound,
18    )]
19    pub market: UncheckedAccount<'info>,
20
21    pub mint: Account<'info, Mint>,
22
23    /// User's token account to transfer from.
24    #[account(
25        mut,
26        constraint = user_token_account.owner == user.key(),
27        constraint = user_token_account.mint == mint.key(),
28    )]
29    pub user_token_account: Account<'info, TokenAccount>,
30
31    /// Vault token account to transfer into.
32    #[account(
33        mut,
34        seeds = [b"vault", market.key().as_ref()],
35        bump,
36        constraint = vault.mint == mint.key(),
37    )]
38    pub vault: Account<'info, TokenAccount>,
39
40    pub token_program: Program<'info, Token>,
41}
42
43pub fn handler(ctx: Context<DepositFeeCredits>, account_idx: u16, amount: u64) -> Result<()> {
44    require!(amount > 0, PercolatorError::InsufficientBalance);
45
46    // Transfer tokens from user to vault
47    transfer_checked(
48        CpiContext::new(
49            ctx.accounts.token_program.key(),
50            TransferChecked {
51                from: ctx.accounts.user_token_account.to_account_info(),
52                to: ctx.accounts.vault.to_account_info(),
53                authority: ctx.accounts.user.to_account_info(),
54                mint: ctx.accounts.mint.to_account_info(),
55            },
56        ),
57        amount,
58        ctx.accounts.mint.decimals,
59    )?;
60
61    let market = &ctx.accounts.market;
62    let mut data = market.try_borrow_mut_data()?;
63
64    require!(
65        &data[0..8] == b"percmrkt",
66        PercolatorError::AccountNotFound
67    );
68
69    let header = header_from_account_data(&data)?;
70    require!(
71        header.mint == ctx.accounts.mint.key(),
72        PercolatorError::Unauthorized
73    );
74
75    let engine = engine_from_account_data(&mut data);
76
77    // Verify account ownership
78    require!(
79        engine.is_used(account_idx as usize),
80        PercolatorError::AccountNotFound
81    );
82    require!(
83        engine.accounts[account_idx as usize].owner == ctx.accounts.user.key().to_bytes(),
84        PercolatorError::Unauthorized
85    );
86
87    let clock = Clock::get()?;
88
89    engine
90        .deposit_fee_credits(account_idx, amount as u128, clock.slot)
91        .map_err(from_risk_error)?;
92
93    emit!(events::FeeCreditsDeposited {
94        user: ctx.accounts.user.key(),
95        account_idx,
96        amount,
97    });
98
99    Ok(())
100}