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]);
| Part | What it contains |
|---|
setupInstructions | Setup instructions that must run before refreshes or the sync step |
preInstructions | Permissionless refresh instructions that must run before the sync step |
instruction | The Squads sync transaction instruction that wraps the vault-signed Kamino action |
postInstructions | Permissionless 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.
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
| Parameter | Type | Description |
|---|
market | KaminoMarket | Kamino lending market such as KaminoMarket.MAIN |
asset | string | Reserve key from KAMINO_RESERVES[market] |
amount | BN | Amount 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
| Parameter | Type | Description |
|---|
market | KaminoMarket | Kamino lending market |
asset | string | Reserve key from KAMINO_RESERVES[market] |
amount | BN | Amount 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
| Parameter | Type | Description |
|---|
market | KaminoMarket | Kamino lending market |
asset | string | Reserve key to borrow from |
amount | BN | Amount 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
| Parameter | Type | Description |
|---|
market | KaminoMarket | Kamino lending market |
asset | string | Reserve key to repay |
amount | BN | Amount 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.