Skip to main content
Deposit assets as collateral into Kamino lending reserves, then borrow other assets against your deposited collateral.

Deposit Collateral

Deposit assets as collateral to enable borrowing.
1

Import Dependencies

Import the required packages for Solana RPC communication, Kamino SDK operations, and Kit transaction building.
import {
  createSolanaRpc,
  createSolanaRpcSubscriptions,
  address,
  pipe,
  createTransactionMessage,
  setTransactionMessageFeePayerSigner,
  setTransactionMessageLifetimeUsingBlockhash,
  appendTransactionMessageInstructions,
  signTransactionMessageWithSigners,
  sendAndConfirmTransactionFactory,
  getSignatureFromTransaction,
} from '@solana/kit';
import { KaminoMarket, KaminoAction, VanillaObligation, PROGRAM_ID } from '@kamino-finance/klend-sdk';
import { parseKeypairFile } from '@kamino-finance/klend-sdk/dist/utils/signer.js';
import BN from 'bn.js';
2

Load Signer and Initialize Market

Load your keypair from a file and initialize RPC connections and the Kamino market.
const KEYPAIR_FILE = '/path/to/your/keypair.json';

const signer = await parseKeypairFile(KEYPAIR_FILE);

const rpc = createSolanaRpc('https://api.mainnet-beta.solana.com');
const rpcSubscriptions = createSolanaRpcSubscriptions('wss://api.mainnet-beta.solana.com');
const marketPubkey = address('7u3HeHxYDLhnCoErrtycNokbQYbWGzLs6JSDqGAv5PfF');
const market = await KaminoMarket.load(rpc, marketPubkey, 100);
Replace /path/to/your/keypair.json with the actual path to your keypair file. The KaminoMarket.load() method fetches the current market state including all reserve data.
3

Build Deposit Instructions

Build deposit instructions for depositing collateral to enable borrowing.
const usdcMint = address('EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v');
const depositAmount = new BN(3_000_000); // 3 USDC (6 decimals)

const signatures: string[] = [];

let depositAction = await KaminoAction.buildDepositTxns(
  market!,
  depositAmount,
  usdcMint,
  signer,
  new VanillaObligation(PROGRAM_ID),
  true,
  undefined,
  1_000_000,
  true,
  false,
  { skipInitialization: false, skipLutCreation: false }
);

const hasSetup = (depositAction.setupIxs || []).length > 0;

let instructions = [
  ...(depositAction.setupIxs || []),
  ...(depositAction.lendingIxs || []),
  ...(depositAction.cleanupIxs || []),
];
The buildDepositTxns method creates instructions to deposit collateral. This enables you to borrow other assets against your deposit.
4

Send Deposit Transaction with Error Handling

Send the deposit transaction with automatic retry logic for setup-related errors.
try {
  const { value: depositBlockhash } = await rpc.getLatestBlockhash({ commitment: 'finalized' }).send();
  const depositTx = pipe(
    createTransactionMessage({ version: 0 }),
    (tx) => setTransactionMessageFeePayerSigner(signer, tx),
    (tx) => setTransactionMessageLifetimeUsingBlockhash(depositBlockhash, tx),
    (tx) => appendTransactionMessageInstructions(instructions, tx)
  );
  const depositSigned = await signTransactionMessageWithSigners(depositTx);
  const depositSignature = getSignatureFromTransaction(depositSigned);
  signatures.push(depositSignature);

  await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })(depositSigned, {
    commitment: 'confirmed',
    skipPreflight: true,
  });

  console.log(`Deposit successful! Signature: ${depositSignature}`);
} catch (error: any) {
  const errorMsg = error?.message || error?.toString() || '';
  const is0x17a3 =
    errorMsg.includes('0x17a3') || errorMsg.includes('6051') || errorMsg.includes('IncorrectInstructionInPosition');

  if (hasSetup && is0x17a3) {
    await new Promise((resolve) => setTimeout(resolve, 2000));

    const reloadedMarket = await KaminoMarket.load(rpc, marketPubkey, 400);

    depositAction = await KaminoAction.buildDepositTxns(
      reloadedMarket!,
      depositAmount,
      usdcMint,
      signer,
      new VanillaObligation(PROGRAM_ID),
      true,
      undefined,
      1_000_000,
      true,
      false,
      { skipInitialization: false, skipLutCreation: false }
    );

    instructions = [
      ...(depositAction.setupIxs || []),
      ...(depositAction.lendingIxs || []),
      ...(depositAction.cleanupIxs || []),
    ];

    const { value: retryBlockhash } = await rpc.getLatestBlockhash({ commitment: 'finalized' }).send();
    const retryTx = pipe(
      createTransactionMessage({ version: 0 }),
      (tx) => setTransactionMessageFeePayerSigner(signer, tx),
      (tx) => setTransactionMessageLifetimeUsingBlockhash(retryBlockhash, tx),
      (tx) => appendTransactionMessageInstructions(instructions, tx)
    );
    const retrySigned = await signTransactionMessageWithSigners(retryTx);
    const retrySignature = getSignatureFromTransaction(retrySigned);
    signatures.push(retrySignature);

    await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })(retrySigned, {
      commitment: 'confirmed',
      skipPreflight: true,
    });

    console.log(
      `Deposit successful! Signature: ${retrySignature}\nSetup transaction: https://solscan.io/tx/${signatures[0]}`
    );
  } else {
    console.error('Deposit failed:', error);
  }
}
When setup instructions are included, the first transaction may fail with error 0x17a3. The retry logic handles this by waiting for blockchain state to settle, reloading the market, and rebuilding instructions.
Once the deposit transaction is confirmed, your collateral is deposited and you can now borrow assets against it. An obligation is created to track your position.

