diff --git a/sdk/src/user.ts b/sdk/src/user.ts index 0296dd63e..bc90a6307 100644 --- a/sdk/src/user.ts +++ b/sdk/src/user.ts @@ -352,6 +352,10 @@ export class User { }; } + public isPositionEmpty(position: PerpPosition): boolean { + return position.baseAssetAmount.eq(ZERO) && position.openOrders === 0; + } + public getIsolatePerpPositionTokenAmount(perpMarketIndex: number): BN { const perpPosition = this.getPerpPosition(perpMarketIndex); if (!perpPosition) return ZERO; @@ -485,7 +489,8 @@ export class User { marketIndex: number, collateralBuffer = ZERO, enterHighLeverageMode = undefined, - maxMarginRatio = undefined + maxMarginRatio = undefined, + positionType: 'isolated' | 'cross' = 'cross' ): BN { const perpPosition = this.getPerpPositionOrEmpty(marketIndex); @@ -499,10 +504,29 @@ export class User { ) : ZERO; - const freeCollateral = this.getFreeCollateral( - 'Initial', - enterHighLeverageMode - ).sub(collateralBuffer); + let freeCollateral: BN; + if (positionType === 'isolated' && this.isPositionEmpty(perpPosition)) { + const { + totalAssetValue: quoteSpotMarketAssetValue, + totalLiabilityValue: quoteSpotMarketLiabilityValue, + } = this.getSpotMarketAssetAndLiabilityValue( + perpMarket.quoteSpotMarketIndex, + 'Initial', + undefined, + undefined, + true + ); + + freeCollateral = quoteSpotMarketAssetValue.sub( + quoteSpotMarketLiabilityValue + ); + } else { + freeCollateral = this.getFreeCollateral( + 'Initial', + enterHighLeverageMode, + positionType === 'isolated' ? marketIndex : undefined + ).sub(collateralBuffer); + } return this.getPerpBuyingPowerFromFreeCollateralAndBaseAssetAmount( marketIndex, @@ -544,17 +568,15 @@ export class User { enterHighLeverageMode = false, perpMarketIndex?: number ): BN { - const { totalCollateral, marginRequirement, getIsolatedFreeCollateral } = - this.getMarginCalculation(marginCategory, { - enteringHighLeverage: enterHighLeverageMode, - strict: marginCategory === 'Initial', - }); + const calc = this.getMarginCalculation(marginCategory, { + enteringHighLeverage: enterHighLeverageMode, + strict: marginCategory === 'Initial', + }); if (perpMarketIndex !== undefined) { - return getIsolatedFreeCollateral(perpMarketIndex); + return calc.getIsolatedFreeCollateral(perpMarketIndex); } else { - const freeCollateral = totalCollateral.sub(marginRequirement); - return freeCollateral.gte(ZERO) ? freeCollateral : ZERO; + return calc.getCrossFreeCollateral(); } } @@ -2752,7 +2774,8 @@ export class User { tradeSide: PositionDirection, isLp = false, enterHighLeverageMode = undefined, - maxMarginRatio = undefined + maxMarginRatio = undefined, + positionType: 'isolated' | 'cross' = 'cross' ): { tradeSize: BN; oppositeSideTradeSize: BN } { let tradeSize = ZERO; let oppositeSideTradeSize = ZERO; @@ -2792,7 +2815,8 @@ export class User { targetMarketIndex, lpBuffer, enterHighLeverageMode, - maxMarginRatio + maxMarginRatio, + positionType ); if (maxPositionSize.gte(ZERO)) {