UNPKG

granite-math-sdk

Version:

Granite math sdk

496 lines (486 loc) 18.4 kB
"use strict"; 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 });