@drift-labs/sdk 0.2.0-master.36 → 0.2.0-master.37

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.
@@ -86,7 +86,7 @@ type RemainingAccountParams = {
86
86
  writablePerpMarketIndexes?: number[];
87
87
  writableSpotMarketIndexes?: number[];
88
88
  readablePerpMarketIndex?: number;
89
- readableSpotMarketIndex?: number;
89
+ readableSpotMarketIndexes?: number[];
90
90
  useMarketLastSlotCache?: boolean;
91
91
  };
92
92
 
@@ -108,7 +108,8 @@ export class ClearingHouse {
108
108
  eventEmitter: StrictEventEmitter<EventEmitter, ClearingHouseAccountEvents>;
109
109
  _isSubscribed = false;
110
110
  txSender: TxSender;
111
- marketLastSlotCache = new Map<number, number>();
111
+ perpMarketLastSlotCache = new Map<number, number>();
112
+ spotMarketLastSlotCache = new Map<number, number>();
112
113
  authority: PublicKey;
113
114
 
114
115
  public get isSubscribed() {
@@ -664,11 +665,14 @@ export class ClearingHouse {
664
665
  this.getRemainingAccountMapsForUsers(params.userAccounts);
665
666
 
666
667
  if (params.useMarketLastSlotCache) {
667
- const lastUserPositionsSlot = this.getUserAccountAndSlot()?.slot;
668
- for (const [marketIndex, slot] of this.marketLastSlotCache.entries()) {
668
+ const lastUserSlot = this.getUserAccountAndSlot()?.slot;
669
+ for (const [
670
+ marketIndex,
671
+ slot,
672
+ ] of this.perpMarketLastSlotCache.entries()) {
669
673
  // if cache has more recent slot than user positions account slot, add market to remaining accounts
670
674
  // otherwise remove from slot
671
- if (slot > lastUserPositionsSlot) {
675
+ if (slot > lastUserSlot) {
672
676
  const marketAccount = this.getPerpMarketAccount(marketIndex);
673
677
  perpMarketAccountMap.set(marketIndex, {
674
678
  pubkey: marketAccount.pubkey,
@@ -681,7 +685,32 @@ export class ClearingHouse {
681
685
  isWritable: false,
682
686
  });
683
687
  } else {
684
- this.marketLastSlotCache.delete(marketIndex);
688
+ this.perpMarketLastSlotCache.delete(marketIndex);
689
+ }
690
+ }
691
+
692
+ for (const [
693
+ marketIndex,
694
+ slot,
695
+ ] of this.spotMarketLastSlotCache.entries()) {
696
+ // if cache has more recent slot than user positions account slot, add market to remaining accounts
697
+ // otherwise remove from slot
698
+ if (slot > lastUserSlot) {
699
+ const marketAccount = this.getSpotMarketAccount(marketIndex);
700
+ spotMarketAccountMap.set(marketIndex, {
701
+ pubkey: marketAccount.pubkey,
702
+ isSigner: false,
703
+ isWritable: false,
704
+ });
705
+ if (!marketAccount.oracle.equals(PublicKey.default)) {
706
+ oracleAccountMap.set(marketAccount.oracle.toString(), {
707
+ pubkey: marketAccount.oracle,
708
+ isSigner: false,
709
+ isWritable: false,
710
+ });
711
+ }
712
+ } else {
713
+ this.spotMarketLastSlotCache.delete(marketIndex);
685
714
  }
686
715
  }
687
716
  }
@@ -720,21 +749,23 @@ export class ClearingHouse {
720
749
  }
721
750
  }
722
751
 
723
- if (params.readableSpotMarketIndex !== undefined) {
724
- const spotMarketAccount = this.getSpotMarketAccount(
725
- params.readableSpotMarketIndex
726
- );
727
- spotMarketAccountMap.set(params.readableSpotMarketIndex, {
728
- pubkey: spotMarketAccount.pubkey,
729
- isSigner: false,
730
- isWritable: false,
731
- });
732
- if (spotMarketAccount.marketIndex !== 0) {
733
- oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
734
- pubkey: spotMarketAccount.oracle,
752
+ if (params.readableSpotMarketIndexes !== undefined) {
753
+ for (const readableSpotMarketIndex of params.readableSpotMarketIndexes) {
754
+ const spotMarketAccount = this.getSpotMarketAccount(
755
+ readableSpotMarketIndex
756
+ );
757
+ spotMarketAccountMap.set(readableSpotMarketIndex, {
758
+ pubkey: spotMarketAccount.pubkey,
735
759
  isSigner: false,
736
760
  isWritable: false,
737
761
  });
762
+ if (spotMarketAccount.marketIndex !== 0) {
763
+ oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
764
+ pubkey: spotMarketAccount.oracle,
765
+ isSigner: false,
766
+ isWritable: false,
767
+ });
768
+ }
738
769
  }
739
770
  }
740
771
 
@@ -793,6 +824,17 @@ export class ClearingHouse {
793
824
  isWritable: false,
794
825
  });
795
826
  }
827
+
828
+ if (
829
+ !spotPosition.openAsks.eq(ZERO) ||
830
+ !spotPosition.openBids.eq(ZERO)
831
+ ) {
832
+ spotMarketAccountMap.set(spotPosition.marketIndex, {
833
+ pubkey: this.getQuoteSpotMarketAccount().pubkey,
834
+ isSigner: false,
835
+ isWritable: false,
836
+ });
837
+ }
796
838
  }
797
839
  }
798
840
  for (const position of userAccount.perpPositions) {
@@ -894,11 +936,12 @@ export class ClearingHouse {
894
936
  );
895
937
  }
896
938
 
897
- const { txSig } = await this.txSender.send(
939
+ const { txSig, slot } = await this.txSender.send(
898
940
  tx,
899
941
  additionalSigners,
900
942
  this.opts
901
943
  );
944
+ this.spotMarketLastSlotCache.set(marketIndex, slot);
902
945
  return txSig;
903
946
  }
904
947
 
@@ -1119,12 +1162,12 @@ export class ClearingHouse {
1119
1162
  );
1120
1163
  }
