@hubbleprotocol/farms-sdk
Version:
913 lines • 81.8 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
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 __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); }
var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) {
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
var g = generator.apply(thisArg, _arguments || []), i, q = [];
return i = {}, verb("next"), verb("throw"), verb("return", awaitReturn), i[Symbol.asyncIterator] = function () { return this; }, i;
function awaitReturn(f) { return function (v) { return Promise.resolve(v).then(f, reject); }; }
function verb(n, f) { if (g[n]) { i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; if (f) i[n] = f(i[n]); } }
function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
function fulfill(value) { resume("next", value); }
function reject(value) { resume("throw", value); }
function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getAllBoosts = exports.calculatePointsPerDay = exports.calcAvgBoost = exports.Farms = exports.farmsId = void 0;
exports.getCurrentTimeUnit = getCurrentTimeUnit;
exports.getCurrentRps = getCurrentRps;
exports.printMultisigTx = printMultisigTx;
exports.printSimulateTx = printSimulateTx;
const anchor_1 = require("@coral-xyz/anchor");
const farms_json_1 = __importDefault(require("./rpc_client/farms.json"));
// @ts-ignore
const base58_js_1 = require("base58-js");
const web3_js_1 = require("@solana/web3.js");
const utils_1 = require("./utils");
const utils_2 = require("./utils");
const accounts_1 = require("./rpc_client/accounts");
const accounts_2 = require("./rpc_client/accounts");
const farmOperations = __importStar(require("./utils/operations"));
const decimal_js_1 = __importDefault(require("decimal.js"));
const web3_js_2 = require("@solana/web3.js");
const index_1 = require("./rpc_client/types/index");
const programId_1 = require("./rpc_client/programId");
const scope_sdk_1 = require("@hubbleprotocol/scope-sdk");
const arrayUtils_1 = require("./utils/arrayUtils");
const klend_sdk_1 = require("@kamino-finance/klend-sdk");
const types_1 = require("@kamino-finance/klend-sdk/dist/idl_codegen/types");
const utils_3 = require("./commands/utils");
const market_1 = require("@project-serum/serum/lib/market");
const sendTransactionsUtils_1 = require("./utils/sendTransactionsUtils");
const spl_token_1 = require("@solana/spl-token");
exports.farmsId = new web3_js_1.PublicKey("FarmsPZpWu9i7Kky8tPN37rs2TpmMrAZrC7S7vJa91Hr");
class Farms {
constructor(connection) {
this._connection = connection;
this._provider = new anchor_1.AnchorProvider(connection, (0, utils_1.getReadOnlyWallet)(), {
commitment: connection.commitment,
});
this._farmsProgramId = exports.farmsId;
this._farmsProgram = new anchor_1.Program(farms_json_1.default, this._farmsProgramId, this._provider);
}
getConnection() {
return this._connection;
}
getProgramID() {
return this._farmsProgramId;
}
getProgram() {
return this._farmsProgram;
}
getAllUserStatesForUser(user) {
return __awaiter(this, void 0, void 0, function* () {
let filters = [];
filters.push({
memcmp: {
bytes: user.toBase58(),
offset: 48,
},
});
filters.push({
dataSize: accounts_1.UserState.layout.span + 8,
});
const userStates = (yield this._farmsProgram.account.userState.all(filters)).map((x) => {
let res = {
userState: new accounts_1.UserState(x.account),
key: x.publicKey,
};
return res;
});
return userStates;
});
}
getAllUserStates() {
return __awaiter(this, void 0, void 0, function* () {
return (yield this._farmsProgram.account.userState.all([
{
dataSize: accounts_1.UserState.layout.span + 8,
},
])).map((x) => {
const userAndKey = {
userState: new accounts_1.UserState(x.account),
key: x.publicKey,
};
return userAndKey;
});
});
}
getAllUserStatesWithFilter(isFarmDelegated) {
return __awaiter(this, void 0, void 0, function* () {
return (yield this._farmsProgram.account.userState.all([
{
dataSize: accounts_1.UserState.layout.span + 8,
},
{
memcmp: { bytes: isFarmDelegated ? "2" : "1", offset: 80 },
},
])).map((x) => {
const userAndKey = {
userState: new accounts_1.UserState(x.account),
key: x.publicKey,
};
return userAndKey;
});
});
}
/**
* Get all farms user states from an async generator filled with batches of max 100 user states each
* @example
* const userStateGenerator = farms.batchGetAllUserStates();
* for await (const userStates of userStateGenerator) {
* console.log('got a batch of user states:', userStates.length);
* }
*/
batchGetAllUserStates() {
return __asyncGenerator(this, arguments, function* batchGetAllUserStates_1() {
const userStatePubkeys = yield __await(this._connection.getProgramAccounts(this._farmsProgramId, {
filters: [
{
dataSize: accounts_1.UserState.layout.span + 8,
},
],
dataSlice: {
offset: 0,
length: 0,
},
}));
for (const batch of (0, arrayUtils_1.chunks)(userStatePubkeys.map((x) => x.pubkey), 100)) {
const userStateAccounts = yield __await(this._connection.getMultipleAccountsInfo(batch));
const userStateBatch = [];
for (let i = 0; i < userStateAccounts.length; i++) {
const userState = userStateAccounts[i];
const pubkey = batch[i];
if (userState === null) {
continue;
}
const userStateAccount = accounts_1.UserState.decode(userState.data);
if (!userStateAccount) {
throw Error(`Could not decode user state account ${pubkey.toString()}`);
}
userStateBatch.push({ key: pubkey, userState: userStateAccount });
}
yield yield __await(userStateBatch);
}
});
}
getAllUserStatesForFarm(farm) {
return __awaiter(this, void 0, void 0, function* () {
return (yield this._farmsProgram.account.userState.all([
{
dataSize: accounts_1.UserState.layout.span + 8,
},
{
memcmp: {
offset: 8 + 8,
bytes: farm.toBase58(),
},
},
])).map((x) => {
const userAndKey = {
userState: new accounts_1.UserState(x.account),
key: x.publicKey,
};
return userAndKey;
});
});
}
getFarmsForMint(mint) {
return __awaiter(this, void 0, void 0, function* () {
let filters = [];
filters.push({
memcmp: {
bytes: mint.toBase58(),
offset: 72,
},
});
filters.push({
dataSize: accounts_2.FarmState.layout.span + 8,
});
const farms = (yield this._farmsProgram.account.farmState.all(filters)).map((x) => {
let res = {
farmState: new accounts_2.FarmState(x.account),
key: x.publicKey,
};
return res;
});
return farms;
});
}
getAllFarmStates() {
return __awaiter(this, void 0, void 0, function* () {
return (yield this._farmsProgram.account.farmState.all([
{
dataSize: accounts_2.FarmState.layout.span + 8,
},
])).map((x) => {
const farmAndKey = {
farmState: new accounts_2.FarmState(x.account),
key: x.publicKey,
};
return farmAndKey;
});
});
}
getAllFarmStatesByPubkeys(keys) {
return __awaiter(this, void 0, void 0, function* () {
const farmAndKeys = [];
const farmStates = yield this.fetchMultipleFarmStatesWithCheckedSize(keys);
farmStates.forEach((farmState, index) => {
if (farmState) {
farmAndKeys.push({
farmState: farmState,
key: keys[index],
});
}
});
return farmAndKeys;
});
}
getStakedAmountForMintForFarm(mint, farm) {
return __awaiter(this, void 0, void 0, function* () {
const farms = yield this.getFarmsForMint(mint);
for (let index = 0; index < farms.length; index++) {
if (farms[index].key.equals(farm)) {
return (0, utils_2.lamportsToCollDecimal)(new decimal_js_1.default((0, utils_2.scaleDownWads)(farms[index].farmState.totalActiveStakeScaled)), farms[index].farmState.token.decimals.toNumber());
}
}
throw Error("No Farm found");
});
}
getStakedAmountForMint(mint) {
return __awaiter(this, void 0, void 0, function* () {
const farms = yield this.getFarmsForMint(mint);
let totalStaked = new decimal_js_1.default(0);
for (let index = 0; index < farms.length; index++) {
totalStaked = totalStaked.add((0, utils_2.lamportsToCollDecimal)(new decimal_js_1.default(farms[index].farmState.totalStakedAmount.toString()), farms[index].farmState.token.decimals.toNumber()));
}
return totalStaked;
});
}
getLockupDurationAndExpiry(farm, user) {
return __awaiter(this, void 0, void 0, function* () {
let userStateAddress = (0, utils_2.getUserStatePDA)(this._farmsProgramId, farm, user);
let userState = yield accounts_1.UserState.fetch(this._connection, userStateAddress);
let farmState = yield accounts_2.FarmState.fetch(this._connection, farm);
if (!farmState) {
throw new Error("Error fetching farm state");
}
let lockingMode = farmState === null || farmState === void 0 ? void 0 : farmState.lockingMode.toNumber();
let lockingDuration = farmState === null || farmState === void 0 ? void 0 : farmState.lockingDuration.toNumber();
let penalty = farmState.lockingEarlyWithdrawalPenaltyBps.toNumber();
if (penalty !== 0 && penalty !== 10000) {
throw "Early withdrawal penalty is not supported yet";
}
if (penalty > 10000) {
throw "Early withdrawal penalty is too high";
}
let lockingStart = 0;
const slot = yield this._connection.getSlot();
const timestampNow = (yield this._connection.getBlockTime(slot));
if (lockingMode == index_1.LockingMode.None.discriminator) {
return {
farmLockupOriginalDuration: 0,
farmLockupExpiry: 0,
lockupRemainingDuration: 0,
};
}
if (lockingMode == index_1.LockingMode.WithExpiry.discriminator) {
// Locking starts globally for the entire farm
lockingStart = farmState === null || farmState === void 0 ? void 0 : farmState.lockingStartTimestamp.toNumber();
}
if (lockingMode == index_1.LockingMode.Continuous.discriminator) {
// Locking starts for each user individually at each stake
// if the user has a state, else now
if (userState === null) {
lockingStart = timestampNow;
}
else {
if (!userState) {
throw new Error("Error fetching user state");
}
lockingStart = userState.lastStakeTs.toNumber();
}
}
const timestampBeginning = lockingStart;
const timestampMaturity = lockingStart + lockingDuration;
if (timestampNow >= timestampMaturity) {
// Time has passed, no remaining
return {
farmLockupOriginalDuration: farmState.lockingDuration.toNumber(),
farmLockupExpiry: timestampMaturity,
lockupRemainingDuration: 0,
};
}
if (timestampNow < timestampBeginning) {
// Time has not started, no remaining
return {
farmLockupOriginalDuration: farmState.lockingDuration.toNumber(),
farmLockupExpiry: timestampMaturity,
lockupRemainingDuration: 0,
};
}
const timeRemaining = timestampMaturity - timestampNow;
const remainingLockedDurationSeconds = Math.max(timeRemaining, 0);
return {
farmLockupOriginalDuration: farmState.lockingDuration.toNumber(),
farmLockupExpiry: timestampMaturity,
lockupRemainingDuration: remainingLockedDurationSeconds,
};
});
}
getUserStateKeysForDelegatedFarm(user, farm, delegatees) {
return __awaiter(this, void 0, void 0, function* () {
if (delegatees) {
return this.getUserStateKeysForDelegatedFarmDeterministic(user, farm, delegatees);
}
const userStates = yield this.getAllUserStatesForUser(user);
const userStateKeysForFarm = [];
for (let index = 0; index < userStates.length; index++) {
if (userStates[index].userState.farmState.equals(farm)) {
userStateKeysForFarm.push(userStates[index]);
}
}
if (userStateKeysForFarm.length === 0) {
throw Error("No user state found for user " + user + " for farm " + farm);
}
else {
return userStateKeysForFarm;
}
});
}
getUserStateKeysForDelegatedFarmDeterministic(user, farm, delegatees) {
return __awaiter(this, void 0, void 0, function* () {
const userStateAddresses = [];
const userStateKeysForFarm = [];
delegatees.forEach((delegatee) => {
const userStateAddress = (0, utils_2.getUserStatePDA)(this._farmsProgramId, farm, delegatee);
userStateAddresses.push(userStateAddress);
});
const userStates = yield accounts_1.UserState.fetchMultiple(this._connection, userStateAddresses);
userStates.forEach((userState, index) => {
if (userState && userState.farmState.equals(farm)) {
userStateKeysForFarm.push({
key: userStateAddresses[index],
userState: userState,
});
}
});
if (userStateKeysForFarm.length === 0) {
throw Error("No user state found for user " + user + " for farm " + farm);
}
else {
return userStateKeysForFarm;
}
});
}
getAllFarmsForUser(user, strategiesToInclude) {
return __awaiter(this, void 0, void 0, function* () {
const userStates = yield this.getAllUserStatesForUser(user);
const farmPks = new Array();
for (let i = 0; i < userStates.length; i++) {
farmPks[i] = userStates[i].userState.farmState;
}
const farmStates = yield this.getAllFarmStatesByPubkeys(farmPks);
if (!farmStates) {
throw new Error("Error fetching farms");
}
let farmStatesFiltered = [];
if (strategiesToInclude) {
farmStatesFiltered = farmStates.filter((farmStates) => {
if (strategiesToInclude.contains(farmStates.farmState.strategyId)) {
return true;
}
return false;
});
}
else {
farmStatesFiltered = farmStates;
}
if (farmStatesFiltered.length === 0) {
// Return empty if no serializable farm states found
return new klend_sdk_1.PubkeyHashMap();
}
const timestamp = new decimal_js_1.default((yield this._connection.getBlockTime(yield this._connection.getSlot())));
const userFarms = new klend_sdk_1.PubkeyHashMap();
for (let userState of userStates) {
const userPendingRewardAmounts = [];
let farmState = farmStatesFiltered.find((farmState) => farmState.key.equals(userState.userState.farmState));
if (!farmState) {
// Skip farms that are not serializable anymore
continue;
}
let oraclePrices = null;
if (!farmState.farmState.scopePrices.equals(web3_js_1.PublicKey.default)) {
oraclePrices = yield scope_sdk_1.OraclePrices.fetch(this._connection, farmState.farmState.scopePrices);
if (!oraclePrices) {
throw new Error("Error fetching oracle prices");
}
}
let hasReward = false;
// calculate userState pending rewards
for (let indexReward = 0; indexReward < farmState.farmState.rewardInfos.length; indexReward++) {
userPendingRewardAmounts[indexReward] = (0, utils_1.calculatePendingRewards)(farmState.farmState, userState.userState, indexReward, timestamp, oraclePrices);
if (userPendingRewardAmounts[indexReward].gt(0)) {
hasReward = true;
}
}
// add new userFarm state if non empty (has rewards or stake) and not already present
if (!userFarms.has(userState.userState.farmState)) {
const userFarm = {
userStateAddress: userState.key,
farm: userState.userState.farmState,
strategyId: farmState.farmState.strategyId,
delegateAuthority: farmState.farmState.delegateAuthority,
stakedToken: farmState.farmState.token.mint,
activeStakeByDelegatee: new klend_sdk_1.PubkeyHashMap(),
pendingDepositStakeByDelegatee: new klend_sdk_1.PubkeyHashMap(),
pendingWithdrawalUnstakeByDelegatee: new klend_sdk_1.PubkeyHashMap(),
pendingRewards: new Array(farmState.farmState.rewardInfos.length)
.fill(undefined)
.map(function (value, index) {
return {
rewardTokenMint: new web3_js_1.PublicKey(0),
rewardTokenProgramId: farmState.farmState.rewardInfos[index].token.tokenProgram,
rewardType: (farmState === null || farmState === void 0 ? void 0 : farmState.farmState.rewardInfos[index].rewardType) || 0,
cumulatedPendingRewards: new decimal_js_1.default(0),
pendingRewardsByDelegatee: new klend_sdk_1.PubkeyHashMap(),
};
}),
};
if (new decimal_js_1.default((0, utils_2.scaleDownWads)(userState.userState.activeStakeScaled)).gt(0) ||
hasReward) {
userFarms.set(userState.userState.farmState, userFarm);
}
else {
// skip as we are not accounting for empty userFarms
continue;
}
}
// add new userFarm state if non empty (has rewards or stake) and not already present
const refUserFarm = userFarms.get(userState.userState.farmState);
if (!refUserFarm) {
throw new Error("User farm state not loaded properly ");
}
const updatedUserFarm = Object.assign({}, refUserFarm);
if (updatedUserFarm.activeStakeByDelegatee.has(userState.userState.delegatee)) {
console.error("Delegatee for user for farm already present. There should be only one delegatee for this user for this farm");
continue;
}
// active stake by delegatee
updatedUserFarm.activeStakeByDelegatee.set(userState.userState.delegatee, (0, utils_2.lamportsToCollDecimal)(new decimal_js_1.default((0, utils_2.scaleDownWads)(userState.userState.activeStakeScaled)), farmState.farmState.token.decimals.toNumber()));
// pendingDepositStake by delegatee
updatedUserFarm.pendingDepositStakeByDelegatee.set(userState.userState.delegatee, new decimal_js_1.default((0, utils_2.scaleDownWads)(userState.userState.pendingDepositStakeScaled)));
// pendingWithdrawalUnstake by delegatee
updatedUserFarm.pendingWithdrawalUnstakeByDelegatee.set(userState.userState.delegatee, new decimal_js_1.default((0, utils_2.scaleDownWads)(userState.userState.pendingWithdrawalUnstakeScaled)));
// cummulating rewards
for (let indexReward = 0; indexReward < farmState.farmState.rewardInfos.length; indexReward++) {
updatedUserFarm.pendingRewards[indexReward].rewardTokenMint =
farmState.farmState.rewardInfos[indexReward].token.mint;
updatedUserFarm.pendingRewards[indexReward].cumulatedPendingRewards =
updatedUserFarm.pendingRewards[indexReward].cumulatedPendingRewards.add(userPendingRewardAmounts[indexReward]);
updatedUserFarm.pendingRewards[indexReward].pendingRewardsByDelegatee.set(userState.userState.delegatee, userPendingRewardAmounts[indexReward]);
}
// set updated userFarm
userFarms.set(userState.userState.farmState, updatedUserFarm);
}
return userFarms;
});
}
getUserStateKeyForUndelegatedFarm(user, farmAddress) {
return __awaiter(this, void 0, void 0, function* () {
const userStateAddress = (0, utils_2.getUserStatePDA)(this._farmsProgramId, farmAddress, user);
const userState = yield accounts_1.UserState.fetch(this._connection, userStateAddress);
if (!userState) {
throw new Error(`User state not found ${userStateAddress.toString()}`);
}
return {
key: userStateAddress,
userState: userState,
};
});
}
getUserForUndelegatedFarm(user, farmAddress) {
return __awaiter(this, void 0, void 0, function* () {
const farmState = yield accounts_2.FarmState.fetch(this._connection, farmAddress);
if (!farmState) {
throw new Error(`Farm not found ${farmAddress.toString()}`);
}
const userStateAddress = (0, utils_2.getUserStatePDA)(this._farmsProgramId, farmAddress, user);
const userState = yield accounts_1.UserState.fetch(this._connection, userStateAddress);
if (!userState) {
throw new Error(`User state not found ${userStateAddress.toString()}`);
}
const userFarm = {
userStateAddress: userStateAddress,
farm: farmAddress,
strategyId: farmState.strategyId,
delegateAuthority: farmState.delegateAuthority,
stakedToken: farmState.token.mint,
activeStakeByDelegatee: new klend_sdk_1.PubkeyHashMap(),
pendingDepositStakeByDelegatee: new klend_sdk_1.PubkeyHashMap(),
pendingWithdrawalUnstakeByDelegatee: new klend_sdk_1.PubkeyHashMap(),
pendingRewards: new Array(farmState.rewardInfos.length)
.fill(undefined)
.map(function (value, index) {
return {
rewardTokenMint: new web3_js_1.PublicKey(0),
rewardTokenProgramId: farmState === null || farmState === void 0 ? void 0 : farmState.rewardInfos[index].token.tokenProgram,
rewardType: (farmState === null || farmState === void 0 ? void 0 : farmState.rewardInfos[index].rewardType) || 0,
cumulatedPendingRewards: new decimal_js_1.default(0),
pendingRewardsByDelegatee: new klend_sdk_1.PubkeyHashMap(),
};
}),
};
// active stake
userFarm.activeStakeByDelegatee.set(user, (0, utils_2.lamportsToCollDecimal)(new decimal_js_1.default((0, utils_2.scaleDownWads)(userState.activeStakeScaled)), farmState.token.decimals.toNumber()));
// pendingDepositStake
userFarm.pendingDepositStakeByDelegatee.set(user, new decimal_js_1.default((0, utils_2.scaleDownWads)(userState.pendingDepositStakeScaled)));
// pendingWithdrawalUnstake
userFarm.pendingWithdrawalUnstakeByDelegatee.set(user, new decimal_js_1.default((0, utils_2.scaleDownWads)(userState.pendingWithdrawalUnstakeScaled)));
// get oraclePrices
const timestamp = new decimal_js_1.default((yield this._connection.getBlockTime(yield this._connection.getSlot())));
let oraclePrices = null;
if (!farmState.scopePrices.equals(web3_js_1.PublicKey.default)) {
oraclePrices = yield scope_sdk_1.OraclePrices.fetch(this._connection, farmState.scopePrices);
if (!oraclePrices) {
throw new Error("Error fetching oracle prices");
}
}
const userPendingRewardAmounts = [];
for (let indexReward = 0; indexReward < farmState.rewardInfos.length; indexReward++) {
// calculate pending rewards
userPendingRewardAmounts[indexReward] = (0, utils_1.calculatePendingRewards)(farmState, userState, indexReward, timestamp, oraclePrices);
userFarm.pendingRewards[indexReward].rewardTokenMint =
farmState.rewardInfos[indexReward].token.mint;
userFarm.pendingRewards[indexReward].cumulatedPendingRewards =
userPendingRewardAmounts[indexReward];
userFarm.pendingRewards[indexReward].pendingRewardsByDelegatee.set(user, userPendingRewardAmounts[indexReward]);
}
return userFarm;
});
}
executeTransaction(ix_1, signer_1) {
return __awaiter(this, arguments, void 0, function* (ix, signer, extraSigners = [], web3Client, priorityFeeMultiplier = 0) {
const microLamport = Math.pow(10, 6); // 1 lamport
const computeUnits = 200000;
const microLamportsPrioritizationFee = microLamport / computeUnits;
const tx = new web3_js_1.Transaction();
let { blockhash } = yield this._connection.getLatestBlockhash();
if (priorityFeeMultiplier) {
const priorityFeeIxn = (0, utils_3.createAddExtraComputeUnitFeeTransaction)(computeUnits, microLamportsPrioritizationFee * priorityFeeMultiplier);
tx.add(...priorityFeeIxn);
}
tx.recentBlockhash = blockhash;
tx.feePayer = signer.publicKey;
tx.add(...ix);
let sig;
if (web3Client) {
sig = yield (0, sendTransactionsUtils_1.signSendAndConfirmRawTransactionWithRetry)({
mainConnection: web3Client.sendConnection,
extraConnections: web3Client.sendConnectionsExtra,
tx: new web3_js_2.VersionedTransaction(tx.compileMessage()),
signers: [signer, ...extraSigners],
commitment: "confirmed",
sendTransactionOptions: {
skipPreflight: true,
preflightCommitment: "confirmed",
},
});
}
else {
sig = yield (0, web3_js_1.sendAndConfirmTransaction)(this._connection, tx, [signer, ...extraSigners], { skipPreflight: true, commitment: "confirmed" });
}
return sig;
});
}
createNewUserIx(user, farm) {
return __awaiter(this, void 0, void 0, function* () {
const userState = (0, utils_2.getUserStatePDA)(this._farmsProgramId, farm, user);
const ix = farmOperations.initializeUser(farm, user, userState);
return ix;
});
}
createNewUser(user, farm, priorityFeeMultiplier, web3Client) {
return __awaiter(this, void 0, void 0, function* () {
const ix = yield this.createNewUserIx(user.publicKey, farm);
let sig = yield this.executeTransaction([ix], user, [], web3Client, priorityFeeMultiplier);
const userState = (0, utils_2.getUserStatePDA)(this._farmsProgramId, farm, user.publicKey);
if (process.env.DEBUG === "true") {
console.log("Initialize User: " + userState);
console.log("Refresh Farm txn: " + sig.toString());
}
return sig;
});
}
stakeIx(user, farm, amountLamports, stakeTokenMint, scopePrices) {
return __awaiter(this, void 0, void 0, function* () {
const farmVault = (0, utils_2.getFarmVaultPDA)(this._farmsProgramId, farm, stakeTokenMint);
const userStatePk = (0, utils_2.getUserStatePDA)(this._farmsProgramId, farm, user);
const userTokenAta = yield (0, utils_2.getAssociatedTokenAddress)(user, stakeTokenMint, spl_token_1.TOKEN_PROGRAM_ID);
const ix = farmOperations.stake(user, userStatePk, userTokenAta, farm, farmVault, stakeTokenMint, scopePrices, new anchor_1.BN(amountLamports.toString()));
return ix;
});
}
stake(user, farm, amountLamports, stakeTokenMint, priorityFeeMultiplier, web3Client) {
return __awaiter(this, void 0, void 0, function* () {
const ix = yield this.stakeIx(user.publicKey, farm, amountLamports, stakeTokenMint, programId_1.PROGRAM_ID);
let increaseComputeIx = (0, utils_2.createAddExtraComputeUnitsTransaction)(user.publicKey, 400000);
let sig = yield this.executeTransaction([increaseComputeIx, ix], user, [], web3Client, priorityFeeMultiplier);
if (process.env.DEBUG === "true") {
console.log("User " + " stake " + amountLamports);
console.log("Stake txn: " + sig.toString());
}
return sig;
});
}
unstakeIx(user, farm, amountLamports, scopePrices) {
return __awaiter(this, void 0, void 0, function* () {
const userStatePk = (0, utils_2.getUserStatePDA)(this._farmsProgramId, farm, user);
const ix = farmOperations.unstake(user, userStatePk, farm, scopePrices, new anchor_1.BN(amountLamports));
return ix;
});
}
unstake(user, farm, sharesAmount, priorityFeeMultiplier, web3Client) {
return __awaiter(this, void 0, void 0, function* () {
const ix = yield this.unstakeIx(user.publicKey, farm, sharesAmount, programId_1.PROGRAM_ID);
let sig = yield this.executeTransaction([ix], user, [], web3Client, priorityFeeMultiplier);
if (process.env.DEBUG === "true") {
console.log("Unstake " + sharesAmount);
console.log("Unstake txn: " + sig.toString());
}
return sig;
});
}
withdrawUnstakedDepositIx(user, userState, farmState, stakeTokenMint) {
return __awaiter(this, void 0, void 0, function* () {
const userTokenAta = yield (0, utils_2.getAssociatedTokenAddress)(user, stakeTokenMint, spl_token_1.TOKEN_PROGRAM_ID);
const farmVault = (0, utils_2.getFarmVaultPDA)(this._farmsProgramId, farmState, stakeTokenMint);
const farmVaultsAuthority = (0, utils_2.getFarmAuthorityPDA)(this._farmsProgramId, farmState);
const ix = farmOperations.withdrawUnstakedDeposit(user, userState, farmState, userTokenAta, farmVault, farmVaultsAuthority);
return ix;
});
}
withdrawUnstakedDeposit(user, farmState, tokenMint, userState, priorityFeeMultiplier, web3Client) {
return __awaiter(this, void 0, void 0, function* () {
const ix = yield this.withdrawUnstakedDepositIx(user.publicKey, userState, farmState, tokenMint);
let sig = yield this.executeTransaction([ix], user, [], web3Client, priorityFeeMultiplier);
if (process.env.DEBUG === "true") {
console.log("User " + userState + " withdraw unstaked deposit ");
console.log("Withdraw Unstaked Deposit txn: " + sig.toString());
}
return sig;
});
}
claimForUserForFarmRewardIx(user_1, farm_1, rewardMint_1, isDelegated_1) {
return __awaiter(this, arguments, void 0, function* (user, farm, rewardMint, isDelegated, rewardIndex = -1, delegatees) {
const ixns = [];
const ataIxns = [];
const userStatesAndKeys = isDelegated
? yield this.getUserStateKeysForDelegatedFarm(user, farm, delegatees)
: [yield this.getUserStateKeyForUndelegatedFarm(user, farm)];
const farmState = yield accounts_2.FarmState.fetch(this._connection, farm);
if (!farmState) {
throw new Error(`Farm not found ${farm.toString()}`);
}
const treasuryVault = (0, utils_2.getTreasuryVaultPDA)(this._farmsProgramId, farmState.globalConfig, rewardMint);
// find rewardIndex if not defined
if (rewardIndex === -1) {
rewardIndex = farmState.rewardInfos.findIndex((r) => r.token.mint.equals(rewardMint));
}
const rewardsTokenProgram = farmState.rewardInfos[rewardIndex].token.tokenProgram;
const userRewardAta = yield (0, utils_2.getAssociatedTokenAddress)(user, rewardMint, rewardsTokenProgram);
const ataExists = yield (0, utils_1.checkIfAccountExists)(this._connection, userRewardAta);
if (!ataExists) {
const [, ix] = yield (0, utils_1.createAssociatedTokenAccountIdempotentInstruction)(user, rewardMint, user, rewardsTokenProgram, userRewardAta);
ataIxns.push([rewardMint, ix]);
}
for (let userStateIndex = 0; userStateIndex < userStatesAndKeys.length; userStateIndex++) {
const ix = farmOperations.harvestReward(user, userStatesAndKeys[userStateIndex].key, userRewardAta, farmState.globalConfig, treasuryVault, farm, rewardMint, farmState.rewardInfos[rewardIndex].rewardsVault, farmState.farmVaultsAuthority, farmState.scopePrices.equals(web3_js_1.PublicKey.default)
? programId_1.PROGRAM_ID
: farmState.scopePrices, rewardsTokenProgram, rewardIndex);
ixns.push(ix);
}
return [ataIxns, ixns];
});
}
claimForUserForFarmReward(user_1, farm_1, rewardMint_1, isDelegated_1) {
return __awaiter(this, arguments, void 0, function* (user, farm, rewardMint, isDelegated, rewardIndex = -1, priorityFeeMultiplier, web3Client) {
const [_ataIxns, ixns] = yield this.claimForUserForFarmRewardIx(user.publicKey, farm, rewardMint, isDelegated, rewardIndex);
let sig = yield this.executeTransaction(ixns, user, [], web3Client, priorityFeeMultiplier);
if (process.env.DEBUG === "true") {
console.log("Harvest reward " + rewardIndex);
console.log("HarvestReward txn: " + sig.toString());
}
return sig;
});
}
claimForUserForFarmAllRewardsIx(user, farm, isDelegated, delegatees) {
return __awaiter(this, void 0, void 0, function* () {
const farmState = yield accounts_2.FarmState.fetch(this._connection, farm);
const userStatesAndKeys = isDelegated
? yield this.getUserStateKeysForDelegatedFarm(user, farm, delegatees)
: [yield this.getUserStateKeyForUndelegatedFarm(user, farm)];
const ixs = new Array();
// hardcoded as a hotfix for JTO release;
// TODO: replace by proper fix
const jitoFarm = new web3_js_1.PublicKey("Cik985zLyHYdv5Hs73BUWUcMHMhgfBNwbcCYyvBjV2tt");
if (!farmState) {
throw new Error(`Farm not found ${farm.toString()}`);
}
for (let userStateIndex = 0; userStateIndex < userStatesAndKeys.length; userStateIndex++) {
for (let rewardIndex = 0; rewardIndex < farmState.numRewardTokens.toNumber(); rewardIndex++) {
if (!jitoFarm.equals(farm) &&
farmState.rewardInfos[rewardIndex].rewardType ==
index_1.RewardType.Constant.discriminator) {
continue;
}
const rewardMint = farmState.rewardInfos[rewardIndex].token.mint;
const rewardTokenProgram = farmState.rewardInfos[rewardIndex].token.tokenProgram;
const userRewardAta = yield (0, utils_2.getAssociatedTokenAddress)(user, rewardMint, rewardTokenProgram);
const treasuryVault = (0, utils_2.getTreasuryVaultPDA)(this._farmsProgramId, farmState.globalConfig, rewardMint);
const ataExists = yield (0, utils_1.checkIfAccountExists)(this._connection, userRewardAta);
if (!ataExists) {
const [, ix] = yield (0, utils_1.createAssociatedTokenAccountIdempotentInstruction)(user, rewardMint, user, rewardTokenProgram, userRewardAta);
ixs.push(ix);
}
ixs.push(farmOperations.harvestReward(user, userStatesAndKeys[userStateIndex].key, userRewardAta, farmState.globalConfig, treasuryVault, farm, rewardMint, farmState.rewardInfos[rewardIndex].rewardsVault, farmState.farmVaultsAuthority, farmState.scopePrices.equals(web3_js_1.PublicKey.default)
? programId_1.PROGRAM_ID
: farmState.scopePrices, rewardTokenProgram, rewardIndex));
}
}
return ixs;
});
}
claimForUserForFarmAllRewards(user, farm, isDelegated, priorityFeeMultiplier, web3Client) {
return __awaiter(this, void 0, void 0, function* () {
const ixs = yield this.claimForUserForFarmAllRewardsIx(user.publicKey, farm, isDelegated);
const sigs = new Array();
for (let i = 0; i < ixs.length; i++) {
sigs[i] = yield this.executeTransaction([ixs[i]], user, [], web3Client, priorityFeeMultiplier);
}
return sigs;
});
}
transferOwnershipIx(user, userState, newUser) {
return __awaiter(this, void 0, void 0, function* () {
const ix = farmOperations.transferOwnership(user, userState, newUser);
return ix;
});
}
transferOwnership(user, userState, newUser, priorityFeeMultiplier, web3Client) {
return __awaiter(this, void 0, void 0, function* () {
const ix = yield this.transferOwnershipIx(user.publicKey, userState, newUser);
let sig = yield this.executeTransaction([ix], user, [], web3Client, priorityFeeMultiplier);
if (process.env.DEBUG === "true") {
console.log("Transfer User " +
userState +
" ownership from " +
user.publicKey +
" to " +
newUser);
console.log("Transfer User Ownership txn: " + sig.toString());
}
return sig;
});
}
transferOwnershipAllUserStatesIx(user, newUser) {
return __awaiter(this, void 0, void 0, function* () {
const userStates = yield this.getAllUserStatesForUser(user);
const ixs = new Array();
for (let index = 0; index < userStates.length; index++) {
ixs[index] = farmOperations.transferOwnership(user, userStates[index].key, newUser);
}
return ixs;
});
}
transferOwnershipAllUserStates(user, newUser, priorityFeeMultiplier, web3Client) {
return __awaiter(this, void 0, void 0, function* () {
const ixs = yield this.transferOwnershipAllUserStatesIx(user.publicKey, newUser);
const sigs = new Array();
for (let i = 0; i < ixs.length; i++) {
sigs[i] = yield this.executeTransaction([ixs[i]], user, [], web3Client, priorityFeeMultiplier);
}
return sigs;
});
}
createFarmIx(admin, farm, globalConfig, stakeTokenMint) {
return __awaiter(this, void 0, void 0, function* () {
const farmVault = (0, utils_2.getFarmVaultPDA)(this._farmsProgramId, farm.publicKey, stakeTokenMint);
const farmVaultAuthority = (0, utils_2.getFarmAuthorityPDA)(this._farmsProgramId, farm.publicKey);
let ixs = [];
ixs.push(yield (0, utils_2.createKeypairRentExemptIx)(this._provider.connection, admin, farm, utils_1.SIZE_FARM_STATE, this._farmsProgramId));
ixs.push(farmOperations.initializeFarm(globalConfig, admin, farm.publicKey, farmVault, farmVaultAuthority, stakeTokenMint));
return ixs;
});
}
createFarm(admin_1, globalConfig_1, farm_1, mint_1) {
return __awaiter(this, arguments, void 0, function* (admin, globalConfig, farm, mint, mode = "execute", priorityFeeMultiplier, web3Client) {
const ix = yield this.createFarmIx(mode === "multisig"
? new web3_js_1.PublicKey(process.env.MULTISIG)
: admin.publicKey, farm, globalConfig, mint);
const log = "Initialize Farm: " + farm.toString();
return this.processTxn(admin, ix, mode, priorityFeeMultiplier, log, [farm], web3Client);
});
}
addRewardToFarmIx(admin, globalConfig, farm, mint, tokenProgram) {
return __awaiter(this, void 0, void 0, function* () {
const globalConfigState = yield accounts_2.GlobalConfig.fetch(this._connection, globalConfig);
if (!globalConfigState) {
throw new Error("Could not fetch global config");
}
const treasuryVault = (0, utils_2.getTreasuryVaultPDA)(this._farmsProgramId, globalConfig, mint);
let farmVaultAuthority = (0, utils_2.getFarmAuthorityPDA)(this._farmsProgramId, farm);
const rewardVault = (0, utils_2.getRewardVaultPDA)(this._farmsProgramId, farm, mint);
const ix = farmOperations.initializeReward(globalConfig, globalConfigState.treasuryVaultsAuthority, treasuryVault, admin, farm, rewardVault, farmVaultAuthority, mint, tokenProgram);
return ix;
});
}
addRewardToFarm(admin_1, globalConfig_1, farm_1, mint_1, tokenProgram_1) {
return __awaiter(this, arguments, void 0, function* (admin, globalConfig, farm, mint, tokenProgram, mode = "execute", priorityFeeMultiplier, web3Client) {
const ix = yield this.addRewardToFarmIx(mode === "multisig"
? new web3_js_1.PublicKey(process.env.MULTISIG)
: admin.publicKey, globalConfig, farm, mint, tokenProgram);
const log = "Initialize Reward: " + mint;
return this.processTxn(admin, [ix], mode, priorityFeeMultiplier, log, [], web3Client);
});
}
addRewardAmountToFarmIx(payer_1, farm_1, mint_1, amount_1) {
return __awaiter(this, arguments, void 0, function* (payer, farm, mint, amount, rewardIndexOverride = -1, decimalsOverride = -1, tokenProgramOverride = spl_token_1.TOKEN_PROGRAM_ID, scopePricesOverride = programId_1.PROGRAM_ID) {
let decimals = decimalsOverride;
let rewardIndex = rewardIndexOverride;
let scopePrices = scopePricesOverride;
let tokenProgram = tokenProgramOverride;
if (rewardIndex == -1) {
const farmState = yield accounts_2.FarmState.fetch(this._connection, farm);
if (!farmState) {
throw new Error(`Could not fetch farm state ${farm.toBase58()}`);
}
scopePrices = farmState.scopePrices.equals(web3_js_1.PublicKey.default)
? programId_1.PROGRAM_ID
: farmState.scopePrices;
for (let i = 0; farmState.rewardInfos.length; i++) {
if (farmState.rewardInfos[i].token.mint.equals(mint)) {
if (!farmState.rewardInfos[i].token.tokenProgram.equals(web3_js_1.PublicKey.default)) {
tokenProgram = farmState.rewardInfos[i].token.tokenProgram;
}
rewardIndex = i;
decimals = farmState.rewardInfos[i].token.decimals.toNumber();
break;
}
}
}
if (decimals == -1) {
throw new Error(`Could not find reward token ${mint.toBase58()}`);
}
let amountLamports = new anchor_1.BN((0, utils_2.collToLamportsDecimal)(amount, decimals).floor().toString());
const payerRewardAta = yield (0, utils_2.getAssociatedTokenAddress)(payer, mint, tokenProgram);
let rewardVault = (0, utils_2.getRewardVaultPDA)(this._farmsProgramId, farm, mint);
let farmVaultsAuthority = (0, utils_2.getFarmAuthorityPDA)(this._farmsProgramId, farm);
const ix = farmOperations.addReward(payer, farm, rewardVault, farmVaultsAuthority, payerRewardAta, mint, scopePrices, rewardIndex, tokenProgram, amountLamports);
return ix;
});
}
withdrawRewardAmountFromFarmIx(payer_1, farm_1, mint_1, amount_1) {
return __awaiter(this, arguments, void 0, function* (payer, farm, mint, amount, rewardIndexOverride = -1, decimalsOverride = -1, tokenProgramOverride = spl_token_1.TOKEN_PROGRAM_ID, scopePricesOverride = programId_1.PROGRAM_ID) {
let decimals = decimalsOverride;
let tokenProgram = tokenProgramOverride;
let rewardInde