@drift-labs/sdk 2.37.1-beta.1 → 2.37.1-beta.11
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/adminClient.d.ts +1 -0
- package/lib/adminClient.js +10 -0
- package/lib/constants/perpMarkets.js +20 -0
- package/lib/idl/drift.json +73 -8
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/math/auction.js +1 -1
- package/lib/orderSubscriber/OrderSubscriber.d.ts +5 -1
- package/lib/orderSubscriber/OrderSubscriber.js +10 -0
- package/lib/orderSubscriber/types.d.ts +5 -0
- package/lib/tx/baseTxSender.d.ts +30 -0
- package/lib/tx/baseTxSender.js +176 -0
- package/lib/tx/fastSingleTxSender.d.ts +27 -0
- package/lib/tx/fastSingleTxSender.js +83 -0
- package/lib/tx/retryTxSender.d.ts +5 -14
- package/lib/tx/retryTxSender.js +7 -158
- package/lib/types.d.ts +18 -0
- package/lib/types.js +1 -0
- package/lib/user.d.ts +12 -3
- package/lib/user.js +261 -73
- package/package.json +2 -2
- package/src/adminClient.ts +18 -0
- package/src/constants/perpMarkets.ts +20 -0
- package/src/idl/drift.json +73 -8
- package/src/index.ts +1 -0
- package/src/marinade/types.ts +70 -70
- package/src/math/auction.ts +1 -1
- package/src/orderSubscriber/OrderSubscriber.ts +19 -2
- package/src/orderSubscriber/types.ts +11 -0
- package/src/tx/baseTxSender.ts +276 -0
- package/src/tx/fastSingleTxSender.ts +142 -0
- package/src/tx/retryTxSender.ts +9 -235
- package/src/types.ts +19 -0
- package/src/user.ts +455 -119
- package/tests/amm/test.ts +83 -39
- package/tests/dlob/helpers.ts +2 -0
- package/tests/dlob/test.ts +19 -17
package/lib/tx/retryTxSender.js
CHANGED
|
@@ -1,17 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
3
|
exports.RetryTxSender = void 0;
|
|
7
|
-
const web3_js_1 = require("@solana/web3.js");
|
|
8
4
|
const anchor_1 = require("@coral-xyz/anchor");
|
|
9
|
-
const
|
|
10
|
-
const bs58_1 = __importDefault(require("bs58"));
|
|
5
|
+
const baseTxSender_1 = require("./baseTxSender");
|
|
11
6
|
const DEFAULT_TIMEOUT = 35000;
|
|
12
7
|
const DEFAULT_RETRY = 8000;
|
|
13
|
-
class RetryTxSender {
|
|
8
|
+
class RetryTxSender extends baseTxSender_1.BaseTxSender {
|
|
14
9
|
constructor({ connection, wallet, opts = anchor_1.AnchorProvider.defaultOptions(), timeout = DEFAULT_TIMEOUT, retrySleep = DEFAULT_RETRY, additionalConnections = new Array(), }) {
|
|
10
|
+
super({ connection, wallet, opts, timeout, additionalConnections });
|
|
15
11
|
this.timoutCount = 0;
|
|
16
12
|
this.connection = connection;
|
|
17
13
|
this.wallet = wallet;
|
|
@@ -20,66 +16,11 @@ class RetryTxSender {
|
|
|
20
16
|
this.retrySleep = retrySleep;
|
|
21
17
|
this.additionalConnections = additionalConnections;
|
|
22
18
|
}
|
|
23
|
-
async
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
if (opts === undefined) {
|
|
28
|
-
opts = this.opts;
|
|
29
|
-
}
|
|
30
|
-
const signedTx = preSigned
|
|
31
|
-
? tx
|
|
32
|
-
: await this.prepareTx(tx, additionalSigners, opts);
|
|
33
|
-
return this.sendRawTransaction(signedTx.serialize(), opts);
|
|
34
|
-
}
|
|
35
|
-
async prepareTx(tx, additionalSigners, opts) {
|
|
36
|
-
tx.feePayer = this.wallet.publicKey;
|
|
37
|
-
tx.recentBlockhash = (await this.connection.getRecentBlockhash(opts.preflightCommitment)).blockhash;
|
|
38
|
-
additionalSigners
|
|
39
|
-
.filter((s) => s !== undefined)
|
|
40
|
-
.forEach((kp) => {
|
|
41
|
-
tx.partialSign(kp);
|
|
19
|
+
async sleep(reference) {
|
|
20
|
+
return new Promise((resolve) => {
|
|
21
|
+
reference.resolve = resolve;
|
|
22
|
+
setTimeout(resolve, this.retrySleep);
|
|
42
23
|
});
|
|
43
|
-
const signedTx = await this.wallet.signTransaction(tx);
|
|
44
|
-
return signedTx;
|
|
45
|
-
}
|
|
46
|
-
async getVersionedTransaction(ixs, lookupTableAccounts, additionalSigners, opts) {
|
|
47
|
-
if (additionalSigners === undefined) {
|
|
48
|
-
additionalSigners = [];
|
|
49
|
-
}
|
|
50
|
-
if (opts === undefined) {
|
|
51
|
-
opts = this.opts;
|
|
52
|
-
}
|
|
53
|
-
const message = new web3_js_1.TransactionMessage({
|
|
54
|
-
payerKey: this.wallet.publicKey,
|
|
55
|
-
recentBlockhash: (await this.connection.getRecentBlockhash(opts.preflightCommitment)).blockhash,
|
|
56
|
-
instructions: ixs,
|
|
57
|
-
}).compileToV0Message(lookupTableAccounts);
|
|
58
|
-
const tx = new web3_js_1.VersionedTransaction(message);
|
|
59
|
-
return tx;
|
|
60
|
-
}
|
|
61
|
-
async sendVersionedTransaction(tx, additionalSigners, opts, preSigned) {
|
|
62
|
-
let signedTx;
|
|
63
|
-
if (preSigned) {
|
|
64
|
-
signedTx = tx;
|
|
65
|
-
// @ts-ignore
|
|
66
|
-
}
|
|
67
|
-
else if (this.wallet.payer) {
|
|
68
|
-
// @ts-ignore
|
|
69
|
-
tx.sign((additionalSigners !== null && additionalSigners !== void 0 ? additionalSigners : []).concat(this.wallet.payer));
|
|
70
|
-
signedTx = tx;
|
|
71
|
-
}
|
|
72
|
-
else {
|
|
73
|
-
additionalSigners === null || additionalSigners === void 0 ? void 0 : additionalSigners.filter((s) => s !== undefined).forEach((kp) => {
|
|
74
|
-
tx.sign([kp]);
|
|
75
|
-
});
|
|
76
|
-
// @ts-ignore
|
|
77
|
-
signedTx = await this.wallet.signTransaction(tx);
|
|
78
|
-
}
|
|
79
|
-
if (opts === undefined) {
|
|
80
|
-
opts = this.opts;
|
|
81
|
-
}
|
|
82
|
-
return this.sendRawTransaction(signedTx.serialize(), opts);
|
|
83
24
|
}
|
|
84
25
|
async sendRawTransaction(rawTransaction, opts) {
|
|
85
26
|
const startTime = this.getTimestamp();
|
|
@@ -130,97 +71,5 @@ class RetryTxSender {
|
|
|
130
71
|
}
|
|
131
72
|
return { txSig: txid, slot };
|
|
132
73
|
}
|
|
133
|
-
async confirmTransaction(signature, commitment) {
|
|
134
|
-
let decodedSignature;
|
|
135
|
-
try {
|
|
136
|
-
decodedSignature = bs58_1.default.decode(signature);
|
|
137
|
-
}
|
|
138
|
-
catch (err) {
|
|
139
|
-
throw new Error('signature must be base58 encoded: ' + signature);
|
|
140
|
-
}
|
|
141
|
-
(0, assert_1.default)(decodedSignature.length === 64, 'signature has invalid length');
|
|
142
|
-
const start = Date.now();
|
|
143
|
-
const subscriptionCommitment = commitment || this.opts.commitment;
|
|
144
|
-
const subscriptionIds = new Array();
|
|
145
|
-
const connections = [this.connection, ...this.additionalConnections];
|
|
146
|
-
let response = null;
|
|
147
|
-
const promises = connections.map((connection, i) => {
|
|
148
|
-
let subscriptionId;
|
|
149
|
-
const confirmPromise = new Promise((resolve, reject) => {
|
|
150
|
-
try {
|
|
151
|
-
subscriptionId = connection.onSignature(signature, (result, context) => {
|
|
152
|
-
subscriptionIds[i] = undefined;
|
|
153
|
-
response = {
|
|
154
|
-
context,
|
|
155
|
-
value: result,
|
|
156
|
-
};
|
|
157
|
-
resolve(null);
|
|
158
|
-
}, subscriptionCommitment);
|
|
159
|
-
}
|
|
160
|
-
catch (err) {
|
|
161
|
-
reject(err);
|
|
162
|
-
}
|
|
163
|
-
});
|
|
164
|
-
subscriptionIds.push(subscriptionId);
|
|
165
|
-
return confirmPromise;
|
|
166
|
-
});
|
|
167
|
-
try {
|
|
168
|
-
await this.promiseTimeout(promises, this.timeout);
|
|
169
|
-
}
|
|
170
|
-
finally {
|
|
171
|
-
for (const [i, subscriptionId] of subscriptionIds.entries()) {
|
|
172
|
-
if (subscriptionId) {
|
|
173
|
-
connections[i].removeSignatureListener(subscriptionId);
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
if (response === null) {
|
|
178
|
-
this.timoutCount += 1;
|
|
179
|
-
const duration = (Date.now() - start) / 1000;
|
|
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.`);
|
|
181
|
-
}
|
|
182
|
-
return response;
|
|
183
|
-
}
|
|
184
|
-
getTimestamp() {
|
|
185
|
-
return new Date().getTime();
|
|
186
|
-
}
|
|
187
|
-
async sleep(reference) {
|
|
188
|
-
return new Promise((resolve) => {
|
|
189
|
-
reference.resolve = resolve;
|
|
190
|
-
setTimeout(resolve, this.retrySleep);
|
|
191
|
-
});
|
|
192
|
-
}
|
|
193
|
-
promiseTimeout(promises, timeoutMs) {
|
|
194
|
-
let timeoutId;
|
|
195
|
-
const timeoutPromise = new Promise((resolve) => {
|
|
196
|
-
timeoutId = setTimeout(() => resolve(null), timeoutMs);
|
|
197
|
-
});
|
|
198
|
-
return Promise.race([...promises, timeoutPromise]).then((result) => {
|
|
199
|
-
clearTimeout(timeoutId);
|
|
200
|
-
return result;
|
|
201
|
-
});
|
|
202
|
-
}
|
|
203
|
-
sendToAdditionalConnections(rawTx, opts) {
|
|
204
|
-
this.additionalConnections.map((connection) => {
|
|
205
|
-
connection.sendRawTransaction(rawTx, opts).catch((e) => {
|
|
206
|
-
console.error(
|
|
207
|
-
// @ts-ignore
|
|
208
|
-
`error sending tx to additional connection ${connection._rpcEndpoint}`);
|
|
209
|
-
console.error(e);
|
|
210
|
-
});
|
|
211
|
-
});
|
|
212
|
-
}
|
|
213
|
-
addAdditionalConnection(newConnection) {
|
|
214
|
-
const alreadyUsingConnection = this.additionalConnections.filter((connection) => {
|
|
215
|
-
// @ts-ignore
|
|
216
|
-
return connection._rpcEndpoint === newConnection.rpcEndpoint;
|
|
217
|
-
}).length > 0;
|
|
218
|
-
if (!alreadyUsingConnection) {
|
|
219
|
-
this.additionalConnections.push(newConnection);
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
getTimeoutCount() {
|
|
223
|
-
return this.timoutCount;
|
|
224
|
-
}
|
|
225
74
|
}
|
|
226
75
|
exports.RetryTxSender = RetryTxSender;
|
package/lib/types.d.ts
CHANGED
|
@@ -50,6 +50,9 @@ export declare class UserStatus {
|
|
|
50
50
|
static readonly BANKRUPT: {
|
|
51
51
|
bankrupt: {};
|
|
52
52
|
};
|
|
53
|
+
static readonly REDUCE_ONLY: {
|
|
54
|
+
reduceOnly: {};
|
|
55
|
+
};
|
|
53
56
|
}
|
|
54
57
|
export declare class ContractType {
|
|
55
58
|
static readonly PERPETUAL: {
|
|
@@ -818,6 +821,7 @@ export type AMM = {
|
|
|
818
821
|
bidQuoteAssetReserve: BN;
|
|
819
822
|
askBaseAssetReserve: BN;
|
|
820
823
|
askQuoteAssetReserve: BN;
|
|
824
|
+
perLpBase: number;
|
|
821
825
|
};
|
|
822
826
|
export type PerpPosition = {
|
|
823
827
|
baseAssetAmount: BN;
|
|
@@ -834,6 +838,7 @@ export type PerpPosition = {
|
|
|
834
838
|
remainderBaseAssetAmount: number;
|
|
835
839
|
lastBaseAssetAmountPerLp: BN;
|
|
836
840
|
lastQuoteAssetAmountPerLp: BN;
|
|
841
|
+
perLpBase: number;
|
|
837
842
|
};
|
|
838
843
|
export type UserStatsAccount = {
|
|
839
844
|
numberOfSubAccounts: number;
|
|
@@ -1114,3 +1119,16 @@ export type PerpMarketExtendedInfo = {
|
|
|
1114
1119
|
pnlPoolValue: BN;
|
|
1115
1120
|
contractTier: ContractTier;
|
|
1116
1121
|
};
|
|
1122
|
+
export type HealthComponents = {
|
|
1123
|
+
deposits: HealthComponent[];
|
|
1124
|
+
borrows: HealthComponent[];
|
|
1125
|
+
perpPositions: HealthComponent[];
|
|
1126
|
+
perpPnl: HealthComponent[];
|
|
1127
|
+
};
|
|
1128
|
+
export type HealthComponent = {
|
|
1129
|
+
marketIndex: number;
|
|
1130
|
+
size: BN;
|
|
1131
|
+
value: BN;
|
|
1132
|
+
weight: BN;
|
|
1133
|
+
weightedValue: BN;
|
|
1134
|
+
};
|
package/lib/types.js
CHANGED
|
@@ -33,6 +33,7 @@ exports.UserStatus = UserStatus;
|
|
|
33
33
|
UserStatus.ACTIVE = { active: {} };
|
|
34
34
|
UserStatus.BEING_LIQUIDATED = { beingLiquidated: {} };
|
|
35
35
|
UserStatus.BANKRUPT = { bankrupt: {} };
|
|
36
|
+
UserStatus.REDUCE_ONLY = { reduceOnly: {} };
|
|
36
37
|
class ContractType {
|
|
37
38
|
}
|
|
38
39
|
exports.ContractType = ContractType;
|
package/lib/user.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { PublicKey } from '@solana/web3.js';
|
|
|
3
3
|
import { EventEmitter } from 'events';
|
|
4
4
|
import StrictEventEmitter from 'strict-event-emitter-types';
|
|
5
5
|
import { DriftClient } from './driftClient';
|
|
6
|
-
import { MarginCategory, Order, UserAccount, PerpPosition, SpotPosition, PerpMarketAccount } from './types';
|
|
6
|
+
import { MarginCategory, Order, UserAccount, PerpPosition, SpotPosition, PerpMarketAccount, HealthComponents } from './types';
|
|
7
7
|
import { UserAccountSubscriber, UserAccountEvents, DataAndSlot } from './accounts/types';
|
|
8
8
|
import { PositionDirection, BN, SpotMarketAccount, MarketType } from '.';
|
|
9
9
|
import { OraclePriceData } from './oracles/types';
|
|
@@ -101,10 +101,10 @@ export declare class User {
|
|
|
101
101
|
getPerpBuyingPower(marketIndex: number, collateralBuffer?: any): BN;
|
|
102
102
|
getPerpBuyingPowerFromFreeCollateralAndBaseAssetAmount(marketIndex: number, freeCollateral: BN, baseAssetAmount: BN): BN;
|
|
103
103
|
/**
|
|
104
|
-
* calculates Free Collateral = Total collateral -
|
|
104
|
+
* calculates Free Collateral = Total collateral - margin requirement
|
|
105
105
|
* @returns : Precision QUOTE_PRECISION
|
|
106
106
|
*/
|
|
107
|
-
getFreeCollateral(): BN;
|
|
107
|
+
getFreeCollateral(marginCategory?: MarginCategory): BN;
|
|
108
108
|
/**
|
|
109
109
|
* @returns The margin requirement of a certain type (Initial or Maintenance) in USDC. : QUOTE_PRECISION
|
|
110
110
|
*/
|
|
@@ -153,6 +153,12 @@ export declare class User {
|
|
|
153
153
|
* @returns : number (value from [0, 100])
|
|
154
154
|
*/
|
|
155
155
|
getHealth(): number;
|
|
156
|
+
calculateWeightedPerpPositionValue(perpPosition: PerpPosition, marginCategory?: MarginCategory, liquidationBuffer?: BN, includeOpenOrders?: boolean, strict?: boolean): BN;
|
|
157
|
+
/**
|
|
158
|
+
* calculates position value of a single perp market in margin system
|
|
159
|
+
* @returns : Precision QUOTE_PRECISION
|
|
160
|
+
*/
|
|
161
|
+
getPerpMarketLiabilityValue(marketIndex: number, marginCategory?: MarginCategory, liquidationBuffer?: BN, includeOpenOrders?: boolean, strict?: boolean): BN;
|
|
156
162
|
/**
|
|
157
163
|
* calculates sum of position value across all positions in margin system
|
|
158
164
|
* @returns : Precision QUOTE_PRECISION
|
|
@@ -352,6 +358,9 @@ export declare class User {
|
|
|
352
358
|
perpTier: number;
|
|
353
359
|
spotTier: number;
|
|
354
360
|
};
|
|
361
|
+
getHealthComponents({ marginCategory, }: {
|
|
362
|
+
marginCategory: MarginCategory;
|
|
363
|
+
}): HealthComponents;
|
|
355
364
|
/**
|
|
356
365
|
* Get the total position value, excluding any position coming from the given target market
|
|
357
366
|
* @param marketToIgnore
|