Skip to main content

Documentation Index

Fetch the complete documentation index at: https://kamino.com/docs/llms.txt

Use this file to discover all available pages before exploring further.

A fixed rate reserve locks borrowers into a predictable rate for a defined duration. Borrows on the reserve carry a maturity timestamp and pay a host-set fixed rate component on top of the variable IR curve. At maturity, the borrower must repay, roll over, or face liquidation. Each (rate, term) combination lives on its own reserve. A market that offers, say, 4%/30-day, 5%/60-day, and 6%/90-day USDC borrows would have three USDC fixed rate reserves — one per (rate, term) pair — each with its own debt maturity.

Reserve-level configuration

The fixed-rate mechanics are controlled by these ReserveConfig fields:
FieldWhat it does
debt_term_secondsDuration of the fixed term, in seconds. 0 = open-term reserve. Setting any positive value makes every borrow on this reserve a fixed-term borrow
debt_maturity_timestampOptional absolute Unix timestamp when all debt on this reserve matures simultaneously. 0 = each borrow rolls forward debt_term_seconds from origination
host_fixed_interest_rate_bpsFixed-rate component (bps) added to the variable rate from the IR curve
early_repay_remaining_interest_pctPenalty for repaying before maturity, expressed as percent (0–100) of the remaining interest to maturity

Market-level rollover settings

FieldWhat it does
fixed_term_rollover_window_duration_secondsWindow before maturity allowing fixed→fixed rollover. 0 disables
open_term_rollover_window_duration_secondsWindow before maturity allowing fixed→open rollover. 0 disables
obligation_borrow_migration_to_fixed_execution_enabledIf 1, allows open→fixed migration anytime
obligation_borrow_rollover_configuration_enabledIf 1, allows borrowers to pre-configure rollover behavior
min_partial_rollover_valueMinimum size for a partial rollover. 0 requires full rollovers only
term_based_full_liquidation_duration_secsTime after maturity before full (close-factor-bypassing) liquidation is available
mature_reserve_debt_liquidation_enabledMaster switch for mature-debt liquidation flow
obligation_borrow_debt_term_liquidation_enabledPer-feature switch for the term-based liquidation path

Configure a fixed rate reserve via SDK

Reserve-level fields are set via kaminoManager.updateReserveIxs (or at creation via addAssetToMarketIxs). Market-level rollover and liquidation flags are set via updateLendingMarketIxs.

Reserve config

import {
  KaminoManager,
  DEFAULT_RECENT_SLOT_DURATION_MS,
  PROGRAM_ID,
  MarketWithAddress,
} from '@kamino-finance/klend-sdk';
import { LendingMarket, Reserve } from '@kamino-finance/klend-sdk/dist/@codegen/klend/accounts';
import { address } from '@solana/kit';

// ... rpc setup, adminSigner ...

const kaminoManager = new KaminoManager(rpc, DEFAULT_RECENT_SLOT_DURATION_MS, PROGRAM_ID);

const marketState = await LendingMarket.fetch(rpc, marketAddress);
if (!marketState) throw new Error('Market not found');
const marketWithAddress: MarketWithAddress = { address: marketAddress, state: marketState };

const reserve = await Reserve.fetch(rpc, reserveAddress);
if (!reserve) throw new Error('Reserve not found');

const newConfig = { ...reserve.config };
newConfig.debtTermSeconds = 2_592_000n;            // 30 days
newConfig.debtMaturityTimestamp = 0n;              // 0 = per-borrow rolling term
newConfig.hostFixedInterestRateBps = 500;          // 5%
newConfig.earlyRepayRemainingInterestPct = 50;     // 50% penalty on remaining interest

const updateIxs = await kaminoManager.updateReserveIxs(
  adminSigner,
  marketWithAddress,
  reserveAddress,
  newConfig,
);
// submit each chunk in order

Market-level rollover and liquidation flags

const newLendingMarket = { ...marketState };
newLendingMarket.fixedTermRolloverWindowDurationSeconds = 172_800n;     // 48 hours
newLendingMarket.openTermRolloverWindowDurationSeconds = 0n;
newLendingMarket.obligationBorrowMigrationToFixedExecutionEnabled = 0;
newLendingMarket.obligationBorrowRolloverConfigurationEnabled = 1;
newLendingMarket.minPartialRolloverValue = 100_000n;
newLendingMarket.termBasedFullLiquidationDurationSecs = 86_400n;        // 24h after maturity
newLendingMarket.matureReserveDebtLiquidationEnabled = 1;
newLendingMarket.obligationBorrowDebtTermLiquidationEnabled = 1;

const ixs = kaminoManager.updateLendingMarketIxs(adminSigner, marketWithAddress, newLendingMarket);
// submit each ix in order

