@drift-labs/sdk 0.1.19-master.2 → 0.1.21-master.4

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 (143) hide show
  1. package/lib/accounts/bulkAccountLoader.d.ts +31 -0
  2. package/lib/accounts/bulkAccountLoader.js +177 -0
  3. package/lib/accounts/bulkUserSubscription.d.ts +7 -0
  4. package/lib/accounts/bulkUserSubscription.js +28 -0
  5. package/lib/accounts/pollingClearingHouseAccountSubscriber.d.ts +49 -0
  6. package/lib/accounts/pollingClearingHouseAccountSubscriber.js +228 -0
  7. package/lib/accounts/pollingTokenAccountSubscriber.d.ts +25 -0
  8. package/lib/accounts/pollingTokenAccountSubscriber.js +79 -0
  9. package/lib/accounts/pollingUserAccountSubscriber.d.ts +32 -0
  10. package/lib/accounts/pollingUserAccountSubscriber.js +136 -0
  11. package/lib/accounts/types.d.ts +38 -3
  12. package/lib/accounts/utils.d.ts +1 -0
  13. package/lib/accounts/utils.js +7 -0
  14. package/lib/accounts/webSocketAccountSubscriber.d.ts +6 -3
  15. package/lib/accounts/webSocketAccountSubscriber.js +43 -12
  16. package/lib/accounts/{defaultClearingHouseAccountSubscriber.d.ts → webSocketClearingHouseAccountSubscriber.d.ts} +8 -3
  17. package/lib/accounts/{defaultClearingHouseAccountSubscriber.js → webSocketClearingHouseAccountSubscriber.js} +30 -4
  18. package/lib/accounts/{defaultUserAccountSubscriber.d.ts → webSocketUserAccountSubscriber.d.ts} +6 -3
  19. package/lib/accounts/{defaultUserAccountSubscriber.js → webSocketUserAccountSubscriber.js} +16 -4
  20. package/lib/addresses.d.ts +4 -1
  21. package/lib/addresses.js +28 -1
  22. package/lib/admin.d.ts +10 -4
  23. package/lib/admin.js +54 -17
  24. package/lib/assert/assert.d.ts +0 -1
  25. package/lib/clearingHouse.d.ts +39 -4
  26. package/lib/clearingHouse.js +334 -23
  27. package/lib/clearingHouseUser.d.ts +27 -6
  28. package/lib/clearingHouseUser.js +125 -45
  29. package/lib/config.d.ts +0 -1
  30. package/lib/constants/markets.d.ts +2 -2
  31. package/lib/constants/markets.js +28 -15
  32. package/lib/constants/numericConstants.d.ts +4 -2
  33. package/lib/constants/numericConstants.js +16 -17
  34. package/lib/examples/makeTradeExample.d.ts +0 -1
  35. package/lib/examples/makeTradeExample.js +6 -6
  36. package/lib/factory/clearingHouse.d.ts +25 -0
  37. package/lib/factory/clearingHouse.js +64 -0
  38. package/lib/factory/clearingHouseUser.d.ts +19 -0
  39. package/lib/factory/clearingHouseUser.js +34 -0
  40. package/lib/idl/clearing_house.json +1066 -39
  41. package/lib/index.d.ts +11 -3
  42. package/lib/index.js +12 -2
  43. package/lib/math/amm.d.ts +3 -1
  44. package/lib/math/amm.js +128 -15
  45. package/lib/math/conversion.d.ts +1 -2
  46. package/lib/math/conversion.js +1 -1
  47. package/lib/math/funding.d.ts +0 -1
  48. package/lib/math/funding.js +1 -1
  49. package/lib/math/insuranceFund.d.ts +2 -2
  50. package/lib/math/insuranceFund.js +3 -6
  51. package/lib/math/market.d.ts +2 -2
  52. package/lib/math/market.js +12 -2
  53. package/lib/math/orders.d.ts +3 -0
  54. package/lib/math/orders.js +32 -0
  55. package/lib/math/position.d.ts +6 -3
  56. package/lib/math/position.js +21 -10
  57. package/lib/math/trade.d.ts +0 -1
  58. package/lib/math/trade.js +16 -16
  59. package/lib/math/utils.d.ts +2 -2
  60. package/lib/math/utils.js +3 -3
  61. package/lib/mockUSDCFaucet.d.ts +2 -2
  62. package/lib/orderParams.d.ts +7 -0
  63. package/lib/orderParams.js +108 -0
  64. package/lib/orders.d.ts +6 -0
  65. package/lib/orders.js +136 -0
  66. package/lib/pythClient.d.ts +0 -1
  67. package/lib/pythClient.js +1 -1
  68. package/lib/token/index.d.ts +3 -0
  69. package/lib/token/index.js +38 -0
  70. package/lib/tx/defaultTxSender.d.ts +0 -1
  71. package/lib/tx/types.d.ts +0 -1
  72. package/lib/tx/utils.d.ts +0 -1
  73. package/lib/types.d.ts +147 -3
  74. package/lib/types.js +36 -1
  75. package/lib/util/computeUnits.d.ts +0 -1
  76. package/lib/util/tps.d.ts +0 -1
  77. package/lib/wallet.d.ts +0 -1
  78. package/package.json +11 -3
  79. package/src/accounts/bulkAccountLoader.ts +215 -0
  80. package/src/accounts/bulkUserSubscription.ts +28 -0
  81. package/src/accounts/pollingClearingHouseAccountSubscriber.ts +326 -0
  82. package/src/accounts/pollingTokenAccountSubscriber.ts +99 -0
  83. package/src/accounts/pollingUserAccountSubscriber.ts +194 -0
  84. package/src/accounts/types.ts +48 -1
  85. package/src/accounts/utils.ts +3 -0
  86. package/src/accounts/webSocketAccountSubscriber.ts +67 -17
  87. package/src/accounts/{defaultClearingHouseAccountSubscriber.ts → webSocketClearingHouseAccountSubscriber.ts} +51 -1
  88. package/src/accounts/{defaultUserAccountSubscriber.ts → webSocketUserAccountSubscriber.ts} +33 -3
  89. package/src/addresses.ts +37 -0
  90. package/src/admin.ts +92 -24
  91. package/src/clearingHouse.ts +455 -22
  92. package/src/clearingHouseUser.ts +155 -18
  93. package/src/constants/markets.ts +17 -1
  94. package/src/constants/numericConstants.ts +3 -1
  95. package/src/examples/makeTradeExample.ts +4 -1
  96. package/src/factory/clearingHouse.ts +125 -0
  97. package/src/factory/clearingHouseUser.ts +73 -0
  98. package/src/idl/clearing_house.json +1066 -39
  99. package/src/index.ts +11 -2
  100. package/src/math/amm.ts +169 -14
  101. package/src/math/conversion.ts +1 -1
  102. package/src/math/insuranceFund.ts +1 -1
  103. package/src/math/market.ts +28 -2
  104. package/src/math/orders.ts +44 -0
  105. package/src/math/position.ts +24 -4
  106. package/src/math/utils.ts +1 -1
  107. package/src/mockUSDCFaucet.ts +1 -1
  108. package/src/orderParams.ts +151 -0
  109. package/src/orders.ts +236 -0
  110. package/src/token/index.ts +37 -0
  111. package/src/types.ts +130 -2
  112. package/tsconfig.json +0 -1
  113. package/lib/accounts/defaultClearingHouseAccountSubscriber.d.ts.map +0 -1
  114. package/lib/accounts/defaultUserAccountSubscriber.d.ts.map +0 -1
  115. package/lib/accounts/types.d.ts.map +0 -1
  116. package/lib/accounts/webSocketAccountSubscriber.d.ts.map +0 -1
  117. package/lib/addresses.d.ts.map +0 -1
  118. package/lib/admin.d.ts.map +0 -1
  119. package/lib/assert/assert.d.ts.map +0 -1
  120. package/lib/clearingHouse.d.ts.map +0 -1
  121. package/lib/clearingHouseUser.d.ts.map +0 -1
  122. package/lib/config.d.ts.map +0 -1
  123. package/lib/constants/markets.d.ts.map +0 -1
  124. package/lib/constants/numericConstants.d.ts.map +0 -1
  125. package/lib/examples/makeTradeExample.d.ts.map +0 -1
  126. package/lib/index.d.ts.map +0 -1
  127. package/lib/math/amm.d.ts.map +0 -1
  128. package/lib/math/conversion.d.ts.map +0 -1
  129. package/lib/math/funding.d.ts.map +0 -1
  130. package/lib/math/insuranceFund.d.ts.map +0 -1
  131. package/lib/math/market.d.ts.map +0 -1
  132. package/lib/math/position.d.ts.map +0 -1
  133. package/lib/math/trade.d.ts.map +0 -1
  134. package/lib/math/utils.d.ts.map +0 -1
  135. package/lib/mockUSDCFaucet.d.ts.map +0 -1
  136. package/lib/pythClient.d.ts.map +0 -1
  137. package/lib/tx/defaultTxSender.d.ts.map +0 -1
  138. package/lib/tx/types.d.ts.map +0 -1
  139. package/lib/tx/utils.d.ts.map +0 -1
  140. package/lib/types.d.ts.map +0 -1
  141. package/lib/util/computeUnits.d.ts.map +0 -1
  142. package/lib/util/tps.d.ts.map +0 -1
  143. package/lib/wallet.d.ts.map +0 -1
