|
3 | 3 | use anchor_lang::{AccountDeserialize, InstructionData};
|
4 | 4 | use anchor_spl::token::TokenAccount;
|
5 | 5 | use light_compressed_token_sdk::{
|
6 |
| - instructions::transfer::account_metas::{ |
7 |
| - get_transfer_instruction_account_metas, TokenAccountsMetaConfig, |
| 6 | + instructions::{ |
| 7 | + batch_compress::{ |
| 8 | + get_batch_compress_instruction_account_metas, BatchCompressMetaConfig, Recipient, |
| 9 | + }, |
| 10 | + transfer::account_metas::{ |
| 11 | + get_transfer_instruction_account_metas, TokenAccountsMetaConfig, |
| 12 | + }, |
8 | 13 | },
|
9 | 14 | token_pool::get_token_pool_pda,
|
10 | 15 | TokenAccountMeta, SPL_TOKEN_PROGRAM_ID,
|
@@ -447,3 +452,170 @@ async fn decompress_compressed_tokens(
|
447 | 452 | rpc.create_and_send_transaction(&[instruction], &payer.pubkey(), &[payer])
|
448 | 453 | .await
|
449 | 454 | }
|
| 455 | + |
| 456 | +#[tokio::test] |
| 457 | +async fn test_batch_compress() { |
| 458 | + // Initialize the test environment |
| 459 | + let mut rpc = LightProgramTest::new(ProgramTestConfig::new_v2( |
| 460 | + false, |
| 461 | + Some(vec![("sdk_token_test", sdk_token_test::ID)]), |
| 462 | + )) |
| 463 | + .await |
| 464 | + .unwrap(); |
| 465 | + |
| 466 | + let payer = rpc.get_payer().insecure_clone(); |
| 467 | + |
| 468 | + // Create a mint |
| 469 | + let mint_pubkey = create_mint_helper(&mut rpc, &payer).await; |
| 470 | + println!("Created mint: {}", mint_pubkey); |
| 471 | + |
| 472 | + // Create a token account |
| 473 | + let token_account_keypair = Keypair::new(); |
| 474 | + |
| 475 | + create_token_account(&mut rpc, &mint_pubkey, &token_account_keypair, &payer) |
| 476 | + .await |
| 477 | + .unwrap(); |
| 478 | + |
| 479 | + println!("Created token account: {}", token_account_keypair.pubkey()); |
| 480 | + |
| 481 | + // Mint some tokens to the account |
| 482 | + let mint_amount = 2_000_000; // 2000 tokens with 6 decimals |
| 483 | + |
| 484 | + mint_spl_tokens( |
| 485 | + &mut rpc, |
| 486 | + &mint_pubkey, |
| 487 | + &token_account_keypair.pubkey(), |
| 488 | + &payer.pubkey(), // owner |
| 489 | + &payer, // mint authority |
| 490 | + mint_amount, |
| 491 | + false, // not token22 |
| 492 | + ) |
| 493 | + .await |
| 494 | + .unwrap(); |
| 495 | + |
| 496 | + println!("Minted {} tokens to account", mint_amount); |
| 497 | + |
| 498 | + // Create multiple recipients for batch compression |
| 499 | + let recipient1 = Keypair::new().pubkey(); |
| 500 | + let recipient2 = Keypair::new().pubkey(); |
| 501 | + let recipient3 = Keypair::new().pubkey(); |
| 502 | + |
| 503 | + let recipients = vec![ |
| 504 | + Recipient { |
| 505 | + pubkey: recipient1, |
| 506 | + amount: 100_000, |
| 507 | + }, |
| 508 | + Recipient { |
| 509 | + pubkey: recipient2, |
| 510 | + amount: 200_000, |
| 511 | + }, |
| 512 | + Recipient { |
| 513 | + pubkey: recipient3, |
| 514 | + amount: 300_000, |
| 515 | + }, |
| 516 | + ]; |
| 517 | + |
| 518 | + let total_batch_amount: u64 = recipients.iter().map(|r| r.amount).sum(); |
| 519 | + |
| 520 | + // Perform batch compression |
| 521 | + batch_compress_spl_tokens( |
| 522 | + &mut rpc, |
| 523 | + &payer, |
| 524 | + recipients, |
| 525 | + mint_pubkey, |
| 526 | + token_account_keypair.pubkey(), |
| 527 | + ) |
| 528 | + .await |
| 529 | + .unwrap(); |
| 530 | + |
| 531 | + println!( |
| 532 | + "Batch compressed {} tokens to {} recipients successfully", |
| 533 | + total_batch_amount, 3 |
| 534 | + ); |
| 535 | + |
| 536 | + // Verify each recipient received their compressed tokens |
| 537 | + for (i, recipient) in [recipient1, recipient2, recipient3].iter().enumerate() { |
| 538 | + let compressed_accounts = rpc |
| 539 | + .indexer() |
| 540 | + .unwrap() |
| 541 | + .get_compressed_token_accounts_by_owner(recipient, None, None) |
| 542 | + .await |
| 543 | + .unwrap() |
| 544 | + .value |
| 545 | + .items; |
| 546 | + |
| 547 | + assert!( |
| 548 | + !compressed_accounts.is_empty(), |
| 549 | + "Recipient {} should have compressed tokens", |
| 550 | + i + 1 |
| 551 | + ); |
| 552 | + |
| 553 | + let compressed_account = &compressed_accounts[0]; |
| 554 | + assert_eq!(compressed_account.token.owner, *recipient); |
| 555 | + assert_eq!(compressed_account.token.mint, mint_pubkey); |
| 556 | + |
| 557 | + let expected_amount = match i { |
| 558 | + 0 => 100_000, |
| 559 | + 1 => 200_000, |
| 560 | + 2 => 300_000, |
| 561 | + _ => unreachable!(), |
| 562 | + }; |
| 563 | + assert_eq!(compressed_account.token.amount, expected_amount); |
| 564 | + |
| 565 | + println!( |
| 566 | + "Verified recipient {} received {} compressed tokens", |
| 567 | + i + 1, |
| 568 | + compressed_account.token.amount |
| 569 | + ); |
| 570 | + } |
| 571 | + |
| 572 | + println!("Batch compression test completed successfully!"); |
| 573 | +} |
| 574 | + |
| 575 | +async fn batch_compress_spl_tokens( |
| 576 | + rpc: &mut LightProgramTest, |
| 577 | + payer: &Keypair, |
| 578 | + recipients: Vec<Recipient>, |
| 579 | + mint: Pubkey, |
| 580 | + token_account: Pubkey, |
| 581 | +) -> Result<Signature, RpcError> { |
| 582 | + let mut remaining_accounts = PackedAccounts::default(); |
| 583 | + let token_pool_pda = get_token_pool_pda(&mint); |
| 584 | + println!("token_pool_pda {:?}", token_pool_pda); |
| 585 | + // Use batch compress account metas |
| 586 | + let config = BatchCompressMetaConfig::new_client( |
| 587 | + token_pool_pda, |
| 588 | + token_account, |
| 589 | + SPL_TOKEN_PROGRAM_ID.into(), |
| 590 | + rpc.get_random_state_tree_info().unwrap().tree, |
| 591 | + false, // with_lamports |
| 592 | + ); |
| 593 | + |
| 594 | + remaining_accounts.add_pre_accounts_signer_mut(payer.pubkey()); |
| 595 | + let metas = get_batch_compress_instruction_account_metas(config); |
| 596 | + remaining_accounts.add_pre_accounts_metas(metas.as_slice()); |
| 597 | + |
| 598 | + let output_tree_index = rpc |
| 599 | + .get_random_state_tree_info() |
| 600 | + .unwrap() |
| 601 | + .pack_output_tree_index(&mut remaining_accounts) |
| 602 | + .unwrap(); |
| 603 | + |
| 604 | + let (remaining_accounts, _, _) = remaining_accounts.to_account_metas(); |
| 605 | + |
| 606 | + let instruction = Instruction { |
| 607 | + program_id: sdk_token_test::ID, |
| 608 | + accounts: [remaining_accounts].concat(), |
| 609 | + data: sdk_token_test::instruction::BatchCompressTokens { |
| 610 | + recipients, |
| 611 | + _output_tree_index: output_tree_index, |
| 612 | + _mint: mint, |
| 613 | + token_pool_index: 0, // Default pool index |
| 614 | + token_pool_bump: 255, // Default bump |
| 615 | + } |
| 616 | + .data(), |
| 617 | + }; |
| 618 | + |
| 619 | + rpc.create_and_send_transaction(&[instruction], &payer.pubkey(), &[payer]) |
| 620 | + .await |
| 621 | +} |
0 commit comments