@drift-labs/sdk 0.2.0-master.11 → 0.2.0-master.12

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.
Files changed (72) hide show
  1. package/lib/clearingHouse.d.ts +7 -2
  2. package/lib/clearingHouse.js +157 -37
  3. package/lib/clearingHouseUser.d.ts +10 -15
  4. package/lib/clearingHouseUser.js +92 -74
  5. package/lib/config.js +1 -1
  6. package/lib/constants/banks.d.ts +2 -2
  7. package/lib/constants/banks.js +4 -3
  8. package/lib/constants/numericConstants.d.ts +2 -0
  9. package/lib/constants/numericConstants.js +3 -1
  10. package/lib/events/eventList.js +3 -0
  11. package/lib/events/types.d.ts +2 -1
  12. package/lib/factory/bigNum.d.ts +1 -0
  13. package/lib/factory/bigNum.js +37 -11
  14. package/lib/idl/clearing_house.json +97 -19
  15. package/lib/index.d.ts +1 -0
  16. package/lib/index.js +1 -0
  17. package/lib/math/bankBalance.d.ts +3 -1
  18. package/lib/math/bankBalance.js +54 -1
  19. package/lib/math/margin.d.ts +11 -0
  20. package/lib/math/margin.js +72 -0
  21. package/lib/math/market.d.ts +4 -1
  22. package/lib/math/market.js +35 -1
  23. package/lib/math/position.d.ts +8 -0
  24. package/lib/math/position.js +42 -12
  25. package/lib/orders.d.ts +1 -2
  26. package/lib/orders.js +2 -77
  27. package/lib/tokenFaucet.d.ts +1 -0
  28. package/lib/tokenFaucet.js +23 -12
  29. package/lib/tx/retryTxSender.js +9 -2
  30. package/lib/types.d.ts +24 -3
  31. package/lib/types.js +6 -0
  32. package/lib/util/getTokenAddress.d.ts +2 -0
  33. package/lib/util/getTokenAddress.js +9 -0
  34. package/package.json +1 -1
  35. package/src/clearingHouse.ts +301 -47
  36. package/src/clearingHouseConfig.js +2 -0
  37. package/src/clearingHouseUser.ts +213 -104
  38. package/src/clearingHouseUserConfig.js +2 -0
  39. package/src/config.ts +1 -1
  40. package/src/constants/banks.js +42 -0
  41. package/src/constants/banks.ts +6 -3
  42. package/src/constants/markets.js +42 -0
  43. package/src/constants/numericConstants.js +41 -0
  44. package/src/constants/numericConstants.ts +3 -0
  45. package/src/events/eventList.ts +3 -0
  46. package/src/events/types.ts +2 -0
  47. package/src/factory/bigNum.js +37 -11
  48. package/src/factory/bigNum.ts +43 -13
  49. package/src/idl/clearing_house.json +97 -19
  50. package/src/index.js +67 -98
  51. package/src/index.ts +1 -0
  52. package/src/math/bankBalance.ts +98 -1
  53. package/src/math/margin.ts +124 -0
  54. package/src/math/market.ts +66 -1
  55. package/src/math/position.ts +59 -9
  56. package/src/orders.ts +4 -157
  57. package/src/tokenFaucet.js +189 -0
  58. package/src/tokenFaucet.ts +38 -15
  59. package/src/tx/retryTxSender.ts +11 -3
  60. package/src/types.js +12 -1
  61. package/src/types.ts +25 -3
  62. package/src/{accounts/fetch.js → util/computeUnits.js} +11 -13
  63. package/src/util/getTokenAddress.js +9 -0
  64. package/src/util/getTokenAddress.ts +18 -0
  65. package/tests/bn/test.ts +2 -0
  66. package/src/addresses/pda.js +0 -104
  67. package/src/math/bankBalance.js +0 -75
  68. package/src/math/market.js +0 -57
  69. package/src/math/orders.js +0 -110
  70. package/src/math/position.js +0 -140
  71. package/src/orders.js +0 -134
  72. package/src/tx/retryTxSender.js +0 -188
