@drift-labs/sdk 0.1.36-master.7 → 0.2.0-master.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.
Files changed (197) hide show
  1. package/lib/accounts/bulkAccountLoader.d.ts +6 -6
  2. package/lib/accounts/bulkAccountLoader.js +81 -95
  3. package/lib/accounts/bulkUserSubscription.js +13 -57
  4. package/lib/accounts/fetch.d.ts +4 -0
  5. package/lib/accounts/fetch.js +18 -0
  6. package/lib/accounts/pollingClearingHouseAccountSubscriber.d.ts +34 -38
  7. package/lib/accounts/pollingClearingHouseAccountSubscriber.js +224 -224
  8. package/lib/accounts/pollingOracleSubscriber.d.ts +3 -3
  9. package/lib/accounts/pollingOracleSubscriber.js +37 -49
  10. package/lib/accounts/pollingTokenAccountSubscriber.d.ts +3 -3
  11. package/lib/accounts/pollingTokenAccountSubscriber.js +35 -50
  12. package/lib/accounts/pollingUserAccountSubscriber.d.ts +7 -13
  13. package/lib/accounts/pollingUserAccountSubscriber.js +71 -134
  14. package/lib/accounts/types.d.ts +34 -41
  15. package/lib/accounts/webSocketAccountSubscriber.d.ts +6 -4
  16. package/lib/accounts/webSocketAccountSubscriber.js +39 -35
  17. package/lib/accounts/webSocketClearingHouseAccountSubscriber.d.ts +33 -28
  18. package/lib/accounts/webSocketClearingHouseAccountSubscriber.js +153 -185
  19. package/lib/accounts/webSocketUserAccountSubscriber.d.ts +5 -11
  20. package/lib/accounts/webSocketUserAccountSubscriber.js +22 -67
  21. package/lib/addresses/marketAddresses.d.ts +4 -0
  22. package/lib/addresses/marketAddresses.js +15 -0
  23. package/lib/addresses/pda.d.ts +12 -0
  24. package/lib/addresses/pda.js +83 -0
  25. package/lib/admin.d.ts +9 -17
  26. package/lib/admin.js +375 -558
  27. package/lib/clearingHouse.d.ts +86 -109
  28. package/lib/clearingHouse.js +828 -895
  29. package/lib/clearingHouseConfig.d.ts +34 -0
  30. package/lib/clearingHouseConfig.js +2 -0
  31. package/lib/clearingHouseUser.d.ts +19 -22
  32. package/lib/clearingHouseUser.js +155 -141
  33. package/lib/clearingHouseUserConfig.d.ts +14 -0
  34. package/lib/clearingHouseUserConfig.js +2 -0
  35. package/lib/config.d.ts +12 -0
  36. package/lib/config.js +35 -4
  37. package/lib/constants/banks.d.ts +16 -0
  38. package/lib/constants/banks.js +34 -0
  39. package/lib/constants/markets.d.ts +8 -3
  40. package/lib/constants/markets.js +13 -206
  41. package/lib/constants/numericConstants.d.ts +17 -0
  42. package/lib/constants/numericConstants.js +23 -6
  43. package/lib/events/eventList.d.ts +22 -0
  44. package/lib/events/eventList.js +77 -0
  45. package/lib/events/eventSubscriber.d.ts +34 -0
  46. package/lib/events/eventSubscriber.js +126 -0
  47. package/lib/events/fetchLogs.d.ts +13 -0
  48. package/lib/events/fetchLogs.js +39 -0
  49. package/lib/events/pollingLogProvider.d.ts +15 -0
  50. package/lib/events/pollingLogProvider.js +53 -0
  51. package/lib/events/sort.d.ts +2 -0
  52. package/lib/events/sort.js +44 -0
  53. package/lib/events/txEventCache.d.ts +24 -0
  54. package/lib/events/txEventCache.js +71 -0
  55. package/lib/events/types.d.ts +49 -0
  56. package/lib/events/types.js +20 -0
  57. package/lib/events/webSocketLogProvider.d.ts +12 -0
  58. package/lib/events/webSocketLogProvider.js +30 -0
  59. package/lib/examples/makeTradeExample.js +26 -27
  60. package/lib/factory/bigNum.d.ts +118 -0
  61. package/lib/factory/bigNum.js +364 -0
  62. package/lib/factory/oracleClient.d.ts +1 -2
  63. package/lib/factory/oracleClient.js +6 -2
  64. package/lib/idl/clearing_house.json +2287 -2938
  65. package/lib/index.d.ts +12 -4
  66. package/lib/index.js +12 -4
  67. package/lib/math/amm.d.ts +24 -29
  68. package/lib/math/amm.js +239 -178
  69. package/lib/math/auction.d.ts +5 -0
  70. package/lib/math/auction.js +39 -0
  71. package/lib/math/bankBalance.d.ts +9 -0
  72. package/lib/math/bankBalance.js +75 -0
  73. package/lib/math/conversion.d.ts +0 -1
  74. package/lib/math/conversion.js +1 -5
  75. package/lib/math/funding.d.ts +6 -6
  76. package/lib/math/funding.js +158 -175
  77. package/lib/math/market.d.ts +6 -6
  78. package/lib/math/market.js +10 -9
  79. package/lib/math/orders.d.ts +5 -0
  80. package/lib/math/orders.js +31 -1
  81. package/lib/math/position.d.ts +7 -5
  82. package/lib/math/position.js +27 -27
  83. package/lib/math/repeg.d.ts +22 -0
  84. package/lib/math/repeg.js +128 -0
  85. package/lib/math/trade.d.ts +5 -4
  86. package/lib/math/trade.js +29 -21
  87. package/lib/mockUSDCFaucet.js +87 -116
  88. package/lib/oracles/oracleClientCache.d.ts +8 -0
  89. package/lib/oracles/oracleClientCache.js +19 -0
  90. package/lib/oracles/pythClient.d.ts +3 -5
  91. package/lib/oracles/pythClient.js +12 -31
  92. package/lib/oracles/quoteAssetOracleClient.d.ts +9 -0
  93. package/lib/oracles/quoteAssetOracleClient.js +21 -0
  94. package/lib/oracles/switchboardClient.d.ts +3 -5
  95. package/lib/oracles/switchboardClient.js +29 -50
  96. package/lib/oracles/types.d.ts +6 -1
  97. package/lib/orders.d.ts +6 -7
  98. package/lib/orders.js +10 -80
  99. package/lib/slot/SlotSubscriber.d.ts +12 -0
  100. package/lib/slot/SlotSubscriber.js +23 -0
  101. package/lib/tx/retryTxSender.d.ts +2 -2
  102. package/lib/tx/retryTxSender.js +108 -123
  103. package/lib/tx/types.d.ts +5 -1
  104. package/lib/tx/utils.d.ts +1 -1
  105. package/lib/tx/utils.js +11 -2
  106. package/lib/types.d.ts +110 -109
  107. package/lib/types.js +14 -1
  108. package/lib/userName.d.ts +4 -0
  109. package/lib/userName.js +20 -0
  110. package/lib/util/computeUnits.js +10 -21
  111. package/lib/util/tps.js +11 -22
  112. package/lib/wallet.js +7 -20
  113. package/package.json +11 -4
  114. package/src/accounts/bulkAccountLoader.ts +21 -15
  115. package/src/accounts/bulkUserSubscription.ts +1 -45
  116. package/src/accounts/fetch.ts +33 -0
  117. package/src/accounts/pollingClearingHouseAccountSubscriber.ts +249 -214
  118. package/src/accounts/pollingOracleSubscriber.ts +16 -8
  119. package/src/accounts/pollingTokenAccountSubscriber.ts +11 -8
  120. package/src/accounts/pollingUserAccountSubscriber.ts +21 -86
  121. package/src/accounts/types.ts +41 -70
  122. package/src/accounts/webSocketAccountSubscriber.ts +33 -16
  123. package/src/accounts/webSocketClearingHouseAccountSubscriber.ts +190 -240
  124. package/src/accounts/webSocketUserAccountSubscriber.ts +11 -71
  125. package/src/addresses/marketAddresses.ts +18 -0
  126. package/src/addresses/pda.ts +118 -0
  127. package/src/admin.ts +218 -346
  128. package/src/clearingHouse.ts +983 -952
  129. package/src/clearingHouseConfig.ts +37 -0
  130. package/src/clearingHouseUser.ts +275 -185
  131. package/src/clearingHouseUserConfig.ts +18 -0
  132. package/src/config.ts +54 -1
  133. package/src/constants/banks.ts +43 -0
  134. package/src/constants/markets.ts +16 -207
  135. package/src/constants/numericConstants.ts +34 -5
  136. package/src/events/eventList.ts +94 -0
  137. package/src/events/eventSubscriber.ts +194 -0
  138. package/src/events/fetchLogs.ts +80 -0
  139. package/src/events/pollingLogProvider.ts +79 -0
  140. package/src/events/sort.ts +65 -0
  141. package/src/events/txEventCache.ts +74 -0
  142. package/src/events/types.ts +98 -0
  143. package/src/events/webSocketLogProvider.ts +38 -0
  144. package/src/examples/makeTradeExample.ts +20 -11
  145. package/src/factory/bigNum.ts +524 -0
  146. package/src/factory/oracleClient.ts +7 -4
  147. package/src/idl/clearing_house.json +2287 -2938
  148. package/src/index.ts +12 -4
  149. package/src/math/amm.ts +414 -245
  150. package/src/math/auction.ts +39 -0
  151. package/src/math/bankBalance.ts +112 -0
  152. package/src/math/conversion.ts +1 -11
  153. package/src/math/funding.ts +12 -9
  154. package/src/math/market.ts +37 -30
  155. package/src/math/orders.ts +38 -0
  156. package/src/math/position.ts +48 -35
  157. package/src/math/repeg.ts +176 -0
  158. package/src/math/trade.ts +45 -35
  159. package/src/math/utils.js +27 -0
  160. package/src/math/utils.js.map +1 -0
  161. package/src/oracles/oracleClientCache.ts +20 -0
  162. package/src/oracles/pythClient.ts +4 -11
  163. package/src/oracles/quoteAssetOracleClient.ts +25 -0
  164. package/src/oracles/switchboardClient.ts +11 -24
  165. package/src/oracles/types.ts +7 -1
  166. package/src/orders.ts +24 -126
  167. package/src/slot/SlotSubscriber.ts +32 -0
  168. package/src/tx/retryTxSender.ts +6 -4
  169. package/src/tx/types.ts +6 -1
  170. package/src/tx/utils.ts +22 -3
  171. package/src/types.ts +111 -122
  172. package/src/userName.ts +20 -0
  173. package/src/util/computeUnits.js +17 -0
  174. package/src/util/computeUnits.js.map +1 -0
  175. package/tests/bn/test.ts +255 -0
  176. package/tsconfig.json +12 -12
  177. package/lib/addresses.d.ts +0 -10
  178. package/lib/addresses.js +0 -93
  179. package/lib/constants/accounts.d.ts +0 -15
  180. package/lib/constants/accounts.js +0 -18
  181. package/lib/factory/clearingHouse.d.ts +0 -35
  182. package/lib/factory/clearingHouse.js +0 -81
  183. package/lib/factory/clearingHouseUser.d.ts +0 -19
  184. package/lib/factory/clearingHouseUser.js +0 -34
  185. package/lib/math/insuranceFund.d.ts +0 -15
  186. package/lib/math/insuranceFund.js +0 -33
  187. package/lib/settlement.d.ts +0 -4
  188. package/lib/settlement.js +0 -10
  189. package/lib/tx/defaultTxSender.d.ts +0 -8
  190. package/lib/tx/defaultTxSender.js +0 -12
  191. package/src/addresses.ts +0 -82
  192. package/src/constants/accounts.ts +0 -26
  193. package/src/factory/clearingHouse.ts +0 -173
  194. package/src/factory/clearingHouseUser.ts +0 -73
  195. package/src/math/insuranceFund.ts +0 -29
  196. package/src/settlement.ts +0 -9
  197. package/src/tx/defaultTxSender.ts +0 -24
