@@ -93,8 +93,9 @@ pub(crate) async fn prepare_token_accounts_instructions(
9393 }
9494
9595 create_instructions. push ( create_associated_token_account (
96- & owner,
97- & ata_address,
96+ // ATA address will be derived in the function
97+ & owner, // funder
98+ & owner, // owner
9899 & mint_address,
99100 & mint_account_infos[ i] . owner ,
100101 ) ) ;
@@ -366,7 +367,7 @@ mod tests {
366367 setup_mint_te_fee, RpcContext ,
367368 } ;
368369 use serial_test:: serial;
369- use spl_associated_token_account :: instruction :: create_associated_token_account_idempotent ;
370+
370371 use std:: str:: FromStr ;
371372
372373 // 1. Basic Utility Tests
@@ -395,6 +396,9 @@ mod tests {
395396
396397 // Verify empty result
397398 assert_eq ! ( result. token_account_addresses. len( ) , 0 ) ;
399+ assert_eq ! ( result. create_instructions. len( ) , 0 ) ;
400+ assert_eq ! ( result. cleanup_instructions. len( ) , 0 ) ;
401+ assert_eq ! ( result. additional_signers. len( ) , 0 ) ;
398402 }
399403
400404 #[ tokio:: test]
@@ -417,24 +421,90 @@ mod tests {
417421 . await
418422 . unwrap ( ) ;
419423
424+ // Verify result
425+ assert_eq ! ( result. token_account_addresses. len( ) , 1 ) ;
420426 assert_eq ! ( result. token_account_addresses[ & mint] , ata) ;
427+ assert_eq ! ( result. create_instructions. len( ) , 1 ) ;
428+ assert_eq ! ( result. cleanup_instructions. len( ) , 0 ) ;
429+ assert_eq ! ( result. additional_signers. len( ) , 0 ) ;
430+
431+ // Verify uninitialized state
432+ let account = ctx. rpc . get_account ( & ata) . await ;
433+ assert ! ( account
434+ . err( )
435+ . unwrap( )
436+ . to_string( )
437+ . contains( "AccountNotFound" ) ) ;
421438
422- // Use idempotent version of create ATA
423- let mut instructions = vec ! [ create_associated_token_account_idempotent(
424- & ctx. signer. pubkey( ) ,
439+ // Verify instruction
440+ ctx. send_transaction ( result. create_instructions )
441+ . await
442+ . unwrap ( ) ;
443+
444+ // Verify initialized account
445+ let account = ctx. rpc . get_account ( & ata) . await . unwrap ( ) ;
446+ let token_account = Account :: unpack ( & account. data ) . unwrap ( ) ;
447+ assert_eq ! ( token_account. amount, 0 ) ;
448+ assert_eq ! ( token_account. mint, mint) ;
449+ assert_eq ! ( token_account. owner, ctx. signer. pubkey( ) ) ;
450+ }
451+
452+ #[ tokio:: test]
453+ #[ serial]
454+ async fn test_token_without_balance_multiple_with_te ( ) {
455+ let ctx = RpcContext :: new ( ) . await ;
456+ let mint0 = setup_mint ( & ctx) . await . unwrap ( ) ;
457+ let mint1 = setup_mint_te ( & ctx, & [ ] ) . await . unwrap ( ) ;
458+
459+ let ata0 = get_associated_token_address_with_program_id (
425460 & ctx. signer . pubkey ( ) ,
426- & mint ,
461+ & mint0 ,
427462 & TOKEN_PROGRAM_ID ,
428- ) ] ;
429- instructions. extend ( result. create_instructions ) ;
463+ ) ;
464+ let ata1 = get_associated_token_address_with_program_id (
465+ & ctx. signer . pubkey ( ) ,
466+ & mint1,
467+ & TOKEN_2022_PROGRAM_ID ,
468+ ) ;
469+
470+ let result = prepare_token_accounts_instructions (
471+ & ctx. rpc ,
472+ ctx. signer . pubkey ( ) ,
473+ vec ! [
474+ TokenAccountStrategy :: WithoutBalance ( mint0) ,
475+ TokenAccountStrategy :: WithoutBalance ( mint1) ,
476+ ] ,
477+ )
478+ . await
479+ . unwrap ( ) ;
430480
431- ctx. send_transaction ( instructions) . await . unwrap ( ) ;
481+ // Verify result
482+ assert_eq ! ( result. token_account_addresses. len( ) , 2 ) ;
483+ assert_eq ! ( result. token_account_addresses[ & mint0] , ata0) ;
484+ assert_eq ! ( result. token_account_addresses[ & mint1] , ata1) ;
485+ assert_eq ! ( result. create_instructions. len( ) , 2 ) ;
486+ assert_eq ! ( result. cleanup_instructions. len( ) , 0 ) ;
487+ assert_eq ! ( result. additional_signers. len( ) , 0 ) ;
432488
433- let account = ctx. rpc . get_account ( & ata) . await . unwrap ( ) ;
489+ // Verify instruction
490+ ctx. send_transaction ( result. create_instructions )
491+ . await
492+ . unwrap ( ) ;
493+
494+ // Verify initialized account
495+ let account = ctx. rpc . get_account ( & ata0) . await . unwrap ( ) ;
496+ assert_eq ! ( account. owner, TOKEN_PROGRAM_ID ) ;
434497 let token_account = Account :: unpack ( & account. data ) . unwrap ( ) ;
435498 assert_eq ! ( token_account. amount, 0 ) ;
436- assert_eq ! ( token_account. mint, mint ) ;
499+ assert_eq ! ( token_account. mint, mint0 ) ;
437500 assert_eq ! ( token_account. owner, ctx. signer. pubkey( ) ) ;
501+
502+ let account = ctx. rpc . get_account ( & ata1) . await . unwrap ( ) ;
503+ assert_eq ! ( account. owner, TOKEN_2022_PROGRAM_ID ) ;
504+ let token_account = StateWithExtensions :: < Account > :: unpack ( & account. data ) . unwrap ( ) ;
505+ assert_eq ! ( token_account. base. amount, 0 ) ;
506+ assert_eq ! ( token_account. base. mint, mint1) ;
507+ assert_eq ! ( token_account. base. owner, ctx. signer. pubkey( ) ) ;
438508 }
439509
440510 #[ tokio:: test]
@@ -458,6 +528,13 @@ mod tests {
458528 . await
459529 . unwrap ( ) ;
460530
531+ // Verify result
532+ assert_eq ! ( result. token_account_addresses. len( ) , 1 ) ;
533+ assert_eq ! ( result. token_account_addresses[ & mint] , ata) ;
534+ assert_eq ! ( result. create_instructions. len( ) , 0 ) ;
535+ assert_eq ! ( result. cleanup_instructions. len( ) , 0 ) ;
536+ assert_eq ! ( result. additional_signers. len( ) , 0 ) ;
537+
461538 // Verify account state
462539 let account = ctx. rpc . get_account ( & ata) . await . unwrap ( ) ;
463540 let token_account = Account :: unpack ( & account. data ) . unwrap ( ) ;
@@ -592,6 +669,13 @@ mod tests {
592669 . await
593670 . unwrap ( ) ;
594671
672+ // Verify result
673+ assert_eq ! ( result. token_account_addresses. len( ) , 1 ) ;
674+ assert_eq ! ( result. token_account_addresses[ & mint] , ata) ;
675+ assert_eq ! ( result. create_instructions. len( ) , 0 ) ;
676+ assert_eq ! ( result. cleanup_instructions. len( ) , 0 ) ;
677+ assert_eq ! ( result. additional_signers. len( ) , 0 ) ;
678+
595679 // Verify account wasn't modified
596680 let final_account = ctx. rpc . get_account ( & ata) . await . unwrap ( ) ;
597681 assert_eq ! ( initial_account. data, final_account. data) ;
@@ -618,22 +702,32 @@ mod tests {
618702 . await
619703 . unwrap ( ) ;
620704
705+ // Verify result
706+ assert_eq ! ( result. token_account_addresses. len( ) , 1 ) ;
621707 assert_eq ! ( result. token_account_addresses[ & native_mint:: ID ] , ata) ;
708+ assert_eq ! ( result. create_instructions. len( ) , 1 ) ;
709+ assert_eq ! ( result. cleanup_instructions. len( ) , 0 ) ;
710+ assert_eq ! ( result. additional_signers. len( ) , 0 ) ;
711+
712+ // Verify uninitialized state
713+ let account = ctx. rpc . get_account ( & ata) . await ;
714+ assert ! ( account
715+ . err( )
716+ . unwrap( )
717+ . to_string( )
718+ . contains( "AccountNotFound" ) ) ;
622719
623- // Use idempotent version of create ATA
624- let mut instructions = vec ! [ create_associated_token_account_idempotent(
625- & ctx. signer. pubkey( ) ,
626- & ctx. signer. pubkey( ) ,
627- & native_mint:: ID ,
628- & TOKEN_PROGRAM_ID ,
629- ) ] ;
630- instructions. extend ( result. create_instructions ) ;
631-
632- ctx. send_transaction ( instructions) . await . unwrap ( ) ;
720+ // Verify instruction
721+ ctx. send_transaction ( result. create_instructions )
722+ . await
723+ . unwrap ( ) ;
633724
725+ // Verify initialized account
634726 let account = ctx. rpc . get_account ( & ata) . await . unwrap ( ) ;
635727 let token_account = Account :: unpack ( & account. data ) . unwrap ( ) ;
636728 assert_eq ! ( token_account. amount, 0 ) ;
729+ assert_eq ! ( token_account. mint, native_mint:: ID ) ;
730+ assert_eq ! ( token_account. owner, ctx. signer. pubkey( ) ) ;
637731 }
638732
639733 #[ tokio:: test]
@@ -656,24 +750,41 @@ mod tests {
656750 . await
657751 . unwrap ( ) ;
658752
753+ // Verify result
754+ assert_eq ! ( result. token_account_addresses. len( ) , 1 ) ;
659755 assert_eq ! ( result. token_account_addresses[ & native_mint:: ID ] , ata) ;
756+ assert_eq ! ( result. create_instructions. len( ) , 1 ) ;
757+ assert_eq ! ( result. cleanup_instructions. len( ) , 1 ) ;
758+ assert_eq ! ( result. additional_signers. len( ) , 0 ) ;
759+
760+ // Verify uninitialized state
761+ let account = ctx. rpc . get_account ( & ata) . await ;
762+ assert ! ( account
763+ . err( )
764+ . unwrap( )
765+ . to_string( )
766+ . contains( "AccountNotFound" ) ) ;
660767
661- // Use idempotent version of create ATA
662- let mut instructions = vec ! [ create_associated_token_account_idempotent(
663- & ctx. signer. pubkey( ) ,
664- & ctx. signer. pubkey( ) ,
665- & native_mint:: ID ,
666- & TOKEN_PROGRAM_ID ,
667- ) ] ;
668- instructions. extend ( result. create_instructions ) ;
669-
670- ctx. send_transaction ( instructions) . await . unwrap ( ) ;
768+ // Verify instruction
769+ ctx. send_transaction ( result. create_instructions )
770+ . await
771+ . unwrap ( ) ;
671772
773+ // Verify initialized account
672774 let account = ctx. rpc . get_account ( & ata) . await . unwrap ( ) ;
673775 let token_account = Account :: unpack ( & account. data ) . unwrap ( ) ;
674776 assert_eq ! ( token_account. amount, 0 ) ;
675777 assert_eq ! ( token_account. mint, native_mint:: ID ) ;
676778 assert_eq ! ( token_account. owner, ctx. signer. pubkey( ) ) ;
779+
780+ // Execute cleanup instructions
781+ ctx. send_transaction ( result. cleanup_instructions )
782+ . await
783+ . unwrap ( ) ;
784+
785+ // Verify account was cleaned up
786+ let accounts = ctx. rpc . get_multiple_accounts ( & [ ata] ) . await . unwrap ( ) ;
787+ assert ! ( accounts[ 0 ] . is_none( ) || accounts[ 0 ] . as_ref( ) . unwrap( ) . data. is_empty( ) ) ;
677788 }
678789
679790 #[ tokio:: test]
@@ -692,10 +803,14 @@ mod tests {
692803 . unwrap ( ) ;
693804
694805 // Verify token account address is mapped correctly
806+ assert_eq ! ( result. token_account_addresses. len( ) , 1 ) ;
695807 assert ! ( result
696808 . token_account_addresses
697809 . contains_key( & native_mint:: ID ) ) ;
698810 let token_address = result. token_account_addresses [ & native_mint:: ID ] ;
811+ assert_eq ! ( result. create_instructions. len( ) , 2 ) ; // create account + initialize (token) account 3
812+ assert_eq ! ( result. cleanup_instructions. len( ) , 1 ) ;
813+ assert_eq ! ( result. additional_signers. len( ) , 1 ) ;
699814
700815 // Execute create instructions
701816 ctx. send_transaction_with_signers (
@@ -747,10 +862,14 @@ mod tests {
747862 . unwrap ( ) ;
748863
749864 // Verify token account address is mapped correctly
865+ assert_eq ! ( result. token_account_addresses. len( ) , 1 ) ;
750866 assert ! ( result
751867 . token_account_addresses
752868 . contains_key( & native_mint:: ID ) ) ;
753869 let token_address = result. token_account_addresses [ & native_mint:: ID ] ;
870+ assert_eq ! ( result. create_instructions. len( ) , 2 ) ; // create account with seed + initialize (token) account 3
871+ assert_eq ! ( result. cleanup_instructions. len( ) , 1 ) ;
872+ assert_eq ! ( result. additional_signers. len( ) , 0 ) ;
754873
755874 // Execute and verify using get_multiple_accounts
756875 ctx. send_transaction_with_signers (
@@ -768,6 +887,19 @@ mod tests {
768887 let account = accounts[ 0 ] . as_ref ( ) . unwrap ( ) ;
769888 let token_account = Account :: unpack ( & account. data ) . unwrap ( ) ;
770889 assert_eq ! ( token_account. amount, amount) ;
890+
891+ // Execute cleanup instructions
892+ ctx. send_transaction ( result. cleanup_instructions )
893+ . await
894+ . unwrap ( ) ;
895+
896+ // Verify account was cleaned up
897+ let accounts = ctx
898+ . rpc
899+ . get_multiple_accounts ( & [ token_address] )
900+ . await
901+ . unwrap ( ) ;
902+ assert ! ( accounts[ 0 ] . is_none( ) || accounts[ 0 ] . as_ref( ) . unwrap( ) . data. is_empty( ) ) ;
771903 }
772904
773905 #[ tokio:: test]
0 commit comments