@drift-labs/sdk 0.1.10 → 0.1.14
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/defaultClearingHouseAccountSubscriber.d.ts +1 -0
- package/lib/accounts/defaultClearingHouseAccountSubscriber.d.ts.map +1 -1
- package/lib/accounts/defaultClearingHouseAccountSubscriber.js +17 -0
- package/lib/accounts/defaultUserAccountSubscriber.d.ts +2 -0
- package/lib/accounts/defaultUserAccountSubscriber.d.ts.map +1 -1
- package/lib/accounts/defaultUserAccountSubscriber.js +16 -0
- package/lib/accounts/types.d.ts +3 -21
- package/lib/accounts/types.d.ts.map +1 -1
- package/lib/accounts/webSocketAccountSubscriber.d.ts +2 -0
- package/lib/accounts/webSocketAccountSubscriber.d.ts.map +1 -1
- package/lib/accounts/webSocketAccountSubscriber.js +13 -3
- package/lib/clearingHouse.d.ts +4 -0
- package/lib/clearingHouse.d.ts.map +1 -1
- package/lib/clearingHouse.js +8 -0
- package/lib/clearingHouseUser.d.ts +33 -5
- package/lib/clearingHouseUser.d.ts.map +1 -1
- package/lib/clearingHouseUser.js +224 -78
- package/lib/constants/markets.d.ts.map +1 -1
- package/lib/constants/markets.js +21 -0
- package/lib/constants/numericConstants.d.ts +1 -0
- package/lib/constants/numericConstants.d.ts.map +1 -1
- package/lib/constants/numericConstants.js +2 -1
- package/lib/examples/makeTradeExample.d.ts.map +1 -1
- package/lib/examples/makeTradeExample.js +14 -13
- package/lib/idl/clearing_house.json +94 -42
- package/lib/index.d.ts +3 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +3 -1
- package/lib/math/amm.d.ts +26 -1
- package/lib/math/amm.d.ts.map +1 -1
- package/lib/math/amm.js +85 -10
- package/lib/math/funding.d.ts +6 -6
- package/lib/math/funding.d.ts.map +1 -1
- package/lib/math/funding.js +69 -25
- package/lib/math/insuranceFund.d.ts +15 -0
- package/lib/math/insuranceFund.d.ts.map +1 -0
- package/lib/math/insuranceFund.js +36 -0
- package/lib/math/position.d.ts +7 -1
- package/lib/math/position.d.ts.map +1 -1
- package/lib/math/position.js +32 -24
- package/lib/math/trade.d.ts +1 -1
- package/lib/math/trade.d.ts.map +1 -1
- package/lib/math/trade.js +9 -4
- package/lib/types.d.ts +0 -50
- package/lib/types.d.ts.map +1 -1
- package/lib/util/computeUnits.d.ts +3 -0
- package/lib/util/computeUnits.d.ts.map +1 -0
- package/lib/util/computeUnits.js +27 -0
- package/lib/wallet.d.ts +10 -0
- package/lib/wallet.d.ts.map +1 -0
- package/lib/wallet.js +35 -0
- package/package.json +3 -13
- package/src/accounts/defaultClearingHouseAccountSubscriber.ts +18 -0
- package/src/accounts/defaultUserAccountSubscriber.ts +18 -0
- package/src/accounts/types.ts +3 -28
- package/src/accounts/webSocketAccountSubscriber.ts +16 -6
- package/src/clearingHouse.ts +9 -3
- package/src/clearingHouseUser.ts +325 -107
- package/src/constants/markets.ts +21 -0
- package/src/constants/numericConstants.ts +2 -0
- package/src/examples/makeTradeExample.ts +2 -1
- package/src/idl/clearing_house.json +94 -42
- package/src/index.ts +3 -1
- package/src/math/amm.ts +120 -13
- package/src/math/funding.ts +109 -51
- package/src/math/insuranceFund.ts +29 -0
- package/src/math/position.ts +33 -26
- package/src/math/trade.ts +9 -5
- package/src/types.ts +0 -54
- package/src/util/computeUnits.ts +21 -0
- package/src/wallet.ts +22 -0
- package/.eslintrc.json +0 -36
- package/.prettierignore +0 -1
- package/.prettierrc.js +0 -9
- package/lib/accounts/defaultHistoryAccountSubscriber.d.ts +0 -29
- package/lib/accounts/defaultHistoryAccountSubscriber.d.ts.map +0 -1
- package/lib/accounts/defaultHistoryAccountSubscriber.js +0 -110
- package/src/accounts/defaultHistoryAccountSubscriber.ts +0 -179
package/src/math/funding.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { BN } from '@project-serum/anchor';
|
|
2
|
+
import { PriceData } from '@pythnetwork/client';
|
|
2
3
|
import {
|
|
3
4
|
AMM_RESERVE_PRECISION,
|
|
4
5
|
MARK_PRICE_PRECISION,
|
|
5
6
|
QUOTE_PRECISION,
|
|
6
7
|
ZERO,
|
|
7
8
|
} from '../constants/numericConstants';
|
|
8
|
-
import { PythClient } from '../pythClient';
|
|
9
9
|
import { Market } from '../types';
|
|
10
10
|
import { calculateMarkPrice } from './market';
|
|
11
11
|
|
|
@@ -18,7 +18,7 @@ import { calculateMarkPrice } from './market';
|
|
|
18
18
|
*/
|
|
19
19
|
export async function calculateAllEstimatedFundingRate(
|
|
20
20
|
market: Market,
|
|
21
|
-
|
|
21
|
+
oraclePriceData: PriceData,
|
|
22
22
|
periodAdjustment: BN = new BN(1)
|
|
23
23
|
): Promise<[BN, BN, BN, BN, BN]> {
|
|
24
24
|
// periodAdjustment
|
|
@@ -43,9 +43,12 @@ export async function calculateAllEstimatedFundingRate(
|
|
|
43
43
|
const lastMarkPriceTwapTs = market.amm.lastMarkPriceTwapTs;
|
|
44
44
|
|
|
45
45
|
const timeSinceLastMarkChange = now.sub(lastMarkPriceTwapTs);
|
|
46
|
-
const markTwapTimeSinceLastUpdate = BN.max(
|
|
46
|
+
const markTwapTimeSinceLastUpdate = BN.max(
|
|
47
|
+
secondsInHour,
|
|
48
|
+
secondsInHour.sub(timeSinceLastMarkChange)
|
|
49
|
+
);
|
|
47
50
|
const baseAssetPriceWithMantissa = calculateMarkPrice(market);
|
|
48
|
-
|
|
51
|
+
|
|
49
52
|
const markTwapWithMantissa = markTwapTimeSinceLastUpdate
|
|
50
53
|
.mul(lastMarkTwapWithMantissa)
|
|
51
54
|
.add(timeSinceLastMarkChange.mul(baseAssetPriceWithMantissa))
|
|
@@ -57,14 +60,44 @@ export async function calculateAllEstimatedFundingRate(
|
|
|
57
60
|
const lastOraclePriceTwapTs = market.amm.lastOraclePriceTwapTs;
|
|
58
61
|
|
|
59
62
|
const timeSinceLastOracleTwapUpdate = now.sub(lastOraclePriceTwapTs);
|
|
60
|
-
const oracleTwapTimeSinceLastUpdate = BN.max(
|
|
61
|
-
|
|
62
|
-
|
|
63
|
+
const oracleTwapTimeSinceLastUpdate = BN.max(
|
|
64
|
+
secondsInHour,
|
|
65
|
+
secondsInHour.sub(timeSinceLastOracleTwapUpdate)
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
// verify pyth input is positive for live update
|
|
69
|
+
let oracleStablePriceNum = 0;
|
|
70
|
+
let oracleInputCount = 0;
|
|
71
|
+
if (oraclePriceData.price >= 0) {
|
|
72
|
+
oracleStablePriceNum += oraclePriceData.price;
|
|
73
|
+
oracleInputCount += 1;
|
|
74
|
+
}
|
|
75
|
+
if (oraclePriceData.previousPrice >= 0) {
|
|
76
|
+
oracleStablePriceNum += oraclePriceData.previousPrice;
|
|
77
|
+
oracleInputCount += 1;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
oracleStablePriceNum = oracleStablePriceNum / oracleInputCount;
|
|
81
|
+
const oraclePriceStableWithMantissa = new BN(
|
|
82
|
+
oracleStablePriceNum * MARK_PRICE_PRECISION.toNumber()
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
let oracleTwapWithMantissa = lastOracleTwapWithMantissa;
|
|
86
|
+
|
|
87
|
+
const oracleLiveVsTwap = oraclePriceStableWithMantissa
|
|
88
|
+
.sub(lastOracleTwapWithMantissa)
|
|
89
|
+
.abs()
|
|
90
|
+
.mul(MARK_PRICE_PRECISION)
|
|
91
|
+
.mul(new BN(100))
|
|
92
|
+
.div(lastOracleTwapWithMantissa);
|
|
63
93
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
94
|
+
// verify pyth live input is within 10% of last twap for live update
|
|
95
|
+
if (oracleLiveVsTwap.lte(MARK_PRICE_PRECISION.mul(new BN(10)))) {
|
|
96
|
+
oracleTwapWithMantissa = oracleTwapTimeSinceLastUpdate
|
|
97
|
+
.mul(lastOracleTwapWithMantissa)
|
|
98
|
+
.add(timeSinceLastMarkChange.mul(oraclePriceStableWithMantissa))
|
|
99
|
+
.div(timeSinceLastOracleTwapUpdate.add(oracleTwapTimeSinceLastUpdate));
|
|
100
|
+
}
|
|
68
101
|
|
|
69
102
|
const twapSpread = markTwapWithMantissa.sub(oracleTwapWithMantissa);
|
|
70
103
|
|
|
@@ -98,64 +131,85 @@ export async function calculateAllEstimatedFundingRate(
|
|
|
98
131
|
if (market.baseAssetAmountLong.gt(market.baseAssetAmountShort.abs())) {
|
|
99
132
|
largerSide = market.baseAssetAmountLong.abs();
|
|
100
133
|
smallerSide = market.baseAssetAmountShort.abs();
|
|
101
|
-
if(twapSpread.gt(new BN(0))) {
|
|
102
|
-
return [
|
|
134
|
+
if (twapSpread.gt(new BN(0))) {
|
|
135
|
+
return [
|
|
136
|
+
markTwapWithMantissa,
|
|
137
|
+
oracleTwapWithMantissa,
|
|
138
|
+
lowerboundEst,
|
|
139
|
+
interpEst,
|
|
140
|
+
interpEst,
|
|
141
|
+
];
|
|
103
142
|
}
|
|
104
143
|
} else if (market.baseAssetAmountLong.lt(market.baseAssetAmountShort.abs())) {
|
|
105
144
|
largerSide = market.baseAssetAmountShort.abs();
|
|
106
145
|
smallerSide = market.baseAssetAmountLong.abs();
|
|
107
|
-
if(twapSpread.lt(new BN(0))){
|
|
108
|
-
return [
|
|
146
|
+
if (twapSpread.lt(new BN(0))) {
|
|
147
|
+
return [
|
|
148
|
+
markTwapWithMantissa,
|
|
149
|
+
oracleTwapWithMantissa,
|
|
150
|
+
lowerboundEst,
|
|
151
|
+
interpEst,
|
|
152
|
+
interpEst,
|
|
153
|
+
];
|
|
109
154
|
}
|
|
110
|
-
} else{
|
|
111
|
-
return [
|
|
155
|
+
} else {
|
|
156
|
+
return [
|
|
157
|
+
markTwapWithMantissa,
|
|
158
|
+
oracleTwapWithMantissa,
|
|
159
|
+
lowerboundEst,
|
|
160
|
+
interpEst,
|
|
161
|
+
interpEst,
|
|
162
|
+
];
|
|
112
163
|
}
|
|
113
164
|
|
|
114
165
|
if (largerSide.gt(ZERO)) {
|
|
115
|
-
|
|
116
|
-
|
|
166
|
+
// funding smaller flow
|
|
167
|
+
cappedAltEst = smallerSide.mul(twapSpread).div(hoursInDay);
|
|
117
168
|
const feePoolTopOff = feePoolSize
|
|
118
169
|
.mul(MARK_PRICE_PRECISION.div(QUOTE_PRECISION))
|
|
119
|
-
.mul(AMM_RESERVE_PRECISION)
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
cappedAltEst = cappedAltEst.add(feePoolTopOff);
|
|
170
|
+
.mul(AMM_RESERVE_PRECISION);
|
|
171
|
+
cappedAltEst = cappedAltEst.add(feePoolTopOff).div(largerSide);
|
|
123
172
|
|
|
124
173
|
cappedAltEst = cappedAltEst
|
|
125
174
|
.mul(MARK_PRICE_PRECISION)
|
|
126
175
|
.mul(new BN(100))
|
|
127
176
|
.div(oracleTwapWithMantissa)
|
|
128
|
-
.mul(periodAdjustment)
|
|
129
|
-
|
|
130
|
-
if (cappedAltEst.abs().
|
|
177
|
+
.mul(periodAdjustment);
|
|
178
|
+
|
|
179
|
+
if (cappedAltEst.abs().gte(interpEst.abs())) {
|
|
131
180
|
cappedAltEst = interpEst;
|
|
132
181
|
}
|
|
133
182
|
} else {
|
|
134
183
|
cappedAltEst = interpEst;
|
|
135
184
|
}
|
|
136
185
|
|
|
137
|
-
|
|
138
|
-
|
|
186
|
+
return [
|
|
187
|
+
markTwapWithMantissa,
|
|
188
|
+
oracleTwapWithMantissa,
|
|
189
|
+
lowerboundEst,
|
|
190
|
+
cappedAltEst,
|
|
191
|
+
interpEst,
|
|
192
|
+
];
|
|
139
193
|
}
|
|
140
194
|
|
|
141
195
|
/**
|
|
142
196
|
*
|
|
143
197
|
* @param market
|
|
144
|
-
* @param
|
|
198
|
+
* @param oraclePriceData
|
|
145
199
|
* @param periodAdjustment
|
|
146
200
|
* @param estimationMethod
|
|
147
201
|
* @returns Estimated funding rate. : Precision //TODO-PRECISION
|
|
148
202
|
*/
|
|
149
203
|
export async function calculateEstimatedFundingRate(
|
|
150
204
|
market: Market,
|
|
151
|
-
|
|
205
|
+
oraclePriceData: PriceData,
|
|
152
206
|
periodAdjustment: BN = new BN(1),
|
|
153
207
|
estimationMethod: 'interpolated' | 'lowerbound' | 'capped'
|
|
154
208
|
): Promise<BN> {
|
|
155
209
|
const [_1, _2, lowerboundEst, cappedAltEst, interpEst] =
|
|
156
210
|
await calculateAllEstimatedFundingRate(
|
|
157
211
|
market,
|
|
158
|
-
|
|
212
|
+
oraclePriceData,
|
|
159
213
|
periodAdjustment
|
|
160
214
|
);
|
|
161
215
|
|
|
@@ -179,14 +233,15 @@ export async function calculateEstimatedFundingRate(
|
|
|
179
233
|
*/
|
|
180
234
|
export async function calculateLongShortFundingRate(
|
|
181
235
|
market: Market,
|
|
182
|
-
|
|
236
|
+
oraclePriceData: PriceData,
|
|
183
237
|
periodAdjustment: BN = new BN(1)
|
|
184
238
|
): Promise<[BN, BN]> {
|
|
185
|
-
const [_1, _2, _, cappedAltEst, interpEst] =
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
239
|
+
const [_1, _2, _, cappedAltEst, interpEst] =
|
|
240
|
+
await calculateAllEstimatedFundingRate(
|
|
241
|
+
market,
|
|
242
|
+
oraclePriceData,
|
|
243
|
+
periodAdjustment
|
|
244
|
+
);
|
|
190
245
|
|
|
191
246
|
if (market.baseAssetAmountLong.gt(market.baseAssetAmountShort)) {
|
|
192
247
|
return [cappedAltEst, interpEst];
|
|
@@ -198,29 +253,32 @@ export async function calculateLongShortFundingRate(
|
|
|
198
253
|
}
|
|
199
254
|
|
|
200
255
|
/**
|
|
201
|
-
*
|
|
202
|
-
* @param market
|
|
203
|
-
* @param pythClient
|
|
204
|
-
* @param periodAdjustment
|
|
205
|
-
* @param estimationMethod
|
|
256
|
+
*
|
|
257
|
+
* @param market
|
|
258
|
+
* @param pythClient
|
|
259
|
+
* @param periodAdjustment
|
|
260
|
+
* @param estimationMethod
|
|
206
261
|
* @returns Estimated funding rate. : Precision //TODO-PRECISION
|
|
207
262
|
*/
|
|
208
|
-
|
|
263
|
+
export async function calculateLongShortFundingRateAndLiveTwaps(
|
|
209
264
|
market: Market,
|
|
210
|
-
|
|
211
|
-
periodAdjustment: BN = new BN(1)
|
|
265
|
+
oraclePriceData: PriceData,
|
|
266
|
+
periodAdjustment: BN = new BN(1)
|
|
212
267
|
): Promise<[BN, BN, BN, BN]> {
|
|
213
|
-
const [markTwapLive, oracleTwapLive, _2, cappedAltEst, interpEst] =
|
|
214
|
-
await calculateAllEstimatedFundingRate(
|
|
268
|
+
const [markTwapLive, oracleTwapLive, _2, cappedAltEst, interpEst] =
|
|
269
|
+
await calculateAllEstimatedFundingRate(
|
|
270
|
+
market,
|
|
271
|
+
oraclePriceData,
|
|
272
|
+
periodAdjustment
|
|
273
|
+
);
|
|
215
274
|
|
|
216
|
-
if(market.baseAssetAmountLong.gt(market.baseAssetAmountShort.abs())){
|
|
275
|
+
if (market.baseAssetAmountLong.gt(market.baseAssetAmountShort.abs())) {
|
|
217
276
|
return [markTwapLive, oracleTwapLive, cappedAltEst, interpEst];
|
|
218
|
-
} else if(market.baseAssetAmountLong.lt(market.baseAssetAmountShort.abs())){
|
|
277
|
+
} else if (market.baseAssetAmountLong.lt(market.baseAssetAmountShort.abs())) {
|
|
219
278
|
return [markTwapLive, oracleTwapLive, interpEst, cappedAltEst];
|
|
220
|
-
} else{
|
|
279
|
+
} else {
|
|
221
280
|
return [markTwapLive, oracleTwapLive, interpEst, interpEst];
|
|
222
281
|
}
|
|
223
|
-
|
|
224
282
|
}
|
|
225
283
|
|
|
226
284
|
/**
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { MarketsAccount, StateAccount } from '../types';
|
|
2
|
+
import BN from 'bn.js';
|
|
3
|
+
import { Connection } from '@solana/web3.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* In the case of a levered loss, the exchange first pays out undistributed fees and then the insurance fund.
|
|
7
|
+
* Thus the de facto size of the insurance fund is the amount in the insurance vault plus the sum of each markets
|
|
8
|
+
* undistributed fees.
|
|
9
|
+
*
|
|
10
|
+
* @param connection
|
|
11
|
+
* @param state
|
|
12
|
+
* @param marketsAccount
|
|
13
|
+
* @returns Precision : QUOTE_ASSET_PRECISION
|
|
14
|
+
*/
|
|
15
|
+
export async function calculateInsuranceFundSize(
|
|
16
|
+
connection: Connection,
|
|
17
|
+
state: StateAccount,
|
|
18
|
+
marketsAccount: MarketsAccount
|
|
19
|
+
): Promise<BN> {
|
|
20
|
+
const insuranceVaultPublicKey = state.insuranceVault;
|
|
21
|
+
const insuranceVaultAmount = new BN(
|
|
22
|
+
(
|
|
23
|
+
await connection.getTokenAccountBalance(insuranceVaultPublicKey)
|
|
24
|
+
).value.amount
|
|
25
|
+
);
|
|
26
|
+
return marketsAccount.markets.reduce((insuranceVaultAmount, market) => {
|
|
27
|
+
return insuranceVaultAmount.add(market.amm.totalFee.div(new BN(2)));
|
|
28
|
+
}, insuranceVaultAmount);
|
|
29
|
+
}
|
package/src/math/position.ts
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import { Market, PositionDirection, UserPosition } from '../types';
|
|
2
|
-
import {
|
|
3
|
-
AMM_TO_QUOTE_PRECISION_RATIO,
|
|
4
|
-
PEG_PRECISION,
|
|
5
|
-
ZERO,
|
|
6
|
-
} from '../constants/numericConstants';
|
|
7
1
|
import BN from 'bn.js';
|
|
8
|
-
import { calculateAmmReservesAfterSwap, getSwapDirection } from './amm';
|
|
9
2
|
import {
|
|
10
3
|
AMM_RESERVE_PRECISION,
|
|
4
|
+
AMM_TIMES_PEG_TO_QUOTE_PRECISION_RATIO,
|
|
5
|
+
AMM_TO_QUOTE_PRECISION_RATIO,
|
|
11
6
|
FUNDING_PAYMENT_PRECISION,
|
|
7
|
+
MARK_PRICE_PRECISION,
|
|
8
|
+
ONE,
|
|
12
9
|
PRICE_TO_QUOTE_PRECISION,
|
|
10
|
+
ZERO,
|
|
13
11
|
} from '../constants/numericConstants';
|
|
12
|
+
import { Market, PositionDirection, UserPosition } from '../types';
|
|
13
|
+
import { calculateAmmReservesAfterSwap, getSwapDirection } from './amm';
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
16
|
* calculateBaseAssetValue
|
|
@@ -43,15 +43,13 @@ export function calculateBaseAssetValue(
|
|
|
43
43
|
return market.amm.quoteAssetReserve
|
|
44
44
|
.sub(newQuoteAssetReserve)
|
|
45
45
|
.mul(market.amm.pegMultiplier)
|
|
46
|
-
.div(
|
|
47
|
-
.div(AMM_TO_QUOTE_PRECISION_RATIO);
|
|
46
|
+
.div(AMM_TIMES_PEG_TO_QUOTE_PRECISION_RATIO);
|
|
48
47
|
|
|
49
48
|
case PositionDirection.LONG:
|
|
50
49
|
return newQuoteAssetReserve
|
|
51
50
|
.sub(market.amm.quoteAssetReserve)
|
|
52
51
|
.mul(market.amm.pegMultiplier)
|
|
53
|
-
.div(
|
|
54
|
-
.div(AMM_TO_QUOTE_PRECISION_RATIO);
|
|
52
|
+
.div(AMM_TIMES_PEG_TO_QUOTE_PRECISION_RATIO);
|
|
55
53
|
}
|
|
56
54
|
}
|
|
57
55
|
|
|
@@ -72,21 +70,13 @@ export function calculatePositionPNL(
|
|
|
72
70
|
return ZERO;
|
|
73
71
|
}
|
|
74
72
|
|
|
75
|
-
const directionToClose = marketPosition.baseAssetAmount.gt(ZERO)
|
|
76
|
-
? PositionDirection.SHORT
|
|
77
|
-
: PositionDirection.LONG;
|
|
78
|
-
|
|
79
73
|
const baseAssetValue = calculateBaseAssetValue(market, marketPosition);
|
|
80
|
-
let pnlAssetAmount;
|
|
81
74
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
case PositionDirection.LONG:
|
|
88
|
-
pnlAssetAmount = marketPosition.quoteAssetAmount.sub(baseAssetValue);
|
|
89
|
-
break;
|
|
75
|
+
let pnl;
|
|
76
|
+
if (marketPosition.baseAssetAmount.gt(ZERO)) {
|
|
77
|
+
pnl = baseAssetValue.sub(marketPosition.quoteAssetAmount);
|
|
78
|
+
} else {
|
|
79
|
+
pnl = marketPosition.quoteAssetAmount.sub(baseAssetValue).sub(ONE);
|
|
90
80
|
}
|
|
91
81
|
|
|
92
82
|
if (withFunding) {
|
|
@@ -95,10 +85,10 @@ export function calculatePositionPNL(
|
|
|
95
85
|
marketPosition
|
|
96
86
|
).div(PRICE_TO_QUOTE_PRECISION);
|
|
97
87
|
|
|
98
|
-
|
|
88
|
+
pnl = pnl.add(fundingRatePnL);
|
|
99
89
|
}
|
|
100
90
|
|
|
101
|
-
return
|
|
91
|
+
return pnl;
|
|
102
92
|
}
|
|
103
93
|
|
|
104
94
|
/**
|
|
@@ -131,3 +121,20 @@ export function calculatePositionFundingPNL(
|
|
|
131
121
|
|
|
132
122
|
return perPositionFundingRate;
|
|
133
123
|
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
*
|
|
127
|
+
* @param userPosition
|
|
128
|
+
* @returns Precision: MARK_PRICE_PRECISION (10^10)
|
|
129
|
+
*/
|
|
130
|
+
export function calculateEntryPrice(userPosition: UserPosition): BN {
|
|
131
|
+
if (userPosition.baseAssetAmount.eq(ZERO)) {
|
|
132
|
+
return ZERO;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return userPosition.quoteAssetAmount
|
|
136
|
+
.mul(MARK_PRICE_PRECISION)
|
|
137
|
+
.mul(AMM_TO_QUOTE_PRECISION_RATIO)
|
|
138
|
+
.div(userPosition.baseAssetAmount)
|
|
139
|
+
.abs();
|
|
140
|
+
}
|
package/src/math/trade.ts
CHANGED
|
@@ -146,7 +146,8 @@ export function calculateTradeAcquiredAmounts(
|
|
|
146
146
|
export function calculateTargetPriceTrade(
|
|
147
147
|
market: Market,
|
|
148
148
|
targetPrice: BN,
|
|
149
|
-
pct: BN = MAXPCT
|
|
149
|
+
pct: BN = MAXPCT,
|
|
150
|
+
outputAssetType: AssetType = 'quote'
|
|
150
151
|
): [PositionDirection, BN, BN, BN] {
|
|
151
152
|
assert(market.amm.baseAssetReserve.gt(ZERO));
|
|
152
153
|
assert(targetPrice.gt(ZERO));
|
|
@@ -199,7 +200,7 @@ export function calculateTargetPriceTrade(
|
|
|
199
200
|
.mul(peg)
|
|
200
201
|
.div(PEG_PRECISION)
|
|
201
202
|
.div(AMM_TO_QUOTE_PRECISION_RATIO);
|
|
202
|
-
baseSize =
|
|
203
|
+
baseSize = baseAssetReserveAfter.sub(baseAssetReserveBefore);
|
|
203
204
|
} else if (markPriceBefore.lt(targetPrice)) {
|
|
204
205
|
// underestimate y2
|
|
205
206
|
baseAssetReserveAfter = squareRootBN(
|
|
@@ -221,7 +222,7 @@ export function calculateTargetPriceTrade(
|
|
|
221
222
|
.mul(peg)
|
|
222
223
|
.div(PEG_PRECISION)
|
|
223
224
|
.div(AMM_TO_QUOTE_PRECISION_RATIO);
|
|
224
|
-
baseSize =
|
|
225
|
+
baseSize = baseAssetReserveBefore.sub(baseAssetReserveAfter);
|
|
225
226
|
} else {
|
|
226
227
|
// no trade, market is at target
|
|
227
228
|
direction = PositionDirection.LONG;
|
|
@@ -254,6 +255,9 @@ export function calculateTargetPriceTrade(
|
|
|
254
255
|
'err: ' +
|
|
255
256
|
tp2.sub(tp1).abs().toString()
|
|
256
257
|
);
|
|
257
|
-
|
|
258
|
-
|
|
258
|
+
if (outputAssetType == 'quote') {
|
|
259
|
+
return [direction, tradeSize, entryPrice, targetPrice];
|
|
260
|
+
} else {
|
|
261
|
+
return [direction, baseSize, entryPrice, targetPrice];
|
|
262
|
+
}
|
|
259
263
|
}
|
package/src/types.ts
CHANGED
|
@@ -259,60 +259,6 @@ export type UserAccount = {
|
|
|
259
259
|
totalFeePaid: BN;
|
|
260
260
|
};
|
|
261
261
|
|
|
262
|
-
// # UI ↔ History Server Data Types
|
|
263
|
-
export interface Trade {
|
|
264
|
-
price: number;
|
|
265
|
-
beforePrice: number;
|
|
266
|
-
afterPrice: number;
|
|
267
|
-
side: TradeSide;
|
|
268
|
-
size: number;
|
|
269
|
-
quoteSize: number;
|
|
270
|
-
ts: number;
|
|
271
|
-
fee: number;
|
|
272
|
-
marketIndex: number;
|
|
273
|
-
chainTs: number;
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
export type Liquidation = {
|
|
277
|
-
ts: number;
|
|
278
|
-
chainTs: number;
|
|
279
|
-
recordId: number;
|
|
280
|
-
userAuthority: PublicKey;
|
|
281
|
-
user: PublicKey;
|
|
282
|
-
partial: boolean;
|
|
283
|
-
baseAssetValue: number;
|
|
284
|
-
baseAssetValueClosed: number;
|
|
285
|
-
liquidationFee: number;
|
|
286
|
-
feeToLiquidator: number;
|
|
287
|
-
feeToInsuranceFund: number;
|
|
288
|
-
liquidator: PublicKey;
|
|
289
|
-
totalCollateral: number;
|
|
290
|
-
collateral: number;
|
|
291
|
-
unrealizedPnl: number;
|
|
292
|
-
marginRatio: number;
|
|
293
|
-
};
|
|
294
|
-
|
|
295
|
-
export type Candle = {
|
|
296
|
-
open: number;
|
|
297
|
-
close: number;
|
|
298
|
-
high: number;
|
|
299
|
-
low: number;
|
|
300
|
-
volume: number;
|
|
301
|
-
start: number;
|
|
302
|
-
end: number;
|
|
303
|
-
};
|
|
304
|
-
export interface FundingPayment {
|
|
305
|
-
userPublicKey: string;
|
|
306
|
-
serverTs: number;
|
|
307
|
-
marketIndex: number;
|
|
308
|
-
amount: string;
|
|
309
|
-
blockchainTs: number;
|
|
310
|
-
baseAssetAmount: string;
|
|
311
|
-
userLastCumulativeFunding: string;
|
|
312
|
-
userLastFundingRateTs: string;
|
|
313
|
-
rate: number;
|
|
314
|
-
}
|
|
315
|
-
|
|
316
262
|
// # Misc Types
|
|
317
263
|
export interface IWallet {
|
|
318
264
|
signTransaction(tx: Transaction): Promise<Transaction>;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Connection, Finality, PublicKey } from '@solana/web3.js';
|
|
2
|
+
|
|
3
|
+
export async function findComputeUnitConsumption(
|
|
4
|
+
programId: PublicKey,
|
|
5
|
+
connection: Connection,
|
|
6
|
+
txSignature: string,
|
|
7
|
+
commitment: Finality = 'confirmed'
|
|
8
|
+
): Promise<number[]> {
|
|
9
|
+
const tx = await connection.getTransaction(txSignature, { commitment });
|
|
10
|
+
const computeUnits = [];
|
|
11
|
+
const regex = new RegExp(
|
|
12
|
+
`Program ${programId.toString()} consumed ([0-9]{0,6}) of 200000 compute units`
|
|
13
|
+
);
|
|
14
|
+
tx.meta.logMessages.forEach((logMessage) => {
|
|
15
|
+
const match = logMessage.match(regex);
|
|
16
|
+
if (match && match[1]) {
|
|
17
|
+
computeUnits.push(match[1]);
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
return computeUnits;
|
|
21
|
+
}
|
package/src/wallet.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Keypair, PublicKey, Transaction } from '@solana/web3.js';
|
|
2
|
+
import { IWallet } from './types';
|
|
3
|
+
|
|
4
|
+
export class Wallet implements IWallet {
|
|
5
|
+
constructor(readonly payer: Keypair) {}
|
|
6
|
+
|
|
7
|
+
async signTransaction(tx: Transaction): Promise<Transaction> {
|
|
8
|
+
tx.partialSign(this.payer);
|
|
9
|
+
return tx;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
async signAllTransactions(txs: Transaction[]): Promise<Transaction[]> {
|
|
13
|
+
return txs.map((t) => {
|
|
14
|
+
t.partialSign(this.payer);
|
|
15
|
+
return t;
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
get publicKey(): PublicKey {
|
|
20
|
+
return this.payer.publicKey;
|
|
21
|
+
}
|
|
22
|
+
}
|
package/.eslintrc.json
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"root": true,
|
|
3
|
-
"parser": "@typescript-eslint/parser",
|
|
4
|
-
"env": {
|
|
5
|
-
"browser": true
|
|
6
|
-
},
|
|
7
|
-
"ignorePatterns": ["**/lib"],
|
|
8
|
-
"plugins": [],
|
|
9
|
-
"extends": [
|
|
10
|
-
"eslint:recommended",
|
|
11
|
-
"plugin:@typescript-eslint/eslint-recommended",
|
|
12
|
-
"plugin:@typescript-eslint/recommended"
|
|
13
|
-
],
|
|
14
|
-
"rules": {
|
|
15
|
-
"@typescript-eslint/explicit-function-return-type": "off",
|
|
16
|
-
"@typescript-eslint/ban-ts-ignore": "off",
|
|
17
|
-
"@typescript-eslint/ban-ts-comment": "off",
|
|
18
|
-
"@typescript-eslint/no-explicit-any": "off",
|
|
19
|
-
"@typescript-eslint/no-unused-vars": [
|
|
20
|
-
2,
|
|
21
|
-
{
|
|
22
|
-
"argsIgnorePattern": "^_",
|
|
23
|
-
"varsIgnorePattern": "^_"
|
|
24
|
-
}
|
|
25
|
-
],
|
|
26
|
-
"@typescript-eslint/no-var-requires": 0,
|
|
27
|
-
"@typescript-eslint/no-empty-function": 0,
|
|
28
|
-
"no-mixed-spaces-and-tabs": [2, "smart-tabs"],
|
|
29
|
-
"semi": 2
|
|
30
|
-
},
|
|
31
|
-
"settings": {
|
|
32
|
-
"react": {
|
|
33
|
-
"version": "detect"
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
}
|
package/.prettierignore
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
**/node_modules/**
|
package/.prettierrc.js
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
/// <reference types="node" />
|
|
2
|
-
import { ClearingHouseAccountEvents, HistoryAccountSubscriber } from './types';
|
|
3
|
-
import { AccountSubscriber } from './types';
|
|
4
|
-
import { CurveHistoryAccount, DepositHistoryAccount, FundingPaymentHistoryAccount, FundingRateHistoryAccount, LiquidationHistoryAccount, TradeHistoryAccount } from '../types';
|
|
5
|
-
import { Program } from '@project-serum/anchor';
|
|
6
|
-
import StrictEventEmitter from 'strict-event-emitter-types';
|
|
7
|
-
import { EventEmitter } from 'events';
|
|
8
|
-
export declare class DefaultHistoryAccountSubscriber implements HistoryAccountSubscriber {
|
|
9
|
-
isSubscribed: boolean;
|
|
10
|
-
program: Program;
|
|
11
|
-
eventEmitter: StrictEventEmitter<EventEmitter, ClearingHouseAccountEvents>;
|
|
12
|
-
tradeHistoryAccountSubscriber?: AccountSubscriber<TradeHistoryAccount>;
|
|
13
|
-
depositHistoryAccountSubscriber?: AccountSubscriber<DepositHistoryAccount>;
|
|
14
|
-
fundingPaymentHistoryAccountSubscriber?: AccountSubscriber<FundingPaymentHistoryAccount>;
|
|
15
|
-
fundingRateHistoryAccountSubscriber?: AccountSubscriber<FundingRateHistoryAccount>;
|
|
16
|
-
curveHistoryAccountSubscriber?: AccountSubscriber<CurveHistoryAccount>;
|
|
17
|
-
liquidationHistoryAccountSubscriber?: AccountSubscriber<LiquidationHistoryAccount>;
|
|
18
|
-
constructor(program: Program);
|
|
19
|
-
subscribe(): Promise<boolean>;
|
|
20
|
-
unsubscribe(): Promise<void>;
|
|
21
|
-
assertIsSubscribed(): void;
|
|
22
|
-
getTradeHistoryAccount(): TradeHistoryAccount;
|
|
23
|
-
getDepositHistoryAccount(): DepositHistoryAccount;
|
|
24
|
-
getFundingPaymentHistoryAccount(): FundingPaymentHistoryAccount;
|
|
25
|
-
getFundingRateHistoryAccount(): FundingRateHistoryAccount;
|
|
26
|
-
getCurveHistoryAccount(): CurveHistoryAccount;
|
|
27
|
-
getLiquidationHistoryAccount(): LiquidationHistoryAccount;
|
|
28
|
-
}
|
|
29
|
-
//# sourceMappingURL=defaultHistoryAccountSubscriber.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"defaultHistoryAccountSubscriber.d.ts","sourceRoot":"","sources":["../../src/accounts/defaultHistoryAccountSubscriber.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,0BAA0B,EAAE,wBAAwB,EAAE,MAAM,SAAS,CAAC;AAC/E,OAAO,EAAE,iBAAiB,EAAsB,MAAM,SAAS,CAAC;AAChE,OAAO,EACN,mBAAmB,EACnB,qBAAqB,EACrB,4BAA4B,EAC5B,yBAAyB,EACzB,yBAAyB,EAEzB,mBAAmB,EACnB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,OAAO,kBAAkB,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAItC,qBAAa,+BACZ,YAAW,wBAAwB;IAEnC,YAAY,EAAE,OAAO,CAAC;IACtB,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,kBAAkB,CAAC,YAAY,EAAE,0BAA0B,CAAC,CAAC;IAC3E,6BAA6B,CAAC,EAAE,iBAAiB,CAAC,mBAAmB,CAAC,CAAC;IACvE,+BAA+B,CAAC,EAAE,iBAAiB,CAAC,qBAAqB,CAAC,CAAC;IAC3E,sCAAsC,CAAC,EAAE,iBAAiB,CAAC,4BAA4B,CAAC,CAAC;IACzF,mCAAmC,CAAC,EAAE,iBAAiB,CAAC,yBAAyB,CAAC,CAAC;IACnF,6BAA6B,CAAC,EAAE,iBAAiB,CAAC,mBAAmB,CAAC,CAAC;IACvE,mCAAmC,CAAC,EAAE,iBAAiB,CAAC,yBAAyB,CAAC,CAAC;gBAEhE,OAAO,EAAE,OAAO;IAMtB,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC;IA2F7B,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAczC,kBAAkB,IAAI,IAAI;IAQnB,sBAAsB,IAAI,mBAAmB;IAK7C,wBAAwB,IAAI,qBAAqB;IAKjD,+BAA+B,IAAI,4BAA4B;IAK/D,4BAA4B,IAAI,yBAAyB;IAKzD,sBAAsB,IAAI,mBAAmB;IAK7C,4BAA4B,IAAI,yBAAyB;CAIhE"}
|