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: u64,
67}
68
69#[derive(BorshSerialize)]
70pub struct WithdrawArgs {
71    pub account_idx: u16,
72    pub amount: u64,
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 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    mint: &Pubkey,
133    user_token_account: &Pubkey,
134    vault: &Pubkey,
135    token_program: &Pubkey,
136    args: DepositArgs,
137) -> Instruction {
138    build_ix(
139        program_id,
140        "deposit",
141        args,
142        vec![
143            AccountMeta::new(*user, true),
144            AccountMeta::new(*market, false),
145            AccountMeta::new_readonly(*mint, false),
146            AccountMeta::new(*user_token_account, false),
147            AccountMeta::new(*vault, false),
148            AccountMeta::new_readonly(*token_program, false),
149        ],
150    )
151}
152
153pub fn withdraw_ix(
154    program_id: &Pubkey,
155    market: &Pubkey,
156    user: &Pubkey,
157    mint: &Pubkey,
158    user_token_account: &Pubkey,
159    vault: &Pubkey,
160    token_program: &Pubkey,
161    args: WithdrawArgs,
162) -> Instruction {
163    build_ix(
164        program_id,
165        "withdraw",
166        args,
167        vec![
168            AccountMeta::new(*user, true),
169            AccountMeta::new(*market, false),
170            AccountMeta::new_readonly(*mint, false),
171            AccountMeta::new(*user_token_account, false),
172            AccountMeta::new(*vault, false),
173            AccountMeta::new_readonly(*token_program, false),
174        ],
175    )
176}
177
178pub fn trade_ix(
179    program_id: &Pubkey,
180    market: &Pubkey,
181    authority: &Pubkey,
182    args: TradeArgs,
183) -> Instruction {
184    build_ix(
185        program_id,
186        "trade",
187        args,
188        vec![
189            AccountMeta::new(*market, false),
190            AccountMeta::new_readonly(*authority, true),
191        ],
192    )
193}
194
195pub fn crank_ix(
196    program_id: &Pubkey,
197    market: &Pubkey,
198    cranker: &Pubkey,
199    oracle: &Pubkey,
200    args: CrankArgs,
201) -> Instruction {
202    build_ix(
203        program_id,
204        "crank",
205        args,
206        vec![
207            AccountMeta::new_readonly(*cranker, true),
208            AccountMeta::new(*market, false),
209            AccountMeta::new_readonly(*oracle, false),
210        ],
211    )
212}
213
214pub fn liquidate_ix(
215    program_id: &Pubkey,
216    market: &Pubkey,
217    liquidator: &Pubkey,
218    args: LiquidateArgs,
219) -> Instruction {
220    build_ix(
221        program_id,
222        "liquidate",
223        args,
224        vec![
225            AccountMeta::new(*market, false),
226            AccountMeta::new_readonly(*liquidator, true),
227        ],
228    )
229}
230
231pub fn settle_ix(
232    program_id: &Pubkey,
233    market: &Pubkey,
234    user: &Pubkey,
235    args: SettleArgs,
236) -> Instruction {
237    build_ix(
238        program_id,
239        "settle",
240        args,
241        vec![
242            AccountMeta::new(*market, false),
243            AccountMeta::new_readonly(*user, true),
244        ],
245    )
246}
247
248pub fn close_account_ix(
249    program_id: &Pubkey,
250    market: &Pubkey,
251    user: &Pubkey,
252    args: CloseAccountArgs,
253) -> Instruction {
254    build_ix(
255        program_id,
256        "close_account",
257        args,
258        vec![
259            AccountMeta::new(*market, false),
260            AccountMeta::new_readonly(*user, true),
261        ],
262    )
263}