@@ -13,6 +13,8 @@ use solana_sdk::{
1313 transaction:: Transaction ,
1414} ;
1515
16+ use crate :: setup:: TOKEN_PROGRAM_ID ;
17+
1618fn batch_instruction ( instructions : Vec < Instruction > ) -> Result < Instruction , ProgramError > {
1719 // Create a `Vec` of ordered `AccountMeta`s
1820 let mut accounts: Vec < AccountMeta > = vec ! [ ] ;
@@ -25,11 +27,32 @@ fn batch_instruction(instructions: Vec<Instruction>) -> Result<Instruction, Prog
2527 return Err ( ProgramError :: IncorrectProgramId ) ;
2628 }
2729
30+ // Number of accounts of the instruction.
2831 data. push ( instruction. accounts . len ( ) as u8 ) ;
29- data. push ( instruction. data . len ( ) as u8 ) ;
3032
33+ for account in instruction. accounts {
34+ let index = accounts. iter ( ) . position ( |x| x. pubkey == account. pubkey ) ;
35+
36+ let index = if let Some ( index) = index {
37+ // The account is already in the list.
38+ let existing = accounts. get_mut ( index) . unwrap ( ) ;
39+ existing. is_writable |= account. is_writable ;
40+ existing. is_signer |= account. is_signer ;
41+
42+ index as u8
43+ } else {
44+ let index = accounts. len ( ) as u8 ;
45+ // The account is not in the list.
46+ accounts. push ( account) ;
47+
48+ index
49+ } ;
50+
51+ data. push ( index) ;
52+ }
53+
54+ data. push ( instruction. data . len ( ) as u8 ) ;
3155 data. extend_from_slice ( & instruction. data ) ;
32- accounts. extend_from_slice ( & instruction. accounts ) ;
3356 }
3457
3558 Ok ( Instruction {
@@ -39,8 +62,7 @@ fn batch_instruction(instructions: Vec<Instruction>) -> Result<Instruction, Prog
3962 } )
4063}
4164
42- #[ test_case:: test_case( spl_token:: ID ; "spl-token" ) ]
43- // #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")]
65+ #[ test_case:: test_case( TOKEN_PROGRAM_ID ; "p-token" ) ]
4466#[ tokio:: test]
4567async fn batch ( token_program : Pubkey ) {
4668 let mut context = ProgramTest :: new ( "token_program" , token_program, None )
@@ -223,3 +245,180 @@ async fn batch(token_program: Pubkey) {
223245 spl_token:: state:: Account :: unpack ( & owner_b_ta_a_account. unwrap ( ) . data ) . unwrap ( ) ;
224246 assert_eq ! ( owner_b_ta_a_account. amount, 1000000 ) ;
225247}
248+
249+ #[ test_case:: test_case( TOKEN_PROGRAM_ID ; "p-token" ) ]
250+ #[ tokio:: test]
251+ async fn sequence ( token_program : Pubkey ) {
252+ let mut context = ProgramTest :: new ( "token_program" , token_program, None )
253+ . start_with_context ( )
254+ . await ;
255+
256+ let rent = context. banks_client . get_rent ( ) . await . unwrap ( ) ;
257+
258+ let mint_len = spl_token:: state:: Mint :: LEN ;
259+ let mint_rent = rent. minimum_balance ( mint_len) ;
260+
261+ let account_len = spl_token:: state:: Account :: LEN ;
262+ let account_rent = rent. minimum_balance ( account_len) ;
263+
264+ // Create a mint
265+ let mint_a = Keypair :: new ( ) ;
266+ let mint_authority = Keypair :: new ( ) ;
267+ let create_mint_a = system_instruction:: create_account (
268+ & context. payer . pubkey ( ) ,
269+ & mint_a. pubkey ( ) ,
270+ mint_rent,
271+ mint_len as u64 ,
272+ & token_program,
273+ ) ;
274+ let initialize_mint_ix = spl_token:: instruction:: initialize_mint (
275+ & token_program,
276+ & mint_a. pubkey ( ) ,
277+ & mint_authority. pubkey ( ) ,
278+ None ,
279+ 6 ,
280+ )
281+ . unwrap ( ) ;
282+
283+ // Create a mint 2 with a freeze authority
284+ let mint_b = Keypair :: new ( ) ;
285+ let freeze_authority = Pubkey :: new_unique ( ) ;
286+ let create_mint_b = system_instruction:: create_account (
287+ & context. payer . pubkey ( ) ,
288+ & mint_b. pubkey ( ) ,
289+ mint_rent,
290+ mint_len as u64 ,
291+ & token_program,
292+ ) ;
293+ let initialize_mint_with_freeze_authority_ix = spl_token:: instruction:: initialize_mint2 (
294+ & token_program,
295+ & mint_b. pubkey ( ) ,
296+ & mint_authority. pubkey ( ) ,
297+ Some ( & freeze_authority) ,
298+ 6 ,
299+ )
300+ . unwrap ( ) ;
301+
302+ // Create 2 token accounts for mint A and 1 for mint B
303+ let owner_a = Keypair :: new ( ) ;
304+ let owner_b = Keypair :: new ( ) ;
305+ let owner_a_ta_a = Keypair :: new ( ) ;
306+ let owner_b_ta_a = Keypair :: new ( ) ;
307+
308+ let create_owner_a_ta_a = system_instruction:: create_account (
309+ & context. payer . pubkey ( ) ,
310+ & owner_a_ta_a. pubkey ( ) ,
311+ account_rent,
312+ account_len as u64 ,
313+ & token_program,
314+ ) ;
315+ let create_owner_b_ta_a = system_instruction:: create_account (
316+ & context. payer . pubkey ( ) ,
317+ & owner_b_ta_a. pubkey ( ) ,
318+ account_rent,
319+ account_len as u64 ,
320+ & token_program,
321+ ) ;
322+ let intialize_owner_a_ta_a = spl_token:: instruction:: initialize_account3 (
323+ & token_program,
324+ & owner_a_ta_a. pubkey ( ) ,
325+ & mint_a. pubkey ( ) ,
326+ & owner_a. pubkey ( ) ,
327+ )
328+ . unwrap ( ) ;
329+ let intialize_owner_b_ta_a = spl_token:: instruction:: initialize_account3 (
330+ & token_program,
331+ & owner_b_ta_a. pubkey ( ) ,
332+ & mint_a. pubkey ( ) ,
333+ & owner_b. pubkey ( ) ,
334+ )
335+ . unwrap ( ) ;
336+
337+ // Mint Token A to Owner A
338+ let mint_token_a_to_owner_a = spl_token:: instruction:: mint_to (
339+ & token_program,
340+ & mint_a. pubkey ( ) ,
341+ & owner_a_ta_a. pubkey ( ) ,
342+ & mint_authority. pubkey ( ) ,
343+ & [ ] ,
344+ 1_000_000 ,
345+ )
346+ . unwrap ( ) ;
347+
348+ // Transfer Token A from Owner A to Owner B
349+ let transfer_token_a_to_owner_b = spl_token:: instruction:: transfer (
350+ & token_program,
351+ & owner_a_ta_a. pubkey ( ) ,
352+ & owner_b_ta_a. pubkey ( ) ,
353+ & owner_a. pubkey ( ) ,
354+ & [ ] ,
355+ 1_000_000 ,
356+ )
357+ . unwrap ( ) ;
358+
359+ // Close Token A
360+ let close_owner_a_ta_a = spl_token:: instruction:: close_account (
361+ & token_program,
362+ & owner_a_ta_a. pubkey ( ) ,
363+ & owner_a. pubkey ( ) ,
364+ & owner_a. pubkey ( ) ,
365+ & [ ] ,
366+ )
367+ . unwrap ( ) ;
368+
369+ let tx = Transaction :: new_signed_with_payer (
370+ & [
371+ create_mint_a,
372+ create_mint_b,
373+ create_owner_a_ta_a,
374+ create_owner_b_ta_a,
375+ initialize_mint_ix,
376+ initialize_mint_with_freeze_authority_ix,
377+ intialize_owner_a_ta_a,
378+ intialize_owner_b_ta_a,
379+ mint_token_a_to_owner_a,
380+ transfer_token_a_to_owner_b,
381+ close_owner_a_ta_a,
382+ ] ,
383+ Some ( & context. payer . pubkey ( ) ) ,
384+ & vec ! [
385+ & context. payer,
386+ & mint_a,
387+ & mint_b,
388+ & owner_a_ta_a,
389+ & owner_b_ta_a,
390+ & mint_authority,
391+ & owner_a,
392+ ] ,
393+ context. last_blockhash ,
394+ ) ;
395+ context. banks_client . process_transaction ( tx) . await . unwrap ( ) ;
396+
397+ let mint_a_account = context
398+ . banks_client
399+ . get_account ( mint_a. pubkey ( ) )
400+ . await
401+ . unwrap ( ) ;
402+ assert ! ( mint_a_account. is_some( ) ) ;
403+ let mint_a_account = spl_token:: state:: Mint :: unpack ( & mint_a_account. unwrap ( ) . data ) . unwrap ( ) ;
404+ assert_eq ! ( mint_a_account. supply, 1000000 ) ;
405+
406+ let mint_b_account = context
407+ . banks_client
408+ . get_account ( mint_b. pubkey ( ) )
409+ . await
410+ . unwrap ( ) ;
411+ assert ! ( mint_b_account. is_some( ) ) ;
412+ let mint_b_account = spl_token:: state:: Mint :: unpack ( & mint_b_account. unwrap ( ) . data ) . unwrap ( ) ;
413+ assert_eq ! ( mint_b_account. supply, 0 ) ;
414+
415+ let owner_b_ta_a_account = context
416+ . banks_client
417+ . get_account ( owner_b_ta_a. pubkey ( ) )
418+ . await
419+ . unwrap ( ) ;
420+ assert ! ( owner_b_ta_a_account. is_some( ) ) ;
421+ let owner_b_ta_a_account =
422+ spl_token:: state:: Account :: unpack ( & owner_b_ta_a_account. unwrap ( ) . data ) . unwrap ( ) ;
423+ assert_eq ! ( owner_b_ta_a_account. amount, 1000000 ) ;
424+ }
0 commit comments