@drift-labs/sdk 0.2.0-master.3 → 0.2.0-master.31

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 (208) hide show
  1. package/README.md +13 -13
  2. package/lib/accounts/bulkUserStatsSubscription.d.ts +7 -0
  3. package/lib/accounts/bulkUserStatsSubscription.js +21 -0
  4. package/lib/accounts/bulkUserSubscription.js +0 -1
  5. package/lib/accounts/fetch.d.ts +2 -1
  6. package/lib/accounts/fetch.js +9 -1
  7. package/lib/accounts/pollingClearingHouseAccountSubscriber.d.ts +16 -16
  8. package/lib/accounts/pollingClearingHouseAccountSubscriber.js +31 -28
  9. package/lib/accounts/pollingUserStatsAccountSubscriber.d.ts +27 -0
  10. package/lib/accounts/pollingUserStatsAccountSubscriber.js +113 -0
  11. package/lib/accounts/types.d.ts +22 -11
  12. package/lib/accounts/webSocketClearingHouseAccountSubscriber.d.ts +17 -17
  13. package/lib/accounts/webSocketClearingHouseAccountSubscriber.js +37 -35
  14. package/lib/accounts/webSocketUserStatsAccountSubsriber.d.ts +20 -0
  15. package/lib/accounts/webSocketUserStatsAccountSubsriber.js +47 -0
  16. package/lib/addresses/marketAddresses.d.ts +1 -3
  17. package/lib/addresses/pda.d.ts +10 -4
  18. package/lib/addresses/pda.js +51 -14
  19. package/lib/admin.d.ts +42 -26
  20. package/lib/admin.js +228 -81
  21. package/lib/clearingHouse.d.ts +130 -49
  22. package/lib/clearingHouse.js +1256 -367
  23. package/lib/clearingHouseConfig.d.ts +4 -4
  24. package/lib/clearingHouseUser.d.ts +51 -39
  25. package/lib/clearingHouseUser.js +408 -191
  26. package/lib/clearingHouseUserStats.d.ts +18 -0
  27. package/lib/clearingHouseUserStats.js +49 -0
  28. package/lib/clearingHouseUserStatsConfig.d.ts +14 -0
  29. package/lib/clearingHouseUserStatsConfig.js +2 -0
  30. package/lib/config.d.ts +7 -9
  31. package/lib/config.js +21 -21
  32. package/lib/constants/numericConstants.d.ts +25 -12
  33. package/lib/constants/numericConstants.js +35 -21
  34. package/lib/constants/perpMarkets.d.ts +18 -0
  35. package/lib/constants/{markets.js → perpMarkets.js} +7 -7
  36. package/lib/constants/spotMarkets.d.ts +19 -0
  37. package/lib/constants/spotMarkets.js +53 -0
  38. package/lib/dlob/DLOB.d.ts +74 -0
  39. package/lib/dlob/DLOB.js +595 -0
  40. package/lib/dlob/DLOBNode.d.ts +54 -0
  41. package/lib/dlob/DLOBNode.js +85 -0
  42. package/lib/dlob/NodeList.d.ts +26 -0
  43. package/lib/dlob/NodeList.js +139 -0
  44. package/lib/events/eventList.js +3 -0
  45. package/lib/events/eventSubscriber.d.ts +4 -2
  46. package/lib/events/eventSubscriber.js +16 -9
  47. package/lib/events/fetchLogs.d.ts +10 -1
  48. package/lib/events/fetchLogs.js +27 -7
  49. package/lib/events/pollingLogProvider.d.ts +2 -1
  50. package/lib/events/pollingLogProvider.js +6 -2
  51. package/lib/events/sort.js +8 -11
  52. package/lib/events/types.d.ts +8 -2
  53. package/lib/events/types.js +6 -0
  54. package/lib/examples/makeTradeExample.js +20 -8
  55. package/lib/factory/bigNum.d.ts +2 -0
  56. package/lib/factory/bigNum.js +48 -10
  57. package/lib/idl/clearing_house.json +4889 -1529
  58. package/lib/idl/{mock_usdc_faucet.json → token_faucet.json} +46 -23
  59. package/lib/index.d.ts +21 -6
  60. package/lib/index.js +25 -6
  61. package/lib/math/amm.d.ts +9 -6
  62. package/lib/math/amm.js +91 -66
  63. package/lib/math/auction.js +4 -1
  64. package/lib/math/conversion.js +1 -1
  65. package/lib/math/funding.d.ts +6 -6
  66. package/lib/math/funding.js +11 -10
  67. package/lib/math/insurance.d.ts +4 -0
  68. package/lib/math/insurance.js +27 -0
  69. package/lib/math/margin.d.ts +11 -0
  70. package/lib/math/margin.js +77 -0
  71. package/lib/math/market.d.ts +14 -9
  72. package/lib/math/market.js +72 -10
  73. package/lib/math/oracles.d.ts +4 -0
  74. package/lib/math/oracles.js +36 -8
  75. package/lib/math/orders.d.ts +6 -2
  76. package/lib/math/orders.js +78 -3
  77. package/lib/math/position.d.ts +21 -13
  78. package/lib/math/position.js +76 -36
  79. package/lib/math/repeg.js +14 -5
  80. package/lib/math/spotBalance.d.ts +22 -0
  81. package/lib/math/spotBalance.js +192 -0
  82. package/lib/math/spotMarket.d.ts +4 -0
  83. package/lib/math/spotMarket.js +8 -0
  84. package/lib/math/spotPosition.d.ts +6 -0
  85. package/lib/math/spotPosition.js +23 -0
  86. package/lib/math/trade.d.ts +10 -10
  87. package/lib/math/trade.js +32 -39
  88. package/lib/oracles/pythClient.js +1 -1
  89. package/lib/oracles/quoteAssetOracleClient.js +1 -1
  90. package/lib/oracles/switchboardClient.js +1 -1
  91. package/lib/orderParams.d.ts +14 -5
  92. package/lib/orderParams.js +12 -92
  93. package/lib/serum/serumSubscriber.d.ts +23 -0
  94. package/lib/serum/serumSubscriber.js +41 -0
  95. package/lib/serum/types.d.ts +11 -0
  96. package/lib/serum/types.js +2 -0
  97. package/lib/slot/SlotSubscriber.d.ts +7 -0
  98. package/lib/slot/SlotSubscriber.js +3 -0
  99. package/lib/{mockUSDCFaucet.d.ts → tokenFaucet.d.ts} +8 -5
  100. package/lib/{mockUSDCFaucet.js → tokenFaucet.js} +63 -51
  101. package/lib/tx/retryTxSender.d.ts +1 -1
  102. package/lib/tx/retryTxSender.js +13 -4
  103. package/lib/tx/types.d.ts +1 -1
  104. package/lib/tx/utils.js +1 -1
  105. package/lib/types.d.ts +566 -138
  106. package/lib/types.js +129 -5
  107. package/lib/userMap/userMap.d.ts +25 -0
  108. package/lib/userMap/userMap.js +73 -0
  109. package/lib/userMap/userStatsMap.d.ts +19 -0
  110. package/lib/userMap/userStatsMap.js +68 -0
  111. package/lib/util/computeUnits.js +1 -1
  112. package/lib/util/getTokenAddress.d.ts +2 -0
  113. package/lib/util/getTokenAddress.js +9 -0
  114. package/package.json +12 -6
  115. package/src/accounts/bulkUserStatsSubscription.ts +33 -0
  116. package/src/accounts/bulkUserSubscription.ts +0 -1
  117. package/src/accounts/fetch.ts +27 -2
  118. package/src/accounts/pollingClearingHouseAccountSubscriber.ts +46 -42
  119. package/src/accounts/pollingUserStatsAccountSubscriber.ts +172 -0
  120. package/src/accounts/types.ts +31 -11
  121. package/src/accounts/webSocketClearingHouseAccountSubscriber.ts +64 -59
  122. package/src/accounts/webSocketUserStatsAccountSubsriber.ts +80 -0
  123. package/src/addresses/marketAddresses.ts +1 -2
  124. package/src/addresses/pda.ts +88 -14
  125. package/src/admin.ts +452 -147
  126. package/src/assert/assert.js +9 -0
  127. package/src/clearingHouse.ts +2066 -467
  128. package/src/clearingHouseConfig.ts +4 -3
  129. package/src/clearingHouseUser.ts +747 -294
  130. package/src/clearingHouseUserStats.ts +75 -0
  131. package/src/clearingHouseUserStatsConfig.ts +18 -0
  132. package/src/config.ts +30 -31
  133. package/src/constants/numericConstants.ts +48 -25
  134. package/src/constants/{markets.ts → perpMarkets.ts} +10 -10
  135. package/src/constants/spotMarkets.ts +73 -0
  136. package/src/dlob/DLOB.ts +953 -0
  137. package/src/dlob/DLOBNode.ts +167 -0
  138. package/src/dlob/NodeList.ts +189 -0
  139. package/src/events/eventList.js +77 -0
  140. package/src/events/eventList.ts +3 -0
  141. package/src/events/eventSubscriber.ts +20 -12
  142. package/src/events/fetchLogs.ts +35 -8
  143. package/src/events/pollingLogProvider.ts +10 -2
  144. package/src/events/sort.ts +11 -15
  145. package/src/events/types.ts +19 -1
  146. package/src/examples/makeTradeExample.js +157 -0
  147. package/src/examples/makeTradeExample.ts +32 -14
  148. package/src/factory/bigNum.ts +65 -13
  149. package/src/idl/clearing_house.json +4889 -1529
  150. package/src/idl/{mock_usdc_faucet.json → token_faucet.json} +46 -23
  151. package/src/index.ts +21 -6
  152. package/src/math/amm.ts +171 -88
  153. package/src/math/auction.ts +5 -1
  154. package/src/math/conversion.ts +2 -2
  155. package/src/math/funding.ts +20 -18
  156. package/src/math/insurance.ts +35 -0
  157. package/src/math/margin.ts +127 -0
  158. package/src/math/market.ts +145 -14
  159. package/src/math/oracles.ts +63 -9
  160. package/src/math/orders.ts +138 -4
  161. package/src/math/position.ts +119 -58
  162. package/src/math/repeg.ts +16 -6
  163. package/src/math/spotBalance.ts +319 -0
  164. package/src/math/spotMarket.ts +9 -0
  165. package/src/math/spotPosition.ts +47 -0
  166. package/src/math/trade.ts +53 -59
  167. package/src/oracles/pythClient.ts +2 -2
  168. package/src/oracles/quoteAssetOracleClient.ts +2 -2
  169. package/src/oracles/switchboardClient.ts +2 -2
  170. package/src/orderParams.ts +24 -137
  171. package/src/serum/serumSubscriber.ts +80 -0
  172. package/src/serum/types.ts +13 -0
  173. package/src/slot/SlotSubscriber.ts +11 -1
  174. package/src/token/index.js +38 -0
  175. package/src/{mockUSDCFaucet.ts → tokenFaucet.ts} +82 -70
  176. package/src/tx/retryTxSender.ts +16 -5
  177. package/src/tx/types.js +2 -0
  178. package/src/tx/types.ts +2 -1
  179. package/src/tx/utils.js +17 -0
  180. package/src/tx/utils.ts +1 -1
  181. package/src/types.ts +533 -140
  182. package/src/userMap/userMap.ts +100 -0
  183. package/src/userMap/userStatsMap.ts +110 -0
  184. package/src/util/computeUnits.js +21 -11
  185. package/src/util/computeUnits.ts +1 -1
  186. package/src/util/getTokenAddress.js +9 -0
  187. package/src/util/getTokenAddress.ts +18 -0
  188. package/src/util/promiseTimeout.js +14 -0
  189. package/src/util/tps.js +27 -0
  190. package/tests/bn/test.ts +24 -10
  191. package/tests/dlob/helpers.ts +397 -0
  192. package/tests/dlob/test.ts +3688 -0
  193. package/lib/constants/banks.d.ts +0 -16
  194. package/lib/constants/banks.js +0 -34
  195. package/lib/constants/markets.d.ts +0 -19
  196. package/lib/math/bankBalance.d.ts +0 -9
  197. package/lib/math/bankBalance.js +0 -75
  198. package/lib/math/state.d.ts +0 -8
  199. package/lib/math/state.js +0 -15
  200. package/lib/orders.d.ts +0 -8
  201. package/lib/orders.js +0 -134
  202. package/src/constants/banks.ts +0 -43
  203. package/src/math/bankBalance.ts +0 -112
  204. package/src/math/state.ts +0 -14
  205. package/src/math/utils.js +0 -27
  206. package/src/math/utils.js.map +0 -1
  207. package/src/orders.ts +0 -244
  208. package/src/util/computeUnits.js.map +0 -1
