@drift-labs/sdk 0.1.18-master.0 → 0.1.18-orders.1

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 (108) hide show
  1. package/lib/accounts/defaultClearingHouseAccountSubscriber.d.ts +7 -4
  2. package/lib/accounts/defaultClearingHouseAccountSubscriber.js +27 -2
  3. package/lib/accounts/defaultHistoryAccountSubscriber.d.ts +28 -0
  4. package/lib/accounts/defaultHistoryAccountSubscriber.js +110 -0
  5. package/lib/accounts/defaultUserAccountSubscriber.d.ts +3 -2
  6. package/lib/accounts/defaultUserAccountSubscriber.js +12 -1
  7. package/lib/accounts/types.d.ts +31 -5
  8. package/lib/accounts/webSocketAccountSubscriber.d.ts +0 -1
  9. package/lib/addresses.d.ts +4 -1
  10. package/lib/addresses.js +28 -1
  11. package/lib/admin.d.ts +10 -5
  12. package/lib/admin.js +53 -30
  13. package/lib/assert/assert.d.ts +0 -1
  14. package/lib/clearingHouse.d.ts +22 -3
  15. package/lib/clearingHouse.js +246 -15
  16. package/lib/clearingHouseUser.d.ts +10 -17
  17. package/lib/clearingHouseUser.js +111 -97
  18. package/lib/config.d.ts +0 -1
  19. package/lib/config.js +1 -1
  20. package/lib/constants/markets.d.ts +0 -1
  21. package/lib/constants/numericConstants.d.ts +0 -1
  22. package/lib/examples/makeTradeExample.d.ts +0 -1
  23. package/lib/examples/makeTradeExample.js +6 -6
  24. package/lib/idl/clearing_house.json +895 -132
  25. package/lib/index.d.ts +4 -1
  26. package/lib/index.js +4 -0
  27. package/lib/math/amm.d.ts +1 -1
  28. package/lib/math/amm.js +38 -15
  29. package/lib/math/conversion.d.ts +0 -1
  30. package/lib/math/conversion.js +1 -1
  31. package/lib/math/funding.d.ts +0 -1
  32. package/lib/math/funding.js +1 -1
  33. package/lib/math/insuranceFund.d.ts +0 -1
  34. package/lib/math/market.d.ts +2 -2
  35. package/lib/math/market.js +12 -2
  36. package/lib/math/orders.d.ts +3 -0
  37. package/lib/math/orders.js +30 -0
  38. package/lib/math/position.d.ts +4 -2
  39. package/lib/math/position.js +19 -5
  40. package/lib/math/trade.d.ts +0 -1
  41. package/lib/math/trade.js +16 -16
  42. package/lib/math/utils.d.ts +0 -1
  43. package/lib/mockUSDCFaucet.d.ts +0 -1
  44. package/lib/orderParams.d.ts +7 -0
  45. package/lib/orderParams.js +88 -0
  46. package/lib/orders.d.ts +5 -0
  47. package/lib/orders.js +136 -0
  48. package/lib/pythClient.d.ts +0 -1
  49. package/lib/pythClient.js +1 -1
  50. package/lib/tx/defaultTxSender.d.ts +0 -1
  51. package/lib/tx/types.d.ts +0 -1
  52. package/lib/tx/utils.d.ts +0 -1
  53. package/lib/types.d.ts +140 -7
  54. package/lib/types.js +36 -1
  55. package/lib/util/computeUnits.d.ts +0 -1
  56. package/lib/util/tps.d.ts +0 -1
  57. package/lib/wallet.d.ts +0 -1
  58. package/package.json +1 -1
  59. package/src/accounts/defaultClearingHouseAccountSubscriber.ts +52 -5
  60. package/src/accounts/defaultHistoryAccountSubscriber.ts +176 -0
  61. package/src/accounts/defaultUserAccountSubscriber.ts +29 -2
  62. package/src/accounts/types.ts +41 -4
  63. package/src/addresses.ts +35 -0
  64. package/src/admin.ts +86 -33
  65. package/src/clearingHouse.ts +340 -7
  66. package/src/clearingHouseUser.ts +154 -102
  67. package/src/config.ts +1 -1
  68. package/src/idl/clearing_house.json +895 -132
  69. package/src/index.ts +4 -0
  70. package/src/math/amm.ts +47 -14
  71. package/src/math/market.ts +28 -2
  72. package/src/math/orders.ts +39 -0
  73. package/src/math/position.ts +23 -3
  74. package/src/orderParams.ts +128 -0
  75. package/src/orders.ts +230 -0
  76. package/src/types.ts +124 -6
  77. package/tsconfig.json +0 -1
  78. package/lib/accounts/defaultClearingHouseAccountSubscriber.d.ts.map +0 -1
  79. package/lib/accounts/defaultUserAccountSubscriber.d.ts.map +0 -1
  80. package/lib/accounts/types.d.ts.map +0 -1
  81. package/lib/accounts/webSocketAccountSubscriber.d.ts.map +0 -1
  82. package/lib/addresses.d.ts.map +0 -1
  83. package/lib/admin.d.ts.map +0 -1
  84. package/lib/assert/assert.d.ts.map +0 -1
  85. package/lib/clearingHouse.d.ts.map +0 -1
  86. package/lib/clearingHouseUser.d.ts.map +0 -1
  87. package/lib/config.d.ts.map +0 -1
  88. package/lib/constants/markets.d.ts.map +0 -1
  89. package/lib/constants/numericConstants.d.ts.map +0 -1
  90. package/lib/examples/makeTradeExample.d.ts.map +0 -1
  91. package/lib/index.d.ts.map +0 -1
  92. package/lib/math/amm.d.ts.map +0 -1
  93. package/lib/math/conversion.d.ts.map +0 -1
  94. package/lib/math/funding.d.ts.map +0 -1
  95. package/lib/math/insuranceFund.d.ts.map +0 -1
  96. package/lib/math/market.d.ts.map +0 -1
  97. package/lib/math/position.d.ts.map +0 -1
  98. package/lib/math/trade.d.ts.map +0 -1
  99. package/lib/math/utils.d.ts.map +0 -1
  100. package/lib/mockUSDCFaucet.d.ts.map +0 -1
  101. package/lib/pythClient.d.ts.map +0 -1
  102. package/lib/tx/defaultTxSender.d.ts.map +0 -1
  103. package/lib/tx/types.d.ts.map +0 -1
  104. package/lib/tx/utils.d.ts.map +0 -1
  105. package/lib/types.d.ts.map +0 -1
  106. package/lib/util/computeUnits.d.ts.map +0 -1
  107. package/lib/util/tps.d.ts.map +0 -1
  108. package/lib/wallet.d.ts.map +0 -1
