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