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

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 (114) hide show
  1. package/lib/accounts/fetch.d.ts +2 -1
  2. package/lib/accounts/fetch.js +9 -1
  3. package/lib/accounts/pollingUserStatsAccountSubscriber.d.ts +27 -0
  4. package/lib/accounts/pollingUserStatsAccountSubscriber.js +113 -0
  5. package/lib/accounts/types.d.ts +14 -1
  6. package/lib/accounts/webSocketUserStatsAccountSubsriber.d.ts +20 -0
  7. package/lib/accounts/webSocketUserStatsAccountSubsriber.js +47 -0
  8. package/lib/addresses/pda.d.ts +1 -0
  9. package/lib/addresses/pda.js +8 -1
  10. package/lib/admin.d.ts +2 -0
  11. package/lib/admin.js +18 -0
  12. package/lib/clearingHouse.d.ts +24 -3
  13. package/lib/clearingHouse.js +352 -51
  14. package/lib/clearingHouseConfig.d.ts +1 -0
  15. package/lib/clearingHouseUser.d.ts +15 -15
  16. package/lib/clearingHouseUser.js +185 -73
  17. package/lib/clearingHouseUserStats.d.ts +17 -0
  18. package/lib/clearingHouseUserStats.js +36 -0
  19. package/lib/clearingHouseUserStatsConfig.d.ts +14 -0
  20. package/lib/clearingHouseUserStatsConfig.js +2 -0
  21. package/lib/config.js +1 -1
  22. package/lib/constants/banks.d.ts +2 -2
  23. package/lib/constants/banks.js +4 -3
  24. package/lib/constants/numericConstants.d.ts +2 -0
  25. package/lib/constants/numericConstants.js +3 -1
  26. package/lib/events/eventList.js +3 -0
  27. package/lib/events/types.d.ts +2 -1
  28. package/lib/factory/bigNum.d.ts +1 -0
  29. package/lib/factory/bigNum.js +37 -11
  30. package/lib/idl/clearing_house.json +692 -58
  31. package/lib/index.d.ts +1 -0
  32. package/lib/index.js +1 -0
  33. package/lib/math/amm.js +2 -2
  34. package/lib/math/bankBalance.d.ts +7 -1
  35. package/lib/math/bankBalance.js +76 -1
  36. package/lib/math/margin.d.ts +11 -0
  37. package/lib/math/margin.js +72 -0
  38. package/lib/math/market.d.ts +4 -1
  39. package/lib/math/market.js +35 -1
  40. package/lib/math/oracles.d.ts +3 -0
  41. package/lib/math/oracles.js +25 -5
  42. package/lib/math/position.d.ts +8 -0
  43. package/lib/math/position.js +43 -12
  44. package/lib/math/trade.js +2 -2
  45. package/lib/orders.d.ts +1 -2
  46. package/lib/orders.js +2 -77
  47. package/lib/tokenFaucet.d.ts +1 -0
  48. package/lib/tokenFaucet.js +23 -12
  49. package/lib/tx/retryTxSender.js +9 -2
  50. package/lib/types.d.ts +78 -10
  51. package/lib/types.js +12 -0
  52. package/lib/util/getTokenAddress.d.ts +2 -0
  53. package/lib/util/getTokenAddress.js +9 -0
  54. package/package.json +1 -1
  55. package/src/accounts/fetch.ts +27 -2
  56. package/src/accounts/pollingUserStatsAccountSubscriber.ts +172 -0
  57. package/src/accounts/types.ts +18 -0
  58. package/src/accounts/webSocketUserStatsAccountSubsriber.ts +80 -0
  59. package/src/addresses/pda.ts +13 -0
  60. package/src/admin.ts +29 -1
  61. package/src/clearingHouse.ts +619 -62
  62. package/src/clearingHouseConfig.ts +1 -0
  63. package/src/clearingHouseUser.ts +317 -105
  64. package/src/clearingHouseUserStats.ts +53 -0
  65. package/src/clearingHouseUserStatsConfig.ts +18 -0
  66. package/src/config.ts +1 -1
  67. package/src/constants/banks.js +42 -0
  68. package/src/constants/banks.ts +6 -3
  69. package/src/constants/markets.js +42 -0
  70. package/src/constants/numericConstants.js +41 -0
  71. package/src/constants/numericConstants.ts +3 -0
  72. package/src/events/eventList.ts +3 -0
  73. package/src/events/types.ts +2 -0
  74. package/src/factory/bigNum.js +37 -11
  75. package/src/factory/bigNum.ts +43 -13
  76. package/src/idl/clearing_house.json +692 -58
  77. package/src/index.ts +1 -0
  78. package/src/math/amm.ts +8 -5
  79. package/src/math/bankBalance.ts +147 -1
  80. package/src/math/margin.ts +124 -0
  81. package/src/math/market.ts +66 -1
  82. package/src/math/oracles.ts +42 -5
  83. package/src/math/position.ts +60 -9
  84. package/src/math/trade.ts +2 -2
  85. package/src/orders.ts +4 -157
  86. package/src/tokenFaucet.js +189 -0
  87. package/src/tokenFaucet.ts +38 -15
  88. package/src/tx/retryTxSender.ts +11 -3
  89. package/src/types.js +12 -1
  90. package/src/types.ts +83 -10
  91. package/src/{accounts/fetch.js → util/computeUnits.js} +11 -13
  92. package/src/util/getTokenAddress.js +9 -0
  93. package/src/util/getTokenAddress.ts +18 -0
  94. package/tests/bn/test.ts +2 -0
  95. package/src/accounts/bulkAccountLoader.js +0 -197
  96. package/src/accounts/bulkUserSubscription.js +0 -33
  97. package/src/accounts/pollingClearingHouseAccountSubscriber.js +0 -311
  98. package/src/accounts/pollingOracleSubscriber.js +0 -93
  99. package/src/accounts/pollingTokenAccountSubscriber.js +0 -90
  100. package/src/accounts/pollingUserAccountSubscriber.js +0 -132
  101. package/src/accounts/types.js +0 -10
  102. package/src/accounts/utils.js +0 -7
  103. package/src/accounts/webSocketAccountSubscriber.js +0 -93
  104. package/src/accounts/webSocketClearingHouseAccountSubscriber.js +0 -233
  105. package/src/accounts/webSocketUserAccountSubscriber.js +0 -62
  106. package/src/addresses/pda.js +0 -104
  107. package/src/index.js +0 -100
  108. package/src/math/bankBalance.js +0 -75
  109. package/src/math/market.js +0 -57
  110. package/src/math/orders.js +0 -110
  111. package/src/math/position.js +0 -140
  112. package/src/mockUSDCFaucet.js +0 -280
  113. package/src/orders.js +0 -134
  114. package/src/tx/retryTxSender.js +0 -188
