1use borsh::BorshDeserialize;
9use borsh::BorshSerialize;
10
11pub const UNSTAKE_DISCRIMINATOR: u8 = 1;
12
13#[derive(Debug)]
15pub struct Unstake {
16 pub unstaker_account: solana_pubkey::Pubkey,
17
18 pub state_account: solana_pubkey::Pubkey,
19
20 pub pending_withdraw_account: solana_pubkey::Pubkey,
21
22 pub unstaker_xorca_ata: solana_pubkey::Pubkey,
23
24 pub xorca_mint_account: solana_pubkey::Pubkey,
25
26 pub orca_mint_account: solana_pubkey::Pubkey,
27
28 pub vault_account: solana_pubkey::Pubkey,
29
30 pub system_program_account: solana_pubkey::Pubkey,
31
32 pub token_program_account: solana_pubkey::Pubkey,
33}
34
35impl Unstake {
36 pub fn instruction(&self, args: UnstakeInstructionArgs) -> solana_instruction::Instruction {
37 self.instruction_with_remaining_accounts(args, &[])
38 }
39 #[allow(clippy::arithmetic_side_effects)]
40 #[allow(clippy::vec_init_then_push)]
41 pub fn instruction_with_remaining_accounts(
42 &self,
43 args: UnstakeInstructionArgs,
44 remaining_accounts: &[solana_instruction::AccountMeta],
45 ) -> solana_instruction::Instruction {
46 let mut accounts = Vec::with_capacity(9 + remaining_accounts.len());
47 accounts.push(solana_instruction::AccountMeta::new(
48 self.unstaker_account,
49 true,
50 ));
51 accounts.push(solana_instruction::AccountMeta::new(
52 self.state_account,
53 false,
54 ));
55 accounts.push(solana_instruction::AccountMeta::new(
56 self.pending_withdraw_account,
57 false,
58 ));
59 accounts.push(solana_instruction::AccountMeta::new(
60 self.unstaker_xorca_ata,
61 false,
62 ));
63 accounts.push(solana_instruction::AccountMeta::new(
64 self.xorca_mint_account,
65 false,
66 ));
67 accounts.push(solana_instruction::AccountMeta::new_readonly(
68 self.orca_mint_account,
69 false,
70 ));
71 accounts.push(solana_instruction::AccountMeta::new_readonly(
72 self.vault_account,
73 false,
74 ));
75 accounts.push(solana_instruction::AccountMeta::new_readonly(
76 self.system_program_account,
77 false,
78 ));
79 accounts.push(solana_instruction::AccountMeta::new_readonly(
80 self.token_program_account,
81 false,
82 ));
83 accounts.extend_from_slice(remaining_accounts);
84 let mut data = borsh::to_vec(&UnstakeInstructionData::new()).unwrap();
85 let mut args = borsh::to_vec(&args).unwrap();
86 data.append(&mut args);
87
88 solana_instruction::Instruction {
89 program_id: crate::XORCA_STAKING_PROGRAM_ID,
90 accounts,
91 data,
92 }
93 }
94}
95
96#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)]
97#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
98pub struct UnstakeInstructionData {
99 discriminator: u8,
100}
101
102impl UnstakeInstructionData {
103 pub fn new() -> Self {
104 Self { discriminator: 1 }
105 }
106}
107
108impl Default for UnstakeInstructionData {
109 fn default() -> Self {
110 Self::new()
111 }
112}
113
114#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)]
115#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
116pub struct UnstakeInstructionArgs {
117 pub xorca_unstake_amount: u64,
118 pub withdraw_index: u8,
119}
120
121#[derive(Clone, Debug, Default)]
135pub struct UnstakeBuilder {
136 unstaker_account: Option<solana_pubkey::Pubkey>,
137 state_account: Option<solana_pubkey::Pubkey>,
138 pending_withdraw_account: Option<solana_pubkey::Pubkey>,
139 unstaker_xorca_ata: Option<solana_pubkey::Pubkey>,
140 xorca_mint_account: Option<solana_pubkey::Pubkey>,
141 orca_mint_account: Option<solana_pubkey::Pubkey>,
142 vault_account: Option<solana_pubkey::Pubkey>,
143 system_program_account: Option<solana_pubkey::Pubkey>,
144 token_program_account: Option<solana_pubkey::Pubkey>,
145 xorca_unstake_amount: Option<u64>,
146 withdraw_index: Option<u8>,
147 __remaining_accounts: Vec<solana_instruction::AccountMeta>,
148}
149
150impl UnstakeBuilder {
151 pub fn new() -> Self {
152 Self::default()
153 }
154 #[inline(always)]
155 pub fn unstaker_account(&mut self, unstaker_account: solana_pubkey::Pubkey) -> &mut Self {
156 self.unstaker_account = Some(unstaker_account);
157 self
158 }
159 #[inline(always)]
160 pub fn state_account(&mut self, state_account: solana_pubkey::Pubkey) -> &mut Self {
161 self.state_account = Some(state_account);
162 self
163 }
164 #[inline(always)]
165 pub fn pending_withdraw_account(
166 &mut self,
167 pending_withdraw_account: solana_pubkey::Pubkey,
168 ) -> &mut Self {
169 self.pending_withdraw_account = Some(pending_withdraw_account);
170 self
171 }
172 #[inline(always)]
173 pub fn unstaker_xorca_ata(&mut self, unstaker_xorca_ata: solana_pubkey::Pubkey) -> &mut Self {
174 self.unstaker_xorca_ata = Some(unstaker_xorca_ata);
175 self
176 }
177 #[inline(always)]
178 pub fn xorca_mint_account(&mut self, xorca_mint_account: solana_pubkey::Pubkey) -> &mut Self {
179 self.xorca_mint_account = Some(xorca_mint_account);
180 self
181 }
182 #[inline(always)]
183 pub fn orca_mint_account(&mut self, orca_mint_account: solana_pubkey::Pubkey) -> &mut Self {
184 self.orca_mint_account = Some(orca_mint_account);
185 self
186 }
187 #[inline(always)]
188 pub fn vault_account(&mut self, vault_account: solana_pubkey::Pubkey) -> &mut Self {
189 self.vault_account = Some(vault_account);
190 self
191 }
192 #[inline(always)]
193 pub fn system_program_account(
194 &mut self,
195 system_program_account: solana_pubkey::Pubkey,
196 ) -> &mut Self {
197 self.system_program_account = Some(system_program_account);
198 self
199 }
200 #[inline(always)]
201 pub fn token_program_account(
202 &mut self,
203 token_program_account: solana_pubkey::Pubkey,
204 ) -> &mut Self {
205 self.token_program_account = Some(token_program_account);
206 self
207 }
208 #[inline(always)]
209 pub fn xorca_unstake_amount(&mut self, xorca_unstake_amount: u64) -> &mut Self {
210 self.xorca_unstake_amount = Some(xorca_unstake_amount);
211 self
212 }
213 #[inline(always)]
214 pub fn withdraw_index(&mut self, withdraw_index: u8) -> &mut Self {
215 self.withdraw_index = Some(withdraw_index);
216 self
217 }
218 #[inline(always)]
220 pub fn add_remaining_account(&mut self, account: solana_instruction::AccountMeta) -> &mut Self {
221 self.__remaining_accounts.push(account);
222 self
223 }
224 #[inline(always)]
226 pub fn add_remaining_accounts(
227 &mut self,
228 accounts: &[solana_instruction::AccountMeta],
229 ) -> &mut Self {
230 self.__remaining_accounts.extend_from_slice(accounts);
231 self
232 }
233 #[allow(clippy::clone_on_copy)]
234 pub fn instruction(&self) -> solana_instruction::Instruction {
235 let accounts = Unstake {
236 unstaker_account: self.unstaker_account.expect("unstaker_account is not set"),
237 state_account: self.state_account.expect("state_account is not set"),
238 pending_withdraw_account: self
239 .pending_withdraw_account
240 .expect("pending_withdraw_account is not set"),
241 unstaker_xorca_ata: self
242 .unstaker_xorca_ata
243 .expect("unstaker_xorca_ata is not set"),
244 xorca_mint_account: self
245 .xorca_mint_account
246 .expect("xorca_mint_account is not set"),
247 orca_mint_account: self
248 .orca_mint_account
249 .expect("orca_mint_account is not set"),
250 vault_account: self.vault_account.expect("vault_account is not set"),
251 system_program_account: self
252 .system_program_account
253 .expect("system_program_account is not set"),
254 token_program_account: self
255 .token_program_account
256 .expect("token_program_account is not set"),
257 };
258 let args = UnstakeInstructionArgs {
259 xorca_unstake_amount: self
260 .xorca_unstake_amount
261 .clone()
262 .expect("xorca_unstake_amount is not set"),
263 withdraw_index: self
264 .withdraw_index
265 .clone()
266 .expect("withdraw_index is not set"),
267 };
268
269 accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts)
270 }
271}
272
273pub struct UnstakeCpiAccounts<'a, 'b> {
275 pub unstaker_account: &'b solana_account_info::AccountInfo<'a>,
276
277 pub state_account: &'b solana_account_info::AccountInfo<'a>,
278
279 pub pending_withdraw_account: &'b solana_account_info::AccountInfo<'a>,
280
281 pub unstaker_xorca_ata: &'b solana_account_info::AccountInfo<'a>,
282
283 pub xorca_mint_account: &'b solana_account_info::AccountInfo<'a>,
284
285 pub orca_mint_account: &'b solana_account_info::AccountInfo<'a>,
286
287 pub vault_account: &'b solana_account_info::AccountInfo<'a>,
288
289 pub system_program_account: &'b solana_account_info::AccountInfo<'a>,
290
291 pub token_program_account: &'b solana_account_info::AccountInfo<'a>,
292}
293
294pub struct UnstakeCpi<'a, 'b> {
296 pub __program: &'b solana_account_info::AccountInfo<'a>,
298
299 pub unstaker_account: &'b solana_account_info::AccountInfo<'a>,
300
301 pub state_account: &'b solana_account_info::AccountInfo<'a>,
302
303 pub pending_withdraw_account: &'b solana_account_info::AccountInfo<'a>,
304
305 pub unstaker_xorca_ata: &'b solana_account_info::AccountInfo<'a>,
306
307 pub xorca_mint_account: &'b solana_account_info::AccountInfo<'a>,
308
309 pub orca_mint_account: &'b solana_account_info::AccountInfo<'a>,
310
311 pub vault_account: &'b solana_account_info::AccountInfo<'a>,
312
313 pub system_program_account: &'b solana_account_info::AccountInfo<'a>,
314
315 pub token_program_account: &'b solana_account_info::AccountInfo<'a>,
316 pub __args: UnstakeInstructionArgs,
318}
319
320impl<'a, 'b> UnstakeCpi<'a, 'b> {
321 pub fn new(
322 program: &'b solana_account_info::AccountInfo<'a>,
323 accounts: UnstakeCpiAccounts<'a, 'b>,
324 args: UnstakeInstructionArgs,
325 ) -> Self {
326 Self {
327 __program: program,
328 unstaker_account: accounts.unstaker_account,
329 state_account: accounts.state_account,
330 pending_withdraw_account: accounts.pending_withdraw_account,
331 unstaker_xorca_ata: accounts.unstaker_xorca_ata,
332 xorca_mint_account: accounts.xorca_mint_account,
333 orca_mint_account: accounts.orca_mint_account,
334 vault_account: accounts.vault_account,
335 system_program_account: accounts.system_program_account,
336 token_program_account: accounts.token_program_account,
337 __args: args,
338 }
339 }
340 #[inline(always)]
341 pub fn invoke(&self) -> solana_program_error::ProgramResult {
342 self.invoke_signed_with_remaining_accounts(&[], &[])
343 }
344 #[inline(always)]
345 pub fn invoke_with_remaining_accounts(
346 &self,
347 remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)],
348 ) -> solana_program_error::ProgramResult {
349 self.invoke_signed_with_remaining_accounts(&[], remaining_accounts)
350 }
351 #[inline(always)]
352 pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult {
353 self.invoke_signed_with_remaining_accounts(signers_seeds, &[])
354 }
355 #[allow(clippy::arithmetic_side_effects)]
356 #[allow(clippy::clone_on_copy)]
357 #[allow(clippy::vec_init_then_push)]
358 pub fn invoke_signed_with_remaining_accounts(
359 &self,
360 signers_seeds: &[&[&[u8]]],
361 remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)],
362 ) -> solana_program_error::ProgramResult {
363 let mut accounts = Vec::with_capacity(9 + remaining_accounts.len());
364 accounts.push(solana_instruction::AccountMeta::new(
365 *self.unstaker_account.key,
366 true,
367 ));
368 accounts.push(solana_instruction::AccountMeta::new(
369 *self.state_account.key,
370 false,
371 ));
372 accounts.push(solana_instruction::AccountMeta::new(
373 *self.pending_withdraw_account.key,
374 false,
375 ));
376 accounts.push(solana_instruction::AccountMeta::new(
377 *self.unstaker_xorca_ata.key,
378 false,
379 ));
380 accounts.push(solana_instruction::AccountMeta::new(
381 *self.xorca_mint_account.key,
382 false,
383 ));
384 accounts.push(solana_instruction::AccountMeta::new_readonly(
385 *self.orca_mint_account.key,
386 false,
387 ));
388 accounts.push(solana_instruction::AccountMeta::new_readonly(
389 *self.vault_account.key,
390 false,
391 ));
392 accounts.push(solana_instruction::AccountMeta::new_readonly(
393 *self.system_program_account.key,
394 false,
395 ));
396 accounts.push(solana_instruction::AccountMeta::new_readonly(
397 *self.token_program_account.key,
398 false,
399 ));
400 remaining_accounts.iter().for_each(|remaining_account| {
401 accounts.push(solana_instruction::AccountMeta {
402 pubkey: *remaining_account.0.key,
403 is_signer: remaining_account.1,
404 is_writable: remaining_account.2,
405 })
406 });
407 let mut data = borsh::to_vec(&UnstakeInstructionData::new()).unwrap();
408 let mut args = borsh::to_vec(&self.__args).unwrap();
409 data.append(&mut args);
410
411 let instruction = solana_instruction::Instruction {
412 program_id: crate::XORCA_STAKING_PROGRAM_ID,
413 accounts,
414 data,
415 };
416 let mut account_infos = Vec::with_capacity(10 + remaining_accounts.len());
417 account_infos.push(self.__program.clone());
418 account_infos.push(self.unstaker_account.clone());
419 account_infos.push(self.state_account.clone());
420 account_infos.push(self.pending_withdraw_account.clone());
421 account_infos.push(self.unstaker_xorca_ata.clone());
422 account_infos.push(self.xorca_mint_account.clone());
423 account_infos.push(self.orca_mint_account.clone());
424 account_infos.push(self.vault_account.clone());
425 account_infos.push(self.system_program_account.clone());
426 account_infos.push(self.token_program_account.clone());
427 remaining_accounts
428 .iter()
429 .for_each(|remaining_account| account_infos.push(remaining_account.0.clone()));
430
431 if signers_seeds.is_empty() {
432 solana_cpi::invoke(&instruction, &account_infos)
433 } else {
434 solana_cpi::invoke_signed(&instruction, &account_infos, signers_seeds)
435 }
436 }
437}
438
439#[derive(Clone, Debug)]
453pub struct UnstakeCpiBuilder<'a, 'b> {
454 instruction: Box<UnstakeCpiBuilderInstruction<'a, 'b>>,
455}
456
457impl<'a, 'b> UnstakeCpiBuilder<'a, 'b> {
458 pub fn new(program: &'b solana_account_info::AccountInfo<'a>) -> Self {
459 let instruction = Box::new(UnstakeCpiBuilderInstruction {
460 __program: program,
461 unstaker_account: None,
462 state_account: None,
463 pending_withdraw_account: None,
464 unstaker_xorca_ata: None,
465 xorca_mint_account: None,
466 orca_mint_account: None,
467 vault_account: None,
468 system_program_account: None,
469 token_program_account: None,
470 xorca_unstake_amount: None,
471 withdraw_index: None,
472 __remaining_accounts: Vec::new(),
473 });
474 Self { instruction }
475 }
476 #[inline(always)]
477 pub fn unstaker_account(
478 &mut self,
479 unstaker_account: &'b solana_account_info::AccountInfo<'a>,
480 ) -> &mut Self {
481 self.instruction.unstaker_account = Some(unstaker_account);
482 self
483 }
484 #[inline(always)]
485 pub fn state_account(
486 &mut self,
487 state_account: &'b solana_account_info::AccountInfo<'a>,
488 ) -> &mut Self {
489 self.instruction.state_account = Some(state_account);
490 self
491 }
492 #[inline(always)]
493 pub fn pending_withdraw_account(
494 &mut self,
495 pending_withdraw_account: &'b solana_account_info::AccountInfo<'a>,
496 ) -> &mut Self {
497 self.instruction.pending_withdraw_account = Some(pending_withdraw_account);
498 self
499 }
500 #[inline(always)]
501 pub fn unstaker_xorca_ata(
502 &mut self,
503 unstaker_xorca_ata: &'b solana_account_info::AccountInfo<'a>,
504 ) -> &mut Self {
505 self.instruction.unstaker_xorca_ata = Some(unstaker_xorca_ata);
506 self
507 }
508 #[inline(always)]
509 pub fn xorca_mint_account(
510 &mut self,
511 xorca_mint_account: &'b solana_account_info::AccountInfo<'a>,
512 ) -> &mut Self {
513 self.instruction.xorca_mint_account = Some(xorca_mint_account);
514 self
515 }
516 #[inline(always)]
517 pub fn orca_mint_account(
518 &mut self,
519 orca_mint_account: &'b solana_account_info::AccountInfo<'a>,
520 ) -> &mut Self {
521 self.instruction.orca_mint_account = Some(orca_mint_account);
522 self
523 }
524 #[inline(always)]
525 pub fn vault_account(
526 &mut self,
527 vault_account: &'b solana_account_info::AccountInfo<'a>,
528 ) -> &mut Self {
529 self.instruction.vault_account = Some(vault_account);
530 self
531 }
532 #[inline(always)]
533 pub fn system_program_account(
534 &mut self,
535 system_program_account: &'b solana_account_info::AccountInfo<'a>,
536 ) -> &mut Self {
537 self.instruction.system_program_account = Some(system_program_account);
538 self
539 }
540 #[inline(always)]
541 pub fn token_program_account(
542 &mut self,
543 token_program_account: &'b solana_account_info::AccountInfo<'a>,
544 ) -> &mut Self {
545 self.instruction.token_program_account = Some(token_program_account);
546 self
547 }
548 #[inline(always)]
549 pub fn xorca_unstake_amount(&mut self, xorca_unstake_amount: u64) -> &mut Self {
550 self.instruction.xorca_unstake_amount = Some(xorca_unstake_amount);
551 self
552 }
553 #[inline(always)]
554 pub fn withdraw_index(&mut self, withdraw_index: u8) -> &mut Self {
555 self.instruction.withdraw_index = Some(withdraw_index);
556 self
557 }
558 #[inline(always)]
560 pub fn add_remaining_account(
561 &mut self,
562 account: &'b solana_account_info::AccountInfo<'a>,
563 is_writable: bool,
564 is_signer: bool,
565 ) -> &mut Self {
566 self.instruction
567 .__remaining_accounts
568 .push((account, is_writable, is_signer));
569 self
570 }
571 #[inline(always)]
576 pub fn add_remaining_accounts(
577 &mut self,
578 accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)],
579 ) -> &mut Self {
580 self.instruction
581 .__remaining_accounts
582 .extend_from_slice(accounts);
583 self
584 }
585 #[inline(always)]
586 pub fn invoke(&self) -> solana_program_error::ProgramResult {
587 self.invoke_signed(&[])
588 }
589 #[allow(clippy::clone_on_copy)]
590 #[allow(clippy::vec_init_then_push)]
591 pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult {
592 let args = UnstakeInstructionArgs {
593 xorca_unstake_amount: self
594 .instruction
595 .xorca_unstake_amount
596 .clone()
597 .expect("xorca_unstake_amount is not set"),
598 withdraw_index: self
599 .instruction
600 .withdraw_index
601 .clone()
602 .expect("withdraw_index is not set"),
603 };
604 let instruction = UnstakeCpi {
605 __program: self.instruction.__program,
606
607 unstaker_account: self
608 .instruction
609 .unstaker_account
610 .expect("unstaker_account is not set"),
611
612 state_account: self
613 .instruction
614 .state_account
615 .expect("state_account is not set"),
616
617 pending_withdraw_account: self
618 .instruction
619 .pending_withdraw_account
620 .expect("pending_withdraw_account is not set"),
621
622 unstaker_xorca_ata: self
623 .instruction
624 .unstaker_xorca_ata
625 .expect("unstaker_xorca_ata is not set"),
626
627 xorca_mint_account: self
628 .instruction
629 .xorca_mint_account
630 .expect("xorca_mint_account is not set"),
631
632 orca_mint_account: self
633 .instruction
634 .orca_mint_account
635 .expect("orca_mint_account is not set"),
636
637 vault_account: self
638 .instruction
639 .vault_account
640 .expect("vault_account is not set"),
641
642 system_program_account: self
643 .instruction
644 .system_program_account
645 .expect("system_program_account is not set"),
646
647 token_program_account: self
648 .instruction
649 .token_program_account
650 .expect("token_program_account is not set"),
651 __args: args,
652 };
653 instruction.invoke_signed_with_remaining_accounts(
654 signers_seeds,
655 &self.instruction.__remaining_accounts,
656 )
657 }
658}
659
660#[derive(Clone, Debug)]
661struct UnstakeCpiBuilderInstruction<'a, 'b> {
662 __program: &'b solana_account_info::AccountInfo<'a>,
663 unstaker_account: Option<&'b solana_account_info::AccountInfo<'a>>,
664 state_account: Option<&'b solana_account_info::AccountInfo<'a>>,
665 pending_withdraw_account: Option<&'b solana_account_info::AccountInfo<'a>>,
666 unstaker_xorca_ata: Option<&'b solana_account_info::AccountInfo<'a>>,
667 xorca_mint_account: Option<&'b solana_account_info::AccountInfo<'a>>,
668 orca_mint_account: Option<&'b solana_account_info::AccountInfo<'a>>,
669 vault_account: Option<&'b solana_account_info::AccountInfo<'a>>,
670 system_program_account: Option<&'b solana_account_info::AccountInfo<'a>>,
671 token_program_account: Option<&'b solana_account_info::AccountInfo<'a>>,
672 xorca_unstake_amount: Option<u64>,
673 withdraw_index: Option<u8>,
674 __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>,
676}