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.
Earn Withdraw with API
Import Dependencies
Import the required packages for Solana RPC communication, transaction handling, and Kamino SDK utilities.import {
createSolanaRpc,
createSolanaRpcSubscriptions,
pipe,
getTransactionDecoder,
getCompiledTransactionMessageDecoder,
decompileTransactionMessageFetchingLookupTables,
setTransactionMessageFeePayerSigner,
setTransactionMessageLifetimeUsingBlockhash,
addSignersToTransactionMessage,
signTransactionMessageWithSigners,
sendAndConfirmTransactionFactory,
getSignatureFromTransaction,
} from '@solana/kit';
import { parseKeypairFile } from '@kamino-finance/klend-sdk/dist/utils/signer.js';
Set up the configuration and initialize RPC connections.const KEYPAIR_FILE = '/path/to/your/keypair.json';
const API_BASE_URL = 'https://api.kamino.finance';
const signer = await parseKeypairFile(KEYPAIR_FILE);
const rpc = createSolanaRpc('https://api.mainnet-beta.solana.com');
const rpcSubscriptions = createSolanaRpcSubscriptions('wss://api.mainnet-beta.solana.com');
Call Kamino API
Make a POST request to the Kamino API to build the withdrawal transaction.const response = await fetch(`${API_BASE_URL}/ktx/kvault/withdraw`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
wallet: signer.address,
kvault: 'HDsayqAsDWy3QvANGqh2yNraqcD8Fnjgh73Mhb3WRS5E',
amount: '1.0',
}),
});
if (!response.ok) {
const error = await response.json();
throw new Error(`API error: ${error.message}`);
}
const { transaction: encodedTransaction } = await response.json();
The API returns a pre-built transaction encoded in base64 format. This transaction includes Address Lookup Tables (ALTs) for efficiency.
Decode Transaction
Decode the base64-encoded transaction and extract the message bytes.const txBuffer = Buffer.from(encodedTransaction, 'base64');
const txMessageBytes = getTransactionDecoder().decode(txBuffer).messageBytes;
const compiledMessage = getCompiledTransactionMessageDecoder().decode(txMessageBytes);
Resolve Address Lookup Tables
Fetch and resolve the Address Lookup Tables from the blockchain.const { value: latestBlockhash } = await rpc.getLatestBlockhash({ commitment: 'finalized' }).send();
const signedTransaction = await pipe(
await decompileTransactionMessageFetchingLookupTables(compiledMessage, rpc),
(tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx),
(tx) => setTransactionMessageFeePayerSigner(signer, tx),
(tx) => addSignersToTransactionMessage([signer], tx),
(tx) => signTransactionMessageWithSigners(tx)
);
decompileTransactionMessageFetchingLookupTables fetches the lookup table data from the blockchain and resolves all address references. This is required for transactions that use ALTs.
A fresh blockhash is fetched and set to ensure the transaction remains valid.
Send and Confirm Transaction
Submit the signed transaction to the Solana network.const signature = getSignatureFromTransaction(signedTransaction);
console.log(`Sending transaction with signature: ${signature}`);
await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })(signedTransaction, {
commitment: 'confirmed',
skipPreflight: true,
});
console.log('Withdrawal successful! Signature:', signature);
Your withdrawal is complete! The API built the transaction, you signed it locally (keeping your keys secure), and it was successfully submitted to the network.