1use bytemuck::{Pod, Zeroable};
2use solana_pubkey::Pubkey;
3use spl_discriminator::SplDiscriminate;
4use spl_pod::primitives::PodU128;
5
6use super::common::{BigFractionBytes, LastUpdate};
7
8#[derive(Debug, Clone, Copy, Pod, Zeroable, SplDiscriminate)]
14#[discriminator_hash_input("account:Obligation")]
15#[repr(C)]
16pub struct Obligation {
17 pub tag: u64,
18 pub last_update: LastUpdate,
19 pub lending_market: Pubkey,
20 pub owner: Pubkey,
21 pub deposits: [ObligationCollateral; 8],
23 pub lowest_reserve_deposit_liquidation_ltv: u64,
24 pub deposited_value_sf: PodU128,
26 pub borrows: [ObligationLiquidity; 5],
28 pub borrow_factor_adjusted_debt_value_sf: PodU128,
30 pub borrowed_assets_market_value_sf: PodU128,
32 pub allowed_borrow_value_sf: PodU128,
34 pub unhealthy_borrow_value_sf: PodU128,
36 pub padding_deprecated_asset_tiers: [u8; 13],
37 pub elevation_group: u8,
38 pub num_of_obsolete_deposit_reserves: u8,
39 pub has_debt: u8,
41 pub referrer: Pubkey,
42 pub borrowing_disabled: u8,
43 pub autodeleverage_target_ltv_pct: u8,
44 pub lowest_reserve_deposit_max_ltv_pct: u8,
45 pub num_of_obsolete_borrow_reserves: u8,
46 pub reserved: [u8; 4],
47 pub highest_borrow_factor_pct: u64,
48 pub autodeleverage_margin_call_started_timestamp: u64,
49 pub obligation_orders: [ObligationOrder; 2],
50 pub borrow_order: BorrowOrder,
51 pub padding_3: [u64; 73],
52}
53
54const _: () = assert!(core::mem::size_of::<Obligation>() == 3336);
55
56impl Obligation {
57 pub fn num_deposits(&self) -> usize {
59 self.deposits
60 .iter()
61 .filter(|d| d.deposit_reserve != Pubkey::default())
62 .count()
63 }
64
65 pub fn num_borrows(&self) -> usize {
67 self.borrows
68 .iter()
69 .filter(|b| b.borrow_reserve != Pubkey::default())
70 .count()
71 }
72
73 pub fn deposited_value(&self) -> u128 {
75 u128::from(self.deposited_value_sf)
76 }
77
78 pub fn allowed_borrow_value(&self) -> u128 {
80 u128::from(self.allowed_borrow_value_sf)
81 }
82
83 pub fn unhealthy_borrow_value(&self) -> u128 {
85 u128::from(self.unhealthy_borrow_value_sf)
86 }
87
88 pub fn borrow_factor_adjusted_debt_value(&self) -> u128 {
90 u128::from(self.borrow_factor_adjusted_debt_value_sf)
91 }
92
93 pub fn borrowed_assets_market_value(&self) -> u128 {
95 u128::from(self.borrowed_assets_market_value_sf)
96 }
97
98 pub fn is_liquidatable(&self) -> bool {
101 let debt = self.borrow_factor_adjusted_debt_value();
102 let unhealthy = self.unhealthy_borrow_value();
103 debt > unhealthy && unhealthy > 0
104 }
105
106 pub fn is_borrowing_disabled(&self) -> bool {
109 self.borrow_factor_adjusted_debt_value() >= self.allowed_borrow_value()
110 }
111}
112
113impl ObligationCollateral {
114 pub fn is_active(&self) -> bool {
116 self.deposit_reserve != Pubkey::default()
117 }
118
119 pub fn market_value(&self) -> u128 {
121 u128::from(self.market_value_sf)
122 }
123}
124
125impl ObligationLiquidity {
126 pub fn is_active(&self) -> bool {
128 self.borrow_reserve != Pubkey::default()
129 }
130
131 pub fn borrowed_amount(&self) -> u128 {
133 u128::from(self.borrowed_amount_sf)
134 }
135
136 pub fn market_value(&self) -> u128 {
138 u128::from(self.market_value_sf)
139 }
140
141 pub fn borrow_factor_adjusted_market_value(&self) -> u128 {
143 u128::from(self.borrow_factor_adjusted_market_value_sf)
144 }
145}
146
147#[derive(Debug, Clone, Copy, Pod, Zeroable)]
153#[repr(C)]
154pub struct ObligationCollateral {
155 pub deposit_reserve: Pubkey,
156 pub deposited_amount: u64,
157 pub market_value_sf: PodU128,
158 pub borrowed_amount_against_this_collateral_in_elevation_group: u64,
159 pub padding: [u64; 9],
160}
161
162#[derive(Debug, Clone, Copy, Pod, Zeroable)]
164#[repr(C)]
165pub struct ObligationLiquidity {
166 pub borrow_reserve: Pubkey,
167 pub cumulative_borrow_rate_bsf: BigFractionBytes,
168 pub last_borrowed_at_timestamp: u64,
169 pub borrowed_amount_sf: PodU128,
170 pub market_value_sf: PodU128,
171 pub borrow_factor_adjusted_market_value_sf: PodU128,
172 pub borrowed_amount_outside_elevation_groups: u64,
173 pub fixed_term_borrow_rollover_config: FixedTermBorrowRolloverConfig,
174 pub borrowed_amount_at_expiration: u64,
175 pub padding2: [u64; 4],
176}
177
178#[derive(Debug, Clone, Copy, Zeroable, Pod)]
180#[repr(C)]
181pub struct FixedTermBorrowRolloverConfig {
182 pub auto_rollover_enabled: u8,
183 pub open_term_allowed: u8,
184 pub migration_to_fixed_enabled: u8,
185 pub alignment_padding: [u8; 1],
186 pub max_borrow_rate_bps: u32,
187 pub min_debt_term_seconds: u64,
188}
189
190#[derive(Debug, Clone, Copy, Pod, Zeroable)]
192#[repr(C)]
193pub struct ObligationOrder {
194 pub condition_threshold_sf: PodU128,
195 pub opportunity_parameter_sf: PodU128,
196 pub min_execution_bonus_bps: u16,
197 pub max_execution_bonus_bps: u16,
198 pub condition_type: u8,
199 pub opportunity_type: u8,
200 pub padding1: [u8; 10],
201 pub padding2: [PodU128; 5],
202}
203
204#[derive(Debug, Clone, Copy, Zeroable, Pod)]
206#[repr(C)]
207pub struct BorrowOrder {
208 pub debt_liquidity_mint: Pubkey,
209 pub remaining_debt_amount: u64,
210 pub filled_debt_destination: Pubkey,
211 pub min_debt_term_seconds: u64,
212 pub fillable_until_timestamp: u64,
213 pub placed_at_timestamp: u64,
214 pub last_updated_at_timestamp: u64,
215 pub requested_debt_amount: u64,
216 pub max_borrow_rate_bps: u32,
217 pub active: u8,
218 pub enable_auto_rollover_on_filled_borrows: u8,
219 pub padding1: [u8; 2],
220 pub end_padding: [u64; 5],
221}