Skip to main content

percli_program/instructions/
trade.rs

1use anchor_lang::prelude::*;
2
3use crate::error::{from_risk_error, PercolatorError};
4use crate::state::{engine_from_account_data, header_from_account_data, MARKET_ACCOUNT_SIZE};
5
6#[derive(Accounts)]
7pub struct Trade<'info> {
8    /// Matcher authority — must match the matcher stored in the market header.
9    pub signer: 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(
21    ctx: Context<Trade>,
22    account_a: u16,
23    account_b: u16,
24    size_q: i128,
25    exec_price: u64,
26    funding_rate: i64,
27) -> Result<()> {
28    require!(account_a != account_b, PercolatorError::InvalidMatchingEngine);
29
30    let market = &ctx.accounts.market;
31    let mut data = market.try_borrow_mut_data()?;
32
33    require!(&data[0..8] == b"percmrkt", PercolatorError::AccountNotFound);
34
35    // Verify signer is the designated matcher authority
36    let header = header_from_account_data(&data)?;
37    require!(
38        header.matcher == ctx.accounts.signer.key(),
39        PercolatorError::Unauthorized
40    );
41
42    let engine = engine_from_account_data(&mut data);
43    let oracle_price = engine.last_oracle_price;
44    let clock = Clock::get()?;
45
46    engine
47        .execute_trade_not_atomic(
48            account_a,
49            account_b,
50            oracle_price,
51            clock.slot,
52            size_q,
53            exec_price,
54            funding_rate,
55        )
56        .map_err(from_risk_error)?;
57
58    Ok(())
59}