package/src/index.js CHANGED
@@ -1,100 +1,69 @@
1
- 'use strict';
2
- var __createBinding =
3
- (this && this.__createBinding) ||
4
- (Object.create
5
- ? function (o, m, k, k2) {
6
- if (k2 === undefined) k2 = k;
7
- Object.defineProperty(o, k2, {
8
- enumerable: true,
9
- get: function () {
10
- return m[k];
11
- },
12
- });
13
- }
14
- : function (o, m, k, k2) {
15
- if (k2 === undefined) k2 = k;
16
- o[k2] = m[k];
17
- });
18
- var __exportStar =
19
- (this && this.__exportStar) ||
20
- function (m, exports) {
21
- for (var p in m)
22
- if (p !== 'default' && !Object.prototype.hasOwnProperty.call(exports, p))
23
- __createBinding(exports, m, p);
24
- };
25
- var __importDefault =
26
- (this && this.__importDefault) ||
27
- function (mod) {
28
- return mod && mod.__esModule ? mod : { default: mod };
29
- };
30
- Object.defineProperty(exports, '__esModule', { value: true });
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5
+ }) : (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ o[k2] = m[k];
8
+ }));
9
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
10
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
11
+ };
12
+ var __importDefault = (this && this.__importDefault) || function (mod) {
13
+ return (mod && mod.__esModule) ? mod : { "default": mod };
14
+ };
15
+ Object.defineProperty(exports, "__esModule", { value: true });
31
16
  exports.pyth = exports.PublicKey = exports.BN = void 0;
32
- const anchor_1 = require('@project-serum/anchor');
33
- Object.defineProperty(exports, 'BN', {
34
- enumerable: true,
35
- get: function () {
36
- return anchor_1.BN;
37
- },
38
- });
39
- const web3_js_1 = require('@solana/web3.js');
40
- Object.defineProperty(exports, 'PublicKey', {
41
- enumerable: true,
42
- get: function () {
43
- return web3_js_1.PublicKey;
44
- },
45
- });
46
- const client_1 = __importDefault(require('@pythnetwork/client'));
17
+ const anchor_1 = require("@project-serum/anchor");
18
+ Object.defineProperty(exports, "BN", { enumerable: true, get: function () { return anchor_1.BN; } });
19
+ const web3_js_1 = require("@solana/web3.js");
20
+ Object.defineProperty(exports, "PublicKey", { enumerable: true, get: function () { return web3_js_1.PublicKey; } });
21
+ const client_1 = __importDefault(require("@pythnetwork/client"));
47
22
  exports.pyth = client_1.default;
