import {
createSolanaRpc,
createSolanaRpcSubscriptions,
address,
pipe,
createTransactionMessage,
setTransactionMessageFeePayerSigner,
setTransactionMessageLifetimeUsingBlockhash,
appendTransactionMessageInstructions,
signTransactionMessageWithSigners,
sendAndConfirmTransactionFactory,
getSignatureFromTransaction,
compressTransactionMessageUsingAddressLookupTables,
assertIsTransactionWithinSizeLimit,
} from "@solana/kit";
import type { Address } from "@solana/kit";
import { Kamino } from "@kamino-finance/kliquidity-sdk";
import { parseKeypairFile } from "@kamino-finance/klend-sdk/dist/utils/signer";
import { fetchAllAddressLookupTable } from "@solana-program/address-lookup-table";
import Decimal from "decimal.js";
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 STRATEGY = address("CEz5keL9hBCUbtVbmcwenthRMwmZLupxJ6YtYAgzp4ex");
const usdcAmount = new Decimal(2.0);
const slippageBps = new Decimal(100);
const signer = await parseKeypairFile(KEYPAIR_FILE);
const rpc = createSolanaRpc(RPC_ENDPOINT);
const rpcSubscriptions = createSolanaRpcSubscriptions(WS_ENDPOINT);
const kamino = new Kamino("mainnet-beta", rpc);
const strategyState = (await kamino.getStrategiesWithAddresses([STRATEGY]))[0];
if (!strategyState) {
console.log("Strategy not found:", STRATEGY);
process.exit(1);
}
const { instructions, lookupTablesAddresses } =
await kamino.singleSidedDepositTokenB(
{ address: STRATEGY, strategy: strategyState.strategy },
usdcAmount,
signer,
slippageBps,
);
const allAddresses = new Set<string>();
for (const ix of instructions) {
allAddresses.add(ix.programAddress.toString());
for (const acc of ix.accounts ?? []) allAddresses.add(acc.address.toString());
}
const lutResp = await fetch("https://api.kamino.finance/luts/find-minimal", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ addresses: Array.from(allAddresses) }),
});
if (!lutResp.ok) {
console.log(
"luts/find-minimal failed:",
lutResp.status,
await lutResp.text(),
);
process.exit(1);
}
const { lutAddresses: minimalLutAddresses } = (await lutResp.json()) as {
lutAddresses: string[];
};
const dedupedLutAddresses = Array.from(
new Set(
[
...lookupTablesAddresses,
...minimalLutAddresses.map((a) => address(a)),
].map((a) => a.toString()),
),
).map((a) => address(a));
const lutAccounts = await fetchAllAddressLookupTable(rpc, dedupedLutAddresses);
const lutsByAddress: Record<Address, Address[]> = {};
for (const acc of lutAccounts) {
lutsByAddress[acc.address] = acc.data.addresses;
}
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(instructions, tx),
(tx) => compressTransactionMessageUsingAddressLookupTables(tx, lutsByAddress),
);
const signedTransaction =
await signTransactionMessageWithSigners(transactionMessage);
assertIsTransactionWithinSizeLimit(signedTransaction);
const signature = getSignatureFromTransaction(signedTransaction);
await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })(
signedTransaction,
{
commitment: "confirmed",
skipPreflight: true,
},
);
console.log(
"Strategy single-sided USDC deposit successful! Signature:",
signature,
);