Skip to main content

Quickstart

This guide will walk you through setting up your development environment and making your first interaction with the Kamino Lending protocol on Solana.

Prerequisites

Before you begin, ensure you have:
  • Node.js 16+ installed
  • Solana CLI tools installed
  • A Solana wallet with devnet SOL for testing
  • Basic familiarity with Solana and Anchor

Installation

1

Install Anchor CLI

Kamino Lending is built with Anchor 0.29.0. Install the Anchor CLI:
cargo install --git https://github.com/coral-xyz/anchor --tag v0.29.0 anchor-cli
Verify the installation:
anchor --version
# Should output: anchor-cli 0.29.0
2

Set up your project

Create a new project and install dependencies:
mkdir my-klend-integration
cd my-klend-integration
npm init -y
npm install @coral-xyz/anchor @solana/web3.js
You’ll also need the Kamino Lending IDL file to interact with the program. You can generate it from the source or obtain it from the Kamino Finance repository.
3

Configure your connection

Create a file config.ts to set up your connection to the Kamino Lending program:
import { Connection, PublicKey, clusterApiUrl } from '@solana/web3.js';
import { AnchorProvider, Program } from '@coral-xyz/anchor';

// Kamino Lending program ID on devnet
export const KLEND_PROGRAM_ID = new PublicKey(
  'KLend2g3cP87fffoy8q1mQqGKjrxjC8boSyAYavgmjD'
);

// Connect to devnet
export const connection = new Connection(
  clusterApiUrl('devnet'),
  'confirmed'
);

// Set up provider (you'll need to configure your wallet)
export function getProvider(wallet: any) {
  return new AnchorProvider(
    connection,
    wallet,
    { commitment: 'confirmed' }
  );
}
4

Initialize an obligation

An obligation tracks a user’s deposits and borrows. Here’s how to create one:
import { PublicKey, Keypair, SystemProgram } from '@solana/web3.js';
import { Program } from '@coral-xyz/anchor';
import { KLEND_PROGRAM_ID } from './config';

async function initializeObligation(
  program: Program,
  lendingMarket: PublicKey,
  obligationOwner: Keypair,
  userMetadata: PublicKey
) {
  // Generate a unique ID for this obligation
  const obligationId = 0;
  const tag = 0; // Tag 0 = no specific seed requirements
  
  // Derive the obligation PDA
  const [obligationPubkey] = PublicKey.findProgramAddressSync(
    [
      Buffer.from([tag]),
      Buffer.from([obligationId]),
      obligationOwner.publicKey.toBuffer(),
      lendingMarket.toBuffer(),
      PublicKey.default.toBuffer(), // seed1_account for tag 0
      PublicKey.default.toBuffer(), // seed2_account for tag 0
    ],
    KLEND_PROGRAM_ID
  );
  
  // Initialize the obligation
  const tx = await program.methods
    .initObligation({
      tag,
      id: obligationId,
    })
    .accounts({
      obligationOwner: obligationOwner.publicKey,
      feePayer: obligationOwner.publicKey,
      obligation: obligationPubkey,
      lendingMarket,
      seed1Account: PublicKey.default,
      seed2Account: PublicKey.default,
      ownerUserMetadata: userMetadata,
      systemProgram: SystemProgram.programId,
    })
    .signers([obligationOwner])
    .rpc();
  
  console.log('Obligation initialized:', obligationPubkey.toString());
  console.log('Transaction signature:', tx);
  
  return obligationPubkey;
}
The initObligation instruction is defined at src/lib.rs:135. It requires a UserMetadata account to track referrals.
5

Deposit liquidity to a reserve

Once you have an obligation, you can deposit assets into reserves:
import { PublicKey } from '@solana/web3.js';
import { TOKEN_PROGRAM_ID, getAssociatedTokenAddress } from '@solana/spl-token';

async function depositReserveLiquidity(
  program: Program,
  reserve: PublicKey,
  lendingMarket: PublicKey,
  user: Keypair,
  amount: number
) {
  const reserveData = await program.account.reserve.fetch(reserve);
  
  // Get user token accounts
  const userSourceLiquidity = await getAssociatedTokenAddress(
    reserveData.liquidity.mintPubkey,
    user.publicKey
  );
  
  const userDestinationCollateral = await getAssociatedTokenAddress(
    reserveData.collateral.mintPubkey,
    user.publicKey
  );
  
  // Derive lending market authority
  const [lendingMarketAuthority] = PublicKey.findProgramAddressSync(
    [Buffer.from('lma'), lendingMarket.toBuffer()],
    KLEND_PROGRAM_ID
  );
  
  // Deposit liquidity
  const tx = await program.methods
    .depositReserveLiquidity(amount)
    .accounts({
      owner: user.publicKey,
      reserve,
      lendingMarket,
      lendingMarketAuthority,
      reserveLiquidityMint: reserveData.liquidity.mintPubkey,
      reserveLiquiditySupply: reserveData.liquidity.supplyVault,
      reserveCollateralMint: reserveData.collateral.mintPubkey,
      userSourceLiquidity,
      userDestinationCollateral,
      liquidityTokenProgram: TOKEN_PROGRAM_ID,
      collateralTokenProgram: TOKEN_PROGRAM_ID,
    })
    .signers([user])
    .rpc();
  
  console.log('Liquidity deposited successfully');
  console.log('Transaction signature:', tx);
}
The depositReserveLiquidity instruction is disabled when the lending market is in emergency mode. The instruction is defined at src/lib.rs:120.
6

Query account data

Read on-chain data to monitor positions and market state:
async function getObligationHealth(
  program: Program,
  obligation: PublicKey
) {
  const obligationData = await program.account.obligation.fetch(obligation);
  
  // Convert scale factors to human-readable values
  const depositedValue = obligationData.depositedValueSf;
  const borrowedValue = obligationData.borrowedAssetsMarketValueSf;
  const allowedBorrowValue = obligationData.allowedBorrowValueSf;
  
  console.log('Obligation Health:');
  console.log('  Deposited Value:', depositedValue.toString());
  console.log('  Borrowed Value:', borrowedValue.toString());
  console.log('  Allowed Borrow Value:', allowedBorrowValue.toString());
  console.log('  Active Deposits:', obligationData.deposits.filter(
    d => d.depositedAmount > 0
  ).length);
  console.log('  Active Borrows:', obligationData.borrows.filter(
    b => b.borrowedAmountSf > 0
  ).length);
  
  return obligationData;
}

Next steps

Now that you’ve successfully interacted with Kamino Lending, explore more advanced features:

Borrowing

Learn how to borrow assets against collateral

Flash loans

Execute uncollateralized flash loan strategies

Liquidations

Participate in protocol liquidations

Program Reference

Explore all program instructions

Common program IDs

Keep these addresses handy when building your integration:
NetworkProgram ID
MainnetKLend2g3cP87fffoy8q1mQqGKjrxjC8boSyAYavgmjD
StagingSLendK7ySfcEzyaFqy93gDnD3RtrpXJcnRwb6zFHJSh
DevnetKLend2g3cP87fffoy8q1mQqGKjrxjC8boSyAYavgmjD
For production deployments, always verify the program ID and test thoroughly on devnet first.

Build docs developers (and LLMs) love