@drift-labs/sdk 0.1.36-master.7 → 0.2.0-master.0
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.d.ts +6 -6
- package/lib/accounts/bulkAccountLoader.js +81 -95
- package/lib/accounts/bulkUserSubscription.js +13 -57
- package/lib/accounts/fetch.d.ts +4 -0
- package/lib/accounts/fetch.js +18 -0
- package/lib/accounts/pollingClearingHouseAccountSubscriber.d.ts +34 -38
- package/lib/accounts/pollingClearingHouseAccountSubscriber.js +224 -224
- package/lib/accounts/pollingOracleSubscriber.d.ts +3 -3
- package/lib/accounts/pollingOracleSubscriber.js +37 -49
- package/lib/accounts/pollingTokenAccountSubscriber.d.ts +3 -3
- package/lib/accounts/pollingTokenAccountSubscriber.js +35 -50
- package/lib/accounts/pollingUserAccountSubscriber.d.ts +7 -13
- package/lib/accounts/pollingUserAccountSubscriber.js +71 -134
- package/lib/accounts/types.d.ts +34 -41
- package/lib/accounts/webSocketAccountSubscriber.d.ts +6 -4
- package/lib/accounts/webSocketAccountSubscriber.js +39 -35
- package/lib/accounts/webSocketClearingHouseAccountSubscriber.d.ts +33 -28
- package/lib/accounts/webSocketClearingHouseAccountSubscriber.js +153 -185
- package/lib/accounts/webSocketUserAccountSubscriber.d.ts +5 -11
- package/lib/accounts/webSocketUserAccountSubscriber.js +22 -67
- package/lib/addresses/marketAddresses.d.ts +4 -0
- package/lib/addresses/marketAddresses.js +15 -0
- package/lib/addresses/pda.d.ts +12 -0
- package/lib/addresses/pda.js +83 -0
- package/lib/admin.d.ts +8 -17
- package/lib/admin.js +366 -558
- package/lib/clearingHouse.d.ts +84 -109
- package/lib/clearingHouse.js +778 -899
- package/lib/clearingHouseConfig.d.ts +34 -0
- package/lib/clearingHouseConfig.js +2 -0
- package/lib/clearingHouseUser.d.ts +19 -22
- package/lib/clearingHouseUser.js +155 -141
- package/lib/clearingHouseUserConfig.d.ts +14 -0
- package/lib/clearingHouseUserConfig.js +2 -0
- package/lib/config.d.ts +12 -0
- package/lib/config.js +35 -4
- package/lib/constants/banks.d.ts +16 -0
- package/lib/constants/banks.js +34 -0
- package/lib/constants/markets.d.ts +8 -3
- package/lib/constants/markets.js +13 -206
- package/lib/constants/numericConstants.d.ts +16 -0
- package/lib/constants/numericConstants.js +22 -6
- package/lib/events/eventList.d.ts +22 -0
- package/lib/events/eventList.js +77 -0
- package/lib/events/eventSubscriber.d.ts +34 -0
- package/lib/events/eventSubscriber.js +126 -0
- package/lib/events/fetchLogs.d.ts +13 -0
- package/lib/events/fetchLogs.js +39 -0
- package/lib/events/pollingLogProvider.d.ts +15 -0
- package/lib/events/pollingLogProvider.js +53 -0
- package/lib/events/sort.d.ts +2 -0
- package/lib/events/sort.js +44 -0
- package/lib/events/txEventCache.d.ts +24 -0
- package/lib/events/txEventCache.js +71 -0
- package/lib/events/types.d.ts +49 -0
- package/lib/events/types.js +20 -0
- package/lib/events/webSocketLogProvider.d.ts +12 -0
- package/lib/events/webSocketLogProvider.js +30 -0
- package/lib/examples/makeTradeExample.js +26 -27
- package/lib/factory/bigNum.d.ts +112 -0
- package/lib/factory/bigNum.js +356 -0
- package/lib/factory/oracleClient.d.ts +1 -2
- package/lib/factory/oracleClient.js +6 -2
- package/lib/idl/clearing_house.json +2213 -2951
- package/lib/index.d.ts +12 -4
- package/lib/index.js +12 -4
- package/lib/math/amm.d.ts +19 -29
- package/lib/math/amm.js +129 -179
- package/lib/math/auction.d.ts +5 -0
- package/lib/math/auction.js +39 -0
- package/lib/math/bankBalance.d.ts +9 -0
- package/lib/math/bankBalance.js +75 -0
- package/lib/math/conversion.d.ts +0 -1
- package/lib/math/conversion.js +1 -5
- package/lib/math/funding.d.ts +6 -6
- package/lib/math/funding.js +158 -175
- package/lib/math/market.d.ts +6 -6
- package/lib/math/market.js +10 -9
- package/lib/math/orders.d.ts +5 -0
- package/lib/math/orders.js +31 -1
- package/lib/math/position.d.ts +7 -5
- package/lib/math/position.js +27 -27
- package/lib/math/repeg.d.ts +22 -0
- package/lib/math/repeg.js +128 -0
- package/lib/math/trade.d.ts +5 -4
- package/lib/math/trade.js +29 -21
- package/lib/mockUSDCFaucet.js +87 -116
- package/lib/oracles/oracleClientCache.d.ts +8 -0
- package/lib/oracles/oracleClientCache.js +19 -0
- package/lib/oracles/pythClient.d.ts +3 -5
- package/lib/oracles/pythClient.js +12 -31
- package/lib/oracles/quoteAssetOracleClient.d.ts +9 -0
- package/lib/oracles/quoteAssetOracleClient.js +21 -0
- package/lib/oracles/switchboardClient.d.ts +3 -5
- package/lib/oracles/switchboardClient.js +29 -50
- package/lib/oracles/types.d.ts +6 -1
- package/lib/orders.d.ts +6 -6
- package/lib/orders.js +10 -9
- package/lib/slot/SlotSubscriber.d.ts +12 -0
- package/lib/slot/SlotSubscriber.js +23 -0
- package/lib/tx/retryTxSender.d.ts +2 -2
- package/lib/tx/retryTxSender.js +108 -123
- package/lib/tx/types.d.ts +5 -1
- package/lib/tx/utils.d.ts +1 -1
- package/lib/tx/utils.js +11 -2
- package/lib/types.d.ts +105 -109
- package/lib/types.js +13 -1
- package/lib/userName.d.ts +4 -0
- package/lib/userName.js +20 -0
- package/lib/util/computeUnits.js +10 -21
- package/lib/util/tps.js +11 -22
- package/lib/wallet.js +7 -20
- package/package.json +10 -3
- package/src/accounts/bulkAccountLoader.ts +21 -15
- package/src/accounts/bulkUserSubscription.ts +1 -45
- package/src/accounts/fetch.ts +33 -0
- package/src/accounts/pollingClearingHouseAccountSubscriber.ts +249 -214
- package/src/accounts/pollingOracleSubscriber.ts +16 -8
- package/src/accounts/pollingTokenAccountSubscriber.ts +11 -8
- package/src/accounts/pollingUserAccountSubscriber.ts +21 -86
- package/src/accounts/types.ts +41 -70
- package/src/accounts/webSocketAccountSubscriber.ts +33 -16
- package/src/accounts/webSocketClearingHouseAccountSubscriber.ts +190 -240
- package/src/accounts/webSocketUserAccountSubscriber.ts +11 -71
- package/src/addresses/marketAddresses.ts +18 -0
- package/src/addresses/pda.ts +118 -0
- package/src/admin.ts +205 -346
- package/src/clearingHouse.ts +918 -961
- package/src/clearingHouseConfig.ts +37 -0
- package/src/clearingHouseUser.ts +275 -185
- package/src/clearingHouseUserConfig.ts +18 -0
- package/src/config.ts +54 -1
- package/src/constants/banks.ts +43 -0
- package/src/constants/markets.ts +16 -207
- package/src/constants/numericConstants.ts +33 -5
- package/src/events/eventList.ts +94 -0
- package/src/events/eventSubscriber.ts +194 -0
- package/src/events/fetchLogs.ts +80 -0
- package/src/events/pollingLogProvider.ts +79 -0
- package/src/events/sort.ts +65 -0
- package/src/events/txEventCache.ts +74 -0
- package/src/events/types.ts +98 -0
- package/src/events/webSocketLogProvider.ts +38 -0
- package/src/examples/makeTradeExample.ts +20 -11
- package/src/factory/bigNum.ts +507 -0
- package/src/factory/oracleClient.ts +7 -4
- package/src/idl/clearing_house.json +2213 -2951
- package/src/index.ts +12 -4
- package/src/math/amm.ts +229 -245
- package/src/math/auction.ts +39 -0
- package/src/math/bankBalance.ts +112 -0
- package/src/math/conversion.ts +1 -11
- package/src/math/funding.ts +12 -9
- package/src/math/market.ts +37 -30
- package/src/math/orders.ts +38 -0
- package/src/math/position.ts +48 -35
- package/src/math/repeg.ts +175 -0
- package/src/math/trade.ts +45 -35
- package/src/math/utils.js +27 -0
- package/src/math/utils.js.map +1 -0
- package/src/oracles/oracleClientCache.ts +20 -0
- package/src/oracles/pythClient.ts +4 -11
- package/src/oracles/quoteAssetOracleClient.ts +25 -0
- package/src/oracles/switchboardClient.ts +11 -24
- package/src/oracles/types.ts +7 -1
- package/src/orders.ts +35 -20
- package/src/slot/SlotSubscriber.ts +32 -0
- package/src/tx/retryTxSender.ts +6 -4
- package/src/tx/types.ts +6 -1
- package/src/tx/utils.ts +22 -3
- package/src/types.ts +108 -122
- package/src/userName.ts +20 -0
- package/src/util/computeUnits.js +17 -0
- package/src/util/computeUnits.js.map +1 -0
- package/tests/bn/test.ts +255 -0
- package/tsconfig.json +12 -12
- package/lib/addresses.d.ts +0 -10
- package/lib/addresses.js +0 -93
- package/lib/constants/accounts.d.ts +0 -15
- package/lib/constants/accounts.js +0 -18
- package/lib/factory/clearingHouse.d.ts +0 -35
- package/lib/factory/clearingHouse.js +0 -81
- package/lib/factory/clearingHouseUser.d.ts +0 -19
- package/lib/factory/clearingHouseUser.js +0 -34
- package/lib/math/insuranceFund.d.ts +0 -15
- package/lib/math/insuranceFund.js +0 -33
- package/lib/settlement.d.ts +0 -4
- package/lib/settlement.js +0 -10
- package/lib/tx/defaultTxSender.d.ts +0 -8
- package/lib/tx/defaultTxSender.js +0 -12
- package/src/addresses.ts +0 -82
- package/src/constants/accounts.ts +0 -26
- package/src/factory/clearingHouse.ts +0 -173
- package/src/factory/clearingHouseUser.ts +0 -73
- package/src/math/insuranceFund.ts +0 -29
- package/src/settlement.ts +0 -9
- package/src/tx/defaultTxSender.ts +0 -24
package/src/math/trade.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { MarketAccount, PositionDirection, SwapDirection } from '../types';
|
|
2
2
|
import { BN } from '@project-serum/anchor';
|
|
3
3
|
import { assert } from '../assert/assert';
|
|
4
4
|
import {
|
|
@@ -17,10 +17,12 @@ import {
|
|
|
17
17
|
calculatePrice,
|
|
18
18
|
getSwapDirection,
|
|
19
19
|
AssetType,
|
|
20
|
-
|
|
20
|
+
calculateUpdatedAMMSpreadReserves,
|
|
21
|
+
calculateQuoteAssetAmountSwapped,
|
|
21
22
|
} from './amm';
|
|
22
23
|
import { squareRootBN } from './utils';
|
|
23
24
|
import { isVariant } from '../types';
|
|
25
|
+
import { OraclePriceData } from '../oracles/types';
|
|
24
26
|
|
|
25
27
|
const MAXPCT = new BN(1000); //percentage units are [0,1000] => [0,1]
|
|
26
28
|
|
|
@@ -57,20 +59,21 @@ export type PriceImpactUnit =
|
|
|
57
59
|
export function calculateTradeSlippage(
|
|
58
60
|
direction: PositionDirection,
|
|
59
61
|
amount: BN,
|
|
60
|
-
market:
|
|
62
|
+
market: MarketAccount,
|
|
61
63
|
inputAssetType: AssetType = 'quote',
|
|
64
|
+
oraclePriceData?: OraclePriceData,
|
|
62
65
|
useSpread = true
|
|
63
66
|
): [BN, BN, BN, BN] {
|
|
64
67
|
let oldPrice: BN;
|
|
65
68
|
|
|
66
69
|
if (useSpread && market.amm.baseSpread > 0) {
|
|
67
70
|
if (isVariant(direction, 'long')) {
|
|
68
|
-
oldPrice = calculateAskPrice(market);
|
|
71
|
+
oldPrice = calculateAskPrice(market, oraclePriceData);
|
|
69
72
|
} else {
|
|
70
|
-
oldPrice = calculateBidPrice(market);
|
|
73
|
+
oldPrice = calculateBidPrice(market, oraclePriceData);
|
|
71
74
|
}
|
|
72
75
|
} else {
|
|
73
|
-
oldPrice = calculateMarkPrice(market);
|
|
76
|
+
oldPrice = calculateMarkPrice(market, oraclePriceData);
|
|
74
77
|
}
|
|
75
78
|
if (amount.eq(ZERO)) {
|
|
76
79
|
return [ZERO, ZERO, oldPrice, oldPrice];
|
|
@@ -80,26 +83,33 @@ export function calculateTradeSlippage(
|
|
|
80
83
|
amount,
|
|
81
84
|
market,
|
|
82
85
|
inputAssetType,
|
|
86
|
+
oraclePriceData,
|
|
83
87
|
useSpread
|
|
84
88
|
);
|
|
85
89
|
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
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
|
+
);
|
|
98
|
+
|
|
99
|
+
const entryPrice = quoteAssetAmountAcquired
|
|
100
|
+
.mul(AMM_TO_QUOTE_PRECISION_RATIO)
|
|
101
|
+
.mul(MARK_PRICE_PRECISION)
|
|
102
|
+
.div(acquiredBase.abs());
|
|
91
103
|
|
|
92
104
|
let amm: Parameters<typeof calculateAmmReservesAfterSwap>[0];
|
|
93
105
|
if (useSpread && market.amm.baseSpread > 0) {
|
|
94
|
-
const { baseAssetReserve, quoteAssetReserve } =
|
|
95
|
-
market.amm,
|
|
96
|
-
direction
|
|
97
|
-
);
|
|
106
|
+
const { baseAssetReserve, quoteAssetReserve, sqrtK, newPeg } =
|
|
107
|
+
calculateUpdatedAMMSpreadReserves(market.amm, direction, oraclePriceData);
|
|
98
108
|
amm = {
|
|
99
109
|
baseAssetReserve,
|
|
100
110
|
quoteAssetReserve,
|
|
101
|
-
sqrtK:
|
|
102
|
-
pegMultiplier:
|
|
111
|
+
sqrtK: sqrtK,
|
|
112
|
+
pegMultiplier: newPeg,
|
|
103
113
|
};
|
|
104
114
|
} else {
|
|
105
115
|
amm = market.amm;
|
|
@@ -112,9 +122,9 @@ export function calculateTradeSlippage(
|
|
|
112
122
|
);
|
|
113
123
|
|
|
114
124
|
if (direction == PositionDirection.SHORT) {
|
|
115
|
-
assert(newPrice.
|
|
125
|
+
assert(newPrice.lte(oldPrice));
|
|
116
126
|
} else {
|
|
117
|
-
assert(oldPrice.
|
|
127
|
+
assert(oldPrice.lte(newPrice));
|
|
118
128
|
}
|
|
119
129
|
|
|
120
130
|
const pctMaxSlippage = newPrice
|
|
@@ -145,8 +155,9 @@ export function calculateTradeSlippage(
|
|
|
145
155
|
export function calculateTradeAcquiredAmounts(
|
|
146
156
|
direction: PositionDirection,
|
|
147
157
|
amount: BN,
|
|
148
|
-
market:
|
|
158
|
+
market: MarketAccount,
|
|
149
159
|
inputAssetType: AssetType = 'quote',
|
|
160
|
+
oraclePriceData: OraclePriceData,
|
|
150
161
|
useSpread = true
|
|
151
162
|
): [BN, BN] {
|
|
152
163
|
if (amount.eq(ZERO)) {
|
|
@@ -157,15 +168,13 @@ export function calculateTradeAcquiredAmounts(
|
|
|
157
168
|
|
|
158
169
|
let amm: Parameters<typeof calculateAmmReservesAfterSwap>[0];
|
|
159
170
|
if (useSpread && market.amm.baseSpread > 0) {
|
|
160
|
-
const { baseAssetReserve, quoteAssetReserve } =
|
|
161
|
-
market.amm,
|
|
162
|
-
direction
|
|
163
|
-
);
|
|
171
|
+
const { baseAssetReserve, quoteAssetReserve, sqrtK, newPeg } =
|
|
172
|
+
calculateUpdatedAMMSpreadReserves(market.amm, direction, oraclePriceData);
|
|
164
173
|
amm = {
|
|
165
174
|
baseAssetReserve,
|
|
166
175
|
quoteAssetReserve,
|
|
167
|
-
sqrtK:
|
|
168
|
-
pegMultiplier:
|
|
176
|
+
sqrtK: sqrtK,
|
|
177
|
+
pegMultiplier: newPeg,
|
|
169
178
|
};
|
|
170
179
|
} else {
|
|
171
180
|
amm = market.amm;
|
|
@@ -197,19 +206,20 @@ export function calculateTradeAcquiredAmounts(
|
|
|
197
206
|
* ]
|
|
198
207
|
*/
|
|
199
208
|
export function calculateTargetPriceTrade(
|
|
200
|
-
market:
|
|
209
|
+
market: MarketAccount,
|
|
201
210
|
targetPrice: BN,
|
|
202
211
|
pct: BN = MAXPCT,
|
|
203
212
|
outputAssetType: AssetType = 'quote',
|
|
213
|
+
oraclePriceData?: OraclePriceData,
|
|
204
214
|
useSpread = true
|
|
205
215
|
): [PositionDirection, BN, BN, BN] {
|
|
206
216
|
assert(market.amm.baseAssetReserve.gt(ZERO));
|
|
207
217
|
assert(targetPrice.gt(ZERO));
|
|
208
218
|
assert(pct.lte(MAXPCT) && pct.gt(ZERO));
|
|
209
219
|
|
|
210
|
-
const markPriceBefore = calculateMarkPrice(market);
|
|
211
|
-
const bidPriceBefore = calculateBidPrice(market);
|
|
212
|
-
const askPriceBefore = calculateAskPrice(market);
|
|
220
|
+
const markPriceBefore = calculateMarkPrice(market, oraclePriceData);
|
|
221
|
+
const bidPriceBefore = calculateBidPrice(market, oraclePriceData);
|
|
222
|
+
const askPriceBefore = calculateAskPrice(market, oraclePriceData);
|
|
213
223
|
|
|
214
224
|
let direction;
|
|
215
225
|
if (targetPrice.gt(markPriceBefore)) {
|
|
@@ -230,19 +240,19 @@ export function calculateTargetPriceTrade(
|
|
|
230
240
|
let baseAssetReserveBefore: BN;
|
|
231
241
|
let quoteAssetReserveBefore: BN;
|
|
232
242
|
|
|
243
|
+
let peg = market.amm.pegMultiplier;
|
|
244
|
+
|
|
233
245
|
if (useSpread && market.amm.baseSpread > 0) {
|
|
234
|
-
const { baseAssetReserve, quoteAssetReserve } =
|
|
235
|
-
market.amm,
|
|
236
|
-
direction
|
|
237
|
-
);
|
|
246
|
+
const { baseAssetReserve, quoteAssetReserve, newPeg } =
|
|
247
|
+
calculateUpdatedAMMSpreadReserves(market.amm, direction, oraclePriceData);
|
|
238
248
|
baseAssetReserveBefore = baseAssetReserve;
|
|
239
249
|
quoteAssetReserveBefore = quoteAssetReserve;
|
|
250
|
+
peg = newPeg;
|
|
240
251
|
} else {
|
|
241
252
|
baseAssetReserveBefore = market.amm.baseAssetReserve;
|
|
242
253
|
quoteAssetReserveBefore = market.amm.quoteAssetReserve;
|
|
243
254
|
}
|
|
244
255
|
|
|
245
|
-
const peg = market.amm.pegMultiplier;
|
|
246
256
|
const invariant = market.amm.sqrtK.mul(market.amm.sqrtK);
|
|
247
257
|
const k = invariant.mul(MARK_PRICE_PRECISION);
|
|
248
258
|
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.squareRootBN = void 0;
|
|
4
|
+
const __1 = require("../");
|
|
5
|
+
const squareRootBN = (n, closeness = new __1.BN(1)) => {
|
|
6
|
+
// Assuming the sqrt of n as n only
|
|
7
|
+
let x = n;
|
|
8
|
+
// The closed guess will be stored in the root
|
|
9
|
+
let root;
|
|
10
|
+
// To count the number of iterations
|
|
11
|
+
let count = 0;
|
|
12
|
+
const TWO = new __1.BN(2);
|
|
13
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
14
|
+
while (count < Number.MAX_SAFE_INTEGER) {
|
|
15
|
+
count++;
|
|
16
|
+
// Calculate more closed x
|
|
17
|
+
root = x.add(n.div(x)).div(TWO);
|
|
18
|
+
// Check for closeness
|
|
19
|
+
if (x.sub(root).abs().lte(closeness))
|
|
20
|
+
break;
|
|
21
|
+
// Update root
|
|
22
|
+
x = root;
|
|
23
|
+
}
|
|
24
|
+
return root;
|
|
25
|
+
};
|
|
26
|
+
exports.squareRootBN = squareRootBN;
|
|
27
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["utils.ts"],"names":[],"mappings":";;;AAAA,2BAAyB;AAElB,MAAM,YAAY,GAAG,CAAC,CAAC,EAAE,SAAS,GAAG,IAAI,MAAE,CAAC,CAAC,CAAC,EAAE,EAAE;IACxD,mCAAmC;IACnC,IAAI,CAAC,GAAG,CAAC,CAAC;IAEV,8CAA8C;IAC9C,IAAI,IAAI,CAAC;IAET,oCAAoC;IACpC,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,MAAM,GAAG,GAAG,IAAI,MAAE,CAAC,CAAC,CAAC,CAAC;IAEtB,6DAA6D;IAC7D,OAAO,KAAK,GAAG,MAAM,CAAC,gBAAgB,EAAE;QACvC,KAAK,EAAE,CAAC;QAER,0BAA0B;QAC1B,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAEhC,sBAAsB;QACtB,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC;YAAE,MAAM;QAE5C,cAAc;QACd,CAAC,GAAG,IAAI,CAAC;KACT;IAED,OAAO,IAAI,CAAC;AACb,CAAC,CAAC;AA1BW,QAAA,YAAY,gBA0BvB"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { OracleClient } from './types';
|
|
2
|
+
import { OracleSource } from '../types';
|
|
3
|
+
import { getOracleClient } from '../factory/oracleClient';
|
|
4
|
+
import { Connection } from '@solana/web3.js';
|
|
5
|
+
|
|
6
|
+
export class OracleClientCache {
|
|
7
|
+
cache = new Map<string, OracleClient>();
|
|
8
|
+
public constructor() {}
|
|
9
|
+
|
|
10
|
+
public get(oracleSource: OracleSource, connection: Connection) {
|
|
11
|
+
const key = Object.keys(oracleSource)[0];
|
|
12
|
+
if (this.cache.has(key)) {
|
|
13
|
+
return this.cache.get(key);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const client = getOracleClient(oracleSource, connection);
|
|
17
|
+
this.cache.set(key, client);
|
|
18
|
+
return client;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -1,21 +1,16 @@
|
|
|
1
|
-
import { parsePriceData
|
|
1
|
+
import { parsePriceData } from '@pythnetwork/client';
|
|
2
2
|
import { Connection, PublicKey } from '@solana/web3.js';
|
|
3
|
-
import { OraclePriceData } from './types';
|
|
3
|
+
import { OracleClient, OraclePriceData } from './types';
|
|
4
4
|
import { BN } from '@project-serum/anchor';
|
|
5
5
|
import { MARK_PRICE_PRECISION, TEN } from '../constants/numericConstants';
|
|
6
6
|
|
|
7
|
-
export class PythClient {
|
|
7
|
+
export class PythClient implements OracleClient {
|
|
8
8
|
private connection: Connection;
|
|
9
9
|
|
|
10
10
|
public constructor(connection: Connection) {
|
|
11
11
|
this.connection = connection;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
public async getPriceData(pricePublicKey: PublicKey): Promise<PriceData> {
|
|
15
|
-
const account = await this.connection.getAccountInfo(pricePublicKey);
|
|
16
|
-
return parsePriceData(account.data);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
14
|
public async getOraclePriceData(
|
|
20
15
|
pricePublicKey: PublicKey
|
|
21
16
|
): Promise<OraclePriceData> {
|
|
@@ -23,9 +18,7 @@ export class PythClient {
|
|
|
23
18
|
return this.getOraclePriceDataFromBuffer(accountInfo.data);
|
|
24
19
|
}
|
|
25
20
|
|
|
26
|
-
public
|
|
27
|
-
buffer: Buffer
|
|
28
|
-
): Promise<OraclePriceData> {
|
|
21
|
+
public getOraclePriceDataFromBuffer(buffer: Buffer): OraclePriceData {
|
|
29
22
|
const priceData = parsePriceData(buffer);
|
|
30
23
|
return {
|
|
31
24
|
price: convertPythPrice(priceData.aggregate.price, priceData.exponent),
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { PublicKey } from '@solana/web3.js';
|
|
2
|
+
import { OracleClient, OraclePriceData } from './types';
|
|
3
|
+
import { BN } from '@project-serum/anchor';
|
|
4
|
+
import { MARK_PRICE_PRECISION } from '../constants/numericConstants';
|
|
5
|
+
|
|
6
|
+
export const QUOTE_ORACLE_PRICE_DATA: OraclePriceData = {
|
|
7
|
+
price: MARK_PRICE_PRECISION,
|
|
8
|
+
slot: new BN(0),
|
|
9
|
+
confidence: new BN(1),
|
|
10
|
+
hasSufficientNumberOfDataPoints: true,
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export class QuoteAssetOracleClient implements OracleClient {
|
|
14
|
+
public constructor() {}
|
|
15
|
+
|
|
16
|
+
public async getOraclePriceData(
|
|
17
|
+
_pricePublicKey: PublicKey
|
|
18
|
+
): Promise<OraclePriceData> {
|
|
19
|
+
return Promise.resolve(QUOTE_ORACLE_PRICE_DATA);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
public getOraclePriceDataFromBuffer(_buffer: Buffer): OraclePriceData {
|
|
23
|
+
return QUOTE_ORACLE_PRICE_DATA;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -1,25 +1,18 @@
|
|
|
1
|
-
import {
|
|
2
|
-
getSwitchboardPid,
|
|
3
|
-
SwitchboardDecimal,
|
|
4
|
-
} from '@switchboard-xyz/switchboard-v2';
|
|
1
|
+
import { SwitchboardDecimal } from '@switchboard-xyz/switchboard-v2';
|
|
5
2
|
import { Connection, Keypair, PublicKey } from '@solana/web3.js';
|
|
6
|
-
import { DriftEnv } from '../config';
|
|
7
3
|
import { BN, Program, Idl, AnchorProvider } from '@project-serum/anchor';
|
|
8
4
|
import { MARK_PRICE_PRECISION, TEN } from '../constants/numericConstants';
|
|
9
5
|
import { OracleClient, OraclePriceData } from './types';
|
|
10
6
|
import { Wallet } from '../wallet';
|
|
11
7
|
import switchboardV2Idl from '../idl/switchboard_v2.json';
|
|
12
8
|
|
|
13
|
-
|
|
14
|
-
const programMap = new Map<string, Program>();
|
|
9
|
+
let program: Program | undefined;
|
|
15
10
|
|
|
16
11
|
export class SwitchboardClient implements OracleClient {
|
|
17
12
|
connection: Connection;
|
|
18
|
-
env: DriftEnv;
|
|
19
13
|
|
|
20
|
-
public constructor(connection: Connection
|
|
14
|
+
public constructor(connection: Connection) {
|
|
21
15
|
this.connection = connection;
|
|
22
|
-
this.env = env;
|
|
23
16
|
}
|
|
24
17
|
|
|
25
18
|
public async getOraclePriceData(
|
|
@@ -29,10 +22,8 @@ export class SwitchboardClient implements OracleClient {
|
|
|
29
22
|
return this.getOraclePriceDataFromBuffer(accountInfo.data);
|
|
30
23
|
}
|
|
31
24
|
|
|
32
|
-
public
|
|
33
|
-
|
|
34
|
-
): Promise<OraclePriceData> {
|
|
35
|
-
const program = await this.getProgram();
|
|
25
|
+
public getOraclePriceDataFromBuffer(buffer: Buffer): OraclePriceData {
|
|
26
|
+
const program = this.getProgram();
|
|
36
27
|
|
|
37
28
|
const aggregatorAccountData =
|
|
38
29
|
program.account.aggregatorAccountData.coder.accounts.decode(
|
|
@@ -61,23 +52,19 @@ export class SwitchboardClient implements OracleClient {
|
|
|
61
52
|
};
|
|
62
53
|
}
|
|
63
54
|
|
|
64
|
-
public
|
|
65
|
-
if (
|
|
66
|
-
return
|
|
55
|
+
public getProgram(): Program {
|
|
56
|
+
if (program) {
|
|
57
|
+
return program;
|
|
67
58
|
}
|
|
68
59
|
|
|
69
|
-
|
|
70
|
-
programMap.set(this.env, program);
|
|
60
|
+
program = getSwitchboardProgram(this.connection);
|
|
71
61
|
return program;
|
|
72
62
|
}
|
|
73
63
|
}
|
|
74
64
|
|
|
75
|
-
|
|
76
|
-
env: DriftEnv,
|
|
77
|
-
connection: Connection
|
|
78
|
-
): Promise<Program> {
|
|
65
|
+
function getSwitchboardProgram(connection: Connection): Program {
|
|
79
66
|
const DEFAULT_KEYPAIR = Keypair.fromSeed(new Uint8Array(32).fill(1));
|
|
80
|
-
const programId =
|
|
67
|
+
const programId = PublicKey.default;
|
|
81
68
|
const wallet = new Wallet(DEFAULT_KEYPAIR);
|
|
82
69
|
const provider = new AnchorProvider(connection, wallet, {});
|
|
83
70
|
|
package/src/oracles/types.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { BN } from '@project-serum/anchor';
|
|
2
2
|
import { PublicKey } from '@solana/web3.js';
|
|
3
|
+
import { OracleSource } from '../types';
|
|
3
4
|
|
|
4
5
|
export type OraclePriceData = {
|
|
5
6
|
price: BN;
|
|
@@ -10,7 +11,12 @@ export type OraclePriceData = {
|
|
|
10
11
|
twapConfidence?: BN;
|
|
11
12
|
};
|
|
12
13
|
|
|
14
|
+
export type OracleInfo = {
|
|
15
|
+
publicKey: PublicKey;
|
|
16
|
+
source: OracleSource;
|
|
17
|
+
};
|
|
18
|
+
|
|
13
19
|
export interface OracleClient {
|
|
14
|
-
getOraclePriceDataFromBuffer(buffer: Buffer):
|
|
20
|
+
getOraclePriceDataFromBuffer(buffer: Buffer): OraclePriceData;
|
|
15
21
|
getOraclePriceData(publicKey: PublicKey): Promise<OraclePriceData>;
|
|
16
22
|
}
|
package/src/orders.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
isVariant,
|
|
3
|
-
|
|
3
|
+
MarketAccount,
|
|
4
4
|
Order,
|
|
5
5
|
PositionDirection,
|
|
6
6
|
SwapDirection,
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
calculateSpreadReserves,
|
|
15
15
|
ClearingHouseUser,
|
|
16
16
|
isOrderRiskIncreasingInSameDirection,
|
|
17
|
+
standardizeBaseAssetAmount,
|
|
17
18
|
TEN_THOUSAND,
|
|
18
19
|
} from '.';
|
|
19
20
|
import {
|
|
@@ -36,9 +37,9 @@ import { OraclePriceData } from '.';
|
|
|
36
37
|
export function calculateNewStateAfterOrder(
|
|
37
38
|
userAccount: UserAccount,
|
|
38
39
|
userPosition: UserPosition,
|
|
39
|
-
market:
|
|
40
|
+
market: MarketAccount,
|
|
40
41
|
order: Order
|
|
41
|
-
): [UserAccount, UserPosition,
|
|
42
|
+
): [UserAccount, UserPosition, MarketAccount] | null {
|
|
42
43
|
if (isVariant(order.status, 'init')) {
|
|
43
44
|
return null;
|
|
44
45
|
}
|
|
@@ -47,7 +48,7 @@ export function calculateNewStateAfterOrder(
|
|
|
47
48
|
market,
|
|
48
49
|
order
|
|
49
50
|
);
|
|
50
|
-
if (baseAssetAmountToTrade.lt(market.amm.
|
|
51
|
+
if (baseAssetAmountToTrade.lt(market.amm.baseAssetAmountStepSize)) {
|
|
51
52
|
return null;
|
|
52
53
|
}
|
|
53
54
|
|
|
@@ -155,8 +156,8 @@ export function calculateNewStateAfterOrder(
|
|
|
155
156
|
}
|
|
156
157
|
|
|
157
158
|
function calculateAmountSwapped(
|
|
158
|
-
marketBefore:
|
|
159
|
-
marketAfter:
|
|
159
|
+
marketBefore: MarketAccount,
|
|
160
|
+
marketAfter: MarketAccount
|
|
160
161
|
): { quoteAssetAmountSwapped: BN; baseAssetAmountSwapped: BN } {
|
|
161
162
|
return {
|
|
162
163
|
quoteAssetAmountSwapped: marketBefore.amm.quoteAssetReserve
|
|
@@ -172,7 +173,7 @@ function calculateAmountSwapped(
|
|
|
172
173
|
}
|
|
173
174
|
|
|
174
175
|
export function calculateBaseAssetAmountMarketCanExecute(
|
|
175
|
-
market:
|
|
176
|
+
market: MarketAccount,
|
|
176
177
|
order: Order,
|
|
177
178
|
oraclePriceData?: OraclePriceData
|
|
178
179
|
): BN {
|
|
@@ -189,7 +190,7 @@ export function calculateBaseAssetAmountMarketCanExecute(
|
|
|
189
190
|
}
|
|
190
191
|
|
|
191
192
|
export function calculateAmountToTradeForLimit(
|
|
192
|
-
market:
|
|
193
|
+
market: MarketAccount,
|
|
193
194
|
order: Order,
|
|
194
195
|
oraclePriceData?: OraclePriceData
|
|
195
196
|
): BN {
|
|
@@ -213,8 +214,12 @@ export function calculateAmountToTradeForLimit(
|
|
|
213
214
|
const [maxAmountToTrade, direction] = calculateMaxBaseAssetAmountToTrade(
|
|
214
215
|
market.amm,
|
|
215
216
|
limitPrice,
|
|
216
|
-
order.direction
|
|
217
|
-
|
|
217
|
+
order.direction
|
|
218
|
+
);
|
|
219
|
+
|
|
220
|
+
const baseAssetAmount = standardizeBaseAssetAmount(
|
|
221
|
+
maxAmountToTrade,
|
|
222
|
+
market.amm.baseAssetAmountStepSize
|
|
218
223
|
);
|
|
219
224
|
|
|
220
225
|
// Check that directions are the same
|
|
@@ -223,13 +228,13 @@ export function calculateAmountToTradeForLimit(
|
|
|
223
228
|
return ZERO;
|
|
224
229
|
}
|
|
225
230
|
|
|
226
|
-
return
|
|
231
|
+
return baseAssetAmount.gt(order.baseAssetAmount)
|
|
227
232
|
? order.baseAssetAmount
|
|
228
|
-
:
|
|
233
|
+
: baseAssetAmount;
|
|
229
234
|
}
|
|
230
235
|
|
|
231
236
|
export function calculateAmountToTradeForTriggerLimit(
|
|
232
|
-
market:
|
|
237
|
+
market: MarketAccount,
|
|
233
238
|
order: Order
|
|
234
239
|
): BN {
|
|
235
240
|
if (order.baseAssetAmountFilled.eq(ZERO)) {
|
|
@@ -256,7 +261,7 @@ function isSameDirection(
|
|
|
256
261
|
}
|
|
257
262
|
|
|
258
263
|
function calculateAmountToTradeForTriggerMarket(
|
|
259
|
-
market:
|
|
264
|
+
market: MarketAccount,
|
|
260
265
|
order: Order
|
|
261
266
|
): BN {
|
|
262
267
|
return isTriggerConditionSatisfied(market, order)
|
|
@@ -264,8 +269,12 @@ function calculateAmountToTradeForTriggerMarket(
|
|
|
264
269
|
: ZERO;
|
|
265
270
|
}
|
|
266
271
|
|
|
267
|
-
function isTriggerConditionSatisfied(
|
|
268
|
-
|
|
272
|
+
function isTriggerConditionSatisfied(
|
|
273
|
+
market: MarketAccount,
|
|
274
|
+
order: Order,
|
|
275
|
+
oraclePriceData?: OraclePriceData
|
|
276
|
+
): boolean {
|
|
277
|
+
const markPrice = calculateMarkPrice(market, oraclePriceData);
|
|
269
278
|
if (isVariant(order.triggerCondition, 'above')) {
|
|
270
279
|
return markPrice.gt(order.triggerPrice);
|
|
271
280
|
} else {
|
|
@@ -274,9 +283,10 @@ function isTriggerConditionSatisfied(market: Market, order: Order): boolean {
|
|
|
274
283
|
}
|
|
275
284
|
|
|
276
285
|
export function calculateBaseAssetAmountUserCanExecute(
|
|
277
|
-
market:
|
|
286
|
+
market: MarketAccount,
|
|
278
287
|
order: Order,
|
|
279
|
-
user: ClearingHouseUser
|
|
288
|
+
user: ClearingHouseUser,
|
|
289
|
+
oraclePriceData?: OraclePriceData
|
|
280
290
|
): BN {
|
|
281
291
|
const maxLeverage = user.getMaxLeverage(order.marketIndex, 'Initial');
|
|
282
292
|
const freeCollateral = user.getFreeCollateral();
|
|
@@ -287,7 +297,11 @@ export function calculateBaseAssetAmountUserCanExecute(
|
|
|
287
297
|
const position =
|
|
288
298
|
user.getUserPosition(order.marketIndex) ||
|
|
289
299
|
user.getEmptyPosition(order.marketIndex);
|
|
290
|
-
const positionValue = calculateBaseAssetValue(
|
|
300
|
+
const positionValue = calculateBaseAssetValue(
|
|
301
|
+
market,
|
|
302
|
+
position,
|
|
303
|
+
oraclePriceData
|
|
304
|
+
);
|
|
291
305
|
quoteAssetAmount = freeCollateral
|
|
292
306
|
.mul(maxLeverage)
|
|
293
307
|
.div(TEN_THOUSAND)
|
|
@@ -307,7 +321,8 @@ export function calculateBaseAssetAmountUserCanExecute(
|
|
|
307
321
|
if (useSpread) {
|
|
308
322
|
const { baseAssetReserve, quoteAssetReserve } = calculateSpreadReserves(
|
|
309
323
|
market.amm,
|
|
310
|
-
order.direction
|
|
324
|
+
order.direction,
|
|
325
|
+
oraclePriceData
|
|
311
326
|
);
|
|
312
327
|
amm = {
|
|
313
328
|
baseAssetReserve,
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Connection } from '@solana/web3.js';
|
|
2
|
+
|
|
3
|
+
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
4
|
+
type SlotSubscriberConfig = {}; // for future customization
|
|
5
|
+
|
|
6
|
+
export class SlotSubscriber {
|
|
7
|
+
currentSlot: number;
|
|
8
|
+
subscriptionId: number;
|
|
9
|
+
|
|
10
|
+
public constructor(
|
|
11
|
+
private connection: Connection,
|
|
12
|
+
_config?: SlotSubscriberConfig
|
|
13
|
+
) {}
|
|
14
|
+
|
|
15
|
+
public async subscribe(): Promise<void> {
|
|
16
|
+
this.currentSlot = await this.connection.getSlot('confirmed');
|
|
17
|
+
|
|
18
|
+
this.subscriptionId = this.connection.onSlotChange((slotInfo) => {
|
|
19
|
+
this.currentSlot = slotInfo.slot;
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
public getSlot(): number {
|
|
24
|
+
return this.currentSlot;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
public async unsubscribe(): Promise<void> {
|
|
28
|
+
if (this.subscriptionId) {
|
|
29
|
+
await this.connection.removeSlotChangeListener(this.subscriptionId);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
package/src/tx/retryTxSender.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { TxSender } from './types';
|
|
1
|
+
import { TxSender, TxSigAndSlot } from './types';
|
|
2
2
|
import {
|
|
3
3
|
Commitment,
|
|
4
4
|
ConfirmOptions,
|
|
@@ -43,7 +43,7 @@ export class RetryTxSender implements TxSender {
|
|
|
43
43
|
tx: Transaction,
|
|
44
44
|
additionalSigners?: Array<Signer>,
|
|
45
45
|
opts?: ConfirmOptions
|
|
46
|
-
): Promise<
|
|
46
|
+
): Promise<TxSigAndSlot> {
|
|
47
47
|
if (additionalSigners === undefined) {
|
|
48
48
|
additionalSigners = [];
|
|
49
49
|
}
|
|
@@ -86,8 +86,10 @@ export class RetryTxSender implements TxSender {
|
|
|
86
86
|
}
|
|
87
87
|
})();
|
|
88
88
|
|
|
89
|
+
let slot: number;
|
|
89
90
|
try {
|
|
90
|
-
await this.confirmTransaction(txid, opts.commitment);
|
|
91
|
+
const result = await this.confirmTransaction(txid, opts.commitment);
|
|
92
|
+
slot = result.context.slot;
|
|
91
93
|
} catch (e) {
|
|
92
94
|
console.error(e);
|
|
93
95
|
throw e;
|
|
@@ -95,7 +97,7 @@ export class RetryTxSender implements TxSender {
|
|
|
95
97
|
stopWaiting();
|
|
96
98
|
}
|
|
97
99
|
|
|
98
|
-
return txid;
|
|
100
|
+
return { txSig: txid, slot };
|
|
99
101
|
}
|
|
100
102
|
|
|
101
103
|
async prepareTx(
|
package/src/tx/types.ts
CHANGED
|
@@ -6,6 +6,11 @@ import {
|
|
|
6
6
|
TransactionSignature,
|
|
7
7
|
} from '@solana/web3.js';
|
|
8
8
|
|
|
9
|
+
export type TxSigAndSlot = {
|
|
10
|
+
txSig: TransactionSignature;
|
|
11
|
+
slot: number;
|
|
12
|
+
};
|
|
13
|
+
|
|
9
14
|
export interface TxSender {
|
|
10
15
|
provider: Provider;
|
|
11
16
|
|
|
@@ -13,5 +18,5 @@ export interface TxSender {
|
|
|
13
18
|
tx: Transaction,
|
|
14
19
|
additionalSigners?: Array<Signer>,
|
|
15
20
|
opts?: ConfirmOptions
|
|
16
|
-
): Promise<
|
|
21
|
+
): Promise<TxSigAndSlot>;
|
|
17
22
|
}
|
package/src/tx/utils.ts
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
Transaction,
|
|
3
|
+
TransactionInstruction,
|
|
4
|
+
ComputeBudgetProgram,
|
|
5
|
+
} from '@solana/web3.js';
|
|
2
6
|
|
|
3
|
-
|
|
4
|
-
|
|
7
|
+
const COMPUTE_UNITS_DEFAULT = 200_000;
|
|
8
|
+
|
|
9
|
+
export function wrapInTx(
|
|
10
|
+
instruction: TransactionInstruction,
|
|
11
|
+
computeUnits = 500_000 // TODO, requires less code change
|
|
12
|
+
): Transaction {
|
|
13
|
+
const tx = new Transaction();
|
|
14
|
+
if (computeUnits != COMPUTE_UNITS_DEFAULT) {
|
|
15
|
+
tx.add(
|
|
16
|
+
ComputeBudgetProgram.requestUnits({
|
|
17
|
+
units: computeUnits,
|
|
18
|
+
additionalFee: 0,
|
|
19
|
+
})
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return tx.add(instruction);
|
|
5
24
|
}
|