Skip to content

Kamino API (1.0.0)

The Kamino API provides a comprehensive way to interact with Kamino without reading directly from the blockchain.

The API also provides the ability to fetch data that might not be available from just reading the chain.

Kamino products covered by this documentation:

  • Kamino Earn Vaults (kvaults)
  • Kamino Borrow (klend) (checkout out the SDK examples too)
  • Kamino Liquidity (yvaults) (coming soon, in the meantime, checkout out the SDK examples)

The API is rate-limited for unauthenticated users. If you feel you need to make more requests or run into rate-limit issues, please reach out.

Download OpenAPI description
Languages
Servers
Mock server
https://api-docs.kamino.com/_mock/kamino-api/
https://api.kamino.finance/

📊 Vault Data

Endpoints to retrieve information about the state of Kamino Earn Vaults

Operations

Get all kvaults

Request

Get all Kamino Earn Vaults

curl -i -X GET \
  https://api-docs.kamino.com/_mock/kamino-api/kvaults/vaults

Responses

OK

Bodyapplication/jsonArray [
addressstringrequired
Example: "VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd"
stateobject(The vault state object)required
state.​vaultAdminAuthoritystringrequired
Example: "VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd"
state.​baseVaultAuthoritystringrequired
Example: "VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd"
state.​baseVaultAuthorityBumpnumberrequired

Bump seed for the base vault authority

state.​tokenMintstringrequired
Example: "VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd"
state.​tokenMintDecimalsnumberrequired

Decimals of the token mint

state.​tokenVaultstringrequired
Example: "VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd"
state.​tokenProgramstringrequired
Example: "VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd"
state.​sharesMintstringrequired
Example: "VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd"
state.​sharesMintDecimalsnumberrequired

Decimals of the shares mint

state.​tokenAvailablestringrequired

Amount of tokens available in the vault

state.​sharesIssuedstringrequired

Total shares issued by the vault

state.​availableCrankFundsstringrequired

Available crank funds in the vault

state.​performanceFeeBpsnumberrequired

Performance fee in basis points

state.​managementFeeBpsnumberrequired

Management fee in basis points

state.​lastFeeChargeTimestampnumberrequired

Timestamp of the last fee charge

state.​prevAumstringrequired
Example: "1234.56789"
state.​pendingFeesstringrequired
Example: "1234.56789"
state.​vaultAllocationStrategyArray of objectsrequired

List of vault allocation strategies

state.​vaultAllocationStrategy[].​reservestringrequired
Example: "VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd"
state.​vaultAllocationStrategy[].​ctokenVaultstringrequired
Example: "VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd"
state.​vaultAllocationStrategy[].​targetAllocationWeightnumberrequired

Target allocation weight as a whole number

state.​vaultAllocationStrategy[].​tokenAllocationCapstringrequired

Token allocation cap in lamports

state.​vaultAllocationStrategy[].​ctokenVaultBumpnumberrequired

cToken vault bump seed

state.​vaultAllocationStrategy[].​ctokenAllocationstringrequired

cToken allocation in lamports

state.​vaultAllocationStrategy[].​lastInvestSlotstringrequired

Last invest slot

state.​vaultAllocationStrategy[].​tokenTargetAllocationstringrequired
Example: "1234.56789"
state.​minDepositAmountstringrequired

Minimum deposit amount in lamports

state.​minWithdrawAmountstringrequired

Minimum withdraw amount in lamports

state.​minInvestAmountstringrequired

Minimum invest amount in lamports

state.​minInvestDelaySlotsnumberrequired

Minimum invest delay in slots

state.​crankFundFeePerReservestringrequired

Crank fund fee per reserve

state.​pendingAdminstringrequired
Example: "VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd"
state.​cumulativeEarnedIntereststringrequired
Example: "1234.56789"
state.​cumulativeMgmtFeesstringrequired
Example: "1234.56789"
state.​cumulativePerfFeesstringrequired
Example: "1234.56789"
state.​namestringrequired

Name of the vault

state.​vaultLookupTablestringrequired
Example: "VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd"
state.​vaultFarmstringrequired
Example: "VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd"
state.​creationTimestampnumberrequired

Timestamp of vault creation

state.​allocationAdminstringrequired
Example: "VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd"
programIdstringrequired
Example: "VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd"
]
Response
application/json
[ { "address": "VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd", "state": {}, "programId": "VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd" } ]

Get KVault by address

Request

Get a single Kamino Earn Vault by the KVault account address

