@drift-labs/sdk 0.2.0-master.0 → 0.2.0-master.11

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 (121) hide show
  1. package/lib/admin.d.ts +8 -5
  2. package/lib/admin.js +43 -11
  3. package/lib/clearingHouse.d.ts +28 -18
  4. package/lib/clearingHouse.js +366 -143
  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 +2 -0
  10. package/lib/constants/numericConstants.js +3 -1
  11. package/lib/factory/bigNum.d.ts +8 -2
  12. package/lib/factory/bigNum.js +14 -6
  13. package/lib/idl/clearing_house.json +805 -202
  14. package/lib/idl/{mock_usdc_faucet.json → token_faucet.json} +46 -23
  15. package/lib/index.d.ts +3 -2
  16. package/lib/index.js +7 -2
  17. package/lib/math/amm.d.ts +6 -1
  18. package/lib/math/amm.js +124 -41
  19. package/lib/math/auction.js +4 -1
  20. package/lib/math/orders.d.ts +2 -2
  21. package/lib/math/orders.js +18 -11
  22. package/lib/math/position.js +3 -1
  23. package/lib/math/repeg.js +1 -1
  24. package/lib/math/trade.d.ts +1 -1
  25. package/lib/math/trade.js +7 -10
  26. package/lib/orderParams.d.ts +14 -5
  27. package/lib/orderParams.js +8 -96
  28. package/lib/orders.d.ts +1 -2
  29. package/lib/orders.js +6 -85
  30. package/lib/slot/SlotSubscriber.d.ts +7 -0
  31. package/lib/slot/SlotSubscriber.js +3 -0
  32. package/lib/{mockUSDCFaucet.d.ts → tokenFaucet.d.ts} +7 -5
  33. package/lib/{mockUSDCFaucet.js → tokenFaucet.js} +41 -40
  34. package/lib/tx/utils.js +1 -1
  35. package/lib/types.d.ts +137 -14
  36. package/lib/types.js +53 -1
  37. package/lib/util/computeUnits.js +1 -1
  38. package/package.json +3 -3
  39. package/src/accounts/bulkAccountLoader.js +197 -0
  40. package/src/accounts/bulkUserSubscription.js +33 -0
  41. package/src/accounts/fetch.js +29 -0
  42. package/src/accounts/pollingClearingHouseAccountSubscriber.js +311 -0
  43. package/src/accounts/pollingOracleSubscriber.js +93 -0
  44. package/src/accounts/pollingTokenAccountSubscriber.js +90 -0
  45. package/src/accounts/pollingUserAccountSubscriber.js +132 -0
  46. package/src/accounts/types.js +10 -0
  47. package/src/accounts/utils.js +7 -0
  48. package/src/accounts/webSocketAccountSubscriber.js +93 -0
  49. package/src/accounts/webSocketClearingHouseAccountSubscriber.js +233 -0
  50. package/src/accounts/webSocketUserAccountSubscriber.js +62 -0
  51. package/src/addresses/marketAddresses.js +26 -0
  52. package/src/addresses/pda.js +104 -0
  53. package/src/admin.ts +66 -14
  54. package/src/assert/assert.js +9 -0
  55. package/src/clearingHouse.ts +558 -230
  56. package/src/clearingHouseUser.ts +12 -23
  57. package/src/config.ts +1 -1
  58. package/src/constants/banks.ts +9 -2
  59. package/src/constants/numericConstants.ts +2 -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 +364 -0
  70. package/src/factory/bigNum.ts +26 -9
  71. package/src/factory/oracleClient.js +20 -0
  72. package/src/idl/clearing_house.json +805 -202
  73. package/src/idl/{mock_usdc_faucet.json → token_faucet.json} +46 -23
  74. package/src/index.js +100 -0
  75. package/src/index.ts +3 -2
  76. package/src/math/amm.js +369 -0
  77. package/src/math/amm.ts +207 -52
  78. package/src/math/auction.js +42 -0
  79. package/src/math/auction.ts +5 -1
  80. package/src/math/bankBalance.js +75 -0
  81. package/src/math/conversion.js +11 -0
  82. package/src/math/funding.js +248 -0
  83. package/src/math/market.js +57 -0
  84. package/src/math/oracles.js +26 -0
  85. package/src/math/orders.js +110 -0
  86. package/src/math/orders.ts +17 -13
  87. package/src/math/position.js +140 -0
  88. package/src/math/position.ts +5 -1
  89. package/src/math/repeg.js +128 -0
  90. package/src/math/repeg.ts +2 -1
  91. package/src/math/state.js +15 -0
  92. package/src/math/trade.js +253 -0
  93. package/src/math/trade.ts +23 -25
  94. package/src/math/utils.js +0 -1
  95. package/src/mockUSDCFaucet.js +280 -0
  96. package/src/oracles/oracleClientCache.js +19 -0
  97. package/src/oracles/pythClient.js +46 -0
  98. package/src/oracles/quoteAssetOracleClient.js +32 -0
  99. package/src/oracles/switchboardClient.js +69 -0
  100. package/src/oracles/types.js +2 -0
  101. package/src/orderParams.js +20 -0
  102. package/src/orderParams.ts +20 -141
  103. package/src/orders.js +134 -0
  104. package/src/orders.ts +7 -131
  105. package/src/slot/SlotSubscriber.js +39 -0
  106. package/src/slot/SlotSubscriber.ts +11 -1
  107. package/src/token/index.js +38 -0
  108. package/src/{mockUSDCFaucet.ts → tokenFaucet.ts} +48 -59
  109. package/src/tx/retryTxSender.js +188 -0
  110. package/src/tx/types.js +2 -0
  111. package/src/tx/utils.js +17 -0
  112. package/src/tx/utils.ts +1 -1
  113. package/src/types.js +114 -0
  114. package/src/types.ts +132 -16
  115. package/src/userName.js +20 -0
  116. package/src/util/computeUnits.ts +1 -1
  117. package/src/util/promiseTimeout.js +14 -0
  118. package/src/util/tps.js +27 -0
  119. package/src/wallet.js +35 -0
  120. package/src/util/computeUnits.js +0 -17
  121. 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,17 +488,25 @@ 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
