Repaying debt on a multiply position reduces your outstanding debt balance, lowers your LTV (Loan-to-Value) ratio, and improves position health. This example shows how to repay USDC debt on a TSLAx multiply position using the Klend SDK.
Multiply Repay with xStocks
Repay debt on a TSLAx multiply position to reduce leverage and improve position health.
Import Dependencies
Import the required packages for Solana RPC communication, Kamino SDK operations, and transaction building.import {
createSolanaRpc,
createSolanaRpcSubscriptions,
address,
pipe,
createTransactionMessage,
setTransactionMessageFeePayerSigner,
setTransactionMessageLifetimeUsingBlockhash,
appendTransactionMessageInstructions,
signTransactionMessageWithSigners,
sendAndConfirmTransactionFactory,
getSignatureFromTransaction,
} from '@solana/kit';
import {
KaminoMarket,
KaminoAction,
MultiplyObligation,
PROGRAM_ID,
parseKeypairFile,
DEFAULT_RECENT_SLOT_DURATION_MS,
} from '@kamino-finance/klend-sdk';
import BN from 'bn.js';
Load Configuration and Initialize Market
Load the keypair and initialize the xStocks market.const KEYPAIR_FILE = '/path/to/your/keypair.json';
const signer = await parseKeypairFile(KEYPAIR_FILE);
const rpc = createSolanaRpc('https://api.mainnet-beta.solana.com');
const rpcSubscriptions = createSolanaRpcSubscriptions('wss://api.mainnet-beta.solana.com');
const marketPubkey = address('5wJeMrUYECGq41fxRESKALVcHnNX26TAWy4W98yULsua'); // xStocks Market
const market = await KaminoMarket.load(rpc, marketPubkey, DEFAULT_RECENT_SLOT_DURATION_MS);
Find TSLAx Reserve in Market
Dynamically discover the TSLAx token mint by searching the market reserves by symbol.const tslaReserve = Array.from(market!.reserves.values()).find((reserve) => reserve.symbol === 'TSLAx');
if (!tslaReserve) {
console.log('TSLAx reserve not found in xStocks market');
}
const collTokenMint = tslaReserve.getLiquidityMint();
const debtTokenMint = address('EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'); // USDC
This dynamic discovery approach allows the code to work across different markets without hardcoding token mint addresses.
Set the amount of USDC to repay. This example repays $10 USDC.const repayAmount = new BN(10_000_000); // 10.00 USDC (6 decimals)
const currentSlot = await rpc.getSlot().send();
You can repay any amount up to your total debt. After repaying, you are able to withdraw your collateral.
Fetch Existing Multiply Obligation
Create the multiply obligation type and fetch the existing position from the blockchain.const obligationType = new MultiplyObligation(collTokenMint, debtTokenMint, PROGRAM_ID);
const obligation = await market!.getObligationByWallet(address(signer.address), obligationType);
if (!obligation) {
console.log('No obligation found for this wallet. You must have an active borrow to repay.');
}
The MultiplyObligation type identifies this as a leveraged position rather than a standard borrow. The obligation must exist before you can repay debt.
Build Repay Transaction
Use KaminoAction.buildRepayTxns to generate the repay instructions.const repayAction = await KaminoAction.buildRepayTxns(
market!,
repayAmount,
debtTokenMint,
signer,
obligationType,
true, // useV2Ixs
undefined, // scopeRefreshConfig
currentSlot,
signer, // payer
1_000_000, // extraComputeBudget
true, // includeAtaIxs
false // requestElevationGroup
);
const allInstructions = [
...(repayAction.setupIxs || []),
...(repayAction.lendingIxs || []),
...(repayAction.cleanupIxs || []),
];
buildRepayTxns handles all the complexity of repaying multiply positions, including ATA creation, scope price refreshes, and obligation updates.
Send Transaction
Get a fresh blockhash, build the transaction, sign it, and send it to the network.const { value: latestBlockhash } = await rpc.getLatestBlockhash({ commitment: 'finalized' }).send();
const transactionMessage = pipe(
createTransactionMessage({ version: 0 }),
(tx) => setTransactionMessageFeePayerSigner(signer, tx),
(tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx),
(tx) => appendTransactionMessageInstructions(allInstructions, tx)
);
const signedTransaction = await signTransactionMessageWithSigners(transactionMessage);
const signature = getSignatureFromTransaction(signedTransaction);
await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })(signedTransaction, {
commitment: 'confirmed',
skipPreflight: true,
});
console.log(`Multiply repay successful! Repaid $10 USDC debt on TSLAx multiply position.`);
console.log(`Transaction signature: ${signature}`);
The repay transaction is complete, reducing your debt balance and improving your position’s health factor.
Borrow and Multiply SDK Methods
| Method | Operation | When to Use |
|---|
getDepositWithLeverageIxs | Open position or add collateral | Creating or adding to a leveraged position |
buildRepayTxns | Repay with wallet funds | Reducing debt using USDC, SOL, etc. from wallet |
buildWithdrawTxns | Withdraw collateral | Withdrawing collateral after debt is repaid |
getWithdrawWithLeverageIxs | Deleverage and withdraw | Sell collateral to repay debt and receive remaining value in wallet |
getRepayWithCollIxs | Repay debt with collateral | Sell collateral to repay debt without withdrawing (value stays in position) |
Multiply operations use MultiplyObligation. Vanilla operations use VanillaObligation. The obligation type determines which PDA is derived for your position.