@drift-labs/sdk 0.1.19-master.1 → 0.1.21-master.3
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.
- package/lib/accounts/bulkAccountLoader.d.ts +31 -0
- package/lib/accounts/bulkAccountLoader.js +177 -0
- package/lib/accounts/bulkUserSubscription.d.ts +7 -0
- package/lib/accounts/bulkUserSubscription.js +28 -0
- package/lib/accounts/pollingClearingHouseAccountSubscriber.d.ts +49 -0
- package/lib/accounts/pollingClearingHouseAccountSubscriber.js +228 -0
- package/lib/accounts/pollingTokenAccountSubscriber.d.ts +25 -0
- package/lib/accounts/pollingTokenAccountSubscriber.js +79 -0
- package/lib/accounts/pollingUserAccountSubscriber.d.ts +32 -0
- package/lib/accounts/pollingUserAccountSubscriber.js +136 -0
- package/lib/accounts/types.d.ts +38 -3
- package/lib/accounts/utils.d.ts +1 -0
- package/lib/accounts/utils.js +7 -0
- package/lib/accounts/webSocketAccountSubscriber.d.ts +6 -3
- package/lib/accounts/webSocketAccountSubscriber.js +43 -12
- package/lib/accounts/{defaultClearingHouseAccountSubscriber.d.ts → webSocketClearingHouseAccountSubscriber.d.ts} +8 -3
- package/lib/accounts/{defaultClearingHouseAccountSubscriber.js → webSocketClearingHouseAccountSubscriber.js} +30 -4
- package/lib/accounts/{defaultUserAccountSubscriber.d.ts → webSocketUserAccountSubscriber.d.ts} +6 -3
- package/lib/accounts/{defaultUserAccountSubscriber.js → webSocketUserAccountSubscriber.js} +16 -4
- package/lib/addresses.d.ts +4 -1
- package/lib/addresses.js +28 -1
- package/lib/admin.d.ts +10 -4
- package/lib/admin.js +54 -17
- package/lib/assert/assert.d.ts +0 -1
- package/lib/clearingHouse.d.ts +39 -4
- package/lib/clearingHouse.js +334 -23
- package/lib/clearingHouseUser.d.ts +26 -20
- package/lib/clearingHouseUser.js +149 -118
- package/lib/config.d.ts +0 -1
- package/lib/constants/markets.d.ts +2 -2
- package/lib/constants/markets.js +28 -15
- package/lib/constants/numericConstants.d.ts +4 -2
- package/lib/constants/numericConstants.js +16 -17
- package/lib/examples/makeTradeExample.d.ts +0 -1
- package/lib/examples/makeTradeExample.js +6 -6
- package/lib/factory/clearingHouse.d.ts +25 -0
- package/lib/factory/clearingHouse.js +64 -0
- package/lib/factory/clearingHouseUser.d.ts +19 -0
- package/lib/factory/clearingHouseUser.js +34 -0
- package/lib/idl/clearing_house.json +1066 -39
- package/lib/index.d.ts +11 -3
- package/lib/index.js +12 -2
- package/lib/math/amm.d.ts +1 -1
- package/lib/math/amm.js +38 -15
- package/lib/math/conversion.d.ts +1 -2
- package/lib/math/conversion.js +1 -1
- package/lib/math/funding.d.ts +0 -1
- package/lib/math/funding.js +1 -1
- package/lib/math/insuranceFund.d.ts +2 -2
- package/lib/math/insuranceFund.js +3 -6
- package/lib/math/market.d.ts +2 -2
- package/lib/math/market.js +12 -2
- package/lib/math/orders.d.ts +3 -0
- package/lib/math/orders.js +32 -0
- package/lib/math/position.d.ts +6 -3
- package/lib/math/position.js +21 -10
- package/lib/math/trade.d.ts +0 -1
- package/lib/math/trade.js +16 -16
- package/lib/math/utils.d.ts +2 -2
- package/lib/math/utils.js +3 -3
- package/lib/mockUSDCFaucet.d.ts +2 -2
- package/lib/orderParams.d.ts +7 -0
- package/lib/orderParams.js +108 -0
- package/lib/orders.d.ts +6 -0
- package/lib/orders.js +136 -0
- package/lib/pythClient.d.ts +0 -1
- package/lib/pythClient.js +1 -1
- package/lib/token/index.d.ts +3 -0
- package/lib/token/index.js +38 -0
- package/lib/tx/defaultTxSender.d.ts +0 -1
- package/lib/tx/types.d.ts +0 -1
- package/lib/tx/utils.d.ts +0 -1
- package/lib/types.d.ts +147 -3
- package/lib/types.js +36 -1
- package/lib/util/computeUnits.d.ts +0 -1
- package/lib/util/tps.d.ts +0 -1
- package/lib/wallet.d.ts +0 -1
- package/package.json +11 -3
- package/src/accounts/bulkAccountLoader.ts +215 -0
- package/src/accounts/bulkUserSubscription.ts +28 -0
- package/src/accounts/pollingClearingHouseAccountSubscriber.ts +326 -0
- package/src/accounts/pollingTokenAccountSubscriber.ts +99 -0
- package/src/accounts/pollingUserAccountSubscriber.ts +194 -0
- package/src/accounts/types.ts +48 -1
- package/src/accounts/utils.ts +3 -0
- package/src/accounts/webSocketAccountSubscriber.ts +67 -17
- package/src/accounts/{defaultClearingHouseAccountSubscriber.ts → webSocketClearingHouseAccountSubscriber.ts} +51 -1
- package/src/accounts/{defaultUserAccountSubscriber.ts → webSocketUserAccountSubscriber.ts} +33 -3
- package/src/addresses.ts +37 -0
- package/src/admin.ts +92 -24
- package/src/clearingHouse.ts +455 -22
- package/src/clearingHouseUser.ts +190 -108
- package/src/constants/markets.ts +17 -1
- package/src/constants/numericConstants.ts +3 -1
- package/src/examples/makeTradeExample.ts +4 -1
- package/src/factory/clearingHouse.ts +125 -0
- package/src/factory/clearingHouseUser.ts +73 -0
- package/src/idl/clearing_house.json +1066 -39
- package/src/index.ts +11 -2
- package/src/math/amm.ts +47 -14
- package/src/math/conversion.ts +1 -1
- package/src/math/insuranceFund.ts +1 -1
- package/src/math/market.ts +28 -2
- package/src/math/orders.ts +44 -0
- package/src/math/position.ts +24 -4
- package/src/math/utils.ts +1 -1
- package/src/mockUSDCFaucet.ts +1 -1
- package/src/orderParams.ts +151 -0
- package/src/orders.ts +236 -0
- package/src/token/index.ts +37 -0
- package/src/types.ts +130 -2
- package/tsconfig.json +0 -1
- package/lib/accounts/defaultClearingHouseAccountSubscriber.d.ts.map +0 -1
- package/lib/accounts/defaultUserAccountSubscriber.d.ts.map +0 -1
- package/lib/accounts/types.d.ts.map +0 -1
- package/lib/accounts/webSocketAccountSubscriber.d.ts.map +0 -1
- package/lib/addresses.d.ts.map +0 -1
- package/lib/admin.d.ts.map +0 -1
- package/lib/assert/assert.d.ts.map +0 -1
- package/lib/clearingHouse.d.ts.map +0 -1
- package/lib/clearingHouseUser.d.ts.map +0 -1
- package/lib/config.d.ts.map +0 -1
- package/lib/constants/markets.d.ts.map +0 -1
- package/lib/constants/numericConstants.d.ts.map +0 -1
- package/lib/examples/makeTradeExample.d.ts.map +0 -1
- package/lib/index.d.ts.map +0 -1
- package/lib/math/amm.d.ts.map +0 -1
- package/lib/math/conversion.d.ts.map +0 -1
- package/lib/math/funding.d.ts.map +0 -1
- package/lib/math/insuranceFund.d.ts.map +0 -1
- package/lib/math/market.d.ts.map +0 -1
- package/lib/math/position.d.ts.map +0 -1
- package/lib/math/trade.d.ts.map +0 -1
- package/lib/math/utils.d.ts.map +0 -1
- package/lib/mockUSDCFaucet.d.ts.map +0 -1
- package/lib/pythClient.d.ts.map +0 -1
- package/lib/tx/defaultTxSender.d.ts.map +0 -1
- package/lib/tx/types.d.ts.map +0 -1
- package/lib/tx/utils.d.ts.map +0 -1
- package/lib/types.d.ts.map +0 -1
- package/lib/util/computeUnits.d.ts.map +0 -1
- package/lib/util/tps.d.ts.map +0 -1
- 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
|
+
}
|
package/src/accounts/types.ts
CHANGED
|
@@ -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
|
+
};
|
|
@@ -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.
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
this.
|
|
30
|
-
|
|
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
|
|
36
|
-
this.
|
|
37
|
-
|
|
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
|
-
|
|
40
|
-
|
|
41
|
-
|
|
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
|
-
|
|
48
|
-
|
|
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
|
|
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 {
|
|
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
|
|
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
|
+
}
|