Path
pubkeystringrequired
Example: VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd
curl -i -X GET \
  https://api-docs.kamino.com/_mock/kamino-api/kvaults/vaults/VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd

Responses

OK

Bodyapplication/json
addressstringrequired
Example: "VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd"
stateobject(The vault state object)required
state.​vaultAdminAuthoritystringrequired
Example: "VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd"
state.​baseVaultAuthoritystringrequired
Example: "VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd"
state.​baseVaultAuthorityBumpnumberrequired

Bump seed for the base vault authority

state.​tokenMintstringrequired
Example: "VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd"
state.​tokenMintDecimalsnumberrequired

Decimals of the token mint

state.​tokenVaultstringrequired
Example: "VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd"
state.​tokenProgramstringrequired
Example: "VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd"
state.​sharesMintstringrequired
Example: "VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd"
state.​sharesMintDecimalsnumberrequired

Decimals of the shares mint

state.​tokenAvailablestringrequired

Amount of tokens available in the vault

state.​sharesIssuedstringrequired

Total shares issued by the vault

state.​availableCrankFundsstringrequired

Available crank funds in the vault

state.​performanceFeeBpsnumberrequired

Performance fee in basis points

state.​managementFeeBpsnumberrequired

Management fee in basis points

state.​lastFeeChargeTimestampnumberrequired

Timestamp of the last fee charge

state.​prevAumstringrequired
Example: "1234.56789"
state.​pendingFeesstringrequired
Example: "1234.56789"
state.​vaultAllocationStrategyArray of objectsrequired

List of vault allocation strategies

state.​vaultAllocationStrategy[].​reservestringrequired
Example: "VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd"
state.​vaultAllocationStrategy[].​ctokenVaultstringrequired
Example: "VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd"
state.​vaultAllocationStrategy[].​targetAllocationWeightnumberrequired

Target allocation weight as a whole number

state.​vaultAllocationStrategy[].​tokenAllocationCapstringrequired

Token allocation cap in lamports

state.​vaultAllocationStrategy[].​ctokenVaultBumpnumberrequired

cToken vault bump seed

state.​vaultAllocationStrategy[].​ctokenAllocationstringrequired

cToken allocation in lamports

state.​vaultAllocationStrategy[].​lastInvestSlotstringrequired

Last invest slot

state.​vaultAllocationStrategy[].​tokenTargetAllocationstringrequired
Example: "1234.56789"
state.​minDepositAmountstringrequired

Minimum deposit amount in lamports

state.​minWithdrawAmountstringrequired

Minimum withdraw amount in lamports

state.​minInvestAmountstringrequired

Minimum invest amount in lamports

state.​minInvestDelaySlotsnumberrequired

Minimum invest delay in slots

state.​crankFundFeePerReservestringrequired

Crank fund fee per reserve

state.​pendingAdminstringrequired
Example: "VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd"
state.​cumulativeEarnedIntereststringrequired
Example: "1234.56789"
state.​cumulativeMgmtFeesstringrequired
Example: "1234.56789"
state.​cumulativePerfFeesstringrequired
Example: "1234.56789"
state.​namestringrequired

Name of the vault

state.​vaultLookupTablestringrequired
Example: "VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd"
state.​vaultFarmstringrequired
Example: "VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd"
state.​creationTimestampnumberrequired

Timestamp of vault creation

state.​allocationAdminstringrequired
Example: "VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd"
programIdstringrequired
Example: "VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd"
Response
application/json
{ "address": "VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd", "state": { "vaultAdminAuthority": "VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd", "baseVaultAuthority": "VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd", "baseVaultAuthorityBump": 0, "tokenMint": "VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd", "tokenMintDecimals": 0, "tokenVault": "VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd", "tokenProgram": "VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd", "sharesMint": "VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd", "sharesMintDecimals": 0, "tokenAvailable": "string", "sharesIssued": "string", "availableCrankFunds": "string", "performanceFeeBps": 0, "managementFeeBps": 0, "lastFeeChargeTimestamp": 0, "prevAum": "1234.56789", "pendingFees": "1234.56789", "vaultAllocationStrategy": [], "minDepositAmount": "string", "minWithdrawAmount": "string", "minInvestAmount": "string", "minInvestDelaySlots": 0, "crankFundFeePerReserve": "string", "pendingAdmin": "VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd", "cumulativeEarnedInterest": "1234.56789", "cumulativeMgmtFees": "1234.56789", "cumulativePerfFees": "1234.56789", "name": "string", "vaultLookupTable": "VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd", "vaultFarm": "VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd", "creationTimestamp": 0, "allocationAdmin": "VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd" }, "programId": "VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd" }

