@drift-labs/sdk 2.74.0-beta.1 → 2.74.0-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 +12 -3
- package/lib/adminClient.js +60 -32
- package/lib/blockhashSubscriber/BlockhashSubscriber.d.ts +21 -0
- package/lib/blockhashSubscriber/BlockhashSubscriber.js +73 -0
- package/lib/blockhashSubscriber/index.d.ts +1 -0
- package/lib/blockhashSubscriber/index.js +17 -0
- package/lib/blockhashSubscriber/types.d.ts +7 -0
- package/lib/blockhashSubscriber/types.js +2 -0
- package/lib/dlob/orderBookLevels.js +47 -12
- package/lib/driftClient.d.ts +5 -0
- package/lib/driftClient.js +17 -0
- package/lib/events/parse.d.ts +1 -1
- package/lib/events/parse.js +12 -12
- package/lib/idl/drift.json +85 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/math/funding.js +0 -6
- package/lib/math/oracles.js +1 -1
- package/lib/math/tiers.js +1 -1
- package/lib/oracles/prelaunchOracleClient.js +1 -0
- package/lib/oracles/types.d.ts +1 -0
- package/lib/tx/baseTxSender.d.ts +1 -1
- package/lib/tx/baseTxSender.js +9 -2
- package/lib/tx/fastSingleTxSender.d.ts +1 -1
- package/lib/tx/fastSingleTxSender.js +11 -3
- package/lib/tx/types.d.ts +1 -1
- package/lib/types.d.ts +3 -0
- package/lib/types.js +1 -0
- package/lib/user.d.ts +6 -4
- package/lib/user.js +24 -21
- package/package.json +1 -1
- package/src/adminClient.ts +297 -87
- package/src/blockhashSubscriber/BlockhashSubscriber.ts +108 -0
- package/src/blockhashSubscriber/index.ts +1 -0
- package/src/blockhashSubscriber/types.ts +8 -0
- package/src/dlob/orderBookLevels.ts +51 -15
- package/src/driftClient.ts +37 -0
- package/src/events/parse.ts +26 -12
- package/src/idl/drift.json +85 -0
- package/src/index.ts +1 -0
- package/src/math/funding.ts +0 -4
- package/src/math/oracles.ts +1 -1
- package/src/math/tiers.ts +1 -1
- package/src/oracles/prelaunchOracleClient.ts +1 -0
- package/src/oracles/types.ts +1 -0
- package/src/tx/baseTxSender.ts +12 -4
- package/src/tx/fastSingleTxSender.ts +13 -5
- package/src/tx/types.ts +2 -1
- package/src/types.ts +1 -0
- package/src/user.ts +32 -30
- package/tests/amm/test.ts +3 -1
- package/tests/dlob/test.ts +57 -0
package/src/adminClient.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
PublicKey,
|
|
3
3
|
SYSVAR_RENT_PUBKEY,
|
|
4
|
+
TransactionInstruction,
|
|
4
5
|
TransactionSignature,
|
|
5
6
|
} from '@solana/web3.js';
|
|
6
7
|
import {
|
|
@@ -31,7 +32,13 @@ import {
|
|
|
31
32
|
import { squareRootBN } from './math/utils';
|
|
32
33
|
import { TOKEN_PROGRAM_ID } from '@solana/spl-token';
|
|
33
34
|
import { DriftClient } from './driftClient';
|
|
34
|
-
import {
|
|
35
|
+
import {
|
|
36
|
+
PEG_PRECISION,
|
|
37
|
+
ZERO,
|
|
38
|
+
ONE,
|
|
39
|
+
BASE_PRECISION,
|
|
40
|
+
PRICE_PRECISION,
|
|
41
|
+
} from './constants/numericConstants';
|
|
35
42
|
import { calculateTargetPriceTrade } from './math/trade';
|
|
36
43
|
import { calculateAmmReservesAfterSwap, getSwapDirection } from './math/amm';
|
|
37
44
|
import { PROGRAM_ID as PHOENIX_PROGRAM_ID } from '@ellipsis-labs/phoenix-sdk';
|
|
@@ -84,10 +91,84 @@ export class AdminClient extends DriftClient {
|
|
|
84
91
|
maintenanceLiabilityWeight: number,
|
|
85
92
|
imfFactor = 0,
|
|
86
93
|
liquidatorFee = 0,
|
|
94
|
+
ifLiquidationFee = 0,
|
|
87
95
|
activeStatus = true,
|
|
96
|
+
assetTier = AssetTier.COLLATERAL,
|
|
97
|
+
scaleInitialAssetWeightStart = ZERO,
|
|
98
|
+
withdrawGuardThreshold = ZERO,
|
|
99
|
+
orderTickSize = ONE,
|
|
100
|
+
orderStepSize = ONE,
|
|
101
|
+
ifTotalFactor = 0,
|
|
88
102
|
name = DEFAULT_MARKET_NAME
|
|
89
103
|
): Promise<TransactionSignature> {
|
|
90
104
|
const spotMarketIndex = this.getStateAccount().numberOfSpotMarkets;
|
|
105
|
+
|
|
106
|
+
const initializeIx = await this.getInitializeSpotMarketIx(
|
|
107
|
+
this.wallet.publicKey,
|
|
108
|
+
mint,
|
|
109
|
+
optimalUtilization,
|
|
110
|
+
optimalRate,
|
|
111
|
+
maxRate,
|
|
112
|
+
oracle,
|
|
113
|
+
oracleSource,
|
|
114
|
+
initialAssetWeight,
|
|
115
|
+
maintenanceAssetWeight,
|
|
116
|
+
initialLiabilityWeight,
|
|
117
|
+
maintenanceLiabilityWeight,
|
|
118
|
+
imfFactor,
|
|
119
|
+
liquidatorFee,
|
|
120
|
+
ifLiquidationFee,
|
|
121
|
+
activeStatus,
|
|
122
|
+
assetTier,
|
|
123
|
+
scaleInitialAssetWeightStart,
|
|
124
|
+
withdrawGuardThreshold,
|
|
125
|
+
orderTickSize,
|
|
126
|
+
orderStepSize,
|
|
127
|
+
ifTotalFactor,
|
|
128
|
+
name
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
const tx = await this.buildTransaction(initializeIx);
|
|
132
|
+
|
|
133
|
+
const { txSig } = await this.sendTransaction(tx, [], this.opts);
|
|
134
|
+
|
|
135
|
+
// const { txSig } = await this.sendTransaction(initializeTx, [], this.opts);
|
|
136
|
+
|
|
137
|
+
await this.accountSubscriber.addSpotMarket(spotMarketIndex);
|
|
138
|
+
await this.accountSubscriber.addOracle({
|
|
139
|
+
source: oracleSource,
|
|
140
|
+
publicKey: oracle,
|
|
141
|
+
});
|
|
142
|
+
await this.accountSubscriber.setSpotOracleMap();
|
|
143
|
+
|
|
144
|
+
return txSig;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
public async getInitializeSpotMarketIx(
|
|
148
|
+
admin: PublicKey,
|
|
149
|
+
mint: PublicKey,
|
|
150
|
+
optimalUtilization: number,
|
|
151
|
+
optimalRate: number,
|
|
152
|
+
maxRate: number,
|
|
153
|
+
oracle: PublicKey,
|
|
154
|
+
oracleSource: OracleSource,
|
|
155
|
+
initialAssetWeight: number,
|
|
156
|
+
maintenanceAssetWeight: number,
|
|
157
|
+
initialLiabilityWeight: number,
|
|
158
|
+
maintenanceLiabilityWeight: number,
|
|
159
|
+
imfFactor = 0,
|
|
160
|
+
liquidatorFee = 0,
|
|
161
|
+
ifLiquidationFee = 0,
|
|
162
|
+
activeStatus = true,
|
|
163
|
+
assetTier = AssetTier.COLLATERAL,
|
|
164
|
+
scaleInitialAssetWeightStart = ZERO,
|
|
165
|
+
withdrawGuardThreshold = ZERO,
|
|
166
|
+
orderTickSize = ONE,
|
|
167
|
+
orderStepSize = ONE,
|
|
168
|
+
ifTotalFactor = 0,
|
|
169
|
+
name = DEFAULT_MARKET_NAME
|
|
170
|
+
): Promise<TransactionInstruction> {
|
|
171
|
+
const spotMarketIndex = this.getStateAccount().numberOfSpotMarkets;
|
|
91
172
|
const spotMarket = await getSpotMarketPublicKey(
|
|
92
173
|
this.program.programId,
|
|
93
174
|
spotMarketIndex
|
|
@@ -115,11 +196,18 @@ export class AdminClient extends DriftClient {
|
|
|
115
196
|
maintenanceLiabilityWeight,
|
|
116
197
|
imfFactor,
|
|
117
198
|
liquidatorFee,
|
|
199
|
+
ifLiquidationFee,
|
|
118
200
|
activeStatus,
|
|
201
|
+
assetTier,
|
|
202
|
+
scaleInitialAssetWeightStart,
|
|
203
|
+
withdrawGuardThreshold,
|
|
204
|
+
orderTickSize,
|
|
205
|
+
orderStepSize,
|
|
206
|
+
ifTotalFactor,
|
|
119
207
|
nameBuffer,
|
|
120
208
|
{
|
|
121
209
|
accounts: {
|
|
122
|
-
admin
|
|
210
|
+
admin,
|
|
123
211
|
state: await this.getStatePublicKey(),
|
|
124
212
|
spotMarket,
|
|
125
213
|
spotMarketVault,
|
|
@@ -134,27 +222,34 @@ export class AdminClient extends DriftClient {
|
|
|
134
222
|
}
|
|
135
223
|
);
|
|
136
224
|
|
|
137
|
-
|
|
225
|
+
return initializeIx;
|
|
226
|
+
}
|
|
138
227
|
|
|
139
|
-
|
|
228
|
+
public async initializeSerumFulfillmentConfig(
|
|
229
|
+
marketIndex: number,
|
|
230
|
+
serumMarket: PublicKey,
|
|
231
|
+
serumProgram: PublicKey
|
|
232
|
+
): Promise<TransactionSignature> {
|
|
233
|
+
const initializeIx = await this.getInitializeSerumFulfillmentConfigIx(
|
|
234
|
+
this.wallet.publicKey,
|
|
235
|
+
marketIndex,
|
|
236
|
+
serumMarket,
|
|
237
|
+
serumProgram
|
|
238
|
+
);
|
|
140
239
|
|
|
141
|
-
|
|
240
|
+
const tx = await this.buildTransaction(initializeIx);
|
|
142
241
|
|
|
143
|
-
await this.
|
|
144
|
-
await this.accountSubscriber.addOracle({
|
|
145
|
-
source: oracleSource,
|
|
146
|
-
publicKey: oracle,
|
|
147
|
-
});
|
|
148
|
-
await this.accountSubscriber.setSpotOracleMap();
|
|
242
|
+
const { txSig } = await this.sendTransaction(tx, [], this.opts);
|
|
149
243
|
|
|
150
244
|
return txSig;
|
|
151
245
|
}
|
|
152
246
|
|
|
153
|
-
public async
|
|
247
|
+
public async getInitializeSerumFulfillmentConfigIx(
|
|
248
|
+
admin: PublicKey,
|
|
154
249
|
marketIndex: number,
|
|
155
250
|
serumMarket: PublicKey,
|
|
156
251
|
serumProgram: PublicKey
|
|
157
|
-
): Promise<
|
|
252
|
+
): Promise<TransactionInstruction> {
|
|
158
253
|
const serumOpenOrders = getSerumOpenOrdersPublicKey(
|
|
159
254
|
this.program.programId,
|
|
160
255
|
serumMarket
|
|
@@ -165,25 +260,35 @@ export class AdminClient extends DriftClient {
|
|
|
165
260
|
serumMarket
|
|
166
261
|
);
|
|
167
262
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
{
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
263
|
+
return await this.program.instruction.initializeSerumFulfillmentConfig(
|
|
264
|
+
marketIndex,
|
|
265
|
+
{
|
|
266
|
+
accounts: {
|
|
267
|
+
admin,
|
|
268
|
+
state: await this.getStatePublicKey(),
|
|
269
|
+
baseSpotMarket: this.getSpotMarketAccount(marketIndex).pubkey,
|
|
270
|
+
quoteSpotMarket: this.getQuoteSpotMarketAccount().pubkey,
|
|
271
|
+
driftSigner: this.getSignerPublicKey(),
|
|
272
|
+
serumProgram,
|
|
273
|
+
serumMarket,
|
|
274
|
+
serumOpenOrders,
|
|
275
|
+
rent: SYSVAR_RENT_PUBKEY,
|
|
276
|
+
systemProgram: anchor.web3.SystemProgram.programId,
|
|
277
|
+
serumFulfillmentConfig,
|
|
278
|
+
},
|
|
279
|
+
}
|
|
280
|
+
);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
public async initializePhoenixFulfillmentConfig(
|
|
284
|
+
marketIndex: number,
|
|
285
|
+
phoenixMarket: PublicKey
|
|
286
|
+
): Promise<TransactionSignature> {
|
|
287
|
+
const initializeIx = await this.getInitializePhoenixFulfillmentConfigIx(
|
|
288
|
+
this.wallet.publicKey,
|
|
289
|
+
marketIndex,
|
|
290
|
+
phoenixMarket
|
|
291
|
+
);
|
|
187
292
|
|
|
188
293
|
const tx = await this.buildTransaction(initializeIx);
|
|
189
294
|
|
|
@@ -192,39 +297,33 @@ export class AdminClient extends DriftClient {
|
|
|
192
297
|
return txSig;
|
|
193
298
|
}
|
|
194
299
|
|
|
195
|
-
public async
|
|
300
|
+
public async getInitializePhoenixFulfillmentConfigIx(
|
|
301
|
+
admin: PublicKey,
|
|
196
302
|
marketIndex: number,
|
|
197
303
|
phoenixMarket: PublicKey
|
|
198
|
-
): Promise<
|
|
304
|
+
): Promise<TransactionInstruction> {
|
|
199
305
|
const phoenixFulfillmentConfig = getPhoenixFulfillmentConfigPublicKey(
|
|
200
306
|
this.program.programId,
|
|
201
307
|
phoenixMarket
|
|
202
308
|
);
|
|
203
309
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
{
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
);
|
|
222
|
-
|
|
223
|
-
const tx = await this.buildTransaction(initializeIx);
|
|
224
|
-
|
|
225
|
-
const { txSig } = await this.sendTransaction(tx, [], this.opts);
|
|
226
|
-
|
|
227
|
-
return txSig;
|
|
310
|
+
return await this.program.instruction.initializePhoenixFulfillmentConfig(
|
|
311
|
+
marketIndex,
|
|
312
|
+
{
|
|
313
|
+
accounts: {
|
|
314
|
+
admin,
|
|
315
|
+
state: await this.getStatePublicKey(),
|
|
316
|
+
baseSpotMarket: this.getSpotMarketAccount(marketIndex).pubkey,
|
|
317
|
+
quoteSpotMarket: this.getQuoteSpotMarketAccount().pubkey,
|
|
318
|
+
driftSigner: this.getSignerPublicKey(),
|
|
319
|
+
phoenixMarket: phoenixMarket,
|
|
320
|
+
phoenixProgram: PHOENIX_PROGRAM_ID,
|
|
321
|
+
rent: SYSVAR_RENT_PUBKEY,
|
|
322
|
+
systemProgram: anchor.web3.SystemProgram.programId,
|
|
323
|
+
phoenixFulfillmentConfig,
|
|
324
|
+
},
|
|
325
|
+
}
|
|
326
|
+
);
|
|
228
327
|
}
|
|
229
328
|
|
|
230
329
|
public async initializePerpMarket(
|
|
@@ -238,40 +337,52 @@ export class AdminClient extends DriftClient {
|
|
|
238
337
|
marginRatioInitial = 2000,
|
|
239
338
|
marginRatioMaintenance = 500,
|
|
240
339
|
liquidatorFee = 0,
|
|
340
|
+
ifLiquidatorFee = 10000,
|
|
341
|
+
imfFactor = 0,
|
|
241
342
|
activeStatus = true,
|
|
343
|
+
baseSpread = 0,
|
|
344
|
+
maxSpread = 142500,
|
|
345
|
+
maxOpenInterest = ZERO,
|
|
346
|
+
maxRevenueWithdrawPerPeriod = ZERO,
|
|
347
|
+
quoteMaxInsurance = ZERO,
|
|
348
|
+
orderStepSize = BASE_PRECISION.divn(10000),
|
|
349
|
+
orderTickSize = PRICE_PRECISION.divn(100000),
|
|
350
|
+
minOrderSize = BASE_PRECISION.divn(10000),
|
|
351
|
+
concentrationCoefScale = ONE,
|
|
352
|
+
curveUpdateIntensity = 0,
|
|
353
|
+
ammJitIntensity = 0,
|
|
242
354
|
name = DEFAULT_MARKET_NAME
|
|
243
355
|
): Promise<TransactionSignature> {
|
|
244
356
|
const currentPerpMarketIndex = this.getStateAccount().numberOfMarkets;
|
|
245
|
-
const perpMarketPublicKey = await getPerpMarketPublicKey(
|
|
246
|
-
this.program.programId,
|
|
247
|
-
currentPerpMarketIndex
|
|
248
|
-
);
|
|
249
357
|
|
|
250
|
-
const
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
358
|
+
const initializeMarketIx = await this.getInitializePerpMarketIx(
|
|
359
|
+
this.wallet.publicKey,
|
|
360
|
+
marketIndex,
|
|
361
|
+
priceOracle,
|
|
362
|
+
baseAssetReserve,
|
|
363
|
+
quoteAssetReserve,
|
|
364
|
+
periodicity,
|
|
365
|
+
pegMultiplier,
|
|
366
|
+
oracleSource,
|
|
367
|
+
marginRatioInitial,
|
|
368
|
+
marginRatioMaintenance,
|
|
369
|
+
liquidatorFee,
|
|
370
|
+
ifLiquidatorFee,
|
|
371
|
+
imfFactor,
|
|
372
|
+
activeStatus,
|
|
373
|
+
baseSpread,
|
|
374
|
+
maxSpread,
|
|
375
|
+
maxOpenInterest,
|
|
376
|
+
maxRevenueWithdrawPerPeriod,
|
|
377
|
+
quoteMaxInsurance,
|
|
378
|
+
orderStepSize,
|
|
379
|
+
orderTickSize,
|
|
380
|
+
minOrderSize,
|
|
381
|
+
concentrationCoefScale,
|
|
382
|
+
curveUpdateIntensity,
|
|
383
|
+
ammJitIntensity,
|
|
384
|
+
name
|
|
385
|
+
);
|
|
275
386
|
const tx = await this.buildTransaction(initializeMarketIx);
|
|
276
387
|
|
|
277
388
|
const { txSig } = await this.sendTransaction(tx, [], this.opts);
|
|
@@ -290,6 +401,79 @@ export class AdminClient extends DriftClient {
|
|
|
290
401
|
return txSig;
|
|
291
402
|
}
|
|
292
403
|
|
|
404
|
+
public async getInitializePerpMarketIx(
|
|
405
|
+
admin: PublicKey,
|
|
406
|
+
marketIndex: number,
|
|
407
|
+
priceOracle: PublicKey,
|
|
408
|
+
baseAssetReserve: BN,
|
|
409
|
+
quoteAssetReserve: BN,
|
|
410
|
+
periodicity: BN,
|
|
411
|
+
pegMultiplier: BN = PEG_PRECISION,
|
|
412
|
+
oracleSource: OracleSource = OracleSource.PYTH,
|
|
413
|
+
marginRatioInitial = 2000,
|
|
414
|
+
marginRatioMaintenance = 500,
|
|
415
|
+
liquidatorFee = 0,
|
|
416
|
+
ifLiquidatorFee = 10000,
|
|
417
|
+
imfFactor = 0,
|
|
418
|
+
activeStatus = true,
|
|
419
|
+
baseSpread = 0,
|
|
420
|
+
maxSpread = 142500,
|
|
421
|
+
maxOpenInterest = ZERO,
|
|
422
|
+
maxRevenueWithdrawPerPeriod = ZERO,
|
|
423
|
+
quoteMaxInsurance = ZERO,
|
|
424
|
+
orderStepSize = BASE_PRECISION.divn(10000),
|
|
425
|
+
orderTickSize = PRICE_PRECISION.divn(100000),
|
|
426
|
+
minOrderSize = BASE_PRECISION.divn(10000),
|
|
427
|
+
concentrationCoefScale = ONE,
|
|
428
|
+
curveUpdateIntensity = 0,
|
|
429
|
+
ammJitIntensity = 0,
|
|
430
|
+
name = DEFAULT_MARKET_NAME
|
|
431
|
+
): Promise<TransactionInstruction> {
|
|
432
|
+
const currentPerpMarketIndex = this.getStateAccount().numberOfMarkets;
|
|
433
|
+
const perpMarketPublicKey = await getPerpMarketPublicKey(
|
|
434
|
+
this.program.programId,
|
|
435
|
+
currentPerpMarketIndex
|
|
436
|
+
);
|
|
437
|
+
|
|
438
|
+
const nameBuffer = encodeName(name);
|
|
439
|
+
return await this.program.instruction.initializePerpMarket(
|
|
440
|
+
marketIndex,
|
|
441
|
+
baseAssetReserve,
|
|
442
|
+
quoteAssetReserve,
|
|
443
|
+
periodicity,
|
|
444
|
+
pegMultiplier,
|
|
445
|
+
oracleSource,
|
|
446
|
+
marginRatioInitial,
|
|
447
|
+
marginRatioMaintenance,
|
|
448
|
+
liquidatorFee,
|
|
449
|
+
ifLiquidatorFee,
|
|
450
|
+
imfFactor,
|
|
451
|
+
activeStatus,
|
|
452
|
+
baseSpread,
|
|
453
|
+
maxSpread,
|
|
454
|
+
maxOpenInterest,
|
|
455
|
+
maxRevenueWithdrawPerPeriod,
|
|
456
|
+
quoteMaxInsurance,
|
|
457
|
+
orderStepSize,
|
|
458
|
+
orderTickSize,
|
|
459
|
+
minOrderSize,
|
|
460
|
+
concentrationCoefScale,
|
|
461
|
+
curveUpdateIntensity,
|
|
462
|
+
ammJitIntensity,
|
|
463
|
+
nameBuffer,
|
|
464
|
+
{
|
|
465
|
+
accounts: {
|
|
466
|
+
state: await this.getStatePublicKey(),
|
|
467
|
+
admin,
|
|
468
|
+
oracle: priceOracle,
|
|
469
|
+
perpMarket: perpMarketPublicKey,
|
|
470
|
+
rent: SYSVAR_RENT_PUBKEY,
|
|
471
|
+
systemProgram: anchor.web3.SystemProgram.programId,
|
|
472
|
+
},
|
|
473
|
+
}
|
|
474
|
+
);
|
|
475
|
+
}
|
|
476
|
+
|
|
293
477
|
public async deleteInitializedPerpMarket(
|
|
294
478
|
marketIndex: number
|
|
295
479
|
): Promise<TransactionSignature> {
|
|
@@ -2172,4 +2356,30 @@ export class AdminClient extends DriftClient {
|
|
|
2172
2356
|
|
|
2173
2357
|
return txSig;
|
|
2174
2358
|
}
|
|
2359
|
+
|
|
2360
|
+
public async deletePrelaunchOracle(
|
|
2361
|
+
perpMarketIndex: number
|
|
2362
|
+
): Promise<TransactionSignature> {
|
|
2363
|
+
const deletePrelaunchOracleIx =
|
|
2364
|
+
await this.program.instruction.deletePrelaunchOracle(perpMarketIndex, {
|
|
2365
|
+
accounts: {
|
|
2366
|
+
admin: this.wallet.publicKey,
|
|
2367
|
+
state: await this.getStatePublicKey(),
|
|
2368
|
+
prelaunchOracle: await getPrelaunchOraclePublicKey(
|
|
2369
|
+
this.program.programId,
|
|
2370
|
+
perpMarketIndex
|
|
2371
|
+
),
|
|
2372
|
+
perpMarket: await getPerpMarketPublicKey(
|
|
2373
|
+
this.program.programId,
|
|
2374
|
+
perpMarketIndex
|
|
2375
|
+
),
|
|
2376
|
+
},
|
|
2377
|
+
});
|
|
2378
|
+
|
|
2379
|
+
const tx = await this.buildTransaction(deletePrelaunchOracleIx);
|
|
2380
|
+
|
|
2381
|
+
const { txSig } = await this.sendTransaction(tx, [], this.opts);
|
|
2382
|
+
|
|
2383
|
+
return txSig;
|
|
2384
|
+
}
|
|
2175
2385
|
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import {
|
|
2
|
+
BlockhashWithExpiryBlockHeight,
|
|
3
|
+
Commitment,
|
|
4
|
+
Connection,
|
|
5
|
+
Context,
|
|
6
|
+
} from '@solana/web3.js';
|
|
7
|
+
import { BlockhashSubscriberConfig } from './types';
|
|
8
|
+
|
|
9
|
+
export class BlockhashSubscriber {
|
|
10
|
+
private connection: Connection;
|
|
11
|
+
private isSubscribed = false;
|
|
12
|
+
private latestBlockHeight: number;
|
|
13
|
+
private latestBlockHeightContext: Context | undefined;
|
|
14
|
+
private blockhashes: Array<BlockhashWithExpiryBlockHeight> = [];
|
|
15
|
+
private updateBlockhashIntervalId: NodeJS.Timeout | undefined;
|
|
16
|
+
private commitment: Commitment;
|
|
17
|
+
private updateIntervalMs: number;
|
|
18
|
+
|
|
19
|
+
constructor(config: BlockhashSubscriberConfig) {
|
|
20
|
+
if (!config.connection && !config.rpcUrl) {
|
|
21
|
+
throw new Error(
|
|
22
|
+
'BlockhashSubscriber requires one of connection or rpcUrl must be provided'
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
this.connection = config.connection || new Connection(config.rpcUrl!);
|
|
26
|
+
this.commitment = config.commitment ?? 'confirmed';
|
|
27
|
+
this.updateIntervalMs = config.updateIntervalMs ?? 1000;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
getBlockhashCacheSize(): number {
|
|
31
|
+
return this.blockhashes.length;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
getLatestBlockHeight(): number {
|
|
35
|
+
return this.latestBlockHeight;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
getLatestBlockHeightContext(): Context | undefined {
|
|
39
|
+
return this.latestBlockHeightContext;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
getLatestBlockhash(
|
|
43
|
+
offset?: number
|
|
44
|
+
): BlockhashWithExpiryBlockHeight | undefined {
|
|
45
|
+
if (this.blockhashes.length === 0) {
|
|
46
|
+
return undefined;
|
|
47
|
+
}
|
|
48
|
+
const clampedOffset = Math.max(
|
|
49
|
+
0,
|
|
50
|
+
Math.min(this.blockhashes.length - 1, offset ?? 0)
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
return this.blockhashes[this.blockhashes.length - 1 - clampedOffset];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
pruneBlockhashes() {
|
|
57
|
+
if (this.latestBlockHeight) {
|
|
58
|
+
this.blockhashes = this.blockhashes.filter(
|
|
59
|
+
(blockhash) => blockhash.lastValidBlockHeight > this.latestBlockHeight!
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async updateBlockhash() {
|
|
65
|
+
const [resp, lastConfirmedBlockHeight] = await Promise.all([
|
|
66
|
+
this.connection.getLatestBlockhashAndContext({
|
|
67
|
+
commitment: this.commitment,
|
|
68
|
+
}),
|
|
69
|
+
this.connection.getBlockHeight({ commitment: this.commitment }),
|
|
70
|
+
]);
|
|
71
|
+
this.latestBlockHeight = lastConfirmedBlockHeight;
|
|
72
|
+
this.latestBlockHeightContext = resp.context;
|
|
73
|
+
|
|
74
|
+
// avoid caching duplicate blockhashes
|
|
75
|
+
if (this.blockhashes.length > 0) {
|
|
76
|
+
if (
|
|
77
|
+
resp.value.blockhash ===
|
|
78
|
+
this.blockhashes[this.blockhashes.length - 1].blockhash
|
|
79
|
+
) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
this.blockhashes.push(resp.value);
|
|
85
|
+
this.pruneBlockhashes();
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
async subscribe() {
|
|
89
|
+
if (this.isSubscribed) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
this.isSubscribed = true;
|
|
93
|
+
|
|
94
|
+
await this.updateBlockhash();
|
|
95
|
+
this.updateBlockhashIntervalId = setInterval(
|
|
96
|
+
this.updateBlockhash.bind(this),
|
|
97
|
+
this.updateIntervalMs
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
unsubscribe() {
|
|
102
|
+
if (this.updateBlockhashIntervalId) {
|
|
103
|
+
clearInterval(this.updateBlockhashIntervalId);
|
|
104
|
+
this.updateBlockhashIntervalId = undefined;
|
|
105
|
+
}
|
|
106
|
+
this.isSubscribed = false;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './BlockhashSubscriber';
|
|
@@ -219,6 +219,9 @@ export function getVammL2Generator({
|
|
|
219
219
|
);
|
|
220
220
|
|
|
221
221
|
baseSwapped = bidAmm.baseAssetReserve.sub(afterSwapBaseReserves).abs();
|
|
222
|
+
if (baseSwapped.eq(ZERO)) {
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
222
225
|
if (remainingBaseLiquidity.lt(baseSwapped)) {
|
|
223
226
|
baseSwapped = remainingBaseLiquidity;
|
|
224
227
|
[afterSwapQuoteReserves, afterSwapBaseReserves] =
|
|
@@ -299,6 +302,9 @@ export function getVammL2Generator({
|
|
|
299
302
|
);
|
|
300
303
|
|
|
301
304
|
baseSwapped = askAmm.baseAssetReserve.sub(afterSwapBaseReserves).abs();
|
|
305
|
+
if (baseSwapped.eq(ZERO)) {
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
302
308
|
if (remainingBaseLiquidity.lt(baseSwapped)) {
|
|
303
309
|
baseSwapped = remainingBaseLiquidity;
|
|
304
310
|
[afterSwapQuoteReserves, afterSwapBaseReserves] =
|
|
@@ -423,6 +429,30 @@ function groupL2Levels(
|
|
|
423
429
|
return groupedLevels;
|
|
424
430
|
}
|
|
425
431
|
|
|
432
|
+
/**
|
|
433
|
+
* Method to merge bids or asks by price
|
|
434
|
+
*/
|
|
435
|
+
const mergeByPrice = (bidsOrAsks: L2Level[]) => {
|
|
436
|
+
const merged = new Map<string, L2Level>();
|
|
437
|
+
for (const level of bidsOrAsks) {
|
|
438
|
+
const key = level.price.toString();
|
|
439
|
+
if (merged.has(key)) {
|
|
440
|
+
const existing = merged.get(key);
|
|
441
|
+
existing.size = existing.size.add(level.size);
|
|
442
|
+
for (const [source, size] of Object.entries(level.sources)) {
|
|
443
|
+
if (existing.sources[source]) {
|
|
444
|
+
existing.sources[source] = existing.sources[source].add(size);
|
|
445
|
+
} else {
|
|
446
|
+
existing.sources[source] = size;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
} else {
|
|
450
|
+
merged.set(key, cloneL2Level(level));
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
return Array.from(merged.values());
|
|
454
|
+
};
|
|
455
|
+
|
|
426
456
|
/**
|
|
427
457
|
* The purpose of this function is uncross the L2 orderbook by modifying the bid/ask price at the top of the book
|
|
428
458
|
* This will make the liquidity look worse but more intuitive (users familiar with clob get confused w temporarily
|
|
@@ -461,8 +491,8 @@ export function uncrossL2(
|
|
|
461
491
|
return { bids, asks };
|
|
462
492
|
}
|
|
463
493
|
|
|
464
|
-
const newBids = [];
|
|
465
|
-
const newAsks = [];
|
|
494
|
+
const newBids: L2Level[] = [];
|
|
495
|
+
const newAsks: L2Level[] = [];
|
|
466
496
|
|
|
467
497
|
const updateLevels = (newPrice: BN, oldLevel: L2Level, levels: L2Level[]) => {
|
|
468
498
|
if (levels.length > 0 && levels[levels.length - 1].price.eq(newPrice)) {
|
|
@@ -522,19 +552,19 @@ export function uncrossL2(
|
|
|
522
552
|
continue;
|
|
523
553
|
}
|
|
524
554
|
|
|
525
|
-
if (nextBid.price.
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
}
|
|
555
|
+
if (userBids.has(nextBid.price.toString())) {
|
|
556
|
+
newBids.push(nextBid);
|
|
557
|
+
bidIndex++;
|
|
558
|
+
continue;
|
|
559
|
+
}
|
|
531
560
|
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
561
|
+
if (userAsks.has(nextAsk.price.toString())) {
|
|
562
|
+
newAsks.push(nextAsk);
|
|
563
|
+
askIndex++;
|
|
564
|
+
continue;
|
|
565
|
+
}
|
|
537
566
|
|
|
567
|
+
if (nextBid.price.gte(nextAsk.price)) {
|
|
538
568
|
if (
|
|
539
569
|
nextBid.price.gt(referencePrice) &&
|
|
540
570
|
nextAsk.price.gt(referencePrice)
|
|
@@ -588,8 +618,14 @@ export function uncrossL2(
|
|
|
588
618
|
}
|
|
589
619
|
}
|
|
590
620
|
|
|
621
|
+
newBids.sort((a, b) => b.price.cmp(a.price));
|
|
622
|
+
newAsks.sort((a, b) => a.price.cmp(b.price));
|
|
623
|
+
|
|
624
|
+
const finalNewBids = mergeByPrice(newBids);
|
|
625
|
+
const finalNewAsks = mergeByPrice(newAsks);
|
|
626
|
+
|
|
591
627
|
return {
|
|
592
|
-
bids:
|
|
593
|
-
asks:
|
|
628
|
+
bids: finalNewBids,
|
|
629
|
+
asks: finalNewAsks,
|
|
594
630
|
};
|
|
595
631
|
}
|