@drift-labs/sdk 0.2.0-master.12 → 0.2.0-master.15
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/bulkUserStatsSubscription.d.ts +7 -0
- package/lib/accounts/bulkUserStatsSubscription.js +21 -0
- package/lib/accounts/bulkUserSubscription.js +0 -1
- package/lib/accounts/fetch.d.ts +2 -1
- package/lib/accounts/fetch.js +9 -1
- package/lib/accounts/pollingUserStatsAccountSubscriber.d.ts +27 -0
- package/lib/accounts/pollingUserStatsAccountSubscriber.js +113 -0
- package/lib/accounts/types.d.ts +14 -2
- package/lib/accounts/webSocketUserStatsAccountSubsriber.d.ts +20 -0
- package/lib/accounts/webSocketUserStatsAccountSubsriber.js +47 -0
- package/lib/addresses/pda.d.ts +1 -0
- package/lib/addresses/pda.js +8 -1
- package/lib/admin.d.ts +2 -0
- package/lib/admin.js +18 -0
- package/lib/clearingHouse.d.ts +17 -1
- package/lib/clearingHouse.js +195 -14
- package/lib/clearingHouseConfig.d.ts +1 -0
- package/lib/clearingHouseUser.d.ts +5 -0
- package/lib/clearingHouseUser.js +97 -3
- package/lib/clearingHouseUserStats.d.ts +17 -0
- package/lib/clearingHouseUserStats.js +36 -0
- package/lib/clearingHouseUserStatsConfig.d.ts +14 -0
- package/{src/clearingHouseConfig.js → lib/clearingHouseUserStatsConfig.js} +0 -0
- package/lib/config.js +1 -1
- package/lib/factory/bigNum.js +7 -9
- package/lib/idl/clearing_house.json +620 -64
- package/lib/math/amm.js +2 -2
- package/lib/math/bankBalance.d.ts +4 -0
- package/lib/math/bankBalance.js +24 -2
- package/lib/math/oracles.d.ts +3 -0
- package/lib/math/oracles.js +25 -5
- package/lib/math/position.js +2 -1
- package/lib/math/trade.js +2 -2
- package/lib/types.d.ts +57 -9
- package/lib/types.js +6 -0
- package/package.json +1 -1
- package/src/accounts/bulkUserStatsSubscription.ts +33 -0
- package/src/accounts/bulkUserSubscription.ts +0 -1
- package/src/accounts/fetch.ts +27 -2
- package/src/accounts/pollingUserStatsAccountSubscriber.ts +172 -0
- package/src/accounts/types.ts +18 -0
- package/src/accounts/webSocketUserStatsAccountSubsriber.ts +80 -0
- package/src/addresses/pda.ts +13 -0
- package/src/admin.ts +29 -1
- package/src/clearingHouse.ts +318 -15
- package/src/clearingHouseConfig.ts +1 -0
- package/src/clearingHouseUser.ts +113 -10
- package/src/clearingHouseUserStats.ts +53 -0
- package/src/clearingHouseUserStatsConfig.ts +18 -0
- package/src/config.ts +1 -1
- package/src/factory/bigNum.ts +6 -7
- package/src/idl/clearing_house.json +620 -64
- package/src/math/amm.ts +8 -5
- package/src/math/bankBalance.ts +50 -1
- package/src/math/oracles.ts +42 -5
- package/src/math/position.ts +2 -1
- package/src/math/trade.ts +2 -2
- package/src/types.ts +61 -9
- package/tests/bn/test.ts +8 -0
- package/src/accounts/bulkAccountLoader.js +0 -197
- package/src/accounts/bulkUserSubscription.js +0 -33
- package/src/accounts/pollingClearingHouseAccountSubscriber.js +0 -311
- package/src/accounts/pollingOracleSubscriber.js +0 -93
- package/src/accounts/pollingTokenAccountSubscriber.js +0 -90
- package/src/accounts/pollingUserAccountSubscriber.js +0 -132
- package/src/accounts/types.js +0 -10
- package/src/accounts/utils.js +0 -7
- package/src/accounts/webSocketAccountSubscriber.js +0 -93
- package/src/accounts/webSocketClearingHouseAccountSubscriber.js +0 -233
- package/src/accounts/webSocketUserAccountSubscriber.js +0 -62
- package/src/addresses/marketAddresses.js +0 -26
- package/src/assert/assert.js +0 -9
- package/src/clearingHouseUserConfig.js +0 -2
- package/src/constants/banks.js +0 -42
- package/src/constants/markets.js +0 -42
- package/src/constants/numericConstants.js +0 -41
- package/src/events/eventList.js +0 -77
- package/src/events/eventSubscriber.js +0 -139
- package/src/events/fetchLogs.js +0 -50
- package/src/events/pollingLogProvider.js +0 -64
- package/src/events/sort.js +0 -44
- package/src/events/txEventCache.js +0 -71
- package/src/events/types.js +0 -20
- package/src/events/webSocketLogProvider.js +0 -41
- package/src/examples/makeTradeExample.js +0 -80
- package/src/factory/bigNum.js +0 -390
- package/src/factory/oracleClient.js +0 -20
- package/src/index.js +0 -69
- package/src/math/amm.js +0 -369
- package/src/math/auction.js +0 -42
- package/src/math/conversion.js +0 -11
- package/src/math/funding.js +0 -248
- package/src/math/oracles.js +0 -26
- package/src/math/repeg.js +0 -128
- package/src/math/state.js +0 -15
- package/src/math/trade.js +0 -253
- package/src/math/utils.js +0 -26
- package/src/math/utils.js.map +0 -1
- package/src/mockUSDCFaucet.js +0 -280
- package/src/oracles/oracleClientCache.js +0 -19
- package/src/oracles/pythClient.js +0 -46
- package/src/oracles/quoteAssetOracleClient.js +0 -32
- package/src/oracles/switchboardClient.js +0 -69
- package/src/oracles/types.js +0 -2
- package/src/orderParams.js +0 -20
- package/src/slot/SlotSubscriber.js +0 -39
- package/src/token/index.js +0 -38
- package/src/tokenFaucet.js +0 -189
- package/src/tx/types.js +0 -2
- package/src/tx/utils.js +0 -17
- package/src/types.js +0 -125
- package/src/userName.js +0 -20
- package/src/util/computeUnits.js +0 -27
- package/src/util/getTokenAddress.js +0 -9
- package/src/util/promiseTimeout.js +0 -14
- package/src/util/tps.js +0 -27
- package/src/wallet.js +0 -35
package/lib/math/amm.js
CHANGED
|
@@ -8,11 +8,11 @@ const assert_1 = require("../assert/assert");
|
|
|
8
8
|
const __1 = require("..");
|
|
9
9
|
const repeg_1 = require("./repeg");
|
|
10
10
|
function calculatePegFromTargetPrice(targetPrice, baseAssetReserve, quoteAssetReserve) {
|
|
11
|
-
return targetPrice
|
|
11
|
+
return anchor_1.BN.max(targetPrice
|
|
12
12
|
.mul(baseAssetReserve)
|
|
13
13
|
.div(quoteAssetReserve)
|
|
14
14
|
.add(numericConstants_1.PRICE_DIV_PEG.div(new anchor_1.BN(2)))
|
|
15
|
-
.div(numericConstants_1.PRICE_DIV_PEG);
|
|
15
|
+
.div(numericConstants_1.PRICE_DIV_PEG), numericConstants_1.ONE);
|
|
16
16
|
}
|
|
17
17
|
exports.calculatePegFromTargetPrice = calculatePegFromTargetPrice;
|
|
18
18
|
function calculateOptimalPegAndBudget(amm, oraclePriceData) {
|
package/lib/math/bankBalance.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.calculateInterestAccumulated = exports.calculateLiabilityWeight = exports.calculateAssetWeight = exports.getTokenAmount = exports.getBalance = void 0;
|
|
3
|
+
exports.calculateWithdrawLimit = exports.calculateInterestAccumulated = exports.calculateLiabilityWeight = exports.calculateAssetWeight = exports.getTokenAmount = exports.getBalance = void 0;
|
|
4
4
|
const types_1 = require("../types");
|
|
5
5
|
const anchor_1 = require("@project-serum/anchor");
|
|
6
6
|
const numericConstants_1 = require("../constants/numericConstants");
|
|
@@ -109,7 +109,7 @@ function calculateInterestAccumulated(bank, now) {
|
|
|
109
109
|
.mul(borrowRateSlope)
|
|
110
110
|
.div(numericConstants_1.BANK_UTILIZATION_PRECISION);
|
|
111
111
|
}
|
|
112
|
-
const timeSinceLastUpdate = now.sub(bank.
|
|
112
|
+
const timeSinceLastUpdate = now.sub(bank.lastInterestTs);
|
|
113
113
|
const modifiedBorrowRate = interest_rate.mul(timeSinceLastUpdate);
|
|
114
114
|
const modifiedDepositRate = modifiedBorrowRate
|
|
115
115
|
.mul(utilization)
|
|
@@ -126,3 +126,25 @@ function calculateInterestAccumulated(bank, now) {
|
|
|
126
126
|
return { borrowInterest, depositInterest };
|
|
127
127
|
}
|
|
128
128
|
exports.calculateInterestAccumulated = calculateInterestAccumulated;
|
|
129
|
+
function calculateWithdrawLimit(bank, now) {
|
|
130
|
+
const bankDepositTokenAmount = getTokenAmount(bank.depositBalance, bank, types_1.BankBalanceType.DEPOSIT);
|
|
131
|
+
const bankBorrowTokenAmount = getTokenAmount(bank.borrowBalance, bank, types_1.BankBalanceType.BORROW);
|
|
132
|
+
const twentyFourHours = new anchor_1.BN(60 * 60 * 24);
|
|
133
|
+
const sinceLast = now.sub(bank.lastTwapTs);
|
|
134
|
+
const sinceStart = anchor_1.BN.max(numericConstants_1.ZERO, twentyFourHours.sub(sinceLast));
|
|
135
|
+
const borrowTokenTwapLive = bank.borrowTokenTwap
|
|
136
|
+
.mul(sinceStart)
|
|
137
|
+
.add(bankBorrowTokenAmount.mul(sinceLast))
|
|
138
|
+
.div(sinceLast.add(sinceLast));
|
|
139
|
+
const depositTokenTwapLive = bank.depositTokenTwap
|
|
140
|
+
.mul(sinceStart)
|
|
141
|
+
.add(bankDepositTokenAmount.mul(sinceLast))
|
|
142
|
+
.div(sinceLast.add(sinceLast));
|
|
143
|
+
const maxBorrowTokens = anchor_1.BN.min(anchor_1.BN.max(bankDepositTokenAmount.div(new anchor_1.BN(6)), borrowTokenTwapLive.add(borrowTokenTwapLive.div(new anchor_1.BN(5)))), bankDepositTokenAmount.sub(bankDepositTokenAmount.div(new anchor_1.BN(10)))); // between ~15-90% utilization with friction on twap
|
|
144
|
+
const minDepositTokens = depositTokenTwapLive.sub(anchor_1.BN.min(anchor_1.BN.max(depositTokenTwapLive.div(new anchor_1.BN(5)), bank.withdrawGuardThreshold), depositTokenTwapLive));
|
|
145
|
+
return {
|
|
146
|
+
borrowLimit: maxBorrowTokens.sub(bankBorrowTokenAmount),
|
|
147
|
+
withdrawLimit: bankDepositTokenAmount.sub(minDepositTokens),
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
exports.calculateWithdrawLimit = calculateWithdrawLimit;
|
package/lib/math/oracles.d.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
/// <reference types="bn.js" />
|
|
1
2
|
import { AMM, OracleGuardRails } from '../types';
|
|
2
3
|
import { OraclePriceData } from '../oracles/types';
|
|
4
|
+
import { BN } from '../index';
|
|
3
5
|
export declare function isOracleValid(amm: AMM, oraclePriceData: OraclePriceData, oracleGuardRails: OracleGuardRails, slot: number): boolean;
|
|
6
|
+
export declare function isOracleTooDivergent(amm: AMM, oraclePriceData: OraclePriceData, oracleGuardRails: OracleGuardRails, now: BN): boolean;
|
package/lib/math/oracles.js
CHANGED
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.isOracleValid = void 0;
|
|
3
|
+
exports.isOracleTooDivergent = exports.isOracleValid = void 0;
|
|
4
4
|
const numericConstants_1 = require("../constants/numericConstants");
|
|
5
5
|
const index_1 = require("../index");
|
|
6
6
|
function isOracleValid(amm, oraclePriceData, oracleGuardRails, slot) {
|
|
7
|
-
const isOraclePriceNonPositive = oraclePriceData.price.
|
|
7
|
+
const isOraclePriceNonPositive = oraclePriceData.price.lte(numericConstants_1.ZERO);
|
|
8
8
|
const isOraclePriceTooVolatile = oraclePriceData.price
|
|
9
9
|
.div(index_1.BN.max(numericConstants_1.ONE, amm.lastOraclePriceTwap))
|
|
10
10
|
.gt(oracleGuardRails.validity.tooVolatileRatio) ||
|
|
11
11
|
amm.lastOraclePriceTwap
|
|
12
12
|
.div(index_1.BN.max(numericConstants_1.ONE, oraclePriceData.price))
|
|
13
13
|
.gt(oracleGuardRails.validity.tooVolatileRatio);
|
|
14
|
-
const isConfidenceTooLarge =
|
|
15
|
-
.
|
|
16
|
-
.
|
|
14
|
+
const isConfidenceTooLarge = new index_1.BN(amm.baseSpread)
|
|
15
|
+
.add(index_1.BN.max(numericConstants_1.ONE, oraclePriceData.confidence))
|
|
16
|
+
.mul(numericConstants_1.BID_ASK_SPREAD_PRECISION)
|
|
17
|
+
.div(oraclePriceData.price)
|
|
18
|
+
.gt(new index_1.BN(amm.maxSpread));
|
|
17
19
|
const oracleIsStale = oraclePriceData.slot
|
|
18
20
|
.sub(new index_1.BN(slot))
|
|
19
21
|
.gt(oracleGuardRails.validity.slotsBeforeStale);
|
|
@@ -24,3 +26,21 @@ function isOracleValid(amm, oraclePriceData, oracleGuardRails, slot) {
|
|
|
24
26
|
isConfidenceTooLarge);
|
|
25
27
|
}
|
|
26
28
|
exports.isOracleValid = isOracleValid;
|
|
29
|
+
function isOracleTooDivergent(amm, oraclePriceData, oracleGuardRails, now) {
|
|
30
|
+
const sinceLastUpdate = now.sub(amm.lastOraclePriceTwapTs);
|
|
31
|
+
const sinceStart = index_1.BN.max(numericConstants_1.ZERO, new index_1.BN(60 * 5).sub(sinceLastUpdate));
|
|
32
|
+
const oracleTwap5min = amm.lastOraclePriceTwap5min
|
|
33
|
+
.mul(sinceStart)
|
|
34
|
+
.add(oraclePriceData.price)
|
|
35
|
+
.mul(sinceLastUpdate)
|
|
36
|
+
.div(sinceStart.add(sinceLastUpdate));
|
|
37
|
+
const oracleSpread = oracleTwap5min.sub(oraclePriceData.price);
|
|
38
|
+
const oracleSpreadPct = oracleSpread
|
|
39
|
+
.mul(numericConstants_1.MARK_PRICE_PRECISION)
|
|
40
|
+
.div(oracleTwap5min);
|
|
41
|
+
const tooDivergent = oracleSpreadPct
|
|
42
|
+
.abs()
|
|
43
|
+
.gte(numericConstants_1.BID_ASK_SPREAD_PRECISION.mul(oracleGuardRails.priceDivergence.markOracleDivergenceNumerator).div(oracleGuardRails.priceDivergence.markOracleDivergenceDenominator));
|
|
44
|
+
return tooDivergent;
|
|
45
|
+
}
|
|
46
|
+
exports.isOracleTooDivergent = isOracleTooDivergent;
|
package/lib/math/position.js
CHANGED
|
@@ -117,7 +117,8 @@ exports.calculatePositionFundingPNL = calculatePositionFundingPNL;
|
|
|
117
117
|
function positionIsAvailable(position) {
|
|
118
118
|
return (position.baseAssetAmount.eq(numericConstants_1.ZERO) &&
|
|
119
119
|
position.openOrders.eq(numericConstants_1.ZERO) &&
|
|
120
|
-
position.quoteAssetAmount.eq(numericConstants_1.ZERO)
|
|
120
|
+
position.quoteAssetAmount.eq(numericConstants_1.ZERO) &&
|
|
121
|
+
position.lpShares.eq(numericConstants_1.ZERO));
|
|
121
122
|
}
|
|
122
123
|
exports.positionIsAvailable = positionIsAvailable;
|
|
123
124
|
/**
|
package/lib/math/trade.js
CHANGED
|
@@ -113,8 +113,8 @@ function calculateTradeAcquiredAmounts(direction, amount, market, inputAssetType
|
|
|
113
113
|
const [newQuoteAssetReserve, newBaseAssetReserve] = (0, amm_1.calculateAmmReservesAfterSwap)(amm, inputAssetType, amount, swapDirection);
|
|
114
114
|
const acquiredBase = amm.baseAssetReserve.sub(newBaseAssetReserve);
|
|
115
115
|
const acquiredQuote = amm.quoteAssetReserve.sub(newQuoteAssetReserve);
|
|
116
|
-
const
|
|
117
|
-
return [acquiredBase, acquiredQuote,
|
|
116
|
+
const acquiredQuoteAssetAmount = (0, amm_1.calculateQuoteAssetAmountSwapped)(acquiredQuote.abs(), amm.pegMultiplier, swapDirection);
|
|
117
|
+
return [acquiredBase, acquiredQuote, acquiredQuoteAssetAmount];
|
|
118
118
|
}
|
|
119
119
|
exports.calculateTradeAcquiredAmounts = calculateTradeAcquiredAmounts;
|
|
120
120
|
/**
|
package/lib/types.d.ts
CHANGED
|
@@ -203,6 +203,8 @@ export declare type LiquidationRecord = {
|
|
|
203
203
|
liquidateBorrow: LiquidateBorrowRecord;
|
|
204
204
|
liquidateBorrowForPerpPnl: LiquidateBorrowForPerpPnlRecord;
|
|
205
205
|
liquidatePerpPnlForDeposit: LiquidatePerpPnlForDepositRecord;
|
|
206
|
+
perpBankruptcy: PerpBankruptcyRecord;
|
|
207
|
+
borrowBankruptcy: BorrowBankruptcyRecord;
|
|
206
208
|
};
|
|
207
209
|
export declare class LiquidationType {
|
|
208
210
|
static readonly LIQUIDATE_PERP: {
|
|
@@ -217,6 +219,12 @@ export declare class LiquidationType {
|
|
|
217
219
|
static readonly LIQUIDATE_PERP_PNL_FOR_DEPOSIT: {
|
|
218
220
|
liquidatePerpPnlForDeposit: {};
|
|
219
221
|
};
|
|
222
|
+
static readonly PERP_BANKRUPTCY: {
|
|
223
|
+
perpBankruptcy: {};
|
|
224
|
+
};
|
|
225
|
+
static readonly BORROW_BANKRUPTCY: {
|
|
226
|
+
borrowBankruptcy: {};
|
|
227
|
+
};
|
|
220
228
|
}
|
|
221
229
|
export declare type LiquidatePerpRecord = {
|
|
222
230
|
marketIndex: BN;
|
|
@@ -255,14 +263,25 @@ export declare type LiquidatePerpPnlForDepositRecord = {
|
|
|
255
263
|
assetPrice: BN;
|
|
256
264
|
assetTransfer: BN;
|
|
257
265
|
};
|
|
266
|
+
export declare type PerpBankruptcyRecord = {
|
|
267
|
+
marketIndex: BN;
|
|
268
|
+
pnl: BN;
|
|
269
|
+
cumulativeFundingRateDelta: BN;
|
|
270
|
+
};
|
|
271
|
+
export declare type BorrowBankruptcyRecord = {
|
|
272
|
+
bankIndex: BN;
|
|
273
|
+
borrowAmount: BN;
|
|
274
|
+
cumulativeDepositInterestDelta: BN;
|
|
275
|
+
};
|
|
258
276
|
export declare type SettlePnlRecord = {
|
|
259
277
|
ts: BN;
|
|
278
|
+
user: PublicKey;
|
|
260
279
|
marketIndex: BN;
|
|
261
280
|
pnl: BN;
|
|
262
281
|
baseAssetAmount: BN;
|
|
263
282
|
quoteAssetAmountAfter: BN;
|
|
264
283
|
quoteEntryamount: BN;
|
|
265
|
-
|
|
284
|
+
settlePrice: BN;
|
|
266
285
|
};
|
|
267
286
|
export declare type OrderRecord = {
|
|
268
287
|
ts: BN;
|
|
@@ -349,7 +368,8 @@ export declare type BankAccount = {
|
|
|
349
368
|
cumulativeBorrowInterest: BN;
|
|
350
369
|
depositBalance: BN;
|
|
351
370
|
borrowBalance: BN;
|
|
352
|
-
|
|
371
|
+
lastInterestTs: BN;
|
|
372
|
+
lastTwapTs: BN;
|
|
353
373
|
oracle: PublicKey;
|
|
354
374
|
initialAssetWeight: BN;
|
|
355
375
|
maintenanceAssetWeight: BN;
|
|
@@ -357,6 +377,10 @@ export declare type BankAccount = {
|
|
|
357
377
|
maintenanceLiabilityWeight: BN;
|
|
358
378
|
liquidationFee: BN;
|
|
359
379
|
imfFactor: BN;
|
|
380
|
+
withdrawGuardThreshold: BN;
|
|
381
|
+
depositTokenTwap: BN;
|
|
382
|
+
borrowTokenTwap: BN;
|
|
383
|
+
utilizationTwap: BN;
|
|
360
384
|
};
|
|
361
385
|
export declare type PoolBalance = {
|
|
362
386
|
balance: BN;
|
|
@@ -368,8 +392,10 @@ export declare type AMM = {
|
|
|
368
392
|
lastFundingRate: BN;
|
|
369
393
|
lastFundingRateTs: BN;
|
|
370
394
|
lastMarkPriceTwap: BN;
|
|
395
|
+
lastMarkPriceTwap5min: BN;
|
|
371
396
|
lastMarkPriceTwapTs: BN;
|
|
372
397
|
lastOraclePriceTwap: BN;
|
|
398
|
+
lastOraclePriceTwap5min: BN;
|
|
373
399
|
lastOraclePriceTwapTs: BN;
|
|
374
400
|
lastOracleMarkSpreadPct: BN;
|
|
375
401
|
lastOracleConfPct: BN;
|
|
@@ -380,11 +406,16 @@ export declare type AMM = {
|
|
|
380
406
|
pegMultiplier: BN;
|
|
381
407
|
cumulativeFundingRateLong: BN;
|
|
382
408
|
cumulativeFundingRateShort: BN;
|
|
409
|
+
cumulativeFundingRateLp: BN;
|
|
383
410
|
cumulativeRepegRebateLong: BN;
|
|
384
411
|
cumulativeRepegRebateShort: BN;
|
|
385
412
|
totalFeeMinusDistributions: BN;
|
|
386
413
|
totalFeeWithdrawn: BN;
|
|
387
414
|
totalFee: BN;
|
|
415
|
+
cumulativeFundingPaymentPerLp: BN;
|
|
416
|
+
cumulativeFeePerLp: BN;
|
|
417
|
+
cumulativeNetBaseAssetAmountPerLp: BN;
|
|
418
|
+
userLpShares: BN;
|
|
388
419
|
minimumQuoteAssetTradeSize: BN;
|
|
389
420
|
baseAssetAmountStepSize: BN;
|
|
390
421
|
maxBaseAssetAmountRatio: number;
|
|
@@ -406,6 +437,8 @@ export declare type AMM = {
|
|
|
406
437
|
longSpread: BN;
|
|
407
438
|
shortSpread: BN;
|
|
408
439
|
maxSpread: number;
|
|
440
|
+
marketPosition: UserPosition;
|
|
441
|
+
marketPositionPerLp: UserPosition;
|
|
409
442
|
};
|
|
410
443
|
export declare type UserPosition = {
|
|
411
444
|
baseAssetAmount: BN;
|
|
@@ -416,14 +449,20 @@ export declare type UserPosition = {
|
|
|
416
449
|
openOrders: BN;
|
|
417
450
|
openBids: BN;
|
|
418
451
|
openAsks: BN;
|
|
452
|
+
realizedPnl: BN;
|
|
453
|
+
lpShares: BN;
|
|
454
|
+
lastFeePerLp: BN;
|
|
455
|
+
lastNetBaseAssetAmountPerLp: BN;
|
|
456
|
+
lastNetQuoteAssetAmountPerLp: BN;
|
|
419
457
|
};
|
|
420
|
-
export declare type
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
458
|
+
export declare type UserStatsAccount = {
|
|
459
|
+
numberOfUsers: number;
|
|
460
|
+
makerVolume30D: BN;
|
|
461
|
+
takerVolume30D: BN;
|
|
462
|
+
fillerVolume30D: BN;
|
|
463
|
+
lastMakerVolume30DTs: BN;
|
|
464
|
+
lastTakerVolume30DTs: BN;
|
|
465
|
+
lastFillerVolume30DTs: BN;
|
|
427
466
|
fees: {
|
|
428
467
|
totalFeePaid: BN;
|
|
429
468
|
totalFeeRebate: BN;
|
|
@@ -431,9 +470,16 @@ export declare type UserAccount = {
|
|
|
431
470
|
totalReferralReward: BN;
|
|
432
471
|
totalRefereeDiscount: BN;
|
|
433
472
|
};
|
|
473
|
+
};
|
|
474
|
+
export declare type UserAccount = {
|
|
475
|
+
authority: PublicKey;
|
|
476
|
+
name: number[];
|
|
477
|
+
userId: number;
|
|
478
|
+
bankBalances: UserBankBalance[];
|
|
434
479
|
positions: UserPosition[];
|
|
435
480
|
orders: Order[];
|
|
436
481
|
beingLiquidated: boolean;
|
|
482
|
+
bankrupt: boolean;
|
|
437
483
|
nextLiquidationId: number;
|
|
438
484
|
};
|
|
439
485
|
export declare type UserBankBalance = {
|
|
@@ -529,10 +575,12 @@ export declare const DefaultOrderParams: {
|
|
|
529
575
|
};
|
|
530
576
|
export declare type MakerInfo = {
|
|
531
577
|
maker: PublicKey;
|
|
578
|
+
makerStats: PublicKey;
|
|
532
579
|
order: Order;
|
|
533
580
|
};
|
|
534
581
|
export declare type TakerInfo = {
|
|
535
582
|
taker: PublicKey;
|
|
583
|
+
takerStats: PublicKey;
|
|
536
584
|
order: Order;
|
|
537
585
|
};
|
|
538
586
|
export interface IWallet {
|
package/lib/types.js
CHANGED
|
@@ -108,6 +108,12 @@ LiquidationType.LIQUIDATE_BORROW_FOR_PERP_PNL = {
|
|
|
108
108
|
LiquidationType.LIQUIDATE_PERP_PNL_FOR_DEPOSIT = {
|
|
109
109
|
liquidatePerpPnlForDeposit: {},
|
|
110
110
|
};
|
|
111
|
+
LiquidationType.PERP_BANKRUPTCY = {
|
|
112
|
+
perpBankruptcy: {},
|
|
113
|
+
};
|
|
114
|
+
LiquidationType.BORROW_BANKRUPTCY = {
|
|
115
|
+
borrowBankruptcy: {},
|
|
116
|
+
};
|
|
111
117
|
exports.DefaultOrderParams = {
|
|
112
118
|
orderType: OrderType.MARKET,
|
|
113
119
|
userOrderId: 0,
|
package/package.json
CHANGED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { ClearingHouseUserStats } from '../clearingHouseUserStats';
|
|
2
|
+
import { BulkAccountLoader } from './bulkAccountLoader';
|
|
3
|
+
import { PollingUserStatsAccountSubscriber } from './pollingUserStatsAccountSubscriber';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @param userStats
|
|
7
|
+
* @param accountLoader
|
|
8
|
+
*/
|
|
9
|
+
export async function bulkPollingUserStatsSubscribe(
|
|
10
|
+
userStats: ClearingHouseUserStats[],
|
|
11
|
+
accountLoader: BulkAccountLoader
|
|
12
|
+
): Promise<void> {
|
|
13
|
+
if (userStats.length === 0) {
|
|
14
|
+
await accountLoader.load();
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
await Promise.all(
|
|
19
|
+
userStats.map((userStat) => {
|
|
20
|
+
return (
|
|
21
|
+
userStat.accountSubscriber as PollingUserStatsAccountSubscriber
|
|
22
|
+
).addToAccountLoader();
|
|
23
|
+
})
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
await accountLoader.load();
|
|
27
|
+
|
|
28
|
+
await Promise.all(
|
|
29
|
+
userStats.map(async (userStat) => {
|
|
30
|
+
return userStat.subscribe();
|
|
31
|
+
})
|
|
32
|
+
);
|
|
33
|
+
}
|
|
@@ -17,7 +17,6 @@ export async function bulkPollingUserSubscribe(
|
|
|
17
17
|
|
|
18
18
|
await Promise.all(
|
|
19
19
|
users.map((user) => {
|
|
20
|
-
// Pull the keys from the authority map so we can skip fetching them in addToAccountLoader
|
|
21
20
|
return (
|
|
22
21
|
user.accountSubscriber as PollingUserAccountSubscriber
|
|
23
22
|
).addToAccountLoader();
|
package/src/accounts/fetch.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { Connection, PublicKey } from '@solana/web3.js';
|
|
2
|
-
import { UserAccount } from '../types';
|
|
3
|
-
import {
|
|
2
|
+
import { UserAccount, UserStatsAccount } from '../types';
|
|
3
|
+
import {
|
|
4
|
+
getUserAccountPublicKey,
|
|
5
|
+
getUserStatsAccountPublicKey,
|
|
6
|
+
} from '../addresses/pda';
|
|
4
7
|
import { Program } from '@project-serum/anchor';
|
|
5
8
|
|
|
6
9
|
export async function fetchUserAccounts(
|
|
@@ -31,3 +34,25 @@ export async function fetchUserAccounts(
|
|
|
31
34
|
) as UserAccount;
|
|
32
35
|
});
|
|
33
36
|
}
|
|
37
|
+
|
|
38
|
+
export async function fetchUserStatsAccount(
|
|
39
|
+
connection: Connection,
|
|
40
|
+
program: Program,
|
|
41
|
+
authority: PublicKey
|
|
42
|
+
): Promise<UserStatsAccount | undefined> {
|
|
43
|
+
const userStatsPublicKey = getUserStatsAccountPublicKey(
|
|
44
|
+
program.programId,
|
|
45
|
+
authority
|
|
46
|
+
);
|
|
47
|
+
const accountInfo = await connection.getAccountInfo(
|
|
48
|
+
userStatsPublicKey,
|
|
49
|
+
'confirmed'
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
return accountInfo
|
|
53
|
+
? (program.account.user.coder.accounts.decode(
|
|
54
|
+
'UserStats',
|
|
55
|
+
accountInfo.data
|
|
56
|
+
) as UserStatsAccount)
|
|
57
|
+
: undefined;
|
|
58
|
+
}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DataAndSlot,
|
|
3
|
+
AccountToPoll,
|
|
4
|
+
NotSubscribedError,
|
|
5
|
+
UserStatsAccountSubscriber,
|
|
6
|
+
UserStatsAccountEvents,
|
|
7
|
+
} from './types';
|
|
8
|
+
import { Program } from '@project-serum/anchor';
|
|
9
|
+
import StrictEventEmitter from 'strict-event-emitter-types';
|
|
10
|
+
import { EventEmitter } from 'events';
|
|
11
|
+
import { PublicKey } from '@solana/web3.js';
|
|
12
|
+
import { UserStatsAccount } from '../types';
|
|
13
|
+
import { BulkAccountLoader } from './bulkAccountLoader';
|
|
14
|
+
import { capitalize } from './utils';
|
|
15
|
+
|
|
16
|
+
export class PollingUserStatsAccountSubscriber
|
|
17
|
+
implements UserStatsAccountSubscriber
|
|
18
|
+
{
|
|
19
|
+
isSubscribed: boolean;
|
|
20
|
+
program: Program;
|
|
21
|
+
eventEmitter: StrictEventEmitter<EventEmitter, UserStatsAccountEvents>;
|
|
22
|
+
userStatsAccountPublicKey: PublicKey;
|
|
23
|
+
|
|
24
|
+
accountLoader: BulkAccountLoader;
|
|
25
|
+
accountsToPoll = new Map<string, AccountToPoll>();
|
|
26
|
+
errorCallbackId?: string;
|
|
27
|
+
|
|
28
|
+
userStats?: DataAndSlot<UserStatsAccount>;
|
|
29
|
+
|
|
30
|
+
public constructor(
|
|
31
|
+
program: Program,
|
|
32
|
+
userStatsAccountPublicKey: PublicKey,
|
|
33
|
+
accountLoader: BulkAccountLoader
|
|
34
|
+
) {
|
|
35
|
+
this.isSubscribed = false;
|
|
36
|
+
this.program = program;
|
|
37
|
+
this.accountLoader = accountLoader;
|
|
38
|
+
this.eventEmitter = new EventEmitter();
|
|
39
|
+
this.userStatsAccountPublicKey = userStatsAccountPublicKey;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async subscribe(): Promise<boolean> {
|
|
43
|
+
if (this.isSubscribed) {
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
await this.addToAccountLoader();
|
|
48
|
+
|
|
49
|
+
let subscriptionSucceeded = false;
|
|
50
|
+
let retries = 0;
|
|
51
|
+
while (!subscriptionSucceeded && retries < 5) {
|
|
52
|
+
await this.fetchIfUnloaded();
|
|
53
|
+
subscriptionSucceeded = this.didSubscriptionSucceed();
|
|
54
|
+
retries++;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (subscriptionSucceeded) {
|
|
58
|
+
this.eventEmitter.emit('update');
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
this.isSubscribed = subscriptionSucceeded;
|
|
62
|
+
return subscriptionSucceeded;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async addToAccountLoader(): Promise<void> {
|
|
66
|
+
if (this.accountsToPoll.size > 0) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
this.accountsToPoll.set(this.userStatsAccountPublicKey.toString(), {
|
|
71
|
+
key: 'userStats',
|
|
72
|
+
publicKey: this.userStatsAccountPublicKey,
|
|
73
|
+
eventType: 'userStatsAccountUpdate',
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
for (const [_, accountToPoll] of this.accountsToPoll) {
|
|
77
|
+
accountToPoll.callbackId = this.accountLoader.addAccount(
|
|
78
|
+
accountToPoll.publicKey,
|
|
79
|
+
(buffer, slot) => {
|
|
80
|
+
if (!buffer) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const account = this.program.account[
|
|
85
|
+
accountToPoll.key
|
|
86
|
+
].coder.accounts.decode(capitalize(accountToPoll.key), buffer);
|
|
87
|
+
this[accountToPoll.key] = { data: account, slot };
|
|
88
|
+
// @ts-ignore
|
|
89
|
+
this.eventEmitter.emit(accountToPoll.eventType, account);
|
|
90
|
+
this.eventEmitter.emit('update');
|
|
91
|
+
}
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
this.errorCallbackId = this.accountLoader.addErrorCallbacks((error) => {
|
|
96
|
+
this.eventEmitter.emit('error', error);
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
async fetchIfUnloaded(): Promise<void> {
|
|
101
|
+
let shouldFetch = false;
|
|
102
|
+
for (const [_, accountToPoll] of this.accountsToPoll) {
|
|
103
|
+
if (this[accountToPoll.key] === undefined) {
|
|
104
|
+
shouldFetch = true;
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (shouldFetch) {
|
|
110
|
+
await this.fetch();
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
async fetch(): Promise<void> {
|
|
115
|
+
await this.accountLoader.load();
|
|
116
|
+
for (const [_, accountToPoll] of this.accountsToPoll) {
|
|
117
|
+
const { buffer, slot } = this.accountLoader.getBufferAndSlot(
|
|
118
|
+
accountToPoll.publicKey
|
|
119
|
+
);
|
|
120
|
+
if (buffer) {
|
|
121
|
+
const account = this.program.account[
|
|
122
|
+
accountToPoll.key
|
|
123
|
+
].coder.accounts.decode(capitalize(accountToPoll.key), buffer);
|
|
124
|
+
this[accountToPoll.key] = { data: account, slot };
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
didSubscriptionSucceed(): boolean {
|
|
130
|
+
let success = true;
|
|
131
|
+
for (const [_, accountToPoll] of this.accountsToPoll) {
|
|
132
|
+
if (!this[accountToPoll.key]) {
|
|
133
|
+
success = false;
|
|
134
|
+
break;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return success;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
async unsubscribe(): Promise<void> {
|
|
141
|
+
if (!this.isSubscribed) {
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
for (const [_, accountToPoll] of this.accountsToPoll) {
|
|
146
|
+
this.accountLoader.removeAccount(
|
|
147
|
+
accountToPoll.publicKey,
|
|
148
|
+
accountToPoll.callbackId
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
this.accountLoader.removeErrorCallbacks(this.errorCallbackId);
|
|
153
|
+
this.errorCallbackId = undefined;
|
|
154
|
+
|
|
155
|
+
this.accountsToPoll.clear();
|
|
156
|
+
|
|
157
|
+
this.isSubscribed = false;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
assertIsSubscribed(): void {
|
|
161
|
+
if (!this.isSubscribed) {
|
|
162
|
+
throw new NotSubscribedError(
|
|
163
|
+
'You must call `subscribe` before using this function'
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
public getUserStatsAccountAndSlot(): DataAndSlot<UserStatsAccount> {
|
|
169
|
+
this.assertIsSubscribed();
|
|
170
|
+
return this.userStats;
|
|
171
|
+
}
|
|
172
|
+
}
|
package/src/accounts/types.ts
CHANGED
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
OracleSource,
|
|
5
5
|
StateAccount,
|
|
6
6
|
UserAccount,
|
|
7
|
+
UserStatsAccount,
|
|
7
8
|
} from '../types';
|
|
8
9
|
import StrictEventEmitter from 'strict-event-emitter-types';
|
|
9
10
|
import { EventEmitter } from 'events';
|
|
@@ -130,3 +131,20 @@ export type DataAndSlot<T> = {
|
|
|
130
131
|
data: T;
|
|
131
132
|
slot: number;
|
|
132
133
|
};
|
|
134
|
+
|
|
135
|
+
export interface UserStatsAccountEvents {
|
|
136
|
+
userStatsAccountUpdate: (payload: UserStatsAccount) => void;
|
|
137
|
+
update: void;
|
|
138
|
+
error: (e: Error) => void;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export interface UserStatsAccountSubscriber {
|
|
142
|
+
eventEmitter: StrictEventEmitter<EventEmitter, UserStatsAccountEvents>;
|
|
143
|
+
isSubscribed: boolean;
|
|
144
|
+
|
|
145
|
+
subscribe(): Promise<boolean>;
|
|
146
|
+
fetch(): Promise<void>;
|
|
147
|
+
unsubscribe(): Promise<void>;
|
|
148
|
+
|
|
149
|
+
getUserStatsAccountAndSlot(): DataAndSlot<UserStatsAccount>;
|
|
150
|
+
}
|