Skip to main content

klend_interface/state/
reserve.rs

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// ---------------------------------------------------------------------------
9// Reserve
10// ---------------------------------------------------------------------------
11
12/// Lending reserve account state.
13#[derive(Debug, Clone, Copy, Pod, Zeroable, SplDiscriminate)]
14#[discriminator_hash_input("account:Reserve")]
15#[repr(C)]
16pub struct Reserve {
17    pub version: u64,
18    pub last_update: LastUpdate,
19    pub lending_market: Pubkey,
20    pub farm_collateral: Pubkey,
21    pub farm_debt: Pubkey,
22    pub liquidity: ReserveLiquidity,
23    pub reserve_liquidity_padding: [u64; 150],
24    pub collateral: ReserveCollateral,
25    pub reserve_collateral_padding: [u64; 150],
26    pub config: ReserveConfig,
27    pub config_padding: [u64; 114],
28    pub borrowed_amount_outside_elevation_group: u64,
29    pub borrowed_amounts_against_this_reserve_in_elevation_groups: [u64; 32],
30    pub withdraw_queue: WithdrawQueue,
31    pub padding: [u64; 204],
32}
33
34const _: () = assert!(core::mem::size_of::<Reserve>() == 8616);
35
36impl Reserve {
37    /// Total available (unborrowed) liquidity in native token units.
38    pub fn available_liquidity(&self) -> u64 {
39        self.liquidity.total_available_amount
40    }
41
42    /// Total borrowed amount as a raw u128 scaled fraction.
43    pub fn borrowed_amount(&self) -> u128 {
44        u128::from(self.liquidity.borrowed_amount_sf)
45    }
46
47    /// Market price of the reserve token as a raw u128 scaled fraction.
48    pub fn market_price(&self) -> u128 {
49        u128::from(self.liquidity.market_price_sf)
50    }
51
52    /// Decimals of the liquidity mint.
53    pub fn mint_decimals(&self) -> u64 {
54        self.liquidity.mint_decimals
55    }
56
57    /// Total supply of collateral tokens (cTokens).
58    pub fn collateral_total_supply(&self) -> u64 {
59        self.collateral.mint_total_supply
60    }
61
62    /// Accumulated protocol fees as a raw u128 scaled fraction.
63    pub fn accumulated_protocol_fees(&self) -> u128 {
64        u128::from(self.liquidity.accumulated_protocol_fees_sf)
65    }
66
67    /// Accumulated referrer fees as a raw u128 scaled fraction.
68    pub fn accumulated_referrer_fees(&self) -> u128 {
69        u128::from(self.liquidity.accumulated_referrer_fees_sf)
70    }
71
72    /// Reserve status: 0 = Active, 1 = Obsolete, 2 = Hidden.
73    pub fn status(&self) -> u8 {
74        self.config.status
75    }
76
77    /// Whether the reserve is in emergency mode.
78    pub fn is_emergency_mode(&self) -> bool {
79        self.config.emergency_mode != 0
80    }
81
82    /// Loan-to-value percentage.
83    pub fn loan_to_value_pct(&self) -> u8 {
84        self.config.loan_to_value_pct
85    }
86
87    /// Liquidation threshold percentage.
88    pub fn liquidation_threshold_pct(&self) -> u8 {
89        self.config.liquidation_threshold_pct
90    }
91
92    /// Borrow factor percentage (100 = 1x).
93    pub fn borrow_factor_pct(&self) -> u64 {
94        self.config.borrow_factor_pct
95    }
96
97    /// Deposit limit in native token units.
98    pub fn deposit_limit(&self) -> u64 {
99        self.config.deposit_limit
100    }
101
102    /// Borrow limit in native token units.
103    pub fn borrow_limit(&self) -> u64 {
104        self.config.borrow_limit
105    }
106
107    /// Next sequence number for withdraw tickets.
108    pub fn next_withdraw_ticket_sequence_number(&self) -> u64 {
109        self.withdraw_queue.next_issued_ticket_sequence_number
110    }
111}
112
113// ---------------------------------------------------------------------------
114// ReserveLiquidity
115// ---------------------------------------------------------------------------
116
117/// Reserve liquidity state.
118#[derive(Debug, Clone, Copy, Pod, Zeroable)]
119#[repr(C)]
120pub struct ReserveLiquidity {
121    pub mint_pubkey: Pubkey,
122    pub supply_vault: Pubkey,
123    pub fee_vault: Pubkey,
124    pub total_available_amount: u64,
125    /// Total borrowed (scaled fraction).
126    pub borrowed_amount_sf: PodU128,
127    /// Market price in quote currency (scaled fraction).
128    pub market_price_sf: PodU128,
129    pub market_price_last_updated_ts: u64,
130    pub mint_decimals: u64,
131    pub deposit_limit_crossed_timestamp: u64,
132    pub borrow_limit_crossed_timestamp: u64,
133    /// Cumulative borrow rate (big scaled fraction).
134    pub cumulative_borrow_rate_bsf: BigFractionBytes,
135    /// Protocol fees (scaled fraction).
136    pub accumulated_protocol_fees_sf: PodU128,
137    /// Referrer fees (scaled fraction).
138    pub accumulated_referrer_fees_sf: PodU128,
139    /// Pending referrer fees (scaled fraction).
140    pub pending_referrer_fees_sf: PodU128,
141    /// Referral rate (scaled fraction).
142    pub absolute_referral_rate_sf: PodU128,
143    pub token_program: Pubkey,
144    pub padding2: [u64; 51],
145    pub padding3: [PodU128; 32],
146}
147
148// ---------------------------------------------------------------------------
149// ReserveCollateral
150// ---------------------------------------------------------------------------
151
152/// Reserve collateral state.
153#[derive(Debug, Clone, Copy, Pod, Zeroable)]
154#[repr(C)]
155pub struct ReserveCollateral {
156    pub mint_pubkey: Pubkey,
157    pub mint_total_supply: u64,
158    pub supply_vault: Pubkey,
159    pub padding1: [PodU128; 32],
160    pub padding2: [PodU128; 32],
161}
162
163// ---------------------------------------------------------------------------
164// ReserveConfig
165// ---------------------------------------------------------------------------
166
167/// Reserve configuration parameters.
168#[derive(Debug, Clone, Copy, Pod, Zeroable)]
169#[repr(C)]
170pub struct ReserveConfig {
171    /// 0 = Active, 1 = Obsolete, 2 = Hidden.
172    pub status: u8,
173    pub padding_deprecated_asset_tier: u8,
174    pub host_fixed_interest_rate_bps: u16,
175    pub min_deleveraging_bonus_bps: u16,
176    pub block_ctoken_usage: u8,
177    pub early_repay_remaining_interest_pct: u8,
178    /// Whether the reserve is in emergency mode.
179    pub emergency_mode: u8,
180    pub reserved_1: [u8; 4],
181    pub protocol_order_execution_fee_pct: u8,
182    pub protocol_take_rate_pct: u8,
183    pub protocol_liquidation_fee_pct: u8,
184    pub loan_to_value_pct: u8,
185    pub liquidation_threshold_pct: u8,
186    pub min_liquidation_bonus_bps: u16,
187    pub max_liquidation_bonus_bps: u16,
188    pub bad_debt_liquidation_bonus_bps: u16,
189    pub deleveraging_margin_call_period_secs: u64,
190    pub deleveraging_threshold_decrease_bps_per_day: u64,
191    pub fees: ReserveFees,
192    pub borrow_rate_curve: BorrowRateCurve,
193    pub borrow_factor_pct: u64,
194    pub deposit_limit: u64,
195    pub borrow_limit: u64,
196    pub token_info: TokenInfo,
197    pub deposit_withdrawal_cap: WithdrawalCaps,
198    pub debt_withdrawal_cap: WithdrawalCaps,
199    pub elevation_groups: [u8; 20],
200    pub disable_usage_as_coll_outside_emode: u8,
201    pub utilization_limit_block_borrowing_above_pct: u8,
202    pub autodeleverage_enabled: u8,
203    pub proposer_authority_locked: u8,
204    pub borrow_limit_outside_elevation_group: u64,
205    pub borrow_limit_against_this_collateral_in_elevation_group: [u64; 32],
206    pub deleveraging_bonus_increase_bps_per_day: u64,
207    pub debt_maturity_timestamp: u64,
208    pub debt_term_seconds: u64,
209}
210
211const _: () = assert!(core::mem::size_of::<ReserveConfig>() == 936);
212
213// ---------------------------------------------------------------------------
214// ReserveFees
215// ---------------------------------------------------------------------------
216
217#[derive(Debug, Clone, Copy, Zeroable, Pod)]
218#[repr(C)]
219pub struct ReserveFees {
220    /// Borrow origination fee (scaled fraction).
221    pub origination_fee_sf: u64,
222    /// Flash loan fee (u64::MAX = disabled).
223    pub flash_loan_fee_sf: u64,
224    pub padding: [u8; 8],
225}
226
227// ---------------------------------------------------------------------------
228// BorrowRateCurve / CurvePoint
229// ---------------------------------------------------------------------------
230
231#[derive(Debug, Clone, Copy, Zeroable, Pod)]
232#[repr(C)]
233pub struct BorrowRateCurve {
234    pub points: [CurvePoint; 11],
235}
236
237#[derive(Debug, Clone, Copy, Zeroable, Pod)]
238#[repr(C)]
239pub struct CurvePoint {
240    pub utilization_rate_bps: u32,
241    pub borrow_rate_bps: u32,
242}
243
244// ---------------------------------------------------------------------------
245// TokenInfo and oracle configs
246// ---------------------------------------------------------------------------
247
248#[derive(Debug, Clone, Copy, Pod, Zeroable)]
249#[repr(C)]
250pub struct TokenInfo {
251    pub name: [u8; 32],
252    pub heuristic: PriceHeuristic,
253    pub max_twap_divergence_bps: u64,
254    pub max_age_price_seconds: u64,
255    pub max_age_twap_seconds: u64,
256    pub scope_configuration: ScopeConfiguration,
257    pub switchboard_configuration: SwitchboardConfiguration,
258    pub pyth_configuration: PythConfiguration,
259    pub block_price_usage: u8,
260    pub reserved: [u8; 7],
261    pub _padding: [u64; 19],
262}
263
264const _: () = assert!(core::mem::size_of::<TokenInfo>() == 384);
265
266impl TokenInfo {
267    /// Token name as a UTF-8 string, trimmed of null padding.
268    ///
269    /// Returns `None` if the name bytes are not valid UTF-8.
270    pub fn name_str(&self) -> Option<&str> {
271        let end = self
272            .name
273            .iter()
274            .position(|&b| b == 0)
275            .unwrap_or(self.name.len());
276        core::str::from_utf8(&self.name[..end]).ok()
277    }
278}
279
280#[derive(Debug, Clone, Copy, Zeroable, Pod)]
281#[repr(C)]
282pub struct PriceHeuristic {
283    pub lower: u64,
284    pub upper: u64,
285    pub exp: u64,
286}
287
288#[derive(Debug, Clone, Copy, Zeroable, Pod)]
289#[repr(C)]
290pub struct ScopeConfiguration {
291    pub price_feed: Pubkey,
292    pub price_chain: [u16; 4],
293    pub twap_chain: [u16; 4],
294}
295
296#[derive(Debug, Clone, Copy, Zeroable, Pod)]
297#[repr(C)]
298pub struct SwitchboardConfiguration {
299    pub price_aggregator: Pubkey,
300    pub twap_aggregator: Pubkey,
301}
302
303#[derive(Debug, Clone, Copy, Zeroable, Pod)]
304#[repr(C)]
305pub struct PythConfiguration {
306    pub price: Pubkey,
307}
308
309// ---------------------------------------------------------------------------
310// WithdrawalCaps
311// ---------------------------------------------------------------------------
312
313#[derive(Debug, Clone, Copy, Zeroable, Pod)]
314#[repr(C)]
315pub struct WithdrawalCaps {
316    pub config_capacity: i64,
317    pub current_total: i64,
318    pub last_interval_start_timestamp: u64,
319    pub config_interval_length_seconds: u64,
320}
321
322// ---------------------------------------------------------------------------
323// WithdrawQueue
324// ---------------------------------------------------------------------------
325
326#[derive(Debug, Clone, Copy, Zeroable, Pod)]
327#[repr(C)]
328pub struct WithdrawQueue {
329    pub queued_collateral_amount: u64,
330    pub next_issued_ticket_sequence_number: u64,
331    pub next_withdrawable_ticket_sequence_number: u64,
332}