@drift-labs/sdk 2.31.1-beta.1 → 2.31.1-beta.10
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/VERSION +1 -1
- package/lib/accounts/mockUserAccountSubscriber.d.ts +23 -0
- package/lib/accounts/mockUserAccountSubscriber.js +31 -0
- package/lib/constants/perpMarkets.js +20 -0
- package/lib/driftClient.d.ts +6 -1
- package/lib/driftClient.js +58 -21
- package/lib/driftClientConfig.d.ts +4 -9
- package/lib/idl/drift.json +1 -1
- package/lib/math/tiers.d.ts +4 -0
- package/lib/math/tiers.js +52 -0
- package/lib/tx/retryTxSender.d.ts +14 -3
- package/lib/tx/retryTxSender.js +27 -22
- package/lib/tx/types.d.ts +3 -2
- package/lib/user.d.ts +10 -1
- package/lib/user.js +39 -8
- package/lib/userConfig.d.ts +4 -0
- package/lib/userStats.js +4 -1
- package/lib/userStatsConfig.d.ts +2 -0
- package/package.json +1 -1
- package/src/accounts/mockUserAccountSubscriber.ts +53 -0
- package/src/config.ts +2 -2
- package/src/constants/perpMarkets.ts +20 -0
- package/src/driftClient.ts +76 -21
- package/src/driftClientConfig.ts +4 -9
- package/src/idl/drift.json +1 -1
- package/src/math/tiers.ts +44 -0
- package/src/tx/retryTxSender.ts +46 -36
- package/src/tx/types.ts +4 -2
- package/src/user.ts +63 -12
- package/src/userConfig.ts +5 -0
- package/src/userStats.ts +4 -0
- package/src/userStatsConfig.ts +3 -0
package/lib/user.js
CHANGED
|
@@ -12,6 +12,7 @@ const pollingUserAccountSubscriber_1 = require("./accounts/pollingUserAccountSub
|
|
|
12
12
|
const webSocketUserAccountSubscriber_1 = require("./accounts/webSocketUserAccountSubscriber");
|
|
13
13
|
const spotPosition_1 = require("./math/spotPosition");
|
|
14
14
|
const oracles_1 = require("./math/oracles");
|
|
15
|
+
const tiers_1 = require("./math/tiers");
|
|
15
16
|
class User {
|
|
16
17
|
get isSubscribed() {
|
|
17
18
|
return this._isSubscribed && this.accountSubscriber.isSubscribed;
|
|
@@ -20,13 +21,16 @@ class User {
|
|
|
20
21
|
this._isSubscribed = val;
|
|
21
22
|
}
|
|
22
23
|
constructor(config) {
|
|
23
|
-
var _a;
|
|
24
|
+
var _a, _b;
|
|
24
25
|
this._isSubscribed = false;
|
|
25
26
|
this.driftClient = config.driftClient;
|
|
26
27
|
this.userAccountPublicKey = config.userAccountPublicKey;
|
|
27
28
|
if (((_a = config.accountSubscription) === null || _a === void 0 ? void 0 : _a.type) === 'polling') {
|
|
28
29
|
this.accountSubscriber = new pollingUserAccountSubscriber_1.PollingUserAccountSubscriber(config.driftClient.program, config.userAccountPublicKey, config.accountSubscription.accountLoader);
|
|
29
30
|
}
|
|
31
|
+
else if (((_b = config.accountSubscription) === null || _b === void 0 ? void 0 : _b.type) === 'custom') {
|
|
32
|
+
this.accountSubscriber = config.accountSubscription.userAccountSubscriber;
|
|
33
|
+
}
|
|
30
34
|
else {
|
|
31
35
|
this.accountSubscriber = new webSocketUserAccountSubscriber_1.WebSocketUserAccountSubscriber(config.driftClient.program, config.userAccountPublicKey);
|
|
32
36
|
}
|
|
@@ -176,7 +180,9 @@ class User {
|
|
|
176
180
|
* @returns : pnl from settle
|
|
177
181
|
*/
|
|
178
182
|
getPerpPositionWithLPSettle(marketIndex, originalPosition) {
|
|
179
|
-
|
|
183
|
+
var _a;
|
|
184
|
+
originalPosition =
|
|
185
|
+
(_a = originalPosition !== null && originalPosition !== void 0 ? originalPosition : this.getPerpPosition(marketIndex)) !== null && _a !== void 0 ? _a : this.getEmptyPosition(marketIndex);
|
|
180
186
|
if (originalPosition.lpShares.eq(numericConstants_1.ZERO)) {
|
|
181
187
|
return [originalPosition, numericConstants_1.ZERO, numericConstants_1.ZERO];
|
|
182
188
|
}
|
|
@@ -228,7 +234,7 @@ class User {
|
|
|
228
234
|
let pnl;
|
|
229
235
|
if (updateType == 'open' || updateType == 'increase') {
|
|
230
236
|
newQuoteEntry = position.quoteEntryAmount.add(deltaQaa);
|
|
231
|
-
pnl =
|
|
237
|
+
pnl = numericConstants_1.ZERO;
|
|
232
238
|
}
|
|
233
239
|
else if (updateType == 'reduce' || updateType == 'close') {
|
|
234
240
|
newQuoteEntry = position.quoteEntryAmount.sub(position.quoteEntryAmount
|
|
@@ -305,6 +311,9 @@ class User {
|
|
|
305
311
|
!(pos.openOrders == 0) ||
|
|
306
312
|
!pos.lpShares.eq(numericConstants_1.ZERO));
|
|
307
313
|
}
|
|
314
|
+
getActiveSpotPositions() {
|
|
315
|
+
return this.getUserAccount().spotPositions.filter((pos) => !(0, spotPosition_1.isSpotPositionAvailable)(pos));
|
|
316
|
+
}
|
|
308
317
|
/**
|
|
309
318
|
* calculates unrealized position price pnl
|
|
310
319
|
* @returns : Precision QUOTE_PRECISION
|
|
@@ -601,7 +610,8 @@ class User {
|
|
|
601
610
|
* @returns : Precision QUOTE_PRECISION
|
|
602
611
|
*/
|
|
603
612
|
getPerpPositionValue(marketIndex, oraclePriceData, includeOpenOrders = false) {
|
|
604
|
-
const userPosition = this.
|
|
613
|
+
const userPosition = this.getPerpPositionWithLPSettle(marketIndex)[0] ||
|
|
614
|
+
this.getEmptyPosition(marketIndex);
|
|
605
615
|
const market = this.driftClient.getPerpMarketAccount(userPosition.marketIndex);
|
|
606
616
|
return (0, margin_1.calculateBaseAssetValueWithOracle)(market, userPosition, oraclePriceData, includeOpenOrders);
|
|
607
617
|
}
|
|
@@ -775,12 +785,16 @@ class User {
|
|
|
775
785
|
const totalCollateral = this.getTotalCollateral('Maintenance');
|
|
776
786
|
// if user being liq'd, can continue to be liq'd until total collateral above the margin requirement plus buffer
|
|
777
787
|
let liquidationBuffer = undefined;
|
|
778
|
-
|
|
779
|
-
if (isBeingLiquidated) {
|
|
788
|
+
if (this.isBeingLiquidated()) {
|
|
780
789
|
liquidationBuffer = new _1.BN(this.driftClient.getStateAccount().liquidationMarginBufferRatio);
|
|
781
790
|
}
|
|
782
|
-
const
|
|
783
|
-
|
|
791
|
+
const marginRequirement = this.getMaintenanceMarginRequirement(liquidationBuffer);
|
|
792
|
+
const canBeLiquidated = totalCollateral.lt(marginRequirement);
|
|
793
|
+
return {
|
|
794
|
+
canBeLiquidated,
|
|
795
|
+
marginRequirement,
|
|
796
|
+
totalCollateral,
|
|
797
|
+
};
|
|
784
798
|
}
|
|
785
799
|
isBeingLiquidated() {
|
|
786
800
|
return (0, types_1.isOneOfVariant)(this.getUserAccount().status, [
|
|
@@ -1281,6 +1295,23 @@ class User {
|
|
|
1281
1295
|
}
|
|
1282
1296
|
return true;
|
|
1283
1297
|
}
|
|
1298
|
+
getSafestTiers() {
|
|
1299
|
+
let safestPerpTier = 4;
|
|
1300
|
+
let safestSpotTier = 4;
|
|
1301
|
+
for (const perpPosition of this.getActivePerpPositions()) {
|
|
1302
|
+
safestPerpTier = Math.min(safestPerpTier, (0, tiers_1.getPerpMarketTierNumber)(this.driftClient.getPerpMarketAccount(perpPosition.marketIndex)));
|
|
1303
|
+
}
|
|
1304
|
+
for (const spotPosition of this.getActiveSpotPositions()) {
|
|
1305
|
+
if ((0, types_1.isVariant)(spotPosition.balanceType, 'deposit')) {
|
|
1306
|
+
continue;
|
|
1307
|
+
}
|
|
1308
|
+
safestSpotTier = Math.min(safestSpotTier, (0, tiers_1.getSpotMarketTierNumber)(this.driftClient.getSpotMarketAccount(spotPosition.marketIndex)));
|
|
1309
|
+
}
|
|
1310
|
+
return {
|
|
1311
|
+
perpTier: safestPerpTier,
|
|
1312
|
+
spotTier: safestSpotTier,
|
|
1313
|
+
};
|
|
1314
|
+
}
|
|
1284
1315
|
/**
|
|
1285
1316
|
* Get the total position value, excluding any position coming from the given target market
|
|
1286
1317
|
* @param marketToIgnore
|
package/lib/userConfig.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { DriftClient } from './driftClient';
|
|
2
2
|
import { PublicKey } from '@solana/web3.js';
|
|
3
3
|
import { BulkAccountLoader } from './accounts/bulkAccountLoader';
|
|
4
|
+
import { UserAccountSubscriber } from './accounts/types';
|
|
4
5
|
export type UserConfig = {
|
|
5
6
|
accountSubscription?: UserSubscriptionConfig;
|
|
6
7
|
driftClient: DriftClient;
|
|
@@ -11,4 +12,7 @@ export type UserSubscriptionConfig = {
|
|
|
11
12
|
} | {
|
|
12
13
|
type: 'polling';
|
|
13
14
|
accountLoader: BulkAccountLoader;
|
|
15
|
+
} | {
|
|
16
|
+
type: 'custom';
|
|
17
|
+
userAccountSubscriber: UserAccountSubscriber;
|
|
14
18
|
};
|
package/lib/userStats.js
CHANGED
|
@@ -7,12 +7,15 @@ const webSocketUserStatsAccountSubsriber_1 = require("./accounts/webSocketUserSt
|
|
|
7
7
|
const pda_1 = require("./addresses/pda");
|
|
8
8
|
class UserStats {
|
|
9
9
|
constructor(config) {
|
|
10
|
-
var _a;
|
|
10
|
+
var _a, _b;
|
|
11
11
|
this.driftClient = config.driftClient;
|
|
12
12
|
this.userStatsAccountPublicKey = config.userStatsAccountPublicKey;
|
|
13
13
|
if (((_a = config.accountSubscription) === null || _a === void 0 ? void 0 : _a.type) === 'polling') {
|
|
14
14
|
this.accountSubscriber = new pollingUserStatsAccountSubscriber_1.PollingUserStatsAccountSubscriber(config.driftClient.program, config.userStatsAccountPublicKey, config.accountSubscription.accountLoader);
|
|
15
15
|
}
|
|
16
|
+
else if (((_b = config.accountSubscription) === null || _b === void 0 ? void 0 : _b.type) === 'custom') {
|
|
17
|
+
throw new Error('Custom account subscription not yet implemented for user stats');
|
|
18
|
+
}
|
|
16
19
|
else {
|
|
17
20
|
this.accountSubscriber = new webSocketUserStatsAccountSubsriber_1.WebSocketUserStatsAccountSubscriber(config.driftClient.program, config.userStatsAccountPublicKey);
|
|
18
21
|
}
|
package/lib/userStatsConfig.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { DataAndSlot, UserAccountEvents, UserAccountSubscriber } from './types';
|
|
2
|
+
import { PublicKey } from '@solana/web3.js';
|
|
3
|
+
import StrictEventEmitter from 'strict-event-emitter-types';
|
|
4
|
+
import { EventEmitter } from 'events';
|
|
5
|
+
import { UserAccount } from '../types';
|
|
6
|
+
|
|
7
|
+
export class MockUserAccountSubscriber implements UserAccountSubscriber {
|
|
8
|
+
isSubscribed: boolean;
|
|
9
|
+
eventEmitter: StrictEventEmitter<EventEmitter, UserAccountEvents>;
|
|
10
|
+
userAccountPublicKey: PublicKey;
|
|
11
|
+
|
|
12
|
+
callbackId?: string;
|
|
13
|
+
errorCallbackId?: string;
|
|
14
|
+
|
|
15
|
+
user: DataAndSlot<UserAccount>;
|
|
16
|
+
|
|
17
|
+
public constructor(
|
|
18
|
+
userAccountPublicKey: PublicKey,
|
|
19
|
+
data: UserAccount,
|
|
20
|
+
slot: number
|
|
21
|
+
) {
|
|
22
|
+
this.isSubscribed = true;
|
|
23
|
+
this.eventEmitter = new EventEmitter();
|
|
24
|
+
this.userAccountPublicKey = userAccountPublicKey;
|
|
25
|
+
this.user = { data, slot };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async subscribe(_userAccount?: UserAccount): Promise<boolean> {
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async addToAccountLoader(): Promise<void> {}
|
|
33
|
+
|
|
34
|
+
async fetch(): Promise<void> {}
|
|
35
|
+
|
|
36
|
+
doesAccountExist(): boolean {
|
|
37
|
+
return this.user !== undefined;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async unsubscribe(): Promise<void> {}
|
|
41
|
+
|
|
42
|
+
assertIsSubscribed(): void {}
|
|
43
|
+
|
|
44
|
+
public getUserAccountAndSlot(): DataAndSlot<UserAccount> {
|
|
45
|
+
return this.user;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
public updateData(userAccount: UserAccount, slot: number): void {
|
|
49
|
+
this.user = { data: userAccount, slot };
|
|
50
|
+
this.eventEmitter.emit('userAccountUpdate', userAccount);
|
|
51
|
+
this.eventEmitter.emit('update');
|
|
52
|
+
}
|
|
53
|
+
}
|
package/src/config.ts
CHANGED
|
@@ -131,7 +131,7 @@ export async function findAllMarketAndOracles(program: Program): Promise<{
|
|
|
131
131
|
(await program.account.spotMarket.all()) as ProgramAccount<SpotMarketAccount>[];
|
|
132
132
|
|
|
133
133
|
for (const perpMarketProgramAccount of perpMarketProgramAccounts) {
|
|
134
|
-
const perpMarket = perpMarketProgramAccount.account;
|
|
134
|
+
const perpMarket = perpMarketProgramAccount.account as PerpMarketAccount;
|
|
135
135
|
perpMarketIndexes.push(perpMarket.marketIndex);
|
|
136
136
|
oracleInfos.set(perpMarket.amm.oracle.toString(), {
|
|
137
137
|
publicKey: perpMarket.amm.oracle,
|
|
@@ -140,7 +140,7 @@ export async function findAllMarketAndOracles(program: Program): Promise<{
|
|
|
140
140
|
}
|
|
141
141
|
|
|
142
142
|
for (const spotMarketProgramAccount of spotMarketProgramAccounts) {
|
|
143
|
-
const spotMarket = spotMarketProgramAccount.account;
|
|
143
|
+
const spotMarket = spotMarketProgramAccount.account as SpotMarketAccount;
|
|
144
144
|
spotMarketIndexes.push(spotMarket.marketIndex);
|
|
145
145
|
oracleInfos.set(spotMarket.oracle.toString(), {
|
|
146
146
|
publicKey: spotMarket.oracle,
|
|
@@ -134,6 +134,16 @@ export const DevnetPerpMarkets: PerpMarketConfig[] = [
|
|
|
134
134
|
launchTs: 1683125906000,
|
|
135
135
|
oracleSource: OracleSource.PYTH,
|
|
136
136
|
},
|
|
137
|
+
{
|
|
138
|
+
fullName: 'RNDR',
|
|
139
|
+
category: ['Infra'],
|
|
140
|
+
symbol: 'RNDR-PERP',
|
|
141
|
+
baseAssetSymbol: 'RNDR',
|
|
142
|
+
marketIndex: 12,
|
|
143
|
+
oracle: new PublicKey('C2QvUPBiU3fViSyqA4nZgGyYqLgYf9PRpd8B8oLoo48w'),
|
|
144
|
+
launchTs: 1683125906000,
|
|
145
|
+
oracleSource: OracleSource.PYTH,
|
|
146
|
+
},
|
|
137
147
|
];
|
|
138
148
|
|
|
139
149
|
export const MainnetPerpMarkets: PerpMarketConfig[] = [
|
|
@@ -257,6 +267,16 @@ export const MainnetPerpMarkets: PerpMarketConfig[] = [
|
|
|
257
267
|
launchTs: 1683125906000,
|
|
258
268
|
oracleSource: OracleSource.PYTH,
|
|
259
269
|
},
|
|
270
|
+
{
|
|
271
|
+
fullName: 'RNDR',
|
|
272
|
+
category: ['Infra'],
|
|
273
|
+
symbol: 'RNDR-PERP',
|
|
274
|
+
baseAssetSymbol: 'RNDR',
|
|
275
|
+
marketIndex: 12,
|
|
276
|
+
oracle: new PublicKey('CYGfrBJB9HgLf9iZyN4aH5HvUAi2htQ4MjPxeXMf4Egn'),
|
|
277
|
+
launchTs: 1683125906000,
|
|
278
|
+
oracleSource: OracleSource.PYTH,
|
|
279
|
+
},
|
|
260
280
|
];
|
|
261
281
|
|
|
262
282
|
export const PerpMarkets: { [key in DriftEnv]: PerpMarketConfig[] } = {
|
package/src/driftClient.ts
CHANGED
|
@@ -95,6 +95,7 @@ import {
|
|
|
95
95
|
PRICE_PRECISION,
|
|
96
96
|
QUOTE_SPOT_MARKET_INDEX,
|
|
97
97
|
ZERO,
|
|
98
|
+
QUOTE_PRECISION,
|
|
98
99
|
} from './constants/numericConstants';
|
|
99
100
|
import { findDirectionToClose, positionIsAvailable } from './math/position';
|
|
100
101
|
import { getSignedTokenAmount, getTokenAmount } from './math/spotBalance';
|
|
@@ -115,6 +116,7 @@ import { fetchUserStatsAccount } from './accounts/fetch';
|
|
|
115
116
|
import { castNumberToSpotPrecision } from './math/spotMarket';
|
|
116
117
|
import { JupiterClient, Route, SwapMode } from './jupiter/jupiterClient';
|
|
117
118
|
import { getNonIdleUserFilter } from './memcmp';
|
|
119
|
+
import { UserStatsSubscriptionConfig } from './userStatsConfig';
|
|
118
120
|
|
|
119
121
|
type RemainingAccountParams = {
|
|
120
122
|
userAccounts: UserAccount[];
|
|
@@ -139,6 +141,7 @@ export class DriftClient {
|
|
|
139
141
|
userStats?: UserStats;
|
|
140
142
|
activeSubAccountId: number;
|
|
141
143
|
userAccountSubscriptionConfig: UserSubscriptionConfig;
|
|
144
|
+
userStatsAccountSubscriptionConfig: UserStatsSubscriptionConfig;
|
|
142
145
|
accountSubscriber: DriftClientAccountSubscriber;
|
|
143
146
|
eventEmitter: StrictEventEmitter<EventEmitter, DriftClientAccountEvents>;
|
|
144
147
|
_isSubscribed = false;
|
|
@@ -152,6 +155,7 @@ export class DriftClient {
|
|
|
152
155
|
authoritySubAccountMap?: Map<string, number[]>;
|
|
153
156
|
skipLoadUsers?: boolean;
|
|
154
157
|
txVersion: TransactionVersion;
|
|
158
|
+
txParams: TxParams;
|
|
155
159
|
|
|
156
160
|
public get isSubscribed() {
|
|
157
161
|
return this._isSubscribed && this.accountSubscriber.isSubscribed;
|
|
@@ -180,6 +184,10 @@ export class DriftClient {
|
|
|
180
184
|
this.activeSubAccountId = config.activeSubAccountId ?? 0;
|
|
181
185
|
this.skipLoadUsers = config.skipLoadUsers ?? false;
|
|
182
186
|
this.txVersion = config.txVersion ?? 'legacy';
|
|
187
|
+
this.txParams = {
|
|
188
|
+
computeUnits: config.txParams?.computeUnits ?? 600_000,
|
|
189
|
+
computeUnitsPrice: config.txParams?.computeUnitsPrice ?? 0,
|
|
190
|
+
};
|
|
183
191
|
|
|
184
192
|
if (config.includeDelegates && config.subAccountIds) {
|
|
185
193
|
throw new Error(
|
|
@@ -206,15 +214,23 @@ export class DriftClient {
|
|
|
206
214
|
: new Map<string, number[]>();
|
|
207
215
|
|
|
208
216
|
this.includeDelegates = config.includeDelegates ?? false;
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
:
|
|
216
|
-
|
|
217
|
-
|
|
217
|
+
if (config.accountSubscription?.type === 'polling') {
|
|
218
|
+
this.userAccountSubscriptionConfig = {
|
|
219
|
+
type: 'polling',
|
|
220
|
+
accountLoader: config.accountSubscription.accountLoader,
|
|
221
|
+
};
|
|
222
|
+
this.userStatsAccountSubscriptionConfig = {
|
|
223
|
+
type: 'polling',
|
|
224
|
+
accountLoader: config.accountSubscription.accountLoader,
|
|
225
|
+
};
|
|
226
|
+
} else {
|
|
227
|
+
this.userAccountSubscriptionConfig = {
|
|
228
|
+
type: 'websocket',
|
|
229
|
+
};
|
|
230
|
+
this.userStatsAccountSubscriptionConfig = {
|
|
231
|
+
type: 'websocket',
|
|
232
|
+
};
|
|
233
|
+
}
|
|
218
234
|
|
|
219
235
|
if (config.userStats) {
|
|
220
236
|
this.userStats = new UserStats({
|
|
@@ -257,12 +273,13 @@ export class DriftClient {
|
|
|
257
273
|
);
|
|
258
274
|
}
|
|
259
275
|
this.eventEmitter = this.accountSubscriber.eventEmitter;
|
|
260
|
-
this.txSender =
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
276
|
+
this.txSender =
|
|
277
|
+
config.txSender ??
|
|
278
|
+
new RetryTxSender({
|
|
279
|
+
connection: this.connection,
|
|
280
|
+
wallet: this.wallet,
|
|
281
|
+
opts: this.opts,
|
|
282
|
+
});
|
|
266
283
|
}
|
|
267
284
|
|
|
268
285
|
public getUserMapKey(subAccountId: number, authority: PublicKey): string {
|
|
@@ -503,7 +520,7 @@ export class DriftClient {
|
|
|
503
520
|
|
|
504
521
|
this.skipLoadUsers = false;
|
|
505
522
|
// Update provider for txSender with new wallet details
|
|
506
|
-
this.txSender.
|
|
523
|
+
this.txSender.wallet = newWallet;
|
|
507
524
|
this.wallet = newWallet;
|
|
508
525
|
this.provider = newProvider;
|
|
509
526
|
this.program = newProgram;
|
|
@@ -547,7 +564,7 @@ export class DriftClient {
|
|
|
547
564
|
this.userStats = new UserStats({
|
|
548
565
|
driftClient: this,
|
|
549
566
|
userStatsAccountPublicKey: this.getUserStatsAccountPublicKey(),
|
|
550
|
-
accountSubscription: this.
|
|
567
|
+
accountSubscription: this.userStatsAccountSubscriptionConfig,
|
|
551
568
|
});
|
|
552
569
|
|
|
553
570
|
await this.userStats.subscribe();
|
|
@@ -1033,11 +1050,19 @@ export class DriftClient {
|
|
|
1033
1050
|
const userMapKey = this.getUserMapKey(subAccountId, authority);
|
|
1034
1051
|
|
|
1035
1052
|
if (!this.users.has(userMapKey)) {
|
|
1036
|
-
throw new Error(`
|
|
1053
|
+
throw new Error(`DriftClient has no user for user id ${userMapKey}`);
|
|
1037
1054
|
}
|
|
1038
1055
|
return this.users.get(userMapKey);
|
|
1039
1056
|
}
|
|
1040
1057
|
|
|
1058
|
+
public hasUser(subAccountId?: number, authority?: PublicKey): boolean {
|
|
1059
|
+
subAccountId = subAccountId ?? this.activeSubAccountId;
|
|
1060
|
+
authority = authority ?? this.authority;
|
|
1061
|
+
const userMapKey = this.getUserMapKey(subAccountId, authority);
|
|
1062
|
+
|
|
1063
|
+
return this.users.has(userMapKey);
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1041
1066
|
public getUsers(): User[] {
|
|
1042
1067
|
// delegate users get added to the end
|
|
1043
1068
|
return [...this.users.values()]
|
|
@@ -1695,7 +1720,7 @@ export class DriftClient {
|
|
|
1695
1720
|
}
|
|
1696
1721
|
|
|
1697
1722
|
/**
|
|
1698
|
-
* Creates the
|
|
1723
|
+
* Creates the User account for a user, and deposits some initial collateral
|
|
1699
1724
|
* @param amount
|
|
1700
1725
|
* @param userTokenAccount
|
|
1701
1726
|
* @param marketIndex
|
|
@@ -2296,6 +2321,35 @@ export class DriftClient {
|
|
|
2296
2321
|
});
|
|
2297
2322
|
}
|
|
2298
2323
|
|
|
2324
|
+
public getQuoteValuePerLpShare(marketIndex: number): BN {
|
|
2325
|
+
const perpMarketAccount = this.getPerpMarketAccount(marketIndex);
|
|
2326
|
+
|
|
2327
|
+
const openBids = BN.max(
|
|
2328
|
+
perpMarketAccount.amm.baseAssetReserve.sub(
|
|
2329
|
+
perpMarketAccount.amm.minBaseAssetReserve
|
|
2330
|
+
),
|
|
2331
|
+
ZERO
|
|
2332
|
+
);
|
|
2333
|
+
|
|
2334
|
+
const openAsks = BN.max(
|
|
2335
|
+
perpMarketAccount.amm.maxBaseAssetReserve.sub(
|
|
2336
|
+
perpMarketAccount.amm.baseAssetReserve
|
|
2337
|
+
),
|
|
2338
|
+
ZERO
|
|
2339
|
+
);
|
|
2340
|
+
|
|
2341
|
+
const oraclePriceData = this.getOracleDataForPerpMarket(marketIndex);
|
|
2342
|
+
|
|
2343
|
+
const maxOpenBidsAsks = BN.max(openBids, openAsks);
|
|
2344
|
+
const quoteValuePerLpShare = maxOpenBidsAsks
|
|
2345
|
+
.mul(oraclePriceData.price)
|
|
2346
|
+
.mul(QUOTE_PRECISION)
|
|
2347
|
+
.div(PRICE_PRECISION)
|
|
2348
|
+
.div(perpMarketAccount.amm.sqrtK);
|
|
2349
|
+
|
|
2350
|
+
return quoteValuePerLpShare;
|
|
2351
|
+
}
|
|
2352
|
+
|
|
2299
2353
|
/**
|
|
2300
2354
|
* @deprecated use {@link placePerpOrder} or {@link placeAndTakePerpOrder} instead
|
|
2301
2355
|
*/
|
|
@@ -5366,7 +5420,7 @@ export class DriftClient {
|
|
|
5366
5420
|
lookupTables?: AddressLookupTableAccount[]
|
|
5367
5421
|
): Promise<Transaction | VersionedTransaction> {
|
|
5368
5422
|
const allIx = [];
|
|
5369
|
-
const computeUnits = txParams?.computeUnits ??
|
|
5423
|
+
const computeUnits = txParams?.computeUnits ?? this.txParams.computeUnits;
|
|
5370
5424
|
if (computeUnits !== 200_000) {
|
|
5371
5425
|
allIx.push(
|
|
5372
5426
|
ComputeBudgetProgram.setComputeUnitLimit({
|
|
@@ -5374,7 +5428,8 @@ export class DriftClient {
|
|
|
5374
5428
|
})
|
|
5375
5429
|
);
|
|
5376
5430
|
}
|
|
5377
|
-
const computeUnitsPrice =
|
|
5431
|
+
const computeUnitsPrice =
|
|
5432
|
+
txParams?.computeUnitsPrice ?? this.txParams.computeUnitsPrice;
|
|
5378
5433
|
if (computeUnitsPrice !== 0) {
|
|
5379
5434
|
allIx.push(
|
|
5380
5435
|
ComputeBudgetProgram.setComputeUnitPrice({
|
package/src/driftClientConfig.ts
CHANGED
|
@@ -4,10 +4,11 @@ import {
|
|
|
4
4
|
PublicKey,
|
|
5
5
|
TransactionVersion,
|
|
6
6
|
} from '@solana/web3.js';
|
|
7
|
-
import { IWallet } from './types';
|
|
7
|
+
import { IWallet, TxParams } from './types';
|
|
8
8
|
import { OracleInfo } from './oracles/types';
|
|
9
9
|
import { BulkAccountLoader } from './accounts/bulkAccountLoader';
|
|
10
10
|
import { DriftEnv } from './config';
|
|
11
|
+
import { TxSender } from './tx/types';
|
|
11
12
|
|
|
12
13
|
export type DriftClientConfig = {
|
|
13
14
|
connection: Connection;
|
|
@@ -16,7 +17,7 @@ export type DriftClientConfig = {
|
|
|
16
17
|
programID?: PublicKey;
|
|
17
18
|
accountSubscription?: DriftClientSubscriptionConfig;
|
|
18
19
|
opts?: ConfirmOptions;
|
|
19
|
-
|
|
20
|
+
txSender?: TxSender;
|
|
20
21
|
subAccountIds?: number[];
|
|
21
22
|
activeSubAccountId?: number;
|
|
22
23
|
perpMarketIndexes?: number[];
|
|
@@ -29,6 +30,7 @@ export type DriftClientConfig = {
|
|
|
29
30
|
authoritySubAccountMap?: Map<string, number[]>; // if passed this will override subAccountIds and includeDelegates
|
|
30
31
|
skipLoadUsers?: boolean; // if passed to constructor, no user accounts will be loaded. they will load if updateWallet is called afterwards.
|
|
31
32
|
txVersion?: TransactionVersion; // which tx version to use
|
|
33
|
+
txParams?: TxParams; // default tx params to use
|
|
32
34
|
};
|
|
33
35
|
|
|
34
36
|
export type DriftClientSubscriptionConfig =
|
|
@@ -39,10 +41,3 @@ export type DriftClientSubscriptionConfig =
|
|
|
39
41
|
type: 'polling';
|
|
40
42
|
accountLoader: BulkAccountLoader;
|
|
41
43
|
};
|
|
42
|
-
|
|
43
|
-
type TxSenderConfig = {
|
|
44
|
-
type: 'retry';
|
|
45
|
-
timeout?: number;
|
|
46
|
-
retrySleep?: number;
|
|
47
|
-
additionalConnections?: Connection[];
|
|
48
|
-
};
|
package/src/idl/drift.json
CHANGED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { isVariant, PerpMarketAccount, SpotMarketAccount } from '../types';
|
|
2
|
+
|
|
3
|
+
export function getPerpMarketTierNumber(perpMarket: PerpMarketAccount): number {
|
|
4
|
+
if (isVariant(perpMarket.contractTier, 'a')) {
|
|
5
|
+
return 0;
|
|
6
|
+
} else if (isVariant(perpMarket.contractTier, 'b')) {
|
|
7
|
+
return 1;
|
|
8
|
+
} else if (isVariant(perpMarket.contractTier, 'c')) {
|
|
9
|
+
return 2;
|
|
10
|
+
} else if (isVariant(perpMarket.contractTier, 'speculative')) {
|
|
11
|
+
return 3;
|
|
12
|
+
} else if (isVariant(perpMarket.contractTier, 'isolated')) {
|
|
13
|
+
return 4;
|
|
14
|
+
} else {
|
|
15
|
+
return 5;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function getSpotMarketTierNumber(spotMarket: SpotMarketAccount): number {
|
|
20
|
+
if (isVariant(spotMarket.assetTier, 'collateral')) {
|
|
21
|
+
return 0;
|
|
22
|
+
} else if (isVariant(spotMarket.assetTier, 'protected')) {
|
|
23
|
+
return 1;
|
|
24
|
+
} else if (isVariant(spotMarket.assetTier, 'cross')) {
|
|
25
|
+
return 2;
|
|
26
|
+
} else if (isVariant(spotMarket.assetTier, 'isolated')) {
|
|
27
|
+
return 3;
|
|
28
|
+
} else if (isVariant(spotMarket.assetTier, 'unlisted')) {
|
|
29
|
+
return 4;
|
|
30
|
+
} else {
|
|
31
|
+
return 5;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function perpTierIsAsSafeAs(
|
|
36
|
+
perpTier: number,
|
|
37
|
+
otherPerpTier: number,
|
|
38
|
+
otherSpotTier: number
|
|
39
|
+
): boolean {
|
|
40
|
+
const asSafeAsPerp = perpTier <= otherPerpTier;
|
|
41
|
+
const asSafeAsSpot =
|
|
42
|
+
otherSpotTier === 4 || (otherSpotTier >= 2 && perpTier <= 2);
|
|
43
|
+
return asSafeAsSpot && asSafeAsPerp;
|
|
44
|
+
}
|