@drift-labs/sdk 0.1.23-master.4 → 0.1.26
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/lib/accounts/bulkAccountLoader.d.ts +2 -0
- package/lib/accounts/bulkAccountLoader.js +24 -0
- package/lib/addresses.js +5 -1
- package/lib/admin.d.ts +2 -2
- package/lib/admin.js +11 -5
- package/lib/clearingHouse.js +7 -1
- package/lib/clearingHouseUser.d.ts +12 -17
- package/lib/clearingHouseUser.js +114 -217
- package/lib/constants/markets.d.ts +6 -4
- package/lib/constants/markets.js +48 -0
- package/lib/constants/numericConstants.d.ts +2 -2
- package/lib/constants/numericConstants.js +3 -3
- package/lib/factory/oracleClient.d.ts +5 -0
- package/lib/factory/oracleClient.js +16 -0
- package/lib/idl/clearing_house.json +58 -5
- package/lib/idl/switchboard_v2.json +4663 -0
- package/lib/index.d.ts +4 -1
- package/lib/index.js +9 -2
- package/lib/math/funding.d.ts +6 -6
- package/lib/math/funding.js +4 -16
- package/lib/math/orders.d.ts +1 -0
- package/lib/math/orders.js +19 -1
- package/lib/mockUSDCFaucet.js +5 -1
- package/lib/oracles/pythClient.d.ts +14 -0
- package/lib/oracles/pythClient.js +53 -0
- package/lib/oracles/switchboardClient.d.ts +13 -0
- package/lib/oracles/switchboardClient.js +76 -0
- package/lib/oracles/types.d.ts +15 -0
- package/lib/oracles/types.js +2 -0
- package/lib/orderParams.d.ts +1 -1
- package/lib/orderParams.js +2 -2
- package/lib/orders.js +1 -1
- package/lib/types.d.ts +5 -1
- package/package.json +2 -1
- package/src/accounts/bulkAccountLoader.ts +32 -0
- package/src/accounts/types.js +10 -0
- package/src/accounts/utils.js +7 -0
- package/src/accounts/webSocketAccountSubscriber.js +76 -0
- package/src/addresses.js +83 -0
- package/src/admin.ts +15 -4
- package/src/clearingHouse.ts +2 -0
- package/src/clearingHouseUser.ts +161 -330
- package/src/constants/markets.ts +54 -3
- package/src/constants/numericConstants.ts +2 -2
- package/src/factory/oracleClient.ts +22 -0
- package/src/idl/clearing_house.json +58 -5
- package/src/idl/switchboard_v2.json +4663 -0
- package/src/index.ts +4 -1
- package/src/math/funding.ts +9 -25
- package/src/math/orders.ts +28 -0
- package/src/mockUSDCFaucet.js +171 -0
- package/src/oracles/pythClient.ts +49 -0
- package/src/oracles/switchboardClient.ts +87 -0
- package/src/oracles/types.ts +15 -0
- package/src/orderParams.ts +3 -2
- package/src/orders.ts +1 -1
- package/src/types.js +60 -0
- package/src/types.ts +6 -1
- package/lib/pythClient.d.ts +0 -7
- package/lib/pythClient.js +0 -25
- package/src/pythClient.ts +0 -15
package/lib/clearingHouseUser.js
CHANGED
|
@@ -10,6 +10,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.ClearingHouseUser = void 0;
|
|
13
|
+
const types_1 = require("./types");
|
|
13
14
|
const position_1 = require("./math/position");
|
|
14
15
|
const numericConstants_1 = require("./constants/numericConstants");
|
|
15
16
|
const _1 = require(".");
|
|
@@ -136,19 +137,39 @@ class ClearingHouseUser {
|
|
|
136
137
|
* calculates Buying Power = FC * MAX_LEVERAGE
|
|
137
138
|
* @returns : Precision QUOTE_PRECISION
|
|
138
139
|
*/
|
|
139
|
-
getBuyingPower() {
|
|
140
|
+
getBuyingPower(marketIndex) {
|
|
140
141
|
return this.getFreeCollateral()
|
|
141
|
-
.mul(this.getMaxLeverage('Initial'))
|
|
142
|
+
.mul(this.getMaxLeverage(marketIndex, 'Initial'))
|
|
142
143
|
.div(numericConstants_1.TEN_THOUSAND);
|
|
143
144
|
}
|
|
144
145
|
/**
|
|
145
|
-
* calculates Free Collateral =
|
|
146
|
+
* calculates Free Collateral = Total collateral - initial margin requirement
|
|
146
147
|
* @returns : Precision QUOTE_PRECISION
|
|
147
148
|
*/
|
|
148
149
|
getFreeCollateral() {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
150
|
+
const totalCollateral = this.getTotalCollateral();
|
|
151
|
+
const initialMarginRequirement = this.getInitialMarginRequirement();
|
|
152
|
+
const freeCollateral = totalCollateral.sub(initialMarginRequirement);
|
|
153
|
+
return freeCollateral.gte(numericConstants_1.ZERO) ? freeCollateral : numericConstants_1.ZERO;
|
|
154
|
+
}
|
|
155
|
+
getInitialMarginRequirement() {
|
|
156
|
+
return this.getUserPositionsAccount().positions.reduce((marginRequirement, marketPosition) => {
|
|
157
|
+
const market = this.clearingHouse.getMarket(marketPosition.marketIndex);
|
|
158
|
+
return marginRequirement.add((0, _1.calculateBaseAssetValue)(market, marketPosition)
|
|
159
|
+
.mul(new _1.BN(market.marginRatioInitial))
|
|
160
|
+
.div(numericConstants_1.MARGIN_PRECISION));
|
|
161
|
+
}, numericConstants_1.ZERO);
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* @returns The partial margin requirement in USDC. : QUOTE_PRECISION
|
|
165
|
+
*/
|
|
166
|
+
getPartialMarginRequirement() {
|
|
167
|
+
return this.getUserPositionsAccount().positions.reduce((marginRequirement, marketPosition) => {
|
|
168
|
+
const market = this.clearingHouse.getMarket(marketPosition.marketIndex);
|
|
169
|
+
return marginRequirement.add((0, _1.calculateBaseAssetValue)(market, marketPosition)
|
|
170
|
+
.mul(new _1.BN(market.marginRatioPartial))
|
|
171
|
+
.div(numericConstants_1.MARGIN_PRECISION));
|
|
172
|
+
}, numericConstants_1.ZERO);
|
|
152
173
|
}
|
|
153
174
|
/**
|
|
154
175
|
* calculates unrealized position price pnl
|
|
@@ -262,24 +283,24 @@ class ClearingHouseUser {
|
|
|
262
283
|
* @params category {Initial, Partial, Maintenance}
|
|
263
284
|
* @returns : Precision TEN_THOUSAND
|
|
264
285
|
*/
|
|
265
|
-
getMaxLeverage(category) {
|
|
266
|
-
const
|
|
286
|
+
getMaxLeverage(marketIndex, category = 'Initial') {
|
|
287
|
+
const market = this.clearingHouse.getMarket(marketIndex);
|
|
267
288
|
let marginRatioCategory;
|
|
268
289
|
switch (category) {
|
|
269
290
|
case 'Initial':
|
|
270
|
-
marginRatioCategory =
|
|
291
|
+
marginRatioCategory = market.marginRatioInitial;
|
|
271
292
|
break;
|
|
272
293
|
case 'Maintenance':
|
|
273
|
-
marginRatioCategory =
|
|
294
|
+
marginRatioCategory = market.marginRatioMaintenance;
|
|
274
295
|
break;
|
|
275
296
|
case 'Partial':
|
|
276
|
-
marginRatioCategory =
|
|
297
|
+
marginRatioCategory = market.marginRatioPartial;
|
|
277
298
|
break;
|
|
278
299
|
default:
|
|
279
|
-
marginRatioCategory =
|
|
300
|
+
marginRatioCategory = market.marginRatioInitial;
|
|
280
301
|
break;
|
|
281
302
|
}
|
|
282
|
-
const maxLeverage = numericConstants_1.TEN_THOUSAND.mul(numericConstants_1.TEN_THOUSAND).div(marginRatioCategory);
|
|
303
|
+
const maxLeverage = numericConstants_1.TEN_THOUSAND.mul(numericConstants_1.TEN_THOUSAND).div(new _1.BN(marginRatioCategory));
|
|
283
304
|
return maxLeverage;
|
|
284
305
|
}
|
|
285
306
|
/**
|
|
@@ -294,8 +315,10 @@ class ClearingHouseUser {
|
|
|
294
315
|
return this.getTotalCollateral().mul(numericConstants_1.TEN_THOUSAND).div(totalPositionValue);
|
|
295
316
|
}
|
|
296
317
|
canBeLiquidated() {
|
|
318
|
+
const totalCollateral = this.getTotalCollateral();
|
|
319
|
+
const partialMaintenanceRequirement = this.getPartialMarginRequirement();
|
|
297
320
|
const marginRatio = this.getMarginRatio();
|
|
298
|
-
const canLiquidate =
|
|
321
|
+
const canLiquidate = totalCollateral.lt(partialMaintenanceRequirement);
|
|
299
322
|
return [canLiquidate, marginRatio];
|
|
300
323
|
}
|
|
301
324
|
/**
|
|
@@ -319,97 +342,13 @@ class ClearingHouseUser {
|
|
|
319
342
|
}
|
|
320
343
|
/**
|
|
321
344
|
* Calculate the liquidation price of a position, with optional parameter to calculate the liquidation price after a trade
|
|
322
|
-
* @param
|
|
345
|
+
* @param marketPosition
|
|
323
346
|
* @param positionBaseSizeChange // change in position size to calculate liquidation price for : Precision 10^13
|
|
324
347
|
* @param partial
|
|
325
348
|
* @returns Precision : MARK_PRICE_PRECISION
|
|
326
349
|
*/
|
|
327
|
-
|
|
328
|
-
//
|
|
329
|
-
// todo: margin_ratio is not symmetric on price action (both numer and denom change)
|
|
330
|
-
// margin_ratio = collateral / base_asset_value
|
|
331
|
-
/* example: assume BTC price is $40k (examine 10% up/down)
|
|
332
|
-
|
|
333
|
-
if 10k deposit and levered 10x short BTC => BTC up $400 means:
|
|
334
|
-
1. higher base_asset_value (+$4k)
|
|
335
|
-
2. lower collateral (-$4k)
|
|
336
|
-
3. (10k - 4k)/(100k + 4k) => 6k/104k => .0576
|
|
337
|
-
|
|
338
|
-
for 10x long, BTC down $400:
|
|
339
|
-
3. (10k - 4k) / (100k - 4k) = 6k/96k => .0625 */
|
|
340
|
-
const currentPrice = (0, _1.calculateMarkPrice)(this.clearingHouse.getMarket(targetMarket.marketIndex));
|
|
341
|
-
const totalCollateralUSDC = this.getTotalCollateral();
|
|
342
|
-
// calculate the total position value ignoring any value from the target market of the trade
|
|
343
|
-
const totalCurrentPositionValueIgnoringTargetUSDC = this.getTotalPositionValueExcludingMarket(targetMarket.marketIndex);
|
|
344
|
-
const currentMarketPosition = this.getUserPosition(targetMarket.marketIndex) ||
|
|
345
|
-
this.getEmptyPosition(targetMarket.marketIndex);
|
|
346
|
-
const currentMarketPositionBaseSize = currentMarketPosition.baseAssetAmount;
|
|
347
|
-
// calculate position for current market after trade
|
|
348
|
-
const proposedMarketPosition = {
|
|
349
|
-
marketIndex: targetMarket.marketIndex,
|
|
350
|
-
baseAssetAmount: currentMarketPositionBaseSize.add(positionBaseSizeChange),
|
|
351
|
-
lastCumulativeFundingRate: new _1.BN(0),
|
|
352
|
-
quoteAssetAmount: new _1.BN(0),
|
|
353
|
-
openOrders: new _1.BN(0),
|
|
354
|
-
};
|
|
355
|
-
const market = this.clearingHouse.getMarket(proposedMarketPosition.marketIndex);
|
|
356
|
-
const proposedMarketPositionValueUSDC = (0, _1.calculateBaseAssetValue)(market, proposedMarketPosition);
|
|
357
|
-
// total position value after trade
|
|
358
|
-
const targetTotalPositionValueUSDC = totalCurrentPositionValueIgnoringTargetUSDC.add(proposedMarketPositionValueUSDC);
|
|
359
|
-
let totalFreeCollateralUSDC = this.getTotalCollateral().sub(this.getTotalPositionValue()
|
|
360
|
-
.mul(numericConstants_1.TEN_THOUSAND)
|
|
361
|
-
.div(this.getMaxLeverage('Maintenance')));
|
|
362
|
-
if (partial) {
|
|
363
|
-
totalFreeCollateralUSDC = this.getTotalCollateral().sub(this.getTotalPositionValue()
|
|
364
|
-
.mul(numericConstants_1.TEN_THOUSAND)
|
|
365
|
-
.div(this.getMaxLeverage('Partial')));
|
|
366
|
-
}
|
|
367
|
-
// if the position value after the trade is less than total collateral, there is no liq price
|
|
368
|
-
if (targetTotalPositionValueUSDC.lte(totalFreeCollateralUSDC) &&
|
|
369
|
-
proposedMarketPosition.baseAssetAmount.gt(numericConstants_1.ZERO)) {
|
|
370
|
-
return new _1.BN(-1);
|
|
371
|
-
}
|
|
372
|
-
// get current margin ratio based on current collateral and proposed total position value
|
|
373
|
-
let marginRatio;
|
|
374
|
-
if (proposedMarketPositionValueUSDC.eq(numericConstants_1.ZERO)) {
|
|
375
|
-
marginRatio = numericConstants_1.BN_MAX;
|
|
376
|
-
}
|
|
377
|
-
else {
|
|
378
|
-
marginRatio = totalCollateralUSDC
|
|
379
|
-
.mul(numericConstants_1.TEN_THOUSAND)
|
|
380
|
-
.div(proposedMarketPositionValueUSDC);
|
|
381
|
-
}
|
|
382
|
-
let liqRatio = numericConstants_1.FULL_LIQUIDATION_RATIO;
|
|
383
|
-
if (partial) {
|
|
384
|
-
liqRatio = numericConstants_1.PARTIAL_LIQUIDATION_RATIO;
|
|
385
|
-
}
|
|
386
|
-
// sign of position in current market after the trade
|
|
387
|
-
const baseAssetSignIsNeg = proposedMarketPosition.baseAssetAmount.isNeg();
|
|
388
|
-
let pctChange = marginRatio.abs().sub(liqRatio);
|
|
389
|
-
// if user is short, higher price is liq
|
|
390
|
-
if (baseAssetSignIsNeg) {
|
|
391
|
-
pctChange = pctChange.add(numericConstants_1.TEN_THOUSAND);
|
|
392
|
-
}
|
|
393
|
-
else {
|
|
394
|
-
if (numericConstants_1.TEN_THOUSAND.lte(pctChange)) {
|
|
395
|
-
// no liquidation price, position is a fully/over collateralized long
|
|
396
|
-
// handle as NaN on UI
|
|
397
|
-
return new _1.BN(-1);
|
|
398
|
-
}
|
|
399
|
-
pctChange = numericConstants_1.TEN_THOUSAND.sub(pctChange);
|
|
400
|
-
}
|
|
401
|
-
const liqPrice = currentPrice.mul(pctChange).div(numericConstants_1.TEN_THOUSAND);
|
|
402
|
-
return liqPrice;
|
|
403
|
-
}
|
|
404
|
-
/**
|
|
405
|
-
* Calculate the liquidation price of a position, with optional parameter to calculate the liquidation price after a trade
|
|
406
|
-
* @param targetMarket
|
|
407
|
-
* @param positionBaseSizeChange // change in position size to calculate liquidation price for : Precision 10^13
|
|
408
|
-
* @param partial
|
|
409
|
-
* @returns Precision : MARK_PRICE_PRECISION
|
|
410
|
-
*/
|
|
411
|
-
liquidationPrice(targetMarket, positionBaseSizeChange = numericConstants_1.ZERO, partial = false) {
|
|
412
|
-
// solves formula for example calc below
|
|
350
|
+
liquidationPrice(marketPosition, positionBaseSizeChange = numericConstants_1.ZERO, partial = false) {
|
|
351
|
+
// solves formula for example canBeLiquidated below
|
|
413
352
|
/* example: assume BTC price is $40k (examine 10% up/down)
|
|
414
353
|
|
|
415
354
|
if 10k deposit and levered 10x short BTC => BTC up $400 means:
|
|
@@ -419,77 +358,86 @@ class ClearingHouseUser {
|
|
|
419
358
|
|
|
420
359
|
for 10x long, BTC down $400:
|
|
421
360
|
3. (10k - 4k) / (100k - 4k) = 6k/96k => .0625 */
|
|
422
|
-
const
|
|
423
|
-
const tpv = this.getTotalPositionValue();
|
|
424
|
-
const partialLev = 16;
|
|
425
|
-
const maintLev = 20;
|
|
426
|
-
const thisLev = partial ? new _1.BN(partialLev) : new _1.BN(maintLev);
|
|
361
|
+
const totalCollateral = this.getTotalCollateral();
|
|
427
362
|
// calculate the total position value ignoring any value from the target market of the trade
|
|
428
|
-
const
|
|
429
|
-
const currentMarketPosition = this.getUserPosition(
|
|
430
|
-
this.getEmptyPosition(
|
|
363
|
+
const totalPositionValueExcludingTargetMarket = this.getTotalPositionValueExcludingMarket(marketPosition.marketIndex);
|
|
364
|
+
const currentMarketPosition = this.getUserPosition(marketPosition.marketIndex) ||
|
|
365
|
+
this.getEmptyPosition(marketPosition.marketIndex);
|
|
431
366
|
const currentMarketPositionBaseSize = currentMarketPosition.baseAssetAmount;
|
|
432
367
|
const proposedBaseAssetAmount = currentMarketPositionBaseSize.add(positionBaseSizeChange);
|
|
433
368
|
// calculate position for current market after trade
|
|
434
369
|
const proposedMarketPosition = {
|
|
435
|
-
marketIndex:
|
|
370
|
+
marketIndex: marketPosition.marketIndex,
|
|
436
371
|
baseAssetAmount: proposedBaseAssetAmount,
|
|
437
372
|
lastCumulativeFundingRate: currentMarketPosition.lastCumulativeFundingRate,
|
|
438
373
|
quoteAssetAmount: new _1.BN(0),
|
|
439
374
|
openOrders: new _1.BN(0),
|
|
440
375
|
};
|
|
376
|
+
if (proposedBaseAssetAmount.eq(numericConstants_1.ZERO))
|
|
377
|
+
return new _1.BN(-1);
|
|
441
378
|
const market = this.clearingHouse.getMarket(proposedMarketPosition.marketIndex);
|
|
442
|
-
const
|
|
379
|
+
const proposedMarketPositionValue = (0, _1.calculateBaseAssetValue)(market, proposedMarketPosition);
|
|
443
380
|
// total position value after trade
|
|
444
|
-
const
|
|
445
|
-
|
|
446
|
-
.
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
381
|
+
const totalPositionValueAfterTrade = totalPositionValueExcludingTargetMarket.add(proposedMarketPositionValue);
|
|
382
|
+
const marginRequirementExcludingTargetMarket = this.getUserPositionsAccount().positions.reduce((totalMarginRequirement, position) => {
|
|
383
|
+
if (!position.marketIndex.eq(marketPosition.marketIndex)) {
|
|
384
|
+
const market = this.clearingHouse.getMarket(position.marketIndex);
|
|
385
|
+
const positionValue = (0, _1.calculateBaseAssetValue)(market, position);
|
|
386
|
+
const marketMarginRequirement = positionValue
|
|
387
|
+
.mul(partial
|
|
388
|
+
? new _1.BN(market.marginRatioPartial)
|
|
389
|
+
: new _1.BN(market.marginRatioMaintenance))
|
|
390
|
+
.div(numericConstants_1.MARGIN_PRECISION);
|
|
391
|
+
totalMarginRequirement = totalMarginRequirement.add(marketMarginRequirement);
|
|
392
|
+
}
|
|
393
|
+
return totalMarginRequirement;
|
|
394
|
+
}, numericConstants_1.ZERO);
|
|
395
|
+
const freeCollateralExcludingTargetMarket = totalCollateral.sub(marginRequirementExcludingTargetMarket);
|
|
396
|
+
// if the position value after the trade is less than free collateral, there is no liq price
|
|
397
|
+
if (totalPositionValueAfterTrade.lte(freeCollateralExcludingTargetMarket) &&
|
|
398
|
+
proposedMarketPosition.baseAssetAmount.abs().gt(numericConstants_1.ZERO)) {
|
|
399
|
+
return new _1.BN(-1);
|
|
452
400
|
}
|
|
453
|
-
|
|
401
|
+
const marginRequirementAfterTrade = marginRequirementExcludingTargetMarket.add(proposedMarketPositionValue
|
|
402
|
+
.mul(partial
|
|
403
|
+
? new _1.BN(market.marginRatioPartial)
|
|
404
|
+
: new _1.BN(market.marginRatioMaintenance))
|
|
405
|
+
.div(numericConstants_1.MARGIN_PRECISION));
|
|
406
|
+
const freeCollateralAfterTrade = totalCollateral.sub(marginRequirementAfterTrade);
|
|
407
|
+
const marketMaxLeverage = partial
|
|
408
|
+
? this.getMaxLeverage(proposedMarketPosition.marketIndex, 'Partial')
|
|
409
|
+
: this.getMaxLeverage(proposedMarketPosition.marketIndex, 'Maintenance');
|
|
410
|
+
let priceDelta;
|
|
454
411
|
if (proposedBaseAssetAmount.lt(numericConstants_1.ZERO)) {
|
|
455
|
-
|
|
456
|
-
.mul(
|
|
457
|
-
.
|
|
412
|
+
priceDelta = freeCollateralAfterTrade
|
|
413
|
+
.mul(marketMaxLeverage) // precision is TEN_THOUSAND
|
|
414
|
+
.div(marketMaxLeverage.add(numericConstants_1.TEN_THOUSAND))
|
|
458
415
|
.mul(numericConstants_1.PRICE_TO_QUOTE_PRECISION)
|
|
459
|
-
.
|
|
416
|
+
.mul(numericConstants_1.AMM_RESERVE_PRECISION)
|
|
417
|
+
.div(proposedBaseAssetAmount);
|
|
460
418
|
}
|
|
461
419
|
else {
|
|
462
|
-
|
|
463
|
-
.mul(
|
|
464
|
-
.sub(
|
|
420
|
+
priceDelta = freeCollateralAfterTrade
|
|
421
|
+
.mul(marketMaxLeverage) // precision is TEN_THOUSAND
|
|
422
|
+
.div(marketMaxLeverage.sub(numericConstants_1.TEN_THOUSAND))
|
|
465
423
|
.mul(numericConstants_1.PRICE_TO_QUOTE_PRECISION)
|
|
466
|
-
.
|
|
424
|
+
.mul(numericConstants_1.AMM_RESERVE_PRECISION)
|
|
425
|
+
.div(proposedBaseAssetAmount);
|
|
467
426
|
}
|
|
468
|
-
let
|
|
427
|
+
let markPriceAfterTrade;
|
|
469
428
|
if (positionBaseSizeChange.eq(numericConstants_1.ZERO)) {
|
|
470
|
-
|
|
429
|
+
markPriceAfterTrade = (0, _1.calculateMarkPrice)(this.clearingHouse.getMarket(marketPosition.marketIndex));
|
|
471
430
|
}
|
|
472
431
|
else {
|
|
473
432
|
const direction = positionBaseSizeChange.gt(numericConstants_1.ZERO)
|
|
474
433
|
? _1.PositionDirection.LONG
|
|
475
434
|
: _1.PositionDirection.SHORT;
|
|
476
|
-
|
|
435
|
+
markPriceAfterTrade = (0, _1.calculateTradeSlippage)(direction, positionBaseSizeChange.abs(), this.clearingHouse.getMarket(marketPosition.marketIndex), 'base')[3]; // newPrice after swap
|
|
477
436
|
}
|
|
478
|
-
|
|
479
|
-
if (targetTotalPositionValueUSDC.lte(totalFreeCollateralUSDC) &&
|
|
480
|
-
proposedMarketPosition.baseAssetAmount.gt(numericConstants_1.ZERO)) {
|
|
437
|
+
if (priceDelta.gt(markPriceAfterTrade)) {
|
|
481
438
|
return new _1.BN(-1);
|
|
482
439
|
}
|
|
483
|
-
|
|
484
|
-
return new _1.BN(-1);
|
|
485
|
-
const eatMargin2 = priceDelt
|
|
486
|
-
.mul(numericConstants_1.AMM_RESERVE_PRECISION)
|
|
487
|
-
.div(proposedBaseAssetAmount);
|
|
488
|
-
if (eatMargin2.gt(currentPrice)) {
|
|
489
|
-
return new _1.BN(-1);
|
|
490
|
-
}
|
|
491
|
-
const liqPrice = currentPrice.sub(eatMargin2);
|
|
492
|
-
return liqPrice;
|
|
440
|
+
return markPriceAfterTrade.sub(priceDelta);
|
|
493
441
|
}
|
|
494
442
|
/**
|
|
495
443
|
* Calculates the estimated liquidation price for a position after closing a quote amount of the position.
|
|
@@ -530,33 +478,24 @@ class ClearingHouseUser {
|
|
|
530
478
|
*
|
|
531
479
|
* @param targetMarketIndex
|
|
532
480
|
* @param tradeSide
|
|
533
|
-
* @param userMaxLeverageSetting - leverage : Precision TEN_THOUSAND
|
|
534
481
|
* @returns tradeSizeAllowed : Precision QUOTE_PRECISION
|
|
535
482
|
*/
|
|
536
|
-
getMaxTradeSizeUSDC(targetMarketIndex, tradeSide
|
|
483
|
+
getMaxTradeSizeUSDC(targetMarketIndex, tradeSide) {
|
|
537
484
|
const currentPosition = this.getUserPosition(targetMarketIndex) ||
|
|
538
485
|
this.getEmptyPosition(targetMarketIndex);
|
|
539
|
-
const targetSide = tradeSide
|
|
486
|
+
const targetSide = (0, types_1.isVariant)(tradeSide, 'short') ? 'short' : 'long';
|
|
540
487
|
const currentPositionSide = (currentPosition === null || currentPosition === void 0 ? void 0 : currentPosition.baseAssetAmount.isNeg())
|
|
541
488
|
? 'short'
|
|
542
489
|
: 'long';
|
|
543
|
-
const
|
|
490
|
+
const targetingSameSide = !currentPosition
|
|
544
491
|
? true
|
|
545
492
|
: targetSide === currentPositionSide;
|
|
546
493
|
// add any position we have on the opposite side of the current trade, because we can "flip" the size of this position without taking any extra leverage.
|
|
547
|
-
const oppositeSizeValueUSDC =
|
|
494
|
+
const oppositeSizeValueUSDC = targetingSameSide
|
|
548
495
|
? numericConstants_1.ZERO
|
|
549
496
|
: this.getPositionValue(targetMarketIndex);
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
const remainingLeverage = _1.BN.max(userMaxLeverageSetting.sub(currentLeverage), numericConstants_1.ZERO);
|
|
553
|
-
// get total collateral
|
|
554
|
-
const totalCollateral = this.getTotalCollateral();
|
|
555
|
-
// position side allowed based purely on current leverage
|
|
556
|
-
let maxPositionSize = remainingLeverage
|
|
557
|
-
.mul(totalCollateral)
|
|
558
|
-
.div(numericConstants_1.TEN_THOUSAND);
|
|
559
|
-
if (userMaxLeverageSetting.sub(currentLeverage).gte(numericConstants_1.ZERO)) {
|
|
497
|
+
let maxPositionSize = this.getBuyingPower(targetMarketIndex);
|
|
498
|
+
if (maxPositionSize.gte(numericConstants_1.ZERO)) {
|
|
560
499
|
if (oppositeSizeValueUSDC.eq(numericConstants_1.ZERO)) {
|
|
561
500
|
// case 1 : Regular trade where current total position less than max, and no opposite position to account for
|
|
562
501
|
// do nothing
|
|
@@ -568,25 +507,24 @@ class ClearingHouseUser {
|
|
|
568
507
|
}
|
|
569
508
|
else {
|
|
570
509
|
// current leverage is greater than max leverage - can only reduce position size
|
|
571
|
-
if (!
|
|
572
|
-
const
|
|
573
|
-
const
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
const
|
|
577
|
-
|
|
578
|
-
.
|
|
579
|
-
|
|
580
|
-
if (
|
|
581
|
-
|
|
582
|
-
.gte(quoteValueOfMaxLeverage)) {
|
|
583
|
-
// case 3: Can only reduce the current position because it will still be greater than max leverage
|
|
584
|
-
maxPositionSize = currentPositionQuoteSize;
|
|
510
|
+
if (!targetingSameSide) {
|
|
511
|
+
const market = this.clearingHouse.getMarket(targetMarketIndex);
|
|
512
|
+
const marketPositionValue = this.getPositionValue(targetMarketIndex);
|
|
513
|
+
const totalCollateral = this.getTotalCollateral();
|
|
514
|
+
const marginRequirement = this.getInitialMarginRequirement();
|
|
515
|
+
const marginFreedByClosing = marketPositionValue
|
|
516
|
+
.mul(new _1.BN(market.marginRatioInitial))
|
|
517
|
+
.div(numericConstants_1.MARGIN_PRECISION);
|
|
518
|
+
const marginRequirementAfterClosing = marginRequirement.sub(marginFreedByClosing);
|
|
519
|
+
if (marginRequirementAfterClosing.gt(totalCollateral)) {
|
|
520
|
+
maxPositionSize = marketPositionValue;
|
|
585
521
|
}
|
|
586
522
|
else {
|
|
587
|
-
|
|
588
|
-
const
|
|
589
|
-
|
|
523
|
+
const freeCollateralAfterClose = totalCollateral.sub(marginRequirementAfterClosing);
|
|
524
|
+
const buyingPowerAfterClose = freeCollateralAfterClose
|
|
525
|
+
.mul(this.getMaxLeverage(targetMarketIndex))
|
|
526
|
+
.div(numericConstants_1.TEN_THOUSAND);
|
|
527
|
+
maxPositionSize = marketPositionValue.add(buyingPowerAfterClose);
|
|
590
528
|
}
|
|
591
529
|
}
|
|
592
530
|
else {
|
|
@@ -659,46 +597,5 @@ class ClearingHouseUser {
|
|
|
659
597
|
}
|
|
660
598
|
return this.getTotalPositionValue().sub(currentMarketPositionValueUSDC);
|
|
661
599
|
}
|
|
662
|
-
canFillOrder(order) {
|
|
663
|
-
const userAccount = this.getUserAccount();
|
|
664
|
-
const userPositionsAccount = this.getUserPositionsAccount();
|
|
665
|
-
const userPosition = this.getUserPosition(order.marketIndex);
|
|
666
|
-
const market = this.clearingHouse.getMarket(order.marketIndex);
|
|
667
|
-
if ((0, position_1.isEmptyPosition)(userPosition)) {
|
|
668
|
-
return false;
|
|
669
|
-
}
|
|
670
|
-
const newState = (0, _1.calculateNewStateAfterOrder)(userAccount, userPosition, market, order);
|
|
671
|
-
if (newState === null) {
|
|
672
|
-
return false;
|
|
673
|
-
}
|
|
674
|
-
const [userAccountAfter, userPositionAfter, marketAfter] = newState;
|
|
675
|
-
const totalPositionValue = userPositionsAccount.positions.reduce((positionValue, marketPosition) => {
|
|
676
|
-
let market = this.clearingHouse.getMarket(marketPosition.marketIndex);
|
|
677
|
-
if (marketPosition.marketIndex.eq(order.marketIndex)) {
|
|
678
|
-
market = marketAfter;
|
|
679
|
-
marketPosition = userPositionAfter;
|
|
680
|
-
}
|
|
681
|
-
return positionValue.add((0, _1.calculateBaseAssetValue)(market, marketPosition));
|
|
682
|
-
}, numericConstants_1.ZERO);
|
|
683
|
-
if (totalPositionValue.eq(numericConstants_1.ZERO)) {
|
|
684
|
-
return true;
|
|
685
|
-
}
|
|
686
|
-
const unrealizedPnL = userPositionsAccount.positions.reduce((pnl, marketPosition) => {
|
|
687
|
-
let market = this.clearingHouse.getMarket(marketPosition.marketIndex);
|
|
688
|
-
pnl = pnl.add((0, _1.calculatePositionFundingPNL)(market, marketPosition).div(numericConstants_1.PRICE_TO_QUOTE_PRECISION));
|
|
689
|
-
if (marketPosition.marketIndex.eq(order.marketIndex)) {
|
|
690
|
-
market = marketAfter;
|
|
691
|
-
marketPosition = userPositionAfter;
|
|
692
|
-
}
|
|
693
|
-
// update
|
|
694
|
-
return pnl.add((0, _1.calculatePositionPNL)(market, marketPosition, false));
|
|
695
|
-
}, numericConstants_1.ZERO);
|
|
696
|
-
const totalCollateral = userAccountAfter.collateral.add(unrealizedPnL);
|
|
697
|
-
const marginRatioAfter = totalCollateral
|
|
698
|
-
.mul(numericConstants_1.TEN_THOUSAND)
|
|
699
|
-
.div(totalPositionValue);
|
|
700
|
-
const marginRatioInitial = this.clearingHouse.getStateAccount().marginRatioInitial;
|
|
701
|
-
return marginRatioAfter.gte(marginRatioInitial);
|
|
702
|
-
}
|
|
703
600
|
}
|
|
704
601
|
exports.ClearingHouseUser = ClearingHouseUser;
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
/// <reference types="bn.js" />
|
|
2
|
-
import { BN } from '../';
|
|
3
|
-
declare type
|
|
2
|
+
import { BN, OracleSource } from '../';
|
|
3
|
+
export declare type MarketConfig = {
|
|
4
|
+
fullName?: string;
|
|
5
|
+
category?: string[];
|
|
4
6
|
symbol: string;
|
|
5
7
|
baseAssetSymbol: string;
|
|
6
8
|
marketIndex: BN;
|
|
7
9
|
devnetPythOracle: string;
|
|
8
10
|
mainnetPythOracle: string;
|
|
9
11
|
launchTs: number;
|
|
12
|
+
oracleSource: OracleSource;
|
|
10
13
|
};
|
|
11
|
-
export declare const Markets:
|
|
12
|
-
export {};
|
|
14
|
+
export declare const Markets: MarketConfig[];
|
package/lib/constants/markets.js
CHANGED
|
@@ -4,108 +4,156 @@ exports.Markets = void 0;
|
|
|
4
4
|
const __1 = require("../");
|
|
5
5
|
exports.Markets = [
|
|
6
6
|
{
|
|
7
|
+
fullName: 'Solana',
|
|
8
|
+
category: ['L1', 'Infra'],
|
|
7
9
|
symbol: 'SOL-PERP',
|
|
8
10
|
baseAssetSymbol: 'SOL',
|
|
9
11
|
marketIndex: new __1.BN(0),
|
|
10
12
|
devnetPythOracle: 'J83w4HKfqxwcq3BEMMkPFSppX3gqekLyLJBexebFVkix',
|
|
11
13
|
mainnetPythOracle: 'H6ARHf6YXhGYeQfUzQNGk6rDNnLBQKrenN712K4AQJEG',
|
|
12
14
|
launchTs: 1635209696886,
|
|
15
|
+
oracleSource: __1.OracleSource.PYTH,
|
|
13
16
|
},
|
|
14
17
|
{
|
|
18
|
+
fullName: 'Bitcoin',
|
|
19
|
+
category: ['L1', 'Payment'],
|
|
15
20
|
symbol: 'BTC-PERP',
|
|
16
21
|
baseAssetSymbol: 'BTC',
|
|
17
22
|
marketIndex: new __1.BN(1),
|
|
18
23
|
devnetPythOracle: 'HovQMDrbAgAYPCmHVSrezcSmkMtXSSUsLDFANExrZh2J',
|
|
19
24
|
mainnetPythOracle: 'GVXRSBjFk6e6J3NbVPXohDJetcTjaeeuykUpbQF8UoMU',
|
|
20
25
|
launchTs: 1637691088868,
|
|
26
|
+
oracleSource: __1.OracleSource.PYTH,
|
|
21
27
|
},
|
|
22
28
|
{
|
|
29
|
+
fullName: 'Ethereum',
|
|
30
|
+
category: ['L1', 'Infra'],
|
|
23
31
|
symbol: 'ETH-PERP',
|
|
24
32
|
baseAssetSymbol: 'ETH',
|
|
25
33
|
marketIndex: new __1.BN(2),
|
|
26
34
|
devnetPythOracle: 'EdVCmQ9FSPcVe5YySXDPCRmc8aDQLKJ9xvYBMZPie1Vw',
|
|
27
35
|
mainnetPythOracle: 'JBu1AL4obBcCMqKBBxhpWCNUt136ijcuMZLFvTP7iWdB',
|
|
28
36
|
launchTs: 1637691133472,
|
|
37
|
+
oracleSource: __1.OracleSource.PYTH,
|
|
29
38
|
},
|
|
30
39
|
{
|
|
40
|
+
fullName: 'Terra',
|
|
41
|
+
category: ['L1', 'Infra'],
|
|
31
42
|
symbol: 'LUNA-PERP',
|
|
32
43
|
baseAssetSymbol: 'LUNA',
|
|
33
44
|
marketIndex: new __1.BN(3),
|
|
34
45
|
devnetPythOracle: '8PugCXTAHLM9kfLSQWe2njE5pzAgUdpPk3Nx5zSm7BD3',
|
|
35
46
|
mainnetPythOracle: '5bmWuR1dgP4avtGYMNKLuxumZTVKGgoN2BCMXWDNL9nY',
|
|
36
47
|
launchTs: 1638821738525,
|
|
48
|
+
oracleSource: __1.OracleSource.PYTH,
|
|
37
49
|
},
|
|
38
50
|
{
|
|
39
51
|
symbol: 'AVAX-PERP',
|
|
52
|
+
category: ['L1', 'Infra'],
|
|
40
53
|
baseAssetSymbol: 'AVAX',
|
|
41
54
|
marketIndex: new __1.BN(4),
|
|
42
55
|
devnetPythOracle: 'FVb5h1VmHPfVb1RfqZckchq18GxRv4iKt8T4eVTQAqdz',
|
|
43
56
|
mainnetPythOracle: 'Ax9ujW5B9oqcv59N8m6f1BpTBq2rGeGaBcpKjC5UYsXU',
|
|
44
57
|
launchTs: 1639092501080,
|
|
58
|
+
oracleSource: __1.OracleSource.PYTH,
|
|
45
59
|
},
|
|
46
60
|
{
|
|
61
|
+
fullName: 'Binance Coin',
|
|
47
62
|
symbol: 'BNB-PERP',
|
|
63
|
+
category: ['L1', 'Exchange'],
|
|
48
64
|
baseAssetSymbol: 'BNB',
|
|
49
65
|
marketIndex: new __1.BN(5),
|
|
50
66
|
devnetPythOracle: 'GwzBgrXb4PG59zjce24SF2b9JXbLEjJJTBkmytuEZj1b',
|
|
51
67
|
mainnetPythOracle: '4CkQJBxhU8EZ2UjhigbtdaPbpTe6mqf811fipYBFbSYN',
|
|
52
68
|
launchTs: 1639523193012,
|
|
69
|
+
oracleSource: __1.OracleSource.PYTH,
|
|
53
70
|
},
|
|
54
71
|
{
|
|
72
|
+
fullName: 'Polygon',
|
|
73
|
+
category: ['L1', 'Infra'],
|
|
55
74
|
symbol: 'MATIC-PERP',
|
|
56
75
|
baseAssetSymbol: 'MATIC',
|
|
57
76
|
marketIndex: new __1.BN(6),
|
|
58
77
|
devnetPythOracle: 'FBirwuDFuRAu4iSGc7RGxN5koHB7EJM1wbCmyPuQoGur',
|
|
59
78
|
mainnetPythOracle: '7KVswB9vkCgeM3SHP7aGDijvdRAHK8P5wi9JXViCrtYh',
|
|
60
79
|
launchTs: 1641488603564,
|
|
80
|
+
oracleSource: __1.OracleSource.PYTH,
|
|
61
81
|
},
|
|
62
82
|
{
|
|
83
|
+
fullName: 'Cosmos',
|
|
84
|
+
category: ['L1', 'Infra'],
|
|
63
85
|
symbol: 'ATOM-PERP',
|
|
64
86
|
baseAssetSymbol: 'ATOM',
|
|
65
87
|
marketIndex: new __1.BN(7),
|
|
66
88
|
devnetPythOracle: '7YAze8qFUMkBnyLVdKT4TFUUFui99EwS5gfRArMcrvFk',
|
|
67
89
|
mainnetPythOracle: 'CrCpTerNqtZvqLcKqz1k13oVeXV9WkMD2zA9hBKXrsbN',
|
|
68
90
|
launchTs: 1641920238195,
|
|
91
|
+
oracleSource: __1.OracleSource.PYTH,
|
|
69
92
|
},
|
|
70
93
|
{
|
|
94
|
+
fullName: 'Polkadot',
|
|
71
95
|
symbol: 'DOT-PERP',
|
|
72
96
|
baseAssetSymbol: 'DOT',
|
|
73
97
|
marketIndex: new __1.BN(8),
|
|
74
98
|
devnetPythOracle: '4dqq5VBpN4EwYb7wyywjjfknvMKu7m78j9mKZRXTj462',
|
|
75
99
|
mainnetPythOracle: 'EcV1X1gY2yb4KXxjVQtTHTbioum2gvmPnFk4zYAt7zne',
|
|
76
100
|
launchTs: 1642629253786,
|
|
101
|
+
oracleSource: __1.OracleSource.PYTH,
|
|
77
102
|
},
|
|
78
103
|
{
|
|
104
|
+
fullName: 'Cardano',
|
|
105
|
+
category: ['L1', 'Infra'],
|
|
79
106
|
symbol: 'ADA-PERP',
|
|
80
107
|
baseAssetSymbol: 'ADA',
|
|
81
108
|
marketIndex: new __1.BN(9),
|
|
82
109
|
devnetPythOracle: '8oGTURNmSQkrBS1AQ5NjB2p8qY34UVmMA9ojrw8vnHus',
|
|
83
110
|
mainnetPythOracle: '3pyn4svBbxJ9Wnn3RVeafyLWfzie6yC5eTig2S62v9SC',
|
|
84
111
|
launchTs: 1643084413000,
|
|
112
|
+
oracleSource: __1.OracleSource.PYTH,
|
|
85
113
|
},
|
|
86
114
|
{
|
|
115
|
+
fullName: 'Algorand',
|
|
116
|
+
category: ['L1', 'Infra'],
|
|
87
117
|
symbol: 'ALGO-PERP',
|
|
88
118
|
baseAssetSymbol: 'ALGO',
|
|
89
119
|
marketIndex: new __1.BN(10),
|
|
90
120
|
devnetPythOracle: 'c1A946dY5NHuVda77C8XXtXytyR3wK1SCP3eA9VRfC3',
|
|
91
121
|
mainnetPythOracle: 'HqFyq1wh1xKvL7KDqqT7NJeSPdAqsDqnmBisUC2XdXAX',
|
|
92
122
|
launchTs: 1643686767000,
|
|
123
|
+
oracleSource: __1.OracleSource.PYTH,
|
|
93
124
|
},
|
|
94
125
|
{
|
|
126
|
+
fullName: 'FTX Coin',
|
|
127
|
+
category: ['L1', 'Exchange'],
|
|
95
128
|
symbol: 'FTT-PERP',
|
|
96
129
|
baseAssetSymbol: 'FTT',
|
|
97
130
|
marketIndex: new __1.BN(11),
|
|
98
131
|
devnetPythOracle: '6vivTRs5ZPeeXbjo7dfburfaYDWoXjBtdtuYgQRuGfu',
|
|
99
132
|
mainnetPythOracle: '8JPJJkmDScpcNmBRKGZuPuG2GYAveQgP3t5gFuMymwvF',
|
|
100
133
|
launchTs: 1644382122000,
|
|
134
|
+
oracleSource: __1.OracleSource.PYTH,
|
|
101
135
|
},
|
|
102
136
|
{
|
|
137
|
+
fullName: 'Litecoin',
|
|
138
|
+
category: ['L1', 'Payments'],
|
|
103
139
|
symbol: 'LTC-PERP',
|
|
104
140
|
baseAssetSymbol: 'LTC',
|
|
105
141
|
marketIndex: new __1.BN(12),
|
|
106
142
|
devnetPythOracle: 'BLArYBCUYhdWiY8PCUTpvFE21iaJq85dvxLk9bYMobcU',
|
|
107
143
|
mainnetPythOracle: '8RMnV1eD55iqUFJLMguPkYBkq8DCtx81XcmAja93LvRR',
|
|
108
144
|
launchTs: 1645027429000,
|
|
145
|
+
oracleSource: __1.OracleSource.PYTH,
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
fullName: 'Ripple',
|
|
149
|
+
category: ['L1', 'Payments'],
|
|
150
|
+
symbol: 'XRP-PERP',
|
|
151
|
+
baseAssetSymbol: 'XRP',
|
|
152
|
+
marketIndex: new __1.BN(13),
|
|
153
|
+
devnetPythOracle: 'WMW5xc3HypXwTnPesyUT49uLsyHwNURsWAEk39onKuk',
|
|
154
|
+
mainnetPythOracle: 'WMW5xc3HypXwTnPesyUT49uLsyHwNURsWAEk39onKuk',
|
|
155
|
+
launchTs: 1647543166000,
|
|
156
|
+
oracleSource: __1.OracleSource.SWITCHBOARD,
|
|
109
157
|
},
|
|
110
158
|
// {
|
|
111
159
|
// symbol: 'mSOL-PERP',
|
|
@@ -3,11 +3,10 @@ import { BN } from '../';
|
|
|
3
3
|
export declare const ZERO: BN;
|
|
4
4
|
export declare const ONE: BN;
|
|
5
5
|
export declare const TWO: BN;
|
|
6
|
+
export declare const TEN: BN;
|
|
6
7
|
export declare const TEN_THOUSAND: BN;
|
|
7
8
|
export declare const BN_MAX: BN;
|
|
8
9
|
export declare const MAX_LEVERAGE: BN;
|
|
9
|
-
export declare const FULL_LIQUIDATION_RATIO: BN;
|
|
10
|
-
export declare const PARTIAL_LIQUIDATION_RATIO: BN;
|
|
11
10
|
export declare const QUOTE_PRECISION: BN;
|
|
12
11
|
export declare const MARK_PRICE_PRECISION: BN;
|
|
13
12
|
export declare const FUNDING_PAYMENT_PRECISION: BN;
|
|
@@ -17,3 +16,4 @@ export declare const BASE_PRECISION: BN;
|
|
|
17
16
|
export declare const AMM_TO_QUOTE_PRECISION_RATIO: BN;
|
|
18
17
|
export declare const PRICE_TO_QUOTE_PRECISION: BN;
|
|
19
18
|
export declare const AMM_TIMES_PEG_TO_QUOTE_PRECISION_RATIO: BN;
|
|
19
|
+
export declare const MARGIN_PRECISION: BN;
|