- const priceOracle = this.getMarketAccount(orderParams.marketIndex).amm
495
- .oracle;
496
510
  const remainingAccounts = this.getRemainingAccounts({
497
511
  writableMarketIndex: orderParams.marketIndex,
498
512
  });
@@ -501,26 +515,10 @@ class ClearingHouse {
501
515
  state: await this.getStatePublicKey(),
502
516
  user: userAccountPublicKey,
503
517
  authority: this.wallet.publicKey,
504
- oracle: priceOracle,
505
518
  },
506
519
  remainingAccounts,
507
520
  });
508
521
  }
509
- async expireOrders(userAccountPublicKey) {
510
- const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getExpireOrdersIx(userAccountPublicKey)), [], this.opts);
511
- return txSig;
512
- }
513
- async getExpireOrdersIx(userAccountPublicKey) {
514
- const fillerPublicKey = await this.getUserAccountPublicKey();
515
- return await this.program.instruction.expireOrders({
516
- accounts: {
517
- state: await this.getStatePublicKey(),
518
- filler: fillerPublicKey,
519
- user: userAccountPublicKey,
520
- authority: this.wallet.publicKey,
521
- },
522
- });
523
- }
524
522
  async updateAMMs(marketIndexes) {
525
523
  const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getUpdateAMMsIx(marketIndexes)), [], this.opts);
526
524
  return txSig;
@@ -561,15 +559,12 @@ class ClearingHouse {
561
559
  }