Get current KVault metrics

Request

Get current Kamino Earn Vault metrics for a given vault

Path
pubkeystringrequired
Example: VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd
curl -i -X GET \
  https://api-docs.kamino.com/_mock/kamino-api/kvaults/vaults/VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd/metrics

Responses

OK

Bodyapplication/json
apy7dstringrequired
Example: "0.2"
apy24hstringrequired
Example: "0.2"
apy30dstringrequired
Example: "0.2"
apy90dstringrequired
Example: "0.2"
apy180dstringrequired
Example: "0.2"
apy365dstringrequired
Example: "0.2"
tokenPricestringrequired
Example: "1234.56789"
solPricestringrequired
Example: "1234.56789"
tokensAvailablestringrequired
Example: "1234.56789"
tokensAvailableUsdstringrequired
Example: "1234.56789"
tokensInvestedstringrequired
Example: "1234.56789"
tokensInvestedUsdstringrequired
Example: "1234.56789"
sharePricestringrequired
Example: "1234.56789"
tokensPerSharestringrequired
Example: "1234.56789"
apystringrequired
Example: "0.2"
apyTheoreticalstringrequired
Example: "0.2"
apyActualstringrequired
Example: "0.2"
apyFarmRewardsstringrequired
Example: "0.2"
apyIncentivesstringrequired
Example: "0.2"
apyReservesIncentivesstringrequired
Example: "0.2"
numberOfHoldersnumberrequired

Number of holders of the kvault

sharesIssuedstringrequired
Example: "1234.56789"
cumulativeInterestEarnedstringrequired
Example: "1234.56789"
cumulativeInterestEarnedUsdstringrequired
Example: "1234.56789"
cumulativeInterestEarnedSolstringrequired
Example: "1234.56789"
interestEarnedPerSecondstringrequired
Example: "1234.56789"
interestEarnedPerSecondUsdstringrequired
Example: "1234.56789"
interestEarnedPerSecondSolstringrequired
Example: "1234.56789"
cumulativePerformanceFeesstringrequired
Example: "1234.56789"
cumulativePerformanceFeesUsdstringrequired
Example: "1234.56789"
cumulativePerformanceFeesSolstringrequired
Example: "1234.56789"
cumulativeManagementFeesstringrequired
Example: "1234.56789"
cumulativeManagementFeesUsdstringrequired
Example: "1234.56789"
cumulativeManagementFeesSolstringrequired
Example: "1234.56789"
Response
application/json
{ "apy7d": "0.2", "apy24h": "0.2", "apy30d": "0.2", "apy90d": "0.2", "apy180d": "0.2", "apy365d": "0.2", "tokenPrice": "1234.56789", "solPrice": "1234.56789", "tokensAvailable": "1234.56789", "tokensAvailableUsd": "1234.56789", "tokensInvested": "1234.56789", "tokensInvestedUsd": "1234.56789", "sharePrice": "1234.56789", "tokensPerShare": "1234.56789", "apy": "0.2", "apyTheoretical": "0.2", "apyActual": "0.2", "apyFarmRewards": "0.2", "apyIncentives": "0.2", "apyReservesIncentives": "0.2", "numberOfHolders": 0, "sharesIssued": "1234.56789", "cumulativeInterestEarned": "1234.56789", "cumulativeInterestEarnedUsd": "1234.56789", "cumulativeInterestEarnedSol": "1234.56789", "interestEarnedPerSecond": "1234.56789", "interestEarnedPerSecondUsd": "1234.56789", "interestEarnedPerSecondSol": "1234.56789", "cumulativePerformanceFees": "1234.56789", "cumulativePerformanceFeesUsd": "1234.56789", "cumulativePerformanceFeesSol": "1234.56789", "cumulativeManagementFees": "1234.56789", "cumulativeManagementFeesUsd": "1234.56789", "cumulativeManagementFeesSol": "1234.56789" }

🕵️‍♂️ User Data

Endpoints to retrieve information about the state of Kamino Earn Vault users

Operations

🌍 Global Data

Endpoints to retrieve information about the global state of Kamino Earn Vaults

Operations

🪙 Share Mint Data

Endpoints to retrieve information about the global state of Kamino Earn Vault share mints

Operations

🌱 Deposit

Get unsigned Solana transactions to deposit into Kamino Earn Vaults

