batch.rs 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. #![cfg(not(feature = "fuzzing"))]
  2. mod setup;
  3. use {
  4. crate::setup::TOKEN_PROGRAM_ID,
  5. solana_program_test::{tokio, ProgramTest},
  6. solana_sdk::{
  7. instruction::{AccountMeta, Instruction},
  8. program_error::ProgramError,
  9. program_pack::Pack,
  10. pubkey::Pubkey,
  11. signature::{Keypair, Signer},
  12. system_instruction,
  13. transaction::Transaction,
  14. },
  15. };
  16. fn batch_instruction(instructions: Vec<Instruction>) -> Result<Instruction, ProgramError> {
  17. // Create a `Vec` of ordered `AccountMeta`s
  18. let mut accounts: Vec<AccountMeta> = vec![];
  19. // Start with the batch discriminator
  20. let mut data: Vec<u8> = vec![0xff];
  21. for instruction in instructions {
  22. // Error out on non-token IX.
  23. if instruction.program_id.ne(&spl_token::ID) {
  24. return Err(ProgramError::IncorrectProgramId);
  25. }
  26. data.push(instruction.accounts.len() as u8);
  27. data.push(instruction.data.len() as u8);
  28. data.extend_from_slice(&instruction.data);
  29. accounts.extend_from_slice(&instruction.accounts);
  30. }
  31. Ok(Instruction {
  32. program_id: spl_token::ID,
  33. data,
  34. accounts,
  35. })
  36. }
  37. #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")]
  38. #[tokio::test]
  39. async fn batch(token_program: Pubkey) {
  40. let context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None)
  41. .start_with_context()
  42. .await;
  43. let rent = context.banks_client.get_rent().await.unwrap();
  44. let mint_len = spl_token::state::Mint::LEN;
  45. let mint_rent = rent.minimum_balance(mint_len);
  46. let account_len = spl_token::state::Account::LEN;
  47. let account_rent = rent.minimum_balance(account_len);
  48. // Create a mint
  49. let mint_a = Keypair::new();
  50. let mint_authority = Keypair::new();
  51. let create_mint_a = system_instruction::create_account(
  52. &context.payer.pubkey(),
  53. &mint_a.pubkey(),
  54. mint_rent,
  55. mint_len as u64,
  56. &token_program,
  57. );
  58. let initialize_mint_ix = spl_token::instruction::initialize_mint(
  59. &token_program,
  60. &mint_a.pubkey(),
  61. &mint_authority.pubkey(),
  62. None,
  63. 6,
  64. )
  65. .unwrap();
  66. // Create a mint 2 with a freeze authority
  67. let mint_b = Keypair::new();
  68. let freeze_authority = Pubkey::new_unique();
  69. let create_mint_b = system_instruction::create_account(
  70. &context.payer.pubkey(),
  71. &mint_b.pubkey(),
  72. mint_rent,
  73. mint_len as u64,
  74. &token_program,
  75. );
  76. let initialize_mint_with_freeze_authority_ix = spl_token::instruction::initialize_mint2(
  77. &token_program,
  78. &mint_b.pubkey(),
  79. &mint_authority.pubkey(),
  80. Some(&freeze_authority),
  81. 6,
  82. )
  83. .unwrap();
  84. // Create 2 token accounts for mint A and 1 for mint B
  85. let owner_a = Keypair::new();
  86. let owner_b = Keypair::new();
  87. let owner_a_ta_a = Keypair::new();
  88. let owner_b_ta_a = Keypair::new();
  89. let create_owner_a_ta_a = system_instruction::create_account(
  90. &context.payer.pubkey(),
  91. &owner_a_ta_a.pubkey(),
  92. account_rent,
  93. account_len as u64,
  94. &token_program,
  95. );
  96. let create_owner_b_ta_a = system_instruction::create_account(
  97. &context.payer.pubkey(),
  98. &owner_b_ta_a.pubkey(),
  99. account_rent,
  100. account_len as u64,
  101. &token_program,
  102. );
  103. let intialize_owner_a_ta_a = spl_token::instruction::initialize_account3(
  104. &token_program,
  105. &owner_a_ta_a.pubkey(),
  106. &mint_a.pubkey(),
  107. &owner_a.pubkey(),
  108. )
  109. .unwrap();
  110. let intialize_owner_b_ta_a = spl_token::instruction::initialize_account3(
  111. &token_program,
  112. &owner_b_ta_a.pubkey(),
  113. &mint_a.pubkey(),
  114. &owner_b.pubkey(),
  115. )
  116. .unwrap();
  117. // Mint Token A to Owner A
  118. let mint_token_a_to_owner_a = spl_token::instruction::mint_to(
  119. &token_program,
  120. &mint_a.pubkey(),
  121. &owner_a_ta_a.pubkey(),
  122. &mint_authority.pubkey(),
  123. &[],
  124. 1_000_000,
  125. )
  126. .unwrap();
  127. // Transfer Token A from Owner A to Owner B
  128. let transfer_token_a_to_owner_b = spl_token::instruction::transfer(
  129. &token_program,
  130. &owner_a_ta_a.pubkey(),
  131. &owner_b_ta_a.pubkey(),
  132. &owner_a.pubkey(),
  133. &[],
  134. 1_000_000,
  135. )
  136. .unwrap();
  137. // Close Token A
  138. let close_owner_a_ta_a = spl_token::instruction::close_account(
  139. &token_program,
  140. &owner_a_ta_a.pubkey(),
  141. &owner_a.pubkey(),
  142. &owner_a.pubkey(),
  143. &[],
  144. )
  145. .unwrap();
  146. let batch_ix = batch_instruction(vec![
  147. initialize_mint_ix,
  148. initialize_mint_with_freeze_authority_ix,
  149. intialize_owner_a_ta_a,
  150. intialize_owner_b_ta_a,
  151. mint_token_a_to_owner_a,
  152. transfer_token_a_to_owner_b,
  153. close_owner_a_ta_a,
  154. ])
  155. .unwrap();
  156. let tx = Transaction::new_signed_with_payer(
  157. &[
  158. create_mint_a,
  159. create_mint_b,
  160. create_owner_a_ta_a,
  161. create_owner_b_ta_a,
  162. batch_ix,
  163. ],
  164. Some(&context.payer.pubkey()),
  165. &vec![
  166. &context.payer,
  167. &mint_a,
  168. &mint_b,
  169. &owner_a_ta_a,
  170. &owner_b_ta_a,
  171. &mint_authority,
  172. &owner_a,
  173. ],
  174. context.last_blockhash,
  175. );
  176. context.banks_client.process_transaction(tx).await.unwrap();
  177. let mint_a_account = context
  178. .banks_client
  179. .get_account(mint_a.pubkey())
  180. .await
  181. .unwrap();
  182. assert!(mint_a_account.is_some());
  183. let mint_a_account = spl_token::state::Mint::unpack(&mint_a_account.unwrap().data).unwrap();
  184. assert_eq!(mint_a_account.supply, 1000000);
  185. let mint_b_account = context
  186. .banks_client
  187. .get_account(mint_b.pubkey())
  188. .await
  189. .unwrap();
  190. assert!(mint_b_account.is_some());
  191. let mint_b_account = spl_token::state::Mint::unpack(&mint_b_account.unwrap().data).unwrap();
  192. assert_eq!(mint_b_account.supply, 0);
  193. let owner_b_ta_a_account = context
  194. .banks_client
  195. .get_account(owner_b_ta_a.pubkey())
  196. .await
  197. .unwrap();
  198. assert!(owner_b_ta_a_account.is_some());
  199. let owner_b_ta_a_account =
  200. spl_token::state::Account::unpack(&owner_b_ta_a_account.unwrap().data).unwrap();
  201. assert_eq!(owner_b_ta_a_account.amount, 1000000);
  202. }