@drift-labs/sdk 2.13.0-beta.1 → 2.13.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "2.13.0-beta.1",
2
+ "version": "2.13.0-beta.2",
3
3
  "name": "drift",
4
4
  "instructions": [
5
5
  {
@@ -7,5 +7,5 @@ imfFactor: BN, liabilityWeight: BN, precision: BN): BN;
7
7
  export declare function calculateSizeDiscountAssetWeight(size: BN, // AMM_RESERVE_PRECISION
8
8
  imfFactor: BN, assetWeight: BN): BN;
9
9
  export declare function calculateOraclePriceForPerpMargin(perpPosition: PerpPosition, market: PerpMarketAccount, oraclePriceData: OraclePriceData): BN;
10
- export declare function calculateBaseAssetValueWithOracle(market: PerpMarketAccount, perpPosition: PerpPosition, oraclePriceData: OraclePriceData): BN;
10
+ export declare function calculateBaseAssetValueWithOracle(market: PerpMarketAccount, perpPosition: PerpPosition, oraclePriceData: OraclePriceData, includeOpenOrders?: boolean): BN;
11
11
  export declare function calculateWorstCaseBaseAssetAmount(perpPosition: PerpPosition): BN;
@@ -11,7 +11,7 @@ imfFactor, liabilityWeight, precision) {
11
11
  if (imfFactor.eq(numericConstants_1.ZERO)) {
12
12
  return liabilityWeight;
13
13
  }
14
- const sizeSqrt = utils_1.squareRootBN(size.mul(new anchor_1.BN(10)).add(new anchor_1.BN(1))); //1e9 -> 1e10 -> 1e5
14
+ const sizeSqrt = utils_1.squareRootBN(size.abs().mul(new anchor_1.BN(10)).add(new anchor_1.BN(1))); //1e9 -> 1e10 -> 1e5
15
15
  const denom0 = anchor_1.BN.max(new anchor_1.BN(1), numericConstants_1.SPOT_MARKET_IMF_PRECISION.div(imfFactor));
16
16
  assert_1.assert(denom0.gt(numericConstants_1.ZERO));
17
17
  const liabilityWeightNumerator = liabilityWeight.sub(liabilityWeight.div(anchor_1.BN.max(new anchor_1.BN(1), numericConstants_1.SPOT_MARKET_IMF_PRECISION.div(imfFactor))));
@@ -30,7 +30,7 @@ imfFactor, assetWeight) {
30
30
  if (imfFactor.eq(numericConstants_1.ZERO)) {
31
31
  return assetWeight;
32
32
  }
33
- const sizeSqrt = utils_1.squareRootBN(size.mul(new anchor_1.BN(10)).add(new anchor_1.BN(1))); //1e9 -> 1e10 -> 1e5
33
+ const sizeSqrt = utils_1.squareRootBN(size.abs().mul(new anchor_1.BN(10)).add(new anchor_1.BN(1))); //1e9 -> 1e10 -> 1e5
34
34
  const imfNumerator = numericConstants_1.SPOT_MARKET_IMF_PRECISION.add(numericConstants_1.SPOT_MARKET_IMF_PRECISION.div(new anchor_1.BN(10)));
35
35
  const sizeDiscountAssetWeight = imfNumerator
36
36
  .mul(numericConstants_1.SPOT_MARKET_WEIGHT_PRECISION)
@@ -58,15 +58,15 @@ function calculateOraclePriceForPerpMargin(perpPosition, market, oraclePriceData
58
58
  return marginPrice;
59
59
  }
60
60
  exports.calculateOraclePriceForPerpMargin = calculateOraclePriceForPerpMargin;
61
- function calculateBaseAssetValueWithOracle(market, perpPosition, oraclePriceData) {
61
+ function calculateBaseAssetValueWithOracle(market, perpPosition, oraclePriceData, includeOpenOrders = false) {
62
62
  let price = oraclePriceData.price;
63
63
  if (types_1.isVariant(market.status, 'settlement')) {
64
64
  price = market.expiryPrice;
65
65
  }
66
- return perpPosition.baseAssetAmount
67
- .abs()
68
- .mul(price)
69
- .div(numericConstants_1.AMM_RESERVE_PRECISION);
66
+ const baseAssetAmount = includeOpenOrders
67
+ ? calculateWorstCaseBaseAssetAmount(perpPosition)
68
+ : perpPosition.baseAssetAmount;
69
+ return baseAssetAmount.abs().mul(price).div(numericConstants_1.AMM_RESERVE_PRECISION);
70
70
  }
71
71
  exports.calculateBaseAssetValueWithOracle = calculateBaseAssetValueWithOracle;
72
72
  function calculateWorstCaseBaseAssetAmount(perpPosition) {
@@ -54,16 +54,13 @@ function isOracleTooDivergent(amm, oraclePriceData, oracleGuardRails, now) {
54
54
  exports.isOracleTooDivergent = isOracleTooDivergent;
55
55
  function calculateLiveOracleTwap(histOracleData, oraclePriceData, now, period) {
56
56
  let oracleTwap = undefined;
57
- if (period.eq(numericConstants_1.ONE_HOUR)) {
58
- //todo: assumes its 1hr
59
- // period = amm.fundingPeriod;
60
- oracleTwap = histOracleData.lastOraclePriceTwap;
61
- }
62
- else if (period.eq(numericConstants_1.FIVE_MINUTE)) {
63
- histOracleData.lastOraclePriceTwap5Min;
57
+ if (period.eq(numericConstants_1.FIVE_MINUTE)) {
58
+ oracleTwap = histOracleData.lastOraclePriceTwap5Min;
64
59
  }
65
60
  else {
66
- throw Error('unsupported twap period passed');
61
+ //todo: assumes its fundingPeriod (1hr)
62
+ // period = amm.fundingPeriod;
63
+ oracleTwap = histOracleData.lastOraclePriceTwap;
67
64
  }
68
65
  const sinceLastUpdate = index_1.BN.max(numericConstants_1.ONE, now.sub(histOracleData.lastOraclePriceTwapTs));
69
66
  const sinceStart = index_1.BN.max(numericConstants_1.ZERO, period.sub(sinceLastUpdate));
package/lib/math/utils.js CHANGED
@@ -7,6 +7,9 @@ function clampBN(x, min, max) {
7
7
  }
8
8
  exports.clampBN = clampBN;
9
9
  const squareRootBN = (n, closeness = new __1.BN(1)) => {
10
+ if (n.lt(__1.ZERO)) {
11
+ throw new Error('square root of negative number');
12
+ }
10
13
  // Assuming the sqrt of n as n only
11
14
  let x = n;
12
15
  // The closed guess will be stored in the root
package/lib/user.d.ts CHANGED
@@ -77,10 +77,11 @@ export declare class User {
77
77
  */
78
78
  getSettledLPPosition(marketIndex: number): [PerpPosition, BN, BN];
79
79
  /**
80
- * calculates Buying Power = FC * MAX_LEVERAGE
80
+ * calculates Buying Power = free collateral / initial margin ratio
81
81
  * @returns : Precision QUOTE_PRECISION
82
82
  */
83
83
  getBuyingPower(marketIndex: number): BN;
84
+ getBuyingPowerFromFreeCollateralAndBaseAssetAmount(marketIndex: number, freeCollateral: BN, baseAssetAmount: BN): BN;
84
85
  /**
85
86
  * calculates Free Collateral = Total collateral - initial margin requirement
86
87
  * @returns : Precision QUOTE_PRECISION
@@ -133,7 +134,7 @@ export declare class User {
133
134
  * calculates position value in margin system
134
135
  * @returns : Precision QUOTE_PRECISION
135
136
  */
136
- getPerpPositionValue(marketIndex: number, oraclePriceData: OraclePriceData): BN;
137
+ getPerpPositionValue(marketIndex: number, oraclePriceData: OraclePriceData, includeOpenOrders?: boolean): BN;
137
138
  getPositionSide(currentPosition: Pick<PerpPosition, 'baseAssetAmount'>): PositionDirection | undefined;
138
139
  /**
139
140
  * calculates average exit price (optionally for closing up to 100% of position)
package/lib/user.js CHANGED
@@ -239,13 +239,20 @@ class User {
239
239
  return [position, remainderBaa, pnl];
240
240
  }
241
241
  /**
242
- * calculates Buying Power = FC * MAX_LEVERAGE
242
+ * calculates Buying Power = free collateral / initial margin ratio
243
243
  * @returns : Precision QUOTE_PRECISION
244
244
  */
245
245
  getBuyingPower(marketIndex) {
246
- return this.getFreeCollateral()
247
- .mul(this.getMaxLeverage(marketIndex, 'Initial'))
248
- .div(numericConstants_1.TEN_THOUSAND);
246
+ const perpPosition = this.getPerpPosition(marketIndex);
247
+ const worstCaseBaseAssetAmount = perpPosition
248
+ ? margin_1.calculateWorstCaseBaseAssetAmount(perpPosition)
249
+ : numericConstants_1.ZERO;
250
+ const freeCollateral = this.getFreeCollateral();
251
+ return this.getBuyingPowerFromFreeCollateralAndBaseAssetAmount(marketIndex, freeCollateral, worstCaseBaseAssetAmount);
252
+ }
253
+ getBuyingPowerFromFreeCollateralAndBaseAssetAmount(marketIndex, freeCollateral, baseAssetAmount) {
254
+ const marginRatio = _1.calculateMarketMarginRatio(this.driftClient.getPerpMarketAccount(marketIndex), baseAssetAmount, 'Initial');
255
+ return freeCollateral.mul(numericConstants_1.MARGIN_PRECISION).div(new _1.BN(marginRatio));
249
256
  }
250
257
  /**
251
258
  * calculates Free Collateral = Total collateral - initial margin requirement
@@ -557,10 +564,10 @@ class User {
557
564
  * calculates position value in margin system
558
565
  * @returns : Precision QUOTE_PRECISION
559
566
  */
560
- getPerpPositionValue(marketIndex, oraclePriceData) {
567
+ getPerpPositionValue(marketIndex, oraclePriceData, includeOpenOrders = false) {
561
568
  const userPosition = this.getPerpPosition(marketIndex) || this.getEmptyPosition(marketIndex);
562
569
  const market = this.driftClient.getPerpMarketAccount(userPosition.marketIndex);
563
- return margin_1.calculateBaseAssetValueWithOracle(market, userPosition, oraclePriceData);
570
+ return margin_1.calculateBaseAssetValueWithOracle(market, userPosition, oraclePriceData, includeOpenOrders);
564
571
  }
565
572
  getPositionSide(currentPosition) {
566
573
  if (currentPosition.baseAssetAmount.gt(numericConstants_1.ZERO)) {
@@ -779,7 +786,7 @@ class User {
779
786
  3. (10k - 4k) / (100k - 4k) = 6k/96k => .0625 */
780
787
  const totalCollateral = this.getTotalCollateral('Maintenance');
781
788
  // calculate the total position value ignoring any value from the target market of the trade
782
- const totalPositionValueExcludingTargetMarket = this.getTotalPerpPositionValueExcludingMarket(perpPosition.marketIndex);
789
+ const totalPositionValueExcludingTargetMarket = this.getTotalPerpPositionValueExcludingMarket(perpPosition.marketIndex, undefined, undefined, true);
783
790
  const currentPerpPosition = this.getPerpPosition(perpPosition.marketIndex) ||
784
791
  this.getEmptyPosition(perpPosition.marketIndex);
785
792
  const currentPerpPositionBaseSize = currentPerpPosition.baseAssetAmount;
@@ -794,8 +801,8 @@ class User {
794
801
  quoteBreakEvenAmount: new _1.BN(0),
795
802
  quoteEntryAmount: new _1.BN(0),
796
803
  openOrders: 0,
797
- openBids: new _1.BN(0),
798
- openAsks: new _1.BN(0),
804
+ openBids: currentPerpPosition.openBids,
805
+ openAsks: currentPerpPosition.openAsks,
799
806
  settledPnl: numericConstants_1.ZERO,
800
807
  lpShares: numericConstants_1.ZERO,
801
808
  lastBaseAssetAmountPerLp: numericConstants_1.ZERO,
@@ -804,13 +811,13 @@ class User {
804
811
  if (proposedBaseAssetAmount.eq(numericConstants_1.ZERO))
805
812
  return new _1.BN(-1);
806
813
  const market = this.driftClient.getPerpMarketAccount(proposedPerpPosition.marketIndex);
807
- const proposedPerpPositionValue = margin_1.calculateBaseAssetValueWithOracle(market, proposedPerpPosition, this.getOracleDataForPerpMarket(market.marketIndex));
814
+ const proposedPerpPositionValue = margin_1.calculateBaseAssetValueWithOracle(market, proposedPerpPosition, this.getOracleDataForPerpMarket(market.marketIndex), true);
808
815
  // total position value after trade
809
816
  const totalPositionValueAfterTrade = totalPositionValueExcludingTargetMarket.add(proposedPerpPositionValue);
810
817
  const marginRequirementOfAll = this.getMaintenanceMarginRequirement();
811
- const positionValue = margin_1.calculateBaseAssetValueWithOracle(market, proposedPerpPosition, this.getOracleDataForPerpMarket(market.marketIndex));
818
+ const positionValue = margin_1.calculateBaseAssetValueWithOracle(market, currentPerpPosition, this.getOracleDataForPerpMarket(market.marketIndex), true);
812
819
  const marginRequirementOfTargetMarket = positionValue
813
- .mul(new _1.BN(_1.calculateMarketMarginRatio(market, proposedPerpPosition.baseAssetAmount.abs(), 'Maintenance')))
820
+ .mul(new _1.BN(_1.calculateMarketMarginRatio(market, margin_1.calculateWorstCaseBaseAssetAmount(currentPerpPosition).abs(), 'Maintenance')))
814
821
  .div(numericConstants_1.MARGIN_PRECISION);
815
822
  const marginRequirementExcludingTargetMarket = marginRequirementOfAll.sub(marginRequirementOfTargetMarket);
816
823
  const freeCollateralExcludingTargetMarket = totalCollateral.sub(marginRequirementExcludingTargetMarket);
@@ -819,13 +826,14 @@ class User {
819
826
  proposedPerpPosition.baseAssetAmount.gt(numericConstants_1.ZERO)) {
820
827
  return new _1.BN(-1);
821
828
  }
829
+ const proposedWorstCastBaseAssetAmount = margin_1.calculateWorstCaseBaseAssetAmount(proposedPerpPosition);
822
830
  const marginRequirementTargetMarket = proposedPerpPositionValue
823
- .mul(new _1.BN(_1.calculateMarketMarginRatio(market, proposedPerpPosition.baseAssetAmount.abs(), 'Maintenance')))
831
+ .mul(new _1.BN(_1.calculateMarketMarginRatio(market, proposedWorstCastBaseAssetAmount.abs(), 'Maintenance')))
824
832
  .div(numericConstants_1.MARGIN_PRECISION);
825
833
  const marginRequirementAfterTrade = marginRequirementExcludingTargetMarket.add(marginRequirementTargetMarket);
826
834
  const freeCollateralAfterTrade = totalCollateral.sub(marginRequirementAfterTrade);
827
835
  const marketMaxMaintLeverage = new _1.BN(numericConstants_1.TEN_THOUSAND.mul(numericConstants_1.TEN_THOUSAND).toNumber() /
828
- _1.calculateMarketMarginRatio(market, proposedPerpPosition.baseAssetAmount, 'Maintenance'));
836
+ _1.calculateMarketMarginRatio(market, proposedWorstCastBaseAssetAmount.abs(), 'Maintenance'));
829
837
  let priceDelta;
830
838
  if (proposedBaseAssetAmount.lt(numericConstants_1.ZERO)) {
831
839
  priceDelta = freeCollateralAfterTrade
@@ -933,9 +941,7 @@ class User {
933
941
  }
934
942
  else {
935
943
  const freeCollateralAfterClose = totalCollateral.sub(marginRequirementAfterClosing);
936
- const buyingPowerAfterClose = freeCollateralAfterClose
937
- .mul(this.getMaxLeverage(targetMarketIndex))
938
- .div(numericConstants_1.TEN_THOUSAND);
944
+ const buyingPowerAfterClose = this.getBuyingPowerFromFreeCollateralAndBaseAssetAmount(targetMarketIndex, freeCollateralAfterClose, numericConstants_1.ZERO);
939
945
  maxPositionSize = perpPositionValue.add(buyingPowerAfterClose);
940
946
  }
941
947
  }
@@ -960,7 +966,7 @@ class User {
960
966
  const currentPosition = this.getPerpPosition(targetMarketIndex) ||
961
967
  this.getEmptyPosition(targetMarketIndex);
962
968
  const oracleData = this.getOracleDataForPerpMarket(targetMarketIndex);
963
- let currentPositionQuoteAmount = this.getPerpPositionValue(targetMarketIndex, oracleData);
969
+ let currentPositionQuoteAmount = this.getPerpPositionValue(targetMarketIndex, oracleData, includeOpenOrders);
964
970
  const currentSide = currentPosition && currentPosition.baseAssetAmount.isNeg()
965
971
  ? _1.PositionDirection.SHORT
966
972
  : _1.PositionDirection.LONG;
@@ -1089,7 +1095,7 @@ class User {
1089
1095
  const oracleData = this.getOracleDataForPerpMarket(marketToIgnore);
1090
1096
  let currentPerpPositionValueUSDC = numericConstants_1.ZERO;
1091
1097
  if (currentPerpPosition) {
1092
- currentPerpPositionValueUSDC = this.getPerpPositionValue(marketToIgnore, oracleData);
1098
+ currentPerpPositionValueUSDC = this.getPerpPositionValue(marketToIgnore, oracleData, includeOpenOrders);
1093
1099
  }
1094
1100
  return this.getTotalPerpPositionValue(marginCategory, liquidationBuffer, includeOpenOrders).sub(currentPerpPositionValueUSDC);
1095
1101
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drift-labs/sdk",
3
- "version": "2.13.0-beta.1",
3
+ "version": "2.13.0-beta.2",
4
4
  "main": "lib/index.js",
5
5
  "types": "lib/index.d.ts",
6
6
  "author": "crispheaney",
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "2.13.0-beta.1",
2
+ "version": "2.13.0-beta.2",
3
3
  "name": "drift",
4
4
  "instructions": [
5
5
  {
@@ -22,7 +22,7 @@ export function calculateSizePremiumLiabilityWeight(
22
22
  return liabilityWeight;
23
23
  }
24
24
 
25
- const sizeSqrt = squareRootBN(size.mul(new BN(10)).add(new BN(1))); //1e9 -> 1e10 -> 1e5
25
+ const sizeSqrt = squareRootBN(size.abs().mul(new BN(10)).add(new BN(1))); //1e9 -> 1e10 -> 1e5
26
26
 
27
27
  const denom0 = BN.max(new BN(1), SPOT_MARKET_IMF_PRECISION.div(imfFactor));
28
28
  assert(denom0.gt(ZERO));
@@ -57,7 +57,7 @@ export function calculateSizeDiscountAssetWeight(
57
57
  return assetWeight;
58
58
  }
59
59
 
60
- const sizeSqrt = squareRootBN(size.mul(new BN(10)).add(new BN(1))); //1e9 -> 1e10 -> 1e5
60
+ const sizeSqrt = squareRootBN(size.abs().mul(new BN(10)).add(new BN(1))); //1e9 -> 1e10 -> 1e5
61
61
  const imfNumerator = SPOT_MARKET_IMF_PRECISION.add(
62
62
  SPOT_MARKET_IMF_PRECISION.div(new BN(10))
63
63
  );
@@ -106,17 +106,19 @@ export function calculateOraclePriceForPerpMargin(
106
106
  export function calculateBaseAssetValueWithOracle(
107
107
  market: PerpMarketAccount,
108
108
  perpPosition: PerpPosition,
109
- oraclePriceData: OraclePriceData
109
+ oraclePriceData: OraclePriceData,
110
+ includeOpenOrders = false
110
111
  ): BN {
111
112
  let price = oraclePriceData.price;
112
113
  if (isVariant(market.status, 'settlement')) {
113
114
  price = market.expiryPrice;
114
115
  }
115
116
 
116
- return perpPosition.baseAssetAmount
117
- .abs()
118
- .mul(price)
119
- .div(AMM_RESERVE_PRECISION);
117
+ const baseAssetAmount = includeOpenOrders
118
+ ? calculateWorstCaseBaseAssetAmount(perpPosition)
119
+ : perpPosition.baseAssetAmount;
120
+
121
+ return baseAssetAmount.abs().mul(price).div(AMM_RESERVE_PRECISION);
120
122
  }
121
123
 
122
124
  export function calculateWorstCaseBaseAssetAmount(
@@ -7,7 +7,6 @@ import {
7
7
  ONE,
8
8
  ZERO,
9
9
  FIVE_MINUTE,
10
- ONE_HOUR,
11
10
  } from '../constants/numericConstants';
12
11
  import { BN, HistoricalOracleData, PerpMarketAccount } from '../index';
13
12
  import { assert } from '../assert/assert';
@@ -98,14 +97,12 @@ export function calculateLiveOracleTwap(
98
97
  period: BN
99
98
  ): BN {
100
99
  let oracleTwap = undefined;
101
- if (period.eq(ONE_HOUR)) {
102
- //todo: assumes its 1hr
100
+ if (period.eq(FIVE_MINUTE)) {
101
+ oracleTwap = histOracleData.lastOraclePriceTwap5Min;
102
+ } else {
103
+ //todo: assumes its fundingPeriod (1hr)
103
104
  // period = amm.fundingPeriod;
104
105
  oracleTwap = histOracleData.lastOraclePriceTwap;
105
- } else if (period.eq(FIVE_MINUTE)) {
106
- histOracleData.lastOraclePriceTwap5Min;
107
- } else {
108
- throw Error('unsupported twap period passed');
109
106
  }
110
107
 
111
108
  const sinceLastUpdate = BN.max(
package/src/math/utils.ts CHANGED
@@ -1,10 +1,14 @@
1
- import { BN } from '../';
1
+ import { BN, ZERO } from '../';
2
2
 
3
3
  export function clampBN(x: BN, min: BN, max: BN): BN {
4
4
  return BN.max(min, BN.min(x, max));
5
5
  }
6
6
 
7
7
  export const squareRootBN = (n, closeness = new BN(1)): BN => {
8
+ if (n.lt(ZERO)) {
9
+ throw new Error('square root of negative number');
10
+ }
11
+
8
12
  // Assuming the sqrt of n as n only
9
13
  let x = n;
10
14
 
package/src/user.ts CHANGED
@@ -365,13 +365,36 @@ export class User {
365
365
  }
366
366
 
367
367
  /**
368
- * calculates Buying Power = FC * MAX_LEVERAGE
368
+ * calculates Buying Power = free collateral / initial margin ratio
369
369
  * @returns : Precision QUOTE_PRECISION
370
370
  */
371
371
  public getBuyingPower(marketIndex: number): BN {
372
- return this.getFreeCollateral()
373
- .mul(this.getMaxLeverage(marketIndex, 'Initial'))
374
- .div(TEN_THOUSAND);
372
+ const perpPosition = this.getPerpPosition(marketIndex);
373
+ const worstCaseBaseAssetAmount = perpPosition
374
+ ? calculateWorstCaseBaseAssetAmount(perpPosition)
375
+ : ZERO;
376
+
377
+ const freeCollateral = this.getFreeCollateral();
378
+
379
+ return this.getBuyingPowerFromFreeCollateralAndBaseAssetAmount(
380
+ marketIndex,
381
+ freeCollateral,
382
+ worstCaseBaseAssetAmount
383
+ );
384
+ }
385
+
386
+ getBuyingPowerFromFreeCollateralAndBaseAssetAmount(
387
+ marketIndex: number,
388
+ freeCollateral: BN,
389
+ baseAssetAmount: BN
390
+ ): BN {
391
+ const marginRatio = calculateMarketMarginRatio(
392
+ this.driftClient.getPerpMarketAccount(marketIndex),
393
+ baseAssetAmount,
394
+ 'Initial'
395
+ );
396
+
397
+ return freeCollateral.mul(MARGIN_PRECISION).div(new BN(marginRatio));
375
398
  }
376
399
 
377
400
  /**
@@ -978,7 +1001,8 @@ export class User {
978
1001
  */
979
1002
  public getPerpPositionValue(
980
1003
  marketIndex: number,
981
- oraclePriceData: OraclePriceData
1004
+ oraclePriceData: OraclePriceData,
1005
+ includeOpenOrders = false
982
1006
  ): BN {
983
1007
  const userPosition =
984
1008
  this.getPerpPosition(marketIndex) || this.getEmptyPosition(marketIndex);
@@ -988,7 +1012,8 @@ export class User {
988
1012
  return calculateBaseAssetValueWithOracle(
989
1013
  market,
990
1014
  userPosition,
991
- oraclePriceData
1015
+ oraclePriceData,
1016
+ includeOpenOrders
992
1017
  );
993
1018
  }
994
1019
 
@@ -1341,7 +1366,12 @@ export class User {
1341
1366
 
1342
1367
  // calculate the total position value ignoring any value from the target market of the trade
1343
1368
  const totalPositionValueExcludingTargetMarket =
1344
- this.getTotalPerpPositionValueExcludingMarket(perpPosition.marketIndex);
1369
+ this.getTotalPerpPositionValueExcludingMarket(
1370
+ perpPosition.marketIndex,
1371
+ undefined,
1372
+ undefined,
1373
+ true
1374
+ );
1345
1375
 
1346
1376
  const currentPerpPosition =
1347
1377
  this.getPerpPosition(perpPosition.marketIndex) ||
@@ -1363,8 +1393,8 @@ export class User {
1363
1393
  quoteBreakEvenAmount: new BN(0),
1364
1394
  quoteEntryAmount: new BN(0),
1365
1395
  openOrders: 0,
1366
- openBids: new BN(0),
1367
- openAsks: new BN(0),
1396
+ openBids: currentPerpPosition.openBids,
1397
+ openAsks: currentPerpPosition.openAsks,
1368
1398
  settledPnl: ZERO,
1369
1399
  lpShares: ZERO,
1370
1400
  lastBaseAssetAmountPerLp: ZERO,
@@ -1380,7 +1410,8 @@ export class User {
1380
1410
  const proposedPerpPositionValue = calculateBaseAssetValueWithOracle(
1381
1411
  market,
1382
1412
  proposedPerpPosition,
1383
- this.getOracleDataForPerpMarket(market.marketIndex)
1413
+ this.getOracleDataForPerpMarket(market.marketIndex),
1414
+ true
1384
1415
  );
1385
1416
 
1386
1417
  // total position value after trade
@@ -1390,15 +1421,16 @@ export class User {
1390
1421
  const marginRequirementOfAll = this.getMaintenanceMarginRequirement();
1391
1422
  const positionValue = calculateBaseAssetValueWithOracle(
1392
1423
  market,
1393
- proposedPerpPosition,
1394
- this.getOracleDataForPerpMarket(market.marketIndex)
1424
+ currentPerpPosition,
1425
+ this.getOracleDataForPerpMarket(market.marketIndex),
1426
+ true
1395
1427
  );
1396
1428
  const marginRequirementOfTargetMarket = positionValue
1397
1429
  .mul(
1398
1430
  new BN(
1399
1431
  calculateMarketMarginRatio(
1400
1432
  market,
1401
- proposedPerpPosition.baseAssetAmount.abs(),
1433
+ calculateWorstCaseBaseAssetAmount(currentPerpPosition).abs(),
1402
1434
  'Maintenance'
1403
1435
  )
1404
1436
  )
@@ -1421,12 +1453,14 @@ export class User {
1421
1453
  return new BN(-1);
1422
1454
  }
1423
1455
 
1456
+ const proposedWorstCastBaseAssetAmount =
1457
+ calculateWorstCaseBaseAssetAmount(proposedPerpPosition);
1424
1458
  const marginRequirementTargetMarket = proposedPerpPositionValue
1425
1459
  .mul(
1426
1460
  new BN(
1427
1461
  calculateMarketMarginRatio(
1428
1462
  market,
1429
- proposedPerpPosition.baseAssetAmount.abs(),
1463
+ proposedWorstCastBaseAssetAmount.abs(),
1430
1464
  'Maintenance'
1431
1465
  )
1432
1466
  )
@@ -1443,7 +1477,7 @@ export class User {
1443
1477
  TEN_THOUSAND.mul(TEN_THOUSAND).toNumber() /
1444
1478
  calculateMarketMarginRatio(
1445
1479
  market,
1446
- proposedPerpPosition.baseAssetAmount,
1480
+ proposedWorstCastBaseAssetAmount.abs(),
1447
1481
  'Maintenance'
1448
1482
  )
1449
1483
  );
@@ -1591,9 +1625,12 @@ export class User {
1591
1625
  const freeCollateralAfterClose = totalCollateral.sub(
1592
1626
  marginRequirementAfterClosing
1593
1627
  );
1594
- const buyingPowerAfterClose = freeCollateralAfterClose
1595
- .mul(this.getMaxLeverage(targetMarketIndex))
1596
- .div(TEN_THOUSAND);
1628
+ const buyingPowerAfterClose =
1629
+ this.getBuyingPowerFromFreeCollateralAndBaseAssetAmount(
1630
+ targetMarketIndex,
1631
+ freeCollateralAfterClose,
1632
+ ZERO
1633
+ );
1597
1634
  maxPositionSize = perpPositionValue.add(buyingPowerAfterClose);
1598
1635
  }
1599
1636
  } else {
@@ -1630,7 +1667,8 @@ export class User {
1630
1667
 
1631
1668
  let currentPositionQuoteAmount = this.getPerpPositionValue(
1632
1669
  targetMarketIndex,
1633
- oracleData
1670
+ oracleData,
1671
+ includeOpenOrders
1634
1672
  );
1635
1673
 
1636
1674
  const currentSide =
@@ -1841,7 +1879,8 @@ export class User {
1841
1879
  if (currentPerpPosition) {
1842
1880
  currentPerpPositionValueUSDC = this.getPerpPositionValue(
1843
1881
  marketToIgnore,
1844
- oracleData
1882
+ oracleData,
1883
+ includeOpenOrders
1845
1884
  );
1846
1885
  }
1847
1886