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

🕵️‍♂️ 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

Get KLend rewards

Request

Fetches all active KLend reward metrics for a specific points source

Query
sourcestring

Points source identifier

Example: source=Season1
curl -i -X GET \
  'https://api-docs.kamino.com/_mock/kamino-api/klend/rewards?source=Season1'

Responses

OK

Bodyapplication/jsonArray [
depositReservestring or nullrequired
Example: "VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd"
borrowReservestring or nullrequired
Example: "VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd"
marketstringrequired
Example: "VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd"
rewardTokenstringrequired
Example: "VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd"
lastCalculatedstring(date-time)required

Timestamp of the last calculation

apystringrequired
Example: "0.2"
tokensPerSecondstringrequired
Example: "1234.56789"
activePositionsUsdstringrequired
Example: "1234.56789"
]
Response
application/json
[ { "depositReserve": "VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd", "borrowReserve": "VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd", "market": "VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd", "rewardToken": "VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd", "lastCalculated": "2019-08-24T14:15:22Z", "apy": "0.2", "tokensPerSecond": "1234.56789", "activePositionsUsd": "1234.56789" } ]

Get user KLend rewards

Request

Fetches KLend reward data for a specific user and points source

Path
pubkeystringrequired
Example: VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd
Query
sourcestring

Points source identifier

Example: source=Season1
curl -i -X GET \
  'https://api-docs.kamino.com/_mock/kamino-api/klend/users/VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd/rewards?source=Season1'

Responses

OK

Bodyapplication/json
avgBaseApystringrequired
Example: "0.2"
avgBoostedApystringrequired
Example: "0.2"
avgMaxApystringrequired
Example: "0.2"
rewardsArray of objects(KlendUserRewardMetric)required

List of klend user reward metrics

rewards[].​depositReservestring or nullrequired
Example: "VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd"
rewards[].​borrowReservestring or nullrequired
Example: "VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd"
rewards[].​marketstringrequired
Example: "VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd"
rewards[].​rewardMintstringrequired
Example: "VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd"
rewards[].​lastCalculatedstring(date)required

Timestamp of the last calculation

rewards[].​tokensEarnedstringrequired
Example: "1234.56789"
rewards[].​tokensPerSecondstringrequired
Example: "1234.56789"
rewards[].​stakingBooststringrequired
Example: "1234.56789"
rewards[].​effectiveStakingBooststringrequired
Example: "1234.56789"
rewards[].​baseApystringrequired
Example: "0.2"
rewards[].​boostedApystringrequired
Example: "0.2"
rewards[].​maxApystringrequired
Example: "0.2"
rewards[].​usdAmountstringrequired
Example: "1234.56789"
rewards[].​usdAmountBoostedstringrequired
Example: "1234.56789"
Response
application/json
{ "avgBaseApy": "0.2", "avgBoostedApy": "0.2", "avgMaxApy": "0.2", "rewards": [ {} ] }

Get KLend reward history

Request

Fetches historical KLend reward metrics for a specific deposit and borrow reserve pair

Path
depositReservePubkeystringrequired
Example: VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd
borrowReservePubkeystringrequired
Example: VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd
Query
startstring or number
Default "1970-01-01T00:00:00.000Z"
Any of:

Date input (ISO 8601 string or epoch in ms)

string
Default "1970-01-01T00:00:00.000Z"
endstring or number
Default "2025-11-06T12:14:45.561Z"
Any of:

Date input (ISO 8601 string or epoch in ms)

string
Default "2025-11-06T12:14:45.561Z"
frequencystring

Frequency of historical data aggregation

Enum"hour""day"
Example: frequency=hour
curl -i -X GET \
  'https://api-docs.kamino.com/_mock/kamino-api/klend/VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd/VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd/rewards/history?start=2024-01-01T00%3A00%3A00.000Z&end=2024-01-01T00%3A00%3A00.000Z&frequency=hour'

Responses

OK

Bodyapplication/jsonArray [
timestampstring(date-time)required

Timestamp of the data point

depositReservestring or nullrequired
Example: "VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd"
borrowReservestring or nullrequired
Example: "VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd"
rewardTokenstringrequired
Example: "VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd"
rewardApystringrequired
Example: "0.2"
]
Response
application/json
[ { "timestamp": "2019-08-24T14:15:22Z", "depositReserve": "VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd", "borrowReserve": "VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd", "rewardToken": "VEG1EMtttdHunMbSza8uoms1R18VXmYSph2bBpHcSJd", "rewardApy": "0.2" } ]

👥 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