Skip to content

Commit b3cbe49

Browse files
committed
Add tests
1 parent c16f20c commit b3cbe49

File tree

1 file changed

+375
-0
lines changed

1 file changed

+375
-0
lines changed

p-token/tests/withdraw_excess_lamports.rs

+375
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use {
88
solana_program_test::{tokio, BanksClientError, ProgramTest},
99
solana_sdk::{
1010
instruction::InstructionError,
11+
program_pack::Pack,
1112
pubkey::Pubkey,
1213
signature::{Keypair, Signer},
1314
system_instruction,
@@ -758,3 +759,377 @@ async fn fail_withdraw_excess_lamports_from_multisig_missing_signer(token_progra
758759
))
759760
);
760761
}
762+
763+
#[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")]
764+
#[tokio::test]
765+
async fn withdraw_excess_lamports_from_mint_with_no_authority(token_program: Pubkey) {
766+
let context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None)
767+
.start_with_context()
768+
.await;
769+
770+
let excess_lamports = 4_000_000_000_000;
771+
772+
// Given a mint authority, freeze authority and an account keypair.
773+
774+
let mint_authority = Keypair::new();
775+
let freeze_authority = Pubkey::new_unique();
776+
let mint_account = Keypair::new();
777+
let account_pubkey = mint_account.pubkey();
778+
779+
let account_size = size_of::<Mint>();
780+
let rent = context.banks_client.get_rent().await.unwrap();
781+
782+
let mut initialize_ix = spl_token::instruction::initialize_mint(
783+
&spl_token::ID,
784+
&mint_account.pubkey(),
785+
&mint_authority.pubkey(),
786+
Some(&freeze_authority),
787+
0,
788+
)
789+
.unwrap();
790+
// Switches the program id to the token program.
791+
initialize_ix.program_id = token_program;
792+
793+
// And we initialize a mint account with excess lamports.
794+
795+
let instructions = vec![
796+
system_instruction::create_account(
797+
&context.payer.pubkey(),
798+
&mint_account.pubkey(),
799+
rent.minimum_balance(account_size) + excess_lamports,
800+
account_size as u64,
801+
&token_program,
802+
),
803+
initialize_ix,
804+
];
805+
806+
let tx = Transaction::new_signed_with_payer(
807+
&instructions,
808+
Some(&context.payer.pubkey()),
809+
&[&context.payer, &mint_account],
810+
context.last_blockhash,
811+
);
812+
context.banks_client.process_transaction(tx).await.unwrap();
813+
814+
let account = context
815+
.banks_client
816+
.get_account(mint_account.pubkey())
817+
.await
818+
.unwrap();
819+
820+
assert!(account.is_some());
821+
822+
let account = account.unwrap();
823+
assert_eq!(
824+
account.lamports,
825+
rent.minimum_balance(account_size) + excess_lamports
826+
);
827+
828+
// And we remove the mint authority.
829+
830+
let mut set_authority_ix = spl_token::instruction::set_authority(
831+
&spl_token::ID,
832+
&mint_account.pubkey(),
833+
None,
834+
spl_token::instruction::AuthorityType::MintTokens,
835+
&mint_authority.pubkey(),
836+
&[&mint_authority.pubkey()],
837+
)
838+
.unwrap();
839+
// Switches the program id to the token program.
840+
set_authority_ix.program_id = token_program;
841+
842+
let tx = Transaction::new_signed_with_payer(
843+
&[set_authority_ix],
844+
Some(&context.payer.pubkey()),
845+
&[&context.payer, &mint_authority],
846+
context.last_blockhash,
847+
);
848+
context.banks_client.process_transaction(tx).await.unwrap();
849+
850+
let account = context
851+
.banks_client
852+
.get_account(mint_account.pubkey())
853+
.await
854+
.unwrap();
855+
856+
assert!(account.is_some());
857+
858+
let account = account.unwrap();
859+
let account = spl_token::state::Mint::unpack(&account.data).unwrap();
860+
861+
assert!(account.mint_authority.is_none());
862+
863+
// When we withdraw the excess lamports with no authority.
864+
865+
let destination = Pubkey::new_unique();
866+
867+
let mut withdraw_ix = spl_token_2022::instruction::withdraw_excess_lamports(
868+
&spl_token_2022::ID,
869+
&account_pubkey,
870+
&destination,
871+
&mint_account.pubkey(),
872+
&[],
873+
)
874+
.unwrap();
875+
// Switches the program id to the token program.
876+
withdraw_ix.program_id = token_program;
877+
878+
let tx = Transaction::new_signed_with_payer(
879+
&[withdraw_ix],
880+
Some(&context.payer.pubkey()),
881+
&[&context.payer, &mint_account],
882+
context.last_blockhash,
883+
);
884+
context.banks_client.process_transaction(tx).await.unwrap();
885+
886+
// Then the destination account has the excess lamports.
887+
888+
let destination = context.banks_client.get_account(destination).await.unwrap();
889+
890+
assert!(destination.is_some());
891+
892+
let destination = destination.unwrap();
893+
assert_eq!(destination.lamports, excess_lamports);
894+
}
895+
896+
#[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")]
897+
#[tokio::test]
898+
async fn fail_withdraw_excess_lamports_from_mint_with_mint_as_signer(token_program: Pubkey) {
899+
let context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None)
900+
.start_with_context()
901+
.await;
902+
903+
let excess_lamports = 4_000_000_000_000;
904+
905+
// Given a mint authority, freeze authority and an account keypair.
906+
907+
let mint_authority = Keypair::new();
908+
let freeze_authority = Pubkey::new_unique();
909+
let mint_account = Keypair::new();
910+
let account_pubkey = mint_account.pubkey();
911+
912+
let account_size = size_of::<Mint>();
913+
let rent = context.banks_client.get_rent().await.unwrap();
914+
915+
let mut initialize_ix = spl_token::instruction::initialize_mint(
916+
&spl_token::ID,
917+
&mint_account.pubkey(),
918+
&mint_authority.pubkey(),
919+
Some(&freeze_authority),
920+
0,
921+
)
922+
.unwrap();
923+
// Switches the program id to the token program.
924+
initialize_ix.program_id = token_program;
925+
926+
// And we initialize a mint account with excess lamports.
927+
928+
let instructions = vec![
929+
system_instruction::create_account(
930+
&context.payer.pubkey(),
931+
&mint_account.pubkey(),
932+
rent.minimum_balance(account_size) + excess_lamports,
933+
account_size as u64,
934+
&token_program,
935+
),
936+
initialize_ix,
937+
];
938+
939+
let tx = Transaction::new_signed_with_payer(
940+
&instructions,
941+
Some(&context.payer.pubkey()),
942+
&[&context.payer, &mint_account],
943+
context.last_blockhash,
944+
);
945+
context.banks_client.process_transaction(tx).await.unwrap();
946+
947+
let account = context
948+
.banks_client
949+
.get_account(mint_account.pubkey())
950+
.await
951+
.unwrap();
952+
953+
assert!(account.is_some());
954+
955+
let account = account.unwrap();
956+
assert_eq!(
957+
account.lamports,
958+
rent.minimum_balance(account_size) + excess_lamports
959+
);
960+
961+
// When we try to withdraw the excess lamports with the mint as authority.
962+
963+
let destination = Pubkey::new_unique();
964+
965+
let mut withdraw_ix = spl_token_2022::instruction::withdraw_excess_lamports(
966+
&spl_token_2022::ID,
967+
&account_pubkey,
968+
&destination,
969+
&mint_account.pubkey(),
970+
&[],
971+
)
972+
.unwrap();
973+
// Switches the program id to the token program.
974+
withdraw_ix.program_id = token_program;
975+
976+
let tx = Transaction::new_signed_with_payer(
977+
&[withdraw_ix],
978+
Some(&context.payer.pubkey()),
979+
&[&context.payer, &mint_account],
980+
context.last_blockhash,
981+
);
982+
let error = context
983+
.banks_client
984+
.process_transaction(tx)
985+
.await
986+
.unwrap_err();
987+
988+
// Then we expect an error.
989+
990+
assert_matches!(
991+
error,
992+
BanksClientError::TransactionError(TransactionError::InstructionError(
993+
_,
994+
InstructionError::Custom(4) // TokenError::OwnerMismatch
995+
))
996+
);
997+
}
998+
999+
#[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")]
1000+
#[tokio::test]
1001+
async fn fail_withdraw_excess_lamports_from_mint_with_no_authority(token_program: Pubkey) {
1002+
let context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None)
1003+
.start_with_context()
1004+
.await;
1005+
1006+
let excess_lamports = 4_000_000_000_000;
1007+
1008+
// Given a mint authority, freeze authority and an account keypair.
1009+
1010+
let mint_authority = Keypair::new();
1011+
let freeze_authority = Pubkey::new_unique();
1012+
let mint_account = Keypair::new();
1013+
let account_pubkey = mint_account.pubkey();
1014+
1015+
let account_size = size_of::<Mint>();
1016+
let rent = context.banks_client.get_rent().await.unwrap();
1017+
1018+
let mut initialize_ix = spl_token::instruction::initialize_mint(
1019+
&spl_token::ID,
1020+
&mint_account.pubkey(),
1021+
&mint_authority.pubkey(),
1022+
Some(&freeze_authority),
1023+
0,
1024+
)
1025+
.unwrap();
1026+
// Switches the program id to the token program.
1027+
initialize_ix.program_id = token_program;
1028+
1029+
// And we initialize a mint account with excess lamports.
1030+
1031+
let instructions = vec![
1032+
system_instruction::create_account(
1033+
&context.payer.pubkey(),
1034+
&mint_account.pubkey(),
1035+
rent.minimum_balance(account_size) + excess_lamports,
1036+
account_size as u64,
1037+
&token_program,
1038+
),
1039+
initialize_ix,
1040+
];
1041+
1042+
let tx = Transaction::new_signed_with_payer(
1043+
&instructions,
1044+
Some(&context.payer.pubkey()),
1045+
&[&context.payer, &mint_account],
1046+
context.last_blockhash,
1047+
);
1048+
context.banks_client.process_transaction(tx).await.unwrap();
1049+
1050+
let account = context
1051+
.banks_client
1052+
.get_account(mint_account.pubkey())
1053+
.await
1054+
.unwrap();
1055+
1056+
assert!(account.is_some());
1057+
1058+
let account = account.unwrap();
1059+
assert_eq!(
1060+
account.lamports,
1061+
rent.minimum_balance(account_size) + excess_lamports
1062+
);
1063+
1064+
// And we remove the mint authority.
1065+
1066+
let mut set_authority_ix = spl_token::instruction::set_authority(
1067+
&spl_token::ID,
1068+
&mint_account.pubkey(),
1069+
None,
1070+
spl_token::instruction::AuthorityType::MintTokens,
1071+
&mint_authority.pubkey(),
1072+
&[&mint_authority.pubkey()],
1073+
)
1074+
.unwrap();
1075+
// Switches the program id to the token program.
1076+
set_authority_ix.program_id = token_program;
1077+
1078+
let tx = Transaction::new_signed_with_payer(
1079+
&[set_authority_ix],
1080+
Some(&context.payer.pubkey()),
1081+
&[&context.payer, &mint_authority],
1082+
context.last_blockhash,
1083+
);
1084+
context.banks_client.process_transaction(tx).await.unwrap();
1085+
1086+
let account = context
1087+
.banks_client
1088+
.get_account(mint_account.pubkey())
1089+
.await
1090+
.unwrap();
1091+
1092+
assert!(account.is_some());
1093+
1094+
let account = account.unwrap();
1095+
let account = spl_token::state::Mint::unpack(&account.data).unwrap();
1096+
1097+
assert!(account.mint_authority.is_none());
1098+
1099+
// When we try to withdraw the excess lamports with the "old" mint authority.
1100+
1101+
let destination = Pubkey::new_unique();
1102+
1103+
let mut withdraw_ix = spl_token_2022::instruction::withdraw_excess_lamports(
1104+
&spl_token_2022::ID,
1105+
&account_pubkey,
1106+
&destination,
1107+
&mint_authority.pubkey(),
1108+
&[],
1109+
)
1110+
.unwrap();
1111+
// Switches the program id to the token program.
1112+
withdraw_ix.program_id = token_program;
1113+
1114+
let tx = Transaction::new_signed_with_payer(
1115+
&[withdraw_ix],
1116+
Some(&context.payer.pubkey()),
1117+
&[&context.payer, &mint_authority],
1118+
context.last_blockhash,
1119+
);
1120+
let error = context
1121+
.banks_client
1122+
.process_transaction(tx)
1123+
.await
1124+
.unwrap_err();
1125+
1126+
// Then the destination account has the excess lamports.
1127+
1128+
assert_matches!(
1129+
error,
1130+
BanksClientError::TransactionError(TransactionError::InstructionError(
1131+
_,
1132+
InstructionError::Custom(15) // TokenError::AuthorityTypeNotSupported
1133+
))
1134+
);
1135+
}

0 commit comments

Comments
 (0)