Deposit Transaction
import {
  address,
  Address,
  addSignersToTransactionMessage,
  CompiledTransactionMessage,
  createSolanaRpc,
  createSolanaRpcSubscriptions,
  decompileTransactionMessageFetchingLookupTables, generateKeyPairSigner,
  getCompiledTransactionMessageDecoder,
  getSignatureFromTransaction,
  getTransactionDecoder,
  pipe,
  sendAndConfirmTransactionFactory,
  setTransactionMessageFeePayerSigner,
  setTransactionMessageLifetimeUsingBlockhash,
  Signature,
  signTransactionMessageWithSigners,
  TransactionMessageBytes,
  TransactionSigner
} from '@solana/kit';

async function fetchTx(wallet: Address, kvault: Address, amount: number): Promise<TransactionMessageBytes> {
  const resp = await fetch(
    `https://api.kamino.finance/ktx/kvault/deposit`,
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        wallet: `${wallet}`,
        kvault: `${kvault}`,
        amount: amount.toString()
      })
    }
  );

  const data = (await resp.json()) as { transaction: string };

  const txBuffer = Buffer.from(data.transaction, 'base64');
  return getTransactionDecoder().decode(txBuffer).messageBytes;
}

async function signAndSendTx(wallet: TransactionSigner, txBytes: TransactionMessageBytes): Promise<Signature> {
  const rpc = createSolanaRpc('https://api.mainnet-beta.solana.com');
  const rpcSubscriptions = createSolanaRpcSubscriptions('wss://api.mainnet-beta.solana.com');

  const dMessage: CompiledTransactionMessage = getCompiledTransactionMessageDecoder().decode(txBytes);

  const bh = await rpc.getLatestBlockhash({ commitment: 'finalized' }).send();

  const tx = await pipe(
    await decompileTransactionMessageFetchingLookupTables(dMessage, rpc),
    (tx) => setTransactionMessageLifetimeUsingBlockhash(bh.value, tx),
    (tx) => setTransactionMessageFeePayerSigner(wallet, tx),
    (tx) => addSignersToTransactionMessage([wallet], tx),
    (tx) => signTransactionMessageWithSigners(tx)
  );

  const encodedTxMessage = Buffer.from(tx.messageBytes).toString('base64');
  console.log(`🔍 Simulation URL: https://explorer.solana.com/tx/inspector?message=${encodeURIComponent(encodedTxMessage)}&cluster=mainnet-beta&signatures=${encodeURIComponent(`[${wallet}]`)}`);

  const sig = getSignatureFromTransaction(tx);

  console.log(`Sending tx with signature: https://solscan.io/tx/${sig}`);
  await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })(tx, {
    commitment: 'confirmed',
    preflightCommitment: 'confirmed',
    maxRetries: 0n,
    skipPreflight: true,
    minContextSlot: bh.context.slot,
  });

  console.log(`✅ Tx sent successfully`)

  return sig;
}

async function main() {
  const wallet = await generateKeyPairSigner();
  // Neutral Trade USDC Max Yield Vault
  const vault = address('67dqmR76uAbjX6e81A1ganKv3ou31WUMEdeWJkwVfeXy');

  // 100 USDC
  const depositAmount = 100.0;

  console.log(`Using temporary wallet: ${wallet.address} to deposit into vault: ${vault}`);

  const tx = await fetchTx(wallet.address, vault, depositAmount);
  await signAndSendTx(wallet, tx);
}

main().then(() => `⚡️Deposit transaction complete`).catch((err) => console.error(err));
Operations

🏃‍♂️ Withdraw

Get unsigned Solana transactions to withdraw from Kamino Earn Vaults

Withdraw Transaction
import {
  address,
  Address,
  addSignersToTransactionMessage,
  CompiledTransactionMessage,
  createSolanaRpc,
  createSolanaRpcSubscriptions,
  decompileTransactionMessageFetchingLookupTables, generateKeyPairSigner,
  getCompiledTransactionMessageDecoder,
  getSignatureFromTransaction,
  getTransactionDecoder,
  pipe,
  sendAndConfirmTransactionFactory,
  setTransactionMessageFeePayerSigner,
  setTransactionMessageLifetimeUsingBlockhash,
  Signature,
  signTransactionMessageWithSigners,
  TransactionMessageBytes,
  TransactionSigner
} from '@solana/kit';

async function fetchTx(wallet: Address, kvault: Address, amount: number): Promise<TransactionMessageBytes> {
  const resp = await fetch(
    `https://api.kamino.finance/ktx/kvault/withdraw`,
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        wallet: `${wallet}`,
        kvault: `${kvault}`,
        amount: amount.toString()
      })
    }
  );

  const data = (await resp.json()) as { transaction: string };

  const txBuffer = Buffer.from(data.transaction, 'base64');
  return getTransactionDecoder().decode(txBuffer).messageBytes;
}