@@ -44,6 +44,8 @@ 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");
48
+ const clearingHouseUserStats_1 = require("./clearingHouseUserStats");
47
49
  /**
48
50
  * # ClearingHouse
49
51
  * 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.
@@ -71,6 +73,13 @@ class ClearingHouse {
71
73
  type: 'websocket',
72
74
  };
73
75
  this.createUsers(userIds, this.userAccountSubscriptionConfig);
76
+ if (config.userStats) {
77
+ this.userStats = new clearingHouseUserStats_1.ClearingHouseUserStats({
78
+ clearingHouse: this,
79
+ userStatsAccountPublicKey: (0, pda_1.getUserStatsAccountPublicKey)(this.program.programId, this.wallet.publicKey),
80
+ accountSubscription: this.userAccountSubscriptionConfig,
81
+ });
82
+ }
74
83
  let marketIndexes = config.marketIndexes;
75
84
  let bankIndexes = config.bankIndexes;
76
85
  let oracleInfos = config.oracleInfos;
@@ -111,6 +120,9 @@ class ClearingHouse {
111
120
  }
112
121
  async subscribe() {
113
122
  const subscribePromises = this.subscribeUsers().concat(this.accountSubscriber.subscribe());
123
+ if (this.userStats !== undefined) {
124
+ subscribePromises.concat(this.userStats.subscribe());
125
+ }
114
126
  this.isSubscribed = (await Promise.all(subscribePromises)).reduce((success, prevSuccess) => success && prevSuccess);
115
127
  return this.isSubscribed;
116
128
  }
@@ -127,6 +139,9 @@ class ClearingHouse {
127
139
  }
128
140
  async unsubscribe() {
129
141
  const unsubscribePromises = this.unsubscribeUsers().concat(this.accountSubscriber.unsubscribe());
142
+ if (this.userStats !== undefined) {
143
+ unsubscribePromises.concat(this.userStats.unsubscribe());
144
+ }
130
145
  await Promise.all(unsubscribePromises);
131
146
  this.isSubscribed = false;
132
147
  }
@@ -187,6 +202,7 @@ class ClearingHouse {
187
202
  await Promise.all(this.subscribeUsers());
188
203
  }
189
204
  this.activeUserId = activeUserId;
205
+ this.userStatsAccountPublicKey = undefined;
190
206
  }
191
207
  async switchActiveUser(userId) {
192
208
  this.activeUserId = userId;
@@ -201,7 +217,12 @@ class ClearingHouse {
201
217
  }
202
218
  async initializeUserAccount(userId = 0, name = userName_1.DEFAULT_USER_NAME) {
203
219
  const [userAccountPublicKey, initializeUserAccountIx] = await this.getInitializeUserInstructions(userId, name);
204
- const tx = new web3_js_1.Transaction().add(initializeUserAccountIx);
220
+ const tx = new web3_js_1.Transaction();
221
+ if (userId === 0) {
222
+ // not the safest assumption, can explicitly check if user stats account exists if it causes problems
223
+ tx.add(await this.getInitializeUserStatsIx());
224
+ }
225
+ tx.add(initializeUserAccountIx);
205
226
  const { txSig } = await this.txSender.send(tx, [], this.opts);
206
227
  return [txSig, userAccountPublicKey];
207
228
  }
@@ -211,6 +232,7 @@ class ClearingHouse {
211
232
  const initializeUserAccountIx = await this.program.instruction.initializeUser(userId, nameBuffer, {
212
233
  accounts: {
213
234
  user: userAccountPublicKey,
235
+ userStats: this.getUserStatsAccountPublicKey(),
214
236
  authority: this.wallet.publicKey,
215
237
  payer: this.wallet.publicKey,
216
238
  rent: anchor.web3.SYSVAR_RENT_PUBKEY,
@@ -220,6 +242,18 @@ class ClearingHouse {
220
242
  });
221
243
  return [userAccountPublicKey, initializeUserAccountIx];
222
244
  }
245
+ async getInitializeUserStatsIx() {
246
+ return await this.program.instruction.initializeUserStats({
247
+ accounts: {
248
+ userStats: this.getUserStatsAccountPublicKey(),
249
+ authority: this.wallet.publicKey,
250
+ payer: this.wallet.publicKey,
251
+ rent: anchor.web3.SYSVAR_RENT_PUBKEY,
252
+ systemProgram: anchor.web3.SystemProgram.programId,
253
+ state: await this.getStatePublicKey(),
254
+ },
255
+ });
256
+ }
223
257
  getUser(userId) {
224
258
  userId = userId !== null && userId !== void 0 ? userId : this.activeUserId;
225
259
  if (!this.users.has(userId)) {
@@ -230,6 +264,16 @@ class ClearingHouse {
230
264
  getUsers() {
231
265
  return [...this.users.values()];
232
266
  }
267
+ getUserStats() {
268
+ return this.userStats;
269
+ }
270
+ getUserStatsAccountPublicKey() {
271
+ if (this.userStatsAccountPublicKey) {
272
+ return this.userStatsAccountPublicKey;
273
+ }
274
+ this.userStatsAccountPublicKey = (0, pda_1.getUserStatsAccountPublicKey)(this.program.programId, this.wallet.publicKey);
275
+ return this.userStatsAccountPublicKey;
276
+ }
233
277
  async getUserAccountPublicKey() {
234
278
  return this.getUser().userAccountPublicKey;
235
279
  }
@@ -284,8 +328,7 @@ class ClearingHouse {
284
328
  marketAccountMap.set(marketIndexNum, {
285
329
  pubkey: marketAccount.pubkey,
286
330
  isSigner: false,
287
- // isWritable: false, // TODO
288
- isWritable: true,
331
+ isWritable: false,
289
332
  });
290
333
  oracleAccountMap.set(marketAccount.pubkey.toString(), {
291
334
  pubkey: marketAccount.amm.oracle,
@@ -294,6 +337,19 @@ class ClearingHouse {
294
337
  });
295
338
  }
296
339
  }
340
+ if (params.readableMarketIndex) {
341
+ const marketAccount = this.getMarketAccount(params.readableMarketIndex.toNumber());
342
+ marketAccountMap.set(params.readableMarketIndex.toNumber(), {
343
+ pubkey: marketAccount.pubkey,
344
+ isSigner: false,
345
+ isWritable: true,
346
+ });
347
+ oracleAccountMap.set(marketAccount.amm.oracle.toString(), {
348
+ pubkey: marketAccount.amm.oracle,
349
+ isSigner: false,
350
+ isWritable: false,
351
+ });
352
+ }
297
353
  if (params.writableMarketIndex) {
298
354
  const marketAccount = this.getMarketAccount(params.writableMarketIndex.toNumber());
299
355
  marketAccountMap.set(params.writableMarketIndex.toNumber(), {
@@ -355,9 +411,27 @@ class ClearingHouse {
355
411
  return (_a = this.getUserAccount()) === null || _a === void 0 ? void 0 : _a.orders.find((order) => order.userOrderId === userOrderId);
356
412
  }
357
413
  async deposit(amount, bankIndex, collateralAccountPublicKey, userId, reduceOnly = false) {
414
+ const tx = new web3_js_1.Transaction();
415
+ const additionalSigners = [];
416
+ const bank = this.getBankAccount(bankIndex);
417
+ const isSolBank = bank.mint.equals(banks_1.WRAPPED_SOL_MINT);
418
+ const authority = this.wallet.publicKey;
419
+ const createWSOLTokenAccount = isSolBank && collateralAccountPublicKey.equals(authority);
420
+ if (createWSOLTokenAccount) {
421
+ const { ixs, signers, pubkey } = await this.getWrappedSolAccountCreationIxs(amount);
422
+ collateralAccountPublicKey = pubkey;
423
+ ixs.forEach((ix) => {
424
+ tx.add(ix);
425
+ });
426
+ signers.forEach((signer) => additionalSigners.push(signer));
427
+ }
358
428
  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);
429
+ tx.add(depositCollateralIx);
430
+ // Close the wrapped sol account at the end of the transaction
431
+ if (createWSOLTokenAccount) {
432
+ tx.add(spl_token_1.Token.createCloseAccountInstruction(spl_token_1.TOKEN_PROGRAM_ID, collateralAccountPublicKey, authority, authority, []));
433
+ }
434
+ const { txSig } = await this.txSender.send(tx, additionalSigners, this.opts);
361
435
  return txSig;
362
436
  }
363
437
  async getDepositInstruction(amount, bankIndex, userTokenAccount, userId, reduceOnly = false, userInitialized = true) {
@@ -399,40 +473,132 @@ class ClearingHouse {
399
473
  remainingAccounts,
400
474
  });
401
475
  }
476
+ async checkIfAccountExists(account) {
477
+ try {
478
+ const accountInfo = await this.connection.getAccountInfo(account);
479
+ return accountInfo && true;
480
+ }
481
+ catch (e) {
482
+ // Doesn't already exist
483
+ return false;
484
+ }
485
+ }
486
+ async getSolWithdrawalIxs(bankIndex, amount) {
487
+ const result = {
488
+ ixs: [],
489
+ signers: [],
490
+ pubkey: web3_js_1.PublicKey.default,
491
+ };
492
+ // Create a temporary wrapped SOL account to store the SOL that we're withdrawing
493
+ const authority = this.wallet.publicKey;
494
+ const { ixs, signers, pubkey } = await this.getWrappedSolAccountCreationIxs(amount);
495
+ result.pubkey = pubkey;
496
+ ixs.forEach((ix) => {
497
+ result.ixs.push(ix);
498
+ });
499
+ signers.forEach((ix) => {
500
+ result.signers.push(ix);
501
+ });
502
+ const withdrawIx = await this.getWithdrawIx(amount, bankIndex, pubkey, true);
503
+ result.ixs.push(withdrawIx);
504
+ result.ixs.push(spl_token_1.Token.createCloseAccountInstruction(spl_token_1.TOKEN_PROGRAM_ID, pubkey, authority, authority, []));
505
+ return result;
506
+ }
507
+ async getWrappedSolAccountCreationIxs(amount) {
508
+ const wrappedSolAccount = new web3_js_1.Keypair();
509
+ const result = {
510
+ ixs: [],
511
+ signers: [],
512
+ pubkey: wrappedSolAccount.publicKey,
513
+ };
514
+ const rentSpaceLamports = new anchor_1.BN(web3_js_1.LAMPORTS_PER_SOL / 100);
515
+ const depositAmountLamports = amount.add(rentSpaceLamports);
516
+ const authority = this.wallet.publicKey;
517
+ result.ixs.push(web3_js_1.SystemProgram.createAccount({
518
+ fromPubkey: authority,
519
+ newAccountPubkey: wrappedSolAccount.publicKey,
520
+ lamports: depositAmountLamports.toNumber(),
521
+ space: 165,
522
+ programId: spl_token_1.TOKEN_PROGRAM_ID,
523
+ }));
524
+ result.ixs.push(spl_token_1.Token.createInitAccountInstruction(spl_token_1.TOKEN_PROGRAM_ID, banks_1.WRAPPED_SOL_MINT, wrappedSolAccount.publicKey, authority));
525
+ result.signers.push(wrappedSolAccount);
526
+ return result;
527
+ }
402
528
  /**
403
529
  * Creates the Clearing House User account for a user, and deposits some initial collateral
404
- * @param userId
405
- * @param name
406
530
  * @param amount
407
531
  * @param userTokenAccount
532
+ * @param bankIndex
533
+ * @param userId
534
+ * @param name
408
535
  * @param fromUserId
409
536
  * @returns
410
537
  */