@@ -0,0 +1,194 @@
1
+ import {
2
+ AccountToPoll,
3
+ NotSubscribedError,
4
+ UserAccountEvents,
5
+ UserAccountSubscriber,
6
+ } from './types';
7
+ import { Program } from '@project-serum/anchor';
8
+ import StrictEventEmitter from 'strict-event-emitter-types';
9
+ import { EventEmitter } from 'events';
10
+ import { PublicKey } from '@solana/web3.js';
11
+ import {
12
+ getUserAccountPublicKey,
13
+ getUserOrdersAccountPublicKey,
14
+ } from '../addresses';
15
+ import { UserAccount, UserOrdersAccount, UserPositionsAccount } from '../types';
16
+ import { BulkAccountLoader } from './bulkAccountLoader';
17
+ import { capitalize } from './utils';
18
+ import { ClearingHouseConfigType } from '../factory/clearingHouse';
19
+
20
+ export class PollingUserAccountSubscriber implements UserAccountSubscriber {
21
+ isSubscribed: boolean;
22
+ program: Program;
23
+ eventEmitter: StrictEventEmitter<EventEmitter, UserAccountEvents>;
24
+ authority: PublicKey;
25
+
26
+ accountLoader: BulkAccountLoader;
27
+ accountsToPoll = new Map<string, AccountToPoll>();
28
+ errorCallbackId?: string;
29
+
30
+ user?: UserAccount;
31
+ userPositions?: UserPositionsAccount;
32
+ userOrders?: UserOrdersAccount;
33
+
34
+ type: ClearingHouseConfigType = 'polling';
35
+
36
+ public constructor(
37
+ program: Program,
38
+ authority: PublicKey,
39
+ accountLoader: BulkAccountLoader
40
+ ) {
41
+ this.isSubscribed = false;
42
+ this.program = program;
43
+ this.authority = authority;
44
+ this.accountLoader = accountLoader;
45
+ this.eventEmitter = new EventEmitter();
46
+ }
47
+
48
+ async subscribe(): Promise<boolean> {
49
+ if (this.isSubscribed) {
50
+ return true;
51
+ }
52
+
53
+ await this.addToAccountLoader();
54
+ await this.fetchIfUnloaded();
55
+ this.eventEmitter.emit('update');
56
+
57
+ this.isSubscribed = true;
58
+ return true;
59
+ }
60
+
61
+ async addToAccountLoader(): Promise<void> {
62
+ if (this.accountsToPoll.size > 0) {
63
+ return;
64
+ }
65
+
66
+ const userPublicKey = await getUserAccountPublicKey(
67
+ this.program.programId,
68
+ this.authority
69
+ );
70
+
71
+ const userAccount = (await this.program.account.user.fetch(
72
+ userPublicKey
73
+ )) as UserAccount;
74
+
75
+ this.accountsToPoll.set(userPublicKey.toString(), {
76
+ key: 'user',
77
+ publicKey: userPublicKey,
78
+ eventType: 'userAccountData',
79
+ });
80
+
81
+ this.accountsToPoll.set(userAccount.positions.toString(), {
82
+ key: 'userPositions',
83
+ publicKey: userAccount.positions,
84
+ eventType: 'userPositionsData',
85
+ });
86
+
87
+ const userOrdersPublicKey = await getUserOrdersAccountPublicKey(
88
+ this.program.programId,
89
+ userPublicKey
90
+ );
91
+
92
+ const userOrdersExist =
93
+ (
94
+ await this.program.provider.connection.getParsedAccountInfo(
95
+ userOrdersPublicKey
96
+ )
97
+ ).value !== null;
98
+ if (userOrdersExist) {
99
+ this.accountsToPoll.set(userOrdersPublicKey.toString(), {
100
+ key: 'userOrders',
101
+ publicKey: userOrdersPublicKey,
102
+ eventType: 'userOrdersData',
103
+ });
104
+ }
105
+
106
+ for (const [_, accountToPoll] of this.accountsToPoll) {
107
+ accountToPoll.callbackId = this.accountLoader.addAccount(
108
+ accountToPoll.publicKey,
109
+ (buffer) => {
110
+ const account = this.program.account[
111
+ accountToPoll.key
112
+ ].coder.accounts.decode(capitalize(accountToPoll.key), buffer);
113
+ this[accountToPoll.key] = account;
114
+ // @ts-ignore
115
+ this.eventEmitter.emit(accountToPoll.eventType, account);
116
+ this.eventEmitter.emit('update');
117
+ }
118
+ );
119
+ }
120
+
121
+ this.errorCallbackId = this.accountLoader.addErrorCallbacks((error) => {
122
+ this.eventEmitter.emit('error', error);
123
+ });
124
+ }
125
+
126
+ async fetchIfUnloaded(): Promise<void> {
127
+ let shouldFetch = false;
128
+ for (const [_, accountToPoll] of this.accountsToPoll) {
129
+ if (this[accountToPoll.key] === undefined) {
130
+ shouldFetch = true;
131
+ break;
132
+ }
133
+ }
134
+
135
+ if (shouldFetch) {
136
+ await this.fetch();
137
+ }
138
+ }
139
+
140
+ async fetch(): Promise<void> {
141
+ await this.accountLoader.load();
142
+ for (const [_, accountToPoll] of this.accountsToPoll) {
143
+ const buffer = this.accountLoader.getAccountData(accountToPoll.publicKey);
144
+ if (buffer) {
145
+ this[accountToPoll.key] = this.program.account[
146
+ accountToPoll.key
147
+ ].coder.accounts.decode(capitalize(accountToPoll.key), buffer);
148
+ }
149
+ }
150
+ }
151
+
152
+ async unsubscribe(): Promise<void> {
153
+ if (!this.isSubscribed) {
154
+ return;
155
+ }
156
+
157
+ for (const [_, accountToPoll] of this.accountsToPoll) {
158
+ this.accountLoader.removeAccount(
159
+ accountToPoll.publicKey,
160
+ accountToPoll.callbackId
161
+ );
162
+ }
163
+
164
+ this.accountLoader.removeErrorCallbacks(this.errorCallbackId);
165
+ this.errorCallbackId = undefined;
166
+
167
+ this.accountsToPoll.clear();
168
+
169
+ this.isSubscribed = false;
170
+ }
171
+
172
+ assertIsSubscribed(): void {
173
+ if (!this.isSubscribed) {
174
+ throw new NotSubscribedError(
175
+ 'You must call `subscribe` before using this function'
176
+ );
177
+ }
178
+ }
179
+
180
+ public getUserAccount(): UserAccount {
181
+ this.assertIsSubscribed();
182
+ return this.user;
183
+ }
184
+
185
+ public getUserPositionsAccount(): UserPositionsAccount {
186
+ this.assertIsSubscribed();
187
+ return this.userPositions;
188
+ }
189
+
190
+ public getUserOrdersAccount(): UserOrdersAccount {
191
+ this.assertIsSubscribed();
192
+ return this.userOrders;
193
+ }
194
+ }
@@ -5,13 +5,19 @@ import {
5
5
  FundingRateHistoryAccount,
6
6
  LiquidationHistoryAccount,
7
7
  MarketsAccount,
8
+ OrderHistoryAccount,
9
+ OrderStateAccount,
8
10
  StateAccount,
9
11
  TradeHistoryAccount,
10
12
  UserAccount,
13
+ UserOrdersAccount,
11
14
  UserPositionsAccount,
12
15
  } from '../types';
