use borsh::BorshSerialize;
use solana_instruction::{AccountMeta, Instruction};
use solana_pubkey::Pubkey;
use crate::{discriminators, pda, util::*, KVAULT_PROGRAM_ID};
pub struct WithdrawAccounts {
pub user: Pubkey,
pub vault_state: Pubkey,
pub global_config: Pubkey,
pub token_vault: Pubkey,
pub base_vault_authority: Pubkey,
pub user_token_ata: Pubkey,
pub token_mint: Pubkey,
pub user_shares_ata: Pubkey,
pub shares_mint: Pubkey,
pub token_program: Pubkey,
pub shares_token_program: Pubkey,
pub klend_program: Pubkey,
pub invested_vault_state: Pubkey,
pub reserve: Pubkey,
pub ctoken_vault: Pubkey,
pub lending_market: Pubkey,
pub lending_market_authority: Pubkey,
pub reserve_liquidity_supply: Pubkey,
pub reserve_collateral_mint: Pubkey,
pub reserve_collateral_token_program: Pubkey,
pub instruction_sysvar_account: Pubkey,
}
fn build_withdraw_accounts(accounts: &WithdrawAccounts) -> Vec<AccountMeta> {
let (evt_auth, _) = pda::event_authority(&KVAULT_PROGRAM_ID);
vec![
signer(accounts.user),
writable(accounts.vault_state),
readonly(accounts.global_config),
writable(accounts.token_vault),
readonly(accounts.base_vault_authority),
writable(accounts.user_token_ata),
writable(accounts.token_mint),
writable(accounts.user_shares_ata),
writable(accounts.shares_mint),
readonly(accounts.token_program),
readonly(accounts.shares_token_program),
readonly(accounts.klend_program),
readonly(evt_auth),
readonly(KVAULT_PROGRAM_ID),
writable(accounts.invested_vault_state),
writable(accounts.reserve),
writable(accounts.ctoken_vault),
readonly(accounts.lending_market),
readonly(accounts.lending_market_authority),
writable(accounts.reserve_liquidity_supply),
writable(accounts.reserve_collateral_mint),
readonly(accounts.reserve_collateral_token_program),
readonly(accounts.instruction_sysvar_account),
readonly(evt_auth),
readonly(KVAULT_PROGRAM_ID),
]
}
pub fn withdraw(
accounts: WithdrawAccounts,
shares_amount: u64,
remaining_accounts: Vec<AccountMeta>,
) -> Instruction {
#[derive(BorshSerialize)]
struct Args {
shares_amount: u64,
}
let args = Args { shares_amount };
let mut data = discriminators::WITHDRAW.to_vec();
args.serialize(&mut data).unwrap();
let mut account_metas = build_withdraw_accounts(&accounts);
account_metas.extend(remaining_accounts);
Instruction {
program_id: KVAULT_PROGRAM_ID,
accounts: account_metas,
data,
}
}
pub fn sell(
accounts: WithdrawAccounts,
shares_amount: u64,
remaining_accounts: Vec<AccountMeta>,
) -> Instruction {
#[derive(BorshSerialize)]
struct Args {
shares_amount: u64,
}
let args = Args { shares_amount };
let mut data = discriminators::SELL.to_vec();
args.serialize(&mut data).unwrap();
let mut account_metas = build_withdraw_accounts(&accounts);
account_metas.extend(remaining_accounts);
Instruction {
program_id: KVAULT_PROGRAM_ID,
accounts: account_metas,
data,
}
}
pub struct WithdrawFromAvailableAccounts {
pub user: Pubkey,
pub vault_state: Pubkey,
pub global_config: Pubkey,
pub token_vault: Pubkey,
pub base_vault_authority: Pubkey,
pub user_token_ata: Pubkey,
pub token_mint: Pubkey,
pub user_shares_ata: Pubkey,
pub shares_mint: Pubkey,
pub token_program: Pubkey,
pub shares_token_program: Pubkey,
pub klend_program: Pubkey,
}
pub fn withdraw_from_available(
accounts: WithdrawFromAvailableAccounts,
shares_amount: u64,
remaining_accounts: Vec<AccountMeta>,
) -> Instruction {
#[derive(BorshSerialize)]
struct Args {
shares_amount: u64,
}
let args = Args { shares_amount };
let mut data = discriminators::WITHDRAW_FROM_AVAILABLE.to_vec();
args.serialize(&mut data).unwrap();
let (evt_auth, _) = pda::event_authority(&KVAULT_PROGRAM_ID);
let mut account_metas = vec![
signer(accounts.user),
writable(accounts.vault_state),
readonly(accounts.global_config),
writable(accounts.token_vault),
readonly(accounts.base_vault_authority),
writable(accounts.user_token_ata),
writable(accounts.token_mint),
writable(accounts.user_shares_ata),
writable(accounts.shares_mint),
readonly(accounts.token_program),
readonly(accounts.shares_token_program),
readonly(accounts.klend_program),
readonly(evt_auth),
readonly(KVAULT_PROGRAM_ID),
];
account_metas.extend(remaining_accounts);
Instruction {
program_id: KVAULT_PROGRAM_ID,
accounts: account_metas,
data,
}
}