Skip to content

Commit

Permalink
clean up PriorityFeeSubscriber, add helius method
Browse files Browse the repository at this point in the history
  • Loading branch information
wphan committed Jan 28, 2024
1 parent d1e519c commit 1f78a8a
Show file tree
Hide file tree
Showing 11 changed files with 185 additions and 94 deletions.
16 changes: 15 additions & 1 deletion example.config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,23 @@ global:

# RPC endpoint to use
endpoint: https://api.mainnet-beta.solana.com
# custom websocket endpoint to use (if null will be determined from rpc endpoint)

# Custom websocket endpoint to use (if null will be determined from `endpoint``)
# Note: the default wsEndpoint value simply replaces http(s) with ws(s), so if
# your RPC provider requires a special path (i.e. /ws) for websocket connections
# you must set this.
wsEndpoint:

# optional if you want to use helius' global priority fee method AND `endpoint` is not
# already a helius url.
heliusEndpoint:

# `solana` or `helius`. If `helius` `endpoint` must be a helius RPC, or `heliusEndpoint`
# must be set
# solana: uses https://solana.com/docs/rpc/http/getrecentprioritizationfees
# helius: uses https://docs.helius.dev/solana-rpc-nodes/alpha-priority-fee-api
priorityFeeMethod: solana

# Private key to use to sign transactions.
# will load from KEEPER_PRIVATE_KEY env var if null
keeperPrivateKey:
Expand Down
15 changes: 6 additions & 9 deletions src/bots/filler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,7 @@ export class FillerBot implements Bot {
eventSubscriber: EventSubscriber | undefined,
runtimeSpec: RuntimeSpec,
config: FillerConfig,
priorityFeeSubscriber: PriorityFeeSubscriber,
jitoSearcherClient?: SearcherClient,
jitoAuthKeypair?: Keypair,
tipPayerKeypair?: Keypair
Expand Down Expand Up @@ -350,13 +351,11 @@ export class FillerBot implements Bot {
}`
);

this.priorityFeeSubscriber = new PriorityFeeSubscriber({
connection: this.driftClient.connection,
frequencyMs: 5000,
addresses: [
new PublicKey('8BnEgHoWFysVcuFFX7QztDmzuH8r5ZFvyP3sYwn1XTh6'), // Openbook SOL/USDC is good indicator of fees
],
});
this.priorityFeeSubscriber = priorityFeeSubscriber;
this.priorityFeeSubscriber.updateAddresses([
new PublicKey('8BnEgHoWFysVcuFFX7QztDmzuH8r5ZFvyP3sYwn1XTh6'), // Openbook SOL/USDC
new PublicKey('8UJgxaiQx5nTrdDgph5FiahMmzduuLTLf5WmsPegYA6W'), // sol-perp
]);
}

protected initializeMetrics() {
Expand Down Expand Up @@ -575,8 +574,6 @@ export class FillerBot implements Bot {
this.lookupTableAccount =
await this.driftClient.fetchMarketLookupTableAccount();

await this.priorityFeeSubscriber.subscribe();

await webhookMessage(`[${this.name}]: started`);
}

Expand Down
3 changes: 3 additions & 0 deletions src/bots/fillerLite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
OrderSubscriber,
UserAccount,
User,
PriorityFeeSubscriber,
} from '@drift-labs/sdk';

import { Keypair, PublicKey } from '@solana/web3.js';
Expand All @@ -28,6 +29,7 @@ export class FillerLiteBot extends FillerBot {
driftClient: DriftClient,
runtimeSpec: RuntimeSpec,
config: FillerConfig,
priorityFeeSubscriber: PriorityFeeSubscriber,
jitoSearcherClient?: SearcherClient,
jitoAuthKeypair?: Keypair,
tipPayerKeypair?: Keypair
Expand All @@ -40,6 +42,7 @@ export class FillerLiteBot extends FillerBot {
undefined,
runtimeSpec,
config,
priorityFeeSubscriber,
jitoSearcherClient,
jitoAuthKeypair,
tipPayerKeypair
Expand Down
15 changes: 6 additions & 9 deletions src/bots/jitMaker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ export class JitMaker implements Bot {
driftClient: DriftClient, // driftClient needs to have correct number of subaccounts listed
jitter: JitterSniper | JitterShotgun,
config: JitMakerConfig,
driftEnv: DriftEnv
driftEnv: DriftEnv,
priorityFeeSubscriber: PriorityFeeSubscriber
) {
this.subAccountIds = config.subaccounts ?? [0];
this.marketIndexes = config.perpMarketIndicies ?? [0];
Expand Down Expand Up @@ -107,13 +108,10 @@ export class JitMaker implements Bot {
driftClient: this.driftClient,
});

this.priorityFeeSubscriber = new PriorityFeeSubscriber({
connection: this.driftClient.connection,
frequencyMs: 5000,
addresses: [
new PublicKey('8UJgxaiQx5nTrdDgph5FiahMmzduuLTLf5WmsPegYA6W'), // sol-perp
],
});
this.priorityFeeSubscriber = priorityFeeSubscriber;
this.priorityFeeSubscriber.updateAddresses([
new PublicKey('8UJgxaiQx5nTrdDgph5FiahMmzduuLTLf5WmsPegYA6W'), // sol-perp
]);
}

/**
Expand All @@ -125,7 +123,6 @@ export class JitMaker implements Bot {
// do stuff that takes some time
await this.slotSubscriber.subscribe();
await this.dlobSubscriber.subscribe();
await this.priorityFeeSubscriber.subscribe();

logger.info(`${this.name} init done`);
}
Expand Down
15 changes: 5 additions & 10 deletions src/bots/liquidator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,7 @@ export class LiquidatorBot implements Bot {
runtimeSpec: RuntimeSpec,
config: LiquidatorConfig,
defaultSubaccountId: number,
priorityFeeSubscriber: PriorityFeeSubscriber,
SERUM_LOOKUP_TABLE?: PublicKey
) {
this.liquidatorConfig = config;
Expand Down Expand Up @@ -521,14 +522,10 @@ export class LiquidatorBot implements Bot {
connection: this.driftClient.connection,
});
}

this.priorityFeeSubscriber = new PriorityFeeSubscriber({
connection: this.driftClient.connection,
frequencyMs: 5000,
addresses: [
new PublicKey('8BnEgHoWFysVcuFFX7QztDmzuH8r5ZFvyP3sYwn1XTh6'), // Openbook SOL/USDC is good indicator of fees
],
});
this.priorityFeeSubscriber = priorityFeeSubscriber;
this.priorityFeeSubscriber.updateAddresses([
new PublicKey('8BnEgHoWFysVcuFFX7QztDmzuH8r5ZFvyP3sYwn1XTh6'), // Openbook SOL/USDC
]);

if (!config.maxPositionTakeoverPctOfCollateral) {
// spend 50% of collateral by default
Expand Down Expand Up @@ -640,8 +637,6 @@ export class LiquidatorBot implements Bot {
}
}

await this.priorityFeeSubscriber.subscribe();

await webhookMessage(`[${this.name}]: started`);
}

Expand Down
15 changes: 6 additions & 9 deletions src/bots/spotFiller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,7 @@ export class SpotFillerBot implements Bot {
userMap: UserMap,
runtimeSpec: RuntimeSpec,
config: FillerConfig,
priorityFeeSubscriber: PriorityFeeSubscriber,
eventSubscriber?: EventSubscriber
) {
this.name = config.botId;
Expand All @@ -275,13 +276,11 @@ export class SpotFillerBot implements Bot {
this.initializeMetrics();
}

this.priorityFeeSubscriber = new PriorityFeeSubscriber({
connection: this.driftClient.connection,
frequencyMs: 5000,
addresses: [
new PublicKey('8BnEgHoWFysVcuFFX7QztDmzuH8r5ZFvyP3sYwn1XTh6'), // Openbook SOL/USDC is good indicator of fees
],
});
this.priorityFeeSubscriber = priorityFeeSubscriber;
this.priorityFeeSubscriber.updateAddresses([
new PublicKey('8BnEgHoWFysVcuFFX7QztDmzuH8r5ZFvyP3sYwn1XTh6'), // Openbook SOL/USDC
]);

this.revertOnFailure = config.revertOnFailure ?? true;
this.simulateTxForCUEstimate = config.simulateTxForCUEstimate ?? true;
logger.info(
Expand Down Expand Up @@ -613,8 +612,6 @@ export class SpotFillerBot implements Bot {
}
}

await this.priorityFeeSubscriber.subscribe();

await webhookMessage(`[${this.name}]: started`);
}

Expand Down
15 changes: 6 additions & 9 deletions src/bots/uncrossArbBot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,8 @@ export class UncrossArbBot implements Bot {
jitProxyClient: JitProxyClient,
slotSubscriber: SlotSubscriber,
config: BaseBotConfig,
driftEnv: DriftEnv
driftEnv: DriftEnv,
priorityFeeSubscriber: PriorityFeeSubscriber
) {
this.jitProxyClient = jitProxyClient;
this.driftClient = driftClient;
Expand Down Expand Up @@ -144,13 +145,10 @@ export class UncrossArbBot implements Bot {
driftClient: this.driftClient,
});

this.priorityFeeSubscriber = new PriorityFeeSubscriber({
connection: this.driftClient.connection,
frequencyMs: 5000,
addresses: [
new PublicKey('8UJgxaiQx5nTrdDgph5FiahMmzduuLTLf5WmsPegYA6W'), // sol-perp
],
});
this.priorityFeeSubscriber = priorityFeeSubscriber;
this.priorityFeeSubscriber.updateAddresses([
new PublicKey('8UJgxaiQx5nTrdDgph5FiahMmzduuLTLf5WmsPegYA6W'), // sol-perp
]);
}

/**
Expand All @@ -161,7 +159,6 @@ export class UncrossArbBot implements Bot {

await this.orderSubscriber.subscribe();
await this.dlobSubscriber.subscribe();
await this.priorityFeeSubscriber.subscribe();
this.lookupTableAccount =
await this.driftClient.fetchMarketLookupTableAccount();

Expand Down
34 changes: 16 additions & 18 deletions src/bots/userLpSettler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import {

const SETTLE_LP_CHUNKS = 4;
const SLEEP_MS = 500;
const PRIORITY_FEE_SUBSCRIBER_FREQ_MS = 1000;
const MAX_COMPUTE_UNIT_PRICE_MICRO_LAMPORTS = 10000; // cap the computeUnitPrice to pay for settlePnl txs

const errorCodesToSuppress = [
Expand All @@ -50,7 +49,11 @@ export class UserLpSettlerBot implements Bot {
private watchdogTimerMutex = new Mutex();
private watchdogTimerLastPatTime = Date.now();

constructor(driftClientConfigs: DriftClientConfig, config: BaseBotConfig) {
constructor(
driftClientConfigs: DriftClientConfig,
config: BaseBotConfig,
priorityFeeSubscriber: PriorityFeeSubscriber
) {
this.name = config.botId;
this.dryRun = config.dryRun;
this.runOnce = config.runOnce || false;
Expand Down Expand Up @@ -85,6 +88,17 @@ export class UserLpSettlerBot implements Bot {
includeIdle: false,
disableSyncOnTotalAccountsChange: true,
});

const perpMarkets = this.driftClient
.getPerpMarketAccounts()
.map((m) => m.pubkey);

this.priorityFeeSubscriber = priorityFeeSubscriber;
this.priorityFeeSubscriber.updateAddresses([...perpMarkets]);

logger.info(
`Lp settler looking at ${perpMarkets.length} perp markets to determine priority fee`
);
}

public async init() {
Expand All @@ -99,22 +113,6 @@ export class UserLpSettlerBot implements Bot {
this.lookupTableAccount =
await this.driftClient.fetchMarketLookupTableAccount();

const perpMarkets = this.driftClient
.getPerpMarketAccounts()
.map((m) => m.pubkey);

logger.info(
`Lp settler looking at ${perpMarkets.length} perp markets to determine priority fee`
);

this.priorityFeeSubscriber = new PriorityFeeSubscriber({
connection: this.driftClient.connection,
frequencyMs: PRIORITY_FEE_SUBSCRIBER_FREQ_MS,
addresses: [...perpMarkets],
});
await this.priorityFeeSubscriber.subscribe();
await sleepMs(PRIORITY_FEE_SUBSCRIBER_FREQ_MS);

// logger.info(`Initializing UserMap`);
// const startUserMapSub = Date.now();
// await this.userMap.subscribe();
Expand Down
42 changes: 21 additions & 21 deletions src/bots/userPnlSettler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ const MIN_PNL_TO_SETTLE = new BN(-10).mul(QUOTE_PRECISION);
const SETTLE_USER_CHUNKS = 4;
const CU_PER_SETTLE_PNL = 500_000; // annecdotal: https://explorer.solana.com/tx/fLoSxBpBkowozkPMem9s3KLGQYt3KDHemTRzZPWFe48sZc1VJsgRTiYJUGXZGYRWQTwF42PjpgFLe6fpH9aCLh1#ix-1
const SLEEP_MS = 500;
const PRIORITY_FEE_SUBSCRIBER_FREQ_MS = 1000;
const MAX_COMPUTE_UNIT_PRICE_MICRO_LAMPORTS = 50000; // cap the computeUnitPrice to pay for settlePnl txs

const errorCodesToSuppress = [
Expand All @@ -78,7 +77,11 @@ export class UserPnlSettlerBot implements Bot {
private watchdogTimerMutex = new Mutex();
private watchdogTimerLastPatTime = Date.now();

constructor(driftClientConfigs: DriftClientConfig, config: BaseBotConfig) {
constructor(
driftClientConfigs: DriftClientConfig,
config: BaseBotConfig,
priorityFeeSubscriber: PriorityFeeSubscriber
) {
this.name = config.botId;
this.dryRun = config.dryRun;
this.runOnce = config.runOnce || false;
Expand Down Expand Up @@ -113,6 +116,22 @@ export class UserPnlSettlerBot implements Bot {
skipInitialLoad: false,
includeIdle: false,
});

const spotMarkets = this.driftClient
.getSpotMarketAccounts()
.map((m) => m.pubkey);
const perpMarkets = this.driftClient
.getPerpMarketAccounts()
.map((m) => m.pubkey);
this.priorityFeeSubscriber = priorityFeeSubscriber;
this.priorityFeeSubscriber.updateAddresses([
...spotMarkets,
...perpMarkets,
]);

logger.info(
`Pnl settler looking at ${spotMarkets.length} spot markets and ${perpMarkets.length} perp markets to determine priority fee`
);
}

public async init() {
Expand All @@ -127,25 +146,6 @@ export class UserPnlSettlerBot implements Bot {
this.lookupTableAccount =
await this.driftClient.fetchMarketLookupTableAccount();

const spotMarkets = this.driftClient
.getSpotMarketAccounts()
.map((m) => m.pubkey);
const perpMarkets = this.driftClient
.getPerpMarketAccounts()
.map((m) => m.pubkey);

logger.info(
`Pnl settler looking at ${spotMarkets.length} spot markets and ${perpMarkets.length} perp markets to determine priority fee`
);

this.priorityFeeSubscriber = new PriorityFeeSubscriber({
connection: this.driftClient.connection,
frequencyMs: PRIORITY_FEE_SUBSCRIBER_FREQ_MS,
addresses: [...spotMarkets, ...perpMarkets],
});
await this.priorityFeeSubscriber.subscribe();
await sleepMs(PRIORITY_FEE_SUBSCRIBER_FREQ_MS);

logger.info(`${this.name} init'd!`);
}

