@drift-labs/sdk 0.1.19-master.0 → 0.1.21-master.0
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 +32 -0
- package/lib/accounts/bulkAccountLoader.d.ts.map +1 -0
- package/lib/accounts/bulkAccountLoader.js +175 -0
- package/lib/accounts/bulkUserSubscription.d.ts +8 -0
- package/lib/accounts/bulkUserSubscription.d.ts.map +1 -0
- package/lib/accounts/bulkUserSubscription.js +28 -0
- package/lib/accounts/pollingClearingHouseAccountSubscriber.d.ts +46 -0
- package/lib/accounts/pollingClearingHouseAccountSubscriber.d.ts.map +1 -0
- package/lib/accounts/pollingClearingHouseAccountSubscriber.js +206 -0
- package/lib/accounts/pollingTokenAccountSubscriber.d.ts +26 -0
- package/lib/accounts/pollingTokenAccountSubscriber.d.ts.map +1 -0
- package/lib/accounts/pollingTokenAccountSubscriber.js +79 -0
- package/lib/accounts/pollingUserAccountSubscriber.d.ts +31 -0
- package/lib/accounts/pollingUserAccountSubscriber.d.ts.map +1 -0
- package/lib/accounts/pollingUserAccountSubscriber.js +123 -0
- package/lib/accounts/types.d.ts +30 -0
- package/lib/accounts/types.d.ts.map +1 -1
- package/lib/accounts/utils.d.ts +2 -0
- package/lib/accounts/utils.d.ts.map +1 -0
- package/lib/accounts/utils.js +7 -0
- package/lib/accounts/webSocketAccountSubscriber.d.ts +6 -2
- package/lib/accounts/webSocketAccountSubscriber.d.ts.map +1 -1
- package/lib/accounts/webSocketAccountSubscriber.js +43 -12
- package/lib/accounts/{defaultClearingHouseAccountSubscriber.d.ts → webSocketClearingHouseAccountSubscriber.d.ts} +4 -2
- package/lib/accounts/webSocketClearingHouseAccountSubscriber.d.ts.map +1 -0
- package/lib/accounts/{defaultClearingHouseAccountSubscriber.js → webSocketClearingHouseAccountSubscriber.js} +5 -4
- package/lib/accounts/{defaultUserAccountSubscriber.d.ts → webSocketUserAccountSubscriber.d.ts} +4 -2
- package/lib/accounts/webSocketUserAccountSubscriber.d.ts.map +1 -0
- package/lib/accounts/{defaultUserAccountSubscriber.js → webSocketUserAccountSubscriber.js} +5 -4
- package/lib/admin.d.ts +1 -0
- package/lib/admin.d.ts.map +1 -1
- package/lib/admin.js +23 -14
- package/lib/clearingHouse.d.ts +12 -2
- package/lib/clearingHouse.d.ts.map +1 -1
- package/lib/clearingHouse.js +28 -17
- package/lib/clearingHouseUser.d.ts +11 -3
- package/lib/clearingHouseUser.d.ts.map +1 -1
- package/lib/clearingHouseUser.js +46 -36
- package/lib/constants/markets.d.ts +2 -1
- package/lib/constants/markets.d.ts.map +1 -1
- package/lib/constants/markets.js +20 -15
- package/lib/constants/numericConstants.d.ts +3 -1
- package/lib/constants/numericConstants.d.ts.map +1 -1
- package/lib/constants/numericConstants.js +15 -17
- package/lib/examples/makeTradeExample.js +6 -6
- package/lib/factory/clearingHouse.d.ts +26 -0
- package/lib/factory/clearingHouse.d.ts.map +1 -0
- package/lib/factory/clearingHouse.js +64 -0
- package/lib/factory/clearingHouseUser.d.ts +20 -0
- package/lib/factory/clearingHouseUser.d.ts.map +1 -0
- package/lib/factory/clearingHouseUser.js +34 -0
- package/lib/index.d.ts +8 -2
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +9 -2
- package/lib/math/amm.js +7 -7
- package/lib/math/conversion.d.ts +1 -1
- package/lib/math/conversion.d.ts.map +1 -1
- package/lib/math/conversion.js +1 -1
- package/lib/math/funding.js +1 -1
- package/lib/math/insuranceFund.d.ts +2 -1
- package/lib/math/insuranceFund.d.ts.map +1 -1
- package/lib/math/insuranceFund.js +3 -6
- package/lib/math/market.js +1 -1
- package/lib/math/position.d.ts +2 -1
- package/lib/math/position.d.ts.map +1 -1
- package/lib/math/position.js +3 -6
- package/lib/math/trade.js +16 -16
- package/lib/math/utils.d.ts +2 -1
- package/lib/math/utils.d.ts.map +1 -1
- package/lib/math/utils.js +3 -3
- package/lib/mockUSDCFaucet.d.ts +2 -1
- package/lib/mockUSDCFaucet.d.ts.map +1 -1
- package/lib/pythClient.js +1 -1
- package/lib/token/index.d.ts +4 -0
- package/lib/token/index.d.ts.map +1 -0
- package/lib/token/index.js +38 -0
- package/lib/types.d.ts +2 -1
- package/lib/types.d.ts.map +1 -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 +293 -0
- package/src/accounts/pollingTokenAccountSubscriber.ts +99 -0
- package/src/accounts/pollingUserAccountSubscriber.ts +166 -0
- package/src/accounts/types.ts +38 -0
- package/src/accounts/utils.ts +3 -0
- package/src/accounts/webSocketAccountSubscriber.ts +67 -17
- package/src/accounts/{defaultClearingHouseAccountSubscriber.ts → webSocketClearingHouseAccountSubscriber.ts} +4 -1
- package/src/accounts/{defaultUserAccountSubscriber.ts → webSocketUserAccountSubscriber.ts} +4 -1
- package/src/admin.ts +27 -18
- package/src/clearingHouse.ts +25 -17
- package/src/clearingHouseUser.ts +26 -6
- package/src/constants/markets.ts +9 -1
- package/src/constants/numericConstants.ts +2 -1
- package/src/examples/makeTradeExample.ts +4 -1
- package/src/factory/clearingHouse.ts +125 -0
- package/src/factory/clearingHouseUser.ts +73 -0
- package/src/index.ts +8 -2
- package/src/math/conversion.ts +1 -1
- package/src/math/insuranceFund.ts +1 -1
- package/src/math/position.ts +1 -1
- package/src/math/utils.ts +1 -1
- package/src/mockUSDCFaucet.ts +1 -1
- package/src/token/index.ts +37 -0
- package/src/types.ts +1 -1
- package/lib/accounts/defaultClearingHouseAccountSubscriber.d.ts.map +0 -1
- package/lib/accounts/defaultUserAccountSubscriber.d.ts.map +0 -1
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import {
|
|
2
|
+
NotSubscribedError,
|
|
3
|
+
TokenAccountEvents,
|
|
4
|
+
TokenAccountSubscriber,
|
|
5
|
+
} from './types';
|
|
6
|
+
import { Program } from '@project-serum/anchor';
|
|
7
|
+
import StrictEventEmitter from 'strict-event-emitter-types';
|
|
8
|
+
import { EventEmitter } from 'events';
|
|
9
|
+
import { PublicKey } from '@solana/web3.js';
|
|
10
|
+
import { BulkAccountLoader } from './bulkAccountLoader';
|
|
11
|
+
import { AccountInfo } from '@solana/spl-token';
|
|
12
|
+
import { parseTokenAccount } from '../token';
|
|
13
|
+
|
|
14
|
+
export class PollingTokenAccountSubscriber implements TokenAccountSubscriber {
|
|
15
|
+
isSubscribed: boolean;
|
|
16
|
+
program: Program;
|
|
17
|
+
eventEmitter: StrictEventEmitter<EventEmitter, TokenAccountEvents>;
|
|
18
|
+
publicKey: PublicKey;
|
|
19
|
+
|
|
20
|
+
accountLoader: BulkAccountLoader;
|
|
21
|
+
callbackId?: string;
|
|
22
|
+
errorCallbackId?: string;
|
|
23
|
+
|
|
24
|
+
tokenAccount?: AccountInfo;
|
|
25
|
+
|
|
26
|
+
public constructor(publicKey: PublicKey, accountLoader: BulkAccountLoader) {
|
|
27
|
+
this.isSubscribed = false;
|
|
28
|
+
this.publicKey = publicKey;
|
|
29
|
+
this.accountLoader = accountLoader;
|
|
30
|
+
this.eventEmitter = new EventEmitter();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async subscribe(): Promise<boolean> {
|
|
34
|
+
if (this.isSubscribed) {
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
this.addToAccountLoader();
|
|
39
|
+
await this.fetch();
|
|
40
|
+
this.eventEmitter.emit('update');
|
|
41
|
+
|
|
42
|
+
this.isSubscribed = true;
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
addToAccountLoader(): void {
|
|
47
|
+
if (this.callbackId) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
this.callbackId = this.accountLoader.addAccount(
|
|
52
|
+
this.publicKey,
|
|
53
|
+
(buffer) => {
|
|
54
|
+
const tokenAccount = parseTokenAccount(buffer);
|
|
55
|
+
this.tokenAccount = tokenAccount;
|
|
56
|
+
// @ts-ignore
|
|
57
|
+
this.eventEmitter.emit('tokenAccountUpdate', tokenAccount);
|
|
58
|
+
this.eventEmitter.emit('update');
|
|
59
|
+
}
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
this.errorCallbackId = this.accountLoader.addErrorCallbacks((error) => {
|
|
63
|
+
this.eventEmitter.emit('error', error);
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async fetch(): Promise<void> {
|
|
68
|
+
await this.accountLoader.load();
|
|
69
|
+
const buffer = this.accountLoader.getAccountData(this.publicKey);
|
|
70
|
+
this.tokenAccount = parseTokenAccount(buffer);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async unsubscribe(): Promise<void> {
|
|
74
|
+
if (!this.isSubscribed) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
this.accountLoader.removeAccount(this.publicKey, this.callbackId);
|
|
79
|
+
this.callbackId = undefined;
|
|
80
|
+
|
|
81
|
+
this.accountLoader.removeErrorCallbacks(this.errorCallbackId);
|
|
82
|
+
this.errorCallbackId = undefined;
|
|
83
|
+
|
|
84
|
+
this.isSubscribed = false;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
assertIsSubscribed(): void {
|
|
88
|
+
if (!this.isSubscribed) {
|
|
89
|
+
throw new NotSubscribedError(
|
|
90
|
+
'You must call `subscribe` before using this function'
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
public getTokenAccount(): AccountInfo {
|
|
96
|
+
this.assertIsSubscribed();
|
|
97
|
+
return this.tokenAccount;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
@@ -0,0 +1,166 @@
|
|
|
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 { getUserAccountPublicKey } from '../addresses';
|
|
12
|
+
import { UserAccount, UserPositionsAccount } from '../types';
|
|
13
|
+
import { BulkAccountLoader } from './bulkAccountLoader';
|
|
14
|
+
import { capitalize } from './utils';
|
|
15
|
+
import { ClearingHouseConfigType } from '../factory/clearingHouse';
|
|
16
|
+
|
|
17
|
+
export class PollingUserAccountSubscriber implements UserAccountSubscriber {
|
|
18
|
+
isSubscribed: boolean;
|
|
19
|
+
program: Program;
|
|
20
|
+
eventEmitter: StrictEventEmitter<EventEmitter, UserAccountEvents>;
|
|
21
|
+
authority: PublicKey;
|
|
22
|
+
|
|
23
|
+
accountLoader: BulkAccountLoader;
|
|
24
|
+
accountsToPoll = new Map<string, AccountToPoll>();
|
|
25
|
+
errorCallbackId?: string;
|
|
26
|
+
|
|
27
|
+
user?: UserAccount;
|
|
28
|
+
userPositions?: UserPositionsAccount;
|
|
29
|
+
|
|
30
|
+
type: ClearingHouseConfigType = 'polling';
|
|
31
|
+
|
|
32
|
+
public constructor(
|
|
33
|
+
program: Program,
|
|
34
|
+
authority: PublicKey,
|
|
35
|
+
accountLoader: BulkAccountLoader
|
|
36
|
+
) {
|
|
37
|
+
this.isSubscribed = false;
|
|
38
|
+
this.program = program;
|
|
39
|
+
this.authority = authority;
|
|
40
|
+
this.accountLoader = accountLoader;
|
|
41
|
+
this.eventEmitter = new EventEmitter();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async subscribe(): Promise<boolean> {
|
|
45
|
+
if (this.isSubscribed) {
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
await this.addToAccountLoader();
|
|
50
|
+
await this.fetchIfUnloaded();
|
|
51
|
+
this.eventEmitter.emit('update');
|
|
52
|
+
|
|
53
|
+
this.isSubscribed = true;
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async addToAccountLoader(): Promise<void> {
|
|
58
|
+
if (this.accountsToPoll.size > 0) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const userPublicKey = await getUserAccountPublicKey(
|
|
63
|
+
this.program.programId,
|
|
64
|
+
this.authority
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
const userAccount = (await this.program.account.user.fetch(
|
|
68
|
+
userPublicKey
|
|
69
|
+
)) as UserAccount;
|
|
70
|
+
|
|
71
|
+
this.accountsToPoll.set(userPublicKey.toString(), {
|
|
72
|
+
key: 'user',
|
|
73
|
+
publicKey: userPublicKey,
|
|
74
|
+
eventType: 'userAccountData',
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
this.accountsToPoll.set(userAccount.positions.toString(), {
|
|
78
|
+
key: 'userPositions',
|
|
79
|
+
publicKey: userAccount.positions,
|
|
80
|
+
eventType: 'userPositionsData',
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
for (const [_, accountToPoll] of this.accountsToPoll) {
|
|
84
|
+
accountToPoll.callbackId = this.accountLoader.addAccount(
|
|
85
|
+
accountToPoll.publicKey,
|
|
86
|
+
(buffer) => {
|
|
87
|
+
const account = this.program.account[
|
|
88
|
+
accountToPoll.key
|
|
89
|
+
].coder.accounts.decode(capitalize(accountToPoll.key), buffer);
|
|
90
|
+
this[accountToPoll.key] = account;
|
|
91
|
+
// @ts-ignore
|
|
92
|
+
this.eventEmitter.emit(accountToPoll.eventType, account);
|
|
93
|
+
this.eventEmitter.emit('update');
|
|
94
|
+
}
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
this.errorCallbackId = this.accountLoader.addErrorCallbacks((error) => {
|
|
99
|
+
this.eventEmitter.emit('error', error);
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async fetchIfUnloaded(): Promise<void> {
|
|
104
|
+
let shouldFetch = false;
|
|
105
|
+
for (const [_, accountToPoll] of this.accountsToPoll) {
|
|
106
|
+
if (this[accountToPoll.key] === undefined) {
|
|
107
|
+
shouldFetch = true;
|
|
108
|
+
break;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (shouldFetch) {
|
|
113
|
+
await this.fetch();
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
async fetch(): Promise<void> {
|
|
118
|
+
await this.accountLoader.load();
|
|
119
|
+
for (const [_, accountToPoll] of this.accountsToPoll) {
|
|
120
|
+
const buffer = this.accountLoader.getAccountData(accountToPoll.publicKey);
|
|
121
|
+
if (buffer) {
|
|
122
|
+
this[accountToPoll.key] = this.program.account[
|
|
123
|
+
accountToPoll.key
|
|
124
|
+
].coder.accounts.decode(capitalize(accountToPoll.key), buffer);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
async unsubscribe(): Promise<void> {
|
|
130
|
+
if (!this.isSubscribed) {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
for (const [_, accountToPoll] of this.accountsToPoll) {
|
|
135
|
+
this.accountLoader.removeAccount(
|
|
136
|
+
accountToPoll.publicKey,
|
|
137
|
+
accountToPoll.callbackId
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
this.accountLoader.removeErrorCallbacks(this.errorCallbackId);
|
|
142
|
+
this.errorCallbackId = undefined;
|
|
143
|
+
|
|
144
|
+
this.accountsToPoll.clear();
|
|
145
|
+
|
|
146
|
+
this.isSubscribed = false;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
assertIsSubscribed(): void {
|
|
150
|
+
if (!this.isSubscribed) {
|
|
151
|
+
throw new NotSubscribedError(
|
|
152
|
+
'You must call `subscribe` before using this function'
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
public getUserAccount(): UserAccount {
|
|
158
|
+
this.assertIsSubscribed();
|
|
159
|
+
return this.user;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
public getUserPositionsAccount(): UserPositionsAccount {
|
|
163
|
+
this.assertIsSubscribed();
|
|
164
|
+
return this.userPositions;
|
|
165
|
+
}
|
|
166
|
+
}
|
package/src/accounts/types.ts
CHANGED
|
@@ -12,6 +12,9 @@ import {
|
|
|
12
12
|
} from '../types';
|
|
13
13
|
import StrictEventEmitter from 'strict-event-emitter-types';
|
|
14
14
|
import { EventEmitter } from 'events';
|
|
15
|
+
import { PublicKey } from '@solana/web3.js';
|
|
16
|
+
import { AccountInfo } from '@solana/spl-token';
|
|
17
|
+
import { ClearingHouseConfigType, ClearingHouseUserConfigType } from '..';
|
|
15
18
|
|
|
16
19
|
export interface AccountSubscriber<T> {
|
|
17
20
|
data?: T;
|
|
@@ -36,6 +39,7 @@ export interface ClearingHouseAccountEvents {
|
|
|
36
39
|
depositHistoryAccountUpdate: (payload: DepositHistoryAccount) => void;
|
|
37
40
|
curveHistoryAccountUpdate: (payload: ExtendedCurveHistoryAccount) => void;
|
|
38
41
|
update: void;
|
|
42
|
+
error: (e: Error) => void;
|
|
39
43
|
}
|
|
40
44
|
|
|
41
45
|
export type ClearingHouseAccountTypes =
|
|
@@ -66,12 +70,15 @@ export interface ClearingHouseAccountSubscriber {
|
|
|
66
70
|
getFundingRateHistoryAccount(): FundingRateHistoryAccount;
|
|
67
71
|
getCurveHistoryAccount(): ExtendedCurveHistoryAccount;
|
|
68
72
|
getLiquidationHistoryAccount(): LiquidationHistoryAccount;
|
|
73
|
+
|
|
74
|
+
type: ClearingHouseConfigType;
|
|
69
75
|
}
|
|
70
76
|
|
|
71
77
|
export interface UserAccountEvents {
|
|
72
78
|
userAccountData: (payload: UserAccount) => void;
|
|
73
79
|
userPositionsData: (payload: UserPositionsAccount) => void;
|
|
74
80
|
update: void;
|
|
81
|
+
error: (e: Error) => void;
|
|
75
82
|
}
|
|
76
83
|
|
|
77
84
|
export interface UserAccountSubscriber {
|
|
@@ -84,4 +91,35 @@ export interface UserAccountSubscriber {
|
|
|
84
91
|
|
|
85
92
|
getUserAccount(): UserAccount;
|
|
86
93
|
getUserPositionsAccount(): UserPositionsAccount;
|
|
94
|
+
|
|
95
|
+
type: ClearingHouseUserConfigType;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export interface TokenAccountEvents {
|
|
99
|
+
tokenAccountUpdate: (payload: AccountInfo) => void;
|
|
100
|
+
update: void;
|
|
101
|
+
error: (e: Error) => void;
|
|
87
102
|
}
|
|
103
|
+
|
|
104
|
+
export interface TokenAccountSubscriber {
|
|
105
|
+
eventEmitter: StrictEventEmitter<EventEmitter, TokenAccountEvents>;
|
|
106
|
+
isSubscribed: boolean;
|
|
107
|
+
|
|
108
|
+
subscribe(): Promise<boolean>;
|
|
109
|
+
fetch(): Promise<void>;
|
|
110
|
+
unsubscribe(): Promise<void>;
|
|
111
|
+
|
|
112
|
+
getTokenAccount(): AccountInfo;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export type AccountToPoll = {
|
|
116
|
+
key: string;
|
|
117
|
+
publicKey: PublicKey;
|
|
118
|
+
eventType: string;
|
|
119
|
+
callbackId?: string;
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
export type AccountData = {
|
|
123
|
+
slot: number;
|
|
124
|
+
buffer: Buffer | undefined;
|
|
125
|
+
};
|
|
@@ -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
|
}
|
|
@@ -19,8 +19,9 @@ import StrictEventEmitter from 'strict-event-emitter-types';
|
|
|
19
19
|
import { EventEmitter } from 'events';
|
|
20
20
|
import { getClearingHouseStateAccountPublicKey } from '../addresses';
|
|
21
21
|
import { WebSocketAccountSubscriber } from './webSocketAccountSubscriber';
|
|
22
|
+
import { ClearingHouseConfigType } from '../factory/clearingHouse';
|
|
22
23
|
|
|
23
|
-
export class
|
|
24
|
+
export class WebSocketClearingHouseAccountSubscriber
|
|
24
25
|
implements ClearingHouseAccountSubscriber
|
|
25
26
|
{
|
|
26
27
|
isSubscribed: boolean;
|
|
@@ -37,6 +38,8 @@ export class DefaultClearingHouseAccountSubscriber
|
|
|
37
38
|
|
|
38
39
|
optionalExtraSubscriptions: ClearingHouseAccountTypes[] = [];
|
|
39
40
|
|
|
41
|
+
type: ClearingHouseConfigType = 'websocket';
|
|
42
|
+
|
|
40
43
|
private isSubscribing = false;
|
|
41
44
|
private subscriptionPromise: Promise<boolean>;
|
|
42
45
|
private subscriptionPromiseResolver: (val: boolean) => void;
|
|
@@ -11,8 +11,9 @@ import { PublicKey } from '@solana/web3.js';
|
|
|
11
11
|
import { getUserAccountPublicKey } from '../addresses';
|
|
12
12
|
import { WebSocketAccountSubscriber } from './webSocketAccountSubscriber';
|
|
13
13
|
import { UserAccount, UserPositionsAccount } from '../types';
|
|
14
|
+
import { ClearingHouseConfigType } from '../factory/clearingHouse';
|
|
14
15
|
|
|
15
|
-
export class
|
|
16
|
+
export class WebSocketUserAccountSubscriber implements UserAccountSubscriber {
|
|
16
17
|
isSubscribed: boolean;
|
|
17
18
|
program: Program;
|
|
18
19
|
eventEmitter: StrictEventEmitter<EventEmitter, UserAccountEvents>;
|
|
@@ -21,6 +22,8 @@ export class DefaultUserAccountSubscriber implements UserAccountSubscriber {
|
|
|
21
22
|
userDataAccountSubscriber: AccountSubscriber<UserAccount>;
|
|
22
23
|
userPositionsAccountSubscriber: AccountSubscriber<UserPositionsAccount>;
|
|
23
24
|
|
|
25
|
+
type: ClearingHouseConfigType = 'websocket';
|
|
26
|
+
|
|
24
27
|
public constructor(program: Program, authority: PublicKey) {
|
|
25
28
|
this.isSubscribed = false;
|
|
26
29
|
this.program = program;
|
package/src/admin.ts
CHANGED
|
@@ -6,17 +6,18 @@ import {
|
|
|
6
6
|
TransactionSignature,
|
|
7
7
|
} from '@solana/web3.js';
|
|
8
8
|
import { FeeStructure, IWallet, OracleGuardRails, OracleSource } from './types';
|
|
9
|
-
import { BN,
|
|
9
|
+
import { BN, Provider } from '@project-serum/anchor';
|
|
10
10
|
import * as anchor from '@project-serum/anchor';
|
|
11
11
|
import { getClearingHouseStateAccountPublicKeyAndNonce } from './addresses';
|
|
12
12
|
import { TOKEN_PROGRAM_ID } from '@solana/spl-token';
|
|
13
13
|
import { ClearingHouse } from './clearingHouse';
|
|
14
14
|
import { PEG_PRECISION } from './constants/numericConstants';
|
|
15
|
-
import clearingHouseIDL from './idl/clearing_house.json';
|
|
16
|
-
import { DefaultClearingHouseAccountSubscriber } from './accounts/defaultClearingHouseAccountSubscriber';
|
|
17
|
-
import { DefaultTxSender } from './tx/defaultTxSender';
|
|
18
15
|
import { calculateTargetPriceTrade } from './math/trade';
|
|
19
16
|
import { calculateAmmReservesAfterSwap, getSwapDirection } from './math/amm';
|
|
17
|
+
import {
|
|
18
|
+
getAdmin,
|
|
19
|
+
getWebSocketClearingHouseConfig,
|
|
20
|
+
} from './factory/clearingHouse';
|
|
20
21
|
|
|
21
22
|
export class Admin extends ClearingHouse {
|
|
22
23
|
public static from(
|
|
@@ -25,24 +26,13 @@ export class Admin extends ClearingHouse {
|
|
|
25
26
|
clearingHouseProgramId: PublicKey,
|
|
26
27
|
opts: ConfirmOptions = Provider.defaultOptions()
|
|
27
28
|
): Admin {
|
|
28
|
-
const
|
|
29
|
-
const program = new Program(
|
|
30
|
-
clearingHouseIDL as Idl,
|
|
31
|
-
clearingHouseProgramId,
|
|
32
|
-
provider
|
|
33
|
-
);
|
|
34
|
-
const accountSubscriber = new DefaultClearingHouseAccountSubscriber(
|
|
35
|
-
program
|
|
36
|
-
);
|
|
37
|
-
const txSender = new DefaultTxSender(provider);
|
|
38
|
-
return new Admin(
|
|
29
|
+
const config = getWebSocketClearingHouseConfig(
|
|
39
30
|
connection,
|
|
40
31
|
wallet,
|
|
41
|
-
|
|
42
|
-
accountSubscriber,
|
|
43
|
-
txSender,
|
|
32
|
+
clearingHouseProgramId,
|
|
44
33
|
opts
|
|
45
34
|
);
|
|
35
|
+
return getAdmin(config);
|
|
46
36
|
}
|
|
47
37
|
|
|
48
38
|
public async initialize(
|
|
@@ -338,6 +328,25 @@ export class Admin extends ClearingHouse {
|
|
|
338
328
|
});
|
|
339
329
|
}
|
|
340
330
|
|
|
331
|
+
public async resetAmmOracleTwap(
|
|
332
|
+
marketIndex: BN
|
|
333
|
+
): Promise<TransactionSignature> {
|
|
334
|
+
const state = this.getStateAccount();
|
|
335
|
+
const markets = this.getMarketsAccount();
|
|
336
|
+
const marketData = markets.markets[marketIndex.toNumber()];
|
|
337
|
+
const ammData = marketData.amm;
|
|
338
|
+
|
|
339
|
+
return await this.program.rpc.resetAmmOracleTwap(marketIndex, {
|
|
340
|
+
accounts: {
|
|
341
|
+
state: await this.getStatePublicKey(),
|
|
342
|
+
admin: this.wallet.publicKey,
|
|
343
|
+
oracle: ammData.oracle,
|
|
344
|
+
markets: state.markets,
|
|
345
|
+
curveHistory: state.extendedCurveHistory,
|
|
346
|
+
},
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
|
|
341
350
|
public async withdrawFromInsuranceVault(
|
|
342
351
|
amount: BN,
|
|
343
352
|
recipient: PublicKey
|
package/src/clearingHouse.ts
CHANGED
|
@@ -44,16 +44,19 @@ import {
|
|
|
44
44
|
ClearingHouseAccountEvents,
|
|
45
45
|
ClearingHouseAccountTypes,
|
|
46
46
|
} from './accounts/types';
|
|
47
|
-
import { DefaultClearingHouseAccountSubscriber } from './accounts/defaultClearingHouseAccountSubscriber';
|
|
48
47
|
import { TxSender } from './tx/types';
|
|
49
48
|
import { DefaultTxSender } from './tx/defaultTxSender';
|
|
50
49
|
import { wrapInTx } from './tx/utils';
|
|
50
|
+
import {
|
|
51
|
+
getClearingHouse,
|
|
52
|
+
getWebSocketClearingHouseConfig,
|
|
53
|
+
} from './factory/clearingHouse';
|
|
51
54
|
|
|
52
55
|
/**
|
|
53
56
|
* # ClearingHouse
|
|
54
57
|
* 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.
|
|
55
58
|
*
|
|
56
|
-
* The default way to construct a ClearingHouse instance is using the {@link from} method. This will create an instance using the static {@link
|
|
59
|
+
* The default way to construct a ClearingHouse instance is using the {@link from} method. This will create an instance using the static {@link WebSocketClearingHouseAccountSubscriber}, which will use a websocket for each state account subscription.
|
|
57
60
|
* Alternatively, if you want to implement your own method of subscribing to the state accounts on the blockchain, you can implement a {@link ClearingHouseAccountSubscriber} and use it in the {@link ClearingHouse.constructor}
|
|
58
61
|
*/
|
|
59
62
|
export class ClearingHouse {
|
|
@@ -64,33 +67,38 @@ export class ClearingHouse {
|
|
|
64
67
|
opts?: ConfirmOptions;
|
|
65
68
|
accountSubscriber: ClearingHouseAccountSubscriber;
|
|
66
69
|
eventEmitter: StrictEventEmitter<EventEmitter, ClearingHouseAccountEvents>;
|
|
67
|
-
|
|
70
|
+
_isSubscribed = false;
|
|
68
71
|
txSender: TxSender;
|
|
69
72
|
|
|
73
|
+
public get isSubscribed() {
|
|
74
|
+
return this._isSubscribed && this.accountSubscriber.isSubscribed;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
public set isSubscribed(val: boolean) {
|
|
78
|
+
this._isSubscribed = val;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* @deprecated You should use the getClearingHouse factory method instead
|
|
83
|
+
* @param connection
|
|
84
|
+
* @param wallet
|
|
85
|
+
* @param clearingHouseProgramId
|
|
86
|
+
* @param opts
|
|
87
|
+
* @returns
|
|
88
|
+
*/
|
|
70
89
|
public static from(
|
|
71
90
|
connection: Connection,
|
|
72
91
|
wallet: IWallet,
|
|
73
92
|
clearingHouseProgramId: PublicKey,
|
|
74
93
|
opts: ConfirmOptions = Provider.defaultOptions()
|
|
75
94
|
): ClearingHouse {
|
|
76
|
-
const
|
|
77
|
-
const program = new Program(
|
|
78
|
-
clearingHouseIDL as Idl,
|
|
79
|
-
clearingHouseProgramId,
|
|
80
|
-
provider
|
|
81
|
-
);
|
|
82
|
-
const accountSubscriber = new DefaultClearingHouseAccountSubscriber(
|
|
83
|
-
program
|
|
84
|
-
);
|
|
85
|
-
const txSender = new DefaultTxSender(provider);
|
|
86
|
-
return new ClearingHouse(
|
|
95
|
+
const config = getWebSocketClearingHouseConfig(
|
|
87
96
|
connection,
|
|
88
97
|
wallet,
|
|
89
|
-
|
|
90
|
-
accountSubscriber,
|
|
91
|
-
txSender,
|
|
98
|
+
clearingHouseProgramId,
|
|
92
99
|
opts
|
|
93
100
|
);
|
|
101
|
+
return getClearingHouse(config);
|
|
94
102
|
}
|
|
95
103
|
|
|
96
104
|
public constructor(
|