User-side rollover

The user-facing rollover instruction (rolloverFixedTermBorrow) is part of the on-chain klend program. The current public klend-sdk does not yet expose a dedicated TypeScript helper for it; until it ships, end-user apps integrate the rollover via the Kamino webapp or by building the instruction manually from the program IDL.

Open-term vs. fixed-rate

ModeConfiguration
Open-term (default)debt_term_seconds = 0, debt_maturity_timestamp = 0, host_fixed_interest_rate_bps = 0
Per-borrow rolling fixed termdebt_term_seconds > 0, debt_maturity_timestamp = 0. Every borrow matures debt_term_seconds after origination
Cohort fixed termdebt_term_seconds > 0, debt_maturity_timestamp > 0. All debt matures at the absolute timestamp
Mixing fixed and open on the same reserve isn’t supported. To run both, deploy two reserves for the same mint.

How interest accrues

Total borrow rate = IR curve rate at current utilization + host_fixed_interest_rate_bps. The fixed component is a flat bps add-on; the variable component reacts to utilization as on any reserve. The borrower’s actual cost depends on both how full the reserve is and the curator’s fixed-rate setting. This design lets a curator offer “5% fixed plus utilization premium” pricing while keeping the variable component responsive.

Maturity and what happens at it

When a borrow reaches its debt_maturity_timestamp (per-borrow or cohort):
OutcomeTrigger
Repay in fullThe borrower repays. The position closes
Roll overThe borrower rolls into a new fixed term — same reserve, different reserve, or migrates to open-term. Subject to market-level rollover flags
Liquidation as mature debtIf mature_reserve_debt_liquidation_enabled = 1 and obligation_borrow_debt_term_liquidation_enabled = 1, mature debt becomes liquidatable
Forced full liquidationAfter term_based_full_liquidation_duration_secs past maturity, the position is eligible for full (close-factor-bypassing) liquidation

The rollover modes

ModeSourceDestinationConstraints
Fixed → FixedA fixed rate reserveAnother (or same) fixed rate reserveAllowed only inside fixed_term_rollover_window_duration_seconds of original maturity
Fixed → OpenA fixed rate reserveAn open-term reserve for the same mintAllowed only inside open_term_rollover_window_duration_seconds of original maturity
Open → FixedAn open-term reserveA fixed rate reserve for the same mintAllowed any time, gated by obligation_borrow_migration_to_fixed_execution_enabled
Rollover preserves the principal but resets accrual: the new term starts fresh. Penalties from the prior term do not carry over.

Early-repay penalty

penalty = early_repay_remaining_interest_pct% × (interest that would have accrued from now to maturity)
early_repay_remaining_interest_pctEffect
0No penalty. Borrowers can repay any time at no extra cost
5050% of remaining interest is owed at repay. Mild discouragement of early exit
100Full term’s interest is locked in. The borrower owes the same regardless of repay time
If the borrower borrows additional principal on an already-active fixed-term position, the borrow timestamp is reset for the entire position. Effectively, the new top-up creates a new fixed term covering the combined balance. After a rollover, penalties reset to zero for the new term.

Curator workflow: launching a fixed rate reserve

1

Decide the (rate, term) matrix

Pick the durations and rates you want to offer (e.g., 30/60/90 days at 4%/5%/6%). Each combination is a separate reserve.
2

Configure each reserve

Set debt_term_seconds, host_fixed_interest_rate_bps, early_repay_remaining_interest_pct. Choose risk parameters (LTV, threshold, IR curve) appropriate for the duration.
3

Set market-level rollover windows

Decide the rollover window — how far before maturity borrowers can roll. Common settings: 24–72 hours.
4

Enable mature-debt liquidation

Set mature_reserve_debt_liquidation_enabled = 1 and obligation_borrow_debt_term_liquidation_enabled = 1. Choose term_based_full_liquidation_duration_secs (typically 12–48 hours after maturity).
5

Test on staging

Take a fixed-term borrow on staging, fast-forward time using a test scenario, exercise rollover, exercise repay, exercise mature-debt liquidation. Confirm the lifecycle works before mainnet.

Common errors

ErrorCause
BorrowRolloverExecutionDisabledMarket-level rollover window is 0. Set fixed_term_rollover_window_duration_seconds (or open_term_rollover_window_duration_seconds) to a positive value
RolloverWindowNotOpenBorrower tried to roll outside the configured window before maturity
MatureDebtLiquidationDisabledThe position is mature but liquidation flags are off. Either enable the liquidation flags or repay
Sub-$2 obligations stuck near maturityA known edge case where dust positions interact poorly with the close-factor cap. Set min_full_liquidation_value_threshold low enough that mature dust positions can be fully liquidated

Reference