1use borsh::BorshDeserialize;
9use borsh::BorshSerialize;
10
11#[derive(Debug)]
13pub struct ClosePosition {
14 pub position_authority: solana_pubkey::Pubkey,
15
16 pub receiver: 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 token_program: solana_pubkey::Pubkey,
25}
26
27impl ClosePosition {
28 pub fn instruction(&self) -> solana_instruction::Instruction {
29 self.instruction_with_remaining_accounts(&[])
30 }
31 #[allow(clippy::arithmetic_side_effects)]
32 #[allow(clippy::vec_init_then_push)]
33 pub fn instruction_with_remaining_accounts(
34 &self,
35 remaining_accounts: &[solana_instruction::AccountMeta],
36 ) -> solana_instruction::Instruction {
37 let mut accounts = Vec::with_capacity(6 + remaining_accounts.len());
38 accounts.push(solana_instruction::AccountMeta::new_readonly(
39 self.position_authority,
40 true,
41 ));
42 accounts.push(solana_instruction::AccountMeta::new(self.receiver, false));
43 accounts.push(solana_instruction::AccountMeta::new(self.position, false));
44 accounts.push(solana_instruction::AccountMeta::new(
45 self.position_mint,
46 false,
47 ));
48 accounts.push(solana_instruction::AccountMeta::new(
49 self.position_token_account,
50 false,
51 ));
52 accounts.push(solana_instruction::AccountMeta::new_readonly(
53 self.token_program,
54 false,
55 ));
56 accounts.extend_from_slice(remaining_accounts);
57 let data = borsh::to_vec(&ClosePositionInstructionData::new()).unwrap();
58
59 solana_instruction::Instruction {
60 program_id: crate::WHIRLPOOL_ID,
61 accounts,
62 data,
63 }
64 }
65}
66
67#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)]
68#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
69pub struct ClosePositionInstructionData {
70 discriminator: [u8; 8],
71}
72
73impl ClosePositionInstructionData {
74 pub fn new() -> Self {
75 Self {
76 discriminator: [123, 134, 81, 0, 49, 68, 98, 98],
77 }
78 }
79}
80
81impl Default for ClosePositionInstructionData {
82 fn default() -> Self {
83 Self::new()
84 }
85}
86
87#[derive(Clone, Debug, Default)]
98pub struct ClosePositionBuilder {
99 position_authority: Option<solana_pubkey::Pubkey>,
100 receiver: Option<solana_pubkey::Pubkey>,
101 position: Option<solana_pubkey::Pubkey>,
102 position_mint: Option<solana_pubkey::Pubkey>,
103 position_token_account: Option<solana_pubkey::Pubkey>,
104 token_program: Option<solana_pubkey::Pubkey>,
105 __remaining_accounts: Vec<solana_instruction::AccountMeta>,
106}
107
108impl ClosePositionBuilder {
109 pub fn new() -> Self {
110 Self::default()
111 }
112 #[inline(always)]
113 pub fn position_authority(&mut self, position_authority: solana_pubkey::Pubkey) -> &mut Self {
114 self.position_authority = Some(position_authority);
115 self
116 }
117 #[inline(always)]
118 pub fn receiver(&mut self, receiver: solana_pubkey::Pubkey) -> &mut Self {
119 self.receiver = Some(receiver);
120 self
121 }
122 #[inline(always)]
123 pub fn position(&mut self, position: solana_pubkey::Pubkey) -> &mut Self {
124 self.position = Some(position);
125 self
126 }
127 #[inline(always)]
128 pub fn position_mint(&mut self, position_mint: solana_pubkey::Pubkey) -> &mut Self {
129 self.position_mint = Some(position_mint);
130 self
131 }
132 #[inline(always)]
133 pub fn position_token_account(
134 &mut self,
135 position_token_account: solana_pubkey::Pubkey,
136 ) -> &mut Self {
137 self.position_token_account = Some(position_token_account);
138 self
139 }
140 #[inline(always)]
142 pub fn token_program(&mut self, token_program: solana_pubkey::Pubkey) -> &mut Self {
143 self.token_program = Some(token_program);
144 self
145 }
146 #[inline(always)]
148 pub fn add_remaining_account(&mut self, account: solana_instruction::AccountMeta) -> &mut Self {
149 self.__remaining_accounts.push(account);
150 self
151 }
152 #[inline(always)]
154 pub fn add_remaining_accounts(
155 &mut self,
156 accounts: &[solana_instruction::AccountMeta],
157 ) -> &mut Self {
158 self.__remaining_accounts.extend_from_slice(accounts);
159 self
160 }
161 #[allow(clippy::clone_on_copy)]
162 pub fn instruction(&self) -> solana_instruction::Instruction {
163 let accounts = ClosePosition {
164 position_authority: self
165 .position_authority
166 .expect("position_authority is not set"),
167 receiver: self.receiver.expect("receiver is not set"),
168 position: self.position.expect("position is not set"),
169 position_mint: self.position_mint.expect("position_mint is not set"),
170 position_token_account: self
171 .position_token_account
172 .expect("position_token_account is not set"),
173 token_program: self.token_program.unwrap_or(solana_pubkey::pubkey!(
174 "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
175 )),
176 };
177
178 accounts.instruction_with_remaining_accounts(&self.__remaining_accounts)
179 }
180}
181
182pub struct ClosePositionCpiAccounts<'a, 'b> {
184 pub position_authority: &'b solana_account_info::AccountInfo<'a>,
185
186 pub receiver: &'b solana_account_info::AccountInfo<'a>,
187
188 pub position: &'b solana_account_info::AccountInfo<'a>,
189
190 pub position_mint: &'b solana_account_info::AccountInfo<'a>,
191
192 pub position_token_account: &'b solana_account_info::AccountInfo<'a>,
193
194 pub token_program: &'b solana_account_info::AccountInfo<'a>,
195}
196
197pub struct ClosePositionCpi<'a, 'b> {
199 pub __program: &'b solana_account_info::AccountInfo<'a>,
201
202 pub position_authority: &'b solana_account_info::AccountInfo<'a>,
203
204 pub receiver: &'b solana_account_info::AccountInfo<'a>,
205
206 pub position: &'b solana_account_info::AccountInfo<'a>,
207
208 pub position_mint: &'b solana_account_info::AccountInfo<'a>,
209
210 pub position_token_account: &'b solana_account_info::AccountInfo<'a>,
211
212 pub token_program: &'b solana_account_info::AccountInfo<'a>,
213}
214
215impl<'a, 'b> ClosePositionCpi<'a, 'b> {
216 pub fn new(
217 program: &'b solana_account_info::AccountInfo<'a>,
218 accounts: ClosePositionCpiAccounts<'a, 'b>,
219 ) -> Self {
220 Self {
221 __program: program,
222 position_authority: accounts.position_authority,
223 receiver: accounts.receiver,
224 position: accounts.position,
225 position_mint: accounts.position_mint,
226 position_token_account: accounts.position_token_account,
227 token_program: accounts.token_program,
228 }
229 }
230 #[inline(always)]
231 pub fn invoke(&self) -> solana_program_entrypoint::ProgramResult {
232 self.invoke_signed_with_remaining_accounts(&[], &[])
233 }
234 #[inline(always)]
235 pub fn invoke_with_remaining_accounts(
236 &self,
237 remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)],
238 ) -> solana_program_entrypoint::ProgramResult {
239 self.invoke_signed_with_remaining_accounts(&[], remaining_accounts)
240 }
241 #[inline(always)]
242 pub fn invoke_signed(
243 &self,
244 signers_seeds: &[&[&[u8]]],
245 ) -> solana_program_entrypoint::ProgramResult {
246 self.invoke_signed_with_remaining_accounts(signers_seeds, &[])
247 }
248 #[allow(clippy::arithmetic_side_effects)]
249 #[allow(clippy::clone_on_copy)]
250 #[allow(clippy::vec_init_then_push)]
251 pub fn invoke_signed_with_remaining_accounts(
252 &self,
253 signers_seeds: &[&[&[u8]]],
254 remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)],
255 ) -> solana_program_entrypoint::ProgramResult {
256 let mut accounts = Vec::with_capacity(6 + remaining_accounts.len());
257 accounts.push(solana_instruction::AccountMeta::new_readonly(
258 *self.position_authority.key,
259 true,
260 ));
261 accounts.push(solana_instruction::AccountMeta::new(
262 *self.receiver.key,
263 false,
264 ));
265 accounts.push(solana_instruction::AccountMeta::new(
266 *self.position.key,
267 false,
268 ));
269 accounts.push(solana_instruction::AccountMeta::new(
270 *self.position_mint.key,
271 false,
272 ));
273 accounts.push(solana_instruction::AccountMeta::new(
274 *self.position_token_account.key,
275 false,
276 ));
277 accounts.push(solana_instruction::AccountMeta::new_readonly(
278 *self.token_program.key,
279 false,
280 ));
281 remaining_accounts.iter().for_each(|remaining_account| {
282 accounts.push(solana_instruction::AccountMeta {
283 pubkey: *remaining_account.0.key,
284 is_signer: remaining_account.1,
285 is_writable: remaining_account.2,
286 })
287 });
288 let data = borsh::to_vec(&ClosePositionInstructionData::new()).unwrap();
289
290 let instruction = solana_instruction::Instruction {
291 program_id: crate::WHIRLPOOL_ID,
292 accounts,
293 data,
294 };
295 let mut account_infos = Vec::with_capacity(7 + remaining_accounts.len());
296 account_infos.push(self.__program.clone());
297 account_infos.push(self.position_authority.clone());
298 account_infos.push(self.receiver.clone());
299 account_infos.push(self.position.clone());
300 account_infos.push(self.position_mint.clone());
301 account_infos.push(self.position_token_account.clone());
302 account_infos.push(self.token_program.clone());
303 remaining_accounts
304 .iter()
305 .for_each(|remaining_account| account_infos.push(remaining_account.0.clone()));
306
307 if signers_seeds.is_empty() {
308 solana_cpi::invoke(&instruction, &account_infos)
309 } else {
310 solana_cpi::invoke_signed(&instruction, &account_infos, signers_seeds)
311 }
312 }
313}
314
315#[derive(Clone, Debug)]
326pub struct ClosePositionCpiBuilder<'a, 'b> {
327 instruction: Box<ClosePositionCpiBuilderInstruction<'a, 'b>>,
328}
329
330impl<'a, 'b> ClosePositionCpiBuilder<'a, 'b> {
331 pub fn new(program: &'b solana_account_info::AccountInfo<'a>) -> Self {
332 let instruction = Box::new(ClosePositionCpiBuilderInstruction {
333 __program: program,
334 position_authority: None,
335 receiver: None,
336 position: None,
337 position_mint: None,
338 position_token_account: None,
339 token_program: None,
340 __remaining_accounts: Vec::new(),
341 });
342 Self { instruction }
343 }
344 #[inline(always)]
345 pub fn position_authority(
346 &mut self,
347 position_authority: &'b solana_account_info::AccountInfo<'a>,
348 ) -> &mut Self {
349 self.instruction.position_authority = Some(position_authority);
350 self
351 }
352 #[inline(always)]
353 pub fn receiver(&mut self, receiver: &'b solana_account_info::AccountInfo<'a>) -> &mut Self {
354 self.instruction.receiver = Some(receiver);
355 self
356 }
357 #[inline(always)]
358 pub fn position(&mut self, position: &'b solana_account_info::AccountInfo<'a>) -> &mut Self {
359 self.instruction.position = Some(position);
360 self
361 }
362 #[inline(always)]
363 pub fn position_mint(
364 &mut self,
365 position_mint: &'b solana_account_info::AccountInfo<'a>,
366 ) -> &mut Self {
367 self.instruction.position_mint = Some(position_mint);
368 self
369 }
370 #[inline(always)]
371 pub fn position_token_account(
372 &mut self,
373 position_token_account: &'b solana_account_info::AccountInfo<'a>,
374 ) -> &mut Self {
375 self.instruction.position_token_account = Some(position_token_account);
376 self
377 }
378 #[inline(always)]
379 pub fn token_program(
380 &mut self,
381 token_program: &'b solana_account_info::AccountInfo<'a>,
382 ) -> &mut Self {
383 self.instruction.token_program = Some(token_program);
384 self
385 }
386 #[inline(always)]
388 pub fn add_remaining_account(
389 &mut self,
390 account: &'b solana_account_info::AccountInfo<'a>,
391 is_writable: bool,
392 is_signer: bool,
393 ) -> &mut Self {
394 self.instruction
395 .__remaining_accounts
396 .push((account, is_writable, is_signer));
397 self
398 }
399 #[inline(always)]
404 pub fn add_remaining_accounts(
405 &mut self,
406 accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)],
407 ) -> &mut Self {
408 self.instruction
409 .__remaining_accounts
410 .extend_from_slice(accounts);
411 self
412 }
413 #[inline(always)]
414 pub fn invoke(&self) -> solana_program_entrypoint::ProgramResult {
415 self.invoke_signed(&[])
416 }
417 #[allow(clippy::clone_on_copy)]
418 #[allow(clippy::vec_init_then_push)]
419 pub fn invoke_signed(
420 &self,
421 signers_seeds: &[&[&[u8]]],
422 ) -> solana_program_entrypoint::ProgramResult {
423 let instruction = ClosePositionCpi {
424 __program: self.instruction.__program,
425
426 position_authority: self
427 .instruction
428 .position_authority
429 .expect("position_authority is not set"),
430
431 receiver: self.instruction.receiver.expect("receiver is not set"),
432
433 position: self.instruction.position.expect("position is not set"),
434
435 position_mint: self
436 .instruction
437 .position_mint
438 .expect("position_mint is not set"),
439
440 position_token_account: self
441 .instruction
442 .position_token_account
443 .expect("position_token_account is not set"),
444
445 token_program: self
446 .instruction
447 .token_program
448 .expect("token_program is not set"),
449 };
450 instruction.invoke_signed_with_remaining_accounts(
451 signers_seeds,
452 &self.instruction.__remaining_accounts,
453 )
454 }
455}
456
457#[derive(Clone, Debug)]
458struct ClosePositionCpiBuilderInstruction<'a, 'b> {
459 __program: &'b solana_account_info::AccountInfo<'a>,
460 position_authority: Option<&'b solana_account_info::AccountInfo<'a>>,
461 receiver: Option<&'b solana_account_info::AccountInfo<'a>>,
462 position: Option<&'b solana_account_info::AccountInfo<'a>>,
463 position_mint: Option<&'b solana_account_info::AccountInfo<'a>>,
464 position_token_account: Option<&'b solana_account_info::AccountInfo<'a>>,
465 token_program: Option<&'b solana_account_info::AccountInfo<'a>>,
466 __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>,
468}