access-protocol 0.7.15

Access Protocol
Documentation
use solana_program::clock::SECONDS_PER_DAY;
use solana_sdk::signer::Signer;

use access_protocol::state::Tag::BondAccount;

use crate::common::test_runner::TestRunner;

pub mod common;

#[tokio::test]
async fn v1_bonds() {
    // Setup the token + basic accounts
    let mut tr = TestRunner::new(1_000_000).await.unwrap();
    // ---------------------------------------------------------------------------------------------
    // Unlockable bond
    // ---------------------------------------------------------------------------------------------
    // Create users
    let pool_owner = tr.create_user_with_ata().await.unwrap();
    let bond_recipient = tr.create_user_with_ata().await.unwrap();
    // Create stake pool
    tr.create_pool(&pool_owner, 10_000)
        .await
        .unwrap();
    // Activate stake pool
    tr.activate_stake_pool(&pool_owner.pubkey()).await.unwrap();

    let current_time = tr.get_current_time().await;
    let bond_amount = 20_000;

    // Create bond
    tr.create_bond(
        &pool_owner.pubkey(),
        &bond_recipient.pubkey(),
        bond_amount,
        1,
        5 * SECONDS_PER_DAY as i64,
        1,
    )
    .await
    .unwrap();
    tr.claim_bond(&pool_owner.pubkey(), &bond_recipient.pubkey())
        .await
        .unwrap();

    let pool_stats = tr.pool_stats(pool_owner.pubkey()).await.unwrap();
    assert_eq!(pool_stats.header.total_staked, bond_amount);
    assert_eq!(pool_stats.vault, bond_amount);
    let central_state_stats = tr.central_state_stats().await.unwrap();
    assert_eq!(central_state_stats.account.total_staked, bond_amount);
    let bond = tr
        .bond_stats(bond_recipient.pubkey(), pool_owner.pubkey(), bond_amount)
        .await
        .unwrap();
    assert_eq!(bond.tag, BondAccount);
    assert_eq!(
        bond.unlock_start_date,
        current_time + 5 * SECONDS_PER_DAY as i64
    );
    assert_eq!(bond.stake_pool, tr.get_pool_pda(&pool_owner.pubkey()));
    assert_eq!(bond.total_staked, bond_amount);
    assert_eq!(bond.owner, bond_recipient.pubkey());
    assert_eq!(bond.last_claimed_offset, 0);
    assert_eq!(bond.pool_minimum_at_creation, 10_000);

    // Claim zero rewards
    let recipient_stats = tr.staker_stats(bond_recipient.pubkey()).await.unwrap();
    assert_eq!(recipient_stats.balance, 0);
    tr.claim_bond_rewards(&pool_owner.pubkey(), &bond_recipient)
        .await
        .unwrap_err();
    let recipient_stats = tr.staker_stats(bond_recipient.pubkey()).await.unwrap();
    assert_eq!(recipient_stats.balance, 0);

    // Claim rewards
    _ = tr.sleep(SECONDS_PER_DAY).await;
    tr.crank_pool(&pool_owner.pubkey()).await.unwrap();
    tr.claim_bond_rewards(&pool_owner.pubkey(), &bond_recipient)
        .await
        .unwrap();
    let recipient_stats = tr.staker_stats(bond_recipient.pubkey()).await.unwrap();
    assert_eq!(recipient_stats.balance, 500_000);

    // Try unlocking - shouldn't be possible
    tr.unlock_bond(&pool_owner.pubkey(), &bond_recipient)
        .await
        .unwrap_err();

    // Move 5 days to the future
    _ = tr.sleep(5 * SECONDS_PER_DAY).await;
    tr.crank_pool(&pool_owner.pubkey()).await.unwrap();
    // Unlocking should not be possible before reward claim
    tr.unlock_bond(&pool_owner.pubkey(), &bond_recipient)
        .await
        .unwrap_err();
    _ = tr.sleep(1).await;
    // Claim rewards
    tr.claim_bond_rewards(&pool_owner.pubkey(), &bond_recipient)
        .await
        .unwrap();
    // Unlocking should be possible now
    tr.unlock_bond(&pool_owner.pubkey(), &bond_recipient)
        .await
        .unwrap();
    // Check all the stats
    let recipient_stats = tr.staker_stats(bond_recipient.pubkey()).await.unwrap();
    assert_eq!(recipient_stats.balance, 2 * 500_000 + bond_amount);
    let pool_stats = tr.pool_stats(pool_owner.pubkey()).await.unwrap();
    assert_eq!(pool_stats.header.total_staked, 0);
    assert_eq!(pool_stats.vault, 0);
    let central_state_stats = tr.central_state_stats().await.unwrap();
    assert_eq!(central_state_stats.account.total_staked, 0);
    let bond = tr
        .bond_stats(bond_recipient.pubkey(), pool_owner.pubkey(), bond_amount)
        .await
        .unwrap();
    assert_eq!(bond.tag, BondAccount);
    assert_eq!(
        bond.unlock_start_date,
        current_time + 5 * SECONDS_PER_DAY as i64
    );
    assert_eq!(bond.stake_pool, tr.get_pool_pda(&pool_owner.pubkey()));
    assert_eq!(bond.total_staked, 0);
    assert_eq!(bond.owner, bond_recipient.pubkey());
    assert_eq!(bond.last_claimed_offset, 6);
    assert_eq!(bond.pool_minimum_at_creation, 10_000);

    // Second unlock should not be possible
    // fixme but it is - what does it do?
    tr.unlock_bond(&pool_owner.pubkey(), &bond_recipient)
        .await
        .unwrap();
    let recipient_stats = tr.staker_stats(bond_recipient.pubkey()).await.unwrap();
    assert_eq!(recipient_stats.balance, 2 * 500_000 + bond_amount);
    let pool_stats = tr.pool_stats(pool_owner.pubkey()).await.unwrap();
    assert_eq!(pool_stats.header.total_staked, 0);
    assert_eq!(pool_stats.vault, 0);
    let central_state_stats = tr.central_state_stats().await.unwrap();
    assert_eq!(central_state_stats.account.total_staked, 0);
    let bond = tr
        .bond_stats(bond_recipient.pubkey(), pool_owner.pubkey(), bond_amount)
        .await
        .unwrap();
    assert_eq!(bond.tag, BondAccount);
    assert_eq!(
        bond.unlock_start_date,
        current_time + 5 * SECONDS_PER_DAY as i64
    );
    assert_eq!(bond.stake_pool, tr.get_pool_pda(&pool_owner.pubkey()));
    assert_eq!(bond.total_staked, 0);
    assert_eq!(bond.owner, bond_recipient.pubkey());
    assert_eq!(bond.last_claimed_offset, 6);
    assert_eq!(bond.pool_minimum_at_creation, 10_000);

    // Claim rewards in another 5 days
    _ = tr.sleep(5 * SECONDS_PER_DAY).await;
    tr.crank_pool(&pool_owner.pubkey()).await.unwrap();
    tr.claim_bond_rewards(&pool_owner.pubkey(), &bond_recipient)
        .await
        .unwrap_err();
}