411
538
  async initializeUserAccountAndDepositCollateral(amount, userTokenAccount, bankIndex = new anchor_1.BN(0), userId = 0, name = userName_1.DEFAULT_USER_NAME, fromUserId) {
412
539
  const [userAccountPublicKey, initializeUserAccountIx] = await this.getInitializeUserInstructions(userId, name);
540
+ const additionalSigners = [];
541
+ const bank = this.getBankAccount(bankIndex);
542
+ const isSolBank = bank.mint.equals(banks_1.WRAPPED_SOL_MINT);
543
+ const tx = new web3_js_1.Transaction();
544
+ const authority = this.wallet.publicKey;
545
+ const createWSOLTokenAccount = isSolBank && userTokenAccount.equals(authority);
546
+ if (createWSOLTokenAccount) {
547
+ const { ixs: startIxs, signers, pubkey, } = await this.getWrappedSolAccountCreationIxs(amount);
548
+ userTokenAccount = pubkey;
549
+ startIxs.forEach((ix) => {
550
+ tx.add(ix);
551
+ });
552
+ signers.forEach((signer) => additionalSigners.push(signer));
553
+ }
413
554
  const depositCollateralIx = fromUserId != null
414
555
  ? await this.getTransferDepositIx(amount, bankIndex, fromUserId, userId)
415
556
  : 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, []);
