1#![allow(deprecated)]
6
7#[cfg(feature = "serde")]
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", derive(Serialize, Deserialize))]
43#[cfg_attr(
44 feature = "serde",
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", serde(with = "As::<DisplayFromStr>"))]
70 mint_authority: Pubkey,
71 #[cfg_attr(feature = "serde", 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", 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", serde(with = "As::<DisplayFromStr>"))]
432 owner: Pubkey,
433 },
434 SyncNative,
445 InitializeAccount3 {
453 #[cfg_attr(feature = "serde", serde(with = "As::<DisplayFromStr>"))]
455 owner: Pubkey,
456 },
457 InitializeMultisig2 {
466 m: u8,
469 },
470 InitializeMint2 {
478 decimals: u8,
480 #[cfg_attr(feature = "serde", serde(with = "As::<DisplayFromStr>"))]
482 mint_authority: Pubkey,
483 #[cfg_attr(feature = "serde", 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", 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", 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", derive(Serialize, Deserialize))]
1119#[cfg_attr(feature = "serde", 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 fn from(index: u8) -> Result<Self, ProgramError> {
1184 match index {
1185 0 => Ok(AuthorityType::MintTokens),
1186 1 => Ok(AuthorityType::FreezeAccount),
1187 2 => Ok(AuthorityType::AccountOwner),
1188 3 => Ok(AuthorityType::CloseAccount),
1189 4 => Ok(AuthorityType::TransferFeeConfig),
1190 5 => Ok(AuthorityType::WithheldWithdraw),
1191 6 => Ok(AuthorityType::CloseMint),
1192 7 => Ok(AuthorityType::InterestRate),
1193 8 => Ok(AuthorityType::PermanentDelegate),
1194 9 => Ok(AuthorityType::ConfidentialTransferMint),
1195 10 => Ok(AuthorityType::TransferHookProgramId),
1196 11 => Ok(AuthorityType::ConfidentialTransferFeeConfig),
1197 12 => Ok(AuthorityType::MetadataPointer),
1198 13 => Ok(AuthorityType::GroupPointer),
1199 14 => Ok(AuthorityType::GroupMemberPointer),
1200 15 => Ok(AuthorityType::ScaledUiAmount),
1201 16 => Ok(AuthorityType::Pause),
1202 _ => Err(TokenError::InvalidInstruction.into()),
1203 }
1204 }
1205}
1206
1207pub fn initialize_mint(
1209 token_program_id: &Pubkey,
1210 mint_pubkey: &Pubkey,
1211 mint_authority_pubkey: &Pubkey,
1212 freeze_authority_pubkey: Option<&Pubkey>,
1213 decimals: u8,
1214) -> Result<Instruction, ProgramError> {
1215 check_spl_token_program_account(token_program_id)?;
1216 let freeze_authority = freeze_authority_pubkey.cloned().into();
1217 let data = TokenInstruction::InitializeMint {
1218 mint_authority: *mint_authority_pubkey,
1219 freeze_authority,
1220 decimals,
1221 }
1222 .pack();
1223
1224 let accounts = vec![
1225 AccountMeta::new(*mint_pubkey, false),
1226 AccountMeta::new_readonly(sysvar::rent::id(), false),
1227 ];
1228
1229 Ok(Instruction {
1230 program_id: *token_program_id,
1231 accounts,
1232 data,
1233 })
1234}
1235
1236pub fn initialize_mint2(
1238 token_program_id: &Pubkey,
1239 mint_pubkey: &Pubkey,
1240 mint_authority_pubkey: &Pubkey,
1241 freeze_authority_pubkey: Option<&Pubkey>,
1242 decimals: u8,
1243) -> Result<Instruction, ProgramError> {
1244 check_spl_token_program_account(token_program_id)?;
1245 let freeze_authority = freeze_authority_pubkey.cloned().into();
1246 let data = TokenInstruction::InitializeMint2 {
1247 mint_authority: *mint_authority_pubkey,
1248 freeze_authority,
1249 decimals,
1250 }
1251 .pack();
1252
1253 let accounts = vec![AccountMeta::new(*mint_pubkey, false)];
1254
1255 Ok(Instruction {
1256 program_id: *token_program_id,
1257 accounts,
1258 data,
1259 })
1260}
1261
1262pub fn initialize_account(
1264 token_program_id: &Pubkey,
1265 account_pubkey: &Pubkey,
1266 mint_pubkey: &Pubkey,
1267 owner_pubkey: &Pubkey,
1268) -> Result<Instruction, ProgramError> {
1269 check_spl_token_program_account(token_program_id)?;
1270 let data = TokenInstruction::InitializeAccount.pack();
1271
1272 let accounts = vec![
1273 AccountMeta::new(*account_pubkey, false),
1274 AccountMeta::new_readonly(*mint_pubkey, false),
1275 AccountMeta::new_readonly(*owner_pubkey, false),
1276 AccountMeta::new_readonly(sysvar::rent::id(), false),
1277 ];
1278
1279 Ok(Instruction {
1280 program_id: *token_program_id,
1281 accounts,
1282 data,
1283 })
1284}
1285
1286pub fn initialize_account2(
1288 token_program_id: &Pubkey,
1289 account_pubkey: &Pubkey,
1290 mint_pubkey: &Pubkey,
1291 owner_pubkey: &Pubkey,
1292) -> Result<Instruction, ProgramError> {
1293 check_spl_token_program_account(token_program_id)?;
1294 let data = TokenInstruction::InitializeAccount2 {
1295 owner: *owner_pubkey,
1296 }
1297 .pack();
1298
1299 let accounts = vec![
1300 AccountMeta::new(*account_pubkey, false),
1301 AccountMeta::new_readonly(*mint_pubkey, false),
1302 AccountMeta::new_readonly(sysvar::rent::id(), false),
1303 ];
1304
1305 Ok(Instruction {
1306 program_id: *token_program_id,
1307 accounts,
1308 data,
1309 })
1310}
1311
1312pub fn initialize_account3(
1314 token_program_id: &Pubkey,
1315 account_pubkey: &Pubkey,
1316 mint_pubkey: &Pubkey,
1317 owner_pubkey: &Pubkey,
1318) -> Result<Instruction, ProgramError> {
1319 check_spl_token_program_account(token_program_id)?;
1320 let data = TokenInstruction::InitializeAccount3 {
1321 owner: *owner_pubkey,
1322 }
1323 .pack();
1324
1325 let accounts = vec![
1326 AccountMeta::new(*account_pubkey, false),
1327 AccountMeta::new_readonly(*mint_pubkey, false),
1328 ];
1329
1330 Ok(Instruction {
1331 program_id: *token_program_id,
1332 accounts,
1333 data,
1334 })
1335}
1336
1337pub fn initialize_multisig(
1339 token_program_id: &Pubkey,
1340 multisig_pubkey: &Pubkey,
1341 signer_pubkeys: &[&Pubkey],
1342 m: u8,
1343) -> Result<Instruction, ProgramError> {
1344 check_spl_token_program_account(token_program_id)?;
1345 if !is_valid_signer_index(m as usize)
1346 || !is_valid_signer_index(signer_pubkeys.len())
1347 || m as usize > signer_pubkeys.len()
1348 {
1349 return Err(ProgramError::MissingRequiredSignature);
1350 }
1351 let data = TokenInstruction::InitializeMultisig { m }.pack();
1352
1353 let mut accounts = Vec::with_capacity(1 + 1 + signer_pubkeys.len());
1354 accounts.push(AccountMeta::new(*multisig_pubkey, false));
1355 accounts.push(AccountMeta::new_readonly(sysvar::rent::id(), false));
1356 for signer_pubkey in signer_pubkeys.iter() {
1357 accounts.push(AccountMeta::new_readonly(**signer_pubkey, false));
1358 }
1359
1360 Ok(Instruction {
1361 program_id: *token_program_id,
1362 accounts,
1363 data,
1364 })
1365}
1366
1367pub fn initialize_multisig2(
1369 token_program_id: &Pubkey,
1370 multisig_pubkey: &Pubkey,
1371 signer_pubkeys: &[&Pubkey],
1372 m: u8,
1373) -> Result<Instruction, ProgramError> {
1374 check_spl_token_program_account(token_program_id)?;
1375 if !is_valid_signer_index(m as usize)
1376 || !is_valid_signer_index(signer_pubkeys.len())
1377 || m as usize > signer_pubkeys.len()
1378 {
1379 return Err(ProgramError::MissingRequiredSignature);
1380 }
1381 let data = TokenInstruction::InitializeMultisig2 { m }.pack();
1382
1383 let mut accounts = Vec::with_capacity(1 + 1 + signer_pubkeys.len());
1384 accounts.push(AccountMeta::new(*multisig_pubkey, false));
1385 for signer_pubkey in signer_pubkeys.iter() {
1386 accounts.push(AccountMeta::new_readonly(**signer_pubkey, false));
1387 }
1388
1389 Ok(Instruction {
1390 program_id: *token_program_id,
1391 accounts,
1392 data,
1393 })
1394}
1395
1396#[deprecated(
1398 since = "4.0.0",
1399 note = "please use `transfer_checked` or `transfer_checked_with_fee` instead"
1400)]
1401pub fn transfer(
1402 token_program_id: &Pubkey,
1403 source_pubkey: &Pubkey,
1404 destination_pubkey: &Pubkey,
1405 authority_pubkey: &Pubkey,
1406 signer_pubkeys: &[&Pubkey],
1407 amount: u64,
1408) -> Result<Instruction, ProgramError> {
1409 check_spl_token_program_account(token_program_id)?;
1410 #[allow(deprecated)]
1411 let data = TokenInstruction::Transfer { amount }.pack();
1412
1413 let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1414 accounts.push(AccountMeta::new(*source_pubkey, false));
1415 accounts.push(AccountMeta::new(*destination_pubkey, false));
1416 accounts.push(AccountMeta::new_readonly(
1417 *authority_pubkey,
1418 signer_pubkeys.is_empty(),
1419 ));
1420 for signer_pubkey in signer_pubkeys.iter() {
1421 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1422 }
1423
1424 Ok(Instruction {
1425 program_id: *token_program_id,
1426 accounts,
1427 data,
1428 })
1429}
1430
1431pub fn approve(
1433 token_program_id: &Pubkey,
1434 source_pubkey: &Pubkey,
1435 delegate_pubkey: &Pubkey,
1436 owner_pubkey: &Pubkey,
1437 signer_pubkeys: &[&Pubkey],
1438 amount: u64,
1439) -> Result<Instruction, ProgramError> {
1440 check_spl_token_program_account(token_program_id)?;
1441 let data = TokenInstruction::Approve { amount }.pack();
1442
1443 let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1444 accounts.push(AccountMeta::new(*source_pubkey, false));
1445 accounts.push(AccountMeta::new_readonly(*delegate_pubkey, false));
1446 accounts.push(AccountMeta::new_readonly(
1447 *owner_pubkey,
1448 signer_pubkeys.is_empty(),
1449 ));
1450 for signer_pubkey in signer_pubkeys.iter() {
1451 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1452 }
1453
1454 Ok(Instruction {
1455 program_id: *token_program_id,
1456 accounts,
1457 data,
1458 })
1459}
1460
1461pub fn revoke(
1463 token_program_id: &Pubkey,
1464 source_pubkey: &Pubkey,
1465 owner_pubkey: &Pubkey,
1466 signer_pubkeys: &[&Pubkey],
1467) -> Result<Instruction, ProgramError> {
1468 check_spl_token_program_account(token_program_id)?;
1469 let data = TokenInstruction::Revoke.pack();
1470
1471 let mut accounts = Vec::with_capacity(2 + signer_pubkeys.len());
1472 accounts.push(AccountMeta::new(*source_pubkey, false));
1473 accounts.push(AccountMeta::new_readonly(
1474 *owner_pubkey,
1475 signer_pubkeys.is_empty(),
1476 ));
1477 for signer_pubkey in signer_pubkeys.iter() {
1478 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1479 }
1480
1481 Ok(Instruction {
1482 program_id: *token_program_id,
1483 accounts,
1484 data,
1485 })
1486}
1487
1488pub fn set_authority(
1490 token_program_id: &Pubkey,
1491 owned_pubkey: &Pubkey,
1492 new_authority_pubkey: Option<&Pubkey>,
1493 authority_type: AuthorityType,
1494 owner_pubkey: &Pubkey,
1495 signer_pubkeys: &[&Pubkey],
1496) -> Result<Instruction, ProgramError> {
1497 check_spl_token_program_account(token_program_id)?;
1498 let new_authority = new_authority_pubkey.cloned().into();
1499 let data = TokenInstruction::SetAuthority {
1500 authority_type,
1501 new_authority,
1502 }
1503 .pack();
1504
1505 let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1506 accounts.push(AccountMeta::new(*owned_pubkey, false));
1507 accounts.push(AccountMeta::new_readonly(
1508 *owner_pubkey,
1509 signer_pubkeys.is_empty(),
1510 ));
1511 for signer_pubkey in signer_pubkeys.iter() {
1512 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1513 }
1514
1515 Ok(Instruction {
1516 program_id: *token_program_id,
1517 accounts,
1518 data,
1519 })
1520}
1521
1522pub fn mint_to(
1524 token_program_id: &Pubkey,
1525 mint_pubkey: &Pubkey,
1526 account_pubkey: &Pubkey,
1527 mint_authority_pubkey: &Pubkey,
1528 signer_pubkeys: &[&Pubkey],
1529 amount: u64,
1530) -> Result<Instruction, ProgramError> {
1531 check_spl_token_program_account(token_program_id)?;
1532 let data = TokenInstruction::MintTo { amount }.pack();
1533
1534 let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1535 accounts.push(AccountMeta::new(*mint_pubkey, false));
1536 accounts.push(AccountMeta::new(*account_pubkey, false));
1537 accounts.push(AccountMeta::new_readonly(
1538 *mint_authority_pubkey,
1539 signer_pubkeys.is_empty(),
1540 ));
1541 for signer_pubkey in signer_pubkeys.iter() {
1542 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1543 }
1544
1545 Ok(Instruction {
1546 program_id: *token_program_id,
1547 accounts,
1548 data,
1549 })
1550}
1551
1552pub fn burn(
1554 token_program_id: &Pubkey,
1555 account_pubkey: &Pubkey,
1556 mint_pubkey: &Pubkey,
1557 authority_pubkey: &Pubkey,
1558 signer_pubkeys: &[&Pubkey],
1559 amount: u64,
1560) -> Result<Instruction, ProgramError> {
1561 check_spl_token_program_account(token_program_id)?;
1562 let data = TokenInstruction::Burn { amount }.pack();
1563
1564 let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1565 accounts.push(AccountMeta::new(*account_pubkey, false));
1566 accounts.push(AccountMeta::new(*mint_pubkey, false));
1567 accounts.push(AccountMeta::new_readonly(
1568 *authority_pubkey,
1569 signer_pubkeys.is_empty(),
1570 ));
1571 for signer_pubkey in signer_pubkeys.iter() {
1572 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1573 }
1574
1575 Ok(Instruction {
1576 program_id: *token_program_id,
1577 accounts,
1578 data,
1579 })
1580}
1581
1582pub fn close_account(
1584 token_program_id: &Pubkey,
1585 account_pubkey: &Pubkey,
1586 destination_pubkey: &Pubkey,
1587 owner_pubkey: &Pubkey,
1588 signer_pubkeys: &[&Pubkey],
1589) -> Result<Instruction, ProgramError> {
1590 check_spl_token_program_account(token_program_id)?;
1591 let data = TokenInstruction::CloseAccount.pack();
1592
1593 let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1594 accounts.push(AccountMeta::new(*account_pubkey, false));
1595 accounts.push(AccountMeta::new(*destination_pubkey, false));
1596 accounts.push(AccountMeta::new_readonly(
1597 *owner_pubkey,
1598 signer_pubkeys.is_empty(),
1599 ));
1600 for signer_pubkey in signer_pubkeys.iter() {
1601 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1602 }
1603
1604 Ok(Instruction {
1605 program_id: *token_program_id,
1606 accounts,
1607 data,
1608 })
1609}
1610
1611pub fn freeze_account(
1613 token_program_id: &Pubkey,
1614 account_pubkey: &Pubkey,
1615 mint_pubkey: &Pubkey,
1616 freeze_authority_pubkey: &Pubkey,
1617 signer_pubkeys: &[&Pubkey],
1618) -> Result<Instruction, ProgramError> {
1619 check_spl_token_program_account(token_program_id)?;
1620 let data = TokenInstruction::FreezeAccount.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_readonly(*mint_pubkey, false));
1625 accounts.push(AccountMeta::new_readonly(
1626 *freeze_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 thaw_account(
1642 token_program_id: &Pubkey,
1643 account_pubkey: &Pubkey,
1644 mint_pubkey: &Pubkey,
1645 freeze_authority_pubkey: &Pubkey,
1646 signer_pubkeys: &[&Pubkey],
1647) -> Result<Instruction, ProgramError> {
1648 check_spl_token_program_account(token_program_id)?;
1649 let data = TokenInstruction::ThawAccount.pack();
1650
1651 let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1652 accounts.push(AccountMeta::new(*account_pubkey, false));
1653 accounts.push(AccountMeta::new_readonly(*mint_pubkey, false));
1654 accounts.push(AccountMeta::new_readonly(
1655 *freeze_authority_pubkey,
1656 signer_pubkeys.is_empty(),
1657 ));
1658 for signer_pubkey in signer_pubkeys.iter() {
1659 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1660 }
1661
1662 Ok(Instruction {
1663 program_id: *token_program_id,
1664 accounts,
1665 data,
1666 })
1667}
1668
1669#[allow(clippy::too_many_arguments)]
1671pub fn transfer_checked(
1672 token_program_id: &Pubkey,
1673 source_pubkey: &Pubkey,
1674 mint_pubkey: &Pubkey,
1675 destination_pubkey: &Pubkey,
1676 authority_pubkey: &Pubkey,
1677 signer_pubkeys: &[&Pubkey],
1678 amount: u64,
1679 decimals: u8,
1680) -> Result<Instruction, ProgramError> {
1681 check_spl_token_program_account(token_program_id)?;
1682 let data = TokenInstruction::TransferChecked { amount, decimals }.pack();
1683
1684 let mut accounts = Vec::with_capacity(4 + signer_pubkeys.len());
1685 accounts.push(AccountMeta::new(*source_pubkey, false));
1686 accounts.push(AccountMeta::new_readonly(*mint_pubkey, false));
1687 accounts.push(AccountMeta::new(*destination_pubkey, false));
1688 accounts.push(AccountMeta::new_readonly(
1689 *authority_pubkey,
1690 signer_pubkeys.is_empty(),
1691 ));
1692 for signer_pubkey in signer_pubkeys.iter() {
1693 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1694 }
1695
1696 Ok(Instruction {
1697 program_id: *token_program_id,
1698 accounts,
1699 data,
1700 })
1701}
1702
1703#[allow(clippy::too_many_arguments)]
1705pub fn approve_checked(
1706 token_program_id: &Pubkey,
1707 source_pubkey: &Pubkey,
1708 mint_pubkey: &Pubkey,
1709 delegate_pubkey: &Pubkey,
1710 owner_pubkey: &Pubkey,
1711 signer_pubkeys: &[&Pubkey],
1712 amount: u64,
1713 decimals: u8,
1714) -> Result<Instruction, ProgramError> {
1715 check_spl_token_program_account(token_program_id)?;
1716 let data = TokenInstruction::ApproveChecked { amount, decimals }.pack();
1717
1718 let mut accounts = Vec::with_capacity(4 + signer_pubkeys.len());
1719 accounts.push(AccountMeta::new(*source_pubkey, false));
1720 accounts.push(AccountMeta::new_readonly(*mint_pubkey, false));
1721 accounts.push(AccountMeta::new_readonly(*delegate_pubkey, false));
1722 accounts.push(AccountMeta::new_readonly(
1723 *owner_pubkey,
1724 signer_pubkeys.is_empty(),
1725 ));
1726 for signer_pubkey in signer_pubkeys.iter() {
1727 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1728 }
1729
1730 Ok(Instruction {
1731 program_id: *token_program_id,
1732 accounts,
1733 data,
1734 })
1735}
1736
1737pub fn mint_to_checked(
1739 token_program_id: &Pubkey,
1740 mint_pubkey: &Pubkey,
1741 account_pubkey: &Pubkey,
1742 mint_authority_pubkey: &Pubkey,
1743 signer_pubkeys: &[&Pubkey],
1744 amount: u64,
1745 decimals: u8,
1746) -> Result<Instruction, ProgramError> {
1747 check_spl_token_program_account(token_program_id)?;
1748 let data = TokenInstruction::MintToChecked { amount, decimals }.pack();
1749
1750 let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1751 accounts.push(AccountMeta::new(*mint_pubkey, false));
1752 accounts.push(AccountMeta::new(*account_pubkey, false));
1753 accounts.push(AccountMeta::new_readonly(
1754 *mint_authority_pubkey,
1755 signer_pubkeys.is_empty(),
1756 ));
1757 for signer_pubkey in signer_pubkeys.iter() {
1758 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1759 }
1760
1761 Ok(Instruction {
1762 program_id: *token_program_id,
1763 accounts,
1764 data,
1765 })
1766}
1767
1768pub fn burn_checked(
1770 token_program_id: &Pubkey,
1771 account_pubkey: &Pubkey,
1772 mint_pubkey: &Pubkey,
1773 authority_pubkey: &Pubkey,
1774 signer_pubkeys: &[&Pubkey],
1775 amount: u64,
1776 decimals: u8,
1777) -> Result<Instruction, ProgramError> {
1778 check_spl_token_program_account(token_program_id)?;
1779 let data = TokenInstruction::BurnChecked { amount, decimals }.pack();
1780
1781 let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1782 accounts.push(AccountMeta::new(*account_pubkey, false));
1783 accounts.push(AccountMeta::new(*mint_pubkey, false));
1784 accounts.push(AccountMeta::new_readonly(
1785 *authority_pubkey,
1786 signer_pubkeys.is_empty(),
1787 ));
1788 for signer_pubkey in signer_pubkeys.iter() {
1789 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1790 }
1791
1792 Ok(Instruction {
1793 program_id: *token_program_id,
1794 accounts,
1795 data,
1796 })
1797}
1798
1799pub fn sync_native(
1801 token_program_id: &Pubkey,
1802 account_pubkey: &Pubkey,
1803) -> Result<Instruction, ProgramError> {
1804 check_spl_token_program_account(token_program_id)?;
1805
1806 Ok(Instruction {
1807 program_id: *token_program_id,
1808 accounts: vec![AccountMeta::new(*account_pubkey, false)],
1809 data: TokenInstruction::SyncNative.pack(),
1810 })
1811}
1812
1813pub fn get_account_data_size(
1815 token_program_id: &Pubkey,
1816 mint_pubkey: &Pubkey,
1817 extension_types: &[ExtensionType],
1818) -> Result<Instruction, ProgramError> {
1819 check_spl_token_program_account(token_program_id)?;
1820 Ok(Instruction {
1821 program_id: *token_program_id,
1822 accounts: vec![AccountMeta::new_readonly(*mint_pubkey, false)],
1823 data: TokenInstruction::GetAccountDataSize {
1824 extension_types: extension_types.to_vec(),
1825 }
1826 .pack(),
1827 })
1828}
1829
1830pub fn initialize_mint_close_authority(
1832 token_program_id: &Pubkey,
1833 mint_pubkey: &Pubkey,
1834 close_authority: Option<&Pubkey>,
1835) -> Result<Instruction, ProgramError> {
1836 check_program_account(token_program_id)?;
1837 let close_authority = close_authority.cloned().into();
1838 Ok(Instruction {
1839 program_id: *token_program_id,
1840 accounts: vec![AccountMeta::new(*mint_pubkey, false)],
1841 data: TokenInstruction::InitializeMintCloseAuthority { close_authority }.pack(),
1842 })
1843}
1844
1845pub fn initialize_immutable_owner(
1847 token_program_id: &Pubkey,
1848 token_account: &Pubkey,
1849) -> Result<Instruction, ProgramError> {
1850 check_spl_token_program_account(token_program_id)?;
1851 Ok(Instruction {
1852 program_id: *token_program_id,
1853 accounts: vec![AccountMeta::new(*token_account, false)],
1854 data: TokenInstruction::InitializeImmutableOwner.pack(),
1855 })
1856}
1857
1858pub fn amount_to_ui_amount(
1860 token_program_id: &Pubkey,
1861 mint_pubkey: &Pubkey,
1862 amount: u64,
1863) -> Result<Instruction, ProgramError> {
1864 check_spl_token_program_account(token_program_id)?;
1865
1866 Ok(Instruction {
1867 program_id: *token_program_id,
1868 accounts: vec![AccountMeta::new_readonly(*mint_pubkey, false)],
1869 data: TokenInstruction::AmountToUiAmount { amount }.pack(),
1870 })
1871}
1872
1873pub fn ui_amount_to_amount(
1875 token_program_id: &Pubkey,
1876 mint_pubkey: &Pubkey,
1877 ui_amount: &str,
1878) -> Result<Instruction, ProgramError> {
1879 check_spl_token_program_account(token_program_id)?;
1880
1881 Ok(Instruction {
1882 program_id: *token_program_id,
1883 accounts: vec![AccountMeta::new_readonly(*mint_pubkey, false)],
1884 data: TokenInstruction::UiAmountToAmount { ui_amount }.pack(),
1885 })
1886}
1887
1888pub fn reallocate(
1890 token_program_id: &Pubkey,
1891 account_pubkey: &Pubkey,
1892 payer: &Pubkey,
1893 owner_pubkey: &Pubkey,
1894 signer_pubkeys: &[&Pubkey],
1895 extension_types: &[ExtensionType],
1896) -> Result<Instruction, ProgramError> {
1897 check_program_account(token_program_id)?;
1898
1899 let mut accounts = Vec::with_capacity(4 + signer_pubkeys.len());
1900 accounts.push(AccountMeta::new(*account_pubkey, false));
1901 accounts.push(AccountMeta::new(*payer, true));
1902 accounts.push(AccountMeta::new_readonly(system_program::id(), false));
1903 accounts.push(AccountMeta::new_readonly(
1904 *owner_pubkey,
1905 signer_pubkeys.is_empty(),
1906 ));
1907 for signer_pubkey in signer_pubkeys.iter() {
1908 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1909 }
1910
1911 Ok(Instruction {
1912 program_id: *token_program_id,
1913 accounts,
1914 data: TokenInstruction::Reallocate {
1915 extension_types: extension_types.to_vec(),
1916 }
1917 .pack(),
1918 })
1919}
1920
1921pub fn create_native_mint(
1923 token_program_id: &Pubkey,
1924 payer: &Pubkey,
1925) -> Result<Instruction, ProgramError> {
1926 check_program_account(token_program_id)?;
1927
1928 Ok(Instruction {
1929 program_id: *token_program_id,
1930 accounts: vec![
1931 AccountMeta::new(*payer, true),
1932 AccountMeta::new(crate::native_mint::id(), false),
1933 AccountMeta::new_readonly(system_program::id(), false),
1934 ],
1935 data: TokenInstruction::CreateNativeMint.pack(),
1936 })
1937}
1938
1939pub fn initialize_non_transferable_mint(
1941 token_program_id: &Pubkey,
1942 mint_pubkey: &Pubkey,
1943) -> Result<Instruction, ProgramError> {
1944 check_program_account(token_program_id)?;
1945 Ok(Instruction {
1946 program_id: *token_program_id,
1947 accounts: vec![AccountMeta::new(*mint_pubkey, false)],
1948 data: TokenInstruction::InitializeNonTransferableMint.pack(),
1949 })
1950}
1951
1952pub fn initialize_permanent_delegate(
1954 token_program_id: &Pubkey,
1955 mint_pubkey: &Pubkey,
1956 delegate: &Pubkey,
1957) -> Result<Instruction, ProgramError> {
1958 check_program_account(token_program_id)?;
1959 Ok(Instruction {
1960 program_id: *token_program_id,
1961 accounts: vec![AccountMeta::new(*mint_pubkey, false)],
1962 data: TokenInstruction::InitializePermanentDelegate {
1963 delegate: *delegate,
1964 }
1965 .pack(),
1966 })
1967}
1968
1969pub fn is_valid_signer_index(index: usize) -> bool {
1972 (MIN_SIGNERS..=MAX_SIGNERS).contains(&index)
1973}
1974
1975pub fn decode_instruction_type<T: TryFrom<u8>>(input: &[u8]) -> Result<T, ProgramError> {
1977 if input.is_empty() {
1978 Err(ProgramError::InvalidInstructionData)
1979 } else {
1980 T::try_from(input[0]).map_err(|_| TokenError::InvalidInstruction.into())
1981 }
1982}
1983
1984pub fn decode_instruction_data<T: Pod>(input_with_type: &[u8]) -> Result<&T, ProgramError> {
2014 if input_with_type.len() != pod_get_packed_len::<T>().saturating_add(1) {
2015 Err(ProgramError::InvalidInstructionData)
2016 } else {
2017 pod_from_bytes(&input_with_type[1..])
2018 }
2019}
2020
2021pub(crate) fn encode_instruction<T: Into<u8>, D: Pod>(
2023 token_program_id: &Pubkey,
2024 accounts: Vec<AccountMeta>,
2025 token_instruction_type: TokenInstruction,
2026 instruction_type: T,
2027 instruction_data: &D,
2028) -> Instruction {
2029 let mut data = token_instruction_type.pack();
2030 data.push(T::into(instruction_type));
2031 data.extend_from_slice(bytemuck::bytes_of(instruction_data));
2032 Instruction {
2033 program_id: *token_program_id,
2034 accounts,
2035 data,
2036 }
2037}
2038
2039pub fn withdraw_excess_lamports(
2041 token_program_id: &Pubkey,
2042 source_account: &Pubkey,
2043 destination_account: &Pubkey,
2044 authority: &Pubkey,
2045 signers: &[&Pubkey],
2046) -> Result<Instruction, ProgramError> {
2047 check_program_account(token_program_id)?;
2048
2049 let mut accounts = vec![
2050 AccountMeta::new(*source_account, false),
2051 AccountMeta::new(*destination_account, false),
2052 AccountMeta::new_readonly(*authority, signers.is_empty()),
2053 ];
2054
2055 for signer in signers {
2056 accounts.push(AccountMeta::new_readonly(**signer, true))
2057 }
2058
2059 Ok(Instruction {
2060 program_id: *token_program_id,
2061 accounts,
2062 data: TokenInstruction::WithdrawExcessLamports.pack(),
2063 })
2064}
2065
2066#[cfg(test)]
2067mod test {
2068 use {super::*, proptest::prelude::*};
2069
2070 #[test]
2071 fn test_initialize_mint_packing() {
2072 let decimals = 2;
2073 let mint_authority = Pubkey::new_from_array([1u8; 32]);
2074 let freeze_authority = COption::None;
2075 let check = TokenInstruction::InitializeMint {
2076 decimals,
2077 mint_authority,
2078 freeze_authority,
2079 };
2080 let packed = check.pack();
2081 let mut expect = Vec::from([0u8, 2]);
2082 expect.extend_from_slice(&[1u8; 32]);
2083 expect.extend_from_slice(&[0]);
2084 assert_eq!(packed, expect);
2085 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2086 assert_eq!(unpacked, check);
2087
2088 let mint_authority = Pubkey::new_from_array([2u8; 32]);
2089 let freeze_authority = COption::Some(Pubkey::new_from_array([3u8; 32]));
2090 let check = TokenInstruction::InitializeMint {
2091 decimals,
2092 mint_authority,
2093 freeze_authority,
2094 };
2095 let packed = check.pack();
2096 let mut expect = vec![0u8, 2];
2097 expect.extend_from_slice(&[2u8; 32]);
2098 expect.extend_from_slice(&[1]);
2099 expect.extend_from_slice(&[3u8; 32]);
2100 assert_eq!(packed, expect);
2101 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2102 assert_eq!(unpacked, check);
2103 }
2104
2105 #[test]
2106 fn test_initialize_account_packing() {
2107 let check = TokenInstruction::InitializeAccount;
2108 let packed = check.pack();
2109 let expect = Vec::from([1u8]);
2110 assert_eq!(packed, expect);
2111 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2112 assert_eq!(unpacked, check);
2113 }
2114
2115 #[test]
2116 fn test_initialize_multisig_packing() {
2117 let m = 1;
2118 let check = TokenInstruction::InitializeMultisig { m };
2119 let packed = check.pack();
2120 let expect = Vec::from([2u8, 1]);
2121 assert_eq!(packed, expect);
2122 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2123 assert_eq!(unpacked, check);
2124 }
2125
2126 #[test]
2127 fn test_transfer_packing() {
2128 let amount = 1;
2129 #[allow(deprecated)]
2130 let check = TokenInstruction::Transfer { amount };
2131 let packed = check.pack();
2132 let expect = Vec::from([3u8, 1, 0, 0, 0, 0, 0, 0, 0]);
2133 assert_eq!(packed, expect);
2134 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2135 assert_eq!(unpacked, check);
2136 }
2137
2138 #[test]
2139 fn test_approve_packing() {
2140 let amount = 1;
2141 let check = TokenInstruction::Approve { amount };
2142 let packed = check.pack();
2143 let expect = Vec::from([4u8, 1, 0, 0, 0, 0, 0, 0, 0]);
2144 assert_eq!(packed, expect);
2145 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2146 assert_eq!(unpacked, check);
2147 }
2148
2149 #[test]
2150 fn test_revoke_packing() {
2151 let check = TokenInstruction::Revoke;
2152 let packed = check.pack();
2153 let expect = Vec::from([5u8]);
2154 assert_eq!(packed, expect);
2155 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2156 assert_eq!(unpacked, check);
2157 }
2158
2159 #[test]
2160 fn test_set_authority_packing() {
2161 let authority_type = AuthorityType::FreezeAccount;
2162 let new_authority = COption::Some(Pubkey::new_from_array([4u8; 32]));
2163 let check = TokenInstruction::SetAuthority {
2164 authority_type: authority_type.clone(),
2165 new_authority,
2166 };
2167 let packed = check.pack();
2168 let mut expect = Vec::from([6u8, 1]);
2169 expect.extend_from_slice(&[1]);
2170 expect.extend_from_slice(&[4u8; 32]);
2171 assert_eq!(packed, expect);
2172 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2173 assert_eq!(unpacked, check);
2174 }
2175
2176 #[test]
2177 fn test_mint_to_packing() {
2178 let amount = 1;
2179 let check = TokenInstruction::MintTo { amount };
2180 let packed = check.pack();
2181 let expect = Vec::from([7u8, 1, 0, 0, 0, 0, 0, 0, 0]);
2182 assert_eq!(packed, expect);
2183 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2184 assert_eq!(unpacked, check);
2185 }
2186
2187 #[test]
2188 fn test_burn_packing() {
2189 let amount = 1;
2190 let check = TokenInstruction::Burn { amount };
2191 let packed = check.pack();
2192 let expect = Vec::from([8u8, 1, 0, 0, 0, 0, 0, 0, 0]);
2193 assert_eq!(packed, expect);
2194 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2195 assert_eq!(unpacked, check);
2196 }
2197
2198 #[test]
2199 fn test_close_account_packing() {
2200 let check = TokenInstruction::CloseAccount;
2201 let packed = check.pack();
2202 let expect = Vec::from([9u8]);
2203 assert_eq!(packed, expect);
2204 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2205 assert_eq!(unpacked, check);
2206 }
2207
2208 #[test]
2209 fn test_freeze_account_packing() {
2210 let check = TokenInstruction::FreezeAccount;
2211 let packed = check.pack();
2212 let expect = Vec::from([10u8]);
2213 assert_eq!(packed, expect);
2214 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2215 assert_eq!(unpacked, check);
2216 }
2217
2218 #[test]
2219 fn test_thaw_account_packing() {
2220 let check = TokenInstruction::ThawAccount;
2221 let packed = check.pack();
2222 let expect = Vec::from([11u8]);
2223 assert_eq!(packed, expect);
2224 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2225 assert_eq!(unpacked, check);
2226 }
2227
2228 #[test]
2229 fn test_transfer_checked_packing() {
2230 let amount = 1;
2231 let decimals = 2;
2232 let check = TokenInstruction::TransferChecked { amount, decimals };
2233 let packed = check.pack();
2234 let expect = Vec::from([12u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]);
2235 assert_eq!(packed, expect);
2236 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2237 assert_eq!(unpacked, check);
2238 }
2239
2240 #[test]
2241 fn test_approve_checked_packing() {
2242 let amount = 1;
2243 let decimals = 2;
2244
2245 let check = TokenInstruction::ApproveChecked { amount, decimals };
2246 let packed = check.pack();
2247 let expect = Vec::from([13u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]);
2248 assert_eq!(packed, expect);
2249 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2250 assert_eq!(unpacked, check);
2251 }
2252
2253 #[test]
2254 fn test_mint_to_checked_packing() {
2255 let amount = 1;
2256 let decimals = 2;
2257 let check = TokenInstruction::MintToChecked { amount, decimals };
2258 let packed = check.pack();
2259 let expect = Vec::from([14u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]);
2260 assert_eq!(packed, expect);
2261 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2262 assert_eq!(unpacked, check);
2263 }
2264
2265 #[test]
2266 fn test_burn_checked_packing() {
2267 let amount = 1;
2268 let decimals = 2;
2269 let check = TokenInstruction::BurnChecked { amount, decimals };
2270 let packed = check.pack();
2271 let expect = Vec::from([15u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]);
2272 assert_eq!(packed, expect);
2273 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2274 assert_eq!(unpacked, check);
2275 }
2276
2277 #[test]
2278 fn test_initialize_account2_packing() {
2279 let owner = Pubkey::new_from_array([2u8; 32]);
2280 let check = TokenInstruction::InitializeAccount2 { owner };
2281 let packed = check.pack();
2282 let mut expect = vec![16u8];
2283 expect.extend_from_slice(&[2u8; 32]);
2284 assert_eq!(packed, expect);
2285 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2286 assert_eq!(unpacked, check);
2287 }
2288
2289 #[test]
2290 fn test_sync_native_packing() {
2291 let check = TokenInstruction::SyncNative;
2292 let packed = check.pack();
2293 let expect = vec![17u8];
2294 assert_eq!(packed, expect);
2295 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2296 assert_eq!(unpacked, check);
2297 }
2298
2299 #[test]
2300 fn test_initialize_account3_packing() {
2301 let owner = Pubkey::new_from_array([2u8; 32]);
2302 let check = TokenInstruction::InitializeAccount3 { owner };
2303 let packed = check.pack();
2304 let mut expect = vec![18u8];
2305 expect.extend_from_slice(&[2u8; 32]);
2306 assert_eq!(packed, expect);
2307 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2308 assert_eq!(unpacked, check);
2309 }
2310
2311 #[test]
2312 fn test_initialize_multisig2_packing() {
2313 let m = 1;
2314 let check = TokenInstruction::InitializeMultisig2 { m };
2315 let packed = check.pack();
2316 let expect = Vec::from([19u8, 1]);
2317 assert_eq!(packed, expect);
2318 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2319 assert_eq!(unpacked, check);
2320 }
2321
2322 #[test]
2323 fn test_initialize_mint2_packing() {
2324 let decimals = 2;
2325 let mint_authority = Pubkey::new_from_array([1u8; 32]);
2326 let freeze_authority = COption::None;
2327 let check = TokenInstruction::InitializeMint2 {
2328 decimals,
2329 mint_authority,
2330 freeze_authority,
2331 };
2332 let packed = check.pack();
2333 let mut expect = Vec::from([20u8, 2]);
2334 expect.extend_from_slice(&[1u8; 32]);
2335 expect.extend_from_slice(&[0]);
2336 assert_eq!(packed, expect);
2337 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2338 assert_eq!(unpacked, check);
2339
2340 let decimals = 2;
2341 let mint_authority = Pubkey::new_from_array([2u8; 32]);
2342 let freeze_authority = COption::Some(Pubkey::new_from_array([3u8; 32]));
2343 let check = TokenInstruction::InitializeMint2 {
2344 decimals,
2345 mint_authority,
2346 freeze_authority,
2347 };
2348 let packed = check.pack();
2349 let mut expect = vec![20u8, 2];
2350 expect.extend_from_slice(&[2u8; 32]);
2351 expect.extend_from_slice(&[1]);
2352 expect.extend_from_slice(&[3u8; 32]);
2353 assert_eq!(packed, expect);
2354 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2355 assert_eq!(unpacked, check);
2356 }
2357
2358 #[test]
2359 fn test_get_account_data_size_packing() {
2360 let extension_types = vec![];
2361 let check = TokenInstruction::GetAccountDataSize {
2362 extension_types: extension_types.clone(),
2363 };
2364 let packed = check.pack();
2365 let expect = [21u8];
2366 assert_eq!(packed, &[21u8]);
2367 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2368 assert_eq!(unpacked, check);
2369
2370 let extension_types = vec![
2371 ExtensionType::TransferFeeConfig,
2372 ExtensionType::TransferFeeAmount,
2373 ];
2374 let check = TokenInstruction::GetAccountDataSize {
2375 extension_types: extension_types.clone(),
2376 };
2377 let packed = check.pack();
2378 let expect = [21u8, 1, 0, 2, 0];
2379 assert_eq!(packed, &[21u8, 1, 0, 2, 0]);
2380 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2381 assert_eq!(unpacked, check);
2382 }
2383
2384 #[test]
2385 fn test_amount_to_ui_amount_packing() {
2386 let amount = 42;
2387 let check = TokenInstruction::AmountToUiAmount { amount };
2388 let packed = check.pack();
2389 let expect = vec![23u8, 42, 0, 0, 0, 0, 0, 0, 0];
2390 assert_eq!(packed, expect);
2391 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2392 assert_eq!(unpacked, check);
2393 }
2394
2395 #[test]
2396 fn test_ui_amount_to_amount_packing() {
2397 let ui_amount = "0.42";
2398 let check = TokenInstruction::UiAmountToAmount { ui_amount };
2399 let packed = check.pack();
2400 let expect = vec![24u8, 48, 46, 52, 50];
2401 assert_eq!(packed, expect);
2402 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2403 assert_eq!(unpacked, check);
2404 }
2405
2406 #[test]
2407 fn test_initialize_mint_close_authority_packing() {
2408 let close_authority = COption::Some(Pubkey::new_from_array([10u8; 32]));
2409 let check = TokenInstruction::InitializeMintCloseAuthority { close_authority };
2410 let packed = check.pack();
2411 let mut expect = vec![25u8, 1];
2412 expect.extend_from_slice(&[10u8; 32]);
2413 assert_eq!(packed, expect);
2414 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2415 assert_eq!(unpacked, check);
2416 }
2417
2418 #[test]
2419 fn test_create_native_mint_packing() {
2420 let check = TokenInstruction::CreateNativeMint;
2421 let packed = check.pack();
2422 let expect = vec![31u8];
2423 assert_eq!(packed, expect);
2424 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2425 assert_eq!(unpacked, check);
2426 }
2427
2428 #[test]
2429 fn test_initialize_permanent_delegate_packing() {
2430 let delegate = Pubkey::new_from_array([11u8; 32]);
2431 let check = TokenInstruction::InitializePermanentDelegate { delegate };
2432 let packed = check.pack();
2433 let mut expect = vec![35u8];
2434 expect.extend_from_slice(&[11u8; 32]);
2435 assert_eq!(packed, expect);
2436 let unpacked = TokenInstruction::unpack(&expect).unwrap();
2437 assert_eq!(unpacked, check);
2438 }
2439
2440 macro_rules! test_instruction {
2441 ($a:ident($($b:tt)*)) => {
2442 let instruction_v3 = spl_token_interface::instruction::$a($($b)*).unwrap();
2443 let instruction_2022 = $a($($b)*).unwrap();
2444 assert_eq!(instruction_v3, instruction_2022);
2445 }
2446 }
2447
2448 #[test]
2449 fn test_v3_compatibility() {
2450 let token_program_id = spl_token_interface::id();
2451 let mint_pubkey = Pubkey::new_unique();
2452 let mint_authority_pubkey = Pubkey::new_unique();
2453 let freeze_authority_pubkey = Pubkey::new_unique();
2454 let decimals = 9u8;
2455
2456 let account_pubkey = Pubkey::new_unique();
2457 let owner_pubkey = Pubkey::new_unique();
2458
2459 let multisig_pubkey = Pubkey::new_unique();
2460 let signer_pubkeys_vec = vec![Pubkey::new_unique(); MAX_SIGNERS];
2461 let signer_pubkeys = signer_pubkeys_vec.iter().collect::<Vec<_>>();
2462 let m = 10u8;
2463
2464 let source_pubkey = Pubkey::new_unique();
2465 let destination_pubkey = Pubkey::new_unique();
2466 let authority_pubkey = Pubkey::new_unique();
2467 let amount = 1_000_000_000_000;
2468
2469 let delegate_pubkey = Pubkey::new_unique();
2470 let owned_pubkey = Pubkey::new_unique();
2471 let new_authority_pubkey = Pubkey::new_unique();
2472
2473 let ui_amount = "100000.00";
2474
2475 test_instruction!(initialize_mint(
2476 &token_program_id,
2477 &mint_pubkey,
2478 &mint_authority_pubkey,
2479 None,
2480 decimals,
2481 ));
2482 test_instruction!(initialize_mint2(
2483 &token_program_id,
2484 &mint_pubkey,
2485 &mint_authority_pubkey,
2486 Some(&freeze_authority_pubkey),
2487 decimals,
2488 ));
2489
2490 test_instruction!(initialize_account(
2491 &token_program_id,
2492 &account_pubkey,
2493 &mint_pubkey,
2494 &owner_pubkey,
2495 ));
2496 test_instruction!(initialize_account2(
2497 &token_program_id,
2498 &account_pubkey,
2499 &mint_pubkey,
2500 &owner_pubkey,
2501 ));
2502 test_instruction!(initialize_account3(
2503 &token_program_id,
2504 &account_pubkey,
2505 &mint_pubkey,
2506 &owner_pubkey,
2507 ));
2508 test_instruction!(initialize_multisig(
2509 &token_program_id,
2510 &multisig_pubkey,
2511 &signer_pubkeys,
2512 m,
2513 ));
2514 test_instruction!(initialize_multisig2(
2515 &token_program_id,
2516 &multisig_pubkey,
2517 &signer_pubkeys,
2518 m,
2519 ));
2520 #[allow(deprecated)]
2521 {
2522 test_instruction!(transfer(
2523 &token_program_id,
2524 &source_pubkey,
2525 &destination_pubkey,
2526 &authority_pubkey,
2527 &signer_pubkeys,
2528 amount
2529 ));
2530 }
2531 test_instruction!(transfer_checked(
2532 &token_program_id,
2533 &source_pubkey,
2534 &mint_pubkey,
2535 &destination_pubkey,
2536 &authority_pubkey,
2537 &signer_pubkeys,
2538 amount,
2539 decimals,
2540 ));
2541 test_instruction!(approve(
2542 &token_program_id,
2543 &source_pubkey,
2544 &delegate_pubkey,
2545 &owner_pubkey,
2546 &signer_pubkeys,
2547 amount
2548 ));
2549 test_instruction!(approve_checked(
2550 &token_program_id,
2551 &source_pubkey,
2552 &mint_pubkey,
2553 &delegate_pubkey,
2554 &owner_pubkey,
2555 &signer_pubkeys,
2556 amount,
2557 decimals
2558 ));
2559 test_instruction!(revoke(
2560 &token_program_id,
2561 &source_pubkey,
2562 &owner_pubkey,
2563 &signer_pubkeys,
2564 ));
2565
2566 {
2568 let instruction_v3 = spl_token_interface::instruction::set_authority(
2569 &token_program_id,
2570 &owned_pubkey,
2571 Some(&new_authority_pubkey),
2572 spl_token_interface::instruction::AuthorityType::AccountOwner,
2573 &owner_pubkey,
2574 &signer_pubkeys,
2575 )
2576 .unwrap();
2577 let instruction_2022 = set_authority(
2578 &token_program_id,
2579 &owned_pubkey,
2580 Some(&new_authority_pubkey),
2581 AuthorityType::AccountOwner,
2582 &owner_pubkey,
2583 &signer_pubkeys,
2584 )
2585 .unwrap();
2586 assert_eq!(instruction_v3, instruction_2022);
2587 }
2588
2589 test_instruction!(mint_to(
2590 &token_program_id,
2591 &mint_pubkey,
2592 &account_pubkey,
2593 &owner_pubkey,
2594 &signer_pubkeys,
2595 amount,
2596 ));
2597 test_instruction!(mint_to_checked(
2598 &token_program_id,
2599 &mint_pubkey,
2600 &account_pubkey,
2601 &owner_pubkey,
2602 &signer_pubkeys,
2603 amount,
2604 decimals,
2605 ));
2606 test_instruction!(burn(
2607 &token_program_id,
2608 &account_pubkey,
2609 &mint_pubkey,
2610 &authority_pubkey,
2611 &signer_pubkeys,
2612 amount,
2613 ));
2614 test_instruction!(burn_checked(
2615 &token_program_id,
2616 &account_pubkey,
2617 &mint_pubkey,
2618 &authority_pubkey,
2619 &signer_pubkeys,
2620 amount,
2621 decimals,
2622 ));
2623 test_instruction!(close_account(
2624 &token_program_id,
2625 &account_pubkey,
2626 &destination_pubkey,
2627 &owner_pubkey,
2628 &signer_pubkeys,
2629 ));
2630 test_instruction!(freeze_account(
2631 &token_program_id,
2632 &account_pubkey,
2633 &mint_pubkey,
2634 &freeze_authority_pubkey,
2635 &signer_pubkeys,
2636 ));
2637 test_instruction!(thaw_account(
2638 &token_program_id,
2639 &account_pubkey,
2640 &mint_pubkey,
2641 &freeze_authority_pubkey,
2642 &signer_pubkeys,
2643 ));
2644 test_instruction!(sync_native(&token_program_id, &account_pubkey,));
2645
2646 {
2648 let instruction_v3 = spl_token_interface::instruction::get_account_data_size(
2649 &token_program_id,
2650 &mint_pubkey,
2651 )
2652 .unwrap();
2653 let instruction_2022 =
2654 get_account_data_size(&token_program_id, &mint_pubkey, &[]).unwrap();
2655 assert_eq!(instruction_v3, instruction_2022);
2656 }
2657
2658 test_instruction!(initialize_immutable_owner(
2659 &token_program_id,
2660 &account_pubkey,
2661 ));
2662
2663 test_instruction!(amount_to_ui_amount(&token_program_id, &mint_pubkey, amount,));
2664
2665 test_instruction!(ui_amount_to_amount(
2666 &token_program_id,
2667 &mint_pubkey,
2668 ui_amount,
2669 ));
2670 }
2671
2672 proptest! {
2673 #![proptest_config(ProptestConfig::with_cases(1024))]
2674 #[test]
2675 fn test_instruction_unpack_proptest(
2676 data in prop::collection::vec(any::<u8>(), 0..255)
2677 ) {
2678 let _no_panic = TokenInstruction::unpack(&data);
2679 }
2680 }
2681}