async function signAndSendTx(wallet: TransactionSigner, txBytes: TransactionMessageBytes): Promise<Signature> {
  const rpc = createSolanaRpc('https://api.mainnet-beta.solana.com');
  const rpcSubscriptions = createSolanaRpcSubscriptions('wss://api.mainnet-beta.solana.com');

  const dMessage: CompiledTransactionMessage = getCompiledTransactionMessageDecoder().decode(txBytes);

  const bh = await rpc.getLatestBlockhash({ commitment: 'finalized' }).send();

  const tx = await pipe(
    await decompileTransactionMessageFetchingLookupTables(dMessage, rpc),
    (tx) => setTransactionMessageLifetimeUsingBlockhash(bh.value, tx),
    (tx) => setTransactionMessageFeePayerSigner(wallet, tx),
    (tx) => addSignersToTransactionMessage([wallet], tx),
    (tx) => signTransactionMessageWithSigners(tx)
  );

  const encodedTxMessage = Buffer.from(tx.messageBytes).toString('base64');
  console.log(`🔍 Simulation URL: https://explorer.solana.com/tx/inspector?message=${encodeURIComponent(encodedTxMessage)}&cluster=mainnet-beta&signatures=${encodeURIComponent(`[${wallet}]`)}`);

  const sig = getSignatureFromTransaction(tx);

  console.log(`Sending tx with signature: https://solscan.io/tx/${sig}`);
  await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })(tx, {
    commitment: 'confirmed',
    preflightCommitment: 'confirmed',
    maxRetries: 0n,
    skipPreflight: true,
    minContextSlot: bh.context.slot,
  });

  console.log(`✅ Tx sent successfully`)

  return sig;
}

async function main() {
  const wallet = await generateKeyPairSigner();
  // Neutral Trade USDC Max Yield Vault
  const vault = address('67dqmR76uAbjX6e81A1ganKv3ou31WUMEdeWJkwVfeXy');

  // 50 USDC
  const withdrawAmount = 50.0;

  console.log(`Using temporary wallet: ${wallet.address} to withdraw from vault: ${vault}`);

  const tx = await fetchTx(wallet.address, vault, withdrawAmount);
  await signAndSendTx(wallet, tx);
}

main().then(() => `⚡️Withdrawal transaction complete`).catch((err) => console.error(err));
Operations

🏦 Markets

Operations

🍬 Rewards

Get up-to-date and historical rewards data.

Operations

👥 Users and Loans

Operations

📝 Deposit

Get unsigned Solana transactions to deposit liquidity into a Kamino Lend market reserve, which can then be used as collateral to borrow

Deposit Transaction
import {
  address,
  Address,
  addSignersToTransactionMessage,
  CompiledTransactionMessage,
  createSolanaRpc,
  createSolanaRpcSubscriptions,
  decompileTransactionMessageFetchingLookupTables, generateKeyPairSigner,
  getCompiledTransactionMessageDecoder,
  getSignatureFromTransaction,
  getTransactionDecoder,
  pipe,
  sendAndConfirmTransactionFactory,
  setTransactionMessageFeePayerSigner,
  setTransactionMessageLifetimeUsingBlockhash,
  Signature,
  signTransactionMessageWithSigners,
  TransactionMessageBytes,
  TransactionSigner
} from '@solana/kit';

async function fetchTx(wallet: Address, market: Address, reserve: Address, amount: number): Promise<TransactionMessageBytes> {
  const resp = await fetch(
    `https://api.kamino.finance/ktx/klend/deposit`,
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        wallet: `${wallet}`,
        market: `${market}`,
        reserve: `${reserve}`,
        amount: amount.toString()
      })
    }
  );

  const data = (await resp.json()) as { transaction: string };

  const txBuffer = Buffer.from(data.transaction, 'base64');
  return getTransactionDecoder().decode(txBuffer).messageBytes;
}

