diff --git a/build_all.sh b/build_all.sh index 5333e79..40e9a9f 100644 --- a/build_all.sh +++ b/build_all.sh @@ -1,6 +1,10 @@ git submodule init git submodule update --recursive +rm -rf node_modules +rm -rf drift-common/protocol/sdk/node_modules +rm -rf drift-common/common-ts/node_modules + echo "building sdk..." cd drift-common/protocol/sdk yarn clean && yarn && yarn build && yarn link diff --git a/drift-common b/drift-common index 6721454..a9b2094 160000 --- a/drift-common +++ b/drift-common @@ -1 +1 @@ -Subproject commit 67214545014ef420d80b5d6fed8e11741311c54c +Subproject commit a9b2094da3f77715b1d41f2913496fcf03b2a97f diff --git a/src/dlob-subscriber/DLOBSubscriberIO.ts b/src/dlob-subscriber/DLOBSubscriberIO.ts index 20c2867..fe72fd3 100644 --- a/src/dlob-subscriber/DLOBSubscriberIO.ts +++ b/src/dlob-subscriber/DLOBSubscriberIO.ts @@ -13,7 +13,7 @@ import { PerpOperation, PositionDirection, ZERO, - calculateBidAskPrice, + calculateAMMBidAskPrice, getLimitPrice, isOperationPaused, isVariant, @@ -177,9 +177,11 @@ export class DLOBSubscriberIO extends DLOBSubscriber { let bestBid = bestDlobBid; let bestAsk = bestDlobAsk; if (marketType === 'perp') { - const [bestVammBid, bestVammAsk] = calculateBidAskPrice( + const [bestVammBid, bestVammAsk] = calculateAMMBidAskPrice( this.driftClient.getPerpMarketAccount(marketArgs.marketIndex).amm, - oraclePriceData, + this.driftClient.getMMOracleDataForPerpMarket( + marketArgs.marketIndex + ), true ); diff --git a/src/index.ts b/src/index.ts index fe6382f..916c46c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -79,7 +79,7 @@ const sdkConfig = initialize({ env: process.env.ENV }); const stateCommitment: Commitment = 'confirmed'; const serverPort = process.env.PORT || 6969; -export const ORDERBOOK_UPDATE_INTERVAL = 1000; +export const ORDERBOOK_UPDATE_INTERVAL = parseInt(process.env.ORDERBOOK_UPDATE_INTERVAL) || 400; const WS_FALLBACK_FETCH_INTERVAL = ORDERBOOK_UPDATE_INTERVAL * 60; const useWebsocket = process.env.USE_WEBSOCKET?.toLowerCase() === 'true'; const hermesUrl = process.env.HERMES_ENDPOINT; diff --git a/src/publishers/dlobPublisher.ts b/src/publishers/dlobPublisher.ts index 476e6e5..ffd81de 100644 --- a/src/publishers/dlobPublisher.ts +++ b/src/publishers/dlobPublisher.ts @@ -118,7 +118,7 @@ const useOrderSubscriber = process.env.USE_ORDER_SUBSCRIBER?.toLowerCase() === 'true'; const ORDERBOOK_UPDATE_INTERVAL = - parseInt(process.env.ORDERBOOK_UPDATE_INTERVAL) || 1000; + parseInt(process.env.ORDERBOOK_UPDATE_INTERVAL) || 400; const WS_FALLBACK_FETCH_INTERVAL = 60_000; const KILLSWITCH_SLOT_DIFF_THRESHOLD = diff --git a/src/utils/utils.ts b/src/utils/utils.ts index 351e140..5fcb17f 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -25,6 +25,7 @@ import { PERCENTAGE_PRECISION_EXP, } from '@drift-labs/sdk'; import { RedisClient } from '@drift/common/clients'; +import { TradeOffsetPrice } from '@drift/common'; import { logger } from './logger'; import { NextFunction, Request, Response } from 'express'; import FEATURE_FLAGS from './featureFlags'; @@ -746,6 +747,37 @@ export const convertRawL2ToBN = (rawL2: any): L2OrderBook => { }; }; +/** + * Maps TradeOffsetPrice values to corresponding property names in estimatedPrices object + * @param offsetFrom - TradeOffsetPrice type or 'marketBased' or undefined + * @returns Property name string for accessing estimatedPrices + */ +export const mapTradeOffsetPriceToProperty = ( + offsetFrom: TradeOffsetPrice | 'marketBased' | undefined +): string => { + switch (offsetFrom) { + case 'best': + return 'bestPrice'; + case 'worst': + return 'worstPrice'; + case 'oracle': + return 'oraclePrice'; + case 'mark': + return 'markPrice'; + case 'entry': + return 'entryPrice'; + case 'bestOffer': + // For bestOffer, we'll use the best price (could be refined based on direction) + return 'bestPrice'; + case 'marketBased': + // Default to mark price for market-based pricing + return 'markPrice'; + default: + // Default fallback to mark price + return 'markPrice'; + } +}; + /** * Get L2 orderbook data and calculate estimated prices * @param driftClient - DriftClient instance @@ -935,11 +967,18 @@ export const mapToMarketOrderParams = async ( }; } + const startPriceProperty = mapTradeOffsetPriceToProperty( + params.auctionStartPriceOffsetFrom + ); + const startPrice = estimatedPrices[startPriceProperty]; + processedSlippageTolerance = calculateDynamicSlippage( params.marketIndex, params.marketType, driftClient, - l2Formatted + l2Formatted, + startPrice, + estimatedPrices.worstPrice ); } } else { @@ -1072,7 +1111,9 @@ export const calculateDynamicSlippage = ( marketIndex: number, marketType: string, driftClient: DriftClient, - l2Formatted: L2OrderBook + l2Formatted: L2OrderBook, + startPrice: BN, + worstPrice: BN ): number => { // Determine if this is a major market (PERP with marketIndex 0, 1, or 2) const isPerp = marketType.toLowerCase() === 'perp'; @@ -1113,17 +1154,28 @@ export const calculateDynamicSlippage = ( let dynamicSlippage = baseSlippage + spreadBaseSlippage; + // use halfway to worst price as size adjusted slippage + if (startPrice && worstPrice) { + const sizeAdjustedSlippage = + (startPrice.sub(worstPrice).abs().toNumber() / + BN.max(startPrice, worstPrice).toNumber() / + 2) * + 100; + + dynamicSlippage = Math.max(dynamicSlippage, sizeAdjustedSlippage); + } + // Apply multiplier from env var const multiplier = isMajor ? parseFloat(process.env.DYNAMIC_SLIPPAGE_MULTIPLIER_MAJOR || '1.02') - : parseFloat(process.env.DYNAMIC_SLIPPAGE_MULTIPLIER_NON_MAJOR || '1.5'); + : parseFloat(process.env.DYNAMIC_SLIPPAGE_MULTIPLIER_NON_MAJOR || '1.4'); dynamicSlippage = dynamicSlippage * multiplier; // Enforce minimum and maximum limits from env vars const minSlippage = parseFloat(process.env.DYNAMIC_SLIPPAGE_MIN || '0.05'); // 0.05% minimum const maxSlippage = parseFloat(process.env.DYNAMIC_SLIPPAGE_MAX || '5'); // 5% maximum - return Math.min(Math.max(dynamicSlippage, minSlippage), maxSlippage); + return Math.min(Math.max(dynamicSlippage, minSlippage), maxSlippage) / 100; }; /**