Skip to main content

percli_program/instructions/
close_account.rs

1use anchor_lang::prelude::*;
2
3use crate::error::{from_risk_error, PercolatorError};
4use crate::instructions::events;
5use crate::state::{engine_from_account_data, MARKET_ACCOUNT_SIZE};
6
7#[derive(Accounts)]
8pub struct CloseAccount<'info> {
9    pub user: Signer<'info>,
10
11    /// CHECK: Validated via owner, discriminator, and size.
12    #[account(
13        mut,
14        owner = crate::ID @ PercolatorError::AccountNotFound,
15        constraint = market.data_len() >= MARKET_ACCOUNT_SIZE @ PercolatorError::AccountNotFound,
16    )]
17    pub market: UncheckedAccount<'info>,
18}
19
20pub fn handler(ctx: Context<CloseAccount>, account_idx: u16, funding_rate: i64) -> Result<()> {
21    let market = &ctx.accounts.market;
22    let mut data = market.try_borrow_mut_data()?;
23
24    require!(&data[0..8] == b"percmrkt", PercolatorError::AccountNotFound);
25
26    let engine = engine_from_account_data(&mut data);
27
28    // Verify signer owns this account
29    let account_owner = engine.accounts[account_idx as usize].owner;
30    require!(
31        account_owner == ctx.accounts.user.key().to_bytes(),
32        PercolatorError::Unauthorized
33    );
34
35    let oracle_price = engine.last_oracle_price;
36    let clock = Clock::get()?;
37
38    engine
39        .close_account_not_atomic(account_idx, clock.slot, oracle_price, funding_rate)
40        .map_err(from_risk_error)?;
41
42    emit!(events::AccountClosed {
43        user: ctx.accounts.user.key(),
44        account_idx,
45    });
46
47    Ok(())
48}