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// --- Instruction builders ---
118
119pub fn initialize_market_ix(
120    program_id: &Pubkey,
121    market: &Pubkey,
122    authority: &Pubkey,
123    mint: &Pubkey,
124    vault: &Pubkey,
125    oracle: &Pubkey,
126    matcher: &Pubkey,
127    token_program: &Pubkey,
128    args: InitializeMarketArgs,
129) -> Instruction {
130    build_ix(
131        program_id,
132        "initialize_market",
133        args,
134        vec![
135            AccountMeta::new(*authority, true),
136            AccountMeta::new(*market, false),
137            AccountMeta::new_readonly(*mint, false),
138            AccountMeta::new(*vault, false),
139            AccountMeta::new_readonly(*oracle, false),
140            AccountMeta::new_readonly(*matcher, false),
141            AccountMeta::new_readonly(*token_program, false),
142            AccountMeta::new_readonly(system_program::id(), false),
143        ],
144    )
145}
146
147pub fn deposit_ix(
148    program_id: &Pubkey,
149    market: &Pubkey,
150    user: &Pubkey,
151    mint: &Pubkey,
152    user_token_account: &Pubkey,
153    vault: &Pubkey,
154    token_program: &Pubkey,
155    args: DepositArgs,
156) -> Instruction {
157    build_ix(
158        program_id,
159        "deposit",
160        args,
161        vec![
162            AccountMeta::new(*user, true),
163            AccountMeta::new(*market, false),
164            AccountMeta::new_readonly(*mint, false),
165            AccountMeta::new(*user_token_account, false),
166            AccountMeta::new(*vault, false),
167            AccountMeta::new_readonly(*token_program, false),
168        ],
169    )
170}
171
172pub fn withdraw_ix(
173    program_id: &Pubkey,
174    market: &Pubkey,
175    user: &Pubkey,
176    mint: &Pubkey,
177    user_token_account: &Pubkey,
178    vault: &Pubkey,
179    token_program: &Pubkey,
180    args: WithdrawArgs,
181) -> Instruction {
182    build_ix(
183        program_id,
184        "withdraw",
185        args,
186        vec![
187            AccountMeta::new(*user, true),
188            AccountMeta::new(*market, false),
189            AccountMeta::new_readonly(*mint, false),
190            AccountMeta::new(*user_token_account, false),
191            AccountMeta::new(*vault, false),
192            AccountMeta::new_readonly(*token_program, false),
193        ],
194    )
195}
196
197pub fn trade_ix(
198    program_id: &Pubkey,
199    market: &Pubkey,
200    authority: &Pubkey,
201    args: TradeArgs,
202) -> Instruction {
203    build_ix(
204        program_id,
205        "trade",
206        args,
207        vec![
208            AccountMeta::new_readonly(*authority, true),
209            AccountMeta::new(*market, false),
210        ],
211    )
212}
213
214pub fn crank_ix(
215    program_id: &Pubkey,
216    market: &Pubkey,
217    cranker: &Pubkey,
218    oracle: &Pubkey,
219    args: CrankArgs,
220) -> Instruction {
221    build_ix(
222        program_id,
223        "crank",
224        args,
225        vec![
226            AccountMeta::new_readonly(*cranker, true),
227            AccountMeta::new(*market, false),
228            AccountMeta::new_readonly(*oracle, false),
229        ],
230    )
231}
232
233pub fn liquidate_ix(
234    program_id: &Pubkey,
235    market: &Pubkey,
236    liquidator: &Pubkey,
237    args: LiquidateArgs,
238) -> Instruction {
239    build_ix(
240        program_id,
241        "liquidate",
242        args,
243        vec![
244            AccountMeta::new_readonly(*liquidator, true),
245            AccountMeta::new(*market, false),
246        ],
247    )
248}
249
250pub fn settle_ix(
251    program_id: &Pubkey,
252    market: &Pubkey,
253    user: &Pubkey,
254    args: SettleArgs,
255) -> Instruction {
256    build_ix(
257        program_id,
258        "settle",
259        args,
260        vec![
261            AccountMeta::new_readonly(*user, true),
262            AccountMeta::new(*market, false),
263        ],
264    )
265}
266
267pub fn close_account_ix(
268    program_id: &Pubkey,
269    market: &Pubkey,
270    user: &Pubkey,
271    args: CloseAccountArgs,
272) -> Instruction {
273    build_ix(
274        program_id,
275        "close_account",
276        args,
277        vec![
278            AccountMeta::new_readonly(*user, true),
279            AccountMeta::new(*market, false),
280        ],
281    )
282}
283
284pub fn reclaim_account_ix(
285    program_id: &Pubkey,
286    market: &Pubkey,
287    reclaimer: &Pubkey,
288    args: ReclaimAccountArgs,
289) -> Instruction {
290    build_ix(
291        program_id,
292        "reclaim_account",
293        args,
294        vec![
295            AccountMeta::new_readonly(*reclaimer, true),
296            AccountMeta::new(*market, false),
297        ],
298    )
299}
300
301pub fn withdraw_insurance_ix(
302    program_id: &Pubkey,
303    market: &Pubkey,
304    authority: &Pubkey,
305    mint: &Pubkey,
306    authority_token_account: &Pubkey,
307    vault: &Pubkey,
308    token_program: &Pubkey,
309    args: WithdrawInsuranceArgs,
310) -> Instruction {
311    build_ix(
312        program_id,
313        "withdraw_insurance",
314        args,
315        vec![
316            AccountMeta::new(*authority, true),
317            AccountMeta::new(*market, false),
318            AccountMeta::new_readonly(*mint, false),
319            AccountMeta::new(*authority_token_account, false),
320            AccountMeta::new(*vault, false),
321            AccountMeta::new_readonly(*token_program, false),
322        ],
323    )
324}