From 9baff8226228b6e7909ca64f1ae68c4ba8ced4fa Mon Sep 17 00:00:00 2001 From: Chris Heaney Date: Tue, 28 Nov 2023 19:53:36 -0500 Subject: [PATCH] init order subscriber flag --- src/dlobProvider.ts | 65 ++++++++++++++++++++++++++++++++++ src/index.ts | 85 +++++++++++++++++++++++++++++---------------- 2 files changed, 120 insertions(+), 30 deletions(-) create mode 100644 src/dlobProvider.ts diff --git a/src/dlobProvider.ts b/src/dlobProvider.ts new file mode 100644 index 0000000..bfa58f2 --- /dev/null +++ b/src/dlobProvider.ts @@ -0,0 +1,65 @@ +import {DLOB, OrderSubscriber, UserAccount, UserMap} from "@drift-labs/sdk"; +import {PublicKey} from "@solana/web3.js"; + +export type DLOBProvider = { + subscribe() : Promise; + getDLOB(slot: number): Promise; + getUniqueAuthorities(): PublicKey[]; + getUserAccounts(): Generator<{userAccount: UserAccount, publicKey: PublicKey}>; + getUserAccount(publicKey: PublicKey): UserAccount | undefined; + size(): number; +} + +export function getDLOBProviderFromUserMap(userMap:UserMap) : DLOBProvider { + return { + subscribe: async () => { + await userMap.subscribe(); + }, + getDLOB: async (slot: number) => { + return await userMap.getDLOB(slot); + }, + getUniqueAuthorities: () => { + return userMap.getUniqueAuthorities(); + }, + getUserAccounts: function*() { + for (const user of userMap.values()) { + yield {userAccount: user.getUserAccount(), publicKey: user.getUserAccountPublicKey()}; + } + }, + getUserAccount: (publicKey) => { + return userMap.get(publicKey.toString())?.getUserAccount(); + }, + size: () => { + return userMap.size(); + } + }; +} + +export function getDLOBProviderFromOrderSubscriber(orderSubscriber: OrderSubscriber) : DLOBProvider { + return { + subscribe: async () => { + await orderSubscriber.subscribe(); + }, + getDLOB: async (slot: number) => { + return await orderSubscriber.getDLOB(slot); + }, + getUniqueAuthorities: () => { + const authorities = new Set(); + for (const { userAccount } of orderSubscriber.usersAccounts.values()) { + authorities.add(userAccount.authority); + } + return Array.from(authorities.values()); + }, + getUserAccounts: function*() { + for (const [key, {userAccount}] of orderSubscriber.usersAccounts.entries()) { + yield {userAccount: userAccount, publicKey: new PublicKey(key)}; + } + }, + getUserAccount: (publicKey) => { + return orderSubscriber.usersAccounts.get(publicKey.toString())?.userAccount; + }, + size(): number { + return orderSubscriber.usersAccounts.size; + } + }; +} diff --git a/src/index.ts b/src/index.ts index 8caed26..f96be35 100644 --- a/src/index.ts +++ b/src/index.ts @@ -27,6 +27,7 @@ import { groupL2, initialize, isVariant, + OrderSubscriber, } from '@drift-labs/sdk'; import { logger, setLogLevel } from './utils/logger'; @@ -46,6 +47,7 @@ import { sleep, validateDlobQuery, } from './utils/utils'; +import {DLOBProvider, getDLOBProviderFromOrderSubscriber, getDLOBProviderFromUserMap} from "./dlobProvider"; require('dotenv').config(); const driftEnv = (process.env.ENV || 'devnet') as DriftEnv; @@ -57,6 +59,7 @@ const stateCommitment: Commitment = 'processed'; const serverPort = process.env.PORT || 6969; export const ORDERBOOK_UPDATE_INTERVAL = 1000; const useWebsocket = process.env.USE_WEBSOCKET?.toLowerCase() === 'true'; +const useOrderSubscriber = process.env.USE_ORDER_SUBSCRIBER?.toLowerCase() === 'true'; const rateLimitCallsPerSecond = process.env.RATE_LIMIT_CALLS_PER_SECOND ? parseInt(process.env.RATE_LIMIT_CALLS_PER_SECOND) @@ -196,6 +199,7 @@ const main = async () => { type: 'polling', accountLoader: bulkAccountLoader, }; + slotSource = { getSlot: () => bulkAccountLoader!.getSlot(), }; @@ -206,6 +210,7 @@ const main = async () => { }; slotSubscriber = new SlotSubscriber(connection); await slotSubscriber.subscribe(); + slotSource = { getSlot: () => slotSubscriber!.getSlot(), }; @@ -219,6 +224,40 @@ const main = async () => { env: driftEnv, }); + let dlobProvider : DLOBProvider; + if (useOrderSubscriber) { + let subscriptionConfig; + if (useWebsocket) { + subscriptionConfig = { + type: "websocket", + }; + } else { + subscriptionConfig = { + type: "polling", + frequency: ORDERBOOK_UPDATE_INTERVAL + }; + } + + const orderSubscriber = new OrderSubscriber({ + driftClient, + subscriptionConfig, + }); + + dlobProvider = getDLOBProviderFromOrderSubscriber(orderSubscriber); + + slotSource = { + getSlot: () => orderSubscriber.getSlot(), + }; + } else { + const userMap = new UserMap( + driftClient, + driftClient.userAccountSubscriptionConfig, + false + ); + + dlobProvider = getDLOBProviderFromUserMap(userMap); + } + const dlobCoder = DLOBOrdersCoder.create(); await driftClient.subscribe(); @@ -233,18 +272,13 @@ const main = async () => { const userStatsMap = new UserStatsMap(driftClient); - logger.info(`Initializing userMap...`); + logger.info(`Initializing DLOB Provider...`); const initUserMapStart = Date.now(); - const userMap = new UserMap( - driftClient, - driftClient.userAccountSubscriptionConfig, - false - ); - await userMap.subscribe(); - logger.info(`userMap initialized in ${Date.now() - initUserMapStart} ms`); + await dlobProvider.subscribe(); + logger.info(`dlob provider initialized in ${Date.now() - initUserMapStart} ms`); const initUserStatsMapStarts = Date.now(); - await userStatsMap.sync(userMap.getUniqueAuthorities()); + await userStatsMap.sync(dlobProvider.getUniqueAuthorities()); logger.info( `userStatsMap initialized in ${Date.now() - initUserStatsMapStarts} ms` ); @@ -253,7 +287,7 @@ const main = async () => { const initDlobSubscriberStart = Date.now(); const dlobSubscriber = new DLOBSubscriber({ driftClient, - dlobSource: userMap, + dlobSource: dlobProvider, slotSource, updateFrequency: ORDERBOOK_UPDATE_INTERVAL, }); @@ -267,7 +301,7 @@ const main = async () => { const handleStartup = async (_req, res, _next) => { if ( driftClient.isSubscribed && - userMap.size() > 0 && + dlobProvider.size() > 0 && userStatsMap.size() > 0 ) { res.writeHead(200); @@ -299,16 +333,14 @@ const main = async () => { }); } - for (const user of userMap.values()) { - const userAccount = user.getUserAccount(); - + for (const {userAccount, publicKey} of dlobProvider.getUserAccounts()) { for (const order of userAccount.orders) { if (isVariant(order.status, 'init')) { continue; } orders.push({ - user: user.getUserAccountPublicKey().toBase58(), + user: publicKey.toBase58(), order: order, }); } @@ -354,9 +386,7 @@ const main = async () => { } oracles.push(oracleHuman); } - for (const user of userMap.values()) { - const userAccount = user.getUserAccount(); - + for (const {userAccount, publicKey} of dlobProvider.getUserAccounts()) { for (const order of userAccount.orders) { if (isVariant(order.status, 'init')) { continue; @@ -394,7 +424,7 @@ const main = async () => { } orders.push({ - user: user.getUserAccountPublicKey().toBase58(), + user: publicKey.toBase58(), order: orderHuman, }); } @@ -418,16 +448,14 @@ const main = async () => { try { const dlobOrders: DLOBOrders = []; - for (const user of userMap.values()) { - const userAccount = user.getUserAccount(); - + for (const {userAccount, publicKey} of dlobProvider.getUserAccounts()) { for (const order of userAccount.orders) { if (isVariant(order.status, 'init')) { continue; } dlobOrders.push({ - user: user.getUserAccountPublicKey(), + user: publicKey, order, } as DLOBOrder); } @@ -468,9 +496,7 @@ const main = async () => { const dlobOrders: DLOBOrders = []; - for (const user of userMap.values()) { - const userAccount = user.getUserAccount(); - + for (const {userAccount, publicKey} of dlobProvider.getUserAccounts()) { for (const order of userAccount.orders) { if (isVariant(order.status, 'init')) { continue; @@ -486,7 +512,7 @@ const main = async () => { } dlobOrders.push({ - user: user.getUserAccountPublicKey(), + user: publicKey, order, } as DLOBOrder); } @@ -557,10 +583,9 @@ const main = async () => { continue; } else { if (`${includeUserStats}`.toLowerCase() === 'true') { - const userAccount = side.userAccount.toBase58(); - await userMap.mustGet(userAccount); + const userAccount = dlobProvider.getUserAccount(side.userAccount); const userStats = await userStatsMap.mustGet( - userMap.getUserAuthority(userAccount)!.toBase58() + userAccount.authority.toBase58() ); topMakers.add([ userAccount,