@drift-labs/sdk 0.1.36-master.5 → 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 +7 -6
  2. package/lib/accounts/bulkAccountLoader.js +83 -93
  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 -12
  26. package/lib/admin.js +366 -490
  27. package/lib/clearingHouse.d.ts +84 -103
  28. package/lib/clearingHouse.js +779 -810
  29. package/lib/clearingHouseConfig.d.ts +34 -0
  30. package/lib/clearingHouseConfig.js +2 -0
  31. package/lib/clearingHouseUser.d.ts +19 -18
  32. package/lib/clearingHouseUser.js +157 -115
  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 +1739 -2287
  65. package/lib/index.d.ts +13 -4
  66. package/lib/index.js +13 -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/oracles.d.ts +3 -0
  80. package/lib/math/oracles.js +26 -0
  81. package/lib/math/orders.d.ts +5 -0
  82. package/lib/math/orders.js +31 -1
  83. package/lib/math/position.d.ts +7 -4
  84. package/lib/math/position.js +27 -9
  85. package/lib/math/repeg.d.ts +22 -0
  86. package/lib/math/repeg.js +128 -0
  87. package/lib/math/trade.d.ts +13 -8
  88. package/lib/math/trade.js +85 -22
  89. package/lib/mockUSDCFaucet.js +87 -116
  90. package/lib/oracles/oracleClientCache.d.ts +8 -0
  91. package/lib/oracles/oracleClientCache.js +19 -0
  92. package/lib/oracles/pythClient.d.ts +3 -5
  93. package/lib/oracles/pythClient.js +12 -30
  94. package/lib/oracles/quoteAssetOracleClient.d.ts +9 -0
  95. package/lib/oracles/quoteAssetOracleClient.js +21 -0
  96. package/lib/oracles/switchboardClient.d.ts +3 -5
  97. package/lib/oracles/switchboardClient.js +29 -47
  98. package/lib/oracles/types.d.ts +7 -1
  99. package/lib/orders.d.ts +6 -6
  100. package/lib/orders.js +10 -9
  101. package/lib/slot/SlotSubscriber.d.ts +12 -0
  102. package/lib/slot/SlotSubscriber.js +23 -0
  103. package/lib/tx/retryTxSender.d.ts +2 -2
  104. package/lib/tx/retryTxSender.js +108 -123
  105. package/lib/tx/types.d.ts +5 -1
  106. package/lib/tx/utils.d.ts +1 -1
  107. package/lib/tx/utils.js +11 -2
  108. package/lib/types.d.ts +105 -98
  109. package/lib/types.js +13 -1
  110. package/lib/userName.d.ts +4 -0
  111. package/lib/userName.js +20 -0
  112. package/lib/util/computeUnits.js +10 -21
  113. package/lib/util/tps.js +11 -22
  114. package/lib/wallet.js +7 -20
  115. package/package.json +10 -3
  116. package/src/accounts/bulkAccountLoader.ts +26 -15
  117. package/src/accounts/bulkUserSubscription.ts +1 -45
  118. package/src/accounts/fetch.ts +33 -0
  119. package/src/accounts/pollingClearingHouseAccountSubscriber.ts +249 -214
  120. package/src/accounts/pollingOracleSubscriber.ts +16 -8
  121. package/src/accounts/pollingTokenAccountSubscriber.ts +11 -8
  122. package/src/accounts/pollingUserAccountSubscriber.ts +21 -86
  123. package/src/accounts/types.ts +41 -70
  124. package/src/accounts/webSocketAccountSubscriber.ts +33 -16
  125. package/src/accounts/webSocketClearingHouseAccountSubscriber.ts +190 -240
  126. package/src/accounts/webSocketUserAccountSubscriber.ts +11 -71
  127. package/src/addresses/marketAddresses.ts +18 -0
  128. package/src/addresses/pda.ts +118 -0
  129. package/src/admin.ts +209 -267
  130. package/src/clearingHouse.ts +921 -829
  131. package/src/clearingHouseConfig.ts +37 -0
  132. package/src/clearingHouseUser.ts +280 -127
  133. package/src/clearingHouseUserConfig.ts +18 -0
  134. package/src/config.ts +54 -1
  135. package/src/constants/banks.ts +43 -0
  136. package/src/constants/markets.ts +16 -207
  137. package/src/constants/numericConstants.ts +33 -5
  138. package/src/events/eventList.ts +94 -0
  139. package/src/events/eventSubscriber.ts +194 -0
  140. package/src/events/fetchLogs.ts +80 -0
  141. package/src/events/pollingLogProvider.ts +79 -0
  142. package/src/events/sort.ts +65 -0
  143. package/src/events/txEventCache.ts +74 -0
  144. package/src/events/types.ts +98 -0
  145. package/src/events/webSocketLogProvider.ts +38 -0
  146. package/src/examples/makeTradeExample.ts +20 -11
  147. package/src/factory/bigNum.ts +507 -0
  148. package/src/factory/oracleClient.ts +7 -4
  149. package/src/idl/clearing_house.json +1739 -2287
  150. package/src/index.ts +13 -4
  151. package/src/math/amm.ts +229 -245
  152. package/src/math/auction.ts +39 -0
  153. package/src/math/bankBalance.ts +112 -0
  154. package/src/math/conversion.ts +1 -11
  155. package/src/math/funding.ts +12 -9
  156. package/src/math/market.ts +37 -30
  157. package/src/math/oracles.ts +36 -0
  158. package/src/math/orders.ts +38 -0
  159. package/src/math/position.ts +48 -13
  160. package/src/math/repeg.ts +175 -0
  161. package/src/math/trade.ts +114 -36
  162. package/src/math/utils.js +27 -0
  163. package/src/math/utils.js.map +1 -0
  164. package/src/oracles/oracleClientCache.ts +20 -0
  165. package/src/oracles/pythClient.ts +5 -11
  166. package/src/oracles/quoteAssetOracleClient.ts +25 -0
  167. package/src/oracles/switchboardClient.ts +16 -24
  168. package/src/oracles/types.ts +8 -1
  169. package/src/orders.ts +35 -20
  170. package/src/slot/SlotSubscriber.ts +32 -0
  171. package/src/tx/retryTxSender.ts +6 -4
  172. package/src/tx/types.ts +6 -1
  173. package/src/tx/utils.ts +22 -3
  174. package/src/types.ts +108 -110
  175. package/src/userName.ts +20 -0
  176. package/src/util/computeUnits.js +17 -0
  177. package/src/util/computeUnits.js.map +1 -0
  178. package/tests/bn/test.ts +255 -0
  179. package/tsconfig.json +12 -12
  180. package/lib/addresses.d.ts +0 -9
  181. package/lib/addresses.js +0 -87
  182. package/lib/constants/accounts.d.ts +0 -15
  183. package/lib/constants/accounts.js +0 -18
  184. package/lib/factory/clearingHouse.d.ts +0 -35
  185. package/lib/factory/clearingHouse.js +0 -81
  186. package/lib/factory/clearingHouseUser.d.ts +0 -19
  187. package/lib/factory/clearingHouseUser.js +0 -34
  188. package/lib/math/insuranceFund.d.ts +0 -15
  189. package/lib/math/insuranceFund.js +0 -33
  190. package/lib/tx/defaultTxSender.d.ts +0 -8
  191. package/lib/tx/defaultTxSender.js +0 -12
  192. package/src/addresses.ts +0 -71
  193. package/src/constants/accounts.ts +0 -26
  194. package/src/factory/clearingHouse.ts +0 -173
  195. package/src/factory/clearingHouseUser.ts +0 -73
  196. package/src/math/insuranceFund.ts +0 -29
  197. package/src/tx/defaultTxSender.ts +0 -24
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isOracleValid = void 0;
4
+ const numericConstants_1 = require("../constants/numericConstants");
5
+ const index_1 = require("../index");
6
+ function isOracleValid(amm, oraclePriceData, oracleGuardRails, slot) {
7
+ const isOraclePriceNonPositive = oraclePriceData.price.lt(numericConstants_1.ZERO);
8
+ const isOraclePriceTooVolatile = oraclePriceData.price
9
+ .div(index_1.BN.max(numericConstants_1.ONE, amm.lastOraclePriceTwap))
10
+ .gt(oracleGuardRails.validity.tooVolatileRatio) ||
11
+ amm.lastOraclePriceTwap
12
+ .div(index_1.BN.max(numericConstants_1.ONE, oraclePriceData.price))
13
+ .gt(oracleGuardRails.validity.tooVolatileRatio);
14
+ const isConfidenceTooLarge = oraclePriceData.price
15
+ .div(index_1.BN.max(numericConstants_1.ONE, oraclePriceData.confidence))
16
+ .lt(oracleGuardRails.validity.confidenceIntervalMaxSize);
17
+ const oracleIsStale = oraclePriceData.slot
18
+ .sub(new index_1.BN(slot))
19
+ .gt(oracleGuardRails.validity.slotsBeforeStale);
20
+ return !(!oraclePriceData.hasSufficientNumberOfDataPoints ||
21
+ oracleIsStale ||
22
+ isOraclePriceNonPositive ||
23
+ isOraclePriceTooVolatile ||
24
+ isConfidenceTooLarge);
25
+ }
26
+ exports.isOracleValid = isOracleValid;
@@ -1,5 +1,10 @@
1
+ /// <reference types="bn.js" />
1
2
  import { ClearingHouseUser } from '../clearingHouseUser';
