Skip to main content

Documentation Index

Fetch the complete documentation index at: https://v2-docs.exponent.finance/llms.txt

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

Use these instructions when your strategy vault should interact with Kamino Lend. For direct Kamino Vault deposits and direct Kamino Farm staking, see Kamino Vault instructions and Kamino Farm instructions.

Transaction structure

Every Kamino Lend action goes through createVaultSyncTransaction.
import BN from "bn.js";
import {
  KaminoMarket,
  createVaultSyncTransaction,
  kaminoAction,
} from "@exponent-labs/exponent-sdk";
import {
  Transaction,
  sendAndConfirmTransaction,
} from "@solana/web3.js";

const { setupInstructions, preInstructions, instruction, postInstructions } =
  await createVaultSyncTransaction({
    instructions: [
      kaminoAction.deposit(KaminoMarket.MAIN, "USDC", new BN(100_000_000)),
    ],
    owner: vaultPda,
    connection,
    policyPda,
    vaultPda,
    signer: wallet.publicKey,
    vaultAddress,
  });

const tx = new Transaction().add(
  ...setupInstructions,
  ...preInstructions,
  instruction,
  ...postInstructions,
);
await sendAndConfirmTransaction(connection, tx, [wallet]);
PartWhat it contains
setupInstructionsSetup instructions that must run before refreshes or the sync step
preInstructionsPermissionless refresh instructions that must run before the sync step
instructionThe Squads sync transaction instruction that wraps the vault-signed Kamino action
postInstructionsPermissionless refresh instructions that must run after the sync step
Kamino refresh instructions must stay top-level. Send the result in this order: setupInstructions, then preInstructions, then instruction, then postInstructions.

One-time setup

Before deposit, withdraw, borrow, or repay, the managed vault usually needs two Kamino Lending accounts.

Init user metadata

Creates the Kamino UserMetadata PDA for the managed vault owner.
kaminoAction.initUserMetadata(KaminoMarket.MAIN)

Init obligation

Creates the Kamino Obligation PDA for one lending market.
kaminoAction.initObligation(KaminoMarket.MAIN)
Both setup actions are safe to include before a lending action in the same createVaultSyncTransaction call.

Deposit

kaminoAction.deposit deposits the vault’s reserve token ATA into a Kamino reserve and receives reserve collateral inside the obligation.
import BN from "bn.js";
import {
  KaminoMarket,
  createVaultSyncTransaction,
  kaminoAction,
} from "@exponent-labs/exponent-sdk";
import {
  Transaction,
  sendAndConfirmTransaction,
} from "@solana/web3.js";

const { setupInstructions, preInstructions, instruction, postInstructions } =
  await createVaultSyncTransaction({
    instructions: [
      kaminoAction.deposit(KaminoMarket.MAIN, "USDC", new BN(100_000_000)),
    ],
    owner: vaultPda,
    connection,
    policyPda,
    vaultPda,
    signer: wallet.publicKey,
    vaultAddress,
  });

const tx = new Transaction().add(
  ...setupInstructions,
  ...preInstructions,
  instruction,
  ...postInstructions,
);
await sendAndConfirmTransaction(connection, tx, [wallet]);

Parameters

ParameterTypeDescription
marketKaminoMarketKamino lending market such as KaminoMarket.MAIN
assetstringReserve key from KAMINO_RESERVES[market]
amountBNAmount to deposit in native token units
A matching policy must exist before you execute the transaction. See Policy Builders.

Withdraw

kaminoAction.withdraw redeems reserve collateral back into the vault’s reserve token ATA.
const { setupInstructions, preInstructions, instruction, postInstructions } =
  await createVaultSyncTransaction({
    instructions: [
      kaminoAction.withdraw(KaminoMarket.MAIN, "USDC", new BN(50_000_000)),
    ],
    owner: vaultPda,
    connection,
    policyPda,
    vaultPda,
    signer: wallet.publicKey,
    vaultAddress,
  });

const tx = new Transaction().add(
  ...setupInstructions,
  ...preInstructions,
  instruction,
  ...postInstructions,
);
await sendAndConfirmTransaction(connection, tx, [wallet]);

Parameters

ParameterTypeDescription
marketKaminoMarketKamino lending market
assetstringReserve key from KAMINO_RESERVES[market]
amountBNAmount to withdraw in native token units
You specify the underlying token amount. The SDK resolves the collateral-side accounting from the reserve state.
A matching policy must exist before you execute the transaction. See Policy Builders.

Borrow

kaminoAction.borrow borrows reserve liquidity against the vault’s Kamino obligation.
const { setupInstructions, preInstructions, instruction, postInstructions } =
  await createVaultSyncTransaction({
    instructions: [
      kaminoAction.borrow(KaminoMarket.MAIN, "SOL", new BN(1_000_000_000)),
    ],
    owner: vaultPda,
    connection,
    policyPda,
    vaultPda,
    signer: wallet.publicKey,
    vaultAddress,
  });