1121
1164
 
1122
- const { txSig } = await this.txSender.send(
1165
+ const { txSig, slot } = await this.txSender.send(
1123
1166
  tx,
1124
1167
  additionalSigners,
1125
1168
  this.opts
1126
1169
  );
1127
-
1170
+ this.spotMarketLastSlotCache.set(marketIndex, slot);
1128
1171
  return [txSig, userAccountPublicKey];
1129
1172
  }
1130
1173
 
@@ -1242,11 +1285,12 @@ export class ClearingHouse {
1242
1285
  );
1243
1286
  }
1244
1287
 
1245
- const { txSig } = await this.txSender.send(
1288
+ const { txSig, slot } = await this.txSender.send(
1246
1289
  tx,
1247
1290
  additionalSigners,
1248
1291
  this.opts
1249
1292
  );
1293
+ this.spotMarketLastSlotCache.set(marketIndex, slot);
1250
1294
  return txSig;
1251
1295
  }
1252
1296
 
@@ -1262,6 +1306,7 @@ export class ClearingHouse {
1262
1306
  userAccounts: [this.getUserAccount()],
1263
1307
  useMarketLastSlotCache: true,
1264
1308
  writableSpotMarketIndexes: [marketIndex],
1309
+ readableSpotMarketIndexes: [QUOTE_SPOT_MARKET_INDEX],
1265
1310
  });
1266
1311
 
1267
1312
  const spotMarketAccount = this.getSpotMarketAccount(marketIndex);