async function signAndSendTx(wallet: TransactionSigner, txBytes: TransactionMessageBytes): Promise<Signature> {
  const rpc = createSolanaRpc('https://api.mainnet-beta.solana.com');
  const rpcSubscriptions = createSolanaRpcSubscriptions('wss://api.mainnet-beta.solana.com');

  const dMessage: CompiledTransactionMessage = getCompiledTransactionMessageDecoder().decode(txBytes);

  const bh = await rpc.getLatestBlockhash({ commitment: 'finalized' }).send();

  const tx = await pipe(
    await decompileTransactionMessageFetchingLookupTables(dMessage, rpc),
    (tx) => setTransactionMessageLifetimeUsingBlockhash(bh.value, tx),
    (tx) => setTransactionMessageFeePayerSigner(wallet, tx),
    (tx) => addSignersToTransactionMessage([wallet], tx),
    (tx) => signTransactionMessageWithSigners(tx)
  );

  const encodedTxMessage = Buffer.from(tx.messageBytes).toString('base64');
  console.log(`🔍 Simulation URL: https://explorer.solana.com/tx/inspector?message=${encodeURIComponent(encodedTxMessage)}&cluster=mainnet-beta&signatures=${encodeURIComponent(`[${wallet}]`)}`);

  const sig = getSignatureFromTransaction(tx);

  console.log(`Sending tx with signature: https://solscan.io/tx/${sig}`);
  await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })(tx, {
    commitment: 'confirmed',
    preflightCommitment: 'confirmed',
    maxRetries: 0n,
    skipPreflight: true,
    minContextSlot: bh.context.slot,
  });

  console.log(`✅ Tx sent successfully`)

  return sig;
}

async function main() {
  const wallet = await generateKeyPairSigner();
  // Main market
  const market = address('7u3HeHxYDLhnCoErrtycNokbQYbWGzLs6JSDqGAv5PfF');
  // USDC reserve in main market
  const reserve = address('D6q6wuQSrifJKZYpR1M8R4YawnLDtDsMmWM1NbBmgJ59');

  // 50 USDC
  const depositAmount = 50.0;

  console.log(`Using temporary wallet: ${wallet.address} to deposit into market: ${market}, reserve: ${reserve}`);

  const tx = await fetchTx(wallet.address, market, reserve, depositAmount);
  await signAndSendTx(wallet, tx);
}

main().then(() => `⚡️Deposit transaction complete`).catch((err) => console.error(err));
Operations

💳 Borrow

Get unsigned Solana transactions to borrow liquidity from a given Kamino Lend market reserve

Borrow Transaction
import {
  address,
  Address,
  addSignersToTransactionMessage,
  CompiledTransactionMessage,
  createSolanaRpc,
  createSolanaRpcSubscriptions,
  decompileTransactionMessageFetchingLookupTables, generateKeyPairSigner,
  getCompiledTransactionMessageDecoder,
  getSignatureFromTransaction,
  getTransactionDecoder,
  pipe,
  sendAndConfirmTransactionFactory,
  setTransactionMessageFeePayerSigner,
  setTransactionMessageLifetimeUsingBlockhash,
  Signature,
  signTransactionMessageWithSigners,
  TransactionMessageBytes,
  TransactionSigner
} from '@solana/kit';

async function fetchTx(wallet: Address, market: Address, reserve: Address, amount: number): Promise<TransactionMessageBytes> {
  const resp = await fetch(
    `https://api.kamino.finance/ktx/klend/borrow`,
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        wallet: `${wallet}`,
        market: `${market}`,
        reserve: `${reserve}`,
        amount: amount.toString()
      })
    }
  );

  const data = (await resp.json()) as { transaction: string };

  const txBuffer = Buffer.from(data.transaction, 'base64');
  return getTransactionDecoder().decode(txBuffer).messageBytes;
}

async function signAndSendTx(wallet: TransactionSigner, txBytes: TransactionMessageBytes): Promise<Signature> {
  const rpc = createSolanaRpc('https://api.mainnet-beta.solana.com');
  const rpcSubscriptions = createSolanaRpcSubscriptions('wss://api.mainnet-beta.solana.com');

  const dMessage: CompiledTransactionMessage = getCompiledTransactionMessageDecoder().decode(txBytes);

  const bh = await rpc.getLatestBlockhash({ commitment: 'finalized' }).send();

  const tx = await pipe(
    await decompileTransactionMessageFetchingLookupTables(dMessage, rpc),
    (tx) => setTransactionMessageLifetimeUsingBlockhash(bh.value, tx),
    (tx) => setTransactionMessageFeePayerSigner(wallet, tx),
    (tx) => addSignersToTransactionMessage([wallet], tx),
    (tx) => signTransactionMessageWithSigners(tx)
  );

  const encodedTxMessage = Buffer.from(tx.messageBytes).toString('base64');
  console.log(`🔍 Simulation URL: https://explorer.solana.com/tx/inspector?message=${encodeURIComponent(encodedTxMessage)}&cluster=mainnet-beta&signatures=${encodeURIComponent(`[${wallet}]`)}`);

  const sig = getSignatureFromTransaction(tx);

  console.log(`Sending tx with signature: https://solscan.io/tx/${sig}`);
  await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })(tx, {
    commitment: 'confirmed',
    preflightCommitment: 'confirmed',
    maxRetries: 0n,
    skipPreflight: true,
    minContextSlot: bh.context.slot,
  });

  console.log(`✅ Tx sent successfully`)

  return sig;
}

