Skip to main content

percli_chain/
ix.rs

1use borsh::BorshSerialize;
2use sha2::{Digest, Sha256};
3#[allow(deprecated)]
4use solana_sdk::{
5    instruction::{AccountMeta, Instruction},
6    pubkey::Pubkey,
7    system_program,
8};
9
10/// Compute the Anchor instruction discriminator: first 8 bytes of sha256("global:<name>").
11pub fn anchor_discriminator(name: &str) -> [u8; 8] {
12    let hash = Sha256::digest(format!("global:{name}").as_bytes());
13    let mut disc = [0u8; 8];
14    disc.copy_from_slice(&hash[..8]);
15    disc
16}
17
18/// Build an Anchor instruction with discriminator + borsh-serialized args.
19pub fn build_ix(
20    program_id: &Pubkey,
21    name: &str,
22    args: impl BorshSerialize,
23    accounts: Vec<AccountMeta>,
24) -> Instruction {
25    let mut data = anchor_discriminator(name).to_vec();
26    args.serialize(&mut data).expect("borsh serialize");
27    Instruction {
28        program_id: *program_id,
29        accounts,
30        data,
31    }
32}
33
34// --- Arg structs matching the on-chain Anchor ABI ---
35
36#[derive(BorshSerialize)]
37pub struct InitializeMarketArgs {
38    pub init_slot: u64,
39    pub init_oracle_price: u64,
40    pub params: RiskParamsInput,
41}
42
43#[derive(BorshSerialize)]
44pub struct RiskParamsInput {
45    pub warmup_period_slots: u64,
46    pub maintenance_margin_bps: u64,
47    pub initial_margin_bps: u64,
48    pub trading_fee_bps: u64,
49    pub max_accounts: u64,
50    pub new_account_fee: u64,
51    pub maintenance_fee_per_slot: u64,
52    pub max_crank_staleness_slots: u64,
53    pub liquidation_fee_bps: u64,
54    pub liquidation_fee_cap: u64,
55    pub min_liquidation_abs: u64,
56    pub min_initial_deposit: u64,
57    pub min_nonzero_mm_req: u64,
58    pub min_nonzero_im_req: u64,
59    pub insurance_floor: u64,
60}
61
62#[derive(BorshSerialize)]
63pub struct DepositArgs {
64    pub account_idx: u16,
65    pub amount: u64,
66}
67
68#[derive(BorshSerialize)]
69pub struct WithdrawArgs {
70    pub account_idx: u16,
71    pub amount: u64,
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 funding_rate: i64,
87}
88
89#[derive(BorshSerialize)]
90pub struct LiquidateArgs {
91    pub account_idx: u16,
92    pub funding_rate: i64,
93}
94
95#[derive(BorshSerialize)]
96pub struct SettleArgs {
97    pub account_idx: u16,
98    pub funding_rate: i64,
99}
100
101#[derive(BorshSerialize)]
102pub struct CloseAccountArgs {
103    pub account_idx: u16,
104    pub funding_rate: i64,
105}
106
107#[derive(BorshSerialize)]
108pub struct ReclaimAccountArgs {
109    pub account_idx: u16,
110}
111
112#[derive(BorshSerialize)]
113pub struct WithdrawInsuranceArgs {
114    pub amount: u64,
115}
116
117#[derive(BorshSerialize)]
118pub struct TopUpInsuranceArgs {
119    pub amount: u64,
120}
121
122#[derive(BorshSerialize)]
123pub struct DepositFeeCreditsArgs {
124    pub account_idx: u16,
125    pub amount: u64,
126}
127
128#[derive(BorshSerialize)]
129pub struct ConvertReleasedPnlArgs {
130    pub account_idx: u16,
131    pub x_req: u64,
132    pub funding_rate: i64,
133}
134
135#[derive(BorshSerialize)]
136pub struct UpdateMatcherArgs {
137    pub new_matcher: Pubkey,
138}
139
140#[derive(BorshSerialize)]
141pub struct TransferAuthorityArgs {
142    pub new_authority: Pubkey,
143}
144
145// --- Instruction builders ---
146
147pub fn initialize_market_ix(
148    program_id: &Pubkey,
149    market: &Pubkey,
150    authority: &Pubkey,
151    mint: &Pubkey,
152    vault: &Pubkey,
153    oracle: &Pubkey,
154    matcher: &Pubkey,
155    token_program: &Pubkey,
156    args: InitializeMarketArgs,
157) -> Instruction {
158    build_ix(
159        program_id,
160        "initialize_market",
161        args,
162        vec![
163            AccountMeta::new(*authority, true),
164            AccountMeta::new(*market, false),
165            AccountMeta::new_readonly(*mint, false),
166            AccountMeta::new(*vault, false),
167            AccountMeta::new_readonly(*oracle, false),
168            AccountMeta::new_readonly(*matcher, false),
169            AccountMeta::new_readonly(*token_program, false),
170            AccountMeta::new_readonly(system_program::id(), false),
171        ],
172    )
173}
174
175pub fn deposit_ix(
176    program_id: &Pubkey,
177    market: &Pubkey,
178    user: &Pubkey,
179    mint: &Pubkey,
180    user_token_account: &Pubkey,
181    vault: &Pubkey,
182    token_program: &Pubkey,
183    args: DepositArgs,
184) -> Instruction {
185    build_ix(
186        program_id,
187        "deposit",
188        args,
189        vec![
190            AccountMeta::new(*user, true),
191            AccountMeta::new(*market, false),
192            AccountMeta::new_readonly(*mint, false),
193            AccountMeta::new(*user_token_account, false),
194            AccountMeta::new(*vault, false),
195            AccountMeta::new_readonly(*token_program, false),
196        ],
197    )
198}
199
200pub fn withdraw_ix(
201    program_id: &Pubkey,
202    market: &Pubkey,
203    user: &Pubkey,
204    mint: &Pubkey,
205    user_token_account: &Pubkey,
206    vault: &Pubkey,
207    token_program: &Pubkey,
208    args: WithdrawArgs,
209) -> Instruction {
210    build_ix(
211        program_id,
212        "withdraw",
213        args,
214        vec![
215            AccountMeta::new(*user, true),
216            AccountMeta::new(*market, false),
217            AccountMeta::new_readonly(*mint, false),
218            AccountMeta::new(*user_token_account, false),
219            AccountMeta::new(*vault, false),
220            AccountMeta::new_readonly(*token_program, false),
221        ],
222    )
223}
224
225pub fn trade_ix(
226    program_id: &Pubkey,
227    market: &Pubkey,
228    authority: &Pubkey,
229    args: TradeArgs,
230) -> Instruction {
231    build_ix(
232        program_id,
233        "trade",
234        args,
235        vec![
236            AccountMeta::new_readonly(*authority, true),
237            AccountMeta::new(*market, false),
238        ],
239    )
240}
241
242pub fn crank_ix(
243    program_id: &Pubkey,
244    market: &Pubkey,
245    cranker: &Pubkey,
246    oracle: &Pubkey,
247    args: CrankArgs,
248) -> Instruction {
249    build_ix(
250        program_id,
251        "crank",
252        args,
253        vec![
254            AccountMeta::new_readonly(*cranker, true),
255            AccountMeta::new(*market, false),
256            AccountMeta::new_readonly(*oracle, false),
257        ],
258    )
259}
260
261pub fn liquidate_ix(
262    program_id: &Pubkey,
263    market: &Pubkey,
264    liquidator: &Pubkey,
265    args: LiquidateArgs,
266) -> Instruction {
267    build_ix(
268        program_id,
269        "liquidate",
270        args,
271        vec![
272            AccountMeta::new_readonly(*liquidator, true),
273            AccountMeta::new(*market, false),
274        ],
275    )
276}
277
278pub fn settle_ix(
279    program_id: &Pubkey,
280    market: &Pubkey,
281    user: &Pubkey,
282    args: SettleArgs,
283) -> Instruction {
284    build_ix(
285        program_id,
286        "settle",
287        args,
288        vec![
289            AccountMeta::new_readonly(*user, true),
290            AccountMeta::new(*market, false),
291        ],
292    )
293}
294
295pub fn close_account_ix(
296    program_id: &Pubkey,
297    market: &Pubkey,
298    user: &Pubkey,
299    args: CloseAccountArgs,
300) -> Instruction {
301    build_ix(
302        program_id,
303        "close_account",
304        args,
305        vec![
306            AccountMeta::new_readonly(*user, true),
307            AccountMeta::new(*market, false),
308        ],
309    )
310}
311
312pub fn reclaim_account_ix(
313    program_id: &Pubkey,
314    market: &Pubkey,
315    reclaimer: &Pubkey,
316    args: ReclaimAccountArgs,
317) -> Instruction {
318    build_ix(
319        program_id,
320        "reclaim_account",
321        args,
322        vec![
323            AccountMeta::new_readonly(*reclaimer, true),
324            AccountMeta::new(*market, false),
325        ],
326    )
327}
328
329pub fn withdraw_insurance_ix(
330    program_id: &Pubkey,
331    market: &Pubkey,
332    authority: &Pubkey,
333    mint: &Pubkey,
334    authority_token_account: &Pubkey,
335    vault: &Pubkey,
336    token_program: &Pubkey,
337    args: WithdrawInsuranceArgs,
338) -> Instruction {
339    build_ix(
340        program_id,
341        "withdraw_insurance",
342        args,
343        vec![
344            AccountMeta::new(*authority, true),
345            AccountMeta::new(*market, false),
346            AccountMeta::new_readonly(*mint, false),
347            AccountMeta::new(*authority_token_account, false),
348            AccountMeta::new(*vault, false),
349            AccountMeta::new_readonly(*token_program, false),
350        ],
351    )
352}
353
354pub fn top_up_insurance_ix(
355    program_id: &Pubkey,
356    market: &Pubkey,
357    depositor: &Pubkey,
358    mint: &Pubkey,
359    depositor_token_account: &Pubkey,
360    vault: &Pubkey,
361    token_program: &Pubkey,
362    args: TopUpInsuranceArgs,
363) -> Instruction {
364    build_ix(
365        program_id,
366        "top_up_insurance",
367        args,
368        vec![
369            AccountMeta::new(*depositor, true),
370            AccountMeta::new(*market, false),
371            AccountMeta::new_readonly(*mint, false),
372            AccountMeta::new(*depositor_token_account, false),
373            AccountMeta::new(*vault, false),
374            AccountMeta::new_readonly(*token_program, false),
375        ],
376    )
377}
378
379pub fn deposit_fee_credits_ix(
380    program_id: &Pubkey,
381    market: &Pubkey,
382    user: &Pubkey,
383    mint: &Pubkey,
384    user_token_account: &Pubkey,
385    vault: &Pubkey,
386    token_program: &Pubkey,
387    args: DepositFeeCreditsArgs,
388) -> Instruction {
389    build_ix(
390        program_id,
391        "deposit_fee_credits",
392        args,
393        vec![
394            AccountMeta::new(*user, true),
395            AccountMeta::new(*market, false),
396            AccountMeta::new_readonly(*mint, false),
397            AccountMeta::new(*user_token_account, false),
398            AccountMeta::new(*vault, false),
399            AccountMeta::new_readonly(*token_program, false),
400        ],
401    )
402}
403
404pub fn convert_released_pnl_ix(
405    program_id: &Pubkey,
406    market: &Pubkey,
407    user: &Pubkey,
408    oracle: &Pubkey,
409    args: ConvertReleasedPnlArgs,
410) -> Instruction {
411    build_ix(
412        program_id,
413        "convert_released_pnl",
414        args,
415        vec![
416            AccountMeta::new_readonly(*user, true),
417            AccountMeta::new(*market, false),
418            AccountMeta::new_readonly(*oracle, false),
419        ],
420    )
421}
422
423pub fn accrue_market_ix(
424    program_id: &Pubkey,
425    market: &Pubkey,
426    signer: &Pubkey,
427    oracle: &Pubkey,
428) -> Instruction {
429    build_ix(
430        program_id,
431        "accrue_market",
432        (),
433        vec![
434            AccountMeta::new_readonly(*signer, true),
435            AccountMeta::new(*market, false),
436            AccountMeta::new_readonly(*oracle, false),
437        ],
438    )
439}
440
441pub fn update_matcher_ix(
442    program_id: &Pubkey,
443    market: &Pubkey,
444    authority: &Pubkey,
445    args: UpdateMatcherArgs,
446) -> Instruction {
447    build_ix(
448        program_id,
449        "update_matcher",
450        args,
451        vec![
452            AccountMeta::new_readonly(*authority, true),
453            AccountMeta::new(*market, false),
454        ],
455    )
456}
457
458pub fn update_oracle_ix(
459    program_id: &Pubkey,
460    market: &Pubkey,
461    authority: &Pubkey,
462    new_oracle: &Pubkey,
463) -> Instruction {
464    build_ix(
465        program_id,
466        "update_oracle",
467        (),
468        vec![
469            AccountMeta::new_readonly(*authority, true),
470            AccountMeta::new(*market, false),
471            AccountMeta::new_readonly(*new_oracle, false),
472        ],
473    )
474}
475
476pub fn migrate_header_v1_ix(
477    program_id: &Pubkey,
478    market: &Pubkey,
479    authority: &Pubkey,
480) -> Instruction {
481    build_ix(
482        program_id,
483        "migrate_header_v1",
484        (),
485        vec![
486            AccountMeta::new(*authority, true),
487            AccountMeta::new(*market, false),
488        ],
489    )
490}
491
492pub fn transfer_authority_ix(
493    program_id: &Pubkey,
494    market: &Pubkey,
495    authority: &Pubkey,
496    args: TransferAuthorityArgs,
497) -> Instruction {
498    build_ix(
499        program_id,
500        "transfer_authority",
501        args,
502        vec![
503            AccountMeta::new_readonly(*authority, true),
504            AccountMeta::new(*market, false),
505        ],
506    )
507}
508
509pub fn accept_authority_ix(
510    program_id: &Pubkey,
511    market: &Pubkey,
512    new_authority: &Pubkey,
513) -> Instruction {
514    build_ix(
515        program_id,
516        "accept_authority",
517        (),
518        vec![
519            AccountMeta::new_readonly(*new_authority, true),
520            AccountMeta::new(*market, false),
521        ],
522    )
523}