percli_program/instructions/
initialize_market.rs1use anchor_lang::prelude::*;
2use anchor_spl::token::{Mint, Token, TokenAccount};
3use percli_core::RiskParams;
4
5use crate::error::PercolatorError;
6use crate::state::{engine_from_account_data, write_header, MarketHeader, MARKET_ACCOUNT_SIZE};
7
8#[derive(Accounts)]
9pub struct InitializeMarket<'info> {
10 #[account(mut)]
11 pub authority: Signer<'info>,
12
13 #[account(
15 init,
16 payer = authority,
17 space = MARKET_ACCOUNT_SIZE,
18 seeds = [b"market", authority.key().as_ref()],
19 bump,
20 )]
21 pub market: UncheckedAccount<'info>,
22
23 pub mint: Account<'info, Mint>,
25
26 #[account(
28 init,
29 payer = authority,
30 token::mint = mint,
31 token::authority = market,
32 seeds = [b"vault", market.key().as_ref()],
33 bump,
34 )]
35 pub vault: Account<'info, TokenAccount>,
36
37 pub oracle: UncheckedAccount<'info>,
39
40 pub matcher: UncheckedAccount<'info>,
43
44 pub token_program: Program<'info, Token>,
45 pub system_program: Program<'info, System>,
46}
47
48pub fn handler(
49 ctx: Context<InitializeMarket>,
50 init_slot: u64,
51 init_oracle_price: u64,
52 params: RiskParamsInput,
53) -> Result<()> {
54 let market = &ctx.accounts.market;
55 let mut data = market.try_borrow_mut_data()?;
56
57 data[0..8].copy_from_slice(b"percmrkt");
59
60 let header = MarketHeader {
61 authority: ctx.accounts.authority.key(),
62 mint: ctx.accounts.mint.key(),
63 oracle: ctx.accounts.oracle.key(),
64 matcher: ctx.accounts.matcher.key(),
65 bump: ctx.bumps.market,
66 vault_bump: ctx.bumps.vault,
67 _padding: [0; 6],
68 };
69 write_header(&mut data, &header);
70
71 require!(init_oracle_price > 0, PercolatorError::InvalidOraclePriceValue);
72
73 let engine = engine_from_account_data(&mut data);
74 let risk_params = params.to_risk_params();
75 engine.init_in_place(risk_params, init_slot, init_oracle_price);
76
77 Ok(())
78}
79
80#[derive(AnchorSerialize, AnchorDeserialize, Clone)]
82pub struct RiskParamsInput {
83 pub warmup_period_slots: u64,
84 pub maintenance_margin_bps: u64,
85 pub initial_margin_bps: u64,
86 pub trading_fee_bps: u64,
87 pub max_accounts: u64,
88 pub new_account_fee: u64,
89 pub maintenance_fee_per_slot: u64,
90 pub max_crank_staleness_slots: u64,
91 pub liquidation_fee_bps: u64,
92 pub liquidation_fee_cap: u64,
93 pub min_liquidation_abs: u64,
94 pub min_initial_deposit: u64,
95 pub min_nonzero_mm_req: u64,
96 pub min_nonzero_im_req: u64,
97 pub insurance_floor: u64,
98}
99
100impl RiskParamsInput {
101 pub fn to_risk_params(&self) -> RiskParams {
102 use percli_core::U128;
103 RiskParams {
104 warmup_period_slots: self.warmup_period_slots,
105 maintenance_margin_bps: self.maintenance_margin_bps,
106 initial_margin_bps: self.initial_margin_bps,
107 trading_fee_bps: self.trading_fee_bps,
108 max_accounts: self.max_accounts,
109 new_account_fee: U128::new(self.new_account_fee as u128),
110 maintenance_fee_per_slot: U128::new(self.maintenance_fee_per_slot as u128),
111 max_crank_staleness_slots: self.max_crank_staleness_slots,
112 liquidation_fee_bps: self.liquidation_fee_bps,
113 liquidation_fee_cap: U128::new(self.liquidation_fee_cap as u128),
114 min_liquidation_abs: U128::new(self.min_liquidation_abs as u128),
115 min_initial_deposit: U128::new(self.min_initial_deposit as u128),
116 min_nonzero_mm_req: self.min_nonzero_mm_req as u128,
117 min_nonzero_im_req: self.min_nonzero_im_req as u128,
118 insurance_floor: U128::new(self.insurance_floor as u128),
119 }
120 }
121}