async function main() {
  const wallet = await generateKeyPairSigner();
  // Main market
  const market = address('7u3HeHxYDLhnCoErrtycNokbQYbWGzLs6JSDqGAv5PfF');
  // USDC reserve in main market
  const reserve = address('D6q6wuQSrifJKZYpR1M8R4YawnLDtDsMmWM1NbBmgJ59');

  // 50 USDC
  const borrowAmount = 50.0;

  console.log(`Using temporary wallet: ${wallet.address} to borrow from market: ${market}, reserve: ${reserve}`);

  const tx = await fetchTx(wallet.address, market, reserve, borrowAmount);
  await signAndSendTx(wallet, tx);
}

main().then(() => `⚡️Borrow transaction complete`).catch((err) => console.error(err));
Operations

📝 Repay

Get unsigned Solana transactions to repay debt for a given Kamino Lend user position

Repay Transaction
import {
  address,
  Address,
  addSignersToTransactionMessage,
  CompiledTransactionMessage,
  createSolanaRpc,
  createSolanaRpcSubscriptions,
  decompileTransactionMessageFetchingLookupTables, generateKeyPairSigner,
  getCompiledTransactionMessageDecoder,
  getSignatureFromTransaction,
  getTransactionDecoder,
  pipe,
  sendAndConfirmTransactionFactory,
  setTransactionMessageFeePayerSigner,
  setTransactionMessageLifetimeUsingBlockhash,
  Signature,
  signTransactionMessageWithSigners,
  TransactionMessageBytes,
  TransactionSigner
} from '@solana/kit';

async function fetchTx(wallet: Address, market: Address, reserve: Address, amount: number): Promise<TransactionMessageBytes> {
  const resp = await fetch(
    `https://api.kamino.finance/ktx/klend/repay`,
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        wallet: `${wallet}`,
        market: `${market}`,
        reserve: `${reserve}`,
        amount: amount.toString()
      })
    }
  );

  const data = (await resp.json()) as { transaction: string };

  const txBuffer = Buffer.from(data.transaction, 'base64');
  return getTransactionDecoder().decode(txBuffer).messageBytes;
}

async function signAndSendTx(wallet: TransactionSigner, txBytes: TransactionMessageBytes): Promise<Signature> {
  const rpc = createSolanaRpc('https://api.mainnet-beta.solana.com');
  const rpcSubscriptions = createSolanaRpcSubscriptions('wss://api.mainnet-beta.solana.com');

  const dMessage: CompiledTransactionMessage = getCompiledTransactionMessageDecoder().decode(txBytes);

  const bh = await rpc.getLatestBlockhash({ commitment: 'finalized' }).send();

  const tx = await pipe(
    await decompileTransactionMessageFetchingLookupTables(dMessage, rpc),
    (tx) => setTransactionMessageLifetimeUsingBlockhash(bh.value, tx),
    (tx) => setTransactionMessageFeePayerSigner(wallet, tx),
    (tx) => addSignersToTransactionMessage([wallet], tx),
    (tx) => signTransactionMessageWithSigners(tx)
  );

  const encodedTxMessage = Buffer.from(tx.messageBytes).toString('base64');
  console.log(`🔍 Simulation URL: https://explorer.solana.com/tx/inspector?message=${encodeURIComponent(encodedTxMessage)}&cluster=mainnet-beta&signatures=${encodeURIComponent(`[${wallet}]`)}`);

  const sig = getSignatureFromTransaction(tx);

  console.log(`Sending tx with signature: https://solscan.io/tx/${sig}`);
  await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })(tx, {
    commitment: 'confirmed',
    preflightCommitment: 'confirmed',
    maxRetries: 0n,
    skipPreflight: true,
    minContextSlot: bh.context.slot,
  });

  console.log(`✅ Tx sent successfully`)

  return sig;
}

