@drift-labs/sdk 0.2.0-master.12 → 0.2.0-master.15

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 (117) hide show
  1. package/lib/accounts/bulkUserStatsSubscription.d.ts +7 -0
  2. package/lib/accounts/bulkUserStatsSubscription.js +21 -0
  3. package/lib/accounts/bulkUserSubscription.js +0 -1
  4. package/lib/accounts/fetch.d.ts +2 -1
  5. package/lib/accounts/fetch.js +9 -1
  6. package/lib/accounts/pollingUserStatsAccountSubscriber.d.ts +27 -0
  7. package/lib/accounts/pollingUserStatsAccountSubscriber.js +113 -0
  8. package/lib/accounts/types.d.ts +14 -2
  9. package/lib/accounts/webSocketUserStatsAccountSubsriber.d.ts +20 -0
  10. package/lib/accounts/webSocketUserStatsAccountSubsriber.js +47 -0
  11. package/lib/addresses/pda.d.ts +1 -0
  12. package/lib/addresses/pda.js +8 -1
  13. package/lib/admin.d.ts +2 -0
  14. package/lib/admin.js +18 -0
  15. package/lib/clearingHouse.d.ts +17 -1
  16. package/lib/clearingHouse.js +195 -14
  17. package/lib/clearingHouseConfig.d.ts +1 -0
  18. package/lib/clearingHouseUser.d.ts +5 -0
  19. package/lib/clearingHouseUser.js +97 -3
  20. package/lib/clearingHouseUserStats.d.ts +17 -0
  21. package/lib/clearingHouseUserStats.js +36 -0
  22. package/lib/clearingHouseUserStatsConfig.d.ts +14 -0
  23. package/{src/clearingHouseConfig.js → lib/clearingHouseUserStatsConfig.js} +0 -0
  24. package/lib/config.js +1 -1
  25. package/lib/factory/bigNum.js +7 -9
  26. package/lib/idl/clearing_house.json +620 -64
  27. package/lib/math/amm.js +2 -2
  28. package/lib/math/bankBalance.d.ts +4 -0
  29. package/lib/math/bankBalance.js +24 -2
  30. package/lib/math/oracles.d.ts +3 -0
  31. package/lib/math/oracles.js +25 -5
  32. package/lib/math/position.js +2 -1
  33. package/lib/math/trade.js +2 -2
  34. package/lib/types.d.ts +57 -9
  35. package/lib/types.js +6 -0
  36. package/package.json +1 -1
  37. package/src/accounts/bulkUserStatsSubscription.ts +33 -0
  38. package/src/accounts/bulkUserSubscription.ts +0 -1
  39. package/src/accounts/fetch.ts +27 -2
  40. package/src/accounts/pollingUserStatsAccountSubscriber.ts +172 -0
  41. package/src/accounts/types.ts +18 -0
  42. package/src/accounts/webSocketUserStatsAccountSubsriber.ts +80 -0
  43. package/src/addresses/pda.ts +13 -0
  44. package/src/admin.ts +29 -1
  45. package/src/clearingHouse.ts +318 -15
  46. package/src/clearingHouseConfig.ts +1 -0
  47. package/src/clearingHouseUser.ts +113 -10
  48. package/src/clearingHouseUserStats.ts +53 -0
  49. package/src/clearingHouseUserStatsConfig.ts +18 -0
  50. package/src/config.ts +1 -1
  51. package/src/factory/bigNum.ts +6 -7
  52. package/src/idl/clearing_house.json +620 -64
  53. package/src/math/amm.ts +8 -5
  54. package/src/math/bankBalance.ts +50 -1
  55. package/src/math/oracles.ts +42 -5
  56. package/src/math/position.ts +2 -1
  57. package/src/math/trade.ts +2 -2
  58. package/src/types.ts +61 -9
  59. package/tests/bn/test.ts +8 -0
  60. package/src/accounts/bulkAccountLoader.js +0 -197
  61. package/src/accounts/bulkUserSubscription.js +0 -33
  62. package/src/accounts/pollingClearingHouseAccountSubscriber.js +0 -311
  63. package/src/accounts/pollingOracleSubscriber.js +0 -93
  64. package/src/accounts/pollingTokenAccountSubscriber.js +0 -90
  65. package/src/accounts/pollingUserAccountSubscriber.js +0 -132
  66. package/src/accounts/types.js +0 -10
  67. package/src/accounts/utils.js +0 -7
  68. package/src/accounts/webSocketAccountSubscriber.js +0 -93
  69. package/src/accounts/webSocketClearingHouseAccountSubscriber.js +0 -233
  70. package/src/accounts/webSocketUserAccountSubscriber.js +0 -62
  71. package/src/addresses/marketAddresses.js +0 -26
  72. package/src/assert/assert.js +0 -9
  73. package/src/clearingHouseUserConfig.js +0 -2
  74. package/src/constants/banks.js +0 -42
  75. package/src/constants/markets.js +0 -42
  76. package/src/constants/numericConstants.js +0 -41
  77. package/src/events/eventList.js +0 -77
  78. package/src/events/eventSubscriber.js +0 -139
  79. package/src/events/fetchLogs.js +0 -50
  80. package/src/events/pollingLogProvider.js +0 -64
  81. package/src/events/sort.js +0 -44
  82. package/src/events/txEventCache.js +0 -71
  83. package/src/events/types.js +0 -20
  84. package/src/events/webSocketLogProvider.js +0 -41
  85. package/src/examples/makeTradeExample.js +0 -80
  86. package/src/factory/bigNum.js +0 -390
  87. package/src/factory/oracleClient.js +0 -20
  88. package/src/index.js +0 -69
  89. package/src/math/amm.js +0 -369
  90. package/src/math/auction.js +0 -42
  91. package/src/math/conversion.js +0 -11
  92. package/src/math/funding.js +0 -248
  93. package/src/math/oracles.js +0 -26
  94. package/src/math/repeg.js +0 -128
  95. package/src/math/state.js +0 -15
  96. package/src/math/trade.js +0 -253
  97. package/src/math/utils.js +0 -26
  98. package/src/math/utils.js.map +0 -1
  99. package/src/mockUSDCFaucet.js +0 -280
  100. package/src/oracles/oracleClientCache.js +0 -19
  101. package/src/oracles/pythClient.js +0 -46
  102. package/src/oracles/quoteAssetOracleClient.js +0 -32
  103. package/src/oracles/switchboardClient.js +0 -69
  104. package/src/oracles/types.js +0 -2
  105. package/src/orderParams.js +0 -20
  106. package/src/slot/SlotSubscriber.js +0 -39
  107. package/src/token/index.js +0 -38
  108. package/src/tokenFaucet.js +0 -189
  109. package/src/tx/types.js +0 -2
  110. package/src/tx/utils.js +0 -17
  111. package/src/types.js +0 -125
  112. package/src/userName.js +0 -20
  113. package/src/util/computeUnits.js +0 -27
  114. package/src/util/getTokenAddress.js +0 -9
  115. package/src/util/promiseTimeout.js +0 -14
  116. package/src/util/tps.js +0 -27
  117. package/src/wallet.js +0 -35