562
560
  async getCancelOrderIx(orderId) {
563
561
  const userAccountPublicKey = await this.getUserAccountPublicKey();
564
- const order = this.getOrder(orderId);
565
- const oracle = this.getMarketAccount(order.marketIndex).amm.oracle;
566
562
  const remainingAccounts = this.getRemainingAccounts({});
567
- return await this.program.instruction.cancelOrder(orderId, {
563
+ return await this.program.instruction.cancelOrder(orderId !== null && orderId !== void 0 ? orderId : null, {
568
564
  accounts: {
569
565
  state: await this.getStatePublicKey(),
570
566
  user: userAccountPublicKey,
571
567
  authority: this.wallet.publicKey,
572
- oracle,
573
568
  },
574
569
  remainingAccounts,
575
570
  });
@@ -593,117 +588,150 @@ class ClearingHouse {
593
588
  remainingAccounts,
594
589
  });
595
590
  }
596
- async cancelAllOrders(bestEffort) {
597
- const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getCancelAllOrdersIx(bestEffort)), [], this.opts);
591
+ async fillOrder(userAccountPublicKey, user, order, makerInfo) {
592
+ const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getFillOrderIx(userAccountPublicKey, user, order, makerInfo)), [], this.opts);
598
593
  return txSig;
599
594
  }
600
- async getCancelAllOrdersIx(bestEffort) {
601
- const userAccountPublicKey = await this.getUserAccountPublicKey();
602
- const remainingAccounts = this.getRemainingAccounts({});
603
- for (const order of this.getUserAccount().orders) {
604
- const oracle = this.getMarketAccount(order.marketIndex).amm.oracle;
605
- remainingAccounts.push({
606
- pubkey: oracle,
607
- isWritable: false,
608
- isSigner: false,
609
- });
610
- }
611
- return await this.program.instruction.cancelAllOrders(bestEffort, {
612
- accounts: {
613
- state: await this.getStatePublicKey(),
614
- user: userAccountPublicKey,
615
- authority: this.wallet.publicKey,
616
- },
617
- remainingAccounts,
595
+ async getFillOrderIx(userAccountPublicKey, userAccount, order, makerInfo) {
596
+ const fillerPublicKey = await this.getUserAccountPublicKey();
597
+ const marketIndex = order.marketIndex;
598
+ const marketAccount = this.getMarketAccount(marketIndex);
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,
618
606
  });
619
- }
620
- async cancelOrdersByMarketAndSide(bestEffort, marketIndexOnly, directionOnly) {
621
- const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getCancelOrdersByMarketAndSideIx(bestEffort, marketIndexOnly, directionOnly)), [], this.opts);
622
- return txSig;
623
- }
624
- async getCancelOrdersByMarketAndSideIx(bestEffort, marketIndexOnly, directionOnly) {
625
- const userAccountPublicKey = await this.getUserAccountPublicKey();
626
- const remainingAccounts = this.getRemainingAccounts({});
627
- for (const order of this.getUserAccount().orders) {
628
- const oracle = this.getMarketAccount(order.marketIndex).amm.oracle;
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
+ }
629
+ for (const position of userAccount.positions) {
630
+ if (!(0, position_1.positionIsAvailable)(position) &&
631
+ !position.marketIndex.eq(order.marketIndex)) {
632
+ const market = this.getMarketAccount(position.marketIndex);
633
+ marketAccountMap.set(position.marketIndex.toNumber(), {
634
+ pubkey: market.pubkey,
635
+ isWritable: true,
636
+ isSigner: false,
637
+ });
638
+ oracleAccountMap.set(market.amm.oracle.toString(), {
639
+ pubkey: market.amm.oracle,
640
+ isWritable: false,
641
+ isSigner: false,
642
+ });
643
+ }
644
+ }
645
+ const remainingAccounts = [
646
+ ...oracleAccountMap.values(),
647
+ ...bankAccountMap.values(),
648
+ ...marketAccountMap.values(),
649
+ ];
650
+ if (makerInfo) {
629
651
  remainingAccounts.push({
630
- pubkey: oracle,
631
- isWritable: false,
652
+ pubkey: makerInfo.maker,
653
+ isWritable: true,
632
654
  isSigner: false,
633
655
  });
634
656
  }
635
- return await this.program.instruction.cancelOrdersByMarketAndSide(bestEffort, marketIndexOnly, directionOnly, {
657
+ const orderId = order.orderId;
658
+ const makerOrderId = makerInfo ? makerInfo.order.orderId : null;
659
+ return await this.program.instruction.fillOrder(orderId, makerOrderId, {
636
660
  accounts: {
637
661
  state: await this.getStatePublicKey(),
662
+ filler: fillerPublicKey,
638
663
  user: userAccountPublicKey,
639
664
  authority: this.wallet.publicKey,
640
665
  },
641
666
  remainingAccounts,
642
667
  });
643
668
  }
644
- async fillOrder(userAccountPublicKey, user, order, makerInfo) {
645
- const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getFillOrderIx(userAccountPublicKey, user, order, makerInfo)), [], this.opts);
669
+ async triggerOrder(userAccountPublicKey, user, order) {
670
+ const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getTriggerOrderIx(userAccountPublicKey, user, order)), [], this.opts);
646
671
  return txSig;