const tx = new Transaction().add(
  ...setupInstructions,
  ...preInstructions,
  instruction,
  ...postInstructions,
);
await sendAndConfirmTransaction(connection, tx, [wallet]);

Parameters

ParameterTypeDescription
marketKaminoMarketKamino lending market
assetstringReserve key to borrow from
amountBNAmount to borrow in native token units
A matching policy must exist before you execute the transaction. See Policy Builders.

Repay

kaminoAction.repay repays borrowed reserve liquidity.
const { setupInstructions, preInstructions, instruction, postInstructions } =
  await createVaultSyncTransaction({
    instructions: [
      kaminoAction.repay(KaminoMarket.MAIN, "SOL", new BN(1_000_000_000)),
    ],
    owner: vaultPda,
    connection,
    policyPda,
    vaultPda,
    signer: wallet.publicKey,
    vaultAddress,
  });

const tx = new Transaction().add(
  ...setupInstructions,
  ...preInstructions,
  instruction,
  ...postInstructions,
);
await sendAndConfirmTransaction(connection, tx, [wallet]);

Parameters

ParameterTypeDescription
marketKaminoMarketKamino lending market
assetstringReserve key to repay
amountBNAmount to repay in native token units
A matching policy must exist before you execute the transaction. See Policy Builders.

Full flow example

This flow deposits USDC into Kamino Lend, borrows SOL, repays the SOL borrow, and then withdraws the USDC collateral.

Step 1: Setup and deposit

import BN from "bn.js";
import {
  ExponentVault,
  KaminoMarket,
  createVaultSyncTransaction,
  kaminoAction,
} from "@exponent-labs/exponent-sdk";
import {
  Connection,
  PublicKey,
  Transaction,
  sendAndConfirmTransaction,
} from "@solana/web3.js";

const connection = new Connection("https://api.mainnet-beta.solana.com");
const vault = await ExponentVault.load({ connection, address: vaultAddress });

const vaultPda = vault.state.squadsVault;
const policyPda = new PublicKey("...");

const { setupInstructions, preInstructions, instruction, postInstructions } =
  await createVaultSyncTransaction({
    instructions: [
      kaminoAction.initUserMetadata(KaminoMarket.MAIN),
      kaminoAction.initObligation(KaminoMarket.MAIN),
      kaminoAction.deposit(KaminoMarket.MAIN, "USDC", new BN(1_000_000_000)),
    ],
    owner: vaultPda,
    connection,
    policyPda,
    vaultPda,
    signer: wallet.publicKey,
    vaultAddress,
  });

const tx = new Transaction().add(
  ...setupInstructions,
  ...preInstructions,
  instruction,
  ...postInstructions,
);
await sendAndConfirmTransaction(connection, tx, [wallet]);

Step 2: Borrow SOL against collateral

const { setupInstructions, preInstructions, instruction, postInstructions } =
  await createVaultSyncTransaction({
    instructions: [
      kaminoAction.borrow(KaminoMarket.MAIN, "SOL", new BN(5_000_000_000)),
    ],
    owner: vaultPda,
    connection,
    policyPda,
    vaultPda,
    signer: wallet.publicKey,
    vaultAddress,
  });

const tx = new Transaction().add(
  ...setupInstructions,
  ...preInstructions,
  instruction,
  ...postInstructions,
);
await sendAndConfirmTransaction(connection, tx, [wallet]);

Step 3: Repay the SOL borrow

const { setupInstructions, preInstructions, instruction, postInstructions } =
  await createVaultSyncTransaction({
    instructions: [
      kaminoAction.repay(KaminoMarket.MAIN, "SOL", new BN(5_000_000_000)),
    ],
    owner: vaultPda,
    connection,
    policyPda,
    vaultPda,
    signer: wallet.publicKey,
    vaultAddress,
  });

const tx = new Transaction().add(
  ...setupInstructions,
  ...preInstructions,
  instruction,
  ...postInstructions,
);
await sendAndConfirmTransaction(connection, tx, [wallet]);

Step 4: Withdraw USDC collateral

const { setupInstructions, preInstructions, instruction, postInstructions } =
  await createVaultSyncTransaction({
    instructions: [
      kaminoAction.withdraw(KaminoMarket.MAIN, "USDC", new BN(1_000_000_000)),
    ],
    owner: vaultPda,
    connection,
    policyPda,
    vaultPda,
    signer: wallet.publicKey,
    vaultAddress,
  });

const tx = new Transaction().add(
  ...setupInstructions,
  ...preInstructions,
  instruction,
  ...postInstructions,
);
await sendAndConfirmTransaction(connection, tx, [wallet]);

Available asset keys

Look up the supported reserve keys for one Kamino market:
import { KAMINO_RESERVES, KaminoMarket } from "@exponent-labs/exponent-sdk";

const assets = Object.keys(KAMINO_RESERVES[KaminoMarket.MAIN]);

SOL handling

The SDK wraps and unwraps SOL automatically when the Kamino action uses SOL.