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