48
- __exportStar(require('./tokenFaucet'), exports);
49
- __exportStar(require('./oracles/types'), exports);
50
- __exportStar(require('./oracles/pythClient'), exports);
51
- __exportStar(require('./oracles/switchboardClient'), exports);
52
- __exportStar(require('./types'), exports);
53
- __exportStar(require('./constants/markets'), exports);
54
- __exportStar(require('./accounts/fetch'), exports);
55
- __exportStar(
56
- require('./accounts/webSocketClearingHouseAccountSubscriber'),
57
- exports
58
- );
59
- __exportStar(require('./accounts/bulkAccountLoader'), exports);
60
- __exportStar(require('./accounts/bulkUserSubscription'), exports);
61
- __exportStar(
62
- require('./accounts/pollingClearingHouseAccountSubscriber'),
63
- exports
64
- );
65
- __exportStar(require('./accounts/pollingOracleSubscriber'), exports);
66
- __exportStar(require('./accounts/pollingTokenAccountSubscriber'), exports);
67
- __exportStar(require('./accounts/types'), exports);
68
- __exportStar(require('./addresses/pda'), exports);
69
- __exportStar(require('./admin'), exports);
70
- __exportStar(require('./clearingHouseUser'), exports);
71
- __exportStar(require('./clearingHouseUserConfig'), exports);
72
- __exportStar(require('./clearingHouse'), exports);
73
- __exportStar(require('./factory/oracleClient'), exports);
74
- __exportStar(require('./factory/bigNum'), exports);
75
- __exportStar(require('./events/types'), exports);
76
- __exportStar(require('./events/eventSubscriber'), exports);
77
- __exportStar(require('./math/auction'), exports);
78
- __exportStar(require('./math/conversion'), exports);
79
- __exportStar(require('./math/funding'), exports);
80
- __exportStar(require('./math/market'), exports);
81
- __exportStar(require('./math/position'), exports);
82
- __exportStar(require('./math/oracles'), exports);
83
- __exportStar(require('./math/amm'), exports);
84
- __exportStar(require('./math/trade'), exports);
85
- __exportStar(require('./math/orders'), exports);
86
- __exportStar(require('./math/repeg'), exports);
87
- __exportStar(require('./orders'), exports);
88
- __exportStar(require('./orderParams'), exports);
89
- __exportStar(require('./slot/SlotSubscriber'), exports);
90
- __exportStar(require('./wallet'), exports);
91
- __exportStar(require('./types'), exports);
92
- __exportStar(require('./math/utils'), exports);
93
- __exportStar(require('./config'), exports);
94
- __exportStar(require('./constants/numericConstants'), exports);
95
- __exportStar(require('./tx/retryTxSender'), exports);
96
- __exportStar(require('./util/computeUnits'), exports);
97
- __exportStar(require('./util/tps'), exports);
98
- __exportStar(require('./math/bankBalance'), exports);
99
- __exportStar(require('./constants/banks'), exports);
100
- __exportStar(require('./clearingHouseConfig'), exports);
23
+ __exportStar(require("./tokenFaucet"), exports);
24
+ __exportStar(require("./oracles/types"), exports);
25
+ __exportStar(require("./oracles/pythClient"), exports);
26
+ __exportStar(require("./oracles/switchboardClient"), exports);
27
+ __exportStar(require("./types"), exports);
28
+ __exportStar(require("./constants/markets"), exports);
29
+ __exportStar(require("./accounts/fetch"), exports);
30
+ __exportStar(require("./accounts/webSocketClearingHouseAccountSubscriber"), exports);
31
+ __exportStar(require("./accounts/bulkAccountLoader"), exports);
32
+ __exportStar(require("./accounts/bulkUserSubscription"), exports);
33
+ __exportStar(require("./accounts/pollingClearingHouseAccountSubscriber"), exports);
34
+ __exportStar(require("./accounts/pollingOracleSubscriber"), exports);
35
+ __exportStar(require("./accounts/pollingTokenAccountSubscriber"), exports);
36
+ __exportStar(require("./accounts/types"), exports);
37
+ __exportStar(require("./addresses/pda"), exports);
38
+ __exportStar(require("./admin"), exports);
39
+ __exportStar(require("./clearingHouseUser"), exports);
40
+ __exportStar(require("./clearingHouseUserConfig"), exports);
41
+ __exportStar(require("./clearingHouse"), exports);
42
+ __exportStar(require("./factory/oracleClient"), exports);
43
+ __exportStar(require("./factory/bigNum"), exports);
44
+ __exportStar(require("./events/types"), exports);
45
+ __exportStar(require("./events/eventSubscriber"), exports);
46
+ __exportStar(require("./math/auction"), exports);
47
+ __exportStar(require("./math/conversion"), exports);
48
+ __exportStar(require("./math/funding"), exports);
49
+ __exportStar(require("./math/market"), exports);
50
+ __exportStar(require("./math/position"), exports);
51
+ __exportStar(require("./math/oracles"), exports);
52
+ __exportStar(require("./math/amm"), exports);
53
+ __exportStar(require("./math/trade"), exports);
54
+ __exportStar(require("./math/orders"), exports);
55
+ __exportStar(require("./math/repeg"), exports);
56
+ __exportStar(require("./orders"), exports);
57
+ __exportStar(require("./orderParams"), exports);
58
+ __exportStar(require("./slot/SlotSubscriber"), exports);
59
+ __exportStar(require("./wallet"), exports);
60
+ __exportStar(require("./types"), exports);
61
+ __exportStar(require("./math/utils"), exports);
62
+ __exportStar(require("./config"), exports);
63
+ __exportStar(require("./constants/numericConstants"), exports);
64
+ __exportStar(require("./tx/retryTxSender"), exports);
65
+ __exportStar(require("./util/computeUnits"), exports);
66
+ __exportStar(require("./util/tps"), exports);
67
+ __exportStar(require("./math/bankBalance"), exports);
68
+ __exportStar(require("./constants/banks"), exports);
69
+ __exportStar(require("./clearingHouseConfig"), exports);
package/src/index.ts CHANGED
@@ -35,6 +35,7 @@ export * from './math/amm';
35
35
  export * from './math/trade';
36
36
  export * from './math/orders';
37
37
  export * from './math/repeg';
38
+ export * from './math/margin';
38
39
  export * from './orders';
39
40
  export * from './orderParams';
40
41
  export * from './slot/SlotSubscriber';
