Updated to use same formatting as monorepo

This commit is contained in:
Luke Steyn
2023-05-31 23:08:37 +09:00
parent a86a1f0e3e
commit c0c97c9b63
5 changed files with 771 additions and 763 deletions

8
.prettierrc.js Normal file
View File

@@ -0,0 +1,8 @@
module.exports = {
semi: true,
trailingComma: 'es5',
singleQuote: true,
printWidth: 80,
tabWidth: 2,
useTabs: true,
};

4
.vscode/launch.json vendored
View File

@@ -10,7 +10,7 @@
"name": "Debug", "name": "Debug",
"port": 2230, "port": 2230,
"timeout": 3000, "timeout": 3000,
"restart": true, "restart": true
}, }
] ]
} }

View File

@@ -1,13 +1,13 @@
import { program, Option } from "commander"; import { program, Option } from 'commander';
import responseTime = require("response-time"); import responseTime = require('response-time');
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 compression from 'compression';
import morgan from "morgan"; import morgan from 'morgan';
import cors from "cors"; import cors from 'cors';
import { Connection, Commitment, PublicKey } from "@solana/web3.js"; import { Connection, Commitment, PublicKey } from '@solana/web3.js';
import { import {
getVariant, getVariant,
@@ -27,29 +27,29 @@ import {
SpotMarketConfig, SpotMarketConfig,
PhoenixSubscriber, PhoenixSubscriber,
SerumSubscriber, SerumSubscriber,
} from "@drift-labs/sdk"; } from '@drift-labs/sdk';
import { Mutex } from "async-mutex"; import { Mutex } from 'async-mutex';
import { getWallet } from "./utils"; import { getWallet } from './utils';
import { logger, setLogLevel } from "./logger"; import { logger, setLogLevel } from './logger';
import { PrometheusExporter } from "@opentelemetry/exporter-prometheus"; import { PrometheusExporter } from '@opentelemetry/exporter-prometheus';
import { import {
ExplicitBucketHistogramAggregation, ExplicitBucketHistogramAggregation,
InstrumentType, InstrumentType,
MeterProvider, MeterProvider,
View, View,
} from "@opentelemetry/sdk-metrics-base"; } from '@opentelemetry/sdk-metrics-base';
import { ObservableResult } from "@opentelemetry/api"; import { ObservableResult } from '@opentelemetry/api';
require("dotenv").config(); require('dotenv').config();
const driftEnv = (process.env.ENV || "devnet") as DriftEnv; const driftEnv = (process.env.ENV || 'devnet') as DriftEnv;
const commitHash = process.env.COMMIT; const commitHash = process.env.COMMIT;
//@ts-ignore //@ts-ignore
const sdkConfig = initialize({ env: process.env.ENV }); const sdkConfig = initialize({ env: process.env.ENV });
const stateCommitment: Commitment = "confirmed"; const stateCommitment: Commitment = 'confirmed';
const serverPort = process.env.PORT || 6969; const serverPort = process.env.PORT || 6969;
const bulkAccountLoaderPollingInterval = process.env const bulkAccountLoaderPollingInterval = process.env
@@ -70,13 +70,13 @@ const logHttp = morgan(logFormat, {
function errorHandler(err, _req, res, _next) { function errorHandler(err, _req, res, _next) {
logger.error(err.stack); logger.error(err.stack);
res.status(500).send("Internal error"); res.status(500).send('Internal error');
} }
const app = express(); const app = express();
app.use(cors({ origin: "*" })); app.use(cors({ origin: '*' }));
app.use(compression()); app.use(compression());
app.set("trust proxy", 1); app.set('trust proxy', 1);
app.use(logHttp); app.use(logHttp);
app.use( app.use(
@@ -90,29 +90,29 @@ app.use(
// strip off /dlob, if the request comes from exchange history server LB // strip off /dlob, if the request comes from exchange history server LB
app.use((req, _res, next) => { app.use((req, _res, next) => {
if (req.url.startsWith("/dlob")) { if (req.url.startsWith('/dlob')) {
req.url = req.url.replace("/dlob", ""); req.url = req.url.replace('/dlob', '');
if (req.url === "") { if (req.url === '') {
req.url = "/"; req.url = '/';
} }
} }
next(); next();
}); });
program program
.option("-d, --dry-run", "Dry run, do not send transactions on chain") .option('-d, --dry-run', 'Dry run, do not send transactions on chain')
.option("--test-liveness", "Purposefully fail liveness test after 1 minute") .option('--test-liveness', 'Purposefully fail liveness test after 1 minute')
.addOption( .addOption(
new Option( new Option(
"-p, --private-key <string>", '-p, --private-key <string>',
"private key, supports path to id.json, or list of comma separate numbers" 'private key, supports path to id.json, or list of comma separate numbers'
).env("ANCHOR_PRIVATE_KEY") ).env('ANCHOR_PRIVATE_KEY')
) )
.option("--debug", "Enable debug logging") .option('--debug', 'Enable debug logging')
.parse(); .parse();
const opts = program.opts(); const opts = program.opts();
setLogLevel(opts.debug ? "debug" : "info"); setLogLevel(opts.debug ? 'debug' : 'info');
const endpoint = process.env.ENDPOINT; const endpoint = process.env.ENDPOINT;
const wsEndpoint = process.env.WS_ENDPOINT; const wsEndpoint = process.env.WS_ENDPOINT;
@@ -143,9 +143,9 @@ const createHistogramBuckets = (
}; };
enum METRIC_TYPES { enum METRIC_TYPES {
runtime_specs = "runtime_specs", runtime_specs = 'runtime_specs',
endpoint_response_times_histogram = "endpoint_response_times_histogram", endpoint_response_times_histogram = 'endpoint_response_times_histogram',
health_status = "health_status", health_status = 'health_status',
} }
export enum HEALTH_STATUS { export enum HEALTH_STATUS {
@@ -169,7 +169,7 @@ const exporter = new PrometheusExporter(
); );
} }
); );
const meterName = "dlob-meter"; const meterName = 'dlob-meter';
const meterProvider = new MeterProvider({ const meterProvider = new MeterProvider({
views: [ views: [
new View({ new View({
@@ -186,7 +186,7 @@ const meter = meterProvider.getMeter(meterName);
const runtimeSpecsGauge = meter.createObservableGauge( const runtimeSpecsGauge = meter.createObservableGauge(
METRIC_TYPES.runtime_specs, METRIC_TYPES.runtime_specs,
{ {
description: "Runtime sepcification of this program", description: 'Runtime sepcification of this program',
} }
); );
const bootTimeMs = Date.now(); const bootTimeMs = Date.now();
@@ -203,7 +203,7 @@ let healthStatus: HEALTH_STATUS = HEALTH_STATUS.Ok;
const healthStatusGauge = meter.createObservableGauge( const healthStatusGauge = meter.createObservableGauge(
METRIC_TYPES.health_status, METRIC_TYPES.health_status,
{ {
description: "Health status of this program", description: 'Health status of this program',
} }
); );
healthStatusGauge.addCallback((obs: ObservableResult) => { healthStatusGauge.addCallback((obs: ObservableResult) => {
@@ -213,8 +213,8 @@ healthStatusGauge.addCallback((obs: ObservableResult) => {
const endpointResponseTimeHistogram = meter.createHistogram( const endpointResponseTimeHistogram = meter.createHistogram(
METRIC_TYPES.endpoint_response_times_histogram, METRIC_TYPES.endpoint_response_times_histogram,
{ {
description: "Duration of endpoint responses", description: 'Duration of endpoint responses',
unit: "ms", unit: 'ms',
} }
); );
@@ -228,7 +228,7 @@ const getPhoenixSubscriber = (
programId: new PublicKey(sdkConfig.PHOENIX), programId: new PublicKey(sdkConfig.PHOENIX),
marketAddress: marketConfig.phoenixMarket, marketAddress: marketConfig.phoenixMarket,
accountSubscription: { accountSubscription: {
type: "polling", type: 'polling',
accountLoader, accountLoader,
}, },
}); });
@@ -244,7 +244,7 @@ const getSerumSubscriber = (
programId: new PublicKey(sdkConfig.SERUM_V3), programId: new PublicKey(sdkConfig.SERUM_V3),
marketAddress: marketConfig.serumMarket, marketAddress: marketConfig.serumMarket,
accountSubscription: { accountSubscription: {
type: "polling", type: 'polling',
accountLoader, accountLoader,
}, },
}); });
@@ -322,7 +322,7 @@ const main = async () => {
return { publicKey: mkt.oracle, source: mkt.oracleSource }; return { publicKey: mkt.oracle, source: mkt.oracleSource };
}), }),
accountSubscription: { accountSubscription: {
type: "polling", type: 'polling',
accountLoader: bulkAccountLoader, accountLoader: bulkAccountLoader,
}, },
env: driftEnv, env: driftEnv,
@@ -345,13 +345,13 @@ const main = async () => {
logger.info(` . SOL balance: ${lamportsBalance / 10 ** 9}`); logger.info(` . SOL balance: ${lamportsBalance / 10 ** 9}`);
await driftClient.subscribe(); await driftClient.subscribe();
driftClient.eventEmitter.on("error", (e) => { driftClient.eventEmitter.on('error', (e) => {
logger.info("clearing house error"); logger.info('clearing house error');
logger.error(e); logger.error(e);
}); });
await slotSubscriber.subscribe(); await slotSubscriber.subscribe();
slotSubscriber.eventEmitter.on("newSlot", async (slot: number) => { slotSubscriber.eventEmitter.on('newSlot', async (slot: number) => {
await lastSlotReceivedMutex.runExclusive(async () => { await lastSlotReceivedMutex.runExclusive(async () => {
lastSlotReceived = slot; lastSlotReceived = slot;
}); });
@@ -398,15 +398,15 @@ const main = async () => {
); );
// start http server listening to /health endpoint using http package // start http server listening to /health endpoint using http package
app.get("/health", handleResponseTime, async (req, res, next) => { app.get('/health', handleResponseTime, async (req, res, next) => {
try { try {
if (req.url === "/health") { if (req.url === '/health') {
if (opts.testLiveness) { if (opts.testLiveness) {
if (Date.now() > startupTime + 60 * 1000) { if (Date.now() > startupTime + 60 * 1000) {
healthStatus = HEALTH_STATUS.LivenessTesting; healthStatus = HEALTH_STATUS.LivenessTesting;
res.writeHead(500); res.writeHead(500);
res.end("Testing liveness test fail"); res.end('Testing liveness test fail');
return; return;
} }
} }
@@ -466,17 +466,17 @@ const main = async () => {
// liveness check passed // liveness check passed
healthStatus = HEALTH_STATUS.Ok; healthStatus = HEALTH_STATUS.Ok;
res.writeHead(200); res.writeHead(200);
res.end("OK"); res.end('OK');
} else { } else {
res.writeHead(404); res.writeHead(404);
res.end("Not found"); res.end('Not found');
} }
} catch (e) { } catch (e) {
next(e); next(e);
} }
}); });
app.get("/orders/json/raw", handleResponseTime, async (_req, res, next) => { app.get('/orders/json/raw', handleResponseTime, async (_req, res, next) => {
try { try {
// object with userAccount key and orders object serialized // object with userAccount key and orders object serialized
const orders: Array<any> = []; const orders: Array<any> = [];
@@ -497,7 +497,7 @@ const main = async () => {
const userAccount = user.getUserAccount(); const userAccount = user.getUserAccount();
for (const order of userAccount.orders) { for (const order of userAccount.orders) {
if (getVariant(order.status) === "init") { if (getVariant(order.status) === 'init') {
continue; continue;
} }
@@ -522,7 +522,7 @@ const main = async () => {
} }
}); });
app.get("/orders/json", handleResponseTime, async (_req, res, next) => { app.get('/orders/json', handleResponseTime, async (_req, res, next) => {
try { try {
// object with userAccount key and orders object serialized // object with userAccount key and orders object serialized
const slot = bulkAccountLoader.mostRecentSlot; const slot = bulkAccountLoader.mostRecentSlot;
@@ -541,10 +541,10 @@ const main = async () => {
oracle.hasSufficientNumberOfDataPoints, oracle.hasSufficientNumberOfDataPoints,
}; };
if (oracle.twap) { if (oracle.twap) {
oracleHuman["twap"] = oracle.twap.toString(); oracleHuman['twap'] = oracle.twap.toString();
} }
if (oracle.twapConfidence) { if (oracle.twapConfidence) {
oracleHuman["twapConfidence"] = oracle.twapConfidence.toString(); oracleHuman['twapConfidence'] = oracle.twapConfidence.toString();
} }
oracles.push(oracleHuman); oracles.push(oracleHuman);
} }
@@ -552,7 +552,7 @@ const main = async () => {
const userAccount = user.getUserAccount(); const userAccount = user.getUserAccount();
for (const order of userAccount.orders) { for (const order of userAccount.orders) {
if (getVariant(order.status) === "init") { if (getVariant(order.status) === 'init') {
continue; continue;
} }
@@ -584,7 +584,7 @@ const main = async () => {
maxTs: order.maxTs.toString(), maxTs: order.maxTs.toString(),
}; };
if (order.quoteAssetAmount) { if (order.quoteAssetAmount) {
orderHuman["quoteAssetAmount"] = order.quoteAssetAmount.toString(); orderHuman['quoteAssetAmount'] = order.quoteAssetAmount.toString();
} }
orders.push({ orders.push({
@@ -608,7 +608,7 @@ const main = async () => {
} }
}); });
app.get("/orders/idl", handleResponseTime, async (_req, res, next) => { app.get('/orders/idl', handleResponseTime, async (_req, res, next) => {
try { try {
const dlobOrders: DLOBOrders = []; const dlobOrders: DLOBOrders = [];
@@ -616,7 +616,7 @@ const main = async () => {
const userAccount = user.getUserAccount(); const userAccount = user.getUserAccount();
for (const order of userAccount.orders) { for (const order of userAccount.orders) {
if (getVariant(order.status) === "init") { if (getVariant(order.status) === 'init') {
continue; continue;
} }
@@ -634,7 +634,7 @@ const main = async () => {
} }
}); });
app.get("/orders/idlWithSlot", handleResponseTime, async (req, res, next) => { app.get('/orders/idlWithSlot', handleResponseTime, async (req, res, next) => {
try { try {
const { marketName, marketIndex, marketType } = req.query; const { marketName, marketIndex, marketType } = req.query;
const { normedMarketType, normedMarketIndex, error } = validateDlobQuery( const { normedMarketType, normedMarketIndex, error } = validateDlobQuery(
@@ -664,7 +664,7 @@ const main = async () => {
const userAccount = user.getUserAccount(); const userAccount = user.getUserAccount();
for (const order of userAccount.orders) { for (const order of userAccount.orders) {
if (getVariant(order.status) === "init") { if (getVariant(order.status) === 'init') {
continue; continue;
} }
@@ -687,7 +687,7 @@ const main = async () => {
res.end( res.end(
JSON.stringify({ JSON.stringify({
slot: bulkAccountLoader.mostRecentSlot, slot: bulkAccountLoader.mostRecentSlot,
data: dlobCoder.encode(dlobOrders).toString("base64"), data: dlobCoder.encode(dlobOrders).toString('base64'),
}) })
); );
} catch (err) { } catch (err) {
@@ -711,13 +711,13 @@ const main = async () => {
if (marketIndex === undefined || marketType === undefined) { if (marketIndex === undefined || marketType === undefined) {
return { return {
error: error:
"Bad Request: (marketName) or (marketIndex and marketType) must be supplied", 'Bad Request: (marketName) or (marketIndex and marketType) must be supplied',
}; };
} }
// validate marketType // validate marketType
switch ((marketType as string).toLowerCase()) { switch ((marketType as string).toLowerCase()) {
case "spot": { case 'spot': {
normedMarketType = MarketType.SPOT; normedMarketType = MarketType.SPOT;
normedMarketIndex = parseInt(marketIndex as string); normedMarketIndex = parseInt(marketIndex as string);
const spotMarketIndicies = SpotMarkets[driftEnv].map( const spotMarketIndicies = SpotMarkets[driftEnv].map(
@@ -725,12 +725,12 @@ const main = async () => {
); );
if (!spotMarketIndicies.includes(normedMarketIndex)) { if (!spotMarketIndicies.includes(normedMarketIndex)) {
return { return {
error: "Bad Request: invalid marketIndex", error: 'Bad Request: invalid marketIndex',
}; };
} }
break; break;
} }
case "perp": { case 'perp': {
normedMarketType = MarketType.PERP; normedMarketType = MarketType.PERP;
normedMarketIndex = parseInt(marketIndex as string); normedMarketIndex = parseInt(marketIndex as string);
const perpMarketIndicies = PerpMarkets[driftEnv].map( const perpMarketIndicies = PerpMarkets[driftEnv].map(
@@ -738,7 +738,7 @@ const main = async () => {
); );
if (!perpMarketIndicies.includes(normedMarketIndex)) { if (!perpMarketIndicies.includes(normedMarketIndex)) {
return { return {
error: "Bad Request: invalid marketIndex", error: 'Bad Request: invalid marketIndex',
}; };
} }
break; break;
@@ -755,7 +755,7 @@ const main = async () => {
driftClient.getMarketIndexAndType(normedMarketName); driftClient.getMarketIndexAndType(normedMarketName);
if (!derivedMarketInfo) { if (!derivedMarketInfo) {
return { return {
error: "Bad Request: unrecognized marketName", error: 'Bad Request: unrecognized marketName',
}; };
} }
normedMarketType = derivedMarketInfo.marketType; normedMarketType = derivedMarketInfo.marketType;
@@ -768,7 +768,7 @@ const main = async () => {
}; };
}; };
app.get("/l2", handleResponseTime, async (req, res, next) => { app.get('/l2', handleResponseTime, async (req, res, next) => {
try { try {
const { const {
marketName, marketName,
@@ -790,18 +790,18 @@ const main = async () => {
return; return;
} }
const isSpot = marketType === "spot"; const isSpot = marketType === 'spot';
const l2 = await dlobSubscriber.getL2({ const l2 = await dlobSubscriber.getL2({
marketIndex: normedMarketIndex, marketIndex: normedMarketIndex,
marketType: normedMarketType, marketType: normedMarketType,
depth: depth ? parseInt(depth as string) : 10, depth: depth ? parseInt(depth as string) : 10,
includeVamm: `${includeVamm}`.toLowerCase() === "true", includeVamm: `${includeVamm}`.toLowerCase() === 'true',
fallbackL2Generators: isSpot fallbackL2Generators: isSpot
? [ ? [
`${includePhoenix}`.toLowerCase() === "true" && `${includePhoenix}`.toLowerCase() === 'true' &&
MARKET_SUBSCRIBERS[normedMarketIndex].phoenix, MARKET_SUBSCRIBERS[normedMarketIndex].phoenix,
`${includeSerum}`.toLowerCase() === "true" && `${includeSerum}`.toLowerCase() === 'true' &&
MARKET_SUBSCRIBERS[normedMarketIndex].serum, MARKET_SUBSCRIBERS[normedMarketIndex].serum,
].filter((a) => !!a) ].filter((a) => !!a)
: [], : [],
@@ -810,7 +810,7 @@ const main = async () => {
for (const key of Object.keys(l2)) { for (const key of Object.keys(l2)) {
for (const idx in l2[key]) { for (const idx in l2[key]) {
const level = l2[key][idx]; const level = l2[key][idx];
const sources = level["sources"]; const sources = level['sources'];
for (const sourceKey of Object.keys(sources)) { for (const sourceKey of Object.keys(sources)) {
sources[sourceKey] = sources[sourceKey].toString(); sources[sourceKey] = sources[sourceKey].toString();
} }
@@ -829,7 +829,7 @@ const main = async () => {
} }
}); });
app.get("/l3", handleResponseTime, async (req, res, next) => { app.get('/l3', handleResponseTime, async (req, res, next) => {
try { try {
const { marketName, marketIndex, marketType } = req.query; const { marketName, marketIndex, marketType } = req.query;

View File

@@ -1,4 +1,4 @@
import { createLogger, transports, format } from "winston"; import { createLogger, transports, format } from 'winston';
export const logger = createLogger({ export const logger = createLogger({
transports: [new transports.Console()], transports: [new transports.Console()],

View File

@@ -1,15 +1,15 @@
import fs from "fs"; import fs from 'fs';
import { Keypair } from "@solana/web3.js"; import { Keypair } from '@solana/web3.js';
import { bs58 } from "@project-serum/anchor/dist/cjs/utils/bytes"; import { bs58 } from '@project-serum/anchor/dist/cjs/utils/bytes';
import { Wallet } from "@drift-labs/sdk"; import { Wallet } from '@drift-labs/sdk';
import { logger } from "./logger"; import { logger } from './logger';
export function getWallet(): Wallet { export function getWallet(): Wallet {
const privateKey = process.env.ANCHOR_PRIVATE_KEY; const privateKey = process.env.ANCHOR_PRIVATE_KEY;
if (!privateKey) { if (!privateKey) {
throw new Error( throw new Error(
"Must set environment variable ANCHOR_PRIVATE_KEY with the path to a id.json or a list of commma separated numbers" 'Must set environment variable ANCHOR_PRIVATE_KEY with the path to a id.json or a list of commma separated numbers'
); );
} }
// try to load privateKey as a filepath // try to load privateKey as a filepath
@@ -20,10 +20,10 @@ export function getWallet(): Wallet {
JSON.parse(fs.readFileSync(privateKey).toString()) JSON.parse(fs.readFileSync(privateKey).toString())
); );
} else { } else {
if (privateKey.includes(",")) { if (privateKey.includes(',')) {
logger.info(`Trying to load private key as comma separated numbers`); logger.info(`Trying to load private key as comma separated numbers`);
loadedKey = Uint8Array.from( loadedKey = Uint8Array.from(
privateKey.split(",").map((val) => Number(val)) privateKey.split(',').map((val) => Number(val))
); );
} else { } else {
logger.info(`Trying to load private key as base58 string`); logger.info(`Trying to load private key as base58 string`);