@drift-labs/sdk 0.2.0-master.3 → 0.2.0-master.31
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/README.md +13 -13
- 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/pollingClearingHouseAccountSubscriber.d.ts +16 -16
- package/lib/accounts/pollingClearingHouseAccountSubscriber.js +31 -28
- package/lib/accounts/pollingUserStatsAccountSubscriber.d.ts +27 -0
- package/lib/accounts/pollingUserStatsAccountSubscriber.js +113 -0
- package/lib/accounts/types.d.ts +22 -11
- package/lib/accounts/webSocketClearingHouseAccountSubscriber.d.ts +17 -17
- package/lib/accounts/webSocketClearingHouseAccountSubscriber.js +37 -35
- package/lib/accounts/webSocketUserStatsAccountSubsriber.d.ts +20 -0
- package/lib/accounts/webSocketUserStatsAccountSubsriber.js +47 -0
- package/lib/addresses/marketAddresses.d.ts +1 -3
- package/lib/addresses/pda.d.ts +10 -4
- package/lib/addresses/pda.js +51 -14
- package/lib/admin.d.ts +42 -26
- package/lib/admin.js +228 -81
- package/lib/clearingHouse.d.ts +130 -49
- package/lib/clearingHouse.js +1256 -367
- package/lib/clearingHouseConfig.d.ts +4 -4
- package/lib/clearingHouseUser.d.ts +51 -39
- package/lib/clearingHouseUser.js +408 -191
- 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.d.ts +7 -9
- package/lib/config.js +21 -21
- package/lib/constants/numericConstants.d.ts +25 -12
- package/lib/constants/numericConstants.js +35 -21
- package/lib/constants/perpMarkets.d.ts +18 -0
- package/lib/constants/{markets.js → perpMarkets.js} +7 -7
- package/lib/constants/spotMarkets.d.ts +19 -0
- package/lib/constants/spotMarkets.js +53 -0
- package/lib/dlob/DLOB.d.ts +74 -0
- package/lib/dlob/DLOB.js +595 -0
- package/lib/dlob/DLOBNode.d.ts +54 -0
- package/lib/dlob/DLOBNode.js +85 -0
- package/lib/dlob/NodeList.d.ts +26 -0
- package/lib/dlob/NodeList.js +139 -0
- package/lib/events/eventList.js +3 -0
- package/lib/events/eventSubscriber.d.ts +4 -2
- package/lib/events/eventSubscriber.js +16 -9
- package/lib/events/fetchLogs.d.ts +10 -1
- package/lib/events/fetchLogs.js +27 -7
- package/lib/events/pollingLogProvider.d.ts +2 -1
- package/lib/events/pollingLogProvider.js +6 -2
- package/lib/events/sort.js +8 -11
- package/lib/events/types.d.ts +8 -2
- package/lib/events/types.js +6 -0
- package/lib/examples/makeTradeExample.js +20 -8
- package/lib/factory/bigNum.d.ts +2 -0
- package/lib/factory/bigNum.js +48 -10
- package/lib/idl/clearing_house.json +4889 -1529
- package/lib/idl/{mock_usdc_faucet.json → token_faucet.json} +46 -23
- package/lib/index.d.ts +21 -6
- package/lib/index.js +25 -6
- package/lib/math/amm.d.ts +9 -6
- package/lib/math/amm.js +91 -66
- package/lib/math/auction.js +4 -1
- package/lib/math/conversion.js +1 -1
- package/lib/math/funding.d.ts +6 -6
- package/lib/math/funding.js +11 -10
- package/lib/math/insurance.d.ts +4 -0
- package/lib/math/insurance.js +27 -0
- package/lib/math/margin.d.ts +11 -0
- package/lib/math/margin.js +77 -0
- package/lib/math/market.d.ts +14 -9
- package/lib/math/market.js +72 -10
- package/lib/math/oracles.d.ts +4 -0
- package/lib/math/oracles.js +36 -8
- package/lib/math/orders.d.ts +6 -2
- package/lib/math/orders.js +78 -3
- package/lib/math/position.d.ts +21 -13
- package/lib/math/position.js +76 -36
- package/lib/math/repeg.js +14 -5
- package/lib/math/spotBalance.d.ts +22 -0
- package/lib/math/spotBalance.js +192 -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/trade.d.ts +10 -10
- package/lib/math/trade.js +32 -39
- package/lib/oracles/pythClient.js +1 -1
- package/lib/oracles/quoteAssetOracleClient.js +1 -1
- package/lib/oracles/switchboardClient.js +1 -1
- package/lib/orderParams.d.ts +14 -5
- package/lib/orderParams.js +12 -92
- 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/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.d.ts +1 -1
- package/lib/tx/retryTxSender.js +13 -4
- package/lib/tx/types.d.ts +1 -1
- package/lib/tx/utils.js +1 -1
- package/lib/types.d.ts +566 -138
- package/lib/types.js +129 -5
- 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/lib/util/computeUnits.js +1 -1
- package/lib/util/getTokenAddress.d.ts +2 -0
- package/lib/util/getTokenAddress.js +9 -0
- package/package.json +12 -6
- package/src/accounts/bulkUserStatsSubscription.ts +33 -0
- package/src/accounts/bulkUserSubscription.ts +0 -1
- package/src/accounts/fetch.ts +27 -2
- package/src/accounts/pollingClearingHouseAccountSubscriber.ts +46 -42
- package/src/accounts/pollingUserStatsAccountSubscriber.ts +172 -0
- package/src/accounts/types.ts +31 -11
- package/src/accounts/webSocketClearingHouseAccountSubscriber.ts +64 -59
- package/src/accounts/webSocketUserStatsAccountSubsriber.ts +80 -0
- package/src/addresses/marketAddresses.ts +1 -2
- package/src/addresses/pda.ts +88 -14
- package/src/admin.ts +452 -147
- package/src/assert/assert.js +9 -0
- package/src/clearingHouse.ts +2066 -467
- package/src/clearingHouseConfig.ts +4 -3
- package/src/clearingHouseUser.ts +747 -294
- package/src/clearingHouseUserStats.ts +75 -0
- package/src/clearingHouseUserStatsConfig.ts +18 -0
- package/src/config.ts +30 -31
- package/src/constants/numericConstants.ts +48 -25
- package/src/constants/{markets.ts → perpMarkets.ts} +10 -10
- package/src/constants/spotMarkets.ts +73 -0
- package/src/dlob/DLOB.ts +953 -0
- package/src/dlob/DLOBNode.ts +167 -0
- package/src/dlob/NodeList.ts +189 -0
- package/src/events/eventList.js +77 -0
- package/src/events/eventList.ts +3 -0
- package/src/events/eventSubscriber.ts +20 -12
- package/src/events/fetchLogs.ts +35 -8
- package/src/events/pollingLogProvider.ts +10 -2
- package/src/events/sort.ts +11 -15
- package/src/events/types.ts +19 -1
- package/src/examples/makeTradeExample.js +157 -0
- package/src/examples/makeTradeExample.ts +32 -14
- package/src/factory/bigNum.ts +65 -13
- package/src/idl/clearing_house.json +4889 -1529
- package/src/idl/{mock_usdc_faucet.json → token_faucet.json} +46 -23
- package/src/index.ts +21 -6
- package/src/math/amm.ts +171 -88
- package/src/math/auction.ts +5 -1
- package/src/math/conversion.ts +2 -2
- package/src/math/funding.ts +20 -18
- package/src/math/insurance.ts +35 -0
- package/src/math/margin.ts +127 -0
- package/src/math/market.ts +145 -14
- package/src/math/oracles.ts +63 -9
- package/src/math/orders.ts +138 -4
- package/src/math/position.ts +119 -58
- package/src/math/repeg.ts +16 -6
- package/src/math/spotBalance.ts +319 -0
- package/src/math/spotMarket.ts +9 -0
- package/src/math/spotPosition.ts +47 -0
- package/src/math/trade.ts +53 -59
- package/src/oracles/pythClient.ts +2 -2
- package/src/oracles/quoteAssetOracleClient.ts +2 -2
- package/src/oracles/switchboardClient.ts +2 -2
- package/src/orderParams.ts +24 -137
- package/src/serum/serumSubscriber.ts +80 -0
- package/src/serum/types.ts +13 -0
- package/src/slot/SlotSubscriber.ts +11 -1
- package/src/token/index.js +38 -0
- package/src/{mockUSDCFaucet.ts → tokenFaucet.ts} +82 -70
- package/src/tx/retryTxSender.ts +16 -5
- package/src/tx/types.js +2 -0
- package/src/tx/types.ts +2 -1
- package/src/tx/utils.js +17 -0
- package/src/tx/utils.ts +1 -1
- package/src/types.ts +533 -140
- package/src/userMap/userMap.ts +100 -0
- package/src/userMap/userStatsMap.ts +110 -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/tests/bn/test.ts +24 -10
- package/tests/dlob/helpers.ts +397 -0
- package/tests/dlob/test.ts +3688 -0
- package/lib/constants/banks.d.ts +0 -16
- package/lib/constants/banks.js +0 -34
- package/lib/constants/markets.d.ts +0 -19
- package/lib/math/bankBalance.d.ts +0 -9
- package/lib/math/bankBalance.js +0 -75
- package/lib/math/state.d.ts +0 -8
- package/lib/math/state.js +0 -15
- package/lib/orders.d.ts +0 -8
- package/lib/orders.js +0 -134
- package/src/constants/banks.ts +0 -43
- package/src/math/bankBalance.ts +0 -112
- package/src/math/state.ts +0 -14
- package/src/math/utils.js +0 -27
- package/src/math/utils.js.map +0 -1
- package/src/orders.ts +0 -244
- package/src/util/computeUnits.js.map +0 -1
package/src/math/funding.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { BN } from '@project-serum/anchor';
|
|
2
2
|
import {
|
|
3
3
|
AMM_RESERVE_PRECISION,
|
|
4
|
-
|
|
4
|
+
PRICE_PRECISION,
|
|
5
5
|
QUOTE_PRECISION,
|
|
6
6
|
ZERO,
|
|
7
7
|
} from '../constants/numericConstants';
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
8
|
+
import { PerpMarketAccount, isVariant } from '../types';
|
|
9
|
+
import { calculateReservePrice } from './market';
|
|
10
10
|
import { OraclePriceData } from '../oracles/types';
|
|
11
11
|
|
|
12
12
|
/**
|
|
@@ -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
|
|
|
@@ -48,7 +48,7 @@ export async function calculateAllEstimatedFundingRate(
|
|
|
48
48
|
secondsInHour,
|
|
49
49
|
BN.max(ZERO, secondsInHour.sub(timeSinceLastMarkChange))
|
|
50
50
|
);
|
|
51
|
-
const baseAssetPriceWithMantissa =
|
|
51
|
+
const baseAssetPriceWithMantissa = calculateReservePrice(
|
|
52
52
|
market,
|
|
53
53
|
oraclePriceData
|
|
54
54
|
);
|
|
@@ -60,8 +60,10 @@ export async function calculateAllEstimatedFundingRate(
|
|
|
60
60
|
|
|
61
61
|
// calculate real-time (predicted) oracle twap
|
|
62
62
|
// note: oracle twap depends on `when the chord is struck` (market is trade)
|
|
63
|
-
const lastOracleTwapWithMantissa =
|
|
64
|
-
|
|
63
|
+
const lastOracleTwapWithMantissa =
|
|
64
|
+
market.amm.historicalOracleData.lastOraclePriceTwap;
|
|
65
|
+
const lastOraclePriceTwapTs =
|
|
66
|
+
market.amm.historicalOracleData.lastOraclePriceTwapTs;
|
|
65
67
|
|
|
66
68
|
const oracleInvalidDuration = BN.max(
|
|
67
69
|
ZERO,
|
|
@@ -85,12 +87,12 @@ export async function calculateAllEstimatedFundingRate(
|
|
|
85
87
|
const oracleLiveVsTwap = oraclePrice
|
|
86
88
|
.sub(lastOracleTwapWithMantissa)
|
|
87
89
|
.abs()
|
|
88
|
-
.mul(
|
|
90
|
+
.mul(PRICE_PRECISION)
|
|
89
91
|
.mul(new BN(100))
|
|
90
92
|
.div(lastOracleTwapWithMantissa);
|
|
91
93
|
|
|
92
94
|
// verify pyth live input is within 10% of last twap for live update
|
|
93
|
-
if (oracleLiveVsTwap.lte(
|
|
95
|
+
if (oracleLiveVsTwap.lte(PRICE_PRECISION.mul(new BN(10)))) {
|
|
94
96
|
oracleTwapWithMantissa = oracleTwapTimeSinceLastUpdate
|
|
95
97
|
.mul(lastOracleTwapWithMantissa)
|
|
96
98
|
.add(timeSinceLastMarkChange.mul(oraclePrice))
|
|
@@ -108,7 +110,7 @@ export async function calculateAllEstimatedFundingRate(
|
|
|
108
110
|
);
|
|
109
111
|
|
|
110
112
|
const twapSpreadPct = twapSpread
|
|
111
|
-
.mul(
|
|
113
|
+
.mul(PRICE_PRECISION)
|
|
112
114
|
.mul(new BN(100))
|
|
113
115
|
.div(shrunkLastOracleTwapwithMantissa);
|
|
114
116
|
|
|
@@ -125,7 +127,7 @@ export async function calculateAllEstimatedFundingRate(
|
|
|
125
127
|
const interpRateQuote = twapSpreadPct
|
|
126
128
|
.mul(periodAdjustment)
|
|
127
129
|
.div(hoursInDay)
|
|
128
|
-
.div(
|
|
130
|
+
.div(PRICE_PRECISION.div(QUOTE_PRECISION));
|
|
129
131
|
|
|
130
132
|
let feePoolSize = calculateFundingPool(market);
|
|
131
133
|
if (interpRateQuote.lt(new BN(0))) {
|
|
@@ -173,12 +175,12 @@ export async function calculateAllEstimatedFundingRate(
|
|
|
173
175
|
// funding smaller flow
|
|
174
176
|
cappedAltEst = smallerSide.mul(twapSpread).div(hoursInDay);
|
|
175
177
|
const feePoolTopOff = feePoolSize
|
|
176
|
-
.mul(
|
|
178
|
+
.mul(PRICE_PRECISION.div(QUOTE_PRECISION))
|
|
177
179
|
.mul(AMM_RESERVE_PRECISION);
|
|
178
180
|
cappedAltEst = cappedAltEst.add(feePoolTopOff).div(largerSide);
|
|
179
181
|
|
|
180
182
|
cappedAltEst = cappedAltEst
|
|
181
|
-
.mul(
|
|
183
|
+
.mul(PRICE_PRECISION)
|
|
182
184
|
.mul(new BN(100))
|
|
183
185
|
.div(oracleTwapWithMantissa)
|
|
184
186
|
.mul(periodAdjustment);
|
|
@@ -208,7 +210,7 @@ export async function calculateAllEstimatedFundingRate(
|
|
|
208
210
|
* @returns Estimated funding rate. : Precision //TODO-PRECISION
|
|
209
211
|
*/
|
|
210
212
|
export async function calculateEstimatedFundingRate(
|
|
211
|
-
market:
|
|
213
|
+
market: PerpMarketAccount,
|
|
212
214
|
oraclePriceData?: OraclePriceData,
|
|
213
215
|
periodAdjustment: BN = new BN(1),
|
|
214
216
|
estimationMethod?: 'interpolated' | 'lowerbound' | 'capped'
|
|
@@ -238,7 +240,7 @@ export async function calculateEstimatedFundingRate(
|
|
|
238
240
|
* @returns Estimated funding rate. : Precision //TODO-PRECISION
|
|
239
241
|
*/
|
|
240
242
|
export async function calculateLongShortFundingRate(
|
|
241
|
-
market:
|
|
243
|
+
market: PerpMarketAccount,
|
|
242
244
|
oraclePriceData?: OraclePriceData,
|
|
243
245
|
periodAdjustment: BN = new BN(1)
|
|
244
246
|
): Promise<[BN, BN]> {
|
|
@@ -266,7 +268,7 @@ export async function calculateLongShortFundingRate(
|
|
|
266
268
|
* @returns Estimated funding rate. : Precision //TODO-PRECISION
|
|
267
269
|
*/
|
|
268
270
|
export async function calculateLongShortFundingRateAndLiveTwaps(
|
|
269
|
-
market:
|
|
271
|
+
market: PerpMarketAccount,
|
|
270
272
|
oraclePriceData?: OraclePriceData,
|
|
271
273
|
periodAdjustment: BN = new BN(1)
|
|
272
274
|
): Promise<[BN, BN, BN, BN]> {
|
|
@@ -291,7 +293,7 @@ export async function calculateLongShortFundingRateAndLiveTwaps(
|
|
|
291
293
|
* @param market
|
|
292
294
|
* @returns Estimated fee pool size
|
|
293
295
|
*/
|
|
294
|
-
export function calculateFundingPool(market:
|
|
296
|
+
export function calculateFundingPool(market: PerpMarketAccount): BN {
|
|
295
297
|
// todo
|
|
296
298
|
const totalFeeLB = market.amm.totalExchangeFee.div(new BN(2));
|
|
297
299
|
const feePool = BN.max(
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { ZERO } from '../constants/numericConstants';
|
|
2
|
+
import { BN } from '../index';
|
|
3
|
+
|
|
4
|
+
export function stakeAmountToShares(
|
|
5
|
+
amount: BN,
|
|
6
|
+
totalIfShares: BN,
|
|
7
|
+
insuranceFundVaultBalance: BN
|
|
8
|
+
): BN {
|
|
9
|
+
let nShares: BN;
|
|
10
|
+
if (insuranceFundVaultBalance.gt(ZERO)) {
|
|
11
|
+
nShares = amount.mul(totalIfShares).div(insuranceFundVaultBalance);
|
|
12
|
+
} else {
|
|
13
|
+
nShares = amount;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return nShares;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function unstakeSharesToAmount(
|
|
20
|
+
nShares: BN,
|
|
21
|
+
totalIfShares: BN,
|
|
22
|
+
insuranceFundVaultBalance: BN
|
|
23
|
+
): BN {
|
|
24
|
+
let amount: BN;
|
|
25
|
+
if (totalIfShares.gt(ZERO)) {
|
|
26
|
+
amount = BN.max(
|
|
27
|
+
ZERO,
|
|
28
|
+
nShares.mul(insuranceFundVaultBalance).div(totalIfShares)
|
|
29
|
+
);
|
|
30
|
+
} else {
|
|
31
|
+
amount = ZERO;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return amount;
|
|
35
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { squareRootBN } from './utils';
|
|
2
|
+
import {
|
|
3
|
+
SPOT_MARKET_WEIGHT_PRECISION,
|
|
4
|
+
SPOT_MARKET_IMF_PRECISION,
|
|
5
|
+
ZERO,
|
|
6
|
+
BID_ASK_SPREAD_PRECISION,
|
|
7
|
+
AMM_RESERVE_PRECISION,
|
|
8
|
+
} from '../constants/numericConstants';
|
|
9
|
+
import { BN } from '@project-serum/anchor';
|
|
10
|
+
import { OraclePriceData } from '../oracles/types';
|
|
11
|
+
import { PerpMarketAccount, PerpPosition } from '..';
|
|
12
|
+
import { assert } from '../assert/assert';
|
|
13
|
+
|
|
14
|
+
export function calculateSizePremiumLiabilityWeight(
|
|
15
|
+
size: BN, // AMM_RESERVE_PRECISION
|
|
16
|
+
imfFactor: BN,
|
|
17
|
+
liabilityWeight: BN,
|
|
18
|
+
precision: BN
|
|
19
|
+
): BN {
|
|
20
|
+
if (imfFactor.eq(ZERO)) {
|
|
21
|
+
return liabilityWeight;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const sizeSqrt = squareRootBN(size.mul(new BN(10)).add(new BN(1))); //1e9 -> 1e10 -> 1e5
|
|
25
|
+
|
|
26
|
+
const denom0 = BN.max(new BN(1), SPOT_MARKET_IMF_PRECISION.div(imfFactor));
|
|
27
|
+
assert(denom0.gt(ZERO));
|
|
28
|
+
const liabilityWeightNumerator = liabilityWeight.sub(
|
|
29
|
+
liabilityWeight.div(
|
|
30
|
+
BN.max(new BN(1), SPOT_MARKET_IMF_PRECISION.div(imfFactor))
|
|
31
|
+
)
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
const denom = new BN(100_000).mul(SPOT_MARKET_IMF_PRECISION).div(precision);
|
|
35
|
+
assert(denom.gt(ZERO));
|
|
36
|
+
|
|
37
|
+
const sizePremiumLiabilityWeight = liabilityWeightNumerator.add(
|
|
38
|
+
sizeSqrt // 1e5
|
|
39
|
+
.mul(imfFactor)
|
|
40
|
+
.div(denom) // 1e5
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
const maxLiabilityWeight = BN.max(
|
|
44
|
+
liabilityWeight,
|
|
45
|
+
sizePremiumLiabilityWeight
|
|
46
|
+
);
|
|
47
|
+
return maxLiabilityWeight;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function calculateSizeDiscountAssetWeight(
|
|
51
|
+
size: BN, // AMM_RESERVE_PRECISION
|
|
52
|
+
imfFactor: BN,
|
|
53
|
+
assetWeight: BN
|
|
54
|
+
): BN {
|
|
55
|
+
if (imfFactor.eq(ZERO)) {
|
|
56
|
+
return assetWeight;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const sizeSqrt = squareRootBN(size.mul(new BN(10)).add(new BN(1))); //1e9 -> 1e10 -> 1e5
|
|
60
|
+
const imfNumerator = SPOT_MARKET_IMF_PRECISION.add(
|
|
61
|
+
SPOT_MARKET_IMF_PRECISION.div(new BN(10))
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
const sizeDiscountAssetWeight = imfNumerator
|
|
65
|
+
.mul(SPOT_MARKET_WEIGHT_PRECISION)
|
|
66
|
+
.div(
|
|
67
|
+
SPOT_MARKET_IMF_PRECISION.add(
|
|
68
|
+
sizeSqrt // 1e5
|
|
69
|
+
.mul(imfFactor)
|
|
70
|
+
.div(new BN(100_000)) // 1e5
|
|
71
|
+
)
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
const minAssetWeight = BN.min(assetWeight, sizeDiscountAssetWeight);
|
|
75
|
+
|
|
76
|
+
return minAssetWeight;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function calculateOraclePriceForPerpMargin(
|
|
80
|
+
perpPosition: PerpPosition,
|
|
81
|
+
market: PerpMarketAccount,
|
|
82
|
+
oraclePriceData: OraclePriceData
|
|
83
|
+
): BN {
|
|
84
|
+
const oraclePriceOffset = BN.min(
|
|
85
|
+
new BN(market.amm.maxSpread)
|
|
86
|
+
.mul(oraclePriceData.price)
|
|
87
|
+
.div(BID_ASK_SPREAD_PRECISION),
|
|
88
|
+
oraclePriceData.confidence.add(
|
|
89
|
+
new BN(market.amm.baseSpread)
|
|
90
|
+
.mul(oraclePriceData.price)
|
|
91
|
+
.div(BID_ASK_SPREAD_PRECISION)
|
|
92
|
+
)
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
let marginPrice: BN;
|
|
96
|
+
if (perpPosition.baseAssetAmount.gt(ZERO)) {
|
|
97
|
+
marginPrice = oraclePriceData.price.sub(oraclePriceOffset);
|
|
98
|
+
} else {
|
|
99
|
+
marginPrice = oraclePriceData.price.add(oraclePriceOffset);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return marginPrice;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export function calculateBaseAssetValueWithOracle(
|
|
106
|
+
market: PerpMarketAccount,
|
|
107
|
+
perpPosition: PerpPosition,
|
|
108
|
+
oraclePriceData: OraclePriceData
|
|
109
|
+
): BN {
|
|
110
|
+
return perpPosition.baseAssetAmount
|
|
111
|
+
.abs()
|
|
112
|
+
.mul(oraclePriceData.price)
|
|
113
|
+
.div(AMM_RESERVE_PRECISION);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export function calculateWorstCaseBaseAssetAmount(
|
|
117
|
+
perpPosition: PerpPosition
|
|
118
|
+
): BN {
|
|
119
|
+
const allBids = perpPosition.baseAssetAmount.add(perpPosition.openBids);
|
|
120
|
+
const allAsks = perpPosition.baseAssetAmount.add(perpPosition.openAsks);
|
|
121
|
+
|
|
122
|
+
if (allBids.abs().gt(allAsks.abs())) {
|
|
123
|
+
return allBids;
|
|
124
|
+
} else {
|
|
125
|
+
return allAsks;
|
|
126
|
+
}
|
|
127
|
+
}
|
package/src/math/market.ts
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import { BN } from '@project-serum/anchor';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
PerpMarketAccount,
|
|
4
|
+
PositionDirection,
|
|
5
|
+
MarginCategory,
|
|
6
|
+
SpotMarketAccount,
|
|
7
|
+
SpotBalanceType,
|
|
8
|
+
} from '../types';
|
|
3
9
|
import {
|
|
4
10
|
calculateAmmReservesAfterSwap,
|
|
5
11
|
calculatePrice,
|
|
@@ -7,16 +13,27 @@ import {
|
|
|
7
13
|
getSwapDirection,
|
|
8
14
|
calculateUpdatedAMM,
|
|
9
15
|
} from './amm';
|
|
16
|
+
import {
|
|
17
|
+
calculateSizeDiscountAssetWeight,
|
|
18
|
+
calculateSizePremiumLiabilityWeight,
|
|
19
|
+
} from './margin';
|
|
10
20
|
import { OraclePriceData } from '../oracles/types';
|
|
21
|
+
import {
|
|
22
|
+
BASE_PRECISION,
|
|
23
|
+
MARGIN_PRECISION,
|
|
24
|
+
PRICE_TO_QUOTE_PRECISION,
|
|
25
|
+
ZERO,
|
|
26
|
+
} from '../constants/numericConstants';
|
|
27
|
+
import { getTokenAmount } from './spotBalance';
|
|
11
28
|
|
|
12
29
|
/**
|
|
13
30
|
* Calculates market mark price
|
|
14
31
|
*
|
|
15
32
|
* @param market
|
|
16
|
-
* @return markPrice : Precision
|
|
33
|
+
* @return markPrice : Precision PRICE_PRECISION
|
|
17
34
|
*/
|
|
18
|
-
export function
|
|
19
|
-
market:
|
|
35
|
+
export function calculateReservePrice(
|
|
36
|
+
market: PerpMarketAccount,
|
|
20
37
|
oraclePriceData: OraclePriceData
|
|
21
38
|
): BN {
|
|
22
39
|
const newAmm = calculateUpdatedAMM(market.amm, oraclePriceData);
|
|
@@ -31,10 +48,10 @@ export function calculateMarkPrice(
|
|
|
31
48
|
* Calculates market bid price
|
|
32
49
|
*
|
|
33
50
|
* @param market
|
|
34
|
-
* @return bidPrice : Precision
|
|
51
|
+
* @return bidPrice : Precision PRICE_PRECISION
|
|
35
52
|
*/
|
|
36
53
|
export function calculateBidPrice(
|
|
37
|
-
market:
|
|
54
|
+
market: PerpMarketAccount,
|
|
38
55
|
oraclePriceData: OraclePriceData
|
|
39
56
|
): BN {
|
|
40
57
|
const { baseAssetReserve, quoteAssetReserve, newPeg } =
|
|
@@ -51,10 +68,10 @@ export function calculateBidPrice(
|
|
|
51
68
|
* Calculates market ask price
|
|
52
69
|
*
|
|
53
70
|
* @param market
|
|
54
|
-
* @return
|
|
71
|
+
* @return askPrice : Precision PRICE_PRECISION
|
|
55
72
|
*/
|
|
56
73
|
export function calculateAskPrice(
|
|
57
|
-
market:
|
|
74
|
+
market: PerpMarketAccount,
|
|
58
75
|
oraclePriceData: OraclePriceData
|
|
59
76
|
): BN {
|
|
60
77
|
const { baseAssetReserve, quoteAssetReserve, newPeg } =
|
|
@@ -70,8 +87,8 @@ export function calculateAskPrice(
|
|
|
70
87
|
export function calculateNewMarketAfterTrade(
|
|
71
88
|
baseAssetAmount: BN,
|
|
72
89
|
direction: PositionDirection,
|
|
73
|
-
market:
|
|
74
|
-
):
|
|
90
|
+
market: PerpMarketAccount
|
|
91
|
+
): PerpMarketAccount {
|
|
75
92
|
const [newQuoteAssetReserve, newBaseAssetReserve] =
|
|
76
93
|
calculateAmmReservesAfterSwap(
|
|
77
94
|
market.amm,
|
|
@@ -89,12 +106,12 @@ export function calculateNewMarketAfterTrade(
|
|
|
89
106
|
return newMarket;
|
|
90
107
|
}
|
|
91
108
|
|
|
92
|
-
export function
|
|
93
|
-
market:
|
|
109
|
+
export function calculateOracleReserveSpread(
|
|
110
|
+
market: PerpMarketAccount,
|
|
94
111
|
oraclePriceData: OraclePriceData
|
|
95
112
|
): BN {
|
|
96
|
-
const
|
|
97
|
-
return calculateOracleSpread(
|
|
113
|
+
const reservePrice = calculateReservePrice(market, oraclePriceData);
|
|
114
|
+
return calculateOracleSpread(reservePrice, oraclePriceData);
|
|
98
115
|
}
|
|
99
116
|
|
|
100
117
|
export function calculateOracleSpread(
|
|
@@ -103,3 +120,117 @@ export function calculateOracleSpread(
|
|
|
103
120
|
): BN {
|
|
104
121
|
return price.sub(oraclePriceData.price);
|
|
105
122
|
}
|
|
123
|
+
|
|
124
|
+
export function calculateMarketMarginRatio(
|
|
125
|
+
market: PerpMarketAccount,
|
|
126
|
+
size: BN,
|
|
127
|
+
marginCategory: MarginCategory
|
|
128
|
+
): number {
|
|
129
|
+
let marginRatio;
|
|
130
|
+
switch (marginCategory) {
|
|
131
|
+
case 'Initial':
|
|
132
|
+
marginRatio = calculateSizePremiumLiabilityWeight(
|
|
133
|
+
size,
|
|
134
|
+
market.imfFactor,
|
|
135
|
+
new BN(market.marginRatioInitial),
|
|
136
|
+
MARGIN_PRECISION
|
|
137
|
+
).toNumber();
|
|
138
|
+
break;
|
|
139
|
+
case 'Maintenance':
|
|
140
|
+
marginRatio = calculateSizePremiumLiabilityWeight(
|
|
141
|
+
size,
|
|
142
|
+
market.imfFactor,
|
|
143
|
+
new BN(market.marginRatioMaintenance),
|
|
144
|
+
MARGIN_PRECISION
|
|
145
|
+
).toNumber();
|
|
146
|
+
break;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return marginRatio;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export function calculateUnrealizedAssetWeight(
|
|
153
|
+
market: PerpMarketAccount,
|
|
154
|
+
quoteSpotMarket: SpotMarketAccount,
|
|
155
|
+
unrealizedPnl: BN,
|
|
156
|
+
marginCategory: MarginCategory,
|
|
157
|
+
oraclePriceData: OraclePriceData
|
|
158
|
+
): BN {
|
|
159
|
+
let assetWeight: BN;
|
|
160
|
+
switch (marginCategory) {
|
|
161
|
+
case 'Initial':
|
|
162
|
+
assetWeight = new BN(market.unrealizedInitialAssetWeight);
|
|
163
|
+
|
|
164
|
+
if (market.unrealizedMaxImbalance.gt(ZERO)) {
|
|
165
|
+
const netUnsettledPnl = calculateNetUserPnlImbalance(
|
|
166
|
+
market,
|
|
167
|
+
quoteSpotMarket,
|
|
168
|
+
oraclePriceData
|
|
169
|
+
);
|
|
170
|
+
if (netUnsettledPnl.gt(market.unrealizedMaxImbalance)) {
|
|
171
|
+
assetWeight = assetWeight
|
|
172
|
+
.mul(market.unrealizedMaxImbalance)
|
|
173
|
+
.div(netUnsettledPnl);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
assetWeight = calculateSizeDiscountAssetWeight(
|
|
178
|
+
unrealizedPnl,
|
|
179
|
+
market.unrealizedImfFactor,
|
|
180
|
+
assetWeight
|
|
181
|
+
);
|
|
182
|
+
break;
|
|
183
|
+
case 'Maintenance':
|
|
184
|
+
assetWeight = new BN(market.unrealizedMaintenanceAssetWeight);
|
|
185
|
+
break;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
return assetWeight;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export function calculateMarketAvailablePNL(
|
|
192
|
+
perpMarket: PerpMarketAccount,
|
|
193
|
+
spotMarket: SpotMarketAccount
|
|
194
|
+
): BN {
|
|
195
|
+
return getTokenAmount(
|
|
196
|
+
perpMarket.pnlPool.balance,
|
|
197
|
+
spotMarket,
|
|
198
|
+
SpotBalanceType.DEPOSIT
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
export function calculateNetUserPnl(
|
|
203
|
+
perpMarket: PerpMarketAccount,
|
|
204
|
+
oraclePriceData: OraclePriceData
|
|
205
|
+
): BN {
|
|
206
|
+
const netUserPositionValue = perpMarket.amm.netBaseAssetAmount
|
|
207
|
+
.mul(oraclePriceData.price)
|
|
208
|
+
.div(BASE_PRECISION)
|
|
209
|
+
.div(PRICE_TO_QUOTE_PRECISION);
|
|
210
|
+
|
|
211
|
+
const netUserCostBasis = perpMarket.amm.quoteAssetAmountLong
|
|
212
|
+
.add(perpMarket.amm.quoteAssetAmountShort)
|
|
213
|
+
.sub(perpMarket.amm.cumulativeSocialLoss);
|
|
214
|
+
|
|
215
|
+
const netUserPnl = netUserPositionValue.add(netUserCostBasis);
|
|
216
|
+
|
|
217
|
+
return netUserPnl;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
export function calculateNetUserPnlImbalance(
|
|
221
|
+
perpMarket: PerpMarketAccount,
|
|
222
|
+
spotMarket: SpotMarketAccount,
|
|
223
|
+
oraclePriceData: OraclePriceData
|
|
224
|
+
): BN {
|
|
225
|
+
const netUserPnl = calculateNetUserPnl(perpMarket, oraclePriceData);
|
|
226
|
+
|
|
227
|
+
const pnlPool = getTokenAmount(
|
|
228
|
+
perpMarket.pnlPool.balance,
|
|
229
|
+
spotMarket,
|
|
230
|
+
SpotBalanceType.DEPOSIT
|
|
231
|
+
);
|
|
232
|
+
|
|
233
|
+
const imbalance = netUserPnl.sub(pnlPool);
|
|
234
|
+
|
|
235
|
+
return imbalance;
|
|
236
|
+
}
|
package/src/math/oracles.ts
CHANGED
|
@@ -1,7 +1,29 @@
|
|
|
1
1
|
import { AMM, OracleGuardRails } from '../types';
|
|
2
2
|
import { OraclePriceData } from '../oracles/types';
|
|
3
|
-
import {
|
|
4
|
-
|
|
3
|
+
import {
|
|
4
|
+
BID_ASK_SPREAD_PRECISION,
|
|
5
|
+
MARGIN_PRECISION,
|
|
6
|
+
PRICE_PRECISION,
|
|
7
|
+
ONE,
|
|
8
|
+
ZERO,
|
|
9
|
+
} from '../constants/numericConstants';
|
|
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
|
+
}
|
|
5
27
|
|
|
6
28
|
export function isOracleValid(
|
|
7
29
|
amm: AMM,
|
|
@@ -9,22 +31,24 @@ export function isOracleValid(
|
|
|
9
31
|
oracleGuardRails: OracleGuardRails,
|
|
10
32
|
slot: number
|
|
11
33
|
): boolean {
|
|
12
|
-
const isOraclePriceNonPositive = oraclePriceData.price.
|
|
34
|
+
const isOraclePriceNonPositive = oraclePriceData.price.lte(ZERO);
|
|
13
35
|
const isOraclePriceTooVolatile =
|
|
14
36
|
oraclePriceData.price
|
|
15
|
-
.div(BN.max(ONE, amm.lastOraclePriceTwap))
|
|
37
|
+
.div(BN.max(ONE, amm.historicalOracleData.lastOraclePriceTwap))
|
|
16
38
|
.gt(oracleGuardRails.validity.tooVolatileRatio) ||
|
|
17
|
-
amm.lastOraclePriceTwap
|
|
39
|
+
amm.historicalOracleData.lastOraclePriceTwap
|
|
18
40
|
.div(BN.max(ONE, oraclePriceData.price))
|
|
19
41
|
.gt(oracleGuardRails.validity.tooVolatileRatio);
|
|
20
42
|
|
|
21
|
-
const isConfidenceTooLarge =
|
|
22
|
-
.
|
|
23
|
-
.
|
|
43
|
+
const isConfidenceTooLarge = new BN(amm.baseSpread)
|
|
44
|
+
.add(BN.max(ONE, oraclePriceData.confidence))
|
|
45
|
+
.mul(BID_ASK_SPREAD_PRECISION)
|
|
46
|
+
.div(oraclePriceData.price)
|
|
47
|
+
.gt(new BN(amm.maxSpread));
|
|
24
48
|
|
|
25
49
|
const oracleIsStale = oraclePriceData.slot
|
|
26
50
|
.sub(new BN(slot))
|
|
27
|
-
.gt(oracleGuardRails.validity.
|
|
51
|
+
.gt(oracleGuardRails.validity.slotsBeforeStaleForAmm);
|
|
28
52
|
|
|
29
53
|
return !(
|
|
30
54
|
!oraclePriceData.hasSufficientNumberOfDataPoints ||
|
|
@@ -34,3 +58,33 @@ export function isOracleValid(
|
|
|
34
58
|
isConfidenceTooLarge
|
|
35
59
|
);
|
|
36
60
|
}
|
|
61
|
+
|
|
62
|
+
export function isOracleTooDivergent(
|
|
63
|
+
amm: AMM,
|
|
64
|
+
oraclePriceData: OraclePriceData,
|
|
65
|
+
oracleGuardRails: OracleGuardRails,
|
|
66
|
+
now: BN
|
|
67
|
+
): boolean {
|
|
68
|
+
const sinceLastUpdate = now.sub(
|
|
69
|
+
amm.historicalOracleData.lastOraclePriceTwapTs
|
|
70
|
+
);
|
|
71
|
+
const sinceStart = BN.max(ZERO, new BN(60 * 5).sub(sinceLastUpdate));
|
|
72
|
+
const oracleTwap5min = amm.historicalOracleData.lastOraclePriceTwap5min
|
|
73
|
+
.mul(sinceStart)
|
|
74
|
+
.add(oraclePriceData.price)
|
|
75
|
+
.mul(sinceLastUpdate)
|
|
76
|
+
.div(sinceStart.add(sinceLastUpdate));
|
|
77
|
+
|
|
78
|
+
const oracleSpread = oracleTwap5min.sub(oraclePriceData.price);
|
|
79
|
+
const oracleSpreadPct = oracleSpread.mul(PRICE_PRECISION).div(oracleTwap5min);
|
|
80
|
+
|
|
81
|
+
const tooDivergent = oracleSpreadPct
|
|
82
|
+
.abs()
|
|
83
|
+
.gte(
|
|
84
|
+
BID_ASK_SPREAD_PRECISION.mul(
|
|
85
|
+
oracleGuardRails.priceDivergence.markOracleDivergenceNumerator
|
|
86
|
+
).div(oracleGuardRails.priceDivergence.markOracleDivergenceDenominator)
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
return tooDivergent;
|
|
90
|
+
}
|