557
+ if (userId === 0) {
558
+ tx.add(await this.getInitializeUserStatsIx());
559
+ }
560
+ tx.add(initializeUserAccountIx).add(depositCollateralIx);
561
+ // Close the wrapped sol account at the end of the transaction
562
+ if (createWSOLTokenAccount) {
563
+ tx.add(spl_token_1.Token.createCloseAccountInstruction(spl_token_1.TOKEN_PROGRAM_ID, userTokenAccount, authority, authority, []));
564
+ }
565
+ const { txSig } = await this.txSender.send(tx, additionalSigners, this.opts);
420
566
  return [txSig, userAccountPublicKey];
421
567
  }
422
568
  async initializeUserAccountForDevnet(userId = 0, name = userName_1.DEFAULT_USER_NAME, bankIndex, tokenFaucet, amount) {
423
569
  const [associateTokenPublicKey, createAssociatedAccountIx, mintToIx] = await tokenFaucet.createAssociatedTokenAccountAndMintToInstructions(this.wallet.publicKey, amount);
424
570
  const [userAccountPublicKey, initializeUserAccountIx] = await this.getInitializeUserInstructions(userId, name);
425
571
  const depositCollateralIx = await this.getDepositInstruction(amount, bankIndex, associateTokenPublicKey, userId, false, false);
426
- const tx = new web3_js_1.Transaction()
427
- .add(createAssociatedAccountIx)
428
- .add(mintToIx)
429
- .add(initializeUserAccountIx)
430
- .add(depositCollateralIx);
572
+ const tx = new web3_js_1.Transaction().add(createAssociatedAccountIx).add(mintToIx);
573
+ if (userId === 0) {
574
+ tx.add(await this.getInitializeUserStatsIx());
575
+ }
576
+ tx.add(initializeUserAccountIx).add(depositCollateralIx);
431
577
  const txSig = await this.program.provider.sendAndConfirm(tx, []);
432
578
  return [txSig, userAccountPublicKey];
433
579
  }
