batch.rs 6.2 KB

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