@drift-labs/sdk 0.2.0-master.2 → 0.2.0-master.20
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 -1
- 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 +9 -5
- package/lib/admin.js +52 -11
- package/lib/clearingHouse.d.ts +52 -23
- package/lib/clearingHouse.js +727 -197
- package/lib/clearingHouseConfig.d.ts +1 -0
- package/lib/clearingHouseUser.d.ts +17 -17
- package/lib/clearingHouseUser.js +186 -101
- package/lib/clearingHouseUserStats.d.ts +18 -0
- package/lib/clearingHouseUserStats.js +49 -0
- package/lib/clearingHouseUserStatsConfig.d.ts +14 -0
- package/lib/clearingHouseUserStatsConfig.js +2 -0
- package/lib/config.js +1 -1
- package/lib/constants/banks.d.ts +2 -2
- package/lib/constants/banks.js +12 -4
- package/lib/constants/numericConstants.d.ts +5 -0
- package/lib/constants/numericConstants.js +8 -3
- package/lib/events/eventList.js +3 -0
- package/lib/events/types.d.ts +3 -1
- package/lib/events/types.js +2 -0
- package/lib/factory/bigNum.d.ts +1 -0
- package/lib/factory/bigNum.js +34 -10
- package/lib/idl/clearing_house.json +1609 -388
- package/lib/idl/{mock_usdc_faucet.json → token_faucet.json} +46 -23
- package/lib/index.d.ts +9 -3
- package/lib/index.js +13 -3
- package/lib/math/amm.d.ts +1 -0
- package/lib/math/amm.js +22 -38
- package/lib/math/auction.js +4 -1
- package/lib/math/bankBalance.d.ts +7 -1
- package/lib/math/bankBalance.js +77 -2
- package/lib/math/margin.d.ts +11 -0
- package/lib/math/margin.js +72 -0
- package/lib/math/market.d.ts +4 -1
- package/lib/math/market.js +35 -1
- package/lib/math/oracles.d.ts +3 -0
- package/lib/math/oracles.js +25 -5
- package/lib/math/orders.d.ts +5 -2
- package/lib/math/orders.js +53 -12
- package/lib/math/position.d.ts +8 -0
- package/lib/math/position.js +45 -12
- package/lib/math/trade.d.ts +1 -1
- package/lib/math/trade.js +7 -10
- package/lib/orderParams.d.ts +14 -5
- package/lib/orderParams.js +8 -96
- package/lib/slot/SlotSubscriber.d.ts +7 -0
- package/lib/slot/SlotSubscriber.js +3 -0
- package/lib/{mockUSDCFaucet.d.ts → tokenFaucet.d.ts} +8 -5
- package/lib/{mockUSDCFaucet.js → tokenFaucet.js} +63 -51
- package/lib/tx/retryTxSender.js +9 -2
- package/lib/tx/utils.js +1 -1
- package/lib/types.d.ts +233 -26
- package/lib/types.js +64 -1
- package/lib/util/computeUnits.js +1 -1
- package/lib/util/getTokenAddress.d.ts +2 -0
- package/lib/util/getTokenAddress.js +9 -0
- package/package.json +3 -3
- 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/marketAddresses.js +26 -0
- package/src/addresses/pda.ts +13 -0
- package/src/admin.ts +82 -15
- package/src/assert/assert.js +9 -0
- package/src/clearingHouse.ts +1224 -319
- package/src/clearingHouseConfig.ts +1 -0
- package/src/clearingHouseUser.ts +311 -148
- package/src/clearingHouseUserStats.ts +75 -0
- package/src/clearingHouseUserStatsConfig.ts +18 -0
- package/src/config.ts +1 -1
- package/src/constants/banks.js +42 -0
- package/src/constants/banks.ts +14 -4
- package/src/constants/markets.js +42 -0
- package/src/constants/numericConstants.js +41 -0
- package/src/constants/numericConstants.ts +14 -2
- package/src/events/eventList.js +77 -0
- package/src/events/eventList.ts +3 -0
- package/src/events/eventSubscriber.js +139 -0
- package/src/events/fetchLogs.js +50 -0
- package/src/events/pollingLogProvider.js +64 -0
- package/src/events/sort.js +44 -0
- package/src/events/txEventCache.js +71 -0
- package/src/events/types.ts +6 -0
- package/src/events/webSocketLogProvider.js +41 -0
- package/src/examples/makeTradeExample.js +80 -0
- package/src/factory/bigNum.js +390 -0
- package/src/factory/bigNum.ts +42 -13
- package/src/factory/oracleClient.js +20 -0
- package/src/idl/clearing_house.json +1609 -388
- package/src/idl/{mock_usdc_faucet.json → token_faucet.json} +46 -23
- package/src/index.ts +9 -3
- package/src/math/amm.ts +54 -55
- package/src/math/auction.js +42 -0
- package/src/math/auction.ts +5 -1
- package/src/math/bankBalance.ts +148 -2
- package/src/math/conversion.js +11 -0
- package/src/math/funding.js +248 -0
- package/src/math/margin.ts +124 -0
- package/src/math/market.ts +66 -1
- package/src/math/oracles.js +26 -0
- package/src/math/oracles.ts +42 -5
- package/src/math/orders.ts +112 -13
- package/src/math/position.ts +64 -9
- package/src/math/repeg.js +128 -0
- package/src/math/state.js +15 -0
- package/src/math/trade.js +253 -0
- package/src/math/trade.ts +23 -25
- package/src/math/utils.js +0 -1
- package/src/oracles/oracleClientCache.js +19 -0
- package/src/oracles/pythClient.js +46 -0
- package/src/oracles/quoteAssetOracleClient.js +32 -0
- package/src/oracles/switchboardClient.js +69 -0
- package/src/oracles/types.js +2 -0
- package/src/orderParams.js +20 -0
- package/src/orderParams.ts +20 -141
- package/src/slot/SlotSubscriber.js +39 -0
- package/src/slot/SlotSubscriber.ts +11 -1
- package/src/token/index.js +38 -0
- package/src/tokenFaucet.js +189 -0
- package/src/{mockUSDCFaucet.ts → tokenFaucet.ts} +82 -70
- package/src/tx/retryTxSender.ts +11 -3
- package/src/tx/types.js +2 -0
- package/src/tx/utils.js +17 -0
- package/src/tx/utils.ts +1 -1
- package/src/types.ts +236 -27
- package/src/userName.js +20 -0
- package/src/util/computeUnits.js +21 -11
- package/src/util/computeUnits.ts +1 -1
- package/src/util/getTokenAddress.js +9 -0
- package/src/util/getTokenAddress.ts +18 -0
- package/src/util/promiseTimeout.js +14 -0
- package/src/util/tps.js +27 -0
- package/src/wallet.js +35 -0
- package/tests/bn/test.ts +10 -0
- package/lib/orders.d.ts +0 -8
- package/lib/orders.js +0 -142
- package/src/orders.ts +0 -251
- package/src/util/computeUnits.js.map +0 -1
package/src/clearingHouseUser.ts
CHANGED
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
PRICE_TO_QUOTE_PRECISION,
|
|
22
22
|
MARGIN_PRECISION,
|
|
23
23
|
BANK_WEIGHT_PRECISION,
|
|
24
|
+
BANK_BALANCE_PRECISION_EXP,
|
|
24
25
|
} from './constants/numericConstants';
|
|
25
26
|
import {
|
|
26
27
|
UserAccountSubscriber,
|
|
@@ -32,17 +33,26 @@ import {
|
|
|
32
33
|
calculateBaseAssetValue,
|
|
33
34
|
calculatePositionFundingPNL,
|
|
34
35
|
calculatePositionPNL,
|
|
36
|
+
calculateUnrealizedAssetWeight,
|
|
37
|
+
calculateMarketMarginRatio,
|
|
35
38
|
PositionDirection,
|
|
36
39
|
calculateTradeSlippage,
|
|
37
40
|
BN,
|
|
38
41
|
BankAccount,
|
|
39
42
|
} from '.';
|
|
40
|
-
import {
|
|
43
|
+
import {
|
|
44
|
+
getTokenAmount,
|
|
45
|
+
calculateAssetWeight,
|
|
46
|
+
calculateLiabilityWeight,
|
|
47
|
+
} from './math/bankBalance';
|
|
48
|
+
import {
|
|
49
|
+
calculateMarginBaseAssetValue,
|
|
50
|
+
calculateWorstCaseBaseAssetAmount,
|
|
51
|
+
} from './math/margin';
|
|
41
52
|
import { OraclePriceData } from './oracles/types';
|
|
42
53
|
import { ClearingHouseUserConfig } from './clearingHouseUserConfig';
|
|
43
54
|
import { PollingUserAccountSubscriber } from './accounts/pollingUserAccountSubscriber';
|
|
44
55
|
import { WebSocketUserAccountSubscriber } from './accounts/webSocketUserAccountSubscriber';
|
|
45
|
-
|
|
46
56
|
export class ClearingHouseUser {
|
|
47
57
|
clearingHouse: ClearingHouse;
|
|
48
58
|
userAccountPublicKey: PublicKey;
|
|
@@ -124,9 +134,13 @@ export class ClearingHouseUser {
|
|
|
124
134
|
quoteAssetAmount: ZERO,
|
|
125
135
|
quoteEntryAmount: ZERO,
|
|
126
136
|
openOrders: ZERO,
|
|
127
|
-
unsettledPnl: ZERO,
|
|
128
137
|
openBids: ZERO,
|
|
129
138
|
openAsks: ZERO,
|
|
139
|
+
realizedPnl: ZERO,
|
|
140
|
+
lpShares: ZERO,
|
|
141
|
+
lastFeePerLp: ZERO,
|
|
142
|
+
lastNetBaseAssetAmountPerLp: ZERO,
|
|
143
|
+
lastNetQuoteAssetAmountPerLp: ZERO,
|
|
130
144
|
};
|
|
131
145
|
}
|
|
132
146
|
|
|
@@ -162,6 +176,98 @@ export class ClearingHouseUser {
|
|
|
162
176
|
return userAccountRPCResponse.value !== null;
|
|
163
177
|
}
|
|
164
178
|
|
|
179
|
+
/**
|
|
180
|
+
* calculates the market position if the lp position was settled
|
|
181
|
+
* @returns : userPosition
|
|
182
|
+
*/
|
|
183
|
+
public getSettledLPPosition(marketIndex: BN): [UserPosition, BN] {
|
|
184
|
+
const position = this.getUserPosition(marketIndex);
|
|
185
|
+
const market = this.clearingHouse.getMarketAccount(position.marketIndex);
|
|
186
|
+
const nShares = position.lpShares;
|
|
187
|
+
|
|
188
|
+
const deltaBaa = market.amm.marketPositionPerLp.baseAssetAmount
|
|
189
|
+
.sub(position.lastNetBaseAssetAmountPerLp)
|
|
190
|
+
.mul(nShares)
|
|
191
|
+
.div(AMM_RESERVE_PRECISION);
|
|
192
|
+
const deltaQaa = market.amm.marketPositionPerLp.quoteAssetAmount
|
|
193
|
+
.sub(position.lastNetQuoteAssetAmountPerLp)
|
|
194
|
+
.mul(nShares)
|
|
195
|
+
.div(AMM_RESERVE_PRECISION);
|
|
196
|
+
|
|
197
|
+
function sign(v: BN) {
|
|
198
|
+
const sign = { true: new BN(1), false: new BN(-1) }[
|
|
199
|
+
v.gte(ZERO).toString()
|
|
200
|
+
];
|
|
201
|
+
return sign;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const remainder = deltaBaa
|
|
205
|
+
.abs()
|
|
206
|
+
.mod(market.amm.baseAssetAmountStepSize)
|
|
207
|
+
.mul(sign(deltaBaa));
|
|
208
|
+
const _standardizedBaa = deltaBaa.sub(remainder);
|
|
209
|
+
|
|
210
|
+
let remainderBaa;
|
|
211
|
+
if (_standardizedBaa.abs().gte(market.amm.baseAssetAmountStepSize)) {
|
|
212
|
+
remainderBaa = remainder;
|
|
213
|
+
} else {
|
|
214
|
+
remainderBaa = deltaBaa;
|
|
215
|
+
}
|
|
216
|
+
const standardizedBaa = deltaBaa.sub(remainderBaa);
|
|
217
|
+
|
|
218
|
+
const reaminderPerLP = remainderBaa.mul(AMM_RESERVE_PRECISION).div(nShares);
|
|
219
|
+
|
|
220
|
+
position.baseAssetAmount = position.baseAssetAmount.add(standardizedBaa);
|
|
221
|
+
position.quoteAssetAmount = position.quoteAssetAmount.add(deltaQaa);
|
|
222
|
+
|
|
223
|
+
position.lastNetBaseAssetAmountPerLp =
|
|
224
|
+
market.amm.marketPositionPerLp.baseAssetAmount.sub(reaminderPerLP);
|
|
225
|
+
|
|
226
|
+
let updateType;
|
|
227
|
+
if (position.baseAssetAmount.eq(ZERO)) {
|
|
228
|
+
updateType = 'open';
|
|
229
|
+
} else if (sign(position.baseAssetAmount).eq(sign(deltaBaa))) {
|
|
230
|
+
updateType = 'increase';
|
|
231
|
+
} else if (position.baseAssetAmount.abs().gt(deltaBaa.abs())) {
|
|
232
|
+
updateType = 'reduce';
|
|
233
|
+
} else if (position.baseAssetAmount.abs().eq(deltaBaa.abs())) {
|
|
234
|
+
updateType = 'close';
|
|
235
|
+
} else {
|
|
236
|
+
updateType = 'flip';
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
let newQuoteEntry;
|
|
240
|
+
let pnl;
|
|
241
|
+
if (updateType == 'open' || updateType == 'increase') {
|
|
242
|
+
newQuoteEntry = position.quoteEntryAmount.add(deltaQaa);
|
|
243
|
+
pnl = 0;
|
|
244
|
+
} else if (updateType == 'reduce' || updateType == 'close') {
|
|
245
|
+
newQuoteEntry = position.quoteEntryAmount.sub(
|
|
246
|
+
position.quoteEntryAmount
|
|
247
|
+
.mul(deltaBaa.abs())
|
|
248
|
+
.div(position.baseAssetAmount.abs())
|
|
249
|
+
);
|
|
250
|
+
pnl = position.quoteEntryAmount.sub(newQuoteEntry);
|
|
251
|
+
} else {
|
|
252
|
+
newQuoteEntry = deltaQaa.sub(
|
|
253
|
+
deltaQaa.mul(position.baseAssetAmount.abs()).div(deltaBaa.abs())
|
|
254
|
+
);
|
|
255
|
+
pnl = position.quoteEntryAmount.add(deltaQaa.sub(newQuoteEntry));
|
|
256
|
+
}
|
|
257
|
+
position.quoteEntryAmount = newQuoteEntry;
|
|
258
|
+
|
|
259
|
+
if (position.baseAssetAmount.gt(ZERO)) {
|
|
260
|
+
position.lastCumulativeFundingRate = market.amm.cumulativeFundingRateLong;
|
|
261
|
+
} else if (position.baseAssetAmount.lt(ZERO)) {
|
|
262
|
+
position.lastCumulativeFundingRate =
|
|
263
|
+
market.amm.cumulativeFundingRateShort;
|
|
264
|
+
} else {
|
|
265
|
+
position.lastCumulativeFundingRate = ZERO;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
return [position, pnl];
|
|
269
|
+
}
|
|
270
|
+
|
|
165
271
|
/**
|
|
166
272
|
* calculates Buying Power = FC * MAX_LEVERAGE
|
|
167
273
|
* @returns : Precision QUOTE_PRECISION
|
|
@@ -184,81 +290,114 @@ export class ClearingHouseUser {
|
|
|
184
290
|
}
|
|
185
291
|
|
|
186
292
|
public getInitialMarginRequirement(): BN {
|
|
187
|
-
|
|
188
|
-
|
|
293
|
+
const postionMarginRequirement = this.getUserAccount().positions.reduce(
|
|
294
|
+
(marginRequirement, marketPosition) => {
|
|
189
295
|
const market = this.clearingHouse.getMarketAccount(
|
|
190
296
|
marketPosition.marketIndex
|
|
191
297
|
);
|
|
192
|
-
|
|
193
|
-
|
|
298
|
+
const worstCaseBaseAssetAmount =
|
|
299
|
+
calculateWorstCaseBaseAssetAmount(marketPosition);
|
|
300
|
+
|
|
301
|
+
const worstCaseAssetValue = worstCaseBaseAssetAmount
|
|
302
|
+
.abs()
|
|
303
|
+
.mul(this.getOracleDataForMarket(market.marketIndex).price)
|
|
304
|
+
.div(AMM_TO_QUOTE_PRECISION_RATIO.mul(MARK_PRICE_PRECISION));
|
|
305
|
+
|
|
306
|
+
const marketMarginRatio = new BN(
|
|
307
|
+
calculateMarketMarginRatio(
|
|
194
308
|
market,
|
|
195
|
-
|
|
196
|
-
|
|
309
|
+
worstCaseBaseAssetAmount.abs(),
|
|
310
|
+
'Initial'
|
|
197
311
|
)
|
|
198
|
-
.mul(new BN(market.marginRatioInitial))
|
|
199
|
-
.div(MARGIN_PRECISION)
|
|
200
312
|
);
|
|
201
|
-
|
|
202
|
-
|
|
313
|
+
return marginRequirement.add(
|
|
314
|
+
worstCaseAssetValue.mul(marketMarginRatio).div(MARGIN_PRECISION)
|
|
315
|
+
);
|
|
316
|
+
},
|
|
317
|
+
ZERO
|
|
318
|
+
);
|
|
319
|
+
|
|
320
|
+
const bankMarginRequirement = this.getBankLiabilityValue(
|
|
321
|
+
undefined,
|
|
322
|
+
'Initial'
|
|
323
|
+
);
|
|
324
|
+
|
|
325
|
+
return bankMarginRequirement.add(postionMarginRequirement);
|
|
203
326
|
}
|
|
204
327
|
|
|
205
328
|
/**
|
|
206
|
-
* @returns The
|
|
329
|
+
* @returns The maintenance margin requirement in USDC. : QUOTE_PRECISION
|
|
207
330
|
*/
|
|
208
|
-
public
|
|
331
|
+
public getMaintenanceMarginRequirement(): BN {
|
|
209
332
|
return this.getUserAccount()
|
|
210
333
|
.positions.reduce((marginRequirement, marketPosition) => {
|
|
211
334
|
const market = this.clearingHouse.getMarketAccount(
|
|
212
335
|
marketPosition.marketIndex
|
|
213
336
|
);
|
|
337
|
+
const worstCaseBaseAssetAmount =
|
|
338
|
+
calculateWorstCaseBaseAssetAmount(marketPosition);
|
|
339
|
+
|
|
340
|
+
const worstCaseAssetValue = worstCaseBaseAssetAmount
|
|
341
|
+
.abs()
|
|
342
|
+
.mul(this.getOracleDataForMarket(market.marketIndex).price)
|
|
343
|
+
.div(AMM_TO_QUOTE_PRECISION_RATIO.mul(MARK_PRICE_PRECISION));
|
|
344
|
+
|
|
214
345
|
return marginRequirement.add(
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
346
|
+
worstCaseAssetValue
|
|
347
|
+
.mul(
|
|
348
|
+
new BN(
|
|
349
|
+
calculateMarketMarginRatio(
|
|
350
|
+
market,
|
|
351
|
+
worstCaseBaseAssetAmount.abs(),
|
|
352
|
+
'Maintenance'
|
|
353
|
+
)
|
|
354
|
+
)
|
|
355
|
+
)
|
|
221
356
|
.div(MARGIN_PRECISION)
|
|
222
357
|
);
|
|
223
358
|
}, ZERO)
|
|
224
|
-
.add(this.
|
|
359
|
+
.add(this.getBankLiabilityValue(undefined, 'Maintenance'));
|
|
225
360
|
}
|
|
226
361
|
|
|
227
362
|
/**
|
|
228
363
|
* calculates unrealized position price pnl
|
|
229
364
|
* @returns : Precision QUOTE_PRECISION
|
|
230
365
|
*/
|
|
231
|
-
public getUnrealizedPNL(
|
|
366
|
+
public getUnrealizedPNL(
|
|
367
|
+
withFunding?: boolean,
|
|
368
|
+
marketIndex?: BN,
|
|
369
|
+
withWeightMarginCategory?: MarginCategory
|
|
370
|
+
): BN {
|
|
232
371
|
return this.getUserAccount()
|
|
233
372
|
.positions.filter((pos) =>
|
|
234
373
|
marketIndex ? pos.marketIndex === marketIndex : true
|
|
235
374
|
)
|
|
236
|
-
.reduce((
|
|
375
|
+
.reduce((unrealizedPnl, marketPosition) => {
|
|
237
376
|
const market = this.clearingHouse.getMarketAccount(
|
|
238
377
|
marketPosition.marketIndex
|
|
239
378
|
);
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
this.getOracleDataForMarket(market.marketIndex)
|
|
246
|
-
)
|
|
379
|
+
let positionUnrealizedPnl = calculatePositionPNL(
|
|
380
|
+
market,
|
|
381
|
+
marketPosition,
|
|
382
|
+
withFunding,
|
|
383
|
+
this.getOracleDataForMarket(market.marketIndex)
|
|
247
384
|
);
|
|
248
|
-
}, ZERO);
|
|
249
|
-
}
|
|
250
385
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
386
|
+
if (withWeightMarginCategory !== undefined) {
|
|
387
|
+
if (positionUnrealizedPnl.gt(ZERO)) {
|
|
388
|
+
positionUnrealizedPnl = positionUnrealizedPnl
|
|
389
|
+
.mul(
|
|
390
|
+
calculateUnrealizedAssetWeight(
|
|
391
|
+
market,
|
|
392
|
+
positionUnrealizedPnl,
|
|
393
|
+
withWeightMarginCategory
|
|
394
|
+
)
|
|
395
|
+
)
|
|
396
|
+
.div(new BN(BANK_WEIGHT_PRECISION));
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
return unrealizedPnl.add(positionUnrealizedPnl);
|
|
262
401
|
}, ZERO);
|
|
263
402
|
}
|
|
264
403
|
|
|
@@ -279,14 +418,18 @@ export class ClearingHouseUser {
|
|
|
279
418
|
}, ZERO);
|
|
280
419
|
}
|
|
281
420
|
|
|
282
|
-
public
|
|
421
|
+
public getBankLiabilityValue(
|
|
422
|
+
bankIndex?: BN,
|
|
423
|
+
withWeightMarginCategory?: MarginCategory
|
|
424
|
+
): BN {
|
|
283
425
|
return this.getUserAccount().bankBalances.reduce(
|
|
284
|
-
(
|
|
426
|
+
(totalLiabilityValue, bankBalance) => {
|
|
285
427
|
if (
|
|
286
428
|
bankBalance.balance.eq(ZERO) ||
|
|
287
|
-
isVariant(bankBalance.balanceType, 'deposit')
|
|
429
|
+
isVariant(bankBalance.balanceType, 'deposit') ||
|
|
430
|
+
(bankIndex !== undefined && !bankBalance.bankIndex.eq(bankIndex))
|
|
288
431
|
) {
|
|
289
|
-
return
|
|
432
|
+
return totalLiabilityValue;
|
|
290
433
|
}
|
|
291
434
|
|
|
292
435
|
// Todo this needs to account for whether it's based on initial or maintenance requirements
|
|
@@ -299,23 +442,42 @@ export class ClearingHouseUser {
|
|
|
299
442
|
bankAccount,
|
|
300
443
|
bankBalance.balanceType
|
|
301
444
|
);
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
.
|
|
308
|
-
|
|
445
|
+
|
|
446
|
+
let liabilityValue = tokenAmount
|
|
447
|
+
.mul(this.getOracleDataForBank(bankAccount.bankIndex).price)
|
|
448
|
+
.div(MARK_PRICE_PRECISION)
|
|
449
|
+
.div(
|
|
450
|
+
new BN(10).pow(
|
|
451
|
+
new BN(bankAccount.decimals).sub(BANK_BALANCE_PRECISION_EXP)
|
|
452
|
+
)
|
|
453
|
+
);
|
|
454
|
+
|
|
455
|
+
if (withWeightMarginCategory !== undefined) {
|
|
456
|
+
const weight = calculateLiabilityWeight(
|
|
457
|
+
tokenAmount,
|
|
458
|
+
bankAccount,
|
|
459
|
+
withWeightMarginCategory
|
|
460
|
+
);
|
|
461
|
+
liabilityValue = liabilityValue
|
|
462
|
+
.mul(weight)
|
|
463
|
+
.div(BANK_WEIGHT_PRECISION);
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
return totalLiabilityValue.add(liabilityValue);
|
|
309
467
|
},
|
|
310
468
|
ZERO
|
|
311
469
|
);
|
|
312
470
|
}
|
|
313
471
|
|
|
314
|
-
public
|
|
472
|
+
public getBankAssetValue(
|
|
473
|
+
bankIndex?: BN,
|
|
474
|
+
withWeightMarginCategory?: MarginCategory
|
|
475
|
+
): BN {
|
|
315
476
|
return this.getUserAccount().bankBalances.reduce(
|
|
316
477
|
(totalAssetValue, bankBalance) => {
|
|
317
478
|
if (
|
|
318
479
|
bankBalance.balance.eq(ZERO) ||
|
|
480
|
+
isVariant(bankBalance.balanceType, 'borrow') ||
|
|
319
481
|
(bankIndex !== undefined && !bankBalance.bankIndex.eq(bankIndex))
|
|
320
482
|
) {
|
|
321
483
|
return totalAssetValue;
|
|
@@ -326,65 +488,53 @@ export class ClearingHouseUser {
|
|
|
326
488
|
bankBalance.bankIndex
|
|
327
489
|
);
|
|
328
490
|
|
|
329
|
-
|
|
491
|
+
const tokenAmount = getTokenAmount(
|
|
330
492
|
bankBalance.balance,
|
|
331
493
|
bankAccount,
|
|
332
494
|
bankBalance.balanceType
|
|
333
495
|
);
|
|
334
496
|
|
|
335
|
-
|
|
336
|
-
|
|
497
|
+
let assetValue = tokenAmount
|
|
498
|
+
.mul(this.getOracleDataForBank(bankAccount.bankIndex).price)
|
|
499
|
+
.div(MARK_PRICE_PRECISION)
|
|
500
|
+
.div(
|
|
501
|
+
new BN(10).pow(
|
|
502
|
+
new BN(bankAccount.decimals).sub(BANK_BALANCE_PRECISION_EXP)
|
|
503
|
+
)
|
|
504
|
+
);
|
|
505
|
+
if (withWeightMarginCategory !== undefined) {
|
|
506
|
+
const weight = calculateAssetWeight(
|
|
507
|
+
tokenAmount,
|
|
508
|
+
bankAccount,
|
|
509
|
+
withWeightMarginCategory
|
|
510
|
+
);
|
|
511
|
+
assetValue = assetValue.mul(weight).div(BANK_WEIGHT_PRECISION);
|
|
337
512
|
}
|
|
338
513
|
|
|
339
|
-
return totalAssetValue.add(
|
|
340
|
-
tokenAmount
|
|
341
|
-
.mul(this.getOracleDataForBank(bankAccount.bankIndex).price)
|
|
342
|
-
.div(MARK_PRICE_PRECISION)
|
|
343
|
-
);
|
|
514
|
+
return totalAssetValue.add(assetValue);
|
|
344
515
|
},
|
|
345
516
|
ZERO
|
|
346
517
|
);
|
|
347
518
|
}
|
|
348
519
|
|
|
520
|
+
public getNetBankValue(withWeightMarginCategory?: MarginCategory): BN {
|
|
521
|
+
return this.getBankAssetValue(undefined, withWeightMarginCategory).sub(
|
|
522
|
+
this.getBankLiabilityValue(undefined, withWeightMarginCategory)
|
|
523
|
+
);
|
|
524
|
+
}
|
|
525
|
+
|
|
349
526
|
/**
|
|
350
527
|
* calculates TotalCollateral: collateral + unrealized pnl
|
|
351
|
-
* TODO: rename to total equity (for perpetuals swaps)
|
|
352
528
|
* @returns : Precision QUOTE_PRECISION
|
|
353
529
|
*/
|
|
354
|
-
public getTotalCollateral(): BN {
|
|
355
|
-
return this.
|
|
356
|
-
.
|
|
357
|
-
|
|
358
|
-
bankBalance.balance.eq(ZERO) ||
|
|
359
|
-
isVariant(bankBalance.balanceType, 'borrow')
|
|
360
|
-
) {
|
|
361
|
-
return totalAssetValue;
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
// Todo this needs to account for whether it's based on initial or maintenance requirements
|
|
365
|
-
const bankAccount: BankAccount = this.clearingHouse.getBankAccount(
|
|
366
|
-
bankBalance.bankIndex
|
|
367
|
-
);
|
|
368
|
-
|
|
369
|
-
const tokenAmount = getTokenAmount(
|
|
370
|
-
bankBalance.balance,
|
|
371
|
-
bankAccount,
|
|
372
|
-
bankBalance.balanceType
|
|
373
|
-
);
|
|
374
|
-
return totalAssetValue.add(
|
|
375
|
-
tokenAmount
|
|
376
|
-
.mul(this.getOracleDataForBank(bankAccount.bankIndex).price)
|
|
377
|
-
.mul(bankAccount.initialAssetWeight)
|
|
378
|
-
.div(BANK_WEIGHT_PRECISION)
|
|
379
|
-
.div(MARK_PRICE_PRECISION)
|
|
380
|
-
);
|
|
381
|
-
}, ZERO)
|
|
382
|
-
.add(this.getUnrealizedPNL(true))
|
|
383
|
-
.add(this.getUnsettledPNL());
|
|
530
|
+
public getTotalCollateral(marginCategory: MarginCategory = 'Initial'): BN {
|
|
531
|
+
return this.getBankAssetValue(undefined, marginCategory).add(
|
|
532
|
+
this.getUnrealizedPNL(true, undefined, marginCategory)
|
|
533
|
+
);
|
|
384
534
|
}
|
|
385
535
|
|
|
386
536
|
/**
|
|
387
|
-
* calculates sum of position value across all positions
|
|
537
|
+
* calculates sum of position value across all positions in margin system
|
|
388
538
|
* @returns : Precision QUOTE_PRECISION
|
|
389
539
|
*/
|
|
390
540
|
getTotalPositionValue(): BN {
|
|
@@ -393,20 +543,20 @@ export class ClearingHouseUser {
|
|
|
393
543
|
const market = this.clearingHouse.getMarketAccount(
|
|
394
544
|
marketPosition.marketIndex
|
|
395
545
|
);
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
this.getOracleDataForMarket(market.marketIndex)
|
|
401
|
-
)
|
|
546
|
+
const posVal = calculateMarginBaseAssetValue(
|
|
547
|
+
market,
|
|
548
|
+
marketPosition,
|
|
549
|
+
this.getOracleDataForMarket(market.marketIndex)
|
|
402
550
|
);
|
|
551
|
+
|
|
552
|
+
return positionValue.add(posVal);
|
|
403
553
|
},
|
|
404
554
|
ZERO
|
|
405
555
|
);
|
|
406
556
|
}
|
|
407
557
|
|
|
408
558
|
/**
|
|
409
|
-
* calculates position value
|
|
559
|
+
* calculates position value in margin system
|
|
410
560
|
* @returns : Precision QUOTE_PRECISION
|
|
411
561
|
*/
|
|
412
562
|
public getPositionValue(
|
|
@@ -418,7 +568,7 @@ export class ClearingHouseUser {
|
|
|
418
568
|
const market = this.clearingHouse.getMarketAccount(
|
|
419
569
|
userPosition.marketIndex
|
|
420
570
|
);
|
|
421
|
-
return
|
|
571
|
+
return calculateMarginBaseAssetValue(market, userPosition, oraclePriceData);
|
|
422
572
|
}
|
|
423
573
|
|
|
424
574
|
public getPositionSide(
|
|
@@ -434,12 +584,13 @@ export class ClearingHouseUser {
|
|
|
434
584
|
}
|
|
435
585
|
|
|
436
586
|
/**
|
|
437
|
-
* calculates average exit price for closing 100% of position
|
|
587
|
+
* calculates average exit price (optionally for closing up to 100% of position)
|
|
438
588
|
* @returns : Precision MARK_PRICE_PRECISION
|
|
439
589
|
*/
|
|
440
590
|
public getPositionEstimatedExitPriceAndPnl(
|
|
441
591
|
position: UserPosition,
|
|
442
|
-
amountToClose?: BN
|
|
592
|
+
amountToClose?: BN,
|
|
593
|
+
useAMMClose = false
|
|
443
594
|
): [BN, BN] {
|
|
444
595
|
const market = this.clearingHouse.getMarketAccount(position.marketIndex);
|
|
445
596
|
|
|
@@ -459,11 +610,21 @@ export class ClearingHouseUser {
|
|
|
459
610
|
} as UserPosition;
|
|
460
611
|
}
|
|
461
612
|
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
613
|
+
let baseAssetValue: BN;
|
|
614
|
+
|
|
615
|
+
if (useAMMClose) {
|
|
616
|
+
baseAssetValue = calculateBaseAssetValue(
|
|
617
|
+
market,
|
|
618
|
+
position,
|
|
619
|
+
oraclePriceData
|
|
620
|
+
);
|
|
621
|
+
} else {
|
|
622
|
+
baseAssetValue = calculateMarginBaseAssetValue(
|
|
623
|
+
market,
|
|
624
|
+
position,
|
|
625
|
+
oraclePriceData
|
|
626
|
+
);
|
|
627
|
+
}
|
|
467
628
|
if (position.baseAssetAmount.eq(ZERO)) {
|
|
468
629
|
return [ZERO, ZERO];
|
|
469
630
|
}
|
|
@@ -505,22 +666,13 @@ export class ClearingHouseUser {
|
|
|
505
666
|
category: MarginCategory = 'Initial'
|
|
506
667
|
): BN {
|
|
507
668
|
const market = this.clearingHouse.getMarketAccount(marketIndex);
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
marginRatioCategory = market.marginRatioMaintenance;
|
|
516
|
-
break;
|
|
517
|
-
case 'Partial':
|
|
518
|
-
marginRatioCategory = market.marginRatioPartial;
|
|
519
|
-
break;
|
|
520
|
-
default:
|
|
521
|
-
marginRatioCategory = market.marginRatioInitial;
|
|
522
|
-
break;
|
|
523
|
-
}
|
|
669
|
+
|
|
670
|
+
const marginRatioCategory = calculateMarketMarginRatio(
|
|
671
|
+
market,
|
|
672
|
+
// worstCaseBaseAssetAmount.abs(),
|
|
673
|
+
ZERO, // todo
|
|
674
|
+
category
|
|
675
|
+
);
|
|
524
676
|
const maxLeverage = TEN_THOUSAND.mul(TEN_THOUSAND).div(
|
|
525
677
|
new BN(marginRatioCategory)
|
|
526
678
|
);
|
|
@@ -543,7 +695,8 @@ export class ClearingHouseUser {
|
|
|
543
695
|
|
|
544
696
|
public canBeLiquidated(): [boolean, BN] {
|
|
545
697
|
const totalCollateral = this.getTotalCollateral();
|
|
546
|
-
const partialMaintenanceRequirement =
|
|
698
|
+
const partialMaintenanceRequirement =
|
|
699
|
+
this.getMaintenanceMarginRequirement();
|
|
547
700
|
const marginRatio = this.getMarginRatio();
|
|
548
701
|
const canLiquidate = totalCollateral.lt(partialMaintenanceRequirement);
|
|
549
702
|
return [canLiquidate, marginRatio];
|
|
@@ -587,8 +740,7 @@ export class ClearingHouseUser {
|
|
|
587
740
|
*/
|
|
588
741
|
public liquidationPrice(
|
|
589
742
|
marketPosition: Pick<UserPosition, 'marketIndex'>,
|
|
590
|
-
positionBaseSizeChange: BN = ZERO
|
|
591
|
-
partial = false
|
|
743
|
+
positionBaseSizeChange: BN = ZERO
|
|
592
744
|
): BN {
|
|
593
745
|
// solves formula for example canBeLiquidated below
|
|
594
746
|
|
|
@@ -622,14 +774,17 @@ export class ClearingHouseUser {
|
|
|
622
774
|
const proposedMarketPosition: UserPosition = {
|
|
623
775
|
marketIndex: marketPosition.marketIndex,
|
|
624
776
|
baseAssetAmount: proposedBaseAssetAmount,
|
|
625
|
-
lastCumulativeFundingRate:
|
|
626
|
-
currentMarketPosition.lastCumulativeFundingRate,
|
|
627
777
|
quoteAssetAmount: new BN(0),
|
|
778
|
+
lastCumulativeFundingRate: ZERO,
|
|
628
779
|
quoteEntryAmount: new BN(0),
|
|
629
780
|
openOrders: new BN(0),
|
|
630
|
-
unsettledPnl: new BN(0),
|
|
631
781
|
openBids: new BN(0),
|
|
632
782
|
openAsks: new BN(0),
|
|
783
|
+
realizedPnl: ZERO,
|
|
784
|
+
lpShares: ZERO,
|
|
785
|
+
lastFeePerLp: ZERO,
|
|
786
|
+
lastNetBaseAssetAmountPerLp: ZERO,
|
|
787
|
+
lastNetQuoteAssetAmountPerLp: ZERO,
|
|
633
788
|
};
|
|
634
789
|
|
|
635
790
|
if (proposedBaseAssetAmount.eq(ZERO)) return new BN(-1);
|
|
@@ -638,7 +793,7 @@ export class ClearingHouseUser {
|
|
|
638
793
|
proposedMarketPosition.marketIndex
|
|
639
794
|
);
|
|
640
795
|
|
|
641
|
-
const proposedMarketPositionValue =
|
|
796
|
+
const proposedMarketPositionValue = calculateMarginBaseAssetValue(
|
|
642
797
|
market,
|
|
643
798
|
proposedMarketPosition,
|
|
644
799
|
this.getOracleDataForMarket(market.marketIndex)
|
|
@@ -655,16 +810,20 @@ export class ClearingHouseUser {
|
|
|
655
810
|
const market = this.clearingHouse.getMarketAccount(
|
|
656
811
|
position.marketIndex
|
|
657
812
|
);
|
|
658
|
-
const positionValue =
|
|
813
|
+
const positionValue = calculateMarginBaseAssetValue(
|
|
659
814
|
market,
|
|
660
815
|
position,
|
|
661
816
|
this.getOracleDataForMarket(market.marketIndex)
|
|
662
817
|
);
|
|
663
818
|
const marketMarginRequirement = positionValue
|
|
664
819
|
.mul(
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
820
|
+
new BN(
|
|
821
|
+
calculateMarketMarginRatio(
|
|
822
|
+
market,
|
|
823
|
+
position.baseAssetAmount.abs(),
|
|
824
|
+
'Maintenance'
|
|
825
|
+
)
|
|
826
|
+
)
|
|
668
827
|
)
|
|
669
828
|
.div(MARGIN_PRECISION);
|
|
670
829
|
totalMarginRequirement = totalMarginRequirement.add(
|
|
@@ -692,9 +851,13 @@ export class ClearingHouseUser {
|
|
|
692
851
|
marginRequirementExcludingTargetMarket.add(
|
|
693
852
|
proposedMarketPositionValue
|
|
694
853
|
.mul(
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
854
|
+
new BN(
|
|
855
|
+
calculateMarketMarginRatio(
|
|
856
|
+
market,
|
|
857
|
+
proposedMarketPosition.baseAssetAmount.abs(),
|
|
858
|
+
'Maintenance'
|
|
859
|
+
)
|
|
860
|
+
)
|
|
698
861
|
)
|
|
699
862
|
.div(MARGIN_PRECISION)
|
|
700
863
|
);
|
|
@@ -702,9 +865,10 @@ export class ClearingHouseUser {
|
|
|
702
865
|
marginRequirementAfterTrade
|
|
703
866
|
);
|
|
704
867
|
|
|
705
|
-
const marketMaxLeverage =
|
|
706
|
-
|
|
707
|
-
|
|
868
|
+
const marketMaxLeverage = this.getMaxLeverage(
|
|
869
|
+
proposedMarketPosition.marketIndex,
|
|
870
|
+
'Maintenance'
|
|
871
|
+
);
|
|
708
872
|
|
|
709
873
|
let priceDelta;
|
|
710
874
|
if (proposedBaseAssetAmount.lt(ZERO)) {
|
|
@@ -765,11 +929,11 @@ export class ClearingHouseUser {
|
|
|
765
929
|
|
|
766
930
|
const closeBaseAmount = currentPosition.baseAssetAmount
|
|
767
931
|
.mul(closeQuoteAmount)
|
|
768
|
-
.div(currentPosition.quoteAssetAmount)
|
|
932
|
+
.div(currentPosition.quoteAssetAmount.abs())
|
|
769
933
|
.add(
|
|
770
934
|
currentPosition.baseAssetAmount
|
|
771
935
|
.mul(closeQuoteAmount)
|
|
772
|
-
.mod(currentPosition.quoteAssetAmount)
|
|
936
|
+
.mod(currentPosition.quoteAssetAmount.abs())
|
|
773
937
|
)
|
|
774
938
|
.neg();
|
|
775
939
|
|
|
@@ -777,8 +941,7 @@ export class ClearingHouseUser {
|
|
|
777
941
|
{
|
|
778
942
|
marketIndex: positionMarketIndex,
|
|
779
943
|
},
|
|
780
|
-
closeBaseAmount
|
|
781
|
-
true
|
|
944
|
+
closeBaseAmount
|
|
782
945
|
);
|
|
783
946
|
}
|
|
784
947
|
|