@drift-labs/sdk 0.2.0-master.4 → 0.2.0-master.40

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 (234) hide show
  1. package/README.md +27 -27
  2. package/lib/accounts/bulkAccountLoader.d.ts +2 -0
  3. package/lib/accounts/bulkAccountLoader.js +36 -29
  4. package/lib/accounts/bulkUserStatsSubscription.d.ts +7 -0
  5. package/lib/accounts/bulkUserStatsSubscription.js +21 -0
  6. package/lib/accounts/bulkUserSubscription.d.ts +2 -2
  7. package/lib/accounts/bulkUserSubscription.js +0 -1
  8. package/lib/accounts/fetch.d.ts +2 -1
  9. package/lib/accounts/fetch.js +9 -1
  10. package/lib/accounts/{pollingClearingHouseAccountSubscriber.d.ts → pollingDriftClientAccountSubscriber.d.ts} +20 -25
  11. package/lib/accounts/{pollingClearingHouseAccountSubscriber.js → pollingDriftClientAccountSubscriber.js} +45 -49
  12. package/lib/accounts/{pollingOracleSubscriber.d.ts → pollingOracleAccountSubscriber.d.ts} +2 -2
  13. package/lib/accounts/{pollingOracleSubscriber.js → pollingOracleAccountSubscriber.js} +3 -3
  14. package/lib/accounts/pollingUserStatsAccountSubscriber.d.ts +27 -0
  15. package/lib/accounts/pollingUserStatsAccountSubscriber.js +113 -0
  16. package/lib/accounts/types.d.ts +26 -15
  17. package/lib/accounts/webSocketDriftClientAccountSubscriber.d.ts +49 -0
  18. package/lib/accounts/{webSocketClearingHouseAccountSubscriber.js → webSocketDriftClientAccountSubscriber.js} +47 -45
  19. package/lib/accounts/webSocketUserStatsAccountSubsriber.d.ts +20 -0
  20. package/lib/accounts/webSocketUserStatsAccountSubsriber.js +47 -0
  21. package/lib/addresses/marketAddresses.d.ts +1 -3
  22. package/lib/addresses/marketAddresses.js +1 -1
  23. package/lib/addresses/pda.d.ts +15 -9
  24. package/lib/addresses/pda.js +73 -35
  25. package/lib/adminClient.d.ts +65 -0
  26. package/lib/adminClient.js +637 -0
  27. package/lib/config.d.ts +9 -9
  28. package/lib/config.js +25 -21
  29. package/lib/constants/numericConstants.d.ts +30 -12
  30. package/lib/constants/numericConstants.js +41 -21
  31. package/lib/constants/perpMarkets.d.ts +18 -0
  32. package/lib/constants/{markets.js → perpMarkets.js} +7 -7
  33. package/lib/constants/spotMarkets.d.ts +19 -0
  34. package/lib/constants/spotMarkets.js +53 -0
  35. package/lib/dlob/DLOB.d.ts +82 -0
  36. package/lib/dlob/DLOB.js +696 -0
  37. package/lib/dlob/DLOBNode.d.ts +54 -0
  38. package/lib/dlob/DLOBNode.js +77 -0
  39. package/lib/dlob/NodeList.d.ts +27 -0
  40. package/lib/dlob/NodeList.js +144 -0
  41. package/lib/driftClient.d.ts +233 -0
  42. package/lib/driftClient.js +2096 -0
  43. package/lib/{clearingHouseConfig.d.ts → driftClientConfig.d.ts} +9 -9
  44. package/lib/{clearingHouseConfig.js → driftClientConfig.js} +0 -0
  45. package/lib/events/eventList.js +3 -0
  46. package/lib/events/eventSubscriber.d.ts +5 -2
  47. package/lib/events/eventSubscriber.js +25 -11
  48. package/lib/events/fetchLogs.d.ts +13 -2
  49. package/lib/events/fetchLogs.js +40 -12
  50. package/lib/events/pollingLogProvider.d.ts +2 -1
  51. package/lib/events/pollingLogProvider.js +7 -3
  52. package/lib/events/sort.js +8 -11
  53. package/lib/events/types.d.ts +9 -3
  54. package/lib/events/types.js +6 -0
  55. package/lib/events/webSocketLogProvider.js +1 -1
  56. package/lib/examples/makeTradeExample.js +30 -18
  57. package/lib/factory/bigNum.d.ts +8 -4
  58. package/lib/factory/bigNum.js +109 -19
  59. package/lib/idl/drift.json +8250 -0
  60. package/lib/idl/{mock_usdc_faucet.json → token_faucet.json} +46 -23
  61. package/lib/index.d.ts +30 -13
  62. package/lib/index.js +30 -13
  63. package/lib/math/amm.d.ts +9 -6
  64. package/lib/math/amm.js +91 -38
  65. package/lib/math/conversion.js +1 -1
  66. package/lib/math/exchangeStatus.d.ts +4 -0
  67. package/lib/math/exchangeStatus.js +18 -0
  68. package/lib/math/funding.d.ts +6 -6
  69. package/lib/math/funding.js +23 -21
  70. package/lib/math/insurance.d.ts +4 -0
  71. package/lib/math/insurance.js +27 -0
  72. package/lib/math/margin.d.ts +11 -0
  73. package/lib/math/margin.js +82 -0
  74. package/lib/math/market.d.ts +14 -9
  75. package/lib/math/market.js +70 -10
  76. package/lib/math/oracles.d.ts +4 -0
  77. package/lib/math/oracles.js +36 -8
  78. package/lib/math/orders.d.ts +14 -6
  79. package/lib/math/orders.js +90 -17
  80. package/lib/math/position.d.ts +27 -13
  81. package/lib/math/position.js +92 -36
  82. package/lib/math/repeg.js +17 -8
  83. package/lib/math/spotBalance.d.ts +22 -0
  84. package/lib/math/spotBalance.js +192 -0
  85. package/lib/math/spotMarket.d.ts +4 -0
  86. package/lib/math/spotMarket.js +8 -0
  87. package/lib/math/spotPosition.d.ts +6 -0
  88. package/lib/math/spotPosition.js +23 -0
  89. package/lib/math/trade.d.ts +10 -10
  90. package/lib/math/trade.js +27 -31
  91. package/lib/oracles/pythClient.js +1 -1
  92. package/lib/oracles/quoteAssetOracleClient.js +1 -1
  93. package/lib/oracles/switchboardClient.js +1 -1
  94. package/lib/orderParams.d.ts +4 -4
  95. package/lib/orderParams.js +12 -4
  96. package/lib/serum/serumFulfillmentConfigMap.d.ts +10 -0
  97. package/lib/serum/serumFulfillmentConfigMap.js +17 -0
  98. package/lib/serum/serumSubscriber.d.ts +27 -0
  99. package/lib/serum/serumSubscriber.js +56 -0
  100. package/lib/serum/types.d.ts +11 -0
  101. package/lib/{clearingHouseUserConfig.js → serum/types.js} +0 -0
  102. package/lib/slot/SlotSubscriber.d.ts +7 -0
  103. package/lib/slot/SlotSubscriber.js +3 -0
  104. package/lib/{mockUSDCFaucet.d.ts → tokenFaucet.d.ts} +8 -5
  105. package/lib/{mockUSDCFaucet.js → tokenFaucet.js} +63 -51
  106. package/lib/tx/retryTxSender.d.ts +1 -1
  107. package/lib/tx/retryTxSender.js +13 -4
  108. package/lib/tx/types.d.ts +1 -1
  109. package/lib/tx/utils.js +1 -1
  110. package/lib/types.d.ts +589 -196
  111. package/lib/types.js +108 -17
  112. package/lib/user.d.ts +226 -0
  113. package/lib/user.js +949 -0
  114. package/lib/userConfig.d.ts +14 -0
  115. package/lib/userConfig.js +2 -0
  116. package/lib/userMap/userMap.d.ts +41 -0
  117. package/lib/userMap/userMap.js +85 -0
  118. package/lib/userMap/userStatsMap.d.ts +19 -0
  119. package/lib/userMap/userStatsMap.js +68 -0
  120. package/lib/userName.d.ts +1 -0
  121. package/lib/userName.js +3 -2
  122. package/lib/userStats.d.ts +18 -0
  123. package/lib/userStats.js +49 -0
  124. package/lib/userStatsConfig.d.ts +14 -0
  125. package/lib/userStatsConfig.js +2 -0
  126. package/lib/util/computeUnits.js +1 -1
  127. package/lib/util/getTokenAddress.d.ts +2 -0
  128. package/lib/util/getTokenAddress.js +9 -0
  129. package/package.json +10 -3
  130. package/src/accounts/bulkAccountLoader.ts +44 -34
  131. package/src/accounts/bulkUserStatsSubscription.ts +33 -0
  132. package/src/accounts/bulkUserSubscription.ts +2 -3
  133. package/src/accounts/fetch.ts +27 -2
  134. package/src/accounts/{pollingClearingHouseAccountSubscriber.ts → pollingDriftClientAccountSubscriber.ts} +65 -75
  135. package/src/accounts/{pollingOracleSubscriber.ts → pollingOracleAccountSubscriber.ts} +2 -2
  136. package/src/accounts/pollingUserStatsAccountSubscriber.ts +172 -0
  137. package/src/accounts/types.ts +35 -15
  138. package/src/accounts/{webSocketClearingHouseAccountSubscriber.ts → webSocketDriftClientAccountSubscriber.ts} +78 -73
  139. package/src/accounts/webSocketUserStatsAccountSubsriber.ts +80 -0
  140. package/src/addresses/marketAddresses.ts +3 -4
  141. package/src/addresses/pda.ts +105 -33
  142. package/src/adminClient.ts +1207 -0
  143. package/src/config.ts +37 -31
  144. package/src/constants/numericConstants.ts +58 -24
  145. package/src/constants/{markets.ts → perpMarkets.ts} +10 -10
  146. package/src/constants/spotMarkets.ts +73 -0
  147. package/src/dlob/DLOB.ts +1123 -0
  148. package/src/dlob/DLOBNode.ts +155 -0
  149. package/src/dlob/NodeList.ts +195 -0
  150. package/src/driftClient.ts +3564 -0
  151. package/src/{clearingHouseConfig.ts → driftClientConfig.ts} +9 -8
  152. package/src/events/eventList.ts +3 -0
  153. package/src/events/eventSubscriber.ts +36 -14
  154. package/src/events/fetchLogs.ts +55 -13
  155. package/src/events/pollingLogProvider.ts +11 -3
  156. package/src/events/sort.ts +11 -15
  157. package/src/events/types.ts +21 -2
  158. package/src/events/webSocketLogProvider.ts +1 -1
  159. package/src/examples/makeTradeExample.ts +44 -28
  160. package/src/factory/bigNum.ts +150 -22
  161. package/src/idl/drift.json +8250 -0
  162. package/src/idl/pyth.json +98 -2
  163. package/src/idl/{mock_usdc_faucet.json → token_faucet.json} +46 -23
  164. package/src/index.ts +30 -13
  165. package/src/math/amm.ts +161 -48
  166. package/src/math/conversion.ts +2 -2
  167. package/src/math/exchangeStatus.ts +31 -0
  168. package/src/math/funding.ts +41 -31
  169. package/src/math/insurance.ts +35 -0
  170. package/src/math/margin.ts +133 -0
  171. package/src/math/market.ts +143 -14
  172. package/src/math/oracles.ts +63 -9
  173. package/src/math/orders.ts +163 -26
  174. package/src/math/position.ts +136 -58
  175. package/src/math/repeg.ts +19 -9
  176. package/src/math/spotBalance.ts +319 -0
  177. package/src/math/spotMarket.ts +9 -0
  178. package/src/math/spotPosition.ts +47 -0
  179. package/src/math/trade.ts +33 -37
  180. package/src/oracles/pythClient.ts +2 -2
  181. package/src/oracles/quoteAssetOracleClient.ts +2 -2
  182. package/src/oracles/switchboardClient.ts +2 -2
  183. package/src/orderParams.ts +16 -8
  184. package/src/serum/serumFulfillmentConfigMap.ts +26 -0
  185. package/src/serum/serumSubscriber.ts +99 -0
  186. package/src/serum/types.ts +13 -0
  187. package/src/slot/SlotSubscriber.ts +11 -1
  188. package/src/{mockUSDCFaucet.ts → tokenFaucet.ts} +82 -70
  189. package/src/tx/retryTxSender.ts +16 -5
  190. package/src/tx/types.ts +2 -1
  191. package/src/tx/utils.ts +1 -1
  192. package/src/types.ts +572 -178
  193. package/src/user.ts +1582 -0
  194. package/src/{clearingHouseUserConfig.ts → userConfig.ts} +5 -5
  195. package/src/userMap/userMap.ts +124 -0
  196. package/src/userMap/userStatsMap.ts +108 -0
  197. package/src/userName.ts +2 -1
  198. package/src/userStats.ts +75 -0
  199. package/src/userStatsConfig.ts +18 -0
  200. package/src/util/computeUnits.ts +1 -1
  201. package/src/util/getTokenAddress.ts +18 -0
  202. package/tests/bn/test.ts +46 -11
  203. package/tests/dlob/helpers.ts +611 -0
  204. package/tests/dlob/test.ts +4588 -0
  205. package/lib/accounts/webSocketClearingHouseAccountSubscriber.d.ts +0 -49
  206. package/lib/admin.d.ts +0 -44
  207. package/lib/admin.js +0 -433
  208. package/lib/clearingHouse.d.ts +0 -133
  209. package/lib/clearingHouse.js +0 -931
  210. package/lib/clearingHouseUser.d.ts +0 -187
  211. package/lib/clearingHouseUser.js +0 -643
  212. package/lib/clearingHouseUserConfig.d.ts +0 -14
  213. package/lib/constants/banks.d.ts +0 -16
  214. package/lib/constants/banks.js +0 -34
  215. package/lib/constants/markets.d.ts +0 -19
  216. package/lib/idl/clearing_house.json +0 -3998
  217. package/lib/math/bankBalance.d.ts +0 -9
  218. package/lib/math/bankBalance.js +0 -75
  219. package/lib/math/state.d.ts +0 -8
  220. package/lib/math/state.js +0 -15
  221. package/lib/orders.d.ts +0 -8
  222. package/lib/orders.js +0 -134
  223. package/src/admin.ts +0 -722
  224. package/src/clearingHouse.ts +0 -1451
  225. package/src/clearingHouseUser.ts +0 -989
  226. package/src/constants/banks.ts +0 -43
  227. package/src/idl/clearing_house.json +0 -3998
  228. package/src/math/bankBalance.ts +0 -112
  229. package/src/math/state.ts +0 -14
  230. package/src/math/utils.js +0 -27
  231. package/src/math/utils.js.map +0 -1
  232. package/src/orders.ts +0 -244
  233. package/src/util/computeUnits.js +0 -17
  234. package/src/util/computeUnits.js.map +0 -1
