@drift-labs/sdk 0.2.0-master.3 → 0.2.0-master.30

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 (208) hide show
  1. package/README.md +13 -13
  2. package/lib/accounts/bulkUserStatsSubscription.d.ts +7 -0
  3. package/lib/accounts/bulkUserStatsSubscription.js +21 -0
  4. package/lib/accounts/bulkUserSubscription.js +0 -1
  5. package/lib/accounts/fetch.d.ts +2 -1
  6. package/lib/accounts/fetch.js +9 -1
  7. package/lib/accounts/pollingClearingHouseAccountSubscriber.d.ts +16 -16
  8. package/lib/accounts/pollingClearingHouseAccountSubscriber.js +31 -28
  9. package/lib/accounts/pollingUserStatsAccountSubscriber.d.ts +27 -0
  10. package/lib/accounts/pollingUserStatsAccountSubscriber.js +113 -0
  11. package/lib/accounts/types.d.ts +22 -11
  12. package/lib/accounts/webSocketClearingHouseAccountSubscriber.d.ts +17 -17
  13. package/lib/accounts/webSocketClearingHouseAccountSubscriber.js +37 -35
  14. package/lib/accounts/webSocketUserStatsAccountSubsriber.d.ts +20 -0
  15. package/lib/accounts/webSocketUserStatsAccountSubsriber.js +47 -0
  16. package/lib/addresses/marketAddresses.d.ts +1 -3
  17. package/lib/addresses/pda.d.ts +10 -4
  18. package/lib/addresses/pda.js +51 -14
  19. package/lib/admin.d.ts +34 -22
  20. package/lib/admin.js +182 -73
  21. package/lib/clearingHouse.d.ts +120 -42
  22. package/lib/clearingHouse.js +1505 -254
  23. package/lib/clearingHouseConfig.d.ts +4 -4
  24. package/lib/clearingHouseUser.d.ts +50 -38
  25. package/lib/clearingHouseUser.js +410 -190
  26. package/lib/clearingHouseUserStats.d.ts +18 -0
  27. package/lib/clearingHouseUserStats.js +49 -0
  28. package/lib/clearingHouseUserStatsConfig.d.ts +14 -0
  29. package/lib/clearingHouseUserStatsConfig.js +2 -0
  30. package/lib/config.d.ts +7 -9
  31. package/lib/config.js +21 -21
  32. package/lib/constants/numericConstants.d.ts +18 -12
  33. package/lib/constants/numericConstants.js +28 -21
  34. package/lib/constants/perpMarkets.d.ts +18 -0
  35. package/lib/constants/{markets.js → perpMarkets.js} +7 -7
  36. package/lib/constants/spotMarkets.d.ts +19 -0
  37. package/lib/constants/spotMarkets.js +53 -0
  38. package/lib/dlob/DLOB.d.ts +73 -0
  39. package/lib/dlob/DLOB.js +553 -0
  40. package/lib/dlob/DLOBNode.d.ts +52 -0
  41. package/lib/dlob/DLOBNode.js +82 -0
  42. package/lib/dlob/NodeList.d.ts +26 -0
  43. package/lib/dlob/NodeList.js +138 -0
  44. package/lib/events/eventList.js +3 -0
  45. package/lib/events/eventSubscriber.d.ts +4 -2
  46. package/lib/events/eventSubscriber.js +16 -9
  47. package/lib/events/fetchLogs.d.ts +10 -1
  48. package/lib/events/fetchLogs.js +27 -7
  49. package/lib/events/pollingLogProvider.d.ts +2 -1
  50. package/lib/events/pollingLogProvider.js +6 -2
  51. package/lib/events/sort.js +8 -11
  52. package/lib/events/types.d.ts +7 -2
  53. package/lib/events/types.js +5 -0
  54. package/lib/examples/makeTradeExample.js +20 -8
  55. package/lib/factory/bigNum.d.ts +1 -0
  56. package/lib/factory/bigNum.js +34 -10
  57. package/lib/idl/clearing_house.json +4313 -1433
  58. package/lib/idl/{mock_usdc_faucet.json → token_faucet.json} +46 -23
  59. package/lib/index.d.ts +21 -6
  60. package/lib/index.js +25 -6
  61. package/lib/math/amm.d.ts +8 -5
  62. package/lib/math/amm.js +68 -46
  63. package/lib/math/auction.js +4 -1
  64. package/lib/math/conversion.js +1 -1
  65. package/lib/math/funding.d.ts +6 -6
  66. package/lib/math/funding.js +11 -10
  67. package/lib/math/insurance.d.ts +4 -0
  68. package/lib/math/insurance.js +27 -0
  69. package/lib/math/margin.d.ts +11 -0
  70. package/lib/math/margin.js +77 -0
  71. package/lib/math/market.d.ts +14 -9
  72. package/lib/math/market.js +69 -7
  73. package/lib/math/oracles.d.ts +4 -0
  74. package/lib/math/oracles.js +36 -8
  75. package/lib/math/orders.d.ts +6 -2
  76. package/lib/math/orders.js +78 -3
  77. package/lib/math/position.d.ts +21 -13
  78. package/lib/math/position.js +76 -36
  79. package/lib/math/repeg.js +14 -5
  80. package/lib/math/spotBalance.d.ts +22 -0
  81. package/lib/math/spotBalance.js +193 -0
  82. package/lib/math/spotMarket.d.ts +4 -0
  83. package/lib/math/spotMarket.js +8 -0
  84. package/lib/math/spotPosition.d.ts +6 -0
  85. package/lib/math/spotPosition.js +23 -0
  86. package/lib/math/trade.d.ts +10 -10
  87. package/lib/math/trade.js +22 -29
  88. package/lib/oracles/pythClient.js +1 -1
  89. package/lib/oracles/quoteAssetOracleClient.js +1 -1
  90. package/lib/oracles/switchboardClient.js +1 -1
  91. package/lib/orderParams.d.ts +14 -5
  92. package/lib/orderParams.js +12 -92
  93. package/lib/serum/serumSubscriber.d.ts +23 -0
  94. package/lib/serum/serumSubscriber.js +41 -0
  95. package/lib/serum/types.d.ts +11 -0
  96. package/lib/serum/types.js +2 -0
  97. package/lib/slot/SlotSubscriber.d.ts +7 -0
  98. package/lib/slot/SlotSubscriber.js +3 -0
  99. package/lib/{mockUSDCFaucet.d.ts → tokenFaucet.d.ts} +8 -5
  100. package/lib/{mockUSDCFaucet.js → tokenFaucet.js} +63 -51
  101. package/lib/tx/retryTxSender.d.ts +1 -1
  102. package/lib/tx/retryTxSender.js +13 -4
  103. package/lib/tx/types.d.ts +1 -1
  104. package/lib/tx/utils.js +1 -1
  105. package/lib/types.d.ts +474 -123
  106. package/lib/types.js +99 -5
  107. package/lib/userMap/userMap.d.ts +25 -0
  108. package/lib/userMap/userMap.js +73 -0
  109. package/lib/userMap/userStatsMap.d.ts +19 -0
  110. package/lib/userMap/userStatsMap.js +68 -0
  111. package/lib/util/computeUnits.js +1 -1
  112. package/lib/util/getTokenAddress.d.ts +2 -0
  113. package/lib/util/getTokenAddress.js +9 -0
  114. package/package.json +9 -5
  115. package/src/accounts/bulkUserStatsSubscription.ts +33 -0
  116. package/src/accounts/bulkUserSubscription.ts +0 -1
  117. package/src/accounts/fetch.ts +27 -2
  118. package/src/accounts/pollingClearingHouseAccountSubscriber.ts +46 -42
  119. package/src/accounts/pollingUserStatsAccountSubscriber.ts +172 -0
  120. package/src/accounts/types.ts +31 -11
  121. package/src/accounts/webSocketClearingHouseAccountSubscriber.ts +64 -59
  122. package/src/accounts/webSocketUserStatsAccountSubsriber.ts +80 -0
  123. package/src/addresses/marketAddresses.ts +1 -2
  124. package/src/addresses/pda.ts +88 -14
  125. package/src/admin.ts +333 -128
  126. package/src/assert/assert.js +9 -0
  127. package/src/clearingHouse.ts +2464 -458
  128. package/src/clearingHouseConfig.ts +4 -3
  129. package/src/clearingHouseUser.ts +747 -291
  130. package/src/clearingHouseUserStats.ts +75 -0
  131. package/src/clearingHouseUserStatsConfig.ts +18 -0
  132. package/src/config.ts +30 -31
  133. package/src/constants/numericConstants.ts +41 -25
  134. package/src/constants/{markets.ts → perpMarkets.ts} +10 -10
  135. package/src/constants/spotMarkets.ts +72 -0
  136. package/src/dlob/DLOB.ts +868 -0
  137. package/src/dlob/DLOBNode.ts +162 -0
  138. package/src/dlob/NodeList.ts +185 -0
  139. package/src/events/eventList.js +77 -0
  140. package/src/events/eventList.ts +3 -0
  141. package/src/events/eventSubscriber.ts +20 -12
  142. package/src/events/fetchLogs.ts +35 -8
  143. package/src/events/pollingLogProvider.ts +10 -2
  144. package/src/events/sort.ts +11 -15
  145. package/src/events/types.ts +16 -1
  146. package/src/examples/makeTradeExample.js +157 -0
  147. package/src/examples/makeTradeExample.ts +32 -14
  148. package/src/factory/bigNum.ts +42 -13
  149. package/src/idl/clearing_house.json +4313 -1433
  150. package/src/idl/{mock_usdc_faucet.json → token_faucet.json} +46 -23
  151. package/src/index.ts +21 -6
  152. package/src/math/amm.ts +136 -66
  153. package/src/math/auction.ts +5 -1
  154. package/src/math/conversion.ts +2 -2
  155. package/src/math/funding.ts +20 -18
  156. package/src/math/insurance.ts +35 -0
  157. package/src/math/margin.ts +127 -0
  158. package/src/math/market.ts +138 -12
  159. package/src/math/oracles.ts +63 -9
  160. package/src/math/orders.ts +138 -4
  161. package/src/math/position.ts +119 -58
  162. package/src/math/repeg.ts +16 -6
  163. package/src/math/spotBalance.ts +316 -0
  164. package/src/math/spotMarket.ts +9 -0
  165. package/src/math/spotPosition.ts +47 -0
  166. package/src/math/trade.ts +43 -49
  167. package/src/oracles/pythClient.ts +2 -2
  168. package/src/oracles/quoteAssetOracleClient.ts +2 -2
  169. package/src/oracles/switchboardClient.ts +2 -2
  170. package/src/orderParams.ts +24 -137
  171. package/src/serum/serumSubscriber.ts +80 -0
  172. package/src/serum/types.ts +13 -0
  173. package/src/slot/SlotSubscriber.ts +11 -1
  174. package/src/token/index.js +38 -0
  175. package/src/{mockUSDCFaucet.ts → tokenFaucet.ts} +82 -70
  176. package/src/tx/retryTxSender.ts +16 -5
  177. package/src/tx/types.js +2 -0
  178. package/src/tx/types.ts +2 -1
  179. package/src/tx/utils.js +17 -0
  180. package/src/tx/utils.ts +1 -1
  181. package/src/types.ts +477 -125
  182. package/src/userMap/userMap.ts +100 -0
  183. package/src/userMap/userStatsMap.ts +110 -0
  184. package/src/util/computeUnits.js +21 -11
  185. package/src/util/computeUnits.ts +1 -1
  186. package/src/util/getTokenAddress.js +9 -0
  187. package/src/util/getTokenAddress.ts +18 -0
  188. package/src/util/promiseTimeout.js +14 -0
  189. package/src/util/tps.js +27 -0
  190. package/tests/bn/test.ts +12 -3
  191. package/tests/dlob/helpers.ts +374 -0
  192. package/tests/dlob/test.ts +2865 -0
  193. package/lib/constants/banks.d.ts +0 -16
  194. package/lib/constants/banks.js +0 -34
  195. package/lib/constants/markets.d.ts +0 -19
  196. package/lib/math/bankBalance.d.ts +0 -9
  197. package/lib/math/bankBalance.js +0 -75
  198. package/lib/math/state.d.ts +0 -8
  199. package/lib/math/state.js +0 -15
  200. package/lib/orders.d.ts +0 -8
  201. package/lib/orders.js +0 -134
  202. package/src/constants/banks.ts +0 -43
  203. package/src/math/bankBalance.ts +0 -112
  204. package/src/math/state.ts +0 -14
  205. package/src/math/utils.js +0 -27
  206. package/src/math/utils.js.map +0 -1
  207. package/src/orders.ts +0 -244
  208. package/src/util/computeUnits.js.map +0 -1
@@ -28,7 +28,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
28
28
  Object.defineProperty(exports, "__esModule", { value: true });
29
29
  exports.ClearingHouse = void 0;
30
30
  const anchor_1 = require("@project-serum/anchor");
31
+ const bs58_1 = __importDefault(require("bs58"));
31
32
  const spl_token_1 = require("@solana/spl-token");
33
+ const types_1 = require("./types");
32
34
  const anchor = __importStar(require("@project-serum/anchor"));
33
35
  const clearing_house_json_1 = __importDefault(require("./idl/clearing_house.json"));
34
36
  const web3_js_1 = require("@solana/web3.js");
@@ -36,21 +38,23 @@ const pda_1 = require("./addresses/pda");
36
38
  const utils_1 = require("./tx/utils");
37
39
  const numericConstants_1 = require("./constants/numericConstants");
38
40
  const position_1 = require("./math/position");
39
- const bankBalance_1 = require("./math/bankBalance");
41
+ const spotBalance_1 = require("./math/spotBalance");
40
42
  const userName_1 = require("./userName");
41
43
  const pollingClearingHouseAccountSubscriber_1 = require("./accounts/pollingClearingHouseAccountSubscriber");
42
44
  const webSocketClearingHouseAccountSubscriber_1 = require("./accounts/webSocketClearingHouseAccountSubscriber");
43
45
  const retryTxSender_1 = require("./tx/retryTxSender");
44
46
  const clearingHouseUser_1 = require("./clearingHouseUser");
45
- const orderParams_1 = require("./orderParams");
46
47
  const config_1 = require("./config");
48
+ const spotMarkets_1 = require("./constants/spotMarkets");
49
+ const clearingHouseUserStats_1 = require("./clearingHouseUserStats");
50
+ const spotPosition_1 = require("./math/spotPosition");
47
51
  /**
48
52
  * # ClearingHouse
49
53
  * This class is the main way to interact with Drift Protocol. It allows you to subscribe to the various accounts where the Market's state is stored, as well as: opening positions, liquidating, settling funding, depositing & withdrawing, and more.
50
54
  */