@@ -1,4 +1,9 @@
1
- import { BankAccount, BankBalanceType, isVariant } from '../types';
1
+ import {
2
+ BankAccount,
3
+ BankBalanceType,
4
+ isVariant,
5
+ MarginCategory,
6
+ } from '../types';
2
7
  import { BN } from '@project-serum/anchor';
3
8
  import {
4
9
  BANK_UTILIZATION_PRECISION,
@@ -6,8 +11,14 @@ import {
6
11
  TEN,
7
12
  ZERO,
8
13
  BANK_INTEREST_PRECISION,
14
+ BANK_WEIGHT_PRECISION,
9
15
  ONE_YEAR,
16
+ AMM_RESERVE_PRECISION,
10
17
  } from '../constants/numericConstants';
18
+ import {
19
+ calculateSizeDiscountAssetWeight,
20
+ calculateSizePremiumLiabilityWeight,
21
+ } from './margin';
11
22
 
12
23
  export function getBalance(
13
24
  tokenAmount: BN,
@@ -43,6 +54,92 @@ export function getTokenAmount(
43
54
  return balanceAmount.mul(cumulativeInterest).div(precisionDecrease);
44
55
  }
45
56
 
57
+ export function calculateAssetWeight(
58
+ balanceAmount: BN,
59
+ bank: BankAccount,
60
+ marginCategory: MarginCategory
61
+ ): BN {
62
+ const sizePrecision = TEN.pow(new BN(bank.decimals));
63
+ let sizeInAmmReservePrecision;
64
+ if (sizePrecision.gt(AMM_RESERVE_PRECISION)) {
65
+ sizeInAmmReservePrecision = balanceAmount.div(
66
+ sizePrecision.div(AMM_RESERVE_PRECISION)
67
+ );
68
+ } else {
69
+ sizeInAmmReservePrecision = balanceAmount
70
+ .mul(AMM_RESERVE_PRECISION)
71
+ .div(sizePrecision);
72
+ }
73
+
74
+ let assetWeight;
75
+
76
+ switch (marginCategory) {
77
+ case 'Initial':
78
+ assetWeight = calculateSizeDiscountAssetWeight(
79
+ sizeInAmmReservePrecision,
80
+ bank.imfFactor,
81
+ bank.initialAssetWeight
82
+ );
83
+ break;
84
+ case 'Maintenance':
85
+ assetWeight = calculateSizeDiscountAssetWeight(
86
+ sizeInAmmReservePrecision,
87
+ bank.imfFactor,
88
+ bank.maintenanceAssetWeight
89
+ );
90
+ break;
91
+ default:
92
+ assetWeight = bank.initialAssetWeight;
93
+ break;
94
+ }
95
+
96
+ return assetWeight;
97
+ }
98
+
99
+ export function calculateLiabilityWeight(
100
+ balanceAmount: BN,
101
+ bank: BankAccount,
102
+ marginCategory: MarginCategory
103
+ ): BN {
104
+ const sizePrecision = TEN.pow(new BN(bank.decimals));
105
+ let sizeInAmmReservePrecision;
106
+ if (sizePrecision.gt(AMM_RESERVE_PRECISION)) {
107
+ sizeInAmmReservePrecision = balanceAmount.div(
108
+ sizePrecision.div(AMM_RESERVE_PRECISION)
109
+ );
110
+ } else {
111
+ sizeInAmmReservePrecision = balanceAmount
112
+ .mul(AMM_RESERVE_PRECISION)
113
+ .div(sizePrecision);
114
+ }
115
+
116
+ let assetWeight;
117
+
118
+ switch (marginCategory) {
119
+ case 'Initial':
120
+ assetWeight = calculateSizePremiumLiabilityWeight(
121
+ sizeInAmmReservePrecision,
122
+ bank.imfFactor,
123
+ bank.initialLiabilityWeight,
124
+ BANK_WEIGHT_PRECISION
125
+ );
126
+ break;
127
+ case 'Maintenance':
128
+ assetWeight = calculateSizePremiumLiabilityWeight(
129
+ sizeInAmmReservePrecision,
130
+ bank.imfFactor,
131
+ bank.maintenanceLiabilityWeight,
132
+ BANK_WEIGHT_PRECISION
133
+ );
134
+ break;
135
+ default:
136
+ assetWeight = bank.initialLiabilityWeight;
137
+ break;
138
+ }
139
+
140
+ return assetWeight;
141
+ }
142
+
46
143
  export function calculateInterestAccumulated(
47
144
  bank: BankAccount,
48
145
  now: BN
@@ -0,0 +1,124 @@
1
+ import { squareRootBN } from './utils';
2
+ import {
3
+ BANK_WEIGHT_PRECISION,
4
+ BANK_IMF_PRECISION,
5
+ ZERO,
6
+ BID_ASK_SPREAD_PRECISION,
7
+ AMM_TO_QUOTE_PRECISION_RATIO,
8
+ MARK_PRICE_PRECISION,
9
+ } from '../constants/numericConstants';
10
+ import { BN } from '@project-serum/anchor';
11
+ import { OraclePriceData } from '../oracles/types';
12
+ import { MarketAccount, UserPosition } from '..';
13
+
14
+ export function calculateSizePremiumLiabilityWeight(
15
+ size: BN, // AMM_RESERVE_PRECISION
16
+ imfFactor: BN,
17
+ liabilityWeight: BN,
18
+ precision: BN
19
+ ): BN {
20
+ if (imfFactor.eq(ZERO)) {
21
+ return liabilityWeight;
22
+ }
23
+
24
+ const sizeSqrt = squareRootBN(size.div(new BN(1000)).add(new BN(1))); //1e13 -> 1e10 -> 1e5
25
+ const liabilityWeightNumerator = liabilityWeight.sub(
26
+ liabilityWeight.div(BN.max(new BN(1), BANK_IMF_PRECISION.div(imfFactor)))
27
+ );
28
+
29
+ const sizePremiumLiabilityWeight = liabilityWeightNumerator.add(
30
+ sizeSqrt // 1e5
31
+ .mul(imfFactor)
32
+ .div(new BN(100_000).mul(BANK_IMF_PRECISION).div(precision)) // 1e5
33
+ );
34
+
35
+ const maxLiabilityWeight = BN.max(
36
+ liabilityWeight,
37
+ sizePremiumLiabilityWeight
38
+ );
39
+ return maxLiabilityWeight;
40
+ }
41
+
42
+ export function calculateSizeDiscountAssetWeight(
43
+ size: BN, // AMM_RESERVE_PRECISION
44
+ imfFactor: BN,
45
+ assetWeight: BN
46
+ ): BN {
47
+ if (imfFactor.eq(ZERO)) {
48
+ return assetWeight;
49
+ }
50
+
51
+ const sizeSqrt = squareRootBN(size.div(new BN(1000)).add(new BN(1))); //1e13 -> 1e10 -> 1e5
52
+ const imfNumerator = BANK_IMF_PRECISION.add(
53
+ BANK_IMF_PRECISION.div(new BN(10))
54
+ );
55
+
56
+ const sizeDiscountAssetWeight = imfNumerator.mul(BANK_WEIGHT_PRECISION).div(
57
+ BANK_IMF_PRECISION.add(
58
+ sizeSqrt // 1e5
59
+ .mul(imfFactor)
60
+ .div(new BN(100_000)) // 1e5
61
+ )
62
+ );
63
+
64
+ const minAssetWeight = BN.min(assetWeight, sizeDiscountAssetWeight);
65
+
66
+ return minAssetWeight;
67
+ }
68
+
69
+ export function calculateOraclePriceForPerpMargin(
70
+ marketPosition: UserPosition,
71
+ market: MarketAccount,
72
+ oraclePriceData: OraclePriceData
73
+ ): BN {
74
+ const oraclePriceOffset = BN.min(
75
+ new BN(market.amm.maxSpread)
76
+ .mul(oraclePriceData.price)
77
+ .div(BID_ASK_SPREAD_PRECISION),
78
+ oraclePriceData.confidence.add(
79
+ new BN(market.amm.baseSpread)
80
+ .mul(oraclePriceData.price)
81
+ .div(BID_ASK_SPREAD_PRECISION)
82
+ )
83
+ );
84
+
85
+ let marginPrice: BN;
86
+ if (marketPosition.baseAssetAmount.gt(ZERO)) {
87
+ marginPrice = oraclePriceData.price.sub(oraclePriceOffset);
88
+ } else {
89
+ marginPrice = oraclePriceData.price.add(oraclePriceOffset);
90
+ }
91
+
92
+ return marginPrice;
93
+ }
94
+
95
+ export function calculateMarginBaseAssetValue(
96
+ market: MarketAccount,
97
+ marketPosition: UserPosition,
98
+ oraclePriceData: OraclePriceData
99
+ ): BN {
100
+ const marginPrice = calculateOraclePriceForPerpMargin(
101
+ marketPosition,
102
+ market,
103
+ oraclePriceData
104
+ );
105
+ const baseAssetValue = marketPosition.baseAssetAmount
106
+ .abs()
107
+ .mul(marginPrice)
108
+ .div(AMM_TO_QUOTE_PRECISION_RATIO.mul(MARK_PRICE_PRECISION));
109
+
110
+ return baseAssetValue;
111
+ }
112
+
113
+ export function calculateWorstCaseBaseAssetAmount(
114
+ marketPosition: UserPosition
115
+ ): BN {
116
+ const allBids = marketPosition.baseAssetAmount.add(marketPosition.openBids);
117
+ const allAsks = marketPosition.baseAssetAmount.add(marketPosition.openAsks);
118
+
119
+ if (allBids.abs().gt(allAsks.abs())) {
120
+ return allBids;
121
+ } else {
122
+ return allAsks;
123
+ }
124
+ }
@@ -1,5 +1,11 @@
1
1
  import { BN } from '@project-serum/anchor';
2
- import { MarketAccount, PositionDirection } from '../types';
2
+ import {
3
+ MarketAccount,
4
+ PositionDirection,
5
+ MarginCategory,
6
+ BankAccount,
7
+ BankBalanceType,
8
+ } from '../types';
3
9
  import {
4
10
  calculateAmmReservesAfterSwap,
5
11
  calculatePrice,
@@ -7,7 +13,13 @@ import {
7
13
  getSwapDirection,
8
14
  calculateUpdatedAMM,
9
15
  } from './amm';
16
+ import {
17
+ calculateSizeDiscountAssetWeight,
18
+ calculateSizePremiumLiabilityWeight,
19
+ } from './margin';
10
20
  import { OraclePriceData } from '../oracles/types';
21
+ import { MARGIN_PRECISION } from '../constants/numericConstants';
22
+ import { getTokenAmount } from './bankBalance';
11
23
 
12
24
  /**
13
25
  * Calculates market mark price
@@ -103,3 +115,56 @@ export function calculateOracleSpread(
103
115
  ): BN {
104
116
  return price.sub(oraclePriceData.price);
105
117
  }
118
+
119
+ export function calculateMarketMarginRatio(
120
+ market: MarketAccount,
121
+ size: BN,
122
+ marginCategory: MarginCategory
123
+ ): number {
124
+ let marginRatio;
125
+ switch (marginCategory) {
126
+ case 'Initial':
127
+ marginRatio = calculateSizePremiumLiabilityWeight(
128
+ size,
129
+ market.imfFactor,
130
+ new BN(market.marginRatioInitial),
131
+ MARGIN_PRECISION
132
+ ).toNumber();
133
+ break;
134
+ case 'Maintenance':
135
+ marginRatio = market.marginRatioMaintenance;
136
+ break;
137
+ }
138
+
139
+ return marginRatio;
140
+ }
141
+
142
+ export function calculateUnsettledAssetWeight(
143
+ market: MarketAccount,
144
+ unsettledPnl: BN,
145
+ marginCategory: MarginCategory
146
+ ): BN {
147
+ let assetWeight: BN;
148
+
149
+ switch (marginCategory) {
150
+ case 'Initial':
151
+ assetWeight = calculateSizeDiscountAssetWeight(
152
+ unsettledPnl,
153
+ market.unsettledImfFactor,
154
+ new BN(market.unsettledInitialAssetWeight)
155
+ );
156
+ break;
157
+ case 'Maintenance':
158
+ assetWeight = new BN(market.unsettledMaintenanceAssetWeight);
159
+ break;
160
+ }
161
+
162
+ return assetWeight;
163
+ }
164
+
165
+ export function calculateMarketAvailablePNL(
166
+ market: MarketAccount,
167
+ bank: BankAccount
168
+ ): BN {
169
+ return getTokenAmount(market.pnlPool.balance, bank, BankBalanceType.DEPOSIT);
170
+ }
@@ -18,6 +18,8 @@ import {
18
18
  getSwapDirection,
19
19
  } from './amm';
20
20
 
21
+ import { calculateMarginBaseAssetValue } from './margin';
22
+
21
23
  /**
22
24
  * calculateBaseAssetValue
23
25
  * = market value of closing entire position
@@ -84,6 +86,7 @@ export function calculateBaseAssetValue(
84
86
  * @param market
85
87
  * @param marketPosition
86
88
  * @param withFunding (adds unrealized funding payment pnl to result)
89
+ * @param oraclePriceData
87
90
  * @returns BaseAssetAmount : Precision QUOTE_PRECISION
88
91
  */
89
92
  export function calculatePositionPNL(
@@ -93,21 +96,21 @@ export function calculatePositionPNL(
93
96
  oraclePriceData: OraclePriceData
94
97
  ): BN {
95
98
  if (marketPosition.baseAssetAmount.eq(ZERO)) {
96
- return ZERO;
99
+ return marketPosition.quoteAssetAmount;
97
100
  }
98
101
 
99
- const baseAssetValue = calculateBaseAssetValue(
102
+ const baseAssetValue = calculateMarginBaseAssetValue(
100
103
  market,
101
104
  marketPosition,
102
105
  oraclePriceData
103
106
  );
104
107
 
105
- let pnl;
106
- if (marketPosition.baseAssetAmount.gt(ZERO)) {
107
- pnl = baseAssetValue.sub(marketPosition.quoteAssetAmount);
108
- } else {
109
- pnl = marketPosition.quoteAssetAmount.sub(baseAssetValue);
110
- }
108
+ const baseAssetValueSign = marketPosition.baseAssetAmount.isNeg()
109
+ ? new BN(-1)
110
+ : new BN(1);
111
+ let pnl = baseAssetValue
112
+ .mul(baseAssetValueSign)
113
+ .add(marketPosition.quoteAssetAmount);
111
114
 
112
115
  if (withFunding) {
113
116
  const fundingRatePnL = calculatePositionFundingPNL(
@@ -121,6 +124,36 @@ export function calculatePositionPNL(
121
124
  return pnl;
122
125
  }
123
126
 
127
+ export function calculateUnsettledPnl(
128
+ market: MarketAccount,
129
+ marketPosition: UserPosition,
130
+ oraclePriceData: OraclePriceData
131
+ ): BN {
132
+ const unrealizedPnl = calculatePositionPNL(
133
+ market,
134
+ marketPosition,
135
+ true,
136
+ oraclePriceData
137
+ );
138
+
139
+ let unsettledPnl = unrealizedPnl;
140
+ if (unrealizedPnl.gt(ZERO)) {
141
+ const fundingPnL = calculatePositionFundingPNL(market, marketPosition).div(
142
+ PRICE_TO_QUOTE_PRECISION
143
+ );
144
+
145
+ const maxPositivePnl = BN.max(
146
+ marketPosition.quoteAssetAmount
147
+ .add(marketPosition.quoteEntryAmount)
148
+ .add(fundingPnL),
149
+ ZERO
150
+ );
151
+
152
+ unsettledPnl = BN.min(maxPositivePnl, unrealizedPnl);
153
+ }
154
+ return unsettledPnl;
155
+ }
156
+
124
157
  /**
125
158
  *
126
159
  * @param market
@@ -156,7 +189,7 @@ export function positionIsAvailable(position: UserPosition): boolean {
156
189
  return (
157
190
  position.baseAssetAmount.eq(ZERO) &&
158
191
  position.openOrders.eq(ZERO) &&
159
- position.unsettledPnl.eq(ZERO)
192
+ position.quoteAssetAmount.eq(ZERO)
160
193
  );
161
194
  }
162
195
 
@@ -170,6 +203,23 @@ export function calculateEntryPrice(userPosition: UserPosition): BN {
170
203
  return ZERO;
171
204
  }
172
205
 
206
+ return userPosition.quoteEntryAmount
207
+ .mul(MARK_PRICE_PRECISION)
208
+ .mul(AMM_TO_QUOTE_PRECISION_RATIO)
209
+ .div(userPosition.baseAssetAmount)
210
+ .abs();
211
+ }
212
+
213
+ /**
214
+ *
215
+ * @param userPosition
216
+ * @returns Precision: MARK_PRICE_PRECISION (10^10)
217
+ */
218
+ export function calculateCostBasis(userPosition: UserPosition): BN {
219
+ if (userPosition.baseAssetAmount.eq(ZERO)) {
220
+ return ZERO;
221
+ }
222
+
173
223
  return userPosition.quoteAssetAmount
174
224
  .mul(MARK_PRICE_PRECISION)
175
225
  .mul(AMM_TO_QUOTE_PRECISION_RATIO)