@drift-labs/sdk 0.2.0-master.2 → 0.2.0-master.22
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 +736 -200
- package/lib/clearingHouseConfig.d.ts +1 -0
- package/lib/clearingHouseUser.d.ts +24 -16
- package/lib/clearingHouseUser.js +223 -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 +1603 -377
- 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 +6 -2
- package/lib/math/orders.js +62 -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 +236 -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 +1232 -323
- package/src/clearingHouseConfig.ts +1 -0
- package/src/clearingHouseUser.ts +343 -155
- 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/sort.js +44 -0
- package/src/events/txEventCache.js +71 -0
- package/src/events/types.ts +6 -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 +1603 -377
- 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 +129 -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 +239 -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,12 +134,21 @@ 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
|
|
|
147
|
+
public getClonedPosition(position: UserPosition): UserPosition {
|
|
148
|
+
const clonedPosition = Object.assign({}, position);
|
|
149
|
+
return clonedPosition;
|
|
150
|
+
}
|
|
151
|
+
|
|
133
152
|
/**
|
|
134
153
|
* @param orderId
|
|
135
154
|
* @returns Order
|
|
@@ -162,6 +181,100 @@ export class ClearingHouseUser {
|
|
|
162
181
|
return userAccountRPCResponse.value !== null;
|
|
163
182
|
}
|
|
164
183
|
|
|
184
|
+
/**
|
|
185
|
+
* calculates the market position if the lp position was settled
|
|
186
|
+
* @returns : userPosition
|
|
187
|
+
*/
|
|
188
|
+
public getSettledLPPosition(marketIndex: BN): [UserPosition, BN, BN] {
|
|
189
|
+
const _position = this.getUserPosition(marketIndex);
|
|
190
|
+
const position = this.getClonedPosition(_position);
|
|
191
|
+
|
|
192
|
+
const market = this.clearingHouse.getMarketAccount(position.marketIndex);
|
|
193
|
+
const nShares = position.lpShares;
|
|
194
|
+
|
|
195
|
+
const deltaBaa = market.amm.marketPositionPerLp.baseAssetAmount
|
|
196
|
+
.sub(position.lastNetBaseAssetAmountPerLp)
|
|
197
|
+
.mul(nShares)
|
|
198
|
+
.div(AMM_RESERVE_PRECISION);
|
|
199
|
+
const deltaQaa = market.amm.marketPositionPerLp.quoteAssetAmount
|
|
200
|
+
.sub(position.lastNetQuoteAssetAmountPerLp)
|
|
201
|
+
.mul(nShares)
|
|
202
|
+
.div(AMM_RESERVE_PRECISION);
|
|
203
|
+
|
|
204
|
+
function sign(v: BN) {
|
|
205
|
+
const sign = { true: new BN(1), false: new BN(-1) }[
|
|
206
|
+
v.gte(ZERO).toString()
|
|
207
|
+
];
|
|
208
|
+
return sign;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const remainder = deltaBaa
|
|
212
|
+
.abs()
|
|
213
|
+
.mod(market.amm.baseAssetAmountStepSize)
|
|
214
|
+
.mul(sign(deltaBaa));
|
|
215
|
+
const _standardizedBaa = deltaBaa.sub(remainder);
|
|
216
|
+
|
|
217
|
+
let remainderBaa;
|
|
218
|
+
if (_standardizedBaa.abs().gte(market.amm.baseAssetAmountStepSize)) {
|
|
219
|
+
remainderBaa = remainder;
|
|
220
|
+
} else {
|
|
221
|
+
remainderBaa = deltaBaa;
|
|
222
|
+
}
|
|
223
|
+
const standardizedBaa = deltaBaa.sub(remainderBaa);
|
|
224
|
+
|
|
225
|
+
const reaminderPerLP = remainderBaa.mul(AMM_RESERVE_PRECISION).div(nShares);
|
|
226
|
+
|
|
227
|
+
position.baseAssetAmount = position.baseAssetAmount.add(standardizedBaa);
|
|
228
|
+
position.quoteAssetAmount = position.quoteAssetAmount.add(deltaQaa);
|
|
229
|
+
|
|
230
|
+
position.lastNetBaseAssetAmountPerLp =
|
|
231
|
+
market.amm.marketPositionPerLp.baseAssetAmount.sub(reaminderPerLP);
|
|
232
|
+
|
|
233
|
+
let updateType;
|
|
234
|
+
if (position.baseAssetAmount.eq(ZERO)) {
|
|
235
|
+
updateType = 'open';
|
|
236
|
+
} else if (sign(position.baseAssetAmount).eq(sign(deltaBaa))) {
|
|
237
|
+
updateType = 'increase';
|
|
238
|
+
} else if (position.baseAssetAmount.abs().gt(deltaBaa.abs())) {
|
|
239
|
+
updateType = 'reduce';
|
|
240
|
+
} else if (position.baseAssetAmount.abs().eq(deltaBaa.abs())) {
|
|
241
|
+
updateType = 'close';
|
|
242
|
+
} else {
|
|
243
|
+
updateType = 'flip';
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
let newQuoteEntry;
|
|
247
|
+
let pnl;
|
|
248
|
+
if (updateType == 'open' || updateType == 'increase') {
|
|
249
|
+
newQuoteEntry = position.quoteEntryAmount.add(deltaQaa);
|
|
250
|
+
pnl = 0;
|
|
251
|
+
} else if (updateType == 'reduce' || updateType == 'close') {
|
|
252
|
+
newQuoteEntry = position.quoteEntryAmount.sub(
|
|
253
|
+
position.quoteEntryAmount
|
|
254
|
+
.mul(deltaBaa.abs())
|
|
255
|
+
.div(position.baseAssetAmount.abs())
|
|
256
|
+
);
|
|
257
|
+
pnl = position.quoteEntryAmount.sub(newQuoteEntry);
|
|
258
|
+
} else {
|
|
259
|
+
newQuoteEntry = deltaQaa.sub(
|
|
260
|
+
deltaQaa.mul(position.baseAssetAmount.abs()).div(deltaBaa.abs())
|
|
261
|
+
);
|
|
262
|
+
pnl = position.quoteEntryAmount.add(deltaQaa.sub(newQuoteEntry));
|
|
263
|
+
}
|
|
264
|
+
position.quoteEntryAmount = newQuoteEntry;
|
|
265
|
+
|
|
266
|
+
if (position.baseAssetAmount.gt(ZERO)) {
|
|
267
|
+
position.lastCumulativeFundingRate = market.amm.cumulativeFundingRateLong;
|
|
268
|
+
} else if (position.baseAssetAmount.lt(ZERO)) {
|
|
269
|
+
position.lastCumulativeFundingRate =
|
|
270
|
+
market.amm.cumulativeFundingRateShort;
|
|
271
|
+
} else {
|
|
272
|
+
position.lastCumulativeFundingRate = ZERO;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
return [position, remainderBaa, pnl];
|
|
276
|
+
}
|
|
277
|
+
|
|
165
278
|
/**
|
|
166
279
|
* calculates Buying Power = FC * MAX_LEVERAGE
|
|
167
280
|
* @returns : Precision QUOTE_PRECISION
|
|
@@ -183,82 +296,133 @@ export class ClearingHouseUser {
|
|
|
183
296
|
return freeCollateral.gte(ZERO) ? freeCollateral : ZERO;
|
|
184
297
|
}
|
|
185
298
|
|
|
186
|
-
|
|
299
|
+
/**
|
|
300
|
+
* @returns The margin requirement of a certain type (Initial or Maintenance) in USDC. : QUOTE_PRECISION
|
|
301
|
+
*/
|
|
302
|
+
public getMarginRequirement(type: MarginCategory): BN {
|
|
187
303
|
return this.getUserAccount()
|
|
188
304
|
.positions.reduce((marginRequirement, marketPosition) => {
|
|
189
305
|
const market = this.clearingHouse.getMarketAccount(
|
|
190
306
|
marketPosition.marketIndex
|
|
191
307
|
);
|
|
308
|
+
|
|
309
|
+
if (marketPosition.lpShares.gt(ZERO)) {
|
|
310
|
+
// is an lp
|
|
311
|
+
// clone so we dont mutate the position
|
|
312
|
+
marketPosition = this.getClonedPosition(marketPosition);
|
|
313
|
+
|
|
314
|
+
// settle position
|
|
315
|
+
const [settledPosition, dustBaa, _] = this.getSettledLPPosition(
|
|
316
|
+
market.marketIndex
|
|
317
|
+
);
|
|
318
|
+
marketPosition.baseAssetAmount =
|
|
319
|
+
settledPosition.baseAssetAmount.add(dustBaa);
|
|
320
|
+
marketPosition.quoteAssetAmount = settledPosition.quoteAssetAmount;
|
|
321
|
+
|
|
322
|
+
// open orders
|
|
323
|
+
let openAsks;
|
|
324
|
+
if (market.amm.maxBaseAssetReserve > market.amm.baseAssetReserve) {
|
|
325
|
+
openAsks = market.amm.maxBaseAssetReserve
|
|
326
|
+
.sub(market.amm.baseAssetReserve)
|
|
327
|
+
.mul(marketPosition.lpShares)
|
|
328
|
+
.div(market.amm.sqrtK)
|
|
329
|
+
.mul(new BN(-1));
|
|
330
|
+
} else {
|
|
331
|
+
openAsks = ZERO;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
let openBids;
|
|
335
|
+
if (market.amm.minBaseAssetReserve < market.amm.baseAssetReserve) {
|
|
336
|
+
openBids = market.amm.baseAssetReserve
|
|
337
|
+
.sub(market.amm.minBaseAssetReserve)
|
|
338
|
+
.mul(marketPosition.lpShares)
|
|
339
|
+
.div(market.amm.sqrtK);
|
|
340
|
+
} else {
|
|
341
|
+
openBids = ZERO;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
marketPosition.openAsks = marketPosition.openAsks.add(openAsks);
|
|
345
|
+
marketPosition.openBids = marketPosition.openBids.add(openBids);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
const worstCaseBaseAssetAmount =
|
|
349
|
+
calculateWorstCaseBaseAssetAmount(marketPosition);
|
|
350
|
+
|
|
351
|
+
const worstCaseAssetValue = worstCaseBaseAssetAmount
|
|
352
|
+
.abs()
|
|
353
|
+
.mul(this.getOracleDataForMarket(market.marketIndex).price)
|
|
354
|
+
.div(AMM_TO_QUOTE_PRECISION_RATIO.mul(MARK_PRICE_PRECISION));
|
|
355
|
+
|
|
192
356
|
return marginRequirement.add(
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
357
|
+
worstCaseAssetValue
|
|
358
|
+
.mul(
|
|
359
|
+
new BN(
|
|
360
|
+
calculateMarketMarginRatio(
|
|
361
|
+
market,
|
|
362
|
+
worstCaseBaseAssetAmount.abs(),
|
|
363
|
+
type
|
|
364
|
+
)
|
|
365
|
+
)
|
|
366
|
+
)
|
|
199
367
|
.div(MARGIN_PRECISION)
|
|
200
368
|
);
|
|
201
369
|
}, ZERO)
|
|
202
|
-
.add(this.
|
|
370
|
+
.add(this.getBankLiabilityValue(undefined, type));
|
|
203
371
|
}
|
|
204
372
|
|
|
205
373
|
/**
|
|
206
|
-
* @returns The
|
|
374
|
+
* @returns The initial margin requirement in USDC. : QUOTE_PRECISION
|
|
207
375
|
*/
|
|
208
|
-
public
|
|
209
|
-
return this.
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
marketPosition,
|
|
218
|
-
this.getOracleDataForMarket(market.marketIndex)
|
|
219
|
-
)
|
|
220
|
-
.mul(new BN(market.marginRatioPartial))
|
|
221
|
-
.div(MARGIN_PRECISION)
|
|
222
|
-
);
|
|
223
|
-
}, ZERO)
|
|
224
|
-
.add(this.getTotalLiability());
|
|
376
|
+
public getInitialMarginRequirement(): BN {
|
|
377
|
+
return this.getMarginRequirement('Initial');
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* @returns The maintenance margin requirement in USDC. : QUOTE_PRECISION
|
|
382
|
+
*/
|
|
383
|
+
public getMaintenanceMarginRequirement(): BN {
|
|
384
|
+
return this.getMarginRequirement('Maintenance');
|
|
225
385
|
}
|
|
226
386
|
|
|
227
387
|
/**
|
|
228
388
|
* calculates unrealized position price pnl
|
|
229
389
|
* @returns : Precision QUOTE_PRECISION
|
|
230
390
|
*/
|
|
231
|
-
public getUnrealizedPNL(
|
|
391
|
+
public getUnrealizedPNL(
|
|
392
|
+
withFunding?: boolean,
|
|
393
|
+
marketIndex?: BN,
|
|
394
|
+
withWeightMarginCategory?: MarginCategory
|
|
395
|
+
): BN {
|
|
232
396
|
return this.getUserAccount()
|
|
233
397
|
.positions.filter((pos) =>
|
|
234
398
|
marketIndex ? pos.marketIndex === marketIndex : true
|
|
235
399
|
)
|
|
236
|
-
.reduce((
|
|
400
|
+
.reduce((unrealizedPnl, marketPosition) => {
|
|
237
401
|
const market = this.clearingHouse.getMarketAccount(
|
|
238
402
|
marketPosition.marketIndex
|
|
239
403
|
);
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
this.getOracleDataForMarket(market.marketIndex)
|
|
246
|
-
)
|
|
404
|
+
let positionUnrealizedPnl = calculatePositionPNL(
|
|
405
|
+
market,
|
|
406
|
+
marketPosition,
|
|
407
|
+
withFunding,
|
|
408
|
+
this.getOracleDataForMarket(market.marketIndex)
|
|
247
409
|
);
|
|
248
|
-
}, ZERO);
|
|
249
|
-
}
|
|
250
410
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
411
|
+
if (withWeightMarginCategory !== undefined) {
|
|
412
|
+
if (positionUnrealizedPnl.gt(ZERO)) {
|
|
413
|
+
positionUnrealizedPnl = positionUnrealizedPnl
|
|
414
|
+
.mul(
|
|
415
|
+
calculateUnrealizedAssetWeight(
|
|
416
|
+
market,
|
|
417
|
+
positionUnrealizedPnl,
|
|
418
|
+
withWeightMarginCategory
|
|
419
|
+
)
|
|
420
|
+
)
|
|
421
|
+
.div(new BN(BANK_WEIGHT_PRECISION));
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
return unrealizedPnl.add(positionUnrealizedPnl);
|
|
262
426
|
}, ZERO);
|
|
263
427
|
}
|
|
264
428
|
|
|
@@ -279,14 +443,18 @@ export class ClearingHouseUser {
|
|
|
279
443
|
}, ZERO);
|
|
280
444
|
}
|
|
281
445
|
|
|
282
|
-
public
|
|
446
|
+
public getBankLiabilityValue(
|
|
447
|
+
bankIndex?: BN,
|
|
448
|
+
withWeightMarginCategory?: MarginCategory
|
|
449
|
+
): BN {
|
|
283
450
|
return this.getUserAccount().bankBalances.reduce(
|
|
284
|
-
(
|
|
451
|
+
(totalLiabilityValue, bankBalance) => {
|
|
285
452
|
if (
|
|
286
453
|
bankBalance.balance.eq(ZERO) ||
|
|
287
|
-
isVariant(bankBalance.balanceType, 'deposit')
|
|
454
|
+
isVariant(bankBalance.balanceType, 'deposit') ||
|
|
455
|
+
(bankIndex !== undefined && !bankBalance.bankIndex.eq(bankIndex))
|
|
288
456
|
) {
|
|
289
|
-
return
|
|
457
|
+
return totalLiabilityValue;
|
|
290
458
|
}
|
|
291
459
|
|
|
292
460
|
// Todo this needs to account for whether it's based on initial or maintenance requirements
|
|
@@ -299,23 +467,42 @@ export class ClearingHouseUser {
|
|
|
299
467
|
bankAccount,
|
|
300
468
|
bankBalance.balanceType
|
|
301
469
|
);
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
.
|
|
308
|
-
|
|
470
|
+
|
|
471
|
+
let liabilityValue = tokenAmount
|
|
472
|
+
.mul(this.getOracleDataForBank(bankAccount.bankIndex).price)
|
|
473
|
+
.div(MARK_PRICE_PRECISION)
|
|
474
|
+
.div(
|
|
475
|
+
new BN(10).pow(
|
|
476
|
+
new BN(bankAccount.decimals).sub(BANK_BALANCE_PRECISION_EXP)
|
|
477
|
+
)
|
|
478
|
+
);
|
|
479
|
+
|
|
480
|
+
if (withWeightMarginCategory !== undefined) {
|
|
481
|
+
const weight = calculateLiabilityWeight(
|
|
482
|
+
tokenAmount,
|
|
483
|
+
bankAccount,
|
|
484
|
+
withWeightMarginCategory
|
|
485
|
+
);
|
|
486
|
+
liabilityValue = liabilityValue
|
|
487
|
+
.mul(weight)
|
|
488
|
+
.div(BANK_WEIGHT_PRECISION);
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
return totalLiabilityValue.add(liabilityValue);
|
|
309
492
|
},
|
|
310
493
|
ZERO
|
|
311
494
|
);
|
|
312
495
|
}
|
|
313
496
|
|
|
314
|
-
public
|
|
497
|
+
public getBankAssetValue(
|
|
498
|
+
bankIndex?: BN,
|
|
499
|
+
withWeightMarginCategory?: MarginCategory
|
|
500
|
+
): BN {
|
|
315
501
|
return this.getUserAccount().bankBalances.reduce(
|
|
316
502
|
(totalAssetValue, bankBalance) => {
|
|
317
503
|
if (
|
|
318
504
|
bankBalance.balance.eq(ZERO) ||
|
|
505
|
+
isVariant(bankBalance.balanceType, 'borrow') ||
|
|
319
506
|
(bankIndex !== undefined && !bankBalance.bankIndex.eq(bankIndex))
|
|
320
507
|
) {
|
|
321
508
|
return totalAssetValue;
|
|
@@ -326,65 +513,53 @@ export class ClearingHouseUser {
|
|
|
326
513
|
bankBalance.bankIndex
|
|
327
514
|
);
|
|
328
515
|
|
|
329
|
-
|
|
516
|
+
const tokenAmount = getTokenAmount(
|
|
330
517
|
bankBalance.balance,
|
|
331
518
|
bankAccount,
|
|
332
519
|
bankBalance.balanceType
|
|
333
520
|
);
|
|
334
521
|
|
|
335
|
-
|
|
336
|
-
|
|
522
|
+
let assetValue = tokenAmount
|
|
523
|
+
.mul(this.getOracleDataForBank(bankAccount.bankIndex).price)
|
|
524
|
+
.div(MARK_PRICE_PRECISION)
|
|
525
|
+
.div(
|
|
526
|
+
new BN(10).pow(
|
|
527
|
+
new BN(bankAccount.decimals).sub(BANK_BALANCE_PRECISION_EXP)
|
|
528
|
+
)
|
|
529
|
+
);
|
|
530
|
+
if (withWeightMarginCategory !== undefined) {
|
|
531
|
+
const weight = calculateAssetWeight(
|
|
532
|
+
tokenAmount,
|
|
533
|
+
bankAccount,
|
|
534
|
+
withWeightMarginCategory
|
|
535
|
+
);
|
|
536
|
+
assetValue = assetValue.mul(weight).div(BANK_WEIGHT_PRECISION);
|
|
337
537
|
}
|
|
338
538
|
|
|
339
|
-
return totalAssetValue.add(
|
|
340
|
-
tokenAmount
|
|
341
|
-
.mul(this.getOracleDataForBank(bankAccount.bankIndex).price)
|
|
342
|
-
.div(MARK_PRICE_PRECISION)
|
|
343
|
-
);
|
|
539
|
+
return totalAssetValue.add(assetValue);
|
|
344
540
|
},
|
|
345
541
|
ZERO
|
|
346
542
|
);
|
|
347
543
|
}
|
|
348
544
|
|
|
545
|
+
public getNetBankValue(withWeightMarginCategory?: MarginCategory): BN {
|
|
546
|
+
return this.getBankAssetValue(undefined, withWeightMarginCategory).sub(
|
|
547
|
+
this.getBankLiabilityValue(undefined, withWeightMarginCategory)
|
|
548
|
+
);
|
|
549
|
+
}
|
|
550
|
+
|
|
349
551
|
/**
|
|
350
552
|
* calculates TotalCollateral: collateral + unrealized pnl
|
|
351
|
-
* TODO: rename to total equity (for perpetuals swaps)
|
|
352
553
|
* @returns : Precision QUOTE_PRECISION
|
|
353
554
|
*/
|
|
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());
|
|
555
|
+
public getTotalCollateral(marginCategory: MarginCategory = 'Initial'): BN {
|
|
556
|
+
return this.getBankAssetValue(undefined, marginCategory).add(
|
|
557
|
+
this.getUnrealizedPNL(true, undefined, marginCategory)
|
|
558
|
+
);
|
|
384
559
|
}
|
|
385
560
|
|
|
386
561
|
/**
|
|
387
|
-
* calculates sum of position value across all positions
|
|
562
|
+
* calculates sum of position value across all positions in margin system
|
|
388
563
|
* @returns : Precision QUOTE_PRECISION
|
|
389
564
|
*/
|
|
390
565
|
getTotalPositionValue(): BN {
|
|
@@ -393,20 +568,20 @@ export class ClearingHouseUser {
|
|
|
393
568
|
const market = this.clearingHouse.getMarketAccount(
|
|
394
569
|
marketPosition.marketIndex
|
|
395
570
|
);
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
this.getOracleDataForMarket(market.marketIndex)
|
|
401
|
-
)
|
|
571
|
+
const posVal = calculateMarginBaseAssetValue(
|
|
572
|
+
market,
|
|
573
|
+
marketPosition,
|
|
574
|
+
this.getOracleDataForMarket(market.marketIndex)
|
|
402
575
|
);
|
|
576
|
+
|
|
577
|
+
return positionValue.add(posVal);
|
|
403
578
|
},
|
|
404
579
|
ZERO
|
|
405
580
|
);
|
|
406
581
|
}
|
|
407
582
|
|
|
408
583
|
/**
|
|
409
|
-
* calculates position value
|
|
584
|
+
* calculates position value in margin system
|
|
410
585
|
* @returns : Precision QUOTE_PRECISION
|
|
411
586
|
*/
|
|
412
587
|
public getPositionValue(
|
|
@@ -418,7 +593,7 @@ export class ClearingHouseUser {
|
|
|
418
593
|
const market = this.clearingHouse.getMarketAccount(
|
|
419
594
|
userPosition.marketIndex
|
|
420
595
|
);
|
|
421
|
-
return
|
|
596
|
+
return calculateMarginBaseAssetValue(market, userPosition, oraclePriceData);
|
|
422
597
|
}
|
|
423
598
|
|
|
424
599
|
public getPositionSide(
|
|
@@ -434,12 +609,13 @@ export class ClearingHouseUser {
|
|
|
434
609
|
}
|
|
435
610
|
|
|
436
611
|
/**
|
|
437
|
-
* calculates average exit price for closing 100% of position
|
|
612
|
+
* calculates average exit price (optionally for closing up to 100% of position)
|
|
438
613
|
* @returns : Precision MARK_PRICE_PRECISION
|
|
439
614
|
*/
|
|
440
615
|
public getPositionEstimatedExitPriceAndPnl(
|
|
441
616
|
position: UserPosition,
|
|
442
|
-
amountToClose?: BN
|
|
617
|
+
amountToClose?: BN,
|
|
618
|
+
useAMMClose = false
|
|
443
619
|
): [BN, BN] {
|
|
444
620
|
const market = this.clearingHouse.getMarketAccount(position.marketIndex);
|
|
445
621
|
|
|
@@ -459,11 +635,21 @@ export class ClearingHouseUser {
|
|
|
459
635
|
} as UserPosition;
|
|
460
636
|
}
|
|
461
637
|
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
638
|
+
let baseAssetValue: BN;
|
|
639
|
+
|
|
640
|
+
if (useAMMClose) {
|
|
641
|
+
baseAssetValue = calculateBaseAssetValue(
|
|
642
|
+
market,
|
|
643
|
+
position,
|
|
644
|
+
oraclePriceData
|
|
645
|
+
);
|
|
646
|
+
} else {
|
|
647
|
+
baseAssetValue = calculateMarginBaseAssetValue(
|
|
648
|
+
market,
|
|
649
|
+
position,
|
|
650
|
+
oraclePriceData
|
|
651
|
+
);
|
|
652
|
+
}
|
|
467
653
|
if (position.baseAssetAmount.eq(ZERO)) {
|
|
468
654
|
return [ZERO, ZERO];
|
|
469
655
|
}
|
|
@@ -505,22 +691,13 @@ export class ClearingHouseUser {
|
|
|
505
691
|
category: MarginCategory = 'Initial'
|
|
506
692
|
): BN {
|
|
507
693
|
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
|
-
}
|
|
694
|
+
|
|
695
|
+
const marginRatioCategory = calculateMarketMarginRatio(
|
|
696
|
+
market,
|
|
697
|
+
// worstCaseBaseAssetAmount.abs(),
|
|
698
|
+
ZERO, // todo
|
|
699
|
+
category
|
|
700
|
+
);
|
|
524
701
|
const maxLeverage = TEN_THOUSAND.mul(TEN_THOUSAND).div(
|
|
525
702
|
new BN(marginRatioCategory)
|
|
526
703
|
);
|
|
@@ -543,7 +720,8 @@ export class ClearingHouseUser {
|
|
|
543
720
|
|
|
544
721
|
public canBeLiquidated(): [boolean, BN] {
|
|
545
722
|
const totalCollateral = this.getTotalCollateral();
|
|
546
|
-
const partialMaintenanceRequirement =
|
|
723
|
+
const partialMaintenanceRequirement =
|
|
724
|
+
this.getMaintenanceMarginRequirement();
|
|
547
725
|
const marginRatio = this.getMarginRatio();
|
|
548
726
|
const canLiquidate = totalCollateral.lt(partialMaintenanceRequirement);
|
|
549
727
|
return [canLiquidate, marginRatio];
|
|
@@ -587,8 +765,7 @@ export class ClearingHouseUser {
|
|
|
587
765
|
*/
|
|
588
766
|
public liquidationPrice(
|
|
589
767
|
marketPosition: Pick<UserPosition, 'marketIndex'>,
|
|
590
|
-
positionBaseSizeChange: BN = ZERO
|
|
591
|
-
partial = false
|
|
768
|
+
positionBaseSizeChange: BN = ZERO
|
|
592
769
|
): BN {
|
|
593
770
|
// solves formula for example canBeLiquidated below
|
|
594
771
|
|
|
@@ -622,14 +799,17 @@ export class ClearingHouseUser {
|
|
|
622
799
|
const proposedMarketPosition: UserPosition = {
|
|
623
800
|
marketIndex: marketPosition.marketIndex,
|
|
624
801
|
baseAssetAmount: proposedBaseAssetAmount,
|
|
625
|
-
lastCumulativeFundingRate:
|
|
626
|
-
currentMarketPosition.lastCumulativeFundingRate,
|
|
627
802
|
quoteAssetAmount: new BN(0),
|
|
803
|
+
lastCumulativeFundingRate: ZERO,
|
|
628
804
|
quoteEntryAmount: new BN(0),
|
|
629
805
|
openOrders: new BN(0),
|
|
630
|
-
unsettledPnl: new BN(0),
|
|
631
806
|
openBids: new BN(0),
|
|
632
807
|
openAsks: new BN(0),
|
|
808
|
+
realizedPnl: ZERO,
|
|
809
|
+
lpShares: ZERO,
|
|
810
|
+
lastFeePerLp: ZERO,
|
|
811
|
+
lastNetBaseAssetAmountPerLp: ZERO,
|
|
812
|
+
lastNetQuoteAssetAmountPerLp: ZERO,
|
|
633
813
|
};
|
|
634
814
|
|
|
635
815
|
if (proposedBaseAssetAmount.eq(ZERO)) return new BN(-1);
|
|
@@ -638,7 +818,7 @@ export class ClearingHouseUser {
|
|
|
638
818
|
proposedMarketPosition.marketIndex
|
|
639
819
|
);
|
|
640
820
|
|
|
641
|
-
const proposedMarketPositionValue =
|
|
821
|
+
const proposedMarketPositionValue = calculateMarginBaseAssetValue(
|
|
642
822
|
market,
|
|
643
823
|
proposedMarketPosition,
|
|
644
824
|
this.getOracleDataForMarket(market.marketIndex)
|
|
@@ -655,16 +835,20 @@ export class ClearingHouseUser {
|
|
|
655
835
|
const market = this.clearingHouse.getMarketAccount(
|
|
656
836
|
position.marketIndex
|
|
657
837
|
);
|
|
658
|
-
const positionValue =
|
|
838
|
+
const positionValue = calculateMarginBaseAssetValue(
|
|
659
839
|
market,
|
|
660
840
|
position,
|
|
661
841
|
this.getOracleDataForMarket(market.marketIndex)
|
|
662
842
|
);
|
|
663
843
|
const marketMarginRequirement = positionValue
|
|
664
844
|
.mul(
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
845
|
+
new BN(
|
|
846
|
+
calculateMarketMarginRatio(
|
|
847
|
+
market,
|
|
848
|
+
position.baseAssetAmount.abs(),
|
|
849
|
+
'Maintenance'
|
|
850
|
+
)
|
|
851
|
+
)
|
|
668
852
|
)
|
|
669
853
|
.div(MARGIN_PRECISION);
|
|
670
854
|
totalMarginRequirement = totalMarginRequirement.add(
|
|
@@ -692,9 +876,13 @@ export class ClearingHouseUser {
|
|
|
692
876
|
marginRequirementExcludingTargetMarket.add(
|
|
693
877
|
proposedMarketPositionValue
|
|
694
878
|
.mul(
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
879
|
+
new BN(
|
|
880
|
+
calculateMarketMarginRatio(
|
|
881
|
+
market,
|
|
882
|
+
proposedMarketPosition.baseAssetAmount.abs(),
|
|
883
|
+
'Maintenance'
|
|
884
|
+
)
|
|
885
|
+
)
|
|
698
886
|
)
|
|
699
887
|
.div(MARGIN_PRECISION)
|
|
700
888
|
);
|
|
@@ -702,9 +890,10 @@ export class ClearingHouseUser {
|
|
|
702
890
|
marginRequirementAfterTrade
|
|
703
891
|
);
|
|
704
892
|
|
|
705
|
-
const marketMaxLeverage =
|
|
706
|
-
|
|
707
|
-
|
|
893
|
+
const marketMaxLeverage = this.getMaxLeverage(
|
|
894
|
+
proposedMarketPosition.marketIndex,
|
|
895
|
+
'Maintenance'
|
|
896
|
+
);
|
|
708
897
|
|
|
709
898
|
let priceDelta;
|
|
710
899
|
if (proposedBaseAssetAmount.lt(ZERO)) {
|
|
@@ -765,11 +954,11 @@ export class ClearingHouseUser {
|
|
|
765
954
|
|
|
766
955
|
const closeBaseAmount = currentPosition.baseAssetAmount
|
|
767
956
|
.mul(closeQuoteAmount)
|
|
768
|
-
.div(currentPosition.quoteAssetAmount)
|
|
957
|
+
.div(currentPosition.quoteAssetAmount.abs())
|
|
769
958
|
.add(
|
|
770
959
|
currentPosition.baseAssetAmount
|
|
771
960
|
.mul(closeQuoteAmount)
|
|
772
|
-
.mod(currentPosition.quoteAssetAmount)
|
|
961
|
+
.mod(currentPosition.quoteAssetAmount.abs())
|
|
773
962
|
)
|
|
774
963
|
.neg();
|
|
775
964
|
|
|
@@ -777,8 +966,7 @@ export class ClearingHouseUser {
|
|
|
777
966
|
{
|
|
778
967
|
marketIndex: positionMarketIndex,
|
|
779
968
|
},
|
|
780
|
-
closeBaseAmount
|
|
781
|
-
true
|
|
969
|
+
closeBaseAmount
|
|
782
970
|
);
|
|
783
971
|
}
|
|
784
972
|
|