Skip to content

Commit f4252d3

Browse files
authored
sdk: fix vamm l2 generator base swapped and add new top of book (#1626)
* sdk: bigz/fix-vamm-l2-generator-baseSwapped var assign * fix ask book else baseSwapped calc * use proper quoteAmount with baseSwap for top of book orders * clean up console.log * sdk: getVammL2Generator reduce loc (#1628) * sdk: getVammL2Generator-reduce-loc * add MAJORS_TOP_OF_BOOK_QUOTE_AMOUNTS * add marketindex check topOfBookAmounts
1 parent 92f7dc3 commit f4252d3

File tree

2 files changed

+98
-179
lines changed

2 files changed

+98
-179
lines changed

sdk/src/dlob/DLOBSubscriber.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { DriftClient } from '../driftClient';
1212
import { isVariant, MarketType } from '../types';
1313
import {
1414
DEFAULT_TOP_OF_BOOK_QUOTE_AMOUNTS,
15+
MAJORS_TOP_OF_BOOK_QUOTE_AMOUNTS,
1516
getVammL2Generator,
1617
L2OrderBook,
1718
L2OrderBookGenerator,
@@ -140,7 +141,7 @@ export class DLOBSubscriber {
140141
marketAccount: this.driftClient.getPerpMarketAccount(marketIndex),
141142
oraclePriceData,
142143
numOrders: numVammOrders ?? depth,
143-
topOfBookQuoteAmounts: DEFAULT_TOP_OF_BOOK_QUOTE_AMOUNTS,
144+
topOfBookQuoteAmounts: marketIndex < 3 ? MAJORS_TOP_OF_BOOK_QUOTE_AMOUNTS : DEFAULT_TOP_OF_BOOK_QUOTE_AMOUNTS,
144145
}),
145146
];
146147
}

sdk/src/dlob/orderBookLevels.ts

Lines changed: 96 additions & 178 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ import {
1717
standardizePrice,
1818
SwapDirection,
1919
ZERO,
20+
PRICE_PRECISION,
21+
AMM_TO_QUOTE_PRECISION_RATIO,
22+
standardizeBaseAssetAmount,
2023
} from '..';
2124
import { PublicKey } from '@solana/web3.js';
2225
import { assert } from '../assert/assert';
@@ -66,6 +69,13 @@ export const DEFAULT_TOP_OF_BOOK_QUOTE_AMOUNTS = [
6669
new BN(5000).mul(QUOTE_PRECISION),
6770
];
6871

