1#![allow(
2 clippy::all,
3 clippy::pedantic,
4 clippy::nursery,
5 clippy::expect_used,
6 clippy::unwrap_used,
7 clippy::indexing_slicing,
8 clippy::allow_attributes,
9 clippy::allow_attributes_without_reason,
10 clippy::mem_forget,
11 unfulfilled_lint_expectations,
12 unexpected_cfgs,
13 unused_imports
14)]
15
16use borsh::BorshDeserialize;
24use borsh::BorshSerialize;
25
26pub const STAKE_DISCRIMINATOR: [u8; 8] =
27 [206, 176, 202, 18, 200, 209, 179, 108];
28
29#[derive(Debug)]
31pub struct Stake {
32 pub user: solana_address::Address,
33 pub payer: solana_address::Address,
34 pub staking_mint: solana_address::Address,
35 pub global_config: solana_address::Address,
36 pub staking_config: solana_address::Address,
37 pub user_stake_position: solana_address::Address,
38 pub user_token_account: solana_address::Address,
39 pub pool_vault: solana_address::Address,
40 pub token_program: solana_address::Address,
41 pub associated_token_program: solana_address::Address,
42 pub system_program: solana_address::Address,
43 pub event_authority: solana_address::Address,
44 pub program: solana_address::Address,
45}
46
47impl Stake {
48 pub fn instruction(
49 &self,
50 args: StakeInstructionArgs,
51 ) -> solana_instruction::Instruction {
52 self.instruction_with_remaining_accounts(args, &[])
53 }
54 #[allow(clippy::arithmetic_side_effects)]
55 #[allow(clippy::vec_init_then_push)]
56 pub fn instruction_with_remaining_accounts(
57 &self,
58 args: StakeInstructionArgs,
59 remaining_accounts: &[solana_instruction::AccountMeta],
60 ) -> solana_instruction::Instruction {
61 let mut accounts = Vec::with_capacity(13 + remaining_accounts.len());
62 accounts.push(solana_instruction::AccountMeta::new_readonly(
63 self.user, true,
64 ));
65 accounts.push(solana_instruction::AccountMeta::new(self.payer, true));
66 accounts.push(solana_instruction::AccountMeta::new_readonly(
67 self.staking_mint,
68 false,
69 ));
70 accounts.push(solana_instruction::AccountMeta::new_readonly(
71 self.global_config,
72 false,
73 ));
74 accounts.push(solana_instruction::AccountMeta::new(
75 self.staking_config,
76 false,
77 ));
78 accounts.push(solana_instruction::AccountMeta::new(
79 self.user_stake_position,
80 false,
81 ));
82 accounts.push(solana_instruction::AccountMeta::new(
83 self.user_token_account,
84 false,
85 ));
86 accounts
87 .push(solana_instruction::AccountMeta::new(self.pool_vault, false));
88 accounts.push(solana_instruction::AccountMeta::new_readonly(
89 self.token_program,
90 false,
91 ));
92 accounts.push(solana_instruction::AccountMeta::new_readonly(
93 self.associated_token_program,
94 false,
95 ));
96 accounts.push(solana_instruction::AccountMeta::new_readonly(
97 self.system_program,
98 false,
99 ));
100 accounts.push(solana_instruction::AccountMeta::new_readonly(
101 self.event_authority,
102 false,
103 ));
104 accounts.push(solana_instruction::AccountMeta::new_readonly(
105 self.program,
106 false,
107 ));
108 accounts.extend_from_slice(remaining_accounts);
109 let mut data = StakeInstructionData::new().try_to_vec().unwrap();
110 let mut args = args.try_to_vec().unwrap();
111 data.append(&mut args);
112
113 solana_instruction::Instruction {
114 program_id: crate::nexus::generated::SEND_NEXUS_ID,
115 accounts,
116 data,
117 }
118 }
119}
120
121#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)]
122#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
123#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
124pub struct StakeInstructionData {
125 discriminator: [u8; 8],
126}
127
128impl StakeInstructionData {
129 pub fn new() -> Self {
130 Self {
131 discriminator: [206, 176, 202, 18, 200, 209, 179, 108],
132 }
133 }
134
135 pub(crate) fn try_to_vec(&self) -> Result<Vec<u8>, std::io::Error> {
136 borsh::to_vec(self)
137 }
138}
139
140impl Default for StakeInstructionData {
141 fn default() -> Self {
142 Self::new()
143 }
144}
145
146#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)]
147#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
148#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
149pub struct StakeInstructionArgs {
150 pub amount: u64,
151}
152
153impl StakeInstructionArgs {
154 pub(crate) fn try_to_vec(&self) -> Result<Vec<u8>, std::io::Error> {
155 borsh::to_vec(self)
156 }
157}
158
159#[derive(Clone, Debug)]
177pub struct StakeBuilder {
178 user: solana_address::Address,
179 payer: solana_address::Address,
180 staking_mint: solana_address::Address,
181 staking_config: Option<solana_address::Address>,
182 user_stake_position: Option<solana_address::Address>,
183 user_token_account: Option<solana_address::Address>,
184 pool_vault: Option<solana_address::Address>,
185 amount: u64,
186 __remaining_accounts: Vec<solana_instruction::AccountMeta>,
187}
188
189impl StakeBuilder {
190 pub fn new(
191 user: solana_address::Address,
192 payer: solana_address::Address,
193 staking_mint: solana_address::Address,
194 amount: u64,
195 ) -> Self {
196 Self {
197 user,
198 payer,
199 staking_mint,
200 staking_config: None,
201 user_stake_position: None,
202 user_token_account: None,
203 pool_vault: None,
204 amount,
205 __remaining_accounts: Vec::new(),
206 }
207 }
208 #[inline(always)]
210 pub fn staking_config(
211 &mut self,
212 staking_config: solana_address::Address,
213 ) -> &mut Self {
214 self.staking_config = Some(staking_config);
215 self
216 }
217 #[inline(always)]
219 pub fn user_stake_position(
220 &mut self,
221 user_stake_position: solana_address::Address,
222 ) -> &mut Self {
223 self.user_stake_position = Some(user_stake_position);
224 self
225 }
226 #[inline(always)]
228 pub fn user_token_account(
229 &mut self,
230 user_token_account: solana_address::Address,
231 ) -> &mut Self {
232 self.user_token_account = Some(user_token_account);
233 self
234 }
235 #[inline(always)]
237 pub fn pool_vault(
238 &mut self,
239 pool_vault: solana_address::Address,
240 ) -> &mut Self {
241 self.pool_vault = Some(pool_vault);
242 self
243 }
244 #[inline(always)]
246 pub fn add_remaining_account(
247 &mut self,
248 account: solana_instruction::AccountMeta,
249 ) -> &mut Self {
250 self.__remaining_accounts.push(account);
251 self
252 }
253 #[inline(always)]
255 pub fn add_remaining_accounts(
256 &mut self,
257 accounts: &[solana_instruction::AccountMeta],
258 ) -> &mut Self {
259 self.__remaining_accounts.extend_from_slice(accounts);
260 self
261 }
262 #[allow(clippy::clone_on_copy)]
263 pub fn instruction(&self) -> solana_instruction::Instruction {
264 let user = self.user;
265 let payer = self.payer;
266 let staking_mint = self.staking_mint;
267 let global_config =
268 crate::nexus::generated::pdas::GLOBAL_CONFIG_ADDRESS;
269 let staking_config = self
270 .staking_config
271 .unwrap_or(crate::nexus::generated::pdas::STAKING_CONFIG_ADDRESS);
272 let user_stake_position =
273 self.user_stake_position.unwrap_or_else(|| {
274 crate::nexus::generated::pdas::find_user_stake_position_pda(
275 &self.user,
276 &self.staking_mint,
277 )
278 .0
279 });
280 let user_token_account = self.user_token_account.unwrap_or_else(|| {
281 solana_address::Address::find_program_address(
282 &[
283 self.user.as_ref(),
284 &[
285 6, 221, 246, 225, 238, 117, 143, 222, 24, 66, 93, 188,
286 228, 108, 205, 218, 182, 26, 252, 77, 131, 185, 13, 39,
287 254, 189, 249, 40, 216, 161, 139, 252,
288 ],
289 self.staking_mint.as_ref(),
290 ],
291 &solana_address::address!(
292 "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"
293 ),
294 )
295 .0
296 });
297 let pool_vault = self.pool_vault.unwrap_or_else(|| {
298 solana_address::Address::find_program_address(
299 &[
300 staking_config.as_ref(),
301 &[
302 6, 221, 246, 225, 238, 117, 143, 222, 24, 66, 93, 188,
303 228, 108, 205, 218, 182, 26, 252, 77, 131, 185, 13, 39,
304 254, 189, 249, 40, 216, 161, 139, 252,
305 ],
306 self.staking_mint.as_ref(),
307 ],
308 &solana_address::address!(
309 "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"
310 ),
311 )
312 .0
313 });
314 let token_program = solana_address::address!(
315 "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb"
316 );
317 let associated_token_program = solana_address::address!(
318 "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"
319 );
320 let system_program =
321 solana_address::address!("11111111111111111111111111111111");
322 let event_authority =
323 crate::nexus::generated::pdas::EVENT_AUTHORITY_ADDRESS;
324 let program = solana_address::address!(
325 "7rrCurqdWFesbzwtYPo95fM8waTtVXgXwCom45x1sfNX"
326 );
327 let accounts = Stake {
328 user,
329 payer,
330 staking_mint,
331 global_config,
332 staking_config,
333 user_stake_position,
334 user_token_account,
335 pool_vault,
336 token_program,
337 associated_token_program,
338 system_program,
339 event_authority,
340 program,
341 };
342 let args = StakeInstructionArgs {
343 amount: self.amount.clone(),
344 };
345
346 accounts.instruction_with_remaining_accounts(
347 args,
348 &self.__remaining_accounts,
349 )
350 }
351}
352
353pub struct StakeCpiAccounts<'a, 'b> {
355 pub user: &'b solana_program::account_info::AccountInfo<'a>,
356 pub payer: &'b solana_program::account_info::AccountInfo<'a>,
357 pub staking_mint: &'b solana_program::account_info::AccountInfo<'a>,
358 pub global_config: &'b solana_program::account_info::AccountInfo<'a>,
359 pub staking_config: &'b solana_program::account_info::AccountInfo<'a>,
360 pub user_stake_position: &'b solana_program::account_info::AccountInfo<'a>,
361 pub user_token_account: &'b solana_program::account_info::AccountInfo<'a>,
362 pub pool_vault: &'b solana_program::account_info::AccountInfo<'a>,
363 pub token_program: &'b solana_program::account_info::AccountInfo<'a>,
364 pub associated_token_program:
365 &'b solana_program::account_info::AccountInfo<'a>,
366 pub system_program: &'b solana_program::account_info::AccountInfo<'a>,
367 pub event_authority: &'b solana_program::account_info::AccountInfo<'a>,
368 pub program: &'b solana_program::account_info::AccountInfo<'a>,
369}
370
371pub struct StakeCpi<'a, 'b> {
373 pub __program: &'b solana_program::account_info::AccountInfo<'a>,
375 pub user: &'b solana_program::account_info::AccountInfo<'a>,
376 pub payer: &'b solana_program::account_info::AccountInfo<'a>,
377 pub staking_mint: &'b solana_program::account_info::AccountInfo<'a>,
378 pub global_config: &'b solana_program::account_info::AccountInfo<'a>,
379 pub staking_config: &'b solana_program::account_info::AccountInfo<'a>,
380 pub user_stake_position: &'b solana_program::account_info::AccountInfo<'a>,
381 pub user_token_account: &'b solana_program::account_info::AccountInfo<'a>,
382 pub pool_vault: &'b solana_program::account_info::AccountInfo<'a>,
383 pub token_program: &'b solana_program::account_info::AccountInfo<'a>,
384 pub associated_token_program:
385 &'b solana_program::account_info::AccountInfo<'a>,
386 pub system_program: &'b solana_program::account_info::AccountInfo<'a>,
387 pub event_authority: &'b solana_program::account_info::AccountInfo<'a>,
388 pub program: &'b solana_program::account_info::AccountInfo<'a>,
389 pub __args: StakeInstructionArgs,
391}
392
393impl<'a, 'b> StakeCpi<'a, 'b> {
394 pub fn new(
395 program: &'b solana_program::account_info::AccountInfo<'a>,
396 accounts: StakeCpiAccounts<'a, 'b>,
397 args: StakeInstructionArgs,
398 ) -> Self {
399 Self {
400 __program: program,
401 user: accounts.user,
402 payer: accounts.payer,
403 staking_mint: accounts.staking_mint,
404 global_config: accounts.global_config,
405 staking_config: accounts.staking_config,
406 user_stake_position: accounts.user_stake_position,
407 user_token_account: accounts.user_token_account,
408 pool_vault: accounts.pool_vault,
409 token_program: accounts.token_program,
410 associated_token_program: accounts.associated_token_program,
411 system_program: accounts.system_program,
412 event_authority: accounts.event_authority,
413 program: accounts.program,
414 __args: args,
415 }
416 }
417 #[inline(always)]
418 pub fn invoke(&self) -> solana_program::entrypoint::ProgramResult {
419 self.invoke_signed_with_remaining_accounts(&[], &[])
420 }
421 #[inline(always)]
422 pub fn invoke_with_remaining_accounts(
423 &self,
424 remaining_accounts: &[(
425 &'b solana_program::account_info::AccountInfo<'a>,
426 bool,
427 bool,
428 )],
429 ) -> solana_program::entrypoint::ProgramResult {
430 self.invoke_signed_with_remaining_accounts(&[], remaining_accounts)
431 }
432 #[inline(always)]
433 pub fn invoke_signed(
434 &self,
435 signers_seeds: &[&[&[u8]]],
436 ) -> solana_program::entrypoint::ProgramResult {
437 self.invoke_signed_with_remaining_accounts(signers_seeds, &[])
438 }
439 #[allow(clippy::arithmetic_side_effects)]
440 #[allow(clippy::clone_on_copy)]
441 #[allow(clippy::vec_init_then_push)]
442 pub fn invoke_signed_with_remaining_accounts(
443 &self,
444 signers_seeds: &[&[&[u8]]],
445 remaining_accounts: &[(
446 &'b solana_program::account_info::AccountInfo<'a>,
447 bool,
448 bool,
449 )],
450 ) -> solana_program::entrypoint::ProgramResult {
451 let mut accounts = Vec::with_capacity(13 + remaining_accounts.len());
452 accounts.push(solana_instruction::AccountMeta::new_readonly(
453 *self.user.key,
454 true,
455 ));
456 accounts
457 .push(solana_instruction::AccountMeta::new(*self.payer.key, true));
458 accounts.push(solana_instruction::AccountMeta::new_readonly(
459 *self.staking_mint.key,
460 false,
461 ));
462 accounts.push(solana_instruction::AccountMeta::new_readonly(
463 *self.global_config.key,
464 false,
465 ));
466 accounts.push(solana_instruction::AccountMeta::new(
467 *self.staking_config.key,
468 false,
469 ));
470 accounts.push(solana_instruction::AccountMeta::new(
471 *self.user_stake_position.key,
472 false,
473 ));
474 accounts.push(solana_instruction::AccountMeta::new(
475 *self.user_token_account.key,
476 false,
477 ));
478 accounts.push(solana_instruction::AccountMeta::new(
479 *self.pool_vault.key,
480 false,
481 ));
482 accounts.push(solana_instruction::AccountMeta::new_readonly(
483 *self.token_program.key,
484 false,
485 ));
486 accounts.push(solana_instruction::AccountMeta::new_readonly(
487 *self.associated_token_program.key,
488 false,
489 ));
490 accounts.push(solana_instruction::AccountMeta::new_readonly(
491 *self.system_program.key,
492 false,
493 ));
494 accounts.push(solana_instruction::AccountMeta::new_readonly(
495 *self.event_authority.key,
496 false,
497 ));
498 accounts.push(solana_instruction::AccountMeta::new_readonly(
499 *self.program.key,
500 false,
501 ));
502 remaining_accounts.iter().for_each(|remaining_account| {
503 accounts.push(solana_instruction::AccountMeta {
504 pubkey: *remaining_account.0.key,
505 is_writable: remaining_account.1,
506 is_signer: remaining_account.2,
507 })
508 });
509 let mut data = StakeInstructionData::new().try_to_vec().unwrap();
510 let mut args = self.__args.try_to_vec().unwrap();
511 data.append(&mut args);
512
513 let instruction = solana_instruction::Instruction {
514 program_id: crate::nexus::generated::SEND_NEXUS_ID,
515 accounts,
516 data,
517 };
518 let mut account_infos =
519 Vec::with_capacity(14 + remaining_accounts.len());
520 account_infos.push(self.__program.clone());
521 account_infos.push(self.user.clone());
522 account_infos.push(self.payer.clone());
523 account_infos.push(self.staking_mint.clone());
524 account_infos.push(self.global_config.clone());
525 account_infos.push(self.staking_config.clone());
526 account_infos.push(self.user_stake_position.clone());
527 account_infos.push(self.user_token_account.clone());
528 account_infos.push(self.pool_vault.clone());
529 account_infos.push(self.token_program.clone());
530 account_infos.push(self.associated_token_program.clone());
531 account_infos.push(self.system_program.clone());
532 account_infos.push(self.event_authority.clone());
533 account_infos.push(self.program.clone());
534 remaining_accounts.iter().for_each(|remaining_account| {
535 account_infos.push(remaining_account.0.clone())
536 });
537
538 if signers_seeds.is_empty() {
539 solana_program::program::invoke(&instruction, &account_infos)
540 } else {
541 solana_program::program::invoke_signed(
542 &instruction,
543 &account_infos,
544 signers_seeds,
545 )
546 }
547 }
548}
549
550#[derive(Clone, Debug)]
568pub struct StakeCpiBuilder<'a, 'b> {
569 instruction: Box<StakeCpiBuilderInstruction<'a, 'b>>,
570}
571
572impl<'a, 'b> StakeCpiBuilder<'a, 'b> {
573 pub fn new(
574 __program: &'b solana_program::account_info::AccountInfo<'a>,
575 user: &'b solana_program::account_info::AccountInfo<'a>,
576 payer: &'b solana_program::account_info::AccountInfo<'a>,
577 staking_mint: &'b solana_program::account_info::AccountInfo<'a>,
578 global_config: &'b solana_program::account_info::AccountInfo<'a>,
579 staking_config: &'b solana_program::account_info::AccountInfo<'a>,
580 user_stake_position: &'b solana_program::account_info::AccountInfo<'a>,
581 user_token_account: &'b solana_program::account_info::AccountInfo<'a>,
582 pool_vault: &'b solana_program::account_info::AccountInfo<'a>,
583 token_program: &'b solana_program::account_info::AccountInfo<'a>,
584 associated_token_program: &'b solana_program::account_info::AccountInfo<
585 'a,
586 >,
587 system_program: &'b solana_program::account_info::AccountInfo<'a>,
588 event_authority: &'b solana_program::account_info::AccountInfo<'a>,
589 program: &'b solana_program::account_info::AccountInfo<'a>,
590 amount: u64,
591 ) -> Self {
592 let instruction = Box::new(StakeCpiBuilderInstruction {
593 __program,
594 user,
595 payer,
596 staking_mint,
597 global_config,
598 staking_config,
599 user_stake_position,
600 user_token_account,
601 pool_vault,
602 token_program,
603 associated_token_program,
604 system_program,
605 event_authority,
606 program,
607 amount,
608 __remaining_accounts: Vec::new(),
609 });
610 Self { instruction }
611 }
612 #[inline(always)]
614 pub fn add_remaining_account(
615 &mut self,
616 account: &'b solana_program::account_info::AccountInfo<'a>,
617 is_writable: bool,
618 is_signer: bool,
619 ) -> &mut Self {
620 self.instruction.__remaining_accounts.push((
621 account,
622 is_writable,
623 is_signer,
624 ));
625 self
626 }
627 #[inline(always)]
632 pub fn add_remaining_accounts(
633 &mut self,
634 accounts: &[(
635 &'b solana_program::account_info::AccountInfo<'a>,
636 bool,
637 bool,
638 )],
639 ) -> &mut Self {
640 self.instruction
641 .__remaining_accounts
642 .extend_from_slice(accounts);
643 self
644 }
645 #[inline(always)]
646 pub fn invoke(&self) -> solana_program::entrypoint::ProgramResult {
647 self.invoke_signed(&[])
648 }
649 #[allow(clippy::clone_on_copy)]
650 #[allow(clippy::vec_init_then_push)]
651 pub fn invoke_signed(
652 &self,
653 signers_seeds: &[&[&[u8]]],
654 ) -> solana_program::entrypoint::ProgramResult {
655 let args = StakeInstructionArgs {
656 amount: self.instruction.amount.clone(),
657 };
658 let instruction = StakeCpi {
659 __program: self.instruction.__program,
660 user: self.instruction.user,
661 payer: self.instruction.payer,
662 staking_mint: self.instruction.staking_mint,
663 global_config: self.instruction.global_config,
664 staking_config: self.instruction.staking_config,
665 user_stake_position: self.instruction.user_stake_position,
666 user_token_account: self.instruction.user_token_account,
667 pool_vault: self.instruction.pool_vault,
668 token_program: self.instruction.token_program,
669 associated_token_program: self.instruction.associated_token_program,
670 system_program: self.instruction.system_program,
671 event_authority: self.instruction.event_authority,
672 program: self.instruction.program,
673 __args: args,
674 };
675 instruction.invoke_signed_with_remaining_accounts(
676 signers_seeds,
677 &self.instruction.__remaining_accounts,
678 )
679 }
680}
681
682#[derive(Clone, Debug)]
683struct StakeCpiBuilderInstruction<'a, 'b> {
684 __program: &'b solana_program::account_info::AccountInfo<'a>,
685 user: &'b solana_program::account_info::AccountInfo<'a>,
686 payer: &'b solana_program::account_info::AccountInfo<'a>,
687 staking_mint: &'b solana_program::account_info::AccountInfo<'a>,
688 global_config: &'b solana_program::account_info::AccountInfo<'a>,
689 staking_config: &'b solana_program::account_info::AccountInfo<'a>,
690 user_stake_position: &'b solana_program::account_info::AccountInfo<'a>,
691 user_token_account: &'b solana_program::account_info::AccountInfo<'a>,
692 pool_vault: &'b solana_program::account_info::AccountInfo<'a>,
693 token_program: &'b solana_program::account_info::AccountInfo<'a>,
694 associated_token_program: &'b solana_program::account_info::AccountInfo<'a>,
695 system_program: &'b solana_program::account_info::AccountInfo<'a>,
696 event_authority: &'b solana_program::account_info::AccountInfo<'a>,
697 program: &'b solana_program::account_info::AccountInfo<'a>,
698 amount: u64,
699 __remaining_accounts: Vec<(
701 &'b solana_program::account_info::AccountInfo<'a>,
702 bool,
703 bool,
704 )>,
705}