wp-solana-test-utils 0.1.1

Protocol-specific test fixtures for Raydium CLMM, Meteora DLMM, Orca Whirlpool
Documentation
//! Shared type definitions for lending protocol test fixtures.
//!
//! Lending protocols (Solend, MarginFi, Kamino, etc.) manage N reserves per
//! market rather than the fixed token-A/token-B pair used by AMM/CLMM pools.
//! These types capture that dynamic structure so each protocol-specific fixture
//! can reuse the same account layout.

use solana_sdk::pubkey::Pubkey;

/// Top-level accounts for a lending market under test.
///
/// A single market contains an arbitrary number of [`ReserveAccounts`], one per
/// asset (SOL, USDC, USDT, ETH, jitoSOL, …).
#[derive(Debug, Clone)]
pub struct LendingMarketAccounts {
    /// The on-chain program that owns this market (e.g. Solend, MarginFi).
    pub program_id: Pubkey,
    /// The market's top-level state account.
    pub market_address: Pubkey,
    /// Per-asset reserve accounts belonging to this market.
    pub reserves: Vec<ReserveAccounts>,
}

impl LendingMarketAccounts {
    /// Look up a reserve by its token mint.
    ///
    /// Returns `None` when no reserve in this market matches `mint`.
    pub fn reserve_by_mint(&self, mint: &Pubkey) -> Option<&ReserveAccounts> {
        self.reserves.iter().find(|r| r.token_mint == *mint)
    }
}

/// Accounts associated with a single reserve inside a lending market.
#[derive(Debug, Clone)]
pub struct ReserveAccounts {
    /// The reserve's own state account.
    pub reserve_address: Pubkey,
    /// SPL token mint for the underlying asset.
    pub token_mint: Pubkey,
    /// Vault that holds deposited liquidity.
    pub liquidity_vault: Pubkey,
    /// Mint for the collateral receipt token (cToken / share token).
    pub collateral_mint: Pubkey,
    /// Price oracle account used by the protocol.
    pub oracle: Pubkey,
    /// The test payer's associated token account for this asset.
    pub payer_ata: Pubkey,
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_reserve_by_mint_lookup() {
        let mint_sol = Pubkey::new_unique();
        let mint_usdc = Pubkey::new_unique();
        let mint_usdt = Pubkey::new_unique();
        let mint_unknown = Pubkey::new_unique();

        let reserve_sol = ReserveAccounts {
            reserve_address: Pubkey::new_unique(),
            token_mint: mint_sol,
            liquidity_vault: Pubkey::new_unique(),
            collateral_mint: Pubkey::new_unique(),
            oracle: Pubkey::new_unique(),
            payer_ata: Pubkey::new_unique(),
        };
        let reserve_usdc = ReserveAccounts {
            reserve_address: Pubkey::new_unique(),
            token_mint: mint_usdc,
            liquidity_vault: Pubkey::new_unique(),
            collateral_mint: Pubkey::new_unique(),
            oracle: Pubkey::new_unique(),
            payer_ata: Pubkey::new_unique(),
        };
        let reserve_usdt = ReserveAccounts {
            reserve_address: Pubkey::new_unique(),
            token_mint: mint_usdt,
            liquidity_vault: Pubkey::new_unique(),
            collateral_mint: Pubkey::new_unique(),
            oracle: Pubkey::new_unique(),
            payer_ata: Pubkey::new_unique(),
        };

        let expected_sol_addr = reserve_sol.reserve_address;
        let expected_usdc_addr = reserve_usdc.reserve_address;
        let expected_usdt_addr = reserve_usdt.reserve_address;

        let market = LendingMarketAccounts {
            program_id: Pubkey::new_unique(),
            market_address: Pubkey::new_unique(),
            reserves: vec![reserve_sol, reserve_usdc, reserve_usdt],
        };

        // Positive lookups
        let found_sol = market.reserve_by_mint(&mint_sol).expect("SOL reserve");
        assert_eq!(found_sol.reserve_address, expected_sol_addr);

        let found_usdc = market.reserve_by_mint(&mint_usdc).expect("USDC reserve");
        assert_eq!(found_usdc.reserve_address, expected_usdc_addr);

        let found_usdt = market.reserve_by_mint(&mint_usdt).expect("USDT reserve");
        assert_eq!(found_usdt.reserve_address, expected_usdt_addr);

        // Negative lookup — unknown mint returns None
        assert!(market.reserve_by_mint(&mint_unknown).is_none());
    }
}