Skip to content

Commit 698f957

Browse files
committed
Merge branch 'master' into mainnet-beta
2 parents 43de3ee + 2c1135b commit 698f957

File tree

3 files changed

+157
-105
lines changed

3 files changed

+157
-105
lines changed

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
"main": "lib/index.js",
66
"license": "Apache-2.0",
77
"dependencies": {
8-
"@drift-labs/jit-proxy": "0.21.63",
9-
"@drift-labs/sdk": "2.142.0-beta.25",
8+
"@drift-labs/jit-proxy": "0.21.70",
9+
"@drift-labs/sdk": "2.143.0-beta.4",
1010
"@drift/common": "file:./drift-common/common-ts",
1111
"@opentelemetry/api": "1.7.0",
1212
"@opentelemetry/auto-instrumentations-node": "^0.62.1",

src/bots/pythCranker.ts

Lines changed: 146 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ export class PythCrankerBot implements Bot {
8080
public dryRun: boolean;
8181
private feedIdToPriceFeedMap: Map<string, PriceFeed> = new Map();
8282
public defaultIntervalMs: number;
83+
public minIntervalMs: number; // stores the minimum update interval for any feed, will ensure bot runs at least this interval
8384

8485
private blockhashSubscriber: BlockhashSubscriber;
8586
private health: boolean = true;
@@ -101,6 +102,7 @@ export class PythCrankerBot implements Bot {
101102
this.name = crankConfigs.botId;
102103
this.dryRun = crankConfigs.dryRun;
103104
this.defaultIntervalMs = crankConfigs.intervalMs ?? 30_000;
105+
this.minIntervalMs = this.defaultIntervalMs;
104106
if (!globalConfig.hermesEndpoint) {
105107
throw new Error('Missing hermesEndpoint in global config');
106108
}
@@ -169,101 +171,129 @@ export class PythCrankerBot implements Bot {
169171
}
170172
);
171173

172-
if (!this.crankConfigs.overridePythIds) {
173-
for (const marketConfig of perpMarketConfigs) {
174-
const feedId = marketConfig.pythFeedId;
175-
if (!feedId) {
176-
logger.warn(`No pyth feed id for market ${marketConfig.symbol}`);
177-
continue;
178-
}
179-
const perpMarket = this.driftClient.getPerpMarketAccount(
180-
marketConfig.marketIndex
181-
);
182-
if (!perpMarket) {
183-
logger.warn(`No perp market for market ${marketConfig.symbol}`);
184-
continue;
185-
}
186-
if (isOneOfVariant(perpMarket.status, ['delisted', 'settlement'])) {
187-
logger.warn(
188-
`Skipping perp market ${marketConfig.symbol} is delisted`
189-
);
190-
continue;
191-
}
192-
193-
const updateConfigs = updateDefault;
194-
const earlyUpdateConfigs = earlyUpdateDefault;
195-
if (isOneOfVariant(perpMarket.contractTier, ['a', 'b'])) {
196-
updateConfigs.timeDiffMs = 15_000;
197-
earlyUpdateConfigs.timeDiffMs = 10_000;
198-
}
199-
const pubkey = getPythPullOraclePublicKey(
200-
this.driftClient.program.programId,
201-
getFeedIdUint8Array(feedId)
202-
);
174+
// Build default feedIdsToCrank from all perp markets
175+
for (const marketConfig of perpMarketConfigs) {
176+
const feedId = marketConfig.pythFeedId;
177+
if (!feedId) {
178+
logger.warn(`No pyth feed id for market ${marketConfig.symbol}`);
179+
continue;
180+
}
181+
const perpMarket = this.driftClient.getPerpMarketAccount(
182+
marketConfig.marketIndex
183+
);
184+
if (!perpMarket) {
185+
logger.warn(`No perp market for market ${marketConfig.symbol}`);
186+
continue;
187+
}
188+
if (isOneOfVariant(perpMarket.status, ['delisted', 'settlement'])) {
189+
logger.warn(`Skipping perp market ${marketConfig.symbol} is delisted`);
190+
continue;
191+
}
203192

204-
this.feedIdsToCrank.push({
205-
baseSymbol: marketConfig.baseAssetSymbol.toUpperCase(),
206-
feedId,
207-
updateConfig:
208-
this.crankConfigs?.updateConfigs?.[feedId]?.update ?? updateConfigs,
209-
earlyUpdateConfig:
210-
this.crankConfigs?.updateConfigs?.[feedId]?.earlyUpdate ??
211-
earlyUpdateConfigs,
212-
accountAddress: pubkey,
213-
});
193+
const updateConfigs = { ...updateDefault };
194+
const earlyUpdateConfigs = { ...earlyUpdateDefault };
195+
if (isOneOfVariant(perpMarket.contractTier, ['a', 'b'])) {
196+
updateConfigs.timeDiffMs = 15_000;
197+
earlyUpdateConfigs.timeDiffMs = 10_000;
214198
}
215199

216-
for (const marketConfig of spotMarketConfigs) {
217-
if (
218-
this.feedIdsToCrank.findIndex(
219-
(feedId) => feedId.baseSymbol === marketConfig.symbol
220-
) !== -1
221-
)
222-
continue;
200+
const pubkey = getPythPullOraclePublicKey(
201+
this.driftClient.program.programId,
202+
getFeedIdUint8Array(feedId)
203+
);
223204

224-
const feedId = marketConfig.pythFeedId;
225-
if (!feedId) {
226-
logger.warn(`No pyth feed id for market ${marketConfig.symbol}`);
227-
continue;
228-
}
229-
const updateConfigs = updateDefault;
230-
const earlyUpdateConfigs = earlyUpdateDefault;
231-
if (
232-
isOneOfVariant(marketConfig.oracleSource, [
233-
'pythPullStableCoin',
234-
'pythStableCoin',
235-
])
236-
) {
237-
updateConfigs.timeDiffMs = 15_000;
238-
updateConfigs.priceDiffPct = 0.1;
239-
earlyUpdateConfigs.timeDiffMs = 10_000;
240-
earlyUpdateConfigs.priceDiffPct = 0.05;
241-
}
242-
const pubkey = getPythPullOraclePublicKey(
243-
this.driftClient.program.programId,
244-
getFeedIdUint8Array(feedId)
245-
);
246-
this.feedIdsToCrank.push({
247-
baseSymbol: marketConfig.symbol.toUpperCase(),
248-
feedId,
249-
updateConfig:
250-
this.crankConfigs?.updateConfigs?.[feedId]?.update ?? updateConfigs,
251-
earlyUpdateConfig:
252-
this.crankConfigs?.updateConfigs?.[feedId]?.earlyUpdate ??
253-
earlyUpdateConfigs,
254-
accountAddress: pubkey,
255-
});
205+
const finalUpdateConfig =
206+
this.crankConfigs?.updateConfigs?.[feedId]?.update ?? updateConfigs;
207+
const finalEarlyUpdateConfig =
208+
this.crankConfigs?.updateConfigs?.[feedId]?.earlyUpdate ??
209+
earlyUpdateConfigs;
210+
211+
this.minIntervalMs = Math.min(
212+
this.minIntervalMs,
213+
finalUpdateConfig.timeDiffMs,
214+
finalEarlyUpdateConfig.timeDiffMs
215+
);
216+
217+
this.feedIdsToCrank.push({
218+
baseSymbol: marketConfig.baseAssetSymbol.toUpperCase(),
219+
feedId,
220+
updateConfig: finalUpdateConfig,
221+
earlyUpdateConfig: finalEarlyUpdateConfig,
222+
accountAddress: pubkey,
223+
});
224+
}
225+
226+
// Add spot markets to default feedIdsToCrank
227+
for (const marketConfig of spotMarketConfigs) {
228+
if (
229+
this.feedIdsToCrank.findIndex(
230+
(feedId) => feedId.baseSymbol === marketConfig.symbol
231+
) !== -1
232+
)
233+
continue;
234+
235+
const feedId = marketConfig.pythFeedId;
236+
if (!feedId) {
237+
logger.warn(`No pyth feed id for market ${marketConfig.symbol}`);
238+
continue;
239+
}
240+
const updateConfigs = { ...updateDefault };
241+
const earlyUpdateConfigs = { ...earlyUpdateDefault };
242+
if (
243+
isOneOfVariant(marketConfig.oracleSource, [
244+
'pythPullStableCoin',
245+
'pythStableCoin',
246+
])
247+
) {
248+
updateConfigs.timeDiffMs = 15_000;
249+
updateConfigs.priceDiffPct = 0.1;
250+
earlyUpdateConfigs.timeDiffMs = 10_000;
251+
earlyUpdateConfigs.priceDiffPct = 0.05;
256252
}
257-
} else {
253+
254+
const pubkey = getPythPullOraclePublicKey(
255+
this.driftClient.program.programId,
256+
getFeedIdUint8Array(feedId)
257+
);
258+
259+
const finalUpdateConfig =
260+
this.crankConfigs?.updateConfigs?.[feedId]?.update ?? updateConfigs;
261+
const finalEarlyUpdateConfig =
262+
this.crankConfigs?.updateConfigs?.[feedId]?.earlyUpdate ??
263+
earlyUpdateConfigs;
264+
265+
this.minIntervalMs = Math.min(
266+
this.minIntervalMs,
267+
finalUpdateConfig.timeDiffMs,
268+
finalEarlyUpdateConfig.timeDiffMs
269+
);
270+
271+
this.feedIdsToCrank.push({
272+
baseSymbol: marketConfig.symbol.toUpperCase(),
273+
feedId,
274+
updateConfig: finalUpdateConfig,
275+
earlyUpdateConfig: finalEarlyUpdateConfig,
276+
accountAddress: pubkey,
277+
});
278+
}
279+
280+
// Override configs for specific feed IDs if provided
281+
if (this.crankConfigs.overridePythIds) {
258282
for (const feedId of this.crankConfigs.overridePythIds) {
283+
const existingFeedIndex = this.feedIdsToCrank.findIndex(
284+
(feed) => feed.feedId === feedId
285+
);
286+
287+
// Find the market config for this feed
259288
const marketConfig = perpMarketConfigs.find(
260289
(market) => market.pythFeedId === feedId
261290
);
262291
const spotMarketConfig = spotMarketConfigs.find(
263292
(market) => market.pythFeedId === feedId
264293
);
294+
265295
if (!marketConfig && !spotMarketConfig) {
266-
logger.warn(`No market config found for feed id ${feedId}`);
296+
logger.warn(`No market config found for override feed id ${feedId}`);
267297
continue;
268298
}
269299

@@ -275,18 +305,35 @@ export class PythCrankerBot implements Bot {
275305
? marketConfig
276306
: spotMarketConfig;
277307

278-
const updateConfigs = updateDefault;
279-
const earlyUpdateConfigs = earlyUpdateDefault;
280-
this.feedIdsToCrank.push({
308+
const updateConfigs = { ...updateDefault };
309+
const earlyUpdateConfigs = { ...earlyUpdateDefault };
310+
311+
const finalUpdateConfig =
312+
this.crankConfigs?.updateConfigs?.[feedId]?.update ?? updateConfigs;
313+
const finalEarlyUpdateConfig =
314+
this.crankConfigs?.updateConfigs?.[feedId]?.earlyUpdate ??
315+
earlyUpdateConfigs;
316+
317+
const overrideFeed = {
281318
baseSymbol: baseSymbol,
282319
feedId,
283-
updateConfig:
284-
this.crankConfigs?.updateConfigs?.[feedId]?.update ?? updateConfigs,
285-
earlyUpdateConfig:
286-
this.crankConfigs?.updateConfigs?.[feedId]?.earlyUpdate ??
287-
earlyUpdateConfigs,
320+
updateConfig: finalUpdateConfig,
321+
earlyUpdateConfig: finalEarlyUpdateConfig,
288322
accountAddress: marketConfigToUse!.oracle,
289-
});
323+
};
324+
325+
if (existingFeedIndex !== -1) {
326+
// Override existing feed
327+
this.feedIdsToCrank[existingFeedIndex] = overrideFeed;
328+
} else {
329+
// Add new feed
330+
this.feedIdsToCrank.push(overrideFeed);
331+
}
332+
this.minIntervalMs = Math.min(
333+
this.minIntervalMs,
334+
finalUpdateConfig.timeDiffMs,
335+
finalEarlyUpdateConfig.timeDiffMs
336+
);
290337
}
291338
}
292339

@@ -309,13 +356,18 @@ export class PythCrankerBot implements Bot {
309356
}
310357

311358
async startIntervalLoop(intervalMs: number | undefined): Promise<void> {
312-
logger.info(`Starting ${this.name} bot with interval ${intervalMs} ms`);
313-
await sleepMs(5000);
359+
const startInterval = Math.min(
360+
intervalMs ?? this.defaultIntervalMs,
361+
this.minIntervalMs
362+
);
363+
logger.info(
364+
`Starting ${this.name} bot with interval ${startInterval} ms (default: ${this.defaultIntervalMs} ms, min: ${this.minIntervalMs} ms)`
365+
);
314366
await this.runCrankLoop();
315367

316368
setInterval(async () => {
317369
await this.runCrankLoop();
318-
}, intervalMs);
370+
}, startInterval);
319371
}
320372

321373
async getVaaForPriceFeedIds(feedIds: string[]): Promise<string> {

yarn.lock

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -112,21 +112,21 @@
112112
enabled "2.0.x"
113113
kuler "^2.0.0"
114114

115-
"@drift-labs/[email protected].63":
116-
version "0.21.63"
117-
resolved "https://registry.yarnpkg.com/@drift-labs/jit-proxy/-/jit-proxy-0.21.63.tgz#092c78903548f3ec7cd0550970b76aaf1f063942"
118-
integrity sha512-M5o/4RzZrmi7jYqdQ/9QdFZNyFe60iIzETJGHT9GkcXOhssHLwc0pimcpAbMa0gVD1WZA9phtLQs5vMqP3yglg==
115+
"@drift-labs/[email protected].70":
116+
version "0.21.70"
117+
resolved "https://registry.yarnpkg.com/@drift-labs/jit-proxy/-/jit-proxy-0.21.70.tgz#a4c29869992a37639cba200fe72a7ac510ecca6b"
118+
integrity sha512-+9KS26eGVrUeKXdudEi/UYnYodfm2bCVbiQm30JJJMs+UM8wWuuBwnWFQwhZjS7ruVJ/FS1QhyAB3kwUqp2wTg==
119119
dependencies:
120120
"@coral-xyz/anchor" "0.29.0"
121-
"@drift-labs/sdk" "2.142.0-beta.25"
121+
"@drift-labs/sdk" "2.143.0-beta.4"
122122
"@solana/web3.js" "1.98.0"
123123
tweetnacl-util "^0.15.1"
124124
typescript "5.4.5"
125125

126-
"@drift-labs/sdk@2.142.0-beta.25":
127-
version "2.142.0-beta.25"
128-
resolved "https://registry.yarnpkg.com/@drift-labs/sdk/-/sdk-2.142.0-beta.25.tgz#cefba6b6995fb16663e080f6531234dd5ec69390"
129-
integrity sha512-tOuShLP6tqngL6+MWKzvw13WLclzcS9YP6pKU7r84EIAa6OVNml+md+oW61CnIzZRAAH01+V5ao227IVTx2hUA==
126+
"@drift-labs/sdk@2.143.0-beta.4":
127+
version "2.143.0-beta.4"
128+
resolved "https://registry.yarnpkg.com/@drift-labs/sdk/-/sdk-2.143.0-beta.4.tgz#c60c0c99cbd9b4f33079fb9306660f8bb9d4ae0b"
129+
integrity sha512-PViVk0pnDvB7hVPHipjRuTgkAB9cc8EhabHgXx9+vIk86LCnxae9rJJNjfZnKsMN2TF4f82pBVJ6i7oIFeSJEg==
130130
dependencies:
131131
"@coral-xyz/anchor" "0.29.0"
132132
"@coral-xyz/anchor-30" "npm:@coral-xyz/[email protected]"

0 commit comments

Comments
 (0)