@@ -4,6 +4,8 @@ use fixtures::{assert_custom_error, prelude::*};
44use marginfi:: prelude:: * ;
55use pretty_assertions:: assert_eq;
66use solana_program_test:: * ;
7+ use solana_sdk:: signature:: Keypair ;
8+ use solana_sdk:: system_program;
79use solana_sdk:: {
810 compute_budget:: ComputeBudgetInstruction , signer:: Signer , transaction:: Transaction ,
911} ;
@@ -18,6 +20,7 @@ use solana_sdk::{
1820// 7. Flashloan fails because of invalid `end_flashloan` ix order
1921// 8. Flashloan fails because `end_flashloan` ix is for another account
2022// 9. Flashloan fails because account is already in a flashloan
23+ // 10. Flashloan fails because account transfer during flashloan
2124
2225#[ tokio:: test]
2326async fn flashloan_success_1op ( ) -> anyhow:: Result < ( ) > {
@@ -41,7 +44,6 @@ async fn flashloan_success_1op() -> anyhow::Result<()> {
4144
4245 let borrower_token_account_f_sol = test_f. sol_mint . create_empty_token_account ( ) . await ;
4346 // Borrow SOL
44-
4547 let borrow_ix = borrower_mfi_account_f
4648 . make_bank_borrow_ix ( borrower_token_account_f_sol. key , sol_bank, 1_000 )
4749 . await ;
@@ -56,7 +58,7 @@ async fn flashloan_success_1op() -> anyhow::Result<()> {
5658 . await ;
5759
5860 let flash_loan_result = borrower_mfi_account_f
59- . try_flashloan ( vec ! [ borrow_ix, repay_ix] , vec ! [ ] , vec ! [ ] )
61+ . try_flashloan ( vec ! [ borrow_ix, repay_ix] , vec ! [ ] , vec ! [ ] , None )
6062 . await ;
6163
6264 assert ! ( flash_loan_result. is_ok( ) ) ;
@@ -108,7 +110,7 @@ async fn flashloan_success_3op() -> anyhow::Result<()> {
108110 ixs. push ( ComputeBudgetInstruction :: set_compute_unit_limit ( 1_400_000 ) ) ;
109111
110112 let flash_loan_result = borrower_mfi_account_f
111- . try_flashloan ( ixs, vec ! [ ] , vec ! [ ] )
113+ . try_flashloan ( ixs, vec ! [ ] , vec ! [ ] , None )
112114 . await ;
113115
114116 assert ! ( flash_loan_result. is_ok( ) ) ;
@@ -137,13 +139,12 @@ async fn flashloan_fail_account_health() -> anyhow::Result<()> {
137139
138140 let borrower_token_account_f_sol = test_f. sol_mint . create_empty_token_account ( ) . await ;
139141 // Borrow SOL
140-
141142 let borrow_ix = borrower_mfi_account_f
142143 . make_bank_borrow_ix ( borrower_token_account_f_sol. key , sol_bank, 1_000 )
143144 . await ;
144145
145146 let flash_loan_result = borrower_mfi_account_f
146- . try_flashloan ( vec ! [ borrow_ix] , vec ! [ ] , vec ! [ sol_bank. key] )
147+ . try_flashloan ( vec ! [ borrow_ix] , vec ! [ ] , vec ! [ sol_bank. key] , None )
147148 . await ;
148149
149150 assert_custom_error ! (
@@ -192,7 +193,7 @@ async fn flashloan_ok_missing_flag() -> anyhow::Result<()> {
192193 . await ;
193194
194195 let flash_loan_result = borrower_mfi_account_f
195- . try_flashloan ( vec ! [ borrow_ix, repay_ix] , vec ! [ ] , vec ! [ ] )
196+ . try_flashloan ( vec ! [ borrow_ix, repay_ix] , vec ! [ ] , vec ! [ ] , None )
196197 . await ;
197198
198199 assert ! ( flash_loan_result. is_ok( ) ) ;
@@ -503,3 +504,66 @@ async fn flashloan_fail_already_in_flashloan() -> anyhow::Result<()> {
503504
504505 Ok ( ( ) )
505506}
507+
508+ #[ tokio:: test]
509+ async fn flashloan_fail_account_transfer_during_flashloan ( ) -> anyhow:: Result < ( ) > {
510+ let test_f = TestFixture :: new ( Some ( TestSettings :: all_banks_payer_not_admin ( ) ) ) . await ;
511+
512+ let sol_bank = test_f. get_bank ( & BankMint :: Sol ) ;
513+
514+ // Fund SOL lender
515+ let lender_mfi_account_f = test_f. create_marginfi_account ( ) . await ;
516+ let lender_token_account_f_sol = test_f
517+ . sol_mint
518+ . create_token_account_and_mint_to ( 1_000 )
519+ . await ;
520+ lender_mfi_account_f
521+ . try_bank_deposit ( lender_token_account_f_sol. key , sol_bank, 1_000 , None )
522+ . await ?;
523+
524+ // Fund SOL borrower
525+ let borrower_mfi_account_f = test_f. create_marginfi_account ( ) . await ;
526+
527+ let borrower_token_account_f_sol = test_f. sol_mint . create_empty_token_account ( ) . await ;
528+
529+ // Borrow SOL
530+ let borrow_ix = borrower_mfi_account_f
531+ . make_bank_borrow_ix ( borrower_token_account_f_sol. key , sol_bank, 1_000 )
532+ . await ;
533+
534+ let new_authority = Keypair :: new ( ) ;
535+ let new_account = Keypair :: new ( ) ;
536+
537+ let account = borrower_mfi_account_f. load ( ) . await ;
538+
539+ let transfer_account_ix = Instruction {
540+ program_id : marginfi:: id ( ) ,
541+ accounts : marginfi:: accounts:: TransferToNewAccount {
542+ old_marginfi_account : borrower_mfi_account_f. key ,
543+ new_marginfi_account : new_account. pubkey ( ) ,
544+ group : account. group ,
545+ authority : test_f. payer ( ) ,
546+ new_authority : new_authority. pubkey ( ) ,
547+ global_fee_wallet : test_f. marginfi_group . fee_wallet ,
548+ system_program : system_program:: ID ,
549+ }
550+ . to_account_metas ( None ) ,
551+ data : marginfi:: instruction:: TransferToNewAccount { } . data ( ) ,
552+ } ;
553+
554+ let flash_loan_result = borrower_mfi_account_f
555+ . try_flashloan (
556+ vec ! [ borrow_ix, transfer_account_ix] ,
557+ vec ! [ ] ,
558+ vec ! [ sol_bank. key] ,
559+ Some ( & new_account) ,
560+ )
561+ . await ;
562+
563+ assert_custom_error ! (
564+ flash_loan_result. unwrap_err( ) ,
565+ MarginfiError :: AccountInFlashloan
566+ ) ;
567+
568+ Ok ( ( ) )
569+ }
0 commit comments