@@ -0,0 +1,80 @@
1
+ import {
2
+ DataAndSlot,
3
+ AccountSubscriber,
4
+ NotSubscribedError,
5
+ UserStatsAccountSubscriber,
6
+ UserStatsAccountEvents,
7
+ } from './types';
8
+ import { Program } from '@project-serum/anchor';
9
+ import StrictEventEmitter from 'strict-event-emitter-types';
10
+ import { EventEmitter } from 'events';
11
+ import { PublicKey } from '@solana/web3.js';
12
+ import { WebSocketAccountSubscriber } from './webSocketAccountSubscriber';
13
+ import { UserStatsAccount } from '../types';
14
+
15
+ export class WebSocketUserStatsAccountSubscriber
16
+ implements UserStatsAccountSubscriber
17
+ {
18
+ isSubscribed: boolean;
19
+ program: Program;
20
+ eventEmitter: StrictEventEmitter<EventEmitter, UserStatsAccountEvents>;
21
+ userStatsAccountPublicKey: PublicKey;
22
+
23
+ userStatsAccountSubscriber: AccountSubscriber<UserStatsAccount>;
24
+
25
+ public constructor(program: Program, userStatsAccountPublicKey: PublicKey) {
26
+ this.isSubscribed = false;
27
+ this.program = program;
28
+ this.userStatsAccountPublicKey = userStatsAccountPublicKey;
29
+ this.eventEmitter = new EventEmitter();
30
+ }
31
+
32
+ async subscribe(): Promise<boolean> {
33
+ if (this.isSubscribed) {
34
+ return true;
35
+ }
36
+
37
+ this.userStatsAccountSubscriber = new WebSocketAccountSubscriber(
38
+ 'userStats',
39
+ this.program,
40
+ this.userStatsAccountPublicKey
41
+ );
42
+ await this.userStatsAccountSubscriber.subscribe(
43
+ (data: UserStatsAccount) => {
44
+ this.eventEmitter.emit('userStatsAccountUpdate', data);
45
+ this.eventEmitter.emit('update');
46
+ }
47
+ );
48
+
49
+ this.eventEmitter.emit('update');
50
+ this.isSubscribed = true;
51
+ return true;
52
+ }
53
+
54
+ async fetch(): Promise<void> {
55
+ await Promise.all([this.userStatsAccountSubscriber.fetch()]);
56
+ }
57
+
58
+ async unsubscribe(): Promise<void> {
59
+ if (!this.isSubscribed) {
60
+ return;
61
+ }
62
+
63
+ await Promise.all([this.userStatsAccountSubscriber.unsubscribe()]);
64
+
65
+ this.isSubscribed = false;
66
+ }
67
+
68
+ assertIsSubscribed(): void {
69
+ if (!this.isSubscribed) {
70
+ throw new NotSubscribedError(
71
+ 'You must call `subscribe` before using this function'
72
+ );
73
+ }
74
+ }
75
+
76
+ public getUserStatsAccountAndSlot(): DataAndSlot<UserStatsAccount> {
77
+ this.assertIsSubscribed();
78
+ return this.userStatsAccountSubscriber.dataAndSlot;
79
+ }
80
+ }
@@ -57,6 +57,19 @@ export function getUserAccountPublicKeySync(
57
57
  )[0];
