@drift-labs/sdk 0.2.0-master.3 → 0.2.0-master.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -13
- package/lib/accounts/bulkUserStatsSubscription.d.ts +7 -0
- package/lib/accounts/bulkUserStatsSubscription.js +21 -0
- 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 +16 -16
- package/lib/accounts/pollingClearingHouseAccountSubscriber.js +31 -28
- package/lib/accounts/pollingUserStatsAccountSubscriber.d.ts +27 -0
- package/lib/accounts/pollingUserStatsAccountSubscriber.js +113 -0
- package/lib/accounts/types.d.ts +22 -11
- package/lib/accounts/webSocketClearingHouseAccountSubscriber.d.ts +17 -17
- package/lib/accounts/webSocketClearingHouseAccountSubscriber.js +37 -35
- 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/pda.d.ts +10 -4
- package/lib/addresses/pda.js +51 -14
- package/lib/admin.d.ts +34 -22
- package/lib/admin.js +182 -73
- package/lib/clearingHouse.d.ts +120 -42
- package/lib/clearingHouse.js +1505 -254
- package/lib/clearingHouseConfig.d.ts +4 -4
- package/lib/clearingHouseUser.d.ts +50 -38
- package/lib/clearingHouseUser.js +410 -190
- package/lib/clearingHouseUserStats.d.ts +18 -0
- package/lib/clearingHouseUserStats.js +49 -0
- package/lib/clearingHouseUserStatsConfig.d.ts +14 -0
- package/lib/clearingHouseUserStatsConfig.js +2 -0
- package/lib/config.d.ts +7 -9
- package/lib/config.js +21 -21
- package/lib/constants/numericConstants.d.ts +18 -12
- package/lib/constants/numericConstants.js +28 -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 +73 -0
- package/lib/dlob/DLOB.js +553 -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/eventList.js +3 -0
- package/lib/events/eventSubscriber.d.ts +4 -2
- package/lib/events/eventSubscriber.js +16 -9
- package/lib/events/fetchLogs.d.ts +10 -1
- package/lib/events/fetchLogs.js +27 -7
- package/lib/events/pollingLogProvider.d.ts +2 -1
- package/lib/events/pollingLogProvider.js +6 -2
- package/lib/events/sort.js +8 -11
- package/lib/events/types.d.ts +7 -2
- package/lib/events/types.js +5 -0
- package/lib/examples/makeTradeExample.js +20 -8
- package/lib/factory/bigNum.d.ts +1 -0
- package/lib/factory/bigNum.js +34 -10
- package/lib/idl/clearing_house.json +4313 -1433
- package/lib/idl/{mock_usdc_faucet.json → token_faucet.json} +46 -23
- package/lib/index.d.ts +21 -6
- package/lib/index.js +25 -6
- package/lib/math/amm.d.ts +8 -5
- package/lib/math/amm.js +68 -46
- package/lib/math/auction.js +4 -1
- package/lib/math/conversion.js +1 -1
- package/lib/math/funding.d.ts +6 -6
- package/lib/math/funding.js +11 -10
- 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 +77 -0
- package/lib/math/market.d.ts +14 -9
- package/lib/math/market.js +69 -7
- package/lib/math/oracles.d.ts +4 -0
- package/lib/math/oracles.js +36 -8
- package/lib/math/orders.d.ts +6 -2
- package/lib/math/orders.js +78 -3
- package/lib/math/position.d.ts +21 -13
- package/lib/math/position.js +76 -36
- package/lib/math/repeg.js +14 -5
- 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/trade.d.ts +10 -10
- package/lib/math/trade.js +22 -29
- 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 +14 -5
- package/lib/orderParams.js +12 -92
- 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/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 +474 -123
- package/lib/types.js +99 -5
- 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/lib/util/computeUnits.js +1 -1
- package/lib/util/getTokenAddress.d.ts +2 -0
- package/lib/util/getTokenAddress.js +9 -0
- package/package.json +9 -5
- package/src/accounts/bulkUserStatsSubscription.ts +33 -0
- package/src/accounts/bulkUserSubscription.ts +0 -1
- package/src/accounts/fetch.ts +27 -2
- package/src/accounts/pollingClearingHouseAccountSubscriber.ts +46 -42
- package/src/accounts/pollingUserStatsAccountSubscriber.ts +172 -0
- package/src/accounts/types.ts +31 -11
- package/src/accounts/webSocketClearingHouseAccountSubscriber.ts +64 -59
- package/src/accounts/webSocketUserStatsAccountSubsriber.ts +80 -0
- package/src/addresses/marketAddresses.ts +1 -2
- package/src/addresses/pda.ts +88 -14
- package/src/admin.ts +333 -128
- package/src/assert/assert.js +9 -0
- package/src/clearingHouse.ts +2464 -458
- package/src/clearingHouseConfig.ts +4 -3
- package/src/clearingHouseUser.ts +747 -291
- package/src/clearingHouseUserStats.ts +75 -0
- package/src/clearingHouseUserStatsConfig.ts +18 -0
- package/src/config.ts +30 -31
- package/src/constants/numericConstants.ts +41 -25
- package/src/constants/{markets.ts → perpMarkets.ts} +10 -10
- package/src/constants/spotMarkets.ts +72 -0
- package/src/dlob/DLOB.ts +868 -0
- package/src/dlob/DLOBNode.ts +162 -0
- package/src/dlob/NodeList.ts +185 -0
- package/src/events/eventList.js +77 -0
- package/src/events/eventList.ts +3 -0
- package/src/events/eventSubscriber.ts +20 -12
- package/src/events/fetchLogs.ts +35 -8
- package/src/events/pollingLogProvider.ts +10 -2
- package/src/events/sort.ts +11 -15
- package/src/events/types.ts +16 -1
- package/src/examples/makeTradeExample.js +157 -0
- package/src/examples/makeTradeExample.ts +32 -14
- package/src/factory/bigNum.ts +42 -13
- package/src/idl/clearing_house.json +4313 -1433
- package/src/idl/{mock_usdc_faucet.json → token_faucet.json} +46 -23
- package/src/index.ts +21 -6
- package/src/math/amm.ts +136 -66
- package/src/math/auction.ts +5 -1
- package/src/math/conversion.ts +2 -2
- package/src/math/funding.ts +20 -18
- package/src/math/insurance.ts +35 -0
- package/src/math/margin.ts +127 -0
- package/src/math/market.ts +138 -12
- package/src/math/oracles.ts +63 -9
- package/src/math/orders.ts +138 -4
- package/src/math/position.ts +119 -58
- package/src/math/repeg.ts +16 -6
- package/src/math/spotBalance.ts +316 -0
- package/src/math/spotMarket.ts +9 -0
- package/src/math/spotPosition.ts +47 -0
- package/src/math/trade.ts +43 -49
- 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 +24 -137
- package/src/serum/serumSubscriber.ts +80 -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 +477 -125
- package/src/userMap/userMap.ts +100 -0
- package/src/userMap/userStatsMap.ts +110 -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 +12 -3
- package/tests/dlob/helpers.ts +374 -0
- package/tests/dlob/test.ts +2865 -0
- 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/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/constants/banks.ts +0 -43
- 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
|
@@ -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.openAsks.neg(),
|
|
35
|
+
spotMarketAccount.decimals,
|
|
36
|
+
oraclePriceData
|
|
37
|
+
);
|
|
38
|
+
return [tokenAmountAllBidsFill, worstCaseQuoteTokenAmount];
|
|
39
|
+
} else {
|
|
40
|
+
const worstCaseQuoteTokenAmount = getTokenValue(
|
|
41
|
+
spotPosition.openBids.neg(),
|
|
42
|
+
spotMarketAccount.decimals,
|
|
43
|
+
oraclePriceData
|
|
44
|
+
);
|
|
45
|
+
return [tokenAmountAllAsksFill, worstCaseQuoteTokenAmount];
|
|
46
|
+
}
|
|
47
|
+
}
|
package/src/math/trade.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
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 {
|
|
5
|
-
|
|
5
|
+
PRICE_PRECISION,
|
|
6
6
|
PEG_PRECISION,
|
|
7
7
|
AMM_TO_QUOTE_PRECISION_RATIO,
|
|
8
8
|
ZERO,
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
import {
|
|
11
11
|
calculateBidPrice,
|
|
12
12
|
calculateAskPrice,
|
|
13
|
-
|
|
13
|
+
calculateReservePrice,
|
|
14
14
|
} from './market';
|
|
15
15
|
import {
|
|
16
16
|
calculateAmmReservesAfterSwap,
|
|
@@ -48,18 +48,18 @@ export type PriceImpactUnit =
|
|
|
48
48
|
* @param useSpread whether to consider spread with calculating slippage
|
|
49
49
|
* @return [pctAvgSlippage, pctMaxSlippage, entryPrice, newPrice]
|
|
50
50
|
*
|
|
51
|
-
* 'pctAvgSlippage' => the percentage change to entryPrice (average est slippage in execution) : Precision
|
|
51
|
+
* 'pctAvgSlippage' => the percentage change to entryPrice (average est slippage in execution) : Precision PRICE_PRECISION
|
|
52
52
|
*
|
|
53
|
-
* 'pctMaxSlippage' => the percentage change to maxPrice (highest est slippage in execution) : Precision
|
|
53
|
+
* 'pctMaxSlippage' => the percentage change to maxPrice (highest est slippage in execution) : Precision PRICE_PRECISION
|
|
54
54
|
*
|
|
55
|
-
* 'entryPrice' => the average price of the trade : Precision
|
|
55
|
+
* 'entryPrice' => the average price of the trade : Precision PRICE_PRECISION
|
|
56
56
|
*
|
|
57
|
-
* 'newPrice' => the price of the asset after the trade : Precision
|
|
57
|
+
* 'newPrice' => the price of the asset after the trade : Precision PRICE_PRECISION
|
|
58
58
|
*/
|
|
59
59
|
export function calculateTradeSlippage(
|
|
60
60
|
direction: PositionDirection,
|
|
61
61
|
amount: BN,
|
|
62
|
-
market:
|
|
62
|
+
market: PerpMarketAccount,
|
|
63
63
|
inputAssetType: AssetType = 'quote',
|
|
64
64
|
oraclePriceData?: OraclePriceData,
|
|
65
65
|
useSpread = true
|
|
@@ -73,33 +73,25 @@ export function calculateTradeSlippage(
|
|
|
73
73
|
oldPrice = calculateBidPrice(market, oraclePriceData);
|
|
74
74
|
}
|
|
75
75
|
} else {
|
|
76
|
-
oldPrice =
|
|
76
|
+
oldPrice = calculateReservePrice(market, oraclePriceData);
|
|
77
77
|
}
|
|
78
78
|
if (amount.eq(ZERO)) {
|
|
79
79
|
return [ZERO, ZERO, oldPrice, oldPrice];
|
|
80
80
|
}
|
|
81
|
-
const [
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
const swapDirection = isVariant(direction, 'long')
|
|
91
|
-
? SwapDirection.REMOVE
|
|
92
|
-
: SwapDirection.ADD;
|
|
93
|
-
const quoteAssetAmountAcquired = calculateQuoteAssetAmountSwapped(
|
|
94
|
-
acquiredQuote.abs(),
|
|
95
|
-
market.amm.pegMultiplier,
|
|
96
|
-
swapDirection
|
|
97
|
-
);
|
|
81
|
+
const [acquiredBaseReserve, acquiredQuoteReserve, acquiredQuoteAssetAmount] =
|
|
82
|
+
calculateTradeAcquiredAmounts(
|
|
83
|
+
direction,
|
|
84
|
+
amount,
|
|
85
|
+
market,
|
|
86
|
+
inputAssetType,
|
|
87
|
+
oraclePriceData,
|
|
88
|
+
useSpread
|
|
89
|
+
);
|
|
98
90
|
|
|
99
|
-
const entryPrice =
|
|
91
|
+
const entryPrice = acquiredQuoteAssetAmount
|
|
100
92
|
.mul(AMM_TO_QUOTE_PRECISION_RATIO)
|
|
101
|
-
.mul(
|
|
102
|
-
.div(
|
|
93
|
+
.mul(PRICE_PRECISION)
|
|
94
|
+
.div(acquiredBaseReserve.abs());
|
|
103
95
|
|
|
104
96
|
let amm: Parameters<typeof calculateAmmReservesAfterSwap>[0];
|
|
105
97
|
if (useSpread && market.amm.baseSpread > 0) {
|
|
@@ -116,8 +108,8 @@ export function calculateTradeSlippage(
|
|
|
116
108
|
}
|
|
117
109
|
|
|
118
110
|
const newPrice = calculatePrice(
|
|
119
|
-
amm.baseAssetReserve.sub(
|
|
120
|
-
amm.quoteAssetReserve.sub(
|
|
111
|
+
amm.baseAssetReserve.sub(acquiredBaseReserve),
|
|
112
|
+
amm.quoteAssetReserve.sub(acquiredQuoteReserve),
|
|
121
113
|
amm.pegMultiplier
|
|
122
114
|
);
|
|
123
115
|
|
|
@@ -129,12 +121,12 @@ export function calculateTradeSlippage(
|
|
|
129
121
|
|
|
130
122
|
const pctMaxSlippage = newPrice
|
|
131
123
|
.sub(oldPrice)
|
|
132
|
-
.mul(
|
|
124
|
+
.mul(PRICE_PRECISION)
|
|
133
125
|
.div(oldPrice)
|
|
134
126
|
.abs();
|
|
135
127
|
const pctAvgSlippage = entryPrice
|
|
136
128
|
.sub(oldPrice)
|
|
137
|
-
.mul(
|
|
129
|
+
.mul(PRICE_PRECISION)
|
|
138
130
|
.div(oldPrice)
|
|
139
131
|
.abs();
|
|
140
132
|
|
|
@@ -155,13 +147,13 @@ export function calculateTradeSlippage(
|
|
|
155
147
|
export function calculateTradeAcquiredAmounts(
|
|
156
148
|
direction: PositionDirection,
|
|
157
149
|
amount: BN,
|
|
158
|
-
market:
|
|
150
|
+
market: PerpMarketAccount,
|
|
159
151
|
inputAssetType: AssetType = 'quote',
|
|
160
152
|
oraclePriceData: OraclePriceData,
|
|
161
153
|
useSpread = true
|
|
162
|
-
): [BN, BN] {
|
|
154
|
+
): [BN, BN, BN] {
|
|
163
155
|
if (amount.eq(ZERO)) {
|
|
164
|
-
return [ZERO, ZERO];
|
|
156
|
+
return [ZERO, ZERO, ZERO];
|
|
165
157
|
}
|
|
166
158
|
|
|
167
159
|
const swapDirection = getSwapDirection(inputAssetType, direction);
|
|
@@ -185,7 +177,13 @@ export function calculateTradeAcquiredAmounts(
|
|
|
185
177
|
|
|
186
178
|
const acquiredBase = amm.baseAssetReserve.sub(newBaseAssetReserve);
|
|
187
179
|
const acquiredQuote = amm.quoteAssetReserve.sub(newQuoteAssetReserve);
|
|
188
|
-
|
|
180
|
+
const acquiredQuoteAssetAmount = calculateQuoteAssetAmountSwapped(
|
|
181
|
+
acquiredQuote.abs(),
|
|
182
|
+
amm.pegMultiplier,
|
|
183
|
+
swapDirection
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
return [acquiredBase, acquiredQuote, acquiredQuoteAssetAmount];
|
|
189
187
|
}
|
|
190
188
|
|
|
191
189
|
/**
|
|
@@ -201,12 +199,12 @@ export function calculateTradeAcquiredAmounts(
|
|
|
201
199
|
* [
|
|
202
200
|
* direction => direction of trade required, PositionDirection
|
|
203
201
|
* tradeSize => size of trade required, TODO-PRECISION
|
|
204
|
-
* entryPrice => the entry price for the trade,
|
|
205
|
-
* targetPrice => the target price
|
|
202
|
+
* entryPrice => the entry price for the trade, PRICE_PRECISION
|
|
203
|
+
* targetPrice => the target price PRICE_PRECISION
|
|
206
204
|
* ]
|
|
207
205
|
*/
|
|
208
206
|
export function calculateTargetPriceTrade(
|
|
209
|
-
market:
|
|
207
|
+
market: PerpMarketAccount,
|
|
210
208
|
targetPrice: BN,
|
|
211
209
|
pct: BN = MAXPCT,
|
|
212
210
|
outputAssetType: AssetType = 'quote',
|
|
@@ -217,7 +215,7 @@ export function calculateTargetPriceTrade(
|
|
|
217
215
|
assert(targetPrice.gt(ZERO));
|
|
218
216
|
assert(pct.lte(MAXPCT) && pct.gt(ZERO));
|
|
219
217
|
|
|
220
|
-
const markPriceBefore =
|
|
218
|
+
const markPriceBefore = calculateReservePrice(market, oraclePriceData);
|
|
221
219
|
const bidPriceBefore = calculateBidPrice(market, oraclePriceData);
|
|
222
220
|
const askPriceBefore = calculateAskPrice(market, oraclePriceData);
|
|
223
221
|
|
|
@@ -254,7 +252,7 @@ export function calculateTargetPriceTrade(
|
|
|
254
252
|
}
|
|
255
253
|
|
|
256
254
|
const invariant = market.amm.sqrtK.mul(market.amm.sqrtK);
|
|
257
|
-
const k = invariant.mul(
|
|
255
|
+
const k = invariant.mul(PRICE_PRECISION);
|
|
258
256
|
|
|
259
257
|
let baseAssetReserveAfter;
|
|
260
258
|
let quoteAssetReserveAfter;
|
|
@@ -279,9 +277,7 @@ export function calculateTargetPriceTrade(
|
|
|
279
277
|
baseAssetReserveAfter = squareRootBN(
|
|
280
278
|
k.div(targetPrice).mul(peg).div(PEG_PRECISION).sub(biasModifier)
|
|
281
279
|
).sub(new BN(1));
|
|
282
|
-
quoteAssetReserveAfter = k
|
|
283
|
-
.div(MARK_PRICE_PRECISION)
|
|
284
|
-
.div(baseAssetReserveAfter);
|
|
280
|
+
quoteAssetReserveAfter = k.div(PRICE_PRECISION).div(baseAssetReserveAfter);
|
|
285
281
|
|
|
286
282
|
markPriceAfter = calculatePrice(
|
|
287
283
|
baseAssetReserveAfter,
|
|
@@ -300,9 +296,7 @@ export function calculateTargetPriceTrade(
|
|
|
300
296
|
baseAssetReserveAfter = squareRootBN(
|
|
301
297
|
k.div(targetPrice).mul(peg).div(PEG_PRECISION).add(biasModifier)
|
|
302
298
|
).add(new BN(1));
|
|
303
|
-
quoteAssetReserveAfter = k
|
|
304
|
-
.div(MARK_PRICE_PRECISION)
|
|
305
|
-
.div(baseAssetReserveAfter);
|
|
299
|
+
quoteAssetReserveAfter = k.div(PRICE_PRECISION).div(baseAssetReserveAfter);
|
|
306
300
|
|
|
307
301
|
markPriceAfter = calculatePrice(
|
|
308
302
|
baseAssetReserveAfter,
|
|
@@ -336,7 +330,7 @@ export function calculateTargetPriceTrade(
|
|
|
336
330
|
|
|
337
331
|
const entryPrice = tradeSize
|
|
338
332
|
.mul(AMM_TO_QUOTE_PRECISION_RATIO)
|
|
339
|
-
.mul(
|
|
333
|
+
.mul(PRICE_PRECISION)
|
|
340
334
|
.div(baseSize.abs());
|
|
341
335
|
|
|
342
336
|
assert(tp1.sub(tp2).lte(originalDiff), 'Target Price Calculation incorrect');
|
|
@@ -2,7 +2,7 @@ import { parsePriceData } from '@pythnetwork/client';
|
|
|
2
2
|
import { Connection, PublicKey } from '@solana/web3.js';
|
|
3
3
|
import { OracleClient, OraclePriceData } from './types';
|
|
4
4
|
import { BN } from '@project-serum/anchor';
|
|
5
|
-
import {
|
|
5
|
+
import { PRICE_PRECISION, TEN } from '../constants/numericConstants';
|
|
6
6
|
|
|
7
7
|
export class PythClient implements OracleClient {
|
|
8
8
|
private connection: Connection;
|
|
@@ -38,6 +38,6 @@ export function convertPythPrice(price: number, exponent: number): BN {
|
|
|
38
38
|
exponent = Math.abs(exponent);
|
|
39
39
|
const pythPrecision = TEN.pow(new BN(exponent).abs());
|
|
40
40
|
return new BN(price * Math.pow(10, exponent))
|
|
41
|
-
.mul(
|
|
41
|
+
.mul(PRICE_PRECISION)
|
|
42
42
|
.div(pythPrecision);
|
|
43
43
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { PublicKey } from '@solana/web3.js';
|
|
2
2
|
import { OracleClient, OraclePriceData } from './types';
|
|
3
3
|
import { BN } from '@project-serum/anchor';
|
|
4
|
-
import {
|
|
4
|
+
import { PRICE_PRECISION } from '../constants/numericConstants';
|
|
5
5
|
|
|
6
6
|
export const QUOTE_ORACLE_PRICE_DATA: OraclePriceData = {
|
|
7
|
-
price:
|
|
7
|
+
price: PRICE_PRECISION,
|
|
8
8
|
slot: new BN(0),
|
|
9
9
|
confidence: new BN(1),
|
|
10
10
|
hasSufficientNumberOfDataPoints: true,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { SwitchboardDecimal } from '@switchboard-xyz/switchboard-v2';
|
|
2
2
|
import { Connection, Keypair, PublicKey } from '@solana/web3.js';
|
|
3
3
|
import { BN, Program, Idl, AnchorProvider } from '@project-serum/anchor';
|
|
4
|
-
import {
|
|
4
|
+
import { PRICE_PRECISION, TEN } from '../constants/numericConstants';
|
|
5
5
|
import { OracleClient, OraclePriceData } from './types';
|
|
6
6
|
import { Wallet } from '../wallet';
|
|
7
7
|
import switchboardV2Idl from '../idl/switchboard_v2.json';
|
|
@@ -74,6 +74,6 @@ function getSwitchboardProgram(connection: Connection): Program {
|
|
|
74
74
|
function convertSwitchboardDecimal(switchboardDecimal: SwitchboardDecimal): BN {
|
|
75
75
|
const switchboardPrecision = TEN.pow(new BN(switchboardDecimal.scale));
|
|
76
76
|
return switchboardDecimal.mantissa
|
|
77
|
-
.mul(
|
|
77
|
+
.mul(PRICE_PRECISION)
|
|
78
78
|
.div(switchboardPrecision);
|
|
79
79
|
}
|
package/src/orderParams.ts
CHANGED
|
@@ -1,154 +1,41 @@
|
|
|
1
|
-
import {
|
|
2
|
-
OrderParams,
|
|
3
|
-
OrderTriggerCondition,
|
|
4
|
-
OrderType,
|
|
5
|
-
PositionDirection,
|
|
6
|
-
} from './types';
|
|
1
|
+
import { OptionalOrderParams, OrderTriggerCondition, OrderType } from './types';
|
|
7
2
|
import { BN } from '@project-serum/anchor';
|
|
8
|
-
import { ZERO } from './constants/numericConstants';
|
|
9
3
|
|
|
10
4
|
export function getLimitOrderParams(
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
price: BN,
|
|
15
|
-
reduceOnly: boolean,
|
|
16
|
-
discountToken = false,
|
|
17
|
-
referrer = false,
|
|
18
|
-
userOrderId = 0,
|
|
19
|
-
postOnly = false,
|
|
20
|
-
oraclePriceOffset = ZERO,
|
|
21
|
-
immediateOrCancel = false
|
|
22
|
-
): OrderParams {
|
|
23
|
-
return {
|
|
5
|
+
params: Omit<OptionalOrderParams, 'orderType' | 'marketType'> & { price: BN }
|
|
6
|
+
): OptionalOrderParams {
|
|
7
|
+
return Object.assign({}, params, {
|
|
24
8
|
orderType: OrderType.LIMIT,
|
|
25
|
-
|
|
26
|
-
marketIndex,
|
|
27
|
-
direction,
|
|
28
|
-
quoteAssetAmount: ZERO,
|
|
29
|
-
baseAssetAmount,
|
|
30
|
-
price,
|
|
31
|
-
reduceOnly,
|
|
32
|
-
postOnly,
|
|
33
|
-
immediateOrCancel,
|
|
34
|
-
positionLimit: ZERO,
|
|
35
|
-
padding0: true,
|
|
36
|
-
padding1: ZERO,
|
|
37
|
-
optionalAccounts: {
|
|
38
|
-
discountToken,
|
|
39
|
-
referrer,
|
|
40
|
-
},
|
|
41
|
-
triggerCondition: OrderTriggerCondition.ABOVE,
|
|
42
|
-
triggerPrice: ZERO,
|
|
43
|
-
oraclePriceOffset,
|
|
44
|
-
};
|
|
9
|
+
});
|
|
45
10
|
}
|
|
46
11
|
|
|
47
12
|
export function getTriggerMarketOrderParams(
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
discountToken = false,
|
|
55
|
-
referrer = false,
|
|
56
|
-
userOrderId = 0
|
|
57
|
-
): OrderParams {
|
|
58
|
-
return {
|
|
13
|
+
params: Omit<OptionalOrderParams, 'orderType' | 'marketType'> & {
|
|
14
|
+
triggerCondition: OrderTriggerCondition;
|
|
15
|
+
triggerPrice: BN;
|
|
16
|
+
}
|
|
17
|
+
): OptionalOrderParams {
|
|
18
|
+
return Object.assign({}, params, {
|
|
59
19
|
orderType: OrderType.TRIGGER_MARKET,
|
|
60
|
-
|
|
61
|
-
marketIndex,
|
|
62
|
-
direction,
|
|
63
|
-
quoteAssetAmount: ZERO,
|
|
64
|
-
baseAssetAmount,
|
|
65
|
-
price: ZERO,
|
|
66
|
-
reduceOnly,
|
|
67
|
-
postOnly: false,
|
|
68
|
-
immediateOrCancel: false,
|
|
69
|
-
positionLimit: ZERO,
|
|
70
|
-
padding0: true,
|
|
71
|
-
padding1: ZERO,
|
|
72
|
-
optionalAccounts: {
|
|
73
|
-
discountToken,
|
|
74
|
-
referrer,
|
|
75
|
-
},
|
|
76
|
-
triggerCondition,
|
|
77
|
-
triggerPrice,
|
|
78
|
-
oraclePriceOffset: ZERO,
|
|
79
|
-
};
|
|
20
|
+
});
|
|
80
21
|
}
|
|
81
22
|
|
|
82
23
|
export function getTriggerLimitOrderParams(
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
discountToken = false,
|
|
91
|
-
referrer = false,
|
|
92
|
-
userOrderId = 0
|
|
93
|
-
): OrderParams {
|
|
94
|
-
return {
|
|
24
|
+
params: Omit<OptionalOrderParams, 'orderType' | 'marketType'> & {
|
|
25
|
+
triggerCondition: OrderTriggerCondition;
|
|
26
|
+
triggerPrice: BN;
|
|
27
|
+
price: BN;
|
|
28
|
+
}
|
|
29
|
+
): OptionalOrderParams {
|
|
30
|
+
return Object.assign({}, params, {
|
|
95
31
|
orderType: OrderType.TRIGGER_LIMIT,
|
|
96
|
-
|
|
97
|
-
marketIndex,
|
|
98
|
-
direction,
|
|
99
|
-
quoteAssetAmount: ZERO,
|
|
100
|
-
baseAssetAmount,
|
|
101
|
-
price,
|
|
102
|
-
reduceOnly,
|
|
103
|
-
postOnly: false,
|
|
104
|
-
immediateOrCancel: false,
|
|
105
|
-
positionLimit: ZERO,
|
|
106
|
-
padding0: true,
|
|
107
|
-
padding1: ZERO,
|
|
108
|
-
optionalAccounts: {
|
|
109
|
-
discountToken,
|
|
110
|
-
referrer,
|
|
111
|
-
},
|
|
112
|
-
triggerCondition,
|
|
113
|
-
triggerPrice,
|
|
114
|
-
oraclePriceOffset: ZERO,
|
|
115
|
-
};
|
|
32
|
+
});
|
|
116
33
|
}
|
|
117
34
|
|
|
118
35
|
export function getMarketOrderParams(
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
baseAssetAmount: BN,
|
|
123
|
-
reduceOnly: boolean,
|
|
124
|
-
price = ZERO,
|
|
125
|
-
discountToken = false,
|
|
126
|
-
referrer = false
|
|
127
|
-
): OrderParams {
|
|
128
|
-
if (baseAssetAmount.eq(ZERO) && quoteAssetAmount.eq(ZERO)) {
|
|
129
|
-
throw Error('baseAssetAmount or quoteAssetAmount must be zero');
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
return {
|
|
36
|
+
params: Omit<OptionalOrderParams, 'orderType' | 'marketType'>
|
|
37
|
+
): OptionalOrderParams {
|
|
38
|
+
return Object.assign({}, params, {
|
|
133
39
|
orderType: OrderType.MARKET,
|
|
134
|
-
|
|
135
|
-
marketIndex,
|
|
136
|
-
direction,
|
|
137
|
-
quoteAssetAmount,
|
|
138
|
-
baseAssetAmount,
|
|
139
|
-
price,
|
|
140
|
-
reduceOnly,
|
|
141
|
-
postOnly: false,
|
|
142
|
-
immediateOrCancel: false,
|
|
143
|
-
positionLimit: ZERO,
|
|
144
|
-
padding0: true,
|
|
145
|
-
padding1: ZERO,
|
|
146
|
-
optionalAccounts: {
|
|
147
|
-
discountToken,
|
|
148
|
-
referrer,
|
|
149
|
-
},
|
|
150
|
-
triggerCondition: OrderTriggerCondition.ABOVE,
|
|
151
|
-
triggerPrice: ZERO,
|
|
152
|
-
oraclePriceOffset: ZERO,
|
|
153
|
-
};
|
|
40
|
+
});
|
|
154
41
|
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { Connection, PublicKey } from '@solana/web3.js';
|
|
2
|
+
import { BulkAccountLoader } from '../accounts/bulkAccountLoader';
|
|
3
|
+
import { Market, Orderbook } from '@project-serum/serum';
|
|
4
|
+
import { SerumMarketSubscriberConfig } from './types';
|
|
5
|
+
|
|
6
|
+
export class SerumSubscriber {
|
|
7
|
+
connection: Connection;
|
|
8
|
+
programId: PublicKey;
|
|
9
|
+
marketAddress: PublicKey;
|
|
10
|
+
accountLoader: BulkAccountLoader;
|
|
11
|
+
market: Market;
|
|
12
|
+
|
|
13
|
+
subscribed: boolean;
|
|
14
|
+
|
|
15
|
+
asksAddress: PublicKey;
|
|
16
|
+
asks: Orderbook;
|
|
17
|
+
asksCallbackId: string;
|
|
18
|
+
lastAsksSlot: number;
|
|
19
|
+
|
|
20
|
+
bidsAddress: PublicKey;
|
|
21
|
+
bids: Orderbook;
|
|
22
|
+
bidsCallbackId: string;
|
|
23
|
+
lastBidsSlot: number;
|
|
24
|
+
|
|
25
|
+
public constructor(config: SerumMarketSubscriberConfig) {
|
|
26
|
+
this.connection = config.connection;
|
|
27
|
+
this.programId = config.programId;
|
|
28
|
+
this.marketAddress = config.marketAddress;
|
|
29
|
+
this.accountLoader = config.accountSubscription.accountLoader;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
public async subscribe(): Promise<void> {
|
|
33
|
+
if (this.subscribed) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
this.market = await Market.load(
|
|
38
|
+
this.connection,
|
|
39
|
+
this.marketAddress,
|
|
40
|
+
undefined,
|
|
41
|
+
this.programId
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
this.asksAddress = this.market.asksAddress;
|
|
45
|
+
this.asks = await this.market.loadAsks(this.connection);
|
|
46
|
+
|
|
47
|
+
this.asksCallbackId = this.accountLoader.addAccount(
|
|
48
|
+
this.asksAddress,
|
|
49
|
+
(buffer, slot) => {
|
|
50
|
+
this.lastAsksSlot = slot;
|
|
51
|
+
this.asks = Orderbook.decode(this.market, buffer);
|
|
52
|
+
console.log(this.asks.getL2(3));
|
|
53
|
+
}
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
this.bidsAddress = this.market.bidsAddress;
|
|
57
|
+
this.bids = await this.market.loadBids(this.connection);
|
|
58
|
+
|
|
59
|
+
this.bidsCallbackId = this.accountLoader.addAccount(
|
|
60
|
+
this.bidsAddress,
|
|
61
|
+
(buffer, slot) => {
|
|
62
|
+
this.lastBidsSlot = slot;
|
|
63
|
+
this.bids = Orderbook.decode(this.market, buffer);
|
|
64
|
+
}
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
this.subscribed = true;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
public async unsubscribe(): Promise<void> {
|
|
71
|
+
if (!this.subscribed) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
this.accountLoader.removeAccount(this.asksAddress, this.asksCallbackId);
|
|
76
|
+
this.accountLoader.removeAccount(this.bidsAddress, this.bidsCallbackId);
|
|
77
|
+
|
|
78
|
+
this.subscribed = false;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Connection, PublicKey } from '@solana/web3.js';
|
|
2
|
+
import { BulkAccountLoader } from '../accounts/bulkAccountLoader';
|
|
3
|
+
|
|
4
|
+
export type SerumMarketSubscriberConfig = {
|
|
5
|
+
connection: Connection;
|
|
6
|
+
programId: PublicKey;
|
|
7
|
+
marketAddress: PublicKey;
|
|
8
|
+
accountSubscription: {
|
|
9
|
+
// enables use to add web sockets in the future
|
|
10
|
+
type: 'polling';
|
|
11
|
+
accountLoader: BulkAccountLoader;
|
|
12
|
+
};
|
|
13
|
+
};
|
|
@@ -1,22 +1,32 @@
|
|
|
1
1
|
import { Connection } from '@solana/web3.js';
|
|
2
|
+
import { EventEmitter } from 'events';
|
|
3
|
+
import StrictEventEmitter from 'strict-event-emitter-types/types/src';
|
|
2
4
|
|
|
3
5
|
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
4
6
|
type SlotSubscriberConfig = {}; // for future customization
|
|
5
7
|
|
|
8
|
+
export interface SlotSubscriberEvents {
|
|
9
|
+
newSlot: (newSlot: number) => void;
|
|
10
|
+
}
|
|
11
|
+
|
|
6
12
|
export class SlotSubscriber {
|
|
7
13
|
currentSlot: number;
|
|
8
14
|
subscriptionId: number;
|
|
15
|
+
eventEmitter: StrictEventEmitter<EventEmitter, SlotSubscriberEvents>;
|
|
9
16
|
|
|
10
17
|
public constructor(
|
|
11
18
|
private connection: Connection,
|
|
12
19
|
_config?: SlotSubscriberConfig
|
|
13
|
-
) {
|
|
20
|
+
) {
|
|
21
|
+
this.eventEmitter = new EventEmitter();
|
|
22
|
+
}
|
|
14
23
|
|
|
15
24
|
public async subscribe(): Promise<void> {
|
|
16
25
|
this.currentSlot = await this.connection.getSlot('confirmed');
|
|
17
26
|
|
|
18
27
|
this.subscriptionId = this.connection.onSlotChange((slotInfo) => {
|
|
19
28
|
this.currentSlot = slotInfo.slot;
|
|
29
|
+
this.eventEmitter.emit('newSlot', slotInfo.slot);
|
|
20
30
|
});
|
|
21
31
|
}
|
|
22
32
|
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseTokenAccount = void 0;
|
|
4
|
+
const spl_token_1 = require("@solana/spl-token");
|
|
5
|
+
const web3_js_1 = require("@solana/web3.js");
|
|
6
|
+
function parseTokenAccount(data) {
|
|
7
|
+
const accountInfo = spl_token_1.AccountLayout.decode(data);
|
|
8
|
+
accountInfo.mint = new web3_js_1.PublicKey(accountInfo.mint);
|
|
9
|
+
accountInfo.owner = new web3_js_1.PublicKey(accountInfo.owner);
|
|
10
|
+
accountInfo.amount = spl_token_1.u64.fromBuffer(accountInfo.amount);
|
|
11
|
+
if (accountInfo.delegateOption === 0) {
|
|
12
|
+
accountInfo.delegate = null;
|
|
13
|
+
// eslint-disable-next-line new-cap
|
|
14
|
+
accountInfo.delegatedAmount = new spl_token_1.u64(0);
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
accountInfo.delegate = new web3_js_1.PublicKey(accountInfo.delegate);
|
|
18
|
+
accountInfo.delegatedAmount = spl_token_1.u64.fromBuffer(accountInfo.delegatedAmount);
|
|
19
|
+
}
|
|
20
|
+
accountInfo.isInitialized = accountInfo.state !== 0;
|
|
21
|
+
accountInfo.isFrozen = accountInfo.state === 2;
|
|
22
|
+
if (accountInfo.isNativeOption === 1) {
|
|
23
|
+
accountInfo.rentExemptReserve = spl_token_1.u64.fromBuffer(accountInfo.isNative);
|
|
24
|
+
accountInfo.isNative = true;
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
accountInfo.rentExemptReserve = null;
|
|
28
|
+
accountInfo.isNative = false;
|
|
29
|
+
}
|
|
30
|
+
if (accountInfo.closeAuthorityOption === 0) {
|
|
31
|
+
accountInfo.closeAuthority = null;
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
accountInfo.closeAuthority = new web3_js_1.PublicKey(accountInfo.closeAuthority);
|
|
35
|
+
}
|
|
36
|
+
return accountInfo;
|
|
37
|
+
}
|
|
38
|
+
exports.parseTokenAccount = parseTokenAccount;
|