2
3
  import { Order } from '../types';
4
+ import { BN } from '@project-serum/anchor';
5
+ import { OraclePriceData } from '../oracles/types';
3
6
  export declare function isOrderRiskIncreasing(user: ClearingHouseUser, order: Order): boolean;
4
7
  export declare function isOrderRiskIncreasingInSameDirection(user: ClearingHouseUser, order: Order): boolean;
5
8
  export declare function isOrderReduceOnly(user: ClearingHouseUser, order: Order): boolean;
9
+ export declare function standardizeBaseAssetAmount(baseAssetAmount: BN, stepSize: BN): BN;
10
+ export declare function getLimitPrice(order: Order, oraclePriceData: OraclePriceData, slot: number): BN;
@@ -1,8 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isOrderReduceOnly = exports.isOrderRiskIncreasingInSameDirection = exports.isOrderRiskIncreasing = void 0;
3
+ exports.getLimitPrice = exports.standardizeBaseAssetAmount = exports.isOrderReduceOnly = exports.isOrderRiskIncreasingInSameDirection = exports.isOrderRiskIncreasing = void 0;
4
4
  const types_1 = require("../types");
5
5
  const numericConstants_1 = require("../constants/numericConstants");
6
+ const anchor_1 = require("@project-serum/anchor");
7
+ const auction_1 = require("./auction");
6
8
  function isOrderRiskIncreasing(user, order) {
7
9
  if ((0, types_1.isVariant)(order.status, 'init')) {
8
10
  return false;
@@ -71,3 +73,31 @@ function isOrderReduceOnly(user, order) {
71
73
  return true;
72
74
  }
73
75
  exports.isOrderReduceOnly = isOrderReduceOnly;
76
+ function standardizeBaseAssetAmount(baseAssetAmount, stepSize) {
77
+ const remainder = baseAssetAmount.mod(stepSize);
78
+ return baseAssetAmount.sub(remainder);
79
+ }
80
+ exports.standardizeBaseAssetAmount = standardizeBaseAssetAmount;
81
+ function getLimitPrice(order, oraclePriceData, slot) {
82
+ let limitPrice;
83
+ if (!order.oraclePriceOffset.eq(numericConstants_1.ZERO)) {
84
+ const floatingPrice = oraclePriceData.price.add(order.oraclePriceOffset);
85
+ if (order.postOnly) {
86
+ limitPrice = (0, types_1.isVariant)(order.direction, 'long')
87
+ ? anchor_1.BN.min(order.price, floatingPrice)
88
+ : anchor_1.BN.max(order.price, floatingPrice);
89
+ }
90
+ else {
91
+ limitPrice = floatingPrice;
92
+ }
93
+ }
94
+ else if ((0, types_1.isVariant)(order.orderType, 'market') ||
95
+ (0, types_1.isVariant)(order.orderType, 'triggerMarket')) {
96
+ limitPrice = (0, auction_1.getAuctionPrice)(order, slot);
97
+ }
98
+ else {
99
+ limitPrice = order.price;
100
+ }
101
+ return limitPrice;
102
+ }
103
+ exports.getLimitPrice = getLimitPrice;
@@ -1,14 +1,16 @@
1
1
  /// <reference types="bn.js" />
2
2
  import { BN } from '../';
3
- import { Market, PositionDirection, UserPosition } from '../types';
3
+ import { OraclePriceData } from '../oracles/types';
4
+ import { MarketAccount, PositionDirection, UserPosition } from '../types';
4
5
  /**
5
6
  * calculateBaseAssetValue
6
7
  * = market value of closing entire position
7
8
  * @param market
8
9
  * @param userPosition
10
+ * @param oraclePriceData
9
11
  * @returns Base Asset Value. : Precision QUOTE_PRECISION
10
12
  */
11
- export declare function calculateBaseAssetValue(market: Market, userPosition: UserPosition): BN;
13
+ export declare function calculateBaseAssetValue(market: MarketAccount, userPosition: UserPosition, oraclePriceData: OraclePriceData): BN;
12
14
  /**
13
15
  * calculatePositionPNL
14
16
  * = BaseAssetAmount * (Avg Exit Price - Avg Entry Price)
@@ -17,14 +19,15 @@ export declare function calculateBaseAssetValue(market: Market, userPosition: Us
17
19
  * @param withFunding (adds unrealized funding payment pnl to result)
18
20
  * @returns BaseAssetAmount : Precision QUOTE_PRECISION
19
21
  */
20
- export declare function calculatePositionPNL(market: Market, marketPosition: UserPosition, withFunding?: boolean): BN;
22
+ export declare function calculatePositionPNL(market: MarketAccount, marketPosition: UserPosition, withFunding: boolean, oraclePriceData: OraclePriceData): BN;
21
23
  /**
22
24
  *
23
25
  * @param market
24
26
  * @param marketPosition
25
27
  * @returns // TODO-PRECISION
26
28
  */
27
- export declare function calculatePositionFundingPNL(market: Market, marketPosition: UserPosition): BN;
29
+ export declare function calculatePositionFundingPNL(market: MarketAccount, marketPosition: UserPosition): BN;
30
+ export declare function positionIsAvailable(position: UserPosition): boolean;
28
31
  /**
29
32
  *
30
33
  * @param userPosition
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isEmptyPosition = exports.positionCurrentDirection = exports.findDirectionToClose = exports.calculateEntryPrice = exports.calculatePositionFundingPNL = exports.calculatePositionPNL = exports.calculateBaseAssetValue = void 0;
3
+ exports.isEmptyPosition = exports.positionCurrentDirection = exports.findDirectionToClose = exports.calculateEntryPrice = exports.positionIsAvailable = exports.calculatePositionFundingPNL = exports.calculatePositionPNL = exports.calculateBaseAssetValue = void 0;
4
4
  const __1 = require("../");
5
5
  const numericConstants_1 = require("../constants/numericConstants");
6
6
  const types_1 = require("../types");
@@ -10,24 +10,38 @@ const amm_1 = require("./amm");
10
10
  * = market value of closing entire position
11
11
  * @param market
12
12
  * @param userPosition
13
+ * @param oraclePriceData
13
14
  * @returns Base Asset Value. : Precision QUOTE_PRECISION
14
15
  */
15
- function calculateBaseAssetValue(market, userPosition) {
16
+ function calculateBaseAssetValue(market, userPosition, oraclePriceData) {
16
17
  if (userPosition.baseAssetAmount.eq(numericConstants_1.ZERO)) {
17
18
  return numericConstants_1.ZERO;
18
19
  }
19
20
  const directionToClose = findDirectionToClose(userPosition);
20
- const [newQuoteAssetReserve, _] = (0, amm_1.calculateAmmReservesAfterSwap)(market.amm, 'base', userPosition.baseAssetAmount.abs(), (0, amm_1.getSwapDirection)('base', directionToClose));
21
+ let prepegAmm;
22
+ if (market.amm.baseSpread > 0) {
23
+ const { baseAssetReserve, quoteAssetReserve, sqrtK, newPeg } = (0, amm_1.calculateUpdatedAMMSpreadReserves)(market.amm, directionToClose, oraclePriceData);
24
+ prepegAmm = {
25
+ baseAssetReserve,
26
+ quoteAssetReserve,
27
+ sqrtK: sqrtK,
28
+ pegMultiplier: newPeg,
29
+ };
30
+ }
31
+ else {
32
+ prepegAmm = (0, amm_1.calculateUpdatedAMM)(market.amm, oraclePriceData);
33
+ }
34
+ const [newQuoteAssetReserve, _] = (0, amm_1.calculateAmmReservesAfterSwap)(prepegAmm, 'base', userPosition.baseAssetAmount.abs(), (0, amm_1.getSwapDirection)('base', directionToClose));
21
35
  switch (directionToClose) {
22
36
  case types_1.PositionDirection.SHORT:
23
- return market.amm.quoteAssetReserve
37
+ return prepegAmm.quoteAssetReserve
24
38
  .sub(newQuoteAssetReserve)
25
- .mul(market.amm.pegMultiplier)
39
+ .mul(prepegAmm.pegMultiplier)
26
40
  .div(numericConstants_1.AMM_TIMES_PEG_TO_QUOTE_PRECISION_RATIO);
27
41
  case types_1.PositionDirection.LONG:
28
42
  return newQuoteAssetReserve
29
- .sub(market.amm.quoteAssetReserve)
30
- .mul(market.amm.pegMultiplier)
43
+ .sub(prepegAmm.quoteAssetReserve)
44
+ .mul(prepegAmm.pegMultiplier)
31
45
  .div(numericConstants_1.AMM_TIMES_PEG_TO_QUOTE_PRECISION_RATIO)
32
46
  .add(numericConstants_1.ONE);
33
47
  }
@@ -41,11 +55,11 @@ exports.calculateBaseAssetValue = calculateBaseAssetValue;
41
55
  * @param withFunding (adds unrealized funding payment pnl to result)
42
56
  * @returns BaseAssetAmount : Precision QUOTE_PRECISION
43
57
  */
44
- function calculatePositionPNL(market, marketPosition, withFunding = false) {
58
+ function calculatePositionPNL(market, marketPosition, withFunding = false, oraclePriceData) {
45
59
  if (marketPosition.baseAssetAmount.eq(numericConstants_1.ZERO)) {
46
60
  return numericConstants_1.ZERO;
47
61
  }
48
- const baseAssetValue = calculateBaseAssetValue(market, marketPosition);
62
+ const baseAssetValue = calculateBaseAssetValue(market, marketPosition, oraclePriceData);
49
63
  let pnl;
50
64
  if (marketPosition.baseAssetAmount.gt(numericConstants_1.ZERO)) {
51
65
  pnl = baseAssetValue.sub(marketPosition.quoteAssetAmount);
@@ -86,6 +100,10 @@ function calculatePositionFundingPNL(market, marketPosition) {
86
100
  return perPositionFundingRate;
87
101
  }
88
102
  exports.calculatePositionFundingPNL = calculatePositionFundingPNL;
103
+ function positionIsAvailable(position) {
104
+ return position.baseAssetAmount.eq(numericConstants_1.ZERO) && position.openOrders.eq(numericConstants_1.ZERO);
105
+ }
106
+ exports.positionIsAvailable = positionIsAvailable;
89
107
  /**
90
108
  *
91
109
  * @param userPosition
@@ -0,0 +1,22 @@
1
+ /// <reference types="bn.js" />
2
+ import { BN } from '@project-serum/anchor';
3
+ import { AMM } from '../types';
4
+ /**
5
+ * Helper function calculating adjust k cost
6
+ * @param amm
7
+ * @param numerator
8
+ * @param denomenator
9
+ * @returns cost : Precision QUOTE_ASSET_PRECISION
10
+ */
11
+ export declare function calculateAdjustKCost(amm: AMM, numerator: BN, denomenator: BN): BN;
12
+ /**
13
+ * Helper function calculating adjust pegMultiplier (repeg) cost
14
+ *
15
+ * @param amm
16
+ * @param newPeg
17
+ * @returns cost : Precision QUOTE_ASSET_PRECISION
18
+ */
19
+ export declare function calculateRepegCost(amm: AMM, newPeg: BN): BN;
20
+ export declare function calculateBudgetedKBN(x: BN, y: BN, budget: BN, Q: BN, d: BN): [BN, BN];
21
+ export declare function calculateBudgetedK(amm: AMM, cost: BN): [BN, BN];
22
+ export declare function calculateBudgetedPeg(amm: AMM, cost: BN, targetPrice: BN): BN;
@@ -0,0 +1,128 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.calculateBudgetedPeg = exports.calculateBudgetedK = exports.calculateBudgetedKBN = exports.calculateRepegCost = exports.calculateAdjustKCost = void 0;
4
+ const anchor_1 = require("@project-serum/anchor");
5
+ const assert_1 = require("../assert/assert");
6
+ const numericConstants_1 = require("../constants/numericConstants");
7
+ /**
8
+ * Helper function calculating adjust k cost
9
+ * @param amm
10
+ * @param numerator
11
+ * @param denomenator
12
+ * @returns cost : Precision QUOTE_ASSET_PRECISION
13
+ */
14
+ function calculateAdjustKCost(amm, numerator, denomenator) {
15
+ // const k = market.amm.sqrtK.mul(market.amm.sqrtK);
16
+ const x = amm.baseAssetReserve;
17
+ const y = amm.quoteAssetReserve;
18
+ const d = amm.netBaseAssetAmount;
19
+ const Q = amm.pegMultiplier;
20
+ const quoteScale = y.mul(d).mul(Q); //.div(AMM_RESERVE_PRECISION);
21
+ const p = numerator.mul(numericConstants_1.MARK_PRICE_PRECISION).div(denomenator);
22
+ const cost = quoteScale
23
+ .div(x.add(d))
24
+ .sub(quoteScale
25
+ .mul(p)
26
+ .div(numericConstants_1.MARK_PRICE_PRECISION)
27
+ .div(x.mul(p).div(numericConstants_1.MARK_PRICE_PRECISION).add(d)))
28
+ .div(numericConstants_1.AMM_TO_QUOTE_PRECISION_RATIO)
29
+ .div(numericConstants_1.PEG_PRECISION);
30
+ return cost.mul(new anchor_1.BN(-1));
31
+ }
32
+ exports.calculateAdjustKCost = calculateAdjustKCost;
33
+ /**
34
+ * Helper function calculating adjust pegMultiplier (repeg) cost
35
+ *
36
+ * @param amm
37
+ * @param newPeg
38
+ * @returns cost : Precision QUOTE_ASSET_PRECISION
39
+ */
40
+ function calculateRepegCost(amm, newPeg) {
41
+ const dqar = amm.quoteAssetReserve.sub(amm.terminalQuoteAssetReserve);
42
+ const cost = dqar
43
+ .mul(newPeg.sub(amm.pegMultiplier))
44
+ .div(numericConstants_1.AMM_TO_QUOTE_PRECISION_RATIO)
45
+ .div(numericConstants_1.PEG_PRECISION);
46
+ return cost;
47
+ }
48
+ exports.calculateRepegCost = calculateRepegCost;
49
+ function calculateBudgetedKBN(x, y, budget, Q, d) {
50
+ (0, assert_1.assert)(Q.gt(new anchor_1.BN(0)));
51
+ const C = budget.mul(new anchor_1.BN(-1));
52
+ let dSign = new anchor_1.BN(1);
53
+ if (d.lt(new anchor_1.BN(0))) {
54
+ dSign = new anchor_1.BN(-1);
55
+ }
56
+ const pegged_y_d_d = y
57
+ .mul(d)
58
+ .mul(d)
59
+ .mul(Q)
60
+ .div(numericConstants_1.AMM_RESERVE_PRECISION)
61
+ .div(numericConstants_1.AMM_RESERVE_PRECISION)
62
+ .div(numericConstants_1.PEG_PRECISION);
63
+ const numer1 = pegged_y_d_d;
64
+ const numer2 = C.mul(d)
65
+ .div(numericConstants_1.QUOTE_PRECISION)
66
+ .mul(x.add(d))
67
+ .div(numericConstants_1.AMM_RESERVE_PRECISION)
68
+ .mul(dSign);
69
+ const denom1 = C.mul(x)
70
+ .mul(x.add(d))
71
+ .div(numericConstants_1.AMM_RESERVE_PRECISION)
72
+ .div(numericConstants_1.QUOTE_PRECISION);
73
+ const denom2 = pegged_y_d_d;
74
+ const numerator = numer1.sub(numer2).div(numericConstants_1.AMM_TO_QUOTE_PRECISION_RATIO);
75
+ const denominator = denom1.add(denom2).div(numericConstants_1.AMM_TO_QUOTE_PRECISION_RATIO);
76
+ return [numerator, denominator];
77
+ }
78
+ exports.calculateBudgetedKBN = calculateBudgetedKBN;
79
+ function calculateBudgetedK(amm, cost) {
80
+ // wolframalpha.com
81
+ // (1/(x+d) - p/(x*p+d))*y*d*Q = C solve for p
82
+ // p = (d(y*d*Q - C(x+d))) / (C*x(x+d) + y*d*d*Q)
83
+ // numer
84
+ // = y*d*d*Q - Cxd - Cdd
85
+ // = y/x*Q*d*d - Cd - Cd/x
86
+ // = mark - C/d - C/(x)
87
+ // = mark/C - 1/d - 1/x
88
+ // denom
89
+ // = C*x*x + C*x*d + y*d*d*Q
90
+ // = x/d**2 + 1 / d + mark/C
91
+ // todo: assumes k = x * y
92
+ // otherwise use: (y(1-p) + (kp^2/(x*p+d)) - k/(x+d)) * Q = C solve for p
93
+ const x = amm.baseAssetReserve;
94
+ const y = amm.quoteAssetReserve;
95
+ const d = amm.netBaseAssetAmount;
96
+ const Q = amm.pegMultiplier;
97
+ const [numerator, denominator] = calculateBudgetedKBN(x, y, cost, Q, d);
98
+ return [numerator, denominator];
99
+ }
100
+ exports.calculateBudgetedK = calculateBudgetedK;
101
+ function calculateBudgetedPeg(amm, cost, targetPrice) {
102
+ // wolframalpha.com
103
+ // (1/(x+d) - p/(x*p+d))*y*d*Q = C solve for p
104
+ // p = (d(y*d*Q - C(x+d))) / (C*x(x+d) + y*y*d*Q)
105
+ // todo: assumes k = x * y
106
+ // otherwise use: (y(1-p) + (kp^2/(x*p+d)) - k/(x+d)) * Q = C solve for p
107
+ const targetPeg = targetPrice
108
+ .mul(amm.baseAssetReserve)
109
+ .div(amm.quoteAssetReserve)
110
+ .div(numericConstants_1.MARK_PRICE_PRECISION.div(numericConstants_1.PEG_PRECISION));
111
+ const k = amm.sqrtK.mul(amm.sqrtK);
112
+ const x = amm.baseAssetReserve;
113
+ const y = amm.quoteAssetReserve;
114
+ const d = amm.netBaseAssetAmount;
115
+ const Q = amm.pegMultiplier;
116
+ const C = cost.mul(new anchor_1.BN(-1));
117
+ const deltaQuoteAssetReserves = y.sub(k.div(x.add(d)));
118
+ const pegChangeDirection = targetPeg.sub(Q);
119
+ const useTargetPeg = (deltaQuoteAssetReserves.lt(numericConstants_1.ZERO) && pegChangeDirection.gt(numericConstants_1.ZERO)) ||
120
+ (deltaQuoteAssetReserves.gt(numericConstants_1.ZERO) && pegChangeDirection.lt(numericConstants_1.ZERO));
121
+ if (deltaQuoteAssetReserves.eq(numericConstants_1.ZERO) || useTargetPeg) {
122
+ return targetPeg;
123
+ }
124
+ const deltaPegMultiplier = C.mul(numericConstants_1.MARK_PRICE_PRECISION).div(deltaQuoteAssetReserves.div(numericConstants_1.AMM_TO_QUOTE_PRECISION_RATIO));
125
+ const newPeg = Q.sub(deltaPegMultiplier.mul(numericConstants_1.PEG_PRECISION).div(numericConstants_1.MARK_PRICE_PRECISION));
126
+ return newPeg;
127
+ }
128
+ exports.calculateBudgetedPeg = calculateBudgetedPeg;
@@ -1,13 +1,16 @@
1
1
  /// <reference types="bn.js" />
2
- import { Market, PositionDirection } from '../types';
2
+ import { MarketAccount, PositionDirection } from '../types';
3
3
  import { BN } from '@project-serum/anchor';
4
4
  import { AssetType } from './amm';
5
+ import { OraclePriceData } from '../oracles/types';
5
6
  export declare type PriceImpactUnit = 'entryPrice' | 'maxPrice' | 'priceDelta' | 'priceDeltaAsNumber' | 'pctAvg' | 'pctMax' | 'quoteAssetAmount' | 'quoteAssetAmountPeg' | 'acquiredBaseAssetAmount' | 'acquiredQuoteAssetAmount' | 'all';
6
7
  /**
7
8
  * Calculates avg/max slippage (price impact) for candidate trade
8
9
  * @param direction
9
10
  * @param amount
10
11
  * @param market
12
+ * @param inputAssetType which asset is being traded
13
+ * @param useSpread whether to consider spread with calculating slippage
11
14
  * @return [pctAvgSlippage, pctMaxSlippage, entryPrice, newPrice]
12
15
  *
13
16
  * 'pctAvgSlippage' => the percentage change to entryPrice (average est slippage in execution) : Precision MARK_PRICE_PRECISION
@@ -18,7 +21,7 @@ export declare type PriceImpactUnit = 'entryPrice' | 'maxPrice' | 'priceDelta' |
18
21
  *
19
22
  * 'newPrice' => the price of the asset after the trade : Precision MARK_PRICE_PRECISION
20
23
  */
21
- export declare function calculateTradeSlippage(direction: PositionDirection, amount: BN, market: Market, inputAssetType?: AssetType): [BN, BN, BN, BN];
24
+ export declare function calculateTradeSlippage(direction: PositionDirection, amount: BN, market: MarketAccount, inputAssetType?: AssetType, oraclePriceData?: OraclePriceData, useSpread?: boolean): [BN, BN, BN, BN];
22
25
  /**
23
26
  * Calculates acquired amounts for trade executed
24
27
  * @param direction
@@ -27,23 +30,25 @@ export declare function calculateTradeSlippage(direction: PositionDirection, amo
27
30
  * @param inputAssetType
28
31
  * @param useSpread
29
32
  * @return
30
- * | 'acquiredBase' => positive/negative change in user's base : BN TODO-PRECISION
33
+ * | 'acquiredBase' => positive/negative change in user's base : BN AMM_RESERVE_PRECISION
31
34
  * | 'acquiredQuote' => positive/negative change in user's quote : BN TODO-PRECISION
32
35
  */
33
- export declare function calculateTradeAcquiredAmounts(direction: PositionDirection, amount: BN, market: Market, inputAssetType?: AssetType, useSpread?: boolean): [BN, BN];
36
+ export declare function calculateTradeAcquiredAmounts(direction: PositionDirection, amount: BN, market: MarketAccount, inputAssetType: AssetType, oraclePriceData: OraclePriceData, useSpread?: boolean): [BN, BN];
34
37
  /**
35
38
  * calculateTargetPriceTrade
36
39
  * simple function for finding arbitraging trades
37
40
  * @param market
38
41
  * @param targetPrice
39
42
  * @param pct optional default is 100% gap filling, can set smaller.
43
+ * @param outputAssetType which asset to trade.
44
+ * @param useSpread whether or not to consider the spread when calculating the trade size
40
45
  * @returns trade direction/size in order to push price to a targetPrice,
41
46
  *
42
47
  * [
43
- * direction => direction of trade required, TODO-PRECISION
48
+ * direction => direction of trade required, PositionDirection
44
49
  * tradeSize => size of trade required, TODO-PRECISION
45
- * entryPrice => the entry price for the trade, TODO-PRECISION
46
- * targetPrice => the target price TODO-PRECISION
50
+ * entryPrice => the entry price for the trade, MARK_PRICE_PRECISION
51
+ * targetPrice => the target price MARK_PRICE_PRECISION
47
52
  * ]
48
53
  */
49
- export declare function calculateTargetPriceTrade(market: Market, targetPrice: BN, pct?: BN, outputAssetType?: AssetType): [PositionDirection, BN, BN, BN];
54
+ export declare function calculateTargetPriceTrade(market: MarketAccount, targetPrice: BN, pct?: BN, outputAssetType?: AssetType, oraclePriceData?: OraclePriceData, useSpread?: boolean): [PositionDirection, BN, BN, BN];
package/lib/math/trade.js CHANGED
@@ -8,12 +8,15 @@ const numericConstants_1 = require("../constants/numericConstants");
8
8
  const market_1 = require("./market");
9
9
  const amm_1 = require("./amm");
10
10
  const utils_1 = require("./utils");
11
+ const types_2 = require("../types");
11
12
  const MAXPCT = new anchor_1.BN(1000); //percentage units are [0,1000] => [0,1]
12
13
  /**
13
14
  * Calculates avg/max slippage (price impact) for candidate trade
14
15
  * @param direction
15
16
  * @param amount
16
17
  * @param market
18
+ * @param inputAssetType which asset is being traded
19
+ * @param useSpread whether to consider spread with calculating slippage
17
20
  * @return [pctAvgSlippage, pctMaxSlippage, entryPrice, newPrice]
18
21
  *
19
22
  * 'pctAvgSlippage' => the percentage change to entryPrice (average est slippage in execution) : Precision MARK_PRICE_PRECISION
@@ -24,19 +27,50 @@ const MAXPCT = new anchor_1.BN(1000); //percentage units are [0,1000] => [0,1]
24
27
  *
25
28
  * 'newPrice' => the price of the asset after the trade : Precision MARK_PRICE_PRECISION
26
29
  */
27
- function calculateTradeSlippage(direction, amount, market, inputAssetType = 'quote') {
28
- const oldPrice = (0, market_1.calculateMarkPrice)(market);
30
+ function calculateTradeSlippage(direction, amount, market, inputAssetType = 'quote', oraclePriceData, useSpread = true) {
31
+ let oldPrice;
32
+ if (useSpread && market.amm.baseSpread > 0) {
33
+ if ((0, types_2.isVariant)(direction, 'long')) {
34
+ oldPrice = (0, market_1.calculateAskPrice)(market, oraclePriceData);
35
+ }
36
+ else {
37
+ oldPrice = (0, market_1.calculateBidPrice)(market, oraclePriceData);
38
+ }
39
+ }
40
+ else {
41
+ oldPrice = (0, market_1.calculateMarkPrice)(market, oraclePriceData);
42
+ }
29
43
  if (amount.eq(numericConstants_1.ZERO)) {
30
44
  return [numericConstants_1.ZERO, numericConstants_1.ZERO, oldPrice, oldPrice];
31
45
  }
32
- const [acquiredBase, acquiredQuote] = calculateTradeAcquiredAmounts(direction, amount, market, inputAssetType);
33
- const entryPrice = (0, amm_1.calculatePrice)(acquiredBase, acquiredQuote, market.amm.pegMultiplier).mul(new anchor_1.BN(-1));
34
- const newPrice = (0, amm_1.calculatePrice)(market.amm.baseAssetReserve.sub(acquiredBase), market.amm.quoteAssetReserve.sub(acquiredQuote), market.amm.pegMultiplier);
46
+ const [acquiredBase, acquiredQuote] = calculateTradeAcquiredAmounts(direction, amount, market, inputAssetType, oraclePriceData, useSpread);
47
+ const swapDirection = (0, types_2.isVariant)(direction, 'long')
48
+ ? types_1.SwapDirection.REMOVE
49
+ : types_1.SwapDirection.ADD;
50
+ const quoteAssetAmountAcquired = (0, amm_1.calculateQuoteAssetAmountSwapped)(acquiredQuote.abs(), market.amm.pegMultiplier, swapDirection);
51
+ const entryPrice = quoteAssetAmountAcquired
52
+ .mul(numericConstants_1.AMM_TO_QUOTE_PRECISION_RATIO)
53
+ .mul(numericConstants_1.MARK_PRICE_PRECISION)
54
+ .div(acquiredBase.abs());
55
+ let amm;
56
+ if (useSpread && market.amm.baseSpread > 0) {
57
+ const { baseAssetReserve, quoteAssetReserve, sqrtK, newPeg } = (0, amm_1.calculateUpdatedAMMSpreadReserves)(market.amm, direction, oraclePriceData);
58
+ amm = {
59
+ baseAssetReserve,
60
+ quoteAssetReserve,
61
+ sqrtK: sqrtK,
62
+ pegMultiplier: newPeg,
63
+ };
64
+ }
65
+ else {
66
+ amm = market.amm;
67
+ }
68
+ const newPrice = (0, amm_1.calculatePrice)(amm.baseAssetReserve.sub(acquiredBase), amm.quoteAssetReserve.sub(acquiredQuote), amm.pegMultiplier);
35
69
  if (direction == types_1.PositionDirection.SHORT) {
36
- (0, assert_1.assert)(newPrice.lt(oldPrice));
70
+ (0, assert_1.assert)(newPrice.lte(oldPrice));
37
71
  }
38
72
  else {
39
- (0, assert_1.assert)(oldPrice.lt(newPrice));
73
+ (0, assert_1.assert)(oldPrice.lte(newPrice));
40
74
  }
41
75
  const pctMaxSlippage = newPrice
42
76
  .sub(oldPrice)
@@ -59,22 +93,22 @@ exports.calculateTradeSlippage = calculateTradeSlippage;
59
93
  * @param inputAssetType
60
94
  * @param useSpread
61
95
  * @return
62
- * | 'acquiredBase' => positive/negative change in user's base : BN TODO-PRECISION
96
+ * | 'acquiredBase' => positive/negative change in user's base : BN AMM_RESERVE_PRECISION
63
97
  * | 'acquiredQuote' => positive/negative change in user's quote : BN TODO-PRECISION
64
98
  */
65
- function calculateTradeAcquiredAmounts(direction, amount, market, inputAssetType = 'quote', useSpread = true) {
99
+ function calculateTradeAcquiredAmounts(direction, amount, market, inputAssetType = 'quote', oraclePriceData, useSpread = true) {
66
100
  if (amount.eq(numericConstants_1.ZERO)) {
67
101
  return [numericConstants_1.ZERO, numericConstants_1.ZERO];
68
102
  }
69
103
  const swapDirection = (0, amm_1.getSwapDirection)(inputAssetType, direction);
70
104
  let amm;
71
105
  if (useSpread && market.amm.baseSpread > 0) {
72
- const { baseAssetReserve, quoteAssetReserve } = (0, amm_1.calculateSpreadReserves)(market.amm, direction);
106
+ const { baseAssetReserve, quoteAssetReserve, sqrtK, newPeg } = (0, amm_1.calculateUpdatedAMMSpreadReserves)(market.amm, direction, oraclePriceData);
73
107
  amm = {
74
108
  baseAssetReserve,
75
109
  quoteAssetReserve,
76
- sqrtK: market.amm.sqrtK,
77
- pegMultiplier: market.amm.pegMultiplier,
110
+ sqrtK: sqrtK,
111
+ pegMultiplier: newPeg,
78
112
  };
79
113
  }
80
114
  else {
@@ -92,43 +126,72 @@ exports.calculateTradeAcquiredAmounts = calculateTradeAcquiredAmounts;
92
126
  * @param market
93
127
  * @param targetPrice
94
128
  * @param pct optional default is 100% gap filling, can set smaller.
129
+ * @param outputAssetType which asset to trade.
130
+ * @param useSpread whether or not to consider the spread when calculating the trade size
95
131
  * @returns trade direction/size in order to push price to a targetPrice,
96
132
  *
97
133
  * [
98
- * direction => direction of trade required, TODO-PRECISION
134
+ * direction => direction of trade required, PositionDirection
99
135
  * tradeSize => size of trade required, TODO-PRECISION
100
- * entryPrice => the entry price for the trade, TODO-PRECISION
101
- * targetPrice => the target price TODO-PRECISION
136
+ * entryPrice => the entry price for the trade, MARK_PRICE_PRECISION
137
+ * targetPrice => the target price MARK_PRICE_PRECISION
102
138
  * ]
103
139
  */
104
- function calculateTargetPriceTrade(market, targetPrice, pct = MAXPCT, outputAssetType = 'quote') {
140
+ function calculateTargetPriceTrade(market, targetPrice, pct = MAXPCT, outputAssetType = 'quote', oraclePriceData, useSpread = true) {
105
141
  (0, assert_1.assert)(market.amm.baseAssetReserve.gt(numericConstants_1.ZERO));
106
142
  (0, assert_1.assert)(targetPrice.gt(numericConstants_1.ZERO));
107
143
  (0, assert_1.assert)(pct.lte(MAXPCT) && pct.gt(numericConstants_1.ZERO));
108
- const markPriceBefore = (0, market_1.calculateMarkPrice)(market);
144
+ const markPriceBefore = (0, market_1.calculateMarkPrice)(market, oraclePriceData);
145
+ const bidPriceBefore = (0, market_1.calculateBidPrice)(market, oraclePriceData);
146
+ const askPriceBefore = (0, market_1.calculateAskPrice)(market, oraclePriceData);
147
+ let direction;
109
148
  if (targetPrice.gt(markPriceBefore)) {
110
149
  const priceGap = targetPrice.sub(markPriceBefore);
111
150
  const priceGapScaled = priceGap.mul(pct).div(MAXPCT);
112
151
  targetPrice = markPriceBefore.add(priceGapScaled);
152
+ direction = types_1.PositionDirection.LONG;
113
153
  }
114
154
  else {
115
155
  const priceGap = markPriceBefore.sub(targetPrice);
116
156
  const priceGapScaled = priceGap.mul(pct).div(MAXPCT);
117
157
  targetPrice = markPriceBefore.sub(priceGapScaled);
158
+ direction = types_1.PositionDirection.SHORT;
118
159
  }
119
- let direction;
120
160
  let tradeSize;
121
161
  let baseSize;
122
- const baseAssetReserveBefore = market.amm.baseAssetReserve;
123
- const quoteAssetReserveBefore = market.amm.quoteAssetReserve;
124
- const peg = market.amm.pegMultiplier;
162
+ let baseAssetReserveBefore;
163
+ let quoteAssetReserveBefore;
164
+ let peg = market.amm.pegMultiplier;
165
+ if (useSpread && market.amm.baseSpread > 0) {
166
+ const { baseAssetReserve, quoteAssetReserve, newPeg } = (0, amm_1.calculateUpdatedAMMSpreadReserves)(market.amm, direction, oraclePriceData);
167
+ baseAssetReserveBefore = baseAssetReserve;
168
+ quoteAssetReserveBefore = quoteAssetReserve;
169
+ peg = newPeg;
170
+ }
171
+ else {
172
+ baseAssetReserveBefore = market.amm.baseAssetReserve;
173
+ quoteAssetReserveBefore = market.amm.quoteAssetReserve;
174
+ }
125
175
  const invariant = market.amm.sqrtK.mul(market.amm.sqrtK);
126
176
  const k = invariant.mul(numericConstants_1.MARK_PRICE_PRECISION);
127
177
  let baseAssetReserveAfter;
128
178
  let quoteAssetReserveAfter;
129
179
  const biasModifier = new anchor_1.BN(1);
130
180
  let markPriceAfter;
131
- if (markPriceBefore.gt(targetPrice)) {
181
+ if (useSpread &&
182
+ targetPrice.lt(askPriceBefore) &&
183
+ targetPrice.gt(bidPriceBefore)) {
184
+ // no trade, market is at target
185
+ if (markPriceBefore.gt(targetPrice)) {
186
+ direction = types_1.PositionDirection.SHORT;
187
+ }
188
+ else {
189
+ direction = types_1.PositionDirection.LONG;
190
+ }
191
+ tradeSize = numericConstants_1.ZERO;
192
+ return [direction, tradeSize, targetPrice, targetPrice];
193
+ }
194
+ else if (markPriceBefore.gt(targetPrice)) {
132
195
  // overestimate y2
133
196
  baseAssetReserveAfter = (0, utils_1.squareRootBN)(k.div(targetPrice).mul(peg).div(numericConstants_1.PEG_PRECISION).sub(biasModifier)).sub(new anchor_1.BN(1));
134
197
  quoteAssetReserveAfter = k