UNPKG

@drift-labs/sdk

Version:
135 lines (134 loc) 6.92 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getMarginShortage = exports.calculateMaxPctToLiquidate = exports.calculateAssetTransferForLiabilityTransfer = exports.calculateLiabilityTransferToCoverMarginShortage = exports.calculateBaseAssetAmountToCoverMarginShortage = void 0; const anchor_1 = require("@coral-xyz/anchor"); const numericConstants_1 = require("../constants/numericConstants"); function calculateBaseAssetAmountToCoverMarginShortage(marginShortage, marginRatio, liquidationFee, ifLiquidationFee, oraclePrice, quoteOraclePrice) { const marginRatioBN = new anchor_1.BN(marginRatio) .mul(numericConstants_1.LIQUIDATION_FEE_PRECISION) .div(numericConstants_1.MARGIN_PRECISION); const liquidationFeeBN = new anchor_1.BN(liquidationFee); if (oraclePrice.eq(new anchor_1.BN(0)) || marginRatioBN.lte(liquidationFeeBN)) { // undefined is max return undefined; } return marginShortage.mul(numericConstants_1.PRICE_TIMES_AMM_TO_QUOTE_PRECISION_RATIO).div(oraclePrice .mul(quoteOraclePrice) .div(numericConstants_1.PRICE_PRECISION) .mul(marginRatioBN.sub(liquidationFeeBN)) .div(numericConstants_1.LIQUIDATION_FEE_PRECISION) .sub(oraclePrice.mul(new anchor_1.BN(ifLiquidationFee)).div(numericConstants_1.LIQUIDATION_FEE_PRECISION))); } exports.calculateBaseAssetAmountToCoverMarginShortage = calculateBaseAssetAmountToCoverMarginShortage; function calculateLiabilityTransferToCoverMarginShortage(marginShortage, assetWeight, assetLiquidationMultiplier, liabilityWeight, liabilityLiquidationMultiplier, liabilityDecimals, liabilityPrice, ifLiquidationFee) { if (assetWeight >= liabilityWeight) { // undefined is max return undefined; } let numeratorScale; let denominatorScale; if (liabilityDecimals > 6) { numeratorScale = new anchor_1.BN(10).pow(new anchor_1.BN(liabilityDecimals - 6)); denominatorScale = new anchor_1.BN(1); } else { numeratorScale = new anchor_1.BN(1); denominatorScale = new anchor_1.BN(10).pow(new anchor_1.BN(6 - liabilityDecimals)); } // multiply market weights by extra 10 to increase precision const liabilityWeightComponent = liabilityWeight * 10; const assetWeightComponent = (assetWeight * 10 * assetLiquidationMultiplier) / liabilityLiquidationMultiplier; if (assetWeightComponent >= liabilityWeightComponent) { return undefined; } return anchor_1.BN.max(marginShortage .mul(numeratorScale) .mul(numericConstants_1.PRICE_PRECISION.mul(numericConstants_1.SPOT_MARKET_WEIGHT_PRECISION).mul(numericConstants_1.TEN)) .div(liabilityPrice .mul(new anchor_1.BN(liabilityWeightComponent).sub(new anchor_1.BN(assetWeightComponent))) .sub(liabilityPrice .mul(new anchor_1.BN(ifLiquidationFee)) .div(numericConstants_1.LIQUIDATION_FEE_PRECISION) .mul(new anchor_1.BN(liabilityWeight)) .mul(new anchor_1.BN(10)))) .div(denominatorScale), numericConstants_1.ONE); } exports.calculateLiabilityTransferToCoverMarginShortage = calculateLiabilityTransferToCoverMarginShortage; function calculateAssetTransferForLiabilityTransfer(assetAmount, assetLiquidationMultiplier, assetDecimals, assetPrice, liabilityAmount, liabilityLiquidationMultiplier, liabilityDecimals, liabilityPrice) { let numeratorScale; let denominatorScale; if (assetDecimals > liabilityDecimals) { numeratorScale = new anchor_1.BN(10).pow(new anchor_1.BN(assetDecimals - liabilityDecimals)); denominatorScale = new anchor_1.BN(1); } else { numeratorScale = new anchor_1.BN(1); denominatorScale = new anchor_1.BN(10).pow(new anchor_1.BN(liabilityDecimals - assetDecimals)); } let assetTransfer = liabilityAmount .mul(numeratorScale) .mul(liabilityPrice) .mul(new anchor_1.BN(assetLiquidationMultiplier)) .div(assetPrice.mul(new anchor_1.BN(liabilityLiquidationMultiplier))) .div(denominatorScale); assetTransfer = anchor_1.BN.max(assetTransfer, numericConstants_1.ONE); // Need to check if asset_transfer should be rounded to asset amount let assetValueNumeratorScale; let assetValueDenominatorScale; if (assetDecimals > 6) { assetValueNumeratorScale = new anchor_1.BN(10).pow(new anchor_1.BN(assetDecimals - 6)); assetValueDenominatorScale = new anchor_1.BN(1); } else { assetValueNumeratorScale = new anchor_1.BN(1); assetValueDenominatorScale = new anchor_1.BN(10).pow(new anchor_1.BN(6 - assetDecimals)); } let assetDelta; if (assetTransfer > assetAmount) { assetDelta = assetTransfer.sub(assetAmount); } else { assetDelta = assetAmount.sub(assetTransfer); } const assetValueDelta = assetDelta .mul(assetPrice) .div(numericConstants_1.PRICE_PRECISION) .mul(assetValueNumeratorScale) .div(assetValueDenominatorScale); if (assetValueDelta.lt(numericConstants_1.QUOTE_PRECISION)) { assetTransfer = assetAmount; } return assetTransfer; } exports.calculateAssetTransferForLiabilityTransfer = calculateAssetTransferForLiabilityTransfer; function calculateMaxPctToLiquidate(userLastActiveSlot, userLiquidationMarginFreed, marginShortage, slot, initialPctToLiquidate, liquidationDuration) { // if margin shortage is tiny, accelerate liquidation if (marginShortage.lt(new anchor_1.BN(50).mul(numericConstants_1.QUOTE_PRECISION))) { return numericConstants_1.LIQUIDATION_PCT_PRECISION; } let slotsElapsed; if (userLiquidationMarginFreed.gt(new anchor_1.BN(0))) { slotsElapsed = anchor_1.BN.max(slot.sub(userLastActiveSlot), new anchor_1.BN(0)); } else { slotsElapsed = new anchor_1.BN(0); } const pctFreeable = anchor_1.BN.min(slotsElapsed .mul(numericConstants_1.LIQUIDATION_PCT_PRECISION) .div(liquidationDuration) // ~ 1 minute if per slot is 400ms .add(initialPctToLiquidate), numericConstants_1.LIQUIDATION_PCT_PRECISION); const totalMarginShortage = marginShortage.add(userLiquidationMarginFreed); const maxMarginFreed = totalMarginShortage .mul(pctFreeable) .div(numericConstants_1.LIQUIDATION_PCT_PRECISION); const marginFreeable = anchor_1.BN.max(maxMarginFreed.sub(userLiquidationMarginFreed), new anchor_1.BN(0)); return marginFreeable.mul(numericConstants_1.LIQUIDATION_PCT_PRECISION).div(marginShortage); } exports.calculateMaxPctToLiquidate = calculateMaxPctToLiquidate; function getMarginShortage(maintenanceMarginRequirementPlusBuffer, maintenanceTotalCollateral) { return maintenanceMarginRequirementPlusBuffer .sub(maintenanceTotalCollateral) .abs(); } exports.getMarginShortage = getMarginShortage;