Repay Debt
Repay borrowed assets to improve your position health.1
Import Dependencies
import {
createSolanaRpc,
createSolanaRpcSubscriptions,
address,
pipe,
createTransactionMessage,
setTransactionMessageFeePayerSigner,
setTransactionMessageLifetimeUsingBlockhash,
appendTransactionMessageInstructions,
signTransactionMessageWithSigners,
assertIsTransactionWithinSizeLimit,
sendAndConfirmTransactionFactory,
getSignatureFromTransaction,
} from '@solana/kit';
import {
KaminoMarket,
KaminoAction,
VanillaObligation,
PROGRAM_ID,
getCurrentLedgerInstant,
getMedianSlotDurationInMsFromLastEpochs,
} from '@kamino-finance/klend-sdk';
import { parseKeypairFile } from '@kamino-finance/klend-sdk/dist/utils/signer.js';
import BN from 'bn.js';
2
Load Market and Initialize RPC
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('7u3HeHxYDLhnCoErrtycNokbQYbWGzLs6JSDqGAv5PfF'); // SOL/BTC Market
const market = await KaminoMarket.load(rpc, marketPubkey, await getMedianSlotDurationInMsFromLastEpochs());
3
Load the Obligation
Load the wallet’s borrow position so the SDK refreshes every reserve it uses.const obligation = await market!.getObligationByWallet(signer.address, new VanillaObligation(PROGRAM_ID));
if (!obligation) {
console.log('No borrow position found for', signer.address);
}
4
Build Repay Instructions
Repay part of the USDT loan from the USDT in the wallet.const usdtMint = address('Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB');
const usdtReserve = market!.getExistingFloatRateReserveByMint(usdtMint);
const repayAction = await KaminoAction.buildRepayTxns({
kaminoMarket: market!,
amount: new BN(1_000_000),
reserveAddress: usdtReserve.address,
owner: signer,
obligation: obligation!,
useV2Ixs: true,
scopeRefreshConfig: undefined,
currentLedgerInstant: await getCurrentLedgerInstant(rpc),
});
To repay the whole loan including accrued interest, pass
new BN(U64_MAX) as the amount (U64_MAX is exported by the SDK). The program repays the exact debt, so no dust is left.5
Build the Transaction
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(KaminoAction.actionToIxs(repayAction), tx)
);
6
Sign and Send
const signedTransaction = await signTransactionMessageWithSigners(transactionMessage);
assertIsTransactionWithinSizeLimit(signedTransaction);
await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })(signedTransaction, {
commitment: 'confirmed',
skipPreflight: true,
});
console.log('Repay successful! Signature:', getSignatureFromTransaction(signedTransaction));
The debt in the borrow position is reduced.
Withdraw Collateral
Withdraw collateral from your obligation.1
Import Dependencies
import {
createSolanaRpc,
createSolanaRpcSubscriptions,
address,
pipe,
createTransactionMessage,
setTransactionMessageFeePayerSigner,
setTransactionMessageLifetimeUsingBlockhash,
appendTransactionMessageInstructions,
signTransactionMessageWithSigners,
assertIsTransactionWithinSizeLimit,
sendAndConfirmTransactionFactory,
getSignatureFromTransaction,
} from '@solana/kit';
import {
KaminoMarket,
KaminoAction,
VanillaObligation,
PROGRAM_ID,
getCurrentLedgerInstant,
getMedianSlotDurationInMsFromLastEpochs,
} from '@kamino-finance/klend-sdk';
import { parseKeypairFile } from '@kamino-finance/klend-sdk/dist/utils/signer.js';
import BN from 'bn.js';
2
Load Market and Initialize RPC
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('7u3HeHxYDLhnCoErrtycNokbQYbWGzLs6JSDqGAv5PfF'); // SOL/BTC Market
const market = await KaminoMarket.load(rpc, marketPubkey, await getMedianSlotDurationInMsFromLastEpochs());
3
Load the Obligation
Load the wallet’s borrow position so the SDK refreshes every reserve it uses.const obligation = await market!.getObligationByWallet(signer.address, new VanillaObligation(PROGRAM_ID));
if (!obligation) {
console.log('No borrow position found for', signer.address);
}
4
Build Withdraw Instructions
Withdraw USDC collateral from the borrow position.const usdcMint = address('EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v');
const usdcReserve = market!.getExistingFloatRateReserveByMint(usdcMint);
const withdrawAction = await KaminoAction.buildWithdrawTxns({
kaminoMarket: market!,
amount: new BN(1_000_000),
reserveAddress: usdcReserve.address,
owner: signer,
obligation: obligation!,
useV2Ixs: true,
scopeRefreshConfig: undefined,
currentLedgerInstant: await getCurrentLedgerInstant(rpc),
});
With open borrows, the withdrawal must keep the position under its borrow limit. To withdraw all of a deposit, pass
new BN(U64_MAX) as the amount.5
Build the Transaction
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(KaminoAction.actionToIxs(withdrawAction), tx)
);
6
Sign and Send
const signedTransaction = await signTransactionMessageWithSigners(transactionMessage);
assertIsTransactionWithinSizeLimit(signedTransaction);
await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })(signedTransaction, {
commitment: 'confirmed',
skipPreflight: true,
});
console.log('Withdraw successful! Signature:', getSignatureFromTransaction(signedTransaction));
The collateral is back in the wallet.