434
580
  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);
581
+ const tx = new web3_js_1.Transaction();
582
+ const additionalSigners = [];
583
+ const bank = this.getBankAccount(bankIndex);
584
+ const isSolBank = bank.mint.equals(banks_1.WRAPPED_SOL_MINT);
585
+ const authority = this.wallet.publicKey;
586
+ const createWSOLTokenAccount = isSolBank && userTokenAccount.equals(authority);
587
+ if (createWSOLTokenAccount) {
588
+ const { ixs, signers, pubkey } = await this.getWrappedSolAccountCreationIxs(amount);
589
+ userTokenAccount = pubkey;
590
+ ixs.forEach((ix) => {
591
+ tx.add(ix);
592
+ });
593
+ signers.forEach((signer) => additionalSigners.push(signer));
594
+ }
595
+ const withdrawCollateral = await this.getWithdrawIx(amount, bank.bankIndex, userTokenAccount, reduceOnly);
596
+ tx.add(withdrawCollateral);
597
+ // Close the wrapped sol account at the end of the transaction
598
+ if (createWSOLTokenAccount) {
599
+ tx.add(spl_token_1.Token.createCloseAccountInstruction(spl_token_1.TOKEN_PROGRAM_ID, userTokenAccount, authority, authority, []));
600
+ }
601
+ const { txSig } = await this.txSender.send(tx, additionalSigners, this.opts);
436
602
  return txSig;
437
603
  }
438
604
  async getWithdrawIx(amount, bankIndex, userTokenAccount, reduceOnly = false) {
@@ -487,6 +653,82 @@ class ClearingHouse {
487
653
  },
488
654
  });
489
655
  }
