Skip to content

Commit

Permalink
Merge pull request #349 from drift-labs/master
Browse files Browse the repository at this point in the history
master -> mainnet
  • Loading branch information
lowkeynicc authored Jan 18, 2025
2 parents b5af7d6 + 9ea30fd commit 4e3ff30
Show file tree
Hide file tree
Showing 14 changed files with 186 additions and 156 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
"main": "lib/index.js",
"license": "Apache-2.0",
"dependencies": {
"@drift-labs/jit-proxy": "0.12.47",
"@drift-labs/sdk": "2.107.0-beta.3",
"@drift-labs/jit-proxy": "0.12.52",
"@drift-labs/sdk": "2.107.0-beta.8",
"@opentelemetry/api": "1.7.0",
"@opentelemetry/auto-instrumentations-node": "0.31.2",
"@opentelemetry/exporter-prometheus": "0.31.0",
Expand Down
35 changes: 31 additions & 4 deletions src/bots/filler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {
QUOTE_PRECISION,
ClockSubscriber,
DriftEnv,
PerpMarkets,
} from '@drift-labs/sdk';
import { Mutex, tryAcquire, E_ALREADY_LOCKED } from 'async-mutex';

Expand Down Expand Up @@ -75,6 +76,7 @@ import {
import { getErrorCode } from '../error';
import {
SimulateAndGetTxWithCUsResponse,
chunks,
getAllPythOracleUpdateIxs,
getFillSignatureFromUserAccountAndOrderId,
getNodeToFillSignature,
Expand All @@ -95,6 +97,7 @@ import { LRUCache } from 'lru-cache';
import { bs58 } from '@project-serum/anchor/dist/cjs/utils/bytes';
import { PythPriceFeedSubscriber } from '../pythPriceFeedSubscriber';
import { TxThreaded } from './common/txThreaded';
import { PythLazerSubscriber } from '../pythLazerSubscriber';

const TX_COUNT_COOLDOWN_ON_BURST = 10; // send this many tx before resetting burst mode
const FILL_ORDER_THROTTLE_BACKOFF = 1000; // the time to wait before trying to fill a throttled (error filling) node again
Expand Down Expand Up @@ -235,6 +238,7 @@ export class FillerBot extends TxThreaded implements Bot {
protected rebalanceSettledPnlThreshold: BN;

pythPriceSubscriber?: PythPriceFeedSubscriber;
pythLazerSubscriber?: PythLazerSubscriber;

constructor(
slotSubscriber: SlotSubscriber,
Expand Down Expand Up @@ -362,6 +366,25 @@ export class FillerBot extends TxThreaded implements Bot {
});

this.signerPubkey = this.driftClient.wallet.publicKey.toBase58();

// Pyth lazer: remember to remove devnet guard
if (this.globalConfig.driftEnv == 'devnet') {
if (!this.globalConfig.lazerEndpoint || !this.globalConfig.lazerToken) {
throw new Error('Missing lazerEndpoint or lazerToken in global config');
}

const markets = PerpMarkets[this.globalConfig.driftEnv!].filter(
(market) => market.pythLazerId !== undefined
);
const pythLazerIds = markets.map((m) => m.pythLazerId!);
const pythLazerIdsChunks = chunks(pythLazerIds, 5);
this.pythLazerSubscriber = new PythLazerSubscriber(
this.globalConfig.lazerEndpoint,
this.globalConfig.lazerToken,
pythLazerIdsChunks,
this.globalConfig.driftEnv
);
}
}

protected initializeMetrics(metricsPort?: number) {
Expand Down Expand Up @@ -512,6 +535,7 @@ export class FillerBot extends TxThreaded implements Bot {
);

await this.clockSubscriber.subscribe();
await this.pythLazerSubscriber?.subscribe();

this.lutAccounts.push(
await this.driftClient.fetchMarketLookupTableAccount()
Expand Down Expand Up @@ -1382,7 +1406,8 @@ export class FillerBot extends TxThreaded implements Bot {
}

private async getPythIxsFromNode(
node: NodeToFill | NodeToTrigger
node: NodeToFill | NodeToTrigger,
precedingIxs: TransactionInstruction[] = []
): Promise<TransactionInstruction[]> {
const marketIndex = node.node.order?.marketIndex;
if (marketIndex === undefined) {
Expand Down Expand Up @@ -1411,7 +1436,8 @@ export class FillerBot extends TxThreaded implements Bot {
MarketType.PERP,
this.pythPriceSubscriber!,
this.driftClient,
this.globalConfig.numNonActiveOraclesToPush ?? 0
this.pythLazerSubscriber,
precedingIxs
);
return pythIxs;
}
Expand Down Expand Up @@ -1703,9 +1729,10 @@ export class FillerBot extends TxThreaded implements Bot {
let removeLastIxPostSim = this.revertOnFailure;
if (
this.pythPriceSubscriber &&
this.pythLazerSubscriber &&
((makerInfos.length == 2 && !referrerInfo) || makerInfos.length < 2)
) {
const pythIxs = await this.getPythIxsFromNode(nodeToFill);
const pythIxs = await this.getPythIxsFromNode(nodeToFill, ixs);
ixs.push(...pythIxs);
removeLastIxPostSim = false;
}
Expand Down Expand Up @@ -1930,7 +1957,7 @@ export class FillerBot extends TxThreaded implements Bot {

let removeLastIxPostSim = this.revertOnFailure;
if (this.pythPriceSubscriber) {
const pythIxs = await this.getPythIxsFromNode(nodeToTrigger);
const pythIxs = await this.getPythIxsFromNode(nodeToTrigger, ixs);
ixs.push(...pythIxs);
removeLastIxPostSim = false;
}
Expand Down
41 changes: 37 additions & 4 deletions src/bots/makerBidAskTwapCrank.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
DriftMarketInfo,
isOneOfVariant,
getVariant,
PerpMarkets,
} from '@drift-labs/sdk';
import { Mutex } from 'async-mutex';

Expand All @@ -31,13 +32,15 @@ import {
import { webhookMessage } from '../webhook';
import { ConfirmOptions, Signer } from '@solana/web3.js';
import {
chunks,
getAllPythOracleUpdateIxs,
getDriftPriorityFeeEndpoint,
handleSimResultError,
simulateAndGetTxWithCUs,
SimulateAndGetTxWithCUsResponse,
} from '../utils';
import { PythPriceFeedSubscriber } from '../pythPriceFeedSubscriber';
import { PythLazerSubscriber } from '../pythLazerSubscriber';
import { PythPullClient } from '@drift-labs/sdk';
import { BundleSender } from '../bundleSender';

Expand Down Expand Up @@ -176,6 +179,7 @@ export class MakerBidAskTwapCrank implements Bot {
private watchdogTimerMutex = new Mutex();
private watchdogTimerLastPatTime = Date.now();
private pythPriceSubscriber?: PythPriceFeedSubscriber;
private pythLazerSubscriber?: PythLazerSubscriber;
private pythPullOracleClient: PythPullClient;
private pythHealthy: boolean = true;
private lookupTableAccounts: AddressLookupTableAccount[];
Expand Down Expand Up @@ -204,9 +208,30 @@ export class MakerBidAskTwapCrank implements Bot {
this.lookupTableAccounts = lookupTableAccounts;
this.pythPullOracleClient = new PythPullClient(this.driftClient.connection);
this.bundleSender = bundleSender;

// Pyth lazer: remember to remove devnet guard
if (this.globalConfig.driftEnv == 'devnet') {
if (!this.globalConfig.lazerEndpoint || !this.globalConfig.lazerToken) {
throw new Error('Missing lazerEndpoint or lazerToken in global config');
}

const markets = PerpMarkets[this.globalConfig.driftEnv!].filter(
(market) => market.pythLazerId !== undefined
);
const pythLazerIds = markets.map((m) => m.pythLazerId!);
const pythLazerIdsChunks = chunks(pythLazerIds, 10);
this.pythLazerSubscriber = new PythLazerSubscriber(
this.globalConfig.lazerEndpoint,
this.globalConfig.lazerToken,
pythLazerIdsChunks,
this.globalConfig.driftEnv
);
}
}

public async init() {
await this.pythLazerSubscriber?.subscribe();

logger.info(`[${this.name}] initing, runOnce: ${this.runOnce}`);
this.lookupTableAccounts.push(
await this.driftClient.fetchMarketLookupTableAccount()
Expand Down Expand Up @@ -403,7 +428,8 @@ export class MakerBidAskTwapCrank implements Bot {
}

private async getPythIxsFromTwapCrankInfo(
crankMarketIndex: number
crankMarketIndex: number,
precedingIxs: TransactionInstruction[] = []
): Promise<TransactionInstruction[]> {
if (crankMarketIndex === undefined) {
throw new Error('Market index not found on node');
Expand All @@ -417,7 +443,8 @@ export class MakerBidAskTwapCrank implements Bot {
MarketType.PERP,
this.pythPriceSubscriber!,
this.driftClient,
this.globalConfig.numNonActiveOraclesToPush ?? 0
this.pythLazerSubscriber,
precedingIxs
);
return pythIxs;
}
Expand Down Expand Up @@ -548,10 +575,16 @@ export class MakerBidAskTwapCrank implements Bot {
this.pythPriceSubscriber &&
isOneOfVariant(
this.driftClient.getPerpMarketAccount(mi)!.amm.oracleSource,
['pythPull', 'pyth1KPull', 'pyth1MPull', 'pythStableCoinPull']
[
'pythPull',
'pyth1KPull',
'pyth1MPull',
'pythStableCoinPull',
'pythLazer',
]
)
) {
const pythIxs = await this.getPythIxsFromTwapCrankInfo(mi);
const pythIxs = await this.getPythIxsFromTwapCrankInfo(mi, ixs);
ixs.push(...pythIxs);
pythIxsPushed = true;
} else if (usingSwitchboardOnDemand) {
Expand Down
25 changes: 19 additions & 6 deletions src/bots/pythLazerCranker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,12 @@ import { GlobalConfig, PythLazerCrankerBotConfig } from '../config';
import { PriceUpdateAccount } from '@pythnetwork/pyth-solana-receiver/lib/PythSolanaReceiver';
import {
BlockhashSubscriber,
DevnetPerpMarkets,
DevnetSpotMarkets,
DriftClient,
getPythLazerOraclePublicKey,
MainnetPerpMarkets,
MainnetSpotMarkets,
PriorityFeeSubscriber,
TxSigAndSlot,
} from '@drift-labs/sdk';
Expand Down Expand Up @@ -57,12 +61,21 @@ export class PythLazerCrankerBot implements Bot {
throw new Error('Only devnet drift env is supported');
}

const updateConfigs = this.crankConfigs.updateConfigs;
const feedIdChunks = chunks(Object.keys(updateConfigs), 11).map((chunk) =>
chunk.map((alias) => {
return updateConfigs[alias].feedId;
})
);
const spotMarkets =
this.globalConfig.driftEnv === 'mainnet-beta'
? DevnetSpotMarkets
: MainnetSpotMarkets;
const perpMarkets =
this.globalConfig.driftEnv === 'mainnet-beta'
? DevnetPerpMarkets
: MainnetPerpMarkets;

const allFeedIds = [
...spotMarkets.map((market) => market.pythLazerId),
...perpMarkets.map((market) => market.pythLazerId),
].filter((id) => id !== undefined) as number[];
const allFeedIdsSet = new Set(allFeedIds);
const feedIdChunks = chunks(Array.from(allFeedIdsSet), 11);

if (!this.globalConfig.lazerEndpoint || !this.globalConfig.lazerToken) {
throw new Error('Missing lazerEndpoint or lazerToken in global config');
Expand Down
27 changes: 0 additions & 27 deletions src/bots/spotFiller.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import {
DriftEnv,
DriftClient,
SpotMarketAccount,
MakerInfo,
Expand Down Expand Up @@ -69,7 +68,6 @@ import {
} from './common/txLogParse';
import { FillerConfig, GlobalConfig } from '../config';
import {
getAllPythOracleUpdateIxs,
getFillSignatureFromUserAccountAndOrderId,
getNodeToFillSignature,
getNodeToTriggerSignature,
Expand Down Expand Up @@ -97,7 +95,6 @@ import {
import { selectMakers } from '../makerSelection';
import { LRUCache } from 'lru-cache';
import { bs58 } from '@project-serum/anchor/dist/cjs/utils/bytes';
import { PythPriceFeedSubscriber } from '../pythPriceFeedSubscriber';
import { FallbackLiquiditySource } from '../experimental-bots/filler-common/types';

const THROTTLED_NODE_SIZE_TO_PRUNE = 10; // Size of throttled nodes to get to before pruning the map
Expand Down Expand Up @@ -319,7 +316,6 @@ export class SpotFillerBot implements Bot {
protected minGasBalanceToFill: number;
protected rebalanceSettledPnlThreshold: BN;

protected pythPriceSubscriber?: PythPriceFeedSubscriber;
protected lookupTableAccounts: AddressLookupTableAccount[];

constructor(
Expand All @@ -331,7 +327,6 @@ export class SpotFillerBot implements Bot {
priorityFeeSubscriber: PriorityFeeSubscriber,
blockhashSubscriber: BlockhashSubscriber,
bundleSender?: BundleSender,
pythPriceSubscriber?: PythPriceFeedSubscriber,
lookupTableAccounts: AddressLookupTableAccount[] = []
) {
this.globalConfig = globalConfig;
Expand Down Expand Up @@ -389,7 +384,6 @@ export class SpotFillerBot implements Bot {
`${this.name}: rebalancing enabled: ${this.jupiterClient !== undefined}`
);

this.pythPriceSubscriber = pythPriceSubscriber;
this.lookupTableAccounts = lookupTableAccounts;

this.userMap = userMap;
Expand Down Expand Up @@ -1707,27 +1701,6 @@ export class SpotFillerBot implements Bot {
}
}

private async getPythIxsFromNode(
node: NodeToFill | NodeToTrigger
): Promise<TransactionInstruction[]> {
const marketIndex = node.node.order?.marketIndex;
if (marketIndex === undefined) {
throw new Error('Market index not found on node');
}
if (!this.pythPriceSubscriber) {
throw new Error('Pyth price subscriber not initialized');
}
const pythIxs = await getAllPythOracleUpdateIxs(
this.runtimeSpec.driftEnv as DriftEnv,
marketIndex,
MarketType.SPOT,
this.pythPriceSubscriber!,
this.driftClient,
this.globalConfig.numNonActiveOraclesToPush ?? 0
);
return pythIxs;
}

/**
*
* @param fillTxId id of current fill
Expand Down
2 changes: 0 additions & 2 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,6 @@ export interface GlobalConfig {
hermesEndpoint?: string;
lazerEndpoint?: string;
lazerToken?: string;
numNonActiveOraclesToPush?: number;

// Optional to specify markets loaded by drift client
perpMarketsToLoad?: Array<number>;
Expand Down Expand Up @@ -247,7 +246,6 @@ const defaultConfig: Partial<Config> = {

endpoint: process.env.ENDPOINT!,
hermesEndpoint: process.env.HERMES_ENDPOINT,
numNonActiveOraclesToPush: 0,
wsEndpoint: process.env.WS_ENDPOINT,
heliusEndpoint: process.env.HELIUS_ENDPOINT,
additionalSendTxEndpoints: [],
Expand Down
4 changes: 2 additions & 2 deletions src/experimental-bots/filler-common/dlobBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ class DLOBBuilder {
) {
return;
}
this.dlob.insertOrder(
dlob.insertOrder(
order,
pubkey,
this.slotSubscriber.getSlot(),
Expand All @@ -192,7 +192,7 @@ class DLOBBuilder {
slot,
}: SwiftOrderParamsMessage = this.driftClient.program.coder.types.decode(
'SwiftOrderParamsMessage',
Buffer.from(orderData['order_message'], 'base64')
Buffer.from(orderData['order_message'], 'hex')
);

const takerAuthority = new PublicKey(orderData['taker_authority']);
Expand Down
Loading

0 comments on commit 4e3ff30

Please sign in to comment.