async function main() {
  const wallet = await generateKeyPairSigner();
  // Main market
  const market = address('7u3HeHxYDLhnCoErrtycNokbQYbWGzLs6JSDqGAv5PfF');
  // USDC reserve in main market
  const reserve = address('D6q6wuQSrifJKZYpR1M8R4YawnLDtDsMmWM1NbBmgJ59');

  // 50 USDC
  const repayAmount = 50.0;

  console.log(`Using temporary wallet: ${wallet.address} to repay debt from market: ${market}, reserve: ${reserve}`);

  const tx = await fetchTx(wallet.address, market, reserve, repayAmount);
  await signAndSendTx(wallet, tx);
}

main().then(() => `⚡️Repay transaction complete`).catch((err) => console.error(err));
Operations

🐝 Withdraw

Get unsigned Solana transactions to withdraw liquidity from a given Kamino Lend market reserve

Withdraw Transaction
import {
  address,
  Address,
  addSignersToTransactionMessage,
  CompiledTransactionMessage,
  createSolanaRpc,
  createSolanaRpcSubscriptions,
  decompileTransactionMessageFetchingLookupTables, generateKeyPairSigner,
  getCompiledTransactionMessageDecoder,
  getSignatureFromTransaction,
  getTransactionDecoder,
  pipe,
  sendAndConfirmTransactionFactory,
  setTransactionMessageFeePayerSigner,
  setTransactionMessageLifetimeUsingBlockhash,
  Signature,
  signTransactionMessageWithSigners,
  TransactionMessageBytes,
  TransactionSigner
} from '@solana/kit';

async function fetchTx(wallet: Address, market: Address, reserve: Address, amount: number): Promise<TransactionMessageBytes> {
  const resp = await fetch(
    `https://api.kamino.finance/ktx/klend/withdraw`,
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        wallet: `${wallet}`,
        market: `${market}`,
        reserve: `${reserve}`,
        amount: amount.toString()
      })
    }
  );

  const data = (await resp.json()) as { transaction: string };

  const txBuffer = Buffer.from(data.transaction, 'base64');
  return getTransactionDecoder().decode(txBuffer).messageBytes;
}

async function signAndSendTx(wallet: TransactionSigner, txBytes: TransactionMessageBytes): Promise<Signature> {
  const rpc = createSolanaRpc('https://api.mainnet-beta.solana.com');
  const rpcSubscriptions = createSolanaRpcSubscriptions('wss://api.mainnet-beta.solana.com');

  const dMessage: CompiledTransactionMessage = getCompiledTransactionMessageDecoder().decode(txBytes);

  const bh = await rpc.getLatestBlockhash({ commitment: 'finalized' }).send();

  const tx = await pipe(
    await decompileTransactionMessageFetchingLookupTables(dMessage, rpc),
    (tx) => setTransactionMessageLifetimeUsingBlockhash(bh.value, tx),
    (tx) => setTransactionMessageFeePayerSigner(wallet, tx),
    (tx) => addSignersToTransactionMessage([wallet], tx),
    (tx) => signTransactionMessageWithSigners(tx)
  );

  const encodedTxMessage = Buffer.from(tx.messageBytes).toString('base64');
  console.log(`🔍 Simulation URL: https://explorer.solana.com/tx/inspector?message=${encodeURIComponent(encodedTxMessage)}&cluster=mainnet-beta&signatures=${encodeURIComponent(`[${wallet}]`)}`);

  const sig = getSignatureFromTransaction(tx);

  console.log(`Sending tx with signature: https://solscan.io/tx/${sig}`);
  await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })(tx, {
    commitment: 'confirmed',
    preflightCommitment: 'confirmed',
    maxRetries: 0n,
    skipPreflight: true,
    minContextSlot: bh.context.slot,
  });

  console.log(`✅ Tx sent successfully`)

  return sig;
}

async function main() {
  const wallet = await generateKeyPairSigner();
  // Main market
  const market = address('7u3HeHxYDLhnCoErrtycNokbQYbWGzLs6JSDqGAv5PfF');
  // USDC reserve in main market
  const reserve = address('D6q6wuQSrifJKZYpR1M8R4YawnLDtDsMmWM1NbBmgJ59');

  // 50 USDC
  const withdrawAmount = 50.0;

  console.log(`Using temporary wallet: ${wallet.address} to withdraw from market: ${market}, reserve: ${reserve}`);

  const tx = await fetchTx(wallet.address, market, reserve, withdrawAmount);
  await signAndSendTx(wallet, tx);
}

main().then(() => `⚡️Withdraw transaction complete`).catch((err) => console.error(err));
Operations