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