@drift-labs/sdk 0.2.0-master.25 → 0.2.0-master.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/accounts/pollingClearingHouseAccountSubscriber.d.ts +14 -13
- package/lib/accounts/pollingClearingHouseAccountSubscriber.js +30 -27
- package/lib/accounts/types.d.ts +9 -9
- package/lib/accounts/webSocketClearingHouseAccountSubscriber.d.ts +15 -14
- package/lib/accounts/webSocketClearingHouseAccountSubscriber.js +38 -34
- package/lib/addresses/pda.d.ts +7 -6
- package/lib/addresses/pda.js +31 -27
- package/lib/admin.d.ts +13 -7
- package/lib/admin.js +111 -44
- package/lib/clearingHouse.d.ts +71 -42
- package/lib/clearingHouse.js +767 -278
- package/lib/clearingHouseConfig.d.ts +2 -2
- package/lib/clearingHouseUser.d.ts +24 -22
- package/lib/clearingHouseUser.js +273 -177
- package/lib/config.d.ts +7 -7
- package/lib/config.js +21 -21
- package/lib/constants/numericConstants.d.ts +12 -12
- package/lib/constants/numericConstants.js +13 -13
- package/lib/constants/{markets.d.ts → perpMarkets.d.ts} +5 -5
- package/lib/constants/{markets.js → perpMarkets.js} +4 -4
- package/lib/constants/{banks.d.ts → spotMarkets.d.ts} +6 -6
- package/lib/constants/{banks.js → spotMarkets.js} +16 -16
- package/lib/dlob/DLOB.d.ts +73 -0
- package/lib/dlob/DLOB.js +557 -0
- package/lib/dlob/DLOBNode.d.ts +52 -0
- package/lib/dlob/DLOBNode.js +82 -0
- package/lib/dlob/NodeList.d.ts +26 -0
- package/lib/dlob/NodeList.js +138 -0
- package/lib/events/types.d.ts +2 -1
- package/lib/events/types.js +1 -0
- package/lib/examples/makeTradeExample.js +7 -7
- package/lib/idl/clearing_house.json +1152 -503
- package/lib/index.d.ts +10 -3
- package/lib/index.js +10 -3
- package/lib/math/amm.d.ts +2 -2
- package/lib/math/amm.js +1 -1
- package/lib/math/funding.d.ts +6 -6
- package/lib/math/funding.js +2 -1
- package/lib/math/margin.d.ts +4 -4
- package/lib/math/margin.js +18 -11
- package/lib/math/market.d.ts +11 -10
- package/lib/math/market.js +30 -7
- package/lib/math/oracles.d.ts +2 -1
- package/lib/math/oracles.js +11 -1
- package/lib/math/orders.d.ts +6 -6
- package/lib/math/orders.js +31 -16
- package/lib/math/position.d.ts +13 -13
- package/lib/math/position.js +19 -19
- package/lib/math/spotBalance.d.ts +22 -0
- package/lib/math/spotBalance.js +193 -0
- package/lib/math/spotMarket.d.ts +4 -0
- package/lib/math/spotMarket.js +8 -0
- package/lib/math/spotPosition.d.ts +6 -0
- package/lib/math/spotPosition.js +23 -0
- package/lib/math/state.js +2 -2
- package/lib/math/trade.d.ts +4 -4
- package/lib/orderParams.d.ts +4 -4
- package/lib/orderParams.js +12 -4
- package/lib/serum/serumSubscriber.d.ts +23 -0
- package/lib/serum/serumSubscriber.js +41 -0
- package/lib/serum/types.d.ts +11 -0
- package/lib/serum/types.js +2 -0
- package/lib/tx/retryTxSender.d.ts +1 -1
- package/lib/tx/retryTxSender.js +4 -2
- package/lib/tx/types.d.ts +1 -1
- package/lib/types.d.ts +148 -57
- package/lib/types.js +39 -11
- package/lib/userMap/userMap.d.ts +25 -0
- package/lib/userMap/userMap.js +73 -0
- package/lib/userMap/userStatsMap.d.ts +19 -0
- package/lib/userMap/userStatsMap.js +68 -0
- package/package.json +6 -3
- package/src/accounts/pollingClearingHouseAccountSubscriber.ts +42 -38
- package/src/accounts/types.ts +12 -9
- package/src/accounts/webSocketClearingHouseAccountSubscriber.ts +65 -52
- package/src/addresses/pda.ts +49 -44
- package/src/admin.ts +190 -55
- package/src/clearingHouse.ts +1092 -365
- package/src/clearingHouseConfig.ts +2 -2
- package/src/clearingHouseUser.ts +518 -255
- package/src/config.ts +30 -30
- package/src/constants/numericConstants.ts +17 -15
- package/src/constants/{markets.ts → perpMarkets.ts} +5 -5
- package/src/constants/{banks.ts → spotMarkets.ts} +19 -19
- package/src/dlob/DLOB.ts +884 -0
- package/src/dlob/DLOBNode.ts +163 -0
- package/src/dlob/NodeList.ts +185 -0
- package/src/events/types.ts +3 -0
- package/src/examples/makeTradeExample.js +152 -75
- package/src/examples/makeTradeExample.ts +10 -8
- package/src/idl/clearing_house.json +1152 -503
- package/src/index.ts +10 -3
- package/src/math/amm.ts +6 -3
- package/src/math/funding.ts +7 -7
- package/src/math/margin.ts +34 -23
- package/src/math/market.ts +72 -20
- package/src/math/oracles.ts +18 -1
- package/src/math/orders.ts +33 -25
- package/src/math/position.ts +31 -31
- package/src/math/spotBalance.ts +316 -0
- package/src/math/spotMarket.ts +9 -0
- package/src/math/spotPosition.ts +47 -0
- package/src/math/state.ts +2 -2
- package/src/math/trade.ts +4 -4
- package/src/orderParams.ts +16 -8
- package/src/serum/serumSubscriber.ts +80 -0
- package/src/serum/types.ts +13 -0
- package/src/tx/retryTxSender.ts +5 -2
- package/src/tx/types.ts +2 -1
- package/src/types.ts +135 -56
- package/src/userMap/userMap.ts +100 -0
- package/src/userMap/userStatsMap.ts +110 -0
- package/tests/bn/test.ts +2 -3
- package/tests/dlob/helpers.ts +322 -0
- package/tests/dlob/test.ts +2865 -0
- package/lib/math/bankBalance.d.ts +0 -15
- package/lib/math/bankBalance.js +0 -150
- package/src/constants/numericConstants.js +0 -41
- package/src/math/bankBalance.ts +0 -258
- package/src/math/oracles.js +0 -26
- package/src/math/state.js +0 -15
- package/src/orderParams.js +0 -20
- package/src/slot/SlotSubscriber.js +0 -39
- package/src/tokenFaucet.js +0 -189
package/src/math/position.ts
CHANGED
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
ZERO,
|
|
11
11
|
} from '../constants/numericConstants';
|
|
12
12
|
import { OraclePriceData } from '../oracles/types';
|
|
13
|
-
import {
|
|
13
|
+
import { PerpMarketAccount, PositionDirection, PerpPosition } from '../types';
|
|
14
14
|
import {
|
|
15
15
|
calculateUpdatedAMM,
|
|
16
16
|
calculateUpdatedAMMSpreadReserves,
|
|
@@ -29,8 +29,8 @@ import { calculateBaseAssetValueWithOracle } from './margin';
|
|
|
29
29
|
* @returns Base Asset Value. : Precision QUOTE_PRECISION
|
|
30
30
|
*/
|
|
31
31
|
export function calculateBaseAssetValue(
|
|
32
|
-
market:
|
|
33
|
-
userPosition:
|
|
32
|
+
market: PerpMarketAccount,
|
|
33
|
+
userPosition: PerpPosition,
|
|
34
34
|
oraclePriceData: OraclePriceData
|
|
35
35
|
): BN {
|
|
36
36
|
if (userPosition.baseAssetAmount.eq(ZERO)) {
|
|
@@ -84,38 +84,38 @@ export function calculateBaseAssetValue(
|
|
|
84
84
|
* calculatePositionPNL
|
|
85
85
|
* = BaseAssetAmount * (Avg Exit Price - Avg Entry Price)
|
|
86
86
|
* @param market
|
|
87
|
-
* @param
|
|
87
|
+
* @param PerpPosition
|
|
88
88
|
* @param withFunding (adds unrealized funding payment pnl to result)
|
|
89
89
|
* @param oraclePriceData
|
|
90
90
|
* @returns BaseAssetAmount : Precision QUOTE_PRECISION
|
|
91
91
|
*/
|
|
92
92
|
export function calculatePositionPNL(
|
|
93
|
-
market:
|
|
94
|
-
|
|
93
|
+
market: PerpMarketAccount,
|
|
94
|
+
perpPosition: PerpPosition,
|
|
95
95
|
withFunding = false,
|
|
96
96
|
oraclePriceData: OraclePriceData
|
|
97
97
|
): BN {
|
|
98
|
-
if (
|
|
99
|
-
return
|
|
98
|
+
if (perpPosition.baseAssetAmount.eq(ZERO)) {
|
|
99
|
+
return perpPosition.quoteAssetAmount;
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
const baseAssetValue = calculateBaseAssetValueWithOracle(
|
|
103
103
|
market,
|
|
104
|
-
|
|
104
|
+
perpPosition,
|
|
105
105
|
oraclePriceData
|
|
106
106
|
);
|
|
107
107
|
|
|
108
|
-
const baseAssetValueSign =
|
|
108
|
+
const baseAssetValueSign = perpPosition.baseAssetAmount.isNeg()
|
|
109
109
|
? new BN(-1)
|
|
110
110
|
: new BN(1);
|
|
111
111
|
let pnl = baseAssetValue
|
|
112
112
|
.mul(baseAssetValueSign)
|
|
113
|
-
.add(
|
|
113
|
+
.add(perpPosition.quoteAssetAmount);
|
|
114
114
|
|
|
115
115
|
if (withFunding) {
|
|
116
116
|
const fundingRatePnL = calculatePositionFundingPNL(
|
|
117
117
|
market,
|
|
118
|
-
|
|
118
|
+
perpPosition
|
|
119
119
|
).div(PRICE_TO_QUOTE_PRECISION);
|
|
120
120
|
|
|
121
121
|
pnl = pnl.add(fundingRatePnL);
|
|
@@ -125,26 +125,26 @@ export function calculatePositionPNL(
|
|
|
125
125
|
}
|
|
126
126
|
|
|
127
127
|
export function calculateUnsettledPnl(
|
|
128
|
-
market:
|
|
129
|
-
|
|
128
|
+
market: PerpMarketAccount,
|
|
129
|
+
perpPosition: PerpPosition,
|
|
130
130
|
oraclePriceData: OraclePriceData
|
|
131
131
|
): BN {
|
|
132
132
|
const unrealizedPnl = calculatePositionPNL(
|
|
133
133
|
market,
|
|
134
|
-
|
|
134
|
+
perpPosition,
|
|
135
135
|
true,
|
|
136
136
|
oraclePriceData
|
|
137
137
|
);
|
|
138
138
|
|
|
139
139
|
let unsettledPnl = unrealizedPnl;
|
|
140
140
|
if (unrealizedPnl.gt(ZERO)) {
|
|
141
|
-
const fundingPnL = calculatePositionFundingPNL(market,
|
|
141
|
+
const fundingPnL = calculatePositionFundingPNL(market, perpPosition).div(
|
|
142
142
|
PRICE_TO_QUOTE_PRECISION
|
|
143
143
|
);
|
|
144
144
|
|
|
145
145
|
const maxPositivePnl = BN.max(
|
|
146
|
-
|
|
147
|
-
.sub(
|
|
146
|
+
perpPosition.quoteAssetAmount
|
|
147
|
+
.sub(perpPosition.quoteEntryAmount)
|
|
148
148
|
.add(fundingPnL),
|
|
149
149
|
ZERO
|
|
150
150
|
);
|
|
@@ -157,27 +157,27 @@ export function calculateUnsettledPnl(
|
|
|
157
157
|
/**
|
|
158
158
|
*
|
|
159
159
|
* @param market
|
|
160
|
-
* @param
|
|
160
|
+
* @param PerpPosition
|
|
161
161
|
* @returns // TODO-PRECISION
|
|
162
162
|
*/
|
|
163
163
|
export function calculatePositionFundingPNL(
|
|
164
|
-
market:
|
|
165
|
-
|
|
164
|
+
market: PerpMarketAccount,
|
|
165
|
+
perpPosition: PerpPosition
|
|
166
166
|
): BN {
|
|
167
|
-
if (
|
|
167
|
+
if (perpPosition.baseAssetAmount.eq(ZERO)) {
|
|
168
168
|
return ZERO;
|
|
169
169
|
}
|
|
170
170
|
|
|
171
171
|
let ammCumulativeFundingRate: BN;
|
|
172
|
-
if (
|
|
172
|
+
if (perpPosition.baseAssetAmount.gt(ZERO)) {
|
|
173
173
|
ammCumulativeFundingRate = market.amm.cumulativeFundingRateLong;
|
|
174
174
|
} else {
|
|
175
175
|
ammCumulativeFundingRate = market.amm.cumulativeFundingRateShort;
|
|
176
176
|
}
|
|
177
177
|
|
|
178
178
|
const perPositionFundingRate = ammCumulativeFundingRate
|
|
179
|
-
.sub(
|
|
180
|
-
.mul(
|
|
179
|
+
.sub(perpPosition.lastCumulativeFundingRate)
|
|
180
|
+
.mul(perpPosition.baseAssetAmount)
|
|
181
181
|
.div(AMM_RESERVE_PRECISION)
|
|
182
182
|
.div(FUNDING_PAYMENT_PRECISION)
|
|
183
183
|
.mul(new BN(-1));
|
|
@@ -185,7 +185,7 @@ export function calculatePositionFundingPNL(
|
|
|
185
185
|
return perPositionFundingRate;
|
|
186
186
|
}
|
|
187
187
|
|
|
188
|
-
export function positionIsAvailable(position:
|
|
188
|
+
export function positionIsAvailable(position: PerpPosition): boolean {
|
|
189
189
|
return (
|
|
190
190
|
position.baseAssetAmount.eq(ZERO) &&
|
|
191
191
|
position.openOrders.eq(ZERO) &&
|
|
@@ -199,7 +199,7 @@ export function positionIsAvailable(position: UserPosition): boolean {
|
|
|
199
199
|
* @param userPosition
|
|
200
200
|
* @returns Precision: MARK_PRICE_PRECISION (10^10)
|
|
201
201
|
*/
|
|
202
|
-
export function calculateEntryPrice(userPosition:
|
|
202
|
+
export function calculateEntryPrice(userPosition: PerpPosition): BN {
|
|
203
203
|
if (userPosition.baseAssetAmount.eq(ZERO)) {
|
|
204
204
|
return ZERO;
|
|
205
205
|
}
|
|
@@ -216,7 +216,7 @@ export function calculateEntryPrice(userPosition: UserPosition): BN {
|
|
|
216
216
|
* @param userPosition
|
|
217
217
|
* @returns Precision: MARK_PRICE_PRECISION (10^10)
|
|
218
218
|
*/
|
|
219
|
-
export function calculateCostBasis(userPosition:
|
|
219
|
+
export function calculateCostBasis(userPosition: PerpPosition): BN {
|
|
220
220
|
if (userPosition.baseAssetAmount.eq(ZERO)) {
|
|
221
221
|
return ZERO;
|
|
222
222
|
}
|
|
@@ -229,7 +229,7 @@ export function calculateCostBasis(userPosition: UserPosition): BN {
|
|
|
229
229
|
}
|
|
230
230
|
|
|
231
231
|
export function findDirectionToClose(
|
|
232
|
-
userPosition:
|
|
232
|
+
userPosition: PerpPosition
|
|
233
233
|
): PositionDirection {
|
|
234
234
|
return userPosition.baseAssetAmount.gt(ZERO)
|
|
235
235
|
? PositionDirection.SHORT
|
|
@@ -237,14 +237,14 @@ export function findDirectionToClose(
|
|
|
237
237
|
}
|
|
238
238
|
|
|
239
239
|
export function positionCurrentDirection(
|
|
240
|
-
userPosition:
|
|
240
|
+
userPosition: PerpPosition
|
|
241
241
|
): PositionDirection {
|
|
242
242
|
return userPosition.baseAssetAmount.gte(ZERO)
|
|
243
243
|
? PositionDirection.LONG
|
|
244
244
|
: PositionDirection.SHORT;
|
|
245
245
|
}
|
|
246
246
|
|
|
247
|
-
export function isEmptyPosition(userPosition:
|
|
247
|
+
export function isEmptyPosition(userPosition: PerpPosition): boolean {
|
|
248
248
|
return (
|
|
249
249
|
userPosition.baseAssetAmount.eq(ZERO) && userPosition.openOrders.eq(ZERO)
|
|
250
250
|
);
|
|
@@ -0,0 +1,316 @@
|
|
|
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_INTEREST_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(16 - 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(16 - 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(10 + spotDecimals - 6));
|
|
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
|
+
spotMarket.imfFactor,
|
|
107
|
+
spotMarket.initialAssetWeight
|
|
108
|
+
);
|
|
109
|
+
break;
|
|
110
|
+
case 'Maintenance':
|
|
111
|
+
assetWeight = calculateSizeDiscountAssetWeight(
|
|
112
|
+
sizeInAmmReservePrecision,
|
|
113
|
+
spotMarket.imfFactor,
|
|
114
|
+
spotMarket.maintenanceAssetWeight
|
|
115
|
+
);
|
|
116
|
+
break;
|
|
117
|
+
default:
|
|
118
|
+
assetWeight = 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
|
+
spotMarket.imfFactor,
|
|
149
|
+
spotMarket.initialLiabilityWeight,
|
|
150
|
+
SPOT_MARKET_WEIGHT_PRECISION
|
|
151
|
+
);
|
|
152
|
+
break;
|
|
153
|
+
case 'Maintenance':
|
|
154
|
+
assetWeight = calculateSizePremiumLiabilityWeight(
|
|
155
|
+
sizeInAmmReservePrecision,
|
|
156
|
+
spotMarket.imfFactor,
|
|
157
|
+
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(bank.optimalUtilization)) {
|
|
200
|
+
const surplusUtilization = utilization.sub(bank.optimalUtilization);
|
|
201
|
+
const borrowRateSlope = bank.maxBorrowRate
|
|
202
|
+
.sub(bank.optimalBorrowRate)
|
|
203
|
+
.mul(SPOT_MARKET_UTILIZATION_PRECISION)
|
|
204
|
+
.div(SPOT_MARKET_UTILIZATION_PRECISION.sub(bank.optimalUtilization));
|
|
205
|
+
|
|
206
|
+
interestRate = bank.optimalBorrowRate.add(
|
|
207
|
+
surplusUtilization
|
|
208
|
+
.mul(borrowRateSlope)
|
|
209
|
+
.div(SPOT_MARKET_UTILIZATION_PRECISION)
|
|
210
|
+
);
|
|
211
|
+
} else {
|
|
212
|
+
const borrowRateSlope = bank.optimalBorrowRate
|
|
213
|
+
.mul(SPOT_MARKET_UTILIZATION_PRECISION)
|
|
214
|
+
.div(SPOT_MARKET_UTILIZATION_PRECISION.sub(bank.optimalUtilization));
|
|
215
|
+
|
|
216
|
+
interestRate = utilization
|
|
217
|
+
.mul(borrowRateSlope)
|
|
218
|
+
.div(SPOT_MARKET_UTILIZATION_PRECISION);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
return interestRate;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
export function calculateDepositRate(bank: SpotMarketAccount): BN {
|
|
225
|
+
const utilization = calculateUtilization(bank);
|
|
226
|
+
const borrowRate = calculateBorrowRate(bank);
|
|
227
|
+
const depositRate = borrowRate
|
|
228
|
+
.mul(utilization)
|
|
229
|
+
.div(SPOT_MARKET_UTILIZATION_PRECISION);
|
|
230
|
+
return depositRate;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
export function calculateBorrowRate(bank: SpotMarketAccount): BN {
|
|
234
|
+
return calculateInterestRate(bank);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
export function calculateInterestAccumulated(
|
|
238
|
+
bank: SpotMarketAccount,
|
|
239
|
+
now: BN
|
|
240
|
+
): { borrowInterest: BN; depositInterest: BN } {
|
|
241
|
+
const interestRate = calculateInterestRate(bank);
|
|
242
|
+
|
|
243
|
+
const timeSinceLastUpdate = now.sub(bank.lastInterestTs);
|
|
244
|
+
|
|
245
|
+
const modifiedBorrowRate = interestRate.mul(timeSinceLastUpdate);
|
|
246
|
+
|
|
247
|
+
const utilization = calculateUtilization(bank);
|
|
248
|
+
|
|
249
|
+
const modifiedDepositRate = modifiedBorrowRate
|
|
250
|
+
.mul(utilization)
|
|
251
|
+
.div(SPOT_MARKET_UTILIZATION_PRECISION);
|
|
252
|
+
|
|
253
|
+
const borrowInterest = bank.cumulativeBorrowInterest
|
|
254
|
+
.mul(modifiedBorrowRate)
|
|
255
|
+
.div(ONE_YEAR)
|
|
256
|
+
.div(SPOT_MARKET_INTEREST_PRECISION)
|
|
257
|
+
.add(ONE);
|
|
258
|
+
const depositInterest = bank.cumulativeDepositInterest
|
|
259
|
+
.mul(modifiedDepositRate)
|
|
260
|
+
.div(ONE_YEAR)
|
|
261
|
+
.div(SPOT_MARKET_INTEREST_PRECISION);
|
|
262
|
+
|
|
263
|
+
return { borrowInterest, depositInterest };
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
export function calculateWithdrawLimit(
|
|
267
|
+
spotMarket: SpotMarketAccount,
|
|
268
|
+
now: BN
|
|
269
|
+
): { borrowLimit: BN; withdrawLimit: BN } {
|
|
270
|
+
const marketDepositTokenAmount = getTokenAmount(
|
|
271
|
+
spotMarket.depositBalance,
|
|
272
|
+
spotMarket,
|
|
273
|
+
SpotBalanceType.DEPOSIT
|
|
274
|
+
);
|
|
275
|
+
const marketBorrowTokenAmount = getTokenAmount(
|
|
276
|
+
spotMarket.borrowBalance,
|
|
277
|
+
spotMarket,
|
|
278
|
+
SpotBalanceType.BORROW
|
|
279
|
+
);
|
|
280
|
+
|
|
281
|
+
const twentyFourHours = new BN(60 * 60 * 24);
|
|
282
|
+
const sinceLast = now.sub(spotMarket.lastTwapTs);
|
|
283
|
+
const sinceStart = BN.max(ZERO, twentyFourHours.sub(sinceLast));
|
|
284
|
+
const borrowTokenTwapLive = spotMarket.borrowTokenTwap
|
|
285
|
+
.mul(sinceStart)
|
|
286
|
+
.add(marketBorrowTokenAmount.mul(sinceLast))
|
|
287
|
+
.div(sinceLast.add(sinceLast));
|
|
288
|
+
|
|
289
|
+
const depositTokenTwapLive = spotMarket.depositTokenTwap
|
|
290
|
+
.mul(sinceStart)
|
|
291
|
+
.add(marketDepositTokenAmount.mul(sinceLast))
|
|
292
|
+
.div(sinceLast.add(sinceLast));
|
|
293
|
+
|
|
294
|
+
const maxBorrowTokens = BN.min(
|
|
295
|
+
BN.max(
|
|
296
|
+
marketDepositTokenAmount.div(new BN(6)),
|
|
297
|
+
borrowTokenTwapLive.add(borrowTokenTwapLive.div(new BN(5)))
|
|
298
|
+
),
|
|
299
|
+
marketDepositTokenAmount.sub(marketDepositTokenAmount.div(new BN(10)))
|
|
300
|
+
); // between ~15-90% utilization with friction on twap
|
|
301
|
+
|
|
302
|
+
const minDepositTokens = depositTokenTwapLive.sub(
|
|
303
|
+
BN.min(
|
|
304
|
+
BN.max(
|
|
305
|
+
depositTokenTwapLive.div(new BN(5)),
|
|
306
|
+
spotMarket.withdrawGuardThreshold
|
|
307
|
+
),
|
|
308
|
+
depositTokenTwapLive
|
|
309
|
+
)
|
|
310
|
+
);
|
|
311
|
+
|
|
312
|
+
return {
|
|
313
|
+
borrowLimit: maxBorrowTokens.sub(marketBorrowTokenAmount),
|
|
314
|
+
withdrawLimit: marketDepositTokenAmount.sub(minDepositTokens),
|
|
315
|
+
};
|
|
316
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { SpotMarketAccount, SpotPosition } from '../types';
|
|
2
|
+
import { ZERO } from '../constants/numericConstants';
|
|
3
|
+
import { BN } from '@project-serum/anchor';
|
|
4
|
+
import {
|
|
5
|
+
getSignedTokenAmount,
|
|
6
|
+
getTokenAmount,
|
|
7
|
+
getTokenValue,
|
|
8
|
+
} from './spotBalance';
|
|
9
|
+
import { OraclePriceData } from '../oracles/types';
|
|
10
|
+
|
|
11
|
+
export function isSpotPositionAvailable(position: SpotPosition): boolean {
|
|
12
|
+
return position.balance.eq(ZERO) && position.openOrders === 0;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function getWorstCaseTokenAmounts(
|
|
16
|
+
spotPosition: SpotPosition,
|
|
17
|
+
spotMarketAccount: SpotMarketAccount,
|
|
18
|
+
oraclePriceData: OraclePriceData
|
|
19
|
+
): [BN, BN] {
|
|
20
|
+
const tokenAmount = getSignedTokenAmount(
|
|
21
|
+
getTokenAmount(
|
|
22
|
+
spotPosition.balance,
|
|
23
|
+
spotMarketAccount,
|
|
24
|
+
spotPosition.balanceType
|
|
25
|
+
),
|
|
26
|
+
spotPosition.balanceType
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
const tokenAmountAllBidsFill = tokenAmount.add(spotPosition.openBids);
|
|
30
|
+
const tokenAmountAllAsksFill = tokenAmount.add(spotPosition.openAsks);
|
|
31
|
+
|
|
32
|
+
if (tokenAmountAllAsksFill.abs().gt(tokenAmountAllBidsFill.abs())) {
|
|
33
|
+
const worstCaseQuoteTokenAmount = getTokenValue(
|
|
34
|
+
spotPosition.openBids.neg(),
|
|
35
|
+
spotMarketAccount.decimals,
|
|
36
|
+
oraclePriceData
|
|
37
|
+
);
|
|
38
|
+
return [tokenAmountAllBidsFill, worstCaseQuoteTokenAmount];
|
|
39
|
+
} else {
|
|
40
|
+
const worstCaseQuoteTokenAmount = getTokenValue(
|
|
41
|
+
spotPosition.openAsks.neg(),
|
|
42
|
+
spotMarketAccount.decimals,
|
|
43
|
+
oraclePriceData
|
|
44
|
+
);
|
|
45
|
+
return [tokenAmountAllAsksFill, worstCaseQuoteTokenAmount];
|
|
46
|
+
}
|
|
47
|
+
}
|
package/src/math/state.ts
CHANGED
|
@@ -8,7 +8,7 @@ import { StateAccount } from '../types';
|
|
|
8
8
|
*/
|
|
9
9
|
export function getExchangeFee(state: StateAccount): number {
|
|
10
10
|
const exchangeFee =
|
|
11
|
-
state.
|
|
12
|
-
state.
|
|
11
|
+
state.perpFeeStructure.feeNumerator.toNumber() /
|
|
12
|
+
state.perpFeeStructure.feeDenominator.toNumber();
|
|
13
13
|
return exchangeFee;
|
|
14
14
|
}
|
package/src/math/trade.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { PerpMarketAccount, PositionDirection } from '../types';
|
|
2
2
|
import { BN } from '@project-serum/anchor';
|
|
3
3
|
import { assert } from '../assert/assert';
|
|
4
4
|
import {
|
|
@@ -59,7 +59,7 @@ export type PriceImpactUnit =
|
|
|
59
59
|
export function calculateTradeSlippage(
|
|
60
60
|
direction: PositionDirection,
|
|
61
61
|
amount: BN,
|
|
62
|
-
market:
|
|
62
|
+
market: PerpMarketAccount,
|
|
63
63
|
inputAssetType: AssetType = 'quote',
|
|
64
64
|
oraclePriceData?: OraclePriceData,
|
|
65
65
|
useSpread = true
|
|
@@ -147,7 +147,7 @@ export function calculateTradeSlippage(
|
|
|
147
147
|
export function calculateTradeAcquiredAmounts(
|
|
148
148
|
direction: PositionDirection,
|
|
149
149
|
amount: BN,
|
|
150
|
-
market:
|
|
150
|
+
market: PerpMarketAccount,
|
|
151
151
|
inputAssetType: AssetType = 'quote',
|
|
152
152
|
oraclePriceData: OraclePriceData,
|
|
153
153
|
useSpread = true
|
|
@@ -204,7 +204,7 @@ export function calculateTradeAcquiredAmounts(
|
|
|
204
204
|
* ]
|
|
205
205
|
*/
|
|
206
206
|
export function calculateTargetPriceTrade(
|
|
207
|
-
market:
|
|
207
|
+
market: PerpMarketAccount,
|
|
208
208
|
targetPrice: BN,
|
|
209
209
|
pct: BN = MAXPCT,
|
|
210
210
|
outputAssetType: AssetType = 'quote',
|
package/src/orderParams.ts
CHANGED
|
@@ -2,32 +2,40 @@ import { OptionalOrderParams, OrderTriggerCondition, OrderType } from './types';
|
|
|
2
2
|
import { BN } from '@project-serum/anchor';
|
|
3
3
|
|
|
4
4
|
export function getLimitOrderParams(
|
|
5
|
-
params: Omit<OptionalOrderParams, 'orderType'> & { price: BN }
|
|
5
|
+
params: Omit<OptionalOrderParams, 'orderType' | 'marketType'> & { price: BN }
|
|
6
6
|
): OptionalOrderParams {
|
|
7
|
-
return Object.assign({}, params, {
|
|
7
|
+
return Object.assign({}, params, {
|
|
8
|
+
orderType: OrderType.LIMIT,
|
|
9
|
+
});
|
|
8
10
|
}
|
|
9
11
|
|
|
10
12
|
export function getTriggerMarketOrderParams(
|
|
11
|
-
params: Omit<OptionalOrderParams, 'orderType'> & {
|
|
13
|
+
params: Omit<OptionalOrderParams, 'orderType' | 'marketType'> & {
|
|
12
14
|
triggerCondition: OrderTriggerCondition;
|
|
13
15
|
triggerPrice: BN;
|
|
14
16
|
}
|
|
15
17
|
): OptionalOrderParams {
|
|
16
|
-
return Object.assign({}, params, {
|
|
18
|
+
return Object.assign({}, params, {
|
|
19
|
+
orderType: OrderType.TRIGGER_MARKET,
|
|
20
|
+
});
|
|
17
21
|
}
|
|
18
22
|
|
|
19
23
|
export function getTriggerLimitOrderParams(
|
|
20
|
-
params: Omit<OptionalOrderParams, 'orderType'> & {
|
|
24
|
+
params: Omit<OptionalOrderParams, 'orderType' | 'marketType'> & {
|
|
21
25
|
triggerCondition: OrderTriggerCondition;
|
|
22
26
|
triggerPrice: BN;
|
|
23
27
|
price: BN;
|
|
24
28
|
}
|
|
25
29
|
): OptionalOrderParams {
|
|
26
|
-
return Object.assign({}, params, {
|
|
30
|
+
return Object.assign({}, params, {
|
|
31
|
+
orderType: OrderType.TRIGGER_LIMIT,
|
|
32
|
+
});
|
|
27
33
|
}
|
|
28
34
|
|
|
29
35
|
export function getMarketOrderParams(
|
|
30
|
-
params: Omit<OptionalOrderParams, 'orderType'>
|
|
36
|
+
params: Omit<OptionalOrderParams, 'orderType' | 'marketType'>
|
|
31
37
|
): OptionalOrderParams {
|
|
32
|
-
return Object.assign({}, params, {
|
|
38
|
+
return Object.assign({}, params, {
|
|
39
|
+
orderType: OrderType.MARKET,
|
|
40
|
+
});
|
|
33
41
|
}
|