@drift-labs/sdk-browser
Version:
SDK for Drift Protocol
398 lines (397 loc) • 19.7 kB
TypeScript
/// <reference types="node" />
/// <reference types="bn.js" />
import { PublicKey } from '@solana/web3.js';
import { EventEmitter } from 'events';
import StrictEventEmitter from 'strict-event-emitter-types';
import { DriftClient } from './driftClient';
import { HealthComponent, HealthComponents, MarginCategory, Order, PerpMarketAccount, PerpPosition, SpotPosition, UserAccount, UserStatus } from './types';
import { DataAndSlot, UserAccountEvents, UserAccountSubscriber } from './accounts/types';
import { BN } from '@coral-xyz/anchor';
import { MarketType, PositionDirection, SpotMarketAccount } from './types';
import { UserStats } from './userStats';
import { OraclePriceData } from './oracles/types';
import { UserConfig } from './userConfig';
import { StrictOraclePrice } from './oracles/strictOraclePrice';
export declare class User {
driftClient: DriftClient;
userAccountPublicKey: PublicKey;
accountSubscriber: UserAccountSubscriber;
_isSubscribed: boolean;
eventEmitter: StrictEventEmitter<EventEmitter, UserAccountEvents>;
get isSubscribed(): boolean;
set isSubscribed(val: boolean);
constructor(config: UserConfig);
/**
* Subscribe to User state accounts
* @returns SusbcriptionSuccess result
*/
subscribe(userAccount?: UserAccount): Promise<boolean>;
/**
* Forces the accountSubscriber to fetch account updates from rpc
*/
fetchAccounts(): Promise<void>;
unsubscribe(): Promise<void>;
getUserAccount(): UserAccount;
forceGetUserAccount(): Promise<UserAccount>;
getUserAccountAndSlot(): DataAndSlot<UserAccount> | undefined;
getPerpPositionForUserAccount(userAccount: UserAccount, marketIndex: number): PerpPosition | undefined;
/**
* Gets the user's current position for a given perp market. If the user has no position returns undefined
* @param marketIndex
* @returns userPerpPosition
*/
getPerpPosition(marketIndex: number): PerpPosition | undefined;
getPerpPositionOrEmpty(marketIndex: number): PerpPosition;
getPerpPositionAndSlot(marketIndex: number): DataAndSlot<PerpPosition | undefined>;
getSpotPositionForUserAccount(userAccount: UserAccount, marketIndex: number): SpotPosition | undefined;
/**
* Gets the user's current position for a given spot market. If the user has no position returns undefined
* @param marketIndex
* @returns userSpotPosition
*/
getSpotPosition(marketIndex: number): SpotPosition | undefined;
getSpotPositionAndSlot(marketIndex: number): DataAndSlot<SpotPosition | undefined>;
getEmptySpotPosition(marketIndex: number): SpotPosition;
/**
* Returns the token amount for a given market. The spot market precision is based on the token mint decimals.
* Positive if it is a deposit, negative if it is a borrow.
*
* @param marketIndex
*/
getTokenAmount(marketIndex: number): BN;
getEmptyPosition(marketIndex: number): PerpPosition;
getClonedPosition(position: PerpPosition): PerpPosition;
getOrderForUserAccount(userAccount: UserAccount, orderId: number): Order | undefined;
/**
* @param orderId
* @returns Order
*/
getOrder(orderId: number): Order | undefined;
getOrderAndSlot(orderId: number): DataAndSlot<Order | undefined>;
getOrderByUserIdForUserAccount(userAccount: UserAccount, userOrderId: number): Order | undefined;
/**
* @param userOrderId
* @returns Order
*/
getOrderByUserOrderId(userOrderId: number): Order | undefined;
getOrderByUserOrderIdAndSlot(userOrderId: number): DataAndSlot<Order | undefined>;
getOpenOrdersForUserAccount(userAccount?: UserAccount): Order[];
getOpenOrders(): Order[];
getOpenOrdersAndSlot(): DataAndSlot<Order[]>;
getUserAccountPublicKey(): PublicKey;
exists(): Promise<boolean>;
/**
* calculates the total open bids/asks in a perp market (including lps)
* @returns : open bids
* @returns : open asks
*/
getPerpBidAsks(marketIndex: number): [BN, BN];
/**
* calculates Buying Power = free collateral / initial margin ratio
* @returns : Precision QUOTE_PRECISION
*/
getPerpBuyingPower(marketIndex: number, collateralBuffer?: BN, enterHighLeverageMode?: any): BN;
getPerpBuyingPowerFromFreeCollateralAndBaseAssetAmount(marketIndex: number, freeCollateral: BN, baseAssetAmount: BN, enterHighLeverageMode?: any, perpPosition?: PerpPosition): BN;
/**
* calculates Free Collateral = Total collateral - margin requirement
* @returns : Precision QUOTE_PRECISION
*/
getFreeCollateral(marginCategory?: MarginCategory, enterHighLeverageMode?: any): BN;
/**
* @returns The margin requirement of a certain type (Initial or Maintenance) in USDC. : QUOTE_PRECISION
*/
getMarginRequirement(marginCategory: MarginCategory, liquidationBuffer?: BN, strict?: boolean, includeOpenOrders?: boolean, enteringHighLeverage?: any): BN;
/**
* @returns The initial margin requirement in USDC. : QUOTE_PRECISION
*/
getInitialMarginRequirement(enterHighLeverageMode?: any): BN;
/**
* @returns The maintenance margin requirement in USDC. : QUOTE_PRECISION
*/
getMaintenanceMarginRequirement(liquidationBuffer?: BN): BN;
getActivePerpPositionsForUserAccount(userAccount: UserAccount): PerpPosition[];
getActivePerpPositions(): PerpPosition[];
getActivePerpPositionsAndSlot(): DataAndSlot<PerpPosition[]>;
getActiveSpotPositionsForUserAccount(userAccount: UserAccount): SpotPosition[];
getActiveSpotPositions(): SpotPosition[];
getActiveSpotPositionsAndSlot(): DataAndSlot<SpotPosition[]>;
/**
* calculates unrealized position price pnl
* @returns : Precision QUOTE_PRECISION
*/
getUnrealizedPNL(withFunding?: boolean, marketIndex?: number, withWeightMarginCategory?: MarginCategory, strict?: boolean, liquidationBuffer?: BN): BN;
/**
* calculates unrealized funding payment pnl
* @returns : Precision QUOTE_PRECISION
*/
getUnrealizedFundingPNL(marketIndex?: number): BN;
getFuelBonus(now: BN, includeSettled?: boolean, includeUnsettled?: boolean, givenUserStats?: UserStats): {
depositFuel: BN;
borrowFuel: BN;
positionFuel: BN;
takerFuel: BN;
makerFuel: BN;
insuranceFuel: BN;
};
getSpotMarketAssetAndLiabilityValue(marketIndex?: number, marginCategory?: MarginCategory, liquidationBuffer?: BN, includeOpenOrders?: boolean, strict?: boolean, now?: BN): {
totalAssetValue: BN;
totalLiabilityValue: BN;
};
getSpotMarketLiabilityValue(marketIndex?: number, marginCategory?: MarginCategory, liquidationBuffer?: BN, includeOpenOrders?: boolean, strict?: boolean, now?: BN): BN;
getSpotLiabilityValue(tokenAmount: BN, strictOraclePrice: StrictOraclePrice, spotMarketAccount: SpotMarketAccount, marginCategory?: MarginCategory, liquidationBuffer?: BN): BN;
getSpotMarketAssetValue(marketIndex?: number, marginCategory?: MarginCategory, includeOpenOrders?: boolean, strict?: boolean, now?: BN): BN;
getSpotAssetValue(tokenAmount: BN, strictOraclePrice: StrictOraclePrice, spotMarketAccount: SpotMarketAccount, marginCategory?: MarginCategory): BN;
getSpotPositionValue(marketIndex: number, marginCategory?: MarginCategory, includeOpenOrders?: boolean, strict?: boolean, now?: BN): BN;
getNetSpotMarketValue(withWeightMarginCategory?: MarginCategory): BN;
/**
* calculates TotalCollateral: collateral + unrealized pnl
* @returns : Precision QUOTE_PRECISION
*/
getTotalCollateral(marginCategory?: MarginCategory, strict?: boolean, includeOpenOrders?: boolean, liquidationBuffer?: BN): BN;
getLiquidationBuffer(): BN | undefined;
/**
* calculates User Health by comparing total collateral and maint. margin requirement
* @returns : number (value from [0, 100])
*/
getHealth(): number;
calculateWeightedPerpPositionLiability(perpPosition: PerpPosition, marginCategory?: MarginCategory, liquidationBuffer?: BN, includeOpenOrders?: boolean, strict?: boolean, enteringHighLeverage?: any): BN;
/**
* calculates position value of a single perp market in margin system
* @returns : Precision QUOTE_PRECISION
*/
getPerpMarketLiabilityValue(marketIndex: number, marginCategory?: MarginCategory, liquidationBuffer?: BN, includeOpenOrders?: boolean, strict?: boolean): BN;
/**
* calculates sum of position value across all positions in margin system
* @returns : Precision QUOTE_PRECISION
*/
getTotalPerpPositionLiability(marginCategory?: MarginCategory, liquidationBuffer?: BN, includeOpenOrders?: boolean, strict?: boolean, enteringHighLeverage?: any): BN;
/**
* calculates position value based on oracle
* @returns : Precision QUOTE_PRECISION
*/
getPerpPositionValue(marketIndex: number, oraclePriceData: Pick<OraclePriceData, 'price'>, includeOpenOrders?: boolean): BN;
/**
* calculates position liabiltiy value in margin system
* @returns : Precision QUOTE_PRECISION
*/
getPerpLiabilityValue(marketIndex: number, oraclePriceData: OraclePriceData, includeOpenOrders?: boolean): BN;
getPositionSide(currentPosition: Pick<PerpPosition, 'baseAssetAmount'>): PositionDirection | undefined;
/**
* calculates average exit price (optionally for closing up to 100% of position)
* @returns : Precision PRICE_PRECISION
*/
getPositionEstimatedExitPriceAndPnl(position: PerpPosition, amountToClose?: BN, useAMMClose?: boolean): [BN, BN];
/**
* calculates current user leverage which is (total liability size) / (net asset value)
* @returns : Precision TEN_THOUSAND
*/
getLeverage(includeOpenOrders?: boolean): BN;
calculateLeverageFromComponents({ perpLiabilityValue, perpPnl, spotAssetValue, spotLiabilityValue, }: {
perpLiabilityValue: BN;
perpPnl: BN;
spotAssetValue: BN;
spotLiabilityValue: BN;
}): BN;
getLeverageComponents(includeOpenOrders?: boolean, marginCategory?: MarginCategory): {
perpLiabilityValue: BN;
perpPnl: BN;
spotAssetValue: BN;
spotLiabilityValue: BN;
};
isDustDepositPosition(spotMarketAccount: SpotMarketAccount): boolean;
getSpotMarketAccountsWithDustPosition(): SpotMarketAccount[];
getTotalLiabilityValue(marginCategory?: MarginCategory): BN;
getTotalAssetValue(marginCategory?: MarginCategory): BN;
getNetUsdValue(): BN;
/**
* Calculates the all time P&L of the user.
*
* Net withdraws + Net spot market value + Net unrealized P&L -
*/
getTotalAllTimePnl(): BN;
/**
* calculates max allowable leverage exceeding hitting requirement category
* for large sizes where imf factor activates, result is a lower bound
* @param marginCategory {Initial, Maintenance}
* @param isLp if calculating max leveraging for adding lp, need to add buffer
* @param enterHighLeverageMode can pass this as true to calculate max leverage if the user was to enter high leverage mode
* @returns : Precision TEN_THOUSAND
*/
getMaxLeverageForPerp(perpMarketIndex: number, _marginCategory?: MarginCategory, isLp?: boolean, enterHighLeverageMode?: any): BN;
/**
* calculates max allowable leverage exceeding hitting requirement category
* @param spotMarketIndex
* @param direction
* @returns : Precision TEN_THOUSAND
*/
getMaxLeverageForSpot(spotMarketIndex: number, direction: PositionDirection): BN;
/**
* calculates margin ratio: 1 / leverage
* @returns : Precision TEN_THOUSAND
*/
getMarginRatio(): BN;
canBeLiquidated(): {
canBeLiquidated: boolean;
marginRequirement: BN;
totalCollateral: BN;
};
isBeingLiquidated(): boolean;
hasStatus(status: UserStatus): boolean;
isBankrupt(): boolean;
isHighLeverageMode(marginCategory: MarginCategory): boolean;
/**
* Checks if any user position cumulative funding differs from respective market cumulative funding
* @returns
*/
needsToSettleFundingPayment(): boolean;
/**
* Calculate the liquidation price of a spot position
* @param marketIndex
* @returns Precision : PRICE_PRECISION
*/
spotLiquidationPrice(marketIndex: number, positionBaseSizeChange?: BN): BN;
/**
* Calculate the liquidation price of a perp position, with optional parameter to calculate the liquidation price after a trade
* @param marketIndex
* @param positionBaseSizeChange // change in position size to calculate liquidation price for : Precision 10^9
* @param estimatedEntryPrice
* @param marginCategory // allow Initial to be passed in if we are trying to calculate price for DLP de-risking
* @param includeOpenOrders
* @param offsetCollateral // allows calculating the liquidation price after this offset collateral is added to the user's account (e.g. : what will the liquidation price be for this position AFTER I deposit $x worth of collateral)
* @returns Precision : PRICE_PRECISION
*/
liquidationPrice(marketIndex: number, positionBaseSizeChange?: BN, estimatedEntryPrice?: BN, marginCategory?: MarginCategory, includeOpenOrders?: boolean, offsetCollateral?: BN, enteringHighLeverage?: any): BN;
calculateEntriesEffectOnFreeCollateral(market: PerpMarketAccount, oraclePrice: BN, perpPosition: PerpPosition, positionBaseSizeChange: BN, estimatedEntryPrice: BN, includeOpenOrders: boolean, enteringHighLeverage?: any, marginCategory?: MarginCategory): BN;
calculateFreeCollateralDeltaForPerp(market: PerpMarketAccount, perpPosition: PerpPosition, positionBaseSizeChange: BN, oraclePrice: BN, marginCategory?: MarginCategory, includeOpenOrders?: boolean, enteringHighLeverage?: any): BN | undefined;
calculateFreeCollateralDeltaForSpot(market: SpotMarketAccount, signedTokenAmount: BN, marginCategory?: MarginCategory): BN;
/**
* Calculates the estimated liquidation price for a position after closing a quote amount of the position.
* @param positionMarketIndex
* @param closeQuoteAmount
* @returns : Precision PRICE_PRECISION
*/
liquidationPriceAfterClose(positionMarketIndex: number, closeQuoteAmount: BN, estimatedEntryPrice?: BN): BN;
getMarginUSDCRequiredForTrade(targetMarketIndex: number, baseSize: BN, estEntryPrice?: BN): BN;
getCollateralDepositRequiredForTrade(targetMarketIndex: number, baseSize: BN, collateralIndex: number): BN;
/**
* Separates the max trade size into two parts:
* - tradeSize: The maximum trade size for target direction
* - oppositeSideTradeSize: the trade size for closing the opposite direction
* @param targetMarketIndex
* @param tradeSide
* @param isLp
* @returns { tradeSize: BN, oppositeSideTradeSize: BN} : Precision QUOTE_PRECISION
*/
getMaxTradeSizeUSDCForPerp(targetMarketIndex: number, tradeSide: PositionDirection, isLp?: boolean, enterHighLeverageMode?: any): {
tradeSize: BN;
oppositeSideTradeSize: BN;
};
/**
* Get the maximum trade size for a given market, taking into account the user's current leverage, positions, collateral, etc.
*
* @param targetMarketIndex
* @param direction
* @param currentQuoteAssetValue
* @param currentSpotMarketNetValue
* @returns tradeSizeAllowed : Precision QUOTE_PRECISION
*/
getMaxTradeSizeUSDCForSpot(targetMarketIndex: number, direction: PositionDirection, currentQuoteAssetValue?: BN, currentSpotMarketNetValue?: BN): BN;
/**
* Calculates the max amount of token that can be swapped from inMarket to outMarket
* Assumes swap happens at oracle price
*
* @param inMarketIndex
* @param outMarketIndex
* @param calculateSwap function to similate in to out swa
* @param iterationLimit how long to run appromixation before erroring out
*/
getMaxSwapAmount({ inMarketIndex, outMarketIndex, calculateSwap, iterationLimit, }: {
inMarketIndex: number;
outMarketIndex: number;
calculateSwap?: (inAmount: BN) => BN;
iterationLimit?: number;
}): {
inAmount: BN;
outAmount: BN;
leverage: BN;
};
cloneAndUpdateSpotPosition(position: SpotPosition, tokenAmount: BN, market: SpotMarketAccount): SpotPosition;
calculateSpotPositionFreeCollateralContribution(spotPosition: SpotPosition, strictOraclePrice: StrictOraclePrice): BN;
calculateSpotPositionLeverageContribution(spotPosition: SpotPosition, strictOraclePrice: StrictOraclePrice): {
totalAssetValue: BN;
totalLiabilityValue: BN;
};
/**
* Estimates what the user leverage will be after swap
* @param inMarketIndex
* @param outMarketIndex
* @param inAmount
* @param outAmount
*/
accountLeverageAfterSwap({ inMarketIndex, outMarketIndex, inAmount, outAmount, }: {
inMarketIndex: number;
outMarketIndex: number;
inAmount: BN;
outAmount: BN;
}): BN;
/**
* Returns the leverage ratio for the account after adding (or subtracting) the given quote size to the given position
* @param targetMarketIndex
* @param: targetMarketType
* @param tradeQuoteAmount
* @param tradeSide
* @param includeOpenOrders
* @returns leverageRatio : Precision TEN_THOUSAND
*/
accountLeverageRatioAfterTrade(targetMarketIndex: number, targetMarketType: MarketType, tradeQuoteAmount: BN, tradeSide: PositionDirection, includeOpenOrders?: boolean): BN;
getUserFeeTier(marketType: MarketType, now?: BN): import("./types").FeeTier;
/**
* Calculates how much perp fee will be taken for a given sized trade
* @param quoteAmount
* @returns feeForQuote : Precision QUOTE_PRECISION
*/
calculateFeeForQuoteAmount(quoteAmount: BN, marketIndex?: number, enteringHighLeverageMode?: boolean): BN;
/**
* Calculates a user's max withdrawal amounts for a spot market. If reduceOnly is true,
* it will return the max withdrawal amount without opening a liability for the user
* @param marketIndex
* @returns withdrawalLimit : Precision is the token precision for the chosen SpotMarket
*/
getWithdrawalLimit(marketIndex: number, reduceOnly?: boolean): BN;
canBypassWithdrawLimits(marketIndex: number): {
canBypass: boolean;
netDeposits: BN;
depositAmount: BN;
maxDepositAmount: BN;
};
canMakeIdle(slot: BN): boolean;
getSafestTiers(): {
perpTier: number;
spotTier: number;
};
getPerpPositionHealth({ marginCategory, perpPosition, oraclePriceData, quoteOraclePriceData, }: {
marginCategory: MarginCategory;
perpPosition: PerpPosition;
oraclePriceData?: OraclePriceData;
quoteOraclePriceData?: OraclePriceData;
}): HealthComponent;
getHealthComponents({ marginCategory, }: {
marginCategory: MarginCategory;
}): HealthComponents;
/**
* Get the total position value, excluding any position coming from the given target market
* @param marketToIgnore
* @returns positionValue : Precision QUOTE_PRECISION
*/
private getTotalPerpPositionValueExcludingMarket;
private getMMOracleDataForPerpMarket;
private getOracleDataForPerpMarket;
private getOracleDataForSpotMarket;
/**
* Get the active perp and spot positions of the user.
*/
getActivePositions(): {
activePerpPositions: number[];
activeSpotPositions: number[];
};
}