@drift-labs/sdk 0.2.0-master.29 → 0.2.0-master.30
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/pollingClearingHouseAccountSubscriber.d.ts +10 -11
- package/lib/accounts/pollingClearingHouseAccountSubscriber.js +4 -4
- package/lib/accounts/types.d.ts +4 -6
- package/lib/accounts/webSocketClearingHouseAccountSubscriber.d.ts +10 -11
- package/lib/accounts/webSocketClearingHouseAccountSubscriber.js +6 -8
- package/lib/addresses/marketAddresses.d.ts +1 -3
- package/lib/addresses/pda.d.ts +5 -5
- package/lib/addresses/pda.js +5 -5
- package/lib/admin.d.ts +27 -28
- package/lib/admin.js +12 -37
- package/lib/clearingHouse.d.ts +61 -62
- package/lib/clearingHouse.js +92 -110
- package/lib/clearingHouseConfig.d.ts +2 -4
- package/lib/clearingHouseUser.d.ts +16 -16
- package/lib/clearingHouseUser.js +16 -16
- package/lib/config.d.ts +2 -4
- package/lib/config.js +1 -1
- package/lib/constants/numericConstants.d.ts +7 -8
- package/lib/constants/numericConstants.js +17 -18
- package/lib/constants/perpMarkets.d.ts +2 -3
- package/lib/constants/perpMarkets.js +3 -3
- package/lib/constants/spotMarkets.d.ts +2 -1
- package/lib/constants/spotMarkets.js +6 -4
- package/lib/dlob/DLOB.d.ts +13 -13
- package/lib/dlob/DLOB.js +36 -40
- package/lib/dlob/DLOBNode.js +2 -2
- package/lib/events/sort.js +1 -1
- package/lib/examples/makeTradeExample.js +3 -3
- package/lib/idl/clearing_house.json +359 -310
- package/lib/math/amm.d.ts +2 -2
- package/lib/math/amm.js +10 -10
- package/lib/math/conversion.js +1 -1
- package/lib/math/funding.js +9 -9
- package/lib/math/margin.js +3 -3
- package/lib/math/market.d.ts +4 -4
- package/lib/math/market.js +7 -7
- package/lib/math/oracles.js +6 -8
- package/lib/math/position.d.ts +2 -2
- package/lib/math/position.js +9 -9
- package/lib/math/repeg.js +7 -6
- package/lib/math/spotBalance.js +5 -5
- package/lib/math/spotPosition.js +2 -2
- package/lib/math/trade.d.ts +6 -6
- package/lib/math/trade.js +15 -19
- package/lib/oracles/pythClient.js +1 -1
- package/lib/oracles/quoteAssetOracleClient.js +1 -1
- package/lib/oracles/switchboardClient.js +1 -1
- package/lib/types.d.ts +63 -51
- package/lib/types.js +1 -1
- package/package.json +2 -1
- package/src/accounts/pollingClearingHouseAccountSubscriber.ts +15 -15
- package/src/accounts/types.ts +4 -5
- package/src/accounts/webSocketClearingHouseAccountSubscriber.ts +17 -25
- package/src/addresses/marketAddresses.ts +1 -2
- package/src/addresses/pda.ts +10 -10
- package/src/admin.ts +42 -79
- package/src/clearingHouse.ts +164 -212
- package/src/clearingHouseConfig.ts +2 -3
- package/src/clearingHouseUser.ts +35 -35
- package/src/config.ts +3 -4
- package/src/constants/numericConstants.ts +19 -21
- package/src/constants/perpMarkets.ts +5 -5
- package/src/constants/spotMarkets.ts +8 -5
- package/src/dlob/DLOB.ts +54 -70
- package/src/dlob/DLOBNode.ts +5 -6
- package/src/events/sort.ts +1 -1
- package/src/examples/makeTradeExample.js +2 -2
- package/src/examples/makeTradeExample.ts +5 -8
- package/src/idl/clearing_house.json +359 -310
- package/src/math/amm.ts +14 -11
- package/src/math/conversion.ts +2 -2
- package/src/math/funding.ts +13 -11
- package/src/math/margin.ts +4 -5
- package/src/math/market.ts +5 -5
- package/src/math/oracles.ts +9 -9
- package/src/math/position.ts +11 -19
- package/src/math/repeg.ts +8 -7
- package/src/math/spotBalance.ts +6 -6
- package/src/math/spotPosition.ts +2 -2
- package/src/math/trade.ts +17 -21
- package/src/oracles/pythClient.ts +2 -2
- package/src/oracles/quoteAssetOracleClient.ts +2 -2
- package/src/oracles/switchboardClient.ts +2 -2
- package/src/types.ts +69 -51
- package/tests/dlob/helpers.ts +56 -4
- package/src/addresses/marketAddresses.js +0 -26
- package/src/constants/banks.js +0 -42
- package/src/constants/markets.js +0 -42
- package/src/events/txEventCache.js +0 -71
- package/src/factory/bigNum.js +0 -390
- package/src/factory/oracleClient.js +0 -20
- package/src/math/auction.js +0 -42
- package/src/math/conversion.js +0 -11
- package/src/math/funding.js +0 -248
- package/src/math/repeg.js +0 -128
- package/src/math/trade.js +0 -253
- package/src/math/utils.js +0 -26
- package/src/math/utils.js.map +0 -1
- 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/oracles/types.js +0 -2
- package/src/userName.js +0 -20
- package/src/wallet.js +0 -35
package/src/math/amm.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { BN } from '@project-serum/anchor';
|
|
2
2
|
import {
|
|
3
3
|
AMM_TIMES_PEG_TO_QUOTE_PRECISION_RATIO,
|
|
4
|
-
|
|
4
|
+
PRICE_PRECISION,
|
|
5
5
|
PEG_PRECISION,
|
|
6
6
|
ZERO,
|
|
7
7
|
BID_ASK_SPREAD_PRECISION,
|
|
@@ -242,7 +242,7 @@ export function calculateBidAskPrice(
|
|
|
242
242
|
* @param baseAssetReserves
|
|
243
243
|
* @param quoteAssetReserves
|
|
244
244
|
* @param pegMultiplier
|
|
245
|
-
* @returns price : Precision
|
|
245
|
+
* @returns price : Precision PRICE_PRECISION
|
|
246
246
|
*/
|
|
247
247
|
export function calculatePrice(
|
|
248
248
|
baseAssetReserves: BN,
|
|
@@ -254,7 +254,7 @@ export function calculatePrice(
|
|
|
254
254
|
}
|
|
255
255
|
|
|
256
256
|
return quoteAssetReserves
|
|
257
|
-
.mul(
|
|
257
|
+
.mul(PRICE_PRECISION)
|
|
258
258
|
.mul(pegMultiplier)
|
|
259
259
|
.div(PEG_PRECISION)
|
|
260
260
|
.div(baseAssetReserves);
|
|
@@ -343,11 +343,14 @@ export function calculateInventoryScale(
|
|
|
343
343
|
maxBaseAssetReserve
|
|
344
344
|
);
|
|
345
345
|
|
|
346
|
-
const
|
|
346
|
+
const minSideLiquidity = BN.max(
|
|
347
|
+
new BN(1),
|
|
348
|
+
BN.min(openBids.abs(), openAsks.abs())
|
|
349
|
+
);
|
|
347
350
|
const inventoryScale =
|
|
348
|
-
BN.min(netBaseAssetAmount.abs(),
|
|
349
|
-
.mul(BID_ASK_SPREAD_PRECISION.mul(new BN(
|
|
350
|
-
.div(
|
|
351
|
+
BN.min(netBaseAssetAmount.abs(), minSideLiquidity)
|
|
352
|
+
.mul(BID_ASK_SPREAD_PRECISION.mul(new BN(10)))
|
|
353
|
+
.div(minSideLiquidity)
|
|
351
354
|
.toNumber() / BID_ASK_SPREAD_PRECISION.toNumber();
|
|
352
355
|
|
|
353
356
|
return inventoryScale;
|
|
@@ -370,7 +373,7 @@ export function calculateEffectiveLeverage(
|
|
|
370
373
|
|
|
371
374
|
const localBaseAssetValue = netBaseAssetAmount
|
|
372
375
|
.mul(markPrice)
|
|
373
|
-
.div(AMM_TO_QUOTE_PRECISION_RATIO.mul(
|
|
376
|
+
.div(AMM_TO_QUOTE_PRECISION_RATIO.mul(PRICE_PRECISION));
|
|
374
377
|
|
|
375
378
|
const effectiveLeverage =
|
|
376
379
|
localBaseAssetValue.sub(netBaseAssetValue).toNumber() /
|
|
@@ -614,7 +617,7 @@ export function getSwapDirection(
|
|
|
614
617
|
* Helper function calculating terminal price of amm
|
|
615
618
|
*
|
|
616
619
|
* @param market
|
|
617
|
-
* @returns cost : Precision
|
|
620
|
+
* @returns cost : Precision PRICE_PRECISION
|
|
618
621
|
*/
|
|
619
622
|
export function calculateTerminalPrice(market: PerpMarketAccount) {
|
|
620
623
|
const directionToClose = market.amm.netBaseAssetAmount.gt(ZERO)
|
|
@@ -630,7 +633,7 @@ export function calculateTerminalPrice(market: PerpMarketAccount) {
|
|
|
630
633
|
);
|
|
631
634
|
|
|
632
635
|
const terminalPrice = newQuoteAssetReserve
|
|
633
|
-
.mul(
|
|
636
|
+
.mul(PRICE_PRECISION)
|
|
634
637
|
.mul(market.amm.pegMultiplier)
|
|
635
638
|
.div(PEG_PRECISION)
|
|
636
639
|
.div(newBaseAssetReserve);
|
|
@@ -647,7 +650,7 @@ export function calculateMaxBaseAssetAmountToTrade(
|
|
|
647
650
|
const invariant = amm.sqrtK.mul(amm.sqrtK);
|
|
648
651
|
|
|
649
652
|
const newBaseAssetReserveSquared = invariant
|
|
650
|
-
.mul(
|
|
653
|
+
.mul(PRICE_PRECISION)
|
|
651
654
|
.mul(amm.pegMultiplier)
|
|
652
655
|
.div(limit_price)
|
|
653
656
|
.div(PEG_PRECISION);
|
package/src/math/conversion.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { BN } from '../';
|
|
2
|
-
import {
|
|
2
|
+
import { PRICE_PRECISION } from '../constants/numericConstants';
|
|
3
3
|
|
|
4
4
|
export const convertToNumber = (
|
|
5
5
|
bigNumber: BN,
|
|
6
|
-
precision: BN =
|
|
6
|
+
precision: BN = PRICE_PRECISION
|
|
7
7
|
) => {
|
|
8
8
|
if (!bigNumber) return 0;
|
|
9
9
|
return (
|
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
8
|
import { PerpMarketAccount, isVariant } from '../types';
|
|
9
|
-
import {
|
|
9
|
+
import { calculateReservePrice } from './market';
|
|
10
10
|
import { OraclePriceData } from '../oracles/types';
|
|
11
11
|
|
|
12
12
|
/**
|
|
@@ -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);
|
package/src/math/margin.ts
CHANGED
|
@@ -4,8 +4,7 @@ import {
|
|
|
4
4
|
SPOT_MARKET_IMF_PRECISION,
|
|
5
5
|
ZERO,
|
|
6
6
|
BID_ASK_SPREAD_PRECISION,
|
|
7
|
-
|
|
8
|
-
MARK_PRICE_PRECISION,
|
|
7
|
+
AMM_RESERVE_PRECISION,
|
|
9
8
|
} from '../constants/numericConstants';
|
|
10
9
|
import { BN } from '@project-serum/anchor';
|
|
11
10
|
import { OraclePriceData } from '../oracles/types';
|
|
@@ -22,7 +21,7 @@ export function calculateSizePremiumLiabilityWeight(
|
|
|
22
21
|
return liabilityWeight;
|
|
23
22
|
}
|
|
24
23
|
|
|
25
|
-
const sizeSqrt = squareRootBN(size.
|
|
24
|
+
const sizeSqrt = squareRootBN(size.mul(new BN(10)).add(new BN(1))); //1e9 -> 1e10 -> 1e5
|
|
26
25
|
|
|
27
26
|
const denom0 = BN.max(new BN(1), SPOT_MARKET_IMF_PRECISION.div(imfFactor));
|
|
28
27
|
assert(denom0.gt(ZERO));
|
|
@@ -57,7 +56,7 @@ export function calculateSizeDiscountAssetWeight(
|
|
|
57
56
|
return assetWeight;
|
|
58
57
|
}
|
|
59
58
|
|
|
60
|
-
const sizeSqrt = squareRootBN(size.
|
|
59
|
+
const sizeSqrt = squareRootBN(size.mul(new BN(10)).add(new BN(1))); //1e9 -> 1e10 -> 1e5
|
|
61
60
|
const imfNumerator = SPOT_MARKET_IMF_PRECISION.add(
|
|
62
61
|
SPOT_MARKET_IMF_PRECISION.div(new BN(10))
|
|
63
62
|
);
|
|
@@ -111,7 +110,7 @@ export function calculateBaseAssetValueWithOracle(
|
|
|
111
110
|
return perpPosition.baseAssetAmount
|
|
112
111
|
.abs()
|
|
113
112
|
.mul(oraclePriceData.price)
|
|
114
|
-
.div(
|
|
113
|
+
.div(AMM_RESERVE_PRECISION);
|
|
115
114
|
}
|
|
116
115
|
|
|
117
116
|
export function calculateWorstCaseBaseAssetAmount(
|
package/src/math/market.ts
CHANGED
|
@@ -30,9 +30,9 @@ import { getTokenAmount } from './spotBalance';
|
|
|
30
30
|
* Calculates market mark price
|
|
31
31
|
*
|
|
32
32
|
* @param market
|
|
33
|
-
* @return markPrice : Precision
|
|
33
|
+
* @return markPrice : Precision PRICE_PRECISION
|
|
34
34
|
*/
|
|
35
|
-
export function
|
|
35
|
+
export function calculateReservePrice(
|
|
36
36
|
market: PerpMarketAccount,
|
|
37
37
|
oraclePriceData: OraclePriceData
|
|
38
38
|
): BN {
|
|
@@ -48,7 +48,7 @@ export function calculateMarkPrice(
|
|
|
48
48
|
* Calculates market bid price
|
|
49
49
|
*
|
|
50
50
|
* @param market
|
|
51
|
-
* @return bidPrice : Precision
|
|
51
|
+
* @return bidPrice : Precision PRICE_PRECISION
|
|
52
52
|
*/
|
|
53
53
|
export function calculateBidPrice(
|
|
54
54
|
market: PerpMarketAccount,
|
|
@@ -68,7 +68,7 @@ export function calculateBidPrice(
|
|
|
68
68
|
* Calculates market ask price
|
|
69
69
|
*
|
|
70
70
|
* @param market
|
|
71
|
-
* @return askPrice : Precision
|
|
71
|
+
* @return askPrice : Precision PRICE_PRECISION
|
|
72
72
|
*/
|
|
73
73
|
export function calculateAskPrice(
|
|
74
74
|
market: PerpMarketAccount,
|
|
@@ -110,7 +110,7 @@ export function calculateMarkOracleSpread(
|
|
|
110
110
|
market: PerpMarketAccount,
|
|
111
111
|
oraclePriceData: OraclePriceData
|
|
112
112
|
): BN {
|
|
113
|
-
const markPrice =
|
|
113
|
+
const markPrice = calculateReservePrice(market, oraclePriceData);
|
|
114
114
|
return calculateOracleSpread(markPrice, oraclePriceData);
|
|
115
115
|
}
|
|
116
116
|
|
package/src/math/oracles.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { OraclePriceData } from '../oracles/types';
|
|
|
3
3
|
import {
|
|
4
4
|
BID_ASK_SPREAD_PRECISION,
|
|
5
5
|
MARGIN_PRECISION,
|
|
6
|
-
|
|
6
|
+
PRICE_PRECISION,
|
|
7
7
|
ONE,
|
|
8
8
|
ZERO,
|
|
9
9
|
} from '../constants/numericConstants';
|
|
@@ -34,9 +34,9 @@ export function isOracleValid(
|
|
|
34
34
|
const isOraclePriceNonPositive = oraclePriceData.price.lte(ZERO);
|
|
35
35
|
const isOraclePriceTooVolatile =
|
|
36
36
|
oraclePriceData.price
|
|
37
|
-
.div(BN.max(ONE, amm.lastOraclePriceTwap))
|
|
37
|
+
.div(BN.max(ONE, amm.historicalOracleData.lastOraclePriceTwap))
|
|
38
38
|
.gt(oracleGuardRails.validity.tooVolatileRatio) ||
|
|
39
|
-
amm.lastOraclePriceTwap
|
|
39
|
+
amm.historicalOracleData.lastOraclePriceTwap
|
|
40
40
|
.div(BN.max(ONE, oraclePriceData.price))
|
|
41
41
|
.gt(oracleGuardRails.validity.tooVolatileRatio);
|
|
42
42
|
|
|
@@ -48,7 +48,7 @@ export function isOracleValid(
|
|
|
48
48
|
|
|
49
49
|
const oracleIsStale = oraclePriceData.slot
|
|
50
50
|
.sub(new BN(slot))
|
|
51
|
-
.gt(oracleGuardRails.validity.
|
|
51
|
+
.gt(oracleGuardRails.validity.slotsBeforeStaleForAmm);
|
|
52
52
|
|
|
53
53
|
return !(
|
|
54
54
|
!oraclePriceData.hasSufficientNumberOfDataPoints ||
|
|
@@ -65,18 +65,18 @@ export function isOracleTooDivergent(
|
|
|
65
65
|
oracleGuardRails: OracleGuardRails,
|
|
66
66
|
now: BN
|
|
67
67
|
): boolean {
|
|
68
|
-
const sinceLastUpdate = now.sub(
|
|
68
|
+
const sinceLastUpdate = now.sub(
|
|
69
|
+
amm.historicalOracleData.lastOraclePriceTwapTs
|
|
70
|
+
);
|
|
69
71
|
const sinceStart = BN.max(ZERO, new BN(60 * 5).sub(sinceLastUpdate));
|
|
70
|
-
const oracleTwap5min = amm.lastOraclePriceTwap5min
|
|
72
|
+
const oracleTwap5min = amm.historicalOracleData.lastOraclePriceTwap5min
|
|
71
73
|
.mul(sinceStart)
|
|
72
74
|
.add(oraclePriceData.price)
|
|
73
75
|
.mul(sinceLastUpdate)
|
|
74
76
|
.div(sinceStart.add(sinceLastUpdate));
|
|
75
77
|
|
|
76
78
|
const oracleSpread = oracleTwap5min.sub(oraclePriceData.price);
|
|
77
|
-
const oracleSpreadPct = oracleSpread
|
|
78
|
-
.mul(MARK_PRICE_PRECISION)
|
|
79
|
-
.div(oracleTwap5min);
|
|
79
|
+
const oracleSpreadPct = oracleSpread.mul(PRICE_PRECISION).div(oracleTwap5min);
|
|
80
80
|
|
|
81
81
|
const tooDivergent = oracleSpreadPct
|
|
82
82
|
.abs()
|
package/src/math/position.ts
CHANGED
|
@@ -3,10 +3,9 @@ import {
|
|
|
3
3
|
AMM_RESERVE_PRECISION,
|
|
4
4
|
AMM_TIMES_PEG_TO_QUOTE_PRECISION_RATIO,
|
|
5
5
|
AMM_TO_QUOTE_PRECISION_RATIO,
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
FUNDING_RATE_BUFFER_PRECISION,
|
|
7
|
+
PRICE_PRECISION,
|
|
8
8
|
ONE,
|
|
9
|
-
PRICE_TO_QUOTE_PRECISION,
|
|
10
9
|
ZERO,
|
|
11
10
|
} from '../constants/numericConstants';
|
|
12
11
|
import { OraclePriceData } from '../oracles/types';
|
|
@@ -119,10 +118,7 @@ export function calculatePositionPNL(
|
|
|
119
118
|
.add(perpPosition.quoteAssetAmount);
|
|
120
119
|
|
|
121
120
|
if (withFunding) {
|
|
122
|
-
const fundingRatePnL = calculatePositionFundingPNL(
|
|
123
|
-
market,
|
|
124
|
-
perpPosition
|
|
125
|
-
).div(PRICE_TO_QUOTE_PRECISION);
|
|
121
|
+
const fundingRatePnL = calculatePositionFundingPNL(market, perpPosition);
|
|
126
122
|
|
|
127
123
|
pnl = pnl.add(fundingRatePnL);
|
|
128
124
|
}
|
|
@@ -143,9 +139,7 @@ export function calculateClaimablePnl(
|
|
|
143
139
|
oraclePriceData
|
|
144
140
|
);
|
|
145
141
|
|
|
146
|
-
const fundingPnL = calculatePositionFundingPNL(market, perpPosition)
|
|
147
|
-
PRICE_TO_QUOTE_PRECISION
|
|
148
|
-
);
|
|
142
|
+
const fundingPnL = calculatePositionFundingPNL(market, perpPosition);
|
|
149
143
|
|
|
150
144
|
let unsettledPnl = unrealizedPnl.add(fundingPnL);
|
|
151
145
|
if (unrealizedPnl.gt(ZERO)) {
|
|
@@ -193,7 +187,7 @@ export function calculatePositionFundingPNL(
|
|
|
193
187
|
.sub(perpPosition.lastCumulativeFundingRate)
|
|
194
188
|
.mul(perpPosition.baseAssetAmount)
|
|
195
189
|
.div(AMM_RESERVE_PRECISION)
|
|
196
|
-
.div(
|
|
190
|
+
.div(FUNDING_RATE_BUFFER_PRECISION)
|
|
197
191
|
.mul(new BN(-1));
|
|
198
192
|
|
|
199
193
|
return perPositionFundingRate;
|
|
@@ -202,7 +196,7 @@ export function calculatePositionFundingPNL(
|
|
|
202
196
|
export function positionIsAvailable(position: PerpPosition): boolean {
|
|
203
197
|
return (
|
|
204
198
|
position.baseAssetAmount.eq(ZERO) &&
|
|
205
|
-
position.openOrders
|
|
199
|
+
position.openOrders === 0 &&
|
|
206
200
|
position.quoteAssetAmount.eq(ZERO) &&
|
|
207
201
|
position.lpShares.eq(ZERO)
|
|
208
202
|
);
|
|
@@ -211,7 +205,7 @@ export function positionIsAvailable(position: PerpPosition): boolean {
|
|
|
211
205
|
/**
|
|
212
206
|
*
|
|
213
207
|
* @param userPosition
|
|
214
|
-
* @returns Precision:
|
|
208
|
+
* @returns Precision: PRICE_PRECISION (10^10)
|
|
215
209
|
*/
|
|
216
210
|
export function calculateEntryPrice(userPosition: PerpPosition): BN {
|
|
217
211
|
if (userPosition.baseAssetAmount.eq(ZERO)) {
|
|
@@ -219,7 +213,7 @@ export function calculateEntryPrice(userPosition: PerpPosition): BN {
|
|
|
219
213
|
}
|
|
220
214
|
|
|
221
215
|
return userPosition.quoteEntryAmount
|
|
222
|
-
.mul(
|
|
216
|
+
.mul(PRICE_PRECISION)
|
|
223
217
|
.mul(AMM_TO_QUOTE_PRECISION_RATIO)
|
|
224
218
|
.div(userPosition.baseAssetAmount)
|
|
225
219
|
.abs();
|
|
@@ -228,7 +222,7 @@ export function calculateEntryPrice(userPosition: PerpPosition): BN {
|
|
|
228
222
|
/**
|
|
229
223
|
*
|
|
230
224
|
* @param userPosition
|
|
231
|
-
* @returns Precision:
|
|
225
|
+
* @returns Precision: PRICE_PRECISION (10^10)
|
|
232
226
|
*/
|
|
233
227
|
export function calculateCostBasis(userPosition: PerpPosition): BN {
|
|
234
228
|
if (userPosition.baseAssetAmount.eq(ZERO)) {
|
|
@@ -236,7 +230,7 @@ export function calculateCostBasis(userPosition: PerpPosition): BN {
|
|
|
236
230
|
}
|
|
237
231
|
|
|
238
232
|
return userPosition.quoteAssetAmount
|
|
239
|
-
.mul(
|
|
233
|
+
.mul(PRICE_PRECISION)
|
|
240
234
|
.mul(AMM_TO_QUOTE_PRECISION_RATIO)
|
|
241
235
|
.div(userPosition.baseAssetAmount)
|
|
242
236
|
.abs();
|
|
@@ -259,7 +253,5 @@ export function positionCurrentDirection(
|
|
|
259
253
|
}
|
|
260
254
|
|
|
261
255
|
export function isEmptyPosition(userPosition: PerpPosition): boolean {
|
|
262
|
-
return (
|
|
263
|
-
userPosition.baseAssetAmount.eq(ZERO) && userPosition.openOrders.eq(ZERO)
|
|
264
|
-
);
|
|
256
|
+
return userPosition.baseAssetAmount.eq(ZERO) && userPosition.openOrders === 0;
|
|
265
257
|
}
|
package/src/math/repeg.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { BN } from '@project-serum/anchor';
|
|
2
2
|
import { assert } from '../assert/assert';
|
|
3
3
|
import {
|
|
4
|
-
|
|
4
|
+
PRICE_PRECISION,
|
|
5
5
|
AMM_RESERVE_PRECISION,
|
|
6
6
|
PEG_PRECISION,
|
|
7
7
|
AMM_TO_QUOTE_PRECISION_RATIO,
|
|
@@ -31,15 +31,15 @@ export function calculateAdjustKCost(
|
|
|
31
31
|
|
|
32
32
|
const quoteScale = y.mul(d).mul(Q); //.div(AMM_RESERVE_PRECISION);
|
|
33
33
|
|
|
34
|
-
const p = numerator.mul(
|
|
34
|
+
const p = numerator.mul(PRICE_PRECISION).div(denomenator);
|
|
35
35
|
|
|
36
36
|
const cost = quoteScale
|
|
37
37
|
.div(x.add(d))
|
|
38
38
|
.sub(
|
|
39
39
|
quoteScale
|
|
40
40
|
.mul(p)
|
|
41
|
-
.div(
|
|
42
|
-
.div(x.mul(p).div(
|
|
41
|
+
.div(PRICE_PRECISION)
|
|
42
|
+
.div(x.mul(p).div(PRICE_PRECISION).add(d))
|
|
43
43
|
)
|
|
44
44
|
.div(AMM_TO_QUOTE_PRECISION_RATIO)
|
|
45
45
|
.div(PEG_PRECISION);
|
|
@@ -101,7 +101,8 @@ export function calculateBudgetedKBN(
|
|
|
101
101
|
// protocol is spending to increase k
|
|
102
102
|
if (C.lt(ZERO)) {
|
|
103
103
|
// thus denom1 is negative and solution is unstable
|
|
104
|
-
if (denom1.
|
|
104
|
+
if (denom1.abs().gt(denom2.abs())) {
|
|
105
|
+
console.log('denom1 > denom2', denom1.toString(), denom2.toString());
|
|
105
106
|
console.log('budget cost exceeds stable K solution');
|
|
106
107
|
return [new BN(10000), new BN(1)];
|
|
107
108
|
}
|
|
@@ -174,11 +175,11 @@ export function calculateBudgetedPeg(amm: AMM, cost: BN, targetPrice: BN): BN {
|
|
|
174
175
|
return targetPeg;
|
|
175
176
|
}
|
|
176
177
|
|
|
177
|
-
const deltaPegMultiplier = C.mul(
|
|
178
|
+
const deltaPegMultiplier = C.mul(PRICE_PRECISION).div(
|
|
178
179
|
deltaQuoteAssetReserves.div(AMM_TO_QUOTE_PRECISION_RATIO)
|
|
179
180
|
);
|
|
180
181
|
const newPeg = Q.sub(
|
|
181
|
-
deltaPegMultiplier.mul(PEG_PRECISION).div(
|
|
182
|
+
deltaPegMultiplier.mul(PEG_PRECISION).div(PRICE_PRECISION)
|
|
182
183
|
);
|
|
183
184
|
|
|
184
185
|
return newPeg;
|
package/src/math/spotBalance.ts
CHANGED
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
ONE,
|
|
11
11
|
TEN,
|
|
12
12
|
ZERO,
|
|
13
|
-
|
|
13
|
+
SPOT_MARKET_RATE_PRECISION,
|
|
14
14
|
SPOT_MARKET_WEIGHT_PRECISION,
|
|
15
15
|
ONE_YEAR,
|
|
16
16
|
AMM_RESERVE_PRECISION,
|
|
@@ -26,7 +26,7 @@ export function getBalance(
|
|
|
26
26
|
spotMarket: SpotMarketAccount,
|
|
27
27
|
balanceType: SpotBalanceType
|
|
28
28
|
): BN {
|
|
29
|
-
const precisionIncrease = TEN.pow(new BN(
|
|
29
|
+
const precisionIncrease = TEN.pow(new BN(19 - spotMarket.decimals));
|
|
30
30
|
|
|
31
31
|
const cumulativeInterest = isVariant(balanceType, 'deposit')
|
|
32
32
|
? spotMarket.cumulativeDepositInterest
|
|
@@ -46,7 +46,7 @@ export function getTokenAmount(
|
|
|
46
46
|
spotMarket: SpotMarketAccount,
|
|
47
47
|
balanceType: SpotBalanceType
|
|
48
48
|
): BN {
|
|
49
|
-
const precisionDecrease = TEN.pow(new BN(
|
|
49
|
+
const precisionDecrease = TEN.pow(new BN(19 - spotMarket.decimals));
|
|
50
50
|
|
|
51
51
|
const cumulativeInterest = isVariant(balanceType, 'deposit')
|
|
52
52
|
? spotMarket.cumulativeDepositInterest
|
|
@@ -75,7 +75,7 @@ export function getTokenValue(
|
|
|
75
75
|
return ZERO;
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
-
const precisionDecrease = TEN.pow(new BN(
|
|
78
|
+
const precisionDecrease = TEN.pow(new BN(spotDecimals));
|
|
79
79
|
|
|
80
80
|
return tokenAmount.mul(oraclePriceData.price).div(precisionDecrease);
|
|
81
81
|
}
|
|
@@ -253,12 +253,12 @@ export function calculateInterestAccumulated(
|
|
|
253
253
|
const borrowInterest = bank.cumulativeBorrowInterest
|
|
254
254
|
.mul(modifiedBorrowRate)
|
|
255
255
|
.div(ONE_YEAR)
|
|
256
|
-
.div(
|
|
256
|
+
.div(SPOT_MARKET_RATE_PRECISION)
|
|
257
257
|
.add(ONE);
|
|
258
258
|
const depositInterest = bank.cumulativeDepositInterest
|
|
259
259
|
.mul(modifiedDepositRate)
|
|
260
260
|
.div(ONE_YEAR)
|
|
261
|
-
.div(
|
|
261
|
+
.div(SPOT_MARKET_RATE_PRECISION);
|
|
262
262
|
|
|
263
263
|
return { borrowInterest, depositInterest };
|
|
264
264
|
}
|
package/src/math/spotPosition.ts
CHANGED
|
@@ -31,14 +31,14 @@ export function getWorstCaseTokenAmounts(
|
|
|
31
31
|
|
|
32
32
|
if (tokenAmountAllAsksFill.abs().gt(tokenAmountAllBidsFill.abs())) {
|
|
33
33
|
const worstCaseQuoteTokenAmount = getTokenValue(
|
|
34
|
-
spotPosition.
|
|
34
|
+
spotPosition.openAsks.neg(),
|
|
35
35
|
spotMarketAccount.decimals,
|
|
36
36
|
oraclePriceData
|
|
37
37
|
);
|
|
38
38
|
return [tokenAmountAllBidsFill, worstCaseQuoteTokenAmount];
|
|
39
39
|
} else {
|
|
40
40
|
const worstCaseQuoteTokenAmount = getTokenValue(
|
|
41
|
-
spotPosition.
|
|
41
|
+
spotPosition.openBids.neg(),
|
|
42
42
|
spotMarketAccount.decimals,
|
|
43
43
|
oraclePriceData
|
|
44
44
|
);
|
package/src/math/trade.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { PerpMarketAccount, PositionDirection } from '../types';
|
|
|
2
2
|
import { BN } from '@project-serum/anchor';
|
|
3
3
|
import { assert } from '../assert/assert';
|
|
4
4
|
import {
|
|
5
|
-
|
|
5
|
+
PRICE_PRECISION,
|
|
6
6
|
PEG_PRECISION,
|
|
7
7
|
AMM_TO_QUOTE_PRECISION_RATIO,
|
|
8
8
|
ZERO,
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
import {
|
|
11
11
|
calculateBidPrice,
|
|
12
12
|
calculateAskPrice,
|
|
13
|
-
|
|
13
|
+
calculateReservePrice,
|
|
14
14
|
} from './market';
|
|
15
15
|
import {
|
|
16
16
|
calculateAmmReservesAfterSwap,
|
|
@@ -48,13 +48,13 @@ export type PriceImpactUnit =
|
|
|
48
48
|
* @param useSpread whether to consider spread with calculating slippage
|
|
49
49
|
* @return [pctAvgSlippage, pctMaxSlippage, entryPrice, newPrice]
|
|
50
50
|
*
|
|
51
|
-
* 'pctAvgSlippage' => the percentage change to entryPrice (average est slippage in execution) : Precision
|
|
51
|
+
* 'pctAvgSlippage' => the percentage change to entryPrice (average est slippage in execution) : Precision PRICE_PRECISION
|
|
52
52
|
*
|
|
53
|
-
* 'pctMaxSlippage' => the percentage change to maxPrice (highest est slippage in execution) : Precision
|
|
53
|
+
* 'pctMaxSlippage' => the percentage change to maxPrice (highest est slippage in execution) : Precision PRICE_PRECISION
|
|
54
54
|
*
|
|
55
|
-
* 'entryPrice' => the average price of the trade : Precision
|
|
55
|
+
* 'entryPrice' => the average price of the trade : Precision PRICE_PRECISION
|
|
56
56
|
*
|
|
57
|
-
* 'newPrice' => the price of the asset after the trade : Precision
|
|
57
|
+
* 'newPrice' => the price of the asset after the trade : Precision PRICE_PRECISION
|
|
58
58
|
*/
|
|
59
59
|
export function calculateTradeSlippage(
|
|
60
60
|
direction: PositionDirection,
|
|
@@ -73,7 +73,7 @@ export function calculateTradeSlippage(
|
|
|
73
73
|
oldPrice = calculateBidPrice(market, oraclePriceData);
|
|
74
74
|
}
|
|
75
75
|
} else {
|
|
76
|
-
oldPrice =
|
|
76
|
+
oldPrice = calculateReservePrice(market, oraclePriceData);
|
|
77
77
|
}
|
|
78
78
|
if (amount.eq(ZERO)) {
|
|
79
79
|
return [ZERO, ZERO, oldPrice, oldPrice];
|
|
@@ -90,7 +90,7 @@ export function calculateTradeSlippage(
|
|
|
90
90
|
|
|
91
91
|
const entryPrice = acquiredQuoteAssetAmount
|
|
92
92
|
.mul(AMM_TO_QUOTE_PRECISION_RATIO)
|
|
93
|
-
.mul(
|
|
93
|
+
.mul(PRICE_PRECISION)
|
|
94
94
|
.div(acquiredBaseReserve.abs());
|
|
95
95
|
|
|
96
96
|
let amm: Parameters<typeof calculateAmmReservesAfterSwap>[0];
|
|
@@ -121,12 +121,12 @@ export function calculateTradeSlippage(
|
|
|
121
121
|
|
|
122
122
|
const pctMaxSlippage = newPrice
|
|
123
123
|
.sub(oldPrice)
|
|
124
|
-
.mul(
|
|
124
|
+
.mul(PRICE_PRECISION)
|
|
125
125
|
.div(oldPrice)
|
|
126
126
|
.abs();
|
|
127
127
|
const pctAvgSlippage = entryPrice
|
|
128
128
|
.sub(oldPrice)
|
|
129
|
-
.mul(
|
|
129
|
+
.mul(PRICE_PRECISION)
|
|
130
130
|
.div(oldPrice)
|
|
131
131
|
.abs();
|
|
132
132
|
|
|
@@ -199,8 +199,8 @@ export function calculateTradeAcquiredAmounts(
|
|
|
199
199
|
* [
|
|
200
200
|
* direction => direction of trade required, PositionDirection
|
|
201
201
|
* tradeSize => size of trade required, TODO-PRECISION
|
|
202
|
-
* entryPrice => the entry price for the trade,
|
|
203
|
-
* targetPrice => the target price
|
|
202
|
+
* entryPrice => the entry price for the trade, PRICE_PRECISION
|
|
203
|
+
* targetPrice => the target price PRICE_PRECISION
|
|
204
204
|
* ]
|
|
205
205
|
*/
|
|
206
206
|
export function calculateTargetPriceTrade(
|
|
@@ -215,7 +215,7 @@ export function calculateTargetPriceTrade(
|
|
|
215
215
|
assert(targetPrice.gt(ZERO));
|
|
216
216
|
assert(pct.lte(MAXPCT) && pct.gt(ZERO));
|
|
217
217
|
|
|
218
|
-
const markPriceBefore =
|
|
218
|
+
const markPriceBefore = calculateReservePrice(market, oraclePriceData);
|
|
219
219
|
const bidPriceBefore = calculateBidPrice(market, oraclePriceData);
|
|
220
220
|
const askPriceBefore = calculateAskPrice(market, oraclePriceData);
|
|
221
221
|
|
|
@@ -252,7 +252,7 @@ export function calculateTargetPriceTrade(
|
|
|
252
252
|
}
|
|
253
253
|
|
|
254
254
|
const invariant = market.amm.sqrtK.mul(market.amm.sqrtK);
|
|
255
|
-
const k = invariant.mul(
|
|
255
|
+
const k = invariant.mul(PRICE_PRECISION);
|
|
256
256
|
|
|
257
257
|
let baseAssetReserveAfter;
|
|
258
258
|
let quoteAssetReserveAfter;
|
|
@@ -277,9 +277,7 @@ export function calculateTargetPriceTrade(
|
|
|
277
277
|
baseAssetReserveAfter = squareRootBN(
|
|
278
278
|
k.div(targetPrice).mul(peg).div(PEG_PRECISION).sub(biasModifier)
|
|
279
279
|
).sub(new BN(1));
|
|
280
|
-
quoteAssetReserveAfter = k
|
|
281
|
-
.div(MARK_PRICE_PRECISION)
|
|
282
|
-
.div(baseAssetReserveAfter);
|
|
280
|
+
quoteAssetReserveAfter = k.div(PRICE_PRECISION).div(baseAssetReserveAfter);
|
|
283
281
|
|
|
284
282
|
markPriceAfter = calculatePrice(
|
|
285
283
|
baseAssetReserveAfter,
|
|
@@ -298,9 +296,7 @@ export function calculateTargetPriceTrade(
|
|
|
298
296
|
baseAssetReserveAfter = squareRootBN(
|
|
299
297
|
k.div(targetPrice).mul(peg).div(PEG_PRECISION).add(biasModifier)
|
|
300
298
|
).add(new BN(1));
|
|
301
|
-
quoteAssetReserveAfter = k
|
|
302
|
-
.div(MARK_PRICE_PRECISION)
|
|
303
|
-
.div(baseAssetReserveAfter);
|
|
299
|
+
quoteAssetReserveAfter = k.div(PRICE_PRECISION).div(baseAssetReserveAfter);
|
|
304
300
|
|
|
305
301
|
markPriceAfter = calculatePrice(
|
|
306
302
|
baseAssetReserveAfter,
|
|
@@ -334,7 +330,7 @@ export function calculateTargetPriceTrade(
|
|
|
334
330
|
|
|
335
331
|
const entryPrice = tradeSize
|
|
336
332
|
.mul(AMM_TO_QUOTE_PRECISION_RATIO)
|
|
337
|
-
.mul(
|
|
333
|
+
.mul(PRICE_PRECISION)
|
|
338
334
|
.div(baseSize.abs());
|
|
339
335
|
|
|
340
336
|
assert(tp1.sub(tp2).lte(originalDiff), 'Target Price Calculation incorrect');
|
|
@@ -2,7 +2,7 @@ import { parsePriceData } from '@pythnetwork/client';
|
|
|
2
2
|
import { Connection, PublicKey } from '@solana/web3.js';
|
|
3
3
|
import { OracleClient, OraclePriceData } from './types';
|
|
4
4
|
import { BN } from '@project-serum/anchor';
|
|
5
|
-
import {
|
|
5
|
+
import { PRICE_PRECISION, TEN } from '../constants/numericConstants';
|
|
6
6
|
|
|
7
7
|
export class PythClient implements OracleClient {
|
|
8
8
|
private connection: Connection;
|
|
@@ -38,6 +38,6 @@ export function convertPythPrice(price: number, exponent: number): BN {
|
|
|
38
38
|
exponent = Math.abs(exponent);
|
|
39
39
|
const pythPrecision = TEN.pow(new BN(exponent).abs());
|
|
40
40
|
return new BN(price * Math.pow(10, exponent))
|
|
41
|
-
.mul(
|
|
41
|
+
.mul(PRICE_PRECISION)
|
|
42
42
|
.div(pythPrecision);
|
|
43
43
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { PublicKey } from '@solana/web3.js';
|
|
2
2
|
import { OracleClient, OraclePriceData } from './types';
|
|
3
3
|
import { BN } from '@project-serum/anchor';
|
|
4
|
-
import {
|
|
4
|
+
import { PRICE_PRECISION } from '../constants/numericConstants';
|
|
5
5
|
|
|
6
6
|
export const QUOTE_ORACLE_PRICE_DATA: OraclePriceData = {
|
|
7
|
-
price:
|
|
7
|
+
price: PRICE_PRECISION,
|
|
8
8
|
slot: new BN(0),
|
|
9
9
|
confidence: new BN(1),
|
|
10
10
|
hasSufficientNumberOfDataPoints: true,
|