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 maintenance_margin_bps: u64,
46    pub initial_margin_bps: u64,
47    pub liquidation_fee_bps: u64,
48    pub insurance_fee_bps: u64,
49    pub adl_threshold_bps: u64,
50    pub max_leverage_q: u64,
51    pub min_order_size_q: u64,
52    pub tick_size: u64,
53    pub max_oi_imbalance_q: u64,
54    pub haircut_start_bps: u64,
55    pub haircut_end_bps: u64,
56    pub haircut_maturity_slots: u64,
57    pub matured_haircut_bps: u64,
58    pub max_accounts: u64,
59    pub min_nonzero_mm_req: u128,
60    pub min_nonzero_im_req: u128,
61}
62
63#[derive(BorshSerialize)]
64pub struct DepositArgs {
65    pub account_idx: u16,
66    pub amount: u128,
67}
68
69#[derive(BorshSerialize)]
70pub struct WithdrawArgs {
71    pub account_idx: u16,
72    pub amount: u128,
73    pub funding_rate: i64,
74}
75
76#[derive(BorshSerialize)]
77pub struct TradeArgs {
78    pub account_a: u16,
79    pub account_b: u16,
80    pub size_q: i128,
81    pub exec_price: u64,
82    pub funding_rate: i64,
83}
84
85#[derive(BorshSerialize)]
86pub struct CrankArgs {
87    pub oracle_price: u64,
88    pub funding_rate: i64,
89}
90
91#[derive(BorshSerialize)]
92pub struct LiquidateArgs {
93    pub account_idx: u16,
94    pub funding_rate: i64,
95}
96
97#[derive(BorshSerialize)]
98pub struct SettleArgs {
99    pub account_idx: u16,
100    pub funding_rate: i64,
101}
102
103#[derive(BorshSerialize)]
104pub struct CloseAccountArgs {
105    pub account_idx: u16,
106    pub funding_rate: i64,
107}
108
109// --- Instruction builders ---
110
111pub fn initialize_market_ix(
112    program_id: &Pubkey,
113    market: &Pubkey,
114    authority: &Pubkey,
115    args: InitializeMarketArgs,
116) -> Instruction {
117    build_ix(
118        program_id,
119        "initialize_market",
120        args,
121        vec![
122            AccountMeta::new(*market, false),
123            AccountMeta::new(*authority, true),
124            AccountMeta::new_readonly(system_program::id(), false),
125        ],
126    )
127}
128
129pub fn deposit_ix(
130    program_id: &Pubkey,
131    market: &Pubkey,
132    user: &Pubkey,
133    args: DepositArgs,
134) -> Instruction {
135    build_ix(
136        program_id,
137        "deposit",
138        args,
139        vec![
140            AccountMeta::new(*market, false),
141            AccountMeta::new_readonly(*user, true),
142        ],
143    )
144}
145
146pub fn withdraw_ix(
147    program_id: &Pubkey,
148    market: &Pubkey,
149    user: &Pubkey,
150    args: WithdrawArgs,
151) -> Instruction {
152    build_ix(
153        program_id,
154        "withdraw",
155        args,
156        vec![
157            AccountMeta::new(*market, false),
158            AccountMeta::new_readonly(*user, true),
159        ],
160    )
161}
162
163pub fn trade_ix(
164    program_id: &Pubkey,
165    market: &Pubkey,
166    authority: &Pubkey,
167    args: TradeArgs,
168) -> Instruction {
169    build_ix(
170        program_id,
171        "trade",
172        args,
173        vec![
174            AccountMeta::new(*market, false),
175            AccountMeta::new_readonly(*authority, true),
176        ],
177    )
178}
179
180pub fn crank_ix(
181    program_id: &Pubkey,
182    market: &Pubkey,
183    cranker: &Pubkey,
184    args: CrankArgs,
185) -> Instruction {
186    build_ix(
187        program_id,
188        "crank",
189        args,
190        vec![
191            AccountMeta::new(*market, false),
192            AccountMeta::new_readonly(*cranker, true),
193        ],
194    )
195}
196
197pub fn liquidate_ix(
198    program_id: &Pubkey,
199    market: &Pubkey,
200    liquidator: &Pubkey,
201    args: LiquidateArgs,
202) -> Instruction {
203    build_ix(
204        program_id,
205        "liquidate",
206        args,
207        vec![
208            AccountMeta::new(*market, false),
209            AccountMeta::new_readonly(*liquidator, true),
210        ],
211    )
212}
213
214pub fn settle_ix(
215    program_id: &Pubkey,
216    market: &Pubkey,
217    user: &Pubkey,
218    args: SettleArgs,
219) -> Instruction {
220    build_ix(
221        program_id,
222        "settle",
223        args,
224        vec![
225            AccountMeta::new(*market, false),
226            AccountMeta::new_readonly(*user, true),
227        ],
228    )
229}
230
231pub fn close_account_ix(
232    program_id: &Pubkey,
233    market: &Pubkey,
234    user: &Pubkey,
235    args: CloseAccountArgs,
236) -> Instruction {
237    build_ix(
238        program_id,
239        "close_account",
240        args,
241        vec![
242            AccountMeta::new(*market, false),
243            AccountMeta::new_readonly(*user, true),
244        ],
245    )
246}