13
16
  import StrictEventEmitter from 'strict-event-emitter-types';
14
17
  import { EventEmitter } from 'events';
18
+ import { PublicKey } from '@solana/web3.js';
19
+ import { AccountInfo } from '@solana/spl-token';
20
+ import { ClearingHouseConfigType, ClearingHouseUserConfigType } from '..';
15
21
 
16
22
  export interface AccountSubscriber<T> {
17
23
  data?: T;
@@ -35,7 +41,10 @@ export interface ClearingHouseAccountEvents {
35
41
  liquidationHistoryAccountUpdate: (payload: LiquidationHistoryAccount) => void;
36
42
  depositHistoryAccountUpdate: (payload: DepositHistoryAccount) => void;
37
43
  curveHistoryAccountUpdate: (payload: ExtendedCurveHistoryAccount) => void;
44
+ orderHistoryAccountUpdate: (payload: OrderHistoryAccount) => void;
45
+ orderStateAccountUpdate: (payload: OrderStateAccount) => void;
38
46
  update: void;
47
+ error: (e: Error) => void;
39
48
  }
40
49
 
41
50
  export type ClearingHouseAccountTypes =
@@ -44,7 +53,8 @@ export type ClearingHouseAccountTypes =
44
53
  | 'fundingPaymentHistoryAccount'
45
54
  | 'fundingRateHistoryAccount'
46
55
  | 'curveHistoryAccount'
47
- | 'liquidationHistoryAccount';
56
+ | 'liquidationHistoryAccount'
57
+ | 'orderHistoryAccount';
48
58
 
49
59
  export interface ClearingHouseAccountSubscriber {
50
60
  eventEmitter: StrictEventEmitter<EventEmitter, ClearingHouseAccountEvents>;
@@ -66,12 +76,18 @@ export interface ClearingHouseAccountSubscriber {
66
76
  getFundingRateHistoryAccount(): FundingRateHistoryAccount;
67
77
  getCurveHistoryAccount(): ExtendedCurveHistoryAccount;
68
78
  getLiquidationHistoryAccount(): LiquidationHistoryAccount;
79
+ getOrderStateAccount(): OrderStateAccount;
80
+ getOrderHistoryAccount(): OrderHistoryAccount;
81
+
82
+ type: ClearingHouseConfigType;
69
83
  }
70
84
 
71
85
  export interface UserAccountEvents {
72
86
  userAccountData: (payload: UserAccount) => void;
73
87
  userPositionsData: (payload: UserPositionsAccount) => void;
88
+ userOrdersData: (payload: UserOrdersAccount) => void;
74
89
  update: void;
90
+ error: (e: Error) => void;
75
91
  }
76
92
 
77
93
  export interface UserAccountSubscriber {
@@ -84,4 +100,35 @@ export interface UserAccountSubscriber {
84
100
 
85
101
  getUserAccount(): UserAccount;
86
102
  getUserPositionsAccount(): UserPositionsAccount;
103
+ getUserOrdersAccount(): UserOrdersAccount;
104
+ type: ClearingHouseUserConfigType;
105
+ }
106
+
107
+ export interface TokenAccountEvents {
108
+ tokenAccountUpdate: (payload: AccountInfo) => void;
109
+ update: void;
110
+ error: (e: Error) => void;
111
+ }
112
+
113
+ export interface TokenAccountSubscriber {
114
+ eventEmitter: StrictEventEmitter<EventEmitter, TokenAccountEvents>;
115
+ isSubscribed: boolean;
116
+
117
+ subscribe(): Promise<boolean>;
118
+ fetch(): Promise<void>;
119
+ unsubscribe(): Promise<void>;
120
+
121
+ getTokenAccount(): AccountInfo;
87
122
  }
123
+
124
+ export type AccountToPoll = {
125
+ key: string;
126
+ publicKey: PublicKey;
127
+ eventType: string;
128
+ callbackId?: string;
129
+ };
130
+
131
+ export type AccountData = {
132
+ slot: number;
133
+ buffer: Buffer | undefined;
134
+ };
@@ -0,0 +1,3 @@
1
+ export function capitalize(value: string): string {
2
+ return value[0].toUpperCase() + value.slice(1);
3
+ }
@@ -1,13 +1,17 @@
1
- import { AccountSubscriber } from './types';
1
+ import { AccountData, AccountSubscriber } from './types';
2
2
  import { Program } from '@project-serum/anchor';
3
- import { PublicKey } from '@solana/web3.js';
3
+ import { AccountInfo, Context, PublicKey } from '@solana/web3.js';
4
+ import { capitalize } from './utils';
5
+ import * as Buffer from 'buffer';
4
6
 
5
7
  export class WebSocketAccountSubscriber<T> implements AccountSubscriber<T> {
6
8
  data?: T;
9
+ accountData?: AccountData;
7
10
  accountName: string;
8
11
  program: Program;
9
12
  accountPublicKey: PublicKey;
10
13
  onChange: (data: T) => void;
14
+ listenerId?: number;
11
15
 
12
16
  public constructor(
13
17
  accountName: string,
@@ -20,32 +24,78 @@ export class WebSocketAccountSubscriber<T> implements AccountSubscriber<T> {
20
24
  }
21
25
 
22
26
  async subscribe(onChange: (data: T) => void): Promise<void> {
27
+ if (this.listenerId) {
28
+ return;
29
+ }
30
+
23
31
  this.onChange = onChange;
24
32
  await this.fetch();
25
33
 
26
- this.program.account[this.accountName]
27
- .subscribe(this.accountPublicKey, this.program.provider.opts.commitment)
28
- .on('change', async (data: T) => {
29
- this.data = data;
30
- this.onChange(data);
31
- });
34
+ this.listenerId = this.program.provider.connection.onAccountChange(
35
+ this.accountPublicKey,
36
+ (accountInfo, context) => {
37
+ this.handleRpcResponse(context, accountInfo);
38
+ },
39
+ this.program.provider.opts.commitment
40
+ );
32
41
  }
33
42
 
34
43
  async fetch(): Promise<void> {
35
- const newData = (await this.program.account[this.accountName].fetch(
36
- this.accountPublicKey
37
- )) as T;
44
+ const rpcResponse =
45
+ await this.program.provider.connection.getAccountInfoAndContext(
46
+ this.accountPublicKey,
47
+ this.program.provider.opts.commitment
48
+ );
49
+ this.handleRpcResponse(rpcResponse.context, rpcResponse?.value);
50
+ }
51
+
52
+ handleRpcResponse(context: Context, accountInfo?: AccountInfo<Buffer>): void {
53
+ const newSlot = context.slot;
54
+ let newBuffer: Buffer | undefined = undefined;
55
+ if (accountInfo) {
56
+ newBuffer = accountInfo.data;
57
+ }
38
58
 
39
- // if data has changed trigger update
40
- if (JSON.stringify(newData) !== JSON.stringify(this.data)) {
41
- this.data = newData;
59
+ if (!this.accountData) {
60
+ this.accountData = {
61
+ buffer: newBuffer,
62
+ slot: newSlot,
63
+ };
64
+ if (newBuffer) {
65
+ this.data = this.program.account[
66
+ this.accountName
67
+ ].coder.accounts.decode(capitalize(this.accountName), newBuffer);
68
+ this.onChange(this.data);
69
+ }
70
+ return;
71
+ }
72
+
73
+ if (newSlot <= this.accountData.slot) {
74
+ return;
75
+ }
76
+
77
+ const oldBuffer = this.accountData.buffer;
78
+ if (newBuffer && (!oldBuffer || !newBuffer.equals(oldBuffer))) {
79
+ this.accountData = {
80
+ buffer: newBuffer,
81
+ slot: newSlot,
82
+ };
83
+ this.data = this.program.account[this.accountName].coder.accounts.decode(
84
+ capitalize(this.accountName),
85
+ newBuffer
86
+ );
42
87
  this.onChange(this.data);
43
88
  }
44
89
  }
45
90
 
46
91
  unsubscribe(): Promise<void> {
47
- return this.program.account[this.accountName].unsubscribe(
48
- this.accountPublicKey
49
- );
92
+ if (this.listenerId) {
93
+ const promise =
94
+ this.program.provider.connection.removeAccountChangeListener(
95
+ this.listenerId
96
+ );
97
+ this.listenerId = undefined;
98
+ return promise;
99
+ }
50
100
  }
51
101
  }
@@ -11,6 +11,8 @@ import {
11
11
  FundingRateHistoryAccount,
12
12
  LiquidationHistoryAccount,
13
13
  MarketsAccount,
14
+ OrderHistoryAccount,
15
+ OrderStateAccount,
14
16
  StateAccount,
15
17
  TradeHistoryAccount,
16
18
  } from '../types';
@@ -19,8 +21,9 @@ import StrictEventEmitter from 'strict-event-emitter-types';
19
21
  import { EventEmitter } from 'events';
20
22
  import { getClearingHouseStateAccountPublicKey } from '../addresses';
21
23
  import { WebSocketAccountSubscriber } from './webSocketAccountSubscriber';
24
+ import { ClearingHouseConfigType } from '../factory/clearingHouse';
22
25
 
23
- export class DefaultClearingHouseAccountSubscriber
26
+ export class WebSocketClearingHouseAccountSubscriber
24
27
  implements ClearingHouseAccountSubscriber
25
28
  {
26
29
  isSubscribed: boolean;
@@ -34,9 +37,13 @@ export class DefaultClearingHouseAccountSubscriber
34
37
  fundingRateHistoryAccountSubscriber?: AccountSubscriber<FundingRateHistoryAccount>;
35
38
  curveHistoryAccountSubscriber?: AccountSubscriber<ExtendedCurveHistoryAccount>;
36
39
  liquidationHistoryAccountSubscriber?: AccountSubscriber<LiquidationHistoryAccount>;
40
+ orderStateAccountSubscriber?: AccountSubscriber<OrderStateAccount>;
41
+ orderHistoryAccountSubscriber?: AccountSubscriber<OrderHistoryAccount>;
37
42
 
38
43
  optionalExtraSubscriptions: ClearingHouseAccountTypes[] = [];
39
44
 
45
+ type: ClearingHouseConfigType = 'websocket';
46
+
40
47
  private isSubscribing = false;
41
48
  private subscriptionPromise: Promise<boolean>;
42
49
  private subscriptionPromiseResolver: (val: boolean) => void;
@@ -92,6 +99,21 @@ export class DefaultClearingHouseAccountSubscriber
92
99
  this.eventEmitter.emit('update');
93
100
  });
94
101
 
102
+ this.orderStateAccountSubscriber = new WebSocketAccountSubscriber(
103
+ 'orderState',
104
+ this.program,
105
+ state.orderState
106
+ );
107
+
108
+ await this.orderStateAccountSubscriber.subscribe(
109
+ (data: OrderStateAccount) => {
110
+ this.eventEmitter.emit('orderStateAccountUpdate', data);
111
+ this.eventEmitter.emit('update');
112
+ }
113
+ );
114
+
115
+ const orderState = this.orderStateAccountSubscriber.data;
116
+
95
117
  // create subscribers for other state accounts
96
118
 
97
119
  this.tradeHistoryAccountSubscriber = new WebSocketAccountSubscriber(
@@ -131,6 +153,12 @@ export class DefaultClearingHouseAccountSubscriber
131
153
  state.extendedCurveHistory
132
154
  );
133
155
 
156
+ this.orderHistoryAccountSubscriber = new WebSocketAccountSubscriber(
157
+ 'orderHistory',
158
+ this.program,
159
+ orderState.orderHistory
160
+ );
161
+
134
162
  const extraSusbcribersToUse: {
135
163
  subscriber: AccountSubscriber<any>;
136
164
  eventType: keyof ClearingHouseAccountEvents;
@@ -172,6 +200,12 @@ export class DefaultClearingHouseAccountSubscriber
172
200
  eventType: 'curveHistoryAccountUpdate',
173
201
  });
174
202
 
203
+ if (optionalSubscriptions?.includes('orderHistoryAccount'))
204
+ extraSusbcribersToUse.push({
205
+ subscriber: this.orderHistoryAccountSubscriber,
206
+ eventType: 'orderHistoryAccountUpdate',
207
+ });
208
+
175
209
  this.optionalExtraSubscriptions = optionalSubscriptions ?? [];
176
210
 
177
211
  // await all subcriptions in parallel to boost performance
@@ -219,6 +253,7 @@ export class DefaultClearingHouseAccountSubscriber
219
253
 
220
254
  await this.stateAccountSubscriber.unsubscribe();
221
255
  await this.marketsAccountSubscriber.unsubscribe();
256
+ await this.orderStateAccountSubscriber.unsubscribe();
222
257
 
223
258
  if (this.optionalExtraSubscriptions.includes('tradeHistoryAccount')) {
224
259
  await this.tradeHistoryAccountSubscriber.unsubscribe();
@@ -246,6 +281,10 @@ export class DefaultClearingHouseAccountSubscriber
246
281
  await this.liquidationHistoryAccountSubscriber.unsubscribe();
247
282
  }
248
283
 
284
+ if (this.optionalExtraSubscriptions.includes('orderHistoryAccount')) {
285
+ await this.orderHistoryAccountSubscriber.unsubscribe();
286
+ }
287
+
249
288
  this.isSubscribed = false;
250
289
  }
251
290
 
@@ -318,4 +357,15 @@ export class DefaultClearingHouseAccountSubscriber
318
357
  this.assertOptionalIsSubscribed('liquidationHistoryAccount');
319
358
  return this.liquidationHistoryAccountSubscriber.data;
320
359
  }
360
+
361
+ public getOrderHistoryAccount(): OrderHistoryAccount {
362
+ this.assertIsSubscribed();
363
+ this.assertOptionalIsSubscribed('orderHistoryAccount');
364
+ return this.orderHistoryAccountSubscriber.data;
365
+ }
366
+
367
+ public getOrderStateAccount(): OrderStateAccount {
368
+ this.assertIsSubscribed();
369
+ return this.orderStateAccountSubscriber.data;
370
+ }
321
371
  }
