diff --git a/package.json b/package.json index 899b0032..deea20f9 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "@opentelemetry/sdk-node": "0.31.0", "@project-serum/anchor": "0.19.1-beta.1", "@project-serum/serum": "0.13.65", - "@pythnetwork/price-service-client": "1.9.0", + "@pythnetwork/hermes-client": "2.0.0", "@pythnetwork/pyth-lazer-sdk": "0.3.2", "@solana/spl-token": "0.3.7", "@solana/web3.js": "1.92.3", @@ -83,5 +83,8 @@ }, "engines": { "node": ">=20.18.0" + }, + "resolutions": { + "jito-ts": "4.1.1" } } diff --git a/src/bots/pythCranker.ts b/src/bots/pythCranker.ts index a6882915..3b817df9 100644 --- a/src/bots/pythCranker.ts +++ b/src/bots/pythCranker.ts @@ -1,14 +1,11 @@ -import { Bot } from '../types'; +import { Bot, PythPullPriceData } from '../types'; import { logger } from '../logger'; import { GlobalConfig, PythCrankerBotConfig, PythUpdateConfigs, } from '../config'; -import { - PriceFeed, - PriceServiceConnection, -} from '@pythnetwork/price-service-client'; +import { HermesClient, PriceUpdate } from '@pythnetwork/hermes-client'; import { PriceUpdateAccount } from '@pythnetwork/pyth-solana-receiver/lib/PythSolanaReceiver'; import { BlockhashSubscriber, @@ -66,7 +63,8 @@ export type FeedIdToCrankInfo = { }; export class PythCrankerBot implements Bot { - private priceServiceConnection: PriceServiceConnection; + private priceServiceConnection: HermesClient; + private pythEventSource: EventSource | undefined; private feedIdsToCrank: FeedIdToCrankInfo[] = []; private pythOracleClient: OracleClient; readonly decodeFunc: (name: string, data: Buffer) => PriceUpdateAccount; @@ -74,7 +72,7 @@ export class PythCrankerBot implements Bot { public name: string; public dryRun: boolean; private intervalMs: number; - private feedIdToPriceFeedMap: Map = new Map(); + private feedIdToPriceUpdateMap: Map = new Map(); public defaultIntervalMs = 30_000; private blockhashSubscriber: BlockhashSubscriber; @@ -96,7 +94,7 @@ export class PythCrankerBot implements Bot { if (!globalConfig.hermesEndpoint) { throw new Error('Missing hermesEndpoint in global config'); } - this.priceServiceConnection = new PriceServiceConnection( + this.priceServiceConnection = new HermesClient( globalConfig.hermesEndpoint, { timeout: 10_000, @@ -233,12 +231,28 @@ export class PythCrankerBot implements Bot { }); } - await this.priceServiceConnection.subscribePriceFeedUpdates( - this.feedIdsToCrank.map((x) => x.feedId), - (priceFeed) => { - this.feedIdToPriceFeedMap.set(priceFeed.id, priceFeed); + this.pythEventSource = + await this.priceServiceConnection.getPriceUpdatesStream( + this.feedIdsToCrank.map((x) => x.feedId) + ); + + this.pythEventSource.onmessage = async (event) => { + const priceUpdate = JSON.parse(event.data) as PriceUpdate; + if (priceUpdate.parsed) { + for (const update of priceUpdate.parsed) { + this.feedIdToPriceUpdateMap.set(update.id, { + expo: update.price.expo, + publishTime: update.price.publish_time, + price: +update.price.price as number, + conf: +update.price.conf, + }); + } + } else { + logger.warn( + `Received invalid price update: ${JSON.stringify(priceUpdate)}` + ); } - ); + }; this.priorityFeeSubscriber?.updateAddresses([ this.driftClient.getReceiverProgram().programId, @@ -250,9 +264,7 @@ export class PythCrankerBot implements Bot { this.feedIdsToCrank = []; this.blockhashSubscriber.unsubscribe(); await this.driftClient.unsubscribe(); - await this.priceServiceConnection.unsubscribePriceFeedUpdates( - this.feedIdsToCrank.map((x) => x.feedId) - ); + this.pythEventSource?.close(); } async startIntervalLoop(intervalMs = this.intervalMs): Promise { @@ -266,17 +278,13 @@ export class PythCrankerBot implements Bot { } async getVaaForPriceFeedIds(feedIds: string[]): Promise { - const latestVaa = await this.priceServiceConnection.getLatestVaas(feedIds); - return latestVaa[0]; - } - - async getLatestPriceFeedUpdatesForFeedIds( - feedIds: string[] - ): Promise { - const latestPrices = await this.priceServiceConnection.getLatestPriceFeeds( - feedIds + const latestVaa = await this.priceServiceConnection.getLatestPriceUpdates( + feedIds, + { + encoding: 'base64', + } ); - return latestPrices; + return latestVaa.binary.data[0]; } private async getBlockhashForTx(): Promise { @@ -327,16 +335,15 @@ export class PythCrankerBot implements Bot { ); return; } - const pythnetPriceFeed = this.feedIdToPriceFeedMap.get( + const pythnetPriceData = this.feedIdToPriceUpdateMap.get( trimFeedId(feedIdCrankInfo.feedId) ); - if (!pythnetPriceFeed || !onChainPriceFeed) { + if (!pythnetPriceData || !onChainPriceFeed) { logger.info(`Missing price feed data for ${feedIdCrankInfo.feedId}`); return; } - const pythnetPriceData = pythnetPriceFeed.getPriceUnchecked(); const onChainPriceData = this.pythOracleClient.getOraclePriceDataFromBuffer(result.data); const onChainSlot = onChainPriceData.slot.toNumber(); diff --git a/src/bots/trigger.ts b/src/bots/trigger.ts index 81516c6a..edb8c562 100644 --- a/src/bots/trigger.ts +++ b/src/bots/trigger.ts @@ -54,7 +54,7 @@ import { } from '@solana/web3.js'; import { PriceUpdateAccount } from '@pythnetwork/pyth-solana-receiver/lib/PythSolanaReceiver'; import { PythLazerSubscriber } from '../pythLazerSubscriber'; -import { PriceServiceConnection } from '@pythnetwork/price-service-client'; +import { PythPriceFeedSubscriber } from '../pythPriceFeedSubscriber'; const TRIGGER_ORDER_COOLDOWN_MS = 10000; // time to wait between triggering an order @@ -101,15 +101,14 @@ function getPythPullFeedIdsToCrank( const marketIdToFeedId: Map = new Map(); for (const market of [...spotMarkets, ...perpMarkets]) { - if (!getVariant(market.oracleSource).toLowerCase().includes('pull')) { - continue; - } - if (market.pythFeedId === undefined) { - logger.warn( - `No pyth feed id for market ${ - market.symbol - } with oracleSource ${getVariant(market.oracleSource)}` - ); + const oracleSourceStr = getVariant(market.oracleSource).toLowerCase(); + if ( + !( + oracleSourceStr.includes('pull') && + oracleSourceStr.includes('pyth') && + market.pythFeedId !== undefined + ) + ) { continue; } @@ -193,7 +192,7 @@ export class TriggerBot implements Bot { private pythLazerClient?: PythLazerSubscriber; private pythPullFeedIdsToCrank: FeedIdToCrankInfo[] = []; - private pythPullClient?: PriceServiceConnection; + private pythPullClient?: PythPriceFeedSubscriber; // map from marketId (i.e. perp-0 or spot-0) to pyth feed id private marketIdToPythPullFeedId: Map = new Map(); @@ -269,7 +268,7 @@ export class TriggerBot implements Bot { this.globalConfig.driftEnv ); - this.pythPullClient = new PriceServiceConnection( + this.pythPullClient = new PythPriceFeedSubscriber( this.globalConfig.hermesEndpoint, { timeout: 10_000, @@ -414,12 +413,8 @@ export class TriggerBot implements Bot { this.pythPullClient ) { await this.pythLazerClient.subscribe(); - await this.pythPullClient.subscribePriceFeedUpdates( - this.pythPullFeedIdsToCrank.map((x) => x.feedId), - (priceFeed) => { - const p = priceFeed.getPriceUnchecked().getPriceAsNumberUnchecked(); - this.pythPullFeedIdToPrice.set('0x' + priceFeed.id, p); - } + await this.pythPullClient.subscribe( + this.pythPullFeedIdsToCrank.map((x) => x.feedId) ); } } @@ -522,7 +517,7 @@ export class TriggerBot implements Bot { if (!feedId) { return []; } - const vaa = await this.pythPullClient?.getLatestVaas([feedId]); + const vaa = await this.pythPullClient?.getLatestCachedVaa(feedId); if (!vaa) { return []; } diff --git a/src/experimental-bots/entrypoint.ts b/src/experimental-bots/entrypoint.ts index d941b81c..e4bb9ef9 100644 --- a/src/experimental-bots/entrypoint.ts +++ b/src/experimental-bots/entrypoint.ts @@ -224,11 +224,7 @@ const runBot = async () => { if (config.global.hermesEndpoint) { pythPriceSubscriber = new PythPriceFeedSubscriber( config.global.hermesEndpoint, - { - priceFeedRequestConfig: { - binary: true, - }, - } + {} ); } diff --git a/src/experimental-bots/filler-common/dlobBuilder.ts b/src/experimental-bots/filler-common/dlobBuilder.ts index 1f88ad52..ea191cf4 100644 --- a/src/experimental-bots/filler-common/dlobBuilder.ts +++ b/src/experimental-bots/filler-common/dlobBuilder.ts @@ -283,10 +283,7 @@ class DLOBBuilder { auctionDuration: signedMsgOrderParams.auctionDuration, auctionStartPrice: signedMsgOrderParams.auctionStartPrice, auctionEndPrice: signedMsgOrderParams.auctionEndPrice, - immediateOrCancel: - (signedMsgOrderParams.bitFlags & - OrderParamsBitFlag.ImmediateOrCancel) !== - 0, + immediateOrCancel: false, direction: signedMsgOrderParams.direction, postOnly: false, oraclePriceOffset: signedMsgOrderParams.oraclePriceOffset ?? 0, diff --git a/src/index.ts b/src/index.ts index 45170e6f..4cd4ab13 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,7 @@ /* eslint-disable @typescript-eslint/no-non-null-assertion */ +import 'rpc-websockets/dist/lib/client'; import { program, Option } from 'commander'; -import * as http from 'http'; +import * as http from 'node:http'; import { Connection, @@ -455,11 +456,7 @@ const runBot = async () => { if (config.global.hermesEndpoint) { pythPriceSubscriber = new PythPriceFeedSubscriber( config.global.hermesEndpoint, - { - priceFeedRequestConfig: { - binary: true, - }, - } + {} ); } diff --git a/src/pythPriceFeedSubscriber.ts b/src/pythPriceFeedSubscriber.ts index cc2fe037..fe476093 100644 --- a/src/pythPriceFeedSubscriber.ts +++ b/src/pythPriceFeedSubscriber.ts @@ -1,23 +1,33 @@ +import { trimFeedId } from '@drift-labs/sdk'; import { - PriceFeed, - PriceServiceConnection, - PriceServiceConnectionConfig, -} from '@pythnetwork/price-service-client'; + HermesClient, + HermesClientConfig, + PriceUpdate, +} from '@pythnetwork/hermes-client'; -export class PythPriceFeedSubscriber extends PriceServiceConnection { +export class PythPriceFeedSubscriber extends HermesClient { protected latestPythVaas: Map = new Map(); // priceFeedId -> vaa + protected streams?: EventSource[]; - constructor(endpoint: string, config: PriceServiceConnectionConfig) { + constructor(endpoint: string, config: HermesClientConfig) { super(endpoint, config); } async subscribe(feedIds: string[]) { - await super.subscribePriceFeedUpdates(feedIds, (priceFeed: PriceFeed) => { - if (priceFeed.vaa) { - const priceFeedId = '0x' + priceFeed.id; - this.latestPythVaas.set(priceFeedId, priceFeed.vaa); - } - }); + for (const feedId of feedIds) { + const trimmedId = trimFeedId(feedId); + const stream = await this.getPriceUpdatesStream([feedId], { + encoding: 'base64', + }); + stream.onmessage = async (event) => { + const data = JSON.parse(event.data) as PriceUpdate; + if (!data.parsed) { + console.error('Failed to parse VAA for feedId: ', feedId); + return; + } + this.latestPythVaas.set(trimmedId, data.binary.data[0]); + }; + } } getLatestCachedVaa(feedId: string): string | undefined { diff --git a/src/types.ts b/src/types.ts index d2c6ea46..0f4b58d6 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,5 +1,5 @@ import { BN, PositionDirection } from '@drift-labs/sdk'; -import { PriceServiceConnection } from '@pythnetwork/price-service-client'; +import { HermesClient } from '@pythnetwork/hermes-client'; export const constants = { devnet: { @@ -116,7 +116,7 @@ export interface Bot { readonly name: string; readonly dryRun: boolean; readonly defaultIntervalMs?: number; - readonly pythConnection?: PriceServiceConnection; + readonly pythConnection?: HermesClient; /** * Initialize the bot @@ -138,3 +138,10 @@ export interface Bot { */ healthCheck: () => Promise; } + +export type PythPullPriceData = { + conf: number; + price: number; + expo: number; + publishTime: number; +}; diff --git a/yarn.lock b/yarn.lock index 286d4768..399e5abc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -255,7 +255,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.27.1" -"@babel/runtime@^7.10.5", "@babel/runtime@^7.12.5", "@babel/runtime@^7.15.4", "@babel/runtime@^7.17.2", "@babel/runtime@^7.23.4", "@babel/runtime@^7.24.6", "@babel/runtime@^7.25.0": +"@babel/runtime@^7.10.5", "@babel/runtime@^7.12.5", "@babel/runtime@^7.17.2", "@babel/runtime@^7.23.4", "@babel/runtime@^7.24.6", "@babel/runtime@^7.25.0": version "7.27.1" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.27.1.tgz#9fce313d12c9a77507f264de74626e87fd0dc541" integrity sha512-1x3D2xEk2fRo3PAhwQwu5UubzgiVWSXTBfWpVd2Mx2AzRqJuDJCsgaDVZ7HB5iGzDW1Hl1sWN2mFyKjmR9uAog== @@ -1689,25 +1689,14 @@ assert "^2.0.0" buffer "^6.0.1" -"@pythnetwork/price-service-client@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@pythnetwork/price-service-client/-/price-service-client-1.9.0.tgz#1503d67b1a7c14386d30bb420502df4857027e76" - integrity sha512-SLm3IFcfmy9iMqHeT4Ih6qMNZhJEefY14T9yTlpsH2D/FE5+BaGGnfcexUifVlfH6M7mwRC4hEFdNvZ6ebZjJg== - dependencies: - "@pythnetwork/price-service-sdk" "*" - "@types/ws" "^8.5.3" - axios "^1.5.1" - axios-retry "^3.8.0" - isomorphic-ws "^4.0.1" - ts-log "^2.2.4" - ws "^8.6.0" - -"@pythnetwork/price-service-sdk@*", "@pythnetwork/price-service-sdk@>=1.6.0": - version "1.8.0" - resolved "https://registry.yarnpkg.com/@pythnetwork/price-service-sdk/-/price-service-sdk-1.8.0.tgz#f5f01f654963eb9a0cf12127b4f1a89b60ef008a" - integrity sha512-tFZ1thj3Zja06DzPIX2dEWSi7kIfIyqreoywvw5NQ3Z1pl5OJHQGMEhxt6Li3UCGSp2ooYZS9wl8/8XfrfrNSA== +"@pythnetwork/hermes-client@2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@pythnetwork/hermes-client/-/hermes-client-2.0.0.tgz#c8ea4b2a790d617cc24c4c573125a33da9d1e65f" + integrity sha512-8ZbCrO5NSlsu1zauIJjZv0sPR3qF9uzgCpBpAPSBGBjwKP0T3TdIRfuSzf9mpzrqf+b7QUqNVNLWZqgN7nlREw== dependencies: - bn.js "^5.2.1" + "@zodios/core" "^10.9.6" + eventsource "^3.0.5" + zod "^3.23.8" "@pythnetwork/price-service-sdk@1.7.1": version "1.7.1" @@ -1716,6 +1705,13 @@ dependencies: bn.js "^5.2.1" +"@pythnetwork/price-service-sdk@>=1.6.0": + version "1.8.0" + resolved "https://registry.yarnpkg.com/@pythnetwork/price-service-sdk/-/price-service-sdk-1.8.0.tgz#f5f01f654963eb9a0cf12127b4f1a89b60ef008a" + integrity sha512-tFZ1thj3Zja06DzPIX2dEWSi7kIfIyqreoywvw5NQ3Z1pl5OJHQGMEhxt6Li3UCGSp2ooYZS9wl8/8XfrfrNSA== + dependencies: + bn.js "^5.2.1" + "@pythnetwork/pyth-lazer-sdk@0.3.2": version "0.3.2" resolved "https://registry.yarnpkg.com/@pythnetwork/pyth-lazer-sdk/-/pyth-lazer-sdk-0.3.2.tgz#5837ca483efe7f5380c2f079d9cd4cd20ec3704e" @@ -2669,7 +2665,7 @@ dependencies: "@types/node" "*" -"@types/ws@^8.2.2", "@types/ws@^8.5.3": +"@types/ws@^8.2.2": version "8.18.1" resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.18.1.tgz#48464e4bf2ddfd17db13d845467f6070ffea4aa9" integrity sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg== @@ -2806,6 +2802,11 @@ "@typescript-eslint/types" "5.62.0" eslint-visitor-keys "^3.3.0" +"@zodios/core@^10.9.6": + version "10.9.6" + resolved "https://registry.yarnpkg.com/@zodios/core/-/core-10.9.6.tgz#64ad831216e6ffa71679ea6be8d1ed882bb04d83" + integrity sha512-aH4rOdb3AcezN7ws8vDgBfGboZMk2JGGzEq/DtW65MhnRxyTGRuLJRWVQ/2KxDgWvV2F5oTkAS+5pnjKbl0n+A== + JSONStream@^1.3.5: version "1.3.5" resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" @@ -3028,14 +3029,6 @@ aws-sdk@2.1511.0: uuid "8.0.0" xml2js "0.5.0" -axios-retry@^3.8.0: - version "3.9.1" - resolved "https://registry.yarnpkg.com/axios-retry/-/axios-retry-3.9.1.tgz#c8924a8781c8e0a2c5244abf773deb7566b3830d" - integrity sha512-8PJDLJv7qTTMMwdnbMvrLYuvB47M81wRtxQmEdV5w4rgbTXTt+vtPkXwajOfOdSyv/wZICJOC+/UhXH4aQ/R+w== - dependencies: - "@babel/runtime" "^7.15.4" - is-retry-allowed "^2.2.0" - axios@1.7.7: version "1.7.7" resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.7.tgz#2f554296f9892a72ac8d8e4c5b79c14a91d0a47f" @@ -3052,7 +3045,7 @@ axios@^0.21.1: dependencies: follow-redirects "^1.14.0" -axios@^1.5.1, axios@^1.6.8, axios@^1.7.4, axios@^1.7.8, axios@^1.8.3: +axios@^1.6.8, axios@^1.7.4, axios@^1.7.8, axios@^1.8.3: version "1.9.0" resolved "https://registry.yarnpkg.com/axios/-/axios-1.9.0.tgz#25534e3b72b54540077d33046f77e3b8d7081901" integrity sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg== @@ -3950,6 +3943,18 @@ events@1.1.1: resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" integrity sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw== +eventsource-parser@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/eventsource-parser/-/eventsource-parser-3.0.1.tgz#5e358dba9a55ba64ca90da883c4ca35bd82467bd" + integrity sha512-VARTJ9CYeuQYb0pZEPbzi740OWFgpHe7AYJ2WFZVnUDUQp5Dk2yJUgF36YsZ81cOyxT0QxmXD2EQpapAouzWVA== + +eventsource@^3.0.5: + version "3.0.6" + resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-3.0.6.tgz#5c4b24cd70c0323eed2651a5ee07bd4bc391e656" + integrity sha512-l19WpE2m9hSuyP06+FbuUUf1G+R0SFLrtQfbRb9PRr+oimOfxQhgGCbVaXg5IvZyyTThJsxh6L/srkMiCeBPDA== + dependencies: + eventsource-parser "^3.0.1" + expect@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/expect/-/expect-29.7.0.tgz#578874590dcb3214514084c08115d8aee61e11bc" @@ -4576,11 +4581,6 @@ is-regex@^1.2.1: has-tostringtag "^1.0.2" hasown "^2.0.2" -is-retry-allowed@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-2.2.0.tgz#88f34cbd236e043e71b6932d09b0c65fb7b4d71d" - integrity sha512-XVm7LOeLpTW4jV19QSH38vkswxoLud8sQ57YwJVTPWdiaI9I8keEhGFpBlslyVsgdQy4Opg8QOLb8YRgsyZiQg== - is-stream@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" @@ -6233,7 +6233,7 @@ triple-beam@^1.3.0: resolved "https://registry.yarnpkg.com/triple-beam/-/triple-beam-1.4.1.tgz#6fde70271dc6e5d73ca0c3b24e2d92afb7441984" integrity sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg== -ts-log@^2.2.4, ts-log@^2.2.7: +ts-log@^2.2.7: version "2.2.7" resolved "https://registry.yarnpkg.com/ts-log/-/ts-log-2.2.7.tgz#4f4512144898b77c9984e91587076fcb8518688e" integrity sha512-320x5Ggei84AxzlXp91QkIGSw5wgaLT6GeAH0KsqDmRZdVWW2OiSeVvElVoatk3f7nicwXlElXsoFkARiGE2yg== @@ -6535,7 +6535,7 @@ ws@^7.4.5, ws@^7.5.10: resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.10.tgz#58b5c20dc281633f6c19113f39b349bd8bd558d9" integrity sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ== -ws@^8.18.0, ws@^8.5.0, ws@^8.6.0: +ws@^8.18.0, ws@^8.5.0: version "8.18.1" resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.1.tgz#ea131d3784e1dfdff91adb0a4a116b127515e3cb" integrity sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w== @@ -6639,6 +6639,11 @@ yocto-queue@^0.1.0: resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== +zod@^3.23.8: + version "3.24.3" + resolved "https://registry.yarnpkg.com/zod/-/zod-3.24.3.tgz#1f40f750a05e477396da64438e0e1c0995dafd87" + integrity sha512-HhY1oqzWCQWuUqvBFnsyrtZRhyPeR7SUGv+C4+MsisMuVfSPx8HpwWqH8tRahSlt6M3PiFAcoeFhZAqIXTxoSg== + zstddec@0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/zstddec/-/zstddec-0.1.0.tgz#7050f3f0e0c3978562d0c566b3e5a427d2bad7ec"