Skip to main content

percli_chain/
ix.rs

1use borsh::BorshSerialize;
2use sha2::{Digest, Sha256};
3use solana_sdk::{
4    instruction::{AccountMeta, Instruction},
5    pubkey::Pubkey,
6    system_program,
7};
8
9/// Compute the Anchor instruction discriminator: first 8 bytes of sha256("global:<name>").
10pub fn anchor_discriminator(name: &str) -> [u8; 8] {
11    let hash = Sha256::digest(format!("global:{name}").as_bytes());
12    let mut disc = [0u8; 8];
13    disc.copy_from_slice(&hash[..8]);
14    disc
15}
16
17/// Build an Anchor instruction with discriminator + borsh-serialized args.
18pub fn build_ix(
19    program_id: &Pubkey,
20    name: &str,
21    args: impl BorshSerialize,
22    accounts: Vec<AccountMeta>,
23) -> Instruction {
24    let mut data = anchor_discriminator(name).to_vec();
25    args.serialize(&mut data).expect("borsh serialize");
26    Instruction {
27        program_id: *program_id,
28        accounts,
29        data,
30    }
31}
32
33// --- Arg structs matching the on-chain Anchor ABI ---
34
35#[derive(BorshSerialize)]
36pub struct InitializeMarketArgs {
37    pub init_slot: u64,
38    pub init_oracle_price: u64,
39    pub params: RiskParamsInput,
40}
41
42#[derive(BorshSerialize)]
43pub struct RiskParamsInput {
44    pub maintenance_margin_bps: u64,
45    pub initial_margin_bps: u64,
46    pub liquidation_fee_bps: u64,
47    pub insurance_fee_bps: u64,
48    pub adl_threshold_bps: u64,
49    pub max_leverage_q: u64,
50    pub min_order_size_q: u64,
51    pub tick_size: u64,
52    pub max_oi_imbalance_q: u64,
53    pub haircut_start_bps: u64,
54    pub haircut_end_bps: u64,
55    pub haircut_maturity_slots: u64,
56    pub matured_haircut_bps: u64,
57    pub max_accounts: u64,
58    pub min_nonzero_mm_req: u128,
59    pub min_nonzero_im_req: u128,
60}
61
62#[derive(BorshSerialize)]
63pub struct DepositArgs {
64    pub account_idx: u16,
65    pub amount: u128,
66}
67
68#[derive(BorshSerialize)]
69pub struct WithdrawArgs {
70    pub account_idx: u16,
71    pub amount: u128,
72    pub funding_rate: i64,
73}
74
75#[derive(BorshSerialize)]
76pub struct TradeArgs {
77    pub account_a: u16,
78    pub account_b: u16,
79    pub size_q: i128,
80    pub exec_price: u64,
81    pub funding_rate: i64,
82}
83
84#[derive(BorshSerialize)]
85pub struct CrankArgs {
86    pub oracle_price: u64,
87    pub funding_rate: i64,
88}
89
90#[derive(BorshSerialize)]
91pub struct LiquidateArgs {
92    pub account_idx: u16,
93    pub funding_rate: i64,
94}
95
96#[derive(BorshSerialize)]
97pub struct SettleArgs {
98    pub account_idx: u16,
99    pub funding_rate: i64,
100}
101
102#[derive(BorshSerialize)]
103pub struct CloseAccountArgs {
104    pub account_idx: u16,
105    pub funding_rate: i64,
106}
107
108// --- Instruction builders ---
109
110pub fn initialize_market_ix(
111    program_id: &Pubkey,
112    market: &Pubkey,
113    authority: &Pubkey,
114    args: InitializeMarketArgs,
115) -> Instruction {
116    build_ix(
117        program_id,
118        "initialize_market",
119        args,
120        vec![
121            AccountMeta::new(*market, false),
122            AccountMeta::new(*authority, true),
123            AccountMeta::new_readonly(system_program::id(), false),
124        ],
125    )
126}
127
128pub fn deposit_ix(
129    program_id: &Pubkey,
130    market: &Pubkey,
131    user: &Pubkey,
132    args: DepositArgs,
133) -> Instruction {
134    build_ix(
135        program_id,
136        "deposit",
137        args,
138        vec![
139            AccountMeta::new(*market, false),
140            AccountMeta::new_readonly(*user, true),
141        ],
142    )
143}
144
145pub fn withdraw_ix(
146    program_id: &Pubkey,
147    market: &Pubkey,
148    user: &Pubkey,
149    args: WithdrawArgs,
150) -> Instruction {
151    build_ix(
152        program_id,
153        "withdraw",
154        args,
155        vec![
156            AccountMeta::new(*market, false),
157            AccountMeta::new_readonly(*user, true),
158        ],
159    )
160}
161
162pub fn trade_ix(
163    program_id: &Pubkey,
164    market: &Pubkey,
165    authority: &Pubkey,
166    args: TradeArgs,
167) -> Instruction {
168    build_ix(
169        program_id,
170        "trade",
171        args,
172        vec![
173            AccountMeta::new(*market, false),
174            AccountMeta::new_readonly(*authority, true),
175        ],
176    )
177}
178
179pub fn crank_ix(
180    program_id: &Pubkey,
181    market: &Pubkey,
182    cranker: &Pubkey,
183    args: CrankArgs,
184) -> Instruction {
185    build_ix(
186        program_id,
187        "crank",
188        args,
189        vec![
190            AccountMeta::new(*market, false),
191            AccountMeta::new_readonly(*cranker, true),
192        ],
193    )
194}
195
196pub fn liquidate_ix(
197    program_id: &Pubkey,
198    market: &Pubkey,
199    liquidator: &Pubkey,
200    args: LiquidateArgs,
201) -> Instruction {
202    build_ix(
203        program_id,
204        "liquidate",
205        args,
206        vec![
207            AccountMeta::new(*market, false),
208            AccountMeta::new_readonly(*liquidator, true),
209        ],
210    )
211}
212
213pub fn settle_ix(
214    program_id: &Pubkey,
215    market: &Pubkey,
216    user: &Pubkey,
217    args: SettleArgs,
218) -> Instruction {
219    build_ix(
220        program_id,
221        "settle",
222        args,
223        vec![
224            AccountMeta::new(*market, false),
225            AccountMeta::new_readonly(*user, true),
226        ],
227    )
228}
229
230pub fn close_account_ix(
231    program_id: &Pubkey,
232    market: &Pubkey,
233    user: &Pubkey,
234    args: CloseAccountArgs,
235) -> Instruction {
236    build_ix(
237        program_id,
238        "close_account",
239        args,
240        vec![
241            AccountMeta::new(*market, false),
242            AccountMeta::new_readonly(*user, true),
243        ],
244    )
245}