@@ -8,11 +8,15 @@ import { Program } from '@project-serum/anchor';
8
8
  import StrictEventEmitter from 'strict-event-emitter-types';
9
9
  import { EventEmitter } from 'events';
10
10
  import { PublicKey } from '@solana/web3.js';
11
- import { getUserAccountPublicKey } from '../addresses';
11
+ import {
12
+ getUserAccountPublicKey,
13
+ getUserOrdersAccountPublicKey,
14
+ } from '../addresses';
12
15
  import { WebSocketAccountSubscriber } from './webSocketAccountSubscriber';
13
- import { UserAccount, UserPositionsAccount } from '../types';
16
+ import { UserAccount, UserOrdersAccount, UserPositionsAccount } from '../types';
17
+ import { ClearingHouseConfigType } from '../factory/clearingHouse';
14
18
 
15
- export class DefaultUserAccountSubscriber implements UserAccountSubscriber {
19
+ export class WebSocketUserAccountSubscriber implements UserAccountSubscriber {
16
20
  isSubscribed: boolean;
17
21
  program: Program;
18
22
  eventEmitter: StrictEventEmitter<EventEmitter, UserAccountEvents>;
@@ -20,6 +24,9 @@ export class DefaultUserAccountSubscriber implements UserAccountSubscriber {
20
24
 
21
25
  userDataAccountSubscriber: AccountSubscriber<UserAccount>;
22
26
  userPositionsAccountSubscriber: AccountSubscriber<UserPositionsAccount>;
27
+ userOrdersAccountSubscriber: AccountSubscriber<UserOrdersAccount>;
28
+
29
+ type: ClearingHouseConfigType = 'websocket';
23
30
 
24
31
  public constructor(program: Program, authority: PublicKey) {
25
32
  this.isSubscribed = false;
@@ -61,6 +68,23 @@ export class DefaultUserAccountSubscriber implements UserAccountSubscriber {
61
68
  }
62
69
  );
63
70
 
71
+ const userOrdersPublicKey = await getUserOrdersAccountPublicKey(
72
+ this.program.programId,
73
+ userPublicKey
74
+ );
75
+
76
+ this.userOrdersAccountSubscriber = new WebSocketAccountSubscriber(
77
+ 'userOrders',
78
+ this.program,
79
+ userOrdersPublicKey
80
+ );
81
+ await this.userOrdersAccountSubscriber.subscribe(
82
+ (data: UserOrdersAccount) => {
83
+ this.eventEmitter.emit('userOrdersData', data);
84
+ this.eventEmitter.emit('update');
85
+ }
86
+ );
87
+
64
88
  this.eventEmitter.emit('update');
65
89
  this.isSubscribed = true;
66
90
  return true;
@@ -70,6 +94,7 @@ export class DefaultUserAccountSubscriber implements UserAccountSubscriber {
70
94
  await Promise.all([
71
95
  this.userDataAccountSubscriber.fetch(),
72
96
  this.userPositionsAccountSubscriber.fetch(),
97
+ this.userOrdersAccountSubscriber.fetch(),
73
98
  ]);
74
99
  }
75
100
 
@@ -81,6 +106,7 @@ export class DefaultUserAccountSubscriber implements UserAccountSubscriber {
81
106
  await Promise.all([
82
107
  this.userDataAccountSubscriber.unsubscribe(),
83
108
  this.userPositionsAccountSubscriber.unsubscribe(),
109
+ await this.userOrdersAccountSubscriber.unsubscribe(),
84
110
  ]);
85
111
 
86
112
  this.isSubscribed = false;
@@ -103,4 +129,8 @@ export class DefaultUserAccountSubscriber implements UserAccountSubscriber {
103
129
  this.assertIsSubscribed();
104
130
  return this.userPositionsAccountSubscriber.data;
105
131
  }
132
+
133
+ public getUserOrdersAccount(): UserOrdersAccount {
134
+ return this.userOrdersAccountSubscriber.data;
135
+ }
106
136
  }
package/src/addresses.ts CHANGED
@@ -10,6 +10,21 @@ export async function getClearingHouseStateAccountPublicKeyAndNonce(
10
10
  );
11
11
  }
12
12
 
13
+ export async function getOrderStateAccountPublicKey(
14
+ programId: PublicKey
15
+ ): Promise<PublicKey> {
16
+ return (await getOrderStateAccountPublicKeyAndNonce(programId))[0];
17
+ }
18
+
19
+ export async function getOrderStateAccountPublicKeyAndNonce(
20
+ programId: PublicKey
21
+ ): Promise<[PublicKey, number]> {
22
+ return anchor.web3.PublicKey.findProgramAddress(
23
+ [Buffer.from(anchor.utils.bytes.utf8.encode('order_state'))],
24
+ programId
25
+ );
26
+ }
27
+
13
28
  export async function getClearingHouseStateAccountPublicKey(
14
29
  programId: PublicKey
15
30
  ): Promise<PublicKey> {
@@ -32,3 +47,25 @@ export async function getUserAccountPublicKey(
32
47
  ): Promise<PublicKey> {
33
48
  return (await getUserAccountPublicKeyAndNonce(programId, authority))[0];
34
49
  }
50
+
51
+ export async function getUserOrdersAccountPublicKeyAndNonce(
52
+ programId: PublicKey,
53
+ userAccount: PublicKey
54
+ ): Promise<[PublicKey, number]> {
55
+ return anchor.web3.PublicKey.findProgramAddress(
56
+ [
57
+ Buffer.from(anchor.utils.bytes.utf8.encode('user_orders')),
58
+ userAccount.toBuffer(),
59
+ ],
60
+ programId
61
+ );
62
+ }
63
+
64
+ export async function getUserOrdersAccountPublicKey(
65
+ programId: PublicKey,
66
+ userAccount: PublicKey
67
+ ): Promise<PublicKey> {
68
+ return (
69
+ await getUserOrdersAccountPublicKeyAndNonce(programId, userAccount)
70
+ )[0];
71
+ }