656
+ async settleLP(settleeUserAccountPublicKey, marketIndex) {
657
+ const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.settleLPIx(settleeUserAccountPublicKey, marketIndex)), [], this.opts);
658
+ return txSig;
659
+ }
660
+ async settleLPIx(settleeUserAccountPublicKey, marketIndex) {
661
+ const settleeUserAccount = (await this.program.account.user.fetch(settleeUserAccountPublicKey));
662
+ const userPositions = settleeUserAccount.positions;
663
+ const remainingAccounts = [];
664
+ let foundMarket = false;
665
+ for (const position of userPositions) {
666
+ if (!(0, position_1.positionIsAvailable)(position)) {
667
+ const marketPublicKey = await (0, pda_1.getMarketPublicKey)(this.program.programId, position.marketIndex);
668
+ remainingAccounts.push({
669
+ pubkey: marketPublicKey,
670
+ isWritable: true,
671
+ isSigner: false,
672
+ });
673
+ if (marketIndex.eq(position.marketIndex)) {
674
+ foundMarket = true;
675
+ }
676
+ }
677
+ }
678
+ if (!foundMarket) {
679
+ console.log('Warning: lp is not in the market specified -- tx will likely fail');
680
+ }
681
+ return this.program.instruction.settleLp(marketIndex, {
682
+ accounts: {
683
+ state: await this.getStatePublicKey(),
684
+ user: settleeUserAccountPublicKey,
685
+ },
686
+ remainingAccounts: remainingAccounts,
687
+ });
688
+ }
689
+ async removeLiquidity(marketIndex, sharesToBurn) {
690
+ const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getRemoveLiquidityIx(marketIndex, sharesToBurn)), [], this.opts);
691
+ return txSig;
692
+ }
693
+ async getRemoveLiquidityIx(marketIndex, sharesToBurn) {
694
+ const userAccountPublicKey = await this.getUserAccountPublicKey();
695
+ const remainingAccounts = this.getRemainingAccounts({
696
+ writableMarketIndex: marketIndex,
697
+ });
698
+ if (sharesToBurn == undefined) {
699
+ const userAccount = this.getUserAccount();
700
+ const marketPosition = userAccount.positions.filter((position) => position.marketIndex.eq(marketIndex))[0];
701
+ sharesToBurn = marketPosition.lpShares;
702
+ console.log('burning lp shares:', sharesToBurn.toString());
703
+ }
704
+ return this.program.instruction.removeLiquidity(sharesToBurn, marketIndex, {
705
+ accounts: {
706
+ state: await this.getStatePublicKey(),
707
+ user: userAccountPublicKey,
708
+ authority: this.wallet.publicKey,
709
+ },
710
+ remainingAccounts: remainingAccounts,
711
+ });
712
+ }
713
+ async addLiquidity(amount, marketIndex) {
714
+ const { txSig, slot } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getAddLiquidityIx(amount, marketIndex)), [], this.opts);
715
+ this.marketLastSlotCache.set(marketIndex.toNumber(), slot);
716
+ return txSig;
717
+ }
718
+ async getAddLiquidityIx(amount, marketIndex) {
719
+ const userAccountPublicKey = await this.getUserAccountPublicKey();
720
+ const remainingAccounts = this.getRemainingAccounts({
721
+ writableMarketIndex: marketIndex,
722
+ });
723
+ return this.program.instruction.addLiquidity(amount, marketIndex, {
724
+ accounts: {
725
+ state: await this.getStatePublicKey(),
726
+ user: userAccountPublicKey,
727
+ authority: this.wallet.publicKey,
728
+ },
729
+ remainingAccounts: remainingAccounts,
730
+ });
731
+ }
490
732
  async openPosition(direction, amount, marketIndex, limitPrice) {
491
733
  return await this.placeAndTake({
492
734
  orderType: types_1.OrderType.MARKET,
@@ -508,12 +750,13 @@ class ClearingHouse {
508
750
  orderParams = this.getOrderParams(orderParams);
509
751
  const userAccountPublicKey = await this.getUserAccountPublicKey();
510
752
  const remainingAccounts = this.getRemainingAccounts({
511
- writableMarketIndex: orderParams.marketIndex,
753
+ readableMarketIndex: orderParams.marketIndex,
512
754
  });
513
755
  return await this.program.instruction.placeOrder(orderParams, {
514
756
  accounts: {
515
757
  state: await this.getStatePublicKey(),
516
758
  user: userAccountPublicKey,
759
+ userStats: this.getUserStatsAccountPublicKey(),
517
760
  authority: this.wallet.publicKey,
518
761
  },
519
762
  remainingAccounts,
@@ -593,29 +836,21 @@ class ClearingHouse {
593
836
  return txSig;
594
837
  }
595
838
  async getFillOrderIx(userAccountPublicKey, userAccount, order, makerInfo) {
839
+ const userStatsPublicKey = (0, pda_1.getUserStatsAccountPublicKey)(this.program.programId, userAccount.authority);
596
840
  const fillerPublicKey = await this.getUserAccountPublicKey();
841
+ const fillerStatsPublicKey = this.getUserStatsAccountPublicKey();
597
842
  const marketIndex = order.marketIndex;
598
843
  const marketAccount = this.getMarketAccount(marketIndex);
599
844
  const oracleAccountMap = new Map();
600
845
  const bankAccountMap = new Map();
601
846
  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
847
  for (const bankBalance of userAccount.bankBalances) {
613
848
  if (!bankBalance.balance.eq(numericConstants_1.ZERO)) {
614
849
  const bankAccount = this.getBankAccount(bankBalance.bankIndex);
615
850
  bankAccountMap.set(bankBalance.bankIndex.toNumber(), {
616
851
  pubkey: bankAccount.pubkey,
617
852
  isSigner: false,
618
- isWritable: true,
853
+ isWritable: false,
619
854
  });
620
855
  if (!bankAccount.oracle.equals(web3_js_1.PublicKey.default)) {
621
856
  oracleAccountMap.set(bankAccount.oracle.toString(), {
@@ -632,7 +867,7 @@ class ClearingHouse {
632
867
  const market = this.getMarketAccount(position.marketIndex);
633
868
  marketAccountMap.set(position.marketIndex.toNumber(), {
634
869
  pubkey: market.pubkey,
635
- isWritable: true,
870
+ isWritable: false,
636
871
  isSigner: false,
637
872
  });
638
873
  oracleAccountMap.set(market.amm.oracle.toString(), {
@@ -642,6 +877,16 @@ class ClearingHouse {
642
877
  });
643
878
  }
644
879
  }
880
+ marketAccountMap.set(marketIndex.toNumber(), {
881
+ pubkey: marketAccount.pubkey,
882
+ isWritable: true,
883
+ isSigner: false,
884
+ });
885
+ oracleAccountMap.set(marketAccount.amm.oracle.toString(), {
886
+ pubkey: marketAccount.amm.oracle,
887
+ isWritable: false,
888
+ isSigner: false,
889
+ });
645
890
  const remainingAccounts = [
646
891
  ...oracleAccountMap.values(),
647
892
  ...bankAccountMap.values(),
@@ -653,6 +898,11 @@ class ClearingHouse {
653
898
  isWritable: true,
654
899
  isSigner: false,
655
900
  });
901
+ remainingAccounts.push({
902
+ pubkey: makerInfo.makerStats,
903
+ isWritable: true,
904
+ isSigner: false,
905
+ });
656
906
  }
657
907
  const orderId = order.orderId;
658
908
  const makerOrderId = makerInfo ? makerInfo.order.orderId : null;
@@ -660,7 +910,9 @@ class ClearingHouse {
660
910
  accounts: {
661
911
  state: await this.getStatePublicKey(),
662
912
  filler: fillerPublicKey,
913
+ fillerStats: fillerStatsPublicKey,
663
914
  user: userAccountPublicKey,
915
+ userStats: userStatsPublicKey,
664
916
  authority: this.wallet.publicKey,
665
917
  },
666
918
  remainingAccounts,
@@ -677,23 +929,13 @@ class ClearingHouse {
677
929
  const oracleAccountMap = new Map();
678
930
  const bankAccountMap = new Map();
679
931
  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
932
  for (const bankBalance of userAccount.bankBalances) {
691
933
  if (!bankBalance.balance.eq(numericConstants_1.ZERO)) {
692
934
  const bankAccount = this.getBankAccount(bankBalance.bankIndex);
693
935
  bankAccountMap.set(bankBalance.bankIndex.toNumber(), {
694
936
  pubkey: bankAccount.pubkey,
695
937
  isSigner: false,
696
- isWritable: true,
938
+ isWritable: false,
697
939
  });
698
940
  if (!bankAccount.oracle.equals(web3_js_1.PublicKey.default)) {
699
941
  oracleAccountMap.set(bankAccount.oracle.toString(), {
@@ -710,7 +952,7 @@ class ClearingHouse {
710
952
  const market = this.getMarketAccount(position.marketIndex);
711
953
  marketAccountMap.set(position.marketIndex.toNumber(), {
712
954
  pubkey: market.pubkey,
713
- isWritable: true,
955
+ isWritable: false,
714
956
  isSigner: false,
715
957
  });
716
958
  oracleAccountMap.set(market.amm.oracle.toString(), {
@@ -720,6 +962,16 @@ class ClearingHouse {
720
962
  });
721
963
  }
722
964
  }
965
+ marketAccountMap.set(marketIndex.toNumber(), {
966
+ pubkey: marketAccount.pubkey,
967
+ isWritable: true,
968
+ isSigner: false,
969
+ });
970
+ oracleAccountMap.set(marketAccount.amm.oracle.toString(), {
971
+ pubkey: marketAccount.amm.oracle,
972
+ isWritable: false,
973
+ isSigner: false,
974
+ });
723
975
  const remainingAccounts = [
724
976
  ...oracleAccountMap.values(),
725
977
  ...bankAccountMap.values(),
@@ -743,6 +995,7 @@ class ClearingHouse {
743
995
  }
744
996
  async getPlaceAndTakeIx(orderParams, makerInfo) {
745
997
  orderParams = this.getOrderParams(orderParams);
998
+ const userStatsPublicKey = await this.getUserStatsAccountPublicKey();
746
999
  const userAccountPublicKey = await this.getUserAccountPublicKey();
747
1000
  const remainingAccounts = this.getRemainingAccounts({
748
1001
  writableMarketIndex: orderParams.marketIndex,
@@ -756,11 +1009,17 @@ class ClearingHouse {
756
1009
  isSigner: false,
757
1010
  isWritable: true,
758
1011
  });
1012
+ remainingAccounts.push({
1013
+ pubkey: makerInfo.makerStats,
1014
+ isSigner: false,
1015
+ isWritable: true,
1016
+ });
759
1017
  }
760
1018
  return await this.program.instruction.placeAndTake(orderParams, makerOrderId, {
761
1019
  accounts: {
762
1020
  state: await this.getStatePublicKey(),
763
1021
  user: userAccountPublicKey,
1022
+ userStats: userStatsPublicKey,
764
1023
  authority: this.wallet.publicKey,
765
1024
  },
766
1025
  remainingAccounts,
@@ -773,22 +1032,19 @@ class ClearingHouse {
773
1032
  }
774
1033
  async getPlaceAndMakeIx(orderParams, takerInfo) {
775
1034
  orderParams = this.getOrderParams(orderParams);
1035
+ const userStatsPublicKey = this.getUserStatsAccountPublicKey();
776
1036
  const userAccountPublicKey = await this.getUserAccountPublicKey();
777
1037
  const remainingAccounts = this.getRemainingAccounts({
778
1038
  writableMarketIndex: orderParams.marketIndex,
779
- writableBankIndex: numericConstants_1.QUOTE_ASSET_BANK_INDEX,
780
1039
  });
781
1040
  const takerOrderId = takerInfo.order.orderId;
782
- remainingAccounts.push({
783
- pubkey: takerInfo.taker,
784
- isSigner: false,
785
- isWritable: true,
786
- });
787
1041
  return await this.program.instruction.placeAndMake(orderParams, takerOrderId, {
788
1042
  accounts: {
789
1043
  state: await this.getStatePublicKey(),
790
1044
  user: userAccountPublicKey,
1045
+ userStats: userStatsPublicKey,
791
1046
  taker: takerInfo.taker,
1047
+ takerStats: takerInfo.takerStats,
792
1048
  authority: this.wallet.publicKey,
793
1049
  },
794
1050
  remainingAccounts,
@@ -799,7 +1055,7 @@ class ClearingHouse {
799
1055
  * @param marketIndex
800
1056
  * @returns
801
1057
  */
802
- async closePosition(marketIndex) {
1058
+ async closePosition(marketIndex, limitPrice) {
803
1059
  const userPosition = this.getUser().getUserPosition(marketIndex);
804
1060
  if (!userPosition) {
805
1061
  throw Error(`No position in market ${marketIndex.toString()}`);
@@ -808,8 +1064,9 @@ class ClearingHouse {
808
1064
  orderType: types_1.OrderType.MARKET,
809
1065
  marketIndex,
810
1066
  direction: (0, position_1.findDirectionToClose)(userPosition),
811
- baseAssetAmount: userPosition.baseAssetAmount,
1067
+ baseAssetAmount: userPosition.baseAssetAmount.abs(),
812
1068
  reduceOnly: true,
1069
+ price: limitPrice,
813
1070
  });
814
1071
  }
815
1072
  async settlePNLs(users, marketIndex) {
@@ -834,7 +1091,7 @@ class ClearingHouse {
834
1091
  const market = this.getMarketAccount(position.marketIndex);
835
1092
  marketAccountMap.set(position.marketIndex.toNumber(), {
836
1093
  pubkey: market.pubkey,
837
- isWritable: true,
1094
+ isWritable: false,
838
1095
  isSigner: false,
839
1096
  });
840
1097
  oracleAccountMap.set(market.amm.oracle.toString(), {
@@ -896,7 +1153,9 @@ class ClearingHouse {
896
1153
  return txSig;
897
1154
  }
898
1155
  async getLiquidatePerpIx(userAccountPublicKey, userAccount, marketIndex, maxBaseAssetAmount) {
1156
+ const userStatsPublicKey = (0, pda_1.getUserStatsAccountPublicKey)(this.program.programId, userAccount.authority);
899
1157
  const liquidatorPublicKey = await this.getUserAccountPublicKey();
1158
+ const liquidatorStatsPublicKey = this.getUserStatsAccountPublicKey();
900
1159
  const remainingAccounts = this.getRemainingAccountsForLiquidation({
901
1160
  writableMarketIndex: marketIndex,
902
1161
  userAccount,
@@ -906,7 +1165,9 @@ class ClearingHouse {
906
1165
  state: await this.getStatePublicKey(),
907
1166
  authority: this.wallet.publicKey,
908
1167
  user: userAccountPublicKey,
1168
+ userStats: userStatsPublicKey,
909
1169
  liquidator: liquidatorPublicKey,
1170
+ liquidatorStats: liquidatorStatsPublicKey,
910
1171
  },
911
1172
  remainingAccounts: remainingAccounts,
912
1173
  });
@@ -973,6 +1234,46 @@ class ClearingHouse {
973
1234
  remainingAccounts: remainingAccounts,
974
1235
  });
975
1236
  }
1237
+ async resolvePerpBankruptcy(userAccountPublicKey, userAccount, marketIndex) {
1238
+ const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getResolvePerpBankruptcyIx(userAccountPublicKey, userAccount, marketIndex)), [], this.opts);
1239
+ return txSig;
1240
+ }
1241
+ async getResolvePerpBankruptcyIx(userAccountPublicKey, userAccount, marketIndex) {
1242
+ const liquidatorPublicKey = await this.getUserAccountPublicKey();
1243
+ const remainingAccounts = this.getRemainingAccountsForLiquidation({
1244
+ writableMarketIndex: marketIndex,
1245
+ userAccount,
1246
+ });
1247
+ return await this.program.instruction.resolvePerpBankruptcy(marketIndex, {
1248
+ accounts: {
1249
+ state: await this.getStatePublicKey(),
1250
+ authority: this.wallet.publicKey,
1251
+ user: userAccountPublicKey,
1252
+ liquidator: liquidatorPublicKey,
1253
+ },
1254
+ remainingAccounts: remainingAccounts,
1255
+ });
1256
+ }
1257
+ async resolveBorrowBankruptcy(userAccountPublicKey, userAccount, bankIndex) {
1258
+ const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getResolveBorrowBankruptcyIx(userAccountPublicKey, userAccount, bankIndex)), [], this.opts);
1259
+ return txSig;
1260
+ }
1261
+ async getResolveBorrowBankruptcyIx(userAccountPublicKey, userAccount, bankIndex) {
1262
+ const liquidatorPublicKey = await this.getUserAccountPublicKey();
1263
+ const remainingAccounts = this.getRemainingAccountsForLiquidation({
1264
+ writableBankIndexes: [bankIndex],
1265
+ userAccount,
1266
+ });
1267
+ return await this.program.instruction.resolveBorrowBankruptcy(bankIndex, {
1268
+ accounts: {
1269
+ state: await this.getStatePublicKey(),
1270
+ authority: this.wallet.publicKey,
1271
+ user: userAccountPublicKey,
1272
+ liquidator: liquidatorPublicKey,
1273
+ },
1274
+ remainingAccounts: remainingAccounts,
1275
+ });
1276
+ }
976
1277
  getRemainingAccountsForLiquidation(params) {
977
1278
  const liquidateeUserAccount = params.userAccount;
978
1279
  const oracleAccountMap = new Map();
@@ -18,6 +18,7 @@ export declare type ClearingHouseConfig = {
18
18
  bankIndexes?: BN[];
19
19
  oracleInfos?: OracleInfo[];
20
20
  env?: DriftEnv;
21
+ userStats?: boolean;
21
22
  };
22
23
  declare type ClearingHouseSubscriptionConfig = {
23
24
  type: 'websocket';