use anchor_lang::{InstructionData, ToAccountMetas};
use solana_program::{instruction::Instruction, pubkey::Pubkey};
use crate::constants::{
INSTRUCTIONS_SYSVAR_ID, KAMINO_FARMS_PROGRAM_ID, KAMINO_LENDING_PROGRAM_ID, SYSTEM_PROGRAM_ID,
};
pub struct SpendKaminoParams {
pub owner: Pubkey,
pub admin: Pubkey,
pub spend_fee_destination: Pubkey,
pub liquidity_mint: Pubkey,
pub liquidity_token_program: Pubkey,
pub kamino_market: Pubkey,
pub kamino_reserve: Pubkey,
pub spend_amount_base_units: u64,
pub fee_amount_base_units: u64,
}
pub fn spend_kamino(params: &SpendKaminoParams) -> Instruction {
let vault = pyra_accounts::get_vault(¶ms.owner);
let vault_liquidity_ata = pyra_accounts::get_associated_token_address(
&vault,
¶ms.liquidity_mint,
¶ms.liquidity_token_program,
);
let spend_hold = pyra_accounts::get_spend_hold();
let spend_hold_liquidity_ata = pyra_accounts::get_associated_token_address(
&spend_hold,
¶ms.liquidity_mint,
¶ms.liquidity_token_program,
);
let spend_fee_destination_ata = pyra_accounts::get_associated_token_address(
¶ms.spend_fee_destination,
¶ms.liquidity_mint,
¶ms.liquidity_token_program,
);
let kamino_obligation =
pyra_accounts::get_kamino_obligation(¶ms.owner, ¶ms.kamino_market);
let kamino_market_authority =
pyra_accounts::get_kamino_lending_market_authority(¶ms.kamino_market);
let kamino_reserve_liquidity_supply =
pyra_accounts::get_kamino_reserve_liquidity_supply(¶ms.kamino_reserve);
let kamino_reserve_collateral_mint =
pyra_accounts::get_kamino_reserve_collateral_mint(¶ms.kamino_reserve);
let kamino_reserve_collateral_supply =
pyra_accounts::get_kamino_reserve_collateral_supply(¶ms.kamino_reserve);
let accounts = crate::pyra_program::client::accounts::SpendKamino {
vault,
vault_liquidity_ata,
admin: params.admin,
spend_hold,
spend_hold_liquidity_ata,
spend_fee_destination: params.spend_fee_destination,
spend_fee_destination_ata,
liquidity_mint: params.liquidity_mint,
liquidity_token_program: params.liquidity_token_program,
associated_token_program: pyra_accounts::ASSOCIATED_TOKEN_PROGRAM_ID,
kamino_program: KAMINO_LENDING_PROGRAM_ID,
kamino_obligation,
kamino_market: params.kamino_market,
kamino_market_authority,
kamino_reserve: params.kamino_reserve,
kamino_reserve_liquidity_supply,
kamino_reserve_collateral_mint,
kamino_reserve_collateral_supply,
collateral_token_program: pyra_tokens::TOKEN_PROGRAM_ID,
instructions_sysvar_account: INSTRUCTIONS_SYSVAR_ID,
kamino_farms_program: KAMINO_FARMS_PROGRAM_ID,
system_program: SYSTEM_PROGRAM_ID,
}
.to_account_metas(None);
let data = crate::pyra_program::client::args::SpendKamino {
spend_amount_base_units: params.spend_amount_base_units,
fee_amount_base_units: params.fee_amount_base_units,
}
.data();
Instruction {
program_id: pyra_accounts::PYRA_PROGRAM_ID,
accounts,
data,
}
}
#[cfg(test)]
#[allow(clippy::unwrap_used)]
mod tests {
use super::*;
use solana_pubkey::pubkey;
#[test]
fn test_spend_kamino_instruction() {
let owner = pubkey!("d4A2prbA2whesmvHaL88BH6Ewn5N4bTSjm4GiKy2eSi");
let admin = pubkey!("7u3HeHxYDLhnCoErrtycNokbQYbWGzLs6JSDqGAv5PfF");
let market = pubkey!("Gnt27xtC473ZT2Mw5u8wZ68Z3gULkSTb5DuxJy7eJotD");
let reserve = pubkey!("AdtRGGhmqvom3Fk5H2LTnGMfcXmUQdhSz8aPJGfhFqHj");
let mint = pubkey!("DUcTi3rDyS5QEmZ4BNRBejtArmDCWaPYGfN44vBJXKL5");
let token_program = pubkey!("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA");
let fee_dest = pubkey!("3NJYftD5sjVfxFkKFgU7bbtBBhBsBYAg1CEhJkJ4iY3H");
let ix = spend_kamino(&SpendKaminoParams {
owner,
admin,
spend_fee_destination: fee_dest,
liquidity_mint: mint,
liquidity_token_program: token_program,
kamino_market: market,
kamino_reserve: reserve,
spend_amount_base_units: 1_000_000,
fee_amount_base_units: 10_000,
});
assert_eq!(ix.program_id, pyra_accounts::PYRA_PROGRAM_ID);
assert_eq!(ix.accounts.len(), 22);
assert_eq!(ix.accounts[0].pubkey, pyra_accounts::get_vault(&owner));
assert!(ix.accounts[0].is_writable);
assert_eq!(ix.accounts[2].pubkey, admin);
assert!(ix.accounts[2].is_signer);
assert!(ix.accounts[2].is_writable);
assert!(!ix.data.is_empty());
}
}