Skip to main content

percli_program/instructions/
initialize_market.rs

1use anchor_lang::prelude::*;
2use percli_core::RiskParams;
3
4use crate::state::{engine_from_account_data, write_header, MarketHeader, MARKET_ACCOUNT_SIZE};
5
6#[derive(Accounts)]
7pub struct InitializeMarket<'info> {
8    #[account(mut)]
9    pub authority: Signer<'info>,
10
11    /// CHECK: Manually validated. Initialized as a PDA with the correct size.
12    #[account(
13        init,
14        payer = authority,
15        space = MARKET_ACCOUNT_SIZE,
16        seeds = [b"market", authority.key().as_ref()],
17        bump,
18    )]
19    pub market: UncheckedAccount<'info>,
20
21    pub system_program: Program<'info, System>,
22}
23
24pub fn handler(
25    ctx: Context<InitializeMarket>,
26    init_slot: u64,
27    init_oracle_price: u64,
28    params: RiskParamsInput,
29) -> Result<()> {
30    let market = &ctx.accounts.market;
31    let mut data = market.try_borrow_mut_data()?;
32
33    // Write discriminator (first 8 bytes) — use a fixed marker
34    data[0..8].copy_from_slice(b"percmrkt");
35
36    let header = MarketHeader {
37        authority: ctx.accounts.authority.key(),
38        bump: ctx.bumps.market,
39        _padding: [0; 7],
40    };
41    write_header(&mut data, &header);
42
43    let engine = engine_from_account_data(&mut data);
44    let risk_params = params.to_risk_params();
45    engine.init_in_place(risk_params, init_slot, init_oracle_price);
46
47    Ok(())
48}
49
50/// Anchor-friendly input for RiskParams (all primitives, no wrapper types).
51#[derive(AnchorSerialize, AnchorDeserialize, Clone)]
52pub struct RiskParamsInput {
53    pub warmup_period_slots: u64,
54    pub maintenance_margin_bps: u64,
55    pub initial_margin_bps: u64,
56    pub trading_fee_bps: u64,
57    pub max_accounts: u64,
58    pub new_account_fee: u64,
59    pub maintenance_fee_per_slot: u64,
60    pub max_crank_staleness_slots: u64,
61    pub liquidation_fee_bps: u64,
62    pub liquidation_fee_cap: u64,
63    pub liquidation_buffer_bps: u64,
64    pub min_liquidation_abs: u64,
65    pub min_initial_deposit: u64,
66    pub min_nonzero_mm_req: u64,
67    pub min_nonzero_im_req: u64,
68    pub insurance_floor: u64,
69}
70
71impl RiskParamsInput {
72    pub fn to_risk_params(&self) -> RiskParams {
73        use percli_core::U128;
74        RiskParams {
75            warmup_period_slots: self.warmup_period_slots,
76            maintenance_margin_bps: self.maintenance_margin_bps,
77            initial_margin_bps: self.initial_margin_bps,
78            trading_fee_bps: self.trading_fee_bps,
79            max_accounts: self.max_accounts,
80            new_account_fee: U128::new(self.new_account_fee as u128),
81            maintenance_fee_per_slot: U128::new(self.maintenance_fee_per_slot as u128),
82            max_crank_staleness_slots: self.max_crank_staleness_slots,
83            liquidation_fee_bps: self.liquidation_fee_bps,
84            liquidation_fee_cap: U128::new(self.liquidation_fee_cap as u128),
85            liquidation_buffer_bps: self.liquidation_buffer_bps,
86            min_liquidation_abs: U128::new(self.min_liquidation_abs as u128),
87            min_initial_deposit: U128::new(self.min_initial_deposit as u128),
88            min_nonzero_mm_req: self.min_nonzero_mm_req as u128,
89            min_nonzero_im_req: self.min_nonzero_im_req as u128,
90            insurance_floor: U128::new(self.insurance_floor as u128),
91        }
92    }
93}