1use crate::{check_program_account, error::TokenError};
4use gemachain_program::{
5 instruction::{AccountMeta, Instruction},
6 program_error::ProgramError,
7 program_option::COption,
8 pubkey::Pubkey,
9 sysvar,
10};
11use std::convert::TryInto;
12use std::mem::size_of;
13
14pub const MIN_SIGNERS: usize = 1;
16pub const MAX_SIGNERS: usize = 11;
18
19#[repr(C)]
21#[derive(Clone, Debug, PartialEq)]
22pub enum TokenInstruction {
23 InitializeMint {
38 decimals: u8,
40 mint_authority: Pubkey,
42 freeze_authority: COption<Pubkey>,
44 },
45 InitializeAccount,
64 InitializeMultisig {
84 m: u8,
87 },
88 Transfer {
106 amount: u64,
108 },
109 Approve {
125 amount: u64,
127 },
128 Revoke,
141 SetAuthority {
154 authority_type: AuthorityType,
156 new_authority: COption<Pubkey>,
158 },
159 MintTo {
175 amount: u64,
177 },
178 Burn {
194 amount: u64,
196 },
197 CloseAccount,
213 FreezeAccount,
229 ThawAccount,
244
245 TransferChecked {
269 amount: u64,
271 decimals: u8,
273 },
274 ApproveChecked {
296 amount: u64,
298 decimals: u8,
300 },
301 MintToChecked {
321 amount: u64,
323 decimals: u8,
325 },
326 BurnChecked {
347 amount: u64,
349 decimals: u8,
351 },
352 InitializeAccount2 {
363 owner: Pubkey,
365 },
366 SyncNative,
376 InitializeAccount3 {
383 owner: Pubkey,
385 },
386 InitializeMultisig2 {
394 m: u8,
397 },
398 InitializeMint2 {
405 decimals: u8,
407 mint_authority: Pubkey,
409 freeze_authority: COption<Pubkey>,
411 },
412}
413impl TokenInstruction {
414 pub fn unpack(input: &[u8]) -> Result<Self, ProgramError> {
416 use TokenError::InvalidInstruction;
417
418 let (&tag, rest) = input.split_first().ok_or(InvalidInstruction)?;
419 Ok(match tag {
420 0 => {
421 let (&decimals, rest) = rest.split_first().ok_or(InvalidInstruction)?;
422 let (mint_authority, rest) = Self::unpack_pubkey(rest)?;
423 let (freeze_authority, _rest) = Self::unpack_pubkey_option(rest)?;
424 Self::InitializeMint {
425 mint_authority,
426 freeze_authority,
427 decimals,
428 }
429 }
430 1 => Self::InitializeAccount,
431 2 => {
432 let &m = rest.get(0).ok_or(InvalidInstruction)?;
433 Self::InitializeMultisig { m }
434 }
435 3 | 4 | 7 | 8 => {
436 let amount = rest
437 .get(..8)
438 .and_then(|slice| slice.try_into().ok())
439 .map(u64::from_le_bytes)
440 .ok_or(InvalidInstruction)?;
441 match tag {
442 3 => Self::Transfer { amount },
443 4 => Self::Approve { amount },
444 7 => Self::MintTo { amount },
445 8 => Self::Burn { amount },
446 _ => unreachable!(),
447 }
448 }
449 5 => Self::Revoke,
450 6 => {
451 let (authority_type, rest) = rest
452 .split_first()
453 .ok_or_else(|| ProgramError::from(InvalidInstruction))
454 .and_then(|(&t, rest)| Ok((AuthorityType::from(t)?, rest)))?;
455 let (new_authority, _rest) = Self::unpack_pubkey_option(rest)?;
456
457 Self::SetAuthority {
458 authority_type,
459 new_authority,
460 }
461 }
462 9 => Self::CloseAccount,
463 10 => Self::FreezeAccount,
464 11 => Self::ThawAccount,
465 12 => {
466 let (amount, rest) = rest.split_at(8);
467 let amount = amount
468 .try_into()
469 .ok()
470 .map(u64::from_le_bytes)
471 .ok_or(InvalidInstruction)?;
472 let (&decimals, _rest) = rest.split_first().ok_or(InvalidInstruction)?;
473
474 Self::TransferChecked { amount, decimals }
475 }
476 13 => {
477 let (amount, rest) = rest.split_at(8);
478 let amount = amount
479 .try_into()
480 .ok()
481 .map(u64::from_le_bytes)
482 .ok_or(InvalidInstruction)?;
483 let (&decimals, _rest) = rest.split_first().ok_or(InvalidInstruction)?;
484
485 Self::ApproveChecked { amount, decimals }
486 }
487 14 => {
488 let (amount, rest) = rest.split_at(8);
489 let amount = amount
490 .try_into()
491 .ok()
492 .map(u64::from_le_bytes)
493 .ok_or(InvalidInstruction)?;
494 let (&decimals, _rest) = rest.split_first().ok_or(InvalidInstruction)?;
495
496 Self::MintToChecked { amount, decimals }
497 }
498 15 => {
499 let (amount, rest) = rest.split_at(8);
500 let amount = amount
501 .try_into()
502 .ok()
503 .map(u64::from_le_bytes)
504 .ok_or(InvalidInstruction)?;
505 let (&decimals, _rest) = rest.split_first().ok_or(InvalidInstruction)?;
506
507 Self::BurnChecked { amount, decimals }
508 }
509 16 => {
510 let (owner, _rest) = Self::unpack_pubkey(rest)?;
511 Self::InitializeAccount2 { owner }
512 }
513 17 => Self::SyncNative,
514 18 => {
515 let (owner, _rest) = Self::unpack_pubkey(rest)?;
516 Self::InitializeAccount3 { owner }
517 }
518 19 => {
519 let &m = rest.get(0).ok_or(InvalidInstruction)?;
520 Self::InitializeMultisig2 { m }
521 }
522 20 => {
523 let (&decimals, rest) = rest.split_first().ok_or(InvalidInstruction)?;
524 let (mint_authority, rest) = Self::unpack_pubkey(rest)?;
525 let (freeze_authority, _rest) = Self::unpack_pubkey_option(rest)?;
526 Self::InitializeMint2 {
527 mint_authority,
528 freeze_authority,
529 decimals,
530 }
531 }
532 _ => return Err(TokenError::InvalidInstruction.into()),
533 })
534 }
535
536 pub fn pack(&self) -> Vec<u8> {
538 let mut buf = Vec::with_capacity(size_of::<Self>());
539 match self {
540 &Self::InitializeMint {
541 ref mint_authority,
542 ref freeze_authority,
543 decimals,
544 } => {
545 buf.push(0);
546 buf.push(decimals);
547 buf.extend_from_slice(mint_authority.as_ref());
548 Self::pack_pubkey_option(freeze_authority, &mut buf);
549 }
550 Self::InitializeAccount => buf.push(1),
551 &Self::InitializeMultisig { m } => {
552 buf.push(2);
553 buf.push(m);
554 }
555 &Self::Transfer { amount } => {
556 buf.push(3);
557 buf.extend_from_slice(&amount.to_le_bytes());
558 }
559 &Self::Approve { amount } => {
560 buf.push(4);
561 buf.extend_from_slice(&amount.to_le_bytes());
562 }
563 &Self::MintTo { amount } => {
564 buf.push(7);
565 buf.extend_from_slice(&amount.to_le_bytes());
566 }
567 &Self::Burn { amount } => {
568 buf.push(8);
569 buf.extend_from_slice(&amount.to_le_bytes());
570 }
571 Self::Revoke => buf.push(5),
572 Self::SetAuthority {
573 authority_type,
574 ref new_authority,
575 } => {
576 buf.push(6);
577 buf.push(authority_type.into());
578 Self::pack_pubkey_option(new_authority, &mut buf);
579 }
580 Self::CloseAccount => buf.push(9),
581 Self::FreezeAccount => buf.push(10),
582 Self::ThawAccount => buf.push(11),
583 &Self::TransferChecked { amount, decimals } => {
584 buf.push(12);
585 buf.extend_from_slice(&amount.to_le_bytes());
586 buf.push(decimals);
587 }
588 &Self::ApproveChecked { amount, decimals } => {
589 buf.push(13);
590 buf.extend_from_slice(&amount.to_le_bytes());
591 buf.push(decimals);
592 }
593 &Self::MintToChecked { amount, decimals } => {
594 buf.push(14);
595 buf.extend_from_slice(&amount.to_le_bytes());
596 buf.push(decimals);
597 }
598 &Self::BurnChecked { amount, decimals } => {
599 buf.push(15);
600 buf.extend_from_slice(&amount.to_le_bytes());
601 buf.push(decimals);
602 }
603 &Self::InitializeAccount2 { owner } => {
604 buf.push(16);
605 buf.extend_from_slice(owner.as_ref());
606 }
607 &Self::SyncNative => {
608 buf.push(17);
609 }
610 &Self::InitializeAccount3 { owner } => {
611 buf.push(18);
612 buf.extend_from_slice(owner.as_ref());
613 }
614 &Self::InitializeMultisig2 { m } => {
615 buf.push(19);
616 buf.push(m);
617 }
618 &Self::InitializeMint2 {
619 ref mint_authority,
620 ref freeze_authority,
621 decimals,
622 } => {
623 buf.push(20);
624 buf.push(decimals);
625 buf.extend_from_slice(mint_authority.as_ref());
626 Self::pack_pubkey_option(freeze_authority, &mut buf);
627 }
628 };
629 buf
630 }
631
632 fn unpack_pubkey(input: &[u8]) -> Result<(Pubkey, &[u8]), ProgramError> {
633 if input.len() >= 32 {
634 let (key, rest) = input.split_at(32);
635 let pk = Pubkey::new(key);
636 Ok((pk, rest))
637 } else {
638 Err(TokenError::InvalidInstruction.into())
639 }
640 }
641
642 fn unpack_pubkey_option(input: &[u8]) -> Result<(COption<Pubkey>, &[u8]), ProgramError> {
643 match input.split_first() {
644 Option::Some((&0, rest)) => Ok((COption::None, rest)),
645 Option::Some((&1, rest)) if rest.len() >= 32 => {
646 let (key, rest) = rest.split_at(32);
647 let pk = Pubkey::new(key);
648 Ok((COption::Some(pk), rest))
649 }
650 _ => Err(TokenError::InvalidInstruction.into()),
651 }
652 }
653
654 fn pack_pubkey_option(value: &COption<Pubkey>, buf: &mut Vec<u8>) {
655 match *value {
656 COption::Some(ref key) => {
657 buf.push(1);
658 buf.extend_from_slice(&key.to_bytes());
659 }
660 COption::None => buf.push(0),
661 }
662 }
663}
664
665#[repr(u8)]
667#[derive(Clone, Debug, PartialEq)]
668pub enum AuthorityType {
669 MintTokens,
671 FreezeAccount,
673 AccountOwner,
675 CloseAccount,
677}
678
679impl AuthorityType {
680 fn into(&self) -> u8 {
681 match self {
682 AuthorityType::MintTokens => 0,
683 AuthorityType::FreezeAccount => 1,
684 AuthorityType::AccountOwner => 2,
685 AuthorityType::CloseAccount => 3,
686 }
687 }
688
689 fn from(index: u8) -> Result<Self, ProgramError> {
690 match index {
691 0 => Ok(AuthorityType::MintTokens),
692 1 => Ok(AuthorityType::FreezeAccount),
693 2 => Ok(AuthorityType::AccountOwner),
694 3 => Ok(AuthorityType::CloseAccount),
695 _ => Err(TokenError::InvalidInstruction.into()),
696 }
697 }
698}
699
700pub fn initialize_mint(
702 token_program_id: &Pubkey,
703 mint_pubkey: &Pubkey,
704 mint_authority_pubkey: &Pubkey,
705 freeze_authority_pubkey: Option<&Pubkey>,
706 decimals: u8,
707) -> Result<Instruction, ProgramError> {
708 check_program_account(token_program_id)?;
709 let freeze_authority = freeze_authority_pubkey.cloned().into();
710 let data = TokenInstruction::InitializeMint {
711 mint_authority: *mint_authority_pubkey,
712 freeze_authority,
713 decimals,
714 }
715 .pack();
716
717 let accounts = vec![
718 AccountMeta::new(*mint_pubkey, false),
719 AccountMeta::new_readonly(sysvar::rent::id(), false),
720 ];
721
722 Ok(Instruction {
723 program_id: *token_program_id,
724 accounts,
725 data,
726 })
727}
728
729pub fn initialize_mint2(
731 token_program_id: &Pubkey,
732 mint_pubkey: &Pubkey,
733 mint_authority_pubkey: &Pubkey,
734 freeze_authority_pubkey: Option<&Pubkey>,
735 decimals: u8,
736) -> Result<Instruction, ProgramError> {
737 check_program_account(token_program_id)?;
738 let freeze_authority = freeze_authority_pubkey.cloned().into();
739 let data = TokenInstruction::InitializeMint2 {
740 mint_authority: *mint_authority_pubkey,
741 freeze_authority,
742 decimals,
743 }
744 .pack();
745
746 let accounts = vec![AccountMeta::new(*mint_pubkey, false)];
747
748 Ok(Instruction {
749 program_id: *token_program_id,
750 accounts,
751 data,
752 })
753}
754
755pub fn initialize_account(
757 token_program_id: &Pubkey,
758 account_pubkey: &Pubkey,
759 mint_pubkey: &Pubkey,
760 owner_pubkey: &Pubkey,
761) -> Result<Instruction, ProgramError> {
762 check_program_account(token_program_id)?;
763 let data = TokenInstruction::InitializeAccount.pack();
764
765 let accounts = vec![
766 AccountMeta::new(*account_pubkey, false),
767 AccountMeta::new_readonly(*mint_pubkey, false),
768 AccountMeta::new_readonly(*owner_pubkey, false),
769 AccountMeta::new_readonly(sysvar::rent::id(), false),
770 ];
771
772 Ok(Instruction {
773 program_id: *token_program_id,
774 accounts,
775 data,
776 })
777}
778
779pub fn initialize_account2(
781 token_program_id: &Pubkey,
782 account_pubkey: &Pubkey,
783 mint_pubkey: &Pubkey,
784 owner_pubkey: &Pubkey,
785) -> Result<Instruction, ProgramError> {
786 check_program_account(token_program_id)?;
787 let data = TokenInstruction::InitializeAccount2 {
788 owner: *owner_pubkey,
789 }
790 .pack();
791
792 let accounts = vec![
793 AccountMeta::new(*account_pubkey, false),
794 AccountMeta::new_readonly(*mint_pubkey, false),
795 AccountMeta::new_readonly(sysvar::rent::id(), false),
796 ];
797
798 Ok(Instruction {
799 program_id: *token_program_id,
800 accounts,
801 data,
802 })
803}
804
805pub fn initialize_account3(
807 token_program_id: &Pubkey,
808 account_pubkey: &Pubkey,
809 mint_pubkey: &Pubkey,
810 owner_pubkey: &Pubkey,
811) -> Result<Instruction, ProgramError> {
812 check_program_account(token_program_id)?;
813 let data = TokenInstruction::InitializeAccount3 {
814 owner: *owner_pubkey,
815 }
816 .pack();
817
818 let accounts = vec![
819 AccountMeta::new(*account_pubkey, false),
820 AccountMeta::new_readonly(*mint_pubkey, false),
821 ];
822
823 Ok(Instruction {
824 program_id: *token_program_id,
825 accounts,
826 data,
827 })
828}
829
830pub fn initialize_multisig(
832 token_program_id: &Pubkey,
833 multisig_pubkey: &Pubkey,
834 signer_pubkeys: &[&Pubkey],
835 m: u8,
836) -> Result<Instruction, ProgramError> {
837 check_program_account(token_program_id)?;
838 if !is_valid_signer_index(m as usize)
839 || !is_valid_signer_index(signer_pubkeys.len())
840 || m as usize > signer_pubkeys.len()
841 {
842 return Err(ProgramError::MissingRequiredSignature);
843 }
844 let data = TokenInstruction::InitializeMultisig { m }.pack();
845
846 let mut accounts = Vec::with_capacity(1 + 1 + signer_pubkeys.len());
847 accounts.push(AccountMeta::new(*multisig_pubkey, false));
848 accounts.push(AccountMeta::new_readonly(sysvar::rent::id(), false));
849 for signer_pubkey in signer_pubkeys.iter() {
850 accounts.push(AccountMeta::new_readonly(**signer_pubkey, false));
851 }
852
853 Ok(Instruction {
854 program_id: *token_program_id,
855 accounts,
856 data,
857 })
858}
859
860pub fn initialize_multisig2(
862 token_program_id: &Pubkey,
863 multisig_pubkey: &Pubkey,
864 signer_pubkeys: &[&Pubkey],
865 m: u8,
866) -> Result<Instruction, ProgramError> {
867 check_program_account(token_program_id)?;
868 if !is_valid_signer_index(m as usize)
869 || !is_valid_signer_index(signer_pubkeys.len())
870 || m as usize > signer_pubkeys.len()
871 {
872 return Err(ProgramError::MissingRequiredSignature);
873 }
874 let data = TokenInstruction::InitializeMultisig2 { m }.pack();
875
876 let mut accounts = Vec::with_capacity(1 + 1 + signer_pubkeys.len());
877 accounts.push(AccountMeta::new(*multisig_pubkey, false));
878 for signer_pubkey in signer_pubkeys.iter() {
879 accounts.push(AccountMeta::new_readonly(**signer_pubkey, false));
880 }
881
882 Ok(Instruction {
883 program_id: *token_program_id,
884 accounts,
885 data,
886 })
887}
888
889pub fn transfer(
891 token_program_id: &Pubkey,
892 source_pubkey: &Pubkey,
893 destination_pubkey: &Pubkey,
894 authority_pubkey: &Pubkey,
895 signer_pubkeys: &[&Pubkey],
896 amount: u64,
897) -> Result<Instruction, ProgramError> {
898 check_program_account(token_program_id)?;
899 let data = TokenInstruction::Transfer { amount }.pack();
900
901 let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
902 accounts.push(AccountMeta::new(*source_pubkey, false));
903 accounts.push(AccountMeta::new(*destination_pubkey, false));
904 accounts.push(AccountMeta::new_readonly(
905 *authority_pubkey,
906 signer_pubkeys.is_empty(),
907 ));
908 for signer_pubkey in signer_pubkeys.iter() {
909 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
910 }
911
912 Ok(Instruction {
913 program_id: *token_program_id,
914 accounts,
915 data,
916 })
917}
918
919pub fn approve(
921 token_program_id: &Pubkey,
922 source_pubkey: &Pubkey,
923 delegate_pubkey: &Pubkey,
924 owner_pubkey: &Pubkey,
925 signer_pubkeys: &[&Pubkey],
926 amount: u64,
927) -> Result<Instruction, ProgramError> {
928 check_program_account(token_program_id)?;
929 let data = TokenInstruction::Approve { amount }.pack();
930
931 let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
932 accounts.push(AccountMeta::new(*source_pubkey, false));
933 accounts.push(AccountMeta::new_readonly(*delegate_pubkey, false));
934 accounts.push(AccountMeta::new_readonly(
935 *owner_pubkey,
936 signer_pubkeys.is_empty(),
937 ));
938 for signer_pubkey in signer_pubkeys.iter() {
939 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
940 }
941
942 Ok(Instruction {
943 program_id: *token_program_id,
944 accounts,
945 data,
946 })
947}
948
949pub fn revoke(
951 token_program_id: &Pubkey,
952 source_pubkey: &Pubkey,
953 owner_pubkey: &Pubkey,
954 signer_pubkeys: &[&Pubkey],
955) -> Result<Instruction, ProgramError> {
956 check_program_account(token_program_id)?;
957 let data = TokenInstruction::Revoke.pack();
958
959 let mut accounts = Vec::with_capacity(2 + signer_pubkeys.len());
960 accounts.push(AccountMeta::new(*source_pubkey, false));
961 accounts.push(AccountMeta::new_readonly(
962 *owner_pubkey,
963 signer_pubkeys.is_empty(),
964 ));
965 for signer_pubkey in signer_pubkeys.iter() {
966 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
967 }
968
969 Ok(Instruction {
970 program_id: *token_program_id,
971 accounts,
972 data,
973 })
974}
975
976pub fn set_authority(
978 token_program_id: &Pubkey,
979 owned_pubkey: &Pubkey,
980 new_authority_pubkey: Option<&Pubkey>,
981 authority_type: AuthorityType,
982 owner_pubkey: &Pubkey,
983 signer_pubkeys: &[&Pubkey],
984) -> Result<Instruction, ProgramError> {
985 check_program_account(token_program_id)?;
986 let new_authority = new_authority_pubkey.cloned().into();
987 let data = TokenInstruction::SetAuthority {
988 authority_type,
989 new_authority,
990 }
991 .pack();
992
993 let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
994 accounts.push(AccountMeta::new(*owned_pubkey, false));
995 accounts.push(AccountMeta::new_readonly(
996 *owner_pubkey,
997 signer_pubkeys.is_empty(),
998 ));
999 for signer_pubkey in signer_pubkeys.iter() {
1000 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1001 }
1002
1003 Ok(Instruction {
1004 program_id: *token_program_id,
1005 accounts,
1006 data,
1007 })
1008}
1009
1010pub fn mint_to(
1012 token_program_id: &Pubkey,
1013 mint_pubkey: &Pubkey,
1014 account_pubkey: &Pubkey,
1015 owner_pubkey: &Pubkey,
1016 signer_pubkeys: &[&Pubkey],
1017 amount: u64,
1018) -> Result<Instruction, ProgramError> {
1019 check_program_account(token_program_id)?;
1020 let data = TokenInstruction::MintTo { amount }.pack();
1021
1022 let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1023 accounts.push(AccountMeta::new(*mint_pubkey, false));
1024 accounts.push(AccountMeta::new(*account_pubkey, false));
1025 accounts.push(AccountMeta::new_readonly(
1026 *owner_pubkey,
1027 signer_pubkeys.is_empty(),
1028 ));
1029 for signer_pubkey in signer_pubkeys.iter() {
1030 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1031 }
1032
1033 Ok(Instruction {
1034 program_id: *token_program_id,
1035 accounts,
1036 data,
1037 })
1038}
1039
1040pub fn burn(
1042 token_program_id: &Pubkey,
1043 account_pubkey: &Pubkey,
1044 mint_pubkey: &Pubkey,
1045 authority_pubkey: &Pubkey,
1046 signer_pubkeys: &[&Pubkey],
1047 amount: u64,
1048) -> Result<Instruction, ProgramError> {
1049 check_program_account(token_program_id)?;
1050 let data = TokenInstruction::Burn { amount }.pack();
1051
1052 let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1053 accounts.push(AccountMeta::new(*account_pubkey, false));
1054 accounts.push(AccountMeta::new(*mint_pubkey, false));
1055 accounts.push(AccountMeta::new_readonly(
1056 *authority_pubkey,
1057 signer_pubkeys.is_empty(),
1058 ));
1059 for signer_pubkey in signer_pubkeys.iter() {
1060 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1061 }
1062
1063 Ok(Instruction {
1064 program_id: *token_program_id,
1065 accounts,
1066 data,
1067 })
1068}
1069
1070pub fn close_account(
1072 token_program_id: &Pubkey,
1073 account_pubkey: &Pubkey,
1074 destination_pubkey: &Pubkey,
1075 owner_pubkey: &Pubkey,
1076 signer_pubkeys: &[&Pubkey],
1077) -> Result<Instruction, ProgramError> {
1078 check_program_account(token_program_id)?;
1079 let data = TokenInstruction::CloseAccount.pack();
1080
1081 let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1082 accounts.push(AccountMeta::new(*account_pubkey, false));
1083 accounts.push(AccountMeta::new(*destination_pubkey, false));
1084 accounts.push(AccountMeta::new_readonly(
1085 *owner_pubkey,
1086 signer_pubkeys.is_empty(),
1087 ));
1088 for signer_pubkey in signer_pubkeys.iter() {
1089 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1090 }
1091
1092 Ok(Instruction {
1093 program_id: *token_program_id,
1094 accounts,
1095 data,
1096 })
1097}
1098
1099pub fn freeze_account(
1101 token_program_id: &Pubkey,
1102 account_pubkey: &Pubkey,
1103 mint_pubkey: &Pubkey,
1104 owner_pubkey: &Pubkey,
1105 signer_pubkeys: &[&Pubkey],
1106) -> Result<Instruction, ProgramError> {
1107 check_program_account(token_program_id)?;
1108 let data = TokenInstruction::FreezeAccount.pack();
1109
1110 let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1111 accounts.push(AccountMeta::new(*account_pubkey, false));
1112 accounts.push(AccountMeta::new_readonly(*mint_pubkey, false));
1113 accounts.push(AccountMeta::new_readonly(
1114 *owner_pubkey,
1115 signer_pubkeys.is_empty(),
1116 ));
1117 for signer_pubkey in signer_pubkeys.iter() {
1118 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1119 }
1120
1121 Ok(Instruction {
1122 program_id: *token_program_id,
1123 accounts,
1124 data,
1125 })
1126}
1127
1128pub fn thaw_account(
1130 token_program_id: &Pubkey,
1131 account_pubkey: &Pubkey,
1132 mint_pubkey: &Pubkey,
1133 owner_pubkey: &Pubkey,
1134 signer_pubkeys: &[&Pubkey],
1135) -> Result<Instruction, ProgramError> {
1136 check_program_account(token_program_id)?;
1137 let data = TokenInstruction::ThawAccount.pack();
1138
1139 let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1140 accounts.push(AccountMeta::new(*account_pubkey, false));
1141 accounts.push(AccountMeta::new_readonly(*mint_pubkey, false));
1142 accounts.push(AccountMeta::new_readonly(
1143 *owner_pubkey,
1144 signer_pubkeys.is_empty(),
1145 ));
1146 for signer_pubkey in signer_pubkeys.iter() {
1147 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1148 }
1149
1150 Ok(Instruction {
1151 program_id: *token_program_id,
1152 accounts,
1153 data,
1154 })
1155}
1156
1157#[allow(clippy::too_many_arguments)]
1159pub fn transfer_checked(
1160 token_program_id: &Pubkey,
1161 source_pubkey: &Pubkey,
1162 mint_pubkey: &Pubkey,
1163 destination_pubkey: &Pubkey,
1164 authority_pubkey: &Pubkey,
1165 signer_pubkeys: &[&Pubkey],
1166 amount: u64,
1167 decimals: u8,
1168) -> Result<Instruction, ProgramError> {
1169 check_program_account(token_program_id)?;
1170 let data = TokenInstruction::TransferChecked { amount, decimals }.pack();
1171
1172 let mut accounts = Vec::with_capacity(4 + signer_pubkeys.len());
1173 accounts.push(AccountMeta::new(*source_pubkey, false));
1174 accounts.push(AccountMeta::new_readonly(*mint_pubkey, false));
1175 accounts.push(AccountMeta::new(*destination_pubkey, false));
1176 accounts.push(AccountMeta::new_readonly(
1177 *authority_pubkey,
1178 signer_pubkeys.is_empty(),
1179 ));
1180 for signer_pubkey in signer_pubkeys.iter() {
1181 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1182 }
1183
1184 Ok(Instruction {
1185 program_id: *token_program_id,
1186 accounts,
1187 data,
1188 })
1189}
1190
1191#[allow(clippy::too_many_arguments)]
1193pub fn approve_checked(
1194 token_program_id: &Pubkey,
1195 source_pubkey: &Pubkey,
1196 mint_pubkey: &Pubkey,
1197 delegate_pubkey: &Pubkey,
1198 owner_pubkey: &Pubkey,
1199 signer_pubkeys: &[&Pubkey],
1200 amount: u64,
1201 decimals: u8,
1202) -> Result<Instruction, ProgramError> {
1203 check_program_account(token_program_id)?;
1204 let data = TokenInstruction::ApproveChecked { amount, decimals }.pack();
1205
1206 let mut accounts = Vec::with_capacity(4 + signer_pubkeys.len());
1207 accounts.push(AccountMeta::new(*source_pubkey, false));
1208 accounts.push(AccountMeta::new_readonly(*mint_pubkey, false));
1209 accounts.push(AccountMeta::new_readonly(*delegate_pubkey, false));
1210 accounts.push(AccountMeta::new_readonly(
1211 *owner_pubkey,
1212 signer_pubkeys.is_empty(),
1213 ));
1214 for signer_pubkey in signer_pubkeys.iter() {
1215 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1216 }
1217
1218 Ok(Instruction {
1219 program_id: *token_program_id,
1220 accounts,
1221 data,
1222 })
1223}
1224
1225pub fn mint_to_checked(
1227 token_program_id: &Pubkey,
1228 mint_pubkey: &Pubkey,
1229 account_pubkey: &Pubkey,
1230 owner_pubkey: &Pubkey,
1231 signer_pubkeys: &[&Pubkey],
1232 amount: u64,
1233 decimals: u8,
1234) -> Result<Instruction, ProgramError> {
1235 check_program_account(token_program_id)?;
1236 let data = TokenInstruction::MintToChecked { amount, decimals }.pack();
1237
1238 let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1239 accounts.push(AccountMeta::new(*mint_pubkey, false));
1240 accounts.push(AccountMeta::new(*account_pubkey, false));
1241 accounts.push(AccountMeta::new_readonly(
1242 *owner_pubkey,
1243 signer_pubkeys.is_empty(),
1244 ));
1245 for signer_pubkey in signer_pubkeys.iter() {
1246 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1247 }
1248
1249 Ok(Instruction {
1250 program_id: *token_program_id,
1251 accounts,
1252 data,
1253 })
1254}
1255
1256pub fn burn_checked(
1258 token_program_id: &Pubkey,
1259 account_pubkey: &Pubkey,
1260 mint_pubkey: &Pubkey,
1261 authority_pubkey: &Pubkey,
1262 signer_pubkeys: &[&Pubkey],
1263 amount: u64,
1264 decimals: u8,
1265) -> Result<Instruction, ProgramError> {
1266 check_program_account(token_program_id)?;
1267 let data = TokenInstruction::BurnChecked { amount, decimals }.pack();
1268
1269 let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1270 accounts.push(AccountMeta::new(*account_pubkey, false));
1271 accounts.push(AccountMeta::new(*mint_pubkey, false));
1272 accounts.push(AccountMeta::new_readonly(
1273 *authority_pubkey,
1274 signer_pubkeys.is_empty(),
1275 ));
1276 for signer_pubkey in signer_pubkeys.iter() {
1277 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1278 }
1279
1280 Ok(Instruction {
1281 program_id: *token_program_id,
1282 accounts,
1283 data,
1284 })
1285}
1286
1287pub fn sync_native(
1289 token_program_id: &Pubkey,
1290 account_pubkey: &Pubkey,
1291) -> Result<Instruction, ProgramError> {
1292 check_program_account(token_program_id)?;
1293
1294 Ok(Instruction {
1295 program_id: *token_program_id,
1296 accounts: vec![AccountMeta::new(*account_pubkey, false)],
1297 data: TokenInstruction::SyncNative.pack(),
1298 })
1299}
1300
1301pub fn is_valid_signer_index(index: usize) -> bool {
1303 (MIN_SIGNERS..=MAX_SIGNERS).contains(&index)
1304}
1305
1306#[cfg(test)]
1307mod test {
1308 use super::*;
1309
1310 #[test]
1311 fn test_instruction_packing() {
1312 let check = TokenInstruction::InitializeMint {
1313 decimals: 2,
1314 mint_authority: Pubkey::new(&[1u8; 32]),
1315 freeze_authority: COption::None,
1316 };
1317 let packed = check.pack();
1318 let mut expect = Vec::from([0u8, 2]);
1319 expect.extend_from_slice(&[1u8; 32]);
1320 expect.extend_from_slice(&[0]);
1321 assert_eq!(packed, expect);
1322 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1323 assert_eq!(unpacked, check);
1324
1325 let check = TokenInstruction::InitializeMint {
1326 decimals: 2,
1327 mint_authority: Pubkey::new(&[2u8; 32]),
1328 freeze_authority: COption::Some(Pubkey::new(&[3u8; 32])),
1329 };
1330 let packed = check.pack();
1331 let mut expect = vec![0u8, 2];
1332 expect.extend_from_slice(&[2u8; 32]);
1333 expect.extend_from_slice(&[1]);
1334 expect.extend_from_slice(&[3u8; 32]);
1335 assert_eq!(packed, expect);
1336 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1337 assert_eq!(unpacked, check);
1338
1339 let check = TokenInstruction::InitializeAccount;
1340 let packed = check.pack();
1341 let expect = Vec::from([1u8]);
1342 assert_eq!(packed, expect);
1343 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1344 assert_eq!(unpacked, check);
1345
1346 let check = TokenInstruction::InitializeMultisig { m: 1 };
1347 let packed = check.pack();
1348 let expect = Vec::from([2u8, 1]);
1349 assert_eq!(packed, expect);
1350 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1351 assert_eq!(unpacked, check);
1352
1353 let check = TokenInstruction::Transfer { amount: 1 };
1354 let packed = check.pack();
1355 let expect = Vec::from([3u8, 1, 0, 0, 0, 0, 0, 0, 0]);
1356 assert_eq!(packed, expect);
1357 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1358 assert_eq!(unpacked, check);
1359
1360 let check = TokenInstruction::Approve { amount: 1 };
1361 let packed = check.pack();
1362 let expect = Vec::from([4u8, 1, 0, 0, 0, 0, 0, 0, 0]);
1363 assert_eq!(packed, expect);
1364 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1365 assert_eq!(unpacked, check);
1366
1367 let check = TokenInstruction::Revoke;
1368 let packed = check.pack();
1369 let expect = Vec::from([5u8]);
1370 assert_eq!(packed, expect);
1371 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1372 assert_eq!(unpacked, check);
1373
1374 let check = TokenInstruction::SetAuthority {
1375 authority_type: AuthorityType::FreezeAccount,
1376 new_authority: COption::Some(Pubkey::new(&[4u8; 32])),
1377 };
1378 let packed = check.pack();
1379 let mut expect = Vec::from([6u8, 1]);
1380 expect.extend_from_slice(&[1]);
1381 expect.extend_from_slice(&[4u8; 32]);
1382 assert_eq!(packed, expect);
1383 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1384 assert_eq!(unpacked, check);
1385
1386 let check = TokenInstruction::MintTo { amount: 1 };
1387 let packed = check.pack();
1388 let expect = Vec::from([7u8, 1, 0, 0, 0, 0, 0, 0, 0]);
1389 assert_eq!(packed, expect);
1390 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1391 assert_eq!(unpacked, check);
1392
1393 let check = TokenInstruction::Burn { amount: 1 };
1394 let packed = check.pack();
1395 let expect = Vec::from([8u8, 1, 0, 0, 0, 0, 0, 0, 0]);
1396 assert_eq!(packed, expect);
1397 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1398 assert_eq!(unpacked, check);
1399
1400 let check = TokenInstruction::CloseAccount;
1401 let packed = check.pack();
1402 let expect = Vec::from([9u8]);
1403 assert_eq!(packed, expect);
1404 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1405 assert_eq!(unpacked, check);
1406
1407 let check = TokenInstruction::FreezeAccount;
1408 let packed = check.pack();
1409 let expect = Vec::from([10u8]);
1410 assert_eq!(packed, expect);
1411 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1412 assert_eq!(unpacked, check);
1413
1414 let check = TokenInstruction::ThawAccount;
1415 let packed = check.pack();
1416 let expect = Vec::from([11u8]);
1417 assert_eq!(packed, expect);
1418 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1419 assert_eq!(unpacked, check);
1420
1421 let check = TokenInstruction::TransferChecked {
1422 amount: 1,
1423 decimals: 2,
1424 };
1425 let packed = check.pack();
1426 let expect = Vec::from([12u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]);
1427 assert_eq!(packed, expect);
1428 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1429 assert_eq!(unpacked, check);
1430
1431 let check = TokenInstruction::ApproveChecked {
1432 amount: 1,
1433 decimals: 2,
1434 };
1435 let packed = check.pack();
1436 let expect = Vec::from([13u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]);
1437 assert_eq!(packed, expect);
1438 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1439 assert_eq!(unpacked, check);
1440
1441 let check = TokenInstruction::MintToChecked {
1442 amount: 1,
1443 decimals: 2,
1444 };
1445 let packed = check.pack();
1446 let expect = Vec::from([14u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]);
1447 assert_eq!(packed, expect);
1448 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1449 assert_eq!(unpacked, check);
1450
1451 let check = TokenInstruction::BurnChecked {
1452 amount: 1,
1453 decimals: 2,
1454 };
1455 let packed = check.pack();
1456 let expect = Vec::from([15u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]);
1457 assert_eq!(packed, expect);
1458 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1459 assert_eq!(unpacked, check);
1460
1461 let check = TokenInstruction::InitializeAccount2 {
1462 owner: Pubkey::new(&[2u8; 32]),
1463 };
1464 let packed = check.pack();
1465 let mut expect = vec![16u8];
1466 expect.extend_from_slice(&[2u8; 32]);
1467 assert_eq!(packed, expect);
1468 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1469 assert_eq!(unpacked, check);
1470
1471 let check = TokenInstruction::SyncNative;
1472 let packed = check.pack();
1473 let expect = vec![17u8];
1474 assert_eq!(packed, expect);
1475 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1476 assert_eq!(unpacked, check);
1477
1478 let check = TokenInstruction::InitializeAccount3 {
1479 owner: Pubkey::new(&[2u8; 32]),
1480 };
1481 let packed = check.pack();
1482 let mut expect = vec![18u8];
1483 expect.extend_from_slice(&[2u8; 32]);
1484 assert_eq!(packed, expect);
1485 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1486 assert_eq!(unpacked, check);
1487
1488 let check = TokenInstruction::InitializeMultisig2 { m: 1 };
1489 let packed = check.pack();
1490 let expect = Vec::from([19u8, 1]);
1491 assert_eq!(packed, expect);
1492 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1493 assert_eq!(unpacked, check);
1494
1495 let check = TokenInstruction::InitializeMint2 {
1496 decimals: 2,
1497 mint_authority: Pubkey::new(&[1u8; 32]),
1498 freeze_authority: COption::None,
1499 };
1500 let packed = check.pack();
1501 let mut expect = Vec::from([20u8, 2]);
1502 expect.extend_from_slice(&[1u8; 32]);
1503 expect.extend_from_slice(&[0]);
1504 assert_eq!(packed, expect);
1505 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1506 assert_eq!(unpacked, check);
1507
1508 let check = TokenInstruction::InitializeMint2 {
1509 decimals: 2,
1510 mint_authority: Pubkey::new(&[2u8; 32]),
1511 freeze_authority: COption::Some(Pubkey::new(&[3u8; 32])),
1512 };
1513 let packed = check.pack();
1514 let mut expect = vec![20u8, 2];
1515 expect.extend_from_slice(&[2u8; 32]);
1516 expect.extend_from_slice(&[1]);
1517 expect.extend_from_slice(&[3u8; 32]);
1518 assert_eq!(packed, expect);
1519 let unpacked = TokenInstruction::unpack(&expect).unwrap();
1520 assert_eq!(unpacked, check);
1521 }
1522}