@drift-labs/sdk 0.2.0-master.25 → 0.2.0-master.27

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 (124) hide show
  1. package/lib/accounts/pollingClearingHouseAccountSubscriber.d.ts +14 -13
  2. package/lib/accounts/pollingClearingHouseAccountSubscriber.js +30 -27
  3. package/lib/accounts/types.d.ts +9 -9
  4. package/lib/accounts/webSocketClearingHouseAccountSubscriber.d.ts +15 -14
  5. package/lib/accounts/webSocketClearingHouseAccountSubscriber.js +38 -34
  6. package/lib/addresses/pda.d.ts +7 -6
  7. package/lib/addresses/pda.js +31 -27
  8. package/lib/admin.d.ts +13 -7
  9. package/lib/admin.js +111 -44
  10. package/lib/clearingHouse.d.ts +71 -42
  11. package/lib/clearingHouse.js +767 -278
  12. package/lib/clearingHouseConfig.d.ts +2 -2
  13. package/lib/clearingHouseUser.d.ts +24 -22
  14. package/lib/clearingHouseUser.js +273 -177
  15. package/lib/config.d.ts +7 -7
  16. package/lib/config.js +21 -21
  17. package/lib/constants/numericConstants.d.ts +12 -12
  18. package/lib/constants/numericConstants.js +13 -13
  19. package/lib/constants/{markets.d.ts → perpMarkets.d.ts} +5 -5
  20. package/lib/constants/{markets.js → perpMarkets.js} +4 -4
  21. package/lib/constants/{banks.d.ts → spotMarkets.d.ts} +6 -6
  22. package/lib/constants/{banks.js → spotMarkets.js} +16 -16
  23. package/lib/dlob/DLOB.d.ts +73 -0
  24. package/lib/dlob/DLOB.js +557 -0
  25. package/lib/dlob/DLOBNode.d.ts +52 -0
  26. package/lib/dlob/DLOBNode.js +82 -0
  27. package/lib/dlob/NodeList.d.ts +26 -0
  28. package/lib/dlob/NodeList.js +138 -0
  29. package/lib/events/types.d.ts +2 -1
  30. package/lib/events/types.js +1 -0
  31. package/lib/examples/makeTradeExample.js +7 -7
  32. package/lib/idl/clearing_house.json +1152 -503
  33. package/lib/index.d.ts +10 -3
  34. package/lib/index.js +10 -3
  35. package/lib/math/amm.d.ts +2 -2
  36. package/lib/math/amm.js +1 -1
  37. package/lib/math/funding.d.ts +6 -6
  38. package/lib/math/funding.js +2 -1
  39. package/lib/math/margin.d.ts +4 -4
  40. package/lib/math/margin.js +18 -11
  41. package/lib/math/market.d.ts +11 -10
  42. package/lib/math/market.js +30 -7
  43. package/lib/math/oracles.d.ts +2 -1
  44. package/lib/math/oracles.js +11 -1
  45. package/lib/math/orders.d.ts +6 -6
  46. package/lib/math/orders.js +31 -16
  47. package/lib/math/position.d.ts +13 -13
  48. package/lib/math/position.js +19 -19
  49. package/lib/math/spotBalance.d.ts +22 -0
  50. package/lib/math/spotBalance.js +193 -0
  51. package/lib/math/spotMarket.d.ts +4 -0
  52. package/lib/math/spotMarket.js +8 -0
  53. package/lib/math/spotPosition.d.ts +6 -0
  54. package/lib/math/spotPosition.js +23 -0
  55. package/lib/math/state.js +2 -2
  56. package/lib/math/trade.d.ts +4 -4
  57. package/lib/orderParams.d.ts +4 -4
  58. package/lib/orderParams.js +12 -4
  59. package/lib/serum/serumSubscriber.d.ts +23 -0
  60. package/lib/serum/serumSubscriber.js +41 -0
  61. package/lib/serum/types.d.ts +11 -0
  62. package/lib/serum/types.js +2 -0
  63. package/lib/tx/retryTxSender.d.ts +1 -1
  64. package/lib/tx/retryTxSender.js +4 -2
  65. package/lib/tx/types.d.ts +1 -1
  66. package/lib/types.d.ts +148 -57
  67. package/lib/types.js +39 -11
  68. package/lib/userMap/userMap.d.ts +25 -0
  69. package/lib/userMap/userMap.js +73 -0
  70. package/lib/userMap/userStatsMap.d.ts +19 -0
  71. package/lib/userMap/userStatsMap.js +68 -0
  72. package/package.json +6 -3
  73. package/src/accounts/pollingClearingHouseAccountSubscriber.ts +42 -38
  74. package/src/accounts/types.ts +12 -9
  75. package/src/accounts/webSocketClearingHouseAccountSubscriber.ts +65 -52
  76. package/src/addresses/pda.ts +49 -44
  77. package/src/admin.ts +190 -55
  78. package/src/clearingHouse.ts +1092 -365
  79. package/src/clearingHouseConfig.ts +2 -2
  80. package/src/clearingHouseUser.ts +518 -255
  81. package/src/config.ts +30 -30
  82. package/src/constants/numericConstants.ts +17 -15
  83. package/src/constants/{markets.ts → perpMarkets.ts} +5 -5
  84. package/src/constants/{banks.ts → spotMarkets.ts} +19 -19
  85. package/src/dlob/DLOB.ts +884 -0
  86. package/src/dlob/DLOBNode.ts +163 -0
  87. package/src/dlob/NodeList.ts +185 -0
  88. package/src/events/types.ts +3 -0
  89. package/src/examples/makeTradeExample.js +152 -75
  90. package/src/examples/makeTradeExample.ts +10 -8
  91. package/src/idl/clearing_house.json +1152 -503
  92. package/src/index.ts +10 -3
  93. package/src/math/amm.ts +6 -3
  94. package/src/math/funding.ts +7 -7
  95. package/src/math/margin.ts +34 -23
  96. package/src/math/market.ts +72 -20
  97. package/src/math/oracles.ts +18 -1
  98. package/src/math/orders.ts +33 -25
  99. package/src/math/position.ts +31 -31
  100. package/src/math/spotBalance.ts +316 -0
  101. package/src/math/spotMarket.ts +9 -0
  102. package/src/math/spotPosition.ts +47 -0
  103. package/src/math/state.ts +2 -2
  104. package/src/math/trade.ts +4 -4
  105. package/src/orderParams.ts +16 -8
  106. package/src/serum/serumSubscriber.ts +80 -0
  107. package/src/serum/types.ts +13 -0
  108. package/src/tx/retryTxSender.ts +5 -2
  109. package/src/tx/types.ts +2 -1
  110. package/src/types.ts +135 -56
  111. package/src/userMap/userMap.ts +100 -0
  112. package/src/userMap/userStatsMap.ts +110 -0
  113. package/tests/bn/test.ts +2 -3
  114. package/tests/dlob/helpers.ts +322 -0
  115. package/tests/dlob/test.ts +2865 -0
  116. package/lib/math/bankBalance.d.ts +0 -15
  117. package/lib/math/bankBalance.js +0 -150
  118. package/src/constants/numericConstants.js +0 -41
  119. package/src/math/bankBalance.ts +0 -258
  120. package/src/math/oracles.js +0 -26
  121. package/src/math/state.js +0 -15
  122. package/src/orderParams.js +0 -20
  123. package/src/slot/SlotSubscriber.js +0 -39
  124. package/src/tokenFaucet.js +0 -189
@@ -5,17 +5,19 @@ import {
5
5
  IWallet,
6
6
  PositionDirection,
7
7
  UserAccount,
8
- MarketAccount,
8
+ PerpMarketAccount,
9
9
  OrderParams,
10
10
  Order,
11
- BankAccount,
12
- UserBankBalance,
11
+ SpotMarketAccount,
12
+ SpotPosition,
13
13
  MakerInfo,
14
14
  TakerInfo,
15
15
  OptionalOrderParams,
16
16
  DefaultOrderParams,
17
17
  OrderType,
18
18
  ReferrerInfo,
19
+ MarketType,
20
+ SerumV3FulfillmentConfigAccount,
19
21
  } from './types';
20
22
  import * as anchor from '@project-serum/anchor';
21
23
  import clearingHouseIDL from './idl/clearing_house.json';
