@@ -169,13 +169,23 @@ pub async fn create_generic_transfer2_instruction<R: Rpc + Indexer>(
169169 payer : Pubkey ,
170170 should_filter_zero_outputs : bool ,
171171) -> Result < Instruction , TokenSdkError > {
172- // // Get a single shared output queue for ALL compress/compress-and-close operations
173- // // This prevents reordering issues caused by the sort_by_key at the end
174- // let shared_output_queue = rpc
175- // .get_random_state_tree_info()
176- // .unwrap()
177- // .get_output_pubkey()
178- // .unwrap();
172+ // Transfer2 supports a single output queue per instruction. Legacy helpers accept
173+ // per-action queues, but normalize them down to one shared queue for the IX.
174+ let mut explicit_output_queue = None ;
175+ for action in & actions {
176+ let candidate = match action {
177+ Transfer2InstructionType :: Compress ( input) => Some ( input. output_queue ) ,
178+ Transfer2InstructionType :: CompressAndClose ( input) => Some ( input. output_queue ) ,
179+ Transfer2InstructionType :: Decompress ( _)
180+ | Transfer2InstructionType :: Transfer ( _)
181+ | Transfer2InstructionType :: Approve ( _) => None ,
182+ } ;
183+ if let Some ( candidate) = candidate {
184+ if explicit_output_queue. is_none ( ) {
185+ explicit_output_queue = Some ( candidate) ;
186+ }
187+ }
188+ }
179189
180190 let mut hashes = Vec :: new ( ) ;
181191 actions. iter ( ) . for_each ( |account| match account {
@@ -210,26 +220,16 @@ pub async fn create_generic_transfer2_instruction<R: Rpc + Indexer>(
210220 . value ;
211221
212222 let mut packed_tree_accounts = PackedAccounts :: default ( ) ;
213- // tree infos must be packed before packing the token input accounts
214- let packed_tree_infos = rpc_proof_result
215- . pack_tree_infos ( & mut packed_tree_accounts)
216- . unwrap ( ) ;
217-
218- // We use a single shared output queue for all compress/compress-and-close operations to avoid ordering failures.
219- let shared_output_queue = if packed_tree_infos. address_trees . is_empty ( ) {
220- let shared_output_queue = rpc
221- . get_random_state_tree_info ( )
223+ // Pack only input state tree infos. Grouped transfer2 proofs can span multiple output trees.
224+ let packed_tree_infos = rpc_proof_result. pack_state_tree_infos ( & mut packed_tree_accounts) ;
225+
226+ let shared_output_queue = explicit_output_queue. unwrap_or_else ( || {
227+ rpc. get_random_state_tree_info ( )
222228 . unwrap ( )
223229 . get_output_pubkey ( )
224- . unwrap ( ) ;
225- packed_tree_accounts. insert_or_get ( shared_output_queue)
226- } else {
227- packed_tree_infos
228- . state_trees
229- . as_ref ( )
230230 . unwrap ( )
231- . output_tree_index
232- } ;
231+ } ) ;
232+ let shared_output_queue = packed_tree_accounts . insert_or_get ( shared_output_queue ) ;
233233
234234 let mut inputs_offset = 0 ;
235235 let mut in_lamports = Vec :: new ( ) ;
@@ -245,12 +245,7 @@ pub async fn create_generic_transfer2_instruction<R: Rpc + Indexer>(
245245 let token_data = input_token_account
246246 . iter ( )
247247 . zip (
248- packed_tree_infos
249- . state_trees
250- . as_ref ( )
251- . unwrap ( )
252- . packed_tree_infos [ inputs_offset..]
253- . iter ( ) ,
248+ packed_tree_infos[ inputs_offset..] . iter ( ) ,
254249 )
255250 . map ( |( account, rpc_account) | {
256251 if input. to != account. token . owner {
@@ -393,14 +388,7 @@ pub async fn create_generic_transfer2_instruction<R: Rpc + Indexer>(
393388 let token_data = input
394389 . compressed_token_account
395390 . iter ( )
396- . zip (
397- packed_tree_infos
398- . state_trees
399- . as_ref ( )
400- . unwrap ( )
401- . packed_tree_infos [ inputs_offset..]
402- . iter ( ) ,
403- )
391+ . zip ( packed_tree_infos[ inputs_offset..] . iter ( ) )
404392 . map ( |( account, rpc_account) | {
405393 pack_input_token_account (
406394 account,
@@ -462,14 +450,7 @@ pub async fn create_generic_transfer2_instruction<R: Rpc + Indexer>(
462450 let token_data = input
463451 . compressed_token_account
464452 . iter ( )
465- . zip (
466- packed_tree_infos
467- . state_trees
468- . as_ref ( )
469- . unwrap ( )
470- . packed_tree_infos [ inputs_offset..]
471- . iter ( ) ,
472- )
453+ . zip ( packed_tree_infos[ inputs_offset..] . iter ( ) )
473454 . map ( |( account, rpc_account) | {
474455 pack_input_token_account (
475456 account,
@@ -544,14 +525,7 @@ pub async fn create_generic_transfer2_instruction<R: Rpc + Indexer>(
544525 let token_data = input
545526 . compressed_token_account
546527 . iter ( )
547- . zip (
548- packed_tree_infos
549- . state_trees
550- . as_ref ( )
551- . unwrap ( )
552- . packed_tree_infos [ inputs_offset..]
553- . iter ( ) ,
554- )
528+ . zip ( packed_tree_infos[ inputs_offset..] . iter ( ) )
555529 . map ( |( account, rpc_account) | {
556530 pack_input_token_account (
557531 account,
0 commit comments