@drift-labs/sdk 0.1.36-master.7 → 0.2.0-master.0

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 +8 -17
  26. package/lib/admin.js +366 -558
  27. package/lib/clearingHouse.d.ts +84 -109
  28. package/lib/clearingHouse.js +778 -899
  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 +16 -0
  42. package/lib/constants/numericConstants.js +22 -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 +112 -0
  61. package/lib/factory/bigNum.js +356 -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 +2213 -2951
  65. package/lib/index.d.ts +12 -4
  66. package/lib/index.js +12 -4
  67. package/lib/math/amm.d.ts +19 -29
  68. package/lib/math/amm.js +129 -179
  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 -6
  98. package/lib/orders.js +10 -9
  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 +105 -109
  107. package/lib/types.js +13 -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 +10 -3
  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 +205 -346
  128. package/src/clearingHouse.ts +918 -961
  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 +33 -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 +507 -0
  146. package/src/factory/oracleClient.ts +7 -4
  147. package/src/idl/clearing_house.json +2213 -2951
  148. package/src/index.ts +12 -4
  149. package/src/math/amm.ts +229 -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 +175 -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 +35 -20
  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 +108 -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
@@ -0,0 +1,112 @@
1
+ import { BankAccount, BankBalanceType, isVariant } from '../types';
2
+ import { BN } from '@project-serum/anchor';
3
+ import {
4
+ BANK_UTILIZATION_PRECISION,
5
+ ONE,
6
+ TEN,
7
+ ZERO,
8
+ BANK_INTEREST_PRECISION,
9
+ ONE_YEAR,
10
+ } from '../constants/numericConstants';
11
+
12
+ export function getBalance(
13
+ tokenAmount: BN,
14
+ bank: BankAccount,
15
+ balanceType: BankBalanceType
16
+ ): BN {
17
+ const precisionIncrease = TEN.pow(new BN(16 - bank.decimals));
18
+
19
+ const cumulativeInterest = isVariant(balanceType, 'deposit')
20
+ ? bank.cumulativeDepositInterest
21
+ : bank.cumulativeBorrowInterest;
22
+
23
+ let balance = tokenAmount.mul(precisionIncrease).div(cumulativeInterest);
24
+
25
+ if (!balance.eq(ZERO) && isVariant(balanceType, 'borrow')) {
26
+ balance = balance.add(ONE);
27
+ }
28
+
29
+ return balance;
30
+ }
31
+
32
+ export function getTokenAmount(
33
+ balanceAmount: BN,
34
+ bank: BankAccount,
35
+ balanceType: BankBalanceType
36
+ ): BN {
37
+ const precisionDecrease = TEN.pow(new BN(16 - bank.decimals));
38
+
39
+ const cumulativeInterest = isVariant(balanceType, 'deposit')
40
+ ? bank.cumulativeDepositInterest
41
+ : bank.cumulativeBorrowInterest;
42
+
43
+ return balanceAmount.mul(cumulativeInterest).div(precisionDecrease);
44
+ }
45
+
46
+ export function calculateInterestAccumulated(
47
+ bank: BankAccount,
48
+ now: BN
49
+ ): { borrowInterest: BN; depositInterest: BN } {
50
+ const token_deposit_amount = getTokenAmount(
51
+ bank.depositBalance,
52
+ bank,
53
+ BankBalanceType.DEPOSIT
54
+ );
55
+ const token_borrow_amount = getTokenAmount(
56
+ bank.borrowBalance,
57
+ bank,
58
+ BankBalanceType.BORROW
59
+ );
60
+
61
+ let utilization: BN;
62
+ if (token_borrow_amount.eq(ZERO) && token_deposit_amount.eq(ZERO)) {
63
+ utilization = ZERO;
64
+ } else if (token_deposit_amount.eq(ZERO)) {
65
+ utilization = BANK_UTILIZATION_PRECISION;
66
+ } else {
67
+ utilization = token_borrow_amount
68
+ .mul(BANK_UTILIZATION_PRECISION)
69
+ .div(token_deposit_amount);
70
+ }
71
+
72
+ let interest_rate: BN;
73
+ if (utilization.gt(bank.optimalUtilization)) {
74
+ const surplusUtilization = utilization.sub(bank.optimalUtilization);
75
+ const borrowRateSlope = bank.maxBorrowRate
76
+ .sub(bank.optimalBorrowRate)
77
+ .mul(BANK_UTILIZATION_PRECISION)
78
+ .div(BANK_UTILIZATION_PRECISION.sub(bank.optimalUtilization));
79
+
80
+ interest_rate = bank.optimalBorrowRate.add(
81
+ surplusUtilization.mul(borrowRateSlope).div(BANK_UTILIZATION_PRECISION)
82
+ );
83
+ } else {
84
+ const borrowRateSlope = bank.optimalBorrowRate
85
+ .mul(BANK_UTILIZATION_PRECISION)
86
+ .div(BANK_UTILIZATION_PRECISION.sub(bank.optimalUtilization));
87
+
88
+ interest_rate = utilization
89
+ .mul(borrowRateSlope)
90
+ .div(BANK_UTILIZATION_PRECISION);
91
+ }
92
+
93
+ const timeSinceLastUpdate = now.sub(bank.lastUpdated);
94
+
95
+ const modifiedBorrowRate = interest_rate.mul(timeSinceLastUpdate);
96
+
97
+ const modifiedDepositRate = modifiedBorrowRate
98
+ .mul(utilization)
99
+ .div(BANK_UTILIZATION_PRECISION);
100
+
101
+ const borrowInterest = bank.cumulativeBorrowInterest
102
+ .mul(modifiedBorrowRate)
103
+ .div(ONE_YEAR)
104
+ .div(BANK_INTEREST_PRECISION)
105
+ .add(ONE);
106
+ const depositInterest = bank.cumulativeDepositInterest
107
+ .mul(modifiedDepositRate)
108
+ .div(ONE_YEAR)
109
+ .div(BANK_INTEREST_PRECISION);
110
+
111
+ return { borrowInterest, depositInterest };
112
+ }
@@ -1,8 +1,5 @@
1
1
  import { BN } from '../';
