@hubbleprotocol/farms-sdk
Version:
773 lines • 48 kB
JavaScript
"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