|
@@ -2,12 +2,24 @@ mod setup;
|
|
|
|
|
|
use {
|
|
|
crate::setup::TOKEN_PROGRAM_ID,
|
|
|
+ agave_feature_set::FeatureSet,
|
|
|
+ mollusk_svm::{result::Check, Mollusk},
|
|
|
+ pinocchio_token_interface::{
|
|
|
+ native_mint,
|
|
|
+ state::{
|
|
|
+ account::Account as TokenAccount, account_state::AccountState, load_mut_unchecked,
|
|
|
+ mint::Mint,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ solana_account::Account,
|
|
|
solana_instruction::{AccountMeta, Instruction},
|
|
|
solana_keypair::Keypair,
|
|
|
solana_program_error::ProgramError,
|
|
|
solana_program_pack::Pack,
|
|
|
solana_program_test::{tokio, ProgramTest},
|
|
|
solana_pubkey::Pubkey,
|
|
|
+ solana_rent::Rent,
|
|
|
+ solana_sdk_ids::bpf_loader_upgradeable,
|
|
|
solana_signer::Signer,
|
|
|
solana_system_interface::instruction::create_account,
|
|
|
solana_transaction::Transaction,
|
|
@@ -40,7 +52,7 @@ fn batch_instruction(instructions: Vec<Instruction>) -> Result<Instruction, Prog
|
|
|
}
|
|
|
|
|
|
#[tokio::test]
|
|
|
-async fn batch() {
|
|
|
+async fn batch_initialize_mint_transfer_close() {
|
|
|
let context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None)
|
|
|
.start_with_context()
|
|
|
.await;
|
|
@@ -218,4 +230,534 @@ async fn batch() {
|
|
|
let owner_b_ta_a_account =
|
|
|
spl_token::state::Account::unpack(&owner_b_ta_a_account.unwrap().data).unwrap();
|
|
|
assert_eq!(owner_b_ta_a_account.amount, 1000000);
|
|
|
+
|
|
|
+ let closed_owner_a_ta_a = context
|
|
|
+ .banks_client
|
|
|
+ .get_account(owner_a_ta_a.pubkey())
|
|
|
+ .await
|
|
|
+ .unwrap();
|
|
|
+ assert!(closed_owner_a_ta_a.is_none());
|
|
|
+}
|
|
|
+
|
|
|
+fn create_mint(
|
|
|
+ mint_authority: &Pubkey,
|
|
|
+ supply: u64,
|
|
|
+ decimals: u8,
|
|
|
+ program_owner: &Pubkey,
|
|
|
+) -> Account {
|
|
|
+ let space = size_of::<Mint>();
|
|
|
+ let lamports = Rent::default().minimum_balance(space);
|
|
|
+
|
|
|
+ let mut data: Vec<u8> = vec![0u8; space];
|
|
|
+ let mint = unsafe { load_mut_unchecked::<Mint>(data.as_mut_slice()).unwrap() };
|
|
|
+ mint.set_initialized();
|
|
|
+ mint.set_supply(supply);
|
|
|
+ mint.set_mint_authority(mint_authority.as_array());
|
|
|
+ mint.decimals = decimals;
|
|
|
+
|
|
|
+ Account {
|
|
|
+ lamports,
|
|
|
+ data,
|
|
|
+ owner: *program_owner,
|
|
|
+ executable: false,
|
|
|
+ ..Default::default()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+fn create_token_account(
|
|
|
+ mint: &Pubkey,
|
|
|
+ owner: &Pubkey,
|
|
|
+ is_native: bool,
|
|
|
+ amount: u64,
|
|
|
+ program_owner: &Pubkey,
|
|
|
+) -> Account {
|
|
|
+ let space = size_of::<TokenAccount>();
|
|
|
+ let mut lamports = Rent::default().minimum_balance(space);
|
|
|
+
|
|
|
+ let mut data: Vec<u8> = vec![0u8; space];
|
|
|
+ let token = unsafe { load_mut_unchecked::<TokenAccount>(data.as_mut_slice()).unwrap() };
|
|
|
+ token.set_account_state(AccountState::Initialized);
|
|
|
+ token.mint = *mint.as_array();
|
|
|
+ token.owner = *owner.as_array();
|
|
|
+ token.set_amount(amount);
|
|
|
+ token.set_native(is_native);
|
|
|
+ token.set_native_amount(amount);
|
|
|
+
|
|
|
+ if is_native {
|
|
|
+ lamports = lamports.saturating_add(amount);
|
|
|
+ }
|
|
|
+
|
|
|
+ Account {
|
|
|
+ lamports,
|
|
|
+ data,
|
|
|
+ owner: *program_owner,
|
|
|
+ executable: false,
|
|
|
+ ..Default::default()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/// Creates a Mollusk instance with the default feature set, excluding the
|
|
|
+/// `bpf_account_data_direct_mapping` feature.
|
|
|
+fn mollusk() -> Mollusk {
|
|
|
+ let feature_set = {
|
|
|
+ let mut fs = FeatureSet::all_enabled();
|
|
|
+ fs.active_mut()
|
|
|
+ .remove(&agave_feature_set::bpf_account_data_direct_mapping::id());
|
|
|
+ fs
|
|
|
+ };
|
|
|
+ let mut mollusk = Mollusk {
|
|
|
+ feature_set,
|
|
|
+ ..Default::default()
|
|
|
+ };
|
|
|
+ mollusk.add_program(
|
|
|
+ &TOKEN_PROGRAM_ID,
|
|
|
+ "pinocchio_token_program",
|
|
|
+ &bpf_loader_upgradeable::id(),
|
|
|
+ );
|
|
|
+ mollusk
|
|
|
+}
|
|
|
+
|
|
|
+#[tokio::test]
|
|
|
+async fn batch_transfer() {
|
|
|
+ let authority_key = Pubkey::new_unique();
|
|
|
+ let mint_key = Pubkey::new_unique();
|
|
|
+
|
|
|
+ // source account
|
|
|
+ // - amount: 1_000_000_000
|
|
|
+ // - mint: mint_key
|
|
|
+ // - is_native: false
|
|
|
+ // - program_id: TOKEN_PROGRAM_ID
|
|
|
+ let source_account_key = Pubkey::new_unique();
|
|
|
+ let source_account = create_token_account(
|
|
|
+ &mint_key,
|
|
|
+ &authority_key,
|
|
|
+ false,
|
|
|
+ 1_000_000_000,
|
|
|
+ &TOKEN_PROGRAM_ID,
|
|
|
+ );
|
|
|
+
|
|
|
+ // destination account
|
|
|
+ // - amount: 0
|
|
|
+ // - mint: mint_key
|
|
|
+ // - is_native: false
|
|
|
+ // - program_id: TOKEN_PROGRAM_ID
|
|
|
+ let destination_account_key = Pubkey::new_unique();
|
|
|
+ let destination_account =
|
|
|
+ create_token_account(&mint_key, &authority_key, false, 0, &TOKEN_PROGRAM_ID);
|
|
|
+
|
|
|
+ let instruction = batch_instruction(vec![spl_token::instruction::transfer(
|
|
|
+ &TOKEN_PROGRAM_ID,
|
|
|
+ &source_account_key,
|
|
|
+ &destination_account_key,
|
|
|
+ &authority_key,
|
|
|
+ &[],
|
|
|
+ 500_000_000,
|
|
|
+ )
|
|
|
+ .unwrap()])
|
|
|
+ .unwrap();
|
|
|
+
|
|
|
+ // Expected to succeed.
|
|
|
+
|
|
|
+ mollusk().process_and_validate_instruction_chain(
|
|
|
+ &[(&instruction, &[Check::success(), Check::all_rent_exempt()])],
|
|
|
+ &[
|
|
|
+ (source_account_key, source_account),
|
|
|
+ (destination_account_key, destination_account),
|
|
|
+ (
|
|
|
+ authority_key,
|
|
|
+ Account {
|
|
|
+ lamports: Rent::default().minimum_balance(0),
|
|
|
+ ..Default::default()
|
|
|
+ },
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ );
|
|
|
+}
|
|
|
+
|
|
|
+#[tokio::test]
|
|
|
+async fn batch_fail_transfer_with_invalid_program_owner() {
|
|
|
+ let invalid_program_id = Pubkey::new_from_array([2; 32]);
|
|
|
+ let native_mint = Pubkey::new_from_array(native_mint::ID);
|
|
|
+ let authority_key = Pubkey::new_unique();
|
|
|
+
|
|
|
+ // source account
|
|
|
+ // - amount: 1_000_000_000
|
|
|
+ // - mint: native_mint
|
|
|
+ // - is_native: true
|
|
|
+ // - program_id: invalid_program_id
|
|
|
+ let source_account_key = Pubkey::new_unique();
|
|
|
+ let source_account = create_token_account(
|
|
|
+ &native_mint,
|
|
|
+ &authority_key,
|
|
|
+ true,
|
|
|
+ 1_000_000_000,
|
|
|
+ &invalid_program_id,
|
|
|
+ );
|
|
|
+
|
|
|
+ // destination account
|
|
|
+ // - amount: 0
|
|
|
+ // - mint: native_mint
|
|
|
+ // - is_native: true
|
|
|
+ // - program_id: TOKEN_PROGRAM_ID
|
|
|
+ let destination_account_key = Pubkey::new_unique();
|
|
|
+ let destination_account =
|
|
|
+ create_token_account(&native_mint, &authority_key, true, 0, &TOKEN_PROGRAM_ID);
|
|
|
+
|
|
|
+ let instruction = batch_instruction(vec![spl_token::instruction::transfer(
|
|
|
+ &TOKEN_PROGRAM_ID,
|
|
|
+ &source_account_key,
|
|
|
+ &destination_account_key,
|
|
|
+ &authority_key,
|
|
|
+ &[],
|
|
|
+ 500_000_000,
|
|
|
+ )
|
|
|
+ .unwrap()])
|
|
|
+ .unwrap();
|
|
|
+
|
|
|
+ // Expected to fail since source account has an invalid program owner.
|
|
|
+
|
|
|
+ mollusk().process_and_validate_instruction_chain(
|
|
|
+ &[(
|
|
|
+ &instruction,
|
|
|
+ &[
|
|
|
+ Check::err(ProgramError::IncorrectProgramId),
|
|
|
+ Check::all_rent_exempt(),
|
|
|
+ ],
|
|
|
+ )],
|
|
|
+ &[
|
|
|
+ (source_account_key, source_account),
|
|
|
+ (destination_account_key, destination_account),
|
|
|
+ (
|
|
|
+ authority_key,
|
|
|
+ Account {
|
|
|
+ lamports: Rent::default().minimum_balance(0),
|
|
|
+ ..Default::default()
|
|
|
+ },
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ );
|
|
|
+}
|
|
|
+
|
|
|
+#[tokio::test]
|
|
|
+async fn batch_fail_transfer_checked_with_invalid_program_owner() {
|
|
|
+ let invalid_program_id = Pubkey::new_from_array([2; 32]);
|
|
|
+ let authority_key = Pubkey::new_unique();
|
|
|
+
|
|
|
+ let native_mint_key = Pubkey::new_from_array(native_mint::ID);
|
|
|
+ let native_mint = create_mint(&authority_key, 5_000_000_000, 9, &TOKEN_PROGRAM_ID);
|
|
|
+
|
|
|
+ // source account
|
|
|
+ // - amount: 1_000_000_000
|
|
|
+ // - mint: native_mint
|
|
|
+ // - is_native: true
|
|
|
+ // - program_id: invalid_program_id
|
|
|
+ let source_account_key = Pubkey::new_unique();
|
|
|
+ let source_account = create_token_account(
|
|
|
+ &native_mint_key,
|
|
|
+ &authority_key,
|
|
|
+ true,
|
|
|
+ 1_000_000_000,
|
|
|
+ &invalid_program_id,
|
|
|
+ );
|
|
|
+
|
|
|
+ // destination account
|
|
|
+ // - amount: 0
|
|
|
+ // - mint: native_mint
|
|
|
+ // - is_native: true
|
|
|
+ // - program_id: TOKEN_PROGRAM_ID
|
|
|
+ let destination_account_key = Pubkey::new_unique();
|
|
|
+ let destination_account =
|
|
|
+ create_token_account(&native_mint_key, &authority_key, true, 0, &TOKEN_PROGRAM_ID);
|
|
|
+
|
|
|
+ let instruction = batch_instruction(vec![spl_token::instruction::transfer_checked(
|
|
|
+ &TOKEN_PROGRAM_ID,
|
|
|
+ &source_account_key,
|
|
|
+ &native_mint_key,
|
|
|
+ &destination_account_key,
|
|
|
+ &authority_key,
|
|
|
+ &[],
|
|
|
+ 500_000_000,
|
|
|
+ 9,
|
|
|
+ )
|
|
|
+ .unwrap()])
|
|
|
+ .unwrap();
|
|
|
+
|
|
|
+ // Expected to fail since source account has an invalid program owner.
|
|
|
+
|
|
|
+ mollusk().process_and_validate_instruction_chain(
|
|
|
+ &[(
|
|
|
+ &instruction,
|
|
|
+ &[
|
|
|
+ Check::err(ProgramError::IncorrectProgramId),
|
|
|
+ Check::all_rent_exempt(),
|
|
|
+ ],
|
|
|
+ )],
|
|
|
+ &[
|
|
|
+ (source_account_key, source_account),
|
|
|
+ (destination_account_key, destination_account),
|
|
|
+ (native_mint_key, native_mint),
|
|
|
+ (
|
|
|
+ authority_key,
|
|
|
+ Account {
|
|
|
+ lamports: Rent::default().minimum_balance(0),
|
|
|
+ ..Default::default()
|
|
|
+ },
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ );
|
|
|
+}
|
|
|
+
|
|
|
+#[tokio::test]
|
|
|
+async fn batch_fail_swap_tokens_with_invalid_program_owner() {
|
|
|
+ let native_mint = Pubkey::new_from_array(native_mint::ID);
|
|
|
+ let invalid_program_id = Pubkey::new_from_array([2; 32]);
|
|
|
+ let authority_key = Pubkey::new_unique();
|
|
|
+
|
|
|
+ // Account A
|
|
|
+ // - amount: 1_000
|
|
|
+ // - mint: native_mint
|
|
|
+ // - is_native: false
|
|
|
+ // - program_id: invalid_program_id
|
|
|
+ let account_a_key = Pubkey::new_unique();
|
|
|
+ let account_a = create_token_account(
|
|
|
+ &native_mint,
|
|
|
+ &authority_key,
|
|
|
+ false,
|
|
|
+ 1_000,
|
|
|
+ &invalid_program_id,
|
|
|
+ );
|
|
|
+
|
|
|
+ // Account B
|
|
|
+ // - amount: 0
|
|
|
+ // - mint: native_mint
|
|
|
+ // - is_native: true
|
|
|
+ // - program_id: TOKEN_PROGRAM_ID
|
|
|
+ let account_b_key = Pubkey::new_unique();
|
|
|
+ let account_b = create_token_account(&native_mint, &authority_key, true, 0, &TOKEN_PROGRAM_ID);
|
|
|
+
|
|
|
+ // Account C
|
|
|
+ // - amount: 0
|
|
|
+ // - mint: native_mint
|
|
|
+ // - is_native: true
|
|
|
+ // - program_id: TOKEN_PROGRAM_ID
|
|
|
+ let account_c_key = Pubkey::new_unique();
|
|
|
+ let account_c =
|
|
|
+ create_token_account(&native_mint, &authority_key, true, 1_000, &TOKEN_PROGRAM_ID);
|
|
|
+
|
|
|
+ // Batch instruction to swap tokens
|
|
|
+ // - transfer 300 from account A to account B
|
|
|
+ // - transfer 300 from account C to account A
|
|
|
+ let instruction = batch_instruction(vec![
|
|
|
+ spl_token::instruction::sync_native(&TOKEN_PROGRAM_ID, &account_b_key).unwrap(),
|
|
|
+ spl_token::instruction::sync_native(&TOKEN_PROGRAM_ID, &account_c_key).unwrap(),
|
|
|
+ spl_token::instruction::transfer(
|
|
|
+ &TOKEN_PROGRAM_ID,
|
|
|
+ &account_a_key,
|
|
|
+ &account_b_key,
|
|
|
+ &authority_key,
|
|
|
+ &[],
|
|
|
+ 300,
|
|
|
+ )
|
|
|
+ .unwrap(),
|
|
|
+ spl_token::instruction::transfer(
|
|
|
+ &TOKEN_PROGRAM_ID,
|
|
|
+ &account_c_key,
|
|
|
+ &account_a_key,
|
|
|
+ &authority_key,
|
|
|
+ &[],
|
|
|
+ 300,
|
|
|
+ )
|
|
|
+ .unwrap(),
|
|
|
+ ])
|
|
|
+ .unwrap();
|
|
|
+
|
|
|
+ // Expected to fail since account A has an invalid program owner.
|
|
|
+
|
|
|
+ mollusk().process_and_validate_instruction_chain(
|
|
|
+ &[(
|
|
|
+ &instruction,
|
|
|
+ &[
|
|
|
+ Check::err(ProgramError::IncorrectProgramId),
|
|
|
+ Check::all_rent_exempt(),
|
|
|
+ ],
|
|
|
+ )],
|
|
|
+ &[
|
|
|
+ (account_a_key, account_a),
|
|
|
+ (account_b_key, account_b),
|
|
|
+ (account_c_key, account_c),
|
|
|
+ (
|
|
|
+ authority_key,
|
|
|
+ Account {
|
|
|
+ lamports: Rent::default().minimum_balance(0),
|
|
|
+ ..Default::default()
|
|
|
+ },
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ );
|
|
|
+}
|
|
|
+
|
|
|
+#[tokio::test]
|
|
|
+async fn batch_fail_mint_to_with_invalid_program_owner() {
|
|
|
+ let invalid_program_id = Pubkey::new_from_array([2; 32]);
|
|
|
+ let authority_key = Pubkey::new_unique();
|
|
|
+
|
|
|
+ let mint_key = Pubkey::new_unique();
|
|
|
+ let mint = create_mint(&authority_key, 0, 0, &TOKEN_PROGRAM_ID);
|
|
|
+
|
|
|
+ // account A (invalid)
|
|
|
+ // - amount: 1_000_000_000
|
|
|
+ // - mint: native_mint
|
|
|
+ // - is_native: false
|
|
|
+ // - program_id: invalid_program_id
|
|
|
+ let account_a_key = Pubkey::new_unique();
|
|
|
+ let account_a = create_token_account(&mint_key, &authority_key, false, 0, &invalid_program_id);
|
|
|
+
|
|
|
+ // account B
|
|
|
+ // - amount: 0
|
|
|
+ // - mint: native_mint
|
|
|
+ // - is_native: false
|
|
|
+ // - program_id: TOKEN_PROGRAM_ID
|
|
|
+ let account_b_key = Pubkey::new_unique();
|
|
|
+ let account_b = create_token_account(&mint_key, &authority_key, false, 0, &TOKEN_PROGRAM_ID);
|
|
|
+
|
|
|
+ let instruction = batch_instruction(vec![
|
|
|
+ spl_token::instruction::mint_to(
|
|
|
+ &TOKEN_PROGRAM_ID,
|
|
|
+ &mint_key,
|
|
|
+ &account_a_key,
|
|
|
+ &authority_key,
|
|
|
+ &[],
|
|
|
+ 1_000_000_000,
|
|
|
+ )
|
|
|
+ .unwrap(),
|
|
|
+ spl_token::instruction::mint_to(
|
|
|
+ &TOKEN_PROGRAM_ID,
|
|
|
+ &mint_key,
|
|
|
+ &account_b_key,
|
|
|
+ &authority_key,
|
|
|
+ &[],
|
|
|
+ 1_000_000_000,
|
|
|
+ )
|
|
|
+ .unwrap(),
|
|
|
+ ])
|
|
|
+ .unwrap();
|
|
|
+
|
|
|
+ // Expected to fail since source account has an invalid program owner.
|
|
|
+
|
|
|
+ mollusk().process_and_validate_instruction_chain(
|
|
|
+ &[(
|
|
|
+ &instruction,
|
|
|
+ &[
|
|
|
+ Check::err(ProgramError::IncorrectProgramId),
|
|
|
+ Check::all_rent_exempt(),
|
|
|
+ ],
|
|
|
+ )],
|
|
|
+ &[
|
|
|
+ (mint_key, mint),
|
|
|
+ (account_a_key, account_a),
|
|
|
+ (account_b_key, account_b),
|
|
|
+ (
|
|
|
+ authority_key,
|
|
|
+ Account {
|
|
|
+ lamports: Rent::default().minimum_balance(0),
|
|
|
+ ..Default::default()
|
|
|
+ },
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ );
|
|
|
+}
|
|
|
+
|
|
|
+#[tokio::test]
|
|
|
+async fn batch_fail_burn_with_invalid_program_owner() {
|
|
|
+ let invalid_program_id = Pubkey::new_from_array([2; 32]);
|
|
|
+ let authority_key = Pubkey::new_unique();
|
|
|
+
|
|
|
+ let mint_key = Pubkey::new_unique();
|
|
|
+ let mint = create_mint(&authority_key, 2_000_000_000, 0, &TOKEN_PROGRAM_ID);
|
|
|
+
|
|
|
+ // account A
|
|
|
+ // - amount: 0
|
|
|
+ // - mint: native_mint
|
|
|
+ // - is_native: false
|
|
|
+ // - program_id: TOKEN_PROGRAM_ID
|
|
|
+ let account_a_key = Pubkey::new_unique();
|
|
|
+ let account_a = create_token_account(&mint_key, &authority_key, false, 0, &TOKEN_PROGRAM_ID);
|
|
|
+
|
|
|
+ // account B (invalid)
|
|
|
+ // - amount: 1_000_000_000
|
|
|
+ // - mint: native_mint
|
|
|
+ // - is_native: false
|
|
|
+ // - program_id: invalid_program_id
|
|
|
+ let account_b_key = Pubkey::new_unique();
|
|
|
+ let account_b = create_token_account(
|
|
|
+ &mint_key,
|
|
|
+ &authority_key,
|
|
|
+ false,
|
|
|
+ 1_000_000_000,
|
|
|
+ &invalid_program_id,
|
|
|
+ );
|
|
|
+
|
|
|
+ let instruction = batch_instruction(vec![
|
|
|
+ spl_token::instruction::mint_to(
|
|
|
+ &TOKEN_PROGRAM_ID,
|
|
|
+ &mint_key,
|
|
|
+ &account_a_key,
|
|
|
+ &authority_key,
|
|
|
+ &[],
|
|
|
+ 1_000_000_000,
|
|
|
+ )
|
|
|
+ .unwrap(),
|
|
|
+ spl_token::instruction::mint_to(
|
|
|
+ &TOKEN_PROGRAM_ID,
|
|
|
+ &mint_key,
|
|
|
+ &account_b_key,
|
|
|
+ &authority_key,
|
|
|
+ &[],
|
|
|
+ 1_000_000_000,
|
|
|
+ )
|
|
|
+ .unwrap(),
|
|
|
+ spl_token::instruction::burn(
|
|
|
+ &TOKEN_PROGRAM_ID,
|
|
|
+ &account_a_key,
|
|
|
+ &mint_key,
|
|
|
+ &authority_key,
|
|
|
+ &[],
|
|
|
+ 1_000_000_000,
|
|
|
+ )
|
|
|
+ .unwrap(),
|
|
|
+ spl_token::instruction::burn(
|
|
|
+ &TOKEN_PROGRAM_ID,
|
|
|
+ &account_b_key,
|
|
|
+ &mint_key,
|
|
|
+ &authority_key,
|
|
|
+ &[],
|
|
|
+ 1_000_000_000,
|
|
|
+ )
|
|
|
+ .unwrap(),
|
|
|
+ ])
|
|
|
+ .unwrap();
|
|
|
+
|
|
|
+ // Expected to fail since source account has an invalid program owner.
|
|
|
+
|
|
|
+ mollusk().process_and_validate_instruction_chain(
|
|
|
+ &[(
|
|
|
+ &instruction,
|
|
|
+ &[
|
|
|
+ Check::err(ProgramError::IncorrectProgramId),
|
|
|
+ Check::all_rent_exempt(),
|
|
|
+ ],
|
|
|
+ )],
|
|
|
+ &[
|
|
|
+ (mint_key, mint),
|
|
|
+ (account_a_key, account_a),
|
|
|
+ (account_b_key, account_b),
|
|
|
+ (
|
|
|
+ authority_key,
|
|
|
+ Account {
|
|
|
+ lamports: Rent::default().minimum_balance(0),
|
|
|
+ ..Default::default()
|
|
|
+ },
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ );
|
|
|
}
|