UNPKG

@kamino-finance/farms-sdk

Version:
335 lines 12.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.parseTokenSymbol = exports.getCustomProgramErrorCode = exports.WAD = void 0; exports.collToLamportsDecimal = collToLamportsDecimal; exports.lamportsToCollDecimal = lamportsToCollDecimal; exports.decimalToBN = decimalToBN; exports.checkIfAccountExists = checkIfAccountExists; exports.mapAnchorError = mapAnchorError; exports.getTokenAccountBalance = getTokenAccountBalance; exports.getTokenAccountBalanceLamports = getTokenAccountBalanceLamports; exports.getSolBalanceInLamports = getSolBalanceInLamports; exports.getSolBalance = getSolBalance; 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.getGlobalConfigValue = getGlobalConfigValue; exports.createKeypairRentExemptIx = createKeypairRentExemptIx; exports.sleep = sleep; exports.scaleDownWads = scaleDownWads; exports.convertAmountToStake = convertAmountToStake; exports.retryAsync = retryAsync; exports.noopProfiledFunctionExecution = noopProfiledFunctionExecution; exports.isValidPubkey = isValidPubkey; const farms_1 = require("../@codegen/farms/errors/farms"); const kit_1 = require("@solana/kit"); const decimal_js_1 = require("decimal.js"); const accounts_1 = require("../@codegen/farms/accounts"); const system_1 = require("@solana-program/system"); const programs_1 = require("../@codegen/farms/programs"); const compute_budget_1 = require("@solana-program/compute-budget"); const pubkey_1 = require("./pubkey"); exports.WAD = new decimal_js_1.Decimal("1".concat(Array(18 + 1).join("0"))); const addressEncoder = (0, kit_1.getAddressEncoder)(); function collToLamportsDecimal(amount, decimals) { const factor = Math.pow(10, decimals); return new decimal_js_1.Decimal(amount).mul(factor); } function lamportsToCollDecimal(amount, decimals) { const factor = Math.pow(10, decimals); return new decimal_js_1.Decimal(amount).div(factor); } function decimalToBN(value) { // Note: the `Decimal.toString()` can return exponential notation (e.g. "1e9") for large numbers. This notation is // not accepted by `BigInt` constructor (i.e. invalid character "e"). Hence, we use `Decimal.toFixed()` (which is // different than `number.toFixed()` - it will not do any rounding, just render a normal notation). // see https://mikemcl.github.io/decimal.js/#toFixed return BigInt(value.toFixed()); } async function checkIfAccountExists(connection, account) { return ((await connection.getAccountInfo(account, { encoding: "base64" }).send()) .value != 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) { if (!isNaN(Number(errorCode))) { const errorMessage = (0, farms_1.getFarmsErrorMessage)(Number(errorCode)); if (errorMessage) { throw new Error(errorMessage); } } throw new Error(e); } throw e; } } async function getTokenAccountBalance(rpc, tokenAccount) { const tokenAccountBalance = await rpc .getTokenAccountBalance(tokenAccount) .send(); return new decimal_js_1.Decimal(tokenAccountBalance.value.amount).div(decimal_js_1.Decimal.pow(10, tokenAccountBalance.value.decimals)); } async function getTokenAccountBalanceLamports(rpc, tokenAccount) { const tokenAccountBalance = await rpc .getTokenAccountBalance(tokenAccount) .send(); return new decimal_js_1.Decimal(tokenAccountBalance.value.amount).toNumber(); } async function getSolBalanceInLamports(rpc, account) { let balance = undefined; while (balance === undefined) { balance = (await rpc.getBalance(account).send()).value; } return balance; } async function getSolBalance(rpc, account) { const balance = new decimal_js_1.Decimal((await getSolBalanceInLamports(rpc, account)).toString()); return lamportsToCollDecimal(balance, 9); } function createAddExtraComputeUnitsTransaction(units) { return (0, compute_budget_1.getSetComputeUnitLimitInstruction)({ 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(rpc, account) { const info = await rpc.getAccountInfo(account, { encoding: "base64" }).send(); if (info.value === null || info.value.data[0].length === 0) { return false; } return true; } async function fetchFarmStateWithRetry(rpc, addr) { return fetchWithRetry(async () => { const account = await (0, accounts_1.fetchMaybeFarmState)(rpc, addr); return account.exists ? account.data : null; }, addr); } async function fetchGlobalConfigWithRetry(rpc, addr) { const result = await fetchWithRetry(async () => { const account = await (0, accounts_1.fetchMaybeGlobalConfig)(rpc, addr); return account.exists ? account.data : null; }, addr); if (result === null) { throw new Error(`GlobalConfig account ${addr} not found after retries`); } return result; } async function fetchUserStateWithRetry(rpc, addr) { const result = await fetchWithRetry(async () => { const account = await (0, accounts_1.fetchMaybeUserState)(rpc, addr); return account.exists ? account.data : null; }, addr); if (result === null) { throw new Error(`UserState account ${addr} not found after retries`); } return result; } async function getTreasuryVaultPDA(programId, globalConfig, rewardMint) { const [treasuryVault] = await (0, kit_1.getProgramDerivedAddress)({ seeds: [ new TextEncoder().encode("tvault"), addressEncoder.encode(globalConfig), addressEncoder.encode(rewardMint), ], programAddress: programId, }); return treasuryVault; } async function getTreasuryAuthorityPDA(farmsProgramId, globalConfig) { const [treasuryAuthority] = await (0, kit_1.getProgramDerivedAddress)({ seeds: [ new TextEncoder().encode("authority"), addressEncoder.encode(globalConfig), ], programAddress: farmsProgramId, }); return treasuryAuthority; } async function getFarmAuthorityPDA(farmsProgramId, farmState) { const [farmAuthority] = await (0, kit_1.getProgramDerivedAddress)({ seeds: [ new TextEncoder().encode("authority"), addressEncoder.encode(farmState), ], programAddress: farmsProgramId, }); return farmAuthority; } async function getFarmVaultPDA(farmsProgramId, farmState, tokenMint) { const [farmVault] = await (0, kit_1.getProgramDerivedAddress)({ seeds: [ new TextEncoder().encode("fvault"), addressEncoder.encode(farmState), addressEncoder.encode(tokenMint), ], programAddress: farmsProgramId, }); return farmVault; } async function getRewardVaultPDA(programId, farmState, rewardMint) { const [rewardVault] = await (0, kit_1.getProgramDerivedAddress)({ seeds: [ new TextEncoder().encode("rvault"), addressEncoder.encode(farmState), addressEncoder.encode(rewardMint), ], programAddress: programId, }); return rewardVault; } async function getUserStatePDA(programId, farmState, owner) { const [userState] = await (0, kit_1.getProgramDerivedAddress)({ seeds: [ new TextEncoder().encode("user"), addressEncoder.encode(farmState), addressEncoder.encode(owner), ], programAddress: 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; } 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 = (0, kit_1.address)(flagValue); } else { throw new Error("flagValueType must be 'number', 'bool', or 'publicKey'"); } let buffer; if (typeof value === "string" && (0, kit_1.isAddress)(value)) { buffer = new Uint8Array(addressEncoder.encode(value)); } else if (typeof value === "boolean") { buffer = new Uint8Array(32); buffer[0] = value ? 1 : 0; } else if (typeof value === "bigint") { buffer = new Uint8Array(32); const view = new DataView(buffer.buffer); view.setBigUint64(0, value, true); // 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 createKeypairRentExemptIx(rpc, payer, account, size, programId = programs_1.FARMS_PROGRAM_ADDRESS) { return (0, system_1.getCreateAccountInstruction)({ payer: payer, space: size, lamports: await rpc.getMinimumBalanceForRentExemption(size).send(), programAddress: programId, newAccount: account, }); } 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 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; } function isValidPubkey(address) { if (!address) { return false; } return address !== pubkey_1.DEFAULT_PUBLIC_KEY; } //# sourceMappingURL=utils.js.map