@@ -1293,7 +1338,7 @@ export class ClearingHouse {
1293
1338
  fromSubAccountId: number,
1294
1339
  toSubAccountId: number
1295
1340
  ): Promise<TransactionSignature> {
1296
- const { txSig } = await this.txSender.send(
1341
+ const { txSig, slot } = await this.txSender.send(
1297
1342
  wrapInTx(
1298
1343
  await this.getTransferDepositIx(
1299
1344
  amount,
@@ -1305,6 +1350,12 @@ export class ClearingHouse {
1305
1350
  [],
1306
1351
  this.opts
1307
1352
  );
1353
+ if (
1354
+ fromSubAccountId === this.activeSubAccountId ||
1355
+ toSubAccountId === this.activeSubAccountId
1356
+ ) {
1357
+ this.spotMarketLastSlotCache.set(marketIndex, slot);
1358
+ }
1308
1359
  return txSig;
1309
1360
  }
1310
1361
 
@@ -1356,6 +1407,7 @@ export class ClearingHouse {
1356
1407
  toUser,
1357
1408
  userStats: this.getUserStatsAccountPublicKey(),
1358
1409
  state: await this.getStatePublicKey(),
1410
+ spotMarketVault: this.getQuoteSpotMarketAccount().vault,
1359
1411
  },
1360
1412
  remainingAccounts,
1361
1413
  });
@@ -1530,7 +1582,7 @@ export class ClearingHouse {
1530
1582
  [],
1531
1583
  this.opts
1532
1584
  );
1533
- this.marketLastSlotCache.set(marketIndex, slot);
1585
+ this.perpMarketLastSlotCache.set(marketIndex, slot);
1534
1586
  return txSig;
1535
1587
  }
1536
1588
 
@@ -1619,7 +1671,7 @@ export class ClearingHouse {
1619
1671
  true
1620
1672
  );
1621
1673
 
1622
- this.marketLastSlotCache.set(orderParams.marketIndex, slot);
1674
+ this.perpMarketLastSlotCache.set(orderParams.marketIndex, slot);
1623
1675
 
1624
1676
  return { txSig, signedFillTx };
1625
1677
  }
@@ -1632,7 +1684,7 @@ export class ClearingHouse {
1632
1684
  [],
1633
1685
  this.opts
1634
1686
  );
1635
- this.marketLastSlotCache.set(orderParams.marketIndex, slot);
1687
+ this.perpMarketLastSlotCache.set(orderParams.marketIndex, slot);
1636
1688
  return txSig;
1637
1689
  }
1638
1690
 
