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// --- Instruction builders ---
108
109pub fn initialize_market_ix(
110    program_id: &Pubkey,
111    market: &Pubkey,
112    authority: &Pubkey,
113    mint: &Pubkey,
114    vault: &Pubkey,
115    oracle: &Pubkey,
116    matcher: &Pubkey,
117    token_program: &Pubkey,
118    args: InitializeMarketArgs,
119) -> Instruction {
120    build_ix(
121        program_id,
122        "initialize_market",
123        args,
124        vec![
125            AccountMeta::new(*authority, true),
126            AccountMeta::new(*market, false),
127            AccountMeta::new_readonly(*mint, false),
128            AccountMeta::new(*vault, false),
129            AccountMeta::new_readonly(*oracle, false),
130            AccountMeta::new_readonly(*matcher, false),
131            AccountMeta::new_readonly(*token_program, false),
132            AccountMeta::new_readonly(system_program::id(), false),
133        ],
134    )
135}
136
137pub fn deposit_ix(
138    program_id: &Pubkey,
139    market: &Pubkey,
140    user: &Pubkey,
141    mint: &Pubkey,
142    user_token_account: &Pubkey,
143    vault: &Pubkey,
144    token_program: &Pubkey,
145    args: DepositArgs,
146) -> Instruction {
147    build_ix(
148        program_id,
149        "deposit",
150        args,
151        vec![
152            AccountMeta::new(*user, true),
153            AccountMeta::new(*market, false),
154            AccountMeta::new_readonly(*mint, false),
155            AccountMeta::new(*user_token_account, false),
156            AccountMeta::new(*vault, false),
157            AccountMeta::new_readonly(*token_program, false),
158        ],
159    )
160}
161
162pub fn withdraw_ix(
163    program_id: &Pubkey,
164    market: &Pubkey,
165    user: &Pubkey,
166    mint: &Pubkey,
167    user_token_account: &Pubkey,
168    vault: &Pubkey,
169    token_program: &Pubkey,
170    args: WithdrawArgs,
171) -> Instruction {
172    build_ix(
173        program_id,
174        "withdraw",
175        args,
176        vec![
177            AccountMeta::new(*user, true),
178            AccountMeta::new(*market, false),
179            AccountMeta::new_readonly(*mint, false),
180            AccountMeta::new(*user_token_account, false),
181            AccountMeta::new(*vault, false),
182            AccountMeta::new_readonly(*token_program, false),
183        ],
184    )
185}
186
187pub fn trade_ix(
188    program_id: &Pubkey,
189    market: &Pubkey,
190    authority: &Pubkey,
191    args: TradeArgs,
192) -> Instruction {
193    build_ix(
194        program_id,
195        "trade",
196        args,
197        vec![
198            AccountMeta::new(*market, false),
199            AccountMeta::new_readonly(*authority, true),
200        ],
201    )
202}
203
204pub fn crank_ix(
205    program_id: &Pubkey,
206    market: &Pubkey,
207    cranker: &Pubkey,
208    oracle: &Pubkey,
209    args: CrankArgs,
210) -> Instruction {
211    build_ix(
212        program_id,
213        "crank",
214        args,
215        vec![
216            AccountMeta::new_readonly(*cranker, true),
217            AccountMeta::new(*market, false),
218            AccountMeta::new_readonly(*oracle, false),
219        ],
220    )
221}
222
223pub fn liquidate_ix(
224    program_id: &Pubkey,
225    market: &Pubkey,
226    liquidator: &Pubkey,
227    args: LiquidateArgs,
228) -> Instruction {
229    build_ix(
230        program_id,
231        "liquidate",
232        args,
233        vec![
234            AccountMeta::new(*market, false),
235            AccountMeta::new_readonly(*liquidator, true),
236        ],
237    )
238}
239
240pub fn settle_ix(
241    program_id: &Pubkey,
242    market: &Pubkey,
243    user: &Pubkey,
244    args: SettleArgs,
245) -> Instruction {
246    build_ix(
247        program_id,
248        "settle",
249        args,
250        vec![
251            AccountMeta::new(*market, false),
252            AccountMeta::new_readonly(*user, true),
253        ],
254    )
255}
256
257pub fn close_account_ix(
258    program_id: &Pubkey,
259    market: &Pubkey,
260    user: &Pubkey,
261    args: CloseAccountArgs,
262) -> Instruction {
263    build_ix(
264        program_id,
265        "close_account",
266        args,
267        vec![
268            AccountMeta::new(*market, false),
269            AccountMeta::new_readonly(*user, true),
270        ],
271    )
272}