@drift-labs/sdk 2.74.0-beta.1 → 2.74.0-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/adminClient.d.ts +5 -2
- package/lib/adminClient.js +17 -4
- 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 +89 -1
- 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 +73 -1
- 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 +89 -1
- 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
|
@@ -27,6 +27,6 @@ export declare class FastSingleTxSender extends BaseTxSender {
|
|
|
27
27
|
});
|
|
28
28
|
startBlockhashRefreshLoop(): void;
|
|
29
29
|
prepareTx(tx: Transaction, additionalSigners: Array<Signer>, _opts: ConfirmOptions): Promise<Transaction>;
|
|
30
|
-
getVersionedTransaction(ixs: TransactionInstruction[], lookupTableAccounts: AddressLookupTableAccount[], additionalSigners?: Array<Signer>, opts?: ConfirmOptions): Promise<VersionedTransaction>;
|
|
30
|
+
getVersionedTransaction(ixs: TransactionInstruction[], lookupTableAccounts: AddressLookupTableAccount[], additionalSigners?: Array<Signer>, opts?: ConfirmOptions, blockhash?: string): Promise<VersionedTransaction>;
|
|
31
31
|
sendRawTransaction(rawTransaction: Buffer | Uint8Array, opts: ConfirmOptions): Promise<TxSigAndSlot>;
|
|
32
32
|
}
|
|
@@ -52,7 +52,7 @@ class FastSingleTxSender extends baseTxSender_1.BaseTxSender {
|
|
|
52
52
|
const signedTx = await this.wallet.signTransaction(tx);
|
|
53
53
|
return signedTx;
|
|
54
54
|
}
|
|
55
|
-
async getVersionedTransaction(ixs, lookupTableAccounts, additionalSigners, opts) {
|
|
55
|
+
async getVersionedTransaction(ixs, lookupTableAccounts, additionalSigners, opts, blockhash) {
|
|
56
56
|
var _a;
|
|
57
57
|
if (additionalSigners === undefined) {
|
|
58
58
|
additionalSigners = [];
|
|
@@ -60,10 +60,18 @@ class FastSingleTxSender extends baseTxSender_1.BaseTxSender {
|
|
|
60
60
|
if (opts === undefined) {
|
|
61
61
|
opts = this.opts;
|
|
62
62
|
}
|
|
63
|
+
let recentBlockhash = '';
|
|
64
|
+
if (blockhash) {
|
|
65
|
+
recentBlockhash = blockhash;
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
recentBlockhash =
|
|
69
|
+
(_a = this.recentBlockhash) !== null && _a !== void 0 ? _a : (await this.connection.getLatestBlockhash(opts.preflightCommitment))
|
|
70
|
+
.blockhash;
|
|
71
|
+
}
|
|
63
72
|
const message = new web3_js_1.TransactionMessage({
|
|
64
73
|
payerKey: this.wallet.publicKey,
|
|
65
|
-
recentBlockhash
|
|
66
|
-
.blockhash,
|
|
74
|
+
recentBlockhash,
|
|
67
75
|
instructions: ixs,
|
|
68
76
|
}).compileToV0Message(lookupTableAccounts);
|
|
69
77
|
const tx = new web3_js_1.VersionedTransaction(message);
|
package/lib/tx/types.d.ts
CHANGED
|
@@ -17,7 +17,7 @@ export interface TxSender {
|
|
|
17
17
|
wallet: IWallet;
|
|
18
18
|
send(tx: Transaction, additionalSigners?: Array<Signer>, opts?: ConfirmOptions, preSigned?: boolean, extraConfirmationOptions?: ExtraConfirmationOptions): Promise<TxSigAndSlot>;
|
|
19
19
|
sendVersionedTransaction(tx: VersionedTransaction, additionalSigners?: Array<Signer>, opts?: ConfirmOptions, preSigned?: boolean, extraConfirmationOptions?: ExtraConfirmationOptions): Promise<TxSigAndSlot>;
|
|
20
|
-
getVersionedTransaction(ixs: TransactionInstruction[], lookupTableAccounts: AddressLookupTableAccount[], additionalSigners?: Array<Signer>, opts?: ConfirmOptions): Promise<VersionedTransaction>;
|
|
20
|
+
getVersionedTransaction(ixs: TransactionInstruction[], lookupTableAccounts: AddressLookupTableAccount[], additionalSigners?: Array<Signer>, opts?: ConfirmOptions, blockhash?: string): Promise<VersionedTransaction>;
|
|
21
21
|
sendRawTransaction(rawTransaction: Buffer | Uint8Array, opts: ConfirmOptions): Promise<TxSigAndSlot>;
|
|
22
22
|
simulateTransaction(tx: VersionedTransaction): Promise<boolean>;
|
|
23
23
|
getTimeoutCount(): number;
|
package/lib/types.d.ts
CHANGED
package/lib/types.js
CHANGED
|
@@ -60,6 +60,7 @@ ContractTier.A = { a: {} };
|
|
|
60
60
|
ContractTier.B = { b: {} };
|
|
61
61
|
ContractTier.C = { c: {} };
|
|
62
62
|
ContractTier.SPECULATIVE = { speculative: {} };
|
|
63
|
+
ContractTier.HIGHLY_SPECULATIVE = { highlySpeculative: {} };
|
|
63
64
|
ContractTier.ISOLATED = { isolated: {} };
|
|
64
65
|
class AssetTier {
|
|
65
66
|
}
|
package/lib/user.d.ts
CHANGED
|
@@ -246,13 +246,15 @@ export declare class User {
|
|
|
246
246
|
/**
|
|
247
247
|
* Calculate the liquidation price of a perp position, with optional parameter to calculate the liquidation price after a trade
|
|
248
248
|
* @param marketIndex
|
|
249
|
-
* @param positionBaseSizeChange // change in position size to calculate liquidation price for : Precision 10^
|
|
249
|
+
* @param positionBaseSizeChange // change in position size to calculate liquidation price for : Precision 10^9
|
|
250
|
+
* @param estimatedEntryPrice
|
|
250
251
|
* @param marginCategory // allow Initial to be passed in if we are trying to calculate price for DLP de-risking
|
|
252
|
+
* @param includeOpenOrders
|
|
251
253
|
* @returns Precision : PRICE_PRECISION
|
|
252
254
|
*/
|
|
253
|
-
liquidationPrice(marketIndex: number, positionBaseSizeChange?: BN, estimatedEntryPrice?: BN, marginCategory?: MarginCategory): BN;
|
|
254
|
-
calculateEntriesEffectOnFreeCollateral(market: PerpMarketAccount, oraclePrice: BN, perpPosition: PerpPosition, positionBaseSizeChange: BN, estimatedEntryPrice: BN): BN;
|
|
255
|
-
calculateFreeCollateralDeltaForPerp(market: PerpMarketAccount, perpPosition: PerpPosition, positionBaseSizeChange: BN, marginCategory?: MarginCategory): BN | undefined;
|
|
255
|
+
liquidationPrice(marketIndex: number, positionBaseSizeChange?: BN, estimatedEntryPrice?: BN, marginCategory?: MarginCategory, includeOpenOrders?: boolean): BN;
|
|
256
|
+
calculateEntriesEffectOnFreeCollateral(market: PerpMarketAccount, oraclePrice: BN, perpPosition: PerpPosition, positionBaseSizeChange: BN, estimatedEntryPrice: BN, includeOpenOrders: boolean): BN;
|
|
257
|
+
calculateFreeCollateralDeltaForPerp(market: PerpMarketAccount, perpPosition: PerpPosition, positionBaseSizeChange: BN, marginCategory?: MarginCategory, includeOpenOrders?: boolean): BN | undefined;
|
|
256
258
|
calculateFreeCollateralDeltaForSpot(market: SpotMarketAccount, signedTokenAmount: BN, marginCategory?: MarginCategory): BN;
|
|
257
259
|
/**
|
|
258
260
|
* Calculates the estimated liquidation price for a position after closing a quote amount of the position.
|
package/lib/user.js
CHANGED
|
@@ -1082,13 +1082,15 @@ class User {
|
|
|
1082
1082
|
/**
|
|
1083
1083
|
* Calculate the liquidation price of a perp position, with optional parameter to calculate the liquidation price after a trade
|
|
1084
1084
|
* @param marketIndex
|
|
1085
|
-
* @param positionBaseSizeChange // change in position size to calculate liquidation price for : Precision 10^
|
|
1085
|
+
* @param positionBaseSizeChange // change in position size to calculate liquidation price for : Precision 10^9
|
|
1086
|
+
* @param estimatedEntryPrice
|
|
1086
1087
|
* @param marginCategory // allow Initial to be passed in if we are trying to calculate price for DLP de-risking
|
|
1088
|
+
* @param includeOpenOrders
|
|
1087
1089
|
* @returns Precision : PRICE_PRECISION
|
|
1088
1090
|
*/
|
|
1089
|
-
liquidationPrice(marketIndex, positionBaseSizeChange = numericConstants_1.ZERO, estimatedEntryPrice = numericConstants_1.ZERO, marginCategory = 'Maintenance') {
|
|
1091
|
+
liquidationPrice(marketIndex, positionBaseSizeChange = numericConstants_1.ZERO, estimatedEntryPrice = numericConstants_1.ZERO, marginCategory = 'Maintenance', includeOpenOrders = false) {
|
|
1090
1092
|
const totalCollateral = this.getTotalCollateral(marginCategory);
|
|
1091
|
-
const marginRequirement = this.getMarginRequirement(marginCategory, undefined, false);
|
|
1093
|
+
const marginRequirement = this.getMarginRequirement(marginCategory, undefined, false, includeOpenOrders);
|
|
1092
1094
|
let freeCollateral = _1.BN.max(numericConstants_1.ZERO, totalCollateral.sub(marginRequirement));
|
|
1093
1095
|
const oracle = this.driftClient.getPerpMarketAccount(marketIndex).amm.oracle;
|
|
1094
1096
|
const oraclePrice = this.driftClient.getOracleDataForPerpMarket(marketIndex).price;
|
|
@@ -1096,9 +1098,9 @@ class User {
|
|
|
1096
1098
|
const currentPerpPosition = this.getPerpPositionWithLPSettle(marketIndex, undefined, true)[0] ||
|
|
1097
1099
|
this.getEmptyPosition(marketIndex);
|
|
1098
1100
|
positionBaseSizeChange = (0, _1.standardizeBaseAssetAmount)(positionBaseSizeChange, market.amm.orderStepSize);
|
|
1099
|
-
const freeCollateralChangeFromNewPosition = this.calculateEntriesEffectOnFreeCollateral(market, oraclePrice, currentPerpPosition, positionBaseSizeChange, estimatedEntryPrice);
|
|
1101
|
+
const freeCollateralChangeFromNewPosition = this.calculateEntriesEffectOnFreeCollateral(market, oraclePrice, currentPerpPosition, positionBaseSizeChange, estimatedEntryPrice, includeOpenOrders);
|
|
1100
1102
|
freeCollateral = freeCollateral.add(freeCollateralChangeFromNewPosition);
|
|
1101
|
-
let freeCollateralDelta = this.calculateFreeCollateralDeltaForPerp(market, currentPerpPosition, positionBaseSizeChange, marginCategory);
|
|
1103
|
+
let freeCollateralDelta = this.calculateFreeCollateralDeltaForPerp(market, currentPerpPosition, positionBaseSizeChange, marginCategory, includeOpenOrders);
|
|
1102
1104
|
if (!freeCollateralDelta) {
|
|
1103
1105
|
return new _1.BN(-1);
|
|
1104
1106
|
}
|
|
@@ -1125,7 +1127,7 @@ class User {
|
|
|
1125
1127
|
}
|
|
1126
1128
|
return liqPrice;
|
|
1127
1129
|
}
|
|
1128
|
-
calculateEntriesEffectOnFreeCollateral(market, oraclePrice, perpPosition, positionBaseSizeChange, estimatedEntryPrice) {
|
|
1130
|
+
calculateEntriesEffectOnFreeCollateral(market, oraclePrice, perpPosition, positionBaseSizeChange, estimatedEntryPrice, includeOpenOrders) {
|
|
1129
1131
|
let freeCollateralChange = numericConstants_1.ZERO;
|
|
1130
1132
|
// update free collateral to account for change in pnl from new position
|
|
1131
1133
|
if (!estimatedEntryPrice.eq(numericConstants_1.ZERO) && !positionBaseSizeChange.eq(numericConstants_1.ZERO)) {
|
|
@@ -1139,8 +1141,6 @@ class User {
|
|
|
1139
1141
|
freeCollateralChange = costBasis.sub(newPositionValue);
|
|
1140
1142
|
}
|
|
1141
1143
|
else {
|
|
1142
|
-
console.log('newPositionValue', newPositionValue.toString());
|
|
1143
|
-
console.log('costBasis', costBasis.toString());
|
|
1144
1144
|
freeCollateralChange = newPositionValue.sub(costBasis);
|
|
1145
1145
|
}
|
|
1146
1146
|
// assume worst fee tier
|
|
@@ -1150,30 +1150,33 @@ class User {
|
|
|
1150
1150
|
.divn(takerFeeTier.feeDenominator);
|
|
1151
1151
|
freeCollateralChange = freeCollateralChange.sub(takerFee);
|
|
1152
1152
|
}
|
|
1153
|
-
const
|
|
1154
|
-
|
|
1155
|
-
|
|
1153
|
+
const baseAssetAmount = includeOpenOrders
|
|
1154
|
+
? (0, margin_1.calculateWorstCaseBaseAssetAmount)(perpPosition)
|
|
1155
|
+
: perpPosition.baseAssetAmount;
|
|
1156
|
+
const newBaseAssetAmount = baseAssetAmount.add(positionBaseSizeChange);
|
|
1157
|
+
const newMarginRatio = (0, _1.calculateMarketMarginRatio)(market, newBaseAssetAmount.abs(), 'Maintenance');
|
|
1156
1158
|
// update free collateral to account for new margin requirement from position change
|
|
1157
|
-
freeCollateralChange = freeCollateralChange.sub(
|
|
1159
|
+
freeCollateralChange = freeCollateralChange.sub(newBaseAssetAmount
|
|
1158
1160
|
.abs()
|
|
1159
|
-
.sub(
|
|
1161
|
+
.sub(baseAssetAmount.abs())
|
|
1160
1162
|
.mul(oraclePrice)
|
|
1161
1163
|
.div(numericConstants_1.BASE_PRECISION)
|
|
1162
1164
|
.mul(new _1.BN(newMarginRatio))
|
|
1163
1165
|
.div(numericConstants_1.MARGIN_PRECISION));
|
|
1164
1166
|
return freeCollateralChange;
|
|
1165
1167
|
}
|
|
1166
|
-
calculateFreeCollateralDeltaForPerp(market, perpPosition, positionBaseSizeChange, marginCategory = 'Maintenance') {
|
|
1167
|
-
const
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
const
|
|
1172
|
-
const
|
|
1168
|
+
calculateFreeCollateralDeltaForPerp(market, perpPosition, positionBaseSizeChange, marginCategory = 'Maintenance', includeOpenOrders = false) {
|
|
1169
|
+
const baseAssetAmount = includeOpenOrders
|
|
1170
|
+
? (0, margin_1.calculateWorstCaseBaseAssetAmount)(perpPosition)
|
|
1171
|
+
: perpPosition.baseAssetAmount;
|
|
1172
|
+
// zero if include orders == false
|
|
1173
|
+
const orderBaseAssetAmount = baseAssetAmount.sub(perpPosition.baseAssetAmount);
|
|
1174
|
+
const proposedBaseAssetAmount = baseAssetAmount.add(positionBaseSizeChange);
|
|
1175
|
+
const marginRatio = (0, _1.calculateMarketMarginRatio)(market, proposedBaseAssetAmount.abs(), marginCategory, this.getUserAccount().maxMarginRatio);
|
|
1173
1176
|
const marginRatioQuotePrecision = new _1.BN(marginRatio)
|
|
1174
1177
|
.mul(numericConstants_1.QUOTE_PRECISION)
|
|
1175
1178
|
.div(numericConstants_1.MARGIN_PRECISION);
|
|
1176
|
-
if (
|
|
1179
|
+
if (proposedBaseAssetAmount.eq(numericConstants_1.ZERO)) {
|
|
1177
1180
|
return undefined;
|
|
1178
1181
|
}
|
|
1179
1182
|
let freeCollateralDelta = numericConstants_1.ZERO;
|
package/package.json
CHANGED
package/src/adminClient.ts
CHANGED
|
@@ -31,7 +31,13 @@ import {
|
|
|
31
31
|
import { squareRootBN } from './math/utils';
|
|
32
32
|
import { TOKEN_PROGRAM_ID } from '@solana/spl-token';
|
|
33
33
|
import { DriftClient } from './driftClient';
|
|
34
|
-
import {
|
|
34
|
+
import {
|
|
35
|
+
PEG_PRECISION,
|
|
36
|
+
ZERO,
|
|
37
|
+
ONE,
|
|
38
|
+
BASE_PRECISION,
|
|
39
|
+
PRICE_PRECISION,
|
|
40
|
+
} from './constants/numericConstants';
|
|
35
41
|
import { calculateTargetPriceTrade } from './math/trade';
|
|
36
42
|
import { calculateAmmReservesAfterSwap, getSwapDirection } from './math/amm';
|
|
37
43
|
import { PROGRAM_ID as PHOENIX_PROGRAM_ID } from '@ellipsis-labs/phoenix-sdk';
|
|
@@ -84,7 +90,14 @@ export class AdminClient extends DriftClient {
|
|
|
84
90
|
maintenanceLiabilityWeight: number,
|
|
85
91
|
imfFactor = 0,
|
|
86
92
|
liquidatorFee = 0,
|
|
93
|
+
ifLiquidationFee = 0,
|
|
87
94
|
activeStatus = true,
|
|
95
|
+
assetTier = AssetTier.COLLATERAL,
|
|
96
|
+
scaleInitialAssetWeightStart = ZERO,
|
|
97
|
+
withdrawGuardThreshold = ZERO,
|
|
98
|
+
orderTickSize = ONE,
|
|
99
|
+
orderStepSize = ONE,
|
|
100
|
+
ifTotalFactor = 0,
|
|
88
101
|
name = DEFAULT_MARKET_NAME
|
|
89
102
|
): Promise<TransactionSignature> {
|
|
90
103
|
const spotMarketIndex = this.getStateAccount().numberOfSpotMarkets;
|
|
@@ -115,7 +128,14 @@ export class AdminClient extends DriftClient {
|
|
|
115
128
|
maintenanceLiabilityWeight,
|
|
116
129
|
imfFactor,
|
|
117
130
|
liquidatorFee,
|
|
131
|
+
ifLiquidationFee,
|
|
118
132
|
activeStatus,
|
|
133
|
+
assetTier,
|
|
134
|
+
scaleInitialAssetWeightStart,
|
|
135
|
+
withdrawGuardThreshold,
|
|
136
|
+
orderTickSize,
|
|
137
|
+
orderStepSize,
|
|
138
|
+
ifTotalFactor,
|
|
119
139
|
nameBuffer,
|
|
120
140
|
{
|
|
121
141
|
accounts: {
|
|
@@ -238,7 +258,20 @@ export class AdminClient extends DriftClient {
|
|
|
238
258
|
marginRatioInitial = 2000,
|
|
239
259
|
marginRatioMaintenance = 500,
|
|
240
260
|
liquidatorFee = 0,
|
|
261
|
+
ifLiquidatorFee = 10000,
|
|
262
|
+
imfFactor = 0,
|
|
241
263
|
activeStatus = true,
|
|
264
|
+
baseSpread = 0,
|
|
265
|
+
maxSpread = 142500,
|
|
266
|
+
maxOpenInterest = ZERO,
|
|
267
|
+
maxRevenueWithdrawPerPeriod = ZERO,
|
|
268
|
+
quoteMaxInsurance = ZERO,
|
|
269
|
+
orderStepSize = BASE_PRECISION.divn(10000),
|
|
270
|
+
orderTickSize = PRICE_PRECISION.divn(100000),
|
|
271
|
+
minOrderSize = BASE_PRECISION.divn(10000),
|
|
272
|
+
concentrationCoefScale = ONE,
|
|
273
|
+
curveUpdateIntensity = 0,
|
|
274
|
+
ammJitIntensity = 0,
|
|
242
275
|
name = DEFAULT_MARKET_NAME
|
|
243
276
|
): Promise<TransactionSignature> {
|
|
244
277
|
const currentPerpMarketIndex = this.getStateAccount().numberOfMarkets;
|
|
@@ -259,7 +292,20 @@ export class AdminClient extends DriftClient {
|
|
|
259
292
|
marginRatioInitial,
|
|
260
293
|
marginRatioMaintenance,
|
|
261
294
|
liquidatorFee,
|
|
295
|
+
ifLiquidatorFee,
|
|
296
|
+
imfFactor,
|
|
262
297
|
activeStatus,
|
|
298
|
+
baseSpread,
|
|
299
|
+
maxSpread,
|
|
300
|
+
maxOpenInterest,
|
|
301
|
+
maxRevenueWithdrawPerPeriod,
|
|
302
|
+
quoteMaxInsurance,
|
|
303
|
+
orderStepSize,
|
|
304
|
+
orderTickSize,
|
|
305
|
+
minOrderSize,
|
|
306
|
+
concentrationCoefScale,
|
|
307
|
+
curveUpdateIntensity,
|
|
308
|
+
ammJitIntensity,
|
|
263
309
|
nameBuffer,
|
|
264
310
|
{
|
|
265
311
|
accounts: {
|
|
@@ -2172,4 +2218,30 @@ export class AdminClient extends DriftClient {
|
|
|
2172
2218
|
|
|
2173
2219
|
return txSig;
|
|
2174
2220
|
}
|
|
2221
|
+
|
|
2222
|
+
public async deletePrelaunchOracle(
|
|
2223
|
+
perpMarketIndex: number
|
|
2224
|
+
): Promise<TransactionSignature> {
|
|
2225
|
+
const deletePrelaunchOracleIx =
|
|
2226
|
+
await this.program.instruction.deletePrelaunchOracle(perpMarketIndex, {
|
|
2227
|
+
accounts: {
|
|
2228
|
+
admin: this.wallet.publicKey,
|
|
2229
|
+
state: await this.getStatePublicKey(),
|
|
2230
|
+
prelaunchOracle: await getPrelaunchOraclePublicKey(
|
|
2231
|
+
this.program.programId,
|
|
2232
|
+
perpMarketIndex
|
|
2233
|
+
),
|
|
2234
|
+
perpMarket: await getPerpMarketPublicKey(
|
|
2235
|
+
this.program.programId,
|
|
2236
|
+
perpMarketIndex
|
|
2237
|
+
),
|
|
2238
|
+
},
|
|
2239
|
+
});
|
|
2240
|
+
|
|
2241
|
+
const tx = await this.buildTransaction(deletePrelaunchOracleIx);
|
|
2242
|
+
|
|
2243
|
+
const { txSig } = await this.sendTransaction(tx, [], this.opts);
|
|
2244
|
+
|
|
2245
|
+
return txSig;
|
|
2246
|
+
}
|
|
2175
2247
|
}
|
|
@@ -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
|
}
|
package/src/driftClient.ts
CHANGED
|
@@ -1074,6 +1074,43 @@ export class DriftClient {
|
|
|
1074
1074
|
return ix;
|
|
1075
1075
|
}
|
|
1076
1076
|
|
|
1077
|
+
public async updateUserReduceOnly(
|
|
1078
|
+
updates: { reduceOnly: boolean; subAccountId: number }[]
|
|
1079
|
+
): Promise<TransactionSignature> {
|
|
1080
|
+
const ixs = await Promise.all(
|
|
1081
|
+
updates.map(async ({ reduceOnly, subAccountId }) => {
|
|
1082
|
+
return await this.getUpdateUserReduceOnlyIx(reduceOnly, subAccountId);
|
|
1083
|
+
})
|
|
1084
|
+
);
|
|
1085
|
+
|
|
1086
|
+
const tx = await this.buildTransaction(ixs, this.txParams);
|
|
1087
|
+
|
|
1088
|
+
const { txSig } = await this.sendTransaction(tx, [], this.opts);
|
|
1089
|
+
return txSig;
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
public async getUpdateUserReduceOnlyIx(
|
|
1093
|
+
reduceOnly: boolean,
|
|
1094
|
+
subAccountId: number
|
|
1095
|
+
) {
|
|
1096
|
+
const ix = await this.program.instruction.updateUserReduceOnly(
|
|
1097
|
+
subAccountId,
|
|
1098
|
+
reduceOnly,
|
|
1099
|
+
{
|
|
1100
|
+
accounts: {
|
|
1101
|
+
user: getUserAccountPublicKeySync(
|
|
1102
|
+
this.program.programId,
|
|
1103
|
+
this.wallet.publicKey,
|
|
1104
|
+
subAccountId
|
|
1105
|
+
),
|
|
1106
|
+
authority: this.wallet.publicKey,
|
|
1107
|
+
},
|
|
1108
|
+
}
|
|
1109
|
+
);
|
|
1110
|
+
|
|
1111
|
+
return ix;
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1077
1114
|
public async fetchAllUserAccounts(
|
|
1078
1115
|
includeIdle = true
|
|
1079
1116
|
): Promise<ProgramAccount<UserAccount>[]> {
|