@drift-labs/sdk 0.2.0-master.3 → 0.2.0-master.31
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/README.md +13 -13
- package/lib/accounts/bulkUserStatsSubscription.d.ts +7 -0
- package/lib/accounts/bulkUserStatsSubscription.js +21 -0
- package/lib/accounts/bulkUserSubscription.js +0 -1
- package/lib/accounts/fetch.d.ts +2 -1
- package/lib/accounts/fetch.js +9 -1
- package/lib/accounts/pollingClearingHouseAccountSubscriber.d.ts +16 -16
- package/lib/accounts/pollingClearingHouseAccountSubscriber.js +31 -28
- package/lib/accounts/pollingUserStatsAccountSubscriber.d.ts +27 -0
- package/lib/accounts/pollingUserStatsAccountSubscriber.js +113 -0
- package/lib/accounts/types.d.ts +22 -11
- package/lib/accounts/webSocketClearingHouseAccountSubscriber.d.ts +17 -17
- package/lib/accounts/webSocketClearingHouseAccountSubscriber.js +37 -35
- package/lib/accounts/webSocketUserStatsAccountSubsriber.d.ts +20 -0
- package/lib/accounts/webSocketUserStatsAccountSubsriber.js +47 -0
- package/lib/addresses/marketAddresses.d.ts +1 -3
- package/lib/addresses/pda.d.ts +10 -4
- package/lib/addresses/pda.js +51 -14
- package/lib/admin.d.ts +42 -26
- package/lib/admin.js +228 -81
- package/lib/clearingHouse.d.ts +130 -49
- package/lib/clearingHouse.js +1256 -367
- package/lib/clearingHouseConfig.d.ts +4 -4
- package/lib/clearingHouseUser.d.ts +51 -39
- package/lib/clearingHouseUser.js +408 -191
- package/lib/clearingHouseUserStats.d.ts +18 -0
- package/lib/clearingHouseUserStats.js +49 -0
- package/lib/clearingHouseUserStatsConfig.d.ts +14 -0
- package/lib/clearingHouseUserStatsConfig.js +2 -0
- package/lib/config.d.ts +7 -9
- package/lib/config.js +21 -21
- package/lib/constants/numericConstants.d.ts +25 -12
- package/lib/constants/numericConstants.js +35 -21
- package/lib/constants/perpMarkets.d.ts +18 -0
- package/lib/constants/{markets.js → perpMarkets.js} +7 -7
- package/lib/constants/spotMarkets.d.ts +19 -0
- package/lib/constants/spotMarkets.js +53 -0
- package/lib/dlob/DLOB.d.ts +74 -0
- package/lib/dlob/DLOB.js +595 -0
- package/lib/dlob/DLOBNode.d.ts +54 -0
- package/lib/dlob/DLOBNode.js +85 -0
- package/lib/dlob/NodeList.d.ts +26 -0
- package/lib/dlob/NodeList.js +139 -0
- package/lib/events/eventList.js +3 -0
- package/lib/events/eventSubscriber.d.ts +4 -2
- package/lib/events/eventSubscriber.js +16 -9
- package/lib/events/fetchLogs.d.ts +10 -1
- package/lib/events/fetchLogs.js +27 -7
- package/lib/events/pollingLogProvider.d.ts +2 -1
- package/lib/events/pollingLogProvider.js +6 -2
- package/lib/events/sort.js +8 -11
- package/lib/events/types.d.ts +8 -2
- package/lib/events/types.js +6 -0
- package/lib/examples/makeTradeExample.js +20 -8
- package/lib/factory/bigNum.d.ts +2 -0
- package/lib/factory/bigNum.js +48 -10
- package/lib/idl/clearing_house.json +4889 -1529
- package/lib/idl/{mock_usdc_faucet.json → token_faucet.json} +46 -23
- package/lib/index.d.ts +21 -6
- package/lib/index.js +25 -6
- package/lib/math/amm.d.ts +9 -6
- package/lib/math/amm.js +91 -66
- package/lib/math/auction.js +4 -1
- package/lib/math/conversion.js +1 -1
- package/lib/math/funding.d.ts +6 -6
- package/lib/math/funding.js +11 -10
- package/lib/math/insurance.d.ts +4 -0
- package/lib/math/insurance.js +27 -0
- package/lib/math/margin.d.ts +11 -0
- package/lib/math/margin.js +77 -0
- package/lib/math/market.d.ts +14 -9
- package/lib/math/market.js +72 -10
- package/lib/math/oracles.d.ts +4 -0
- package/lib/math/oracles.js +36 -8
- package/lib/math/orders.d.ts +6 -2
- package/lib/math/orders.js +78 -3
- package/lib/math/position.d.ts +21 -13
- package/lib/math/position.js +76 -36
- package/lib/math/repeg.js +14 -5
- package/lib/math/spotBalance.d.ts +22 -0
- package/lib/math/spotBalance.js +192 -0
- package/lib/math/spotMarket.d.ts +4 -0
- package/lib/math/spotMarket.js +8 -0
- package/lib/math/spotPosition.d.ts +6 -0
- package/lib/math/spotPosition.js +23 -0
- package/lib/math/trade.d.ts +10 -10
- package/lib/math/trade.js +32 -39
- package/lib/oracles/pythClient.js +1 -1
- package/lib/oracles/quoteAssetOracleClient.js +1 -1
- package/lib/oracles/switchboardClient.js +1 -1
- package/lib/orderParams.d.ts +14 -5
- package/lib/orderParams.js +12 -92
- package/lib/serum/serumSubscriber.d.ts +23 -0
- package/lib/serum/serumSubscriber.js +41 -0
- package/lib/serum/types.d.ts +11 -0
- package/lib/serum/types.js +2 -0
- package/lib/slot/SlotSubscriber.d.ts +7 -0
- package/lib/slot/SlotSubscriber.js +3 -0
- package/lib/{mockUSDCFaucet.d.ts → tokenFaucet.d.ts} +8 -5
- package/lib/{mockUSDCFaucet.js → tokenFaucet.js} +63 -51
- package/lib/tx/retryTxSender.d.ts +1 -1
- package/lib/tx/retryTxSender.js +13 -4
- package/lib/tx/types.d.ts +1 -1
- package/lib/tx/utils.js +1 -1
- package/lib/types.d.ts +566 -138
- package/lib/types.js +129 -5
- package/lib/userMap/userMap.d.ts +25 -0
- package/lib/userMap/userMap.js +73 -0
- package/lib/userMap/userStatsMap.d.ts +19 -0
- package/lib/userMap/userStatsMap.js +68 -0
- package/lib/util/computeUnits.js +1 -1
- package/lib/util/getTokenAddress.d.ts +2 -0
- package/lib/util/getTokenAddress.js +9 -0
- package/package.json +12 -6
- package/src/accounts/bulkUserStatsSubscription.ts +33 -0
- package/src/accounts/bulkUserSubscription.ts +0 -1
- package/src/accounts/fetch.ts +27 -2
- package/src/accounts/pollingClearingHouseAccountSubscriber.ts +46 -42
- package/src/accounts/pollingUserStatsAccountSubscriber.ts +172 -0
- package/src/accounts/types.ts +31 -11
- package/src/accounts/webSocketClearingHouseAccountSubscriber.ts +64 -59
- package/src/accounts/webSocketUserStatsAccountSubsriber.ts +80 -0
- package/src/addresses/marketAddresses.ts +1 -2
- package/src/addresses/pda.ts +88 -14
- package/src/admin.ts +452 -147
- package/src/assert/assert.js +9 -0
- package/src/clearingHouse.ts +2066 -467
- package/src/clearingHouseConfig.ts +4 -3
- package/src/clearingHouseUser.ts +747 -294
- package/src/clearingHouseUserStats.ts +75 -0
- package/src/clearingHouseUserStatsConfig.ts +18 -0
- package/src/config.ts +30 -31
- package/src/constants/numericConstants.ts +48 -25
- package/src/constants/{markets.ts → perpMarkets.ts} +10 -10
- package/src/constants/spotMarkets.ts +73 -0
- package/src/dlob/DLOB.ts +953 -0
- package/src/dlob/DLOBNode.ts +167 -0
- package/src/dlob/NodeList.ts +189 -0
- package/src/events/eventList.js +77 -0
- package/src/events/eventList.ts +3 -0
- package/src/events/eventSubscriber.ts +20 -12
- package/src/events/fetchLogs.ts +35 -8
- package/src/events/pollingLogProvider.ts +10 -2
- package/src/events/sort.ts +11 -15
- package/src/events/types.ts +19 -1
- package/src/examples/makeTradeExample.js +157 -0
- package/src/examples/makeTradeExample.ts +32 -14
- package/src/factory/bigNum.ts +65 -13
- package/src/idl/clearing_house.json +4889 -1529
- package/src/idl/{mock_usdc_faucet.json → token_faucet.json} +46 -23
- package/src/index.ts +21 -6
- package/src/math/amm.ts +171 -88
- package/src/math/auction.ts +5 -1
- package/src/math/conversion.ts +2 -2
- package/src/math/funding.ts +20 -18
- package/src/math/insurance.ts +35 -0
- package/src/math/margin.ts +127 -0
- package/src/math/market.ts +145 -14
- package/src/math/oracles.ts +63 -9
- package/src/math/orders.ts +138 -4
- package/src/math/position.ts +119 -58
- package/src/math/repeg.ts +16 -6
- package/src/math/spotBalance.ts +319 -0
- package/src/math/spotMarket.ts +9 -0
- package/src/math/spotPosition.ts +47 -0
- package/src/math/trade.ts +53 -59
- package/src/oracles/pythClient.ts +2 -2
- package/src/oracles/quoteAssetOracleClient.ts +2 -2
- package/src/oracles/switchboardClient.ts +2 -2
- package/src/orderParams.ts +24 -137
- package/src/serum/serumSubscriber.ts +80 -0
- package/src/serum/types.ts +13 -0
- package/src/slot/SlotSubscriber.ts +11 -1
- package/src/token/index.js +38 -0
- package/src/{mockUSDCFaucet.ts → tokenFaucet.ts} +82 -70
- package/src/tx/retryTxSender.ts +16 -5
- package/src/tx/types.js +2 -0
- package/src/tx/types.ts +2 -1
- package/src/tx/utils.js +17 -0
- package/src/tx/utils.ts +1 -1
- package/src/types.ts +533 -140
- package/src/userMap/userMap.ts +100 -0
- package/src/userMap/userStatsMap.ts +110 -0
- package/src/util/computeUnits.js +21 -11
- package/src/util/computeUnits.ts +1 -1
- package/src/util/getTokenAddress.js +9 -0
- package/src/util/getTokenAddress.ts +18 -0
- package/src/util/promiseTimeout.js +14 -0
- package/src/util/tps.js +27 -0
- package/tests/bn/test.ts +24 -10
- package/tests/dlob/helpers.ts +397 -0
- package/tests/dlob/test.ts +3688 -0
- package/lib/constants/banks.d.ts +0 -16
- package/lib/constants/banks.js +0 -34
- package/lib/constants/markets.d.ts +0 -19
- package/lib/math/bankBalance.d.ts +0 -9
- package/lib/math/bankBalance.js +0 -75
- package/lib/math/state.d.ts +0 -8
- package/lib/math/state.js +0 -15
- package/lib/orders.d.ts +0 -8
- package/lib/orders.js +0 -134
- package/src/constants/banks.ts +0 -43
- package/src/math/bankBalance.ts +0 -112
- package/src/math/state.ts +0 -14
- package/src/math/utils.js +0 -27
- package/src/math/utils.js.map +0 -1
- package/src/orders.ts +0 -244
- package/src/util/computeUnits.js.map +0 -1
|
@@ -6,18 +6,18 @@ import {
|
|
|
6
6
|
NotSubscribedError,
|
|
7
7
|
OraclesToPoll,
|
|
8
8
|
} from './types';
|
|
9
|
-
import {
|
|
9
|
+
import { Program } from '@project-serum/anchor';
|
|
10
10
|
import StrictEventEmitter from 'strict-event-emitter-types';
|
|
11
11
|
import { EventEmitter } from 'events';
|
|
12
12
|
import {
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
SpotMarketAccount,
|
|
14
|
+
PerpMarketAccount,
|
|
15
15
|
StateAccount,
|
|
16
16
|
UserAccount,
|
|
17
17
|
} from '../types';
|
|
18
18
|
import {
|
|
19
19
|
getClearingHouseStateAccountPublicKey,
|
|
20
|
-
|
|
20
|
+
getSpotMarketPublicKey,
|
|
21
21
|
getMarketPublicKey,
|
|
22
22
|
} from '../addresses/pda';
|
|
23
23
|
import { BulkAccountLoader } from './bulkAccountLoader';
|
|
@@ -32,8 +32,8 @@ export class PollingClearingHouseAccountSubscriber
|
|
|
32
32
|
{
|
|
33
33
|
isSubscribed: boolean;
|
|
34
34
|
program: Program;
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
perpMarketIndexes: number[];
|
|
36
|
+
spotMarketIndexes: number[];
|
|
37
37
|
oracleInfos: OracleInfo[];
|
|
38
38
|
oracleClientCache = new OracleClientCache();
|
|
39
39
|
|
|
@@ -45,8 +45,8 @@ export class PollingClearingHouseAccountSubscriber
|
|
|
45
45
|
errorCallbackId?: string;
|
|
46
46
|
|
|
47
47
|
state?: DataAndSlot<StateAccount>;
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
perpMarket = new Map<number, DataAndSlot<PerpMarketAccount>>();
|
|
49
|
+
spotMarket = new Map<number, DataAndSlot<SpotMarketAccount>>();
|
|
50
50
|
oracles = new Map<string, DataAndSlot<OraclePriceData>>();
|
|
51
51
|
user?: DataAndSlot<UserAccount>;
|
|
52
52
|
|
|
@@ -57,16 +57,16 @@ export class PollingClearingHouseAccountSubscriber
|
|
|
57
57
|
public constructor(
|
|
58
58
|
program: Program,
|
|
59
59
|
accountLoader: BulkAccountLoader,
|
|
60
|
-
|
|
61
|
-
|
|
60
|
+
perpMarketIndexes: number[],
|
|
61
|
+
spotMarketIndexes: number[],
|
|
62
62
|
oracleInfos: OracleInfo[]
|
|
63
63
|
) {
|
|
64
64
|
this.isSubscribed = false;
|
|
65
65
|
this.program = program;
|
|
66
66
|
this.eventEmitter = new EventEmitter();
|
|
67
67
|
this.accountLoader = accountLoader;
|
|
68
|
-
this.
|
|
69
|
-
this.
|
|
68
|
+
this.perpMarketIndexes = perpMarketIndexes;
|
|
69
|
+
this.spotMarketIndexes = spotMarketIndexes;
|
|
70
70
|
this.oracleInfos = oracleInfos;
|
|
71
71
|
}
|
|
72
72
|
|
|
@@ -122,51 +122,51 @@ export class PollingClearingHouseAccountSubscriber
|
|
|
122
122
|
});
|
|
123
123
|
|
|
124
124
|
await this.updateMarketAccountsToPoll();
|
|
125
|
-
await this.
|
|
125
|
+
await this.updateSpotMarketAccountsToPoll();
|
|
126
126
|
}
|
|
127
127
|
|
|
128
128
|
async updateMarketAccountsToPoll(): Promise<boolean> {
|
|
129
|
-
for (const marketIndex of this.
|
|
129
|
+
for (const marketIndex of this.perpMarketIndexes) {
|
|
130
130
|
await this.addMarketAccountToPoll(marketIndex);
|
|
131
131
|
}
|
|
132
132
|
return true;
|
|
133
133
|
}
|
|
134
134
|
|
|
135
|
-
async addMarketAccountToPoll(marketIndex:
|
|
135
|
+
async addMarketAccountToPoll(marketIndex: number): Promise<boolean> {
|
|
136
136
|
const marketPublicKey = await getMarketPublicKey(
|
|
137
137
|
this.program.programId,
|
|
138
138
|
marketIndex
|
|
139
139
|
);
|
|
140
140
|
|
|
141
141
|
this.accountsToPoll.set(marketPublicKey.toString(), {
|
|
142
|
-
key: '
|
|
142
|
+
key: 'perpMarket',
|
|
143
143
|
publicKey: marketPublicKey,
|
|
144
|
-
eventType: '
|
|
145
|
-
mapKey: marketIndex
|
|
144
|
+
eventType: 'perpMarketAccountUpdate',
|
|
145
|
+
mapKey: marketIndex,
|
|
146
146
|
});
|
|
147
147
|
|
|
148
148
|
return true;
|
|
149
149
|
}
|
|
150
150
|
|
|
151
|
-
async
|
|
152
|
-
for (const
|
|
153
|
-
await this.
|
|
151
|
+
async updateSpotMarketAccountsToPoll(): Promise<boolean> {
|
|
152
|
+
for (const marketIndex of this.spotMarketIndexes) {
|
|
153
|
+
await this.addSpotMarketAccountToPoll(marketIndex);
|
|
154
154
|
}
|
|
155
155
|
|
|
156
156
|
return true;
|
|
157
157
|
}
|
|
158
158
|
|
|
159
|
-
async
|
|
160
|
-
const
|
|
159
|
+
async addSpotMarketAccountToPoll(marketIndex: number): Promise<boolean> {
|
|
160
|
+
const marketPublicKey = await getSpotMarketPublicKey(
|
|
161
161
|
this.program.programId,
|
|
162
|
-
|
|
162
|
+
marketIndex
|
|
163
163
|
);
|
|
164
164
|
|
|
165
|
-
this.accountsToPoll.set(
|
|
166
|
-
key: '
|
|
167
|
-
publicKey:
|
|
168
|
-
eventType: '
|
|
169
|
-
mapKey:
|
|
165
|
+
this.accountsToPoll.set(marketPublicKey.toString(), {
|
|
166
|
+
key: 'spotMarket',
|
|
167
|
+
publicKey: marketPublicKey,
|
|
168
|
+
eventType: 'spotMarketAccountUpdate',
|
|
169
|
+
mapKey: marketIndex,
|
|
170
170
|
});
|
|
171
171
|
return true;
|
|
172
172
|
}
|
|
@@ -353,14 +353,14 @@ export class PollingClearingHouseAccountSubscriber
|
|
|
353
353
|
this.isSubscribed = false;
|
|
354
354
|
}
|
|
355
355
|
|
|
356
|
-
async
|
|
357
|
-
await this.
|
|
358
|
-
const accountToPoll = this.accountsToPoll.get(
|
|
356
|
+
async addSpotMarket(marketIndex: number): Promise<boolean> {
|
|
357
|
+
await this.addSpotMarketAccountToPoll(marketIndex);
|
|
358
|
+
const accountToPoll = this.accountsToPoll.get(marketIndex.toString());
|
|
359
359
|
this.addAccountToAccountLoader(accountToPoll);
|
|
360
360
|
return true;
|
|
361
361
|
}
|
|
362
362
|
|
|
363
|
-
async
|
|
363
|
+
async addPerpMarket(marketIndex: number): Promise<boolean> {
|
|
364
364
|
await this.addMarketAccountToPoll(marketIndex);
|
|
365
365
|
const accountToPoll = this.accountsToPoll.get(marketIndex.toString());
|
|
366
366
|
this.addAccountToAccountLoader(accountToPoll);
|
|
@@ -394,19 +394,23 @@ export class PollingClearingHouseAccountSubscriber
|
|
|
394
394
|
}
|
|
395
395
|
|
|
396
396
|
public getMarketAccountAndSlot(
|
|
397
|
-
marketIndex:
|
|
398
|
-
): DataAndSlot<
|
|
399
|
-
return this.
|
|
397
|
+
marketIndex: number
|
|
398
|
+
): DataAndSlot<PerpMarketAccount> | undefined {
|
|
399
|
+
return this.perpMarket.get(marketIndex);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
public getMarketAccountsAndSlots(): DataAndSlot<PerpMarketAccount>[] {
|
|
403
|
+
return Array.from(this.perpMarket.values());
|
|
400
404
|
}
|
|
401
405
|
|
|
402
|
-
public
|
|
403
|
-
|
|
406
|
+
public getSpotMarketAccountAndSlot(
|
|
407
|
+
marketIndex: number
|
|
408
|
+
): DataAndSlot<SpotMarketAccount> | undefined {
|
|
409
|
+
return this.spotMarket.get(marketIndex);
|
|
404
410
|
}
|
|
405
411
|
|
|
406
|
-
public
|
|
407
|
-
|
|
408
|
-
): DataAndSlot<BankAccount> | undefined {
|
|
409
|
-
return this.bank.get(bankIndex.toNumber());
|
|
412
|
+
public getSpotMarketAccountsAndSlots(): DataAndSlot<SpotMarketAccount>[] {
|
|
413
|
+
return Array.from(this.spotMarket.values());
|
|
410
414
|
}
|
|
411
415
|
|
|
412
416
|
public getOraclePriceDataAndSlot(
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DataAndSlot,
|
|
3
|
+
AccountToPoll,
|
|
4
|
+
NotSubscribedError,
|
|
5
|
+
UserStatsAccountSubscriber,
|
|
6
|
+
UserStatsAccountEvents,
|
|
7
|
+
} from './types';
|
|
8
|
+
import { Program } from '@project-serum/anchor';
|
|
9
|
+
import StrictEventEmitter from 'strict-event-emitter-types';
|
|
10
|
+
import { EventEmitter } from 'events';
|
|
11
|
+
import { PublicKey } from '@solana/web3.js';
|
|
12
|
+
import { UserStatsAccount } from '../types';
|
|
13
|
+
import { BulkAccountLoader } from './bulkAccountLoader';
|
|
14
|
+
import { capitalize } from './utils';
|
|
15
|
+
|
|
16
|
+
export class PollingUserStatsAccountSubscriber
|
|
17
|
+
implements UserStatsAccountSubscriber
|
|
18
|
+
{
|
|
19
|
+
isSubscribed: boolean;
|
|
20
|
+
program: Program;
|
|
21
|
+
eventEmitter: StrictEventEmitter<EventEmitter, UserStatsAccountEvents>;
|
|
22
|
+
userStatsAccountPublicKey: PublicKey;
|
|
23
|
+
|
|
24
|
+
accountLoader: BulkAccountLoader;
|
|
25
|
+
accountsToPoll = new Map<string, AccountToPoll>();
|
|
26
|
+
errorCallbackId?: string;
|
|
27
|
+
|
|
28
|
+
userStats?: DataAndSlot<UserStatsAccount>;
|
|
29
|
+
|
|
30
|
+
public constructor(
|
|
31
|
+
program: Program,
|
|
32
|
+
userStatsAccountPublicKey: PublicKey,
|
|
33
|
+
accountLoader: BulkAccountLoader
|
|
34
|
+
) {
|
|
35
|
+
this.isSubscribed = false;
|
|
36
|
+
this.program = program;
|
|
37
|
+
this.accountLoader = accountLoader;
|
|
38
|
+
this.eventEmitter = new EventEmitter();
|
|
39
|
+
this.userStatsAccountPublicKey = userStatsAccountPublicKey;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async subscribe(): Promise<boolean> {
|
|
43
|
+
if (this.isSubscribed) {
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
await this.addToAccountLoader();
|
|
48
|
+
|
|
49
|
+
let subscriptionSucceeded = false;
|
|
50
|
+
let retries = 0;
|
|
51
|
+
while (!subscriptionSucceeded && retries < 5) {
|
|
52
|
+
await this.fetchIfUnloaded();
|
|
53
|
+
subscriptionSucceeded = this.didSubscriptionSucceed();
|
|
54
|
+
retries++;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (subscriptionSucceeded) {
|
|
58
|
+
this.eventEmitter.emit('update');
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
this.isSubscribed = subscriptionSucceeded;
|
|
62
|
+
return subscriptionSucceeded;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async addToAccountLoader(): Promise<void> {
|
|
66
|
+
if (this.accountsToPoll.size > 0) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
this.accountsToPoll.set(this.userStatsAccountPublicKey.toString(), {
|
|
71
|
+
key: 'userStats',
|
|
72
|
+
publicKey: this.userStatsAccountPublicKey,
|
|
73
|
+
eventType: 'userStatsAccountUpdate',
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
for (const [_, accountToPoll] of this.accountsToPoll) {
|
|
77
|
+
accountToPoll.callbackId = this.accountLoader.addAccount(
|
|
78
|
+
accountToPoll.publicKey,
|
|
79
|
+
(buffer, slot) => {
|
|
80
|
+
if (!buffer) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const account = this.program.account[
|
|
85
|
+
accountToPoll.key
|
|
86
|
+
].coder.accounts.decode(capitalize(accountToPoll.key), buffer);
|
|
87
|
+
this[accountToPoll.key] = { data: account, slot };
|
|
88
|
+
// @ts-ignore
|
|
89
|
+
this.eventEmitter.emit(accountToPoll.eventType, account);
|
|
90
|
+
this.eventEmitter.emit('update');
|
|
91
|
+
}
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
this.errorCallbackId = this.accountLoader.addErrorCallbacks((error) => {
|
|
96
|
+
this.eventEmitter.emit('error', error);
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
async fetchIfUnloaded(): Promise<void> {
|
|
101
|
+
let shouldFetch = false;
|
|
102
|
+
for (const [_, accountToPoll] of this.accountsToPoll) {
|
|
103
|
+
if (this[accountToPoll.key] === undefined) {
|
|
104
|
+
shouldFetch = true;
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (shouldFetch) {
|
|
110
|
+
await this.fetch();
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
async fetch(): Promise<void> {
|
|
115
|
+
await this.accountLoader.load();
|
|
116
|
+
for (const [_, accountToPoll] of this.accountsToPoll) {
|
|
117
|
+
const { buffer, slot } = this.accountLoader.getBufferAndSlot(
|
|
118
|
+
accountToPoll.publicKey
|
|
119
|
+
);
|
|
120
|
+
if (buffer) {
|
|
121
|
+
const account = this.program.account[
|
|
122
|
+
accountToPoll.key
|
|
123
|
+
].coder.accounts.decode(capitalize(accountToPoll.key), buffer);
|
|
124
|
+
this[accountToPoll.key] = { data: account, slot };
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
didSubscriptionSucceed(): boolean {
|
|
130
|
+
let success = true;
|
|
131
|
+
for (const [_, accountToPoll] of this.accountsToPoll) {
|
|
132
|
+
if (!this[accountToPoll.key]) {
|
|
133
|
+
success = false;
|
|
134
|
+
break;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return success;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
async unsubscribe(): Promise<void> {
|
|
141
|
+
if (!this.isSubscribed) {
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
for (const [_, accountToPoll] of this.accountsToPoll) {
|
|
146
|
+
this.accountLoader.removeAccount(
|
|
147
|
+
accountToPoll.publicKey,
|
|
148
|
+
accountToPoll.callbackId
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
this.accountLoader.removeErrorCallbacks(this.errorCallbackId);
|
|
153
|
+
this.errorCallbackId = undefined;
|
|
154
|
+
|
|
155
|
+
this.accountsToPoll.clear();
|
|
156
|
+
|
|
157
|
+
this.isSubscribed = false;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
assertIsSubscribed(): void {
|
|
161
|
+
if (!this.isSubscribed) {
|
|
162
|
+
throw new NotSubscribedError(
|
|
163
|
+
'You must call `subscribe` before using this function'
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
public getUserStatsAccountAndSlot(): DataAndSlot<UserStatsAccount> {
|
|
169
|
+
this.assertIsSubscribed();
|
|
170
|
+
return this.userStats;
|
|
171
|
+
}
|
|
172
|
+
}
|
package/src/accounts/types.ts
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
SpotMarketAccount,
|
|
3
|
+
PerpMarketAccount,
|
|
4
4
|
OracleSource,
|
|
5
5
|
StateAccount,
|
|
6
6
|
UserAccount,
|
|
7
|
+
UserStatsAccount,
|
|
7
8
|
} from '../types';
|
|
8
9
|
import StrictEventEmitter from 'strict-event-emitter-types';
|
|
9
10
|
import { EventEmitter } from 'events';
|
|
10
11
|
import { PublicKey } from '@solana/web3.js';
|
|
11
12
|
import { AccountInfo } from '@solana/spl-token';
|
|
12
13
|
import { OracleInfo, OraclePriceData } from '..';
|
|
13
|
-
import { BN } from '@project-serum/anchor';
|
|
14
14
|
|
|
15
15
|
export interface AccountSubscriber<T> {
|
|
16
16
|
dataAndSlot?: DataAndSlot<T>;
|
|
@@ -25,8 +25,8 @@ export class NotSubscribedError extends Error {
|
|
|
25
25
|
|
|
26
26
|
export interface ClearingHouseAccountEvents {
|
|
27
27
|
stateAccountUpdate: (payload: StateAccount) => void;
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
perpMarketAccountUpdate: (payload: PerpMarketAccount) => void;
|
|
29
|
+
spotMarketAccountUpdate: (payload: SpotMarketAccount) => void;
|
|
30
30
|
oraclePriceUpdate: (publicKey: PublicKey, data: OraclePriceData) => void;
|
|
31
31
|
userAccountUpdate: (payload: UserAccount) => void;
|
|
32
32
|
update: void;
|
|
@@ -41,16 +41,19 @@ export interface ClearingHouseAccountSubscriber {
|
|
|
41
41
|
fetch(): Promise<void>;
|
|
42
42
|
unsubscribe(): Promise<void>;
|
|
43
43
|
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
addPerpMarket(marketIndex: number): Promise<boolean>;
|
|
45
|
+
addSpotMarket(marketIndex: number): Promise<boolean>;
|
|
46
46
|
addOracle(oracleInfo: OracleInfo): Promise<boolean>;
|
|
47
47
|
|
|
48
48
|
getStateAccountAndSlot(): DataAndSlot<StateAccount>;
|
|
49
49
|
getMarketAccountAndSlot(
|
|
50
|
-
marketIndex:
|
|
51
|
-
): DataAndSlot<
|
|
52
|
-
getMarketAccountsAndSlots(): DataAndSlot<
|
|
53
|
-
|
|
50
|
+
marketIndex: number
|
|
51
|
+
): DataAndSlot<PerpMarketAccount> | undefined;
|
|
52
|
+
getMarketAccountsAndSlots(): DataAndSlot<PerpMarketAccount>[];
|
|
53
|
+
getSpotMarketAccountAndSlot(
|
|
54
|
+
marketIndex: number
|
|
55
|
+
): DataAndSlot<SpotMarketAccount> | undefined;
|
|
56
|
+
getSpotMarketAccountsAndSlots(): DataAndSlot<SpotMarketAccount>[];
|
|
54
57
|
getOraclePriceDataAndSlot(
|
|
55
58
|
oraclePublicKey: PublicKey
|
|
56
59
|
): DataAndSlot<OraclePriceData> | undefined;
|
|
@@ -130,3 +133,20 @@ export type DataAndSlot<T> = {
|
|
|
130
133
|
data: T;
|
|
131
134
|
slot: number;
|
|
132
135
|
};
|
|
136
|
+
|
|
137
|
+
export interface UserStatsAccountEvents {
|
|
138
|
+
userStatsAccountUpdate: (payload: UserStatsAccount) => void;
|
|
139
|
+
update: void;
|
|
140
|
+
error: (e: Error) => void;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export interface UserStatsAccountSubscriber {
|
|
144
|
+
eventEmitter: StrictEventEmitter<EventEmitter, UserStatsAccountEvents>;
|
|
145
|
+
isSubscribed: boolean;
|
|
146
|
+
|
|
147
|
+
subscribe(): Promise<boolean>;
|
|
148
|
+
fetch(): Promise<void>;
|
|
149
|
+
unsubscribe(): Promise<void>;
|
|
150
|
+
|
|
151
|
+
getUserStatsAccountAndSlot(): DataAndSlot<UserStatsAccount>;
|
|
152
|
+
}
|
|
@@ -4,13 +4,13 @@ import {
|
|
|
4
4
|
DataAndSlot,
|
|
5
5
|
} from './types';
|
|
6
6
|
import { AccountSubscriber, NotSubscribedError } from './types';
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
7
|
+
import { SpotMarketAccount, PerpMarketAccount, StateAccount } from '../types';
|
|
8
|
+
import { Program } from '@project-serum/anchor';
|
|
9
9
|
import StrictEventEmitter from 'strict-event-emitter-types';
|
|
10
10
|
import { EventEmitter } from 'events';
|
|
11
11
|
import {
|
|
12
12
|
getClearingHouseStateAccountPublicKey,
|
|
13
|
-
|
|
13
|
+
getSpotMarketPublicKey,
|
|
14
14
|
getMarketPublicKey,
|
|
15
15
|
} from '../addresses/pda';
|
|
16
16
|
import { WebSocketAccountSubscriber } from './webSocketAccountSubscriber';
|
|
@@ -25,18 +25,21 @@ export class WebSocketClearingHouseAccountSubscriber
|
|
|
25
25
|
{
|
|
26
26
|
isSubscribed: boolean;
|
|
27
27
|
program: Program;
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
perpMarketIndexes: number[];
|
|
29
|
+
spotMarketIndexes: number[];
|
|
30
30
|
oracleInfos: OracleInfo[];
|
|
31
31
|
oracleClientCache = new OracleClientCache();
|
|
32
32
|
|
|
33
33
|
eventEmitter: StrictEventEmitter<EventEmitter, ClearingHouseAccountEvents>;
|
|
34
34
|
stateAccountSubscriber?: AccountSubscriber<StateAccount>;
|
|
35
|
-
|
|
35
|
+
perpMarketAccountSubscribers = new Map<
|
|
36
36
|
number,
|
|
37
|
-
AccountSubscriber<
|
|
37
|
+
AccountSubscriber<PerpMarketAccount>
|
|
38
|
+
>();
|
|
39
|
+
spotMarketAccountSubscribers = new Map<
|
|
40
|
+
number,
|
|
41
|
+
AccountSubscriber<SpotMarketAccount>
|
|
38
42
|
>();
|
|
39
|
-
bankAccountSubscribers = new Map<number, AccountSubscriber<BankAccount>>();
|
|
40
43
|
oracleSubscribers = new Map<string, AccountSubscriber<OraclePriceData>>();
|
|
41
44
|
|
|
42
45
|
private isSubscribing = false;
|
|
@@ -45,15 +48,15 @@ export class WebSocketClearingHouseAccountSubscriber
|
|
|
45
48
|
|
|
46
49
|
public constructor(
|
|
47
50
|
program: Program,
|
|
48
|
-
|
|
49
|
-
|
|
51
|
+
perpMarketIndexes: number[],
|
|
52
|
+
spotMarketIndexes: number[],
|
|
50
53
|
oracleInfos: OracleInfo[]
|
|
51
54
|
) {
|
|
52
55
|
this.isSubscribed = false;
|
|
53
56
|
this.program = program;
|
|
54
57
|
this.eventEmitter = new EventEmitter();
|
|
55
|
-
this.
|
|
56
|
-
this.
|
|
58
|
+
this.perpMarketIndexes = perpMarketIndexes;
|
|
59
|
+
this.spotMarketIndexes = spotMarketIndexes;
|
|
57
60
|
this.oracleInfos = oracleInfos;
|
|
58
61
|
}
|
|
59
62
|
|
|
@@ -90,8 +93,8 @@ export class WebSocketClearingHouseAccountSubscriber
|
|
|
90
93
|
// subscribe to market accounts
|
|
91
94
|
await this.subscribeToMarketAccounts();
|
|
92
95
|
|
|
93
|
-
// subscribe to
|
|
94
|
-
await this.
|
|
96
|
+
// subscribe to spot market accounts
|
|
97
|
+
await this.subscribeToSpotMarketAccounts();
|
|
95
98
|
|
|
96
99
|
// subscribe to oracles
|
|
97
100
|
await this.subscribeToOracles();
|
|
@@ -106,55 +109,52 @@ export class WebSocketClearingHouseAccountSubscriber
|
|
|
106
109
|
}
|
|
107
110
|
|
|
108
111
|
async subscribeToMarketAccounts(): Promise<boolean> {
|
|
109
|
-
for (const marketIndex of this.
|
|
112
|
+
for (const marketIndex of this.perpMarketIndexes) {
|
|
110
113
|
await this.subscribeToMarketAccount(marketIndex);
|
|
111
114
|
}
|
|
112
115
|
return true;
|
|
113
116
|
}
|
|
114
117
|
|
|
115
|
-
async subscribeToMarketAccount(marketIndex:
|
|
118
|
+
async subscribeToMarketAccount(marketIndex: number): Promise<boolean> {
|
|
116
119
|
const marketPublicKey = await getMarketPublicKey(
|
|
117
120
|
this.program.programId,
|
|
118
121
|
marketIndex
|
|
119
122
|
);
|
|
120
|
-
const accountSubscriber = new WebSocketAccountSubscriber<
|
|
121
|
-
'
|
|
123
|
+
const accountSubscriber = new WebSocketAccountSubscriber<PerpMarketAccount>(
|
|
124
|
+
'perpMarket',
|
|
122
125
|
this.program,
|
|
123
126
|
marketPublicKey
|
|
124
127
|
);
|
|
125
|
-
await accountSubscriber.subscribe((data:
|
|
126
|
-
this.eventEmitter.emit('
|
|
128
|
+
await accountSubscriber.subscribe((data: PerpMarketAccount) => {
|
|
129
|
+
this.eventEmitter.emit('perpMarketAccountUpdate', data);
|
|
127
130
|
this.eventEmitter.emit('update');
|
|
128
131
|
});
|
|
129
|
-
this.
|
|
130
|
-
marketIndex.toNumber(),
|
|
131
|
-
accountSubscriber
|
|
132
|
-
);
|
|
132
|
+
this.perpMarketAccountSubscribers.set(marketIndex, accountSubscriber);
|
|
133
133
|
return true;
|
|
134
134
|
}
|
|
135
135
|
|
|
136
|
-
async
|
|
137
|
-
for (const
|
|
138
|
-
await this.
|
|
136
|
+
async subscribeToSpotMarketAccounts(): Promise<boolean> {
|
|
137
|
+
for (const marketIndex of this.spotMarketIndexes) {
|
|
138
|
+
await this.subscribeToSpotMarketAccount(marketIndex);
|
|
139
139
|
}
|
|
140
140
|
return true;
|
|
141
141
|
}
|
|
142
142
|
|
|
143
|
-
async
|
|
144
|
-
const
|
|
143
|
+
async subscribeToSpotMarketAccount(marketIndex: number): Promise<boolean> {
|
|
144
|
+
const marketPublicKey = await getSpotMarketPublicKey(
|
|
145
145
|
this.program.programId,
|
|
146
|
-
|
|
146
|
+
marketIndex
|
|
147
147
|
);
|
|
148
|
-
const accountSubscriber = new WebSocketAccountSubscriber<
|
|
149
|
-
'
|
|
148
|
+
const accountSubscriber = new WebSocketAccountSubscriber<SpotMarketAccount>(
|
|
149
|
+
'spotMarket',
|
|
150
150
|
this.program,
|
|
151
|
-
|
|
151
|
+
marketPublicKey
|
|
152
152
|
);
|
|
153
|
-
await accountSubscriber.subscribe((data:
|
|
154
|
-
this.eventEmitter.emit('
|
|
153
|
+
await accountSubscriber.subscribe((data: SpotMarketAccount) => {
|
|
154
|
+
this.eventEmitter.emit('spotMarketAccountUpdate', data);
|
|
155
155
|
this.eventEmitter.emit('update');
|
|
156
156
|
});
|
|
157
|
-
this.
|
|
157
|
+
this.spotMarketAccountSubscribers.set(marketIndex, accountSubscriber);
|
|
158
158
|
return true;
|
|
159
159
|
}
|
|
160
160
|
|
|
@@ -195,13 +195,13 @@ export class WebSocketClearingHouseAccountSubscriber
|
|
|
195
195
|
}
|
|
196
196
|
|
|
197
197
|
async unsubscribeFromMarketAccounts(): Promise<void> {
|
|
198
|
-
for (const accountSubscriber of this.
|
|
198
|
+
for (const accountSubscriber of this.perpMarketAccountSubscribers.values()) {
|
|
199
199
|
await accountSubscriber.unsubscribe();
|
|
200
200
|
}
|
|
201
201
|
}
|
|
202
202
|
|
|
203
|
-
async
|
|
204
|
-
for (const accountSubscriber of this.
|
|
203
|
+
async unsubscribeFromSpotMarketAccounts(): Promise<void> {
|
|
204
|
+
for (const accountSubscriber of this.spotMarketAccountSubscribers.values()) {
|
|
205
205
|
await accountSubscriber.unsubscribe();
|
|
206
206
|
}
|
|
207
207
|
}
|
|
@@ -219,13 +219,13 @@ export class WebSocketClearingHouseAccountSubscriber
|
|
|
219
219
|
|
|
220
220
|
const promises = [this.stateAccountSubscriber.fetch()]
|
|
221
221
|
.concat(
|
|
222
|
-
Array.from(this.
|
|
223
|
-
subscriber.fetch()
|
|
222
|
+
Array.from(this.perpMarketAccountSubscribers.values()).map(
|
|
223
|
+
(subscriber) => subscriber.fetch()
|
|
224
224
|
)
|
|
225
225
|
)
|
|
226
226
|
.concat(
|
|
227
|
-
Array.from(this.
|
|
228
|
-
subscriber.fetch()
|
|
227
|
+
Array.from(this.spotMarketAccountSubscribers.values()).map(
|
|
228
|
+
(subscriber) => subscriber.fetch()
|
|
229
229
|
)
|
|
230
230
|
);
|
|
231
231
|
|
|
@@ -240,21 +240,21 @@ export class WebSocketClearingHouseAccountSubscriber
|
|
|
240
240
|
await this.stateAccountSubscriber.unsubscribe();
|
|
241
241
|
|
|
242
242
|
await this.unsubscribeFromMarketAccounts();
|
|
243
|
-
await this.
|
|
243
|
+
await this.unsubscribeFromSpotMarketAccounts();
|
|
244
244
|
await this.unsubscribeFromOracles();
|
|
245
245
|
|
|
246
246
|
this.isSubscribed = false;
|
|
247
247
|
}
|
|
248
248
|
|
|
249
|
-
async
|
|
250
|
-
if (this.
|
|
249
|
+
async addSpotMarket(marketIndex: number): Promise<boolean> {
|
|
250
|
+
if (this.spotMarketAccountSubscribers.has(marketIndex)) {
|
|
251
251
|
return true;
|
|
252
252
|
}
|
|
253
|
-
return this.
|
|
253
|
+
return this.subscribeToSpotMarketAccount(marketIndex);
|
|
254
254
|
}
|
|
255
255
|
|
|
256
|
-
async
|
|
257
|
-
if (this.
|
|
256
|
+
async addPerpMarket(marketIndex: number): Promise<boolean> {
|
|
257
|
+
if (this.perpMarketAccountSubscribers.has(marketIndex)) {
|
|
258
258
|
return true;
|
|
259
259
|
}
|
|
260
260
|
return this.subscribeToMarketAccount(marketIndex);
|
|
@@ -286,24 +286,29 @@ export class WebSocketClearingHouseAccountSubscriber
|
|
|
286
286
|
}
|
|
287
287
|
|
|
288
288
|
public getMarketAccountAndSlot(
|
|
289
|
-
marketIndex:
|
|
290
|
-
): DataAndSlot<
|
|
289
|
+
marketIndex: number
|
|
290
|
+
): DataAndSlot<PerpMarketAccount> | undefined {
|
|
291
291
|
this.assertIsSubscribed();
|
|
292
|
-
return this.
|
|
293
|
-
.dataAndSlot;
|
|
292
|
+
return this.perpMarketAccountSubscribers.get(marketIndex).dataAndSlot;
|
|
294
293
|
}
|
|
295
294
|
|
|
296
|
-
public getMarketAccountsAndSlots(): DataAndSlot<
|
|
297
|
-
return Array.from(this.
|
|
295
|
+
public getMarketAccountsAndSlots(): DataAndSlot<PerpMarketAccount>[] {
|
|
296
|
+
return Array.from(this.perpMarketAccountSubscribers.values()).map(
|
|
298
297
|
(subscriber) => subscriber.dataAndSlot
|
|
299
298
|
);
|
|
300
299
|
}
|
|
301
300
|
|
|
302
|
-
public
|
|
303
|
-
|
|
304
|
-
): DataAndSlot<
|
|
301
|
+
public getSpotMarketAccountAndSlot(
|
|
302
|
+
marketIndex: number
|
|
303
|
+
): DataAndSlot<SpotMarketAccount> | undefined {
|
|
305
304
|
this.assertIsSubscribed();
|
|
306
|
-
return this.
|
|
305
|
+
return this.spotMarketAccountSubscribers.get(marketIndex).dataAndSlot;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
public getSpotMarketAccountsAndSlots(): DataAndSlot<SpotMarketAccount>[] {
|
|
309
|
+
return Array.from(this.spotMarketAccountSubscribers.values()).map(
|
|
310
|
+
(subscriber) => subscriber.dataAndSlot
|
|
311
|
+
);
|
|
307
312
|
}
|
|
308
313
|
|
|
309
314
|
public getOraclePriceDataAndSlot(
|