@drift-labs/sdk 0.2.0-master.10 → 0.2.0-master.13

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 (82) hide show
  1. package/lib/admin.d.ts +3 -3
  2. package/lib/admin.js +6 -6
  3. package/lib/clearingHouse.d.ts +22 -6
  4. package/lib/clearingHouse.js +357 -74
  5. package/lib/clearingHouseUser.d.ts +12 -17
  6. package/lib/clearingHouseUser.js +97 -88
  7. package/lib/config.js +1 -1
  8. package/lib/constants/banks.d.ts +2 -2
  9. package/lib/constants/banks.js +5 -4
  10. package/lib/constants/numericConstants.d.ts +3 -0
  11. package/lib/constants/numericConstants.js +4 -1
  12. package/lib/events/eventList.js +3 -0
  13. package/lib/events/types.d.ts +2 -1
  14. package/lib/factory/bigNum.d.ts +1 -0
  15. package/lib/factory/bigNum.js +37 -11
  16. package/lib/idl/clearing_house.json +611 -146
  17. package/lib/idl/{mock_usdc_faucet.json → token_faucet.json} +46 -23
  18. package/lib/index.d.ts +2 -1
  19. package/lib/index.js +2 -1
  20. package/lib/math/amm.js +2 -2
  21. package/lib/math/bankBalance.d.ts +3 -1
  22. package/lib/math/bankBalance.js +54 -1
  23. package/lib/math/margin.d.ts +11 -0
  24. package/lib/math/margin.js +72 -0
  25. package/lib/math/market.d.ts +4 -1
  26. package/lib/math/market.js +35 -1
  27. package/lib/math/position.d.ts +8 -0
  28. package/lib/math/position.js +42 -12
  29. package/lib/orders.d.ts +1 -2
  30. package/lib/orders.js +2 -77
  31. package/lib/{mockUSDCFaucet.d.ts → tokenFaucet.d.ts} +8 -5
  32. package/lib/{mockUSDCFaucet.js → tokenFaucet.js} +63 -51
  33. package/lib/tx/retryTxSender.js +9 -2
  34. package/lib/types.d.ts +86 -16
  35. package/lib/types.js +18 -1
  36. package/lib/util/computeUnits.js +1 -1
  37. package/lib/util/getTokenAddress.d.ts +2 -0
  38. package/lib/util/getTokenAddress.js +9 -0
  39. package/package.json +1 -1
  40. package/src/admin.ts +7 -7
  41. package/src/clearingHouse.ts +636 -94
  42. package/src/clearingHouseConfig.js +2 -0
  43. package/src/clearingHouseUser.ts +219 -121
  44. package/src/clearingHouseUserConfig.js +2 -0
  45. package/src/config.ts +1 -1
  46. package/src/constants/banks.js +42 -0
  47. package/src/constants/banks.ts +7 -4
  48. package/src/constants/markets.js +42 -0
  49. package/src/constants/numericConstants.js +41 -0
  50. package/src/constants/numericConstants.ts +4 -0
  51. package/src/events/eventList.ts +3 -0
  52. package/src/events/types.ts +2 -0
  53. package/src/factory/bigNum.js +37 -11
  54. package/src/factory/bigNum.ts +43 -13
  55. package/src/idl/clearing_house.json +611 -146
  56. package/src/idl/{mock_usdc_faucet.json → token_faucet.json} +46 -23
  57. package/src/index.js +1 -1
  58. package/src/index.ts +2 -1
  59. package/src/math/amm.ts +8 -5
  60. package/src/math/bankBalance.ts +98 -1
  61. package/src/math/margin.ts +124 -0
  62. package/src/math/market.ts +66 -1
  63. package/src/math/position.ts +59 -9
  64. package/src/mockUSDCFaucet.js +276 -167
  65. package/src/orders.ts +4 -157
  66. package/src/tokenFaucet.js +189 -0
  67. package/src/{mockUSDCFaucet.ts → tokenFaucet.ts} +82 -70
  68. package/src/tx/retryTxSender.ts +11 -3
  69. package/src/types.js +12 -1
  70. package/src/types.ts +88 -16
  71. package/src/{accounts/fetch.js → util/computeUnits.js} +11 -13
  72. package/src/util/computeUnits.ts +1 -1
  73. package/src/util/getTokenAddress.js +9 -0
  74. package/src/util/getTokenAddress.ts +18 -0
  75. package/tests/bn/test.ts +2 -0
  76. package/src/addresses/pda.js +0 -104
  77. package/src/math/bankBalance.js +0 -75
  78. package/src/math/market.js +0 -57
  79. package/src/math/orders.js +0 -110
  80. package/src/math/position.js +0 -140
  81. package/src/orders.js +0 -134
  82. package/src/tx/retryTxSender.js +0 -188
