1use borsh::BorshSerialize;
9use borsh::BorshDeserialize;
10
11#[derive(Debug)]
13pub struct Stake {
14
15
16 pub authority: solana_pubkey::Pubkey,
17
18
19 pub owner: solana_pubkey::Pubkey,
20
21
22 pub treasury: solana_pubkey::Pubkey,
23
24
25 pub position: solana_pubkey::Pubkey,
26
27
28 pub treasury_staked_token_account: solana_pubkey::Pubkey,
29
30
31 pub authority_staked_token_account: solana_pubkey::Pubkey,
32
33
34 pub token_program: solana_pubkey::Pubkey,
35 }
36
37impl Stake {
38 pub fn instruction(&self, args: StakeInstructionArgs) -> solana_instruction::Instruction {
39 self.instruction_with_remaining_accounts(args, &[])
40 }
41 #[allow(clippy::arithmetic_side_effects)]
42 #[allow(clippy::vec_init_then_push)]
43 pub fn instruction_with_remaining_accounts(&self, args: StakeInstructionArgs, remaining_accounts: &[solana_instruction::AccountMeta]) -> solana_instruction::Instruction {
44 let mut accounts = Vec::with_capacity(7+ remaining_accounts.len());
45 accounts.push(solana_instruction::AccountMeta::new(
46 self.authority,
47 true
48 ));
49 accounts.push(solana_instruction::AccountMeta::new_readonly(
50 self.owner,
51 false
52 ));
53 accounts.push(solana_instruction::AccountMeta::new(
54 self.treasury,
55 false
56 ));
57 accounts.push(solana_instruction::AccountMeta::new(
58 self.position,
59 false
60 ));
61 accounts.push(solana_instruction::AccountMeta::new(
62 self.treasury_staked_token_account,
63 false
64 ));
65 accounts.push(solana_instruction::AccountMeta::new(
66 self.authority_staked_token_account,
67 false
68 ));
69 accounts.push(solana_instruction::AccountMeta::new_readonly(
70 self.token_program,
71 false
72 ));
73 accounts.extend_from_slice(remaining_accounts);
74 let mut data = borsh::to_vec(&StakeInstructionData::new()).unwrap();
75 let mut args = borsh::to_vec(&args).unwrap();
76 data.append(&mut args);
77
78 solana_instruction::Instruction {
79 program_id: crate::TUNA_STAKING_ID,
80 accounts,
81 data,
82 }
83 }
84}
85
86#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)]
87#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
88 pub struct StakeInstructionData {
89 discriminator: [u8; 8],
90 }
91
92impl StakeInstructionData {
93 pub fn new() -> Self {
94 Self {
95 discriminator: [206, 176, 202, 18, 200, 209, 179, 108],
96 }
97 }
98}
99
100impl Default for StakeInstructionData {
101 fn default() -> Self {
102 Self::new()
103 }
104}
105
106#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)]
107#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
108 pub struct StakeInstructionArgs {
109 pub shares: u64,
110 }
111
112
113#[derive(Clone, Debug, Default)]
125pub struct StakeBuilder {
126 authority: Option<solana_pubkey::Pubkey>,
127 owner: Option<solana_pubkey::Pubkey>,
128 treasury: Option<solana_pubkey::Pubkey>,
129 position: Option<solana_pubkey::Pubkey>,
130 treasury_staked_token_account: Option<solana_pubkey::Pubkey>,
131 authority_staked_token_account: Option<solana_pubkey::Pubkey>,
132 token_program: Option<solana_pubkey::Pubkey>,
133 shares: Option<u64>,
134 __remaining_accounts: Vec<solana_instruction::AccountMeta>,
135}
136
137impl StakeBuilder {
138 pub fn new() -> Self {
139 Self::default()
140 }
141 #[inline(always)]
142 pub fn authority(&mut self, authority: solana_pubkey::Pubkey) -> &mut Self {
143 self.authority = Some(authority);
144 self
145 }
146 #[inline(always)]
147 pub fn owner(&mut self, owner: solana_pubkey::Pubkey) -> &mut Self {
148 self.owner = Some(owner);
149 self
150 }
151 #[inline(always)]
152 pub fn treasury(&mut self, treasury: solana_pubkey::Pubkey) -> &mut Self {
153 self.treasury = Some(treasury);
154 self
155 }
156 #[inline(always)]
157 pub fn position(&mut self, position: solana_pubkey::Pubkey) -> &mut Self {
158 self.position = Some(position);
159 self
160 }
161 #[inline(always)]
162 pub fn treasury_staked_token_account(&mut self, treasury_staked_token_account: solana_pubkey::Pubkey) -> &mut Self {
163 self.treasury_staked_token_account = Some(treasury_staked_token_account);
164 self
165 }
166 #[inline(always)]
167 pub fn authority_staked_token_account(&mut self, authority_staked_token_account: solana_pubkey::Pubkey) -> &mut Self {
168 self.authority_staked_token_account = Some(authority_staked_token_account);
169 self
170 }
171 #[inline(always)]
173 pub fn token_program(&mut self, token_program: solana_pubkey::Pubkey) -> &mut Self {
174 self.token_program = Some(token_program);
175 self
176 }
177 #[inline(always)]
178 pub fn shares(&mut self, shares: u64) -> &mut Self {
179 self.shares = Some(shares);
180 self
181 }
182 #[inline(always)]
184 pub fn add_remaining_account(&mut self, account: solana_instruction::AccountMeta) -> &mut Self {
185 self.__remaining_accounts.push(account);
186 self
187 }
188 #[inline(always)]
190 pub fn add_remaining_accounts(&mut self, accounts: &[solana_instruction::AccountMeta]) -> &mut Self {
191 self.__remaining_accounts.extend_from_slice(accounts);
192 self
193 }
194 #[allow(clippy::clone_on_copy)]
195 pub fn instruction(&self) -> solana_instruction::Instruction {
196 let accounts = Stake {
197 authority: self.authority.expect("authority is not set"),
198 owner: self.owner.expect("owner is not set"),
199 treasury: self.treasury.expect("treasury is not set"),
200 position: self.position.expect("position is not set"),
201 treasury_staked_token_account: self.treasury_staked_token_account.expect("treasury_staked_token_account is not set"),
202 authority_staked_token_account: self.authority_staked_token_account.expect("authority_staked_token_account is not set"),
203 token_program: self.token_program.unwrap_or(solana_pubkey::pubkey!("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA")),
204 };
205 let args = StakeInstructionArgs {
206 shares: self.shares.clone().expect("shares is not set"),
207 };
208
209 accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts)
210 }
211}
212
213 pub struct StakeCpiAccounts<'a, 'b> {
215
216
217 pub authority: &'b solana_account_info::AccountInfo<'a>,
218
219
220 pub owner: &'b solana_account_info::AccountInfo<'a>,
221
222
223 pub treasury: &'b solana_account_info::AccountInfo<'a>,
224
225
226 pub position: &'b solana_account_info::AccountInfo<'a>,
227
228
229 pub treasury_staked_token_account: &'b solana_account_info::AccountInfo<'a>,
230
231
232 pub authority_staked_token_account: &'b solana_account_info::AccountInfo<'a>,
233
234
235 pub token_program: &'b solana_account_info::AccountInfo<'a>,
236 }
237
238pub struct StakeCpi<'a, 'b> {
240 pub __program: &'b solana_account_info::AccountInfo<'a>,
242
243
244 pub authority: &'b solana_account_info::AccountInfo<'a>,
245
246
247 pub owner: &'b solana_account_info::AccountInfo<'a>,
248
249
250 pub treasury: &'b solana_account_info::AccountInfo<'a>,
251
252
253 pub position: &'b solana_account_info::AccountInfo<'a>,
254
255
256 pub treasury_staked_token_account: &'b solana_account_info::AccountInfo<'a>,
257
258
259 pub authority_staked_token_account: &'b solana_account_info::AccountInfo<'a>,
260
261
262 pub token_program: &'b solana_account_info::AccountInfo<'a>,
263 pub __args: StakeInstructionArgs,
265 }
266
267impl<'a, 'b> StakeCpi<'a, 'b> {
268 pub fn new(
269 program: &'b solana_account_info::AccountInfo<'a>,
270 accounts: StakeCpiAccounts<'a, 'b>,
271 args: StakeInstructionArgs,
272 ) -> Self {
273 Self {
274 __program: program,
275 authority: accounts.authority,
276 owner: accounts.owner,
277 treasury: accounts.treasury,
278 position: accounts.position,
279 treasury_staked_token_account: accounts.treasury_staked_token_account,
280 authority_staked_token_account: accounts.authority_staked_token_account,
281 token_program: accounts.token_program,
282 __args: args,
283 }
284 }
285 #[inline(always)]
286 pub fn invoke(&self) -> solana_program_entrypoint::ProgramResult {
287 self.invoke_signed_with_remaining_accounts(&[], &[])
288 }
289 #[inline(always)]
290 pub fn invoke_with_remaining_accounts(&self, remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)]) -> solana_program_entrypoint::ProgramResult {
291 self.invoke_signed_with_remaining_accounts(&[], remaining_accounts)
292 }
293 #[inline(always)]
294 pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_entrypoint::ProgramResult {
295 self.invoke_signed_with_remaining_accounts(signers_seeds, &[])
296 }
297 #[allow(clippy::arithmetic_side_effects)]
298 #[allow(clippy::clone_on_copy)]
299 #[allow(clippy::vec_init_then_push)]
300 pub fn invoke_signed_with_remaining_accounts(
301 &self,
302 signers_seeds: &[&[&[u8]]],
303 remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)]
304 ) -> solana_program_entrypoint::ProgramResult {
305 let mut accounts = Vec::with_capacity(7+ remaining_accounts.len());
306 accounts.push(solana_instruction::AccountMeta::new(
307 *self.authority.key,
308 true
309 ));
310 accounts.push(solana_instruction::AccountMeta::new_readonly(
311 *self.owner.key,
312 false
313 ));
314 accounts.push(solana_instruction::AccountMeta::new(
315 *self.treasury.key,
316 false
317 ));
318 accounts.push(solana_instruction::AccountMeta::new(
319 *self.position.key,
320 false
321 ));
322 accounts.push(solana_instruction::AccountMeta::new(
323 *self.treasury_staked_token_account.key,
324 false
325 ));
326 accounts.push(solana_instruction::AccountMeta::new(
327 *self.authority_staked_token_account.key,
328 false
329 ));
330 accounts.push(solana_instruction::AccountMeta::new_readonly(
331 *self.token_program.key,
332 false
333 ));
334 remaining_accounts.iter().for_each(|remaining_account| {
335 accounts.push(solana_instruction::AccountMeta {
336 pubkey: *remaining_account.0.key,
337 is_signer: remaining_account.1,
338 is_writable: remaining_account.2,
339 })
340 });
341 let mut data = borsh::to_vec(&StakeInstructionData::new()).unwrap();
342 let mut args = borsh::to_vec(&self.__args).unwrap();
343 data.append(&mut args);
344
345 let instruction = solana_instruction::Instruction {
346 program_id: crate::TUNA_STAKING_ID,
347 accounts,
348 data,
349 };
350 let mut account_infos = Vec::with_capacity(8 + remaining_accounts.len());
351 account_infos.push(self.__program.clone());
352 account_infos.push(self.authority.clone());
353 account_infos.push(self.owner.clone());
354 account_infos.push(self.treasury.clone());
355 account_infos.push(self.position.clone());
356 account_infos.push(self.treasury_staked_token_account.clone());
357 account_infos.push(self.authority_staked_token_account.clone());
358 account_infos.push(self.token_program.clone());
359 remaining_accounts.iter().for_each(|remaining_account| account_infos.push(remaining_account.0.clone()));
360
361 if signers_seeds.is_empty() {
362 solana_cpi::invoke(&instruction, &account_infos)
363 } else {
364 solana_cpi::invoke_signed(&instruction, &account_infos, signers_seeds)
365 }
366 }
367}
368
369#[derive(Clone, Debug)]
381pub struct StakeCpiBuilder<'a, 'b> {
382 instruction: Box<StakeCpiBuilderInstruction<'a, 'b>>,
383}
384
385impl<'a, 'b> StakeCpiBuilder<'a, 'b> {
386 pub fn new(program: &'b solana_account_info::AccountInfo<'a>) -> Self {
387 let instruction = Box::new(StakeCpiBuilderInstruction {
388 __program: program,
389 authority: None,
390 owner: None,
391 treasury: None,
392 position: None,
393 treasury_staked_token_account: None,
394 authority_staked_token_account: None,
395 token_program: None,
396 shares: None,
397 __remaining_accounts: Vec::new(),
398 });
399 Self { instruction }
400 }
401 #[inline(always)]
402 pub fn authority(&mut self, authority: &'b solana_account_info::AccountInfo<'a>) -> &mut Self {
403 self.instruction.authority = Some(authority);
404 self
405 }
406 #[inline(always)]
407 pub fn owner(&mut self, owner: &'b solana_account_info::AccountInfo<'a>) -> &mut Self {
408 self.instruction.owner = Some(owner);
409 self
410 }
411 #[inline(always)]
412 pub fn treasury(&mut self, treasury: &'b solana_account_info::AccountInfo<'a>) -> &mut Self {
413 self.instruction.treasury = Some(treasury);
414 self
415 }
416 #[inline(always)]
417 pub fn position(&mut self, position: &'b solana_account_info::AccountInfo<'a>) -> &mut Self {
418 self.instruction.position = Some(position);
419 self
420 }
421 #[inline(always)]
422 pub fn treasury_staked_token_account(&mut self, treasury_staked_token_account: &'b solana_account_info::AccountInfo<'a>) -> &mut Self {
423 self.instruction.treasury_staked_token_account = Some(treasury_staked_token_account);
424 self
425 }
426 #[inline(always)]
427 pub fn authority_staked_token_account(&mut self, authority_staked_token_account: &'b solana_account_info::AccountInfo<'a>) -> &mut Self {
428 self.instruction.authority_staked_token_account = Some(authority_staked_token_account);
429 self
430 }
431 #[inline(always)]
432 pub fn token_program(&mut self, token_program: &'b solana_account_info::AccountInfo<'a>) -> &mut Self {
433 self.instruction.token_program = Some(token_program);
434 self
435 }
436 #[inline(always)]
437 pub fn shares(&mut self, shares: u64) -> &mut Self {
438 self.instruction.shares = Some(shares);
439 self
440 }
441 #[inline(always)]
443 pub fn add_remaining_account(&mut self, account: &'b solana_account_info::AccountInfo<'a>, is_writable: bool, is_signer: bool) -> &mut Self {
444 self.instruction.__remaining_accounts.push((account, is_writable, is_signer));
445 self
446 }
447 #[inline(always)]
452 pub fn add_remaining_accounts(&mut self, accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)]) -> &mut Self {
453 self.instruction.__remaining_accounts.extend_from_slice(accounts);
454 self
455 }
456 #[inline(always)]
457 pub fn invoke(&self) -> solana_program_entrypoint::ProgramResult {
458 self.invoke_signed(&[])
459 }
460 #[allow(clippy::clone_on_copy)]
461 #[allow(clippy::vec_init_then_push)]
462 pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_entrypoint::ProgramResult {
463 let args = StakeInstructionArgs {
464 shares: self.instruction.shares.clone().expect("shares is not set"),
465 };
466 let instruction = StakeCpi {
467 __program: self.instruction.__program,
468
469 authority: self.instruction.authority.expect("authority is not set"),
470
471 owner: self.instruction.owner.expect("owner is not set"),
472
473 treasury: self.instruction.treasury.expect("treasury is not set"),
474
475 position: self.instruction.position.expect("position is not set"),
476
477 treasury_staked_token_account: self.instruction.treasury_staked_token_account.expect("treasury_staked_token_account is not set"),
478
479 authority_staked_token_account: self.instruction.authority_staked_token_account.expect("authority_staked_token_account is not set"),
480
481 token_program: self.instruction.token_program.expect("token_program is not set"),
482 __args: args,
483 };
484 instruction.invoke_signed_with_remaining_accounts(signers_seeds, &self.instruction.__remaining_accounts)
485 }
486}
487
488#[derive(Clone, Debug)]
489struct StakeCpiBuilderInstruction<'a, 'b> {
490 __program: &'b solana_account_info::AccountInfo<'a>,
491 authority: Option<&'b solana_account_info::AccountInfo<'a>>,
492 owner: Option<&'b solana_account_info::AccountInfo<'a>>,
493 treasury: Option<&'b solana_account_info::AccountInfo<'a>>,
494 position: Option<&'b solana_account_info::AccountInfo<'a>>,
495 treasury_staked_token_account: Option<&'b solana_account_info::AccountInfo<'a>>,
496 authority_staked_token_account: Option<&'b solana_account_info::AccountInfo<'a>>,
497 token_program: Option<&'b solana_account_info::AccountInfo<'a>>,
498 shares: Option<u64>,
499 __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>,
501}
502