@drift-labs/sdk 0.2.0-master.11 → 0.2.0-master.14
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/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 +2 -0
- package/lib/admin.js +18 -0
- package/lib/clearingHouse.d.ts +24 -3
- package/lib/clearingHouse.js +352 -51
- package/lib/clearingHouseConfig.d.ts +1 -0
- package/lib/clearingHouseUser.d.ts +15 -15
- package/lib/clearingHouseUser.js +185 -73
- package/lib/clearingHouseUserStats.d.ts +17 -0
- package/lib/clearingHouseUserStats.js +36 -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 +4 -3
- package/lib/constants/numericConstants.d.ts +2 -0
- package/lib/constants/numericConstants.js +3 -1
- package/lib/events/eventList.js +3 -0
- package/lib/events/types.d.ts +2 -1
- package/lib/factory/bigNum.d.ts +1 -0
- package/lib/factory/bigNum.js +37 -11
- package/lib/idl/clearing_house.json +692 -58
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/math/amm.js +2 -2
- package/lib/math/bankBalance.d.ts +7 -1
- package/lib/math/bankBalance.js +76 -1
- 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/position.d.ts +8 -0
- package/lib/math/position.js +43 -12
- package/lib/math/trade.js +2 -2
- package/lib/orders.d.ts +1 -2
- package/lib/orders.js +2 -77
- package/lib/tokenFaucet.d.ts +1 -0
- package/lib/tokenFaucet.js +23 -12
- package/lib/tx/retryTxSender.js +9 -2
- package/lib/types.d.ts +78 -10
- package/lib/types.js +12 -0
- package/lib/util/getTokenAddress.d.ts +2 -0
- package/lib/util/getTokenAddress.js +9 -0
- package/package.json +1 -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 +619 -62
- package/src/clearingHouseConfig.ts +1 -0
- package/src/clearingHouseUser.ts +317 -105
- package/src/clearingHouseUserStats.ts +53 -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 +6 -3
- package/src/constants/markets.js +42 -0
- package/src/constants/numericConstants.js +41 -0
- package/src/constants/numericConstants.ts +3 -0
- package/src/events/eventList.ts +3 -0
- package/src/events/types.ts +2 -0
- package/src/factory/bigNum.js +37 -11
- package/src/factory/bigNum.ts +43 -13
- package/src/idl/clearing_house.json +692 -58
- package/src/index.ts +1 -0
- package/src/math/amm.ts +8 -5
- package/src/math/bankBalance.ts +147 -1
- package/src/math/margin.ts +124 -0
- package/src/math/market.ts +66 -1
- package/src/math/oracles.ts +42 -5
- package/src/math/position.ts +60 -9
- package/src/math/trade.ts +2 -2
- package/src/orders.ts +4 -157
- package/src/tokenFaucet.js +189 -0
- package/src/tokenFaucet.ts +38 -15
- package/src/tx/retryTxSender.ts +11 -3
- package/src/types.js +12 -1
- package/src/types.ts +83 -10
- package/src/{accounts/fetch.js → util/computeUnits.js} +11 -13
- package/src/util/getTokenAddress.js +9 -0
- package/src/util/getTokenAddress.ts +18 -0
- package/tests/bn/test.ts +2 -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/pda.js +0 -104
- package/src/index.js +0 -100
- package/src/math/bankBalance.js +0 -75
- package/src/math/market.js +0 -57
- package/src/math/orders.js +0 -110
- package/src/math/position.js +0 -140
- package/src/mockUSDCFaucet.js +0 -280
- package/src/orders.js +0 -134
- package/src/tx/retryTxSender.js +0 -188
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
|
+
calculateUnsettledAssetWeight,
|
|
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,26 +290,43 @@ 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
331
|
public getMaintenanceMarginRequirement(): BN {
|
|
209
332
|
return this.getUserAccount()
|
|
@@ -211,24 +334,40 @@ export class ClearingHouseUser {
|
|
|
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
|
|
@@ -237,28 +376,28 @@ export class ClearingHouseUser {
|
|
|
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 pnl0 = 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 (pnl0.gt(ZERO)) {
|
|
388
|
+
pnl0 = pnl0
|
|
389
|
+
.mul(
|
|
390
|
+
calculateUnsettledAssetWeight(
|
|
391
|
+
market,
|
|
392
|
+
pnl0,
|
|
393
|
+
withWeightMarginCategory
|
|
394
|
+
)
|
|
395
|
+
)
|
|
396
|
+
.div(new BN(BANK_WEIGHT_PRECISION));
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
return pnl.add(pnl0);
|
|
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,32 +488,46 @@ 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 {
|
|
530
|
+
public getTotalCollateral(marginCategory: MarginCategory = 'Initial'): BN {
|
|
355
531
|
return this.getUserAccount()
|
|
356
532
|
.bankBalances.reduce((totalAssetValue, bankBalance) => {
|
|
357
533
|
if (
|
|
@@ -371,20 +547,32 @@ export class ClearingHouseUser {
|
|
|
371
547
|
bankAccount,
|
|
372
548
|
bankBalance.balanceType
|
|
373
549
|
);
|
|
550
|
+
|
|
551
|
+
const weight = calculateAssetWeight(
|
|
552
|
+
tokenAmount,
|
|
553
|
+
bankAccount,
|
|
554
|
+
marginCategory
|
|
555
|
+
);
|
|
556
|
+
|
|
374
557
|
return totalAssetValue.add(
|
|
375
558
|
tokenAmount
|
|
376
559
|
.mul(this.getOracleDataForBank(bankAccount.bankIndex).price)
|
|
377
|
-
.mul(
|
|
560
|
+
.mul(weight)
|
|
378
561
|
.div(BANK_WEIGHT_PRECISION)
|
|
379
562
|
.div(MARK_PRICE_PRECISION)
|
|
563
|
+
// Adjust for decimals of bank account
|
|
564
|
+
.div(
|
|
565
|
+
new BN(10).pow(
|
|
566
|
+
new BN(bankAccount.decimals).sub(BANK_BALANCE_PRECISION_EXP)
|
|
567
|
+
)
|
|
568
|
+
)
|
|
380
569
|
);
|
|
381
570
|
}, ZERO)
|
|
382
|
-
.add(this.getUnrealizedPNL(true))
|
|
383
|
-
.add(this.getUnsettledPNL());
|
|
571
|
+
.add(this.getUnrealizedPNL(true, undefined, marginCategory));
|
|
384
572
|
}
|
|
385
573
|
|
|
386
574
|
/**
|
|
387
|
-
* calculates sum of position value across all positions
|
|
575
|
+
* calculates sum of position value across all positions in margin system
|
|
388
576
|
* @returns : Precision QUOTE_PRECISION
|
|
389
577
|
*/
|
|
390
578
|
getTotalPositionValue(): BN {
|
|
@@ -393,20 +581,20 @@ export class ClearingHouseUser {
|
|
|
393
581
|
const market = this.clearingHouse.getMarketAccount(
|
|
394
582
|
marketPosition.marketIndex
|
|
395
583
|
);
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
this.getOracleDataForMarket(market.marketIndex)
|
|
401
|
-
)
|
|
584
|
+
const posVal = calculateMarginBaseAssetValue(
|
|
585
|
+
market,
|
|
586
|
+
marketPosition,
|
|
587
|
+
this.getOracleDataForMarket(market.marketIndex)
|
|
402
588
|
);
|
|
589
|
+
|
|
590
|
+
return positionValue.add(posVal);
|
|
403
591
|
},
|
|
404
592
|
ZERO
|
|
405
593
|
);
|
|
406
594
|
}
|
|
407
595
|
|
|
408
596
|
/**
|
|
409
|
-
* calculates position value
|
|
597
|
+
* calculates position value in margin system
|
|
410
598
|
* @returns : Precision QUOTE_PRECISION
|
|
411
599
|
*/
|
|
412
600
|
public getPositionValue(
|
|
@@ -418,7 +606,7 @@ export class ClearingHouseUser {
|
|
|
418
606
|
const market = this.clearingHouse.getMarketAccount(
|
|
419
607
|
userPosition.marketIndex
|
|
420
608
|
);
|
|
421
|
-
return
|
|
609
|
+
return calculateMarginBaseAssetValue(market, userPosition, oraclePriceData);
|
|
422
610
|
}
|
|
423
611
|
|
|
424
612
|
public getPositionSide(
|
|
@@ -434,12 +622,13 @@ export class ClearingHouseUser {
|
|
|
434
622
|
}
|
|
435
623
|
|
|
436
624
|
/**
|
|
437
|
-
* calculates average exit price for closing 100% of position
|
|
625
|
+
* calculates average exit price (optionally for closing up to 100% of position)
|
|
438
626
|
* @returns : Precision MARK_PRICE_PRECISION
|
|
439
627
|
*/
|
|
440
628
|
public getPositionEstimatedExitPriceAndPnl(
|
|
441
629
|
position: UserPosition,
|
|
442
|
-
amountToClose?: BN
|
|
630
|
+
amountToClose?: BN,
|
|
631
|
+
useAMMClose = false
|
|
443
632
|
): [BN, BN] {
|
|
444
633
|
const market = this.clearingHouse.getMarketAccount(position.marketIndex);
|
|
445
634
|
|
|
@@ -459,11 +648,21 @@ export class ClearingHouseUser {
|
|
|
459
648
|
} as UserPosition;
|
|
460
649
|
}
|
|
461
650
|
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
651
|
+
let baseAssetValue: BN;
|
|
652
|
+
|
|
653
|
+
if (useAMMClose) {
|
|
654
|
+
baseAssetValue = calculateBaseAssetValue(
|
|
655
|
+
market,
|
|
656
|
+
position,
|
|
657
|
+
oraclePriceData
|
|
658
|
+
);
|
|
659
|
+
} else {
|
|
660
|
+
baseAssetValue = calculateMarginBaseAssetValue(
|
|
661
|
+
market,
|
|
662
|
+
position,
|
|
663
|
+
oraclePriceData
|
|
664
|
+
);
|
|
665
|
+
}
|
|
467
666
|
if (position.baseAssetAmount.eq(ZERO)) {
|
|
468
667
|
return [ZERO, ZERO];
|
|
469
668
|
}
|
|
@@ -505,19 +704,13 @@ export class ClearingHouseUser {
|
|
|
505
704
|
category: MarginCategory = 'Initial'
|
|
506
705
|
): BN {
|
|
507
706
|
const market = this.clearingHouse.getMarketAccount(marketIndex);
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
marginRatioCategory = market.marginRatioMaintenance;
|
|
516
|
-
break;
|
|
517
|
-
default:
|
|
518
|
-
marginRatioCategory = market.marginRatioInitial;
|
|
519
|
-
break;
|
|
520
|
-
}
|
|
707
|
+
|
|
708
|
+
const marginRatioCategory = calculateMarketMarginRatio(
|
|
709
|
+
market,
|
|
710
|
+
// worstCaseBaseAssetAmount.abs(),
|
|
711
|
+
ZERO, // todo
|
|
712
|
+
category
|
|
713
|
+
);
|
|
521
714
|
const maxLeverage = TEN_THOUSAND.mul(TEN_THOUSAND).div(
|
|
522
715
|
new BN(marginRatioCategory)
|
|
523
716
|
);
|
|
@@ -619,14 +812,17 @@ export class ClearingHouseUser {
|
|
|
619
812
|
const proposedMarketPosition: UserPosition = {
|
|
620
813
|
marketIndex: marketPosition.marketIndex,
|
|
621
814
|
baseAssetAmount: proposedBaseAssetAmount,
|
|
622
|
-
lastCumulativeFundingRate:
|
|
623
|
-
currentMarketPosition.lastCumulativeFundingRate,
|
|
624
815
|
quoteAssetAmount: new BN(0),
|
|
816
|
+
lastCumulativeFundingRate: ZERO,
|
|
625
817
|
quoteEntryAmount: new BN(0),
|
|
626
818
|
openOrders: new BN(0),
|
|
627
|
-
unsettledPnl: new BN(0),
|
|
628
819
|
openBids: new BN(0),
|
|
629
820
|
openAsks: new BN(0),
|
|
821
|
+
realizedPnl: ZERO,
|
|
822
|
+
lpShares: ZERO,
|
|
823
|
+
lastFeePerLp: ZERO,
|
|
824
|
+
lastNetBaseAssetAmountPerLp: ZERO,
|
|
825
|
+
lastNetQuoteAssetAmountPerLp: ZERO,
|
|
630
826
|
};
|
|
631
827
|
|
|
632
828
|
if (proposedBaseAssetAmount.eq(ZERO)) return new BN(-1);
|
|
@@ -635,7 +831,7 @@ export class ClearingHouseUser {
|
|
|
635
831
|
proposedMarketPosition.marketIndex
|
|
636
832
|
);
|
|
637
833
|
|
|
638
|
-
const proposedMarketPositionValue =
|
|
834
|
+
const proposedMarketPositionValue = calculateMarginBaseAssetValue(
|
|
639
835
|
market,
|
|
640
836
|
proposedMarketPosition,
|
|
641
837
|
this.getOracleDataForMarket(market.marketIndex)
|
|
@@ -652,13 +848,21 @@ export class ClearingHouseUser {
|
|
|
652
848
|
const market = this.clearingHouse.getMarketAccount(
|
|
653
849
|
position.marketIndex
|
|
654
850
|
);
|
|
655
|
-
const positionValue =
|
|
851
|
+
const positionValue = calculateMarginBaseAssetValue(
|
|
656
852
|
market,
|
|
657
853
|
position,
|
|
658
854
|
this.getOracleDataForMarket(market.marketIndex)
|
|
659
855
|
);
|
|
660
856
|
const marketMarginRequirement = positionValue
|
|
661
|
-
.mul(
|
|
857
|
+
.mul(
|
|
858
|
+
new BN(
|
|
859
|
+
calculateMarketMarginRatio(
|
|
860
|
+
market,
|
|
861
|
+
position.baseAssetAmount.abs(),
|
|
862
|
+
'Maintenance'
|
|
863
|
+
)
|
|
864
|
+
)
|
|
865
|
+
)
|
|
662
866
|
.div(MARGIN_PRECISION);
|
|
663
867
|
totalMarginRequirement = totalMarginRequirement.add(
|
|
664
868
|
marketMarginRequirement
|
|
@@ -684,7 +888,15 @@ export class ClearingHouseUser {
|
|
|
684
888
|
const marginRequirementAfterTrade =
|
|
685
889
|
marginRequirementExcludingTargetMarket.add(
|
|
686
890
|
proposedMarketPositionValue
|
|
687
|
-
.mul(
|
|
891
|
+
.mul(
|
|
892
|
+
new BN(
|
|
893
|
+
calculateMarketMarginRatio(
|
|
894
|
+
market,
|
|
895
|
+
proposedMarketPosition.baseAssetAmount.abs(),
|
|
896
|
+
'Maintenance'
|
|
897
|
+
)
|
|
898
|
+
)
|
|
899
|
+
)
|
|
688
900
|
.div(MARGIN_PRECISION)
|
|
689
901
|
);
|
|
690
902
|
const freeCollateralAfterTrade = totalCollateral.sub(
|
|
@@ -755,11 +967,11 @@ export class ClearingHouseUser {
|
|
|
755
967
|
|
|
756
968
|
const closeBaseAmount = currentPosition.baseAssetAmount
|
|
757
969
|
.mul(closeQuoteAmount)
|
|
758
|
-
.div(currentPosition.quoteAssetAmount)
|
|
970
|
+
.div(currentPosition.quoteAssetAmount.abs())
|
|
759
971
|
.add(
|
|
760
972
|
currentPosition.baseAssetAmount
|
|
761
973
|
.mul(closeQuoteAmount)
|
|
762
|
-
.mod(currentPosition.quoteAssetAmount)
|
|
974
|
+
.mod(currentPosition.quoteAssetAmount.abs())
|
|
763
975
|
)
|
|
764
976
|
.neg();
|
|
765
977
|
|