1use {
4 crate::{check_program_account, error::TokenError},
5 solana_instruction::{AccountMeta, Instruction},
6 solana_program_error::ProgramError,
7 solana_program_option::COption,
8 solana_pubkey::Pubkey,
9 solana_sdk_ids::sysvar,
10 std::{convert::TryInto, mem::size_of},
11};
12
13pub const MIN_SIGNERS: usize = 1;
15pub const MAX_SIGNERS: usize = 11;
17const U64_BYTES: usize = 8;
19
20#[repr(C, u8)]
22#[derive(Clone, Debug, PartialEq)]
23pub enum TokenInstruction<'a> {
24 InitializeMint {
38 decimals: u8,
40 mint_authority: Pubkey,
42 freeze_authority: COption<Pubkey>,
44 },
45 InitializeAccount,
64 InitializeMultisig {
84 m: u8,
87 },
88 Transfer {
106 amount: u64,
108 },
109 Approve {
125 amount: u64,
127 },
128 Revoke,
141 SetAuthority {
154 authority_type: AuthorityType,
156 new_authority: COption<Pubkey>,
158 },
159 MintTo {
175 amount: u64,
177 },
178 Burn {
194 amount: u64,
196 },
197 CloseAccount,
213 FreezeAccount,
229 ThawAccount,
244
245 TransferChecked {
269 amount: u64,
271 decimals: u8,
273 },
274 ApproveChecked {
296 amount: u64,
298 decimals: u8,
300 },
301 MintToChecked {
321 amount: u64,
323 decimals: u8,
325 },
326 BurnChecked {
347 amount: u64,
349 decimals: u8,
351 },
352 InitializeAccount2 {
364 owner: Pubkey,
366 },
367 SyncNative,
384 InitializeAccount3 {
392 owner: Pubkey,
394 },
395 InitializeMultisig2 {
404 m: u8,
407 },
408 InitializeMint2 {
415 decimals: u8,
417 mint_authority: Pubkey,
419 freeze_authority: COption<Pubkey>,
421 },
422 GetAccountDataSize, InitializeImmutableOwner,
447 AmountToUiAmount {
460 amount: u64,
462 },
463 UiAmountToAmount {
474 ui_amount: &'a str,
476 },
477 WithdrawExcessLamports = 38,
494 UnwrapLamports {
517 amount: COption<u64>,
519 } = 45,
520 Batch = 255,
549 }
553impl<'a> TokenInstruction<'a> {
554 pub fn unpack(input: &'a [u8]) -> Result<Self, ProgramError> {
557 use TokenError::InvalidInstruction;
558
559 let (&tag, rest) = input.split_first().ok_or(InvalidInstruction)?;
560 Ok(match tag {
561 0 => {
562 let (&decimals, rest) = rest.split_first().ok_or(InvalidInstruction)?;
563 let (mint_authority, rest) = Self::unpack_pubkey(rest)?;
564 let (freeze_authority, _rest) = Self::unpack_pubkey_option(rest)?;
565 Self::InitializeMint {
566 mint_authority,
567 freeze_authority,
568 decimals,
569 }
570 }
571 1 => Self::InitializeAccount,
572 2 => {
573 let &m = rest.first().ok_or(InvalidInstruction)?;
574 Self::InitializeMultisig { m }
575 }
576 3 | 4 | 7 | 8 => {
577 let amount = rest
578 .get(..8)
579 .and_then(|slice| slice.try_into().ok())
580 .map(u64::from_le_bytes)
581 .ok_or(InvalidInstruction)?;
582 match tag {
583 3 => Self::Transfer { amount },
584 4 => Self::Approve { amount },
585 7 => Self::MintTo { amount },
586 8 => Self::Burn { amount },
587 _ => unreachable!(),
588 }
589 }
590 5 => Self::Revoke,
591 6 => {
592 let (authority_type, rest) = rest
593 .split_first()
594 .ok_or_else(|| ProgramError::from(InvalidInstruction))
595 .and_then(|(&t, rest)| Ok((AuthorityType::from(t)?, rest)))?;
596 let (new_authority, _rest) = Self::unpack_pubkey_option(rest)?;
597
598 Self::SetAuthority {
599 authority_type,
600 new_authority,
601 }
602 }
603 9 => Self::CloseAccount,
604 10 => Self::FreezeAccount,
605 11 => Self::ThawAccount,
606 12 => {
607 let (amount, decimals, _rest) = Self::unpack_amount_decimals(rest)?;
608 Self::TransferChecked { amount, decimals }
609 }
610 13 => {
611 let (amount, decimals, _rest) = Self::unpack_amount_decimals(rest)?;
612 Self::ApproveChecked { amount, decimals }
613 }
614 14 => {
615 let (amount, decimals, _rest) = Self::unpack_amount_decimals(rest)?;
616 Self::MintToChecked { amount, decimals }
617 }
618 15 => {
619 let (amount, decimals, _rest) = Self::unpack_amount_decimals(rest)?;
620 Self::BurnChecked { amount, decimals }
621 }
622 16 => {
623 let (owner, _rest) = Self::unpack_pubkey(rest)?;
624 Self::InitializeAccount2 { owner }
625 }
626 17 => Self::SyncNative,
627 18 => {
628 let (owner, _rest) = Self::unpack_pubkey(rest)?;
629 Self::InitializeAccount3 { owner }
630 }
631 19 => {
632 let &m = rest.first().ok_or(InvalidInstruction)?;
633 Self::InitializeMultisig2 { m }
634 }
635 20 => {
636 let (&decimals, rest) = rest.split_first().ok_or(InvalidInstruction)?;
637 let (mint_authority, rest) = Self::unpack_pubkey(rest)?;
638 let (freeze_authority, _rest) = Self::unpack_pubkey_option(rest)?;
639 Self::InitializeMint2 {
640 mint_authority,
641 freeze_authority,
642 decimals,
643 }
644 }
645 21 => Self::GetAccountDataSize,
646 22 => Self::InitializeImmutableOwner,
647 23 => {
648 let (amount, _rest) = Self::unpack_u64(rest)?;
649 Self::AmountToUiAmount { amount }
650 }
651 24 => {
652 let ui_amount = std::str::from_utf8(rest).map_err(|_| InvalidInstruction)?;
653 Self::UiAmountToAmount { ui_amount }
654 }
655 38 => Self::WithdrawExcessLamports,
656 45 => {
657 let (amount, _rest) = Self::unpack_u64_option(rest)?;
658 Self::UnwrapLamports { amount }
659 }
660 255 => Self::Batch,
661 _ => return Err(TokenError::InvalidInstruction.into()),
662 })
663 }
664
665 pub fn pack(&self) -> Vec<u8> {
668 let mut buf = Vec::with_capacity(size_of::<Self>());
669 match self {
670 &Self::InitializeMint {
671 ref mint_authority,
672 ref freeze_authority,
673 decimals,
674 } => {
675 buf.push(0);
676 buf.push(decimals);
677 buf.extend_from_slice(mint_authority.as_ref());
678 Self::pack_pubkey_option(freeze_authority, &mut buf);
679 }
680 Self::InitializeAccount => buf.push(1),
681 &Self::InitializeMultisig { m } => {
682 buf.push(2);
683 buf.push(m);
684 }
685 &Self::Transfer { amount } => {
686 buf.push(3);
687 buf.extend_from_slice(&amount.to_le_bytes());
688 }
689 &Self::Approve { amount } => {
690 buf.push(4);
691 buf.extend_from_slice(&amount.to_le_bytes());
692 }
693 &Self::MintTo { amount } => {
694 buf.push(7);
695 buf.extend_from_slice(&amount.to_le_bytes());
696 }
697 &Self::Burn { amount } => {
698 buf.push(8);
699 buf.extend_from_slice(&amount.to_le_bytes());
700 }
701 Self::Revoke => buf.push(5),
702 Self::SetAuthority {
703 authority_type,
704 ref new_authority,
705 } => {
706 buf.push(6);
707 buf.push(authority_type.into());
708 Self::pack_pubkey_option(new_authority, &mut buf);
709 }
710 Self::CloseAccount => buf.push(9),
711 Self::FreezeAccount => buf.push(10),
712 Self::ThawAccount => buf.push(11),
713 &Self::TransferChecked { amount, decimals } => {
714 buf.push(12);
715 buf.extend_from_slice(&amount.to_le_bytes());
716 buf.push(decimals);
717 }
718 &Self::ApproveChecked { amount, decimals } => {
719 buf.push(13);
720 buf.extend_from_slice(&amount.to_le_bytes());
721 buf.push(decimals);
722 }
723 &Self::MintToChecked { amount, decimals } => {
724 buf.push(14);
725 buf.extend_from_slice(&amount.to_le_bytes());
726 buf.push(decimals);
727 }
728 &Self::BurnChecked { amount, decimals } => {
729 buf.push(15);
730 buf.extend_from_slice(&amount.to_le_bytes());
731 buf.push(decimals);
732 }
733 &Self::InitializeAccount2 { owner } => {
734 buf.push(16);
735 buf.extend_from_slice(owner.as_ref());
736 }
737 &Self::SyncNative => {
738 buf.push(17);
739 }
740 &Self::InitializeAccount3 { owner } => {
741 buf.push(18);
742 buf.extend_from_slice(owner.as_ref());
743 }
744 &Self::InitializeMultisig2 { m } => {
745 buf.push(19);
746 buf.push(m);
747 }
748 &Self::InitializeMint2 {
749 ref mint_authority,
750 ref freeze_authority,
751 decimals,
752 } => {
753 buf.push(20);
754 buf.push(decimals);
755 buf.extend_from_slice(mint_authority.as_ref());
756 Self::pack_pubkey_option(freeze_authority, &mut buf);
757 }
758 &Self::GetAccountDataSize => {
759 buf.push(21);
760 }
761 &Self::InitializeImmutableOwner => {
762 buf.push(22);
763 }
764 &Self::AmountToUiAmount { amount } => {
765 buf.push(23);
766 buf.extend_from_slice(&amount.to_le_bytes());
767 }
768 Self::UiAmountToAmount { ui_amount } => {
769 buf.push(24);
770 buf.extend_from_slice(ui_amount.as_bytes());
771 }
772 &Self::WithdrawExcessLamports => {
773 buf.push(38);
774 }
775 Self::UnwrapLamports { ref amount } => {
776 buf.push(45);
777 Self::pack_u64_option(amount, &mut buf);
778 }
779 &Self::Batch => {
780 buf.push(255);
781 }
782 };
783 buf
784 }
785
786 fn unpack_pubkey(input: &[u8]) -> Result<(Pubkey, &[u8]), ProgramError> {
787 if input.len() >= 32 {
788 let (key, rest) = input.split_at(32);
789 let pk = Pubkey::try_from(key).map_err(|_| TokenError::InvalidInstruction)?;
790 Ok((pk, rest))
791 } else {
792 Err(TokenError::InvalidInstruction.into())
793 }
794 }
795
796 fn unpack_pubkey_option(input: &[u8]) -> Result<(COption<Pubkey>, &[u8]), ProgramError> {
797 match input.split_first() {
798 Option::Some((&0, rest)) => Ok((COption::None, rest)),
799 Option::Some((&1, rest)) if rest.len() >= 32 => {
800 let (key, rest) = rest.split_at(32);
801 let pk = Pubkey::try_from(key).map_err(|_| TokenError::InvalidInstruction)?;
802 Ok((COption::Some(pk), rest))
803 }
804 _ => Err(TokenError::InvalidInstruction.into()),
805 }
806 }
807
808 fn pack_pubkey_option(value: &COption<Pubkey>, buf: &mut Vec<u8>) {
809 match *value {
810 COption::Some(ref key) => {
811 buf.push(1);
812 buf.extend_from_slice(&key.to_bytes());
813 }
814 COption::None => buf.push(0),
815 }
816 }
817
818 fn unpack_u64(input: &[u8]) -> Result<(u64, &[u8]), ProgramError> {
819 let value = input
820 .get(..U64_BYTES)
821 .and_then(|slice| slice.try_into().ok())
822 .map(u64::from_le_bytes)
823 .ok_or(TokenError::InvalidInstruction)?;
824 Ok((value, &input[U64_BYTES..]))
825 }
826
827 fn unpack_u64_option(input: &[u8]) -> Result<(COption<u64>, &[u8]), ProgramError> {
828 match input.split_first() {
829 Option::Some((&0, rest)) => Ok((COption::None, rest)),
830 Option::Some((&1, rest)) if rest.len() >= 8 => {
831 let (amount, rest) = rest
832 .split_first_chunk::<8>()
833 .ok_or(TokenError::InvalidInstruction)?;
834 let v = u64::from_le_bytes(*amount);
835 Ok((COption::Some(v), rest))
836 }
837 _ => Err(TokenError::InvalidInstruction.into()),
838 }
839 }
840
841 fn pack_u64_option(value: &COption<u64>, buf: &mut Vec<u8>) {
842 match *value {
843 COption::Some(ref amount) => {
844 buf.push(1);
845 buf.extend_from_slice(&amount.to_le_bytes());
846 }
847 COption::None => buf.push(0),
848 }
849 }
850
851 fn unpack_amount_decimals(input: &[u8]) -> Result<(u64, u8, &[u8]), ProgramError> {
852 let (amount, rest) = Self::unpack_u64(input)?;
853 let (&decimals, rest) = rest.split_first().ok_or(TokenError::InvalidInstruction)?;
854 Ok((amount, decimals, rest))
855 }
856}
857
858#[repr(u8)]
860#[derive(Clone, Debug, PartialEq)]
861pub enum AuthorityType {
862 MintTokens,
864 FreezeAccount,
866 AccountOwner,
868 CloseAccount,
870}
871
872impl AuthorityType {
873 fn into(&self) -> u8 {
874 match self {
875 AuthorityType::MintTokens => 0,
876 AuthorityType::FreezeAccount => 1,
877 AuthorityType::AccountOwner => 2,
878 AuthorityType::CloseAccount => 3,
879 }
880 }
881
882 fn from(index: u8) -> Result<Self, ProgramError> {
883 match index {
884 0 => Ok(AuthorityType::MintTokens),
885 1 => Ok(AuthorityType::FreezeAccount),
886 2 => Ok(AuthorityType::AccountOwner),
887 3 => Ok(AuthorityType::CloseAccount),
888 _ => Err(TokenError::InvalidInstruction.into()),
889 }
890 }
891}
892
893pub fn initialize_mint(
895 token_program_id: &Pubkey,
896 mint_pubkey: &Pubkey,
897 mint_authority_pubkey: &Pubkey,
898 freeze_authority_pubkey: Option<&Pubkey>,
899 decimals: u8,
900) -> Result<Instruction, ProgramError> {
901 check_program_account(token_program_id)?;
902 let freeze_authority = freeze_authority_pubkey.cloned().into();
903 let data = TokenInstruction::InitializeMint {
904 mint_authority: *mint_authority_pubkey,
905 freeze_authority,
906 decimals,
907 }
908 .pack();
909
910 let accounts = vec![
911 AccountMeta::new(*mint_pubkey, false),
912 AccountMeta::new_readonly(sysvar::rent::id(), false),
913 ];
914
915 Ok(Instruction {
916 program_id: *token_program_id,
917 accounts,
918 data,
919 })
920}
921
922pub fn initialize_mint2(
924 token_program_id: &Pubkey,
925 mint_pubkey: &Pubkey,
926 mint_authority_pubkey: &Pubkey,
927 freeze_authority_pubkey: Option<&Pubkey>,
928 decimals: u8,
929) -> Result<Instruction, ProgramError> {
930 check_program_account(token_program_id)?;
931 let freeze_authority = freeze_authority_pubkey.cloned().into();
932 let data = TokenInstruction::InitializeMint2 {
933 mint_authority: *mint_authority_pubkey,
934 freeze_authority,
935 decimals,
936 }
937 .pack();
938
939 let accounts = vec![AccountMeta::new(*mint_pubkey, false)];
940
941 Ok(Instruction {
942 program_id: *token_program_id,
943 accounts,
944 data,
945 })
946}
947
948pub fn initialize_account(
950 token_program_id: &Pubkey,
951 account_pubkey: &Pubkey,
952 mint_pubkey: &Pubkey,
953 owner_pubkey: &Pubkey,
954) -> Result<Instruction, ProgramError> {
955 check_program_account(token_program_id)?;
956 let data = TokenInstruction::InitializeAccount.pack();
957
958 let accounts = vec![
959 AccountMeta::new(*account_pubkey, false),
960 AccountMeta::new_readonly(*mint_pubkey, false),
961 AccountMeta::new_readonly(*owner_pubkey, false),
962 AccountMeta::new_readonly(sysvar::rent::id(), false),
963 ];
964
965 Ok(Instruction {
966 program_id: *token_program_id,
967 accounts,
968 data,
969 })
970}
971
972pub fn initialize_account2(
974 token_program_id: &Pubkey,
975 account_pubkey: &Pubkey,
976 mint_pubkey: &Pubkey,
977 owner_pubkey: &Pubkey,
978) -> Result<Instruction, ProgramError> {
979 check_program_account(token_program_id)?;
980 let data = TokenInstruction::InitializeAccount2 {
981 owner: *owner_pubkey,
982 }
983 .pack();
984
985 let accounts = vec![
986 AccountMeta::new(*account_pubkey, false),
987 AccountMeta::new_readonly(*mint_pubkey, false),
988 AccountMeta::new_readonly(sysvar::rent::id(), false),
989 ];
990
991 Ok(Instruction {
992 program_id: *token_program_id,
993 accounts,
994 data,
995 })
996}
997
998pub fn initialize_account3(
1000 token_program_id: &Pubkey,
1001 account_pubkey: &Pubkey,
1002 mint_pubkey: &Pubkey,
1003 owner_pubkey: &Pubkey,
1004) -> Result<Instruction, ProgramError> {
1005 check_program_account(token_program_id)?;
1006 let data = TokenInstruction::InitializeAccount3 {
1007 owner: *owner_pubkey,
1008 }
1009 .pack();
1010
1011 let accounts = vec![
1012 AccountMeta::new(*account_pubkey, false),
1013 AccountMeta::new_readonly(*mint_pubkey, false),
1014 ];
1015
1016 Ok(Instruction {
1017 program_id: *token_program_id,
1018 accounts,
1019 data,
1020 })
1021}
1022
1023pub fn initialize_multisig(
1025 token_program_id: &Pubkey,
1026 multisig_pubkey: &Pubkey,
1027 signer_pubkeys: &[&Pubkey],
1028 m: u8,
1029) -> Result<Instruction, ProgramError> {
1030 check_program_account(token_program_id)?;
1031 if !is_valid_signer_index(m as usize)
1032 || !is_valid_signer_index(signer_pubkeys.len())
1033 || m as usize > signer_pubkeys.len()
1034 {
1035 return Err(ProgramError::MissingRequiredSignature);
1036 }
1037 let data = TokenInstruction::InitializeMultisig { m }.pack();
1038
1039 let mut accounts = Vec::with_capacity(1 + 1 + signer_pubkeys.len());
1040 accounts.push(AccountMeta::new(*multisig_pubkey, false));
1041 accounts.push(AccountMeta::new_readonly(sysvar::rent::id(), false));
1042 for signer_pubkey in signer_pubkeys.iter() {
1043 accounts.push(AccountMeta::new_readonly(**signer_pubkey, false));
1044 }
1045
1046 Ok(Instruction {
1047 program_id: *token_program_id,
1048 accounts,
1049 data,
1050 })
1051}
1052
1053pub fn initialize_multisig2(
1055 token_program_id: &Pubkey,
1056 multisig_pubkey: &Pubkey,
1057 signer_pubkeys: &[&Pubkey],
1058 m: u8,
1059) -> Result<Instruction, ProgramError> {
1060 check_program_account(token_program_id)?;
1061 if !is_valid_signer_index(m as usize)
1062 || !is_valid_signer_index(signer_pubkeys.len())
1063 || m as usize > signer_pubkeys.len()
1064 {
1065 return Err(ProgramError::MissingRequiredSignature);
1066 }
1067 let data = TokenInstruction::InitializeMultisig2 { m }.pack();
1068
1069 let mut accounts = Vec::with_capacity(1 + 1 + signer_pubkeys.len());
1070 accounts.push(AccountMeta::new(*multisig_pubkey, false));
1071 for signer_pubkey in signer_pubkeys.iter() {
1072 accounts.push(AccountMeta::new_readonly(**signer_pubkey, false));
1073 }
1074
1075 Ok(Instruction {
1076 program_id: *token_program_id,
1077 accounts,
1078 data,
1079 })
1080}
1081
1082pub fn transfer(
1084 token_program_id: &Pubkey,
1085 source_pubkey: &Pubkey,
1086 destination_pubkey: &Pubkey,
1087 authority_pubkey: &Pubkey,
1088 signer_pubkeys: &[&Pubkey],
1089 amount: u64,
1090) -> Result<Instruction, ProgramError> {
1091 check_program_account(token_program_id)?;
1092 let data = TokenInstruction::Transfer { amount }.pack();
1093
1094 let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1095 accounts.push(AccountMeta::new(*source_pubkey, false));
1096 accounts.push(AccountMeta::new(*destination_pubkey, false));
1097 accounts.push(AccountMeta::new_readonly(
1098 *authority_pubkey,
1099 signer_pubkeys.is_empty(),
1100 ));
1101 for signer_pubkey in signer_pubkeys.iter() {
1102 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1103 }
1104
1105 Ok(Instruction {
1106 program_id: *token_program_id,
1107 accounts,
1108 data,
1109 })
1110}
1111
1112pub fn approve(
1114 token_program_id: &Pubkey,
1115 source_pubkey: &Pubkey,
1116 delegate_pubkey: &Pubkey,
1117 owner_pubkey: &Pubkey,
1118 signer_pubkeys: &[&Pubkey],
1119 amount: u64,
1120) -> Result<Instruction, ProgramError> {
1121 check_program_account(token_program_id)?;
1122 let data = TokenInstruction::Approve { amount }.pack();
1123
1124 let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1125 accounts.push(AccountMeta::new(*source_pubkey, false));
1126 accounts.push(AccountMeta::new_readonly(*delegate_pubkey, false));
1127 accounts.push(AccountMeta::new_readonly(
1128 *owner_pubkey,
1129 signer_pubkeys.is_empty(),
1130 ));
1131 for signer_pubkey in signer_pubkeys.iter() {
1132 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1133 }
1134
1135 Ok(Instruction {
1136 program_id: *token_program_id,
1137 accounts,
1138 data,
1139 })
1140}
1141
1142pub fn revoke(
1144 token_program_id: &Pubkey,
1145 source_pubkey: &Pubkey,
1146 owner_pubkey: &Pubkey,
1147 signer_pubkeys: &[&Pubkey],
1148) -> Result<Instruction, ProgramError> {
1149 check_program_account(token_program_id)?;
1150 let data = TokenInstruction::Revoke.pack();
1151
1152 let mut accounts = Vec::with_capacity(2 + signer_pubkeys.len());
1153 accounts.push(AccountMeta::new(*source_pubkey, false));
1154 accounts.push(AccountMeta::new_readonly(
1155 *owner_pubkey,
1156 signer_pubkeys.is_empty(),
1157 ));
1158 for signer_pubkey in signer_pubkeys.iter() {
1159 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1160 }
1161
1162 Ok(Instruction {
1163 program_id: *token_program_id,
1164 accounts,
1165 data,
1166 })
1167}
1168
1169pub fn set_authority(
1171 token_program_id: &Pubkey,
1172 owned_pubkey: &Pubkey,
1173 new_authority_pubkey: Option<&Pubkey>,
1174 authority_type: AuthorityType,
1175 owner_pubkey: &Pubkey,
1176 signer_pubkeys: &[&Pubkey],
1177) -> Result<Instruction, ProgramError> {
1178 check_program_account(token_program_id)?;
1179 let new_authority = new_authority_pubkey.cloned().into();
1180 let data = TokenInstruction::SetAuthority {
1181 authority_type,
1182 new_authority,
1183 }
1184 .pack();
1185
1186 let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1187 accounts.push(AccountMeta::new(*owned_pubkey, false));
1188 accounts.push(AccountMeta::new_readonly(
1189 *owner_pubkey,
1190 signer_pubkeys.is_empty(),
1191 ));
1192 for signer_pubkey in signer_pubkeys.iter() {
1193 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1194 }
1195
1196 Ok(Instruction {
1197 program_id: *token_program_id,
1198 accounts,
1199 data,
1200 })
1201}
1202
1203pub fn mint_to(
1205 token_program_id: &Pubkey,
1206 mint_pubkey: &Pubkey,
1207 account_pubkey: &Pubkey,
1208 owner_pubkey: &Pubkey,
1209 signer_pubkeys: &[&Pubkey],
1210 amount: u64,
1211) -> Result<Instruction, ProgramError> {
1212 check_program_account(token_program_id)?;
1213 let data = TokenInstruction::MintTo { amount }.pack();
1214
1215 let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1216 accounts.push(AccountMeta::new(*mint_pubkey, false));
1217 accounts.push(AccountMeta::new(*account_pubkey, false));
1218 accounts.push(AccountMeta::new_readonly(
1219 *owner_pubkey,
1220 signer_pubkeys.is_empty(),
1221 ));
1222 for signer_pubkey in signer_pubkeys.iter() {
1223 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1224 }
1225
1226 Ok(Instruction {
1227 program_id: *token_program_id,
1228 accounts,
1229 data,
1230 })
1231}
1232
1233pub fn burn(
1235 token_program_id: &Pubkey,
1236 account_pubkey: &Pubkey,
1237 mint_pubkey: &Pubkey,
1238 authority_pubkey: &Pubkey,
1239 signer_pubkeys: &[&Pubkey],
1240 amount: u64,
1241) -> Result<Instruction, ProgramError> {
1242 check_program_account(token_program_id)?;
1243 let data = TokenInstruction::Burn { amount }.pack();
1244
1245 let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1246 accounts.push(AccountMeta::new(*account_pubkey, false));
1247 accounts.push(AccountMeta::new(*mint_pubkey, false));
1248 accounts.push(AccountMeta::new_readonly(
1249 *authority_pubkey,
1250 signer_pubkeys.is_empty(),
1251 ));
1252 for signer_pubkey in signer_pubkeys.iter() {
1253 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1254 }
1255
1256 Ok(Instruction {
1257 program_id: *token_program_id,
1258 accounts,
1259 data,
1260 })
1261}
1262
1263pub fn close_account(
1265 token_program_id: &Pubkey,
1266 account_pubkey: &Pubkey,
1267 destination_pubkey: &Pubkey,
1268 owner_pubkey: &Pubkey,
1269 signer_pubkeys: &[&Pubkey],
1270) -> Result<Instruction, ProgramError> {
1271 check_program_account(token_program_id)?;
1272 let data = TokenInstruction::CloseAccount.pack();
1273
1274 let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1275 accounts.push(AccountMeta::new(*account_pubkey, false));
1276 accounts.push(AccountMeta::new(*destination_pubkey, false));
1277 accounts.push(AccountMeta::new_readonly(
1278 *owner_pubkey,
1279 signer_pubkeys.is_empty(),
1280 ));
1281 for signer_pubkey in signer_pubkeys.iter() {
1282 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1283 }
1284
1285 Ok(Instruction {
1286 program_id: *token_program_id,
1287 accounts,
1288 data,
1289 })
1290}
1291
1292pub fn freeze_account(
1294 token_program_id: &Pubkey,
1295 account_pubkey: &Pubkey,
1296 mint_pubkey: &Pubkey,
1297 owner_pubkey: &Pubkey,
1298 signer_pubkeys: &[&Pubkey],
1299) -> Result<Instruction, ProgramError> {
1300 check_program_account(token_program_id)?;
1301 let data = TokenInstruction::FreezeAccount.pack();
1302
1303 let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1304 accounts.push(AccountMeta::new(*account_pubkey, false));
1305 accounts.push(AccountMeta::new_readonly(*mint_pubkey, false));
1306 accounts.push(AccountMeta::new_readonly(
1307 *owner_pubkey,
1308 signer_pubkeys.is_empty(),
1309 ));
1310 for signer_pubkey in signer_pubkeys.iter() {
1311 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1312 }
1313
1314 Ok(Instruction {
1315 program_id: *token_program_id,
1316 accounts,
1317 data,
1318 })
1319}
1320
1321pub fn thaw_account(
1323 token_program_id: &Pubkey,
1324 account_pubkey: &Pubkey,
1325 mint_pubkey: &Pubkey,
1326 owner_pubkey: &Pubkey,
1327 signer_pubkeys: &[&Pubkey],
1328) -> Result<Instruction, ProgramError> {
1329 check_program_account(token_program_id)?;
1330 let data = TokenInstruction::ThawAccount.pack();
1331
1332 let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1333 accounts.push(AccountMeta::new(*account_pubkey, false));
1334 accounts.push(AccountMeta::new_readonly(*mint_pubkey, false));
1335 accounts.push(AccountMeta::new_readonly(
1336 *owner_pubkey,
1337 signer_pubkeys.is_empty(),
1338 ));
1339 for signer_pubkey in signer_pubkeys.iter() {
1340 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1341 }
1342
1343 Ok(Instruction {
1344 program_id: *token_program_id,
1345 accounts,
1346 data,
1347 })
1348}
1349
1350#[allow(clippy::too_many_arguments)]
1352pub fn transfer_checked(
1353 token_program_id: &Pubkey,
1354 source_pubkey: &Pubkey,
1355 mint_pubkey: &Pubkey,
1356 destination_pubkey: &Pubkey,
1357 authority_pubkey: &Pubkey,
1358 signer_pubkeys: &[&Pubkey],
1359 amount: u64,
1360 decimals: u8,
1361) -> Result<Instruction, ProgramError> {
1362 check_program_account(token_program_id)?;
1363 let data = TokenInstruction::TransferChecked { amount, decimals }.pack();
1364
1365 let mut accounts = Vec::with_capacity(4 + signer_pubkeys.len());
1366 accounts.push(AccountMeta::new(*source_pubkey, false));
1367 accounts.push(AccountMeta::new_readonly(*mint_pubkey, false));
1368 accounts.push(AccountMeta::new(*destination_pubkey, false));
1369 accounts.push(AccountMeta::new_readonly(
1370 *authority_pubkey,
1371 signer_pubkeys.is_empty(),
1372 ));
1373 for signer_pubkey in signer_pubkeys.iter() {
1374 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1375 }
1376
1377 Ok(Instruction {
1378 program_id: *token_program_id,
1379 accounts,
1380 data,
1381 })
1382}
1383
1384#[allow(clippy::too_many_arguments)]
1386pub fn approve_checked(
1387 token_program_id: &Pubkey,
1388 source_pubkey: &Pubkey,
1389 mint_pubkey: &Pubkey,
1390 delegate_pubkey: &Pubkey,
1391 owner_pubkey: &Pubkey,
1392 signer_pubkeys: &[&Pubkey],
1393 amount: u64,
1394 decimals: u8,
1395) -> Result<Instruction, ProgramError> {
1396 check_program_account(token_program_id)?;
1397 let data = TokenInstruction::ApproveChecked { amount, decimals }.pack();
1398
1399 let mut accounts = Vec::with_capacity(4 + signer_pubkeys.len());
1400 accounts.push(AccountMeta::new(*source_pubkey, false));
1401 accounts.push(AccountMeta::new_readonly(*mint_pubkey, false));
1402 accounts.push(AccountMeta::new_readonly(*delegate_pubkey, false));
1403 accounts.push(AccountMeta::new_readonly(
1404 *owner_pubkey,
1405 signer_pubkeys.is_empty(),
1406 ));
1407 for signer_pubkey in signer_pubkeys.iter() {
1408 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1409 }
1410
1411 Ok(Instruction {
1412 program_id: *token_program_id,
1413 accounts,
1414 data,
1415 })
1416}
1417
1418pub fn mint_to_checked(
1420 token_program_id: &Pubkey,
1421 mint_pubkey: &Pubkey,
1422 account_pubkey: &Pubkey,
1423 owner_pubkey: &Pubkey,
1424 signer_pubkeys: &[&Pubkey],
1425 amount: u64,
1426 decimals: u8,
1427) -> Result<Instruction, ProgramError> {
1428 check_program_account(token_program_id)?;
1429 let data = TokenInstruction::MintToChecked { amount, decimals }.pack();
1430
1431 let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1432 accounts.push(AccountMeta::new(*mint_pubkey, false));
1433 accounts.push(AccountMeta::new(*account_pubkey, false));
1434 accounts.push(AccountMeta::new_readonly(
1435 *owner_pubkey,
1436 signer_pubkeys.is_empty(),
1437 ));
1438 for signer_pubkey in signer_pubkeys.iter() {
1439 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1440 }
1441
1442 Ok(Instruction {
1443 program_id: *token_program_id,
1444 accounts,
1445 data,
1446 })
1447}
1448
1449pub fn burn_checked(
1451 token_program_id: &Pubkey,
1452 account_pubkey: &Pubkey,
1453 mint_pubkey: &Pubkey,
1454 authority_pubkey: &Pubkey,
1455 signer_pubkeys: &[&Pubkey],
1456 amount: u64,
1457 decimals: u8,
1458) -> Result<Instruction, ProgramError> {
1459 check_program_account(token_program_id)?;
1460 let data = TokenInstruction::BurnChecked { amount, decimals }.pack();
1461
1462 let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1463 accounts.push(AccountMeta::new(*account_pubkey, false));
1464 accounts.push(AccountMeta::new(*mint_pubkey, false));
1465 accounts.push(AccountMeta::new_readonly(
1466 *authority_pubkey,
1467 signer_pubkeys.is_empty(),
1468 ));
1469 for signer_pubkey in signer_pubkeys.iter() {
1470 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1471 }
1472
1473 Ok(Instruction {
1474 program_id: *token_program_id,
1475 accounts,
1476 data,
1477 })
1478}
1479
1480pub fn sync_native(
1482 token_program_id: &Pubkey,
1483 account_pubkey: &Pubkey,
1484) -> Result<Instruction, ProgramError> {
1485 check_program_account(token_program_id)?;
1486
1487 Ok(Instruction {
1488 program_id: *token_program_id,
1489 accounts: vec![AccountMeta::new(*account_pubkey, false)],
1490 data: TokenInstruction::SyncNative.pack(),
1491 })
1492}
1493
1494pub fn sync_native_with_rent_sysvar(
1497 token_program_id: &Pubkey,
1498 account_pubkey: &Pubkey,
1499) -> Result<Instruction, ProgramError> {
1500 let mut instruction = sync_native(token_program_id, account_pubkey)?;
1501 instruction
1502 .accounts
1503 .push(AccountMeta::new_readonly(sysvar::rent::id(), false));
1504
1505 Ok(instruction)
1506}
1507
1508pub fn get_account_data_size(
1510 token_program_id: &Pubkey,
1511 mint_pubkey: &Pubkey,
1512) -> Result<Instruction, ProgramError> {
1513 check_program_account(token_program_id)?;
1514
1515 Ok(Instruction {
1516 program_id: *token_program_id,
1517 accounts: vec![AccountMeta::new_readonly(*mint_pubkey, false)],
1518 data: TokenInstruction::GetAccountDataSize.pack(),
1519 })
1520}
1521
1522pub fn initialize_immutable_owner(
1524 token_program_id: &Pubkey,
1525 account_pubkey: &Pubkey,
1526) -> Result<Instruction, ProgramError> {
1527 check_program_account(token_program_id)?;
1528 Ok(Instruction {
1529 program_id: *token_program_id,
1530 accounts: vec![AccountMeta::new(*account_pubkey, false)],
1531 data: TokenInstruction::InitializeImmutableOwner.pack(),
1532 })
1533}
1534
1535pub fn amount_to_ui_amount(
1537 token_program_id: &Pubkey,
1538 mint_pubkey: &Pubkey,
1539 amount: u64,
1540) -> Result<Instruction, ProgramError> {
1541 check_program_account(token_program_id)?;
1542
1543 Ok(Instruction {
1544 program_id: *token_program_id,
1545 accounts: vec![AccountMeta::new_readonly(*mint_pubkey, false)],
1546 data: TokenInstruction::AmountToUiAmount { amount }.pack(),
1547 })
1548}
1549
1550pub fn ui_amount_to_amount(
1552 token_program_id: &Pubkey,
1553 mint_pubkey: &Pubkey,
1554 ui_amount: &str,
1555) -> Result<Instruction, ProgramError> {
1556 check_program_account(token_program_id)?;
1557
1558 Ok(Instruction {
1559 program_id: *token_program_id,
1560 accounts: vec![AccountMeta::new_readonly(*mint_pubkey, false)],
1561 data: TokenInstruction::UiAmountToAmount { ui_amount }.pack(),
1562 })
1563}
1564
1565pub fn withdraw_excess_lamports(
1567 token_program_id: &Pubkey,
1568 account_pubkey: &Pubkey,
1569 destination_pubkey: &Pubkey,
1570 authority_pubkey: &Pubkey,
1571 signer_pubkeys: &[&Pubkey],
1572) -> Result<Instruction, ProgramError> {
1573 check_program_account(token_program_id)?;
1574 let data = TokenInstruction::WithdrawExcessLamports.pack();
1575
1576 let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1577 accounts.push(AccountMeta::new(*account_pubkey, false));
1578 accounts.push(AccountMeta::new(*destination_pubkey, false));
1579 accounts.push(AccountMeta::new_readonly(
1580 *authority_pubkey,
1581 signer_pubkeys.is_empty(),
1582 ));
1583 for signer_pubkey in signer_pubkeys.iter() {
1584 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1585 }
1586
1587 Ok(Instruction {
1588 program_id: *token_program_id,
1589 accounts,
1590 data,
1591 })
1592}
1593
1594pub fn unwrap_lamports(
1596 token_program_id: &Pubkey,
1597 account_pubkey: &Pubkey,
1598 destination_pubkey: &Pubkey,
1599 authority_pubkey: &Pubkey,
1600 signer_pubkeys: &[&Pubkey],
1601 amount: Option<u64>,
1602) -> Result<Instruction, ProgramError> {
1603 check_program_account(token_program_id)?;
1604
1605 let amount = amount.into();
1606 let data = TokenInstruction::UnwrapLamports { amount }.pack();
1607
1608 let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1609 accounts.push(AccountMeta::new(*account_pubkey, false));
1610 accounts.push(AccountMeta::new(*destination_pubkey, false));
1611 accounts.push(AccountMeta::new_readonly(
1612 *authority_pubkey,
1613 signer_pubkeys.is_empty(),
1614 ));
1615 for signer_pubkey in signer_pubkeys.iter() {
1616 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1617 }
1618
1619 Ok(Instruction {
1620 program_id: *token_program_id,
1621 accounts,
1622 data,
1623 })
1624}
1625
1626pub fn batch(
1628 token_program_id: &Pubkey,
1629 instructions: &[Instruction],
1630) -> Result<Instruction, ProgramError> {
1631 check_program_account(token_program_id)?;
1632
1633 let mut data: Vec<u8> = TokenInstruction::Batch.pack();
1634 let mut accounts: Vec<AccountMeta> = vec![];
1635
1636 for instruction in instructions {
1637 if token_program_id != &instruction.program_id {
1638 return Err(ProgramError::IncorrectProgramId);
1639 }
1640
1641 data.push(instruction.accounts.len() as u8);
1642
1643 if instruction.data.len() > u8::MAX as usize {
1644 return Err(ProgramError::InvalidInstructionData);
1645 }
1646
1647 data.push(instruction.data.len() as u8);
1648
1649 data.extend_from_slice(&instruction.data);
1650 accounts.extend_from_slice(&instruction.accounts);
1651 }
1652
1653 Ok(Instruction {
1654 program_id: *token_program_id,
1655 data,
1656 accounts,
1657 })
1658}
1659
1660pub fn is_valid_signer_index(index: usize) -> bool {
1663 (MIN_SIGNERS..=MAX_SIGNERS).contains(&index)
1664}
1665
1666#[cfg(test)]
1667mod test {
1668 use {super::*, proptest::prelude::*};
1669
1670 #[test]
1671 fn test_instruction_packing() {
1672 let check = TokenInstruction::InitializeMint {
1673 decimals: 2,
1674 mint_authority: Pubkey::new_from_array([1u8; 32]),
1675 freeze_authority: COption::None,
1676 };
1677 let packed = check.pack();
1678 let mut expect = Vec::from([0u8, 2]);
1679 expect.extend_from_slice(&[1u8; 32]);
1680 expect.extend_from_slice(&[0]);
1681 assert_eq!(packed, expect);
1682 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1683 assert_eq!(unpacked, check);
1684
1685 let check = TokenInstruction::InitializeMint {
1686 decimals: 2,
1687 mint_authority: Pubkey::new_from_array([2u8; 32]),
1688 freeze_authority: COption::Some(Pubkey::new_from_array([3u8; 32])),
1689 };
1690 let packed = check.pack();
1691 let mut expect = vec![0u8, 2];
1692 expect.extend_from_slice(&[2u8; 32]);
1693 expect.extend_from_slice(&[1]);
1694 expect.extend_from_slice(&[3u8; 32]);
1695 assert_eq!(packed, expect);
1696 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1697 assert_eq!(unpacked, check);
1698
1699 let check = TokenInstruction::InitializeAccount;
1700 let packed = check.pack();
1701 let expect = Vec::from([1u8]);
1702 assert_eq!(packed, expect);
1703 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1704 assert_eq!(unpacked, check);
1705
1706 let check = TokenInstruction::InitializeMultisig { m: 1 };
1707 let packed = check.pack();
1708 let expect = Vec::from([2u8, 1]);
1709 assert_eq!(packed, expect);
1710 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1711 assert_eq!(unpacked, check);
1712
1713 let check = TokenInstruction::Transfer { amount: 1 };
1714 let packed = check.pack();
1715 let expect = Vec::from([3u8, 1, 0, 0, 0, 0, 0, 0, 0]);
1716 assert_eq!(packed, expect);
1717 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1718 assert_eq!(unpacked, check);
1719
1720 let check = TokenInstruction::Approve { amount: 1 };
1721 let packed = check.pack();
1722 let expect = Vec::from([4u8, 1, 0, 0, 0, 0, 0, 0, 0]);
1723 assert_eq!(packed, expect);
1724 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1725 assert_eq!(unpacked, check);
1726
1727 let check = TokenInstruction::Revoke;
1728 let packed = check.pack();
1729 let expect = Vec::from([5u8]);
1730 assert_eq!(packed, expect);
1731 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1732 assert_eq!(unpacked, check);
1733
1734 let check = TokenInstruction::SetAuthority {
1735 authority_type: AuthorityType::FreezeAccount,
1736 new_authority: COption::Some(Pubkey::new_from_array([4u8; 32])),
1737 };
1738 let packed = check.pack();
1739 let mut expect = Vec::from([6u8, 1]);
1740 expect.extend_from_slice(&[1]);
1741 expect.extend_from_slice(&[4u8; 32]);
1742 assert_eq!(packed, expect);
1743 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1744 assert_eq!(unpacked, check);
1745
1746 let check = TokenInstruction::MintTo { amount: 1 };
1747 let packed = check.pack();
1748 let expect = Vec::from([7u8, 1, 0, 0, 0, 0, 0, 0, 0]);
1749 assert_eq!(packed, expect);
1750 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1751 assert_eq!(unpacked, check);
1752
1753 let check = TokenInstruction::Burn { amount: 1 };
1754 let packed = check.pack();
1755 let expect = Vec::from([8u8, 1, 0, 0, 0, 0, 0, 0, 0]);
1756 assert_eq!(packed, expect);
1757 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1758 assert_eq!(unpacked, check);
1759
1760 let check = TokenInstruction::CloseAccount;
1761 let packed = check.pack();
1762 let expect = Vec::from([9u8]);
1763 assert_eq!(packed, expect);
1764 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1765 assert_eq!(unpacked, check);
1766
1767 let check = TokenInstruction::FreezeAccount;
1768 let packed = check.pack();
1769 let expect = Vec::from([10u8]);
1770 assert_eq!(packed, expect);
1771 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1772 assert_eq!(unpacked, check);
1773
1774 let check = TokenInstruction::ThawAccount;
1775 let packed = check.pack();
1776 let expect = Vec::from([11u8]);
1777 assert_eq!(packed, expect);
1778 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1779 assert_eq!(unpacked, check);
1780
1781 let check = TokenInstruction::TransferChecked {
1782 amount: 1,
1783 decimals: 2,
1784 };
1785 let packed = check.pack();
1786 let expect = Vec::from([12u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]);
1787 assert_eq!(packed, expect);
1788 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1789 assert_eq!(unpacked, check);
1790
1791 let check = TokenInstruction::ApproveChecked {
1792 amount: 1,
1793 decimals: 2,
1794 };
1795 let packed = check.pack();
1796 let expect = Vec::from([13u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]);
1797 assert_eq!(packed, expect);
1798 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1799 assert_eq!(unpacked, check);
1800
1801 let check = TokenInstruction::MintToChecked {
1802 amount: 1,
1803 decimals: 2,
1804 };
1805 let packed = check.pack();
1806 let expect = Vec::from([14u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]);
1807 assert_eq!(packed, expect);
1808 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1809 assert_eq!(unpacked, check);
1810
1811 let check = TokenInstruction::BurnChecked {
1812 amount: 1,
1813 decimals: 2,
1814 };
1815 let packed = check.pack();
1816 let expect = Vec::from([15u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]);
1817 assert_eq!(packed, expect);
1818 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1819 assert_eq!(unpacked, check);
1820
1821 let check = TokenInstruction::InitializeAccount2 {
1822 owner: Pubkey::new_from_array([2u8; 32]),
1823 };
1824 let packed = check.pack();
1825 let mut expect = vec![16u8];
1826 expect.extend_from_slice(&[2u8; 32]);
1827 assert_eq!(packed, expect);
1828 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1829 assert_eq!(unpacked, check);
1830
1831 let check = TokenInstruction::SyncNative;
1832 let packed = check.pack();
1833 let expect = vec![17u8];
1834 assert_eq!(packed, expect);
1835 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1836 assert_eq!(unpacked, check);
1837
1838 let check = TokenInstruction::InitializeAccount3 {
1839 owner: Pubkey::new_from_array([2u8; 32]),
1840 };
1841 let packed = check.pack();
1842 let mut expect = vec![18u8];
1843 expect.extend_from_slice(&[2u8; 32]);
1844 assert_eq!(packed, expect);
1845 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1846 assert_eq!(unpacked, check);
1847
1848 let check = TokenInstruction::InitializeMultisig2 { m: 1 };
1849 let packed = check.pack();
1850 let expect = Vec::from([19u8, 1]);
1851 assert_eq!(packed, expect);
1852 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1853 assert_eq!(unpacked, check);
1854
1855 let check = TokenInstruction::InitializeMint2 {
1856 decimals: 2,
1857 mint_authority: Pubkey::new_from_array([1u8; 32]),
1858 freeze_authority: COption::None,
1859 };
1860 let packed = check.pack();
1861 let mut expect = Vec::from([20u8, 2]);
1862 expect.extend_from_slice(&[1u8; 32]);
1863 expect.extend_from_slice(&[0]);
1864 assert_eq!(packed, expect);
1865 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1866 assert_eq!(unpacked, check);
1867
1868 let check = TokenInstruction::InitializeMint2 {
1869 decimals: 2,
1870 mint_authority: Pubkey::new_from_array([2u8; 32]),
1871 freeze_authority: COption::Some(Pubkey::new_from_array([3u8; 32])),
1872 };
1873 let packed = check.pack();
1874 let mut expect = vec![20u8, 2];
1875 expect.extend_from_slice(&[2u8; 32]);
1876 expect.extend_from_slice(&[1]);
1877 expect.extend_from_slice(&[3u8; 32]);
1878 assert_eq!(packed, expect);
1879 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1880 assert_eq!(unpacked, check);
1881
1882 let check = TokenInstruction::GetAccountDataSize;
1883 let packed = check.pack();
1884 let expect = vec![21u8];
1885 assert_eq!(packed, expect);
1886 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1887 assert_eq!(unpacked, check);
1888
1889 let check = TokenInstruction::InitializeImmutableOwner;
1890 let packed = check.pack();
1891 let expect = vec![22u8];
1892 assert_eq!(packed, expect);
1893 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1894 assert_eq!(unpacked, check);
1895
1896 let check = TokenInstruction::AmountToUiAmount { amount: 42 };
1897 let packed = check.pack();
1898 let expect = vec![23u8, 42, 0, 0, 0, 0, 0, 0, 0];
1899 assert_eq!(packed, expect);
1900 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1901 assert_eq!(unpacked, check);
1902
1903 let check = TokenInstruction::UiAmountToAmount { ui_amount: "0.42" };
1904 let packed = check.pack();
1905 let expect = vec![24u8, 48, 46, 52, 50];
1906 assert_eq!(packed, expect);
1907 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1908 assert_eq!(unpacked, check);
1909
1910 let check = TokenInstruction::WithdrawExcessLamports;
1911 let packed = check.pack();
1912 let expect = vec![38u8];
1913 assert_eq!(packed, expect);
1914 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1915 assert_eq!(unpacked, check);
1916
1917 let check = TokenInstruction::UnwrapLamports {
1918 amount: COption::Some(42),
1919 };
1920 let packed = check.pack();
1921 let expect = vec![45u8, 1, 42, 0, 0, 0, 0, 0, 0, 0];
1922 assert_eq!(packed, expect);
1923 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1924 assert_eq!(unpacked, check);
1925
1926 let check = TokenInstruction::UnwrapLamports {
1927 amount: COption::None,
1928 };
1929 let packed = check.pack();
1930 let expect = vec![45u8, 0];
1931 assert_eq!(packed, expect);
1932 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1933 assert_eq!(unpacked, check);
1934
1935 let check = TokenInstruction::Batch;
1936 let packed = check.pack();
1937 let expect = vec![255u8];
1938 assert_eq!(packed, expect);
1939 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1940 assert_eq!(unpacked, check);
1941 }
1942
1943 #[test]
1944 fn test_instruction_unpack_panic() {
1945 for i in 0..255u8 {
1946 for j in 1..10 {
1947 let mut data = vec![0; j];
1948 data[0] = i;
1949 let _no_panic = TokenInstruction::unpack(&data);
1950 }
1951 }
1952 }
1953
1954 proptest! {
1955 #![proptest_config(ProptestConfig::with_cases(1024))]
1956 #[test]
1957 fn test_instruction_unpack_proptest(
1958 data in prop::collection::vec(any::<u8>(), 0..255)
1959 ) {
1960 let _no_panic = TokenInstruction::unpack(&data);
1961 }
1962 }
1963}