@drift-labs/sdk 0.2.0-master.25 → 0.2.0-master.27
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/pollingClearingHouseAccountSubscriber.d.ts +14 -13
- package/lib/accounts/pollingClearingHouseAccountSubscriber.js +30 -27
- package/lib/accounts/types.d.ts +9 -9
- package/lib/accounts/webSocketClearingHouseAccountSubscriber.d.ts +15 -14
- package/lib/accounts/webSocketClearingHouseAccountSubscriber.js +38 -34
- package/lib/addresses/pda.d.ts +7 -6
- package/lib/addresses/pda.js +31 -27
- package/lib/admin.d.ts +13 -7
- package/lib/admin.js +111 -44
- package/lib/clearingHouse.d.ts +71 -42
- package/lib/clearingHouse.js +767 -278
- package/lib/clearingHouseConfig.d.ts +2 -2
- package/lib/clearingHouseUser.d.ts +24 -22
- package/lib/clearingHouseUser.js +273 -177
- package/lib/config.d.ts +7 -7
- package/lib/config.js +21 -21
- package/lib/constants/numericConstants.d.ts +12 -12
- package/lib/constants/numericConstants.js +13 -13
- package/lib/constants/{markets.d.ts → perpMarkets.d.ts} +5 -5
- package/lib/constants/{markets.js → perpMarkets.js} +4 -4
- package/lib/constants/{banks.d.ts → spotMarkets.d.ts} +6 -6
- package/lib/constants/{banks.js → spotMarkets.js} +16 -16
- package/lib/dlob/DLOB.d.ts +73 -0
- package/lib/dlob/DLOB.js +557 -0
- package/lib/dlob/DLOBNode.d.ts +52 -0
- package/lib/dlob/DLOBNode.js +82 -0
- package/lib/dlob/NodeList.d.ts +26 -0
- package/lib/dlob/NodeList.js +138 -0
- package/lib/events/types.d.ts +2 -1
- package/lib/events/types.js +1 -0
- package/lib/examples/makeTradeExample.js +7 -7
- package/lib/idl/clearing_house.json +1152 -503
- package/lib/index.d.ts +10 -3
- package/lib/index.js +10 -3
- package/lib/math/amm.d.ts +2 -2
- package/lib/math/amm.js +1 -1
- package/lib/math/funding.d.ts +6 -6
- package/lib/math/funding.js +2 -1
- package/lib/math/margin.d.ts +4 -4
- package/lib/math/margin.js +18 -11
- package/lib/math/market.d.ts +11 -10
- package/lib/math/market.js +30 -7
- package/lib/math/oracles.d.ts +2 -1
- package/lib/math/oracles.js +11 -1
- package/lib/math/orders.d.ts +6 -6
- package/lib/math/orders.js +31 -16
- package/lib/math/position.d.ts +13 -13
- package/lib/math/position.js +19 -19
- package/lib/math/spotBalance.d.ts +22 -0
- package/lib/math/spotBalance.js +193 -0
- package/lib/math/spotMarket.d.ts +4 -0
- package/lib/math/spotMarket.js +8 -0
- package/lib/math/spotPosition.d.ts +6 -0
- package/lib/math/spotPosition.js +23 -0
- package/lib/math/state.js +2 -2
- package/lib/math/trade.d.ts +4 -4
- package/lib/orderParams.d.ts +4 -4
- package/lib/orderParams.js +12 -4
- package/lib/serum/serumSubscriber.d.ts +23 -0
- package/lib/serum/serumSubscriber.js +41 -0
- package/lib/serum/types.d.ts +11 -0
- package/lib/serum/types.js +2 -0
- package/lib/tx/retryTxSender.d.ts +1 -1
- package/lib/tx/retryTxSender.js +4 -2
- package/lib/tx/types.d.ts +1 -1
- package/lib/types.d.ts +148 -57
- package/lib/types.js +39 -11
- package/lib/userMap/userMap.d.ts +25 -0
- package/lib/userMap/userMap.js +73 -0
- package/lib/userMap/userStatsMap.d.ts +19 -0
- package/lib/userMap/userStatsMap.js +68 -0
- package/package.json +6 -3
- package/src/accounts/pollingClearingHouseAccountSubscriber.ts +42 -38
- package/src/accounts/types.ts +12 -9
- package/src/accounts/webSocketClearingHouseAccountSubscriber.ts +65 -52
- package/src/addresses/pda.ts +49 -44
- package/src/admin.ts +190 -55
- package/src/clearingHouse.ts +1092 -365
- package/src/clearingHouseConfig.ts +2 -2
- package/src/clearingHouseUser.ts +518 -255
- package/src/config.ts +30 -30
- package/src/constants/numericConstants.ts +17 -15
- package/src/constants/{markets.ts → perpMarkets.ts} +5 -5
- package/src/constants/{banks.ts → spotMarkets.ts} +19 -19
- package/src/dlob/DLOB.ts +884 -0
- package/src/dlob/DLOBNode.ts +163 -0
- package/src/dlob/NodeList.ts +185 -0
- package/src/events/types.ts +3 -0
- package/src/examples/makeTradeExample.js +152 -75
- package/src/examples/makeTradeExample.ts +10 -8
- package/src/idl/clearing_house.json +1152 -503
- package/src/index.ts +10 -3
- package/src/math/amm.ts +6 -3
- package/src/math/funding.ts +7 -7
- package/src/math/margin.ts +34 -23
- package/src/math/market.ts +72 -20
- package/src/math/oracles.ts +18 -1
- package/src/math/orders.ts +33 -25
- package/src/math/position.ts +31 -31
- package/src/math/spotBalance.ts +316 -0
- package/src/math/spotMarket.ts +9 -0
- package/src/math/spotPosition.ts +47 -0
- package/src/math/state.ts +2 -2
- package/src/math/trade.ts +4 -4
- package/src/orderParams.ts +16 -8
- package/src/serum/serumSubscriber.ts +80 -0
- package/src/serum/types.ts +13 -0
- package/src/tx/retryTxSender.ts +5 -2
- package/src/tx/types.ts +2 -1
- package/src/types.ts +135 -56
- package/src/userMap/userMap.ts +100 -0
- package/src/userMap/userStatsMap.ts +110 -0
- package/tests/bn/test.ts +2 -3
- package/tests/dlob/helpers.ts +322 -0
- package/tests/dlob/test.ts +2865 -0
- package/lib/math/bankBalance.d.ts +0 -15
- package/lib/math/bankBalance.js +0 -150
- package/src/constants/numericConstants.js +0 -41
- package/src/math/bankBalance.ts +0 -258
- package/src/math/oracles.js +0 -26
- package/src/math/state.js +0 -15
- package/src/orderParams.js +0 -20
- package/src/slot/SlotSubscriber.js +0 -39
- package/src/tokenFaucet.js +0 -189
package/src/index.ts
CHANGED
|
@@ -7,7 +7,7 @@ export * from './oracles/types';
|
|
|
7
7
|
export * from './oracles/pythClient';
|
|
8
8
|
export * from './oracles/switchboardClient';
|
|
9
9
|
export * from './types';
|
|
10
|
-
export * from './constants/
|
|
10
|
+
export * from './constants/perpMarkets';
|
|
11
11
|
export * from './accounts/fetch';
|
|
12
12
|
export * from './accounts/webSocketClearingHouseAccountSubscriber';
|
|
13
13
|
export * from './accounts/bulkAccountLoader';
|
|
@@ -32,6 +32,7 @@ export * from './events/types';
|
|
|
32
32
|
export * from './events/eventSubscriber';
|
|
33
33
|
export * from './events/fetchLogs';
|
|
34
34
|
export * from './math/auction';
|
|
35
|
+
export * from './math/spotMarket';
|
|
35
36
|
export * from './math/conversion';
|
|
36
37
|
export * from './math/funding';
|
|
37
38
|
export * from './math/market';
|
|
@@ -50,11 +51,17 @@ export * from './types';
|
|
|
50
51
|
export * from './math/utils';
|
|
51
52
|
export * from './config';
|
|
52
53
|
export * from './constants/numericConstants';
|
|
54
|
+
export * from './serum/serumSubscriber';
|
|
53
55
|
export * from './tx/retryTxSender';
|
|
54
56
|
export * from './util/computeUnits';
|
|
55
57
|
export * from './util/tps';
|
|
56
|
-
export * from './math/
|
|
57
|
-
export * from './constants/
|
|
58
|
+
export * from './math/spotBalance';
|
|
59
|
+
export * from './constants/spotMarkets';
|
|
58
60
|
export * from './clearingHouseConfig';
|
|
61
|
+
export * from './dlob/DLOB';
|
|
62
|
+
export * from './dlob/DLOBNode';
|
|
63
|
+
export * from './dlob/NodeList';
|
|
64
|
+
export * from './userMap/userMap';
|
|
65
|
+
export * from './userMap/userStatsMap';
|
|
59
66
|
|
|
60
67
|
export { BN, PublicKey, pyth };
|
package/src/math/amm.ts
CHANGED
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
AMM,
|
|
16
16
|
PositionDirection,
|
|
17
17
|
SwapDirection,
|
|
18
|
-
|
|
18
|
+
PerpMarketAccount,
|
|
19
19
|
isVariant,
|
|
20
20
|
} from '../types';
|
|
21
21
|
import { assert } from '../assert/assert';
|
|
@@ -418,7 +418,10 @@ export function calculateSpreadBN(
|
|
|
418
418
|
);
|
|
419
419
|
}
|
|
420
420
|
|
|
421
|
-
const maxTargetSpread: number =
|
|
421
|
+
const maxTargetSpread: number = Math.max(
|
|
422
|
+
maxSpread,
|
|
423
|
+
lastOracleMarkSpreadPct.abs().toNumber()
|
|
424
|
+
);
|
|
422
425
|
|
|
423
426
|
const MAX_INVENTORY_SKEW = 5;
|
|
424
427
|
|
|
@@ -613,7 +616,7 @@ export function getSwapDirection(
|
|
|
613
616
|
* @param market
|
|
614
617
|
* @returns cost : Precision MARK_PRICE_PRECISION
|
|
615
618
|
*/
|
|
616
|
-
export function calculateTerminalPrice(market:
|
|
619
|
+
export function calculateTerminalPrice(market: PerpMarketAccount) {
|
|
617
620
|
const directionToClose = market.amm.netBaseAssetAmount.gt(ZERO)
|
|
618
621
|
? PositionDirection.SHORT
|
|
619
622
|
: PositionDirection.LONG;
|
package/src/math/funding.ts
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
QUOTE_PRECISION,
|
|
6
6
|
ZERO,
|
|
7
7
|
} from '../constants/numericConstants';
|
|
8
|
-
import {
|
|
8
|
+
import { PerpMarketAccount, isVariant } from '../types';
|
|
9
9
|
import { calculateMarkPrice } from './market';
|
|
10
10
|
import { OraclePriceData } from '../oracles/types';
|
|
11
11
|
|
|
@@ -17,7 +17,7 @@ import { OraclePriceData } from '../oracles/types';
|
|
|
17
17
|
* @returns Estimated funding rate. : Precision //TODO-PRECISION
|
|
18
18
|
*/
|
|
19
19
|
export async function calculateAllEstimatedFundingRate(
|
|
20
|
-
market:
|
|
20
|
+
market: PerpMarketAccount,
|
|
21
21
|
oraclePriceData?: OraclePriceData,
|
|
22
22
|
periodAdjustment: BN = new BN(1)
|
|
23
23
|
): Promise<[BN, BN, BN, BN, BN]> {
|
|
@@ -29,7 +29,7 @@ export async function calculateAllEstimatedFundingRate(
|
|
|
29
29
|
const hoursInDay = new BN(24);
|
|
30
30
|
const ONE = new BN(1);
|
|
31
31
|
|
|
32
|
-
if (
|
|
32
|
+
if (isVariant(market.status, 'uninitialized')) {
|
|
33
33
|
return [ZERO, ZERO, ZERO, ZERO, ZERO];
|
|
34
34
|
}
|
|
35
35
|
|
|
@@ -208,7 +208,7 @@ export async function calculateAllEstimatedFundingRate(
|
|
|
208
208
|
* @returns Estimated funding rate. : Precision //TODO-PRECISION
|
|
209
209
|
*/
|
|
210
210
|
export async function calculateEstimatedFundingRate(
|
|
211
|
-
market:
|
|
211
|
+
market: PerpMarketAccount,
|
|
212
212
|
oraclePriceData?: OraclePriceData,
|
|
213
213
|
periodAdjustment: BN = new BN(1),
|
|
214
214
|
estimationMethod?: 'interpolated' | 'lowerbound' | 'capped'
|
|
@@ -238,7 +238,7 @@ export async function calculateEstimatedFundingRate(
|
|
|
238
238
|
* @returns Estimated funding rate. : Precision //TODO-PRECISION
|
|
239
239
|
*/
|
|
240
240
|
export async function calculateLongShortFundingRate(
|
|
241
|
-
market:
|
|
241
|
+
market: PerpMarketAccount,
|
|
242
242
|
oraclePriceData?: OraclePriceData,
|
|
243
243
|
periodAdjustment: BN = new BN(1)
|
|
244
244
|
): Promise<[BN, BN]> {
|
|
@@ -266,7 +266,7 @@ export async function calculateLongShortFundingRate(
|
|
|
266
266
|
* @returns Estimated funding rate. : Precision //TODO-PRECISION
|
|
267
267
|
*/
|
|
268
268
|
export async function calculateLongShortFundingRateAndLiveTwaps(
|
|
269
|
-
market:
|
|
269
|
+
market: PerpMarketAccount,
|
|
270
270
|
oraclePriceData?: OraclePriceData,
|
|
271
271
|
periodAdjustment: BN = new BN(1)
|
|
272
272
|
): Promise<[BN, BN, BN, BN]> {
|
|
@@ -291,7 +291,7 @@ export async function calculateLongShortFundingRateAndLiveTwaps(
|
|
|
291
291
|
* @param market
|
|
292
292
|
* @returns Estimated fee pool size
|
|
293
293
|
*/
|
|
294
|
-
export function calculateFundingPool(market:
|
|
294
|
+
export function calculateFundingPool(market: PerpMarketAccount): BN {
|
|
295
295
|
// todo
|
|
296
296
|
const totalFeeLB = market.amm.totalExchangeFee.div(new BN(2));
|
|
297
297
|
const feePool = BN.max(
|
package/src/math/margin.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { squareRootBN } from './utils';
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
SPOT_MARKET_WEIGHT_PRECISION,
|
|
4
|
+
SPOT_MARKET_IMF_PRECISION,
|
|
5
5
|
ZERO,
|
|
6
6
|
BID_ASK_SPREAD_PRECISION,
|
|
7
7
|
AMM_TO_QUOTE_PRECISION_RATIO,
|
|
@@ -9,7 +9,8 @@ import {
|
|
|
9
9
|
} from '../constants/numericConstants';
|
|
10
10
|
import { BN } from '@project-serum/anchor';
|
|
11
11
|
import { OraclePriceData } from '../oracles/types';
|
|
12
|
-
import {
|
|
12
|
+
import { PerpMarketAccount, PerpPosition } from '..';
|
|
13
|
+
import { assert } from '../assert/assert';
|
|
13
14
|
|
|
14
15
|
export function calculateSizePremiumLiabilityWeight(
|
|
15
16
|
size: BN, // AMM_RESERVE_PRECISION
|
|
@@ -22,14 +23,22 @@ export function calculateSizePremiumLiabilityWeight(
|
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
const sizeSqrt = squareRootBN(size.div(new BN(1000)).add(new BN(1))); //1e13 -> 1e10 -> 1e5
|
|
26
|
+
|
|
27
|
+
const denom0 = BN.max(new BN(1), SPOT_MARKET_IMF_PRECISION.div(imfFactor));
|
|
28
|
+
assert(denom0.gt(ZERO));
|
|
25
29
|
const liabilityWeightNumerator = liabilityWeight.sub(
|
|
26
|
-
liabilityWeight.div(
|
|
30
|
+
liabilityWeight.div(
|
|
31
|
+
BN.max(new BN(1), SPOT_MARKET_IMF_PRECISION.div(imfFactor))
|
|
32
|
+
)
|
|
27
33
|
);
|
|
28
34
|
|
|
35
|
+
const denom = new BN(100_000).mul(SPOT_MARKET_IMF_PRECISION).div(precision);
|
|
36
|
+
assert(denom.gt(ZERO));
|
|
37
|
+
|
|
29
38
|
const sizePremiumLiabilityWeight = liabilityWeightNumerator.add(
|
|
30
39
|
sizeSqrt // 1e5
|
|
31
40
|
.mul(imfFactor)
|
|
32
|
-
.div(
|
|
41
|
+
.div(denom) // 1e5
|
|
33
42
|
);
|
|
34
43
|
|
|
35
44
|
const maxLiabilityWeight = BN.max(
|
|
@@ -49,17 +58,19 @@ export function calculateSizeDiscountAssetWeight(
|
|
|
49
58
|
}
|
|
50
59
|
|
|
51
60
|
const sizeSqrt = squareRootBN(size.div(new BN(1000)).add(new BN(1))); //1e13 -> 1e10 -> 1e5
|
|
52
|
-
const imfNumerator =
|
|
53
|
-
|
|
61
|
+
const imfNumerator = SPOT_MARKET_IMF_PRECISION.add(
|
|
62
|
+
SPOT_MARKET_IMF_PRECISION.div(new BN(10))
|
|
54
63
|
);
|
|
55
64
|
|
|
56
|
-
const sizeDiscountAssetWeight = imfNumerator
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
65
|
+
const sizeDiscountAssetWeight = imfNumerator
|
|
66
|
+
.mul(SPOT_MARKET_WEIGHT_PRECISION)
|
|
67
|
+
.div(
|
|
68
|
+
SPOT_MARKET_IMF_PRECISION.add(
|
|
69
|
+
sizeSqrt // 1e5
|
|
70
|
+
.mul(imfFactor)
|
|
71
|
+
.div(new BN(100_000)) // 1e5
|
|
72
|
+
)
|
|
73
|
+
);
|
|
63
74
|
|
|
64
75
|
const minAssetWeight = BN.min(assetWeight, sizeDiscountAssetWeight);
|
|
65
76
|
|
|
@@ -67,8 +78,8 @@ export function calculateSizeDiscountAssetWeight(
|
|
|
67
78
|
}
|
|
68
79
|
|
|
69
80
|
export function calculateOraclePriceForPerpMargin(
|
|
70
|
-
|
|
71
|
-
market:
|
|
81
|
+
perpPosition: PerpPosition,
|
|
82
|
+
market: PerpMarketAccount,
|
|
72
83
|
oraclePriceData: OraclePriceData
|
|
73
84
|
): BN {
|
|
74
85
|
const oraclePriceOffset = BN.min(
|
|
@@ -83,7 +94,7 @@ export function calculateOraclePriceForPerpMargin(
|
|
|
83
94
|
);
|
|
84
95
|
|
|
85
96
|
let marginPrice: BN;
|
|
86
|
-
if (
|
|
97
|
+
if (perpPosition.baseAssetAmount.gt(ZERO)) {
|
|
87
98
|
marginPrice = oraclePriceData.price.sub(oraclePriceOffset);
|
|
88
99
|
} else {
|
|
89
100
|
marginPrice = oraclePriceData.price.add(oraclePriceOffset);
|
|
@@ -93,21 +104,21 @@ export function calculateOraclePriceForPerpMargin(
|
|
|
93
104
|
}
|
|
94
105
|
|
|
95
106
|
export function calculateBaseAssetValueWithOracle(
|
|
96
|
-
market:
|
|
97
|
-
|
|
107
|
+
market: PerpMarketAccount,
|
|
108
|
+
perpPosition: PerpPosition,
|
|
98
109
|
oraclePriceData: OraclePriceData
|
|
99
110
|
): BN {
|
|
100
|
-
return
|
|
111
|
+
return perpPosition.baseAssetAmount
|
|
101
112
|
.abs()
|
|
102
113
|
.mul(oraclePriceData.price)
|
|
103
114
|
.div(AMM_TO_QUOTE_PRECISION_RATIO.mul(MARK_PRICE_PRECISION));
|
|
104
115
|
}
|
|
105
116
|
|
|
106
117
|
export function calculateWorstCaseBaseAssetAmount(
|
|
107
|
-
|
|
118
|
+
perpPosition: PerpPosition
|
|
108
119
|
): BN {
|
|
109
|
-
const allBids =
|
|
110
|
-
const allAsks =
|
|
120
|
+
const allBids = perpPosition.baseAssetAmount.add(perpPosition.openBids);
|
|
121
|
+
const allAsks = perpPosition.baseAssetAmount.add(perpPosition.openAsks);
|
|
111
122
|
|
|
112
123
|
if (allBids.abs().gt(allAsks.abs())) {
|
|
113
124
|
return allBids;
|
package/src/math/market.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { BN } from '@project-serum/anchor';
|
|
2
2
|
import {
|
|
3
|
-
|
|
3
|
+
PerpMarketAccount,
|
|
4
4
|
PositionDirection,
|
|
5
5
|
MarginCategory,
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
SpotMarketAccount,
|
|
7
|
+
SpotBalanceType,
|
|
8
8
|
} from '../types';
|
|
9
9
|
import {
|
|
10
10
|
calculateAmmReservesAfterSwap,
|
|
@@ -18,8 +18,13 @@ import {
|
|
|
18
18
|
calculateSizePremiumLiabilityWeight,
|
|
19
19
|
} from './margin';
|
|
20
20
|
import { OraclePriceData } from '../oracles/types';
|
|
21
|
-
import {
|
|
22
|
-
|
|
21
|
+
import {
|
|
22
|
+
BASE_PRECISION,
|
|
23
|
+
MARGIN_PRECISION,
|
|
24
|
+
PRICE_TO_QUOTE_PRECISION,
|
|
25
|
+
ZERO,
|
|
26
|
+
} from '../constants/numericConstants';
|
|
27
|
+
import { getTokenAmount } from './spotBalance';
|
|
23
28
|
|
|
24
29
|
/**
|
|
25
30
|
* Calculates market mark price
|
|
@@ -28,7 +33,7 @@ import { getTokenAmount } from './bankBalance';
|
|
|
28
33
|
* @return markPrice : Precision MARK_PRICE_PRECISION
|
|
29
34
|
*/
|
|
30
35
|
export function calculateMarkPrice(
|
|
31
|
-
market:
|
|
36
|
+
market: PerpMarketAccount,
|
|
32
37
|
oraclePriceData: OraclePriceData
|
|
33
38
|
): BN {
|
|
34
39
|
const newAmm = calculateUpdatedAMM(market.amm, oraclePriceData);
|
|
@@ -46,7 +51,7 @@ export function calculateMarkPrice(
|
|
|
46
51
|
* @return bidPrice : Precision MARK_PRICE_PRECISION
|
|
47
52
|
*/
|
|
48
53
|
export function calculateBidPrice(
|
|
49
|
-
market:
|
|
54
|
+
market: PerpMarketAccount,
|
|
50
55
|
oraclePriceData: OraclePriceData
|
|
51
56
|
): BN {
|
|
52
57
|
const { baseAssetReserve, quoteAssetReserve, newPeg } =
|
|
@@ -63,10 +68,10 @@ export function calculateBidPrice(
|
|
|
63
68
|
* Calculates market ask price
|
|
64
69
|
*
|
|
65
70
|
* @param market
|
|
66
|
-
* @return
|
|
71
|
+
* @return askPrice : Precision MARK_PRICE_PRECISION
|
|
67
72
|
*/
|
|
68
73
|
export function calculateAskPrice(
|
|
69
|
-
market:
|
|
74
|
+
market: PerpMarketAccount,
|
|
70
75
|
oraclePriceData: OraclePriceData
|
|
71
76
|
): BN {
|
|
72
77
|
const { baseAssetReserve, quoteAssetReserve, newPeg } =
|
|
@@ -82,8 +87,8 @@ export function calculateAskPrice(
|
|
|
82
87
|
export function calculateNewMarketAfterTrade(
|
|
83
88
|
baseAssetAmount: BN,
|
|
84
89
|
direction: PositionDirection,
|
|
85
|
-
market:
|
|
86
|
-
):
|
|
90
|
+
market: PerpMarketAccount
|
|
91
|
+
): PerpMarketAccount {
|
|
87
92
|
const [newQuoteAssetReserve, newBaseAssetReserve] =
|
|
88
93
|
calculateAmmReservesAfterSwap(
|
|
89
94
|
market.amm,
|
|
@@ -102,7 +107,7 @@ export function calculateNewMarketAfterTrade(
|
|
|
102
107
|
}
|
|
103
108
|
|
|
104
109
|
export function calculateMarkOracleSpread(
|
|
105
|
-
market:
|
|
110
|
+
market: PerpMarketAccount,
|
|
106
111
|
oraclePriceData: OraclePriceData
|
|
107
112
|
): BN {
|
|
108
113
|
const markPrice = calculateMarkPrice(market, oraclePriceData);
|
|
@@ -117,7 +122,7 @@ export function calculateOracleSpread(
|
|
|
117
122
|
}
|
|
118
123
|
|
|
119
124
|
export function calculateMarketMarginRatio(
|
|
120
|
-
market:
|
|
125
|
+
market: PerpMarketAccount,
|
|
121
126
|
size: BN,
|
|
122
127
|
marginCategory: MarginCategory
|
|
123
128
|
): number {
|
|
@@ -140,18 +145,34 @@ export function calculateMarketMarginRatio(
|
|
|
140
145
|
}
|
|
141
146
|
|
|
142
147
|
export function calculateUnrealizedAssetWeight(
|
|
143
|
-
market:
|
|
148
|
+
market: PerpMarketAccount,
|
|
149
|
+
quoteSpotMarket: SpotMarketAccount,
|
|
144
150
|
unrealizedPnl: BN,
|
|
145
|
-
marginCategory: MarginCategory
|
|
151
|
+
marginCategory: MarginCategory,
|
|
152
|
+
oraclePriceData: OraclePriceData
|
|
146
153
|
): BN {
|
|
147
154
|
let assetWeight: BN;
|
|
148
|
-
|
|
149
155
|
switch (marginCategory) {
|
|
150
156
|
case 'Initial':
|
|
157
|
+
assetWeight = new BN(market.unrealizedInitialAssetWeight);
|
|
158
|
+
|
|
159
|
+
if (market.unrealizedMaxImbalance.gt(ZERO)) {
|
|
160
|
+
const netUnsettledPnl = calculateNetUserImbalance(
|
|
161
|
+
market,
|
|
162
|
+
quoteSpotMarket,
|
|
163
|
+
oraclePriceData
|
|
164
|
+
);
|
|
165
|
+
if (netUnsettledPnl.gt(market.unrealizedMaxImbalance)) {
|
|
166
|
+
assetWeight = assetWeight
|
|
167
|
+
.mul(market.unrealizedMaxImbalance)
|
|
168
|
+
.div(netUnsettledPnl);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
151
172
|
assetWeight = calculateSizeDiscountAssetWeight(
|
|
152
173
|
unrealizedPnl,
|
|
153
174
|
market.unrealizedImfFactor,
|
|
154
|
-
|
|
175
|
+
assetWeight
|
|
155
176
|
);
|
|
156
177
|
break;
|
|
157
178
|
case 'Maintenance':
|
|
@@ -163,8 +184,39 @@ export function calculateUnrealizedAssetWeight(
|
|
|
163
184
|
}
|
|
164
185
|
|
|
165
186
|
export function calculateMarketAvailablePNL(
|
|
166
|
-
|
|
167
|
-
|
|
187
|
+
perpMarket: PerpMarketAccount,
|
|
188
|
+
spotMarket: SpotMarketAccount
|
|
168
189
|
): BN {
|
|
169
|
-
return getTokenAmount(
|
|
190
|
+
return getTokenAmount(
|
|
191
|
+
perpMarket.pnlPool.balance,
|
|
192
|
+
spotMarket,
|
|
193
|
+
SpotBalanceType.DEPOSIT
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
export function calculateNetUserImbalance(
|
|
198
|
+
market: PerpMarketAccount,
|
|
199
|
+
bank: SpotMarketAccount,
|
|
200
|
+
oraclePriceData: OraclePriceData
|
|
201
|
+
): BN {
|
|
202
|
+
const netUserPositionValue = market.amm.netBaseAssetAmount
|
|
203
|
+
.mul(oraclePriceData.price)
|
|
204
|
+
.div(BASE_PRECISION)
|
|
205
|
+
.div(PRICE_TO_QUOTE_PRECISION);
|
|
206
|
+
|
|
207
|
+
const netUserCostBasis = market.amm.quoteAssetAmountLong
|
|
208
|
+
.add(market.amm.quoteAssetAmountShort)
|
|
209
|
+
.sub(market.amm.cumulativeSocialLoss);
|
|
210
|
+
|
|
211
|
+
const userEntitledPnl = netUserPositionValue.add(netUserCostBasis);
|
|
212
|
+
|
|
213
|
+
const pnlPool = getTokenAmount(
|
|
214
|
+
market.pnlPool.balance,
|
|
215
|
+
bank,
|
|
216
|
+
SpotBalanceType.DEPOSIT
|
|
217
|
+
);
|
|
218
|
+
|
|
219
|
+
const imbalance = userEntitledPnl.sub(pnlPool);
|
|
220
|
+
|
|
221
|
+
return imbalance;
|
|
170
222
|
}
|
package/src/math/oracles.ts
CHANGED
|
@@ -2,11 +2,28 @@ import { AMM, OracleGuardRails } from '../types';
|
|
|
2
2
|
import { OraclePriceData } from '../oracles/types';
|
|
3
3
|
import {
|
|
4
4
|
BID_ASK_SPREAD_PRECISION,
|
|
5
|
+
MARGIN_PRECISION,
|
|
5
6
|
MARK_PRICE_PRECISION,
|
|
6
7
|
ONE,
|
|
7
8
|
ZERO,
|
|
8
9
|
} from '../constants/numericConstants';
|
|
9
|
-
import { BN } from '../index';
|
|
10
|
+
import { BN, PerpMarketAccount } from '../index';
|
|
11
|
+
import { assert } from '../assert/assert';
|
|
12
|
+
|
|
13
|
+
export function oraclePriceBands(
|
|
14
|
+
market: PerpMarketAccount,
|
|
15
|
+
oraclePriceData: OraclePriceData
|
|
16
|
+
): [BN, BN] {
|
|
17
|
+
const maxPercentDiff =
|
|
18
|
+
market.marginRatioInitial - market.marginRatioMaintenance;
|
|
19
|
+
const offset = oraclePriceData.price
|
|
20
|
+
.mul(new BN(maxPercentDiff))
|
|
21
|
+
.div(MARGIN_PRECISION);
|
|
22
|
+
|
|
23
|
+
assert(offset.gt(ZERO));
|
|
24
|
+
|
|
25
|
+
return [oraclePriceData.price.sub(offset), oraclePriceData.price.add(offset)];
|
|
26
|
+
}
|
|
10
27
|
|
|
11
28
|
export function isOracleValid(
|
|
12
29
|
amm: AMM,
|
package/src/math/orders.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { ClearingHouseUser } from '../clearingHouseUser';
|
|
|
2
2
|
import {
|
|
3
3
|
isOneOfVariant,
|
|
4
4
|
isVariant,
|
|
5
|
-
|
|
5
|
+
PerpMarketAccount,
|
|
6
6
|
Order,
|
|
7
7
|
PositionDirection,
|
|
8
8
|
} from '../types';
|
|
@@ -131,9 +131,9 @@ export function standardizeBaseAssetAmount(
|
|
|
131
131
|
|
|
132
132
|
export function getLimitPrice(
|
|
133
133
|
order: Order,
|
|
134
|
-
market: MarketAccount,
|
|
135
134
|
oraclePriceData: OraclePriceData,
|
|
136
|
-
slot: number
|
|
135
|
+
slot: number,
|
|
136
|
+
perpMarket?: PerpMarketAccount
|
|
137
137
|
): BN {
|
|
138
138
|
let limitPrice;
|
|
139
139
|
if (!order.oraclePriceOffset.eq(ZERO)) {
|
|
@@ -143,14 +143,26 @@ export function getLimitPrice(
|
|
|
143
143
|
limitPrice = getAuctionPrice(order, slot);
|
|
144
144
|
} else if (!order.price.eq(ZERO)) {
|
|
145
145
|
limitPrice = order.price;
|
|
146
|
-
} else if (isVariant(order.direction, 'long')) {
|
|
147
|
-
const askPrice = calculateAskPrice(market, oraclePriceData);
|
|
148
|
-
const delta = askPrice.div(new BN(market.amm.maxSlippageRatio));
|
|
149
|
-
limitPrice = askPrice.add(delta);
|
|
150
146
|
} else {
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
147
|
+
if (perpMarket) {
|
|
148
|
+
if (isVariant(order.direction, 'long')) {
|
|
149
|
+
const askPrice = calculateAskPrice(perpMarket, oraclePriceData);
|
|
150
|
+
const delta = askPrice.div(new BN(perpMarket.amm.maxSlippageRatio));
|
|
151
|
+
limitPrice = askPrice.add(delta);
|
|
152
|
+
} else {
|
|
153
|
+
const bidPrice = calculateBidPrice(perpMarket, oraclePriceData);
|
|
154
|
+
const delta = bidPrice.div(new BN(perpMarket.amm.maxSlippageRatio));
|
|
155
|
+
limitPrice = bidPrice.sub(delta);
|
|
156
|
+
}
|
|
157
|
+
} else {
|
|
158
|
+
// check oracle validity?
|
|
159
|
+
const oraclePrice1Pct = oraclePriceData.price.div(new BN(100));
|
|
160
|
+
if (isVariant(order.direction, 'long')) {
|
|
161
|
+
limitPrice = oraclePriceData.price.add(oraclePrice1Pct);
|
|
162
|
+
} else {
|
|
163
|
+
limitPrice = oraclePriceData.price.sub(oraclePrice1Pct);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
154
166
|
}
|
|
155
167
|
} else {
|
|
156
168
|
limitPrice = order.price;
|
|
@@ -161,10 +173,9 @@ export function getLimitPrice(
|
|
|
161
173
|
|
|
162
174
|
export function isFillableByVAMM(
|
|
163
175
|
order: Order,
|
|
164
|
-
market:
|
|
176
|
+
market: PerpMarketAccount,
|
|
165
177
|
oraclePriceData: OraclePriceData,
|
|
166
|
-
slot: number
|
|
167
|
-
maxAuctionDuration: number
|
|
178
|
+
slot: number
|
|
168
179
|
): boolean {
|
|
169
180
|
return (
|
|
170
181
|
(isAuctionComplete(order, slot) &&
|
|
@@ -174,13 +185,13 @@ export function isFillableByVAMM(
|
|
|
174
185
|
oraclePriceData,
|
|
175
186
|
slot
|
|
176
187
|
).eq(ZERO)) ||
|
|
177
|
-
isOrderExpired(order, slot
|
|
188
|
+
isOrderExpired(order, slot)
|
|
178
189
|
);
|
|
179
190
|
}
|
|
180
191
|
|
|
181
192
|
export function calculateBaseAssetAmountForAmmToFulfill(
|
|
182
193
|
order: Order,
|
|
183
|
-
market:
|
|
194
|
+
market: PerpMarketAccount,
|
|
184
195
|
oraclePriceData: OraclePriceData,
|
|
185
196
|
slot: number
|
|
186
197
|
): BN {
|
|
@@ -191,7 +202,7 @@ export function calculateBaseAssetAmountForAmmToFulfill(
|
|
|
191
202
|
return ZERO;
|
|
192
203
|
}
|
|
193
204
|
|
|
194
|
-
const limitPrice = getLimitPrice(order,
|
|
205
|
+
const limitPrice = getLimitPrice(order, oraclePriceData, slot, market);
|
|
195
206
|
const baseAssetAmount = calculateBaseAssetAmountToFillUpToLimitPrice(
|
|
196
207
|
order,
|
|
197
208
|
market,
|
|
@@ -209,7 +220,7 @@ export function calculateBaseAssetAmountForAmmToFulfill(
|
|
|
209
220
|
|
|
210
221
|
export function calculateBaseAssetAmountToFillUpToLimitPrice(
|
|
211
222
|
order: Order,
|
|
212
|
-
market:
|
|
223
|
+
market: PerpMarketAccount,
|
|
213
224
|
limitPrice: BN,
|
|
214
225
|
oraclePriceData: OraclePriceData
|
|
215
226
|
): BN {
|
|
@@ -246,17 +257,14 @@ function isSameDirection(
|
|
|
246
257
|
);
|
|
247
258
|
}
|
|
248
259
|
|
|
249
|
-
export function isOrderExpired(
|
|
250
|
-
order: Order,
|
|
251
|
-
slot: number,
|
|
252
|
-
maxAuctionDuration: number
|
|
253
|
-
): boolean {
|
|
260
|
+
export function isOrderExpired(order: Order, slot: number): boolean {
|
|
254
261
|
if (
|
|
255
|
-
|
|
256
|
-
!isVariant(order.status, 'open')
|
|
262
|
+
isOneOfVariant(order.orderType, ['triggerMarket', 'triggerLimit']) ||
|
|
263
|
+
!isVariant(order.status, 'open') ||
|
|
264
|
+
order.timeInForce === 0
|
|
257
265
|
) {
|
|
258
266
|
return false;
|
|
259
267
|
}
|
|
260
268
|
|
|
261
|
-
return new BN(slot).sub(order.slot).gt(new BN(
|
|
269
|
+
return new BN(slot).sub(order.slot).gt(new BN(order.timeInForce));
|
|
262
270
|
}
|