@drift-labs/sdk 0.2.0-master.1 → 0.2.0-master.2
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/types.d.ts +1 -0
- package/lib/admin.d.ts +1 -0
- package/lib/admin.js +9 -0
- package/lib/clearingHouse.d.ts +5 -3
- package/lib/clearingHouse.js +58 -4
- package/lib/config.js +1 -1
- package/lib/constants/numericConstants.d.ts +1 -0
- package/lib/constants/numericConstants.js +2 -1
- package/lib/factory/bigNum.d.ts +8 -2
- package/lib/factory/bigNum.js +14 -6
- package/lib/idl/clearing_house.json +106 -19
- package/lib/math/amm.d.ts +6 -1
- package/lib/math/amm.js +127 -16
- package/lib/math/repeg.js +1 -1
- package/lib/orders.d.ts +1 -2
- package/lib/orders.js +5 -76
- package/lib/types.d.ts +5 -0
- package/lib/types.js +1 -0
- package/package.json +1 -1
- package/src/admin.ts +13 -0
- package/src/clearingHouse.ts +82 -8
- package/src/config.ts +1 -1
- package/src/constants/numericConstants.ts +1 -0
- package/src/factory/bigNum.ts +26 -9
- package/src/idl/clearing_house.json +106 -19
- package/src/math/amm.ts +202 -17
- package/src/math/repeg.ts +2 -1
- package/src/orders.ts +6 -123
- package/src/types.ts +4 -1
package/lib/math/amm.js
CHANGED
|
@@ -1,25 +1,58 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.calculateQuoteAssetAmountSwapped = exports.calculateMaxBaseAssetAmountToTrade = exports.calculateTerminalPrice = exports.getSwapDirection = exports.calculateSwapOutput = exports.calculateSpreadReserves = exports.calculateSpread = exports.calculateAmmReservesAfterSwap = exports.calculatePrice = exports.calculateBidAskPrice = exports.calculateUpdatedAMMSpreadReserves = exports.calculateUpdatedAMM = exports.calculateNewAmm = void 0;
|
|
3
|
+
exports.calculateQuoteAssetAmountSwapped = exports.calculateMaxBaseAssetAmountToTrade = exports.calculateTerminalPrice = exports.getSwapDirection = exports.calculateSwapOutput = exports.calculateSpreadReserves = exports.calculateSpread = exports.calculateSpreadBN = exports.calculateMaxSpread = exports.calculateEffectiveLeverage = exports.calculateAmmReservesAfterSwap = exports.calculatePrice = exports.calculateBidAskPrice = exports.calculateUpdatedAMMSpreadReserves = exports.calculateUpdatedAMM = exports.calculateNewAmm = exports.calculateOptimalPegAndBudget = exports.calculatePegFromTargetPrice = void 0;
|
|
4
4
|
const anchor_1 = require("@project-serum/anchor");
|
|
5
5
|
const numericConstants_1 = require("../constants/numericConstants");
|
|
6
6
|
const types_1 = require("../types");
|
|
7
7
|
const assert_1 = require("../assert/assert");
|
|
8
8
|
const __1 = require("..");
|
|
9
9
|
const repeg_1 = require("./repeg");
|
|
10
|
-
function
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
function calculatePegFromTargetPrice(targetPrice, baseAssetReserve, quoteAssetReserve) {
|
|
11
|
+
return targetPrice
|
|
12
|
+
.mul(baseAssetReserve)
|
|
13
|
+
.div(quoteAssetReserve)
|
|
14
|
+
.add(numericConstants_1.PRICE_DIV_PEG.div(new anchor_1.BN(2)))
|
|
15
|
+
.div(numericConstants_1.PRICE_DIV_PEG);
|
|
16
|
+
}
|
|
17
|
+
exports.calculatePegFromTargetPrice = calculatePegFromTargetPrice;
|
|
18
|
+
function calculateOptimalPegAndBudget(amm, oraclePriceData) {
|
|
19
|
+
const markPriceBefore = calculatePrice(amm.baseAssetReserve, amm.quoteAssetReserve, amm.pegMultiplier);
|
|
13
20
|
const targetPrice = oraclePriceData.price;
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
.div(amm.quoteAssetReserve)
|
|
17
|
-
.add(numericConstants_1.MARK_PRICE_PRECISION.div(numericConstants_1.PEG_PRECISION).div(new anchor_1.BN(2)))
|
|
18
|
-
.div(numericConstants_1.MARK_PRICE_PRECISION.div(numericConstants_1.PEG_PRECISION));
|
|
19
|
-
let prePegCost = (0, repeg_1.calculateRepegCost)(amm, newPeg);
|
|
21
|
+
const newPeg = calculatePegFromTargetPrice(targetPrice, amm.baseAssetReserve, amm.quoteAssetReserve);
|
|
22
|
+
const prePegCost = (0, repeg_1.calculateRepegCost)(amm, newPeg);
|
|
20
23
|
const totalFeeLB = amm.totalExchangeFee.div(new anchor_1.BN(2));
|
|
21
24
|
const budget = anchor_1.BN.max(numericConstants_1.ZERO, amm.totalFeeMinusDistributions.sub(totalFeeLB));
|
|
22
|
-
if (
|
|
25
|
+
if (budget.lt(prePegCost)) {
|
|
26
|
+
const maxPriceSpread = new anchor_1.BN(amm.maxSpread)
|
|
27
|
+
.mul(targetPrice)
|
|
28
|
+
.div(numericConstants_1.BID_ASK_SPREAD_PRECISION);
|
|
29
|
+
let newTargetPrice;
|
|
30
|
+
let newOptimalPeg;
|
|
31
|
+
let newBudget;
|
|
32
|
+
const targetPriceGap = markPriceBefore.sub(targetPrice);
|
|
33
|
+
if (targetPriceGap.abs().gt(maxPriceSpread)) {
|
|
34
|
+
const markAdj = targetPriceGap.abs().sub(maxPriceSpread);
|
|
35
|
+
if (targetPriceGap.lt(new anchor_1.BN(0))) {
|
|
36
|
+
newTargetPrice = markPriceBefore.add(markAdj);
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
newTargetPrice = markPriceBefore.sub(markAdj);
|
|
40
|
+
}
|
|
41
|
+
newOptimalPeg = calculatePegFromTargetPrice(newTargetPrice, amm.baseAssetReserve, amm.quoteAssetReserve);
|
|
42
|
+
newBudget = (0, repeg_1.calculateRepegCost)(amm, newOptimalPeg);
|
|
43
|
+
return [newTargetPrice, newOptimalPeg, newBudget, false];
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return [targetPrice, newPeg, budget, true];
|
|
47
|
+
}
|
|
48
|
+
exports.calculateOptimalPegAndBudget = calculateOptimalPegAndBudget;
|
|
49
|
+
function calculateNewAmm(amm, oraclePriceData) {
|
|
50
|
+
let pKNumer = new anchor_1.BN(1);
|
|
51
|
+
let pKDenom = new anchor_1.BN(1);
|
|
52
|
+
const [targetPrice, _newPeg, budget, checkLowerBound] = calculateOptimalPegAndBudget(amm, oraclePriceData);
|
|
53
|
+
let prePegCost = (0, repeg_1.calculateRepegCost)(amm, _newPeg);
|
|
54
|
+
let newPeg = _newPeg;
|
|
55
|
+
if (prePegCost.gt(budget) && checkLowerBound) {
|
|
23
56
|
[pKNumer, pKDenom] = [new anchor_1.BN(999), new anchor_1.BN(1000)];
|
|
24
57
|
const deficitMadeup = (0, repeg_1.calculateAdjustKCost)(amm, pKNumer, pKDenom);
|
|
25
58
|
(0, assert_1.assert)(deficitMadeup.lte(new anchor_1.BN(0)));
|
|
@@ -73,8 +106,14 @@ function calculateUpdatedAMMSpreadReserves(amm, direction, oraclePriceData) {
|
|
|
73
106
|
return result;
|
|
74
107
|
}
|
|
75
108
|
exports.calculateUpdatedAMMSpreadReserves = calculateUpdatedAMMSpreadReserves;
|
|
76
|
-
function calculateBidAskPrice(amm, oraclePriceData) {
|
|
77
|
-
|
|
109
|
+
function calculateBidAskPrice(amm, oraclePriceData, withUpdate = true) {
|
|
110
|
+
let newAmm;
|
|
111
|
+
if (withUpdate) {
|
|
112
|
+
newAmm = calculateUpdatedAMM(amm, oraclePriceData);
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
newAmm = amm;
|
|
116
|
+
}
|
|
78
117
|
const askReserves = calculateSpreadReserves(newAmm, types_1.PositionDirection.LONG, oraclePriceData);
|
|
79
118
|
const bidReserves = calculateSpreadReserves(newAmm, types_1.PositionDirection.SHORT, oraclePriceData);
|
|
80
119
|
const askPrice = calculatePrice(askReserves.baseAssetReserve, askReserves.quoteAssetReserve, newAmm.pegMultiplier);
|
|
@@ -126,6 +165,67 @@ function calculateAmmReservesAfterSwap(amm, inputAssetType, swapAmount, swapDire
|
|
|
126
165
|
return [newQuoteAssetReserve, newBaseAssetReserve];
|
|
127
166
|
}
|
|
128
167
|
exports.calculateAmmReservesAfterSwap = calculateAmmReservesAfterSwap;
|
|
168
|
+
function calculateEffectiveLeverage(baseSpread, quoteAssetReserve, terminalQuoteAssetReserve, pegMultiplier, netBaseAssetAmount, markPrice, totalFeeMinusDistributions) {
|
|
169
|
+
// inventory skew
|
|
170
|
+
const netBaseAssetValue = quoteAssetReserve
|
|
171
|
+
.sub(terminalQuoteAssetReserve)
|
|
172
|
+
.mul(pegMultiplier)
|
|
173
|
+
.div(numericConstants_1.AMM_TIMES_PEG_TO_QUOTE_PRECISION_RATIO);
|
|
174
|
+
const localBaseAssetValue = netBaseAssetAmount
|
|
175
|
+
.mul(markPrice)
|
|
176
|
+
.div(numericConstants_1.AMM_TO_QUOTE_PRECISION_RATIO.mul(numericConstants_1.MARK_PRICE_PRECISION));
|
|
177
|
+
const effectiveLeverage = localBaseAssetValue.sub(netBaseAssetValue).toNumber() /
|
|
178
|
+
(Math.max(0, totalFeeMinusDistributions.toNumber()) + 1) +
|
|
179
|
+
1 / numericConstants_1.QUOTE_PRECISION.toNumber();
|
|
180
|
+
return effectiveLeverage;
|
|
181
|
+
}
|
|
182
|
+
exports.calculateEffectiveLeverage = calculateEffectiveLeverage;
|
|
183
|
+
function calculateMaxSpread(marginRatioInitial) {
|
|
184
|
+
const maxTargetSpread = new anchor_1.BN(marginRatioInitial)
|
|
185
|
+
.mul(numericConstants_1.BID_ASK_SPREAD_PRECISION.div(numericConstants_1.MARGIN_PRECISION))
|
|
186
|
+
.toNumber();
|
|
187
|
+
return maxTargetSpread;
|
|
188
|
+
}
|
|
189
|
+
exports.calculateMaxSpread = calculateMaxSpread;
|
|
190
|
+
function calculateSpreadBN(baseSpread, lastOracleMarkSpreadPct, lastOracleConfPct, maxSpread, quoteAssetReserve, terminalQuoteAssetReserve, pegMultiplier, netBaseAssetAmount, markPrice, totalFeeMinusDistributions) {
|
|
191
|
+
let longSpread = baseSpread / 2;
|
|
192
|
+
let shortSpread = baseSpread / 2;
|
|
193
|
+
if (lastOracleMarkSpreadPct.gt(numericConstants_1.ZERO)) {
|
|
194
|
+
shortSpread = Math.max(shortSpread, lastOracleMarkSpreadPct.abs().toNumber() + lastOracleConfPct.toNumber());
|
|
195
|
+
}
|
|
196
|
+
else if (lastOracleMarkSpreadPct.lt(numericConstants_1.ZERO)) {
|
|
197
|
+
longSpread = Math.max(longSpread, lastOracleMarkSpreadPct.abs().toNumber() + lastOracleConfPct.toNumber());
|
|
198
|
+
}
|
|
199
|
+
const maxTargetSpread = maxSpread;
|
|
200
|
+
const MAX_INVENTORY_SKEW = 5;
|
|
201
|
+
const effectiveLeverage = calculateEffectiveLeverage(baseSpread, quoteAssetReserve, terminalQuoteAssetReserve, pegMultiplier, netBaseAssetAmount, markPrice, totalFeeMinusDistributions);
|
|
202
|
+
if (totalFeeMinusDistributions.gt(numericConstants_1.ZERO)) {
|
|
203
|
+
const spreadScale = Math.min(MAX_INVENTORY_SKEW, 1 + effectiveLeverage);
|
|
204
|
+
if (netBaseAssetAmount.gt(numericConstants_1.ZERO)) {
|
|
205
|
+
longSpread *= spreadScale;
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
shortSpread *= spreadScale;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
else {
|
|
212
|
+
longSpread *= MAX_INVENTORY_SKEW;
|
|
213
|
+
shortSpread *= MAX_INVENTORY_SKEW;
|
|
214
|
+
}
|
|
215
|
+
const totalSpread = longSpread + shortSpread;
|
|
216
|
+
if (totalSpread > maxTargetSpread) {
|
|
217
|
+
if (longSpread > shortSpread) {
|
|
218
|
+
longSpread = Math.min(longSpread, maxTargetSpread);
|
|
219
|
+
shortSpread = maxTargetSpread - longSpread;
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
shortSpread = Math.min(shortSpread, maxTargetSpread);
|
|
223
|
+
longSpread = maxTargetSpread - shortSpread;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
return [longSpread, shortSpread];
|
|
227
|
+
}
|
|
228
|
+
exports.calculateSpreadBN = calculateSpreadBN;
|
|
129
229
|
function calculateSpread(amm, direction, oraclePriceData) {
|
|
130
230
|
let spread = amm.baseSpread / 2;
|
|
131
231
|
if (amm.baseSpread == 0 || amm.curveUpdateIntensity == 0) {
|
|
@@ -133,14 +233,18 @@ function calculateSpread(amm, direction, oraclePriceData) {
|
|
|
133
233
|
}
|
|
134
234
|
const markPrice = calculatePrice(amm.baseAssetReserve, amm.quoteAssetReserve, amm.pegMultiplier);
|
|
135
235
|
const targetPrice = (oraclePriceData === null || oraclePriceData === void 0 ? void 0 : oraclePriceData.price) || markPrice;
|
|
236
|
+
const confInterval = oraclePriceData.confidence || numericConstants_1.ZERO;
|
|
136
237
|
const targetMarkSpreadPct = markPrice
|
|
137
238
|
.sub(targetPrice)
|
|
138
239
|
.mul(numericConstants_1.BID_ASK_SPREAD_PRECISION)
|
|
139
240
|
.div(markPrice);
|
|
241
|
+
const confIntervalPct = confInterval
|
|
242
|
+
.mul(numericConstants_1.BID_ASK_SPREAD_PRECISION)
|
|
243
|
+
.div(markPrice);
|
|
140
244
|
// oracle retreat
|
|
141
245
|
if (((0, types_1.isVariant)(direction, 'long') && targetMarkSpreadPct.lt(numericConstants_1.ZERO)) ||
|
|
142
246
|
((0, types_1.isVariant)(direction, 'short') && targetMarkSpreadPct.gt(numericConstants_1.ZERO))) {
|
|
143
|
-
spread = Math.max(spread, targetMarkSpreadPct.abs().toNumber());
|
|
247
|
+
spread = Math.max(spread, targetMarkSpreadPct.abs().toNumber() + confIntervalPct.abs().toNumber());
|
|
144
248
|
}
|
|
145
249
|
// inventory skew
|
|
146
250
|
const MAX_INVENTORY_SKEW = 5;
|
|
@@ -161,9 +265,16 @@ function calculateSpread(amm, direction, oraclePriceData) {
|
|
|
161
265
|
if (amm.totalFeeMinusDistributions.gt(numericConstants_1.ZERO)) {
|
|
162
266
|
effectiveLeverage =
|
|
163
267
|
localPnl.sub(netPnl).toNumber() /
|
|
164
|
-
amm.totalFeeMinusDistributions.toNumber();
|
|
268
|
+
(amm.totalFeeMinusDistributions.toNumber() + 1);
|
|
269
|
+
}
|
|
270
|
+
let spreadScale = Math.min(MAX_INVENTORY_SKEW, 1 + effectiveLeverage);
|
|
271
|
+
const maxTargetSpread = numericConstants_1.BID_ASK_SPREAD_PRECISION.toNumber() / 50; // 2%
|
|
272
|
+
// cap the scale to attempt to only scale up to maxTargetSpread
|
|
273
|
+
// always let the oracle retreat methods go through 100%
|
|
274
|
+
if (spreadScale * spread > maxTargetSpread) {
|
|
275
|
+
spreadScale = Math.max(1.05, maxTargetSpread / spread);
|
|
165
276
|
}
|
|
166
|
-
spread *=
|
|
277
|
+
spread *= spreadScale;
|
|
167
278
|
}
|
|
168
279
|
return spread;
|
|
169
280
|
}
|
package/lib/math/repeg.js
CHANGED
|
@@ -107,7 +107,7 @@ function calculateBudgetedPeg(amm, cost, targetPrice) {
|
|
|
107
107
|
const targetPeg = targetPrice
|
|
108
108
|
.mul(amm.baseAssetReserve)
|
|
109
109
|
.div(amm.quoteAssetReserve)
|
|
110
|
-
.div(numericConstants_1.
|
|
110
|
+
.div(numericConstants_1.PRICE_DIV_PEG);
|
|
111
111
|
const k = amm.sqrtK.mul(amm.sqrtK);
|
|
112
112
|
const x = amm.baseAssetReserve;
|
|
113
113
|
const y = amm.quoteAssetReserve;
|
package/lib/orders.d.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
/// <reference types="bn.js" />
|
|
2
2
|
import { MarketAccount, Order, UserAccount, UserPosition } from './types';
|
|
3
|
-
import { BN
|
|
3
|
+
import { BN } from '.';
|
|
4
4
|
import { OraclePriceData } from '.';
|
|
5
5
|
export declare function calculateNewStateAfterOrder(userAccount: UserAccount, userPosition: UserPosition, market: MarketAccount, order: Order): [UserAccount, UserPosition, MarketAccount] | null;
|
|
6
6
|
export declare function calculateBaseAssetAmountMarketCanExecute(market: MarketAccount, order: Order, oraclePriceData?: OraclePriceData): BN;
|
|
7
7
|
export declare function calculateAmountToTradeForLimit(market: MarketAccount, order: Order, oraclePriceData?: OraclePriceData): BN;
|
|
8
8
|
export declare function calculateAmountToTradeForTriggerLimit(market: MarketAccount, order: Order): BN;
|
|
9
|
-
export declare function calculateBaseAssetAmountUserCanExecute(market: MarketAccount, order: Order, user: ClearingHouseUser, oraclePriceData?: OraclePriceData): BN;
|
package/lib/orders.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.calculateAmountToTradeForTriggerLimit = exports.calculateAmountToTradeForLimit = exports.calculateBaseAssetAmountMarketCanExecute = exports.calculateNewStateAfterOrder = void 0;
|
|
4
4
|
const types_1 = require("./types");
|
|
5
5
|
const _1 = require(".");
|
|
6
6
|
const market_1 = require("./math/market");
|
|
@@ -88,7 +88,6 @@ function calculateBaseAssetAmountMarketCanExecute(market, order, oraclePriceData
|
|
|
88
88
|
return calculateAmountToTradeForTriggerLimit(market, order);
|
|
89
89
|
}
|
|
90
90
|
else if ((0, types_1.isVariant)(order.orderType, 'market')) {
|
|
91
|
-
// should never be a market order queued
|
|
92
91
|
return numericConstants_1.ZERO;
|
|
93
92
|
}
|
|
94
93
|
else {
|
|
@@ -125,11 +124,8 @@ function calculateAmountToTradeForLimit(market, order, oraclePriceData) {
|
|
|
125
124
|
}
|
|
126
125
|
exports.calculateAmountToTradeForLimit = calculateAmountToTradeForLimit;
|
|
127
126
|
function calculateAmountToTradeForTriggerLimit(market, order) {
|
|
128
|
-
if (order.
|
|
129
|
-
|
|
130
|
-
if (baseAssetAmount.eq(numericConstants_1.ZERO)) {
|
|
131
|
-
return numericConstants_1.ZERO;
|
|
132
|
-
}
|
|
127
|
+
if (!order.triggered) {
|
|
128
|
+
return numericConstants_1.ZERO;
|
|
133
129
|
}
|
|
134
130
|
return calculateAmountToTradeForLimit(market, order);
|
|
135
131
|
}
|
|
@@ -139,75 +135,8 @@ function isSameDirection(firstDirection, secondDirection) {
|
|
|
139
135
|
((0, types_1.isVariant)(firstDirection, 'short') && (0, types_1.isVariant)(secondDirection, 'short')));
|
|
140
136
|
}
|
|
141
137
|
function calculateAmountToTradeForTriggerMarket(market, order) {
|
|
142
|
-
|
|
143
|
-
? order.baseAssetAmount
|
|
144
|
-
: numericConstants_1.ZERO;
|
|
145
|
-
}
|
|
146
|
-
function isTriggerConditionSatisfied(market, order, oraclePriceData) {
|
|
147
|
-
const markPrice = (0, market_1.calculateMarkPrice)(market, oraclePriceData);
|
|
148
|
-
if ((0, types_1.isVariant)(order.triggerCondition, 'above')) {
|
|
149
|
-
return markPrice.gt(order.triggerPrice);
|
|
150
|
-
}
|
|
151
|
-
else {
|
|
152
|
-
return markPrice.lt(order.triggerPrice);
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
function calculateBaseAssetAmountUserCanExecute(market, order, user, oraclePriceData) {
|
|
156
|
-
const maxLeverage = user.getMaxLeverage(order.marketIndex, 'Initial');
|
|
157
|
-
const freeCollateral = user.getFreeCollateral();
|
|
158
|
-
let quoteAssetAmount;
|
|
159
|
-
if ((0, _1.isOrderRiskIncreasingInSameDirection)(user, order)) {
|
|
160
|
-
quoteAssetAmount = freeCollateral.mul(maxLeverage).div(_1.TEN_THOUSAND);
|
|
161
|
-
}
|
|
162
|
-
else {
|
|
163
|
-
const position = user.getUserPosition(order.marketIndex) ||
|
|
164
|
-
user.getEmptyPosition(order.marketIndex);
|
|
165
|
-
const positionValue = (0, _1.calculateBaseAssetValue)(market, position, oraclePriceData);
|
|
166
|
-
quoteAssetAmount = freeCollateral
|
|
167
|
-
.mul(maxLeverage)
|
|
168
|
-
.div(_1.TEN_THOUSAND)
|
|
169
|
-
.add(positionValue.mul(numericConstants_1.TWO));
|
|
170
|
-
}
|
|
171
|
-
if (quoteAssetAmount.lte(numericConstants_1.ZERO)) {
|
|
138
|
+
if (!order.triggered) {
|
|
172
139
|
return numericConstants_1.ZERO;
|
|
173
140
|
}
|
|
174
|
-
|
|
175
|
-
? types_1.SwapDirection.ADD
|
|
176
|
-
: types_1.SwapDirection.REMOVE;
|
|
177
|
-
const useSpread = !order.postOnly;
|
|
178
|
-
let amm;
|
|
179
|
-
if (useSpread) {
|
|
180
|
-
const { baseAssetReserve, quoteAssetReserve } = (0, _1.calculateSpreadReserves)(market.amm, order.direction, oraclePriceData);
|
|
181
|
-
amm = {
|
|
182
|
-
baseAssetReserve,
|
|
183
|
-
quoteAssetReserve,
|
|
184
|
-
sqrtK: market.amm.sqrtK,
|
|
185
|
-
pegMultiplier: market.amm.pegMultiplier,
|
|
186
|
-
};
|
|
187
|
-
}
|
|
188
|
-
else {
|
|
189
|
-
amm = market.amm;
|
|
190
|
-
}
|
|
191
|
-
const baseAssetReservesBefore = amm.baseAssetReserve;
|
|
192
|
-
const [_, baseAssetReservesAfter] = (0, _1.calculateAmmReservesAfterSwap)(amm, 'quote', quoteAssetAmount, swapDirection);
|
|
193
|
-
let baseAssetAmount = baseAssetReservesBefore
|
|
194
|
-
.sub(baseAssetReservesAfter)
|
|
195
|
-
.abs();
|
|
196
|
-
if (order.reduceOnly) {
|
|
197
|
-
const position = user.getUserPosition(order.marketIndex) ||
|
|
198
|
-
user.getEmptyPosition(order.marketIndex);
|
|
199
|
-
if ((0, types_1.isVariant)(order.direction, 'long') &&
|
|
200
|
-
position.baseAssetAmount.gte(numericConstants_1.ZERO)) {
|
|
201
|
-
baseAssetAmount = numericConstants_1.ZERO;
|
|
202
|
-
}
|
|
203
|
-
else if ((0, types_1.isVariant)(order.direction, 'short') &&
|
|
204
|
-
position.baseAssetAmount.lte(numericConstants_1.ZERO)) {
|
|
205
|
-
baseAssetAmount = numericConstants_1.ZERO;
|
|
206
|
-
}
|
|
207
|
-
else {
|
|
208
|
-
_1.BN.min(baseAssetAmount, position.baseAssetAmount.abs());
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
return baseAssetAmount;
|
|
141
|
+
return order.baseAssetAmount;
|
|
212
142
|
}
|
|
213
|
-
exports.calculateBaseAssetAmountUserCanExecute = calculateBaseAssetAmountUserCanExecute;
|
package/lib/types.d.ts
CHANGED
|
@@ -88,6 +88,9 @@ export declare class OrderAction {
|
|
|
88
88
|
static readonly FILL: {
|
|
89
89
|
fill: {};
|
|
90
90
|
};
|
|
91
|
+
static readonly TRIGGER: {
|
|
92
|
+
trigger: {};
|
|
93
|
+
};
|
|
91
94
|
}
|
|
92
95
|
export declare class OrderTriggerCondition {
|
|
93
96
|
static readonly ABOVE: {
|
|
@@ -304,6 +307,7 @@ export declare type AMM = {
|
|
|
304
307
|
lastAskPriceTwap: BN;
|
|
305
308
|
longSpread: BN;
|
|
306
309
|
shortSpread: BN;
|
|
310
|
+
maxSpread: number;
|
|
307
311
|
};
|
|
308
312
|
export declare type UserPosition = {
|
|
309
313
|
baseAssetAmount: BN;
|
|
@@ -356,6 +360,7 @@ export declare type Order = {
|
|
|
356
360
|
reduceOnly: boolean;
|
|
357
361
|
triggerPrice: BN;
|
|
358
362
|
triggerCondition: OrderTriggerCondition;
|
|
363
|
+
triggered: boolean;
|
|
359
364
|
discountTier: OrderDiscountTier;
|
|
360
365
|
existingPositionDirection: PositionDirection;
|
|
361
366
|
referrer: PublicKey;
|
package/lib/types.js
CHANGED
|
@@ -50,6 +50,7 @@ OrderAction.PLACE = { place: {} };
|
|
|
50
50
|
OrderAction.CANCEL = { cancel: {} };
|
|
51
51
|
OrderAction.EXPIRE = { expire: {} };
|
|
52
52
|
OrderAction.FILL = { fill: {} };
|
|
53
|
+
OrderAction.TRIGGER = { trigger: {} };
|
|
53
54
|
class OrderTriggerCondition {
|
|
54
55
|
}
|
|
55
56
|
exports.OrderTriggerCondition = OrderTriggerCondition;
|
package/package.json
CHANGED
package/src/admin.ts
CHANGED
|
@@ -444,6 +444,19 @@ export class Admin extends ClearingHouse {
|
|
|
444
444
|
});
|
|
445
445
|
}
|
|
446
446
|
|
|
447
|
+
public async updateMarketMaxSpread(
|
|
448
|
+
marketIndex: BN,
|
|
449
|
+
maxSpread: number
|
|
450
|
+
): Promise<TransactionSignature> {
|
|
451
|
+
return await this.program.rpc.updateMarketMaxSpread(maxSpread, {
|
|
452
|
+
accounts: {
|
|
453
|
+
admin: this.wallet.publicKey,
|
|
454
|
+
state: await this.getStatePublicKey(),
|
|
455
|
+
market: await getMarketPublicKey(this.program.programId, marketIndex),
|
|
456
|
+
},
|
|
457
|
+
});
|
|
458
|
+
}
|
|
459
|
+
|
|
447
460
|
public async updatePartialLiquidationClosePercentage(
|
|
448
461
|
numerator: BN,
|
|
449
462
|
denominator: BN
|
package/src/clearingHouse.ts
CHANGED
|
@@ -914,7 +914,7 @@ export class ClearingHouse {
|
|
|
914
914
|
});
|
|
915
915
|
}
|
|
916
916
|
|
|
917
|
-
public async cancelOrder(orderId
|
|
917
|
+
public async cancelOrder(orderId?: BN): Promise<TransactionSignature> {
|
|
918
918
|
const { txSig } = await this.txSender.send(
|
|
919
919
|
wrapInTx(await this.getCancelOrderIx(orderId)),
|
|
920
920
|
[],
|
|
@@ -923,20 +923,16 @@ export class ClearingHouse {
|
|
|
923
923
|
return txSig;
|
|
924
924
|
}
|
|
925
925
|
|
|
926
|
-
public async getCancelOrderIx(orderId
|
|
926
|
+
public async getCancelOrderIx(orderId?: BN): Promise<TransactionInstruction> {
|
|
927
927
|
const userAccountPublicKey = await this.getUserAccountPublicKey();
|
|
928
928
|
|
|
929
|
-
const order = this.getOrder(orderId);
|
|
930
|
-
const oracle = this.getMarketAccount(order.marketIndex).amm.oracle;
|
|
931
|
-
|
|
932
929
|
const remainingAccounts = this.getRemainingAccounts({});
|
|
933
930
|
|
|
934
|
-
return await this.program.instruction.cancelOrder(orderId, {
|
|
931
|
+
return await this.program.instruction.cancelOrder(orderId ?? null, {
|
|
935
932
|
accounts: {
|
|
936
933
|
state: await this.getStatePublicKey(),
|
|
937
934
|
user: userAccountPublicKey,
|
|
938
935
|
authority: this.wallet.publicKey,
|
|
939
|
-
oracle,
|
|
940
936
|
},
|
|
941
937
|
remainingAccounts,
|
|
942
938
|
});
|
|
@@ -1066,7 +1062,7 @@ export class ClearingHouse {
|
|
|
1066
1062
|
public async fillOrder(
|
|
1067
1063
|
userAccountPublicKey: PublicKey,
|
|
1068
1064
|
user: UserAccount,
|
|
1069
|
-
order
|
|
1065
|
+
order?: Order,
|
|
1070
1066
|
makerInfo?: MakerInfo
|
|
1071
1067
|
): Promise<TransactionSignature> {
|
|
1072
1068
|
const { txSig } = await this.txSender.send(
|
|
@@ -1156,6 +1152,84 @@ export class ClearingHouse {
|
|
|
1156
1152
|
});
|
|
1157
1153
|
}
|
|
1158
1154
|
|
|
1155
|
+
public async triggerOrder(
|
|
1156
|
+
userAccountPublicKey: PublicKey,
|
|
1157
|
+
user: UserAccount,
|
|
1158
|
+
order: Order
|
|
1159
|
+
): Promise<TransactionSignature> {
|
|
1160
|
+
const { txSig } = await this.txSender.send(
|
|
1161
|
+
wrapInTx(await this.getTriggerOrderIx(userAccountPublicKey, user, order)),
|
|
1162
|
+
[],
|
|
1163
|
+
this.opts
|
|
1164
|
+
);
|
|
1165
|
+
return txSig;
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1168
|
+
public async getTriggerOrderIx(
|
|
1169
|
+
userAccountPublicKey: PublicKey,
|
|
1170
|
+
userAccount: UserAccount,
|
|
1171
|
+
order: Order
|
|
1172
|
+
): Promise<TransactionInstruction> {
|
|
1173
|
+
const fillerPublicKey = await this.getUserAccountPublicKey();
|
|
1174
|
+
|
|
1175
|
+
const marketIndex = order.marketIndex;
|
|
1176
|
+
const marketAccount = this.getMarketAccount(marketIndex);
|
|
1177
|
+
|
|
1178
|
+
const bankAccountInfos = [
|
|
1179
|
+
{
|
|
1180
|
+
pubkey: this.getQuoteAssetBankAccount().pubkey,
|
|
1181
|
+
isSigner: false,
|
|
1182
|
+
isWritable: true,
|
|
1183
|
+
},
|
|
1184
|
+
];
|
|
1185
|
+
const marketAccountInfos = [
|
|
1186
|
+
{
|
|
1187
|
+
pubkey: marketAccount.pubkey,
|
|
1188
|
+
isWritable: true,
|
|
1189
|
+
isSigner: false,
|
|
1190
|
+
},
|
|
1191
|
+
];
|
|
1192
|
+
const oracleAccountInfos = [
|
|
1193
|
+
{
|
|
1194
|
+
pubkey: marketAccount.amm.oracle,
|
|
1195
|
+
isWritable: false,
|
|
1196
|
+
isSigner: false,
|
|
1197
|
+
},
|
|
1198
|
+
];
|
|
1199
|
+
for (const position of userAccount.positions) {
|
|
1200
|
+
if (
|
|
1201
|
+
!positionIsAvailable(position) &&
|
|
1202
|
+
!position.marketIndex.eq(order.marketIndex)
|
|
1203
|
+
) {
|
|
1204
|
+
const market = this.getMarketAccount(position.marketIndex);
|
|
1205
|
+
marketAccountInfos.push({
|
|
1206
|
+
pubkey: market.pubkey,
|
|
1207
|
+
isWritable: false,
|
|
1208
|
+
isSigner: false,
|
|
1209
|
+
});
|
|
1210
|
+
oracleAccountInfos.push({
|
|
1211
|
+
pubkey: market.amm.oracle,
|
|
1212
|
+
isWritable: false,
|
|
1213
|
+
isSigner: false,
|
|
1214
|
+
});
|
|
1215
|
+
}
|
|
1216
|
+
}
|
|
1217
|
+
const remainingAccounts = oracleAccountInfos.concat(
|
|
1218
|
+
bankAccountInfos.concat(marketAccountInfos)
|
|
1219
|
+
);
|
|
1220
|
+
|
|
1221
|
+
const orderId = order.orderId;
|
|
1222
|
+
return await this.program.instruction.triggerOrder(orderId, {
|
|
1223
|
+
accounts: {
|
|
1224
|
+
state: await this.getStatePublicKey(),
|
|
1225
|
+
filler: fillerPublicKey,
|
|
1226
|
+
user: userAccountPublicKey,
|
|
1227
|
+
authority: this.wallet.publicKey,
|
|
1228
|
+
},
|
|
1229
|
+
remainingAccounts,
|
|
1230
|
+
});
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1159
1233
|
public async placeAndTake(
|
|
1160
1234
|
orderParams: OrderParams,
|
|
1161
1235
|
makerInfo?: MakerInfo
|
package/src/config.ts
CHANGED
|
@@ -28,7 +28,7 @@ export const configs: { [key in DriftEnv]: DriftConfig } = {
|
|
|
28
28
|
devnet: {
|
|
29
29
|
ENV: 'devnet',
|
|
30
30
|
PYTH_ORACLE_MAPPING_ADDRESS: 'BmA9Z6FjioHJPpjT39QazZyhDRUdZy2ezwx4GiDdE2u2',
|
|
31
|
-
CLEARING_HOUSE_PROGRAM_ID: '
|
|
31
|
+
CLEARING_HOUSE_PROGRAM_ID: '9jwr5nC2f9yAraXrg4UzHXmCX3vi9FQkjD6p9e8bRqNa',
|
|
32
32
|
USDC_MINT_ADDRESS: '8zGuJQqwhZafTah7Uc7Z4tXRnguqkn5KLFAP8oV6PHe2',
|
|
33
33
|
MARKETS: DevnetMarkets,
|
|
34
34
|
BANKS: DevnetBanks,
|
|
@@ -43,6 +43,7 @@ export const BASE_PRECISION_EXP = AMM_RESERVE_PRECISION_EXP;
|
|
|
43
43
|
|
|
44
44
|
export const AMM_TO_QUOTE_PRECISION_RATIO =
|
|
45
45
|
AMM_RESERVE_PRECISION.div(QUOTE_PRECISION); // 10^7
|
|
46
|
+
export const PRICE_DIV_PEG = MARK_PRICE_PRECISION.div(PEG_PRECISION); //10^7
|
|
46
47
|
export const PRICE_TO_QUOTE_PRECISION =
|
|
47
48
|
MARK_PRICE_PRECISION.div(QUOTE_PRECISION);
|
|
48
49
|
export const AMM_TIMES_PEG_TO_QUOTE_PRECISION_RATIO =
|
package/src/factory/bigNum.ts
CHANGED
|
@@ -234,8 +234,14 @@ export class BigNum {
|
|
|
234
234
|
return printString;
|
|
235
235
|
}
|
|
236
236
|
|
|
237
|
-
public prettyPrint(
|
|
238
|
-
|
|
237
|
+
public prettyPrint(
|
|
238
|
+
useTradePrecision?: boolean,
|
|
239
|
+
precisionOverride?: number
|
|
240
|
+
): string {
|
|
241
|
+
const [leftSide, rightSide] = this.printShort(
|
|
242
|
+
useTradePrecision,
|
|
243
|
+
precisionOverride
|
|
244
|
+
).split(BigNum.delim);
|
|
239
245
|
|
|
240
246
|
let formattedLeftSide = leftSide;
|
|
241
247
|
|
|
@@ -374,13 +380,24 @@ export class BigNum {
|
|
|
374
380
|
return this.toPrecision(6, true);
|
|
375
381
|
}
|
|
376
382
|
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
383
|
+
/**
|
|
384
|
+
* Print dollar formatted value. Defaults to fixed decimals two unless a given precision is given.
|
|
385
|
+
* @param useTradePrecision
|
|
386
|
+
* @param precisionOverride
|
|
387
|
+
* @returns
|
|
388
|
+
*/
|
|
389
|
+
public toNotional(
|
|
390
|
+
useTradePrecision?: boolean,
|
|
391
|
+
precisionOverride?: number
|
|
392
|
+
): string {
|
|
393
|
+
const prefix = `${this.lt(BigNum.zero()) ? `-` : ``}$`;
|
|
394
|
+
|
|
395
|
+
const val =
|
|
396
|
+
useTradePrecision || precisionOverride
|
|
397
|
+
? this.prettyPrint(useTradePrecision, precisionOverride)
|
|
398
|
+
: BigNum.fromPrint(this.toFixed(2), new BN(2)).prettyPrint();
|
|
399
|
+
|
|
400
|
+
return `${prefix}${val.replace('-', '')}`;
|
|
384
401
|
}
|
|
385
402
|
|
|
386
403
|
public toMillified(precision = 3): string {
|