use bytemuck::{Pod, Zeroable};
use solana_pubkey::Pubkey;
use spl_discriminator::SplDiscriminate;
use spl_pod::primitives::PodU128;
use super::common::{BigFractionBytes, LastUpdate};
#[derive(Debug, Clone, Copy, Pod, Zeroable, SplDiscriminate)]
#[discriminator_hash_input("account:Obligation")]
#[repr(C)]
pub struct Obligation {
pub tag: u64,
pub last_update: LastUpdate,
pub lending_market: Pubkey,
pub owner: Pubkey,
pub deposits: [ObligationCollateral; 8],
pub lowest_reserve_deposit_liquidation_ltv: u64,
pub deposited_value_sf: PodU128,
pub borrows: [ObligationLiquidity; 5],
pub borrow_factor_adjusted_debt_value_sf: PodU128,
pub borrowed_assets_market_value_sf: PodU128,
pub allowed_borrow_value_sf: PodU128,
pub unhealthy_borrow_value_sf: PodU128,
pub padding_deprecated_asset_tiers: [u8; 13],
pub elevation_group: u8,
pub num_of_obsolete_deposit_reserves: u8,
pub has_debt: u8,
pub referrer: Pubkey,
pub borrowing_disabled: u8,
pub autodeleverage_target_ltv_pct: u8,
pub lowest_reserve_deposit_max_ltv_pct: u8,
pub num_of_obsolete_borrow_reserves: u8,
pub reserved: [u8; 4],
pub highest_borrow_factor_pct: u64,
pub autodeleverage_margin_call_started_timestamp: u64,
pub obligation_orders: [ObligationOrder; 2],
pub borrow_order: BorrowOrder,
pub padding_3: [u64; 73],
}
const _: () = assert!(core::mem::size_of::<Obligation>() == 3336);
impl Obligation {
pub fn num_deposits(&self) -> usize {
self.deposits
.iter()
.filter(|d| d.deposit_reserve != Pubkey::default())
.count()
}
pub fn num_borrows(&self) -> usize {
self.borrows
.iter()
.filter(|b| b.borrow_reserve != Pubkey::default())
.count()
}
pub fn deposited_value(&self) -> u128 {
u128::from(self.deposited_value_sf)
}
pub fn allowed_borrow_value(&self) -> u128 {
u128::from(self.allowed_borrow_value_sf)
}
pub fn unhealthy_borrow_value(&self) -> u128 {
u128::from(self.unhealthy_borrow_value_sf)
}
pub fn borrow_factor_adjusted_debt_value(&self) -> u128 {
u128::from(self.borrow_factor_adjusted_debt_value_sf)
}
pub fn borrowed_assets_market_value(&self) -> u128 {
u128::from(self.borrowed_assets_market_value_sf)
}
pub fn is_liquidatable(&self) -> bool {
let debt = self.borrow_factor_adjusted_debt_value();
let unhealthy = self.unhealthy_borrow_value();
debt > unhealthy && unhealthy > 0
}
pub fn is_borrowing_disabled(&self) -> bool {
self.borrow_factor_adjusted_debt_value() >= self.allowed_borrow_value()
}
}
impl ObligationCollateral {
pub fn is_active(&self) -> bool {
self.deposit_reserve != Pubkey::default()
}
pub fn market_value(&self) -> u128 {
u128::from(self.market_value_sf)
}
}
impl ObligationLiquidity {
pub fn is_active(&self) -> bool {
self.borrow_reserve != Pubkey::default()
}
pub fn borrowed_amount(&self) -> u128 {
u128::from(self.borrowed_amount_sf)
}
pub fn market_value(&self) -> u128 {
u128::from(self.market_value_sf)
}
pub fn borrow_factor_adjusted_market_value(&self) -> u128 {
u128::from(self.borrow_factor_adjusted_market_value_sf)
}
}
#[derive(Debug, Clone, Copy, Pod, Zeroable)]
#[repr(C)]
pub struct ObligationCollateral {
pub deposit_reserve: Pubkey,
pub deposited_amount: u64,
pub market_value_sf: PodU128,
pub borrowed_amount_against_this_collateral_in_elevation_group: u64,
pub padding: [u64; 9],
}
#[derive(Debug, Clone, Copy, Pod, Zeroable)]
#[repr(C)]
pub struct ObligationLiquidity {
pub borrow_reserve: Pubkey,
pub cumulative_borrow_rate_bsf: BigFractionBytes,
pub last_borrowed_at_timestamp: u64,
pub borrowed_amount_sf: PodU128,
pub market_value_sf: PodU128,
pub borrow_factor_adjusted_market_value_sf: PodU128,
pub borrowed_amount_outside_elevation_groups: u64,
pub fixed_term_borrow_rollover_config: FixedTermBorrowRolloverConfig,
pub borrowed_amount_at_expiration: u64,
pub padding2: [u64; 4],
}
#[derive(Debug, Clone, Copy, Zeroable, Pod)]
#[repr(C)]
pub struct FixedTermBorrowRolloverConfig {
pub auto_rollover_enabled: u8,
pub open_term_allowed: u8,
pub migration_to_fixed_enabled: u8,
pub alignment_padding: [u8; 1],
pub max_borrow_rate_bps: u32,
pub min_debt_term_seconds: u64,
}
#[derive(Debug, Clone, Copy, Pod, Zeroable)]
#[repr(C)]
pub struct ObligationOrder {
pub condition_threshold_sf: PodU128,
pub opportunity_parameter_sf: PodU128,
pub min_execution_bonus_bps: u16,
pub max_execution_bonus_bps: u16,
pub condition_type: u8,
pub opportunity_type: u8,
pub padding1: [u8; 10],
pub padding2: [PodU128; 5],
}
#[derive(Debug, Clone, Copy, Zeroable, Pod)]
#[repr(C)]
pub struct BorrowOrder {
pub debt_liquidity_mint: Pubkey,
pub remaining_debt_amount: u64,
pub filled_debt_destination: Pubkey,
pub min_debt_term_seconds: u64,
pub fillable_until_timestamp: u64,
pub placed_at_timestamp: u64,
pub last_updated_at_timestamp: u64,
pub requested_debt_amount: u64,
pub max_borrow_rate_bps: u32,
pub active: u8,
pub enable_auto_rollover_on_filled_borrows: u8,
pub padding1: [u8; 2],
pub end_padding: [u64; 5],
}