Merge pull request #58 from drift-labs/wphan/dlob_publisher_limit_accounts_tracked
take in perp and spot markets from env var
This commit is contained in:
@@ -2,16 +2,11 @@ import {
|
|||||||
BN,
|
BN,
|
||||||
DLOBSubscriber,
|
DLOBSubscriber,
|
||||||
DLOBSubscriptionConfig,
|
DLOBSubscriptionConfig,
|
||||||
DevnetPerpMarkets,
|
|
||||||
DevnetSpotMarkets,
|
|
||||||
L2OrderBookGenerator,
|
L2OrderBookGenerator,
|
||||||
MainnetPerpMarkets,
|
|
||||||
MainnetSpotMarkets,
|
|
||||||
MarketType,
|
MarketType,
|
||||||
groupL2,
|
groupL2,
|
||||||
isVariant,
|
isVariant,
|
||||||
} from '@drift-labs/sdk';
|
} from '@drift-labs/sdk';
|
||||||
import { driftEnv } from '../publishers/dlobPublisher';
|
|
||||||
import { RedisClient } from '../utils/redisClient';
|
import { RedisClient } from '../utils/redisClient';
|
||||||
import {
|
import {
|
||||||
SubscriberLookup,
|
SubscriberLookup,
|
||||||
@@ -33,6 +28,11 @@ type wsMarketL2Args = {
|
|||||||
updateOnChange?: boolean;
|
updateOnChange?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type wsMarketInfo = {
|
||||||
|
marketIndex: number;
|
||||||
|
marketName: string;
|
||||||
|
};
|
||||||
|
|
||||||
export class DLOBSubscriberIO extends DLOBSubscriber {
|
export class DLOBSubscriberIO extends DLOBSubscriber {
|
||||||
public marketL2Args: wsMarketL2Args[] = [];
|
public marketL2Args: wsMarketL2Args[] = [];
|
||||||
public lastSeenL2Formatted: Map<MarketType, Map<number, any>>;
|
public lastSeenL2Formatted: Map<MarketType, Map<number, any>>;
|
||||||
@@ -41,6 +41,8 @@ export class DLOBSubscriberIO extends DLOBSubscriber {
|
|||||||
constructor(
|
constructor(
|
||||||
config: DLOBSubscriptionConfig & {
|
config: DLOBSubscriptionConfig & {
|
||||||
redisClient: RedisClient;
|
redisClient: RedisClient;
|
||||||
|
perpMarketInfos: wsMarketInfo[];
|
||||||
|
spotMarketInfos: wsMarketInfo[];
|
||||||
spotMarketSubscribers: SubscriberLookup;
|
spotMarketSubscribers: SubscriberLookup;
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
@@ -52,17 +54,11 @@ export class DLOBSubscriberIO extends DLOBSubscriber {
|
|||||||
this.lastSeenL2Formatted.set(MarketType.SPOT, new Map());
|
this.lastSeenL2Formatted.set(MarketType.SPOT, new Map());
|
||||||
this.lastSeenL2Formatted.set(MarketType.PERP, new Map());
|
this.lastSeenL2Formatted.set(MarketType.PERP, new Map());
|
||||||
|
|
||||||
// Add all active markets to the market L2Args
|
for (const market of config.perpMarketInfos) {
|
||||||
const perpMarkets =
|
|
||||||
driftEnv === 'devnet' ? DevnetPerpMarkets : MainnetPerpMarkets;
|
|
||||||
const spotMarkets =
|
|
||||||
driftEnv === 'devnet' ? DevnetSpotMarkets : MainnetSpotMarkets;
|
|
||||||
|
|
||||||
for (const market of perpMarkets) {
|
|
||||||
this.marketL2Args.push({
|
this.marketL2Args.push({
|
||||||
marketIndex: market.marketIndex,
|
marketIndex: market.marketIndex,
|
||||||
marketType: MarketType.PERP,
|
marketType: MarketType.PERP,
|
||||||
marketName: market.symbol,
|
marketName: market.marketName,
|
||||||
depth: -1,
|
depth: -1,
|
||||||
numVammOrders: 100,
|
numVammOrders: 100,
|
||||||
includeVamm: true,
|
includeVamm: true,
|
||||||
@@ -70,11 +66,11 @@ export class DLOBSubscriberIO extends DLOBSubscriber {
|
|||||||
fallbackL2Generators: [],
|
fallbackL2Generators: [],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
for (const market of spotMarkets) {
|
for (const market of config.spotMarketInfos) {
|
||||||
this.marketL2Args.push({
|
this.marketL2Args.push({
|
||||||
marketIndex: market.marketIndex,
|
marketIndex: market.marketIndex,
|
||||||
marketType: MarketType.SPOT,
|
marketType: MarketType.SPOT,
|
||||||
marketName: market.symbol,
|
marketName: market.marketName,
|
||||||
depth: -1,
|
depth: -1,
|
||||||
includeVamm: false,
|
includeVamm: false,
|
||||||
updateOnChange: true,
|
updateOnChange: true,
|
||||||
@@ -92,7 +88,7 @@ export class DLOBSubscriberIO extends DLOBSubscriber {
|
|||||||
try {
|
try {
|
||||||
this.getL2AndSendMsg(l2Args);
|
this.getL2AndSendMsg(l2Args);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(error);
|
console.error(error);
|
||||||
console.log(`Error getting L2 ${l2Args.marketName}`);
|
console.log(`Error getting L2 ${l2Args.marketName}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,9 @@ import {
|
|||||||
DriftClientSubscriptionConfig,
|
DriftClientSubscriptionConfig,
|
||||||
SlotSubscriber,
|
SlotSubscriber,
|
||||||
isVariant,
|
isVariant,
|
||||||
|
OracleInfo,
|
||||||
|
PerpMarketConfig,
|
||||||
|
SpotMarketConfig,
|
||||||
} from '@drift-labs/sdk';
|
} from '@drift-labs/sdk';
|
||||||
|
|
||||||
import { logger, setLogLevel } from '../utils/logger';
|
import { logger, setLogLevel } from '../utils/logger';
|
||||||
@@ -21,9 +24,13 @@ import {
|
|||||||
SubscriberLookup,
|
SubscriberLookup,
|
||||||
getPhoenixSubscriber,
|
getPhoenixSubscriber,
|
||||||
getSerumSubscriber,
|
getSerumSubscriber,
|
||||||
|
parsePositiveIntArray,
|
||||||
sleep,
|
sleep,
|
||||||
} from '../utils/utils';
|
} from '../utils/utils';
|
||||||
import { DLOBSubscriberIO } from '../dlob-subscriber/DLOBSubscriberIO';
|
import {
|
||||||
|
DLOBSubscriberIO,
|
||||||
|
wsMarketInfo,
|
||||||
|
} from '../dlob-subscriber/DLOBSubscriberIO';
|
||||||
import { RedisClient } from '../utils/redisClient';
|
import { RedisClient } from '../utils/redisClient';
|
||||||
import {
|
import {
|
||||||
DLOBProvider,
|
DLOBProvider,
|
||||||
@@ -64,6 +71,16 @@ const ORDERBOOK_UPDATE_INTERVAL =
|
|||||||
parseInt(process.env.ORDERBOOK_UPDATE_INTERVAL) || 1000;
|
parseInt(process.env.ORDERBOOK_UPDATE_INTERVAL) || 1000;
|
||||||
const WS_FALLBACK_FETCH_INTERVAL = 10_000;
|
const WS_FALLBACK_FETCH_INTERVAL = 10_000;
|
||||||
|
|
||||||
|
// comma separated list of perp market indexes to load: i.e. 0,1,2,3
|
||||||
|
const PERP_MARKETS_TO_LOAD = process.env.PERP_MARKETS_TO_LOAD
|
||||||
|
? parsePositiveIntArray(process.env.PERP_MARKETS_TO_LOAD)
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
// comma separated list of spot market indexes to load: i.e. 0,1,2,3
|
||||||
|
const SPOT_MARKETS_TO_LOAD = process.env.SPOT_MARKETS_TO_LOAD
|
||||||
|
? parsePositiveIntArray(process.env.SPOT_MARKETS_TO_LOAD)
|
||||||
|
: undefined;
|
||||||
|
|
||||||
logger.info(`RPC endpoint: ${endpoint}`);
|
logger.info(`RPC endpoint: ${endpoint}`);
|
||||||
logger.info(`WS endpoint: ${wsEndpoint}`);
|
logger.info(`WS endpoint: ${wsEndpoint}`);
|
||||||
logger.info(`DriftEnv: ${driftEnv}`);
|
logger.info(`DriftEnv: ${driftEnv}`);
|
||||||
@@ -71,22 +88,117 @@ logger.info(`Commit: ${commitHash}`);
|
|||||||
|
|
||||||
let MARKET_SUBSCRIBERS: SubscriberLookup = {};
|
let MARKET_SUBSCRIBERS: SubscriberLookup = {};
|
||||||
|
|
||||||
|
const getMarketsAndOraclesToLoad = (
|
||||||
|
sdkConfig: any
|
||||||
|
): {
|
||||||
|
perpMarketInfos: wsMarketInfo[];
|
||||||
|
spotMarketInfos: wsMarketInfo[];
|
||||||
|
oracleInfos?: OracleInfo[];
|
||||||
|
} => {
|
||||||
|
const oracleInfos: OracleInfo[] = [];
|
||||||
|
const oraclesTracked = new Set();
|
||||||
|
const perpMarketInfos: wsMarketInfo[] = [];
|
||||||
|
const spotMarketInfos: wsMarketInfo[] = [];
|
||||||
|
|
||||||
|
// only watch all markets if neither env vars are specified
|
||||||
|
const noMarketsSpecified = !PERP_MARKETS_TO_LOAD && !SPOT_MARKETS_TO_LOAD;
|
||||||
|
|
||||||
|
let perpIndexes = PERP_MARKETS_TO_LOAD;
|
||||||
|
if (!perpIndexes) {
|
||||||
|
if (noMarketsSpecified) {
|
||||||
|
perpIndexes = sdkConfig.PERP_MARKETS.map((m) => m.marketIndex);
|
||||||
|
} else {
|
||||||
|
perpIndexes = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let spotIndexes = SPOT_MARKETS_TO_LOAD;
|
||||||
|
if (!spotIndexes) {
|
||||||
|
if (noMarketsSpecified) {
|
||||||
|
spotIndexes = sdkConfig.SPOT_MARKETS.map((m) => m.marketIndex);
|
||||||
|
} else {
|
||||||
|
spotIndexes = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (perpIndexes.length > 0) {
|
||||||
|
for (const idx of perpIndexes) {
|
||||||
|
const perpMarketConfig = sdkConfig.PERP_MARKETS[idx] as PerpMarketConfig;
|
||||||
|
if (!perpMarketConfig) {
|
||||||
|
throw new Error(`Perp market config for ${idx} not found`);
|
||||||
|
}
|
||||||
|
const oracleKey = perpMarketConfig.oracle.toBase58();
|
||||||
|
if (!oraclesTracked.has(oracleKey)) {
|
||||||
|
logger.info(`Tracking oracle ${oracleKey} for perp market ${idx}`);
|
||||||
|
oracleInfos.push({
|
||||||
|
publicKey: perpMarketConfig.oracle,
|
||||||
|
source: perpMarketConfig.oracleSource,
|
||||||
|
});
|
||||||
|
oraclesTracked.add(oracleKey);
|
||||||
|
}
|
||||||
|
perpMarketInfos.push({
|
||||||
|
marketIndex: perpMarketConfig.marketIndex,
|
||||||
|
marketName: perpMarketConfig.symbol,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
logger.info(
|
||||||
|
`DlobPublisher tracking perp markets: ${JSON.stringify(perpMarketInfos)}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (spotIndexes.length > 0) {
|
||||||
|
for (const idx of spotIndexes) {
|
||||||
|
const spotMarketConfig = sdkConfig.SPOT_MARKETS[idx] as SpotMarketConfig;
|
||||||
|
if (!spotMarketConfig) {
|
||||||
|
throw new Error(`Spot market config for ${idx} not found`);
|
||||||
|
}
|
||||||
|
const oracleKey = spotMarketConfig.oracle.toBase58();
|
||||||
|
if (!oraclesTracked.has(oracleKey)) {
|
||||||
|
logger.info(`Tracking oracle ${oracleKey} for spot market ${idx}`);
|
||||||
|
oracleInfos.push({
|
||||||
|
publicKey: spotMarketConfig.oracle,
|
||||||
|
source: spotMarketConfig.oracleSource,
|
||||||
|
});
|
||||||
|
oraclesTracked.add(oracleKey);
|
||||||
|
}
|
||||||
|
spotMarketInfos.push({
|
||||||
|
marketIndex: spotMarketConfig.marketIndex,
|
||||||
|
marketName: spotMarketConfig.symbol,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
logger.info(
|
||||||
|
`DlobPublisher tracking spot markets: ${JSON.stringify(spotMarketInfos)}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
perpMarketInfos,
|
||||||
|
spotMarketInfos,
|
||||||
|
oracleInfos,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
const initializeAllMarketSubscribers = async (driftClient: DriftClient) => {
|
const initializeAllMarketSubscribers = async (driftClient: DriftClient) => {
|
||||||
const markets: SubscriberLookup = {};
|
const markets: SubscriberLookup = {};
|
||||||
|
|
||||||
for (const market of sdkConfig.SPOT_MARKETS) {
|
for (const market of driftClient.getSpotMarketAccounts()) {
|
||||||
markets[market.marketIndex] = {
|
markets[market.marketIndex] = {
|
||||||
phoenix: undefined,
|
phoenix: undefined,
|
||||||
serum: undefined,
|
serum: undefined,
|
||||||
};
|
};
|
||||||
|
const marketConfig = sdkConfig.SPOT_MARKETS[market.marketIndex];
|
||||||
|
|
||||||
if (market.phoenixMarket) {
|
if (marketConfig.phoenixMarket) {
|
||||||
const phoenixConfigAccount =
|
const phoenixConfigAccount =
|
||||||
await driftClient.getPhoenixV1FulfillmentConfig(market.phoenixMarket);
|
await driftClient.getPhoenixV1FulfillmentConfig(
|
||||||
|
marketConfig.phoenixMarket
|
||||||
|
);
|
||||||
if (isVariant(phoenixConfigAccount.status, 'enabled')) {
|
if (isVariant(phoenixConfigAccount.status, 'enabled')) {
|
||||||
|
logger.info(
|
||||||
|
`Loading phoenix subscriber for spot market ${market.marketIndex}`
|
||||||
|
);
|
||||||
const phoenixSubscriber = getPhoenixSubscriber(
|
const phoenixSubscriber = getPhoenixSubscriber(
|
||||||
driftClient,
|
driftClient,
|
||||||
market,
|
marketConfig,
|
||||||
sdkConfig
|
sdkConfig
|
||||||
);
|
);
|
||||||
await phoenixSubscriber.subscribe();
|
await phoenixSubscriber.subscribe();
|
||||||
@@ -103,14 +215,17 @@ const initializeAllMarketSubscribers = async (driftClient: DriftClient) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (market.serumMarket) {
|
if (marketConfig.serumMarket) {
|
||||||
const serumConfigAccount = await driftClient.getSerumV3FulfillmentConfig(
|
const serumConfigAccount = await driftClient.getSerumV3FulfillmentConfig(
|
||||||
market.serumMarket
|
marketConfig.serumMarket
|
||||||
);
|
);
|
||||||
if (isVariant(serumConfigAccount.status, 'enabled')) {
|
if (isVariant(serumConfigAccount.status, 'enabled')) {
|
||||||
|
logger.info(
|
||||||
|
`Loading serum subscriber for spot market ${market.marketIndex}`
|
||||||
|
);
|
||||||
const serumSubscriber = getSerumSubscriber(
|
const serumSubscriber = getSerumSubscriber(
|
||||||
driftClient,
|
driftClient,
|
||||||
market,
|
marketConfig,
|
||||||
sdkConfig
|
sdkConfig
|
||||||
);
|
);
|
||||||
await serumSubscriber.subscribe();
|
await serumSubscriber.subscribe();
|
||||||
@@ -177,12 +292,17 @@ const main = async () => {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { perpMarketInfos, spotMarketInfos, oracleInfos } =
|
||||||
|
getMarketsAndOraclesToLoad(sdkConfig);
|
||||||
driftClient = new DriftClient({
|
driftClient = new DriftClient({
|
||||||
connection,
|
connection,
|
||||||
wallet,
|
wallet,
|
||||||
programID: clearingHousePublicKey,
|
programID: clearingHousePublicKey,
|
||||||
accountSubscription,
|
accountSubscription,
|
||||||
env: driftEnv,
|
env: driftEnv,
|
||||||
|
perpMarketIndexes: perpMarketInfos.map((m) => m.marketIndex),
|
||||||
|
spotMarketIndexes: spotMarketInfos.map((m) => m.marketIndex),
|
||||||
|
oracleInfos,
|
||||||
});
|
});
|
||||||
|
|
||||||
const lamportsBalance = await connection.getBalance(wallet.publicKey);
|
const lamportsBalance = await connection.getBalance(wallet.publicKey);
|
||||||
@@ -271,6 +391,8 @@ const main = async () => {
|
|||||||
updateFrequency: ORDERBOOK_UPDATE_INTERVAL,
|
updateFrequency: ORDERBOOK_UPDATE_INTERVAL,
|
||||||
redisClient,
|
redisClient,
|
||||||
spotMarketSubscribers: MARKET_SUBSCRIBERS,
|
spotMarketSubscribers: MARKET_SUBSCRIBERS,
|
||||||
|
perpMarketInfos,
|
||||||
|
spotMarketInfos,
|
||||||
});
|
});
|
||||||
await dlobSubscriber.subscribe();
|
await dlobSubscriber.subscribe();
|
||||||
if (useWebsocket && !FEATURE_FLAGS.DISABLE_GPA_REFRESH) {
|
if (useWebsocket && !FEATURE_FLAGS.DISABLE_GPA_REFRESH) {
|
||||||
|
|||||||
@@ -39,6 +39,17 @@ export function sleep(ms: number): Promise<void> {
|
|||||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function parsePositiveIntArray(
|
||||||
|
intArray: string,
|
||||||
|
separator = ','
|
||||||
|
): number[] {
|
||||||
|
return intArray
|
||||||
|
.split(separator)
|
||||||
|
.map((s) => s.trim())
|
||||||
|
.map((s) => parseInt(s))
|
||||||
|
.filter((n) => !isNaN(n) && n > 0);
|
||||||
|
}
|
||||||
|
|
||||||
export const getOracleForMarket = (
|
export const getOracleForMarket = (
|
||||||
driftClient: DriftClient,
|
driftClient: DriftClient,
|
||||||
marketType: MarketType,
|
marketType: MarketType,
|
||||||
|
|||||||
Reference in New Issue
Block a user