@@ -1,1451 +0,0 @@
1
- import { AnchorProvider, BN, Idl, Program } from '@project-serum/anchor';
2
- import { TOKEN_PROGRAM_ID } from '@solana/spl-token';
3
- import {
4
- StateAccount,
5
- IWallet,
6
- PositionDirection,
7
- UserAccount,
8
- MarketAccount,
9
- OrderParams,
10
- Order,
11
- BankAccount,
12
- UserBankBalance,
13
- MakerInfo,
14
- OptionalOrderParams,
15
- DefaultOrderParams,
16
- OrderType,
17
- } from './types';
18
- import * as anchor from '@project-serum/anchor';
19
- import clearingHouseIDL from './idl/clearing_house.json';
20
-
21
- import {
22
- Connection,
23
- PublicKey,
24
- TransactionSignature,
25
- ConfirmOptions,
26
- Transaction,
27
- TransactionInstruction,
28
- AccountMeta,
29
- } from '@solana/web3.js';
30
-
31
- import { MockUSDCFaucet } from './mockUSDCFaucet';
32
- import { EventEmitter } from 'events';
33
- import StrictEventEmitter from 'strict-event-emitter-types';
34
- import {
35
- getClearingHouseStateAccountPublicKey,
36
- getMarketPublicKey,
37
- getUserAccountPublicKey,
38
- getUserAccountPublicKeySync,
39
- } from './addresses/pda';
40
- import {
41
- ClearingHouseAccountSubscriber,
42
- ClearingHouseAccountEvents,
43
- DataAndSlot,
44
- } from './accounts/types';
45
- import { TxSender } from './tx/types';
46
- import { wrapInTx } from './tx/utils';
47
- import { QUOTE_ASSET_BANK_INDEX, ZERO } from './constants/numericConstants';
48
- import { findDirectionToClose, positionIsAvailable } from './math/position';
49
- import { getTokenAmount } from './math/bankBalance';
50
- import { DEFAULT_USER_NAME, encodeName } from './userName';
51
- import { OraclePriceData } from './oracles/types';
52
- import { ClearingHouseConfig } from './clearingHouseConfig';
53
- import { PollingClearingHouseAccountSubscriber } from './accounts/pollingClearingHouseAccountSubscriber';
54
- import { WebSocketClearingHouseAccountSubscriber } from './accounts/webSocketClearingHouseAccountSubscriber';
55
- import { RetryTxSender } from './tx/retryTxSender';
56
- import { ClearingHouseUser } from './clearingHouseUser';
57
- import { ClearingHouseUserAccountSubscriptionConfig } from './clearingHouseUserConfig';
58
- import { getMarketsBanksAndOraclesForSubscription } from './config';
59
-
60
- /**
61
- * # ClearingHouse
62
- * 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.
63
- */
64
- export class ClearingHouse {
65
- connection: Connection;
66
- wallet: IWallet;
67
- public program: Program;
68
- provider: AnchorProvider;
69
- opts?: ConfirmOptions;
70
- users = new Map<number, ClearingHouseUser>();
71
- activeUserId: number;
72
- userAccountSubscriptionConfig: ClearingHouseUserAccountSubscriptionConfig;
73
- accountSubscriber: ClearingHouseAccountSubscriber;
74
- eventEmitter: StrictEventEmitter<EventEmitter, ClearingHouseAccountEvents>;
75
- _isSubscribed = false;
76
- txSender: TxSender;
77
- marketLastSlotCache = new Map<number, number>();
78
-
79
- public get isSubscribed() {
80
- return this._isSubscribed && this.accountSubscriber.isSubscribed;
81
- }
82
-
83
- public set isSubscribed(val: boolean) {
84
- this._isSubscribed = val;
85
- }
86
-
87
- public constructor(config: ClearingHouseConfig) {
88
- this.connection = config.connection;
89
- this.wallet = config.wallet;
90
- this.opts = config.opts || AnchorProvider.defaultOptions();
91
- this.provider = new AnchorProvider(
92
- config.connection,
93
- config.wallet,
94
- this.opts
95
- );
96
- this.program = new Program(
97
- clearingHouseIDL as Idl,
98
- config.programID,
99
- this.provider
100
- );
101
-
102
- const userIds = config.userIds ?? [0];
103
- this.activeUserId = config.activeUserId ?? userIds[0];
104
- this.userAccountSubscriptionConfig =
105
- config.accountSubscription?.type === 'polling'
106
- ? {
107
- type: 'polling',
108
- accountLoader: config.accountSubscription.accountLoader,
109
- }
110
- : {
111
- type: 'websocket',
112
- };
113
- this.createUsers(userIds, this.userAccountSubscriptionConfig);
114
-
115
- let marketIndexes = config.marketIndexes;
116
- let bankIndexes = config.bankIndexes;
117
- let oracleInfos = config.oracleInfos;
118
- if (config.env) {
119
- const {
120
- marketIndexes: envMarketIndexes,
121
- bankIndexes: envBankIndexes,
122
- oracleInfos: envOralceInfos,
123
- } = getMarketsBanksAndOraclesForSubscription(config.env);
124
- marketIndexes = marketIndexes ? marketIndexes : envMarketIndexes;
125
- bankIndexes = bankIndexes ? bankIndexes : envBankIndexes;
126
- oracleInfos = oracleInfos ? oracleInfos : envOralceInfos;
127
- }
128
-
129
- if (config.accountSubscription?.type === 'polling') {
130
- this.accountSubscriber = new PollingClearingHouseAccountSubscriber(
131
- this.program,
132
- config.accountSubscription.accountLoader,
133
- marketIndexes ?? [],
134
- bankIndexes ?? [],
135
- oracleInfos ?? []
136
- );
137
- } else {
138
- this.accountSubscriber = new WebSocketClearingHouseAccountSubscriber(
139
- this.program,
140
- config.marketIndexes ?? [],
141
- config.bankIndexes ?? [],
142
- config.oracleInfos ?? []
143
- );
144
- }
145
- this.eventEmitter = this.accountSubscriber.eventEmitter;
146
- this.txSender = new RetryTxSender(
147
- this.provider,
148
- config.txSenderConfig?.timeout,
149
- config.txSenderConfig?.retrySleep,
150
- config.txSenderConfig?.additionalConnections
151
- );
152
- }
153
-
154
- createUsers(
155
- userIds: number[],
156
- accountSubscriptionConfig: ClearingHouseUserAccountSubscriptionConfig
157
- ): void {
158
- for (const userId of userIds) {
159
- const user = this.createUser(userId, accountSubscriptionConfig);
160
- this.users.set(userId, user);
161
- }
162
- }
163
-
164
- createUser(
165
- userId: number,
166
- accountSubscriptionConfig: ClearingHouseUserAccountSubscriptionConfig
167
- ): ClearingHouseUser {
168
- const userAccountPublicKey = getUserAccountPublicKeySync(
169
- this.program.programId,
170
- this.wallet.publicKey,
171
- userId
172
- );
173
-
174
- return new ClearingHouseUser({
175
- clearingHouse: this,
176
- userAccountPublicKey,
177
- accountSubscription: accountSubscriptionConfig,
178
- });
179
- }
180
-
181
- public async subscribe(): Promise<boolean> {
182
- const subscribePromises = this.subscribeUsers().concat(
183
- this.accountSubscriber.subscribe()
184
- );
185
- this.isSubscribed = (await Promise.all(subscribePromises)).reduce(
186
- (success, prevSuccess) => success && prevSuccess
187
- );
188
- return this.isSubscribed;
189
- }
190
-
191
- subscribeUsers(): Promise<boolean>[] {
192
- return [...this.users.values()].map((user) => user.subscribe());
193
- }
194
-
195
- /**
196
- * Forces the accountSubscriber to fetch account updates from rpc
197
- */
198
- public async fetchAccounts(): Promise<void> {
199
- await Promise.all(
200
- [...this.users.values()]
201
- .map((user) => user.fetchAccounts())
202
- .concat(this.accountSubscriber.fetch())
203
- );
204
- }
205
-
206
- public async unsubscribe(): Promise<void> {
207
- const unsubscribePromises = this.unsubscribeUsers().concat(
208
- this.accountSubscriber.unsubscribe()
209
- );
210
- await Promise.all(unsubscribePromises);
211
- this.isSubscribed = false;
212
- }
213
-
214
- unsubscribeUsers(): Promise<void>[] {
215
- return [...this.users.values()].map((user) => user.unsubscribe());
216
- }
217
-
218
- statePublicKey?: PublicKey;
219
- public async getStatePublicKey(): Promise<PublicKey> {
220
- if (this.statePublicKey) {
221
- return this.statePublicKey;
222
- }
223
- this.statePublicKey = await getClearingHouseStateAccountPublicKey(
224
- this.program.programId
225
- );
226
- return this.statePublicKey;
227
- }
228
-
229
- public getStateAccount(): StateAccount {
230
- return this.accountSubscriber.getStateAccountAndSlot().data;
231
- }
232
-
233
- public getMarketAccount(marketIndex: BN | number): MarketAccount | undefined {
234
- marketIndex = marketIndex instanceof BN ? marketIndex : new BN(marketIndex);
235
- return this.accountSubscriber.getMarketAccountAndSlot(marketIndex)?.data;
236
- }
237
-
238
- public getMarketAccounts(): MarketAccount[] {
239
- return this.accountSubscriber
240
- .getMarketAccountsAndSlots()
241
- .map((value) => value.data);
242
- }
243
-
244
- public getBankAccount(bankIndex: BN | number): BankAccount | undefined {
245
- bankIndex = bankIndex instanceof BN ? bankIndex : new BN(bankIndex);
246
- return this.accountSubscriber.getBankAccountAndSlot(bankIndex).data;
247
- }
248
-
249
- public getQuoteAssetBankAccount(): BankAccount {
250
- return this.accountSubscriber.getBankAccountAndSlot(QUOTE_ASSET_BANK_INDEX)
251
- .data;
252
- }
253
-
254
- public getOraclePriceDataAndSlot(
255
- oraclePublicKey: PublicKey
256
- ): DataAndSlot<OraclePriceData> | undefined {
257
- return this.accountSubscriber.getOraclePriceDataAndSlot(oraclePublicKey);
258
- }
259
-
260
- /**
261
- * Update the wallet to use for clearing house transactions and linked user account
262
- * @param newWallet
263
- * @param userIds
264
- * @param activeUserId
265
- */
266
- public async updateWallet(
267
- newWallet: IWallet,
268
- userIds = [0],
269
- activeUserId = 0
270
- ): Promise<void> {
271
- const newProvider = new AnchorProvider(
272
- this.connection,
273
- newWallet,
274
- this.opts
275
- );
276
- const newProgram = new Program(
277
- clearingHouseIDL as Idl,
278
- this.program.programId,
279
- newProvider
280
- );
281
-
282
- // Update provider for txSender with new wallet details
283
- this.txSender.provider = newProvider;
284
-
285
- this.wallet = newWallet;
286
- this.provider = newProvider;
287
- this.program = newProgram;
288
-
289
- if (this.isSubscribed) {
290
- await Promise.all(this.unsubscribeUsers());
291
- }
292
- this.users.clear();
293
- this.createUsers(userIds, this.userAccountSubscriptionConfig);
294
- if (this.isSubscribed) {
295
- await Promise.all(this.subscribeUsers());
296
- }
297
-
298
- this.activeUserId = activeUserId;
299
- }
300
-
301
- public async switchActiveUser(userId: number): Promise<void> {
302
- this.activeUserId = userId;
303
- }
304
-
305
- public async addUser(userId: number): Promise<void> {
306
- if (this.users.has(userId)) {
307
- return;
308
- }
309
-
310
- const user = this.createUser(userId, this.userAccountSubscriptionConfig);
311
- await user.subscribe();
312
- this.users.set(userId, user);
313
- }
314
-
315
- public async initializeUserAccount(
316
- userId = 0,
317
- name = DEFAULT_USER_NAME
318
- ): Promise<[TransactionSignature, PublicKey]> {
319
- const [userAccountPublicKey, initializeUserAccountIx] =
320
- await this.getInitializeUserInstructions(userId, name);
321
-
322
- const tx = new Transaction().add(initializeUserAccountIx);
323
- const { txSig } = await this.txSender.send(tx, [], this.opts);
324
- return [txSig, userAccountPublicKey];
325
- }
326
-
327
- async getInitializeUserInstructions(
328
- userId = 0,
329
- name = DEFAULT_USER_NAME
330
- ): Promise<[PublicKey, TransactionInstruction]> {
331
- const userAccountPublicKey = await getUserAccountPublicKey(
332
- this.program.programId,
333
- this.wallet.publicKey,
334
- userId
335
- );
336
-
337
- const nameBuffer = encodeName(name);
338
- const initializeUserAccountIx =
339
- await this.program.instruction.initializeUser(userId, nameBuffer, {
340
- accounts: {
341
- user: userAccountPublicKey,
342
- authority: this.wallet.publicKey,
343
- payer: this.wallet.publicKey,
344
- rent: anchor.web3.SYSVAR_RENT_PUBKEY,
345
- systemProgram: anchor.web3.SystemProgram.programId,
346
- state: await this.getStatePublicKey(),
347
- },
348
- });
349
-
350
- return [userAccountPublicKey, initializeUserAccountIx];
351
- }
352
-
353
- public getUser(userId?: number): ClearingHouseUser {
354
- userId = userId ?? this.activeUserId;
355
- if (!this.users.has(userId)) {
356
- throw new Error(`Clearing House has no user for user id ${userId}`);
357
- }
358
- return this.users.get(userId);
359
- }
360
-
361
- public getUsers(): ClearingHouseUser[] {
362
- return [...this.users.values()];
363
- }
364
-
365
- public async getUserAccountPublicKey(): Promise<PublicKey> {
366
- return this.getUser().userAccountPublicKey;
367
- }
368
-
369
- public getUserAccount(userId?: number): UserAccount | undefined {
370
- return this.getUser(userId).getUserAccount();
371
- }
372
-
373
- public getUserAccountAndSlot(
374
- userId?: number
375
- ): DataAndSlot<UserAccount> | undefined {
376
- return this.getUser(userId).getUserAccountAndSlot();
377
- }
378
-
379
- public getUserBankBalance(
380
- bankIndex: number | BN
381
- ): UserBankBalance | undefined {
382
- const bankIndexBN = bankIndex instanceof BN ? bankIndex : new BN(bankIndex);
383
- return this.getUserAccount().bankBalances.find((bankBalance) =>
384
- bankBalance.bankIndex.eq(bankIndexBN)
385
- );
386
- }
387
-
388
- public getQuoteAssetTokenAmount(): BN {
389
- const bank = this.getBankAccount(QUOTE_ASSET_BANK_INDEX);
390
- const userBankBalance = this.getUserBankBalance(QUOTE_ASSET_BANK_INDEX);
391
- return getTokenAmount(
392
- userBankBalance.balance,
393
- bank,
394
- userBankBalance.balanceType
395
- );
396
- }
397
-
398
- getRemainingAccounts(params: {
399
- writableMarketIndex?: BN;
400
- writableBankIndex?: BN;
401
- }): AccountMeta[] {
402
- const userAccountAndSlot = this.getUserAccountAndSlot();
403
- if (!userAccountAndSlot) {
404
- throw Error(
405
- 'No user account found. Most likely user account does not exist or failed to fetch account'
406
- );
407
- }
408
- const { data: userAccount, slot: lastUserPositionsSlot } =
409
- userAccountAndSlot;
410
-
411
- const oracleAccountMap = new Map<string, AccountMeta>();
412
- const bankAccountMap = new Map<number, AccountMeta>();
413
- const marketAccountMap = new Map<number, AccountMeta>();
414
- for (const [marketIndexNum, slot] of this.marketLastSlotCache.entries()) {
415
- // if cache has more recent slot than user positions account slot, add market to remaining accounts
416
- // otherwise remove from slot
417
- if (slot > lastUserPositionsSlot) {
418
- const marketAccount = this.getMarketAccount(marketIndexNum);
419
- marketAccountMap.set(marketIndexNum, {
420
- pubkey: marketAccount.pubkey,
421
- isSigner: false,
422
- isWritable: false,
423
- });
424
- oracleAccountMap.set(marketAccount.amm.oracle.toString(), {
425
- pubkey: marketAccount.amm.oracle,
426
- isSigner: false,
427
- isWritable: false,
428
- });
429
- } else {
430
- this.marketLastSlotCache.delete(marketIndexNum);
431
- }
432
- }
433
-
434
- for (const position of userAccount.positions) {
435
- if (!positionIsAvailable(position)) {
436
- const marketIndexNum = position.marketIndex.toNumber();
437
- const marketAccount = this.getMarketAccount(marketIndexNum);
438
- marketAccountMap.set(marketIndexNum, {
439
- pubkey: marketAccount.pubkey,
440
- isSigner: false,
441
- // isWritable: false, // TODO
442
- isWritable: true,
443
- });
444
- oracleAccountMap.set(marketAccount.pubkey.toString(), {
445
- pubkey: marketAccount.amm.oracle,
446
- isSigner: false,
447
- isWritable: false,
448
- });
449
- }
450
- }
451
-
452
- if (params.writableMarketIndex) {
453
- const marketAccount = this.getMarketAccount(
454
- params.writableMarketIndex.toNumber()
455
- );
456
- marketAccountMap.set(params.writableMarketIndex.toNumber(), {
457
- pubkey: marketAccount.pubkey,
458
- isSigner: false,
459
- isWritable: true,
460
- });
461
- oracleAccountMap.set(marketAccount.amm.oracle.toString(), {
462
- pubkey: marketAccount.amm.oracle,
463
- isSigner: false,
464
- isWritable: false,
465
- });
466
- }
467
-
468
- for (const userBankBalance of userAccount.bankBalances) {
469
- if (!userBankBalance.balance.eq(ZERO)) {
470
- const bankAccount = this.getBankAccount(userBankBalance.bankIndex);
471
- bankAccountMap.set(userBankBalance.bankIndex.toNumber(), {
472
- pubkey: bankAccount.pubkey,
473
- isSigner: false,
474
- isWritable: false,
475
- });
476
- if (!bankAccount.bankIndex.eq(ZERO)) {
477
- oracleAccountMap.set(bankAccount.oracle.toString(), {
478
- pubkey: bankAccount.oracle,
479
- isSigner: false,
480
- isWritable: false,
481
- });
482
- }
483
- }
484
- }
485
-
486
- if (params.writableBankIndex) {
487
- const bankAccount = this.getBankAccount(params.writableBankIndex);
488
- bankAccountMap.set(params.writableBankIndex.toNumber(), {
489
- pubkey: bankAccount.pubkey,
490
- isSigner: false,
491
- isWritable: true,
492
- });
493
- if (!bankAccount.bankIndex.eq(ZERO)) {
494
- oracleAccountMap.set(bankAccount.oracle.toString(), {
495
- pubkey: bankAccount.oracle,
496
- isSigner: false,
497
- isWritable: false,
498
- });
499
- }
500
- }
501
-
502
- return [
503
- ...oracleAccountMap.values(),
504
- ...bankAccountMap.values(),
505
- ...marketAccountMap.values(),
506
- ];
507
- }
508
-
509
- public getOrder(orderId: BN | number): Order | undefined {
510
- const orderIdBN = orderId instanceof BN ? orderId : new BN(orderId);
511
- return this.getUserAccount()?.orders.find((order) =>
512
- order.orderId.eq(orderIdBN)
513
- );
514
- }
515
-
516
- public getOrderByUserId(userOrderId: number): Order | undefined {
517
- return this.getUserAccount()?.orders.find(
518
- (order) => order.userOrderId === userOrderId
519
- );
520
- }
521
-
522
- public async deposit(
523
- amount: BN,
524
- bankIndex: BN,
525
- collateralAccountPublicKey: PublicKey,
526
- userId?: number,
527
- reduceOnly = false
528
- ): Promise<TransactionSignature> {
529
- const depositCollateralIx = await this.getDepositInstruction(
530
- amount,
531
- bankIndex,
532
- collateralAccountPublicKey,
533
- userId,
534
- reduceOnly,
535
- true
536
- );
537
-
538
- const tx = new Transaction().add(depositCollateralIx);
539
-
540
- const { txSig } = await this.txSender.send(tx);
541
- return txSig;
542
- }
543
-
544
- async getDepositInstruction(
545
- amount: BN,
546
- bankIndex: BN,
547
- userTokenAccount: PublicKey,
548
- userId?: number,
549
- reduceOnly = false,
550
- userInitialized = true
551
- ): Promise<TransactionInstruction> {
552
- const userAccountPublicKey = userId
553
- ? await getUserAccountPublicKey(
554
- this.program.programId,
555
- this.wallet.publicKey,
556
- userId
557
- )
558
- : await this.getUserAccountPublicKey();
559
-
560
- let remainingAccounts = [];
561
- if (userInitialized) {
562
- remainingAccounts = this.getRemainingAccounts({
563
- writableBankIndex: bankIndex,
564
- });
565
- } else {
566
- remainingAccounts = [
567
- {
568
- pubkey: this.getBankAccount(bankIndex).pubkey,
569
- isSigner: false,
570
- isWritable: true,
571
- },
572
- ];
573
- }
574
-
575
- const bank = this.getBankAccount(bankIndex);
576
-
577
- return await this.program.instruction.deposit(
578
- bankIndex,
579
- amount,
580
- reduceOnly,
581
- {
582
- accounts: {
583
- state: await this.getStatePublicKey(),
584
- bank: bank.pubkey,
585
- bankVault: bank.vault,
586
- user: userAccountPublicKey,
587
- userTokenAccount: userTokenAccount,
588
- authority: this.wallet.publicKey,
589
- tokenProgram: TOKEN_PROGRAM_ID,
590
- },
591
- remainingAccounts,
592
- }
593
- );
594
- }
595
-
596
- /**
597
- * Creates the Clearing House User account for a user, and deposits some initial collateral
598
- * @param userId
599
- * @param name
600
- * @param amount
601
- * @param userTokenAccount
602
- * @param fromUserId
603
- * @returns
604
- */
605
- public async initializeUserAccountAndDepositCollateral(
606
- amount: BN,
607
- userTokenAccount: PublicKey,
608
- bankIndex = new BN(0),
609
- userId = 0,
610
- name = DEFAULT_USER_NAME,
611
- fromUserId?: number
612
- ): Promise<[TransactionSignature, PublicKey]> {
613
- const [userAccountPublicKey, initializeUserAccountIx] =
614
- await this.getInitializeUserInstructions(userId, name);
615
-
616
- const depositCollateralIx =
617
- fromUserId != null
618
- ? await this.getTransferDepositIx(amount, bankIndex, fromUserId, userId)
619
- : await this.getDepositInstruction(
620
- amount,
621
- bankIndex,
622
- userTokenAccount,
623
- userId,
624
- false,
625
- false
626
- );
627
-
628
- const tx = new Transaction()
629
- .add(initializeUserAccountIx)
630
- .add(depositCollateralIx);
631
-
632
- const { txSig } = await this.txSender.send(tx, []);
633
-
634
- return [txSig, userAccountPublicKey];
635
- }
636
-
637
- public async initializeUserAccountForDevnet(
638
- userId = 0,
639
- name = DEFAULT_USER_NAME,
640
- mockUSDCFaucet: MockUSDCFaucet,
641
- amount: BN
642
- ): Promise<[TransactionSignature, PublicKey]> {
643
- const [associateTokenPublicKey, createAssociatedAccountIx, mintToIx] =
644
- await mockUSDCFaucet.createAssociatedTokenAccountAndMintToInstructions(
645
- this.wallet.publicKey,
646
- amount
647
- );
648
-
649
- const [userAccountPublicKey, initializeUserAccountIx] =
650
- await this.getInitializeUserInstructions(userId, name);
651
-
652
- const depositCollateralIx = await this.getDepositInstruction(
653
- amount,
654
- new BN(0),
655
- associateTokenPublicKey,
656
- userId,
657
- false,
658
- false
659
- );
660
-
661
- const tx = new Transaction()
662
- .add(createAssociatedAccountIx)
663
- .add(mintToIx)
664
- .add(initializeUserAccountIx)
665
- .add(depositCollateralIx);
666
-
667
- const txSig = await this.program.provider.sendAndConfirm(tx, []);
668
-
669
- return [txSig, userAccountPublicKey];
670
- }
671
-
672
- public async withdraw(
673
- amount: BN,
674
- bankIndex: BN,
675
- userTokenAccount: PublicKey,
676
- reduceOnly = false
677
- ): Promise<TransactionSignature> {
678
- const { txSig } = await this.txSender.send(
679
- wrapInTx(
680
- await this.getWithdrawIx(
681
- amount,
682
- bankIndex,
683
- userTokenAccount,
684
- reduceOnly
685
- )
686
- ),
687
- [],
688
- this.opts
689
- );
690
- return txSig;
691
- }
692
-
693
- public async getWithdrawIx(
694
- amount: BN,
695
- bankIndex: BN,
696
- userTokenAccount: PublicKey,
697
- reduceOnly = false
698
- ): Promise<TransactionInstruction> {
699
- const userAccountPublicKey = await this.getUserAccountPublicKey();
700
-
701
- const remainingAccounts = this.getRemainingAccounts({
702
- writableBankIndex: bankIndex,
703
- });
704
-
705
- const bank = this.getBankAccount(bankIndex);
706
-
707
- return await this.program.instruction.withdraw(
708
- bankIndex,
709
- amount,
710
- reduceOnly,
711
- {
712
- accounts: {
713
- state: await this.getStatePublicKey(),
714
- bank: bank.pubkey,
715
- bankVault: bank.vault,
716
- bankVaultAuthority: bank.vaultAuthority,
717
- user: userAccountPublicKey,
718
- userTokenAccount: userTokenAccount,
719
- authority: this.wallet.publicKey,
720
- tokenProgram: TOKEN_PROGRAM_ID,
721
- },
722
- remainingAccounts,
723
- }
724
- );
725
- }
726
-
727
- public async transferDeposit(
728
- amount: BN,
729
- bankIndex: BN,
730
- fromUserId: number,
731
- toUserId: number
732
- ): Promise<TransactionSignature> {
733
- const { txSig } = await this.txSender.send(
734
- wrapInTx(
735
- await this.getTransferDepositIx(amount, bankIndex, fromUserId, toUserId)
736
- ),
737
- [],
738
- this.opts
739
- );
740
- return txSig;
741
- }
742
-
743
- public async getTransferDepositIx(
744
- amount: BN,
745
- bankIndex: BN,
746
- fromUserId: number,
747
- toUserId: number
748
- ): Promise<TransactionInstruction> {
749
- const fromUser = await getUserAccountPublicKey(
750
- this.program.programId,
751
- this.wallet.publicKey,
752
- fromUserId
753
- );
754
- const toUser = await getUserAccountPublicKey(
755
- this.program.programId,
756
- this.wallet.publicKey,
757
- toUserId
758
- );
759
-
760
- const remainingAccounts = this.getRemainingAccounts({
761
- writableBankIndex: bankIndex,
762
- });
763
-
764
- return await this.program.instruction.transferDeposit(bankIndex, amount, {
765
- accounts: {
766
- authority: this.wallet.publicKey,
767
- fromUser,
768
- toUser,
769
- state: await this.getStatePublicKey(),
770
- },
771
- remainingAccounts,
772
- });
773
- }
774
-
775
- public async updateBankCumulativeInterest(
776
- bankIndex: BN
777
- ): Promise<TransactionSignature> {
778
- const { txSig } = await this.txSender.send(
779
- wrapInTx(await this.updateBankCumulativeInterestIx(bankIndex)),
780
- [],
781
- this.opts
782
- );
783
- return txSig;
784
- }
785
-
786
- public async updateBankCumulativeInterestIx(
787
- bankIndex: BN
788
- ): Promise<TransactionInstruction> {
789
- const bank = this.getBankAccount(bankIndex);
790
- return await this.program.instruction.updateBankCumulativeInterest({
791
- accounts: {
792
- bank: bank.pubkey,
793
- },
794
- });
795
- }
796
-
797
- public async openPosition(
798
- direction: PositionDirection,
799
- amount: BN,
800
- marketIndex: BN,
801
- limitPrice?: BN
802
- ): Promise<TransactionSignature> {
803
- return await this.placeAndTake({
804
- orderType: OrderType.MARKET,
805
- marketIndex,
806
- direction,
807
- baseAssetAmount: amount,
808
- price: limitPrice,
809
- });
810
- }
811
-
812
- public async placeOrder(
813
- orderParams: OptionalOrderParams
814
- ): Promise<TransactionSignature> {
815
- const { txSig, slot } = await this.txSender.send(
816
- wrapInTx(await this.getPlaceOrderIx(orderParams)),
817
- [],
818
- this.opts
819
- );
820
- this.marketLastSlotCache.set(orderParams.marketIndex.toNumber(), slot);
821
- return txSig;
822
- }
823
-
824
- getOrderParams(optionalOrderParams: OptionalOrderParams): OrderParams {
825
- return Object.assign({}, DefaultOrderParams, optionalOrderParams);
826
- }
827
-
828
- public async getPlaceOrderIx(
829
- orderParams: OptionalOrderParams
830
- ): Promise<TransactionInstruction> {
831
- orderParams = this.getOrderParams(orderParams);
832
- const userAccountPublicKey = await this.getUserAccountPublicKey();
833
-
834
- const remainingAccounts = this.getRemainingAccounts({
835
- writableMarketIndex: orderParams.marketIndex,
836
- });
837
-
838
- return await this.program.instruction.placeOrder(orderParams, {
839
- accounts: {
840
- state: await this.getStatePublicKey(),
841
- user: userAccountPublicKey,
842
- authority: this.wallet.publicKey,
843
- },
844
- remainingAccounts,
845
- });
846
- }
847
-
848
- public async updateAMMs(marketIndexes: BN[]): Promise<TransactionSignature> {
849
- const { txSig } = await this.txSender.send(
850
- wrapInTx(await this.getUpdateAMMsIx(marketIndexes)),
851
- [],
852
- this.opts
853
- );
854
- return txSig;
855
- }
856
-
857
- public async getUpdateAMMsIx(
858
- marketIndexes: BN[]
859
- ): Promise<TransactionInstruction> {
860
- for (let i = marketIndexes.length; i < 5; i++) {
861
- marketIndexes.push(new BN(100));
862
- }
863
- const marketAccountInfos = [];
864
- const oracleAccountInfos = [];
865
- for (const marketIndex of marketIndexes) {
866
- if (!marketIndex.eq(new BN(100))) {
867
- const market = this.getMarketAccount(marketIndex);
868
- marketAccountInfos.push({
869
- pubkey: market.pubkey,
870
- isWritable: true,
871
- isSigner: false,
872
- });
873
- oracleAccountInfos.push({
874
- pubkey: market.amm.oracle,
875
- isWritable: false,
876
- isSigner: false,
877
- });
878
- }
879
- }
880
- const remainingAccounts = oracleAccountInfos.concat(marketAccountInfos);
881
-
882
- return await this.program.instruction.updateAmms(marketIndexes, {
883
- accounts: {
884
- state: await this.getStatePublicKey(),
885
- authority: this.wallet.publicKey,
886
- },
887
- remainingAccounts,
888
- });
889
- }
890
-
891
- public async cancelOrder(orderId?: BN): Promise<TransactionSignature> {
892
- const { txSig } = await this.txSender.send(
893
- wrapInTx(await this.getCancelOrderIx(orderId)),
894
- [],
895
- this.opts
896
- );
897
- return txSig;
898
- }
899
-
900
- public async getCancelOrderIx(orderId?: BN): Promise<TransactionInstruction> {
901
- const userAccountPublicKey = await this.getUserAccountPublicKey();
902
-
903
- const remainingAccounts = this.getRemainingAccounts({});
904
-
905
- return await this.program.instruction.cancelOrder(orderId ?? null, {
906
- accounts: {
907
- state: await this.getStatePublicKey(),
908
- user: userAccountPublicKey,
909
- authority: this.wallet.publicKey,
910
- },
911
- remainingAccounts,
912
- });
913
- }
914
-
915
- public async cancelOrderByUserId(
916
- userOrderId: number
917
- ): Promise<TransactionSignature> {
918
- const { txSig } = await this.txSender.send(
919
- wrapInTx(await this.getCancelOrderByUserIdIx(userOrderId)),
920
- [],
921
- this.opts
922
- );
923
- return txSig;
924
- }
925
-
926
- public async getCancelOrderByUserIdIx(
927
- userOrderId: number
928
- ): Promise<TransactionInstruction> {
929
- const userAccountPublicKey = await this.getUserAccountPublicKey();
930
-
931
- const order = this.getOrderByUserId(userOrderId);
932
- const oracle = this.getMarketAccount(order.marketIndex).amm.oracle;
933
-
934
- const remainingAccounts = this.getRemainingAccounts({});
935
-
936
- return await this.program.instruction.cancelOrderByUserId(userOrderId, {
937
- accounts: {
938
- state: await this.getStatePublicKey(),
939
- user: userAccountPublicKey,
940
- authority: this.wallet.publicKey,
941
- oracle,
942
- },
943
- remainingAccounts,
944
- });
945
- }
946
-
947
- public async fillOrder(
948
- userAccountPublicKey: PublicKey,
949
- user: UserAccount,
950
- order?: Order,
951
- makerInfo?: MakerInfo
952
- ): Promise<TransactionSignature> {
953
- const { txSig } = await this.txSender.send(
954
- wrapInTx(
955
- await this.getFillOrderIx(userAccountPublicKey, user, order, makerInfo)
956
- ),
957
- [],
958
- this.opts
959
- );
960
- return txSig;
961
- }
962
-
963
- public async getFillOrderIx(
964
- userAccountPublicKey: PublicKey,
965
- userAccount: UserAccount,
966
- order: Order,
967
- makerInfo?: MakerInfo
968
- ): Promise<TransactionInstruction> {
969
- const fillerPublicKey = await this.getUserAccountPublicKey();
970
-
971
- const marketIndex = order.marketIndex;
972
- const marketAccount = this.getMarketAccount(marketIndex);
973
-
974
- const bankAccountInfos = [
975
- {
976
- pubkey: this.getQuoteAssetBankAccount().pubkey,
977
- isSigner: false,
978
- isWritable: true,
979
- },
980
- ];
981
- const marketAccountInfos = [
982
- {
983
- pubkey: marketAccount.pubkey,
984
- isWritable: true,
985
- isSigner: false,
986
- },
987
- ];
988
- const oracleAccountInfos = [
989
- {
990
- pubkey: marketAccount.amm.oracle,
991
- isWritable: false,
992
- isSigner: false,
993
- },
994
- ];
995
- for (const position of userAccount.positions) {
996
- if (
997
- !positionIsAvailable(position) &&
998
- !position.marketIndex.eq(order.marketIndex)
999
- ) {
1000
- const market = this.getMarketAccount(position.marketIndex);
1001
- marketAccountInfos.push({
1002
- pubkey: market.pubkey,
1003
- isWritable: true,
1004
- isSigner: false,
1005
- });
1006
- oracleAccountInfos.push({
1007
- pubkey: market.amm.oracle,
1008
- isWritable: false,
1009
- isSigner: false,
1010
- });
1011
- }
1012
- }
1013
- const remainingAccounts = oracleAccountInfos.concat(
1014
- bankAccountInfos.concat(marketAccountInfos)
1015
- );
1016
-
1017
- if (makerInfo) {
1018
- remainingAccounts.push({
1019
- pubkey: makerInfo.maker,
1020
- isWritable: true,
1021
- isSigner: false,
1022
- });
1023
- }
1024
-
1025
- const orderId = order.orderId;
1026
- const makerOrderId = makerInfo ? makerInfo.order.orderId : null;
1027
- return await this.program.instruction.fillOrder(orderId, makerOrderId, {
1028
- accounts: {
1029
- state: await this.getStatePublicKey(),
1030
- filler: fillerPublicKey,
1031
- user: userAccountPublicKey,
1032
- authority: this.wallet.publicKey,
1033
- },
1034
- remainingAccounts,
1035
- });
1036
- }
1037
-
1038
- public async triggerOrder(
1039
- userAccountPublicKey: PublicKey,
1040
- user: UserAccount,
1041
- order: Order
1042
- ): Promise<TransactionSignature> {
1043
- const { txSig } = await this.txSender.send(
1044
- wrapInTx(await this.getTriggerOrderIx(userAccountPublicKey, user, order)),
1045
- [],
1046
- this.opts
1047
- );
1048
- return txSig;
1049
- }
1050
-
1051
- public async getTriggerOrderIx(
1052
- userAccountPublicKey: PublicKey,
1053
- userAccount: UserAccount,
1054
- order: Order
1055
- ): Promise<TransactionInstruction> {
1056
- const fillerPublicKey = await this.getUserAccountPublicKey();
1057
-
1058
- const marketIndex = order.marketIndex;
1059
- const marketAccount = this.getMarketAccount(marketIndex);
1060
-
1061
- const bankAccountInfos = [
1062
- {
1063
- pubkey: this.getQuoteAssetBankAccount().pubkey,
1064
- isSigner: false,
1065
- isWritable: true,
1066
- },
1067
- ];
1068
- const marketAccountInfos = [
1069
- {
1070
- pubkey: marketAccount.pubkey,
1071
- isWritable: true,
1072
- isSigner: false,
1073
- },
1074
- ];
1075
- const oracleAccountInfos = [
1076
- {
1077
- pubkey: marketAccount.amm.oracle,
1078
- isWritable: false,
1079
- isSigner: false,
1080
- },
1081
- ];
1082
- for (const position of userAccount.positions) {
1083
- if (
1084
- !positionIsAvailable(position) &&
1085
- !position.marketIndex.eq(order.marketIndex)
1086
- ) {
1087
- const market = this.getMarketAccount(position.marketIndex);
1088
- marketAccountInfos.push({
1089
- pubkey: market.pubkey,
1090
- isWritable: false,
1091
- isSigner: false,
1092
- });
1093
- oracleAccountInfos.push({
1094
- pubkey: market.amm.oracle,
1095
- isWritable: false,
1096
- isSigner: false,
1097
- });
1098
- }
1099
- }
1100
- const remainingAccounts = oracleAccountInfos.concat(
1101
- bankAccountInfos.concat(marketAccountInfos)
1102
- );
1103
-
1104
- const orderId = order.orderId;
1105
- return await this.program.instruction.triggerOrder(orderId, {
1106
- accounts: {
1107
- state: await this.getStatePublicKey(),
1108
- filler: fillerPublicKey,
1109
- user: userAccountPublicKey,
1110
- authority: this.wallet.publicKey,
1111
- },
1112
- remainingAccounts,
1113
- });
1114
- }
1115
-
1116
- public async placeAndTake(
1117
- orderParams: OptionalOrderParams,
1118
- makerInfo?: MakerInfo
1119
- ): Promise<TransactionSignature> {
1120
- const { txSig, slot } = await this.txSender.send(
1121
- wrapInTx(await this.getPlaceAndTakeIx(orderParams, makerInfo)),
1122
- [],
1123
- this.opts
1124
- );
1125
- this.marketLastSlotCache.set(orderParams.marketIndex.toNumber(), slot);
1126
- return txSig;
1127
- }
1128
-
1129
- public async getPlaceAndTakeIx(
1130
- orderParams: OptionalOrderParams,
1131
- makerInfo?: MakerInfo
1132
- ): Promise<TransactionInstruction> {
1133
- orderParams = this.getOrderParams(orderParams);
1134
- const userAccountPublicKey = await this.getUserAccountPublicKey();
1135
-
1136
- const remainingAccounts = this.getRemainingAccounts({
1137
- writableMarketIndex: orderParams.marketIndex,
1138
- writableBankIndex: QUOTE_ASSET_BANK_INDEX,
1139
- });
1140
-
1141
- let makerOrderId = null;
1142
- if (makerInfo) {
1143
- makerOrderId = makerInfo.order.orderId;
1144
- remainingAccounts.push({
1145
- pubkey: makerInfo.maker,
1146
- isSigner: false,
1147
- isWritable: true,
1148
- });
1149
- }
1150
-
1151
- return await this.program.instruction.placeAndTake(
1152
- orderParams,
1153
- makerOrderId,
1154
- {
1155
- accounts: {
1156
- state: await this.getStatePublicKey(),
1157
- user: userAccountPublicKey,
1158
- authority: this.wallet.publicKey,
1159
- },
1160
- remainingAccounts,
1161
- }
1162
- );
1163
- }
1164
-
1165
- /**
1166
- * Close an entire position. If you want to reduce a position, use the {@link openPosition} method in the opposite direction of the current position.
1167
- * @param marketIndex
1168
- * @returns
1169
- */
1170
- public async closePosition(marketIndex: BN): Promise<TransactionSignature> {
1171
- const userPosition = this.getUser().getUserPosition(marketIndex);
1172
- if (!userPosition) {
1173
- throw Error(`No position in market ${marketIndex.toString()}`);
1174
- }
1175
-
1176
- return await this.placeAndTake({
1177
- orderType: OrderType.MARKET,
1178
- marketIndex,
1179
- direction: findDirectionToClose(userPosition),
1180
- baseAssetAmount: userPosition.baseAssetAmount,
1181
- reduceOnly: true,
1182
- });
1183
- }
1184
-
1185
- public async settlePNLs(
1186
- users: {
1187
- settleeUserAccountPublicKey: PublicKey;
1188
- settleeUserAccount: UserAccount;
1189
- }[],
1190
- marketIndex: BN
1191
- ): Promise<TransactionSignature> {
1192
- const ixs = [];
1193
- for (const { settleeUserAccountPublicKey, settleeUserAccount } of users) {
1194
- ixs.push(
1195
- await this.settlePNLIx(
1196
- settleeUserAccountPublicKey,
1197
- settleeUserAccount,
1198
- marketIndex
1199
- )
1200
- );
1201
- }
1202
-
1203
- const tx = new Transaction().add(...ixs);
1204
-
1205
- const { txSig } = await this.txSender.send(tx, [], this.opts);
1206
- return txSig;
1207
- }
1208
-
1209
- public async settlePNL(
1210
- settleeUserAccountPublicKey: PublicKey,
1211
- settleeUserAccount: UserAccount,
1212
- marketIndex: BN
1213
- ): Promise<TransactionSignature> {
1214
- const { txSig } = await this.txSender.send(
1215
- wrapInTx(
1216
- await this.settlePNLIx(
1217
- settleeUserAccountPublicKey,
1218
- settleeUserAccount,
1219
- marketIndex
1220
- )
1221
- ),
1222
- [],
1223
- this.opts
1224
- );
1225
- return txSig;
1226
- }
1227
-
1228
- public async settlePNLIx(
1229
- settleeUserAccountPublicKey: PublicKey,
1230
- settleeUserAccount: UserAccount,
1231
- marketIndex: BN
1232
- ): Promise<TransactionInstruction> {
1233
- const marketAccountMap = new Map<number, AccountMeta>();
1234
- const oracleAccountMap = new Map<string, AccountMeta>();
1235
- const bankAccountMap = new Map<number, AccountMeta>();
1236
- for (const position of settleeUserAccount.positions) {
1237
- if (!positionIsAvailable(position)) {
1238
- const market = this.getMarketAccount(position.marketIndex);
1239
- marketAccountMap.set(position.marketIndex.toNumber(), {
1240
- pubkey: market.pubkey,
1241
- isWritable: true, // TODO
1242
- isSigner: false,
1243
- });
1244
- oracleAccountMap.set(market.amm.oracle.toString(), {
1245
- pubkey: market.amm.oracle,
1246
- isWritable: false,
1247
- isSigner: false,
1248
- });
1249
- }
1250
- }
1251
-
1252
- for (const userBankBalance of settleeUserAccount.bankBalances) {
1253
- if (!userBankBalance.balance.eq(QUOTE_ASSET_BANK_INDEX)) {
1254
- const bankAccount = this.getBankAccount(userBankBalance.bankIndex);
1255
- bankAccountMap.set(userBankBalance.bankIndex.toNumber(), {
1256
- pubkey: bankAccount.pubkey,
1257
- isSigner: false,
1258
- isWritable: false,
1259
- });
1260
- if (!bankAccount.bankIndex.eq(ZERO)) {
1261
- oracleAccountMap.set(bankAccount.oracle.toString(), {
1262
- pubkey: bankAccount.oracle,
1263
- isSigner: false,
1264
- isWritable: false,
1265
- });
1266
- }
1267
- }
1268
- }
1269
-
1270
- const marketAccount = this.getMarketAccount(marketIndex.toNumber());
1271
- marketAccountMap.set(marketIndex.toNumber(), {
1272
- pubkey: marketAccount.pubkey,
1273
- isSigner: false,
1274
- isWritable: true,
1275
- });
1276
- oracleAccountMap.set(marketAccount.amm.oracle.toString(), {
1277
- pubkey: marketAccount.amm.oracle,
1278
- isSigner: false,
1279
- isWritable: false,
1280
- });
1281
-
1282
- bankAccountMap.set(QUOTE_ASSET_BANK_INDEX.toNumber(), {
1283
- pubkey: this.getBankAccount(QUOTE_ASSET_BANK_INDEX).pubkey,
1284
- isSigner: false,
1285
- isWritable: true,
1286
- });
1287
-
1288
- const remainingAccounts = [
1289
- ...oracleAccountMap.values(),
1290
- ...bankAccountMap.values(),
1291
- ...marketAccountMap.values(),
1292
- ];
1293
-
1294
- return await this.program.instruction.settlePnl(marketIndex, {
1295
- accounts: {
1296
- state: await this.getStatePublicKey(),
1297
- authority: this.wallet.publicKey,
1298
- user: settleeUserAccountPublicKey,
1299
- },
1300
- remainingAccounts: remainingAccounts,
1301
- });
1302
- }
1303
-
1304
- public async liquidate(
1305
- liquidateeUserAccountPublicKey: PublicKey
1306
- ): Promise<TransactionSignature> {
1307
- const { txSig } = await this.txSender.send(
1308
- wrapInTx(await this.getLiquidateIx(liquidateeUserAccountPublicKey)),
1309
- [],
1310
- this.opts
1311
- );
1312
- return txSig;
1313
- }
1314
-
1315
- public async getLiquidateIx(
1316
- liquidateeUserAccountPublicKey: PublicKey
1317
- ): Promise<TransactionInstruction> {
1318
- const userAccountPublicKey = await this.getUserAccountPublicKey();
1319
- const liquidateeUserAccount = (await this.program.account.user.fetch(
1320
- liquidateeUserAccountPublicKey
1321
- )) as UserAccount;
1322
-
1323
- const bankAccountInfos = [
1324
- {
1325
- pubkey: this.getQuoteAssetBankAccount().pubkey,
1326
- isSigner: false,
1327
- isWritable: true,
1328
- },
1329
- ];
1330
- const marketAccountInfos = [];
1331
- const oracleAccountInfos = [];
1332
- for (const position of liquidateeUserAccount.positions) {
1333
- if (!positionIsAvailable(position)) {
1334
- const market = this.getMarketAccount(position.marketIndex);
1335
- const marketPublicKey = await getMarketPublicKey(
1336
- this.program.programId,
1337
- position.marketIndex
1338
- );
1339
- marketAccountInfos.push({
1340
- pubkey: marketPublicKey,
1341
- isWritable: true,
1342
- isSigner: false,
1343
- });
1344
- oracleAccountInfos.push({
1345
- pubkey: market.amm.oracle,
1346
- isWritable: false,
1347
- isSigner: false,
1348
- });
1349
- }
1350
- }
1351
- const remainingAccounts = oracleAccountInfos.concat(
1352
- bankAccountInfos.concat(marketAccountInfos)
1353
- );
1354
-
1355
- const state = this.getStateAccount();
1356
- const quoteAssetBankAccount = this.getQuoteAssetBankAccount();
1357
- return await this.program.instruction.liquidate({
1358
- accounts: {
1359
- state: await this.getStatePublicKey(),
1360
- authority: this.wallet.publicKey,
1361
- user: liquidateeUserAccountPublicKey,
1362
- liquidator: userAccountPublicKey,
1363
- bankVault: quoteAssetBankAccount.vault,
1364
- bankVaultAuthority: quoteAssetBankAccount.vaultAuthority,
1365
- insuranceVault: state.insuranceVault,
1366
- tokenProgram: TOKEN_PROGRAM_ID,
1367
- },
1368
- remainingAccounts: remainingAccounts,
1369
- });
1370
- }
1371
-
1372
- public async updateFundingRate(
1373
- oracle: PublicKey,
1374
- marketIndex: BN
1375
- ): Promise<TransactionSignature> {
1376
- const { txSig } = await this.txSender.send(
1377
- wrapInTx(await this.getUpdateFundingRateIx(oracle, marketIndex)),
1378
- [],
1379
- this.opts
1380
- );
1381
- return txSig;
1382
- }
1383
-
1384
- public async getUpdateFundingRateIx(
1385
- oracle: PublicKey,
1386
- marketIndex: BN
1387
- ): Promise<TransactionInstruction> {
1388
- return await this.program.instruction.updateFundingRate(marketIndex, {
1389
- accounts: {
1390
- state: await this.getStatePublicKey(),
1391
- market: await getMarketPublicKey(this.program.programId, marketIndex),
1392
- oracle: oracle,
1393
- },
1394
- });
1395
- }
1396
-
1397
- public async settleFundingPayment(
1398
- userAccount: PublicKey
1399
- ): Promise<TransactionSignature> {
1400
- const { txSig } = await this.txSender.send(
1401
- wrapInTx(await this.getSettleFundingPaymentIx(userAccount)),
1402
- [],
1403
- this.opts
1404
- );
1405
- return txSig;
1406
- }
1407
-
1408
- public async getSettleFundingPaymentIx(
1409
- userAccount: PublicKey
1410
- ): Promise<TransactionInstruction> {
1411
- const user = (await this.program.account.user.fetch(
1412
- userAccount
1413
- )) as UserAccount;
1414
-
1415
- const userPositions = user.positions;
1416
-
1417
- const remainingAccounts = [];
1418
- for (const position of userPositions) {
1419
- if (!positionIsAvailable(position)) {
1420
- const marketPublicKey = await getMarketPublicKey(
1421
- this.program.programId,
1422
- position.marketIndex
1423
- );
1424
- remainingAccounts.push({
1425
- pubkey: marketPublicKey,
1426
- isWritable: false,
1427
- isSigner: false,
1428
- });
1429
- }
1430
- }
1431
-
1432
- return await this.program.instruction.settleFundingPayment({
1433
- accounts: {
1434
- state: await this.getStatePublicKey(),
1435
- user: userAccount,
1436
- },
1437
- remainingAccounts,
1438
- });
1439
- }
1440
-
1441
- public triggerEvent(eventName: keyof ClearingHouseAccountEvents, data?: any) {
1442
- this.eventEmitter.emit(eventName, data);
1443
- }
1444
-
1445
- public getOracleDataForMarket(marketIndex: BN): OraclePriceData {
1446
- const oracleKey = this.getMarketAccount(marketIndex).amm.oracle;
1447
- const oracleData = this.getOraclePriceDataAndSlot(oracleKey).data;
1448
-
1449
- return oracleData;
1450
- }
1451
- }