UNPKG

@drift-labs/sdk

Version:
439 lines (438 loc) • 24.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getSpotLiabilityValue = exports.getSpotAssetValue = exports.calculateWithdrawLimit = exports.calculateTokenUtilizationLimits = exports.calculateInterestAccumulated = exports.calculateBorrowRate = exports.calculateDepositRate = exports.calculateInterestRate = exports.calculateSpotMarketBorrowCapacity = exports.calculateUtilization = exports.calculateLiabilityWeight = exports.calculateScaledInitialAssetWeight = exports.calculateAssetWeight = exports.getTokenValue = exports.getStrictTokenValue = exports.getSignedTokenAmount = exports.getTokenAmount = exports.getBalance = void 0; const types_1 = require("../types"); const anchor_1 = require("@coral-xyz/anchor"); const numericConstants_1 = require("../constants/numericConstants"); const margin_1 = require("./margin"); const numericConstants_2 = require("../constants/numericConstants"); const utils_1 = require("./utils"); /** * Calculates the balance of a given token amount including any accumulated interest. This * is the same as `SpotPosition.scaledBalance`. * * @param {BN} tokenAmount - the amount of tokens * @param {SpotMarketAccount} spotMarket - the spot market account * @param {SpotBalanceType} balanceType - the balance type ('deposit' or 'borrow') * @return {BN} the calculated balance, scaled by `SPOT_MARKET_BALANCE_PRECISION` */ function getBalance(tokenAmount, spotMarket, balanceType) { const precisionIncrease = numericConstants_1.TEN.pow(new anchor_1.BN(19 - spotMarket.decimals)); const cumulativeInterest = (0, types_1.isVariant)(balanceType, 'deposit') ? spotMarket.cumulativeDepositInterest : spotMarket.cumulativeBorrowInterest; let balance = tokenAmount.mul(precisionIncrease).div(cumulativeInterest); if (!balance.eq(numericConstants_1.ZERO) && (0, types_1.isVariant)(balanceType, 'borrow')) { balance = balance.add(numericConstants_1.ONE); } return balance; } exports.getBalance = getBalance; /** * Calculates the spot token amount including any accumulated interest. * * @param {BN} balanceAmount - The balance amount, typically from `SpotPosition.scaledBalance` * @param {SpotMarketAccount} spotMarket - The spot market account details * @param {SpotBalanceType} balanceType - The balance type to be used for calculation * @returns {BN} The calculated token amount, scaled by `SpotMarketConfig.precision` */ function getTokenAmount(balanceAmount, spotMarket, balanceType) { const precisionDecrease = numericConstants_1.TEN.pow(new anchor_1.BN(19 - spotMarket.decimals)); if ((0, types_1.isVariant)(balanceType, 'deposit')) { return balanceAmount .mul(spotMarket.cumulativeDepositInterest) .div(precisionDecrease); } else { return (0, utils_1.divCeil)(balanceAmount.mul(spotMarket.cumulativeBorrowInterest), precisionDecrease); } } exports.getTokenAmount = getTokenAmount; /** * Returns the signed (positive for deposit,negative for borrow) token amount based on the balance type. * * @param {BN} tokenAmount - The token amount to convert (from `getTokenAmount`) * @param {SpotBalanceType} balanceType - The balance type to determine the sign of the token amount. * @returns {BN} - The signed token amount, scaled by `SpotMarketConfig.precision` */ function getSignedTokenAmount(tokenAmount, balanceType) { if ((0, types_1.isVariant)(balanceType, 'deposit')) { return tokenAmount; } else { return tokenAmount.abs().neg(); } } exports.getSignedTokenAmount = getSignedTokenAmount; /** * Calculates the value of a given token amount using the worst of the provided oracle price and its TWAP. * * @param {BN} tokenAmount - The amount of tokens to calculate the value for (from `getTokenAmount`) * @param {number} spotDecimals - The number of decimals in the token. * @param {StrictOraclePrice} strictOraclePrice - Contains oracle price and 5min twap. * @return {BN} The calculated value of the given token amount, scaled by `PRICE_PRECISION` */ function getStrictTokenValue(tokenAmount, spotDecimals, strictOraclePrice) { if (tokenAmount.eq(numericConstants_1.ZERO)) { return numericConstants_1.ZERO; } let price; if (tokenAmount.gte(numericConstants_1.ZERO)) { price = strictOraclePrice.min(); } else { price = strictOraclePrice.max(); } const precisionDecrease = numericConstants_1.TEN.pow(new anchor_1.BN(spotDecimals)); return tokenAmount.mul(price).div(precisionDecrease); } exports.getStrictTokenValue = getStrictTokenValue; /** * Calculates the value of a given token amount in relation to an oracle price data * * @param {BN} tokenAmount - The amount of tokens to calculate the value for (from `getTokenAmount`) * @param {number} spotDecimals - The number of decimal places of the token. * @param {OraclePriceData} oraclePriceData - The oracle price data (typically a token/USD oracle). * @return {BN} The value of the token based on the oracle, scaled by `PRICE_PRECISION` */ function getTokenValue(tokenAmount, spotDecimals, oraclePriceData) { if (tokenAmount.eq(numericConstants_1.ZERO)) { return numericConstants_1.ZERO; } const precisionDecrease = numericConstants_1.TEN.pow(new anchor_1.BN(spotDecimals)); return tokenAmount.mul(oraclePriceData.price).div(precisionDecrease); } exports.getTokenValue = getTokenValue; function calculateAssetWeight(balanceAmount, oraclePrice, spotMarket, marginCategory) { const sizePrecision = numericConstants_1.TEN.pow(new anchor_1.BN(spotMarket.decimals)); let sizeInAmmReservePrecision; if (sizePrecision.gt(numericConstants_1.AMM_RESERVE_PRECISION)) { sizeInAmmReservePrecision = balanceAmount.div(sizePrecision.div(numericConstants_1.AMM_RESERVE_PRECISION)); } else { sizeInAmmReservePrecision = balanceAmount .mul(numericConstants_1.AMM_RESERVE_PRECISION) .div(sizePrecision); } let assetWeight; switch (marginCategory) { case 'Initial': assetWeight = (0, margin_1.calculateSizeDiscountAssetWeight)(sizeInAmmReservePrecision, new anchor_1.BN(spotMarket.imfFactor), calculateScaledInitialAssetWeight(spotMarket, oraclePrice)); break; case 'Maintenance': assetWeight = (0, margin_1.calculateSizeDiscountAssetWeight)(sizeInAmmReservePrecision, new anchor_1.BN(spotMarket.imfFactor), new anchor_1.BN(spotMarket.maintenanceAssetWeight)); break; default: assetWeight = calculateScaledInitialAssetWeight(spotMarket, oraclePrice); break; } return assetWeight; } exports.calculateAssetWeight = calculateAssetWeight; function calculateScaledInitialAssetWeight(spotMarket, oraclePrice) { if (spotMarket.scaleInitialAssetWeightStart.eq(numericConstants_1.ZERO)) { return new anchor_1.BN(spotMarket.initialAssetWeight); } const deposits = getTokenAmount(spotMarket.depositBalance, spotMarket, types_1.SpotBalanceType.DEPOSIT); const depositsValue = getTokenValue(deposits, spotMarket.decimals, { price: oraclePrice, }); if (depositsValue.lt(spotMarket.scaleInitialAssetWeightStart)) { return new anchor_1.BN(spotMarket.initialAssetWeight); } else { return new anchor_1.BN(spotMarket.initialAssetWeight) .mul(spotMarket.scaleInitialAssetWeightStart) .div(depositsValue); } } exports.calculateScaledInitialAssetWeight = calculateScaledInitialAssetWeight; function calculateLiabilityWeight(size, spotMarket, marginCategory) { const sizePrecision = numericConstants_1.TEN.pow(new anchor_1.BN(spotMarket.decimals)); let sizeInAmmReservePrecision; if (sizePrecision.gt(numericConstants_1.AMM_RESERVE_PRECISION)) { sizeInAmmReservePrecision = size.div(sizePrecision.div(numericConstants_1.AMM_RESERVE_PRECISION)); } else { sizeInAmmReservePrecision = size .mul(numericConstants_1.AMM_RESERVE_PRECISION) .div(sizePrecision); } let liabilityWeight; switch (marginCategory) { case 'Initial': liabilityWeight = (0, margin_1.calculateSizePremiumLiabilityWeight)(sizeInAmmReservePrecision, new anchor_1.BN(spotMarket.imfFactor), new anchor_1.BN(spotMarket.initialLiabilityWeight), numericConstants_1.SPOT_MARKET_WEIGHT_PRECISION); break; case 'Maintenance': liabilityWeight = (0, margin_1.calculateSizePremiumLiabilityWeight)(sizeInAmmReservePrecision, new anchor_1.BN(spotMarket.imfFactor), new anchor_1.BN(spotMarket.maintenanceLiabilityWeight), numericConstants_1.SPOT_MARKET_WEIGHT_PRECISION); break; default: liabilityWeight = new anchor_1.BN(spotMarket.initialLiabilityWeight); break; } return liabilityWeight; } exports.calculateLiabilityWeight = calculateLiabilityWeight; function calculateUtilization(bank, delta = numericConstants_1.ZERO) { let tokenDepositAmount = getTokenAmount(bank.depositBalance, bank, types_1.SpotBalanceType.DEPOSIT); let tokenBorrowAmount = getTokenAmount(bank.borrowBalance, bank, types_1.SpotBalanceType.BORROW); if (delta.gt(numericConstants_1.ZERO)) { tokenDepositAmount = tokenDepositAmount.add(delta); } else if (delta.lt(numericConstants_1.ZERO)) { tokenBorrowAmount = tokenBorrowAmount.add(delta.abs()); } let utilization; if (tokenBorrowAmount.eq(numericConstants_1.ZERO) && tokenDepositAmount.eq(numericConstants_1.ZERO)) { utilization = numericConstants_1.ZERO; } else if (tokenDepositAmount.eq(numericConstants_1.ZERO)) { utilization = numericConstants_1.SPOT_MARKET_UTILIZATION_PRECISION; } else { utilization = tokenBorrowAmount .mul(numericConstants_1.SPOT_MARKET_UTILIZATION_PRECISION) .div(tokenDepositAmount); } return utilization; } exports.calculateUtilization = calculateUtilization; /** * calculates max borrow amount where rate would stay below targetBorrowRate * @param spotMarketAccount * @param targetBorrowRate * @returns : Precision: TOKEN DECIMALS */ function calculateSpotMarketBorrowCapacity(spotMarketAccount, targetBorrowRate) { const currentBorrowRate = calculateBorrowRate(spotMarketAccount); const tokenDepositAmount = getTokenAmount(spotMarketAccount.depositBalance, spotMarketAccount, types_1.SpotBalanceType.DEPOSIT); const tokenBorrowAmount = getTokenAmount(spotMarketAccount.borrowBalance, spotMarketAccount, types_1.SpotBalanceType.BORROW); let targetUtilization; // target utilization past mid point if (targetBorrowRate.gte(new anchor_1.BN(spotMarketAccount.optimalBorrowRate))) { const borrowRateSlope = new anchor_1.BN(spotMarketAccount.maxBorrowRate - spotMarketAccount.optimalBorrowRate) .mul(numericConstants_1.SPOT_MARKET_UTILIZATION_PRECISION) .div(numericConstants_1.SPOT_MARKET_UTILIZATION_PRECISION.sub(new anchor_1.BN(spotMarketAccount.optimalUtilization))); const surplusTargetUtilization = targetBorrowRate .sub(new anchor_1.BN(spotMarketAccount.optimalBorrowRate)) .mul(numericConstants_1.SPOT_MARKET_UTILIZATION_PRECISION) .div(borrowRateSlope); targetUtilization = surplusTargetUtilization.add(new anchor_1.BN(spotMarketAccount.optimalUtilization)); } else { const borrowRateSlope = new anchor_1.BN(spotMarketAccount.optimalBorrowRate) .mul(numericConstants_1.SPOT_MARKET_UTILIZATION_PRECISION) .div(new anchor_1.BN(spotMarketAccount.optimalUtilization)); targetUtilization = targetBorrowRate .mul(numericConstants_1.SPOT_MARKET_UTILIZATION_PRECISION) .div(borrowRateSlope); } const totalCapacity = tokenDepositAmount .mul(targetUtilization) .div(numericConstants_1.SPOT_MARKET_UTILIZATION_PRECISION); let remainingCapacity; if (currentBorrowRate.gte(targetBorrowRate)) { remainingCapacity = numericConstants_1.ZERO; } else { remainingCapacity = anchor_1.BN.max(numericConstants_1.ZERO, totalCapacity.sub(tokenBorrowAmount)); } if (spotMarketAccount.maxTokenBorrowsFraction > 0) { const maxTokenBorrows = spotMarketAccount.maxTokenDeposits .mul(new anchor_1.BN(spotMarketAccount.maxTokenBorrowsFraction)) .divn(10000); remainingCapacity = anchor_1.BN.min(remainingCapacity, anchor_1.BN.max(numericConstants_1.ZERO, maxTokenBorrows.sub(tokenBorrowAmount))); } return { totalCapacity, remainingCapacity }; } exports.calculateSpotMarketBorrowCapacity = calculateSpotMarketBorrowCapacity; function calculateInterestRate(bank, delta = numericConstants_1.ZERO, currentUtilization = null) { // todo: ensure both a delta and current util aren't pass? const utilization = currentUtilization || calculateUtilization(bank, delta); const optimalUtil = new anchor_1.BN(bank.optimalUtilization); const optimalRate = new anchor_1.BN(bank.optimalBorrowRate); const maxRate = new anchor_1.BN(bank.maxBorrowRate); const minRate = new anchor_1.BN(bank.minBorrowRate).mul(numericConstants_2.PERCENTAGE_PRECISION.divn(200)); const weightsDivisor = new anchor_1.BN(1000); const segments = [ [new anchor_1.BN(850000), new anchor_1.BN(50)], [new anchor_1.BN(900000), new anchor_1.BN(100)], [new anchor_1.BN(950000), new anchor_1.BN(150)], [new anchor_1.BN(990000), new anchor_1.BN(200)], [new anchor_1.BN(995000), new anchor_1.BN(250)], [numericConstants_1.SPOT_MARKET_UTILIZATION_PRECISION, new anchor_1.BN(250)], ]; let rate; if (utilization.lte(optimalUtil)) { // below optimal: linear ramp from 0 to optimalRate const slope = optimalRate .mul(numericConstants_1.SPOT_MARKET_UTILIZATION_PRECISION) .div(optimalUtil); rate = utilization.mul(slope).div(numericConstants_1.SPOT_MARKET_UTILIZATION_PRECISION); } else { // above optimal: piecewise segments const totalExtraRate = maxRate.sub(optimalRate); rate = optimalRate.clone(); let prevUtil = optimalUtil.clone(); for (const [bp, weight] of segments) { const segmentEnd = bp.gt(numericConstants_1.SPOT_MARKET_UTILIZATION_PRECISION) ? numericConstants_1.SPOT_MARKET_UTILIZATION_PRECISION : bp; const segmentRange = segmentEnd.sub(prevUtil); const segmentRateTotal = totalExtraRate.mul(weight).div(weightsDivisor); if (utilization.lte(segmentEnd)) { const partialUtil = utilization.sub(prevUtil); const partialRate = segmentRateTotal.mul(partialUtil).div(segmentRange); rate = rate.add(partialRate); break; } else { rate = rate.add(segmentRateTotal); prevUtil = segmentEnd; } } } return anchor_1.BN.max(minRate, rate); } exports.calculateInterestRate = calculateInterestRate; function calculateDepositRate(bank, delta = numericConstants_1.ZERO, currentUtilization = null) { // positive delta => adding to deposit // negative delta => adding to borrow const utilization = currentUtilization || calculateUtilization(bank, delta); const borrowRate = calculateBorrowRate(bank, delta, utilization); const depositRate = borrowRate .mul(numericConstants_2.PERCENTAGE_PRECISION.sub(new anchor_1.BN(bank.insuranceFund.totalFactor))) .mul(utilization) .div(numericConstants_1.SPOT_MARKET_UTILIZATION_PRECISION) .div(numericConstants_2.PERCENTAGE_PRECISION); return depositRate; } exports.calculateDepositRate = calculateDepositRate; function calculateBorrowRate(bank, delta = numericConstants_1.ZERO, currentUtilization = null) { return calculateInterestRate(bank, delta, currentUtilization); } exports.calculateBorrowRate = calculateBorrowRate; function calculateInterestAccumulated(bank, now) { const interestRate = calculateInterestRate(bank); const timeSinceLastUpdate = now.sub(bank.lastInterestTs); const modifiedBorrowRate = interestRate.mul(timeSinceLastUpdate); const utilization = calculateUtilization(bank); const modifiedDepositRate = modifiedBorrowRate .mul(utilization) .div(numericConstants_1.SPOT_MARKET_UTILIZATION_PRECISION); const borrowInterest = bank.cumulativeBorrowInterest .mul(modifiedBorrowRate) .div(numericConstants_1.ONE_YEAR) .div(numericConstants_1.SPOT_MARKET_RATE_PRECISION) .add(numericConstants_1.ONE); const depositInterest = bank.cumulativeDepositInterest .mul(modifiedDepositRate) .div(numericConstants_1.ONE_YEAR) .div(numericConstants_1.SPOT_MARKET_RATE_PRECISION); return { borrowInterest, depositInterest }; } exports.calculateInterestAccumulated = calculateInterestAccumulated; function calculateTokenUtilizationLimits(depositTokenAmount, borrowTokenAmount, spotMarket) { // Calculates the allowable minimum deposit and maximum borrow amounts for immediate withdrawal based on market utilization. // First, it determines a maximum withdrawal utilization from the market's target and historic utilization. // Then, it deduces corresponding deposit/borrow amounts. // Note: For deposit sizes below the guard threshold, withdrawals aren't blocked. const maxWithdrawUtilization = anchor_1.BN.max(new anchor_1.BN(spotMarket.optimalUtilization), spotMarket.utilizationTwap.add(numericConstants_1.SPOT_MARKET_UTILIZATION_PRECISION.sub(spotMarket.utilizationTwap).div(new anchor_1.BN(2)))); let minDepositTokensForUtilization = borrowTokenAmount .mul(numericConstants_1.SPOT_MARKET_UTILIZATION_PRECISION) .div(maxWithdrawUtilization); // don't block withdraws for deposit sizes below guard threshold minDepositTokensForUtilization = anchor_1.BN.min(minDepositTokensForUtilization, depositTokenAmount.sub(spotMarket.withdrawGuardThreshold)); let maxBorrowTokensForUtilization = maxWithdrawUtilization .mul(depositTokenAmount) .div(numericConstants_1.SPOT_MARKET_UTILIZATION_PRECISION); maxBorrowTokensForUtilization = anchor_1.BN.max(spotMarket.withdrawGuardThreshold, maxBorrowTokensForUtilization); return { minDepositTokensForUtilization, maxBorrowTokensForUtilization, }; } exports.calculateTokenUtilizationLimits = calculateTokenUtilizationLimits; function calculateWithdrawLimit(spotMarket, now) { const marketDepositTokenAmount = getTokenAmount(spotMarket.depositBalance, spotMarket, types_1.SpotBalanceType.DEPOSIT); const marketBorrowTokenAmount = getTokenAmount(spotMarket.borrowBalance, spotMarket, types_1.SpotBalanceType.BORROW); const twentyFourHours = new anchor_1.BN(60 * 60 * 24); const sinceLast = now.sub(spotMarket.lastTwapTs); const sinceStart = anchor_1.BN.max(numericConstants_1.ZERO, twentyFourHours.sub(sinceLast)); const borrowTokenTwapLive = spotMarket.borrowTokenTwap .mul(sinceStart) .add(marketBorrowTokenAmount.mul(sinceLast)) .div(sinceLast.add(sinceStart)); const depositTokenTwapLive = spotMarket.depositTokenTwap .mul(sinceStart) .add(marketDepositTokenAmount.mul(sinceLast)) .div(sinceLast.add(sinceStart)); const lesserDepositAmount = anchor_1.BN.min(marketDepositTokenAmount, depositTokenTwapLive); let maxBorrowTokensTwap; if (spotMarket.poolId == 0) { maxBorrowTokensTwap = anchor_1.BN.max(spotMarket.withdrawGuardThreshold, anchor_1.BN.min(anchor_1.BN.max(marketDepositTokenAmount.div(new anchor_1.BN(3)), borrowTokenTwapLive.add(lesserDepositAmount.div(new anchor_1.BN(7)))), lesserDepositAmount.sub(lesserDepositAmount.div(new anchor_1.BN(8))))); // main pool between ~30-92.5% utilization with friction on twap in 20% increments } else { maxBorrowTokensTwap = anchor_1.BN.max(spotMarket.withdrawGuardThreshold, anchor_1.BN.min(anchor_1.BN.max(marketDepositTokenAmount.div(new anchor_1.BN(2)), borrowTokenTwapLive.add(lesserDepositAmount.div(new anchor_1.BN(3)))), lesserDepositAmount.sub(lesserDepositAmount.div(new anchor_1.BN(20))))); // isolated pools between 50-95% utilization with friction on twap in 33% increments } const minDepositTokensTwap = depositTokenTwapLive.sub(anchor_1.BN.max(depositTokenTwapLive.div(new anchor_1.BN(4)), anchor_1.BN.min(spotMarket.withdrawGuardThreshold, depositTokenTwapLive))); const { minDepositTokensForUtilization, maxBorrowTokensForUtilization } = calculateTokenUtilizationLimits(marketDepositTokenAmount, marketBorrowTokenAmount, spotMarket); const minDepositTokens = anchor_1.BN.max(minDepositTokensForUtilization, minDepositTokensTwap); let maxBorrowTokens = anchor_1.BN.min(maxBorrowTokensForUtilization, maxBorrowTokensTwap); const withdrawLimit = anchor_1.BN.max(marketDepositTokenAmount.sub(minDepositTokens), numericConstants_1.ZERO); let borrowLimit = maxBorrowTokens.sub(marketBorrowTokenAmount); borrowLimit = anchor_1.BN.min(borrowLimit, marketDepositTokenAmount.sub(marketBorrowTokenAmount)); if (spotMarket.maxTokenBorrowsFraction > 0) { const maxTokenBorrowsByFraction = spotMarket.maxTokenDeposits .mul(new anchor_1.BN(spotMarket.maxTokenBorrowsFraction)) .divn(10000); const trueMaxBorrowTokensAvailable = maxTokenBorrowsByFraction.sub(marketBorrowTokenAmount); maxBorrowTokens = anchor_1.BN.min(maxBorrowTokens, trueMaxBorrowTokensAvailable); borrowLimit = anchor_1.BN.min(borrowLimit, maxBorrowTokens); } if (withdrawLimit.eq(numericConstants_1.ZERO) || (0, types_1.isVariant)(spotMarket.assetTier, 'protected')) { borrowLimit = numericConstants_1.ZERO; } return { borrowLimit, withdrawLimit, maxBorrowAmount: maxBorrowTokens, minDepositAmount: minDepositTokens, currentDepositAmount: marketDepositTokenAmount, currentBorrowAmount: marketBorrowTokenAmount, }; } exports.calculateWithdrawLimit = calculateWithdrawLimit; function getSpotAssetValue(tokenAmount, strictOraclePrice, spotMarketAccount, maxMarginRatio, marginCategory) { let assetValue = getStrictTokenValue(tokenAmount, spotMarketAccount.decimals, strictOraclePrice); if (marginCategory !== undefined) { let weight = calculateAssetWeight(tokenAmount, strictOraclePrice.current, spotMarketAccount, marginCategory); if (marginCategory === 'Initial' && spotMarketAccount.marketIndex !== numericConstants_1.QUOTE_SPOT_MARKET_INDEX) { const userCustomAssetWeight = anchor_1.BN.max(numericConstants_1.ZERO, numericConstants_1.SPOT_MARKET_WEIGHT_PRECISION.subn(maxMarginRatio)); weight = anchor_1.BN.min(weight, userCustomAssetWeight); } assetValue = assetValue.mul(weight).div(numericConstants_1.SPOT_MARKET_WEIGHT_PRECISION); } return assetValue; } exports.getSpotAssetValue = getSpotAssetValue; function getSpotLiabilityValue(tokenAmount, strictOraclePrice, spotMarketAccount, maxMarginRatio, marginCategory, liquidationBuffer) { let liabilityValue = getStrictTokenValue(tokenAmount, spotMarketAccount.decimals, strictOraclePrice); if (marginCategory !== undefined) { let weight = calculateLiabilityWeight(tokenAmount, spotMarketAccount, marginCategory); if (marginCategory === 'Initial' && spotMarketAccount.marketIndex !== numericConstants_1.QUOTE_SPOT_MARKET_INDEX) { weight = anchor_1.BN.max(weight, numericConstants_1.SPOT_MARKET_WEIGHT_PRECISION.addn(maxMarginRatio)); } if (liquidationBuffer !== undefined) { weight = weight.add(liquidationBuffer); } liabilityValue = liabilityValue .mul(weight) .div(numericConstants_1.SPOT_MARKET_WEIGHT_PRECISION); } return liabilityValue; } exports.getSpotLiabilityValue = getSpotLiabilityValue;