percli_program/instructions/
deposit.rs1use anchor_lang::prelude::*;
2use anchor_spl::token::{transfer_checked, Mint, Token, TokenAccount, TransferChecked};
3
4use crate::error::{from_risk_error, PercolatorError};
5use crate::state::{engine_from_account_data, header_from_account_data, MARKET_ACCOUNT_SIZE};
6
7#[derive(Accounts)]
8pub struct Deposit<'info> {
9 #[account(mut)]
10 pub user: Signer<'info>,
11
12 #[account(
14 mut,
15 owner = crate::ID @ PercolatorError::AccountNotFound,
16 constraint = market.data_len() == MARKET_ACCOUNT_SIZE @ PercolatorError::AccountNotFound,
17 )]
18 pub market: UncheckedAccount<'info>,
19
20 pub mint: Account<'info, Mint>,
22
23 #[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 #[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<Deposit>, account_idx: u16, amount: u64) -> Result<()> {
44 require!(amount > 0, PercolatorError::InsufficientBalance);
45
46 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;
63 let mut data = market.try_borrow_mut_data()?;
64
65 require!(
66 &data[0..8] == b"percmrkt",
67 PercolatorError::AccountNotFound
68 );
69
70 let header = header_from_account_data(&data)?;
71 require!(header.mint == ctx.accounts.mint.key(), PercolatorError::Unauthorized);
72
73 let engine = engine_from_account_data(&mut data);
74
75 let user_key = ctx.accounts.user.key();
77 if engine.is_used(account_idx as usize) {
78 let existing_owner = engine.accounts[account_idx as usize].owner;
79 if existing_owner != [0u8; 32] {
80 require!(existing_owner == user_key.to_bytes(), PercolatorError::Unauthorized);
81 }
82 }
83
84 let oracle_price = engine.last_oracle_price;
85 let clock = Clock::get()?;
86
87 engine
88 .deposit(account_idx, amount as u128, oracle_price, clock.slot)
89 .map_err(from_risk_error)?;
90
91 let _ = engine.set_owner(account_idx, user_key.to_bytes());
93
94 Ok(())
95}