UNPKG

@ox-fun/drift-sdk

Version:

SDK for Drift Protocol

132 lines (112 loc) 3.35 kB
import { squareRootBN } from './utils'; import { SPOT_MARKET_WEIGHT_PRECISION, SPOT_MARKET_IMF_PRECISION, ZERO, BID_ASK_SPREAD_PRECISION, AMM_RESERVE_PRECISION, } from '../constants/numericConstants'; import { BN } from '@coral-xyz/anchor'; import { OraclePriceData } from '../oracles/types'; import { PerpMarketAccount, PerpPosition } from '..'; import { isVariant } from '../types'; import { assert } from '../assert/assert'; export function calculateSizePremiumLiabilityWeight( size: BN, // AMM_RESERVE_PRECISION imfFactor: BN, liabilityWeight: BN, precision: BN ): BN { if (imfFactor.eq(ZERO)) { return liabilityWeight; } const sizeSqrt = squareRootBN(size.abs().mul(new BN(10)).add(new BN(1))); //1e9 -> 1e10 -> 1e5 const liabilityWeightNumerator = liabilityWeight.sub( liabilityWeight.div(new BN(5)) ); const denom = new BN(100_000).mul(SPOT_MARKET_IMF_PRECISION).div(precision); assert(denom.gt(ZERO)); const sizePremiumLiabilityWeight = liabilityWeightNumerator.add( sizeSqrt // 1e5 .mul(imfFactor) .div(denom) // 1e5 ); const maxLiabilityWeight = BN.max( liabilityWeight, sizePremiumLiabilityWeight ); return maxLiabilityWeight; } export function calculateSizeDiscountAssetWeight( size: BN, // AMM_RESERVE_PRECISION imfFactor: BN, assetWeight: BN ): BN { if (imfFactor.eq(ZERO)) { return assetWeight; } const sizeSqrt = squareRootBN(size.abs().mul(new BN(10)).add(new BN(1))); //1e9 -> 1e10 -> 1e5 const imfNumerator = SPOT_MARKET_IMF_PRECISION.add( SPOT_MARKET_IMF_PRECISION.div(new BN(10)) ); const sizeDiscountAssetWeight = imfNumerator .mul(SPOT_MARKET_WEIGHT_PRECISION) .div( SPOT_MARKET_IMF_PRECISION.add( sizeSqrt // 1e5 .mul(imfFactor) .div(new BN(100_000)) // 1e5 ) ); const minAssetWeight = BN.min(assetWeight, sizeDiscountAssetWeight); return minAssetWeight; } export function calculateOraclePriceForPerpMargin( perpPosition: PerpPosition, market: PerpMarketAccount, oraclePriceData: OraclePriceData ): BN { const oraclePriceOffset = BN.min( new BN(market.amm.maxSpread) .mul(oraclePriceData.price) .div(BID_ASK_SPREAD_PRECISION), oraclePriceData.confidence.add( new BN(market.amm.baseSpread) .mul(oraclePriceData.price) .div(BID_ASK_SPREAD_PRECISION) ) ); let marginPrice: BN; if (perpPosition.baseAssetAmount.gt(ZERO)) { marginPrice = oraclePriceData.price.sub(oraclePriceOffset); } else { marginPrice = oraclePriceData.price.add(oraclePriceOffset); } return marginPrice; } export function calculateBaseAssetValueWithOracle( market: PerpMarketAccount, perpPosition: PerpPosition, oraclePriceData: OraclePriceData, includeOpenOrders = false ): BN { let price = oraclePriceData.price; if (isVariant(market.status, 'settlement')) { price = market.expiryPrice; } const baseAssetAmount = includeOpenOrders ? calculateWorstCaseBaseAssetAmount(perpPosition) : perpPosition.baseAssetAmount; return baseAssetAmount.abs().mul(price).div(AMM_RESERVE_PRECISION); } export function calculateWorstCaseBaseAssetAmount( perpPosition: PerpPosition ): BN { const allBids = perpPosition.baseAssetAmount.add(perpPosition.openBids); const allAsks = perpPosition.baseAssetAmount.add(perpPosition.openAsks); if (allBids.abs().gt(allAsks.abs())) { return allBids; } else { return allAsks; } }