@drift-labs/sdk 0.1.33 → 0.1.34-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 (50) hide show
  1. package/lib/admin.d.ts +1 -0
  2. package/lib/admin.js +11 -0
  3. package/lib/constants/numericConstants.d.ts +2 -0
  4. package/lib/constants/numericConstants.js +3 -1
  5. package/lib/idl/clearing_house.json +40 -2
  6. package/lib/math/amm.d.ts +7 -2
  7. package/lib/math/amm.js +45 -6
  8. package/lib/math/funding.js +3 -1
  9. package/lib/math/market.d.ts +15 -0
  10. package/lib/math/market.js +29 -2
  11. package/lib/math/trade.d.ts +3 -1
  12. package/lib/math/trade.js +18 -6
  13. package/lib/orders.js +26 -7
  14. package/lib/types.d.ts +2 -1
  15. package/package.json +1 -1
  16. package/src/admin.ts +17 -0
  17. package/src/constants/numericConstants.ts +2 -0
  18. package/src/idl/clearing_house.json +40 -2
  19. package/src/math/amm.ts +71 -6
  20. package/src/math/funding.ts +11 -8
  21. package/src/math/market.ts +47 -1
  22. package/src/math/trade.ts +24 -13
  23. package/src/orders.ts +39 -9
  24. package/src/types.ts +2 -1
  25. package/src/assert/assert.js +0 -10
  26. package/src/assert/assert.js.map +0 -1
  27. package/src/math/conversion.js +0 -16
  28. package/src/math/conversion.js.map +0 -1
  29. package/src/math/funding.js +0 -223
  30. package/src/math/funding.js.map +0 -1
  31. package/src/math/insuranceFund.js +0 -23
  32. package/src/math/insuranceFund.js.map +0 -1
  33. package/src/math/position.js +0 -121
  34. package/src/math/position.js.map +0 -1
  35. package/src/math/utils.js +0 -27
  36. package/src/math/utils.js.map +0 -1
  37. package/src/oracles/switchboardClient.js +0 -60
  38. package/src/oracles/switchboardClient.js.map +0 -1
  39. package/src/token/index.js +0 -39
  40. package/src/token/index.js.map +0 -1
  41. package/src/tx/defaultTxSender.js +0 -13
  42. package/src/tx/defaultTxSender.js.map +0 -1
  43. package/src/tx/types.js +0 -3
  44. package/src/tx/types.js.map +0 -1
  45. package/src/tx/utils.js +0 -9
  46. package/src/tx/utils.js.map +0 -1
  47. package/src/util/computeUnits.js +0 -17
  48. package/src/util/computeUnits.js.map +0 -1
  49. package/src/util/tps.js +0 -17
  50. package/src/util/tps.js.map +0 -1
package/src/math/amm.ts CHANGED
@@ -7,6 +7,8 @@ import {
7
7
  AMM_TO_QUOTE_PRECISION_RATIO,
8
8
  QUOTE_PRECISION,
9
9
  AMM_RESERVE_PRECISION,
10
+ BID_ASK_SPREAD_PRECISION,
11
+ ONE,
10
12
  } from '../constants/numericConstants';
11
13
  import { calculateBaseAssetValue } from './position';