@@ -6,16 +6,10 @@ import {
6
6
  isVariant,
7
7
  MarginCategory,
8
8
  Order,
9
- SettlementStateAccount,
10
9
  UserAccount,
11
- UserOrdersAccount,
12
10
  UserPosition,
13
- UserPositionsAccount,
14
11
  } from './types';
15
- import {
16
- calculateEntryPrice,
17
- calculateSettledPositionPNL,
18
- } from './math/position';
12
+ import { calculateEntryPrice } from './math/position';
19
13
  import {
20
14
  MARK_PRICE_PRECISION,
21
15
  AMM_TO_QUOTE_PRECISION_RATIO,
@@ -26,30 +20,33 @@ import {
26
20
  AMM_RESERVE_PRECISION,
27
21
  PRICE_TO_QUOTE_PRECISION,
28
22
  MARGIN_PRECISION,
23
+ BANK_WEIGHT_PRECISION,
29
24
  } from './constants/numericConstants';
30
- import { UserAccountSubscriber, UserAccountEvents } from './accounts/types';
25
+ import {
26
+ UserAccountSubscriber,
27
+ UserAccountEvents,
28
+ DataAndSlot,
29
+ } from './accounts/types';
31
30
  import {
32
31
  calculateMarkPrice,
33
32
  calculateBaseAssetValue,
34
33
  calculatePositionFundingPNL,
35
34
  calculatePositionPNL,
36
35
  PositionDirection,
37
- getUserOrdersAccountPublicKey,
38
36
  calculateTradeSlippage,
39
37
  BN,
38
+ BankAccount,
40
39
  } from '.';
41
- import { getUserAccountPublicKey } from './addresses';
42
- import {
43
- getClearingHouseUser,
44
- getWebSocketClearingHouseUserConfig,
45
- } from './factory/clearingHouseUser';
40
+ import { getTokenAmount } from './math/bankBalance';
41
+ import { OraclePriceData } from './oracles/types';
42
+ import { ClearingHouseUserConfig } from './clearingHouseUserConfig';
43
+ import { PollingUserAccountSubscriber } from './accounts/pollingUserAccountSubscriber';
44
+ import { WebSocketUserAccountSubscriber } from './accounts/webSocketUserAccountSubscriber';
46
45
 
47
46
  export class ClearingHouseUser {
48
47
  clearingHouse: ClearingHouse;
49
- authority: PublicKey;
48
+ userAccountPublicKey: PublicKey;
50
49
  accountSubscriber: UserAccountSubscriber;
51
- userAccountPublicKey?: PublicKey;
52
- userOrdersAccountPublicKey?: PublicKey;
53
50
  _isSubscribed = false;
54
51
  eventEmitter: StrictEventEmitter<EventEmitter, UserAccountEvents>;
55
52
 
@@ -61,34 +58,21 @@ export class ClearingHouseUser {
61
58
  this._isSubscribed = val;
62
59
  }
63
60
 
64
- /**
65
- * @deprecated You should use getClearingHouseUser factory method instead
66
- * @param clearingHouse
67
- * @param authority
68
- * @returns
69
- */
70
- public static from(
71
- clearingHouse: ClearingHouse,
72
- authority: PublicKey
73
- ): ClearingHouseUser {
74
- if (clearingHouse.accountSubscriber.type !== 'websocket')
75
- throw 'This method only works for clearing houses with a websocket account listener. Try using the getClearingHouseUser factory method to initialize a ClearingHouseUser instead';
76
-
77
- const config = getWebSocketClearingHouseUserConfig(
78
- clearingHouse,
79
- authority
80
- );
81
- return getClearingHouseUser(config);
82
- }
83
-
84
- public constructor(
85
- clearingHouse: ClearingHouse,
86
- authority: PublicKey,
87
- accountSubscriber: UserAccountSubscriber
88
- ) {
89
- this.clearingHouse = clearingHouse;
90
- this.authority = authority;
91
- this.accountSubscriber = accountSubscriber;
61
+ public constructor(config: ClearingHouseUserConfig) {
62
+ this.clearingHouse = config.clearingHouse;
63
+ this.userAccountPublicKey = config.userAccountPublicKey;
64
+ if (config.accountSubscription?.type === 'polling') {
65
+ this.accountSubscriber = new PollingUserAccountSubscriber(
66
+ config.clearingHouse.program,
67
+ config.userAccountPublicKey,
68
+ config.accountSubscription.accountLoader
69
+ );
70
+ } else {
71
+ this.accountSubscriber = new WebSocketUserAccountSubscriber(
72
+ config.clearingHouse.program,
73
+ config.userAccountPublicKey
74
+ );
75
+ }
92
76
  this.eventEmitter = this.accountSubscriber.eventEmitter;
93
77
  }
94
78
 
@@ -97,9 +81,6 @@ export class ClearingHouseUser {
97
81
  * @returns SusbcriptionSuccess result
98
82
  */
99
83
  public async subscribe(): Promise<boolean> {
100
- // Clearing house should already be subscribed, but await for the subscription just incase to avoid race condition
101
- await this.clearingHouse.subscribe();
102
-
103
84
  this.isSubscribed = await this.accountSubscriber.subscribe();
104
85
  return this.isSubscribed;
105
86
  }
@@ -117,15 +98,11 @@ export class ClearingHouseUser {
117
98
  }
118
99
 
119
100
  public getUserAccount(): UserAccount {
120
- return this.accountSubscriber.getUserAccount();
101
+ return this.accountSubscriber.getUserAccountAndSlot().data;
121
102
  }
122
103
 
123
- public getUserPositionsAccount(): UserPositionsAccount {
124
- return this.accountSubscriber.getUserPositionsAccount();
125
- }
126
-
127
- public getUserOrdersAccount(): UserOrdersAccount | undefined {
128
- return this.accountSubscriber.getUserOrdersAccount();
104
+ public getUserAccountAndSlot(): DataAndSlot<UserAccount> | undefined {
105
+ return this.accountSubscriber.getUserAccountAndSlot();
129
106
  }
130
107
 
131
108
  /**
@@ -134,7 +111,7 @@ export class ClearingHouseUser {
134
111
  * @returns userPosition
135
112
  */
136
113
  public getUserPosition(marketIndex: BN): UserPosition | undefined {
137
- return this.getUserPositionsAccount().positions.find((position) =>
114
+ return this.getUserAccount().positions.find((position) =>
138
115
  position.marketIndex.eq(marketIndex)
139
116
  );
140
117
  }
@@ -145,7 +122,11 @@ export class ClearingHouseUser {
145
122
  lastCumulativeFundingRate: ZERO,
146
123
  marketIndex,
147
124
  quoteAssetAmount: ZERO,
125
+ quoteEntryAmount: ZERO,
148
126
  openOrders: ZERO,
127
+ unsettledPnl: ZERO,
128
+ openBids: ZERO,
129
+ openAsks: ZERO,
149
130
  };
150
131
  }
151
132
 
@@ -154,7 +135,7 @@ export class ClearingHouseUser {
154
135
  * @returns Order
155
136
  */
156
137
  public getOrder(orderId: BN): Order | undefined {
157
- return this.getUserOrdersAccount().orders.find((order) =>
138
+ return this.getUserAccount().orders.find((order) =>
158
139
  order.orderId.eq(orderId)
159
140
  );
160
141
  }
@@ -164,40 +145,19 @@ export class ClearingHouseUser {
164
145
  * @returns Order
165
146
  */
166
147
  public getOrderByUserOrderId(userOrderId: number): Order | undefined {
167
- return this.getUserOrdersAccount().orders.find(
148
+ return this.getUserAccount().orders.find(
168
149
  (order) => order.userOrderId === userOrderId
169
150
  );
170
151
  }
171
152
 
172
- public async getUserAccountPublicKey(): Promise<PublicKey> {
173
- if (this.userAccountPublicKey) {
174
- return this.userAccountPublicKey;
175
- }
176
-
177
- this.userAccountPublicKey = await getUserAccountPublicKey(
178
- this.clearingHouse.program.programId,
179
- this.authority
180
- );
153
+ public getUserAccountPublicKey(): PublicKey {
181
154
  return this.userAccountPublicKey;
182
155
  }
183
156
 
184
- public async getUserOrdersAccountPublicKey(): Promise<PublicKey> {
185
- if (this.userOrdersAccountPublicKey) {
186
- return this.userOrdersAccountPublicKey;
187
- }
188
-
189
- this.userOrdersAccountPublicKey = await getUserOrdersAccountPublicKey(
190
- this.clearingHouse.program.programId,
191
- await this.getUserAccountPublicKey()
192
- );
193
- return this.userOrdersAccountPublicKey;
194
- }
195
-
196
157
  public async exists(): Promise<boolean> {
197
- const userAccountPublicKey = await this.getUserAccountPublicKey();
198
158
  const userAccountRPCResponse =
199
159
  await this.clearingHouse.connection.getParsedAccountInfo(
200
- userAccountPublicKey
160
+ this.userAccountPublicKey
201
161
  );
202
162
  return userAccountRPCResponse.value !== null;
203
163
  }
@@ -224,34 +184,44 @@ export class ClearingHouseUser {
224
184
  }
225
185
 
226
186
  public getInitialMarginRequirement(): BN {
227
- return this.getUserPositionsAccount().positions.reduce(
228
- (marginRequirement, marketPosition) => {
229
- const market = this.clearingHouse.getMarket(marketPosition.marketIndex);
187
+ return this.getUserAccount()
188
+ .positions.reduce((marginRequirement, marketPosition) => {
189
+ const market = this.clearingHouse.getMarketAccount(
190
+ marketPosition.marketIndex
191
+ );
230
192
  return marginRequirement.add(
231
- calculateBaseAssetValue(market, marketPosition)
193
+ calculateBaseAssetValue(
194
+ market,
195
+ marketPosition,
196
+ this.getOracleDataForMarket(market.marketIndex)
197
+ )
232
198
  .mul(new BN(market.marginRatioInitial))
233
199
  .div(MARGIN_PRECISION)
234
200
  );
235
- },
236
- ZERO
237
- );
201
+ }, ZERO)
202
+ .add(this.getTotalLiability());
238
203
  }
239
204
 
240
205
  /**
241
206
  * @returns The partial margin requirement in USDC. : QUOTE_PRECISION
242
207
  */
243
208
  public getPartialMarginRequirement(): BN {
244
- return this.getUserPositionsAccount().positions.reduce(
245
- (marginRequirement, marketPosition) => {
246
- const market = this.clearingHouse.getMarket(marketPosition.marketIndex);
209
+ return this.getUserAccount()
210
+ .positions.reduce((marginRequirement, marketPosition) => {
211
+ const market = this.clearingHouse.getMarketAccount(
212
+ marketPosition.marketIndex
213
+ );
247
214
  return marginRequirement.add(
248
- calculateBaseAssetValue(market, marketPosition)
215
+ calculateBaseAssetValue(
216
+ market,
217
+ marketPosition,
218
+ this.getOracleDataForMarket(market.marketIndex)
219
+ )
249
220
  .mul(new BN(market.marginRatioPartial))
250
221
  .div(MARGIN_PRECISION)
251
222
  );
252
- },
253
- ZERO
254
- );
223
+ }, ZERO)
224
+ .add(this.getTotalLiability());
255
225
  }
256
226
 
257
227
  /**
@@ -259,42 +229,158 @@ export class ClearingHouseUser {
259
229
  * @returns : Precision QUOTE_PRECISION
260
230
  */
261
231
  public getUnrealizedPNL(withFunding?: boolean, marketIndex?: BN): BN {
262
- return this.getUserPositionsAccount()
232
+ return this.getUserAccount()
263
233
  .positions.filter((pos) =>
264
234
  marketIndex ? pos.marketIndex === marketIndex : true
265
235
  )
266
236
  .reduce((pnl, marketPosition) => {
267
- const market = this.clearingHouse.getMarket(marketPosition.marketIndex);
237
+ const market = this.clearingHouse.getMarketAccount(
238
+ marketPosition.marketIndex
239
+ );
268
240
  return pnl.add(
269
- calculatePositionPNL(market, marketPosition, withFunding)
241
+ calculatePositionPNL(
242
+ market,
243
+ marketPosition,
244
+ withFunding,
245
+ this.getOracleDataForMarket(market.marketIndex)
246
+ )
270
247
  );
271
248
  }, ZERO);
272
249
  }
273
250
 
251
+ /**
252
+ * calculates unrealized position price pnl
253
+ * @returns : Precision QUOTE_PRECISION
254
+ */
255
+ public getUnsettledPNL(marketIndex?: BN): BN {
256
+ return this.getUserAccount()
257
+ .positions.filter((pos) =>
258
+ marketIndex ? pos.marketIndex === marketIndex : true
259
+ )
260
+ .reduce((pnl, marketPosition) => {
261
+ return pnl.add(marketPosition.unsettledPnl);
262
+ }, ZERO);
263
+ }
264
+
274
265
  /**
275
266
  * calculates unrealized funding payment pnl
276
267
  * @returns : Precision QUOTE_PRECISION
277
268
  */
278
269
  public getUnrealizedFundingPNL(marketIndex?: BN): BN {
279
- return this.getUserPositionsAccount()
270
+ return this.getUserAccount()
280
271
  .positions.filter((pos) =>
281
272
  marketIndex ? pos.marketIndex === marketIndex : true
282
273
  )
283
274
  .reduce((pnl, marketPosition) => {
284
- const market = this.clearingHouse.getMarket(marketPosition.marketIndex);
275
+ const market = this.clearingHouse.getMarketAccount(
276
+ marketPosition.marketIndex
277
+ );
285
278
  return pnl.add(calculatePositionFundingPNL(market, marketPosition));
286
279
  }, ZERO);
287
280
  }
288
281
 
282
+ public getTotalLiability(): BN {
283
+ return this.getUserAccount().bankBalances.reduce(
284
+ (totalAssetValue, bankBalance) => {
285
+ if (
286
+ bankBalance.balance.eq(ZERO) ||
287
+ isVariant(bankBalance.balanceType, 'deposit')
288
+ ) {
289
+ return totalAssetValue;
290
+ }
291
+
292
+ // Todo this needs to account for whether it's based on initial or maintenance requirements
293
+ const bankAccount: BankAccount = this.clearingHouse.getBankAccount(
294
+ bankBalance.bankIndex
295
+ );
296
+
297
+ const tokenAmount = getTokenAmount(
298
+ bankBalance.balance,
299
+ bankAccount,
300
+ bankBalance.balanceType
301
+ );
302
+ return totalAssetValue.add(
303
+ tokenAmount
304
+ .mul(this.getOracleDataForBank(bankAccount.bankIndex).price)
305
+ .mul(bankAccount.initialLiabilityWeight)
306
+ .div(BANK_WEIGHT_PRECISION)
307
+ .div(MARK_PRICE_PRECISION)
308
+ );
309
+ },
310
+ ZERO
311
+ );
312
+ }
313
+
314
+ public getCollateralValue(bankIndex?: BN): BN {
315
+ return this.getUserAccount().bankBalances.reduce(
316
+ (totalAssetValue, bankBalance) => {
317
+ if (
318
+ bankBalance.balance.eq(ZERO) ||
319
+ (bankIndex !== undefined && !bankBalance.bankIndex.eq(bankIndex))
320
+ ) {
321
+ return totalAssetValue;
322
+ }
323
+
324
+ // Todo this needs to account for whether it's based on initial or maintenance requirements
325
+ const bankAccount: BankAccount = this.clearingHouse.getBankAccount(
326
+ bankBalance.bankIndex
327
+ );
328
+
329
+ let tokenAmount = getTokenAmount(
330
+ bankBalance.balance,
331
+ bankAccount,
332
+ bankBalance.balanceType
333
+ );
334
+
335
+ if (isVariant(bankBalance.balanceType, 'borrow')) {
336
+ tokenAmount = tokenAmount.mul(new BN(-1));
337
+ }
338
+
339
+ return totalAssetValue.add(
340
+ tokenAmount
341
+ .mul(this.getOracleDataForBank(bankAccount.bankIndex).price)
342
+ .div(MARK_PRICE_PRECISION)
343
+ );
344
+ },
345
+ ZERO
346
+ );
347
+ }
348
+
289
349
  /**
290
350
  * calculates TotalCollateral: collateral + unrealized pnl
351
+ * TODO: rename to total equity (for perpetuals swaps)
291
352
  * @returns : Precision QUOTE_PRECISION
292
353
  */
293
354
  public getTotalCollateral(): BN {
294
- return (
295
- this.getUserAccount().collateral.add(this.getUnrealizedPNL(true)) ??
296
- new BN(0)
297
- );
355
+ return this.getUserAccount()
356
+ .bankBalances.reduce((totalAssetValue, bankBalance) => {
357
+ if (
358
+ bankBalance.balance.eq(ZERO) ||
359
+ isVariant(bankBalance.balanceType, 'borrow')
360
+ ) {
361
+ return totalAssetValue;
362
+ }
363
+
364
+ // Todo this needs to account for whether it's based on initial or maintenance requirements
365
+ const bankAccount: BankAccount = this.clearingHouse.getBankAccount(
366
+ bankBalance.bankIndex
367
+ );
368
+
369
+ const tokenAmount = getTokenAmount(
370
+ bankBalance.balance,
371
+ bankAccount,
372
+ bankBalance.balanceType
373
+ );
374
+ return totalAssetValue.add(
375
+ tokenAmount
376
+ .mul(this.getOracleDataForBank(bankAccount.bankIndex).price)
377
+ .mul(bankAccount.initialAssetWeight)
378
+ .div(BANK_WEIGHT_PRECISION)
379
+ .div(MARK_PRICE_PRECISION)
380
+ );
381
+ }, ZERO)
382
+ .add(this.getUnrealizedPNL(true))
383
+ .add(this.getUnsettledPNL());
298
384
  }
299
385
 
300
386
  /**
@@ -302,11 +388,17 @@ export class ClearingHouseUser {
302
388
  * @returns : Precision QUOTE_PRECISION
303
389
  */
304
390
  getTotalPositionValue(): BN {
305
- return this.getUserPositionsAccount().positions.reduce(
391
+ return this.getUserAccount().positions.reduce(
306
392
  (positionValue, marketPosition) => {
307
- const market = this.clearingHouse.getMarket(marketPosition.marketIndex);
393
+ const market = this.clearingHouse.getMarketAccount(
394
+ marketPosition.marketIndex
395
+ );
308
396
  return positionValue.add(
309
- calculateBaseAssetValue(market, marketPosition)
397
+ calculateBaseAssetValue(
398
+ market,
399
+ marketPosition,
400
+ this.getOracleDataForMarket(market.marketIndex)
401
+ )
310
402
  );
311
403
  },
312
404
  ZERO
@@ -317,11 +409,16 @@ export class ClearingHouseUser {
317
409
  * calculates position value from closing 100%
318
410
  * @returns : Precision QUOTE_PRECISION
319
411
  */
320
- public getPositionValue(marketIndex: BN): BN {
412
+ public getPositionValue(
413
+ marketIndex: BN,
414
+ oraclePriceData: OraclePriceData
415
+ ): BN {
321
416
  const userPosition =
322
417
  this.getUserPosition(marketIndex) || this.getEmptyPosition(marketIndex);
323
- const market = this.clearingHouse.getMarket(userPosition.marketIndex);
324
- return calculateBaseAssetValue(market, userPosition);
418
+ const market = this.clearingHouse.getMarketAccount(
419
+ userPosition.marketIndex
420
+ );
421
+ return calculateBaseAssetValue(market, userPosition, oraclePriceData);
325
422
  }
326
423
 
327
424
  public getPositionSide(
@@ -344,13 +441,15 @@ export class ClearingHouseUser {
344
441
  position: UserPosition,
345
442
  amountToClose?: BN
346
443
  ): [BN, BN] {
347
- const market = this.clearingHouse.getMarket(position.marketIndex);
444
+ const market = this.clearingHouse.getMarketAccount(position.marketIndex);
348
445
 
349
446
  const entryPrice = calculateEntryPrice(position);
350
447
 
448
+ const oraclePriceData = this.getOracleDataForMarket(position.marketIndex);
449
+
351
450
  if (amountToClose) {
352
451
  if (amountToClose.eq(ZERO)) {
353
- return [calculateMarkPrice(market), ZERO];
452
+ return [calculateMarkPrice(market, oraclePriceData), ZERO];
354
453
  }
355
454
  position = {
356
455
  baseAssetAmount: amountToClose,
@@ -360,7 +459,11 @@ export class ClearingHouseUser {
360
459
  } as UserPosition;
361
460
  }
362
461
 
363
- const baseAssetValue = calculateBaseAssetValue(market, position);
462
+ const baseAssetValue = calculateBaseAssetValue(
463
+ market,
464
+ position,
465
+ oraclePriceData
466
+ );
364
467
  if (position.baseAssetAmount.eq(ZERO)) {
365
468
  return [ZERO, ZERO];
366
469
  }
@@ -401,7 +504,7 @@ export class ClearingHouseUser {
401
504
  marketIndex: BN | number,
402
505
  category: MarginCategory = 'Initial'
403
506
  ): BN {
404
- const market = this.clearingHouse.getMarket(marketIndex);
507
+ const market = this.clearingHouse.getMarketAccount(marketIndex);
405
508
  let marginRatioCategory: number;
406
509
 
407
510
  switch (category) {
@@ -451,14 +554,14 @@ export class ClearingHouseUser {
451
554
  * @returns
452
555
  */
453
556
  public needsToSettleFundingPayment(): boolean {
454
- const marketsAccount = this.clearingHouse.getMarketsAccount();
455
- for (const userPosition of this.getUserPositionsAccount().positions) {
557
+ for (const userPosition of this.getUserAccount().positions) {
456
558
  if (userPosition.baseAssetAmount.eq(ZERO)) {
457
559
  continue;
458
560
  }
459
561
 
460
- const market =
461
- marketsAccount.markets[userPosition.marketIndex.toNumber()];
562
+ const market = this.clearingHouse.getMarketAccount(
563
+ userPosition.marketIndex
564
+ );
462
565
  if (
463
566
  market.amm.cumulativeFundingRateLong.eq(
464
567
  userPosition.lastCumulativeFundingRate
@@ -522,18 +625,23 @@ export class ClearingHouseUser {
522
625
  lastCumulativeFundingRate:
523
626
  currentMarketPosition.lastCumulativeFundingRate,
524
627
  quoteAssetAmount: new BN(0),
628
+ quoteEntryAmount: new BN(0),
525
629
  openOrders: new BN(0),
630
+ unsettledPnl: new BN(0),
631
+ openBids: new BN(0),
632
+ openAsks: new BN(0),
526
633
  };
527
634
 
528
635
  if (proposedBaseAssetAmount.eq(ZERO)) return new BN(-1);
529
636
 
530
- const market = this.clearingHouse.getMarket(
637
+ const market = this.clearingHouse.getMarketAccount(
531
638
  proposedMarketPosition.marketIndex
532
639
  );
533
640
 
534
641
  const proposedMarketPositionValue = calculateBaseAssetValue(
535
642
  market,
536
- proposedMarketPosition
643
+ proposedMarketPosition,
644
+ this.getOracleDataForMarket(market.marketIndex)
537
645
  );
538
646
 
539
647
  // total position value after trade
@@ -541,11 +649,17 @@ export class ClearingHouseUser {
541
649
  totalPositionValueExcludingTargetMarket.add(proposedMarketPositionValue);
542
650
 
543
651
  const marginRequirementExcludingTargetMarket =
544
- this.getUserPositionsAccount().positions.reduce(
652
+ this.getUserAccount().positions.reduce(
545
653
  (totalMarginRequirement, position) => {
546
654
  if (!position.marketIndex.eq(marketPosition.marketIndex)) {
547
- const market = this.clearingHouse.getMarket(position.marketIndex);
548
- const positionValue = calculateBaseAssetValue(market, position);
655
+ const market = this.clearingHouse.getMarketAccount(
656
+ position.marketIndex
657
+ );
658
+ const positionValue = calculateBaseAssetValue(
659
+ market,
660
+ position,
661
+ this.getOracleDataForMarket(market.marketIndex)
662
+ );
549
663
  const marketMarginRequirement = positionValue
550
664
  .mul(
551
665
  partial
@@ -612,7 +726,8 @@ export class ClearingHouseUser {
612
726
  let markPriceAfterTrade;
613
727
  if (positionBaseSizeChange.eq(ZERO)) {
614
728
  markPriceAfterTrade = calculateMarkPrice(
615
- this.clearingHouse.getMarket(marketPosition.marketIndex)
729
+ this.clearingHouse.getMarketAccount(marketPosition.marketIndex),
730
+ this.getOracleDataForMarket(marketPosition.marketIndex)
616
731
  );
617
732
  } else {
618
733
  const direction = positionBaseSizeChange.gt(ZERO)
@@ -621,8 +736,9 @@ export class ClearingHouseUser {
621
736
  markPriceAfterTrade = calculateTradeSlippage(
622
737
  direction,
623
738
  positionBaseSizeChange.abs(),
624
- this.clearingHouse.getMarket(marketPosition.marketIndex),
625
- 'base'
739
+ this.clearingHouse.getMarketAccount(marketPosition.marketIndex),
740
+ 'base',
741
+ this.getOracleDataForMarket(marketPosition.marketIndex)
626
742
  )[3]; // newPrice after swap
627
743
  }
628
744
 
@@ -661,7 +777,8 @@ export class ClearingHouseUser {
661
777
  {
662
778
  marketIndex: positionMarketIndex,
663
779
  },
664
- closeBaseAmount
780
+ closeBaseAmount,
781
+ true
665
782
  );
666
783
  }
667
784
 
@@ -704,10 +821,12 @@ export class ClearingHouseUser {
704
821
  ? true
705
822
  : targetSide === currentPositionSide;
706
823
 
824
+ const oracleData = this.getOracleDataForMarket(targetMarketIndex);
825
+
707
826
  // add any position we have on the opposite side of the current trade, because we can "flip" the size of this position without taking any extra leverage.
708
827
  const oppositeSizeValueUSDC = targetingSameSide
709
828
  ? ZERO
710
- : this.getPositionValue(targetMarketIndex);
829
+ : this.getPositionValue(targetMarketIndex, oracleData);
711
830
 
712
831
  let maxPositionSize = this.getBuyingPower(targetMarketIndex);
713
832
  if (maxPositionSize.gte(ZERO)) {
@@ -724,8 +843,11 @@ export class ClearingHouseUser {
724
843
  // current leverage is greater than max leverage - can only reduce position size
725
844
 
726
845
  if (!targetingSameSide) {
727
- const market = this.clearingHouse.getMarket(targetMarketIndex);
728
- const marketPositionValue = this.getPositionValue(targetMarketIndex);
846
+ const market = this.clearingHouse.getMarketAccount(targetMarketIndex);
847
+ const marketPositionValue = this.getPositionValue(
848
+ targetMarketIndex,
849
+ oracleData
850
+ );
729
851
  const totalCollateral = this.getTotalCollateral();
730
852
  const marginRequirement = this.getInitialMarginRequirement();
731
853
  const marginFreedByClosing = marketPositionValue
@@ -774,7 +896,12 @@ export class ClearingHouseUser {
774
896
  this.getUserPosition(targetMarketIndex) ||
775
897
  this.getEmptyPosition(targetMarketIndex);
776
898
 
777
- let currentPositionQuoteAmount = this.getPositionValue(targetMarketIndex);
899
+ const oracleData = this.getOracleDataForMarket(targetMarketIndex);
900
+
901
+ let currentPositionQuoteAmount = this.getPositionValue(
902
+ targetMarketIndex,
903
+ oracleData
904
+ );
778
905
 
779
906
  const currentSide =
780
907
  currentPosition && currentPosition.baseAssetAmount.isNeg()
@@ -830,70 +957,33 @@ export class ClearingHouseUser {
830
957
  this.getUserPosition(marketToIgnore) ||
831
958
  this.getEmptyPosition(marketToIgnore);
832
959
 
960
+ const oracleData = this.getOracleDataForMarket(marketToIgnore);
961
+
833
962
  let currentMarketPositionValueUSDC = ZERO;
834
963
  if (currentMarketPosition) {
835
- currentMarketPositionValueUSDC = this.getPositionValue(marketToIgnore);
964
+ currentMarketPositionValueUSDC = this.getPositionValue(
965
+ marketToIgnore,
966
+ oracleData
967
+ );
836
968
  }
837
969
 
838
970
  return this.getTotalPositionValue().sub(currentMarketPositionValueUSDC);
839
971
  }
840
972
 
841
- public getClaimableCollateral(settlementState: SettlementStateAccount): BN {
842
- return this.getSettledPositionValue()
843
- .mul(
844
- settlementState.collateralAvailableToClaim.sub(
845
- this.getUserAccount().lastCollateralAvailableToClaim
846
- )
847
- )
848
- .div(settlementState.totalSettlementValue);
849
- }
850
-
851
- public getSettledPositionValue(): BN {
852
- return BN.max(
853
- this.getUserAccount()
854
- .collateral.add(
855
- this.getUnrealizedFundingPNL().div(PRICE_TO_QUOTE_PRECISION)
856
- )
857
- .add(this.getSettledPositionsPNL()),
858
- ZERO
859
- );
860
- }
973
+ private getOracleDataForMarket(marketIndex: BN): OraclePriceData {
974
+ const oracleKey =
975
+ this.clearingHouse.getMarketAccount(marketIndex).amm.oracle;
976
+ const oracleData =
977
+ this.clearingHouse.getOraclePriceDataAndSlot(oracleKey).data;
861
978
 
862
- public getSettledPositionsPNL(): BN {
863
- return this.getUserPositionsAccount().positions.reduce(
864
- (pnl, marketPosition) => {
865
- const market = this.clearingHouse.getMarket(marketPosition.marketIndex);
866
- return pnl.add(calculateSettledPositionPNL(market, marketPosition));
867
- },
868
- ZERO
869
- );
979
+ return oracleData;
870
980
  }
981
+ private getOracleDataForBank(bankIndex: BN): OraclePriceData {
982
+ const oracleKey = this.clearingHouse.getBankAccount(bankIndex).oracle;
871
983
 
872
- public async estimateClaimableCollateral(): Promise<BN> {
873
- const currentCollateralVaultBalance = new BN(
874
- (
875
- await this.clearingHouse.connection.getTokenAccountBalance(
876
- this.clearingHouse.getStateAccount().collateralVault
877
- )
878
- ).value.amount
879
- );
880
- const currentInsuranceVaultBalance = new BN(
881
- (
882
- await this.clearingHouse.connection.getTokenAccountBalance(
883
- this.clearingHouse.getStateAccount().insuranceVault
884
- )
885
- ).value.amount
886
- );
887
-
888
- const totalClaimableCollateral = currentCollateralVaultBalance.add(
889
- currentInsuranceVaultBalance
890
- );
891
- const totalEstimatedSettlementValue =
892
- await this.clearingHouse.getTotalSettlementSize();
893
- const userSettledPositionValue = await this.getSettledPositionValue();
984
+ const oracleData =
985
+ this.clearingHouse.getOraclePriceDataAndSlot(oracleKey).data;
894
986
 
895
- return totalClaimableCollateral
896
- .mul(userSettledPositionValue)
897
- .div(totalEstimatedSettlementValue);
987
+ return oracleData;
898
988
  }
899
989
  }