@drift-labs/sdk 2.14.0-beta.0 → 2.15.0-beta.0
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 +0 -1
- package/lib/accounts/bulkAccountLoader.js +3 -3
- package/lib/accounts/fetch.js +2 -2
- package/lib/accounts/pollingDriftClientAccountSubscriber.js +7 -7
- package/lib/accounts/pollingTokenAccountSubscriber.js +2 -2
- package/lib/accounts/pollingUserAccountSubscriber.js +2 -2
- package/lib/accounts/pollingUserStatsAccountSubscriber.js +2 -2
- package/lib/accounts/types.d.ts +0 -1
- package/lib/accounts/webSocketAccountSubscriber.js +1 -1
- package/lib/accounts/webSocketDriftClientAccountSubscriber.js +3 -3
- package/lib/addresses/marketAddresses.js +1 -1
- package/lib/addresses/pda.js +1 -5
- package/lib/adminClient.js +57 -61
- package/lib/constants/numericConstants.d.ts +1 -0
- package/lib/constants/numericConstants.js +3 -2
- package/lib/constants/perpMarkets.js +10 -0
- package/lib/dlob/DLOB.js +68 -68
- package/lib/dlob/DLOBNode.js +7 -7
- package/lib/dlob/NodeList.js +2 -2
- package/lib/driftClient.js +81 -85
- package/lib/events/eventSubscriber.js +2 -2
- package/lib/events/pollingLogProvider.js +1 -1
- package/lib/examples/loadDlob.js +2 -2
- package/lib/examples/makeTradeExample.js +9 -9
- package/lib/factory/bigNum.js +9 -9
- package/lib/factory/oracleClient.js +2 -2
- package/lib/idl/drift.json +1 -1
- package/lib/index.js +1 -5
- package/lib/math/amm.js +23 -23
- package/lib/math/auction.js +6 -6
- package/lib/math/exchangeStatus.js +2 -2
- package/lib/math/funding.js +2 -2
- package/lib/math/margin.js +5 -5
- package/lib/math/market.js +13 -13
- package/lib/math/oracles.js +1 -1
- package/lib/math/orders.js +23 -23
- package/lib/math/position.js +5 -5
- package/lib/math/repeg.js +1 -1
- package/lib/math/spotBalance.js +8 -8
- package/lib/math/spotPosition.js +3 -3
- package/lib/math/trade.js +42 -42
- package/lib/oracles/oracleClientCache.js +1 -1
- package/lib/oracles/pythClient.js +1 -1
- package/lib/tokenFaucet.js +1 -5
- package/lib/tx/retryTxSender.js +1 -1
- package/lib/user.js +52 -52
- package/lib/userMap/userMap.js +1 -1
- package/lib/userMap/userStatsMap.js +3 -3
- package/lib/userStats.js +2 -2
- package/package.json +1 -1
- package/src/assert/assert.js +9 -0
- package/src/constants/numericConstants.ts +1 -0
- package/src/constants/perpMarkets.ts +10 -0
- package/src/dlob/DLOB.ts +1 -1
- package/src/idl/drift.json +1 -1
- package/src/token/index.js +38 -0
- package/src/tx/types.js +2 -0
- package/src/tx/utils.js +17 -0
- package/src/user.ts +2 -1
- package/src/util/computeUnits.js +27 -0
- package/src/util/getTokenAddress.js +9 -0
- package/src/util/promiseTimeout.js +14 -0
- package/src/util/tps.js +27 -0
package/lib/user.js
CHANGED
|
@@ -142,7 +142,7 @@ class User {
|
|
|
142
142
|
return [numericConstants_1.ZERO, numericConstants_1.ZERO];
|
|
143
143
|
}
|
|
144
144
|
const market = this.driftClient.getPerpMarketAccount(marketIndex);
|
|
145
|
-
const [marketOpenBids, marketOpenAsks] =
|
|
145
|
+
const [marketOpenBids, marketOpenAsks] = amm_1.calculateMarketOpenBidAsk(market.amm.baseAssetReserve, market.amm.minBaseAssetReserve, market.amm.maxBaseAssetReserve, market.amm.orderStepSize);
|
|
146
146
|
const lpOpenBids = marketOpenBids
|
|
147
147
|
.mul(position.lpShares)
|
|
148
148
|
.div(market.amm.sqrtK);
|
|
@@ -245,13 +245,13 @@ class User {
|
|
|
245
245
|
getBuyingPower(marketIndex) {
|
|
246
246
|
const perpPosition = this.getPerpPosition(marketIndex);
|
|
247
247
|
const worstCaseBaseAssetAmount = perpPosition
|
|
248
|
-
?
|
|
248
|
+
? margin_1.calculateWorstCaseBaseAssetAmount(perpPosition)
|
|
249
249
|
: numericConstants_1.ZERO;
|
|
250
250
|
const freeCollateral = this.getFreeCollateral();
|
|
251
251
|
return this.getBuyingPowerFromFreeCollateralAndBaseAssetAmount(marketIndex, freeCollateral, worstCaseBaseAssetAmount);
|
|
252
252
|
}
|
|
253
253
|
getBuyingPowerFromFreeCollateralAndBaseAssetAmount(marketIndex, freeCollateral, baseAssetAmount) {
|
|
254
|
-
const marginRatio =
|
|
254
|
+
const marginRatio = _1.calculateMarketMarginRatio(this.driftClient.getPerpMarketAccount(marketIndex), baseAssetAmount, 'Initial');
|
|
255
255
|
return freeCollateral.mul(numericConstants_1.MARGIN_PRECISION).div(new _1.BN(marginRatio));
|
|
256
256
|
}
|
|
257
257
|
/**
|
|
@@ -302,11 +302,11 @@ class User {
|
|
|
302
302
|
if (perpPosition.lpShares.gt(numericConstants_1.ZERO)) {
|
|
303
303
|
perpPosition = this.getSettledLPPosition(perpPosition.marketIndex)[0];
|
|
304
304
|
}
|
|
305
|
-
let positionUnrealizedPnl =
|
|
305
|
+
let positionUnrealizedPnl = _1.calculatePositionPNL(market, perpPosition, withFunding, oraclePriceData);
|
|
306
306
|
if (withWeightMarginCategory !== undefined) {
|
|
307
307
|
if (positionUnrealizedPnl.gt(numericConstants_1.ZERO)) {
|
|
308
308
|
positionUnrealizedPnl = positionUnrealizedPnl
|
|
309
|
-
.mul(
|
|
309
|
+
.mul(_1.calculateUnrealizedAssetWeight(market, quoteSpotMarket, positionUnrealizedPnl, withWeightMarginCategory, oraclePriceData))
|
|
310
310
|
.div(new _1.BN(numericConstants_1.SPOT_MARKET_WEIGHT_PRECISION));
|
|
311
311
|
}
|
|
312
312
|
}
|
|
@@ -322,21 +322,21 @@ class User {
|
|
|
322
322
|
.perpPositions.filter((pos) => marketIndex ? pos.marketIndex === marketIndex : true)
|
|
323
323
|
.reduce((pnl, perpPosition) => {
|
|
324
324
|
const market = this.driftClient.getPerpMarketAccount(perpPosition.marketIndex);
|
|
325
|
-
return pnl.add(
|
|
325
|
+
return pnl.add(_1.calculatePositionFundingPNL(market, perpPosition));
|
|
326
326
|
}, numericConstants_1.ZERO);
|
|
327
327
|
}
|
|
328
328
|
getSpotMarketLiabilityValue(marketIndex, marginCategory, liquidationBuffer, includeOpenOrders, strict = false, now) {
|
|
329
329
|
now = now || new _1.BN(new Date().getTime() / 1000);
|
|
330
330
|
return this.getUserAccount().spotPositions.reduce((totalLiabilityValue, spotPosition) => {
|
|
331
|
-
if (
|
|
331
|
+
if (spotPosition_1.isSpotPositionAvailable(spotPosition) ||
|
|
332
332
|
(marketIndex !== undefined &&
|
|
333
333
|
spotPosition.marketIndex !== marketIndex)) {
|
|
334
334
|
return totalLiabilityValue;
|
|
335
335
|
}
|
|
336
336
|
const spotMarketAccount = this.driftClient.getSpotMarketAccount(spotPosition.marketIndex);
|
|
337
337
|
if (spotPosition.marketIndex === numericConstants_1.QUOTE_SPOT_MARKET_INDEX) {
|
|
338
|
-
if (
|
|
339
|
-
const tokenAmount =
|
|
338
|
+
if (types_1.isVariant(spotPosition.balanceType, 'borrow')) {
|
|
339
|
+
const tokenAmount = spotBalance_1.getTokenAmount(spotPosition.scaledBalance, spotMarketAccount, spotPosition.balanceType);
|
|
340
340
|
let weight = numericConstants_1.SPOT_MARKET_WEIGHT_PRECISION;
|
|
341
341
|
if (marginCategory === 'Initial') {
|
|
342
342
|
weight = _1.BN.max(weight, new _1.BN(this.getUserAccount().maxMarginRatio));
|
|
@@ -352,8 +352,8 @@ class User {
|
|
|
352
352
|
}
|
|
353
353
|
const oraclePriceData = this.getOracleDataForSpotMarket(spotPosition.marketIndex);
|
|
354
354
|
if (!includeOpenOrders) {
|
|
355
|
-
if (
|
|
356
|
-
const tokenAmount =
|
|
355
|
+
if (types_1.isVariant(spotPosition.balanceType, 'borrow')) {
|
|
356
|
+
const tokenAmount = spotBalance_1.getTokenAmount(spotPosition.scaledBalance, spotMarketAccount, spotPosition.balanceType);
|
|
357
357
|
const liabilityValue = this.getSpotLiabilityValue(tokenAmount, oraclePriceData, spotMarketAccount, marginCategory, liquidationBuffer, strict, now);
|
|
358
358
|
return totalLiabilityValue.add(liabilityValue);
|
|
359
359
|
}
|
|
@@ -361,7 +361,7 @@ class User {
|
|
|
361
361
|
return totalLiabilityValue;
|
|
362
362
|
}
|
|
363
363
|
}
|
|
364
|
-
const [worstCaseTokenAmount, worstCaseQuoteTokenAmount] =
|
|
364
|
+
const [worstCaseTokenAmount, worstCaseQuoteTokenAmount] = spotPosition_1.getWorstCaseTokenAmounts(spotPosition, spotMarketAccount, this.getOracleDataForSpotMarket(spotPosition.marketIndex));
|
|
365
365
|
let newTotalLiabilityValue = totalLiabilityValue;
|
|
366
366
|
if (worstCaseTokenAmount.lt(numericConstants_1.ZERO)) {
|
|
367
367
|
const baseLiabilityValue = this.getSpotLiabilityValue(worstCaseTokenAmount.abs(), oraclePriceData, spotMarketAccount, marginCategory, liquidationBuffer, strict, now);
|
|
@@ -387,15 +387,15 @@ class User {
|
|
|
387
387
|
getSpotLiabilityValue(tokenAmount, oraclePriceData, spotMarketAccount, marginCategory, liquidationBuffer, strict = false, now) {
|
|
388
388
|
let liabilityValue = null;
|
|
389
389
|
if (strict && spotMarketAccount.marketIndex != numericConstants_1.QUOTE_SPOT_MARKET_INDEX) {
|
|
390
|
-
const estOracleTwap =
|
|
390
|
+
const estOracleTwap = oracles_1.calculateLiveOracleTwap(spotMarketAccount.historicalOracleData, oraclePriceData, now, numericConstants_1.FIVE_MINUTE // 5MIN
|
|
391
391
|
);
|
|
392
|
-
liabilityValue =
|
|
392
|
+
liabilityValue = _1.getStrictTokenValue(tokenAmount, spotMarketAccount.decimals, oraclePriceData, estOracleTwap);
|
|
393
393
|
}
|
|
394
394
|
else {
|
|
395
|
-
liabilityValue =
|
|
395
|
+
liabilityValue = _1.getTokenValue(tokenAmount, spotMarketAccount.decimals, oraclePriceData);
|
|
396
396
|
}
|
|
397
397
|
if (marginCategory !== undefined) {
|
|
398
|
-
let weight =
|
|
398
|
+
let weight = spotBalance_1.calculateLiabilityWeight(tokenAmount, spotMarketAccount, marginCategory);
|
|
399
399
|
if (marginCategory === 'Initial') {
|
|
400
400
|
weight = _1.BN.max(weight, new _1.BN(this.getUserAccount().maxMarginRatio));
|
|
401
401
|
}
|
|
@@ -411,7 +411,7 @@ class User {
|
|
|
411
411
|
getSpotMarketAssetValue(marketIndex, marginCategory, includeOpenOrders, strict = false, now) {
|
|
412
412
|
now = now || new _1.BN(new Date().getTime() / 1000);
|
|
413
413
|
return this.getUserAccount().spotPositions.reduce((totalAssetValue, spotPosition) => {
|
|
414
|
-
if (
|
|
414
|
+
if (spotPosition_1.isSpotPositionAvailable(spotPosition) ||
|
|
415
415
|
(marketIndex !== undefined &&
|
|
416
416
|
spotPosition.marketIndex !== marketIndex)) {
|
|
417
417
|
return totalAssetValue;
|
|
@@ -419,8 +419,8 @@ class User {
|
|
|
419
419
|
// Todo this needs to account for whether it's based on initial or maintenance requirements
|
|
420
420
|
const spotMarketAccount = this.driftClient.getSpotMarketAccount(spotPosition.marketIndex);
|
|
421
421
|
if (spotPosition.marketIndex === numericConstants_1.QUOTE_SPOT_MARKET_INDEX) {
|
|
422
|
-
if (
|
|
423
|
-
const tokenAmount =
|
|
422
|
+
if (types_1.isVariant(spotPosition.balanceType, 'deposit')) {
|
|
423
|
+
const tokenAmount = spotBalance_1.getTokenAmount(spotPosition.scaledBalance, spotMarketAccount, spotPosition.balanceType);
|
|
424
424
|
return totalAssetValue.add(tokenAmount);
|
|
425
425
|
}
|
|
426
426
|
else {
|
|
@@ -429,8 +429,8 @@ class User {
|
|
|
429
429
|
}
|
|
430
430
|
const oraclePriceData = this.getOracleDataForSpotMarket(spotPosition.marketIndex);
|
|
431
431
|
if (!includeOpenOrders) {
|
|
432
|
-
if (
|
|
433
|
-
const tokenAmount =
|
|
432
|
+
if (types_1.isVariant(spotPosition.balanceType, 'deposit')) {
|
|
433
|
+
const tokenAmount = spotBalance_1.getTokenAmount(spotPosition.scaledBalance, spotMarketAccount, spotPosition.balanceType);
|
|
434
434
|
const assetValue = this.getSpotAssetValue(tokenAmount, oraclePriceData, spotMarketAccount, marginCategory, strict, now);
|
|
435
435
|
return totalAssetValue.add(assetValue);
|
|
436
436
|
}
|
|
@@ -438,7 +438,7 @@ class User {
|
|
|
438
438
|
return totalAssetValue;
|
|
439
439
|
}
|
|
440
440
|
}
|
|
441
|
-
const [worstCaseTokenAmount, worstCaseQuoteTokenAmount] =
|
|
441
|
+
const [worstCaseTokenAmount, worstCaseQuoteTokenAmount] = spotPosition_1.getWorstCaseTokenAmounts(spotPosition, spotMarketAccount, this.getOracleDataForSpotMarket(spotPosition.marketIndex));
|
|
442
442
|
let newTotalAssetValue = totalAssetValue;
|
|
443
443
|
if (worstCaseTokenAmount.gt(numericConstants_1.ZERO)) {
|
|
444
444
|
const baseAssetValue = this.getSpotAssetValue(worstCaseTokenAmount, oraclePriceData, spotMarketAccount, marginCategory, strict, now);
|
|
@@ -453,15 +453,15 @@ class User {
|
|
|
453
453
|
getSpotAssetValue(tokenAmount, oraclePriceData, spotMarketAccount, marginCategory, strict = false, now) {
|
|
454
454
|
let assetValue = null;
|
|
455
455
|
if (strict && spotMarketAccount.marketIndex != numericConstants_1.QUOTE_SPOT_MARKET_INDEX) {
|
|
456
|
-
const estOracleTwap =
|
|
456
|
+
const estOracleTwap = oracles_1.calculateLiveOracleTwap(spotMarketAccount.historicalOracleData, oraclePriceData, now, numericConstants_1.FIVE_MINUTE // 5MIN
|
|
457
457
|
);
|
|
458
|
-
assetValue =
|
|
458
|
+
assetValue = _1.getStrictTokenValue(tokenAmount, spotMarketAccount.decimals, oraclePriceData, estOracleTwap);
|
|
459
459
|
}
|
|
460
460
|
else {
|
|
461
|
-
assetValue =
|
|
461
|
+
assetValue = _1.getTokenValue(tokenAmount, spotMarketAccount.decimals, oraclePriceData);
|
|
462
462
|
}
|
|
463
463
|
if (marginCategory !== undefined) {
|
|
464
|
-
const weight =
|
|
464
|
+
const weight = spotBalance_1.calculateAssetWeight(tokenAmount, spotMarketAccount, marginCategory);
|
|
465
465
|
assetValue = assetValue.mul(weight).div(numericConstants_1.SPOT_MARKET_WEIGHT_PRECISION);
|
|
466
466
|
}
|
|
467
467
|
return assetValue;
|
|
@@ -482,8 +482,8 @@ class User {
|
|
|
482
482
|
*/
|
|
483
483
|
getHealth() {
|
|
484
484
|
const userAccount = this.getUserAccount();
|
|
485
|
-
if (
|
|
486
|
-
|
|
485
|
+
if (types_1.isVariant(userAccount.status, 'beingLiquidated') ||
|
|
486
|
+
types_1.isVariant(userAccount.status, 'bankrupt')) {
|
|
487
487
|
return 0;
|
|
488
488
|
}
|
|
489
489
|
const totalCollateral = this.getTotalCollateral('Maintenance');
|
|
@@ -529,25 +529,25 @@ class User {
|
|
|
529
529
|
perpPosition.openBids = totalOpenBids;
|
|
530
530
|
}
|
|
531
531
|
let valuationPrice = this.getOracleDataForPerpMarket(market.marketIndex).price;
|
|
532
|
-
if (
|
|
532
|
+
if (types_1.isVariant(market.status, 'settlement')) {
|
|
533
533
|
valuationPrice = market.expiryPrice;
|
|
534
534
|
}
|
|
535
535
|
const baseAssetAmount = includeOpenOrders
|
|
536
|
-
?
|
|
536
|
+
? margin_1.calculateWorstCaseBaseAssetAmount(perpPosition)
|
|
537
537
|
: perpPosition.baseAssetAmount;
|
|
538
538
|
let baseAssetValue = baseAssetAmount
|
|
539
539
|
.abs()
|
|
540
540
|
.mul(valuationPrice)
|
|
541
541
|
.div(numericConstants_1.AMM_TO_QUOTE_PRECISION_RATIO.mul(numericConstants_1.PRICE_PRECISION));
|
|
542
542
|
if (marginCategory) {
|
|
543
|
-
let marginRatio = new _1.BN(
|
|
543
|
+
let marginRatio = new _1.BN(_1.calculateMarketMarginRatio(market, baseAssetAmount.abs(), marginCategory));
|
|
544
544
|
if (marginCategory === 'Initial') {
|
|
545
545
|
marginRatio = _1.BN.max(marginRatio, new _1.BN(this.getUserAccount().maxMarginRatio));
|
|
546
546
|
}
|
|
547
547
|
if (liquidationBuffer !== undefined) {
|
|
548
548
|
marginRatio = marginRatio.add(liquidationBuffer);
|
|
549
549
|
}
|
|
550
|
-
if (
|
|
550
|
+
if (types_1.isVariant(market.status, 'settlement')) {
|
|
551
551
|
marginRatio = numericConstants_1.ZERO;
|
|
552
552
|
}
|
|
553
553
|
baseAssetValue = baseAssetValue
|
|
@@ -567,7 +567,7 @@ class User {
|
|
|
567
567
|
getPerpPositionValue(marketIndex, oraclePriceData, includeOpenOrders = false) {
|
|
568
568
|
const userPosition = this.getPerpPosition(marketIndex) || this.getEmptyPosition(marketIndex);
|
|
569
569
|
const market = this.driftClient.getPerpMarketAccount(userPosition.marketIndex);
|
|
570
|
-
return
|
|
570
|
+
return margin_1.calculateBaseAssetValueWithOracle(market, userPosition, oraclePriceData, includeOpenOrders);
|
|
571
571
|
}
|
|
572
572
|
getPositionSide(currentPosition) {
|
|
573
573
|
if (currentPosition.baseAssetAmount.gt(numericConstants_1.ZERO)) {
|
|
@@ -586,11 +586,11 @@ class User {
|
|
|
586
586
|
*/
|
|
587
587
|
getPositionEstimatedExitPriceAndPnl(position, amountToClose, useAMMClose = false) {
|
|
588
588
|
const market = this.driftClient.getPerpMarketAccount(position.marketIndex);
|
|
589
|
-
const entryPrice =
|
|
589
|
+
const entryPrice = position_1.calculateEntryPrice(position);
|
|
590
590
|
const oraclePriceData = this.getOracleDataForPerpMarket(position.marketIndex);
|
|
591
591
|
if (amountToClose) {
|
|
592
592
|
if (amountToClose.eq(numericConstants_1.ZERO)) {
|
|
593
|
-
return [
|
|
593
|
+
return [_1.calculateReservePrice(market, oraclePriceData), numericConstants_1.ZERO];
|
|
594
594
|
}
|
|
595
595
|
position = {
|
|
596
596
|
baseAssetAmount: amountToClose,
|
|
@@ -601,10 +601,10 @@ class User {
|
|
|
601
601
|
}
|
|
602
602
|
let baseAssetValue;
|
|
603
603
|
if (useAMMClose) {
|
|
604
|
-
baseAssetValue =
|
|
604
|
+
baseAssetValue = _1.calculateBaseAssetValue(market, position, oraclePriceData);
|
|
605
605
|
}
|
|
606
606
|
else {
|
|
607
|
-
baseAssetValue =
|
|
607
|
+
baseAssetValue = margin_1.calculateBaseAssetValueWithOracle(market, position, oraclePriceData);
|
|
608
608
|
}
|
|
609
609
|
if (position.baseAssetAmount.eq(numericConstants_1.ZERO)) {
|
|
610
610
|
return [numericConstants_1.ZERO, numericConstants_1.ZERO];
|
|
@@ -656,7 +656,7 @@ class User {
|
|
|
656
656
|
return numericConstants_1.ZERO;
|
|
657
657
|
}
|
|
658
658
|
const totalLiabilityValue = totalPerpLiability.add(totalSpotLiability);
|
|
659
|
-
const marginRatio =
|
|
659
|
+
const marginRatio = _1.calculateMarketMarginRatio(market,
|
|
660
660
|
// worstCaseBaseAssetAmount.abs(),
|
|
661
661
|
numericConstants_1.ZERO, // todo
|
|
662
662
|
category);
|
|
@@ -689,7 +689,7 @@ class User {
|
|
|
689
689
|
const totalCollateral = this.getTotalCollateral('Maintenance');
|
|
690
690
|
// if user being liq'd, can continue to be liq'd until total collateral above the margin requirement plus buffer
|
|
691
691
|
let liquidationBuffer = undefined;
|
|
692
|
-
const isBeingLiquidated =
|
|
692
|
+
const isBeingLiquidated = types_1.isVariant(this.getUserAccount().status, 'beingLiquidated');
|
|
693
693
|
if (isBeingLiquidated) {
|
|
694
694
|
liquidationBuffer = new _1.BN(this.driftClient.getStateAccount().liquidationMarginBufferRatio);
|
|
695
695
|
}
|
|
@@ -697,13 +697,13 @@ class User {
|
|
|
697
697
|
return totalCollateral.lt(maintenanceRequirement);
|
|
698
698
|
}
|
|
699
699
|
isBeingLiquidated() {
|
|
700
|
-
return
|
|
700
|
+
return types_1.isOneOfVariant(this.getUserAccount().status, [
|
|
701
701
|
'beingLiquidated',
|
|
702
702
|
'bankrupt',
|
|
703
703
|
]);
|
|
704
704
|
}
|
|
705
705
|
isBankrupt() {
|
|
706
|
-
return
|
|
706
|
+
return types_1.isVariant(this.getUserAccount().status, 'bankrupt');
|
|
707
707
|
}
|
|
708
708
|
/**
|
|
709
709
|
* Checks if any user position cumulative funding differs from respective market cumulative funding
|
|
@@ -737,7 +737,7 @@ class User {
|
|
|
737
737
|
const maintenanceMarginRequirement = this.getMaintenanceMarginRequirement();
|
|
738
738
|
const freeCollateral = _1.BN.max(numericConstants_1.ZERO, totalCollateral.sub(maintenanceMarginRequirement));
|
|
739
739
|
const market = this.driftClient.getSpotMarketAccount(marketIndex);
|
|
740
|
-
const signedTokenAmount =
|
|
740
|
+
const signedTokenAmount = _1.getSignedTokenAmount(spotBalance_1.getTokenAmount(currentSpotPosition.scaledBalance, market, currentSpotPosition.balanceType), currentSpotPosition.balanceType);
|
|
741
741
|
if (signedTokenAmount.eq(numericConstants_1.ZERO)) {
|
|
742
742
|
return new _1.BN(-1);
|
|
743
743
|
}
|
|
@@ -777,7 +777,7 @@ class User {
|
|
|
777
777
|
const maintenanceMarginRequirement = this.getMaintenanceMarginRequirement();
|
|
778
778
|
const freeCollateral = _1.BN.max(numericConstants_1.ZERO, totalCollateral.sub(maintenanceMarginRequirement));
|
|
779
779
|
const market = this.driftClient.getPerpMarketAccount(marketIndex);
|
|
780
|
-
const currentPerpPosition = this.getPerpPosition(marketIndex);
|
|
780
|
+
const currentPerpPosition = this.getPerpPosition(marketIndex) || this.getEmptyPosition(marketIndex);
|
|
781
781
|
let freeCollateralDelta = this.calculateFreeCollateralDeltaForPerp(market, currentPerpPosition, positionBaseSizeChange);
|
|
782
782
|
if (!freeCollateralDelta) {
|
|
783
783
|
return new _1.BN(-1);
|
|
@@ -789,7 +789,7 @@ class User {
|
|
|
789
789
|
if (spotMarketWithSameOracle) {
|
|
790
790
|
const spotPosition = this.getSpotPosition(spotMarketWithSameOracle.marketIndex);
|
|
791
791
|
if (spotPosition) {
|
|
792
|
-
const signedTokenAmount =
|
|
792
|
+
const signedTokenAmount = _1.getSignedTokenAmount(spotBalance_1.getTokenAmount(spotPosition.scaledBalance, spotMarketWithSameOracle, spotPosition.balanceType), spotPosition.balanceType);
|
|
793
793
|
const spotFreeCollateralDelta = this.calculateFreeCollateralDeltaForSpot(spotMarketWithSameOracle, signedTokenAmount);
|
|
794
794
|
freeCollateralDelta = freeCollateralDelta.add(spotFreeCollateralDelta || numericConstants_1.ZERO);
|
|
795
795
|
}
|
|
@@ -809,11 +809,11 @@ class User {
|
|
|
809
809
|
}
|
|
810
810
|
calculateFreeCollateralDeltaForPerp(market, perpPosition, positionBaseSizeChange) {
|
|
811
811
|
const currentBaseAssetAmount = perpPosition.baseAssetAmount;
|
|
812
|
-
const worstCaseBaseAssetAmount =
|
|
812
|
+
const worstCaseBaseAssetAmount = margin_1.calculateWorstCaseBaseAssetAmount(perpPosition);
|
|
813
813
|
const orderBaseAssetAmount = worstCaseBaseAssetAmount.sub(currentBaseAssetAmount);
|
|
814
814
|
const proposedBaseAssetAmount = currentBaseAssetAmount.add(positionBaseSizeChange);
|
|
815
815
|
const proposedWorstCaseBaseAssetAmount = worstCaseBaseAssetAmount.add(positionBaseSizeChange);
|
|
816
|
-
const marginRatio =
|
|
816
|
+
const marginRatio = _1.calculateMarketMarginRatio(market, proposedWorstCaseBaseAssetAmount.abs(), 'Maintenance');
|
|
817
817
|
const marginRatioQuotePrecision = new _1.BN(marginRatio)
|
|
818
818
|
.mul(numericConstants_1.QUOTE_PRECISION)
|
|
819
819
|
.div(numericConstants_1.MARGIN_PRECISION);
|
|
@@ -840,14 +840,14 @@ class User {
|
|
|
840
840
|
calculateFreeCollateralDeltaForSpot(market, signedTokenAmount) {
|
|
841
841
|
const tokenPrecision = new _1.BN(Math.pow(10, market.decimals));
|
|
842
842
|
if (signedTokenAmount.gt(numericConstants_1.ZERO)) {
|
|
843
|
-
const assetWeight =
|
|
843
|
+
const assetWeight = spotBalance_1.calculateAssetWeight(signedTokenAmount, market, 'Maintenance');
|
|
844
844
|
return numericConstants_1.QUOTE_PRECISION.mul(assetWeight)
|
|
845
845
|
.div(numericConstants_1.SPOT_MARKET_WEIGHT_PRECISION)
|
|
846
846
|
.mul(signedTokenAmount)
|
|
847
847
|
.div(tokenPrecision);
|
|
848
848
|
}
|
|
849
849
|
else {
|
|
850
|
-
const liabilityWeight =
|
|
850
|
+
const liabilityWeight = spotBalance_1.calculateLiabilityWeight(signedTokenAmount.abs(), market, 'Maintenance');
|
|
851
851
|
return numericConstants_1.QUOTE_PRECISION.neg()
|
|
852
852
|
.mul(liabilityWeight)
|
|
853
853
|
.div(numericConstants_1.SPOT_MARKET_WEIGHT_PRECISION)
|
|
@@ -897,7 +897,7 @@ class User {
|
|
|
897
897
|
getMaxTradeSizeUSDC(targetMarketIndex, tradeSide) {
|
|
898
898
|
const currentPosition = this.getPerpPosition(targetMarketIndex) ||
|
|
899
899
|
this.getEmptyPosition(targetMarketIndex);
|
|
900
|
-
const targetSide =
|
|
900
|
+
const targetSide = types_1.isVariant(tradeSide, 'short') ? 'short' : 'long';
|
|
901
901
|
const currentPositionSide = (currentPosition === null || currentPosition === void 0 ? void 0 : currentPosition.baseAssetAmount.isNeg())
|
|
902
902
|
? 'short'
|
|
903
903
|
: 'long';
|
|
@@ -1009,7 +1009,7 @@ class User {
|
|
|
1009
1009
|
const nowTs = new _1.BN(Math.floor(Date.now() / 1000));
|
|
1010
1010
|
const spotMarket = this.driftClient.getSpotMarketAccount(marketIndex);
|
|
1011
1011
|
// eslint-disable-next-line prefer-const
|
|
1012
|
-
let { borrowLimit, withdrawLimit } =
|
|
1012
|
+
let { borrowLimit, withdrawLimit } = spotBalance_1.calculateWithdrawLimit(spotMarket, nowTs);
|
|
1013
1013
|
const freeCollateral = this.getFreeCollateral();
|
|
1014
1014
|
const oracleData = this.getOracleDataForSpotMarket(marketIndex);
|
|
1015
1015
|
const precisionIncrease = numericConstants_1.TEN.pow(new _1.BN(spotMarket.decimals - 6));
|
|
@@ -1055,7 +1055,7 @@ class User {
|
|
|
1055
1055
|
netDeposits,
|
|
1056
1056
|
};
|
|
1057
1057
|
}
|
|
1058
|
-
if (
|
|
1058
|
+
if (types_1.isVariant(position.balanceType, 'borrow')) {
|
|
1059
1059
|
return {
|
|
1060
1060
|
canBypass: false,
|
|
1061
1061
|
maxDepositAmount,
|
|
@@ -1063,7 +1063,7 @@ class User {
|
|
|
1063
1063
|
depositAmount: numericConstants_1.ZERO,
|
|
1064
1064
|
};
|
|
1065
1065
|
}
|
|
1066
|
-
const depositAmount =
|
|
1066
|
+
const depositAmount = spotBalance_1.getTokenAmount(position.scaledBalance, spotMarket, 'deposit');
|
|
1067
1067
|
if (netDeposits.lt(numericConstants_1.ZERO)) {
|
|
1068
1068
|
return {
|
|
1069
1069
|
canBypass: false,
|
package/lib/userMap/userMap.js
CHANGED
|
@@ -26,7 +26,7 @@ class UserMap {
|
|
|
26
26
|
userAccountArray.push(programUserAccount.account);
|
|
27
27
|
}
|
|
28
28
|
if (this.accountSubscription.type === 'polling') {
|
|
29
|
-
await
|
|
29
|
+
await __1.bulkPollingUserSubscribe(userArray, this.accountSubscription.accountLoader);
|
|
30
30
|
}
|
|
31
31
|
else {
|
|
32
32
|
await Promise.all(userArray.map((user, i) => user.subscribe(userAccountArray[i])));
|
|
@@ -23,14 +23,14 @@ class UserStatsMap {
|
|
|
23
23
|
}
|
|
24
24
|
const chUserStat = new __1.UserStats({
|
|
25
25
|
driftClient: this.driftClient,
|
|
26
|
-
userStatsAccountPublicKey:
|
|
26
|
+
userStatsAccountPublicKey: __1.getUserStatsAccountPublicKey(this.driftClient.program.programId, userStat.authority),
|
|
27
27
|
accountSubscription: this.accountSubscription,
|
|
28
28
|
});
|
|
29
29
|
userStatArray.push(chUserStat);
|
|
30
30
|
userStatsAccountArray.push(userStat);
|
|
31
31
|
}
|
|
32
32
|
if (this.accountSubscription.type === 'polling') {
|
|
33
|
-
await
|
|
33
|
+
await __1.bulkPollingUserStatsSubscribe(userStatArray, this.accountSubscription.accountLoader);
|
|
34
34
|
}
|
|
35
35
|
else {
|
|
36
36
|
await Promise.all(userStatArray.map((userStat, i) => userStat.subscribe(userStatsAccountArray[i])));
|
|
@@ -42,7 +42,7 @@ class UserStatsMap {
|
|
|
42
42
|
async addUserStat(authority) {
|
|
43
43
|
const userStat = new __1.UserStats({
|
|
44
44
|
driftClient: this.driftClient,
|
|
45
|
-
userStatsAccountPublicKey:
|
|
45
|
+
userStatsAccountPublicKey: __1.getUserStatsAccountPublicKey(this.driftClient.program.programId, authority),
|
|
46
46
|
accountSubscription: this.accountSubscription,
|
|
47
47
|
});
|
|
48
48
|
await userStat.subscribe();
|
package/lib/userStats.js
CHANGED
|
@@ -40,8 +40,8 @@ class UserStats {
|
|
|
40
40
|
}
|
|
41
41
|
else {
|
|
42
42
|
return {
|
|
43
|
-
referrer:
|
|
44
|
-
referrerStats:
|
|
43
|
+
referrer: pda_1.getUserAccountPublicKeySync(this.driftClient.program.programId, this.getAccount().referrer, 0),
|
|
44
|
+
referrerStats: pda_1.getUserStatsAccountPublicKey(this.driftClient.program.programId, this.getAccount().referrer),
|
|
45
45
|
};
|
|
46
46
|
}
|
|
47
47
|
}
|
package/package.json
CHANGED
|
@@ -17,6 +17,7 @@ export const BN_MAX = new BN(Number.MAX_SAFE_INTEGER);
|
|
|
17
17
|
export const TEN_MILLION = TEN_THOUSAND.mul(TEN_THOUSAND);
|
|
18
18
|
|
|
19
19
|
export const MAX_LEVERAGE = new BN(5);
|
|
20
|
+
export const MAX_LEVERAGE_ORDER_SIZE = new BN('18446744073709551615');
|
|
20
21
|
|
|
21
22
|
export const PERCENTAGE_PRECISION_EXP = new BN(6);
|
|
22
23
|
export const PERCENTAGE_PRECISION = new BN(10).pow(PERCENTAGE_PRECISION_EXP);
|
|
@@ -44,6 +44,16 @@ export const DevnetPerpMarkets: PerpMarketConfig[] = [
|
|
|
44
44
|
launchTs: 1637691133472,
|
|
45
45
|
oracleSource: OracleSource.PYTH,
|
|
46
46
|
},
|
|
47
|
+
{
|
|
48
|
+
fullName: 'Aptos',
|
|
49
|
+
category: ['L1', 'Infra'],
|
|
50
|
+
symbol: 'APT-PERP',
|
|
51
|
+
baseAssetSymbol: 'APT',
|
|
52
|
+
marketIndex: 3,
|
|
53
|
+
oracle: new PublicKey('5d2QJ6u2NveZufmJ4noHja5EHs3Bv1DUMPLG5xfasSVs'),
|
|
54
|
+
launchTs: 1675610186000,
|
|
55
|
+
oracleSource: OracleSource.PYTH,
|
|
56
|
+
},
|
|
47
57
|
];
|
|
48
58
|
|
|
49
59
|
export const MainnetPerpMarkets: PerpMarketConfig[] = [
|
package/src/dlob/DLOB.ts
CHANGED
|
@@ -951,7 +951,7 @@ export class DLOB {
|
|
|
951
951
|
}
|
|
952
952
|
|
|
953
953
|
isRestingLimitOrder(order: Order, slot: number): boolean {
|
|
954
|
-
return order.postOnly || new BN(slot).sub(order.slot).gte(new BN(
|
|
954
|
+
return order.postOnly || new BN(slot).sub(order.slot).gte(new BN(45));
|
|
955
955
|
}
|
|
956
956
|
|
|
957
957
|
*getLimitBids(
|
package/src/idl/drift.json
CHANGED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseTokenAccount = void 0;
|
|
4
|
+
const spl_token_1 = require("@solana/spl-token");
|
|
5
|
+
const web3_js_1 = require("@solana/web3.js");
|
|
6
|
+
function parseTokenAccount(data) {
|
|
7
|
+
const accountInfo = spl_token_1.AccountLayout.decode(data);
|
|
8
|
+
accountInfo.mint = new web3_js_1.PublicKey(accountInfo.mint);
|
|
9
|
+
accountInfo.owner = new web3_js_1.PublicKey(accountInfo.owner);
|
|
10
|
+
accountInfo.amount = spl_token_1.u64.fromBuffer(accountInfo.amount);
|
|
11
|
+
if (accountInfo.delegateOption === 0) {
|
|
12
|
+
accountInfo.delegate = null;
|
|
13
|
+
// eslint-disable-next-line new-cap
|
|
14
|
+
accountInfo.delegatedAmount = new spl_token_1.u64(0);
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
accountInfo.delegate = new web3_js_1.PublicKey(accountInfo.delegate);
|
|
18
|
+
accountInfo.delegatedAmount = spl_token_1.u64.fromBuffer(accountInfo.delegatedAmount);
|
|
19
|
+
}
|
|
20
|
+
accountInfo.isInitialized = accountInfo.state !== 0;
|
|
21
|
+
accountInfo.isFrozen = accountInfo.state === 2;
|
|
22
|
+
if (accountInfo.isNativeOption === 1) {
|
|
23
|
+
accountInfo.rentExemptReserve = spl_token_1.u64.fromBuffer(accountInfo.isNative);
|
|
24
|
+
accountInfo.isNative = true;
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
accountInfo.rentExemptReserve = null;
|
|
28
|
+
accountInfo.isNative = false;
|
|
29
|
+
}
|
|
30
|
+
if (accountInfo.closeAuthorityOption === 0) {
|
|
31
|
+
accountInfo.closeAuthority = null;
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
accountInfo.closeAuthority = new web3_js_1.PublicKey(accountInfo.closeAuthority);
|
|
35
|
+
}
|
|
36
|
+
return accountInfo;
|
|
37
|
+
}
|
|
38
|
+
exports.parseTokenAccount = parseTokenAccount;
|
package/src/tx/types.js
ADDED
package/src/tx/utils.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.wrapInTx = void 0;
|
|
4
|
+
const web3_js_1 = require("@solana/web3.js");
|
|
5
|
+
const COMPUTE_UNITS_DEFAULT = 200000;
|
|
6
|
+
function wrapInTx(instruction, computeUnits = 600000 // TODO, requires less code change
|
|
7
|
+
) {
|
|
8
|
+
const tx = new web3_js_1.Transaction();
|
|
9
|
+
if (computeUnits != COMPUTE_UNITS_DEFAULT) {
|
|
10
|
+
tx.add(web3_js_1.ComputeBudgetProgram.requestUnits({
|
|
11
|
+
units: computeUnits,
|
|
12
|
+
additionalFee: 0,
|
|
13
|
+
}));
|
|
14
|
+
}
|
|
15
|
+
return tx.add(instruction);
|
|
16
|
+
}
|
|
17
|
+
exports.wrapInTx = wrapInTx;
|
package/src/user.ts
CHANGED
|
@@ -1377,7 +1377,8 @@ export class User {
|
|
|
1377
1377
|
);
|
|
1378
1378
|
|
|
1379
1379
|
const market = this.driftClient.getPerpMarketAccount(marketIndex);
|
|
1380
|
-
const currentPerpPosition =
|
|
1380
|
+
const currentPerpPosition =
|
|
1381
|
+
this.getPerpPosition(marketIndex) || this.getEmptyPosition(marketIndex);
|
|
1381
1382
|
|
|
1382
1383
|
let freeCollateralDelta = this.calculateFreeCollateralDeltaForPerp(
|
|
1383
1384
|
market,
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.findComputeUnitConsumption = void 0;
|
|
13
|
+
function findComputeUnitConsumption(programId, connection, txSignature, commitment = 'confirmed') {
|
|
14
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
15
|
+
const tx = yield connection.getTransaction(txSignature, { commitment });
|
|
16
|
+
const computeUnits = [];
|
|
17
|
+
const regex = new RegExp(`Program ${programId.toString()} consumed ([0-9]{0,6}) of ([0-9]{0,7}) compute units`);
|
|
18
|
+
tx.meta.logMessages.forEach((logMessage) => {
|
|
19
|
+
const match = logMessage.match(regex);
|
|
20
|
+
if (match && match[1]) {
|
|
21
|
+
computeUnits.push(match[1]);
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
return computeUnits;
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
exports.findComputeUnitConsumption = findComputeUnitConsumption;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getTokenAddress = void 0;
|
|
4
|
+
const spl_token_1 = require("@solana/spl-token");
|
|
5
|
+
const web3_js_1 = require("@solana/web3.js");
|
|
6
|
+
const getTokenAddress = (mintAddress, userPubKey) => {
|
|
7
|
+
return spl_token_1.Token.getAssociatedTokenAddress(spl_token_1.ASSOCIATED_TOKEN_PROGRAM_ID, spl_token_1.TOKEN_PROGRAM_ID, new web3_js_1.PublicKey(mintAddress), new web3_js_1.PublicKey(userPubKey));
|
|
8
|
+
};
|
|
9
|
+
exports.getTokenAddress = getTokenAddress;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.promiseTimeout = void 0;
|
|
4
|
+
function promiseTimeout(promise, timeoutMs) {
|
|
5
|
+
let timeoutId;
|
|
6
|
+
const timeoutPromise = new Promise((resolve) => {
|
|
7
|
+
timeoutId = setTimeout(() => resolve(null), timeoutMs);
|
|
8
|
+
});
|
|
9
|
+
return Promise.race([promise, timeoutPromise]).then((result) => {
|
|
10
|
+
clearTimeout(timeoutId);
|
|
11
|
+
return result;
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
exports.promiseTimeout = promiseTimeout;
|
package/src/util/tps.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.estimateTps = void 0;
|
|
13
|
+
function estimateTps(programId, connection, failed) {
|
|
14
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
15
|
+
let signatures = yield connection.getSignaturesForAddress(programId, undefined, 'finalized');
|
|
16
|
+
if (failed) {
|
|
17
|
+
signatures = signatures.filter((signature) => signature.err);
|
|
18
|
+
}
|
|
19
|
+
const numberOfSignatures = signatures.length;
|
|
20
|
+
if (numberOfSignatures === 0) {
|
|
21
|
+
return 0;
|
|
22
|
+
}
|
|
23
|
+
return (numberOfSignatures /
|
|
24
|
+
(signatures[0].blockTime - signatures[numberOfSignatures - 1].blockTime));
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
exports.estimateTps = estimateTps;
|