@drift-labs/common
Version:
Common functions for Drift
125 lines • 7.13 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.USER_UTILS = void 0;
const sdk_1 = require("@drift-labs/sdk");
const types_1 = require("../types");
const trading_1 = require("./trading");
const utils_1 = require("../utils");
const getOpenPositionData = (driftClient, userPositions, user, perpMarketLookup, markPriceCallback) => {
const oracleGuardRails = driftClient.getStateAccount().oracleGuardRails;
const newResult = userPositions
.filter((position) => !position.baseAssetAmount.eq(sdk_1.ZERO) ||
!position.quoteAssetAmount.eq(sdk_1.ZERO) ||
!position.lpShares.eq(sdk_1.ZERO))
.map((position) => {
var _a, _b, _c;
const perpMarketConfig = perpMarketLookup[position.marketIndex];
const perpMarket = driftClient.getPerpMarketAccount(position.marketIndex);
const usdcSpotMarket = driftClient.getSpotMarketAccount(sdk_1.QUOTE_SPOT_MARKET_INDEX);
const oraclePriceData = driftClient.getOracleDataForPerpMarket(position.marketIndex);
let oraclePrice = oraclePriceData.price;
// mark price fetched with a callback so we don't need extra dlob server calls. fallback to oracle
let markPrice = markPriceCallback
? (_a = markPriceCallback(position.marketIndex)) !== null && _a !== void 0 ? _a : oraclePriceData.price
: oraclePriceData.price;
let estExitPrice = user.getPositionEstimatedExitPriceAndPnl(position, position.baseAssetAmount)[0];
const entryPrice = (0, sdk_1.calculateEntryPrice)(position);
const isShort = position.baseAssetAmount.isNeg();
if (types_1.UIMarket.checkIsPredictionMarket(perpMarketConfig)) {
const isResolved = utils_1.ENUM_UTILS.match(perpMarket === null || perpMarket === void 0 ? void 0 : perpMarket.status, sdk_1.MarketStatus.SETTLEMENT) ||
utils_1.ENUM_UTILS.match(perpMarket === null || perpMarket === void 0 ? void 0 : perpMarket.status, sdk_1.MarketStatus.DELISTED);
if (isResolved) {
const resolvedToNo = perpMarket.expiryPrice.lte(sdk_1.ZERO.add(perpMarket.amm.orderTickSize));
const price = resolvedToNo
? sdk_1.ZERO.mul(sdk_1.PRICE_PRECISION)
: sdk_1.ONE.mul(sdk_1.PRICE_PRECISION);
estExitPrice = price;
markPrice = price;
oraclePrice = price;
}
}
// if for any reason oracle or mark price blips to 0, fallback to the other one so we don't show a crazy pnl
if (markPrice.lte(sdk_1.ZERO) && oraclePrice.gt(sdk_1.ZERO)) {
markPrice = oraclePrice;
}
if (oraclePrice.lte(sdk_1.ZERO) && markPrice.gt(sdk_1.ZERO)) {
oraclePrice = markPrice;
}
const pnlVsMark = trading_1.TRADING_UTILS.calculatePotentialProfit({
currentPositionSize: sdk_1.BigNum.from(position.baseAssetAmount.abs(), sdk_1.BASE_PRECISION_EXP),
currentPositionDirection: isShort
? sdk_1.PositionDirection.SHORT
: sdk_1.PositionDirection.LONG,
currentPositionEntryPrice: sdk_1.BigNum.from(entryPrice, sdk_1.PRICE_PRECISION_EXP),
tradeDirection: isShort
? sdk_1.PositionDirection.LONG
: sdk_1.PositionDirection.SHORT,
exitBaseSize: sdk_1.BigNum.from(position.baseAssetAmount.abs(), sdk_1.BASE_PRECISION_EXP),
exitPrice: sdk_1.BigNum.from(markPrice, sdk_1.PRICE_PRECISION_EXP),
takerFeeBps: 0,
}).estimatedProfit.shiftTo(sdk_1.QUOTE_PRECISION_EXP).val;
const pnlVsOracle = trading_1.TRADING_UTILS.calculatePotentialProfit({
currentPositionSize: sdk_1.BigNum.from(position.baseAssetAmount.abs(), sdk_1.BASE_PRECISION_EXP),
currentPositionDirection: isShort
? sdk_1.PositionDirection.SHORT
: sdk_1.PositionDirection.LONG,
currentPositionEntryPrice: sdk_1.BigNum.from(entryPrice, sdk_1.PRICE_PRECISION_EXP),
tradeDirection: isShort
? sdk_1.PositionDirection.LONG
: sdk_1.PositionDirection.SHORT,
exitBaseSize: sdk_1.BigNum.from(position.baseAssetAmount.abs(), sdk_1.BASE_PRECISION_EXP),
exitPrice: sdk_1.BigNum.from(oraclePrice, sdk_1.PRICE_PRECISION_EXP),
takerFeeBps: 0,
}).estimatedProfit.shiftTo(sdk_1.QUOTE_PRECISION_EXP).val;
return {
marketIndex: position.marketIndex,
marketSymbol: perpMarketConfig.symbol,
direction: isShort ? 'short' : 'long',
notional: user
.getPerpPositionValue(position.marketIndex, oraclePriceData)
.abs(),
baseSize: position.baseAssetAmount,
markPrice,
entryPrice,
exitPrice: estExitPrice,
liqPrice: user.liquidationPrice(position.marketIndex, sdk_1.ZERO),
quoteAssetNotionalAmount: position.quoteAssetAmount,
quoteEntryAmount: position.quoteEntryAmount,
quoteBreakEvenAmount: position.quoteBreakEvenAmount,
pnlVsMark,
pnlVsOracle,
unsettledPnl: (0, sdk_1.calculateClaimablePnl)(perpMarket, usdcSpotMarket, position, oraclePriceData),
unsettledFundingPnl: (0, sdk_1.calculateUnsettledFundingPnl)(perpMarket, position),
// Includes both settled and unsettled funding as well as fees
feesAndFundingPnl: (0, sdk_1.calculateFeesAndFundingPnl)(perpMarket, position),
totalUnrealizedPnl: (0, sdk_1.calculatePositionPNL)(perpMarket, position, true, oraclePriceData),
unrealizedFundingPnl: user.getUnrealizedFundingPNL(position.marketIndex),
lastCumulativeFundingRate: position.lastCumulativeFundingRate,
openOrders: position.openOrders,
costBasis: (0, sdk_1.calculateCostBasis)(position),
realizedPnl: position.settledPnl,
pnlIsClaimable: (0, sdk_1.isOracleValid)(perpMarket, oraclePriceData, oracleGuardRails, (_b = perpMarket.amm.lastUpdateSlot) === null || _b === void 0 ? void 0 : _b.toNumber()),
lpShares: position.lpShares,
remainderBaseAmount: (_c = position.remainderBaseAssetAmount) !== null && _c !== void 0 ? _c : 0,
lpDeriskPrice: user.liquidationPrice(position.marketIndex, undefined, undefined, 'Initial', true),
maxMarginRatio: position.maxMarginRatio,
};
});
return newResult;
};
const checkIfUserAccountExists = async (driftClient, config) => {
let userPubKey;
if (config.type === 'userPubKey') {
userPubKey = config.userPubKey;
}
else {
userPubKey = (0, sdk_1.getUserAccountPublicKeySync)(driftClient.program.programId, config.authority, config.subAccountId);
}
const accountInfo = await driftClient.connection.getAccountInfo(userPubKey);
return accountInfo !== null;
};
exports.USER_UTILS = {
getOpenPositionData,
checkIfUserAccountExists,
};
//# sourceMappingURL=user.js.map
;