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.

Withdraw assets from Kamino Earn vaults to redeem your shares for underlying tokens. The SDK handles transaction building and vault interaction.

Complete Flow

Implement the full withdrawal flow either in an off-chain TypeScript client or via on-chain Rust CPI within your Anchor program.
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 { KaminoVault } from '@kamino-finance/klend-sdk';
import { parseKeypairFile } from '@kamino-finance/klend-sdk/dist/utils/signer.js';
import { Decimal } from 'decimal.js';
@solana/kit provides modern utilities for RPC, transaction building, and signing. @kamino-finance/klend-sdk contains vault operation methods.
2

Load Keypair and Initialize Vault

Load the keypair from file, initialize RPC connections, and create the vault instance.
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 vault = new KaminoVault(
  rpc,
  address('HDsayqAsDWy3QvANGqh2yNraqcD8Fnjgh73Mhb3WRS5E') // USDC vault
);
parseKeypairFile loads an existing keypair from a JSON file.
3

Build Withdraw Instructions

Generate withdraw instructions including optional unstaking instructions.
const withdrawAmount = new Decimal(1.0);
const bundle = await vault.withdrawIxs(signer, withdrawAmount);
const instructions = [...(bundle.unstakeFromFarmIfNeededIxs || []), ...(bundle.withdrawIxs || [])];

if (!instructions.length) {
  throw new Error('No instructions returned by Kamino SDK');
}
The withdrawIxs method returns both unstaking and withdraw instructions. The bundle ensures optimal handling by automatically unstaking deposited assets when needed. The amount represents vault shares to redeem.
4

Build and Send Transaction

Fetch the latest blockhash and construct the transaction message.
const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();

const transactionMessage = pipe(
  createTransactionMessage({ version: 0 }),
  (tx) => setTransactionMessageFeePayerSigner(signer, tx),
  (tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx),
  (tx) => appendTransactionMessageInstructions(instructions, tx)
);
Kit’s pipe function enables functional composition of transaction building steps for cleaner, more maintainable code.
Sign and send the transaction with built-in confirmation.
const signedTransaction = await signTransactionMessageWithSigners(transactionMessage);

const signature = getSignatureFromTransaction(signedTransaction);

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

console.log('Withdraw successful! Signature:', signature);
The withdrawal is complete. Your vault shares have been redeemed for the underlying assets.

Full Code Example

import {
  createSolanaRpc,
  createSolanaRpcSubscriptions,
  address,
  pipe,
  createTransactionMessage,
  setTransactionMessageFeePayerSigner,
  setTransactionMessageLifetimeUsingBlockhash,
  appendTransactionMessageInstructions,
  signTransactionMessageWithSigners,
  sendAndConfirmTransactionFactory,
  getSignatureFromTransaction,
} from '@solana/kit';
import { KaminoVault } from '@kamino-finance/klend-sdk';
import { parseKeypairFile } from '@kamino-finance/klend-sdk/dist/utils/signer.js';
import { Decimal } from 'decimal.js';

// Configuration - UPDATE THESE VALUES
const KEYPAIR_FILE = '/path/to/your/keypair.json';

// Load keypair from file
const signer = await parseKeypairFile(KEYPAIR_FILE);

// Initialize RPC and RPC Subscriptions
const rpc = createSolanaRpc('https://api.mainnet-beta.solana.com');
const rpcSubscriptions = createSolanaRpcSubscriptions('wss://api.mainnet-beta.solana.com');
const vault = new KaminoVault(
  rpc,
  address('HDsayqAsDWy3QvANGqh2yNraqcD8Fnjgh73Mhb3WRS5E') // USDC vault
);

// Build withdraw instructions (includes optional unstaking)
const withdrawAmount = new Decimal(1.0);
const bundle = await vault.withdrawIxs(signer, withdrawAmount);
const instructions = [...(bundle.unstakeFromFarmIfNeededIxs || []), ...(bundle.withdrawIxs || [])];

if (!instructions.length) {
  throw new Error('No instructions returned by Kamino SDK');
}

// Build and sign transaction using functional pipe pattern
const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();

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

const signedTransaction = await signTransactionMessageWithSigners(transactionMessage);

// Send and confirm transaction
const signature = getSignatureFromTransaction(signedTransaction);

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

console.log('Withdraw successful! Signature:', signature);