From 3e28b03a992e3f8d6e8f4c9d3eeae335dccede2b Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Mon, 22 Sep 2025 23:17:28 +0000 Subject: [PATCH 01/12] feat(lazer-sdk): add History service support with get_symbols() function - Add LazerClientConfig type wrapping WebSocketPoolConfig with historyServiceUrl - Implement get_symbols() method to query /v1/symbols endpoint - Add TypeScript interfaces for SymbolResponse and query parameters - Update example to demonstrate BTC symbol search and subscription - Add cross-fetch dependency for Node.js compatibility - Bump version to 2.1.0 following semver for new feature Co-Authored-By: Tejas Badadare --- lazer/sdk/js/examples/index.ts | 33 +++++++++++++++++++ lazer/sdk/js/package.json | 3 +- lazer/sdk/js/src/client.ts | 58 +++++++++++++++++++++++++++++----- lazer/sdk/js/src/protocol.ts | 31 ++++++++++++++++++ 4 files changed, 116 insertions(+), 9 deletions(-) diff --git a/lazer/sdk/js/examples/index.ts b/lazer/sdk/js/examples/index.ts index f6170b542e..56e67f039e 100644 --- a/lazer/sdk/js/examples/index.ts +++ b/lazer/sdk/js/examples/index.ts @@ -58,6 +58,36 @@ client.addAllConnectionsDownListener(() => { console.error("All connections are down!"); }); +console.info("Querying symbols with 'BTC'..."); +const btcSymbols = await client.get_symbols({ + query: "BTC", + asset_type: "crypto", +}); +console.info( + "Found BTC symbols:", + btcSymbols.map((s) => ({ name: s.name, id: s.pyth_lazer_id })), +); + +if (btcSymbols.length > 0) { + const btcSymbol = btcSymbols[0]; + if (btcSymbol) { + const btcFeedId = btcSymbol.pyth_lazer_id; + console.info(`Subscribing to BTC feed ID: ${String(btcFeedId)}`); + + client.subscribe({ + type: "subscribe", + subscriptionId: 3, + priceFeedIds: [btcFeedId], + properties: ["price", "confidence"], + formats: ["solana"], + deliveryFormat: "json", + channel: "fixed_rate@200ms", + parsed: true, + jsonBinaryEncoding: "hex", + }); + } +} + // Create and remove one or more subscriptions on the fly client.subscribe({ type: "subscribe", @@ -86,4 +116,7 @@ await new Promise((resolve) => setTimeout(resolve, 10_000)); client.unsubscribe(1); client.unsubscribe(2); +if (btcSymbols.length > 0 && btcSymbols[0]) { + client.unsubscribe(3); +} client.shutdown(); diff --git a/lazer/sdk/js/package.json b/lazer/sdk/js/package.json index 6c412d5281..bdcf824f83 100644 --- a/lazer/sdk/js/package.json +++ b/lazer/sdk/js/package.json @@ -1,6 +1,6 @@ { "name": "@pythnetwork/pyth-lazer-sdk", - "version": "2.0.0", + "version": "2.1.0", "description": "Pyth Lazer SDK", "publishConfig": { "access": "public" @@ -59,6 +59,7 @@ "license": "Apache-2.0", "dependencies": { "@isaacs/ttlcache": "^1.4.1", + "cross-fetch": "^4.0.0", "isomorphic-ws": "^5.0.0", "ts-log": "^2.2.7", "ws": "^8.18.0" diff --git a/lazer/sdk/js/src/client.ts b/lazer/sdk/js/src/client.ts index b09b4eefad..2ad04d3130 100644 --- a/lazer/sdk/js/src/client.ts +++ b/lazer/sdk/js/src/client.ts @@ -1,6 +1,13 @@ +import fetch from "cross-fetch"; import WebSocket from "isomorphic-ws"; -import type { ParsedPayload, Request, Response } from "./protocol.js"; +import type { + ParsedPayload, + Request, + Response, + SymbolResponse, + SymbolsQueryParams, +} from "./protocol.js"; import { BINARY_UPDATE_FORMAT_MAGIC_LE, FORMAT_MAGICS_LE } from "./protocol.js"; import type { WebSocketPoolConfig } from "./socket/websocket-pool.js"; import { WebSocketPool } from "./socket/websocket-pool.js"; @@ -20,23 +27,30 @@ export type JsonOrBinaryResponse = } | { type: "binary"; value: BinaryResponse }; +export type LazerClientConfig = WebSocketPoolConfig & { + historyServiceUrl?: string; +}; + const UINT16_NUM_BYTES = 2; const UINT32_NUM_BYTES = 4; const UINT64_NUM_BYTES = 8; export class PythLazerClient { - private constructor(private readonly wsp: WebSocketPool) {} + private constructor( + private readonly wsp: WebSocketPool, + private readonly historyServiceUrl: string, + ) {} /** * Creates a new PythLazerClient instance. - * @param urls - List of WebSocket URLs of the Pyth Lazer service - * @param token - The access token for authentication - * @param numConnections - The number of parallel WebSocket connections to establish (default: 3). A higher number gives a more reliable stream. The connections will round-robin across the provided URLs. - * @param logger - Optional logger to get socket level logs. Compatible with most loggers such as the built-in console and `bunyan`. + * @param config - Configuration including WebSocket URLs, token, and optional history service URL */ - static async create(config: WebSocketPoolConfig): Promise { + static async create(config: LazerClientConfig): Promise { const wsp = await WebSocketPool.create(config); - return new PythLazerClient(wsp); + const historyServiceUrl = + config.historyServiceUrl ?? + "https://history.pyth-lazer.dourolabs.app/history"; + return new PythLazerClient(wsp, historyServiceUrl); } /** @@ -123,4 +137,32 @@ export class PythLazerClient { shutdown(): void { this.wsp.shutdown(); } + + /** + * Queries the symbols endpoint to get available price feed symbols. + * @param params - Optional query parameters to filter symbols + * @returns Promise resolving to array of symbol information + */ + async get_symbols(params?: SymbolsQueryParams): Promise { + const url = new URL(`${this.historyServiceUrl}/v1/symbols`); + + if (params?.query) { + url.searchParams.set("query", params.query); + } + if (params?.asset_type) { + url.searchParams.set("asset_type", params.asset_type); + } + + try { + const response = await fetch(url.toString()); + if (!response.ok) { + throw new Error(`HTTP error! status: ${String(response.status)}`); + } + return (await response.json()) as SymbolResponse[]; + } catch (error) { + throw new Error( + `Failed to fetch symbols: ${error instanceof Error ? error.message : String(error)}`, + ); + } + } } diff --git a/lazer/sdk/js/src/protocol.ts b/lazer/sdk/js/src/protocol.ts index 747a4cf3bf..956183e2fc 100644 --- a/lazer/sdk/js/src/protocol.ts +++ b/lazer/sdk/js/src/protocol.ts @@ -97,3 +97,34 @@ export const FORMAT_MAGICS_LE = { LE_ECDSA: 1_296_547_300, LE_UNSIGNED: 1_499_680_012, }; + +export type AssetType = + | "crypto" + | "fx" + | "equity" + | "metal" + | "rates" + | "nav" + | "commodity" + | "funding-rate"; + +export type SymbolsQueryParams = { + query?: string; + asset_type?: AssetType; +}; + +export type SymbolResponse = { + pyth_lazer_id: number; + name: string; + symbol: string; + description: string; + asset_type: string; + exponent: number; + min_publishers: number; + min_channel: string; + state: string; + schedule: string; + cmc_id?: number | null; + hermes_id?: string | null; + interval?: string | null; +}; From 04b4bf4508f23793adf458d8732fa8e413eb0d97 Mon Sep 17 00:00:00 2001 From: Tejas Badadare Date: Mon, 22 Sep 2025 16:42:22 -0700 Subject: [PATCH 02/12] move history endpoint to constants --- Cargo.lock | 36 ++-- lazer/sdk/js/package.json | 2 +- lazer/sdk/js/src/client.ts | 11 +- pnpm-lock.yaml | 341 +++++++++++++++++++++++++++---------- 4 files changed, 274 insertions(+), 116 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a94b6221f9..048f0956da 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5656,7 +5656,7 @@ dependencies = [ [[package]] name = "pyth-lazer-agent" -version = "0.5.0" +version = "0.5.1" dependencies = [ "anyhow", "backoff", @@ -5674,8 +5674,8 @@ dependencies = [ "hyper 1.6.0", "hyper-util", "protobuf", - "pyth-lazer-protocol 0.14.0", - "pyth-lazer-publisher-sdk 0.10.0", + "pyth-lazer-protocol 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)", + "pyth-lazer-publisher-sdk 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", "reqwest 0.12.23", "serde", "serde_json", @@ -5725,18 +5725,23 @@ dependencies = [ [[package]] name = "pyth-lazer-protocol" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91b3e69c264b2ad80b5943df86c606daae63b13f93062abcc008c09a9e2e621e" +version = "0.15.1" dependencies = [ + "alloy-primitives 0.8.25", "anyhow", + "assert_float_eq", + "bincode 1.3.3", + "bs58", "byteorder", "chrono", "derive_more 1.0.0", + "ed25519-dalek 2.1.1", "hex", "humantime", "humantime-serde", "itertools 0.13.0", + "libsecp256k1 0.7.2", + "mry", "protobuf", "rust_decimal", "serde", @@ -5747,22 +5752,17 @@ dependencies = [ [[package]] name = "pyth-lazer-protocol" version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d91dc5606c70529bf14769034738bc8773d359b4313be3c44449dd3b442096d" dependencies = [ - "alloy-primitives 0.8.25", "anyhow", - "assert_float_eq", - "bincode 1.3.3", - "bs58", "byteorder", "chrono", "derive_more 1.0.0", - "ed25519-dalek 2.1.1", "hex", "humantime", "humantime-serde", "itertools 0.13.0", - "libsecp256k1 0.7.2", - "mry", "protobuf", "rust_decimal", "serde", @@ -5772,27 +5772,27 @@ dependencies = [ [[package]] name = "pyth-lazer-publisher-sdk" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98f83b818450d72f6f6db5a9d98e90d2668971da14363820829998290d913f80" +version = "0.12.1" dependencies = [ "anyhow", "fs-err", "protobuf", "protobuf-codegen", - "pyth-lazer-protocol 0.14.0", + "pyth-lazer-protocol 0.15.1", "serde_json", ] [[package]] name = "pyth-lazer-publisher-sdk" version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34b5f8284182d0acb4afa3c8289727511e36f59ab15b52d850aa2e32ffe0684f" dependencies = [ "anyhow", "fs-err", "protobuf", "protobuf-codegen", - "pyth-lazer-protocol 0.15.1", + "pyth-lazer-protocol 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json", ] diff --git a/lazer/sdk/js/package.json b/lazer/sdk/js/package.json index bdcf824f83..089615308c 100644 --- a/lazer/sdk/js/package.json +++ b/lazer/sdk/js/package.json @@ -1,6 +1,6 @@ { "name": "@pythnetwork/pyth-lazer-sdk", - "version": "2.1.0", + "version": "3.0.0", "description": "Pyth Lazer SDK", "publishConfig": { "access": "public" diff --git a/lazer/sdk/js/src/client.ts b/lazer/sdk/js/src/client.ts index 2ad04d3130..366fcc352c 100644 --- a/lazer/sdk/js/src/client.ts +++ b/lazer/sdk/js/src/client.ts @@ -11,6 +11,7 @@ import type { import { BINARY_UPDATE_FORMAT_MAGIC_LE, FORMAT_MAGICS_LE } from "./protocol.js"; import type { WebSocketPoolConfig } from "./socket/websocket-pool.js"; import { WebSocketPool } from "./socket/websocket-pool.js"; +import { DEFAULT_HISTORY_SERVICE_URL } from "./constants.js"; export type BinaryResponse = { subscriptionId: number; @@ -22,9 +23,9 @@ export type BinaryResponse = { }; export type JsonOrBinaryResponse = | { - type: "json"; - value: Response; - } + type: "json"; + value: Response; + } | { type: "binary"; value: BinaryResponse }; export type LazerClientConfig = WebSocketPoolConfig & { @@ -39,7 +40,7 @@ export class PythLazerClient { private constructor( private readonly wsp: WebSocketPool, private readonly historyServiceUrl: string, - ) {} + ) { } /** * Creates a new PythLazerClient instance. @@ -49,7 +50,7 @@ export class PythLazerClient { const wsp = await WebSocketPool.create(config); const historyServiceUrl = config.historyServiceUrl ?? - "https://history.pyth-lazer.dourolabs.app/history"; + DEFAULT_HISTORY_SERVICE_URL; return new PythLazerClient(wsp, historyServiceUrl); } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4f6da87650..a8d1361769 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1310,7 +1310,7 @@ importers: version: 0.9.36(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bs58@5.0.0)(react-dom@19.1.0(react@19.1.0))(react-native@0.78.2(@babel/core@7.27.1)(@babel/preset-env@7.26.9(@babel/core@7.27.1))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))(react@19.1.0) '@solana/wallet-adapter-wallets': specifier: 'catalog:' - version: 0.19.33(@babel/runtime@7.27.0)(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.27.1)(@babel/preset-env@7.26.9(@babel/core@7.27.1))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))(@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bs58@5.0.0)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.1.0(react@19.1.0))(react-native@0.78.2(@babel/core@7.27.1)(@babel/preset-env@7.26.9(@babel/core@7.27.1))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))(react@19.1.0)(tslib@2.8.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.24.4) + version: 0.19.33(@babel/runtime@7.27.0)(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.27.1)(@babel/preset-env@7.26.9(@babel/core@7.27.1))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))(@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bs58@5.0.0)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(ioredis@5.7.0)(react-dom@19.1.0(react@19.1.0))(react-native@0.78.2(@babel/core@7.27.1)(@babel/preset-env@7.26.9(@babel/core@7.27.1))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))(react@19.1.0)(tslib@2.8.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.24.4) '@solana/web3.js': specifier: 'catalog:' version: 1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) @@ -1890,7 +1890,7 @@ importers: version: 0.9.36(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(react-dom@19.1.0(react@19.1.0))(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))(react@19.1.0) '@solana/wallet-adapter-wallets': specifier: 'catalog:' - version: 0.19.33(@babel/runtime@7.27.0)(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))(@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.1.0(react@19.1.0))(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))(react@19.1.0)(tslib@2.8.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.24.2) + version: 0.19.33(@babel/runtime@7.27.0)(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))(@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(ioredis@5.7.0)(react-dom@19.1.0(react@19.1.0))(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))(react@19.1.0)(tslib@2.8.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.24.2) '@solana/web3.js': specifier: ^1.73.0 version: 1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) @@ -2077,6 +2077,9 @@ importers: '@isaacs/ttlcache': specifier: ^1.4.1 version: 1.4.1 + cross-fetch: + specifier: ^4.0.0 + version: 4.1.0(encoding@0.1.13) isomorphic-ws: specifier: ^5.0.0 version: 5.0.0(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@6.0.3)) @@ -26900,6 +26903,17 @@ snapshots: '@ethersproject/properties': 5.8.0 '@ethersproject/strings': 5.8.0 + '@everstake/wallet-sdk-solana@2.0.9(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + dependencies: + '@solana-program/compute-budget': 0.6.1(@solana/web3.js@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))) + '@solana-program/stake': 0.1.0(@solana/web3.js@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))) + '@solana-program/system': 0.6.2(@solana/web3.js@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))) + '@solana/web3.js': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + - typescript + - ws + '@everstake/wallet-sdk-solana@2.0.9(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: '@solana-program/compute-budget': 0.6.1(@solana/web3.js@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))) @@ -28413,12 +28427,12 @@ snapshots: '@types/yargs': 17.0.33 chalk: 4.1.2 - '@jnwng/walletconnect-solana@0.2.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.2)': + '@jnwng/walletconnect-solana@0.2.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(ioredis@5.7.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.2)': dependencies: '@solana/web3.js': 1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) '@walletconnect/qrcode-modal': 1.8.0 - '@walletconnect/sign-client': 2.19.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.2) - '@walletconnect/utils': 2.19.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.2) + '@walletconnect/sign-client': 2.19.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.7.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.2) + '@walletconnect/utils': 2.19.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.7.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.2) bs58: 5.0.0 transitivePeerDependencies: - '@azure/app-configuration' @@ -28444,11 +28458,11 @@ snapshots: - utf-8-validate - zod - '@jnwng/walletconnect-solana@0.2.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.27.1)(@babel/preset-env@7.26.9(@babel/core@7.27.1))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.4)': + '@jnwng/walletconnect-solana@0.2.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.27.1)(@babel/preset-env@7.26.9(@babel/core@7.27.1))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(ioredis@5.7.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.4)': dependencies: '@solana/web3.js': 1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) '@walletconnect/qrcode-modal': 1.8.0 - '@walletconnect/sign-client': 2.19.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.27.1)(@babel/preset-env@7.26.9(@babel/core@7.27.1))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.4) + '@walletconnect/sign-client': 2.19.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.27.1)(@babel/preset-env@7.26.9(@babel/core@7.27.1))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.7.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.4) '@walletconnect/utils': 2.19.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.27.1)(@babel/preset-env@7.26.9(@babel/core@7.27.1))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.7.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.4) bs58: 5.0.0 transitivePeerDependencies: @@ -31839,7 +31853,7 @@ snapshots: '@react-native/codegen@0.78.2(@babel/preset-env@7.26.9(@babel/core@7.26.10))': dependencies: - '@babel/parser': 7.27.2 + '@babel/parser': 7.28.4 '@babel/preset-env': 7.26.9(@babel/core@7.26.10) glob: 7.2.3 hermes-parser: 0.25.1 @@ -31852,7 +31866,7 @@ snapshots: '@react-native/codegen@0.78.2(@babel/preset-env@7.26.9(@babel/core@7.27.1))': dependencies: - '@babel/parser': 7.27.2 + '@babel/parser': 7.28.4 '@babel/preset-env': 7.26.9(@babel/core@7.27.1) glob: 7.2.3 hermes-parser: 0.25.1 @@ -33121,31 +33135,60 @@ snapshots: - react - react-native + '@solana-program/compute-budget@0.6.1(@solana/web3.js@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)))': + dependencies: + '@solana/web3.js': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana-program/compute-budget@0.6.1(@solana/web3.js@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)))': dependencies: '@solana/web3.js': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana-program/compute-budget@0.7.0(@solana/kit@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)))': + dependencies: + '@solana/kit': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana-program/compute-budget@0.7.0(@solana/kit@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)))': dependencies: '@solana/kit': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana-program/stake@0.1.0(@solana/web3.js@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)))': + dependencies: + '@solana/web3.js': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana-program/stake@0.1.0(@solana/web3.js@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)))': dependencies: '@solana/web3.js': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana-program/system@0.6.2(@solana/web3.js@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)))': + dependencies: + '@solana/web3.js': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana-program/system@0.6.2(@solana/web3.js@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)))': dependencies: '@solana/web3.js': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana-program/system@0.7.0(@solana/kit@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)))': + dependencies: + '@solana/kit': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana-program/system@0.7.0(@solana/kit@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)))': dependencies: '@solana/kit': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana-program/token-2022@0.4.0(@solana/kit@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)))(@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))': + dependencies: + '@solana/kit': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/sysvars': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana-program/token-2022@0.4.0(@solana/kit@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)))(@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))': dependencies: '@solana/kit': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) '@solana/sysvars': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana-program/token@0.5.1(@solana/kit@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)))': + dependencies: + '@solana/kit': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana-program/token@0.5.1(@solana/kit@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)))': dependencies: '@solana/kit': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) @@ -33485,6 +33528,31 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/kit@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + dependencies: + '@solana/accounts': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/addresses': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/codecs': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/errors': 2.1.0(typescript@5.8.2) + '@solana/functional': 2.1.0(typescript@5.8.2) + '@solana/instructions': 2.1.0(typescript@5.8.2) + '@solana/keys': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/programs': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/rpc': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/rpc-parsed-types': 2.1.0(typescript@5.8.2) + '@solana/rpc-spec-types': 2.1.0(typescript@5.8.2) + '@solana/rpc-subscriptions': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/rpc-types': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/signers': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/sysvars': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/transaction-confirmation': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/transaction-messages': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/transactions': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + typescript: 5.8.2 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + - ws + '@solana/kit@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: '@solana/accounts': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) @@ -33671,6 +33739,15 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/rpc-subscriptions-channel-websocket@2.0.0(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + dependencies: + '@solana/errors': 2.0.0(typescript@5.8.2) + '@solana/functional': 2.0.0(typescript@5.8.2) + '@solana/rpc-subscriptions-spec': 2.0.0(typescript@5.8.2) + '@solana/subscribable': 2.0.0(typescript@5.8.2) + typescript: 5.8.2 + ws: 8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@solana/rpc-subscriptions-channel-websocket@2.0.0(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: '@solana/errors': 2.0.0(typescript@5.8.2) @@ -33680,6 +33757,15 @@ snapshots: typescript: 5.8.2 ws: 8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@solana/rpc-subscriptions-channel-websocket@2.1.0(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + dependencies: + '@solana/errors': 2.1.0(typescript@5.8.2) + '@solana/functional': 2.1.0(typescript@5.8.2) + '@solana/rpc-subscriptions-spec': 2.1.0(typescript@5.8.2) + '@solana/subscribable': 2.1.0(typescript@5.8.2) + typescript: 5.8.2 + ws: 8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@solana/rpc-subscriptions-channel-websocket@2.1.0(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: '@solana/errors': 2.1.0(typescript@5.8.2) @@ -33705,6 +33791,24 @@ snapshots: '@solana/subscribable': 2.1.0(typescript@5.8.2) typescript: 5.8.2 + '@solana/rpc-subscriptions@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + dependencies: + '@solana/errors': 2.0.0(typescript@5.8.2) + '@solana/fast-stable-stringify': 2.0.0(typescript@5.8.2) + '@solana/functional': 2.0.0(typescript@5.8.2) + '@solana/promises': 2.0.0(typescript@5.8.2) + '@solana/rpc-spec-types': 2.0.0(typescript@5.8.2) + '@solana/rpc-subscriptions-api': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/rpc-subscriptions-channel-websocket': 2.0.0(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/rpc-subscriptions-spec': 2.0.0(typescript@5.8.2) + '@solana/rpc-transformers': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/rpc-types': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/subscribable': 2.0.0(typescript@5.8.2) + typescript: 5.8.2 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + - ws + '@solana/rpc-subscriptions@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: '@solana/errors': 2.0.0(typescript@5.8.2) @@ -33723,6 +33827,24 @@ snapshots: - fastestsmallesttextencoderdecoder - ws + '@solana/rpc-subscriptions@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + dependencies: + '@solana/errors': 2.1.0(typescript@5.8.2) + '@solana/fast-stable-stringify': 2.1.0(typescript@5.8.2) + '@solana/functional': 2.1.0(typescript@5.8.2) + '@solana/promises': 2.1.0(typescript@5.8.2) + '@solana/rpc-spec-types': 2.1.0(typescript@5.8.2) + '@solana/rpc-subscriptions-api': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/rpc-subscriptions-channel-websocket': 2.1.0(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/rpc-subscriptions-spec': 2.1.0(typescript@5.8.2) + '@solana/rpc-transformers': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/rpc-types': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/subscribable': 2.1.0(typescript@5.8.2) + typescript: 5.8.2 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + - ws + '@solana/rpc-subscriptions@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: '@solana/errors': 2.1.0(typescript@5.8.2) @@ -33993,6 +34115,23 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/transaction-confirmation@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + dependencies: + '@solana/addresses': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/codecs-strings': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/errors': 2.0.0(typescript@5.8.2) + '@solana/keys': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/promises': 2.0.0(typescript@5.8.2) + '@solana/rpc': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/rpc-subscriptions': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/rpc-types': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/transaction-messages': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/transactions': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + typescript: 5.8.2 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + - ws + '@solana/transaction-confirmation@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: '@solana/addresses': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) @@ -34010,6 +34149,23 @@ snapshots: - fastestsmallesttextencoderdecoder - ws + '@solana/transaction-confirmation@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + dependencies: + '@solana/addresses': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/codecs-strings': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/errors': 2.1.0(typescript@5.8.2) + '@solana/keys': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/promises': 2.1.0(typescript@5.8.2) + '@solana/rpc': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/rpc-subscriptions': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/rpc-types': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/transaction-messages': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/transactions': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + typescript: 5.8.2 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + - ws + '@solana/transaction-confirmation@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: '@solana/addresses': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) @@ -34383,11 +34539,11 @@ snapshots: - utf-8-validate - ws - '@solana/wallet-adapter-trezor@0.1.3(@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.78.2(@babel/core@7.27.1)(@babel/preset-env@7.26.9(@babel/core@7.27.1))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))(tslib@2.8.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + '@solana/wallet-adapter-trezor@0.1.3(@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.78.2(@babel/core@7.27.1)(@babel/preset-env@7.26.9(@babel/core@7.27.1))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))(tslib@2.8.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: '@solana/wallet-adapter-base': 0.9.24(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) '@solana/web3.js': 1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) - '@trezor/connect-web': 9.5.3(@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.78.2(@babel/core@7.27.1)(@babel/preset-env@7.26.9(@babel/core@7.27.1))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))(tslib@2.8.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@trezor/connect-web': 9.5.3(@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.78.2(@babel/core@7.27.1)(@babel/preset-env@7.26.9(@babel/core@7.27.1))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))(tslib@2.8.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) buffer: 6.0.3 transitivePeerDependencies: - '@solana/sysvars' @@ -34416,9 +34572,9 @@ snapshots: '@solana/wallet-standard-util': 1.1.2 '@solana/web3.js': 1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) - '@solana/wallet-adapter-walletconnect@0.1.17(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.2)': + '@solana/wallet-adapter-walletconnect@0.1.17(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(ioredis@5.7.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.2)': dependencies: - '@jnwng/walletconnect-solana': 0.2.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.2) + '@jnwng/walletconnect-solana': 0.2.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(ioredis@5.7.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.2) '@solana/wallet-adapter-base': 0.9.24(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) '@solana/web3.js': 1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) transitivePeerDependencies: @@ -34445,9 +34601,9 @@ snapshots: - utf-8-validate - zod - '@solana/wallet-adapter-walletconnect@0.1.17(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.27.1)(@babel/preset-env@7.26.9(@babel/core@7.27.1))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.4)': + '@solana/wallet-adapter-walletconnect@0.1.17(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.27.1)(@babel/preset-env@7.26.9(@babel/core@7.27.1))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(ioredis@5.7.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.4)': dependencies: - '@jnwng/walletconnect-solana': 0.2.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.27.1)(@babel/preset-env@7.26.9(@babel/core@7.27.1))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.4) + '@jnwng/walletconnect-solana': 0.2.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.27.1)(@babel/preset-env@7.26.9(@babel/core@7.27.1))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(ioredis@5.7.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.4) '@solana/wallet-adapter-base': 0.9.24(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) '@solana/web3.js': 1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) transitivePeerDependencies: @@ -34474,7 +34630,7 @@ snapshots: - utf-8-validate - zod - '@solana/wallet-adapter-wallets@0.19.33(@babel/runtime@7.27.0)(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))(@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.1.0(react@19.1.0))(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))(react@19.1.0)(tslib@2.8.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.24.2)': + '@solana/wallet-adapter-wallets@0.19.33(@babel/runtime@7.27.0)(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))(@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(ioredis@5.7.0)(react-dom@19.1.0(react@19.1.0))(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))(react@19.1.0)(tslib@2.8.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.24.2)': dependencies: '@solana/wallet-adapter-alpha': 0.1.11(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) '@solana/wallet-adapter-avana': 0.1.14(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) @@ -34510,7 +34666,7 @@ snapshots: '@solana/wallet-adapter-trezor': 0.1.3(@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))(tslib@2.8.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) '@solana/wallet-adapter-trust': 0.1.14(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) '@solana/wallet-adapter-unsafe-burner': 0.1.8(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) - '@solana/wallet-adapter-walletconnect': 0.1.17(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.2) + '@solana/wallet-adapter-walletconnect': 0.1.17(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(ioredis@5.7.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.2) '@solana/wallet-adapter-xdefi': 0.1.8(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) '@solana/web3.js': 1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) transitivePeerDependencies: @@ -34551,7 +34707,7 @@ snapshots: - ws - zod - '@solana/wallet-adapter-wallets@0.19.33(@babel/runtime@7.27.0)(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.27.1)(@babel/preset-env@7.26.9(@babel/core@7.27.1))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))(@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bs58@5.0.0)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.1.0(react@19.1.0))(react-native@0.78.2(@babel/core@7.27.1)(@babel/preset-env@7.26.9(@babel/core@7.27.1))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))(react@19.1.0)(tslib@2.8.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.24.4)': + '@solana/wallet-adapter-wallets@0.19.33(@babel/runtime@7.27.0)(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.27.1)(@babel/preset-env@7.26.9(@babel/core@7.27.1))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))(@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bs58@5.0.0)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(ioredis@5.7.0)(react-dom@19.1.0(react@19.1.0))(react-native@0.78.2(@babel/core@7.27.1)(@babel/preset-env@7.26.9(@babel/core@7.27.1))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))(react@19.1.0)(tslib@2.8.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.24.4)': dependencies: '@solana/wallet-adapter-alpha': 0.1.11(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) '@solana/wallet-adapter-avana': 0.1.14(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) @@ -34584,10 +34740,10 @@ snapshots: '@solana/wallet-adapter-tokenary': 0.1.13(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) '@solana/wallet-adapter-tokenpocket': 0.4.20(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) '@solana/wallet-adapter-torus': 0.11.29(@babel/runtime@7.27.0)(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) - '@solana/wallet-adapter-trezor': 0.1.3(@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.78.2(@babel/core@7.27.1)(@babel/preset-env@7.26.9(@babel/core@7.27.1))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))(tslib@2.8.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/wallet-adapter-trezor': 0.1.3(@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.78.2(@babel/core@7.27.1)(@babel/preset-env@7.26.9(@babel/core@7.27.1))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))(tslib@2.8.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) '@solana/wallet-adapter-trust': 0.1.14(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) '@solana/wallet-adapter-unsafe-burner': 0.1.8(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) - '@solana/wallet-adapter-walletconnect': 0.1.17(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.27.1)(@babel/preset-env@7.26.9(@babel/core@7.27.1))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.4) + '@solana/wallet-adapter-walletconnect': 0.1.17(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.27.1)(@babel/preset-env@7.26.9(@babel/core@7.27.1))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(ioredis@5.7.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.4) '@solana/wallet-adapter-xdefi': 0.1.8(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) '@solana/web3.js': 1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) transitivePeerDependencies: @@ -34810,6 +34966,31 @@ snapshots: - encoding - utf-8-validate + '@solana/web3.js@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + dependencies: + '@solana/accounts': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/addresses': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/codecs': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/errors': 2.0.0(typescript@5.8.2) + '@solana/functional': 2.0.0(typescript@5.8.2) + '@solana/instructions': 2.0.0(typescript@5.8.2) + '@solana/keys': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/programs': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/rpc': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/rpc-parsed-types': 2.0.0(typescript@5.8.2) + '@solana/rpc-spec-types': 2.0.0(typescript@5.8.2) + '@solana/rpc-subscriptions': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/rpc-types': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/signers': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/sysvars': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/transaction-confirmation': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/transaction-messages': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/transactions': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + typescript: 5.8.2 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + - ws + '@solana/web3.js@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: '@solana/accounts': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) @@ -35947,6 +36128,17 @@ snapshots: - expo-localization - react-native + '@trezor/blockchain-link-types@1.3.3(fastestsmallesttextencoderdecoder@1.0.22)(tslib@2.8.1)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + dependencies: + '@solana/kit': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@trezor/type-utils': 1.1.5 + '@trezor/utxo-lib': 2.3.3(tslib@2.8.1) + tslib: 2.8.1 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + - typescript + - ws + '@trezor/blockchain-link-types@1.3.3(fastestsmallesttextencoderdecoder@1.0.22)(tslib@2.8.1)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: '@solana/kit': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) @@ -36009,13 +36201,13 @@ snapshots: - utf-8-validate - ws - '@trezor/blockchain-link@2.4.3(@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.78.2(@babel/core@7.27.1)(@babel/preset-env@7.26.9(@babel/core@7.27.1))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))(tslib@2.8.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + '@trezor/blockchain-link@2.4.3(@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.78.2(@babel/core@7.27.1)(@babel/preset-env@7.26.9(@babel/core@7.27.1))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))(tslib@2.8.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: - '@everstake/wallet-sdk-solana': 2.0.9(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@solana-program/token': 0.5.1(@solana/kit@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))) - '@solana-program/token-2022': 0.4.0(@solana/kit@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)))(@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)) - '@solana/kit': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@trezor/blockchain-link-types': 1.3.3(fastestsmallesttextencoderdecoder@1.0.22)(tslib@2.8.1)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@everstake/wallet-sdk-solana': 2.0.9(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana-program/token': 0.5.1(@solana/kit@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))) + '@solana-program/token-2022': 0.4.0(@solana/kit@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)))(@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)) + '@solana/kit': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@trezor/blockchain-link-types': 1.3.3(fastestsmallesttextencoderdecoder@1.0.22)(tslib@2.8.1)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) '@trezor/blockchain-link-utils': 1.3.3(react-native@0.78.2(@babel/core@7.27.1)(@babel/preset-env@7.26.9(@babel/core@7.27.1))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))(tslib@2.8.1) '@trezor/env-utils': 1.3.2(react-native@0.78.2(@babel/core@7.27.1)(@babel/preset-env@7.26.9(@babel/core@7.27.1))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))(tslib@2.8.1) '@trezor/utils': 9.3.3(tslib@2.8.1) @@ -36095,9 +36287,9 @@ snapshots: - utf-8-validate - ws - '@trezor/connect-web@9.5.3(@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.78.2(@babel/core@7.27.1)(@babel/preset-env@7.26.9(@babel/core@7.27.1))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))(tslib@2.8.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + '@trezor/connect-web@9.5.3(@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.78.2(@babel/core@7.27.1)(@babel/preset-env@7.26.9(@babel/core@7.27.1))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))(tslib@2.8.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: - '@trezor/connect': 9.5.3(@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.78.2(@babel/core@7.27.1)(@babel/preset-env@7.26.9(@babel/core@7.27.1))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))(tslib@2.8.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@trezor/connect': 9.5.3(@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.78.2(@babel/core@7.27.1)(@babel/preset-env@7.26.9(@babel/core@7.27.1))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))(tslib@2.8.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) '@trezor/connect-common': 0.3.3(react-native@0.78.2(@babel/core@7.27.1)(@babel/preset-env@7.26.9(@babel/core@7.27.1))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))(tslib@2.8.1) '@trezor/utils': 9.3.3(tslib@2.8.1) tslib: 2.8.1 @@ -36158,7 +36350,7 @@ snapshots: - utf-8-validate - ws - '@trezor/connect@9.5.3(@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.78.2(@babel/core@7.27.1)(@babel/preset-env@7.26.9(@babel/core@7.27.1))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))(tslib@2.8.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + '@trezor/connect@9.5.3(@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.78.2(@babel/core@7.27.1)(@babel/preset-env@7.26.9(@babel/core@7.27.1))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))(tslib@2.8.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: '@ethereumjs/common': 4.4.0 '@ethereumjs/tx': 5.4.0 @@ -36166,13 +36358,13 @@ snapshots: '@mobily/ts-belt': 3.13.1 '@noble/hashes': 1.8.0 '@scure/bip39': 1.6.0 - '@solana-program/compute-budget': 0.7.0(@solana/kit@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))) - '@solana-program/system': 0.7.0(@solana/kit@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))) - '@solana-program/token': 0.5.1(@solana/kit@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))) - '@solana-program/token-2022': 0.4.0(@solana/kit@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)))(@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)) - '@solana/kit': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@trezor/blockchain-link': 2.4.3(@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.78.2(@babel/core@7.27.1)(@babel/preset-env@7.26.9(@babel/core@7.27.1))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))(tslib@2.8.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@trezor/blockchain-link-types': 1.3.3(fastestsmallesttextencoderdecoder@1.0.22)(tslib@2.8.1)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana-program/compute-budget': 0.7.0(@solana/kit@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))) + '@solana-program/system': 0.7.0(@solana/kit@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))) + '@solana-program/token': 0.5.1(@solana/kit@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))) + '@solana-program/token-2022': 0.4.0(@solana/kit@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)))(@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)) + '@solana/kit': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@trezor/blockchain-link': 2.4.3(@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.78.2(@babel/core@7.27.1)(@babel/preset-env@7.26.9(@babel/core@7.27.1))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))(tslib@2.8.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@trezor/blockchain-link-types': 1.3.3(fastestsmallesttextencoderdecoder@1.0.22)(tslib@2.8.1)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) '@trezor/blockchain-link-utils': 1.3.3(react-native@0.78.2(@babel/core@7.27.1)(@babel/preset-env@7.26.9(@babel/core@7.27.1))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))(tslib@2.8.1) '@trezor/connect-analytics': 1.3.2(react-native@0.78.2(@babel/core@7.27.1)(@babel/preset-env@7.26.9(@babel/core@7.27.1))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))(tslib@2.8.1) '@trezor/connect-common': 0.3.3(react-native@0.78.2(@babel/core@7.27.1)(@babel/preset-env@7.26.9(@babel/core@7.27.1))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))(tslib@2.8.1) @@ -37711,21 +37903,21 @@ snapshots: '@walletconnect/window-metadata': 1.0.0 detect-browser: 5.2.0 - '@walletconnect/core@2.19.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.2)': + '@walletconnect/core@2.19.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.7.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.2)': dependencies: '@walletconnect/heartbeat': 1.2.2 '@walletconnect/jsonrpc-provider': 1.0.14 '@walletconnect/jsonrpc-types': 1.0.4 '@walletconnect/jsonrpc-utils': 1.0.8 '@walletconnect/jsonrpc-ws-connection': 1.0.16(bufferutil@4.0.9)(utf-8-validate@5.0.10) - '@walletconnect/keyvaluestorage': 1.1.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))) + '@walletconnect/keyvaluestorage': 1.1.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))(ioredis@5.7.0) '@walletconnect/logger': 2.1.2 '@walletconnect/relay-api': 1.0.11 '@walletconnect/relay-auth': 1.1.0 '@walletconnect/safe-json': 1.0.2 '@walletconnect/time': 1.0.2 - '@walletconnect/types': 2.19.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))) - '@walletconnect/utils': 2.19.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.2) + '@walletconnect/types': 2.19.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))(ioredis@5.7.0) + '@walletconnect/utils': 2.19.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.7.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.2) '@walletconnect/window-getters': 1.0.1 es-toolkit: 1.33.0 events: 3.3.0 @@ -37888,7 +38080,7 @@ snapshots: - bufferutil - utf-8-validate - '@walletconnect/keyvaluestorage@1.1.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))': + '@walletconnect/keyvaluestorage@1.1.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))(ioredis@5.7.0)': dependencies: '@walletconnect/safe-json': 1.0.2 idb-keyval: 6.2.1 @@ -37999,16 +38191,16 @@ snapshots: dependencies: tslib: 1.14.1 - '@walletconnect/sign-client@2.19.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.2)': + '@walletconnect/sign-client@2.19.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.7.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.2)': dependencies: - '@walletconnect/core': 2.19.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.2) + '@walletconnect/core': 2.19.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.7.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.2) '@walletconnect/events': 1.0.1 '@walletconnect/heartbeat': 1.2.2 '@walletconnect/jsonrpc-utils': 1.0.8 '@walletconnect/logger': 2.1.2 '@walletconnect/time': 1.0.2 - '@walletconnect/types': 2.19.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))) - '@walletconnect/utils': 2.19.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.2) + '@walletconnect/types': 2.19.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))(ioredis@5.7.0) + '@walletconnect/utils': 2.19.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.7.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.2) events: 3.3.0 transitivePeerDependencies: - '@azure/app-configuration' @@ -38069,53 +38261,18 @@ snapshots: - utf-8-validate - zod - '@walletconnect/sign-client@2.19.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.27.1)(@babel/preset-env@7.26.9(@babel/core@7.27.1))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.4)': - dependencies: - '@walletconnect/core': 2.19.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.27.1)(@babel/preset-env@7.26.9(@babel/core@7.27.1))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.7.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.4) - '@walletconnect/events': 1.0.1 - '@walletconnect/heartbeat': 1.2.2 - '@walletconnect/jsonrpc-utils': 1.0.8 - '@walletconnect/logger': 2.1.2 - '@walletconnect/time': 1.0.2 - '@walletconnect/types': 2.19.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.27.1)(@babel/preset-env@7.26.9(@babel/core@7.27.1))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))(ioredis@5.7.0) - '@walletconnect/utils': 2.19.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.27.1)(@babel/preset-env@7.26.9(@babel/core@7.27.1))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.7.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.4) - events: 3.3.0 - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - ioredis - - typescript - - uploadthing - - utf-8-validate - - zod - '@walletconnect/time@1.0.2': dependencies: tslib: 1.14.1 '@walletconnect/types@1.8.0': {} - '@walletconnect/types@2.19.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))': + '@walletconnect/types@2.19.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))(ioredis@5.7.0)': dependencies: '@walletconnect/events': 1.0.1 '@walletconnect/heartbeat': 1.2.2 '@walletconnect/jsonrpc-types': 1.0.4 - '@walletconnect/keyvaluestorage': 1.1.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))) + '@walletconnect/keyvaluestorage': 1.1.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))(ioredis@5.7.0) '@walletconnect/logger': 2.1.2 events: 3.3.0 transitivePeerDependencies: @@ -38205,18 +38362,18 @@ snapshots: - utf-8-validate - zod - '@walletconnect/utils@2.19.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.2)': + '@walletconnect/utils@2.19.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.7.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.2)': dependencies: '@noble/ciphers': 1.2.1 '@noble/curves': 1.8.1 '@noble/hashes': 1.7.1 '@walletconnect/jsonrpc-utils': 1.0.8 - '@walletconnect/keyvaluestorage': 1.1.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))) + '@walletconnect/keyvaluestorage': 1.1.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))(ioredis@5.7.0) '@walletconnect/relay-api': 1.0.11 '@walletconnect/relay-auth': 1.1.0 '@walletconnect/safe-json': 1.0.2 '@walletconnect/time': 1.0.2 - '@walletconnect/types': 2.19.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))) + '@walletconnect/types': 2.19.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))(ioredis@5.7.0) '@walletconnect/window-getters': 1.0.1 '@walletconnect/window-metadata': 1.0.1 bs58: 6.0.0 @@ -45625,7 +45782,7 @@ snapshots: jscodeshift@17.3.0(@babel/preset-env@7.26.9(@babel/core@7.26.10)): dependencies: '@babel/core': 7.27.1 - '@babel/parser': 7.27.2 + '@babel/parser': 7.28.4 '@babel/plugin-transform-class-properties': 7.25.9(@babel/core@7.27.1) '@babel/plugin-transform-modules-commonjs': 7.27.1(@babel/core@7.27.1) '@babel/plugin-transform-nullish-coalescing-operator': 7.26.6(@babel/core@7.27.1) @@ -45650,7 +45807,7 @@ snapshots: jscodeshift@17.3.0(@babel/preset-env@7.26.9(@babel/core@7.27.1)): dependencies: '@babel/core': 7.27.1 - '@babel/parser': 7.27.2 + '@babel/parser': 7.28.4 '@babel/plugin-transform-class-properties': 7.25.9(@babel/core@7.27.1) '@babel/plugin-transform-modules-commonjs': 7.27.1(@babel/core@7.27.1) '@babel/plugin-transform-nullish-coalescing-operator': 7.26.6(@babel/core@7.27.1) @@ -46552,7 +46709,7 @@ snapshots: dependencies: '@babel/traverse': 7.27.1 '@babel/traverse--for-generate-function-map': '@babel/traverse@7.27.1' - '@babel/types': 7.27.1 + '@babel/types': 7.28.4 flow-enums-runtime: 0.0.6 invariant: 2.2.4 metro-symbolicate: 0.81.4 @@ -46589,8 +46746,8 @@ snapshots: dependencies: '@babel/core': 7.27.1 '@babel/generator': 7.27.1 - '@babel/parser': 7.27.2 - '@babel/types': 7.27.1 + '@babel/parser': 7.28.4 + '@babel/types': 7.28.4 flow-enums-runtime: 0.0.6 metro: 0.81.4(bufferutil@4.0.9)(utf-8-validate@5.0.10) metro-babel-transformer: 0.81.4 @@ -46610,10 +46767,10 @@ snapshots: '@babel/code-frame': 7.27.1 '@babel/core': 7.27.1 '@babel/generator': 7.27.1 - '@babel/parser': 7.27.2 + '@babel/parser': 7.28.4 '@babel/template': 7.27.2 '@babel/traverse': 7.27.1 - '@babel/types': 7.27.1 + '@babel/types': 7.28.4 accepts: 1.3.8 chalk: 4.1.2 ci-info: 2.0.0 From 728be08c4d675920d67377b7cc88e0c248c14089 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 23 Sep 2025 00:04:27 +0000 Subject: [PATCH 03/12] feat(lazer-sdk): add Router service support with latest_price and price endpoints - Add TypeScript interfaces for LatestPriceRequest, PriceRequest, and JsonUpdate - Update LazerClientConfig to include routerServiceUrl with default - Implement get_latest_price() and get_price() HTTP methods in PythLazerClient - Create router-example.ts demonstrating all Router endpoint use cases - Bump version to 2.2.0 to reflect new Router service functionality - Add router-example script to package.json for easy testing Co-Authored-By: Tejas Badadare --- lazer/sdk/js/examples/router-example.ts | 49 ++++++++++++++ lazer/sdk/js/package.json | 3 +- lazer/sdk/js/src/client.ts | 87 ++++++++++++++++++++++++- lazer/sdk/js/src/protocol.ts | 29 +++++++++ 4 files changed, 165 insertions(+), 3 deletions(-) create mode 100644 lazer/sdk/js/examples/router-example.ts diff --git a/lazer/sdk/js/examples/router-example.ts b/lazer/sdk/js/examples/router-example.ts new file mode 100644 index 0000000000..a24011db61 --- /dev/null +++ b/lazer/sdk/js/examples/router-example.ts @@ -0,0 +1,49 @@ +import { PythLazerClient } from "../src/index.js"; + +const client = await PythLazerClient.create({ + urls: ["wss://router.pyth-lazer.dourolabs.app/ws"], + token: "", + routerServiceUrl: "https://router.pyth-lazer.dourolabs.app", +}); + +// Example 1: Get latest price for BTC using feed IDs +await client.get_latest_price({ + priceFeedIds: [1], + properties: ["price", "confidence", "exponent"], + formats: ["solana"], + jsonBinaryEncoding: "hex", + parsed: true, + channel: "fixed_rate@200ms", +}); + +// Example 2: Get latest price using symbols +await client.get_latest_price({ + symbols: ["BTC/USD"], + properties: ["price", "confidence"], + formats: ["evm"], + parsed: true, + channel: "real_time", +}); + +// Example 3: Get historical price at specific timestamp +const historicalTimestamp = (Date.now() - 60_000) * 1000; +await client.get_price({ + timestamp: historicalTimestamp.toString(), + priceFeedIds: [1], + properties: ["price", "publisherCount"], + formats: ["solana"], + parsed: true, + channel: "fixed_rate@200ms", +}); + +// Example 4: Get multiple feeds with different formats +await client.get_latest_price({ + priceFeedIds: [1, 2, 3], + properties: ["price", "confidence", "exponent", "publisherCount"], + formats: ["evm", "solana"], + jsonBinaryEncoding: "base64", + parsed: true, + channel: "fixed_rate@50ms", +}); + +client.shutdown(); diff --git a/lazer/sdk/js/package.json b/lazer/sdk/js/package.json index bdcf824f83..fb1b04d622 100644 --- a/lazer/sdk/js/package.json +++ b/lazer/sdk/js/package.json @@ -1,6 +1,6 @@ { "name": "@pythnetwork/pyth-lazer-sdk", - "version": "2.1.0", + "version": "2.2.0", "description": "Pyth Lazer SDK", "publishConfig": { "access": "public" @@ -29,6 +29,7 @@ "test:format": "prettier --check .", "fix:format": "prettier --write .", "example": "node --loader ts-node/esm examples/index.js", + "router-example": "node --loader ts-node/esm examples/router-example.js", "doc": "typedoc --out docs/typedoc src" }, "devDependencies": { diff --git a/lazer/sdk/js/src/client.ts b/lazer/sdk/js/src/client.ts index 2ad04d3130..cdc32c639b 100644 --- a/lazer/sdk/js/src/client.ts +++ b/lazer/sdk/js/src/client.ts @@ -7,6 +7,9 @@ import type { Response, SymbolResponse, SymbolsQueryParams, + LatestPriceRequest, + PriceRequest, + JsonUpdate, } from "./protocol.js"; import { BINARY_UPDATE_FORMAT_MAGIC_LE, FORMAT_MAGICS_LE } from "./protocol.js"; import type { WebSocketPoolConfig } from "./socket/websocket-pool.js"; @@ -29,6 +32,7 @@ export type JsonOrBinaryResponse = export type LazerClientConfig = WebSocketPoolConfig & { historyServiceUrl?: string; + routerServiceUrl?: string; }; const UINT16_NUM_BYTES = 2; @@ -39,18 +43,22 @@ export class PythLazerClient { private constructor( private readonly wsp: WebSocketPool, private readonly historyServiceUrl: string, + private readonly routerServiceUrl: string, ) {} /** * Creates a new PythLazerClient instance. - * @param config - Configuration including WebSocket URLs, token, and optional history service URL + * @param config - Configuration including WebSocket URLs, token, history service URL, and router service URL */ static async create(config: LazerClientConfig): Promise { const wsp = await WebSocketPool.create(config); const historyServiceUrl = config.historyServiceUrl ?? "https://history.pyth-lazer.dourolabs.app/history"; - return new PythLazerClient(wsp, historyServiceUrl); + const routerServiceUrl = + config.routerServiceUrl ?? + "https://router.pyth-lazer.dourolabs.app"; + return new PythLazerClient(wsp, historyServiceUrl, routerServiceUrl); } /** @@ -165,4 +173,79 @@ export class PythLazerClient { ); } } + + /** + * Queries the latest price endpoint to get current price data. + * @param params - Parameters for the latest price request + * @returns Promise resolving to JsonUpdate with current price data + */ + async get_latest_price(params: LatestPriceRequest): Promise { + const url = new URL(`${this.routerServiceUrl}/v1/latest_price`); + + if (params.priceFeedIds) { + for (const id of params.priceFeedIds) url.searchParams.append('priceFeedIds', id.toString()); + } + if (params.symbols) { + for (const symbol of params.symbols) url.searchParams.append('symbols', symbol); + } + for (const prop of params.properties) url.searchParams.append('properties', prop); + for (const format of params.formats) url.searchParams.append('formats', format); + if (params.jsonBinaryEncoding) { + url.searchParams.set('jsonBinaryEncoding', params.jsonBinaryEncoding); + } + if (params.parsed !== undefined) { + url.searchParams.set('parsed', params.parsed.toString()); + } + url.searchParams.set('channel', params.channel); + + try { + const response = await fetch(url.toString()); + if (!response.ok) { + throw new Error(`HTTP error! status: ${String(response.status)}`); + } + return (await response.json()) as JsonUpdate; + } catch (error) { + throw new Error( + `Failed to fetch latest price: ${error instanceof Error ? error.message : String(error)}`, + ); + } + } + + /** + * Queries the price endpoint to get historical price data at a specific timestamp. + * @param params - Parameters for the price request including timestamp + * @returns Promise resolving to JsonUpdate with price data at the specified time + */ + async get_price(params: PriceRequest): Promise { + const url = new URL(`${this.routerServiceUrl}/v1/price`); + + url.searchParams.set('timestamp', params.timestamp); + if (params.priceFeedIds) { + for (const id of params.priceFeedIds) url.searchParams.append('priceFeedIds', id.toString()); + } + if (params.symbols) { + for (const symbol of params.symbols) url.searchParams.append('symbols', symbol); + } + for (const prop of params.properties) url.searchParams.append('properties', prop); + for (const format of params.formats) url.searchParams.append('formats', format); + if (params.jsonBinaryEncoding) { + url.searchParams.set('jsonBinaryEncoding', params.jsonBinaryEncoding); + } + if (params.parsed !== undefined) { + url.searchParams.set('parsed', params.parsed.toString()); + } + url.searchParams.set('channel', params.channel); + + try { + const response = await fetch(url.toString()); + if (!response.ok) { + throw new Error(`HTTP error! status: ${String(response.status)}`); + } + return (await response.json()) as JsonUpdate; + } catch (error) { + throw new Error( + `Failed to fetch price: ${error instanceof Error ? error.message : String(error)}`, + ); + } + } } diff --git a/lazer/sdk/js/src/protocol.ts b/lazer/sdk/js/src/protocol.ts index 956183e2fc..b11fb52d8f 100644 --- a/lazer/sdk/js/src/protocol.ts +++ b/lazer/sdk/js/src/protocol.ts @@ -128,3 +128,32 @@ export type SymbolResponse = { hermes_id?: string | null; interval?: string | null; }; + +export type LatestPriceRequest = { + priceFeedIds?: number[]; + symbols?: string[]; + properties: PriceFeedProperty[]; + formats: Format[]; + jsonBinaryEncoding?: JsonBinaryEncoding; + parsed?: boolean; + channel: Channel; +}; + +export type PriceRequest = { + timestamp: string; + priceFeedIds?: number[]; + symbols?: string[]; + properties: PriceFeedProperty[]; + formats: Format[]; + jsonBinaryEncoding?: JsonBinaryEncoding; + parsed?: boolean; + channel: Channel; +}; + +export type JsonUpdate = { + parsed?: ParsedPayload; + evm?: JsonBinaryData; + solana?: JsonBinaryData; + leEcdsa?: JsonBinaryData; + leUnsigned?: JsonBinaryData; +}; From f9aa7e345693fb57210fc49731b9417e1f76081e Mon Sep 17 00:00:00 2001 From: Tejas Badadare Date: Mon, 22 Sep 2025 18:53:29 -0700 Subject: [PATCH 04/12] feat(lazer-js-sdk): update names, add examples --- lazer/sdk/js/examples/history.ts | 42 ++++++ lazer/sdk/js/examples/index.ts | 122 ---------------- lazer/sdk/js/examples/router-example.ts | 49 ------- lazer/sdk/js/examples/streaming.ts | 115 +++++++++++++++ lazer/sdk/js/examples/symbols.ts | 24 ++++ lazer/sdk/js/examples/util.ts | 93 +++++++++++++ lazer/sdk/js/package.json | 5 +- lazer/sdk/js/src/client.ts | 162 +++++++++++++--------- lazer/sdk/js/src/constants.ts | 6 +- lazer/sdk/js/src/protocol.ts | 82 +++++------ lazer/sdk/js/src/socket/websocket-pool.ts | 20 ++- 11 files changed, 422 insertions(+), 298 deletions(-) create mode 100644 lazer/sdk/js/examples/history.ts delete mode 100644 lazer/sdk/js/examples/index.ts delete mode 100644 lazer/sdk/js/examples/router-example.ts create mode 100644 lazer/sdk/js/examples/streaming.ts create mode 100644 lazer/sdk/js/examples/symbols.ts create mode 100644 lazer/sdk/js/examples/util.ts diff --git a/lazer/sdk/js/examples/history.ts b/lazer/sdk/js/examples/history.ts new file mode 100644 index 0000000000..40fe8ed83a --- /dev/null +++ b/lazer/sdk/js/examples/history.ts @@ -0,0 +1,42 @@ +import { PythLazerClient } from "../src/index.js"; +import { displayParsedPrices } from "./util.js"; + +const client = await PythLazerClient.create({ token: "your-token-here", logger: console }); + +// Example 1: Get latest price for BTC using feed IDs +console.log("\n=== Example 1: Latest BTC price (requested with feed ID) ==="); +const response1 = await client.get_latest_price({ + priceFeedIds: [1], + properties: ["price", "confidence", "exponent"], + formats: [], + jsonBinaryEncoding: "hex", + parsed: true, + channel: "fixed_rate@200ms", +}); +displayParsedPrices(response1); + +// Example 2: Get latest price using symbols +console.log("\n=== Example 2: Latest ETH price (requested with symbols) ==="); +const response2 = await client.get_latest_price({ + // symbols: ["Crypto.ETH/USD"], + priceFeedIds: [2], + properties: ["price", "confidence", "exponent"], + formats: [], + parsed: true, + channel: "real_time", +}); +displayParsedPrices(response2); + +// Example 3: Get historical price at specific timestamp +console.log("\n=== Example 3: Historical BTC price at timestamp ==="); +const oneMinAgo = 1754348458565000; +console.log(`Requesting price from timestamp: ${oneMinAgo} (${new Date(oneMinAgo / 1000).toISOString()})`); +const response3 = await client.get_price({ + timestamp: oneMinAgo, + priceFeedIds: [1], + properties: ["price", "confidence", "exponent"], + formats: [], + parsed: true, + channel: "real_time", +}); +displayParsedPrices(response3); diff --git a/lazer/sdk/js/examples/index.ts b/lazer/sdk/js/examples/index.ts deleted file mode 100644 index 56e67f039e..0000000000 --- a/lazer/sdk/js/examples/index.ts +++ /dev/null @@ -1,122 +0,0 @@ -/* eslint-disable no-console */ -/* eslint-disable @typescript-eslint/no-empty-function */ - -import { PythLazerClient } from "../src/index.js"; - -// Ignore debug messages -console.debug = () => {}; - -const client = await PythLazerClient.create({ - urls: [ - "wss://pyth-lazer-0.dourolabs.app/v1/stream", - "wss://pyth-lazer-1.dourolabs.app/v1/stream", - ], - token: "you-access-token-here", // Replace with your actual access token - numConnections: 4, // Optionally specify number of parallel redundant connections to reduce the chance of dropped messages. The connections will round-robin across the provided URLs. Default is 4. - logger: console, // Optionally log socket operations (to the console in this case.) - onError: (error) => { - console.error("WebSocket error:", error); - }, - // Optional configuration for resilient WebSocket connections - rwsConfig: { - heartbeatTimeoutDurationMs: 5000, // Optional heartbeat timeout duration in milliseconds - maxRetryDelayMs: 1000, // Optional maximum retry delay in milliseconds - logAfterRetryCount: 10, // Optional log after how many retries - }, -}); - -// Read and process messages from the Lazer stream -client.addMessageListener((message) => { - console.info("got message:", message); - switch (message.type) { - case "json": { - if (message.value.type == "streamUpdated") { - console.info( - "stream updated for subscription", - message.value.subscriptionId, - ":", - message.value.parsed?.priceFeeds, - ); - } - break; - } - case "binary": { - if ("solana" in message.value) { - console.info("solana message:", message.value.solana?.toString("hex")); - } - if ("evm" in message.value) { - console.info("evm message:", message.value.evm?.toString("hex")); - } - break; - } - } -}); - -// Monitor for all connections in the pool being down simultaneously (e.g. if the internet goes down) -// The connections may still try to reconnect in the background. To shut down the client completely, call shutdown(). -client.addAllConnectionsDownListener(() => { - console.error("All connections are down!"); -}); - -console.info("Querying symbols with 'BTC'..."); -const btcSymbols = await client.get_symbols({ - query: "BTC", - asset_type: "crypto", -}); -console.info( - "Found BTC symbols:", - btcSymbols.map((s) => ({ name: s.name, id: s.pyth_lazer_id })), -); - -if (btcSymbols.length > 0) { - const btcSymbol = btcSymbols[0]; - if (btcSymbol) { - const btcFeedId = btcSymbol.pyth_lazer_id; - console.info(`Subscribing to BTC feed ID: ${String(btcFeedId)}`); - - client.subscribe({ - type: "subscribe", - subscriptionId: 3, - priceFeedIds: [btcFeedId], - properties: ["price", "confidence"], - formats: ["solana"], - deliveryFormat: "json", - channel: "fixed_rate@200ms", - parsed: true, - jsonBinaryEncoding: "hex", - }); - } -} - -// Create and remove one or more subscriptions on the fly -client.subscribe({ - type: "subscribe", - subscriptionId: 1, - priceFeedIds: [1, 2], - properties: ["price"], - formats: ["solana"], - deliveryFormat: "binary", - channel: "fixed_rate@200ms", - parsed: false, - jsonBinaryEncoding: "base64", -}); -client.subscribe({ - type: "subscribe", - subscriptionId: 2, - priceFeedIds: [1, 2, 3, 4, 5], - properties: ["price", "exponent", "publisherCount", "confidence"], - formats: ["evm"], - deliveryFormat: "json", - channel: "fixed_rate@200ms", - parsed: true, - jsonBinaryEncoding: "hex", -}); - -await new Promise((resolve) => setTimeout(resolve, 10_000)); - -client.unsubscribe(1); -client.unsubscribe(2); -if (btcSymbols.length > 0 && btcSymbols[0]) { - client.unsubscribe(3); -} -client.shutdown(); diff --git a/lazer/sdk/js/examples/router-example.ts b/lazer/sdk/js/examples/router-example.ts deleted file mode 100644 index a24011db61..0000000000 --- a/lazer/sdk/js/examples/router-example.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { PythLazerClient } from "../src/index.js"; - -const client = await PythLazerClient.create({ - urls: ["wss://router.pyth-lazer.dourolabs.app/ws"], - token: "", - routerServiceUrl: "https://router.pyth-lazer.dourolabs.app", -}); - -// Example 1: Get latest price for BTC using feed IDs -await client.get_latest_price({ - priceFeedIds: [1], - properties: ["price", "confidence", "exponent"], - formats: ["solana"], - jsonBinaryEncoding: "hex", - parsed: true, - channel: "fixed_rate@200ms", -}); - -// Example 2: Get latest price using symbols -await client.get_latest_price({ - symbols: ["BTC/USD"], - properties: ["price", "confidence"], - formats: ["evm"], - parsed: true, - channel: "real_time", -}); - -// Example 3: Get historical price at specific timestamp -const historicalTimestamp = (Date.now() - 60_000) * 1000; -await client.get_price({ - timestamp: historicalTimestamp.toString(), - priceFeedIds: [1], - properties: ["price", "publisherCount"], - formats: ["solana"], - parsed: true, - channel: "fixed_rate@200ms", -}); - -// Example 4: Get multiple feeds with different formats -await client.get_latest_price({ - priceFeedIds: [1, 2, 3], - properties: ["price", "confidence", "exponent", "publisherCount"], - formats: ["evm", "solana"], - jsonBinaryEncoding: "base64", - parsed: true, - channel: "fixed_rate@50ms", -}); - -client.shutdown(); diff --git a/lazer/sdk/js/examples/streaming.ts b/lazer/sdk/js/examples/streaming.ts new file mode 100644 index 0000000000..c3ea213036 --- /dev/null +++ b/lazer/sdk/js/examples/streaming.ts @@ -0,0 +1,115 @@ +/* eslint-disable no-console */ +/* eslint-disable @typescript-eslint/no-empty-function */ + +import { PythLazerClient } from "../src/index.js"; +import { renderFeeds, refreshFeedDisplay } from "./util.js"; + +// Ignore debug messages +console.debug = () => { }; + +// Store feed data for in-place updates +const feedData = new Map(); + +const client = await PythLazerClient.create({ + token: "your-token-here", // Replace with your actual access token + logger: console, // Optionally log socket operations (to the console in this case.) + webSocketPoolConfig: { + urls: [ + "wss://pyth-lazer-0.dourolabs.app/v1/stream", + "wss://pyth-lazer-1.dourolabs.app/v1/stream", + ], + numConnections: 4, // Optionally specify number of parallel redundant connections to reduce the chance of dropped messages. The connections will round-robin across the provided URLs. Default is 4. + onError: (error) => { + console.error("WebSocket error:", error); + }, + // Optional configuration for resilient WebSocket connections + rwsConfig: { + heartbeatTimeoutDurationMs: 5000, // Optional heartbeat timeout duration in milliseconds + maxRetryDelayMs: 1000, // Optional maximum retry delay in milliseconds + logAfterRetryCount: 10, // Optional log after how many retries + }, + }, +}); + +// Read and display messages from the Lazer stream +client.addMessageListener((message) => { + switch (message.type) { + case "json": { + if (message.value.type == "streamUpdated") { + refreshFeedDisplay(message.value, feedData); + } + break; + } + case "binary": { + // Print out the binary hex messages if you want: + // if ("solana" in message.value) { + // console.info("solana message:", message.value.solana?.toString("hex")); + // } + // if ("evm" in message.value) { + // console.info("evm message:", message.value.evm?.toString("hex")); + // } + break; + } + } +}); + +// Monitor for all connections in the pool being down simultaneously (e.g. if the internet goes down) +// The connections may still try to reconnect in the background. To shut down the client completely, call shutdown(). +client.addAllConnectionsDownListener(() => { + console.error("All connections are down!"); +}); + +renderFeeds(feedData); + +// Create and remove one or more subscriptions on the fly +client.subscribe({ + type: "subscribe", + subscriptionId: 1, + priceFeedIds: [1, 2], + properties: ["price"], + formats: ["solana"], + deliveryFormat: "binary", + channel: "fixed_rate@200ms", + parsed: false, + jsonBinaryEncoding: "base64", +}); +client.subscribe({ + type: "subscribe", + subscriptionId: 2, + priceFeedIds: [1, 2, 3, 4, 5], + properties: ["price", "exponent", "publisherCount", "confidence"], + formats: ["evm"], + deliveryFormat: "json", + channel: "fixed_rate@200ms", + parsed: true, + jsonBinaryEncoding: "hex", +}); +client.subscribe({ + type: "subscribe", + subscriptionId: 3, + priceFeedIds: [1], + properties: ["price", "confidence"], + formats: ["solana"], + deliveryFormat: "json", + channel: "fixed_rate@200ms", + parsed: true, + jsonBinaryEncoding: "hex", +}); + +await new Promise((resolve) => setTimeout(resolve, 30_000)); + +client.unsubscribe(1); +client.unsubscribe(2); +client.unsubscribe(3); + +process.stdout.write('\x1b[2J\x1b[H'); +console.log('🛑 Shutting down Pyth Lazer demo after 30 seconds...'); +console.log('👋 Goodbye!'); + +client.shutdown(); diff --git a/lazer/sdk/js/examples/symbols.ts b/lazer/sdk/js/examples/symbols.ts new file mode 100644 index 0000000000..e0c3ca92ec --- /dev/null +++ b/lazer/sdk/js/examples/symbols.ts @@ -0,0 +1,24 @@ +import { PythLazerClient } from "../src/index.js"; + +const client = await PythLazerClient.create({ token: "your-token-here", logger: console }); + +// Example 1: Get latest price for BTC using feed IDs +console.log("\n=== Example 1: Search feeds by name/symbol ==="); +const response1 = await client.get_symbols({ query: "BTC" }); +console.log(response1); + +// Example 2: Get latest price using symbols +console.log("\n=== Example 2: Get feeds by asset type ==="); +const response2 = await client.get_symbols({ + asset_type: "equity", +}); +console.log(response2); + +// Example 3: Get feeds by asset type and query +console.log("\n=== Example 3: Get feeds by asset type and name/symbol ==="); +const response3 = await client.get_symbols({ + asset_type: "equity", + query: "AAPL", +}); + +console.log(response3); diff --git a/lazer/sdk/js/examples/util.ts b/lazer/sdk/js/examples/util.ts new file mode 100644 index 0000000000..9937dd2515 --- /dev/null +++ b/lazer/sdk/js/examples/util.ts @@ -0,0 +1,93 @@ +import type { JsonUpdate, ParsedFeedPayload } from "../src/index.js"; + +// Helper function to render all feeds in place +export function renderFeeds(feedData: Map) { + // Clear screen and move cursor to top + process.stdout.write('\x1b[2J\x1b[H'); + + if (feedData.size === 0) { + console.log('Waiting for price feed data...\n'); + return; + } + + console.log('🔴 Live Lazer Price Feeds\n'); + console.log('━'.repeat(80)); + + // Sort feeds by ID for consistent display order + const sortedFeeds = Array.from(feedData.values()).sort((a, b) => { + const aId = String(a.priceFeedId); + const bId = String(b.priceFeedId); + return aId.localeCompare(bId); + }); + + sortedFeeds.forEach((feed, index) => { + const readablePrice = feed.price * Math.pow(10, feed.exponent); + const readableConfidence = feed.confidence !== null ? feed.confidence * Math.pow(10, feed.exponent) : null; + const timeAgo = Math.round((Date.now() - feed.lastUpdate.getTime())); + + console.log(`\x1b[36m${index + 1}. Feed ID: ${feed.priceFeedId}\x1b[0m`); + console.log(` 💰 Price: \x1b[32m$${readablePrice.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 8 })}\x1b[0m`); + + if (readableConfidence !== null) { + console.log(` 📊 Confidence: \x1b[33m±$${readableConfidence.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 8 })}\x1b[0m`); + } + + console.log(` ⏰ Updated: \x1b[90m${timeAgo}ms ago\x1b[0m`); + console.log(''); + }); + + console.log('━'.repeat(80)); + console.log(`\x1b[90mLast refresh: ${new Date().toLocaleTimeString()}\x1b[0m`); +} + +// Helper function to update price feed data and refresh display +export function refreshFeedDisplay(response: any, feedData: Map) { + if (response.parsed?.priceFeeds) { + response.parsed.priceFeeds.forEach((feed: any, index: number) => { + if (feed.price && feed.exponent !== undefined) { + const feedId = feed.priceFeedId !== undefined ? String(feed.priceFeedId) : `feed_${index + 1}`; + const readableConfidence = feed.confidence ? Number(feed.confidence) : null; + + feedData.set(feedId, { + priceFeedId: feed.priceFeedId !== undefined ? feed.priceFeedId : `feed_${index + 1}`, + price: Number(feed.price), + confidence: readableConfidence, + exponent: feed.exponent, + lastUpdate: new Date() + }); + } + }); + + renderFeeds(feedData); + } +} + +// Helper function to calculate human-friendly price values +export function displayParsedPrices(response: JsonUpdate) { + if (response.parsed?.priceFeeds) { + response.parsed.priceFeeds.forEach((feed: ParsedFeedPayload, index: number) => { + if (feed.price && feed.exponent !== undefined) { + const readablePrice = Number(feed.price) * Math.pow(10, feed.exponent); + const readableConfidence = feed.confidence ? Number(feed.confidence) * Math.pow(10, feed.exponent) : null; + + console.log(`Feed ${feed.priceFeedId || index + 1}:`); + console.log(`\tPrice: $${readablePrice.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 8 })}`); + if (readableConfidence !== null) { + console.log(`\tConfidence: ±$${readableConfidence.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 8 })}`); + } + } + }); + } +} diff --git a/lazer/sdk/js/package.json b/lazer/sdk/js/package.json index a07049144d..478b38e77d 100644 --- a/lazer/sdk/js/package.json +++ b/lazer/sdk/js/package.json @@ -28,8 +28,9 @@ "test:types": "tsc", "test:format": "prettier --check .", "fix:format": "prettier --write .", - "example": "node --loader ts-node/esm examples/index.js", - "router-example": "node --loader ts-node/esm examples/router-example.js", + "example:streaming": "node --loader ts-node/esm examples/streaming.js", + "example:history": "node --loader ts-node/esm examples/history.js", + "example:symbols": "node --loader ts-node/esm examples/symbols.js", "doc": "typedoc --out docs/typedoc src" }, "devDependencies": { diff --git a/lazer/sdk/js/src/client.ts b/lazer/sdk/js/src/client.ts index 8b4d978d9c..2e9f919699 100644 --- a/lazer/sdk/js/src/client.ts +++ b/lazer/sdk/js/src/client.ts @@ -1,6 +1,7 @@ import fetch from "cross-fetch"; import WebSocket from "isomorphic-ws"; - +import type { Logger } from "ts-log"; +import { dummyLogger } from "ts-log"; import type { ParsedPayload, Request, @@ -14,7 +15,7 @@ import type { import { BINARY_UPDATE_FORMAT_MAGIC_LE, FORMAT_MAGICS_LE } from "./protocol.js"; import type { WebSocketPoolConfig } from "./socket/websocket-pool.js"; import { WebSocketPool } from "./socket/websocket-pool.js"; -import { DEFAULT_HISTORY_SERVICE_URL, DEFAULT_ROUTER_SERVICE_URL, DEFAULT_STREAM_SERVICE_0_URL, DEFAULT_STREAM_SERVICE_1_URL } from "./constants.js"; +import { DEFAULT_METADATA_SERVICE_URL, DEFAULT_PRICE_SERVICE_URL } from "./constants.js"; export type BinaryResponse = { subscriptionId: number; @@ -36,39 +37,55 @@ const UINT16_NUM_BYTES = 2; const UINT32_NUM_BYTES = 4; const UINT64_NUM_BYTES = 8; -export type LazerClientConfig = WebSocketPoolConfig & { - historyServiceUrl?: string; - routerServiceUrl?: string; - streamServiceUrls?: string[]; +export type LazerClientConfig = { + token: string; + metadataServiceUrl?: string; + priceServiceUrl?: string; + logger?: Logger; + webSocketPoolConfig?: WebSocketPoolConfig; }; export class PythLazerClient { private constructor( - private readonly wsp: WebSocketPool, - private readonly historyServiceUrl: string, - private readonly routerServiceUrl: string, + private readonly token: string, + private readonly metadataServiceUrl: string, + private readonly priceServiceUrl: string, + private readonly logger: Logger, + private readonly wsp?: WebSocketPool, ) { } + /** + * Validates that the WebSocket pool is available for streaming operations. + * @throws Error if WebSocket pool is not configured + */ + private validateWebSocketPool(): void { + if (!this.wsp) { + throw new Error("WebSocket pool is not available. Make sure to provide webSocketPoolConfig when creating the client."); + } + } + /** * Creates a new PythLazerClient instance. - * @param config - Configuration including WebSocket URLs, token, history service URL, and router service URL + * @param config - Configuration including WebSocket URLs, token, metadata service URL, and price service URL */ static async create(config: LazerClientConfig): Promise { - const historyServiceUrl = - config.historyServiceUrl ?? - DEFAULT_HISTORY_SERVICE_URL; - const routerServiceUrl = - config.routerServiceUrl ?? - DEFAULT_ROUTER_SERVICE_URL; - const streamServiceUrls = - config.streamServiceUrls ?? - [DEFAULT_STREAM_SERVICE_0_URL, DEFAULT_STREAM_SERVICE_1_URL]; + const token = config.token; - const wsp = await WebSocketPool.create({ - ...config, - urls: streamServiceUrls, - }); - return new PythLazerClient(wsp, historyServiceUrl, routerServiceUrl); + // Collect and remove trailing slash from URLs + const metadataServiceUrl = + (config.metadataServiceUrl ?? + DEFAULT_METADATA_SERVICE_URL).replace(/\/+$/, ''); + const priceServiceUrl = + (config.priceServiceUrl ?? + DEFAULT_PRICE_SERVICE_URL).replace(/\/+$/, ''); + const logger = config.logger ?? dummyLogger; + + // If webSocketPoolConfig is provided, create a WebSocket pool and block until at least one connection is established. + let wsp: WebSocketPool | undefined; + if (config.webSocketPoolConfig) { + wsp = await WebSocketPool.create(config.webSocketPoolConfig, token, logger); + } + return new PythLazerClient(token, metadataServiceUrl, priceServiceUrl, logger, wsp); } /** @@ -78,7 +95,8 @@ export class PythLazerClient { * or a binary response containing EVM, Solana, or parsed payload data. */ addMessageListener(handler: (event: JsonOrBinaryResponse) => void) { - this.wsp.addMessageListener((data: WebSocket.Data) => { + this.validateWebSocketPool(); + this.wsp!.addMessageListener((data: WebSocket.Data) => { if (typeof data == "string") { handler({ type: "json", @@ -129,18 +147,21 @@ export class PythLazerClient { } subscribe(request: Request) { + this.validateWebSocketPool(); if (request.type !== "subscribe") { throw new Error("Request must be a subscribe request"); } - this.wsp.addSubscription(request); + this.wsp!.addSubscription(request); } unsubscribe(subscriptionId: number) { - this.wsp.removeSubscription(subscriptionId); + this.validateWebSocketPool(); + this.wsp!.removeSubscription(subscriptionId); } send(request: Request) { - this.wsp.sendRequest(request); + this.validateWebSocketPool(); + this.wsp!.sendRequest(request); } /** @@ -149,11 +170,31 @@ export class PythLazerClient { * @param handler - Function to be called when all connections are down */ addAllConnectionsDownListener(handler: () => void): void { - this.wsp.addAllConnectionsDownListener(handler); + this.validateWebSocketPool(); + this.wsp!.addAllConnectionsDownListener(handler); } shutdown(): void { - this.wsp.shutdown(); + this.validateWebSocketPool(); + this.wsp!.shutdown(); + } + + /** + * Private helper method to make authenticated HTTP requests with Bearer token + * @param url - The URL to fetch + * @param options - Additional fetch options + * @returns Promise resolving to the fetch Response + */ + private async authenticatedFetch(url: string, options: RequestInit = {}): Promise { + const headers = { + 'Authorization': `Bearer ${this.token}`, + ...options.headers, + }; + + return fetch(url, { + ...options, + headers, + }); } /** @@ -162,7 +203,7 @@ export class PythLazerClient { * @returns Promise resolving to array of symbol information */ async get_symbols(params?: SymbolsQueryParams): Promise { - const url = new URL(`${this.historyServiceUrl}/v1/symbols`); + const url = new URL(`${this.metadataServiceUrl}/v1/symbols`); if (params?.query) { url.searchParams.set("query", params.query); @@ -172,7 +213,7 @@ export class PythLazerClient { } try { - const response = await fetch(url.toString()); + const response = await this.authenticatedFetch(url.toString()); if (!response.ok) { throw new Error(`HTTP error! status: ${String(response.status)} - ${await response.text()}`); } @@ -190,26 +231,18 @@ export class PythLazerClient { * @returns Promise resolving to JsonUpdate with current price data */ async get_latest_price(params: LatestPriceRequest): Promise { - const url = new URL(`${this.routerServiceUrl}/v1/latest_price`); - - if (params.priceFeedIds) { - for (const id of params.priceFeedIds) url.searchParams.append('priceFeedIds', id.toString()); - } - if (params.symbols) { - for (const symbol of params.symbols) url.searchParams.append('symbols', symbol); - } - for (const prop of params.properties) url.searchParams.append('properties', prop); - for (const format of params.formats) url.searchParams.append('formats', format); - if (params.jsonBinaryEncoding) { - url.searchParams.set('jsonBinaryEncoding', params.jsonBinaryEncoding); - } - if (params.parsed !== undefined) { - url.searchParams.set('parsed', params.parsed.toString()); - } - url.searchParams.set('channel', params.channel); + const url = `${this.priceServiceUrl}/v1/latest_price`; try { - const response = await fetch(url.toString()); + const body = JSON.stringify(params); + this.logger.debug("get_latest_price", { url, body }); + const response = await this.authenticatedFetch(url, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: body, + }); if (!response.ok) { throw new Error(`HTTP error! status: ${String(response.status)} - ${await response.text()}`); } @@ -227,27 +260,18 @@ export class PythLazerClient { * @returns Promise resolving to JsonUpdate with price data at the specified time */ async get_price(params: PriceRequest): Promise { - const url = new URL(`${this.routerServiceUrl}/v1/price`); - - url.searchParams.set('timestamp', params.timestamp); - if (params.priceFeedIds) { - for (const id of params.priceFeedIds) url.searchParams.append('priceFeedIds', id.toString()); - } - if (params.symbols) { - for (const symbol of params.symbols) url.searchParams.append('symbols', symbol); - } - for (const prop of params.properties) url.searchParams.append('properties', prop); - for (const format of params.formats) url.searchParams.append('formats', format); - if (params.jsonBinaryEncoding) { - url.searchParams.set('jsonBinaryEncoding', params.jsonBinaryEncoding); - } - if (params.parsed !== undefined) { - url.searchParams.set('parsed', params.parsed.toString()); - } - url.searchParams.set('channel', params.channel); + const url = `${this.priceServiceUrl}/v1/price`; try { - const response = await fetch(url.toString()); + const body = JSON.stringify(params); + this.logger.debug("get_price", { url, body }); + const response = await this.authenticatedFetch(url, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: body, + }); if (!response.ok) { throw new Error(`HTTP error! status: ${String(response.status)} - ${await response.text()}`); } diff --git a/lazer/sdk/js/src/constants.ts b/lazer/sdk/js/src/constants.ts index 61f1d2e1a9..1ef95cb9f0 100644 --- a/lazer/sdk/js/src/constants.ts +++ b/lazer/sdk/js/src/constants.ts @@ -2,10 +2,10 @@ export const SOLANA_LAZER_PROGRAM_ID = "pytd2yyk641x7ak7mkaasSJVXh6YYZnC7wTmtgAyxPt"; export const SOLANA_LAZER_STORAGE_ID = "3rdJbqfnagQ4yx9HXJViD4zc4xpiSqmFsKpPuSCQVyQL"; -export const DEFAULT_HISTORY_SERVICE_URL = +export const DEFAULT_METADATA_SERVICE_URL = "https://history.pyth-lazer.dourolabs.app/history"; -export const DEFAULT_ROUTER_SERVICE_URL = - "https://router.pyth-lazer.dourolabs.app"; +export const DEFAULT_PRICE_SERVICE_URL = + "https://pyth-lazer-0.dourolabs.app"; export const DEFAULT_STREAM_SERVICE_0_URL = "wss://pyth-lazer-0.dourolabs.app/v1/stream"; export const DEFAULT_STREAM_SERVICE_1_URL = diff --git a/lazer/sdk/js/src/protocol.ts b/lazer/sdk/js/src/protocol.ts index b11fb52d8f..482cbe775a 100644 --- a/lazer/sdk/js/src/protocol.ts +++ b/lazer/sdk/js/src/protocol.ts @@ -12,21 +12,21 @@ export type Channel = "real_time" | "fixed_rate@50ms" | "fixed_rate@200ms"; export type Request = | { - type: "subscribe"; - subscriptionId: number; - priceFeedIds: number[]; - properties: PriceFeedProperty[]; - formats: Format[]; - deliveryFormat?: DeliveryFormat; - jsonBinaryEncoding?: JsonBinaryEncoding; - parsed?: boolean; - ignoreInvalidFeedIds?: boolean; - channel: Channel; - } + type: "subscribe"; + subscriptionId: number; + priceFeedIds: number[]; + properties: PriceFeedProperty[]; + formats: Format[]; + deliveryFormat?: DeliveryFormat; + jsonBinaryEncoding?: JsonBinaryEncoding; + parsed?: boolean; + ignoreInvalidFeedIds?: boolean; + channel: Channel; + } | { - type: "unsubscribe"; - subscriptionId: number; - }; + type: "unsubscribe"; + subscriptionId: number; + }; export type ParsedFeedPayload = { priceFeedId: number; @@ -56,37 +56,37 @@ export type InvalidFeedSubscriptionDetails = { export type Response = | { - type: "error"; - error: string; - } + type: "error"; + error: string; + } | { - type: "subscribed"; - subscriptionId: number; - } + type: "subscribed"; + subscriptionId: number; + } | { - type: "subscribedWithInvalidFeedIdsIgnored"; - subscriptionId: number; - subscribedFeedIds: number[]; - ignoredInvalidFeedIds: InvalidFeedSubscriptionDetails; - } + type: "subscribedWithInvalidFeedIdsIgnored"; + subscriptionId: number; + subscribedFeedIds: number[]; + ignoredInvalidFeedIds: InvalidFeedSubscriptionDetails; + } | { - type: "unsubscribed"; - subscriptionId: number; - } + type: "unsubscribed"; + subscriptionId: number; + } | { - type: "subscriptionError"; - subscriptionId: number; - error: string; - } + type: "subscriptionError"; + subscriptionId: number; + error: string; + } | { - type: "streamUpdated"; - subscriptionId: number; - parsed?: ParsedPayload | undefined; - evm?: JsonBinaryData | undefined; - solana?: JsonBinaryData | undefined; - leEcdsa?: JsonBinaryData | undefined; - leUnsigned?: JsonBinaryData | undefined; - }; + type: "streamUpdated"; + subscriptionId: number; + parsed?: ParsedPayload | undefined; + evm?: JsonBinaryData | undefined; + solana?: JsonBinaryData | undefined; + leEcdsa?: JsonBinaryData | undefined; + leUnsigned?: JsonBinaryData | undefined; + }; export const BINARY_UPDATE_FORMAT_MAGIC_LE = 461_928_307; @@ -140,7 +140,7 @@ export type LatestPriceRequest = { }; export type PriceRequest = { - timestamp: string; + timestamp: number; priceFeedIds?: number[]; symbols?: string[]; properties: PriceFeedProperty[]; diff --git a/lazer/sdk/js/src/socket/websocket-pool.ts b/lazer/sdk/js/src/socket/websocket-pool.ts index 6e57811c0c..e281c4b05f 100644 --- a/lazer/sdk/js/src/socket/websocket-pool.ts +++ b/lazer/sdk/js/src/socket/websocket-pool.ts @@ -7,14 +7,13 @@ import { dummyLogger } from "ts-log"; import type { Request, Response } from "../protocol.js"; import type { ResilientWebSocketConfig } from "./resilient-websocket.js"; import { ResilientWebSocket } from "./resilient-websocket.js"; +import { DEFAULT_STREAM_SERVICE_0_URL, DEFAULT_STREAM_SERVICE_1_URL } from "../constants.js"; const DEFAULT_NUM_CONNECTIONS = 4; export type WebSocketPoolConfig = { urls: string[]; - token: string; numConnections?: number; - logger?: Logger; rwsConfig?: Omit; onError?: (error: ErrorEvent) => void; }; @@ -49,31 +48,28 @@ export class WebSocketPool { * @param numConnections - Number of parallel WebSocket connections to maintain (default: 3) * @param logger - Optional logger to get socket level logs. Compatible with most loggers such as the built-in console and `bunyan`. */ - static async create(config: WebSocketPoolConfig): Promise { - if (config.urls.length === 0) { - throw new Error("No URLs provided"); - } - - const logger = config.logger ?? dummyLogger; - const pool = new WebSocketPool(logger); + static async create(config: WebSocketPoolConfig, token: string, logger?: Logger | undefined): Promise { + const urls = config.urls ?? [DEFAULT_STREAM_SERVICE_0_URL, DEFAULT_STREAM_SERVICE_1_URL]; + const log = logger ?? dummyLogger; + const pool = new WebSocketPool(log); const numConnections = config.numConnections ?? DEFAULT_NUM_CONNECTIONS; for (let i = 0; i < numConnections; i++) { - const url = config.urls[i % config.urls.length]; + const url = urls[i % urls.length]; if (!url) { throw new Error(`URLs must not be null or empty`); } const wsOptions = { ...config.rwsConfig?.wsOptions, headers: { - Authorization: `Bearer ${config.token}`, + Authorization: `Bearer ${token}`, }, }; const rws = new ResilientWebSocket({ ...config.rwsConfig, endpoint: url, wsOptions, - logger, + logger: log, }); // If a websocket client unexpectedly disconnects, ResilientWebSocket will reestablish From 8bba7908a22e617c356d87fb3d957cd419271fbc Mon Sep 17 00:00:00 2001 From: Tejas Badadare Date: Mon, 22 Sep 2025 18:54:54 -0700 Subject: [PATCH 05/12] make wsp.urls optional (use default) --- lazer/sdk/js/src/socket/websocket-pool.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lazer/sdk/js/src/socket/websocket-pool.ts b/lazer/sdk/js/src/socket/websocket-pool.ts index e281c4b05f..52a4823ae5 100644 --- a/lazer/sdk/js/src/socket/websocket-pool.ts +++ b/lazer/sdk/js/src/socket/websocket-pool.ts @@ -12,7 +12,7 @@ import { DEFAULT_STREAM_SERVICE_0_URL, DEFAULT_STREAM_SERVICE_1_URL } from "../c const DEFAULT_NUM_CONNECTIONS = 4; export type WebSocketPoolConfig = { - urls: string[]; + urls?: string[]; numConnections?: number; rwsConfig?: Omit; onError?: (error: ErrorEvent) => void; From dc3c953393138f7c302f2b3d395b76044400de2c Mon Sep 17 00:00:00 2001 From: Tejas Badadare Date: Mon, 22 Sep 2025 18:56:59 -0700 Subject: [PATCH 06/12] make wsp.urls optional (use default) --- lazer/sdk/js/examples/streaming.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/lazer/sdk/js/examples/streaming.ts b/lazer/sdk/js/examples/streaming.ts index c3ea213036..a8af211024 100644 --- a/lazer/sdk/js/examples/streaming.ts +++ b/lazer/sdk/js/examples/streaming.ts @@ -18,12 +18,8 @@ const feedData = new Map { console.error("WebSocket error:", error); From 859e363dc83aec772d1170e9887b8c8e256067fd Mon Sep 17 00:00:00 2001 From: Tejas Badadare Date: Mon, 22 Sep 2025 19:40:55 -0700 Subject: [PATCH 07/12] format --- lazer/sdk/js/examples/history.ts | 9 ++++----- lazer/sdk/js/examples/streaming.ts | 4 ++-- lazer/sdk/js/examples/util.ts | 24 +++++++++++------------ lazer/sdk/js/src/client.ts | 5 +++-- lazer/sdk/js/src/socket/websocket-pool.ts | 2 +- 5 files changed, 22 insertions(+), 22 deletions(-) diff --git a/lazer/sdk/js/examples/history.ts b/lazer/sdk/js/examples/history.ts index 40fe8ed83a..d686a29d87 100644 --- a/lazer/sdk/js/examples/history.ts +++ b/lazer/sdk/js/examples/history.ts @@ -1,5 +1,5 @@ -import { PythLazerClient } from "../src/index.js"; import { displayParsedPrices } from "./util.js"; +import { PythLazerClient } from "../src/index.js"; const client = await PythLazerClient.create({ token: "your-token-here", logger: console }); @@ -18,7 +18,6 @@ displayParsedPrices(response1); // Example 2: Get latest price using symbols console.log("\n=== Example 2: Latest ETH price (requested with symbols) ==="); const response2 = await client.get_latest_price({ - // symbols: ["Crypto.ETH/USD"], priceFeedIds: [2], properties: ["price", "confidence", "exponent"], formats: [], @@ -29,10 +28,10 @@ displayParsedPrices(response2); // Example 3: Get historical price at specific timestamp console.log("\n=== Example 3: Historical BTC price at timestamp ==="); -const oneMinAgo = 1754348458565000; -console.log(`Requesting price from timestamp: ${oneMinAgo} (${new Date(oneMinAgo / 1000).toISOString()})`); +const timestamp = 1_754_348_458_565_000; +console.log(`Requesting price from timestamp: ${timestamp} (${new Date(timestamp / 1000).toISOString()})`); const response3 = await client.get_price({ - timestamp: oneMinAgo, + timestamp: timestamp, priceFeedIds: [1], properties: ["price", "confidence", "exponent"], formats: [], diff --git a/lazer/sdk/js/examples/streaming.ts b/lazer/sdk/js/examples/streaming.ts index a8af211024..d4640a67ca 100644 --- a/lazer/sdk/js/examples/streaming.ts +++ b/lazer/sdk/js/examples/streaming.ts @@ -1,8 +1,8 @@ /* eslint-disable no-console */ /* eslint-disable @typescript-eslint/no-empty-function */ -import { PythLazerClient } from "../src/index.js"; import { renderFeeds, refreshFeedDisplay } from "./util.js"; +import { PythLazerClient } from "../src/index.js"; // Ignore debug messages console.debug = () => { }; @@ -104,7 +104,7 @@ client.unsubscribe(1); client.unsubscribe(2); client.unsubscribe(3); -process.stdout.write('\x1b[2J\x1b[H'); +process.stdout.write('\u001B[2J\u001B[H'); console.log('🛑 Shutting down Pyth Lazer demo after 30 seconds...'); console.log('👋 Goodbye!'); diff --git a/lazer/sdk/js/examples/util.ts b/lazer/sdk/js/examples/util.ts index 9937dd2515..381396f945 100644 --- a/lazer/sdk/js/examples/util.ts +++ b/lazer/sdk/js/examples/util.ts @@ -9,7 +9,7 @@ export function renderFeeds(feedData: Map) { // Clear screen and move cursor to top - process.stdout.write('\x1b[2J\x1b[H'); + process.stdout.write('\u001B[2J\u001B[H'); if (feedData.size === 0) { console.log('Waiting for price feed data...\n'); @@ -20,30 +20,30 @@ export function renderFeeds(feedData: Map { + const sortedFeeds = [...feedData.values()].sort((a, b) => { const aId = String(a.priceFeedId); const bId = String(b.priceFeedId); return aId.localeCompare(bId); }); - sortedFeeds.forEach((feed, index) => { + for (const [index, feed] of sortedFeeds.entries()) { const readablePrice = feed.price * Math.pow(10, feed.exponent); - const readableConfidence = feed.confidence !== null ? feed.confidence * Math.pow(10, feed.exponent) : null; + const readableConfidence = feed.confidence === null ? null : feed.confidence * Math.pow(10, feed.exponent); const timeAgo = Math.round((Date.now() - feed.lastUpdate.getTime())); - console.log(`\x1b[36m${index + 1}. Feed ID: ${feed.priceFeedId}\x1b[0m`); - console.log(` 💰 Price: \x1b[32m$${readablePrice.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 8 })}\x1b[0m`); + console.log(`\u001B[36m${index + 1}. Feed ID: ${feed.priceFeedId}\u001B[0m`); + console.log(` 💰 Price: \u001B[32m$${readablePrice.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 8 })}\u001B[0m`); if (readableConfidence !== null) { - console.log(` 📊 Confidence: \x1b[33m±$${readableConfidence.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 8 })}\x1b[0m`); + console.log(` 📊 Confidence: \u001B[33m±$${readableConfidence.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 8 })}\u001B[0m`); } - console.log(` ⏰ Updated: \x1b[90m${timeAgo}ms ago\x1b[0m`); + console.log(` ⏰ Updated: \u001B[90m${timeAgo}ms ago\u001B[0m`); console.log(''); - }); + } console.log('━'.repeat(80)); - console.log(`\x1b[90mLast refresh: ${new Date().toLocaleTimeString()}\x1b[0m`); + console.log(`\u001B[90mLast refresh: ${new Date().toLocaleTimeString()}\u001B[0m`); } // Helper function to update price feed data and refresh display @@ -57,11 +57,11 @@ export function refreshFeedDisplay(response: any, feedData: Map { if (feed.price && feed.exponent !== undefined) { - const feedId = feed.priceFeedId !== undefined ? String(feed.priceFeedId) : `feed_${index + 1}`; + const feedId = feed.priceFeedId === undefined ? `feed_${index + 1}` : String(feed.priceFeedId); const readableConfidence = feed.confidence ? Number(feed.confidence) : null; feedData.set(feedId, { - priceFeedId: feed.priceFeedId !== undefined ? feed.priceFeedId : `feed_${index + 1}`, + priceFeedId: feed.priceFeedId === undefined ? `feed_${index + 1}` : feed.priceFeedId, price: Number(feed.price), confidence: readableConfidence, exponent: feed.exponent, diff --git a/lazer/sdk/js/src/client.ts b/lazer/sdk/js/src/client.ts index 2e9f919699..0cd3a40341 100644 --- a/lazer/sdk/js/src/client.ts +++ b/lazer/sdk/js/src/client.ts @@ -2,6 +2,8 @@ import fetch from "cross-fetch"; import WebSocket from "isomorphic-ws"; import type { Logger } from "ts-log"; import { dummyLogger } from "ts-log"; + +import { DEFAULT_METADATA_SERVICE_URL, DEFAULT_PRICE_SERVICE_URL } from "./constants.js"; import type { ParsedPayload, Request, @@ -15,7 +17,6 @@ import type { import { BINARY_UPDATE_FORMAT_MAGIC_LE, FORMAT_MAGICS_LE } from "./protocol.js"; import type { WebSocketPoolConfig } from "./socket/websocket-pool.js"; import { WebSocketPool } from "./socket/websocket-pool.js"; -import { DEFAULT_METADATA_SERVICE_URL, DEFAULT_PRICE_SERVICE_URL } from "./constants.js"; export type BinaryResponse = { subscriptionId: number; @@ -52,7 +53,7 @@ export class PythLazerClient { private readonly priceServiceUrl: string, private readonly logger: Logger, private readonly wsp?: WebSocketPool, - ) { } + ) {} /** * Validates that the WebSocket pool is available for streaming operations. diff --git a/lazer/sdk/js/src/socket/websocket-pool.ts b/lazer/sdk/js/src/socket/websocket-pool.ts index 52a4823ae5..29f1d805d1 100644 --- a/lazer/sdk/js/src/socket/websocket-pool.ts +++ b/lazer/sdk/js/src/socket/websocket-pool.ts @@ -48,7 +48,7 @@ export class WebSocketPool { * @param numConnections - Number of parallel WebSocket connections to maintain (default: 3) * @param logger - Optional logger to get socket level logs. Compatible with most loggers such as the built-in console and `bunyan`. */ - static async create(config: WebSocketPoolConfig, token: string, logger?: Logger | undefined): Promise { + static async create(config: WebSocketPoolConfig, token: string, logger?: Logger ): Promise { const urls = config.urls ?? [DEFAULT_STREAM_SERVICE_0_URL, DEFAULT_STREAM_SERVICE_1_URL]; const log = logger ?? dummyLogger; const pool = new WebSocketPool(log); From bf0e14125919df07585983e7ef2679fb4dcb1ea6 Mon Sep 17 00:00:00 2001 From: Tejas Badadare Date: Mon, 22 Sep 2025 20:52:02 -0700 Subject: [PATCH 08/12] lint, format --- lazer/sdk/js/examples/history.ts | 11 +- lazer/sdk/js/examples/streaming.ts | 28 ++-- lazer/sdk/js/examples/symbols.ts | 7 +- lazer/sdk/js/examples/util.ts | 172 +++++++++++++--------- lazer/sdk/js/src/client.ts | 103 ++++++++----- lazer/sdk/js/src/constants.ts | 3 +- lazer/sdk/js/src/protocol.ts | 80 +++++----- lazer/sdk/js/src/socket/websocket-pool.ts | 16 +- 8 files changed, 252 insertions(+), 168 deletions(-) diff --git a/lazer/sdk/js/examples/history.ts b/lazer/sdk/js/examples/history.ts index d686a29d87..7798618aff 100644 --- a/lazer/sdk/js/examples/history.ts +++ b/lazer/sdk/js/examples/history.ts @@ -1,7 +1,12 @@ +/* eslint-disable no-console */ + import { displayParsedPrices } from "./util.js"; import { PythLazerClient } from "../src/index.js"; -const client = await PythLazerClient.create({ token: "your-token-here", logger: console }); +const client = await PythLazerClient.create({ + token: "your-token-here", + logger: console, +}); // Example 1: Get latest price for BTC using feed IDs console.log("\n=== Example 1: Latest BTC price (requested with feed ID) ==="); @@ -29,7 +34,9 @@ displayParsedPrices(response2); // Example 3: Get historical price at specific timestamp console.log("\n=== Example 3: Historical BTC price at timestamp ==="); const timestamp = 1_754_348_458_565_000; -console.log(`Requesting price from timestamp: ${timestamp} (${new Date(timestamp / 1000).toISOString()})`); +console.log( + `Requesting price from timestamp: ${timestamp.toString()} (${new Date(timestamp / 1000).toISOString()})`, +); const response3 = await client.get_price({ timestamp: timestamp, priceFeedIds: [1], diff --git a/lazer/sdk/js/examples/streaming.ts b/lazer/sdk/js/examples/streaming.ts index d4640a67ca..9a7af3e9f2 100644 --- a/lazer/sdk/js/examples/streaming.ts +++ b/lazer/sdk/js/examples/streaming.ts @@ -2,19 +2,23 @@ /* eslint-disable @typescript-eslint/no-empty-function */ import { renderFeeds, refreshFeedDisplay } from "./util.js"; +import type { JsonUpdate } from "../src/index.js"; import { PythLazerClient } from "../src/index.js"; // Ignore debug messages -console.debug = () => { }; +console.debug = () => {}; // Store feed data for in-place updates -const feedData = new Map(); +const feedData = new Map< + string, + { + priceFeedId: string | number; + price: number; + confidence: number | undefined; + exponent: number; + lastUpdate: Date; + } +>(); const client = await PythLazerClient.create({ token: "your-token-here", // Replace with your actual access token @@ -38,7 +42,7 @@ client.addMessageListener((message) => { switch (message.type) { case "json": { if (message.value.type == "streamUpdated") { - refreshFeedDisplay(message.value, feedData); + refreshFeedDisplay(message.value as JsonUpdate, feedData); } break; } @@ -104,8 +108,8 @@ client.unsubscribe(1); client.unsubscribe(2); client.unsubscribe(3); -process.stdout.write('\u001B[2J\u001B[H'); -console.log('🛑 Shutting down Pyth Lazer demo after 30 seconds...'); -console.log('👋 Goodbye!'); +process.stdout.write("\u001B[2J\u001B[H"); +console.log("🛑 Shutting down Pyth Lazer demo after 30 seconds..."); +console.log("👋 Goodbye!"); client.shutdown(); diff --git a/lazer/sdk/js/examples/symbols.ts b/lazer/sdk/js/examples/symbols.ts index e0c3ca92ec..afe9e8ef88 100644 --- a/lazer/sdk/js/examples/symbols.ts +++ b/lazer/sdk/js/examples/symbols.ts @@ -1,6 +1,11 @@ +/* eslint-disable no-console */ + import { PythLazerClient } from "../src/index.js"; -const client = await PythLazerClient.create({ token: "your-token-here", logger: console }); +const client = await PythLazerClient.create({ + token: "your-token-here", + logger: console, +}); // Example 1: Get latest price for BTC using feed IDs console.log("\n=== Example 1: Search feeds by name/symbol ==="); diff --git a/lazer/sdk/js/examples/util.ts b/lazer/sdk/js/examples/util.ts index 381396f945..10924e98f1 100644 --- a/lazer/sdk/js/examples/util.ts +++ b/lazer/sdk/js/examples/util.ts @@ -1,93 +1,127 @@ -import type { JsonUpdate, ParsedFeedPayload } from "../src/index.js"; +/* eslint-disable no-console */ -// Helper function to render all feeds in place -export function renderFeeds(feedData: Map) { - // Clear screen and move cursor to top - process.stdout.write('\u001B[2J\u001B[H'); +import type { JsonUpdate } from "../src/index.js"; - if (feedData.size === 0) { - console.log('Waiting for price feed data...\n'); - return; +// Helper function to render all feeds in place +export function renderFeeds( + feedData: Map< + string, + { + priceFeedId: string | number; + price: number; + confidence: number | undefined; + exponent: number; + lastUpdate: Date; } + >, +) { + // Clear screen and move cursor to top + process.stdout.write("\u001B[2J\u001B[H"); - console.log('🔴 Live Lazer Price Feeds\n'); - console.log('━'.repeat(80)); + if (feedData.size === 0) { + console.log("Waiting for price feed data...\n"); + return; + } - // Sort feeds by ID for consistent display order - const sortedFeeds = [...feedData.values()].sort((a, b) => { - const aId = String(a.priceFeedId); - const bId = String(b.priceFeedId); - return aId.localeCompare(bId); - }); + console.log("🔴 Live Lazer Price Feeds\n"); + console.log("━".repeat(80)); - for (const [index, feed] of sortedFeeds.entries()) { - const readablePrice = feed.price * Math.pow(10, feed.exponent); - const readableConfidence = feed.confidence === null ? null : feed.confidence * Math.pow(10, feed.exponent); - const timeAgo = Math.round((Date.now() - feed.lastUpdate.getTime())); + // Sort feeds by ID for consistent display order + const sortedFeeds = [...feedData.values()].sort((a, b) => { + const aId = String(a.priceFeedId); + const bId = String(b.priceFeedId); + return aId.localeCompare(bId); + }); - console.log(`\u001B[36m${index + 1}. Feed ID: ${feed.priceFeedId}\u001B[0m`); - console.log(` 💰 Price: \u001B[32m$${readablePrice.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 8 })}\u001B[0m`); + for (const [index, feed] of sortedFeeds.entries()) { + const readablePrice = feed.price * Math.pow(10, feed.exponent); + const readableConfidence = + feed.confidence === undefined + ? undefined + : feed.confidence * Math.pow(10, feed.exponent); + const timeAgo = Math.round(Date.now() - feed.lastUpdate.getTime()); - if (readableConfidence !== null) { - console.log(` 📊 Confidence: \u001B[33m±$${readableConfidence.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 8 })}\u001B[0m`); - } + console.log( + `\u001B[36m${(index + 1).toString()}. Feed ID: ${feed.priceFeedId.toString()}\u001B[0m`, + ); + console.log( + ` 💰 Price: \u001B[32m$${readablePrice.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 8 })}\u001B[0m`, + ); - console.log(` ⏰ Updated: \u001B[90m${timeAgo}ms ago\u001B[0m`); - console.log(''); + if (readableConfidence !== undefined) { + console.log( + ` 📊 Confidence: \u001B[33m±$${readableConfidence.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 8 })}\u001B[0m`, + ); } - console.log('━'.repeat(80)); - console.log(`\u001B[90mLast refresh: ${new Date().toLocaleTimeString()}\u001B[0m`); + console.log( + ` ⏰ Updated: \u001B[90m${timeAgo.toString()}ms ago\u001B[0m`, + ); + console.log(""); + } + + console.log("━".repeat(80)); + console.log( + `\u001B[90mLast refresh: ${new Date().toLocaleTimeString()}\u001B[0m`, + ); } // Helper function to update price feed data and refresh display -export function refreshFeedDisplay(response: any, feedData: Map) { - if (response.parsed?.priceFeeds) { - response.parsed.priceFeeds.forEach((feed: any, index: number) => { - if (feed.price && feed.exponent !== undefined) { - const feedId = feed.priceFeedId === undefined ? `feed_${index + 1}` : String(feed.priceFeedId); - const readableConfidence = feed.confidence ? Number(feed.confidence) : null; +export function refreshFeedDisplay( + response: JsonUpdate, + feedData: Map< + string, + { + priceFeedId: string | number; + price: number; + confidence: number | undefined; + exponent: number; + lastUpdate: Date; + } + >, +) { + if (response.parsed?.priceFeeds) { + for (const [index, feed] of response.parsed.priceFeeds.entries()) { + if (feed.price && feed.exponent !== undefined) { + const feedId = `feed_${(index + 1).toString()}`; + const readableConfidence = feed.confidence + ? Number(feed.confidence) + : undefined; - feedData.set(feedId, { - priceFeedId: feed.priceFeedId === undefined ? `feed_${index + 1}` : feed.priceFeedId, - price: Number(feed.price), - confidence: readableConfidence, - exponent: feed.exponent, - lastUpdate: new Date() - }); - } + feedData.set(feedId, { + priceFeedId: `feed_${(index + 1).toString()}`, + price: Number(feed.price), + confidence: readableConfidence, + exponent: feed.exponent, + lastUpdate: new Date(), }); - - renderFeeds(feedData); + } } + + renderFeeds(feedData); + } } // Helper function to calculate human-friendly price values export function displayParsedPrices(response: JsonUpdate) { - if (response.parsed?.priceFeeds) { - response.parsed.priceFeeds.forEach((feed: ParsedFeedPayload, index: number) => { - if (feed.price && feed.exponent !== undefined) { - const readablePrice = Number(feed.price) * Math.pow(10, feed.exponent); - const readableConfidence = feed.confidence ? Number(feed.confidence) * Math.pow(10, feed.exponent) : null; + if (response.parsed?.priceFeeds) { + for (const [index, feed] of response.parsed.priceFeeds.entries()) { + if (feed.price && feed.exponent !== undefined) { + const readablePrice = Number(feed.price) * Math.pow(10, feed.exponent); + const readableConfidence = feed.confidence + ? Number(feed.confidence) * Math.pow(10, feed.exponent) + : undefined; - console.log(`Feed ${feed.priceFeedId || index + 1}:`); - console.log(`\tPrice: $${readablePrice.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 8 })}`); - if (readableConfidence !== null) { - console.log(`\tConfidence: ±$${readableConfidence.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 8 })}`); - } - } - }); + console.log(`Feed ${(index + 1).toString()}:`); + console.log( + `\tPrice: $${readablePrice.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 8 })}`, + ); + if (readableConfidence !== undefined) { + console.log( + `\tConfidence: ±$${readableConfidence.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 8 })}`, + ); + } + } } + } } diff --git a/lazer/sdk/js/src/client.ts b/lazer/sdk/js/src/client.ts index 0cd3a40341..7bdc16c4bc 100644 --- a/lazer/sdk/js/src/client.ts +++ b/lazer/sdk/js/src/client.ts @@ -3,7 +3,10 @@ import WebSocket from "isomorphic-ws"; import type { Logger } from "ts-log"; import { dummyLogger } from "ts-log"; -import { DEFAULT_METADATA_SERVICE_URL, DEFAULT_PRICE_SERVICE_URL } from "./constants.js"; +import { + DEFAULT_METADATA_SERVICE_URL, + DEFAULT_PRICE_SERVICE_URL, +} from "./constants.js"; import type { ParsedPayload, Request, @@ -28,12 +31,11 @@ export type BinaryResponse = { }; export type JsonOrBinaryResponse = | { - type: "json"; - value: Response; - } + type: "json"; + value: Response; + } | { type: "binary"; value: BinaryResponse }; - const UINT16_NUM_BYTES = 2; const UINT32_NUM_BYTES = 4; const UINT64_NUM_BYTES = 8; @@ -56,37 +58,51 @@ export class PythLazerClient { ) {} /** - * Validates that the WebSocket pool is available for streaming operations. + * Gets the WebSocket pool. If the WebSocket pool is not configured, an error is thrown. * @throws Error if WebSocket pool is not configured + * @returns The WebSocket pool */ - private validateWebSocketPool(): void { + private getWebSocketPool(): WebSocketPool { if (!this.wsp) { - throw new Error("WebSocket pool is not available. Make sure to provide webSocketPoolConfig when creating the client."); + throw new Error( + "WebSocket pool is not available. Make sure to provide webSocketPoolConfig when creating the client.", + ); } + return this.wsp; } /** * Creates a new PythLazerClient instance. - * @param config - Configuration including WebSocket URLs, token, metadata service URL, and price service URL + * @param config - Configuration including token, metadata service URL, and price service URL, and WebSocket pool configuration */ static async create(config: LazerClientConfig): Promise { const token = config.token; // Collect and remove trailing slash from URLs - const metadataServiceUrl = - (config.metadataServiceUrl ?? - DEFAULT_METADATA_SERVICE_URL).replace(/\/+$/, ''); - const priceServiceUrl = - (config.priceServiceUrl ?? - DEFAULT_PRICE_SERVICE_URL).replace(/\/+$/, ''); + const metadataServiceUrl = ( + config.metadataServiceUrl ?? DEFAULT_METADATA_SERVICE_URL + ).replace(/\/+$/, ""); + const priceServiceUrl = ( + config.priceServiceUrl ?? DEFAULT_PRICE_SERVICE_URL + ).replace(/\/+$/, ""); const logger = config.logger ?? dummyLogger; // If webSocketPoolConfig is provided, create a WebSocket pool and block until at least one connection is established. let wsp: WebSocketPool | undefined; if (config.webSocketPoolConfig) { - wsp = await WebSocketPool.create(config.webSocketPoolConfig, token, logger); + wsp = await WebSocketPool.create( + config.webSocketPoolConfig, + token, + logger, + ); } - return new PythLazerClient(token, metadataServiceUrl, priceServiceUrl, logger, wsp); + return new PythLazerClient( + token, + metadataServiceUrl, + priceServiceUrl, + logger, + wsp, + ); } /** @@ -96,8 +112,8 @@ export class PythLazerClient { * or a binary response containing EVM, Solana, or parsed payload data. */ addMessageListener(handler: (event: JsonOrBinaryResponse) => void) { - this.validateWebSocketPool(); - this.wsp!.addMessageListener((data: WebSocket.Data) => { + const wsp = this.getWebSocketPool(); + wsp.addMessageListener((data: WebSocket.Data) => { if (typeof data == "string") { handler({ type: "json", @@ -148,21 +164,21 @@ export class PythLazerClient { } subscribe(request: Request) { - this.validateWebSocketPool(); + const wsp = this.getWebSocketPool(); if (request.type !== "subscribe") { throw new Error("Request must be a subscribe request"); } - this.wsp!.addSubscription(request); + wsp.addSubscription(request); } unsubscribe(subscriptionId: number) { - this.validateWebSocketPool(); - this.wsp!.removeSubscription(subscriptionId); + const wsp = this.getWebSocketPool(); + wsp.removeSubscription(subscriptionId); } send(request: Request) { - this.validateWebSocketPool(); - this.wsp!.sendRequest(request); + const wsp = this.getWebSocketPool(); + wsp.sendRequest(request); } /** @@ -171,13 +187,13 @@ export class PythLazerClient { * @param handler - Function to be called when all connections are down */ addAllConnectionsDownListener(handler: () => void): void { - this.validateWebSocketPool(); - this.wsp!.addAllConnectionsDownListener(handler); + const wsp = this.getWebSocketPool(); + wsp.addAllConnectionsDownListener(handler); } shutdown(): void { - this.validateWebSocketPool(); - this.wsp!.shutdown(); + const wsp = this.getWebSocketPool(); + wsp.shutdown(); } /** @@ -186,10 +202,13 @@ export class PythLazerClient { * @param options - Additional fetch options * @returns Promise resolving to the fetch Response */ - private async authenticatedFetch(url: string, options: RequestInit = {}): Promise { + private async authenticatedFetch( + url: string, + options: RequestInit = {}, + ): Promise { const headers = { - 'Authorization': `Bearer ${this.token}`, - ...options.headers, + Authorization: `Bearer ${this.token}`, + ...(options.headers as Record), }; return fetch(url, { @@ -216,7 +235,9 @@ export class PythLazerClient { try { const response = await this.authenticatedFetch(url.toString()); if (!response.ok) { - throw new Error(`HTTP error! status: ${String(response.status)} - ${await response.text()}`); + throw new Error( + `HTTP error! status: ${String(response.status)} - ${await response.text()}`, + ); } return (await response.json()) as SymbolResponse[]; } catch (error) { @@ -238,14 +259,16 @@ export class PythLazerClient { const body = JSON.stringify(params); this.logger.debug("get_latest_price", { url, body }); const response = await this.authenticatedFetch(url, { - method: 'POST', + method: "POST", headers: { - 'Content-Type': 'application/json', + "Content-Type": "application/json", }, body: body, }); if (!response.ok) { - throw new Error(`HTTP error! status: ${String(response.status)} - ${await response.text()}`); + throw new Error( + `HTTP error! status: ${String(response.status)} - ${await response.text()}`, + ); } return (await response.json()) as JsonUpdate; } catch (error) { @@ -267,14 +290,16 @@ export class PythLazerClient { const body = JSON.stringify(params); this.logger.debug("get_price", { url, body }); const response = await this.authenticatedFetch(url, { - method: 'POST', + method: "POST", headers: { - 'Content-Type': 'application/json', + "Content-Type": "application/json", }, body: body, }); if (!response.ok) { - throw new Error(`HTTP error! status: ${String(response.status)} - ${await response.text()}`); + throw new Error( + `HTTP error! status: ${String(response.status)} - ${await response.text()}`, + ); } return (await response.json()) as JsonUpdate; } catch (error) { diff --git a/lazer/sdk/js/src/constants.ts b/lazer/sdk/js/src/constants.ts index 1ef95cb9f0..b905efd79a 100644 --- a/lazer/sdk/js/src/constants.ts +++ b/lazer/sdk/js/src/constants.ts @@ -4,8 +4,7 @@ export const SOLANA_LAZER_STORAGE_ID = "3rdJbqfnagQ4yx9HXJViD4zc4xpiSqmFsKpPuSCQVyQL"; export const DEFAULT_METADATA_SERVICE_URL = "https://history.pyth-lazer.dourolabs.app/history"; -export const DEFAULT_PRICE_SERVICE_URL = - "https://pyth-lazer-0.dourolabs.app"; +export const DEFAULT_PRICE_SERVICE_URL = "https://pyth-lazer-0.dourolabs.app"; export const DEFAULT_STREAM_SERVICE_0_URL = "wss://pyth-lazer-0.dourolabs.app/v1/stream"; export const DEFAULT_STREAM_SERVICE_1_URL = diff --git a/lazer/sdk/js/src/protocol.ts b/lazer/sdk/js/src/protocol.ts index 482cbe775a..697b6f2b70 100644 --- a/lazer/sdk/js/src/protocol.ts +++ b/lazer/sdk/js/src/protocol.ts @@ -12,21 +12,21 @@ export type Channel = "real_time" | "fixed_rate@50ms" | "fixed_rate@200ms"; export type Request = | { - type: "subscribe"; - subscriptionId: number; - priceFeedIds: number[]; - properties: PriceFeedProperty[]; - formats: Format[]; - deliveryFormat?: DeliveryFormat; - jsonBinaryEncoding?: JsonBinaryEncoding; - parsed?: boolean; - ignoreInvalidFeedIds?: boolean; - channel: Channel; - } + type: "subscribe"; + subscriptionId: number; + priceFeedIds: number[]; + properties: PriceFeedProperty[]; + formats: Format[]; + deliveryFormat?: DeliveryFormat; + jsonBinaryEncoding?: JsonBinaryEncoding; + parsed?: boolean; + ignoreInvalidFeedIds?: boolean; + channel: Channel; + } | { - type: "unsubscribe"; - subscriptionId: number; - }; + type: "unsubscribe"; + subscriptionId: number; + }; export type ParsedFeedPayload = { priceFeedId: number; @@ -56,37 +56,37 @@ export type InvalidFeedSubscriptionDetails = { export type Response = | { - type: "error"; - error: string; - } + type: "error"; + error: string; + } | { - type: "subscribed"; - subscriptionId: number; - } + type: "subscribed"; + subscriptionId: number; + } | { - type: "subscribedWithInvalidFeedIdsIgnored"; - subscriptionId: number; - subscribedFeedIds: number[]; - ignoredInvalidFeedIds: InvalidFeedSubscriptionDetails; - } + type: "subscribedWithInvalidFeedIdsIgnored"; + subscriptionId: number; + subscribedFeedIds: number[]; + ignoredInvalidFeedIds: InvalidFeedSubscriptionDetails; + } | { - type: "unsubscribed"; - subscriptionId: number; - } + type: "unsubscribed"; + subscriptionId: number; + } | { - type: "subscriptionError"; - subscriptionId: number; - error: string; - } + type: "subscriptionError"; + subscriptionId: number; + error: string; + } | { - type: "streamUpdated"; - subscriptionId: number; - parsed?: ParsedPayload | undefined; - evm?: JsonBinaryData | undefined; - solana?: JsonBinaryData | undefined; - leEcdsa?: JsonBinaryData | undefined; - leUnsigned?: JsonBinaryData | undefined; - }; + type: "streamUpdated"; + subscriptionId: number; + parsed?: ParsedPayload | undefined; + evm?: JsonBinaryData | undefined; + solana?: JsonBinaryData | undefined; + leEcdsa?: JsonBinaryData | undefined; + leUnsigned?: JsonBinaryData | undefined; + }; export const BINARY_UPDATE_FORMAT_MAGIC_LE = 461_928_307; diff --git a/lazer/sdk/js/src/socket/websocket-pool.ts b/lazer/sdk/js/src/socket/websocket-pool.ts index 29f1d805d1..f56a91ec24 100644 --- a/lazer/sdk/js/src/socket/websocket-pool.ts +++ b/lazer/sdk/js/src/socket/websocket-pool.ts @@ -7,7 +7,10 @@ import { dummyLogger } from "ts-log"; import type { Request, Response } from "../protocol.js"; import type { ResilientWebSocketConfig } from "./resilient-websocket.js"; import { ResilientWebSocket } from "./resilient-websocket.js"; -import { DEFAULT_STREAM_SERVICE_0_URL, DEFAULT_STREAM_SERVICE_1_URL } from "../constants.js"; +import { + DEFAULT_STREAM_SERVICE_0_URL, + DEFAULT_STREAM_SERVICE_1_URL, +} from "../constants.js"; const DEFAULT_NUM_CONNECTIONS = 4; @@ -48,8 +51,15 @@ export class WebSocketPool { * @param numConnections - Number of parallel WebSocket connections to maintain (default: 3) * @param logger - Optional logger to get socket level logs. Compatible with most loggers such as the built-in console and `bunyan`. */ - static async create(config: WebSocketPoolConfig, token: string, logger?: Logger ): Promise { - const urls = config.urls ?? [DEFAULT_STREAM_SERVICE_0_URL, DEFAULT_STREAM_SERVICE_1_URL]; + static async create( + config: WebSocketPoolConfig, + token: string, + logger?: Logger, + ): Promise { + const urls = config.urls ?? [ + DEFAULT_STREAM_SERVICE_0_URL, + DEFAULT_STREAM_SERVICE_1_URL, + ]; const log = logger ?? dummyLogger; const pool = new WebSocketPool(log); const numConnections = config.numConnections ?? DEFAULT_NUM_CONNECTIONS; From c7b2ff69c70a9a934c993c5c4f6995e680bb67c1 Mon Sep 17 00:00:00 2001 From: Tejas Badadare Date: Tue, 23 Sep 2025 10:12:31 -0700 Subject: [PATCH 09/12] update lazer sui js sdk to use updated js sdk --- .../js/examples/fetch-and-verify-update.ts | 31 ++++--------------- lazer/contracts/sui/sdk/js/package.json | 2 +- lazer/sdk/js/examples/streaming.ts | 8 ++--- 3 files changed, 11 insertions(+), 30 deletions(-) diff --git a/lazer/contracts/sui/sdk/js/examples/fetch-and-verify-update.ts b/lazer/contracts/sui/sdk/js/examples/fetch-and-verify-update.ts index 1f3ebb1297..707e03ebc2 100644 --- a/lazer/contracts/sui/sdk/js/examples/fetch-and-verify-update.ts +++ b/lazer/contracts/sui/sdk/js/examples/fetch-and-verify-update.ts @@ -1,44 +1,26 @@ import { SuiClient } from "@mysten/sui/client"; import { Ed25519Keypair } from "@mysten/sui/keypairs/ed25519"; import { Transaction } from "@mysten/sui/transactions"; -import type { Request as SubscriptionRequest } from "@pythnetwork/pyth-lazer-sdk"; import { PythLazerClient } from "@pythnetwork/pyth-lazer-sdk"; import yargs from "yargs"; import { hideBin } from "yargs/helpers"; import { addParseAndVerifyLeEcdsaUpdateCall } from "../src/client.js"; -async function getOneLeEcdsaUpdate(urls: string[], token: string) { +async function getOneLeEcdsaUpdate(token: string) { const lazer = await PythLazerClient.create({ - urls, token, - numConnections: 1, }); - const subscription: SubscriptionRequest = { - subscriptionId: 1, - type: "subscribe", + const latestPrice = await lazer.get_latest_price({ priceFeedIds: [1], properties: ["price", "bestBidPrice", "bestAskPrice", "exponent"], formats: ["leEcdsa"], channel: "fixed_rate@200ms", - deliveryFormat: "binary", jsonBinaryEncoding: "hex", - }; - - lazer.subscribe(subscription); - - return new Promise((resolve) => { - lazer.addMessageListener((event) => { - if (event.type === "binary" && event.value.leEcdsa) { - const buf = event.value.leEcdsa; - - // For the purposes of this example, we only need one update. - lazer.shutdown(); - resolve(buf); - } - }); }); + + return latestPrice } async function main() { @@ -87,8 +69,7 @@ async function main() { const provider = new SuiClient({ url: args.fullnodeUrl }); // Fetch the price update - const updateBytes = await getOneLeEcdsaUpdate( - args.lazerUrls, + const update = await getOneLeEcdsaUpdate( args.lazerToken, ); @@ -100,7 +81,7 @@ async function main() { tx, packageId: args.packageId, stateObjectId: args.stateObjectId, - updateBytes, + updateBytes: Buffer.from(update.leEcdsa?.data ?? "", "hex"), }); // --- You can add more calls to the transaction that consume the parsed update here --- diff --git a/lazer/contracts/sui/sdk/js/package.json b/lazer/contracts/sui/sdk/js/package.json index a8fe2d31e6..19c61b3ce7 100644 --- a/lazer/contracts/sui/sdk/js/package.json +++ b/lazer/contracts/sui/sdk/js/package.json @@ -1,6 +1,6 @@ { "name": "@pythnetwork/pyth-lazer-sui-js", - "version": "0.1.0", + "version": "0.1.1", "description": "TypeScript SDK for the Pyth Lazer Sui contract", "license": "Apache-2.0", "type": "module", diff --git a/lazer/sdk/js/examples/streaming.ts b/lazer/sdk/js/examples/streaming.ts index 9a7af3e9f2..5ea1aa9134 100644 --- a/lazer/sdk/js/examples/streaming.ts +++ b/lazer/sdk/js/examples/streaming.ts @@ -6,7 +6,7 @@ import type { JsonUpdate } from "../src/index.js"; import { PythLazerClient } from "../src/index.js"; // Ignore debug messages -console.debug = () => {}; +console.debug = () => { }; // Store feed data for in-place updates const feedData = new Map< @@ -21,7 +21,7 @@ const feedData = new Map< >(); const client = await PythLazerClient.create({ - token: "your-token-here", // Replace with your actual access token + token: "ZpIVWYXIXXIPAARXLt50VTRMNjW91UUAnDu-test", // Replace with your actual access token logger: console, // Optionally log operations (to the console in this case.) webSocketPoolConfig: { numConnections: 4, // Optionally specify number of parallel redundant connections to reduce the chance of dropped messages. The connections will round-robin across the provided URLs. Default is 4. @@ -86,7 +86,7 @@ client.subscribe({ properties: ["price", "exponent", "publisherCount", "confidence"], formats: ["evm"], deliveryFormat: "json", - channel: "fixed_rate@200ms", + channel: "fixed_rate@50ms", parsed: true, jsonBinaryEncoding: "hex", }); @@ -97,7 +97,7 @@ client.subscribe({ properties: ["price", "confidence"], formats: ["solana"], deliveryFormat: "json", - channel: "fixed_rate@200ms", + channel: "real_time", parsed: true, jsonBinaryEncoding: "hex", }); From 51db2dd2ce543f2ca358451f4b782f4adf45d473 Mon Sep 17 00:00:00 2001 From: Tejas Badadare Date: Tue, 23 Sep 2025 10:50:03 -0700 Subject: [PATCH 10/12] display symbols in streaming example --- lazer/sdk/js/examples/streaming.ts | 21 +++++++++++++++------ lazer/sdk/js/examples/util.ts | 24 ++++++++++++++---------- 2 files changed, 29 insertions(+), 16 deletions(-) diff --git a/lazer/sdk/js/examples/streaming.ts b/lazer/sdk/js/examples/streaming.ts index 5ea1aa9134..047447379c 100644 --- a/lazer/sdk/js/examples/streaming.ts +++ b/lazer/sdk/js/examples/streaming.ts @@ -1,27 +1,29 @@ /* eslint-disable no-console */ /* eslint-disable @typescript-eslint/no-empty-function */ +/* eslint-disable unicorn/prefer-top-level-await */ import { renderFeeds, refreshFeedDisplay } from "./util.js"; import type { JsonUpdate } from "../src/index.js"; import { PythLazerClient } from "../src/index.js"; // Ignore debug messages -console.debug = () => { }; +console.debug = () => {}; // Store feed data for in-place updates const feedData = new Map< string, { - priceFeedId: string | number; + priceFeedId: number; price: number; confidence: number | undefined; exponent: number; lastUpdate: Date; } >(); +const symbolsMap = new Map(); const client = await PythLazerClient.create({ - token: "ZpIVWYXIXXIPAARXLt50VTRMNjW91UUAnDu-test", // Replace with your actual access token + token: "your-token-here", // Replace with your actual access token logger: console, // Optionally log operations (to the console in this case.) webSocketPoolConfig: { numConnections: 4, // Optionally specify number of parallel redundant connections to reduce the chance of dropped messages. The connections will round-robin across the provided URLs. Default is 4. @@ -37,12 +39,19 @@ const client = await PythLazerClient.create({ }, }); -// Read and display messages from the Lazer stream +// Fetch current map of price feeds +void client.get_symbols().then((symbols) => { + for (const symbol of symbols) { + symbolsMap.set(symbol.pyth_lazer_id, symbol.symbol); + } +}); + +// Add a listener to read and display messages from the Lazer stream client.addMessageListener((message) => { switch (message.type) { case "json": { if (message.value.type == "streamUpdated") { - refreshFeedDisplay(message.value as JsonUpdate, feedData); + refreshFeedDisplay(message.value as JsonUpdate, feedData, symbolsMap); } break; } @@ -65,7 +74,7 @@ client.addAllConnectionsDownListener(() => { console.error("All connections are down!"); }); -renderFeeds(feedData); +renderFeeds(feedData, symbolsMap); // Create and remove one or more subscriptions on the fly client.subscribe({ diff --git a/lazer/sdk/js/examples/util.ts b/lazer/sdk/js/examples/util.ts index 10924e98f1..0bdf108db1 100644 --- a/lazer/sdk/js/examples/util.ts +++ b/lazer/sdk/js/examples/util.ts @@ -7,13 +7,14 @@ export function renderFeeds( feedData: Map< string, { - priceFeedId: string | number; + priceFeedId: number; price: number; confidence: number | undefined; exponent: number; lastUpdate: Date; } >, + symbolsMap: Map, ) { // Clear screen and move cursor to top process.stdout.write("\u001B[2J\u001B[H"); @@ -41,9 +42,12 @@ export function renderFeeds( : feed.confidence * Math.pow(10, feed.exponent); const timeAgo = Math.round(Date.now() - feed.lastUpdate.getTime()); - console.log( - `\u001B[36m${(index + 1).toString()}. Feed ID: ${feed.priceFeedId.toString()}\u001B[0m`, - ); + const symbolName = symbolsMap.get(Number(feed.priceFeedId)); + const displayName = symbolName + ? `Feed ID: ${feed.priceFeedId.toString()} (${symbolName})` + : `Feed ID: ${feed.priceFeedId.toString()}`; + + console.log(`\u001B[36m${(index + 1).toString()}. ${displayName}\u001B[0m`); console.log( ` 💰 Price: \u001B[32m$${readablePrice.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 8 })}\u001B[0m`, ); @@ -72,24 +76,24 @@ export function refreshFeedDisplay( feedData: Map< string, { - priceFeedId: string | number; + priceFeedId: number; price: number; confidence: number | undefined; exponent: number; lastUpdate: Date; } >, + symbolsMap: Map, ) { if (response.parsed?.priceFeeds) { - for (const [index, feed] of response.parsed.priceFeeds.entries()) { + for (const feed of response.parsed.priceFeeds) { if (feed.price && feed.exponent !== undefined) { - const feedId = `feed_${(index + 1).toString()}`; const readableConfidence = feed.confidence ? Number(feed.confidence) : undefined; - feedData.set(feedId, { - priceFeedId: `feed_${(index + 1).toString()}`, + feedData.set(feed.priceFeedId.toString(), { + priceFeedId: feed.priceFeedId, price: Number(feed.price), confidence: readableConfidence, exponent: feed.exponent, @@ -98,7 +102,7 @@ export function refreshFeedDisplay( } } - renderFeeds(feedData); + renderFeeds(feedData, symbolsMap); } } From 56f0aefe649600f99064fce1979be42e6edd854c Mon Sep 17 00:00:00 2001 From: Tejas Badadare Date: Tue, 23 Sep 2025 10:55:49 -0700 Subject: [PATCH 11/12] lint --- .../sui/sdk/js/examples/fetch-and-verify-update.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lazer/contracts/sui/sdk/js/examples/fetch-and-verify-update.ts b/lazer/contracts/sui/sdk/js/examples/fetch-and-verify-update.ts index 707e03ebc2..47a3c0dd76 100644 --- a/lazer/contracts/sui/sdk/js/examples/fetch-and-verify-update.ts +++ b/lazer/contracts/sui/sdk/js/examples/fetch-and-verify-update.ts @@ -20,7 +20,7 @@ async function getOneLeEcdsaUpdate(token: string) { jsonBinaryEncoding: "hex", }); - return latestPrice + return latestPrice; } async function main() { @@ -69,9 +69,7 @@ async function main() { const provider = new SuiClient({ url: args.fullnodeUrl }); // Fetch the price update - const update = await getOneLeEcdsaUpdate( - args.lazerToken, - ); + const update = await getOneLeEcdsaUpdate(args.lazerToken); // Build the Sui transaction const tx = new Transaction(); From 4d98508152abded32895cad14bcaf9f43f6988c8 Mon Sep 17 00:00:00 2001 From: Tejas Badadare Date: Tue, 23 Sep 2025 10:59:29 -0700 Subject: [PATCH 12/12] add comment --- lazer/sdk/js/examples/streaming.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/lazer/sdk/js/examples/streaming.ts b/lazer/sdk/js/examples/streaming.ts index 047447379c..1fdbfc5631 100644 --- a/lazer/sdk/js/examples/streaming.ts +++ b/lazer/sdk/js/examples/streaming.ts @@ -117,6 +117,7 @@ client.unsubscribe(1); client.unsubscribe(2); client.unsubscribe(3); +// Clear screen and move cursor to top process.stdout.write("\u001B[2J\u001B[H"); console.log("🛑 Shutting down Pyth Lazer demo after 30 seconds..."); console.log("👋 Goodbye!");