2
- import {
3
- MARK_PRICE_PRECISION,
4
- PEG_PRECISION,
5
- } from '../constants/numericConstants';
2
+ import { MARK_PRICE_PRECISION } from '../constants/numericConstants';
6
3
 
7
4
  export const convertToNumber = (
8
5
  bigNumber: BN,
@@ -14,10 +11,3 @@ export const convertToNumber = (
14
11
  bigNumber.mod(precision).toNumber() / precision.toNumber()
15
12
  );
16
13
  };
17
-
18
- export const convertBaseAssetAmountToNumber = (baseAssetAmount: BN) => {
19
- return convertToNumber(
20
- baseAssetAmount,
21
- MARK_PRICE_PRECISION.mul(PEG_PRECISION)
22
- );
23
- };
@@ -5,7 +5,7 @@ import {
5
5
  QUOTE_PRECISION,
6
6
  ZERO,
7
7
  } from '../constants/numericConstants';
8
- import { Market } from '../types';
8
+ import { MarketAccount } from '../types';
9
9
  import { calculateMarkPrice } from './market';
10
10
  import { OraclePriceData } from '../oracles/types';
11
11
 
@@ -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: Market,
20
+ market: MarketAccount,
21
21
  oraclePriceData?: OraclePriceData,
22
22
  periodAdjustment: BN = new BN(1)
