use anchor_lang::prelude::*;
use anchor_spl::token::TokenAccount;
use num_traits::cast::ToPrimitive;
use vipers::unwrap_int;
use crate::{state::AccountingMethod, SyncLido, SyncMarinade, SOL};
pub trait Accountant<'info> {
const METHOD: AccountingMethod;
fn sol_value(&self, amount: u64) -> Result<SOL, ProgramError>;
fn crate_reserves(&self) -> &TokenAccount;
}
impl<'info> Accountant<'info> for SyncMarinade<'info> {
const METHOD: AccountingMethod = AccountingMethod::Marinade;
fn sol_value(&self, amount: u64) -> Result<SOL, ProgramError> {
let msol_price: u64 = self.marinade.msol_price;
let sol_value = unwrap_int!((amount as u128)
.checked_mul(msol_price.into())
.and_then(|v| v.checked_div(0x1_0000_0000_u128))
.and_then(|v| v.to_u64()));
Ok(SOL::from(sol_value))
}
fn crate_reserves(&self) -> &TokenAccount {
&self.marinade_stake_pool_tokens
}
}
impl<'info> Accountant<'info> for SyncLido<'info> {
const METHOD: AccountingMethod = AccountingMethod::Lido;
fn sol_value(&self, amount: u64) -> Result<SOL, ProgramError> {
let lido = &*self.lido;
let sol_value = unwrap_int!((amount as u128)
.checked_mul(lido.exchange_rate.sol_balance.0.into())
.and_then(|v| v.checked_div(lido.exchange_rate.st_sol_supply.0.into()))
.and_then(|v| v.to_u64()));
Ok(SOL::from(sol_value))
}
fn crate_reserves(&self) -> &TokenAccount {
&self.lido_stake_pool_tokens
}
}