@drift-labs/sdk 0.2.0-master.4 → 0.2.0-master.41
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 -27
- 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 +9 -9
- package/lib/config.js +25 -21
- package/lib/constants/numericConstants.d.ts +30 -12
- package/lib/constants/numericConstants.js +41 -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 +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.js +3 -0
- 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 +40 -12
- 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/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 +8386 -0
- package/lib/idl/{mock_usdc_faucet.json → token_faucet.json} +46 -23
- package/lib/index.d.ts +30 -13
- package/lib/index.js +30 -13
- 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 +92 -36
- 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/lib/{clearingHouseUserConfig.js → serum/types.js} +0 -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 +688 -216
- package/lib/types.js +153 -24
- package/lib/user.d.ts +228 -0
- package/lib/user.js +959 -0
- package/lib/userConfig.d.ts +14 -0
- package/lib/userConfig.js +2 -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/lib/userStatsConfig.js +2 -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 +11 -4
- 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/assert/assert.js +9 -0
- package/src/config.ts +37 -31
- package/src/constants/numericConstants.ts +58 -24
- package/src/constants/{markets.ts → perpMarkets.ts} +10 -10
- package/src/constants/spotMarkets.ts +73 -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.js +77 -0
- package/src/events/eventList.ts +3 -0
- package/src/events/eventSubscriber.ts +36 -14
- package/src/events/fetchLogs.ts +55 -13
- package/src/events/pollingLogProvider.ts +11 -3
- package/src/events/sort.ts +11 -15
- package/src/events/types.ts +27 -2
- package/src/events/webSocketLogProvider.ts +1 -1
- package/src/examples/makeTradeExample.js +157 -0
- package/src/examples/makeTradeExample.ts +44 -28
- package/src/factory/bigNum.ts +150 -22
- package/src/idl/drift.json +8386 -0
- package/src/idl/pyth.json +98 -2
- package/src/idl/{mock_usdc_faucet.json → token_faucet.json} +46 -23
- package/src/index.ts +30 -13
- 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 +136 -58
- 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/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 +650 -189
- 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/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 +46 -11
- package/tests/dlob/helpers.ts +620 -0
- package/tests/dlob/test.ts +4586 -0
- package/yarn-error.log +3160 -0
- package/lib/accounts/webSocketClearingHouseAccountSubscriber.d.ts +0 -49
- package/lib/admin.d.ts +0 -44
- package/lib/admin.js +0 -433
- package/lib/clearingHouse.d.ts +0 -133
- package/lib/clearingHouse.js +0 -931
- package/lib/clearingHouseUser.d.ts +0 -187
- package/lib/clearingHouseUser.js +0 -643
- package/lib/clearingHouseUserConfig.d.ts +0 -14
- 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/idl/clearing_house.json +0 -3998
- 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/admin.ts +0 -722
- package/src/clearingHouse.ts +0 -1451
- package/src/clearingHouseUser.ts +0 -989
- package/src/constants/banks.ts +0 -43
- package/src/idl/clearing_house.json +0 -3998
- 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/position.ts
CHANGED
|
@@ -1,22 +1,23 @@
|
|
|
1
|
-
import { BN } from '../';
|
|
1
|
+
import { BN, SpotMarketAccount } from '../';
|
|
2
2
|
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';
|
|
13
|
-
import {
|
|
12
|
+
import { PerpMarketAccount, PositionDirection, PerpPosition } from '../types';
|
|
14
13
|
import {
|
|
15
14
|
calculateUpdatedAMM,
|
|
16
15
|
calculateUpdatedAMMSpreadReserves,
|
|
17
16
|
calculateAmmReservesAfterSwap,
|
|
18
17
|
getSwapDirection,
|
|
19
18
|
} from './amm';
|
|
19
|
+
import { calculateBaseAssetValueWithOracle } from './margin';
|
|
20
|
+
import { calculateNetUserPnlImbalance } from './market';
|
|
20
21
|
|
|
21
22
|
/**
|
|
22
23
|
* calculateBaseAssetValue
|
|
@@ -27,9 +28,11 @@ import {
|
|
|
27
28
|
* @returns Base Asset Value. : Precision QUOTE_PRECISION
|
|
28
29
|
*/
|
|
29
30
|
export function calculateBaseAssetValue(
|
|
30
|
-
market:
|
|
31
|
-
userPosition:
|
|
32
|
-
oraclePriceData: OraclePriceData
|
|
31
|
+
market: PerpMarketAccount,
|
|
32
|
+
userPosition: PerpPosition,
|
|
33
|
+
oraclePriceData: OraclePriceData,
|
|
34
|
+
useSpread = true,
|
|
35
|
+
skipUpdate = false
|
|
33
36
|
): BN {
|
|
34
37
|
if (userPosition.baseAssetAmount.eq(ZERO)) {
|
|
35
38
|
return ZERO;
|
|
@@ -38,21 +41,25 @@ export function calculateBaseAssetValue(
|
|
|
38
41
|
const directionToClose = findDirectionToClose(userPosition);
|
|
39
42
|
let prepegAmm: Parameters<typeof calculateAmmReservesAfterSwap>[0];
|
|
40
43
|
|
|
41
|
-
if (
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
44
|
+
if (!skipUpdate) {
|
|
45
|
+
if (market.amm.baseSpread > 0 && useSpread) {
|
|
46
|
+
const { baseAssetReserve, quoteAssetReserve, sqrtK, newPeg } =
|
|
47
|
+
calculateUpdatedAMMSpreadReserves(
|
|
48
|
+
market.amm,
|
|
49
|
+
directionToClose,
|
|
50
|
+
oraclePriceData
|
|
51
|
+
);
|
|
52
|
+
prepegAmm = {
|
|
53
|
+
baseAssetReserve,
|
|
54
|
+
quoteAssetReserve,
|
|
55
|
+
sqrtK: sqrtK,
|
|
56
|
+
pegMultiplier: newPeg,
|
|
57
|
+
};
|
|
58
|
+
} else {
|
|
59
|
+
prepegAmm = calculateUpdatedAMM(market.amm, oraclePriceData);
|
|
60
|
+
}
|
|
54
61
|
} else {
|
|
55
|
-
prepegAmm =
|
|
62
|
+
prepegAmm = market.amm;
|
|
56
63
|
}
|
|
57
64
|
|
|
58
65
|
const [newQuoteAssetReserve, _] = calculateAmmReservesAfterSwap(
|
|
@@ -82,38 +89,36 @@ export function calculateBaseAssetValue(
|
|
|
82
89
|
* calculatePositionPNL
|
|
83
90
|
* = BaseAssetAmount * (Avg Exit Price - Avg Entry Price)
|
|
84
91
|
* @param market
|
|
85
|
-
* @param
|
|
92
|
+
* @param PerpPosition
|
|
86
93
|
* @param withFunding (adds unrealized funding payment pnl to result)
|
|
94
|
+
* @param oraclePriceData
|
|
87
95
|
* @returns BaseAssetAmount : Precision QUOTE_PRECISION
|
|
88
96
|
*/
|
|
89
97
|
export function calculatePositionPNL(
|
|
90
|
-
market:
|
|
91
|
-
|
|
98
|
+
market: PerpMarketAccount,
|
|
99
|
+
perpPosition: PerpPosition,
|
|
92
100
|
withFunding = false,
|
|
93
101
|
oraclePriceData: OraclePriceData
|
|
94
102
|
): BN {
|
|
95
|
-
if (
|
|
96
|
-
return
|
|
103
|
+
if (perpPosition.baseAssetAmount.eq(ZERO)) {
|
|
104
|
+
return perpPosition.quoteAssetAmount;
|
|
97
105
|
}
|
|
98
106
|
|
|
99
|
-
const baseAssetValue =
|
|
107
|
+
const baseAssetValue = calculateBaseAssetValueWithOracle(
|
|
100
108
|
market,
|
|
101
|
-
|
|
109
|
+
perpPosition,
|
|
102
110
|
oraclePriceData
|
|
103
111
|
);
|
|
104
112
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
113
|
+
const baseAssetValueSign = perpPosition.baseAssetAmount.isNeg()
|
|
114
|
+
? new BN(-1)
|
|
115
|
+
: new BN(1);
|
|
116
|
+
let pnl = baseAssetValue
|
|
117
|
+
.mul(baseAssetValueSign)
|
|
118
|
+
.add(perpPosition.quoteAssetAmount);
|
|
111
119
|
|
|
112
120
|
if (withFunding) {
|
|
113
|
-
const fundingRatePnL = calculatePositionFundingPNL(
|
|
114
|
-
market,
|
|
115
|
-
marketPosition
|
|
116
|
-
).div(PRICE_TO_QUOTE_PRECISION);
|
|
121
|
+
const fundingRatePnL = calculatePositionFundingPNL(market, perpPosition);
|
|
117
122
|
|
|
118
123
|
pnl = pnl.add(fundingRatePnL);
|
|
119
124
|
}
|
|
@@ -121,60 +126,135 @@ export function calculatePositionPNL(
|
|
|
121
126
|
return pnl;
|
|
122
127
|
}
|
|
123
128
|
|
|
129
|
+
export function calculateClaimablePnl(
|
|
130
|
+
market: PerpMarketAccount,
|
|
131
|
+
spotMarket: SpotMarketAccount,
|
|
132
|
+
perpPosition: PerpPosition,
|
|
133
|
+
oraclePriceData: OraclePriceData
|
|
134
|
+
): BN {
|
|
135
|
+
const unrealizedPnl = calculatePositionPNL(
|
|
136
|
+
market,
|
|
137
|
+
perpPosition,
|
|
138
|
+
true,
|
|
139
|
+
oraclePriceData
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
const fundingPnL = calculatePositionFundingPNL(market, perpPosition);
|
|
143
|
+
|
|
144
|
+
let unsettledPnl = unrealizedPnl.add(fundingPnL);
|
|
145
|
+
if (unrealizedPnl.gt(ZERO)) {
|
|
146
|
+
const excessPnlPool = BN.max(
|
|
147
|
+
ZERO,
|
|
148
|
+
calculateNetUserPnlImbalance(market, spotMarket, oraclePriceData).mul(
|
|
149
|
+
new BN(-1)
|
|
150
|
+
)
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
const maxPositivePnl = BN.max(
|
|
154
|
+
perpPosition.quoteAssetAmount
|
|
155
|
+
.sub(perpPosition.quoteEntryAmount)
|
|
156
|
+
.add(excessPnlPool),
|
|
157
|
+
ZERO
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
unsettledPnl = BN.min(maxPositivePnl, unrealizedPnl);
|
|
161
|
+
}
|
|
162
|
+
return unsettledPnl;
|
|
163
|
+
}
|
|
164
|
+
|
|
124
165
|
/**
|
|
125
166
|
*
|
|
126
167
|
* @param market
|
|
127
|
-
* @param
|
|
168
|
+
* @param PerpPosition
|
|
128
169
|
* @returns // TODO-PRECISION
|
|
129
170
|
*/
|
|
130
171
|
export function calculatePositionFundingPNL(
|
|
131
|
-
market:
|
|
132
|
-
|
|
172
|
+
market: PerpMarketAccount,
|
|
173
|
+
perpPosition: PerpPosition
|
|
133
174
|
): BN {
|
|
134
|
-
if (
|
|
175
|
+
if (perpPosition.baseAssetAmount.eq(ZERO)) {
|
|
135
176
|
return ZERO;
|
|
136
177
|
}
|
|
137
178
|
|
|
138
179
|
let ammCumulativeFundingRate: BN;
|
|
139
|
-
if (
|
|
180
|
+
if (perpPosition.baseAssetAmount.gt(ZERO)) {
|
|
140
181
|
ammCumulativeFundingRate = market.amm.cumulativeFundingRateLong;
|
|
141
182
|
} else {
|
|
142
183
|
ammCumulativeFundingRate = market.amm.cumulativeFundingRateShort;
|
|
143
184
|
}
|
|
144
185
|
|
|
145
186
|
const perPositionFundingRate = ammCumulativeFundingRate
|
|
146
|
-
.sub(
|
|
147
|
-
.mul(
|
|
187
|
+
.sub(perpPosition.lastCumulativeFundingRate)
|
|
188
|
+
.mul(perpPosition.baseAssetAmount)
|
|
148
189
|
.div(AMM_RESERVE_PRECISION)
|
|
149
|
-
.div(
|
|
190
|
+
.div(FUNDING_RATE_BUFFER_PRECISION)
|
|
150
191
|
.mul(new BN(-1));
|
|
151
192
|
|
|
152
193
|
return perPositionFundingRate;
|
|
153
194
|
}
|
|
154
195
|
|
|
155
|
-
export function positionIsAvailable(position:
|
|
156
|
-
return
|
|
196
|
+
export function positionIsAvailable(position: PerpPosition): boolean {
|
|
197
|
+
return (
|
|
198
|
+
position.baseAssetAmount.eq(ZERO) &&
|
|
199
|
+
position.openOrders === 0 &&
|
|
200
|
+
position.quoteAssetAmount.eq(ZERO) &&
|
|
201
|
+
position.lpShares.eq(ZERO)
|
|
202
|
+
);
|
|
157
203
|
}
|
|
158
204
|
|
|
159
205
|
/**
|
|
160
206
|
*
|
|
161
207
|
* @param userPosition
|
|
162
|
-
* @returns Precision:
|
|
208
|
+
* @returns Precision: PRICE_PRECISION (10^6)
|
|
163
209
|
*/
|
|
164
|
-
export function
|
|
210
|
+
export function calculateBreakEvenPrice(userPosition: PerpPosition): BN {
|
|
211
|
+
if (userPosition.baseAssetAmount.eq(ZERO)) {
|
|
212
|
+
return ZERO;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return userPosition.quoteBreakEvenAmount
|
|
216
|
+
.mul(PRICE_PRECISION)
|
|
217
|
+
.mul(AMM_TO_QUOTE_PRECISION_RATIO)
|
|
218
|
+
.div(userPosition.baseAssetAmount)
|
|
219
|
+
.abs();
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
*
|
|
224
|
+
* @param userPosition
|
|
225
|
+
* @returns Precision: PRICE_PRECISION (10^6)
|
|
226
|
+
*/
|
|
227
|
+
export function calculateEntryPrice(userPosition: PerpPosition): BN {
|
|
228
|
+
if (userPosition.baseAssetAmount.eq(ZERO)) {
|
|
229
|
+
return ZERO;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
return userPosition.quoteEntryAmount
|
|
233
|
+
.mul(PRICE_PRECISION)
|
|
234
|
+
.mul(AMM_TO_QUOTE_PRECISION_RATIO)
|
|
235
|
+
.div(userPosition.baseAssetAmount)
|
|
236
|
+
.abs();
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
*
|
|
241
|
+
* @param userPosition
|
|
242
|
+
* @returns Precision: PRICE_PRECISION (10^10)
|
|
243
|
+
*/
|
|
244
|
+
export function calculateCostBasis(userPosition: PerpPosition): BN {
|
|
165
245
|
if (userPosition.baseAssetAmount.eq(ZERO)) {
|
|
166
246
|
return ZERO;
|
|
167
247
|
}
|
|
168
248
|
|
|
169
249
|
return userPosition.quoteAssetAmount
|
|
170
|
-
.mul(
|
|
250
|
+
.mul(PRICE_PRECISION)
|
|
171
251
|
.mul(AMM_TO_QUOTE_PRECISION_RATIO)
|
|
172
252
|
.div(userPosition.baseAssetAmount)
|
|
173
253
|
.abs();
|
|
174
254
|
}
|
|
175
255
|
|
|
176
256
|
export function findDirectionToClose(
|
|
177
|
-
userPosition:
|
|
257
|
+
userPosition: PerpPosition
|
|
178
258
|
): PositionDirection {
|
|
179
259
|
return userPosition.baseAssetAmount.gt(ZERO)
|
|
180
260
|
? PositionDirection.SHORT
|
|
@@ -182,15 +262,13 @@ export function findDirectionToClose(
|
|
|
182
262
|
}
|
|
183
263
|
|
|
184
264
|
export function positionCurrentDirection(
|
|
185
|
-
userPosition:
|
|
265
|
+
userPosition: PerpPosition
|
|
186
266
|
): PositionDirection {
|
|
187
267
|
return userPosition.baseAssetAmount.gte(ZERO)
|
|
188
268
|
? PositionDirection.LONG
|
|
189
269
|
: PositionDirection.SHORT;
|
|
190
270
|
}
|
|
191
271
|
|
|
192
|
-
export function isEmptyPosition(userPosition:
|
|
193
|
-
return (
|
|
194
|
-
userPosition.baseAssetAmount.eq(ZERO) && userPosition.openOrders.eq(ZERO)
|
|
195
|
-
);
|
|
272
|
+
export function isEmptyPosition(userPosition: PerpPosition): boolean {
|
|
273
|
+
return userPosition.baseAssetAmount.eq(ZERO) && userPosition.openOrders === 0;
|
|
196
274
|
}
|
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,
|
|
@@ -26,20 +26,20 @@ export function calculateAdjustKCost(
|
|
|
26
26
|
const x = amm.baseAssetReserve;
|
|
27
27
|
const y = amm.quoteAssetReserve;
|
|
28
28
|
|
|
29
|
-
const d = amm.
|
|
29
|
+
const d = amm.baseAssetAmountWithAmm;
|
|
30
30
|
const Q = amm.pegMultiplier;
|
|
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);
|
|
@@ -98,6 +98,16 @@ export function calculateBudgetedKBN(
|
|
|
98
98
|
.div(QUOTE_PRECISION);
|
|
99
99
|
const denom2 = pegged_y_d_d;
|
|
100
100
|
|
|
101
|
+
// protocol is spending to increase k
|
|
102
|
+
if (C.lt(ZERO)) {
|
|
103
|
+
// thus denom1 is negative and solution is unstable
|
|
104
|
+
if (denom1.abs().gt(denom2.abs())) {
|
|
105
|
+
console.log('denom1 > denom2', denom1.toString(), denom2.toString());
|
|
106
|
+
console.log('budget cost exceeds stable K solution');
|
|
107
|
+
return [new BN(10000), new BN(1)];
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
101
111
|
const numerator = numer1.sub(numer2).div(AMM_TO_QUOTE_PRECISION_RATIO);
|
|
102
112
|
const denominator = denom1.add(denom2).div(AMM_TO_QUOTE_PRECISION_RATIO);
|
|
103
113
|
|
|
@@ -125,7 +135,7 @@ export function calculateBudgetedK(amm: AMM, cost: BN): [BN, BN] {
|
|
|
125
135
|
const x = amm.baseAssetReserve;
|
|
126
136
|
const y = amm.quoteAssetReserve;
|
|
127
137
|
|
|
128
|
-
const d = amm.
|
|
138
|
+
const d = amm.baseAssetAmountWithAmm;
|
|
129
139
|
const Q = amm.pegMultiplier;
|
|
130
140
|
|
|
131
141
|
const [numerator, denominator] = calculateBudgetedKBN(x, y, cost, Q, d);
|
|
@@ -149,7 +159,7 @@ export function calculateBudgetedPeg(amm: AMM, cost: BN, targetPrice: BN): BN {
|
|
|
149
159
|
const x = amm.baseAssetReserve;
|
|
150
160
|
const y = amm.quoteAssetReserve;
|
|
151
161
|
|
|
152
|
-
const d = amm.
|
|
162
|
+
const d = amm.baseAssetAmountWithAmm;
|
|
153
163
|
const Q = amm.pegMultiplier;
|
|
154
164
|
|
|
155
165
|
const C = cost.mul(new BN(-1));
|
|
@@ -165,11 +175,11 @@ export function calculateBudgetedPeg(amm: AMM, cost: BN, targetPrice: BN): BN {
|
|
|
165
175
|
return targetPeg;
|
|
166
176
|
}
|
|
167
177
|
|
|
168
|
-
const deltaPegMultiplier = C.mul(
|
|
178
|
+
const deltaPegMultiplier = C.mul(PRICE_PRECISION).div(
|
|
169
179
|
deltaQuoteAssetReserves.div(AMM_TO_QUOTE_PRECISION_RATIO)
|
|
170
180
|
);
|
|
171
181
|
const newPeg = Q.sub(
|
|
172
|
-
deltaPegMultiplier.mul(PEG_PRECISION).div(
|
|
182
|
+
deltaPegMultiplier.mul(PEG_PRECISION).div(PRICE_PRECISION)
|
|
173
183
|
);
|
|
174
184
|
|
|
175
185
|
return newPeg;
|
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
import {
|
|
2
|
+
SpotMarketAccount,
|
|
3
|
+
SpotBalanceType,
|
|
4
|
+
isVariant,
|
|
5
|
+
MarginCategory,
|
|
6
|
+
} from '../types';
|
|
7
|
+
import { BN } from '@project-serum/anchor';
|
|
8
|
+
import {
|
|
9
|
+
SPOT_MARKET_UTILIZATION_PRECISION,
|
|
10
|
+
ONE,
|
|
11
|
+
TEN,
|
|
12
|
+
ZERO,
|
|
13
|
+
SPOT_MARKET_RATE_PRECISION,
|
|
14
|
+
SPOT_MARKET_WEIGHT_PRECISION,
|
|
15
|
+
ONE_YEAR,
|
|
16
|
+
AMM_RESERVE_PRECISION,
|
|
17
|
+
} from '../constants/numericConstants';
|
|
18
|
+
import {
|
|
19
|
+
calculateSizeDiscountAssetWeight,
|
|
20
|
+
calculateSizePremiumLiabilityWeight,
|
|
21
|
+
} from './margin';
|
|
22
|
+
import { OraclePriceData } from '../oracles/types';
|
|
23
|
+
|
|
24
|
+
export function getBalance(
|
|
25
|
+
tokenAmount: BN,
|
|
26
|
+
spotMarket: SpotMarketAccount,
|
|
27
|
+
balanceType: SpotBalanceType
|
|
28
|
+
): BN {
|
|
29
|
+
const precisionIncrease = TEN.pow(new BN(19 - spotMarket.decimals));
|
|
30
|
+
|
|
31
|
+
const cumulativeInterest = isVariant(balanceType, 'deposit')
|
|
32
|
+
? spotMarket.cumulativeDepositInterest
|
|
33
|
+
: spotMarket.cumulativeBorrowInterest;
|
|
34
|
+
|
|
35
|
+
let balance = tokenAmount.mul(precisionIncrease).div(cumulativeInterest);
|
|
36
|
+
|
|
37
|
+
if (!balance.eq(ZERO) && isVariant(balanceType, 'borrow')) {
|
|
38
|
+
balance = balance.add(ONE);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return balance;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function getTokenAmount(
|
|
45
|
+
balanceAmount: BN,
|
|
46
|
+
spotMarket: SpotMarketAccount,
|
|
47
|
+
balanceType: SpotBalanceType
|
|
48
|
+
): BN {
|
|
49
|
+
const precisionDecrease = TEN.pow(new BN(19 - spotMarket.decimals));
|
|
50
|
+
|
|
51
|
+
const cumulativeInterest = isVariant(balanceType, 'deposit')
|
|
52
|
+
? spotMarket.cumulativeDepositInterest
|
|
53
|
+
: spotMarket.cumulativeBorrowInterest;
|
|
54
|
+
|
|
55
|
+
return balanceAmount.mul(cumulativeInterest).div(precisionDecrease);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function getSignedTokenAmount(
|
|
59
|
+
tokenAmount: BN,
|
|
60
|
+
balanceType: SpotBalanceType
|
|
61
|
+
): BN {
|
|
62
|
+
if (isVariant(balanceType, 'deposit')) {
|
|
63
|
+
return tokenAmount;
|
|
64
|
+
} else {
|
|
65
|
+
return tokenAmount.abs().neg();
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function getTokenValue(
|
|
70
|
+
tokenAmount: BN,
|
|
71
|
+
spotDecimals: number,
|
|
72
|
+
oraclePriceData: OraclePriceData
|
|
73
|
+
): BN {
|
|
74
|
+
if (tokenAmount.eq(ZERO)) {
|
|
75
|
+
return ZERO;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const precisionDecrease = TEN.pow(new BN(spotDecimals));
|
|
79
|
+
|
|
80
|
+
return tokenAmount.mul(oraclePriceData.price).div(precisionDecrease);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function calculateAssetWeight(
|
|
84
|
+
balanceAmount: BN,
|
|
85
|
+
spotMarket: SpotMarketAccount,
|
|
86
|
+
marginCategory: MarginCategory
|
|
87
|
+
): BN {
|
|
88
|
+
const sizePrecision = TEN.pow(new BN(spotMarket.decimals));
|
|
89
|
+
let sizeInAmmReservePrecision;
|
|
90
|
+
if (sizePrecision.gt(AMM_RESERVE_PRECISION)) {
|
|
91
|
+
sizeInAmmReservePrecision = balanceAmount.div(
|
|
92
|
+
sizePrecision.div(AMM_RESERVE_PRECISION)
|
|
93
|
+
);
|
|
94
|
+
} else {
|
|
95
|
+
sizeInAmmReservePrecision = balanceAmount
|
|
96
|
+
.mul(AMM_RESERVE_PRECISION)
|
|
97
|
+
.div(sizePrecision);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
let assetWeight;
|
|
101
|
+
|
|
102
|
+
switch (marginCategory) {
|
|
103
|
+
case 'Initial':
|
|
104
|
+
assetWeight = calculateSizeDiscountAssetWeight(
|
|
105
|
+
sizeInAmmReservePrecision,
|
|
106
|
+
new BN(spotMarket.imfFactor),
|
|
107
|
+
new BN(spotMarket.initialAssetWeight)
|
|
108
|
+
);
|
|
109
|
+
break;
|
|
110
|
+
case 'Maintenance':
|
|
111
|
+
assetWeight = calculateSizeDiscountAssetWeight(
|
|
112
|
+
sizeInAmmReservePrecision,
|
|
113
|
+
new BN(spotMarket.imfFactor),
|
|
114
|
+
new BN(spotMarket.maintenanceAssetWeight)
|
|
115
|
+
);
|
|
116
|
+
break;
|
|
117
|
+
default:
|
|
118
|
+
assetWeight = new BN(spotMarket.initialAssetWeight);
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return assetWeight;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export function calculateLiabilityWeight(
|
|
126
|
+
balanceAmount: BN,
|
|
127
|
+
spotMarket: SpotMarketAccount,
|
|
128
|
+
marginCategory: MarginCategory
|
|
129
|
+
): BN {
|
|
130
|
+
const sizePrecision = TEN.pow(new BN(spotMarket.decimals));
|
|
131
|
+
let sizeInAmmReservePrecision;
|
|
132
|
+
if (sizePrecision.gt(AMM_RESERVE_PRECISION)) {
|
|
133
|
+
sizeInAmmReservePrecision = balanceAmount.div(
|
|
134
|
+
sizePrecision.div(AMM_RESERVE_PRECISION)
|
|
135
|
+
);
|
|
136
|
+
} else {
|
|
137
|
+
sizeInAmmReservePrecision = balanceAmount
|
|
138
|
+
.mul(AMM_RESERVE_PRECISION)
|
|
139
|
+
.div(sizePrecision);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
let assetWeight;
|
|
143
|
+
|
|
144
|
+
switch (marginCategory) {
|
|
145
|
+
case 'Initial':
|
|
146
|
+
assetWeight = calculateSizePremiumLiabilityWeight(
|
|
147
|
+
sizeInAmmReservePrecision,
|
|
148
|
+
new BN(spotMarket.imfFactor),
|
|
149
|
+
new BN(spotMarket.initialLiabilityWeight),
|
|
150
|
+
SPOT_MARKET_WEIGHT_PRECISION
|
|
151
|
+
);
|
|
152
|
+
break;
|
|
153
|
+
case 'Maintenance':
|
|
154
|
+
assetWeight = calculateSizePremiumLiabilityWeight(
|
|
155
|
+
sizeInAmmReservePrecision,
|
|
156
|
+
new BN(spotMarket.imfFactor),
|
|
157
|
+
new BN(spotMarket.maintenanceLiabilityWeight),
|
|
158
|
+
SPOT_MARKET_WEIGHT_PRECISION
|
|
159
|
+
);
|
|
160
|
+
break;
|
|
161
|
+
default:
|
|
162
|
+
assetWeight = spotMarket.initialLiabilityWeight;
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return assetWeight;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export function calculateUtilization(bank: SpotMarketAccount): BN {
|
|
170
|
+
const tokenDepositAmount = getTokenAmount(
|
|
171
|
+
bank.depositBalance,
|
|
172
|
+
bank,
|
|
173
|
+
SpotBalanceType.DEPOSIT
|
|
174
|
+
);
|
|
175
|
+
const tokenBorrowAmount = getTokenAmount(
|
|
176
|
+
bank.borrowBalance,
|
|
177
|
+
bank,
|
|
178
|
+
SpotBalanceType.BORROW
|
|
179
|
+
);
|
|
180
|
+
|
|
181
|
+
let utilization: BN;
|
|
182
|
+
if (tokenBorrowAmount.eq(ZERO) && tokenDepositAmount.eq(ZERO)) {
|
|
183
|
+
utilization = ZERO;
|
|
184
|
+
} else if (tokenDepositAmount.eq(ZERO)) {
|
|
185
|
+
utilization = SPOT_MARKET_UTILIZATION_PRECISION;
|
|
186
|
+
} else {
|
|
187
|
+
utilization = tokenBorrowAmount
|
|
188
|
+
.mul(SPOT_MARKET_UTILIZATION_PRECISION)
|
|
189
|
+
.div(tokenDepositAmount);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return utilization;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export function calculateInterestRate(bank: SpotMarketAccount): BN {
|
|
196
|
+
const utilization = calculateUtilization(bank);
|
|
197
|
+
|
|
198
|
+
let interestRate: BN;
|
|
199
|
+
if (utilization.gt(new BN(bank.optimalUtilization))) {
|
|
200
|
+
const surplusUtilization = utilization.sub(new BN(bank.optimalUtilization));
|
|
201
|
+
const borrowRateSlope = new BN(bank.maxBorrowRate - bank.optimalBorrowRate)
|
|
202
|
+
.mul(SPOT_MARKET_UTILIZATION_PRECISION)
|
|
203
|
+
.div(
|
|
204
|
+
SPOT_MARKET_UTILIZATION_PRECISION.sub(new BN(bank.optimalUtilization))
|
|
205
|
+
);
|
|
206
|
+
|
|
207
|
+
interestRate = new BN(bank.optimalBorrowRate).add(
|
|
208
|
+
surplusUtilization
|
|
209
|
+
.mul(borrowRateSlope)
|
|
210
|
+
.div(SPOT_MARKET_UTILIZATION_PRECISION)
|
|
211
|
+
);
|
|
212
|
+
} else {
|
|
213
|
+
const borrowRateSlope = new BN(bank.optimalBorrowRate)
|
|
214
|
+
.mul(SPOT_MARKET_UTILIZATION_PRECISION)
|
|
215
|
+
.div(
|
|
216
|
+
SPOT_MARKET_UTILIZATION_PRECISION.sub(new BN(bank.optimalUtilization))
|
|
217
|
+
);
|
|
218
|
+
|
|
219
|
+
interestRate = utilization
|
|
220
|
+
.mul(borrowRateSlope)
|
|
221
|
+
.div(SPOT_MARKET_UTILIZATION_PRECISION);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
return interestRate;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
export function calculateDepositRate(bank: SpotMarketAccount): BN {
|
|
228
|
+
const utilization = calculateUtilization(bank);
|
|
229
|
+
const borrowRate = calculateBorrowRate(bank);
|
|
230
|
+
const depositRate = borrowRate
|
|
231
|
+
.mul(utilization)
|
|
232
|
+
.div(SPOT_MARKET_UTILIZATION_PRECISION);
|
|
233
|
+
return depositRate;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
export function calculateBorrowRate(bank: SpotMarketAccount): BN {
|
|
237
|
+
return calculateInterestRate(bank);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
export function calculateInterestAccumulated(
|
|
241
|
+
bank: SpotMarketAccount,
|
|
242
|
+
now: BN
|
|
243
|
+
): { borrowInterest: BN; depositInterest: BN } {
|
|
244
|
+
const interestRate = calculateInterestRate(bank);
|
|
245
|
+
|
|
246
|
+
const timeSinceLastUpdate = now.sub(bank.lastInterestTs);
|
|
247
|
+
|
|
248
|
+
const modifiedBorrowRate = interestRate.mul(timeSinceLastUpdate);
|
|
249
|
+
|
|
250
|
+
const utilization = calculateUtilization(bank);
|
|
251
|
+
|
|
252
|
+
const modifiedDepositRate = modifiedBorrowRate
|
|
253
|
+
.mul(utilization)
|
|
254
|
+
.div(SPOT_MARKET_UTILIZATION_PRECISION);
|
|
255
|
+
|
|
256
|
+
const borrowInterest = bank.cumulativeBorrowInterest
|
|
257
|
+
.mul(modifiedBorrowRate)
|
|
258
|
+
.div(ONE_YEAR)
|
|
259
|
+
.div(SPOT_MARKET_RATE_PRECISION)
|
|
260
|
+
.add(ONE);
|
|
261
|
+
const depositInterest = bank.cumulativeDepositInterest
|
|
262
|
+
.mul(modifiedDepositRate)
|
|
263
|
+
.div(ONE_YEAR)
|
|
264
|
+
.div(SPOT_MARKET_RATE_PRECISION);
|
|
265
|
+
|
|
266
|
+
return { borrowInterest, depositInterest };
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
export function calculateWithdrawLimit(
|
|
270
|
+
spotMarket: SpotMarketAccount,
|
|
271
|
+
now: BN
|
|
272
|
+
): { borrowLimit: BN; withdrawLimit: BN } {
|
|
273
|
+
const marketDepositTokenAmount = getTokenAmount(
|
|
274
|
+
spotMarket.depositBalance,
|
|
275
|
+
spotMarket,
|
|
276
|
+
SpotBalanceType.DEPOSIT
|
|
277
|
+
);
|
|
278
|
+
const marketBorrowTokenAmount = getTokenAmount(
|
|
279
|
+
spotMarket.borrowBalance,
|
|
280
|
+
spotMarket,
|
|
281
|
+
SpotBalanceType.BORROW
|
|
282
|
+
);
|
|
283
|
+
|
|
284
|
+
const twentyFourHours = new BN(60 * 60 * 24);
|
|
285
|
+
const sinceLast = now.sub(spotMarket.lastTwapTs);
|
|
286
|
+
const sinceStart = BN.max(ZERO, twentyFourHours.sub(sinceLast));
|
|
287
|
+
const borrowTokenTwapLive = spotMarket.borrowTokenTwap
|
|
288
|
+
.mul(sinceStart)
|
|
289
|
+
.add(marketBorrowTokenAmount.mul(sinceLast))
|
|
290
|
+
.div(sinceLast.add(sinceStart));
|
|
291
|
+
|
|
292
|
+
const depositTokenTwapLive = spotMarket.depositTokenTwap
|
|
293
|
+
.mul(sinceStart)
|
|
294
|
+
.add(marketDepositTokenAmount.mul(sinceLast))
|
|
295
|
+
.div(sinceLast.add(sinceStart));
|
|
296
|
+
|
|
297
|
+
const maxBorrowTokens = BN.min(
|
|
298
|
+
BN.max(
|
|
299
|
+
marketDepositTokenAmount.div(new BN(6)),
|
|
300
|
+
borrowTokenTwapLive.add(borrowTokenTwapLive.div(new BN(5)))
|
|
301
|
+
),
|
|
302
|
+
marketDepositTokenAmount.sub(marketDepositTokenAmount.div(new BN(5)))
|
|
303
|
+
); // between ~15-80% utilization with friction on twap
|
|
304
|
+
|
|
305
|
+
const minDepositTokens = depositTokenTwapLive.sub(
|
|
306
|
+
BN.min(
|
|
307
|
+
BN.max(
|
|
308
|
+
depositTokenTwapLive.div(new BN(5)),
|
|
309
|
+
spotMarket.withdrawGuardThreshold
|
|
310
|
+
),
|
|
311
|
+
depositTokenTwapLive
|
|
312
|
+
)
|
|
313
|
+
);
|
|
314
|
+
|
|
315
|
+
return {
|
|
316
|
+
borrowLimit: maxBorrowTokens.sub(marketBorrowTokenAmount),
|
|
317
|
+
withdrawLimit: marketDepositTokenAmount.sub(minDepositTokens),
|
|
318
|
+
};
|
|
319
|
+
}
|