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 SETTLE_DISCRIMINATOR: [u8; 8] =
27 [175, 42, 185, 87, 144, 131, 102, 212];
28
29#[derive(Debug)]
31pub struct Settle {
32 pub user: solana_address::Address,
33 pub payer: solana_address::Address,
34 pub staking_mint: solana_address::Address,
35 pub reward_mint: solana_address::Address,
36 pub staking_config: solana_address::Address,
37 pub user_stake_position: solana_address::Address,
38 pub launchpad_reward_accrual: solana_address::Address,
39 pub dex_reward_accrual: solana_address::Address,
40 pub user_reward_debt: solana_address::Address,
41}
42
43impl Settle {
44 pub fn instruction(&self) -> solana_instruction::Instruction {
45 self.instruction_with_remaining_accounts(&[])
46 }
47 #[allow(clippy::arithmetic_side_effects)]
48 #[allow(clippy::vec_init_then_push)]
49 pub fn instruction_with_remaining_accounts(
50 &self,
51 remaining_accounts: &[solana_instruction::AccountMeta],
52 ) -> solana_instruction::Instruction {
53 let mut accounts = Vec::with_capacity(9 + remaining_accounts.len());
54 accounts.push(solana_instruction::AccountMeta::new_readonly(
55 self.user, false,
56 ));
57 accounts.push(solana_instruction::AccountMeta::new(self.payer, true));
58 accounts.push(solana_instruction::AccountMeta::new_readonly(
59 self.staking_mint,
60 false,
61 ));
62 accounts.push(solana_instruction::AccountMeta::new_readonly(
63 self.reward_mint,
64 false,
65 ));
66 accounts.push(solana_instruction::AccountMeta::new_readonly(
67 self.staking_config,
68 false,
69 ));
70 accounts.push(solana_instruction::AccountMeta::new(
71 self.user_stake_position,
72 false,
73 ));
74 accounts.push(solana_instruction::AccountMeta::new_readonly(
75 self.launchpad_reward_accrual,
76 false,
77 ));
78 accounts.push(solana_instruction::AccountMeta::new_readonly(
79 self.dex_reward_accrual,
80 false,
81 ));
82 accounts.push(solana_instruction::AccountMeta::new(
83 self.user_reward_debt,
84 false,
85 ));
86 accounts.extend_from_slice(remaining_accounts);
87 let data = SettleInstructionData::new().try_to_vec().unwrap();
88
89 solana_instruction::Instruction {
90 program_id: crate::nexus::generated::SEND_NEXUS_ID,
91 accounts,
92 data,
93 }
94 }
95}
96
97#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)]
98#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
99#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
100pub struct SettleInstructionData {
101 discriminator: [u8; 8],
102}
103
104impl SettleInstructionData {
105 pub fn new() -> Self {
106 Self {
107 discriminator: [175, 42, 185, 87, 144, 131, 102, 212],
108 }
109 }
110
111 pub(crate) fn try_to_vec(&self) -> Result<Vec<u8>, std::io::Error> {
112 borsh::to_vec(self)
113 }
114}
115
116impl Default for SettleInstructionData {
117 fn default() -> Self {
118 Self::new()
119 }
120}
121
122#[derive(Clone, Debug)]
136pub struct SettleBuilder {
137 user: solana_address::Address,
138 payer: solana_address::Address,
139 staking_mint: solana_address::Address,
140 reward_mint: solana_address::Address,
141 user_stake_position: Option<solana_address::Address>,
142 launchpad_reward_accrual: Option<solana_address::Address>,
143 dex_reward_accrual: Option<solana_address::Address>,
144 user_reward_debt: Option<solana_address::Address>,
145 __remaining_accounts: Vec<solana_instruction::AccountMeta>,
146}
147
148impl SettleBuilder {
149 pub fn new(
150 user: solana_address::Address,
151 payer: solana_address::Address,
152 staking_mint: solana_address::Address,
153 reward_mint: solana_address::Address,
154 ) -> Self {
155 Self {
156 user,
157 payer,
158 staking_mint,
159 reward_mint,
160 user_stake_position: None,
161 launchpad_reward_accrual: None,
162 dex_reward_accrual: None,
163 user_reward_debt: None,
164 __remaining_accounts: Vec::new(),
165 }
166 }
167 #[inline(always)]
169 pub fn user_stake_position(
170 &mut self,
171 user_stake_position: solana_address::Address,
172 ) -> &mut Self {
173 self.user_stake_position = Some(user_stake_position);
174 self
175 }
176 #[inline(always)]
178 pub fn launchpad_reward_accrual(
179 &mut self,
180 launchpad_reward_accrual: solana_address::Address,
181 ) -> &mut Self {
182 self.launchpad_reward_accrual = Some(launchpad_reward_accrual);
183 self
184 }
185 #[inline(always)]
187 pub fn dex_reward_accrual(
188 &mut self,
189 dex_reward_accrual: solana_address::Address,
190 ) -> &mut Self {
191 self.dex_reward_accrual = Some(dex_reward_accrual);
192 self
193 }
194 #[inline(always)]
196 pub fn user_reward_debt(
197 &mut self,
198 user_reward_debt: solana_address::Address,
199 ) -> &mut Self {
200 self.user_reward_debt = Some(user_reward_debt);
201 self
202 }
203 #[inline(always)]
205 pub fn add_remaining_account(
206 &mut self,
207 account: solana_instruction::AccountMeta,
208 ) -> &mut Self {
209 self.__remaining_accounts.push(account);
210 self
211 }
212 #[inline(always)]
214 pub fn add_remaining_accounts(
215 &mut self,
216 accounts: &[solana_instruction::AccountMeta],
217 ) -> &mut Self {
218 self.__remaining_accounts.extend_from_slice(accounts);
219 self
220 }
221 #[allow(clippy::clone_on_copy)]
222 pub fn instruction(&self) -> solana_instruction::Instruction {
223 let user = self.user;
224 let payer = self.payer;
225 let staking_mint = self.staking_mint;
226 let reward_mint = self.reward_mint;
227 let staking_config =
228 crate::nexus::generated::pdas::STAKING_CONFIG_ADDRESS;
229 let user_stake_position =
230 self.user_stake_position.unwrap_or_else(|| {
231 crate::nexus::generated::pdas::find_user_stake_position_pda(
232 &self.user,
233 &self.staking_mint,
234 )
235 .0
236 });
237 let launchpad_reward_accrual =
238 self.launchpad_reward_accrual.unwrap_or_else(|| {
239 solana_address::Address::find_program_address(
240 &[
241 &[
242 114, 101, 119, 97, 114, 100, 95, 97, 99, 99, 114,
243 117, 97, 108,
244 ],
245 self.reward_mint.as_ref(),
246 ],
247 &solana_address::address!(
248 "5R1uFyEE4oxqkm7hJDqHq6gXaLVF9dxeF3LF4yz1sfLP"
249 ),
250 )
251 .0
252 });
253 let dex_reward_accrual = self.dex_reward_accrual.unwrap_or_else(|| {
254 solana_address::Address::find_program_address(
255 &[
256 &[
257 114, 101, 119, 97, 114, 100, 95, 97, 99, 99, 114, 117,
258 97, 108,
259 ],
260 self.reward_mint.as_ref(),
261 ],
262 &solana_address::address!(
263 "84qj5FPZZdXkQy8mfowyg6RBZ3XKuTds6XS4ZYT1sfDX"
264 ),
265 )
266 .0
267 });
268 let user_reward_debt = self.user_reward_debt.unwrap_or_else(|| {
269 crate::nexus::generated::pdas::find_user_reward_debt_pda(
270 &self.user,
271 &self.staking_mint,
272 &self.reward_mint,
273 )
274 .0
275 });
276 let accounts = Settle {
277 user,
278 payer,
279 staking_mint,
280 reward_mint,
281 staking_config,
282 user_stake_position,
283 launchpad_reward_accrual,
284 dex_reward_accrual,
285 user_reward_debt,
286 };
287
288 accounts.instruction_with_remaining_accounts(&self.__remaining_accounts)
289 }
290}
291
292pub struct SettleCpiAccounts<'a, 'b> {
294 pub user: &'b solana_program::account_info::AccountInfo<'a>,
295 pub payer: &'b solana_program::account_info::AccountInfo<'a>,
296 pub staking_mint: &'b solana_program::account_info::AccountInfo<'a>,
297 pub reward_mint: &'b solana_program::account_info::AccountInfo<'a>,
298 pub staking_config: &'b solana_program::account_info::AccountInfo<'a>,
299 pub user_stake_position: &'b solana_program::account_info::AccountInfo<'a>,
300 pub launchpad_reward_accrual:
301 &'b solana_program::account_info::AccountInfo<'a>,
302 pub dex_reward_accrual: &'b solana_program::account_info::AccountInfo<'a>,
303 pub user_reward_debt: &'b solana_program::account_info::AccountInfo<'a>,
304}
305
306pub struct SettleCpi<'a, 'b> {
308 pub __program: &'b solana_program::account_info::AccountInfo<'a>,
310 pub user: &'b solana_program::account_info::AccountInfo<'a>,
311 pub payer: &'b solana_program::account_info::AccountInfo<'a>,
312 pub staking_mint: &'b solana_program::account_info::AccountInfo<'a>,
313 pub reward_mint: &'b solana_program::account_info::AccountInfo<'a>,
314 pub staking_config: &'b solana_program::account_info::AccountInfo<'a>,
315 pub user_stake_position: &'b solana_program::account_info::AccountInfo<'a>,
316 pub launchpad_reward_accrual:
317 &'b solana_program::account_info::AccountInfo<'a>,
318 pub dex_reward_accrual: &'b solana_program::account_info::AccountInfo<'a>,
319 pub user_reward_debt: &'b solana_program::account_info::AccountInfo<'a>,
320}
321
322impl<'a, 'b> SettleCpi<'a, 'b> {
323 pub fn new(
324 program: &'b solana_program::account_info::AccountInfo<'a>,
325 accounts: SettleCpiAccounts<'a, 'b>,
326 ) -> Self {
327 Self {
328 __program: program,
329 user: accounts.user,
330 payer: accounts.payer,
331 staking_mint: accounts.staking_mint,
332 reward_mint: accounts.reward_mint,
333 staking_config: accounts.staking_config,
334 user_stake_position: accounts.user_stake_position,
335 launchpad_reward_accrual: accounts.launchpad_reward_accrual,
336 dex_reward_accrual: accounts.dex_reward_accrual,
337 user_reward_debt: accounts.user_reward_debt,
338 }
339 }
340 #[inline(always)]
341 pub fn invoke(&self) -> solana_program::entrypoint::ProgramResult {
342 self.invoke_signed_with_remaining_accounts(&[], &[])
343 }
344 #[inline(always)]
345 pub fn invoke_with_remaining_accounts(
346 &self,
347 remaining_accounts: &[(
348 &'b solana_program::account_info::AccountInfo<'a>,
349 bool,
350 bool,
351 )],
352 ) -> solana_program::entrypoint::ProgramResult {
353 self.invoke_signed_with_remaining_accounts(&[], remaining_accounts)
354 }
355 #[inline(always)]
356 pub fn invoke_signed(
357 &self,
358 signers_seeds: &[&[&[u8]]],
359 ) -> solana_program::entrypoint::ProgramResult {
360 self.invoke_signed_with_remaining_accounts(signers_seeds, &[])
361 }
362 #[allow(clippy::arithmetic_side_effects)]
363 #[allow(clippy::clone_on_copy)]
364 #[allow(clippy::vec_init_then_push)]
365 pub fn invoke_signed_with_remaining_accounts(
366 &self,
367 signers_seeds: &[&[&[u8]]],
368 remaining_accounts: &[(
369 &'b solana_program::account_info::AccountInfo<'a>,
370 bool,
371 bool,
372 )],
373 ) -> solana_program::entrypoint::ProgramResult {
374 let mut accounts = Vec::with_capacity(9 + remaining_accounts.len());
375 accounts.push(solana_instruction::AccountMeta::new_readonly(
376 *self.user.key,
377 false,
378 ));
379 accounts
380 .push(solana_instruction::AccountMeta::new(*self.payer.key, true));
381 accounts.push(solana_instruction::AccountMeta::new_readonly(
382 *self.staking_mint.key,
383 false,
384 ));
385 accounts.push(solana_instruction::AccountMeta::new_readonly(
386 *self.reward_mint.key,
387 false,
388 ));
389 accounts.push(solana_instruction::AccountMeta::new_readonly(
390 *self.staking_config.key,
391 false,
392 ));
393 accounts.push(solana_instruction::AccountMeta::new(
394 *self.user_stake_position.key,
395 false,
396 ));
397 accounts.push(solana_instruction::AccountMeta::new_readonly(
398 *self.launchpad_reward_accrual.key,
399 false,
400 ));
401 accounts.push(solana_instruction::AccountMeta::new_readonly(
402 *self.dex_reward_accrual.key,
403 false,
404 ));
405 accounts.push(solana_instruction::AccountMeta::new(
406 *self.user_reward_debt.key,
407 false,
408 ));
409 remaining_accounts.iter().for_each(|remaining_account| {
410 accounts.push(solana_instruction::AccountMeta {
411 pubkey: *remaining_account.0.key,
412 is_writable: remaining_account.1,
413 is_signer: remaining_account.2,
414 })
415 });
416 let data = SettleInstructionData::new().try_to_vec().unwrap();
417
418 let instruction = solana_instruction::Instruction {
419 program_id: crate::nexus::generated::SEND_NEXUS_ID,
420 accounts,
421 data,
422 };
423 let mut account_infos =
424 Vec::with_capacity(10 + remaining_accounts.len());
425 account_infos.push(self.__program.clone());
426 account_infos.push(self.user.clone());
427 account_infos.push(self.payer.clone());
428 account_infos.push(self.staking_mint.clone());
429 account_infos.push(self.reward_mint.clone());
430 account_infos.push(self.staking_config.clone());
431 account_infos.push(self.user_stake_position.clone());
432 account_infos.push(self.launchpad_reward_accrual.clone());
433 account_infos.push(self.dex_reward_accrual.clone());
434 account_infos.push(self.user_reward_debt.clone());
435 remaining_accounts.iter().for_each(|remaining_account| {
436 account_infos.push(remaining_account.0.clone())
437 });
438
439 if signers_seeds.is_empty() {
440 solana_program::program::invoke(&instruction, &account_infos)
441 } else {
442 solana_program::program::invoke_signed(
443 &instruction,
444 &account_infos,
445 signers_seeds,
446 )
447 }
448 }
449}
450
451#[derive(Clone, Debug)]
465pub struct SettleCpiBuilder<'a, 'b> {
466 instruction: Box<SettleCpiBuilderInstruction<'a, 'b>>,
467}
468
469impl<'a, 'b> SettleCpiBuilder<'a, 'b> {
470 pub fn new(
471 __program: &'b solana_program::account_info::AccountInfo<'a>,
472 user: &'b solana_program::account_info::AccountInfo<'a>,
473 payer: &'b solana_program::account_info::AccountInfo<'a>,
474 staking_mint: &'b solana_program::account_info::AccountInfo<'a>,
475 reward_mint: &'b solana_program::account_info::AccountInfo<'a>,
476 staking_config: &'b solana_program::account_info::AccountInfo<'a>,
477 user_stake_position: &'b solana_program::account_info::AccountInfo<'a>,
478 launchpad_reward_accrual: &'b solana_program::account_info::AccountInfo<
479 'a,
480 >,
481 dex_reward_accrual: &'b solana_program::account_info::AccountInfo<'a>,
482 user_reward_debt: &'b solana_program::account_info::AccountInfo<'a>,
483 ) -> Self {
484 let instruction = Box::new(SettleCpiBuilderInstruction {
485 __program,
486 user,
487 payer,
488 staking_mint,
489 reward_mint,
490 staking_config,
491 user_stake_position,
492 launchpad_reward_accrual,
493 dex_reward_accrual,
494 user_reward_debt,
495 __remaining_accounts: Vec::new(),
496 });
497 Self { instruction }
498 }
499 #[inline(always)]
501 pub fn add_remaining_account(
502 &mut self,
503 account: &'b solana_program::account_info::AccountInfo<'a>,
504 is_writable: bool,
505 is_signer: bool,
506 ) -> &mut Self {
507 self.instruction.__remaining_accounts.push((
508 account,
509 is_writable,
510 is_signer,
511 ));
512 self
513 }
514 #[inline(always)]
519 pub fn add_remaining_accounts(
520 &mut self,
521 accounts: &[(
522 &'b solana_program::account_info::AccountInfo<'a>,
523 bool,
524 bool,
525 )],
526 ) -> &mut Self {
527 self.instruction
528 .__remaining_accounts
529 .extend_from_slice(accounts);
530 self
531 }
532 #[inline(always)]
533 pub fn invoke(&self) -> solana_program::entrypoint::ProgramResult {
534 self.invoke_signed(&[])
535 }
536 #[allow(clippy::clone_on_copy)]
537 #[allow(clippy::vec_init_then_push)]
538 pub fn invoke_signed(
539 &self,
540 signers_seeds: &[&[&[u8]]],
541 ) -> solana_program::entrypoint::ProgramResult {
542 let instruction = SettleCpi {
543 __program: self.instruction.__program,
544 user: self.instruction.user,
545 payer: self.instruction.payer,
546 staking_mint: self.instruction.staking_mint,
547 reward_mint: self.instruction.reward_mint,
548 staking_config: self.instruction.staking_config,
549 user_stake_position: self.instruction.user_stake_position,
550 launchpad_reward_accrual: self.instruction.launchpad_reward_accrual,
551 dex_reward_accrual: self.instruction.dex_reward_accrual,
552 user_reward_debt: self.instruction.user_reward_debt,
553 };
554 instruction.invoke_signed_with_remaining_accounts(
555 signers_seeds,
556 &self.instruction.__remaining_accounts,
557 )
558 }
559}
560
561#[derive(Clone, Debug)]
562struct SettleCpiBuilderInstruction<'a, 'b> {
563 __program: &'b solana_program::account_info::AccountInfo<'a>,
564 user: &'b solana_program::account_info::AccountInfo<'a>,
565 payer: &'b solana_program::account_info::AccountInfo<'a>,
566 staking_mint: &'b solana_program::account_info::AccountInfo<'a>,
567 reward_mint: &'b solana_program::account_info::AccountInfo<'a>,
568 staking_config: &'b solana_program::account_info::AccountInfo<'a>,
569 user_stake_position: &'b solana_program::account_info::AccountInfo<'a>,
570 launchpad_reward_accrual: &'b solana_program::account_info::AccountInfo<'a>,
571 dex_reward_accrual: &'b solana_program::account_info::AccountInfo<'a>,
572 user_reward_debt: &'b solana_program::account_info::AccountInfo<'a>,
573 __remaining_accounts: Vec<(
575 &'b solana_program::account_info::AccountInfo<'a>,
576 bool,
577 bool,
578 )>,
579}