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