@drift-labs/sdk 0.2.0-temp.2 → 2.0.0
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 +27 -29
- package/lib/accounts/bulkAccountLoader.d.ts +2 -0
- package/lib/accounts/bulkAccountLoader.js +36 -29
- package/lib/accounts/bulkUserStatsSubscription.d.ts +7 -0
- package/lib/accounts/bulkUserStatsSubscription.js +21 -0
- package/lib/accounts/bulkUserSubscription.d.ts +2 -2
- 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 → pollingDriftClientAccountSubscriber.d.ts} +20 -25
- package/lib/accounts/{pollingClearingHouseAccountSubscriber.js → pollingDriftClientAccountSubscriber.js} +45 -49
- package/lib/accounts/{pollingOracleSubscriber.d.ts → pollingOracleAccountSubscriber.d.ts} +2 -2
- package/lib/accounts/{pollingOracleSubscriber.js → pollingOracleAccountSubscriber.js} +3 -3
- package/lib/accounts/pollingUserAccountSubscriber.d.ts +1 -1
- package/lib/accounts/pollingUserAccountSubscriber.js +5 -11
- package/lib/accounts/pollingUserStatsAccountSubscriber.d.ts +27 -0
- package/lib/accounts/pollingUserStatsAccountSubscriber.js +107 -0
- package/lib/accounts/types.d.ts +26 -15
- package/lib/accounts/webSocketDriftClientAccountSubscriber.d.ts +49 -0
- package/lib/accounts/{webSocketClearingHouseAccountSubscriber.js → webSocketDriftClientAccountSubscriber.js} +47 -45
- 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/marketAddresses.js +1 -1
- package/lib/addresses/pda.d.ts +15 -9
- package/lib/addresses/pda.js +73 -35
- package/lib/adminClient.d.ts +65 -0
- package/lib/adminClient.js +637 -0
- package/lib/config.d.ts +10 -10
- package/lib/config.js +26 -22
- package/lib/constants/numericConstants.d.ts +29 -12
- package/lib/constants/numericConstants.js +40 -21
- package/lib/constants/perpMarkets.d.ts +18 -0
- package/lib/constants/{markets.js → perpMarkets.js} +20 -9
- package/lib/constants/spotMarkets.d.ts +19 -0
- package/lib/constants/spotMarkets.js +63 -0
- package/lib/dlob/DLOB.d.ts +82 -0
- package/lib/dlob/DLOB.js +694 -0
- package/lib/dlob/DLOBNode.d.ts +54 -0
- package/lib/dlob/DLOBNode.js +77 -0
- package/lib/dlob/NodeList.d.ts +27 -0
- package/lib/dlob/NodeList.js +144 -0
- package/lib/driftClient.d.ts +234 -0
- package/lib/driftClient.js +2108 -0
- package/lib/{clearingHouseConfig.d.ts → driftClientConfig.d.ts} +9 -9
- package/lib/{clearingHouseConfig.js → driftClientConfig.js} +0 -0
- package/lib/events/eventList.d.ts +0 -1
- package/lib/events/eventList.js +0 -7
- package/lib/events/eventSubscriber.d.ts +5 -2
- package/lib/events/eventSubscriber.js +25 -11
- package/lib/events/fetchLogs.d.ts +13 -2
- package/lib/events/fetchLogs.js +45 -14
- package/lib/events/pollingLogProvider.d.ts +2 -1
- package/lib/events/pollingLogProvider.js +7 -3
- package/lib/events/sort.js +8 -11
- package/lib/events/txEventCache.d.ts +0 -2
- package/lib/events/txEventCache.js +0 -14
- package/lib/events/types.d.ts +11 -3
- package/lib/events/types.js +8 -0
- package/lib/events/webSocketLogProvider.js +1 -1
- package/lib/examples/makeTradeExample.js +30 -18
- package/lib/factory/bigNum.d.ts +8 -4
- package/lib/factory/bigNum.js +109 -19
- package/lib/idl/drift.json +8392 -0
- package/lib/index.d.ts +29 -12
- package/lib/index.js +29 -12
- package/lib/math/amm.d.ts +9 -6
- package/lib/math/amm.js +91 -38
- package/lib/math/conversion.js +1 -1
- package/lib/math/exchangeStatus.d.ts +4 -0
- package/lib/math/exchangeStatus.js +18 -0
- package/lib/math/funding.d.ts +6 -6
- package/lib/math/funding.js +23 -21
- 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 +82 -0
- package/lib/math/market.d.ts +14 -9
- package/lib/math/market.js +70 -10
- package/lib/math/oracles.d.ts +4 -0
- package/lib/math/oracles.js +36 -8
- package/lib/math/orders.d.ts +16 -6
- package/lib/math/orders.js +97 -17
- package/lib/math/position.d.ts +27 -13
- package/lib/math/position.js +91 -37
- package/lib/math/repeg.js +17 -8
- 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 +27 -31
- 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 +4 -4
- package/lib/orderParams.js +12 -4
- package/lib/serum/serumFulfillmentConfigMap.d.ts +10 -0
- package/lib/serum/serumFulfillmentConfigMap.js +17 -0
- package/lib/serum/serumSubscriber.d.ts +27 -0
- package/lib/serum/serumSubscriber.js +56 -0
- package/lib/serum/types.d.ts +11 -0
- package/{src/oracles → lib/serum}/types.js +0 -0
- package/lib/tokenFaucet.d.ts +1 -0
- package/lib/tokenFaucet.js +23 -12
- 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/types.d.ts +631 -222
- package/lib/types.js +137 -24
- package/lib/user.d.ts +228 -0
- package/lib/user.js +959 -0
- package/lib/userConfig.d.ts +14 -0
- package/lib/{clearingHouseUserConfig.js → userConfig.js} +0 -0
- package/lib/userMap/userMap.d.ts +41 -0
- package/lib/userMap/userMap.js +85 -0
- package/lib/userMap/userStatsMap.d.ts +19 -0
- package/lib/userMap/userStatsMap.js +68 -0
- package/lib/userName.d.ts +1 -0
- package/lib/userName.js +3 -2
- package/lib/userStats.d.ts +18 -0
- package/lib/userStats.js +49 -0
- package/lib/userStatsConfig.d.ts +14 -0
- package/{src/clearingHouseConfig.js → lib/userStatsConfig.js} +0 -0
- package/lib/util/getTokenAddress.d.ts +2 -0
- package/lib/util/getTokenAddress.js +9 -0
- package/package.json +12 -5
- package/src/accounts/bulkAccountLoader.ts +44 -34
- package/src/accounts/bulkUserStatsSubscription.ts +33 -0
- package/src/accounts/bulkUserSubscription.ts +2 -3
- package/src/accounts/fetch.ts +27 -2
- package/src/accounts/{pollingClearingHouseAccountSubscriber.ts → pollingDriftClientAccountSubscriber.ts} +65 -75
- package/src/accounts/{pollingOracleSubscriber.ts → pollingOracleAccountSubscriber.ts} +2 -2
- package/src/accounts/pollingUserAccountSubscriber.ts +5 -12
- package/src/accounts/pollingUserStatsAccountSubscriber.ts +166 -0
- package/src/accounts/types.ts +35 -15
- package/src/accounts/{webSocketClearingHouseAccountSubscriber.ts → webSocketDriftClientAccountSubscriber.ts} +78 -73
- package/src/accounts/webSocketUserStatsAccountSubsriber.ts +80 -0
- package/src/addresses/marketAddresses.ts +3 -4
- package/src/addresses/pda.ts +105 -33
- package/src/adminClient.ts +1207 -0
- package/src/config.ts +41 -34
- package/src/constants/numericConstants.ts +59 -26
- package/src/constants/{markets.ts → perpMarkets.ts} +22 -11
- package/src/constants/spotMarkets.ts +83 -0
- package/src/dlob/DLOB.ts +1120 -0
- package/src/dlob/DLOBNode.ts +155 -0
- package/src/dlob/NodeList.ts +195 -0
- package/src/driftClient.ts +3594 -0
- package/src/{clearingHouseConfig.ts → driftClientConfig.ts} +9 -8
- package/src/events/eventList.ts +1 -8
- package/src/events/eventSubscriber.ts +36 -14
- package/src/events/fetchLogs.ts +60 -15
- package/src/events/pollingLogProvider.ts +11 -3
- package/src/events/sort.ts +11 -15
- package/src/events/txEventCache.ts +0 -16
- package/src/events/types.ts +27 -2
- package/src/events/webSocketLogProvider.ts +1 -1
- package/src/examples/makeTradeExample.js +152 -75
- package/src/examples/makeTradeExample.ts +44 -28
- package/src/factory/bigNum.ts +150 -22
- package/src/idl/drift.json +8392 -0
- package/src/idl/pyth.json +98 -2
- package/src/index.ts +29 -12
- package/src/math/amm.ts +161 -48
- package/src/math/conversion.ts +2 -2
- package/src/math/exchangeStatus.ts +31 -0
- package/src/math/funding.ts +41 -31
- package/src/math/insurance.ts +35 -0
- package/src/math/margin.ts +133 -0
- package/src/math/market.ts +143 -14
- package/src/math/oracles.ts +63 -9
- package/src/math/orders.ts +168 -26
- package/src/math/position.ts +133 -59
- package/src/math/repeg.ts +19 -9
- 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 +33 -37
- 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 +16 -8
- package/src/serum/serumFulfillmentConfigMap.ts +26 -0
- package/src/serum/serumSubscriber.ts +99 -0
- package/src/serum/types.ts +13 -0
- package/src/tokenFaucet.ts +38 -15
- package/src/tx/retryTxSender.ts +16 -5
- package/src/tx/types.ts +2 -1
- package/src/types.ts +594 -195
- package/src/user.ts +1599 -0
- package/src/{clearingHouseUserConfig.ts → userConfig.ts} +5 -5
- package/src/userMap/userMap.ts +124 -0
- package/src/userMap/userStatsMap.ts +108 -0
- package/src/userName.ts +2 -1
- package/src/userStats.ts +75 -0
- package/src/userStatsConfig.ts +18 -0
- package/src/util/getTokenAddress.ts +18 -0
- package/tests/bn/test.ts +46 -11
- package/tests/dlob/helpers.ts +619 -0
- package/tests/dlob/test.ts +4586 -0
- package/lib/accounts/webSocketClearingHouseAccountSubscriber.d.ts +0 -49
- package/lib/admin.d.ts +0 -44
- package/lib/admin.js +0 -438
- package/lib/clearingHouse.d.ts +0 -146
- package/lib/clearingHouse.js +0 -1154
- package/lib/clearingHouseUser.d.ts +0 -187
- package/lib/clearingHouseUser.js +0 -634
- package/lib/clearingHouseUserConfig.d.ts +0 -14
- package/lib/constants/banks.d.ts +0 -16
- package/lib/constants/banks.js +0 -41
- package/lib/constants/markets.d.ts +0 -19
- package/lib/idl/clearing_house.json +0 -4464
- 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/accounts/bulkAccountLoader.js +0 -197
- package/src/accounts/bulkUserSubscription.js +0 -33
- package/src/accounts/pollingClearingHouseAccountSubscriber.js +0 -311
- package/src/accounts/pollingOracleSubscriber.js +0 -93
- package/src/accounts/pollingTokenAccountSubscriber.js +0 -90
- package/src/accounts/pollingUserAccountSubscriber.js +0 -132
- package/src/accounts/types.js +0 -10
- package/src/accounts/utils.js +0 -7
- package/src/accounts/webSocketAccountSubscriber.js +0 -93
- package/src/accounts/webSocketClearingHouseAccountSubscriber.js +0 -233
- package/src/accounts/webSocketUserAccountSubscriber.js +0 -62
- package/src/addresses/marketAddresses.js +0 -26
- package/src/admin.js +0 -517
- package/src/admin.ts +0 -730
- package/src/clearingHouse.ts +0 -1828
- package/src/clearingHouseUser.ts +0 -978
- package/src/clearingHouseUserConfig.js +0 -2
- package/src/config.js +0 -67
- package/src/constants/banks.js +0 -42
- package/src/constants/banks.ts +0 -50
- package/src/constants/markets.js +0 -42
- package/src/constants/numericConstants.js +0 -41
- package/src/events/eventSubscriber.js +0 -139
- package/src/events/fetchLogs.js +0 -50
- package/src/events/pollingLogProvider.js +0 -64
- package/src/events/sort.js +0 -44
- package/src/events/txEventCache.js +0 -71
- package/src/events/types.js +0 -20
- package/src/events/webSocketLogProvider.js +0 -41
- package/src/factory/bigNum.js +0 -390
- package/src/factory/oracleClient.js +0 -20
- package/src/idl/clearing_house.json +0 -4464
- package/src/index.js +0 -69
- package/src/math/amm.js +0 -369
- package/src/math/auction.js +0 -42
- package/src/math/bankBalance.ts +0 -112
- package/src/math/conversion.js +0 -11
- package/src/math/funding.js +0 -248
- package/src/math/oracles.js +0 -26
- package/src/math/repeg.js +0 -128
- package/src/math/state.js +0 -15
- package/src/math/state.ts +0 -14
- package/src/math/trade.js +0 -253
- package/src/math/utils.js +0 -26
- package/src/math/utils.js.map +0 -1
- package/src/mockUSDCFaucet.js +0 -280
- package/src/oracles/oracleClientCache.js +0 -19
- package/src/oracles/pythClient.js +0 -46
- package/src/oracles/quoteAssetOracleClient.js +0 -32
- package/src/oracles/switchboardClient.js +0 -69
- package/src/orderParams.js +0 -20
- package/src/orders.ts +0 -245
- package/src/slot/SlotSubscriber.js +0 -39
- package/src/tokenFaucet.js +0 -189
- package/src/types.js +0 -125
- package/src/userName.js +0 -20
- package/src/wallet.js +0 -35
package/src/math/funding.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
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 { calculateMarkPrice } from './market';
|
|
8
|
+
import { PerpMarketAccount, isVariant } from '../types';
|
|
10
9
|
import { OraclePriceData } from '../oracles/types';
|
|
10
|
+
import { calculateBidAskPrice } from './amm';
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
*
|
|
@@ -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,10 +48,8 @@ export async function calculateAllEstimatedFundingRate(
|
|
|
48
48
|
secondsInHour,
|
|
49
49
|
BN.max(ZERO, secondsInHour.sub(timeSinceLastMarkChange))
|
|
50
50
|
);
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
oraclePriceData
|
|
54
|
-
);
|
|
51
|
+
const [bid, ask] = calculateBidAskPrice(market.amm, oraclePriceData);
|
|
52
|
+
const baseAssetPriceWithMantissa = bid.add(ask).div(new BN(2));
|
|
55
53
|
|
|
56
54
|
const markTwapWithMantissa = markTwapTimeSinceLastUpdate
|
|
57
55
|
.mul(lastMarkTwapWithMantissa)
|
|
@@ -60,8 +58,10 @@ export async function calculateAllEstimatedFundingRate(
|
|
|
60
58
|
|
|
61
59
|
// calculate real-time (predicted) oracle twap
|
|
62
60
|
// note: oracle twap depends on `when the chord is struck` (market is trade)
|
|
63
|
-
const lastOracleTwapWithMantissa =
|
|
64
|
-
|
|
61
|
+
const lastOracleTwapWithMantissa =
|
|
62
|
+
market.amm.historicalOracleData.lastOraclePriceTwap;
|
|
63
|
+
const lastOraclePriceTwapTs =
|
|
64
|
+
market.amm.historicalOracleData.lastOraclePriceTwapTs;
|
|
65
65
|
|
|
66
66
|
const oracleInvalidDuration = BN.max(
|
|
67
67
|
ZERO,
|
|
@@ -85,12 +85,12 @@ export async function calculateAllEstimatedFundingRate(
|
|
|
85
85
|
const oracleLiveVsTwap = oraclePrice
|
|
86
86
|
.sub(lastOracleTwapWithMantissa)
|
|
87
87
|
.abs()
|
|
88
|
-
.mul(
|
|
88
|
+
.mul(PRICE_PRECISION)
|
|
89
89
|
.mul(new BN(100))
|
|
90
90
|
.div(lastOracleTwapWithMantissa);
|
|
91
91
|
|
|
92
92
|
// verify pyth live input is within 10% of last twap for live update
|
|
93
|
-
if (oracleLiveVsTwap.lte(
|
|
93
|
+
if (oracleLiveVsTwap.lte(PRICE_PRECISION.mul(new BN(10)))) {
|
|
94
94
|
oracleTwapWithMantissa = oracleTwapTimeSinceLastUpdate
|
|
95
95
|
.mul(lastOracleTwapWithMantissa)
|
|
96
96
|
.add(timeSinceLastMarkChange.mul(oraclePrice))
|
|
@@ -108,7 +108,7 @@ export async function calculateAllEstimatedFundingRate(
|
|
|
108
108
|
);
|
|
109
109
|
|
|
110
110
|
const twapSpreadPct = twapSpread
|
|
111
|
-
.mul(
|
|
111
|
+
.mul(PRICE_PRECISION)
|
|
112
112
|
.mul(new BN(100))
|
|
113
113
|
.div(shrunkLastOracleTwapwithMantissa);
|
|
114
114
|
|
|
@@ -125,7 +125,7 @@ export async function calculateAllEstimatedFundingRate(
|
|
|
125
125
|
const interpRateQuote = twapSpreadPct
|
|
126
126
|
.mul(periodAdjustment)
|
|
127
127
|
.div(hoursInDay)
|
|
128
|
-
.div(
|
|
128
|
+
.div(PRICE_PRECISION.div(QUOTE_PRECISION));
|
|
129
129
|
|
|
130
130
|
let feePoolSize = calculateFundingPool(market);
|
|
131
131
|
if (interpRateQuote.lt(new BN(0))) {
|
|
@@ -135,9 +135,11 @@ export async function calculateAllEstimatedFundingRate(
|
|
|
135
135
|
let cappedAltEst: BN;
|
|
136
136
|
let largerSide: BN;
|
|
137
137
|
let smallerSide: BN;
|
|
138
|
-
if (
|
|
139
|
-
|
|
140
|
-
|
|
138
|
+
if (
|
|
139
|
+
market.amm.baseAssetAmountLong.gt(market.amm.baseAssetAmountShort.abs())
|
|
140
|
+
) {
|
|
141
|
+
largerSide = market.amm.baseAssetAmountLong.abs();
|
|
142
|
+
smallerSide = market.amm.baseAssetAmountShort.abs();
|
|
141
143
|
if (twapSpread.gt(new BN(0))) {
|
|
142
144
|
return [
|
|
143
145
|
markTwapWithMantissa,
|
|
@@ -147,9 +149,11 @@ export async function calculateAllEstimatedFundingRate(
|
|
|
147
149
|
interpEst,
|
|
148
150
|
];
|
|
149
151
|
}
|
|
150
|
-
} else if (
|
|
151
|
-
|
|
152
|
-
|
|
152
|
+
} else if (
|
|
153
|
+
market.amm.baseAssetAmountLong.lt(market.amm.baseAssetAmountShort.abs())
|
|
154
|
+
) {
|
|
155
|
+
largerSide = market.amm.baseAssetAmountShort.abs();
|
|
156
|
+
smallerSide = market.amm.baseAssetAmountLong.abs();
|
|
153
157
|
if (twapSpread.lt(new BN(0))) {
|
|
154
158
|
return [
|
|
155
159
|
markTwapWithMantissa,
|
|
@@ -173,12 +177,12 @@ export async function calculateAllEstimatedFundingRate(
|
|
|
173
177
|
// funding smaller flow
|
|
174
178
|
cappedAltEst = smallerSide.mul(twapSpread).div(hoursInDay);
|
|
175
179
|
const feePoolTopOff = feePoolSize
|
|
176
|
-
.mul(
|
|
180
|
+
.mul(PRICE_PRECISION.div(QUOTE_PRECISION))
|
|
177
181
|
.mul(AMM_RESERVE_PRECISION);
|
|
178
182
|
cappedAltEst = cappedAltEst.add(feePoolTopOff).div(largerSide);
|
|
179
183
|
|
|
180
184
|
cappedAltEst = cappedAltEst
|
|
181
|
-
.mul(
|
|
185
|
+
.mul(PRICE_PRECISION)
|
|
182
186
|
.mul(new BN(100))
|
|
183
187
|
.div(oracleTwapWithMantissa)
|
|
184
188
|
.mul(periodAdjustment);
|
|
@@ -208,7 +212,7 @@ export async function calculateAllEstimatedFundingRate(
|
|
|
208
212
|
* @returns Estimated funding rate. : Precision //TODO-PRECISION
|
|
209
213
|
*/
|
|
210
214
|
export async function calculateEstimatedFundingRate(
|
|
211
|
-
market:
|
|
215
|
+
market: PerpMarketAccount,
|
|
212
216
|
oraclePriceData?: OraclePriceData,
|
|
213
217
|
periodAdjustment: BN = new BN(1),
|
|
214
218
|
estimationMethod?: 'interpolated' | 'lowerbound' | 'capped'
|
|
@@ -238,7 +242,7 @@ export async function calculateEstimatedFundingRate(
|
|
|
238
242
|
* @returns Estimated funding rate. : Precision //TODO-PRECISION
|
|
239
243
|
*/
|
|
240
244
|
export async function calculateLongShortFundingRate(
|
|
241
|
-
market:
|
|
245
|
+
market: PerpMarketAccount,
|
|
242
246
|
oraclePriceData?: OraclePriceData,
|
|
243
247
|
periodAdjustment: BN = new BN(1)
|
|
244
248
|
): Promise<[BN, BN]> {
|
|
@@ -249,9 +253,11 @@ export async function calculateLongShortFundingRate(
|
|
|
249
253
|
periodAdjustment
|
|
250
254
|
);
|
|
251
255
|
|
|
252
|
-
if (market.baseAssetAmountLong.gt(market.baseAssetAmountShort)) {
|
|
256
|
+
if (market.amm.baseAssetAmountLong.gt(market.amm.baseAssetAmountShort)) {
|
|
253
257
|
return [cappedAltEst, interpEst];
|
|
254
|
-
} else if (
|
|
258
|
+
} else if (
|
|
259
|
+
market.amm.baseAssetAmountLong.lt(market.amm.baseAssetAmountShort)
|
|
260
|
+
) {
|
|
255
261
|
return [interpEst, cappedAltEst];
|
|
256
262
|
} else {
|
|
257
263
|
return [interpEst, interpEst];
|
|
@@ -266,7 +272,7 @@ export async function calculateLongShortFundingRate(
|
|
|
266
272
|
* @returns Estimated funding rate. : Precision //TODO-PRECISION
|
|
267
273
|
*/
|
|
268
274
|
export async function calculateLongShortFundingRateAndLiveTwaps(
|
|
269
|
-
market:
|
|
275
|
+
market: PerpMarketAccount,
|
|
270
276
|
oraclePriceData?: OraclePriceData,
|
|
271
277
|
periodAdjustment: BN = new BN(1)
|
|
272
278
|
): Promise<[BN, BN, BN, BN]> {
|
|
@@ -277,9 +283,13 @@ export async function calculateLongShortFundingRateAndLiveTwaps(
|
|
|
277
283
|
periodAdjustment
|
|
278
284
|
);
|
|
279
285
|
|
|
280
|
-
if (
|
|
286
|
+
if (
|
|
287
|
+
market.amm.baseAssetAmountLong.gt(market.amm.baseAssetAmountShort.abs())
|
|
288
|
+
) {
|
|
281
289
|
return [markTwapLive, oracleTwapLive, cappedAltEst, interpEst];
|
|
282
|
-
} else if (
|
|
290
|
+
} else if (
|
|
291
|
+
market.amm.baseAssetAmountLong.lt(market.amm.baseAssetAmountShort.abs())
|
|
292
|
+
) {
|
|
283
293
|
return [markTwapLive, oracleTwapLive, interpEst, cappedAltEst];
|
|
284
294
|
} else {
|
|
285
295
|
return [markTwapLive, oracleTwapLive, interpEst, interpEst];
|
|
@@ -291,7 +301,7 @@ export async function calculateLongShortFundingRateAndLiveTwaps(
|
|
|
291
301
|
* @param market
|
|
292
302
|
* @returns Estimated fee pool size
|
|
293
303
|
*/
|
|
294
|
-
export function calculateFundingPool(market:
|
|
304
|
+
export function calculateFundingPool(market: PerpMarketAccount): BN {
|
|
295
305
|
// todo
|
|
296
306
|
const totalFeeLB = market.amm.totalExchangeFee.div(new BN(2));
|
|
297
307
|
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,133 @@
|
|
|
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 { isVariant } from '../types';
|
|
13
|
+
import { assert } from '../assert/assert';
|
|
14
|
+
|
|
15
|
+
export function calculateSizePremiumLiabilityWeight(
|
|
16
|
+
size: BN, // AMM_RESERVE_PRECISION
|
|
17
|
+
imfFactor: BN,
|
|
18
|
+
liabilityWeight: BN,
|
|
19
|
+
precision: BN
|
|
20
|
+
): BN {
|
|
21
|
+
if (imfFactor.eq(ZERO)) {
|
|
22
|
+
return liabilityWeight;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const sizeSqrt = squareRootBN(size.mul(new BN(10)).add(new BN(1))); //1e9 -> 1e10 -> 1e5
|
|
26
|
+
|
|
27
|
+
const denom0 = BN.max(new BN(1), SPOT_MARKET_IMF_PRECISION.div(imfFactor));
|
|
28
|
+
assert(denom0.gt(ZERO));
|
|
29
|
+
const liabilityWeightNumerator = liabilityWeight.sub(
|
|
30
|
+
liabilityWeight.div(
|
|
31
|
+
BN.max(new BN(1), SPOT_MARKET_IMF_PRECISION.div(imfFactor))
|
|
32
|
+
)
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
const denom = new BN(100_000).mul(SPOT_MARKET_IMF_PRECISION).div(precision);
|
|
36
|
+
assert(denom.gt(ZERO));
|
|
37
|
+
|
|
38
|
+
const sizePremiumLiabilityWeight = liabilityWeightNumerator.add(
|
|
39
|
+
sizeSqrt // 1e5
|
|
40
|
+
.mul(imfFactor)
|
|
41
|
+
.div(denom) // 1e5
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
const maxLiabilityWeight = BN.max(
|
|
45
|
+
liabilityWeight,
|
|
46
|
+
sizePremiumLiabilityWeight
|
|
47
|
+
);
|
|
48
|
+
return maxLiabilityWeight;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function calculateSizeDiscountAssetWeight(
|
|
52
|
+
size: BN, // AMM_RESERVE_PRECISION
|
|
53
|
+
imfFactor: BN,
|
|
54
|
+
assetWeight: BN
|
|
55
|
+
): BN {
|
|
56
|
+
if (imfFactor.eq(ZERO)) {
|
|
57
|
+
return assetWeight;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const sizeSqrt = squareRootBN(size.mul(new BN(10)).add(new BN(1))); //1e9 -> 1e10 -> 1e5
|
|
61
|
+
const imfNumerator = SPOT_MARKET_IMF_PRECISION.add(
|
|
62
|
+
SPOT_MARKET_IMF_PRECISION.div(new BN(10))
|
|
63
|
+
);
|
|
64
|
+
|
|
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
|
+
);
|
|
74
|
+
|
|
75
|
+
const minAssetWeight = BN.min(assetWeight, sizeDiscountAssetWeight);
|
|
76
|
+
|
|
77
|
+
return minAssetWeight;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function calculateOraclePriceForPerpMargin(
|
|
81
|
+
perpPosition: PerpPosition,
|
|
82
|
+
market: PerpMarketAccount,
|
|
83
|
+
oraclePriceData: OraclePriceData
|
|
84
|
+
): BN {
|
|
85
|
+
const oraclePriceOffset = BN.min(
|
|
86
|
+
new BN(market.amm.maxSpread)
|
|
87
|
+
.mul(oraclePriceData.price)
|
|
88
|
+
.div(BID_ASK_SPREAD_PRECISION),
|
|
89
|
+
oraclePriceData.confidence.add(
|
|
90
|
+
new BN(market.amm.baseSpread)
|
|
91
|
+
.mul(oraclePriceData.price)
|
|
92
|
+
.div(BID_ASK_SPREAD_PRECISION)
|
|
93
|
+
)
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
let marginPrice: BN;
|
|
97
|
+
if (perpPosition.baseAssetAmount.gt(ZERO)) {
|
|
98
|
+
marginPrice = oraclePriceData.price.sub(oraclePriceOffset);
|
|
99
|
+
} else {
|
|
100
|
+
marginPrice = oraclePriceData.price.add(oraclePriceOffset);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return marginPrice;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export function calculateBaseAssetValueWithOracle(
|
|
107
|
+
market: PerpMarketAccount,
|
|
108
|
+
perpPosition: PerpPosition,
|
|
109
|
+
oraclePriceData: OraclePriceData
|
|
110
|
+
): BN {
|
|
111
|
+
let price = oraclePriceData.price;
|
|
112
|
+
if (isVariant(market.status, 'settlement')) {
|
|
113
|
+
price = market.expiryPrice;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return perpPosition.baseAssetAmount
|
|
117
|
+
.abs()
|
|
118
|
+
.mul(price)
|
|
119
|
+
.div(AMM_RESERVE_PRECISION);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export function calculateWorstCaseBaseAssetAmount(
|
|
123
|
+
perpPosition: PerpPosition
|
|
124
|
+
): BN {
|
|
125
|
+
const allBids = perpPosition.baseAssetAmount.add(perpPosition.openBids);
|
|
126
|
+
const allAsks = perpPosition.baseAssetAmount.add(perpPosition.openAsks);
|
|
127
|
+
|
|
128
|
+
if (allBids.abs().gt(allAsks.abs())) {
|
|
129
|
+
return allBids;
|
|
130
|
+
} else {
|
|
131
|
+
return allAsks;
|
|
132
|
+
}
|
|
133
|
+
}
|
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,115 @@ 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
|
+
new BN(market.imfFactor),
|
|
135
|
+
new BN(market.marginRatioInitial),
|
|
136
|
+
MARGIN_PRECISION
|
|
137
|
+
).toNumber();
|
|
138
|
+
break;
|
|
139
|
+
case 'Maintenance':
|
|
140
|
+
marginRatio = calculateSizePremiumLiabilityWeight(
|
|
141
|
+
size,
|
|
142
|
+
new BN(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.unrealizedPnlInitialAssetWeight);
|
|
163
|
+
|
|
164
|
+
if (market.unrealizedPnlMaxImbalance.gt(ZERO)) {
|
|
165
|
+
const netUnsettledPnl = calculateNetUserPnlImbalance(
|
|
166
|
+
market,
|
|
167
|
+
quoteSpotMarket,
|
|
168
|
+
oraclePriceData
|
|
169
|
+
);
|
|
170
|
+
if (netUnsettledPnl.gt(market.unrealizedPnlMaxImbalance)) {
|
|
171
|
+
assetWeight = assetWeight
|
|
172
|
+
.mul(market.unrealizedPnlMaxImbalance)
|
|
173
|
+
.div(netUnsettledPnl);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
assetWeight = calculateSizeDiscountAssetWeight(
|
|
178
|
+
unrealizedPnl,
|
|
179
|
+
new BN(market.unrealizedPnlImfFactor),
|
|
180
|
+
assetWeight
|
|
181
|
+
);
|
|
182
|
+
break;
|
|
183
|
+
case 'Maintenance':
|
|
184
|
+
assetWeight = new BN(market.unrealizedPnlMaintenanceAssetWeight);
|
|
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.scaledBalance,
|
|
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.baseAssetAmountWithAmm
|
|
207
|
+
.mul(oraclePriceData.price)
|
|
208
|
+
.div(BASE_PRECISION)
|
|
209
|
+
.div(PRICE_TO_QUOTE_PRECISION);
|
|
210
|
+
|
|
211
|
+
const netUserCostBasis = perpMarket.amm.quoteAssetAmount;
|
|
212
|
+
|
|
213
|
+
const netUserPnl = netUserPositionValue.add(netUserCostBasis);
|
|
214
|
+
|
|
215
|
+
return netUserPnl;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export function calculateNetUserPnlImbalance(
|
|
219
|
+
perpMarket: PerpMarketAccount,
|
|
220
|
+
spotMarket: SpotMarketAccount,
|
|
221
|
+
oraclePriceData: OraclePriceData
|
|
222
|
+
): BN {
|
|
223
|
+
const netUserPnl = calculateNetUserPnl(perpMarket, oraclePriceData);
|
|
224
|
+
|
|
225
|
+
const pnlPool = getTokenAmount(
|
|
226
|
+
perpMarket.pnlPool.scaledBalance,
|
|
227
|
+
spotMarket,
|
|
228
|
+
SpotBalanceType.DEPOSIT
|
|
229
|
+
);
|
|
230
|
+
|
|
231
|
+
const imbalance = netUserPnl.sub(pnlPool);
|
|
232
|
+
|
|
233
|
+
return imbalance;
|
|
234
|
+
}
|
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
|
+
}
|