Expand Down
7 changes: 7 additions & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ export interface GlobalConfig {
driftEnv?: DriftEnv;
endpoint?: string;
wsEndpoint?: string;
heliusEndpoint?: string;
priorityFeeMethod?: string;
resubTimeoutMs?: number;
keeperPrivateKey?: string;
initUser?: boolean;
Expand Down Expand Up @@ -124,6 +126,8 @@ const defaultConfig: Partial<Config> = {

endpoint: process.env.ENDPOINT,
wsEndpoint: process.env.WS_ENDPOINT,
heliusEndpoint: process.env.HELIUS_ENDPOINT,
priorityFeeMethod: process.env.PRIORITY_FEE_METHOD ?? 'solana',
keeperPrivateKey: process.env.KEEPER_PRIVATE_KEY,

useJito: false,
Expand Down Expand Up @@ -195,6 +199,9 @@ export function loadConfigFromOpts(opts: any): Config {
driftEnv: (process.env.ENV ?? 'devnet') as DriftEnv,
endpoint: opts.endpoint ?? process.env.ENDPOINT,
wsEndpoint: opts.wsEndpoint ?? process.env.WS_ENDPOINT,
heliusEndpoint: opts.heliusEndpoint ?? process.env.HELIUS_ENDPOINT,
priorityFeeMethod:
opts.priorityFeeMethod ?? process.env.PRIORITY_FEE_METHOD,
keeperPrivateKey: opts.privateKey ?? process.env.KEEPER_PRIVATE_KEY,
eventSubscriberPollingInterval: parseInt(
process.env.BULK_ACCOUNT_LOADER_POLLING_INTERVAL ?? '5000'
Expand Down
Loading

0 comments on commit 1f78a8a

Please sign in to comment.