12
14
  import {
@@ -60,7 +62,10 @@ export type AssetType = 'quote' | 'base';
60
62
  * @returns quoteAssetReserve and baseAssetReserve after swap. : Precision AMM_RESERVE_PRECISION
61
63
  */
62
64
  export function calculateAmmReservesAfterSwap(
63
- amm: AMM,
65
+ amm: Pick<
66
+ AMM,
67
+ 'pegMultiplier' | 'quoteAssetReserve' | 'sqrtK' | 'baseAssetReserve'
68
+ >,
64
69
  inputAssetType: AssetType,
65
70
  swapAmount: BN,
66
71
  swapDirection: SwapDirection
@@ -93,6 +98,38 @@ export function calculateAmmReservesAfterSwap(
93
98
  return [newQuoteAssetReserve, newBaseAssetReserve];
94
99
  }
95
100
 
101
+ export function calculateSpreadReserves(
102
+ amm: AMM,
103
+ direction: PositionDirection
104
+ ): {
105
+ baseAssetReserve: BN;
106
+ quoteAssetReserve: BN;
107
+ } {
108
+ if (amm.baseSpread === 0) {
109
+ return {
110
+ baseAssetReserve: amm.baseAssetReserve,
111
+ quoteAssetReserve: amm.quoteAssetReserve,
112
+ };
113
+ }
114
+
115
+ const quoteAsserReserveDelta = amm.quoteAssetReserve.div(
116
+ BID_ASK_SPREAD_PRECISION.div(new BN(amm.baseSpread / 4))
117
+ );
118
+
119
+ let quoteAssetReserve;
120
+ if (isVariant(direction, 'long')) {
121
+ quoteAssetReserve = amm.quoteAssetReserve.add(quoteAsserReserveDelta);
122
+ } else {
123
+ quoteAssetReserve = amm.quoteAssetReserve.sub(quoteAsserReserveDelta);
124
+ }
125
+
126
+ const baseAssetReserve = amm.sqrtK.mul(amm.sqrtK).div(quoteAssetReserve);
127
+ return {
128
+ baseAssetReserve,
129
+ quoteAssetReserve,
130
+ };
131
+ }
132
+
96
133
  /**
97
134
  * Helper function calculating constant product curve output. Agnostic to whether input asset is quote or base
98
135
  *
@@ -288,7 +325,9 @@ export function calculateTerminalPrice(market: Market) {
288
325
 
289
326
  export function calculateMaxBaseAssetAmountToTrade(
290
327
  amm: AMM,
291
- limit_price: BN
328
+ limit_price: BN,
329
+ direction: PositionDirection,
330
+ useSpread: boolean
292
331
  ): [BN, PositionDirection] {
293
332
  const invariant = amm.sqrtK.mul(amm.sqrtK);
294
333
 
@@ -300,14 +339,24 @@ export function calculateMaxBaseAssetAmountToTrade(
300
339
 
301
340
  const newBaseAssetReserve = squareRootBN(newBaseAssetReserveSquared);
302
341
 
303
- if (newBaseAssetReserve.gt(amm.baseAssetReserve)) {
342
+ let baseAssetReserveBefore;
343
+ if (useSpread) {
344
+ baseAssetReserveBefore = calculateSpreadReserves(
345
+ amm,
346
+ direction
347
+ ).baseAssetReserve;
348
+ } else {
349
+ baseAssetReserveBefore = amm.baseAssetReserve;
350
+ }
351
+
352
+ if (newBaseAssetReserve.gt(baseAssetReserveBefore)) {
304
353
  return [
305
- newBaseAssetReserve.sub(amm.baseAssetReserve),
354
+ newBaseAssetReserve.sub(baseAssetReserveBefore),
306
355
  PositionDirection.SHORT,
307
356
  ];
308
- } else if (newBaseAssetReserve.lt(amm.baseAssetReserve)) {
357
+ } else if (newBaseAssetReserve.lt(baseAssetReserveBefore)) {
309
358
  return [
310
- amm.baseAssetReserve.sub(newBaseAssetReserve),
359
+ baseAssetReserveBefore.sub(newBaseAssetReserve),
311
360
  PositionDirection.LONG,
312
361
  ];
313
362
  } else {
@@ -398,3 +447,19 @@ export function calculateBudgetedPeg(market: Market, cost: BN): BN {
398
447
 
399
448
  return newPeg;
400
449
  }
450
+
451
+ export function calculateQuoteAssetAmountSwapped(
452
+ quoteAssetReserves: BN,
453
+ pegMultiplier: BN,
454
+ swapDirection: SwapDirection
455
+ ): BN {
456
+ let quoteAssetAmount = quoteAssetReserves
457
+ .mul(pegMultiplier)
458
+ .div(AMM_TIMES_PEG_TO_QUOTE_PRECISION_RATIO);
459
+
460
+ if (isVariant(swapDirection, 'remove')) {
461
+ quoteAssetAmount = quoteAssetAmount.add(ONE);
462
+ }
463
+
464
+ return quoteAssetAmount;
465
+ }
@@ -43,13 +43,9 @@ export async function calculateAllEstimatedFundingRate(
43
43
  const lastMarkPriceTwapTs = market.amm.lastMarkPriceTwapTs;
44
44
 
45
45
  const timeSinceLastMarkChange = now.sub(lastMarkPriceTwapTs);
46
- const markTwapTimeSinceLastUpdate =
47
- BN.max(
46
+ const markTwapTimeSinceLastUpdate = BN.max(
48
47
  secondsInHour,
49
- BN.max(
50
- ZERO,
51
- secondsInHour.sub(timeSinceLastMarkChange)
52
- )
48
+ BN.max(ZERO, secondsInHour.sub(timeSinceLastMarkChange))
53
49
  );
54
50
  const baseAssetPriceWithMantissa = calculateMarkPrice(market);
55
51
 
@@ -63,7 +59,10 @@ export async function calculateAllEstimatedFundingRate(
63
59
  const lastOracleTwapWithMantissa = market.amm.lastOraclePriceTwap;
64
60
  const lastOraclePriceTwapTs = market.amm.lastOraclePriceTwapTs;
65
61
 
66
- const oracleInvalidDuration = BN.max(ZERO, lastMarkPriceTwapTs.sub(lastOraclePriceTwapTs));
62
+ const oracleInvalidDuration = BN.max(
63
+ ZERO,
64
+ lastMarkPriceTwapTs.sub(lastOraclePriceTwapTs)
65
+ );
67
66
 
68
67
  const timeSinceLastOracleTwapUpdate = now.sub(lastOraclePriceTwapTs);
69
68
  const oracleTwapTimeSinceLastUpdate = BN.max(
@@ -87,7 +86,11 @@ export async function calculateAllEstimatedFundingRate(
87
86
  .mul(lastOracleTwapWithMantissa)
88
87
  .add(timeSinceLastMarkChange.mul(oraclePrice))
89
88
  .add(oracleInvalidDuration.mul(lastMarkTwapWithMantissa))
90
- .div(timeSinceLastMarkChange.add(oracleTwapTimeSinceLastUpdate).add(oracleInvalidDuration));
89
+ .div(
90
+ timeSinceLastMarkChange
91
+ .add(oracleTwapTimeSinceLastUpdate)
92
+ .add(oracleInvalidDuration)
93
+ );
91
94
  }
92
95
 
93
96
  const twapSpread = lastMarkTwapWithMantissa.sub(lastOracleTwapWithMantissa);
@@ -3,6 +3,7 @@ import { Market, PositionDirection } from '../types';
3
3
  import {
4
4
  calculateAmmReservesAfterSwap,
5
5
  calculatePrice,
6
+ calculateSpreadReserves,
6
7
  getSwapDirection,
7
8
  } from './amm';
8
9
  import { OraclePriceData } from '../oracles/types';
@@ -21,6 +22,44 @@ export function calculateMarkPrice(market: Market): BN {
21
22
  );
22
23
  }
23
24
 
25
+ /**
26
+ * Calculates market bid price
27
+ *
28
+ * @param market
29
+ * @return bidPrice : Precision MARK_PRICE_PRECISION
30
+ */
31
+ export function calculateBidPrice(market: Market): BN {
32
+ const { baseAssetReserve, quoteAssetReserve } = calculateSpreadReserves(
33
+ market.amm,
34
+ PositionDirection.SHORT
35
+ );
36
+
37
+ return calculatePrice(
38
+ baseAssetReserve,
39
+ quoteAssetReserve,
40
+ market.amm.pegMultiplier
41
+ );
42
+ }
43
+
44
+ /**
45
+ * Calculates market ask price
46
+ *
47
+ * @param market
48
+ * @return bidPrice : Precision MARK_PRICE_PRECISION
49
+ */
50
+ export function calculateAskPrice(market: Market): BN {
51
+ const { baseAssetReserve, quoteAssetReserve } = calculateSpreadReserves(
52
+ market.amm,
53
+ PositionDirection.LONG
54
+ );
55
+
56
+ return calculatePrice(
57
+ baseAssetReserve,
58
+ quoteAssetReserve,
59
+ market.amm.pegMultiplier
60
+ );
61
+ }
62
+
24
63
  export function calculateNewMarketAfterTrade(
25
64
  baseAssetAmount: BN,
26
65
  direction: PositionDirection,
@@ -48,5 +87,12 @@ export function calculateMarkOracleSpread(
48
87
  oraclePriceData: OraclePriceData
49
88
  ): BN {
50
89
  const markPrice = calculateMarkPrice(market);
51
- return markPrice.sub(oraclePriceData.price);
90
+ return calculateOracleSpread(markPrice, oraclePriceData);
91
+ }
92
+
93
+ export function calculateOracleSpread(
94
+ price: BN,
95
+ oraclePriceData: OraclePriceData
96
+ ): BN {
97
+ return price.sub(oraclePriceData.price);
52
98
  }
package/src/math/trade.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { isVariant, Market, PositionDirection } from '../types';
1
+ import { Market, PositionDirection } from '../types';
2
2
  import { BN } from '@project-serum/anchor';
3
3
  import { assert } from '../assert/assert';
4
4
  import {
@@ -6,7 +6,6 @@ import {
6
6
  PEG_PRECISION,
7
7
  AMM_TO_QUOTE_PRECISION_RATIO,
8
8
  ZERO,
9
- ONE,
10
9
  } from '../constants/numericConstants';
11
10
  import { calculateMarkPrice } from './market';
12
11
  import {
@@ -14,6 +13,7 @@ import {
14
13
  calculatePrice,
15
14
  getSwapDirection,
16
15
  AssetType,
16
+ calculateSpreadReserves,
17
17
  } from './amm';
18
18
  import { squareRootBN } from './utils';
19
19
 
@@ -101,6 +101,8 @@ export function calculateTradeSlippage(
101
101
  * @param direction
102
102
  * @param amount
103
103
  * @param market
104
+ * @param inputAssetType
105
+ * @param useSpread
104
106
  * @return
105
107
  * | 'acquiredBase' => positive/negative change in user's base : BN TODO-PRECISION
106
108
  * | 'acquiredQuote' => positive/negative change in user's quote : BN TODO-PRECISION
@@ -109,27 +111,36 @@ export function calculateTradeAcquiredAmounts(
109
111
  direction: PositionDirection,
110
112
  amount: BN,
111
113
  market: Market,
112
- inputAssetType: AssetType = 'quote'
114
+ inputAssetType: AssetType = 'quote',
115
+ useSpread = true
113
116
  ): [BN, BN] {
114
117
  if (amount.eq(ZERO)) {
115
118
  return [ZERO, ZERO];
116
119
  }
117
120
 
118
121
  const swapDirection = getSwapDirection(inputAssetType, direction);
119
- const [newQuoteAssetReserve, newBaseAssetReserve] =
120
- calculateAmmReservesAfterSwap(
122
+
123
+ let amm: Parameters<typeof calculateAmmReservesAfterSwap>[0];
124
+ if (useSpread && market.amm.baseSpread > 0) {
125
+ const { baseAssetReserve, quoteAssetReserve } = calculateSpreadReserves(
121
126
  market.amm,
122
- inputAssetType,
123
- amount,
124
- swapDirection
127
+ direction
125
128
  );
126
-
127
- const acquiredBase = market.amm.baseAssetReserve.sub(newBaseAssetReserve);
128
- let acquiredQuote = market.amm.quoteAssetReserve.sub(newQuoteAssetReserve);
129
- if (inputAssetType === 'base' && isVariant(swapDirection, 'remove')) {
130
- acquiredQuote = acquiredQuote.sub(ONE);
129
+ amm = {
130
+ baseAssetReserve,
131
+ quoteAssetReserve,
132
+ sqrtK: market.amm.sqrtK,
133
+ pegMultiplier: market.amm.pegMultiplier,
134
+ };
135
+ } else {
136
+ amm = market.amm;
131
137
  }
132
138
 
139
+ const [newQuoteAssetReserve, newBaseAssetReserve] =
140
+ calculateAmmReservesAfterSwap(amm, inputAssetType, amount, swapDirection);
141
+
142
+ const acquiredBase = amm.baseAssetReserve.sub(newBaseAssetReserve);
143
+ const acquiredQuote = amm.quoteAssetReserve.sub(newQuoteAssetReserve);
133
144
  return [acquiredBase, acquiredQuote];
134
145
  }
135
146
 
package/src/orders.ts CHANGED
@@ -11,6 +11,7 @@ import {
11
11
  BN,
12
12
  calculateAmmReservesAfterSwap,
13
13
  calculateBaseAssetValue,
14
+ calculateSpreadReserves,
14
15
  ClearingHouseUser,
15
16
  isOrderRiskIncreasingInSameDirection,
16
17
  TEN_THOUSAND,
@@ -211,7 +212,9 @@ export function calculateAmountToTradeForLimit(
211
212
 
212
213
  const [maxAmountToTrade, direction] = calculateMaxBaseAssetAmountToTrade(
213
214
  market.amm,
214
- limitPrice
215
+ limitPrice,
216
+ order.direction,
217
+ !order.postOnly
215
218
  );
216
219
 
217
220
  // Check that directions are the same
@@ -295,24 +298,51 @@ export function calculateBaseAssetAmountUserCanExecute(
295
298
  return ZERO;
296
299
  }
297
300
 
298
- const baseAssetReservesBefore = market.amm.baseAssetReserve;
301
+ const swapDirection = isVariant(order.direction, 'long')
302
+ ? SwapDirection.ADD
303
+ : SwapDirection.REMOVE;
304
+
305
+ const useSpread = !order.postOnly;
306
+ let amm: Parameters<typeof calculateAmmReservesAfterSwap>[0];
307
+ if (useSpread) {
308
+ const { baseAssetReserve, quoteAssetReserve } = calculateSpreadReserves(
309
+ market.amm,
310
+ order.direction
311
+ );
312
+ amm = {
313
+ baseAssetReserve,
314
+ quoteAssetReserve,
315
+ sqrtK: market.amm.sqrtK,
316
+ pegMultiplier: market.amm.pegMultiplier,
317
+ };
318
+ } else {
319
+ amm = market.amm;
320
+ }
321
+
322
+ const baseAssetReservesBefore = amm.baseAssetReserve;
299
323
  const [_, baseAssetReservesAfter] = calculateAmmReservesAfterSwap(
300
- market.amm,
324
+ amm,
301
325
  'quote',
302
326
  quoteAssetAmount,
303
- isVariant(order.direction, 'long')
304
- ? SwapDirection.ADD
305
- : SwapDirection.REMOVE
327
+ swapDirection
306
328
  );
307
329
 
308
- let baseAssetAmount = baseAssetReservesBefore.sub(baseAssetReservesAfter).abs();
330
+ let baseAssetAmount = baseAssetReservesBefore
331
+ .sub(baseAssetReservesAfter)
332
+ .abs();
309
333
  if (order.reduceOnly) {
310
334
  const position =
311
335
  user.getUserPosition(order.marketIndex) ||
312
336
  user.getEmptyPosition(order.marketIndex);
313
- if (isVariant(order.direction, 'long') && position.baseAssetAmount.gte(ZERO)) {
337
+ if (
338
+ isVariant(order.direction, 'long') &&
339
+ position.baseAssetAmount.gte(ZERO)
340
+ ) {
314
341
  baseAssetAmount = ZERO;
315
- } else if (isVariant(order.direction, 'short') && position.baseAssetAmount.lte(ZERO)) {
342
+ } else if (
343
+ isVariant(order.direction, 'short') &&
344
+ position.baseAssetAmount.lte(ZERO)
345
+ ) {
316
346
  baseAssetAmount = ZERO;
317
347
  } else {
318
348
  BN.min(baseAssetAmount, position.baseAssetAmount.abs());
package/src/types.ts CHANGED
@@ -154,7 +154,7 @@ export type TradeRecord = {
154
154
  markPriceBefore: BN;
155
155
  markPriceAfter: BN;
156
156
  fee: BN;
157
- referrerReward: BN;
157
+ quoteAssetAmountSurplus: BN;
158
158
  refereeDiscount: BN;
159
159
  tokenDiscount: BN;
160
160
  marketIndex: BN;
@@ -309,6 +309,7 @@ export type AMM = {
309
309
  minimumQuoteAssetTradeSize: BN;
310
310
  minimumBaseAssetTradeSize: BN;
311
311
  lastOraclePrice: BN;
312
+ baseSpread: number;
312
313
  };
313
314
 
314
315
  // # User Account Types
@@ -1,10 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.assert = void 0;
4
- function assert(condition, error) {
5
- if (!condition) {
6
- throw new Error(error || 'Unspecified AssertionError');
7
- }
8
- }
9
- exports.assert = assert;
10
- //# sourceMappingURL=assert.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"assert.js","sourceRoot":"","sources":["assert.ts"],"names":[],"mappings":";;;AAAA,SAAgB,MAAM,CAAC,SAAkB,EAAE,KAAc;IACxD,IAAI,CAAC,SAAS,EAAE;QACf,MAAM,IAAI,KAAK,CAAC,KAAK,IAAI,4BAA4B,CAAC,CAAC;KACvD;AACF,CAAC;AAJD,wBAIC"}
@@ -1,16 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.convertBaseAssetAmountToNumber = exports.convertToNumber = void 0;
4
- const numericConstants_1 = require("../constants/numericConstants");
5
- const convertToNumber = (bigNumber, precision = numericConstants_1.MARK_PRICE_PRECISION) => {
6
- if (!bigNumber)
7
- return 0;
8
- return (bigNumber.div(precision).toNumber() +
9
- bigNumber.mod(precision).toNumber() / precision.toNumber());
10
- };
11
- exports.convertToNumber = convertToNumber;
12
- const convertBaseAssetAmountToNumber = (baseAssetAmount) => {
13
- return (0, exports.convertToNumber)(baseAssetAmount, numericConstants_1.MARK_PRICE_PRECISION.mul(numericConstants_1.PEG_PRECISION));
14
- };
15
- exports.convertBaseAssetAmountToNumber = convertBaseAssetAmountToNumber;
16
- //# sourceMappingURL=conversion.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"conversion.js","sourceRoot":"","sources":["conversion.ts"],"names":[],"mappings":";;;AACA,oEAGuC;AAEhC,MAAM,eAAe,GAAG,CAC9B,SAAa,EACb,YAAgB,uCAAoB,EACnC,EAAE;IACH,IAAI,CAAC,SAAS;QAAE,OAAO,CAAC,CAAC;IACzB,OAAO,CACN,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,QAAQ,EAAE;QACnC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,QAAQ,EAAE,GAAG,SAAS,CAAC,QAAQ,EAAE,CAC1D,CAAC;AACH,CAAC,CAAC;AATW,QAAA,eAAe,mBAS1B;AAEK,MAAM,8BAA8B,GAAG,CAAC,eAAmB,EAAE,EAAE;IACrE,OAAO,IAAA,uBAAe,EACrB,eAAe,EACf,uCAAoB,CAAC,GAAG,CAAC,gCAAa,CAAC,CACvC,CAAC;AACH,CAAC,CAAC;AALW,QAAA,8BAA8B,kCAKzC"}
@@ -1,223 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.calculateFundingPool = exports.calculateLongShortFundingRateAndLiveTwaps = exports.calculateLongShortFundingRate = exports.calculateEstimatedFundingRate = exports.calculateAllEstimatedFundingRate = void 0;
4
- const anchor_1 = require("@project-serum/anchor");
5
- const numericConstants_1 = require("../constants/numericConstants");
6
- const market_1 = require("./market");
7
- /**
8
- *
9
- * @param market
10
- * @param oraclePriceData
11
- * @param periodAdjustment
12
- * @returns Estimated funding rate. : Precision //TODO-PRECISION
13
- */
14
- async function calculateAllEstimatedFundingRate(market, oraclePriceData, periodAdjustment = new anchor_1.BN(1)) {
15
- // periodAdjustment
16
- // 1: hourly
17
- // 24: daily
18
- // 24 * 365.25: annualized
19
- const secondsInHour = new anchor_1.BN(3600);
20
- const hoursInDay = new anchor_1.BN(24);
21
- if (!market.initialized) {
22
- return [numericConstants_1.ZERO, numericConstants_1.ZERO, numericConstants_1.ZERO, numericConstants_1.ZERO, numericConstants_1.ZERO];
23
- }
24
- const payFreq = new anchor_1.BN(market.amm.fundingPeriod);
25
- // todo: sufficiently differs from blockchain timestamp?
26
- const now = new anchor_1.BN((Date.now() / 1000).toFixed(0));
27
- const timeSinceLastUpdate = now.sub(market.amm.lastFundingRateTs);
28
- // calculate real-time mark twap
29
- const lastMarkTwapWithMantissa = market.amm.lastMarkPriceTwap;
30
- const lastMarkPriceTwapTs = market.amm.lastMarkPriceTwapTs;
31
- const timeSinceLastMarkChange = now.sub(lastMarkPriceTwapTs);
32
- const markTwapTimeSinceLastUpdate = anchor_1.BN.max(secondsInHour, secondsInHour.sub(timeSinceLastMarkChange));
33
- const baseAssetPriceWithMantissa = (0, market_1.calculateMarkPrice)(market);
34
- const markTwapWithMantissa = markTwapTimeSinceLastUpdate
35
- .mul(lastMarkTwapWithMantissa)
36
- .add(timeSinceLastMarkChange.mul(baseAssetPriceWithMantissa))
37
- .div(timeSinceLastMarkChange.add(markTwapTimeSinceLastUpdate));
38
- // calculate real-time (predicted) oracle twap
39
- // note: oracle twap depends on `when the chord is struck` (market is trade)
40
- const lastOracleTwapWithMantissa = market.amm.lastOraclePriceTwap;
41
- const lastOraclePriceTwapTs = market.amm.lastOraclePriceTwapTs;
42
- const timeSinceLastOracleTwapUpdate = now.sub(lastOraclePriceTwapTs);
43
- const oracleTwapTimeSinceLastUpdate = anchor_1.BN.max(secondsInHour, secondsInHour.sub(timeSinceLastOracleTwapUpdate));
44
- const oraclePrice = oraclePriceData.price;
45
- let oracleTwapWithMantissa = lastOracleTwapWithMantissa;
46
- const oracleLiveVsTwap = oraclePrice
47
- .sub(lastOracleTwapWithMantissa)
48
- .abs()
49
- .mul(numericConstants_1.MARK_PRICE_PRECISION)
50
- .mul(new anchor_1.BN(100))
51
- .div(lastOracleTwapWithMantissa);
52
- // verify pyth live input is within 10% of last twap for live update
53
- if (oracleLiveVsTwap.lte(numericConstants_1.MARK_PRICE_PRECISION.mul(new anchor_1.BN(10)))) {
54
- oracleTwapWithMantissa = oracleTwapTimeSinceLastUpdate
55
- .mul(lastOracleTwapWithMantissa)
56
- .add(timeSinceLastMarkChange.mul(oraclePrice))
57
- .div(timeSinceLastOracleTwapUpdate.add(oracleTwapTimeSinceLastUpdate));
58
- }
59
- const twapSpread = lastMarkTwapWithMantissa.sub(lastOracleTwapWithMantissa);
60
- const twapSpreadPct = twapSpread
61
- .mul(numericConstants_1.MARK_PRICE_PRECISION)
62
- .mul(new anchor_1.BN(100))
63
- .div(oracleTwapWithMantissa);
64
- const lowerboundEst = twapSpreadPct
65
- .mul(payFreq)
66
- .mul(anchor_1.BN.min(secondsInHour, timeSinceLastUpdate))
67
- .mul(periodAdjustment)
68
- .div(secondsInHour)
69
- .div(secondsInHour)
70
- .div(hoursInDay);
71
- const interpEst = twapSpreadPct.mul(periodAdjustment).div(hoursInDay);
72
- const interpRateQuote = twapSpreadPct
73
- .mul(periodAdjustment)
74
- .div(hoursInDay)
75
- .div(numericConstants_1.MARK_PRICE_PRECISION.div(numericConstants_1.QUOTE_PRECISION));
76
- let feePoolSize = calculateFundingPool(market);
77
- if (interpRateQuote.lt(new anchor_1.BN(0))) {
78
- feePoolSize = feePoolSize.mul(new anchor_1.BN(-1));
79
- }
80
- let cappedAltEst;
81
- let largerSide;
82
- let smallerSide;
83
- if (market.baseAssetAmountLong.gt(market.baseAssetAmountShort.abs())) {
84
- largerSide = market.baseAssetAmountLong.abs();
85
- smallerSide = market.baseAssetAmountShort.abs();
86
- if (twapSpread.gt(new anchor_1.BN(0))) {
87
- return [
88
- markTwapWithMantissa,
89
- oracleTwapWithMantissa,
90
- lowerboundEst,
91
- interpEst,
92
- interpEst,
93
- ];
94
- }
95
- }
96
- else if (market.baseAssetAmountLong.lt(market.baseAssetAmountShort.abs())) {
97
- largerSide = market.baseAssetAmountShort.abs();
98
- smallerSide = market.baseAssetAmountLong.abs();
99
- if (twapSpread.lt(new anchor_1.BN(0))) {
100
- return [
101
- markTwapWithMantissa,
102
- oracleTwapWithMantissa,
103
- lowerboundEst,
104
- interpEst,
105
- interpEst,
106
- ];
107
- }
108
- }
109
- else {
110
- return [
111
- markTwapWithMantissa,
112
- oracleTwapWithMantissa,
113
- lowerboundEst,
114
- interpEst,
115
- interpEst,
116
- ];
117
- }
118
- if (largerSide.gt(numericConstants_1.ZERO)) {
119
- // funding smaller flow
120
- cappedAltEst = smallerSide.mul(twapSpread).div(hoursInDay);
121
- const feePoolTopOff = feePoolSize
122
- .mul(numericConstants_1.MARK_PRICE_PRECISION.div(numericConstants_1.QUOTE_PRECISION))
123
- .mul(numericConstants_1.AMM_RESERVE_PRECISION);
124
- cappedAltEst = cappedAltEst.add(feePoolTopOff).div(largerSide);
125
- cappedAltEst = cappedAltEst
126
- .mul(numericConstants_1.MARK_PRICE_PRECISION)
127
- .mul(new anchor_1.BN(100))
128
- .div(oracleTwapWithMantissa)
129
- .mul(periodAdjustment);
130
- if (cappedAltEst.abs().gte(interpEst.abs())) {
131
- cappedAltEst = interpEst;
132
- }
133
- }
134
- else {
135
- cappedAltEst = interpEst;
136
- }
137
- return [
138
- markTwapWithMantissa,
139
- oracleTwapWithMantissa,
140
- lowerboundEst,
141
- cappedAltEst,
142
- interpEst,
143
- ];
144
- }
145
- exports.calculateAllEstimatedFundingRate = calculateAllEstimatedFundingRate;
146
- /**
147
- *
148
- * @param market
149
- * @param oraclePriceData
150
- * @param periodAdjustment
151
- * @param estimationMethod
152
- * @returns Estimated funding rate. : Precision //TODO-PRECISION
153
- */
154
- async function calculateEstimatedFundingRate(market, oraclePriceData, periodAdjustment = new anchor_1.BN(1), estimationMethod) {
155
- const [_1, _2, lowerboundEst, cappedAltEst, interpEst] = await calculateAllEstimatedFundingRate(market, oraclePriceData, periodAdjustment);
156
- if (estimationMethod == 'lowerbound') {
157
- //assuming remaining funding period has no gap
158
- return lowerboundEst;
159
- }
160
- else if (estimationMethod == 'capped') {
161
- return cappedAltEst;
162
- }
163
- else {
164
- return interpEst;
165
- }
166
- }
167
- exports.calculateEstimatedFundingRate = calculateEstimatedFundingRate;
168
- /**
169
- *
170
- * @param market
171
- * @param oraclePriceData
172
- * @param periodAdjustment
173
- * @returns Estimated funding rate. : Precision //TODO-PRECISION
174
- */
175
- async function calculateLongShortFundingRate(market, oraclePriceData, periodAdjustment = new anchor_1.BN(1)) {
176
- const [_1, _2, _, cappedAltEst, interpEst] = await calculateAllEstimatedFundingRate(market, oraclePriceData, periodAdjustment);
177
- if (market.baseAssetAmountLong.gt(market.baseAssetAmountShort)) {
178
- return [cappedAltEst, interpEst];
179
- }
180
- else if (market.baseAssetAmountLong.lt(market.baseAssetAmountShort)) {
181
- return [interpEst, cappedAltEst];
182
- }
183
- else {
184
- return [interpEst, interpEst];
185
- }
186
- }
187
- exports.calculateLongShortFundingRate = calculateLongShortFundingRate;
188
- /**
189
- *
190
- * @param market
191
- * @param oraclePriceData
192
- * @param periodAdjustment
193
- * @returns Estimated funding rate. : Precision //TODO-PRECISION
194
- */
195
- async function calculateLongShortFundingRateAndLiveTwaps(market, oraclePriceData, periodAdjustment = new anchor_1.BN(1)) {
196
- const [markTwapLive, oracleTwapLive, _2, cappedAltEst, interpEst] = await calculateAllEstimatedFundingRate(market, oraclePriceData, periodAdjustment);
197
- if (market.baseAssetAmountLong.gt(market.baseAssetAmountShort.abs())) {
198
- return [markTwapLive, oracleTwapLive, cappedAltEst, interpEst];
199
- }
200
- else if (market.baseAssetAmountLong.lt(market.baseAssetAmountShort.abs())) {
201
- return [markTwapLive, oracleTwapLive, interpEst, cappedAltEst];
202
- }
203
- else {
204
- return [markTwapLive, oracleTwapLive, interpEst, interpEst];
205
- }
206
- }
207
- exports.calculateLongShortFundingRateAndLiveTwaps = calculateLongShortFundingRateAndLiveTwaps;
208
- /**
209
- *
210
- * @param market
211
- * @returns Estimated fee pool size
212
- */
213
- function calculateFundingPool(market) {
214
- // todo
215
- const totalFeeLB = market.amm.totalFee.div(new anchor_1.BN(2));
216
- const feePool = anchor_1.BN.max(numericConstants_1.ZERO, market.amm.totalFeeMinusDistributions
217
- .sub(totalFeeLB)
218
- .mul(new anchor_1.BN(2))
219
- .div(new anchor_1.BN(3)));
220
- return feePool;
221
- }
222
- exports.calculateFundingPool = calculateFundingPool;
223
- //# sourceMappingURL=funding.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"funding.js","sourceRoot":"","sources":["funding.ts"],"names":[],"mappings":"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"}