Borrow Assets

Borrow assets against your deposited collateral.
1

Import Dependencies

Import the required packages for Solana RPC communication, Kamino SDK operations, and Kit transaction building.
import {
  createSolanaRpc,
  createSolanaRpcSubscriptions,
  address,
  pipe,
  createTransactionMessage,
  setTransactionMessageFeePayerSigner,
  setTransactionMessageLifetimeUsingBlockhash,
  appendTransactionMessageInstructions,
  signTransactionMessageWithSigners,
  sendAndConfirmTransactionFactory,
  getSignatureFromTransaction,
} from '@solana/kit';
import { KaminoMarket, KaminoAction, VanillaObligation, PROGRAM_ID } from '@kamino-finance/klend-sdk';
import { parseKeypairFile } from '@kamino-finance/klend-sdk/dist/utils/signer.js';
import BN from 'bn.js';
2

Load Signer and Initialize Market

Load your keypair from a file and initialize RPC connections and the Kamino market.
const KEYPAIR_FILE = '/path/to/your/keypair.json';

const signer = await parseKeypairFile(KEYPAIR_FILE);

const rpc = createSolanaRpc('https://api.mainnet-beta.solana.com');
const rpcSubscriptions = createSolanaRpcSubscriptions('wss://api.mainnet-beta.solana.com');
const marketPubkey = address('7u3HeHxYDLhnCoErrtycNokbQYbWGzLs6JSDqGAv5PfF');
const market = await KaminoMarket.load(rpc, marketPubkey, 100);
Replace /path/to/your/keypair.json with the actual path to your keypair file. The KaminoMarket.load() method fetches the current market state including all reserve data.
3

Check for Existing Obligation

Verify that an obligation exists before attempting to borrow.
const existingObligation = await market!.getObligationByWallet(signer.address, new VanillaObligation(PROGRAM_ID));

if (!existingObligation) {
  throw new Error('No existing obligation found. Please deposit collateral first.');
}
You must have an existing obligation with deposited collateral before you can borrow. If you haven’t deposited collateral yet, do that first.
4

Build Borrow Instructions

Generate borrow instructions for the specified token and amount.
const usdtMint = address('Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB');
const borrowAmount = new BN(1_000_000); // 1.00 USDT (6 decimals)

const borrowAction = await KaminoAction.buildBorrowTxns(
  market!,
  borrowAmount,
  usdtMint,
  signer,
  new VanillaObligation(PROGRAM_ID),
  true,
  undefined,
  1_000_000,
  true,
  false
);

const allInstructions = [
  ...(borrowAction.setupIxs || []),
  ...(borrowAction.lendingIxs || []),
  ...(borrowAction.cleanupIxs || []),
];
The buildBorrowTxns method creates borrow instructions that withdraw assets from the reserve pool to your wallet. The amount borrowed is added to your debt obligation.
5

Build and Sign Transaction

Use Kit’s functional pipe pattern to build and sign the transaction with a fresh blockhash.
const { value: latestBlockhash } = await rpc
  .getLatestBlockhash({
    commitment: 'finalized',
  })
  .send();

const transactionMessage = pipe(
  createTransactionMessage({ version: 0 }),
  (tx) => setTransactionMessageFeePayerSigner(signer, tx),
  (tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx),
  (tx) => appendTransactionMessageInstructions(allInstructions, tx)
);

const signedTransaction = await signTransactionMessageWithSigners(transactionMessage);
6

Send and Confirm Transaction

Send the borrow transaction and wait for confirmation.
const signature = getSignatureFromTransaction(signedTransaction);

await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })(signedTransaction, {
  commitment: 'confirmed',
  skipPreflight: true,
});

console.log('Borrow successful! Signature:', signature);
Once the borrow transaction is confirmed, the borrowed assets are transferred to your wallet. You now have a debt obligation that accrues interest. Monitor your loan-to-value ratio to avoid liquidation.