@drift-labs/sdk 0.2.0-temp.0 → 0.2.0-temp.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 (115) hide show
  1. package/lib/admin.d.ts +7 -5
  2. package/lib/admin.js +34 -11
  3. package/lib/clearingHouse.d.ts +23 -9
  4. package/lib/clearingHouse.js +335 -95
  5. package/lib/clearingHouseUser.d.ts +2 -2
  6. package/lib/clearingHouseUser.js +8 -17
  7. package/lib/config.js +1 -1
  8. package/lib/constants/banks.js +9 -2
  9. package/lib/constants/numericConstants.d.ts +1 -0
  10. package/lib/constants/numericConstants.js +2 -1
  11. package/lib/idl/clearing_house.json +689 -153
  12. package/lib/idl/{mock_usdc_faucet.json → token_faucet.json} +46 -23
  13. package/lib/index.d.ts +3 -2
  14. package/lib/index.js +7 -2
  15. package/lib/math/amm.js +7 -35
  16. package/lib/math/auction.js +4 -1
  17. package/lib/math/orders.d.ts +2 -2
  18. package/lib/math/orders.js +19 -2
  19. package/lib/math/position.js +3 -1
  20. package/lib/math/trade.d.ts +1 -1
  21. package/lib/math/trade.js +7 -10
  22. package/lib/orderParams.d.ts +14 -5
  23. package/lib/orderParams.js +8 -96
  24. package/lib/orders.js +1 -1
  25. package/lib/slot/SlotSubscriber.d.ts +7 -0
  26. package/lib/slot/SlotSubscriber.js +3 -0
  27. package/lib/{mockUSDCFaucet.d.ts → tokenFaucet.d.ts} +7 -5
  28. package/lib/{mockUSDCFaucet.js → tokenFaucet.js} +41 -40
  29. package/lib/tx/utils.js +1 -1
  30. package/lib/types.d.ts +132 -14
  31. package/lib/types.js +52 -1
  32. package/lib/util/computeUnits.js +1 -1
  33. package/package.json +3 -3
  34. package/src/accounts/bulkAccountLoader.js +197 -0
  35. package/src/accounts/bulkUserSubscription.js +33 -0
  36. package/src/accounts/pollingClearingHouseAccountSubscriber.js +311 -0
  37. package/src/accounts/pollingOracleSubscriber.js +93 -0
  38. package/src/accounts/pollingTokenAccountSubscriber.js +90 -0
  39. package/src/accounts/pollingUserAccountSubscriber.js +132 -0
  40. package/src/accounts/types.js +10 -0
  41. package/src/accounts/utils.js +7 -0
  42. package/src/accounts/webSocketAccountSubscriber.js +93 -0
  43. package/src/accounts/webSocketClearingHouseAccountSubscriber.js +233 -0
  44. package/src/accounts/webSocketUserAccountSubscriber.js +62 -0
  45. package/src/addresses/marketAddresses.js +26 -0
  46. package/src/admin.js +517 -0
  47. package/src/admin.ts +53 -14
  48. package/src/assert/assert.js +9 -0
  49. package/src/clearingHouse.ts +510 -131
  50. package/src/clearingHouseConfig.js +2 -0
  51. package/src/clearingHouseUser.ts +12 -23
  52. package/src/clearingHouseUserConfig.js +2 -0
  53. package/src/config.js +67 -0
  54. package/src/config.ts +1 -1
  55. package/src/constants/banks.js +42 -0
  56. package/src/constants/banks.ts +9 -2
  57. package/src/constants/markets.js +42 -0
  58. package/src/constants/numericConstants.js +41 -0
  59. package/src/constants/numericConstants.ts +1 -0
  60. package/src/events/eventList.js +77 -0
  61. package/src/events/eventSubscriber.js +139 -0
  62. package/src/events/fetchLogs.js +50 -0
  63. package/src/events/pollingLogProvider.js +64 -0
  64. package/src/events/sort.js +44 -0
  65. package/src/events/txEventCache.js +71 -0
  66. package/src/events/types.js +20 -0
  67. package/src/events/webSocketLogProvider.js +41 -0
  68. package/src/examples/makeTradeExample.js +80 -0
  69. package/src/factory/bigNum.js +390 -0
  70. package/src/factory/oracleClient.js +20 -0
  71. package/src/idl/clearing_house.json +689 -153
  72. package/src/idl/{mock_usdc_faucet.json → token_faucet.json} +46 -23
  73. package/src/index.js +69 -0
  74. package/src/index.ts +3 -2
  75. package/src/math/amm.js +369 -0
  76. package/src/math/amm.ts +19 -49
  77. package/src/math/auction.js +42 -0
  78. package/src/math/auction.ts +5 -1
  79. package/src/math/conversion.js +11 -0
  80. package/src/math/funding.js +248 -0
  81. package/src/math/oracles.js +26 -0
  82. package/src/math/orders.ts +17 -3
  83. package/src/math/position.ts +5 -1
  84. package/src/math/repeg.js +128 -0
  85. package/src/math/state.js +15 -0
  86. package/src/math/trade.js +253 -0
  87. package/src/math/trade.ts +23 -25
  88. package/src/math/utils.js +0 -1
  89. package/src/mockUSDCFaucet.js +280 -0
  90. package/src/oracles/oracleClientCache.js +19 -0
  91. package/src/oracles/pythClient.js +46 -0
  92. package/src/oracles/quoteAssetOracleClient.js +32 -0
  93. package/src/oracles/switchboardClient.js +69 -0
  94. package/src/oracles/types.js +2 -0
  95. package/src/orderParams.js +20 -0
  96. package/src/orderParams.ts +20 -141
  97. package/src/orders.ts +2 -1
  98. package/src/slot/SlotSubscriber.js +39 -0
  99. package/src/slot/SlotSubscriber.ts +11 -1
  100. package/src/token/index.js +38 -0
  101. package/src/tokenFaucet.js +189 -0
  102. package/src/{mockUSDCFaucet.ts → tokenFaucet.ts} +48 -59
  103. package/src/tx/types.js +2 -0
  104. package/src/tx/utils.js +17 -0
  105. package/src/tx/utils.ts +1 -1
  106. package/src/types.js +125 -0
  107. package/src/types.ts +128 -15
  108. package/src/userName.js +20 -0
  109. package/src/util/computeUnits.js +21 -11
  110. package/src/util/computeUnits.ts +1 -1
  111. package/src/util/getTokenAddress.js +9 -0
  112. package/src/util/promiseTimeout.js +14 -0
  113. package/src/util/tps.js +27 -0
  114. package/src/wallet.js +35 -0
  115. package/src/util/computeUnits.js.map +0 -1