@@ -3,8 +3,14 @@ import BN from 'bn.js';
3
3
  import { EventEmitter } from 'events';
4
4
  import StrictEventEmitter from 'strict-event-emitter-types';
5
5
  import { ClearingHouse } from './clearingHouse';
6
- import { UserAccount, UserPosition, UserPositionsAccount } from './types';
7
- import { calculateEntryPrice } from './math/position';
6
+ import {
7
+ Order,
8
+ UserAccount,
9
+ UserOrdersAccount,
10
+ UserPosition,
11
+ UserPositionsAccount,
12
+ } from './types';
13
+ import { calculateEntryPrice, isEmptyPosition } from './math/position';
8
14
  import {
9
15
  MARK_PRICE_PRECISION,
10
16
  AMM_TO_QUOTE_PRECISION_RATIO,
@@ -25,6 +31,8 @@ import {
25
31
  calculatePositionFundingPNL,
26
32
  calculatePositionPNL,
27
33
  PositionDirection,
34
+ getUserOrdersAccountPublicKey,
35
+ calculateNewStateAfterOrder,
28
36
  calculateTradeSlippage,
29
37
  } from '.';
30
38
  import { getUserAccountPublicKey } from './addresses';
@@ -34,6 +42,7 @@ export class ClearingHouseUser {
34
42
  authority: PublicKey;
35
43
  accountSubscriber: UserAccountSubscriber;
36
44
  userAccountPublicKey?: PublicKey;
45
+ userOrdersAccountPublicKey?: PublicKey;
37
46
  isSubscribed = false;
38
47
  eventEmitter: StrictEventEmitter<EventEmitter, UserAccountEvents>;
39
48
 
@@ -91,6 +100,10 @@ export class ClearingHouseUser {
91
100
  return this.accountSubscriber.getUserPositionsAccount();
92
101
  }
93
102
 
103
+ public getUserOrdersAccount(): UserOrdersAccount {
104
+ return this.accountSubscriber.getUserOrdersAccount();
105
+ }
106
+
94
107
  /**
95
108
  * Gets the user's current position for a given market. If the user has no position returns undefined
96
109
  * @param marketIndex
@@ -108,9 +121,20 @@ export class ClearingHouseUser {
108
121
  lastCumulativeFundingRate: ZERO,
109
122
  marketIndex,
110
123
  quoteAssetAmount: ZERO,
124
+ openOrders: ZERO,
111
125
  };
112
126
  }
113
127
 
128
+ /**
129
+ * @param orderId
130
+ * @returns Order
131
+ */
132
+ public getOrder(orderId: BN): Order | undefined {
133
+ return this.getUserOrdersAccount().orders.find((order) =>
134
+ order.orderId.eq(orderId)
135
+ );
136
+ }
137
+
114
138
  public async getUserAccountPublicKey(): Promise<PublicKey> {
115
139
  if (this.userAccountPublicKey) {
116
140
  return this.userAccountPublicKey;
@@ -123,6 +147,18 @@ export class ClearingHouseUser {
123
147
  return this.userAccountPublicKey;
124
148
  }
125
149
 
150
+ public async getUserOrdersAccountPublicKey(): Promise<PublicKey> {
151
+ if (this.userOrdersAccountPublicKey) {
152
+ return this.userOrdersAccountPublicKey;
153
+ }
154
+
155
+ this.userOrdersAccountPublicKey = await getUserOrdersAccountPublicKey(
156
+ this.clearingHouse.program.programId,
157
+ this.authority
158
+ );
159
+ return this.userOrdersAccountPublicKey;
160
+ }
161
+
126
162
  public async exists(): Promise<boolean> {
127
163
  const userAccountPublicKey = await this.getUserAccountPublicKey();
128
164
  const userAccountRPCResponse =
@@ -418,6 +454,7 @@ export class ClearingHouseUser {
418
454
  ),
419
455
  lastCumulativeFundingRate: new BN(0),
420
456
  quoteAssetAmount: new BN(0),
457
+ openOrders: new BN(0),
421
458
  };
422
459
 
423
460
  const market = this.clearingHouse.getMarket(
@@ -508,14 +545,14 @@ export class ClearingHouseUser {
508
545
  // solves formula for example calc below
509
546
 
510
547
  /* example: assume BTC price is $40k (examine 10% up/down)
511
-
512
- if 10k deposit and levered 10x short BTC => BTC up $400 means:
513
- 1. higher base_asset_value (+$4k)
514
- 2. lower collateral (-$4k)
515
- 3. (10k - 4k)/(100k + 4k) => 6k/104k => .0576
516
-
517
- for 10x long, BTC down $400:
518
- 3. (10k - 4k) / (100k - 4k) = 6k/96k => .0625 */
548
+
549
+ if 10k deposit and levered 10x short BTC => BTC up $400 means:
550
+ 1. higher base_asset_value (+$4k)
551
+ 2. lower collateral (-$4k)
552
+ 3. (10k - 4k)/(100k + 4k) => 6k/104k => .0576
553
+
554
+ for 10x long, BTC down $400:
555
+ 3. (10k - 4k) / (100k - 4k) = 6k/96k => .0625 */
519
556
 
520
557
  const tc = this.getTotalCollateral();
521
558
  const tpv = this.getTotalPositionValue();
@@ -546,6 +583,7 @@ export class ClearingHouseUser {
546
583
  lastCumulativeFundingRate:
547
584
  currentMarketPosition.lastCumulativeFundingRate,
548
585
  quoteAssetAmount: new BN(0),
586
+ openOrders: new BN(0),
549
587
  };
550
588
 
551
589
  const market = this.clearingHouse.getMarket(
@@ -665,21 +703,6 @@ export class ClearingHouseUser {
665
703
 
666
704
  /**
667
705
  * Get the maximum trade size for a given market, taking into account the user's current leverage, positions, collateral, etc.
668
- *
669
- * To Calculate Max Quote Available:
670
- *
671
- * Case 1: SameSide
672
- * => Remaining quote to get to maxLeverage
673
- *
674
- * Case 2: NOT SameSide && currentLeverage <= maxLeverage
675
- * => Current opposite position x2 + remaining to get to maxLeverage
676
- *
677
- * Case 3: NOT SameSide && currentLeverage > maxLeverage && otherPositions - currentPosition > maxLeverage
678
- * => strictly reduce current position size
679
- *
680
- * Case 4: NOT SameSide && currentLeverage > maxLeverage && otherPositions - currentPosition < maxLeverage
681
- * => current position + remaining to get to maxLeverage
682
- *
683
706
  * @param marketIndex
684
707
  * @param tradeSide
685
708
  * @param userMaxLeverageSetting - leverage : Precision TEN_THOUSAND
@@ -690,28 +713,34 @@ export class ClearingHouseUser {
690
713
  tradeSide: PositionDirection,
691
714
  userMaxLeverageSetting: BN
692
715
  ): BN {
693
- const currentPosition =
694
- this.getUserPosition(targetMarketIndex) ||
695
- this.getEmptyPosition(targetMarketIndex);
716
+ // inline function which get's the current position size on the opposite side of the target trade
717
+ const getOppositePositionValueUSDC = () => {
718
+ if (!currentPosition) return ZERO;
696
719
 
697
- const targetSide = tradeSide === PositionDirection.SHORT ? 'short' : 'long';
720
+ const side = tradeSide === PositionDirection.SHORT ? 'short' : 'long';
698
721
 
699
- const currentPositionSide = currentPosition?.baseAssetAmount.isNeg()
700
- ? 'short'
701
- : 'long';
722
+ if (side === 'long' && currentPosition?.baseAssetAmount.isNeg()) {
723
+ return this.getPositionValue(targetMarketIndex);
724
+ } else if (
725
+ side === 'short' &&
726
+ !currentPosition?.baseAssetAmount.isNeg()
727
+ ) {
728
+ return this.getPositionValue(targetMarketIndex);
729
+ }
702
730
 
703
- const targettingSameSide = !currentPosition
704
- ? true
705
- : targetSide === currentPositionSide;
731
+ return ZERO;
732
+ };
706
733
 
707
- // add any position we have on the opposite side of the current trade, because we can "flip" the size of this position without taking any extra leverage.
708
- const oppositeSizeValueUSDC = targettingSameSide
709
- ? ZERO
710
- : this.getPositionValue(targetMarketIndex);
734
+ const currentPosition =
735
+ this.getUserPosition(targetMarketIndex) ||
736
+ this.getEmptyPosition(targetMarketIndex);
711
737
 
712
738
  // get current leverage
713
739
  const currentLeverage = this.getLeverage();
714
740
 
741
+ // remaining leverage
742
+ // let remainingLeverage = userMaxLeverageSetting;
743
+
715
744
  const remainingLeverage = BN.max(
716
745
  userMaxLeverageSetting.sub(currentLeverage),
717
746
  ZERO
@@ -725,57 +754,10 @@ export class ClearingHouseUser {
725
754
  .mul(totalCollateral)
726
755
  .div(TEN_THOUSAND);
727
756
 
728
- if (userMaxLeverageSetting.sub(currentLeverage).gte(ZERO)) {
729
- if (oppositeSizeValueUSDC.eq(ZERO)) {
730
- // case 1 : Regular trade where current total position less than max, and no opposite position to account for
731
- // do nothing
732
- } else {
733
- // case 2 : trade where current total position less than max, but need to account for flipping the current position over to the other side
734
- maxPositionSize = maxPositionSize.add(
735
- oppositeSizeValueUSDC.mul(new BN(2))
736
- );
737
- }
738
- } else {
739
- // current leverage is greater than max leverage - can only reduce position size
740
-
741
- if (!targettingSameSide) {
742
- const currentPositionQuoteSize =
743
- this.getPositionValue(targetMarketIndex);
744
-
745
- const currentTotalQuoteSize = currentLeverage
746
- .mul(totalCollateral)
747
- .div(TEN_THOUSAND);
748
-
749
- const otherPositionsTotalQuoteSize = currentTotalQuoteSize.sub(
750
- currentPositionQuoteSize
751
- );
752
-
753
- const quoteValueOfMaxLeverage = userMaxLeverageSetting
754
- .mul(totalCollateral)
755
- .div(TEN_THOUSAND);
756
-
757
- if (
758
- otherPositionsTotalQuoteSize
759
- .sub(currentPositionQuoteSize)
760
- .gte(quoteValueOfMaxLeverage)
761
- ) {
762
- // case 3: Can only reduce the current position because it will still be greater than max leverage
763
-
764
- maxPositionSize = currentPositionQuoteSize;
765
- } else {
766
- // case 4: Can reduce the position, and then take extra remaining quote to get to max leverage
757
+ // add any position we have on the opposite side of the current trade, because we can "flip" the size of this position without taking any extra leverage.
758
+ const oppositeSizeValueUSDC = getOppositePositionValueUSDC();
767
759
 
768
- const allowedQuoteSizeAfterClosingCurrentPosition =
769
- quoteValueOfMaxLeverage.sub(otherPositionsTotalQuoteSize);
770
-
771
- maxPositionSize = currentPositionQuoteSize.add(
772
- allowedQuoteSizeAfterClosingCurrentPosition
773
- );
774
- }
775
- } else {
776
- // do nothing if targetting same side
777
- }
778
- }
760
+ maxPositionSize = maxPositionSize.add(oppositeSizeValueUSDC.mul(new BN(2)));
779
761
 
780
762
  // subtract oneMillionth of maxPositionSize
781
763
  // => to avoid rounding errors when taking max leverage
@@ -820,19 +802,13 @@ export class ClearingHouseUser {
820
802
 
821
803
  const totalPositionAfterTradeExcludingTargetMarket =
822
804
  this.getTotalPositionValueExcludingMarket(targetMarketIndex);
805
+ const newLeverage = currentMarketPositionAfterTrade
806
+ .add(totalPositionAfterTradeExcludingTargetMarket)
807
+ .abs()
808
+ .mul(TEN_THOUSAND)
809
+ .div(this.getTotalCollateral());
823
810
 
824
- const totalCollateral = this.getTotalCollateral();
825
-
826
- if (totalCollateral.gt(ZERO)) {
827
- const newLeverage = currentMarketPositionAfterTrade
828
- .add(totalPositionAfterTradeExcludingTargetMarket)
829
- .abs()
830
- .mul(TEN_THOUSAND)
831
- .div(totalCollateral);
832
- return newLeverage;
833
- } else {
834
- return new BN(0);
835
- }
811
+ return newLeverage;
836
812
  }
837
813
 
838
814
  /**
@@ -860,9 +836,85 @@ export class ClearingHouseUser {
860
836
 
861
837
  let currentMarketPositionValueUSDC = ZERO;
862
838
  if (currentMarketPosition) {
863
- currentMarketPositionValueUSDC = this.getPositionValue(marketToIgnore);
839
+ const market = this.clearingHouse.getMarket(
840
+ currentMarketPosition.marketIndex
841
+ );
842
+ currentMarketPositionValueUSDC = calculateBaseAssetValue(
843
+ market,
844
+ currentMarketPosition
845
+ );
864
846
  }
865
847
 
866
848
  return this.getTotalPositionValue().sub(currentMarketPositionValueUSDC);
867
849
  }
850
+
851
+ public canFillOrder(order: Order): boolean {
852
+ const userAccount = this.getUserAccount();
853
+ const userPositionsAccount = this.getUserPositionsAccount();
854
+ const userPosition = this.getUserPosition(order.marketIndex);
855
+ const market = this.clearingHouse.getMarket(order.marketIndex);
856
+
857
+ if (isEmptyPosition(userPosition)) {
858
+ return false;
859
+ }
860
+
861
+ const newState = calculateNewStateAfterOrder(
862
+ userAccount,
863
+ userPosition,
864
+ market,
865
+ order
866
+ );
867
+ if (newState === null) {
868
+ return false;
869
+ }
870
+ const [userAccountAfter, userPositionAfter, marketAfter] = newState;
871
+
872
+ const totalPositionValue = userPositionsAccount.positions.reduce(
873
+ (positionValue, marketPosition) => {
874
+ let market = this.clearingHouse.getMarket(marketPosition.marketIndex);
875
+ if (marketPosition.marketIndex.eq(order.marketIndex)) {
876
+ market = marketAfter;
877
+ marketPosition = userPositionAfter;
878
+ }
879
+
880
+ return positionValue.add(
881
+ calculateBaseAssetValue(market, marketPosition)
882
+ );
883
+ },
884
+ ZERO
885
+ );
886
+
887
+ if (totalPositionValue.eq(ZERO)) {
888
+ return true;
889
+ }
890
+
891
+ const unrealizedPnL = userPositionsAccount.positions.reduce(
892
+ (pnl, marketPosition) => {
893
+ let market = this.clearingHouse.getMarket(marketPosition.marketIndex);
894
+ pnl = pnl.add(
895
+ calculatePositionFundingPNL(market, marketPosition).div(
896
+ PRICE_TO_QUOTE_PRECISION
897
+ )
898
+ );
899
+
900
+ if (marketPosition.marketIndex.eq(order.marketIndex)) {
901
+ market = marketAfter;
902
+ marketPosition = userPositionAfter;
903
+ }
904
+
905
+ // update
906
+ return pnl.add(calculatePositionPNL(market, marketPosition, false));
907
+ },
908
+ ZERO
909
+ );
910
+ const totalCollateral = userAccountAfter.collateral.add(unrealizedPnL);
911
+
912
+ const marginRatioAfter = totalCollateral
913
+ .mul(TEN_THOUSAND)
914
+ .div(totalPositionValue);
915
+
916
+ const marginRatioInitial =
917
+ this.clearingHouse.getStateAccount().marginRatioInitial;
918
+ return marginRatioAfter.gte(marginRatioInitial);
919
+ }
868
920
  }
package/src/config.ts CHANGED
@@ -11,7 +11,7 @@ export const configs: { [key in DriftEnv]: DriftConfig } = {
11
11
  devnet: {
12
12
  ENV: 'devnet',
13
13
  PYTH_ORACLE_MAPPING_ADDRESS: 'BmA9Z6FjioHJPpjT39QazZyhDRUdZy2ezwx4GiDdE2u2',
14
- CLEARING_HOUSE_PROGRAM_ID: 'AsW7LnXB9UA1uec9wi9MctYTgTz7YH9snhxd16GsFaGX',
14
+ CLEARING_HOUSE_PROGRAM_ID: 'HiZ8CnfEE9LrBZTfc8hBneWrPg1Cbsn8Wdy6SPLfae9V',
15
15
  USDC_MINT_ADDRESS: '8zGuJQqwhZafTah7Uc7Z4tXRnguqkn5KLFAP8oV6PHe2',
16
16
  },
17
17
  'mainnet-beta': {