use std::str::FromStr; use borsh::BorshDeserialize; use solana_program::{program_pack::Pack, pubkey::Pubkey, rent, system_instruction}; use human_contract::{ consts::*, contract_vault, contract_wallet, create_buy_instruction, create_drop_instruction, create_init_instruction, create_wallets, process_instruction, state::{ContractState, STATE_ACC_SIZE}, InitInstruction, }; use solana_sdk::signature::Keypair; use spl_associated_token_account::{ get_associated_token_address, instruction::create_associated_token_account, }; use spl_token::instruction::AuthorityType; use { solana_program_test::*, solana_sdk::{signature::Signer, transaction::Transaction}, }; const SOL: u64 = 1e9 as u64; #[tokio::test] async fn test() { test_transaction().await; } async fn test_transaction() { let program_id = Pubkey::from_str("22222222222222222222222222222222222222222222").unwrap(); let (mut banks_client, fee_payer, recent_blockhash) = ProgramTest::new( "human_contract", program_id, processor!(process_instruction), ) .start() .await; // -=-=-=-=-=-=- create token let rent = rent::Rent::default(); let token_mint = Keypair::new(); let owner = Keypair::new(); let treasury = Keypair::new(); let mint_size = spl_token::state::Mint::LEN; let create_mint = solana_program::system_instruction::create_account( &fee_payer.pubkey(), &token_mint.pubkey(), rent.minimum_balance(mint_size), mint_size as u64, &spl_token::ID, ); let initialize_mint = spl_token::instruction::initialize_mint( &spl_token::ID, &token_mint.pubkey(), &fee_payer.pubkey(), None, 4, ) .unwrap(); let token_mint_addr = token_mint.pubkey(); let create_wallets = create_wallets(&program_id, &token_mint_addr, &fee_payer.pubkey()); const EMITTED: u64 = SOL * 100; // mint some tokens to contract wallet let (wallet, _) = contract_wallet!(&program_id, &token_mint_addr); let mint_inst = spl_token::instruction::mint_to( &spl_token::ID, &token_mint.pubkey(), &wallet, &fee_payer.pubkey(), &[], EMITTED, ) .unwrap(); // let (vault, _) = contract_vault!(&program_id, &token_mint_addr); let mint_vault_inst = spl_token::instruction::mint_to( &spl_token::ID, &token_mint.pubkey(), &vault, &fee_payer.pubkey(), &[], EMITTED, ) .unwrap(); let transfer_ownership = spl_token::instruction::set_authority( &spl_token::ID, &token_mint.pubkey(), None, AuthorityType::MintTokens, &fee_payer.pubkey(), &[], ) .unwrap(); let mut transaction = Transaction::new_with_payer( &[ create_mint, initialize_mint, create_wallets, mint_inst, mint_vault_inst, transfer_ownership, ], Some(&fee_payer.pubkey()), ); transaction.sign(&[&fee_payer, &token_mint], recent_blockhash); banks_client.process_transaction(transaction).await.unwrap(); // -=-=-=-=-=-=-=- init state let commission = Keypair::new(); let create_assoc = create_associated_token_account( &fee_payer.pubkey(), &commission.pubkey(), &token_mint.pubkey(), &spl_token::ID, ); let (state_addr, _) = Pubkey::find_program_address(&[V1, STATE_SEED, token_mint.pubkey().as_ref()], &program_id); let init_instruction = create_init_instruction( &program_id, &state_addr, &token_mint.pubkey(), &fee_payer.pubkey(), InitInstruction { admin: fee_payer.pubkey(), owner: owner.pubkey(), commission: commission.pubkey(), treasury: treasury.pubkey(), swap_state: Pubkey::new_unique(), }, ) .unwrap(); // ------ crate drop const BOUGHT: u64 = 10 * SOL; const PRICE: u64 = 1; const START_DATE: i64 = 1; const END_DATE: i64 = i64::MAX; let mut transaction = Transaction::new_with_payer(&[create_assoc, init_instruction], Some(&fee_payer.pubkey())); transaction.sign(&[&fee_payer], recent_blockhash); banks_client.process_transaction(transaction).await.unwrap(); let create_drop = create_drop_instruction( &program_id, &token_mint.pubkey(), &owner.pubkey(), 1, BOUGHT, PRICE, START_DATE, END_DATE, ) .unwrap(); let mut transaction = Transaction::new_with_payer(&[create_drop], Some(&fee_payer.pubkey())); transaction.sign(&[&fee_payer, &owner], recent_blockhash); banks_client.process_transaction(transaction).await.unwrap(); // buy let buyer = Keypair::new(); let transfer = system_instruction::transfer(&fee_payer.pubkey(), &buyer.pubkey(), SOL * 10000); let buyer_assoc = get_associated_token_address(&buyer.pubkey(), &token_mint.pubkey()); let create_assoc = create_associated_token_account( &buyer.pubkey(), &buyer.pubkey(), &token_mint.pubkey(), &spl_token::ID, ); let buy_instruction = create_buy_instruction( &program_id, &state_addr, &token_mint.pubkey(), &buyer.pubkey(), &buyer_assoc, &owner.pubkey(), &treasury.pubkey(), BOUGHT, PRICE, ) .unwrap(); let mut transaction = Transaction::new_with_payer( &[transfer, create_assoc, buy_instruction], Some(&fee_payer.pubkey()), ); transaction.sign(&[&fee_payer, &buyer], recent_blockhash); banks_client.process_transaction(transaction).await.unwrap(); // check tokens let contract_wallet_balance = get_token_balance(&mut banks_client, &wallet).await; assert_eq!(contract_wallet_balance, EMITTED - BOUGHT); let dest_wallet_balance = get_token_balance(&mut banks_client, &buyer_assoc).await; assert_eq!(dest_wallet_balance, BOUGHT); let state_balance = banks_client.get_balance(state_addr).await.unwrap(); assert_eq!( state_balance, SOL.checked_add(rent.minimum_balance(STATE_ACC_SIZE)) .unwrap() ); // sols let owner_balance = banks_client.get_balance(owner.pubkey()).await.unwrap(); assert_eq!(owner_balance, SOL * 1); let treasury_balance = banks_client.get_balance(treasury.pubkey()).await.unwrap(); assert_eq!(treasury_balance, SOL * 8); let state_acc = banks_client.get_account(state_addr).await.unwrap().unwrap(); let state = ContractState::deserialize(&mut &state_acc.data[1..]).unwrap(); dbg!(&state); assert_eq!(state.owner, owner.pubkey()); assert_eq!(state.commission_addr, commission.pubkey()); assert_eq!(state.sold, BOUGHT); let drop = state.drop.unwrap(); assert_eq!(drop.price, 1); assert_ne!(state.vest.deployed_at, 0); } async fn get_token_balance(c: &mut BanksClient, addr: &Pubkey) -> u64 { c.get_packed_account_data::(*addr) .await .unwrap() .amount }