@hubbleprotocol/farms-sdk
Version:
198 lines (183 loc) • 5.43 kB
text/typescript
import {
InitObligationFarmsForReserveAccounts,
InitObligationFarmsForReserveArgs,
KaminoMarket,
KaminoObligation,
KaminoReserve,
initObligationFarmsForReserve,
} from "@kamino-finance/klend-sdk";
import {
PublicKey,
SYSVAR_RENT_PUBKEY,
SystemProgram,
TransactionInstruction,
} from "@solana/web3.js";
import { Farms } from "../Farms";
import { initializeClient } from "./utils";
import { Env, accountExist, getFarmsProgramId, sleep } from "../utils";
import { TOKEN_PROGRAM_ID } from "@solana/spl-token";
export async function initAllKlendUserObligationFarmsFromFileCommand(
market: string,
file: string,
) {
const admin = process.env.ADMIN;
const rpc = process.env.RPC;
const klendProgramId = new PublicKey(process.env.KLEND_PROGRAM_ID || "");
const env = initializeClient(rpc!, admin!, getFarmsProgramId(rpc!), false);
const c = env.provider.connection;
const farmsClient = new Farms(env.provider.connection);
const shouldExecute = true;
const lendingMarket = new PublicKey(market);
const kaminoMarket = await KaminoMarket.load(
c,
lendingMarket,
450,
klendProgramId,
);
if (!kaminoMarket) {
throw new Error("Kamino market not found");
}
let ixns: TransactionInstruction[] = [];
const fs = require("fs");
const rawData = fs.readFileSync(file, "utf8");
const obligationAddresses: string[] = JSON.parse(rawData);
let startAt = 0;
let stopAt = obligationAddresses.length;
let i = startAt;
for (let i = startAt; i < stopAt; i++) {
const obligationAddress = obligationAddresses[i];
console.log(
`Running through obligation ${i}/${obligationAddresses.length} ixns ${ixns.length}`,
);
let obligation = (await kaminoMarket.getObligationByAddress(
new PublicKey(obligationAddress),
))!;
if (!obligation) {
continue;
}
for (const deposit of obligation.deposits) {
const reserve = kaminoMarket.getReserveByMint(deposit[1].mintAddress)!;
const reserveFarms: [PublicKey, number][] = [
[reserve.state.farmCollateral, 0],
// [reserve.state.farmDebt, 1],
];
for (const [reserveFarm, mode] of reserveFarms) {
if (reserveFarm.equals(PublicKey.default)) {
continue;
}
// For this reserve, do both collateral and debt
const userStatePda = getUserFarmPda(
reserveFarm,
obligation.obligationAddress,
farmsClient.getProgramID(),
);
// Only init if does not exist
if (!(await accountExist(c, userStatePda))) {
ixns.push(
getInitIxn(
env,
obligation,
kaminoMarket,
reserve,
reserveFarm,
userStatePda,
farmsClient.getProgramID(),
mode,
),
);
}
}
}
}
// Execute these first
console.log("Executing ixns", ixns.length);
let promises: any = [];
if (shouldExecute) {
let batchSize = 5;
let thisBatch: TransactionInstruction[] = [];
let maxConcurrent = 20;
for (let i = 0; i < ixns.length; i++) {
thisBatch.push(ixns[i]);
console.log("Executing ixn", i);
if (thisBatch.length >= batchSize || i === ixns.length - 1) {
promises.push(
executeWithoutAwait(env, farmsClient, thisBatch, i, ixns.length).then(
(sig) => {
console.log(`Init Signature ${sig} for ${i}/${ixns.length}`);
},
),
);
thisBatch = [];
}
if (promises.length >= maxConcurrent || i === ixns.length - 1) {
await Promise.all(promises);
promises = [];
}
}
}
await Promise.all(promises);
}
const executeWithoutAwait = async (
env: Env,
farmsClient: Farms,
thisBatch: TransactionInstruction[],
i: number,
len: number,
) => {
let numRetries = 5;
let retry = 0;
while (retry < numRetries) {
try {
const sig = await farmsClient.executeTransaction(
thisBatch,
env.initialOwner,
[],
);
return sig;
} catch (e) {
retry += 1;
await sleep(1000);
}
}
return null;
};
const BASE_SEED_USER_STATE = Buffer.from("user");
const getUserFarmPda = (
farm: PublicKey,
obligation: PublicKey,
farmsProgramId: PublicKey,
) =>
PublicKey.findProgramAddressSync(
[BASE_SEED_USER_STATE, farm.toBytes(), obligation.toBytes()],
farmsProgramId,
)[0];
const getInitIxn = (
env: Env,
obligation: KaminoObligation,
market: KaminoMarket,
reserve: KaminoReserve,
reserveFarm: PublicKey,
userStatePda: PublicKey,
farmsProgramId: PublicKey,
mode: number,
): TransactionInstruction => {
const args = {
mode,
} as InitObligationFarmsForReserveArgs;
const accts = {
payer: env.initialOwner.publicKey,
owner: obligation.state.owner,
obligation: obligation.obligationAddress,
lendingMarketAuthority: market.getLendingMarketAuthority(),
reserve: reserve.address,
reserveFarmState: reserveFarm,
obligationFarm: userStatePda,
lendingMarket: reserve.state.lendingMarket,
farmsProgram: farmsProgramId,
rent: SYSVAR_RENT_PUBKEY,
tokenProgram: TOKEN_PROGRAM_ID,
systemProgram: SystemProgram.programId,
} as InitObligationFarmsForReserveAccounts;
const ixn = initObligationFarmsForReserve(args, accts, market.programId);
return ixn;
};