UNPKG

@hubbleprotocol/farms-sdk

Version:
773 lines 48 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.upsertAllFarmConfigsCommand = upsertAllFarmConfigsCommand; exports.estimateRewardDurationRewardCurve = estimateRewardDurationRewardCurve; exports.calculateDaysBalanceRemaining = calculateDaysBalanceRemaining; exports.estimateRewardDuration = estimateRewardDuration; const web3_js_1 = require("@solana/web3.js"); const decimal_js_1 = __importDefault(require("decimal.js")); const Farms_1 = require("../Farms"); const accounts_1 = require("../rpc_client/accounts"); const types_1 = require("../rpc_client/types"); const utils_1 = require("./utils"); const utils_2 = require("../utils"); const fs_1 = __importDefault(require("fs")); const cli_color_1 = __importDefault(require("cli-color")); const klend_sdk_1 = require("@kamino-finance/klend-sdk"); const microLamport = Math.pow(10, 6); const computeUnits = 200000; const microLamportsPrioritizationFee = microLamport / computeUnits; function upsertAllFarmConfigsCommand(targetPath, mode, priorityFeeMultiplier) { return __awaiter(this, void 0, void 0, function* () { const admin = process.env.ADMIN; const rpc = process.env.RPC; const env = (0, utils_1.initializeClient)(rpc, admin, (0, utils_2.getFarmsProgramId)(rpc), mode === "multisig"); // Load files from given directory const farmConfigs = recursiveReadDirectoryOfConfigs(targetPath); const slot = yield env.provider.connection.getSlot("finalized"); for (const [_index, farmConfig] of farmConfigs.entries()) { yield upsertFarmConfig(env, farmConfig, mode, slot, priorityFeeMultiplier); } }); } function upsertFarmConfig(env, farmConfig, mode, slot, priorityFeeMultiplier) { return __awaiter(this, void 0, void 0, function* () { let ixs = []; let signers = [env.initialOwner]; const farmsClient = new Farms_1.Farms(env.provider.connection); const farmState = yield accounts_1.FarmState.fetch(env.provider.connection, farmConfig.farmPubkey); if (farmState === null) { throw Error("Farm state does not exist"); } const topUpPayer = mode === "multisig" ? new web3_js_1.PublicKey(process.env.MULTISIG) : env.initialOwner.publicKey; const payer = farmState.farmAdmin; validateStakingTokenMint(farmConfig, farmState); // Set farm configurations based on differences between config and current farm state ixs.push(...(yield setDepositCapIxIfNecessary(payer, farmsClient, farmConfig, farmState, mode))); ixs.push(...(yield setLockingModeIxIfNecessary(payer, farmsClient, farmConfig, farmState, mode))); ixs.push(...(yield setLockingStartIxIfNecessary(payer, farmsClient, farmConfig, farmState, mode))); ixs.push(...(yield setLockingDurationIxIfNecessary(payer, farmsClient, farmConfig, farmState, mode))); ixs.push(...(yield setLockingEarlyWithdrawalPenaltyIxIfNecessary(payer, farmsClient, farmConfig, farmState, mode))); ixs.push(...(yield setStrategyIdIfNecessary(payer, farmsClient, farmConfig, farmState, mode))); ixs.push(...(yield setWithdrawAuthorityIfNecessary(payer, farmsClient, farmConfig, farmState, mode))); ixs.push(...(yield setSlashedAmountSpillAddressIfNecessary(payer, farmsClient, farmConfig, farmState, mode))); ixs.push(...(yield setPendingFarmAdminIfNecessary(payer, farmsClient, farmConfig, farmState, mode))); ixs.push(...(yield setScopePricesAccountIfNecessary(payer, farmsClient, farmConfig, farmState, mode))); ixs.push(...(yield setScopeOraclePriceIdIxIfNecessary(payer, farmsClient, farmConfig, farmState, mode))); ixs.push(...(yield setScopeOracleMaxAgeIxIfNecessary(payer, farmsClient, farmConfig, farmState, mode))); ixs.push(...(yield setDepositWarmupPeriodIfNecessary(payer, farmsClient, farmConfig, farmState, mode))); ixs.push(...(yield setWithdrawCooldownPeriodIfNecessary(payer, farmsClient, farmConfig, farmState, mode))); for (const [rewardIndex, _rewardInfoConfig] of farmConfig.rewards.entries()) { const rewardTokenProgram = farmState.rewardInfos[rewardIndex].token.tokenProgram; const rewardDecimals = farmState.rewardInfos[rewardIndex].token.decimals.toNumber(); // Initialize reward if required ixs.push(...(yield initRewardIfNecessary(payer, farmsClient, farmConfig, farmState, rewardIndex, mode))); ixs.push(...(yield setRpsDecimalsIxIfNecessary(payer, farmsClient, farmConfig, farmState, rewardIndex, mode))); ixs.push(...(yield setRewardTypeIxIfNecessary(payer, farmsClient, farmConfig, farmState, rewardIndex, mode))); ixs.push(...(yield setRewardMinClaimDurationIxIfNecessary(payer, farmsClient, farmConfig, farmState, rewardIndex, mode))); const { rewardCurve, rewardPerSecond } = getConfigRewardRps(farmState, farmConfig, rewardIndex); if (rewardPerSecond == -1 && !rewardCurve) { throw new Error("Must have either reward per second or reward curve"); } const setRewardCurveIxn = yield setRewardCurveIfNecessary(env, payer, farmsClient, farmState, farmConfig, rewardCurve, rewardIndex, rewardDecimals, slot, mode); ixs.push(...setRewardCurveIxn); let setRewardRpsIxns = []; if (setRewardCurveIxn.length == 0) { setRewardRpsIxns.push(...(yield setRewardPerSecondIfNecessary(payer, farmsClient, farmState, farmConfig, rewardPerSecond, rewardIndex, rewardDecimals, mode))); } ixs.push(...setRewardRpsIxns); // Topup ixs.push(...(yield topupRewardAmountNecessary(env, topUpPayer, farmsClient, farmState, farmConfig, rewardIndex, rewardDecimals, rewardTokenProgram, slot, setRewardCurveIxn.length == 0 && setRewardRpsIxns.length == 0, mode))); } // 5. Send or print txn const { blockhash } = yield (0, utils_2.retryAsync)(() => __awaiter(this, void 0, void 0, function* () { return (0, utils_2.noopProfiledFunctionExecution)(env.provider.connection.getLatestBlockhash("confirmed")); })); let txn = new web3_js_1.Transaction(); txn.recentBlockhash = blockhash; txn.feePayer = mode === "multisig" ? new web3_js_1.PublicKey(process.env.MULTISIG) : env.initialOwner.publicKey; if (ixs.length !== 0) { if (mode !== "multisig") { const priorityFeeIxn = (0, utils_1.createAddExtraComputeUnitFeeTransaction)(computeUnits, microLamportsPrioritizationFee * priorityFeeMultiplier); txn.add(...priorityFeeIxn); } txn.add(...ixs); if (mode === "simulate") { yield (0, Farms_1.printSimulateTx)(env.provider.connection, txn); } else if (mode === "multisig") { yield (0, Farms_1.printMultisigTx)(txn); } else if (mode === "execute") { console.log("Sending."); const sig = yield (0, utils_2.retryAsync)(() => __awaiter(this, void 0, void 0, function* () { return (0, utils_2.noopProfiledFunctionExecution)(sendAndConfirmTxn(env, new web3_js_1.VersionedTransaction(txn.compileMessage()), signers)); })); console.log("Signature", sig); } } mode !== "multisig" && ixs.length > 0 && console.log("-".repeat(150)); }); } function sendAndConfirmTxn(env, txn, signers) { return __awaiter(this, void 0, void 0, function* () { const sig = yield (0, utils_2.signSendAndConfirmRawTransactionWithRetry)({ mainConnection: env.web3Client.sendConnection, extraConnections: env.web3Client.sendConnectionsExtra, tx: txn, signers, commitment: "confirmed", sendTransactionOptions: { maxRetries: 5, preflightCommitment: "confirmed", }, }); return sig; }); } function validateStakingTokenMint(farmConfig, farmState) { if (!farmState.token.mint.equals(farmConfig.stakingTokenMint)) { throw ("Staking token mint mismatch Config: " + farmConfig.stakingTokenMint.toString() + " FarmState: " + farmState.token.mint.toString()); } } function setDepositCapIxIfNecessary(payer, farmsClient, farmConfig, farmState, mode) { return __awaiter(this, void 0, void 0, function* () { let depositCapAmountIx = yield farmsClient.updateFarmConfigIx(payer, farmConfig.farmPubkey, web3_js_1.PublicKey.default, types_1.FarmConfigOption.fromDecoded({ [types_1.FarmConfigOption.DepositCapAmount.kind]: "", }), farmConfig.depositCapAmount, 0); const currentDepositCapAmount = new decimal_js_1.default(farmState.depositCapAmount.toString()).toNumber(); if (currentDepositCapAmount != farmConfig.depositCapAmount) { const valueStringBefore = "depositCapAmount before".padEnd(40) + ": " + currentDepositCapAmount; const valueStringAfter = "depositCapAmount after".padEnd(40) + ": " + farmConfig.depositCapAmount; printDiff(mode, valueStringBefore, valueStringAfter, farmConfig.farmPubkey.toString()); return [depositCapAmountIx]; } return []; }); } function setLockingModeIxIfNecessary(payer, farmsClient, farmConfig, farmState, mode) { return __awaiter(this, void 0, void 0, function* () { let setLockingModeIx = yield farmsClient.updateFarmConfigIx(payer, farmConfig.farmPubkey, web3_js_1.PublicKey.default, types_1.FarmConfigOption.fromDecoded({ [types_1.FarmConfigOption.LockingMode.kind]: "", }), farmConfig.lockingMode, 0); const currentLockingMode = new decimal_js_1.default(farmState.lockingMode.toString()).toNumber(); if (currentLockingMode != farmConfig.lockingMode) { const valueStringBefore = "lockingMode before".padEnd(40) + ": " + currentLockingMode; const valueStringAfter = "lockingMode after".padEnd(40) + ": " + farmConfig.lockingMode; printDiff(mode, valueStringBefore, valueStringAfter, farmConfig.farmPubkey.toString()); return [setLockingModeIx]; } return []; }); } function setLockingStartIxIfNecessary(payer, farmsClient, farmConfig, farmState, mode) { return __awaiter(this, void 0, void 0, function* () { let setLockingStart = yield farmsClient.updateFarmConfigIx(payer, farmConfig.farmPubkey, web3_js_1.PublicKey.default, types_1.FarmConfigOption.fromDecoded({ [types_1.FarmConfigOption.LockingStartTimestamp.kind]: "", }), farmConfig.lockingStart, 0); const currentLockingStartTimestamp = new decimal_js_1.default(farmState.lockingStartTimestamp.toString()).toNumber(); if (currentLockingStartTimestamp != farmConfig.lockingStart) { const valueStringBefore = "lockingStartTimestamp before".padEnd(40) + ": " + currentLockingStartTimestamp; const valueStringAfter = "lockingStartTimestamp after".padEnd(40) + ": " + farmConfig.lockingStart; printDiff(mode, valueStringBefore, valueStringAfter, farmConfig.farmPubkey.toString()); return [setLockingStart]; } return []; }); } function setLockingDurationIxIfNecessary(payer, farmsClient, farmConfig, farmState, mode) { return __awaiter(this, void 0, void 0, function* () { let setLockingDuration = yield farmsClient.updateFarmConfigIx(payer, farmConfig.farmPubkey, web3_js_1.PublicKey.default, types_1.FarmConfigOption.fromDecoded({ [types_1.FarmConfigOption.LockingDuration.kind]: "", }), farmConfig.lockingDuration, 0); const currentLockingDuration = new decimal_js_1.default(farmState.lockingDuration.toString()).toNumber(); if (currentLockingDuration != farmConfig.lockingDuration) { const valueStringBefore = "lockingDuration before".padEnd(40) + ": " + currentLockingDuration; const valueStringAfter = "lockingDuration after".padEnd(40) + ": " + farmConfig.lockingDuration; printDiff(mode, valueStringBefore, valueStringAfter, farmConfig.farmPubkey.toString()); return [setLockingDuration]; } return []; }); } function setLockingEarlyWithdrawalPenaltyIxIfNecessary(payer, farmsClient, farmConfig, farmState, mode) { return __awaiter(this, void 0, void 0, function* () { let setLockingEarlyWithdrawalPenalty = yield farmsClient.updateFarmConfigIx(payer, farmConfig.farmPubkey, web3_js_1.PublicKey.default, types_1.FarmConfigOption.fromDecoded({ [types_1.FarmConfigOption.LockingEarlyWithdrawalPenaltyBps.kind]: "", }), farmConfig.lockingEarlyWithdrawalPenaltyBps, 0); const currentLockingEarlyWithdrawalPenalty = new decimal_js_1.default(farmState.lockingEarlyWithdrawalPenaltyBps.toString()).toNumber(); if (currentLockingEarlyWithdrawalPenalty != farmConfig.lockingEarlyWithdrawalPenaltyBps) { const valueStringBefore = "lockingEarlyWithdrawalPenaltyBps before".padEnd(40) + ": " + currentLockingEarlyWithdrawalPenalty; const valueStringAfter = "lockingEarlyWithdrawalPenaltyBps after".padEnd(40) + ": " + farmConfig.lockingEarlyWithdrawalPenaltyBps; printDiff(mode, valueStringBefore, valueStringAfter, farmConfig.farmPubkey.toString()); return [setLockingEarlyWithdrawalPenalty]; } return []; }); } function setStrategyIdIfNecessary(payer, farmsClient, farmConfig, farmState, mode) { return __awaiter(this, void 0, void 0, function* () { let setStrategyId = yield farmsClient.updateFarmConfigIx(payer, farmConfig.farmPubkey, web3_js_1.PublicKey.default, types_1.FarmConfigOption.fromDecoded({ [types_1.FarmConfigOption.UpdateStrategyId.kind]: "", }), farmConfig.strategyId, 0); if (!farmState.strategyId.equals(farmConfig.strategyId)) { const valueStringBefore = "strategyId before".padEnd(40) + ": " + farmState.strategyId.toString(); const valueStringAfter = "strategyId after".padEnd(40) + ": " + farmConfig.strategyId.toString(); printDiff(mode, valueStringBefore, valueStringAfter, farmConfig.farmPubkey.toString()); return [setStrategyId]; } return []; }); } function setWithdrawAuthorityIfNecessary(payer, farmsClient, farmConfig, farmState, mode) { return __awaiter(this, void 0, void 0, function* () { let setWithdrawAuthority = yield farmsClient.updateFarmConfigIx(payer, farmConfig.farmPubkey, web3_js_1.PublicKey.default, types_1.FarmConfigOption.fromDecoded({ [types_1.FarmConfigOption.WithdrawAuthority.kind]: "", }), farmConfig.withdrawAuthority, 0); if (!farmState.withdrawAuthority.equals(farmConfig.withdrawAuthority)) { const valueStringBefore = "withdrawAuthority before".padEnd(40) + ": " + farmState.withdrawAuthority.toString(); const valueStringAfter = "withdrawAuthority after".padEnd(40) + ": " + farmConfig.withdrawAuthority.toString(); printDiff(mode, valueStringBefore, valueStringAfter, farmConfig.farmPubkey.toString()); return [setWithdrawAuthority]; } return []; }); } function setSlashedAmountSpillAddressIfNecessary(payer, farmsClient, farmConfig, farmState, mode) { return __awaiter(this, void 0, void 0, function* () { let setSlashedAmountSpillAddress = yield farmsClient.updateFarmConfigIx(payer, farmConfig.farmPubkey, web3_js_1.PublicKey.default, types_1.FarmConfigOption.fromDecoded({ [types_1.FarmConfigOption.SlashedAmountSpillAddress.kind]: "", }), farmConfig.slashedAmountSpillAddress, 0); if (!farmState.slashedAmountSpillAddress.equals(farmConfig.slashedAmountSpillAddress)) { const valueStringBefore = "slashedAmountSpillAddress before".padEnd(40) + ": " + farmState.slashedAmountSpillAddress.toString(); const valueStringAfter = "slashedAmountSpillAddress after".padEnd(40) + ": " + farmConfig.slashedAmountSpillAddress.toString(); printDiff(mode, valueStringBefore, valueStringAfter, farmConfig.farmPubkey.toString()); return [setSlashedAmountSpillAddress]; } return []; }); } function setScopePricesAccountIfNecessary(payer, farmsClient, farmConfig, farmState, mode) { return __awaiter(this, void 0, void 0, function* () { let setScopePricesAccount = yield farmsClient.updateFarmConfigIx(payer, farmConfig.farmPubkey, web3_js_1.PublicKey.default, types_1.FarmConfigOption.fromDecoded({ [types_1.FarmConfigOption.ScopePricesAccount.kind]: "", }), farmConfig.scopePrices, 0); if (!farmState.scopePrices.equals(farmConfig.scopePrices)) { const valueStringBefore = "scopePrices before".padEnd(40) + ": " + farmState.scopePrices.toString(); const valueStringAfter = "scopePrices after".padEnd(40) + ": " + farmConfig.scopePrices.toString(); printDiff(mode, valueStringBefore, valueStringAfter, farmConfig.farmPubkey.toString()); return [setScopePricesAccount]; } return []; }); } function setPendingFarmAdminIfNecessary(payer, farmsClient, farmConfig, farmState, mode) { return __awaiter(this, void 0, void 0, function* () { let setPendingFarmAdmin = yield farmsClient.updateFarmConfigIx(payer, farmConfig.farmPubkey, web3_js_1.PublicKey.default, types_1.FarmConfigOption.fromDecoded({ [types_1.FarmConfigOption.UpdatePendingFarmAdmin.kind]: "", }), farmConfig.pendingFarmAdmin, 0); if (!farmState.pendingFarmAdmin.equals(farmConfig.pendingFarmAdmin)) { const valueStringBefore = "pendingFarmAdmin before".padEnd(40) + ": " + farmState.pendingFarmAdmin.toString(); const valueStringAfter = "pendingFarmAdmin after".padEnd(40) + ": " + farmConfig.pendingFarmAdmin.toString(); printDiff(mode, valueStringBefore, valueStringAfter, farmConfig.farmPubkey.toString()); return [setPendingFarmAdmin]; } return []; }); } function setScopeOraclePriceIdIxIfNecessary(payer, farmsClient, farmConfig, farmState, mode) { return __awaiter(this, void 0, void 0, function* () { const currentScopeOraclePriceId = new decimal_js_1.default(farmState.scopeOraclePriceId.toString()).toNumber(); if (currentScopeOraclePriceId != new decimal_js_1.default(farmConfig.scopePriceOracleId).toNumber()) { const valueStringBefore = "scopeOraclePriceId before".padEnd(40) + ": " + farmState.scopeOraclePriceId; const valueStringAfter = "scopeOraclePriceId after".padEnd(40) + ": " + farmConfig.scopePriceOracleId; printDiff(mode, valueStringBefore, valueStringAfter, farmConfig.farmPubkey.toString()); let setScopeOraclePriceId = yield farmsClient.updateFarmConfigIx(payer, farmConfig.farmPubkey, web3_js_1.PublicKey.default, types_1.FarmConfigOption.fromDecoded({ [types_1.FarmConfigOption.ScopeOraclePriceId.kind]: "", }), new decimal_js_1.default(farmConfig.scopePriceOracleId).toNumber(), 0); return [setScopeOraclePriceId]; } return []; }); } function setScopeOracleMaxAgeIxIfNecessary(payer, farmsClient, farmConfig, farmState, mode) { return __awaiter(this, void 0, void 0, function* () { let setScopeOracleMaxAge = yield farmsClient.updateFarmConfigIx(payer, farmConfig.farmPubkey, web3_js_1.PublicKey.default, types_1.FarmConfigOption.fromDecoded({ [types_1.FarmConfigOption.ScopeOracleMaxAge.kind]: "", }), farmConfig.scopeOracleMaxAge, 0); const currentScopeOracleMaxAge = new decimal_js_1.default(farmState.scopeOracleMaxAge.toString()).toNumber(); if (currentScopeOracleMaxAge != farmConfig.scopeOracleMaxAge) { const valueStringBefore = "scopeOracleMaxAge before".padEnd(40) + ": " + currentScopeOracleMaxAge; const valueStringAfter = "scopeOracleMaxAge after".padEnd(40) + ": " + farmConfig.lockingDuration; printDiff(mode, valueStringBefore, valueStringAfter, farmConfig.farmPubkey.toString()); return [setScopeOracleMaxAge]; } return []; }); } function setDepositWarmupPeriodIfNecessary(payer, farmsClient, farmConfig, farmState, mode) { return __awaiter(this, void 0, void 0, function* () { let setDepositWarmupPeriodIx = yield farmsClient.updateFarmConfigIx(payer, farmConfig.farmPubkey, web3_js_1.PublicKey.default, types_1.FarmConfigOption.fromDecoded({ [types_1.FarmConfigOption.DepositWarmupPeriod.kind]: "", }), farmConfig.depositWarmupPeriod, 0); const currentDepositWarmupPeriod = new decimal_js_1.default(farmState.depositWarmupPeriod.toString()).toNumber(); if (currentDepositWarmupPeriod != farmConfig.depositWarmupPeriod) { const valueStringBefore = "depositWarmupPeriod before".padEnd(40) + ": " + currentDepositWarmupPeriod; const valueStringAfter = "depositWarmupPeriod after".padEnd(40) + ": " + farmConfig.depositWarmupPeriod; printDiff(mode, valueStringBefore, valueStringAfter, farmConfig.farmPubkey.toString()); return [setDepositWarmupPeriodIx]; } return []; }); } function setWithdrawCooldownPeriodIfNecessary(payer, farmsClient, farmConfig, farmState, mode) { return __awaiter(this, void 0, void 0, function* () { let setWithdrawCooldownPeriodIx = yield farmsClient.updateFarmConfigIx(payer, farmConfig.farmPubkey, web3_js_1.PublicKey.default, types_1.FarmConfigOption.fromDecoded({ [types_1.FarmConfigOption.WithdrawCooldownPeriod.kind]: "", }), farmConfig.withdrawCooldownPeriod, 0); const currentWithdrawCooldownPeriod = new decimal_js_1.default(farmState.withdrawalCooldownPeriod.toString()).toNumber(); if (currentWithdrawCooldownPeriod != farmConfig.depositWarmupPeriod) { const valueStringBefore = "withdrawalCooldownPeriod before".padEnd(40) + ": " + currentWithdrawCooldownPeriod; const valueStringAfter = "withdrawalCooldownPeriod after".padEnd(40) + ": " + farmConfig.withdrawCooldownPeriod; printDiff(mode, valueStringBefore, valueStringAfter, farmConfig.farmPubkey.toString()); return [setWithdrawCooldownPeriodIx]; } return []; }); } function initRewardIfNecessary(payer, farmsClient, farmConfig, farmState, rewardIndex, mode) { return __awaiter(this, void 0, void 0, function* () { var _a, _b, _c; if (!farmState.rewardInfos[rewardIndex].token.mint.equals(web3_js_1.PublicKey.default) && !((_a = farmConfig.rewards[rewardIndex]) === null || _a === void 0 ? void 0 : _a.rewardTokenMint.equals(farmState.rewardInfos[rewardIndex].token.mint))) { throw new Error("Reward token mint already initialized and does not match config"); } if (!((_b = farmConfig.rewards[rewardIndex]) === null || _b === void 0 ? void 0 : _b.rewardTokenMint.equals(farmState.rewardInfos[rewardIndex].token.mint))) { const rewardMint = (_c = farmConfig.rewards[rewardIndex]) === null || _c === void 0 ? void 0 : _c.rewardTokenMint; const tokenProgram = (yield farmsClient .getConnection() .getAccountInfo(rewardMint)).owner; const initRewardIx = yield farmsClient.addRewardToFarmIx(payer, farmState.globalConfig, farmConfig.farmPubkey, rewardMint, tokenProgram); mode !== "multisig" && console.log("Change for farm: ", cli_color_1.default.yellow(farmConfig.farmPubkey.toString().padEnd(50))); mode !== "multisig" && console.log(cli_color_1.default.green("initialize new reward with mint".padEnd(40) + ": "), cli_color_1.default.yellow(rewardMint.toString()), "\n"); return [initRewardIx]; } return []; }); } function setRpsDecimalsIxIfNecessary(payer, farmsClient, farmConfig, farmState, rewardIndex, mode) { return __awaiter(this, void 0, void 0, function* () { var _a, _b, _c, _d, _e, _f; let setRpsDecimals = yield farmsClient.updateFarmConfigIx(payer, farmConfig.farmPubkey, (_a = farmConfig.rewards[rewardIndex]) === null || _a === void 0 ? void 0 : _a.rewardTokenMint, types_1.FarmConfigOption.fromDecoded({ [types_1.FarmConfigOption.RpsDecimals.kind]: "", }), (_b = farmConfig.rewards[rewardIndex]) === null || _b === void 0 ? void 0 : _b.rewardPerSecondDecimals, rewardIndex); const currentRpsDecimals = new decimal_js_1.default((_c = farmState.rewardInfos[rewardIndex]) === null || _c === void 0 ? void 0 : _c.rewardsPerSecondDecimals.toString()).toNumber(); if (currentRpsDecimals != ((_d = farmConfig.rewards[rewardIndex]) === null || _d === void 0 ? void 0 : _d.rewardPerSecondDecimals)) { const valueStringBefore = "rpsDecimals before".padEnd(40) + ": " + currentRpsDecimals; const valueStringAfter = "rpsDecimals after".padEnd(40) + ": " + ((_e = farmConfig.rewards[rewardIndex]) === null || _e === void 0 ? void 0 : _e.rewardPerSecondDecimals); printDiff(mode, valueStringBefore, valueStringAfter, farmConfig.farmPubkey.toString(), rewardIndex, (_f = farmConfig.rewards[rewardIndex]) === null || _f === void 0 ? void 0 : _f.rewardTokenMint.toString()); return [setRpsDecimals]; } return []; }); } function setRewardTypeIxIfNecessary(payer, farmsClient, farmConfig, farmState, rewardIndex, mode) { return __awaiter(this, void 0, void 0, function* () { var _a, _b, _c, _d, _e, _f, _g; let configRewardType = 0; if (((_a = farmConfig.rewards[rewardIndex]) === null || _a === void 0 ? void 0 : _a.rewardType) === "Proportional") { configRewardType = 0; } else if (((_b = farmConfig.rewards[rewardIndex]) === null || _b === void 0 ? void 0 : _b.rewardType) === "Constant") { configRewardType = 1; } else { throw new Error(`Reward type invalid for farm ${farmConfig.farmPubkey.toString()}`); } let setRewardType = yield farmsClient.updateFarmConfigIx(payer, farmConfig.farmPubkey, (_c = farmConfig.rewards[rewardIndex]) === null || _c === void 0 ? void 0 : _c.rewardTokenMint, types_1.FarmConfigOption.fromDecoded({ [types_1.FarmConfigOption.RewardType.kind]: "", }), configRewardType, rewardIndex); const currentRewardTypeString = ((_d = farmState.rewardInfos[rewardIndex]) === null || _d === void 0 ? void 0 : _d.rewardType) === 0 ? "Proportional" : "Constant"; if (((_e = farmState.rewardInfos[rewardIndex]) === null || _e === void 0 ? void 0 : _e.rewardType) != configRewardType) { const valueStringBefore = "rewardType before".padEnd(40) + ": " + currentRewardTypeString; const valueStringAfter = "rewardType after".padEnd(40) + ": " + ((_f = farmConfig.rewards[rewardIndex]) === null || _f === void 0 ? void 0 : _f.rewardType); printDiff(mode, valueStringBefore, valueStringAfter, farmConfig.farmPubkey.toString(), rewardIndex, (_g = farmConfig.rewards[rewardIndex]) === null || _g === void 0 ? void 0 : _g.rewardTokenMint.toString()); return [setRewardType]; } return []; }); } function setRewardMinClaimDurationIxIfNecessary(payer, farmsClient, farmConfig, farmState, rewardIndex, mode) { return __awaiter(this, void 0, void 0, function* () { var _a, _b, _c, _d, _e, _f; let setRewardMinClaimDuration = yield farmsClient.updateFarmConfigIx(payer, farmConfig.farmPubkey, (_a = farmConfig.rewards[rewardIndex]) === null || _a === void 0 ? void 0 : _a.rewardTokenMint, types_1.FarmConfigOption.fromDecoded({ [types_1.FarmConfigOption.UpdateRewardMinClaimDuration.kind]: "", }), (_b = farmConfig.rewards[rewardIndex]) === null || _b === void 0 ? void 0 : _b.minClaimDurationSeconds, rewardIndex); const currentMinClaimDurationSeconds = new decimal_js_1.default((_c = farmState.rewardInfos[rewardIndex]) === null || _c === void 0 ? void 0 : _c.minClaimDurationSeconds.toString()).toNumber(); if (currentMinClaimDurationSeconds != ((_d = farmConfig.rewards[rewardIndex]) === null || _d === void 0 ? void 0 : _d.minClaimDurationSeconds)) { const valueStringBefore = "minClaimDurationSeconds before".padEnd(40) + ": " + currentMinClaimDurationSeconds; const valueStringAfter = "minClaimDurationSeconds after".padEnd(40) + ": " + ((_e = farmConfig.rewards[rewardIndex]) === null || _e === void 0 ? void 0 : _e.minClaimDurationSeconds); printDiff(mode, valueStringBefore, valueStringAfter, farmConfig.farmPubkey.toString(), rewardIndex, (_f = farmConfig.rewards[rewardIndex]) === null || _f === void 0 ? void 0 : _f.rewardTokenMint.toString()); return [setRewardMinClaimDuration]; } return []; }); } function getCurrentRewardInfo(farmState, rewardIndex) { var _a, _b; let rpsDecimalsCurrent = (_a = farmState === null || farmState === void 0 ? void 0 : farmState.rewardInfos[rewardIndex].rewardsPerSecondDecimals) !== null && _a !== void 0 ? _a : 0; let rewardsAvailableLamports = 0; if (farmState) { let rewardInfo = farmState.rewardInfos[rewardIndex]; rewardsAvailableLamports = new decimal_js_1.default(rewardInfo.rewardsAvailable.toString()).toNumber(); } let rpsCurrent = (_b = farmState === null || farmState === void 0 ? void 0 : farmState.rewardInfos[rewardIndex].rewardScheduleCurve.points[0].rewardPerTimeUnit.toNumber()) !== null && _b !== void 0 ? _b : 0; return { rpsDecimalsCurrent, rewardsAvailableLamports, rpsCurrent, }; } function getConfigRewardRps(farmState, farmConfig, rewardIndex) { var _a, _b, _c, _d; const rewardCurve = []; (_a = farmConfig.rewards[rewardIndex]) === null || _a === void 0 ? void 0 : _a.rewardCurve.forEach((point) => { rewardCurve.push({ startTs: point.startTs, rps: point.rps, }); }); const rewardToTopUpDurationSeconds = ((_b = farmConfig.rewards[rewardIndex]) === null || _b === void 0 ? void 0 : _b.rewardToTopUpDurationDays) ? ((_c = farmConfig.rewards[rewardIndex]) === null || _c === void 0 ? void 0 : _c.rewardToTopUpDurationDays) * 24 * 60 * 60 : 0; const rewardPerSecond = rewardToTopUpDurationSeconds == 0 ? -1 : Math.round((((_d = farmConfig.rewards[rewardIndex]) === null || _d === void 0 ? void 0 : _d.rewardToTopUp) / rewardToTopUpDurationSeconds) * Math.pow(10, new decimal_js_1.default(farmState.rewardInfos[rewardIndex].token.decimals.toString()).toNumber())); if (rewardCurve.length == 1 && rewardPerSecond != -1) { rewardCurve[0].rps = Number(rewardPerSecond.toFixed(0)); } return { rewardCurve, rewardPerSecond, }; } function setRewardPerSecondIfNecessary(payer, farmsClient, farmState, farmConfig, rewardPerSecond, rewardIndex, rewardDecimals, mode) { return __awaiter(this, void 0, void 0, function* () { var _a, _b, _c, _d, _e; const { rewardsAvailableLamports } = getCurrentRewardInfo(farmState, rewardIndex); const rpsCurrent = (_a = farmState === null || farmState === void 0 ? void 0 : farmState.rewardInfos[rewardIndex].rewardScheduleCurve.points[0].rewardPerTimeUnit.toNumber()) !== null && _a !== void 0 ? _a : 0; if (rpsCurrent != rewardPerSecond && rewardPerSecond != -1) { const valueStringBefore = "rewardPerSecond before".padEnd(40) + ": " + rpsCurrent; const valueStringAfter = "rewardPerSecond after".padEnd(40) + ": " + Math.round(rewardPerSecond); printDiff(mode, valueStringBefore, valueStringAfter, farmConfig.farmPubkey.toString(), rewardIndex, (_b = farmConfig.rewards[rewardIndex]) === null || _b === void 0 ? void 0 : _b.rewardTokenMint.toString()); const rpsDecimalsCurrent = farmConfig.rewards[rewardIndex].rewardPerSecondDecimals; if (rewardPerSecond) { estimateRewardDuration(rewardDecimals, (_c = farmConfig.rewards[rewardIndex]) === null || _c === void 0 ? void 0 : _c.rewardToTopUp, rewardsAvailableLamports, rpsCurrent / Math.pow(10, rpsCurrent), rewardPerSecond / Math.pow(10, ((_d = farmConfig.rewards[rewardIndex]) === null || _d === void 0 ? void 0 : _d.rewardPerSecondDecimals)), rpsDecimalsCurrent, mode); } let setRewardPerSecond = yield farmsClient.updateFarmConfigIx(payer, farmConfig.farmPubkey, (_e = farmConfig.rewards[rewardIndex]) === null || _e === void 0 ? void 0 : _e.rewardTokenMint, types_1.FarmConfigOption.fromDecoded({ [types_1.FarmConfigOption.UpdateRewardRps.kind]: "", }), rewardPerSecond, rewardIndex); return [setRewardPerSecond]; } return []; }); } function setRewardCurveIfNecessary(env, payer, farmsClient, farmState, farmConfig, rewardCurve, rewardIndex, rewardDecimals, slot, mode) { return __awaiter(this, void 0, void 0, function* () { var _a, _b, _c; const { rewardsAvailableLamports } = getCurrentRewardInfo(farmState, rewardIndex); const { currentRewardCurve, ts } = yield getCurrentRewardCurveAndTs(env, farmState, rewardIndex, slot); let setRewardCurvePoint = yield farmsClient.updateFarmConfigIx(payer, farmConfig.farmPubkey, (_a = farmConfig.rewards[rewardIndex]) === null || _a === void 0 ? void 0 : _a.rewardTokenMint, types_1.FarmConfigOption.fromDecoded({ [types_1.FarmConfigOption.UpdateRewardScheduleCurvePoints.kind]: "", }), rewardCurve, rewardIndex); let newCurve = false; if (rewardCurve.length > currentRewardCurve.length) { newCurve = true; } for (let i = 0; i < Math.min(rewardCurve.length, currentRewardCurve.length); i++) { if ((currentRewardCurve[i].startTs != rewardCurve[i].startTs || currentRewardCurve[i].rps != rewardCurve[i].rps) && !(rewardCurve[i].startTs == 0 && currentRewardCurve[i].startTs == Number(klend_sdk_1.U64_MAX))) { newCurve = true; break; } } if (newCurve) { const valueStringBefore = "rewardCurve before".padEnd(40) + ": " + JSON.stringify(currentRewardCurve); const valueStringAfter = "rewardCurve after".padEnd(40) + ": " + JSON.stringify(rewardCurve); printDiff(mode, valueStringBefore, valueStringAfter, farmConfig.farmPubkey.toString(), rewardIndex, (_b = farmConfig.rewards[rewardIndex]) === null || _b === void 0 ? void 0 : _b.rewardTokenMint.toString()); const rpsDecimalsCurrent = farmConfig.rewards[rewardIndex].rewardPerSecondDecimals; estimateRewardDurationRewardCurve(rewardDecimals, (_c = farmConfig.rewards[rewardIndex]) === null || _c === void 0 ? void 0 : _c.rewardToTopUp, rewardsAvailableLamports, currentRewardCurve, rewardCurve, rpsDecimalsCurrent, ts, mode); return [setRewardCurvePoint]; } return []; }); } function topupRewardAmountNecessary(env, payer, farmsClient, farmState, farmConfig, rewardIndex, rewardDecimals, tokenProgram, slot, topUpOnly, mode) { return __awaiter(this, void 0, void 0, function* () { var _a, _b, _c, _d, _e, _f; if (((_a = farmConfig.rewards[rewardIndex]) === null || _a === void 0 ? void 0 : _a.rewardToTopUp) > 0) { let topupIx = yield farmsClient.addRewardAmountToFarmIx(payer, farmConfig.farmPubkey, (_b = farmConfig.rewards[rewardIndex]) === null || _b === void 0 ? void 0 : _b.rewardTokenMint, new decimal_js_1.default((_c = farmConfig.rewards[rewardIndex]) === null || _c === void 0 ? void 0 : _c.rewardToTopUp), rewardIndex, rewardDecimals, tokenProgram, farmConfig.scopePrices.equals(web3_js_1.PublicKey.default) ? undefined : farmConfig.scopePrices); const rewardIndexString = rewardIndex == -1 ? "" : " - rewardIndex[" + rewardIndex + "] : " + ((_d = farmConfig.rewards[rewardIndex]) === null || _d === void 0 ? void 0 : _d.rewardTokenMint.toString()); const valueStringAfter = "reward to top up".padEnd(40) + ": " + ((_e = farmConfig.rewards[rewardIndex]) === null || _e === void 0 ? void 0 : _e.rewardToTopUp); mode !== "multisig" && console.log("Change for farm: ", cli_color_1.default.yellow(farmConfig.farmPubkey.toString().concat(rewardIndexString).padEnd(65))); mode !== "multisig" && console.log(cli_color_1.default.green(valueStringAfter), "\n"); if (topUpOnly) { const { rewardsAvailableLamports } = getCurrentRewardInfo(farmState, rewardIndex); const { currentRewardCurve, ts } = yield getCurrentRewardCurveAndTs(env, farmState, rewardIndex, slot); const rpsDecimalsCurrent = farmConfig.rewards[rewardIndex].rewardPerSecondDecimals; estimateRewardDurationRewardCurve(rewardDecimals, (_f = farmConfig.rewards[rewardIndex]) === null || _f === void 0 ? void 0 : _f.rewardToTopUp, rewardsAvailableLamports, currentRewardCurve, currentRewardCurve, rpsDecimalsCurrent, ts, mode); } return [topupIx]; } return []; }); } function estimateRewardDurationRewardCurve(rewardDecimals, rewardToTopUp, remainingLamports, rewardCurveCurrent, newRewardCurve, rpsDecimalsCurrent, ts, mode) { const rewardFactor = Math.pow(10, rewardDecimals); /// Rewards available const newLamports = remainingLamports + rewardToTopUp * rewardFactor; // If we change the number of lamports available const numDaysBalanceRemaining = calculateDaysBalanceRemaining(remainingLamports, rewardCurveCurrent, rpsDecimalsCurrent, ts); const numDaysTopupRemaining = calculateDaysBalanceRemaining(newLamports, rewardCurveCurrent, rpsDecimalsCurrent, ts); mode !== "multisig" && console.log("Days with current balance:", numDaysBalanceRemaining); mode !== "multisig" && console.log("Days with new balance:", numDaysTopupRemaining); // If we change the number of rps const daysWithNewRps = calculateDaysBalanceRemaining(remainingLamports, newRewardCurve, rpsDecimalsCurrent, ts); const daysWithNewRpsAndTopup = calculateDaysBalanceRemaining(newLamports, newRewardCurve, rpsDecimalsCurrent, ts); mode !== "multisig" && console.log("Days with current balance and new reward curve", daysWithNewRps); mode !== "multisig" && console.log("Days with new balance and new reward curve", daysWithNewRpsAndTopup, "\n"); return { remainingLamports, rewardFactor, }; } function calculateDaysBalanceRemaining(lamports, rewardCurve, rpsDecimalsCurrent, ts) { let numDays = 0; let remainingLamports = lamports; for (const [index, _curvePoint] of rewardCurve.entries()) { const rps = rewardCurve[index].rps / Math.pow(10, rpsDecimalsCurrent); if (index == rewardCurve.length - 1) { return remainingLamports / rps / 86400; } if (remainingLamports > 0) { if (ts > rewardCurve[index].startTs && ts < rewardCurve[index + 1].startTs) { const secondsWithCurrentRps = remainingLamports / rps; if (ts + secondsWithCurrentRps <= rewardCurve[index + 1].startTs) { numDays += secondsWithCurrentRps / 86400; return numDays; // all remaining lamports elapsed } else { const actualSecondsAtCurrentRps = rewardCurve[index + 1].startTs - ts; numDays += actualSecondsAtCurrentRps / 86400; remainingLamports -= actualSecondsAtCurrentRps * rps; } } } } return numDays; } function parseFarmConfigFromFile(farmConfigFromFile) { const farmConfig = { farmMetadata: { type: farmConfigFromFile.farmMetadata.type, reserve: farmConfigFromFile.reserve ? new web3_js_1.PublicKey(farmConfigFromFile.reserve) : undefined, market: farmConfigFromFile.market ? new web3_js_1.PublicKey(farmConfigFromFile.market) : undefined, strategy: farmConfigFromFile.strategy ? new web3_js_1.PublicKey(farmConfigFromFile.strategy) : undefined, }, farmPubkey: new web3_js_1.PublicKey(farmConfigFromFile.farmPubkey), stakingTokenMint: new web3_js_1.PublicKey(farmConfigFromFile.stakingTokenMint), withdrawAuthority: new web3_js_1.PublicKey(farmConfigFromFile.withdrawAuthority), globalConfig: new web3_js_1.PublicKey(farmConfigFromFile.globalConfig), strategyId: new web3_js_1.PublicKey(farmConfigFromFile.strategyId), depositCapAmount: farmConfigFromFile.depositCapAmount, rewards: farmConfigFromFile.rewards.map((reward) => { return { rewardTokenMint: new web3_js_1.PublicKey(reward.rewardTokenMint), rewardType: reward.rewardType, rewardPerSecondDecimals: reward.rewardPerSecondDecimals, minClaimDurationSeconds: reward.minClaimDurationSeconds, rewardCurve: reward.rewardCurve, rewardAvailable: reward.rewardAvailable, rewardToTopUp: reward.rewardToTopUp, rewardToTopUpDurationDays: reward.rewardToTopUpDurationDays, }; }), pendingFarmAdmin: new web3_js_1.PublicKey(farmConfigFromFile.pendingFarmAdmin), scopePrices: new web3_js_1.PublicKey(farmConfigFromFile.scopePrices), scopePriceOracleId: farmConfigFromFile.scopePriceOracleId, scopeOracleMaxAge: farmConfigFromFile.scopeOracleMaxAge, lockingMode: farmConfigFromFile.lockingMode, lockingStart: farmConfigFromFile.lockingStart, lockingDuration: farmConfigFromFile.lockingDuration, lockingEarlyWithdrawalPenaltyBps: farmConfigFromFile.lockingEarlyWithdrawalPenaltyBps, depositWarmupPeriod: farmConfigFromFile.depositWarmupPeriod, withdrawCooldownPeriod: farmConfigFromFile.withdrawCooldownPeriod, slashedAmountSpillAddress: new web3_js_1.PublicKey(farmConfigFromFile.slashedAmountSpillAddress), }; return farmConfig; } function recursiveReadDirectoryOfConfigs(targetPath) { const farmConfigs = []; fs_1.default.readdirSync(targetPath, { withFileTypes: true }).forEach((file) => { if (file.isDirectory()) { farmConfigs.push(...recursiveReadDirectoryOfConfigs(targetPath + "/" + file.name)); } else { const farmConfigFromFile = JSON.parse(fs_1.default.readFileSync(targetPath + "/" + file.name, "utf8")); farmConfigs.push(parseFarmConfigFromFile(farmConfigFromFile)); } }); return farmConfigs; } function printDiff(mode, valueStringBefore, valueStringAfter, farmPubkeyString, rewardIndex = -1, rewardMint = "") { const rewardIndexString = rewardIndex == -1 ? "" : " - rewardIndex[" + rewardIndex + "] : " + rewardMint; mode !== "multisig" && console.log("Change for farm: ", cli_color_1.default.yellow(farmPubkeyString.concat(rewardIndexString).padEnd(65))); mode !== "multisig" && console.log(cli_color_1.default.red(valueStringBefore)); mode !== "multisig" && console.log(cli_color_1.default.green(valueStringAfter), "\n"); } function estimateRewardDuration(rewardDecimals, rewardToTopUp, remainingLamports, rpsCurrent, newRps, rpsDecimalsCurrent, mode) { rpsCurrent = rpsCurrent / Math.pow(10, rpsDecimalsCurrent); newRps = newRps / Math.pow(10, rpsDecimalsCurrent); const rewardFactor = Math.pow(10, rewardDecimals); /// Rewards available const newLamports = remainingLamports + rewardToTopUp * rewardFactor; // If we change the number of lamports available const numDaysBalanceRemaining = remainingLamports / rpsCurrent / 86400; const numDaysTopupRemaining = newLamports / rpsCurrent / 86400; mode !== "multisig" && console.log("Days with current balance:", numDaysBalanceRemaining); mode !== "multisig" && console.log("Days with new balance:", numDaysTopupRemaining); // If we change the number of rps const daysWithNewRps = remainingLamports / newRps / 86400; const daysWithNewRpsAndTopup = newLamports / newRps / 86400; mode !== "multisig" && console.log("Days with current balance and new rps", daysWithNewRps); mode !== "multisig" && console.log("Days with new balance and new rps", daysWithNewRpsAndTopup, "\n"); return { remainingLamports, rewardFactor, }; } function getCurrentRewardCurveAndTs(env, farmState, rewardIndex, slot) { return __awaiter(this, void 0, void 0, function* () { let currentRewardCurve = []; if (farmState) { for (const point of farmState.rewardInfos[rewardIndex].rewardScheduleCurve .points) { if (point.tsStart.toString() === klend_sdk_1.U64_MAX && new decimal_js_1.default(point.rewardPerTimeUnit.toString()).toNumber() === 0) { continue; } currentRewardCurve.push({ startTs: new decimal_js_1.default(point.tsStart.toString()).toNumber(), rps: new decimal_js_1.default(point.rewardPerTimeUnit.toString()).toNumber(), }); } } let ts = yield env.provider.connection.getBlockTime(slot); return { currentRewardCurve, ts: ts, }; }); } //# sourceMappingURL=upsert_all_farm_configs.js.map