@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/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
2.31.1-beta.
|
|
1
|
+
2.31.1-beta.10
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { DataAndSlot, UserAccountEvents, UserAccountSubscriber } from './types';
|
|
3
|
+
import { PublicKey } from '@solana/web3.js';
|
|
4
|
+
import StrictEventEmitter from 'strict-event-emitter-types';
|
|
5
|
+
import { EventEmitter } from 'events';
|
|
6
|
+
import { UserAccount } from '../types';
|
|
7
|
+
export declare class MockUserAccountSubscriber implements UserAccountSubscriber {
|
|
8
|
+
isSubscribed: boolean;
|
|
9
|
+
eventEmitter: StrictEventEmitter<EventEmitter, UserAccountEvents>;
|
|
10
|
+
userAccountPublicKey: PublicKey;
|
|
11
|
+
callbackId?: string;
|
|
12
|
+
errorCallbackId?: string;
|
|
13
|
+
user: DataAndSlot<UserAccount>;
|
|
14
|
+
constructor(userAccountPublicKey: PublicKey, data: UserAccount, slot: number);
|
|
15
|
+
subscribe(_userAccount?: UserAccount): Promise<boolean>;
|
|
16
|
+
addToAccountLoader(): Promise<void>;
|
|
17
|
+
fetch(): Promise<void>;
|
|
18
|
+
doesAccountExist(): boolean;
|
|
19
|
+
unsubscribe(): Promise<void>;
|
|
20
|
+
assertIsSubscribed(): void;
|
|
21
|
+
getUserAccountAndSlot(): DataAndSlot<UserAccount>;
|
|
22
|
+
updateData(userAccount: UserAccount, slot: number): void;
|
|
23
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MockUserAccountSubscriber = void 0;
|
|
4
|
+
const events_1 = require("events");
|
|
5
|
+
class MockUserAccountSubscriber {
|
|
6
|
+
constructor(userAccountPublicKey, data, slot) {
|
|
7
|
+
this.isSubscribed = true;
|
|
8
|
+
this.eventEmitter = new events_1.EventEmitter();
|
|
9
|
+
this.userAccountPublicKey = userAccountPublicKey;
|
|
10
|
+
this.user = { data, slot };
|
|
11
|
+
}
|
|
12
|
+
async subscribe(_userAccount) {
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
15
|
+
async addToAccountLoader() { }
|
|
16
|
+
async fetch() { }
|
|
17
|
+
doesAccountExist() {
|
|
18
|
+
return this.user !== undefined;
|
|
19
|
+
}
|
|
20
|
+
async unsubscribe() { }
|
|
21
|
+
assertIsSubscribed() { }
|
|
22
|
+
getUserAccountAndSlot() {
|
|
23
|
+
return this.user;
|
|
24
|
+
}
|
|
25
|
+
updateData(userAccount, slot) {
|
|
26
|
+
this.user = { data: userAccount, slot };
|
|
27
|
+
this.eventEmitter.emit('userAccountUpdate', userAccount);
|
|
28
|
+
this.eventEmitter.emit('update');
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
exports.MockUserAccountSubscriber = MockUserAccountSubscriber;
|
|
@@ -124,6 +124,16 @@ exports.DevnetPerpMarkets = [
|
|
|
124
124
|
launchTs: 1683125906000,
|
|
125
125
|
oracleSource: __1.OracleSource.PYTH,
|
|
126
126
|
},
|
|
127
|
+
{
|
|
128
|
+
fullName: 'RNDR',
|
|
129
|
+
category: ['Infra'],
|
|
130
|
+
symbol: 'RNDR-PERP',
|
|
131
|
+
baseAssetSymbol: 'RNDR',
|
|
132
|
+
marketIndex: 12,
|
|
133
|
+
oracle: new web3_js_1.PublicKey('C2QvUPBiU3fViSyqA4nZgGyYqLgYf9PRpd8B8oLoo48w'),
|
|
134
|
+
launchTs: 1683125906000,
|
|
135
|
+
oracleSource: __1.OracleSource.PYTH,
|
|
136
|
+
},
|
|
127
137
|
];
|
|
128
138
|
exports.MainnetPerpMarkets = [
|
|
129
139
|
{
|
|
@@ -246,6 +256,16 @@ exports.MainnetPerpMarkets = [
|
|
|
246
256
|
launchTs: 1683125906000,
|
|
247
257
|
oracleSource: __1.OracleSource.PYTH,
|
|
248
258
|
},
|
|
259
|
+
{
|
|
260
|
+
fullName: 'RNDR',
|
|
261
|
+
category: ['Infra'],
|
|
262
|
+
symbol: 'RNDR-PERP',
|
|
263
|
+
baseAssetSymbol: 'RNDR',
|
|
264
|
+
marketIndex: 12,
|
|
265
|
+
oracle: new web3_js_1.PublicKey('CYGfrBJB9HgLf9iZyN4aH5HvUAi2htQ4MjPxeXMf4Egn'),
|
|
266
|
+
launchTs: 1683125906000,
|
|
267
|
+
oracleSource: __1.OracleSource.PYTH,
|
|
268
|
+
},
|
|
249
269
|
];
|
|
250
270
|
exports.PerpMarkets = {
|
|
251
271
|
devnet: exports.DevnetPerpMarkets,
|
package/lib/driftClient.d.ts
CHANGED
|
@@ -14,6 +14,7 @@ import { User } from './user';
|
|
|
14
14
|
import { UserSubscriptionConfig } from './userConfig';
|
|
15
15
|
import { UserStats } from './userStats';
|
|
16
16
|
import { JupiterClient, Route, SwapMode } from './jupiter/jupiterClient';
|
|
17
|
+
import { UserStatsSubscriptionConfig } from './userStatsConfig';
|
|
17
18
|
type RemainingAccountParams = {
|
|
18
19
|
userAccounts: UserAccount[];
|
|
19
20
|
writablePerpMarketIndexes?: number[];
|
|
@@ -36,6 +37,7 @@ export declare class DriftClient {
|
|
|
36
37
|
userStats?: UserStats;
|
|
37
38
|
activeSubAccountId: number;
|
|
38
39
|
userAccountSubscriptionConfig: UserSubscriptionConfig;
|
|
40
|
+
userStatsAccountSubscriptionConfig: UserStatsSubscriptionConfig;
|
|
39
41
|
accountSubscriber: DriftClientAccountSubscriber;
|
|
40
42
|
eventEmitter: StrictEventEmitter<EventEmitter, DriftClientAccountEvents>;
|
|
41
43
|
_isSubscribed: boolean;
|
|
@@ -49,6 +51,7 @@ export declare class DriftClient {
|
|
|
49
51
|
authoritySubAccountMap?: Map<string, number[]>;
|
|
50
52
|
skipLoadUsers?: boolean;
|
|
51
53
|
txVersion: TransactionVersion;
|
|
54
|
+
txParams: TxParams;
|
|
52
55
|
get isSubscribed(): boolean;
|
|
53
56
|
set isSubscribed(val: boolean);
|
|
54
57
|
constructor(config: DriftClientConfig);
|
|
@@ -121,6 +124,7 @@ export declare class DriftClient {
|
|
|
121
124
|
getReferrerNameAccountsForAuthority(authority: PublicKey): Promise<ReferrerNameAccount[]>;
|
|
122
125
|
deleteUser(subAccountId?: number, txParams?: TxParams): Promise<TransactionSignature>;
|
|
123
126
|
getUser(subAccountId?: number, authority?: PublicKey): User;
|
|
127
|
+
hasUser(subAccountId?: number, authority?: PublicKey): boolean;
|
|
124
128
|
getUsers(): User[];
|
|
125
129
|
getUserStats(): UserStats;
|
|
126
130
|
fetchReferrerNameAccount(name: string): Promise<ReferrerNameAccount | undefined>;
|
|
@@ -188,7 +192,7 @@ export declare class DriftClient {
|
|
|
188
192
|
private getWrappedSolAccountCreationIxs;
|
|
189
193
|
getAssociatedTokenAccountCreationIx(tokenMintAddress: PublicKey, associatedTokenAddress: PublicKey): anchor.web3.TransactionInstruction;
|
|
190
194
|
/**
|
|
191
|
-
* Creates the
|
|
195
|
+
* Creates the User account for a user, and deposits some initial collateral
|
|
192
196
|
* @param amount
|
|
193
197
|
* @param userTokenAccount
|
|
194
198
|
* @param marketIndex
|
|
@@ -228,6 +232,7 @@ export declare class DriftClient {
|
|
|
228
232
|
getRemovePerpLpSharesIx(marketIndex: number, sharesToBurn?: BN): Promise<TransactionInstruction>;
|
|
229
233
|
addPerpLpShares(amount: BN, marketIndex: number, txParams?: TxParams): Promise<TransactionSignature>;
|
|
230
234
|
getAddPerpLpSharesIx(amount: BN, marketIndex: number): Promise<TransactionInstruction>;
|
|
235
|
+
getQuoteValuePerLpShare(marketIndex: number): BN;
|
|
231
236
|
/**
|
|
232
237
|
* @deprecated use {@link placePerpOrder} or {@link placeAndTakePerpOrder} instead
|
|
233
238
|
*/
|
package/lib/driftClient.js
CHANGED
|
@@ -64,7 +64,7 @@ class DriftClient {
|
|
|
64
64
|
this._isSubscribed = val;
|
|
65
65
|
}
|
|
66
66
|
constructor(config) {
|
|
67
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;
|
|
67
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u;
|
|
68
68
|
this.users = new Map();
|
|
69
69
|
this._isSubscribed = false;
|
|
70
70
|
this.perpMarketLastSlotCache = new Map();
|
|
@@ -78,6 +78,10 @@ class DriftClient {
|
|
|
78
78
|
this.activeSubAccountId = (_c = config.activeSubAccountId) !== null && _c !== void 0 ? _c : 0;
|
|
79
79
|
this.skipLoadUsers = (_d = config.skipLoadUsers) !== null && _d !== void 0 ? _d : false;
|
|
80
80
|
this.txVersion = (_e = config.txVersion) !== null && _e !== void 0 ? _e : 'legacy';
|
|
81
|
+
this.txParams = {
|
|
82
|
+
computeUnits: (_g = (_f = config.txParams) === null || _f === void 0 ? void 0 : _f.computeUnits) !== null && _g !== void 0 ? _g : 600000,
|
|
83
|
+
computeUnitsPrice: (_j = (_h = config.txParams) === null || _h === void 0 ? void 0 : _h.computeUnitsPrice) !== null && _j !== void 0 ? _j : 0,
|
|
84
|
+
};
|
|
81
85
|
if (config.includeDelegates && config.subAccountIds) {
|
|
82
86
|
throw new Error('Can only pass one of includeDelegates or subAccountIds. If you want to specify subaccount ids for multiple authorities, pass authoritySubaccountMap instead');
|
|
83
87
|
}
|
|
@@ -92,16 +96,25 @@ class DriftClient {
|
|
|
92
96
|
: config.subAccountIds
|
|
93
97
|
? new Map([[this.authority.toString(), config.subAccountIds]])
|
|
94
98
|
: new Map();
|
|
95
|
-
this.includeDelegates = (
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
:
|
|
103
|
-
|
|
104
|
-
|
|
99
|
+
this.includeDelegates = (_k = config.includeDelegates) !== null && _k !== void 0 ? _k : false;
|
|
100
|
+
if (((_l = config.accountSubscription) === null || _l === void 0 ? void 0 : _l.type) === 'polling') {
|
|
101
|
+
this.userAccountSubscriptionConfig = {
|
|
102
|
+
type: 'polling',
|
|
103
|
+
accountLoader: config.accountSubscription.accountLoader,
|
|
104
|
+
};
|
|
105
|
+
this.userStatsAccountSubscriptionConfig = {
|
|
106
|
+
type: 'polling',
|
|
107
|
+
accountLoader: config.accountSubscription.accountLoader,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
this.userAccountSubscriptionConfig = {
|
|
112
|
+
type: 'websocket',
|
|
113
|
+
};
|
|
114
|
+
this.userStatsAccountSubscriptionConfig = {
|
|
115
|
+
type: 'websocket',
|
|
116
|
+
};
|
|
117
|
+
}
|
|
105
118
|
if (config.userStats) {
|
|
106
119
|
this.userStats = new userStats_1.UserStats({
|
|
107
120
|
driftClient: this,
|
|
@@ -116,14 +129,19 @@ class DriftClient {
|
|
|
116
129
|
const noMarketsAndOraclesSpecified = config.perpMarketIndexes === undefined &&
|
|
117
130
|
config.spotMarketIndexes === undefined &&
|
|
118
131
|
config.oracleInfos === undefined;
|
|
119
|
-
if (((
|
|
120
|
-
this.accountSubscriber = new pollingDriftClientAccountSubscriber_1.PollingDriftClientAccountSubscriber(this.program, config.accountSubscription.accountLoader, (
|
|
132
|
+
if (((_m = config.accountSubscription) === null || _m === void 0 ? void 0 : _m.type) === 'polling') {
|
|
133
|
+
this.accountSubscriber = new pollingDriftClientAccountSubscriber_1.PollingDriftClientAccountSubscriber(this.program, config.accountSubscription.accountLoader, (_o = config.perpMarketIndexes) !== null && _o !== void 0 ? _o : [], (_p = config.spotMarketIndexes) !== null && _p !== void 0 ? _p : [], (_q = config.oracleInfos) !== null && _q !== void 0 ? _q : [], noMarketsAndOraclesSpecified);
|
|
121
134
|
}
|
|
122
135
|
else {
|
|
123
|
-
this.accountSubscriber = new webSocketDriftClientAccountSubscriber_1.WebSocketDriftClientAccountSubscriber(this.program, (
|
|
136
|
+
this.accountSubscriber = new webSocketDriftClientAccountSubscriber_1.WebSocketDriftClientAccountSubscriber(this.program, (_r = config.perpMarketIndexes) !== null && _r !== void 0 ? _r : [], (_s = config.spotMarketIndexes) !== null && _s !== void 0 ? _s : [], (_t = config.oracleInfos) !== null && _t !== void 0 ? _t : [], noMarketsAndOraclesSpecified);
|
|
124
137
|
}
|
|
125
138
|
this.eventEmitter = this.accountSubscriber.eventEmitter;
|
|
126
|
-
this.txSender =
|
|
139
|
+
this.txSender =
|
|
140
|
+
(_u = config.txSender) !== null && _u !== void 0 ? _u : new retryTxSender_1.RetryTxSender({
|
|
141
|
+
connection: this.connection,
|
|
142
|
+
wallet: this.wallet,
|
|
143
|
+
opts: this.opts,
|
|
144
|
+
});
|
|
127
145
|
}
|
|
128
146
|
getUserMapKey(subAccountId, authority) {
|
|
129
147
|
return `${subAccountId}_${authority.toString()}`;
|
|
@@ -274,7 +292,7 @@ class DriftClient {
|
|
|
274
292
|
const newProgram = new anchor_1.Program(drift_json_1.default, this.program.programId, newProvider);
|
|
275
293
|
this.skipLoadUsers = false;
|
|
276
294
|
// Update provider for txSender with new wallet details
|
|
277
|
-
this.txSender.
|
|
295
|
+
this.txSender.wallet = newWallet;
|
|
278
296
|
this.wallet = newWallet;
|
|
279
297
|
this.provider = newProvider;
|
|
280
298
|
this.program = newProgram;
|
|
@@ -304,7 +322,7 @@ class DriftClient {
|
|
|
304
322
|
this.userStats = new userStats_1.UserStats({
|
|
305
323
|
driftClient: this,
|
|
306
324
|
userStatsAccountPublicKey: this.getUserStatsAccountPublicKey(),
|
|
307
|
-
accountSubscription: this.
|
|
325
|
+
accountSubscription: this.userStatsAccountSubscriptionConfig,
|
|
308
326
|
});
|
|
309
327
|
await this.userStats.subscribe();
|
|
310
328
|
}
|
|
@@ -606,10 +624,16 @@ class DriftClient {
|
|
|
606
624
|
authority = authority !== null && authority !== void 0 ? authority : this.authority;
|
|
607
625
|
const userMapKey = this.getUserMapKey(subAccountId, authority);
|
|
608
626
|
if (!this.users.has(userMapKey)) {
|
|
609
|
-
throw new Error(`
|
|
627
|
+
throw new Error(`DriftClient has no user for user id ${userMapKey}`);
|
|
610
628
|
}
|
|
611
629
|
return this.users.get(userMapKey);
|
|
612
630
|
}
|
|
631
|
+
hasUser(subAccountId, authority) {
|
|
632
|
+
subAccountId = subAccountId !== null && subAccountId !== void 0 ? subAccountId : this.activeSubAccountId;
|
|
633
|
+
authority = authority !== null && authority !== void 0 ? authority : this.authority;
|
|
634
|
+
const userMapKey = this.getUserMapKey(subAccountId, authority);
|
|
635
|
+
return this.users.has(userMapKey);
|
|
636
|
+
}
|
|
613
637
|
getUsers() {
|
|
614
638
|
// delegate users get added to the end
|
|
615
639
|
return [...this.users.values()]
|
|
@@ -1064,7 +1088,7 @@ class DriftClient {
|
|
|
1064
1088
|
return (0, spl_token_1.createAssociatedTokenAccountInstruction)(this.wallet.publicKey, associatedTokenAddress, this.wallet.publicKey, tokenMintAddress);
|
|
1065
1089
|
}
|
|
1066
1090
|
/**
|
|
1067
|
-
* Creates the
|
|
1091
|
+
* Creates the User account for a user, and deposits some initial collateral
|
|
1068
1092
|
* @param amount
|
|
1069
1093
|
* @param userTokenAccount
|
|
1070
1094
|
* @param marketIndex
|
|
@@ -1349,6 +1373,19 @@ class DriftClient {
|
|
|
1349
1373
|
remainingAccounts: remainingAccounts,
|
|
1350
1374
|
});
|
|
1351
1375
|
}
|
|
1376
|
+
getQuoteValuePerLpShare(marketIndex) {
|
|
1377
|
+
const perpMarketAccount = this.getPerpMarketAccount(marketIndex);
|
|
1378
|
+
const openBids = anchor_1.BN.max(perpMarketAccount.amm.baseAssetReserve.sub(perpMarketAccount.amm.minBaseAssetReserve), numericConstants_1.ZERO);
|
|
1379
|
+
const openAsks = anchor_1.BN.max(perpMarketAccount.amm.maxBaseAssetReserve.sub(perpMarketAccount.amm.baseAssetReserve), numericConstants_1.ZERO);
|
|
1380
|
+
const oraclePriceData = this.getOracleDataForPerpMarket(marketIndex);
|
|
1381
|
+
const maxOpenBidsAsks = anchor_1.BN.max(openBids, openAsks);
|
|
1382
|
+
const quoteValuePerLpShare = maxOpenBidsAsks
|
|
1383
|
+
.mul(oraclePriceData.price)
|
|
1384
|
+
.mul(numericConstants_1.QUOTE_PRECISION)
|
|
1385
|
+
.div(numericConstants_1.PRICE_PRECISION)
|
|
1386
|
+
.div(perpMarketAccount.amm.sqrtK);
|
|
1387
|
+
return quoteValuePerLpShare;
|
|
1388
|
+
}
|
|
1352
1389
|
/**
|
|
1353
1390
|
* @deprecated use {@link placePerpOrder} or {@link placeAndTakePerpOrder} instead
|
|
1354
1391
|
*/
|
|
@@ -3049,13 +3086,13 @@ class DriftClient {
|
|
|
3049
3086
|
async buildTransaction(instructions, txParams, txVersion, lookupTables) {
|
|
3050
3087
|
var _a, _b;
|
|
3051
3088
|
const allIx = [];
|
|
3052
|
-
const computeUnits = (_a = txParams === null || txParams === void 0 ? void 0 : txParams.computeUnits) !== null && _a !== void 0 ? _a :
|
|
3089
|
+
const computeUnits = (_a = txParams === null || txParams === void 0 ? void 0 : txParams.computeUnits) !== null && _a !== void 0 ? _a : this.txParams.computeUnits;
|
|
3053
3090
|
if (computeUnits !== 200000) {
|
|
3054
3091
|
allIx.push(web3_js_1.ComputeBudgetProgram.setComputeUnitLimit({
|
|
3055
3092
|
units: computeUnits,
|
|
3056
3093
|
}));
|
|
3057
3094
|
}
|
|
3058
|
-
const computeUnitsPrice = (_b = txParams === null || txParams === void 0 ? void 0 : txParams.computeUnitsPrice) !== null && _b !== void 0 ? _b :
|
|
3095
|
+
const computeUnitsPrice = (_b = txParams === null || txParams === void 0 ? void 0 : txParams.computeUnitsPrice) !== null && _b !== void 0 ? _b : this.txParams.computeUnitsPrice;
|
|
3059
3096
|
if (computeUnitsPrice !== 0) {
|
|
3060
3097
|
allIx.push(web3_js_1.ComputeBudgetProgram.setComputeUnitPrice({
|
|
3061
3098
|
microLamports: computeUnitsPrice,
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { ConfirmOptions, Connection, PublicKey, TransactionVersion } from '@solana/web3.js';
|
|
2
|
-
import { IWallet } from './types';
|
|
2
|
+
import { IWallet, TxParams } from './types';
|
|
3
3
|
import { OracleInfo } from './oracles/types';
|
|
4
4
|
import { BulkAccountLoader } from './accounts/bulkAccountLoader';
|
|
5
5
|
import { DriftEnv } from './config';
|
|
6
|
+
import { TxSender } from './tx/types';
|
|
6
7
|
export type DriftClientConfig = {
|
|
7
8
|
connection: Connection;
|
|
8
9
|
wallet: IWallet;
|
|
@@ -10,7 +11,7 @@ export type DriftClientConfig = {
|
|
|
10
11
|
programID?: PublicKey;
|
|
11
12
|
accountSubscription?: DriftClientSubscriptionConfig;
|
|
12
13
|
opts?: ConfirmOptions;
|
|
13
|
-
|
|
14
|
+
txSender?: TxSender;
|
|
14
15
|
subAccountIds?: number[];
|
|
15
16
|
activeSubAccountId?: number;
|
|
16
17
|
perpMarketIndexes?: number[];
|
|
@@ -23,6 +24,7 @@ export type DriftClientConfig = {
|
|
|
23
24
|
authoritySubAccountMap?: Map<string, number[]>;
|
|
24
25
|
skipLoadUsers?: boolean;
|
|
25
26
|
txVersion?: TransactionVersion;
|
|
27
|
+
txParams?: TxParams;
|
|
26
28
|
};
|
|
27
29
|
export type DriftClientSubscriptionConfig = {
|
|
28
30
|
type: 'websocket';
|
|
@@ -30,10 +32,3 @@ export type DriftClientSubscriptionConfig = {
|
|
|
30
32
|
type: 'polling';
|
|
31
33
|
accountLoader: BulkAccountLoader;
|
|
32
34
|
};
|
|
33
|
-
type TxSenderConfig = {
|
|
34
|
-
type: 'retry';
|
|
35
|
-
timeout?: number;
|
|
36
|
-
retrySleep?: number;
|
|
37
|
-
additionalConnections?: Connection[];
|
|
38
|
-
};
|
|
39
|
-
export {};
|
package/lib/idl/drift.json
CHANGED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { PerpMarketAccount, SpotMarketAccount } from '../types';
|
|
2
|
+
export declare function getPerpMarketTierNumber(perpMarket: PerpMarketAccount): number;
|
|
3
|
+
export declare function getSpotMarketTierNumber(spotMarket: SpotMarketAccount): number;
|
|
4
|
+
export declare function perpTierIsAsSafeAs(perpTier: number, otherPerpTier: number, otherSpotTier: number): boolean;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.perpTierIsAsSafeAs = exports.getSpotMarketTierNumber = exports.getPerpMarketTierNumber = void 0;
|
|
4
|
+
const types_1 = require("../types");
|
|
5
|
+
function getPerpMarketTierNumber(perpMarket) {
|
|
6
|
+
if ((0, types_1.isVariant)(perpMarket.contractTier, 'a')) {
|
|
7
|
+
return 0;
|
|
8
|
+
}
|
|
9
|
+
else if ((0, types_1.isVariant)(perpMarket.contractTier, 'b')) {
|
|
10
|
+
return 1;
|
|
11
|
+
}
|
|
12
|
+
else if ((0, types_1.isVariant)(perpMarket.contractTier, 'c')) {
|
|
13
|
+
return 2;
|
|
14
|
+
}
|
|
15
|
+
else if ((0, types_1.isVariant)(perpMarket.contractTier, 'speculative')) {
|
|
16
|
+
return 3;
|
|
17
|
+
}
|
|
18
|
+
else if ((0, types_1.isVariant)(perpMarket.contractTier, 'isolated')) {
|
|
19
|
+
return 4;
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
return 5;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
exports.getPerpMarketTierNumber = getPerpMarketTierNumber;
|
|
26
|
+
function getSpotMarketTierNumber(spotMarket) {
|
|
27
|
+
if ((0, types_1.isVariant)(spotMarket.assetTier, 'collateral')) {
|
|
28
|
+
return 0;
|
|
29
|
+
}
|
|
30
|
+
else if ((0, types_1.isVariant)(spotMarket.assetTier, 'protected')) {
|
|
31
|
+
return 1;
|
|
32
|
+
}
|
|
33
|
+
else if ((0, types_1.isVariant)(spotMarket.assetTier, 'cross')) {
|
|
34
|
+
return 2;
|
|
35
|
+
}
|
|
36
|
+
else if ((0, types_1.isVariant)(spotMarket.assetTier, 'isolated')) {
|
|
37
|
+
return 3;
|
|
38
|
+
}
|
|
39
|
+
else if ((0, types_1.isVariant)(spotMarket.assetTier, 'unlisted')) {
|
|
40
|
+
return 4;
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
return 5;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
exports.getSpotMarketTierNumber = getSpotMarketTierNumber;
|
|
47
|
+
function perpTierIsAsSafeAs(perpTier, otherPerpTier, otherSpotTier) {
|
|
48
|
+
const asSafeAsPerp = perpTier <= otherPerpTier;
|
|
49
|
+
const asSafeAsSpot = otherSpotTier === 4 || (otherSpotTier >= 2 && perpTier <= 2);
|
|
50
|
+
return asSafeAsSpot && asSafeAsPerp;
|
|
51
|
+
}
|
|
52
|
+
exports.perpTierIsAsSafeAs = perpTierIsAsSafeAs;
|
|
@@ -1,16 +1,26 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
import { TxSender, TxSigAndSlot } from './types';
|
|
3
3
|
import { Commitment, ConfirmOptions, RpcResponseAndContext, Signer, SignatureResult, Transaction, TransactionSignature, Connection, VersionedTransaction, TransactionInstruction, AddressLookupTableAccount } from '@solana/web3.js';
|
|
4
|
-
import {
|
|
4
|
+
import { IWallet } from '../types';
|
|
5
5
|
type ResolveReference = {
|
|
6
6
|
resolve?: () => void;
|
|
7
7
|
};
|
|
8
8
|
export declare class RetryTxSender implements TxSender {
|
|
9
|
-
|
|
9
|
+
connection: Connection;
|
|
10
|
+
wallet: IWallet;
|
|
11
|
+
opts: ConfirmOptions;
|
|
10
12
|
timeout: number;
|
|
11
13
|
retrySleep: number;
|
|
12
14
|
additionalConnections: Connection[];
|
|
13
|
-
|
|
15
|
+
timoutCount: number;
|
|
16
|
+
constructor({ connection, wallet, opts, timeout, retrySleep, additionalConnections, }: {
|
|
17
|
+
connection: Connection;
|
|
18
|
+
wallet: IWallet;
|
|
19
|
+
opts?: ConfirmOptions;
|
|
20
|
+
timeout?: number;
|
|
21
|
+
retrySleep?: number;
|
|
22
|
+
additionalConnections?: any;
|
|
23
|
+
});
|
|
14
24
|
send(tx: Transaction, additionalSigners?: Array<Signer>, opts?: ConfirmOptions, preSigned?: boolean): Promise<TxSigAndSlot>;
|
|
15
25
|
prepareTx(tx: Transaction, additionalSigners: Array<Signer>, opts: ConfirmOptions): Promise<Transaction>;
|
|
16
26
|
getVersionedTransaction(ixs: TransactionInstruction[], lookupTableAccounts: AddressLookupTableAccount[], additionalSigners?: Array<Signer>, opts?: ConfirmOptions): Promise<VersionedTransaction>;
|
|
@@ -22,5 +32,6 @@ export declare class RetryTxSender implements TxSender {
|
|
|
22
32
|
promiseTimeout<T>(promises: Promise<T>[], timeoutMs: number): Promise<T | null>;
|
|
23
33
|
sendToAdditionalConnections(rawTx: Buffer | Uint8Array, opts: ConfirmOptions): void;
|
|
24
34
|
addAdditionalConnection(newConnection: Connection): void;
|
|
35
|
+
getTimeoutCount(): number;
|
|
25
36
|
}
|
|
26
37
|
export {};
|
package/lib/tx/retryTxSender.js
CHANGED
|
@@ -5,15 +5,19 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.RetryTxSender = void 0;
|
|
7
7
|
const web3_js_1 = require("@solana/web3.js");
|
|
8
|
+
const anchor_1 = require("@coral-xyz/anchor");
|
|
8
9
|
const assert_1 = __importDefault(require("assert"));
|
|
9
10
|
const bs58_1 = __importDefault(require("bs58"));
|
|
10
11
|
const DEFAULT_TIMEOUT = 35000;
|
|
11
12
|
const DEFAULT_RETRY = 8000;
|
|
12
13
|
class RetryTxSender {
|
|
13
|
-
constructor(
|
|
14
|
-
this.
|
|
15
|
-
this.
|
|
16
|
-
this.
|
|
14
|
+
constructor({ connection, wallet, opts = anchor_1.AnchorProvider.defaultOptions(), timeout = DEFAULT_TIMEOUT, retrySleep = DEFAULT_RETRY, additionalConnections = new Array(), }) {
|
|
15
|
+
this.timoutCount = 0;
|
|
16
|
+
this.connection = connection;
|
|
17
|
+
this.wallet = wallet;
|
|
18
|
+
this.opts = opts;
|
|
19
|
+
this.timeout = timeout;
|
|
20
|
+
this.retrySleep = retrySleep;
|
|
17
21
|
this.additionalConnections = additionalConnections;
|
|
18
22
|
}
|
|
19
23
|
async send(tx, additionalSigners, opts, preSigned) {
|
|
@@ -21,7 +25,7 @@ class RetryTxSender {
|
|
|
21
25
|
additionalSigners = [];
|
|
22
26
|
}
|
|
23
27
|
if (opts === undefined) {
|
|
24
|
-
opts = this.
|
|
28
|
+
opts = this.opts;
|
|
25
29
|
}
|
|
26
30
|
const signedTx = preSigned
|
|
27
31
|
? tx
|
|
@@ -29,14 +33,14 @@ class RetryTxSender {
|
|
|
29
33
|
return this.sendRawTransaction(signedTx.serialize(), opts);
|
|
30
34
|
}
|
|
31
35
|
async prepareTx(tx, additionalSigners, opts) {
|
|
32
|
-
tx.feePayer = this.
|
|
33
|
-
tx.recentBlockhash = (await this.
|
|
36
|
+
tx.feePayer = this.wallet.publicKey;
|
|
37
|
+
tx.recentBlockhash = (await this.connection.getRecentBlockhash(opts.preflightCommitment)).blockhash;
|
|
34
38
|
additionalSigners
|
|
35
39
|
.filter((s) => s !== undefined)
|
|
36
40
|
.forEach((kp) => {
|
|
37
41
|
tx.partialSign(kp);
|
|
38
42
|
});
|
|
39
|
-
const signedTx = await this.
|
|
43
|
+
const signedTx = await this.wallet.signTransaction(tx);
|
|
40
44
|
return signedTx;
|
|
41
45
|
}
|
|
42
46
|
async getVersionedTransaction(ixs, lookupTableAccounts, additionalSigners, opts) {
|
|
@@ -44,11 +48,11 @@ class RetryTxSender {
|
|
|
44
48
|
additionalSigners = [];
|
|
45
49
|
}
|
|
46
50
|
if (opts === undefined) {
|
|
47
|
-
opts = this.
|
|
51
|
+
opts = this.opts;
|
|
48
52
|
}
|
|
49
53
|
const message = new web3_js_1.TransactionMessage({
|
|
50
|
-
payerKey: this.
|
|
51
|
-
recentBlockhash: (await this.
|
|
54
|
+
payerKey: this.wallet.publicKey,
|
|
55
|
+
recentBlockhash: (await this.connection.getRecentBlockhash(opts.preflightCommitment)).blockhash,
|
|
52
56
|
instructions: ixs,
|
|
53
57
|
}).compileToV0Message(lookupTableAccounts);
|
|
54
58
|
const tx = new web3_js_1.VersionedTransaction(message);
|
|
@@ -60,9 +64,9 @@ class RetryTxSender {
|
|
|
60
64
|
signedTx = tx;
|
|
61
65
|
// @ts-ignore
|
|
62
66
|
}
|
|
63
|
-
else if (this.
|
|
67
|
+
else if (this.wallet.payer) {
|
|
64
68
|
// @ts-ignore
|
|
65
|
-
tx.sign((additionalSigners !== null && additionalSigners !== void 0 ? additionalSigners : []).concat(this.
|
|
69
|
+
tx.sign((additionalSigners !== null && additionalSigners !== void 0 ? additionalSigners : []).concat(this.wallet.payer));
|
|
66
70
|
signedTx = tx;
|
|
67
71
|
}
|
|
68
72
|
else {
|
|
@@ -70,10 +74,10 @@ class RetryTxSender {
|
|
|
70
74
|
tx.sign([kp]);
|
|
71
75
|
});
|
|
72
76
|
// @ts-ignore
|
|
73
|
-
signedTx = await this.
|
|
77
|
+
signedTx = await this.wallet.signTransaction(tx);
|
|
74
78
|
}
|
|
75
79
|
if (opts === undefined) {
|
|
76
|
-
opts = this.
|
|
80
|
+
opts = this.opts;
|
|
77
81
|
}
|
|
78
82
|
return this.sendRawTransaction(signedTx.serialize(), opts);
|
|
79
83
|
}
|
|
@@ -81,7 +85,7 @@ class RetryTxSender {
|
|
|
81
85
|
const startTime = this.getTimestamp();
|
|
82
86
|
let txid;
|
|
83
87
|
try {
|
|
84
|
-
txid = await this.
|
|
88
|
+
txid = await this.connection.sendRawTransaction(rawTransaction, opts);
|
|
85
89
|
this.sendToAdditionalConnections(rawTransaction, opts);
|
|
86
90
|
}
|
|
87
91
|
catch (e) {
|
|
@@ -102,7 +106,7 @@ class RetryTxSender {
|
|
|
102
106
|
while (!done && this.getTimestamp() - startTime < this.timeout) {
|
|
103
107
|
await this.sleep(resolveReference);
|
|
104
108
|
if (!done) {
|
|
105
|
-
this.
|
|
109
|
+
this.connection
|
|
106
110
|
.sendRawTransaction(rawTransaction, opts)
|
|
107
111
|
.catch((e) => {
|
|
108
112
|
console.error(e);
|
|
@@ -136,12 +140,9 @@ class RetryTxSender {
|
|
|
136
140
|
}
|
|
137
141
|
(0, assert_1.default)(decodedSignature.length === 64, 'signature has invalid length');
|
|
138
142
|
const start = Date.now();
|
|
139
|
-
const subscriptionCommitment = commitment || this.
|
|
143
|
+
const subscriptionCommitment = commitment || this.opts.commitment;
|
|
140
144
|
const subscriptionIds = new Array();
|
|
141
|
-
const connections = [
|
|
142
|
-
this.provider.connection,
|
|
143
|
-
...this.additionalConnections,
|
|
144
|
-
];
|
|
145
|
+
const connections = [this.connection, ...this.additionalConnections];
|
|
145
146
|
let response = null;
|
|
146
147
|
const promises = connections.map((connection, i) => {
|
|
147
148
|
let subscriptionId;
|
|
@@ -174,6 +175,7 @@ class RetryTxSender {
|
|
|
174
175
|
}
|
|
175
176
|
}
|
|
176
177
|
if (response === null) {
|
|
178
|
+
this.timoutCount += 1;
|
|
177
179
|
const duration = (Date.now() - start) / 1000;
|
|
178
180
|
throw new Error(`Transaction was not confirmed in ${duration.toFixed(2)} seconds. It is unknown if it succeeded or failed. Check signature ${signature} using the Solana Explorer or CLI tools.`);
|
|
179
181
|
}
|
|
@@ -217,5 +219,8 @@ class RetryTxSender {
|
|
|
217
219
|
this.additionalConnections.push(newConnection);
|
|
218
220
|
}
|
|
219
221
|
}
|
|
222
|
+
getTimeoutCount() {
|
|
223
|
+
return this.timoutCount;
|
|
224
|
+
}
|
|
220
225
|
}
|
|
221
226
|
exports.RetryTxSender = RetryTxSender;
|
package/lib/tx/types.d.ts
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
|
-
import { Provider } from '@coral-xyz/anchor';
|
|
3
2
|
import { AddressLookupTableAccount, ConfirmOptions, Signer, Transaction, TransactionInstruction, TransactionSignature, VersionedTransaction } from '@solana/web3.js';
|
|
3
|
+
import { IWallet } from '../types';
|
|
4
4
|
export type TxSigAndSlot = {
|
|
5
5
|
txSig: TransactionSignature;
|
|
6
6
|
slot: number;
|
|
7
7
|
};
|
|
8
8
|
export interface TxSender {
|
|
9
|
-
|
|
9
|
+
wallet: IWallet;
|
|
10
10
|
send(tx: Transaction, additionalSigners?: Array<Signer>, opts?: ConfirmOptions, preSigned?: boolean): Promise<TxSigAndSlot>;
|
|
11
11
|
sendVersionedTransaction(tx: VersionedTransaction, additionalSigners?: Array<Signer>, opts?: ConfirmOptions, preSigned?: boolean): Promise<TxSigAndSlot>;
|
|
12
12
|
getVersionedTransaction(ixs: TransactionInstruction[], lookupTableAccounts: AddressLookupTableAccount[], additionalSigners?: Array<Signer>, opts?: ConfirmOptions): Promise<VersionedTransaction>;
|
|
13
13
|
sendRawTransaction(rawTransaction: Buffer | Uint8Array, opts: ConfirmOptions): Promise<TxSigAndSlot>;
|
|
14
|
+
getTimeoutCount(): number;
|
|
14
15
|
}
|
package/lib/user.d.ts
CHANGED
|
@@ -107,6 +107,7 @@ export declare class User {
|
|
|
107
107
|
*/
|
|
108
108
|
getMaintenanceMarginRequirement(liquidationBuffer?: BN): BN;
|
|
109
109
|
getActivePerpPositions(): PerpPosition[];
|
|
110
|
+
getActiveSpotPositions(): SpotPosition[];
|
|
110
111
|
/**
|
|
111
112
|
* calculates unrealized position price pnl
|
|
112
113
|
* @returns : Precision QUOTE_PRECISION
|
|
@@ -185,7 +186,11 @@ export declare class User {
|
|
|
185
186
|
* @returns : Precision TEN_THOUSAND
|
|
186
187
|
*/
|
|
187
188
|
getMarginRatio(): BN;
|
|
188
|
-
canBeLiquidated():
|
|
189
|
+
canBeLiquidated(): {
|
|
190
|
+
canBeLiquidated: boolean;
|
|
191
|
+
marginRequirement: BN;
|
|
192
|
+
totalCollateral: BN;
|
|
193
|
+
};
|
|
189
194
|
isBeingLiquidated(): boolean;
|
|
190
195
|
isBankrupt(): boolean;
|
|
191
196
|
/**
|
|
@@ -277,6 +282,10 @@ export declare class User {
|
|
|
277
282
|
maxDepositAmount: BN;
|
|
278
283
|
};
|
|
279
284
|
canMakeIdle(slot: BN, slotsBeforeIdle: BN): boolean;
|
|
285
|
+
getSafestTiers(): {
|
|
286
|
+
perpTier: number;
|
|
287
|
+
spotTier: number;
|
|
288
|
+
};
|
|
280
289
|
/**
|
|
281
290
|
* Get the total position value, excluding any position coming from the given target market
|
|
282
291
|
* @param marketToIgnore
|