Documentation Index
Fetch the complete documentation index at: https://mintlify.com/kamino-finance/klend/llms.txt
Use this file to discover all available pages before exploring further.
Overview
Elevation Groups (also called E-Mode or Efficiency Mode) are isolated risk tiers within Kamino Lending that allow for higher leverage and capital efficiency when borrowing and depositing correlated assets. Each elevation group has its own risk parameters and borrow limits.
ElevationGroup Structure
Defined in state/lending_market.rs:363:
pub struct ElevationGroup {
pub max_liquidation_bonus_bps: u16, // Max liquidation bonus (basis points)
pub id: u8, // Group ID (1-32, 0 = none)
pub ltv_pct: u8, // Loan-to-Value percentage
pub liquidation_threshold_pct: u8, // Liquidation threshold percentage
pub allow_new_loans: u8, // Whether new loans are allowed
pub max_reserves_as_collateral: u8, // Max number of collateral reserves
pub padding_0: u8,
pub debt_reserve: Pubkey, // Primary debt reserve for this group
pub padding_1: [u64; 4],
}
Key Fields:
id: Unique identifier (1-32). ELEVATION_GROUP_NONE (0) means no group
ltv_pct: Maximum loan-to-value ratio (e.g., 90 = 90%)
liquidation_threshold_pct: Liquidation threshold (e.g., 93 = 93%)
debt_reserve: The reserve that must be borrowed in this group
max_reserves_as_collateral: Limits collateral diversity
allow_new_loans: Enables/disables new borrowing
Lending Market Configuration
Storage (state/lending_market.rs:98):
pub struct LendingMarket {
// ...
pub elevation_groups: [ElevationGroup; 32], // Support up to 32 groups
pub elevation_group_padding: [u64; 90],
// ...
}
Each lending market can have up to 32 elevation groups.
Default Configuration (state/lending_market.rs:389):
impl Default for ElevationGroup {
fn default() -> Self {
let mut default = Self::zeroed();
default.max_reserves_as_collateral = u8::MAX; // No limit by default
default
}
}
Managing Elevation Groups
Getting an Elevation Group
Implementation (state/lending_market.rs:274):
pub fn get_elevation_group(&self, id: u8) -> Result<Option<&ElevationGroup>> {
if id == ELEVATION_GROUP_NONE {
Ok(None)
} else {
Ok(Some(
self.elevation_groups
.get(id as usize - 1)
.ok_or(LendingError::InvalidElevationGroup)?,
))
}
}
Note: Group ID is 1-indexed in the user-facing API, but 0-indexed in the array.
Setting an Elevation Group
Implementation (state/lending_market.rs:286):
pub fn set_elevation_group(&mut self, elevation_group: ElevationGroup) -> Result<()> {
// Cannot set ID 0 (reserved for ELEVATION_GROUP_NONE)
if elevation_group.id == ELEVATION_GROUP_NONE {
return err!(LendingError::InvalidElevationGroupConfig);
}
self.elevation_groups[elevation_group.get_index()] = elevation_group;
Ok(())
}
Helper (state/lending_market.rs:402):
pub fn get_index(&self) -> usize {
self.id as usize - 1 // Convert 1-indexed ID to 0-indexed array
}
Checking if New Loans are Allowed
// state/lending_market.rs:398
pub fn new_loans_disabled(&self) -> bool {
self.allow_new_loans == 0
}
Borrow Limits per Elevation Group
Elevation groups enforce strict borrowing rules:
Same Elevation Group Check
Implementation (lending_market/lending_operations.rs:246):
check_same_elevation_group(obligation, borrow_reserve)?;
When borrowing, the obligation’s elevation group must match the reserve’s elevation group.
Borrowing Enabled Checks
Elevation Group Borrowing (lending_market/lending_operations.rs:248):
check_elevation_group_borrowing_enabled(lending_market, obligation)?;
Non-Elevation Group Borrowing (lending_market/lending_operations.rs:249):
check_non_elevation_group_borrowing_enabled(obligation)?;
These functions verify that borrowing is allowed for the obligation’s elevation group configuration.
Debt Tracking
Reserve Fields (state/reserve.rs:92):
pub struct Reserve {
// ...
pub borrowed_amount_outside_elevation_group: u64,
pub borrowed_amounts_against_this_reserve_in_elevation_groups: [u64; 32],
// ...
}
Reserves track borrowed amounts both inside and outside elevation groups.
Update on Borrow (lending_market/lending_operations.rs:357):
let elevation_group = lending_market.get_elevation_group(obligation.elevation_group)?;
utils::update_elevation_group_debt_trackers_on_borrow(
borrow_amount,
obligation,
borrow_index,
elevation_group,
&borrow_reserve_pk,
borrow_reserve,
deposit_reserves_iter,
)?;
disable_usage_as_collateral_outside_emode
This reserve-level setting controls whether a reserve can be used as collateral outside of elevation groups.
Configuration (state/reserve.rs:1377):
pub struct ReserveConfig {
// ...
pub disable_usage_as_coll_outside_emode: u8,
// ...
}
Enforcement
During Deposit (lending_market/lending_operations.rs:414):
if deposit_reserve.config.disable_usage_as_coll_outside_emode > 0
&& obligation.elevation_group == ELEVATION_GROUP_NONE
&& obligation.borrow_factor_adjusted_debt_value_sf > 0
{
msg!("Deposit reserve is disabled for usage as collateral outside elevation group");
return err!(LendingError::DepositDisabledOutsideElevationGroup);
}
Conditions:
- Reserve has
disable_usage_as_coll_outside_emode enabled
- Obligation is not in an elevation group (
ELEVATION_GROUP_NONE)
- Obligation has existing debt
Result: Cannot deposit this asset as collateral unless you’re in an elevation group.
Use Case
This is typically used for correlated assets like:
- LSTs (Liquid Staking Tokens) that should only be used with stablecoin borrowing
- Stablecoins that should only be borrowed against similar stablecoins
- Wrapped assets that should only be used within their ecosystem
Example Configuration:
// wSOL reserve configuration
const wsolReserve = {
// ...
disable_usage_as_coll_outside_emode: 1, // Must be in elevation group
};
// Elevation Group 1: SOL/mSOL group
const solGroup = {
id: 1,
ltv_pct: 90,
liquidation_threshold_pct: 93,
debt_reserve: wsolReserve,
// Users can deposit mSOL and borrow wSOL at high LTV
};
Configuration Examples
Example 1: Stablecoin Elevation Group
const stablecoinGroup: ElevationGroup = {
id: 1,
ltv_pct: 98, // 98% LTV for correlated stables
liquidation_threshold_pct: 99, // 99% liquidation threshold
max_liquidation_bonus_bps: 100, // 1% max liquidation bonus
allow_new_loans: 1, // Enabled
max_reserves_as_collateral: 3, // Max 3 different stables as collateral
debt_reserve: usdcReservePubkey, // Must borrow USDC
padding_0: 0,
padding_1: [0, 0, 0, 0],
};
// Allowed scenario:
// - Deposit USDT, USDC, DAI as collateral (3 reserves)
// - Borrow USDC up to 98% LTV
// - Low liquidation risk due to asset correlation
Example 2: LST (Liquid Staking Token) Group
const lstGroup: ElevationGroup = {
id: 2,
ltv_pct: 90, // 90% LTV
liquidation_threshold_pct: 93, // 93% liquidation threshold
max_liquidation_bonus_bps: 500, // 5% max liquidation bonus
allow_new_loans: 1,
max_reserves_as_collateral: 255, // No limit
debt_reserve: solReservePubkey, // Must borrow SOL
padding_0: 0,
padding_1: [0, 0, 0, 0],
};
// Allowed scenario:
// - Deposit mSOL, stSOL, jitoSOL as collateral
// - Borrow SOL up to 90% LTV
// - Efficient capital use for SOL derivatives
Example 3: Isolated Lending Pool
const isolatedGroup: ElevationGroup = {
id: 3,
ltv_pct: 50, // Conservative 50% LTV
liquidation_threshold_pct: 60, // 60% liquidation threshold
max_liquidation_bonus_bps: 1500, // 15% max liquidation bonus
allow_new_loans: 1,
max_reserves_as_collateral: 1, // Only 1 collateral type
debt_reserve: volatileTokenReserve, // Borrow volatile asset
padding_0: 0,
padding_1: [0, 0, 0, 0],
};
// Allowed scenario:
// - Deposit single collateral type
// - Borrow volatile asset
// - Isolated from other groups to limit contagion risk
Setting Elevation Group via Update Config
Update Mode (lending_market/lending_operations.rs:2284):
UpdateConfigMode::UpdateDisableUsageAsCollOutsideEmode => {
config_items::for_named_field!(&mut reserve.config.disable_usage_as_coll_outside_emode)
.validating(validations::check_valid_bool_u8)
.set(value)?;
}
Market owners can update this configuration through the update_reserve_config instruction.
Working with Elevation Groups
Entering an Elevation Group
Users enter elevation groups by:
- Depositing collateral from reserves in the group
- Borrowing from the group’s
debt_reserve
The obligation automatically joins the elevation group.
Constraints While in a Group
Collateral Restrictions (lending_market/lending_operations.rs:422):
check_same_elevation_group(obligation, deposit_reserve)?;
Can only deposit collateral from reserves in the same elevation group.
Borrow Restrictions (lending_market/lending_operations.rs:246):
check_same_elevation_group(obligation, borrow_reserve)?;
Can only borrow from reserves in the same elevation group.
Exiting an Elevation Group
To exit:
- Repay all borrows
- Withdraw all collateral
- Obligation returns to
ELEVATION_GROUP_NONE
Checking Elevation Group Status
const checkObligationElevationGroup = async (obligation: PublicKey) => {
const obligationData = await loadObligation(obligation);
if (obligationData.elevationGroup === 0) {
console.log("Obligation not in any elevation group");
} else {
console.log(`Obligation in elevation group: ${obligationData.elevationGroup}`);
const lendingMarketData = await loadLendingMarket(lendingMarket);
const group = lendingMarketData.elevationGroups[obligationData.elevationGroup - 1];
console.log(`LTV: ${group.ltvPct}%`);
console.log(`Liquidation Threshold: ${group.liquidationThresholdPct}%`);
console.log(`Max Collateral Reserves: ${group.maxReservesAsCollateral}`);
}
};
Best Practices
- Asset Correlation: Only group highly correlated assets (e.g., stablecoins, LSTs)
- Risk Parameters: Set conservative LTV/liquidation thresholds based on historical price volatility
- Collateral Limits: Use
max_reserves_as_collateral to limit risk from too many collateral types
- Isolation: Use elevation groups to isolate risky assets from the main lending pool
- Monitoring: Track debt levels per elevation group to identify concentration risk
Advanced: Debt Tracking Across Groups
Reserves maintain separate debt counters for each elevation group:
// state/reserve.rs:92-96
pub borrowed_amount_outside_elevation_group: u64,
pub borrowed_amounts_against_this_reserve_in_elevation_groups: [u64; 32],
This enables:
- Per-group borrow limits: Limit exposure to specific elevation groups
- Risk isolation: Track how much is borrowed in vs out of elevation groups
- Utilization monitoring: Understand which groups are driving reserve utilization
Errors
InvalidElevationGroup:
- Elevation group ID doesn’t exist
- ID must be 1-32
InvalidElevationGroupConfig:
- Attempting to set ID 0 (reserved)
- Invalid configuration parameters
DepositDisabledOutsideElevationGroup:
- Reserve requires elevation group membership
- Enable
disable_usage_as_coll_outside_emode
ElevationGroupBorrowLimitExceeded:
- Borrowing would exceed group’s limits
- Check available capacity in the group