@drift-labs/sdk 0.1.18-master.7 → 0.1.18-orders.2

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 (136) hide show
  1. package/lib/accounts/bulkAccountLoader.d.ts +32 -0
  2. package/lib/accounts/bulkAccountLoader.js +156 -0
  3. package/lib/accounts/bulkUserSubscription.d.ts +7 -0
  4. package/lib/accounts/bulkUserSubscription.js +28 -0
  5. package/lib/accounts/pollingClearingHouseAccountSubscriber.d.ts +49 -0
  6. package/lib/accounts/pollingClearingHouseAccountSubscriber.js +228 -0
  7. package/lib/accounts/pollingTokenAccountSubscriber.d.ts +25 -0
  8. package/lib/accounts/pollingTokenAccountSubscriber.js +79 -0
  9. package/lib/accounts/pollingUserAccountSubscriber.d.ts +32 -0
  10. package/lib/accounts/pollingUserAccountSubscriber.js +133 -0
  11. package/lib/accounts/types.d.ts +34 -3
  12. package/lib/accounts/utils.d.ts +1 -0
  13. package/lib/accounts/utils.js +7 -0
  14. package/lib/accounts/webSocketAccountSubscriber.d.ts +0 -1
  15. package/lib/accounts/{defaultClearingHouseAccountSubscriber.d.ts → webSocketClearingHouseAccountSubscriber.d.ts} +8 -3
  16. package/lib/accounts/{defaultClearingHouseAccountSubscriber.js → webSocketClearingHouseAccountSubscriber.js} +30 -4
  17. package/lib/accounts/{defaultUserAccountSubscriber.d.ts → webSocketUserAccountSubscriber.d.ts} +6 -3
  18. package/lib/accounts/{defaultUserAccountSubscriber.js → webSocketUserAccountSubscriber.js} +16 -4
  19. package/lib/addresses.d.ts +4 -1
  20. package/lib/addresses.js +28 -1
  21. package/lib/admin.d.ts +11 -4
  22. package/lib/admin.js +71 -17
  23. package/lib/assert/assert.d.ts +0 -1
  24. package/lib/clearingHouse.d.ts +35 -4
  25. package/lib/clearingHouse.js +294 -23
  26. package/lib/clearingHouseUser.d.ts +19 -18
  27. package/lib/clearingHouseUser.js +129 -101
  28. package/lib/config.d.ts +0 -1
  29. package/lib/config.js +1 -1
  30. package/lib/constants/markets.d.ts +0 -1
  31. package/lib/constants/markets.js +13 -5
  32. package/lib/constants/numericConstants.d.ts +0 -1
  33. package/lib/examples/makeTradeExample.d.ts +0 -1
  34. package/lib/examples/makeTradeExample.js +6 -6
  35. package/lib/factory/clearingHouse.d.ts +25 -0
  36. package/lib/factory/clearingHouse.js +64 -0
  37. package/lib/factory/clearingHouseUser.d.ts +19 -0
  38. package/lib/factory/clearingHouseUser.js +34 -0
  39. package/lib/idl/clearing_house.json +1077 -54
  40. package/lib/index.d.ts +12 -4
  41. package/lib/index.js +17 -4
  42. package/lib/math/amm.d.ts +1 -1
  43. package/lib/math/amm.js +38 -15
  44. package/lib/math/conversion.d.ts +0 -1
  45. package/lib/math/conversion.js +1 -1
  46. package/lib/math/funding.d.ts +0 -1
  47. package/lib/math/funding.js +1 -1
  48. package/lib/math/insuranceFund.d.ts +0 -1
  49. package/lib/math/market.d.ts +2 -2
  50. package/lib/math/market.js +12 -2
  51. package/lib/math/orders.d.ts +3 -0
  52. package/lib/math/orders.js +30 -0
  53. package/lib/math/position.d.ts +4 -2
  54. package/lib/math/position.js +19 -5
  55. package/lib/math/trade.d.ts +0 -1
  56. package/lib/math/trade.js +16 -16
  57. package/lib/math/utils.d.ts +2 -3
  58. package/lib/math/utils.js +6 -3
  59. package/lib/mockUSDCFaucet.d.ts +0 -1
  60. package/lib/orderParams.d.ts +7 -0
  61. package/lib/orderParams.js +108 -0
  62. package/lib/orders.d.ts +5 -0
  63. package/lib/orders.js +136 -0
  64. package/lib/pythClient.d.ts +0 -1
  65. package/lib/pythClient.js +1 -1
  66. package/lib/token/index.d.ts +3 -0
  67. package/lib/token/index.js +38 -0
  68. package/lib/tx/defaultTxSender.d.ts +0 -1
  69. package/lib/tx/types.d.ts +0 -1
  70. package/lib/tx/utils.d.ts +0 -1
  71. package/lib/types.d.ts +144 -2
  72. package/lib/types.js +36 -1
  73. package/lib/util/computeUnits.d.ts +0 -1
  74. package/lib/util/tps.d.ts +0 -1
  75. package/lib/wallet.d.ts +0 -1
  76. package/package.json +3 -3
  77. package/src/accounts/bulkAccountLoader.ts +195 -0
  78. package/src/accounts/bulkUserSubscription.ts +28 -0
  79. package/src/accounts/pollingClearingHouseAccountSubscriber.ts +326 -0
  80. package/src/accounts/pollingTokenAccountSubscriber.ts +99 -0
  81. package/src/accounts/pollingUserAccountSubscriber.ts +186 -0
  82. package/src/accounts/types.ts +43 -1
  83. package/src/accounts/utils.ts +3 -0
  84. package/src/accounts/{defaultClearingHouseAccountSubscriber.ts → webSocketClearingHouseAccountSubscriber.ts} +51 -1
  85. package/src/accounts/{defaultUserAccountSubscriber.ts → webSocketUserAccountSubscriber.ts} +33 -3
  86. package/src/addresses.ts +37 -0
  87. package/src/admin.ts +111 -24
  88. package/src/clearingHouse.ts +399 -22
  89. package/src/clearingHouseUser.ts +179 -107
  90. package/src/config.ts +1 -1
  91. package/src/constants/markets.ts +13 -5
  92. package/src/factory/clearingHouse.ts +125 -0
  93. package/src/factory/clearingHouseUser.ts +73 -0
  94. package/src/idl/clearing_house.json +1077 -54
  95. package/src/index.ts +12 -3
  96. package/src/math/amm.ts +47 -14
  97. package/src/math/market.ts +28 -2
  98. package/src/math/orders.ts +39 -0
  99. package/src/math/position.ts +23 -3
  100. package/src/math/utils.ts +1 -1
  101. package/src/orderParams.ts +151 -0
  102. package/src/orders.ts +230 -0
  103. package/src/token/index.ts +37 -0
  104. package/src/types.ts +128 -1
  105. package/tsconfig.json +0 -1
  106. package/lib/accounts/defaultClearingHouseAccountSubscriber.d.ts.map +0 -1
  107. package/lib/accounts/defaultUserAccountSubscriber.d.ts.map +0 -1
  108. package/lib/accounts/types.d.ts.map +0 -1
  109. package/lib/accounts/webSocketAccountSubscriber.d.ts.map +0 -1
  110. package/lib/addresses.d.ts.map +0 -1
  111. package/lib/admin.d.ts.map +0 -1
  112. package/lib/assert/assert.d.ts.map +0 -1
  113. package/lib/clearingHouse.d.ts.map +0 -1
  114. package/lib/clearingHouseUser.d.ts.map +0 -1
  115. package/lib/config.d.ts.map +0 -1
  116. package/lib/constants/markets.d.ts.map +0 -1
  117. package/lib/constants/numericConstants.d.ts.map +0 -1
  118. package/lib/examples/makeTradeExample.d.ts.map +0 -1
  119. package/lib/index.d.ts.map +0 -1
  120. package/lib/math/amm.d.ts.map +0 -1
  121. package/lib/math/conversion.d.ts.map +0 -1
  122. package/lib/math/funding.d.ts.map +0 -1
  123. package/lib/math/insuranceFund.d.ts.map +0 -1
  124. package/lib/math/market.d.ts.map +0 -1
  125. package/lib/math/position.d.ts.map +0 -1
  126. package/lib/math/trade.d.ts.map +0 -1
  127. package/lib/math/utils.d.ts.map +0 -1
  128. package/lib/mockUSDCFaucet.d.ts.map +0 -1
  129. package/lib/pythClient.d.ts.map +0 -1
  130. package/lib/tx/defaultTxSender.d.ts.map +0 -1
  131. package/lib/tx/types.d.ts.map +0 -1
  132. package/lib/tx/utils.d.ts.map +0 -1
  133. package/lib/types.d.ts.map +0 -1
  134. package/lib/util/computeUnits.d.ts.map +0 -1
  135. package/lib/util/tps.d.ts.map +0 -1
  136. 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,
