@k256/sdk 0.1.6 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -100,24 +100,93 @@ interface RoutePlanStep {
100
100
  percent: number;
101
101
  }
102
102
  /**
103
- * Priority fee estimates
103
+ * Mini block statistics (compact form used in FeeMarket.recentBlocks)
104
104
  */
105
- interface PriorityFees {
105
+ interface BlockMiniStats {
106
+ slot: number;
107
+ cuConsumed: number;
108
+ txCount: number;
109
+ utilizationPct: number;
110
+ avgCuPrice: number;
111
+ }
112
+ /**
113
+ * Direction of the fee trend
114
+ */
115
+ type TrendDirection = 'rising' | 'falling' | 'stable';
116
+ /**
117
+ * Full block-level statistics (standalone message 0x0F)
118
+ */
119
+ interface BlockStats {
120
+ slot: number;
121
+ cuConsumed: number;
122
+ executionCu: number;
123
+ cuLimit: number;
124
+ cuRemaining: number;
125
+ utilizationPct: number;
126
+ txCount: number;
127
+ avgCuPerTx: number;
128
+ avgCuPrice: number;
129
+ minCuPrice: number;
130
+ maxCuPrice: number;
131
+ timestampMs: number;
132
+ }
133
+ /**
134
+ * Per-writable-account fee data
135
+ *
136
+ * Solana's scheduler limits each writable account to 12M CU per block.
137
+ * Fee pricing is per-account: the fee you pay should be
138
+ * max(p75(account) for account in your writable accounts).
139
+ */
140
+ interface AccountFee {
141
+ /** Account public key (Base58) */
142
+ pubkey: string;
143
+ /** Total transactions touching this account in the window */
144
+ totalTxs: number;
145
+ /** Number of slots where this account was active */
146
+ activeSlots: number;
147
+ /** Total CU consumed by transactions touching this account */
148
+ cuConsumed: number;
149
+ /** Account utilization percentage (0-100) of 12M CU limit */
150
+ utilizationPct: number;
151
+ /** 25th percentile fee in microlamports/CU */
152
+ p25: number;
153
+ /** 50th percentile fee in microlamports/CU */
154
+ p50: number;
155
+ /** 75th percentile fee in microlamports/CU */
156
+ p75: number;
157
+ /** 90th percentile fee in microlamports/CU */
158
+ p90: number;
159
+ /** Minimum non-zero fee observed */
160
+ minNonzeroPrice: number;
161
+ }
162
+ /**
163
+ * Fee market update (per-writable-account model)
164
+ *
165
+ * Replaces the old flat PriorityFees struct. Now provides per-account
166
+ * fee data so clients can price transactions based on the specific
167
+ * writable accounts they touch.
168
+ */
169
+ interface FeeMarket {
106
170
  /** Current slot */
107
171
  slot: number;
108
172
  /** Timestamp in milliseconds */
109
173
  timestampMs: number;
110
- /** Recommended fee in microlamports */
174
+ /** Recommended fee in microlamports/CU (max p75 across hottest accounts) */
111
175
  recommended: number;
112
- /** Network state (0=low, 1=normal, 2=high, 3=congested) */
176
+ /** Network state (0=low, 1=normal, 2=high, 3=extreme) */
113
177
  state: NetworkState;
114
178
  /** Whether data is stale */
115
179
  isStale: boolean;
116
- /** Swap fee percentiles */
117
- swapP50: number;
118
- swapP75: number;
119
- swapP90: number;
120
- swapP99: number;
180
+ /** Block utilization percentage (0-100) */
181
+ blockUtilizationPct: number;
182
+ /** Number of blocks in the observation window */
183
+ blocksInWindow: number;
184
+ /** Per-account fee data */
185
+ accounts: AccountFee[];
186
+ /** Recent block mini-stats (v3) */
187
+ recentBlocks: BlockMiniStats[];
188
+ /** Fee trend direction (v3) */
189
+ trend: TrendDirection;
121
190
  }
122
191
  /**
123
192
  * Network congestion state
@@ -197,4 +266,4 @@ interface SubscribeQuoteRequest {
197
266
  refreshIntervalMs?: number;
198
267
  }
199
268
 
200
- export { type Blockhash, type Heartbeat, NetworkState, type OrderLevel, type Pool, type PoolUpdate, type PriorityFees, type Quote, type RoutePlanStep, type SubscribeQuoteRequest, type SubscribeRequest, type Token };
269
+ export { type AccountFee, type BlockMiniStats, type BlockStats, type Blockhash, type FeeMarket, type Heartbeat, NetworkState, type OrderLevel, type Pool, type PoolUpdate, type Quote, type RoutePlanStep, type SubscribeQuoteRequest, type SubscribeRequest, type Token, type TrendDirection };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/types/index.ts"],"names":["NetworkState"],"mappings":";AAoIO,IAAK,YAAA,qBAAAA,aAAAA,KAAL;AACL,EAAAA,aAAAA,CAAAA,aAAAA,CAAA,SAAM,CAAA,CAAA,GAAN,KAAA;AACA,EAAAA,aAAAA,CAAAA,aAAAA,CAAA,YAAS,CAAA,CAAA,GAAT,QAAA;AACA,EAAAA,aAAAA,CAAAA,aAAAA,CAAA,UAAO,CAAA,CAAA,GAAP,MAAA;AACA,EAAAA,aAAAA,CAAAA,aAAAA,CAAA,eAAY,CAAA,CAAA,GAAZ,WAAA;AAJU,EAAA,OAAAA,aAAAA;AAAA,CAAA,EAAA,YAAA,IAAA,EAAA","file":"index.js","sourcesContent":["/**\n * Shared type definitions for K256 SDK\n * \n * These types are used across WebSocket and REST API modules.\n * \n * @module @k256/sdk/types\n */\n\n/**\n * Pool state from DEX\n */\nexport interface Pool {\n /** Pool address (Base58) */\n address: string;\n /** Protocol/DEX name */\n protocol: string;\n /** Token mints in the pool (Base58) */\n tokenMints: string[];\n /** Token balances (as strings for precision) */\n tokenBalances: string[];\n /** Token decimals */\n tokenDecimals: number[];\n}\n\n/**\n * Real-time pool state update\n */\nexport interface PoolUpdate extends Pool {\n /** Global sequence number (monotonically increasing) */\n sequence: number;\n /** Solana slot when updated */\n slot: number;\n /** Write version within slot */\n writeVersion: number;\n /** Best bid price/size (orderbook pools only) */\n bestBid?: OrderLevel;\n /** Best ask price/size (orderbook pools only) */\n bestAsk?: OrderLevel;\n}\n\n/**\n * Order book level (bid or ask)\n */\nexport interface OrderLevel {\n /** Price in base units (as string for precision) */\n price: string;\n /** Size in base units (as string for precision) */\n size: string;\n}\n\n/**\n * Token metadata\n */\nexport interface Token {\n /** Token mint address (Base58) */\n mint: string;\n /** Token symbol (e.g., \"SOL\", \"USDC\") */\n symbol: string;\n /** Token name */\n name: string;\n /** Decimal places */\n decimals: number;\n /** Logo URL (optional) */\n logoUri?: string;\n /** Coingecko ID (optional) */\n coingeckoId?: string;\n}\n\n/**\n * Swap quote from aggregator\n */\nexport interface Quote {\n /** Input token mint (Base58) */\n inputMint: string;\n /** Output token mint (Base58) */\n outputMint: string;\n /** Input amount (as string for precision) */\n inAmount: string;\n /** Output amount (as string for precision) */\n outAmount: string;\n /** Price impact in basis points */\n priceImpactBps: number;\n /** Slippage in basis points */\n slippageBps: number;\n /** Route plan (DEXes used) */\n routePlan: RoutePlanStep[];\n /** Context slot */\n contextSlot: number;\n /** Algorithm used for routing */\n algorithm: string;\n}\n\n/**\n * Step in a swap route\n */\nexport interface RoutePlanStep {\n /** DEX/protocol name */\n protocol: string;\n /** Pool address (Base58) */\n poolAddress: string;\n /** Input mint for this step */\n inputMint: string;\n /** Output mint for this step */\n outputMint: string;\n /** Percentage of input for this step (0-100) */\n percent: number;\n}\n\n/**\n * Priority fee estimates\n */\nexport interface PriorityFees {\n /** Current slot */\n slot: number;\n /** Timestamp in milliseconds */\n timestampMs: number;\n /** Recommended fee in microlamports */\n recommended: number;\n /** Network state (0=low, 1=normal, 2=high, 3=congested) */\n state: NetworkState;\n /** Whether data is stale */\n isStale: boolean;\n /** Swap fee percentiles */\n swapP50: number;\n swapP75: number;\n swapP90: number;\n swapP99: number;\n}\n\n/**\n * Network congestion state\n */\nexport enum NetworkState {\n Low = 0,\n Normal = 1,\n High = 2,\n Congested = 3,\n}\n\n/**\n * Recent blockhash for transactions\n */\nexport interface Blockhash {\n /** Slot of blockhash */\n slot: number;\n /** Timestamp in milliseconds */\n timestampMs: number;\n /** Recent blockhash (Base58) */\n blockhash: string;\n /** Block height */\n blockHeight: number;\n /** Last valid block height for transactions */\n lastValidBlockHeight: number;\n /** Whether data is stale */\n isStale: boolean;\n}\n\n/**\n * WebSocket connection heartbeat\n */\nexport interface Heartbeat {\n /** Server timestamp in milliseconds */\n timestampMs: number;\n /** Connection uptime in seconds */\n uptimeSecs: number;\n /** Total messages sent */\n messagesSent: number;\n /** Pool updates sent */\n poolUpdatesSent: number;\n /** Messages dropped (slow client) */\n messagesDropped: number;\n /** Whether pool updates are enabled */\n poolUpdatesEnabled: boolean;\n /** Subscribed channels */\n subscribedChannels: string[];\n /** Server sequence number */\n serverSequence: number;\n}\n\n/**\n * Subscribe request for WebSocket\n */\nexport interface SubscribeRequest {\n /** Channels to subscribe to */\n channels: ('pools' | 'priority_fees' | 'blockhash')[];\n /** Response format (default: binary) */\n format?: 'binary' | 'json';\n /** Filter by protocol names */\n protocols?: string[];\n /** Filter by pool addresses (Base58) */\n pools?: string[];\n /** Filter by token pairs [[mintA, mintB], ...] */\n tokenPairs?: [string, string][];\n}\n\n/**\n * Quote subscription request\n */\nexport interface SubscribeQuoteRequest {\n /** Input token mint (Base58) */\n inputMint: string;\n /** Output token mint (Base58) */\n outputMint: string;\n /** Amount in base units */\n amount: number;\n /** Slippage tolerance in basis points */\n slippageBps?: number;\n /** Refresh interval in milliseconds */\n refreshIntervalMs?: number;\n}\n"]}
1
+ {"version":3,"sources":["../../src/types/index.ts"],"names":["NetworkState"],"mappings":";AA6MO,IAAK,YAAA,qBAAAA,aAAAA,KAAL;AACL,EAAAA,aAAAA,CAAAA,aAAAA,CAAA,SAAM,CAAA,CAAA,GAAN,KAAA;AACA,EAAAA,aAAAA,CAAAA,aAAAA,CAAA,YAAS,CAAA,CAAA,GAAT,QAAA;AACA,EAAAA,aAAAA,CAAAA,aAAAA,CAAA,UAAO,CAAA,CAAA,GAAP,MAAA;AACA,EAAAA,aAAAA,CAAAA,aAAAA,CAAA,eAAY,CAAA,CAAA,GAAZ,WAAA;AAJU,EAAA,OAAAA,aAAAA;AAAA,CAAA,EAAA,YAAA,IAAA,EAAA","file":"index.js","sourcesContent":["/**\n * Shared type definitions for K256 SDK\n *\n * These types are used across WebSocket and REST API modules.\n *\n * @module @k256/sdk/types\n */\n\n/**\n * Pool state from DEX\n */\nexport interface Pool {\n /** Pool address (Base58) */\n address: string;\n /** Protocol/DEX name */\n protocol: string;\n /** Token mints in the pool (Base58) */\n tokenMints: string[];\n /** Token balances (as strings for precision) */\n tokenBalances: string[];\n /** Token decimals */\n tokenDecimals: number[];\n}\n\n/**\n * Real-time pool state update\n */\nexport interface PoolUpdate extends Pool {\n /** Global sequence number (monotonically increasing) */\n sequence: number;\n /** Solana slot when updated */\n slot: number;\n /** Write version within slot */\n writeVersion: number;\n /** Best bid price/size (orderbook pools only) */\n bestBid?: OrderLevel;\n /** Best ask price/size (orderbook pools only) */\n bestAsk?: OrderLevel;\n}\n\n/**\n * Order book level (bid or ask)\n */\nexport interface OrderLevel {\n /** Price in base units (as string for precision) */\n price: string;\n /** Size in base units (as string for precision) */\n size: string;\n}\n\n/**\n * Token metadata\n */\nexport interface Token {\n /** Token mint address (Base58) */\n mint: string;\n /** Token symbol (e.g., \"SOL\", \"USDC\") */\n symbol: string;\n /** Token name */\n name: string;\n /** Decimal places */\n decimals: number;\n /** Logo URL (optional) */\n logoUri?: string;\n /** Coingecko ID (optional) */\n coingeckoId?: string;\n}\n\n/**\n * Swap quote from aggregator\n */\nexport interface Quote {\n /** Input token mint (Base58) */\n inputMint: string;\n /** Output token mint (Base58) */\n outputMint: string;\n /** Input amount (as string for precision) */\n inAmount: string;\n /** Output amount (as string for precision) */\n outAmount: string;\n /** Price impact in basis points */\n priceImpactBps: number;\n /** Slippage in basis points */\n slippageBps: number;\n /** Route plan (DEXes used) */\n routePlan: RoutePlanStep[];\n /** Context slot */\n contextSlot: number;\n /** Algorithm used for routing */\n algorithm: string;\n}\n\n/**\n * Step in a swap route\n */\nexport interface RoutePlanStep {\n /** DEX/protocol name */\n protocol: string;\n /** Pool address (Base58) */\n poolAddress: string;\n /** Input mint for this step */\n inputMint: string;\n /** Output mint for this step */\n outputMint: string;\n /** Percentage of input for this step (0-100) */\n percent: number;\n}\n\n/**\n * Mini block statistics (compact form used in FeeMarket.recentBlocks)\n */\nexport interface BlockMiniStats {\n slot: number\n cuConsumed: number\n txCount: number\n utilizationPct: number\n avgCuPrice: number\n}\n\n/**\n * Direction of the fee trend\n */\nexport type TrendDirection = 'rising' | 'falling' | 'stable'\n\n/**\n * Full block-level statistics (standalone message 0x0F)\n */\nexport interface BlockStats {\n slot: number\n cuConsumed: number\n executionCu: number\n cuLimit: number\n cuRemaining: number\n utilizationPct: number\n txCount: number\n avgCuPerTx: number\n avgCuPrice: number\n minCuPrice: number\n maxCuPrice: number\n timestampMs: number\n}\n\n/**\n * Per-writable-account fee data\n *\n * Solana's scheduler limits each writable account to 12M CU per block.\n * Fee pricing is per-account: the fee you pay should be\n * max(p75(account) for account in your writable accounts).\n */\nexport interface AccountFee {\n /** Account public key (Base58) */\n pubkey: string;\n /** Total transactions touching this account in the window */\n totalTxs: number;\n /** Number of slots where this account was active */\n activeSlots: number;\n /** Total CU consumed by transactions touching this account */\n cuConsumed: number;\n /** Account utilization percentage (0-100) of 12M CU limit */\n utilizationPct: number;\n /** 25th percentile fee in microlamports/CU */\n p25: number;\n /** 50th percentile fee in microlamports/CU */\n p50: number;\n /** 75th percentile fee in microlamports/CU */\n p75: number;\n /** 90th percentile fee in microlamports/CU */\n p90: number;\n /** Minimum non-zero fee observed */\n minNonzeroPrice: number;\n}\n\n/**\n * Fee market update (per-writable-account model)\n *\n * Replaces the old flat PriorityFees struct. Now provides per-account\n * fee data so clients can price transactions based on the specific\n * writable accounts they touch.\n */\nexport interface FeeMarket {\n /** Current slot */\n slot: number;\n /** Timestamp in milliseconds */\n timestampMs: number;\n /** Recommended fee in microlamports/CU (max p75 across hottest accounts) */\n recommended: number;\n /** Network state (0=low, 1=normal, 2=high, 3=extreme) */\n state: NetworkState;\n /** Whether data is stale */\n isStale: boolean;\n /** Block utilization percentage (0-100) */\n blockUtilizationPct: number;\n /** Number of blocks in the observation window */\n blocksInWindow: number;\n /** Per-account fee data */\n accounts: AccountFee[];\n /** Recent block mini-stats (v3) */\n recentBlocks: BlockMiniStats[];\n /** Fee trend direction (v3) */\n trend: TrendDirection;\n}\n\n/**\n * Network congestion state\n */\nexport enum NetworkState {\n Low = 0,\n Normal = 1,\n High = 2,\n Congested = 3,\n}\n\n/**\n * Recent blockhash for transactions\n */\nexport interface Blockhash {\n /** Slot of blockhash */\n slot: number;\n /** Timestamp in milliseconds */\n timestampMs: number;\n /** Recent blockhash (Base58) */\n blockhash: string;\n /** Block height */\n blockHeight: number;\n /** Last valid block height for transactions */\n lastValidBlockHeight: number;\n /** Whether data is stale */\n isStale: boolean;\n}\n\n/**\n * WebSocket connection heartbeat\n */\nexport interface Heartbeat {\n /** Server timestamp in milliseconds */\n timestampMs: number;\n /** Connection uptime in seconds */\n uptimeSecs: number;\n /** Total messages sent */\n messagesSent: number;\n /** Pool updates sent */\n poolUpdatesSent: number;\n /** Messages dropped (slow client) */\n messagesDropped: number;\n /** Whether pool updates are enabled */\n poolUpdatesEnabled: boolean;\n /** Subscribed channels */\n subscribedChannels: string[];\n /** Server sequence number */\n serverSequence: number;\n}\n\n/**\n * Subscribe request for WebSocket\n */\nexport interface SubscribeRequest {\n /** Channels to subscribe to */\n channels: ('pools' | 'priority_fees' | 'blockhash')[];\n /** Response format (default: binary) */\n format?: 'binary' | 'json';\n /** Filter by protocol names */\n protocols?: string[];\n /** Filter by pool addresses (Base58) */\n pools?: string[];\n /** Filter by token pairs [[mintA, mintB], ...] */\n tokenPairs?: [string, string][];\n}\n\n/**\n * Quote subscription request\n */\nexport interface SubscribeQuoteRequest {\n /** Input token mint (Base58) */\n inputMint: string;\n /** Output token mint (Base58) */\n outputMint: string;\n /** Amount in base units */\n amount: number;\n /** Slippage tolerance in basis points */\n slippageBps?: number;\n /** Refresh interval in milliseconds */\n refreshIntervalMs?: number;\n}\n"]}
@@ -23,8 +23,15 @@ function base58Encode(bytes) {
23
23
  return leadingZeros + digits.reverse().map((d) => BASE58_ALPHABET[d]).join("");
24
24
  }
25
25
  function base58Decode(str) {
26
+ if (str.length === 0) {
27
+ return new Uint8Array(0);
28
+ }
29
+ let leadingZeros = 0;
30
+ for (let i = 0; i < str.length && str[i] === "1"; i++) {
31
+ leadingZeros++;
32
+ }
26
33
  const bytes = [0];
27
- for (let i = 0; i < str.length; i++) {
34
+ for (let i = leadingZeros; i < str.length; i++) {
28
35
  const char = str[i];
29
36
  const value = BASE58_ALPHABET.indexOf(char);
30
37
  if (value === -1) {
@@ -41,10 +48,19 @@ function base58Decode(str) {
41
48
  carry >>= 8;
42
49
  }
43
50
  }
44
- for (let i = 0; i < str.length && str[i] === "1"; i++) {
45
- bytes.push(0);
51
+ bytes.reverse();
52
+ if (leadingZeros > 0 && bytes.length === 1 && bytes[0] === 0) {
53
+ return new Uint8Array(leadingZeros);
54
+ }
55
+ const startIdx = bytes.length > 1 && bytes[0] === 0 ? 1 : 0;
56
+ const result = new Uint8Array(leadingZeros + bytes.length - startIdx);
57
+ for (let i = 0; i < leadingZeros; i++) {
58
+ result[i] = 0;
59
+ }
60
+ for (let i = startIdx; i < bytes.length; i++) {
61
+ result[leadingZeros + i - startIdx] = bytes[i];
46
62
  }
47
- return new Uint8Array(bytes.reverse());
63
+ return result;
48
64
  }
49
65
  function isValidPubkey(address) {
50
66
  if (address.length < 32 || address.length > 44) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utils/base58.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Base58 encoding utilities for Solana addresses\n * \n * Solana uses Base58 encoding (Bitcoin-style) for public keys and signatures.\n */\n\nconst BASE58_ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';\n\n/**\n * Encode bytes to Base58 string (Solana address format)\n * \n * @param bytes - Uint8Array to encode\n * @returns Base58 encoded string\n * \n * @example\n * ```typescript\n * const pubkey = new Uint8Array([1, 2, 3, ...]);\n * const address = base58Encode(pubkey);\n * // \"EPjFWdd5...\"\n * ```\n */\nexport function base58Encode(bytes: Uint8Array): string {\n const digits = [0];\n \n for (let i = 0; i < bytes.length; i++) {\n let carry = bytes[i];\n for (let j = 0; j < digits.length; j++) {\n carry += digits[j] << 8;\n digits[j] = carry % 58;\n carry = (carry / 58) | 0;\n }\n while (carry > 0) {\n digits.push(carry % 58);\n carry = (carry / 58) | 0;\n }\n }\n\n // Leading zeros\n let leadingZeros = '';\n for (let i = 0; i < bytes.length && bytes[i] === 0; i++) {\n leadingZeros += '1';\n }\n\n return leadingZeros + digits.reverse().map(d => BASE58_ALPHABET[d]).join('');\n}\n\n/**\n * Decode Base58 string to bytes\n * \n * @param str - Base58 encoded string\n * @returns Uint8Array of decoded bytes\n * @throws Error if string contains invalid characters\n * \n * @example\n * ```typescript\n * const bytes = base58Decode(\"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v\");\n * // Uint8Array(32) [...]\n * ```\n */\nexport function base58Decode(str: string): Uint8Array {\n const bytes = [0];\n \n for (let i = 0; i < str.length; i++) {\n const char = str[i];\n const value = BASE58_ALPHABET.indexOf(char);\n \n if (value === -1) {\n throw new Error(`Invalid Base58 character: ${char}`);\n }\n \n let carry = value;\n for (let j = 0; j < bytes.length; j++) {\n carry += bytes[j] * 58;\n bytes[j] = carry & 0xff;\n carry >>= 8;\n }\n while (carry > 0) {\n bytes.push(carry & 0xff);\n carry >>= 8;\n }\n }\n\n // Leading '1's are leading zeros\n for (let i = 0; i < str.length && str[i] === '1'; i++) {\n bytes.push(0);\n }\n\n return new Uint8Array(bytes.reverse());\n}\n\n/**\n * Check if a string is a valid Solana public key (Base58, 32-44 chars)\n * \n * @param address - String to validate\n * @returns true if valid Solana pubkey format\n * \n * @example\n * ```typescript\n * isValidPubkey(\"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v\") // true\n * isValidPubkey(\"invalid\") // false\n * ```\n */\nexport function isValidPubkey(address: string): boolean {\n // Solana pubkeys are 32-44 characters in Base58\n if (address.length < 32 || address.length > 44) {\n return false;\n }\n\n // Check all characters are valid Base58\n for (const char of address) {\n if (!BASE58_ALPHABET.includes(char)) {\n return false;\n }\n }\n\n // Try to decode and verify length\n try {\n const bytes = base58Decode(address);\n return bytes.length === 32;\n } catch {\n return false;\n }\n}\n"]}
1
+ {"version":3,"sources":["../../src/utils/base58.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Base58 encoding utilities for Solana addresses\n * \n * Solana uses Base58 encoding (Bitcoin-style) for public keys and signatures.\n */\n\nconst BASE58_ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';\n\n/**\n * Encode bytes to Base58 string (Solana address format)\n * \n * @param bytes - Uint8Array to encode\n * @returns Base58 encoded string\n * \n * @example\n * ```typescript\n * const pubkey = new Uint8Array([1, 2, 3, ...]);\n * const address = base58Encode(pubkey);\n * // \"EPjFWdd5...\"\n * ```\n */\nexport function base58Encode(bytes: Uint8Array): string {\n const digits = [0];\n \n for (let i = 0; i < bytes.length; i++) {\n let carry = bytes[i];\n for (let j = 0; j < digits.length; j++) {\n carry += digits[j] << 8;\n digits[j] = carry % 58;\n carry = (carry / 58) | 0;\n }\n while (carry > 0) {\n digits.push(carry % 58);\n carry = (carry / 58) | 0;\n }\n }\n\n // Leading zeros\n let leadingZeros = '';\n for (let i = 0; i < bytes.length && bytes[i] === 0; i++) {\n leadingZeros += '1';\n }\n\n return leadingZeros + digits.reverse().map(d => BASE58_ALPHABET[d]).join('');\n}\n\n/**\n * Decode Base58 string to bytes\n * \n * @param str - Base58 encoded string\n * @returns Uint8Array of decoded bytes\n * @throws Error if string contains invalid characters\n * \n * @example\n * ```typescript\n * const bytes = base58Decode(\"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v\");\n * // Uint8Array(32) [...]\n * ```\n */\nexport function base58Decode(str: string): Uint8Array {\n if (str.length === 0) {\n return new Uint8Array(0);\n }\n\n // Count leading '1's (they represent leading zero bytes)\n let leadingZeros = 0;\n for (let i = 0; i < str.length && str[i] === '1'; i++) {\n leadingZeros++;\n }\n\n // Process remaining characters through base conversion\n const bytes = [0];\n for (let i = leadingZeros; i < str.length; i++) {\n const char = str[i];\n const value = BASE58_ALPHABET.indexOf(char);\n \n if (value === -1) {\n throw new Error(`Invalid Base58 character: ${char}`);\n }\n \n let carry = value;\n for (let j = 0; j < bytes.length; j++) {\n carry += bytes[j] * 58;\n bytes[j] = carry & 0xff;\n carry >>= 8;\n }\n while (carry > 0) {\n bytes.push(carry & 0xff);\n carry >>= 8;\n }\n }\n\n // Build result: leading zeros + converted bytes (reversed)\n bytes.reverse();\n \n // Handle case where input was all '1's (all leading zeros, no data to convert)\n // In this case, bytes is just [0] from initialization, which we should ignore\n if (leadingZeros > 0 && bytes.length === 1 && bytes[0] === 0) {\n // Input was all '1's, return that many zero bytes\n return new Uint8Array(leadingZeros);\n }\n \n // Remove leading zero from conversion if present (artifact of starting with [0])\n const startIdx = bytes.length > 1 && bytes[0] === 0 ? 1 : 0;\n \n const result = new Uint8Array(leadingZeros + bytes.length - startIdx);\n // Fill leading zeros\n for (let i = 0; i < leadingZeros; i++) {\n result[i] = 0;\n }\n // Copy converted bytes\n for (let i = startIdx; i < bytes.length; i++) {\n result[leadingZeros + i - startIdx] = bytes[i];\n }\n \n return result;\n}\n\n/**\n * Check if a string is a valid Solana public key (Base58, 32-44 chars)\n * \n * @param address - String to validate\n * @returns true if valid Solana pubkey format\n * \n * @example\n * ```typescript\n * isValidPubkey(\"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v\") // true\n * isValidPubkey(\"invalid\") // false\n * ```\n */\nexport function isValidPubkey(address: string): boolean {\n // Solana pubkeys are 32-44 characters in Base58\n if (address.length < 32 || address.length > 44) {\n return false;\n }\n\n // Check all characters are valid Base58\n for (const char of address) {\n if (!BASE58_ALPHABET.includes(char)) {\n return false;\n }\n }\n\n // Try to decode and verify length\n try {\n const bytes = base58Decode(address);\n return bytes.length === 32;\n } catch {\n return false;\n }\n}\n"]}
@@ -21,8 +21,15 @@ function base58Encode(bytes) {
21
21
  return leadingZeros + digits.reverse().map((d) => BASE58_ALPHABET[d]).join("");
22
22
  }
23
23
  function base58Decode(str) {
24
+ if (str.length === 0) {
25
+ return new Uint8Array(0);
26
+ }
27
+ let leadingZeros = 0;
28
+ for (let i = 0; i < str.length && str[i] === "1"; i++) {
29
+ leadingZeros++;
30
+ }
24
31
  const bytes = [0];
25
- for (let i = 0; i < str.length; i++) {
32
+ for (let i = leadingZeros; i < str.length; i++) {
26
33
  const char = str[i];
27
34
  const value = BASE58_ALPHABET.indexOf(char);
28
35
  if (value === -1) {
@@ -39,10 +46,19 @@ function base58Decode(str) {
39
46
  carry >>= 8;
40
47
  }
41
48
  }
42
- for (let i = 0; i < str.length && str[i] === "1"; i++) {
43
- bytes.push(0);
49
+ bytes.reverse();
50
+ if (leadingZeros > 0 && bytes.length === 1 && bytes[0] === 0) {
51
+ return new Uint8Array(leadingZeros);
52
+ }
53
+ const startIdx = bytes.length > 1 && bytes[0] === 0 ? 1 : 0;
54
+ const result = new Uint8Array(leadingZeros + bytes.length - startIdx);
55
+ for (let i = 0; i < leadingZeros; i++) {
56
+ result[i] = 0;
57
+ }
58
+ for (let i = startIdx; i < bytes.length; i++) {
59
+ result[leadingZeros + i - startIdx] = bytes[i];
44
60
  }
45
- return new Uint8Array(bytes.reverse());
61
+ return result;
46
62
  }
47
63
  function isValidPubkey(address) {
48
64
  if (address.length < 32 || address.length > 44) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utils/base58.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Base58 encoding utilities for Solana addresses\n * \n * Solana uses Base58 encoding (Bitcoin-style) for public keys and signatures.\n */\n\nconst BASE58_ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';\n\n/**\n * Encode bytes to Base58 string (Solana address format)\n * \n * @param bytes - Uint8Array to encode\n * @returns Base58 encoded string\n * \n * @example\n * ```typescript\n * const pubkey = new Uint8Array([1, 2, 3, ...]);\n * const address = base58Encode(pubkey);\n * // \"EPjFWdd5...\"\n * ```\n */\nexport function base58Encode(bytes: Uint8Array): string {\n const digits = [0];\n \n for (let i = 0; i < bytes.length; i++) {\n let carry = bytes[i];\n for (let j = 0; j < digits.length; j++) {\n carry += digits[j] << 8;\n digits[j] = carry % 58;\n carry = (carry / 58) | 0;\n }\n while (carry > 0) {\n digits.push(carry % 58);\n carry = (carry / 58) | 0;\n }\n }\n\n // Leading zeros\n let leadingZeros = '';\n for (let i = 0; i < bytes.length && bytes[i] === 0; i++) {\n leadingZeros += '1';\n }\n\n return leadingZeros + digits.reverse().map(d => BASE58_ALPHABET[d]).join('');\n}\n\n/**\n * Decode Base58 string to bytes\n * \n * @param str - Base58 encoded string\n * @returns Uint8Array of decoded bytes\n * @throws Error if string contains invalid characters\n * \n * @example\n * ```typescript\n * const bytes = base58Decode(\"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v\");\n * // Uint8Array(32) [...]\n * ```\n */\nexport function base58Decode(str: string): Uint8Array {\n const bytes = [0];\n \n for (let i = 0; i < str.length; i++) {\n const char = str[i];\n const value = BASE58_ALPHABET.indexOf(char);\n \n if (value === -1) {\n throw new Error(`Invalid Base58 character: ${char}`);\n }\n \n let carry = value;\n for (let j = 0; j < bytes.length; j++) {\n carry += bytes[j] * 58;\n bytes[j] = carry & 0xff;\n carry >>= 8;\n }\n while (carry > 0) {\n bytes.push(carry & 0xff);\n carry >>= 8;\n }\n }\n\n // Leading '1's are leading zeros\n for (let i = 0; i < str.length && str[i] === '1'; i++) {\n bytes.push(0);\n }\n\n return new Uint8Array(bytes.reverse());\n}\n\n/**\n * Check if a string is a valid Solana public key (Base58, 32-44 chars)\n * \n * @param address - String to validate\n * @returns true if valid Solana pubkey format\n * \n * @example\n * ```typescript\n * isValidPubkey(\"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v\") // true\n * isValidPubkey(\"invalid\") // false\n * ```\n */\nexport function isValidPubkey(address: string): boolean {\n // Solana pubkeys are 32-44 characters in Base58\n if (address.length < 32 || address.length > 44) {\n return false;\n }\n\n // Check all characters are valid Base58\n for (const char of address) {\n if (!BASE58_ALPHABET.includes(char)) {\n return false;\n }\n }\n\n // Try to decode and verify length\n try {\n const bytes = base58Decode(address);\n return bytes.length === 32;\n } catch {\n return false;\n }\n}\n"]}
1
+ {"version":3,"sources":["../../src/utils/base58.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Base58 encoding utilities for Solana addresses\n * \n * Solana uses Base58 encoding (Bitcoin-style) for public keys and signatures.\n */\n\nconst BASE58_ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';\n\n/**\n * Encode bytes to Base58 string (Solana address format)\n * \n * @param bytes - Uint8Array to encode\n * @returns Base58 encoded string\n * \n * @example\n * ```typescript\n * const pubkey = new Uint8Array([1, 2, 3, ...]);\n * const address = base58Encode(pubkey);\n * // \"EPjFWdd5...\"\n * ```\n */\nexport function base58Encode(bytes: Uint8Array): string {\n const digits = [0];\n \n for (let i = 0; i < bytes.length; i++) {\n let carry = bytes[i];\n for (let j = 0; j < digits.length; j++) {\n carry += digits[j] << 8;\n digits[j] = carry % 58;\n carry = (carry / 58) | 0;\n }\n while (carry > 0) {\n digits.push(carry % 58);\n carry = (carry / 58) | 0;\n }\n }\n\n // Leading zeros\n let leadingZeros = '';\n for (let i = 0; i < bytes.length && bytes[i] === 0; i++) {\n leadingZeros += '1';\n }\n\n return leadingZeros + digits.reverse().map(d => BASE58_ALPHABET[d]).join('');\n}\n\n/**\n * Decode Base58 string to bytes\n * \n * @param str - Base58 encoded string\n * @returns Uint8Array of decoded bytes\n * @throws Error if string contains invalid characters\n * \n * @example\n * ```typescript\n * const bytes = base58Decode(\"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v\");\n * // Uint8Array(32) [...]\n * ```\n */\nexport function base58Decode(str: string): Uint8Array {\n if (str.length === 0) {\n return new Uint8Array(0);\n }\n\n // Count leading '1's (they represent leading zero bytes)\n let leadingZeros = 0;\n for (let i = 0; i < str.length && str[i] === '1'; i++) {\n leadingZeros++;\n }\n\n // Process remaining characters through base conversion\n const bytes = [0];\n for (let i = leadingZeros; i < str.length; i++) {\n const char = str[i];\n const value = BASE58_ALPHABET.indexOf(char);\n \n if (value === -1) {\n throw new Error(`Invalid Base58 character: ${char}`);\n }\n \n let carry = value;\n for (let j = 0; j < bytes.length; j++) {\n carry += bytes[j] * 58;\n bytes[j] = carry & 0xff;\n carry >>= 8;\n }\n while (carry > 0) {\n bytes.push(carry & 0xff);\n carry >>= 8;\n }\n }\n\n // Build result: leading zeros + converted bytes (reversed)\n bytes.reverse();\n \n // Handle case where input was all '1's (all leading zeros, no data to convert)\n // In this case, bytes is just [0] from initialization, which we should ignore\n if (leadingZeros > 0 && bytes.length === 1 && bytes[0] === 0) {\n // Input was all '1's, return that many zero bytes\n return new Uint8Array(leadingZeros);\n }\n \n // Remove leading zero from conversion if present (artifact of starting with [0])\n const startIdx = bytes.length > 1 && bytes[0] === 0 ? 1 : 0;\n \n const result = new Uint8Array(leadingZeros + bytes.length - startIdx);\n // Fill leading zeros\n for (let i = 0; i < leadingZeros; i++) {\n result[i] = 0;\n }\n // Copy converted bytes\n for (let i = startIdx; i < bytes.length; i++) {\n result[leadingZeros + i - startIdx] = bytes[i];\n }\n \n return result;\n}\n\n/**\n * Check if a string is a valid Solana public key (Base58, 32-44 chars)\n * \n * @param address - String to validate\n * @returns true if valid Solana pubkey format\n * \n * @example\n * ```typescript\n * isValidPubkey(\"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v\") // true\n * isValidPubkey(\"invalid\") // false\n * ```\n */\nexport function isValidPubkey(address: string): boolean {\n // Solana pubkeys are 32-44 characters in Base58\n if (address.length < 32 || address.length > 44) {\n return false;\n }\n\n // Check all characters are valid Base58\n for (const char of address) {\n if (!BASE58_ALPHABET.includes(char)) {\n return false;\n }\n }\n\n // Try to decode and verify length\n try {\n const bytes = base58Decode(address);\n return bytes.length === 32;\n } catch {\n return false;\n }\n}\n"]}
package/dist/ws/index.cjs CHANGED
@@ -53,6 +53,8 @@ var MessageType = {
53
53
  Heartbeat: 13,
54
54
  /** Batched pool updates for high throughput */
55
55
  PoolUpdateBatch: 14,
56
+ /** Block-level statistics (v3) */
57
+ BlockStats: 15,
56
58
  /** Error message (UTF-8 string) */
57
59
  Error: 255
58
60
  };
@@ -93,55 +95,75 @@ function decodeMessage(data) {
93
95
  return { type: "error", data: { message: text } };
94
96
  }
95
97
  case MessageType.PriorityFees: {
96
- if (payload.byteLength < 24) return null;
98
+ if (payload.byteLength < 42) return null;
97
99
  const slot = Number(payloadView.getBigUint64(0, true));
98
100
  const timestampMs = Number(payloadView.getBigUint64(8, true));
99
101
  const recommended = Number(payloadView.getBigUint64(16, true));
100
- const state = payload.byteLength > 24 ? payloadView.getUint8(24) : 1;
101
- const isStale = payload.byteLength > 25 ? payloadView.getUint8(25) !== 0 : false;
102
- let swapP50 = 0, swapP75 = 0, swapP90 = 0, swapP99 = 0;
103
- if (payload.byteLength >= 58) {
104
- swapP50 = Number(payloadView.getBigUint64(26, true));
105
- swapP75 = Number(payloadView.getBigUint64(34, true));
106
- swapP90 = Number(payloadView.getBigUint64(42, true));
107
- swapP99 = Number(payloadView.getBigUint64(50, true));
102
+ const state = payloadView.getUint8(24);
103
+ const isStale = payloadView.getUint8(25) !== 0;
104
+ const blockUtilizationPct = payloadView.getFloat32(26, true);
105
+ const blocksInWindow = payloadView.getUint32(30, true);
106
+ const accountCount = Number(payloadView.getBigUint64(34, true));
107
+ const accounts = [];
108
+ let offset = 42;
109
+ for (let i = 0; i < accountCount && offset + 92 <= payload.byteLength; i++) {
110
+ const pubkeyBytes = new Uint8Array(payload, offset, 32);
111
+ const pubkey = base58Encode(pubkeyBytes);
112
+ const totalTxs = payloadView.getUint32(offset + 32, true);
113
+ const activeSlots = payloadView.getUint32(offset + 36, true);
114
+ const cuConsumed = Number(payloadView.getBigUint64(offset + 40, true));
115
+ const utilizationPct = payloadView.getFloat32(offset + 48, true);
116
+ const p25 = Number(payloadView.getBigUint64(offset + 52, true));
117
+ const p50 = Number(payloadView.getBigUint64(offset + 60, true));
118
+ const p75 = Number(payloadView.getBigUint64(offset + 68, true));
119
+ const p90 = Number(payloadView.getBigUint64(offset + 76, true));
120
+ const minNonzeroPrice = Number(payloadView.getBigUint64(offset + 84, true));
121
+ accounts.push({
122
+ pubkey,
123
+ totalTxs,
124
+ activeSlots,
125
+ cuConsumed,
126
+ utilizationPct,
127
+ p25,
128
+ p50,
129
+ p75,
130
+ p90,
131
+ minNonzeroPrice
132
+ });
133
+ offset += 92;
108
134
  }
109
- let swapSamples = 0;
110
- let landingP50Fee = 0, landingP75Fee = 0, landingP90Fee = 0, landingP99Fee = 0;
111
- let top10Fee = 0, top25Fee = 0;
112
- let spikeDetected = false, spikeFee = 0;
113
- if (payload.byteLength >= 119) {
114
- swapSamples = payloadView.getUint32(58, true);
115
- landingP50Fee = Number(payloadView.getBigUint64(62, true));
116
- landingP75Fee = Number(payloadView.getBigUint64(70, true));
117
- landingP90Fee = Number(payloadView.getBigUint64(78, true));
118
- landingP99Fee = Number(payloadView.getBigUint64(86, true));
119
- top10Fee = Number(payloadView.getBigUint64(94, true));
120
- top25Fee = Number(payloadView.getBigUint64(102, true));
121
- spikeDetected = payloadView.getUint8(110) !== 0;
122
- spikeFee = Number(payloadView.getBigUint64(111, true));
135
+ const recentBlocksCount = Number(payloadView.getBigUint64(offset, true));
136
+ offset += 8;
137
+ const recentBlocks = [];
138
+ for (let i = 0; i < recentBlocksCount; i++) {
139
+ const rbSlot = Number(payloadView.getBigUint64(offset, true));
140
+ offset += 8;
141
+ const rbCuConsumed = Number(payloadView.getBigUint64(offset, true));
142
+ offset += 8;
143
+ const rbTxCount = payloadView.getUint32(offset, true);
144
+ offset += 4;
145
+ const rbUtilizationPct = payloadView.getFloat32(offset, true);
146
+ offset += 4;
147
+ const rbAvgCuPrice = Number(payloadView.getBigUint64(offset, true));
148
+ offset += 8;
149
+ recentBlocks.push({ slot: rbSlot, cuConsumed: rbCuConsumed, txCount: rbTxCount, utilizationPct: rbUtilizationPct, avgCuPrice: rbAvgCuPrice });
123
150
  }
151
+ const trendByte = payloadView.getUint8(offset);
152
+ offset += 1;
153
+ const trend = trendByte === 0 ? "rising" : trendByte === 1 ? "falling" : "stable";
124
154
  return {
125
- type: "priority_fees",
155
+ type: "fee_market",
126
156
  data: {
127
157
  slot,
128
158
  timestampMs,
129
159
  recommended,
130
160
  state,
131
161
  isStale,
132
- swapP50,
133
- swapP75,
134
- swapP90,
135
- swapP99,
136
- swapSamples,
137
- landingP50Fee,
138
- landingP75Fee,
139
- landingP90Fee,
140
- landingP99Fee,
141
- top10Fee,
142
- top25Fee,
143
- spikeDetected,
144
- spikeFee
162
+ blockUtilizationPct,
163
+ blocksInWindow,
164
+ accounts,
165
+ recentBlocks,
166
+ trend
145
167
  }
146
168
  };
147
169
  }
@@ -186,6 +208,51 @@ function decodeMessage(data) {
186
208
  }
187
209
  };
188
210
  }
211
+ case MessageType.BlockStats: {
212
+ let offset = 0;
213
+ const slot = Number(payloadView.getBigUint64(offset, true));
214
+ offset += 8;
215
+ const cuConsumed = Number(payloadView.getBigUint64(offset, true));
216
+ offset += 8;
217
+ const executionCu = Number(payloadView.getBigUint64(offset, true));
218
+ offset += 8;
219
+ const cuLimit = Number(payloadView.getBigUint64(offset, true));
220
+ offset += 8;
221
+ const cuRemaining = Number(payloadView.getBigUint64(offset, true));
222
+ offset += 8;
223
+ const utilizationPct = payloadView.getFloat32(offset, true);
224
+ offset += 4;
225
+ const txCount = payloadView.getUint32(offset, true);
226
+ offset += 4;
227
+ const avgCuPerTx = payloadView.getUint32(offset, true);
228
+ offset += 4;
229
+ const avgCuPrice = Number(payloadView.getBigUint64(offset, true));
230
+ offset += 8;
231
+ const minCuPrice = Number(payloadView.getBigUint64(offset, true));
232
+ offset += 8;
233
+ const maxCuPrice = Number(payloadView.getBigUint64(offset, true));
234
+ offset += 8;
235
+ const timestampMs = Number(payloadView.getBigUint64(offset, true));
236
+ offset += 8;
237
+ return {
238
+ type: "block_stats",
239
+ data: {
240
+ slot,
241
+ cuConsumed,
242
+ executionCu,
243
+ cuLimit,
244
+ cuRemaining,
245
+ utilizationPct,
246
+ txCount,
247
+ avgCuPerTx,
248
+ avgCuPrice,
249
+ minCuPrice,
250
+ maxCuPrice,
251
+ timestampMs
252
+ },
253
+ receivedAt: Date.now()
254
+ };
255
+ }
189
256
  default:
190
257
  return null;
191
258
  }
@@ -267,19 +334,7 @@ function decodePoolUpdate(payload, payloadView) {
267
334
  }
268
335
  };
269
336
  } catch {
270
- return {
271
- type: "pool_update",
272
- data: {
273
- sequence: 0,
274
- slot: 0,
275
- writeVersion: 0,
276
- protocol: "unknown",
277
- poolAddress: "",
278
- tokenMints: [],
279
- tokenBalances: [],
280
- tokenDecimals: []
281
- }
282
- };
337
+ return null;
283
338
  }
284
339
  }
285
340
  function decodeQuote(payload, payloadView) {
@@ -350,25 +405,7 @@ function decodeQuote(payload, payloadView) {
350
405
  }
351
406
  };
352
407
  } catch {
353
- return {
354
- type: "quote",
355
- data: {
356
- topicId: "",
357
- timestampMs: 0,
358
- sequence: 0,
359
- inputMint: "",
360
- outputMint: "",
361
- inAmount: "0",
362
- outAmount: "0",
363
- priceImpactBps: 0,
364
- contextSlot: 0,
365
- algorithm: "",
366
- isImprovement: false,
367
- isCached: false,
368
- isStale: false,
369
- routePlan: null
370
- }
371
- };
408
+ return null;
372
409
  }
373
410
  }
374
411
 
@@ -670,8 +707,11 @@ var K256WebSocketClient = class {
670
707
  case "pool_update":
671
708
  this.config.onPoolUpdate?.(decoded);
672
709
  break;
673
- case "priority_fees":
674
- this.config.onPriorityFees?.(decoded);
710
+ case "fee_market":
711
+ this.config.onFeeMarket?.(decoded);
712
+ break;
713
+ case "block_stats":
714
+ this.config.onBlockStats?.(decoded);
675
715
  break;
676
716
  case "blockhash":
677
717
  this.config.onBlockhash?.(decoded);