granite-math-sdk
Version:
Granite math sdk
496 lines (486 loc) • 18.4 kB
JavaScript
;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var index_exports = {};
__export(index_exports, {
absoluteMaxLeverage: () => absoluteMaxLeverage,
annualizedAPR: () => annualizedAPR,
calculateAccountHealth: () => calculateAccountHealth,
calculateAccountLTV: () => calculateAccountLTV,
calculateAccountLiqLTV: () => calculateAccountLiqLTV,
calculateAccountMaxLTV: () => calculateAccountMaxLTV,
calculateBorrowAPY: () => calculateBorrowAPY,
calculateBorrowCapacity: () => calculateBorrowCapacity,
calculateCollateralToTransfer: () => calculateCollateralToTransfer,
calculateDrop: () => calculateDrop,
calculateDueInterest: () => calculateDueInterest,
calculateLiquidationPoint: () => calculateLiquidationPoint,
calculateLpAPY: () => calculateLpAPY,
calculateLpRewardApy: () => calculateLpRewardApy,
calculateMaxRepayAmount: () => calculateMaxRepayAmount,
calculateMaxWithdrawAmount: () => calculateMaxWithdrawAmount,
calculateTotalCollateralValue: () => calculateTotalCollateralValue,
compoundedInterest: () => compoundedInterest,
computeFlashLoanValues: () => computeFlashLoanValues,
computeTotalEarning: () => computeTotalEarning,
computeUtilizationRate: () => computeUtilizationRate,
convertDebtAssetsToShares: () => convertDebtAssetsToShares,
convertDebtSharesToAssets: () => convertDebtSharesToAssets,
convertLpAssetsToShares: () => convertLpAssetsToShares,
convertLpSharesToAssets: () => convertLpSharesToAssets,
correctedMaxLTV: () => correctedMaxLTV,
estimatedRewards: () => estimatedRewards,
leverageMaxSlippage: () => leverageMaxSlippage,
liquidationRisk: () => liquidationRisk,
liquidatorMaxRepayAmount: () => liquidatorMaxRepayAmount,
lpApyWithStaking: () => lpApyWithStaking,
protocolAvailableToBorrow: () => protocolAvailableToBorrow,
secondsInAYear: () => secondsInAYear,
stakerBonus: () => stakerBonus,
stakersRewardRate: () => stakersRewardRate,
stakingAPY: () => stakingAPY,
stakingRate: () => stakingRate,
swapLoss: () => swapLoss,
unencumberedCollateral: () => unencumberedCollateral,
userAvailableToBorrow: () => userAvailableToBorrow
});
module.exports = __toCommonJS(index_exports);
// src/constants.ts
var secondsInAYear = 365 * 24 * 60 * 60;
// src/modules/borrow.ts
function computeUtilizationRate(openInterest, totalAssets) {
if (totalAssets == 0) return 0;
return openInterest / totalAssets;
}
function annualizedAPR(ur, irParams) {
let ir;
if (ur < irParams.urKink) ir = irParams.slope1 * ur + irParams.baseIR;
else
ir = irParams.slope2 * (ur - irParams.urKink) + irParams.slope1 * irParams.urKink + irParams.baseIR;
return ir;
}
function calculateDueInterest(debtAmt, openInterest, totalAssets, irParams, timeDelta) {
const ur = computeUtilizationRate(openInterest, totalAssets);
const ir = annualizedAPR(ur, irParams);
return debtAmt * (1 + ir / secondsInAYear) ** timeDelta;
}
function compoundedInterest(debtAmt, openInterest, totalAssets, irParams, timeDelta) {
const ur = computeUtilizationRate(openInterest, totalAssets);
const ir = annualizedAPR(ur, irParams);
const interestAccrued = debtAmt * ((1 + ir / secondsInAYear) ** timeDelta - 1);
return interestAccrued;
}
function calculateBorrowAPY(ur, irParams) {
const borrowApr = annualizedAPR(ur, irParams);
return (1 + borrowApr / secondsInAYear) ** secondsInAYear - 1;
}
function convertDebtAssetsToShares(debtAssets, totalDebtShares, totalAssets, openInterest, protocolReservePercentage, irParams, timeDelta) {
if (totalAssets == 0) return 0;
const corretedOpenInterest = compoundedInterest(
openInterest,
openInterest,
totalAssets,
irParams,
timeDelta
);
const accruedInterest = corretedOpenInterest * (1 - protocolReservePercentage);
return debtAssets * totalDebtShares / (accruedInterest + openInterest);
}
function convertDebtSharesToAssets(debtShares, openInterest, totalDebtShares, totalAssets, irParams, timeDelta) {
if (totalDebtShares == 0) return 0;
const accruedInterest = compoundedInterest(
openInterest,
openInterest,
totalAssets,
irParams,
timeDelta
);
return debtShares * (openInterest + accruedInterest) / totalDebtShares;
}
function calculateBorrowCapacity(collaterals) {
let sum = 0;
for (const { amount, price, maxLTV } of collaterals) {
if (!maxLTV) {
throw new Error("Collateral max LTV is not defined");
}
sum += amount * price * maxLTV;
}
return sum;
}
function protocolAvailableToBorrow(freeLiquidity, reserveBalance) {
if (reserveBalance >= freeLiquidity) return 0;
return freeLiquidity - reserveBalance;
}
function userAvailableToBorrow(collaterals, freeLiquidity, reserveBalance, currentDebt) {
const protocolFreeLiquidity = protocolAvailableToBorrow(
freeLiquidity,
reserveBalance
);
return Math.min(
protocolFreeLiquidity,
Math.max(calculateBorrowCapacity(collaterals) - currentDebt, 0)
);
}
function calculateMaxRepayAmount(debtShares, openInterest, totalDebtShares, totalAssets, irParams, timeDelta) {
const ur = computeUtilizationRate(openInterest, totalAssets);
const borrowAPY = calculateBorrowAPY(ur, irParams);
const debtAssets = convertDebtSharesToAssets(
debtShares,
openInterest,
totalDebtShares,
totalAssets,
irParams,
timeDelta
);
const repayMultiplier = 1 + borrowAPY / secondsInAYear * (10 * 60);
return debtAssets * repayMultiplier;
}
// src/modules/account.ts
function calculateTotalCollateralValue(collaterals) {
return collaterals.reduce((total, collateral) => {
return total + collateral.amount * collateral.price;
}, 0);
}
function calculateAccountHealth(collaterals, currentDebt) {
const totalCollateralValue = collaterals.reduce((total, collateral) => {
if (!collateral.liquidationLTV) {
throw new Error("LiquidationLTV is not defined");
}
return total + collateral.amount * collateral.price * collateral.liquidationLTV;
}, 0);
if (currentDebt == 0) {
throw new Error("Current debt cannot be zero");
}
return totalCollateralValue / currentDebt;
}
function calculateAccountLTV(accountTotalDebt, collaterals) {
const accountCollateralValue = calculateTotalCollateralValue(collaterals);
if (accountCollateralValue == 0) {
return 0;
}
return accountTotalDebt / accountCollateralValue;
}
function calculateAccountMaxLTV(collaterals) {
const totalCollateralValue = calculateTotalCollateralValue(collaterals);
if (totalCollateralValue == 0) return 0;
const totalWeightedLTV = collaterals.reduce((sum, collateral) => {
if (collateral.maxLTV !== void 0) {
return sum + collateral.maxLTV * (collateral.amount * collateral.price);
} else {
throw new Error("MaxLTV is not defined for one or more collaterals");
}
}, 0);
return totalWeightedLTV / totalCollateralValue;
}
function calculateAccountLiqLTV(collaterals) {
const accountCollateralValue = calculateTotalCollateralValue(collaterals);
if (accountCollateralValue == 0) {
return 0;
}
const totalWeightedLTV = collaterals.reduce((total, collateral) => {
const collateralValue = collateral.amount * collateral.price;
if (!collateral.liquidationLTV) {
throw new Error("LiquidationLTV is not defined");
}
return total + collateral.liquidationLTV * collateralValue;
}, 0);
return totalWeightedLTV / accountCollateralValue;
}
function calculateMaxWithdrawAmount(collateralToWithdraw, allCollaterals, debtShares, openInterest, totalDebtShares, totalAssets, irParams, timeDelta, decimals, futureDeltaSeconds = 600) {
if (!collateralToWithdraw.maxLTV) {
throw new Error("MaxLTV is not defined for the selected collateral");
}
if (debtShares === 0) {
return collateralToWithdraw.amount;
}
const timeDeltaFuture = timeDelta + futureDeltaSeconds;
const futureDebt = convertDebtSharesToAssets(
debtShares,
openInterest,
totalDebtShares,
totalAssets,
irParams,
timeDeltaFuture
);
const requiredCollateralValue = futureDebt / collateralToWithdraw.maxLTV;
const currentCollateralValue = calculateTotalCollateralValue(allCollaterals);
const excessCollateralValue = currentCollateralValue - requiredCollateralValue;
const maxWithdrawAmount = Math.floor(
excessCollateralValue / collateralToWithdraw.price * Math.pow(10, decimals)
) / Math.pow(10, decimals);
return Math.max(0, Math.min(maxWithdrawAmount, collateralToWithdraw.amount));
}
// src/modules/lp.ts
function convertLpAssetsToShares(assets, totalShares, totalAssets, openInterest, protocolReservePercentage, irParams, timeDelta) {
if (totalAssets == 0) return 0;
const corretedOpenInterest = compoundedInterest(
openInterest,
openInterest,
totalAssets,
irParams,
timeDelta
);
const accruedInterest = corretedOpenInterest * (1 - protocolReservePercentage);
return assets * totalShares / (accruedInterest + totalAssets);
}
function convertLpSharesToAssets(shares, totalShares, totalAssets, openInterest, protocolReservePercentage, irParams, timeDelta) {
if (totalShares == 0) return 0;
const corretedOpenInterest = compoundedInterest(
openInterest,
openInterest,
totalAssets,
irParams,
timeDelta
);
const accruedInterest = corretedOpenInterest * (1 - protocolReservePercentage);
return shares * (accruedInterest + totalAssets) / totalShares;
}
function calculateLpAPY(ur, irParams, protocolReservePercentage) {
if (ur == 0) return 0;
else {
const lpAPR = annualizedAPR(ur, irParams) * (1 - protocolReservePercentage) * ur;
return (1 + lpAPR / secondsInAYear) ** secondsInAYear - 1;
}
}
function computeTotalEarning(shares, totalShares, totalAssets, openInterest, protocolReservePercentage, irParams, reserveBalance, timeDelta) {
return Math.max(
0,
convertLpSharesToAssets(
shares,
totalShares,
totalAssets,
openInterest,
protocolReservePercentage,
irParams,
timeDelta
) - reserveBalance
);
}
// src/modules/liquidation.ts
function calculateDrop(collaterals, currentDebt) {
const totalCollateralValue = collaterals.reduce((total, collateral) => {
if (!collateral.liquidationLTV) {
throw new Error("LiquidationLTV is not defined");
}
return total + collateral.amount * collateral.price * collateral.liquidationLTV;
}, 0);
if (totalCollateralValue == 0) {
return 0;
}
return 1 - currentDebt / totalCollateralValue;
}
function calculateLiquidationPoint(accountLiqLTV, debtShares, openInterest, totalDebtShares, totalAssets, irParams, timeDelta) {
const accountDebt = convertDebtSharesToAssets(
debtShares,
openInterest,
totalDebtShares,
totalAssets,
irParams,
timeDelta
);
return accountLiqLTV !== 0 ? accountDebt / accountLiqLTV : 0;
}
var liquidatorMaxRepayAmount = (debtShares, openInterest, totalDebtShares, totalAssets, irParams, timeDelta, collateral, allCollaterals) => {
if (!collateral.liquidationLTV || !collateral.liquidationPremium)
throw new Error("Liquidation LTV or liquidation premium are not defined");
const debtAssets = convertDebtSharesToAssets(
debtShares,
openInterest,
totalDebtShares,
totalAssets,
irParams,
timeDelta
);
const totalSecuredValue = allCollaterals.reduce((sum, coll) => {
if (!coll.liquidationLTV) {
throw new Error(
"LiquidationLTV is not defined for one or more collaterals"
);
}
return sum + coll.amount * coll.price * coll.liquidationLTV;
}, 0);
const denominator = 1 - (1 + collateral.liquidationPremium) * collateral.liquidationLTV;
const maxRepayCalc = (debtAssets - totalSecuredValue) / denominator;
const collateralValue = collateral.amount * collateral.price;
const collateralCap = collateralValue / (1 + collateral.liquidationPremium);
return Math.max(Math.min(maxRepayCalc, collateralCap), 0);
};
var calculateCollateralToTransfer = (repayAmount, collateral) => {
if (!collateral.liquidationPremium) {
throw new Error("Liquidation premium is not defined");
}
const liquidationReward = repayAmount * collateral.liquidationPremium;
return (repayAmount + liquidationReward) / collateral.price;
};
var liquidationRisk = (debtAssets, openInterest, totalDebtShares, totalAssets, protocolReservePercentage, irParams, timeDelta, initialDebtShares, initialOpenInterest, initialTotalDebtShares, initialTotalAssets, accountLiqLTV) => {
const debtShares = convertDebtAssetsToShares(
debtAssets,
totalDebtShares,
totalAssets,
openInterest,
protocolReservePercentage,
irParams,
timeDelta
);
const newDebtShares = initialDebtShares + debtShares;
const newOpenInterest = initialOpenInterest + debtAssets;
const newTotalDebtShares = initialTotalDebtShares + debtShares;
const newTotalAssets = initialTotalAssets - debtAssets;
return calculateLiquidationPoint(
accountLiqLTV,
newDebtShares,
newOpenInterest,
newTotalDebtShares,
newTotalAssets,
irParams,
timeDelta
);
};
// src/modules/lpRewards.ts
function calculateLpRewardApy(totalLpShares, userLpShares, epoch) {
if (userLpShares <= 0)
throw new Error("User LP shares amount must be positive");
const shareRatio = userLpShares / totalLpShares;
const perSecondRewards = epoch.totalRewards / (epoch.endTimestamp - epoch.startTimestamp);
const userPerSecondRewards = shareRatio * perSecondRewards;
return userPerSecondRewards * secondsInAYear / userLpShares;
}
function estimatedRewards(depositAmount, apr, durationInSeconds) {
if (depositAmount <= 0) throw new Error("Deposit amount must be positive");
if (apr < 0) throw new Error("APR cannot be negative");
if (durationInSeconds <= 0) throw new Error("Duration must be positive");
return depositAmount * apr * (durationInSeconds / secondsInAYear);
}
// src/modules/safetyModule.ts
function stakingRate(stakedLpShares, totalLpShares) {
if (totalLpShares == 0) return 0;
return stakedLpShares / totalLpShares;
}
function stakersRewardRate(sr, params) {
let rr;
if (sr < params.stakedPercentageKink)
rr = params.slope1 * sr + params.baseRewardRate;
else
rr = params.slope2 * (sr - params.stakedPercentageKink) + params.slope1 * params.stakedPercentageKink + params.baseRewardRate;
return rr;
}
function lpApyWithStaking(ur, irParams, protocolReservePercentage, sr, smParams) {
if (ur == 0) return 0;
else {
const rewardRate = stakersRewardRate(sr, smParams);
const lpAPR = annualizedAPR(ur, irParams) * (1 - rewardRate - protocolReservePercentage) * ur;
return (1 + lpAPR / secondsInAYear) ** secondsInAYear - 1;
}
}
function stakerBonus(ur, irParams, sr, smParams) {
if (ur == 0 || sr == 0) return 0;
else {
const rewardRate = stakersRewardRate(sr, smParams);
const lpAPR = annualizedAPR(ur, irParams) * rewardRate * ur / sr;
return (1 + lpAPR / secondsInAYear) ** secondsInAYear - 1;
}
}
function stakingAPY(ur, irParams, protocolReservePercentage, sr, smParams) {
const lpApy = lpApyWithStaking(
ur,
irParams,
protocolReservePercentage,
sr,
smParams
);
const stBonus = stakerBonus(ur, irParams, sr, smParams);
return lpApy + stBonus;
}
// src/modules/leverage.ts
function absoluteMaxLeverage(maxLTV) {
if (maxLTV >= 1 || maxLTV <= 0) throw new Error("Invalid maxLTV");
return 1 / (1 - maxLTV);
}
function correctedMaxLTV(collateral, flashLoanFee, slippage) {
if (!collateral.maxLTV) throw new Error("Invalid maxLTV");
return (1 - flashLoanFee - slippage) * collateral.maxLTV;
}
function unencumberedCollateral(debtShares, openInterest, totalDebtShares, totalAssets, irParams, timeDelta, collateral, maxLTVcorrected) {
const debt = convertDebtSharesToAssets(
debtShares,
openInterest,
totalDebtShares,
totalAssets,
irParams,
timeDelta
);
const encumberedCollateralValue = debt / maxLTVcorrected;
const totalCollateralValue = calculateTotalCollateralValue([collateral]);
return totalCollateralValue - encumberedCollateralValue;
}
function leverageMaxSlippage(collateralValue, slippage) {
if (slippage >= 1 || slippage < 0) throw new Error("Invalid slippage");
return collateralValue / (1 - slippage) - collateralValue;
}
function swapLoss(flashLoanAmount, quote, collateralPrice, marketAssetPrice) {
return flashLoanAmount - quote * collateralPrice / marketAssetPrice;
}
function computeFlashLoanValues(newCollateralValue, swapLoss2) {
const flashLoanValue = newCollateralValue + swapLoss2;
const slippage = swapLoss2 / flashLoanValue;
return { flashLoanValue, slippage };
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
absoluteMaxLeverage,
annualizedAPR,
calculateAccountHealth,
calculateAccountLTV,
calculateAccountLiqLTV,
calculateAccountMaxLTV,
calculateBorrowAPY,
calculateBorrowCapacity,
calculateCollateralToTransfer,
calculateDrop,
calculateDueInterest,
calculateLiquidationPoint,
calculateLpAPY,
calculateLpRewardApy,
calculateMaxRepayAmount,
calculateMaxWithdrawAmount,
calculateTotalCollateralValue,
compoundedInterest,
computeFlashLoanValues,
computeTotalEarning,
computeUtilizationRate,
convertDebtAssetsToShares,
convertDebtSharesToAssets,
convertLpAssetsToShares,
convertLpSharesToAssets,
correctedMaxLTV,
estimatedRewards,
leverageMaxSlippage,
liquidationRisk,
liquidatorMaxRepayAmount,
lpApyWithStaking,
protocolAvailableToBorrow,
secondsInAYear,
stakerBonus,
stakersRewardRate,
stakingAPY,
stakingRate,
swapLoss,
unencumberedCollateral,
userAvailableToBorrow
});