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