@@ -1993,11 +2045,13 @@ export class ClearingHouse {
1993
2045
  public async placeSpotOrder(
1994
2046
  orderParams: OptionalOrderParams
1995
2047
  ): Promise<TransactionSignature> {
1996
- const { txSig } = await this.txSender.send(
2048
+ const { txSig, slot } = await this.txSender.send(
1997
2049
  wrapInTx(await this.getPlaceSpotOrderIx(orderParams)),
1998
2050
  [],
1999
2051
  this.opts
2000
2052
  );
2053
+ this.spotMarketLastSlotCache.set(orderParams.marketIndex, slot);
2054
+ this.spotMarketLastSlotCache.set(QUOTE_SPOT_MARKET_INDEX, slot);
2001
2055
  return txSig;
2002
2056
  }
2003
2057
 
@@ -2010,7 +2064,10 @@ export class ClearingHouse {
2010
2064
  const remainingAccounts = this.getRemainingAccounts({
2011
2065
  userAccounts: [this.getUserAccount()],
2012
2066
  useMarketLastSlotCache: true,
2013
- readableSpotMarketIndex: orderParams.marketIndex,
2067
+ readableSpotMarketIndexes: [
2068
+ orderParams.marketIndex,
2069
+ QUOTE_SPOT_MARKET_INDEX,
2070
+ ],
2014
2071
  });
2015
2072
 
2016
2073
  return await this.program.instruction.placeSpotOrder(orderParams, {
@@ -2291,7 +2348,7 @@ export class ClearingHouse {
2291
2348
  [],
2292
2349
  this.opts
2293
2350
  );
2294
- this.marketLastSlotCache.set(orderParams.marketIndex, slot);
2351
+ this.perpMarketLastSlotCache.set(orderParams.marketIndex, slot);
2295
2352
  return txSig;
2296
2353
  }
2297
2354
 
@@ -2374,7 +2431,7 @@ export class ClearingHouse {
2374
2431
  this.opts
2375
2432
  );
2376
2433
 
2377
- this.marketLastSlotCache.set(orderParams.marketIndex, slot);
2434
+ this.perpMarketLastSlotCache.set(orderParams.marketIndex, slot);
2378
2435
 
2379
2436
  return txSig;
2380
2437
  }
@@ -2431,7 +2488,7 @@ export class ClearingHouse {
2431
2488
  makerInfo?: MakerInfo,
2432
2489
  referrerInfo?: ReferrerInfo
2433
2490
  ): Promise<TransactionSignature> {
2434
- const { txSig } = await this.txSender.send(
2491
+ const { txSig, slot } = await this.txSender.send(
2435
2492
  wrapInTx(
2436
2493
  await this.getPlaceAndTakeSpotOrderIx(
2437
2494
  orderParams,
@@ -2443,6 +2500,8 @@ export class ClearingHouse {
2443
2500
  [],
2444
2501
  this.opts
2445
2502
  );
2503
+ this.spotMarketLastSlotCache.set(orderParams.marketIndex, slot);
2504
+ this.spotMarketLastSlotCache.set(QUOTE_SPOT_MARKET_INDEX, slot);
2446
2505
  return txSig;
2447
2506
  }
2448
2507
 
@@ -2524,26 +2583,30 @@ export class ClearingHouse {
2524
2583
  public async placeAndMakeSpotOrder(
2525
2584
  orderParams: OptionalOrderParams,
2526
2585
  takerInfo: TakerInfo,
2586
+ fulfillmentConfig?: SerumV3FulfillmentConfigAccount,
2527
2587
  referrerInfo?: ReferrerInfo
2528
2588
  ): Promise<TransactionSignature> {
2529
- const { txSig } = await this.txSender.send(
2589
+ const { txSig, slot } = await this.txSender.send(
2530
2590
  wrapInTx(
2531
2591
  await this.getPlaceAndMakeSpotOrderIx(
2532
2592
  orderParams,
2533
2593
  takerInfo,
2594
+ fulfillmentConfig,
2534
2595
  referrerInfo
2535
2596
  )
2536
2597
  ),
2537
2598
  [],
2538
2599
  this.opts
2539
2600
  );
2540
-
2601
+ this.spotMarketLastSlotCache.set(orderParams.marketIndex, slot);
2602
+ this.spotMarketLastSlotCache.set(QUOTE_SPOT_MARKET_INDEX, slot);
2541
2603
  return txSig;
2542
2604
  }
2543
2605
 
2544
2606
  public async getPlaceAndMakeSpotOrderIx(
2545
2607
  orderParams: OptionalOrderParams,
2546
2608
  takerInfo: TakerInfo,
2609
+ fulfillmentConfig?: SerumV3FulfillmentConfigAccount,
2547
2610
  referrerInfo?: ReferrerInfo
2548
2611
  ): Promise<TransactionInstruction> {
2549
2612
  orderParams = this.getOrderParams(orderParams, MarketType.SPOT);
@@ -2572,10 +2635,19 @@ export class ClearingHouse {
2572
2635
  });
2573
2636
  }
2574
2637
 
2638
+ if (fulfillmentConfig) {
2639
+ this.addSerumRemainingAccounts(
2640
+ orderParams.marketIndex,
2641
+ remainingAccounts,
2642
+ fulfillmentConfig
2643
+ );
2644
+ }
2645
+
2575
2646
  const takerOrderId = takerInfo.order.orderId;
2576
2647
  return await this.program.instruction.placeAndMakeSpotOrder(
2577
2648
  orderParams,
2578
2649
  takerOrderId,
2650
+ fulfillmentConfig ? fulfillmentConfig.fulfillmentType : null,
2579
2651
  {
2580
2652
  accounts: {
2581
2653
  state: await this.getStatePublicKey(),
@@ -2614,6 +2686,66 @@ export class ClearingHouse {
2614
2686
  });
2615
2687
  }
2616
2688
 
2689
+ /**
2690
+ * Modifies an open order by closing it and replacing it with a new order.
2691
+ * @param orderId: The open order to modify
2692
+ * @param newBaseAmount: The new base amount for the order. One of [newBaseAmount|newLimitPrice|newOraclePriceOffset] must be provided.
2693
+ * @param newLimitPice: The new limit price for the order. One of [newBaseAmount|newLimitPrice|newOraclePriceOffset] must be provided.
2694
+ * @param newOraclePriceOffset: The new oracle price offset for the order. One of [newBaseAmount|newLimitPrice|newOraclePriceOffset] must be provided.
2695
+ * @returns
2696
+ */
2697
+ public async modifyPerpOrder(
2698
+ orderId: number,
2699
+ newBaseAmount?: BN,
2700
+ newLimitPrice?: BN,
2701
+ newOraclePriceOffset?: number
2702
+ ): Promise<TransactionSignature> {
2703
+ if (!newBaseAmount && !newLimitPrice && !newOraclePriceOffset) {
2704
+ throw new Error(
2705
+ `Must provide newBaseAmount or newLimitPrice or newOraclePriceOffset to modify order`
2706
+ );
2707
+ }
2708
+
2709
+ const openOrder = this.getUser().getOrder(orderId);
2710
+ if (!openOrder) {
2711
+ throw new Error(`No open order with id ${orderId.toString()}`);
2712
+ }
2713
+ const cancelOrderIx = await this.getCancelOrderIx(orderId);
2714
+
2715
+ const newOrderParams: OptionalOrderParams = {
2716
+ orderType: openOrder.orderType,
2717
+ marketType: openOrder.marketType,
2718
+ direction: openOrder.direction,
2719
+ baseAssetAmount: newBaseAmount || openOrder.baseAssetAmount,
2720
+ price: newLimitPrice || openOrder.price,
2721
+ marketIndex: openOrder.marketIndex,
2722
+ reduceOnly: openOrder.reduceOnly,
2723
+ postOnly: openOrder.postOnly,
2724
+ immediateOrCancel: openOrder.immediateOrCancel,
2725
+ triggerPrice: openOrder.triggerPrice,
2726
+ triggerCondition: openOrder.triggerCondition,
2727
+ oraclePriceOffset: newOraclePriceOffset || openOrder.oraclePriceOffset,
2728
+ auctionDuration: openOrder.auctionDuration,
2729
+ maxTs: openOrder.maxTs,
2730
+ auctionStartPrice: openOrder.auctionStartPrice,
2731
+ auctionEndPrice: openOrder.auctionEndPrice,
2732
+ };
2733
+ const placeOrderIx = await this.getPlacePerpOrderIx(newOrderParams);
2734
+
2735
+ const tx = new Transaction();
2736
+ tx.add(
2737
+ ComputeBudgetProgram.requestUnits({
2738
+ units: 1_000_000,
2739
+ additionalFee: 0,
2740
+ })
2741
+ );
2742
+ tx.add(cancelOrderIx);
2743
+ tx.add(placeOrderIx);
2744
+ const { txSig, slot } = await this.txSender.send(tx, [], this.opts);
2745
+ this.perpMarketLastSlotCache.set(newOrderParams.marketIndex, slot);
2746
+ return txSig;
2747
+ }
2748
+
2617
2749
  public async settlePNLs(
2618
2750
  users: {
2619
2751
  settleeUserAccountPublicKey: PublicKey;
@@ -2680,6 +2812,7 @@ export class ClearingHouse {
2680
2812
  state: await this.getStatePublicKey(),
2681
2813
  authority: this.wallet.publicKey,
2682
2814
  user: settleeUserAccountPublicKey,
2815
+ spotMarketVault: this.getQuoteSpotMarketAccount().vault,
2683
2816
  },
2684
2817
  remainingAccounts: remainingAccounts,
2685
2818
  });
@@ -2689,7 +2822,8 @@ export class ClearingHouse {
2689
2822
  userAccountPublicKey: PublicKey,
2690
2823
  userAccount: UserAccount,
2691
2824
  marketIndex: number,
2692
- maxBaseAssetAmount: BN
2825
+ maxBaseAssetAmount: BN,
2826
+ limitPrice?: BN
2693
2827
  ): Promise<TransactionSignature> {
2694
2828
  const { txSig, slot } = await this.txSender.send(
2695
2829
  wrapInTx(
@@ -2697,13 +2831,14 @@ export class ClearingHouse {
2697
2831
  userAccountPublicKey,
2698
2832
  userAccount,
2699
2833
  marketIndex,
2700
- maxBaseAssetAmount
2834
+ maxBaseAssetAmount,
2835
+ limitPrice
2701
2836
  )
2702
2837
  ),
2703
2838
  [],
2704
2839
  this.opts
2705
2840
  );
2706
- this.marketLastSlotCache.set(marketIndex, slot);
2841
+ this.perpMarketLastSlotCache.set(marketIndex, slot);
2707
2842
  return txSig;
2708
2843
  }
2709
2844
 
@@ -2711,7 +2846,8 @@ export class ClearingHouse {
2711
2846
  userAccountPublicKey: PublicKey,
2712
2847
  userAccount: UserAccount,
2713
2848
  marketIndex: number,
2714
- maxBaseAssetAmount: BN
2849
+ maxBaseAssetAmount: BN,
2850
+ limitPrice?: BN
2715
2851
  ): Promise<TransactionInstruction> {
2716
2852
  const userStatsPublicKey = getUserStatsAccountPublicKey(
2717
2853
  this.program.programId,
@@ -2730,6 +2866,7 @@ export class ClearingHouse {
2730
2866
  return await this.program.instruction.liquidatePerp(
2731
2867
  marketIndex,
2732
2868
  maxBaseAssetAmount,
2869
+ limitPrice ?? null,
2733
2870
  {
2734
2871
  accounts: {
2735
2872
  state: await this.getStatePublicKey(),
@@ -2751,7 +2888,7 @@ export class ClearingHouse {
2751
2888
  liabilityMarketIndex: number,
2752
2889
  maxLiabilityTransfer: BN
2753
2890
  ): Promise<TransactionSignature> {
2754
- const { txSig } = await this.txSender.send(
2891
+ const { txSig, slot } = await this.txSender.send(
2755
2892
  wrapInTx(
2756
2893
  await this.getLiquidateSpotIx(
2757
2894
  userAccountPublicKey,
@@ -2764,6 +2901,8 @@ export class ClearingHouse {
2764
2901
  [],
2765
2902
  this.opts
2766
2903
  );
2904
+ this.spotMarketLastSlotCache.set(assetMarketIndex, slot);
2905
+ this.spotMarketLastSlotCache.set(liabilityMarketIndex, slot);
2767
2906
  return txSig;
2768
2907
  }
2769
2908
 
@@ -2826,7 +2965,8 @@ export class ClearingHouse {
2826
2965
  [],
2827
2966
  this.opts
2828
2967
  );
2829
- this.marketLastSlotCache.set(perpMarketIndex, slot);
2968
+ this.perpMarketLastSlotCache.set(perpMarketIndex, slot);
2969
+ this.spotMarketLastSlotCache.set(liabilityMarketIndex, slot);
2830
2970
  return txSig;
2831
2971
  }
2832
2972
 
@@ -2889,7 +3029,8 @@ export class ClearingHouse {
2889
3029
  [],
2890
3030
  this.opts
2891
3031
  );
2892
- this.marketLastSlotCache.set(perpMarketIndex, slot);
3032
+ this.perpMarketLastSlotCache.set(perpMarketIndex, slot);
3033
+ this.spotMarketLastSlotCache.set(assetMarketIndex, slot);
2893
3034
  return txSig;
2894
3035
  }
2895
3036
 
@@ -143,6 +143,7 @@ export class ClearingHouseUser {
143
143
  marketIndex,
144
144
  quoteAssetAmount: ZERO,
145
145
  quoteEntryAmount: ZERO,
146
+ quoteBreakEvenAmount: ZERO,
146
147
  openOrders: 0,
147
148
  openBids: ZERO,
148
149
  openAsks: ZERO,
@@ -773,30 +774,12 @@ export class ClearingHouseUser {
773
774
  settledPosition.baseAssetAmount.add(dustBaa);
774
775
  perpPosition.quoteAssetAmount = settledPosition.quoteAssetAmount;
775
776
 
776
- // open orders
777
- let openAsks;
778
- if (market.amm.maxBaseAssetReserve > market.amm.baseAssetReserve) {
779
- openAsks = market.amm.maxBaseAssetReserve
780
- .sub(market.amm.baseAssetReserve)
781
- .mul(perpPosition.lpShares)
782
- .div(market.amm.sqrtK)
783
- .mul(new BN(-1));
784
- } else {
785
- openAsks = ZERO;
786
- }
787
-
788
- let openBids;
789
- if (market.amm.minBaseAssetReserve < market.amm.baseAssetReserve) {
790
- openBids = market.amm.baseAssetReserve
791
- .sub(market.amm.minBaseAssetReserve)
792
- .mul(perpPosition.lpShares)
793
- .div(market.amm.sqrtK);
794
- } else {
795
- openBids = ZERO;
796
- }
777
+ const [totalOpenBids, totalOpenAsks] = this.getPerpBidAsks(
778
+ market.marketIndex
779
+ );
797
780
 
798
- perpPosition.openAsks = perpPosition.openAsks.add(openAsks);
799
- perpPosition.openBids = perpPosition.openBids.add(openBids);
781
+ perpPosition.openAsks = totalOpenAsks;
782
+ perpPosition.openBids = totalOpenBids;
800
783
  }
801
784
 
802
785
  let valuationPrice = this.getOracleDataForPerpMarket(
@@ -1118,6 +1101,7 @@ export class ClearingHouseUser {
1118
1101
  remainderBaseAssetAmount: 0,
1119
1102
  quoteAssetAmount: new BN(0),
1120
1103
  lastCumulativeFundingRate: ZERO,
1104
+ quoteBreakEvenAmount: new BN(0),
1121
1105
  quoteEntryAmount: new BN(0),
1122
1106
  openOrders: 0,
1123
1107
  openBids: new BN(0),
@@ -1487,7 +1471,7 @@ export class ClearingHouseUser {
1487
1471
 
1488
1472
  const amountWithdrawable = freeCollateral
1489
1473
  .mul(MARGIN_PRECISION)
1490
- .div(spotMarket.initialAssetWeight)
1474
+ .div(new BN(spotMarket.initialAssetWeight))
1491
1475
  .mul(PRICE_PRECISION)
1492
1476
  .div(oracleData.price)
1493
1477
  .mul(precisionIncrease);
@@ -1526,7 +1510,7 @@ export class ClearingHouseUser {
1526
1510
 
1527
1511
  const maxLiabilityAllowed = freeCollatAfterWithdraw
1528
1512
  .mul(MARGIN_PRECISION)
1529
- .div(spotMarket.initialLiabilityWeight)
1513
+ .div(new BN(spotMarket.initialLiabilityWeight))
1530
1514
  .mul(PRICE_PRECISION)
1531
1515
  .div(oracleData.price)
1532
1516
  .mul(precisionIncrease);
package/src/config.ts CHANGED
@@ -29,7 +29,7 @@ export const configs: { [key in DriftEnv]: DriftConfig } = {
29
29
  devnet: {
30
30
  ENV: 'devnet',
31
31
  PYTH_ORACLE_MAPPING_ADDRESS: 'BmA9Z6FjioHJPpjT39QazZyhDRUdZy2ezwx4GiDdE2u2',
32
- CLEARING_HOUSE_PROGRAM_ID: 'BJG3o4CURrokB7huNyiHptYepAtHXj4YfefJiPgzUULV',
32
+ CLEARING_HOUSE_PROGRAM_ID: 'jAEeKs9twxAJmXZHqS2p459xW7FMDjoyvuqthRo9qGS',
33
33
  USDC_MINT_ADDRESS: '8zGuJQqwhZafTah7Uc7Z4tXRnguqkn5KLFAP8oV6PHe2',
34
34
  SERUM_V3: 'DESVgJVGajEgKGXhb6XmqDHGz3VjdgP7rEVESBgxmroY',
35
35
  V2_ALPHA_TICKET_MINT_ADDRESS:
@@ -9,6 +9,11 @@ export class BigNum {
9
9
  static delim = '.';
10
10
  static spacer = ',';
11
11
 
12
+ public static setLocale(locale: string): void {
13
+ BigNum.delim = (1.1).toLocaleString(locale).slice(1, 2) || '.';
14
+ BigNum.spacer = (1000).toLocaleString(locale).slice(1, 2) || ',';
15
+ }
16
+
12
17
  constructor(
13
18
  val: BN | number | string,
14
19
  precisionVal: BN | number | string = new BN(0)
@@ -566,7 +571,21 @@ export class BigNum {
566
571
  * @returns
567
572
  */
568
573
  public toNum() {
569
- return parseFloat(this.print());
574
+ let printedValue = this.print();
575
+
576
+ // Must convert any non-US delimiters and spacers to US format before using parseFloat
577
+ if (BigNum.delim !== '.' || BigNum.spacer !== ',') {
578
+ printedValue = printedValue
579
+ .split('')
580
+ .map((char) => {
581
+ if (char === BigNum.delim) return '.';
582
+ if (char === BigNum.spacer) return ',';
583
+ return char;
584
+ })
585
+ .join('');
586
+ }
587
+
588
+ return parseFloat(printedValue);
570
589
  }
571
590
 
572
591
  static fromJSON(json: { val: string; precision: string }) {
@@ -599,12 +618,16 @@ export class BigNum {
599
618
  static fromPrint(val: string, precisionShift?: BN): BigNum {
600
619
  // Handle empty number edge cases
601
620
  if (!val) return BigNum.from(ZERO, precisionShift);
602
- if (!val.replace(BigNum.delim, ''))
621
+ if (!val.replace(BigNum.delim, '')) {
603
622
  return BigNum.from(ZERO, precisionShift);
623
+ }
604
624
 
605
- const [leftSide, rightSide] = val.split(BigNum.delim);
625
+ const sides = val.split(BigNum.delim);
626
+ const rightSide = sides[1];
627
+ const leftSide = sides[0].replace(/\D/g, '');
628
+ const bnInput = `${leftSide ?? ''}${rightSide ?? ''}`;
606
629
 
607
- const rawBn = new BN(`${leftSide ?? ''}${rightSide ?? ''}`);
630
+ const rawBn = new BN(bnInput);
608
631
 
609
632
  const rightSideLength = rightSide?.length ?? 0;
610
633