1use borsh::BorshSerialize;
9use borsh::BorshDeserialize;
10
11#[derive(Debug)]
13pub struct CompoundReward {
14
15
16 pub authority: solana_pubkey::Pubkey,
17
18
19 pub treasury: solana_pubkey::Pubkey,
20
21
22 pub position: solana_pubkey::Pubkey,
23
24
25 pub staked_token_mint: solana_pubkey::Pubkey,
26
27
28 pub reward_token_mint: solana_pubkey::Pubkey,
29
30
31 pub treasury_staked_token_account: solana_pubkey::Pubkey,
32
33
34 pub treasury_reward_token_account: solana_pubkey::Pubkey,
35
36
37 pub fusionamm_program: solana_pubkey::Pubkey,
38
39
40 pub fusion_pool: solana_pubkey::Pubkey,
41
42
43 pub token_program: solana_pubkey::Pubkey,
44
45
46 pub memo_program: solana_pubkey::Pubkey,
47 }
48
49impl CompoundReward {
50 pub fn instruction(&self) -> solana_instruction::Instruction {
51 self.instruction_with_remaining_accounts(&[])
52 }
53 #[allow(clippy::arithmetic_side_effects)]
54 #[allow(clippy::vec_init_then_push)]
55 pub fn instruction_with_remaining_accounts(&self, remaining_accounts: &[solana_instruction::AccountMeta]) -> solana_instruction::Instruction {
56 let mut accounts = Vec::with_capacity(11+ remaining_accounts.len());
57 accounts.push(solana_instruction::AccountMeta::new(
58 self.authority,
59 true
60 ));
61 accounts.push(solana_instruction::AccountMeta::new(
62 self.treasury,
63 false
64 ));
65 accounts.push(solana_instruction::AccountMeta::new(
66 self.position,
67 false
68 ));
69 accounts.push(solana_instruction::AccountMeta::new_readonly(
70 self.staked_token_mint,
71 false
72 ));
73 accounts.push(solana_instruction::AccountMeta::new_readonly(
74 self.reward_token_mint,
75 false
76 ));
77 accounts.push(solana_instruction::AccountMeta::new(
78 self.treasury_staked_token_account,
79 false
80 ));
81 accounts.push(solana_instruction::AccountMeta::new(
82 self.treasury_reward_token_account,
83 false
84 ));
85 accounts.push(solana_instruction::AccountMeta::new_readonly(
86 self.fusionamm_program,
87 false
88 ));
89 accounts.push(solana_instruction::AccountMeta::new(
90 self.fusion_pool,
91 false
92 ));
93 accounts.push(solana_instruction::AccountMeta::new_readonly(
94 self.token_program,
95 false
96 ));
97 accounts.push(solana_instruction::AccountMeta::new_readonly(
98 self.memo_program,
99 false
100 ));
101 accounts.extend_from_slice(remaining_accounts);
102 let data = borsh::to_vec(&CompoundRewardInstructionData::new()).unwrap();
103
104 solana_instruction::Instruction {
105 program_id: crate::TUNA_STAKING_ID,
106 accounts,
107 data,
108 }
109 }
110}
111
112#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)]
113#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
114 pub struct CompoundRewardInstructionData {
115 discriminator: [u8; 8],
116 }
117
118impl CompoundRewardInstructionData {
119 pub fn new() -> Self {
120 Self {
121 discriminator: [212, 94, 182, 117, 15, 25, 31, 96],
122 }
123 }
124}
125
126impl Default for CompoundRewardInstructionData {
127 fn default() -> Self {
128 Self::new()
129 }
130}
131
132
133
134#[derive(Clone, Debug, Default)]
150pub struct CompoundRewardBuilder {
151 authority: Option<solana_pubkey::Pubkey>,
152 treasury: Option<solana_pubkey::Pubkey>,
153 position: Option<solana_pubkey::Pubkey>,
154 staked_token_mint: Option<solana_pubkey::Pubkey>,
155 reward_token_mint: Option<solana_pubkey::Pubkey>,
156 treasury_staked_token_account: Option<solana_pubkey::Pubkey>,
157 treasury_reward_token_account: Option<solana_pubkey::Pubkey>,
158 fusionamm_program: Option<solana_pubkey::Pubkey>,
159 fusion_pool: Option<solana_pubkey::Pubkey>,
160 token_program: Option<solana_pubkey::Pubkey>,
161 memo_program: Option<solana_pubkey::Pubkey>,
162 __remaining_accounts: Vec<solana_instruction::AccountMeta>,
163}
164
165impl CompoundRewardBuilder {
166 pub fn new() -> Self {
167 Self::default()
168 }
169 #[inline(always)]
170 pub fn authority(&mut self, authority: solana_pubkey::Pubkey) -> &mut Self {
171 self.authority = Some(authority);
172 self
173 }
174 #[inline(always)]
175 pub fn treasury(&mut self, treasury: solana_pubkey::Pubkey) -> &mut Self {
176 self.treasury = Some(treasury);
177 self
178 }
179 #[inline(always)]
180 pub fn position(&mut self, position: solana_pubkey::Pubkey) -> &mut Self {
181 self.position = Some(position);
182 self
183 }
184 #[inline(always)]
185 pub fn staked_token_mint(&mut self, staked_token_mint: solana_pubkey::Pubkey) -> &mut Self {
186 self.staked_token_mint = Some(staked_token_mint);
187 self
188 }
189 #[inline(always)]
190 pub fn reward_token_mint(&mut self, reward_token_mint: solana_pubkey::Pubkey) -> &mut Self {
191 self.reward_token_mint = Some(reward_token_mint);
192 self
193 }
194 #[inline(always)]
195 pub fn treasury_staked_token_account(&mut self, treasury_staked_token_account: solana_pubkey::Pubkey) -> &mut Self {
196 self.treasury_staked_token_account = Some(treasury_staked_token_account);
197 self
198 }
199 #[inline(always)]
200 pub fn treasury_reward_token_account(&mut self, treasury_reward_token_account: solana_pubkey::Pubkey) -> &mut Self {
201 self.treasury_reward_token_account = Some(treasury_reward_token_account);
202 self
203 }
204 #[inline(always)]
205 pub fn fusionamm_program(&mut self, fusionamm_program: solana_pubkey::Pubkey) -> &mut Self {
206 self.fusionamm_program = Some(fusionamm_program);
207 self
208 }
209 #[inline(always)]
210 pub fn fusion_pool(&mut self, fusion_pool: solana_pubkey::Pubkey) -> &mut Self {
211 self.fusion_pool = Some(fusion_pool);
212 self
213 }
214 #[inline(always)]
216 pub fn token_program(&mut self, token_program: solana_pubkey::Pubkey) -> &mut Self {
217 self.token_program = Some(token_program);
218 self
219 }
220 #[inline(always)]
221 pub fn memo_program(&mut self, memo_program: solana_pubkey::Pubkey) -> &mut Self {
222 self.memo_program = Some(memo_program);
223 self
224 }
225 #[inline(always)]
227 pub fn add_remaining_account(&mut self, account: solana_instruction::AccountMeta) -> &mut Self {
228 self.__remaining_accounts.push(account);
229 self
230 }
231 #[inline(always)]
233 pub fn add_remaining_accounts(&mut self, accounts: &[solana_instruction::AccountMeta]) -> &mut Self {
234 self.__remaining_accounts.extend_from_slice(accounts);
235 self
236 }
237 #[allow(clippy::clone_on_copy)]
238 pub fn instruction(&self) -> solana_instruction::Instruction {
239 let accounts = CompoundReward {
240 authority: self.authority.expect("authority is not set"),
241 treasury: self.treasury.expect("treasury is not set"),
242 position: self.position.expect("position is not set"),
243 staked_token_mint: self.staked_token_mint.expect("staked_token_mint is not set"),
244 reward_token_mint: self.reward_token_mint.expect("reward_token_mint is not set"),
245 treasury_staked_token_account: self.treasury_staked_token_account.expect("treasury_staked_token_account is not set"),
246 treasury_reward_token_account: self.treasury_reward_token_account.expect("treasury_reward_token_account is not set"),
247 fusionamm_program: self.fusionamm_program.expect("fusionamm_program is not set"),
248 fusion_pool: self.fusion_pool.expect("fusion_pool is not set"),
249 token_program: self.token_program.unwrap_or(solana_pubkey::pubkey!("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA")),
250 memo_program: self.memo_program.expect("memo_program is not set"),
251 };
252
253 accounts.instruction_with_remaining_accounts(&self.__remaining_accounts)
254 }
255}
256
257 pub struct CompoundRewardCpiAccounts<'a, 'b> {
259
260
261 pub authority: &'b solana_account_info::AccountInfo<'a>,
262
263
264 pub treasury: &'b solana_account_info::AccountInfo<'a>,
265
266
267 pub position: &'b solana_account_info::AccountInfo<'a>,
268
269
270 pub staked_token_mint: &'b solana_account_info::AccountInfo<'a>,
271
272
273 pub reward_token_mint: &'b solana_account_info::AccountInfo<'a>,
274
275
276 pub treasury_staked_token_account: &'b solana_account_info::AccountInfo<'a>,
277
278
279 pub treasury_reward_token_account: &'b solana_account_info::AccountInfo<'a>,
280
281
282 pub fusionamm_program: &'b solana_account_info::AccountInfo<'a>,
283
284
285 pub fusion_pool: &'b solana_account_info::AccountInfo<'a>,
286
287
288 pub token_program: &'b solana_account_info::AccountInfo<'a>,
289
290
291 pub memo_program: &'b solana_account_info::AccountInfo<'a>,
292 }
293
294pub struct CompoundRewardCpi<'a, 'b> {
296 pub __program: &'b solana_account_info::AccountInfo<'a>,
298
299
300 pub authority: &'b solana_account_info::AccountInfo<'a>,
301
302
303 pub treasury: &'b solana_account_info::AccountInfo<'a>,
304
305
306 pub position: &'b solana_account_info::AccountInfo<'a>,
307
308
309 pub staked_token_mint: &'b solana_account_info::AccountInfo<'a>,
310
311
312 pub reward_token_mint: &'b solana_account_info::AccountInfo<'a>,
313
314
315 pub treasury_staked_token_account: &'b solana_account_info::AccountInfo<'a>,
316
317
318 pub treasury_reward_token_account: &'b solana_account_info::AccountInfo<'a>,
319
320
321 pub fusionamm_program: &'b solana_account_info::AccountInfo<'a>,
322
323
324 pub fusion_pool: &'b solana_account_info::AccountInfo<'a>,
325
326
327 pub token_program: &'b solana_account_info::AccountInfo<'a>,
328
329
330 pub memo_program: &'b solana_account_info::AccountInfo<'a>,
331 }
332
333impl<'a, 'b> CompoundRewardCpi<'a, 'b> {
334 pub fn new(
335 program: &'b solana_account_info::AccountInfo<'a>,
336 accounts: CompoundRewardCpiAccounts<'a, 'b>,
337 ) -> Self {
338 Self {
339 __program: program,
340 authority: accounts.authority,
341 treasury: accounts.treasury,
342 position: accounts.position,
343 staked_token_mint: accounts.staked_token_mint,
344 reward_token_mint: accounts.reward_token_mint,
345 treasury_staked_token_account: accounts.treasury_staked_token_account,
346 treasury_reward_token_account: accounts.treasury_reward_token_account,
347 fusionamm_program: accounts.fusionamm_program,
348 fusion_pool: accounts.fusion_pool,
349 token_program: accounts.token_program,
350 memo_program: accounts.memo_program,
351 }
352 }
353 #[inline(always)]
354 pub fn invoke(&self) -> solana_program_entrypoint::ProgramResult {
355 self.invoke_signed_with_remaining_accounts(&[], &[])
356 }
357 #[inline(always)]
358 pub fn invoke_with_remaining_accounts(&self, remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)]) -> solana_program_entrypoint::ProgramResult {
359 self.invoke_signed_with_remaining_accounts(&[], remaining_accounts)
360 }
361 #[inline(always)]
362 pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_entrypoint::ProgramResult {
363 self.invoke_signed_with_remaining_accounts(signers_seeds, &[])
364 }
365 #[allow(clippy::arithmetic_side_effects)]
366 #[allow(clippy::clone_on_copy)]
367 #[allow(clippy::vec_init_then_push)]
368 pub fn invoke_signed_with_remaining_accounts(
369 &self,
370 signers_seeds: &[&[&[u8]]],
371 remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)]
372 ) -> solana_program_entrypoint::ProgramResult {
373 let mut accounts = Vec::with_capacity(11+ remaining_accounts.len());
374 accounts.push(solana_instruction::AccountMeta::new(
375 *self.authority.key,
376 true
377 ));
378 accounts.push(solana_instruction::AccountMeta::new(
379 *self.treasury.key,
380 false
381 ));
382 accounts.push(solana_instruction::AccountMeta::new(
383 *self.position.key,
384 false
385 ));
386 accounts.push(solana_instruction::AccountMeta::new_readonly(
387 *self.staked_token_mint.key,
388 false
389 ));
390 accounts.push(solana_instruction::AccountMeta::new_readonly(
391 *self.reward_token_mint.key,
392 false
393 ));
394 accounts.push(solana_instruction::AccountMeta::new(
395 *self.treasury_staked_token_account.key,
396 false
397 ));
398 accounts.push(solana_instruction::AccountMeta::new(
399 *self.treasury_reward_token_account.key,
400 false
401 ));
402 accounts.push(solana_instruction::AccountMeta::new_readonly(
403 *self.fusionamm_program.key,
404 false
405 ));
406 accounts.push(solana_instruction::AccountMeta::new(
407 *self.fusion_pool.key,
408 false
409 ));
410 accounts.push(solana_instruction::AccountMeta::new_readonly(
411 *self.token_program.key,
412 false
413 ));
414 accounts.push(solana_instruction::AccountMeta::new_readonly(
415 *self.memo_program.key,
416 false
417 ));
418 remaining_accounts.iter().for_each(|remaining_account| {
419 accounts.push(solana_instruction::AccountMeta {
420 pubkey: *remaining_account.0.key,
421 is_signer: remaining_account.1,
422 is_writable: remaining_account.2,
423 })
424 });
425 let data = borsh::to_vec(&CompoundRewardInstructionData::new()).unwrap();
426
427 let instruction = solana_instruction::Instruction {
428 program_id: crate::TUNA_STAKING_ID,
429 accounts,
430 data,
431 };
432 let mut account_infos = Vec::with_capacity(12 + remaining_accounts.len());
433 account_infos.push(self.__program.clone());
434 account_infos.push(self.authority.clone());
435 account_infos.push(self.treasury.clone());
436 account_infos.push(self.position.clone());
437 account_infos.push(self.staked_token_mint.clone());
438 account_infos.push(self.reward_token_mint.clone());
439 account_infos.push(self.treasury_staked_token_account.clone());
440 account_infos.push(self.treasury_reward_token_account.clone());
441 account_infos.push(self.fusionamm_program.clone());
442 account_infos.push(self.fusion_pool.clone());
443 account_infos.push(self.token_program.clone());
444 account_infos.push(self.memo_program.clone());
445 remaining_accounts.iter().for_each(|remaining_account| account_infos.push(remaining_account.0.clone()));
446
447 if signers_seeds.is_empty() {
448 solana_cpi::invoke(&instruction, &account_infos)
449 } else {
450 solana_cpi::invoke_signed(&instruction, &account_infos, signers_seeds)
451 }
452 }
453}
454
455#[derive(Clone, Debug)]
471pub struct CompoundRewardCpiBuilder<'a, 'b> {
472 instruction: Box<CompoundRewardCpiBuilderInstruction<'a, 'b>>,
473}
474
475impl<'a, 'b> CompoundRewardCpiBuilder<'a, 'b> {
476 pub fn new(program: &'b solana_account_info::AccountInfo<'a>) -> Self {
477 let instruction = Box::new(CompoundRewardCpiBuilderInstruction {
478 __program: program,
479 authority: None,
480 treasury: None,
481 position: None,
482 staked_token_mint: None,
483 reward_token_mint: None,
484 treasury_staked_token_account: None,
485 treasury_reward_token_account: None,
486 fusionamm_program: None,
487 fusion_pool: None,
488 token_program: None,
489 memo_program: None,
490 __remaining_accounts: Vec::new(),
491 });
492 Self { instruction }
493 }
494 #[inline(always)]
495 pub fn authority(&mut self, authority: &'b solana_account_info::AccountInfo<'a>) -> &mut Self {
496 self.instruction.authority = Some(authority);
497 self
498 }
499 #[inline(always)]
500 pub fn treasury(&mut self, treasury: &'b solana_account_info::AccountInfo<'a>) -> &mut Self {
501 self.instruction.treasury = Some(treasury);
502 self
503 }
504 #[inline(always)]
505 pub fn position(&mut self, position: &'b solana_account_info::AccountInfo<'a>) -> &mut Self {
506 self.instruction.position = Some(position);
507 self
508 }
509 #[inline(always)]
510 pub fn staked_token_mint(&mut self, staked_token_mint: &'b solana_account_info::AccountInfo<'a>) -> &mut Self {
511 self.instruction.staked_token_mint = Some(staked_token_mint);
512 self
513 }
514 #[inline(always)]
515 pub fn reward_token_mint(&mut self, reward_token_mint: &'b solana_account_info::AccountInfo<'a>) -> &mut Self {
516 self.instruction.reward_token_mint = Some(reward_token_mint);
517 self
518 }
519 #[inline(always)]
520 pub fn treasury_staked_token_account(&mut self, treasury_staked_token_account: &'b solana_account_info::AccountInfo<'a>) -> &mut Self {
521 self.instruction.treasury_staked_token_account = Some(treasury_staked_token_account);
522 self
523 }
524 #[inline(always)]
525 pub fn treasury_reward_token_account(&mut self, treasury_reward_token_account: &'b solana_account_info::AccountInfo<'a>) -> &mut Self {
526 self.instruction.treasury_reward_token_account = Some(treasury_reward_token_account);
527 self
528 }
529 #[inline(always)]
530 pub fn fusionamm_program(&mut self, fusionamm_program: &'b solana_account_info::AccountInfo<'a>) -> &mut Self {
531 self.instruction.fusionamm_program = Some(fusionamm_program);
532 self
533 }
534 #[inline(always)]
535 pub fn fusion_pool(&mut self, fusion_pool: &'b solana_account_info::AccountInfo<'a>) -> &mut Self {
536 self.instruction.fusion_pool = Some(fusion_pool);
537 self
538 }
539 #[inline(always)]
540 pub fn token_program(&mut self, token_program: &'b solana_account_info::AccountInfo<'a>) -> &mut Self {
541 self.instruction.token_program = Some(token_program);
542 self
543 }
544 #[inline(always)]
545 pub fn memo_program(&mut self, memo_program: &'b solana_account_info::AccountInfo<'a>) -> &mut Self {
546 self.instruction.memo_program = Some(memo_program);
547 self
548 }
549 #[inline(always)]
551 pub fn add_remaining_account(&mut self, account: &'b solana_account_info::AccountInfo<'a>, is_writable: bool, is_signer: bool) -> &mut Self {
552 self.instruction.__remaining_accounts.push((account, is_writable, is_signer));
553 self
554 }
555 #[inline(always)]
560 pub fn add_remaining_accounts(&mut self, accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)]) -> &mut Self {
561 self.instruction.__remaining_accounts.extend_from_slice(accounts);
562 self
563 }
564 #[inline(always)]
565 pub fn invoke(&self) -> solana_program_entrypoint::ProgramResult {
566 self.invoke_signed(&[])
567 }
568 #[allow(clippy::clone_on_copy)]
569 #[allow(clippy::vec_init_then_push)]
570 pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_entrypoint::ProgramResult {
571 let instruction = CompoundRewardCpi {
572 __program: self.instruction.__program,
573
574 authority: self.instruction.authority.expect("authority is not set"),
575
576 treasury: self.instruction.treasury.expect("treasury is not set"),
577
578 position: self.instruction.position.expect("position is not set"),
579
580 staked_token_mint: self.instruction.staked_token_mint.expect("staked_token_mint is not set"),
581
582 reward_token_mint: self.instruction.reward_token_mint.expect("reward_token_mint is not set"),
583
584 treasury_staked_token_account: self.instruction.treasury_staked_token_account.expect("treasury_staked_token_account is not set"),
585
586 treasury_reward_token_account: self.instruction.treasury_reward_token_account.expect("treasury_reward_token_account is not set"),
587
588 fusionamm_program: self.instruction.fusionamm_program.expect("fusionamm_program is not set"),
589
590 fusion_pool: self.instruction.fusion_pool.expect("fusion_pool is not set"),
591
592 token_program: self.instruction.token_program.expect("token_program is not set"),
593
594 memo_program: self.instruction.memo_program.expect("memo_program is not set"),
595 };
596 instruction.invoke_signed_with_remaining_accounts(signers_seeds, &self.instruction.__remaining_accounts)
597 }
598}
599
600#[derive(Clone, Debug)]
601struct CompoundRewardCpiBuilderInstruction<'a, 'b> {
602 __program: &'b solana_account_info::AccountInfo<'a>,
603 authority: Option<&'b solana_account_info::AccountInfo<'a>>,
604 treasury: Option<&'b solana_account_info::AccountInfo<'a>>,
605 position: Option<&'b solana_account_info::AccountInfo<'a>>,
606 staked_token_mint: Option<&'b solana_account_info::AccountInfo<'a>>,
607 reward_token_mint: Option<&'b solana_account_info::AccountInfo<'a>>,
608 treasury_staked_token_account: Option<&'b solana_account_info::AccountInfo<'a>>,
609 treasury_reward_token_account: Option<&'b solana_account_info::AccountInfo<'a>>,
610 fusionamm_program: Option<&'b solana_account_info::AccountInfo<'a>>,
611 fusion_pool: Option<&'b solana_account_info::AccountInfo<'a>>,
612 token_program: Option<&'b solana_account_info::AccountInfo<'a>>,
613 memo_program: Option<&'b solana_account_info::AccountInfo<'a>>,
614 __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>,
616}
617