@@ -44,6 +44,7 @@ const webSocketClearingHouseAccountSubscriber_1 = require("./accounts/webSocketC
44
44
  const retryTxSender_1 = require("./tx/retryTxSender");
45
45
  const clearingHouseUser_1 = require("./clearingHouseUser");
46
46
  const config_1 = require("./config");
47
+ const banks_1 = require("./constants/banks");
47
48
  /**
48
49
  * # ClearingHouse
49
50
  * This class is the main way to interact with Drift Protocol. It allows you to subscribe to the various accounts where the Market's state is stored, as well as: opening positions, liquidating, settling funding, depositing & withdrawing, and more.
@@ -284,8 +285,7 @@ class ClearingHouse {
284
285
  marketAccountMap.set(marketIndexNum, {
285
286
  pubkey: marketAccount.pubkey,
286
287
  isSigner: false,
287
- // isWritable: false, // TODO
288
- isWritable: true,
288
+ isWritable: false,
289
289
  });
290
290
  oracleAccountMap.set(marketAccount.pubkey.toString(), {
291
291
  pubkey: marketAccount.amm.oracle,
@@ -294,6 +294,19 @@ class ClearingHouse {
294
294
  });
295
295
  }
296
296
  }
297
+ if (params.readableMarketIndex) {
298
+ const marketAccount = this.getMarketAccount(params.readableMarketIndex.toNumber());
299
+ marketAccountMap.set(params.readableMarketIndex.toNumber(), {
300
+ pubkey: marketAccount.pubkey,
301
+ isSigner: false,
302
+ isWritable: true,
303
+ });
304
+ oracleAccountMap.set(marketAccount.amm.oracle.toString(), {
305
+ pubkey: marketAccount.amm.oracle,
306
+ isSigner: false,
307
+ isWritable: false,
308
+ });
309
+ }
297
310
  if (params.writableMarketIndex) {
298
311
  const marketAccount = this.getMarketAccount(params.writableMarketIndex.toNumber());
299
312
  marketAccountMap.set(params.writableMarketIndex.toNumber(), {
@@ -355,9 +368,27 @@ class ClearingHouse {
355
368
  return (_a = this.getUserAccount()) === null || _a === void 0 ? void 0 : _a.orders.find((order) => order.userOrderId === userOrderId);
356
369
  }
357
370
  async deposit(amount, bankIndex, collateralAccountPublicKey, userId, reduceOnly = false) {
371
+ const tx = new web3_js_1.Transaction();
372
+ const additionalSigners = [];
373
+ const bank = this.getBankAccount(bankIndex);
374
+ const isSolBank = bank.mint.equals(banks_1.WRAPPED_SOL_MINT);
375
+ const authority = this.wallet.publicKey;
376
+ const createWSOLTokenAccount = isSolBank && collateralAccountPublicKey.equals(authority);
377
+ if (createWSOLTokenAccount) {
378
+ const { ixs, signers, pubkey } = await this.getWrappedSolAccountCreationIxs(amount);
379
+ collateralAccountPublicKey = pubkey;
380
+ ixs.forEach((ix) => {
381
+ tx.add(ix);
382
+ });
383
+ signers.forEach((signer) => additionalSigners.push(signer));
384
+ }
358
385
  const depositCollateralIx = await this.getDepositInstruction(amount, bankIndex, collateralAccountPublicKey, userId, reduceOnly, true);
359
- const tx = new web3_js_1.Transaction().add(depositCollateralIx);
360
- const { txSig } = await this.txSender.send(tx);
386
+ tx.add(depositCollateralIx);
387
+ // Close the wrapped sol account at the end of the transaction
388
+ if (createWSOLTokenAccount) {
389
+ tx.add(spl_token_1.Token.createCloseAccountInstruction(spl_token_1.TOKEN_PROGRAM_ID, collateralAccountPublicKey, authority, authority, []));
390
+ }
391
+ const { txSig } = await this.txSender.send(tx, additionalSigners, this.opts);
361
392
  return txSig;
362
393
  }
363
394
  async getDepositInstruction(amount, bankIndex, userTokenAccount, userId, reduceOnly = false, userInitialized = true) {
@@ -399,30 +430,99 @@ class ClearingHouse {
399
430
  remainingAccounts,
400
431
  });
401
432
  }
433
+ async checkIfAccountExists(account) {
434
+ try {
435
+ const accountInfo = await this.connection.getAccountInfo(account);
436
+ return accountInfo && true;
437
+ }
438
+ catch (e) {
439
+ // Doesn't already exist
440
+ return false;
441
+ }
442
+ }
443
+ async getSolWithdrawalIxs(bankIndex, amount) {
444
+ const result = {
445
+ ixs: [],
446
+ signers: [],
447
+ pubkey: web3_js_1.PublicKey.default,
448
+ };
449
+ // Create a temporary wrapped SOL account to store the SOL that we're withdrawing
450
+ const authority = this.wallet.publicKey;
451
+ const { ixs, signers, pubkey } = await this.getWrappedSolAccountCreationIxs(amount);
452
+ result.pubkey = pubkey;
453
+ ixs.forEach((ix) => {
454
+ result.ixs.push(ix);
455
+ });
456
+ signers.forEach((ix) => {
457
+ result.signers.push(ix);
458
+ });
459
+ const withdrawIx = await this.getWithdrawIx(amount, bankIndex, pubkey, true);
460
+ result.ixs.push(withdrawIx);
461
+ result.ixs.push(spl_token_1.Token.createCloseAccountInstruction(spl_token_1.TOKEN_PROGRAM_ID, pubkey, authority, authority, []));
462
+ return result;
463
+ }
464
+ async getWrappedSolAccountCreationIxs(amount) {
465
+ const wrappedSolAccount = new web3_js_1.Keypair();
466
+ const result = {
467
+ ixs: [],
468
+ signers: [],
469
+ pubkey: wrappedSolAccount.publicKey,
470
+ };
471
+ const rentSpaceLamports = new anchor_1.BN(web3_js_1.LAMPORTS_PER_SOL / 100);
472
+ const depositAmountLamports = amount.add(rentSpaceLamports);
473
+ const authority = this.wallet.publicKey;
474
+ result.ixs.push(web3_js_1.SystemProgram.createAccount({
475
+ fromPubkey: authority,
476
+ newAccountPubkey: wrappedSolAccount.publicKey,
477
+ lamports: depositAmountLamports.toNumber(),
478
+ space: 165,
479
+ programId: spl_token_1.TOKEN_PROGRAM_ID,
480
+ }));
481
+ result.ixs.push(spl_token_1.Token.createInitAccountInstruction(spl_token_1.TOKEN_PROGRAM_ID, banks_1.WRAPPED_SOL_MINT, wrappedSolAccount.publicKey, authority));
482
+ result.signers.push(wrappedSolAccount);
483
+ return result;
484
+ }
402
485
  /**
403
486
  * Creates the Clearing House User account for a user, and deposits some initial collateral
404
- * @param userId
405
- * @param name
406
487
  * @param amount
407
488
  * @param userTokenAccount
489
+ * @param bankIndex
490
+ * @param userId
491
+ * @param name
408
492
  * @param fromUserId
409
493
  * @returns
410
494
  */
411
495
  async initializeUserAccountAndDepositCollateral(amount, userTokenAccount, bankIndex = new anchor_1.BN(0), userId = 0, name = userName_1.DEFAULT_USER_NAME, fromUserId) {
412
496
  const [userAccountPublicKey, initializeUserAccountIx] = await this.getInitializeUserInstructions(userId, name);
497
+ const additionalSigners = [];
498
+ const bank = this.getBankAccount(bankIndex);
499
+ const isSolBank = bank.mint.equals(banks_1.WRAPPED_SOL_MINT);
500
+ const tx = new web3_js_1.Transaction();
501
+ const authority = this.wallet.publicKey;
502
+ const createWSOLTokenAccount = isSolBank && userTokenAccount.equals(authority);
503
+ if (createWSOLTokenAccount) {
504
+ const { ixs: startIxs, signers, pubkey, } = await this.getWrappedSolAccountCreationIxs(amount);
505
+ userTokenAccount = pubkey;
506
+ startIxs.forEach((ix) => {
507
+ tx.add(ix);
508
+ });
509
+ signers.forEach((signer) => additionalSigners.push(signer));
510
+ }
413
511
  const depositCollateralIx = fromUserId != null
414
512
  ? await this.getTransferDepositIx(amount, bankIndex, fromUserId, userId)
415
513
  : await this.getDepositInstruction(amount, bankIndex, userTokenAccount, userId, false, false);
416
- const tx = new web3_js_1.Transaction()
417
- .add(initializeUserAccountIx)
418
- .add(depositCollateralIx);
419
- const { txSig } = await this.txSender.send(tx, []);
514
+ tx.add(initializeUserAccountIx).add(depositCollateralIx);
515
+ // Close the wrapped sol account at the end of the transaction
516
+ if (createWSOLTokenAccount) {
517
+ tx.add(spl_token_1.Token.createCloseAccountInstruction(spl_token_1.TOKEN_PROGRAM_ID, userTokenAccount, authority, authority, []));
518
+ }
519
+ const { txSig } = await this.txSender.send(tx, additionalSigners, this.opts);
420
520
  return [txSig, userAccountPublicKey];
421
521
  }
422
- async initializeUserAccountForDevnet(userId = 0, name = userName_1.DEFAULT_USER_NAME, mockUSDCFaucet, amount) {
423
- const [associateTokenPublicKey, createAssociatedAccountIx, mintToIx] = await mockUSDCFaucet.createAssociatedTokenAccountAndMintToInstructions(this.wallet.publicKey, amount);
522
+ async initializeUserAccountForDevnet(userId = 0, name = userName_1.DEFAULT_USER_NAME, bankIndex, tokenFaucet, amount) {
523
+ const [associateTokenPublicKey, createAssociatedAccountIx, mintToIx] = await tokenFaucet.createAssociatedTokenAccountAndMintToInstructions(this.wallet.publicKey, amount);
424
524
  const [userAccountPublicKey, initializeUserAccountIx] = await this.getInitializeUserInstructions(userId, name);
425
- const depositCollateralIx = await this.getDepositInstruction(amount, new anchor_1.BN(0), associateTokenPublicKey, userId, false, false);
525
+ const depositCollateralIx = await this.getDepositInstruction(amount, bankIndex, associateTokenPublicKey, userId, false, false);
426
526
  const tx = new web3_js_1.Transaction()
427
527
  .add(createAssociatedAccountIx)
428
528
  .add(mintToIx)
@@ -432,7 +532,27 @@ class ClearingHouse {
432
532
  return [txSig, userAccountPublicKey];
433
533
  }
434
534
  async withdraw(amount, bankIndex, userTokenAccount, reduceOnly = false) {
435
- const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getWithdrawIx(amount, bankIndex, userTokenAccount, reduceOnly)), [], this.opts);
535
+ const tx = new web3_js_1.Transaction();
536
+ const additionalSigners = [];
537
+ const bank = this.getBankAccount(bankIndex);
538
+ const isSolBank = bank.mint.equals(banks_1.WRAPPED_SOL_MINT);
539
+ const authority = this.wallet.publicKey;
540
+ const createWSOLTokenAccount = isSolBank && userTokenAccount.equals(authority);
541
+ if (createWSOLTokenAccount) {
542
+ const { ixs, signers, pubkey } = await this.getWrappedSolAccountCreationIxs(amount);
543
+ userTokenAccount = pubkey;
544
+ ixs.forEach((ix) => {
545
+ tx.add(ix);
546
+ });
547
+ signers.forEach((signer) => additionalSigners.push(signer));
548
+ }
549
+ const withdrawCollateral = await this.getWithdrawIx(amount, bank.bankIndex, userTokenAccount, reduceOnly);
550
+ tx.add(withdrawCollateral);
551
+ // Close the wrapped sol account at the end of the transaction
552
+ if (createWSOLTokenAccount) {
553
+ tx.add(spl_token_1.Token.createCloseAccountInstruction(spl_token_1.TOKEN_PROGRAM_ID, userTokenAccount, authority, authority, []));
554
+ }
555
+ const { txSig } = await this.txSender.send(tx, additionalSigners, this.opts);
436
556
  return txSig;
437
557
  }
438
558
  async getWithdrawIx(amount, bankIndex, userTokenAccount, reduceOnly = false) {
@@ -508,7 +628,7 @@ class ClearingHouse {
508
628
  orderParams = this.getOrderParams(orderParams);
509
629
  const userAccountPublicKey = await this.getUserAccountPublicKey();
510
630
  const remainingAccounts = this.getRemainingAccounts({
511
- writableMarketIndex: orderParams.marketIndex,
631
+ readableMarketIndex: orderParams.marketIndex,
512
632
  });
513
633
  return await this.program.instruction.placeOrder(orderParams, {
514
634
  accounts: {
@@ -599,23 +719,13 @@ class ClearingHouse {
599
719
  const oracleAccountMap = new Map();
600
720
  const bankAccountMap = new Map();
601
721
  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
722
  for (const bankBalance of userAccount.bankBalances) {
613
723
  if (!bankBalance.balance.eq(numericConstants_1.ZERO)) {
614
724
  const bankAccount = this.getBankAccount(bankBalance.bankIndex);
615
725
  bankAccountMap.set(bankBalance.bankIndex.toNumber(), {
616
726
  pubkey: bankAccount.pubkey,
617
727
  isSigner: false,
618
- isWritable: true,
728
+ isWritable: false,
619
729
  });
620
730
  if (!bankAccount.oracle.equals(web3_js_1.PublicKey.default)) {
621
731
  oracleAccountMap.set(bankAccount.oracle.toString(), {
@@ -632,7 +742,7 @@ class ClearingHouse {
632
742
  const market = this.getMarketAccount(position.marketIndex);
633
743
  marketAccountMap.set(position.marketIndex.toNumber(), {
634
744
  pubkey: market.pubkey,
635
- isWritable: true,
745
+ isWritable: false,
636
746
  isSigner: false,
637
747
  });
638
748
  oracleAccountMap.set(market.amm.oracle.toString(), {
@@ -642,6 +752,16 @@ class ClearingHouse {
642
752
  });
643
753
  }
644
754
  }
755
+ marketAccountMap.set(marketIndex.toNumber(), {
756
+ pubkey: marketAccount.pubkey,
757
+ isWritable: true,
758
+ isSigner: false,
759
+ });
760
+ oracleAccountMap.set(marketAccount.amm.oracle.toString(), {
761
+ pubkey: marketAccount.amm.oracle,
762
+ isWritable: false,
763
+ isSigner: false,
764
+ });
645
765
  const remainingAccounts = [
646
766
  ...oracleAccountMap.values(),
647
767
  ...bankAccountMap.values(),
@@ -677,23 +797,13 @@ class ClearingHouse {
677
797
  const oracleAccountMap = new Map();
678
798
  const bankAccountMap = new Map();
679
799
  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
800
  for (const bankBalance of userAccount.bankBalances) {
691
801
  if (!bankBalance.balance.eq(numericConstants_1.ZERO)) {
692
802
  const bankAccount = this.getBankAccount(bankBalance.bankIndex);
693
803
  bankAccountMap.set(bankBalance.bankIndex.toNumber(), {
694
804
  pubkey: bankAccount.pubkey,
695
805
  isSigner: false,
696
- isWritable: true,
806
+ isWritable: false,
697
807
  });
698
808
  if (!bankAccount.oracle.equals(web3_js_1.PublicKey.default)) {
699
809
  oracleAccountMap.set(bankAccount.oracle.toString(), {
@@ -710,7 +820,7 @@ class ClearingHouse {
710
820
  const market = this.getMarketAccount(position.marketIndex);
711
821
  marketAccountMap.set(position.marketIndex.toNumber(), {
712
822
  pubkey: market.pubkey,
713
- isWritable: true,
823
+ isWritable: false,
714
824
  isSigner: false,
715
825
  });
716
826
  oracleAccountMap.set(market.amm.oracle.toString(), {
@@ -720,6 +830,16 @@ class ClearingHouse {
720
830
  });
721
831
  }
722
832
  }
833
+ marketAccountMap.set(marketIndex.toNumber(), {
834
+ pubkey: marketAccount.pubkey,
835
+ isWritable: true,
836
+ isSigner: false,
837
+ });
838
+ oracleAccountMap.set(marketAccount.amm.oracle.toString(), {
839
+ pubkey: marketAccount.amm.oracle,
840
+ isWritable: false,
841
+ isSigner: false,
842
+ });
723
843
  const remainingAccounts = [
724
844
  ...oracleAccountMap.values(),
725
845
  ...bankAccountMap.values(),
@@ -834,7 +954,7 @@ class ClearingHouse {
834
954
  const market = this.getMarketAccount(position.marketIndex);
835
955
  marketAccountMap.set(position.marketIndex.toNumber(), {
836
956
  pubkey: market.pubkey,
837
- isWritable: true,
957
+ isWritable: false,
838
958
  isSigner: false,
839
959
  });
840
960
  oracleAccountMap.set(market.amm.oracle.toString(), {
@@ -891,54 +1011,217 @@ class ClearingHouse {
891
1011
  remainingAccounts: remainingAccounts,
892
1012
  });
893
1013
  }
894
- async liquidate(liquidateeUserAccountPublicKey) {
895
- const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getLiquidateIx(liquidateeUserAccountPublicKey)), [], this.opts);
1014
+ async liquidatePerp(userAccountPublicKey, userAccount, marketIndex, maxBaseAssetAmount) {
1015
+ const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getLiquidatePerpIx(userAccountPublicKey, userAccount, marketIndex, maxBaseAssetAmount)), [], this.opts);
896
1016
  return txSig;
897
1017
  }
898
- async getLiquidateIx(liquidateeUserAccountPublicKey) {
899
- const userAccountPublicKey = await this.getUserAccountPublicKey();
900
- const liquidateeUserAccount = (await this.program.account.user.fetch(liquidateeUserAccountPublicKey));
901
- const bankAccountInfos = [
902
- {
903
- pubkey: this.getQuoteAssetBankAccount().pubkey,
904
- isSigner: false,
905
- isWritable: true,
1018
+ async getLiquidatePerpIx(userAccountPublicKey, userAccount, marketIndex, maxBaseAssetAmount) {
1019
+ const liquidatorPublicKey = await this.getUserAccountPublicKey();
1020
+ const remainingAccounts = this.getRemainingAccountsForLiquidation({
1021
+ writableMarketIndex: marketIndex,
1022
+ userAccount,
1023
+ });
1024
+ return await this.program.instruction.liquidatePerp(marketIndex, maxBaseAssetAmount, {
1025
+ accounts: {
1026
+ state: await this.getStatePublicKey(),
1027
+ authority: this.wallet.publicKey,
1028
+ user: userAccountPublicKey,
1029
+ liquidator: liquidatorPublicKey,
906
1030
  },
907
- ];
908
- const marketAccountInfos = [];
909
- const oracleAccountInfos = [];
1031
+ remainingAccounts: remainingAccounts,
1032
+ });
1033
+ }
1034
+ async liquidateBorrow(userAccountPublicKey, userAccount, assetBankIndex, liabilityBankIndex, maxLiabilityTransfer) {
1035
+ const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getLiquidateBorrowIx(userAccountPublicKey, userAccount, assetBankIndex, liabilityBankIndex, maxLiabilityTransfer)), [], this.opts);
1036
+ return txSig;
1037
+ }
1038
+ async getLiquidateBorrowIx(userAccountPublicKey, userAccount, assetBankIndex, liabilityBankIndex, maxLiabilityTransfer) {
1039
+ const liquidatorPublicKey = await this.getUserAccountPublicKey();
1040
+ const remainingAccounts = this.getRemainingAccountsForLiquidation({
1041
+ userAccount,
1042
+ writableBankIndexes: [liabilityBankIndex, assetBankIndex],
1043
+ });
1044
+ return await this.program.instruction.liquidateBorrow(assetBankIndex, liabilityBankIndex, maxLiabilityTransfer, {
1045
+ accounts: {
1046
+ state: await this.getStatePublicKey(),
1047
+ authority: this.wallet.publicKey,
1048
+ user: userAccountPublicKey,
1049
+ liquidator: liquidatorPublicKey,
1050
+ },
1051
+ remainingAccounts: remainingAccounts,
1052
+ });
1053
+ }
1054
+ async liquidateBorrowForPerpPnl(userAccountPublicKey, userAccount, perpMarketIndex, liabilityBankIndex, maxLiabilityTransfer) {
1055
+ const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getLiquidateBorrowForPerpPnlIx(userAccountPublicKey, userAccount, perpMarketIndex, liabilityBankIndex, maxLiabilityTransfer)), [], this.opts);
1056
+ return txSig;
1057
+ }
1058
+ async getLiquidateBorrowForPerpPnlIx(userAccountPublicKey, userAccount, perpMarketIndex, liabilityBankIndex, maxLiabilityTransfer) {
1059
+ const liquidatorPublicKey = await this.getUserAccountPublicKey();
1060
+ const remainingAccounts = this.getRemainingAccountsForLiquidation({
1061
+ userAccount,
1062
+ writableMarketIndex: perpMarketIndex,
1063
+ writableBankIndexes: [liabilityBankIndex],
1064
+ });
1065
+ return await this.program.instruction.liquidateBorrowForPerpPnl(perpMarketIndex, liabilityBankIndex, maxLiabilityTransfer, {
1066
+ accounts: {
1067
+ state: await this.getStatePublicKey(),
1068
+ authority: this.wallet.publicKey,
1069
+ user: userAccountPublicKey,
1070
+ liquidator: liquidatorPublicKey,
1071
+ },
1072
+ remainingAccounts: remainingAccounts,
1073
+ });
1074
+ }
1075
+ async liquidatePerpPnlForDeposit(userAccountPublicKey, userAccount, perpMarketIndex, assetBankIndex, maxPnlTransfer) {
1076
+ const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getLiquidatePerpPnlForDepositIx(userAccountPublicKey, userAccount, perpMarketIndex, assetBankIndex, maxPnlTransfer)), [], this.opts);
1077
+ return txSig;
1078
+ }
1079
+ async getLiquidatePerpPnlForDepositIx(userAccountPublicKey, userAccount, perpMarketIndex, assetBankIndex, maxPnlTransfer) {
1080
+ const liquidatorPublicKey = await this.getUserAccountPublicKey();
1081
+ const remainingAccounts = this.getRemainingAccountsForLiquidation({
1082
+ userAccount,
1083
+ writableMarketIndex: perpMarketIndex,
1084
+ writableBankIndexes: [assetBankIndex],
1085
+ });
1086
+ return await this.program.instruction.liquidatePerpPnlForDeposit(perpMarketIndex, assetBankIndex, maxPnlTransfer, {
1087
+ accounts: {
1088
+ state: await this.getStatePublicKey(),
1089
+ authority: this.wallet.publicKey,
1090
+ user: userAccountPublicKey,
1091
+ liquidator: liquidatorPublicKey,
1092
+ },
1093
+ remainingAccounts: remainingAccounts,
1094
+ });
1095
+ }
1096
+ getRemainingAccountsForLiquidation(params) {
1097
+ const liquidateeUserAccount = params.userAccount;
1098
+ const oracleAccountMap = new Map();
1099
+ const bankAccountMap = new Map();
1100
+ const marketAccountMap = new Map();
1101
+ for (const bankBalance of liquidateeUserAccount.bankBalances) {
1102
+ if (!bankBalance.balance.eq(numericConstants_1.ZERO)) {
1103
+ const bankAccount = this.getBankAccount(bankBalance.bankIndex);
1104
+ bankAccountMap.set(bankBalance.bankIndex.toNumber(), {
1105
+ pubkey: bankAccount.pubkey,
1106
+ isSigner: false,
1107
+ isWritable: false,
1108
+ });
1109
+ if (!bankAccount.oracle.equals(web3_js_1.PublicKey.default)) {
1110
+ oracleAccountMap.set(bankAccount.oracle.toString(), {
1111
+ pubkey: bankAccount.oracle,
1112
+ isSigner: false,
1113
+ isWritable: false,
1114
+ });
1115
+ }
1116
+ }
1117
+ }
910
1118
  for (const position of liquidateeUserAccount.positions) {
911
1119
  if (!(0, position_1.positionIsAvailable)(position)) {
912
1120
  const market = this.getMarketAccount(position.marketIndex);
913
- const marketPublicKey = await (0, pda_1.getMarketPublicKey)(this.program.programId, position.marketIndex);
914
- marketAccountInfos.push({
915
- pubkey: marketPublicKey,
916
- isWritable: true,
1121
+ marketAccountMap.set(position.marketIndex.toNumber(), {
1122
+ pubkey: market.pubkey,
1123
+ isWritable: false,
917
1124
  isSigner: false,
918
1125
  });
919
- oracleAccountInfos.push({
1126
+ oracleAccountMap.set(market.amm.oracle.toString(), {
920
1127
  pubkey: market.amm.oracle,
921
1128
  isWritable: false,
922
1129
  isSigner: false,
923
1130
  });
924
1131
  }
925
1132
  }
926
- const remainingAccounts = oracleAccountInfos.concat(bankAccountInfos.concat(marketAccountInfos));
927
- const state = this.getStateAccount();
928
- const quoteAssetBankAccount = this.getQuoteAssetBankAccount();
929
- return await this.program.instruction.liquidate({
930
- accounts: {
931
- state: await this.getStatePublicKey(),
932
- authority: this.wallet.publicKey,
933
- user: liquidateeUserAccountPublicKey,
934
- liquidator: userAccountPublicKey,
935
- bankVault: quoteAssetBankAccount.vault,
936
- bankVaultAuthority: quoteAssetBankAccount.vaultAuthority,
937
- insuranceVault: state.insuranceVault,
938
- tokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
939
- },
940
- remainingAccounts: remainingAccounts,
941
- });
1133
+ const userAccountAndSlot = this.getUserAccountAndSlot();
1134
+ if (!userAccountAndSlot) {
1135
+ throw Error('No user account found. Most likely user account does not exist or failed to fetch account');
1136
+ }
1137
+ const { data: userAccount, slot: lastUserPositionsSlot } = userAccountAndSlot;
1138
+ for (const [marketIndexNum, slot] of this.marketLastSlotCache.entries()) {
1139
+ // if cache has more recent slot than user positions account slot, add market to remaining accounts
1140
+ // otherwise remove from slot
1141
+ if (slot > lastUserPositionsSlot) {
1142
+ const marketAccount = this.getMarketAccount(marketIndexNum);
1143
+ marketAccountMap.set(marketIndexNum, {
1144
+ pubkey: marketAccount.pubkey,
1145
+ isSigner: false,
1146
+ isWritable: false,
1147
+ });
1148
+ oracleAccountMap.set(marketAccount.amm.oracle.toString(), {
1149
+ pubkey: marketAccount.amm.oracle,
1150
+ isSigner: false,
1151
+ isWritable: false,
1152
+ });
1153
+ }
1154
+ else {
1155
+ this.marketLastSlotCache.delete(marketIndexNum);
1156
+ }
1157
+ }
1158
+ for (const bankBalance of userAccount.bankBalances) {
1159
+ if (!bankBalance.balance.eq(numericConstants_1.ZERO)) {
1160
+ const bankAccount = this.getBankAccount(bankBalance.bankIndex);
1161
+ bankAccountMap.set(bankBalance.bankIndex.toNumber(), {
1162
+ pubkey: bankAccount.pubkey,
1163
+ isSigner: false,
1164
+ isWritable: false,
1165
+ });
1166
+ if (!bankAccount.oracle.equals(web3_js_1.PublicKey.default)) {
1167
+ oracleAccountMap.set(bankAccount.oracle.toString(), {
1168
+ pubkey: bankAccount.oracle,
1169
+ isSigner: false,
1170
+ isWritable: false,
1171
+ });
1172
+ }
1173
+ }
1174
+ }
1175
+ for (const position of userAccount.positions) {
1176
+ if (!(0, position_1.positionIsAvailable)(position)) {
1177
+ const market = this.getMarketAccount(position.marketIndex);
1178
+ marketAccountMap.set(position.marketIndex.toNumber(), {
1179
+ pubkey: market.pubkey,
1180
+ isWritable: false,
1181
+ isSigner: false,
1182
+ });
1183
+ oracleAccountMap.set(market.amm.oracle.toString(), {
1184
+ pubkey: market.amm.oracle,
1185
+ isWritable: false,
1186
+ isSigner: false,
1187
+ });
1188
+ }
1189
+ }
1190
+ if (params.writableMarketIndex) {
1191
+ const market = this.getMarketAccount(params.writableMarketIndex);
1192
+ marketAccountMap.set(market.marketIndex.toNumber(), {
1193
+ pubkey: market.pubkey,
1194
+ isSigner: false,
1195
+ isWritable: true,
1196
+ });
1197
+ oracleAccountMap.set(market.amm.oracle.toString(), {
1198
+ pubkey: market.amm.oracle,
1199
+ isSigner: false,
1200
+ isWritable: false,
1201
+ });
1202
+ }
1203
+ if (params.writableBankIndexes) {
1204
+ for (const writableBankIndex of params.writableBankIndexes) {
1205
+ const bank = this.getBankAccount(writableBankIndex);
1206
+ bankAccountMap.set(bank.bankIndex.toNumber(), {
1207
+ pubkey: bank.pubkey,
1208
+ isSigner: false,
1209
+ isWritable: true,
1210
+ });
1211
+ if (!bank.oracle.equals(web3_js_1.PublicKey.default)) {
1212
+ oracleAccountMap.set(bank.oracle.toString(), {
1213
+ pubkey: bank.oracle,
1214
+ isSigner: false,
1215
+ isWritable: false,
1216
+ });
1217
+ }
1218
+ }
1219
+ }
1220
+ return [
1221
+ ...oracleAccountMap.values(),
1222
+ ...bankAccountMap.values(),
1223
+ ...marketAccountMap.values(),
1224
+ ];
942
1225
  }
943
1226
  async updateFundingRate(oracle, marketIndex) {
944
1227
  const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getUpdateFundingRateIx(oracle, marketIndex)), [], this.opts);
@@ -61,48 +61,43 @@ export declare class ClearingHouseUser {
61
61
  getFreeCollateral(): BN;
62
62
  getInitialMarginRequirement(): BN;
63
63
  /**
64
- * @returns The partial margin requirement in USDC. : QUOTE_PRECISION
64
+ * @returns The maintenance 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
70
70
  */
71
- getUnrealizedPNL(withFunding?: boolean, marketIndex?: BN): BN;
72
- /**
73
- * calculates unrealized position price pnl
74
- * @returns : Precision QUOTE_PRECISION
75
- */
76
- getUnsettledPNL(marketIndex?: BN): BN;
71
+ getUnrealizedPNL(withFunding?: boolean, marketIndex?: BN, withWeightMarginCategory?: MarginCategory): BN;
77
72
  /**
78
73
  * calculates unrealized funding payment pnl
79
74
  * @returns : Precision QUOTE_PRECISION
80
75
  */
81
76
  getUnrealizedFundingPNL(marketIndex?: BN): BN;
82
- getTotalLiability(): BN;
83
- getCollateralValue(bankIndex?: BN): BN;
77
+ getBankLiabilityValue(bankIndex?: BN, withWeightMarginCategory?: MarginCategory): BN;
78
+ getBankAssetValue(bankIndex?: BN, withWeightMarginCategory?: MarginCategory): BN;
79
+ getNetBankValue(withWeightMarginCategory?: MarginCategory): BN;
84
80
  /**
85
81
  * calculates TotalCollateral: collateral + unrealized pnl
86
- * TODO: rename to total equity (for perpetuals swaps)
87
82
  * @returns : Precision QUOTE_PRECISION
88
83
  */
89
- getTotalCollateral(): BN;
84
+ getTotalCollateral(marginCategory?: MarginCategory): BN;
90
85
  /**
91
- * calculates sum of position value across all positions
86
+ * calculates sum of position value across all positions in margin system
92
87
  * @returns : Precision QUOTE_PRECISION
93
88
  */
94
89
  getTotalPositionValue(): BN;
95
90
  /**
96
- * calculates position value from closing 100%
91
+ * calculates position value in margin system
97
92
  * @returns : Precision QUOTE_PRECISION
98
93
  */
99
94
  getPositionValue(marketIndex: BN, oraclePriceData: OraclePriceData): BN;
100
95
  getPositionSide(currentPosition: Pick<UserPosition, 'baseAssetAmount'>): PositionDirection | undefined;
101
96
  /**
102
- * calculates average exit price for closing 100% of position
97
+ * calculates average exit price (optionally for closing up to 100% of position)
103
98
  * @returns : Precision MARK_PRICE_PRECISION
104
99
  */
105
- getPositionEstimatedExitPriceAndPnl(position: UserPosition, amountToClose?: BN): [BN, BN];
100
+ getPositionEstimatedExitPriceAndPnl(position: UserPosition, amountToClose?: BN, useAMMClose?: boolean): [BN, BN];
106
101
  /**
107
102
  * calculates current user leverage across all positions
108
103
  * @returns : Precision TEN_THOUSAND
@@ -132,7 +127,7 @@ export declare class ClearingHouseUser {
132
127
  * @param partial
133
128
  * @returns Precision : MARK_PRICE_PRECISION
134
129
  */
135
- liquidationPrice(marketPosition: Pick<UserPosition, 'marketIndex'>, positionBaseSizeChange?: BN, partial?: boolean): BN;
130
+ liquidationPrice(marketPosition: Pick<UserPosition, 'marketIndex'>, positionBaseSizeChange?: BN): BN;
136
131
  /**
137
132
  * Calculates the estimated liquidation price for a position after closing a quote amount of the position.
138
133
  * @param positionMarketIndex