Added oracle data to l2 responses

This commit is contained in:
Luke Steyn
2023-11-26 23:36:45 +01:00
parent 4f579e8dff
commit d8489b7590
4 changed files with 108 additions and 31 deletions

View File

@@ -11,9 +11,9 @@ import {
groupL2, groupL2,
isVariant, isVariant,
} from '@drift-labs/sdk'; } from '@drift-labs/sdk';
import { getOracleForMarket, l2WithBNToStrings } from '../utils/utils';
import { RedisClient } from '../utils/redisClient';
import { driftEnv } from '../publishers/dlobPublisher'; import { driftEnv } from '../publishers/dlobPublisher';
import { RedisClient } from '../utils/redisClient';
import { addOracletoResponse, l2WithBNToStrings } from '../utils/utils';
type wsMarketL2Args = { type wsMarketL2Args = {
marketIndex: number; marketIndex: number;
@@ -106,7 +106,8 @@ export class DLOBSubscriberIO extends DLOBSubscriber {
l2Formatted['marketName'] = marketName?.toUpperCase(); l2Formatted['marketName'] = marketName?.toUpperCase();
l2Formatted['marketType'] = marketType?.toLowerCase(); l2Formatted['marketType'] = marketType?.toLowerCase();
l2Formatted['marketIndex'] = l2Args.marketIndex; l2Formatted['marketIndex'] = l2Args.marketIndex;
l2Formatted['oracle'] = getOracleForMarket( addOracletoResponse(
l2Formatted,
this.driftClient, this.driftClient,
l2Args.marketType, l2Args.marketType,
l2Args.marketIndex l2Args.marketIndex

View File

@@ -1,48 +1,48 @@
import { program } from 'commander'; import { program } from 'commander';
import compression from 'compression';
import cors from 'cors';
import express from 'express'; import express from 'express';
import rateLimit from 'express-rate-limit'; import rateLimit from 'express-rate-limit';
import compression from 'compression';
import morgan from 'morgan'; import morgan from 'morgan';
import cors from 'cors';
import { Connection, Commitment, PublicKey, Keypair } from '@solana/web3.js'; import { Commitment, Connection, Keypair, PublicKey } from '@solana/web3.js';
import { import {
getVariant, BN,
DriftClient, BulkAccountLoader,
initialize, DLOBNode,
DriftEnv,
UserMap,
DLOBOrder, DLOBOrder,
DLOBOrders, DLOBOrders,
DLOBOrdersCoder, DLOBOrdersCoder,
DLOBNode,
isVariant,
BN,
groupL2,
Wallet,
UserStatsMap,
DLOBSubscriber, DLOBSubscriber,
BulkAccountLoader, DriftClient,
DriftEnv,
UserMap,
UserStatsMap,
Wallet,
getVariant,
groupL2,
initialize,
isVariant,
} from '@drift-labs/sdk'; } from '@drift-labs/sdk';
import { logger, setLogLevel } from './utils/logger'; import { logger, setLogLevel } from './utils/logger';
import { Mutex } from 'async-mutex';
import * as http from 'http'; import * as http from 'http';
import { handleHealthCheck } from './core/metrics';
import { handleResponseTime } from './core/middleware';
import { import {
l2WithBNToStrings,
sleep,
getOracleForMarket,
normalizeBatchQueryParams,
SubscriberLookup, SubscriberLookup,
addOracletoResponse,
errorHandler, errorHandler,
getPhoenixSubscriber, getPhoenixSubscriber,
getSerumSubscriber, getSerumSubscriber,
l2WithBNToStrings,
normalizeBatchQueryParams,
sleep,
validateDlobQuery, validateDlobQuery,
} from './utils/utils'; } from './utils/utils';
import { handleResponseTime } from './core/middleware';
import { handleHealthCheck } from './core/metrics';
import { Mutex } from 'async-mutex';
require('dotenv').config(); require('dotenv').config();
const driftEnv = (process.env.ENV || 'devnet') as DriftEnv; const driftEnv = (process.env.ENV || 'devnet') as DriftEnv;
@@ -639,7 +639,8 @@ const main = async () => {
groupL2(l2, groupingBN, finalDepth) groupL2(l2, groupingBN, finalDepth)
); );
if (`${includeOracle}`.toLowerCase() === 'true') { if (`${includeOracle}`.toLowerCase() === 'true') {
l2Formatted['oracle'] = getOracleForMarket( addOracletoResponse(
l2Formatted,
driftClient, driftClient,
normedMarketType, normedMarketType,
normedMarketIndex normedMarketIndex
@@ -652,7 +653,8 @@ const main = async () => {
// make the BNs into strings // make the BNs into strings
const l2Formatted = l2WithBNToStrings(l2); const l2Formatted = l2WithBNToStrings(l2);
if (`${includeOracle}`.toLowerCase() === 'true') { if (`${includeOracle}`.toLowerCase() === 'true') {
l2Formatted['oracle'] = getOracleForMarket( addOracletoResponse(
l2Formatted,
driftClient, driftClient,
normedMarketType, normedMarketType,
normedMarketIndex normedMarketIndex
@@ -760,7 +762,8 @@ const main = async () => {
groupL2(l2, groupingBN, finalDepth) groupL2(l2, groupingBN, finalDepth)
); );
if (`${normedParam['includeOracle']}`.toLowerCase() === 'true') { if (`${normedParam['includeOracle']}`.toLowerCase() === 'true') {
l2Formatted['oracle'] = getOracleForMarket( addOracletoResponse(
l2Formatted,
driftClient, driftClient,
normedMarketType, normedMarketType,
normedMarketIndex normedMarketIndex
@@ -771,7 +774,8 @@ const main = async () => {
// make the BNs into strings // make the BNs into strings
const l2Formatted = l2WithBNToStrings(l2); const l2Formatted = l2WithBNToStrings(l2);
if (`${normedParam['includeOracle']}`.toLowerCase() === 'true') { if (`${normedParam['includeOracle']}`.toLowerCase() === 'true') {
l2Formatted['oracle'] = getOracleForMarket( addOracletoResponse(
l2Formatted,
driftClient, driftClient,
normedMarketType, normedMarketType,
normedMarketIndex normedMarketIndex
@@ -821,7 +825,8 @@ const main = async () => {
} }
if (`${includeOracle}`.toLowerCase() === 'true') { if (`${includeOracle}`.toLowerCase() === 'true') {
l3['oracle'] = getOracleForMarket( addOracletoResponse(
l3,
driftClient, driftClient,
normedMarketType, normedMarketType,
normedMarketIndex normedMarketIndex
@@ -852,4 +857,4 @@ async function recursiveTryCatch(f: () => void) {
recursiveTryCatch(() => main()); recursiveTryCatch(() => main());
export { sdkConfig, endpoint, wsEndpoint, driftEnv, commitHash, driftClient }; export { commitHash, driftClient, driftEnv, endpoint, sdkConfig, wsEndpoint };

View File

@@ -0,0 +1,7 @@
// TODO : Is it worth adding proper infrastructure for feature flags? .. Would allow more powerful things like toggling them at runtime rather than being hardcoded
export const FEATURE_FLAGS = {
OLD_ORACLE_PRICE_IN_L2: true, // TODO : Remove this once we're confident that NEW_ORACLE_DATA_IN_L2 works .. delete corresponding code
NEW_ORACLE_DATA_IN_L2: true,
};
export default FEATURE_FLAGS;

View File

@@ -2,7 +2,9 @@ import {
DriftClient, DriftClient,
DriftEnv, DriftEnv,
L2OrderBook, L2OrderBook,
L3OrderBook,
MarketType, MarketType,
OraclePriceData,
PerpMarkets, PerpMarkets,
PhoenixSubscriber, PhoenixSubscriber,
PublicKey, PublicKey,
@@ -13,6 +15,7 @@ import {
} from '@drift-labs/sdk'; } from '@drift-labs/sdk';
import { logger } from './logger'; import { logger } from './logger';
import { NextFunction, Request, Response } from 'express'; import { NextFunction, Request, Response } from 'express';
import FEATURE_FLAGS from './featureFlags';
export const l2WithBNToStrings = (l2: L2OrderBook): any => { export const l2WithBNToStrings = (l2: L2OrderBook): any => {
for (const key of Object.keys(l2)) { for (const key of Object.keys(l2)) {
@@ -48,6 +51,67 @@ export const getOracleForMarket = (
} }
}; };
type SerializableOraclePriceData = {
price: string;
slot: string;
confidence: string;
hasSufficientNumberOfDataPoints: boolean;
twap?: string;
twapConfidence?: string;
};
const getSerializableOraclePriceData = (
oraclePriceData: OraclePriceData
): SerializableOraclePriceData => {
return {
price: oraclePriceData.price?.toString?.(),
slot: oraclePriceData.slot?.toString?.(),
confidence: oraclePriceData.confidence?.toString?.(),
hasSufficientNumberOfDataPoints:
oraclePriceData.hasSufficientNumberOfDataPoints,
twap: oraclePriceData.twap?.toString?.(),
twapConfidence: oraclePriceData.twapConfidence?.toString?.(),
};
};
export const getOracleDataForMarket = (
driftClient: DriftClient,
marketType: MarketType,
marketIndex: number
): SerializableOraclePriceData => {
if (isVariant(marketType, 'spot')) {
return getSerializableOraclePriceData(
driftClient.getOracleDataForSpotMarket(marketIndex)
);
} else if (isVariant(marketType, 'perp')) {
return getSerializableOraclePriceData(
driftClient.getOracleDataForPerpMarket(marketIndex)
);
}
};
export const addOracletoResponse = (
response: L2OrderBook | L3OrderBook,
driftClient: DriftClient,
marketType: MarketType,
marketIndex: number
): void => {
if (FEATURE_FLAGS.OLD_ORACLE_PRICE_IN_L2) {
response['oracle'] = getOracleForMarket(
driftClient,
marketType,
marketIndex
);
}
if (FEATURE_FLAGS.NEW_ORACLE_DATA_IN_L2) {
response['oracleData'] = getOracleDataForMarket(
driftClient,
marketType,
marketIndex
);
}
};
/** /**
* Takes in a req.query like: `{ * Takes in a req.query like: `{
* marketName: 'SOL-PERP,BTC-PERP,ETH-PERP', * marketName: 'SOL-PERP,BTC-PERP,ETH-PERP',