51
55
  class ClearingHouse {
52
56
  constructor(config) {
53
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
57
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
54
58
  this.users = new Map();
55
59
  this._isSubscribed = false;
56
60
  this.marketLastSlotCache = new Map();
@@ -59,10 +63,11 @@ class ClearingHouse {
59
63
  this.opts = config.opts || anchor_1.AnchorProvider.defaultOptions();
60
64
  this.provider = new anchor_1.AnchorProvider(config.connection, config.wallet, this.opts);
61
65
  this.program = new anchor_1.Program(clearing_house_json_1.default, config.programID, this.provider);
62
- const userIds = (_a = config.userIds) !== null && _a !== void 0 ? _a : [0];
63
- this.activeUserId = (_b = config.activeUserId) !== null && _b !== void 0 ? _b : userIds[0];
66
+ this.authority = (_a = config.authority) !== null && _a !== void 0 ? _a : this.wallet.publicKey;
67
+ const userIds = (_b = config.userIds) !== null && _b !== void 0 ? _b : [0];
68
+ this.activeUserId = (_c = config.activeUserId) !== null && _c !== void 0 ? _c : userIds[0];
64
69
  this.userAccountSubscriptionConfig =
65
- ((_c = config.accountSubscription) === null || _c === void 0 ? void 0 : _c.type) === 'polling'
70
+ ((_d = config.accountSubscription) === null || _d === void 0 ? void 0 : _d.type) === 'polling'
66
71
  ? {
67
72
  type: 'polling',
68
73
  accountLoader: config.accountSubscription.accountLoader,
@@ -71,23 +76,34 @@ class ClearingHouse {
71
76
  type: 'websocket',
72
77
  };
73
78
  this.createUsers(userIds, this.userAccountSubscriptionConfig);
74
- let marketIndexes = config.marketIndexes;
75
- let bankIndexes = config.bankIndexes;
79
+ if (config.userStats) {
80
+ this.userStats = new clearingHouseUserStats_1.ClearingHouseUserStats({
81
+ clearingHouse: this,
82
+ userStatsAccountPublicKey: (0, pda_1.getUserStatsAccountPublicKey)(this.program.programId, this.authority),
83
+ accountSubscription: this.userAccountSubscriptionConfig,
84
+ });
85
+ }
86
+ let perpMarketIndexes = config.perpMarketIndexes;
87
+ let spotMarketIndexes = config.spotMarketIndexes;
76
88
  let oracleInfos = config.oracleInfos;
77
89
  if (config.env) {
78
- const { marketIndexes: envMarketIndexes, bankIndexes: envBankIndexes, oracleInfos: envOralceInfos, } = (0, config_1.getMarketsBanksAndOraclesForSubscription)(config.env);
79
- marketIndexes = marketIndexes ? marketIndexes : envMarketIndexes;
80
- bankIndexes = bankIndexes ? bankIndexes : envBankIndexes;
90
+ const { perpMarketIndexes: envPerpMarketIndexes, spotMarketIndexes: envSpotMarketIndexes, oracleInfos: envOralceInfos, } = (0, config_1.getMarketsAndOraclesForSubscription)(config.env);
91
+ perpMarketIndexes = perpMarketIndexes
92
+ ? perpMarketIndexes
93
+ : envPerpMarketIndexes;
94
+ spotMarketIndexes = spotMarketIndexes
95
+ ? spotMarketIndexes
96
+ : envSpotMarketIndexes;
81
97
  oracleInfos = oracleInfos ? oracleInfos : envOralceInfos;
82
98
  }
83
- if (((_d = config.accountSubscription) === null || _d === void 0 ? void 0 : _d.type) === 'polling') {
84
- this.accountSubscriber = new pollingClearingHouseAccountSubscriber_1.PollingClearingHouseAccountSubscriber(this.program, config.accountSubscription.accountLoader, marketIndexes !== null && marketIndexes !== void 0 ? marketIndexes : [], bankIndexes !== null && bankIndexes !== void 0 ? bankIndexes : [], oracleInfos !== null && oracleInfos !== void 0 ? oracleInfos : []);
99
+ if (((_e = config.accountSubscription) === null || _e === void 0 ? void 0 : _e.type) === 'polling') {
100
+ this.accountSubscriber = new pollingClearingHouseAccountSubscriber_1.PollingClearingHouseAccountSubscriber(this.program, config.accountSubscription.accountLoader, perpMarketIndexes !== null && perpMarketIndexes !== void 0 ? perpMarketIndexes : [], spotMarketIndexes !== null && spotMarketIndexes !== void 0 ? spotMarketIndexes : [], oracleInfos !== null && oracleInfos !== void 0 ? oracleInfos : []);
85
101
  }
86
102
  else {
87
- this.accountSubscriber = new webSocketClearingHouseAccountSubscriber_1.WebSocketClearingHouseAccountSubscriber(this.program, (_e = config.marketIndexes) !== null && _e !== void 0 ? _e : [], (_f = config.bankIndexes) !== null && _f !== void 0 ? _f : [], (_g = config.oracleInfos) !== null && _g !== void 0 ? _g : []);
103
+ this.accountSubscriber = new webSocketClearingHouseAccountSubscriber_1.WebSocketClearingHouseAccountSubscriber(this.program, (_f = config.perpMarketIndexes) !== null && _f !== void 0 ? _f : [], (_g = config.spotMarketIndexes) !== null && _g !== void 0 ? _g : [], (_h = config.oracleInfos) !== null && _h !== void 0 ? _h : []);
88
104
  }
89
105
  this.eventEmitter = this.accountSubscriber.eventEmitter;
90
- this.txSender = new retryTxSender_1.RetryTxSender(this.provider, (_h = config.txSenderConfig) === null || _h === void 0 ? void 0 : _h.timeout, (_j = config.txSenderConfig) === null || _j === void 0 ? void 0 : _j.retrySleep, (_k = config.txSenderConfig) === null || _k === void 0 ? void 0 : _k.additionalConnections);
106
+ this.txSender = new retryTxSender_1.RetryTxSender(this.provider, (_j = config.txSenderConfig) === null || _j === void 0 ? void 0 : _j.timeout, (_k = config.txSenderConfig) === null || _k === void 0 ? void 0 : _k.retrySleep, (_l = config.txSenderConfig) === null || _l === void 0 ? void 0 : _l.additionalConnections);
91
107
  }
92
108
  get isSubscribed() {
93
109
  return this._isSubscribed && this.accountSubscriber.isSubscribed;
@@ -102,7 +118,7 @@ class ClearingHouse {
102
118
  }
103
119
  }
104
120
  createUser(userId, accountSubscriptionConfig) {
105
- const userAccountPublicKey = (0, pda_1.getUserAccountPublicKeySync)(this.program.programId, this.wallet.publicKey, userId);
121
+ const userAccountPublicKey = (0, pda_1.getUserAccountPublicKeySync)(this.program.programId, this.authority, userId);
106
122
  return new clearingHouseUser_1.ClearingHouseUser({
107
123
  clearingHouse: this,
108
124
  userAccountPublicKey,
@@ -111,6 +127,9 @@ class ClearingHouse {
111
127
  }
112
128
  async subscribe() {
113
129
  const subscribePromises = this.subscribeUsers().concat(this.accountSubscriber.subscribe());
130
+ if (this.userStats !== undefined) {
131
+ subscribePromises.concat(this.userStats.subscribe());
132
+ }
114
133
  this.isSubscribed = (await Promise.all(subscribePromises)).reduce((success, prevSuccess) => success && prevSuccess);
115
134
  return this.isSubscribed;
116
135
  }
@@ -121,12 +140,19 @@ class ClearingHouse {
121
140
  * Forces the accountSubscriber to fetch account updates from rpc
122
141
  */
123
142
  async fetchAccounts() {
124
- await Promise.all([...this.users.values()]
143
+ const promises = [...this.users.values()]
125
144
  .map((user) => user.fetchAccounts())
126
- .concat(this.accountSubscriber.fetch()));
145
+ .concat(this.accountSubscriber.fetch());
146
+ if (this.userStats) {
147
+ promises.concat(this.userStats.fetchAccounts());
148
+ }
149
+ await Promise.all(promises);
127
150
  }
128
151
  async unsubscribe() {
129
152
  const unsubscribePromises = this.unsubscribeUsers().concat(this.accountSubscriber.unsubscribe());
153
+ if (this.userStats !== undefined) {
154
+ unsubscribePromises.concat(this.userStats.unsubscribe());
155
+ }
130
156
  await Promise.all(unsubscribePromises);
131
157
  this.isSubscribed = false;
132
158
  }
@@ -140,30 +166,43 @@ class ClearingHouse {
140
166
  this.statePublicKey = await (0, pda_1.getClearingHouseStateAccountPublicKey)(this.program.programId);
141
167
  return this.statePublicKey;
142
168
  }
169
+ getSignerPublicKey() {
170
+ if (this.signerPublicKey) {
171
+ return this.signerPublicKey;
172
+ }
173
+ this.signerPublicKey = (0, pda_1.getClearingHouseSignerPublicKey)(this.program.programId);
174
+ return this.signerPublicKey;
175
+ }
143
176
  getStateAccount() {
144
177
  return this.accountSubscriber.getStateAccountAndSlot().data;
145
178
  }
146
- getMarketAccount(marketIndex) {
179
+ getPerpMarketAccount(marketIndex) {
147
180
  var _a;
148
- marketIndex = marketIndex instanceof anchor_1.BN ? marketIndex : new anchor_1.BN(marketIndex);
149
181
  return (_a = this.accountSubscriber.getMarketAccountAndSlot(marketIndex)) === null || _a === void 0 ? void 0 : _a.data;
150
182
  }
151
- getMarketAccounts() {
183
+ getPerpMarketAccounts() {
152
184
  return this.accountSubscriber
153
185
  .getMarketAccountsAndSlots()
154
186
  .map((value) => value.data);
155
187
  }
156
- getBankAccount(bankIndex) {
157
- bankIndex = bankIndex instanceof anchor_1.BN ? bankIndex : new anchor_1.BN(bankIndex);
158
- return this.accountSubscriber.getBankAccountAndSlot(bankIndex).data;
188
+ getSpotMarketAccount(marketIndex) {
189
+ return this.accountSubscriber.getSpotMarketAccountAndSlot(marketIndex).data;
190
+ }
191
+ getSpotMarketAccounts() {
192
+ return this.accountSubscriber
193
+ .getSpotMarketAccountsAndSlots()
194
+ .map((value) => value.data);
159
195
  }
160
- getQuoteAssetBankAccount() {
161
- return this.accountSubscriber.getBankAccountAndSlot(numericConstants_1.QUOTE_ASSET_BANK_INDEX)
162
- .data;
196
+ getQuoteSpotMarketAccount() {
197
+ return this.accountSubscriber.getSpotMarketAccountAndSlot(numericConstants_1.QUOTE_SPOT_MARKET_INDEX).data;
163
198
  }
164
199
  getOraclePriceDataAndSlot(oraclePublicKey) {
165
200
  return this.accountSubscriber.getOraclePriceDataAndSlot(oraclePublicKey);
166
201
  }
202
+ async getSerumV3FulfillmentConfig(serumMarket) {
203
+ const address = await (0, pda_1.getSerumFulfillmentConfigPublicKey)(this.program.programId, serumMarket);
204
+ return (await this.program.account.serumV3FulfillmentConfig.fetch(address));
205
+ }
167
206
  /**
168
207
  * Update the wallet to use for clearing house transactions and linked user account
169
208
  * @param newWallet
@@ -178,6 +217,7 @@ class ClearingHouse {
178
217
  this.wallet = newWallet;
179
218
  this.provider = newProvider;
180
219
  this.program = newProgram;
220
+ this.authority = newWallet.publicKey;
181
221
  if (this.isSubscribed) {
182
222
  await Promise.all(this.unsubscribeUsers());
183
223
  }
@@ -187,6 +227,7 @@ class ClearingHouse {
187
227
  await Promise.all(this.subscribeUsers());
188
228
  }
189
229
  this.activeUserId = activeUserId;
230
+ this.userStatsAccountPublicKey = undefined;
190
231
  }
191
232
  async switchActiveUser(userId) {
192
233
  this.activeUserId = userId;
@@ -199,27 +240,96 @@ class ClearingHouse {
199
240
  await user.subscribe();
200
241
  this.users.set(userId, user);
201
242
  }
202
- async initializeUserAccount(userId = 0, name = userName_1.DEFAULT_USER_NAME) {
203
- const [userAccountPublicKey, initializeUserAccountIx] = await this.getInitializeUserInstructions(userId, name);
204
- const tx = new web3_js_1.Transaction().add(initializeUserAccountIx);
243
+ async initializeUserAccount(userId = 0, name = userName_1.DEFAULT_USER_NAME, referrerInfo) {
244
+ const [userAccountPublicKey, initializeUserAccountIx] = await this.getInitializeUserInstructions(userId, name, referrerInfo);
245
+ const tx = new web3_js_1.Transaction();
246
+ if (userId === 0) {
247
+ // not the safest assumption, can explicitly check if user stats account exists if it causes problems
248
+ tx.add(await this.getInitializeUserStatsIx());
249
+ }
250
+ tx.add(initializeUserAccountIx);
205
251
  const { txSig } = await this.txSender.send(tx, [], this.opts);
206
252
  return [txSig, userAccountPublicKey];
207
253
  }
208
- async getInitializeUserInstructions(userId = 0, name = userName_1.DEFAULT_USER_NAME) {
254
+ async getInitializeUserInstructions(userId = 0, name = userName_1.DEFAULT_USER_NAME, referrerInfo) {
209
255
  const userAccountPublicKey = await (0, pda_1.getUserAccountPublicKey)(this.program.programId, this.wallet.publicKey, userId);
256
+ const remainingAccounts = new Array();
257
+ if (referrerInfo !== undefined) {
258
+ remainingAccounts.push({
259
+ pubkey: referrerInfo.referrer,
260
+ isWritable: true,
261
+ isSigner: false,
262
+ });
263
+ remainingAccounts.push({
264
+ pubkey: referrerInfo.referrerStats,
265
+ isWritable: true,
266
+ isSigner: false,
267
+ });
268
+ }
210
269
  const nameBuffer = (0, userName_1.encodeName)(name);
211
270
  const initializeUserAccountIx = await this.program.instruction.initializeUser(userId, nameBuffer, {
212
271
  accounts: {
213
272
  user: userAccountPublicKey,
273
+ userStats: this.getUserStatsAccountPublicKey(),
214
274
  authority: this.wallet.publicKey,
215
275
  payer: this.wallet.publicKey,
216
276
  rent: anchor.web3.SYSVAR_RENT_PUBKEY,
217
277
  systemProgram: anchor.web3.SystemProgram.programId,
218
278
  state: await this.getStatePublicKey(),
219
279
  },
280
+ remainingAccounts,
220
281
  });
221
282
  return [userAccountPublicKey, initializeUserAccountIx];
222
283
  }
284
+ async getInitializeUserStatsIx() {
285
+ return await this.program.instruction.initializeUserStats({
286
+ accounts: {
287
+ userStats: this.getUserStatsAccountPublicKey(),
288
+ authority: this.wallet.publicKey,
289
+ payer: this.wallet.publicKey,
290
+ rent: anchor.web3.SYSVAR_RENT_PUBKEY,
291
+ systemProgram: anchor.web3.SystemProgram.programId,
292
+ state: await this.getStatePublicKey(),
293
+ },
294
+ });
295
+ }
296
+ async updateUserName(name, userId = 0) {
297
+ const nameBuffer = (0, userName_1.encodeName)(name);
298
+ return await this.program.rpc.updateUserName(userId, nameBuffer, {
299
+ accounts: {
300
+ user: await this.getUserAccountPublicKey(),
301
+ authority: this.wallet.publicKey,
302
+ },
303
+ });
304
+ }
305
+ async updateUserCustomMarginRatio(marginRatio, userId = 0) {
306
+ return await this.program.rpc.updateUserCustomMarginRatio(userId, marginRatio, {
307
+ accounts: {
308
+ user: await this.getUserAccountPublicKey(),
309
+ authority: this.wallet.publicKey,
310
+ },
311
+ });
312
+ }
313
+ async updateUserDelegate(delegate, userId = 0) {
314
+ return await this.program.rpc.updateUserDelegate(userId, delegate, {
315
+ accounts: {
316
+ user: await this.getUserAccountPublicKey(),
317
+ authority: this.wallet.publicKey,
318
+ },
319
+ });
320
+ }
321
+ async getUserAccountsForDelegate(delegate) {
322
+ const programAccounts = await this.program.account.user.all([
323
+ {
324
+ memcmp: {
325
+ offset: 40,
326
+ /** data to match, as base-58 encoded string and limited to less than 129 bytes */
327
+ bytes: bs58_1.default.encode(delegate.toBuffer()),
328
+ },
329
+ },
330
+ ]);
331
+ return programAccounts.map((programAccount) => programAccount.account);
332
+ }
223
333
  getUser(userId) {
224
334
  userId = userId !== null && userId !== void 0 ? userId : this.activeUserId;
225
335
  if (!this.users.has(userId)) {
@@ -230,6 +340,16 @@ class ClearingHouse {
230
340
  getUsers() {
231
341
  return [...this.users.values()];
232
342
  }
343
+ getUserStats() {
344
+ return this.userStats;
345
+ }
346
+ getUserStatsAccountPublicKey() {
347
+ if (this.userStatsAccountPublicKey) {
348
+ return this.userStatsAccountPublicKey;
349
+ }
350
+ this.userStatsAccountPublicKey = (0, pda_1.getUserStatsAccountPublicKey)(this.program.programId, this.authority);
351
+ return this.userStatsAccountPublicKey;
352
+ }
233
353
  async getUserAccountPublicKey() {
234
354
  return this.getUser().userAccountPublicKey;
235
355
  }
@@ -239,14 +359,13 @@ class ClearingHouse {
239
359
  getUserAccountAndSlot(userId) {
240
360
  return this.getUser(userId).getUserAccountAndSlot();
241
361
  }
242
- getUserBankBalance(bankIndex) {
243
- const bankIndexBN = bankIndex instanceof anchor_1.BN ? bankIndex : new anchor_1.BN(bankIndex);
244
- return this.getUserAccount().bankBalances.find((bankBalance) => bankBalance.bankIndex.eq(bankIndexBN));
362
+ getSpotPosition(marketIndex) {
363
+ return this.getUserAccount().spotPositions.find((spotPosition) => spotPosition.marketIndex === marketIndex);
245
364
  }
246
365
  getQuoteAssetTokenAmount() {
247
- const bank = this.getBankAccount(numericConstants_1.QUOTE_ASSET_BANK_INDEX);
248
- const userBankBalance = this.getUserBankBalance(numericConstants_1.QUOTE_ASSET_BANK_INDEX);
249
- return (0, bankBalance_1.getTokenAmount)(userBankBalance.balance, bank, userBankBalance.balanceType);
366
+ const spotMarket = this.getSpotMarketAccount(numericConstants_1.QUOTE_SPOT_MARKET_INDEX);
367
+ const spotPosition = this.getSpotPosition(numericConstants_1.QUOTE_SPOT_MARKET_INDEX);
368
+ return (0, spotBalance_1.getTokenAmount)(spotPosition.balance, spotMarket, spotPosition.balanceType);
250
369
  }
251
370
  getRemainingAccounts(params) {
252
371
  const userAccountAndSlot = this.getUserAccountAndSlot();
@@ -255,14 +374,14 @@ class ClearingHouse {
255
374
  }
256
375
  const { data: userAccount, slot: lastUserPositionsSlot } = userAccountAndSlot;
257
376
  const oracleAccountMap = new Map();
258
- const bankAccountMap = new Map();
259
- const marketAccountMap = new Map();
377
+ const spotMarketAccountMap = new Map();
378
+ const perpMarketAccountMap = new Map();
260
379
  for (const [marketIndexNum, slot] of this.marketLastSlotCache.entries()) {
261
380
  // if cache has more recent slot than user positions account slot, add market to remaining accounts
262
381
  // otherwise remove from slot
263
382
  if (slot > lastUserPositionsSlot) {
264
- const marketAccount = this.getMarketAccount(marketIndexNum);
265
- marketAccountMap.set(marketIndexNum, {
383
+ const marketAccount = this.getPerpMarketAccount(marketIndexNum);
384
+ perpMarketAccountMap.set(marketIndexNum, {
266
385
  pubkey: marketAccount.pubkey,
267
386
  isSigner: false,
268
387
  isWritable: false,
@@ -277,15 +396,13 @@ class ClearingHouse {
277
396
  this.marketLastSlotCache.delete(marketIndexNum);
278
397
  }
279
398
  }
280
- for (const position of userAccount.positions) {
399
+ for (const position of userAccount.perpPositions) {
281
400
  if (!(0, position_1.positionIsAvailable)(position)) {
282
- const marketIndexNum = position.marketIndex.toNumber();
283
- const marketAccount = this.getMarketAccount(marketIndexNum);
284
- marketAccountMap.set(marketIndexNum, {
401
+ const marketAccount = this.getPerpMarketAccount(position.marketIndex);
402
+ perpMarketAccountMap.set(position.marketIndex, {
285
403
  pubkey: marketAccount.pubkey,
286
404
  isSigner: false,
287
- // isWritable: false, // TODO
288
- isWritable: true,
405
+ isWritable: false,
289
406
  });
290
407
  oracleAccountMap.set(marketAccount.pubkey.toString(), {
291
408
  pubkey: marketAccount.amm.oracle,
@@ -294,9 +411,22 @@ class ClearingHouse {
294
411
  });
295
412
  }
296
413
  }
297
- if (params.writableMarketIndex) {
298
- const marketAccount = this.getMarketAccount(params.writableMarketIndex.toNumber());
299
- marketAccountMap.set(params.writableMarketIndex.toNumber(), {
414
+ if (params.readablePerpMarketIndex !== undefined) {
415
+ const marketAccount = this.getPerpMarketAccount(params.readablePerpMarketIndex);
416
+ perpMarketAccountMap.set(params.readablePerpMarketIndex, {
417
+ pubkey: marketAccount.pubkey,
418
+ isSigner: false,
419
+ isWritable: false,
420
+ });
421
+ oracleAccountMap.set(marketAccount.amm.oracle.toString(), {
422
+ pubkey: marketAccount.amm.oracle,
423
+ isSigner: false,
424
+ isWritable: false,
425
+ });
426
+ }
427
+ if (params.writablePerpMarketIndex !== undefined) {
428
+ const marketAccount = this.getPerpMarketAccount(params.writablePerpMarketIndex);
429
+ perpMarketAccountMap.set(params.writablePerpMarketIndex, {
300
430
  pubkey: marketAccount.pubkey,
301
431
  isSigner: false,
302
432
  isWritable: true,
@@ -307,33 +437,48 @@ class ClearingHouse {
307
437
  isWritable: false,
308
438
  });
309
439
  }
310
- for (const userBankBalance of userAccount.bankBalances) {
311
- if (!userBankBalance.balance.eq(numericConstants_1.ZERO)) {
312
- const bankAccount = this.getBankAccount(userBankBalance.bankIndex);
313
- bankAccountMap.set(userBankBalance.bankIndex.toNumber(), {
314
- pubkey: bankAccount.pubkey,
440
+ for (const spotPosition of userAccount.spotPositions) {
441
+ if (!(0, spotPosition_1.isSpotPositionAvailable)(spotPosition)) {
442
+ const spotMarketAccount = this.getSpotMarketAccount(spotPosition.marketIndex);
443
+ spotMarketAccountMap.set(spotPosition.marketIndex, {
444
+ pubkey: spotMarketAccount.pubkey,
315
445
  isSigner: false,
316
446
  isWritable: false,
317
447
  });
318
- if (!bankAccount.bankIndex.eq(numericConstants_1.ZERO)) {
319
- oracleAccountMap.set(bankAccount.oracle.toString(), {
320
- pubkey: bankAccount.oracle,
448
+ if (spotMarketAccount.marketIndex !== 0) {
449
+ oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
450
+ pubkey: spotMarketAccount.oracle,
321
451
  isSigner: false,
322
452
  isWritable: false,
323
453
  });
324
454
  }
325
455
  }
326
456
  }
327
- if (params.writableBankIndex) {
328
- const bankAccount = this.getBankAccount(params.writableBankIndex);
329
- bankAccountMap.set(params.writableBankIndex.toNumber(), {
330
- pubkey: bankAccount.pubkey,
457
+ if (params.readableSpotMarketIndex !== undefined) {
458
+ const spotMarketAccount = this.getSpotMarketAccount(params.readableSpotMarketIndex);
459
+ spotMarketAccountMap.set(params.readableSpotMarketIndex, {
460
+ pubkey: spotMarketAccount.pubkey,
461
+ isSigner: false,
462
+ isWritable: false,
463
+ });
464
+ if (spotMarketAccount.marketIndex !== 0) {
465
+ oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
466
+ pubkey: spotMarketAccount.oracle,
467
+ isSigner: false,
468
+ isWritable: false,
469
+ });
470
+ }
471
+ }
472
+ if (params.writableSpotMarketIndex !== undefined) {
473
+ const spotMarketAccount = this.getSpotMarketAccount(params.writableSpotMarketIndex);
474
+ spotMarketAccountMap.set(params.writableSpotMarketIndex, {
475
+ pubkey: spotMarketAccount.pubkey,
331
476
  isSigner: false,
332
477
  isWritable: true,
333
478
  });
334
- if (!bankAccount.bankIndex.eq(numericConstants_1.ZERO)) {
335
- oracleAccountMap.set(bankAccount.oracle.toString(), {
336
- pubkey: bankAccount.oracle,
479
+ if (spotMarketAccount.marketIndex !== 0) {
480
+ oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
481
+ pubkey: spotMarketAccount.oracle,
337
482
  isSigner: false,
338
483
  isWritable: false,
339
484
  });
@@ -341,8 +486,8 @@ class ClearingHouse {
341
486
  }
342
487
  return [
343
488
  ...oracleAccountMap.values(),
344
- ...bankAccountMap.values(),
345
- ...marketAccountMap.values(),
489
+ ...spotMarketAccountMap.values(),
490
+ ...perpMarketAccountMap.values(),
346
491
  ];
347
492
  }
348
493
  getOrder(orderId) {
@@ -354,38 +499,63 @@ class ClearingHouse {
354
499
  var _a;
355
500
  return (_a = this.getUserAccount()) === null || _a === void 0 ? void 0 : _a.orders.find((order) => order.userOrderId === userOrderId);
356
501
  }
357
- async deposit(amount, bankIndex, collateralAccountPublicKey, userId, reduceOnly = false) {
358
- const depositCollateralIx = await this.getDepositInstruction(amount, bankIndex, collateralAccountPublicKey, userId, reduceOnly, true);
359
- const tx = new web3_js_1.Transaction().add(depositCollateralIx);
360
- const { txSig } = await this.txSender.send(tx);
502
+ async deposit(amount, marketIndex, collateralAccountPublicKey, userId, reduceOnly = false) {
503
+ const tx = new web3_js_1.Transaction();
504
+ const additionalSigners = [];
505
+ const spotMarketAccount = this.getSpotMarketAccount(marketIndex);
506
+ const isSolMarket = spotMarketAccount.mint.equals(spotMarkets_1.WRAPPED_SOL_MINT);
507
+ const authority = this.authority;
508
+ const createWSOLTokenAccount = isSolMarket && collateralAccountPublicKey.equals(authority);
509
+ if (createWSOLTokenAccount) {
510
+ const { ixs, signers, pubkey } = await this.getWrappedSolAccountCreationIxs(amount, true);
511
+ collateralAccountPublicKey = pubkey;
512
+ ixs.forEach((ix) => {
513
+ tx.add(ix);
514
+ });
515
+ signers.forEach((signer) => additionalSigners.push(signer));
516
+ }
517
+ const depositCollateralIx = await this.getDepositInstruction(amount, marketIndex, collateralAccountPublicKey, userId, reduceOnly, true);
518
+ tx.add(depositCollateralIx);
519
+ // Close the wrapped sol account at the end of the transaction
520
+ if (createWSOLTokenAccount) {
521
+ tx.add(spl_token_1.Token.createCloseAccountInstruction(spl_token_1.TOKEN_PROGRAM_ID, collateralAccountPublicKey, authority, authority, []));
522
+ }
523
+ const { txSig } = await this.txSender.send(tx, additionalSigners, this.opts);
361
524
  return txSig;
362
525
  }
363
- async getDepositInstruction(amount, bankIndex, userTokenAccount, userId, reduceOnly = false, userInitialized = true) {
526
+ async getDepositInstruction(amount, marketIndex, userTokenAccount, userId, reduceOnly = false, userInitialized = true) {
364
527
  const userAccountPublicKey = userId
365
- ? await (0, pda_1.getUserAccountPublicKey)(this.program.programId, this.wallet.publicKey, userId)
528
+ ? await (0, pda_1.getUserAccountPublicKey)(this.program.programId, this.authority, userId)
366
529
  : await this.getUserAccountPublicKey();
367
530
  let remainingAccounts = [];
368
531
  if (userInitialized) {
369
532
  remainingAccounts = this.getRemainingAccounts({
370
- writableBankIndex: bankIndex,
533
+ writableSpotMarketIndex: marketIndex,
371
534
  });
372
535
  }
373
536
  else {
374
- remainingAccounts = [
375
- {
376
- pubkey: this.getBankAccount(bankIndex).pubkey,
537
+ const spotMarketAccount = this.getSpotMarketAccount(marketIndex);
538
+ if (!spotMarketAccount.oracle.equals(web3_js_1.PublicKey.default)) {
539
+ remainingAccounts.push({
540
+ pubkey: spotMarketAccount.oracle,
377
541
  isSigner: false,
378
- isWritable: true,
379
- },
380
- ];
542
+ isWritable: false,
543
+ });
544
+ }
545
+ remainingAccounts.push({
546
+ pubkey: spotMarketAccount.pubkey,
547
+ isSigner: false,
548
+ isWritable: true,
549
+ });
381
550
  }
382
- const bank = this.getBankAccount(bankIndex);
383
- return await this.program.instruction.deposit(bankIndex, amount, reduceOnly, {
551
+ const spotMarketAccount = this.getSpotMarketAccount(marketIndex);
552
+ return await this.program.instruction.deposit(marketIndex, amount, reduceOnly, {
384
553
  accounts: {
385
554
  state: await this.getStatePublicKey(),
386
- bank: bank.pubkey,
387
- bankVault: bank.vault,
555
+ spotMarket: spotMarketAccount.pubkey,
556
+ spotMarketVault: spotMarketAccount.vault,
388
557
  user: userAccountPublicKey,
558
+ userStats: this.getUserStatsAccountPublicKey(),
389
559
  userTokenAccount: userTokenAccount,
390
560
  authority: this.wallet.publicKey,
391
561
  tokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
@@ -393,55 +563,140 @@ class ClearingHouse {
393
563
  remainingAccounts,
394
564
  });
395
565
  }
566
+ async checkIfAccountExists(account) {
567
+ try {
568
+ const accountInfo = await this.connection.getAccountInfo(account);
569
+ return accountInfo != null;
570
+ }
571
+ catch (e) {
572
+ // Doesn't already exist
573
+ return false;
574
+ }
575
+ }
576
+ async getWrappedSolAccountCreationIxs(amount, isDeposit) {
577
+ const wrappedSolAccount = new web3_js_1.Keypair();
578
+ const result = {
579
+ ixs: [],
580
+ signers: [],
581
+ pubkey: wrappedSolAccount.publicKey,
582
+ };
583
+ const rentSpaceLamports = new anchor_1.BN(web3_js_1.LAMPORTS_PER_SOL / 100);
584
+ const lamports = isDeposit
585
+ ? amount.add(rentSpaceLamports)
586
+ : rentSpaceLamports;
587
+ const authority = this.wallet.publicKey;
588
+ result.ixs.push(web3_js_1.SystemProgram.createAccount({
589
+ fromPubkey: authority,
590
+ newAccountPubkey: wrappedSolAccount.publicKey,
591
+ lamports: lamports.toNumber(),
592
+ space: 165,
593
+ programId: spl_token_1.TOKEN_PROGRAM_ID,
594
+ }));
595
+ result.ixs.push(spl_token_1.Token.createInitAccountInstruction(spl_token_1.TOKEN_PROGRAM_ID, spotMarkets_1.WRAPPED_SOL_MINT, wrappedSolAccount.publicKey, authority));
596
+ result.signers.push(wrappedSolAccount);
597
+ return result;
598
+ }
599
+ getAssociatedTokenAccountCreationIx(tokenMintAddress, associatedTokenAddress) {
600
+ const createAssociatedAccountIx = spl_token_1.Token.createAssociatedTokenAccountInstruction(spl_token_1.ASSOCIATED_TOKEN_PROGRAM_ID, spl_token_1.TOKEN_PROGRAM_ID, tokenMintAddress, associatedTokenAddress, this.wallet.publicKey, this.wallet.publicKey);
601
+ return createAssociatedAccountIx;
602
+ }
396
603
  /**
397
604
  * Creates the Clearing House User account for a user, and deposits some initial collateral
398
- * @param userId
399
- * @param name
400
605
  * @param amount
401
606
  * @param userTokenAccount
607
+ * @param marketIndex
608
+ * @param userId
609
+ * @param name
402
610
  * @param fromUserId
403
611
  * @returns
404
612
  */
405
- async initializeUserAccountAndDepositCollateral(amount, userTokenAccount, bankIndex = new anchor_1.BN(0), userId = 0, name = userName_1.DEFAULT_USER_NAME, fromUserId) {
406
- const [userAccountPublicKey, initializeUserAccountIx] = await this.getInitializeUserInstructions(userId, name);
613
+ async initializeUserAccountAndDepositCollateral(amount, userTokenAccount, marketIndex = 0, userId = 0, name = userName_1.DEFAULT_USER_NAME, fromUserId, referrerInfo) {
614
+ const [userAccountPublicKey, initializeUserAccountIx] = await this.getInitializeUserInstructions(userId, name, referrerInfo);
615
+ const additionalSigners = [];
616
+ const spotMarket = this.getSpotMarketAccount(marketIndex);
617
+ const isSolMarket = spotMarket.mint.equals(spotMarkets_1.WRAPPED_SOL_MINT);
618
+ const tx = new web3_js_1.Transaction();
619
+ const authority = this.wallet.publicKey;
620
+ const createWSOLTokenAccount = isSolMarket && userTokenAccount.equals(authority);
621
+ if (createWSOLTokenAccount) {
622
+ const { ixs: startIxs, signers, pubkey, } = await this.getWrappedSolAccountCreationIxs(amount, true);
623
+ userTokenAccount = pubkey;
624
+ startIxs.forEach((ix) => {
625
+ tx.add(ix);
626
+ });
627
+ signers.forEach((signer) => additionalSigners.push(signer));
628
+ }
407
629
  const depositCollateralIx = fromUserId != null
408
- ? await this.getTransferDepositIx(amount, bankIndex, fromUserId, userId)
409
- : await this.getDepositInstruction(amount, bankIndex, userTokenAccount, userId, false, false);
410
- const tx = new web3_js_1.Transaction()
411
- .add(initializeUserAccountIx)
412
- .add(depositCollateralIx);
413
- const { txSig } = await this.txSender.send(tx, []);
630
+ ? await this.getTransferDepositIx(amount, marketIndex, fromUserId, userId)
631
+ : await this.getDepositInstruction(amount, marketIndex, userTokenAccount, userId, false, false);
632
+ if (userId === 0) {
633
+ tx.add(await this.getInitializeUserStatsIx());
634
+ }
635
+ tx.add(initializeUserAccountIx).add(depositCollateralIx);
636
+ // Close the wrapped sol account at the end of the transaction
637
+ if (createWSOLTokenAccount) {
638
+ tx.add(spl_token_1.Token.createCloseAccountInstruction(spl_token_1.TOKEN_PROGRAM_ID, userTokenAccount, authority, authority, []));
639
+ }
640
+ const { txSig } = await this.txSender.send(tx, additionalSigners, this.opts);
414
641
  return [txSig, userAccountPublicKey];
415
642
  }
416
- async initializeUserAccountForDevnet(userId = 0, name = userName_1.DEFAULT_USER_NAME, mockUSDCFaucet, amount) {
417
- const [associateTokenPublicKey, createAssociatedAccountIx, mintToIx] = await mockUSDCFaucet.createAssociatedTokenAccountAndMintToInstructions(this.wallet.publicKey, amount);
418
- const [userAccountPublicKey, initializeUserAccountIx] = await this.getInitializeUserInstructions(userId, name);
419
- const depositCollateralIx = await this.getDepositInstruction(amount, new anchor_1.BN(0), associateTokenPublicKey, userId, false, false);
420
- const tx = new web3_js_1.Transaction()
421
- .add(createAssociatedAccountIx)
422
- .add(mintToIx)
423
- .add(initializeUserAccountIx)
424
- .add(depositCollateralIx);
643
+ async initializeUserAccountForDevnet(userId = 0, name = userName_1.DEFAULT_USER_NAME, marketIndex, tokenFaucet, amount, referrerInfo) {
644
+ const [associateTokenPublicKey, createAssociatedAccountIx, mintToIx] = await tokenFaucet.createAssociatedTokenAccountAndMintToInstructions(this.wallet.publicKey, amount);
645
+ const [userAccountPublicKey, initializeUserAccountIx] = await this.getInitializeUserInstructions(userId, name, referrerInfo);
646
+ const depositCollateralIx = await this.getDepositInstruction(amount, marketIndex, associateTokenPublicKey, userId, false, false);
647
+ const tx = new web3_js_1.Transaction().add(createAssociatedAccountIx).add(mintToIx);
648
+ if (userId === 0) {
649
+ tx.add(await this.getInitializeUserStatsIx());
650
+ }
651
+ tx.add(initializeUserAccountIx).add(depositCollateralIx);
425
652
  const txSig = await this.program.provider.sendAndConfirm(tx, []);
426
653
  return [txSig, userAccountPublicKey];
427
654
  }
428
- async withdraw(amount, bankIndex, userTokenAccount, reduceOnly = false) {
429
- const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getWithdrawIx(amount, bankIndex, userTokenAccount, reduceOnly)), [], this.opts);
655
+ async withdraw(amount, marketIndex, userTokenAccount, reduceOnly = false) {
656
+ const tx = new web3_js_1.Transaction();
657
+ const additionalSigners = [];
658
+ const spotMarketAccount = this.getSpotMarketAccount(marketIndex);
659
+ const isSolMarket = spotMarketAccount.mint.equals(spotMarkets_1.WRAPPED_SOL_MINT);
660
+ const authority = this.wallet.publicKey;
661
+ const createWSOLTokenAccount = isSolMarket && userTokenAccount.equals(authority);
662
+ if (createWSOLTokenAccount) {
663
+ const { ixs, signers, pubkey } = await this.getWrappedSolAccountCreationIxs(amount, false);
664
+ userTokenAccount = pubkey;
665
+ ixs.forEach((ix) => {
666
+ tx.add(ix);
667
+ });
668
+ signers.forEach((signer) => additionalSigners.push(signer));
669
+ }
670
+ else {
671
+ const accountExists = await this.checkIfAccountExists(userTokenAccount);
672
+ if (!accountExists) {
673
+ const createAssociatedTokenAccountIx = this.getAssociatedTokenAccountCreationIx(spotMarketAccount.mint, userTokenAccount);
674
+ tx.add(createAssociatedTokenAccountIx);
675
+ }
676
+ }
677
+ const withdrawCollateral = await this.getWithdrawIx(amount, spotMarketAccount.marketIndex, userTokenAccount, reduceOnly);
678
+ tx.add(withdrawCollateral);
679
+ // Close the wrapped sol account at the end of the transaction
680
+ if (createWSOLTokenAccount) {
681
+ tx.add(spl_token_1.Token.createCloseAccountInstruction(spl_token_1.TOKEN_PROGRAM_ID, userTokenAccount, authority, authority, []));
682
+ }
683
+ const { txSig } = await this.txSender.send(tx, additionalSigners, this.opts);
430
684
  return txSig;
431
685
  }
432
- async getWithdrawIx(amount, bankIndex, userTokenAccount, reduceOnly = false) {
686
+ async getWithdrawIx(amount, marketIndex, userTokenAccount, reduceOnly = false) {
433
687
  const userAccountPublicKey = await this.getUserAccountPublicKey();
434
688
  const remainingAccounts = this.getRemainingAccounts({
435
- writableBankIndex: bankIndex,
689
+ writableSpotMarketIndex: marketIndex,
436
690
  });
437
- const bank = this.getBankAccount(bankIndex);
438
- return await this.program.instruction.withdraw(bankIndex, amount, reduceOnly, {
691
+ const spotMarketAccount = this.getSpotMarketAccount(marketIndex);
692
+ return await this.program.instruction.withdraw(marketIndex, amount, reduceOnly, {
439
693
  accounts: {
440
694
  state: await this.getStatePublicKey(),
441
- bank: bank.pubkey,
442
- bankVault: bank.vault,
443
- bankVaultAuthority: bank.vaultAuthority,
695
+ spotMarket: spotMarketAccount.pubkey,
696
+ spotMarketVault: spotMarketAccount.vault,
697
+ clearingHouseSigner: this.getSignerPublicKey(),
444
698
  user: userAccountPublicKey,
699
+ userStats: this.getUserStatsAccountPublicKey(),
445
700
  userTokenAccount: userTokenAccount,
446
701
  authority: this.wallet.publicKey,
447
702
  tokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
@@ -449,55 +704,175 @@ class ClearingHouse {
449
704
  remainingAccounts,
450
705
  });
451
706
  }
452
- async transferDeposit(amount, bankIndex, fromUserId, toUserId) {
453
- const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getTransferDepositIx(amount, bankIndex, fromUserId, toUserId)), [], this.opts);
707
+ async transferDeposit(amount, marketIndex, fromUserId, toUserId) {
708
+ const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getTransferDepositIx(amount, marketIndex, fromUserId, toUserId)), [], this.opts);
454
709
  return txSig;
455
710
  }
456
- async getTransferDepositIx(amount, bankIndex, fromUserId, toUserId) {
711
+ async getTransferDepositIx(amount, marketIndex, fromUserId, toUserId) {
457
712
  const fromUser = await (0, pda_1.getUserAccountPublicKey)(this.program.programId, this.wallet.publicKey, fromUserId);
458
713
  const toUser = await (0, pda_1.getUserAccountPublicKey)(this.program.programId, this.wallet.publicKey, toUserId);
459
714
  const remainingAccounts = this.getRemainingAccounts({
460
- writableBankIndex: bankIndex,
715
+ writableSpotMarketIndex: marketIndex,
461
716
  });
462
- return await this.program.instruction.transferDeposit(bankIndex, amount, {
717
+ return await this.program.instruction.transferDeposit(marketIndex, amount, {
463
718
  accounts: {
464
719
  authority: this.wallet.publicKey,
465
720
  fromUser,
466
721
  toUser,
722
+ userStats: this.getUserStatsAccountPublicKey(),
467
723
  state: await this.getStatePublicKey(),
468
724
  },
469
725
  remainingAccounts,
470
726
  });
471
727
  }
472
- async updateBankCumulativeInterest(bankIndex) {
473
- const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.updateBankCumulativeInterestIx(bankIndex)), [], this.opts);
728
+ async updateSpotMarketCumulativeInterest(marketIndex) {
729
+ const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.updateSpotMarketCumulativeInterestIx(marketIndex)), [], this.opts);
730
+ return txSig;
731
+ }
732
+ async updateSpotMarketCumulativeInterestIx(marketIndex) {
733
+ const spotMarket = this.getSpotMarketAccount(marketIndex);
734
+ return await this.program.instruction.updateSpotMarketCumulativeInterest({
735
+ accounts: {
736
+ spotMarket: spotMarket.pubkey,
737
+ },
738
+ });
739
+ }
740
+ async settleLP(settleeUserAccountPublicKey, marketIndex) {
741
+ const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.settleLPIx(settleeUserAccountPublicKey, marketIndex)), [], this.opts);
742
+ return txSig;
743
+ }
744
+ async settleLPIx(settleeUserAccountPublicKey, marketIndex) {
745
+ const settleeUserAccount = (await this.program.account.user.fetch(settleeUserAccountPublicKey));
746
+ const userPositions = settleeUserAccount.perpPositions;
747
+ const remainingAccounts = [];
748
+ let foundMarket = false;
749
+ for (const position of userPositions) {
750
+ if (!(0, position_1.positionIsAvailable)(position)) {
751
+ const marketPublicKey = await (0, pda_1.getMarketPublicKey)(this.program.programId, position.marketIndex);
752
+ remainingAccounts.push({
753
+ pubkey: marketPublicKey,
754
+ isWritable: true,
755
+ isSigner: false,
756
+ });
757
+ if (marketIndex === position.marketIndex) {
758
+ foundMarket = true;
759
+ }
760
+ }
761
+ }
762
+ if (!foundMarket) {
763
+ console.log('Warning: lp is not in the market specified -- tx will likely fail');
764
+ }
765
+ return this.program.instruction.settleLp(marketIndex, {
766
+ accounts: {
767
+ state: await this.getStatePublicKey(),
768
+ user: settleeUserAccountPublicKey,
769
+ },
770
+ remainingAccounts: remainingAccounts,
771
+ });
772
+ }
773
+ async removeLiquidity(marketIndex, sharesToBurn) {
774
+ const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getRemoveLiquidityIx(marketIndex, sharesToBurn)), [], this.opts);
775
+ return txSig;
776
+ }
777
+ async getRemoveLiquidityIx(marketIndex, sharesToBurn) {
778
+ const userAccountPublicKey = await this.getUserAccountPublicKey();
779
+ const remainingAccounts = this.getRemainingAccounts({
780
+ writablePerpMarketIndex: marketIndex,
781
+ });
782
+ if (sharesToBurn == undefined) {
783
+ const userAccount = this.getUserAccount();
784
+ const perpPosition = userAccount.perpPositions.filter((position) => position.marketIndex === marketIndex)[0];
785
+ sharesToBurn = perpPosition.lpShares;
786
+ console.log('burning lp shares:', sharesToBurn.toString());
787
+ }
788
+ return this.program.instruction.removeLiquidity(sharesToBurn, marketIndex, {
789
+ accounts: {
790
+ state: await this.getStatePublicKey(),
791
+ user: userAccountPublicKey,
792
+ authority: this.wallet.publicKey,
793
+ },
794
+ remainingAccounts: remainingAccounts,
795
+ });
796
+ }
797
+ async addLiquidity(amount, marketIndex) {
798
+ const { txSig, slot } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getAddLiquidityIx(amount, marketIndex)), [], this.opts);
799
+ this.marketLastSlotCache.set(marketIndex, slot);
474
800
  return txSig;
475
801
  }
476
- async updateBankCumulativeInterestIx(bankIndex) {
477
- const bank = this.getBankAccount(bankIndex);
478
- return await this.program.instruction.updateBankCumulativeInterest({
802
+ async getAddLiquidityIx(amount, marketIndex) {
803
+ const userAccountPublicKey = await this.getUserAccountPublicKey();
804
+ const remainingAccounts = this.getRemainingAccounts({
805
+ writablePerpMarketIndex: marketIndex,
806
+ });
807
+ return this.program.instruction.addLiquidity(amount, marketIndex, {
479
808
  accounts: {
480
- bank: bank.pubkey,
809
+ state: await this.getStatePublicKey(),
810
+ user: userAccountPublicKey,
811
+ authority: this.wallet.publicKey,
481
812
  },
813
+ remainingAccounts: remainingAccounts,
482
814
  });
483
815
  }
484
816
  async openPosition(direction, amount, marketIndex, limitPrice) {
485
- return await this.placeAndTake((0, orderParams_1.getMarketOrderParams)(marketIndex, direction, numericConstants_1.ZERO, amount, false, limitPrice));
817
+ return await this.placeAndTake({
818
+ orderType: types_1.OrderType.MARKET,
819
+ marketIndex,
820
+ direction,
821
+ baseAssetAmount: amount,
822
+ price: limitPrice,
823
+ });
824
+ }
825
+ async sendSignedTx(tx) {
826
+ const { txSig } = await this.txSender.send(tx, undefined, this.opts, true);
827
+ return txSig;
828
+ }
829
+ /**
830
+ * 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.
831
+ * @param orderParams
832
+ * @param userAccountPublicKey
833
+ * @param userAccount
834
+ * @returns
835
+ */
836
+ async sendMarketOrderAndGetSignedFillTx(orderParams, userAccountPublicKey, userAccount) {
837
+ const marketIndex = orderParams.marketIndex;
838
+ const orderId = userAccount.nextOrderId;
839
+ const marketOrderTx = (0, utils_1.wrapInTx)(await this.getPlaceOrderIx(orderParams));
840
+ const fillTx = (0, utils_1.wrapInTx)(await this.getFillOrderIx(userAccountPublicKey, userAccount, {
841
+ orderId,
842
+ marketIndex,
843
+ }));
844
+ // Apply the latest blockhash to the txs so that we can sign before sending them
845
+ const currentBlockHash = (await this.connection.getLatestBlockhash('finalized')).blockhash;
846
+ marketOrderTx.recentBlockhash = currentBlockHash;
847
+ fillTx.recentBlockhash = currentBlockHash;
848
+ marketOrderTx.feePayer = userAccount.authority;
849
+ fillTx.feePayer = userAccount.authority;
850
+ const [signedMarketOrderTx, signedFillTx] = await this.provider.wallet.signAllTransactions([marketOrderTx, fillTx]);
851
+ const { txSig, slot } = await this.txSender.send(signedMarketOrderTx, [], this.opts, true);
852
+ this.marketLastSlotCache.set(orderParams.marketIndex, slot);
853
+ return { txSig, signedFillTx };
486
854
  }
487
855
  async placeOrder(orderParams) {
488
856
  const { txSig, slot } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getPlaceOrderIx(orderParams)), [], this.opts);
489
- this.marketLastSlotCache.set(orderParams.marketIndex.toNumber(), slot);
857
+ this.marketLastSlotCache.set(orderParams.marketIndex, slot);
490
858
  return txSig;
491
859
  }
860
+ getOrderParams(optionalOrderParams, marketType) {
861
+ return Object.assign({}, types_1.DefaultOrderParams, optionalOrderParams, {
862
+ marketType,
863
+ });
864
+ }
492
865
  async getPlaceOrderIx(orderParams) {
866
+ orderParams = this.getOrderParams(orderParams, types_1.MarketType.PERP);
493
867
  const userAccountPublicKey = await this.getUserAccountPublicKey();
494
868
  const remainingAccounts = this.getRemainingAccounts({
495
- writableMarketIndex: orderParams.marketIndex,
869
+ readablePerpMarketIndex: orderParams.marketIndex,
496
870
  });
497
871
  return await this.program.instruction.placeOrder(orderParams, {
498
872
  accounts: {
499
873
  state: await this.getStatePublicKey(),
500
874
  user: userAccountPublicKey,
875
+ userStats: this.getUserStatsAccountPublicKey(),
501
876
  authority: this.wallet.publicKey,
502
877
  },
503
878
  remainingAccounts,
@@ -509,13 +884,13 @@ class ClearingHouse {
509
884
  }
510
885
  async getUpdateAMMsIx(marketIndexes) {
511
886
  for (let i = marketIndexes.length; i < 5; i++) {
512
- marketIndexes.push(new anchor_1.BN(100));
887
+ marketIndexes.push(100);
513
888
  }
514
889
  const marketAccountInfos = [];
515
890
  const oracleAccountInfos = [];
516
891
  for (const marketIndex of marketIndexes) {
517
- if (!marketIndex.eq(new anchor_1.BN(100))) {
518
- const market = this.getMarketAccount(marketIndex);
892
+ if (marketIndex !== 100) {
893
+ const market = this.getPerpMarketAccount(marketIndex);
519
894
  marketAccountInfos.push({
520
895
  pubkey: market.pubkey,
521
896
  isWritable: true,
@@ -537,6 +912,41 @@ class ClearingHouse {
537
912
  remainingAccounts,
538
913
  });
539
914
  }
915
+ async settleExpiredMarket(marketIndex) {
916
+ const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getSettleExpiredMarketIx(marketIndex)), [], this.opts);
917
+ return txSig;
918
+ }
919
+ async getSettleExpiredMarketIx(marketIndex) {
920
+ const marketAccountInfos = [];
921
+ const oracleAccountInfos = [];
922
+ const spotMarketAccountInfos = [];
923
+ const market = this.getPerpMarketAccount(marketIndex);
924
+ marketAccountInfos.push({
925
+ pubkey: market.pubkey,
926
+ isWritable: true,
927
+ isSigner: false,
928
+ });
929
+ oracleAccountInfos.push({
930
+ pubkey: market.amm.oracle,
931
+ isWritable: false,
932
+ isSigner: false,
933
+ });
934
+ spotMarketAccountInfos.push({
935
+ pubkey: this.getSpotMarketAccount(numericConstants_1.QUOTE_SPOT_MARKET_INDEX).pubkey,
936
+ isSigner: false,
937
+ isWritable: true,
938
+ });
939
+ const remainingAccounts = oracleAccountInfos
940
+ .concat(spotMarketAccountInfos)
941
+ .concat(marketAccountInfos);
942
+ return await this.program.instruction.settleExpiredMarket(marketIndex, {
943
+ accounts: {
944
+ state: await this.getStatePublicKey(),
945
+ authority: this.wallet.publicKey,
946
+ },
947
+ remainingAccounts,
948
+ });
949
+ }
540
950
  async cancelOrder(orderId) {
541
951
  const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getCancelOrderIx(orderId)), [], this.opts);
542
952
  return txSig;
@@ -560,7 +970,7 @@ class ClearingHouse {
560
970
  async getCancelOrderByUserIdIx(userOrderId) {
561
971
  const userAccountPublicKey = await this.getUserAccountPublicKey();
562
972
  const order = this.getOrderByUserId(userOrderId);
563
- const oracle = this.getMarketAccount(order.marketIndex).amm.oracle;
973
+ const oracle = this.getPerpMarketAccount(order.marketIndex).amm.oracle;
564
974
  const remainingAccounts = this.getRemainingAccounts({});
565
975
  return await this.program.instruction.cancelOrderByUserId(userOrderId, {
566
976
  accounts: {
@@ -572,58 +982,92 @@ class ClearingHouse {
572
982
  remainingAccounts,
573
983
  });
574
984
  }
575
- async fillOrder(userAccountPublicKey, user, order, makerInfo) {
576
- const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getFillOrderIx(userAccountPublicKey, user, order, makerInfo)), [], this.opts);
985
+ async fillOrder(userAccountPublicKey, user, order, makerInfo, referrerInfo) {
986
+ const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getFillOrderIx(userAccountPublicKey, user, order, makerInfo, referrerInfo)), [], this.opts);
577
987
  return txSig;
578
988
  }
579
- async getFillOrderIx(userAccountPublicKey, userAccount, order, makerInfo) {
989
+ async getFillOrderIx(userAccountPublicKey, userAccount, order, makerInfo, referrerInfo) {
990
+ const userStatsPublicKey = (0, pda_1.getUserStatsAccountPublicKey)(this.program.programId, userAccount.authority);
580
991
  const fillerPublicKey = await this.getUserAccountPublicKey();
581
- const marketIndex = order.marketIndex;
582
- const marketAccount = this.getMarketAccount(marketIndex);
583
- const bankAccountInfos = [
584
- {
585
- pubkey: this.getQuoteAssetBankAccount().pubkey,
586
- isSigner: false,
587
- isWritable: true,
588
- },
589
- ];
590
- const marketAccountInfos = [
591
- {
592
- pubkey: marketAccount.pubkey,
593
- isWritable: true,
594
- isSigner: false,
595
- },
596
- ];
597
- const oracleAccountInfos = [
598
- {
599
- pubkey: marketAccount.amm.oracle,
600
- isWritable: false,
601
- isSigner: false,
602
- },
603
- ];
604
- for (const position of userAccount.positions) {
992
+ const fillerStatsPublicKey = this.getUserStatsAccountPublicKey();
993
+ const marketIndex = order
994
+ ? order.marketIndex
995
+ : userAccount.orders.find((order) => order.orderId.eq(userAccount.nextOrderId.sub(numericConstants_1.ONE))).marketIndex;
996
+ const marketAccount = this.getPerpMarketAccount(marketIndex);
997
+ const oracleAccountMap = new Map();
998
+ const spotMarketAccountMap = new Map();
999
+ const perpMarketAccountMap = new Map();
1000
+ for (const spotPosition of userAccount.spotPositions) {
1001
+ if (!(0, spotPosition_1.isSpotPositionAvailable)(spotPosition)) {
1002
+ const spotMarketAccount = this.getSpotMarketAccount(spotPosition.marketIndex);
1003
+ spotMarketAccountMap.set(spotPosition.marketIndex, {
1004
+ pubkey: spotMarketAccount.pubkey,
1005
+ isSigner: false,
1006
+ isWritable: false,
1007
+ });
1008
+ if (!spotMarketAccount.oracle.equals(web3_js_1.PublicKey.default)) {
1009
+ oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
1010
+ pubkey: spotMarketAccount.oracle,
1011
+ isSigner: false,
1012
+ isWritable: false,
1013
+ });
1014
+ }
1015
+ }
1016
+ }
1017
+ for (const position of userAccount.perpPositions) {
605
1018
  if (!(0, position_1.positionIsAvailable)(position) &&
606
- !position.marketIndex.eq(order.marketIndex)) {
607
- const market = this.getMarketAccount(position.marketIndex);
608
- marketAccountInfos.push({
1019
+ position.marketIndex !== order.marketIndex) {
1020
+ const market = this.getPerpMarketAccount(position.marketIndex);
1021
+ perpMarketAccountMap.set(position.marketIndex, {
609
1022
  pubkey: market.pubkey,
610
1023
  isWritable: false,
611
1024
  isSigner: false,
612
1025
  });
613
- oracleAccountInfos.push({
1026
+ oracleAccountMap.set(market.amm.oracle.toString(), {
614
1027
  pubkey: market.amm.oracle,
615
1028
  isWritable: false,
616
1029
  isSigner: false,
617
1030
  });
618
1031
  }
619
1032
  }
620
- const remainingAccounts = oracleAccountInfos.concat(bankAccountInfos.concat(marketAccountInfos));
1033
+ perpMarketAccountMap.set(marketIndex, {
1034
+ pubkey: marketAccount.pubkey,
1035
+ isWritable: true,
1036
+ isSigner: false,
1037
+ });
1038
+ oracleAccountMap.set(marketAccount.amm.oracle.toString(), {
1039
+ pubkey: marketAccount.amm.oracle,
1040
+ isWritable: false,
1041
+ isSigner: false,
1042
+ });
1043
+ const remainingAccounts = [
1044
+ ...oracleAccountMap.values(),
1045
+ ...spotMarketAccountMap.values(),
1046
+ ...perpMarketAccountMap.values(),
1047
+ ];
621
1048
  if (makerInfo) {
622
1049
  remainingAccounts.push({
623
1050
  pubkey: makerInfo.maker,
624
1051
  isWritable: true,
625
1052
  isSigner: false,
626
1053
  });
1054
+ remainingAccounts.push({
1055
+ pubkey: makerInfo.makerStats,
1056
+ isWritable: true,
1057
+ isSigner: false,
1058
+ });
1059
+ }
1060
+ if (referrerInfo) {
1061
+ remainingAccounts.push({
1062
+ pubkey: referrerInfo.referrer,
1063
+ isWritable: true,
1064
+ isSigner: false,
1065
+ });
1066
+ remainingAccounts.push({
1067
+ pubkey: referrerInfo.referrerStats,
1068
+ isWritable: true,
1069
+ isSigner: false,
1070
+ });
627
1071
  }
628
1072
  const orderId = order.orderId;
629
1073
  const makerOrderId = makerInfo ? makerInfo.order.orderId : null;
@@ -631,58 +1075,283 @@ class ClearingHouse {
631
1075
  accounts: {
632
1076
  state: await this.getStatePublicKey(),
633
1077
  filler: fillerPublicKey,
1078
+ fillerStats: fillerStatsPublicKey,
634
1079
  user: userAccountPublicKey,
1080
+ userStats: userStatsPublicKey,
635
1081
  authority: this.wallet.publicKey,
636
1082
  },
637
1083
  remainingAccounts,
638
1084
  });
639
1085
  }
640
- async triggerOrder(userAccountPublicKey, user, order) {
641
- const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getTriggerOrderIx(userAccountPublicKey, user, order)), [], this.opts);
1086
+ async placeSpotOrder(orderParams) {
1087
+ const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getPlaceSpotOrderIx(orderParams)), [], this.opts);
642
1088
  return txSig;
643
1089
  }
644
- async getTriggerOrderIx(userAccountPublicKey, userAccount, order) {
645
- const fillerPublicKey = await this.getUserAccountPublicKey();
646
- const marketIndex = order.marketIndex;
647
- const marketAccount = this.getMarketAccount(marketIndex);
648
- const bankAccountInfos = [
649
- {
650
- pubkey: this.getQuoteAssetBankAccount().pubkey,
651
- isSigner: false,
652
- isWritable: true,
1090
+ async getPlaceSpotOrderIx(orderParams) {
1091
+ orderParams = this.getOrderParams(orderParams, types_1.MarketType.SPOT);
1092
+ const userAccountPublicKey = await this.getUserAccountPublicKey();
1093
+ const remainingAccounts = this.getRemainingAccounts({
1094
+ readableSpotMarketIndex: orderParams.marketIndex,
1095
+ });
1096
+ return await this.program.instruction.placeSpotOrder(orderParams, {
1097
+ accounts: {
1098
+ state: await this.getStatePublicKey(),
1099
+ user: userAccountPublicKey,
1100
+ userStats: this.getUserStatsAccountPublicKey(),
1101
+ authority: this.wallet.publicKey,
653
1102
  },
1103
+ remainingAccounts,
1104
+ });
1105
+ }
1106
+ async fillSpotOrder(userAccountPublicKey, user, order, fulfillmentConfig, makerInfo, referrerInfo) {
1107
+ const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getFillSpotOrderIx(userAccountPublicKey, user, order, fulfillmentConfig, makerInfo, referrerInfo)), [], this.opts);
1108
+ return txSig;
1109
+ }
1110
+ async getFillSpotOrderIx(userAccountPublicKey, userAccount, order, fulfillmentConfig, makerInfo, referrerInfo) {
1111
+ const userStatsPublicKey = (0, pda_1.getUserStatsAccountPublicKey)(this.program.programId, userAccount.authority);
1112
+ const fillerPublicKey = await this.getUserAccountPublicKey();
1113
+ const fillerStatsPublicKey = this.getUserStatsAccountPublicKey();
1114
+ const marketIndex = order
1115
+ ? order.marketIndex
1116
+ : userAccount.orders.find((order) => order.orderId.eq(userAccount.nextOrderId.sub(numericConstants_1.ONE))).marketIndex;
1117
+ const oracleAccountMap = new Map();
1118
+ const spotMarketAccountMap = new Map();
1119
+ const perpMarketAccountMap = new Map();
1120
+ for (const spotPosition of userAccount.spotPositions) {
1121
+ if (!(0, spotPosition_1.isSpotPositionAvailable)(spotPosition)) {
1122
+ const spotMarket = this.getSpotMarketAccount(spotPosition.marketIndex);
1123
+ spotMarketAccountMap.set(spotPosition.marketIndex, {
1124
+ pubkey: spotMarket.pubkey,
1125
+ isSigner: false,
1126
+ isWritable: false,
1127
+ });
1128
+ if (!spotMarket.oracle.equals(web3_js_1.PublicKey.default)) {
1129
+ oracleAccountMap.set(spotMarket.oracle.toString(), {
1130
+ pubkey: spotMarket.oracle,
1131
+ isSigner: false,
1132
+ isWritable: false,
1133
+ });
1134
+ }
1135
+ }
1136
+ }
1137
+ for (const position of userAccount.perpPositions) {
1138
+ if (!(0, position_1.positionIsAvailable)(position)) {
1139
+ const market = this.getPerpMarketAccount(position.marketIndex);
1140
+ perpMarketAccountMap.set(position.marketIndex, {
1141
+ pubkey: market.pubkey,
1142
+ isWritable: false,
1143
+ isSigner: false,
1144
+ });
1145
+ oracleAccountMap.set(market.amm.oracle.toString(), {
1146
+ pubkey: market.amm.oracle,
1147
+ isWritable: false,
1148
+ isSigner: false,
1149
+ });
1150
+ }
1151
+ }
1152
+ const spotMarketAccount = this.getSpotMarketAccount(marketIndex);
1153
+ spotMarketAccountMap.set(marketIndex, {
1154
+ pubkey: spotMarketAccount.pubkey,
1155
+ isWritable: true,
1156
+ isSigner: false,
1157
+ });
1158
+ if (!spotMarketAccount.oracle.equals(web3_js_1.PublicKey.default)) {
1159
+ oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
1160
+ pubkey: spotMarketAccount.oracle,
1161
+ isWritable: false,
1162
+ isSigner: false,
1163
+ });
1164
+ }
1165
+ const quoteMarketAccount = this.getQuoteSpotMarketAccount();
1166
+ spotMarketAccountMap.set(quoteMarketAccount.marketIndex, {
1167
+ pubkey: quoteMarketAccount.pubkey,
1168
+ isWritable: true,
1169
+ isSigner: false,
1170
+ });
1171
+ const remainingAccounts = [
1172
+ ...oracleAccountMap.values(),
1173
+ ...spotMarketAccountMap.values(),
1174
+ ...perpMarketAccountMap.values(),
654
1175
  ];
655
- const marketAccountInfos = [
656
- {
657
- pubkey: marketAccount.pubkey,
1176
+ if (makerInfo) {
1177
+ remainingAccounts.push({
1178
+ pubkey: makerInfo.maker,
658
1179
  isWritable: true,
659
1180
  isSigner: false,
660
- },
661
- ];
662
- const oracleAccountInfos = [
663
- {
664
- pubkey: marketAccount.amm.oracle,
1181
+ });
1182
+ remainingAccounts.push({
1183
+ pubkey: makerInfo.makerStats,
1184
+ isWritable: true,
1185
+ isSigner: false,
1186
+ });
1187
+ }
1188
+ if (referrerInfo) {
1189
+ remainingAccounts.push({
1190
+ pubkey: referrerInfo.referrer,
1191
+ isWritable: true,
1192
+ isSigner: false,
1193
+ });
1194
+ remainingAccounts.push({
1195
+ pubkey: referrerInfo.referrerStats,
1196
+ isWritable: true,
1197
+ isSigner: false,
1198
+ });
1199
+ }
1200
+ const orderId = order.orderId;
1201
+ const makerOrderId = makerInfo ? makerInfo.order.orderId : null;
1202
+ if (fulfillmentConfig) {
1203
+ remainingAccounts.push({
1204
+ pubkey: fulfillmentConfig.pubkey,
1205
+ isWritable: false,
1206
+ isSigner: false,
1207
+ });
1208
+ remainingAccounts.push({
1209
+ pubkey: fulfillmentConfig.serumProgramId,
665
1210
  isWritable: false,
666
1211
  isSigner: false,
1212
+ });
1213
+ remainingAccounts.push({
1214
+ pubkey: fulfillmentConfig.serumMarket,
1215
+ isWritable: true,
1216
+ isSigner: false,
1217
+ });
1218
+ remainingAccounts.push({
1219
+ pubkey: fulfillmentConfig.serumRequestQueue,
1220
+ isWritable: true,
1221
+ isSigner: false,
1222
+ });
1223
+ remainingAccounts.push({
1224
+ pubkey: fulfillmentConfig.serumEventQueue,
1225
+ isWritable: true,
1226
+ isSigner: false,
1227
+ });
1228
+ remainingAccounts.push({
1229
+ pubkey: fulfillmentConfig.serumBids,
1230
+ isWritable: true,
1231
+ isSigner: false,
1232
+ });
1233
+ remainingAccounts.push({
1234
+ pubkey: fulfillmentConfig.serumAsks,
1235
+ isWritable: true,
1236
+ isSigner: false,
1237
+ });
1238
+ remainingAccounts.push({
1239
+ pubkey: fulfillmentConfig.serumBaseVault,
1240
+ isWritable: true,
1241
+ isSigner: false,
1242
+ });
1243
+ remainingAccounts.push({
1244
+ pubkey: fulfillmentConfig.serumQuoteVault,
1245
+ isWritable: true,
1246
+ isSigner: false,
1247
+ });
1248
+ remainingAccounts.push({
1249
+ pubkey: fulfillmentConfig.serumOpenOrders,
1250
+ isWritable: true,
1251
+ isSigner: false,
1252
+ });
1253
+ remainingAccounts.push({
1254
+ pubkey: (0, pda_1.getSerumSignerPublicKey)(fulfillmentConfig.serumProgramId, fulfillmentConfig.serumMarket, fulfillmentConfig.serumSignerNonce),
1255
+ isWritable: false,
1256
+ isSigner: false,
1257
+ });
1258
+ remainingAccounts.push({
1259
+ pubkey: this.getSignerPublicKey(),
1260
+ isWritable: false,
1261
+ isSigner: false,
1262
+ });
1263
+ remainingAccounts.push({
1264
+ pubkey: spl_token_1.TOKEN_PROGRAM_ID,
1265
+ isWritable: false,
1266
+ isSigner: false,
1267
+ });
1268
+ remainingAccounts.push({
1269
+ pubkey: spotMarketAccount.vault,
1270
+ isWritable: true,
1271
+ isSigner: false,
1272
+ });
1273
+ remainingAccounts.push({
1274
+ pubkey: quoteMarketAccount.vault,
1275
+ isWritable: true,
1276
+ isSigner: false,
1277
+ });
1278
+ remainingAccounts.push({
1279
+ pubkey: this.getStateAccount().srmVault,
1280
+ isWritable: false,
1281
+ isSigner: false,
1282
+ });
1283
+ }
1284
+ return await this.program.instruction.fillSpotOrder(orderId, fulfillmentConfig ? fulfillmentConfig.fulfillmentType : null, makerOrderId, {
1285
+ accounts: {
1286
+ state: await this.getStatePublicKey(),
1287
+ filler: fillerPublicKey,
1288
+ fillerStats: fillerStatsPublicKey,
1289
+ user: userAccountPublicKey,
1290
+ userStats: userStatsPublicKey,
1291
+ authority: this.wallet.publicKey,
667
1292
  },
668
- ];
669
- for (const position of userAccount.positions) {
1293
+ remainingAccounts,
1294
+ });
1295
+ }
1296
+ async triggerOrder(userAccountPublicKey, user, order) {
1297
+ const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getTriggerOrderIx(userAccountPublicKey, user, order)), [], this.opts);
1298
+ return txSig;
1299
+ }
1300
+ async getTriggerOrderIx(userAccountPublicKey, userAccount, order) {
1301
+ const fillerPublicKey = await this.getUserAccountPublicKey();
1302
+ const marketIndex = order.marketIndex;
1303
+ const marketAccount = this.getPerpMarketAccount(marketIndex);
1304
+ const oracleAccountMap = new Map();
1305
+ const spotMarketAccountMap = new Map();
1306
+ const perpMarketAccountMap = new Map();
1307
+ for (const spotPosition of userAccount.spotPositions) {
1308
+ if (!(0, spotPosition_1.isSpotPositionAvailable)(spotPosition)) {
1309
+ const spotMarketAccount = this.getSpotMarketAccount(spotPosition.marketIndex);
1310
+ spotMarketAccountMap.set(spotPosition.marketIndex, {
1311
+ pubkey: spotMarketAccount.pubkey,
1312
+ isSigner: false,
1313
+ isWritable: false,
1314
+ });
1315
+ if (!spotMarketAccount.oracle.equals(web3_js_1.PublicKey.default)) {
1316
+ oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
1317
+ pubkey: spotMarketAccount.oracle,
1318
+ isSigner: false,
1319
+ isWritable: false,
1320
+ });
1321
+ }
1322
+ }
1323
+ }
1324
+ for (const position of userAccount.perpPositions) {
670
1325
  if (!(0, position_1.positionIsAvailable)(position) &&
671
- !position.marketIndex.eq(order.marketIndex)) {
672
- const market = this.getMarketAccount(position.marketIndex);
673
- marketAccountInfos.push({
1326
+ position.marketIndex !== order.marketIndex) {
1327
+ const market = this.getPerpMarketAccount(position.marketIndex);
1328
+ perpMarketAccountMap.set(position.marketIndex, {
674
1329
  pubkey: market.pubkey,
675
1330
  isWritable: false,
676
1331
  isSigner: false,
677
1332
  });
678
- oracleAccountInfos.push({
1333
+ oracleAccountMap.set(market.amm.oracle.toString(), {
679
1334
  pubkey: market.amm.oracle,
680
1335
  isWritable: false,
681
1336
  isSigner: false,
682
1337
  });
683
1338
  }
684
1339
  }
685
- const remainingAccounts = oracleAccountInfos.concat(bankAccountInfos.concat(marketAccountInfos));
1340
+ perpMarketAccountMap.set(marketIndex, {
1341
+ pubkey: marketAccount.pubkey,
1342
+ isWritable: true,
1343
+ isSigner: false,
1344
+ });
1345
+ oracleAccountMap.set(marketAccount.amm.oracle.toString(), {
1346
+ pubkey: marketAccount.amm.oracle,
1347
+ isWritable: false,
1348
+ isSigner: false,
1349
+ });
1350
+ const remainingAccounts = [
1351
+ ...oracleAccountMap.values(),
1352
+ ...spotMarketAccountMap.values(),
1353
+ ...perpMarketAccountMap.values(),
1354
+ ];
686
1355
  const orderId = order.orderId;
687
1356
  return await this.program.instruction.triggerOrder(orderId, {
688
1357
  accounts: {
@@ -694,16 +1363,94 @@ class ClearingHouse {
694
1363
  remainingAccounts,
695
1364
  });
696
1365
  }
697
- async placeAndTake(orderParams, makerInfo) {
698
- const { txSig, slot } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getPlaceAndTakeIx(orderParams, makerInfo)), [], this.opts);
699
- this.marketLastSlotCache.set(orderParams.marketIndex.toNumber(), slot);
1366
+ async triggerSpotOrder(userAccountPublicKey, user, order) {
1367
+ const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getTriggerSpotOrderIx(userAccountPublicKey, user, order)), [], this.opts);
700
1368
  return txSig;
701
1369
  }
702
- async getPlaceAndTakeIx(orderParams, makerInfo) {
1370
+ async getTriggerSpotOrderIx(userAccountPublicKey, userAccount, order) {
1371
+ const fillerPublicKey = await this.getUserAccountPublicKey();
1372
+ const marketIndex = order.marketIndex;
1373
+ const spotMarketAccount = this.getSpotMarketAccount(marketIndex);
1374
+ const oracleAccountMap = new Map();
1375
+ const spotMarketAccountMap = new Map();
1376
+ const perpMarketAccountMap = new Map();
1377
+ for (const spotPosition of userAccount.spotPositions) {
1378
+ if (!(0, spotPosition_1.isSpotPositionAvailable)(spotPosition)) {
1379
+ const spotMarketAccount = this.getSpotMarketAccount(spotPosition.marketIndex);
1380
+ spotMarketAccountMap.set(spotPosition.marketIndex, {
1381
+ pubkey: spotMarketAccount.pubkey,
1382
+ isSigner: false,
1383
+ isWritable: false,
1384
+ });
1385
+ if (!spotMarketAccount.oracle.equals(web3_js_1.PublicKey.default)) {
1386
+ oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
1387
+ pubkey: spotMarketAccount.oracle,
1388
+ isSigner: false,
1389
+ isWritable: false,
1390
+ });
1391
+ }
1392
+ }
1393
+ }
1394
+ for (const position of userAccount.perpPositions) {
1395
+ if (!(0, position_1.positionIsAvailable)(position) &&
1396
+ position.marketIndex !== order.marketIndex) {
1397
+ const market = this.getPerpMarketAccount(position.marketIndex);
1398
+ perpMarketAccountMap.set(position.marketIndex, {
1399
+ pubkey: market.pubkey,
1400
+ isWritable: false,
1401
+ isSigner: false,
1402
+ });
1403
+ oracleAccountMap.set(market.amm.oracle.toString(), {
1404
+ pubkey: market.amm.oracle,
1405
+ isWritable: false,
1406
+ isSigner: false,
1407
+ });
1408
+ }
1409
+ }
1410
+ const quoteSpotMarket = this.getQuoteSpotMarketAccount();
1411
+ spotMarketAccountMap.set(quoteSpotMarket.marketIndex, {
1412
+ pubkey: quoteSpotMarket.pubkey,
1413
+ isWritable: true,
1414
+ isSigner: false,
1415
+ });
1416
+ spotMarketAccountMap.set(marketIndex, {
1417
+ pubkey: spotMarketAccount.pubkey,
1418
+ isWritable: false,
1419
+ isSigner: false,
1420
+ });
1421
+ oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
1422
+ pubkey: spotMarketAccount.oracle,
1423
+ isWritable: false,
1424
+ isSigner: false,
1425
+ });
1426
+ const remainingAccounts = [
1427
+ ...oracleAccountMap.values(),
1428
+ ...spotMarketAccountMap.values(),
1429
+ ...perpMarketAccountMap.values(),
1430
+ ];
1431
+ const orderId = order.orderId;
1432
+ return await this.program.instruction.triggerSpotOrder(orderId, {
1433
+ accounts: {
1434
+ state: await this.getStatePublicKey(),
1435
+ filler: fillerPublicKey,
1436
+ user: userAccountPublicKey,
1437
+ authority: this.wallet.publicKey,
1438
+ },
1439
+ remainingAccounts,
1440
+ });
1441
+ }
1442
+ async placeAndTake(orderParams, makerInfo, referrerInfo) {
1443
+ const { txSig, slot } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getPlaceAndTakeIx(orderParams, makerInfo, referrerInfo)), [], this.opts);
1444
+ this.marketLastSlotCache.set(orderParams.marketIndex, slot);
1445
+ return txSig;
1446
+ }
1447
+ async getPlaceAndTakeIx(orderParams, makerInfo, referrerInfo) {
1448
+ orderParams = this.getOrderParams(orderParams, types_1.MarketType.PERP);
1449
+ const userStatsPublicKey = await this.getUserStatsAccountPublicKey();
703
1450
  const userAccountPublicKey = await this.getUserAccountPublicKey();
704
1451
  const remainingAccounts = this.getRemainingAccounts({
705
- writableMarketIndex: orderParams.marketIndex,
706
- writableBankIndex: numericConstants_1.QUOTE_ASSET_BANK_INDEX,
1452
+ writablePerpMarketIndex: orderParams.marketIndex,
1453
+ writableSpotMarketIndex: numericConstants_1.QUOTE_SPOT_MARKET_INDEX,
707
1454
  });
708
1455
  let makerOrderId = null;
709
1456
  if (makerInfo) {
@@ -713,11 +1460,68 @@ class ClearingHouse {
713
1460
  isSigner: false,
714
1461
  isWritable: true,
715
1462
  });
1463
+ remainingAccounts.push({
1464
+ pubkey: makerInfo.makerStats,
1465
+ isSigner: false,
1466
+ isWritable: true,
1467
+ });
1468
+ }
1469
+ if (referrerInfo) {
1470
+ remainingAccounts.push({
1471
+ pubkey: referrerInfo.referrer,
1472
+ isWritable: true,
1473
+ isSigner: false,
1474
+ });
1475
+ remainingAccounts.push({
1476
+ pubkey: referrerInfo.referrerStats,
1477
+ isWritable: true,
1478
+ isSigner: false,
1479
+ });
716
1480
  }
717
1481
  return await this.program.instruction.placeAndTake(orderParams, makerOrderId, {
718
1482
  accounts: {
719
1483
  state: await this.getStatePublicKey(),
720
1484
  user: userAccountPublicKey,
1485
+ userStats: userStatsPublicKey,
1486
+ authority: this.wallet.publicKey,
1487
+ },
1488
+ remainingAccounts,
1489
+ });
1490
+ }
1491
+ async placeAndMake(orderParams, takerInfo, referrerInfo) {
1492
+ const { txSig, slot } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getPlaceAndMakeIx(orderParams, takerInfo, referrerInfo)), [], this.opts);
1493
+ this.marketLastSlotCache.set(orderParams.marketIndex, slot);
1494
+ return txSig;
1495
+ }
1496
+ async getPlaceAndMakeIx(orderParams, takerInfo, referrerInfo) {
1497
+ orderParams = this.getOrderParams(orderParams, types_1.MarketType.PERP);
1498
+ const userStatsPublicKey = this.getUserStatsAccountPublicKey();
1499
+ const userAccountPublicKey = await this.getUserAccountPublicKey();
1500
+ // todo merge this with getRemainingAccounts
1501
+ const remainingAccounts = this.getRemainingAccountsWithCounterparty({
1502
+ counterPartyUserAccount: takerInfo.takerUserAccount,
1503
+ writablePerpMarketIndex: orderParams.marketIndex,
1504
+ });
1505
+ if (referrerInfo) {
1506
+ remainingAccounts.push({
1507
+ pubkey: referrerInfo.referrer,
1508
+ isWritable: true,
1509
+ isSigner: false,
1510
+ });
1511
+ remainingAccounts.push({
1512
+ pubkey: referrerInfo.referrerStats,
1513
+ isWritable: true,
1514
+ isSigner: false,
1515
+ });
1516
+ }
1517
+ const takerOrderId = takerInfo.order.orderId;
1518
+ return await this.program.instruction.placeAndMake(orderParams, takerOrderId, {
1519
+ accounts: {
1520
+ state: await this.getStatePublicKey(),
1521
+ user: userAccountPublicKey,
1522
+ userStats: userStatsPublicKey,
1523
+ taker: takerInfo.taker,
1524
+ takerStats: takerInfo.takerStats,
721
1525
  authority: this.wallet.publicKey,
722
1526
  },
723
1527
  remainingAccounts,
@@ -728,36 +1532,118 @@ class ClearingHouse {
728
1532
  * @param marketIndex
729
1533
  * @returns
730
1534
  */
731
- async closePosition(marketIndex) {
1535
+ async closePosition(marketIndex, limitPrice) {
732
1536
  const userPosition = this.getUser().getUserPosition(marketIndex);
733
1537
  if (!userPosition) {
734
1538
  throw Error(`No position in market ${marketIndex.toString()}`);
735
1539
  }
736
- return await this.placeAndTake((0, orderParams_1.getMarketOrderParams)(marketIndex, (0, position_1.findDirectionToClose)(userPosition), numericConstants_1.ZERO, userPosition.baseAssetAmount, true, undefined));
1540
+ return await this.placeAndTake({
1541
+ orderType: types_1.OrderType.MARKET,
1542
+ marketIndex,
1543
+ direction: (0, position_1.findDirectionToClose)(userPosition),
1544
+ baseAssetAmount: userPosition.baseAssetAmount.abs(),
1545
+ reduceOnly: true,
1546
+ price: limitPrice,
1547
+ });
737
1548
  }
738
1549
  async settlePNLs(users, marketIndex) {
739
1550
  const ixs = [];
740
1551
  for (const { settleeUserAccountPublicKey, settleeUserAccount } of users) {
741
1552
  ixs.push(await this.settlePNLIx(settleeUserAccountPublicKey, settleeUserAccount, marketIndex));
742
1553
  }
743
- const tx = new web3_js_1.Transaction().add(...ixs);
1554
+ const tx = new web3_js_1.Transaction()
1555
+ .add(web3_js_1.ComputeBudgetProgram.requestUnits({
1556
+ units: 1000000,
1557
+ additionalFee: 0,
1558
+ }))
1559
+ .add(...ixs);
744
1560
  const { txSig } = await this.txSender.send(tx, [], this.opts);
745
1561
  return txSig;
746
1562
  }
747
- async settlePNL(settleeUserAccountPublicKey, settleeUserAccount, marketIndex) {
748
- const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.settlePNLIx(settleeUserAccountPublicKey, settleeUserAccount, marketIndex)), [], this.opts);
1563
+ async settlePNL(settleeUserAccountPublicKey, settleeUserAccount, marketIndex) {
1564
+ const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.settlePNLIx(settleeUserAccountPublicKey, settleeUserAccount, marketIndex)), [], this.opts);
1565
+ return txSig;
1566
+ }
1567
+ async settlePNLIx(settleeUserAccountPublicKey, settleeUserAccount, marketIndex) {
1568
+ const perpMarketAccountMap = new Map();
1569
+ const oracleAccountMap = new Map();
1570
+ const spotMarketAccountMap = new Map();
1571
+ for (const position of settleeUserAccount.perpPositions) {
1572
+ if (!(0, position_1.positionIsAvailable)(position)) {
1573
+ const market = this.getPerpMarketAccount(position.marketIndex);
1574
+ perpMarketAccountMap.set(position.marketIndex, {
1575
+ pubkey: market.pubkey,
1576
+ isWritable: false,
1577
+ isSigner: false,
1578
+ });
1579
+ oracleAccountMap.set(market.amm.oracle.toString(), {
1580
+ pubkey: market.amm.oracle,
1581
+ isWritable: false,
1582
+ isSigner: false,
1583
+ });
1584
+ }
1585
+ }
1586
+ for (const spotPosition of settleeUserAccount.spotPositions) {
1587
+ if (!(0, spotPosition_1.isSpotPositionAvailable)(spotPosition)) {
1588
+ const spotMarketAccount = this.getSpotMarketAccount(spotPosition.marketIndex);
1589
+ spotMarketAccountMap.set(spotPosition.marketIndex, {
1590
+ pubkey: spotMarketAccount.pubkey,
1591
+ isSigner: false,
1592
+ isWritable: false,
1593
+ });
1594
+ if (spotMarketAccount.marketIndex !== 0) {
1595
+ oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
1596
+ pubkey: spotMarketAccount.oracle,
1597
+ isSigner: false,
1598
+ isWritable: false,
1599
+ });
1600
+ }
1601
+ }
1602
+ }
1603
+ const marketAccount = this.getPerpMarketAccount(marketIndex);
1604
+ perpMarketAccountMap.set(marketIndex, {
1605
+ pubkey: marketAccount.pubkey,
1606
+ isSigner: false,
1607
+ isWritable: true,
1608
+ });
1609
+ oracleAccountMap.set(marketAccount.amm.oracle.toString(), {
1610
+ pubkey: marketAccount.amm.oracle,
1611
+ isSigner: false,
1612
+ isWritable: false,
1613
+ });
1614
+ spotMarketAccountMap.set(numericConstants_1.QUOTE_SPOT_MARKET_INDEX, {
1615
+ pubkey: this.getSpotMarketAccount(numericConstants_1.QUOTE_SPOT_MARKET_INDEX).pubkey,
1616
+ isSigner: false,
1617
+ isWritable: true,
1618
+ });
1619
+ const remainingAccounts = [
1620
+ ...oracleAccountMap.values(),
1621
+ ...spotMarketAccountMap.values(),
1622
+ ...perpMarketAccountMap.values(),
1623
+ ];
1624
+ return await this.program.instruction.settlePnl(marketIndex, {
1625
+ accounts: {
1626
+ state: await this.getStatePublicKey(),
1627
+ authority: this.wallet.publicKey,
1628
+ user: settleeUserAccountPublicKey,
1629
+ },
1630
+ remainingAccounts: remainingAccounts,
1631
+ });
1632
+ }
1633
+ async settleExpiredPosition(settleeUserAccountPublicKey, settleeUserAccount, marketIndex) {
1634
+ const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getSettleExpiredPositionIx(settleeUserAccountPublicKey, settleeUserAccount, marketIndex)), [], this.opts);
749
1635
  return txSig;
750
1636
  }
751
- async settlePNLIx(settleeUserAccountPublicKey, settleeUserAccount, marketIndex) {
1637
+ async getSettleExpiredPositionIx(settleeUserAccountPublicKey, settleeUserAccount, marketIndex) {
752
1638
  const marketAccountMap = new Map();
753
1639
  const oracleAccountMap = new Map();
754
- const bankAccountMap = new Map();
755
- for (const position of settleeUserAccount.positions) {
1640
+ const spotMarketAccountMap = new Map();
1641
+ for (const position of settleeUserAccount.perpPositions) {
756
1642
  if (!(0, position_1.positionIsAvailable)(position)) {
757
- const market = this.getMarketAccount(position.marketIndex);
758
- marketAccountMap.set(position.marketIndex.toNumber(), {
1643
+ const market = this.getPerpMarketAccount(position.marketIndex);
1644
+ marketAccountMap.set(position.marketIndex, {
759
1645
  pubkey: market.pubkey,
760
- isWritable: true,
1646
+ isWritable: false,
761
1647
  isSigner: false,
762
1648
  });
763
1649
  oracleAccountMap.set(market.amm.oracle.toString(), {
@@ -767,15 +1653,15 @@ class ClearingHouse {
767
1653
  });
768
1654
  }
769
1655
  }
770
- for (const userBankBalance of settleeUserAccount.bankBalances) {
771
- if (!userBankBalance.balance.eq(numericConstants_1.QUOTE_ASSET_BANK_INDEX)) {
772
- const bankAccount = this.getBankAccount(userBankBalance.bankIndex);
773
- bankAccountMap.set(userBankBalance.bankIndex.toNumber(), {
1656
+ for (const userBankBalance of settleeUserAccount.spotPositions) {
1657
+ if (!userBankBalance.balance.eq(numericConstants_1.ZERO)) {
1658
+ const bankAccount = this.getSpotMarketAccount(userBankBalance.marketIndex);
1659
+ spotMarketAccountMap.set(userBankBalance.marketIndex, {
774
1660
  pubkey: bankAccount.pubkey,
775
1661
  isSigner: false,
776
1662
  isWritable: false,
777
1663
  });
778
- if (!bankAccount.bankIndex.eq(numericConstants_1.ZERO)) {
1664
+ if (bankAccount.marketIndex !== 0) {
779
1665
  oracleAccountMap.set(bankAccount.oracle.toString(), {
780
1666
  pubkey: bankAccount.oracle,
781
1667
  isSigner: false,
@@ -784,8 +1670,8 @@ class ClearingHouse {
784
1670
  }
785
1671
  }
786
1672
  }
787
- const marketAccount = this.getMarketAccount(marketIndex.toNumber());
788
- marketAccountMap.set(marketIndex.toNumber(), {
1673
+ const marketAccount = this.getPerpMarketAccount(marketIndex);
1674
+ marketAccountMap.set(marketIndex, {
789
1675
  pubkey: marketAccount.pubkey,
790
1676
  isSigner: false,
791
1677
  isWritable: true,
@@ -795,17 +1681,17 @@ class ClearingHouse {
795
1681
  isSigner: false,
796
1682
  isWritable: false,
797
1683
  });
798
- bankAccountMap.set(numericConstants_1.QUOTE_ASSET_BANK_INDEX.toNumber(), {
799
- pubkey: this.getBankAccount(numericConstants_1.QUOTE_ASSET_BANK_INDEX).pubkey,
1684
+ spotMarketAccountMap.set(numericConstants_1.QUOTE_SPOT_MARKET_INDEX, {
1685
+ pubkey: this.getSpotMarketAccount(numericConstants_1.QUOTE_SPOT_MARKET_INDEX).pubkey,
800
1686
  isSigner: false,
801
1687
  isWritable: true,
802
1688
  });
803
1689
  const remainingAccounts = [
804
1690
  ...oracleAccountMap.values(),
805
- ...bankAccountMap.values(),
1691
+ ...spotMarketAccountMap.values(),
806
1692
  ...marketAccountMap.values(),
807
1693
  ];
808
- return await this.program.instruction.settlePnl(marketIndex, {
1694
+ return await this.program.instruction.settleExpiredPosition(marketIndex, {
809
1695
  accounts: {
810
1696
  state: await this.getStatePublicKey(),
811
1697
  authority: this.wallet.publicKey,
@@ -814,54 +1700,275 @@ class ClearingHouse {
814
1700
  remainingAccounts: remainingAccounts,
815
1701
  });
816
1702
  }
817
- async liquidate(liquidateeUserAccountPublicKey) {
818
- const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getLiquidateIx(liquidateeUserAccountPublicKey)), [], this.opts);
1703
+ async liquidatePerp(userAccountPublicKey, userAccount, marketIndex, maxBaseAssetAmount) {
1704
+ const { txSig, slot } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getLiquidatePerpIx(userAccountPublicKey, userAccount, marketIndex, maxBaseAssetAmount)), [], this.opts);
1705
+ this.marketLastSlotCache.set(marketIndex, slot);
819
1706
  return txSig;
820
1707
  }
821
- async getLiquidateIx(liquidateeUserAccountPublicKey) {
822
- const userAccountPublicKey = await this.getUserAccountPublicKey();
823
- const liquidateeUserAccount = (await this.program.account.user.fetch(liquidateeUserAccountPublicKey));
824
- const bankAccountInfos = [
825
- {
826
- pubkey: this.getQuoteAssetBankAccount().pubkey,
827
- isSigner: false,
828
- isWritable: true,
1708
+ async getLiquidatePerpIx(userAccountPublicKey, userAccount, marketIndex, maxBaseAssetAmount) {
1709
+ const userStatsPublicKey = (0, pda_1.getUserStatsAccountPublicKey)(this.program.programId, userAccount.authority);
1710
+ const liquidatorPublicKey = await this.getUserAccountPublicKey();
1711
+ const liquidatorStatsPublicKey = this.getUserStatsAccountPublicKey();
1712
+ const remainingAccounts = this.getRemainingAccountsWithCounterparty({
1713
+ writablePerpMarketIndex: marketIndex,
1714
+ counterPartyUserAccount: userAccount,
1715
+ });
1716
+ return await this.program.instruction.liquidatePerp(marketIndex, maxBaseAssetAmount, {
1717
+ accounts: {
1718
+ state: await this.getStatePublicKey(),
1719
+ authority: this.wallet.publicKey,
1720
+ user: userAccountPublicKey,
1721
+ userStats: userStatsPublicKey,
1722
+ liquidator: liquidatorPublicKey,
1723
+ liquidatorStats: liquidatorStatsPublicKey,
829
1724
  },
830
- ];
831
- const marketAccountInfos = [];
832
- const oracleAccountInfos = [];
833
- for (const position of liquidateeUserAccount.positions) {
1725
+ remainingAccounts: remainingAccounts,
1726
+ });
1727
+ }
1728
+ async liquidateBorrow(userAccountPublicKey, userAccount, assetMarketIndex, liabilityMarketIndex, maxLiabilityTransfer) {
1729
+ const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getLiquidateBorrowIx(userAccountPublicKey, userAccount, assetMarketIndex, liabilityMarketIndex, maxLiabilityTransfer)), [], this.opts);
1730
+ return txSig;
1731
+ }
1732
+ async getLiquidateBorrowIx(userAccountPublicKey, userAccount, assetMarketIndex, liabilityMarketIndex, maxLiabilityTransfer) {
1733
+ const liquidatorPublicKey = await this.getUserAccountPublicKey();
1734
+ const remainingAccounts = this.getRemainingAccountsWithCounterparty({
1735
+ counterPartyUserAccount: userAccount,
1736
+ writableSpotMarketIndexes: [liabilityMarketIndex, assetMarketIndex],
1737
+ });
1738
+ return await this.program.instruction.liquidateBorrow(assetMarketIndex, liabilityMarketIndex, maxLiabilityTransfer, {
1739
+ accounts: {
1740
+ state: await this.getStatePublicKey(),
1741
+ authority: this.wallet.publicKey,
1742
+ user: userAccountPublicKey,
1743
+ liquidator: liquidatorPublicKey,
1744
+ },
1745
+ remainingAccounts: remainingAccounts,
1746
+ });
1747
+ }
1748
+ async liquidateBorrowForPerpPnl(userAccountPublicKey, userAccount, perpMarketIndex, liabilityMarketIndex, maxLiabilityTransfer) {
1749
+ const { txSig, slot } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getLiquidateBorrowForPerpPnlIx(userAccountPublicKey, userAccount, perpMarketIndex, liabilityMarketIndex, maxLiabilityTransfer)), [], this.opts);
1750
+ this.marketLastSlotCache.set(perpMarketIndex, slot);
1751
+ return txSig;
1752
+ }
1753
+ async getLiquidateBorrowForPerpPnlIx(userAccountPublicKey, userAccount, perpMarketIndex, liabilityMarketIndex, maxLiabilityTransfer) {
1754
+ const liquidatorPublicKey = await this.getUserAccountPublicKey();
1755
+ const remainingAccounts = this.getRemainingAccountsWithCounterparty({
1756
+ counterPartyUserAccount: userAccount,
1757
+ writablePerpMarketIndex: perpMarketIndex,
1758
+ writableSpotMarketIndexes: [liabilityMarketIndex],
1759
+ });
1760
+ return await this.program.instruction.liquidateBorrowForPerpPnl(perpMarketIndex, liabilityMarketIndex, maxLiabilityTransfer, {
1761
+ accounts: {
1762
+ state: await this.getStatePublicKey(),
1763
+ authority: this.wallet.publicKey,
1764
+ user: userAccountPublicKey,
1765
+ liquidator: liquidatorPublicKey,
1766
+ },
1767
+ remainingAccounts: remainingAccounts,
1768
+ });
1769
+ }
1770
+ async liquidatePerpPnlForDeposit(userAccountPublicKey, userAccount, perpMarketIndex, assetMarketIndex, maxPnlTransfer) {
1771
+ const { txSig, slot } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getLiquidatePerpPnlForDepositIx(userAccountPublicKey, userAccount, perpMarketIndex, assetMarketIndex, maxPnlTransfer)), [], this.opts);
1772
+ this.marketLastSlotCache.set(perpMarketIndex, slot);
1773
+ return txSig;
1774
+ }
1775
+ async getLiquidatePerpPnlForDepositIx(userAccountPublicKey, userAccount, perpMarketIndex, assetMarketIndex, maxPnlTransfer) {
1776
+ const liquidatorPublicKey = await this.getUserAccountPublicKey();
1777
+ const remainingAccounts = this.getRemainingAccountsWithCounterparty({
1778
+ counterPartyUserAccount: userAccount,
1779
+ writablePerpMarketIndex: perpMarketIndex,
1780
+ writableSpotMarketIndexes: [assetMarketIndex],
1781
+ });
1782
+ return await this.program.instruction.liquidatePerpPnlForDeposit(perpMarketIndex, assetMarketIndex, maxPnlTransfer, {
1783
+ accounts: {
1784
+ state: await this.getStatePublicKey(),
1785
+ authority: this.wallet.publicKey,
1786
+ user: userAccountPublicKey,
1787
+ liquidator: liquidatorPublicKey,
1788
+ },
1789
+ remainingAccounts: remainingAccounts,
1790
+ });
1791
+ }
1792
+ async resolvePerpBankruptcy(userAccountPublicKey, userAccount, marketIndex) {
1793
+ const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getResolvePerpBankruptcyIx(userAccountPublicKey, userAccount, marketIndex)), [], this.opts);
1794
+ return txSig;
1795
+ }
1796
+ async getResolvePerpBankruptcyIx(userAccountPublicKey, userAccount, marketIndex) {
1797
+ const liquidatorPublicKey = await this.getUserAccountPublicKey();
1798
+ const remainingAccounts = this.getRemainingAccountsWithCounterparty({
1799
+ writablePerpMarketIndex: marketIndex,
1800
+ writableSpotMarketIndexes: [numericConstants_1.QUOTE_SPOT_MARKET_INDEX],
1801
+ counterPartyUserAccount: userAccount,
1802
+ });
1803
+ const spotMarket = this.getSpotMarketAccount(marketIndex);
1804
+ return await this.program.instruction.resolvePerpBankruptcy(numericConstants_1.QUOTE_SPOT_MARKET_INDEX, marketIndex, {
1805
+ accounts: {
1806
+ state: await this.getStatePublicKey(),
1807
+ authority: this.wallet.publicKey,
1808
+ user: userAccountPublicKey,
1809
+ liquidator: liquidatorPublicKey,
1810
+ spotMarketVault: spotMarket.vault,
1811
+ insuranceFundVault: spotMarket.insuranceFundVault,
1812
+ clearingHouseSigner: this.getSignerPublicKey(),
1813
+ tokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
1814
+ },
1815
+ remainingAccounts: remainingAccounts,
1816
+ });
1817
+ }
1818
+ async resolveBorrowBankruptcy(userAccountPublicKey, userAccount, marketIndex) {
1819
+ const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getResolveBorrowBankruptcyIx(userAccountPublicKey, userAccount, marketIndex)), [], this.opts);
1820
+ return txSig;
1821
+ }
1822
+ async getResolveBorrowBankruptcyIx(userAccountPublicKey, userAccount, marketIndex) {
1823
+ const liquidatorPublicKey = await this.getUserAccountPublicKey();
1824
+ const remainingAccounts = this.getRemainingAccountsWithCounterparty({
1825
+ writableSpotMarketIndexes: [marketIndex],
1826
+ counterPartyUserAccount: userAccount,
1827
+ });
1828
+ const spotMarket = this.getSpotMarketAccount(marketIndex);
1829
+ return await this.program.instruction.resolveBorrowBankruptcy(marketIndex, {
1830
+ accounts: {
1831
+ state: await this.getStatePublicKey(),
1832
+ authority: this.wallet.publicKey,
1833
+ user: userAccountPublicKey,
1834
+ liquidator: liquidatorPublicKey,
1835
+ spotMarketVault: spotMarket.vault,
1836
+ insuranceFundVault: spotMarket.insuranceFundVault,
1837
+ clearingHouseSigner: this.getSignerPublicKey(),
1838
+ tokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
1839
+ },
1840
+ remainingAccounts: remainingAccounts,
1841
+ });
1842
+ }
1843
+ getRemainingAccountsWithCounterparty(params) {
1844
+ const counterPartyUserAccount = params.counterPartyUserAccount;
1845
+ const oracleAccountMap = new Map();
1846
+ const spotMarketAccountMap = new Map();
1847
+ const marketAccountMap = new Map();
1848
+ for (const spotPosition of counterPartyUserAccount.spotPositions) {
1849
+ if (!(0, spotPosition_1.isSpotPositionAvailable)(spotPosition)) {
1850
+ const spotMarket = this.getSpotMarketAccount(spotPosition.marketIndex);
1851
+ spotMarketAccountMap.set(spotPosition.marketIndex, {
1852
+ pubkey: spotMarket.pubkey,
1853
+ isSigner: false,
1854
+ isWritable: false,
1855
+ });
1856
+ if (!spotMarket.oracle.equals(web3_js_1.PublicKey.default)) {
1857
+ oracleAccountMap.set(spotMarket.oracle.toString(), {
1858
+ pubkey: spotMarket.oracle,
1859
+ isSigner: false,
1860
+ isWritable: false,
1861
+ });
1862
+ }
1863
+ }
1864
+ }
1865
+ for (const position of counterPartyUserAccount.perpPositions) {
834
1866
  if (!(0, position_1.positionIsAvailable)(position)) {
835
- const market = this.getMarketAccount(position.marketIndex);
836
- const marketPublicKey = await (0, pda_1.getMarketPublicKey)(this.program.programId, position.marketIndex);
837
- marketAccountInfos.push({
838
- pubkey: marketPublicKey,
839
- isWritable: true,
1867
+ const market = this.getPerpMarketAccount(position.marketIndex);
1868
+ marketAccountMap.set(position.marketIndex, {
1869
+ pubkey: market.pubkey,
1870
+ isWritable: false,
840
1871
  isSigner: false,
841
1872
  });
842
- oracleAccountInfos.push({
1873
+ oracleAccountMap.set(market.amm.oracle.toString(), {
843
1874
  pubkey: market.amm.oracle,
844
1875
  isWritable: false,
845
1876
  isSigner: false,
846
1877
  });
847
1878
  }
848
1879
  }
849
- const remainingAccounts = oracleAccountInfos.concat(bankAccountInfos.concat(marketAccountInfos));
850
- const state = this.getStateAccount();
851
- const quoteAssetBankAccount = this.getQuoteAssetBankAccount();
852
- return await this.program.instruction.liquidate({
853
- accounts: {
854
- state: await this.getStatePublicKey(),
855
- authority: this.wallet.publicKey,
856
- user: liquidateeUserAccountPublicKey,
857
- liquidator: userAccountPublicKey,
858
- bankVault: quoteAssetBankAccount.vault,
859
- bankVaultAuthority: quoteAssetBankAccount.vaultAuthority,
860
- insuranceVault: state.insuranceVault,
861
- tokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
862
- },
863
- remainingAccounts: remainingAccounts,
864
- });
1880
+ const userAccountAndSlot = this.getUserAccountAndSlot();
1881
+ if (!userAccountAndSlot) {
1882
+ throw Error('No user account found. Most likely user account does not exist or failed to fetch account');
1883
+ }
1884
+ const { data: userAccount, slot: lastUserPositionsSlot } = userAccountAndSlot;
1885
+ for (const [marketIndexNum, slot] of this.marketLastSlotCache.entries()) {
1886
+ // if cache has more recent slot than user positions account slot, add market to remaining accounts
1887
+ // otherwise remove from slot
1888
+ if (slot > lastUserPositionsSlot) {
1889
+ const marketAccount = this.getPerpMarketAccount(marketIndexNum);
1890
+ marketAccountMap.set(marketIndexNum, {
1891
+ pubkey: marketAccount.pubkey,
1892
+ isSigner: false,
1893
+ isWritable: false,
1894
+ });
1895
+ oracleAccountMap.set(marketAccount.amm.oracle.toString(), {
1896
+ pubkey: marketAccount.amm.oracle,
1897
+ isSigner: false,
1898
+ isWritable: false,
1899
+ });
1900
+ }
1901
+ else {
1902
+ this.marketLastSlotCache.delete(marketIndexNum);
1903
+ }
1904
+ }
1905
+ for (const spotPosition of userAccount.spotPositions) {
1906
+ if (!(0, spotPosition_1.isSpotPositionAvailable)(spotPosition)) {
1907
+ const spotMarket = this.getSpotMarketAccount(spotPosition.marketIndex);
1908
+ spotMarketAccountMap.set(spotPosition.marketIndex, {
1909
+ pubkey: spotMarket.pubkey,
1910
+ isSigner: false,
1911
+ isWritable: false,
1912
+ });
1913
+ if (!spotMarket.oracle.equals(web3_js_1.PublicKey.default)) {
1914
+ oracleAccountMap.set(spotMarket.oracle.toString(), {
1915
+ pubkey: spotMarket.oracle,
1916
+ isSigner: false,
1917
+ isWritable: false,
1918
+ });
1919
+ }
1920
+ }
1921
+ }
1922
+ for (const position of userAccount.perpPositions) {
1923
+ if (!(0, position_1.positionIsAvailable)(position)) {
1924
+ const market = this.getPerpMarketAccount(position.marketIndex);
1925
+ marketAccountMap.set(position.marketIndex, {
1926
+ pubkey: market.pubkey,
1927
+ isWritable: false,
1928
+ isSigner: false,
1929
+ });
1930
+ oracleAccountMap.set(market.amm.oracle.toString(), {
1931
+ pubkey: market.amm.oracle,
1932
+ isWritable: false,
1933
+ isSigner: false,
1934
+ });
1935
+ }
1936
+ }
1937
+ if (params.writablePerpMarketIndex !== undefined) {
1938
+ const market = this.getPerpMarketAccount(params.writablePerpMarketIndex);
1939
+ marketAccountMap.set(market.marketIndex, {
1940
+ pubkey: market.pubkey,
1941
+ isSigner: false,
1942
+ isWritable: true,
1943
+ });
1944
+ oracleAccountMap.set(market.amm.oracle.toString(), {
1945
+ pubkey: market.amm.oracle,
1946
+ isSigner: false,
1947
+ isWritable: false,
1948
+ });
1949
+ }
1950
+ if (params.writableSpotMarketIndexes !== undefined) {
1951
+ for (const writableSpotMarketIndex of params.writableSpotMarketIndexes) {
1952
+ const spotMarketAccount = this.getSpotMarketAccount(writableSpotMarketIndex);
1953
+ spotMarketAccountMap.set(spotMarketAccount.marketIndex, {
1954
+ pubkey: spotMarketAccount.pubkey,
1955
+ isSigner: false,
1956
+ isWritable: true,
1957
+ });
1958
+ if (!spotMarketAccount.oracle.equals(web3_js_1.PublicKey.default)) {
1959
+ oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
1960
+ pubkey: spotMarketAccount.oracle,
1961
+ isSigner: false,
1962
+ isWritable: false,
1963
+ });
1964
+ }
1965
+ }
1966
+ }
1967
+ return [
1968
+ ...oracleAccountMap.values(),
1969
+ ...spotMarketAccountMap.values(),
1970
+ ...marketAccountMap.values(),
1971
+ ];
865
1972
  }
866
1973
  async updateFundingRate(oracle, marketIndex) {
867
1974
  const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getUpdateFundingRateIx(oracle, marketIndex)), [], this.opts);
@@ -882,7 +1989,7 @@ class ClearingHouse {
882
1989
  }
883
1990
  async getSettleFundingPaymentIx(userAccount) {
884
1991
  const user = (await this.program.account.user.fetch(userAccount));
885
- const userPositions = user.positions;
1992
+ const userPositions = user.perpPositions;
886
1993
  const remainingAccounts = [];
887
1994
  for (const position of userPositions) {
888
1995
  if (!(0, position_1.positionIsAvailable)(position)) {
@@ -906,9 +2013,153 @@ class ClearingHouse {
906
2013
  this.eventEmitter.emit(eventName, data);
907
2014
  }
908
2015
  getOracleDataForMarket(marketIndex) {
909
- const oracleKey = this.getMarketAccount(marketIndex).amm.oracle;
2016
+ const oracleKey = this.getPerpMarketAccount(marketIndex).amm.oracle;
2017
+ const oracleData = this.getOraclePriceDataAndSlot(oracleKey).data;
2018
+ return oracleData;
2019
+ }
2020
+ getOracleDataForSpotMarket(marketIndex) {
2021
+ const oracleKey = this.getSpotMarketAccount(marketIndex).oracle;
910
2022
  const oracleData = this.getOraclePriceDataAndSlot(oracleKey).data;
911
2023
  return oracleData;
912
2024
  }
2025
+ async initializeInsuranceFundStake(marketIndex) {
2026
+ const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getInitializeInsuranceFundStakeIx(marketIndex)), [], this.opts);
2027
+ return txSig;
2028
+ }
2029
+ async getInitializeInsuranceFundStakeIx(marketIndex) {
2030
+ const ifStakeAccountPublicKey = (0, pda_1.getInsuranceFundStakeAccountPublicKey)(this.program.programId, this.wallet.publicKey, marketIndex);
2031
+ return await this.program.instruction.initializeInsuranceFundStake(marketIndex, {
2032
+ accounts: {
2033
+ insuranceFundStake: ifStakeAccountPublicKey,
2034
+ spotMarket: this.getSpotMarketAccount(marketIndex).pubkey,
2035
+ userStats: this.getUserStatsAccountPublicKey(),
2036
+ authority: this.wallet.publicKey,
2037
+ payer: this.wallet.publicKey,
2038
+ rent: anchor.web3.SYSVAR_RENT_PUBKEY,
2039
+ systemProgram: anchor.web3.SystemProgram.programId,
2040
+ state: await this.getStatePublicKey(),
2041
+ },
2042
+ });
2043
+ }
2044
+ async addInsuranceFundStake(marketIndex, amount, collateralAccountPublicKey) {
2045
+ const spotMarket = this.getSpotMarketAccount(marketIndex);
2046
+ const ifStakeAccountPublicKey = (0, pda_1.getInsuranceFundStakeAccountPublicKey)(this.program.programId, this.wallet.publicKey, marketIndex);
2047
+ const remainingAccounts = this.getRemainingAccounts({
2048
+ writableSpotMarketIndex: marketIndex,
2049
+ });
2050
+ return await this.program.rpc.addInsuranceFundStake(marketIndex, amount, {
2051
+ accounts: {
2052
+ state: await this.getStatePublicKey(),
2053
+ spotMarket: spotMarket.pubkey,
2054
+ insuranceFundStake: ifStakeAccountPublicKey,
2055
+ userStats: this.getUserStatsAccountPublicKey(),
2056
+ authority: this.wallet.publicKey,
2057
+ insuranceFundVault: spotMarket.insuranceFundVault,
2058
+ userTokenAccount: collateralAccountPublicKey,
2059
+ tokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
2060
+ },
2061
+ remainingAccounts,
2062
+ });
2063
+ }
2064
+ async requestRemoveInsuranceFundStake(marketIndex, amount) {
2065
+ const spotMarketAccount = this.getSpotMarketAccount(marketIndex);
2066
+ const ifStakeAccountPublicKey = (0, pda_1.getInsuranceFundStakeAccountPublicKey)(this.program.programId, this.wallet.publicKey, marketIndex);
2067
+ const remainingAccounts = this.getRemainingAccounts({
2068
+ writableSpotMarketIndex: marketIndex,
2069
+ });
2070
+ return await this.program.rpc.requestRemoveInsuranceFundStake(marketIndex, amount, {
2071
+ accounts: {
2072
+ state: await this.getStatePublicKey(),
2073
+ spotMarket: spotMarketAccount.pubkey,
2074
+ insuranceFundStake: ifStakeAccountPublicKey,
2075
+ userStats: this.getUserStatsAccountPublicKey(),
2076
+ authority: this.wallet.publicKey,
2077
+ insuranceFundVault: spotMarketAccount.insuranceFundVault,
2078
+ // userTokenAccount: collateralAccountPublicKey,
2079
+ // tokenProgram: TOKEN_PROGRAM_ID,
2080
+ },
2081
+ remainingAccounts,
2082
+ });
2083
+ }
2084
+ async cancelRequestRemoveInsuranceFundStake(marketIndex) {
2085
+ const spotMarketAccount = this.getSpotMarketAccount(marketIndex);
2086
+ const ifStakeAccountPublicKey = (0, pda_1.getInsuranceFundStakeAccountPublicKey)(this.program.programId, this.wallet.publicKey, marketIndex);
2087
+ const remainingAccounts = this.getRemainingAccounts({
2088
+ writableSpotMarketIndex: marketIndex,
2089
+ });
2090
+ return await this.program.rpc.cancelRequestRemoveInsuranceFundStake(marketIndex, {
2091
+ accounts: {
2092
+ state: await this.getStatePublicKey(),
2093
+ spotMarket: spotMarketAccount.pubkey,
2094
+ insuranceFundStake: ifStakeAccountPublicKey,
2095
+ userStats: this.getUserStatsAccountPublicKey(),
2096
+ authority: this.wallet.publicKey,
2097
+ insuranceFundVault: spotMarketAccount.insuranceFundVault,
2098
+ // userTokenAccount: collateralAccountPublicKey,
2099
+ // tokenProgram: TOKEN_PROGRAM_ID,
2100
+ },
2101
+ remainingAccounts,
2102
+ });
2103
+ }
2104
+ async removeInsuranceFundStake(marketIndex, collateralAccountPublicKey) {
2105
+ const spotMarketAccount = this.getSpotMarketAccount(marketIndex);
2106
+ const ifStakeAccountPublicKey = (0, pda_1.getInsuranceFundStakeAccountPublicKey)(this.program.programId, this.wallet.publicKey, marketIndex);
2107
+ const remainingAccounts = this.getRemainingAccounts({
2108
+ writableSpotMarketIndex: marketIndex,
2109
+ });
2110
+ return await this.program.rpc.removeInsuranceFundStake(marketIndex, {
2111
+ accounts: {
2112
+ state: await this.getStatePublicKey(),
2113
+ spotMarket: spotMarketAccount.pubkey,
2114
+ insuranceFundStake: ifStakeAccountPublicKey,
2115
+ userStats: this.getUserStatsAccountPublicKey(),
2116
+ authority: this.wallet.publicKey,
2117
+ insuranceFundVault: spotMarketAccount.insuranceFundVault,
2118
+ clearingHouseSigner: this.getSignerPublicKey(),
2119
+ userTokenAccount: collateralAccountPublicKey,
2120
+ tokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
2121
+ },
2122
+ remainingAccounts,
2123
+ });
2124
+ }
2125
+ async settleRevenueToInsuranceFund(marketIndex) {
2126
+ const spotMarketAccount = this.getSpotMarketAccount(marketIndex);
2127
+ const remainingAccounts = this.getRemainingAccounts({
2128
+ writableSpotMarketIndex: marketIndex,
2129
+ });
2130
+ return await this.program.rpc.settleRevenueToInsuranceFund(marketIndex, {
2131
+ accounts: {
2132
+ state: await this.getStatePublicKey(),
2133
+ spotMarket: spotMarketAccount.pubkey,
2134
+ spotMarketVault: spotMarketAccount.vault,
2135
+ clearingHouseSigner: this.getSignerPublicKey(),
2136
+ insuranceFundVault: spotMarketAccount.insuranceFundVault,
2137
+ tokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
2138
+ },
2139
+ remainingAccounts,
2140
+ });
2141
+ }
2142
+ async resolvePerpPnlDeficit(spotMarketIndex, perpMarketIndex) {
2143
+ const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getResolvePerpPnlDeficitIx(spotMarketIndex, perpMarketIndex)), [], this.opts);
2144
+ return txSig;
2145
+ }
2146
+ async getResolvePerpPnlDeficitIx(spotMarketIndex, perpMarketIndex) {
2147
+ const remainingAccounts = this.getRemainingAccounts({
2148
+ writablePerpMarketIndex: perpMarketIndex,
2149
+ writableSpotMarketIndex: spotMarketIndex,
2150
+ });
2151
+ const spotMarket = this.getSpotMarketAccount(spotMarketIndex);
2152
+ return await this.program.instruction.resolvePerpPnlDeficit(spotMarketIndex, perpMarketIndex, {
2153
+ accounts: {
2154
+ state: await this.getStatePublicKey(),
2155
+ authority: this.wallet.publicKey,
2156
+ spotMarketVault: spotMarket.vault,
2157
+ insuranceFundVault: spotMarket.insuranceFundVault,
2158
+ clearingHouseSigner: this.getSignerPublicKey(),
2159
+ tokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
2160
+ },
2161
+ remainingAccounts: remainingAccounts,
2162
+ });
2163
+ }
913
2164
  }
914
2165
  exports.ClearingHouse = ClearingHouse;