@drift-labs/sdk 0.2.0-master.32 → 0.2.0-master.34
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.js +2 -1
- package/lib/accounts/pollingClearingHouseAccountSubscriber.d.ts +2 -2
- package/lib/accounts/pollingClearingHouseAccountSubscriber.js +8 -8
- package/lib/accounts/types.d.ts +1 -0
- package/lib/accounts/webSocketClearingHouseAccountSubscriber.d.ts +2 -2
- package/lib/accounts/webSocketClearingHouseAccountSubscriber.js +7 -7
- package/lib/addresses/marketAddresses.js +1 -1
- package/lib/addresses/pda.d.ts +4 -4
- package/lib/addresses/pda.js +23 -22
- package/lib/admin.d.ts +30 -32
- package/lib/admin.js +111 -119
- package/lib/clearingHouse.d.ts +43 -34
- package/lib/clearingHouse.js +353 -193
- package/lib/clearingHouseConfig.d.ts +2 -2
- package/lib/clearingHouseUser.d.ts +26 -5
- package/lib/clearingHouseUser.js +151 -51
- package/lib/config.d.ts +2 -0
- package/lib/config.js +5 -1
- package/lib/constants/numericConstants.d.ts +1 -0
- package/lib/constants/numericConstants.js +3 -2
- package/lib/dlob/DLOB.d.ts +18 -11
- package/lib/dlob/DLOB.js +179 -107
- package/lib/dlob/DLOBNode.js +2 -10
- package/lib/dlob/NodeList.js +1 -1
- package/lib/events/eventSubscriber.d.ts +1 -0
- package/lib/events/eventSubscriber.js +11 -4
- package/lib/events/fetchLogs.d.ts +3 -1
- package/lib/events/fetchLogs.js +13 -5
- package/lib/events/pollingLogProvider.js +1 -1
- package/lib/events/types.d.ts +1 -1
- package/lib/events/webSocketLogProvider.js +1 -1
- package/lib/factory/bigNum.d.ts +5 -4
- package/lib/factory/bigNum.js +36 -6
- package/lib/idl/clearing_house.json +1540 -1246
- package/lib/index.d.ts +3 -0
- package/lib/index.js +3 -0
- package/lib/math/amm.js +9 -9
- package/lib/math/exchangeStatus.d.ts +4 -0
- package/lib/math/exchangeStatus.js +18 -0
- package/lib/math/funding.js +10 -10
- package/lib/math/margin.js +6 -1
- package/lib/math/market.js +9 -9
- package/lib/math/orders.d.ts +7 -3
- package/lib/math/orders.js +39 -31
- package/lib/math/repeg.js +3 -3
- package/lib/math/spotBalance.js +3 -3
- package/lib/math/spotPosition.js +2 -2
- package/lib/serum/serumFulfillmentConfigMap.d.ts +10 -0
- package/lib/serum/serumFulfillmentConfigMap.js +17 -0
- package/lib/serum/serumSubscriber.d.ts +4 -0
- package/lib/serum/serumSubscriber.js +16 -1
- package/lib/types.d.ts +60 -75
- package/lib/types.js +2 -1
- package/lib/userMap/userMap.d.ts +17 -1
- package/lib/userMap/userMap.js +12 -0
- package/lib/userName.d.ts +1 -0
- package/lib/userName.js +3 -2
- package/package.json +1 -1
- package/src/accounts/bulkAccountLoader.ts +5 -1
- package/src/accounts/pollingClearingHouseAccountSubscriber.ts +9 -9
- package/src/accounts/webSocketClearingHouseAccountSubscriber.ts +8 -8
- package/src/addresses/marketAddresses.ts +2 -2
- package/src/addresses/pda.ts +20 -20
- package/src/admin.ts +246 -221
- package/src/assert/assert.js +9 -0
- package/src/clearingHouse.ts +556 -236
- package/src/clearingHouseConfig.ts +2 -2
- package/src/clearingHouseUser.ts +237 -87
- package/src/config.ts +8 -1
- package/src/constants/numericConstants.ts +5 -1
- package/src/dlob/DLOB.ts +257 -120
- package/src/dlob/DLOBNode.ts +2 -14
- package/src/dlob/NodeList.ts +1 -1
- package/src/events/eventList.js +77 -0
- package/src/events/eventSubscriber.ts +18 -4
- package/src/events/fetchLogs.ts +20 -5
- package/src/events/pollingLogProvider.ts +1 -1
- package/src/events/types.ts +2 -1
- package/src/events/webSocketLogProvider.ts +1 -1
- package/src/examples/makeTradeExample.js +157 -0
- package/src/factory/bigNum.ts +59 -6
- package/src/idl/clearing_house.json +1540 -1246
- package/src/idl/pyth.json +98 -2
- package/src/index.ts +3 -0
- package/src/math/amm.ts +9 -9
- package/src/math/exchangeStatus.ts +31 -0
- package/src/math/funding.ts +20 -10
- package/src/math/margin.ts +7 -1
- package/src/math/market.ts +9 -9
- package/src/math/orders.ts +44 -29
- package/src/math/repeg.ts +3 -3
- package/src/math/spotBalance.ts +4 -4
- package/src/math/spotPosition.ts +2 -2
- package/src/serum/serumFulfillmentConfigMap.ts +26 -0
- package/src/serum/serumSubscriber.ts +20 -1
- package/src/token/index.js +38 -0
- package/src/tx/types.js +2 -0
- package/src/tx/utils.js +17 -0
- package/src/types.ts +65 -51
- package/src/userMap/userMap.ts +25 -1
- package/src/userName.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/tests/bn/test.ts +22 -1
- package/tests/dlob/helpers.ts +252 -81
- package/tests/dlob/test.ts +1040 -219
|
@@ -11,8 +11,8 @@ export type ClearingHouseConfig = {
|
|
|
11
11
|
accountSubscription?: ClearingHouseSubscriptionConfig;
|
|
12
12
|
opts?: ConfirmOptions;
|
|
13
13
|
txSenderConfig?: TxSenderConfig;
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
subAccountIds?: number[];
|
|
15
|
+
activeSubAccountId?: number;
|
|
16
16
|
perpMarketIndexes?: number[];
|
|
17
17
|
spotMarketIndexes?: number[];
|
|
18
18
|
oracleInfos?: OracleInfo[];
|
package/src/clearingHouseUser.ts
CHANGED
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
MARGIN_PRECISION,
|
|
23
23
|
SPOT_MARKET_WEIGHT_PRECISION,
|
|
24
24
|
QUOTE_SPOT_MARKET_INDEX,
|
|
25
|
+
TEN,
|
|
25
26
|
} from './constants/numericConstants';
|
|
26
27
|
import {
|
|
27
28
|
UserAccountSubscriber,
|
|
@@ -40,12 +41,15 @@ import {
|
|
|
40
41
|
BN,
|
|
41
42
|
SpotMarketAccount,
|
|
42
43
|
getTokenValue,
|
|
44
|
+
SpotBalanceType,
|
|
43
45
|
} from '.';
|
|
44
46
|
import {
|
|
45
47
|
getTokenAmount,
|
|
46
48
|
calculateAssetWeight,
|
|
47
49
|
calculateLiabilityWeight,
|
|
50
|
+
calculateWithdrawLimit,
|
|
48
51
|
} from './math/spotBalance';
|
|
52
|
+
import { calculateMarketOpenBidAsk } from './math/amm';
|
|
49
53
|
import {
|
|
50
54
|
calculateBaseAssetValueWithOracle,
|
|
51
55
|
calculateWorstCaseBaseAssetAmount,
|
|
@@ -186,6 +190,50 @@ export class ClearingHouseUser {
|
|
|
186
190
|
return userAccountRPCResponse.value !== null;
|
|
187
191
|
}
|
|
188
192
|
|
|
193
|
+
/**
|
|
194
|
+
* calculates the total open bids/asks in a perp market (including lps)
|
|
195
|
+
* @returns : open bids
|
|
196
|
+
* @returns : open asks
|
|
197
|
+
*/
|
|
198
|
+
public getPerpBidAsks(marketIndex: number): [BN, BN] {
|
|
199
|
+
const position = this.getUserPosition(marketIndex);
|
|
200
|
+
|
|
201
|
+
const [lpOpenBids, lpOpenAsks] = this.getLPBidAsks(marketIndex);
|
|
202
|
+
|
|
203
|
+
const totalOpenBids = lpOpenBids.add(position.openBids);
|
|
204
|
+
const totalOpenAsks = lpOpenAsks.sub(position.openAsks);
|
|
205
|
+
|
|
206
|
+
return [totalOpenBids, totalOpenAsks];
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* calculates the open bids and asks for an lp
|
|
211
|
+
* @returns : lp open bids
|
|
212
|
+
* @returns : lp open asks
|
|
213
|
+
*/
|
|
214
|
+
public getLPBidAsks(marketIndex: number): [BN, BN] {
|
|
215
|
+
const position = this.getUserPosition(marketIndex);
|
|
216
|
+
if (position.lpShares.eq(ZERO)) {
|
|
217
|
+
return [ZERO, ZERO];
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const market = this.clearingHouse.getPerpMarketAccount(marketIndex);
|
|
221
|
+
const [marketOpenBids, marketOpenAsks] = calculateMarketOpenBidAsk(
|
|
222
|
+
market.amm.baseAssetReserve,
|
|
223
|
+
market.amm.minBaseAssetReserve,
|
|
224
|
+
market.amm.maxBaseAssetReserve
|
|
225
|
+
);
|
|
226
|
+
|
|
227
|
+
const lpOpenBids = marketOpenBids
|
|
228
|
+
.mul(position.lpShares)
|
|
229
|
+
.div(market.amm.sqrtK);
|
|
230
|
+
const lpOpenAsks = marketOpenAsks
|
|
231
|
+
.mul(position.lpShares)
|
|
232
|
+
.div(market.amm.sqrtK);
|
|
233
|
+
|
|
234
|
+
return [lpOpenBids, lpOpenAsks];
|
|
235
|
+
}
|
|
236
|
+
|
|
189
237
|
/**
|
|
190
238
|
* calculates the market position if the lp position was settled
|
|
191
239
|
* @returns : the settled userPosition
|
|
@@ -196,16 +244,20 @@ export class ClearingHouseUser {
|
|
|
196
244
|
const _position = this.getUserPosition(marketIndex);
|
|
197
245
|
const position = this.getClonedPosition(_position);
|
|
198
246
|
|
|
247
|
+
if (position.lpShares.eq(ZERO)) {
|
|
248
|
+
return [position, ZERO, ZERO];
|
|
249
|
+
}
|
|
250
|
+
|
|
199
251
|
const market = this.clearingHouse.getPerpMarketAccount(
|
|
200
252
|
position.marketIndex
|
|
201
253
|
);
|
|
202
254
|
const nShares = position.lpShares;
|
|
203
255
|
|
|
204
|
-
const deltaBaa = market.amm.
|
|
256
|
+
const deltaBaa = market.amm.baseAssetAmountPerLp
|
|
205
257
|
.sub(position.lastNetBaseAssetAmountPerLp)
|
|
206
258
|
.mul(nShares)
|
|
207
259
|
.div(AMM_RESERVE_PRECISION);
|
|
208
|
-
const deltaQaa = market.amm.
|
|
260
|
+
const deltaQaa = market.amm.quoteAssetAmountPerLp
|
|
209
261
|
.sub(position.lastNetQuoteAssetAmountPerLp)
|
|
210
262
|
.mul(nShares)
|
|
211
263
|
.div(AMM_RESERVE_PRECISION);
|
|
@@ -217,7 +269,7 @@ export class ClearingHouseUser {
|
|
|
217
269
|
return sign;
|
|
218
270
|
}
|
|
219
271
|
|
|
220
|
-
function standardize(amount, stepsize) {
|
|
272
|
+
function standardize(amount: BN, stepsize: BN) {
|
|
221
273
|
const remainder = amount.abs().mod(stepsize).mul(sign(amount));
|
|
222
274
|
const standardizedAmount = amount.sub(remainder);
|
|
223
275
|
return [standardizedAmount, remainder];
|
|
@@ -225,18 +277,18 @@ export class ClearingHouseUser {
|
|
|
225
277
|
|
|
226
278
|
const [standardizedBaa, remainderBaa] = standardize(
|
|
227
279
|
deltaBaa,
|
|
228
|
-
market.amm.
|
|
280
|
+
market.amm.orderStepSize
|
|
229
281
|
);
|
|
230
282
|
|
|
231
283
|
position.remainderBaseAssetAmount += remainderBaa.toNumber();
|
|
232
284
|
|
|
233
285
|
if (
|
|
234
286
|
Math.abs(position.remainderBaseAssetAmount) >
|
|
235
|
-
market.amm.
|
|
287
|
+
market.amm.orderStepSize.toNumber()
|
|
236
288
|
) {
|
|
237
289
|
const [newStandardizedBaa, newRemainderBaa] = standardize(
|
|
238
|
-
position.remainderBaseAssetAmount,
|
|
239
|
-
market.amm.
|
|
290
|
+
new BN(position.remainderBaseAssetAmount),
|
|
291
|
+
market.amm.orderStepSize
|
|
240
292
|
);
|
|
241
293
|
position.baseAssetAmount =
|
|
242
294
|
position.baseAssetAmount.add(newStandardizedBaa);
|
|
@@ -364,7 +416,9 @@ export class ClearingHouseUser {
|
|
|
364
416
|
const market = this.clearingHouse.getPerpMarketAccount(
|
|
365
417
|
perpPosition.marketIndex
|
|
366
418
|
);
|
|
367
|
-
const oraclePriceData = this.
|
|
419
|
+
const oraclePriceData = this.getOracleDataForPerpMarket(
|
|
420
|
+
market.marketIndex
|
|
421
|
+
);
|
|
368
422
|
|
|
369
423
|
let positionUnrealizedPnl = calculatePositionPNL(
|
|
370
424
|
market,
|
|
@@ -432,7 +486,7 @@ export class ClearingHouseUser {
|
|
|
432
486
|
if (spotPosition.marketIndex === QUOTE_SPOT_MARKET_INDEX) {
|
|
433
487
|
if (isVariant(spotPosition.balanceType, 'borrow')) {
|
|
434
488
|
const tokenAmount = getTokenAmount(
|
|
435
|
-
spotPosition.
|
|
489
|
+
spotPosition.scaledBalance,
|
|
436
490
|
spotMarketAccount,
|
|
437
491
|
spotPosition.balanceType
|
|
438
492
|
);
|
|
@@ -441,7 +495,7 @@ export class ClearingHouseUser {
|
|
|
441
495
|
if (marginCategory === 'Initial') {
|
|
442
496
|
weight = BN.max(
|
|
443
497
|
weight,
|
|
444
|
-
new BN(this.getUserAccount().
|
|
498
|
+
new BN(this.getUserAccount().maxMarginRatio)
|
|
445
499
|
);
|
|
446
500
|
}
|
|
447
501
|
|
|
@@ -462,7 +516,7 @@ export class ClearingHouseUser {
|
|
|
462
516
|
if (!includeOpenOrders) {
|
|
463
517
|
if (isVariant(spotPosition.balanceType, 'borrow')) {
|
|
464
518
|
const tokenAmount = getTokenAmount(
|
|
465
|
-
spotPosition.
|
|
519
|
+
spotPosition.scaledBalance,
|
|
466
520
|
spotMarketAccount,
|
|
467
521
|
spotPosition.balanceType
|
|
468
522
|
);
|
|
@@ -505,7 +559,7 @@ export class ClearingHouseUser {
|
|
|
505
559
|
if (marginCategory === 'Initial') {
|
|
506
560
|
weight = BN.max(
|
|
507
561
|
weight,
|
|
508
|
-
new BN(this.getUserAccount().
|
|
562
|
+
new BN(this.getUserAccount().maxMarginRatio)
|
|
509
563
|
);
|
|
510
564
|
}
|
|
511
565
|
|
|
@@ -545,10 +599,7 @@ export class ClearingHouseUser {
|
|
|
545
599
|
);
|
|
546
600
|
|
|
547
601
|
if (marginCategory === 'Initial') {
|
|
548
|
-
weight = BN.max(
|
|
549
|
-
weight,
|
|
550
|
-
new BN(this.getUserAccount().customMarginRatio)
|
|
551
|
-
);
|
|
602
|
+
weight = BN.max(weight, new BN(this.getUserAccount().maxMarginRatio));
|
|
552
603
|
}
|
|
553
604
|
|
|
554
605
|
if (liquidationBuffer !== undefined) {
|
|
@@ -585,7 +636,7 @@ export class ClearingHouseUser {
|
|
|
585
636
|
if (spotPosition.marketIndex === QUOTE_SPOT_MARKET_INDEX) {
|
|
586
637
|
if (isVariant(spotPosition.balanceType, 'deposit')) {
|
|
587
638
|
const tokenAmount = getTokenAmount(
|
|
588
|
-
spotPosition.
|
|
639
|
+
spotPosition.scaledBalance,
|
|
589
640
|
spotMarketAccount,
|
|
590
641
|
spotPosition.balanceType
|
|
591
642
|
);
|
|
@@ -603,7 +654,7 @@ export class ClearingHouseUser {
|
|
|
603
654
|
if (!includeOpenOrders) {
|
|
604
655
|
if (isVariant(spotPosition.balanceType, 'deposit')) {
|
|
605
656
|
const tokenAmount = getTokenAmount(
|
|
606
|
-
spotPosition.
|
|
657
|
+
spotPosition.scaledBalance,
|
|
607
658
|
spotMarketAccount,
|
|
608
659
|
spotPosition.balanceType
|
|
609
660
|
);
|
|
@@ -748,12 +799,12 @@ export class ClearingHouseUser {
|
|
|
748
799
|
perpPosition.openBids = perpPosition.openBids.add(openBids);
|
|
749
800
|
}
|
|
750
801
|
|
|
751
|
-
let valuationPrice = this.
|
|
802
|
+
let valuationPrice = this.getOracleDataForPerpMarket(
|
|
752
803
|
market.marketIndex
|
|
753
804
|
).price;
|
|
754
805
|
|
|
755
806
|
if (isVariant(market.status, 'settlement')) {
|
|
756
|
-
valuationPrice = market.
|
|
807
|
+
valuationPrice = market.expiryPrice;
|
|
757
808
|
}
|
|
758
809
|
|
|
759
810
|
const baseAssetAmount = includeOpenOrders
|
|
@@ -777,7 +828,7 @@ export class ClearingHouseUser {
|
|
|
777
828
|
if (marginCategory === 'Initial') {
|
|
778
829
|
marginRatio = BN.max(
|
|
779
830
|
marginRatio,
|
|
780
|
-
new BN(this.getUserAccount().
|
|
831
|
+
new BN(this.getUserAccount().maxMarginRatio)
|
|
781
832
|
);
|
|
782
833
|
}
|
|
783
834
|
|
|
@@ -785,6 +836,10 @@ export class ClearingHouseUser {
|
|
|
785
836
|
marginRatio = marginRatio.add(liquidationBuffer);
|
|
786
837
|
}
|
|
787
838
|
|
|
839
|
+
if (isVariant(market.status, 'settlement')) {
|
|
840
|
+
marginRatio = ZERO;
|
|
841
|
+
}
|
|
842
|
+
|
|
788
843
|
baseAssetValue = baseAssetValue
|
|
789
844
|
.mul(marginRatio)
|
|
790
845
|
.div(MARGIN_PRECISION);
|
|
@@ -843,7 +898,9 @@ export class ClearingHouseUser {
|
|
|
843
898
|
|
|
844
899
|
const entryPrice = calculateEntryPrice(position);
|
|
845
900
|
|
|
846
|
-
const oraclePriceData = this.
|
|
901
|
+
const oraclePriceData = this.getOracleDataForPerpMarket(
|
|
902
|
+
position.marketIndex
|
|
903
|
+
);
|
|
847
904
|
|
|
848
905
|
if (amountToClose) {
|
|
849
906
|
if (amountToClose.eq(ZERO)) {
|
|
@@ -894,25 +951,10 @@ export class ClearingHouseUser {
|
|
|
894
951
|
* calculates current user leverage across all positions
|
|
895
952
|
* @returns : Precision TEN_THOUSAND
|
|
896
953
|
*/
|
|
897
|
-
public getLeverage(
|
|
898
|
-
const totalLiabilityValue = this.
|
|
899
|
-
marginCategory,
|
|
900
|
-
undefined,
|
|
901
|
-
true
|
|
902
|
-
).add(
|
|
903
|
-
this.getSpotMarketLiabilityValue(
|
|
904
|
-
undefined,
|
|
905
|
-
marginCategory,
|
|
906
|
-
undefined,
|
|
907
|
-
true
|
|
908
|
-
)
|
|
909
|
-
);
|
|
954
|
+
public getLeverage(): BN {
|
|
955
|
+
const totalLiabilityValue = this.getTotalLiabilityValue();
|
|
910
956
|
|
|
911
|
-
const totalAssetValue = this.
|
|
912
|
-
undefined,
|
|
913
|
-
marginCategory,
|
|
914
|
-
true
|
|
915
|
-
).add(this.getUnrealizedPNL(true, undefined, marginCategory));
|
|
957
|
+
const totalAssetValue = this.getTotalAssetValue();
|
|
916
958
|
|
|
917
959
|
if (totalAssetValue.eq(ZERO) && totalLiabilityValue.eq(ZERO)) {
|
|
918
960
|
return ZERO;
|
|
@@ -921,9 +963,21 @@ export class ClearingHouseUser {
|
|
|
921
963
|
return totalLiabilityValue.mul(TEN_THOUSAND).div(totalAssetValue);
|
|
922
964
|
}
|
|
923
965
|
|
|
966
|
+
getTotalLiabilityValue(): BN {
|
|
967
|
+
return this.getTotalPerpPositionValue(undefined, undefined, true).add(
|
|
968
|
+
this.getSpotMarketLiabilityValue(undefined, undefined, undefined, true)
|
|
969
|
+
);
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
getTotalAssetValue(): BN {
|
|
973
|
+
return this.getSpotMarketAssetValue(undefined, undefined, true).add(
|
|
974
|
+
this.getUnrealizedPNL(true, undefined, undefined)
|
|
975
|
+
);
|
|
976
|
+
}
|
|
977
|
+
|
|
924
978
|
/**
|
|
925
979
|
* calculates max allowable leverage exceeding hitting requirement category
|
|
926
|
-
* @params category {Initial,
|
|
980
|
+
* @params category {Initial, Maintenance}
|
|
927
981
|
* @returns : Precision TEN_THOUSAND
|
|
928
982
|
*/
|
|
929
983
|
public getMaxLeverage(
|
|
@@ -932,45 +986,44 @@ export class ClearingHouseUser {
|
|
|
932
986
|
): BN {
|
|
933
987
|
const market = this.clearingHouse.getPerpMarketAccount(marketIndex);
|
|
934
988
|
|
|
935
|
-
const
|
|
989
|
+
const totalAssetValue = this.getTotalAssetValue();
|
|
990
|
+
if (totalAssetValue.eq(ZERO)) {
|
|
991
|
+
return ZERO;
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
const totalLiabilityValue = this.getTotalLiabilityValue();
|
|
995
|
+
|
|
996
|
+
const marginRatio = calculateMarketMarginRatio(
|
|
936
997
|
market,
|
|
937
998
|
// worstCaseBaseAssetAmount.abs(),
|
|
938
999
|
ZERO, // todo
|
|
939
1000
|
category
|
|
940
1001
|
);
|
|
941
|
-
const
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
1002
|
+
const freeCollateral = this.getFreeCollateral();
|
|
1003
|
+
|
|
1004
|
+
// how much more liabilities can be opened w remaining free collateral
|
|
1005
|
+
const additionalLiabilities = freeCollateral
|
|
1006
|
+
.mul(MARGIN_PRECISION)
|
|
1007
|
+
.div(new BN(marginRatio));
|
|
1008
|
+
|
|
1009
|
+
return totalLiabilityValue
|
|
1010
|
+
.add(additionalLiabilities)
|
|
1011
|
+
.mul(TEN_THOUSAND)
|
|
1012
|
+
.div(totalAssetValue);
|
|
945
1013
|
}
|
|
946
1014
|
|
|
947
1015
|
/**
|
|
948
1016
|
* calculates margin ratio: total collateral / |total position value|
|
|
949
1017
|
* @returns : Precision TEN_THOUSAND
|
|
950
1018
|
*/
|
|
951
|
-
public getMarginRatio(
|
|
952
|
-
const totalLiabilityValue = this.
|
|
953
|
-
marginCategory,
|
|
954
|
-
undefined,
|
|
955
|
-
true
|
|
956
|
-
).add(
|
|
957
|
-
this.getSpotMarketLiabilityValue(
|
|
958
|
-
undefined,
|
|
959
|
-
marginCategory,
|
|
960
|
-
undefined,
|
|
961
|
-
true
|
|
962
|
-
)
|
|
963
|
-
);
|
|
1019
|
+
public getMarginRatio(): BN {
|
|
1020
|
+
const totalLiabilityValue = this.getTotalLiabilityValue();
|
|
964
1021
|
|
|
965
1022
|
if (totalLiabilityValue.eq(ZERO)) {
|
|
966
1023
|
return BN_MAX;
|
|
967
1024
|
}
|
|
968
1025
|
|
|
969
|
-
const totalAssetValue = this.
|
|
970
|
-
undefined,
|
|
971
|
-
marginCategory,
|
|
972
|
-
true
|
|
973
|
-
).add(this.getUnrealizedPNL(true, undefined, marginCategory));
|
|
1026
|
+
const totalAssetValue = this.getTotalAssetValue();
|
|
974
1027
|
|
|
975
1028
|
return totalAssetValue.mul(TEN_THOUSAND).div(totalLiabilityValue);
|
|
976
1029
|
}
|
|
@@ -980,7 +1033,7 @@ export class ClearingHouseUser {
|
|
|
980
1033
|
|
|
981
1034
|
// if user being liq'd, can continue to be liq'd until total collateral above the margin requirement plus buffer
|
|
982
1035
|
let liquidationBuffer = undefined;
|
|
983
|
-
if (this.getUserAccount().
|
|
1036
|
+
if (this.getUserAccount().isBeingLiquidated) {
|
|
984
1037
|
liquidationBuffer = new BN(
|
|
985
1038
|
this.clearingHouse.getStateAccount().liquidationMarginBufferRatio
|
|
986
1039
|
);
|
|
@@ -1084,7 +1137,7 @@ export class ClearingHouseUser {
|
|
|
1084
1137
|
const proposedPerpPositionValue = calculateBaseAssetValueWithOracle(
|
|
1085
1138
|
market,
|
|
1086
1139
|
proposedPerpPosition,
|
|
1087
|
-
this.
|
|
1140
|
+
this.getOracleDataForPerpMarket(market.marketIndex)
|
|
1088
1141
|
);
|
|
1089
1142
|
|
|
1090
1143
|
// total position value after trade
|
|
@@ -1101,7 +1154,7 @@ export class ClearingHouseUser {
|
|
|
1101
1154
|
const positionValue = calculateBaseAssetValueWithOracle(
|
|
1102
1155
|
market,
|
|
1103
1156
|
position,
|
|
1104
|
-
this.
|
|
1157
|
+
this.getOracleDataForPerpMarket(market.marketIndex)
|
|
1105
1158
|
);
|
|
1106
1159
|
const marketMarginRequirement = positionValue
|
|
1107
1160
|
.mul(
|
|
@@ -1179,7 +1232,7 @@ export class ClearingHouseUser {
|
|
|
1179
1232
|
if (positionBaseSizeChange.eq(ZERO)) {
|
|
1180
1233
|
markPriceAfterTrade = calculateReservePrice(
|
|
1181
1234
|
this.clearingHouse.getPerpMarketAccount(perpPosition.marketIndex),
|
|
1182
|
-
this.
|
|
1235
|
+
this.getOracleDataForPerpMarket(perpPosition.marketIndex)
|
|
1183
1236
|
);
|
|
1184
1237
|
} else {
|
|
1185
1238
|
const direction = positionBaseSizeChange.gt(ZERO)
|
|
@@ -1190,7 +1243,7 @@ export class ClearingHouseUser {
|
|
|
1190
1243
|
positionBaseSizeChange.abs(),
|
|
1191
1244
|
this.clearingHouse.getPerpMarketAccount(perpPosition.marketIndex),
|
|
1192
1245
|
'base',
|
|
1193
|
-
this.
|
|
1246
|
+
this.getOracleDataForPerpMarket(perpPosition.marketIndex)
|
|
1194
1247
|
)[3]; // newPrice after swap
|
|
1195
1248
|
}
|
|
1196
1249
|
|
|
@@ -1272,7 +1325,7 @@ export class ClearingHouseUser {
|
|
|
1272
1325
|
? true
|
|
1273
1326
|
: targetSide === currentPositionSide;
|
|
1274
1327
|
|
|
1275
|
-
const oracleData = this.
|
|
1328
|
+
const oracleData = this.getOracleDataForPerpMarket(targetMarketIndex);
|
|
1276
1329
|
|
|
1277
1330
|
// 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.
|
|
1278
1331
|
const oppositeSizeValueUSDC = targetingSameSide
|
|
@@ -1342,13 +1395,14 @@ export class ClearingHouseUser {
|
|
|
1342
1395
|
public accountLeverageRatioAfterTrade(
|
|
1343
1396
|
targetMarketIndex: number,
|
|
1344
1397
|
tradeQuoteAmount: BN,
|
|
1345
|
-
tradeSide: PositionDirection
|
|
1398
|
+
tradeSide: PositionDirection,
|
|
1399
|
+
includeOpenOrders = true
|
|
1346
1400
|
): BN {
|
|
1347
1401
|
const currentPosition =
|
|
1348
1402
|
this.getUserPosition(targetMarketIndex) ||
|
|
1349
1403
|
this.getEmptyPosition(targetMarketIndex);
|
|
1350
1404
|
|
|
1351
|
-
const oracleData = this.
|
|
1405
|
+
const oracleData = this.getOracleDataForPerpMarket(targetMarketIndex);
|
|
1352
1406
|
|
|
1353
1407
|
let currentPositionQuoteAmount = this.getPerpPositionValue(
|
|
1354
1408
|
targetMarketIndex,
|
|
@@ -1371,19 +1425,32 @@ export class ClearingHouseUser {
|
|
|
1371
1425
|
.abs();
|
|
1372
1426
|
|
|
1373
1427
|
const totalPositionAfterTradeExcludingTargetMarket =
|
|
1374
|
-
this.getTotalPerpPositionValueExcludingMarket(
|
|
1428
|
+
this.getTotalPerpPositionValueExcludingMarket(
|
|
1429
|
+
targetMarketIndex,
|
|
1430
|
+
undefined,
|
|
1431
|
+
undefined,
|
|
1432
|
+
includeOpenOrders
|
|
1433
|
+
);
|
|
1375
1434
|
|
|
1376
|
-
const
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1435
|
+
const totalAssetValue = this.getTotalAssetValue();
|
|
1436
|
+
|
|
1437
|
+
const totalPerpPositionValue = currentPerpPositionAfterTrade
|
|
1438
|
+
.add(totalPositionAfterTradeExcludingTargetMarket)
|
|
1439
|
+
.abs();
|
|
1440
|
+
|
|
1441
|
+
const totalLiabilitiesAfterTrade = totalPerpPositionValue.add(
|
|
1442
|
+
this.getSpotMarketLiabilityValue(undefined, undefined, undefined, false)
|
|
1443
|
+
);
|
|
1444
|
+
|
|
1445
|
+
if (totalAssetValue.eq(ZERO) && totalLiabilitiesAfterTrade.eq(ZERO)) {
|
|
1446
|
+
return ZERO;
|
|
1386
1447
|
}
|
|
1448
|
+
|
|
1449
|
+
const newLeverage = totalLiabilitiesAfterTrade
|
|
1450
|
+
.mul(TEN_THOUSAND)
|
|
1451
|
+
.div(totalAssetValue);
|
|
1452
|
+
|
|
1453
|
+
return newLeverage;
|
|
1387
1454
|
}
|
|
1388
1455
|
|
|
1389
1456
|
/**
|
|
@@ -1399,17 +1466,96 @@ export class ClearingHouseUser {
|
|
|
1399
1466
|
.div(new BN(feeTier.feeDenominator));
|
|
1400
1467
|
}
|
|
1401
1468
|
|
|
1469
|
+
/**
|
|
1470
|
+
* Calculates a user's max withdrawal amounts for a spot market. If reduceOnly is true,
|
|
1471
|
+
* it will return the max withdrawal amount without opening a liability for the user
|
|
1472
|
+
* @param marketIndex
|
|
1473
|
+
* @returns withdrawalLimit : Precision is the token precision for the chosen SpotMarket
|
|
1474
|
+
*/
|
|
1475
|
+
public getWithdrawalLimit(marketIndex: number, reduceOnly?: boolean): BN {
|
|
1476
|
+
const nowTs = new BN(Math.floor(Date.now() / 1000));
|
|
1477
|
+
const spotMarket = this.clearingHouse.getSpotMarketAccount(marketIndex);
|
|
1478
|
+
|
|
1479
|
+
const { borrowLimit, withdrawLimit } = calculateWithdrawLimit(
|
|
1480
|
+
spotMarket,
|
|
1481
|
+
nowTs
|
|
1482
|
+
);
|
|
1483
|
+
|
|
1484
|
+
const freeCollateral = this.getFreeCollateral();
|
|
1485
|
+
const oracleData = this.getOracleDataForSpotMarket(marketIndex);
|
|
1486
|
+
const precisionIncrease = TEN.pow(new BN(spotMarket.decimals - 6));
|
|
1487
|
+
|
|
1488
|
+
const amountWithdrawable = freeCollateral
|
|
1489
|
+
.mul(MARGIN_PRECISION)
|
|
1490
|
+
.div(spotMarket.initialAssetWeight)
|
|
1491
|
+
.mul(PRICE_PRECISION)
|
|
1492
|
+
.div(oracleData.price)
|
|
1493
|
+
.mul(precisionIncrease);
|
|
1494
|
+
|
|
1495
|
+
const userSpotPosition = this.getUserAccount().spotPositions.find(
|
|
1496
|
+
(spotPosition) =>
|
|
1497
|
+
isVariant(spotPosition.balanceType, 'deposit') &&
|
|
1498
|
+
spotPosition.marketIndex == marketIndex
|
|
1499
|
+
);
|
|
1500
|
+
|
|
1501
|
+
const userSpotBalance = userSpotPosition
|
|
1502
|
+
? getTokenAmount(
|
|
1503
|
+
userSpotPosition.scaledBalance,
|
|
1504
|
+
this.clearingHouse.getSpotMarketAccount(marketIndex),
|
|
1505
|
+
SpotBalanceType.DEPOSIT
|
|
1506
|
+
)
|
|
1507
|
+
: ZERO;
|
|
1508
|
+
|
|
1509
|
+
const maxWithdrawValue = BN.min(
|
|
1510
|
+
BN.min(amountWithdrawable, userSpotBalance),
|
|
1511
|
+
withdrawLimit.abs()
|
|
1512
|
+
);
|
|
1513
|
+
|
|
1514
|
+
if (reduceOnly) {
|
|
1515
|
+
return BN.max(maxWithdrawValue, ZERO);
|
|
1516
|
+
} else {
|
|
1517
|
+
const weightedAssetValue = this.getSpotMarketAssetValue(
|
|
1518
|
+
marketIndex,
|
|
1519
|
+
'Initial',
|
|
1520
|
+
false
|
|
1521
|
+
);
|
|
1522
|
+
|
|
1523
|
+
const freeCollatAfterWithdraw = userSpotBalance.gt(ZERO)
|
|
1524
|
+
? freeCollateral.sub(weightedAssetValue)
|
|
1525
|
+
: freeCollateral;
|
|
1526
|
+
|
|
1527
|
+
const maxLiabilityAllowed = freeCollatAfterWithdraw
|
|
1528
|
+
.mul(MARGIN_PRECISION)
|
|
1529
|
+
.div(spotMarket.initialLiabilityWeight)
|
|
1530
|
+
.mul(PRICE_PRECISION)
|
|
1531
|
+
.div(oracleData.price)
|
|
1532
|
+
.mul(precisionIncrease);
|
|
1533
|
+
|
|
1534
|
+
const maxBorrowValue = BN.min(
|
|
1535
|
+
maxWithdrawValue.add(maxLiabilityAllowed),
|
|
1536
|
+
borrowLimit.abs()
|
|
1537
|
+
);
|
|
1538
|
+
|
|
1539
|
+
return BN.max(maxBorrowValue, ZERO);
|
|
1540
|
+
}
|
|
1541
|
+
}
|
|
1542
|
+
|
|
1402
1543
|
/**
|
|
1403
1544
|
* Get the total position value, excluding any position coming from the given target market
|
|
1404
1545
|
* @param marketToIgnore
|
|
1405
1546
|
* @returns positionValue : Precision QUOTE_PRECISION
|
|
1406
1547
|
*/
|
|
1407
|
-
private getTotalPerpPositionValueExcludingMarket(
|
|
1548
|
+
private getTotalPerpPositionValueExcludingMarket(
|
|
1549
|
+
marketToIgnore: number,
|
|
1550
|
+
marginCategory?: MarginCategory,
|
|
1551
|
+
liquidationBuffer?: BN,
|
|
1552
|
+
includeOpenOrders?: boolean
|
|
1553
|
+
): BN {
|
|
1408
1554
|
const currentPerpPosition =
|
|
1409
1555
|
this.getUserPosition(marketToIgnore) ||
|
|
1410
1556
|
this.getEmptyPosition(marketToIgnore);
|
|
1411
1557
|
|
|
1412
|
-
const oracleData = this.
|
|
1558
|
+
const oracleData = this.getOracleDataForPerpMarket(marketToIgnore);
|
|
1413
1559
|
|
|
1414
1560
|
let currentPerpPositionValueUSDC = ZERO;
|
|
1415
1561
|
if (currentPerpPosition) {
|
|
@@ -1419,10 +1565,14 @@ export class ClearingHouseUser {
|
|
|
1419
1565
|
);
|
|
1420
1566
|
}
|
|
1421
1567
|
|
|
1422
|
-
return this.getTotalPerpPositionValue(
|
|
1568
|
+
return this.getTotalPerpPositionValue(
|
|
1569
|
+
marginCategory,
|
|
1570
|
+
liquidationBuffer,
|
|
1571
|
+
includeOpenOrders
|
|
1572
|
+
).sub(currentPerpPositionValueUSDC);
|
|
1423
1573
|
}
|
|
1424
1574
|
|
|
1425
|
-
private
|
|
1575
|
+
private getOracleDataForPerpMarket(marketIndex: number): OraclePriceData {
|
|
1426
1576
|
const oracleKey =
|
|
1427
1577
|
this.clearingHouse.getPerpMarketAccount(marketIndex).amm.oracle;
|
|
1428
1578
|
const oracleData =
|
package/src/config.ts
CHANGED
|
@@ -17,6 +17,8 @@ type DriftConfig = {
|
|
|
17
17
|
PYTH_ORACLE_MAPPING_ADDRESS: string;
|
|
18
18
|
CLEARING_HOUSE_PROGRAM_ID: string;
|
|
19
19
|
USDC_MINT_ADDRESS: string;
|
|
20
|
+
SERUM_V3: string;
|
|
21
|
+
V2_ALPHA_TICKET_MINT_ADDRESS: string;
|
|
20
22
|
PERP_MARKETS: PerpMarketConfig[];
|
|
21
23
|
SPOT_MARKETS: SpotMarketConfig[];
|
|
22
24
|
};
|
|
@@ -27,8 +29,11 @@ export const configs: { [key in DriftEnv]: DriftConfig } = {
|
|
|
27
29
|
devnet: {
|
|
28
30
|
ENV: 'devnet',
|
|
29
31
|
PYTH_ORACLE_MAPPING_ADDRESS: 'BmA9Z6FjioHJPpjT39QazZyhDRUdZy2ezwx4GiDdE2u2',
|
|
30
|
-
CLEARING_HOUSE_PROGRAM_ID: '
|
|
32
|
+
CLEARING_HOUSE_PROGRAM_ID: 'FPVkWvcQgc4aCS8TrKo5c8GqTbKMauvzpADdqzRT2WbT',
|
|
31
33
|
USDC_MINT_ADDRESS: '8zGuJQqwhZafTah7Uc7Z4tXRnguqkn5KLFAP8oV6PHe2',
|
|
34
|
+
SERUM_V3: 'DESVgJVGajEgKGXhb6XmqDHGz3VjdgP7rEVESBgxmroY',
|
|
35
|
+
V2_ALPHA_TICKET_MINT_ADDRESS:
|
|
36
|
+
'DeEiGWfCMP9psnLGkxGrBBMEAW5Jv8bBGMN8DCtFRCyB',
|
|
32
37
|
PERP_MARKETS: DevnetPerpMarkets,
|
|
33
38
|
SPOT_MARKETS: DevnetSpotMarkets,
|
|
34
39
|
},
|
|
@@ -37,6 +42,8 @@ export const configs: { [key in DriftEnv]: DriftConfig } = {
|
|
|
37
42
|
PYTH_ORACLE_MAPPING_ADDRESS: 'AHtgzX45WTKfkPG53L6WYhGEXwQkN1BVknET3sVsLL8J',
|
|
38
43
|
CLEARING_HOUSE_PROGRAM_ID: 'dammHkt7jmytvbS3nHTxQNEcP59aE57nxwV21YdqEDN',
|
|
39
44
|
USDC_MINT_ADDRESS: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
|
|
45
|
+
SERUM_V3: '9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin',
|
|
46
|
+
V2_ALPHA_TICKET_MINT_ADDRESS: '',
|
|
40
47
|
PERP_MARKETS: MainnetMarkets,
|
|
41
48
|
SPOT_MARKETS: MainnetSpotMarkets,
|
|
42
49
|
},
|
|
@@ -37,7 +37,11 @@ export const SPOT_MARKET_CUMULATIVE_INTEREST_PRECISION = new BN(10).pow(
|
|
|
37
37
|
SPOT_MARKET_CUMULATIVE_INTEREST_PRECISION_EXP
|
|
38
38
|
);
|
|
39
39
|
|
|
40
|
-
export const
|
|
40
|
+
export const SPOT_MARKET_UTILIZATION_PRECISION_EXP = new BN(6);
|
|
41
|
+
export const SPOT_MARKET_UTILIZATION_PRECISION = new BN(10).pow(
|
|
42
|
+
SPOT_MARKET_UTILIZATION_PRECISION_EXP
|
|
43
|
+
);
|
|
44
|
+
|
|
41
45
|
export const SPOT_MARKET_WEIGHT_PRECISION = new BN(10000);
|
|
42
46
|
export const SPOT_MARKET_BALANCE_PRECISION_EXP = new BN(9);
|
|
43
47
|
export const SPOT_MARKET_BALANCE_PRECISION = new BN(10).pow(
|