1#![allow(clippy::too_many_arguments)]
4
5use crate::error::SwapError;
6use crate::fees::Fees;
7use solana_program::{
8 instruction::{AccountMeta, Instruction},
9 program_error::ProgramError,
10 program_pack::Pack,
11 pubkey::Pubkey,
12};
13use std::mem::size_of;
14
15#[repr(C)]
17#[derive(Clone, Copy, Debug, PartialEq)]
18#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
19pub struct InitializeData {
20 pub nonce: u8,
22 pub amp_factor: u64,
24 pub fees: Fees,
26}
27
28#[repr(C)]
30#[derive(Clone, Copy, Debug, PartialEq)]
31#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
32pub struct SwapData {
33 pub amount_in: u64,
35 pub minimum_amount_out: u64,
37}
38
39#[repr(C)]
41#[derive(Clone, Copy, Debug, PartialEq)]
42#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
43pub struct DepositData {
44 pub token_a_amount: u64,
46 pub token_b_amount: u64,
48 pub min_mint_amount: u64,
50}
51
52#[repr(C)]
54#[derive(Clone, Copy, Debug, PartialEq)]
55#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
56pub struct WithdrawData {
57 pub pool_token_amount: u64,
60 pub minimum_token_a_amount: u64,
62 pub minimum_token_b_amount: u64,
64}
65
66#[repr(C)]
68#[derive(Clone, Copy, Debug, PartialEq)]
69#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
70pub struct WithdrawOneData {
71 pub pool_token_amount: u64,
74 pub minimum_token_amount: u64,
76}
77
78#[repr(C)]
80#[derive(Clone, Copy, Debug, PartialEq)]
81#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
82pub struct RampAData {
83 pub target_amp: u64,
85 pub stop_ramp_ts: i64,
87}
88
89#[repr(C)]
91#[derive(Clone, Copy, Debug, PartialEq)]
92pub enum AdminInstruction {
93 RampA(RampAData),
98
99 StopRampA,
104
105 Pause,
110
111 Unpause,
116
117 SetFeeAccount,
123
124 ApplyNewAdmin,
129
130 CommitNewAdmin,
136
137 SetNewFees(Fees),
142}
143
144impl AdminInstruction {
145 pub fn unpack(input: &[u8]) -> Result<Option<Self>, ProgramError> {
147 let (&tag, rest) = input.split_first().ok_or(SwapError::InvalidInstruction)?;
148 Ok(match tag {
149 100 => {
150 let (target_amp, rest) = unpack_u64(rest)?;
151 let (stop_ramp_ts, _rest) = unpack_i64(rest)?;
152 Some(Self::RampA(RampAData {
153 target_amp,
154 stop_ramp_ts,
155 }))
156 }
157 101 => Some(Self::StopRampA),
158 102 => Some(Self::Pause),
159 103 => Some(Self::Unpause),
160 104 => Some(Self::SetFeeAccount),
161 105 => Some(Self::ApplyNewAdmin),
162 106 => Some(Self::CommitNewAdmin),
163 107 => {
164 let fees = Fees::unpack_unchecked(rest)?;
165 Some(Self::SetNewFees(fees))
166 }
167 _ => None,
168 })
169 }
170
171 pub fn pack(&self) -> Vec<u8> {
173 let mut buf = Vec::with_capacity(size_of::<Self>());
174 match *self {
175 Self::RampA(RampAData {
176 target_amp,
177 stop_ramp_ts,
178 }) => {
179 buf.push(100);
180 buf.extend_from_slice(&target_amp.to_le_bytes());
181 buf.extend_from_slice(&stop_ramp_ts.to_le_bytes());
182 }
183 Self::StopRampA => buf.push(101),
184 Self::Pause => buf.push(102),
185 Self::Unpause => buf.push(103),
186 Self::SetFeeAccount => buf.push(104),
187 Self::ApplyNewAdmin => buf.push(105),
188 Self::CommitNewAdmin => buf.push(106),
189 Self::SetNewFees(fees) => {
190 buf.push(107);
191 let mut fees_slice = [0u8; Fees::LEN];
192 Pack::pack_into_slice(&fees, &mut fees_slice[..]);
193 buf.extend_from_slice(&fees_slice);
194 }
195 }
196 buf
197 }
198}
199
200pub fn ramp_a(
202 swap_pubkey: &Pubkey,
203 admin_pubkey: &Pubkey,
204 target_amp: u64,
205 stop_ramp_ts: i64,
206) -> Result<Instruction, ProgramError> {
207 let data = AdminInstruction::RampA(RampAData {
208 target_amp,
209 stop_ramp_ts,
210 })
211 .pack();
212
213 let accounts = vec![
214 AccountMeta::new(*swap_pubkey, false),
215 AccountMeta::new_readonly(*admin_pubkey, true),
216 ];
217
218 Ok(Instruction {
219 program_id: crate::ID,
220 accounts,
221 data,
222 })
223}
224
225pub fn stop_ramp_a(
227 swap_pubkey: &Pubkey,
228 admin_pubkey: &Pubkey,
229) -> Result<Instruction, ProgramError> {
230 let data = AdminInstruction::StopRampA.pack();
231
232 let accounts = vec![
233 AccountMeta::new(*swap_pubkey, false),
234 AccountMeta::new_readonly(*admin_pubkey, true),
235 ];
236
237 Ok(Instruction {
238 program_id: crate::ID,
239 accounts,
240 data,
241 })
242}
243
244pub fn pause(swap_pubkey: &Pubkey, admin_pubkey: &Pubkey) -> Result<Instruction, ProgramError> {
246 let data = AdminInstruction::Pause.pack();
247
248 let accounts = vec![
249 AccountMeta::new(*swap_pubkey, false),
250 AccountMeta::new_readonly(*admin_pubkey, true),
251 ];
252
253 Ok(Instruction {
254 program_id: crate::ID,
255 accounts,
256 data,
257 })
258}
259
260pub fn unpause(swap_pubkey: &Pubkey, admin_pubkey: &Pubkey) -> Result<Instruction, ProgramError> {
262 let data = AdminInstruction::Unpause.pack();
263
264 let accounts = vec![
265 AccountMeta::new(*swap_pubkey, false),
266 AccountMeta::new_readonly(*admin_pubkey, true),
267 ];
268
269 Ok(Instruction {
270 program_id: crate::ID,
271 accounts,
272 data,
273 })
274}
275
276pub fn apply_new_admin(
278 swap_pubkey: &Pubkey,
279 admin_pubkey: &Pubkey,
280) -> Result<Instruction, ProgramError> {
281 let data = AdminInstruction::ApplyNewAdmin.pack();
282
283 let accounts = vec![
284 AccountMeta::new(*swap_pubkey, false),
285 AccountMeta::new_readonly(*admin_pubkey, true),
286 ];
287
288 Ok(Instruction {
289 program_id: crate::ID,
290 accounts,
291 data,
292 })
293}
294
295pub fn commit_new_admin(
297 swap_pubkey: &Pubkey,
298 admin_pubkey: &Pubkey,
299 new_admin_pubkey: &Pubkey,
300) -> Result<Instruction, ProgramError> {
301 let data = AdminInstruction::CommitNewAdmin.pack();
302
303 let accounts = vec![
304 AccountMeta::new(*swap_pubkey, false),
305 AccountMeta::new_readonly(*admin_pubkey, true),
306 AccountMeta::new_readonly(*new_admin_pubkey, false),
307 ];
308
309 Ok(Instruction {
310 program_id: crate::ID,
311 accounts,
312 data,
313 })
314}
315
316pub fn set_fee_account(
318 swap_pubkey: &Pubkey,
319 admin_pubkey: &Pubkey,
320 new_fee_account_pubkey: &Pubkey,
321) -> Result<Instruction, ProgramError> {
322 let data = AdminInstruction::SetFeeAccount.pack();
323
324 let accounts = vec![
325 AccountMeta::new(*swap_pubkey, false),
326 AccountMeta::new_readonly(*admin_pubkey, true),
327 AccountMeta::new_readonly(*new_fee_account_pubkey, false),
328 ];
329
330 Ok(Instruction {
331 program_id: crate::ID,
332 accounts,
333 data,
334 })
335}
336
337pub fn set_new_fees(
339 swap_pubkey: &Pubkey,
340 admin_pubkey: &Pubkey,
341 new_fees: Fees,
342) -> Result<Instruction, ProgramError> {
343 let data = AdminInstruction::SetNewFees(new_fees).pack();
344
345 let accounts = vec![
346 AccountMeta::new(*swap_pubkey, false),
347 AccountMeta::new_readonly(*admin_pubkey, true),
348 ];
349
350 Ok(Instruction {
351 program_id: crate::ID,
352 accounts,
353 data,
354 })
355}
356
357#[repr(C)]
359#[derive(Copy, Clone, Debug, PartialEq)]
360#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
361pub enum SwapInstruction {
362 Initialize(InitializeData),
373
374 Swap(SwapData),
386
387 Deposit(DepositData),
401
402 Withdraw(WithdrawData),
417
418 WithdrawOne(WithdrawOneData),
431}
432
433impl SwapInstruction {
434 pub fn unpack(input: &[u8]) -> Result<Self, ProgramError> {
436 let (&tag, rest) = input.split_first().ok_or(SwapError::InvalidInstruction)?;
437 Ok(match tag {
438 0 => {
439 let (&nonce, rest) = rest.split_first().ok_or(SwapError::InvalidInstruction)?;
440 let (amp_factor, rest) = unpack_u64(rest)?;
441 let fees = Fees::unpack_unchecked(rest)?;
442 Self::Initialize(InitializeData {
443 nonce,
444 amp_factor,
445 fees,
446 })
447 }
448 1 => {
449 let (amount_in, rest) = unpack_u64(rest)?;
450 let (minimum_amount_out, _rest) = unpack_u64(rest)?;
451 Self::Swap(SwapData {
452 amount_in,
453 minimum_amount_out,
454 })
455 }
456 2 => {
457 let (token_a_amount, rest) = unpack_u64(rest)?;
458 let (token_b_amount, rest) = unpack_u64(rest)?;
459 let (min_mint_amount, _rest) = unpack_u64(rest)?;
460 Self::Deposit(DepositData {
461 token_a_amount,
462 token_b_amount,
463 min_mint_amount,
464 })
465 }
466 3 => {
467 let (pool_token_amount, rest) = unpack_u64(rest)?;
468 let (minimum_token_a_amount, rest) = unpack_u64(rest)?;
469 let (minimum_token_b_amount, _rest) = unpack_u64(rest)?;
470 Self::Withdraw(WithdrawData {
471 pool_token_amount,
472 minimum_token_a_amount,
473 minimum_token_b_amount,
474 })
475 }
476 4 => {
477 let (pool_token_amount, rest) = unpack_u64(rest)?;
478 let (minimum_token_amount, _rest) = unpack_u64(rest)?;
479 Self::WithdrawOne(WithdrawOneData {
480 pool_token_amount,
481 minimum_token_amount,
482 })
483 }
484 _ => return Err(SwapError::InvalidInstruction.into()),
485 })
486 }
487
488 pub fn pack(&self) -> Vec<u8> {
490 let mut buf = Vec::with_capacity(size_of::<Self>());
491 match *self {
492 Self::Initialize(InitializeData {
493 nonce,
494 amp_factor,
495 fees,
496 }) => {
497 buf.push(0);
498 buf.push(nonce);
499 buf.extend_from_slice(&_factor.to_le_bytes());
500 let mut fees_slice = [0u8; Fees::LEN];
501 Pack::pack_into_slice(&fees, &mut fees_slice[..]);
502 buf.extend_from_slice(&fees_slice);
503 }
504 Self::Swap(SwapData {
505 amount_in,
506 minimum_amount_out,
507 }) => {
508 buf.push(1);
509 buf.extend_from_slice(&amount_in.to_le_bytes());
510 buf.extend_from_slice(&minimum_amount_out.to_le_bytes());
511 }
512 Self::Deposit(DepositData {
513 token_a_amount,
514 token_b_amount,
515 min_mint_amount,
516 }) => {
517 buf.push(2);
518 buf.extend_from_slice(&token_a_amount.to_le_bytes());
519 buf.extend_from_slice(&token_b_amount.to_le_bytes());
520 buf.extend_from_slice(&min_mint_amount.to_le_bytes());
521 }
522 Self::Withdraw(WithdrawData {
523 pool_token_amount,
524 minimum_token_a_amount,
525 minimum_token_b_amount,
526 }) => {
527 buf.push(3);
528 buf.extend_from_slice(&pool_token_amount.to_le_bytes());
529 buf.extend_from_slice(&minimum_token_a_amount.to_le_bytes());
530 buf.extend_from_slice(&minimum_token_b_amount.to_le_bytes());
531 }
532 Self::WithdrawOne(WithdrawOneData {
533 pool_token_amount,
534 minimum_token_amount,
535 }) => {
536 buf.push(4);
537 buf.extend_from_slice(&pool_token_amount.to_le_bytes());
538 buf.extend_from_slice(&minimum_token_amount.to_le_bytes());
539 }
540 }
541 buf
542 }
543}
544
545pub fn initialize(
547 pool_token_program_id: &Pubkey, swap_pubkey: &Pubkey,
549 swap_authority_key: &Pubkey,
550 admin_pubkey: &Pubkey,
551 admin_fee_a_pubkey: &Pubkey,
552 admin_fee_b_pubkey: &Pubkey,
553 token_a_mint_pubkey: &Pubkey,
554 token_a_pubkey: &Pubkey,
555 token_b_mint_pubkey: &Pubkey,
556 token_b_pubkey: &Pubkey,
557 pool_mint_pubkey: &Pubkey,
558 destination_pubkey: &Pubkey, nonce: u8,
560 amp_factor: u64,
561 fees: Fees,
562) -> Result<Instruction, ProgramError> {
563 let data = SwapInstruction::Initialize(InitializeData {
564 nonce,
565 amp_factor,
566 fees,
567 })
568 .pack();
569
570 let accounts = vec![
571 AccountMeta::new(*swap_pubkey, true),
572 AccountMeta::new_readonly(*swap_authority_key, false),
573 AccountMeta::new_readonly(*admin_pubkey, false),
574 AccountMeta::new_readonly(*admin_fee_a_pubkey, false),
575 AccountMeta::new_readonly(*admin_fee_b_pubkey, false),
576 AccountMeta::new_readonly(*token_a_mint_pubkey, false),
577 AccountMeta::new_readonly(*token_a_pubkey, false),
578 AccountMeta::new_readonly(*token_b_mint_pubkey, false),
579 AccountMeta::new_readonly(*token_b_pubkey, false),
580 AccountMeta::new(*pool_mint_pubkey, false),
581 AccountMeta::new(*destination_pubkey, false),
582 AccountMeta::new_readonly(*pool_token_program_id, false),
583 ];
584
585 Ok(Instruction {
586 program_id: crate::ID,
587 accounts,
588 data,
589 })
590}
591
592#[inline(always)]
594pub fn deposit(
595 token_program_id: &Pubkey,
596 swap_pubkey: &Pubkey,
597 swap_authority_key: &Pubkey,
598 user_authority_key: &Pubkey,
599 deposit_token_a_pubkey: &Pubkey,
600 deposit_token_b_pubkey: &Pubkey,
601 swap_token_a_pubkey: &Pubkey,
602 swap_token_b_pubkey: &Pubkey,
603 pool_mint_pubkey: &Pubkey,
604 destination_pubkey: &Pubkey,
605 token_a_amount: u64,
606 token_b_amount: u64,
607 min_mint_amount: u64,
608) -> Result<Instruction, ProgramError> {
609 let data = SwapInstruction::Deposit(DepositData {
610 token_a_amount,
611 token_b_amount,
612 min_mint_amount,
613 })
614 .pack();
615
616 let accounts = vec![
617 AccountMeta::new_readonly(*swap_pubkey, false),
618 AccountMeta::new_readonly(*swap_authority_key, false),
619 AccountMeta::new_readonly(*user_authority_key, true),
620 AccountMeta::new(*deposit_token_a_pubkey, false),
621 AccountMeta::new(*deposit_token_b_pubkey, false),
622 AccountMeta::new(*swap_token_a_pubkey, false),
623 AccountMeta::new(*swap_token_b_pubkey, false),
624 AccountMeta::new(*pool_mint_pubkey, false),
625 AccountMeta::new(*destination_pubkey, false),
626 AccountMeta::new_readonly(*token_program_id, false),
627 ];
628
629 Ok(Instruction {
630 program_id: crate::ID,
631 accounts,
632 data,
633 })
634}
635
636#[inline(always)]
638pub fn withdraw(
639 token_program_id: &Pubkey,
640 swap_pubkey: &Pubkey,
641 swap_authority_key: &Pubkey,
642 user_authority_key: &Pubkey,
643 pool_mint_pubkey: &Pubkey,
644 source_pubkey: &Pubkey,
645 swap_token_a_pubkey: &Pubkey,
646 swap_token_b_pubkey: &Pubkey,
647 destination_token_a_pubkey: &Pubkey,
648 destination_token_b_pubkey: &Pubkey,
649 admin_fee_a_pubkey: &Pubkey,
650 admin_fee_b_pubkey: &Pubkey,
651 pool_token_amount: u64,
652 minimum_token_a_amount: u64,
653 minimum_token_b_amount: u64,
654) -> Result<Instruction, ProgramError> {
655 let data = SwapInstruction::Withdraw(WithdrawData {
656 pool_token_amount,
657 minimum_token_a_amount,
658 minimum_token_b_amount,
659 })
660 .pack();
661
662 let accounts = vec![
663 AccountMeta::new_readonly(*swap_pubkey, false),
664 AccountMeta::new_readonly(*swap_authority_key, false),
665 AccountMeta::new_readonly(*user_authority_key, true),
666 AccountMeta::new(*pool_mint_pubkey, false),
667 AccountMeta::new(*source_pubkey, false),
668 AccountMeta::new(*swap_token_a_pubkey, false),
669 AccountMeta::new(*swap_token_b_pubkey, false),
670 AccountMeta::new(*destination_token_a_pubkey, false),
671 AccountMeta::new(*destination_token_b_pubkey, false),
672 AccountMeta::new(*admin_fee_a_pubkey, false),
673 AccountMeta::new(*admin_fee_b_pubkey, false),
674 AccountMeta::new_readonly(*token_program_id, false),
675 ];
676
677 Ok(Instruction {
678 program_id: crate::ID,
679 accounts,
680 data,
681 })
682}
683
684#[inline(always)]
686pub fn swap(
687 token_program_id: &Pubkey,
688 swap_pubkey: &Pubkey,
689 swap_authority_key: &Pubkey,
690 user_authority_key: &Pubkey,
691 source_pubkey: &Pubkey,
692 swap_source_pubkey: &Pubkey,
693 swap_destination_pubkey: &Pubkey,
694 destination_pubkey: &Pubkey,
695 admin_fee_destination_pubkey: &Pubkey,
696 amount_in: u64,
697 minimum_amount_out: u64,
698) -> Result<Instruction, ProgramError> {
699 let data = SwapInstruction::Swap(SwapData {
700 amount_in,
701 minimum_amount_out,
702 })
703 .pack();
704
705 let accounts = vec![
706 AccountMeta::new_readonly(*swap_pubkey, false),
707 AccountMeta::new_readonly(*swap_authority_key, false),
708 AccountMeta::new_readonly(*user_authority_key, true),
709 AccountMeta::new(*source_pubkey, false),
710 AccountMeta::new(*swap_source_pubkey, false),
711 AccountMeta::new(*swap_destination_pubkey, false),
712 AccountMeta::new(*destination_pubkey, false),
713 AccountMeta::new(*admin_fee_destination_pubkey, false),
714 AccountMeta::new_readonly(*token_program_id, false),
715 ];
716
717 Ok(Instruction {
718 program_id: crate::ID,
719 accounts,
720 data,
721 })
722}
723
724#[inline(always)]
726pub fn withdraw_one(
727 token_program_id: &Pubkey,
728 swap_pubkey: &Pubkey,
729 swap_authority_key: &Pubkey,
730 user_authority_key: &Pubkey,
731 pool_mint_pubkey: &Pubkey,
732 source_pubkey: &Pubkey,
733 swap_base_token_pubkey: &Pubkey,
734 swap_quote_token_pubkey: &Pubkey,
735 base_destination_pubkey: &Pubkey,
736 admin_fee_destination_pubkey: &Pubkey,
737 pool_token_amount: u64,
738 minimum_token_amount: u64,
739) -> Result<Instruction, ProgramError> {
740 let data = SwapInstruction::WithdrawOne(WithdrawOneData {
741 pool_token_amount,
742 minimum_token_amount,
743 })
744 .pack();
745
746 let accounts = vec![
747 AccountMeta::new_readonly(*swap_pubkey, false),
748 AccountMeta::new_readonly(*swap_authority_key, false),
749 AccountMeta::new_readonly(*user_authority_key, true),
750 AccountMeta::new(*pool_mint_pubkey, false),
751 AccountMeta::new(*source_pubkey, false),
752 AccountMeta::new(*swap_base_token_pubkey, false),
753 AccountMeta::new(*swap_quote_token_pubkey, false),
754 AccountMeta::new(*base_destination_pubkey, false),
755 AccountMeta::new(*admin_fee_destination_pubkey, false),
756 AccountMeta::new_readonly(*token_program_id, false),
757 ];
758
759 Ok(Instruction {
760 program_id: crate::ID,
761 accounts,
762 data,
763 })
764}
765
766fn unpack_i64(input: &[u8]) -> Result<(i64, &[u8]), ProgramError> {
767 if input.len() >= 8 {
768 let (amount, rest) = input.split_at(8);
769 let amount = amount
770 .get(..8)
771 .and_then(|slice| slice.try_into().ok())
772 .map(i64::from_le_bytes)
773 .ok_or(SwapError::InvalidInstruction)?;
774 Ok((amount, rest))
775 } else {
776 Err(SwapError::InvalidInstruction.into())
777 }
778}
779
780fn unpack_u64(input: &[u8]) -> Result<(u64, &[u8]), ProgramError> {
781 if input.len() >= 8 {
782 let (amount, rest) = input.split_at(8);
783 let amount = amount
784 .get(..8)
785 .and_then(|slice| slice.try_into().ok())
786 .map(u64::from_le_bytes)
787 .ok_or(SwapError::InvalidInstruction)?;
788 Ok((amount, rest))
789 } else {
790 Err(SwapError::InvalidInstruction.into())
791 }
792}
793
794#[cfg(test)]
795#[allow(clippy::unwrap_used)]
796mod tests {
797 use super::*;
798
799 #[test]
800 fn test_admin_instruction_packing() {
801 let target_amp = 100;
802 let stop_ramp_ts = i64::MAX;
803 let check = AdminInstruction::RampA(RampAData {
804 target_amp,
805 stop_ramp_ts,
806 });
807 let packed = check.pack();
808 let mut expect = vec![100_u8];
809 expect.extend_from_slice(&target_amp.to_le_bytes());
810 expect.extend_from_slice(&stop_ramp_ts.to_le_bytes());
811 assert_eq!(packed, expect);
812 let unpacked = AdminInstruction::unpack(&expect).unwrap();
813 assert_eq!(unpacked, Some(check));
814
815 let check = AdminInstruction::StopRampA;
816 let packed = check.pack();
817 let expect = vec![101_u8];
818 assert_eq!(packed, expect);
819 let unpacked = AdminInstruction::unpack(&expect).unwrap();
820 assert_eq!(unpacked, Some(check));
821
822 let check = AdminInstruction::Pause;
823 let packed = check.pack();
824 let expect = vec![102_u8];
825 assert_eq!(packed, expect);
826 let unpacked = AdminInstruction::unpack(&expect).unwrap();
827 assert_eq!(unpacked, Some(check));
828
829 let check = AdminInstruction::Unpause;
830 let packed = check.pack();
831 let expect = vec![103_u8];
832 assert_eq!(packed, expect);
833 let unpacked = AdminInstruction::unpack(&expect).unwrap();
834 assert_eq!(unpacked, Some(check));
835
836 let check = AdminInstruction::SetFeeAccount;
837 let packed = check.pack();
838 let expect = vec![104_u8];
839 assert_eq!(packed, expect);
840 let unpacked = AdminInstruction::unpack(&expect).unwrap();
841 assert_eq!(unpacked, Some(check));
842
843 let check = AdminInstruction::ApplyNewAdmin;
844 let packed = check.pack();
845 let expect = vec![105_u8];
846 assert_eq!(packed, expect);
847 let unpacked = AdminInstruction::unpack(&expect).unwrap();
848 assert_eq!(unpacked, Some(check));
849
850 let check = AdminInstruction::CommitNewAdmin;
851 let packed = check.pack();
852 let expect = vec![106_u8];
853 assert_eq!(packed, expect);
854 let unpacked = AdminInstruction::unpack(&expect).unwrap();
855 assert_eq!(unpacked, Some(check));
856
857 let new_fees = Fees {
858 admin_trade_fee_numerator: 1,
859 admin_trade_fee_denominator: 2,
860 admin_withdraw_fee_numerator: 3,
861 admin_withdraw_fee_denominator: 4,
862 trade_fee_numerator: 5,
863 trade_fee_denominator: 6,
864 withdraw_fee_numerator: 7,
865 withdraw_fee_denominator: 8,
866 };
867 let check = AdminInstruction::SetNewFees(new_fees);
868 let packed = check.pack();
869 let mut expect = vec![107_u8];
870 let mut new_fees_slice = [0u8; Fees::LEN];
871 new_fees.pack_into_slice(&mut new_fees_slice[..]);
872 expect.extend_from_slice(&new_fees_slice);
873 assert_eq!(packed, expect);
874 let unpacked = AdminInstruction::unpack(&expect).unwrap();
875 assert_eq!(unpacked, Some(check));
876 }
877
878 #[test]
879 fn test_swap_instruction_packing() {
880 let nonce: u8 = 255;
881 let amp_factor: u64 = 0;
882 let fees = Fees {
883 admin_trade_fee_numerator: 1,
884 admin_trade_fee_denominator: 2,
885 admin_withdraw_fee_numerator: 3,
886 admin_withdraw_fee_denominator: 4,
887 trade_fee_numerator: 5,
888 trade_fee_denominator: 6,
889 withdraw_fee_numerator: 7,
890 withdraw_fee_denominator: 8,
891 };
892 let check = SwapInstruction::Initialize(InitializeData {
893 nonce,
894 amp_factor,
895 fees,
896 });
897 let packed = check.pack();
898 let mut expect = vec![0_u8, nonce];
899 expect.extend_from_slice(&_factor.to_le_bytes());
900 let mut fees_slice = [0u8; Fees::LEN];
901 fees.pack_into_slice(&mut fees_slice[..]);
902 expect.extend_from_slice(&fees_slice);
903 assert_eq!(packed, expect);
904 let unpacked = SwapInstruction::unpack(&expect).unwrap();
905 assert_eq!(unpacked, check);
906
907 let amount_in: u64 = 2;
908 let minimum_amount_out: u64 = 10;
909 let check = SwapInstruction::Swap(SwapData {
910 amount_in,
911 minimum_amount_out,
912 });
913 let packed = check.pack();
914 let mut expect = vec![1];
915 expect.extend_from_slice(&amount_in.to_le_bytes());
916 expect.extend_from_slice(&minimum_amount_out.to_le_bytes());
917 assert_eq!(packed, expect);
918 let unpacked = SwapInstruction::unpack(&expect).unwrap();
919 assert_eq!(unpacked, check);
920
921 let token_a_amount: u64 = 10;
922 let token_b_amount: u64 = 20;
923 let min_mint_amount: u64 = 5;
924 let check = SwapInstruction::Deposit(DepositData {
925 token_a_amount,
926 token_b_amount,
927 min_mint_amount,
928 });
929 let packed = check.pack();
930 let mut expect = vec![2];
931 expect.extend_from_slice(&token_a_amount.to_le_bytes());
932 expect.extend_from_slice(&token_b_amount.to_le_bytes());
933 expect.extend_from_slice(&min_mint_amount.to_le_bytes());
934 assert_eq!(packed, expect);
935 let unpacked = SwapInstruction::unpack(&expect).unwrap();
936 assert_eq!(unpacked, check);
937
938 let pool_token_amount: u64 = 1212438012089;
939 let minimum_token_a_amount: u64 = 102198761982612;
940 let minimum_token_b_amount: u64 = 2011239855213;
941 let check = SwapInstruction::Withdraw(WithdrawData {
942 pool_token_amount,
943 minimum_token_a_amount,
944 minimum_token_b_amount,
945 });
946 let packed = check.pack();
947 let mut expect = vec![3];
948 expect.extend_from_slice(&pool_token_amount.to_le_bytes());
949 expect.extend_from_slice(&minimum_token_a_amount.to_le_bytes());
950 expect.extend_from_slice(&minimum_token_b_amount.to_le_bytes());
951 assert_eq!(packed, expect);
952 let unpacked = SwapInstruction::unpack(&expect).unwrap();
953 assert_eq!(unpacked, check);
954
955 let pool_token_amount: u64 = 1212438012089;
956 let minimum_token_amount: u64 = 102198761982612;
957 let check = SwapInstruction::WithdrawOne(WithdrawOneData {
958 pool_token_amount,
959 minimum_token_amount,
960 });
961 let packed = check.pack();
962 let mut expect = vec![4];
963 expect.extend_from_slice(&pool_token_amount.to_le_bytes());
964 expect.extend_from_slice(&minimum_token_amount.to_le_bytes());
965 assert_eq!(packed, expect);
966 let unpacked = SwapInstruction::unpack(&expect).unwrap();
967 assert_eq!(unpacked, check);
968 }
969}