@@ -18,34 +24,57 @@ import {
18
24
  PRICE_TO_QUOTE_PRECISION,
19
25
  } from './constants/numericConstants';
20
26
  import { UserAccountSubscriber, UserAccountEvents } from './accounts/types';
21
- import { DefaultUserAccountSubscriber } from './accounts/defaultUserAccountSubscriber';
22
27
  import {
23
28
  calculateMarkPrice,
24
29
  calculateBaseAssetValue,
25
30
  calculatePositionFundingPNL,
26
31
  calculatePositionPNL,
27
32
  PositionDirection,
33
+ getUserOrdersAccountPublicKey,
34
+ calculateNewStateAfterOrder,
28
35
  calculateTradeSlippage,
29
36
  } from '.';
30
37
  import { getUserAccountPublicKey } from './addresses';
38
+ import {
39
+ getClearingHouseUser,
40
+ getWebSocketClearingHouseUserConfig,
41
+ } from './factory/clearingHouseUser';
31
42
 
32
43
  export class ClearingHouseUser {
33
44
  clearingHouse: ClearingHouse;
34
45
  authority: PublicKey;
35
46
  accountSubscriber: UserAccountSubscriber;
36
47
  userAccountPublicKey?: PublicKey;
37
- isSubscribed = false;
48
+ userOrdersAccountPublicKey?: PublicKey;
49
+ _isSubscribed = false;
38
50
  eventEmitter: StrictEventEmitter<EventEmitter, UserAccountEvents>;
39
51
 
52
+ public get isSubscribed() {
53
+ return this._isSubscribed && this.accountSubscriber.isSubscribed;
54
+ }
55
+
56
+ public set isSubscribed(val: boolean) {
57
+ this._isSubscribed = val;
58
+ }
59
+
60
+ /**
61
+ * @deprecated You should use getClearingHouseUser factory method instead
62
+ * @param clearingHouse
63
+ * @param authority
64
+ * @returns
65
+ */
40
66
  public static from(
41
67
  clearingHouse: ClearingHouse,
42
68
  authority: PublicKey
43
69
  ): ClearingHouseUser {
44
- const accountSubscriber = new DefaultUserAccountSubscriber(
45
- clearingHouse.program,
70
+ if (clearingHouse.accountSubscriber.type !== 'websocket')
71
+ throw 'This method only works for clearing houses with a websocket account listener. Try using the getClearingHouseUser factory method to initialize a ClearingHouseUser instead';
72
+
73
+ const config = getWebSocketClearingHouseUserConfig(
74
+ clearingHouse,
46
75
  authority
47
76
  );
48
- return new ClearingHouseUser(clearingHouse, authority, accountSubscriber);
77
+ return getClearingHouseUser(config);
49
78
  }
50
79
 
51
80
  public constructor(
@@ -91,6 +120,10 @@ export class ClearingHouseUser {
91
120
  return this.accountSubscriber.getUserPositionsAccount();
92
121
  }
93
122
 
123
+ public getUserOrdersAccount(): UserOrdersAccount {
124
+ return this.accountSubscriber.getUserOrdersAccount();
125
+ }
126
+
94
127
  /**
95
128
  * Gets the user's current position for a given market. If the user has no position returns undefined
96
129
  * @param marketIndex
@@ -108,9 +141,20 @@ export class ClearingHouseUser {
108
141
  lastCumulativeFundingRate: ZERO,
109
142
  marketIndex,
110
143
  quoteAssetAmount: ZERO,
144
+ openOrders: ZERO,
111
145
  };
112
146
  }
113
147
 
148
+ /**
149
+ * @param orderId
150
+ * @returns Order
151
+ */
152
+ public getOrder(orderId: BN): Order | undefined {
153
+ return this.getUserOrdersAccount().orders.find((order) =>
154
+ order.orderId.eq(orderId)
155
+ );
156
+ }
157
+
114
158
  public async getUserAccountPublicKey(): Promise<PublicKey> {
115
159
  if (this.userAccountPublicKey) {
116
160
  return this.userAccountPublicKey;
@@ -123,6 +167,18 @@ export class ClearingHouseUser {
123
167
  return this.userAccountPublicKey;
124
168
  }
125
169
 
170
+ public async getUserOrdersAccountPublicKey(): Promise<PublicKey> {
171
+ if (this.userOrdersAccountPublicKey) {
172
+ return this.userOrdersAccountPublicKey;
173
+ }
174
+
175
+ this.userOrdersAccountPublicKey = await getUserOrdersAccountPublicKey(
176
+ this.clearingHouse.program.programId,
177
+ await this.getUserAccountPublicKey()
178
+ );
179
+ return this.userOrdersAccountPublicKey;
180
+ }
181
+
126
182
  public async exists(): Promise<boolean> {
127
183
  const userAccountPublicKey = await this.getUserAccountPublicKey();
128
184
  const userAccountRPCResponse =
@@ -418,6 +474,7 @@ export class ClearingHouseUser {
418
474
  ),
419
475
  lastCumulativeFundingRate: new BN(0),
420
476
  quoteAssetAmount: new BN(0),
477
+ openOrders: new BN(0),
421
478
  };
422
479
 
423
480
  const market = this.clearingHouse.getMarket(
@@ -508,14 +565,14 @@ export class ClearingHouseUser {
508
565
  // solves formula for example calc below
509
566
 
510
567
  /* 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 */
568
+
569
+ if 10k deposit and levered 10x short BTC => BTC up $400 means:
570
+ 1. higher base_asset_value (+$4k)
571
+ 2. lower collateral (-$4k)
572
+ 3. (10k - 4k)/(100k + 4k) => 6k/104k => .0576
573
+
574
+ for 10x long, BTC down $400:
575
+ 3. (10k - 4k) / (100k - 4k) = 6k/96k => .0625 */
519
576
 
520
577
  const tc = this.getTotalCollateral();
521
578
  const tpv = this.getTotalPositionValue();
@@ -546,6 +603,7 @@ export class ClearingHouseUser {
546
603
  lastCumulativeFundingRate:
547
604
  currentMarketPosition.lastCumulativeFundingRate,
548
605
  quoteAssetAmount: new BN(0),
606
+ openOrders: new BN(0),
549
607
  };
550
608
 
551
609
  const market = this.clearingHouse.getMarket(
@@ -665,21 +723,6 @@ export class ClearingHouseUser {
665
723
 
666
724
  /**
667
725
  * 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
726
  * @param marketIndex
684
727
  * @param tradeSide
685
728
  * @param userMaxLeverageSetting - leverage : Precision TEN_THOUSAND
@@ -690,28 +733,34 @@ export class ClearingHouseUser {
690
733
  tradeSide: PositionDirection,
691
734
  userMaxLeverageSetting: BN
692
735
  ): BN {
693
- const currentPosition =
694
- this.getUserPosition(targetMarketIndex) ||
695
- this.getEmptyPosition(targetMarketIndex);
736
+ // inline function which get's the current position size on the opposite side of the target trade
737
+ const getOppositePositionValueUSDC = () => {
738
+ if (!currentPosition) return ZERO;
696
739
 
697
- const targetSide = tradeSide === PositionDirection.SHORT ? 'short' : 'long';
740
+ const side = tradeSide === PositionDirection.SHORT ? 'short' : 'long';
698
741
 
699
- const currentPositionSide = currentPosition?.baseAssetAmount.isNeg()
700
- ? 'short'
701
- : 'long';
742
+ if (side === 'long' && currentPosition?.baseAssetAmount.isNeg()) {
743
+ return this.getPositionValue(targetMarketIndex);
744
+ } else if (
745
+ side === 'short' &&
746
+ !currentPosition?.baseAssetAmount.isNeg()
747
+ ) {
748
+ return this.getPositionValue(targetMarketIndex);
749
+ }
702
750
 
703
- const targettingSameSide = !currentPosition
704
- ? true
705
- : targetSide === currentPositionSide;
751
+ return ZERO;
752
+ };
706
753
 
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);
754
+ const currentPosition =
755
+ this.getUserPosition(targetMarketIndex) ||
756
+ this.getEmptyPosition(targetMarketIndex);
711
757
 
712
758
  // get current leverage
713
759
  const currentLeverage = this.getLeverage();
714
760
 
761
+ // remaining leverage
762
+ // let remainingLeverage = userMaxLeverageSetting;
763
+
715
764
  const remainingLeverage = BN.max(
716
765
  userMaxLeverageSetting.sub(currentLeverage),
717
766
  ZERO
@@ -725,57 +774,10 @@ export class ClearingHouseUser {
725
774
  .mul(totalCollateral)
726
775
  .div(TEN_THOUSAND);
727
776
 
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
767
-
768
- const allowedQuoteSizeAfterClosingCurrentPosition =
769
- quoteValueOfMaxLeverage.sub(otherPositionsTotalQuoteSize);
777
+ // 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.
778
+ const oppositeSizeValueUSDC = getOppositePositionValueUSDC();
770
779
 
771
- maxPositionSize = currentPositionQuoteSize.add(
772
- allowedQuoteSizeAfterClosingCurrentPosition
773
- );
774
- }
775
- } else {
776
- // do nothing if targetting same side
777
- }
778
- }
780
+ maxPositionSize = maxPositionSize.add(oppositeSizeValueUSDC.mul(new BN(2)));
779
781
 
780
782
  // subtract oneMillionth of maxPositionSize
781
783
  // => to avoid rounding errors when taking max leverage
@@ -820,19 +822,13 @@ export class ClearingHouseUser {
820
822
 
821
823
  const totalPositionAfterTradeExcludingTargetMarket =
822
824
  this.getTotalPositionValueExcludingMarket(targetMarketIndex);
825
+ const newLeverage = currentMarketPositionAfterTrade
826
+ .add(totalPositionAfterTradeExcludingTargetMarket)
827
+ .abs()
828
+ .mul(TEN_THOUSAND)
829
+ .div(this.getTotalCollateral());
823
830
 
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
- }
831
+ return newLeverage;
836
832
  }
837
833
 
838
834
  /**
@@ -860,9 +856,85 @@ export class ClearingHouseUser {
860
856
 
861
857
  let currentMarketPositionValueUSDC = ZERO;
862
858
  if (currentMarketPosition) {
863
- currentMarketPositionValueUSDC = this.getPositionValue(marketToIgnore);
859
+ const market = this.clearingHouse.getMarket(
860
+ currentMarketPosition.marketIndex
861
+ );
862
+ currentMarketPositionValueUSDC = calculateBaseAssetValue(
863
+ market,
864
+ currentMarketPosition
865
+ );
864
866
  }
865
867
 
866
868
  return this.getTotalPositionValue().sub(currentMarketPositionValueUSDC);
867
869
  }
870
+
871
+ public canFillOrder(order: Order): boolean {
872
+ const userAccount = this.getUserAccount();
873
+ const userPositionsAccount = this.getUserPositionsAccount();
874
+ const userPosition = this.getUserPosition(order.marketIndex);
875
+ const market = this.clearingHouse.getMarket(order.marketIndex);
876
+
877
+ if (isEmptyPosition(userPosition)) {
878
+ return false;
879
+ }
880
+
881
+ const newState = calculateNewStateAfterOrder(
882
+ userAccount,
883
+ userPosition,
884
+ market,
885
+ order
886
+ );
887
+ if (newState === null) {
888
+ return false;
889
+ }
890
+ const [userAccountAfter, userPositionAfter, marketAfter] = newState;
891
+
892
+ const totalPositionValue = userPositionsAccount.positions.reduce(
893
+ (positionValue, marketPosition) => {
894
+ let market = this.clearingHouse.getMarket(marketPosition.marketIndex);
895
+ if (marketPosition.marketIndex.eq(order.marketIndex)) {
896
+ market = marketAfter;
897
+ marketPosition = userPositionAfter;
898
+ }
899
+
900
+ return positionValue.add(
901
+ calculateBaseAssetValue(market, marketPosition)
902
+ );
903
+ },
904
+ ZERO
905
+ );
906
+
907
+ if (totalPositionValue.eq(ZERO)) {
908
+ return true;
909
+ }
910
+
911
+ const unrealizedPnL = userPositionsAccount.positions.reduce(
912
+ (pnl, marketPosition) => {
913
+ let market = this.clearingHouse.getMarket(marketPosition.marketIndex);
914
+ pnl = pnl.add(
915
+ calculatePositionFundingPNL(market, marketPosition).div(
916
+ PRICE_TO_QUOTE_PRECISION
917
+ )
918
+ );
919
+
920
+ if (marketPosition.marketIndex.eq(order.marketIndex)) {
921
+ market = marketAfter;
922
+ marketPosition = userPositionAfter;
923
+ }
924
+
925
+ // update
926
+ return pnl.add(calculatePositionPNL(market, marketPosition, false));
927
+ },
928
+ ZERO
929
+ );
930
+ const totalCollateral = userAccountAfter.collateral.add(unrealizedPnL);
931
+
932
+ const marginRatioAfter = totalCollateral
933
+ .mul(TEN_THOUSAND)
934
+ .div(totalPositionValue);
935
+
936
+ const marginRatioInitial =
937
+ this.clearingHouse.getStateAccount().marginRatioInitial;
938
+ return marginRatioAfter.gte(marginRatioInitial);
939
+ }
868
940
  }
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: '8mKouB1uzsoMAhAu4qAXCiu8KAfwH7nonpuYfTM21Xg2',
15
15
  USDC_MINT_ADDRESS: '8zGuJQqwhZafTah7Uc7Z4tXRnguqkn5KLFAP8oV6PHe2',
16
16
  },
17
17
  'mainnet-beta': {
@@ -91,11 +91,19 @@ export const Markets: Market[] = [
91
91
  launchTs: 1643084413000,
92
92
  },
93
93
  {
94
- symbol: 'mSOL-PERP',
95
- baseAssetSymbol: 'mSOL',
94
+ symbol: 'ALGO-PERP',
95
+ baseAssetSymbol: 'ALGO',
96
96
  marketIndex: new BN(10),
97
- devnetPythOracle: '9a6RNx3tCu1TSs6TBSfV2XRXEPEZXQ6WB7jRojZRvyeZ',
98
- mainnetPythOracle: 'E4v1BBgoso9s64TQvmyownAVJbhbEPGyzA3qn4n46qj9',
99
- launchTs: 1643346125000,
97
+ devnetPythOracle: 'c1A946dY5NHuVda77C8XXtXytyR3wK1SCP3eA9VRfC3',
98
+ mainnetPythOracle: 'HqFyq1wh1xKvL7KDqqT7NJeSPdAqsDqnmBisUC2XdXAX',
99
+ launchTs: 1643686767000,
100
100
  },
101
+ // {
102
+ // symbol: 'mSOL-PERP',
103
+ // baseAssetSymbol: 'mSOL',
104
+ // marketIndex: new BN(11), //todo
105
+ // devnetPythOracle: '9a6RNx3tCu1TSs6TBSfV2XRXEPEZXQ6WB7jRojZRvyeZ',
106
+ // mainnetPythOracle: 'E4v1BBgoso9s64TQvmyownAVJbhbEPGyzA3qn4n46qj9',
107
+ // launchTs: 1643346125000,
108
+ // },
101
109
  ];
@@ -0,0 +1,125 @@
1
+ import { ConfirmOptions, Connection, PublicKey } from '@solana/web3.js';
2
+ import { IWallet } from '../types';
3
+ import { BulkAccountLoader } from '../accounts/bulkAccountLoader';
4
+ import { TxSender } from '../tx/types';
5
+ import { Idl, Program, Provider } from '@project-serum/anchor';
6
+ import { ClearingHouse } from '../clearingHouse';
7
+ import clearingHouseIDL from '../idl/clearing_house.json';
8
+ import { WebSocketClearingHouseAccountSubscriber } from '../accounts/webSocketClearingHouseAccountSubscriber';
9
+ import { DefaultTxSender } from '../tx/defaultTxSender';
10
+ import { ClearingHouseAccountSubscriber } from '../accounts/types';
11
+ import { PollingClearingHouseAccountSubscriber } from '../accounts/pollingClearingHouseAccountSubscriber';
12
+ import { Admin } from '../admin';
13
+
14
+ export type ClearingHouseConfigType = 'websocket' | 'polling' | 'custom';
15
+
16
+ type BaseClearingHouseConfig = {
17
+ type: ClearingHouseConfigType;
18
+ connection: Connection;
19
+ wallet: IWallet;
20
+ programID: PublicKey;
21
+ opts?: ConfirmOptions;
22
+ txSender?: TxSender;
23
+ };
24
+
25
+ type WebSocketClearingHouseConfiguration = BaseClearingHouseConfig;
26
+
27
+ type PollingClearingHouseConfiguration = BaseClearingHouseConfig & {
28
+ accountLoader: BulkAccountLoader;
29
+ };
30
+
31
+ type ClearingHouseConfig =
32
+ | PollingClearingHouseConfiguration
33
+ | WebSocketClearingHouseConfiguration;
34
+
35
+ export function getWebSocketClearingHouseConfig(
36
+ connection: Connection,
37
+ wallet: IWallet,
38
+ programID: PublicKey,
39
+ opts: ConfirmOptions = Provider.defaultOptions(),
40
+ txSender?: TxSender
41
+ ): WebSocketClearingHouseConfiguration {
42
+ return {
43
+ type: 'websocket',
44
+ connection,
45
+ wallet,
46
+ programID,
47
+ opts,
48
+ txSender,
49
+ };
50
+ }
51
+
52
+ export function getPollingClearingHouseConfig(
53
+ connection: Connection,
54
+ wallet: IWallet,
55
+ programID: PublicKey,
56
+ accountLoader: BulkAccountLoader,
57
+ opts: ConfirmOptions = Provider.defaultOptions(),
58
+ txSender?: TxSender
59
+ ): PollingClearingHouseConfiguration {
60
+ return {
61
+ type: 'polling',
62
+ connection,
63
+ wallet,
64
+ programID,
65
+ accountLoader,
66
+ opts,
67
+ txSender,
68
+ };
69
+ }
70
+
71
+ export function getClearingHouse(config: ClearingHouseConfig): ClearingHouse {
72
+ const provider = new Provider(config.connection, config.wallet, config.opts);
73
+ const program = new Program(
74
+ clearingHouseIDL as Idl,
75
+ config.programID,
76
+ provider
77
+ );
78
+ let accountSubscriber: ClearingHouseAccountSubscriber;
79
+ if (config.type === 'websocket') {
80
+ accountSubscriber = new WebSocketClearingHouseAccountSubscriber(program);
81
+ } else if (config.type === 'polling') {
82
+ accountSubscriber = new PollingClearingHouseAccountSubscriber(
83
+ program,
84
+ (config as PollingClearingHouseConfiguration).accountLoader
85
+ );
86
+ }
87
+
88
+ const txSender = config.txSender || new DefaultTxSender(provider);
89
+ return new ClearingHouse(
90
+ config.connection,
91
+ config.wallet,
92
+ program,
93
+ accountSubscriber,
94
+ txSender,
95
+ config.opts
96
+ );
97
+ }
98
+
99
+ export function getAdmin(config: ClearingHouseConfig): Admin {
100
+ const provider = new Provider(config.connection, config.wallet, config.opts);
101
+ const program = new Program(
102
+ clearingHouseIDL as Idl,
103
+ config.programID,
104
+ provider
105
+ );
106
+ let accountSubscriber: ClearingHouseAccountSubscriber;
107
+ if (config.type === 'websocket') {
108
+ accountSubscriber = new WebSocketClearingHouseAccountSubscriber(program);
109
+ } else if (config.type === 'polling') {
110
+ accountSubscriber = new PollingClearingHouseAccountSubscriber(
111
+ program,
112
+ (config as PollingClearingHouseConfiguration).accountLoader
113
+ );
114
+ }
115
+
116
+ const txSender = config.txSender || new DefaultTxSender(provider);
117
+ return new Admin(
118
+ config.connection,
119
+ config.wallet,
120
+ program,
121
+ accountSubscriber,
122
+ txSender,
123
+ config.opts
124
+ );
125
+ }
@@ -0,0 +1,73 @@
1
+ import { PublicKey } from '@solana/web3.js';
2
+ import { ClearingHouse } from '../clearingHouse';
3
+ import { BulkAccountLoader } from '../accounts/bulkAccountLoader';
4
+ import { ClearingHouseUser } from '../clearingHouseUser';
5
+ import { UserAccountSubscriber } from '../accounts/types';
6
+ import { WebSocketUserAccountSubscriber } from '../accounts/webSocketUserAccountSubscriber';
7
+ import { PollingUserAccountSubscriber } from '../accounts/pollingUserAccountSubscriber';
8
+
9
+ export type ClearingHouseUserConfigType = 'websocket' | 'polling' | 'custom';
10
+
11
+ type BaseClearingHouseUserConfig = {
12
+ type: ClearingHouseUserConfigType;
13
+ clearingHouse: ClearingHouse;
14
+ authority: PublicKey;
15
+ };
16
+
17
+ type WebSocketClearingHouseUserConfig = BaseClearingHouseUserConfig;
18
+
19
+ type PollingClearingHouseUserConfig = BaseClearingHouseUserConfig & {
20
+ accountLoader: BulkAccountLoader;
21
+ };
22
+
23
+ type ClearingHouseUserConfig =
24
+ | PollingClearingHouseUserConfig
25
+ | WebSocketClearingHouseUserConfig;
26
+
27
+ export function getWebSocketClearingHouseUserConfig(
28
+ clearingHouse: ClearingHouse,
29
+ authority: PublicKey
30
+ ): WebSocketClearingHouseUserConfig {
31
+ return {
32
+ type: 'websocket',
33
+ clearingHouse,
34
+ authority,
35
+ };
36
+ }
37
+
38
+ export function getPollingClearingHouseUserConfig(
39
+ clearingHouse: ClearingHouse,
40
+ authority: PublicKey,
41
+ accountLoader: BulkAccountLoader
42
+ ): PollingClearingHouseUserConfig {
43
+ return {
44
+ type: 'polling',
45
+ clearingHouse,
46
+ authority,
47
+ accountLoader,
48
+ };
49
+ }
50
+
51
+ export function getClearingHouseUser(
52
+ config: ClearingHouseUserConfig
53
+ ): ClearingHouseUser {
54
+ let accountSubscriber: UserAccountSubscriber;
55
+ if (config.type === 'websocket') {
56
+ accountSubscriber = new WebSocketUserAccountSubscriber(
57
+ config.clearingHouse.program,
58
+ config.authority
59
+ );
60
+ } else if (config.type === 'polling') {
61
+ accountSubscriber = new PollingUserAccountSubscriber(
62
+ config.clearingHouse.program,
63
+ config.authority,
64
+ (config as PollingClearingHouseUserConfig).accountLoader
65
+ );
66
+ }
67
+
68
+ return new ClearingHouseUser(
69
+ config.clearingHouse,
70
+ config.authority,
71
+ accountSubscriber
72
+ );
73
+ }