58
58
  }
59
59
 
60
+ export function getUserStatsAccountPublicKey(
61
+ programId: PublicKey,
62
+ authority: PublicKey
63
+ ): PublicKey {
64
+ return anchor.web3.PublicKey.findProgramAddressSync(
65
+ [
66
+ Buffer.from(anchor.utils.bytes.utf8.encode('user_stats')),
67
+ authority.toBuffer(),
68
+ ],
69
+ programId
70
+ )[0];
71
+ }
72
+
60
73
  export async function getMarketPublicKey(
61
74
  programId: PublicKey,
62
75
  marketIndex: BN
package/src/admin.ts CHANGED
@@ -575,6 +575,35 @@ export class Admin extends ClearingHouse {
575
575
  });
576
576
  }
577
577
 
578
+ public async updateBankWithdrawGuardThreshold(
579
+ bankIndex: BN,
580
+ withdrawGuardThreshold: BN
581
+ ): Promise<TransactionSignature> {
582
+ return await this.program.rpc.updateBankWithdrawGuardThreshold(
583
+ withdrawGuardThreshold,
584
+ {
585
+ accounts: {
586
+ admin: this.wallet.publicKey,
587
+ state: await this.getStatePublicKey(),
588
+ bank: await getBankPublicKey(this.program.programId, bankIndex),
589
+ },
590
+ }
591
+ );
592
+ }
593
+
594
+ public async updateLpCooldownTime(
595
+ marketIndex: BN,
596
+ cooldownTime: BN
597
+ ): Promise<TransactionSignature> {
598
+ return await this.program.rpc.updateLpCooldownTime(cooldownTime, {
599
+ accounts: {
600
+ admin: this.wallet.publicKey,
601
+ state: await this.getStatePublicKey(),
602
+ market: await getMarketPublicKey(this.program.programId, marketIndex),
603
+ },
604
+ });
605
+ }
606
+
578
607
  public async updateMarketOracle(
579
608
  marketIndex: BN,
580
609
  oracle: PublicKey,
@@ -662,7 +691,6 @@ export class Admin extends ClearingHouse {
662
691
  },
663
692
  });
664
693
  }