647
672
  }
648
- async getFillOrderIx(userAccountPublicKey, userAccount, order, makerInfo) {
673
+ async getTriggerOrderIx(userAccountPublicKey, userAccount, order) {
649
674
  const fillerPublicKey = await this.getUserAccountPublicKey();
650
675
  const marketIndex = order.marketIndex;
651
676
  const marketAccount = this.getMarketAccount(marketIndex);
652
- const oracle = marketAccount.amm.oracle;
653
- const bankAccountInfos = [
654
- {
655
- pubkey: this.getQuoteAssetBankAccount().pubkey,
656
- isSigner: false,
657
- isWritable: true,
658
- },
659
- ];
660
- const marketAccountInfos = [
661
- {
662
- pubkey: marketAccount.pubkey,
663
- isWritable: true,
664
- isSigner: false,
665
- },
666
- ];
667
- const oracleAccountInfos = [
668
- {
669
- pubkey: marketAccount.amm.oracle,
670
- isWritable: false,
671
- isSigner: false,
672
- },
673
- ];
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
+ }
674
707
  for (const position of userAccount.positions) {
675
708
  if (!(0, position_1.positionIsAvailable)(position) &&
676
709
  !position.marketIndex.eq(order.marketIndex)) {
677
710
  const market = this.getMarketAccount(position.marketIndex);
678
- marketAccountInfos.push({
711
+ marketAccountMap.set(position.marketIndex.toNumber(), {
679
712
  pubkey: market.pubkey,
680
- isWritable: false,
713
+ isWritable: true,
681
714
  isSigner: false,
682
715
  });
683
- oracleAccountInfos.push({
716
+ oracleAccountMap.set(market.amm.oracle.toString(), {
684
717
  pubkey: market.amm.oracle,
685
718
  isWritable: false,
686
719
  isSigner: false,
687
720
  });
688
721
  }
689
722
  }
690
- const remainingAccounts = oracleAccountInfos.concat(bankAccountInfos.concat(marketAccountInfos));
691
- if (makerInfo) {
692
- remainingAccounts.push({
693
- pubkey: makerInfo.maker,
694
- isWritable: true,
695
- isSigner: false,
696
- });
697
- }
723
+ const remainingAccounts = [
724
+ ...oracleAccountMap.values(),
725
+ ...bankAccountMap.values(),
726
+ ...marketAccountMap.values(),
727
+ ];
698
728
  const orderId = order.orderId;
699
- const makerOrderId = makerInfo ? makerInfo.order.orderId : null;
700
- return await this.program.instruction.fillOrder(orderId, makerOrderId, {
729
+ return await this.program.instruction.triggerOrder(orderId, {
701
730
  accounts: {
702
731
  state: await this.getStatePublicKey(),
703
732
  filler: fillerPublicKey,
704
733
  user: userAccountPublicKey,
705
734
  authority: this.wallet.publicKey,
706
- oracle: oracle,
707
735
  },
708
736
  remainingAccounts,
709
737
  });
@@ -714,9 +742,8 @@ class ClearingHouse {
714
742
  return txSig;
715
743
  }
716
744
  async getPlaceAndTakeIx(orderParams, makerInfo) {
745
+ orderParams = this.getOrderParams(orderParams);
717
746
  const userAccountPublicKey = await this.getUserAccountPublicKey();
718
- const priceOracle = this.getMarketAccount(orderParams.marketIndex).amm
719
- .oracle;
720
747
  const remainingAccounts = this.getRemainingAccounts({
721
748
  writableMarketIndex: orderParams.marketIndex,
722
749
  writableBankIndex: numericConstants_1.QUOTE_ASSET_BANK_INDEX,
@@ -735,7 +762,34 @@ class ClearingHouse {
735
762
  state: await this.getStatePublicKey(),
736
763
  user: userAccountPublicKey,
737
764
  authority: this.wallet.publicKey,
738
- oracle: priceOracle,
765
+ },
766
+ remainingAccounts,
767
+ });
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,
739
793
  },
740
794
  remainingAccounts,
741
795
  });
@@ -750,7 +804,13 @@ class ClearingHouse {
750
804
  if (!userPosition) {
751
805
  throw Error(`No position in market ${marketIndex.toString()}`);
752
806
  }
753
- 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
+ });
754
814
  }
755
815
  async settlePNLs(users, marketIndex) {
756
816
  const ixs = [];
@@ -831,54 +891,217 @@ class ClearingHouse {
831
891
  remainingAccounts: remainingAccounts,
832
892
  });
833
893
  }
834
- async liquidate(liquidateeUserAccountPublicKey) {
835
- 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);
836
896
  return txSig;
837
897
  }
838
- async getLiquidateIx(liquidateeUserAccountPublicKey) {
839
- const userAccountPublicKey = await this.getUserAccountPublicKey();
840
- const liquidateeUserAccount = (await this.program.account.user.fetch(liquidateeUserAccountPublicKey));
841
- const bankAccountInfos = [
842
- {
843
- pubkey: this.getQuoteAssetBankAccount().pubkey,
844
- isSigner: false,
845
- 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,
846
910
  },
847
- ];
848
- const marketAccountInfos = [];
849
- 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
+ }
850
998
  for (const position of liquidateeUserAccount.positions) {
851
999
  if (!(0, position_1.positionIsAvailable)(position)) {
852
1000
  const market = this.getMarketAccount(position.marketIndex);
853
- const marketPublicKey = await (0, pda_1.getMarketPublicKey)(this.program.programId, position.marketIndex);
854
- marketAccountInfos.push({
855
- pubkey: marketPublicKey,
856
- isWritable: true,
1001
+ marketAccountMap.set(position.marketIndex.toNumber(), {
1002
+ pubkey: market.pubkey,
1003
+ isWritable: false,
857
1004
  isSigner: false,
858
1005
  });
859
- oracleAccountInfos.push({
1006
+ oracleAccountMap.set(market.amm.oracle.toString(), {
860
1007
  pubkey: market.amm.oracle,
861
1008
  isWritable: false,
862
1009
  isSigner: false,
863
1010
  });
864
1011
  }
865
1012
  }
866
- const remainingAccounts = oracleAccountInfos.concat(bankAccountInfos.concat(marketAccountInfos));
867
- const state = this.getStateAccount();
868
- const quoteAssetBankAccount = this.getQuoteAssetBankAccount();
869
- return await this.program.instruction.liquidate({
870
- accounts: {
871
- state: await this.getStatePublicKey(),
872
- authority: this.wallet.publicKey,
873
- user: liquidateeUserAccountPublicKey,
874
- liquidator: userAccountPublicKey,
875
- bankVault: quoteAssetBankAccount.vault,
876
- bankVaultAuthority: quoteAssetBankAccount.vaultAuthority,
877
- insuranceVault: state.insuranceVault,
878
- tokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
879
- },
880
- remainingAccounts: remainingAccounts,
881
- });
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
+ ];
882
1105
  }
883
1106
  async updateFundingRate(oracle, marketIndex) {
884
1107
  const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getUpdateFundingRateIx(oracle, marketIndex)), [], this.opts);