@@ -1,12 +1,12 @@
1
1
  import { BN } from '@project-serum/anchor';
2
2
  import {
3
3
  AMM_RESERVE_PRECISION,
4
- MARK_PRICE_PRECISION,
4
+ PRICE_PRECISION,
5
5
  QUOTE_PRECISION,
6
6
  ZERO,
7
7
  } from '../constants/numericConstants';
8
- import { MarketAccount } from '../types';
9
- import { calculateMarkPrice } from './market';
8
+ import { PerpMarketAccount, isVariant } from '../types';
9
+ import { calculateReservePrice } from './market';
10
10
  import { OraclePriceData } from '../oracles/types';
11
11
 
12
12
  /**
@@ -17,7 +17,7 @@ import { OraclePriceData } from '../oracles/types';
17
17
  * @returns Estimated funding rate. : Precision //TODO-PRECISION
18
18
  */
19
19
  export async function calculateAllEstimatedFundingRate(
20
- market: MarketAccount,
20
+ market: PerpMarketAccount,
21
21
  oraclePriceData?: OraclePriceData,
22
22
  periodAdjustment: BN = new BN(1)
23
23
  ): Promise<[BN, BN, BN, BN, BN]> {
@@ -29,7 +29,7 @@ export async function calculateAllEstimatedFundingRate(
29
29
  const hoursInDay = new BN(24);
30
30
  const ONE = new BN(1);
31
31
 
32
- if (!market.initialized) {
32
+ if (isVariant(market.status, 'uninitialized')) {
33
33
  return [ZERO, ZERO, ZERO, ZERO, ZERO];
34
34
  }
35
35
 
@@ -48,7 +48,7 @@ export async function calculateAllEstimatedFundingRate(
48
48
  secondsInHour,
49
49
  BN.max(ZERO, secondsInHour.sub(timeSinceLastMarkChange))
50
50
  );
51
- const baseAssetPriceWithMantissa = calculateMarkPrice(
51
+ const baseAssetPriceWithMantissa = calculateReservePrice(
52
52
  market,
53
53
  oraclePriceData
54
54
  );
@@ -60,8 +60,10 @@ export async function calculateAllEstimatedFundingRate(
60
60
 
61
61
  // calculate real-time (predicted) oracle twap
62
62
  // note: oracle twap depends on `when the chord is struck` (market is trade)
63
- const lastOracleTwapWithMantissa = market.amm.lastOraclePriceTwap;
64
- const lastOraclePriceTwapTs = market.amm.lastOraclePriceTwapTs;
63
+ const lastOracleTwapWithMantissa =
64
+ market.amm.historicalOracleData.lastOraclePriceTwap;
65
+ const lastOraclePriceTwapTs =
66
+ market.amm.historicalOracleData.lastOraclePriceTwapTs;
65
67
 
66
68
  const oracleInvalidDuration = BN.max(
67
69
  ZERO,
@@ -85,12 +87,12 @@ export async function calculateAllEstimatedFundingRate(
85
87
  const oracleLiveVsTwap = oraclePrice
86
88
  .sub(lastOracleTwapWithMantissa)
87
89
  .abs()
88
- .mul(MARK_PRICE_PRECISION)
90
+ .mul(PRICE_PRECISION)
89
91
  .mul(new BN(100))
90
92
  .div(lastOracleTwapWithMantissa);
91
93
 
92
94
  // verify pyth live input is within 10% of last twap for live update
93
- if (oracleLiveVsTwap.lte(MARK_PRICE_PRECISION.mul(new BN(10)))) {
95
+ if (oracleLiveVsTwap.lte(PRICE_PRECISION.mul(new BN(10)))) {
94
96
  oracleTwapWithMantissa = oracleTwapTimeSinceLastUpdate
95
97
  .mul(lastOracleTwapWithMantissa)
96
98
  .add(timeSinceLastMarkChange.mul(oraclePrice))
@@ -108,7 +110,7 @@ export async function calculateAllEstimatedFundingRate(
108
110
  );
109
111
 
110
112
  const twapSpreadPct = twapSpread
111
- .mul(MARK_PRICE_PRECISION)
113
+ .mul(PRICE_PRECISION)
112
114
  .mul(new BN(100))
113
115
  .div(shrunkLastOracleTwapwithMantissa);
114
116
 
@@ -125,7 +127,7 @@ export async function calculateAllEstimatedFundingRate(
125
127
  const interpRateQuote = twapSpreadPct
126
128
  .mul(periodAdjustment)
127
129
  .div(hoursInDay)
128
- .div(MARK_PRICE_PRECISION.div(QUOTE_PRECISION));
130
+ .div(PRICE_PRECISION.div(QUOTE_PRECISION));
129
131
 
130
132
  let feePoolSize = calculateFundingPool(market);
131
133
  if (interpRateQuote.lt(new BN(0))) {
@@ -173,12 +175,12 @@ export async function calculateAllEstimatedFundingRate(
173
175
  // funding smaller flow
174
176
  cappedAltEst = smallerSide.mul(twapSpread).div(hoursInDay);
175
177
  const feePoolTopOff = feePoolSize
176
- .mul(MARK_PRICE_PRECISION.div(QUOTE_PRECISION))
178
+ .mul(PRICE_PRECISION.div(QUOTE_PRECISION))
177
179
  .mul(AMM_RESERVE_PRECISION);
178
180
  cappedAltEst = cappedAltEst.add(feePoolTopOff).div(largerSide);
179
181
 
180
182
  cappedAltEst = cappedAltEst
181
- .mul(MARK_PRICE_PRECISION)
183
+ .mul(PRICE_PRECISION)
182
184
  .mul(new BN(100))
183
185
  .div(oracleTwapWithMantissa)
184
186
  .mul(periodAdjustment);
@@ -208,7 +210,7 @@ export async function calculateAllEstimatedFundingRate(
208
210
  * @returns Estimated funding rate. : Precision //TODO-PRECISION
209
211
  */
210
212
  export async function calculateEstimatedFundingRate(
211
- market: MarketAccount,
213
+ market: PerpMarketAccount,
212
214
  oraclePriceData?: OraclePriceData,
213
215
  periodAdjustment: BN = new BN(1),
214
216
  estimationMethod?: 'interpolated' | 'lowerbound' | 'capped'
@@ -238,7 +240,7 @@ export async function calculateEstimatedFundingRate(
238
240
  * @returns Estimated funding rate. : Precision //TODO-PRECISION
239
241
  */
240
242
  export async function calculateLongShortFundingRate(
241
- market: MarketAccount,
243
+ market: PerpMarketAccount,
242
244
  oraclePriceData?: OraclePriceData,
243
245
  periodAdjustment: BN = new BN(1)
244
246
  ): Promise<[BN, BN]> {
@@ -266,7 +268,7 @@ export async function calculateLongShortFundingRate(
266
268
  * @returns Estimated funding rate. : Precision //TODO-PRECISION
267
269
  */
268
270
  export async function calculateLongShortFundingRateAndLiveTwaps(
269
- market: MarketAccount,
271
+ market: PerpMarketAccount,
270
272
  oraclePriceData?: OraclePriceData,
271
273
  periodAdjustment: BN = new BN(1)
272
274
  ): Promise<[BN, BN, BN, BN]> {
@@ -291,7 +293,7 @@ export async function calculateLongShortFundingRateAndLiveTwaps(
291
293
  * @param market
292
294
  * @returns Estimated fee pool size
293
295
  */
294
- export function calculateFundingPool(market: MarketAccount): BN {
296
+ export function calculateFundingPool(market: PerpMarketAccount): BN {
295
297
  // todo
296
298
  const totalFeeLB = market.amm.totalExchangeFee.div(new BN(2));
297
299
  const feePool = BN.max(
@@ -0,0 +1,35 @@
1
+ import { ZERO } from '../constants/numericConstants';
2
+ import { BN } from '../index';
3
+
4
+ export function stakeAmountToShares(
5
+ amount: BN,
6
+ totalIfShares: BN,
7
+ insuranceFundVaultBalance: BN
8
+ ): BN {
9
+ let nShares: BN;
10
+ if (insuranceFundVaultBalance.gt(ZERO)) {
11
+ nShares = amount.mul(totalIfShares).div(insuranceFundVaultBalance);
12
+ } else {
13
+ nShares = amount;
14
+ }
15
+
16
+ return nShares;
17
+ }
18
+
19
+ export function unstakeSharesToAmount(
20
+ nShares: BN,
21
+ totalIfShares: BN,
22
+ insuranceFundVaultBalance: BN
23
+ ): BN {
24
+ let amount: BN;
25
+ if (totalIfShares.gt(ZERO)) {
26
+ amount = BN.max(
27
+ ZERO,
28
+ nShares.mul(insuranceFundVaultBalance).div(totalIfShares)
29
+ );
30
+ } else {
31
+ amount = ZERO;
32
+ }
33
+
34
+ return amount;
35
+ }
@@ -0,0 +1,127 @@
1
+ import { squareRootBN } from './utils';
2
+ import {
3
+ SPOT_MARKET_WEIGHT_PRECISION,
4
+ SPOT_MARKET_IMF_PRECISION,
5
+ ZERO,
6
+ BID_ASK_SPREAD_PRECISION,
7
+ AMM_RESERVE_PRECISION,
8
+ } from '../constants/numericConstants';
9
+ import { BN } from '@project-serum/anchor';
10
+ import { OraclePriceData } from '../oracles/types';
11
+ import { PerpMarketAccount, PerpPosition } from '..';
12
+ import { assert } from '../assert/assert';
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.mul(new BN(10)).add(new BN(1))); //1e9 -> 1e10 -> 1e5
25
+
26
+ const denom0 = BN.max(new BN(1), SPOT_MARKET_IMF_PRECISION.div(imfFactor));
27
+ assert(denom0.gt(ZERO));
28
+ const liabilityWeightNumerator = liabilityWeight.sub(
29
+ liabilityWeight.div(
30
+ BN.max(new BN(1), SPOT_MARKET_IMF_PRECISION.div(imfFactor))
31
+ )
32
+ );
33
+
34
+ const denom = new BN(100_000).mul(SPOT_MARKET_IMF_PRECISION).div(precision);
35
+ assert(denom.gt(ZERO));
36
+
37
+ const sizePremiumLiabilityWeight = liabilityWeightNumerator.add(
38
+ sizeSqrt // 1e5
39
+ .mul(imfFactor)
40
+ .div(denom) // 1e5
41
+ );
42
+
43
+ const maxLiabilityWeight = BN.max(
44
+ liabilityWeight,
45
+ sizePremiumLiabilityWeight
46
+ );
47
+ return maxLiabilityWeight;
48
+ }
49
+
50
+ export function calculateSizeDiscountAssetWeight(
51
+ size: BN, // AMM_RESERVE_PRECISION
52
+ imfFactor: BN,
53
+ assetWeight: BN
54
+ ): BN {
55
+ if (imfFactor.eq(ZERO)) {
56
+ return assetWeight;
57
+ }
58
+
59
+ const sizeSqrt = squareRootBN(size.mul(new BN(10)).add(new BN(1))); //1e9 -> 1e10 -> 1e5
60
+ const imfNumerator = SPOT_MARKET_IMF_PRECISION.add(
61
+ SPOT_MARKET_IMF_PRECISION.div(new BN(10))
62
+ );
63
+
64
+ const sizeDiscountAssetWeight = imfNumerator
65
+ .mul(SPOT_MARKET_WEIGHT_PRECISION)
66
+ .div(
67
+ SPOT_MARKET_IMF_PRECISION.add(
68
+ sizeSqrt // 1e5
69
+ .mul(imfFactor)
70
+ .div(new BN(100_000)) // 1e5
71
+ )
72
+ );
73
+
74
+ const minAssetWeight = BN.min(assetWeight, sizeDiscountAssetWeight);
75
+
76
+ return minAssetWeight;
77
+ }
78
+
79
+ export function calculateOraclePriceForPerpMargin(
80
+ perpPosition: PerpPosition,
81
+ market: PerpMarketAccount,
82
+ oraclePriceData: OraclePriceData
83
+ ): BN {
84
+ const oraclePriceOffset = BN.min(
85
+ new BN(market.amm.maxSpread)
86
+ .mul(oraclePriceData.price)
87
+ .div(BID_ASK_SPREAD_PRECISION),
88
+ oraclePriceData.confidence.add(
89
+ new BN(market.amm.baseSpread)
90
+ .mul(oraclePriceData.price)
91
+ .div(BID_ASK_SPREAD_PRECISION)
92
+ )
93
+ );
94
+
95
+ let marginPrice: BN;
96
+ if (perpPosition.baseAssetAmount.gt(ZERO)) {
97
+ marginPrice = oraclePriceData.price.sub(oraclePriceOffset);
98
+ } else {
99
+ marginPrice = oraclePriceData.price.add(oraclePriceOffset);
100
+ }
101
+
102
+ return marginPrice;
103
+ }
104
+
105
+ export function calculateBaseAssetValueWithOracle(
106
+ market: PerpMarketAccount,
107
+ perpPosition: PerpPosition,
108
+ oraclePriceData: OraclePriceData
109
+ ): BN {
110
+ return perpPosition.baseAssetAmount
111
+ .abs()
112
+ .mul(oraclePriceData.price)
113
+ .div(AMM_RESERVE_PRECISION);
114
+ }
115
+
116
+ export function calculateWorstCaseBaseAssetAmount(
117
+ perpPosition: PerpPosition
118
+ ): BN {
119
+ const allBids = perpPosition.baseAssetAmount.add(perpPosition.openBids);
120
+ const allAsks = perpPosition.baseAssetAmount.add(perpPosition.openAsks);
121
+
122
+ if (allBids.abs().gt(allAsks.abs())) {
123
+ return allBids;
124
+ } else {
125
+ return allAsks;
126
+ }
127
+ }
@@ -1,5 +1,11 @@
1
1
  import { BN } from '@project-serum/anchor';
2
- import { MarketAccount, PositionDirection } from '../types';
2
+ import {
3
+ PerpMarketAccount,
4
+ PositionDirection,
5
+ MarginCategory,
6
+ SpotMarketAccount,
7
+ SpotBalanceType,
8
+ } from '../types';
3
9
  import {
4
10
  calculateAmmReservesAfterSwap,
5
11
  calculatePrice,
@@ -7,16 +13,27 @@ 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 {
22
+ BASE_PRECISION,
23
+ MARGIN_PRECISION,
24
+ PRICE_TO_QUOTE_PRECISION,
25
+ ZERO,
26
+ } from '../constants/numericConstants';
27
+ import { getTokenAmount } from './spotBalance';
11
28
 
12
29
  /**
13
30
  * Calculates market mark price
14
31
  *
15
32
  * @param market
16
- * @return markPrice : Precision MARK_PRICE_PRECISION
33
+ * @return markPrice : Precision PRICE_PRECISION
17
34
  */
18
- export function calculateMarkPrice(
19
- market: MarketAccount,
35
+ export function calculateReservePrice(
36
+ market: PerpMarketAccount,
20
37
  oraclePriceData: OraclePriceData
21
38
  ): BN {
22
39
  const newAmm = calculateUpdatedAMM(market.amm, oraclePriceData);
@@ -31,10 +48,10 @@ export function calculateMarkPrice(
31
48
  * Calculates market bid price
32
49
  *
33
50
  * @param market
34
- * @return bidPrice : Precision MARK_PRICE_PRECISION
51
+ * @return bidPrice : Precision PRICE_PRECISION
35
52
  */
36
53
  export function calculateBidPrice(
37
- market: MarketAccount,
54
+ market: PerpMarketAccount,
38
55
  oraclePriceData: OraclePriceData
39
56
  ): BN {
40
57
  const { baseAssetReserve, quoteAssetReserve, newPeg } =
@@ -51,10 +68,10 @@ export function calculateBidPrice(
51
68
  * Calculates market ask price
52
69
  *
53
70
  * @param market
54
- * @return bidPrice : Precision MARK_PRICE_PRECISION
71
+ * @return askPrice : Precision PRICE_PRECISION
55
72
  */
56
73
  export function calculateAskPrice(
57
- market: MarketAccount,
74
+ market: PerpMarketAccount,
58
75
  oraclePriceData: OraclePriceData
59
76
  ): BN {
60
77
  const { baseAssetReserve, quoteAssetReserve, newPeg } =
@@ -70,8 +87,8 @@ export function calculateAskPrice(
70
87
  export function calculateNewMarketAfterTrade(
71
88
  baseAssetAmount: BN,
72
89
  direction: PositionDirection,
73
- market: MarketAccount
74
- ): MarketAccount {
90
+ market: PerpMarketAccount
91
+ ): PerpMarketAccount {
75
92
  const [newQuoteAssetReserve, newBaseAssetReserve] =
76
93
  calculateAmmReservesAfterSwap(
77
94
  market.amm,
@@ -89,12 +106,12 @@ export function calculateNewMarketAfterTrade(
89
106
  return newMarket;
90
107
  }
91
108
 
92
- export function calculateMarkOracleSpread(
93
- market: MarketAccount,
109
+ export function calculateOracleReserveSpread(
110
+ market: PerpMarketAccount,
94
111
  oraclePriceData: OraclePriceData
95
112
  ): BN {
96
- const markPrice = calculateMarkPrice(market, oraclePriceData);
97
- return calculateOracleSpread(markPrice, oraclePriceData);
113
+ const reservePrice = calculateReservePrice(market, oraclePriceData);
114
+ return calculateOracleSpread(reservePrice, oraclePriceData);
98
115
  }
99
116
 
100
117
  export function calculateOracleSpread(
@@ -103,3 +120,117 @@ export function calculateOracleSpread(
103
120
  ): BN {
104
121
  return price.sub(oraclePriceData.price);
105
122
  }
123
+
124
+ export function calculateMarketMarginRatio(
125
+ market: PerpMarketAccount,
126
+ size: BN,
127
+ marginCategory: MarginCategory
128
+ ): number {
129
+ let marginRatio;
130
+ switch (marginCategory) {
131
+ case 'Initial':
132
+ marginRatio = calculateSizePremiumLiabilityWeight(
133
+ size,
134
+ market.imfFactor,
135
+ new BN(market.marginRatioInitial),
136
+ MARGIN_PRECISION
137
+ ).toNumber();
138
+ break;
139
+ case 'Maintenance':
140
+ marginRatio = calculateSizePremiumLiabilityWeight(
141
+ size,
142
+ market.imfFactor,
143
+ new BN(market.marginRatioMaintenance),
144
+ MARGIN_PRECISION
145
+ ).toNumber();
146
+ break;
147
+ }
148
+
149
+ return marginRatio;
150
+ }
151
+
152
+ export function calculateUnrealizedAssetWeight(
153
+ market: PerpMarketAccount,
154
+ quoteSpotMarket: SpotMarketAccount,
155
+ unrealizedPnl: BN,
156
+ marginCategory: MarginCategory,
157
+ oraclePriceData: OraclePriceData
158
+ ): BN {
159
+ let assetWeight: BN;
160
+ switch (marginCategory) {
161
+ case 'Initial':
162
+ assetWeight = new BN(market.unrealizedInitialAssetWeight);
163
+
164
+ if (market.unrealizedMaxImbalance.gt(ZERO)) {
165
+ const netUnsettledPnl = calculateNetUserPnlImbalance(
166
+ market,
167
+ quoteSpotMarket,
168
+ oraclePriceData
169
+ );
170
+ if (netUnsettledPnl.gt(market.unrealizedMaxImbalance)) {
171
+ assetWeight = assetWeight
172
+ .mul(market.unrealizedMaxImbalance)
173
+ .div(netUnsettledPnl);
174
+ }
175
+ }
176
+
177
+ assetWeight = calculateSizeDiscountAssetWeight(
178
+ unrealizedPnl,
179
+ market.unrealizedImfFactor,
180
+ assetWeight
181
+ );
182
+ break;
183
+ case 'Maintenance':
184
+ assetWeight = new BN(market.unrealizedMaintenanceAssetWeight);
185
+ break;
186
+ }
187
+
188
+ return assetWeight;
189
+ }
190
+
191
+ export function calculateMarketAvailablePNL(
192
+ perpMarket: PerpMarketAccount,
193
+ spotMarket: SpotMarketAccount
194
+ ): BN {
195
+ return getTokenAmount(
196
+ perpMarket.pnlPool.balance,
197
+ spotMarket,
198
+ SpotBalanceType.DEPOSIT
199
+ );
200
+ }
201
+
202
+ export function calculateNetUserPnl(
203
+ perpMarket: PerpMarketAccount,
204
+ oraclePriceData: OraclePriceData
205
+ ): BN {
206
+ const netUserPositionValue = perpMarket.amm.netBaseAssetAmount
207
+ .mul(oraclePriceData.price)
208
+ .div(BASE_PRECISION)
209
+ .div(PRICE_TO_QUOTE_PRECISION);
210
+
211
+ const netUserCostBasis = perpMarket.amm.quoteAssetAmountLong
212
+ .add(perpMarket.amm.quoteAssetAmountShort)
213
+ .sub(perpMarket.amm.cumulativeSocialLoss);
214
+
215
+ const netUserPnl = netUserPositionValue.add(netUserCostBasis);
216
+
217
+ return netUserPnl;
218
+ }
219
+
220
+ export function calculateNetUserPnlImbalance(
221
+ perpMarket: PerpMarketAccount,
222
+ spotMarket: SpotMarketAccount,
223
+ oraclePriceData: OraclePriceData
224
+ ): BN {
225
+ const netUserPnl = calculateNetUserPnl(perpMarket, oraclePriceData);
226
+
227
+ const pnlPool = getTokenAmount(
228
+ perpMarket.pnlPool.balance,
229
+ spotMarket,
230
+ SpotBalanceType.DEPOSIT
231
+ );
232
+
233
+ const imbalance = netUserPnl.sub(pnlPool);
234
+
235
+ return imbalance;
236
+ }
@@ -1,7 +1,29 @@
1
1
  import { AMM, OracleGuardRails } from '../types';
2
2
  import { OraclePriceData } from '../oracles/types';
3
- import { ONE, ZERO } from '../constants/numericConstants';
4
- import { BN } from '../index';
3
+ import {
4
+ BID_ASK_SPREAD_PRECISION,
5
+ MARGIN_PRECISION,
6
+ PRICE_PRECISION,
7
+ ONE,
8
+ ZERO,
9
+ } from '../constants/numericConstants';
10
+ import { BN, PerpMarketAccount } from '../index';
11
+ import { assert } from '../assert/assert';
12
+
13
+ export function oraclePriceBands(
14
+ market: PerpMarketAccount,
15
+ oraclePriceData: OraclePriceData
16
+ ): [BN, BN] {
17
+ const maxPercentDiff =
18
+ market.marginRatioInitial - market.marginRatioMaintenance;
19
+ const offset = oraclePriceData.price
20
+ .mul(new BN(maxPercentDiff))
21
+ .div(MARGIN_PRECISION);
22
+
23
+ assert(offset.gt(ZERO));
24
+
25
+ return [oraclePriceData.price.sub(offset), oraclePriceData.price.add(offset)];
26
+ }
5
27
 
6
28
  export function isOracleValid(
7
29
  amm: AMM,
@@ -9,22 +31,24 @@ export function isOracleValid(
9
31
  oracleGuardRails: OracleGuardRails,
10
32
  slot: number
11
33
  ): boolean {
12
- const isOraclePriceNonPositive = oraclePriceData.price.lt(ZERO);
34
+ const isOraclePriceNonPositive = oraclePriceData.price.lte(ZERO);
13
35
  const isOraclePriceTooVolatile =
14
36
  oraclePriceData.price
15
- .div(BN.max(ONE, amm.lastOraclePriceTwap))
37
+ .div(BN.max(ONE, amm.historicalOracleData.lastOraclePriceTwap))
16
38
  .gt(oracleGuardRails.validity.tooVolatileRatio) ||
17
- amm.lastOraclePriceTwap
39
+ amm.historicalOracleData.lastOraclePriceTwap
18
40
  .div(BN.max(ONE, oraclePriceData.price))
19
41
  .gt(oracleGuardRails.validity.tooVolatileRatio);
20
42
 
21
- const isConfidenceTooLarge = oraclePriceData.price
22
- .div(BN.max(ONE, oraclePriceData.confidence))
23
- .lt(oracleGuardRails.validity.confidenceIntervalMaxSize);
43
+ const isConfidenceTooLarge = new BN(amm.baseSpread)
44
+ .add(BN.max(ONE, oraclePriceData.confidence))
45
+ .mul(BID_ASK_SPREAD_PRECISION)
46
+ .div(oraclePriceData.price)
47
+ .gt(new BN(amm.maxSpread));
24
48
 
25
49
  const oracleIsStale = oraclePriceData.slot
26
50
  .sub(new BN(slot))
27
- .gt(oracleGuardRails.validity.slotsBeforeStale);
51
+ .gt(oracleGuardRails.validity.slotsBeforeStaleForAmm);
28
52
 
29
53
  return !(
30
54
  !oraclePriceData.hasSufficientNumberOfDataPoints ||
@@ -34,3 +58,33 @@ export function isOracleValid(
34
58
  isConfidenceTooLarge
35
59
  );
36
60
  }
61
+
62
+ export function isOracleTooDivergent(
63
+ amm: AMM,
64
+ oraclePriceData: OraclePriceData,
65
+ oracleGuardRails: OracleGuardRails,
66
+ now: BN
67
+ ): boolean {
68
+ const sinceLastUpdate = now.sub(
69
+ amm.historicalOracleData.lastOraclePriceTwapTs
70
+ );
71
+ const sinceStart = BN.max(ZERO, new BN(60 * 5).sub(sinceLastUpdate));
72
+ const oracleTwap5min = amm.historicalOracleData.lastOraclePriceTwap5min
73
+ .mul(sinceStart)
74
+ .add(oraclePriceData.price)
75
+ .mul(sinceLastUpdate)
76
+ .div(sinceStart.add(sinceLastUpdate));
77
+
78
+ const oracleSpread = oracleTwap5min.sub(oraclePriceData.price);
79
+ const oracleSpreadPct = oracleSpread.mul(PRICE_PRECISION).div(oracleTwap5min);
80
+
81
+ const tooDivergent = oracleSpreadPct
82
+ .abs()
83
+ .gte(
84
+ BID_ASK_SPREAD_PRECISION.mul(
85
+ oracleGuardRails.priceDivergence.markOracleDivergenceNumerator
86
+ ).div(oracleGuardRails.priceDivergence.markOracleDivergenceDenominator)
87
+ );
88
+
89
+ return tooDivergent;
90
+ }