@drift-labs/sdk 0.2.0-master.32 → 0.2.0-master.33
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/bulkAccountLoader.js +2 -1
- package/lib/accounts/pollingClearingHouseAccountSubscriber.d.ts +2 -2
- package/lib/accounts/pollingClearingHouseAccountSubscriber.js +8 -8
- package/lib/accounts/types.d.ts +1 -0
- package/lib/accounts/webSocketClearingHouseAccountSubscriber.d.ts +2 -2
- package/lib/accounts/webSocketClearingHouseAccountSubscriber.js +7 -7
- package/lib/addresses/marketAddresses.js +1 -1
- package/lib/addresses/pda.d.ts +4 -4
- package/lib/addresses/pda.js +23 -22
- package/lib/admin.d.ts +30 -32
- package/lib/admin.js +111 -119
- package/lib/clearingHouse.d.ts +43 -34
- package/lib/clearingHouse.js +353 -193
- package/lib/clearingHouseConfig.d.ts +2 -2
- package/lib/clearingHouseUser.d.ts +26 -5
- package/lib/clearingHouseUser.js +151 -51
- package/lib/config.d.ts +2 -0
- package/lib/config.js +5 -1
- package/lib/constants/numericConstants.d.ts +1 -0
- package/lib/constants/numericConstants.js +3 -2
- package/lib/dlob/DLOB.d.ts +18 -11
- package/lib/dlob/DLOB.js +179 -107
- package/lib/dlob/DLOBNode.js +2 -10
- package/lib/dlob/NodeList.js +1 -1
- package/lib/events/eventSubscriber.d.ts +1 -0
- package/lib/events/eventSubscriber.js +11 -4
- package/lib/events/fetchLogs.d.ts +3 -1
- package/lib/events/fetchLogs.js +13 -5
- package/lib/events/pollingLogProvider.js +1 -1
- package/lib/events/types.d.ts +1 -1
- package/lib/events/webSocketLogProvider.js +1 -1
- package/lib/factory/bigNum.d.ts +5 -4
- package/lib/factory/bigNum.js +36 -6
- package/lib/idl/clearing_house.json +1527 -1242
- package/lib/index.d.ts +3 -0
- package/lib/index.js +3 -0
- package/lib/math/amm.js +9 -9
- package/lib/math/exchangeStatus.d.ts +4 -0
- package/lib/math/exchangeStatus.js +18 -0
- package/lib/math/funding.js +10 -10
- package/lib/math/margin.js +6 -1
- package/lib/math/market.js +9 -9
- package/lib/math/orders.d.ts +7 -3
- package/lib/math/orders.js +39 -31
- package/lib/math/repeg.js +3 -3
- package/lib/math/spotBalance.js +3 -3
- package/lib/math/spotPosition.js +2 -2
- package/lib/serum/serumFulfillmentConfigMap.d.ts +10 -0
- package/lib/serum/serumFulfillmentConfigMap.js +17 -0
- package/lib/serum/serumSubscriber.d.ts +4 -0
- package/lib/serum/serumSubscriber.js +16 -1
- package/lib/types.d.ts +60 -75
- package/lib/types.js +2 -1
- package/lib/userMap/userMap.d.ts +17 -1
- package/lib/userMap/userMap.js +12 -0
- package/lib/userName.d.ts +1 -0
- package/lib/userName.js +3 -2
- package/package.json +1 -1
- package/src/accounts/bulkAccountLoader.ts +5 -1
- package/src/accounts/pollingClearingHouseAccountSubscriber.ts +9 -9
- package/src/accounts/webSocketClearingHouseAccountSubscriber.ts +8 -8
- package/src/addresses/marketAddresses.ts +2 -2
- package/src/addresses/pda.ts +20 -20
- package/src/admin.ts +246 -221
- package/src/assert/assert.js +9 -0
- package/src/clearingHouse.ts +556 -236
- package/src/clearingHouseConfig.ts +2 -2
- package/src/clearingHouseUser.ts +237 -87
- package/src/config.ts +8 -1
- package/src/constants/numericConstants.ts +5 -1
- package/src/dlob/DLOB.ts +257 -120
- package/src/dlob/DLOBNode.ts +2 -14
- package/src/dlob/NodeList.ts +1 -1
- package/src/events/eventList.js +77 -0
- package/src/events/eventSubscriber.ts +18 -4
- package/src/events/fetchLogs.ts +20 -5
- package/src/events/pollingLogProvider.ts +1 -1
- package/src/events/types.ts +2 -1
- package/src/events/webSocketLogProvider.ts +1 -1
- package/src/examples/makeTradeExample.js +157 -0
- package/src/factory/bigNum.ts +59 -6
- package/src/idl/clearing_house.json +1527 -1242
- package/src/idl/pyth.json +98 -2
- package/src/index.ts +3 -0
- package/src/math/amm.ts +9 -9
- package/src/math/exchangeStatus.ts +31 -0
- package/src/math/funding.ts +20 -10
- package/src/math/margin.ts +7 -1
- package/src/math/market.ts +9 -9
- package/src/math/orders.ts +44 -29
- package/src/math/repeg.ts +3 -3
- package/src/math/spotBalance.ts +4 -4
- package/src/math/spotPosition.ts +2 -2
- package/src/serum/serumFulfillmentConfigMap.ts +26 -0
- package/src/serum/serumSubscriber.ts +20 -1
- package/src/token/index.js +38 -0
- package/src/tx/types.js +2 -0
- package/src/tx/utils.js +17 -0
- package/src/types.ts +65 -51
- package/src/userMap/userMap.ts +25 -1
- package/src/userName.ts +2 -1
- package/src/util/computeUnits.js +27 -0
- package/src/util/getTokenAddress.js +9 -0
- package/src/util/promiseTimeout.js +14 -0
- package/src/util/tps.js +27 -0
- package/tests/bn/test.ts +22 -1
- package/tests/dlob/helpers.ts +252 -81
- package/tests/dlob/test.ts +1040 -219
package/src/idl/pyth.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.
|
|
2
|
+
"version": "0.1.0",
|
|
3
3
|
"name": "pyth",
|
|
4
4
|
"instructions": [
|
|
5
5
|
{
|
|
@@ -41,6 +41,102 @@
|
|
|
41
41
|
"type": "i64"
|
|
42
42
|
}
|
|
43
43
|
]
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"name": "setPriceInfo",
|
|
47
|
+
"accounts": [
|
|
48
|
+
{
|
|
49
|
+
"name": "price",
|
|
50
|
+
"isMut": true,
|
|
51
|
+
"isSigner": false
|
|
52
|
+
}
|
|
53
|
+
],
|
|
54
|
+
"args": [
|
|
55
|
+
{
|
|
56
|
+
"name": "price",
|
|
57
|
+
"type": "i64"
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"name": "conf",
|
|
61
|
+
"type": "u64"
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"name": "slot",
|
|
65
|
+
"type": "u64"
|
|
66
|
+
}
|
|
67
|
+
]
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"name": "setTwap",
|
|
71
|
+
"accounts": [
|
|
72
|
+
{
|
|
73
|
+
"name": "price",
|
|
74
|
+
"isMut": true,
|
|
75
|
+
"isSigner": false
|
|
76
|
+
}
|
|
77
|
+
],
|
|
78
|
+
"args": [
|
|
79
|
+
{
|
|
80
|
+
"name": "twap",
|
|
81
|
+
"type": "i64"
|
|
82
|
+
}
|
|
83
|
+
]
|
|
84
|
+
}
|
|
85
|
+
],
|
|
86
|
+
"types": [
|
|
87
|
+
{
|
|
88
|
+
"name": "PriceStatus",
|
|
89
|
+
"type": {
|
|
90
|
+
"kind": "enum",
|
|
91
|
+
"variants": [
|
|
92
|
+
{
|
|
93
|
+
"name": "Unknown"
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
"name": "Trading"
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
"name": "Halted"
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
"name": "Auction"
|
|
103
|
+
}
|
|
104
|
+
]
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
"name": "CorpAction",
|
|
109
|
+
"type": {
|
|
110
|
+
"kind": "enum",
|
|
111
|
+
"variants": [
|
|
112
|
+
{
|
|
113
|
+
"name": "NoCorpAct"
|
|
114
|
+
}
|
|
115
|
+
]
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
"name": "PriceType",
|
|
120
|
+
"type": {
|
|
121
|
+
"kind": "enum",
|
|
122
|
+
"variants": [
|
|
123
|
+
{
|
|
124
|
+
"name": "Unknown"
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
"name": "Price"
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
"name": "TWAP"
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
"name": "Volatility"
|
|
134
|
+
}
|
|
135
|
+
]
|
|
136
|
+
}
|
|
44
137
|
}
|
|
45
|
-
]
|
|
138
|
+
],
|
|
139
|
+
"metadata": {
|
|
140
|
+
"address": "gSbePebfvPy7tRqimPoVecS2UsBvYv46ynrzWocc92s"
|
|
141
|
+
}
|
|
46
142
|
}
|
package/src/index.ts
CHANGED
|
@@ -34,6 +34,7 @@ export * from './events/fetchLogs';
|
|
|
34
34
|
export * from './math/auction';
|
|
35
35
|
export * from './math/spotMarket';
|
|
36
36
|
export * from './math/conversion';
|
|
37
|
+
export * from './math/exchangeStatus';
|
|
37
38
|
export * from './math/funding';
|
|
38
39
|
export * from './math/market';
|
|
39
40
|
export * from './math/position';
|
|
@@ -52,9 +53,11 @@ export * from './math/utils';
|
|
|
52
53
|
export * from './config';
|
|
53
54
|
export * from './constants/numericConstants';
|
|
54
55
|
export * from './serum/serumSubscriber';
|
|
56
|
+
export * from './serum/serumFulfillmentConfigMap';
|
|
55
57
|
export * from './tx/retryTxSender';
|
|
56
58
|
export * from './util/computeUnits';
|
|
57
59
|
export * from './util/tps';
|
|
60
|
+
export * from './util/promiseTimeout';
|
|
58
61
|
export * from './math/spotBalance';
|
|
59
62
|
export * from './constants/spotMarkets';
|
|
60
63
|
export * from './clearingHouseConfig';
|
package/src/math/amm.ts
CHANGED
|
@@ -117,7 +117,7 @@ export function calculateNewAmm(
|
|
|
117
117
|
newAmm.sqrtK = newAmm.sqrtK.mul(pKNumer).div(pKDenom);
|
|
118
118
|
const invariant = newAmm.sqrtK.mul(newAmm.sqrtK);
|
|
119
119
|
newAmm.quoteAssetReserve = invariant.div(newAmm.baseAssetReserve);
|
|
120
|
-
const directionToClose = amm.
|
|
120
|
+
const directionToClose = amm.baseAssetAmountWithAmm.gt(ZERO)
|
|
121
121
|
? PositionDirection.SHORT
|
|
122
122
|
: PositionDirection.LONG;
|
|
123
123
|
|
|
@@ -125,7 +125,7 @@ export function calculateNewAmm(
|
|
|
125
125
|
calculateAmmReservesAfterSwap(
|
|
126
126
|
newAmm,
|
|
127
127
|
'base',
|
|
128
|
-
amm.
|
|
128
|
+
amm.baseAssetAmountWithAmm.abs(),
|
|
129
129
|
getSwapDirection('base', directionToClose)
|
|
130
130
|
);
|
|
131
131
|
|
|
@@ -157,7 +157,7 @@ export function calculateUpdatedAMM(
|
|
|
157
157
|
newAmm.quoteAssetReserve = invariant.div(newAmm.baseAssetReserve);
|
|
158
158
|
newAmm.pegMultiplier = newPeg;
|
|
159
159
|
|
|
160
|
-
const directionToClose = amm.
|
|
160
|
+
const directionToClose = amm.baseAssetAmountWithAmm.gt(ZERO)
|
|
161
161
|
? PositionDirection.SHORT
|
|
162
162
|
: PositionDirection.LONG;
|
|
163
163
|
|
|
@@ -165,7 +165,7 @@ export function calculateUpdatedAMM(
|
|
|
165
165
|
calculateAmmReservesAfterSwap(
|
|
166
166
|
newAmm,
|
|
167
167
|
'base',
|
|
168
|
-
amm.
|
|
168
|
+
amm.baseAssetAmountWithAmm.abs(),
|
|
169
169
|
getSwapDirection('base', directionToClose)
|
|
170
170
|
);
|
|
171
171
|
|
|
@@ -522,7 +522,7 @@ export function calculateSpread(
|
|
|
522
522
|
amm.quoteAssetReserve,
|
|
523
523
|
amm.terminalQuoteAssetReserve,
|
|
524
524
|
amm.pegMultiplier,
|
|
525
|
-
amm.
|
|
525
|
+
amm.baseAssetAmountWithAmm,
|
|
526
526
|
reservePrice,
|
|
527
527
|
amm.totalFeeMinusDistributions,
|
|
528
528
|
amm.baseAssetReserve,
|
|
@@ -629,7 +629,7 @@ export function getSwapDirection(
|
|
|
629
629
|
* @returns cost : Precision PRICE_PRECISION
|
|
630
630
|
*/
|
|
631
631
|
export function calculateTerminalPrice(market: PerpMarketAccount) {
|
|
632
|
-
const directionToClose = market.amm.
|
|
632
|
+
const directionToClose = market.amm.baseAssetAmountWithAmm.gt(ZERO)
|
|
633
633
|
? PositionDirection.SHORT
|
|
634
634
|
: PositionDirection.LONG;
|
|
635
635
|
|
|
@@ -637,7 +637,7 @@ export function calculateTerminalPrice(market: PerpMarketAccount) {
|
|
|
637
637
|
calculateAmmReservesAfterSwap(
|
|
638
638
|
market.amm,
|
|
639
639
|
'base',
|
|
640
|
-
market.amm.
|
|
640
|
+
market.amm.baseAssetAmountWithAmm.abs(),
|
|
641
641
|
getSwapDirection('base', directionToClose)
|
|
642
642
|
);
|
|
643
643
|
|
|
@@ -713,7 +713,7 @@ export function calculateMaxBaseAssetAmountFillable(
|
|
|
713
713
|
orderDirection: PositionDirection
|
|
714
714
|
): BN {
|
|
715
715
|
const maxFillSize = amm.baseAssetReserve.div(
|
|
716
|
-
new BN(amm.
|
|
716
|
+
new BN(amm.maxFillReserveFraction)
|
|
717
717
|
);
|
|
718
718
|
let maxBaseAssetAmountOnSide: BN;
|
|
719
719
|
if (isVariant(orderDirection, 'long')) {
|
|
@@ -730,6 +730,6 @@ export function calculateMaxBaseAssetAmountFillable(
|
|
|
730
730
|
|
|
731
731
|
return standardizeBaseAssetAmount(
|
|
732
732
|
BN.min(maxFillSize, maxBaseAssetAmountOnSide),
|
|
733
|
-
amm.
|
|
733
|
+
amm.orderStepSize
|
|
734
734
|
);
|
|
735
735
|
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import {
|
|
2
|
+
isOneOfVariant,
|
|
3
|
+
isVariant,
|
|
4
|
+
PerpMarketAccount,
|
|
5
|
+
SpotMarketAccount,
|
|
6
|
+
StateAccount,
|
|
7
|
+
} from '../types';
|
|
8
|
+
|
|
9
|
+
export function exchangePaused(state: StateAccount): boolean {
|
|
10
|
+
return isVariant(state.exchangeStatus, 'paused');
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function fillPaused(
|
|
14
|
+
state: StateAccount,
|
|
15
|
+
market: PerpMarketAccount | SpotMarketAccount
|
|
16
|
+
): boolean {
|
|
17
|
+
return (
|
|
18
|
+
isOneOfVariant(state.exchangeStatus, ['paused', 'fillPaused']) ||
|
|
19
|
+
isOneOfVariant(market.status, ['paused', 'fillPaused'])
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function ammPaused(
|
|
24
|
+
state: StateAccount,
|
|
25
|
+
market: PerpMarketAccount | SpotMarketAccount
|
|
26
|
+
): boolean {
|
|
27
|
+
return (
|
|
28
|
+
isOneOfVariant(state.exchangeStatus, ['paused', 'ammPaused']) ||
|
|
29
|
+
isOneOfVariant(market.status, ['paused', 'ammPaused'])
|
|
30
|
+
);
|
|
31
|
+
}
|
package/src/math/funding.ts
CHANGED
|
@@ -137,9 +137,11 @@ export async function calculateAllEstimatedFundingRate(
|
|
|
137
137
|
let cappedAltEst: BN;
|
|
138
138
|
let largerSide: BN;
|
|
139
139
|
let smallerSide: BN;
|
|
140
|
-
if (
|
|
141
|
-
|
|
142
|
-
|
|
140
|
+
if (
|
|
141
|
+
market.amm.baseAssetAmountLong.gt(market.amm.baseAssetAmountShort.abs())
|
|
142
|
+
) {
|
|
143
|
+
largerSide = market.amm.baseAssetAmountLong.abs();
|
|
144
|
+
smallerSide = market.amm.baseAssetAmountShort.abs();
|
|
143
145
|
if (twapSpread.gt(new BN(0))) {
|
|
144
146
|
return [
|
|
145
147
|
markTwapWithMantissa,
|
|
@@ -149,9 +151,11 @@ export async function calculateAllEstimatedFundingRate(
|
|
|
149
151
|
interpEst,
|
|
150
152
|
];
|
|
151
153
|
}
|
|
152
|
-
} else if (
|
|
153
|
-
|
|
154
|
-
|
|
154
|
+
} else if (
|
|
155
|
+
market.amm.baseAssetAmountLong.lt(market.amm.baseAssetAmountShort.abs())
|
|
156
|
+
) {
|
|
157
|
+
largerSide = market.amm.baseAssetAmountShort.abs();
|
|
158
|
+
smallerSide = market.amm.baseAssetAmountLong.abs();
|
|
155
159
|
if (twapSpread.lt(new BN(0))) {
|
|
156
160
|
return [
|
|
157
161
|
markTwapWithMantissa,
|
|
@@ -251,9 +255,11 @@ export async function calculateLongShortFundingRate(
|
|
|
251
255
|
periodAdjustment
|
|
252
256
|
);
|
|
253
257
|
|
|
254
|
-
if (market.baseAssetAmountLong.gt(market.baseAssetAmountShort)) {
|
|
258
|
+
if (market.amm.baseAssetAmountLong.gt(market.amm.baseAssetAmountShort)) {
|
|
255
259
|
return [cappedAltEst, interpEst];
|
|
256
|
-
} else if (
|
|
260
|
+
} else if (
|
|
261
|
+
market.amm.baseAssetAmountLong.lt(market.amm.baseAssetAmountShort)
|
|
262
|
+
) {
|
|
257
263
|
return [interpEst, cappedAltEst];
|
|
258
264
|
} else {
|
|
259
265
|
return [interpEst, interpEst];
|
|
@@ -279,9 +285,13 @@ export async function calculateLongShortFundingRateAndLiveTwaps(
|
|
|
279
285
|
periodAdjustment
|
|
280
286
|
);
|
|
281
287
|
|
|
282
|
-
if (
|
|
288
|
+
if (
|
|
289
|
+
market.amm.baseAssetAmountLong.gt(market.amm.baseAssetAmountShort.abs())
|
|
290
|
+
) {
|
|
283
291
|
return [markTwapLive, oracleTwapLive, cappedAltEst, interpEst];
|
|
284
|
-
} else if (
|
|
292
|
+
} else if (
|
|
293
|
+
market.amm.baseAssetAmountLong.lt(market.amm.baseAssetAmountShort.abs())
|
|
294
|
+
) {
|
|
285
295
|
return [markTwapLive, oracleTwapLive, interpEst, cappedAltEst];
|
|
286
296
|
} else {
|
|
287
297
|
return [markTwapLive, oracleTwapLive, interpEst, interpEst];
|
package/src/math/margin.ts
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
import { BN } from '@project-serum/anchor';
|
|
10
10
|
import { OraclePriceData } from '../oracles/types';
|
|
11
11
|
import { PerpMarketAccount, PerpPosition } from '..';
|
|
12
|
+
import { isVariant } from '../types';
|
|
12
13
|
import { assert } from '../assert/assert';
|
|
13
14
|
|
|
14
15
|
export function calculateSizePremiumLiabilityWeight(
|
|
@@ -107,9 +108,14 @@ export function calculateBaseAssetValueWithOracle(
|
|
|
107
108
|
perpPosition: PerpPosition,
|
|
108
109
|
oraclePriceData: OraclePriceData
|
|
109
110
|
): BN {
|
|
111
|
+
let price = oraclePriceData.price;
|
|
112
|
+
if (isVariant(market.status, 'settlement')) {
|
|
113
|
+
price = market.expiryPrice;
|
|
114
|
+
}
|
|
115
|
+
|
|
110
116
|
return perpPosition.baseAssetAmount
|
|
111
117
|
.abs()
|
|
112
|
-
.mul(
|
|
118
|
+
.mul(price)
|
|
113
119
|
.div(AMM_RESERVE_PRECISION);
|
|
114
120
|
}
|
|
115
121
|
|
package/src/math/market.ts
CHANGED
|
@@ -159,29 +159,29 @@ export function calculateUnrealizedAssetWeight(
|
|
|
159
159
|
let assetWeight: BN;
|
|
160
160
|
switch (marginCategory) {
|
|
161
161
|
case 'Initial':
|
|
162
|
-
assetWeight = new BN(market.
|
|
162
|
+
assetWeight = new BN(market.unrealizedPnlInitialAssetWeight);
|
|
163
163
|
|
|
164
|
-
if (market.
|
|
164
|
+
if (market.unrealizedPnlMaxImbalance.gt(ZERO)) {
|
|
165
165
|
const netUnsettledPnl = calculateNetUserPnlImbalance(
|
|
166
166
|
market,
|
|
167
167
|
quoteSpotMarket,
|
|
168
168
|
oraclePriceData
|
|
169
169
|
);
|
|
170
|
-
if (netUnsettledPnl.gt(market.
|
|
170
|
+
if (netUnsettledPnl.gt(market.unrealizedPnlMaxImbalance)) {
|
|
171
171
|
assetWeight = assetWeight
|
|
172
|
-
.mul(market.
|
|
172
|
+
.mul(market.unrealizedPnlMaxImbalance)
|
|
173
173
|
.div(netUnsettledPnl);
|
|
174
174
|
}
|
|
175
175
|
}
|
|
176
176
|
|
|
177
177
|
assetWeight = calculateSizeDiscountAssetWeight(
|
|
178
178
|
unrealizedPnl,
|
|
179
|
-
market.
|
|
179
|
+
market.unrealizedPnlImfFactor,
|
|
180
180
|
assetWeight
|
|
181
181
|
);
|
|
182
182
|
break;
|
|
183
183
|
case 'Maintenance':
|
|
184
|
-
assetWeight = new BN(market.
|
|
184
|
+
assetWeight = new BN(market.unrealizedPnlMaintenanceAssetWeight);
|
|
185
185
|
break;
|
|
186
186
|
}
|
|
187
187
|
|
|
@@ -193,7 +193,7 @@ export function calculateMarketAvailablePNL(
|
|
|
193
193
|
spotMarket: SpotMarketAccount
|
|
194
194
|
): BN {
|
|
195
195
|
return getTokenAmount(
|
|
196
|
-
perpMarket.pnlPool.
|
|
196
|
+
perpMarket.pnlPool.scaledBalance,
|
|
197
197
|
spotMarket,
|
|
198
198
|
SpotBalanceType.DEPOSIT
|
|
199
199
|
);
|
|
@@ -203,7 +203,7 @@ export function calculateNetUserPnl(
|
|
|
203
203
|
perpMarket: PerpMarketAccount,
|
|
204
204
|
oraclePriceData: OraclePriceData
|
|
205
205
|
): BN {
|
|
206
|
-
const netUserPositionValue = perpMarket.amm.
|
|
206
|
+
const netUserPositionValue = perpMarket.amm.baseAssetAmountWithAmm
|
|
207
207
|
.mul(oraclePriceData.price)
|
|
208
208
|
.div(BASE_PRECISION)
|
|
209
209
|
.div(PRICE_TO_QUOTE_PRECISION);
|
|
@@ -225,7 +225,7 @@ export function calculateNetUserPnlImbalance(
|
|
|
225
225
|
const netUserPnl = calculateNetUserPnl(perpMarket, oraclePriceData);
|
|
226
226
|
|
|
227
227
|
const pnlPool = getTokenAmount(
|
|
228
|
-
perpMarket.pnlPool.
|
|
228
|
+
perpMarket.pnlPool.scaledBalance,
|
|
229
229
|
spotMarket,
|
|
230
230
|
SpotBalanceType.DEPOSIT
|
|
231
231
|
);
|
package/src/math/orders.ts
CHANGED
|
@@ -10,7 +10,6 @@ import { ZERO, TWO } from '../constants/numericConstants';
|
|
|
10
10
|
import { BN } from '@project-serum/anchor';
|
|
11
11
|
import { OraclePriceData } from '../oracles/types';
|
|
12
12
|
import { getAuctionPrice, isAuctionComplete } from './auction';
|
|
13
|
-
import { calculateAskPrice, calculateBidPrice } from './market';
|
|
14
13
|
import {
|
|
15
14
|
calculateMaxBaseAssetAmountFillable,
|
|
16
15
|
calculateMaxBaseAssetAmountToTrade,
|
|
@@ -132,36 +131,23 @@ export function standardizeBaseAssetAmount(
|
|
|
132
131
|
export function getLimitPrice(
|
|
133
132
|
order: Order,
|
|
134
133
|
oraclePriceData: OraclePriceData,
|
|
135
|
-
slot: number
|
|
136
|
-
perpMarket?: PerpMarketAccount
|
|
134
|
+
slot: number
|
|
137
135
|
): BN {
|
|
138
136
|
let limitPrice;
|
|
139
|
-
if (
|
|
140
|
-
limitPrice = oraclePriceData.price.add(order.oraclePriceOffset);
|
|
137
|
+
if (order.oraclePriceOffset !== 0) {
|
|
138
|
+
limitPrice = oraclePriceData.price.add(new BN(order.oraclePriceOffset));
|
|
141
139
|
} else if (isOneOfVariant(order.orderType, ['market', 'triggerMarket'])) {
|
|
142
140
|
if (!isAuctionComplete(order, slot)) {
|
|
143
141
|
limitPrice = getAuctionPrice(order, slot);
|
|
144
142
|
} else if (!order.price.eq(ZERO)) {
|
|
145
143
|
limitPrice = order.price;
|
|
146
144
|
} else {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
limitPrice = askPrice.add(delta);
|
|
152
|
-
} else {
|
|
153
|
-
const bidPrice = calculateBidPrice(perpMarket, oraclePriceData);
|
|
154
|
-
const delta = bidPrice.div(new BN(perpMarket.amm.maxSlippageRatio));
|
|
155
|
-
limitPrice = bidPrice.sub(delta);
|
|
156
|
-
}
|
|
145
|
+
// check oracle validity?
|
|
146
|
+
const oraclePrice1Pct = oraclePriceData.price.div(new BN(100));
|
|
147
|
+
if (isVariant(order.direction, 'long')) {
|
|
148
|
+
limitPrice = oraclePriceData.price.add(oraclePrice1Pct);
|
|
157
149
|
} else {
|
|
158
|
-
|
|
159
|
-
const oraclePrice1Pct = oraclePriceData.price.div(new BN(100));
|
|
160
|
-
if (isVariant(order.direction, 'long')) {
|
|
161
|
-
limitPrice = oraclePriceData.price.add(oraclePrice1Pct);
|
|
162
|
-
} else {
|
|
163
|
-
limitPrice = oraclePriceData.price.sub(oraclePrice1Pct);
|
|
164
|
-
}
|
|
150
|
+
limitPrice = oraclePriceData.price.sub(oraclePrice1Pct);
|
|
165
151
|
}
|
|
166
152
|
}
|
|
167
153
|
} else {
|
|
@@ -171,11 +157,32 @@ export function getLimitPrice(
|
|
|
171
157
|
return limitPrice;
|
|
172
158
|
}
|
|
173
159
|
|
|
160
|
+
export function getOptionalLimitPrice(
|
|
161
|
+
order: Order,
|
|
162
|
+
oraclePriceData: OraclePriceData,
|
|
163
|
+
slot: number
|
|
164
|
+
): BN | undefined {
|
|
165
|
+
if (hasLimitPrice(order, slot)) {
|
|
166
|
+
return getLimitPrice(order, oraclePriceData, slot);
|
|
167
|
+
} else {
|
|
168
|
+
return undefined;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export function hasLimitPrice(order: Order, slot: number): boolean {
|
|
173
|
+
return (
|
|
174
|
+
order.price.gt(ZERO) ||
|
|
175
|
+
order.oraclePriceOffset != 0 ||
|
|
176
|
+
!isAuctionComplete(order, slot)
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
|
|
174
180
|
export function isFillableByVAMM(
|
|
175
181
|
order: Order,
|
|
176
182
|
market: PerpMarketAccount,
|
|
177
183
|
oraclePriceData: OraclePriceData,
|
|
178
|
-
slot: number
|
|
184
|
+
slot: number,
|
|
185
|
+
ts: number
|
|
179
186
|
): boolean {
|
|
180
187
|
return (
|
|
181
188
|
(isAuctionComplete(order, slot) &&
|
|
@@ -185,7 +192,7 @@ export function isFillableByVAMM(
|
|
|
185
192
|
oraclePriceData,
|
|
186
193
|
slot
|
|
187
194
|
).eq(ZERO)) ||
|
|
188
|
-
isOrderExpired(order,
|
|
195
|
+
isOrderExpired(order, ts)
|
|
189
196
|
);
|
|
190
197
|
}
|
|
191
198
|
|
|
@@ -202,7 +209,7 @@ export function calculateBaseAssetAmountForAmmToFulfill(
|
|
|
202
209
|
return ZERO;
|
|
203
210
|
}
|
|
204
211
|
|
|
205
|
-
const limitPrice = getLimitPrice(order, oraclePriceData, slot
|
|
212
|
+
const limitPrice = getLimitPrice(order, oraclePriceData, slot);
|
|
206
213
|
const baseAssetAmount = calculateBaseAssetAmountToFillUpToLimitPrice(
|
|
207
214
|
order,
|
|
208
215
|
market,
|
|
@@ -233,7 +240,7 @@ export function calculateBaseAssetAmountToFillUpToLimitPrice(
|
|
|
233
240
|
|
|
234
241
|
const baseAssetAmount = standardizeBaseAssetAmount(
|
|
235
242
|
maxAmountToTrade,
|
|
236
|
-
market.amm.
|
|
243
|
+
market.amm.orderStepSize
|
|
237
244
|
);
|
|
238
245
|
|
|
239
246
|
// Check that directions are the same
|
|
@@ -257,14 +264,22 @@ function isSameDirection(
|
|
|
257
264
|
);
|
|
258
265
|
}
|
|
259
266
|
|
|
260
|
-
export function isOrderExpired(order: Order,
|
|
267
|
+
export function isOrderExpired(order: Order, ts: number): boolean {
|
|
261
268
|
if (
|
|
262
269
|
isOneOfVariant(order.orderType, ['triggerMarket', 'triggerLimit']) ||
|
|
263
270
|
!isVariant(order.status, 'open') ||
|
|
264
|
-
order.
|
|
271
|
+
order.maxTs.eq(ZERO)
|
|
265
272
|
) {
|
|
266
273
|
return false;
|
|
267
274
|
}
|
|
268
275
|
|
|
269
|
-
return new BN(
|
|
276
|
+
return new BN(ts).gt(order.maxTs);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
export function isMarketOrder(order: Order): boolean {
|
|
280
|
+
return isOneOfVariant(order.orderType, ['market', 'triggerMarket']);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
export function isLimitOrder(order: Order): boolean {
|
|
284
|
+
return isOneOfVariant(order.orderType, ['limit', 'triggerLimit']);
|
|
270
285
|
}
|
package/src/math/repeg.ts
CHANGED
|
@@ -26,7 +26,7 @@ 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);
|
|
@@ -135,7 +135,7 @@ export function calculateBudgetedK(amm: AMM, cost: BN): [BN, BN] {
|
|
|
135
135
|
const x = amm.baseAssetReserve;
|
|
136
136
|
const y = amm.quoteAssetReserve;
|
|
137
137
|
|
|
138
|
-
const d = amm.
|
|
138
|
+
const d = amm.baseAssetAmountWithAmm;
|
|
139
139
|
const Q = amm.pegMultiplier;
|
|
140
140
|
|
|
141
141
|
const [numerator, denominator] = calculateBudgetedKBN(x, y, cost, Q, d);
|
|
@@ -159,7 +159,7 @@ export function calculateBudgetedPeg(amm: AMM, cost: BN, targetPrice: BN): BN {
|
|
|
159
159
|
const x = amm.baseAssetReserve;
|
|
160
160
|
const y = amm.quoteAssetReserve;
|
|
161
161
|
|
|
162
|
-
const d = amm.
|
|
162
|
+
const d = amm.baseAssetAmountWithAmm;
|
|
163
163
|
const Q = amm.pegMultiplier;
|
|
164
164
|
|
|
165
165
|
const C = cost.mul(new BN(-1));
|
package/src/math/spotBalance.ts
CHANGED
|
@@ -287,20 +287,20 @@ export function calculateWithdrawLimit(
|
|
|
287
287
|
const borrowTokenTwapLive = spotMarket.borrowTokenTwap
|
|
288
288
|
.mul(sinceStart)
|
|
289
289
|
.add(marketBorrowTokenAmount.mul(sinceLast))
|
|
290
|
-
.div(sinceLast.add(
|
|
290
|
+
.div(sinceLast.add(sinceStart));
|
|
291
291
|
|
|
292
292
|
const depositTokenTwapLive = spotMarket.depositTokenTwap
|
|
293
293
|
.mul(sinceStart)
|
|
294
294
|
.add(marketDepositTokenAmount.mul(sinceLast))
|
|
295
|
-
.div(sinceLast.add(
|
|
295
|
+
.div(sinceLast.add(sinceStart));
|
|
296
296
|
|
|
297
297
|
const maxBorrowTokens = BN.min(
|
|
298
298
|
BN.max(
|
|
299
299
|
marketDepositTokenAmount.div(new BN(6)),
|
|
300
300
|
borrowTokenTwapLive.add(borrowTokenTwapLive.div(new BN(5)))
|
|
301
301
|
),
|
|
302
|
-
marketDepositTokenAmount.sub(marketDepositTokenAmount.div(new BN(
|
|
303
|
-
); // between ~15-
|
|
302
|
+
marketDepositTokenAmount.sub(marketDepositTokenAmount.div(new BN(5)))
|
|
303
|
+
); // between ~15-80% utilization with friction on twap
|
|
304
304
|
|
|
305
305
|
const minDepositTokens = depositTokenTwapLive.sub(
|
|
306
306
|
BN.min(
|
package/src/math/spotPosition.ts
CHANGED
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
import { OraclePriceData } from '../oracles/types';
|
|
10
10
|
|
|
11
11
|
export function isSpotPositionAvailable(position: SpotPosition): boolean {
|
|
12
|
-
return position.
|
|
12
|
+
return position.scaledBalance.eq(ZERO) && position.openOrders === 0;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
export function getWorstCaseTokenAmounts(
|
|
@@ -19,7 +19,7 @@ export function getWorstCaseTokenAmounts(
|
|
|
19
19
|
): [BN, BN] {
|
|
20
20
|
const tokenAmount = getSignedTokenAmount(
|
|
21
21
|
getTokenAmount(
|
|
22
|
-
spotPosition.
|
|
22
|
+
spotPosition.scaledBalance,
|
|
23
23
|
spotMarketAccount,
|
|
24
24
|
spotPosition.balanceType
|
|
25
25
|
),
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { PublicKey } from '@solana/web3.js';
|
|
2
|
+
import { SerumV3FulfillmentConfigAccount } from '../types';
|
|
3
|
+
import { ClearingHouse } from '../clearingHouse';
|
|
4
|
+
|
|
5
|
+
export class SerumFulfillmentConfigMap {
|
|
6
|
+
clearingHouse: ClearingHouse;
|
|
7
|
+
map = new Map<number, SerumV3FulfillmentConfigAccount>();
|
|
8
|
+
|
|
9
|
+
public constructor(clearingHouse: ClearingHouse) {
|
|
10
|
+
this.clearingHouse = clearingHouse;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
public async add(
|
|
14
|
+
marketIndex: number,
|
|
15
|
+
serumMarketAddress: PublicKey
|
|
16
|
+
): Promise<void> {
|
|
17
|
+
const account = await this.clearingHouse.getSerumV3FulfillmentConfig(
|
|
18
|
+
serumMarketAddress
|
|
19
|
+
);
|
|
20
|
+
this.map.set(marketIndex, account);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
public get(marketIndex: number): SerumV3FulfillmentConfigAccount {
|
|
24
|
+
return this.map.get(marketIndex);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -2,6 +2,8 @@ import { Connection, PublicKey } from '@solana/web3.js';
|
|
|
2
2
|
import { BulkAccountLoader } from '../accounts/bulkAccountLoader';
|
|
3
3
|
import { Market, Orderbook } from '@project-serum/serum';
|
|
4
4
|
import { SerumMarketSubscriberConfig } from './types';
|
|
5
|
+
import { BN } from '@project-serum/anchor';
|
|
6
|
+
import { PRICE_PRECISION } from '../constants/numericConstants';
|
|
5
7
|
|
|
6
8
|
export class SerumSubscriber {
|
|
7
9
|
connection: Connection;
|
|
@@ -49,7 +51,6 @@ export class SerumSubscriber {
|
|
|
49
51
|
(buffer, slot) => {
|
|
50
52
|
this.lastAsksSlot = slot;
|
|
51
53
|
this.asks = Orderbook.decode(this.market, buffer);
|
|
52
|
-
console.log(this.asks.getL2(3));
|
|
53
54
|
}
|
|
54
55
|
);
|
|
55
56
|
|
|
@@ -67,6 +68,24 @@ export class SerumSubscriber {
|
|
|
67
68
|
this.subscribed = true;
|
|
68
69
|
}
|
|
69
70
|
|
|
71
|
+
public getBestBid(): BN | undefined {
|
|
72
|
+
const bestBid = this.bids.getL2(1)[0];
|
|
73
|
+
if (!bestBid) {
|
|
74
|
+
return undefined;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return new BN(bestBid[0] * PRICE_PRECISION.toNumber());
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
public getBestAsk(): BN | undefined {
|
|
81
|
+
const bestAsk = this.asks.getL2(1)[0];
|
|
82
|
+
if (!bestAsk) {
|
|
83
|
+
return undefined;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return new BN(bestAsk[0] * PRICE_PRECISION.toNumber());
|
|
87
|
+
}
|
|
88
|
+
|
|
70
89
|
public async unsubscribe(): Promise<void> {
|
|
71
90
|
if (!this.subscribed) {
|
|
72
91
|
return;
|