23
23
  ): Promise<[BN, BN, BN, BN, BN]> {
@@ -48,7 +48,10 @@ export async function calculateAllEstimatedFundingRate(
48
48
  secondsInHour,
49
49
  BN.max(ZERO, secondsInHour.sub(timeSinceLastMarkChange))
50
50
  );
51
- const baseAssetPriceWithMantissa = calculateMarkPrice(market);
51
+ const baseAssetPriceWithMantissa = calculateMarkPrice(
52
+ market,
53
+ oraclePriceData
54
+ );
52
55
 
53
56
  const markTwapWithMantissa = markTwapTimeSinceLastUpdate
54
57
  .mul(lastMarkTwapWithMantissa)
@@ -205,7 +208,7 @@ export async function calculateAllEstimatedFundingRate(
205
208
  * @returns Estimated funding rate. : Precision //TODO-PRECISION
206
209
  */
207
210
  export async function calculateEstimatedFundingRate(
208
- market: Market,
211
+ market: MarketAccount,
209
212
  oraclePriceData?: OraclePriceData,
210
213
  periodAdjustment: BN = new BN(1),
211
214
  estimationMethod?: 'interpolated' | 'lowerbound' | 'capped'
@@ -235,7 +238,7 @@ export async function calculateEstimatedFundingRate(
235
238
  * @returns Estimated funding rate. : Precision //TODO-PRECISION
236
239
  */
237
240
  export async function calculateLongShortFundingRate(
238
- market: Market,
241
+ market: MarketAccount,
239
242
  oraclePriceData?: OraclePriceData,
240
243
  periodAdjustment: BN = new BN(1)
241
244
  ): Promise<[BN, BN]> {
@@ -263,7 +266,7 @@ export async function calculateLongShortFundingRate(
263
266
  * @returns Estimated funding rate. : Precision //TODO-PRECISION
264
267
  */
265
268
  export async function calculateLongShortFundingRateAndLiveTwaps(
266
- market: Market,
269
+ market: MarketAccount,
267
270
  oraclePriceData?: OraclePriceData,
268
271
  periodAdjustment: BN = new BN(1)
269
272
  ): Promise<[BN, BN, BN, BN]> {
@@ -288,14 +291,14 @@ export async function calculateLongShortFundingRateAndLiveTwaps(
288
291
  * @param market
289
292
  * @returns Estimated fee pool size
290
293
  */
291
- export function calculateFundingPool(market: Market): BN {
294
+ export function calculateFundingPool(market: MarketAccount): BN {
292
295
  // todo
293
- const totalFeeLB = market.amm.totalFee.div(new BN(2));
296
+ const totalFeeLB = market.amm.totalExchangeFee.div(new BN(2));
294
297
  const feePool = BN.max(
295
298
  ZERO,
296
299
  market.amm.totalFeeMinusDistributions
297
300
  .sub(totalFeeLB)
298
- .mul(new BN(2))
301
+ .mul(new BN(1))
299
302
  .div(new BN(3))
300
303
  );
301
304
  return feePool;
@@ -1,10 +1,11 @@
1
1
  import { BN } from '@project-serum/anchor';
2
- import { Market, PositionDirection } from '../types';
2
+ import { MarketAccount, PositionDirection } from '../types';
3
3
  import {
4
4
  calculateAmmReservesAfterSwap,
5
5
  calculatePrice,
6
- calculateSpreadReserves,
6
+ calculateUpdatedAMMSpreadReserves,
7
7
  getSwapDirection,
8
+ calculateUpdatedAMM,
8
9
  } from './amm';
9
10
  import { OraclePriceData } from '../oracles/types';
10
11
 
@@ -14,11 +15,15 @@ import { OraclePriceData } from '../oracles/types';
14
15
  * @param market
15
16
  * @return markPrice : Precision MARK_PRICE_PRECISION
16
17
  */
17
- export function calculateMarkPrice(market: Market): BN {
18
+ export function calculateMarkPrice(
19
+ market: MarketAccount,
20
+ oraclePriceData: OraclePriceData
21
+ ): BN {
22
+ const newAmm = calculateUpdatedAMM(market.amm, oraclePriceData);
18
23
  return calculatePrice(
19
- market.amm.baseAssetReserve,
20
- market.amm.quoteAssetReserve,
21
- market.amm.pegMultiplier
24
+ newAmm.baseAssetReserve,
25
+ newAmm.quoteAssetReserve,
26
+ newAmm.pegMultiplier
22
27
  );
23
28
  }
24
29
 
@@ -28,17 +33,18 @@ export function calculateMarkPrice(market: Market): BN {
28
33
  * @param market
29
34
  * @return bidPrice : Precision MARK_PRICE_PRECISION
30
35
  */
31
- export function calculateBidPrice(market: Market): BN {
32
- const { baseAssetReserve, quoteAssetReserve } = calculateSpreadReserves(
33
- market.amm,
34
- PositionDirection.SHORT
35
- );
36
+ export function calculateBidPrice(
37
+ market: MarketAccount,
38
+ oraclePriceData: OraclePriceData
39
+ ): BN {
40
+ const { baseAssetReserve, quoteAssetReserve, newPeg } =
41
+ calculateUpdatedAMMSpreadReserves(
42
+ market.amm,
43
+ PositionDirection.SHORT,
44
+ oraclePriceData
45
+ );
36
46
 
37
- return calculatePrice(
38
- baseAssetReserve,
39
- quoteAssetReserve,
40
- market.amm.pegMultiplier
41
- );
47
+ return calculatePrice(baseAssetReserve, quoteAssetReserve, newPeg);
42
48
  }
43
49
 
44
50
  /**
@@ -47,24 +53,25 @@ export function calculateBidPrice(market: Market): BN {
47
53
  * @param market
48
54
  * @return bidPrice : Precision MARK_PRICE_PRECISION
49
55
  */
50
- export function calculateAskPrice(market: Market): BN {
51
- const { baseAssetReserve, quoteAssetReserve } = calculateSpreadReserves(
52
- market.amm,
53
- PositionDirection.LONG
54
- );
56
+ export function calculateAskPrice(
57
+ market: MarketAccount,
58
+ oraclePriceData: OraclePriceData
59
+ ): BN {
60
+ const { baseAssetReserve, quoteAssetReserve, newPeg } =
61
+ calculateUpdatedAMMSpreadReserves(
62
+ market.amm,
63
+ PositionDirection.LONG,
64
+ oraclePriceData
65
+ );
55
66
 
56
- return calculatePrice(
57
- baseAssetReserve,
58
- quoteAssetReserve,
59
- market.amm.pegMultiplier
60
- );
67
+ return calculatePrice(baseAssetReserve, quoteAssetReserve, newPeg);
61
68
  }
62
69
 
63
70
  export function calculateNewMarketAfterTrade(
64
71
  baseAssetAmount: BN,
65
72
  direction: PositionDirection,
66
- market: Market
67
- ): Market {
73
+ market: MarketAccount
74
+ ): MarketAccount {
68
75
  const [newQuoteAssetReserve, newBaseAssetReserve] =
69
76
  calculateAmmReservesAfterSwap(
70
77
  market.amm,
@@ -83,10 +90,10 @@ export function calculateNewMarketAfterTrade(
83
90
  }
84
91
 
85
92
  export function calculateMarkOracleSpread(
86
- market: Market,
93
+ market: MarketAccount,
87
94
  oraclePriceData: OraclePriceData
88
95
  ): BN {
89
- const markPrice = calculateMarkPrice(market);
96
+ const markPrice = calculateMarkPrice(market, oraclePriceData);
90
97
  return calculateOracleSpread(markPrice, oraclePriceData);
91
98
  }
92
99
 
@@ -1,6 +1,9 @@
1
1
  import { ClearingHouseUser } from '../clearingHouseUser';
2
2
  import { isVariant, Order } from '../types';
3
3
  import { ZERO, TWO } from '../constants/numericConstants';
4
+ import { BN } from '@project-serum/anchor';
5
+ import { OraclePriceData } from '../oracles/types';
6
+ import { getAuctionPrice } from './auction';
4
7
 
5
8
  export function isOrderRiskIncreasing(
6
9
  user: ClearingHouseUser,
@@ -106,3 +109,38 @@ export function isOrderReduceOnly(
106
109
 
107
110
  return true;
108
111
  }
112
+
113
+ export function standardizeBaseAssetAmount(
114
+ baseAssetAmount: BN,
115
+ stepSize: BN
116
+ ): BN {
117
+ const remainder = baseAssetAmount.mod(stepSize);
118
+ return baseAssetAmount.sub(remainder);
119
+ }
120
+
121
+ export function getLimitPrice(
122
+ order: Order,
123
+ oraclePriceData: OraclePriceData,
124
+ slot: number
125
+ ): BN {
126
+ let limitPrice;
127
+ if (!order.oraclePriceOffset.eq(ZERO)) {
128
+ const floatingPrice = oraclePriceData.price.add(order.oraclePriceOffset);
129
+ if (order.postOnly) {
130
+ limitPrice = isVariant(order.direction, 'long')
131
+ ? BN.min(order.price, floatingPrice)
132
+ : BN.max(order.price, floatingPrice);
133
+ } else {
134
+ limitPrice = floatingPrice;
135
+ }
136
+ } else if (
137
+ isVariant(order.orderType, 'market') ||
138
+ isVariant(order.orderType, 'triggerMarket')
139
+ ) {
140
+ limitPrice = getAuctionPrice(order, slot);
141
+ } else {
142
+ limitPrice = order.price;
143
+ }
144
+
145
+ return limitPrice;
146
+ }
@@ -9,29 +9,54 @@ import {
9
9
  PRICE_TO_QUOTE_PRECISION,
10
10
  ZERO,
11
11
  } from '../constants/numericConstants';
12
- import { Market, PositionDirection, UserPosition } from '../types';
13
- import { calculateAmmReservesAfterSwap, getSwapDirection } from './amm';
14
- import { SETTLEMENT_RATIO_PRECISION, SETTLEMENT_RATIOS } from '../settlement';
12
+ import { OraclePriceData } from '../oracles/types';
13
+ import { MarketAccount, PositionDirection, UserPosition } from '../types';
14
+ import {
15
+ calculateUpdatedAMM,
16
+ calculateUpdatedAMMSpreadReserves,
17
+ calculateAmmReservesAfterSwap,
18
+ getSwapDirection,
19
+ } from './amm';
15
20
 
16
21
  /**
17
22
  * calculateBaseAssetValue
18
23
  * = market value of closing entire position
19
24
  * @param market
20
25
  * @param userPosition
26
+ * @param oraclePriceData
21
27
  * @returns Base Asset Value. : Precision QUOTE_PRECISION
22
28
  */
23
29
  export function calculateBaseAssetValue(
24
- market: Market,
25
- userPosition: UserPosition
30
+ market: MarketAccount,
31
+ userPosition: UserPosition,
32
+ oraclePriceData: OraclePriceData
26
33
  ): BN {
27
34
  if (userPosition.baseAssetAmount.eq(ZERO)) {
28
35
  return ZERO;
29
36
  }
30
37
 
31
38
  const directionToClose = findDirectionToClose(userPosition);
39
+ let prepegAmm: Parameters<typeof calculateAmmReservesAfterSwap>[0];
40
+
41
+ if (market.amm.baseSpread > 0) {
42
+ const { baseAssetReserve, quoteAssetReserve, sqrtK, newPeg } =
43
+ calculateUpdatedAMMSpreadReserves(
44
+ market.amm,
45
+ directionToClose,
46
+ oraclePriceData
47
+ );
48
+ prepegAmm = {
49
+ baseAssetReserve,
50
+ quoteAssetReserve,
51
+ sqrtK: sqrtK,
52
+ pegMultiplier: newPeg,
53
+ };
54
+ } else {
55
+ prepegAmm = calculateUpdatedAMM(market.amm, oraclePriceData);
56
+ }
32
57
 
33
58
  const [newQuoteAssetReserve, _] = calculateAmmReservesAfterSwap(
34
- market.amm,
59
+ prepegAmm,
35
60
  'base',
36
61
  userPosition.baseAssetAmount.abs(),
37
62
  getSwapDirection('base', directionToClose)
@@ -39,15 +64,15 @@ export function calculateBaseAssetValue(
39
64
 
40
65
  switch (directionToClose) {
41
66
  case PositionDirection.SHORT:
42
- return market.amm.quoteAssetReserve
67
+ return prepegAmm.quoteAssetReserve
43
68
  .sub(newQuoteAssetReserve)
44
- .mul(market.amm.pegMultiplier)
69
+ .mul(prepegAmm.pegMultiplier)
45
70
  .div(AMM_TIMES_PEG_TO_QUOTE_PRECISION_RATIO);
46
71
 
47
72
  case PositionDirection.LONG:
48
73
  return newQuoteAssetReserve
49
- .sub(market.amm.quoteAssetReserve)
50
- .mul(market.amm.pegMultiplier)
74
+ .sub(prepegAmm.quoteAssetReserve)
75
+ .mul(prepegAmm.pegMultiplier)
51
76
  .div(AMM_TIMES_PEG_TO_QUOTE_PRECISION_RATIO)
52
77
  .add(ONE);
53
78
  }
@@ -62,15 +87,20 @@ export function calculateBaseAssetValue(
62
87
  * @returns BaseAssetAmount : Precision QUOTE_PRECISION
63
88
  */
64
89
  export function calculatePositionPNL(
65
- market: Market,
90
+ market: MarketAccount,
66
91
  marketPosition: UserPosition,
67
- withFunding = false
92
+ withFunding = false,
93
+ oraclePriceData: OraclePriceData
68
94
  ): BN {
69
95
  if (marketPosition.baseAssetAmount.eq(ZERO)) {
70
96
  return ZERO;
71
97
  }
72
98
 
73
- const baseAssetValue = calculateBaseAssetValue(market, marketPosition);
99
+ const baseAssetValue = calculateBaseAssetValue(
100
+ market,
101
+ marketPosition,
102
+ oraclePriceData
103
+ );
74
104
 
75
105
  let pnl;
76
106
  if (marketPosition.baseAssetAmount.gt(ZERO)) {
@@ -91,27 +121,6 @@ export function calculatePositionPNL(
91
121
  return pnl;
92
122
  }
93
123
 
94
- export function calculateSettledPositionPNL(
95
- market: Market,
96
- marketPosition: UserPosition
97
- ): BN {
98
- let pnl = calculatePositionPNL(market, marketPosition);
99
-
100
- if (pnl.gt(ZERO)) {
101
- try {
102
- pnl = pnl
103
- .mul(new BN(SETTLEMENT_RATIOS[marketPosition.marketIndex.toNumber()]))
104
- .div(SETTLEMENT_RATIO_PRECISION);
105
- } catch (e) {
106
- console.log(pnl.toString());
107
- console.log(marketPosition.marketIndex.toNumber());
108
- throw e;
109
- }
110
- }
111
-
112
- return pnl;
113
- }
114
-
115
124
  /**
116
125
  *
117
126
  * @param market
@@ -119,7 +128,7 @@ export function calculateSettledPositionPNL(
119
128
  * @returns // TODO-PRECISION
120
129
  */
121
130
  export function calculatePositionFundingPNL(
122
- market: Market,
131
+ market: MarketAccount,
123
132
  marketPosition: UserPosition
124
133
  ): BN {
125
134
  if (marketPosition.baseAssetAmount.eq(ZERO)) {
@@ -143,6 +152,10 @@ export function calculatePositionFundingPNL(
143
152
  return perPositionFundingRate;
144
153
  }
145
154
 
155
+ export function positionIsAvailable(position: UserPosition): boolean {
156
+ return position.baseAssetAmount.eq(ZERO) && position.openOrders.eq(ZERO);
157
+ }
158
+
146
159
  /**
147
160
  *
148
161
  * @param userPosition
@@ -0,0 +1,175 @@
1
+ import { BN } from '@project-serum/anchor';
2
+ import { assert } from '../assert/assert';
3
+ import {
4
+ MARK_PRICE_PRECISION,
5
+ AMM_RESERVE_PRECISION,
6
+ PEG_PRECISION,
7
+ AMM_TO_QUOTE_PRECISION_RATIO,
8
+ QUOTE_PRECISION,
9
+ ZERO,
10
+ } from '../constants/numericConstants';
11
+ import { AMM } from '../types';
12
+ /**
13
+ * Helper function calculating adjust k cost
14
+ * @param amm
15
+ * @param numerator
16
+ * @param denomenator
17
+ * @returns cost : Precision QUOTE_ASSET_PRECISION
18
+ */
19
+ export function calculateAdjustKCost(
20
+ amm: AMM,
21
+ numerator: BN,
22
+ denomenator: BN
23
+ ): BN {
24
+ // const k = market.amm.sqrtK.mul(market.amm.sqrtK);
25
+ const x = amm.baseAssetReserve;
26
+ const y = amm.quoteAssetReserve;
27
+
28
+ const d = amm.netBaseAssetAmount;
29
+ const Q = amm.pegMultiplier;
30
+
31
+ const quoteScale = y.mul(d).mul(Q); //.div(AMM_RESERVE_PRECISION);
32
+
33
+ const p = numerator.mul(MARK_PRICE_PRECISION).div(denomenator);
34
+
35
+ const cost = quoteScale
36
+ .div(x.add(d))
37
+ .sub(
38
+ quoteScale
39
+ .mul(p)
40
+ .div(MARK_PRICE_PRECISION)
41
+ .div(x.mul(p).div(MARK_PRICE_PRECISION).add(d))
42
+ )
43
+ .div(AMM_TO_QUOTE_PRECISION_RATIO)
44
+ .div(PEG_PRECISION);
45
+
46
+ return cost.mul(new BN(-1));
47
+ }
48
+
49
+ /**
50
+ * Helper function calculating adjust pegMultiplier (repeg) cost
51
+ *
52
+ * @param amm
53
+ * @param newPeg
54
+ * @returns cost : Precision QUOTE_ASSET_PRECISION
55
+ */
56
+ export function calculateRepegCost(amm: AMM, newPeg: BN): BN {
57
+ const dqar = amm.quoteAssetReserve.sub(amm.terminalQuoteAssetReserve);
58
+ const cost = dqar
59
+ .mul(newPeg.sub(amm.pegMultiplier))
60
+ .div(AMM_TO_QUOTE_PRECISION_RATIO)
61
+ .div(PEG_PRECISION);
62
+ return cost;
63
+ }
64
+
65
+ export function calculateBudgetedKBN(
66
+ x: BN,
67
+ y: BN,
68
+ budget: BN,
69
+ Q: BN,
70
+ d: BN
71
+ ): [BN, BN] {
72
+ assert(Q.gt(new BN(0)));
73
+ const C = budget.mul(new BN(-1));
74
+
75
+ let dSign = new BN(1);
76
+ if (d.lt(new BN(0))) {
77
+ dSign = new BN(-1);
78
+ }
79
+ const pegged_y_d_d = y
80
+ .mul(d)
81
+ .mul(d)
82
+ .mul(Q)
83
+ .div(AMM_RESERVE_PRECISION)
84
+ .div(AMM_RESERVE_PRECISION)
85
+ .div(PEG_PRECISION);
86
+
87
+ const numer1 = pegged_y_d_d;
88
+ const numer2 = C.mul(d)
89
+ .div(QUOTE_PRECISION)
90
+ .mul(x.add(d))
91
+ .div(AMM_RESERVE_PRECISION)
92
+ .mul(dSign);
93
+
94
+ const denom1 = C.mul(x)
95
+ .mul(x.add(d))
96
+ .div(AMM_RESERVE_PRECISION)
97
+ .div(QUOTE_PRECISION);
98
+ const denom2 = pegged_y_d_d;
99
+
100
+ const numerator = numer1.sub(numer2).div(AMM_TO_QUOTE_PRECISION_RATIO);
101
+ const denominator = denom1.add(denom2).div(AMM_TO_QUOTE_PRECISION_RATIO);
102
+
103
+ return [numerator, denominator];
104
+ }
105
+
106
+ export function calculateBudgetedK(amm: AMM, cost: BN): [BN, BN] {
107
+ // wolframalpha.com
108
+ // (1/(x+d) - p/(x*p+d))*y*d*Q = C solve for p
109
+ // p = (d(y*d*Q - C(x+d))) / (C*x(x+d) + y*d*d*Q)
110
+
111
+ // numer
112
+ // = y*d*d*Q - Cxd - Cdd
113
+ // = y/x*Q*d*d - Cd - Cd/x
114
+ // = mark - C/d - C/(x)
115
+ // = mark/C - 1/d - 1/x
116
+
117
+ // denom
118
+ // = C*x*x + C*x*d + y*d*d*Q
119
+ // = x/d**2 + 1 / d + mark/C
120
+
121
+ // todo: assumes k = x * y
122
+ // otherwise use: (y(1-p) + (kp^2/(x*p+d)) - k/(x+d)) * Q = C solve for p
123
+
124
+ const x = amm.baseAssetReserve;
125
+ const y = amm.quoteAssetReserve;
126
+
127
+ const d = amm.netBaseAssetAmount;
128
+ const Q = amm.pegMultiplier;
129
+
130
+ const [numerator, denominator] = calculateBudgetedKBN(x, y, cost, Q, d);
131
+
132
+ return [numerator, denominator];
133
+ }
134
+
135
+ export function calculateBudgetedPeg(amm: AMM, cost: BN, targetPrice: BN): BN {
136
+ // wolframalpha.com
137
+ // (1/(x+d) - p/(x*p+d))*y*d*Q = C solve for p
138
+ // p = (d(y*d*Q - C(x+d))) / (C*x(x+d) + y*y*d*Q)
139
+
140
+ // todo: assumes k = x * y
141
+ // otherwise use: (y(1-p) + (kp^2/(x*p+d)) - k/(x+d)) * Q = C solve for p
142
+ const targetPeg = targetPrice
143
+ .mul(amm.baseAssetReserve)
144
+ .div(amm.quoteAssetReserve)
145
+ .div(MARK_PRICE_PRECISION.div(PEG_PRECISION));
146
+
147
+ const k = amm.sqrtK.mul(amm.sqrtK);
148
+ const x = amm.baseAssetReserve;
149
+ const y = amm.quoteAssetReserve;
150
+
151
+ const d = amm.netBaseAssetAmount;
152
+ const Q = amm.pegMultiplier;
153
+
154
+ const C = cost.mul(new BN(-1));
155
+
156
+ const deltaQuoteAssetReserves = y.sub(k.div(x.add(d)));
157
+ const pegChangeDirection = targetPeg.sub(Q);
158
+
159
+ const useTargetPeg =
160
+ (deltaQuoteAssetReserves.lt(ZERO) && pegChangeDirection.gt(ZERO)) ||
161
+ (deltaQuoteAssetReserves.gt(ZERO) && pegChangeDirection.lt(ZERO));
162
+
163
+ if (deltaQuoteAssetReserves.eq(ZERO) || useTargetPeg) {
164
+ return targetPeg;
165
+ }
166
+
167
+ const deltaPegMultiplier = C.mul(MARK_PRICE_PRECISION).div(
168
+ deltaQuoteAssetReserves.div(AMM_TO_QUOTE_PRECISION_RATIO)
169
+ );
170
+ const newPeg = Q.sub(
171
+ deltaPegMultiplier.mul(PEG_PRECISION).div(MARK_PRICE_PRECISION)
172
+ );
173
+
174
+ return newPeg;
175
+ }