batch.rs 6.2 KB

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