@hubbleprotocol/farms-sdk
Version:
105 lines • 5.48 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.calculatePendingRewards = calculatePendingRewards;
exports.calculateCurrentRewardPerToken = calculateCurrentRewardPerToken;
exports.calculateNewRewardToBeIssued = calculateNewRewardToBeIssued;
exports.scopePriceForFarm = scopePriceForFarm;
const decimal_js_1 = __importDefault(require("decimal.js"));
const utils_1 = require("./utils");
const web3_js_1 = require("@solana/web3.js");
const types_1 = require("../rpc_client/types");
function calculatePendingRewards(farmState, userState, rewardIndex, ts, scopePrices) {
let scopePrice = scopePriceForFarm(farmState, scopePrices);
const newRewardPerToken = calculateRewardPerStake(farmState, ts, rewardIndex, scopePrice);
const rewardTally = new decimal_js_1.default(userState.rewardsTallyScaled[rewardIndex].toString()).div(utils_1.WAD);
let activeStakeScaled = new decimal_js_1.default(0);
if (farmState.delegateAuthority.equals(web3_js_1.PublicKey.default)) {
activeStakeScaled = new decimal_js_1.default(userState.activeStakeScaled.toString()).div(utils_1.WAD);
}
else {
activeStakeScaled = new decimal_js_1.default(userState.activeStakeScaled.toString());
}
const newRewardTally = activeStakeScaled.mul(newRewardPerToken);
const newReward = new decimal_js_1.default(newRewardTally.sub(rewardTally).toFixed(0));
const prevReward = new decimal_js_1.default(userState.rewardsIssuedUnclaimed[rewardIndex].toString());
const finalReward = prevReward.add(newReward);
return finalReward;
}
function calculateCurrentRewardPerToken(rewardInfo, currentTimeUnit) {
const rewardCurve = rewardInfo.rewardScheduleCurve;
let index = 0;
for (let i = 0; i < rewardCurve.points.length; i++) {
if (new decimal_js_1.default(rewardCurve.points[i].tsStart.toString()).lte(currentTimeUnit)) {
index = i;
}
else {
break;
}
}
return rewardCurve.points[index].rewardPerTimeUnit.toNumber();
}
function calculateRewardPerStake(farmState, ts, rewardIndex, scopePrice) {
const rewardInfo = farmState.rewardInfos[rewardIndex];
const newRewards = calculateNewRewardToBeIssued(farmState, ts, rewardIndex, scopePrice);
let scaledRewards = newRewards.mul(utils_1.WAD);
let rewardPerTokenScaled = new decimal_js_1.default(rewardInfo.rewardPerShareScaled.toString()).div(utils_1.WAD);
let rewardPerTokenScaledAdded = new decimal_js_1.default(0);
const totalActiveStakeScaled = new decimal_js_1.default(farmState.totalActiveStakeScaled.toString());
if (farmState.delegateAuthority.equals(web3_js_1.PublicKey.default)) {
rewardPerTokenScaledAdded = scaledRewards.div(totalActiveStakeScaled);
}
else {
if (scaledRewards.gt(new decimal_js_1.default(0)) &&
totalActiveStakeScaled.gt(new decimal_js_1.default(0))) {
rewardPerTokenScaledAdded = scaledRewards
.div(totalActiveStakeScaled)
.div(utils_1.WAD);
}
}
const finalRewardPerToken = rewardPerTokenScaled.add(rewardPerTokenScaledAdded);
return finalRewardPerToken;
}
function calculateNewRewardToBeIssued(farmState, ts, rewardIndex, scopePrice) {
const rewardInfo = farmState.rewardInfos[rewardIndex];
const tsDiff = ts.sub(new decimal_js_1.default(rewardInfo.lastIssuanceTs.toString()));
let rps = calculateCurrentRewardPerToken(rewardInfo, ts);
let rpsDecimal = new decimal_js_1.default(Math.pow(10, rewardInfo.rewardsPerSecondDecimals));
let newRewards = tsDiff.mul(new decimal_js_1.default(rps)).div(rpsDecimal);
if (rewardInfo.rewardType == types_1.RewardType.Proportional.discriminator) {
// In the `Proportional` case `rps` means
// `reward per second for entire farm`
}
else if (rewardInfo.rewardType == types_1.RewardType.Constant.discriminator) {
// In the `Constant` case `rps` means
// `reward per second for each lamport staked`
const totalStaked = new decimal_js_1.default(farmState.totalStakedAmount.toString());
newRewards = newRewards.mul(totalStaked);
}
if (!farmState.scopePrices.equals(web3_js_1.PublicKey.default)) {
// Oracle adjustment
if (scopePrice == null) {
throw new Error("Scope price not provided");
}
console.log("Adjusting by scope price", scopePrice.toString());
newRewards = newRewards.mul(scopePrice);
}
// We cap rewards by how much is available in the farm anyway
let cappedRewards = decimal_js_1.default.min(newRewards, new decimal_js_1.default(rewardInfo.rewardsAvailable.toString()));
return cappedRewards;
}
function scopePriceForFarm(farmState, scopePrices) {
let scopePrice = null;
if (!farmState.scopePrices.equals(web3_js_1.PublicKey.default)) {
if (scopePrices == null) {
throw new Error("Scope prices not provided");
}
const price = scopePrices.prices[new decimal_js_1.default(farmState.scopeOraclePriceId.toString()).toNumber()];
const factor = new decimal_js_1.default(10).pow(price.price.exp.toString());
scopePrice = new decimal_js_1.default(price.price.value.toString()).div(factor);
}
return scopePrice;
}
//# sourceMappingURL=mathUtils.js.map