batch.rs 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763
  1. mod setup;
  2. use {
  3. crate::setup::TOKEN_PROGRAM_ID,
  4. agave_feature_set::FeatureSet,
  5. mollusk_svm::{result::Check, Mollusk},
  6. pinocchio_token_interface::{
  7. native_mint,
  8. state::{
  9. account::Account as TokenAccount, account_state::AccountState, load_mut_unchecked,
  10. mint::Mint,
  11. },
  12. },
  13. solana_account::Account,
  14. solana_instruction::{AccountMeta, Instruction},
  15. solana_keypair::Keypair,
  16. solana_program_error::ProgramError,
  17. solana_program_pack::Pack,
  18. solana_program_test::{tokio, ProgramTest},
  19. solana_pubkey::Pubkey,
  20. solana_rent::Rent,
  21. solana_sdk_ids::bpf_loader_upgradeable,
  22. solana_signer::Signer,
  23. solana_system_interface::instruction::create_account,
  24. solana_transaction::Transaction,
  25. };
  26. fn batch_instruction(instructions: Vec<Instruction>) -> Result<Instruction, ProgramError> {
  27. // Create a `Vec` of ordered `AccountMeta`s
  28. let mut accounts: Vec<AccountMeta> = vec![];
  29. // Start with the batch discriminator
  30. let mut data: Vec<u8> = vec![0xff];
  31. for instruction in instructions {
  32. // Error out on non-token IX.
  33. if instruction.program_id.ne(&spl_token::ID) {
  34. return Err(ProgramError::IncorrectProgramId);
  35. }
  36. data.push(instruction.accounts.len() as u8);
  37. data.push(instruction.data.len() as u8);
  38. data.extend_from_slice(&instruction.data);
  39. accounts.extend_from_slice(&instruction.accounts);
  40. }
  41. Ok(Instruction {
  42. program_id: spl_token::ID,
  43. data,
  44. accounts,
  45. })
  46. }
  47. #[tokio::test]
  48. async fn batch_initialize_mint_transfer_close() {
  49. let context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None)
  50. .start_with_context()
  51. .await;
  52. let rent = context.banks_client.get_rent().await.unwrap();
  53. let mint_len = spl_token::state::Mint::LEN;
  54. let mint_rent = rent.minimum_balance(mint_len);
  55. let account_len = spl_token::state::Account::LEN;
  56. let account_rent = rent.minimum_balance(account_len);
  57. // Create a mint
  58. let mint_a = Keypair::new();
  59. let mint_authority = Keypair::new();
  60. let create_mint_a = create_account(
  61. &context.payer.pubkey(),
  62. &mint_a.pubkey(),
  63. mint_rent,
  64. mint_len as u64,
  65. &TOKEN_PROGRAM_ID,
  66. );
  67. let initialize_mint_ix = spl_token::instruction::initialize_mint(
  68. &TOKEN_PROGRAM_ID,
  69. &mint_a.pubkey(),
  70. &mint_authority.pubkey(),
  71. None,
  72. 6,
  73. )
  74. .unwrap();
  75. // Create a mint 2 with a freeze authority
  76. let mint_b = Keypair::new();
  77. let freeze_authority = Pubkey::new_unique();
  78. let create_mint_b = create_account(
  79. &context.payer.pubkey(),
  80. &mint_b.pubkey(),
  81. mint_rent,
  82. mint_len as u64,
  83. &TOKEN_PROGRAM_ID,
  84. );
  85. let initialize_mint_with_freeze_authority_ix = spl_token::instruction::initialize_mint2(
  86. &TOKEN_PROGRAM_ID,
  87. &mint_b.pubkey(),
  88. &mint_authority.pubkey(),
  89. Some(&freeze_authority),
  90. 6,
  91. )
  92. .unwrap();
  93. // Create 2 token accounts for mint A and 1 for mint B
  94. let owner_a = Keypair::new();
  95. let owner_b = Keypair::new();
  96. let owner_a_ta_a = Keypair::new();
  97. let owner_b_ta_a = Keypair::new();
  98. let create_owner_a_ta_a = create_account(
  99. &context.payer.pubkey(),
  100. &owner_a_ta_a.pubkey(),
  101. account_rent,
  102. account_len as u64,
  103. &TOKEN_PROGRAM_ID,
  104. );
  105. let create_owner_b_ta_a = create_account(
  106. &context.payer.pubkey(),
  107. &owner_b_ta_a.pubkey(),
  108. account_rent,
  109. account_len as u64,
  110. &TOKEN_PROGRAM_ID,
  111. );
  112. let intialize_owner_a_ta_a = spl_token::instruction::initialize_account3(
  113. &TOKEN_PROGRAM_ID,
  114. &owner_a_ta_a.pubkey(),
  115. &mint_a.pubkey(),
  116. &owner_a.pubkey(),
  117. )
  118. .unwrap();
  119. let intialize_owner_b_ta_a = spl_token::instruction::initialize_account3(
  120. &TOKEN_PROGRAM_ID,
  121. &owner_b_ta_a.pubkey(),
  122. &mint_a.pubkey(),
  123. &owner_b.pubkey(),
  124. )
  125. .unwrap();
  126. // Mint Token A to Owner A
  127. let mint_token_a_to_owner_a = spl_token::instruction::mint_to(
  128. &TOKEN_PROGRAM_ID,
  129. &mint_a.pubkey(),
  130. &owner_a_ta_a.pubkey(),
  131. &mint_authority.pubkey(),
  132. &[],
  133. 1_000_000,
  134. )
  135. .unwrap();
  136. // Transfer Token A from Owner A to Owner B
  137. let transfer_token_a_to_owner_b = spl_token::instruction::transfer(
  138. &TOKEN_PROGRAM_ID,
  139. &owner_a_ta_a.pubkey(),
  140. &owner_b_ta_a.pubkey(),
  141. &owner_a.pubkey(),
  142. &[],
  143. 1_000_000,
  144. )
  145. .unwrap();
  146. // Close Token A
  147. let close_owner_a_ta_a = spl_token::instruction::close_account(
  148. &TOKEN_PROGRAM_ID,
  149. &owner_a_ta_a.pubkey(),
  150. &owner_a.pubkey(),
  151. &owner_a.pubkey(),
  152. &[],
  153. )
  154. .unwrap();
  155. let batch_ix = batch_instruction(vec![
  156. initialize_mint_ix,
  157. initialize_mint_with_freeze_authority_ix,
  158. intialize_owner_a_ta_a,
  159. intialize_owner_b_ta_a,
  160. mint_token_a_to_owner_a,
  161. transfer_token_a_to_owner_b,
  162. close_owner_a_ta_a,
  163. ])
  164. .unwrap();
  165. let tx = Transaction::new_signed_with_payer(
  166. &[
  167. create_mint_a,
  168. create_mint_b,
  169. create_owner_a_ta_a,
  170. create_owner_b_ta_a,
  171. batch_ix,
  172. ],
  173. Some(&context.payer.pubkey()),
  174. &vec![
  175. &context.payer,
  176. &mint_a,
  177. &mint_b,
  178. &owner_a_ta_a,
  179. &owner_b_ta_a,
  180. &mint_authority,
  181. &owner_a,
  182. ],
  183. context.last_blockhash,
  184. );
  185. context.banks_client.process_transaction(tx).await.unwrap();
  186. let mint_a_account = context
  187. .banks_client
  188. .get_account(mint_a.pubkey())
  189. .await
  190. .unwrap();
  191. assert!(mint_a_account.is_some());
  192. let mint_a_account = spl_token::state::Mint::unpack(&mint_a_account.unwrap().data).unwrap();
  193. assert_eq!(mint_a_account.supply, 1000000);
  194. let mint_b_account = context
  195. .banks_client
  196. .get_account(mint_b.pubkey())
  197. .await
  198. .unwrap();
  199. assert!(mint_b_account.is_some());
  200. let mint_b_account = spl_token::state::Mint::unpack(&mint_b_account.unwrap().data).unwrap();
  201. assert_eq!(mint_b_account.supply, 0);
  202. let owner_b_ta_a_account = context
  203. .banks_client
  204. .get_account(owner_b_ta_a.pubkey())
  205. .await
  206. .unwrap();
  207. assert!(owner_b_ta_a_account.is_some());
  208. let owner_b_ta_a_account =
  209. spl_token::state::Account::unpack(&owner_b_ta_a_account.unwrap().data).unwrap();
  210. assert_eq!(owner_b_ta_a_account.amount, 1000000);
  211. let closed_owner_a_ta_a = context
  212. .banks_client
  213. .get_account(owner_a_ta_a.pubkey())
  214. .await
  215. .unwrap();
  216. assert!(closed_owner_a_ta_a.is_none());
  217. }
  218. fn create_mint(
  219. mint_authority: &Pubkey,
  220. supply: u64,
  221. decimals: u8,
  222. program_owner: &Pubkey,
  223. ) -> Account {
  224. let space = size_of::<Mint>();
  225. let lamports = Rent::default().minimum_balance(space);
  226. let mut data: Vec<u8> = vec![0u8; space];
  227. let mint = unsafe { load_mut_unchecked::<Mint>(data.as_mut_slice()).unwrap() };
  228. mint.set_initialized();
  229. mint.set_supply(supply);
  230. mint.set_mint_authority(mint_authority.as_array());
  231. mint.decimals = decimals;
  232. Account {
  233. lamports,
  234. data,
  235. owner: *program_owner,
  236. executable: false,
  237. ..Default::default()
  238. }
  239. }
  240. fn create_token_account(
  241. mint: &Pubkey,
  242. owner: &Pubkey,
  243. is_native: bool,
  244. amount: u64,
  245. program_owner: &Pubkey,
  246. ) -> Account {
  247. let space = size_of::<TokenAccount>();
  248. let mut lamports = Rent::default().minimum_balance(space);
  249. let mut data: Vec<u8> = vec![0u8; space];
  250. let token = unsafe { load_mut_unchecked::<TokenAccount>(data.as_mut_slice()).unwrap() };
  251. token.set_account_state(AccountState::Initialized);
  252. token.mint = *mint.as_array();
  253. token.owner = *owner.as_array();
  254. token.set_amount(amount);
  255. token.set_native(is_native);
  256. token.set_native_amount(amount);
  257. if is_native {
  258. lamports = lamports.saturating_add(amount);
  259. }
  260. Account {
  261. lamports,
  262. data,
  263. owner: *program_owner,
  264. executable: false,
  265. ..Default::default()
  266. }
  267. }
  268. /// Creates a Mollusk instance with the default feature set, excluding the
  269. /// `bpf_account_data_direct_mapping` feature.
  270. fn mollusk() -> Mollusk {
  271. let feature_set = {
  272. let mut fs = FeatureSet::all_enabled();
  273. fs.active_mut()
  274. .remove(&agave_feature_set::bpf_account_data_direct_mapping::id());
  275. fs
  276. };
  277. let mut mollusk = Mollusk {
  278. feature_set,
  279. ..Default::default()
  280. };
  281. mollusk.add_program(
  282. &TOKEN_PROGRAM_ID,
  283. "pinocchio_token_program",
  284. &bpf_loader_upgradeable::id(),
  285. );
  286. mollusk
  287. }
  288. #[tokio::test]
  289. async fn batch_transfer() {
  290. let authority_key = Pubkey::new_unique();
  291. let mint_key = Pubkey::new_unique();
  292. // source account
  293. // - amount: 1_000_000_000
  294. // - mint: mint_key
  295. // - is_native: false
  296. // - program_id: TOKEN_PROGRAM_ID
  297. let source_account_key = Pubkey::new_unique();
  298. let source_account = create_token_account(
  299. &mint_key,
  300. &authority_key,
  301. false,
  302. 1_000_000_000,
  303. &TOKEN_PROGRAM_ID,
  304. );
  305. // destination account
  306. // - amount: 0
  307. // - mint: mint_key
  308. // - is_native: false
  309. // - program_id: TOKEN_PROGRAM_ID
  310. let destination_account_key = Pubkey::new_unique();
  311. let destination_account =
  312. create_token_account(&mint_key, &authority_key, false, 0, &TOKEN_PROGRAM_ID);
  313. let instruction = batch_instruction(vec![spl_token::instruction::transfer(
  314. &TOKEN_PROGRAM_ID,
  315. &source_account_key,
  316. &destination_account_key,
  317. &authority_key,
  318. &[],
  319. 500_000_000,
  320. )
  321. .unwrap()])
  322. .unwrap();
  323. // Expected to succeed.
  324. mollusk().process_and_validate_instruction_chain(
  325. &[(&instruction, &[Check::success(), Check::all_rent_exempt()])],
  326. &[
  327. (source_account_key, source_account),
  328. (destination_account_key, destination_account),
  329. (
  330. authority_key,
  331. Account {
  332. lamports: Rent::default().minimum_balance(0),
  333. ..Default::default()
  334. },
  335. ),
  336. ],
  337. );
  338. }
  339. #[tokio::test]
  340. async fn batch_fail_transfer_with_invalid_program_owner() {
  341. let invalid_program_id = Pubkey::new_from_array([2; 32]);
  342. let native_mint = Pubkey::new_from_array(native_mint::ID);
  343. let authority_key = Pubkey::new_unique();
  344. // source account
  345. // - amount: 1_000_000_000
  346. // - mint: native_mint
  347. // - is_native: true
  348. // - program_id: invalid_program_id
  349. let source_account_key = Pubkey::new_unique();
  350. let source_account = create_token_account(
  351. &native_mint,
  352. &authority_key,
  353. true,
  354. 1_000_000_000,
  355. &invalid_program_id,
  356. );
  357. // destination account
  358. // - amount: 0
  359. // - mint: native_mint
  360. // - is_native: true
  361. // - program_id: TOKEN_PROGRAM_ID
  362. let destination_account_key = Pubkey::new_unique();
  363. let destination_account =
  364. create_token_account(&native_mint, &authority_key, true, 0, &TOKEN_PROGRAM_ID);
  365. let instruction = batch_instruction(vec![spl_token::instruction::transfer(
  366. &TOKEN_PROGRAM_ID,
  367. &source_account_key,
  368. &destination_account_key,
  369. &authority_key,
  370. &[],
  371. 500_000_000,
  372. )
  373. .unwrap()])
  374. .unwrap();
  375. // Expected to fail since source account has an invalid program owner.
  376. mollusk().process_and_validate_instruction_chain(
  377. &[(
  378. &instruction,
  379. &[
  380. Check::err(ProgramError::IncorrectProgramId),
  381. Check::all_rent_exempt(),
  382. ],
  383. )],
  384. &[
  385. (source_account_key, source_account),
  386. (destination_account_key, destination_account),
  387. (
  388. authority_key,
  389. Account {
  390. lamports: Rent::default().minimum_balance(0),
  391. ..Default::default()
  392. },
  393. ),
  394. ],
  395. );
  396. }
  397. #[tokio::test]
  398. async fn batch_fail_transfer_checked_with_invalid_program_owner() {
  399. let invalid_program_id = Pubkey::new_from_array([2; 32]);
  400. let authority_key = Pubkey::new_unique();
  401. let native_mint_key = Pubkey::new_from_array(native_mint::ID);
  402. let native_mint = create_mint(&authority_key, 5_000_000_000, 9, &TOKEN_PROGRAM_ID);
  403. // source account
  404. // - amount: 1_000_000_000
  405. // - mint: native_mint
  406. // - is_native: true
  407. // - program_id: invalid_program_id
  408. let source_account_key = Pubkey::new_unique();
  409. let source_account = create_token_account(
  410. &native_mint_key,
  411. &authority_key,
  412. true,
  413. 1_000_000_000,
  414. &invalid_program_id,
  415. );
  416. // destination account
  417. // - amount: 0
  418. // - mint: native_mint
  419. // - is_native: true
  420. // - program_id: TOKEN_PROGRAM_ID
  421. let destination_account_key = Pubkey::new_unique();
  422. let destination_account =
  423. create_token_account(&native_mint_key, &authority_key, true, 0, &TOKEN_PROGRAM_ID);
  424. let instruction = batch_instruction(vec![spl_token::instruction::transfer_checked(
  425. &TOKEN_PROGRAM_ID,
  426. &source_account_key,
  427. &native_mint_key,
  428. &destination_account_key,
  429. &authority_key,
  430. &[],
  431. 500_000_000,
  432. 9,
  433. )
  434. .unwrap()])
  435. .unwrap();
  436. // Expected to fail since source account has an invalid program owner.
  437. mollusk().process_and_validate_instruction_chain(
  438. &[(
  439. &instruction,
  440. &[
  441. Check::err(ProgramError::IncorrectProgramId),
  442. Check::all_rent_exempt(),
  443. ],
  444. )],
  445. &[
  446. (source_account_key, source_account),
  447. (destination_account_key, destination_account),
  448. (native_mint_key, native_mint),
  449. (
  450. authority_key,
  451. Account {
  452. lamports: Rent::default().minimum_balance(0),
  453. ..Default::default()
  454. },
  455. ),
  456. ],
  457. );
  458. }
  459. #[tokio::test]
  460. async fn batch_fail_swap_tokens_with_invalid_program_owner() {
  461. let native_mint = Pubkey::new_from_array(native_mint::ID);
  462. let invalid_program_id = Pubkey::new_from_array([2; 32]);
  463. let authority_key = Pubkey::new_unique();
  464. // Account A
  465. // - amount: 1_000
  466. // - mint: native_mint
  467. // - is_native: false
  468. // - program_id: invalid_program_id
  469. let account_a_key = Pubkey::new_unique();
  470. let account_a = create_token_account(
  471. &native_mint,
  472. &authority_key,
  473. false,
  474. 1_000,
  475. &invalid_program_id,
  476. );
  477. // Account B
  478. // - amount: 0
  479. // - mint: native_mint
  480. // - is_native: true
  481. // - program_id: TOKEN_PROGRAM_ID
  482. let account_b_key = Pubkey::new_unique();
  483. let account_b = create_token_account(&native_mint, &authority_key, true, 0, &TOKEN_PROGRAM_ID);
  484. // Account C
  485. // - amount: 0
  486. // - mint: native_mint
  487. // - is_native: true
  488. // - program_id: TOKEN_PROGRAM_ID
  489. let account_c_key = Pubkey::new_unique();
  490. let account_c =
  491. create_token_account(&native_mint, &authority_key, true, 1_000, &TOKEN_PROGRAM_ID);
  492. // Batch instruction to swap tokens
  493. // - transfer 300 from account A to account B
  494. // - transfer 300 from account C to account A
  495. let instruction = batch_instruction(vec![
  496. spl_token::instruction::sync_native(&TOKEN_PROGRAM_ID, &account_b_key).unwrap(),
  497. spl_token::instruction::sync_native(&TOKEN_PROGRAM_ID, &account_c_key).unwrap(),
  498. spl_token::instruction::transfer(
  499. &TOKEN_PROGRAM_ID,
  500. &account_a_key,
  501. &account_b_key,
  502. &authority_key,
  503. &[],
  504. 300,
  505. )
  506. .unwrap(),
  507. spl_token::instruction::transfer(
  508. &TOKEN_PROGRAM_ID,
  509. &account_c_key,
  510. &account_a_key,
  511. &authority_key,
  512. &[],
  513. 300,
  514. )
  515. .unwrap(),
  516. ])
  517. .unwrap();
  518. // Expected to fail since account A has an invalid program owner.
  519. mollusk().process_and_validate_instruction_chain(
  520. &[(
  521. &instruction,
  522. &[
  523. Check::err(ProgramError::IncorrectProgramId),
  524. Check::all_rent_exempt(),
  525. ],
  526. )],
  527. &[
  528. (account_a_key, account_a),
  529. (account_b_key, account_b),
  530. (account_c_key, account_c),
  531. (
  532. authority_key,
  533. Account {
  534. lamports: Rent::default().minimum_balance(0),
  535. ..Default::default()
  536. },
  537. ),
  538. ],
  539. );
  540. }
  541. #[tokio::test]
  542. async fn batch_fail_mint_to_with_invalid_program_owner() {
  543. let invalid_program_id = Pubkey::new_from_array([2; 32]);
  544. let authority_key = Pubkey::new_unique();
  545. let mint_key = Pubkey::new_unique();
  546. let mint = create_mint(&authority_key, 0, 0, &TOKEN_PROGRAM_ID);
  547. // account A (invalid)
  548. // - amount: 1_000_000_000
  549. // - mint: native_mint
  550. // - is_native: false
  551. // - program_id: invalid_program_id
  552. let account_a_key = Pubkey::new_unique();
  553. let account_a = create_token_account(&mint_key, &authority_key, false, 0, &invalid_program_id);
  554. // account B
  555. // - amount: 0
  556. // - mint: native_mint
  557. // - is_native: false
  558. // - program_id: TOKEN_PROGRAM_ID
  559. let account_b_key = Pubkey::new_unique();
  560. let account_b = create_token_account(&mint_key, &authority_key, false, 0, &TOKEN_PROGRAM_ID);
  561. let instruction = batch_instruction(vec![
  562. spl_token::instruction::mint_to(
  563. &TOKEN_PROGRAM_ID,
  564. &mint_key,
  565. &account_a_key,
  566. &authority_key,
  567. &[],
  568. 1_000_000_000,
  569. )
  570. .unwrap(),
  571. spl_token::instruction::mint_to(
  572. &TOKEN_PROGRAM_ID,
  573. &mint_key,
  574. &account_b_key,
  575. &authority_key,
  576. &[],
  577. 1_000_000_000,
  578. )
  579. .unwrap(),
  580. ])
  581. .unwrap();
  582. // Expected to fail since source account has an invalid program owner.
  583. mollusk().process_and_validate_instruction_chain(
  584. &[(
  585. &instruction,
  586. &[
  587. Check::err(ProgramError::IncorrectProgramId),
  588. Check::all_rent_exempt(),
  589. ],
  590. )],
  591. &[
  592. (mint_key, mint),
  593. (account_a_key, account_a),
  594. (account_b_key, account_b),
  595. (
  596. authority_key,
  597. Account {
  598. lamports: Rent::default().minimum_balance(0),
  599. ..Default::default()
  600. },
  601. ),
  602. ],
  603. );
  604. }
  605. #[tokio::test]
  606. async fn batch_fail_burn_with_invalid_program_owner() {
  607. let invalid_program_id = Pubkey::new_from_array([2; 32]);
  608. let authority_key = Pubkey::new_unique();
  609. let mint_key = Pubkey::new_unique();
  610. let mint = create_mint(&authority_key, 2_000_000_000, 0, &TOKEN_PROGRAM_ID);
  611. // account A
  612. // - amount: 0
  613. // - mint: native_mint
  614. // - is_native: false
  615. // - program_id: TOKEN_PROGRAM_ID
  616. let account_a_key = Pubkey::new_unique();
  617. let account_a = create_token_account(&mint_key, &authority_key, false, 0, &TOKEN_PROGRAM_ID);
  618. // account B (invalid)
  619. // - amount: 1_000_000_000
  620. // - mint: native_mint
  621. // - is_native: false
  622. // - program_id: invalid_program_id
  623. let account_b_key = Pubkey::new_unique();
  624. let account_b = create_token_account(
  625. &mint_key,
  626. &authority_key,
  627. false,
  628. 1_000_000_000,
  629. &invalid_program_id,
  630. );
  631. let instruction = batch_instruction(vec![
  632. spl_token::instruction::mint_to(
  633. &TOKEN_PROGRAM_ID,
  634. &mint_key,
  635. &account_a_key,
  636. &authority_key,
  637. &[],
  638. 1_000_000_000,
  639. )
  640. .unwrap(),
  641. spl_token::instruction::mint_to(
  642. &TOKEN_PROGRAM_ID,
  643. &mint_key,
  644. &account_b_key,
  645. &authority_key,
  646. &[],
  647. 1_000_000_000,
  648. )
  649. .unwrap(),
  650. spl_token::instruction::burn(
  651. &TOKEN_PROGRAM_ID,
  652. &account_a_key,
  653. &mint_key,
  654. &authority_key,
  655. &[],
  656. 1_000_000_000,
  657. )
  658. .unwrap(),
  659. spl_token::instruction::burn(
  660. &TOKEN_PROGRAM_ID,
  661. &account_b_key,
  662. &mint_key,
  663. &authority_key,
  664. &[],
  665. 1_000_000_000,
  666. )
  667. .unwrap(),
  668. ])
  669. .unwrap();
  670. // Expected to fail since source account has an invalid program owner.
  671. mollusk().process_and_validate_instruction_chain(
  672. &[(
  673. &instruction,
  674. &[
  675. Check::err(ProgramError::IncorrectProgramId),
  676. Check::all_rent_exempt(),
  677. ],
  678. )],
  679. &[
  680. (mint_key, mint),
  681. (account_a_key, account_a),
  682. (account_b_key, account_b),
  683. (
  684. authority_key,
  685. Account {
  686. lamports: Rent::default().minimum_balance(0),
  687. ..Default::default()
  688. },
  689. ),
  690. ],
  691. );
  692. }