1#![allow(deprecated)]
6
7#[cfg(feature = "serde-traits")]
8use {
9 crate::serialization::coption_fromstr,
10 serde::{Deserialize, Serialize},
11 serde_with::{As, DisplayFromStr},
12};
13use {
14 crate::{
15 check_program_account, check_spl_token_program_account, error::TokenError,
16 extension::ExtensionType,
17 },
18 bytemuck::Pod,
19 solana_instruction::{AccountMeta, Instruction},
20 solana_program_error::ProgramError,
21 solana_program_option::COption,
22 solana_pubkey::{Pubkey, PUBKEY_BYTES},
23 solana_sdk_ids::{system_program, sysvar},
24 spl_pod::bytemuck::{pod_from_bytes, pod_get_packed_len},
25 std::{
26 convert::{TryFrom, TryInto},
27 mem::size_of,
28 },
29};
30
31pub const MIN_SIGNERS: usize = 1;
33pub const MAX_SIGNERS: usize = 11;
35const U16_BYTES: usize = 2;
37const U64_BYTES: usize = 8;
39
40#[repr(C)]
42#[cfg_attr(feature = "serde-traits", derive(Serialize, Deserialize))]
43#[cfg_attr(
44 feature = "serde-traits",
45 serde(rename_all_fields = "camelCase", rename_all = "camelCase")
46)]
47#[derive(Clone, Debug, PartialEq)]
48pub enum TokenInstruction<'a> {
49 InitializeMint {
66 decimals: u8,
68 #[cfg_attr(feature = "serde-traits", serde(with = "As::<DisplayFromStr>"))]
70 mint_authority: Pubkey,
71 #[cfg_attr(feature = "serde-traits", serde(with = "coption_fromstr"))]
73 freeze_authority: COption<Pubkey>,
74 },
75 InitializeAccount,
94 InitializeMultisig {
114 m: u8,
117 },
118 #[deprecated(
143 since = "4.0.0",
144 note = "please use `TransferChecked` or `TransferCheckedWithFee` instead"
145 )]
146 Transfer {
147 amount: u64,
149 },
150 Approve {
166 amount: u64,
168 },
169 Revoke,
183 SetAuthority {
196 authority_type: AuthorityType,
198 #[cfg_attr(feature = "serde-traits", serde(with = "coption_fromstr"))]
200 new_authority: COption<Pubkey>,
201 },
202 MintTo {
218 amount: u64,
220 },
221 Burn {
237 amount: u64,
239 },
240 CloseAccount,
275 FreezeAccount,
292 ThawAccount,
307
308 TransferChecked {
335 amount: u64,
337 decimals: u8,
339 },
340 ApproveChecked {
362 amount: u64,
364 decimals: u8,
366 },
367 MintToChecked {
387 amount: u64,
389 decimals: u8,
391 },
392 BurnChecked {
414 amount: u64,
416 decimals: u8,
418 },
419 InitializeAccount2 {
430 #[cfg_attr(feature = "serde-traits", serde(with = "As::<DisplayFromStr>"))]
432 owner: Pubkey,
433 },
434 SyncNative,
445 InitializeAccount3 {
453 #[cfg_attr(feature = "serde-traits", serde(with = "As::<DisplayFromStr>"))]
455 owner: Pubkey,
456 },
457 InitializeMultisig2 {
466 m: u8,
469 },
470 InitializeMint2 {
478 decimals: u8,
480 #[cfg_attr(feature = "serde-traits", serde(with = "As::<DisplayFromStr>"))]
482 mint_authority: Pubkey,
483 #[cfg_attr(feature = "serde-traits", serde(with = "coption_fromstr"))]
485 freeze_authority: COption<Pubkey>,
486 },
487 GetAccountDataSize {
497 extension_types: Vec<ExtensionType>,
499 },
500 InitializeImmutableOwner,
512 AmountToUiAmount {
532 amount: u64,
534 },
535 UiAmountToAmount {
553 ui_amount: &'a str,
555 },
556 InitializeMintCloseAuthority {
570 #[cfg_attr(feature = "serde-traits", serde(with = "coption_fromstr"))]
572 close_authority: COption<Pubkey>,
573 },
574 TransferFeeExtension,
580 ConfidentialTransferExtension,
587 DefaultAccountStateExtension,
594 Reallocate {
613 extension_types: Vec<ExtensionType>,
615 },
616 MemoTransferExtension,
624 CreateNativeMint,
636 InitializeNonTransferableMint,
648 InterestBearingMintExtension,
655 CpiGuardExtension,
662 InitializePermanentDelegate {
679 #[cfg_attr(feature = "serde-traits", serde(with = "As::<DisplayFromStr>"))]
681 delegate: Pubkey,
682 },
683 TransferHookExtension,
689 ConfidentialTransferFeeExtension,
696 WithdrawExcessLamports,
705 MetadataPointerExtension,
712 GroupPointerExtension,
719 GroupMemberPointerExtension,
726 ConfidentialMintBurnExtension,
729 ScaledUiAmountExtension,
732 PausableExtension,
734}
735impl<'a> TokenInstruction<'a> {
736 pub fn unpack(input: &'a [u8]) -> Result<Self, ProgramError> {
739 use TokenError::InvalidInstruction;
740
741 let (&tag, rest) = input.split_first().ok_or(InvalidInstruction)?;
742 Ok(match tag {
743 0 => {
744 let (&decimals, rest) = rest.split_first().ok_or(InvalidInstruction)?;
745 let (mint_authority, rest) = Self::unpack_pubkey(rest)?;
746 let (freeze_authority, _rest) = Self::unpack_pubkey_option(rest)?;
747 Self::InitializeMint {
748 mint_authority,
749 freeze_authority,
750 decimals,
751 }
752 }
753 1 => Self::InitializeAccount,
754 2 => {
755 let &m = rest.first().ok_or(InvalidInstruction)?;
756 Self::InitializeMultisig { m }
757 }
758 3 | 4 | 7 | 8 => {
759 let amount = rest
760 .get(..U64_BYTES)
761 .and_then(|slice| slice.try_into().ok())
762 .map(u64::from_le_bytes)
763 .ok_or(InvalidInstruction)?;
764 match tag {
765 #[allow(deprecated)]
766 3 => Self::Transfer { amount },
767 4 => Self::Approve { amount },
768 7 => Self::MintTo { amount },
769 8 => Self::Burn { amount },
770 _ => unreachable!(),
771 }
772 }
773 5 => Self::Revoke,
774 6 => {
775 let (authority_type, rest) = rest
776 .split_first()
777 .ok_or_else(|| ProgramError::from(InvalidInstruction))
778 .and_then(|(&t, rest)| Ok((AuthorityType::from(t)?, rest)))?;
779 let (new_authority, _rest) = Self::unpack_pubkey_option(rest)?;
780
781 Self::SetAuthority {
782 authority_type,
783 new_authority,
784 }
785 }
786 9 => Self::CloseAccount,
787 10 => Self::FreezeAccount,
788 11 => Self::ThawAccount,
789 12 => {
790 let (amount, decimals, _rest) = Self::unpack_amount_decimals(rest)?;
791 Self::TransferChecked { amount, decimals }
792 }
793 13 => {
794 let (amount, decimals, _rest) = Self::unpack_amount_decimals(rest)?;
795 Self::ApproveChecked { amount, decimals }
796 }
797 14 => {
798 let (amount, decimals, _rest) = Self::unpack_amount_decimals(rest)?;
799 Self::MintToChecked { amount, decimals }
800 }
801 15 => {
802 let (amount, decimals, _rest) = Self::unpack_amount_decimals(rest)?;
803 Self::BurnChecked { amount, decimals }
804 }
805 16 => {
806 let (owner, _rest) = Self::unpack_pubkey(rest)?;
807 Self::InitializeAccount2 { owner }
808 }
809 17 => Self::SyncNative,
810 18 => {
811 let (owner, _rest) = Self::unpack_pubkey(rest)?;
812 Self::InitializeAccount3 { owner }
813 }
814 19 => {
815 let &m = rest.first().ok_or(InvalidInstruction)?;
816 Self::InitializeMultisig2 { m }
817 }
818 20 => {
819 let (&decimals, rest) = rest.split_first().ok_or(InvalidInstruction)?;
820 let (mint_authority, rest) = Self::unpack_pubkey(rest)?;
821 let (freeze_authority, _rest) = Self::unpack_pubkey_option(rest)?;
822 Self::InitializeMint2 {
823 mint_authority,
824 freeze_authority,
825 decimals,
826 }
827 }
828 21 => {
829 let mut extension_types = vec![];
830 for chunk in rest.chunks(size_of::<ExtensionType>()) {
831 extension_types.push(chunk.try_into()?);
832 }
833 Self::GetAccountDataSize { extension_types }
834 }
835 22 => Self::InitializeImmutableOwner,
836 23 => {
837 let (amount, _rest) = Self::unpack_u64(rest)?;
838 Self::AmountToUiAmount { amount }
839 }
840 24 => {
841 let ui_amount = std::str::from_utf8(rest).map_err(|_| InvalidInstruction)?;
842 Self::UiAmountToAmount { ui_amount }
843 }
844 25 => {
845 let (close_authority, _rest) = Self::unpack_pubkey_option(rest)?;
846 Self::InitializeMintCloseAuthority { close_authority }
847 }
848 26 => Self::TransferFeeExtension,
849 27 => Self::ConfidentialTransferExtension,
850 28 => Self::DefaultAccountStateExtension,
851 29 => {
852 let mut extension_types = vec![];
853 for chunk in rest.chunks(size_of::<ExtensionType>()) {
854 extension_types.push(chunk.try_into()?);
855 }
856 Self::Reallocate { extension_types }
857 }
858 30 => Self::MemoTransferExtension,
859 31 => Self::CreateNativeMint,
860 32 => Self::InitializeNonTransferableMint,
861 33 => Self::InterestBearingMintExtension,
862 34 => Self::CpiGuardExtension,
863 35 => {
864 let (delegate, _rest) = Self::unpack_pubkey(rest)?;
865 Self::InitializePermanentDelegate { delegate }
866 }
867 36 => Self::TransferHookExtension,
868 37 => Self::ConfidentialTransferFeeExtension,
869 38 => Self::WithdrawExcessLamports,
870 39 => Self::MetadataPointerExtension,
871 40 => Self::GroupPointerExtension,
872 41 => Self::GroupMemberPointerExtension,
873 42 => Self::ConfidentialMintBurnExtension,
874 43 => Self::ScaledUiAmountExtension,
875 44 => Self::PausableExtension,
876 _ => return Err(TokenError::InvalidInstruction.into()),
877 })
878 }
879
880 pub fn pack(&self) -> Vec<u8> {
883 let mut buf = Vec::with_capacity(size_of::<Self>());
884 match self {
885 &Self::InitializeMint {
886 ref mint_authority,
887 ref freeze_authority,
888 decimals,
889 } => {
890 buf.push(0);
891 buf.push(decimals);
892 buf.extend_from_slice(mint_authority.as_ref());
893 Self::pack_pubkey_option(freeze_authority, &mut buf);
894 }
895 Self::InitializeAccount => buf.push(1),
896 &Self::InitializeMultisig { m } => {
897 buf.push(2);
898 buf.push(m);
899 }
900 #[allow(deprecated)]
901 &Self::Transfer { amount } => {
902 buf.push(3);
903 buf.extend_from_slice(&amount.to_le_bytes());
904 }
905 &Self::Approve { amount } => {
906 buf.push(4);
907 buf.extend_from_slice(&amount.to_le_bytes());
908 }
909 &Self::MintTo { amount } => {
910 buf.push(7);
911 buf.extend_from_slice(&amount.to_le_bytes());
912 }
913 &Self::Burn { amount } => {
914 buf.push(8);
915 buf.extend_from_slice(&amount.to_le_bytes());
916 }
917 Self::Revoke => buf.push(5),
918 Self::SetAuthority {
919 authority_type,
920 ref new_authority,
921 } => {
922 buf.push(6);
923 buf.push(authority_type.into());
924 Self::pack_pubkey_option(new_authority, &mut buf);
925 }
926 Self::CloseAccount => buf.push(9),
927 Self::FreezeAccount => buf.push(10),
928 Self::ThawAccount => buf.push(11),
929 &Self::TransferChecked { amount, decimals } => {
930 buf.push(12);
931 buf.extend_from_slice(&amount.to_le_bytes());
932 buf.push(decimals);
933 }
934 &Self::ApproveChecked { amount, decimals } => {
935 buf.push(13);
936 buf.extend_from_slice(&amount.to_le_bytes());
937 buf.push(decimals);
938 }
939 &Self::MintToChecked { amount, decimals } => {
940 buf.push(14);
941 buf.extend_from_slice(&amount.to_le_bytes());
942 buf.push(decimals);
943 }
944 &Self::BurnChecked { amount, decimals } => {
945 buf.push(15);
946 buf.extend_from_slice(&amount.to_le_bytes());
947 buf.push(decimals);
948 }
949 &Self::InitializeAccount2 { owner } => {
950 buf.push(16);
951 buf.extend_from_slice(owner.as_ref());
952 }
953 &Self::SyncNative => {
954 buf.push(17);
955 }
956 &Self::InitializeAccount3 { owner } => {
957 buf.push(18);
958 buf.extend_from_slice(owner.as_ref());
959 }
960 &Self::InitializeMultisig2 { m } => {
961 buf.push(19);
962 buf.push(m);
963 }
964 &Self::InitializeMint2 {
965 ref mint_authority,
966 ref freeze_authority,
967 decimals,
968 } => {
969 buf.push(20);
970 buf.push(decimals);
971 buf.extend_from_slice(mint_authority.as_ref());
972 Self::pack_pubkey_option(freeze_authority, &mut buf);
973 }
974 Self::GetAccountDataSize { extension_types } => {
975 buf.push(21);
976 for extension_type in extension_types {
977 buf.extend_from_slice(&<[u8; 2]>::from(*extension_type));
978 }
979 }
980 &Self::InitializeImmutableOwner => {
981 buf.push(22);
982 }
983 &Self::AmountToUiAmount { amount } => {
984 buf.push(23);
985 buf.extend_from_slice(&amount.to_le_bytes());
986 }
987 Self::UiAmountToAmount { ui_amount } => {
988 buf.push(24);
989 buf.extend_from_slice(ui_amount.as_bytes());
990 }
991 Self::InitializeMintCloseAuthority { close_authority } => {
992 buf.push(25);
993 Self::pack_pubkey_option(close_authority, &mut buf);
994 }
995 Self::TransferFeeExtension => {
996 buf.push(26);
997 }
998 &Self::ConfidentialTransferExtension => {
999 buf.push(27);
1000 }
1001 &Self::DefaultAccountStateExtension => {
1002 buf.push(28);
1003 }
1004 Self::Reallocate { extension_types } => {
1005 buf.push(29);
1006 for extension_type in extension_types {
1007 buf.extend_from_slice(&<[u8; 2]>::from(*extension_type));
1008 }
1009 }
1010 &Self::MemoTransferExtension => {
1011 buf.push(30);
1012 }
1013 &Self::CreateNativeMint => {
1014 buf.push(31);
1015 }
1016 &Self::InitializeNonTransferableMint => {
1017 buf.push(32);
1018 }
1019 &Self::InterestBearingMintExtension => {
1020 buf.push(33);
1021 }
1022 &Self::CpiGuardExtension => {
1023 buf.push(34);
1024 }
1025 Self::InitializePermanentDelegate { delegate } => {
1026 buf.push(35);
1027 buf.extend_from_slice(delegate.as_ref());
1028 }
1029 &Self::TransferHookExtension => {
1030 buf.push(36);
1031 }
1032 &Self::ConfidentialTransferFeeExtension => {
1033 buf.push(37);
1034 }
1035 &Self::WithdrawExcessLamports => {
1036 buf.push(38);
1037 }
1038 &Self::MetadataPointerExtension => {
1039 buf.push(39);
1040 }
1041 &Self::GroupPointerExtension => {
1042 buf.push(40);
1043 }
1044 &Self::GroupMemberPointerExtension => {
1045 buf.push(41);
1046 }
1047 &Self::ConfidentialMintBurnExtension => {
1048 buf.push(42);
1049 }
1050 &Self::ScaledUiAmountExtension => {
1051 buf.push(43);
1052 }
1053 &Self::PausableExtension => {
1054 buf.push(44);
1055 }
1056 };
1057 buf
1058 }
1059
1060 pub(crate) fn unpack_pubkey(input: &[u8]) -> Result<(Pubkey, &[u8]), ProgramError> {
1061 let pk = input
1062 .get(..PUBKEY_BYTES)
1063 .and_then(|x| Pubkey::try_from(x).ok())
1064 .ok_or(TokenError::InvalidInstruction)?;
1065 Ok((pk, &input[PUBKEY_BYTES..]))
1066 }
1067
1068 pub(crate) fn unpack_pubkey_option(
1069 input: &[u8],
1070 ) -> Result<(COption<Pubkey>, &[u8]), ProgramError> {
1071 match input.split_first() {
1072 Option::Some((&0, rest)) => Ok((COption::None, rest)),
1073 Option::Some((&1, rest)) => {
1074 let (pk, rest) = Self::unpack_pubkey(rest)?;
1075 Ok((COption::Some(pk), rest))
1076 }
1077 _ => Err(TokenError::InvalidInstruction.into()),
1078 }
1079 }
1080
1081 pub(crate) fn pack_pubkey_option(value: &COption<Pubkey>, buf: &mut Vec<u8>) {
1082 match *value {
1083 COption::Some(ref key) => {
1084 buf.push(1);
1085 buf.extend_from_slice(&key.to_bytes());
1086 }
1087 COption::None => buf.push(0),
1088 }
1089 }
1090
1091 pub(crate) fn unpack_u16(input: &[u8]) -> Result<(u16, &[u8]), ProgramError> {
1092 let value = input
1093 .get(..U16_BYTES)
1094 .and_then(|slice| slice.try_into().ok())
1095 .map(u16::from_le_bytes)
1096 .ok_or(TokenError::InvalidInstruction)?;
1097 Ok((value, &input[U16_BYTES..]))
1098 }
1099
1100 pub(crate) fn unpack_u64(input: &[u8]) -> Result<(u64, &[u8]), ProgramError> {
1101 let value = input
1102 .get(..U64_BYTES)
1103 .and_then(|slice| slice.try_into().ok())
1104 .map(u64::from_le_bytes)
1105 .ok_or(TokenError::InvalidInstruction)?;
1106 Ok((value, &input[U64_BYTES..]))
1107 }
1108
1109 pub(crate) fn unpack_amount_decimals(input: &[u8]) -> Result<(u64, u8, &[u8]), ProgramError> {
1110 let (amount, rest) = Self::unpack_u64(input)?;
1111 let (&decimals, rest) = rest.split_first().ok_or(TokenError::InvalidInstruction)?;
1112 Ok((amount, decimals, rest))
1113 }
1114}
1115
1116#[repr(u8)]
1118#[cfg_attr(feature = "serde-traits", derive(Serialize, Deserialize))]
1119#[cfg_attr(feature = "serde-traits", serde(rename_all = "camelCase"))]
1120#[derive(Clone, Debug, PartialEq)]
1121pub enum AuthorityType {
1122 MintTokens,
1124 FreezeAccount,
1126 AccountOwner,
1128 CloseAccount,
1130 TransferFeeConfig,
1132 WithheldWithdraw,
1134 CloseMint,
1136 InterestRate,
1138 PermanentDelegate,
1140 ConfidentialTransferMint,
1143 TransferHookProgramId,
1145 ConfidentialTransferFeeConfig,
1147 MetadataPointer,
1149 GroupPointer,
1151 GroupMemberPointer,
1153 ScaledUiAmount,
1155 Pause,
1157}
1158
1159impl AuthorityType {
1160 fn into(&self) -> u8 {
1161 match self {
1162 AuthorityType::MintTokens => 0,
1163 AuthorityType::FreezeAccount => 1,
1164 AuthorityType::AccountOwner => 2,
1165 AuthorityType::CloseAccount => 3,
1166 AuthorityType::TransferFeeConfig => 4,
1167 AuthorityType::WithheldWithdraw => 5,
1168 AuthorityType::CloseMint => 6,
1169 AuthorityType::InterestRate => 7,
1170 AuthorityType::PermanentDelegate => 8,
1171 AuthorityType::ConfidentialTransferMint => 9,
1172 AuthorityType::TransferHookProgramId => 10,
1173 AuthorityType::ConfidentialTransferFeeConfig => 11,
1174 AuthorityType::MetadataPointer => 12,
1175 AuthorityType::GroupPointer => 13,
1176 AuthorityType::GroupMemberPointer => 14,
1177 AuthorityType::ScaledUiAmount => 15,
1178 AuthorityType::Pause => 16,
1179 }
1180 }
1181
1182 pub(crate) fn from(index: u8) -> Result<Self, ProgramError> {
1183 match index {
1184 0 => Ok(AuthorityType::MintTokens),
1185 1 => Ok(AuthorityType::FreezeAccount),
1186 2 => Ok(AuthorityType::AccountOwner),
1187 3 => Ok(AuthorityType::CloseAccount),
1188 4 => Ok(AuthorityType::TransferFeeConfig),
1189 5 => Ok(AuthorityType::WithheldWithdraw),
1190 6 => Ok(AuthorityType::CloseMint),
1191 7 => Ok(AuthorityType::InterestRate),
1192 8 => Ok(AuthorityType::PermanentDelegate),
1193 9 => Ok(AuthorityType::ConfidentialTransferMint),
1194 10 => Ok(AuthorityType::TransferHookProgramId),
1195 11 => Ok(AuthorityType::ConfidentialTransferFeeConfig),
1196 12 => Ok(AuthorityType::MetadataPointer),
1197 13 => Ok(AuthorityType::GroupPointer),
1198 14 => Ok(AuthorityType::GroupMemberPointer),
1199 15 => Ok(AuthorityType::ScaledUiAmount),
1200 16 => Ok(AuthorityType::Pause),
1201 _ => Err(TokenError::InvalidInstruction.into()),
1202 }
1203 }
1204}
1205
1206pub fn initialize_mint(
1208 token_program_id: &Pubkey,
1209 mint_pubkey: &Pubkey,
1210 mint_authority_pubkey: &Pubkey,
1211 freeze_authority_pubkey: Option<&Pubkey>,
1212 decimals: u8,
1213) -> Result<Instruction, ProgramError> {
1214 check_spl_token_program_account(token_program_id)?;
1215 let freeze_authority = freeze_authority_pubkey.cloned().into();
1216 let data = TokenInstruction::InitializeMint {
1217 mint_authority: *mint_authority_pubkey,
1218 freeze_authority,
1219 decimals,
1220 }
1221 .pack();
1222
1223 let accounts = vec![
1224 AccountMeta::new(*mint_pubkey, false),
1225 AccountMeta::new_readonly(sysvar::rent::id(), false),
1226 ];
1227
1228 Ok(Instruction {
1229 program_id: *token_program_id,
1230 accounts,
1231 data,
1232 })
1233}
1234
1235pub fn initialize_mint2(
1237 token_program_id: &Pubkey,
1238 mint_pubkey: &Pubkey,
1239 mint_authority_pubkey: &Pubkey,
1240 freeze_authority_pubkey: Option<&Pubkey>,
1241 decimals: u8,
1242) -> Result<Instruction, ProgramError> {
1243 check_spl_token_program_account(token_program_id)?;
1244 let freeze_authority = freeze_authority_pubkey.cloned().into();
1245 let data = TokenInstruction::InitializeMint2 {
1246 mint_authority: *mint_authority_pubkey,
1247 freeze_authority,
1248 decimals,
1249 }
1250 .pack();
1251
1252 let accounts = vec![AccountMeta::new(*mint_pubkey, false)];
1253
1254 Ok(Instruction {
1255 program_id: *token_program_id,
1256 accounts,
1257 data,
1258 })
1259}
1260
1261pub fn initialize_account(
1263 token_program_id: &Pubkey,
1264 account_pubkey: &Pubkey,
1265 mint_pubkey: &Pubkey,
1266 owner_pubkey: &Pubkey,
1267) -> Result<Instruction, ProgramError> {
1268 check_spl_token_program_account(token_program_id)?;
1269 let data = TokenInstruction::InitializeAccount.pack();
1270
1271 let accounts = vec![
1272 AccountMeta::new(*account_pubkey, false),
1273 AccountMeta::new_readonly(*mint_pubkey, false),
1274 AccountMeta::new_readonly(*owner_pubkey, false),
1275 AccountMeta::new_readonly(sysvar::rent::id(), false),
1276 ];
1277
1278 Ok(Instruction {
1279 program_id: *token_program_id,
1280 accounts,
1281 data,
1282 })
1283}
1284
1285pub fn initialize_account2(
1287 token_program_id: &Pubkey,
1288 account_pubkey: &Pubkey,
1289 mint_pubkey: &Pubkey,
1290 owner_pubkey: &Pubkey,
1291) -> Result<Instruction, ProgramError> {
1292 check_spl_token_program_account(token_program_id)?;
1293 let data = TokenInstruction::InitializeAccount2 {
1294 owner: *owner_pubkey,
1295 }
1296 .pack();
1297
1298 let accounts = vec![
1299 AccountMeta::new(*account_pubkey, false),
1300 AccountMeta::new_readonly(*mint_pubkey, false),
1301 AccountMeta::new_readonly(sysvar::rent::id(), false),
1302 ];
1303
1304 Ok(Instruction {
1305 program_id: *token_program_id,
1306 accounts,
1307 data,
1308 })
1309}
1310
1311pub fn initialize_account3(
1313 token_program_id: &Pubkey,
1314 account_pubkey: &Pubkey,
1315 mint_pubkey: &Pubkey,
1316 owner_pubkey: &Pubkey,
1317) -> Result<Instruction, ProgramError> {
1318 check_spl_token_program_account(token_program_id)?;
1319 let data = TokenInstruction::InitializeAccount3 {
1320 owner: *owner_pubkey,
1321 }
1322 .pack();
1323
1324 let accounts = vec![
1325 AccountMeta::new(*account_pubkey, false),
1326 AccountMeta::new_readonly(*mint_pubkey, false),
1327 ];
1328
1329 Ok(Instruction {
1330 program_id: *token_program_id,
1331 accounts,
1332 data,
1333 })
1334}
1335
1336pub fn initialize_multisig(
1338 token_program_id: &Pubkey,
1339 multisig_pubkey: &Pubkey,
1340 signer_pubkeys: &[&Pubkey],
1341 m: u8,
1342) -> Result<Instruction, ProgramError> {
1343 check_spl_token_program_account(token_program_id)?;
1344 if !is_valid_signer_index(m as usize)
1345 || !is_valid_signer_index(signer_pubkeys.len())
1346 || m as usize > signer_pubkeys.len()
1347 {
1348 return Err(ProgramError::MissingRequiredSignature);
1349 }
1350 let data = TokenInstruction::InitializeMultisig { m }.pack();
1351
1352 let mut accounts = Vec::with_capacity(1 + 1 + signer_pubkeys.len());
1353 accounts.push(AccountMeta::new(*multisig_pubkey, false));
1354 accounts.push(AccountMeta::new_readonly(sysvar::rent::id(), false));
1355 for signer_pubkey in signer_pubkeys.iter() {
1356 accounts.push(AccountMeta::new_readonly(**signer_pubkey, false));
1357 }
1358
1359 Ok(Instruction {
1360 program_id: *token_program_id,
1361 accounts,
1362 data,
1363 })
1364}
1365
1366pub fn initialize_multisig2(
1368 token_program_id: &Pubkey,
1369 multisig_pubkey: &Pubkey,
1370 signer_pubkeys: &[&Pubkey],
1371 m: u8,
1372) -> Result<Instruction, ProgramError> {
1373 check_spl_token_program_account(token_program_id)?;
1374 if !is_valid_signer_index(m as usize)
1375 || !is_valid_signer_index(signer_pubkeys.len())
1376 || m as usize > signer_pubkeys.len()
1377 {
1378 return Err(ProgramError::MissingRequiredSignature);
1379 }
1380 let data = TokenInstruction::InitializeMultisig2 { m }.pack();
1381
1382 let mut accounts = Vec::with_capacity(1 + 1 + signer_pubkeys.len());
1383 accounts.push(AccountMeta::new(*multisig_pubkey, false));
1384 for signer_pubkey in signer_pubkeys.iter() {
1385 accounts.push(AccountMeta::new_readonly(**signer_pubkey, false));
1386 }
1387
1388 Ok(Instruction {
1389 program_id: *token_program_id,
1390 accounts,
1391 data,
1392 })
1393}
1394
1395#[deprecated(
1397 since = "4.0.0",
1398 note = "please use `transfer_checked` or `transfer_checked_with_fee` instead"
1399)]
1400pub fn transfer(
1401 token_program_id: &Pubkey,
1402 source_pubkey: &Pubkey,
1403 destination_pubkey: &Pubkey,
1404 authority_pubkey: &Pubkey,
1405 signer_pubkeys: &[&Pubkey],
1406 amount: u64,
1407) -> Result<Instruction, ProgramError> {
1408 check_spl_token_program_account(token_program_id)?;
1409 #[allow(deprecated)]
1410 let data = TokenInstruction::Transfer { amount }.pack();
1411
1412 let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1413 accounts.push(AccountMeta::new(*source_pubkey, false));
1414 accounts.push(AccountMeta::new(*destination_pubkey, false));
1415 accounts.push(AccountMeta::new_readonly(
1416 *authority_pubkey,
1417 signer_pubkeys.is_empty(),
1418 ));
1419 for signer_pubkey in signer_pubkeys.iter() {
1420 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1421 }
1422
1423 Ok(Instruction {
1424 program_id: *token_program_id,
1425 accounts,
1426 data,
1427 })
1428}
1429
1430pub fn approve(
1432 token_program_id: &Pubkey,
1433 source_pubkey: &Pubkey,
1434 delegate_pubkey: &Pubkey,
1435 owner_pubkey: &Pubkey,
1436 signer_pubkeys: &[&Pubkey],
1437 amount: u64,
1438) -> Result<Instruction, ProgramError> {
1439 check_spl_token_program_account(token_program_id)?;
1440 let data = TokenInstruction::Approve { amount }.pack();
1441
1442 let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1443 accounts.push(AccountMeta::new(*source_pubkey, false));
1444 accounts.push(AccountMeta::new_readonly(*delegate_pubkey, false));
1445 accounts.push(AccountMeta::new_readonly(
1446 *owner_pubkey,
1447 signer_pubkeys.is_empty(),
1448 ));
1449 for signer_pubkey in signer_pubkeys.iter() {
1450 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1451 }
1452
1453 Ok(Instruction {
1454 program_id: *token_program_id,
1455 accounts,
1456 data,
1457 })
1458}
1459
1460pub fn revoke(
1462 token_program_id: &Pubkey,
1463 source_pubkey: &Pubkey,
1464 owner_pubkey: &Pubkey,
1465 signer_pubkeys: &[&Pubkey],
1466) -> Result<Instruction, ProgramError> {
1467 check_spl_token_program_account(token_program_id)?;
1468 let data = TokenInstruction::Revoke.pack();
1469
1470 let mut accounts = Vec::with_capacity(2 + signer_pubkeys.len());
1471 accounts.push(AccountMeta::new(*source_pubkey, false));
1472 accounts.push(AccountMeta::new_readonly(
1473 *owner_pubkey,
1474 signer_pubkeys.is_empty(),
1475 ));
1476 for signer_pubkey in signer_pubkeys.iter() {
1477 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1478 }
1479
1480 Ok(Instruction {
1481 program_id: *token_program_id,
1482 accounts,
1483 data,
1484 })
1485}
1486
1487pub fn set_authority(
1489 token_program_id: &Pubkey,
1490 owned_pubkey: &Pubkey,
1491 new_authority_pubkey: Option<&Pubkey>,
1492 authority_type: AuthorityType,
1493 owner_pubkey: &Pubkey,
1494 signer_pubkeys: &[&Pubkey],
1495) -> Result<Instruction, ProgramError> {
1496 check_spl_token_program_account(token_program_id)?;
1497 let new_authority = new_authority_pubkey.cloned().into();
1498 let data = TokenInstruction::SetAuthority {
1499 authority_type,
1500 new_authority,
1501 }
1502 .pack();
1503
1504 let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1505 accounts.push(AccountMeta::new(*owned_pubkey, false));
1506 accounts.push(AccountMeta::new_readonly(
1507 *owner_pubkey,
1508 signer_pubkeys.is_empty(),
1509 ));
1510 for signer_pubkey in signer_pubkeys.iter() {
1511 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1512 }
1513
1514 Ok(Instruction {
1515 program_id: *token_program_id,
1516 accounts,
1517 data,
1518 })
1519}
1520
1521pub fn mint_to(
1523 token_program_id: &Pubkey,
1524 mint_pubkey: &Pubkey,
1525 account_pubkey: &Pubkey,
1526 owner_pubkey: &Pubkey,
1527 signer_pubkeys: &[&Pubkey],
1528 amount: u64,
1529) -> Result<Instruction, ProgramError> {
1530 check_spl_token_program_account(token_program_id)?;
1531 let data = TokenInstruction::MintTo { amount }.pack();
1532
1533 let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1534 accounts.push(AccountMeta::new(*mint_pubkey, false));
1535 accounts.push(AccountMeta::new(*account_pubkey, false));
1536 accounts.push(AccountMeta::new_readonly(
1537 *owner_pubkey,
1538 signer_pubkeys.is_empty(),
1539 ));
1540 for signer_pubkey in signer_pubkeys.iter() {
1541 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1542 }
1543
1544 Ok(Instruction {
1545 program_id: *token_program_id,
1546 accounts,
1547 data,
1548 })
1549}
1550
1551pub fn burn(
1553 token_program_id: &Pubkey,
1554 account_pubkey: &Pubkey,
1555 mint_pubkey: &Pubkey,
1556 authority_pubkey: &Pubkey,
1557 signer_pubkeys: &[&Pubkey],
1558 amount: u64,
1559) -> Result<Instruction, ProgramError> {
1560 check_spl_token_program_account(token_program_id)?;
1561 let data = TokenInstruction::Burn { amount }.pack();
1562
1563 let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1564 accounts.push(AccountMeta::new(*account_pubkey, false));
1565 accounts.push(AccountMeta::new(*mint_pubkey, false));
1566 accounts.push(AccountMeta::new_readonly(
1567 *authority_pubkey,
1568 signer_pubkeys.is_empty(),
1569 ));
1570 for signer_pubkey in signer_pubkeys.iter() {
1571 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1572 }
1573
1574 Ok(Instruction {
1575 program_id: *token_program_id,
1576 accounts,
1577 data,
1578 })
1579}
1580
1581pub fn close_account(
1583 token_program_id: &Pubkey,
1584 account_pubkey: &Pubkey,
1585 destination_pubkey: &Pubkey,
1586 owner_pubkey: &Pubkey,
1587 signer_pubkeys: &[&Pubkey],
1588) -> Result<Instruction, ProgramError> {
1589 check_spl_token_program_account(token_program_id)?;
1590 let data = TokenInstruction::CloseAccount.pack();
1591
1592 let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1593 accounts.push(AccountMeta::new(*account_pubkey, false));
1594 accounts.push(AccountMeta::new(*destination_pubkey, false));
1595 accounts.push(AccountMeta::new_readonly(
1596 *owner_pubkey,
1597 signer_pubkeys.is_empty(),
1598 ));
1599 for signer_pubkey in signer_pubkeys.iter() {
1600 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1601 }
1602
1603 Ok(Instruction {
1604 program_id: *token_program_id,
1605 accounts,
1606 data,
1607 })
1608}
1609
1610pub fn freeze_account(
1612 token_program_id: &Pubkey,
1613 account_pubkey: &Pubkey,
1614 mint_pubkey: &Pubkey,
1615 owner_pubkey: &Pubkey,
1616 signer_pubkeys: &[&Pubkey],
1617) -> Result<Instruction, ProgramError> {
1618 check_spl_token_program_account(token_program_id)?;
1619 let data = TokenInstruction::FreezeAccount.pack();
1620
1621 let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1622 accounts.push(AccountMeta::new(*account_pubkey, false));
1623 accounts.push(AccountMeta::new_readonly(*mint_pubkey, false));
1624 accounts.push(AccountMeta::new_readonly(
1625 *owner_pubkey,
1626 signer_pubkeys.is_empty(),
1627 ));
1628 for signer_pubkey in signer_pubkeys.iter() {
1629 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1630 }
1631
1632 Ok(Instruction {
1633 program_id: *token_program_id,
1634 accounts,
1635 data,
1636 })
1637}
1638
1639pub fn thaw_account(
1641 token_program_id: &Pubkey,
1642 account_pubkey: &Pubkey,
1643 mint_pubkey: &Pubkey,
1644 owner_pubkey: &Pubkey,
1645 signer_pubkeys: &[&Pubkey],
1646) -> Result<Instruction, ProgramError> {
1647 check_spl_token_program_account(token_program_id)?;
1648 let data = TokenInstruction::ThawAccount.pack();
1649
1650 let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1651 accounts.push(AccountMeta::new(*account_pubkey, false));
1652 accounts.push(AccountMeta::new_readonly(*mint_pubkey, false));
1653 accounts.push(AccountMeta::new_readonly(
1654 *owner_pubkey,
1655 signer_pubkeys.is_empty(),
1656 ));
1657 for signer_pubkey in signer_pubkeys.iter() {
1658 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1659 }
1660
1661 Ok(Instruction {
1662 program_id: *token_program_id,
1663 accounts,
1664 data,
1665 })
1666}
1667
1668#[allow(clippy::too_many_arguments)]
1670pub fn transfer_checked(
1671 token_program_id: &Pubkey,
1672 source_pubkey: &Pubkey,
1673 mint_pubkey: &Pubkey,
1674 destination_pubkey: &Pubkey,
1675 authority_pubkey: &Pubkey,
1676 signer_pubkeys: &[&Pubkey],
1677 amount: u64,
1678 decimals: u8,
1679) -> Result<Instruction, ProgramError> {
1680 check_spl_token_program_account(token_program_id)?;
1681 let data = TokenInstruction::TransferChecked { amount, decimals }.pack();
1682
1683 let mut accounts = Vec::with_capacity(4 + signer_pubkeys.len());
1684 accounts.push(AccountMeta::new(*source_pubkey, false));
1685 accounts.push(AccountMeta::new_readonly(*mint_pubkey, false));
1686 accounts.push(AccountMeta::new(*destination_pubkey, false));
1687 accounts.push(AccountMeta::new_readonly(
1688 *authority_pubkey,
1689 signer_pubkeys.is_empty(),
1690 ));
1691 for signer_pubkey in signer_pubkeys.iter() {
1692 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1693 }
1694
1695 Ok(Instruction {
1696 program_id: *token_program_id,
1697 accounts,
1698 data,
1699 })
1700}
1701
1702#[allow(clippy::too_many_arguments)]
1704pub fn approve_checked(
1705 token_program_id: &Pubkey,
1706 source_pubkey: &Pubkey,
1707 mint_pubkey: &Pubkey,
1708 delegate_pubkey: &Pubkey,
1709 owner_pubkey: &Pubkey,
1710 signer_pubkeys: &[&Pubkey],
1711 amount: u64,
1712 decimals: u8,
1713) -> Result<Instruction, ProgramError> {
1714 check_spl_token_program_account(token_program_id)?;
1715 let data = TokenInstruction::ApproveChecked { amount, decimals }.pack();
1716
1717 let mut accounts = Vec::with_capacity(4 + signer_pubkeys.len());
1718 accounts.push(AccountMeta::new(*source_pubkey, false));
1719 accounts.push(AccountMeta::new_readonly(*mint_pubkey, false));
1720 accounts.push(AccountMeta::new_readonly(*delegate_pubkey, false));
1721 accounts.push(AccountMeta::new_readonly(
1722 *owner_pubkey,
1723 signer_pubkeys.is_empty(),
1724 ));
1725 for signer_pubkey in signer_pubkeys.iter() {
1726 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1727 }
1728
1729 Ok(Instruction {
1730 program_id: *token_program_id,
1731 accounts,
1732 data,
1733 })
1734}
1735
1736pub fn mint_to_checked(
1738 token_program_id: &Pubkey,
1739 mint_pubkey: &Pubkey,
1740 account_pubkey: &Pubkey,
1741 owner_pubkey: &Pubkey,
1742 signer_pubkeys: &[&Pubkey],
1743 amount: u64,
1744 decimals: u8,
1745) -> Result<Instruction, ProgramError> {
1746 check_spl_token_program_account(token_program_id)?;
1747 let data = TokenInstruction::MintToChecked { amount, decimals }.pack();
1748
1749 let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1750 accounts.push(AccountMeta::new(*mint_pubkey, false));
1751 accounts.push(AccountMeta::new(*account_pubkey, false));
1752 accounts.push(AccountMeta::new_readonly(
1753 *owner_pubkey,
1754 signer_pubkeys.is_empty(),
1755 ));
1756 for signer_pubkey in signer_pubkeys.iter() {
1757 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1758 }
1759
1760 Ok(Instruction {
1761 program_id: *token_program_id,
1762 accounts,
1763 data,
1764 })
1765}
1766
1767pub fn burn_checked(
1769 token_program_id: &Pubkey,
1770 account_pubkey: &Pubkey,
1771 mint_pubkey: &Pubkey,
1772 authority_pubkey: &Pubkey,
1773 signer_pubkeys: &[&Pubkey],
1774 amount: u64,
1775 decimals: u8,
1776) -> Result<Instruction, ProgramError> {
1777 check_spl_token_program_account(token_program_id)?;
1778 let data = TokenInstruction::BurnChecked { amount, decimals }.pack();
1779
1780 let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1781 accounts.push(AccountMeta::new(*account_pubkey, false));
1782 accounts.push(AccountMeta::new(*mint_pubkey, false));
1783 accounts.push(AccountMeta::new_readonly(
1784 *authority_pubkey,
1785 signer_pubkeys.is_empty(),
1786 ));
1787 for signer_pubkey in signer_pubkeys.iter() {
1788 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1789 }
1790
1791 Ok(Instruction {
1792 program_id: *token_program_id,
1793 accounts,
1794 data,
1795 })
1796}
1797
1798pub fn sync_native(
1800 token_program_id: &Pubkey,
1801 account_pubkey: &Pubkey,
1802) -> Result<Instruction, ProgramError> {
1803 check_spl_token_program_account(token_program_id)?;
1804
1805 Ok(Instruction {
1806 program_id: *token_program_id,
1807 accounts: vec![AccountMeta::new(*account_pubkey, false)],
1808 data: TokenInstruction::SyncNative.pack(),
1809 })
1810}
1811
1812pub fn get_account_data_size(
1814 token_program_id: &Pubkey,
1815 mint_pubkey: &Pubkey,
1816 extension_types: &[ExtensionType],
1817) -> Result<Instruction, ProgramError> {
1818 check_spl_token_program_account(token_program_id)?;
1819 Ok(Instruction {
1820 program_id: *token_program_id,
1821 accounts: vec![AccountMeta::new_readonly(*mint_pubkey, false)],
1822 data: TokenInstruction::GetAccountDataSize {
1823 extension_types: extension_types.to_vec(),
1824 }
1825 .pack(),
1826 })
1827}
1828
1829pub fn initialize_mint_close_authority(
1831 token_program_id: &Pubkey,
1832 mint_pubkey: &Pubkey,
1833 close_authority: Option<&Pubkey>,
1834) -> Result<Instruction, ProgramError> {
1835 check_program_account(token_program_id)?;
1836 let close_authority = close_authority.cloned().into();
1837 Ok(Instruction {
1838 program_id: *token_program_id,
1839 accounts: vec![AccountMeta::new(*mint_pubkey, false)],
1840 data: TokenInstruction::InitializeMintCloseAuthority { close_authority }.pack(),
1841 })
1842}
1843
1844pub fn initialize_immutable_owner(
1846 token_program_id: &Pubkey,
1847 token_account: &Pubkey,
1848) -> Result<Instruction, ProgramError> {
1849 check_spl_token_program_account(token_program_id)?;
1850 Ok(Instruction {
1851 program_id: *token_program_id,
1852 accounts: vec![AccountMeta::new(*token_account, false)],
1853 data: TokenInstruction::InitializeImmutableOwner.pack(),
1854 })
1855}
1856
1857pub fn amount_to_ui_amount(
1859 token_program_id: &Pubkey,
1860 mint_pubkey: &Pubkey,
1861 amount: u64,
1862) -> Result<Instruction, ProgramError> {
1863 check_spl_token_program_account(token_program_id)?;
1864
1865 Ok(Instruction {
1866 program_id: *token_program_id,
1867 accounts: vec![AccountMeta::new_readonly(*mint_pubkey, false)],
1868 data: TokenInstruction::AmountToUiAmount { amount }.pack(),
1869 })
1870}
1871
1872pub fn ui_amount_to_amount(
1874 token_program_id: &Pubkey,
1875 mint_pubkey: &Pubkey,
1876 ui_amount: &str,
1877) -> Result<Instruction, ProgramError> {
1878 check_spl_token_program_account(token_program_id)?;
1879
1880 Ok(Instruction {
1881 program_id: *token_program_id,
1882 accounts: vec![AccountMeta::new_readonly(*mint_pubkey, false)],
1883 data: TokenInstruction::UiAmountToAmount { ui_amount }.pack(),
1884 })
1885}
1886
1887pub fn reallocate(
1889 token_program_id: &Pubkey,
1890 account_pubkey: &Pubkey,
1891 payer: &Pubkey,
1892 owner_pubkey: &Pubkey,
1893 signer_pubkeys: &[&Pubkey],
1894 extension_types: &[ExtensionType],
1895) -> Result<Instruction, ProgramError> {
1896 check_program_account(token_program_id)?;
1897
1898 let mut accounts = Vec::with_capacity(4 + signer_pubkeys.len());
1899 accounts.push(AccountMeta::new(*account_pubkey, false));
1900 accounts.push(AccountMeta::new(*payer, true));
1901 accounts.push(AccountMeta::new_readonly(system_program::id(), false));
1902 accounts.push(AccountMeta::new_readonly(
1903 *owner_pubkey,
1904 signer_pubkeys.is_empty(),
1905 ));
1906 for signer_pubkey in signer_pubkeys.iter() {
1907 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1908 }
1909
1910 Ok(Instruction {
1911 program_id: *token_program_id,
1912 accounts,
1913 data: TokenInstruction::Reallocate {
1914 extension_types: extension_types.to_vec(),
1915 }
1916 .pack(),
1917 })
1918}
1919
1920pub fn create_native_mint(
1922 token_program_id: &Pubkey,
1923 payer: &Pubkey,
1924) -> Result<Instruction, ProgramError> {
1925 check_program_account(token_program_id)?;
1926
1927 Ok(Instruction {
1928 program_id: *token_program_id,
1929 accounts: vec![
1930 AccountMeta::new(*payer, true),
1931 AccountMeta::new(crate::native_mint::id(), false),
1932 AccountMeta::new_readonly(system_program::id(), false),
1933 ],
1934 data: TokenInstruction::CreateNativeMint.pack(),
1935 })
1936}
1937
1938pub fn initialize_non_transferable_mint(
1940 token_program_id: &Pubkey,
1941 mint_pubkey: &Pubkey,
1942) -> Result<Instruction, ProgramError> {
1943 check_program_account(token_program_id)?;
1944 Ok(Instruction {
1945 program_id: *token_program_id,
1946 accounts: vec![AccountMeta::new(*mint_pubkey, false)],
1947 data: TokenInstruction::InitializeNonTransferableMint.pack(),
1948 })
1949}
1950
1951pub fn initialize_permanent_delegate(
1953 token_program_id: &Pubkey,
1954 mint_pubkey: &Pubkey,
1955 delegate: &Pubkey,
1956) -> Result<Instruction, ProgramError> {
1957 check_program_account(token_program_id)?;
1958 Ok(Instruction {
1959 program_id: *token_program_id,
1960 accounts: vec![AccountMeta::new(*mint_pubkey, false)],
1961 data: TokenInstruction::InitializePermanentDelegate {
1962 delegate: *delegate,
1963 }
1964 .pack(),
1965 })
1966}
1967
1968pub fn is_valid_signer_index(index: usize) -> bool {
1971 (MIN_SIGNERS..=MAX_SIGNERS).contains(&index)
1972}
1973
1974pub fn decode_instruction_type<T: TryFrom<u8>>(input: &[u8]) -> Result<T, ProgramError> {
1976 if input.is_empty() {
1977 Err(ProgramError::InvalidInstructionData)
1978 } else {
1979 T::try_from(input[0]).map_err(|_| TokenError::InvalidInstruction.into())
1980 }
1981}
1982
1983pub fn decode_instruction_data<T: Pod>(input_with_type: &[u8]) -> Result<&T, ProgramError> {
2013 if input_with_type.len() != pod_get_packed_len::<T>().saturating_add(1) {
2014 Err(ProgramError::InvalidInstructionData)
2015 } else {
2016 pod_from_bytes(&input_with_type[1..])
2017 }
2018}
2019
2020pub(crate) fn encode_instruction<T: Into<u8>, D: Pod>(
2022 token_program_id: &Pubkey,
2023 accounts: Vec<AccountMeta>,
2024 token_instruction_type: TokenInstruction,
2025 instruction_type: T,
2026 instruction_data: &D,
2027) -> Instruction {
2028 let mut data = token_instruction_type.pack();
2029 data.push(T::into(instruction_type));
2030 data.extend_from_slice(bytemuck::bytes_of(instruction_data));
2031 Instruction {
2032 program_id: *token_program_id,
2033 accounts,
2034 data,
2035 }
2036}
2037
2038pub fn withdraw_excess_lamports(
2040 token_program_id: &Pubkey,
2041 source_account: &Pubkey,
2042 destination_account: &Pubkey,
2043 authority: &Pubkey,
2044 signers: &[&Pubkey],
2045) -> Result<Instruction, ProgramError> {
2046 check_program_account(token_program_id)?;
2047
2048 let mut accounts = vec![
2049 AccountMeta::new(*source_account, false),
2050 AccountMeta::new(*destination_account, false),
2051 AccountMeta::new_readonly(*authority, signers.is_empty()),
2052 ];
2053
2054 for signer in signers {
2055 accounts.push(AccountMeta::new_readonly(**signer, true))
2056 }
2057
2058 Ok(Instruction {
2059 program_id: *token_program_id,
2060 accounts,
2061 data: TokenInstruction::WithdrawExcessLamports.pack(),
2062 })
2063}
2064
2065#[cfg(test)]
2066mod test {
2067 use {super::*, crate::pod_instruction::*, proptest::prelude::*};
2068
2069 #[test]
2070 fn test_initialize_mint_packing() {
2071 let decimals = 2;
2072 let mint_authority = Pubkey::new_from_array([1u8; 32]);
2073 let freeze_authority = COption::None;
2074 let check = TokenInstruction::InitializeMint {
2075 decimals,
2076 mint_authority,
2077 freeze_authority,
2078 };
2079 let packed = check.pack();
2080 let mut expect = Vec::from([0u8, 2]);
2081 expect.extend_from_slice(&[1u8; 32]);
2082 expect.extend_from_slice(&[0]);
2083 assert_eq!(packed, expect);
2084 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2085 assert_eq!(unpacked, check);
2086 let instruction_type = decode_instruction_type::<PodTokenInstruction>(&packed).unwrap();
2087 assert_eq!(instruction_type, PodTokenInstruction::InitializeMint);
2088 let (pod, pod_freeze_authority) =
2089 decode_instruction_data_with_coption_pubkey::<InitializeMintData>(&packed).unwrap();
2090 assert_eq!(pod.decimals, decimals);
2091 assert_eq!(pod.mint_authority, mint_authority);
2092 assert_eq!(pod_freeze_authority, freeze_authority.into());
2093
2094 let mint_authority = Pubkey::new_from_array([2u8; 32]);
2095 let freeze_authority = COption::Some(Pubkey::new_from_array([3u8; 32]));
2096 let check = TokenInstruction::InitializeMint {
2097 decimals,
2098 mint_authority,
2099 freeze_authority,
2100 };
2101 let packed = check.pack();
2102 let mut expect = vec![0u8, 2];
2103 expect.extend_from_slice(&[2u8; 32]);
2104 expect.extend_from_slice(&[1]);
2105 expect.extend_from_slice(&[3u8; 32]);
2106 assert_eq!(packed, expect);
2107 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2108 assert_eq!(unpacked, check);
2109
2110 let instruction_type = decode_instruction_type::<PodTokenInstruction>(&packed).unwrap();
2111 assert_eq!(instruction_type, PodTokenInstruction::InitializeMint);
2112 let (pod, pod_freeze_authority) =
2113 decode_instruction_data_with_coption_pubkey::<InitializeMintData>(&packed).unwrap();
2114 assert_eq!(pod.decimals, decimals);
2115 assert_eq!(pod.mint_authority, mint_authority);
2116 assert_eq!(pod_freeze_authority, freeze_authority.into());
2117 }
2118
2119 #[test]
2120 fn test_initialize_account_packing() {
2121 let check = TokenInstruction::InitializeAccount;
2122 let packed = check.pack();
2123 let expect = Vec::from([1u8]);
2124 assert_eq!(packed, expect);
2125 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2126 assert_eq!(unpacked, check);
2127 let instruction_type = decode_instruction_type::<PodTokenInstruction>(&packed).unwrap();
2128 assert_eq!(instruction_type, PodTokenInstruction::InitializeAccount);
2129 }
2130
2131 #[test]
2132 fn test_initialize_multisig_packing() {
2133 let m = 1;
2134 let check = TokenInstruction::InitializeMultisig { m };
2135 let packed = check.pack();
2136 let expect = Vec::from([2u8, 1]);
2137 assert_eq!(packed, expect);
2138 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2139 assert_eq!(unpacked, check);
2140
2141 let instruction_type = decode_instruction_type::<PodTokenInstruction>(&packed).unwrap();
2142 assert_eq!(instruction_type, PodTokenInstruction::InitializeMultisig);
2143 let pod = decode_instruction_data::<InitializeMultisigData>(&packed).unwrap();
2144 assert_eq!(pod.m, m);
2145 }
2146
2147 #[test]
2148 fn test_transfer_packing() {
2149 let amount = 1;
2150 #[allow(deprecated)]
2151 let check = TokenInstruction::Transfer { amount };
2152 let packed = check.pack();
2153 let expect = Vec::from([3u8, 1, 0, 0, 0, 0, 0, 0, 0]);
2154 assert_eq!(packed, expect);
2155 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2156 assert_eq!(unpacked, check);
2157
2158 let instruction_type = decode_instruction_type::<PodTokenInstruction>(&packed).unwrap();
2159 assert_eq!(instruction_type, PodTokenInstruction::Transfer);
2160 let pod = decode_instruction_data::<AmountData>(&packed).unwrap();
2161 assert_eq!(pod.amount, amount.into());
2162 }
2163
2164 #[test]
2165 fn test_approve_packing() {
2166 let amount = 1;
2167 let check = TokenInstruction::Approve { amount };
2168 let packed = check.pack();
2169 let expect = Vec::from([4u8, 1, 0, 0, 0, 0, 0, 0, 0]);
2170 assert_eq!(packed, expect);
2171 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2172 assert_eq!(unpacked, check);
2173
2174 let instruction_type = decode_instruction_type::<PodTokenInstruction>(&packed).unwrap();
2175 assert_eq!(instruction_type, PodTokenInstruction::Approve);
2176 let pod = decode_instruction_data::<AmountData>(&packed).unwrap();
2177 assert_eq!(pod.amount, amount.into());
2178 }
2179
2180 #[test]
2181 fn test_revoke_packing() {
2182 let check = TokenInstruction::Revoke;
2183 let packed = check.pack();
2184 let expect = Vec::from([5u8]);
2185 assert_eq!(packed, expect);
2186 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2187 assert_eq!(unpacked, check);
2188 let instruction_type = decode_instruction_type::<PodTokenInstruction>(&packed).unwrap();
2189 assert_eq!(instruction_type, PodTokenInstruction::Revoke);
2190 }
2191
2192 #[test]
2193 fn test_set_authority_packing() {
2194 let authority_type = AuthorityType::FreezeAccount;
2195 let new_authority = COption::Some(Pubkey::new_from_array([4u8; 32]));
2196 let check = TokenInstruction::SetAuthority {
2197 authority_type: authority_type.clone(),
2198 new_authority,
2199 };
2200 let packed = check.pack();
2201 let mut expect = Vec::from([6u8, 1]);
2202 expect.extend_from_slice(&[1]);
2203 expect.extend_from_slice(&[4u8; 32]);
2204 assert_eq!(packed, expect);
2205 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2206 assert_eq!(unpacked, check);
2207
2208 let instruction_type = decode_instruction_type::<PodTokenInstruction>(&packed).unwrap();
2209 assert_eq!(instruction_type, PodTokenInstruction::SetAuthority);
2210 let (pod, pod_new_authority) =
2211 decode_instruction_data_with_coption_pubkey::<SetAuthorityData>(&packed).unwrap();
2212 assert_eq!(
2213 AuthorityType::from(pod.authority_type).unwrap(),
2214 authority_type
2215 );
2216 assert_eq!(pod_new_authority, new_authority.into());
2217 }
2218
2219 #[test]
2220 fn test_mint_to_packing() {
2221 let amount = 1;
2222 let check = TokenInstruction::MintTo { amount };
2223 let packed = check.pack();
2224 let expect = Vec::from([7u8, 1, 0, 0, 0, 0, 0, 0, 0]);
2225 assert_eq!(packed, expect);
2226 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2227 assert_eq!(unpacked, check);
2228
2229 let instruction_type = decode_instruction_type::<PodTokenInstruction>(&packed).unwrap();
2230 assert_eq!(instruction_type, PodTokenInstruction::MintTo);
2231 let pod = decode_instruction_data::<AmountData>(&packed).unwrap();
2232 assert_eq!(pod.amount, amount.into());
2233 }
2234
2235 #[test]
2236 fn test_burn_packing() {
2237 let amount = 1;
2238 let check = TokenInstruction::Burn { amount };
2239 let packed = check.pack();
2240 let expect = Vec::from([8u8, 1, 0, 0, 0, 0, 0, 0, 0]);
2241 assert_eq!(packed, expect);
2242 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2243 assert_eq!(unpacked, check);
2244
2245 let instruction_type = decode_instruction_type::<PodTokenInstruction>(&packed).unwrap();
2246 assert_eq!(instruction_type, PodTokenInstruction::Burn);
2247 let pod = decode_instruction_data::<AmountData>(&packed).unwrap();
2248 assert_eq!(pod.amount, amount.into());
2249 }
2250
2251 #[test]
2252 fn test_close_account_packing() {
2253 let check = TokenInstruction::CloseAccount;
2254 let packed = check.pack();
2255 let expect = Vec::from([9u8]);
2256 assert_eq!(packed, expect);
2257 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2258 assert_eq!(unpacked, check);
2259 let instruction_type = decode_instruction_type::<PodTokenInstruction>(&packed).unwrap();
2260 assert_eq!(instruction_type, PodTokenInstruction::CloseAccount);
2261 }
2262
2263 #[test]
2264 fn test_freeze_account_packing() {
2265 let check = TokenInstruction::FreezeAccount;
2266 let packed = check.pack();
2267 let expect = Vec::from([10u8]);
2268 assert_eq!(packed, expect);
2269 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2270 assert_eq!(unpacked, check);
2271 let instruction_type = decode_instruction_type::<PodTokenInstruction>(&packed).unwrap();
2272 assert_eq!(instruction_type, PodTokenInstruction::FreezeAccount);
2273 }
2274
2275 #[test]
2276 fn test_thaw_account_packing() {
2277 let check = TokenInstruction::ThawAccount;
2278 let packed = check.pack();
2279 let expect = Vec::from([11u8]);
2280 assert_eq!(packed, expect);
2281 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2282 assert_eq!(unpacked, check);
2283 let instruction_type = decode_instruction_type::<PodTokenInstruction>(&packed).unwrap();
2284 assert_eq!(instruction_type, PodTokenInstruction::ThawAccount);
2285 }
2286
2287 #[test]
2288 fn test_transfer_checked_packing() {
2289 let amount = 1;
2290 let decimals = 2;
2291 let check = TokenInstruction::TransferChecked { amount, decimals };
2292 let packed = check.pack();
2293 let expect = Vec::from([12u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]);
2294 assert_eq!(packed, expect);
2295 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2296 assert_eq!(unpacked, check);
2297
2298 let instruction_type = decode_instruction_type::<PodTokenInstruction>(&packed).unwrap();
2299 assert_eq!(instruction_type, PodTokenInstruction::TransferChecked);
2300 let pod = decode_instruction_data::<AmountCheckedData>(&packed).unwrap();
2301 assert_eq!(pod.amount, amount.into());
2302 assert_eq!(pod.decimals, decimals);
2303 }
2304
2305 #[test]
2306 fn test_approve_checked_packing() {
2307 let amount = 1;
2308 let decimals = 2;
2309
2310 let check = TokenInstruction::ApproveChecked { amount, decimals };
2311 let packed = check.pack();
2312 let expect = Vec::from([13u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]);
2313 assert_eq!(packed, expect);
2314 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2315 assert_eq!(unpacked, check);
2316
2317 let instruction_type = decode_instruction_type::<PodTokenInstruction>(&packed).unwrap();
2318 assert_eq!(instruction_type, PodTokenInstruction::ApproveChecked);
2319 let pod = decode_instruction_data::<AmountCheckedData>(&packed).unwrap();
2320 assert_eq!(pod.amount, amount.into());
2321 assert_eq!(pod.decimals, decimals);
2322 }
2323
2324 #[test]
2325 fn test_mint_to_checked_packing() {
2326 let amount = 1;
2327 let decimals = 2;
2328 let check = TokenInstruction::MintToChecked { amount, decimals };
2329 let packed = check.pack();
2330 let expect = Vec::from([14u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]);
2331 assert_eq!(packed, expect);
2332 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2333 assert_eq!(unpacked, check);
2334 let instruction_type = decode_instruction_type::<PodTokenInstruction>(&packed).unwrap();
2335 assert_eq!(instruction_type, PodTokenInstruction::MintToChecked);
2336 let pod = decode_instruction_data::<AmountCheckedData>(&packed).unwrap();
2337 assert_eq!(pod.amount, amount.into());
2338 assert_eq!(pod.decimals, decimals);
2339 }
2340
2341 #[test]
2342 fn test_burn_checked_packing() {
2343 let amount = 1;
2344 let decimals = 2;
2345 let check = TokenInstruction::BurnChecked { amount, decimals };
2346 let packed = check.pack();
2347 let expect = Vec::from([15u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]);
2348 assert_eq!(packed, expect);
2349 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2350 assert_eq!(unpacked, check);
2351
2352 let instruction_type = decode_instruction_type::<PodTokenInstruction>(&packed).unwrap();
2353 assert_eq!(instruction_type, PodTokenInstruction::BurnChecked);
2354 let pod = decode_instruction_data::<AmountCheckedData>(&packed).unwrap();
2355 assert_eq!(pod.amount, amount.into());
2356 assert_eq!(pod.decimals, decimals);
2357 }
2358
2359 #[test]
2360 fn test_initialize_account2_packing() {
2361 let owner = Pubkey::new_from_array([2u8; 32]);
2362 let check = TokenInstruction::InitializeAccount2 { owner };
2363 let packed = check.pack();
2364 let mut expect = vec![16u8];
2365 expect.extend_from_slice(&[2u8; 32]);
2366 assert_eq!(packed, expect);
2367 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2368 assert_eq!(unpacked, check);
2369
2370 let instruction_type = decode_instruction_type::<PodTokenInstruction>(&packed).unwrap();
2371 assert_eq!(instruction_type, PodTokenInstruction::InitializeAccount2);
2372 let pod_owner = decode_instruction_data::<Pubkey>(&packed).unwrap();
2373 assert_eq!(*pod_owner, owner);
2374 }
2375
2376 #[test]
2377 fn test_sync_native_packing() {
2378 let check = TokenInstruction::SyncNative;
2379 let packed = check.pack();
2380 let expect = vec![17u8];
2381 assert_eq!(packed, expect);
2382 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2383 assert_eq!(unpacked, check);
2384
2385 let instruction_type = decode_instruction_type::<PodTokenInstruction>(&packed).unwrap();
2386 assert_eq!(instruction_type, PodTokenInstruction::SyncNative);
2387 }
2388
2389 #[test]
2390 fn test_initialize_account3_packing() {
2391 let owner = Pubkey::new_from_array([2u8; 32]);
2392 let check = TokenInstruction::InitializeAccount3 { owner };
2393 let packed = check.pack();
2394 let mut expect = vec![18u8];
2395 expect.extend_from_slice(&[2u8; 32]);
2396 assert_eq!(packed, expect);
2397 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2398 assert_eq!(unpacked, check);
2399
2400 let instruction_type = decode_instruction_type::<PodTokenInstruction>(&packed).unwrap();
2401 assert_eq!(instruction_type, PodTokenInstruction::InitializeAccount3);
2402 let pod_owner = decode_instruction_data::<Pubkey>(&packed).unwrap();
2403 assert_eq!(*pod_owner, owner);
2404 }
2405
2406 #[test]
2407 fn test_initialize_multisig2_packing() {
2408 let m = 1;
2409 let check = TokenInstruction::InitializeMultisig2 { m };
2410 let packed = check.pack();
2411 let expect = Vec::from([19u8, 1]);
2412 assert_eq!(packed, expect);
2413 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2414 assert_eq!(unpacked, check);
2415
2416 let instruction_type = decode_instruction_type::<PodTokenInstruction>(&packed).unwrap();
2417 assert_eq!(instruction_type, PodTokenInstruction::InitializeMultisig2);
2418 let pod = decode_instruction_data::<InitializeMultisigData>(&packed).unwrap();
2419 assert_eq!(pod.m, m);
2420 }
2421
2422 #[test]
2423 fn test_initialize_mint2_packing() {
2424 let decimals = 2;
2425 let mint_authority = Pubkey::new_from_array([1u8; 32]);
2426 let freeze_authority = COption::None;
2427 let check = TokenInstruction::InitializeMint2 {
2428 decimals,
2429 mint_authority,
2430 freeze_authority,
2431 };
2432 let packed = check.pack();
2433 let mut expect = Vec::from([20u8, 2]);
2434 expect.extend_from_slice(&[1u8; 32]);
2435 expect.extend_from_slice(&[0]);
2436 assert_eq!(packed, expect);
2437 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2438 assert_eq!(unpacked, check);
2439
2440 let instruction_type = decode_instruction_type::<PodTokenInstruction>(&packed).unwrap();
2441 assert_eq!(instruction_type, PodTokenInstruction::InitializeMint2);
2442 let (pod, pod_freeze_authority) =
2443 decode_instruction_data_with_coption_pubkey::<InitializeMintData>(&packed).unwrap();
2444 assert_eq!(pod.decimals, decimals);
2445 assert_eq!(pod.mint_authority, mint_authority);
2446 assert_eq!(pod_freeze_authority, freeze_authority.into());
2447
2448 let decimals = 2;
2449 let mint_authority = Pubkey::new_from_array([2u8; 32]);
2450 let freeze_authority = COption::Some(Pubkey::new_from_array([3u8; 32]));
2451 let check = TokenInstruction::InitializeMint2 {
2452 decimals,
2453 mint_authority,
2454 freeze_authority,
2455 };
2456 let packed = check.pack();
2457 let mut expect = vec![20u8, 2];
2458 expect.extend_from_slice(&[2u8; 32]);
2459 expect.extend_from_slice(&[1]);
2460 expect.extend_from_slice(&[3u8; 32]);
2461 assert_eq!(packed, expect);
2462 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2463 assert_eq!(unpacked, check);
2464
2465 let instruction_type = decode_instruction_type::<PodTokenInstruction>(&packed).unwrap();
2466 assert_eq!(instruction_type, PodTokenInstruction::InitializeMint2);
2467 let (pod, pod_freeze_authority) =
2468 decode_instruction_data_with_coption_pubkey::<InitializeMintData>(&packed).unwrap();
2469 assert_eq!(pod.decimals, decimals);
2470 assert_eq!(pod.mint_authority, mint_authority);
2471 assert_eq!(pod_freeze_authority, freeze_authority.into());
2472 }
2473
2474 #[test]
2475 fn test_get_account_data_size_packing() {
2476 let extension_types = vec![];
2477 let check = TokenInstruction::GetAccountDataSize {
2478 extension_types: extension_types.clone(),
2479 };
2480 let packed = check.pack();
2481 let expect = [21u8];
2482 assert_eq!(packed, &[21u8]);
2483 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2484 assert_eq!(unpacked, check);
2485
2486 let instruction_type = decode_instruction_type::<PodTokenInstruction>(&packed).unwrap();
2487 assert_eq!(instruction_type, PodTokenInstruction::GetAccountDataSize);
2488 let pod_extension_types = packed[1..]
2489 .chunks(std::mem::size_of::<ExtensionType>())
2490 .map(ExtensionType::try_from)
2491 .collect::<Result<Vec<_>, _>>()
2492 .unwrap();
2493 assert_eq!(pod_extension_types, extension_types);
2494
2495 let extension_types = vec![
2496 ExtensionType::TransferFeeConfig,
2497 ExtensionType::TransferFeeAmount,
2498 ];
2499 let check = TokenInstruction::GetAccountDataSize {
2500 extension_types: extension_types.clone(),
2501 };
2502 let packed = check.pack();
2503 let expect = [21u8, 1, 0, 2, 0];
2504 assert_eq!(packed, &[21u8, 1, 0, 2, 0]);
2505 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2506 assert_eq!(unpacked, check);
2507
2508 let instruction_type = decode_instruction_type::<PodTokenInstruction>(&packed).unwrap();
2509 assert_eq!(instruction_type, PodTokenInstruction::GetAccountDataSize);
2510 let pod_extension_types = packed[1..]
2511 .chunks(std::mem::size_of::<ExtensionType>())
2512 .map(ExtensionType::try_from)
2513 .collect::<Result<Vec<_>, _>>()
2514 .unwrap();
2515 assert_eq!(pod_extension_types, extension_types);
2516 }
2517
2518 #[test]
2519 fn test_amount_to_ui_amount_packing() {
2520 let amount = 42;
2521 let check = TokenInstruction::AmountToUiAmount { amount };
2522 let packed = check.pack();
2523 let expect = vec![23u8, 42, 0, 0, 0, 0, 0, 0, 0];
2524 assert_eq!(packed, expect);
2525 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2526 assert_eq!(unpacked, check);
2527
2528 let instruction_type = decode_instruction_type::<PodTokenInstruction>(&packed).unwrap();
2529 assert_eq!(instruction_type, PodTokenInstruction::AmountToUiAmount);
2530 let data = decode_instruction_data::<AmountData>(&packed).unwrap();
2531 assert_eq!(data.amount, amount.into());
2532 }
2533
2534 #[test]
2535 fn test_ui_amount_to_amount_packing() {
2536 let ui_amount = "0.42";
2537 let check = TokenInstruction::UiAmountToAmount { ui_amount };
2538 let packed = check.pack();
2539 let expect = vec![24u8, 48, 46, 52, 50];
2540 assert_eq!(packed, expect);
2541 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2542 assert_eq!(unpacked, check);
2543
2544 let instruction_type = decode_instruction_type::<PodTokenInstruction>(&packed).unwrap();
2545 assert_eq!(instruction_type, PodTokenInstruction::UiAmountToAmount);
2546 let pod_ui_amount = std::str::from_utf8(&packed[1..]).unwrap();
2547 assert_eq!(pod_ui_amount, ui_amount);
2548 }
2549
2550 #[test]
2551 fn test_initialize_mint_close_authority_packing() {
2552 let close_authority = COption::Some(Pubkey::new_from_array([10u8; 32]));
2553 let check = TokenInstruction::InitializeMintCloseAuthority { close_authority };
2554 let packed = check.pack();
2555 let mut expect = vec![25u8, 1];
2556 expect.extend_from_slice(&[10u8; 32]);
2557 assert_eq!(packed, expect);
2558 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2559 assert_eq!(unpacked, check);
2560
2561 let instruction_type = decode_instruction_type::<PodTokenInstruction>(&packed).unwrap();
2562 assert_eq!(
2563 instruction_type,
2564 PodTokenInstruction::InitializeMintCloseAuthority
2565 );
2566 let (_, pod_close_authority) =
2567 decode_instruction_data_with_coption_pubkey::<()>(&packed).unwrap();
2568 assert_eq!(pod_close_authority, close_authority.into());
2569 }
2570
2571 #[test]
2572 fn test_create_native_mint_packing() {
2573 let check = TokenInstruction::CreateNativeMint;
2574 let packed = check.pack();
2575 let expect = vec![31u8];
2576 assert_eq!(packed, expect);
2577 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2578 assert_eq!(unpacked, check);
2579
2580 let instruction_type = decode_instruction_type::<PodTokenInstruction>(&packed).unwrap();
2581 assert_eq!(instruction_type, PodTokenInstruction::CreateNativeMint);
2582 }
2583
2584 #[test]
2585 fn test_initialize_permanent_delegate_packing() {
2586 let delegate = Pubkey::new_from_array([11u8; 32]);
2587 let check = TokenInstruction::InitializePermanentDelegate { delegate };
2588 let packed = check.pack();
2589 let mut expect = vec![35u8];
2590 expect.extend_from_slice(&[11u8; 32]);
2591 assert_eq!(packed, expect);
2592 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2593 assert_eq!(unpacked, check);
2594
2595 let instruction_type = decode_instruction_type::<PodTokenInstruction>(&packed).unwrap();
2596 assert_eq!(
2597 instruction_type,
2598 PodTokenInstruction::InitializePermanentDelegate
2599 );
2600 let pod_delegate = decode_instruction_data::<Pubkey>(&packed).unwrap();
2601 assert_eq!(*pod_delegate, delegate);
2602 }
2603
2604 macro_rules! test_instruction {
2605 ($a:ident($($b:tt)*)) => {
2606 let instruction_v3 = spl_token::instruction::$a($($b)*).unwrap();
2607 let instruction_2022 = $a($($b)*).unwrap();
2608 assert_eq!(instruction_v3, instruction_2022);
2609 }
2610 }
2611
2612 #[test]
2613 fn test_v3_compatibility() {
2614 let token_program_id = spl_token::id();
2615 let mint_pubkey = Pubkey::new_unique();
2616 let mint_authority_pubkey = Pubkey::new_unique();
2617 let freeze_authority_pubkey = Pubkey::new_unique();
2618 let decimals = 9u8;
2619
2620 let account_pubkey = Pubkey::new_unique();
2621 let owner_pubkey = Pubkey::new_unique();
2622
2623 let multisig_pubkey = Pubkey::new_unique();
2624 let signer_pubkeys_vec = vec![Pubkey::new_unique(); MAX_SIGNERS];
2625 let signer_pubkeys = signer_pubkeys_vec.iter().collect::<Vec<_>>();
2626 let m = 10u8;
2627
2628 let source_pubkey = Pubkey::new_unique();
2629 let destination_pubkey = Pubkey::new_unique();
2630 let authority_pubkey = Pubkey::new_unique();
2631 let amount = 1_000_000_000_000;
2632
2633 let delegate_pubkey = Pubkey::new_unique();
2634 let owned_pubkey = Pubkey::new_unique();
2635 let new_authority_pubkey = Pubkey::new_unique();
2636
2637 let ui_amount = "100000.00";
2638
2639 test_instruction!(initialize_mint(
2640 &token_program_id,
2641 &mint_pubkey,
2642 &mint_authority_pubkey,
2643 None,
2644 decimals,
2645 ));
2646 test_instruction!(initialize_mint2(
2647 &token_program_id,
2648 &mint_pubkey,
2649 &mint_authority_pubkey,
2650 Some(&freeze_authority_pubkey),
2651 decimals,
2652 ));
2653
2654 test_instruction!(initialize_account(
2655 &token_program_id,
2656 &account_pubkey,
2657 &mint_pubkey,
2658 &owner_pubkey,
2659 ));
2660 test_instruction!(initialize_account2(
2661 &token_program_id,
2662 &account_pubkey,
2663 &mint_pubkey,
2664 &owner_pubkey,
2665 ));
2666 test_instruction!(initialize_account3(
2667 &token_program_id,
2668 &account_pubkey,
2669 &mint_pubkey,
2670 &owner_pubkey,
2671 ));
2672 test_instruction!(initialize_multisig(
2673 &token_program_id,
2674 &multisig_pubkey,
2675 &signer_pubkeys,
2676 m,
2677 ));
2678 test_instruction!(initialize_multisig2(
2679 &token_program_id,
2680 &multisig_pubkey,
2681 &signer_pubkeys,
2682 m,
2683 ));
2684 #[allow(deprecated)]
2685 {
2686 test_instruction!(transfer(
2687 &token_program_id,
2688 &source_pubkey,
2689 &destination_pubkey,
2690 &authority_pubkey,
2691 &signer_pubkeys,
2692 amount
2693 ));
2694 }
2695 test_instruction!(transfer_checked(
2696 &token_program_id,
2697 &source_pubkey,
2698 &mint_pubkey,
2699 &destination_pubkey,
2700 &authority_pubkey,
2701 &signer_pubkeys,
2702 amount,
2703 decimals,
2704 ));
2705 test_instruction!(approve(
2706 &token_program_id,
2707 &source_pubkey,
2708 &delegate_pubkey,
2709 &owner_pubkey,
2710 &signer_pubkeys,
2711 amount
2712 ));
2713 test_instruction!(approve_checked(
2714 &token_program_id,
2715 &source_pubkey,
2716 &mint_pubkey,
2717 &delegate_pubkey,
2718 &owner_pubkey,
2719 &signer_pubkeys,
2720 amount,
2721 decimals
2722 ));
2723 test_instruction!(revoke(
2724 &token_program_id,
2725 &source_pubkey,
2726 &owner_pubkey,
2727 &signer_pubkeys,
2728 ));
2729
2730 {
2732 let instruction_v3 = spl_token::instruction::set_authority(
2733 &token_program_id,
2734 &owned_pubkey,
2735 Some(&new_authority_pubkey),
2736 spl_token::instruction::AuthorityType::AccountOwner,
2737 &owner_pubkey,
2738 &signer_pubkeys,
2739 )
2740 .unwrap();
2741 let instruction_2022 = set_authority(
2742 &token_program_id,
2743 &owned_pubkey,
2744 Some(&new_authority_pubkey),
2745 AuthorityType::AccountOwner,
2746 &owner_pubkey,
2747 &signer_pubkeys,
2748 )
2749 .unwrap();
2750 assert_eq!(instruction_v3, instruction_2022);
2751 }
2752
2753 test_instruction!(mint_to(
2754 &token_program_id,
2755 &mint_pubkey,
2756 &account_pubkey,
2757 &owner_pubkey,
2758 &signer_pubkeys,
2759 amount,
2760 ));
2761 test_instruction!(mint_to_checked(
2762 &token_program_id,
2763 &mint_pubkey,
2764 &account_pubkey,
2765 &owner_pubkey,
2766 &signer_pubkeys,
2767 amount,
2768 decimals,
2769 ));
2770 test_instruction!(burn(
2771 &token_program_id,
2772 &account_pubkey,
2773 &mint_pubkey,
2774 &authority_pubkey,
2775 &signer_pubkeys,
2776 amount,
2777 ));
2778 test_instruction!(burn_checked(
2779 &token_program_id,
2780 &account_pubkey,
2781 &mint_pubkey,
2782 &authority_pubkey,
2783 &signer_pubkeys,
2784 amount,
2785 decimals,
2786 ));
2787 test_instruction!(close_account(
2788 &token_program_id,
2789 &account_pubkey,
2790 &destination_pubkey,
2791 &owner_pubkey,
2792 &signer_pubkeys,
2793 ));
2794 test_instruction!(freeze_account(
2795 &token_program_id,
2796 &account_pubkey,
2797 &mint_pubkey,
2798 &owner_pubkey,
2799 &signer_pubkeys,
2800 ));
2801 test_instruction!(thaw_account(
2802 &token_program_id,
2803 &account_pubkey,
2804 &mint_pubkey,
2805 &owner_pubkey,
2806 &signer_pubkeys,
2807 ));
2808 test_instruction!(sync_native(&token_program_id, &account_pubkey,));
2809
2810 {
2812 let instruction_v3 =
2813 spl_token::instruction::get_account_data_size(&token_program_id, &mint_pubkey)
2814 .unwrap();
2815 let instruction_2022 =
2816 get_account_data_size(&token_program_id, &mint_pubkey, &[]).unwrap();
2817 assert_eq!(instruction_v3, instruction_2022);
2818 }
2819
2820 test_instruction!(initialize_immutable_owner(
2821 &token_program_id,
2822 &account_pubkey,
2823 ));
2824
2825 test_instruction!(amount_to_ui_amount(&token_program_id, &mint_pubkey, amount,));
2826
2827 test_instruction!(ui_amount_to_amount(
2828 &token_program_id,
2829 &mint_pubkey,
2830 ui_amount,
2831 ));
2832 }
2833
2834 proptest! {
2835 #![proptest_config(ProptestConfig::with_cases(1024))]
2836 #[test]
2837 fn test_instruction_unpack_proptest(
2838 data in prop::collection::vec(any::<u8>(), 0..255)
2839 ) {
2840 let _no_panic = TokenInstruction::unpack(&data);
2841 }
2842 }
2843}