@drift-labs/sdk
Version:
SDK for Drift Protocol
439 lines (438 loc) • 24.2 kB
JavaScript
"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;