@@ -29,6 +29,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
29
29
  exports.ClearingHouse = void 0;
30
30
  const anchor_1 = require("@project-serum/anchor");
31
31
  const spl_token_1 = require("@solana/spl-token");
32
+ const types_1 = require("./types");
32
33
  const anchor = __importStar(require("@project-serum/anchor"));
33
34
  const clearing_house_json_1 = __importDefault(require("./idl/clearing_house.json"));
34
35
  const web3_js_1 = require("@solana/web3.js");
@@ -42,7 +43,6 @@ const pollingClearingHouseAccountSubscriber_1 = require("./accounts/pollingClear
42
43
  const webSocketClearingHouseAccountSubscriber_1 = require("./accounts/webSocketClearingHouseAccountSubscriber");
43
44
  const retryTxSender_1 = require("./tx/retryTxSender");
44
45
  const clearingHouseUser_1 = require("./clearingHouseUser");
45
- const orderParams_1 = require("./orderParams");
46
46
  const config_1 = require("./config");
47
47
  /**
48
48
  * # ClearingHouse
@@ -371,13 +371,19 @@ class ClearingHouse {
371
371
  });
372
372
  }
373
373
  else {
374
- remainingAccounts = [
375
- {
376
- pubkey: this.getBankAccount(bankIndex).pubkey,
374
+ const bankAccount = this.getBankAccount(bankIndex);
375
+ if (!bankAccount.oracle.equals(web3_js_1.PublicKey.default)) {
376
+ remainingAccounts.push({
377
+ pubkey: bankAccount.oracle,
377
378
  isSigner: false,
378
- isWritable: true,
379
- },
380
- ];
379
+ isWritable: false,
380
+ });
381
+ }
382
+ remainingAccounts.push({
383
+ pubkey: bankAccount.pubkey,
384
+ isSigner: false,
385
+ isWritable: true,
386
+ });
381
387
  }
382
388
  const bank = this.getBankAccount(bankIndex);
383
389
  return await this.program.instruction.deposit(bankIndex, amount, reduceOnly, {
@@ -413,10 +419,10 @@ class ClearingHouse {
413
419
  const { txSig } = await this.txSender.send(tx, []);
414
420
  return [txSig, userAccountPublicKey];
415
421
  }
416
- async initializeUserAccountForDevnet(userId = 0, name = userName_1.DEFAULT_USER_NAME, mockUSDCFaucet, amount) {
417
- const [associateTokenPublicKey, createAssociatedAccountIx, mintToIx] = await mockUSDCFaucet.createAssociatedTokenAccountAndMintToInstructions(this.wallet.publicKey, amount);
422
+ async initializeUserAccountForDevnet(userId = 0, name = userName_1.DEFAULT_USER_NAME, bankIndex, tokenFaucet, amount) {
423
+ const [associateTokenPublicKey, createAssociatedAccountIx, mintToIx] = await tokenFaucet.createAssociatedTokenAccountAndMintToInstructions(this.wallet.publicKey, amount);
418
424
  const [userAccountPublicKey, initializeUserAccountIx] = await this.getInitializeUserInstructions(userId, name);
419
- const depositCollateralIx = await this.getDepositInstruction(amount, new anchor_1.BN(0), associateTokenPublicKey, userId, false, false);
425
+ const depositCollateralIx = await this.getDepositInstruction(amount, bankIndex, associateTokenPublicKey, userId, false, false);
420
426
  const tx = new web3_js_1.Transaction()
421
427
  .add(createAssociatedAccountIx)
422
428
  .add(mintToIx)
@@ -482,14 +488,24 @@ class ClearingHouse {
482
488
  });
483
489
  }
484
490
  async openPosition(direction, amount, marketIndex, limitPrice) {
485
- return await this.placeAndTake((0, orderParams_1.getMarketOrderParams)(marketIndex, direction, numericConstants_1.ZERO, amount, false, limitPrice));
491
+ return await this.placeAndTake({
492
+ orderType: types_1.OrderType.MARKET,
493
+ marketIndex,
494
+ direction,
495
+ baseAssetAmount: amount,
496
+ price: limitPrice,
497
+ });
486
498
  }
487
499
  async placeOrder(orderParams) {
488
500
  const { txSig, slot } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getPlaceOrderIx(orderParams)), [], this.opts);
489
501
  this.marketLastSlotCache.set(orderParams.marketIndex.toNumber(), slot);
490
502
  return txSig;
491
503
  }
504
+ getOrderParams(optionalOrderParams) {
505
+ return Object.assign({}, types_1.DefaultOrderParams, optionalOrderParams);
506
+ }
492
507
  async getPlaceOrderIx(orderParams) {
508
+ orderParams = this.getOrderParams(orderParams);
493
509
  const userAccountPublicKey = await this.getUserAccountPublicKey();
494
510
  const remainingAccounts = this.getRemainingAccounts({
495
511
  writableMarketIndex: orderParams.marketIndex,
@@ -580,44 +596,57 @@ class ClearingHouse {
580
596
  const fillerPublicKey = await this.getUserAccountPublicKey();
581
597
  const marketIndex = order.marketIndex;
582
598
  const marketAccount = this.getMarketAccount(marketIndex);
583
- const bankAccountInfos = [
584
- {
585
- pubkey: this.getQuoteAssetBankAccount().pubkey,
586
- isSigner: false,
587
- isWritable: true,
588
- },
589
- ];
590
- const marketAccountInfos = [
591
- {
592
- pubkey: marketAccount.pubkey,
593
- isWritable: true,
594
- isSigner: false,
595
- },
596
- ];
597
- const oracleAccountInfos = [
598
- {
599
- pubkey: marketAccount.amm.oracle,
600
- isWritable: false,
601
- isSigner: false,
602
- },
603
- ];
599
+ const oracleAccountMap = new Map();
600
+ const bankAccountMap = new Map();
601
+ const marketAccountMap = new Map();
602
+ marketAccountMap.set(marketIndex.toNumber(), {
603
+ pubkey: marketAccount.pubkey,
604
+ isWritable: true,
605
+ isSigner: false,
606
+ });
607
+ oracleAccountMap.set(marketAccount.amm.oracle.toString(), {
608
+ pubkey: marketAccount.amm.oracle,
609
+ isWritable: false,
610
+ isSigner: false,
611
+ });
612
+ for (const bankBalance of userAccount.bankBalances) {
613
+ if (!bankBalance.balance.eq(numericConstants_1.ZERO)) {
614
+ const bankAccount = this.getBankAccount(bankBalance.bankIndex);
615
+ bankAccountMap.set(bankBalance.bankIndex.toNumber(), {
616
+ pubkey: bankAccount.pubkey,
617
+ isSigner: false,
618
+ isWritable: true,
619
+ });
620
+ if (!bankAccount.oracle.equals(web3_js_1.PublicKey.default)) {
621
+ oracleAccountMap.set(bankAccount.oracle.toString(), {
622
+ pubkey: bankAccount.oracle,
623
+ isSigner: false,
624
+ isWritable: false,
625
+ });
626
+ }
627
+ }
628
+ }
604
629
  for (const position of userAccount.positions) {
605
630
  if (!(0, position_1.positionIsAvailable)(position) &&
606
631
  !position.marketIndex.eq(order.marketIndex)) {
607
632
  const market = this.getMarketAccount(position.marketIndex);
608
- marketAccountInfos.push({
633
+ marketAccountMap.set(position.marketIndex.toNumber(), {
609
634
  pubkey: market.pubkey,
610
635
  isWritable: true,
611
636
  isSigner: false,
612
637
  });
613
- oracleAccountInfos.push({
638
+ oracleAccountMap.set(market.amm.oracle.toString(), {
614
639
  pubkey: market.amm.oracle,
615
640
  isWritable: false,
616
641
  isSigner: false,
617
642
  });
618
643
  }
619
644
  }
620
- const remainingAccounts = oracleAccountInfos.concat(bankAccountInfos.concat(marketAccountInfos));
645
+ const remainingAccounts = [
646
+ ...oracleAccountMap.values(),
647
+ ...bankAccountMap.values(),
648
+ ...marketAccountMap.values(),
649
+ ];
621
650
  if (makerInfo) {
622
651
  remainingAccounts.push({
623
652
  pubkey: makerInfo.maker,
@@ -645,44 +674,57 @@ class ClearingHouse {
645
674
  const fillerPublicKey = await this.getUserAccountPublicKey();
646
675
  const marketIndex = order.marketIndex;
647
676
  const marketAccount = this.getMarketAccount(marketIndex);
648
- const bankAccountInfos = [
649
- {
650
- pubkey: this.getQuoteAssetBankAccount().pubkey,
651
- isSigner: false,
652
- isWritable: true,
653
- },
654
- ];
655
- const marketAccountInfos = [
656
- {
657
- pubkey: marketAccount.pubkey,
658
- isWritable: true,
659
- isSigner: false,
660
- },
661
- ];
662
- const oracleAccountInfos = [
663
- {
664
- pubkey: marketAccount.amm.oracle,
665
- isWritable: false,
666
- isSigner: false,
667
- },
668
- ];
677
+ const oracleAccountMap = new Map();
678
+ const bankAccountMap = new Map();
679
+ const marketAccountMap = new Map();
680
+ marketAccountMap.set(marketIndex.toNumber(), {
681
+ pubkey: marketAccount.pubkey,
682
+ isWritable: true,
683
+ isSigner: false,
684
+ });
685
+ oracleAccountMap.set(marketAccount.amm.oracle.toString(), {
686
+ pubkey: marketAccount.amm.oracle,
687
+ isWritable: false,
688
+ isSigner: false,
689
+ });
690
+ for (const bankBalance of userAccount.bankBalances) {
691
+ if (!bankBalance.balance.eq(numericConstants_1.ZERO)) {
692
+ const bankAccount = this.getBankAccount(bankBalance.bankIndex);
693
+ bankAccountMap.set(bankBalance.bankIndex.toNumber(), {
694
+ pubkey: bankAccount.pubkey,
695
+ isSigner: false,
696
+ isWritable: true,
697
+ });
698
+ if (!bankAccount.oracle.equals(web3_js_1.PublicKey.default)) {
699
+ oracleAccountMap.set(bankAccount.oracle.toString(), {
700
+ pubkey: bankAccount.oracle,
701
+ isSigner: false,
702
+ isWritable: false,
703
+ });
704
+ }
705
+ }
706
+ }
669
707
  for (const position of userAccount.positions) {
670
708
  if (!(0, position_1.positionIsAvailable)(position) &&
671
709
  !position.marketIndex.eq(order.marketIndex)) {
672
710
  const market = this.getMarketAccount(position.marketIndex);
673
- marketAccountInfos.push({
711
+ marketAccountMap.set(position.marketIndex.toNumber(), {
674
712
  pubkey: market.pubkey,
675
- isWritable: false,
713
+ isWritable: true,
676
714
  isSigner: false,
677
715
  });
678
- oracleAccountInfos.push({
716
+ oracleAccountMap.set(market.amm.oracle.toString(), {
679
717
  pubkey: market.amm.oracle,
680
718
  isWritable: false,
681
719
  isSigner: false,
682
720
  });
683
721
  }
684
722
  }
685
- const remainingAccounts = oracleAccountInfos.concat(bankAccountInfos.concat(marketAccountInfos));
723
+ const remainingAccounts = [
724
+ ...oracleAccountMap.values(),
725
+ ...bankAccountMap.values(),
726
+ ...marketAccountMap.values(),
727
+ ];
686
728
  const orderId = order.orderId;
687
729
  return await this.program.instruction.triggerOrder(orderId, {
688
730
  accounts: {
@@ -700,6 +742,7 @@ class ClearingHouse {
700
742
  return txSig;
701
743
  }
702
744
  async getPlaceAndTakeIx(orderParams, makerInfo) {
745
+ orderParams = this.getOrderParams(orderParams);
703
746
  const userAccountPublicKey = await this.getUserAccountPublicKey();
704
747
  const remainingAccounts = this.getRemainingAccounts({
705
748
  writableMarketIndex: orderParams.marketIndex,
@@ -723,6 +766,34 @@ class ClearingHouse {
723
766
  remainingAccounts,
724
767
  });
725
768
  }
769
+ async placeAndMake(orderParams, takerInfo) {
770
+ const { txSig, slot } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getPlaceAndMakeIx(orderParams, takerInfo)), [], this.opts);
771
+ this.marketLastSlotCache.set(orderParams.marketIndex.toNumber(), slot);
772
+ return txSig;
773
+ }
774
+ async getPlaceAndMakeIx(orderParams, takerInfo) {
775
+ orderParams = this.getOrderParams(orderParams);
776
+ const userAccountPublicKey = await this.getUserAccountPublicKey();
777
+ const remainingAccounts = this.getRemainingAccounts({
778
+ writableMarketIndex: orderParams.marketIndex,
779
+ writableBankIndex: numericConstants_1.QUOTE_ASSET_BANK_INDEX,
780
+ });
781
+ const takerOrderId = takerInfo.order.orderId;
782
+ remainingAccounts.push({
783
+ pubkey: takerInfo.taker,
784
+ isSigner: false,
785
+ isWritable: true,
786
+ });
787
+ return await this.program.instruction.placeAndMake(orderParams, takerOrderId, {
788
+ accounts: {
789
+ state: await this.getStatePublicKey(),
790
+ user: userAccountPublicKey,
791
+ taker: takerInfo.taker,
792
+ authority: this.wallet.publicKey,
793
+ },
794
+ remainingAccounts,
795
+ });
796
+ }
726
797
  /**
727
798
  * Close an entire position. If you want to reduce a position, use the {@link openPosition} method in the opposite direction of the current position.
728
799
  * @param marketIndex
@@ -733,7 +804,13 @@ class ClearingHouse {
733
804
  if (!userPosition) {
734
805
  throw Error(`No position in market ${marketIndex.toString()}`);
735
806
  }
736
- return await this.placeAndTake((0, orderParams_1.getMarketOrderParams)(marketIndex, (0, position_1.findDirectionToClose)(userPosition), numericConstants_1.ZERO, userPosition.baseAssetAmount, true, undefined));
807
+ return await this.placeAndTake({
808
+ orderType: types_1.OrderType.MARKET,
809
+ marketIndex,
810
+ direction: (0, position_1.findDirectionToClose)(userPosition),
811
+ baseAssetAmount: userPosition.baseAssetAmount,
812
+ reduceOnly: true,
813
+ });
737
814
  }
738
815
  async settlePNLs(users, marketIndex) {
739
816
  const ixs = [];
@@ -814,54 +891,217 @@ class ClearingHouse {
814
891
  remainingAccounts: remainingAccounts,
815
892
  });
816
893
  }
817
- async liquidate(liquidateeUserAccountPublicKey) {
818
- const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getLiquidateIx(liquidateeUserAccountPublicKey)), [], this.opts);
894
+ async liquidatePerp(userAccountPublicKey, userAccount, marketIndex, maxBaseAssetAmount) {
895
+ const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getLiquidatePerpIx(userAccountPublicKey, userAccount, marketIndex, maxBaseAssetAmount)), [], this.opts);
819
896
  return txSig;
820
897
  }
821
- async getLiquidateIx(liquidateeUserAccountPublicKey) {
822
- const userAccountPublicKey = await this.getUserAccountPublicKey();
823
- const liquidateeUserAccount = (await this.program.account.user.fetch(liquidateeUserAccountPublicKey));
824
- const bankAccountInfos = [
825
- {
826
- pubkey: this.getQuoteAssetBankAccount().pubkey,
827
- isSigner: false,
828
- isWritable: true,
898
+ async getLiquidatePerpIx(userAccountPublicKey, userAccount, marketIndex, maxBaseAssetAmount) {
899
+ const liquidatorPublicKey = await this.getUserAccountPublicKey();
900
+ const remainingAccounts = this.getRemainingAccountsForLiquidation({
901
+ writableMarketIndex: marketIndex,
902
+ userAccount,
903
+ });
904
+ return await this.program.instruction.liquidatePerp(marketIndex, maxBaseAssetAmount, {
905
+ accounts: {
906
+ state: await this.getStatePublicKey(),
907
+ authority: this.wallet.publicKey,
908
+ user: userAccountPublicKey,
909
+ liquidator: liquidatorPublicKey,
829
910
  },
830
- ];
831
- const marketAccountInfos = [];
832
- const oracleAccountInfos = [];
911
+ remainingAccounts: remainingAccounts,
912
+ });
913
+ }
914
+ async liquidateBorrow(userAccountPublicKey, userAccount, assetBankIndex, liabilityBankIndex, maxLiabilityTransfer) {
915
+ const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getLiquidateBorrowIx(userAccountPublicKey, userAccount, assetBankIndex, liabilityBankIndex, maxLiabilityTransfer)), [], this.opts);
916
+ return txSig;
917
+ }
918
+ async getLiquidateBorrowIx(userAccountPublicKey, userAccount, assetBankIndex, liabilityBankIndex, maxLiabilityTransfer) {
919
+ const liquidatorPublicKey = await this.getUserAccountPublicKey();
920
+ const remainingAccounts = this.getRemainingAccountsForLiquidation({
921
+ userAccount,
922
+ writableBankIndexes: [liabilityBankIndex, assetBankIndex],
923
+ });
924
+ return await this.program.instruction.liquidateBorrow(assetBankIndex, liabilityBankIndex, maxLiabilityTransfer, {
925
+ accounts: {
926
+ state: await this.getStatePublicKey(),
927
+ authority: this.wallet.publicKey,
928
+ user: userAccountPublicKey,
929
+ liquidator: liquidatorPublicKey,
930
+ },
931
+ remainingAccounts: remainingAccounts,
932
+ });
933
+ }
934
+ async liquidateBorrowForPerpPnl(userAccountPublicKey, userAccount, perpMarketIndex, liabilityBankIndex, maxLiabilityTransfer) {
935
+ const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getLiquidateBorrowForPerpPnlIx(userAccountPublicKey, userAccount, perpMarketIndex, liabilityBankIndex, maxLiabilityTransfer)), [], this.opts);
936
+ return txSig;
937
+ }
938
+ async getLiquidateBorrowForPerpPnlIx(userAccountPublicKey, userAccount, perpMarketIndex, liabilityBankIndex, maxLiabilityTransfer) {
939
+ const liquidatorPublicKey = await this.getUserAccountPublicKey();
940
+ const remainingAccounts = this.getRemainingAccountsForLiquidation({
941
+ userAccount,
942
+ writableMarketIndex: perpMarketIndex,
943
+ writableBankIndexes: [liabilityBankIndex],
944
+ });
945
+ return await this.program.instruction.liquidateBorrowForPerpPnl(perpMarketIndex, liabilityBankIndex, maxLiabilityTransfer, {
946
+ accounts: {
947
+ state: await this.getStatePublicKey(),
948
+ authority: this.wallet.publicKey,
949
+ user: userAccountPublicKey,
950
+ liquidator: liquidatorPublicKey,
951
+ },
952
+ remainingAccounts: remainingAccounts,
953
+ });
954
+ }
955
+ async liquidatePerpPnlForDeposit(userAccountPublicKey, userAccount, perpMarketIndex, assetBankIndex, maxPnlTransfer) {
956
+ const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getLiquidatePerpPnlForDepositIx(userAccountPublicKey, userAccount, perpMarketIndex, assetBankIndex, maxPnlTransfer)), [], this.opts);
957
+ return txSig;
958
+ }
959
+ async getLiquidatePerpPnlForDepositIx(userAccountPublicKey, userAccount, perpMarketIndex, assetBankIndex, maxPnlTransfer) {
960
+ const liquidatorPublicKey = await this.getUserAccountPublicKey();
961
+ const remainingAccounts = this.getRemainingAccountsForLiquidation({
962
+ userAccount,
963
+ writableMarketIndex: perpMarketIndex,
964
+ writableBankIndexes: [assetBankIndex],
965
+ });
966
+ return await this.program.instruction.liquidatePerpPnlForDeposit(perpMarketIndex, assetBankIndex, maxPnlTransfer, {
967
+ accounts: {
968
+ state: await this.getStatePublicKey(),
969
+ authority: this.wallet.publicKey,
970
+ user: userAccountPublicKey,
971
+ liquidator: liquidatorPublicKey,
972
+ },
973
+ remainingAccounts: remainingAccounts,
974
+ });
975
+ }
976
+ getRemainingAccountsForLiquidation(params) {
977
+ const liquidateeUserAccount = params.userAccount;
978
+ const oracleAccountMap = new Map();
979
+ const bankAccountMap = new Map();
980
+ const marketAccountMap = new Map();
981
+ for (const bankBalance of liquidateeUserAccount.bankBalances) {
982
+ if (!bankBalance.balance.eq(numericConstants_1.ZERO)) {
983
+ const bankAccount = this.getBankAccount(bankBalance.bankIndex);
984
+ bankAccountMap.set(bankBalance.bankIndex.toNumber(), {
985
+ pubkey: bankAccount.pubkey,
986
+ isSigner: false,
987
+ isWritable: false,
988
+ });
989
+ if (!bankAccount.oracle.equals(web3_js_1.PublicKey.default)) {
990
+ oracleAccountMap.set(bankAccount.oracle.toString(), {
991
+ pubkey: bankAccount.oracle,
992
+ isSigner: false,
993
+ isWritable: false,
994
+ });
995
+ }
996
+ }
997
+ }
833
998
  for (const position of liquidateeUserAccount.positions) {
834
999
  if (!(0, position_1.positionIsAvailable)(position)) {
835
1000
  const market = this.getMarketAccount(position.marketIndex);
836
- const marketPublicKey = await (0, pda_1.getMarketPublicKey)(this.program.programId, position.marketIndex);
837
- marketAccountInfos.push({
838
- pubkey: marketPublicKey,
839
- isWritable: true,
1001
+ marketAccountMap.set(position.marketIndex.toNumber(), {
1002
+ pubkey: market.pubkey,
1003
+ isWritable: false,
840
1004
  isSigner: false,
841
1005
  });
842
- oracleAccountInfos.push({
1006
+ oracleAccountMap.set(market.amm.oracle.toString(), {
843
1007
  pubkey: market.amm.oracle,
844
1008
  isWritable: false,
845
1009
  isSigner: false,
846
1010
  });
847
1011
  }
848
1012
  }
849
- const remainingAccounts = oracleAccountInfos.concat(bankAccountInfos.concat(marketAccountInfos));
850
- const state = this.getStateAccount();
851
- const quoteAssetBankAccount = this.getQuoteAssetBankAccount();
852
- return await this.program.instruction.liquidate({
853
- accounts: {
854
- state: await this.getStatePublicKey(),
855
- authority: this.wallet.publicKey,
856
- user: liquidateeUserAccountPublicKey,
857
- liquidator: userAccountPublicKey,
858
- bankVault: quoteAssetBankAccount.vault,
859
- bankVaultAuthority: quoteAssetBankAccount.vaultAuthority,
860
- insuranceVault: state.insuranceVault,
861
- tokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
862
- },
863
- remainingAccounts: remainingAccounts,
864
- });
1013
+ const userAccountAndSlot = this.getUserAccountAndSlot();
1014
+ if (!userAccountAndSlot) {
1015
+ throw Error('No user account found. Most likely user account does not exist or failed to fetch account');
1016
+ }
1017
+ const { data: userAccount, slot: lastUserPositionsSlot } = userAccountAndSlot;
1018
+ for (const [marketIndexNum, slot] of this.marketLastSlotCache.entries()) {
1019
+ // if cache has more recent slot than user positions account slot, add market to remaining accounts
1020
+ // otherwise remove from slot
1021
+ if (slot > lastUserPositionsSlot) {
1022
+ const marketAccount = this.getMarketAccount(marketIndexNum);
1023
+ marketAccountMap.set(marketIndexNum, {
1024
+ pubkey: marketAccount.pubkey,
1025
+ isSigner: false,
1026
+ isWritable: false,
1027
+ });
1028
+ oracleAccountMap.set(marketAccount.amm.oracle.toString(), {
1029
+ pubkey: marketAccount.amm.oracle,
1030
+ isSigner: false,
1031
+ isWritable: false,
1032
+ });
1033
+ }
1034
+ else {
1035
+ this.marketLastSlotCache.delete(marketIndexNum);
1036
+ }
1037
+ }
1038
+ for (const bankBalance of userAccount.bankBalances) {
1039
+ if (!bankBalance.balance.eq(numericConstants_1.ZERO)) {
1040
+ const bankAccount = this.getBankAccount(bankBalance.bankIndex);
1041
+ bankAccountMap.set(bankBalance.bankIndex.toNumber(), {
1042
+ pubkey: bankAccount.pubkey,
1043
+ isSigner: false,
1044
+ isWritable: false,
1045
+ });
1046
+ if (!bankAccount.oracle.equals(web3_js_1.PublicKey.default)) {
1047
+ oracleAccountMap.set(bankAccount.oracle.toString(), {
1048
+ pubkey: bankAccount.oracle,
1049
+ isSigner: false,
1050
+ isWritable: false,
1051
+ });
1052
+ }
1053
+ }
1054
+ }
1055
+ for (const position of userAccount.positions) {
1056
+ if (!(0, position_1.positionIsAvailable)(position)) {
1057
+ const market = this.getMarketAccount(position.marketIndex);
1058
+ marketAccountMap.set(position.marketIndex.toNumber(), {
1059
+ pubkey: market.pubkey,
1060
+ isWritable: false,
1061
+ isSigner: false,
1062
+ });
1063
+ oracleAccountMap.set(market.amm.oracle.toString(), {
1064
+ pubkey: market.amm.oracle,
1065
+ isWritable: false,
1066
+ isSigner: false,
1067
+ });
1068
+ }
1069
+ }
1070
+ if (params.writableMarketIndex) {
1071
+ const market = this.getMarketAccount(params.writableMarketIndex);
1072
+ marketAccountMap.set(market.marketIndex.toNumber(), {
1073
+ pubkey: market.pubkey,
1074
+ isSigner: false,
1075
+ isWritable: true,
1076
+ });
1077
+ oracleAccountMap.set(market.amm.oracle.toString(), {
1078
+ pubkey: market.amm.oracle,
1079
+ isSigner: false,
1080
+ isWritable: false,
1081
+ });
1082
+ }
1083
+ if (params.writableBankIndexes) {
1084
+ for (const writableBankIndex of params.writableBankIndexes) {
1085
+ const bank = this.getBankAccount(writableBankIndex);
1086
+ bankAccountMap.set(bank.bankIndex.toNumber(), {
1087
+ pubkey: bank.pubkey,
1088
+ isSigner: false,
1089
+ isWritable: true,
1090
+ });
1091
+ if (!bank.oracle.equals(web3_js_1.PublicKey.default)) {
1092
+ oracleAccountMap.set(bank.oracle.toString(), {
1093
+ pubkey: bank.oracle,
1094
+ isSigner: false,
1095
+ isWritable: false,
1096
+ });
1097
+ }
1098
+ }
1099
+ }
1100
+ return [
1101
+ ...oracleAccountMap.values(),
1102
+ ...bankAccountMap.values(),
1103
+ ...marketAccountMap.values(),
1104
+ ];
865
1105
  }
866
1106
  async updateFundingRate(oracle, marketIndex) {
867
1107
  const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getUpdateFundingRateIx(oracle, marketIndex)), [], this.opts);
@@ -63,7 +63,7 @@ export declare class ClearingHouseUser {
63
63
  /**
64
64
  * @returns The partial margin requirement in USDC. : QUOTE_PRECISION
65
65
  */
66
- getPartialMarginRequirement(): BN;
66
+ getMaintenanceMarginRequirement(): BN;
67
67
  /**
68
68
  * calculates unrealized position price pnl
69
69
  * @returns : Precision QUOTE_PRECISION
@@ -132,7 +132,7 @@ export declare class ClearingHouseUser {
132
132
  * @param partial
133
133
  * @returns Precision : MARK_PRICE_PRECISION
134
134
  */
135
- liquidationPrice(marketPosition: Pick<UserPosition, 'marketIndex'>, positionBaseSizeChange?: BN, partial?: boolean): BN;
135
+ liquidationPrice(marketPosition: Pick<UserPosition, 'marketIndex'>, positionBaseSizeChange?: BN): BN;
136
136
  /**
137
137
  * Calculates the estimated liquidation price for a position after closing a quote amount of the position.
138
138
  * @param positionMarketIndex
@@ -126,12 +126,12 @@ class ClearingHouseUser {
126
126
  /**
127
127
  * @returns The partial margin requirement in USDC. : QUOTE_PRECISION
128
128
  */
129
- getPartialMarginRequirement() {
129
+ getMaintenanceMarginRequirement() {
130
130
  return this.getUserAccount()
131
131
  .positions.reduce((marginRequirement, marketPosition) => {
132
132
  const market = this.clearingHouse.getMarketAccount(marketPosition.marketIndex);
133
133
  return marginRequirement.add((0, _1.calculateBaseAssetValue)(market, marketPosition, this.getOracleDataForMarket(market.marketIndex))
134
- .mul(new _1.BN(market.marginRatioPartial))
134
+ .mul(new _1.BN(market.marginRatioMaintenance))
135
135
  .div(numericConstants_1.MARGIN_PRECISION));
136
136
  }, numericConstants_1.ZERO)
137
137
  .add(this.getTotalLiability());
@@ -319,9 +319,6 @@ class ClearingHouseUser {
319
319
  case 'Maintenance':
320
320
  marginRatioCategory = market.marginRatioMaintenance;
321
321
  break;
322
- case 'Partial':
323
- marginRatioCategory = market.marginRatioPartial;
324
- break;
325
322
  default:
326
323
  marginRatioCategory = market.marginRatioInitial;
327
324
  break;
@@ -342,7 +339,7 @@ class ClearingHouseUser {
342
339
  }
343
340
  canBeLiquidated() {
344
341
  const totalCollateral = this.getTotalCollateral();
345
- const partialMaintenanceRequirement = this.getPartialMarginRequirement();
342
+ const partialMaintenanceRequirement = this.getMaintenanceMarginRequirement();
346
343
  const marginRatio = this.getMarginRatio();
347
344
  const canLiquidate = totalCollateral.lt(partialMaintenanceRequirement);
348
345
  return [canLiquidate, marginRatio];
@@ -372,7 +369,7 @@ class ClearingHouseUser {
372
369
  * @param partial
373
370
  * @returns Precision : MARK_PRICE_PRECISION
374
371
  */
375
- liquidationPrice(marketPosition, positionBaseSizeChange = numericConstants_1.ZERO, partial = false) {
372
+ liquidationPrice(marketPosition, positionBaseSizeChange = numericConstants_1.ZERO) {
376
373
  // solves formula for example canBeLiquidated below
377
374
  /* example: assume BTC price is $40k (examine 10% up/down)
378
375
 
@@ -413,9 +410,7 @@ class ClearingHouseUser {
413
410
  const market = this.clearingHouse.getMarketAccount(position.marketIndex);
414
411
  const positionValue = (0, _1.calculateBaseAssetValue)(market, position, this.getOracleDataForMarket(market.marketIndex));
415
412
  const marketMarginRequirement = positionValue
416
- .mul(partial
417
- ? new _1.BN(market.marginRatioPartial)
418
- : new _1.BN(market.marginRatioMaintenance))
413
+ .mul(new _1.BN(market.marginRatioMaintenance))
419
414
  .div(numericConstants_1.MARGIN_PRECISION);
420
415
  totalMarginRequirement = totalMarginRequirement.add(marketMarginRequirement);
421
416
  }
@@ -428,14 +423,10 @@ class ClearingHouseUser {
428
423
  return new _1.BN(-1);
429
424
  }
430
425
  const marginRequirementAfterTrade = marginRequirementExcludingTargetMarket.add(proposedMarketPositionValue
431
- .mul(partial
432
- ? new _1.BN(market.marginRatioPartial)
433
- : new _1.BN(market.marginRatioMaintenance))
426
+ .mul(new _1.BN(market.marginRatioMaintenance))
434
427
  .div(numericConstants_1.MARGIN_PRECISION));
435
428
  const freeCollateralAfterTrade = totalCollateral.sub(marginRequirementAfterTrade);
436
- const marketMaxLeverage = partial
437
- ? this.getMaxLeverage(proposedMarketPosition.marketIndex, 'Partial')
438
- : this.getMaxLeverage(proposedMarketPosition.marketIndex, 'Maintenance');
429
+ const marketMaxLeverage = this.getMaxLeverage(proposedMarketPosition.marketIndex, 'Maintenance');
439
430
  let priceDelta;
440
431
  if (proposedBaseAssetAmount.lt(numericConstants_1.ZERO)) {
441
432
  priceDelta = freeCollateralAfterTrade
@@ -486,7 +477,7 @@ class ClearingHouseUser {
486
477
  .neg();
487
478
  return this.liquidationPrice({
488
479
  marketIndex: positionMarketIndex,
489
- }, closeBaseAmount, true);
480
+ }, closeBaseAmount);
490
481
  }
491
482
  /**
492
483
  * Get the maximum trade size for a given market, taking into account the user's current leverage, positions, collateral, etc.
package/lib/config.js CHANGED
@@ -7,7 +7,7 @@ exports.configs = {
7
7
  devnet: {
8
8
  ENV: 'devnet',
9
9
  PYTH_ORACLE_MAPPING_ADDRESS: 'BmA9Z6FjioHJPpjT39QazZyhDRUdZy2ezwx4GiDdE2u2',
10
- CLEARING_HOUSE_PROGRAM_ID: '9jwr5nC2f9yAraXrg4UzHXmCX3vi9FQkjD6p9e8bRqNa',
10
+ CLEARING_HOUSE_PROGRAM_ID: '4oyTJnAQ9FqJj1y9mPytbWsLeeHmBzGYfuFqypwyQvuh',
11
11
  USDC_MINT_ADDRESS: '8zGuJQqwhZafTah7Uc7Z4tXRnguqkn5KLFAP8oV6PHe2',
12
12
  MARKETS: markets_1.DevnetMarkets,
13
13
  BANKS: banks_1.DevnetBanks,