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.
Withdraw
The second half of unwinding a position. After you unstake and the farm’s withdrawal cooldown elapses, the stake sits as pending withdrawal. This moves those tokens out of the farm vault back to your token account.
This flow requires a non-delegated farm, since the instruction needs the stake token mint. No Scope prices or refresh are needed here, because it moves already-unstaked tokens and does not touch reward accounting. The instruction only succeeds on-chain once the withdrawal cooldown has elapsed; if there is nothing past cooldown, it fails.
Import Dependencies Import the packages for Solana RPC communication, Kit transaction building, the keypair loader, and the Farms SDK. import {
createSolanaRpc ,
createSolanaRpcSubscriptions ,
address ,
pipe ,
createTransactionMessage ,
setTransactionMessageFeePayerSigner ,
setTransactionMessageLifetimeUsingBlockhash ,
appendTransactionMessageInstructions ,
signTransactionMessageWithSigners ,
getSignatureFromTransaction ,
assertIsTransactionWithinSizeLimit ,
sendAndConfirmTransactionFactory ,
} from "@solana/kit" ;
import { parseKeypairFile } from "@kamino-finance/klend-sdk/dist/utils/signer" ;
import { Farms } from "@kamino-finance/farms-sdk" ;
Set the keypair path, RPC endpoints, target farm, and stake token mint. Load the signer and initialize the farms client. const KEYPAIR_FILE = "/path/to/your/keypair.json" ;
const RPC_ENDPOINT = "https://api.mainnet-beta.solana.com" ;
const WS_ENDPOINT = "wss://api.mainnet-beta.solana.com" ;
const FARM = address ( "DXGwU8Ah7v6TBcc9ZjVmFxiLCMPgrxnsj4ZF7F8sWFxi" ); // non-delegated farm
const STAKE_MINT = address ( "AYUjc3a3QQUiLE6jP7V29UMeUZGADdtiVxhSjoLcqYwr" ); // the farm's stake token
const signer = await parseKeypairFile ( KEYPAIR_FILE );
const rpc = createSolanaRpc ( RPC_ENDPOINT );
const rpcSubscriptions = createSolanaRpcSubscriptions ( WS_ENDPOINT );
const farms = new Farms ( rpc );
Build Withdraw Instruction Resolve the user-state key, then build the withdraw-unstaked instruction. The third argument is the farm address. const { key : userState } = await farms . getUserStateKeyForUndelegatedFarm (
signer . address ,
FARM ,
);
const instructions = [
await farms . withdrawUnstakedDepositIx ( signer , userState , FARM , STAKE_MINT ),
];
Build, Sign, and Send Transaction Compose the v0 transaction, sign, verify it fits the size limit, then send and confirm. const { value : blockhash } = await rpc
. getLatestBlockhash ({ commitment: "finalized" })
. send ();
const transactionMessage = pipe (
createTransactionMessage ({ version: 0 }),
( m ) => setTransactionMessageFeePayerSigner ( signer , m ),
( m ) => setTransactionMessageLifetimeUsingBlockhash ( blockhash , m ),
( m ) => appendTransactionMessageInstructions ( instructions , m ),
);
const signedTransaction = await signTransactionMessageWithSigners ( transactionMessage );
assertIsTransactionWithinSizeLimit ( signedTransaction );
const signature = getSignatureFromTransaction ( signedTransaction );
await sendAndConfirmTransactionFactory ({ rpc , rpcSubscriptions })( signedTransaction , {
commitment: "confirmed" ,
skipPreflight: true ,
});
console . log ( "Withdraw-unstaked successful! Signature:" , signature );
The withdrawal is complete. Your unstaked tokens have been transferred back to your wallet.
Full Code Example
import {
createSolanaRpc ,
createSolanaRpcSubscriptions ,
address ,
pipe ,
createTransactionMessage ,
setTransactionMessageFeePayerSigner ,
setTransactionMessageLifetimeUsingBlockhash ,
appendTransactionMessageInstructions ,
signTransactionMessageWithSigners ,
getSignatureFromTransaction ,
assertIsTransactionWithinSizeLimit ,
sendAndConfirmTransactionFactory ,
} from "@solana/kit" ;
import { parseKeypairFile } from "@kamino-finance/klend-sdk/dist/utils/signer" ;
import { Farms } from "@kamino-finance/farms-sdk" ;
const KEYPAIR_FILE = "/path/to/your/keypair.json" ;
const RPC_ENDPOINT = "https://api.mainnet-beta.solana.com" ;
const WS_ENDPOINT = "wss://api.mainnet-beta.solana.com" ;
const FARM = address ( "DXGwU8Ah7v6TBcc9ZjVmFxiLCMPgrxnsj4ZF7F8sWFxi" );
const STAKE_MINT = address ( "AYUjc3a3QQUiLE6jP7V29UMeUZGADdtiVxhSjoLcqYwr" );
const signer = await parseKeypairFile ( KEYPAIR_FILE );
const rpc = createSolanaRpc ( RPC_ENDPOINT );
const rpcSubscriptions = createSolanaRpcSubscriptions ( WS_ENDPOINT );
const farms = new Farms ( rpc );
const { key : userState } = await farms . getUserStateKeyForUndelegatedFarm (
signer . address ,
FARM ,
);
const instructions = [
await farms . withdrawUnstakedDepositIx ( signer , userState , FARM , STAKE_MINT ),
];
const { value : blockhash } = await rpc
. getLatestBlockhash ({ commitment: "finalized" })
. send ();
const transactionMessage = pipe (
createTransactionMessage ({ version: 0 }),
( m ) => setTransactionMessageFeePayerSigner ( signer , m ),
( m ) => setTransactionMessageLifetimeUsingBlockhash ( blockhash , m ),
( m ) => appendTransactionMessageInstructions ( instructions , m ),
);
const signedTransaction = await signTransactionMessageWithSigners ( transactionMessage );
assertIsTransactionWithinSizeLimit ( signedTransaction );
const signature = getSignatureFromTransaction ( signedTransaction );
await sendAndConfirmTransactionFactory ({ rpc , rpcSubscriptions })( signedTransaction , {
commitment: "confirmed" ,
skipPreflight: true ,
});
console . log ( "Withdraw-unstaked successful! Signature:" , signature );
See all 59 lines