665
-
666
694
  public async updateExchangePaused(
667
695
  exchangePaused: boolean
668
696
  ): Promise<TransactionSignature> {
@@ -41,6 +41,7 @@ import {
41
41
  getMarketPublicKey,
42
42
  getUserAccountPublicKey,
43
43
  getUserAccountPublicKeySync,
44
+ getUserStatsAccountPublicKey,
44
45
  } from './addresses/pda';
45
46
  import {
46
47
  ClearingHouseAccountSubscriber,
@@ -62,6 +63,7 @@ import { ClearingHouseUser } from './clearingHouseUser';
62
63
  import { ClearingHouseUserAccountSubscriptionConfig } from './clearingHouseUserConfig';
63
64
  import { getMarketsBanksAndOraclesForSubscription } from './config';
64
65
  import { WRAPPED_SOL_MINT } from './constants/banks';
66
+ import { ClearingHouseUserStats } from './clearingHouseUserStats';
65
67
 
66
68
  /**
67
69
  * # ClearingHouse
@@ -74,6 +76,7 @@ export class ClearingHouse {
74
76
  provider: AnchorProvider;
75
77
  opts?: ConfirmOptions;
76
78
  users = new Map<number, ClearingHouseUser>();
79
+ userStats?: ClearingHouseUserStats;
77
80
  activeUserId: number;
78
81
  userAccountSubscriptionConfig: ClearingHouseUserAccountSubscriptionConfig;
79
82
  accountSubscriber: ClearingHouseAccountSubscriber;
@@ -117,6 +120,16 @@ export class ClearingHouse {
117
120
  type: 'websocket',
118
121
  };
119
122
  this.createUsers(userIds, this.userAccountSubscriptionConfig);
123
+ if (config.userStats) {
124
+ this.userStats = new ClearingHouseUserStats({
125
+ clearingHouse: this,
126
+ userStatsAccountPublicKey: getUserStatsAccountPublicKey(
127
+ this.program.programId,
128
+ this.wallet.publicKey
129
+ ),
130
+ accountSubscription: this.userAccountSubscriptionConfig,
131
+ });
132
+ }
120
133
 
121
134
  let marketIndexes = config.marketIndexes;
122
135
  let bankIndexes = config.bankIndexes;
@@ -188,6 +201,9 @@ export class ClearingHouse {
188
201
  const subscribePromises = this.subscribeUsers().concat(
189
202
  this.accountSubscriber.subscribe()
190
203
  );
204
+ if (this.userStats !== undefined) {
205
+ subscribePromises.concat(this.userStats.subscribe());
206
+ }
191
207
  this.isSubscribed = (await Promise.all(subscribePromises)).reduce(
192
208
  (success, prevSuccess) => success && prevSuccess
193
209
  );
@@ -213,6 +229,9 @@ export class ClearingHouse {
213
229
  const unsubscribePromises = this.unsubscribeUsers().concat(
214
230
  this.accountSubscriber.unsubscribe()
215
231
  );
232
+ if (this.userStats !== undefined) {
233
+ unsubscribePromises.concat(this.userStats.unsubscribe());
234
+ }
216
235
  await Promise.all(unsubscribePromises);
217
236
  this.isSubscribed = false;
218
237
  }
@@ -302,6 +321,7 @@ export class ClearingHouse {
302
321
  }
303
322
 
304
323
  this.activeUserId = activeUserId;
324
+ this.userStatsAccountPublicKey = undefined;
305
325
  }
306
326
 
307
327
  public async switchActiveUser(userId: number): Promise<void> {
@@ -325,7 +345,12 @@ export class ClearingHouse {
325
345
  const [userAccountPublicKey, initializeUserAccountIx] =
326
346
  await this.getInitializeUserInstructions(userId, name);
327
347
 
328
- const tx = new Transaction().add(initializeUserAccountIx);
348
+ const tx = new Transaction();
349
+ if (userId === 0) {
350
+ // not the safest assumption, can explicitly check if user stats account exists if it causes problems
351
+ tx.add(await this.getInitializeUserStatsIx());
352
+ }
353
+ tx.add(initializeUserAccountIx);
329
354
  const { txSig } = await this.txSender.send(tx, [], this.opts);
330
355
  return [txSig, userAccountPublicKey];
331
356
  }
@@ -345,6 +370,7 @@ export class ClearingHouse {
345
370
  await this.program.instruction.initializeUser(userId, nameBuffer, {
346
371
  accounts: {
347
372
  user: userAccountPublicKey,
373
+ userStats: this.getUserStatsAccountPublicKey(),
348
374
  authority: this.wallet.publicKey,
349
375
  payer: this.wallet.publicKey,
350
376
  rent: anchor.web3.SYSVAR_RENT_PUBKEY,
@@ -356,6 +382,19 @@ export class ClearingHouse {
356
382
  return [userAccountPublicKey, initializeUserAccountIx];
357
383
  }
358
384
 
385
+ async getInitializeUserStatsIx(): Promise<TransactionInstruction> {
386
+ return await this.program.instruction.initializeUserStats({
387
+ accounts: {
388
+ userStats: this.getUserStatsAccountPublicKey(),
389
+ authority: this.wallet.publicKey,
390
+ payer: this.wallet.publicKey,
391
+ rent: anchor.web3.SYSVAR_RENT_PUBKEY,
392
+ systemProgram: anchor.web3.SystemProgram.programId,
393
+ state: await this.getStatePublicKey(),
394
+ },
395
+ });
396
+ }
397
+
359
398
  public getUser(userId?: number): ClearingHouseUser {
360
399
  userId = userId ?? this.activeUserId;
361
400
  if (!this.users.has(userId)) {
@@ -368,6 +407,23 @@ export class ClearingHouse {
368
407
  return [...this.users.values()];
369
408
  }
370
409
 
410
+ public getUserStats(): ClearingHouseUserStats {
411
+ return this.userStats;
412
+ }
413
+
414
+ userStatsAccountPublicKey: PublicKey;
415
+ public getUserStatsAccountPublicKey(): PublicKey {
416
+ if (this.userStatsAccountPublicKey) {
417
+ return this.userStatsAccountPublicKey;
418
+ }
419
+
420
+ this.userStatsAccountPublicKey = getUserStatsAccountPublicKey(
421
+ this.program.programId,
422
+ this.wallet.publicKey
423
+ );
424
+ return this.userStatsAccountPublicKey;
425
+ }
426
+
371
427
  public async getUserAccountPublicKey(): Promise<PublicKey> {
372
428
  return this.getUser().userAccountPublicKey;
373
429
  }
@@ -831,6 +887,9 @@ export class ClearingHouse {
831
887
  false
832
888
  );
833
889
 
890
+ if (userId === 0) {
891
+ tx.add(await this.getInitializeUserStatsIx());
892
+ }
834
893
  tx.add(initializeUserAccountIx).add(depositCollateralIx);
835
894
 
836
895
  // Close the wrapped sol account at the end of the transaction
@@ -880,11 +939,12 @@ export class ClearingHouse {
880
939
  false
881
940
  );
882
941
 
883
- const tx = new Transaction()
884
- .add(createAssociatedAccountIx)
885
- .add(mintToIx)
886
- .add(initializeUserAccountIx)
887
- .add(depositCollateralIx);
942
+ const tx = new Transaction().add(createAssociatedAccountIx).add(mintToIx);
943
+
944
+ if (userId === 0) {
945
+ tx.add(await this.getInitializeUserStatsIx());
946
+ }
947
+ tx.add(initializeUserAccountIx).add(depositCollateralIx);
888
948
 
889
949
  const txSig = await this.program.provider.sendAndConfirm(tx, []);
890
950
 
@@ -1056,6 +1116,135 @@ export class ClearingHouse {
1056
1116
  });
1057
1117
  }
1058
1118
 
1119
+ public async settleLP(
1120
+ settleeUserAccountPublicKey: PublicKey,
1121
+ marketIndex: BN
1122
+ ): Promise<TransactionSignature> {
1123
+ const { txSig } = await this.txSender.send(
1124
+ wrapInTx(await this.settleLPIx(settleeUserAccountPublicKey, marketIndex)),
1125
+ [],
1126
+ this.opts
1127
+ );
1128
+ return txSig;
1129
+ }
1130
+
1131
+ public async settleLPIx(
1132
+ settleeUserAccountPublicKey: PublicKey,
1133
+ marketIndex: BN
1134
+ ): Promise<TransactionInstruction> {
1135
+ const settleeUserAccount = (await this.program.account.user.fetch(
1136
+ settleeUserAccountPublicKey
1137
+ )) as UserAccount;
1138
+ const userPositions = settleeUserAccount.positions;
1139
+ const remainingAccounts = [];
1140
+
1141
+ let foundMarket = false;
1142
+ for (const position of userPositions) {
1143
+ if (!positionIsAvailable(position)) {
1144
+ const marketPublicKey = await getMarketPublicKey(
1145
+ this.program.programId,
1146
+ position.marketIndex
1147
+ );
1148
+ remainingAccounts.push({
1149
+ pubkey: marketPublicKey,
1150
+ isWritable: true,
1151
+ isSigner: false,
1152
+ });
1153
+
1154
+ if (marketIndex.eq(position.marketIndex)) {
1155
+ foundMarket = true;
1156
+ }
1157
+ }
1158
+ }
1159
+
1160
+ if (!foundMarket) {
1161
+ console.log(
1162
+ 'Warning: lp is not in the market specified -- tx will likely fail'
1163
+ );
1164
+ }
1165
+
1166
+ return this.program.instruction.settleLp(marketIndex, {
1167
+ accounts: {
1168
+ state: await this.getStatePublicKey(),
1169
+ user: settleeUserAccountPublicKey,
1170
+ },
1171
+ remainingAccounts: remainingAccounts,
1172
+ });
1173
+ }
1174
+
1175
+ public async removeLiquidity(
1176
+ marketIndex: BN,
1177
+ sharesToBurn?: BN
1178
+ ): Promise<TransactionSignature> {
1179
+ const { txSig } = await this.txSender.send(
1180
+ wrapInTx(await this.getRemoveLiquidityIx(marketIndex, sharesToBurn)),
1181
+ [],
1182
+ this.opts
1183
+ );
1184
+ return txSig;
1185
+ }
1186
+
1187
+ public async getRemoveLiquidityIx(
1188
+ marketIndex: BN,
1189
+ sharesToBurn?: BN
1190
+ ): Promise<TransactionInstruction> {
1191
+ const userAccountPublicKey = await this.getUserAccountPublicKey();
1192
+
1193
+ const remainingAccounts = this.getRemainingAccounts({
1194
+ writableMarketIndex: marketIndex,
1195
+ });
1196
+
1197
+ if (sharesToBurn == undefined) {
1198
+ const userAccount = this.getUserAccount();
1199
+ const marketPosition = userAccount.positions.filter((position) =>
1200
+ position.marketIndex.eq(marketIndex)
1201
+ )[0];
1202
+ sharesToBurn = marketPosition.lpShares;
1203
+ console.log('burning lp shares:', sharesToBurn.toString());
1204
+ }
1205
+
1206
+ return this.program.instruction.removeLiquidity(sharesToBurn, marketIndex, {
1207
+ accounts: {
1208
+ state: await this.getStatePublicKey(),
1209
+ user: userAccountPublicKey,
1210
+ authority: this.wallet.publicKey,
1211
+ },
1212
+ remainingAccounts: remainingAccounts,
1213
+ });
1214
+ }
1215
+
1216
+ public async addLiquidity(
1217
+ amount: BN,
1218
+ marketIndex: BN
1219
+ ): Promise<TransactionSignature> {
1220
+ const { txSig, slot } = await this.txSender.send(
1221
+ wrapInTx(await this.getAddLiquidityIx(amount, marketIndex)),
1222
+ [],
1223
+ this.opts
1224
+ );
1225
+ this.marketLastSlotCache.set(marketIndex.toNumber(), slot);
1226
+ return txSig;
1227
+ }
1228
+
1229
+ public async getAddLiquidityIx(
1230
+ amount: BN,
1231
+ marketIndex: BN
1232
+ ): Promise<TransactionInstruction> {
1233
+ const userAccountPublicKey = await this.getUserAccountPublicKey();
1234
+ const remainingAccounts = this.getRemainingAccounts({
1235
+ writableMarketIndex: marketIndex,
1236
+ });
1237
+
1238
+ return this.program.instruction.addLiquidity(amount, marketIndex, {
1239
+ accounts: {
1240
+ state: await this.getStatePublicKey(),
1241
+ user: userAccountPublicKey,
1242
+ authority: this.wallet.publicKey,
1243
+ },
1244
+ remainingAccounts: remainingAccounts,
1245
+ });
1246
+ }
1247
+
1059
1248
  public async openPosition(
1060
1249
  direction: PositionDirection,
1061
1250
  amount: BN,
@@ -1101,6 +1290,7 @@ export class ClearingHouse {
1101
1290
  accounts: {
1102
1291
  state: await this.getStatePublicKey(),
1103
1292
  user: userAccountPublicKey,
1293
+ userStats: this.getUserStatsAccountPublicKey(),
1104
1294
  authority: this.wallet.publicKey,
1105
1295
  },
1106
1296
  remainingAccounts,
@@ -1228,7 +1418,13 @@ export class ClearingHouse {
1228
1418
  order: Order,
1229
1419
  makerInfo?: MakerInfo
1230
1420
  ): Promise<TransactionInstruction> {
1421
+ const userStatsPublicKey = getUserStatsAccountPublicKey(
1422
+ this.program.programId,
1423
+ userAccount.authority
1424
+ );
1425
+
1231
1426
  const fillerPublicKey = await this.getUserAccountPublicKey();
1427
+ const fillerStatsPublicKey = this.getUserStatsAccountPublicKey();
1232
1428
 
1233
1429
  const marketIndex = order.marketIndex;
1234
1430
  const marketAccount = this.getMarketAccount(marketIndex);
@@ -1298,6 +1494,11 @@ export class ClearingHouse {
1298
1494
  isWritable: true,
1299
1495
  isSigner: false,
1300
1496
  });
1497
+ remainingAccounts.push({
1498
+ pubkey: makerInfo.makerStats,
1499
+ isWritable: true,
1500
+ isSigner: false,
1501
+ });
1301
1502
  }
1302
1503
 
1303
1504
  const orderId = order.orderId;
@@ -1307,7 +1508,9 @@ export class ClearingHouse {
1307
1508
  accounts: {
1308
1509
  state: await this.getStatePublicKey(),
1309
1510
  filler: fillerPublicKey,
1511
+ fillerStats: fillerStatsPublicKey,
1310
1512
  user: userAccountPublicKey,
1513
+ userStats: userStatsPublicKey,
1311
1514
  authority: this.wallet.publicKey,
1312
1515
  },
1313
1516
  remainingAccounts,
@@ -1426,6 +1629,7 @@ export class ClearingHouse {
1426
1629
  makerInfo?: MakerInfo
1427
1630
  ): Promise<TransactionInstruction> {
1428
1631
  orderParams = this.getOrderParams(orderParams);
1632
+ const userStatsPublicKey = await this.getUserStatsAccountPublicKey();
1429
1633
  const userAccountPublicKey = await this.getUserAccountPublicKey();
1430
1634
 
1431
1635
  const remainingAccounts = this.getRemainingAccounts({
@@ -1441,6 +1645,11 @@ export class ClearingHouse {
1441
1645
  isSigner: false,
1442
1646
  isWritable: true,
1443
1647
  });
1648
+ remainingAccounts.push({
1649
+ pubkey: makerInfo.makerStats,
1650
+ isSigner: false,
1651
+ isWritable: true,
1652
+ });
1444
1653
  }
1445
1654
 
1446
1655
  return await this.program.instruction.placeAndTake(
@@ -1450,6 +1659,7 @@ export class ClearingHouse {
1450
1659
  accounts: {
1451
1660
  state: await this.getStatePublicKey(),
1452
1661
  user: userAccountPublicKey,
1662
+ userStats: userStatsPublicKey,
1453
1663
  authority: this.wallet.publicKey,
1454
1664
  },
1455
1665
  remainingAccounts,
@@ -1477,20 +1687,14 @@ export class ClearingHouse {
1477
1687
  takerInfo: TakerInfo
1478
1688
  ): Promise<TransactionInstruction> {
1479
1689
  orderParams = this.getOrderParams(orderParams);
1690
+ const userStatsPublicKey = this.getUserStatsAccountPublicKey();
1480
1691
  const userAccountPublicKey = await this.getUserAccountPublicKey();
1481
1692
 
1482
1693
  const remainingAccounts = this.getRemainingAccounts({
1483
1694
  writableMarketIndex: orderParams.marketIndex,
1484
- writableBankIndex: QUOTE_ASSET_BANK_INDEX,
1485
1695
  });
1486
1696
 
1487
1697
  const takerOrderId = takerInfo!.order!.orderId;
1488
- remainingAccounts.push({
1489
- pubkey: takerInfo.taker,
1490
- isSigner: false,
1491
- isWritable: true,
1492
- });
1493
-
1494
1698
  return await this.program.instruction.placeAndMake(
1495
1699
  orderParams,
1496
1700
  takerOrderId,
@@ -1498,7 +1702,9 @@ export class ClearingHouse {
1498
1702
  accounts: {
1499
1703
  state: await this.getStatePublicKey(),
1500
1704
  user: userAccountPublicKey,
1705
+ userStats: userStatsPublicKey,
1501
1706
  taker: takerInfo.taker,
1707
+ takerStats: takerInfo.takerStats,
1502
1708
  authority: this.wallet.publicKey,
1503
1709
  },
1504
1710
  remainingAccounts,
@@ -1511,7 +1717,10 @@ export class ClearingHouse {
1511
1717
  * @param marketIndex
1512
1718
  * @returns
1513
1719
  */
1514
- public async closePosition(marketIndex: BN): Promise<TransactionSignature> {
1720
+ public async closePosition(
1721
+ marketIndex: BN,
1722
+ limitPrice?: BN
1723
+ ): Promise<TransactionSignature> {
1515
1724
  const userPosition = this.getUser().getUserPosition(marketIndex);
1516
1725
  if (!userPosition) {
1517
1726
  throw Error(`No position in market ${marketIndex.toString()}`);
@@ -1521,8 +1730,9 @@ export class ClearingHouse {
1521
1730
  orderType: OrderType.MARKET,
1522
1731
  marketIndex,
1523
1732
  direction: findDirectionToClose(userPosition),
1524
- baseAssetAmount: userPosition.baseAssetAmount,
1733
+ baseAssetAmount: userPosition.baseAssetAmount.abs(),
1525
1734
  reduceOnly: true,
1735
+ price: limitPrice,
1526
1736
  });
1527
1737
  }
1528
1738
 
@@ -1577,6 +1787,7 @@ export class ClearingHouse {
1577
1787
  const marketAccountMap = new Map<number, AccountMeta>();
1578
1788
  const oracleAccountMap = new Map<string, AccountMeta>();
1579
1789
  const bankAccountMap = new Map<number, AccountMeta>();
1790
+
1580
1791
  for (const position of settleeUserAccount.positions) {
1581
1792
  if (!positionIsAvailable(position)) {
1582
1793
  const market = this.getMarketAccount(position.marketIndex);
@@ -1672,7 +1883,13 @@ export class ClearingHouse {
1672
1883
  marketIndex: BN,
1673
1884
  maxBaseAssetAmount: BN
1674
1885
  ): Promise<TransactionInstruction> {
1886
+ const userStatsPublicKey = getUserStatsAccountPublicKey(
1887
+ this.program.programId,
1888
+ userAccount.authority
1889
+ );
1890
+
1675
1891
  const liquidatorPublicKey = await this.getUserAccountPublicKey();
1892
+ const liquidatorStatsPublicKey = this.getUserStatsAccountPublicKey();
1676
1893
 
1677
1894
  const remainingAccounts = this.getRemainingAccountsForLiquidation({
1678
1895
  writableMarketIndex: marketIndex,
@@ -1687,7 +1904,9 @@ export class ClearingHouse {
1687
1904
  state: await this.getStatePublicKey(),
1688
1905
  authority: this.wallet.publicKey,
1689
1906
  user: userAccountPublicKey,
1907
+ userStats: userStatsPublicKey,
1690
1908
  liquidator: liquidatorPublicKey,
1909
+ liquidatorStats: liquidatorStatsPublicKey,
1691
1910
  },
1692
1911
  remainingAccounts: remainingAccounts,
1693
1912
  }
@@ -1855,6 +2074,90 @@ export class ClearingHouse {
1855
2074
  );
1856
2075
  }
1857
2076
 
2077
+ public async resolvePerpBankruptcy(
2078
+ userAccountPublicKey: PublicKey,
2079
+ userAccount: UserAccount,
2080
+ marketIndex: BN
2081
+ ): Promise<TransactionSignature> {
2082
+ const { txSig } = await this.txSender.send(
2083
+ wrapInTx(
2084
+ await this.getResolvePerpBankruptcyIx(
2085
+ userAccountPublicKey,
2086
+ userAccount,
2087
+ marketIndex
2088
+ )
2089
+ ),
2090
+ [],
2091
+ this.opts
2092
+ );
2093
+ return txSig;
2094
+ }
2095
+
2096
+ public async getResolvePerpBankruptcyIx(
2097
+ userAccountPublicKey: PublicKey,
2098
+ userAccount: UserAccount,
2099
+ marketIndex: BN
2100
+ ): Promise<TransactionInstruction> {
2101
+ const liquidatorPublicKey = await this.getUserAccountPublicKey();
2102
+
2103
+ const remainingAccounts = this.getRemainingAccountsForLiquidation({
2104
+ writableMarketIndex: marketIndex,
2105
+ userAccount,
2106
+ });
2107
+
2108
+ return await this.program.instruction.resolvePerpBankruptcy(marketIndex, {
2109
+ accounts: {
2110
+ state: await this.getStatePublicKey(),
2111
+ authority: this.wallet.publicKey,
2112
+ user: userAccountPublicKey,
2113
+ liquidator: liquidatorPublicKey,
2114
+ },
2115
+ remainingAccounts: remainingAccounts,
2116
+ });
2117
+ }
2118
+
2119
+ public async resolveBorrowBankruptcy(
2120
+ userAccountPublicKey: PublicKey,
2121
+ userAccount: UserAccount,
2122
+ bankIndex: BN
2123
+ ): Promise<TransactionSignature> {
2124
+ const { txSig } = await this.txSender.send(
2125
+ wrapInTx(
2126
+ await this.getResolveBorrowBankruptcyIx(
2127
+ userAccountPublicKey,
2128
+ userAccount,
2129
+ bankIndex
2130
+ )
2131
+ ),
2132
+ [],
2133
+ this.opts
2134
+ );
2135
+ return txSig;
2136
+ }
2137
+
2138
+ public async getResolveBorrowBankruptcyIx(
2139
+ userAccountPublicKey: PublicKey,
2140
+ userAccount: UserAccount,
2141
+ bankIndex: BN
2142
+ ): Promise<TransactionInstruction> {
2143
+ const liquidatorPublicKey = await this.getUserAccountPublicKey();
2144
+
2145
+ const remainingAccounts = this.getRemainingAccountsForLiquidation({
2146
+ writableBankIndexes: [bankIndex],
2147
+ userAccount,
2148
+ });
2149
+
2150
+ return await this.program.instruction.resolveBorrowBankruptcy(bankIndex, {
2151
+ accounts: {
2152
+ state: await this.getStatePublicKey(),
2153
+ authority: this.wallet.publicKey,
2154
+ user: userAccountPublicKey,
2155
+ liquidator: liquidatorPublicKey,
2156
+ },
2157
+ remainingAccounts: remainingAccounts,
2158
+ });
2159
+ }
2160
+
1858
2161
  getRemainingAccountsForLiquidation(params: {
1859
2162
  userAccount: UserAccount;
1860
2163
  writableMarketIndex?: BN;
@@ -18,6 +18,7 @@ export type ClearingHouseConfig = {
18
18
  bankIndexes?: BN[];
19
19
  oracleInfos?: OracleInfo[];
20
20
  env?: DriftEnv;
21
+ userStats?: boolean;
21
22
  };
22
23
 
23
24
  type ClearingHouseSubscriptionConfig =