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;
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;
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();
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();
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();
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();
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()
);
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::<spl_token::state::Account>(*addr)
.await
.unwrap()
.amount
}