1#![allow(deprecated)] use {
6 crate::{
7 check_program_account, check_safe_token_program_account,
8 error::TokenError,
9 extension::{transfer_fee::instruction::TransferFeeInstruction, ExtensionType},
10 pod::{pod_from_bytes, pod_get_packed_len},
11 },
12 bytemuck::Pod,
13 solana_program::{
14 instruction::{AccountMeta, Instruction},
15 program_error::ProgramError,
16 program_option::COption,
17 pubkey::{Pubkey, PUBKEY_BYTES},
18 system_program, sysvar,
19 },
20 std::{
21 convert::{TryFrom, TryInto},
22 mem::size_of,
23 },
24};
25
26#[cfg(feature = "serde-traits")]
27use {
28 crate::serialization::coption_fromstr,
29 serde::{Deserialize, Serialize},
30 serde_with::{As, DisplayFromStr},
31};
32
33pub const MIN_SIGNERS: usize = 1;
35pub const MAX_SIGNERS: usize = 11;
37const U16_BYTES: usize = 2;
39const U64_BYTES: usize = 8;
41
42#[repr(C)]
44#[cfg_attr(feature = "serde-traits", derive(Serialize, Deserialize))]
45#[derive(Clone, Debug, PartialEq)]
46pub enum TokenInstruction<'a> {
47 InitializeMint {
64 decimals: u8,
66 #[cfg_attr(feature = "serde-traits", serde(with = "As::<DisplayFromStr>"))]
68 mint_authority: Pubkey,
69 #[cfg_attr(feature = "serde-traits", serde(with = "coption_fromstr"))]
71 freeze_authority: COption<Pubkey>,
72 },
73 InitializeAccount,
92 InitializeMultisig {
112 m: u8,
115 },
116 #[deprecated(
140 since = "4.0.0",
141 note = "please use `TransferChecked` or `TransferCheckedWithFee` instead"
142 )]
143 Transfer {
144 amount: u64,
146 },
147 Approve {
163 amount: u64,
165 },
166 Revoke,
179 SetAuthority {
192 authority_type: AuthorityType,
194 #[cfg_attr(feature = "serde-traits", serde(with = "coption_fromstr"))]
196 new_authority: COption<Pubkey>,
197 },
198 MintTo {
214 amount: u64,
216 },
217 Burn {
233 amount: u64,
235 },
236 CloseAccount,
262 FreezeAccount,
278 ThawAccount,
293
294 TransferChecked {
321 amount: u64,
323 decimals: u8,
325 },
326 ApproveChecked {
348 amount: u64,
350 decimals: u8,
352 },
353 MintToChecked {
373 amount: u64,
375 decimals: u8,
377 },
378 BurnChecked {
399 amount: u64,
401 decimals: u8,
403 },
404 InitializeAccount2 {
415 owner: Pubkey,
417 },
418 SyncNative,
428 InitializeAccount3 {
435 owner: Pubkey,
437 },
438 InitializeMultisig2 {
446 m: u8,
449 },
450 InitializeMint2 {
457 decimals: u8,
459 #[cfg_attr(feature = "serde-traits", serde(with = "As::<DisplayFromStr>"))]
461 mint_authority: Pubkey,
462 #[cfg_attr(feature = "serde-traits", serde(with = "coption_fromstr"))]
464 freeze_authority: COption<Pubkey>,
465 },
466 GetAccountDataSize {
476 extension_types: Vec<ExtensionType>,
478 },
479 InitializeImmutableOwner,
492 AmountToUiAmount {
503 amount: u64,
505 },
506 UiAmountToAmount {
515 ui_amount: &'a str,
517 },
518 InitializeMintCloseAuthority {
531 #[cfg_attr(feature = "serde-traits", serde(with = "coption_fromstr"))]
533 close_authority: COption<Pubkey>,
534 },
535 TransferFeeExtension(TransferFeeInstruction),
540 ConfidentialTransferExtension,
545 DefaultAccountStateExtension,
550 Reallocate {
569 extension_types: Vec<ExtensionType>,
571 },
572 MemoTransferExtension,
577 CreateNativeMint,
590 InitializeNonTransferableMint,
603 InterestBearingMintExtension,
608 CpiGuardExtension,
613 InitializePermanentDelegate {
630 delegate: Pubkey,
632 },
633}
634impl<'a> TokenInstruction<'a> {
635 pub fn unpack(input: &'a [u8]) -> Result<Self, ProgramError> {
637 use TokenError::InvalidInstruction;
638
639 let (&tag, rest) = input.split_first().ok_or(InvalidInstruction)?;
640 Ok(match tag {
641 0 => {
642 let (&decimals, rest) = rest.split_first().ok_or(InvalidInstruction)?;
643 let (mint_authority, rest) = Self::unpack_pubkey(rest)?;
644 let (freeze_authority, _rest) = Self::unpack_pubkey_option(rest)?;
645 Self::InitializeMint {
646 mint_authority,
647 freeze_authority,
648 decimals,
649 }
650 }
651 1 => Self::InitializeAccount,
652 2 => {
653 let &m = rest.get(0).ok_or(InvalidInstruction)?;
654 Self::InitializeMultisig { m }
655 }
656 3 | 4 | 7 | 8 => {
657 let amount = rest
658 .get(..U64_BYTES)
659 .and_then(|slice| slice.try_into().ok())
660 .map(u64::from_le_bytes)
661 .ok_or(InvalidInstruction)?;
662 match tag {
663 #[allow(deprecated)]
664 3 => Self::Transfer { amount },
665 4 => Self::Approve { amount },
666 7 => Self::MintTo { amount },
667 8 => Self::Burn { amount },
668 _ => unreachable!(),
669 }
670 }
671 5 => Self::Revoke,
672 6 => {
673 let (authority_type, rest) = rest
674 .split_first()
675 .ok_or_else(|| ProgramError::from(InvalidInstruction))
676 .and_then(|(&t, rest)| Ok((AuthorityType::from(t)?, rest)))?;
677 let (new_authority, _rest) = Self::unpack_pubkey_option(rest)?;
678
679 Self::SetAuthority {
680 authority_type,
681 new_authority,
682 }
683 }
684 9 => Self::CloseAccount,
685 10 => Self::FreezeAccount,
686 11 => Self::ThawAccount,
687 12 => {
688 let (amount, decimals, _rest) = Self::unpack_amount_decimals(rest)?;
689 Self::TransferChecked { amount, decimals }
690 }
691 13 => {
692 let (amount, decimals, _rest) = Self::unpack_amount_decimals(rest)?;
693 Self::ApproveChecked { amount, decimals }
694 }
695 14 => {
696 let (amount, decimals, _rest) = Self::unpack_amount_decimals(rest)?;
697 Self::MintToChecked { amount, decimals }
698 }
699 15 => {
700 let (amount, decimals, _rest) = Self::unpack_amount_decimals(rest)?;
701 Self::BurnChecked { amount, decimals }
702 }
703 16 => {
704 let (owner, _rest) = Self::unpack_pubkey(rest)?;
705 Self::InitializeAccount2 { owner }
706 }
707 17 => Self::SyncNative,
708 18 => {
709 let (owner, _rest) = Self::unpack_pubkey(rest)?;
710 Self::InitializeAccount3 { owner }
711 }
712 19 => {
713 let &m = rest.get(0).ok_or(InvalidInstruction)?;
714 Self::InitializeMultisig2 { m }
715 }
716 20 => {
717 let (&decimals, rest) = rest.split_first().ok_or(InvalidInstruction)?;
718 let (mint_authority, rest) = Self::unpack_pubkey(rest)?;
719 let (freeze_authority, _rest) = Self::unpack_pubkey_option(rest)?;
720 Self::InitializeMint2 {
721 mint_authority,
722 freeze_authority,
723 decimals,
724 }
725 }
726 21 => {
727 let mut extension_types = vec![];
728 for chunk in rest.chunks(size_of::<ExtensionType>()) {
729 extension_types.push(chunk.try_into()?);
730 }
731 Self::GetAccountDataSize { extension_types }
732 }
733 22 => Self::InitializeImmutableOwner,
734 23 => {
735 let (amount, _rest) = Self::unpack_u64(rest)?;
736 Self::AmountToUiAmount { amount }
737 }
738 24 => {
739 let ui_amount = std::str::from_utf8(rest).map_err(|_| InvalidInstruction)?;
740 Self::UiAmountToAmount { ui_amount }
741 }
742 25 => {
743 let (close_authority, _rest) = Self::unpack_pubkey_option(rest)?;
744 Self::InitializeMintCloseAuthority { close_authority }
745 }
746 26 => {
747 let (instruction, _rest) = TransferFeeInstruction::unpack(rest)?;
748 Self::TransferFeeExtension(instruction)
749 }
750 27 => Self::ConfidentialTransferExtension,
751 28 => Self::DefaultAccountStateExtension,
752 29 => {
753 let mut extension_types = vec![];
754 for chunk in rest.chunks(size_of::<ExtensionType>()) {
755 extension_types.push(chunk.try_into()?);
756 }
757 Self::Reallocate { extension_types }
758 }
759 30 => Self::MemoTransferExtension,
760 31 => Self::CreateNativeMint,
761 32 => Self::InitializeNonTransferableMint,
762 33 => Self::InterestBearingMintExtension,
763 34 => Self::CpiGuardExtension,
764 35 => {
765 let (delegate, _rest) = Self::unpack_pubkey(rest)?;
766 Self::InitializePermanentDelegate { delegate }
767 }
768 _ => return Err(TokenError::InvalidInstruction.into()),
769 })
770 }
771
772 pub fn pack(&self) -> Vec<u8> {
774 let mut buf = Vec::with_capacity(size_of::<Self>());
775 match self {
776 &Self::InitializeMint {
777 ref mint_authority,
778 ref freeze_authority,
779 decimals,
780 } => {
781 buf.push(0);
782 buf.push(decimals);
783 buf.extend_from_slice(mint_authority.as_ref());
784 Self::pack_pubkey_option(freeze_authority, &mut buf);
785 }
786 Self::InitializeAccount => buf.push(1),
787 &Self::InitializeMultisig { m } => {
788 buf.push(2);
789 buf.push(m);
790 }
791 #[allow(deprecated)]
792 &Self::Transfer { amount } => {
793 buf.push(3);
794 buf.extend_from_slice(&amount.to_le_bytes());
795 }
796 &Self::Approve { amount } => {
797 buf.push(4);
798 buf.extend_from_slice(&amount.to_le_bytes());
799 }
800 &Self::MintTo { amount } => {
801 buf.push(7);
802 buf.extend_from_slice(&amount.to_le_bytes());
803 }
804 &Self::Burn { amount } => {
805 buf.push(8);
806 buf.extend_from_slice(&amount.to_le_bytes());
807 }
808 Self::Revoke => buf.push(5),
809 Self::SetAuthority {
810 authority_type,
811 ref new_authority,
812 } => {
813 buf.push(6);
814 buf.push(authority_type.into());
815 Self::pack_pubkey_option(new_authority, &mut buf);
816 }
817 Self::CloseAccount => buf.push(9),
818 Self::FreezeAccount => buf.push(10),
819 Self::ThawAccount => buf.push(11),
820 &Self::TransferChecked { amount, decimals } => {
821 buf.push(12);
822 buf.extend_from_slice(&amount.to_le_bytes());
823 buf.push(decimals);
824 }
825 &Self::ApproveChecked { amount, decimals } => {
826 buf.push(13);
827 buf.extend_from_slice(&amount.to_le_bytes());
828 buf.push(decimals);
829 }
830 &Self::MintToChecked { amount, decimals } => {
831 buf.push(14);
832 buf.extend_from_slice(&amount.to_le_bytes());
833 buf.push(decimals);
834 }
835 &Self::BurnChecked { amount, decimals } => {
836 buf.push(15);
837 buf.extend_from_slice(&amount.to_le_bytes());
838 buf.push(decimals);
839 }
840 &Self::InitializeAccount2 { owner } => {
841 buf.push(16);
842 buf.extend_from_slice(owner.as_ref());
843 }
844 &Self::SyncNative => {
845 buf.push(17);
846 }
847 &Self::InitializeAccount3 { owner } => {
848 buf.push(18);
849 buf.extend_from_slice(owner.as_ref());
850 }
851 &Self::InitializeMultisig2 { m } => {
852 buf.push(19);
853 buf.push(m);
854 }
855 &Self::InitializeMint2 {
856 ref mint_authority,
857 ref freeze_authority,
858 decimals,
859 } => {
860 buf.push(20);
861 buf.push(decimals);
862 buf.extend_from_slice(mint_authority.as_ref());
863 Self::pack_pubkey_option(freeze_authority, &mut buf);
864 }
865 &Self::GetAccountDataSize {
866 ref extension_types,
867 } => {
868 buf.push(21);
869 for extension_type in extension_types {
870 buf.extend_from_slice(&<[u8; 2]>::from(*extension_type));
871 }
872 }
873 &Self::InitializeImmutableOwner => {
874 buf.push(22);
875 }
876 &Self::AmountToUiAmount { amount } => {
877 buf.push(23);
878 buf.extend_from_slice(&amount.to_le_bytes());
879 }
880 Self::UiAmountToAmount { ui_amount } => {
881 buf.push(24);
882 buf.extend_from_slice(ui_amount.as_bytes());
883 }
884 &Self::InitializeMintCloseAuthority {
885 ref close_authority,
886 } => {
887 buf.push(25);
888 Self::pack_pubkey_option(close_authority, &mut buf);
889 }
890 &Self::TransferFeeExtension(ref instruction) => {
891 buf.push(26);
892 TransferFeeInstruction::pack(instruction, &mut buf);
893 }
894 &Self::ConfidentialTransferExtension => {
895 buf.push(27);
896 }
897 &Self::DefaultAccountStateExtension => {
898 buf.push(28);
899 }
900 &Self::Reallocate {
901 ref extension_types,
902 } => {
903 buf.push(29);
904 for extension_type in extension_types {
905 buf.extend_from_slice(&<[u8; 2]>::from(*extension_type));
906 }
907 }
908 &Self::MemoTransferExtension => {
909 buf.push(30);
910 }
911 &Self::CreateNativeMint => {
912 buf.push(31);
913 }
914 &Self::InitializeNonTransferableMint => {
915 buf.push(32);
916 }
917 &Self::InterestBearingMintExtension => {
918 buf.push(33);
919 }
920 &Self::CpiGuardExtension => {
921 buf.push(34);
922 }
923 &Self::InitializePermanentDelegate { ref delegate } => {
924 buf.push(35);
925 buf.extend_from_slice(delegate.as_ref());
926 }
927 };
928 buf
929 }
930
931 pub(crate) fn unpack_pubkey(input: &[u8]) -> Result<(Pubkey, &[u8]), ProgramError> {
932 let pk = input
933 .get(..PUBKEY_BYTES)
934 .map(Pubkey::new)
935 .ok_or(TokenError::InvalidInstruction)?;
936 Ok((pk, &input[PUBKEY_BYTES..]))
937 }
938
939 pub(crate) fn unpack_pubkey_option(
940 input: &[u8],
941 ) -> Result<(COption<Pubkey>, &[u8]), ProgramError> {
942 match input.split_first() {
943 Option::Some((&0, rest)) => Ok((COption::None, rest)),
944 Option::Some((&1, rest)) => {
945 let (pk, rest) = Self::unpack_pubkey(rest)?;
946 Ok((COption::Some(pk), rest))
947 }
948 _ => Err(TokenError::InvalidInstruction.into()),
949 }
950 }
951
952 pub(crate) fn pack_pubkey_option(value: &COption<Pubkey>, buf: &mut Vec<u8>) {
953 match *value {
954 COption::Some(ref key) => {
955 buf.push(1);
956 buf.extend_from_slice(&key.to_bytes());
957 }
958 COption::None => buf.push(0),
959 }
960 }
961
962 pub(crate) fn unpack_u16(input: &[u8]) -> Result<(u16, &[u8]), ProgramError> {
963 let value = input
964 .get(..U16_BYTES)
965 .and_then(|slice| slice.try_into().ok())
966 .map(u16::from_le_bytes)
967 .ok_or(TokenError::InvalidInstruction)?;
968 Ok((value, &input[U16_BYTES..]))
969 }
970
971 pub(crate) fn unpack_u64(input: &[u8]) -> Result<(u64, &[u8]), ProgramError> {
972 let value = input
973 .get(..U64_BYTES)
974 .and_then(|slice| slice.try_into().ok())
975 .map(u64::from_le_bytes)
976 .ok_or(TokenError::InvalidInstruction)?;
977 Ok((value, &input[U64_BYTES..]))
978 }
979
980 pub(crate) fn unpack_amount_decimals(input: &[u8]) -> Result<(u64, u8, &[u8]), ProgramError> {
981 let (amount, rest) = Self::unpack_u64(input)?;
982 let (&decimals, rest) = rest.split_first().ok_or(TokenError::InvalidInstruction)?;
983 Ok((amount, decimals, rest))
984 }
985}
986
987#[repr(u8)]
989#[cfg_attr(feature = "serde-traits", derive(Serialize, Deserialize))]
990#[derive(Clone, Debug, PartialEq)]
991pub enum AuthorityType {
992 MintTokens,
994 FreezeAccount,
996 AccountOwner,
998 CloseAccount,
1000 TransferFeeConfig,
1002 WithheldWithdraw,
1004 CloseMint,
1006 InterestRate,
1008 PermanentDelegate,
1010 ConfidentialTransferMint,
1013}
1014
1015impl AuthorityType {
1016 fn into(&self) -> u8 {
1017 match self {
1018 AuthorityType::MintTokens => 0,
1019 AuthorityType::FreezeAccount => 1,
1020 AuthorityType::AccountOwner => 2,
1021 AuthorityType::CloseAccount => 3,
1022 AuthorityType::TransferFeeConfig => 4,
1023 AuthorityType::WithheldWithdraw => 5,
1024 AuthorityType::CloseMint => 6,
1025 AuthorityType::InterestRate => 7,
1026 AuthorityType::PermanentDelegate => 8,
1027 AuthorityType::ConfidentialTransferMint => 9,
1028 }
1029 }
1030
1031 fn from(index: u8) -> Result<Self, ProgramError> {
1032 match index {
1033 0 => Ok(AuthorityType::MintTokens),
1034 1 => Ok(AuthorityType::FreezeAccount),
1035 2 => Ok(AuthorityType::AccountOwner),
1036 3 => Ok(AuthorityType::CloseAccount),
1037 4 => Ok(AuthorityType::TransferFeeConfig),
1038 5 => Ok(AuthorityType::WithheldWithdraw),
1039 6 => Ok(AuthorityType::CloseMint),
1040 7 => Ok(AuthorityType::InterestRate),
1041 8 => Ok(AuthorityType::PermanentDelegate),
1042 9 => Ok(AuthorityType::ConfidentialTransferMint),
1043 _ => Err(TokenError::InvalidInstruction.into()),
1044 }
1045 }
1046}
1047
1048pub fn initialize_mint(
1050 token_program_id: &Pubkey,
1051 mint_pubkey: &Pubkey,
1052 mint_authority_pubkey: &Pubkey,
1053 freeze_authority_pubkey: Option<&Pubkey>,
1054 decimals: u8,
1055) -> Result<Instruction, ProgramError> {
1056 check_safe_token_program_account(token_program_id)?;
1057 let freeze_authority = freeze_authority_pubkey.cloned().into();
1058 let data = TokenInstruction::InitializeMint {
1059 mint_authority: *mint_authority_pubkey,
1060 freeze_authority,
1061 decimals,
1062 }
1063 .pack();
1064
1065 let accounts = vec![
1066 AccountMeta::new(*mint_pubkey, false),
1067 AccountMeta::new_readonly(sysvar::rent::id(), false),
1068 ];
1069
1070 Ok(Instruction {
1071 program_id: *token_program_id,
1072 accounts,
1073 data,
1074 })
1075}
1076
1077pub fn initialize_mint2(
1079 token_program_id: &Pubkey,
1080 mint_pubkey: &Pubkey,
1081 mint_authority_pubkey: &Pubkey,
1082 freeze_authority_pubkey: Option<&Pubkey>,
1083 decimals: u8,
1084) -> Result<Instruction, ProgramError> {
1085 check_safe_token_program_account(token_program_id)?;
1086 let freeze_authority = freeze_authority_pubkey.cloned().into();
1087 let data = TokenInstruction::InitializeMint2 {
1088 mint_authority: *mint_authority_pubkey,
1089 freeze_authority,
1090 decimals,
1091 }
1092 .pack();
1093
1094 let accounts = vec![AccountMeta::new(*mint_pubkey, false)];
1095
1096 Ok(Instruction {
1097 program_id: *token_program_id,
1098 accounts,
1099 data,
1100 })
1101}
1102
1103pub fn initialize_account(
1105 token_program_id: &Pubkey,
1106 account_pubkey: &Pubkey,
1107 mint_pubkey: &Pubkey,
1108 owner_pubkey: &Pubkey,
1109) -> Result<Instruction, ProgramError> {
1110 check_safe_token_program_account(token_program_id)?;
1111 let data = TokenInstruction::InitializeAccount.pack();
1112
1113 let accounts = vec![
1114 AccountMeta::new(*account_pubkey, false),
1115 AccountMeta::new_readonly(*mint_pubkey, false),
1116 AccountMeta::new_readonly(*owner_pubkey, false),
1117 AccountMeta::new_readonly(sysvar::rent::id(), false),
1118 ];
1119
1120 Ok(Instruction {
1121 program_id: *token_program_id,
1122 accounts,
1123 data,
1124 })
1125}
1126
1127pub fn initialize_account2(
1129 token_program_id: &Pubkey,
1130 account_pubkey: &Pubkey,
1131 mint_pubkey: &Pubkey,
1132 owner_pubkey: &Pubkey,
1133) -> Result<Instruction, ProgramError> {
1134 check_safe_token_program_account(token_program_id)?;
1135 let data = TokenInstruction::InitializeAccount2 {
1136 owner: *owner_pubkey,
1137 }
1138 .pack();
1139
1140 let accounts = vec![
1141 AccountMeta::new(*account_pubkey, false),
1142 AccountMeta::new_readonly(*mint_pubkey, false),
1143 AccountMeta::new_readonly(sysvar::rent::id(), false),
1144 ];
1145
1146 Ok(Instruction {
1147 program_id: *token_program_id,
1148 accounts,
1149 data,
1150 })
1151}
1152
1153pub fn initialize_account3(
1155 token_program_id: &Pubkey,
1156 account_pubkey: &Pubkey,
1157 mint_pubkey: &Pubkey,
1158 owner_pubkey: &Pubkey,
1159) -> Result<Instruction, ProgramError> {
1160 check_safe_token_program_account(token_program_id)?;
1161 let data = TokenInstruction::InitializeAccount3 {
1162 owner: *owner_pubkey,
1163 }
1164 .pack();
1165
1166 let accounts = vec![
1167 AccountMeta::new(*account_pubkey, false),
1168 AccountMeta::new_readonly(*mint_pubkey, false),
1169 ];
1170
1171 Ok(Instruction {
1172 program_id: *token_program_id,
1173 accounts,
1174 data,
1175 })
1176}
1177
1178pub fn initialize_multisig(
1180 token_program_id: &Pubkey,
1181 multisig_pubkey: &Pubkey,
1182 signer_pubkeys: &[&Pubkey],
1183 m: u8,
1184) -> Result<Instruction, ProgramError> {
1185 check_safe_token_program_account(token_program_id)?;
1186 if !is_valid_signer_index(m as usize)
1187 || !is_valid_signer_index(signer_pubkeys.len())
1188 || m as usize > signer_pubkeys.len()
1189 {
1190 return Err(ProgramError::MissingRequiredSignature);
1191 }
1192 let data = TokenInstruction::InitializeMultisig { m }.pack();
1193
1194 let mut accounts = Vec::with_capacity(1 + 1 + signer_pubkeys.len());
1195 accounts.push(AccountMeta::new(*multisig_pubkey, false));
1196 accounts.push(AccountMeta::new_readonly(sysvar::rent::id(), false));
1197 for signer_pubkey in signer_pubkeys.iter() {
1198 accounts.push(AccountMeta::new_readonly(**signer_pubkey, false));
1199 }
1200
1201 Ok(Instruction {
1202 program_id: *token_program_id,
1203 accounts,
1204 data,
1205 })
1206}
1207
1208pub fn initialize_multisig2(
1210 token_program_id: &Pubkey,
1211 multisig_pubkey: &Pubkey,
1212 signer_pubkeys: &[&Pubkey],
1213 m: u8,
1214) -> Result<Instruction, ProgramError> {
1215 check_safe_token_program_account(token_program_id)?;
1216 if !is_valid_signer_index(m as usize)
1217 || !is_valid_signer_index(signer_pubkeys.len())
1218 || m as usize > signer_pubkeys.len()
1219 {
1220 return Err(ProgramError::MissingRequiredSignature);
1221 }
1222 let data = TokenInstruction::InitializeMultisig2 { m }.pack();
1223
1224 let mut accounts = Vec::with_capacity(1 + 1 + signer_pubkeys.len());
1225 accounts.push(AccountMeta::new(*multisig_pubkey, false));
1226 for signer_pubkey in signer_pubkeys.iter() {
1227 accounts.push(AccountMeta::new_readonly(**signer_pubkey, false));
1228 }
1229
1230 Ok(Instruction {
1231 program_id: *token_program_id,
1232 accounts,
1233 data,
1234 })
1235}
1236
1237#[deprecated(
1239 since = "4.0.0",
1240 note = "please use `transfer_checked` or `transfer_checked_with_fee` instead"
1241)]
1242pub fn transfer(
1243 token_program_id: &Pubkey,
1244 source_pubkey: &Pubkey,
1245 destination_pubkey: &Pubkey,
1246 authority_pubkey: &Pubkey,
1247 signer_pubkeys: &[&Pubkey],
1248 amount: u64,
1249) -> Result<Instruction, ProgramError> {
1250 check_safe_token_program_account(token_program_id)?;
1251 #[allow(deprecated)]
1252 let data = TokenInstruction::Transfer { amount }.pack();
1253
1254 let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1255 accounts.push(AccountMeta::new(*source_pubkey, false));
1256 accounts.push(AccountMeta::new(*destination_pubkey, false));
1257 accounts.push(AccountMeta::new_readonly(
1258 *authority_pubkey,
1259 signer_pubkeys.is_empty(),
1260 ));
1261 for signer_pubkey in signer_pubkeys.iter() {
1262 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1263 }
1264
1265 Ok(Instruction {
1266 program_id: *token_program_id,
1267 accounts,
1268 data,
1269 })
1270}
1271
1272pub fn approve(
1274 token_program_id: &Pubkey,
1275 source_pubkey: &Pubkey,
1276 delegate_pubkey: &Pubkey,
1277 owner_pubkey: &Pubkey,
1278 signer_pubkeys: &[&Pubkey],
1279 amount: u64,
1280) -> Result<Instruction, ProgramError> {
1281 check_safe_token_program_account(token_program_id)?;
1282 let data = TokenInstruction::Approve { amount }.pack();
1283
1284 let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1285 accounts.push(AccountMeta::new(*source_pubkey, false));
1286 accounts.push(AccountMeta::new_readonly(*delegate_pubkey, false));
1287 accounts.push(AccountMeta::new_readonly(
1288 *owner_pubkey,
1289 signer_pubkeys.is_empty(),
1290 ));
1291 for signer_pubkey in signer_pubkeys.iter() {
1292 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1293 }
1294
1295 Ok(Instruction {
1296 program_id: *token_program_id,
1297 accounts,
1298 data,
1299 })
1300}
1301
1302pub fn revoke(
1304 token_program_id: &Pubkey,
1305 source_pubkey: &Pubkey,
1306 owner_pubkey: &Pubkey,
1307 signer_pubkeys: &[&Pubkey],
1308) -> Result<Instruction, ProgramError> {
1309 check_safe_token_program_account(token_program_id)?;
1310 let data = TokenInstruction::Revoke.pack();
1311
1312 let mut accounts = Vec::with_capacity(2 + signer_pubkeys.len());
1313 accounts.push(AccountMeta::new(*source_pubkey, false));
1314 accounts.push(AccountMeta::new_readonly(
1315 *owner_pubkey,
1316 signer_pubkeys.is_empty(),
1317 ));
1318 for signer_pubkey in signer_pubkeys.iter() {
1319 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1320 }
1321
1322 Ok(Instruction {
1323 program_id: *token_program_id,
1324 accounts,
1325 data,
1326 })
1327}
1328
1329pub fn set_authority(
1331 token_program_id: &Pubkey,
1332 owned_pubkey: &Pubkey,
1333 new_authority_pubkey: Option<&Pubkey>,
1334 authority_type: AuthorityType,
1335 owner_pubkey: &Pubkey,
1336 signer_pubkeys: &[&Pubkey],
1337) -> Result<Instruction, ProgramError> {
1338 check_safe_token_program_account(token_program_id)?;
1339 let new_authority = new_authority_pubkey.cloned().into();
1340 let data = TokenInstruction::SetAuthority {
1341 authority_type,
1342 new_authority,
1343 }
1344 .pack();
1345
1346 let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1347 accounts.push(AccountMeta::new(*owned_pubkey, false));
1348 accounts.push(AccountMeta::new_readonly(
1349 *owner_pubkey,
1350 signer_pubkeys.is_empty(),
1351 ));
1352 for signer_pubkey in signer_pubkeys.iter() {
1353 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1354 }
1355
1356 Ok(Instruction {
1357 program_id: *token_program_id,
1358 accounts,
1359 data,
1360 })
1361}
1362
1363pub fn mint_to(
1365 token_program_id: &Pubkey,
1366 mint_pubkey: &Pubkey,
1367 account_pubkey: &Pubkey,
1368 owner_pubkey: &Pubkey,
1369 signer_pubkeys: &[&Pubkey],
1370 amount: u64,
1371) -> Result<Instruction, ProgramError> {
1372 check_safe_token_program_account(token_program_id)?;
1373 let data = TokenInstruction::MintTo { amount }.pack();
1374
1375 let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1376 accounts.push(AccountMeta::new(*mint_pubkey, false));
1377 accounts.push(AccountMeta::new(*account_pubkey, false));
1378 accounts.push(AccountMeta::new_readonly(
1379 *owner_pubkey,
1380 signer_pubkeys.is_empty(),
1381 ));
1382 for signer_pubkey in signer_pubkeys.iter() {
1383 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1384 }
1385
1386 Ok(Instruction {
1387 program_id: *token_program_id,
1388 accounts,
1389 data,
1390 })
1391}
1392
1393pub fn burn(
1395 token_program_id: &Pubkey,
1396 account_pubkey: &Pubkey,
1397 mint_pubkey: &Pubkey,
1398 authority_pubkey: &Pubkey,
1399 signer_pubkeys: &[&Pubkey],
1400 amount: u64,
1401) -> Result<Instruction, ProgramError> {
1402 check_safe_token_program_account(token_program_id)?;
1403 let data = TokenInstruction::Burn { amount }.pack();
1404
1405 let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1406 accounts.push(AccountMeta::new(*account_pubkey, false));
1407 accounts.push(AccountMeta::new(*mint_pubkey, false));
1408 accounts.push(AccountMeta::new_readonly(
1409 *authority_pubkey,
1410 signer_pubkeys.is_empty(),
1411 ));
1412 for signer_pubkey in signer_pubkeys.iter() {
1413 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1414 }
1415
1416 Ok(Instruction {
1417 program_id: *token_program_id,
1418 accounts,
1419 data,
1420 })
1421}
1422
1423pub fn close_account(
1425 token_program_id: &Pubkey,
1426 account_pubkey: &Pubkey,
1427 destination_pubkey: &Pubkey,
1428 owner_pubkey: &Pubkey,
1429 signer_pubkeys: &[&Pubkey],
1430) -> Result<Instruction, ProgramError> {
1431 check_safe_token_program_account(token_program_id)?;
1432 let data = TokenInstruction::CloseAccount.pack();
1433
1434 let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1435 accounts.push(AccountMeta::new(*account_pubkey, false));
1436 accounts.push(AccountMeta::new(*destination_pubkey, false));
1437 accounts.push(AccountMeta::new_readonly(
1438 *owner_pubkey,
1439 signer_pubkeys.is_empty(),
1440 ));
1441 for signer_pubkey in signer_pubkeys.iter() {
1442 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1443 }
1444
1445 Ok(Instruction {
1446 program_id: *token_program_id,
1447 accounts,
1448 data,
1449 })
1450}
1451
1452pub fn freeze_account(
1454 token_program_id: &Pubkey,
1455 account_pubkey: &Pubkey,
1456 mint_pubkey: &Pubkey,
1457 owner_pubkey: &Pubkey,
1458 signer_pubkeys: &[&Pubkey],
1459) -> Result<Instruction, ProgramError> {
1460 check_safe_token_program_account(token_program_id)?;
1461 let data = TokenInstruction::FreezeAccount.pack();
1462
1463 let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1464 accounts.push(AccountMeta::new(*account_pubkey, false));
1465 accounts.push(AccountMeta::new_readonly(*mint_pubkey, false));
1466 accounts.push(AccountMeta::new_readonly(
1467 *owner_pubkey,
1468 signer_pubkeys.is_empty(),
1469 ));
1470 for signer_pubkey in signer_pubkeys.iter() {
1471 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1472 }
1473
1474 Ok(Instruction {
1475 program_id: *token_program_id,
1476 accounts,
1477 data,
1478 })
1479}
1480
1481pub fn thaw_account(
1483 token_program_id: &Pubkey,
1484 account_pubkey: &Pubkey,
1485 mint_pubkey: &Pubkey,
1486 owner_pubkey: &Pubkey,
1487 signer_pubkeys: &[&Pubkey],
1488) -> Result<Instruction, ProgramError> {
1489 check_safe_token_program_account(token_program_id)?;
1490 let data = TokenInstruction::ThawAccount.pack();
1491
1492 let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1493 accounts.push(AccountMeta::new(*account_pubkey, false));
1494 accounts.push(AccountMeta::new_readonly(*mint_pubkey, false));
1495 accounts.push(AccountMeta::new_readonly(
1496 *owner_pubkey,
1497 signer_pubkeys.is_empty(),
1498 ));
1499 for signer_pubkey in signer_pubkeys.iter() {
1500 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1501 }
1502
1503 Ok(Instruction {
1504 program_id: *token_program_id,
1505 accounts,
1506 data,
1507 })
1508}
1509
1510#[allow(clippy::too_many_arguments)]
1512pub fn transfer_checked(
1513 token_program_id: &Pubkey,
1514 source_pubkey: &Pubkey,
1515 mint_pubkey: &Pubkey,
1516 destination_pubkey: &Pubkey,
1517 authority_pubkey: &Pubkey,
1518 signer_pubkeys: &[&Pubkey],
1519 amount: u64,
1520 decimals: u8,
1521) -> Result<Instruction, ProgramError> {
1522 check_safe_token_program_account(token_program_id)?;
1523 let data = TokenInstruction::TransferChecked { amount, decimals }.pack();
1524
1525 let mut accounts = Vec::with_capacity(4 + signer_pubkeys.len());
1526 accounts.push(AccountMeta::new(*source_pubkey, false));
1527 accounts.push(AccountMeta::new_readonly(*mint_pubkey, false));
1528 accounts.push(AccountMeta::new(*destination_pubkey, false));
1529 accounts.push(AccountMeta::new_readonly(
1530 *authority_pubkey,
1531 signer_pubkeys.is_empty(),
1532 ));
1533 for signer_pubkey in signer_pubkeys.iter() {
1534 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1535 }
1536
1537 Ok(Instruction {
1538 program_id: *token_program_id,
1539 accounts,
1540 data,
1541 })
1542}
1543
1544#[allow(clippy::too_many_arguments)]
1546pub fn approve_checked(
1547 token_program_id: &Pubkey,
1548 source_pubkey: &Pubkey,
1549 mint_pubkey: &Pubkey,
1550 delegate_pubkey: &Pubkey,
1551 owner_pubkey: &Pubkey,
1552 signer_pubkeys: &[&Pubkey],
1553 amount: u64,
1554 decimals: u8,
1555) -> Result<Instruction, ProgramError> {
1556 check_safe_token_program_account(token_program_id)?;
1557 let data = TokenInstruction::ApproveChecked { amount, decimals }.pack();
1558
1559 let mut accounts = Vec::with_capacity(4 + signer_pubkeys.len());
1560 accounts.push(AccountMeta::new(*source_pubkey, false));
1561 accounts.push(AccountMeta::new_readonly(*mint_pubkey, false));
1562 accounts.push(AccountMeta::new_readonly(*delegate_pubkey, false));
1563 accounts.push(AccountMeta::new_readonly(
1564 *owner_pubkey,
1565 signer_pubkeys.is_empty(),
1566 ));
1567 for signer_pubkey in signer_pubkeys.iter() {
1568 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1569 }
1570
1571 Ok(Instruction {
1572 program_id: *token_program_id,
1573 accounts,
1574 data,
1575 })
1576}
1577
1578pub fn mint_to_checked(
1580 token_program_id: &Pubkey,
1581 mint_pubkey: &Pubkey,
1582 account_pubkey: &Pubkey,
1583 owner_pubkey: &Pubkey,
1584 signer_pubkeys: &[&Pubkey],
1585 amount: u64,
1586 decimals: u8,
1587) -> Result<Instruction, ProgramError> {
1588 check_safe_token_program_account(token_program_id)?;
1589 let data = TokenInstruction::MintToChecked { amount, decimals }.pack();
1590
1591 let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1592 accounts.push(AccountMeta::new(*mint_pubkey, false));
1593 accounts.push(AccountMeta::new(*account_pubkey, false));
1594 accounts.push(AccountMeta::new_readonly(
1595 *owner_pubkey,
1596 signer_pubkeys.is_empty(),
1597 ));
1598 for signer_pubkey in signer_pubkeys.iter() {
1599 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1600 }
1601
1602 Ok(Instruction {
1603 program_id: *token_program_id,
1604 accounts,
1605 data,
1606 })
1607}
1608
1609pub fn burn_checked(
1611 token_program_id: &Pubkey,
1612 account_pubkey: &Pubkey,
1613 mint_pubkey: &Pubkey,
1614 authority_pubkey: &Pubkey,
1615 signer_pubkeys: &[&Pubkey],
1616 amount: u64,
1617 decimals: u8,
1618) -> Result<Instruction, ProgramError> {
1619 check_safe_token_program_account(token_program_id)?;
1620 let data = TokenInstruction::BurnChecked { amount, decimals }.pack();
1621
1622 let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1623 accounts.push(AccountMeta::new(*account_pubkey, false));
1624 accounts.push(AccountMeta::new(*mint_pubkey, false));
1625 accounts.push(AccountMeta::new_readonly(
1626 *authority_pubkey,
1627 signer_pubkeys.is_empty(),
1628 ));
1629 for signer_pubkey in signer_pubkeys.iter() {
1630 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1631 }
1632
1633 Ok(Instruction {
1634 program_id: *token_program_id,
1635 accounts,
1636 data,
1637 })
1638}
1639
1640pub fn sync_native(
1642 token_program_id: &Pubkey,
1643 account_pubkey: &Pubkey,
1644) -> Result<Instruction, ProgramError> {
1645 check_safe_token_program_account(token_program_id)?;
1646
1647 Ok(Instruction {
1648 program_id: *token_program_id,
1649 accounts: vec![AccountMeta::new(*account_pubkey, false)],
1650 data: TokenInstruction::SyncNative.pack(),
1651 })
1652}
1653
1654pub fn get_account_data_size(
1656 token_program_id: &Pubkey,
1657 mint_pubkey: &Pubkey,
1658 extension_types: &[ExtensionType],
1659) -> Result<Instruction, ProgramError> {
1660 check_safe_token_program_account(token_program_id)?;
1661 Ok(Instruction {
1662 program_id: *token_program_id,
1663 accounts: vec![AccountMeta::new_readonly(*mint_pubkey, false)],
1664 data: TokenInstruction::GetAccountDataSize {
1665 extension_types: extension_types.to_vec(),
1666 }
1667 .pack(),
1668 })
1669}
1670
1671pub fn initialize_mint_close_authority(
1673 token_program_id: &Pubkey,
1674 mint_pubkey: &Pubkey,
1675 close_authority: Option<&Pubkey>,
1676) -> Result<Instruction, ProgramError> {
1677 check_program_account(token_program_id)?;
1678 let close_authority = close_authority.cloned().into();
1679 Ok(Instruction {
1680 program_id: *token_program_id,
1681 accounts: vec![AccountMeta::new(*mint_pubkey, false)],
1682 data: TokenInstruction::InitializeMintCloseAuthority { close_authority }.pack(),
1683 })
1684}
1685
1686pub fn initialize_immutable_owner(
1688 token_program_id: &Pubkey,
1689 token_account: &Pubkey,
1690) -> Result<Instruction, ProgramError> {
1691 check_safe_token_program_account(token_program_id)?;
1692 Ok(Instruction {
1693 program_id: *token_program_id,
1694 accounts: vec![AccountMeta::new(*token_account, false)],
1695 data: TokenInstruction::InitializeImmutableOwner.pack(),
1696 })
1697}
1698
1699pub fn amount_to_ui_amount(
1701 token_program_id: &Pubkey,
1702 mint_pubkey: &Pubkey,
1703 amount: u64,
1704) -> Result<Instruction, ProgramError> {
1705 check_safe_token_program_account(token_program_id)?;
1706
1707 Ok(Instruction {
1708 program_id: *token_program_id,
1709 accounts: vec![AccountMeta::new_readonly(*mint_pubkey, false)],
1710 data: TokenInstruction::AmountToUiAmount { amount }.pack(),
1711 })
1712}
1713
1714pub fn ui_amount_to_amount(
1716 token_program_id: &Pubkey,
1717 mint_pubkey: &Pubkey,
1718 ui_amount: &str,
1719) -> Result<Instruction, ProgramError> {
1720 check_safe_token_program_account(token_program_id)?;
1721
1722 Ok(Instruction {
1723 program_id: *token_program_id,
1724 accounts: vec![AccountMeta::new_readonly(*mint_pubkey, false)],
1725 data: TokenInstruction::UiAmountToAmount { ui_amount }.pack(),
1726 })
1727}
1728
1729pub fn reallocate(
1731 token_program_id: &Pubkey,
1732 account_pubkey: &Pubkey,
1733 payer: &Pubkey,
1734 owner_pubkey: &Pubkey,
1735 signer_pubkeys: &[&Pubkey],
1736 extension_types: &[ExtensionType],
1737) -> Result<Instruction, ProgramError> {
1738 check_program_account(token_program_id)?;
1739
1740 let mut accounts = Vec::with_capacity(4 + signer_pubkeys.len());
1741 accounts.push(AccountMeta::new(*account_pubkey, false));
1742 accounts.push(AccountMeta::new(*payer, true));
1743 accounts.push(AccountMeta::new_readonly(system_program::id(), false));
1744 accounts.push(AccountMeta::new_readonly(
1745 *owner_pubkey,
1746 signer_pubkeys.is_empty(),
1747 ));
1748 for signer_pubkey in signer_pubkeys.iter() {
1749 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1750 }
1751
1752 Ok(Instruction {
1753 program_id: *token_program_id,
1754 accounts,
1755 data: TokenInstruction::Reallocate {
1756 extension_types: extension_types.to_vec(),
1757 }
1758 .pack(),
1759 })
1760}
1761
1762pub fn create_native_mint(
1764 token_program_id: &Pubkey,
1765 payer: &Pubkey,
1766) -> Result<Instruction, ProgramError> {
1767 check_program_account(token_program_id)?;
1768
1769 Ok(Instruction {
1770 program_id: *token_program_id,
1771 accounts: vec![
1772 AccountMeta::new(*payer, true),
1773 AccountMeta::new(crate::native_mint::id(), false),
1774 AccountMeta::new_readonly(system_program::id(), false),
1775 ],
1776 data: TokenInstruction::CreateNativeMint.pack(),
1777 })
1778}
1779
1780pub fn initialize_non_transferable_mint(
1782 token_program_id: &Pubkey,
1783 mint_pubkey: &Pubkey,
1784) -> Result<Instruction, ProgramError> {
1785 check_program_account(token_program_id)?;
1786 Ok(Instruction {
1787 program_id: *token_program_id,
1788 accounts: vec![AccountMeta::new(*mint_pubkey, false)],
1789 data: TokenInstruction::InitializeNonTransferableMint.pack(),
1790 })
1791}
1792
1793pub fn initialize_permanent_delegate(
1795 token_program_id: &Pubkey,
1796 mint_pubkey: &Pubkey,
1797 delegate: &Pubkey,
1798) -> Result<Instruction, ProgramError> {
1799 check_program_account(token_program_id)?;
1800 Ok(Instruction {
1801 program_id: *token_program_id,
1802 accounts: vec![AccountMeta::new(*mint_pubkey, false)],
1803 data: TokenInstruction::InitializePermanentDelegate {
1804 delegate: *delegate,
1805 }
1806 .pack(),
1807 })
1808}
1809
1810pub fn is_valid_signer_index(index: usize) -> bool {
1812 (MIN_SIGNERS..=MAX_SIGNERS).contains(&index)
1813}
1814
1815pub fn decode_instruction_type<T: TryFrom<u8>>(input: &[u8]) -> Result<T, ProgramError> {
1817 if input.is_empty() {
1818 Err(ProgramError::InvalidInstructionData)
1819 } else {
1820 T::try_from(input[0]).map_err(|_| TokenError::InvalidInstruction.into())
1821 }
1822}
1823
1824pub fn decode_instruction_data<T: Pod>(input_with_type: &[u8]) -> Result<&T, ProgramError> {
1836 if input_with_type.len() != pod_get_packed_len::<T>().saturating_add(1) {
1837 Err(ProgramError::InvalidInstructionData)
1838 } else {
1839 pod_from_bytes(&input_with_type[1..])
1840 }
1841}
1842
1843pub(crate) fn encode_instruction<T: Into<u8>, D: Pod>(
1845 token_program_id: &Pubkey,
1846 accounts: Vec<AccountMeta>,
1847 token_instruction_type: TokenInstruction,
1848 instruction_type: T,
1849 instruction_data: &D,
1850) -> Instruction {
1851 let mut data = token_instruction_type.pack();
1852 data.push(T::into(instruction_type));
1853 data.extend_from_slice(bytemuck::bytes_of(instruction_data));
1854 Instruction {
1855 program_id: *token_program_id,
1856 accounts,
1857 data,
1858 }
1859}
1860
1861#[cfg(test)]
1862mod test {
1863 use {super::*, proptest::prelude::*};
1864
1865 #[test]
1866 fn test_instruction_packing() {
1867 let check = TokenInstruction::InitializeMint {
1868 decimals: 2,
1869 mint_authority: Pubkey::new(&[1u8; 32]),
1870 freeze_authority: COption::None,
1871 };
1872 let packed = check.pack();
1873 let mut expect = Vec::from([0u8, 2]);
1874 expect.extend_from_slice(&[1u8; 32]);
1875 expect.extend_from_slice(&[0]);
1876 assert_eq!(packed, expect);
1877 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1878 assert_eq!(unpacked, check);
1879
1880 let check = TokenInstruction::InitializeMint {
1881 decimals: 2,
1882 mint_authority: Pubkey::new(&[2u8; 32]),
1883 freeze_authority: COption::Some(Pubkey::new(&[3u8; 32])),
1884 };
1885 let packed = check.pack();
1886 let mut expect = vec![0u8, 2];
1887 expect.extend_from_slice(&[2u8; 32]);
1888 expect.extend_from_slice(&[1]);
1889 expect.extend_from_slice(&[3u8; 32]);
1890 assert_eq!(packed, expect);
1891 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1892 assert_eq!(unpacked, check);
1893
1894 let check = TokenInstruction::InitializeAccount;
1895 let packed = check.pack();
1896 let expect = Vec::from([1u8]);
1897 assert_eq!(packed, expect);
1898 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1899 assert_eq!(unpacked, check);
1900
1901 let check = TokenInstruction::InitializeMultisig { m: 1 };
1902 let packed = check.pack();
1903 let expect = Vec::from([2u8, 1]);
1904 assert_eq!(packed, expect);
1905 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1906 assert_eq!(unpacked, check);
1907
1908 #[allow(deprecated)]
1909 let check = TokenInstruction::Transfer { amount: 1 };
1910 let packed = check.pack();
1911 let expect = Vec::from([3u8, 1, 0, 0, 0, 0, 0, 0, 0]);
1912 assert_eq!(packed, expect);
1913 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1914 assert_eq!(unpacked, check);
1915
1916 let check = TokenInstruction::Approve { amount: 1 };
1917 let packed = check.pack();
1918 let expect = Vec::from([4u8, 1, 0, 0, 0, 0, 0, 0, 0]);
1919 assert_eq!(packed, expect);
1920 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1921 assert_eq!(unpacked, check);
1922
1923 let check = TokenInstruction::Revoke;
1924 let packed = check.pack();
1925 let expect = Vec::from([5u8]);
1926 assert_eq!(packed, expect);
1927 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1928 assert_eq!(unpacked, check);
1929
1930 let check = TokenInstruction::SetAuthority {
1931 authority_type: AuthorityType::FreezeAccount,
1932 new_authority: COption::Some(Pubkey::new(&[4u8; 32])),
1933 };
1934 let packed = check.pack();
1935 let mut expect = Vec::from([6u8, 1]);
1936 expect.extend_from_slice(&[1]);
1937 expect.extend_from_slice(&[4u8; 32]);
1938 assert_eq!(packed, expect);
1939 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1940 assert_eq!(unpacked, check);
1941
1942 let check = TokenInstruction::MintTo { amount: 1 };
1943 let packed = check.pack();
1944 let expect = Vec::from([7u8, 1, 0, 0, 0, 0, 0, 0, 0]);
1945 assert_eq!(packed, expect);
1946 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1947 assert_eq!(unpacked, check);
1948
1949 let check = TokenInstruction::Burn { amount: 1 };
1950 let packed = check.pack();
1951 let expect = Vec::from([8u8, 1, 0, 0, 0, 0, 0, 0, 0]);
1952 assert_eq!(packed, expect);
1953 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1954 assert_eq!(unpacked, check);
1955
1956 let check = TokenInstruction::CloseAccount;
1957 let packed = check.pack();
1958 let expect = Vec::from([9u8]);
1959 assert_eq!(packed, expect);
1960 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1961 assert_eq!(unpacked, check);
1962
1963 let check = TokenInstruction::FreezeAccount;
1964 let packed = check.pack();
1965 let expect = Vec::from([10u8]);
1966 assert_eq!(packed, expect);
1967 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1968 assert_eq!(unpacked, check);
1969
1970 let check = TokenInstruction::ThawAccount;
1971 let packed = check.pack();
1972 let expect = Vec::from([11u8]);
1973 assert_eq!(packed, expect);
1974 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1975 assert_eq!(unpacked, check);
1976
1977 let check = TokenInstruction::TransferChecked {
1978 amount: 1,
1979 decimals: 2,
1980 };
1981 let packed = check.pack();
1982 let expect = Vec::from([12u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]);
1983 assert_eq!(packed, expect);
1984 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1985 assert_eq!(unpacked, check);
1986
1987 let check = TokenInstruction::ApproveChecked {
1988 amount: 1,
1989 decimals: 2,
1990 };
1991 let packed = check.pack();
1992 let expect = Vec::from([13u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]);
1993 assert_eq!(packed, expect);
1994 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1995 assert_eq!(unpacked, check);
1996
1997 let check = TokenInstruction::MintToChecked {
1998 amount: 1,
1999 decimals: 2,
2000 };
2001 let packed = check.pack();
2002 let expect = Vec::from([14u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]);
2003 assert_eq!(packed, expect);
2004 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2005 assert_eq!(unpacked, check);
2006
2007 let check = TokenInstruction::BurnChecked {
2008 amount: 1,
2009 decimals: 2,
2010 };
2011 let packed = check.pack();
2012 let expect = Vec::from([15u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]);
2013 assert_eq!(packed, expect);
2014 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2015 assert_eq!(unpacked, check);
2016
2017 let check = TokenInstruction::InitializeAccount2 {
2018 owner: Pubkey::new(&[2u8; 32]),
2019 };
2020 let packed = check.pack();
2021 let mut expect = vec![16u8];
2022 expect.extend_from_slice(&[2u8; 32]);
2023 assert_eq!(packed, expect);
2024 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2025 assert_eq!(unpacked, check);
2026
2027 let check = TokenInstruction::SyncNative;
2028 let packed = check.pack();
2029 let expect = vec![17u8];
2030 assert_eq!(packed, expect);
2031 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2032 assert_eq!(unpacked, check);
2033
2034 let check = TokenInstruction::InitializeAccount3 {
2035 owner: Pubkey::new(&[2u8; 32]),
2036 };
2037 let packed = check.pack();
2038 let mut expect = vec![18u8];
2039 expect.extend_from_slice(&[2u8; 32]);
2040 assert_eq!(packed, expect);
2041 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2042 assert_eq!(unpacked, check);
2043
2044 let check = TokenInstruction::InitializeMultisig2 { m: 1 };
2045 let packed = check.pack();
2046 let expect = Vec::from([19u8, 1]);
2047 assert_eq!(packed, expect);
2048 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2049 assert_eq!(unpacked, check);
2050
2051 let check = TokenInstruction::InitializeMint2 {
2052 decimals: 2,
2053 mint_authority: Pubkey::new(&[1u8; 32]),
2054 freeze_authority: COption::None,
2055 };
2056 let packed = check.pack();
2057 let mut expect = Vec::from([20u8, 2]);
2058 expect.extend_from_slice(&[1u8; 32]);
2059 expect.extend_from_slice(&[0]);
2060 assert_eq!(packed, expect);
2061 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2062 assert_eq!(unpacked, check);
2063
2064 let check = TokenInstruction::InitializeMint2 {
2065 decimals: 2,
2066 mint_authority: Pubkey::new(&[2u8; 32]),
2067 freeze_authority: COption::Some(Pubkey::new(&[3u8; 32])),
2068 };
2069 let packed = check.pack();
2070 let mut expect = vec![20u8, 2];
2071 expect.extend_from_slice(&[2u8; 32]);
2072 expect.extend_from_slice(&[1]);
2073 expect.extend_from_slice(&[3u8; 32]);
2074 assert_eq!(packed, expect);
2075 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2076 assert_eq!(unpacked, check);
2077
2078 let check = TokenInstruction::GetAccountDataSize {
2079 extension_types: vec![],
2080 };
2081 let packed = check.pack();
2082 let expect = [21u8];
2083 assert_eq!(packed, &[21u8]);
2084 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2085 assert_eq!(unpacked, check);
2086
2087 let check = TokenInstruction::GetAccountDataSize {
2088 extension_types: vec![
2089 ExtensionType::TransferFeeConfig,
2090 ExtensionType::TransferFeeAmount,
2091 ],
2092 };
2093 let packed = check.pack();
2094 let expect = [21u8, 1, 0, 2, 0];
2095 assert_eq!(packed, &[21u8, 1, 0, 2, 0]);
2096 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2097 assert_eq!(unpacked, check);
2098
2099 let check = TokenInstruction::AmountToUiAmount { amount: 42 };
2100 let packed = check.pack();
2101 let expect = vec![23u8, 42, 0, 0, 0, 0, 0, 0, 0];
2102 assert_eq!(packed, expect);
2103 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2104 assert_eq!(unpacked, check);
2105
2106 let check = TokenInstruction::UiAmountToAmount { ui_amount: "0.42" };
2107 let packed = check.pack();
2108 let expect = vec![24u8, 48, 46, 52, 50];
2109 assert_eq!(packed, expect);
2110 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2111 assert_eq!(unpacked, check);
2112
2113 let check = TokenInstruction::InitializeMintCloseAuthority {
2114 close_authority: COption::Some(Pubkey::new(&[10u8; 32])),
2115 };
2116 let packed = check.pack();
2117 let mut expect = vec![25u8, 1];
2118 expect.extend_from_slice(&[10u8; 32]);
2119 assert_eq!(packed, expect);
2120 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2121 assert_eq!(unpacked, check);
2122
2123 let check = TokenInstruction::CreateNativeMint;
2124 let packed = check.pack();
2125 let expect = vec![31u8];
2126 assert_eq!(packed, expect);
2127 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2128 assert_eq!(unpacked, check);
2129
2130 let check = TokenInstruction::InitializePermanentDelegate {
2131 delegate: Pubkey::new(&[11u8; 32]),
2132 };
2133 let packed = check.pack();
2134 let mut expect = vec![35u8];
2135 expect.extend_from_slice(&[11u8; 32]);
2136 assert_eq!(packed, expect);
2137 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2138 assert_eq!(unpacked, check);
2139 }
2140
2141 macro_rules! test_instruction {
2142 ($a:ident($($b:tt)*)) => {
2143 let instruction_v3 = safe_token::instruction::$a($($b)*).unwrap();
2144 let instruction_2022 = $a($($b)*).unwrap();
2145 assert_eq!(instruction_v3, instruction_2022);
2146 }
2147 }
2148
2149 #[test]
2150 fn test_v3_compatibility() {
2151 let token_program_id = safe_token::id();
2152 let mint_pubkey = Pubkey::new_unique();
2153 let mint_authority_pubkey = Pubkey::new_unique();
2154 let freeze_authority_pubkey = Pubkey::new_unique();
2155 let decimals = 9u8;
2156
2157 let account_pubkey = Pubkey::new_unique();
2158 let owner_pubkey = Pubkey::new_unique();
2159
2160 let multisig_pubkey = Pubkey::new_unique();
2161 let signer_pubkeys_vec = vec![Pubkey::new_unique(); MAX_SIGNERS];
2162 let signer_pubkeys = signer_pubkeys_vec.iter().collect::<Vec<_>>();
2163 let m = 10u8;
2164
2165 let source_pubkey = Pubkey::new_unique();
2166 let destination_pubkey = Pubkey::new_unique();
2167 let authority_pubkey = Pubkey::new_unique();
2168 let amount = 1_000_000_000_000;
2169
2170 let delegate_pubkey = Pubkey::new_unique();
2171 let owned_pubkey = Pubkey::new_unique();
2172 let new_authority_pubkey = Pubkey::new_unique();
2173
2174 let ui_amount = "100000.00";
2175
2176 test_instruction!(initialize_mint(
2177 &token_program_id,
2178 &mint_pubkey,
2179 &mint_authority_pubkey,
2180 None,
2181 decimals,
2182 ));
2183 test_instruction!(initialize_mint2(
2184 &token_program_id,
2185 &mint_pubkey,
2186 &mint_authority_pubkey,
2187 Some(&freeze_authority_pubkey),
2188 decimals,
2189 ));
2190
2191 test_instruction!(initialize_account(
2192 &token_program_id,
2193 &account_pubkey,
2194 &mint_pubkey,
2195 &owner_pubkey,
2196 ));
2197 test_instruction!(initialize_account2(
2198 &token_program_id,
2199 &account_pubkey,
2200 &mint_pubkey,
2201 &owner_pubkey,
2202 ));
2203 test_instruction!(initialize_account3(
2204 &token_program_id,
2205 &account_pubkey,
2206 &mint_pubkey,
2207 &owner_pubkey,
2208 ));
2209 test_instruction!(initialize_multisig(
2210 &token_program_id,
2211 &multisig_pubkey,
2212 &signer_pubkeys,
2213 m,
2214 ));
2215 test_instruction!(initialize_multisig2(
2216 &token_program_id,
2217 &multisig_pubkey,
2218 &signer_pubkeys,
2219 m,
2220 ));
2221 #[allow(deprecated)]
2222 {
2223 test_instruction!(transfer(
2224 &token_program_id,
2225 &source_pubkey,
2226 &destination_pubkey,
2227 &authority_pubkey,
2228 &signer_pubkeys,
2229 amount
2230 ));
2231 }
2232 test_instruction!(transfer_checked(
2233 &token_program_id,
2234 &source_pubkey,
2235 &mint_pubkey,
2236 &destination_pubkey,
2237 &authority_pubkey,
2238 &signer_pubkeys,
2239 amount,
2240 decimals,
2241 ));
2242 test_instruction!(approve(
2243 &token_program_id,
2244 &source_pubkey,
2245 &delegate_pubkey,
2246 &owner_pubkey,
2247 &signer_pubkeys,
2248 amount
2249 ));
2250 test_instruction!(approve_checked(
2251 &token_program_id,
2252 &source_pubkey,
2253 &mint_pubkey,
2254 &delegate_pubkey,
2255 &owner_pubkey,
2256 &signer_pubkeys,
2257 amount,
2258 decimals
2259 ));
2260 test_instruction!(revoke(
2261 &token_program_id,
2262 &source_pubkey,
2263 &owner_pubkey,
2264 &signer_pubkeys,
2265 ));
2266
2267 {
2269 let instruction_v3 = safe_token::instruction::set_authority(
2270 &token_program_id,
2271 &owned_pubkey,
2272 Some(&new_authority_pubkey),
2273 safe_token::instruction::AuthorityType::AccountOwner,
2274 &owner_pubkey,
2275 &signer_pubkeys,
2276 )
2277 .unwrap();
2278 let instruction_2022 = set_authority(
2279 &token_program_id,
2280 &owned_pubkey,
2281 Some(&new_authority_pubkey),
2282 AuthorityType::AccountOwner,
2283 &owner_pubkey,
2284 &signer_pubkeys,
2285 )
2286 .unwrap();
2287 assert_eq!(instruction_v3, instruction_2022);
2288 }
2289
2290 test_instruction!(mint_to(
2291 &token_program_id,
2292 &mint_pubkey,
2293 &account_pubkey,
2294 &owner_pubkey,
2295 &signer_pubkeys,
2296 amount,
2297 ));
2298 test_instruction!(mint_to_checked(
2299 &token_program_id,
2300 &mint_pubkey,
2301 &account_pubkey,
2302 &owner_pubkey,
2303 &signer_pubkeys,
2304 amount,
2305 decimals,
2306 ));
2307 test_instruction!(burn(
2308 &token_program_id,
2309 &account_pubkey,
2310 &mint_pubkey,
2311 &authority_pubkey,
2312 &signer_pubkeys,
2313 amount,
2314 ));
2315 test_instruction!(burn_checked(
2316 &token_program_id,
2317 &account_pubkey,
2318 &mint_pubkey,
2319 &authority_pubkey,
2320 &signer_pubkeys,
2321 amount,
2322 decimals,
2323 ));
2324 test_instruction!(close_account(
2325 &token_program_id,
2326 &account_pubkey,
2327 &destination_pubkey,
2328 &owner_pubkey,
2329 &signer_pubkeys,
2330 ));
2331 test_instruction!(freeze_account(
2332 &token_program_id,
2333 &account_pubkey,
2334 &mint_pubkey,
2335 &owner_pubkey,
2336 &signer_pubkeys,
2337 ));
2338 test_instruction!(thaw_account(
2339 &token_program_id,
2340 &account_pubkey,
2341 &mint_pubkey,
2342 &owner_pubkey,
2343 &signer_pubkeys,
2344 ));
2345 test_instruction!(sync_native(&token_program_id, &account_pubkey,));
2346
2347 {
2349 let instruction_v3 =
2350 safe_token::instruction::get_account_data_size(&token_program_id, &mint_pubkey)
2351 .unwrap();
2352 let instruction_2022 =
2353 get_account_data_size(&token_program_id, &mint_pubkey, &[]).unwrap();
2354 assert_eq!(instruction_v3, instruction_2022);
2355 }
2356
2357 test_instruction!(initialize_immutable_owner(
2358 &token_program_id,
2359 &account_pubkey,
2360 ));
2361
2362 test_instruction!(amount_to_ui_amount(&token_program_id, &mint_pubkey, amount,));
2363
2364 test_instruction!(ui_amount_to_amount(
2365 &token_program_id,
2366 &mint_pubkey,
2367 ui_amount,
2368 ));
2369 }
2370
2371 proptest! {
2372 #![proptest_config(ProptestConfig::with_cases(1024))]
2373 #[test]
2374 fn test_instruction_unpack_proptest(
2375 data in prop::collection::vec(any::<u8>(), 0..255)
2376 ) {
2377 let _no_panic = TokenInstruction::unpack(&data);
2378 }
2379 }
2380}