@drift-labs/sdk 0.2.0-master.38 → 0.2.0-master.39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -14
- package/lib/accounts/bulkUserStatsSubscription.d.ts +2 -2
- package/lib/accounts/bulkUserSubscription.d.ts +2 -2
- package/lib/accounts/{pollingClearingHouseAccountSubscriber.d.ts → pollingDriftClientAccountSubscriber.d.ts} +3 -8
- package/lib/accounts/{pollingClearingHouseAccountSubscriber.js → pollingDriftClientAccountSubscriber.js} +6 -13
- package/lib/accounts/{pollingOracleSubscriber.d.ts → pollingOracleAccountSubscriber.d.ts} +2 -2
- package/lib/accounts/{pollingOracleSubscriber.js → pollingOracleAccountSubscriber.js} +3 -3
- package/lib/accounts/types.d.ts +4 -4
- package/lib/accounts/{webSocketClearingHouseAccountSubscriber.d.ts → webSocketDriftClientAccountSubscriber.d.ts} +3 -3
- package/lib/accounts/{webSocketClearingHouseAccountSubscriber.js → webSocketDriftClientAccountSubscriber.js} +4 -4
- package/lib/addresses/pda.d.ts +3 -3
- package/lib/addresses/pda.js +10 -10
- package/lib/{admin.d.ts → adminClient.d.ts} +9 -4
- package/lib/{admin.js → adminClient.js} +62 -15
- package/lib/config.js +1 -1
- package/lib/constants/numericConstants.d.ts +3 -0
- package/lib/constants/numericConstants.js +5 -2
- package/lib/dlob/DLOB.d.ts +2 -2
- package/lib/dlob/DLOB.js +4 -4
- package/lib/{clearingHouse.d.ts → driftClient.d.ts} +20 -20
- package/lib/{clearingHouse.js → driftClient.js} +28 -28
- package/lib/{clearingHouseConfig.d.ts → driftClientConfig.d.ts} +3 -3
- package/lib/{clearingHouseConfig.js → driftClientConfig.js} +0 -0
- package/lib/examples/makeTradeExample.js +13 -13
- package/lib/idl/{clearing_house.json → drift.json} +603 -119
- package/lib/index.d.ts +10 -10
- package/lib/index.js +10 -10
- package/lib/math/orders.d.ts +4 -4
- package/lib/math/orders.js +3 -3
- package/lib/serum/serumFulfillmentConfigMap.d.ts +3 -3
- package/lib/serum/serumFulfillmentConfigMap.js +3 -3
- package/lib/types.d.ts +38 -2
- package/lib/types.js +2 -1
- package/lib/{clearingHouseUser.d.ts → user.d.ts} +16 -10
- package/lib/{clearingHouseUser.js → user.js} +53 -45
- package/lib/userConfig.d.ts +14 -0
- package/lib/{clearingHouseUserConfig.js → userConfig.js} +0 -0
- package/lib/userMap/userMap.d.ts +17 -17
- package/lib/userMap/userMap.js +15 -15
- package/lib/userMap/userStatsMap.d.ts +7 -7
- package/lib/userMap/userStatsMap.js +10 -10
- package/lib/{clearingHouseUserStats.d.ts → userStats.d.ts} +5 -5
- package/lib/{clearingHouseUserStats.js → userStats.js} +8 -8
- package/lib/userStatsConfig.d.ts +14 -0
- package/lib/{clearingHouseUserStatsConfig.js → userStatsConfig.js} +0 -0
- package/package.json +1 -1
- package/src/accounts/bulkUserStatsSubscription.ts +2 -2
- package/src/accounts/bulkUserSubscription.ts +2 -2
- package/src/accounts/{pollingClearingHouseAccountSubscriber.ts → pollingDriftClientAccountSubscriber.ts} +11 -25
- package/src/accounts/{pollingOracleSubscriber.ts → pollingOracleAccountSubscriber.ts} +2 -2
- package/src/accounts/types.ts +4 -4
- package/src/accounts/{webSocketClearingHouseAccountSubscriber.ts → webSocketDriftClientAccountSubscriber.ts} +7 -7
- package/src/addresses/pda.ts +6 -8
- package/src/{admin.ts → adminClient.ts} +125 -18
- package/src/config.ts +1 -1
- package/src/constants/numericConstants.ts +4 -0
- package/src/dlob/DLOB.ts +5 -5
- package/src/{clearingHouse.ts → driftClient.ts} +45 -47
- package/src/{clearingHouseConfig.ts → driftClientConfig.ts} +3 -3
- package/src/examples/makeTradeExample.ts +15 -17
- package/src/idl/{clearing_house.json → drift.json} +603 -119
- package/src/index.ts +10 -10
- package/src/math/orders.ts +7 -13
- package/src/serum/serumFulfillmentConfigMap.ts +5 -5
- package/src/types.ts +41 -2
- package/src/{clearingHouseUser.ts → user.ts} +59 -53
- package/src/{clearingHouseUserConfig.ts → userConfig.ts} +5 -5
- package/src/userMap/userMap.ts +29 -29
- package/src/userMap/userStatsMap.ts +21 -23
- package/src/{clearingHouseUserStats.ts → userStats.ts} +10 -10
- package/src/userStatsConfig.ts +18 -0
- package/tests/dlob/helpers.ts +55 -13
- package/lib/clearingHouseUserConfig.d.ts +0 -14
- package/lib/clearingHouseUserStatsConfig.d.ts +0 -14
- package/src/clearingHouseUserStatsConfig.ts +0 -18
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.User = void 0;
|
|
4
4
|
const types_1 = require("./types");
|
|
5
5
|
const position_1 = require("./math/position");
|
|
6
6
|
const numericConstants_1 = require("./constants/numericConstants");
|
|
@@ -11,17 +11,17 @@ const margin_1 = require("./math/margin");
|
|
|
11
11
|
const pollingUserAccountSubscriber_1 = require("./accounts/pollingUserAccountSubscriber");
|
|
12
12
|
const webSocketUserAccountSubscriber_1 = require("./accounts/webSocketUserAccountSubscriber");
|
|
13
13
|
const spotPosition_1 = require("./math/spotPosition");
|
|
14
|
-
class
|
|
14
|
+
class User {
|
|
15
15
|
constructor(config) {
|
|
16
16
|
var _a;
|
|
17
17
|
this._isSubscribed = false;
|
|
18
|
-
this.
|
|
18
|
+
this.driftClient = config.driftClient;
|
|
19
19
|
this.userAccountPublicKey = config.userAccountPublicKey;
|
|
20
20
|
if (((_a = config.accountSubscription) === null || _a === void 0 ? void 0 : _a.type) === 'polling') {
|
|
21
|
-
this.accountSubscriber = new pollingUserAccountSubscriber_1.PollingUserAccountSubscriber(config.
|
|
21
|
+
this.accountSubscriber = new pollingUserAccountSubscriber_1.PollingUserAccountSubscriber(config.driftClient.program, config.userAccountPublicKey, config.accountSubscription.accountLoader);
|
|
22
22
|
}
|
|
23
23
|
else {
|
|
24
|
-
this.accountSubscriber = new webSocketUserAccountSubscriber_1.WebSocketUserAccountSubscriber(config.
|
|
24
|
+
this.accountSubscriber = new webSocketUserAccountSubscriber_1.WebSocketUserAccountSubscriber(config.driftClient.program, config.userAccountPublicKey);
|
|
25
25
|
}
|
|
26
26
|
this.eventEmitter = this.accountSubscriber.eventEmitter;
|
|
27
27
|
}
|
|
@@ -32,7 +32,7 @@ class ClearingHouseUser {
|
|
|
32
32
|
this._isSubscribed = val;
|
|
33
33
|
}
|
|
34
34
|
/**
|
|
35
|
-
* Subscribe to
|
|
35
|
+
* Subscribe to User state accounts
|
|
36
36
|
* @returns SusbcriptionSuccess result
|
|
37
37
|
*/
|
|
38
38
|
async subscribe() {
|
|
@@ -56,13 +56,21 @@ class ClearingHouseUser {
|
|
|
56
56
|
return this.accountSubscriber.getUserAccountAndSlot();
|
|
57
57
|
}
|
|
58
58
|
/**
|
|
59
|
-
* Gets the user's current position for a given market. If the user has no position returns undefined
|
|
59
|
+
* Gets the user's current position for a given perp market. If the user has no position returns undefined
|
|
60
60
|
* @param marketIndex
|
|
61
|
-
* @returns
|
|
61
|
+
* @returns userPerpPosition
|
|
62
62
|
*/
|
|
63
|
-
|
|
63
|
+
getPerpPosition(marketIndex) {
|
|
64
64
|
return this.getUserAccount().perpPositions.find((position) => position.marketIndex === marketIndex);
|
|
65
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* Gets the user's current position for a given spot market. If the user has no position returns undefined
|
|
68
|
+
* @param marketIndex
|
|
69
|
+
* @returns userSpotPosition
|
|
70
|
+
*/
|
|
71
|
+
getSpotPosition(marketIndex) {
|
|
72
|
+
return this.getUserAccount().spotPositions.find((position) => position.marketIndex === marketIndex);
|
|
73
|
+
}
|
|
66
74
|
getEmptyPosition(marketIndex) {
|
|
67
75
|
return {
|
|
68
76
|
baseAssetAmount: numericConstants_1.ZERO,
|
|
@@ -103,7 +111,7 @@ class ClearingHouseUser {
|
|
|
103
111
|
return this.userAccountPublicKey;
|
|
104
112
|
}
|
|
105
113
|
async exists() {
|
|
106
|
-
const userAccountRPCResponse = await this.
|
|
114
|
+
const userAccountRPCResponse = await this.driftClient.connection.getParsedAccountInfo(this.userAccountPublicKey);
|
|
107
115
|
return userAccountRPCResponse.value !== null;
|
|
108
116
|
}
|
|
109
117
|
/**
|
|
@@ -112,7 +120,7 @@ class ClearingHouseUser {
|
|
|
112
120
|
* @returns : open asks
|
|
113
121
|
*/
|
|
114
122
|
getPerpBidAsks(marketIndex) {
|
|
115
|
-
const position = this.
|
|
123
|
+
const position = this.getPerpPosition(marketIndex);
|
|
116
124
|
const [lpOpenBids, lpOpenAsks] = this.getLPBidAsks(marketIndex);
|
|
117
125
|
const totalOpenBids = lpOpenBids.add(position.openBids);
|
|
118
126
|
const totalOpenAsks = lpOpenAsks.add(position.openAsks);
|
|
@@ -124,11 +132,11 @@ class ClearingHouseUser {
|
|
|
124
132
|
* @returns : lp open asks
|
|
125
133
|
*/
|
|
126
134
|
getLPBidAsks(marketIndex) {
|
|
127
|
-
const position = this.
|
|
135
|
+
const position = this.getPerpPosition(marketIndex);
|
|
128
136
|
if (position === undefined || position.lpShares.eq(numericConstants_1.ZERO)) {
|
|
129
137
|
return [numericConstants_1.ZERO, numericConstants_1.ZERO];
|
|
130
138
|
}
|
|
131
|
-
const market = this.
|
|
139
|
+
const market = this.driftClient.getPerpMarketAccount(marketIndex);
|
|
132
140
|
const [marketOpenBids, marketOpenAsks] = (0, amm_1.calculateMarketOpenBidAsk)(market.amm.baseAssetReserve, market.amm.minBaseAssetReserve, market.amm.maxBaseAssetReserve);
|
|
133
141
|
const lpOpenBids = marketOpenBids
|
|
134
142
|
.mul(position.lpShares)
|
|
@@ -145,12 +153,12 @@ class ClearingHouseUser {
|
|
|
145
153
|
* @returns : pnl from settle
|
|
146
154
|
*/
|
|
147
155
|
getSettledLPPosition(marketIndex) {
|
|
148
|
-
const _position = this.
|
|
156
|
+
const _position = this.getPerpPosition(marketIndex);
|
|
149
157
|
const position = this.getClonedPosition(_position);
|
|
150
158
|
if (position.lpShares.eq(numericConstants_1.ZERO)) {
|
|
151
159
|
return [position, numericConstants_1.ZERO, numericConstants_1.ZERO];
|
|
152
160
|
}
|
|
153
|
-
const market = this.
|
|
161
|
+
const market = this.driftClient.getPerpMarketAccount(position.marketIndex);
|
|
154
162
|
const nShares = position.lpShares;
|
|
155
163
|
const deltaBaa = market.amm.baseAssetAmountPerLp
|
|
156
164
|
.sub(position.lastNetBaseAssetAmountPerLp)
|
|
@@ -267,11 +275,11 @@ class ClearingHouseUser {
|
|
|
267
275
|
* @returns : Precision QUOTE_PRECISION
|
|
268
276
|
*/
|
|
269
277
|
getUnrealizedPNL(withFunding, marketIndex, withWeightMarginCategory) {
|
|
270
|
-
const quoteSpotMarket = this.
|
|
278
|
+
const quoteSpotMarket = this.driftClient.getQuoteSpotMarketAccount();
|
|
271
279
|
return this.getUserAccount()
|
|
272
280
|
.perpPositions.filter((pos) => marketIndex ? pos.marketIndex === marketIndex : true)
|
|
273
281
|
.reduce((unrealizedPnl, perpPosition) => {
|
|
274
|
-
const market = this.
|
|
282
|
+
const market = this.driftClient.getPerpMarketAccount(perpPosition.marketIndex);
|
|
275
283
|
const oraclePriceData = this.getOracleDataForPerpMarket(market.marketIndex);
|
|
276
284
|
let positionUnrealizedPnl = (0, _1.calculatePositionPNL)(market, perpPosition, withFunding, oraclePriceData);
|
|
277
285
|
if (withWeightMarginCategory !== undefined) {
|
|
@@ -292,7 +300,7 @@ class ClearingHouseUser {
|
|
|
292
300
|
return this.getUserAccount()
|
|
293
301
|
.perpPositions.filter((pos) => marketIndex ? pos.marketIndex === marketIndex : true)
|
|
294
302
|
.reduce((pnl, perpPosition) => {
|
|
295
|
-
const market = this.
|
|
303
|
+
const market = this.driftClient.getPerpMarketAccount(perpPosition.marketIndex);
|
|
296
304
|
return pnl.add((0, _1.calculatePositionFundingPNL)(market, perpPosition));
|
|
297
305
|
}, numericConstants_1.ZERO);
|
|
298
306
|
}
|
|
@@ -303,7 +311,7 @@ class ClearingHouseUser {
|
|
|
303
311
|
spotPosition.marketIndex !== marketIndex)) {
|
|
304
312
|
return totalLiabilityValue;
|
|
305
313
|
}
|
|
306
|
-
const spotMarketAccount = this.
|
|
314
|
+
const spotMarketAccount = this.driftClient.getSpotMarketAccount(spotPosition.marketIndex);
|
|
307
315
|
if (spotPosition.marketIndex === numericConstants_1.QUOTE_SPOT_MARKET_INDEX) {
|
|
308
316
|
if ((0, types_1.isVariant)(spotPosition.balanceType, 'borrow')) {
|
|
309
317
|
const tokenAmount = (0, spotBalance_1.getTokenAmount)(spotPosition.scaledBalance, spotMarketAccount, spotPosition.balanceType);
|
|
@@ -377,7 +385,7 @@ class ClearingHouseUser {
|
|
|
377
385
|
return totalAssetValue;
|
|
378
386
|
}
|
|
379
387
|
// Todo this needs to account for whether it's based on initial or maintenance requirements
|
|
380
|
-
const spotMarketAccount = this.
|
|
388
|
+
const spotMarketAccount = this.driftClient.getSpotMarketAccount(spotPosition.marketIndex);
|
|
381
389
|
if (spotPosition.marketIndex === numericConstants_1.QUOTE_SPOT_MARKET_INDEX) {
|
|
382
390
|
if ((0, types_1.isVariant)(spotPosition.balanceType, 'deposit')) {
|
|
383
391
|
const tokenAmount = (0, spotBalance_1.getTokenAmount)(spotPosition.scaledBalance, spotMarketAccount, spotPosition.balanceType);
|
|
@@ -434,7 +442,7 @@ class ClearingHouseUser {
|
|
|
434
442
|
*/
|
|
435
443
|
getTotalPerpPositionValue(marginCategory, liquidationBuffer, includeOpenOrders) {
|
|
436
444
|
return this.getUserAccount().perpPositions.reduce((totalPerpValue, perpPosition) => {
|
|
437
|
-
const market = this.
|
|
445
|
+
const market = this.driftClient.getPerpMarketAccount(perpPosition.marketIndex);
|
|
438
446
|
if (perpPosition.lpShares.gt(numericConstants_1.ZERO)) {
|
|
439
447
|
// is an lp
|
|
440
448
|
// clone so we dont mutate the position
|
|
@@ -482,8 +490,8 @@ class ClearingHouseUser {
|
|
|
482
490
|
* @returns : Precision QUOTE_PRECISION
|
|
483
491
|
*/
|
|
484
492
|
getPerpPositionValue(marketIndex, oraclePriceData) {
|
|
485
|
-
const userPosition = this.
|
|
486
|
-
const market = this.
|
|
493
|
+
const userPosition = this.getPerpPosition(marketIndex) || this.getEmptyPosition(marketIndex);
|
|
494
|
+
const market = this.driftClient.getPerpMarketAccount(userPosition.marketIndex);
|
|
487
495
|
return (0, margin_1.calculateBaseAssetValueWithOracle)(market, userPosition, oraclePriceData);
|
|
488
496
|
}
|
|
489
497
|
getPositionSide(currentPosition) {
|
|
@@ -502,7 +510,7 @@ class ClearingHouseUser {
|
|
|
502
510
|
* @returns : Precision PRICE_PRECISION
|
|
503
511
|
*/
|
|
504
512
|
getPositionEstimatedExitPriceAndPnl(position, amountToClose, useAMMClose = false) {
|
|
505
|
-
const market = this.
|
|
513
|
+
const market = this.driftClient.getPerpMarketAccount(position.marketIndex);
|
|
506
514
|
const entryPrice = (0, position_1.calculateEntryPrice)(position);
|
|
507
515
|
const oraclePriceData = this.getOracleDataForPerpMarket(position.marketIndex);
|
|
508
516
|
if (amountToClose) {
|
|
@@ -561,7 +569,7 @@ class ClearingHouseUser {
|
|
|
561
569
|
* @returns : Precision TEN_THOUSAND
|
|
562
570
|
*/
|
|
563
571
|
getMaxLeverage(marketIndex, category = 'Initial') {
|
|
564
|
-
const market = this.
|
|
572
|
+
const market = this.driftClient.getPerpMarketAccount(marketIndex);
|
|
565
573
|
const totalAssetValue = this.getTotalAssetValue();
|
|
566
574
|
if (totalAssetValue.eq(numericConstants_1.ZERO)) {
|
|
567
575
|
return numericConstants_1.ZERO;
|
|
@@ -598,7 +606,7 @@ class ClearingHouseUser {
|
|
|
598
606
|
// if user being liq'd, can continue to be liq'd until total collateral above the margin requirement plus buffer
|
|
599
607
|
let liquidationBuffer = undefined;
|
|
600
608
|
if (this.getUserAccount().isBeingLiquidated) {
|
|
601
|
-
liquidationBuffer = new _1.BN(this.
|
|
609
|
+
liquidationBuffer = new _1.BN(this.driftClient.getStateAccount().liquidationMarginBufferRatio);
|
|
602
610
|
}
|
|
603
611
|
const maintenanceRequirement = this.getMaintenanceMarginRequirement(liquidationBuffer);
|
|
604
612
|
return totalCollateral.lt(maintenanceRequirement);
|
|
@@ -612,7 +620,7 @@ class ClearingHouseUser {
|
|
|
612
620
|
if (userPosition.baseAssetAmount.eq(numericConstants_1.ZERO)) {
|
|
613
621
|
continue;
|
|
614
622
|
}
|
|
615
|
-
const market = this.
|
|
623
|
+
const market = this.driftClient.getPerpMarketAccount(userPosition.marketIndex);
|
|
616
624
|
if (market.amm.cumulativeFundingRateLong.eq(userPosition.lastCumulativeFundingRate) ||
|
|
617
625
|
market.amm.cumulativeFundingRateShort.eq(userPosition.lastCumulativeFundingRate)) {
|
|
618
626
|
continue;
|
|
@@ -642,7 +650,7 @@ class ClearingHouseUser {
|
|
|
642
650
|
const totalCollateral = this.getTotalCollateral();
|
|
643
651
|
// calculate the total position value ignoring any value from the target market of the trade
|
|
644
652
|
const totalPositionValueExcludingTargetMarket = this.getTotalPerpPositionValueExcludingMarket(perpPosition.marketIndex);
|
|
645
|
-
const currentPerpPosition = this.
|
|
653
|
+
const currentPerpPosition = this.getPerpPosition(perpPosition.marketIndex) ||
|
|
646
654
|
this.getEmptyPosition(perpPosition.marketIndex);
|
|
647
655
|
const currentPerpPositionBaseSize = currentPerpPosition.baseAssetAmount;
|
|
648
656
|
const proposedBaseAssetAmount = currentPerpPositionBaseSize.add(positionBaseSizeChange);
|
|
@@ -665,13 +673,13 @@ class ClearingHouseUser {
|
|
|
665
673
|
};
|
|
666
674
|
if (proposedBaseAssetAmount.eq(numericConstants_1.ZERO))
|
|
667
675
|
return new _1.BN(-1);
|
|
668
|
-
const market = this.
|
|
676
|
+
const market = this.driftClient.getPerpMarketAccount(proposedPerpPosition.marketIndex);
|
|
669
677
|
const proposedPerpPositionValue = (0, margin_1.calculateBaseAssetValueWithOracle)(market, proposedPerpPosition, this.getOracleDataForPerpMarket(market.marketIndex));
|
|
670
678
|
// total position value after trade
|
|
671
679
|
const totalPositionValueAfterTrade = totalPositionValueExcludingTargetMarket.add(proposedPerpPositionValue);
|
|
672
680
|
const marginRequirementExcludingTargetMarket = this.getUserAccount().perpPositions.reduce((totalMarginRequirement, position) => {
|
|
673
681
|
if (position.marketIndex !== perpPosition.marketIndex) {
|
|
674
|
-
const market = this.
|
|
682
|
+
const market = this.driftClient.getPerpMarketAccount(position.marketIndex);
|
|
675
683
|
const positionValue = (0, margin_1.calculateBaseAssetValueWithOracle)(market, position, this.getOracleDataForPerpMarket(market.marketIndex));
|
|
676
684
|
const marketMarginRequirement = positionValue
|
|
677
685
|
.mul(new _1.BN((0, _1.calculateMarketMarginRatio)(market, position.baseAssetAmount.abs(), 'Maintenance')))
|
|
@@ -710,13 +718,13 @@ class ClearingHouseUser {
|
|
|
710
718
|
}
|
|
711
719
|
let markPriceAfterTrade;
|
|
712
720
|
if (positionBaseSizeChange.eq(numericConstants_1.ZERO)) {
|
|
713
|
-
markPriceAfterTrade = (0, _1.calculateReservePrice)(this.
|
|
721
|
+
markPriceAfterTrade = (0, _1.calculateReservePrice)(this.driftClient.getPerpMarketAccount(perpPosition.marketIndex), this.getOracleDataForPerpMarket(perpPosition.marketIndex));
|
|
714
722
|
}
|
|
715
723
|
else {
|
|
716
724
|
const direction = positionBaseSizeChange.gt(numericConstants_1.ZERO)
|
|
717
725
|
? _1.PositionDirection.LONG
|
|
718
726
|
: _1.PositionDirection.SHORT;
|
|
719
|
-
markPriceAfterTrade = (0, _1.calculateTradeSlippage)(direction, positionBaseSizeChange.abs(), this.
|
|
727
|
+
markPriceAfterTrade = (0, _1.calculateTradeSlippage)(direction, positionBaseSizeChange.abs(), this.driftClient.getPerpMarketAccount(perpPosition.marketIndex), 'base', this.getOracleDataForPerpMarket(perpPosition.marketIndex))[3]; // newPrice after swap
|
|
720
728
|
}
|
|
721
729
|
if (priceDelta.gt(markPriceAfterTrade)) {
|
|
722
730
|
return new _1.BN(-1);
|
|
@@ -730,7 +738,7 @@ class ClearingHouseUser {
|
|
|
730
738
|
* @returns : Precision PRICE_PRECISION
|
|
731
739
|
*/
|
|
732
740
|
liquidationPriceAfterClose(positionMarketIndex, closeQuoteAmount) {
|
|
733
|
-
const currentPosition = this.
|
|
741
|
+
const currentPosition = this.getPerpPosition(positionMarketIndex) ||
|
|
734
742
|
this.getEmptyPosition(positionMarketIndex);
|
|
735
743
|
const closeBaseAmount = currentPosition.baseAssetAmount
|
|
736
744
|
.mul(closeQuoteAmount)
|
|
@@ -765,7 +773,7 @@ class ClearingHouseUser {
|
|
|
765
773
|
* @returns tradeSizeAllowed : Precision QUOTE_PRECISION
|
|
766
774
|
*/
|
|
767
775
|
getMaxTradeSizeUSDC(targetMarketIndex, tradeSide) {
|
|
768
|
-
const currentPosition = this.
|
|
776
|
+
const currentPosition = this.getPerpPosition(targetMarketIndex) ||
|
|
769
777
|
this.getEmptyPosition(targetMarketIndex);
|
|
770
778
|
const targetSide = (0, types_1.isVariant)(tradeSide, 'short') ? 'short' : 'long';
|
|
771
779
|
const currentPositionSide = (currentPosition === null || currentPosition === void 0 ? void 0 : currentPosition.baseAssetAmount.isNeg())
|
|
@@ -793,7 +801,7 @@ class ClearingHouseUser {
|
|
|
793
801
|
else {
|
|
794
802
|
// current leverage is greater than max leverage - can only reduce position size
|
|
795
803
|
if (!targetingSameSide) {
|
|
796
|
-
const market = this.
|
|
804
|
+
const market = this.driftClient.getPerpMarketAccount(targetMarketIndex);
|
|
797
805
|
const perpPositionValue = this.getPerpPositionValue(targetMarketIndex, oracleData);
|
|
798
806
|
const totalCollateral = this.getTotalCollateral();
|
|
799
807
|
const marginRequirement = this.getInitialMarginRequirement();
|
|
@@ -830,7 +838,7 @@ class ClearingHouseUser {
|
|
|
830
838
|
* @returns leverageRatio : Precision TEN_THOUSAND
|
|
831
839
|
*/
|
|
832
840
|
accountLeverageRatioAfterTrade(targetMarketIndex, tradeQuoteAmount, tradeSide, includeOpenOrders = true) {
|
|
833
|
-
const currentPosition = this.
|
|
841
|
+
const currentPosition = this.getPerpPosition(targetMarketIndex) ||
|
|
834
842
|
this.getEmptyPosition(targetMarketIndex);
|
|
835
843
|
const oracleData = this.getOracleDataForPerpMarket(targetMarketIndex);
|
|
836
844
|
let currentPositionQuoteAmount = this.getPerpPositionValue(targetMarketIndex, oracleData);
|
|
@@ -864,7 +872,7 @@ class ClearingHouseUser {
|
|
|
864
872
|
* @returns feeForQuote : Precision QUOTE_PRECISION
|
|
865
873
|
*/
|
|
866
874
|
calculateFeeForQuoteAmount(quoteAmount) {
|
|
867
|
-
const feeTier = this.
|
|
875
|
+
const feeTier = this.driftClient.getStateAccount().perpFeeStructure.feeTiers[0];
|
|
868
876
|
return quoteAmount
|
|
869
877
|
.mul(new _1.BN(feeTier.feeNumerator))
|
|
870
878
|
.div(new _1.BN(feeTier.feeDenominator));
|
|
@@ -877,7 +885,7 @@ class ClearingHouseUser {
|
|
|
877
885
|
*/
|
|
878
886
|
getWithdrawalLimit(marketIndex, reduceOnly) {
|
|
879
887
|
const nowTs = new _1.BN(Math.floor(Date.now() / 1000));
|
|
880
|
-
const spotMarket = this.
|
|
888
|
+
const spotMarket = this.driftClient.getSpotMarketAccount(marketIndex);
|
|
881
889
|
const { borrowLimit, withdrawLimit } = (0, spotBalance_1.calculateWithdrawLimit)(spotMarket, nowTs);
|
|
882
890
|
const freeCollateral = this.getFreeCollateral();
|
|
883
891
|
const oracleData = this.getOracleDataForSpotMarket(marketIndex);
|
|
@@ -891,7 +899,7 @@ class ClearingHouseUser {
|
|
|
891
899
|
const userSpotPosition = this.getUserAccount().spotPositions.find((spotPosition) => (0, types_1.isVariant)(spotPosition.balanceType, 'deposit') &&
|
|
892
900
|
spotPosition.marketIndex == marketIndex);
|
|
893
901
|
const userSpotBalance = userSpotPosition
|
|
894
|
-
? (0, spotBalance_1.getTokenAmount)(userSpotPosition.scaledBalance, this.
|
|
902
|
+
? (0, spotBalance_1.getTokenAmount)(userSpotPosition.scaledBalance, this.driftClient.getSpotMarketAccount(marketIndex), _1.SpotBalanceType.DEPOSIT)
|
|
895
903
|
: numericConstants_1.ZERO;
|
|
896
904
|
const maxWithdrawValue = _1.BN.min(_1.BN.min(amountWithdrawable, userSpotBalance), withdrawLimit.abs());
|
|
897
905
|
if (reduceOnly) {
|
|
@@ -918,7 +926,7 @@ class ClearingHouseUser {
|
|
|
918
926
|
* @returns positionValue : Precision QUOTE_PRECISION
|
|
919
927
|
*/
|
|
920
928
|
getTotalPerpPositionValueExcludingMarket(marketToIgnore, marginCategory, liquidationBuffer, includeOpenOrders) {
|
|
921
|
-
const currentPerpPosition = this.
|
|
929
|
+
const currentPerpPosition = this.getPerpPosition(marketToIgnore) ||
|
|
922
930
|
this.getEmptyPosition(marketToIgnore);
|
|
923
931
|
const oracleData = this.getOracleDataForPerpMarket(marketToIgnore);
|
|
924
932
|
let currentPerpPositionValueUSDC = numericConstants_1.ZERO;
|
|
@@ -928,14 +936,14 @@ class ClearingHouseUser {
|
|
|
928
936
|
return this.getTotalPerpPositionValue(marginCategory, liquidationBuffer, includeOpenOrders).sub(currentPerpPositionValueUSDC);
|
|
929
937
|
}
|
|
930
938
|
getOracleDataForPerpMarket(marketIndex) {
|
|
931
|
-
const oracleKey = this.
|
|
932
|
-
const oracleData = this.
|
|
939
|
+
const oracleKey = this.driftClient.getPerpMarketAccount(marketIndex).amm.oracle;
|
|
940
|
+
const oracleData = this.driftClient.getOraclePriceDataAndSlot(oracleKey).data;
|
|
933
941
|
return oracleData;
|
|
934
942
|
}
|
|
935
943
|
getOracleDataForSpotMarket(marketIndex) {
|
|
936
|
-
const oracleKey = this.
|
|
937
|
-
const oracleData = this.
|
|
944
|
+
const oracleKey = this.driftClient.getSpotMarketAccount(marketIndex).oracle;
|
|
945
|
+
const oracleData = this.driftClient.getOraclePriceDataAndSlot(oracleKey).data;
|
|
938
946
|
return oracleData;
|
|
939
947
|
}
|
|
940
948
|
}
|
|
941
|
-
exports.
|
|
949
|
+
exports.User = User;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { DriftClient } from './driftClient';
|
|
2
|
+
import { PublicKey } from '@solana/web3.js';
|
|
3
|
+
import { BulkAccountLoader } from './accounts/bulkAccountLoader';
|
|
4
|
+
export declare type UserConfig = {
|
|
5
|
+
accountSubscription?: UserSubscriptionConfig;
|
|
6
|
+
driftClient: DriftClient;
|
|
7
|
+
userAccountPublicKey: PublicKey;
|
|
8
|
+
};
|
|
9
|
+
export declare type UserSubscriptionConfig = {
|
|
10
|
+
type: 'websocket';
|
|
11
|
+
} | {
|
|
12
|
+
type: 'polling';
|
|
13
|
+
accountLoader: BulkAccountLoader;
|
|
14
|
+
};
|
|
File without changes
|
package/lib/userMap/userMap.d.ts
CHANGED
|
@@ -1,41 +1,41 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { User, DriftClient, OrderRecord, UserSubscriptionConfig } from '..';
|
|
2
2
|
import { PublicKey } from '@solana/web3.js';
|
|
3
3
|
export interface UserMapInterface {
|
|
4
4
|
fetchAllUsers(): Promise<void>;
|
|
5
5
|
addPubkey(userAccountPublicKey: PublicKey): Promise<void>;
|
|
6
6
|
has(key: string): boolean;
|
|
7
|
-
get(key: string):
|
|
8
|
-
mustGet(key: string): Promise<
|
|
7
|
+
get(key: string): User | undefined;
|
|
8
|
+
mustGet(key: string): Promise<User>;
|
|
9
9
|
getUserAuthority(key: string): PublicKey | undefined;
|
|
10
10
|
updateWithOrderRecord(record: OrderRecord): Promise<void>;
|
|
11
|
-
values(): IterableIterator<
|
|
11
|
+
values(): IterableIterator<User>;
|
|
12
12
|
}
|
|
13
13
|
export declare class UserMap implements UserMapInterface {
|
|
14
14
|
private userMap;
|
|
15
|
-
private
|
|
15
|
+
private driftClient;
|
|
16
16
|
private accountSubscription;
|
|
17
|
-
constructor(
|
|
17
|
+
constructor(driftClient: DriftClient, accountSubscription: UserSubscriptionConfig);
|
|
18
18
|
fetchAllUsers(): Promise<void>;
|
|
19
19
|
addPubkey(userAccountPublicKey: PublicKey): Promise<void>;
|
|
20
20
|
has(key: string): boolean;
|
|
21
21
|
/**
|
|
22
|
-
* gets the
|
|
23
|
-
* @param key userAccountPublicKey to get
|
|
24
|
-
* @returns user
|
|
22
|
+
* gets the User for a particular userAccountPublicKey, if no User exists, undefined is returned
|
|
23
|
+
* @param key userAccountPublicKey to get User for
|
|
24
|
+
* @returns user User | undefined
|
|
25
25
|
*/
|
|
26
|
-
get(key: string):
|
|
26
|
+
get(key: string): User | undefined;
|
|
27
27
|
/**
|
|
28
|
-
* gets the
|
|
29
|
-
* @param key userAccountPublicKey to get
|
|
30
|
-
* @returns
|
|
28
|
+
* gets the User for a particular userAccountPublicKey, if no User exists, new one is created
|
|
29
|
+
* @param key userAccountPublicKey to get User for
|
|
30
|
+
* @returns User
|
|
31
31
|
*/
|
|
32
|
-
mustGet(key: string): Promise<
|
|
32
|
+
mustGet(key: string): Promise<User>;
|
|
33
33
|
/**
|
|
34
|
-
* gets the Authority for a particular userAccountPublicKey, if no
|
|
35
|
-
* @param key userAccountPublicKey to get
|
|
34
|
+
* gets the Authority for a particular userAccountPublicKey, if no User exists, undefined is returned
|
|
35
|
+
* @param key userAccountPublicKey to get User for
|
|
36
36
|
* @returns authority PublicKey | undefined
|
|
37
37
|
*/
|
|
38
38
|
getUserAuthority(key: string): PublicKey | undefined;
|
|
39
39
|
updateWithOrderRecord(record: OrderRecord): Promise<void>;
|
|
40
|
-
values(): IterableIterator<
|
|
40
|
+
values(): IterableIterator<User>;
|
|
41
41
|
}
|
package/lib/userMap/userMap.js
CHANGED
|
@@ -4,20 +4,20 @@ exports.UserMap = void 0;
|
|
|
4
4
|
const __1 = require("..");
|
|
5
5
|
const web3_js_1 = require("@solana/web3.js");
|
|
6
6
|
class UserMap {
|
|
7
|
-
constructor(
|
|
7
|
+
constructor(driftClient, accountSubscription) {
|
|
8
8
|
this.userMap = new Map();
|
|
9
|
-
this.
|
|
9
|
+
this.driftClient = driftClient;
|
|
10
10
|
this.accountSubscription = accountSubscription;
|
|
11
11
|
}
|
|
12
12
|
async fetchAllUsers() {
|
|
13
13
|
const userArray = [];
|
|
14
|
-
const programUserAccounts = (await this.
|
|
14
|
+
const programUserAccounts = (await this.driftClient.program.account.user.all());
|
|
15
15
|
for (const programUserAccount of programUserAccounts) {
|
|
16
16
|
if (this.userMap.has(programUserAccount.publicKey.toString())) {
|
|
17
17
|
continue;
|
|
18
18
|
}
|
|
19
|
-
const user = new __1.
|
|
20
|
-
|
|
19
|
+
const user = new __1.User({
|
|
20
|
+
driftClient: this.driftClient,
|
|
21
21
|
userAccountPublicKey: programUserAccount.publicKey,
|
|
22
22
|
accountSubscription: this.accountSubscription,
|
|
23
23
|
});
|
|
@@ -31,8 +31,8 @@ class UserMap {
|
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
33
|
async addPubkey(userAccountPublicKey) {
|
|
34
|
-
const user = new __1.
|
|
35
|
-
|
|
34
|
+
const user = new __1.User({
|
|
35
|
+
driftClient: this.driftClient,
|
|
36
36
|
userAccountPublicKey,
|
|
37
37
|
accountSubscription: this.accountSubscription,
|
|
38
38
|
});
|
|
@@ -43,17 +43,17 @@ class UserMap {
|
|
|
43
43
|
return this.userMap.has(key);
|
|
44
44
|
}
|
|
45
45
|
/**
|
|
46
|
-
* gets the
|
|
47
|
-
* @param key userAccountPublicKey to get
|
|
48
|
-
* @returns user
|
|
46
|
+
* gets the User for a particular userAccountPublicKey, if no User exists, undefined is returned
|
|
47
|
+
* @param key userAccountPublicKey to get User for
|
|
48
|
+
* @returns user User | undefined
|
|
49
49
|
*/
|
|
50
50
|
get(key) {
|
|
51
51
|
return this.userMap.get(key);
|
|
52
52
|
}
|
|
53
53
|
/**
|
|
54
|
-
* gets the
|
|
55
|
-
* @param key userAccountPublicKey to get
|
|
56
|
-
* @returns
|
|
54
|
+
* gets the User for a particular userAccountPublicKey, if no User exists, new one is created
|
|
55
|
+
* @param key userAccountPublicKey to get User for
|
|
56
|
+
* @returns User
|
|
57
57
|
*/
|
|
58
58
|
async mustGet(key) {
|
|
59
59
|
if (!this.has(key)) {
|
|
@@ -64,8 +64,8 @@ class UserMap {
|
|
|
64
64
|
return user;
|
|
65
65
|
}
|
|
66
66
|
/**
|
|
67
|
-
* gets the Authority for a particular userAccountPublicKey, if no
|
|
68
|
-
* @param key userAccountPublicKey to get
|
|
67
|
+
* gets the Authority for a particular userAccountPublicKey, if no User exists, undefined is returned
|
|
68
|
+
* @param key userAccountPublicKey to get User for
|
|
69
69
|
* @returns authority PublicKey | undefined
|
|
70
70
|
*/
|
|
71
71
|
getUserAuthority(key) {
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { DriftClient, OrderRecord, UserStats, UserStatsSubscriptionConfig } from '..';
|
|
2
2
|
import { PublicKey } from '@solana/web3.js';
|
|
3
3
|
import { UserMap } from './userMap';
|
|
4
4
|
export declare class UserStatsMap {
|
|
5
5
|
/**
|
|
6
|
-
* map from authority pubkey to
|
|
6
|
+
* map from authority pubkey to UserStats
|
|
7
7
|
*/
|
|
8
8
|
private userStatsMap;
|
|
9
|
-
private
|
|
9
|
+
private driftClient;
|
|
10
10
|
private accountSubscription;
|
|
11
|
-
constructor(
|
|
11
|
+
constructor(driftClient: DriftClient, accountSubscription: UserStatsSubscriptionConfig);
|
|
12
12
|
fetchAllUserStats(): Promise<void>;
|
|
13
13
|
addUserStat(authority: PublicKey): Promise<void>;
|
|
14
14
|
updateWithOrderRecord(record: OrderRecord, userMap: UserMap): Promise<void>;
|
|
15
15
|
has(authorityPublicKey: string): boolean;
|
|
16
|
-
get(authorityPublicKey: string):
|
|
17
|
-
mustGet(authorityPublicKey: string): Promise<
|
|
18
|
-
values(): IterableIterator<
|
|
16
|
+
get(authorityPublicKey: string): UserStats;
|
|
17
|
+
mustGet(authorityPublicKey: string): Promise<UserStats>;
|
|
18
|
+
values(): IterableIterator<UserStats>;
|
|
19
19
|
}
|
|
@@ -4,25 +4,25 @@ exports.UserStatsMap = void 0;
|
|
|
4
4
|
const __1 = require("..");
|
|
5
5
|
const web3_js_1 = require("@solana/web3.js");
|
|
6
6
|
class UserStatsMap {
|
|
7
|
-
constructor(
|
|
7
|
+
constructor(driftClient, accountSubscription) {
|
|
8
8
|
/**
|
|
9
|
-
* map from authority pubkey to
|
|
9
|
+
* map from authority pubkey to UserStats
|
|
10
10
|
*/
|
|
11
11
|
this.userStatsMap = new Map();
|
|
12
|
-
this.
|
|
12
|
+
this.driftClient = driftClient;
|
|
13
13
|
this.accountSubscription = accountSubscription;
|
|
14
14
|
}
|
|
15
15
|
async fetchAllUserStats() {
|
|
16
16
|
const userStatArray = [];
|
|
17
|
-
const programUserAccounts = (await this.
|
|
17
|
+
const programUserAccounts = (await this.driftClient.program.account.userStats.all());
|
|
18
18
|
for (const programUserAccount of programUserAccounts) {
|
|
19
19
|
const userStat = programUserAccount.account;
|
|
20
20
|
if (this.userStatsMap.has(userStat.authority.toString())) {
|
|
21
21
|
continue;
|
|
22
22
|
}
|
|
23
|
-
const chUserStat = new __1.
|
|
24
|
-
|
|
25
|
-
userStatsAccountPublicKey: (0, __1.getUserStatsAccountPublicKey)(this.
|
|
23
|
+
const chUserStat = new __1.UserStats({
|
|
24
|
+
driftClient: this.driftClient,
|
|
25
|
+
userStatsAccountPublicKey: (0, __1.getUserStatsAccountPublicKey)(this.driftClient.program.programId, userStat.authority),
|
|
26
26
|
accountSubscription: this.accountSubscription,
|
|
27
27
|
});
|
|
28
28
|
userStatArray.push(chUserStat);
|
|
@@ -35,9 +35,9 @@ class UserStatsMap {
|
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
async addUserStat(authority) {
|
|
38
|
-
const userStat = new __1.
|
|
39
|
-
|
|
40
|
-
userStatsAccountPublicKey: (0, __1.getUserStatsAccountPublicKey)(this.
|
|
38
|
+
const userStat = new __1.UserStats({
|
|
39
|
+
driftClient: this.driftClient,
|
|
40
|
+
userStatsAccountPublicKey: (0, __1.getUserStatsAccountPublicKey)(this.driftClient.program.programId, authority),
|
|
41
41
|
accountSubscription: this.accountSubscription,
|
|
42
42
|
});
|
|
43
43
|
await userStat.subscribe();
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { DriftClient } from './driftClient';
|
|
2
2
|
import { PublicKey } from '@solana/web3.js';
|
|
3
3
|
import { DataAndSlot, UserStatsAccountSubscriber } from './accounts/types';
|
|
4
|
-
import {
|
|
4
|
+
import { UserStatsConfig } from './userStatsConfig';
|
|
5
5
|
import { ReferrerInfo, UserStatsAccount } from './types';
|
|
6
|
-
export declare class
|
|
7
|
-
|
|
6
|
+
export declare class UserStats {
|
|
7
|
+
driftClient: DriftClient;
|
|
8
8
|
userStatsAccountPublicKey: PublicKey;
|
|
9
9
|
accountSubscriber: UserStatsAccountSubscriber;
|
|
10
10
|
isSubscribed: boolean;
|
|
11
|
-
constructor(config:
|
|
11
|
+
constructor(config: UserStatsConfig);
|
|
12
12
|
subscribe(): Promise<boolean>;
|
|
13
13
|
fetchAccounts(): Promise<void>;
|
|
14
14
|
unsubscribe(): Promise<void>;
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.UserStats = void 0;
|
|
4
4
|
const web3_js_1 = require("@solana/web3.js");
|
|
5
5
|
const pollingUserStatsAccountSubscriber_1 = require("./accounts/pollingUserStatsAccountSubscriber");
|
|
6
6
|
const webSocketUserStatsAccountSubsriber_1 = require("./accounts/webSocketUserStatsAccountSubsriber");
|
|
7
7
|
const pda_1 = require("./addresses/pda");
|
|
8
|
-
class
|
|
8
|
+
class UserStats {
|
|
9
9
|
constructor(config) {
|
|
10
10
|
var _a;
|
|
11
|
-
this.
|
|
11
|
+
this.driftClient = config.driftClient;
|
|
12
12
|
this.userStatsAccountPublicKey = config.userStatsAccountPublicKey;
|
|
13
13
|
if (((_a = config.accountSubscription) === null || _a === void 0 ? void 0 : _a.type) === 'polling') {
|
|
14
|
-
this.accountSubscriber = new pollingUserStatsAccountSubscriber_1.PollingUserStatsAccountSubscriber(config.
|
|
14
|
+
this.accountSubscriber = new pollingUserStatsAccountSubscriber_1.PollingUserStatsAccountSubscriber(config.driftClient.program, config.userStatsAccountPublicKey, config.accountSubscription.accountLoader);
|
|
15
15
|
}
|
|
16
16
|
else {
|
|
17
|
-
this.accountSubscriber = new webSocketUserStatsAccountSubsriber_1.WebSocketUserStatsAccountSubscriber(config.
|
|
17
|
+
this.accountSubscriber = new webSocketUserStatsAccountSubsriber_1.WebSocketUserStatsAccountSubscriber(config.driftClient.program, config.userStatsAccountPublicKey);
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
20
|
async subscribe() {
|
|
@@ -40,10 +40,10 @@ class ClearingHouseUserStats {
|
|
|
40
40
|
}
|
|
41
41
|
else {
|
|
42
42
|
return {
|
|
43
|
-
referrer: (0, pda_1.getUserAccountPublicKeySync)(this.
|
|
44
|
-
referrerStats: (0, pda_1.getUserStatsAccountPublicKey)(this.
|
|
43
|
+
referrer: (0, pda_1.getUserAccountPublicKeySync)(this.driftClient.program.programId, this.getAccount().referrer, 0),
|
|
44
|
+
referrerStats: (0, pda_1.getUserStatsAccountPublicKey)(this.driftClient.program.programId, this.getAccount().referrer),
|
|
45
45
|
};
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
|
-
exports.
|
|
49
|
+
exports.UserStats = UserStats;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { DriftClient } from './driftClient';
|
|
2
|
+
import { PublicKey } from '@solana/web3.js';
|
|
3
|
+
import { BulkAccountLoader } from './accounts/bulkAccountLoader';
|
|
4
|
+
export declare type UserStatsConfig = {
|
|
5
|
+
accountSubscription?: UserStatsSubscriptionConfig;
|
|
6
|
+
driftClient: DriftClient;
|
|
7
|
+
userStatsAccountPublicKey: PublicKey;
|
|
8
|
+
};
|
|
9
|
+
export declare type UserStatsSubscriptionConfig = {
|
|
10
|
+
type: 'websocket';
|
|
11
|
+
} | {
|
|
12
|
+
type: 'polling';
|
|
13
|
+
accountLoader: BulkAccountLoader;
|
|
14
|
+
};
|
|
File without changes
|