@drift-labs/sdk 2.0.14 → 2.0.16
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/README.md +3 -3
- package/lib/accounts/pollingDriftClientAccountSubscriber.js +0 -3
- package/lib/accounts/pollingUserStatsAccountSubscriber.js +0 -3
- package/lib/adminClient.d.ts +2 -0
- package/lib/adminClient.js +16 -0
- package/lib/constants/numericConstants.d.ts +3 -0
- package/lib/constants/numericConstants.js +4 -1
- package/lib/dlob/DLOB.d.ts +2 -7
- package/lib/dlob/DLOB.js +84 -166
- package/lib/idl/drift.json +65 -7
- package/lib/math/amm.d.ts +8 -7
- package/lib/math/amm.js +116 -61
- package/lib/math/oracles.d.ts +2 -0
- package/lib/math/oracles.js +23 -1
- package/lib/math/utils.d.ts +2 -1
- package/lib/math/utils.js +5 -1
- package/lib/types.d.ts +6 -2
- package/lib/user.js +10 -6
- package/package.json +1 -1
- package/src/accounts/pollingDriftClientAccountSubscriber.ts +0 -4
- package/src/accounts/pollingUserStatsAccountSubscriber.ts +0 -4
- package/src/adminClient.ts +28 -0
- package/src/constants/numericConstants.ts +7 -0
- package/src/dlob/DLOB.ts +152 -237
- package/src/idl/drift.json +65 -7
- package/src/math/amm.ts +220 -100
- package/src/math/oracles.ts +52 -0
- package/src/math/utils.ts +5 -1
- package/src/types.ts +6 -2
- package/src/user.ts +17 -6
- package/tests/dlob/helpers.ts +4 -2
- package/tests/dlob/test.ts +252 -0
- package/src/events/eventList.js +0 -77
package/lib/math/amm.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.calculateMaxBaseAssetAmountFillable = exports.calculateQuoteAssetAmountSwapped = exports.calculateMaxBaseAssetAmountToTrade = exports.calculateTerminalPrice = exports.getSwapDirection = exports.calculateSwapOutput = exports.calculateSpreadReserves = exports.calculateSpread = exports.calculateSpreadBN = exports.calculateMaxSpread = exports.calculateEffectiveLeverage = exports.calculateInventoryScale = exports.calculateMarketOpenBidAsk = exports.calculateAmmReservesAfterSwap = exports.calculatePrice = exports.calculateBidAskPrice = exports.calculateUpdatedAMMSpreadReserves = exports.calculateUpdatedAMM = exports.calculateNewAmm = exports.calculateOptimalPegAndBudget = exports.calculatePegFromTargetPrice = void 0;
|
|
3
|
+
exports.calculateMaxBaseAssetAmountFillable = exports.calculateQuoteAssetAmountSwapped = exports.calculateMaxBaseAssetAmountToTrade = exports.calculateTerminalPrice = exports.getSwapDirection = exports.calculateSwapOutput = exports.calculateSpreadReserves = exports.calculateSpread = exports.calculateSpreadBN = exports.calculateVolSpreadBN = exports.calculateMaxSpread = exports.calculateEffectiveLeverage = exports.calculateInventoryScale = exports.calculateMarketOpenBidAsk = exports.calculateAmmReservesAfterSwap = exports.calculatePrice = exports.calculateBidAskPrice = exports.calculateUpdatedAMMSpreadReserves = exports.calculateUpdatedAMM = exports.calculateNewAmm = exports.calculateOptimalPegAndBudget = exports.calculatePegFromTargetPrice = void 0;
|
|
4
4
|
const anchor_1 = require("@project-serum/anchor");
|
|
5
5
|
const numericConstants_1 = require("../constants/numericConstants");
|
|
6
6
|
const types_1 = require("../types");
|
|
7
7
|
const assert_1 = require("../assert/assert");
|
|
8
8
|
const __1 = require("..");
|
|
9
9
|
const repeg_1 = require("./repeg");
|
|
10
|
+
const oracles_1 = require("./oracles");
|
|
10
11
|
function calculatePegFromTargetPrice(targetPrice, baseAssetReserve, quoteAssetReserve) {
|
|
11
12
|
return anchor_1.BN.max(targetPrice
|
|
12
13
|
.mul(baseAssetReserve)
|
|
@@ -23,15 +24,16 @@ function calculateOptimalPegAndBudget(amm, oraclePriceData) {
|
|
|
23
24
|
const totalFeeLB = amm.totalExchangeFee.div(new anchor_1.BN(2));
|
|
24
25
|
const budget = anchor_1.BN.max(numericConstants_1.ZERO, amm.totalFeeMinusDistributions.sub(totalFeeLB));
|
|
25
26
|
if (budget.lt(prePegCost)) {
|
|
26
|
-
const
|
|
27
|
+
const halfMaxPriceSpread = new anchor_1.BN(amm.maxSpread)
|
|
28
|
+
.div(new anchor_1.BN(2))
|
|
27
29
|
.mul(targetPrice)
|
|
28
30
|
.div(numericConstants_1.BID_ASK_SPREAD_PRECISION);
|
|
29
31
|
let newTargetPrice;
|
|
30
32
|
let newOptimalPeg;
|
|
31
33
|
let newBudget;
|
|
32
34
|
const targetPriceGap = reservePriceBefore.sub(targetPrice);
|
|
33
|
-
if (targetPriceGap.abs().gt(
|
|
34
|
-
const markAdj = targetPriceGap.abs().sub(
|
|
35
|
+
if (targetPriceGap.abs().gt(halfMaxPriceSpread)) {
|
|
36
|
+
const markAdj = targetPriceGap.abs().sub(halfMaxPriceSpread);
|
|
35
37
|
if (targetPriceGap.lt(new anchor_1.BN(0))) {
|
|
36
38
|
newTargetPrice = reservePriceBefore.add(markAdj);
|
|
37
39
|
}
|
|
@@ -91,12 +93,17 @@ function calculateUpdatedAMM(amm, oraclePriceData) {
|
|
|
91
93
|
newAmm.terminalQuoteAssetReserve = newQuoteAssetReserve;
|
|
92
94
|
newAmm.totalFeeMinusDistributions =
|
|
93
95
|
newAmm.totalFeeMinusDistributions.sub(prepegCost);
|
|
96
|
+
newAmm.netRevenueSinceLastFunding =
|
|
97
|
+
newAmm.netRevenueSinceLastFunding.sub(prepegCost);
|
|
94
98
|
return newAmm;
|
|
95
99
|
}
|
|
96
100
|
exports.calculateUpdatedAMM = calculateUpdatedAMM;
|
|
97
101
|
function calculateUpdatedAMMSpreadReserves(amm, direction, oraclePriceData) {
|
|
98
102
|
const newAmm = calculateUpdatedAMM(amm, oraclePriceData);
|
|
99
|
-
const
|
|
103
|
+
const [shortReserves, longReserves] = calculateSpreadReserves(newAmm, oraclePriceData);
|
|
104
|
+
const dirReserves = (0, types_1.isVariant)(direction, 'long')
|
|
105
|
+
? longReserves
|
|
106
|
+
: shortReserves;
|
|
100
107
|
const result = {
|
|
101
108
|
baseAssetReserve: dirReserves.baseAssetReserve,
|
|
102
109
|
quoteAssetReserve: dirReserves.quoteAssetReserve,
|
|
@@ -114,8 +121,7 @@ function calculateBidAskPrice(amm, oraclePriceData, withUpdate = true) {
|
|
|
114
121
|
else {
|
|
115
122
|
newAmm = amm;
|
|
116
123
|
}
|
|
117
|
-
const askReserves = calculateSpreadReserves(newAmm,
|
|
118
|
-
const bidReserves = calculateSpreadReserves(newAmm, types_1.PositionDirection.SHORT, oraclePriceData);
|
|
124
|
+
const [bidReserves, askReserves] = calculateSpreadReserves(newAmm, oraclePriceData);
|
|
119
125
|
const askPrice = calculatePrice(askReserves.baseAssetReserve, askReserves.quoteAssetReserve, newAmm.pegMultiplier);
|
|
120
126
|
const bidPrice = calculatePrice(bidReserves.baseAssetReserve, bidReserves.quoteAssetReserve, newAmm.pegMultiplier);
|
|
121
127
|
return [bidPrice, askPrice];
|
|
@@ -168,14 +174,14 @@ exports.calculateAmmReservesAfterSwap = calculateAmmReservesAfterSwap;
|
|
|
168
174
|
function calculateMarketOpenBidAsk(baseAssetReserve, minBaseAssetReserve, maxBaseAssetReserve) {
|
|
169
175
|
// open orders
|
|
170
176
|
let openAsks;
|
|
171
|
-
if (maxBaseAssetReserve
|
|
177
|
+
if (maxBaseAssetReserve.gt(baseAssetReserve)) {
|
|
172
178
|
openAsks = maxBaseAssetReserve.sub(baseAssetReserve).mul(new anchor_1.BN(-1));
|
|
173
179
|
}
|
|
174
180
|
else {
|
|
175
181
|
openAsks = numericConstants_1.ZERO;
|
|
176
182
|
}
|
|
177
183
|
let openBids;
|
|
178
|
-
if (minBaseAssetReserve
|
|
184
|
+
if (minBaseAssetReserve.lt(baseAssetReserve)) {
|
|
179
185
|
openBids = baseAssetReserve.sub(minBaseAssetReserve);
|
|
180
186
|
}
|
|
181
187
|
else {
|
|
@@ -184,13 +190,26 @@ function calculateMarketOpenBidAsk(baseAssetReserve, minBaseAssetReserve, maxBas
|
|
|
184
190
|
return [openBids, openAsks];
|
|
185
191
|
}
|
|
186
192
|
exports.calculateMarketOpenBidAsk = calculateMarketOpenBidAsk;
|
|
187
|
-
function calculateInventoryScale(
|
|
188
|
-
|
|
193
|
+
function calculateInventoryScale(baseAssetAmountWithAmm, baseAssetReserve, minBaseAssetReserve, maxBaseAssetReserve, directionalSpread, maxSpread) {
|
|
194
|
+
if (baseAssetAmountWithAmm.eq(numericConstants_1.ZERO)) {
|
|
195
|
+
return 0;
|
|
196
|
+
}
|
|
197
|
+
const defaultLargeBidAskFactor = numericConstants_1.BID_ASK_SPREAD_PRECISION.mul(new anchor_1.BN(10));
|
|
189
198
|
// inventory skew
|
|
190
199
|
const [openBids, openAsks] = calculateMarketOpenBidAsk(baseAssetReserve, minBaseAssetReserve, maxBaseAssetReserve);
|
|
191
200
|
const minSideLiquidity = anchor_1.BN.max(new anchor_1.BN(1), anchor_1.BN.min(openBids.abs(), openAsks.abs()));
|
|
192
|
-
const
|
|
193
|
-
|
|
201
|
+
const inventoryScaleMax = anchor_1.BN.max(defaultLargeBidAskFactor, new anchor_1.BN(maxSpread / 2)
|
|
202
|
+
.mul(numericConstants_1.BID_ASK_SPREAD_PRECISION)
|
|
203
|
+
.div(new anchor_1.BN(Math.max(directionalSpread, 1)))).toNumber() / numericConstants_1.BID_ASK_SPREAD_PRECISION.toNumber();
|
|
204
|
+
const inventoryScale = baseAssetAmountWithAmm
|
|
205
|
+
.mul(anchor_1.BN.max(baseAssetAmountWithAmm.abs(), numericConstants_1.BASE_PRECISION))
|
|
206
|
+
.div(numericConstants_1.BASE_PRECISION)
|
|
207
|
+
.mul(defaultLargeBidAskFactor)
|
|
208
|
+
.div(minSideLiquidity)
|
|
209
|
+
.abs()
|
|
210
|
+
.toNumber() / numericConstants_1.BID_ASK_SPREAD_PRECISION.toNumber();
|
|
211
|
+
const inventorySpreadScale = Math.min(inventoryScaleMax, 1 + inventoryScale);
|
|
212
|
+
return inventorySpreadScale;
|
|
194
213
|
}
|
|
195
214
|
exports.calculateInventoryScale = calculateInventoryScale;
|
|
196
215
|
function calculateEffectiveLeverage(baseSpread, quoteAssetReserve, terminalQuoteAssetReserve, pegMultiplier, netBaseAssetAmount, reservePrice, totalFeeMinusDistributions) {
|
|
@@ -215,31 +234,47 @@ function calculateMaxSpread(marginRatioInitial) {
|
|
|
215
234
|
return maxTargetSpread;
|
|
216
235
|
}
|
|
217
236
|
exports.calculateMaxSpread = calculateMaxSpread;
|
|
218
|
-
function
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
237
|
+
function calculateVolSpreadBN(lastOracleConfPct, reservePrice, markStd, oracleStd, longIntensity, shortIntensity, volume24H) {
|
|
238
|
+
const marketAvgStdPct = markStd
|
|
239
|
+
.add(oracleStd)
|
|
240
|
+
.mul(numericConstants_1.PERCENTAGE_PRECISION)
|
|
241
|
+
.div(reservePrice)
|
|
242
|
+
.div(new anchor_1.BN(2));
|
|
243
|
+
const volSpread = anchor_1.BN.max(lastOracleConfPct, marketAvgStdPct.div(new anchor_1.BN(2)));
|
|
244
|
+
const clampMin = numericConstants_1.PERCENTAGE_PRECISION.div(new anchor_1.BN(100));
|
|
245
|
+
const clampMax = numericConstants_1.PERCENTAGE_PRECISION.mul(new anchor_1.BN(16)).div(new anchor_1.BN(10));
|
|
246
|
+
const longVolSpreadFactor = (0, __1.clampBN)(longIntensity.mul(numericConstants_1.PERCENTAGE_PRECISION).div(anchor_1.BN.max(numericConstants_1.ONE, volume24H)), clampMin, clampMax);
|
|
247
|
+
const shortVolSpreadFactor = (0, __1.clampBN)(shortIntensity.mul(numericConstants_1.PERCENTAGE_PRECISION).div(anchor_1.BN.max(numericConstants_1.ONE, volume24H)), clampMin, clampMax);
|
|
248
|
+
const longVolSpread = anchor_1.BN.max(lastOracleConfPct, volSpread.mul(longVolSpreadFactor).div(numericConstants_1.PERCENTAGE_PRECISION));
|
|
249
|
+
const shortVolSpread = anchor_1.BN.max(lastOracleConfPct, volSpread.mul(shortVolSpreadFactor).div(numericConstants_1.PERCENTAGE_PRECISION));
|
|
250
|
+
return [longVolSpread, shortVolSpread];
|
|
251
|
+
}
|
|
252
|
+
exports.calculateVolSpreadBN = calculateVolSpreadBN;
|
|
253
|
+
function calculateSpreadBN(baseSpread, lastOracleReservePriceSpreadPct, lastOracleConfPct, maxSpread, quoteAssetReserve, terminalQuoteAssetReserve, pegMultiplier, baseAssetAmountWithAmm, reservePrice, totalFeeMinusDistributions, netRevenueSinceLastFunding, baseAssetReserve, minBaseAssetReserve, maxBaseAssetReserve, markStd, oracleStd, longIntensity, shortIntensity, volume24H) {
|
|
254
|
+
const [longVolSpread, shortVolSpread] = calculateVolSpreadBN(lastOracleConfPct, reservePrice, markStd, oracleStd, longIntensity, shortIntensity, volume24H);
|
|
255
|
+
let longSpread = Math.max(baseSpread / 2, longVolSpread.toNumber());
|
|
256
|
+
let shortSpread = Math.max(baseSpread / 2, shortVolSpread.toNumber());
|
|
257
|
+
if (lastOracleReservePriceSpreadPct.gt(numericConstants_1.ZERO)) {
|
|
222
258
|
shortSpread = Math.max(shortSpread, lastOracleReservePriceSpreadPct.abs().toNumber() +
|
|
223
|
-
|
|
259
|
+
shortVolSpread.toNumber());
|
|
224
260
|
}
|
|
225
261
|
else if (lastOracleReservePriceSpreadPct.lt(numericConstants_1.ZERO)) {
|
|
226
262
|
longSpread = Math.max(longSpread, lastOracleReservePriceSpreadPct.abs().toNumber() +
|
|
227
|
-
|
|
263
|
+
longVolSpread.toNumber());
|
|
228
264
|
}
|
|
229
265
|
const maxTargetSpread = Math.max(maxSpread, lastOracleReservePriceSpreadPct.abs().toNumber());
|
|
230
|
-
const
|
|
231
|
-
|
|
232
|
-
const inventorySpreadScale = Math.min(MAX_BID_ASK_INVENTORY_SKEW_FACTOR, 1 + inventoryScale);
|
|
233
|
-
if (netBaseAssetAmount.gt(numericConstants_1.ZERO)) {
|
|
266
|
+
const inventorySpreadScale = calculateInventoryScale(baseAssetAmountWithAmm, baseAssetReserve, minBaseAssetReserve, maxBaseAssetReserve, baseAssetAmountWithAmm.gt(numericConstants_1.ZERO) ? longSpread : shortSpread, maxTargetSpread);
|
|
267
|
+
if (baseAssetAmountWithAmm.gt(numericConstants_1.ZERO)) {
|
|
234
268
|
longSpread *= inventorySpreadScale;
|
|
235
269
|
}
|
|
236
|
-
else if (
|
|
270
|
+
else if (baseAssetAmountWithAmm.lt(numericConstants_1.ZERO)) {
|
|
237
271
|
shortSpread *= inventorySpreadScale;
|
|
238
272
|
}
|
|
239
|
-
const
|
|
273
|
+
const MAX_SPREAD_SCALE = 10;
|
|
240
274
|
if (totalFeeMinusDistributions.gt(numericConstants_1.ZERO)) {
|
|
241
|
-
const
|
|
242
|
-
|
|
275
|
+
const effectiveLeverage = calculateEffectiveLeverage(baseSpread, quoteAssetReserve, terminalQuoteAssetReserve, pegMultiplier, baseAssetAmountWithAmm, reservePrice, totalFeeMinusDistributions);
|
|
276
|
+
const spreadScale = Math.min(MAX_SPREAD_SCALE, 1 + effectiveLeverage);
|
|
277
|
+
if (baseAssetAmountWithAmm.gt(numericConstants_1.ZERO)) {
|
|
243
278
|
longSpread *= spreadScale;
|
|
244
279
|
}
|
|
245
280
|
else {
|
|
@@ -247,26 +282,43 @@ function calculateSpreadBN(baseSpread, lastOracleReservePriceSpreadPct, lastOrac
|
|
|
247
282
|
}
|
|
248
283
|
}
|
|
249
284
|
else {
|
|
250
|
-
longSpread *=
|
|
251
|
-
shortSpread *=
|
|
285
|
+
longSpread *= MAX_SPREAD_SCALE;
|
|
286
|
+
shortSpread *= MAX_SPREAD_SCALE;
|
|
287
|
+
}
|
|
288
|
+
if (netRevenueSinceLastFunding.lt(numericConstants_1.DEFAULT_REVENUE_SINCE_LAST_FUNDING_SPREAD_RETREAT)) {
|
|
289
|
+
const retreatAmount = Math.min(maxTargetSpread / 10, Math.floor((baseSpread * netRevenueSinceLastFunding.abs().toNumber()) /
|
|
290
|
+
numericConstants_1.DEFAULT_REVENUE_SINCE_LAST_FUNDING_SPREAD_RETREAT.toNumber()));
|
|
291
|
+
const halfRetreatAmount = Math.floor(retreatAmount / 2);
|
|
292
|
+
if (baseAssetAmountWithAmm.gt(numericConstants_1.ZERO)) {
|
|
293
|
+
longSpread += retreatAmount;
|
|
294
|
+
shortSpread += halfRetreatAmount;
|
|
295
|
+
}
|
|
296
|
+
else if (baseAssetAmountWithAmm.lt(numericConstants_1.ZERO)) {
|
|
297
|
+
longSpread += halfRetreatAmount;
|
|
298
|
+
shortSpread += retreatAmount;
|
|
299
|
+
}
|
|
300
|
+
else {
|
|
301
|
+
longSpread += halfRetreatAmount;
|
|
302
|
+
shortSpread += halfRetreatAmount;
|
|
303
|
+
}
|
|
252
304
|
}
|
|
253
305
|
const totalSpread = longSpread + shortSpread;
|
|
254
306
|
if (totalSpread > maxTargetSpread) {
|
|
255
307
|
if (longSpread > shortSpread) {
|
|
256
|
-
longSpread = Math.
|
|
308
|
+
longSpread = Math.ceil((longSpread * maxTargetSpread) / totalSpread);
|
|
257
309
|
shortSpread = maxTargetSpread - longSpread;
|
|
258
310
|
}
|
|
259
311
|
else {
|
|
260
|
-
shortSpread = Math.
|
|
312
|
+
shortSpread = Math.ceil((shortSpread * maxTargetSpread) / totalSpread);
|
|
261
313
|
longSpread = maxTargetSpread - shortSpread;
|
|
262
314
|
}
|
|
263
315
|
}
|
|
264
316
|
return [longSpread, shortSpread];
|
|
265
317
|
}
|
|
266
318
|
exports.calculateSpreadBN = calculateSpreadBN;
|
|
267
|
-
function calculateSpread(amm,
|
|
319
|
+
function calculateSpread(amm, oraclePriceData) {
|
|
268
320
|
if (amm.baseSpread == 0 || amm.curveUpdateIntensity == 0) {
|
|
269
|
-
return amm.baseSpread / 2;
|
|
321
|
+
return [amm.baseSpread / 2, amm.baseSpread / 2];
|
|
270
322
|
}
|
|
271
323
|
const reservePrice = calculatePrice(amm.baseAssetReserve, amm.quoteAssetReserve, amm.pegMultiplier);
|
|
272
324
|
const targetPrice = (oraclePriceData === null || oraclePriceData === void 0 ? void 0 : oraclePriceData.price) || reservePrice;
|
|
@@ -278,38 +330,38 @@ function calculateSpread(amm, direction, oraclePriceData) {
|
|
|
278
330
|
const confIntervalPct = confInterval
|
|
279
331
|
.mul(numericConstants_1.BID_ASK_SPREAD_PRECISION)
|
|
280
332
|
.div(reservePrice);
|
|
281
|
-
const
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
}
|
|
286
|
-
else {
|
|
287
|
-
spread = shortSpread;
|
|
288
|
-
}
|
|
289
|
-
return spread;
|
|
333
|
+
const now = new anchor_1.BN(new Date().getTime() / 1000); //todo
|
|
334
|
+
const liveOracleStd = (0, oracles_1.calculateLiveOracleStd)(amm, oraclePriceData, now);
|
|
335
|
+
const [longSpread, shortSpread] = calculateSpreadBN(amm.baseSpread, targetMarkSpreadPct, confIntervalPct, amm.maxSpread, amm.quoteAssetReserve, amm.terminalQuoteAssetReserve, amm.pegMultiplier, amm.baseAssetAmountWithAmm, reservePrice, amm.totalFeeMinusDistributions, amm.netRevenueSinceLastFunding, amm.baseAssetReserve, amm.minBaseAssetReserve, amm.maxBaseAssetReserve, amm.markStd, liveOracleStd, amm.longIntensityVolume, amm.shortIntensityVolume, amm.volume24H);
|
|
336
|
+
return [longSpread, shortSpread];
|
|
290
337
|
}
|
|
291
338
|
exports.calculateSpread = calculateSpread;
|
|
292
|
-
function calculateSpreadReserves(amm,
|
|
293
|
-
|
|
294
|
-
|
|
339
|
+
function calculateSpreadReserves(amm, oraclePriceData) {
|
|
340
|
+
function calculateSpreadReserve(spread, direction, amm) {
|
|
341
|
+
if (spread === 0) {
|
|
342
|
+
return {
|
|
343
|
+
baseAssetReserve: amm.baseAssetReserve,
|
|
344
|
+
quoteAssetReserve: amm.quoteAssetReserve,
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
const quoteAssetReserveDelta = amm.quoteAssetReserve.div(numericConstants_1.BID_ASK_SPREAD_PRECISION.div(new anchor_1.BN(spread / 2)));
|
|
348
|
+
let quoteAssetReserve;
|
|
349
|
+
if ((0, types_1.isVariant)(direction, 'long')) {
|
|
350
|
+
quoteAssetReserve = amm.quoteAssetReserve.add(quoteAssetReserveDelta);
|
|
351
|
+
}
|
|
352
|
+
else {
|
|
353
|
+
quoteAssetReserve = amm.quoteAssetReserve.sub(quoteAssetReserveDelta);
|
|
354
|
+
}
|
|
355
|
+
const baseAssetReserve = amm.sqrtK.mul(amm.sqrtK).div(quoteAssetReserve);
|
|
295
356
|
return {
|
|
296
|
-
baseAssetReserve
|
|
297
|
-
quoteAssetReserve
|
|
357
|
+
baseAssetReserve,
|
|
358
|
+
quoteAssetReserve,
|
|
298
359
|
};
|
|
299
360
|
}
|
|
300
|
-
const
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
}
|
|
305
|
-
else {
|
|
306
|
-
quoteAssetReserve = amm.quoteAssetReserve.sub(quoteAsserReserveDelta);
|
|
307
|
-
}
|
|
308
|
-
const baseAssetReserve = amm.sqrtK.mul(amm.sqrtK).div(quoteAssetReserve);
|
|
309
|
-
return {
|
|
310
|
-
baseAssetReserve,
|
|
311
|
-
quoteAssetReserve,
|
|
312
|
-
};
|
|
361
|
+
const [longSpread, shortSpread] = calculateSpread(amm, oraclePriceData);
|
|
362
|
+
const askReserves = calculateSpreadReserve(longSpread, types_1.PositionDirection.LONG, amm);
|
|
363
|
+
const bidReserves = calculateSpreadReserve(shortSpread, types_1.PositionDirection.SHORT, amm);
|
|
364
|
+
return [bidReserves, askReserves];
|
|
313
365
|
}
|
|
314
366
|
exports.calculateSpreadReserves = calculateSpreadReserves;
|
|
315
367
|
/**
|
|
@@ -376,7 +428,10 @@ function calculateMaxBaseAssetAmountToTrade(amm, limit_price, direction, oracleP
|
|
|
376
428
|
.div(limit_price)
|
|
377
429
|
.div(numericConstants_1.PEG_PRECISION);
|
|
378
430
|
const newBaseAssetReserve = (0, __1.squareRootBN)(newBaseAssetReserveSquared);
|
|
379
|
-
const
|
|
431
|
+
const [shortSpreadReserves, longSpreadReserves] = calculateSpreadReserves(amm, oraclePriceData);
|
|
432
|
+
const baseAssetReserveBefore = (0, types_1.isVariant)(direction, 'long')
|
|
433
|
+
? longSpreadReserves.baseAssetReserve
|
|
434
|
+
: shortSpreadReserves.baseAssetReserve;
|
|
380
435
|
if (newBaseAssetReserve.gt(baseAssetReserveBefore)) {
|
|
381
436
|
return [
|
|
382
437
|
newBaseAssetReserve.sub(baseAssetReserveBefore),
|
package/lib/math/oracles.d.ts
CHANGED
|
@@ -5,3 +5,5 @@ import { BN, PerpMarketAccount } from '../index';
|
|
|
5
5
|
export declare function oraclePriceBands(market: PerpMarketAccount, oraclePriceData: OraclePriceData): [BN, BN];
|
|
6
6
|
export declare function isOracleValid(amm: AMM, oraclePriceData: OraclePriceData, oracleGuardRails: OracleGuardRails, slot: number): boolean;
|
|
7
7
|
export declare function isOracleTooDivergent(amm: AMM, oraclePriceData: OraclePriceData, oracleGuardRails: OracleGuardRails, now: BN): boolean;
|
|
8
|
+
export declare function calculateLiveOracleTwap(amm: AMM, oraclePriceData: OraclePriceData, now: BN): BN;
|
|
9
|
+
export declare function calculateLiveOracleStd(amm: AMM, oraclePriceData: OraclePriceData, now: BN): BN;
|
package/lib/math/oracles.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.isOracleTooDivergent = exports.isOracleValid = exports.oraclePriceBands = void 0;
|
|
3
|
+
exports.calculateLiveOracleStd = exports.calculateLiveOracleTwap = exports.isOracleTooDivergent = exports.isOracleValid = exports.oraclePriceBands = void 0;
|
|
4
4
|
const numericConstants_1 = require("../constants/numericConstants");
|
|
5
5
|
const index_1 = require("../index");
|
|
6
6
|
const assert_1 = require("../assert/assert");
|
|
@@ -52,3 +52,25 @@ function isOracleTooDivergent(amm, oraclePriceData, oracleGuardRails, now) {
|
|
|
52
52
|
return tooDivergent;
|
|
53
53
|
}
|
|
54
54
|
exports.isOracleTooDivergent = isOracleTooDivergent;
|
|
55
|
+
function calculateLiveOracleTwap(amm, oraclePriceData, now) {
|
|
56
|
+
const sinceLastUpdate = now.sub(amm.historicalOracleData.lastOraclePriceTwapTs);
|
|
57
|
+
const sinceStart = index_1.BN.max(numericConstants_1.ZERO, amm.fundingPeriod.sub(sinceLastUpdate));
|
|
58
|
+
const clampRange = amm.historicalOracleData.lastOraclePriceTwap.div(new index_1.BN(3));
|
|
59
|
+
const clampedOraclePrice = index_1.BN.min(amm.historicalOracleData.lastOraclePriceTwap.add(clampRange), index_1.BN.max(oraclePriceData.price, amm.historicalOracleData.lastOraclePriceTwap.sub(clampRange)));
|
|
60
|
+
const newOracleTwap = amm.historicalOracleData.lastOraclePriceTwap
|
|
61
|
+
.mul(sinceStart)
|
|
62
|
+
.add(clampedOraclePrice)
|
|
63
|
+
.mul(sinceLastUpdate)
|
|
64
|
+
.div(sinceStart.add(sinceLastUpdate));
|
|
65
|
+
return newOracleTwap;
|
|
66
|
+
}
|
|
67
|
+
exports.calculateLiveOracleTwap = calculateLiveOracleTwap;
|
|
68
|
+
function calculateLiveOracleStd(amm, oraclePriceData, now) {
|
|
69
|
+
const sinceLastUpdate = now.sub(amm.historicalOracleData.lastOraclePriceTwapTs);
|
|
70
|
+
const sinceStart = index_1.BN.max(numericConstants_1.ZERO, amm.fundingPeriod.sub(sinceLastUpdate));
|
|
71
|
+
const liveOracleTwap = calculateLiveOracleTwap(amm, oraclePriceData, now);
|
|
72
|
+
const priceDeltaVsTwap = oraclePriceData.price.sub(liveOracleTwap).abs();
|
|
73
|
+
const oracleStd = priceDeltaVsTwap.add(amm.oracleStd.mul(sinceStart).div(sinceStart.add(sinceLastUpdate)));
|
|
74
|
+
return oracleStd;
|
|
75
|
+
}
|
|
76
|
+
exports.calculateLiveOracleStd = calculateLiveOracleStd;
|
package/lib/math/utils.d.ts
CHANGED
package/lib/math/utils.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.squareRootBN = void 0;
|
|
3
|
+
exports.squareRootBN = exports.clampBN = void 0;
|
|
4
4
|
const __1 = require("../");
|
|
5
|
+
function clampBN(x, min, max) {
|
|
6
|
+
return __1.BN.max(min, __1.BN.min(x, max));
|
|
7
|
+
}
|
|
8
|
+
exports.clampBN = clampBN;
|
|
5
9
|
const squareRootBN = (n, closeness = new __1.BN(1)) => {
|
|
6
10
|
// Assuming the sqrt of n as n only
|
|
7
11
|
let x = n;
|
package/lib/types.d.ts
CHANGED
|
@@ -606,6 +606,8 @@ export declare type StateAccount = {
|
|
|
606
606
|
perpFeeStructure: FeeStructure;
|
|
607
607
|
spotFeeStructure: FeeStructure;
|
|
608
608
|
lpCooldownTime: BN;
|
|
609
|
+
initialPctToLiquidate: number;
|
|
610
|
+
liquidationDuration: number;
|
|
609
611
|
};
|
|
610
612
|
export declare type PerpMarketAccount = {
|
|
611
613
|
status: MarketStatus;
|
|
@@ -805,8 +807,8 @@ export declare type PerpPosition = {
|
|
|
805
807
|
settledPnl: BN;
|
|
806
808
|
lpShares: BN;
|
|
807
809
|
remainderBaseAssetAmount: number;
|
|
808
|
-
|
|
809
|
-
|
|
810
|
+
lastBaseAssetAmountPerLp: BN;
|
|
811
|
+
lastQuoteAssetAmountPerLp: BN;
|
|
810
812
|
};
|
|
811
813
|
export declare type UserStatsAccount = {
|
|
812
814
|
numberOfSubAccounts: number;
|
|
@@ -848,6 +850,8 @@ export declare type UserAccount = {
|
|
|
848
850
|
totalWithdraws: BN;
|
|
849
851
|
totalSocialLoss: BN;
|
|
850
852
|
cumulativePerpFunding: BN;
|
|
853
|
+
liquidationMarginFreed: BN;
|
|
854
|
+
liquidationStartSlot: BN;
|
|
851
855
|
};
|
|
852
856
|
export declare type SpotPosition = {
|
|
853
857
|
marketIndex: number;
|
package/lib/user.js
CHANGED
|
@@ -85,8 +85,8 @@ class User {
|
|
|
85
85
|
openAsks: numericConstants_1.ZERO,
|
|
86
86
|
settledPnl: numericConstants_1.ZERO,
|
|
87
87
|
lpShares: numericConstants_1.ZERO,
|
|
88
|
-
|
|
89
|
-
|
|
88
|
+
lastBaseAssetAmountPerLp: numericConstants_1.ZERO,
|
|
89
|
+
lastQuoteAssetAmountPerLp: numericConstants_1.ZERO,
|
|
90
90
|
};
|
|
91
91
|
}
|
|
92
92
|
getClonedPosition(position) {
|
|
@@ -161,11 +161,11 @@ class User {
|
|
|
161
161
|
const market = this.driftClient.getPerpMarketAccount(position.marketIndex);
|
|
162
162
|
const nShares = position.lpShares;
|
|
163
163
|
const deltaBaa = market.amm.baseAssetAmountPerLp
|
|
164
|
-
.sub(position.
|
|
164
|
+
.sub(position.lastBaseAssetAmountPerLp)
|
|
165
165
|
.mul(nShares)
|
|
166
166
|
.div(numericConstants_1.AMM_RESERVE_PRECISION);
|
|
167
167
|
const deltaQaa = market.amm.quoteAssetAmountPerLp
|
|
168
|
-
.sub(position.
|
|
168
|
+
.sub(position.lastQuoteAssetAmountPerLp)
|
|
169
169
|
.mul(nShares)
|
|
170
170
|
.div(numericConstants_1.AMM_RESERVE_PRECISION);
|
|
171
171
|
function sign(v) {
|
|
@@ -364,6 +364,7 @@ class User {
|
|
|
364
364
|
newTotalLiabilityValue =
|
|
365
365
|
newTotalLiabilityValue.add(weightedTokenValue);
|
|
366
366
|
}
|
|
367
|
+
newTotalLiabilityValue = newTotalLiabilityValue.add(new _1.BN(spotPosition.openOrders).mul(numericConstants_1.OPEN_ORDER_MARGIN_REQUIREMENT));
|
|
367
368
|
return newTotalLiabilityValue;
|
|
368
369
|
}, numericConstants_1.ZERO);
|
|
369
370
|
}
|
|
@@ -523,6 +524,9 @@ class User {
|
|
|
523
524
|
baseAssetValue = baseAssetValue
|
|
524
525
|
.mul(marginRatio)
|
|
525
526
|
.div(numericConstants_1.MARGIN_PRECISION);
|
|
527
|
+
if (includeOpenOrders) {
|
|
528
|
+
baseAssetValue = baseAssetValue.add(new _1.BN(perpPosition.openOrders).mul(numericConstants_1.OPEN_ORDER_MARGIN_REQUIREMENT));
|
|
529
|
+
}
|
|
526
530
|
}
|
|
527
531
|
return totalPerpValue.add(baseAssetValue);
|
|
528
532
|
}, numericConstants_1.ZERO);
|
|
@@ -760,8 +764,8 @@ class User {
|
|
|
760
764
|
openAsks: new _1.BN(0),
|
|
761
765
|
settledPnl: numericConstants_1.ZERO,
|
|
762
766
|
lpShares: numericConstants_1.ZERO,
|
|
763
|
-
|
|
764
|
-
|
|
767
|
+
lastBaseAssetAmountPerLp: numericConstants_1.ZERO,
|
|
768
|
+
lastQuoteAssetAmountPerLp: numericConstants_1.ZERO,
|
|
765
769
|
};
|
|
766
770
|
if (proposedBaseAssetAmount.eq(numericConstants_1.ZERO))
|
|
767
771
|
return new _1.BN(-1);
|
package/package.json
CHANGED
|
@@ -317,10 +317,6 @@ export class PollingDriftClientAccountSubscriber
|
|
|
317
317
|
}
|
|
318
318
|
|
|
319
319
|
public async unsubscribe(): Promise<void> {
|
|
320
|
-
if (!this.isSubscribed) {
|
|
321
|
-
return;
|
|
322
|
-
}
|
|
323
|
-
|
|
324
320
|
for (const [_, accountToPoll] of this.accountsToPoll) {
|
|
325
321
|
this.accountLoader.removeAccount(
|
|
326
322
|
accountToPoll.publicKey,
|
|
@@ -132,10 +132,6 @@ export class PollingUserStatsAccountSubscriber
|
|
|
132
132
|
}
|
|
133
133
|
|
|
134
134
|
async unsubscribe(): Promise<void> {
|
|
135
|
-
if (!this.isSubscribed) {
|
|
136
|
-
return;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
135
|
for (const [_, accountToPoll] of this.accountsToPoll) {
|
|
140
136
|
this.accountLoader.removeAccount(
|
|
141
137
|
accountToPoll.publicKey,
|
package/src/adminClient.ts
CHANGED
|
@@ -606,6 +606,34 @@ export class AdminClient extends DriftClient {
|
|
|
606
606
|
});
|
|
607
607
|
}
|
|
608
608
|
|
|
609
|
+
public async updateInitialPctToLiquidate(
|
|
610
|
+
initialPctToLiquidate: number
|
|
611
|
+
): Promise<TransactionSignature> {
|
|
612
|
+
return await this.program.rpc.updateInitialPctToLiquidate(
|
|
613
|
+
initialPctToLiquidate,
|
|
614
|
+
{
|
|
615
|
+
accounts: {
|
|
616
|
+
admin: this.wallet.publicKey,
|
|
617
|
+
state: await this.getStatePublicKey(),
|
|
618
|
+
},
|
|
619
|
+
}
|
|
620
|
+
);
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
public async updateLiquidationDuration(
|
|
624
|
+
liquidationDuration: number
|
|
625
|
+
): Promise<TransactionSignature> {
|
|
626
|
+
return await this.program.rpc.updateLiquidationDuration(
|
|
627
|
+
liquidationDuration,
|
|
628
|
+
{
|
|
629
|
+
accounts: {
|
|
630
|
+
admin: this.wallet.publicKey,
|
|
631
|
+
state: await this.getStatePublicKey(),
|
|
632
|
+
},
|
|
633
|
+
}
|
|
634
|
+
);
|
|
635
|
+
}
|
|
636
|
+
|
|
609
637
|
public async updateOracleGuardRails(
|
|
610
638
|
oracleGuardRails: OracleGuardRails
|
|
611
639
|
): Promise<TransactionSignature> {
|
|
@@ -81,6 +81,7 @@ export const AMM_TIMES_PEG_TO_QUOTE_PRECISION_RATIO =
|
|
|
81
81
|
AMM_RESERVE_PRECISION.mul(PEG_PRECISION).div(QUOTE_PRECISION); // 10^9
|
|
82
82
|
export const MARGIN_PRECISION = TEN_THOUSAND;
|
|
83
83
|
export const BID_ASK_SPREAD_PRECISION = new BN(1000000); // 10^6
|
|
84
|
+
export const LIQUIDATION_PCT_PRECISION = TEN_THOUSAND;
|
|
84
85
|
|
|
85
86
|
export const ONE_YEAR = new BN(31536000);
|
|
86
87
|
|
|
@@ -88,3 +89,9 @@ export const QUOTE_SPOT_MARKET_INDEX = 0;
|
|
|
88
89
|
|
|
89
90
|
export const LAMPORTS_PRECISION = new BN(LAMPORTS_PER_SOL);
|
|
90
91
|
export const LAMPORTS_EXP = new BN(Math.log10(LAMPORTS_PER_SOL));
|
|
92
|
+
|
|
93
|
+
export const OPEN_ORDER_MARGIN_REQUIREMENT = QUOTE_PRECISION.div(new BN(100));
|
|
94
|
+
|
|
95
|
+
export const DEFAULT_REVENUE_SINCE_LAST_FUNDING_SPREAD_RETREAT = new BN(
|
|
96
|
+
-25
|
|
97
|
+
).mul(QUOTE_PRECISION);
|