UNPKG

@kamino-finance/farms-sdk

Version:
407 lines 16.6 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.parseTokenSymbol = exports.getCustomProgramErrorCode = exports.WAD = void 0; exports.parseKeypairFile = parseKeypairFile; exports.collToLamportsDecimal = collToLamportsDecimal; exports.lamportsToCollDecimal = lamportsToCollDecimal; exports.solAirdrop = solAirdrop; exports.solAirdropMin = solAirdropMin; exports.checkIfAccountExists = checkIfAccountExists; exports.mapAnchorError = mapAnchorError; exports.getTokenAccountBalance = getTokenAccountBalance; exports.getSolBalanceInLamports = getSolBalanceInLamports; exports.getSolBalance = getSolBalance; exports.getFarmsProgramId = getFarmsProgramId; exports.pubkeyFromFile = pubkeyFromFile; exports.createAddExtraComputeUnitsTransaction = createAddExtraComputeUnitsTransaction; exports.u16ToBytes = u16ToBytes; exports.accountExist = accountExist; exports.fetchFarmStateWithRetry = fetchFarmStateWithRetry; exports.fetchGlobalConfigWithRetry = fetchGlobalConfigWithRetry; exports.fetchUserStateWithRetry = fetchUserStateWithRetry; exports.getTreasuryVaultPDA = getTreasuryVaultPDA; exports.getTreasuryAuthorityPDA = getTreasuryAuthorityPDA; exports.getFarmAuthorityPDA = getFarmAuthorityPDA; exports.getFarmVaultPDA = getFarmVaultPDA; exports.getRewardVaultPDA = getRewardVaultPDA; exports.getUserStatePDA = getUserStatePDA; exports.sendAndConfirmInstructions = sendAndConfirmInstructions; exports.getGlobalConfigValue = getGlobalConfigValue; exports.createKeypairRentExempt = createKeypairRentExempt; exports.createKeypairRentExemptIx = createKeypairRentExemptIx; exports.createGlobalConfigPublicKeyRentExempt = createGlobalConfigPublicKeyRentExempt; exports.createFarmPublicKeyRentExempt = createFarmPublicKeyRentExempt; exports.buildAndSendTxnWithLogs = buildAndSendTxnWithLogs; exports.sleep = sleep; exports.scaleDownWads = scaleDownWads; exports.convertStakeToAmount = convertStakeToAmount; exports.convertAmountToStake = convertAmountToStake; exports.retryAsync = retryAsync; exports.noopProfiledFunctionExecution = noopProfiledFunctionExecution; const anchor = __importStar(require("@coral-xyz/anchor")); const fs = __importStar(require("fs")); const FarmsErrors = __importStar(require("../rpc_client/errors")); const web3_js_1 = require("@solana/web3.js"); const decimal_js_1 = require("decimal.js"); const web3 = __importStar(require("@solana/web3.js")); const setup_1 = require("./setup"); const accounts_1 = require("../rpc_client/accounts"); const Farms_1 = require("../Farms"); exports.WAD = new decimal_js_1.Decimal("1".concat(Array(18 + 1).join("0"))); function parseKeypairFile(file) { return web3_js_1.Keypair.fromSecretKey(Buffer.from(JSON.parse(require("fs").readFileSync(file)))); } function collToLamportsDecimal(amount, decimals) { let factor = Math.pow(10, decimals); return amount.mul(factor); } function lamportsToCollDecimal(amount, decimals) { let factor = Math.pow(10, decimals); return amount.div(factor); } async function solAirdrop(provider, account, solAirdrop) { const airdropTxnId = await provider.connection.requestAirdrop(account, collToLamportsDecimal(solAirdrop, 9).toNumber()); await provider.connection.confirmTransaction(airdropTxnId); return await getSolBalance(provider, account); } async function solAirdropMin(provider, account, minSolAirdrop) { const airdropBatchAmount = decimal_js_1.Decimal.max(50, minSolAirdrop); let currentBalance = await getSolBalance(provider, account); while (currentBalance.lt(minSolAirdrop)) { try { await provider.connection.requestAirdrop(account, collToLamportsDecimal(airdropBatchAmount, 9).toNumber()); } catch (e) { await sleep(100); console.log("Error", e); } await sleep(100); currentBalance = await getSolBalance(provider, account); } return currentBalance; } async function checkIfAccountExists(connection, account) { return (await connection.getAccountInfo(account)) != null; } /** * Get the custom program error code if there's any in the error message and return parsed error code hex to number string * @param errMessage string - error message that would contain the word "custom program error:" if it's a customer program error * @returns [boolean, string] - probably not a custom program error if false otherwise the second element will be the code number in string */ const getCustomProgramErrorCode = (errMessage) => { const index = errMessage.indexOf("Custom program error:"); if (index === -1) { return [false, "May not be a custom program error"]; } else { return [ true, `${parseInt(errMessage.substring(index + 22, index + 28).replace(" ", ""), 16)}`, ]; } }; exports.getCustomProgramErrorCode = getCustomProgramErrorCode; /** * * Maps the private Anchor type ProgramError to a normal Error. * Pass ProgramErr.msg as the Error message so that it can be used with chai matchers * * @param fn - function which may throw an anchor ProgramError */ async function mapAnchorError(fn) { try { return await fn; } catch (e) { let [isCustomProgramError, errorCode] = (0, exports.getCustomProgramErrorCode)(JSON.stringify(e)); if (isCustomProgramError) { let error; if (!isNaN(Number(errorCode))) { error = FarmsErrors.fromCode(Number(errorCode)); throw new Error(error); } else if (Number(errorCode) >= 6000 && Number(errorCode) <= 7000) { errorCode[errorCode.length - 2] === "0" ? (errorCode = errorCode.slice(-1)) : (errorCode = errorCode.slice(-2)); // @ts-ignore error = FarmsIdl.errors[errorCode].msg; throw new Error(error); } else { throw new Error(e); } } throw e; } } async function getTokenAccountBalance(provider, tokenAccount) { const tokenAccountBalance = await provider.connection.getTokenAccountBalance(tokenAccount); return new decimal_js_1.Decimal(tokenAccountBalance.value.amount).div(decimal_js_1.Decimal.pow(10, tokenAccountBalance.value.decimals)); } async function getSolBalanceInLamports(provider, account) { let balance = undefined; while (balance === undefined) { balance = (await provider.connection.getAccountInfo(account))?.lamports; } return balance; } async function getSolBalance(provider, account) { const balance = new decimal_js_1.Decimal(await getSolBalanceInLamports(provider, account)); return lamportsToCollDecimal(balance, 9); } function getFarmsProgramId(cluster) { return new web3_js_1.PublicKey("FarmsPZpWu9i7Kky8tPN37rs2TpmMrAZrC7S7vJa91Hr"); } function pubkeyFromFile(filepath) { const fileContents = fs.readFileSync(filepath, "utf8"); const privateArray = fileContents .replace("[", "") .replace("]", "") .split(",") .map(function (item) { return parseInt(item, 10); }); const array = Uint8Array.from(privateArray); const keypair = web3_js_1.Keypair.fromSecretKey(array); return keypair.publicKey; } function createAddExtraComputeUnitsTransaction(owner, units) { return web3.ComputeBudgetProgram.setComputeUnitLimit({ units }); } function u16ToBytes(num) { const arr = new ArrayBuffer(2); const view = new DataView(arr); view.setUint16(0, num, false); return new Uint8Array(arr); } async function accountExist(connection, account) { const info = await connection.getAccountInfo(account); if (info === null || info.data.length === 0) { return false; } return true; } async function fetchFarmStateWithRetry(env, address) { return fetchWithRetry(async () => await accounts_1.FarmState.fetch(env.provider.connection, address), address); } async function fetchGlobalConfigWithRetry(env, address) { return fetchWithRetry(async () => await accounts_1.GlobalConfig.fetch(env.provider.connection, address), address); } async function fetchUserStateWithRetry(env, address) { return fetchWithRetry(async () => await accounts_1.UserState.fetch(env.provider.connection, address), address); } function getTreasuryVaultPDA(programId, globalConfig, rewardMint) { const [treasuryVault, _rewardTreasuryVaultBump] = anchor.web3.PublicKey.findProgramAddressSync([Buffer.from("tvault"), globalConfig.toBuffer(), rewardMint.toBuffer()], programId); return treasuryVault; } function getTreasuryAuthorityPDA(programId, globalConfig) { const [treasuryAuthority, _treasuryAuthorityBump] = anchor.web3.PublicKey.findProgramAddressSync([Buffer.from("authority"), globalConfig.toBuffer()], programId); return treasuryAuthority; } function getFarmAuthorityPDA(programId, farmState) { const [farmAuthority, _farmAuthorityBump] = anchor.web3.PublicKey.findProgramAddressSync([Buffer.from("authority"), farmState.toBuffer()], programId); return farmAuthority; } function getFarmVaultPDA(programId, farmState, tokenMint) { const [farmVault, _farmVaultBump] = anchor.web3.PublicKey.findProgramAddressSync([Buffer.from("fvault"), farmState.toBuffer(), tokenMint.toBuffer()], programId); return farmVault; } function getRewardVaultPDA(programId, farmState, rewardMint) { const [rewardVault, _rewardVaultBump] = anchor.web3.PublicKey.findProgramAddressSync([Buffer.from("rvault"), farmState.toBuffer(), rewardMint.toBuffer()], programId); return rewardVault; } function getUserStatePDA(programId, farmState, owner) { const [userState, _userStateBump] = anchor.web3.PublicKey.findProgramAddressSync([Buffer.from("user"), farmState.toBuffer(), owner.toBuffer()], programId); return userState; } async function fetchWithRetry(fetch, address, retries = 3) { for (let i = 0; i < retries; i++) { let resp = await fetch(); if (resp !== null) { return resp; } console.log(`[${i + 1}/${retries}] Fetched account ${address} is null. Refetching...`); } return null; } async function sendAndConfirmInstructions(env, ixns) { let tx = new web3_js_1.Transaction(); for (let i = 0; i < ixns.length; i++) { tx.add(ixns[i]); } let { blockhash } = await env.provider.connection.getLatestBlockhash(); tx.recentBlockhash = blockhash; tx.feePayer = env.initialOwner.publicKey; return await web3.sendAndConfirmTransaction(env.provider.connection, tx, [ env.initialOwner, ]); } function getGlobalConfigValue(flagValueType, flagValue) { let value; if (flagValueType === "number") { value = BigInt(flagValue); } else if (flagValueType === "bool") { if (flagValue === "false") { value = false; } else if (flagValue === "true") { value = true; } else { throw new Error("the provided flag value is not valid bool"); } } else if (flagValueType === "publicKey") { value = new web3_js_1.PublicKey(flagValue); } else { throw new Error("flagValueType must be 'number', 'bool', or 'publicKey'"); } let buffer; if (value instanceof web3_js_1.PublicKey) { buffer = value.toBuffer(); } else if (typeof value === "boolean") { buffer = Buffer.alloc(32); value ? buffer.writeUInt8(1, 0) : buffer.writeUInt8(0, 0); } else if (typeof value === "bigint") { buffer = Buffer.alloc(32); buffer.writeBigUInt64LE(value); // Because we send 32 bytes and a u64 has 8 bytes, we write it in LE } else { throw Error("wrong type for value"); } return [...buffer]; } async function createKeypairRentExempt(provider, programId, address, size) { const tx = new web3_js_1.Transaction(); tx.add(await createKeypairRentExemptIx(provider.connection, provider.wallet.publicKey, address, size, programId)); await provider.sendAndConfirm(tx, [address]); return address; } async function createKeypairRentExemptIx(connection, payer, account, size, programId = Farms_1.farmsId) { return web3_js_1.SystemProgram.createAccount({ fromPubkey: payer, newAccountPubkey: account.publicKey, space: size, lamports: await connection.getMinimumBalanceForRentExemption(size), programId: programId, }); } async function createGlobalConfigPublicKeyRentExempt(provider, programId) { const config = web3_js_1.Keypair.generate(); const key = await createKeypairRentExempt(provider, programId, config, setup_1.SIZE_GLOBAL_CONFIG); return key; } async function createFarmPublicKeyRentExempt(provider, programId) { const farm = web3_js_1.Keypair.generate(); const key = await createKeypairRentExempt(provider, programId, farm, setup_1.SIZE_FARM_STATE); return key; } async function buildAndSendTxnWithLogs(c, tx, owner, signers) { const { blockhash } = await c.getLatestBlockhash(); tx.recentBlockhash = blockhash; tx.feePayer = owner.publicKey; try { const sig = await c.sendTransaction(tx, [owner, ...signers]); console.log("Transaction Hash:", sig); await sleep(5000); const res = await c.getTransaction(sig, { commitment: "confirmed", }); console.log("Transaction Logs:\n", res.meta.logMessages); } catch (e) { console.log(e); await sleep(5000); const sig = e.toString().split(" failed ")[0].split("Transaction ")[1]; const res = await c.getTransaction(sig, { commitment: "confirmed", }); console.log("Txn", res.meta.logMessages); } } function sleep(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); } function scaleDownWads(value) { return new decimal_js_1.Decimal(value.toString()).div(exports.WAD).toNumber(); } function convertStakeToAmount(stake, totalStaked, totalAmount) { if (stake === new decimal_js_1.Decimal(0)) { return new decimal_js_1.Decimal(0); } if (totalStaked !== new decimal_js_1.Decimal(0)) { return stake.mul(totalAmount).div(totalStaked); } else { return stake.add(totalAmount); } } function convertAmountToStake(amount, totalStaked, totalAmount) { if (amount === new decimal_js_1.Decimal(0)) { return new decimal_js_1.Decimal(0); } if (totalAmount !== new decimal_js_1.Decimal(0)) { return totalStaked.mul(amount).div(totalAmount); } else { return amount; } } const parseTokenSymbol = (tokenSymbol) => { return String.fromCharCode(...tokenSymbol.filter((x) => x > 0)); }; exports.parseTokenSymbol = parseTokenSymbol; async function retryAsync(fn, retriesLeft = 5, interval = 2000) { try { return await fn(); } catch (error) { if (retriesLeft) { await new Promise((resolve) => setTimeout(resolve, interval)); return await retryAsync(fn, retriesLeft - 1, interval); } throw error; } } function noopProfiledFunctionExecution(promise) { return promise; } //# sourceMappingURL=utils.js.map