@@ -43,6 +45,8 @@ import {
43
45
  getClearingHouseStateAccountPublicKey,
44
46
  getInsuranceFundStakeAccountPublicKey,
45
47
  getMarketPublicKey,
48
+ getSerumFulfillmentConfigPublicKey,
49
+ getSerumSignerPublicKey,
46
50
  getUserAccountPublicKey,
47
51
  getUserAccountPublicKeySync,
48
52
  getUserStatsAccountPublicKey,
@@ -56,11 +60,11 @@ import { TxSender } from './tx/types';
56
60
  import { wrapInTx } from './tx/utils';
57
61
  import {
58
62
  ONE,
59
- QUOTE_ASSET_BANK_INDEX,
63
+ QUOTE_SPOT_MARKET_INDEX,
60
64
  ZERO,
61
65
  } from './constants/numericConstants';
62
66
  import { findDirectionToClose, positionIsAvailable } from './math/position';
63
- import { getTokenAmount } from './math/bankBalance';
67
+ import { getTokenAmount } from './math/spotBalance';
64
68
  import { DEFAULT_USER_NAME, encodeName } from './userName';
65
69
  import { OraclePriceData } from './oracles/types';
66
70
  import { ClearingHouseConfig } from './clearingHouseConfig';
@@ -69,9 +73,10 @@ import { WebSocketClearingHouseAccountSubscriber } from './accounts/webSocketCle
69
73
  import { RetryTxSender } from './tx/retryTxSender';
70
74
  import { ClearingHouseUser } from './clearingHouseUser';
71
75
  import { ClearingHouseUserAccountSubscriptionConfig } from './clearingHouseUserConfig';
72
- import { getMarketsBanksAndOraclesForSubscription } from './config';
73
- import { WRAPPED_SOL_MINT } from './constants/banks';
76
+ import { getMarketsAndOraclesForSubscription } from './config';
77
+ import { WRAPPED_SOL_MINT } from './constants/spotMarkets';
74
78
  import { ClearingHouseUserStats } from './clearingHouseUserStats';
79
+ import { isSpotPositionAvailable } from './math/spotPosition';
75
80
 
76
81
  /**
77
82
  * # ClearingHouse
@@ -139,17 +144,21 @@ export class ClearingHouse {
139
144
  });
140
145
  }
141
146
 
142
- let marketIndexes = config.marketIndexes;
143
- let bankIndexes = config.bankIndexes;
147
+ let perpMarketIndexes = config.perpMarketIndexes;
148
+ let spotMarketIndexes = config.spotMarketIndexes;
144
149
  let oracleInfos = config.oracleInfos;
145
150
  if (config.env) {
146
151
  const {
147
- marketIndexes: envMarketIndexes,
148
- bankIndexes: envBankIndexes,
152
+ perpMarketIndexes: envPerpMarketIndexes,
153
+ spotMarketIndexes: envSpotMarketIndexes,
149
154
  oracleInfos: envOralceInfos,
150
- } = getMarketsBanksAndOraclesForSubscription(config.env);
151
- marketIndexes = marketIndexes ? marketIndexes : envMarketIndexes;
152
- bankIndexes = bankIndexes ? bankIndexes : envBankIndexes;
155
+ } = getMarketsAndOraclesForSubscription(config.env);
156
+ perpMarketIndexes = perpMarketIndexes
157
+ ? perpMarketIndexes
158
+ : envPerpMarketIndexes;
159
+ spotMarketIndexes = spotMarketIndexes
160
+ ? spotMarketIndexes
161
+ : envSpotMarketIndexes;
153
162
  oracleInfos = oracleInfos ? oracleInfos : envOralceInfos;
154
163
  }
155
164
 
@@ -157,15 +166,15 @@ export class ClearingHouse {
157
166
  this.accountSubscriber = new PollingClearingHouseAccountSubscriber(
158
167
  this.program,
159
168
  config.accountSubscription.accountLoader,
160
- marketIndexes ?? [],
161
- bankIndexes ?? [],
169
+ perpMarketIndexes ?? [],
170
+ spotMarketIndexes ?? [],
162
171
  oracleInfos ?? []
163
172
  );
164
173
  } else {
165
174
  this.accountSubscriber = new WebSocketClearingHouseAccountSubscriber(
166
175
  this.program,
167
- config.marketIndexes ?? [],
168
- config.bankIndexes ?? [],
176
+ config.perpMarketIndexes ?? [],
177
+ config.spotMarketIndexes ?? [],
169
178
  config.oracleInfos ?? []
170
179
  );
171
180
  }
@@ -276,25 +285,36 @@ export class ClearingHouse {
276
285
  return this.accountSubscriber.getStateAccountAndSlot().data;
277
286
  }
278
287
 
279
- public getMarketAccount(marketIndex: BN | number): MarketAccount | undefined {
288
+ public getPerpMarketAccount(
289
+ marketIndex: BN | number
290
+ ): PerpMarketAccount | undefined {
280
291
  marketIndex = marketIndex instanceof BN ? marketIndex : new BN(marketIndex);
281
292
  return this.accountSubscriber.getMarketAccountAndSlot(marketIndex)?.data;
282
293
  }
283
294
 
284
- public getMarketAccounts(): MarketAccount[] {
295
+ public getPerpMarketAccounts(): PerpMarketAccount[] {
285
296
  return this.accountSubscriber
286
297
  .getMarketAccountsAndSlots()
287
298
  .map((value) => value.data);
288
299
  }
289
300
 
290
- public getBankAccount(bankIndex: BN | number): BankAccount | undefined {
291
- bankIndex = bankIndex instanceof BN ? bankIndex : new BN(bankIndex);
292
- return this.accountSubscriber.getBankAccountAndSlot(bankIndex).data;
301
+ public getSpotMarketAccount(
302
+ marketIndex: BN | number
303
+ ): SpotMarketAccount | undefined {
304
+ marketIndex = marketIndex instanceof BN ? marketIndex : new BN(marketIndex);
305
+ return this.accountSubscriber.getSpotMarketAccountAndSlot(marketIndex).data;
306
+ }
307
+
308
+ public getSpotMarketAccounts(): SpotMarketAccount[] {
309
+ return this.accountSubscriber
310
+ .getSpotMarketAccountsAndSlots()
311
+ .map((value) => value.data);
293
312
  }
294
313
 
295
- public getQuoteAssetBankAccount(): BankAccount {
296
- return this.accountSubscriber.getBankAccountAndSlot(QUOTE_ASSET_BANK_INDEX)
297
- .data;
314
+ public getQuoteSpotMarketAccount(): SpotMarketAccount {
315
+ return this.accountSubscriber.getSpotMarketAccountAndSlot(
316
+ QUOTE_SPOT_MARKET_INDEX
317
+ ).data;
298
318
  }
299
319
 
300
320
  public getOraclePriceDataAndSlot(
@@ -303,6 +323,18 @@ export class ClearingHouse {
303
323
  return this.accountSubscriber.getOraclePriceDataAndSlot(oraclePublicKey);
304
324
  }
305
325
 
326
+ public async getSerumV3FulfillmentConfig(
327
+ serumMarket: PublicKey
328
+ ): Promise<SerumV3FulfillmentConfigAccount> {
329
+ const address = await getSerumFulfillmentConfigPublicKey(
330
+ this.program.programId,
331
+ serumMarket
332
+ );
333
+ return (await this.program.account.serumV3FulfillmentConfig.fetch(
334
+ address
335
+ )) as SerumV3FulfillmentConfigAccount;
336
+ }
337
+
306
338
  /**
307
339
  * Update the wallet to use for clearing house transactions and linked user account
308
340
  * @param newWallet
@@ -433,6 +465,35 @@ export class ClearingHouse {
433
465
  });
434
466
  }
435
467
 
468
+ public async updateUserName(
469
+ name: string,
470
+ userId = 0
471
+ ): Promise<TransactionSignature> {
472
+ const nameBuffer = encodeName(name);
473
+ return await this.program.rpc.updateUserName(userId, nameBuffer, {
474
+ accounts: {
475
+ user: await this.getUserAccountPublicKey(),
476
+ authority: this.wallet.publicKey,
477
+ },
478
+ });
479
+ }
480
+
481
+ public async updateUserCustomMarginRatio(
482
+ marginRatio: number,
483
+ userId = 0
484
+ ): Promise<TransactionSignature> {
485
+ return await this.program.rpc.updateUserCustomMarginRatio(
486
+ userId,
487
+ marginRatio,
488
+ {
489
+ accounts: {
490
+ user: await this.getUserAccountPublicKey(),
491
+ authority: this.wallet.publicKey,
492
+ },
493
+ }
494
+ );
495
+ }
496
+
436
497
  public getUser(userId?: number): ClearingHouseUser {
437
498
  userId = userId ?? this.activeUserId;
438
499
  if (!this.users.has(userId)) {
@@ -476,29 +537,29 @@ export class ClearingHouse {
476
537
  return this.getUser(userId).getUserAccountAndSlot();
477
538
  }
478
539
 
479
- public getUserBankBalance(
480
- bankIndex: number | BN
481
- ): UserBankBalance | undefined {
482
- const bankIndexBN = bankIndex instanceof BN ? bankIndex : new BN(bankIndex);
483
- return this.getUserAccount().bankBalances.find((bankBalance) =>
484
- bankBalance.bankIndex.eq(bankIndexBN)
540
+ public getSpotPosition(marketIndex: number | BN): SpotPosition | undefined {
541
+ const marketIndexBN =
542
+ marketIndex instanceof BN ? marketIndex : new BN(marketIndex);
543
+ return this.getUserAccount().spotPositions.find((spotPosition) =>
544
+ spotPosition.marketIndex.eq(marketIndexBN)
485
545
  );
486
546
  }
487
547
 
488
548
  public getQuoteAssetTokenAmount(): BN {
489
- const bank = this.getBankAccount(QUOTE_ASSET_BANK_INDEX);
490
- const userBankBalance = this.getUserBankBalance(QUOTE_ASSET_BANK_INDEX);
549
+ const spotMarket = this.getSpotMarketAccount(QUOTE_SPOT_MARKET_INDEX);
550
+ const spotPosition = this.getSpotPosition(QUOTE_SPOT_MARKET_INDEX);
491
551
  return getTokenAmount(
492
- userBankBalance.balance,
493
- bank,
494
- userBankBalance.balanceType
552
+ spotPosition.balance,
553
+ spotMarket,
554
+ spotPosition.balanceType
495
555
  );
496
556
  }
497
557
 
498
558
  getRemainingAccounts(params: {
499
- writableMarketIndex?: BN;
500
- writableBankIndex?: BN;
501
- readableMarketIndex?: BN;
559
+ writablePerpMarketIndex?: BN;
560
+ writableSpotMarketIndex?: BN;
561
+ readablePerpMarketIndex?: BN;
562
+ readableSpotMarketIndex?: BN;
502
563
  }): AccountMeta[] {
503
564
  const userAccountAndSlot = this.getUserAccountAndSlot();
504
565
  if (!userAccountAndSlot) {
@@ -510,14 +571,14 @@ export class ClearingHouse {
510
571
  userAccountAndSlot;
511
572
 
512
573
  const oracleAccountMap = new Map<string, AccountMeta>();
513
- const bankAccountMap = new Map<number, AccountMeta>();
514
- const marketAccountMap = new Map<number, AccountMeta>();
574
+ const spotMarketAccountMap = new Map<number, AccountMeta>();
575
+ const perpMarketAccountMap = new Map<number, AccountMeta>();
515
576
  for (const [marketIndexNum, slot] of this.marketLastSlotCache.entries()) {
516
577
  // if cache has more recent slot than user positions account slot, add market to remaining accounts
517
578
  // otherwise remove from slot
518
579
  if (slot > lastUserPositionsSlot) {
519
- const marketAccount = this.getMarketAccount(marketIndexNum);
520
- marketAccountMap.set(marketIndexNum, {
580
+ const marketAccount = this.getPerpMarketAccount(marketIndexNum);
581
+ perpMarketAccountMap.set(marketIndexNum, {
521
582
  pubkey: marketAccount.pubkey,
522
583
  isSigner: false,
523
584
  isWritable: false,
@@ -532,11 +593,11 @@ export class ClearingHouse {
532
593
  }
533
594
  }
534
595
 
535
- for (const position of userAccount.positions) {
596
+ for (const position of userAccount.perpPositions) {
536
597
  if (!positionIsAvailable(position)) {
537
598
  const marketIndexNum = position.marketIndex.toNumber();
538
- const marketAccount = this.getMarketAccount(marketIndexNum);
539
- marketAccountMap.set(marketIndexNum, {
599
+ const marketAccount = this.getPerpMarketAccount(marketIndexNum);
600
+ perpMarketAccountMap.set(marketIndexNum, {
540
601
  pubkey: marketAccount.pubkey,
541
602
  isSigner: false,
542
603
  isWritable: false,
@@ -549,14 +610,14 @@ export class ClearingHouse {
549
610
  }
550
611
  }
551
612
 
552
- if (params.readableMarketIndex) {
553
- const marketAccount = this.getMarketAccount(
554
- params.readableMarketIndex.toNumber()
613
+ if (params.readablePerpMarketIndex) {
614
+ const marketAccount = this.getPerpMarketAccount(
615
+ params.readablePerpMarketIndex.toNumber()
555
616
  );
556
- marketAccountMap.set(params.readableMarketIndex.toNumber(), {
617
+ perpMarketAccountMap.set(params.readablePerpMarketIndex.toNumber(), {
557
618
  pubkey: marketAccount.pubkey,
558
619
  isSigner: false,
559
- isWritable: true,
620
+ isWritable: false,
560
621
  });
561
622
  oracleAccountMap.set(marketAccount.amm.oracle.toString(), {
562
623
  pubkey: marketAccount.amm.oracle,
@@ -565,11 +626,11 @@ export class ClearingHouse {
565
626
  });
566
627
  }
567
628
 
568
- if (params.writableMarketIndex) {
569
- const marketAccount = this.getMarketAccount(
570
- params.writableMarketIndex.toNumber()
629
+ if (params.writablePerpMarketIndex) {
630
+ const marketAccount = this.getPerpMarketAccount(
631
+ params.writablePerpMarketIndex.toNumber()
571
632
  );
572
- marketAccountMap.set(params.writableMarketIndex.toNumber(), {
633
+ perpMarketAccountMap.set(params.writablePerpMarketIndex.toNumber(), {
573
634
  pubkey: marketAccount.pubkey,
574
635
  isSigner: false,
575
636
  isWritable: true,
@@ -581,17 +642,19 @@ export class ClearingHouse {
581
642
  });
582
643
  }
583
644
 
584
- for (const userBankBalance of userAccount.bankBalances) {
585
- if (!userBankBalance.balance.eq(ZERO)) {
586
- const bankAccount = this.getBankAccount(userBankBalance.bankIndex);
587
- bankAccountMap.set(userBankBalance.bankIndex.toNumber(), {
588
- pubkey: bankAccount.pubkey,
645
+ for (const spotPosition of userAccount.spotPositions) {
646
+ if (!isSpotPositionAvailable(spotPosition)) {
647
+ const spotMarketAccount = this.getSpotMarketAccount(
648
+ spotPosition.marketIndex
649
+ );
650
+ spotMarketAccountMap.set(spotPosition.marketIndex.toNumber(), {
651
+ pubkey: spotMarketAccount.pubkey,
589
652
  isSigner: false,
590
653
  isWritable: false,
591
654
  });
592
- if (!bankAccount.bankIndex.eq(ZERO)) {
593
- oracleAccountMap.set(bankAccount.oracle.toString(), {
594
- pubkey: bankAccount.oracle,
655
+ if (!spotMarketAccount.marketIndex.eq(ZERO)) {
656
+ oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
657
+ pubkey: spotMarketAccount.oracle,
595
658
  isSigner: false,
596
659
  isWritable: false,
597
660
  });
@@ -599,16 +662,36 @@ export class ClearingHouse {
599
662
  }
600
663
  }
601
664
 
602
- if (params.writableBankIndex) {
603
- const bankAccount = this.getBankAccount(params.writableBankIndex);
604
- bankAccountMap.set(params.writableBankIndex.toNumber(), {
605
- pubkey: bankAccount.pubkey,
665
+ if (params.readableSpotMarketIndex) {
666
+ const spotMarketAccount = this.getSpotMarketAccount(
667
+ params.readableSpotMarketIndex
668
+ );
669
+ spotMarketAccountMap.set(params.readableSpotMarketIndex.toNumber(), {
670
+ pubkey: spotMarketAccount.pubkey,
671
+ isSigner: false,
672
+ isWritable: false,
673
+ });
674
+ if (!spotMarketAccount.marketIndex.eq(ZERO)) {
675
+ oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
676
+ pubkey: spotMarketAccount.oracle,
677
+ isSigner: false,
678
+ isWritable: false,
679
+ });
680
+ }
681
+ }
682
+
683
+ if (params.writableSpotMarketIndex) {
684
+ const spotMarketAccount = this.getSpotMarketAccount(
685
+ params.writableSpotMarketIndex
686
+ );
687
+ spotMarketAccountMap.set(params.writableSpotMarketIndex.toNumber(), {
688
+ pubkey: spotMarketAccount.pubkey,
606
689
  isSigner: false,
607
690
  isWritable: true,
608
691
  });
609
- if (!bankAccount.bankIndex.eq(ZERO)) {
610
- oracleAccountMap.set(bankAccount.oracle.toString(), {
611
- pubkey: bankAccount.oracle,
692
+ if (!spotMarketAccount.marketIndex.eq(ZERO)) {
693
+ oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
694
+ pubkey: spotMarketAccount.oracle,
612
695
  isSigner: false,
613
696
  isWritable: false,
614
697
  });
@@ -617,8 +700,8 @@ export class ClearingHouse {
617
700
 
618
701
  return [
619
702
  ...oracleAccountMap.values(),
620
- ...bankAccountMap.values(),
621
- ...marketAccountMap.values(),
703
+ ...spotMarketAccountMap.values(),
704
+ ...perpMarketAccountMap.values(),
622
705
  ];
623
706
  }
624
707
 
@@ -637,7 +720,7 @@ export class ClearingHouse {
637
720
 
638
721
  public async deposit(
639
722
  amount: BN,
640
- bankIndex: BN,
723
+ marketIndex: BN,
641
724
  collateralAccountPublicKey: PublicKey,
642
725
  userId?: number,
643
726
  reduceOnly = false
@@ -645,14 +728,14 @@ export class ClearingHouse {
645
728
  const tx = new Transaction();
646
729
  const additionalSigners: Array<Signer> = [];
647
730
 
648
- const bank = this.getBankAccount(bankIndex);
731
+ const spotMarketAccount = this.getSpotMarketAccount(marketIndex);
649
732
 
650
- const isSolBank = bank.mint.equals(WRAPPED_SOL_MINT);
733
+ const isSolMarket = spotMarketAccount.mint.equals(WRAPPED_SOL_MINT);
651
734
 
652
735
  const authority = this.wallet.publicKey;
653
736
 
654
737
  const createWSOLTokenAccount =
655
- isSolBank && collateralAccountPublicKey.equals(authority);
738
+ isSolMarket && collateralAccountPublicKey.equals(authority);
656
739
 
657
740
  if (createWSOLTokenAccount) {
658
741
  const { ixs, signers, pubkey } =
@@ -669,7 +752,7 @@ export class ClearingHouse {
669
752
 
670
753
  const depositCollateralIx = await this.getDepositInstruction(
671
754
  amount,
672
- bankIndex,
755
+ marketIndex,
673
756
  collateralAccountPublicKey,
674
757
  userId,
675
758
  reduceOnly,
@@ -701,7 +784,7 @@ export class ClearingHouse {
701
784
 
702
785
  async getDepositInstruction(
703
786
  amount: BN,
704
- bankIndex: BN,
787
+ marketIndex: BN,
705
788
  userTokenAccount: PublicKey,
706
789
  userId?: number,
707
790
  reduceOnly = false,
@@ -718,35 +801,35 @@ export class ClearingHouse {
718
801
  let remainingAccounts = [];
719
802
  if (userInitialized) {
720
803
  remainingAccounts = this.getRemainingAccounts({
721
- writableBankIndex: bankIndex,
804
+ writableSpotMarketIndex: marketIndex,
722
805
  });
723
806
  } else {
724
- const bankAccount = this.getBankAccount(bankIndex);
725
- if (!bankAccount.oracle.equals(PublicKey.default)) {
807
+ const spotMarketAccount = this.getSpotMarketAccount(marketIndex);
808
+ if (!spotMarketAccount.oracle.equals(PublicKey.default)) {
726
809
  remainingAccounts.push({
727
- pubkey: bankAccount.oracle,
810
+ pubkey: spotMarketAccount.oracle,
728
811
  isSigner: false,
729
812
  isWritable: false,
730
813
  });
731
814
  }
732
815
  remainingAccounts.push({
733
- pubkey: bankAccount.pubkey,
816
+ pubkey: spotMarketAccount.pubkey,
734
817
  isSigner: false,
735
818
  isWritable: true,
736
819
  });
737
820
  }
738
821
 
739
- const bank = this.getBankAccount(bankIndex);
822
+ const spotMarketAccount = this.getSpotMarketAccount(marketIndex);
740
823
 
741
824
  return await this.program.instruction.deposit(
742
- bankIndex,
825
+ marketIndex,
743
826
  amount,
744
827
  reduceOnly,
745
828
  {
746
829
  accounts: {
747
830
  state: await this.getStatePublicKey(),
748
- bank: bank.pubkey,
749
- bankVault: bank.vault,
831
+ spotMarket: spotMarketAccount.pubkey,
832
+ spotMarketVault: spotMarketAccount.vault,
750
833
  user: userAccountPublicKey,
751
834
  userStats: this.getUserStatsAccountPublicKey(),
752
835
  userTokenAccount: userTokenAccount,
@@ -769,7 +852,7 @@ export class ClearingHouse {
769
852
  }
770
853
 
771
854
  private async getSolWithdrawalIxs(
772
- bankIndex: BN,
855
+ marketIndex: BN,
773
856
  amount: BN
774
857
  ): Promise<{
775
858
  ixs: anchor.web3.TransactionInstruction[];
@@ -801,7 +884,7 @@ export class ClearingHouse {
801
884
 
802
885
  const withdrawIx = await this.getWithdrawIx(
803
886
  amount,
804
- bankIndex,
887
+ marketIndex,
805
888
  pubkey,
806
889
  true
807
890
  );
@@ -868,7 +951,7 @@ export class ClearingHouse {
868
951
  * Creates the Clearing House User account for a user, and deposits some initial collateral
869
952
  * @param amount
870
953
  * @param userTokenAccount
871
- * @param bankIndex
954
+ * @param marketIndex
872
955
  * @param userId
873
956
  * @param name
874
957
  * @param fromUserId
@@ -877,7 +960,7 @@ export class ClearingHouse {
877
960
  public async initializeUserAccountAndDepositCollateral(
878
961
  amount: BN,
879
962
  userTokenAccount: PublicKey,
880
- bankIndex = new BN(0),
963
+ marketIndex = new BN(0),
881
964
  userId = 0,
882
965
  name = DEFAULT_USER_NAME,
883
966
  fromUserId?: number,
@@ -888,16 +971,16 @@ export class ClearingHouse {
888
971
 
889
972
  const additionalSigners: Array<Signer> = [];
890
973
 
891
- const bank = this.getBankAccount(bankIndex);
974
+ const spotMarket = this.getSpotMarketAccount(marketIndex);
892
975
 
893
- const isSolBank = bank.mint.equals(WRAPPED_SOL_MINT);
976
+ const isSolMarket = spotMarket.mint.equals(WRAPPED_SOL_MINT);
894
977
 
895
978
  const tx = new Transaction();
896
979
 
897
980
  const authority = this.wallet.publicKey;
898
981
 
899
982
  const createWSOLTokenAccount =
900
- isSolBank && userTokenAccount.equals(authority);
983
+ isSolMarket && userTokenAccount.equals(authority);
901
984
 
902
985
  if (createWSOLTokenAccount) {
903
986
  const {
@@ -917,10 +1000,15 @@ export class ClearingHouse {
917
1000
 
918
1001
  const depositCollateralIx =
919
1002
  fromUserId != null
920
- ? await this.getTransferDepositIx(amount, bankIndex, fromUserId, userId)
1003
+ ? await this.getTransferDepositIx(
1004
+ amount,
1005
+ marketIndex,
1006
+ fromUserId,
1007
+ userId
1008
+ )
921
1009
  : await this.getDepositInstruction(
922
1010
  amount,
923
- bankIndex,
1011
+ marketIndex,
924
1012
  userTokenAccount,
925
1013
  userId,
926
1014
  false,
@@ -957,7 +1045,7 @@ export class ClearingHouse {
957
1045
  public async initializeUserAccountForDevnet(
958
1046
  userId = 0,
959
1047
  name = DEFAULT_USER_NAME,
960
- bankIndex: BN,
1048
+ marketIndex: BN,
961
1049
  tokenFaucet: TokenFaucet,
962
1050
  amount: BN,
963
1051
  referrerInfo?: ReferrerInfo
@@ -973,7 +1061,7 @@ export class ClearingHouse {
973
1061
 
974
1062
  const depositCollateralIx = await this.getDepositInstruction(
975
1063
  amount,
976
- bankIndex,
1064
+ marketIndex,
977
1065
  associateTokenPublicKey,
978
1066
  userId,
979
1067
  false,
@@ -994,21 +1082,21 @@ export class ClearingHouse {
994
1082
 
995
1083
  public async withdraw(
996
1084
  amount: BN,
997
- bankIndex: BN,
1085
+ marketIndex: BN,
998
1086
  userTokenAccount: PublicKey,
999
1087
  reduceOnly = false
1000
1088
  ): Promise<TransactionSignature> {
1001
1089
  const tx = new Transaction();
1002
1090
  const additionalSigners: Array<Signer> = [];
1003
1091
 
1004
- const bank = this.getBankAccount(bankIndex);
1092
+ const spotMarketAccount = this.getSpotMarketAccount(marketIndex);
1005
1093
 
1006
- const isSolBank = bank.mint.equals(WRAPPED_SOL_MINT);
1094
+ const isSolMarket = spotMarketAccount.mint.equals(WRAPPED_SOL_MINT);
1007
1095
 
1008
1096
  const authority = this.wallet.publicKey;
1009
1097
 
1010
1098
  const createWSOLTokenAccount =
1011
- isSolBank && userTokenAccount.equals(authority);
1099
+ isSolMarket && userTokenAccount.equals(authority);
1012
1100
 
1013
1101
  if (createWSOLTokenAccount) {
1014
1102
  const { ixs, signers, pubkey } =
@@ -1025,7 +1113,7 @@ export class ClearingHouse {
1025
1113
 
1026
1114
  const withdrawCollateral = await this.getWithdrawIx(
1027
1115
  amount,
1028
- bank.bankIndex,
1116
+ spotMarketAccount.marketIndex,
1029
1117
  userTokenAccount,
1030
1118
  reduceOnly
1031
1119
  );
@@ -1055,27 +1143,27 @@ export class ClearingHouse {
1055
1143
 
1056
1144
  public async getWithdrawIx(
1057
1145
  amount: BN,
1058
- bankIndex: BN,
1146
+ marketIndex: BN,
1059
1147
  userTokenAccount: PublicKey,
1060
1148
  reduceOnly = false
1061
1149
  ): Promise<TransactionInstruction> {
1062
1150
  const userAccountPublicKey = await this.getUserAccountPublicKey();
1063
1151
 
1064
1152
  const remainingAccounts = this.getRemainingAccounts({
1065
- writableBankIndex: bankIndex,
1153
+ writableSpotMarketIndex: marketIndex,
1066
1154
  });
1067
1155
 
1068
- const bank = this.getBankAccount(bankIndex);
1156
+ const spotMarketAccount = this.getSpotMarketAccount(marketIndex);
1069
1157
 
1070
1158
  return await this.program.instruction.withdraw(
1071
- bankIndex,
1159
+ marketIndex,
1072
1160
  amount,
1073
1161
  reduceOnly,
1074
1162
  {
1075
1163
  accounts: {
1076
1164
  state: await this.getStatePublicKey(),
1077
- bank: bank.pubkey,
1078
- bankVault: bank.vault,
1165
+ spotMarket: spotMarketAccount.pubkey,
1166
+ spotMarketVault: spotMarketAccount.vault,
1079
1167
  clearingHouseSigner: this.getSignerPublicKey(),
1080
1168
  user: userAccountPublicKey,
1081
1169
  userStats: this.getUserStatsAccountPublicKey(),
@@ -1090,13 +1178,18 @@ export class ClearingHouse {
1090
1178
 
1091
1179
  public async transferDeposit(
1092
1180
  amount: BN,
1093
- bankIndex: BN,
1181
+ marketIndex: BN,
1094
1182
  fromUserId: number,
1095
1183
  toUserId: number
1096
1184
  ): Promise<TransactionSignature> {
1097
1185
  const { txSig } = await this.txSender.send(
1098
1186
  wrapInTx(
1099
- await this.getTransferDepositIx(amount, bankIndex, fromUserId, toUserId)
1187
+ await this.getTransferDepositIx(
1188
+ amount,
1189
+ marketIndex,
1190
+ fromUserId,
1191
+ toUserId
1192
+ )
1100
1193
  ),
1101
1194
  [],
1102
1195
  this.opts
@@ -1106,7 +1199,7 @@ export class ClearingHouse {
1106
1199
 
1107
1200
  public async getTransferDepositIx(
1108
1201
  amount: BN,
1109
- bankIndex: BN,
1202
+ marketIndex: BN,
1110
1203
  fromUserId: number,
1111
1204
  toUserId: number
1112
1205
  ): Promise<TransactionInstruction> {
@@ -1122,10 +1215,10 @@ export class ClearingHouse {
1122
1215
  );
1123
1216
 
1124
1217
  const remainingAccounts = this.getRemainingAccounts({
1125
- writableBankIndex: bankIndex,
1218
+ writableSpotMarketIndex: marketIndex,
1126
1219
  });
1127
1220
 
1128
- return await this.program.instruction.transferDeposit(bankIndex, amount, {
1221
+ return await this.program.instruction.transferDeposit(marketIndex, amount, {
1129
1222
  accounts: {
1130
1223
  authority: this.wallet.publicKey,
1131
1224
  fromUser,
@@ -1137,24 +1230,24 @@ export class ClearingHouse {
1137
1230
  });
1138
1231
  }
1139
1232
 
1140
- public async updateBankCumulativeInterest(
1141
- bankIndex: BN
1233
+ public async updateSpotMarketCumulativeInterest(
1234
+ marketIndex: BN
1142
1235
  ): Promise<TransactionSignature> {
1143
1236
  const { txSig } = await this.txSender.send(
1144
- wrapInTx(await this.updateBankCumulativeInterestIx(bankIndex)),
1237
+ wrapInTx(await this.updateSpotMarketCumulativeInterestIx(marketIndex)),
1145
1238
  [],
1146
1239
  this.opts
1147
1240
  );
1148
1241
  return txSig;
1149
1242
  }
1150
1243
 
1151
- public async updateBankCumulativeInterestIx(
1152
- bankIndex: BN
1244
+ public async updateSpotMarketCumulativeInterestIx(
1245
+ marketIndex: BN
1153
1246
  ): Promise<TransactionInstruction> {
1154
- const bank = this.getBankAccount(bankIndex);
1155
- return await this.program.instruction.updateBankCumulativeInterest({
1247
+ const spotMarket = this.getSpotMarketAccount(marketIndex);
1248
+ return await this.program.instruction.updateSpotMarketCumulativeInterest({
1156
1249
  accounts: {
1157
- bank: bank.pubkey,
1250
+ spotMarket: spotMarket.pubkey,
1158
1251
  },
1159
1252
  });
1160
1253
  }
@@ -1178,7 +1271,7 @@ export class ClearingHouse {
1178
1271
  const settleeUserAccount = (await this.program.account.user.fetch(
1179
1272
  settleeUserAccountPublicKey
1180
1273
  )) as UserAccount;
1181
- const userPositions = settleeUserAccount.positions;
1274
+ const userPositions = settleeUserAccount.perpPositions;
1182
1275
  const remainingAccounts = [];
1183
1276
 
1184
1277
  let foundMarket = false;
@@ -1234,15 +1327,15 @@ export class ClearingHouse {
1234
1327
  const userAccountPublicKey = await this.getUserAccountPublicKey();
1235
1328
 
1236
1329
  const remainingAccounts = this.getRemainingAccounts({
1237
- writableMarketIndex: marketIndex,
1330
+ writablePerpMarketIndex: marketIndex,
1238
1331
  });
1239
1332
 
1240
1333
  if (sharesToBurn == undefined) {
1241
1334
  const userAccount = this.getUserAccount();
1242
- const marketPosition = userAccount.positions.filter((position) =>
1335
+ const perpPosition = userAccount.perpPositions.filter((position) =>
1243
1336
  position.marketIndex.eq(marketIndex)
1244
1337
  )[0];
1245
- sharesToBurn = marketPosition.lpShares;
1338
+ sharesToBurn = perpPosition.lpShares;
1246
1339
  console.log('burning lp shares:', sharesToBurn.toString());
1247
1340
  }
1248
1341
 
@@ -1275,7 +1368,7 @@ export class ClearingHouse {
1275
1368
  ): Promise<TransactionInstruction> {
1276
1369
  const userAccountPublicKey = await this.getUserAccountPublicKey();
1277
1370
  const remainingAccounts = this.getRemainingAccounts({
1278
- writableMarketIndex: marketIndex,
1371
+ writablePerpMarketIndex: marketIndex,
1279
1372
  });
1280
1373
 
1281
1374
  return this.program.instruction.addLiquidity(amount, marketIndex, {
@@ -1303,6 +1396,60 @@ export class ClearingHouse {
1303
1396
  });
1304
1397
  }
1305
1398
 
1399
+ public async sendSignedTx(tx: Transaction): Promise<TransactionSignature> {
1400
+ const { txSig } = await this.txSender.send(tx, undefined, this.opts, true);
1401
+
1402
+ return txSig;
1403
+ }
1404
+
1405
+ /**
1406
+ * Sends a market order and returns a signed tx which can fill the order against the vamm, which the caller can use to fill their own order if required.
1407
+ * @param orderParams
1408
+ * @param userAccountPublicKey
1409
+ * @param userAccount
1410
+ * @returns
1411
+ */
1412
+ public async sendMarketOrderAndGetSignedFillTx(
1413
+ orderParams: OptionalOrderParams,
1414
+ userAccountPublicKey: PublicKey,
1415
+ userAccount: UserAccount
1416
+ ): Promise<{ txSig: TransactionSignature; signedFillTx: Transaction }> {
1417
+ const marketIndex = orderParams.marketIndex;
1418
+ const orderId = userAccount.nextOrderId;
1419
+
1420
+ const marketOrderTx = wrapInTx(await this.getPlaceOrderIx(orderParams));
1421
+ const fillTx = wrapInTx(
1422
+ await this.getFillOrderIx(userAccountPublicKey, userAccount, {
1423
+ orderId,
1424
+ marketIndex,
1425
+ })
1426
+ );
1427
+
1428
+ // Apply the latest blockhash to the txs so that we can sign before sending them
1429
+ const currentBlockHash = (
1430
+ await this.connection.getLatestBlockhash('finalized')
1431
+ ).blockhash;
1432
+ marketOrderTx.recentBlockhash = currentBlockHash;
1433
+ fillTx.recentBlockhash = currentBlockHash;
1434
+
1435
+ marketOrderTx.feePayer = userAccount.authority;
1436
+ fillTx.feePayer = userAccount.authority;
1437
+
1438
+ const [signedMarketOrderTx, signedFillTx] =
1439
+ await this.provider.wallet.signAllTransactions([marketOrderTx, fillTx]);
1440
+
1441
+ const { txSig, slot } = await this.txSender.send(
1442
+ signedMarketOrderTx,
1443
+ [],
1444
+ this.opts,
1445
+ true
1446
+ );
1447
+
1448
+ this.marketLastSlotCache.set(orderParams.marketIndex.toNumber(), slot);
1449
+
1450
+ return { txSig, signedFillTx };
1451
+ }
1452
+
1306
1453
  public async placeOrder(
1307
1454
  orderParams: OptionalOrderParams
1308
1455
  ): Promise<TransactionSignature> {
@@ -1315,18 +1462,23 @@ export class ClearingHouse {
1315
1462
  return txSig;
1316
1463
  }
1317
1464
 
1318
- getOrderParams(optionalOrderParams: OptionalOrderParams): OrderParams {
1319
- return Object.assign({}, DefaultOrderParams, optionalOrderParams);
1465
+ getOrderParams(
1466
+ optionalOrderParams: OptionalOrderParams,
1467
+ marketType: MarketType
1468
+ ): OrderParams {
1469
+ return Object.assign({}, DefaultOrderParams, optionalOrderParams, {
1470
+ marketType,
1471
+ });
1320
1472
  }
1321
1473
 
1322
1474
  public async getPlaceOrderIx(
1323
1475
  orderParams: OptionalOrderParams
1324
1476
  ): Promise<TransactionInstruction> {
1325
- orderParams = this.getOrderParams(orderParams);
1477
+ orderParams = this.getOrderParams(orderParams, MarketType.PERP);
1326
1478
  const userAccountPublicKey = await this.getUserAccountPublicKey();
1327
1479
 
1328
1480
  const remainingAccounts = this.getRemainingAccounts({
1329
- readableMarketIndex: orderParams.marketIndex,
1481
+ readablePerpMarketIndex: orderParams.marketIndex,
1330
1482
  });
1331
1483
 
1332
1484
  return await this.program.instruction.placeOrder(orderParams, {
@@ -1359,7 +1511,7 @@ export class ClearingHouse {
1359
1511
  const oracleAccountInfos = [];
1360
1512
  for (const marketIndex of marketIndexes) {
1361
1513
  if (!marketIndex.eq(new BN(100))) {
1362
- const market = this.getMarketAccount(marketIndex);
1514
+ const market = this.getPerpMarketAccount(marketIndex);
1363
1515
  marketAccountInfos.push({
1364
1516
  pubkey: market.pubkey,
1365
1517
  isWritable: true,
@@ -1383,6 +1535,54 @@ export class ClearingHouse {
1383
1535
  });
1384
1536
  }
1385
1537
 
1538
+ public async settleExpiredMarket(
1539
+ marketIndex: BN
1540
+ ): Promise<TransactionSignature> {
1541
+ const { txSig } = await this.txSender.send(
1542
+ wrapInTx(await this.getSettleExpiredMarketIx(marketIndex)),
1543
+ [],
1544
+ this.opts
1545
+ );
1546
+ return txSig;
1547
+ }
1548
+
1549
+ public async getSettleExpiredMarketIx(
1550
+ marketIndex: BN
1551
+ ): Promise<TransactionInstruction> {
1552
+ const marketAccountInfos = [];
1553
+ const oracleAccountInfos = [];
1554
+ const spotMarketAccountInfos = [];
1555
+ const market = this.getPerpMarketAccount(marketIndex);
1556
+ marketAccountInfos.push({
1557
+ pubkey: market.pubkey,
1558
+ isWritable: true,
1559
+ isSigner: false,
1560
+ });
1561
+ oracleAccountInfos.push({
1562
+ pubkey: market.amm.oracle,
1563
+ isWritable: false,
1564
+ isSigner: false,
1565
+ });
1566
+
1567
+ spotMarketAccountInfos.push({
1568
+ pubkey: this.getSpotMarketAccount(QUOTE_SPOT_MARKET_INDEX).pubkey,
1569
+ isSigner: false,
1570
+ isWritable: true,
1571
+ });
1572
+
1573
+ const remainingAccounts = oracleAccountInfos
1574
+ .concat(spotMarketAccountInfos)
1575
+ .concat(marketAccountInfos);
1576
+
1577
+ return await this.program.instruction.settleExpiredMarket(marketIndex, {
1578
+ accounts: {
1579
+ state: await this.getStatePublicKey(),
1580
+ authority: this.wallet.publicKey,
1581
+ },
1582
+ remainingAccounts,
1583
+ });
1584
+ }
1585
+
1386
1586
  public async cancelOrder(orderId?: BN): Promise<TransactionSignature> {
1387
1587
  const { txSig } = await this.txSender.send(
1388
1588
  wrapInTx(await this.getCancelOrderIx(orderId)),
@@ -1424,7 +1624,7 @@ export class ClearingHouse {
1424
1624
  const userAccountPublicKey = await this.getUserAccountPublicKey();
1425
1625
 
1426
1626
  const order = this.getOrderByUserId(userOrderId);
1427
- const oracle = this.getMarketAccount(order.marketIndex).amm.oracle;
1627
+ const oracle = this.getPerpMarketAccount(order.marketIndex).amm.oracle;
1428
1628
 
1429
1629
  const remainingAccounts = this.getRemainingAccounts({});
1430
1630
 
@@ -1465,7 +1665,7 @@ export class ClearingHouse {
1465
1665
  public async getFillOrderIx(
1466
1666
  userAccountPublicKey: PublicKey,
1467
1667
  userAccount: UserAccount,
1468
- order: Order,
1668
+ order: Pick<Order, 'marketIndex' | 'orderId'>,
1469
1669
  makerInfo?: MakerInfo,
1470
1670
  referrerInfo?: ReferrerInfo
1471
1671
  ): Promise<TransactionInstruction> {
@@ -1482,24 +1682,26 @@ export class ClearingHouse {
1482
1682
  : userAccount.orders.find((order) =>
1483
1683
  order.orderId.eq(userAccount.nextOrderId.sub(ONE))
1484
1684
  ).marketIndex;
1485
- const marketAccount = this.getMarketAccount(marketIndex);
1685
+ const marketAccount = this.getPerpMarketAccount(marketIndex);
1486
1686
 
1487
1687
  const oracleAccountMap = new Map<string, AccountMeta>();
1488
- const bankAccountMap = new Map<number, AccountMeta>();
1489
- const marketAccountMap = new Map<number, AccountMeta>();
1688
+ const spotMarketAccountMap = new Map<number, AccountMeta>();
1689
+ const perpMarketAccountMap = new Map<number, AccountMeta>();
1490
1690
 
1491
- for (const bankBalance of userAccount.bankBalances) {
1492
- if (!bankBalance.balance.eq(ZERO)) {
1493
- const bankAccount = this.getBankAccount(bankBalance.bankIndex);
1494
- bankAccountMap.set(bankBalance.bankIndex.toNumber(), {
1495
- pubkey: bankAccount.pubkey,
1691
+ for (const spotPosition of userAccount.spotPositions) {
1692
+ if (!isSpotPositionAvailable(spotPosition)) {
1693
+ const spotMarketAccount = this.getSpotMarketAccount(
1694
+ spotPosition.marketIndex
1695
+ );
1696
+ spotMarketAccountMap.set(spotPosition.marketIndex.toNumber(), {
1697
+ pubkey: spotMarketAccount.pubkey,
1496
1698
  isSigner: false,
1497
1699
  isWritable: false,
1498
1700
  });
1499
1701
 
1500
- if (!bankAccount.oracle.equals(PublicKey.default)) {
1501
- oracleAccountMap.set(bankAccount.oracle.toString(), {
1502
- pubkey: bankAccount.oracle,
1702
+ if (!spotMarketAccount.oracle.equals(PublicKey.default)) {
1703
+ oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
1704
+ pubkey: spotMarketAccount.oracle,
1503
1705
  isSigner: false,
1504
1706
  isWritable: false,
1505
1707
  });
@@ -1507,13 +1709,13 @@ export class ClearingHouse {
1507
1709
  }
1508
1710
  }
1509
1711
 
1510
- for (const position of userAccount.positions) {
1712
+ for (const position of userAccount.perpPositions) {
1511
1713
  if (
1512
1714
  !positionIsAvailable(position) &&
1513
1715
  !position.marketIndex.eq(order.marketIndex)
1514
1716
  ) {
1515
- const market = this.getMarketAccount(position.marketIndex);
1516
- marketAccountMap.set(position.marketIndex.toNumber(), {
1717
+ const market = this.getPerpMarketAccount(position.marketIndex);
1718
+ perpMarketAccountMap.set(position.marketIndex.toNumber(), {
1517
1719
  pubkey: market.pubkey,
1518
1720
  isWritable: false,
1519
1721
  isSigner: false,
@@ -1526,7 +1728,7 @@ export class ClearingHouse {
1526
1728
  }
1527
1729
  }
1528
1730
 
1529
- marketAccountMap.set(marketIndex.toNumber(), {
1731
+ perpMarketAccountMap.set(marketIndex.toNumber(), {
1530
1732
  pubkey: marketAccount.pubkey,
1531
1733
  isWritable: true,
1532
1734
  isSigner: false,
@@ -1539,8 +1741,8 @@ export class ClearingHouse {
1539
1741
 
1540
1742
  const remainingAccounts = [
1541
1743
  ...oracleAccountMap.values(),
1542
- ...bankAccountMap.values(),
1543
- ...marketAccountMap.values(),
1744
+ ...spotMarketAccountMap.values(),
1745
+ ...perpMarketAccountMap.values(),
1544
1746
  ];
1545
1747
 
1546
1748
  if (makerInfo) {
@@ -1585,45 +1787,101 @@ export class ClearingHouse {
1585
1787
  });
1586
1788
  }
1587
1789
 
1588
- public async triggerOrder(
1790
+ public async placeSpotOrder(
1791
+ orderParams: OptionalOrderParams
1792
+ ): Promise<TransactionSignature> {
1793
+ const { txSig } = await this.txSender.send(
1794
+ wrapInTx(await this.getPlaceSpotOrderIx(orderParams)),
1795
+ [],
1796
+ this.opts
1797
+ );
1798
+ return txSig;
1799
+ }
1800
+
1801
+ public async getPlaceSpotOrderIx(
1802
+ orderParams: OptionalOrderParams
1803
+ ): Promise<TransactionInstruction> {
1804
+ orderParams = this.getOrderParams(orderParams, MarketType.SPOT);
1805
+ const userAccountPublicKey = await this.getUserAccountPublicKey();
1806
+
1807
+ const remainingAccounts = this.getRemainingAccounts({
1808
+ readableSpotMarketIndex: orderParams.marketIndex,
1809
+ });
1810
+
1811
+ return await this.program.instruction.placeSpotOrder(orderParams, {
1812
+ accounts: {
1813
+ state: await this.getStatePublicKey(),
1814
+ user: userAccountPublicKey,
1815
+ userStats: this.getUserStatsAccountPublicKey(),
1816
+ authority: this.wallet.publicKey,
1817
+ },
1818
+ remainingAccounts,
1819
+ });
1820
+ }
1821
+
1822
+ public async fillSpotOrder(
1589
1823
  userAccountPublicKey: PublicKey,
1590
1824
  user: UserAccount,
1591
- order: Order
1825
+ order?: Order,
1826
+ fulfillmentConfig?: SerumV3FulfillmentConfigAccount,
1827
+ makerInfo?: MakerInfo,
1828
+ referrerInfo?: ReferrerInfo
1592
1829
  ): Promise<TransactionSignature> {
1593
1830
  const { txSig } = await this.txSender.send(
1594
- wrapInTx(await this.getTriggerOrderIx(userAccountPublicKey, user, order)),
1831
+ wrapInTx(
1832
+ await this.getFillSpotOrderIx(
1833
+ userAccountPublicKey,
1834
+ user,
1835
+ order,
1836
+ fulfillmentConfig,
1837
+ makerInfo,
1838
+ referrerInfo
1839
+ )
1840
+ ),
1595
1841
  [],
1596
1842
  this.opts
1597
1843
  );
1598
1844
  return txSig;
1599
1845
  }
1600
1846
 
1601
- public async getTriggerOrderIx(
1847
+ public async getFillSpotOrderIx(
1602
1848
  userAccountPublicKey: PublicKey,
1603
1849
  userAccount: UserAccount,
1604
- order: Order
1850
+ order?: Order,
1851
+ fulfillmentConfig?: SerumV3FulfillmentConfigAccount,
1852
+ makerInfo?: MakerInfo,
1853
+ referrerInfo?: ReferrerInfo
1605
1854
  ): Promise<TransactionInstruction> {
1855
+ const userStatsPublicKey = getUserStatsAccountPublicKey(
1856
+ this.program.programId,
1857
+ userAccount.authority
1858
+ );
1859
+
1606
1860
  const fillerPublicKey = await this.getUserAccountPublicKey();
1861
+ const fillerStatsPublicKey = this.getUserStatsAccountPublicKey();
1607
1862
 
1608
- const marketIndex = order.marketIndex;
1609
- const marketAccount = this.getMarketAccount(marketIndex);
1863
+ const marketIndex = order
1864
+ ? order.marketIndex
1865
+ : userAccount.orders.find((order) =>
1866
+ order.orderId.eq(userAccount.nextOrderId.sub(ONE))
1867
+ ).marketIndex;
1610
1868
 
1611
1869
  const oracleAccountMap = new Map<string, AccountMeta>();
1612
- const bankAccountMap = new Map<number, AccountMeta>();
1613
- const marketAccountMap = new Map<number, AccountMeta>();
1614
-
1615
- for (const bankBalance of userAccount.bankBalances) {
1616
- if (!bankBalance.balance.eq(ZERO)) {
1617
- const bankAccount = this.getBankAccount(bankBalance.bankIndex);
1618
- bankAccountMap.set(bankBalance.bankIndex.toNumber(), {
1619
- pubkey: bankAccount.pubkey,
1870
+ const spotMarketAccountMap = new Map<number, AccountMeta>();
1871
+ const perpMarketAccountMap = new Map<number, AccountMeta>();
1872
+
1873
+ for (const spotPosition of userAccount.spotPositions) {
1874
+ if (!isSpotPositionAvailable(spotPosition)) {
1875
+ const spotMarket = this.getSpotMarketAccount(spotPosition.marketIndex);
1876
+ spotMarketAccountMap.set(spotPosition.marketIndex.toNumber(), {
1877
+ pubkey: spotMarket.pubkey,
1620
1878
  isSigner: false,
1621
1879
  isWritable: false,
1622
1880
  });
1623
1881
 
1624
- if (!bankAccount.oracle.equals(PublicKey.default)) {
1625
- oracleAccountMap.set(bankAccount.oracle.toString(), {
1626
- pubkey: bankAccount.oracle,
1882
+ if (!spotMarket.oracle.equals(PublicKey.default)) {
1883
+ oracleAccountMap.set(spotMarket.oracle.toString(), {
1884
+ pubkey: spotMarket.oracle,
1627
1885
  isSigner: false,
1628
1886
  isWritable: false,
1629
1887
  });
@@ -1631,13 +1889,13 @@ export class ClearingHouse {
1631
1889
  }
1632
1890
  }
1633
1891
 
1634
- for (const position of userAccount.positions) {
1892
+ for (const position of userAccount.perpPositions) {
1635
1893
  if (
1636
1894
  !positionIsAvailable(position) &&
1637
1895
  !position.marketIndex.eq(order.marketIndex)
1638
1896
  ) {
1639
- const market = this.getMarketAccount(position.marketIndex);
1640
- marketAccountMap.set(position.marketIndex.toNumber(), {
1897
+ const market = this.getPerpMarketAccount(position.marketIndex);
1898
+ perpMarketAccountMap.set(position.marketIndex.toNumber(), {
1641
1899
  pubkey: market.pubkey,
1642
1900
  isWritable: false,
1643
1901
  isSigner: false,
@@ -1650,77 +1908,42 @@ export class ClearingHouse {
1650
1908
  }
1651
1909
  }
1652
1910
 
1653
- marketAccountMap.set(marketIndex.toNumber(), {
1654
- pubkey: marketAccount.pubkey,
1911
+ const spotMarketAccount = this.getSpotMarketAccount(marketIndex);
1912
+ spotMarketAccountMap.set(marketIndex.toNumber(), {
1913
+ pubkey: spotMarketAccount.pubkey,
1655
1914
  isWritable: true,
1656
1915
  isSigner: false,
1657
1916
  });
1658
- oracleAccountMap.set(marketAccount.amm.oracle.toString(), {
1659
- pubkey: marketAccount.amm.oracle,
1660
- isWritable: false,
1917
+ if (!spotMarketAccount.oracle.equals(PublicKey.default)) {
1918
+ oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
1919
+ pubkey: spotMarketAccount.oracle,
1920
+ isWritable: false,
1921
+ isSigner: false,
1922
+ });
1923
+ }
1924
+ const quoteMarketAccount = this.getQuoteSpotMarketAccount();
1925
+ spotMarketAccountMap.set(quoteMarketAccount.marketIndex.toNumber(), {
1926
+ pubkey: quoteMarketAccount.pubkey,
1927
+ isWritable: true,
1661
1928
  isSigner: false,
1662
1929
  });
1663
1930
 
1664
1931
  const remainingAccounts = [
1665
1932
  ...oracleAccountMap.values(),
1666
- ...bankAccountMap.values(),
1667
- ...marketAccountMap.values(),
1933
+ ...spotMarketAccountMap.values(),
1934
+ ...perpMarketAccountMap.values(),
1668
1935
  ];
1669
1936
 
1670
- const orderId = order.orderId;
1671
- return await this.program.instruction.triggerOrder(orderId, {
1672
- accounts: {
1673
- state: await this.getStatePublicKey(),
1674
- filler: fillerPublicKey,
1675
- user: userAccountPublicKey,
1676
- authority: this.wallet.publicKey,
1677
- },
1678
- remainingAccounts,
1679
- });
1680
- }
1681
-
1682
- public async placeAndTake(
1683
- orderParams: OptionalOrderParams,
1684
- makerInfo?: MakerInfo,
1685
- referrerInfo?: ReferrerInfo
1686
- ): Promise<TransactionSignature> {
1687
- const { txSig, slot } = await this.txSender.send(
1688
- wrapInTx(
1689
- await this.getPlaceAndTakeIx(orderParams, makerInfo, referrerInfo)
1690
- ),
1691
- [],
1692
- this.opts
1693
- );
1694
- this.marketLastSlotCache.set(orderParams.marketIndex.toNumber(), slot);
1695
- return txSig;
1696
- }
1697
-
1698
- public async getPlaceAndTakeIx(
1699
- orderParams: OptionalOrderParams,
1700
- makerInfo?: MakerInfo,
1701
- referrerInfo?: ReferrerInfo
1702
- ): Promise<TransactionInstruction> {
1703
- orderParams = this.getOrderParams(orderParams);
1704
- const userStatsPublicKey = await this.getUserStatsAccountPublicKey();
1705
- const userAccountPublicKey = await this.getUserAccountPublicKey();
1706
-
1707
- const remainingAccounts = this.getRemainingAccounts({
1708
- writableMarketIndex: orderParams.marketIndex,
1709
- writableBankIndex: QUOTE_ASSET_BANK_INDEX,
1710
- });
1711
-
1712
- let makerOrderId = null;
1713
1937
  if (makerInfo) {
1714
- makerOrderId = makerInfo.order.orderId;
1715
1938
  remainingAccounts.push({
1716
1939
  pubkey: makerInfo.maker,
1717
- isSigner: false,
1718
1940
  isWritable: true,
1941
+ isSigner: false,
1719
1942
  });
1720
1943
  remainingAccounts.push({
1721
1944
  pubkey: makerInfo.makerStats,
1722
- isSigner: false,
1723
1945
  isWritable: true,
1946
+ isSigner: false,
1724
1947
  });
1725
1948
  }
1726
1949
 
@@ -1737,9 +1960,370 @@ export class ClearingHouse {
1737
1960
  });
1738
1961
  }
1739
1962
 
1740
- return await this.program.instruction.placeAndTake(
1741
- orderParams,
1742
- makerOrderId,
1963
+ const orderId = order.orderId;
1964
+ const makerOrderId = makerInfo ? makerInfo.order.orderId : null;
1965
+
1966
+ if (fulfillmentConfig) {
1967
+ remainingAccounts.push({
1968
+ pubkey: fulfillmentConfig.pubkey,
1969
+ isWritable: false,
1970
+ isSigner: false,
1971
+ });
1972
+ remainingAccounts.push({
1973
+ pubkey: fulfillmentConfig.serumProgramId,
1974
+ isWritable: false,
1975
+ isSigner: false,
1976
+ });
1977
+ remainingAccounts.push({
1978
+ pubkey: fulfillmentConfig.serumMarket,
1979
+ isWritable: true,
1980
+ isSigner: false,
1981
+ });
1982
+ remainingAccounts.push({
1983
+ pubkey: fulfillmentConfig.serumRequestQueue,
1984
+ isWritable: true,
1985
+ isSigner: false,
1986
+ });
1987
+ remainingAccounts.push({
1988
+ pubkey: fulfillmentConfig.serumEventQueue,
1989
+ isWritable: true,
1990
+ isSigner: false,
1991
+ });
1992
+ remainingAccounts.push({
1993
+ pubkey: fulfillmentConfig.serumBids,
1994
+ isWritable: true,
1995
+ isSigner: false,
1996
+ });
1997
+ remainingAccounts.push({
1998
+ pubkey: fulfillmentConfig.serumAsks,
1999
+ isWritable: true,
2000
+ isSigner: false,
2001
+ });
2002
+ remainingAccounts.push({
2003
+ pubkey: fulfillmentConfig.serumBaseVault,
2004
+ isWritable: true,
2005
+ isSigner: false,
2006
+ });
2007
+ remainingAccounts.push({
2008
+ pubkey: fulfillmentConfig.serumQuoteVault,
2009
+ isWritable: true,
2010
+ isSigner: false,
2011
+ });
2012
+ remainingAccounts.push({
2013
+ pubkey: fulfillmentConfig.serumOpenOrders,
2014
+ isWritable: true,
2015
+ isSigner: false,
2016
+ });
2017
+ remainingAccounts.push({
2018
+ pubkey: getSerumSignerPublicKey(
2019
+ fulfillmentConfig.serumProgramId,
2020
+ fulfillmentConfig.serumMarket,
2021
+ fulfillmentConfig.serumSignerNonce
2022
+ ),
2023
+ isWritable: false,
2024
+ isSigner: false,
2025
+ });
2026
+ remainingAccounts.push({
2027
+ pubkey: this.getSignerPublicKey(),
2028
+ isWritable: false,
2029
+ isSigner: false,
2030
+ });
2031
+ remainingAccounts.push({
2032
+ pubkey: TOKEN_PROGRAM_ID,
2033
+ isWritable: false,
2034
+ isSigner: false,
2035
+ });
2036
+ remainingAccounts.push({
2037
+ pubkey: spotMarketAccount.vault,
2038
+ isWritable: true,
2039
+ isSigner: false,
2040
+ });
2041
+ remainingAccounts.push({
2042
+ pubkey: quoteMarketAccount.vault,
2043
+ isWritable: true,
2044
+ isSigner: false,
2045
+ });
2046
+ }
2047
+
2048
+ return await this.program.instruction.fillSpotOrder(
2049
+ orderId,
2050
+ fulfillmentConfig ? fulfillmentConfig.fulfillmentType : null,
2051
+ makerOrderId,
2052
+ {
2053
+ accounts: {
2054
+ state: await this.getStatePublicKey(),
2055
+ filler: fillerPublicKey,
2056
+ fillerStats: fillerStatsPublicKey,
2057
+ user: userAccountPublicKey,
2058
+ userStats: userStatsPublicKey,
2059
+ authority: this.wallet.publicKey,
2060
+ },
2061
+ remainingAccounts,
2062
+ }
2063
+ );
2064
+ }
2065
+
2066
+ public async triggerOrder(
2067
+ userAccountPublicKey: PublicKey,
2068
+ user: UserAccount,
2069
+ order: Order
2070
+ ): Promise<TransactionSignature> {
2071
+ const { txSig } = await this.txSender.send(
2072
+ wrapInTx(await this.getTriggerOrderIx(userAccountPublicKey, user, order)),
2073
+ [],
2074
+ this.opts
2075
+ );
2076
+ return txSig;
2077
+ }
2078
+
2079
+ public async getTriggerOrderIx(
2080
+ userAccountPublicKey: PublicKey,
2081
+ userAccount: UserAccount,
2082
+ order: Order
2083
+ ): Promise<TransactionInstruction> {
2084
+ const fillerPublicKey = await this.getUserAccountPublicKey();
2085
+
2086
+ const marketIndex = order.marketIndex;
2087
+ const marketAccount = this.getPerpMarketAccount(marketIndex);
2088
+
2089
+ const oracleAccountMap = new Map<string, AccountMeta>();
2090
+ const spotMarketAccountMap = new Map<number, AccountMeta>();
2091
+ const perpMarketAccountMap = new Map<number, AccountMeta>();
2092
+
2093
+ for (const spotPosition of userAccount.spotPositions) {
2094
+ if (!isSpotPositionAvailable(spotPosition)) {
2095
+ const spotMarketAccount = this.getSpotMarketAccount(
2096
+ spotPosition.marketIndex
2097
+ );
2098
+ spotMarketAccountMap.set(spotPosition.marketIndex.toNumber(), {
2099
+ pubkey: spotMarketAccount.pubkey,
2100
+ isSigner: false,
2101
+ isWritable: false,
2102
+ });
2103
+
2104
+ if (!spotMarketAccount.oracle.equals(PublicKey.default)) {
2105
+ oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
2106
+ pubkey: spotMarketAccount.oracle,
2107
+ isSigner: false,
2108
+ isWritable: false,
2109
+ });
2110
+ }
2111
+ }
2112
+ }
2113
+
2114
+ for (const position of userAccount.perpPositions) {
2115
+ if (
2116
+ !positionIsAvailable(position) &&
2117
+ !position.marketIndex.eq(order.marketIndex)
2118
+ ) {
2119
+ const market = this.getPerpMarketAccount(position.marketIndex);
2120
+ perpMarketAccountMap.set(position.marketIndex.toNumber(), {
2121
+ pubkey: market.pubkey,
2122
+ isWritable: false,
2123
+ isSigner: false,
2124
+ });
2125
+ oracleAccountMap.set(market.amm.oracle.toString(), {
2126
+ pubkey: market.amm.oracle,
2127
+ isWritable: false,
2128
+ isSigner: false,
2129
+ });
2130
+ }
2131
+ }
2132
+
2133
+ perpMarketAccountMap.set(marketIndex.toNumber(), {
2134
+ pubkey: marketAccount.pubkey,
2135
+ isWritable: true,
2136
+ isSigner: false,
2137
+ });
2138
+ oracleAccountMap.set(marketAccount.amm.oracle.toString(), {
2139
+ pubkey: marketAccount.amm.oracle,
2140
+ isWritable: false,
2141
+ isSigner: false,
2142
+ });
2143
+
2144
+ const remainingAccounts = [
2145
+ ...oracleAccountMap.values(),
2146
+ ...spotMarketAccountMap.values(),
2147
+ ...perpMarketAccountMap.values(),
2148
+ ];
2149
+
2150
+ const orderId = order.orderId;
2151
+ return await this.program.instruction.triggerOrder(orderId, {
2152
+ accounts: {
2153
+ state: await this.getStatePublicKey(),
2154
+ filler: fillerPublicKey,
2155
+ user: userAccountPublicKey,
2156
+ authority: this.wallet.publicKey,
2157
+ },
2158
+ remainingAccounts,
2159
+ });
2160
+ }
2161
+
2162
+ public async triggerSpotOrder(
2163
+ userAccountPublicKey: PublicKey,
2164
+ user: UserAccount,
2165
+ order: Order
2166
+ ): Promise<TransactionSignature> {
2167
+ const { txSig } = await this.txSender.send(
2168
+ wrapInTx(
2169
+ await this.getTriggerSpotOrderIx(userAccountPublicKey, user, order)
2170
+ ),
2171
+ [],
2172
+ this.opts
2173
+ );
2174
+ return txSig;
2175
+ }
2176
+
2177
+ public async getTriggerSpotOrderIx(
2178
+ userAccountPublicKey: PublicKey,
2179
+ userAccount: UserAccount,
2180
+ order: Order
2181
+ ): Promise<TransactionInstruction> {
2182
+ const fillerPublicKey = await this.getUserAccountPublicKey();
2183
+
2184
+ const marketIndex = order.marketIndex;
2185
+ const spotMarketAccount = this.getSpotMarketAccount(marketIndex);
2186
+
2187
+ const oracleAccountMap = new Map<string, AccountMeta>();
2188
+ const spotMarketAccountMap = new Map<number, AccountMeta>();
2189
+ const perpMarketAccountMap = new Map<number, AccountMeta>();
2190
+
2191
+ for (const spotPosition of userAccount.spotPositions) {
2192
+ if (!isSpotPositionAvailable(spotPosition)) {
2193
+ const spotMarketAccount = this.getSpotMarketAccount(
2194
+ spotPosition.marketIndex
2195
+ );
2196
+ spotMarketAccountMap.set(spotPosition.marketIndex.toNumber(), {
2197
+ pubkey: spotMarketAccount.pubkey,
2198
+ isSigner: false,
2199
+ isWritable: false,
2200
+ });
2201
+
2202
+ if (!spotMarketAccount.oracle.equals(PublicKey.default)) {
2203
+ oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
2204
+ pubkey: spotMarketAccount.oracle,
2205
+ isSigner: false,
2206
+ isWritable: false,
2207
+ });
2208
+ }
2209
+ }
2210
+ }
2211
+
2212
+ for (const position of userAccount.perpPositions) {
2213
+ if (
2214
+ !positionIsAvailable(position) &&
2215
+ !position.marketIndex.eq(order.marketIndex)
2216
+ ) {
2217
+ const market = this.getPerpMarketAccount(position.marketIndex);
2218
+ perpMarketAccountMap.set(position.marketIndex.toNumber(), {
2219
+ pubkey: market.pubkey,
2220
+ isWritable: false,
2221
+ isSigner: false,
2222
+ });
2223
+ oracleAccountMap.set(market.amm.oracle.toString(), {
2224
+ pubkey: market.amm.oracle,
2225
+ isWritable: false,
2226
+ isSigner: false,
2227
+ });
2228
+ }
2229
+ }
2230
+
2231
+ const quoteSpotMarket = this.getQuoteSpotMarketAccount();
2232
+ spotMarketAccountMap.set(quoteSpotMarket.marketIndex.toNumber(), {
2233
+ pubkey: quoteSpotMarket.pubkey,
2234
+ isWritable: true,
2235
+ isSigner: false,
2236
+ });
2237
+ spotMarketAccountMap.set(marketIndex.toNumber(), {
2238
+ pubkey: spotMarketAccount.pubkey,
2239
+ isWritable: false,
2240
+ isSigner: false,
2241
+ });
2242
+ oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
2243
+ pubkey: spotMarketAccount.oracle,
2244
+ isWritable: false,
2245
+ isSigner: false,
2246
+ });
2247
+
2248
+ const remainingAccounts = [
2249
+ ...oracleAccountMap.values(),
2250
+ ...spotMarketAccountMap.values(),
2251
+ ...perpMarketAccountMap.values(),
2252
+ ];
2253
+
2254
+ const orderId = order.orderId;
2255
+ return await this.program.instruction.triggerSpotOrder(orderId, {
2256
+ accounts: {
2257
+ state: await this.getStatePublicKey(),
2258
+ filler: fillerPublicKey,
2259
+ user: userAccountPublicKey,
2260
+ authority: this.wallet.publicKey,
2261
+ },
2262
+ remainingAccounts,
2263
+ });
2264
+ }
2265
+
2266
+ public async placeAndTake(
2267
+ orderParams: OptionalOrderParams,
2268
+ makerInfo?: MakerInfo,
2269
+ referrerInfo?: ReferrerInfo
2270
+ ): Promise<TransactionSignature> {
2271
+ const { txSig, slot } = await this.txSender.send(
2272
+ wrapInTx(
2273
+ await this.getPlaceAndTakeIx(orderParams, makerInfo, referrerInfo)
2274
+ ),
2275
+ [],
2276
+ this.opts
2277
+ );
2278
+ this.marketLastSlotCache.set(orderParams.marketIndex.toNumber(), slot);
2279
+ return txSig;
2280
+ }
2281
+
2282
+ public async getPlaceAndTakeIx(
2283
+ orderParams: OptionalOrderParams,
2284
+ makerInfo?: MakerInfo,
2285
+ referrerInfo?: ReferrerInfo
2286
+ ): Promise<TransactionInstruction> {
2287
+ orderParams = this.getOrderParams(orderParams, MarketType.PERP);
2288
+ const userStatsPublicKey = await this.getUserStatsAccountPublicKey();
2289
+ const userAccountPublicKey = await this.getUserAccountPublicKey();
2290
+
2291
+ const remainingAccounts = this.getRemainingAccounts({
2292
+ writablePerpMarketIndex: orderParams.marketIndex,
2293
+ writableSpotMarketIndex: QUOTE_SPOT_MARKET_INDEX,
2294
+ });
2295
+
2296
+ let makerOrderId = null;
2297
+ if (makerInfo) {
2298
+ makerOrderId = makerInfo.order.orderId;
2299
+ remainingAccounts.push({
2300
+ pubkey: makerInfo.maker,
2301
+ isSigner: false,
2302
+ isWritable: true,
2303
+ });
2304
+ remainingAccounts.push({
2305
+ pubkey: makerInfo.makerStats,
2306
+ isSigner: false,
2307
+ isWritable: true,
2308
+ });
2309
+ }
2310
+
2311
+ if (referrerInfo) {
2312
+ remainingAccounts.push({
2313
+ pubkey: referrerInfo.referrer,
2314
+ isWritable: true,
2315
+ isSigner: false,
2316
+ });
2317
+ remainingAccounts.push({
2318
+ pubkey: referrerInfo.referrerStats,
2319
+ isWritable: true,
2320
+ isSigner: false,
2321
+ });
2322
+ }
2323
+
2324
+ return await this.program.instruction.placeAndTake(
2325
+ orderParams,
2326
+ makerOrderId,
1743
2327
  {
1744
2328
  accounts: {
1745
2329
  state: await this.getStatePublicKey(),
@@ -1775,14 +2359,14 @@ export class ClearingHouse {
1775
2359
  takerInfo: TakerInfo,
1776
2360
  referrerInfo?: ReferrerInfo
1777
2361
  ): Promise<TransactionInstruction> {
1778
- orderParams = this.getOrderParams(orderParams);
2362
+ orderParams = this.getOrderParams(orderParams, MarketType.PERP);
1779
2363
  const userStatsPublicKey = this.getUserStatsAccountPublicKey();
1780
2364
  const userAccountPublicKey = await this.getUserAccountPublicKey();
1781
2365
 
1782
2366
  // todo merge this with getRemainingAccounts
1783
2367
  const remainingAccounts = this.getRemainingAccountsWithCounterparty({
1784
2368
  counterPartyUserAccount: takerInfo.takerUserAccount,
1785
- writableMarketIndex: orderParams.marketIndex,
2369
+ writablePerpMarketIndex: orderParams.marketIndex,
1786
2370
  });
1787
2371
 
1788
2372
  if (referrerInfo) {
@@ -1895,13 +2479,110 @@ export class ClearingHouse {
1895
2479
  settleeUserAccount: UserAccount,
1896
2480
  marketIndex: BN
1897
2481
  ): Promise<TransactionInstruction> {
1898
- const marketAccountMap = new Map<number, AccountMeta>();
2482
+ const perpMarketAccountMap = new Map<number, AccountMeta>();
1899
2483
  const oracleAccountMap = new Map<string, AccountMeta>();
1900
- const bankAccountMap = new Map<number, AccountMeta>();
2484
+ const spotMarketAccountMap = new Map<number, AccountMeta>();
2485
+
2486
+ for (const position of settleeUserAccount.perpPositions) {
2487
+ if (!positionIsAvailable(position)) {
2488
+ const market = this.getPerpMarketAccount(position.marketIndex);
2489
+ perpMarketAccountMap.set(position.marketIndex.toNumber(), {
2490
+ pubkey: market.pubkey,
2491
+ isWritable: false,
2492
+ isSigner: false,
2493
+ });
2494
+ oracleAccountMap.set(market.amm.oracle.toString(), {
2495
+ pubkey: market.amm.oracle,
2496
+ isWritable: false,
2497
+ isSigner: false,
2498
+ });
2499
+ }
2500
+ }
2501
+
2502
+ for (const spotPosition of settleeUserAccount.spotPositions) {
2503
+ if (!isSpotPositionAvailable(spotPosition)) {
2504
+ const spotMarketAccount = this.getSpotMarketAccount(
2505
+ spotPosition.marketIndex
2506
+ );
2507
+ spotMarketAccountMap.set(spotPosition.marketIndex.toNumber(), {
2508
+ pubkey: spotMarketAccount.pubkey,
2509
+ isSigner: false,
2510
+ isWritable: false,
2511
+ });
2512
+ if (!spotMarketAccount.marketIndex.eq(ZERO)) {
2513
+ oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
2514
+ pubkey: spotMarketAccount.oracle,
2515
+ isSigner: false,
2516
+ isWritable: false,
2517
+ });
2518
+ }
2519
+ }
2520
+ }
2521
+
2522
+ const marketAccount = this.getPerpMarketAccount(marketIndex.toNumber());
2523
+ perpMarketAccountMap.set(marketIndex.toNumber(), {
2524
+ pubkey: marketAccount.pubkey,
2525
+ isSigner: false,
2526
+ isWritable: true,
2527
+ });
2528
+ oracleAccountMap.set(marketAccount.amm.oracle.toString(), {
2529
+ pubkey: marketAccount.amm.oracle,
2530
+ isSigner: false,
2531
+ isWritable: false,
2532
+ });
1901
2533
 
1902
- for (const position of settleeUserAccount.positions) {
2534
+ spotMarketAccountMap.set(QUOTE_SPOT_MARKET_INDEX.toNumber(), {
2535
+ pubkey: this.getSpotMarketAccount(QUOTE_SPOT_MARKET_INDEX).pubkey,
2536
+ isSigner: false,
2537
+ isWritable: true,
2538
+ });
2539
+
2540
+ const remainingAccounts = [
2541
+ ...oracleAccountMap.values(),
2542
+ ...spotMarketAccountMap.values(),
2543
+ ...perpMarketAccountMap.values(),
2544
+ ];
2545
+
2546
+ return await this.program.instruction.settlePnl(marketIndex, {
2547
+ accounts: {
2548
+ state: await this.getStatePublicKey(),
2549
+ authority: this.wallet.publicKey,
2550
+ user: settleeUserAccountPublicKey,
2551
+ },
2552
+ remainingAccounts: remainingAccounts,
2553
+ });
2554
+ }
2555
+
2556
+ public async settleExpiredPosition(
2557
+ settleeUserAccountPublicKey: PublicKey,
2558
+ settleeUserAccount: UserAccount,
2559
+ marketIndex: BN
2560
+ ): Promise<TransactionSignature> {
2561
+ const { txSig } = await this.txSender.send(
2562
+ wrapInTx(
2563
+ await this.getSettleExpiredPositionIx(
2564
+ settleeUserAccountPublicKey,
2565
+ settleeUserAccount,
2566
+ marketIndex
2567
+ )
2568
+ ),
2569
+ [],
2570
+ this.opts
2571
+ );
2572
+ return txSig;
2573
+ }
2574
+
2575
+ public async getSettleExpiredPositionIx(
2576
+ settleeUserAccountPublicKey: PublicKey,
2577
+ settleeUserAccount: UserAccount,
2578
+ marketIndex: BN
2579
+ ): Promise<TransactionInstruction> {
2580
+ const marketAccountMap = new Map<number, AccountMeta>();
2581
+ const oracleAccountMap = new Map<string, AccountMeta>();
2582
+ const spotMarketAccountMap = new Map<number, AccountMeta>();
2583
+ for (const position of settleeUserAccount.perpPositions) {
1903
2584
  if (!positionIsAvailable(position)) {
1904
- const market = this.getMarketAccount(position.marketIndex);
2585
+ const market = this.getPerpMarketAccount(position.marketIndex);
1905
2586
  marketAccountMap.set(position.marketIndex.toNumber(), {
1906
2587
  pubkey: market.pubkey,
1907
2588
  isWritable: false,
@@ -1915,15 +2596,17 @@ export class ClearingHouse {
1915
2596
  }
1916
2597
  }
1917
2598
 
1918
- for (const userBankBalance of settleeUserAccount.bankBalances) {
1919
- if (!userBankBalance.balance.eq(QUOTE_ASSET_BANK_INDEX)) {
1920
- const bankAccount = this.getBankAccount(userBankBalance.bankIndex);
1921
- bankAccountMap.set(userBankBalance.bankIndex.toNumber(), {
2599
+ for (const userBankBalance of settleeUserAccount.spotPositions) {
2600
+ if (!userBankBalance.balance.eq(ZERO)) {
2601
+ const bankAccount = this.getSpotMarketAccount(
2602
+ userBankBalance.marketIndex
2603
+ );
2604
+ spotMarketAccountMap.set(userBankBalance.marketIndex.toNumber(), {
1922
2605
  pubkey: bankAccount.pubkey,
1923
2606
  isSigner: false,
1924
2607
  isWritable: false,
1925
2608
  });
1926
- if (!bankAccount.bankIndex.eq(ZERO)) {
2609
+ if (!bankAccount.marketIndex.eq(ZERO)) {
1927
2610
  oracleAccountMap.set(bankAccount.oracle.toString(), {
1928
2611
  pubkey: bankAccount.oracle,
1929
2612
  isSigner: false,
@@ -1933,7 +2616,7 @@ export class ClearingHouse {
1933
2616
  }
1934
2617
  }
1935
2618
 
1936
- const marketAccount = this.getMarketAccount(marketIndex.toNumber());
2619
+ const marketAccount = this.getPerpMarketAccount(marketIndex.toNumber());
1937
2620
  marketAccountMap.set(marketIndex.toNumber(), {
1938
2621
  pubkey: marketAccount.pubkey,
1939
2622
  isSigner: false,
@@ -1945,19 +2628,19 @@ export class ClearingHouse {
1945
2628
  isWritable: false,
1946
2629
  });
1947
2630
 
1948
- bankAccountMap.set(QUOTE_ASSET_BANK_INDEX.toNumber(), {
1949
- pubkey: this.getBankAccount(QUOTE_ASSET_BANK_INDEX).pubkey,
2631
+ spotMarketAccountMap.set(QUOTE_SPOT_MARKET_INDEX.toNumber(), {
2632
+ pubkey: this.getSpotMarketAccount(QUOTE_SPOT_MARKET_INDEX).pubkey,
1950
2633
  isSigner: false,
1951
2634
  isWritable: true,
1952
2635
  });
1953
2636
 
1954
2637
  const remainingAccounts = [
1955
2638
  ...oracleAccountMap.values(),
1956
- ...bankAccountMap.values(),
2639
+ ...spotMarketAccountMap.values(),
1957
2640
  ...marketAccountMap.values(),
1958
2641
  ];
1959
2642
 
1960
- return await this.program.instruction.settlePnl(marketIndex, {
2643
+ return await this.program.instruction.settleExpiredPosition(marketIndex, {
1961
2644
  accounts: {
1962
2645
  state: await this.getStatePublicKey(),
1963
2646
  authority: this.wallet.publicKey,
@@ -1973,7 +2656,7 @@ export class ClearingHouse {
1973
2656
  marketIndex: BN,
1974
2657
  maxBaseAssetAmount: BN
1975
2658
  ): Promise<TransactionSignature> {
1976
- const { txSig } = await this.txSender.send(
2659
+ const { txSig, slot } = await this.txSender.send(
1977
2660
  wrapInTx(
1978
2661
  await this.getLiquidatePerpIx(
1979
2662
  userAccountPublicKey,
@@ -1985,6 +2668,7 @@ export class ClearingHouse {
1985
2668
  [],
1986
2669
  this.opts
1987
2670
  );
2671
+ this.marketLastSlotCache.set(marketIndex.toNumber(), slot);
1988
2672
  return txSig;
1989
2673
  }
1990
2674
 
@@ -2003,7 +2687,7 @@ export class ClearingHouse {
2003
2687
  const liquidatorStatsPublicKey = this.getUserStatsAccountPublicKey();
2004
2688
 
2005
2689
  const remainingAccounts = this.getRemainingAccountsWithCounterparty({
2006
- writableMarketIndex: marketIndex,
2690
+ writablePerpMarketIndex: marketIndex,
2007
2691
  counterPartyUserAccount: userAccount,
2008
2692
  });
2009
2693
 
@@ -2027,8 +2711,8 @@ export class ClearingHouse {
2027
2711
  public async liquidateBorrow(
2028
2712
  userAccountPublicKey: PublicKey,
2029
2713
  userAccount: UserAccount,
2030
- assetBankIndex: BN,
2031
- liabilityBankIndex: BN,
2714
+ assetmarketIndex: BN,
2715
+ liabilitymarketIndex: BN,
2032
2716
  maxLiabilityTransfer: BN
2033
2717
  ): Promise<TransactionSignature> {
2034
2718
  const { txSig } = await this.txSender.send(
@@ -2036,8 +2720,8 @@ export class ClearingHouse {
2036
2720
  await this.getLiquidateBorrowIx(
2037
2721
  userAccountPublicKey,
2038
2722
  userAccount,
2039
- assetBankIndex,
2040
- liabilityBankIndex,
2723
+ assetmarketIndex,
2724
+ liabilitymarketIndex,
2041
2725
  maxLiabilityTransfer
2042
2726
  )
2043
2727
  ),
@@ -2050,20 +2734,20 @@ export class ClearingHouse {
2050
2734
  public async getLiquidateBorrowIx(
2051
2735
  userAccountPublicKey: PublicKey,
2052
2736
  userAccount: UserAccount,
2053
- assetBankIndex: BN,
2054
- liabilityBankIndex: BN,
2737
+ assetmarketIndex: BN,
2738
+ liabilitymarketIndex: BN,
2055
2739
  maxLiabilityTransfer: BN
2056
2740
  ): Promise<TransactionInstruction> {
2057
2741
  const liquidatorPublicKey = await this.getUserAccountPublicKey();
2058
2742
 
2059
2743
  const remainingAccounts = this.getRemainingAccountsWithCounterparty({
2060
2744
  counterPartyUserAccount: userAccount,
2061
- writableBankIndexes: [liabilityBankIndex, assetBankIndex],
2745
+ writableSpotMarketIndexes: [liabilitymarketIndex, assetmarketIndex],
2062
2746
  });
2063
2747
 
2064
2748
  return await this.program.instruction.liquidateBorrow(
2065
- assetBankIndex,
2066
- liabilityBankIndex,
2749
+ assetmarketIndex,
2750
+ liabilitymarketIndex,
2067
2751
  maxLiabilityTransfer,
2068
2752
  {
2069
2753
  accounts: {
@@ -2081,22 +2765,23 @@ export class ClearingHouse {
2081
2765
  userAccountPublicKey: PublicKey,
2082
2766
  userAccount: UserAccount,
2083
2767
  perpMarketIndex: BN,
2084
- liabilityBankIndex: BN,
2768
+ liabilitymarketIndex: BN,
2085
2769
  maxLiabilityTransfer: BN
2086
2770
  ): Promise<TransactionSignature> {
2087
- const { txSig } = await this.txSender.send(
2771
+ const { txSig, slot } = await this.txSender.send(
2088
2772
  wrapInTx(
2089
2773
  await this.getLiquidateBorrowForPerpPnlIx(
2090
2774
  userAccountPublicKey,
2091
2775
  userAccount,
2092
2776
  perpMarketIndex,
2093
- liabilityBankIndex,
2777
+ liabilitymarketIndex,
2094
2778
  maxLiabilityTransfer
2095
2779
  )
2096
2780
  ),
2097
2781
  [],
2098
2782
  this.opts
2099
2783
  );
2784
+ this.marketLastSlotCache.set(perpMarketIndex.toNumber(), slot);
2100
2785
  return txSig;
2101
2786
  }
2102
2787
 
@@ -2104,20 +2789,20 @@ export class ClearingHouse {
2104
2789
  userAccountPublicKey: PublicKey,
2105
2790
  userAccount: UserAccount,
2106
2791
  perpMarketIndex: BN,
2107
- liabilityBankIndex: BN,
2792
+ liabilitymarketIndex: BN,
2108
2793
  maxLiabilityTransfer: BN
2109
2794
  ): Promise<TransactionInstruction> {
2110
2795
  const liquidatorPublicKey = await this.getUserAccountPublicKey();
2111
2796
 
2112
2797
  const remainingAccounts = this.getRemainingAccountsWithCounterparty({
2113
2798
  counterPartyUserAccount: userAccount,
2114
- writableMarketIndex: perpMarketIndex,
2115
- writableBankIndexes: [liabilityBankIndex],
2799
+ writablePerpMarketIndex: perpMarketIndex,
2800
+ writableSpotMarketIndexes: [liabilitymarketIndex],
2116
2801
  });
2117
2802
 
2118
2803
  return await this.program.instruction.liquidateBorrowForPerpPnl(
2119
2804
  perpMarketIndex,
2120
- liabilityBankIndex,
2805
+ liabilitymarketIndex,
2121
2806
  maxLiabilityTransfer,
2122
2807
  {
2123
2808
  accounts: {
@@ -2135,22 +2820,23 @@ export class ClearingHouse {
2135
2820
  userAccountPublicKey: PublicKey,
2136
2821
  userAccount: UserAccount,
2137
2822
  perpMarketIndex: BN,
2138
- assetBankIndex: BN,
2823
+ assetMarketIndex: BN,
2139
2824
  maxPnlTransfer: BN
2140
2825
  ): Promise<TransactionSignature> {
2141
- const { txSig } = await this.txSender.send(
2826
+ const { txSig, slot } = await this.txSender.send(
2142
2827
  wrapInTx(
2143
2828
  await this.getLiquidatePerpPnlForDepositIx(
2144
2829
  userAccountPublicKey,
2145
2830
  userAccount,
2146
2831
  perpMarketIndex,
2147
- assetBankIndex,
2832
+ assetMarketIndex,
2148
2833
  maxPnlTransfer
2149
2834
  )
2150
2835
  ),
2151
2836
  [],
2152
2837
  this.opts
2153
2838
  );
2839
+ this.marketLastSlotCache.set(perpMarketIndex.toNumber(), slot);
2154
2840
  return txSig;
2155
2841
  }
2156
2842
 
@@ -2158,20 +2844,20 @@ export class ClearingHouse {
2158
2844
  userAccountPublicKey: PublicKey,
2159
2845
  userAccount: UserAccount,
2160
2846
  perpMarketIndex: BN,
2161
- assetBankIndex: BN,
2847
+ assetMarketIndex: BN,
2162
2848
  maxPnlTransfer: BN
2163
2849
  ): Promise<TransactionInstruction> {
2164
2850
  const liquidatorPublicKey = await this.getUserAccountPublicKey();
2165
2851
 
2166
2852
  const remainingAccounts = this.getRemainingAccountsWithCounterparty({
2167
2853
  counterPartyUserAccount: userAccount,
2168
- writableMarketIndex: perpMarketIndex,
2169
- writableBankIndexes: [assetBankIndex],
2854
+ writablePerpMarketIndex: perpMarketIndex,
2855
+ writableSpotMarketIndexes: [assetMarketIndex],
2170
2856
  });
2171
2857
 
2172
2858
  return await this.program.instruction.liquidatePerpPnlForDeposit(
2173
2859
  perpMarketIndex,
2174
- assetBankIndex,
2860
+ assetMarketIndex,
2175
2861
  maxPnlTransfer,
2176
2862
  {
2177
2863
  accounts: {
@@ -2188,7 +2874,6 @@ export class ClearingHouse {
2188
2874
  public async resolvePerpBankruptcy(
2189
2875
  userAccountPublicKey: PublicKey,
2190
2876
  userAccount: UserAccount,
2191
- bankIndex: BN,
2192
2877
  marketIndex: BN
2193
2878
  ): Promise<TransactionSignature> {
2194
2879
  const { txSig } = await this.txSender.send(
@@ -2196,7 +2881,6 @@ export class ClearingHouse {
2196
2881
  await this.getResolvePerpBankruptcyIx(
2197
2882
  userAccountPublicKey,
2198
2883
  userAccount,
2199
- bankIndex,
2200
2884
  marketIndex
2201
2885
  )
2202
2886
  ),
@@ -2209,21 +2893,20 @@ export class ClearingHouse {
2209
2893
  public async getResolvePerpBankruptcyIx(
2210
2894
  userAccountPublicKey: PublicKey,
2211
2895
  userAccount: UserAccount,
2212
- bankIndex: BN,
2213
2896
  marketIndex: BN
2214
2897
  ): Promise<TransactionInstruction> {
2215
2898
  const liquidatorPublicKey = await this.getUserAccountPublicKey();
2216
2899
 
2217
2900
  const remainingAccounts = this.getRemainingAccountsWithCounterparty({
2218
- writableMarketIndex: marketIndex,
2219
- writableBankIndexes: [bankIndex],
2901
+ writablePerpMarketIndex: marketIndex,
2902
+ writableSpotMarketIndexes: [QUOTE_SPOT_MARKET_INDEX],
2220
2903
  counterPartyUserAccount: userAccount,
2221
2904
  });
2222
2905
 
2223
- const bank = this.getBankAccount(bankIndex);
2906
+ const spotMarket = this.getSpotMarketAccount(marketIndex);
2224
2907
 
2225
2908
  return await this.program.instruction.resolvePerpBankruptcy(
2226
- bankIndex,
2909
+ QUOTE_SPOT_MARKET_INDEX,
2227
2910
  marketIndex,
2228
2911
  {
2229
2912
  accounts: {
@@ -2231,8 +2914,8 @@ export class ClearingHouse {
2231
2914
  authority: this.wallet.publicKey,
2232
2915
  user: userAccountPublicKey,
2233
2916
  liquidator: liquidatorPublicKey,
2234
- bankVault: bank.vault,
2235
- insuranceFundVault: bank.insuranceFundVault,
2917
+ spotMarketVault: spotMarket.vault,
2918
+ insuranceFundVault: spotMarket.insuranceFundVault,
2236
2919
  clearingHouseSigner: this.getSignerPublicKey(),
2237
2920
  tokenProgram: TOKEN_PROGRAM_ID,
2238
2921
  },
@@ -2244,14 +2927,14 @@ export class ClearingHouse {
2244
2927
  public async resolveBorrowBankruptcy(
2245
2928
  userAccountPublicKey: PublicKey,
2246
2929
  userAccount: UserAccount,
2247
- bankIndex: BN
2930
+ marketIndex: BN
2248
2931
  ): Promise<TransactionSignature> {
2249
2932
  const { txSig } = await this.txSender.send(
2250
2933
  wrapInTx(
2251
2934
  await this.getResolveBorrowBankruptcyIx(
2252
2935
  userAccountPublicKey,
2253
2936
  userAccount,
2254
- bankIndex
2937
+ marketIndex
2255
2938
  )
2256
2939
  ),
2257
2940
  [],
@@ -2263,25 +2946,25 @@ export class ClearingHouse {
2263
2946
  public async getResolveBorrowBankruptcyIx(
2264
2947
  userAccountPublicKey: PublicKey,
2265
2948
  userAccount: UserAccount,
2266
- bankIndex: BN
2949
+ marketIndex: BN
2267
2950
  ): Promise<TransactionInstruction> {
2268
2951
  const liquidatorPublicKey = await this.getUserAccountPublicKey();
2269
2952
 
2270
2953
  const remainingAccounts = this.getRemainingAccountsWithCounterparty({
2271
- writableBankIndexes: [bankIndex],
2954
+ writableSpotMarketIndexes: [marketIndex],
2272
2955
  counterPartyUserAccount: userAccount,
2273
2956
  });
2274
2957
 
2275
- const bank = this.getBankAccount(bankIndex);
2958
+ const spotMarket = this.getSpotMarketAccount(marketIndex);
2276
2959
 
2277
- return await this.program.instruction.resolveBorrowBankruptcy(bankIndex, {
2960
+ return await this.program.instruction.resolveBorrowBankruptcy(marketIndex, {
2278
2961
  accounts: {
2279
2962
  state: await this.getStatePublicKey(),
2280
2963
  authority: this.wallet.publicKey,
2281
2964
  user: userAccountPublicKey,
2282
2965
  liquidator: liquidatorPublicKey,
2283
- bankVault: bank.vault,
2284
- insuranceFundVault: bank.insuranceFundVault,
2966
+ spotMarketVault: spotMarket.vault,
2967
+ insuranceFundVault: spotMarket.insuranceFundVault,
2285
2968
  clearingHouseSigner: this.getSignerPublicKey(),
2286
2969
  tokenProgram: TOKEN_PROGRAM_ID,
2287
2970
  },
@@ -2291,35 +2974,35 @@ export class ClearingHouse {
2291
2974
 
2292
2975
  getRemainingAccountsWithCounterparty(params: {
2293
2976
  counterPartyUserAccount: UserAccount;
2294
- writableMarketIndex?: BN;
2295
- writableBankIndexes?: BN[];
2977
+ writablePerpMarketIndex?: BN;
2978
+ writableSpotMarketIndexes?: BN[];
2296
2979
  }): AccountMeta[] {
2297
2980
  const counterPartyUserAccount = params.counterPartyUserAccount;
2298
2981
 
2299
2982
  const oracleAccountMap = new Map<string, AccountMeta>();
2300
- const bankAccountMap = new Map<number, AccountMeta>();
2983
+ const spotMarketAccountMap = new Map<number, AccountMeta>();
2301
2984
  const marketAccountMap = new Map<number, AccountMeta>();
2302
- for (const bankBalance of counterPartyUserAccount.bankBalances) {
2303
- if (!bankBalance.balance.eq(ZERO)) {
2304
- const bankAccount = this.getBankAccount(bankBalance.bankIndex);
2305
- bankAccountMap.set(bankBalance.bankIndex.toNumber(), {
2306
- pubkey: bankAccount.pubkey,
2985
+ for (const spotPosition of counterPartyUserAccount.spotPositions) {
2986
+ if (!isSpotPositionAvailable(spotPosition)) {
2987
+ const spotMarket = this.getSpotMarketAccount(spotPosition.marketIndex);
2988
+ spotMarketAccountMap.set(spotPosition.marketIndex.toNumber(), {
2989
+ pubkey: spotMarket.pubkey,
2307
2990
  isSigner: false,
2308
2991
  isWritable: false,
2309
2992
  });
2310
2993
 
2311
- if (!bankAccount.oracle.equals(PublicKey.default)) {
2312
- oracleAccountMap.set(bankAccount.oracle.toString(), {
2313
- pubkey: bankAccount.oracle,
2994
+ if (!spotMarket.oracle.equals(PublicKey.default)) {
2995
+ oracleAccountMap.set(spotMarket.oracle.toString(), {
2996
+ pubkey: spotMarket.oracle,
2314
2997
  isSigner: false,
2315
2998
  isWritable: false,
2316
2999
  });
2317
3000
  }
2318
3001
  }
2319
3002
  }
2320
- for (const position of counterPartyUserAccount.positions) {
3003
+ for (const position of counterPartyUserAccount.perpPositions) {
2321
3004
  if (!positionIsAvailable(position)) {
2322
- const market = this.getMarketAccount(position.marketIndex);
3005
+ const market = this.getPerpMarketAccount(position.marketIndex);
2323
3006
  marketAccountMap.set(position.marketIndex.toNumber(), {
2324
3007
  pubkey: market.pubkey,
2325
3008
  isWritable: false,
@@ -2346,7 +3029,7 @@ export class ClearingHouse {
2346
3029
  // if cache has more recent slot than user positions account slot, add market to remaining accounts
2347
3030
  // otherwise remove from slot
2348
3031
  if (slot > lastUserPositionsSlot) {
2349
- const marketAccount = this.getMarketAccount(marketIndexNum);
3032
+ const marketAccount = this.getPerpMarketAccount(marketIndexNum);
2350
3033
  marketAccountMap.set(marketIndexNum, {
2351
3034
  pubkey: marketAccount.pubkey,
2352
3035
  isSigner: false,
@@ -2361,27 +3044,27 @@ export class ClearingHouse {
2361
3044
  this.marketLastSlotCache.delete(marketIndexNum);
2362
3045
  }
2363
3046
  }
2364
- for (const bankBalance of userAccount.bankBalances) {
2365
- if (!bankBalance.balance.eq(ZERO)) {
2366
- const bankAccount = this.getBankAccount(bankBalance.bankIndex);
2367
- bankAccountMap.set(bankBalance.bankIndex.toNumber(), {
2368
- pubkey: bankAccount.pubkey,
3047
+ for (const spotPosition of userAccount.spotPositions) {
3048
+ if (!isSpotPositionAvailable(spotPosition)) {
3049
+ const spotMarket = this.getSpotMarketAccount(spotPosition.marketIndex);
3050
+ spotMarketAccountMap.set(spotPosition.marketIndex.toNumber(), {
3051
+ pubkey: spotMarket.pubkey,
2369
3052
  isSigner: false,
2370
3053
  isWritable: false,
2371
3054
  });
2372
3055
 
2373
- if (!bankAccount.oracle.equals(PublicKey.default)) {
2374
- oracleAccountMap.set(bankAccount.oracle.toString(), {
2375
- pubkey: bankAccount.oracle,
3056
+ if (!spotMarket.oracle.equals(PublicKey.default)) {
3057
+ oracleAccountMap.set(spotMarket.oracle.toString(), {
3058
+ pubkey: spotMarket.oracle,
2376
3059
  isSigner: false,
2377
3060
  isWritable: false,
2378
3061
  });
2379
3062
  }
2380
3063
  }
2381
3064
  }
2382
- for (const position of userAccount.positions) {
3065
+ for (const position of userAccount.perpPositions) {
2383
3066
  if (!positionIsAvailable(position)) {
2384
- const market = this.getMarketAccount(position.marketIndex);
3067
+ const market = this.getPerpMarketAccount(position.marketIndex);
2385
3068
  marketAccountMap.set(position.marketIndex.toNumber(), {
2386
3069
  pubkey: market.pubkey,
2387
3070
  isWritable: false,
@@ -2395,8 +3078,8 @@ export class ClearingHouse {
2395
3078
  }
2396
3079
  }
2397
3080
 
2398
- if (params.writableMarketIndex) {
2399
- const market = this.getMarketAccount(params.writableMarketIndex);
3081
+ if (params.writablePerpMarketIndex) {
3082
+ const market = this.getPerpMarketAccount(params.writablePerpMarketIndex);
2400
3083
  marketAccountMap.set(market.marketIndex.toNumber(), {
2401
3084
  pubkey: market.pubkey,
2402
3085
  isSigner: false,
@@ -2409,17 +3092,19 @@ export class ClearingHouse {
2409
3092
  });
2410
3093
  }
2411
3094
 
2412
- if (params.writableBankIndexes) {
2413
- for (const writableBankIndex of params.writableBankIndexes) {
2414
- const bank = this.getBankAccount(writableBankIndex);
2415
- bankAccountMap.set(bank.bankIndex.toNumber(), {
2416
- pubkey: bank.pubkey,
3095
+ if (params.writableSpotMarketIndexes) {
3096
+ for (const writableSpotMarketIndex of params.writableSpotMarketIndexes) {
3097
+ const spotMarketAccount = this.getSpotMarketAccount(
3098
+ writableSpotMarketIndex
3099
+ );
3100
+ spotMarketAccountMap.set(spotMarketAccount.marketIndex.toNumber(), {
3101
+ pubkey: spotMarketAccount.pubkey,
2417
3102
  isSigner: false,
2418
3103
  isWritable: true,
2419
3104
  });
2420
- if (!bank.oracle.equals(PublicKey.default)) {
2421
- oracleAccountMap.set(bank.oracle.toString(), {
2422
- pubkey: bank.oracle,
3105
+ if (!spotMarketAccount.oracle.equals(PublicKey.default)) {
3106
+ oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
3107
+ pubkey: spotMarketAccount.oracle,
2423
3108
  isSigner: false,
2424
3109
  isWritable: false,
2425
3110
  });
@@ -2429,7 +3114,7 @@ export class ClearingHouse {
2429
3114
 
2430
3115
  return [
2431
3116
  ...oracleAccountMap.values(),
2432
- ...bankAccountMap.values(),
3117
+ ...spotMarketAccountMap.values(),
2433
3118
  ...marketAccountMap.values(),
2434
3119
  ];
2435
3120
  }
@@ -2477,7 +3162,7 @@ export class ClearingHouse {
2477
3162
  userAccount
2478
3163
  )) as UserAccount;
2479
3164
 
2480
- const userPositions = user.positions;
3165
+ const userPositions = user.perpPositions;
2481
3166
 
2482
3167
  const remainingAccounts = [];
2483
3168
  for (const position of userPositions) {
@@ -2508,17 +3193,17 @@ export class ClearingHouse {
2508
3193
  }
2509
3194
 
2510
3195
  public getOracleDataForMarket(marketIndex: BN): OraclePriceData {
2511
- const oracleKey = this.getMarketAccount(marketIndex).amm.oracle;
3196
+ const oracleKey = this.getPerpMarketAccount(marketIndex).amm.oracle;
2512
3197
  const oracleData = this.getOraclePriceDataAndSlot(oracleKey).data;
2513
3198
 
2514
3199
  return oracleData;
2515
3200
  }
2516
3201
 
2517
3202
  public async initializeInsuranceFundStake(
2518
- bankIndex: BN
3203
+ marketIndex: BN
2519
3204
  ): Promise<TransactionSignature> {
2520
3205
  const { txSig } = await this.txSender.send(
2521
- wrapInTx(await this.getInitializeInsuranceFundStakeIx(bankIndex)),
3206
+ wrapInTx(await this.getInitializeInsuranceFundStakeIx(marketIndex)),
2522
3207
  [],
2523
3208
  this.opts
2524
3209
  );
@@ -2526,20 +3211,20 @@ export class ClearingHouse {
2526
3211
  }
2527
3212
 
2528
3213
  public async getInitializeInsuranceFundStakeIx(
2529
- bankIndex: BN
3214
+ marketIndex: BN
2530
3215
  ): Promise<TransactionInstruction> {
2531
3216
  const ifStakeAccountPublicKey = getInsuranceFundStakeAccountPublicKey(
2532
3217
  this.program.programId,
2533
3218
  this.wallet.publicKey,
2534
- bankIndex
3219
+ marketIndex
2535
3220
  );
2536
3221
 
2537
3222
  return await this.program.instruction.initializeInsuranceFundStake(
2538
- bankIndex,
3223
+ marketIndex,
2539
3224
  {
2540
3225
  accounts: {
2541
3226
  insuranceFundStake: ifStakeAccountPublicKey,
2542
- bank: this.getBankAccount(bankIndex).pubkey,
3227
+ spotMarket: this.getSpotMarketAccount(marketIndex).pubkey,
2543
3228
  userStats: this.getUserStatsAccountPublicKey(),
2544
3229
  authority: this.wallet.publicKey,
2545
3230
  payer: this.wallet.publicKey,
@@ -2552,29 +3237,29 @@ export class ClearingHouse {
2552
3237
  }
2553
3238
 
2554
3239
  public async addInsuranceFundStake(
2555
- bankIndex: BN,
3240
+ marketIndex: BN,
2556
3241
  amount: BN,
2557
3242
  collateralAccountPublicKey: PublicKey
2558
3243
  ): Promise<TransactionSignature> {
2559
- const bank = this.getBankAccount(bankIndex);
3244
+ const spotMarket = this.getSpotMarketAccount(marketIndex);
2560
3245
  const ifStakeAccountPublicKey = getInsuranceFundStakeAccountPublicKey(
2561
3246
  this.program.programId,
2562
3247
  this.wallet.publicKey,
2563
- bankIndex
3248
+ marketIndex
2564
3249
  );
2565
3250
 
2566
3251
  const remainingAccounts = this.getRemainingAccounts({
2567
- writableBankIndex: bankIndex,
3252
+ writableSpotMarketIndex: marketIndex,
2568
3253
  });
2569
3254
 
2570
- return await this.program.rpc.addInsuranceFundStake(bankIndex, amount, {
3255
+ return await this.program.rpc.addInsuranceFundStake(marketIndex, amount, {
2571
3256
  accounts: {
2572
3257
  state: await this.getStatePublicKey(),
2573
- bank: bank.pubkey,
3258
+ spotMarket: spotMarket.pubkey,
2574
3259
  insuranceFundStake: ifStakeAccountPublicKey,
2575
3260
  userStats: this.getUserStatsAccountPublicKey(),
2576
3261
  authority: this.wallet.publicKey,
2577
- insuranceFundVault: bank.insuranceFundVault,
3262
+ insuranceFundVault: spotMarket.insuranceFundVault,
2578
3263
  userTokenAccount: collateralAccountPublicKey,
2579
3264
  tokenProgram: TOKEN_PROGRAM_ID,
2580
3265
  },
@@ -2583,31 +3268,31 @@ export class ClearingHouse {
2583
3268
  }
2584
3269
 
2585
3270
  public async requestRemoveInsuranceFundStake(
2586
- bankIndex: BN,
3271
+ marketIndex: BN,
2587
3272
  amount: BN
2588
3273
  ): Promise<TransactionSignature> {
2589
- const bank = this.getBankAccount(bankIndex);
3274
+ const spotMarketAccount = this.getSpotMarketAccount(marketIndex);
2590
3275
  const ifStakeAccountPublicKey = getInsuranceFundStakeAccountPublicKey(
2591
3276
  this.program.programId,
2592
3277
  this.wallet.publicKey,
2593
- bankIndex
3278
+ marketIndex
2594
3279
  );
2595
3280
 
2596
3281
  const remainingAccounts = this.getRemainingAccounts({
2597
- writableBankIndex: bankIndex,
3282
+ writableSpotMarketIndex: marketIndex,
2598
3283
  });
2599
3284
 
2600
3285
  return await this.program.rpc.requestRemoveInsuranceFundStake(
2601
- bankIndex,
3286
+ marketIndex,
2602
3287
  amount,
2603
3288
  {
2604
3289
  accounts: {
2605
3290
  state: await this.getStatePublicKey(),
2606
- bank: bank.pubkey,
3291
+ spotMarket: spotMarketAccount.pubkey,
2607
3292
  insuranceFundStake: ifStakeAccountPublicKey,
2608
3293
  userStats: this.getUserStatsAccountPublicKey(),
2609
3294
  authority: this.wallet.publicKey,
2610
- insuranceFundVault: bank.insuranceFundVault,
3295
+ insuranceFundVault: spotMarketAccount.insuranceFundVault,
2611
3296
  // userTokenAccount: collateralAccountPublicKey,
2612
3297
  // tokenProgram: TOKEN_PROGRAM_ID,
2613
3298
  },
@@ -2617,29 +3302,29 @@ export class ClearingHouse {
2617
3302
  }
2618
3303
 
2619
3304
  public async cancelRequestRemoveInsuranceFundStake(
2620
- bankIndex: BN
3305
+ marketIndex: BN
2621
3306
  ): Promise<TransactionSignature> {
2622
- const bank = this.getBankAccount(bankIndex);
3307
+ const spotMarketAccount = this.getSpotMarketAccount(marketIndex);
2623
3308
  const ifStakeAccountPublicKey = getInsuranceFundStakeAccountPublicKey(
2624
3309
  this.program.programId,
2625
3310
  this.wallet.publicKey,
2626
- bankIndex
3311
+ marketIndex
2627
3312
  );
2628
3313
 
2629
3314
  const remainingAccounts = this.getRemainingAccounts({
2630
- writableBankIndex: bankIndex,
3315
+ writableSpotMarketIndex: marketIndex,
2631
3316
  });
2632
3317
 
2633
3318
  return await this.program.rpc.cancelRequestRemoveInsuranceFundStake(
2634
- bankIndex,
3319
+ marketIndex,
2635
3320
  {
2636
3321
  accounts: {
2637
3322
  state: await this.getStatePublicKey(),
2638
- bank: bank.pubkey,
3323
+ spotMarket: spotMarketAccount.pubkey,
2639
3324
  insuranceFundStake: ifStakeAccountPublicKey,
2640
3325
  userStats: this.getUserStatsAccountPublicKey(),
2641
3326
  authority: this.wallet.publicKey,
2642
- insuranceFundVault: bank.insuranceFundVault,
3327
+ insuranceFundVault: spotMarketAccount.insuranceFundVault,
2643
3328
  // userTokenAccount: collateralAccountPublicKey,
2644
3329
  // tokenProgram: TOKEN_PROGRAM_ID,
2645
3330
  },
@@ -2649,28 +3334,28 @@ export class ClearingHouse {
2649
3334
  }
2650
3335
 
2651
3336
  public async removeInsuranceFundStake(
2652
- bankIndex: BN,
3337
+ marketIndex: BN,
2653
3338
  collateralAccountPublicKey: PublicKey
2654
3339
  ): Promise<TransactionSignature> {
2655
- const bank = this.getBankAccount(bankIndex);
3340
+ const spotMarketAccount = this.getSpotMarketAccount(marketIndex);
2656
3341
  const ifStakeAccountPublicKey = getInsuranceFundStakeAccountPublicKey(
2657
3342
  this.program.programId,
2658
3343
  this.wallet.publicKey,
2659
- bankIndex
3344
+ marketIndex
2660
3345
  );
2661
3346
 
2662
3347
  const remainingAccounts = this.getRemainingAccounts({
2663
- writableBankIndex: bankIndex,
3348
+ writableSpotMarketIndex: marketIndex,
2664
3349
  });
2665
3350
 
2666
- return await this.program.rpc.removeInsuranceFundStake(bankIndex, {
3351
+ return await this.program.rpc.removeInsuranceFundStake(marketIndex, {
2667
3352
  accounts: {
2668
3353
  state: await this.getStatePublicKey(),
2669
- bank: bank.pubkey,
3354
+ spotMarket: spotMarketAccount.pubkey,
2670
3355
  insuranceFundStake: ifStakeAccountPublicKey,
2671
3356
  userStats: this.getUserStatsAccountPublicKey(),
2672
3357
  authority: this.wallet.publicKey,
2673
- insuranceFundVault: bank.insuranceFundVault,
3358
+ insuranceFundVault: spotMarketAccount.insuranceFundVault,
2674
3359
  clearingHouseSigner: this.getSignerPublicKey(),
2675
3360
  userTokenAccount: collateralAccountPublicKey,
2676
3361
  tokenProgram: TOKEN_PROGRAM_ID,
@@ -2680,24 +3365,66 @@ export class ClearingHouse {
2680
3365
  }
2681
3366
 
2682
3367
  public async settleRevenueToInsuranceFund(
2683
- bankIndex: BN
3368
+ marketIndex: BN
2684
3369
  ): Promise<TransactionSignature> {
2685
- const bank = this.getBankAccount(bankIndex);
3370
+ const spotMarketAccount = this.getSpotMarketAccount(marketIndex);
2686
3371
 
2687
3372
  const remainingAccounts = this.getRemainingAccounts({
2688
- writableBankIndex: bankIndex,
3373
+ writableSpotMarketIndex: marketIndex,
2689
3374
  });
2690
3375
 
2691
- return await this.program.rpc.settleRevenueToInsuranceFund(bankIndex, {
3376
+ return await this.program.rpc.settleRevenueToInsuranceFund(marketIndex, {
2692
3377
  accounts: {
2693
3378
  state: await this.getStatePublicKey(),
2694
- bank: bank.pubkey,
2695
- bankVault: bank.vault,
3379
+ spotMarket: spotMarketAccount.pubkey,
3380
+ spotMarketVault: spotMarketAccount.vault,
2696
3381
  clearingHouseSigner: this.getSignerPublicKey(),
2697
- insuranceFundVault: bank.insuranceFundVault,
3382
+ insuranceFundVault: spotMarketAccount.insuranceFundVault,
2698
3383
  tokenProgram: TOKEN_PROGRAM_ID,
2699
3384
  },
2700
3385
  remainingAccounts,
2701
3386
  });
2702
3387
  }
3388
+
3389
+ public async resolvePerpPnlDeficit(
3390
+ spotMarketIndex: BN,
3391
+ perpMarketIndex: BN
3392
+ ): Promise<TransactionSignature> {
3393
+ const { txSig } = await this.txSender.send(
3394
+ wrapInTx(
3395
+ await this.getResolvePerpPnlDeficitIx(spotMarketIndex, perpMarketIndex)
3396
+ ),
3397
+ [],
3398
+ this.opts
3399
+ );
3400
+ return txSig;
3401
+ }
3402
+
3403
+ public async getResolvePerpPnlDeficitIx(
3404
+ spotMarketIndex: BN,
3405
+ perpMarketIndex: BN
3406
+ ): Promise<TransactionInstruction> {
3407
+ const remainingAccounts = this.getRemainingAccounts({
3408
+ writablePerpMarketIndex: perpMarketIndex,
3409
+ writableSpotMarketIndex: spotMarketIndex,
3410
+ });
3411
+
3412
+ const spotMarket = this.getSpotMarketAccount(spotMarketIndex);
3413
+
3414
+ return await this.program.instruction.resolvePerpPnlDeficit(
3415
+ spotMarketIndex,
3416
+ perpMarketIndex,
3417
+ {
3418
+ accounts: {
3419
+ state: await this.getStatePublicKey(),
3420
+ authority: this.wallet.publicKey,
3421
+ spotMarketVault: spotMarket.vault,
3422
+ insuranceFundVault: spotMarket.insuranceFundVault,
3423
+ clearingHouseSigner: this.getSignerPublicKey(),
3424
+ tokenProgram: TOKEN_PROGRAM_ID,
3425
+ },
3426
+ remainingAccounts: remainingAccounts,
3427
+ }
3428
+ );
3429
+ }
2703
3430
  }