72+
export const MAJORS_TOP_OF_BOOK_QUOTE_AMOUNTS = [
73+
new BN(5000).mul(QUOTE_PRECISION),
74+
new BN(10000).mul(QUOTE_PRECISION),
75+
new BN(20000).mul(QUOTE_PRECISION),
76+
new BN(50000).mul(QUOTE_PRECISION),
77+
];
78+
6979
/**
7080
* Get an {@link Generator<L2Level>} generator from a {@link Generator<DLOBNode>}
7181
* @param dlobNodes e.g. {@link DLOB#getRestingLimitAsks} or {@link DLOB#getRestingLimitBids}
@@ -162,29 +172,21 @@ export function getVammL2Generator({
162172
marketAccount,
163173
oraclePriceData,
164174
numOrders,
165-
now,
166-
topOfBookQuoteAmounts,
175+
now = new BN(Math.floor(Date.now() / 1000)),
176+
topOfBookQuoteAmounts = [],
167177
}: {
168178
marketAccount: PerpMarketAccount;
169179
oraclePriceData: OraclePriceData;
170180
numOrders: number;
171181
now?: BN;
172182
topOfBookQuoteAmounts?: BN[];
173183
}): L2OrderBookGenerator {
174-
let numBaseOrders = numOrders;
175-
if (topOfBookQuoteAmounts) {
176-
numBaseOrders = numOrders - topOfBookQuoteAmounts.length;
177-
assert(topOfBookQuoteAmounts.length < numOrders);
178-
}
179-
180184
const updatedAmm = calculateUpdatedAMM(marketAccount.amm, oraclePriceData);
181-
182-
const vammFillsDisabled = isOperationPaused(
185+
const paused = isOperationPaused(
183186
marketAccount.pausedOperations,
184187
PerpOperation.AMM_FILL
185188
);
186-
187-
let [openBids, openAsks] = vammFillsDisabled
189+
let [openBids, openAsks] = paused
188190
? [ZERO, ZERO]
189191
: calculateMarketOpenBidAsk(
190192
updatedAmm.baseAssetReserve,
@@ -193,194 +195,110 @@ export function getVammL2Generator({
193195
updatedAmm.orderStepSize
194196
);
195197

196-
const minOrderSize = marketAccount.amm.minOrderSize;
197-
if (openBids.lt(minOrderSize.muln(2))) {
198-
openBids = ZERO;
199-
}
200-
201-
if (openAsks.abs().lt(minOrderSize.muln(2))) {
198+
if (openBids.lt(marketAccount.amm.minOrderSize.muln(2))) openBids = ZERO;
199+
if (openAsks.abs().lt(marketAccount.amm.minOrderSize.muln(2)))
202200
openAsks = ZERO;
203-
}
204201

205-
now = now ?? new BN(Date.now() / 1000);
206202
const [bidReserves, askReserves] = calculateSpreadReserves(
207203
updatedAmm,
208204
oraclePriceData,
209205
now,
210206
isVariant(marketAccount.contractType, 'prediction')
211207
);
212208

213-
let numBids = 0;
214-
215-
let topOfBookBidSize = ZERO;
216-
let bidSize = openBids.div(new BN(numBaseOrders));
217-
const bidAmm = {
218-
baseAssetReserve: bidReserves.baseAssetReserve,
219-
quoteAssetReserve: bidReserves.quoteAssetReserve,
220-
sqrtK: updatedAmm.sqrtK,
209+
const numBaseOrders = Math.max(1, numOrders - topOfBookQuoteAmounts.length);
210+
const commonOpts = {
211+
numOrders,
212+
numBaseOrders,
213+
oraclePriceData,
214+
orderTickSize: marketAccount.amm.orderTickSize,
215+
orderStepSize: marketAccount.amm.orderStepSize,
221216
pegMultiplier: updatedAmm.pegMultiplier,
217+
sqrtK: updatedAmm.sqrtK,
218+
topOfBookQuoteAmounts,
222219
};
223220

224-
const getL2Bids = function* () {
225-
while (numBids < numOrders && bidSize.gt(ZERO)) {
226-
let quoteSwapped = ZERO;
227-
let baseSwapped = ZERO;
228-
let [afterSwapQuoteReserves, afterSwapBaseReserves] = [ZERO, ZERO];
229-
230-
if (topOfBookQuoteAmounts && numBids < topOfBookQuoteAmounts?.length) {
231-
const remainingBaseLiquidity = openBids.sub(topOfBookBidSize);
232-
quoteSwapped = topOfBookQuoteAmounts[numBids];
233-
[afterSwapQuoteReserves, afterSwapBaseReserves] =
234-
calculateAmmReservesAfterSwap(
235-
bidAmm,
236-
'quote',
237-
quoteSwapped,
238-
SwapDirection.REMOVE
239-
);
240-
241-
baseSwapped = bidAmm.baseAssetReserve.sub(afterSwapBaseReserves).abs();
242-
if (baseSwapped.eq(ZERO)) {
243-
return;
244-
}
245-
if (remainingBaseLiquidity.lt(baseSwapped)) {
246-
baseSwapped = remainingBaseLiquidity;
247-
[afterSwapQuoteReserves, afterSwapBaseReserves] =
248-
calculateAmmReservesAfterSwap(
249-
bidAmm,
250-
'base',
251-
baseSwapped,
252-
SwapDirection.ADD
253-
);
254-
255-
quoteSwapped = calculateQuoteAssetAmountSwapped(
256-
bidAmm.quoteAssetReserve.sub(afterSwapQuoteReserves).abs(),
257-
bidAmm.pegMultiplier,
258-
SwapDirection.ADD
259-
);
260-
}
261-
topOfBookBidSize = topOfBookBidSize.add(baseSwapped);
262-
bidSize = openBids.sub(topOfBookBidSize).div(new BN(numBaseOrders));
263-
} else {
264-
baseSwapped = bidSize;
265-
[afterSwapQuoteReserves, afterSwapBaseReserves] =
266-
calculateAmmReservesAfterSwap(
267-
bidAmm,
268-
'base',
269-
baseSwapped,
270-
SwapDirection.ADD
271-
);
272-
273-
quoteSwapped = calculateQuoteAssetAmountSwapped(
274-
bidAmm.quoteAssetReserve.sub(afterSwapQuoteReserves).abs(),
275-
bidAmm.pegMultiplier,
276-
SwapDirection.ADD
277-
);
278-
}
279-
280-
const price = quoteSwapped.mul(BASE_PRECISION).div(baseSwapped);
281-
282-
bidAmm.baseAssetReserve = afterSwapBaseReserves;
283-
bidAmm.quoteAssetReserve = afterSwapQuoteReserves;
284-
285-
yield {
286-
price,
287-
size: baseSwapped,
288-
sources: { vamm: baseSwapped },
221+
const makeL2Gen = ({
222+
openLiquidity,
223+
startReserves,
224+
swapDir,
225+
positionDir,
226+
}: {
227+
openLiquidity: BN;
228+
startReserves: { baseAssetReserve: BN; quoteAssetReserve: BN };
229+
swapDir: SwapDirection;
230+
positionDir: PositionDirection;
231+
}) => {
232+
return function* () {
233+
let count = 0;
234+
let topSize = ZERO;
235+
let size = openLiquidity.abs().divn(commonOpts.numBaseOrders);
236+
const amm = {
237+
...startReserves,
238+
sqrtK: commonOpts.sqrtK,
239+
pegMultiplier: commonOpts.pegMultiplier,
289240
};
290241

291-
numBids++;
292-
}
293-
};
294-
295-
let numAsks = 0;
296-
let topOfBookAskSize = ZERO;
297-
let askSize = openAsks.abs().div(new BN(numBaseOrders));
298-
const askAmm = {
299-
baseAssetReserve: askReserves.baseAssetReserve,
300-
quoteAssetReserve: askReserves.quoteAssetReserve,
301-
sqrtK: updatedAmm.sqrtK,
302-
pegMultiplier: updatedAmm.pegMultiplier,
303-
};
304-
305-
const getL2Asks = function* () {
306-
while (numAsks < numOrders && askSize.gt(ZERO)) {
307-
let quoteSwapped: BN = ZERO;
308-
let baseSwapped: BN = ZERO;
309-
let [afterSwapQuoteReserves, afterSwapBaseReserves] = [ZERO, ZERO];
310-
311-
if (topOfBookQuoteAmounts && numAsks < topOfBookQuoteAmounts?.length) {
312-
const remainingBaseLiquidity = openAsks
313-
.mul(new BN(-1))
314-
.sub(topOfBookAskSize);
315-
quoteSwapped = topOfBookQuoteAmounts[numAsks];
316-
[afterSwapQuoteReserves, afterSwapBaseReserves] =
317-
calculateAmmReservesAfterSwap(
318-
askAmm,
319-
'quote',
320-
quoteSwapped,
321-
SwapDirection.ADD
322-
);
323-
324-
baseSwapped = askAmm.baseAssetReserve.sub(afterSwapBaseReserves).abs();
325-
if (baseSwapped.eq(ZERO)) {
326-
return;
242+
while (count < commonOpts.numOrders && size.gt(ZERO)) {
243+
let baseSwap = size;
244+
if (count < commonOpts.topOfBookQuoteAmounts.length) {
245+
const raw = commonOpts.topOfBookQuoteAmounts[count]
246+
.mul(AMM_TO_QUOTE_PRECISION_RATIO)
247+
.mul(PRICE_PRECISION)
248+
.div(commonOpts.oraclePriceData.price);
249+
baseSwap = standardizeBaseAssetAmount(raw, commonOpts.orderStepSize);
250+
const remaining = openLiquidity.abs().sub(topSize);
251+
if (remaining.lt(baseSwap)) baseSwap = remaining;
327252
}
328-
if (remainingBaseLiquidity.lt(baseSwapped)) {
329-
baseSwapped = remainingBaseLiquidity;
330-
[afterSwapQuoteReserves, afterSwapBaseReserves] =
331-
calculateAmmReservesAfterSwap(
332-
askAmm,
333-
'base',
334-
baseSwapped,
335-
SwapDirection.REMOVE
336-
);
337-
338-
quoteSwapped = calculateQuoteAssetAmountSwapped(
339-
askAmm.quoteAssetReserve.sub(afterSwapQuoteReserves).abs(),
340-
askAmm.pegMultiplier,
341-
SwapDirection.REMOVE
342-
);
343-
}
344-
topOfBookAskSize = topOfBookAskSize.add(baseSwapped);
345-
askSize = openAsks
346-
.abs()
347-
.sub(topOfBookAskSize)
348-
.div(new BN(numBaseOrders));
349-
} else {
350-
baseSwapped = askSize;
351-
[afterSwapQuoteReserves, afterSwapBaseReserves] =
352-
calculateAmmReservesAfterSwap(
353-
askAmm,
354-
'base',
355-
askSize,
356-
SwapDirection.REMOVE
357-
);
358-
359-
quoteSwapped = calculateQuoteAssetAmountSwapped(
360-
askAmm.quoteAssetReserve.sub(afterSwapQuoteReserves).abs(),
361-
askAmm.pegMultiplier,
362-
SwapDirection.REMOVE
363-
);
364-
}
253+
if (baseSwap.isZero()) return;
365254

366-
const price = quoteSwapped.mul(BASE_PRECISION).div(baseSwapped);
255+
const [newQuoteRes, newBaseRes] = calculateAmmReservesAfterSwap(
256+
amm,
257+
'base',
258+
baseSwap,
259+
swapDir
260+
);
261+
const quoteSwapped = calculateQuoteAssetAmountSwapped(
262+
amm.quoteAssetReserve.sub(newQuoteRes).abs(),
263+
amm.pegMultiplier,
264+
swapDir
265+
);
266+
const price = standardizePrice(
267+
quoteSwapped.mul(BASE_PRECISION).div(baseSwap),
268+
commonOpts.orderTickSize,
269+
positionDir
270+
);
367271

368-
askAmm.baseAssetReserve = afterSwapBaseReserves;
369-
askAmm.quoteAssetReserve = afterSwapQuoteReserves;
272+
amm.baseAssetReserve = newBaseRes;
273+
amm.quoteAssetReserve = newQuoteRes;
370274

371-
yield {
372-
price,
373-
size: baseSwapped,
374-
sources: { vamm: baseSwapped },
375-
};
275+
if (count < commonOpts.topOfBookQuoteAmounts.length) {
276+
topSize = topSize.add(baseSwap);
277+
size = openLiquidity
278+
.abs()
279+
.sub(topSize)
280+
.divn(commonOpts.numBaseOrders);
281+
}
376282

377-
numAsks++;
378-
}
283+
yield { price, size: baseSwap, sources: { vamm: baseSwap } };
284+
count++;
285+
}
286+
};
379287
};
380288

381289
return {
382-
getL2Bids,
383-
getL2Asks,
290+
getL2Bids: makeL2Gen({
291+
openLiquidity: openBids,
292+
startReserves: bidReserves,
293+
swapDir: SwapDirection.ADD,
294+
positionDir: PositionDirection.LONG,
295+
}),
296+
getL2Asks: makeL2Gen({
297+
openLiquidity: openAsks,
298+
startReserves: askReserves,
299+
swapDir: SwapDirection.REMOVE,
300+
positionDir: PositionDirection.SHORT,
301+
}),
384302
};
385303
}
386304

0 commit comments

Comments
 (0)